Files
mareike/app/Resources/EventParticipantResource.php
T

160 lines
8.7 KiB
PHP

<?php
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\Repositories\ParticipantRefundRepository;
use App\Support\Iban;
use App\ValueObjects\Age;
use Illuminate\Http\Resources\Json\JsonResource;
class EventParticipantResource extends JsonResource
{
function __construct(EventParticipant $participant)
{
parent::__construct($participant);
}
public function toArray($request) : array
{
$event = $this->resource->event;
$amountLeft = clone $this->resource->amount;
if ($this->resource->amount_paid !== null) {
$amountLeft->subtractAmount($this->resource->amount_paid);
}
$paymentSummary = $this->resource->paymentSummary();
$presenceDays = $this->resource->arrival_date->diff($this->resource->departure_date)->days;
if ($presenceDays === 0) {
$presenceDays = 1;
$presenceDaysSupport = 1;
} else {
$presenceDaysSupport = $presenceDays;
$presenceDays++;
}
return array_merge(
$this->resource->toArray(),
[
'birthdayDate' => $this->resource->birthday->format('Y-m-d'),
'arrivalDate' => $this->resource->arrival_date->format('Y-m-d'),
'departureDate' => $this->resource->departure_date->format('Y-m-d'),
'registerDate' => $this->resource->created_at->format('d.m.Y'),
'unregistered' => $this->resource->unregistered_at !== null,
'unregisteredAt' => $this->resource->unregistered_at?->format('d.m.Y'),
'fullname' => $this->resource->getFullName(),
'age' => new Age($this->resource->birthday)->getAge(),
'localgroup' => $this->resource->localGroup()?->first()?->name ?? 'Nicht im LV',
// Die Zuordnungen sind nullable: die Kurzanmeldung erhebt nicht alles, und in der Verwaltung
// lassen sich Werte leeren. Ohne Fallback fielen Teilnehmerliste und Detailansicht komplett aus.
'swimmingPermission' => $this->resource->swimmingPermission()->first()?->short ?? 'Unbekannt',
'extendedFirstAid' => $this->resource->firstAidPermission()->first()?->name ?? 'Unbekannt',
'tetanusVaccination' => $this->resource->tetanus_vaccination?->format('d.m.Y') ?? 'Unbekannt',
'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
?? $this->resource->participation_type,
'needs_payment' => $this->resource->amount->getAmount() > 0
&& $this->resource->payment_method === PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION
&& $this->resource->amount_paid?->getAmount() < $this->resource->amount->getAmount(),
'paymentSummary' => [
'hasPaymentInformation' => $paymentSummary->hasPaymentInformation,
'html' => $paymentSummary->html,
],
'nicename' => $this->resource->getNicename(),
'arrival' => $this->resource->arrival_date->format('d.m.Y'),
'departure' => $this->resource->departure_date->format('d.m.Y'),
'amount_left_string' => $amountLeft->toString(),
'amount_left_value' => $amountLeft->getAmount(),
'email_1' => $this->resource->email_1,
'amountPaid' => ['value' => $this->resource->amount_paid, 'readable' => $this->resource->amount_paid?->toString() ?? '0,00 Euro', 'short' => $this->resource->amount_paid?->getFormattedAmount() ?? '0,00'],
'amountExpected' => ['value' => $this->resource->amount, 'readable' => $this->resource->amount?->toString() ?? '0,00 Euro', 'short' => $this->resource->amount?->getFormattedAmount() ?? '0,00'],
// Numerisch, damit das Frontend rechnen bzw. auf "kostenlos" prüfen kann -- `value` oben ist
// ein Amount-Objekt und serialisiert nicht.
'amountExpectedValue' => $this->resource->amount?->getAmount() ?? 0.0,
'amountPaidValue' => $this->resource->amount_paid?->getAmount() ?? 0.0,
// Der laufende bzw. bestätigte Erstattungsvorgang -- null, wenn keiner existiert oder
// der letzte abgebrochen wurde.
'refund' => $this->refund($request),
'refundData' => $this->refundData(),
'alcoholicsAllowed' => new Age($this->resource->birthday)->getAge() >= $event->alcoholics_age,
'localGroupPostcode' => $this->resource->localGroup()->first()?->postcode ?? '00000',
'localGroupCity' => $this->resource->localGroup()->first()?->city ?? '00000',
'state' => config('postCode.map.' . $this->resource->postcode),
'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 ?? 'Unbekannt',
'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',
EfzStatus::EFZ_STATUS_NOT_CHECKED => 'bg-yellow',
EfzStatus::EFZ_STATUS_CHECKED_INVALID => 'bg-red',
default => 'bg-yellow',
},
'efzStatusReadable' => match($this->resource->efz_status) {
EfzStatus::EFZ_STATUS_CHECKED_VALID => 'Gültig',
EfzStatus::EFZ_STATUS_CHECKED_INVALID => 'Nicht eingereicht',
EfzStatus::EFZ_STATUS_NOT_CHECKED => 'Nicht geprüft',
EfzStatus::EFZ_STATUS_NOT_REQUIRED => 'Nicht erforderlich',
default => 'Nicht geprüft',
},
'eventName' => $this->resource->event()->first()->name,
'eventAddress' => $event->getFullAddress(),
'arrivalDateReadable' => $this->resource->arrival_date->format('d.m.Y'),
'departureDateReadable' => $this->resource->departure_date->format('d.m.Y'),
'participationOptions' => $this->resource->selectedOptions()->get()->map(
fn($option) => new EventParticipantOptionResource($option)->toArray($request))->toArray(),
'selectedAddons' => $this->resource->selectedAddons()->get()->map(
fn($addon) => new EventParticipantAddonResource($addon)->toArray($request))->toArray(),
]
);
}
/**
* Der für die Anzeige maßgebliche Erstattungsvorgang.
*
* Abgebrochene Vorgänge bleiben außen vor: für die Aktionsleitung soll die Anmeldung danach
* aussehen wie vor der Freigabe.
*/
private function refund($request): ?array
{
$refund = new ParticipantRefundRepository()->currentFor($this->resource);
return $refund?->toResource()->toArray($request);
}
/**
* Das Konto, auf das erstattet würde -- sofern die Zahlungsart es kennt.
*
* Unmaskiert: Diese Resource speist die Teilnehmerliste der Aktionsleitung, die IBANs ohnehin
* sehen und eingeben darf. Auf der öffentlichen Erstattungsseite geht dieselbe Angabe maskiert
* hinaus, dort besorgt das der RefundPageController.
*
* @return array<string, mixed>
*/
private function refundData(): array
{
$refundData = $this->resource->refundData();
return [
// `available` heißt für das Frontend: Das Konto steht fest, es wird nicht mehr erfragt.
'available' => $refundData->hasAccount(),
'accountOwner' => $refundData->accountOwner,
'accountIban' => $refundData->accountIban === null
? null
: Iban::format($refundData->accountIban),
'source' => $refundData->sourceNote,
];
}
}