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.
51 lines
2.5 KiB
TypeScript
51 lines
2.5 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { openDb } from '../src/db'
|
|
import { createClient } from '../src/repos-clients'
|
|
import { assignModule, createModule, setPrice } from '../src/repos-modules'
|
|
import {
|
|
createRecurringPlan, listRecurringPlans, updateRecurringPlan, deactivateRecurringPlan,
|
|
} from '../src/repos-recurring'
|
|
|
|
function setup() {
|
|
const db = openDb(':memory:')
|
|
const c = createClient(db, 'u1', { name: 'Acme', stateCode: '32' })
|
|
const m = createModule(db, 'u1', { code: 'CLOUD', name: 'Cloud Hosting', allowedKinds: ['monthly', 'yearly'] })
|
|
setPrice(db, 'u1', { moduleId: m.id, kind: 'monthly', pricePaise: 2_000_00, effectiveFrom: '2026-04-01' })
|
|
const cm = assignModule(db, 'u1', { clientId: c.id, moduleId: m.id, kind: 'monthly' })
|
|
return { db, c, m, cm }
|
|
}
|
|
|
|
describe('recurring plans', () => {
|
|
it('creates a plan, lists it, updates and deactivates with audit', () => {
|
|
const { db, c, cm } = setup()
|
|
const p = createRecurringPlan(db, 'u1', {
|
|
clientId: c.id, clientModuleId: cm.id, cadence: 'monthly', nextRun: '2026-08-01', policy: 'auto',
|
|
})
|
|
expect(p.policy).toBe('auto')
|
|
expect(p.amountPaise).toBeNull() // price resolves from the module at generation
|
|
expect(listRecurringPlans(db, c.id)).toHaveLength(1)
|
|
const up = updateRecurringPlan(db, 'u1', p.id, { amountPaise: 2_500_00 })
|
|
expect(up.amountPaise).toBe(2_500_00)
|
|
const off = deactivateRecurringPlan(db, 'u1', p.id)
|
|
expect(off.active).toBe(false)
|
|
const audits = db.prepare(`SELECT action FROM audit_log WHERE entity='recurring_plan'`).all()
|
|
expect(audits.length).toBe(3) // create + update + deactivate
|
|
})
|
|
it('rejects a plan whose module has no price and no explicit amount', () => {
|
|
const db = openDb(':memory:')
|
|
const c = createClient(db, 'u1', { name: 'X', stateCode: '32' })
|
|
const m = createModule(db, 'u1', { code: 'POS', name: 'POS', allowedKinds: ['yearly'] })
|
|
const cm = assignModule(db, 'u1', { clientId: c.id, moduleId: m.id, kind: 'yearly' })
|
|
expect(() => createRecurringPlan(db, 'u1', {
|
|
clientId: c.id, clientModuleId: cm.id, cadence: 'yearly', nextRun: '2026-08-01',
|
|
})).toThrow(/price/i)
|
|
})
|
|
it('rejects a client_module that belongs to another client', () => {
|
|
const { db, cm } = setup()
|
|
const other = createClient(db, 'u1', { name: 'Other', stateCode: '32' })
|
|
expect(() => createRecurringPlan(db, 'u1', {
|
|
clientId: other.id, clientModuleId: cm.id, cadence: 'monthly', nextRun: '2026-08-01', amountPaise: 100_00,
|
|
})).toThrow(/client/i)
|
|
})
|
|
})
|