Document VAT-ID-validity-vs-exemption decoupling and maxLength fixes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -744,18 +744,30 @@ retroactively owes the VAT itself).
|
||||
cost from their normal VAT-inclusive catalog figures to net, since the
|
||||
whole point of the exemption is that the buyer pays less, not that this
|
||||
shop quietly keeps the VAT portion as extra margin.
|
||||
- **Checkout UX**: `app/api/checkout/validate-vat/route.ts` gives instant
|
||||
feedback on the USt-IdNr. field's blur (only once the destination
|
||||
actually qualifies — no point calling VIES for a Deutschland/Schweiz
|
||||
order) — "✓ Bestätigt" flips the sidebar total to the exempt (de-grossed)
|
||||
figures live, as a preview. `app/api/checkout/route.ts` re-runs the exact
|
||||
same VIES check server-side at submit time regardless, as the actual
|
||||
source of truth — the client-side result is never trusted. **VIES being
|
||||
unreachable fails closed**: normal VAT applies, never a guessed
|
||||
exemption — the checkout-time check is the one place in this feature
|
||||
that fails closed (contrast the Payload backend's own
|
||||
`company-settings.vatId` VIES check, which fails open, since that one
|
||||
only needs to catch an admin's data-entry typo, not decide a tax rate).
|
||||
- **VAT-ID *validity* and the exemption *decision* are two separate
|
||||
questions (fixed 2026-07-23)** — a first version only ever called VIES
|
||||
when the destination already qualified for the exemption (Österreich),
|
||||
so a garbage VAT ID on a domestic order (e.g. `"ED123456789"` — not even
|
||||
a real country code) sailed through with just a format check, and a
|
||||
genuinely valid German/Swiss VAT ID got no confirmation either. Now
|
||||
`app/api/checkout/validate-vat/route.ts`/`app/api/checkout/route.ts`
|
||||
check any format-valid VAT ID against VIES regardless of destination
|
||||
(data quality — worth knowing whether it's real at all, same reasoning
|
||||
as `company-settings.vatId`'s own check below) — the exemption itself
|
||||
still only applies when the destination is *also* Österreich. A
|
||||
validated German VAT ID never zero-rates a domestic sale, no matter how
|
||||
real it is.
|
||||
- **Checkout UX**: the USt-IdNr. field's blur gives instant feedback for
|
||||
any country — "✓ USt-IdNr. bestätigt" (plus "— Lieferung wird steuerfrei
|
||||
berechnet." only when the destination actually qualifies) flips the
|
||||
sidebar total to the exempt (de-grossed) figures live, as a preview.
|
||||
`app/api/checkout/route.ts` re-runs the exact same VIES check server-side
|
||||
at submit time regardless, as the actual source of truth — the
|
||||
client-side result is never trusted. **VIES being unreachable fails
|
||||
closed on the exemption**: normal VAT applies, never a guessed exemption
|
||||
(contrast the Payload backend's own `company-settings.vatId` VIES check,
|
||||
which fails open, since that one only needs to catch an admin's
|
||||
data-entry typo, not decide a tax rate).
|
||||
- **Every other checkout field is now blur-validated too** (fixed
|
||||
2026-07-23, alongside this feature) — inline red error text appears the
|
||||
moment a field loses focus (required fields, email format, PLZ digit
|
||||
@@ -765,9 +777,18 @@ retroactively owes the VAT itself).
|
||||
never blurred (e.g. autofill).
|
||||
- **Persistence**: `Orders.vatExempt`/`vatIdValidatedAt` (Payload backend)
|
||||
record the outcome, decided once server-side, never editable in the
|
||||
admin — see the Payload README's "B2B checkout & VAT exemption" section
|
||||
admin. `vatIdValidatedAt` is set for *any* VIES-confirmed VAT ID
|
||||
(data-quality audit trail), independently of whether `vatExempt` is also
|
||||
true — see the Payload README's "B2B checkout & VAT exemption" section
|
||||
for the full field/audit-trail reasoning and the invoice PDF/EN16931 XML
|
||||
side of this feature.
|
||||
- **Every fixed-length numeric field now hard-caps input length too**
|
||||
(fixed 2026-07-23) — PLZ (`maxLength` = the selected country's own digit
|
||||
count), USt-IdNr. (`14`), Packstationnummer (`3`)/Postnummer (`10`, on
|
||||
the backend) all already had `pattern`/`validate` format checks, but
|
||||
nothing stopped the browser from accepting more characters than could
|
||||
ever pass. Same "as simple/state-of-the-art as possible" input-quality
|
||||
pass as the blur-validation fix above.
|
||||
- **`/bestellbestaetigung`** mirrors the same exempt-totals branch from the
|
||||
persisted `OrderSnapshot.vatExempt` flag (it otherwise re-derives totals
|
||||
live from the current catalog, which would show the wrong, VAT-inclusive
|
||||
|
||||
Reference in New Issue
Block a user