// web-admin/src/utils/protocol-audit-flatten.test.ts import { describe, it } from 'node:test' import assert from 'node:assert/strict' import { flattenProtocolAuditRows, extractCollectDate, uniqueProtocolsFromFlatRows, firstPayTimeLines } from './protocol-audit-flatten' describe('extractCollectDate', () => { it('takes YYYY-MM-DD from datetime', () => { assert.equal(extractCollectDate('2025-09-15 08:51:00'), '2025-09-15') assert.equal(extractCollectDate('2025-09-15T08:51:00'), '2025-09-15') }) it('empty → empty', () => { assert.equal(extractCollectDate(''), '') assert.equal(extractCollectDate(undefined), '') }) }) describe('flattenProtocolAuditRows', () => { it('one protocol two samples → two rows, both co-stored', () => { const rows = flattenProtocolAuditRows([ { id: 'p1', protocolNo: 'ZKZX1', motherName: '郭梦朵', projectName: '测试项目', teamName: '陈星项目组111', sampleCollectTime: '2025-09-15 08:51:00', sampleItems: [ { sampleTypeName: '脐带血', sampleCode: 'A1', labStorageCode: 'B0000004' }, { sampleTypeName: '胎盘', sampleCode: 'A2', labStorageCode: 'B0000004A' } ] } ]) assert.equal(rows.length, 2) assert.equal(rows[0].isCoStored, true) assert.equal(rows[1].isCoStored, true) assert.equal(rows[0].collectDate, '2025-09-15') assert.equal(rows[0].labStorageCode, 'B0000004') assert.equal(rows[1].labStorageCode, 'B0000004A') assert.equal(rows[0].protocolId, 'p1') assert.equal(rows[0].projectName, '测试项目') assert.equal(rows[0].teamName, '陈星项目组111') assert.equal(rows[1].projectName, '测试项目') assert.equal(rows[1].teamName, '陈星项目组111') }) it('copies protocol project attribution onto each flat row for table props', () => { const rows = flattenProtocolAuditRows([ { id: 'p-attr', projectName: '归属项目', teamName: '归属项目组', sampleItems: [{ sampleCode: 'ZKZX34000199', sampleTypeName: '围产期造血干细胞' }] } ]) assert.equal(rows.length, 1) assert.equal(rows[0].projectName, '归属项目') assert.equal(rows[0].teamName, '归属项目组') assert.equal(rows[0].sampleCode, 'ZKZX34000199') }) it('zero samples → one placeholder row, not co-stored', () => { const rows = flattenProtocolAuditRows([{ id: 'p2', protocolNo: 'ZKZX2', sampleItems: [] }]) assert.equal(rows.length, 1) assert.equal(rows[0].isCoStored, false) assert.equal(rows[0].labStorageCode, '') }) it('one sample → not co-stored', () => { const rows = flattenProtocolAuditRows([ { id: 'p3', sampleItems: [{ sampleTypeName: '脐带血', sampleCode: 'C1', labStorageCode: 'B7' }] } ]) assert.equal(rows.length, 1) assert.equal(rows[0].isCoStored, false) }) it('donationNo maps to protocolNo', () => { const rows = flattenProtocolAuditRows([ { id: 'd1', donationNo: 'JZ-001', sampleItems: [{ sampleTypeName: '脐带血', sampleCode: 'D1', labStorageCode: 'B9' }] } ]) assert.equal(rows[0].protocolNo, 'JZ-001') }) it('passes research donation excel-parity fields from protocol', () => { const rows = flattenProtocolAuditRows([ { id: 'd2', donationNo: 'JZ-002', monthlyVerifyNo: '202508001', donationStatus: 'sdfq', voidDesc: '母血乙肝阳性', newbornDeliveryTime: '2025-08-29 12:26:00', newbornSex: '0', newbornWeightGram: 3000, deliveryMode: 'sc', birthOrder: 1, maternalBloodCollectTime: '2025-08-29 13:30:00', consentFormUrls: 'https://x/a.pdf', infectiousDiseaseReportUrls: '', attachmentUrls: 'https://x/b.pdf', remark: '备注一', sampleItems: [{ sampleTypeName: 'NK', sampleCode: 'D2', labStorageCode: 'A1' }] } ]) assert.equal(rows[0].monthlyVerifyNo, '202508001') assert.equal(rows[0].donationStatus, 'sdfq') assert.equal(rows[0].voidDesc, '母血乙肝阳性') assert.equal(rows[0].birthOrder, '1') assert.equal(rows[0].newbornWeightGram, '3000') assert.equal(rows[0].consentFormUrls, 'https://x/a.pdf') assert.equal(rows[0].infectiousDiseaseReportUrls, '') assert.equal(rows[0].attachmentUrls, 'https://x/b.pdf') assert.equal(rows[0].remark, '备注一') }) }) describe('uniqueProtocolsFromFlatRows', () => { it('dedupes by protocolId keeping first protocol ref', () => { const flat = flattenProtocolAuditRows([ { id: 'p1', motherName: 'A', sampleItems: [ { sampleCode: '1', labStorageCode: 'B1' }, { sampleCode: '2', labStorageCode: 'B2' } ] } ]) const uniq = uniqueProtocolsFromFlatRows(flat) assert.equal(uniq.length, 1) assert.equal(String(uniq[0].id), 'p1') }) }) describe('firstPayTimeLines', () => { it('prefers firstPayTransferTime from summary', () => { const lines = firstPayTimeLines({ firstPayTransferTime: '2025-09-20 14:30:00', paymentDetails: [ { installmentNo: 1, transferTime: '2025-09-15 09:20:00' }, { installmentNo: 2, transferTime: '2025-10-15 10:05:00' } ] }) assert.deepEqual(lines, ['2025-09-20 14:30:00']) }) it('only first period; ignores later installments', () => { const lines = firstPayTimeLines({ paymentDetails: [ { installmentNo: 1, transferTime: '2025-09-15 09:20:00', installmentDueDate: '2025-09-01' }, { installmentNo: 2, transferTime: '2025-10-15 10:05:00' }, { installmentNo: 3, transferTime: '2025-11-15 11:00:00' } ] }) assert.deepEqual(lines, ['2025-09-15 09:20:00']) }) it('among period-1 transfers picks the earliest transferTime', () => { const lines = firstPayTimeLines({ paymentDetails: [ { installmentNo: 1, transferTime: '2025-09-15 09:20:00' }, { installmentNo: 1, transferTime: '2025-09-20 14:30:00' }, { installmentNo: 1, transferTime: '2025-09-18 08:00:00' }, { installmentNo: 2, transferTime: '2025-10-15 10:05:00' } ] }) assert.deepEqual(lines, ['2025-09-15 09:20:00']) }) it('empty when period 1 has no transferTime', () => { const lines = firstPayTimeLines({ paymentDetails: [{ installmentNo: 1, installmentDueDate: '2025-09-01' }] }) assert.deepEqual(lines, []) }) })