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:
@@ -97,6 +97,7 @@ export function CheckoutContent({
|
||||
trustBadges,
|
||||
shippingSettings,
|
||||
defaultTaxRate,
|
||||
kleinunternehmer,
|
||||
customerEmail,
|
||||
savedProfile,
|
||||
}: {
|
||||
@@ -113,6 +114,11 @@ export function CheckoutContent({
|
||||
shippingSettings: ShippingSettings;
|
||||
/** Tenant's default VAT rate, same role as CartContent's own prop. */
|
||||
defaultTaxRate: number;
|
||||
/** §19 UStG — same role as CartContent's own prop. Also forces the VIES
|
||||
* exemption preview off below: a Kleinunternehmer never charges VAT on
|
||||
* anything, domestic or cross-border, so there's nothing left for the
|
||||
* intra-community exemption to zero-rate. */
|
||||
kleinunternehmer: boolean;
|
||||
/** From the checkout page's own session read (app/lib/customerAuth.ts) —
|
||||
* null means no account is logged in yet, which flips "1. Rechnungsadresse"
|
||||
* into inline-registration mode (password field shown, account created on
|
||||
@@ -341,7 +347,7 @@ export function CheckoutContent({
|
||||
// when set, the billing country otherwise — the exemption depends on
|
||||
// where the goods actually move to, not necessarily the invoice address.
|
||||
const buyerDestinationCountry = destinationCountry(country, hasDifferentShippingAddress, shippingCountry);
|
||||
const vatExemptPreview = vatIdViesStatus === "valid" && isExemptionEligibleCountry(buyerDestinationCountry);
|
||||
const vatExemptPreview = !kleinunternehmer && vatIdViesStatus === "valid" && isExemptionEligibleCountry(buyerDestinationCountry);
|
||||
const exemptTotalsPreview = vatExemptPreview
|
||||
? computeExemptTotals(
|
||||
items.map(({ entry, product }) => ({
|
||||
@@ -538,6 +544,7 @@ export function CheckoutContent({
|
||||
discountCode: data.discountCode,
|
||||
discountAmount: data.discountAmount,
|
||||
vatExempt: Boolean(data.vatExempt),
|
||||
kleinunternehmer: Boolean(data.kleinunternehmer),
|
||||
};
|
||||
try {
|
||||
window.sessionStorage.setItem(ORDER_KEY, JSON.stringify(snapshot));
|
||||
@@ -1160,7 +1167,7 @@ export function CheckoutContent({
|
||||
{entry.variant ? ` (${entry.variant})` : ""}
|
||||
</p>
|
||||
<p className="text-label text-text-muted">
|
||||
{entry.qty} × {formatPrice(unitPrice)} <span>inkl. {taxRate}% MwSt.</span>
|
||||
{entry.qty} × {formatPrice(unitPrice)} {!kleinunternehmer && <span>inkl. {taxRate}% MwSt.</span>}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-body-sm text-text-primary whitespace-nowrap">{formatPrice(entry.qty * unitPrice)}</p>
|
||||
@@ -1235,7 +1242,9 @@ export function CheckoutContent({
|
||||
<span className="flex-1" />
|
||||
<span className="font-bold text-h-small text-text-primary">{formatPrice(displayTotal)}</span>
|
||||
</div>
|
||||
{vatExemptPreview ? (
|
||||
{kleinunternehmer ? (
|
||||
<p className="text-label text-text-muted">Gemäß § 19 UStG wird keine Umsatzsteuer berechnet.</p>
|
||||
) : vatExemptPreview ? (
|
||||
<p className="text-label text-text-muted">Steuerfreie innergemeinschaftliche Lieferung (§4 Nr. 1b UStG)</p>
|
||||
) : (
|
||||
<VatBreakdown groups={taxBreakdown} />
|
||||
|
||||
Reference in New Issue
Block a user