You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
54 lines
2.9 KiB
TypeScript
54 lines
2.9 KiB
TypeScript
// 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': 'SiMS' })
|
|
expect(html).toContain('RECEIPT')
|
|
expect(html).toContain('Received with thanks')
|
|
expect(html).not.toContain('>SAC<') // the GST line table header is absent on receipts
|
|
})
|
|
})
|