CluPilotCloud/lang/en
nexxo 9da1358802 Stop charging VAT to the customers who owe us none
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>
2026-07-30 02:15:41 +02:00
..
admin.php Show the customer, and write the answers once 2026-07-29 22:37:30 +02:00
admin_incidents.php Let an incident be deleted, and start measuring whether the hosts answer 2026-07-29 15:16:48 +02:00
admin_settings.php Quote what a person pays, and tab the settings page 2026-07-29 19:18:10 +02:00
auth.php Ask whether they are a consumer, and let one change their mind 2026-07-29 21:06:06 +02:00
backups.php feat(portal): full sidebar — Cloud, Users, Backups, Invoices, Support 2026-07-25 08:08:33 +02:00
billing.php Ask whether they are a consumer, and let one change their mind 2026-07-29 21:06:06 +02:00
capacity.php Take the order, park it, and say when it will be delivered 2026-07-29 18:50:46 +02:00
checkout.php Say the same thing to the customer, the register and the bank 2026-07-30 01:30:24 +02:00
cloud.php Restart a machine, enforce the quota that was sold, end a route that ended 2026-07-29 18:28:28 +02:00
coming_soon.php Say EU, and stop promising to fix somebody else's deleted folder 2026-07-29 14:17:30 +02:00
common.php Recover silently from an expired session, and show a connection banner when offline 2026-07-28 21:36:21 +02:00
customer_detail.php Let an operator correct a customer's details 2026-07-29 23:18:46 +02:00
customer_message.php Show the customer, and write the answers once 2026-07-29 22:37:30 +02:00
dashboard.php Let the customer buy it themselves, and tab the integrations page 2026-07-29 19:42:28 +02:00
datacenters.php Let a datacenter code be corrected while nothing depends on it, and say which building 2026-07-28 22:25:21 +02:00
delivery.php Quote what a person pays, and tab the settings page 2026-07-29 19:18:10 +02:00
devices.php Recognise the devices an account signs in from, and warn about a new one 2026-07-28 23:28:34 +02:00
domain.php Serve the custom domain, not just announce it 2026-07-29 16:44:52 +02:00
edit_customer.php Let an operator correct a customer's details 2026-07-29 23:18:46 +02:00
errors.php Refuse a portal login for an address that already belongs to an operator 2026-07-28 14:42:16 +02:00
finance.php Quote what a person pays, and tab the settings page 2026-07-29 19:18:10 +02:00
hosts.php Make host onboarding survive the machine it runs on 2026-07-30 00:54:16 +02:00
impersonate.php feat(admin): impersonate customer portal — session login + return banner 2026-07-25 13:46:48 +02:00
inbox.php Read the support mailbox into the console 2026-07-29 21:41:29 +02:00
instances.php Pin the sidebar header and footer so only the nav list scrolls, and shorten two action labels that wrapped 2026-07-28 20:52:12 +02:00
integrations.php Read the support mailbox into the console 2026-07-29 21:41:29 +02:00
invoice.php Say the same thing to the customer, the register and the bank 2026-07-30 01:30:24 +02:00
invoice_mail.php Send the invoice with the invoice attached 2026-07-29 02:13:41 +02:00
invoices.php Say the same thing to the customer, the register and the bank 2026-07-30 01:30:24 +02:00
invoices_admin.php Write an invoice for work that came off no price list 2026-07-29 20:12:26 +02:00
mail.php Put customer instances on their own domain, and say which domains are ours 2026-07-29 16:03:13 +02:00
mail_log.php Keep a register of what was sent, and answer the customer from here 2026-07-29 21:02:36 +02:00
mail_settings.php Bound the mail test-send and real send to a timeout instead of hanging 2026-07-28 16:36:14 +02:00
maintenance.php Put every mail in one design, and confirm an order when the money arrives 2026-07-29 00:14:04 +02:00
new_invoice.php Write an invoice for work that came off no price list 2026-07-29 20:12:26 +02:00
order.php Stop charging VAT to the customers who owe us none 2026-07-30 02:15:41 +02:00
orders.php Keep the shop window off the portal's front door 2026-07-29 00:26:22 +02:00
plans.php Paketversionen: Verkauf wieder aufnehmen und saubere Übergabe 2026-07-29 14:58:11 +02:00
provisioning.php Deliver the storage a customer actually buys 2026-07-29 19:13:10 +02:00
reset_password.php Give people a way back in, and put the URL in English 2026-07-29 16:50:29 +02:00
secrets.php Read the support mailbox into the console 2026-07-29 21:41:29 +02:00
security.php Put customer instances on their own domain, and say which domains are ours 2026-07-29 16:03:13 +02:00
sessions.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.php Stop charging for a service that has ended 2026-07-30 00:52:19 +02:00
status.php Let an incident be deleted, and start measuring whether the hosts answer 2026-07-29 15:16:48 +02:00
support.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
templates.php Show the customer, and write the answers once 2026-07-29 22:37:30 +02:00
two_factor_setup.php Let a half-finished two-factor enrolment be cancelled, and rework the setup page 2026-07-28 22:25:27 +02:00
updating.php Stop root workers breaking every page, and let the panel be closed 2026-07-29 15:43:54 +02:00
users.php Replace native confirm() dialogs with the app's own modal pattern 2026-07-28 19:34:27 +02:00
verify_email.php Require a confirmed address before an account can use anything 2026-07-28 23:43:20 +02:00
vpn.php Replace native confirm() dialogs with the app's own modal pattern 2026-07-28 19:34:27 +02:00
withdrawal.php Charge the price the website shows, and hand a withdrawal back in full 2026-07-29 22:42:02 +02:00