Merge pull request 'fix: 排除拣选位报表中的箱记录' (#63) from codex/picking-bin-pack-filter-1012 into main

This commit is contained in:
lunanting 2026-10-12 14:39:06 +08:00
commit c6c7feaeea
4 changed files with 18 additions and 12 deletions

View File

@ -11,7 +11,8 @@
*
* 口径:
* 库存数量:rpt.jst_packInventoryInfo 按 wms_co_id + 仓位 + sku_id 汇总 qty
* 统计范围:只统计拣选位(bin_group 为空);存货位(bin_group=存货)不纳入
* 统计范围:只统计真实拣选仓位(pack_type=Bin 且 bin_group 为空);
* 箱记录(pack_type=Pack)与存货位(bin_group=存货)不纳入
* 销量: rpt.jst_Orders × rpt.jst_OrderItem,按 send_date,排除 Delete/Cancelled
* 日销: 商品窗口销量 / 窗口天数(整档,不按仓位分摊)
* 等级: 严格按商品日销判定,同一商品占多少个仓位都是同一等级
@ -36,8 +37,9 @@ const PICKING_BIN_WINDOW_OPTIONS = [7, 15, 30, 60];
const PICKING_BIN_DEFAULT_DAYS = 30;
/**
* 仓位类型:本功能只统计拣选位(业务库 bin_group 为空即拣选位)。
* 存货位(bin_group=存货)不纳入动销等级统计,取数在仓位库存表上直接过滤,
* 仓位类型:本功能只统计真实拣选仓位(pack_type=Bin 且 bin_group 为空)。
* 箱记录(pack_type=Pack)和存货位(bin_group=存货)不纳入动销等级统计,
* 取数在仓位库存表上直接过滤,
* 页面也不再提供类型切换。
*/
const BIN_TYPE_PICKING = '拣选';

View File

@ -4,7 +4,8 @@
* 拣选库位动销分析 —— 业务库取数
*
* 库存:rpt.jst_packInventoryInfo 按 wms_co_id + 仓位 + sku_id 汇总 qty(仓位为空的行不参与)
* 范围:只统计拣选位(bin_group 为空);存货位(bin_group=存货)不纳入
* 范围:只统计真实拣选仓位(pack_type=Bin 且 bin_group 为空);
* 箱记录(pack_type=Pack)与存货位(bin_group=存货)不纳入
* 销量:rpt.jst_Orders × rpt.jst_OrderItem,按 send_date,排除 Delete/Cancelled
* 粒度:仓位 × 商品编码(一个仓位有 N 个商品就输出 N 行),列表与导出共用
*
@ -84,8 +85,8 @@ async function fetchPickingBinSkuRows(cloudDb, wmsCoIds, options = {}) {
const binIn = buildInClause(wmsCoIds, 'w');
const shipIn = buildInClause(wmsCoIds, 'v');
// 统计范围固定为拣选位:直接在仓位库存表上过滤 bin_group 为空,
// 存货位(bin_group=存货)不参与动销等级统计。
// 统计范围固定为真实拣选仓位:pack_type=Bin 且 bin_group 为空。
// 仅过滤 bin_group 会把同样为空的 Pack 箱记录误标为拣选位。
const sqlText = `
WITH bin AS (
SELECT p.wms_co_id AS wmsCoId,
@ -97,6 +98,7 @@ async function fetchPickingBinSkuRows(cloudDb, wmsCoIds, options = {}) {
WHERE p.wms_co_id IN (${binIn.clause})
AND ISNULL(p.bin, '') <> ''
AND ISNULL(p.qty, 0) <> 0
AND p.pack_type = N'Bin'
AND ISNULL(p.bin_group, '') = ''
GROUP BY p.wms_co_id,
LTRIM(RTRIM(p.bin)),

View File

@ -116,19 +116,21 @@ test('fetchPickingBinSkuRows 按仓位×商品输出,等级与日销来自商
// 商品销量按占用仓位数分摊(供求和),但等级依据的是未分摊的商品销量
assert.ok(captured.sqlText.includes('/ NULLIF(sp.binCount, 0)'));
assert.ok(captured.sqlText.includes('ISNULL(s.salesQty, 0) / @days AS DECIMAL(18, 4)'));
// 统计范围固定为拣选位:bin_group 为空;只统计有库存的行
// 统计范围固定为真实拣选仓位:pack_type=Bin 且 bin_group 为空;只统计有库存的行
assert.ok(captured.sqlText.includes("p.pack_type = N'Bin'"));
assert.ok(captured.sqlText.includes("ISNULL(p.bin_group, '') = ''"));
assert.ok(captured.sqlText.includes('ISNULL(p.qty, 0) <> 0'));
assert.ok(captured.sqlText.includes('HAVING ABS(SUM(CAST(b.binSkuQty AS DECIMAL(18, 2)))) > 0.0001'));
});
test('fetchPickingBinSkuRows 只统计拣选位,不带类型参数', async () => {
test('fetchPickingBinSkuRows 只统计真实拣选仓位,排除 Pack 箱记录且不带类型参数', async () => {
let captured = null;
const db = {
query: async (sqlText, params) => { captured = { sqlText, params }; return []; },
};
await fetchPickingBinSkuRows(db, [101], { shipFrom: 'a', shipTo: 'b', days: 15 });
// 存货位(bin_group=存货)被排除,且不再有 binType IN (...) 的可变过滤
// Pack 箱记录和存货位被排除,且不再有 binType IN (...) 的可变过滤
assert.ok(captured.sqlText.includes("p.pack_type = N'Bin'"));
assert.ok(captured.sqlText.includes("ISNULL(p.bin_group, '') = ''"));
assert.ok(!captured.sqlText.includes('b.binType IN'));
assert.equal(captured.params.t0, undefined);

View File

@ -14,7 +14,7 @@ export const PICKING_BIN_COLUMNS = [
{
key: 'binType',
label: '类型',
tip: '统计范围固定为拣选位(bin_group 为空的仓位);存货位不纳入动销分析,报表中不会出现',
tip: '统计范围固定为真实拣选仓位(pack_type=Bin 且 bin_group 为空);箱记录和存货位不纳入动销分析',
},
{
key: 'skuId',
@ -63,7 +63,7 @@ export const PICKING_BIN_GRADE_COLORS = {
};
export const PICKING_BIN_DESCRIPTION = [
'【统计范围】只统计拣选位(bin_group 为空的仓位);存货位不纳入动销分析。',
'【统计范围】只统计真实拣选仓位(pack_type=Bin 且 bin_group 为空);箱记录(pack_type=Pack)和存货位不纳入动销分析。',
'',
'【粒度】一行 = 一个「仓位 × 商品编码」组合。一个仓位放了 N 个商品就显示 N 行,列表与导出一致。',
' 库存数量 = 该商品在这个仓位上的实际库存(同一仓位多行相加 = 仓位总库存)。',
@ -86,5 +86,5 @@ export const PICKING_BIN_DESCRIPTION = [
'',
'数据来源:库存取 rpt.jst_packInventoryInfo(按仓库 + 仓位 + 商品汇总);',
'销量取 rpt.jst_Orders × rpt.jst_OrderItem(按 send_date,排除 Delete/Cancelled),与「每日进销存」发货口径一致。',
'统计范围:只取 bin_group 为空的拣选位,存货位(bin_group=存货)不参与统计。',
'统计范围:只取 pack_type=Bin 且 bin_group 为空的真实拣选仓位,箱记录(pack_type=Pack)和存货位(bin_group=存货)不参与统计。',
];