feat: 新增每日进销存(大货库存监控)
This commit is contained in:
parent
37c1adf4f2
commit
700d7ae96d
96
backend/scripts/verify-daily-inventory.js
Normal file
96
backend/scripts/verify-daily-inventory.js
Normal file
@ -0,0 +1,96 @@
|
||||
process.env.CANGKU_SKIP_BOOTSTRAP = '1';
|
||||
const http = require('http');
|
||||
const XLSX = require('xlsx');
|
||||
|
||||
const FIELD_MAP = [
|
||||
['期初数量', 'openingQty'],
|
||||
['加工进仓', 'processIn'],
|
||||
['采购退货', 'purchaseReturn'],
|
||||
['采购进仓', 'purchaseIn'],
|
||||
['其它进仓', 'otherIn'],
|
||||
['其它退货', 'otherReturn'],
|
||||
['销售出仓', 'salesOut'],
|
||||
['盘点', 'stocktaking'],
|
||||
['加工出仓', 'processOut'],
|
||||
['调拨出', 'transferOut'],
|
||||
['销售退货', 'salesReturn'],
|
||||
['调拨入', 'transferIn'],
|
||||
['期初', 'openingQtyExtra'],
|
||||
['其它出库', 'otherOut'],
|
||||
['期末数量', 'closingQty'],
|
||||
];
|
||||
|
||||
function req(method, path, token, body) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const data = body ? JSON.stringify(body) : null;
|
||||
const r = http.request({
|
||||
host: '127.0.0.1', port: 4001, path, method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(data ? { 'Content-Length': Buffer.byteLength(data) } : {}),
|
||||
...(token ? { Authorization: 'Bearer ' + token } : {}),
|
||||
},
|
||||
}, (resp) => { let s = ''; resp.on('data', (d) => { s += d; }); resp.on('end', () => resolve({ code: resp.statusCode, body: s })); });
|
||||
r.on('error', reject);
|
||||
if (data) r.write(data);
|
||||
r.end();
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const login = JSON.parse((await req('POST', '/api/auth/local-preview', null, {})).body);
|
||||
const token = login.access_token || login.token;
|
||||
const res = await req('GET', '/api/daily-inventory', token);
|
||||
if (res.code !== 200) { console.log('接口失败', res.code, res.body.slice(0, 300)); process.exit(1); }
|
||||
const d = JSON.parse(res.body).data;
|
||||
|
||||
const wb = XLSX.readFile('C:/Users/15018737611/Desktop/库存监控.xlsx');
|
||||
const rows = XLSX.utils.sheet_to_json(wb.Sheets['Sheet1'], { header: 1, defval: '' });
|
||||
const h = rows[0];
|
||||
const idx = Object.fromEntries(h.map((c, i) => [String(c).trim(), i]));
|
||||
const byName = new Map(d.items.map((it) => [it.warehouse, it]));
|
||||
|
||||
console.log('接口: 基准日 %s | 快照日 %s | asOf %s | 仓数 %d', d.baselineDate, d.latestBizDate, d.asOf, d.items.length);
|
||||
console.log();
|
||||
|
||||
const diffCounts = {};
|
||||
let totalCells = 0;
|
||||
let diffCells = 0;
|
||||
const samples = [];
|
||||
|
||||
for (const r of rows.slice(1)) {
|
||||
const name = String(r[idx['仓库']] || '').trim();
|
||||
if (!name) continue;
|
||||
const item = byName.get(name);
|
||||
if (!item) { console.log('接口缺少仓库:', name); continue; }
|
||||
for (const [cn, field] of FIELD_MAP) {
|
||||
const raw = r[idx[cn]];
|
||||
const expected = typeof raw === 'number' ? raw : Number(String(raw || '').replace(/,/g, '')) || 0;
|
||||
const actual = Number(item[field] ?? 0);
|
||||
totalCells += 1;
|
||||
// 期末允许 1 件内的副本同步误差
|
||||
const tol = field === 'closingQty' ? 10 : 0;
|
||||
if (Math.abs(expected - actual) > tol) {
|
||||
diffCells += 1;
|
||||
diffCounts[cn] = (diffCounts[cn] || 0) + 1;
|
||||
if (samples.length < 12) samples.push(`${name} | ${cn} | 表格 ${expected} vs 接口 ${actual}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('比对单元格总数: %d,不一致: %d', totalCells, diffCells);
|
||||
if (diffCells) {
|
||||
console.log('\n不一致列统计:', JSON.stringify(diffCounts));
|
||||
console.log('样例:');
|
||||
samples.forEach((s) => console.log(' ' + s));
|
||||
} else {
|
||||
console.log('✓ 全部单元格与表格一致');
|
||||
}
|
||||
|
||||
const withGrade = d.items.filter((x) => x.hasGrade).length;
|
||||
console.log('\n有分级数据仓: %d/%d', withGrade, d.items.length);
|
||||
console.log('无分级的仓:', d.items.filter((x) => !x.hasGrade).map((x) => x.warehouse).join('、'));
|
||||
console.log('\n合计: 期初 %s,期末 %s', d.totals.openingQty, d.totals.closingQty);
|
||||
console.log('崔桥样例:', JSON.stringify(d.items[0], null, 1).replace(/\n\s*/g, ' '));
|
||||
process.exit(0);
|
||||
})().catch((e) => { console.log('ERR', e.message); process.exit(1); });
|
||||
Loading…
x
Reference in New Issue
Block a user