配件库存监控:未配置MKH 不进任何缺货/预警
业务确认(2026-09-17):未配置MKH 的配件不属于模块化体系,预警列一律显示「正常」, 既不报缺货(实时库存<=0)也不报预警(可用天数<=7)。 实现: - 新增 buildWarningOrderSql() 统一表达式(0缺货/1预警/2正常),未配置MKH(cfg.configured=0) 直接判 2。 - 列表映射 mapRow 改用 SQL 算好的 warningOrder 推导 warningLevel(删除重复 normalizeWarningLevel, 避免前后端各算一份导致排序与显示不一致)。 - 汇总计数 buildSummary.outOfStockCount / lowStockDaysCount 改用统一表达式,不再计入未配置MKH。 - 筛选 buildFilters:按预警等级筛选、onlyWarning=1(仅看缺货/预警)均排除未配置MKH。 实测(接口直跑,目标仓 794 SKU): - 未配置MKH 95 个全部判「正常」(其中 55 个库存=0、58 个可用天数<=7,原会预警)。 - summary.outOfStockCount=13 / lowStockDaysCount=3,与已配置MKH 页面分布一致。 - onlyWarning=1 返回 16 条,0 条未配置MKH。
This commit is contained in:
parent
0bb7c5905d
commit
bc8c46d5be
@ -41,7 +41,8 @@ const WAREHOUSE_WMS_CO_ID = 15718196;
|
||||
const DEFAULT_PAGE_SIZE = 50;
|
||||
const MAX_PAGE_SIZE = 200;
|
||||
const DEFAULT_SAFETY_DAYS = 15;
|
||||
// 预警阈值:库存可用天数 <= 7 天即预警
|
||||
// 预警阈值:库存可用天数 <= 7 天即预警(缺货 = 实时库存 <= 0)
|
||||
// ⚠️ 2026-09-17 业务确认:未配置MKH 的配件不进任何预警(见 buildWarningOrderSql)
|
||||
const LOW_STOCK_DAYS_THRESHOLD = 7;
|
||||
|
||||
const WARNING_LEVEL = Object.freeze({
|
||||
@ -93,6 +94,22 @@ const buildConfiguredExistsSql = () => (
|
||||
)`
|
||||
);
|
||||
|
||||
/**
|
||||
* 统一的「预警等级(数值)」表达式(2026-09-17 业务确认:未配置MKH 不进任何预警)。
|
||||
* 0 = 缺货 / 1 = 预警 / 2 = 正常
|
||||
* 未配置MKH(cfg.configured = 0)一律判为「正常」,不报缺货也不报预警。
|
||||
* 注意 cfg / inv / m 三个别名都来自 buildBaseSql 的 OUTER APPLY,WHERE / SELECT 中均可引用。
|
||||
* 列表映射、汇总计数、筛选、排序四处共用此表达式,避免口径不一致。
|
||||
*/
|
||||
const buildWarningOrderSql = () => (
|
||||
`CASE
|
||||
WHEN cfg.configured = 0 THEN 2
|
||||
WHEN COALESCE(inv.qty, m.jsStock, 0) <= 0 THEN 0
|
||||
WHEN m.jsUseDays IS NOT NULL AND m.jsUseDays <= ${LOW_STOCK_DAYS_THRESHOLD} THEN 1
|
||||
ELSE 2
|
||||
END`
|
||||
);
|
||||
|
||||
const buildBaseSql = () => `
|
||||
FROM dbo.jst_sku s
|
||||
OUTER APPLY (
|
||||
@ -139,16 +156,6 @@ const toText = (value) => {
|
||||
return text === '' ? null : text;
|
||||
};
|
||||
|
||||
const normalizeWarningLevel = (realtimeStock, stockDays) => {
|
||||
const stock = Number(realtimeStock || 0);
|
||||
if (stock <= 0) return WARNING_LEVEL.OUT_OF_STOCK;
|
||||
|
||||
const days = toNumber(stockDays);
|
||||
if (days !== null && days <= LOW_STOCK_DAYS_THRESHOLD) return WARNING_LEVEL.WARNING;
|
||||
|
||||
return WARNING_LEVEL.NORMAL;
|
||||
};
|
||||
|
||||
const WARNING_ORDER = {
|
||||
[WARNING_LEVEL.OUT_OF_STOCK]: 0,
|
||||
[WARNING_LEVEL.WARNING]: 1,
|
||||
@ -209,20 +216,14 @@ const buildFilters = (query = {}, monitorDate = null) => {
|
||||
const warningLevel = toText(query.warningLevel);
|
||||
if (warningLevel && Object.prototype.hasOwnProperty.call(WARNING_ORDER, warningLevel)) {
|
||||
params.warningOrder = WARNING_ORDER[warningLevel];
|
||||
conditions.push(`
|
||||
CASE
|
||||
WHEN COALESCE(inv.qty, m.jsStock, 0) <= 0 THEN 0
|
||||
WHEN m.jsUseDays IS NOT NULL AND m.jsUseDays <= ${LOW_STOCK_DAYS_THRESHOLD} THEN 1
|
||||
ELSE 2
|
||||
END = @warningOrder`);
|
||||
// 用统一表达式,未配置MKH 不参与预警判定(筛「缺货 / 预警」时不会漏出未配置MKH)
|
||||
conditions.push(`${buildWarningOrderSql()} = @warningOrder`);
|
||||
}
|
||||
|
||||
const onlyWarning = String(query.onlyWarning || '').toLowerCase();
|
||||
if (['1', 'true', 'yes'].includes(onlyWarning)) {
|
||||
conditions.push(`(
|
||||
COALESCE(inv.qty, m.jsStock, 0) <= 0
|
||||
OR (m.jsUseDays IS NOT NULL AND m.jsUseDays <= ${LOW_STOCK_DAYS_THRESHOLD})
|
||||
)`);
|
||||
// 仅看缺货 / 预警:统一表达式 <= 1(未配置MKH 一律为 2,自动排除)
|
||||
conditions.push(`${buildWarningOrderSql()} <= 1`);
|
||||
}
|
||||
|
||||
return { conditions, params };
|
||||
@ -283,7 +284,14 @@ const mapRow = (row = {}) => {
|
||||
const realtimeStock = Number(row.realtimeStock || 0);
|
||||
const stockDays = toNumber(row.stockDays);
|
||||
const safetyDays = toNumber(row.safetyDays) ?? DEFAULT_SAFETY_DAYS;
|
||||
const warningLevel = normalizeWarningLevel(realtimeStock, stockDays);
|
||||
// 预警等级以 SQL 端 buildWarningOrderSql() 的判定为准(已含「未配置MKH 不进预警」规则),
|
||||
// 前端显示与排序口径保持一致,避免前后端各算一份。
|
||||
const warningOrder = Number(row.warningOrder ?? WARNING_ORDER[WARNING_LEVEL.NORMAL]);
|
||||
const warningLevel = warningOrder === WARNING_ORDER[WARNING_LEVEL.OUT_OF_STOCK]
|
||||
? WARNING_LEVEL.OUT_OF_STOCK
|
||||
: warningOrder === WARNING_ORDER[WARNING_LEVEL.WARNING]
|
||||
? WARNING_LEVEL.WARNING
|
||||
: WARNING_LEVEL.NORMAL;
|
||||
|
||||
return {
|
||||
skuId: toText(row.skuId),
|
||||
@ -292,7 +300,7 @@ const mapRow = (row = {}) => {
|
||||
// 图片优先取产品资料系统数据库(业务库 pic/pic_big 目标仓全为空)
|
||||
imageUrl: toText(row.productImageUrl) || toText(row.imageUrl),
|
||||
warningLevel,
|
||||
warningOrder: WARNING_ORDER[warningLevel],
|
||||
warningOrder,
|
||||
mkhStatus: toText(row.mkhStatus) || MKH_STATUS.UNCONFIGURED,
|
||||
// 业务库无出入库流水表:入库取采购到货(监控日),出库取 pm_stockMonitor 近一日发货量
|
||||
inQtyToday: toNumber(row.inQtyToday) ?? 0,
|
||||
@ -326,11 +334,7 @@ const buildProjection = () => `
|
||||
cost.pictureSkucode
|
||||
) AS imageUrl,
|
||||
CASE WHEN cfg.configured = 1 THEN N'已配置MKH' ELSE N'未配置MKH' END AS mkhStatus,
|
||||
CASE
|
||||
WHEN COALESCE(inv.qty, m.jsStock, 0) <= 0 THEN 0
|
||||
WHEN m.jsUseDays IS NOT NULL AND m.jsUseDays <= ${LOW_STOCK_DAYS_THRESHOLD} THEN 1
|
||||
ELSE 2
|
||||
END AS warningOrder,
|
||||
${buildWarningOrderSql()} AS warningOrder,
|
||||
m.date AS monitorDate`;
|
||||
|
||||
async function getModularStockList(query = {}) {
|
||||
@ -395,9 +399,9 @@ async function buildSummary(whereSql, params) {
|
||||
const rows = await cloudDatabase.query(
|
||||
`SELECT
|
||||
COUNT_BIG(*) AS skuCount,
|
||||
SUM(CASE WHEN COALESCE(inv.qty, m.jsStock, 0) <= 0 THEN 1 ELSE 0 END) AS outOfStockCount,
|
||||
SUM(CASE WHEN ${buildWarningOrderSql()} = 0 THEN 1 ELSE 0 END) AS outOfStockCount,
|
||||
CAST(ISNULL(SUM(COALESCE(inv.qty, m.jsStock, 0)), 0) AS BIGINT) AS totalStock,
|
||||
SUM(CASE WHEN m.jsUseDays IS NOT NULL AND m.jsUseDays <= ${LOW_STOCK_DAYS_THRESHOLD} THEN 1 ELSE 0 END) AS lowStockDaysCount,
|
||||
SUM(CASE WHEN ${buildWarningOrderSql()} = 1 THEN 1 ELSE 0 END) AS lowStockDaysCount,
|
||||
SUM(CASE WHEN cfg.configured = 1 THEN 1 ELSE 0 END) AS configuredCount,
|
||||
MAX(m.date) AS monitorDate
|
||||
${whereSql}`,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user