| 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.
+
+
+
|