CluPilotCloud/tests/Feature/Billing
nexxo 2277dfe4cb
tests / pest (push) Failing after 8m24s Details
tests / assets (push) Successful in 26s Details
tests / release (push) Has been skipped Details
Ask the EU register whether a VAT number is real
vat_id_verified_at was declared on the customer and read by TaxTreatment, and
set by no code anywhere. hasVerifiedVatId() therefore never returned true, so
reverse charge could not trigger for anybody - and every EU business customer was
invoiced Austrian VAT they cannot reclaim in their own country, which is not a
pass-through for them but a real cost until the invoice is corrected.

The check has THREE outcomes, and the third is why VatIdCheck exists. VIES is a
gateway onto twenty-seven national registers and any of them is regularly down.
Reading "I could not ask" as "not registered" would clear a verification that has
stood for months, move that customer onto the domestic rate, and change what
their next invoice says - because a register was asleep. Reading it as
"registered" would put reverse charge on an unchecked number, which is our
liability. So on UNAVAILABLE nothing at all is written.

Asked at the moment the number is entered, because that is when somebody is
looking at the field and can fix a typo. The save has already happened by then
and the check cannot undo it: a register that is down must not cost a customer
their address change.

Shape and membership are refused before a request is spent, and the fake refuses
on the same rule as the real verifier. A fake that answers where VIES would never
have been asked is not a simplification but a different product, and free text
normalises into a well-formed number more easily than it looks - "not a number"
becomes NOTANUMBER, which the shape rule alone reads as a Norwegian one.

clupilot:verify-vat-ids re-asks about the numbers reverse charge rests on, since
a registration can be withdrawn. Deliberately not scheduled: it queries a public
service with a concurrency limit on behalf of somebody else's tax position, and
the cadence is the owner's to set.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 22:42:29 +02:00
..
AddonCancellationTest.php Ask whether they are a consumer, and let one change their mind 2026-07-29 21:06:06 +02:00
AddonEntitlementTest.php Book a downgrade for a date that cannot move, and sell a module once 2026-07-29 17:51:37 +02:00
ApplyPlanChangeTest.php Book a downgrade for a date that cannot move, and sell a module once 2026-07-29 17:51:37 +02:00
ArchivePullAccessTest.php Mint the archive collection key from the console instead of by hand 2026-07-29 10:08:32 +02:00
CustomDomainAccessTest.php Decide who may have their own domain, and decide it in one place 2026-07-29 15:59:04 +02:00
CustomerTypeTest.php Ask whether they are a consumer, and let one change their mind 2026-07-29 21:06:06 +02:00
ExportTargetFormTest.php Keep the SFTP credential on the row it belongs to, encrypted 2026-07-29 02:46:06 +02:00
FinanceSettingsTest.php Decide the VAT rate in one place, before the two disagree 2026-07-29 02:03:29 +02:00
GrantAddonTest.php Let a subscription or add-on be opened for free, with who and why on the row 2026-07-29 12:41:06 +02:00
GrantInvoiceTest.php Skip the invoice for a full gift, keep it out of revenue, hide its price 2026-07-29 12:41:32 +02:00
GrantSubscriptionTest.php Let a subscription or add-on be opened for free, with who and why on the row 2026-07-29 12:41:06 +02:00
InvoiceArchiveTest.php Leave the archive readable by whoever collects from it 2026-07-29 03:48:03 +02:00
InvoiceListTest.php List issued invoices in the console, with no way to change one 2026-07-29 02:21:15 +02:00
InvoiceMailTest.php Send the invoice with the invoice attached 2026-07-29 02:13:41 +02:00
InvoiceMathTest.php Print every line at full price and take the discount off once, in euros 2026-07-29 01:59:56 +02:00
InvoiceNumberTest.php Lay the foundation for self-issued invoices: series, numbers, frozen documents 2026-07-29 00:57:06 +02:00
IssueInvoiceTest.php Issue an invoice from what somebody bought, and freeze it there 2026-07-29 02:09:05 +02:00
PendingPlanChangeTest.php Book a downgrade for a date that cannot move, and sell a module once 2026-07-29 17:51:37 +02:00
PlanCatalogueTest.php Paketversionen: Verkauf wieder aufnehmen und saubere Übergabe 2026-07-29 14:58:11 +02:00
PlanChangeTest.php feat(billing): the plan catalogue becomes three tables, and config stops selling 2026-07-26 12:05:56 +02:00
ProofRegisterTest.php feat(billing): a proof register, and modules frozen at their booked price 2026-07-26 13:07:34 +02:00
RenewalInvoiceTest.php Bill a booked module every month, and put it on the invoice 2026-07-29 20:22:02 +02:00
StorageAllowanceTest.php Deliver the storage a customer actually buys 2026-07-29 19:13:10 +02:00
StripeAddonBillingTest.php Charge the price the website shows, and hand a withdrawal back in full 2026-07-29 22:42:02 +02:00
StripeBillingTest.php Charge the price the website shows, and hand a withdrawal back in full 2026-07-29 22:42:02 +02:00
StripePlanChangeTest.php Invoice every renewal, and tell Stripe when the package changes 2026-07-29 19:35:15 +02:00
VatIdVerificationTest.php Ask the EU register whether a VAT number is real 2026-07-29 22:42:29 +02:00
WithdrawalTest.php Charge the price the website shows, and hand a withdrawal back in full 2026-07-29 22:42:02 +02:00