49 lines
1.6 KiB
PHP
49 lines
1.6 KiB
PHP
<?php
|
|
|
|
namespace App\Actions;
|
|
|
|
use App\Models\DunningCase;
|
|
use App\Models\Subscription;
|
|
use App\Services\Billing\DunningSchedule;
|
|
use Illuminate\Support\Carbon;
|
|
|
|
/**
|
|
* Der Fall, der entsteht, wenn eine Abbuchung zum ersten Mal scheitert.
|
|
*
|
|
* Hängt an ApplyStripeBillingEvent::invoicePaymentFailed(), das bis hierher
|
|
* `past_due` setzte und schwieg. Der Kunde erfuhr davon erst, wenn seine Cloud
|
|
* stand.
|
|
*
|
|
* JE RECHNUNG GENAU EINMAL. Stripe versucht dieselbe Rechnung mehrfach, und
|
|
* jeder Versuch ist ein eigenes Ereignis — ohne diese Bedingung entstünden drei
|
|
* Fälle für eine Schuld, mit drei Mahnläufen und dreifachen Gebühren. Die
|
|
* Eindeutigkeit steht zusätzlich als Index in der Tabelle, damit zwei
|
|
* gleichzeitig eintreffende Ereignisse sie nicht umgehen können.
|
|
*
|
|
* Eröffnet wird auf Stufe 0 — dem HINWEIS. Keine Mahnung, keine Gebühr: eine
|
|
* abgelaufene Karte ist keine Zahlungsverweigerung.
|
|
*/
|
|
class OpenDunningCase
|
|
{
|
|
public function __invoke(Subscription $subscription, string $invoiceId): ?DunningCase
|
|
{
|
|
if ($invoiceId === '') {
|
|
return null;
|
|
}
|
|
|
|
$now = Carbon::now();
|
|
|
|
return DunningCase::query()->firstOrCreate(
|
|
['stripe_invoice_id' => $invoiceId],
|
|
[
|
|
'subscription_id' => $subscription->id,
|
|
'level' => 0,
|
|
'opened_at' => $now,
|
|
// Die erste Mahnung, nicht der Hinweis: der geht sofort hinaus.
|
|
'next_step_at' => $now->copy()->addDays(DunningSchedule::dayOfLevel(1)),
|
|
'fee_invoice_ids' => [],
|
|
],
|
|
);
|
|
}
|
|
}
|