const test = require('node:test'); const assert = require('node:assert/strict'); const { buildTrackerRow, getCycleRange, resolveDueDate, } = require('../services/statusService'); function bill(overrides = {}) { return { id: 1, name: 'Test bill', due_day: 15, expected_amount: 100, autopay_enabled: 0, autodraft_status: 'none', cycle_type: 'monthly', cycle_day: '1', ...overrides, }; } test('monthly bills use due_day and calendar-month cycle range', () => { const monthly = bill({ due_day: 31, cycle_day: '1' }); assert.equal(resolveDueDate(monthly, 2026, 2), '2026-02-28'); assert.deepEqual(getCycleRange(2026, 2, monthly), { start: '2026-02-01', end: '2026-02-28', }); }); test('weekly bills use cycle_day as weekday', () => { const weekly = bill({ cycle_type: 'weekly', cycle_day: 'wednesday' }); assert.equal(resolveDueDate(weekly, 2026, 5), '2026-05-06'); assert.deepEqual(getCycleRange(2026, 5, weekly), { start: '2026-05-06', end: '2026-05-12', }); }); test('biweekly bills use cycle_day weekday on the deterministic two-week cadence', () => { const biweekly = bill({ cycle_type: 'biweekly', cycle_day: 'monday' }); assert.equal(resolveDueDate(biweekly, 2026, 5), '2026-05-04'); assert.deepEqual(getCycleRange(2026, 5, biweekly), { start: '2026-05-04', end: '2026-05-17', }); }); test('quarterly bills only occur in assigned quarter months', () => { const quarterly = bill({ cycle_type: 'quarterly', cycle_day: '2', due_day: 30 }); assert.equal(resolveDueDate(quarterly, 2026, 2), '2026-02-28'); assert.equal(resolveDueDate(quarterly, 2026, 3), null); assert.equal(resolveDueDate(quarterly, 2026, 5), '2026-05-30'); assert.deepEqual(getCycleRange(2026, 5, quarterly), { start: '2026-05-01', end: '2026-07-31', }); }); test('annual bills only occur in their assigned month', () => { const annual = bill({ cycle_type: 'annual', cycle_day: '11', due_day: 31 }); assert.equal(resolveDueDate(annual, 2026, 10), null); assert.equal(resolveDueDate(annual, 2026, 11), '2026-11-30'); assert.deepEqual(getCycleRange(2026, 11, annual), { start: '2026-01-01', end: '2026-12-31', }); }); test('tracker rows are skipped when a bill does not occur in the requested month', () => { const quarterly = bill({ cycle_type: 'quarterly', cycle_day: '1' }); assert.equal(buildTrackerRow(quarterly, [], 2026, 2, '2026-02-01', { gracePeriodDays: 5 }), null); }); test('tracker rows cap due math when a payment exceeds the amount due', () => { const row = buildTrackerRow( bill({ expected_amount: 10000 }), [{ amount: 12500, paid_date: '2026-05-10' }], 2026, 5, '2026-05-16', { gracePeriodDays: 5 }, ); assert.equal(row.status, 'paid'); assert.equal(row.total_paid, 125); assert.equal(row.paid_toward_due, 100); assert.equal(row.overpaid_amount, 25); assert.equal(row.balance, 0); });