路由调用 fetchFlows(wmsCoIds, from) 少了第一个参数 cloudDb, 导致形参错位(cloudDb=数组、wmsCoIds=日期、fromText=undefined), 函数静默返回空 Map 且无任何报错。补传参数,并为 fetchFlows 增加 防呆校验:首参非数据库实例时立即抛 TypeError。补 1 项回归测试。
122 lines
4.5 KiB
JavaScript
122 lines
4.5 KiB
JavaScript
'use strict';
|
||
|
||
/**
|
||
* 每日进销存 —— 流水列取数(业务库原生口径)
|
||
*
|
||
* 业务库 JSReportReplica 能还原的 4 个流水列(其余 8 列缺单据表,保持「—」):
|
||
* 采购进仓(+): rpt.jst_purchase × jst_purchaseItem,按 po_date,状态 Confirmed/Finished,取明细 qty
|
||
* (明细 inQty 全为 0 未同步,故用 qty)
|
||
* 采购退货(−): rpt.jst_purchaseout × jst_purchaseoutItem,按 io_date
|
||
* 销售出仓(−): rpt.jst_Orders × jst_OrderItem,按 send_date,排除 Delete/Cancelled
|
||
* (与「库存周转天数」的发货口径一致;与聚水潭进销存导出的出库单口径有偏差,
|
||
* 因为销售出库单明细数量在业务库未同步,无法精确还原)
|
||
* 销售退货(+): rpt.jst_returnAndRefundInfo × jst_returnAndRefundItem,按 as_date,
|
||
* 类型限定 普通退货/拒收退货/换货/维修,取明细 r_qty(实收数量;
|
||
* qty 字段大多未同步,不能用)
|
||
*
|
||
* 符号约定与页面一致:流入为正、流出为负(前端负数标红)。
|
||
* 因为还有 8 类单据(调拨/盘点/加工/其它出入库)在业务库无表,
|
||
* 「期末 ≠ 期初 + 流水之和」,差值即缺失单据的影响。
|
||
*/
|
||
|
||
const FLOW_QUERIES = [
|
||
{
|
||
field: 'purchaseIn',
|
||
sign: 1,
|
||
sql: `
|
||
SELECT p.wms_co_id AS wmsCoId,
|
||
SUM(CAST(ISNULL(pi.qty, 0) AS DECIMAL(18, 2))) AS qty
|
||
FROM rpt.jst_purchase p
|
||
JOIN rpt.jst_purchaseItem pi ON pi.po_id = p.po_id
|
||
WHERE p.wms_co_id IN (%WAREHOUSES%)
|
||
AND p.po_date >= @from
|
||
AND ISNULL(p.status, '') IN ('Confirmed', 'Finished')
|
||
GROUP BY p.wms_co_id`,
|
||
},
|
||
{
|
||
field: 'purchaseReturn',
|
||
sign: -1,
|
||
sql: `
|
||
SELECT o.wms_co_id AS wmsCoId,
|
||
SUM(CAST(ISNULL(oi.qty, 0) AS DECIMAL(18, 2))) AS qty
|
||
FROM rpt.jst_purchaseout o
|
||
JOIN rpt.jst_purchaseoutItem oi ON oi.io_id = o.io_id
|
||
WHERE o.wms_co_id IN (%WAREHOUSES%)
|
||
AND o.io_date >= @from
|
||
GROUP BY o.wms_co_id`,
|
||
},
|
||
{
|
||
field: 'salesOut',
|
||
sign: -1,
|
||
sql: `
|
||
SELECT o.wms_co_id AS wmsCoId,
|
||
SUM(CAST(ISNULL(oi.qty, 0) AS DECIMAL(18, 2))) AS qty
|
||
FROM rpt.jst_Orders o
|
||
JOIN rpt.jst_OrderItem oi ON oi.o_id = o.o_id
|
||
WHERE o.wms_co_id IN (%WAREHOUSES%)
|
||
AND o.send_date >= @from
|
||
AND ISNULL(o.status, '') NOT IN ('Delete', 'Cancelled')
|
||
GROUP BY o.wms_co_id`,
|
||
},
|
||
{
|
||
field: 'salesReturn',
|
||
sign: 1,
|
||
sql: `
|
||
SELECT r.wms_co_id AS wmsCoId,
|
||
SUM(CAST(ISNULL(ri.r_qty, 0) AS DECIMAL(18, 2))) AS qty
|
||
FROM rpt.jst_returnAndRefundInfo r
|
||
JOIN rpt.jst_returnAndRefundItem ri ON ri.as_id = r.as_id
|
||
WHERE r.wms_co_id IN (%WAREHOUSES%)
|
||
AND r.as_date >= @from
|
||
AND ISNULL(r.type, '') IN (N'普通退货', N'拒收退货', N'换货', N'维修')
|
||
GROUP BY r.wms_co_id`,
|
||
},
|
||
];
|
||
|
||
/** mssql 不支持数组参数,按位展开成 @p0,@p1... */
|
||
function buildInClause(values, prefix) {
|
||
const params = {};
|
||
const clause = values
|
||
.map((v, i) => {
|
||
params[`${prefix}${i}`] = v;
|
||
return `@${prefix}${i}`;
|
||
})
|
||
.join(',');
|
||
return { clause, params };
|
||
}
|
||
|
||
/** 业务库可还原的流水字段(带符号:流入 +1 / 流出 −1) */
|
||
const AVAILABLE_FLOW_FIELDS = FLOW_QUERIES.map((q) => q.field);
|
||
|
||
/**
|
||
* 拉取自 fromText(含)以来各仓的流水合计。
|
||
* @returns {Promise<Map<string, Object>>} key = wmsCoId 字符串,value = { purchaseIn, purchaseReturn, salesOut, salesReturn }(带符号,无记录的字段不出现)
|
||
*/
|
||
async function fetchFlows(cloudDb, wmsCoIds, fromText) {
|
||
if (!cloudDb || typeof cloudDb.query !== 'function') {
|
||
throw new TypeError('fetchFlows 第一个参数必须是数据库实例(防呆:调用漏传 cloudDb 时立即报错而非静默返回空)');
|
||
}
|
||
const map = new Map();
|
||
if (!wmsCoIds.length || !fromText) return map;
|
||
for (const q of FLOW_QUERIES) {
|
||
const { clause, params } = buildInClause(wmsCoIds, 'w');
|
||
const sqlText = q.sql.replace('%WAREHOUSES%', clause);
|
||
const rows = await cloudDb.query(sqlText, { ...params, from: fromText }, { requestTimeout: 120000 });
|
||
for (const r of rows) {
|
||
const key = String(r.wmsCoId);
|
||
const entry = map.get(key) || {};
|
||
const qty = Number(r.qty) || 0;
|
||
entry[q.field] = q.sign * qty;
|
||
map.set(key, entry);
|
||
}
|
||
}
|
||
return map;
|
||
}
|
||
|
||
module.exports = {
|
||
AVAILABLE_FLOW_FIELDS,
|
||
FLOW_QUERIES,
|
||
fetchFlows,
|
||
buildInClause,
|
||
};
|