fix(invoice): partial refund stays "Bezahlt" + use "Endbetrag" final-row label
Two related bugs surfaced when a paid order was partially refunded
(Shopify flips `displayFinancialStatus` to PARTIALLY_REFUNDED as soon
as *any* refund is posted, even a small one):
1. The status row showed "Erstattet" / "Refunded" even though the
customer paid in full and the merchant kept the difference. The
correct status is "Bezahlt" / "Paid" — only when the refund equals
(or, defensively, exceeds) the gross is the order genuinely
refunded.
2. The final row beneath the new refund block was labelled "Offener
Betrag" / "Outstanding amount", falsely suggesting the customer
still owes the kept portion. For an order that has been refunded
but is no longer owing anything, that row is just the final amount
the merchant kept — "Endbetrag" / "Total".
Truth table now implemented:
displayFinancialStatus | refunded | paymentStatus | final-row label
-----------------------+--------------+---------------+-----------------
PAID | 0 | paid | (no refund rows)
PAID | >0 | paid | Endbetrag
PARTIALLY_REFUNDED | < gross | paid (NEW) | Endbetrag (NEW)
PARTIALLY_REFUNDED | == gross | refunded | Endbetrag
REFUNDED | == gross | refunded | Endbetrag
PARTIALLY_PAID | 0 | partial | (no refund rows)
PARTIALLY_PAID | >0 (exotic) | partial | Offener Betrag
PENDING/AUTHORIZED/etc | 0 | unpaid | (no refund rows)
storno / offer | 0 (forced) | n/a | n/a
Implementation:
- composeInvoice.ts: after computing refundedAmount, reclassify
paymentStatus="refunded" → "paid" when 0 < refundedAmount <
totals.gross. requiresPayment is derived from paymentStatus, so
it correctly stays false for partial-refund-on-paid (no GiroCode,
no payment terms — nothing is owed).
- i18n.ts: new `finalAmountLabel` ("Endbetrag" / "Total") in both
languages.
- InvoiceDocument.tsx: the final-row label now picks
outstandingLabel vs. finalAmountLabel based on requiresPayment,
so PARTIALLY_PAID with a refund still says "Offener Betrag"
while PARTIALLY_REFUNDED says "Endbetrag".
Verification: render-sample now runs four refund scenarios — paid +
no refund (regression guard), full refund (status=Erstattet, final
row=Endbetrag 0,00 EUR), partial refund on a paid order (status=
Bezahlt, final row=Endbetrag, no Erstattet), and PARTIALLY_REFUNDED
with refund==gross (status stays refunded). tsc / smoke / tests /
build all green.
This commit is contained in:
@@ -52,6 +52,13 @@ export interface InvoiceStrings {
|
||||
* refundedAmount`) shown when there has been a refund. "Offener
|
||||
* Betrag" / "Outstanding amount". */
|
||||
outstandingLabel: string;
|
||||
/** Label used in place of `outstandingLabel` when the order has been
|
||||
* refunded but nothing is actually owed any more (i.e. the customer
|
||||
* paid in full and got back only part — or all — of the gross via
|
||||
* refunds). "Endbetrag" / "Total". The distinction matters for
|
||||
* PARTIALLY_REFUNDED orders, where calling the kept portion
|
||||
* "outstanding" would falsely suggest the customer still owes it. */
|
||||
finalAmountLabel: string;
|
||||
addressHeading: string;
|
||||
contactHeading: string;
|
||||
legalHeading: string;
|
||||
@@ -169,6 +176,7 @@ const de: InvoiceStrings = {
|
||||
referenceLabel: "Referenz",
|
||||
refundedLabel: "Zurückerstattet",
|
||||
outstandingLabel: "Offener Betrag",
|
||||
finalAmountLabel: "Endbetrag",
|
||||
addressHeading: "Adresse",
|
||||
contactHeading: "Kontakt",
|
||||
legalHeading: "Rechtliches",
|
||||
@@ -258,6 +266,7 @@ const en: InvoiceStrings = {
|
||||
referenceLabel: "Reference",
|
||||
refundedLabel: "Refunded",
|
||||
outstandingLabel: "Outstanding amount",
|
||||
finalAmountLabel: "Total",
|
||||
addressHeading: "Address",
|
||||
contactHeading: "Contact",
|
||||
legalHeading: "Legal",
|
||||
|
||||
Reference in New Issue
Block a user