Files
mareike/tests/Feature/ShortSignUpTest.php
T
2026-09-10 11:11:20 +02:00

332 lines
15 KiB
PHP

<?php
namespace Tests\Feature;
use App\Domains\Event\Actions\ShortSignUp\ShortSignUpCommand;
use App\Domains\Event\Actions\ShortSignUp\ShortSignUpRequest;
use App\Enumerations\EatingHabit;
use App\Enumerations\EfzStatus;
use App\Enumerations\FirstAidPermission;
use App\Enumerations\ParticipationType;
use App\Enumerations\SwimmingPermission;
use App\Models\Event;
use App\Models\EventParticipant;
use App\Models\PaymentMethod;
use App\Models\Tenant;
use App\RelationModels\EventParticipationFee;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;
class ShortSignUpTest extends TestCase
{
use RefreshDatabase;
private Tenant $tenant;
protected function setUp(): void
{
parent::setUp();
Mail::fake();
$this->tenant = Tenant::create([
'slug' => 'tv', 'name' => 'Test', 'email' => 't@example.com', 'email_finance' => 'f@example.com',
'url' => 'test.local', 'account_name' => 'Test e.V.', 'account_iban' => 'DE00', 'account_bic' => 'XY',
'city' => 'Stadt', 'postcode' => '00000', 'is_active_local_group' => true, 'has_active_instance' => true,
]);
app()->instance('tenant', $this->tenant);
PaymentMethod::create(['slug' => PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION]);
DB::table('participation_fee_types')->insert(['slug' => 'FIXED', 'name' => 'Fixed', 'created_at' => now(), 'updated_at' => now()]);
ParticipationType::create(['slug' => ParticipationType::PARTICIPATION_TYPE_PARTICIPANT, 'name' => 'Teilnehmende']);
EfzStatus::create(['slug' => EfzStatus::EFZ_STATUS_NOT_CHECKED, 'name' => 'Nicht geprüft']);
EfzStatus::create(['slug' => EfzStatus::EFZ_STATUS_NOT_REQUIRED, 'name' => 'Nicht erforderlich']);
SwimmingPermission::create(['slug' => SwimmingPermission::SWIMMING_PERMISSION_ALLOWED, 'name' => 'Darf baden', 'short' => 'Erteilt']);
SwimmingPermission::create(['slug' => SwimmingPermission::SWIMMING_PERMISSION_DENIED, 'name' => 'Darf nicht baden', 'short' => 'Keine']);
FirstAidPermission::create(['slug' => FirstAidPermission::FIRST_AID_PERMISSION_ALLOWED, 'name' => 'Zugestimmt', 'description' => '']);
FirstAidPermission::create(['slug' => FirstAidPermission::FIRST_AID_PERMISSION_DENIED, 'name' => 'Abgelehnt', 'description' => '']);
EatingHabit::create(['slug' => EatingHabit::EATING_HABIT_OMNIVOR, 'name' => 'Omnivor']);
}
private function createEvent(bool $withFee = true, bool $swimmingPermissionRequired = true): Event
{
$event = Event::create([
'tenant' => $this->tenant->slug, 'name' => 'Event', 'identifier' => 'evt-1', 'location' => 'Ort',
'postal_code' => '00000', 'email' => 'e@example.com', 'start_date' => '2026-08-01', 'end_date' => '2026-08-05',
'early_bird_end' => '2026-07-01', 'registration_final_end' => '2026-07-20', 'early_bird_end_amount_increase' => 0,
'account_owner' => 'Owner', 'account_iban' => 'DE00', 'participation_fee_type' => 'FIXED',
'pay_per_day' => false, 'pay_direct' => false,
'short_registration' => true, 'swimming_permission_required' => $swimmingPermissionRequired,
]);
if ($withFee) {
$fee = EventParticipationFee::create([
'tenant' => $this->tenant->slug, 'type' => ParticipationType::PARTICIPATION_TYPE_PARTICIPANT,
'name' => 'Teilnahme', 'description' => '', 'amount_standard' => 50.0,
'amount_reduced' => 30.0, 'amount_solidarity' => 70.0,
]);
$event->participation_fee_1 = $fee->id;
$event->save();
$event->refresh();
}
return $event;
}
private function shortRequest(Event $event, array $overrides = []): ShortSignUpRequest
{
return new ShortSignUpRequest(
event: $event,
user_id: null,
firstname: $overrides['firstname'] ?? 'Hans',
lastname: $overrides['lastname'] ?? 'Muster',
nickname: $overrides['nickname'] ?? null,
// Volljährig, sofern nicht anders angegeben.
birthday: $overrides['birthday'] ?? new \DateTime('2000-01-01'),
email: $overrides['email'] ?? 'h@example.com',
phone: $overrides['phone'] ?? '123',
localGroupId: $overrides['localGroupId'] ?? null,
contactPerson: $overrides['contactPerson'] ?? null,
contactEmail: $overrides['contactEmail'] ?? null,
allergies: $overrides['allergies'] ?? null,
intolerances: $overrides['intolerances'] ?? null,
firstAidPermission: $overrides['firstAidPermission'] ?? null,
swimmingPermission: $overrides['swimmingPermission'] ?? null,
foto_socialmedia: true,
foto_print: false,
foto_webseite: false,
foto_partner: false,
foto_intern: false,
paymentMethod: $overrides['paymentMethod'] ?? PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION,
paymentOptions: [],
participationOptions: $overrides['participationOptions'] ?? [],
);
}
public function test_kurzanmeldung_fuellt_nicht_erhobene_pflichtfelder(): void
{
$event = $this->createEvent();
$response = new ShortSignUpCommand($this->shortRequest($event))->execute();
$this->assertTrue($response->success, $response->message ?? '');
$participant = $response->participant;
$this->assertSame('Nicht erforderlich', $participant->address_1);
$this->assertSame('Nicht erforderlich', $participant->city);
$this->assertSame('00000', $participant->postcode);
$this->assertNull($participant->local_group);
$this->assertNull($participant->address_2);
$this->assertNull($participant->medications);
// Zeitraum und Mahlzeiten kommen aus der Veranstaltung.
$this->assertSame('2026-08-01', $participant->arrival_date->format('Y-m-d'));
$this->assertSame('2026-08-05', $participant->departure_date->format('Y-m-d'));
$this->assertSame(1, $participant->arrival_eating);
$this->assertSame(2, $participant->departure_eating);
// Gruppe und Beitragsstufe stehen fest.
$this->assertSame(ParticipationType::PARTICIPATION_TYPE_PARTICIPANT, $participant->participation_type);
$this->assertSame('standard', $participant->fee_type);
$this->assertSame(50.0, $participant->amount->getAmount());
$this->assertSame(EatingHabit::EATING_HABIT_OMNIVOR, $participant->eating_habit);
// Volljährige brauchen keine Erlaubnisse.
$this->assertSame(SwimmingPermission::SWIMMING_PERMISSION_ALLOWED, $participant->swimming_permission);
$this->assertSame(FirstAidPermission::FIRST_AID_PERMISSION_ALLOWED, $participant->first_aid_permission);
$this->assertSame(1, $participant->invoice_sequence);
$this->assertTrue($participant->foto_socialmedia);
$this->assertFalse($participant->foto_print);
}
public function test_u18_ohne_abgefragte_badeerlaubnis_bekommt_keine(): void
{
$event = $this->createEvent(swimmingPermissionRequired: false);
$response = new ShortSignUpCommand($this->shortRequest($event, [
'birthday' => new \DateTime('2015-01-01'),
'contactPerson' => 'Muster, Maria',
'contactEmail' => 'maria@example.com',
'firstAidPermission' => FirstAidPermission::FIRST_AID_PERMISSION_ALLOWED,
]))->execute();
$this->assertTrue($response->success, $response->message ?? '');
$this->assertSame(SwimmingPermission::SWIMMING_PERMISSION_DENIED, $response->participant->swimming_permission);
$this->assertSame(EfzStatus::EFZ_STATUS_NOT_REQUIRED, $response->participant->efz_status);
$this->assertSame('Muster, Maria', $response->participant->contact_person);
$this->assertSame('maria@example.com', $response->participant->email_2);
}
public function test_u18_uebernimmt_gewaehlte_badeerlaubnis(): void
{
$event = $this->createEvent();
$response = new ShortSignUpCommand($this->shortRequest($event, [
'birthday' => new \DateTime('2015-01-01'),
'contactPerson' => 'Muster, Maria',
'contactEmail' => 'maria@example.com',
'firstAidPermission' => FirstAidPermission::FIRST_AID_PERMISSION_DENIED,
'swimmingPermission' => SwimmingPermission::SWIMMING_PERMISSION_ALLOWED,
]))->execute();
$this->assertTrue($response->success, $response->message ?? '');
$this->assertSame(SwimmingPermission::SWIMMING_PERMISSION_ALLOWED, $response->participant->swimming_permission);
$this->assertSame(FirstAidPermission::FIRST_AID_PERMISSION_DENIED, $response->participant->first_aid_permission);
}
public function test_u18_ohne_kontaktperson_wird_abgelehnt(): void
{
$event = $this->createEvent();
$response = new ShortSignUpCommand($this->shortRequest($event, [
'birthday' => new \DateTime('2015-01-01'),
]))->execute();
$this->assertFalse($response->success);
$this->assertSame(0, EventParticipant::count());
}
public function test_ohne_teilnahmegruppe_wird_abgelehnt(): void
{
$event = $this->createEvent(withFee: false);
$response = new ShortSignUpCommand($this->shortRequest($event))->execute();
$this->assertFalse($response->success);
$this->assertNotNull($response->message);
$this->assertSame(0, EventParticipant::count());
}
public function test_teilnahmeoptionen_werden_gespeichert(): void
{
$event = $this->createEvent();
$event->participation_options = [[
'key' => 'shirt',
'title' => 'T-Shirt',
'label' => 'T-Shirt-Größe',
'options' => [['value' => 'm', 'label' => 'M'], ['value' => 'l', 'label' => 'L']],
]];
$event->save();
$response = new ShortSignUpCommand($this->shortRequest($event, [
'participationOptions' => ['shirt' => 'l'],
]))->execute();
$this->assertTrue($response->success, $response->message ?? '');
$options = $response->participant->selectedOptions()->get();
$this->assertCount(1, $options);
$this->assertSame('shirt', $options->first()->question_key);
$this->assertSame('L', $options->first()->value_label);
}
public function test_unbeantwortete_teilnahmeoption_wird_abgelehnt(): void
{
$event = $this->createEvent();
$event->participation_options = [[
'key' => 'shirt',
'title' => 'T-Shirt',
'label' => 'T-Shirt-Größe',
'options' => [['value' => 'm', 'label' => 'M']],
]];
$event->save();
$response = new ShortSignUpCommand($this->shortRequest($event))->execute();
$this->assertFalse($response->success);
$this->assertSame(0, EventParticipant::count());
}
private function createLocalGroup(string $slug, string $name): Tenant
{
return Tenant::create([
'slug' => $slug, 'name' => $name, 'email' => $slug . '@example.com',
'email_finance' => $slug . '-f@example.com', 'url' => $slug . '.local',
'account_name' => $name, 'account_iban' => 'DE00', 'account_bic' => 'XY',
'city' => 'Stadt', 'postcode' => '00000', 'is_active_local_group' => true,
'has_active_instance' => false,
]);
}
public function test_einziger_stamm_wird_ohne_auswahl_zugeordnet(): void
{
$event = $this->createEvent();
$group = $this->createLocalGroup('stamm-a', 'Stamm A');
$event->localGroups()->attach($group->id);
$event->refresh();
$response = new ShortSignUpCommand($this->shortRequest($event))->execute();
$this->assertTrue($response->success, $response->message ?? '');
$this->assertSame('stamm-a', $response->participant->local_group);
}
public function test_bei_mehreren_staemmen_wird_die_auswahl_uebernommen(): void
{
$event = $this->createEvent();
$first = $this->createLocalGroup('stamm-a', 'Stamm A');
$second = $this->createLocalGroup('stamm-b', 'Stamm B');
$event->localGroups()->attach([$first->id, $second->id]);
$event->refresh();
$response = new ShortSignUpCommand($this->shortRequest($event, [
'localGroupId' => $second->id,
]))->execute();
$this->assertTrue($response->success, $response->message ?? '');
$this->assertSame('stamm-b', $response->participant->local_group);
}
public function test_bei_mehreren_staemmen_ist_die_auswahl_pflicht(): void
{
$event = $this->createEvent();
$first = $this->createLocalGroup('stamm-a', 'Stamm A');
$second = $this->createLocalGroup('stamm-b', 'Stamm B');
$event->localGroups()->attach([$first->id, $second->id]);
$event->refresh();
$response = new ShortSignUpCommand($this->shortRequest($event))->execute();
$this->assertFalse($response->success);
$this->assertSame(0, EventParticipant::count());
}
public function test_nicht_teilnehmender_stamm_wird_abgelehnt(): void
{
$event = $this->createEvent();
$first = $this->createLocalGroup('stamm-a', 'Stamm A');
$second = $this->createLocalGroup('stamm-b', 'Stamm B');
$event->localGroups()->attach([$first->id, $second->id]);
$event->refresh();
// Stamm existiert, nimmt aber nicht an der Veranstaltung teil.
$foreign = $this->createLocalGroup('stamm-c', 'Stamm C');
$response = new ShortSignUpCommand($this->shortRequest($event, [
'localGroupId' => $foreign->id,
]))->execute();
$this->assertFalse($response->success);
$this->assertSame(0, EventParticipant::count());
}
public function test_resource_ueberlebt_kurzanmeldung(): void
{
$event = $this->createEvent();
$response = new ShortSignUpCommand($this->shortRequest($event))->execute();
$this->assertTrue($response->success, $response->message ?? '');
// Regressionswächter für Teilnehmerliste, Detailansicht und CSV-Export.
$array = $response->participant->toResource()->toArray(request());
$this->assertSame('Nicht im LV', $array['localgroup']);
$this->assertSame('Erteilt', $array['swimmingPermission']);
$this->assertSame('Zugestimmt', $array['extendedFirstAid']);
$this->assertSame('Omnivor', $array['eatingHabit']);
$this->assertSame('Teilnehmende', $array['participationType']);
}
}