Merge pull request 'fix: 排除拣选位报表中的箱记录' (#63) from codex/picking-bin-pack-filter-1012 into main
This commit is contained in:
commit
c6c7feaeea
@ -11,7 +11,8 @@
|
|||||||
*
|
*
|
||||||
* 口径:
|
* 口径:
|
||||||
* 库存数量:rpt.jst_packInventoryInfo 按 wms_co_id + 仓位 + sku_id 汇总 qty
|
* 库存数量: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
|
* 销量: 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;
|
const PICKING_BIN_DEFAULT_DAYS = 30;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 仓位类型:本功能只统计拣选位(业务库 bin_group 为空即拣选位)。
|
* 仓位类型:本功能只统计真实拣选仓位(pack_type=Bin 且 bin_group 为空)。
|
||||||
* 存货位(bin_group=存货)不纳入动销等级统计,取数在仓位库存表上直接过滤,
|
* 箱记录(pack_type=Pack)和存货位(bin_group=存货)不纳入动销等级统计,
|
||||||
|
* 取数在仓位库存表上直接过滤,
|
||||||
* 页面也不再提供类型切换。
|
* 页面也不再提供类型切换。
|
||||||
*/
|
*/
|
||||||
const BIN_TYPE_PICKING = '拣选';
|
const BIN_TYPE_PICKING = '拣选';
|
||||||
|
|||||||
@ -4,7 +4,8 @@
|
|||||||
* 拣选库位动销分析 —— 业务库取数
|
* 拣选库位动销分析 —— 业务库取数
|
||||||
*
|
*
|
||||||
* 库存:rpt.jst_packInventoryInfo 按 wms_co_id + 仓位 + sku_id 汇总 qty(仓位为空的行不参与)
|
* 库存: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
|
* 销量:rpt.jst_Orders × rpt.jst_OrderItem,按 send_date,排除 Delete/Cancelled
|
||||||
* 粒度:仓位 × 商品编码(一个仓位有 N 个商品就输出 N 行),列表与导出共用
|
* 粒度:仓位 × 商品编码(一个仓位有 N 个商品就输出 N 行),列表与导出共用
|
||||||
*
|
*
|
||||||
@ -84,8 +85,8 @@ async function fetchPickingBinSkuRows(cloudDb, wmsCoIds, options = {}) {
|
|||||||
const binIn = buildInClause(wmsCoIds, 'w');
|
const binIn = buildInClause(wmsCoIds, 'w');
|
||||||
const shipIn = buildInClause(wmsCoIds, 'v');
|
const shipIn = buildInClause(wmsCoIds, 'v');
|
||||||
|
|
||||||
// 统计范围固定为拣选位:直接在仓位库存表上过滤 bin_group 为空,
|
// 统计范围固定为真实拣选仓位:pack_type=Bin 且 bin_group 为空。
|
||||||
// 存货位(bin_group=存货)不参与动销等级统计。
|
// 仅过滤 bin_group 会把同样为空的 Pack 箱记录误标为拣选位。
|
||||||
const sqlText = `
|
const sqlText = `
|
||||||
WITH bin AS (
|
WITH bin AS (
|
||||||
SELECT p.wms_co_id AS wmsCoId,
|
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})
|
WHERE p.wms_co_id IN (${binIn.clause})
|
||||||
AND ISNULL(p.bin, '') <> ''
|
AND ISNULL(p.bin, '') <> ''
|
||||||
AND ISNULL(p.qty, 0) <> 0
|
AND ISNULL(p.qty, 0) <> 0
|
||||||
|
AND p.pack_type = N'Bin'
|
||||||
AND ISNULL(p.bin_group, '') = ''
|
AND ISNULL(p.bin_group, '') = ''
|
||||||
GROUP BY p.wms_co_id,
|
GROUP BY p.wms_co_id,
|
||||||
LTRIM(RTRIM(p.bin)),
|
LTRIM(RTRIM(p.bin)),
|
||||||
|
|||||||
@ -116,19 +116,21 @@ test('fetchPickingBinSkuRows 按仓位×商品输出,等级与日销来自商
|
|||||||
// 商品销量按占用仓位数分摊(供求和),但等级依据的是未分摊的商品销量
|
// 商品销量按占用仓位数分摊(供求和),但等级依据的是未分摊的商品销量
|
||||||
assert.ok(captured.sqlText.includes('/ NULLIF(sp.binCount, 0)'));
|
assert.ok(captured.sqlText.includes('/ NULLIF(sp.binCount, 0)'));
|
||||||
assert.ok(captured.sqlText.includes('ISNULL(s.salesQty, 0) / @days AS DECIMAL(18, 4)'));
|
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.bin_group, '') = ''"));
|
||||||
assert.ok(captured.sqlText.includes('ISNULL(p.qty, 0) <> 0'));
|
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'));
|
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;
|
let captured = null;
|
||||||
const db = {
|
const db = {
|
||||||
query: async (sqlText, params) => { captured = { sqlText, params }; return []; },
|
query: async (sqlText, params) => { captured = { sqlText, params }; return []; },
|
||||||
};
|
};
|
||||||
await fetchPickingBinSkuRows(db, [101], { shipFrom: 'a', shipTo: 'b', days: 15 });
|
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("ISNULL(p.bin_group, '') = ''"));
|
||||||
assert.ok(!captured.sqlText.includes('b.binType IN'));
|
assert.ok(!captured.sqlText.includes('b.binType IN'));
|
||||||
assert.equal(captured.params.t0, undefined);
|
assert.equal(captured.params.t0, undefined);
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export const PICKING_BIN_COLUMNS = [
|
|||||||
{
|
{
|
||||||
key: 'binType',
|
key: 'binType',
|
||||||
label: '类型',
|
label: '类型',
|
||||||
tip: '统计范围固定为拣选位(bin_group 为空的仓位);存货位不纳入动销分析,报表中不会出现',
|
tip: '统计范围固定为真实拣选仓位(pack_type=Bin 且 bin_group 为空);箱记录和存货位不纳入动销分析',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'skuId',
|
key: 'skuId',
|
||||||
@ -63,7 +63,7 @@ export const PICKING_BIN_GRADE_COLORS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const PICKING_BIN_DESCRIPTION = [
|
export const PICKING_BIN_DESCRIPTION = [
|
||||||
'【统计范围】只统计拣选位(bin_group 为空的仓位);存货位不纳入动销分析。',
|
'【统计范围】只统计真实拣选仓位(pack_type=Bin 且 bin_group 为空);箱记录(pack_type=Pack)和存货位不纳入动销分析。',
|
||||||
'',
|
'',
|
||||||
'【粒度】一行 = 一个「仓位 × 商品编码」组合。一个仓位放了 N 个商品就显示 N 行,列表与导出一致。',
|
'【粒度】一行 = 一个「仓位 × 商品编码」组合。一个仓位放了 N 个商品就显示 N 行,列表与导出一致。',
|
||||||
' 库存数量 = 该商品在这个仓位上的实际库存(同一仓位多行相加 = 仓位总库存)。',
|
' 库存数量 = 该商品在这个仓位上的实际库存(同一仓位多行相加 = 仓位总库存)。',
|
||||||
@ -86,5 +86,5 @@ export const PICKING_BIN_DESCRIPTION = [
|
|||||||
'',
|
'',
|
||||||
'数据来源:库存取 rpt.jst_packInventoryInfo(按仓库 + 仓位 + 商品汇总);',
|
'数据来源:库存取 rpt.jst_packInventoryInfo(按仓库 + 仓位 + 商品汇总);',
|
||||||
'销量取 rpt.jst_Orders × rpt.jst_OrderItem(按 send_date,排除 Delete/Cancelled),与「每日进销存」发货口径一致。',
|
'销量取 rpt.jst_Orders × rpt.jst_OrderItem(按 send_date,排除 Delete/Cancelled),与「每日进销存」发货口径一致。',
|
||||||
'统计范围:只取 bin_group 为空的拣选位,存货位(bin_group=存货)不参与统计。',
|
'统计范围:只取 pack_type=Bin 且 bin_group 为空的真实拣选仓位,箱记录(pack_type=Pack)和存货位(bin_group=存货)不参与统计。',
|
||||||
];
|
];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user