import { buildInvoice, Invoice } from '../src/invoicing'; import { Customer } from '../src/auth'; import { TierConfig } from '../src/pricing'; import { UsageEntry } from '../src/usage'; const pro: TierConfig = { id: 'pro', name: 'Pro', multiplier: 0.5, monthlyCreditCents: 1000 }; const customer: Customer = { id: 'cust_2', name: 'Grace', tierId: 'pro', apiKey: 'key-grace', stripeCustomerId: 'cus_123', }; const entry = (endpointId: string, cents: number): UsageEntry => ({ customerId: customer.id, endpointId, cents, metadataBytes: 0, attachmentBytes: 0, timestamp: new Date('2026-07-10T12:00:00Z'), }); describe('buildInvoice', () => { it('groups usage entries into lines per endpoint, sorted', () => { const inv = buildInvoice({ customer, period: '2026-07', sequence: 1, tier: pro, entries: [entry('transform', 3), entry('storage', 6), entry('transform', 3)], }); expect(inv.lines).toEqual([ { endpointId: 'storage', calls: 1, cents: 6 }, { endpointId: 'transform', calls: 2, cents: 6 }, ]); expect(inv.totalCents).toBe(12); }); it('applies a partial monthly credit', () => { const inv = buildInvoice({ customer, period: '2026-07', sequence: 1, tier: pro, entries: [entry('storage', 1500)], }); expect(inv.totalCents).toBe(1500); expect(inv.creditCents).toBe(1000); expect(inv.billableCents).toBe(500); }); it('floors billable at zero when credit exceeds usage', () => { const inv = buildInvoice({ customer, period: '2026-07', sequence: 1, tier: pro, entries: [entry('storage', 400)], }); expect(inv.creditCents).toBe(400); expect(inv.billableCents).toBe(0); }); it('formats the id as INV-- and starts as draft', () => { const inv = buildInvoice({ customer, period: '2026-07', sequence: 7, tier: pro, entries: [] }); expect(inv.id).toBe('INV-2026-07-0007'); expect(inv.status).toBe('draft'); expect(inv.billingType).toBe('stripe'); }); it('carries purchase-order billing fields', () => { const poCustomer: Customer = { ...customer, billingType: 'purchase_order' }; const inv = buildInvoice({ customer: poCustomer, period: '2026-07', sequence: 2, tier: pro, entries: [entry('storage', 2000)], poNumber: 'PO-9982', }); expect(inv.billingType).toBe('purchase_order'); expect(inv.poNumber).toBe('PO-9982'); }); });