diff --git a/apps/hq-web/src/pages/DocumentView.tsx b/apps/hq-web/src/pages/DocumentView.tsx index fb75d51..c87ace0 100644 --- a/apps/hq-web/src/pages/DocumentView.tsx +++ b/apps/hq-web/src/pages/DocumentView.tsx @@ -219,10 +219,16 @@ export function DocumentView() { {paying && ( - { setPaying(false); full.reload() }} - /> +
+
+

Record payment {doc.docNo !== null ? `— ${doc.docNo}` : ''}

+ +
+ { setPaying(false); full.reload() }} + /> +
)} {pdfErr !== undefined && PDF preview unavailable: {pdfErr}} diff --git a/apps/hq/src/templates.ts b/apps/hq/src/templates.ts index c504049..39a978d 100644 --- a/apps/hq/src/templates.ts +++ b/apps/hq/src/templates.ts @@ -74,6 +74,29 @@ function lineRow(l: BillLine, i: number, contents: string[]): string { ` } +/** + * Legacy APEX-imported documents carry only totals (no per-line detail). Rather than print + * a blank line table, show ONE summary line derived from the document's own stored totals: + * description from the doc-number's module prefix (e.g. "SMS/2024/10057" → "SMS"), qty 1, + * rate = taxable, and the GST% back-computed from the tax on the taxable value. Display-only + * — issued documents are never modified (immutability rule). + */ +function fallbackLineRow(doc: Doc): string { + const tax = doc.cgstPaise + doc.sgstPaise + doc.igstPaise + const rateBp = doc.taxablePaise > 0 ? Math.round((tax / doc.taxablePaise) * 10000) : 0 + const label = doc.docNo !== null && doc.docNo.includes('/') ? doc.docNo.split('/')[0]! : 'Software services' + return ` + 1 + ${esc(label)} + — + 1 + ${formatINR(doc.taxablePaise)} + ${formatINR(doc.taxablePaise)} + ${rateBp / 100}% + ${formatINR(doc.payablePaise)} + ` +} + function totalsRows(doc: Doc): string { const rows: [string, Paise][] = [['Taxable Value', doc.taxablePaise]] if (doc.igstPaise > 0) { @@ -254,7 +277,9 @@ export function documentHtml(doc: Doc, client: Client, company: Record - ${doc.payload.lines.map((l, i) => lineRow(l, i, doc.payload.lineContents?.[i] ?? [])).join('\n')} + ${doc.payload.lines.length > 0 + ? doc.payload.lines.map((l, i) => lineRow(l, i, doc.payload.lineContents?.[i] ?? [])).join('\n') + : fallbackLineRow(doc)} `}