135 lines
4.4 KiB
PHP
135 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace App\Domains\ParticipantRefund\Actions\ReleaseRefund;
|
|
|
|
use App\Enumerations\RefundReason;
|
|
use App\Mail\ParticipantRefundMails\RefundReleasedMail;
|
|
use App\Models\EventParticipant;
|
|
use App\Models\ParticipantRefund;
|
|
use App\Repositories\ParticipantRefundRepository;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Illuminate\Support\Str;
|
|
|
|
/**
|
|
* Gibt die Erstattung eines Teilnahmebeitrags frei.
|
|
*
|
|
* Der Vorgang entsteht hier nur als Absichtserklärung: Betrag und Grund stehen fest, die Bankverbindung
|
|
* fehlt noch. Der Teili ergänzt sie über den Link in der Mail. `amount_paid` bleibt unangetastet --
|
|
* gezahlt hat er bis zur Auszahlung weiterhin, was er gezahlt hat.
|
|
*/
|
|
class ReleaseRefundCommand
|
|
{
|
|
private EventParticipant $participant;
|
|
|
|
private ParticipantRefundRepository $refunds;
|
|
|
|
public function __construct(private readonly ReleaseRefundRequest $request)
|
|
{
|
|
$this->participant = $request->participant;
|
|
$this->refunds = new ParticipantRefundRepository();
|
|
}
|
|
|
|
public function execute(): ReleaseRefundResponse
|
|
{
|
|
$response = new ReleaseRefundResponse();
|
|
|
|
$rejection = $this->reject();
|
|
if ($rejection !== null) {
|
|
$response->message = $rejection;
|
|
|
|
return $response;
|
|
}
|
|
|
|
$refund = ParticipantRefund::create([
|
|
'tenant' => $this->participant->tenant,
|
|
'event_id' => $this->participant->event_id,
|
|
'event_participant_id' => $this->participant->id,
|
|
'token' => Str::random(32),
|
|
'status' => ParticipantRefund::STATUS_PENDING,
|
|
'amount' => $this->request->amount,
|
|
'reason' => $this->request->reason,
|
|
'reason_note' => $this->reasonNote(),
|
|
'released_by' => auth()->id(),
|
|
'released_at' => now(),
|
|
]);
|
|
|
|
$this->notify($refund);
|
|
|
|
$response->success = true;
|
|
$response->refund = $refund;
|
|
$response->message = 'Die Erstattung wurde freigegeben. Der Teili wurde per E-Mail informiert.';
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* Alle Gründe, aus denen eine Freigabe nicht zulässig ist.
|
|
*
|
|
* @return string|null Meldung, oder null wenn nichts dagegen spricht.
|
|
*/
|
|
private function reject(): ?string
|
|
{
|
|
if ($this->participant->unregistered_at === null) {
|
|
return 'Eine Erstattung ist nur für abgemeldete Teilis möglich.';
|
|
}
|
|
|
|
if ($this->refunds->openFor($this->participant) !== null) {
|
|
return 'Für diese Anmeldung läuft bereits eine Erstattung.';
|
|
}
|
|
|
|
$amount = $this->request->amount->getAmount();
|
|
if ($amount <= 0) {
|
|
return 'Der Erstattungsbetrag muss größer als 0 sein.';
|
|
}
|
|
|
|
// Mehr zurückgeben als eingegangen ist wäre keine Erstattung mehr. Die halbe Cent-Toleranz
|
|
// fängt die Rundung des gespeicherten Floats ab.
|
|
$paid = $this->participant->amount_paid?->getAmount() ?? 0.0;
|
|
if ($amount > $paid + 0.005) {
|
|
return 'Der Erstattungsbetrag darf den gezahlten Beitrag nicht übersteigen.';
|
|
}
|
|
|
|
$reason = RefundReason::find($this->request->reason);
|
|
if ($reason === null) {
|
|
return 'Bitte wähle einen Erstattungsgrund aus.';
|
|
}
|
|
|
|
if ($reason->requires_note && trim((string) $this->request->reasonNote) === '') {
|
|
return 'Für diesen Grund ist eine Erläuterung erforderlich.';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/** Der Freitext gehört nur zu Gründen, die ihn verlangen -- sonst stünde er ungenutzt in der DB. */
|
|
private function reasonNote(): ?string
|
|
{
|
|
$reason = RefundReason::find($this->request->reason);
|
|
|
|
if ($reason === null || !$reason->requires_note) {
|
|
return null;
|
|
}
|
|
|
|
return trim((string) $this->request->reasonNote);
|
|
}
|
|
|
|
/**
|
|
* Teili und Kontaktperson bekommen je eine eigene Mail -- dasselbe Muster wie bei der Abmeldung
|
|
* (siehe SetParticipationStateCommand).
|
|
*/
|
|
private function notify(ParticipantRefund $refund): void
|
|
{
|
|
Mail::to($this->participant->email_1)->send(new RefundReleasedMail(
|
|
participant: $this->participant,
|
|
refund: $refund,
|
|
));
|
|
|
|
if ($this->participant->email_2 !== null) {
|
|
Mail::to($this->participant->email_2)->send(new RefundReleasedMail(
|
|
participant: $this->participant,
|
|
refund: $refund,
|
|
));
|
|
}
|
|
}
|
|
}
|