CluPilotCloud/resources/views/livewire
nexxo 3b5dee8f0d Ein Ausweg wird nur angeboten, wenn er auch buchbar ist
DowngradeCheck baute seine Empfehlung aus packsToCover(), und die rechnet
bloss. BookAddon lehnt aus ZWEI Gruenden ab - der Deckel bei drei Bloecken
und der Ausschluss von Enterprise -, und die Empfehlung kannte keinen davon.
Solange ein Block 100 GB brachte, war das unerreichbar; seit er 20 GB bringt,
landet jede Ueberschreitung ueber 60 GB dort.

Business -> Team mit 600 GB belegt bot "5 x Zusatzspeicher buchen (+100 GB)"
an. Das Modal klemmte still auf drei, den vierten haette BookAddon abgelehnt,
und der Kunde stand nach 45 Euro im Monat genau dort, wo er vorher stand - auf
der Karte, die sein Abo billiger machen sollte. Enterprise -> Business empfahl
Bloecke, die es fuer dieses Paket ueberhaupt nicht gibt.

AddonCatalogue::bookableQuantity() antwortet jetzt auf beide Gruende. Es gab
einem Enterprise-Vertrag "3" auf die Frage, die sein eigener Docblock stellt.

DowngradeCheck stellt diese eine Frage und klemmt daran: `packs` ist die
gebrauchte Zahl nur, wenn der Vertrag sie auch buchen darf, sonst null - und
dann traegt `short`, was nach allen buchbaren Bloecken uebrig bliebe, gemessen
an DEREN Restmenge statt am Deckel, damit ein Kunde mit einem Block nicht mehr
zu loeschen bekommt als noetig. Kein halbes Angebot: eine Dauerbuchung, die
den Wechsel trotzdem nicht freigibt, ist kein Ausweg, sondern der ausgegraute
Knopf mit Preisschild.

packsToCover() bleibt reine Arithmetik, mit einem Kommentar, der sagt warum:
die kaufmaennische Grenze steht in AddonCatalogue, und ein Klemmen an dieser
Stelle zoege eine Vertragsabfrage in jeden Kontingent-Schritt und ins Portal,
die beide keine Verkaufsfrage stellen.

Der Knopf haengt schon an `packs > 0` und verschwindet von selbst; der Satz
wechselt auf downgrade_escape.capped, der die verbleibende Luecke nennt und
nicht den Grund - "hoechstens drei Bloecke" waere im Enterprise-Fall falsch,
wo es gar keine gibt.

Zwei bestehende Tests hingen an 600 und 800 GB aus der 100-GB-Zeit, beide
inzwischen nicht mehr deckbar; einer haette das Modal gesucht, das die Karte
zu Recht nicht mehr oeffnet. Auf 550 und 560 GB umgestellt, wo sie das pruefen,
wofuer sie geschrieben wurden.

Dazu ein Test, der belegt statt annimmt, warum das max(1, min(...)) in
ConfirmBookStorage stehen bleiben darf: ein Modal ist per openModal direkt
erreichbar, aber bookStoragePacks() legt weder am Deckel noch bei Enterprise
eine Bestellzeile an. Die bestehenden Tests deckten purchase() ab, nicht diese
Weiterleitung.

Voller Testlauf: 2405 bestanden. Pint sauber.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 15:40:26 +02:00
..
admin Hostdetailseite: die Adresse steht neben den IPs und ist ein Klick zur Proxmox-Oberflaeche 2026-08-01 14:12:03 +02:00
auth Accept terms instead of a start date, and fix the sender no server accepts 2026-07-30 15:22:35 +02:00
backups.blade.php Match the panel to the approved template, measured rather than assumed 2026-07-27 17:08:05 +02:00
billing.blade.php Ein Ausweg wird nur angeboten, wenn er auch buchbar ist 2026-08-01 15:40:26 +02:00
checkout.blade.php Give the order a checkout page, and stop hiding what a year costs 2026-07-30 16:00:08 +02:00
cloud.blade.php Restart a machine, enforce the quota that was sold, end a route that ended 2026-07-29 18:28:28 +02:00
confirm-book-storage.blade.php Deliver the storage a customer actually buys 2026-07-29 19:13:10 +02:00
confirm-cancel-addon.blade.php Ask whether they are a consumer, and let one change their mind 2026-07-29 21:06:06 +02:00
confirm-cancel-package.blade.php Take the address by field, fix the customer type, ask why they leave 2026-07-30 16:41:32 +02:00
confirm-close-account.blade.php R24: a modal is never taller than the screen 2026-07-29 23:33:57 +02:00
confirm-delete-own-account.blade.php Discard an unconfirmed registration, and sweep the abandoned ones 2026-07-30 14:08:02 +02:00
confirm-disable-two-factor.blade.php Replace native confirm() dialogs with the app's own modal pattern 2026-07-28 19:34:27 +02:00
confirm-end-other-sessions.blade.php Show where an account is signed in, and let it sign the other places out 2026-07-28 23:38:17 +02:00
confirm-remove-order.blade.php feat(billing): a cart you can actually read and change 2026-07-26 05:26:49 +02:00
confirm-restart-cloud.blade.php Restart a machine, enforce the quota that was sold, end a route that ended 2026-07-29 18:28:28 +02:00
confirm-revoke-seat.blade.php Replace native confirm() dialogs with the app's own modal pattern 2026-07-28 19:34:27 +02:00
confirm-withdraw.blade.php Charge the price the website shows, and hand a withdrawal back in full 2026-07-29 22:42:02 +02:00
custom-domain.blade.php Serve the custom domain, not just announce it 2026-07-29 16:44:52 +02:00
customer-provisioning.blade.php Take the order, park it, and say when it will be delivered 2026-07-29 18:50:46 +02:00
dashboard.blade.php Let the customer buy it themselves, and tab the integrations page 2026-07-29 19:42:28 +02:00
edit-mailbox.blade.php R24: a modal is never taller than the screen 2026-07-29 23:33:57 +02:00
edit-seat.blade.php R24: a modal is never taller than the screen 2026-07-29 23:33:57 +02:00
invoices.blade.php Say the same thing to the customer, the register and the bank 2026-07-30 01:30:24 +02:00
new-support-request.blade.php R24: a modal is never taller than the screen 2026-07-29 23:33:57 +02:00
open-invoices.blade.php Portal: Karte tauschen, offene Rechnungen begleichen, Hinweis bei Faelligkeit 2026-07-31 21:12:31 +02:00
order.blade.php Fix the checkout link, and stop the switch moving under the cursor 2026-07-30 16:05:56 +02:00
payment-method.blade.php Portal: Karte tauschen, offene Rechnungen begleichen, Hinweis bei Faelligkeit 2026-07-31 21:12:31 +02:00
sessions.blade.php Show where an account is signed in, and let it sign the other places out 2026-07-28 23:38:17 +02:00
settings.blade.php Give settings the shape a settings page actually has 2026-07-30 17:59:16 +02:00
support.blade.php Editing in modals, an update button that is not gated on a stale reading, and a support page that is real 2026-07-27 17:55:49 +02:00
users.blade.php Replace native confirm() dialogs with the app's own modal pattern 2026-07-28 19:34:27 +02:00