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.
sims-hq/apps/hq/test/reminders.test.ts

50 lines
2.7 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { openDb } from '../src/db'
import { reminderEmail } from '../src/reminder-templates'
import {
upsertReminder, listQueue, dismissReminder, setReminderStatus, getReminder,
getNumberSetting, setSetting,
} from '../src/repos-reminders'
describe('reminder templates', () => {
it('renders an overdue dunning email with the amount and a polite tone', () => {
const mail = reminderEmail('invoice_overdue', {
clientName: 'Malabar Stores', companyName: 'SiMS',
docNo: 'INV/26-27-0007', amountPaise: 11_800_00, daysOverdue: 12,
})
expect(mail.subject).toContain('INV/26-27-0007')
expect(mail.bodyText).toContain('₹11,800.00')
expect(mail.bodyText).toContain('12 day')
})
})
describe('reminder repo', () => {
it('is idempotent on (rule_kind, subject_id, due_period)', async () => {
const db = openDb(':memory:')
const a = await upsertReminder(db, { ruleKind: 'invoice_overdue', subjectId: 'inv1', duePeriod: '2026-07', clientId: 'c1', docId: 'inv1', now: '2026-07-10T00:00:00Z' })
expect(a.created).toBe(true)
const b = await upsertReminder(db, { ruleKind: 'invoice_overdue', subjectId: 'inv1', duePeriod: '2026-07', clientId: 'c1', docId: 'inv1', now: '2026-07-10T06:00:00Z' })
expect(b.created).toBe(false)
expect(b.id).toBe(a.id) // same row returned, not a duplicate
expect((await listQueue(db)).rows).toHaveLength(1) // Phase 6: listQueue paginates ({ rows, total, page, pageSize })
expect((await listQueue(db)).total).toBe(1)
expect(await db.get(`SELECT COUNT(*) AS n FROM audit_log WHERE entity='reminder'`)).toMatchObject({ n: 1 })
})
it('transitions and dismisses, refusing to dismiss a sent reminder', async () => {
const db = openDb(':memory:')
const { id } = await upsertReminder(db, { ruleKind: 'follow_up', subjectId: 'i1', duePeriod: '2026-07-08', clientId: 'c1', now: '2026-07-10T00:00:00Z' })
const dismissed = await dismissReminder(db, 'u1', id)
expect(dismissed.status).toBe('dismissed')
const { id: id2 } = await upsertReminder(db, { ruleKind: 'invoice_overdue', subjectId: 'inv2', duePeriod: '2026-07', clientId: 'c1', docId: 'inv2', now: '2026-07-10T00:00:00Z' })
await setReminderStatus(db, 'u1', id2, 'sent', { sentAt: '2026-07-10T09:00:00Z' })
expect((await getReminder(db, id2))!.status).toBe('sent')
await expect(dismissReminder(db, 'u1', id2)).rejects.toThrow(/sent/i)
})
it('reads number settings with a fallback', async () => {
const db = openDb(':memory:')
expect(await getNumberSetting(db, 'reminders.overdue_days', 7)).toBe(7)
await setSetting(db, 'u1', 'reminders.overdue_days', '10')
expect(await getNumberSetting(db, 'reminders.overdue_days', 7)).toBe(10)
})
})