CluPilotCloud/tests/Feature/Billing
nexxo a43be4186a Say what the sweep did not check, before telling anyone to archive
stripe:sweep-orphan-prices described itself as listing "what AdoptStripePrice
will not take over". It computes nothing of the sort: it lists every active
Price at one of our Products that no register row knows, adoptable or not — the
only question it asks is whether a row holds the id. And then it invited the
destructive path, with no word anywhere about running stripe:sync-catalogue
first.

Following that advice can make a plan unsellable. Archive an orphan the next
sync would have adopted and the sync can no longer see it: activePricesFor()
asks Stripe for active prices only, so adoption returns null and createPrice()
fires under the same key the crashed run used. For twenty-four hours Stripe
answers a repeated key by replaying the stored response — the archived Price's
id, in the body it had while it was live. The register writes it down as live,
and the checkout is refused. This is the same class of defect the branch exists
against: a comment that was eloquent and wrong.

- The docblock now says what the command lists, names the twenty-four-hour
  replay so nobody has to rediscover it, and the ordering requirement is in
  $description and printed on every path that found something, --archive
  included. The reassurance that archiving is harmless is now scoped to what
  THIS codebase sells; a payment link an operator built by hand against one of
  our Products is withdrawn all the same, and says so.
- stripe:sync-catalogue --dry-run says "created or adopted" again. A dry run
  counts intents without calling ensure(), so it cannot know which Stripe
  already holds — and a dry run is the first thing an operator runs after an
  interrupted one. The live line keeps both figures, where they are knowable.
- The sweep's plan side gets a test: an orphan at a family Product is reported
  and a known plan Price never is. Deleting either half of the lookup turns it
  red; the five tests it joins all stayed green for the products() half.
- The throttle test pinned "once" and neither "per price" nor "per day". A key
  mutated to a constant would have silenced every orphan after the first and
  kept it green — the silent no-op the branch is built against. It now plants a
  second orphan, and travels a day to hear the first one again.
- Two of my own documents corrected. The spec sentence claiming an adoptable
  orphan never appears in this list is what the implementation faithfully built;
  it holds only if a sync has run since the orphan appeared, which nothing
  enforced. And the two adoption classes do not carry the same run log:
  $adoptions on the Price side, $duplicates on the Product side.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 19:12:57 +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
PackageCancellationTest.php Take the address by field, fix the customer type, ask why they leave 2026-07-30 16:41:32 +02:00
PaidOrderFulfilmentTest.php Say the same thing to the customer, the register and the bank 2026-07-30 01:30:24 +02:00
PendingPlanChangeTest.php Say the same thing to the customer, the register and the bank 2026-07-30 01:30:24 +02:00
PlanCatalogueTest.php Paketversionen: Verkauf wieder aufnehmen und saubere Übergabe 2026-07-29 14:58:11 +02:00
PlanChangeTest.php Fix nine defects in the provisioning pipelines 2026-07-30 01:34:55 +02:00
PortalInvoicesTest.php Say the same thing to the customer, the register and the bank 2026-07-30 01:30:24 +02:00
ProofRegisterTest.php Stop charging VAT to the customers who owe us none 2026-07-30 02:15:41 +02:00
RenewalInvoiceTest.php Bill a booked module every month, and put it on the invoice 2026-07-29 20:22:02 +02:00
ReverseChargePriceTest.php Accept terms instead of a start date, and fix the sender no server accepts 2026-07-30 15:22:35 +02:00
SetupFeeTest.php Accept terms instead of a start date, and fix the sender no server accepts 2026-07-30 15:22:35 +02:00
StorageAllowanceTest.php Deliver the storage a customer actually buys 2026-07-29 19:13:10 +02:00
StripeAddonBillingTest.php Stop charging VAT to the customers who owe us none 2026-07-30 02:15:41 +02:00
StripeBillingTest.php Stop charging VAT to the customers who owe us none 2026-07-30 02:15:41 +02:00
StripeIdempotencyKeyTest.php Let the catalogue ask Stripe what products it already has 2026-07-30 17:25:38 +02:00
StripePlanChangeTest.php Invoice every renewal, and tell Stripe when the package changes 2026-07-29 19:35:15 +02:00
StripePriceAdoptionTest.php Say what the sweep did not check, before telling anyone to archive 2026-07-30 19:12:57 +02:00
StripeProductAdoptionTest.php Subtract only what was counted, not everything a singleton adopted 2026-07-30 18:20:27 +02:00
SweepOrphanPricesTest.php Say what the sweep did not check, before telling anyone to archive 2026-07-30 19:12:57 +02:00
VatIdVerificationTest.php Ask the EU register whether a VAT number is real 2026-07-29 22:42:29 +02:00
WithdrawalTest.php Rebuild the customer's settings page as four tabs 2026-07-30 16:25:10 +02:00
YearlyTermTest.php Fix the checkout link, and stop the switch moving under the cursor 2026-07-30 16:05:56 +02:00