// apps/hq/test/receipt.test.ts import { describe, it, expect } from 'vitest' import { openDb } from '../src/db' import { seedIfEmpty } from '../src/seed' import { createClient } from '../src/repos-clients' import { createModule, setPrice } from '../src/repos-modules' import { createDraft, issueDocument, getDocument } from '../src/repos-documents' import { recordPayment, receiptForPayment } from '../src/repos-payments' import { documentHtml } from '../src/templates' async function setup() { const db = openDb(':memory:'); await seedIfEmpty(db) const c = await createClient(db, 'u1', { name: 'Acme', code: 'ACME', stateCode: '32', contacts: [{ name: 'R', email: 'r@acme.in' }] }) const m = await createModule(db, 'u1', { code: 'POS', name: 'POS', allowedKinds: ['yearly'] }) await setPrice(db, 'u1', { moduleId: m.id, kind: 'yearly', pricePaise: 10_000_00, effectiveFrom: '2026-01-01' }) const inv = await issueDocument(db, 'u1', (await createDraft(db, 'u1', { docType: 'INVOICE', clientId: c.id, lines: [{ moduleId: m.id, qty: 1, kind: 'yearly' }] })).id) return { db, c, inv } } describe('payment receipts', () => { it('issues a zero-GST RECEIPT with its own RCT/ series on recordPayment', async () => { const { db, c, inv } = await setup() const out = await recordPayment(db, 'u1', { clientId: c.id, receivedOn: '2026-07-10', mode: 'bank', amountPaise: 11_800_00, allocations: [{ documentId: inv.id, amountPaise: 11_800_00 }], issueReceipt: true, }) expect(out.receipt).toBeDefined() const rc = out.receipt! expect(rc.docType).toBe('RECEIPT') expect(rc.docNo?.startsWith('RCT/')).toBe(true) expect(rc.payablePaise).toBe(11_800_00) expect(rc.cgstPaise + rc.sgstPaise + rc.igstPaise).toBe(0) // acknowledgment, not a tax document expect(rc.payload.receipt?.allocations[0]).toMatchObject({ docNo: inv.docNo, amountPaise: 11_800_00 }) }) it('generates a receipt after the fact from a stored payment', async () => { const { db, c, inv } = await setup() const out = await recordPayment(db, 'u1', { clientId: c.id, receivedOn: '2026-07-10', mode: 'upi', amountPaise: 5_000_00, allocations: [{ documentId: inv.id, amountPaise: 5_000_00 }], }) const rc = await receiptForPayment(db, 'u1', out.payment.id) expect(rc.docType).toBe('RECEIPT') expect((await getDocument(db, rc.id))!.docNo).toBe(rc.docNo) }) it('renders a receipt acknowledgment (no SAC/GST table)', async () => { const { db, c, inv } = await setup() const out = await recordPayment(db, 'u1', { clientId: c.id, receivedOn: '2026-07-10', mode: 'bank', amountPaise: 11_800_00, allocations: [{ documentId: inv.id, amountPaise: 11_800_00 }], issueReceipt: true }) const html = documentHtml(out.receipt!, c, { 'company.name': 'Tecnostac' }) expect(html).toContain('RECEIPT') expect(html).toContain('Received with thanks') expect(html).not.toContain('>SAC<') // the GST line table header is absent on receipts }) })