import { computeUpgradeAmounts } from './upgrade.service'; // Pure arithmetic only, mirroring reschedule.service.spec.ts — no Nest test module, no mocks. describe('computeUpgradeAmounts', () => { const free = { feePercent: 0, feeMinMinor: 0, feeWaived: false }; const waived = { feePercent: 30, feeMinMinor: 50000, feeWaived: true }; const percentOnly = { feePercent: 10, feeMinMinor: 0, feeWaived: false }; const flooredFee = { feePercent: 10, feeMinMinor: 50000, feeWaived: false }; it('charges only the fare difference when the class has no fee', () => { // RS 1752.34 → EBC 2336.46, as seeded on dev expect(computeUpgradeAmounts(free, 175234, 233646)).toEqual({ feeMinor: 0, fareDifferenceMinor: 58412, amountDueMinor: 58412, }); }); it('ignores a configured fee when the policy waives it (US-17 §5)', () => { expect(computeUpgradeAmounts(waived, 175234, 233646)).toEqual({ feeMinor: 0, fareDifferenceMinor: 58412, amountDueMinor: 58412, }); }); it('takes the fee as a percentage of the ORIGINAL fare, not of the difference', () => { const r = computeUpgradeAmounts(percentOnly, 175234, 233646); expect(r.feeMinor).toBe(17523); // 10% of 175234, not of 58412 expect(r.amountDueMinor).toBe(17523 + 58412); }); it('applies the fee floor when the percentage falls below it', () => { const r = computeUpgradeAmounts(flooredFee, 100000, 150000); expect(r.feeMinor).toBe(50000); // max(10% of 100000 = 10000, floor 50000) expect(r.amountDueMinor).toBe(100000); }); it('never lets a negative difference reduce the amount due', () => { // Refused upstream, but the arithmetic must not produce a credit if it ever gets here. const r = computeUpgradeAmounts(percentOnly, 200000, 150000); expect(r.fareDifferenceMinor).toBe(-50000); expect(r.amountDueMinor).toBe(r.feeMinor); expect(r.amountDueMinor).toBeGreaterThanOrEqual(0); }); it('charges the full target fare for a free child', () => { const r = computeUpgradeAmounts(free, 0, 233646); expect(r.feeMinor).toBe(0); // a percentage of zero is zero expect(r.amountDueMinor).toBe(233646); }); });