// apps/hq/test/sms-balances.test.ts — D28: SMS credit review + low-balance flag. 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, setModuleFieldValues } from '../src/repos-modules' import { setSetting } from '../src/repos-reminders' import { smsBalances } from '../src/repos-sms' describe('smsBalances (D28)', () => { it('parses the sms_balance field, flags low, sorts lowest-first, unknown sinks', async () => { const db = openDb(':memory:'); await seedIfEmpty(db) // SMS module (with its sms_balance service field) comes from APEX import in prod; make it here. const sms = await createModule(db, 'u1', { code: 'SMS', name: 'SMS Alerts', sac: '998319', allowedKinds: ['yearly'], fieldSpec: [{ key: 'sms_balance', label: 'SMS balance', type: 'text' }], }) await setSetting(db, 'u1', 'sms.low_balance_threshold', '10000') const low = await createClient(db, 'u1', { name: 'Low Bank', stateCode: '32' }) const high = await createClient(db, 'u1', { name: 'High Bank', stateCode: '32' }) const blank = await createClient(db, 'u1', { name: 'Blank Bank', stateCode: '32' }) // Only LIVE SMS shows on the balance screen (D28) — assign these live. const cmLow = await assignModule(db, 'u1', { clientId: low.id, moduleId: sms.id, kind: 'yearly', status: 'live' }) const cmHigh = await assignModule(db, 'u1', { clientId: high.id, moduleId: sms.id, kind: 'yearly', status: 'live' }) await assignModule(db, 'u1', { clientId: blank.id, moduleId: sms.id, kind: 'yearly', status: 'live' }) await setModuleFieldValues(db, 'u1', cmLow.id, { sms_balance: '2,500' }) // comma-formatted, below threshold await setModuleFieldValues(db, 'u1', cmHigh.id, { sms_balance: '82000' }) // above threshold const b = await smsBalances(db) expect(b.threshold).toBe(10000) expect(b.total).toBe(3) expect(b.lowCount).toBe(1) expect(b.unknownCount).toBe(1) // lowest known first, unknown last expect(b.rows[0]!.clientName).toBe('Low Bank') expect(b.rows[0]!.balance).toBe(2500) expect(b.rows[0]!.low).toBe(true) expect(b.rows[1]!.clientName).toBe('High Bank') expect(b.rows[1]!.low).toBe(false) expect(b.rows[2]!.balance).toBeNull() // blank → unknown, sunk to bottom }) })