Zahlungszwecke

This commit is contained in:
2026-09-07 14:17:50 +02:00
parent 350c8dd0d0
commit 40d5634764
27 changed files with 927 additions and 205 deletions
@@ -3,6 +3,8 @@
namespace App\Domains\Invoice\Actions\CreateInvoice;
use App\Enumerations\InvoiceStatus;
use App\Enumerations\InvoiceType;
use App\Enumerations\TravelReason;
use App\Mail\InvoiceMails\InvoiceMailsNewInvoiceMail;
use App\Mail\InvoiceMails\InvoiceMailsSubmittedConfirmationMail;
use App\Mail\ParticipantParticipationMails\EventSignUpSuccessfullMail;
@@ -19,10 +21,19 @@ class CreateInvoiceCommand {
public function execute() : CreateInvoiceResponse {
$response = new CreateInvoiceResponse();
$rejection = $this->rejectTravelReason();
if ($rejection !== null) {
$response->message = $rejection;
return $response;
}
if ($this->request->accountIban === 'undefined') {
$this->request->accountIban = null;
}
$travelReason = $this->travelReason();
$invoice = Invoice::create([
'tenant' => currentTenant()->slug,
'cost_unit_id' => $this->request->costUnit->id,
@@ -30,6 +41,7 @@ class CreateInvoiceCommand {
'status' => InvoiceStatus::INVOICE_STATUS_NEW,
'type' => $this->request->invoiceType,
'type_other' => $this->request->invoiceTypeExtended,
'purpose' => $this->purpose($travelReason),
'donation' => $this->request->isDonation,
'user_id' => $this->request->paymentPurpose === null ? $this->request->userId : null,
'contact_name' => $this->request->contactName,
@@ -40,9 +52,7 @@ class CreateInvoiceCommand {
'amount' => $this->request->totalAmount,
'distance' => $this->request->distance,
'travel_direction' => $this->request->travelRoute,
'travel_reason' => $this->request->travelReason,
'passengers' => $this->request->passengers,
'transportation' => $this->request->transportations,
'travel_reason' => $travelReason,
'payment_purpose' => $this->request->paymentPurpose,
'comment' => $this->request->notices,
'document_filename' => $this->request->receiptFile !== null ? $this->request->receiptFile->fullPath : null,
@@ -81,6 +91,68 @@ class CreateInvoiceCommand {
}
/**
* Der Zahlungsgrund, einmal beim Anlegen festgehalten.
*
* Danach ist er eine eigene Angabe: Die Kassenwart*in kann ihn korrigieren, und nichts schreibt ihn
* mehr um. Bei Fahrtkosten setzt er sich aus Reisegrund und den gefahrenen Personen zusammen, sonst
* trägt ihn "Was wurde eingekauft". Wo nichts erfasst wird -- Beitragserstattungen -- bleibt er leer.
*
* Steht er schon fest, wird er übernommen: Eine Abrechnungskorrektur kopiert den Beleg, und ein von
* Hand gesetzter Grund darf dabei nicht verloren gehen.
*/
private function purpose(?string $travelReason) : ?string {
if (trim((string) $this->request->purpose) !== '') {
return $this->request->purpose;
}
$purpose = Invoice::joinPurposeParts(
$this->request->invoiceType === InvoiceType::INVOICE_TYPE_TRAVELLING
// Der Name des Grundes, nicht sein Schlüssel: In der Belegliste soll "Materialtransport"
// stehen, nicht "material_transport".
? [TravelReason::text($travelReason), $this->request->travellers]
: [$this->request->invoiceTypeExtended]
);
return $purpose === '' ? null : $purpose;
}
/**
* Was in `travel_reason` landet: der Schlüssel des gewählten Grundes -- oder, bei "Anderer Grund",
* der Text selbst. Der Schlüssel `other` sagt für sich nichts aus, der Text alles.
*
* Ein unbekannter Wert ist deshalb kein Fehler, sondern genau dieser Fall: So kommen auch
* Bestandsbelege und Kopien durch, die ihren Freitext schon mitbringen.
*/
private function travelReason() : ?string {
$reason = TravelReason::find($this->request->travelReason);
if ($reason === null) {
return $this->request->travelReason;
}
return $reason->requires_note
? trim((string) $this->request->travelReasonNote)
: $reason->slug;
}
/**
* Sicherheitsnetz hinter der Oberfläche: Dort geht es erst weiter, wenn die Erläuterung steht. Über
* einen direkten Aufruf ginge das sonst vorbei, und ein "Anderer Grund" ohne Text sagt nichts aus --
* gespeichert würde ein leerer Reisegrund.
*/
private function rejectTravelReason() : ?string {
$reason = TravelReason::find($this->request->travelReason);
if ($reason === null || !$reason->requires_note) {
return null;
}
return trim((string) $this->request->travelReasonNote) === ''
? 'Bitte gib an, was der Grund für die Reise war.'
: null;
}
private function generateInvoiceNumber() : string {
$lastInvoiceNumber = Invoice::query()
->where('tenant', currentTenant()->slug)