billing/dev: Vertragsende in der MAN-Abrechnung, Rechnungslauf ohne Tageskappe, Qualitätsgates (Audit Block 5+6, Deploy E)

Block 5 — MAN-Abrechnung

F06 (E6): Ein explizites Legacy-Vertragsende (grandfathered_until) deckelt
jetzt Auswahl und Sperr-Nachprüfung: Beginnt die nächste Periode nach dem
Vertragsende, gibt es keine Rechnung mehr. Neuer täglicher Befehl
billing:expire-grandfathering (04:15, vor dem Rechnungslauf) setzt
abgelaufene Posten auf gekündigt und schickt je Kunde eine Mail
(GrandfatheringExpired). Auf der Dev-Kopie trägt kein Posten ein
Vertragsende; der Fehler war latent.

F16: Nicht abrechenbare Vereinbarungen bekommen einen Sperrvermerk
(billing_hold_reason/-at), sichtbar auf der Admin-Zahlungsseite, und
stehen im Rechnungslauf hinten an. Der Lauf arbeitet den fälligen Bestand
in Seiten ab; --limit deckelt die erstellten Rechnungen (500), nicht die
betrachteten Fälle. Vorher blockierten 50 unvollständige Fälle die 51.
dauerhaft, und der Durchsatz war auf 50 am Tag begrenzt.

Block 6 — Entwicklung

F24: Lint-Workflow prüft mit pint --test statt zu formatieren; keine
Schreibrechte mehr.
F27: composer run dev startet beide Vite-Server (npm run dev:all).
F28: docs/README.md als historischer Stand markiert, toter Link auf das
Hub-Flux-Archiv korrigiert, aktueller Einstieg dev/README.md.
F26: Login-Modal übernimmt den Fokus, hält Tab im Dialog und gibt den
Fokus beim Schließen an den Auslöser zurück – ohne neue Abhängigkeit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-18 10:41:04 +00:00
parent 72432fdb82
commit 9a88e82baa
15 changed files with 518 additions and 65 deletions

View file

@ -475,10 +475,13 @@ new #[Layout('components.layouts.app'), Title('Zahlungen')] class extends Compon
<div class="text-[11px] text-[color:var(--color-ink-3)]">{{ $blocked->current_period_end?->diffForHumans() }}</div>
</flux:table.cell>
<flux:table.cell>
@if (! $blocked->user?->billingAddress)
@if ($blocked->billing_hold_reason)
<span class="badge warn dot">{{ $blocked->billing_hold_reason }}</span>
<div class="text-[11px] text-[color:var(--color-ink-3)]">{{ __('seit :date', ['date' => $blocked->billing_hold_at?->format('d.m.Y')]) }}</div>
@elseif (! $blocked->user?->billingAddress)
<span class="badge warn dot">{{ __('Keine Rechnungsadresse') }}</span>
@else
<span class="badge">{{ __('Siehe Log') }}</span>
<span class="badge">{{ __('Noch nicht geprüft') }}</span>
@endif
</flux:table.cell>
<flux:table.cell>