cangku/frontend/src/constants/dailyInventory.js
youruo 0e77a70c33 feat: 每日进销存支持导入聚水潭官方进销存校正数据
业务库只能还原 4/12 个流水列且口径与聚水潭不一致(采购按单据日期、销售按订单发货日期,
jst_salesOutboundInfo.qty 全为 0),调拨/盘点/加工/其它出入库无单据表,故以官方导出为准:

- 新增本地表 daily_inventory_official(biz_date + warehouse 存期初/12 流水列/期末)
- 新增解析与导入服务:xlsx 解析、仓库 ID 映射、「期初+流水=期末」恒等式校验
- GET /api/daily-inventory 支持 ?date= 指定业务日,官方值优先、缺失回退推算并返回来源标记
- 新增 POST /api/daily-inventory/official-import(xlsx 上传/JSON)与 GET /official 查询
- 导入后回写本地库存快照(官方期初→上一日期末、官方期末→当日期末),使推算也对齐
- 前端:业务日切换、官方/推算来源标记、导入弹窗、口径说明同步更新
- 仓库清单补入「简尚-横林三仓主仓」(聚水潭导出中存在)
- 命令行导入:npm run inventory:import-official -- <日期> <xlsx>
2026-09-27 14:16:06 +08:00

84 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 每日进销存 —— 列定义
*
* 表头取自桌面《库存监控.xlsx》,顺序与表格一致。
* source 标记该列数据来源,便于在页面上如实标注口径:
* - snapshot:来自项目本地快照表 daily_inventory_snapshot(每日定时落库,自动滚动)
* - runtime:运行时从业务库实时取数
* - unavailable:业务库缺少对应单据表,暂无法计算(渲染为「—」)
*/
export const COLUMN_SOURCE = {
snapshot: 'snapshot',
runtime: 'runtime',
unavailable: 'unavailable',
};
const NO_SOURCE_TIP = '业务库 JSReportReplica 缺少该单据表(调拨 / 盘点 / 加工 / 其它出入库),以聚水潭「进销存按仓导出」为准,导入后本列自动出数';
const FLOW_CALIBER_NOTE = '口径说明:业务库只能还原该列的近似值(采购按单据日期、销售按订单发货日期),与聚水潭进销存口径存在差异,已导入官方数据时以官方为准';
const OFFICIAL_TIP = '同一业务日导入过聚水潭进销存导出时,本列直接采用官方值(单元格为常规色);未导入时回退业务库推算(单元格标灰)';
/** 表格存在两个名为「期初」的列,第二个加后缀区分 */
export const DAILY_INVENTORY_COLUMNS = [
{ key: 'warehouse', label: '仓库', source: 'snapshot', tip: '取自主数据表 rpt.jst_warehouseInfo 的仓库名,表格显示为「XX主仓」' },
{ key: 'openingQty', label: '期初数量', source: 'snapshot', tip: `优先取聚水潭「进销存按仓导出」的官方期初;未导入时取本地快照表 daily_inventory_snapshot 中上一业务日的期末结存(每日 01:30 自动落库),快照缺失则自动用「实时库存扣流水」回推补写(回推值受业务库缺失的 8 类单据影响,与官方存在偏差)` },
{ key: 'processIn', label: '加工进仓', source: 'unavailable', tip: `加工进仓。${NO_SOURCE_TIP} ${OFFICIAL_TIP}` },
{ key: 'purchaseReturn', label: '采购退货', source: 'runtime', tip: `采购退货(流出,负数)。rpt.jst_purchaseout × jst_purchaseoutItem,按 io_date 统计。${FLOW_CALIBER_NOTE} ${OFFICIAL_TIP}` },
{ key: 'purchaseIn', label: '采购进仓', source: 'runtime', tip: `采购进仓(流入)。rpt.jst_purchase × jst_purchaseItem,按 po_date 统计,仅计 Confirmed/Finished 状态。${FLOW_CALIBER_NOTE} ${OFFICIAL_TIP}` },
{ key: 'otherIn', label: '其它进仓', source: 'unavailable', tip: `其它进仓。${NO_SOURCE_TIP} ${OFFICIAL_TIP}` },
{ key: 'otherReturn', label: '其它退货', source: 'unavailable', tip: `其它退货。${NO_SOURCE_TIP} ${OFFICIAL_TIP}` },
{ key: 'salesOut', label: '销售出仓', source: 'runtime', tip: `销售出仓(流出,负数)。rpt.jst_Orders × jst_OrderItem,按 send_date 统计,排除 Delete/Cancelled,与「库存周转天数」的发货口径一致。${FLOW_CALIBER_NOTE} ${OFFICIAL_TIP}` },
{ key: 'stocktaking', label: '盘点', source: 'unavailable', tip: `盘点。${NO_SOURCE_TIP} ${OFFICIAL_TIP}` },
{ key: 'processOut', label: '加工出仓', source: 'unavailable', tip: `加工出仓。${NO_SOURCE_TIP} ${OFFICIAL_TIP}` },
{ key: 'transferOut', label: '调拨出', source: 'unavailable', tip: `调拨出。${NO_SOURCE_TIP} ${OFFICIAL_TIP}` },
{ key: 'salesReturn', label: '销售退货', source: 'runtime', tip: `销售退货(流入)。rpt.jst_returnAndRefundInfo × jst_returnAndRefundItem,按 as_date 统计,类型限定普通退货/拒收退货/换货/维修,取明细实收数量 r_qty。${FLOW_CALIBER_NOTE} ${OFFICIAL_TIP}` },
{ key: 'transferIn', label: '调拨入', source: 'unavailable', tip: `调拨入。${NO_SOURCE_TIP} ${OFFICIAL_TIP}` },
{ key: 'openingQtyExtra', label: '期初(2)', source: 'unavailable', tip: '聚水潭导出表中的第二个「期初」列,业务库无对应来源' },
{ key: 'otherOut', label: '其它出库', source: 'unavailable', tip: `其它出库。${NO_SOURCE_TIP} ${OFFICIAL_TIP}` },
{ key: 'closingQty', label: '期末数量', source: 'runtime', tip: `优先取聚水潭「进销存按仓导出」的官方期末;未导入时取实时库存 rpt.jst_inventoryInfo,按仓库 wms_co_id 单仓统计(存货数量不为 0 的 SKU 汇总)` },
{ key: 'turnoverDays', label: '库存周转天数', source: 'runtime', tip: '月度发货总件数 / 月度日均库存件数 × 100%。月度发货总件数=近 30 天已发货订单件数(jst_OrderItem×jst_Orders,按 send_date,排除 Delete/Cancelled);月度日均库存件数=该仓实时库存(无历史结存表,以当日库存近似)' },
{ key: 'warnLevel', label: '滞销预警级库存量', source: 'runtime', tip: 'SKU 级:库龄 < 3 个月 且 周转率 30%~199% 的库存合计' },
{ key: 'slowLevel', label: '商品慢流级库存量', source: 'runtime', tip: 'SKU 级:库龄 < 3 个月且周转率 ≥ 200%,或库龄 > 3 个月且周转率 30%~99% 的库存合计' },
{ key: 'staleLevel', label: '商品呆滞级库存量', source: 'runtime', tip: 'SKU 级:库龄 3~12 个月且周转率 ≥ 100%,或库龄 > 12 个月且周转率 100%~199% 的库存合计' },
{ key: 'zombieLevel', label: '商品僵尸级库存量', source: 'runtime', tip: 'SKU 级:库龄 > 12 个月 且 周转率 ≥ 200% 的库存合计' },
];
/** 口径说明弹框文案 */
export const FORMULA_DESCRIPTION = [
'数据来源说明(全部来自数据库或聚水潭官方导出,无人工填数):',
'· 聚水潭官方进销存(优先):把聚水潭「进销存按仓导出」的 xlsx 在页面右上角导入后,',
' 该业务日的期初、12 个流水列、期末直接采用官方值,恒等式「期初 + 流水 = 期末」逐仓闭合。',
' 业务库 JSReportReplica 只能还原 4/12 个流水列,且口径与聚水潭不一致(采购按单据日期 vs 实际入库、',
' 销售按订单发货日期 vs 出库单、jst_salesOutboundInfo.qty 全为 0),调拨 / 盘点 / 加工 / 其它出入库更没有对应单据表,',
' 因此未导入官方数据时这些列显示「—」或为业务库近似值(单元格标灰)。',
'· 期初数量:官方期初优先;未导入时取本地快照表 daily_inventory_snapshot 中「上一业务日」的期末结存。',
' 业务库 JSReportReplica 没有按天的历史库存结存表,因此由本系统每天 01:30 把各仓实时库存落一份快照,',
' 今日期初 = 昨日快照,逐日自动滚动;导入官方数据时会同步回写快照,让后续推算也对齐聚水潭口径。',
'· 流水列(12 列):官方数据优先(导入后 12 列全部出数);未导入时业务库可还原 4 列 ——',
' 采购进仓(jst_purchase×Item,po_date,Confirmed/Finished)、采购退货(jst_purchaseout×Item,io_date)、',
' 销售出仓(jst_Orders×OrderItem,send_date,与周转率发货口径一致)、销售退货(jst_returnAndRefund×Item,as_date,实收 r_qty)。',
' 其余 8 列(加工进仓 / 其它进仓 / 其它退货 / 盘点 / 加工出仓 / 调拨出 / 调拨入 / 其它出库)业务库无单据表,显示「—」。',
'· 期末数量:运行时取聚水潭实时库存 rpt.jst_inventoryInfo(按 wms_co_id 单仓),随刷新滚动。',
'· 库存周转天数 / 四级库存量:运行时计算,库龄基准时刻为快照日次日 01:00。',
'',
'算式:',
'· 期末数量 = 期初数量 + 加工进仓 + 采购进仓 + 其它进仓 + 其它退货 + 销售退货 + 调拨入',
' − 采购退货 − 销售出仓 − 盘点 − 加工出仓 − 调拨出 − 其它出库',
'· 库存周转天数 = 月度发货总件数 / 月度日均库存件数 × 100%',
' 月度发货总件数 = 该仓近 30 天已发货订单件数',
' (jst_OrderItem 关联 jst_Orders,按订单发货仓 wms_co_id 归属,send_date 落在窗口内,排除 Delete / Cancelled)',
' 月度日均库存件数 = 该仓聚水潭实时库存 jst_inventoryInfo 汇总',
' (业务库无按天的历史库存结存表,无法算真正的日均库存,以当日库存近似月度日均)',
' 库龄(天) = 基准时刻 − SKU 建档时间 created;3 个月按 90 天、12 个月按 365 天折算',
'· 库存分级(SKU 级,库龄 + 周转率双维度,低于 30% 的不计入任何级别):',
' 库龄 < 3 个月 且 周转率 30%~199% → 滞销预警',
' 库龄 < 3 个月 且 周转率 ≥ 200% → 商品慢流',
' 库龄 > 3 个月 且 周转率 30%~99% → 商品慢流',
' 库龄 3~12 个月 且 周转率 ≥ 100% → 商品呆滞',
' 库龄 > 12 个月 且 周转率 100%~199% → 商品呆滞',
' 库龄 > 12 个月 且 周转率 ≥ 200% → 商品僵尸',
'',
'注意:仓库整体周转率按「该仓发货总量 ÷ 该仓库存总量」计算,与四级分级的 SKU 级取舍不是同一个口径,',
' 两者不必相等(例如整体周转率 6% 的仓里,仍可以有部分 SKU 周转率超 30% 而被判为预警级)。',
];