From 6c9281516e5ef2edb3fd2dce9a33506cac1f2b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Tue, 28 Jul 2026 15:50:58 +0200 Subject: [PATCH 1/8] Basic implementation of payment methods --- .../CreateTenant/CreateTenantAction.php | 14 ++ .../RemovePaymentMethodUsageAction.php | 32 +++ .../UpdateAvailablePaymentMethodAction.php | 33 +++ .../UpdateAvailablePaymentMethodRequest.php | 16 ++ .../UpdateAvailablePaymentMethodResponse.php | 9 + .../TenantPaymentMethodsGetController.php | 19 ++ .../TenantPaymentMethodsUpdateController.php | 32 +++ app/Domains/Admin/Routes/api.php | 4 + .../Views/Partials/TenantPaymentMethods.vue | 212 ++++++++++++++++++ app/Domains/Admin/Views/TenantData.vue | 6 + .../CreateEvent/CreateEventCommand.php | 11 +- .../CreateEvent/CreateEventRequest.php | 4 +- .../Event/Actions/SignUp/SignUpCommand.php | 3 + .../UpdateEvent/UpdateEventCommand.php | 11 + .../UpdateEvent/UpdateEventRequest.php | 4 +- .../UpdateEvent/UpdateEventResponse.php | 2 + .../UpdateParticipantCommand.php | 1 + .../UpdateParticipantRequest.php | 1 + .../Event/Controllers/CreateController.php | 4 +- .../Event/Controllers/DetailsController.php | 6 +- .../ParticipantUpdateController.php | 1 + app/Domains/Event/Views/Create.vue | 9 - .../Event/Views/Partials/CommonSettings.vue | 27 ++- .../Event/Views/Partials/ParticipantData.vue | 20 +- app/Installer/ProductionDataSeeder.php | 7 + .../PaymentMethodsExhaustedMail.php | 46 ++++ app/Models/AvailablePaymentMethod.php | 42 ++++ app/Models/Event.php | 9 + app/Models/EventParticipant.php | 6 + app/Models/PaymentMethod.php | 30 +++ app/Providers/GlobalDataProvider.php | 2 + app/RelationModels/EventPaymentMethods.php | 11 + .../AvailablePaymentMethodResource.php | 24 ++ app/Resources/EventParticipantResource.php | 9 +- app/Resources/EventResource.php | 3 + ...26_07_28_140010_create_payment_methods.php | 38 ++++ ...28_140020_create_event_payment_methods.php | 24 ++ ...d_payment_method_to_event_participants.php | 25 +++ .../payment_methods_exhausted.blade.php | 16 ++ 39 files changed, 749 insertions(+), 24 deletions(-) create mode 100644 app/Domains/Admin/Actions/RemovePaymentMethodUsage/RemovePaymentMethodUsageAction.php create mode 100644 app/Domains/Admin/Actions/UpdateAvailablePaymentMethod/UpdateAvailablePaymentMethodAction.php create mode 100644 app/Domains/Admin/Actions/UpdateAvailablePaymentMethod/UpdateAvailablePaymentMethodRequest.php create mode 100644 app/Domains/Admin/Actions/UpdateAvailablePaymentMethod/UpdateAvailablePaymentMethodResponse.php create mode 100644 app/Domains/Admin/Controllers/TenantPaymentMethodsGetController.php create mode 100644 app/Domains/Admin/Controllers/TenantPaymentMethodsUpdateController.php create mode 100644 app/Domains/Admin/Views/Partials/TenantPaymentMethods.vue create mode 100644 app/Mail/EventReportMails/PaymentMethodsExhaustedMail.php create mode 100644 app/Models/AvailablePaymentMethod.php create mode 100644 app/Models/PaymentMethod.php create mode 100644 app/RelationModels/EventPaymentMethods.php create mode 100644 app/Resources/AvailablePaymentMethodResource.php create mode 100644 database/migrations/2026_07_28_140010_create_payment_methods.php create mode 100644 database/migrations/2026_07_28_140020_create_event_payment_methods.php create mode 100644 database/migrations/2026_07_28_140030_add_payment_method_to_event_participants.php create mode 100644 resources/views/emails/events/payment_methods_exhausted.blade.php diff --git a/app/Domains/Admin/Actions/CreateTenant/CreateTenantAction.php b/app/Domains/Admin/Actions/CreateTenant/CreateTenantAction.php index 05c4504..2ea2af6 100644 --- a/app/Domains/Admin/Actions/CreateTenant/CreateTenantAction.php +++ b/app/Domains/Admin/Actions/CreateTenant/CreateTenantAction.php @@ -2,6 +2,8 @@ namespace App\Domains\Admin\Actions\CreateTenant; +use App\Models\AvailablePaymentMethod; +use App\Models\PaymentMethod; use App\Models\Tenant; class CreateTenantAction @@ -29,6 +31,18 @@ class CreateTenantAction 'has_active_instance' => true, ]); + foreach (PaymentMethod::all() as $paymentMethod) { + $defaults = PaymentMethod::DEFAULTS[$paymentMethod->slug] ?? ['name' => $paymentMethod->slug, 'description' => null]; + + AvailablePaymentMethod::create([ + 'tenant' => $tenant->slug, + 'slug' => $paymentMethod->slug, + 'name' => $defaults['name'], + 'description' => $defaults['description'], + 'active' => true, + ]); + } + $response->success = true; $response->message = 'Stamm wurde angelegt.'; $response->slug = $tenant->slug; diff --git a/app/Domains/Admin/Actions/RemovePaymentMethodUsage/RemovePaymentMethodUsageAction.php b/app/Domains/Admin/Actions/RemovePaymentMethodUsage/RemovePaymentMethodUsageAction.php new file mode 100644 index 0000000..523dedf --- /dev/null +++ b/app/Domains/Admin/Actions/RemovePaymentMethodUsage/RemovePaymentMethodUsageAction.php @@ -0,0 +1,32 @@ +events()->get() as $event) { + $event->paymentMethods()->detach($availablePaymentMethod->id); + + $remainingActive = $event->paymentMethods()->where('active', true)->count(); + if ($remainingActive === 0 && $event->registration_allowed) { + $event->registration_allowed = false; + $event->save(); + + $recipients = $event->eventManagers; + if ($event->costUnit !== null) { + $recipients = $recipients->merge($event->costUnit->treasurers); + } + + foreach ($recipients->unique('id') as $recipient) { + Mail::to($recipient->email)->send(new PaymentMethodsExhaustedMail($event)); + } + } + } + } +} diff --git a/app/Domains/Admin/Actions/UpdateAvailablePaymentMethod/UpdateAvailablePaymentMethodAction.php b/app/Domains/Admin/Actions/UpdateAvailablePaymentMethod/UpdateAvailablePaymentMethodAction.php new file mode 100644 index 0000000..118d4c9 --- /dev/null +++ b/app/Domains/Admin/Actions/UpdateAvailablePaymentMethod/UpdateAvailablePaymentMethodAction.php @@ -0,0 +1,33 @@ +request->availablePaymentMethod->active; + + $this->request->availablePaymentMethod->update([ + 'name' => $this->request->name, + 'description' => $this->request->description, + 'active' => $this->request->active, + ]); + + if ($wasActive && !$this->request->active) { + (new RemovePaymentMethodUsageAction())->execute($this->request->availablePaymentMethod); + } + + $response->success = true; + $response->message = 'Zahlungsmethode wurde gespeichert.'; + + return $response; + } +} diff --git a/app/Domains/Admin/Actions/UpdateAvailablePaymentMethod/UpdateAvailablePaymentMethodRequest.php b/app/Domains/Admin/Actions/UpdateAvailablePaymentMethod/UpdateAvailablePaymentMethodRequest.php new file mode 100644 index 0000000..4cb27ce --- /dev/null +++ b/app/Domains/Admin/Actions/UpdateAvailablePaymentMethod/UpdateAvailablePaymentMethodRequest.php @@ -0,0 +1,16 @@ +json([ + 'paymentMethods' => AvailablePaymentMethod::all(), + 'saveEndpoint' => '/api/v1/admin/tenant/payment-methods', + ]); + } +} diff --git a/app/Domains/Admin/Controllers/TenantPaymentMethodsUpdateController.php b/app/Domains/Admin/Controllers/TenantPaymentMethodsUpdateController.php new file mode 100644 index 0000000..7d4c7c1 --- /dev/null +++ b/app/Domains/Admin/Controllers/TenantPaymentMethodsUpdateController.php @@ -0,0 +1,32 @@ +input('name'), + description: $request->input('description'), + active: (bool) $request->input('active'), + )); + + $response = $action->execute(); + + return response()->json([ + 'status' => $response->success ? 'success' : 'error', + 'message' => $response->message, + ]); + } +} diff --git a/app/Domains/Admin/Routes/api.php b/app/Domains/Admin/Routes/api.php index 2d1337d..a7a7069 100644 --- a/app/Domains/Admin/Routes/api.php +++ b/app/Domains/Admin/Routes/api.php @@ -25,6 +25,8 @@ use App\Domains\Admin\Controllers\TenantImpressUpdateController; use App\Domains\Admin\Controllers\TenantListApiController; use App\Domains\Admin\Controllers\TenantPaymentGetController; use App\Domains\Admin\Controllers\TenantPaymentUpdateController; +use App\Domains\Admin\Controllers\TenantPaymentMethodsGetController; +use App\Domains\Admin\Controllers\TenantPaymentMethodsUpdateController; use App\Middleware\AdminRoleMiddleware; use App\Middleware\IdentifyTenant; use App\Middleware\LvOnlyMiddleware; @@ -36,6 +38,8 @@ Route::middleware([IdentifyTenant::class, 'auth', AdminRoleMiddleware::class])-> Route::post('/contact', TenantContactUpdateController::class); Route::get('/payment', TenantPaymentGetController::class); Route::post('/payment', TenantPaymentUpdateController::class); + Route::get('/payment-methods', TenantPaymentMethodsGetController::class); + Route::post('/payment-methods/{id}', TenantPaymentMethodsUpdateController::class); Route::get('/impress', TenantImpressGetController::class); Route::post('/impress', TenantImpressUpdateController::class); Route::get('/gdpr', TenantGdprGetController::class); diff --git a/app/Domains/Admin/Views/Partials/TenantPaymentMethods.vue b/app/Domains/Admin/Views/Partials/TenantPaymentMethods.vue new file mode 100644 index 0000000..7e93d24 --- /dev/null +++ b/app/Domains/Admin/Views/Partials/TenantPaymentMethods.vue @@ -0,0 +1,212 @@ + + + + + diff --git a/app/Domains/Admin/Views/TenantData.vue b/app/Domains/Admin/Views/TenantData.vue index 5622db5..8d6c19b 100644 --- a/app/Domains/Admin/Views/TenantData.vue +++ b/app/Domains/Admin/Views/TenantData.vue @@ -6,6 +6,7 @@ import TenantContact from "./Partials/TenantContact.vue"; import TenantPayment from "./Partials/TenantPayment.vue"; import TenantImpress from "./Partials/TenantImpress.vue"; import TenantGdpr from "./Partials/TenantGdpr.vue"; +import TenantPaymentMethods from "./Partials/TenantPaymentMethods.vue"; const props = defineProps({ tenant: Object, @@ -22,6 +23,11 @@ const tabs = [ component: TenantPayment, endpoint: '/api/v1/admin/tenant/payment', }, + { + title: 'Zahlungswege', + component: TenantPaymentMethods, + endpoint: '/api/v1/admin/tenant/payment-methods', + }, { title: 'Impressum', component: TenantImpress, diff --git a/app/Domains/Event/Actions/CreateEvent/CreateEventCommand.php b/app/Domains/Event/Actions/CreateEvent/CreateEventCommand.php index 4432649..11e1374 100644 --- a/app/Domains/Event/Actions/CreateEvent/CreateEventCommand.php +++ b/app/Domains/Event/Actions/CreateEvent/CreateEventCommand.php @@ -3,10 +3,12 @@ namespace App\Domains\Event\Actions\CreateEvent; use App\Enumerations\EatingHabit; +use App\Models\AvailablePaymentMethod; use App\Models\Event; use App\Models\Tenant; use App\RelationModels\EventEatingHabits; use App\RelationModels\EventLocalGroups; +use App\RelationModels\EventPaymentMethods; use Illuminate\Support\Str; class CreateEventCommand { @@ -41,7 +43,7 @@ class CreateEventCommand { 'account_iban' => $this->request->accountIban, 'participation_fee_type' => $this->request->participationFeeType->slug, 'pay_per_day' => $this->request->payPerDay, - 'pay_direct' => $this->request->payDirect, + 'pay_direct' => false, 'total_max_amount' => 0, 'support_per_person' => 0, 'support_flat' => 0, @@ -58,6 +60,13 @@ class CreateEventCommand { 'eating_habit_id' => EatingHabit::where('slug', EatingHabit::EATING_HABIT_VEGETARIAN)->first()->id, ]); + foreach (AvailablePaymentMethod::where('active', true)->get() as $availablePaymentMethod) { + EventPaymentMethods::create([ + 'event_id' => $event->id, + 'available_payment_method_id' => $availablePaymentMethod->id, + ]); + } + if (app('tenant')->slug === 'lv') { foreach(Tenant::where(['is_active_local_group' => true])->get() as $tenant) { EventLocalGroups::create(['event_id' => $event->id, 'local_group_id' => $tenant->id]); diff --git a/app/Domains/Event/Actions/CreateEvent/CreateEventRequest.php b/app/Domains/Event/Actions/CreateEvent/CreateEventRequest.php index 87844d5..dbf5ed5 100644 --- a/app/Domains/Event/Actions/CreateEvent/CreateEventRequest.php +++ b/app/Domains/Event/Actions/CreateEvent/CreateEventRequest.php @@ -19,9 +19,8 @@ class CreateEventRequest { public string $accountOwner; public string $accountIban; public bool $payPerDay; - public bool $payDirect; - public function __construct(string $name, string $location, string $postalCode, string $email, DateTime $begin, DateTime $end, DateTime $earlyBirdEnd, DateTime $registrationFinalEnd, int $earlyBirdEndAmountIncrease, ParticipationFeeType $participationFeeType, string $accountOwner, string $accountIban, bool $payPerDay, bool $payDirect) { + public function __construct(string $name, string $location, string $postalCode, string $email, DateTime $begin, DateTime $end, DateTime $earlyBirdEnd, DateTime $registrationFinalEnd, int $earlyBirdEndAmountIncrease, ParticipationFeeType $participationFeeType, string $accountOwner, string $accountIban, bool $payPerDay) { $this->name = $name; $this->location = $location; $this->postalCode = $postalCode; @@ -35,6 +34,5 @@ class CreateEventRequest { $this->accountOwner = $accountOwner; $this->accountIban = $accountIban; $this->payPerDay = $payPerDay; - $this->payDirect = $payDirect; } } diff --git a/app/Domains/Event/Actions/SignUp/SignUpCommand.php b/app/Domains/Event/Actions/SignUp/SignUpCommand.php index c454281..5c2b730 100644 --- a/app/Domains/Event/Actions/SignUp/SignUpCommand.php +++ b/app/Domains/Event/Actions/SignUp/SignUpCommand.php @@ -21,6 +21,8 @@ class SignUpCommand { }; $participantAge = new Age($this->request->birthday); + $paymentMethod = $this->request->event->paymentMethods()->where('active', true)->first(); + $response->participant = $this->request->event->participants()->create( [ 'tenant' => $this->request->event->tenant, @@ -60,6 +62,7 @@ class SignUpCommand { 'notes' => $this->request->notes, 'amount' => $this->request->amount, 'payment_purpose' => $this->request->event->name . ' - Beitrag ' . $this->request->firstname . ' ' . $this->request->lastname, + 'payment_method' => $paymentMethod?->slug, // available_payment_methods.slug === payment_methods.slug 'efz_status' => $participantAge->isfullAged() ? EfzStatus::EFZ_STATUS_NOT_CHECKED : EfzStatus::EFZ_STATUS_NOT_REQUIRED, ] ); diff --git a/app/Domains/Event/Actions/UpdateEvent/UpdateEventCommand.php b/app/Domains/Event/Actions/UpdateEvent/UpdateEventCommand.php index 1acebf3..2105215 100644 --- a/app/Domains/Event/Actions/UpdateEvent/UpdateEventCommand.php +++ b/app/Domains/Event/Actions/UpdateEvent/UpdateEventCommand.php @@ -11,6 +11,12 @@ class UpdateEventCommand { public function execute() : UpdateEventResponse { $response = new UpdateEventResponse(); + if (count($this->request->paymentMethods) === 0) { + $response->success = false; + $response->message = 'Mindestens eine Zahlungsmöglichkeit muss ausgewählt sein.'; + return $response; + } + $this->request->event->name = $this->request->eventName; $this->request->event->location = $this->request->eventLocation; $this->request->event->postal_code = $this->request->postalCode; @@ -26,6 +32,7 @@ class UpdateEventCommand { $this->request->event->resetAllowedEatingHabits(); $this->request->event->resetContributingLocalGroups(); + $this->request->event->resetPaymentMethods(); foreach($this->request->eatingHabits as $eatingHabit) { $this->request->event->eatingHabits()->attach($eatingHabit); @@ -35,6 +42,10 @@ class UpdateEventCommand { $this->request->event->localGroups()->attach($contributingLocalGroup); } + foreach($this->request->paymentMethods as $paymentMethod) { + $this->request->event->paymentMethods()->attach($paymentMethod); + } + $this->request->event->save(); $response->success = true; diff --git a/app/Domains/Event/Actions/UpdateEvent/UpdateEventRequest.php b/app/Domains/Event/Actions/UpdateEvent/UpdateEventRequest.php index 4c9edd4..965b2d5 100644 --- a/app/Domains/Event/Actions/UpdateEvent/UpdateEventRequest.php +++ b/app/Domains/Event/Actions/UpdateEvent/UpdateEventRequest.php @@ -21,8 +21,9 @@ class UpdateEventRequest { public Amount $supportPerPerson; public array $contributingLocalGroups; public array $eatingHabits; + public array $paymentMethods; - public function __construct(Event $event, string $eventName, string $eventLocation, string $postalCode, string $email, DateTime $earlyBirdEnd, DateTime $registrationFinalEnd, int $alcoholicsAge, bool $sendWeeklyReports, bool $registrationAllowed, Amount $flatSupport, Amount $supportPerPerson, array $contributingLocalGroups, array $eatingHabits) { + public function __construct(Event $event, string $eventName, string $eventLocation, string $postalCode, string $email, DateTime $earlyBirdEnd, DateTime $registrationFinalEnd, int $alcoholicsAge, bool $sendWeeklyReports, bool $registrationAllowed, Amount $flatSupport, Amount $supportPerPerson, array $contributingLocalGroups, array $eatingHabits, array $paymentMethods) { $this->event = $event; $this->eventName = $eventName; $this->eventLocation = $eventLocation; @@ -37,5 +38,6 @@ class UpdateEventRequest { $this->supportPerPerson = $supportPerPerson; $this->contributingLocalGroups = $contributingLocalGroups; $this->eatingHabits = $eatingHabits; + $this->paymentMethods = $paymentMethods; } } diff --git a/app/Domains/Event/Actions/UpdateEvent/UpdateEventResponse.php b/app/Domains/Event/Actions/UpdateEvent/UpdateEventResponse.php index c30be98..aa77952 100644 --- a/app/Domains/Event/Actions/UpdateEvent/UpdateEventResponse.php +++ b/app/Domains/Event/Actions/UpdateEvent/UpdateEventResponse.php @@ -4,9 +4,11 @@ namespace App\Domains\Event\Actions\UpdateEvent; class UpdateEventResponse { public bool $success; + public string $message; public function __construct() { $this->success = false; + $this->message = ''; } } diff --git a/app/Domains/Event/Actions/UpdateParticipant/UpdateParticipantCommand.php b/app/Domains/Event/Actions/UpdateParticipant/UpdateParticipantCommand.php index 221c0fb..c333fc0 100644 --- a/app/Domains/Event/Actions/UpdateParticipant/UpdateParticipantCommand.php +++ b/app/Domains/Event/Actions/UpdateParticipant/UpdateParticipantCommand.php @@ -42,6 +42,7 @@ class UpdateParticipantCommand { $p->departure_date = DateTime::createFromFormat('Y-m-d', $this->request->departure); $p->participation_type = $this->request->participationType; $p->eating_habit = $this->request->eatingHabit; + $p->payment_method = $this->request->paymentMethod; $p->allergies = $this->request->allergies; $p->intolerances = $this->request->intolerances; $p->medications = $this->request->medications; diff --git a/app/Domains/Event/Actions/UpdateParticipant/UpdateParticipantRequest.php b/app/Domains/Event/Actions/UpdateParticipant/UpdateParticipantRequest.php index d2ce288..443695a 100644 --- a/app/Domains/Event/Actions/UpdateParticipant/UpdateParticipantRequest.php +++ b/app/Domains/Event/Actions/UpdateParticipant/UpdateParticipantRequest.php @@ -25,6 +25,7 @@ class UpdateParticipantRequest { public string $departure, public string $participationType, public string $eatingHabit, + public ?string $paymentMethod, public ?string $allergies, public ?string $intolerances, public ?string $medications, diff --git a/app/Domains/Event/Controllers/CreateController.php b/app/Domains/Event/Controllers/CreateController.php index 117aa2e..1a9fbab 100644 --- a/app/Domains/Event/Controllers/CreateController.php +++ b/app/Domains/Event/Controllers/CreateController.php @@ -39,7 +39,6 @@ class CreateController extends CommonController { $registrationFinalEnd = DateTime::createFromFormat('Y-m-d', $request->input('eventRegistrationFinalEnd')); $participationFeeType = ParticipationFeeType::where('slug', $request->input('eventParticipationFeeType'))->first(); $payPerDay = $request->input('eventPayPerDay'); - $payDirect = $request->input('eventPayDirectly'); $billingDeadline = clone $eventEnd; $billingDeadline->modify('+6 weeks'); @@ -57,8 +56,7 @@ class CreateController extends CommonController { $participationFeeType, $request->input('eventAccount'), $request->input('eventIban'), - $payPerDay, - $payDirect + $payPerDay ); $wasSuccessful = false; diff --git a/app/Domains/Event/Controllers/DetailsController.php b/app/Domains/Event/Controllers/DetailsController.php index b0d7ebc..d3328d1 100644 --- a/app/Domains/Event/Controllers/DetailsController.php +++ b/app/Domains/Event/Controllers/DetailsController.php @@ -42,6 +42,7 @@ class DetailsController extends CommonController { $contributinLocalGroups = $request->input('contributingLocalGroups'); $eatingHabits = $request->input('eatingHabits'); + $paymentMethods = $request->input('paymentMethods'); $eventUpdateRequest = new UpdateEventRequest( $event, @@ -57,13 +58,14 @@ class DetailsController extends CommonController { $flatSupport, $supportPerPerson, $contributinLocalGroups, - $eatingHabits + $eatingHabits, + $paymentMethods ); $eventUpdateCommand = new UpdateEventCommand($eventUpdateRequest); $response = $eventUpdateCommand->execute(); - return response()->json(['status' => $response->success ? 'success' : 'error']); + return response()->json(['status' => $response->success ? 'success' : 'error', 'message' => $response->message]); } public function updateEventManagers(int $eventId, Request $request) : JsonResponse { diff --git a/app/Domains/Event/Controllers/ParticipantUpdateController.php b/app/Domains/Event/Controllers/ParticipantUpdateController.php index 869bc51..f4d1dbc 100644 --- a/app/Domains/Event/Controllers/ParticipantUpdateController.php +++ b/app/Domains/Event/Controllers/ParticipantUpdateController.php @@ -33,6 +33,7 @@ class ParticipantUpdateController extends CommonController { departure: $request->input('departure'), participationType: $request->input('participationType'), eatingHabit: $request->input('eatingHabit'), + paymentMethod: $request->input('paymentMethod'), allergies: $request->input('allergies'), intolerances: $request->input('intolerances'), medications: $request->input('medications'), diff --git a/app/Domains/Event/Views/Create.vue b/app/Domains/Event/Views/Create.vue index 2c3c359..310cd5d 100644 --- a/app/Domains/Event/Views/Create.vue +++ b/app/Domains/Event/Views/Create.vue @@ -31,7 +31,6 @@ eventRegistrationFinalEnd: '', eventAccount: props.eventAccount ? props.eventAccount : '', eventIban: props.eventIban ? props.eventIban : '', - eventPayDirectly: true, eventPayPerDay: props.eventPayPerDay ? props.eventPayPerDay : false, eventParticipationFeeType: props.participationFeeType ? props.participationFeeType : 'fixed', }); @@ -154,7 +153,6 @@ eventRegistrationFinalEnd: formData.eventRegistrationFinalEnd, eventAccount: formData.eventAccount, eventIban: formData.eventIban, - eventPayDirectly: formData.eventPayDirectly, eventPayPerDay: formData.eventPayPerDay, eventParticipationFeeType: formData.eventParticipationFeeType, } @@ -262,13 +260,6 @@ - - - - Teilnehmende zahlen direkt aufs Veranstaltungskonto - - - diff --git a/app/Domains/Event/Views/Partials/CommonSettings.vue b/app/Domains/Event/Views/Partials/CommonSettings.vue index 738a2fa..22d5737 100644 --- a/app/Domains/Event/Views/Partials/CommonSettings.vue +++ b/app/Domains/Event/Views/Partials/CommonSettings.vue @@ -15,11 +15,13 @@ const dynmicProps = reactive({ localGroups: [], - eatingHabits:[] + eatingHabits:[], + paymentMethods: [] }); const contributingLocalGroups = ref([]) const eatingHabits = ref([]); + const paymentMethods = ref([]); const errors = reactive({}) @@ -46,9 +48,18 @@ contributingLocalGroups.value = props.event.contributingLocalGroups?.map(t => t.id) ?? [] eatingHabits.value = props.event.eatingHabits?.map(t => t.id) ?? [] + paymentMethods.value = props.event.paymentMethods?.map(t => t.id) ?? [] }); async function save() { + if (paymentMethods.value.length === 0) { + toast.error('Mindestens eine Zahlungsmöglichkeit muss ausgewählt sein.') + return + } else if(paymentMethods.value.length > 1) { + toast.error('Aktuell wird nur exakt eine Zahlungseinstellung unterstützt.') + return + } + const response = await request('/api/v1/event/details/' + props.event.id + '/common-settings', { method: 'POST', headers: { @@ -68,6 +79,7 @@ supportPerson: formData.supportPerson, contributingLocalGroups: contributingLocalGroups.value, eatingHabits: eatingHabits.value, + paymentMethods: paymentMethods.value, } }) @@ -75,7 +87,7 @@ toast.success('Einstellungen wurden erfolgreich gespeichert.') emit('close') } else { - toast.error('Beim Speichern ist ein Fehler aufgetreten.') + toast.error(response.message ?? 'Beim Speichern ist ein Fehler aufgetreten.') } } @@ -199,6 +211,17 @@ + + + Zahlungsmöglichkeiten + + + + + + + + diff --git a/app/Domains/Event/Views/Partials/ParticipantData.vue b/app/Domains/Event/Views/Partials/ParticipantData.vue index 26c07f8..fe7606b 100644 --- a/app/Domains/Event/Views/Partials/ParticipantData.vue +++ b/app/Domains/Event/Views/Partials/ParticipantData.vue @@ -49,6 +49,7 @@ const form = reactive({ departure: '', participationType: '', eatingHabit: '', + paymentMethod: '', allergies: '', intolerances: '', medications: '', @@ -82,6 +83,7 @@ watch( form.departure = participant?.departureDate ?? ''; form.participationType = participant?.participation_type ?? ''; form.eatingHabit = participant?.eating_habit ?? ''; + form.paymentMethod = participant?.payment_method ?? ''; form.allergies = participant?.allergies ?? ''; form.intolerances = participant?.intolerances ?? ''; form.medications = participant?.medications ?? ''; @@ -206,7 +208,7 @@ function saveParticipant() { Telefon - + @@ -230,7 +232,7 @@ function saveParticipant() { Ansprechperson Telefon - + @@ -284,6 +286,20 @@ function saveParticipant() { + + Zahlungsmethode + + {{ props.participant.paymentMethod }} + + + eFZ-Status diff --git a/app/Installer/ProductionDataSeeder.php b/app/Installer/ProductionDataSeeder.php index b998645..a0e740d 100644 --- a/app/Installer/ProductionDataSeeder.php +++ b/app/Installer/ProductionDataSeeder.php @@ -14,6 +14,7 @@ use App\Enumerations\ParticipationType; use App\Enumerations\SwimmingPermission; use App\Enumerations\UserRole; use App\Models\CronTask; +use App\Models\PaymentMethod; use App\Models\Tenant; class ProductionDataSeeder { @@ -28,6 +29,12 @@ class ProductionDataSeeder { $this->installParticipationFeeTypes(); $this->installParticipationTypes(); $this->installEfzStatus(); + $this->installPaymentMethods(); + } + + private function installPaymentMethods() { + PaymentMethod::create(['slug' => PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION]); + PaymentMethod::create(['slug' => PaymentMethod::PAYMENT_NOT_DEFINED]); } private function installEfzStatus() { diff --git a/app/Mail/EventReportMails/PaymentMethodsExhaustedMail.php b/app/Mail/EventReportMails/PaymentMethodsExhaustedMail.php new file mode 100644 index 0000000..806eea6 --- /dev/null +++ b/app/Mail/EventReportMails/PaymentMethodsExhaustedMail.php @@ -0,0 +1,46 @@ +event->name + ); + + return new Envelope( + subject: $subject, + ); + } + + /** + * Get the message content definition. + */ + public function content(): Content + { + return new Content( + view: 'emails.events.payment_methods_exhausted', + with: [ + 'eventTitle' => $this->event->name, + ], + ); + } +} diff --git a/app/Models/AvailablePaymentMethod.php b/app/Models/AvailablePaymentMethod.php new file mode 100644 index 0000000..d2d81f8 --- /dev/null +++ b/app/Models/AvailablePaymentMethod.php @@ -0,0 +1,42 @@ + 'boolean', + ]; + + public function paymentMethod(): BelongsTo + { + return $this->belongsTo(PaymentMethod::class, 'slug', 'slug'); + } + + public function events(): BelongsToMany + { + return $this->belongsToMany(Event::class, 'event_payment_methods')->withTimestamps(); + } +} diff --git a/app/Models/Event.php b/app/Models/Event.php index 9e9421a..5ce8b69 100644 --- a/app/Models/Event.php +++ b/app/Models/Event.php @@ -153,6 +153,10 @@ class Event extends InstancedModel return $this->belongsToMany(EatingHabit::class, 'event_allowed_eating_habits', 'event_id', 'eating_habit_id'); } + public function paymentMethods() : BelongsToMany { + return $this->belongsToMany(AvailablePaymentMethod::class, 'event_payment_methods', 'event_id', 'available_payment_method_id')->withTimestamps(); + } + public function resetContributingLocalGroups() { $this->localGroups()->detach(); $this->save(); @@ -163,6 +167,11 @@ class Event extends InstancedModel $this->save(); } + public function resetPaymentMethods() { + $this->paymentMethods()->detach(); + $this->save(); + } + public function resetMangers() { $this->eventManagers()->detach(); $this->save(); diff --git a/app/Models/EventParticipant.php b/app/Models/EventParticipant.php index 4da71a2..dc39eeb 100644 --- a/app/Models/EventParticipant.php +++ b/app/Models/EventParticipant.php @@ -64,6 +64,7 @@ class EventParticipant extends InstancedModel 'amount', 'amount_paid', 'payment_purpose', + 'payment_method', 'efz_status', 'unregistered_at', ]; @@ -126,6 +127,11 @@ class EventParticipant extends InstancedModel return $this->belongsTo(EatingHabit::class, 'eating_habits', 'slug'); } + public function paymentMethod() + { + return $this->belongsTo(\App\Models\PaymentMethod::class, 'payment_method', 'slug'); + } + public function firstAidPermission() { return $this->belongsTo(FirstAidPermission::class, 'first_aid_permission', 'slug'); diff --git a/app/Models/PaymentMethod.php b/app/Models/PaymentMethod.php new file mode 100644 index 0000000..07ee071 --- /dev/null +++ b/app/Models/PaymentMethod.php @@ -0,0 +1,30 @@ + ['name' => 'Überweisung auf Veranstaltungskonto', 'description' => null], + self::PAYMENT_NOT_DEFINED => ['name' => 'Sonstiges (Barzahlung, Zahlung vor Ort)', 'description' => null], + ]; + + protected $fillable = [ + 'slug', + ]; +} diff --git a/app/Providers/GlobalDataProvider.php b/app/Providers/GlobalDataProvider.php index 5383949..9e7c5c9 100644 --- a/app/Providers/GlobalDataProvider.php +++ b/app/Providers/GlobalDataProvider.php @@ -5,6 +5,7 @@ namespace App\Providers; use App\Enumerations\EatingHabit; use App\Enumerations\InvoiceType; use App\Enumerations\UserRole; +use App\Models\AvailablePaymentMethod; use App\Models\Tenant; use App\Models\User; use App\Repositories\EventRepository; @@ -187,6 +188,7 @@ class GlobalDataProvider { [ 'localGroups' => Tenant::where(['is_active_local_group' => true])->get(), 'eatingHabits' => EatingHabit::all(), + 'paymentMethods' => AvailablePaymentMethod::where('active', true)->get(), ]); } diff --git a/app/RelationModels/EventPaymentMethods.php b/app/RelationModels/EventPaymentMethods.php new file mode 100644 index 0000000..0da9ef3 --- /dev/null +++ b/app/RelationModels/EventPaymentMethods.php @@ -0,0 +1,11 @@ +availablePaymentMethod = $availablePaymentMethod; + } + + public function toArray($request) : array { + return [ + 'id' => $this->availablePaymentMethod->id, + 'slug' => $this->availablePaymentMethod->slug, + 'name' => $this->availablePaymentMethod->name, + 'description' => $this->availablePaymentMethod->description, + 'active' => $this->availablePaymentMethod->active, + ]; + } +} diff --git a/app/Resources/EventParticipantResource.php b/app/Resources/EventParticipantResource.php index 62ed6e2..5d19f12 100644 --- a/app/Resources/EventParticipantResource.php +++ b/app/Resources/EventParticipantResource.php @@ -5,7 +5,9 @@ namespace App\Resources; use App\Enumerations\EatingHabit; use App\Enumerations\EfzStatus; use App\Enumerations\ParticipationType; +use App\Models\AvailablePaymentMethod; use App\Models\EventParticipant; +use App\Models\PaymentMethod; use App\ValueObjects\Age; use Illuminate\Http\Resources\Json\JsonResource; @@ -52,7 +54,9 @@ class EventParticipantResource extends JsonResource 'tetanusVaccinationEdit' => $this->resource->tetanus_vaccination?->format('Y-m-d') ?? null, 'presenceDays' => ['real' => $presenceDays, 'support' => $presenceDaysSupport], 'participationType' => ParticipationType::where(['slug' => $this->resource->participation_type])->first()->name, - 'needs_payment' => $this->resource->amount->getAmount() > 0 && $event->pay_direct && $this->resource->amount_paid?->getAmount() < $this->resource->amount->getAmount(), + 'needs_payment' => $this->resource->amount->getAmount() > 0 + && $this->resource->payment_method === PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION + && $this->resource->amount_paid?->getAmount() < $this->resource->amount->getAmount(), 'nicename' => $this->resource->getNicename(), 'arrival' => $this->resource->arrival_date->format('d.m.Y'), 'departure' => $this->resource->departure_date->format('d.m.Y'), @@ -68,6 +72,9 @@ class EventParticipantResource extends JsonResource 'localGroupState' => null !== $this->resource->localGroup()->first()?->postcode ? config('postCode.map.' . $this->resource->postcode) : '--', 'birthday' => $this->resource->birthday->format('d.m.Y'), 'eatingHabit' => EatingHabit::where('slug', $this->resource->eating_habit)->first()->name, + 'paymentMethod' => $this->resource->payment_method !== null + ? AvailablePaymentMethod::withoutGlobalScopes()->where('tenant', $this->resource->tenant)->where('slug', $this->resource->payment_method)->first()?->name ?? $this->resource->payment_method + : null, 'cocColor' => match ($this->resource->efz_status) { EfzStatus::EFZ_STATUS_CHECKED_VALID => 'bg-green', EfzStatus::EFZ_STATUS_NOT_REQUIRED => 'bg-green', diff --git a/app/Resources/EventResource.php b/app/Resources/EventResource.php index 72b373b..602e4ef 100644 --- a/app/Resources/EventResource.php +++ b/app/Resources/EventResource.php @@ -134,6 +134,9 @@ class EventResource extends JsonResource{ $returnArray['eatingHabits'] = $this->event->eatingHabits()->get()->map( fn($eatingHabit) => new EatingHabitResource($eatingHabit))->toArray(); + $returnArray['paymentMethods'] = $this->event->paymentMethods()->get()->map( + fn($paymentMethod) => new AvailablePaymentMethodResource($paymentMethod))->toArray(); + $returnArray['participationTypes'] = []; diff --git a/database/migrations/2026_07_28_140010_create_payment_methods.php b/database/migrations/2026_07_28_140010_create_payment_methods.php new file mode 100644 index 0000000..1d90bda --- /dev/null +++ b/database/migrations/2026_07_28_140010_create_payment_methods.php @@ -0,0 +1,38 @@ +uuid('id')->primary(); + $table->string('slug')->unique(); + $table->timestamps(); + }); + + Schema::create('available_payment_methods', function (Blueprint $table) { + $table->id(); + $table->string('tenant'); + $table->string('slug'); + $table->string('name'); + $table->string('description')->nullable(); + $table->boolean('active')->default(true); + $table->timestamps(); + + $table->foreign('tenant')->references('slug')->on('tenants')->restrictOnDelete()->cascadeOnUpdate(); + $table->foreign('slug')->references('slug')->on('payment_methods')->restrictOnDelete()->cascadeOnUpdate(); + $table->unique(['tenant', 'slug']); + }); + } + + public function down(): void + { + Schema::dropIfExists('available_payment_methods'); + Schema::dropIfExists('payment_methods'); + } +}; diff --git a/database/migrations/2026_07_28_140020_create_event_payment_methods.php b/database/migrations/2026_07_28_140020_create_event_payment_methods.php new file mode 100644 index 0000000..b327d1d --- /dev/null +++ b/database/migrations/2026_07_28_140020_create_event_payment_methods.php @@ -0,0 +1,24 @@ +id(); + $table->foreignId('event_id')->constrained('events', 'id')->restrictOnDelete()->cascadeOnUpdate(); + $table->foreignId('available_payment_method_id')->constrained('available_payment_methods', 'id')->restrictOnDelete()->cascadeOnUpdate(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('event_payment_methods'); + } +}; diff --git a/database/migrations/2026_07_28_140030_add_payment_method_to_event_participants.php b/database/migrations/2026_07_28_140030_add_payment_method_to_event_participants.php new file mode 100644 index 0000000..c8a7247 --- /dev/null +++ b/database/migrations/2026_07_28_140030_add_payment_method_to_event_participants.php @@ -0,0 +1,25 @@ +string('payment_method')->nullable()->after('payment_purpose'); + $table->foreign('payment_method')->references('slug')->on('payment_methods')->restrictOnDelete()->cascadeOnUpdate(); + }); + } + + public function down(): void + { + Schema::table('event_participants', function (Blueprint $table) { + $table->dropForeign(['payment_method']); + $table->dropColumn('payment_method'); + }); + } +}; diff --git a/resources/views/emails/events/payment_methods_exhausted.blade.php b/resources/views/emails/events/payment_methods_exhausted.blade.php new file mode 100644 index 0000000..e49fd82 --- /dev/null +++ b/resources/views/emails/events/payment_methods_exhausted.blade.php @@ -0,0 +1,16 @@ + + + +

+ Für die Veranstaltung "{{ $eventTitle }}" wurde die letzte aktive Zahlungsmöglichkeit deaktiviert. +

+

+ Die Anmeldung für diese Veranstaltung wurde deshalb automatisch deaktiviert, da aktuell keine + Zahlungsmöglichkeit mehr zur Verfügung steht. +

+

+ Bitte aktiviert mindestens eine Zahlungsmöglichkeit für diese Veranstaltung, um die Anmeldung wieder + zu ermöglichen. +

+ + From ab3d52621724bc0e999af85a63aaee4c5af1d9dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Tue, 28 Jul 2026 16:09:38 +0200 Subject: [PATCH 2/8] Basic implementation of payment methods --- .../RemovePaymentMethodUsageAction.php | 2 +- .../Event/Actions/CreateEvent/CreateEventCommand.php | 2 +- app/Domains/Event/Actions/SignUp/SignUpCommand.php | 3 +-- app/Domains/Event/Actions/SignUp/SignUpRequest.php | 3 ++- app/Domains/Event/Controllers/SignupController.php | 11 +++++++++-- app/Domains/Event/Views/Partials/CommonSettings.vue | 4 ++-- .../Event/Views/Partials/SignUpForm/SignupForm.vue | 3 ++- .../Partials/SignUpForm/composables/useSignupForm.js | 3 ++- app/Domains/Event/Views/Signup.vue | 2 ++ app/Models/AvailablePaymentMethod.php | 4 +++- app/Models/Event.php | 5 ++++- app/RelationModels/EventPaymentMethods.php | 2 +- ...2026_07_28_140020_create_event_payment_methods.php | 5 ++++- 13 files changed, 34 insertions(+), 15 deletions(-) diff --git a/app/Domains/Admin/Actions/RemovePaymentMethodUsage/RemovePaymentMethodUsageAction.php b/app/Domains/Admin/Actions/RemovePaymentMethodUsage/RemovePaymentMethodUsageAction.php index 523dedf..27e5c63 100644 --- a/app/Domains/Admin/Actions/RemovePaymentMethodUsage/RemovePaymentMethodUsageAction.php +++ b/app/Domains/Admin/Actions/RemovePaymentMethodUsage/RemovePaymentMethodUsageAction.php @@ -11,7 +11,7 @@ class RemovePaymentMethodUsageAction public function execute(AvailablePaymentMethod $availablePaymentMethod): void { foreach ($availablePaymentMethod->events()->get() as $event) { - $event->paymentMethods()->detach($availablePaymentMethod->id); + $event->paymentMethods()->detach($availablePaymentMethod->slug); $remainingActive = $event->paymentMethods()->where('active', true)->count(); if ($remainingActive === 0 && $event->registration_allowed) { diff --git a/app/Domains/Event/Actions/CreateEvent/CreateEventCommand.php b/app/Domains/Event/Actions/CreateEvent/CreateEventCommand.php index 11e1374..636f4de 100644 --- a/app/Domains/Event/Actions/CreateEvent/CreateEventCommand.php +++ b/app/Domains/Event/Actions/CreateEvent/CreateEventCommand.php @@ -63,7 +63,7 @@ class CreateEventCommand { foreach (AvailablePaymentMethod::where('active', true)->get() as $availablePaymentMethod) { EventPaymentMethods::create([ 'event_id' => $event->id, - 'available_payment_method_id' => $availablePaymentMethod->id, + 'slug' => $availablePaymentMethod->slug, ]); } diff --git a/app/Domains/Event/Actions/SignUp/SignUpCommand.php b/app/Domains/Event/Actions/SignUp/SignUpCommand.php index 5c2b730..48667a4 100644 --- a/app/Domains/Event/Actions/SignUp/SignUpCommand.php +++ b/app/Domains/Event/Actions/SignUp/SignUpCommand.php @@ -21,7 +21,6 @@ class SignUpCommand { }; $participantAge = new Age($this->request->birthday); - $paymentMethod = $this->request->event->paymentMethods()->where('active', true)->first(); $response->participant = $this->request->event->participants()->create( [ @@ -62,7 +61,7 @@ class SignUpCommand { 'notes' => $this->request->notes, 'amount' => $this->request->amount, 'payment_purpose' => $this->request->event->name . ' - Beitrag ' . $this->request->firstname . ' ' . $this->request->lastname, - 'payment_method' => $paymentMethod?->slug, // available_payment_methods.slug === payment_methods.slug + 'payment_method' => $this->request->paymentMethod, 'efz_status' => $participantAge->isfullAged() ? EfzStatus::EFZ_STATUS_NOT_CHECKED : EfzStatus::EFZ_STATUS_NOT_REQUIRED, ] ); diff --git a/app/Domains/Event/Actions/SignUp/SignUpRequest.php b/app/Domains/Event/Actions/SignUp/SignUpRequest.php index 778aa15..fc6d648 100644 --- a/app/Domains/Event/Actions/SignUp/SignUpRequest.php +++ b/app/Domains/Event/Actions/SignUp/SignUpRequest.php @@ -44,7 +44,8 @@ class SignUpRequest { public int $arrival_eating, public int $departure_eating, public ?string $notes, - public Amount $amount + public Amount $amount, + public ?string $paymentMethod, ) { } } diff --git a/app/Domains/Event/Controllers/SignupController.php b/app/Domains/Event/Controllers/SignupController.php index 01bcd6d..01f82d1 100644 --- a/app/Domains/Event/Controllers/SignupController.php +++ b/app/Domains/Event/Controllers/SignupController.php @@ -24,7 +24,12 @@ class SignupController extends CommonController { $availableEvents[] = $event->toResource()->toArray($request); }; - $event = $this->events->getByIdentifier($eventId, false)?->toResource()->toArray($request); + $eventModel = $this->events->getByIdentifier($eventId, false); + $event = $eventModel?->toResource()->toArray($request); + // Aktuell ist genau eine aktive Zahlungsmethode je Event vorgesehen; wird bereits beim Start + // der Anmeldung ermittelt und ans Frontend durchgereicht, statt erst bei der Erstellung des + // Teilnehmenden (siehe SignUpCommand). + $paymentMethod = $eventModel?->paymentMethods()->where('active', true)->first(); $participantData = [ 'firstname' => '', @@ -62,6 +67,7 @@ class SignupController extends CommonController { 'availableEvents' => $availableEvents, 'localGroups' => $event['contributingLocalGroups'], 'participantData' => $participantData, + 'paymentMethod' => $paymentMethod?->slug, ]); return $inertiaProvider->render(); } @@ -136,7 +142,8 @@ class SignupController extends CommonController { $registrationData['anreise_essen'], $registrationData['abreise_essen'], $registrationData['anmerkungen'], - $amount + $amount, + $registrationData['paymentMethod'] ?? null, ); $signupCommand = new SignUpCommand($signupRequest); diff --git a/app/Domains/Event/Views/Partials/CommonSettings.vue b/app/Domains/Event/Views/Partials/CommonSettings.vue index 22d5737..944b66d 100644 --- a/app/Domains/Event/Views/Partials/CommonSettings.vue +++ b/app/Domains/Event/Views/Partials/CommonSettings.vue @@ -48,7 +48,7 @@ contributingLocalGroups.value = props.event.contributingLocalGroups?.map(t => t.id) ?? [] eatingHabits.value = props.event.eatingHabits?.map(t => t.id) ?? [] - paymentMethods.value = props.event.paymentMethods?.map(t => t.id) ?? [] + paymentMethods.value = props.event.paymentMethods?.map(t => t.slug) ?? [] }); async function save() { @@ -218,7 +218,7 @@ - + diff --git a/app/Domains/Event/Views/Partials/SignUpForm/SignupForm.vue b/app/Domains/Event/Views/Partials/SignUpForm/SignupForm.vue index 4f751a5..af4b0f3 100644 --- a/app/Domains/Event/Views/Partials/SignUpForm/SignupForm.vue +++ b/app/Domains/Event/Views/Partials/SignUpForm/SignupForm.vue @@ -16,6 +16,7 @@ const props = defineProps({ event: Object, participantData: Object, localGroups: Array, + paymentMethod: String, }) const emit = defineEmits(['registrationDone']) @@ -23,7 +24,7 @@ const emit = defineEmits(['registrationDone']) const { currentStep, goToStep, formData, selectedAddons, submit, submitting, submitResult, summaryLoading, summaryAmount -} = useSignupForm(props.event, props.participantData) +} = useSignupForm(props.event, props.participantData, props.paymentMethod) const steps = [ { step: 1, label: 'Alter' }, diff --git a/app/Domains/Event/Views/Partials/SignUpForm/composables/useSignupForm.js b/app/Domains/Event/Views/Partials/SignUpForm/composables/useSignupForm.js index a6ae1d5..3f7cd32 100644 --- a/app/Domains/Event/Views/Partials/SignUpForm/composables/useSignupForm.js +++ b/app/Domains/Event/Views/Partials/SignUpForm/composables/useSignupForm.js @@ -1,7 +1,7 @@ import { ref, reactive, computed } from 'vue' import axios from 'axios' -export function useSignupForm(event, participantData) { +export function useSignupForm(event, participantData, paymentMethod) { const currentStep = ref(1) const submitting = ref(false) const summaryLoading = ref(false) @@ -11,6 +11,7 @@ export function useSignupForm(event, participantData) { const formData = reactive({ eatingHabit: 'EATING_HABIT_VEGAN', + paymentMethod: paymentMethod ?? null, userId: participantData.id, eventId: event.id, vorname: participantData.firstname ?? '', diff --git a/app/Domains/Event/Views/Signup.vue b/app/Domains/Event/Views/Signup.vue index a941154..d1b035b 100644 --- a/app/Domains/Event/Views/Signup.vue +++ b/app/Domains/Event/Views/Signup.vue @@ -12,6 +12,7 @@ const props = defineProps({ availableEvents: Array, participantData: Object, localGroups: Array, + paymentMethod: String, }) const showSignup = ref(true) @@ -103,6 +104,7 @@ function close() { :event="props.event" :participantData="props.participantData ?? {}" :localGroups="props.localGroups ?? []" + :paymentMethod="props.paymentMethod ?? null" />