A verified EU business outside Austria gets reverse charge — rate 0, no VAT
line, the note on the invoice — and was still charged 214,80 € for a 179,00 €
package, because one Stripe Price carried the domestic gross for everybody.
There is no VAT line on their document to reclaim, so it was a flat 20 %
surcharge on exactly the customers who read their invoices, and the document
then stated the whole 214,80 € as net at 0 %, so they self-accounted their own
VAT on a base a fifth too large.
A Stripe Price can ask who is buying after all: there are two per sellable
thing now, the domestic gross and the bare net, both live on one Product, and
the checkout picks by TaxTreatment. The rule is Austria B2B 20 %, other EU B2B
without VAT — a domestic business still pays the gross, reclaims it as input
tax, and the price on the website is still the price charged for them.
- stripe:sync-catalogue mints and archives both halves of every pair, per plan
and per module; `reverse_charge` on stripe_plan_prices/stripe_addon_prices
says which is which, and joining it on subscriptions.stripe_price_id says
which one a running contract is billed on. A rate change moves the gross
Price and leaves the net one alone, because the net owes nothing to the rate.
- A status that changes after the sale converges: a verification (or a lapse)
makes stripe:reprice-subscriptions move the contract onto the other Price
with PRORATE_NONE, because the term is already paid for. The module items
follow the same way.
- Downstream follows: the invoice total equals what was taken, the proof
register expects the figure this customer is actually charged (so a correct
reverse-charge sale is no longer flagged as a mismatch, and an overcharged
one is), the setup fee obeys the same rule, and the booking page quotes what
it will charge.
- StripeClient gained activatePrice(). Archived Prices were brought back in our
own table and left inactive at Stripe, so a rate that moved and moved back
pointed the catalogue at a Price no checkout could be opened for.
An unverified number is still charged the gross — an unchecked string must
never be a discount — and where the net Price is missing the checkout refuses
rather than reaching for the domestic one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>