import { describe, it } from 'node:test' import assert from 'node:assert/strict' import { CELL_STORAGE_HEADERS, CUSTOMER_SERVICE_HEADERS, PRESIGN_HEADERS, RESEARCH_HEADERS, buildCellStorageLedgerRows, buildCustomerServiceLedgerRows, buildFreightMergeRanges, buildPresignLedgerRows, buildResearchLedgerRows, formatLedgerDateTime, groupFlatRowsByFreightBatch } from './collection-ledger-export' import type { ProtocolAuditFlatRow } from './protocol-audit-flatten' describe('formatLedgerDateTime', () => { it('uses Chinese text and keeps seconds', () => { assert.equal(formatLedgerDateTime('2026-04-02 16:49:42'), '2026年4月2日16时49分42秒') assert.equal(formatLedgerDateTime('20250907'), '2025年9月7日') }) }) describe('buildPresignLedgerRows', () => { it('maps order fields into the presign sheet columns', () => { const [row] = buildPresignLedgerRows([ { orderDate: '20260402', protocolNo: 'ZKZX1', motherName: '杨育蕾', sampleTypeNames: ['围产期造血干细胞'], regionName: '亳州区域', hospitalName: '涡阳县人民医院', payMode: 'dj', sampleCollectTime: '2026-04-02 16:49:42', contractAmount: 22880, confirmedDepositAmount: 1000, transferTimes: ['2026-04-02 16:49:42'], expectedDeliveryDate: '20260930', salesUserName: '张慧茹', regionManagerUserName: '张颖', remark: '已存' } ]) assert.equal(row.length, PRESIGN_HEADERS.length) assert.deepEqual(row.slice(0, 6), ['1', '2026', '4', '2', 'ZKZX1', '杨育蕾']) assert.equal(row[9], '趸交') assert.equal(row[12], '1000元(定金)') assert.equal(row[13], '2026年4月2日16时49分42秒') assert.equal(row[18], '') }) it('fills refund amount for voided deposit orders', () => { const [row] = buildPresignLedgerRows([ { orderDate: '20250919', motherName: '陈影', confirmedDepositAmount: 1000, transferTimes: ['2025-09-19 17:26:13'], orderStatus: 'void', remark: '悔存-申请退定金' } ]) assert.equal(row[12], '1000元(定金)') assert.equal(row[18], '1000元') }) }) describe('buildCellStorageLedgerRows', () => { it('places installment amounts and keeps template header width', () => { const flat = { protocolId: 'p1', protocol: { protocolStatus: 'sxz', remark: '分期备注', voidType: '', voidDesc: '' }, sampleIndex: 0, isCoStored: false, sampleCollectTime: '2025-09-15 08:51:00', motherName: '郭梦朵', protocolNo: 'PROTO-SHOULD-NOT-EXPORT', sampleCode: 'ZKZX34000849', sampleTypeName: '围产期造血干细胞', regionName: '亳州区域', hospitalName: '涡阳县人民医院', labStorageCode: 'B0000004', salesUserName: '马丽', regionManagerUserName: '张颖', transportType: 'kdys', freightId: 'fr-cell-1', freightTransportLabel: '专线车', freightAmountLabel: '120', monthlyVerifyNo: '202509012', paymentSummary: { payMode: 'fq', contractAmount: 22880, receivedAmount: 6480, pendingAmount: 16400, firstPayTransferTime: '2025-09-15 11:13:01', paymentDetails: [ { installmentNo: 1, dueAmount: 6480, transferAmount: 6480, installmentDueDate: '20250915', transferTime: '2025-09-15 11:13:01' }, { installmentNo: 2, dueAmount: 16400, transferAmount: 0, installmentDueDate: '20251215', transferTime: '' } ] } } as unknown as ProtocolAuditFlatRow const { rows } = buildCellStorageLedgerRows([flat]) const row = rows[0] assert.equal(row.length, CELL_STORAGE_HEADERS.length) assert.equal(CELL_STORAGE_HEADERS[13], '涡阳县人民医院') assert.equal(row[4], '202509012') assert.equal(row[5], 'B0000004') assert.equal(row[6], '生效中') assert.equal(row[9], 'ZKZX34000849') assert.equal(row[11], '否') assert.equal(row[13], '涡阳县人民医院') assert.equal(row[14], '分期') assert.equal(row[16], '22880') assert.equal(row[17], '6480') assert.equal(row[20], '') assert.equal(row[22], '2025年9月15日11时13分01秒') assert.equal(row[24], '16400') assert.equal(row[25], '16400') assert.equal(row[26], '2025年12月15日') assert.equal(row[50], '马丽') assert.equal(row[52], '专线车') assert.equal(row[53], '120') }) it('writes negative refund amount for voided protocols', () => { const { rows } = buildCellStorageLedgerRows([ { protocol: { protocolStatus: 'yzf', remark: '', voidType: 'khhc', voidDesc: '悔存' }, sampleCollectTime: '2025-09-07 13:45:00', motherName: '王晴晴', sampleCode: 'S-VOID', sampleTypeName: '围产期造血干细胞', paymentSummary: { payMode: 'dj', contractAmount: 5000, receivedAmount: 5000, refundAmount: 5000, paymentDetails: [] } } as unknown as ProtocolAuditFlatRow ]) assert.equal(rows[0][19], '5000') assert.equal(rows[0][20], '-5000') }) it('merges transport and freight columns for the same freight batch', () => { const base = { protocol: { protocolStatus: 'sxz', remark: '', voidType: '', voidDesc: '' }, sampleCollectTime: '2025-09-11 18:13:00', motherName: '甲', sampleCode: 'S1', sampleTypeName: 'NK', regionName: '常州', hospitalName: '溧阳市人民医院', labStorageCode: 'UBMC1', freightId: 'batch-cell', freightTransportLabel: '专线车', freightAmountLabel: '100' } const { rows, merges } = buildCellStorageLedgerRows([ { ...base, sampleIndex: 0 } as unknown as ProtocolAuditFlatRow, { ...base, sampleIndex: 1, motherName: '乙', sampleCode: 'S2', labStorageCode: 'UBMC2' } as unknown as ProtocolAuditFlatRow ]) assert.equal(rows[0][52], '专线车') assert.equal(rows[0][53], '100') assert.equal(rows[1][52], '') assert.equal(rows[1][53], '') assert.deepEqual(merges, [ { startRow: 2, endRow: 3, startCol: 53, endCol: 53 }, { startRow: 2, endRow: 3, startCol: 54, endCol: 54 } ]) }) it('groups non-adjacent same freight batch before merging cells', () => { const shared = { protocol: { protocolStatus: 'sxz', remark: '', voidType: '', voidDesc: '' }, sampleCollectTime: '2025-09-11 18:13:00', sampleTypeName: 'NK', regionName: '常州', hospitalName: '溧阳市人民医院', freightTransportLabel: '专线车', freightAmountLabel: '100' } const { rows, merges } = buildCellStorageLedgerRows([ { ...shared, motherName: '甲', sampleCode: 'S1', labStorageCode: 'UBMC1', freightId: 'batch-cell' } as unknown as ProtocolAuditFlatRow, { ...shared, motherName: '丙', sampleCode: 'S3', labStorageCode: 'UBMC3', freightId: 'other', freightTransportLabel: '快递', freightAmountLabel: '25' } as unknown as ProtocolAuditFlatRow, { ...shared, motherName: '乙', sampleCode: 'S2', labStorageCode: 'UBMC2', freightId: 'batch-cell' } as unknown as ProtocolAuditFlatRow ]) assert.equal(rows[0][8], '甲') assert.equal(rows[1][8], '乙') assert.equal(rows[2][8], '丙') assert.equal(rows[0][52], '专线车') assert.equal(rows[0][53], '100') assert.equal(rows[1][52], '') assert.equal(rows[1][53], '') assert.equal(rows[2][52], '快递') assert.equal(rows[2][53], '25') assert.deepEqual(merges, [ { startRow: 2, endRow: 3, startCol: 53, endCol: 53 }, { startRow: 2, endRow: 3, startCol: 54, endCol: 54 } ]) }) }) describe('groupFlatRowsByFreightBatch', () => { it('keeps first-seen batch order and leaves empty freight rows in place', () => { const arranged = groupFlatRowsByFreightBatch([ { motherName: 'A', freightId: 'f1' }, { motherName: 'B', freightId: '' }, { motherName: 'C', freightId: 'f1' }, { motherName: 'D', freightId: 'f2' } ] as unknown as ProtocolAuditFlatRow[]) assert.deepEqual( arranged.map((row) => row.motherName), ['A', 'C', 'B', 'D'] ) }) }) describe('buildResearchLedgerRows', () => { it('maps donation fields and consent flag', () => { const flat = { protocol: { donationStatus: 'yzf', voidType: 'sysfq', voidDesc: '母血乙肝阳性', monthlyVerifyNo: '202508001' }, sampleIndex: 0, sampleCollectTime: '2025-08-29 12:27:00', motherName: '曹陆双', sampleTypeName: '围产期造血干细胞', regionName: '亳州', hospitalName: '涡阳县人民医院', labStorageCode: 'A0000001', salesUserName: '杨莉莉', regionManagerUserName: '张颖', transportType: '', newbornDeliveryTime: '2025-08-29 12:26:00', newbornSex: '0', newbornWeightGram: 3000, deliveryMode: 'sc', birthOrder: 1, maternalBloodCollectTime: '2025-08-29 13:30:00', consentFormUrls: 'http://example/consent', remark: '', freightId: 'fr1', freightTransportLabel: '专线车', freightAmountLabel: '100' } as unknown as ProtocolAuditFlatRow const { rows } = buildResearchLedgerRows([flat]) const row = rows[0] assert.equal(row.length, RESEARCH_HEADERS.length) assert.equal(row[1], '2025年') assert.equal(row[4], '202508001') assert.equal(row[6], '实验室废弃') assert.equal(row[7], '母血乙肝阳性') assert.equal(row[9], '实验室废弃') assert.equal(row[16], '专线车') assert.equal(row[17], '100') assert.equal(row[18], '女') assert.equal(row[19], '3000g') assert.equal(row[20], '顺产') assert.equal(row[23], '1') }) it('keeps sample type in column 10 for active research rows', () => { const { rows } = buildResearchLedgerRows([ { protocol: { donationStatus: 'sxz', voidType: '', voidDesc: '', monthlyVerifyNo: '202508010' }, sampleCollectTime: '2025-08-30 10:00:00', motherName: '正常', sampleTypeName: '围产期造血干细胞', regionName: '亳州', hospitalName: '涡阳县人民医院', freightId: '', freightTransportLabel: '', freightAmountLabel: '' } as unknown as ProtocolAuditFlatRow ]) assert.equal(rows[0][6], '') assert.equal(rows[0][9], '围产期造血干细胞') }) it('maps sdfq void type code to 属地废弃 labels', () => { const flat = { protocol: { donationStatus: 'yzf', voidType: 'sdfq', voidDesc: '', monthlyVerifyNo: '' }, sampleIndex: 0, sampleCollectTime: '2025-08-29 12:27:00', motherName: '测试', sampleTypeName: '围产期造血干细胞', regionName: '亳州', hospitalName: '涡阳县人民医院', labStorageCode: 'A0000002', salesUserName: '', regionManagerUserName: '', transportType: '', newbornDeliveryTime: '', newbornSex: '', newbornWeightGram: '', deliveryMode: 'pgc', birthOrder: '', maternalBloodCollectTime: '', consentFormUrls: '', remark: '', freightId: '', freightTransportLabel: '', freightAmountLabel: '' } as unknown as ProtocolAuditFlatRow const { rows } = buildResearchLedgerRows([flat]) const row = rows[0] assert.equal(row[6], '属地废弃') assert.equal(row[7], '属地废弃') assert.equal(row[9], '属地废弃') assert.equal(row[20], '剖腹产') assert.equal(row[22], '无母血') }) it('merges transport and freight columns for the same freight batch', () => { const base = { protocol: { donationStatus: 'sxz', voidType: '', voidDesc: '', monthlyVerifyNo: '' }, sampleCollectTime: '2025-09-11 18:13:00', motherName: '甲', sampleTypeName: 'NK', regionName: '常州', hospitalName: '溧阳市人民医院', labStorageCode: 'UBMC1', freightId: 'batch-a', freightTransportLabel: '专线车', freightAmountLabel: '100' } const { rows, merges } = buildResearchLedgerRows([ { ...base, sampleIndex: 0 } as unknown as ProtocolAuditFlatRow, { ...base, sampleIndex: 1, motherName: '乙', labStorageCode: 'UBMC2' } as unknown as ProtocolAuditFlatRow ]) assert.equal(rows[0][16], '专线车') assert.equal(rows[0][17], '100') assert.equal(rows[1][16], '') assert.equal(rows[1][17], '') assert.deepEqual(merges, [ { startRow: 2, endRow: 3, startCol: 17, endCol: 17 }, { startRow: 2, endRow: 3, startCol: 18, endCol: 18 } ]) assert.deepEqual(buildFreightMergeRanges(['', 'x', 'x', 'y']), [ { startRow: 3, endRow: 4, startCol: 17, endCol: 17 }, { startRow: 3, endRow: 4, startCol: 18, endCol: 18 } ]) }) it('groups non-adjacent same freight batch before merging research cells', () => { const shared = { protocol: { donationStatus: 'sxz', voidType: '', voidDesc: '', monthlyVerifyNo: '' }, sampleCollectTime: '2025-09-11 18:13:00', sampleTypeName: 'NK', regionName: '常州', hospitalName: '溧阳市人民医院', freightTransportLabel: '专线车', freightAmountLabel: '100' } const { rows, merges } = buildResearchLedgerRows([ { ...shared, motherName: '甲', labStorageCode: 'A1', freightId: 'batch-a' } as unknown as ProtocolAuditFlatRow, { ...shared, motherName: '散', labStorageCode: 'A9', freightId: '', freightTransportLabel: '', freightAmountLabel: '' } as unknown as ProtocolAuditFlatRow, { ...shared, motherName: '乙', labStorageCode: 'A2', freightId: 'batch-a' } as unknown as ProtocolAuditFlatRow ]) assert.equal(rows[0][8], '甲') assert.equal(rows[1][8], '乙') assert.equal(rows[2][8], '散') assert.equal(rows[0][16], '专线车') assert.equal(rows[1][16], '') assert.equal(rows[1][17], '') assert.deepEqual(merges, [ { startRow: 2, endRow: 3, startCol: 17, endCol: 17 }, { startRow: 2, endRow: 3, startCol: 18, endCol: 18 } ]) }) }) describe('buildCustomerServiceLedgerRows', () => { it('fills protocol-number column with sample code', () => { const [row] = buildCustomerServiceLedgerRows([ { labStorageCode: 'B0000002', protocolStatus: 'sxz', smsSendDate: '20250908', smsSendStatus: '已发', sampleCode: 'ZKZX34000852', protocolNo: 'PROTO-SHOULD-NOT-EXPORT', motherName: '高居巧', motherPhone: '17860507206', motherIdCard: '370911199712254424', protocolAttachmentPresent: true, insuranceDocPresent: false, informedConsentPresent: true, healthSurveyPresent: true, payModeLabel: '趸交' } ]) assert.equal(row.length, CUSTOMER_SERVICE_HEADERS.length) assert.equal(row[0], 'B0000002') assert.equal(row[2], '1') assert.equal(row[5], 'ZKZX34000852') assert.equal(row[8], '370911199712254424') assert.equal(row[29], '1') assert.equal(row[30], '0') }) })