'use strict'; const test = require('node:test'); const assert = require('node:assert/strict'); const XLSX = require('xlsx'); const { normalizeRecords, parseWorkbook, checkBalance, } = require('../src/services/dailyInventoryOfficial'); const RECORDS = [ { 一级功能按键: '大货库存监控', 二级功能按键: '每日进销存', 仓库: '简尚-崔桥工厂仓主仓', 期初数量: 90811, 加工进仓: 0, 采购退货: 0, 采购进仓: 0, 其它进仓: 0, 其它退货: 0, 销售出仓: -3252, 盘点: 0, 加工出仓: 0, 调拨出: -881, 销售退货: 0, 调拨入: 4144, 期初: 0, 其它出库: 0, 期末数量: 90822, }, { 仓库: '简尚-新外贸仓主仓', 期初数量: 5165, 销售出仓: -1743, 期末数量: 3422, }, ]; test('normalizeRecords 解析官方导出并映射仓库 ID', () => { const { rows, warnings } = normalizeRecords(RECORDS); assert.equal(rows.length, 2); assert.deepEqual(warnings, []); const [cuiqiao] = rows; assert.equal(cuiqiao.warehouse, '简尚-崔桥工厂仓主仓'); assert.equal(cuiqiao.wmsCoId, 15038426); // 来自项目仓库清单 assert.equal(cuiqiao.openingQty, 90811); assert.equal(cuiqiao.closingQty, 90822); assert.equal(cuiqiao.flows.salesOut, -3252); assert.equal(cuiqiao.flows.transferIn, 4144); assert.equal(cuiqiao.flows.otherIn, 0); // 导出里显式为 0 的列保留 0 // 导出里没有出现的流水列保持 null,不能被当成 0 assert.equal(rows[1].flows.transferOut, null); assert.equal(rows[1].flows.stocktaking, null); // 导出里的第二个「期初」列不参与映射 assert.equal(Object.prototype.hasOwnProperty.call(cuiqiao.flows, 'openingQty'), false); }); test('normalizeRecords 跳过无仓库名的行,未匹配仓库的 wmsCoId 为 null', () => { const { rows } = normalizeRecords([ { 仓库: '', 期初数量: 1, 期末数量: 1 }, { 仓库: '某某新仓主仓', 期初数量: 10, 期末数量: 10 }, ]); assert.equal(rows.length, 1); assert.equal(rows[0].warehouse, '某某新仓主仓'); assert.equal(rows[0].wmsCoId, null); }); test('checkBalance 校验「期初 + 流水 = 期末」,不闭合的仓库会被列出', () => { const { rows } = normalizeRecords(RECORDS); assert.deepEqual(checkBalance(rows), []); const broken = checkBalance([{ warehouse: '差异仓', openingQty: 100, closingQty: 90, flows: { salesOut: -5 }, }]); assert.equal(broken.length, 1); assert.equal(broken[0].diff, 5); }); test('parseWorkbook 能从 xlsx 缓冲区还原仓库行(表头不在首行也能定位)', () => { const grid = [ ['说明', '这一行是导出时附加的标题'], ['一级功能按键', '二级功能按键', '仓库', '期初数量', '销售出仓', '调拨入', '期末数量'], ['大货库存监控', '每日进销存', '简尚-崔桥工厂仓主仓', 90811, -3252, 4144, 90822], ['', '', '简尚-新外贸仓主仓', 5165, -1743, 0, 3422], ]; const ws = XLSX.utils.aoa_to_sheet(grid); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 'Sheet2'); const buffer = XLSX.write(wb, { type: 'buffer', bookType: 'xlsx' }); const { rows, sheetName } = parseWorkbook(buffer); assert.equal(sheetName, 'Sheet2'); assert.equal(rows.length, 2); assert.equal(rows[0].warehouse, '简尚-崔桥工厂仓主仓'); assert.equal(rows[0].flows.transferIn, 4144); assert.equal(rows[1].closingQty, 3422); });