import { describe, expect, it } from 'vitest' import { isExpired, pickFefoBatch, sortFefo, type BatchStock } from '@sims/domain' /** * S5 FEFO — the single batch-pick rule shared by the POS picker and the expiry * dashboard. Dates are ISO strings so ordering is lexicographic; "today" here is * 2026-07-10 (the demo business date). */ const TODAY = '2026-07-10' const b = (id: string, batchNo: string, expiryDate: string | undefined, onHand = 10): BatchStock => ({ id, itemId: 'i-107', batchNo, ...(expiryDate !== undefined ? { expiryDate } : {}), onHand, }) describe('S5 FEFO — sortFefo', () => { it('orders earliest expiry first, undated lots last', () => { const sorted = sortFefo([ b('c', 'B-C', '2026-12-31'), b('u', 'B-U', undefined), b('a', 'B-A', '2026-07-15'), b('x', 'B-X', '2026-07-05'), // already expired — still earliest ]) expect(sorted.map((x) => x.id)).toEqual(['x', 'a', 'c', 'u']) }) it('breaks an exact expiry tie by batch_no and does not mutate the input', () => { const input = [b('2', 'B-Z', '2026-07-20'), b('1', 'B-A', '2026-07-20')] const sorted = sortFefo(input) expect(sorted.map((x) => x.batchNo)).toEqual(['B-A', 'B-Z']) expect(input.map((x) => x.id)).toEqual(['2', '1']) // original order intact }) }) describe('S5 FEFO — isExpired', () => { it('is true only for a dated lot strictly before today', () => { expect(isExpired({ expiryDate: '2026-07-09' }, TODAY)).toBe(true) expect(isExpired({ expiryDate: TODAY }, TODAY)).toBe(false) // expires today = still sellable expect(isExpired({ expiryDate: '2026-07-11' }, TODAY)).toBe(false) expect(isExpired({ expiryDate: undefined }, TODAY)).toBe(false) // undated never expires }) }) describe('S5 FEFO — pickFefoBatch', () => { it('preselects the earliest NON-expired lot, skipping expired ones', () => { const pick = pickFefoBatch([ b('x', 'B-X', '2026-07-05'), // expired — skipped b('a', 'B-A', '2026-07-15'), // earliest sellable b('c', 'B-C', '2026-12-31'), ], TODAY) expect(pick?.id).toBe('a') }) it('falls back to the earliest-expiring lot when every lot is expired', () => { const pick = pickFefoBatch([ b('y', 'B-Y', '2026-07-08'), b('x', 'B-X', '2026-07-01'), // earliest of the expired ], TODAY) expect(pick?.id).toBe('x') }) it('returns undefined for an empty list', () => { expect(pickFefoBatch([], TODAY)).toBeUndefined() }) })