Drop the Netto row for Kleinunternehmer invoices
Validate e-invoices / mustang (push) Successful in 24s
Validate e-invoices / mustang (push) Successful in 24s
Netto = Gesamt is structural under §19 UStG (no tax component ever existed), not the coincidental 0%-this-one-sale case vatExempt orders are in — showing it right under the §19 notice just duplicated Gesamt. At the user's own request after reviewing a real invoice. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -79,6 +79,7 @@ Unlike `vatExempt`, this package does **not** expect `unitPrice` to be de-grosse
|
||||
|
||||
- Visual PDF (`invoicePdf.tsx`/`correctionInvoicePdf.tsx`): the "enthält X% MwSt." annotation under Gesamt becomes "Gemäß § 19 UStG wird keine Umsatzsteuer berechnet." instead — takes precedence over the `vatExempt` note if (implausibly) both were ever set.
|
||||
- E-invoice XML (`buildEInvoiceData.ts`): VAT category `E` + a free-text exemption reason, no VATEX code — see "E-invoicing" above.
|
||||
- **No Netto row** (added 2026-07-24, at the user's own request) — every other invoice type still shows Netto directly under the tax note/annotation, including `vatExempt` ones, where Netto = Gesamt is a *coincidence* worth keeping for layout consistency (0% happens to apply to that one sale). For `kleinunternehmer` it isn't a coincidence — §19 UStG means no tax component ever existed on any of this tenant's invoices, so the row would just repeat Gesamt directly under the §19 notice above it instead of adding information.
|
||||
|
||||
`InvoiceSeller.vatId` is now optional (`string | null`, was a plain required `string`) for the same reason — a Kleinunternehmer commonly never registers for an USt-IdNr. at all (no intra-EU trade). Every renderer treats a missing value as "omit the USt-IdNr. line/field" rather than printing an empty one: the visual PDF footer drops the whole `· USt-IdNr. …` segment, and `buildEInvoiceData.ts`'s `sellerParty()` omits `cac:PartyTaxScheme` entirely rather than emitting one with a blank `CompanyID`.
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@einfach-produktiv/invoicing",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.2",
|
||||
"private": true,
|
||||
"description": "Shared invoice / correction-invoice (Stornorechnung, Gutschrift) PDF generation and VAT-breakdown math, consumed as a git dependency by both the einfach-produktiv frontend and the payload backend — not published to npm.",
|
||||
"type": "module",
|
||||
|
||||
@@ -364,15 +364,23 @@ function CorrectionInvoiceDocument({ kind, order, seller }: { kind: CorrectionIn
|
||||
single well-defined figure (Gesamt minus every rate's own
|
||||
tax, summed) regardless of how many rates are present.
|
||||
Shown on every correction invoice (Storno and Gutschrift
|
||||
alike), not just non-exempt ones. Same small/muted
|
||||
vatNoteLabel/vatNoteValue styling as the MwSt annotation
|
||||
above it, not the larger summaryLabel/summaryValue the
|
||||
build-up rows use — both are supplementary detail below
|
||||
the hero Gesamt figure, same visual tier. */}
|
||||
<View style={styles.nettoRow}>
|
||||
<Text style={styles.vatNoteLabel}>Netto</Text>
|
||||
<Text style={styles.vatNoteValue}>-{formatPrice(rateGroups.reduce((sum, g) => sum + g.net, 0))}</Text>
|
||||
</View>
|
||||
alike), not just non-exempt ones — except `kleinunternehmer`
|
||||
(built 2026-07-24, at the user's own request), same
|
||||
exception as invoicePdf.tsx's own row for the same reason:
|
||||
Netto = Gesamt there isn't a coincidence to preserve for
|
||||
layout consistency, it's structural (§19 UStG means no tax
|
||||
component ever existed to subtract), so the row would just
|
||||
duplicate Gesamt right under the §19 notice. Same
|
||||
small/muted vatNoteLabel/vatNoteValue styling as the MwSt
|
||||
annotation above it, not the larger summaryLabel/
|
||||
summaryValue the build-up rows use — both are supplementary
|
||||
detail below the hero Gesamt figure, same visual tier. */}
|
||||
{!order.kleinunternehmer && (
|
||||
<View style={styles.nettoRow}>
|
||||
<Text style={styles.vatNoteLabel}>Netto</Text>
|
||||
<Text style={styles.vatNoteValue}>-{formatPrice(rateGroups.reduce((sum, g) => sum + g.net, 0))}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
+22
-13
@@ -425,19 +425,28 @@ export function InvoiceDocument({ order, seller }: { order: InvoiceOrder; seller
|
||||
by hand. Shown on every invoice, not just B2B/non-exempt
|
||||
ones — on a vatExempt order Netto and Gesamt happen to be
|
||||
the same figure (0% tax), but the row stays for layout
|
||||
consistency across every invoice this shop issues. Placed
|
||||
last (after the MwSt annotation, not before it) — see
|
||||
that annotation's own comment above for why the order
|
||||
matters here. Styled with the same small/muted
|
||||
vatNoteLabel/vatNoteValue as that annotation, not the
|
||||
larger summaryLabel/summaryValue the build-up rows above
|
||||
Gesamt use — Netto is supplementary detail *below* the
|
||||
hero Gesamt figure, same visual tier as the tax
|
||||
breakdown, not another primary line competing with it. */}
|
||||
<View style={styles.nettoRow}>
|
||||
<Text style={styles.vatNoteLabel}>Netto</Text>
|
||||
<Text style={styles.vatNoteValue}>{formatPrice(rateGroups.reduce((sum, g) => sum + g.net, 0))}</Text>
|
||||
</View>
|
||||
consistency across every invoice this shop issues. The one
|
||||
exception is `kleinunternehmer` (built 2026-07-24, at the
|
||||
user's own request): there Netto = Gesamt for a
|
||||
structural reason, not a coincidental one (§19 UStG means
|
||||
there was never a tax component to subtract in the first
|
||||
place), and the row would just look like a second,
|
||||
redundant total sitting directly under the §19 notice
|
||||
above rather than genuinely new information. Placed last
|
||||
(after the MwSt annotation, not before it) — see that
|
||||
annotation's own comment above for why the order matters
|
||||
here. Styled with the same small/muted vatNoteLabel/
|
||||
vatNoteValue as that annotation, not the larger
|
||||
summaryLabel/summaryValue the build-up rows above Gesamt
|
||||
use — Netto is supplementary detail *below* the hero
|
||||
Gesamt figure, same visual tier as the tax breakdown, not
|
||||
another primary line competing with it. */}
|
||||
{!order.kleinunternehmer && (
|
||||
<View style={styles.nettoRow}>
|
||||
<Text style={styles.vatNoteLabel}>Netto</Text>
|
||||
<Text style={styles.vatNoteValue}>{formatPrice(rateGroups.reduce((sum, g) => sum + g.net, 0))}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
{paid && (
|
||||
<View style={styles.paidBadgeRow}>
|
||||
|
||||
Reference in New Issue
Block a user