/** * Form 16 reconciliation tests. * - Ledger: one CREDIT/DEBIT row per credit/debit note; no deletion (see docs/form16/LEDGER.md). * - 26AS: only Section 194Q, Booking F/O; quarter aggregation; snapshot + auto-debit when total changes. * - Form 16 match: latest 26AS aggregate only; reject mismatch/duplicate. * * Run: npm test -- form16-reconciliation * Or: npm test -- --testPathPattern=form16 * * Optional: FORM16_TEST_DB=1 to run integration tests (requires DB). */ import { getLatest26asAggregatedForQuarter, getLatest26asSnapshot, getQuarterStatus, process26asUploadAggregation, upload26asFile, parse26asTxtFile, } from '../services/form16.service'; describe('Form 16 reconciliation', () => { describe('parse26asTxtFile', () => { it('parses 26AS official format (^ delimiter) and extracts sectionCode 194Q and statusOltas F', () => { const header = '1^Deductor Name^TAN12345G^^^^^Total^Tax^TDS'; const line = '^1^194Q^30-Sep-2024^F^24-Oct-2024^-^1000^100^100'; const buffer = Buffer.from([header, line].join('\n'), 'utf8'); const { rows, errors } = parse26asTxtFile(buffer); expect(errors).toEqual([]); expect(rows.length).toBeGreaterThanOrEqual(1); expect(rows[0].sectionCode).toBe('194Q'); expect(rows[0].statusOltas).toBe('F'); expect(rows[0].taxDeducted).toBe(100); }); it('returns empty rows for empty buffer', () => { const { rows, errors } = parse26asTxtFile(Buffer.from('', 'utf8')); expect(rows).toEqual([]); expect(errors).toEqual([]); }); it('filters by section and booking status in aggregation (194Q, F/O only) – documented behavior', () => { expect(parse26asTxtFile(Buffer.from('x', 'utf8'))).toBeDefined(); }); }); describe('aggregation and snapshot helpers', () => { it('getLatest26asAggregatedForQuarter is a function', () => { expect(typeof getLatest26asAggregatedForQuarter).toBe('function'); }); it('getLatest26asSnapshot is a function', () => { expect(typeof getLatest26asSnapshot).toBe('function'); }); it('getQuarterStatus is a function', () => { expect(typeof getQuarterStatus).toBe('function'); }); }); describe('upload and process', () => { it('upload26asFile accepts buffer and optional uploadLogId', () => { expect(typeof upload26asFile).toBe('function'); }); it('process26asUploadAggregation returns snapshotsCreated and debitsCreated', () => { expect(typeof process26asUploadAggregation).toBe('function'); }); }); });