billing: Zahlungsbestätigung per Mail nach jeder Buchung

Sobald eine bezahlte Stripe-Rechnung in den STR-Kreis gespiegelt
wird, erhält der Kunde eine Bestätigungsmail mit Rechnungsnummer
und Beträgen — deckt Tarif (inkl. Verlängerung), Einzel-PM und
Credits ab. Transaktionsmail ohne Opt-out; durch die idempotente
Spiegelung genau eine Mail pro Beleg, Gutschriften bleiben stumm.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-15 14:36:37 +00:00
parent ff2eee0988
commit 71b247ba18
4 changed files with 128 additions and 0 deletions

View file

@ -7,6 +7,7 @@ use App\Enums\InvoiceStatus;
use App\Enums\PressReleaseStatus;
use App\Enums\SinglePurchaseStatus;
use App\Enums\SinglePurchaseType;
use App\Mail\BookingPaymentConfirmed;
use App\Mail\PressReleaseDepublished;
use App\Models\CreditTopup;
use App\Models\Invoice;
@ -177,6 +178,13 @@ class ProcessStripeWebhook
'number' => $invoice->number,
'stripe_invoice_id' => $stripeInvoiceId,
]);
// Zahlungsbestätigung an den Kunden — genau eine pro Beleg, da die
// Spiegelung über stripe_invoice_id idempotent ist. Deckt alle
// Buchungsarten ab (Tarif inkl. Verlängerung, Einzel-PM, Credits).
if ($user->email) {
Mail::to($user->email)->queue(new BookingPaymentConfirmed($user, $invoice));
}
}
/**

View file

@ -0,0 +1,46 @@
<?php
namespace App\Mail;
use App\Models\Invoice;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
/**
* Zahlungs-/Buchungsbestätigung an den Kunden, sobald eine bezahlte
* Stripe-Rechnung in den STR-Kreis gespiegelt wurde — greift damit für
* jede Buchungsart (Tarif inkl. Verlängerung, Einzel-PM, Credits).
*
* Transaktionsmail: bewusst ohne Opt-out (analog Kündigungs-/
* Widerrufsbestätigungen, siehe EmailNotificationType-Doku).
*/
class BookingPaymentConfirmed extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
public string $invoicesUrl;
public function __construct(
public readonly User $user,
public readonly Invoice $invoice,
) {
$this->invoicesUrl = route('me.invoices.index');
}
public function envelope(): Envelope
{
return new Envelope(
subject: 'Zahlungsbestätigung für Ihre Buchung — Rechnung '.$this->invoice->number,
);
}
public function content(): Content
{
return new Content(view: 'emails.billing.payment-confirmed');
}
}