CluPilotCloud/app
nexxo cd54212b34
tests / pest (push) Failing after 7m32s Details
tests / assets (push) Successful in 25s Details
tests / release (push) Has been skipped Details
Issue an invoice from what somebody bought, and freeze it there
One invoice per purchase rather than per order: a customer who buys a plan and
two add-ons in one go has bought once, and three invoices for one purchase is
three times the paperwork for the same money. Each order becomes a line, which
is also how the add-ons get listed individually.

Everything the document says is copied into the snapshot at the moment the
number is assigned — issuer, recipient, lines, rate, the reason for the rate.
A test changes the company name and the customer name afterwards and asserts
the invoice still says what it said. That is the whole reason no PDF is stored.

The number and the invoice commit in one transaction. A number taken and then
lost to a failure is a gap in a series that must not have one, and the refusal
test asserts that a rejected invoice leaves the counter where it was.

It refuses outright until the company details are complete. An invoice without
a registered name, an address or a VAT number is not a valid invoice here, and
issuing one consumes a number that can never be handed out again.

VAT comes from TaxTreatment, which already existed and already handles a
verified EU VAT ID correctly — including the reverse-charge note, without which
a zero-rated invoice says nothing about why no VAT was charged.

The billing address is carried as the lines it was written as. It is one
free-text field today, and guessing which line is the postcode would put it
where the street belongs, on a document nobody can correct afterwards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 02:09:05 +02:00
..
Actions Put every mail in one design, and confirm an order when the money arrives 2026-07-29 00:14:04 +02:00
Console Move host DNS names off the public zone into vpn-dns's internal hostsdir 2026-07-28 23:44:31 +02:00
Exceptions Refuse a portal login for an address that already belongs to an operator 2026-07-28 14:42:16 +02:00
Http Show where an account is signed in, and let it sign the other places out 2026-07-28 23:38:17 +02:00
Listeners Recognise the devices an account signs in from, and warn about a new one 2026-07-28 23:28:34 +02:00
Livewire Add a raw .env editor to the Integrations page, with a net under it 2026-07-29 01:51:27 +02:00
Mail Put every mail in one design, and confirm an order when the money arrives 2026-07-29 00:14:04 +02:00
Models Lay the foundation for self-issued invoices: series, numbers, frozen documents 2026-07-29 00:57:06 +02:00
Notifications Add the SSH identity to the vault, and give deployment config a console page 2026-07-29 00:52:44 +02:00
Policies Move the console's identity out of the customer table 2026-07-28 10:31:43 +02:00
Providers Move host DNS names off the public zone into vpn-dns's internal hostsdir 2026-07-28 23:44:31 +02:00
Provisioning Add the SSH identity to the vault, and give deployment config a console page 2026-07-29 00:52:44 +02:00
Services Issue an invoice from what somebody bought, and freeze it there 2026-07-29 02:09:05 +02:00
Support Decide the VAT rate in one place, before the two disagree 2026-07-29 02:03:29 +02:00