230 lines
9.0 KiB
PHP
230 lines
9.0 KiB
PHP
<?php
|
|
|
|
namespace App\Domains\Event\Actions\UpdateParticipant;
|
|
|
|
use App\Enumerations\EfzStatus;
|
|
use App\Mail\ParticipantCocMails\ParticipantCocCompleteMail;
|
|
use App\Mail\ParticipantCocMails\ParticipantCocInvalidMail;
|
|
use App\Mail\ParticipantPaymentMails\ParticipantPaymentMissingPaymentMail;
|
|
use App\Mail\ParticipantPaymentMails\ParticipantPaymentOverpaidMail;
|
|
use App\Mail\ParticipantPaymentMails\ParticipantPaymentPaidMail;
|
|
use App\Models\EventParticipant;
|
|
use App\Providers\MissingPaymentProvider;
|
|
use App\ValueObjects\Amount;
|
|
use DateTime;
|
|
use Illuminate\Support\Facades\Mail;
|
|
|
|
class UpdateParticipantCommand {
|
|
private UpdateParticipantResponse $response;
|
|
function __construct(public UpdateParticipantRequest $request) {
|
|
}
|
|
|
|
public function execute() {
|
|
$this->response = new UpdateParticipantResponse();
|
|
|
|
$p = clone($this->request->participant);
|
|
|
|
$p->firstname = $this->request->firstname;
|
|
$p->lastname = $this->request->lastname;
|
|
$p->nickname = $this->request->nickname;
|
|
$p->address_1 = $this->request->address_1;
|
|
$p->address_2 = $this->request->address_2;
|
|
$p->postcode = $this->request->postcode;
|
|
$p->city = $this->request->city;
|
|
$p->local_group = $this->request->localgroup;
|
|
$p->birthday = DateTime::createFromFormat('Y-m-d', $this->request->birthday);
|
|
$p->email_1 = $this->request->email_1;
|
|
$p->phone_1 = $this->request->phone_1;
|
|
$p->contact_person = $this->request->contact_person;
|
|
$p->email_2 = $this->request->email_2;
|
|
$p->phone_2 = $this->request->phone_2;
|
|
$p->arrival_date = DateTime::createFromFormat('Y-m-d', $this->request->arrival);
|
|
$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;
|
|
$p->first_aid_permission = $this->request->extendedFirstAid;
|
|
$p->swimming_permission = $this->request->swimmingPermission;
|
|
$p->tetanus_vaccination = $this->request->tetanusVaccination !== null
|
|
? DateTime::createFromFormat('Y-m-d', $this->request->tetanusVaccination)
|
|
: null;
|
|
$p->notes = $this->request->notes;
|
|
$p->amount_paid = Amount::fromString($this->request->amountPaid);
|
|
$p->amount = Amount::fromString($this->request->amountExpected);
|
|
$p->efz_status = $this->request->cocStatus;
|
|
|
|
if (
|
|
MissingPaymentProvider::calculateMissingPayment(amountPaid: $p->amount_paid, amountToPay: $p->amount)->getAmount()
|
|
!==
|
|
MissingPaymentProvider::calculateMissingPayment(amountPaid: $this->request->participant->amount_paid, amountToPay: $this->request->participant->amount)->getAmount()
|
|
) {
|
|
$this->handleAmountChanges($p);
|
|
}
|
|
|
|
if (
|
|
$p->efz_status !== $this->request->participant->efz_status
|
|
) {
|
|
$this->handleCocStatusChange($p);
|
|
}
|
|
|
|
|
|
$p->save();
|
|
|
|
if ($this->request->participationOptions !== null) {
|
|
$this->syncParticipationOptions($p);
|
|
}
|
|
|
|
if ($this->request->selectedAddons !== null) {
|
|
$this->syncAddons($p);
|
|
}
|
|
|
|
$this->response->success = true;
|
|
$this->response->participant = $p;
|
|
return $this->response;
|
|
}
|
|
|
|
/**
|
|
* Ersetzt die zugeordneten Zusätze (Event-Addons) anhand der Auswahl. Bewusst **ohne Preis/Betrag**
|
|
* (amount 0): der Teilnahmebeitrag wird in den Details ohnehin manuell gesetzt. Es wird nur der Titel als
|
|
* Snapshot gespeichert, damit die Zuordnung sichtbar bleibt.
|
|
*/
|
|
private function syncAddons(EventParticipant $participant): void
|
|
{
|
|
$participant->selectedAddons()->delete();
|
|
|
|
$selection = $this->request->selectedAddons ?? [];
|
|
|
|
foreach ($participant->event?->addons ?? [] as $addon) {
|
|
$key = $addon['key'] ?? null;
|
|
if ($key === null || empty($selection[$key])) {
|
|
continue;
|
|
}
|
|
|
|
$participant->selectedAddons()->create([
|
|
'tenant' => $participant->tenant,
|
|
'event_id' => $participant->event_id,
|
|
'addon_key' => $key,
|
|
'title' => $addon['title'] ?? $key,
|
|
'price' => 0,
|
|
'flat' => (bool)($addon['flat'] ?? false),
|
|
'days' => 0,
|
|
'amount' => 0,
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ersetzt die zugeordneten Teilnahmeoptionen anhand der übergebenen Antworten. Nachträgliche Zuordnung im
|
|
* Back-Office ist lückenlos möglich: nur gegen die Event-Definition gültige Antworten werden gespeichert,
|
|
* leere/entfallene Antworten werden abgeräumt. Frage-/Options-Label werden als Snapshot mitgeschrieben.
|
|
*/
|
|
private function syncParticipationOptions(EventParticipant $participant): void
|
|
{
|
|
$participant->selectedOptions()->delete();
|
|
|
|
$answers = $this->request->participationOptions ?? [];
|
|
|
|
foreach ($participant->event?->participation_options ?? [] as $question) {
|
|
$key = $question['key'] ?? null;
|
|
if ($key === null) {
|
|
continue;
|
|
}
|
|
|
|
$value = $answers[$key] ?? null;
|
|
if ($value === null || $value === '') {
|
|
continue;
|
|
}
|
|
|
|
$option = null;
|
|
foreach ($question['options'] ?? [] as $candidate) {
|
|
if (($candidate['value'] ?? null) === $value) {
|
|
$option = $candidate;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($option === null) {
|
|
continue;
|
|
}
|
|
|
|
$label = trim((string)($question['label'] ?? ''));
|
|
|
|
$participant->selectedOptions()->create([
|
|
'tenant' => $participant->tenant,
|
|
'event_id' => $participant->event_id,
|
|
'question_key' => $key,
|
|
'question_label' => $label !== '' ? $label : ($question['title'] ?? $key),
|
|
'value' => $value,
|
|
'value_label' => $option['label'] ?? $value,
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function handleAmountChanges(EventParticipant $participant) {
|
|
$this->response->amountPaid = $participant->amount_paid;
|
|
$this->response->amountExpected = $participant->amount;
|
|
|
|
$amountToPay = MissingPaymentProvider::calculateMissingPayment(
|
|
amountPaid: $participant->amount_paid,
|
|
amountToPay: $participant->amount,
|
|
);
|
|
|
|
switch (true) {
|
|
case $amountToPay->getAmount() > 0:
|
|
Mail::to($participant->email_1)->send(new ParticipantPaymentMissingPaymentMail(
|
|
participant: $participant,
|
|
));
|
|
|
|
if ($participant->email_2 !== null) {
|
|
Mail::to($participant->email_2)->send(new ParticipantPaymentMissingPaymentMail(
|
|
participant: $participant,
|
|
));
|
|
}
|
|
break;
|
|
case $amountToPay->getAmount() < 0:
|
|
Mail::to($participant->email_1)->send(new ParticipantPaymentOverpaidMail(
|
|
participant: $participant,
|
|
));
|
|
|
|
if ($participant->email_2 !== null) {
|
|
Mail::to($participant->email_2)->send(new ParticipantPaymentOverpaidMail(
|
|
participant: $participant,
|
|
));
|
|
}
|
|
break;
|
|
default:
|
|
Mail::to($participant->email_1)->send(new ParticipantPaymentPaidMail(
|
|
participant: $participant,
|
|
));
|
|
|
|
if ($participant->email_2 !== null) {
|
|
Mail::to($participant->email_2)->send(new ParticipantPaymentPaidMail(
|
|
participant: $participant,
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
private function handleCocStatusChange(EventParticipant $participant) {
|
|
$this->response->cocStatus = $participant->efzStatus()->first();
|
|
|
|
switch ($participant->efzStatus()->first()->slug) {
|
|
case EfzStatus::EFZ_STATUS_CHECKED_VALID:
|
|
case EfzStatus::EFZ_STATUS_NOT_REQUIRED:
|
|
Mail::to($participant->email_1)->send(new ParticipantCocCompleteMail(
|
|
participant: $participant,
|
|
));
|
|
break;
|
|
|
|
case EfzStatus::EFZ_STATUS_CHECKED_INVALID:
|
|
Mail::to($participant->email_1)->send(new ParticipantCocInvalidMail(
|
|
participant: $participant,
|
|
));
|
|
break;
|
|
}
|
|
}
|
|
}
|