采集协议单管理(细胞存储/科研捐赠)展平样本行时未拷贝项目归属字段,导致表格列空白;补齐展平字段并增加回归单测。 Co-authored-by: Cursor <cursoragent@cursor.com>
185 lines
6.4 KiB
TypeScript
185 lines
6.4 KiB
TypeScript
// 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, [])
|
|
})
|
|
})
|