Add condition for leader contribution form
continuous-integration/drone/push Build is passing Details

This commit is contained in:
philipp lang 2025-07-09 22:51:28 +02:00
parent 5fe1004871
commit 6c3c8b5703
7 changed files with 122 additions and 35 deletions

View File

@ -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();
}

View File

@ -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,
];
/**

View File

@ -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);
}
}

View File

@ -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,
];

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('forms', function (Blueprint $table) {
$table->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');
});
}
};

View File

@ -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),

View File

@ -0,0 +1,24 @@
<?php
namespace Tests\RequestFactories;
use Worksome\RequestFactories\RequestFactory;
class ConditionRequestFactory extends RequestFactory
{
public function definition(): array
{
return [
'mode' => 'all',
'ifs' => [],
];
}
public function whenField(string $field, string $value): self {
return $this->state([
'ifs' => [
['field' => $field, 'comparator' => 'isEqual', 'value' => $value]
],
]);
}
}