Add Kleinunternehmerregelung (§19 UStG) support end-to-end
Checkout forces 0% VAT without de-grossing prices when the tenant is a Kleinunternehmer (a business decision, not just an engineering default — unlike the existing intra-community VAT exemption, which does de-gross). Snapshotted onto the order at checkout time so a later toggle of the company-settings checkbox never rewrites an already-issued invoice's tax treatment — same reasoning as the existing vatExempt field. Threaded through: checkout route, order creation/confirmation email, on-demand invoice/Storno/Gutschrift downloads, the Bestellbestätigung page, and the account order-detail page. The four storefront "inkl. X% MwSt." price hints (shop grid, cart upsell, ToDo-Karten landing page, homepage spotlight) drop that clause live when the setting is on. The company-settings Live Preview reflects the checkbox in real time too. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -800,6 +800,14 @@ export type CompanySettings = {
|
||||
sellerEmail: string;
|
||||
vatId: string;
|
||||
taxRatePercent: number;
|
||||
// Kleinunternehmerregelung (§19 UStG) — when true, checkout forces every
|
||||
// order's items to 0% VAT (never de-grossed, unlike the intra-community
|
||||
// exemption) and the tax rate above is ignored. Read live only at
|
||||
// checkout time (see api/checkout/route.ts) to decide what to snapshot
|
||||
// onto the new order — never read live when rendering an existing
|
||||
// order's invoice, see OrderSnapshot/CustomerOrderDetail's own
|
||||
// `kleinunternehmer` field for why.
|
||||
kleinunternehmer: boolean;
|
||||
iban: string | null;
|
||||
bic: string | null;
|
||||
};
|
||||
@@ -843,3 +851,22 @@ export async function getDefaultTaxRatePercent(): Promise<number> {
|
||||
const data: { docs?: { taxRatePercent: number }[] } = await res.json();
|
||||
return data.docs?.[0]?.taxRatePercent ?? 19;
|
||||
}
|
||||
|
||||
// Same ISR-cached, public-catalog-freshness fetch as getDefaultTaxRatePercent()
|
||||
// above (a separate round trip rather than reusing getCompanySettings()'s
|
||||
// deliberate cache: "no-store") — powers the "inkl. X% MwSt." storefront
|
||||
// hints (dropped entirely when this is true, see ProductGrid.tsx/
|
||||
// ProductSpotlight.tsx/etc.) and the cart/checkout VAT-breakdown display.
|
||||
export async function getKleinunternehmer(): Promise<boolean> {
|
||||
const params = new URLSearchParams({ "where[tenant.slug][equals]": TENANT_SLUG, limit: "1" });
|
||||
const res = await fetch(`${PAYLOAD_URL}/api/company-settings?${params}`, {
|
||||
headers: { "x-order-service-secret": process.env.ORDER_SERVICE_SECRET || "" },
|
||||
next: { revalidate: 60 },
|
||||
});
|
||||
if (!res.ok) {
|
||||
console.error(`getKleinunternehmer: Payload returned ${res.status} ${res.statusText}`);
|
||||
return false;
|
||||
}
|
||||
const data: { docs?: { kleinunternehmer: boolean }[] } = await res.json();
|
||||
return data.docs?.[0]?.kleinunternehmer ?? false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user