From 6c3c8b5703c1c05ae98cf6e5725cd650feb1eae4 Mon Sep 17 00:00:00 2001 From: philipp lang Date: Wed, 9 Jul 2025 22:51:28 +0200 Subject: [PATCH] Add condition for leader contribution form --- app/Form/Mails/ConfirmRegistrationMail.php | 4 +- app/Form/Models/Form.php | 3 +- app/Form/Models/Participant.php | 8 +- app/Form/Requests/FormCompileRequest.php | 7 +- ...8_create_forms_leader_condition_column.php | 28 +++++++ .../Feature/Form/GenerateContributionTest.php | 83 +++++++++++++------ .../ConditionRequestFactory.php | 24 ++++++ 7 files changed, 122 insertions(+), 35 deletions(-) create mode 100644 database/migrations/2025_07_09_221048_create_forms_leader_condition_column.php create mode 100644 tests/RequestFactories/ConditionRequestFactory.php diff --git a/app/Form/Mails/ConfirmRegistrationMail.php b/app/Form/Mails/ConfirmRegistrationMail.php index 610c9c6e..e70253e8 100644 --- a/app/Form/Mails/ConfirmRegistrationMail.php +++ b/app/Form/Mails/ConfirmRegistrationMail.php @@ -69,10 +69,8 @@ class ConfirmRegistrationMail extends Mailable */ public function attachments() { - $conditionResolver = app(FormConditionResolver::class)->forParticipant($this->participant); - return $this->participant->form->getMedia('mailattachments') - ->filter(fn ($media) => $conditionResolver->filterCondition(Condition::fromMedia($media))) + ->filter(fn ($media) => $this->participant->matchesCondition(Condition::fromMedia($media))) ->map(fn ($media) => Attachment::fromStorageDisk($media->disk, $media->getPathRelativeToRoot())) ->all(); } diff --git a/app/Form/Models/Form.php b/app/Form/Models/Form.php index 78f64634..b1520887 100644 --- a/app/Form/Models/Form.php +++ b/app/Form/Models/Form.php @@ -49,7 +49,8 @@ class Form extends Model implements HasMedia 'to' => 'datetime', 'registration_from' => 'datetime', 'registration_until' => 'datetime', - 'country' => Country::class + 'country' => Country::class, + 'leader_condition' => Condition::class, ]; /** diff --git a/app/Form/Models/Participant.php b/app/Form/Models/Participant.php index e2b47af6..370ae20c 100644 --- a/app/Form/Models/Participant.php +++ b/app/Form/Models/Participant.php @@ -4,12 +4,12 @@ namespace App\Form\Models; use App\Form\Data\FieldCollection; use App\Form\Data\FormConfigData; +use App\Form\Editor\FormConditionResolver; use App\Form\Mails\ConfirmRegistrationMail; -use App\Form\Scopes\ParticipantFilterScope; +use App\Lib\Editor\Condition; use App\Member\Member; use App\Prevention\Contracts\Preventable; use Database\Factories\Form\Models\ParticipantFactory; -use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -110,4 +110,8 @@ class Participant extends Model implements Preventable { return [...$this->data, 'parent-id' => $this->parent_id, 'created_at' => $this->created_at->timestamp]; } + + public function matchesCondition(Condition $condition): bool { + return app(FormConditionResolver::class)->forParticipant($this)->filterCondition($condition); + } } diff --git a/app/Form/Requests/FormCompileRequest.php b/app/Form/Requests/FormCompileRequest.php index 41fc1f86..951edea4 100644 --- a/app/Form/Requests/FormCompileRequest.php +++ b/app/Form/Requests/FormCompileRequest.php @@ -6,6 +6,7 @@ use App\Contribution\Contracts\HasContributionData; use App\Contribution\Data\MemberData; use App\Contribution\Documents\ContributionDocument; use App\Country; +use App\Form\Editor\FormConditionResolver; use App\Form\Enums\SpecialType; use App\Form\Models\Form; use Carbon\Carbon; @@ -22,7 +23,7 @@ class FormCompileRequest extends Data implements HasContributionData { */ public function type(): string { - $payload = json_decode(rawurldecode(base64_decode(request()->input('payload', ''))), true); + $payload = json_decode(rawurldecode(base64_decode(request()->input('payload'))), true); return $payload['type']; } @@ -54,10 +55,10 @@ class FormCompileRequest extends Data implements HasContributionData { [SpecialType::FIRSTNAME, 'firstname'], [SpecialType::LASTNAME, 'lastname'], [SpecialType::BIRTHDAY, 'birthday'], + [SpecialType::GENDER, 'gender'], [SpecialType::ADDRESS, 'address'], [SpecialType::ZIP, 'zip'], [SpecialType::LOCATION, 'location'], - [SpecialType::GENDER, 'gender'] ]; foreach ($this->form->participants as $participant) { @@ -71,7 +72,7 @@ class FormCompileRequest extends Data implements HasContributionData { } $members[] = [ - 'is_leader' => false, + 'is_leader' => $participant->matchesCondition($participant->form->leader_condition), 'gender' => 'weiblich', ...$member, ]; diff --git a/database/migrations/2025_07_09_221048_create_forms_leader_condition_column.php b/database/migrations/2025_07_09_221048_create_forms_leader_condition_column.php new file mode 100644 index 00000000..9941396e --- /dev/null +++ b/database/migrations/2025_07_09_221048_create_forms_leader_condition_column.php @@ -0,0 +1,28 @@ +json('leader_condition')->after('name')->default(json_encode(['mode' => 'all', 'ifs' => []])); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('forms', function (Blueprint $table) { + $table->dropColumn('leader_condition'); + }); + } +}; diff --git a/tests/Feature/Form/GenerateContributionTest.php b/tests/Feature/Form/GenerateContributionTest.php index 12099d41..699b5498 100644 --- a/tests/Feature/Form/GenerateContributionTest.php +++ b/tests/Feature/Form/GenerateContributionTest.php @@ -12,6 +12,7 @@ use App\Form\Requests\FormCompileRequest; use App\Gender; use Illuminate\Foundation\Testing\DatabaseTransactions; use Tests\Lib\CreatesFormFields; +use Tests\RequestFactories\ConditionRequestFactory; use Zoomyboy\Tex\Tex; uses(DatabaseTransactions::class); @@ -23,11 +24,11 @@ beforeEach(function() { Country::factory()->create(); Gender::factory()->male()->create(); Gender::factory()->female()->create(); + Tex::spy(); + $this->login()->loginNami(); }); it('doesnt create document when no special fields given', function (array $fields, string $field, string $message, string $type) { - $this->login()->loginNami(); - $form = Form::factory() ->fields($fields) ->has(Participant::factory()) @@ -44,8 +45,6 @@ it('doesnt create document when no special fields given', function (array $field ])->with('contribution-documents'); it('validates special types of each document', function (string $type, array $fields, string $field, string $message) { - $this->login()->loginNami(); - $form = Form::factory()->fields([ test()->textField('f')->specialType(SpecialType::FIRSTNAME), test()->textField('l')->specialType(SpecialType::LASTNAME), @@ -65,8 +64,6 @@ it('validates special types of each document', function (string $type, array $fi ]); it('throws error when not validating but fields are not present', function () { - $this->login()->loginNami(); - $form = Form::factory()->fields([]) ->has(Participant::factory()) ->create(); @@ -75,8 +72,6 @@ it('throws error when not validating but fields are not present', function () { }); it('throws error when form doesnt have meta', function () { - $this->login()->loginNami(); - $form = Form::factory()->fields([]) ->has(Participant::factory()) ->zip('') @@ -90,37 +85,73 @@ it('throws error when form doesnt have meta', function () { }); it('throws error when form doesnt have participants', function () { - $this->login()->loginNami(); - $form = Form::factory()->fields([])->create(); generate(CitySolingenDocument::class, $form, true)->assertJsonValidationErrors(['participants' => 'Veranstaltung besitzt noch keine Teilnehmer*innen.']); }); -it('creates document when fields are present', function () { - Tex::spy(); - $this->login()->loginNami(); +dataset('default-form-contribution', fn () => [ + [ + ['fn' => 'Baum', 'ln' => 'Muster', 'bd' => '1991-05-06', 'zip' => '33333', 'loc' => 'Musterstadt', 'add' => 'Laastr 4', 'gen' => 'weiblich'], + fn () => [ + test()->textField('fn')->specialType(SpecialType::FIRSTNAME), + test()->textField('ln')->specialType(SpecialType::LASTNAME), + test()->dateField('bd')->specialType(SpecialType::BIRTHDAY), + test()->dateField('zip')->specialType(SpecialType::ZIP), + test()->dateField('loc')->specialType(SpecialType::LOCATION), + test()->dateField('add')->specialType(SpecialType::ADDRESS), + test()->dateField('gen')->specialType(SpecialType::GENDER), + ] + ] +]); +dataset('form-contributions', fn () => [ + [ + [], + [], + CitySolingenDocument::class, + ['Baum', 'Muster', '1991', 'Musterstadt', 'Laastr 4', '33333'], + ], + [ + ['gen' => 'männlich'], + [], + RdpNrwDocument::class, + ['{m}'], + ], + [ + ['gen' => 'weiblich'], + [], + RdpNrwDocument::class, + ['{w}'], + ], +]); + +it('creates document with participant data', function (array $defaultData, array $defaultFields, array $newData, array $newFields, string $document, array $expected) { $form = Form::factory()->fields([ - test()->textField('fn')->specialType(SpecialType::FIRSTNAME), - test()->textField('ln')->specialType(SpecialType::LASTNAME), - test()->dateField('bd')->specialType(SpecialType::BIRTHDAY), - test()->dateField('zip')->specialType(SpecialType::ZIP), - test()->dateField('loc')->specialType(SpecialType::LOCATION), - test()->dateField('add')->specialType(SpecialType::ADDRESS), + ...$defaultFields, + ...$newFields, ]) - ->has(Participant::factory()->data(['fn' => 'Baum', 'ln' => 'Muster', 'bd' => '1991-05-06', 'zip' => '33333', 'loc' => 'Musterstadt', 'add' => 'Laastr 4'])) + ->has(Participant::factory()->data([...$defaultData, ...$newData])) ->create(); - generate(CitySolingenDocument::class, $form, false)->assertOk(); - Tex::assertCompiled(CitySolingenDocument::class, fn($document) => $document->hasAllContent(['Baum', 'Muster', '1991', 'Musterstadt', 'Laastr 4', '33333'])); -}); + generate($document, $form, false)->assertOk(); + Tex::assertCompiled($document, fn($document) => $document->hasAllContent($expected)); +})->with('default-form-contribution')->with('form-contributions'); +it('creates document with is leader', function (array $defaultData, array $fields) { + $form = Form::factory()->fields([ + ...$fields, + test()->dropdownField('leader')->options(['L', 'NL'])->specialType(SpecialType::LEADER), + ]) + ->has(Participant::factory()->data([...$defaultData, 'leader' => 'L'])) + ->leaderCondition(ConditionRequestFactory::new()->whenField('leader', 'L')->create()) + ->create(); + + generate(RdpNrwDocument::class, $form, false)->assertOk(); + Tex::assertCompiled(RdpNrwDocument::class, fn($document) => $document->hasAllContent(['{L}'])); +})->with('default-form-contribution'); it('creates document with form meta', function () { - Tex::spy(); - $this->login()->loginNami(); - $form = Form::factory()->fields([ test()->textField('fn')->specialType(SpecialType::FIRSTNAME), test()->textField('ln')->specialType(SpecialType::LASTNAME), diff --git a/tests/RequestFactories/ConditionRequestFactory.php b/tests/RequestFactories/ConditionRequestFactory.php new file mode 100644 index 00000000..96048369 --- /dev/null +++ b/tests/RequestFactories/ConditionRequestFactory.php @@ -0,0 +1,24 @@ + 'all', + 'ifs' => [], + ]; + } + + public function whenField(string $field, string $value): self { + return $this->state([ + 'ifs' => [ + ['field' => $field, 'comparator' => 'isEqual', 'value' => $value] + ], + ]); + } +}