mivita/app/Mail/AboCardUpdateLinkMail.php
Kevin ce4750fd1a Stripe-Integration (S4, S5, S7.6): Abos, Zahlungsart ändern, Zahlarten-Kommunikation
Phase S4 – Abos über Stripe (E2E komplett im Testmodus):
- Abo-/Recovery-Checkout: customer_creation=always + setup_future_usage=off_session
- StripePaymentService::chargeAbo (off-session PaymentIntent, Idempotency-Key),
  StripeGateway, Provider-Dispatch im Abbuchungs-Cron (PAYONE-Pfad unverändert)
- Webhook: Zahlungsmittel-Capture vor Paid-Pfad, 503 payment_not_yet_visible bei
  Cron-Transaktions-Race; Command stripe:process-pending-events (Cron-Ende + 10-min
  Scheduler) verarbeitet liegengebliebene Events nach
- createNewAbo/advanceAboAfterRecoveryPayment Stripe-aware inkl. Race-Absicherung;
  Recovery-Orders nutzen advanceAboAfterRecoveryPayment (latenter PAYONE-Duplikat-Bug)
- Migrationen: Stripe-Abo-Spalten auf shopping_payments; clearingtype varchar(3)→(20)
  inkl. Reparatur der zu 'str' gekürzten Live-Zeilen

Phase S5 – Zahlungsart ändern (Scope: jede Zahlart, nicht nur Kreditkarte):
- Stripe Checkout mode=setup ohne Abbuchung; PAYONE-Abos ziehen beim Wechsel auf
  Stripe um (Auslaufmodell §7.2)
- AboPaymentMethodService: beginStripeChange/finalize/applyStripePaymentMethod
  (idempotent, detacht alte PM, card_changes-Log); Webhook setup_intent.succeeded
  als Sicherheitsnetz; Einstiege Portal/CRM/Berater-Kunden-Link flow-abhängig
- Views/Mails flow-abhängig („Zahlungsweise" statt „Kreditkarte")

Phase S7.6 – Zahlarten-Kommunikation:
- Einheitliche Zahlarten-Logos (SVG) + wiederverwendbares Partial payment_logos;
  Checkout/Footer zeigen Kern-Zahlarten + „···"-Icon, /zahlungsarten komplett neu
  mit allen aktiven Stripe-Zahlarten (gegen Account-Konfiguration verifiziert)
  und Vorkasse (PAYONE); Sofort/SEPA entfernt

Tests: StripeAboTest (15), StripePaymentMethodChangeTest (10),
PaymentMethodsCommunicationTest (28), PaymentProviderManagerTest angepasst.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 14:45:17 +00:00

48 lines
1.8 KiB
PHP

<?php
namespace App\Mail;
use App\Models\UserAbo;
use App\Services\AboPaymentMethodService;
use App\Services\Util;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class AboCardUpdateLinkMail extends Mailable
{
use Queueable, SerializesModels;
public function __construct(public UserAbo $userAbo, public string $token) {}
public function build(): self
{
$firstname = $this->userAbo->shopping_user?->billing_firstname;
$salutation = $firstname ? __('email.hello').' '.$firstname : __('email.hello');
// Link zeigt immer auf das Kundenportal (in.mivita.care), unabhängig vom Versand-Kontext.
$link = rtrim(Util::getMyMivitaPortalUrl(), '/').'/abo/karte/'.$this->token;
// Texte je Flow: Stripe = freie Zahlartenwahl (Plan S5), PAYONE-Legacy = Kreditkarte.
$stripeChange = app(AboPaymentMethodService::class)->usesStripeChange();
$subject = $stripeChange
? __('abo.payment_method_change_link_mail_subject')
: __('abo.card_update_link_mail_subject');
return $this->subject($subject)
->view('emails.abo_card_update_link')
->with([
'salutation' => $salutation,
'link' => $link,
'mailTitle' => $subject,
'mailIntro' => $stripeChange
? __('abo.payment_method_change_link_mail_intro')
: __('abo.card_update_link_mail_intro'),
'mailButton' => $stripeChange
? __('abo.payment_method_change_link_mail_button')
: __('abo.card_update_link_mail_button'),
'greetings' => __('email.greetings'),
'sender' => __('email.sender'),
]);
}
}