Creating Participation refunds
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\ParticipantRefund\Actions\AcceptRefund;
|
||||
|
||||
use App\Domains\ParticipantRefund\Actions\CreateRefundDocument\CreateRefundDocumentCommand;
|
||||
use App\Domains\ParticipantRefund\Actions\CreateRefundDocument\CreateRefundDocumentRequest;
|
||||
use App\Mail\ParticipantRefundMails\RefundAcceptedMail;
|
||||
use App\Models\ParticipantRefund;
|
||||
use App\Support\Iban;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
/**
|
||||
* Der Teili bestätigt die Erstattung und hinterlegt seine Bankverbindung.
|
||||
*
|
||||
* Läuft ohne Login -- der Token aus der Mail ist die Autorisierung, dasselbe Modell wie bei
|
||||
* /print-girocode/{identifier}. Betrag und Grund stehen fest und werden hier nicht angefasst: sie kommen
|
||||
* aus der Freigabe der Aktionsleitung.
|
||||
*
|
||||
* Danach ist der Vorgang festgeschrieben; der Beleg geht mit der Bestätigungsmail raus.
|
||||
*/
|
||||
class AcceptRefundCommand
|
||||
{
|
||||
/**
|
||||
* Wortlaut für jeden Fall, in dem der Link nicht (mehr) zu einem offenen Vorgang führt.
|
||||
*
|
||||
* Bewusst ein und derselbe Text für „Token unbekannt" und „abgebrochen": eine abgebrochene Freigabe
|
||||
* soll sich verhalten, als hätte es sie nie gegeben.
|
||||
*/
|
||||
public const string NO_OPEN_REFUND = 'Zu deiner Anmeldung liegt keine freigegebene Rückerstattung vor. '
|
||||
. 'Bitte wende dich an die Aktionsleitung.';
|
||||
|
||||
public function __construct(private readonly AcceptRefundRequest $request)
|
||||
{
|
||||
}
|
||||
|
||||
public function execute(): AcceptRefundResponse
|
||||
{
|
||||
$response = new AcceptRefundResponse();
|
||||
$refund = $this->request->refund;
|
||||
|
||||
if ($refund === null || !$refund->isPending()) {
|
||||
$response->message = $refund?->isAccepted() === true
|
||||
? 'Deine Angaben liegen uns bereits vor.'
|
||||
: self::NO_OPEN_REFUND;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$owner = trim($this->request->accountOwner);
|
||||
$iban = Iban::normalize($this->request->accountIban);
|
||||
|
||||
// Serverseitig und nicht nur im Formular: die Erklärung ist der einzige Grund, warum der Beleg
|
||||
// als Eigenbeleg etwas wert ist. Ließe sie sich mit einem direkten Aufruf übergehen, stünde auf
|
||||
// dem PDF eine Zusicherung, die niemand abgegeben hat.
|
||||
if (!$this->request->declarationAccepted) {
|
||||
$response->errorTypes['declaration'] = 'Bitte bestätige die Erklärung, damit wir erstatten können.';
|
||||
}
|
||||
|
||||
if ($owner === '') {
|
||||
$response->errorTypes['accountOwner'] = 'Bitte gib an, wem das Konto gehört.';
|
||||
}
|
||||
|
||||
if ($iban === '') {
|
||||
$response->errorTypes['accountIban'] = 'Bitte gib die IBAN des Kontos ein.';
|
||||
} elseif (!Iban::isValid($iban)) {
|
||||
$response->errorTypes['accountIban'] = 'Diese IBAN stimmt nicht. Bitte prüfe deine Eingabe.';
|
||||
}
|
||||
|
||||
if ($response->errorTypes !== []) {
|
||||
$response->message = 'Bitte prüfe deine Angaben.';
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$refund->account_owner = $owner;
|
||||
$refund->account_iban = $iban;
|
||||
$refund->status = ParticipantRefund::STATUS_ACCEPTED;
|
||||
$refund->accepted_at = now();
|
||||
$refund->save();
|
||||
|
||||
$this->notify($refund);
|
||||
|
||||
$response->success = true;
|
||||
$response->message = 'Vielen Dank. Deine Angaben liegen uns vor.';
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bestätigung mit dem Beleg im Anhang, an Teili und Kontaktperson.
|
||||
*
|
||||
* Scheitert die Belegerzeugung, geht die Mail trotzdem raus -- der Vorgang ist gespeichert, und die
|
||||
* Aktionsleitung kann den Beleg jederzeit erneut abrufen. Ein Fehler hier darf nicht dazu führen,
|
||||
* dass der Teili gar nichts hört.
|
||||
*/
|
||||
private function notify(ParticipantRefund $refund): void
|
||||
{
|
||||
$document = new CreateRefundDocumentCommand(new CreateRefundDocumentRequest($refund))->execute();
|
||||
|
||||
$pdf = $document->success ? $document->pdfContent : null;
|
||||
$filename = $document->success ? $document->filename : null;
|
||||
|
||||
$participant = $refund->participant;
|
||||
|
||||
Mail::to($participant->email_1)->send(new RefundAcceptedMail(
|
||||
participant: $participant,
|
||||
refund: $refund,
|
||||
pdfContent: $pdf,
|
||||
pdfFilename: $filename,
|
||||
));
|
||||
|
||||
if ($participant->email_2 !== null) {
|
||||
Mail::to($participant->email_2)->send(new RefundAcceptedMail(
|
||||
participant: $participant,
|
||||
refund: $refund,
|
||||
pdfContent: $pdf,
|
||||
pdfFilename: $filename,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\ParticipantRefund\Actions\AcceptRefund;
|
||||
|
||||
use App\Models\ParticipantRefund;
|
||||
|
||||
class AcceptRefundRequest
|
||||
{
|
||||
public function __construct(
|
||||
public readonly ?ParticipantRefund $refund,
|
||||
public readonly string $accountOwner,
|
||||
public readonly string $accountIban,
|
||||
/** Ob der Teili die Erklärung auf der Seite angekreuzt hat. Ohne sie taugt der Beleg nichts. */
|
||||
public readonly bool $declarationAccepted = false,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\ParticipantRefund\Actions\AcceptRefund;
|
||||
|
||||
class AcceptRefundResponse
|
||||
{
|
||||
public bool $success = false;
|
||||
|
||||
public ?string $message = null;
|
||||
|
||||
/**
|
||||
* Feldbezogene Fehler für das Formular. Schlüssel sind die Feldnamen des Frontends.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $errorTypes = [];
|
||||
}
|
||||
Reference in New Issue
Block a user