isOpen()) { return false; } $customerId = $case->subscription?->customer?->stripe_customer_id; if (blank($customerId)) { return false; } $offen = array_column(app(StripeClient::class)->openInvoices((string) $customerId), 'id'); // Platzhalter zählen nicht mit: sie sind keine Stripe-ID, und wogegen // man sie prüfen sollte, weiss niemand. Sie stehen im Fall und auf der // Seite — dort kann ein Mensch nachsehen. Sie hier als „offen" zu // werten hiesse, den Fall für immer festzuhalten. $unsere = array_values(array_filter( array_merge([$case->stripe_invoice_id], array_values($case->fee_invoice_ids ?? [])), fn (string $id) => $id !== AdvanceDunning::PENDING, )); // Steht noch eine davon offen, ist der Fall nicht zu. if (array_intersect($unsere, $offen) !== []) { return false; } $case->update(['settled_at' => Carbon::now()]); $stand = $case->level; // Und die Cloud kommt zurück — NUR die dieses Vertrags. // // Vorher holte eine Zahlung auf Vertrag A jede gesperrte Cloud des // Kunden zurück, auch die, für die noch geschuldet wird (Codex P1). // Ein Kunde mit zwei Verträgen hätte durch das Begleichen des einen // den anderen freibekommen. $instance = $case->instance(); if ($instance !== null && $instance->suspended_at !== null) { app(ResumeInstance::class)($instance); } // Nur wer wirklich stand, bekommt die Entwarnung. Wer auf Stufe 1 // bezahlt hat, hat nie eine Sperre gesehen — ihm zu schreiben, seine // Cloud laufe wieder, wäre eine Nachricht über etwas, das nie war. if ($stand >= DunningSchedule::SUSPENDED) { app(DunningMailer::class)->resumed($case); } return true; } }