// apps/hq/test/milestone-payment.test.ts — payment_id on milestone + link on payment-step tick. import { describe, it, expect } from 'vitest' import { openDb } from '../src/db' import { seedIfEmpty } from '../src/seed' import { createClient } from '../src/repos-clients' import { createModule, assignModule } from '../src/repos-modules' import { setMilestone, listProjectMilestones } from '../src/repos-milestones' import { recordPayment } from '../src/repos-payments' async function world() { const db = openDb(':memory:') await seedIfEmpty(db) const c = await createClient(db, 'u1', { name: 'Kothavara SCB', stateCode: '32' }) const m = await createModule(db, 'u1', { code: 'SMS', name: 'Bulk SMS' }) const cm = await assignModule(db, 'u1', { clientId: c.id, moduleId: m.id, kind: 'yearly' }) return { db, clientId: c.id, cmId: cm.id } } describe('milestone payment_id link (payment-step tick)', () => { it('linking a payment to payment_received stores payment_id and mirrors received_on', async () => { const { db, clientId, cmId } = await world() const pay = await recordPayment(db, 'u1', { clientId, receivedOn: '2026-05-01', mode: 'bank', amountPaise: 1000_00, }) await setMilestone(db, 'u1', cmId, 'payment_received', true, undefined, pay.payment.id) const ms = (await listProjectMilestones(db, cmId)).find((m) => m.key === 'payment_received')! expect(ms.done).toBe(true) expect(ms.doneOn).toBe('2026-05-01') expect(ms.paymentId).toBe(pay.payment.id) }) it('rejects a payment that belongs to a different client', async () => { const { db, cmId } = await world() const other = await createClient(db, 'u1', { name: 'Other Bank', stateCode: '32' }) const pay = await recordPayment(db, 'u1', { clientId: other.id, receivedOn: '2026-05-01', mode: 'bank', amountPaise: 500_00, }) await expect( setMilestone(db, 'u1', cmId, 'payment_received', true, undefined, pay.payment.id), ).rejects.toThrow(/payment/i) }) it('unticking clears payment_id along with done_on', async () => { const { db, clientId, cmId } = await world() const pay = await recordPayment(db, 'u1', { clientId, receivedOn: '2026-05-01', mode: 'bank', amountPaise: 1000_00, }) await setMilestone(db, 'u1', cmId, 'payment_received', true, undefined, pay.payment.id) await setMilestone(db, 'u1', cmId, 'payment_received', false) const ms = (await listProjectMilestones(db, cmId)).find((m) => m.key === 'payment_received')! expect(ms.done).toBe(false) expect(ms.doneOn).toBeNull() expect(ms.paymentId).toBeNull() }) it('an explicit doneOn wins over the payment received_on', async () => { const { db, clientId, cmId } = await world() const pay = await recordPayment(db, 'u1', { clientId, receivedOn: '2026-05-01', mode: 'bank', amountPaise: 1000_00, }) await setMilestone(db, 'u1', cmId, 'payment_received', true, '2026-05-10', pay.payment.id) const ms = (await listProjectMilestones(db, cmId)).find((m) => m.key === 'payment_received')! expect(ms.doneOn).toBe('2026-05-10') expect(ms.paymentId).toBe(pay.payment.id) }) })