diff --git a/src/__tests__/issued-orders.test.ts b/src/__tests__/issued-orders.test.ts
index 023e18e..78c75a2 100644
--- a/src/__tests__/issued-orders.test.ts
+++ b/src/__tests__/issued-orders.test.ts
@@ -507,6 +507,35 @@ describe("renderIssuedOrderHtml", () => {
expect(html).not.toContain("alert(1)");
});
+ it("with VAT: keeps the VAT columns and the DPH cell holds ONLY the line VAT", () => {
+ const html = renderIssuedOrderHtml(order, items, null, null, "cs", issuer);
+ expect(html).toContain("%DPH");
+ expect(html).toContain(">DPH<");
+ // 2 × 100 @ 21 %: DPH cell = 42,00 (VAT only), Celkem cell = 242,00.
+ expect(html).toContain('
42,00 | ');
+ expect(html).toContain('242,00 | ');
+ expect(html).not.toContain("Celkem bez DPH");
+ });
+
+ it("without VAT: hides the VAT columns and labels the total 'Celkem bez DPH'", () => {
+ const html = renderIssuedOrderHtml(
+ { ...order, apply_vat: false },
+ items,
+ null,
+ null,
+ "cs",
+ issuer,
+ );
+ expect(html).not.toContain("%DPH");
+ expect(html).not.toContain(">DPH<");
+ // No per-line VAT cell, line total = netto.
+ expect(html).not.toContain('42,00 | ');
+ expect(html).toContain('200,00 | ');
+ expect(html).toContain("Celkem bez DPH");
+ // The subtotal detail row is dropped (it would duplicate the grand total).
+ expect(html).not.toContain("Mezisoučet");
+ });
+
it("footer shows the logged-in user's name, no e-mail, no Schválil column", () => {
const html = renderIssuedOrderHtml(order, items, null, null, "cs", issuer);
// Footer: Vystavil from authData. No e-mail line.
diff --git a/src/routes/admin/issued-orders-pdf.ts b/src/routes/admin/issued-orders-pdf.ts
index 9250b30..39e3d58 100644
--- a/src/routes/admin/issued-orders-pdf.ts
+++ b/src/routes/admin/issued-orders-pdf.ts
@@ -207,6 +207,7 @@ const translations: Record> = {
subtotal: "Mezisoučet:",
vat_label: "DPH",
total: "Celkem",
+ total_no_vat: "Celkem bez DPH",
amounts_in: "Částky jsou uvedeny v",
notes: "Poznámky",
delivery_terms: "Dodací podmínky:",
@@ -234,6 +235,7 @@ const translations: Record> = {
subtotal: "Subtotal:",
vat_label: "VAT",
total: "Total",
+ total_no_vat: "Total excl. VAT",
amounts_in: "Amounts are in",
notes: "Notes",
delivery_terms: "Delivery terms:",
@@ -336,14 +338,19 @@ export function renderIssuedOrderHtml(
? `${escapeHtml(it.item_description)}
`
: ""
}`;
+ // Without "Uplatnit DPH" the VAT columns are dropped entirely (the
+ // header does the same) instead of printing meaningless 0% / 0.00.
+ const vatCells = applyVat
+ ? `
+ ${Math.floor(rate)}% |
+ ${formatNum(lineVat)} | `
+ : "";
return `
| ${i + 1} |
${descHtml} |
${formatNum(qty, qtyDecimals)}${it.unit ? ` / ${escapeHtml(it.unit)}` : ""} |
${formatNum(unitPrice)} |
- ${formatNum(lineSubtotal)} |
- ${applyVat ? Math.floor(rate) : 0}% |
- ${formatNum(lineVat)} |
+ ${formatNum(lineSubtotal)} | ${vatCells}
${formatNum(lineTotal)} |
`;
})
@@ -769,13 +776,17 @@ ${indentCSS}
| ${escapeHtml(t.col_no)} |
- ${escapeHtml(t.col_desc)} |
+ ${escapeHtml(t.col_desc)} |
${escapeHtml(t.col_qty)} |
${escapeHtml(t.col_unit_price)} |
- ${escapeHtml(t.col_price)} |
+ ${escapeHtml(t.col_price)} | ${
+ applyVat
+ ? `
${escapeHtml(t.col_vat_pct)} |
- ${escapeHtml(t.col_vat)} |
- ${escapeHtml(t.col_total)} |
+ ${escapeHtml(t.col_vat)} | `
+ : ""
+ }
+ ${escapeHtml(t.col_total)} |
@@ -783,17 +794,21 @@ ${indentCSS}
-
+
-
+
${
+ applyVat
+ ? `
${escapeHtml(t.subtotal)}
${formatNum(subtotal)} ${escapeHtml(currency)}
${vatDetailHtml}
-
+
`
+ : ""
+ }
- ${escapeHtml(t.total)}
+ ${escapeHtml(applyVat ? t.total : t.total_no_vat)}
${formatNum(totalToPay)} ${escapeHtml(currency)}
${escapeHtml(t.amounts_in)} ${escapeHtml(currency)}
diff --git a/src/routes/admin/orders-pdf.ts b/src/routes/admin/orders-pdf.ts
index d8a7ea1..ebbac4c 100644
--- a/src/routes/admin/orders-pdf.ts
+++ b/src/routes/admin/orders-pdf.ts
@@ -200,6 +200,7 @@ const translations: Record
> = {
subtotal: "Mezisoučet:",
vat_label: "DPH",
total: "Celkem",
+ total_no_vat: "Celkem bez DPH",
amounts_in: "Částky jsou uvedeny v",
notes: "Poznámky",
issued_by: "Vystavil:",
@@ -228,6 +229,7 @@ const translations: Record> = {
subtotal: "Subtotal:",
vat_label: "VAT",
total: "Total",
+ total_no_vat: "Total excl. VAT",
amounts_in: "Amounts are in",
notes: "Notes",
issued_by: "Issued by:",
@@ -388,14 +390,19 @@ export default async function ordersPdfRoutes(
const lineTotal = lineSubtotal + lineVat;
const qtyDecimals =
Math.floor(item.quantity) === item.quantity ? 0 : 2;
+ // Without "Uplatnit DPH" the VAT columns are dropped entirely
+ // (the header does the same) instead of printing 0% / 0.00.
+ const vatCells = applyVat
+ ? `
+ ${Math.floor(item.vat_rate)}% |
+ ${formatNum(lineVat)} | `
+ : "";
return `
| ${i + 1} |
${escapeHtml(item.description)} |
${formatNum(item.quantity, qtyDecimals)}${item.unit ? ` / ${escapeHtml(item.unit)}` : ""} |
${formatNum(item.unit_price)} |
- ${formatNum(lineSubtotal)} |
- ${applyVat ? Math.floor(item.vat_rate) : 0}% |
- ${formatNum(lineVat)} |
+ ${formatNum(lineSubtotal)} | ${vatCells}
${formatNum(lineTotal)} |
`;
})
@@ -848,13 +855,17 @@ ${indentCSS}
| ${escapeHtml(t.col_no)} |
- ${escapeHtml(t.col_desc)} |
+ ${escapeHtml(t.col_desc)} |
${escapeHtml(t.col_qty)} |
${escapeHtml(t.col_unit_price)} |
- ${escapeHtml(t.col_price)} |
+ ${escapeHtml(t.col_price)} | ${
+ applyVat
+ ? `
${escapeHtml(t.col_vat_pct)} |
- ${escapeHtml(t.col_vat)} |
- ${escapeHtml(t.col_total)} |
+ ${escapeHtml(t.col_vat)} | `
+ : ""
+ }
+ ${escapeHtml(t.col_total)} |
@@ -862,17 +873,21 @@ ${indentCSS}
-
+
-
+
${
+ applyVat
+ ? `
${escapeHtml(t.subtotal)}
${formatNum(subtotal)} ${escapeHtml(currency)}
${vatDetailHtml}
-
+
`
+ : ""
+ }
- ${escapeHtml(t.total)}
+ ${escapeHtml(applyVat ? t.total : t.total_no_vat)}
${formatNum(totalToPay)} ${escapeHtml(currency)}
${escapeHtml(t.amounts_in)} ${escapeHtml(currency)}