|
|
e15898693f
|
fix: 动销分析报表恢复「类型」列(恒为拣选),存货位仍不纳入
上一版为去掉冗余把「类型」整列删了,用户要求的报表列结构中该列仍在,
现恢复:导出与列表均保留「类型」列,值恒为「拣选」(存货位不参与统计,报表中不会出现)
验证(基准日 2026-10-08、30 天):
- 导出表头为 仓库 / 仓位 / 类型 / 商品编码 / 库存数量 / 仓位SKU数 / 商品销量 /
分摊销量 / 商品日销 / 动销等级 / 统计天数 / 统计基准日
- 11897 行,类型列取值集合仅 ['拣选'],空值 0 行;分摊销量合计 98087 = 去重商品销量合计 98087
- 列表接口 binTypes=['拣选'],明细类型集合仅 ['拣选']
- 单测 9/9 通过;语法检查 182 文件通过;eslint 无报错、vite build 成功
|
2026-10-08 16:31:20 +08:00 |
|
|
|
99fa402092
|
feat: 拣选库位动销分析固定只统计拣选位,移除仓位类型切换
- 取数固定只取拣选位:bin CTE 直接过滤 bin_group 为空(更早过滤,存货位不再进入后续 CTE)
移除可变的 binType IN 过滤与 resolveBinTypes,binType 字段恒为拣选
- 接口 payload 的 binTypes / binTypeOptions 固定为 ['拣选'];缓存键不再含类型
- 列表与导出移除「类型」列(全为拣选,冗余);页面移除类型多选器、底部文案改为「统计范围:仅拣选位」
- 口径说明补充统计范围;Tooltip 同步
验证(基准日 2026-10-08、30 天):
- 列表 11871 行 / 6821 个去重商品 / 库存 499141 / 去重商品销量 96847,明细类型集合仅为 ['拣选']
- 导出 11871 行,表头无「类型」列;分摊销量合计 96847 = 去重商品销量合计 96847(差异 -0.0017 浮点舍入)
- 旧参数 binType=存货 被忽略(仍返回拣选且命中同一缓存);7 / 60 天窗口与单仓过滤均正常
- 单测 9/9 通过;后端语法检查 182 文件通过;前端 eslint 无报错、vite build 成功
|
2026-10-08 13:09:49 +08:00 |
|
|
|
88a39975d3
|
feat: 动销等级改为按商品日销统计,列表与导出统一到仓位×商品粒度
- 取数统一为 fetchPickingBinSkuRows:一行 = 一个「仓位 × 商品编码」,列表与导出共用
商品日销 = 商品窗口整档销量 ÷ 天数(不做仓位分摊);同一商品占几个仓位都是同一等级
另输出分摊销量 = 商品销量 ÷ 占用同类型仓位数,供按行求和
- 列表页同步拆到商品粒度:新增商品编码列,去掉 SKU数列,搜索支持商品编码
- 汇总卡片主数值改为去重商品数,另显示明细行数;销量按去重商品口径统计
- 导出新增「分摊销量」「商品日销」列,表头口径标注更明确
- 性能:仓位类型选满时不拼 IN 过滤(避免参数嗅探走坏计划),全类型查询由超时降到约 30 秒
验证(基准日 2026-10-08、30 天、拣选位):
- 明细 11871 行 / 去重商品 6821 个 / 库存合计 499141(与旧口径一致)
- 跨多仓位的 2028 个商品,销量与等级不一致 0 个
- 导出行求和:分摊销量合计 96847 = 去重商品销量合计 96847(差异 -0.0017,浮点舍入)
- 单测 9/9 通过;语法检查 182 文件通过;前端 eslint 无报错、vite build 成功
|
2026-10-08 10:58:17 +08:00 |
|
|
|
31f184edd0
|
feat: 拣选库位动销分析导出增加商品编码,按仓位×商品编码拆行
- 新增 fetchPickingBinSkuRows:仓位 × 商品编码 粒度明细
库存数量 = 该商品在此仓位的实际库存;销量 = 商品销量 ÷ 其占用同类仓位数(贡献)
- 导出列:仓库 / 仓位 / 类型 / 商品编码 / 库存数量 / SKU数 / 销量 / 日销 / 动销等级 / 统计天数 / 统计基准日
- SKU数、动销等级仍为仓位粒度(同一仓位多行重复),列表页口径不变(仍用 bin 级聚合)
- 同一次取数比对:7055 个仓位,列表与导出库存/销量 0 处差异,库存合计一致 497721
- 单测 11 条通过
|
2026-10-08 09:35:26 +08:00 |
|
|
|
817cc74a40
|
feat: 拣选库位动销分析默认按近 30 天销量划分等级
- 默认统计窗口 15 天 -> 30 天(后端 PICKING_BIN_DEFAULT_DAYS 与前端常量同步)
- 可切换窗口补充近 60 天(7 / 15 / 30 / 60)
- 等级阈值不变:爆款≥20 / 热卖 10-20 / 平销 3-10 / 滞销-1 1-3 / 滞销-2 (0,1) / 销售=0
- 单测断言同步更新;实测 30 天窗口:7091 个拣选库位,日销=销量÷30
|
2026-10-07 17:41:17 +08:00 |
|
|
|
e71607386d
|
Merge pull request 'feat: 新增每日进销存业务库校验脚本' (#57) from codex/validate-daily-inventory-biz-1007 into main
|
2026-10-07 17:04:36 +08:00 |
|
|
|
0afcb26119
|
feat: 新增每日进销存业务库校验脚本
- backend/scripts/validateDailyInventoryFromBiz.js <业务日>...
- 直连业务库(凭据经隧道从系统库 database_configs 现取,不落盘):
反算 4 个可还原的流水列(销售出仓/销售退货/采购进仓/采购退货),
与 daily_inventory_official 逐仓比对;期末库存与 jst_inventoryInfo 全仓比对
- 约定:校验类需求默认走业务库,不启浏览器取聚水潭
|
2026-10-07 16:59:56 +08:00 |
|
|
|
70550b5499
|
feat: 新增二级页面「拣选库位动销分析」(大货库存监控)
- 后端:pickingBinSalesAnalysis 配置/服务/路由,仓位库存取 rpt.jst_packInventoryInfo
(bin_group 空值=拣选位、存货=存货位),销量按「SKU 占用同类仓位数平均分摊」,
恒等式「全部库位销量之和 = 有库位 SKU 销量之和」差异为 0
- 动销等级(近 N 天日销,默认 15):爆款>=20、热卖款 10-20、平销款 3-10、
滞销款-1 1-3、滞销款-2 (0,1)、销售=0
- 前端:大货库存监控下新增二级菜单 + 页面(等级卡片、仓库/类型/天数/仓位筛选、
分页表格、xlsx 导出),路由/菜单/页面权限四处注册
- 测试:后端 8 项单测通过;前端 lint/test/build 通过
|
2026-10-07 16:59:39 +08:00 |
|
|
|
a93691f5d8
|
fix: MKH-BOM 配件库存增加箱表兜底,修正「配件有货却判配件不足」
根因
- 配件监控页取实时库存是三级兜底(inventoryInfo → 同仓箱表 packInventoryInfo
→ 监控快照 jsStock),而 MKH-BOM 的 loadComponentStock **只查 jst_inventoryInfo**,
一级来源到底就结束。
- 上游 jst_inventoryInfo 存在滞后:2026-09-30 该行停在 09-28 14:51 的值 0,
而 jst_packInventoryInfo 当日 10:30 已记 bin=ZT-30 qty=200。
- 结果:同一个仓(15718196)、同一个配件,配件监控页显示 200(判「正常」),
MKH-BOM 判「配件不足」、可组装数 0。
案例 MKHDNZ0409260600849 的配件 DNZ040947N1440V01(瓶颈唯一)。
改动
- backend/src/services/mkhBomService.js
· loadComponentStock():一条语句同时取两张表(UNION ALL + src 标记),
库存表有正库存以它为准;为 0 / 缺行时用同仓 jst_packInventoryInfo 的
bin 非空行合计兜底。**只补 0、不覆盖正库存**,与配件监控页
buildRealtimeStockSql 同口径;查询失败仍整体 degraded(不做判定)。
· 文件头 ⑪:修正「不能用 jst_packInventoryInfo 当配件库存 —— 与 MKH 配件
零交集」这条结论 —— 它是 09-17 的表状态(当时该表 bin 全空),
09-18 上游整表重建后已失效。
· 文件头 ⑤:同理修正该表的关联列与数据现状结论。PR #22 的提交信息声称
已更新 ⑤,但实际 diff 未改,此处补齐(该表 wms_co_id 关联、目标仓
727/794 命中、配件仓 743 个 SKU 有箱记录)。
- backend/test/mkhBomService.test.js
· 新增 3 个用例:箱表兜底生效且不覆盖正库存 / SQL 形状防腐化(两张表 +
bin 非空 + 限定仓)/ 查询失败仍降级不做判定。
对照组已验证:在修复前的实现上前两个用例失败(expected 200、actual 0)。
影响与验证
- 仅影响 MKH-BOM 的「配件不足」标记与可组装数;不改预警级别、排序与预警总数。
- 同一数据快照下的新旧口径对照(监控日 2026-09-29):
配件不足 26 → 24(2 行翻盘)、预警总数 29、缺货 23 两边一致,
0 行反向变化、0 处其他字段变化、0 处级别变化。
- 真库实测:DNZ040947N1440V01 0 → 200、DNZ040959N1440V01 0 → 200;
库存表本就有正数的对照配件(60 / 87)未被箱表覆盖。
- 负载(SET STATISTICS IO,300 编码一个分片):jst_inventoryInfo 4543 逻辑读 +
jst_packInventoryInfo 947 逻辑读,物理读 0、Worktable 0;实测中位耗时
215ms → 391ms(+176ms/分片,配件全集 784 个约 3 个分片,占冷查 61s 的 1% 以内,
且结果按编码缓存 10 分钟)。
说明:SHOWPLAN 权限被拒(账号无该权限),改用 STATISTICS IO + 实测耗时 + 数据量
作为执行计划等价证据。
- 数据量边界:配件仓 jst_inventoryInfo 837 行、jst_packInventoryInfo 1163 行
(bin 非空 1024 行)。
- 后端:check-syntax 179 文件通过;node --test 393 项 392 通过
(唯一失败为既有环境问题 resilientSecretStore 权限断言,与本改动无关)。
|
2026-09-30 17:43:30 +08:00 |
|
|
|
30554720b2
|
feat: 客退看板新增「最晚退厂时间」列(工作平台数据,先占位待接入)
- 新增 supplierExitDateProvider.js:按供应商名匹配「最晚退厂时间」,
数据源为工作平台库 WorkbenchDataShared(同实例,另有 WorkbenchIdentity /
DataPlatformControl)。当前副本账号 cangku 无该库访问权限、系统设置里没有它的
连接配置、.env 的 JIAN_SUN_DB_* 与 WORK_ORDER_* 也为空,因此先返回不可用。
接入方式:IT 开通后配 SUPPLIER_EXIT_DATE_ENABLED=true + SUPPLIER_EXIT_DATE_SQL
(查询需返回 supplierName / exitDate 两列),或直接写死 CODE_* 常量,无需改其他文件。
- returnStockWarningService.js:composeRows 增加 latestExitDate /
latestExitDateLabel / latestExitDateAvailable;列表响应新增 exitDateMeta;
导出列在「供应商是否合作」后新增「最晚退厂时间」(未接入时导出显示「待接入」);
口径说明补一条(含完整取证:工作平台库不可达、副本无任何退厂字段、
fys_supplier.NoCoopTime 是不可用的停更快照)。
- StockWarning.jsx:表格新增「最晚退厂时间」列,有值显示日期、未接入显示「待接入」
(Tooltip 说明数据来源与开通方式);monitor.css 补占位符样式。
|
2026-09-28 16:06:40 +08:00 |
|
|
|
f7fc7fef4f
|
fix: 修复客退看板缓存命中时引用未定义常量导致 500
缓存 TTL 改成可配(DEFAULT_CACHE_TTL_MS / resolveCacheTtlMs)时漏改了
loadReplicaRows 里的比较表达式,仍写 CACHE_TTL_MS。缓存为空时短路不触发,
所以本地首轮没暴露;生产被预热任务写过缓存后,第二次请求命中该行即
ReferenceError 500。改为调用 resolveCacheTtlMs()。
|
2026-09-28 15:40:57 +08:00 |
|
|
|
6c3b14fc10
|
客退看板「是否出库」列改为「供应商是否合作」
- returnStockWarningService.js: 新增 supplierCoopSign 取 js_supplier.coopersgn
(LEFT JOIN dbo.js_supplier sp ON sp.scmname = sk.supplier_name),
解析为 supplierCoop / supplierCoopLabel(1=合作 / 2=不合作 / 其它=未知),
导出列「是否出库」同步替换为「供应商是否合作」
- StockWarning.jsx: 表格列替换,新增合作状态 Tag 与判断依据 Tooltip
- returnStockWarehouseRegistry.js: 更新崔桥工厂仓客退位复测结论
(2026-09-27 已同步进副本:349 编码 / 507 件)
|
2026-09-28 15:34:55 +08:00 |
|
|
|
2745cf18ff
|
feat: 库存动销分析「销售=0」导出按仓位拆行,库存数量按实际仓位统计
上一版把同一 SKU 的多个仓位用「、」拼在一格里,库存数量仍是 SKU 总量,
无法直接按仓位盘点。现改为每个仓位独立一行:
- bin CTE 改为按 (wms_co_id, sku_id, LTRIM(RTRIM(bin))) 分组,
SUM(qty) 得到仓位级库存(各仓位行之和 = SKU 总库存,实测 240=60+69+35+76)
- 导出行 = graded(SKU 级「销售=0」判定)LEFT JOIN 仓位级明细:
有仓位数据的 SKU 按仓位展开多行、库存数量取该仓位实际 qty(qty=0 的仓位行剔除);
仓位表未覆盖的 SKU 保留一行(仓位为空、库存取总库存),不丢数据
- 排序:仓库 → SKU 总库存倒序 → SKU → 仓位名称,同一 SKU 的各行保持相邻
- 前端按钮提示同步更新拆行与兜底规则说明
验证:后端 syntax 通过、单测 9/9(全量 389/390,唯一失败为既有 Windows 环境项);
前端 eslint/build 通过;
本地实测:单仓(睢宁 196 行,原 128 SKU 行)样例 SKU 正确拆为 4 行且合计 240;
全仓导出 6798 行(原 3650),有仓位行 6529、仓位为空兜底行 269,覆盖 26 仓
|
2026-09-28 09:55:45 +08:00 |
|
|
|
fc280bfe27
|
feat: 库存动销分析「销售=0」导出增加系统仓位列
仓位用于定位滞销库存的实际存放位置,便于盘点与挪位处理。
数据源为 rpt.jst_packInventoryInfo.bin(jst_sku.bin 全部为空、库存表无仓位字段,
这是业务库唯一可得的系统仓位):
- 按 (wms_co_id, sku_id) 聚合,LTRIM 去空格后 DISTINCT,STRING_AGG 按名称排序用「、」连接
- 排除无仓位(bin 为空)与零库存(qty=0)的行,避免无效仓位干扰
- LEFT JOIN 且按「仓库+SKU」双条件匹配,避免跨仓错配
- 导出列顺序:仓库 | SKU编码 | SKU名称 | 系统仓位 | 库存数量 | 销量 | 统计天数 | 统计基准日
- 前端按钮提示同步说明多仓位拼接规则与留空含义
验证:后端 syntax 通过、单测 9/9(全量 389/390,唯一失败为既有 Windows 权限环境项);
前端 eslint/build/测试均通过;
本地实测导出 3650 行,系统仓位列就位,3381 行有仓位(92.6%,未覆盖的 7.4% 为
仓位表仅含 13 个仓库所致),销量列全为 0,最长仓位串 600 字符(Excel 上限内);
浏览器实测点击下载,文件名与列结构正确
|
2026-09-28 09:34:55 +08:00 |
|
|
|
2c8ed86c26
|
feat: 库存动销分析「销售=0」档支持导出 SKU 明细
- 后端新增 GET /api/stock-sales-analysis/zero-sales-export:
复用与页面完全一致的分档口径(同一段 gradeCase 表达式 + 「有库存或有销量」过滤),
输出仓库/SKU编码/SKU名称/库存数量/销量/统计天数/统计基准日的 SKU 级明细;
支持.days 统计窗口、wmsCoId 逗号分隔过滤(仅允许仓库清单内的 ID,防任意拼参)、
format=xlsx|csv,复用通用导出服务 exportWorkbook
- services 新增 fetchZeroSaleSkuRows:SKU 级「销售=0」查询,LEFT JOIN rpt.jst_sku 取名称,
按仓库+库存倒序排列
- 前端工具栏新增「导出销售=0」按钮:跟随当前统计天数与仓库筛选,
文件名含业务日期与仓库范围,失败时解出错误体给出可读提示
- 测试补充 3 条:防呆抛错、空参短路、SQL 口径与参数传递断言
验证:后端 syntax 通过、单测 8/8(全量 389 条仅既有 Windows 环境项失败);
前端 eslint/build/test 21/21 通过;
本地实测:全仓导出 3641 行、26 仓、销量列全为 0;
单仓(崔桥半成品包装 694 行)与页面「销售=0」SKU 数一致;
浏览器实测点击下载真实文件名「库存动销分析-销售0明细-20260926.xlsx」
|
2026-09-27 17:47:45 +08:00 |
|
|
|
f20bd3a487
|
feat: 侧边栏新增二级「库存动销分析」页面
按《仓库库存动销分析.xlsx》:
- 一级菜单「大货库存监控」下新增二级「库存动销分析」(路由 /planning/operation/stock-sales-analysis)
- 表头与表格结构按需求表:仓库 | 动销等级 | SKU数量 | SKU占比 | 库存数量 | 库存占比 | 销量,
每仓 6 个动销等级(爆款/热卖款/平销款/滞销款-1/滞销款-2/销售=0)+ 1 行汇总,仓库列跨行合并
- 分档口径:日销 = 统计窗口内已发货件数 ÷ 窗口天数(7/14/30 天可选,默认 30),
库存取 rpt.jst_inventoryInfo 实时库存,销量取 jst_Orders×jst_OrderItem 按 send_date
(排除 Delete/Cancelled,与每日进销存发货口径一致),只统计有库存或有销量的 SKU
- 后端 /api/stock-sales-analysis:单条 SQL 一次覆盖全部仓库×等级,5 分钟缓存 + refresh=1 强制重算;
返回逐仓 + 全仓合计、占比、无数据仓数量
- 前端页面:统计天数/仓库筛选、口径说明弹窗、合计行高亮、无数据仓计数提示
- 页面权限:前后端 sidebarPages 注册 pageKey=stock_sales_analysis,默认 planning 角色可见
验证:后端 syntax + 单测 5/5;前端 eslint、build、npm test 21/21;
本地接口 30 天窗口实测 27 仓(崔桥汇总 2080 SKU / 90822 件 / 54076 件销量),
占比逐仓闭合为 100%;浏览器实测侧边栏入口、表头、197 行渲染与截图均正常
|
2026-09-27 16:29:58 +08:00 |
|
|
|
117d59c9f0
|
fix: 每日进销存截图按业务日期归档并补充幂等/执行记录测试
定时任务在凌晨 01:00 推送的是「昨日」数据,但截图对象键原先直接取执行时刻的北京日期,
导致归档目录与通知里的业务日期不一致(daily-inventory/2026-09-26/... 装的是 09-25 的数据)。
现改为由定时任务显式传入业务日期,目录与文件名统一用业务日期、时间仍用执行时刻:
daily-inventory/2026-09-25/daily-inventory-20260925-010000.png
另补充验收要求 8 的测试:
· buildScreenshotNames 归档命名(含业务日期与执行日期不同的场景)
· markNotified / hasNotified 幂等:同业务日同用户只成功一次,跨日期互不影响
· appendRunRecord 保留执行时间、截图地址、通知对象与失败原因
|
2026-09-27 14:53:05 +08:00 |
|
|
|
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 |
|
|
|
c47a25b002
|
fix: 期初兜底弃用 pm_stockMonitor,全部改用实时库存扣流水回推
口径校准(对照聚水潭进销存导出 09-23 期初基准):
崔桥工厂仓 基准 92388 / pm 路径 114286 / 回推 ≈89650
横林二仓 基准 63780 / pm 路径 1197 / 回推 ≈64029
山东青岗集 基准 88377 / pm 路径 67339 / 回推 ≈88210
河南洛宁 基准 83305 / pm 路径 76992 / 回推 ≈82473
pm_stockMonitor.jsStock 只覆盖纳入监控范围的 SKU 子集(横林二仓实测
1197 vs 全仓 63780),系统性偏低,不能充当全仓结存;「实时库存扣
流水回推」与基准偏差 0.3%~2.7%(来自缺失的 8 类单据),显著更准。
|
2026-09-27 10:09:19 +08:00 |
|
|
|
952c57a84a
|
fix: 修复流水取数漏传 cloudDb 导致流水列静默为空
路由调用 fetchFlows(wmsCoIds, from) 少了第一个参数 cloudDb,
导致形参错位(cloudDb=数组、wmsCoIds=日期、fromText=undefined),
函数静默返回空 Map 且无任何报错。补传参数,并为 fetchFlows 增加
防呆校验:首参非数据库实例时立即抛 TypeError。补 1 项回归测试。
|
2026-09-27 10:03:24 +08:00 |
|
|
|
c358aff781
|
feat: 每日进销存补充流水与期初数据,修复合计行 NaN
数据补充(全部来自数据库,无人工填数):
- 流水列接入 4/12:采购进仓(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 列业务库确无单据表(已核实全库表清单),保持「—」待 DBA 建表
- 期初快照缺失时自动兜底:优先用 rpt.pm_stockMonitor(报表库 01:00 跑批 T-1 库存,
按 dbWarehouse 聚合 jsStock,精确);监控表没有的虚拟仓(运营专用/京东仓)用
实时库存扣自期初时刻以来的带符号流水回推(近似),推导结果补写快照逐日滚动
缺陷修复:
- 合计行仓库名显示 NaN:isTotal 渲染分支拦截了所有列,'合计' 被强转数字;
现仓库名原样显示,无数据来源的流水列合计也显示「—」而非误导性 0
- 合计行:某列全部仓库均无数据时合计置空,避免 0 误读
新增 4 项单元测试(流水符号约定、参数展开、期初双路径推导)。
|
2026-09-27 09:54:59 +08:00 |
|
|
|
f205cb9322
|
fix: 截图服务改用系统库专用服务账号身份
页面启动会调用 /api/auth/verify,该接口要求令牌 sub 必须是系统库 users 表中真实且 active
的用户。原实现签发的是一个不存在于用户表的合成身份,verify 返回 401,前端清除令牌并跳转
登录页,截图因此永远拿不到数据(等待数据行 3 分钟超时)。
改为在系统库维护一个仅供服务端使用的专用账号:
· 账号不存在时按 role=admin、status=active、auth_source=service 创建
· 密码哈希为随机值且无人知晓,账号无法通过密码登录
· 已存在时复用 id,并仅对 auth_source=service 的本服务账号补齐管理员与启用状态
· 令牌 sub 使用该账号 id,15 分钟过期,仍只注入 localStorage
· 账号 id 进程内缓存,删除该行即可回收权限
新增 2 项单元测试:账号创建/复用与令牌 sub 校验。
|
2026-09-27 09:24:39 +08:00 |
|
|
|
3bfc48b8b3
|
Merge branch 'codex/daily-inventory-snapshot-0924' into codex/daily-inventory-notify-0924
冲突文件:backend/src/index.js
处理理由:采用已解决好与他人 PR #40/#41 冲突的分支 A 版本,再补回本分支的通知接口
require、/api/daily-inventory-notification 路由注册与调度器启动,双方行为均保留。
|
2026-09-26 12:18:11 +08:00 |
|
|
|
734b974f45
|
Merge branch 'main' into codex/daily-inventory-snapshot-0924(同步 PR #40/#41)
冲突文件:backend/src/index.js
处理理由:main 侧(他人 PR #40、#41)新增崔桥工厂仓客退三类路由 require 与注册、统一 404 与 JSON 错误处理中间件;
本分支仅新增每日进销存快照任务的 require 与 startDailyInventorySnapshotScheduler() 调用。
采用 main 版本文件并补回本分支两处改动,双方行为均保留。
|
2026-09-26 12:16:30 +08:00 |
|
|
|
b0f56b27f5
|
客退看板首仓改为崔桥工厂仓(数据源:崔桥工厂客退临时上架仓)
按 2026-09-25 业务口径,第一张子看板由「横林二仓客退数据监控」改为
「崔桥工厂仓客退数据监控」,取数仓位同步改为聚水潭「崔桥工厂客退临时上架仓」。
- 仓库配置:简尚-崔桥工厂仓 wms_co_id=15038426,客退位 customize_qty_1
- key 由 henglin2 改为 cuiqiao,同步改路由 / 侧边栏 / 路由映射 / 权限条目
- 旧路径 returns-inventory/henlin2* 保留为重定向,避免历史链接 404
- 核销看板(returnMonitorService)仍指向横林二仓,前端入口已下线,本次未动
副本取证:该仓客退位当前只有 2 编码 / 2 件(退货单有量:ERP 3115 条 +
奇门 1812 条),属「客退上架库存未同步进副本」,页面需靠导入功能补数据。
|
2026-09-25 14:16:11 +08:00 |
|
|
|
90fa54bd8c
|
Merge branch 'main' into codex/cangku-returns-monitor-001 (sync 41 commits, keep both sides)
|
2026-09-24 15:37:59 +08:00 |
|
134
|
345214daed
|
fix: force live refresh on MKH sync
|
2026-09-24 14:49:08 +08:00 |
|
134
|
ba6ef97a40
|
fix: reject stale MKH backend responses
|
2026-09-24 14:02:24 +08:00 |
|
134
|
ea312d9070
|
fix: force fresh MKH operational data
|
2026-09-24 13:30:09 +08:00 |
|
|
|
3af6bd9ef2
|
Merge branch 'codex/daily-inventory-snapshot-0924' into codex/daily-inventory-notify-0924
|
2026-09-24 12:00:26 +08:00 |
|
|
|
6c753791ad
|
Merge branch 'main' into codex/daily-inventory-snapshot-0924(同步 PR #31)
|
2026-09-24 12:00:14 +08:00 |
|
|
|
c4ea12e9ba
|
fix: 修正截图站点地址与通知正文链接,生产镜像补充 Chromium 与中文字体
- 截图默认站点改为生产主站 ck.yydd.ai(原默认值指向无关域名)
- 通知正文补充「页面地址」,便于在通知中心直接打开
- 服务身份增加 daily_inventory 页面权限声明
- Dockerfile 安装 Chromium 与 fonts-noto-cjk,否则容器内无法截图且中文显示为方块
|
2026-09-24 11:59:36 +08:00 |
|
|
|
56fba389e4
|
feat: 每日进销存增加定时截图通知
设置(仅管理员)
- 可配置是否启用、通知时间(默认 01:00 Asia/Shanghai)、多名通知用户
- 收件人在后端规范化:去空、去重、限长限量,配置持久化到 system_config
- 接口不返回通知中心密钥与对象存储密钥,只给是否已配置与脱敏预览
定时任务
- 单实例锁(MySQL GET_LOCK),按配置时间触发,命中后 30 分钟内失败最多补跑 3 次
- 服务端签发 15 分钟短时效 JWT 作为专用身份,令牌只写入浏览器 localStorage
- 等数据真正渲染完成(有数据行、无加载中、无错误提示)才截图,展开滚动容器后整页截图
- 对象键形如 daily-inventory/2026-09-25/daily-inventory-20260925-010000.png
- 截图上传成功后才逐用户发通知,单人失败不影响他人;正式推送按「业务日期+收件人」幂等
- 立即测试走同一链路但幂等键带随机数,不影响次日正式推送
- 每次执行记录时间、截图地址、通知对象、成功状态与失败原因
测试
- 覆盖收件人去重、通知时间校验、幂等键、业务日期与对象键、重试退避(17 项)
|
2026-09-24 11:22:51 +08:00 |
|
|
|
9dbe2793a5
|
feat: 每日进销存改为全部从数据库取数
- 期初数量改由本地快照表 daily_inventory_snapshot 提供(上一业务日期末),
每日 01:30 定时任务落库,接口侧缺失时补写兜底,逐日自动滚动
- 新增 dailyInventorySnapshotDb / dailyInventorySnapshotJob 与手动补跑脚本
- dailyInventoryBaseline 瘦身为纯仓库映射,去掉所有硬编码业务数值
- 12 个流水列因业务库缺单据表返回空值,前端灰底显示「—」
- 修复 qty 全为 0 的仓库期末显示 null 的缺陷
- 新增 docs/库存流水单据表需求.md 给 DBA
|
2026-09-24 11:20:30 +08:00 |
|
134
|
4227d9001e
|
fix: reconcile MKH received stock and work orders
|
2026-09-24 09:19:21 +08:00 |
|
|
|
fb1b433f94
|
feat: 新增每日进销存(大货库存监控)
|
2026-09-23 17:40:22 +08:00 |
|
|
|
8655433e39
|
feat: 新增每日进销存(大货库存监控)
|
2026-09-23 17:37:42 +08:00 |
|
|
|
f6b755aac4
|
feat: 新增每日进销存(大货库存监控)
|
2026-09-23 17:37:41 +08:00 |
|
|
|
700d7ae96d
|
feat: 新增每日进销存(大货库存监控)
|
2026-09-23 17:37:40 +08:00 |
|
|
|
37c1adf4f2
|
feat: 新增每日进销存(大货库存监控)
|
2026-09-23 17:37:39 +08:00 |
|
|
|
592c52f891
|
refactor: 移除大货库存监控功能(26 仓)
应用户要求下线该功能组,侧边栏不再显示「大货库存监控」及 26 个仓库二级菜单。
移除内容:
- 前端页面 LargeStockMonitor、18 列定义、API 封装与样式
- 路由 /planning/large-stock-monitor/:warehouseSlug 与权限点 large_stock_monitor
- 侧边栏菜单组 stock-monitor-large 与 SIDEBAR_ROUTE_MAP 26 条映射
- 后端 /api/large-stock-monitor 路由挂载、largeStockMonitor.js、
largeStockMonitorConfig.js、largeStockMonitorFlow.js 及端到端校验脚本
验证:
- 全仓无 largeStockMonitor 残留引用;后端 346 用例 345 通过
(1 项失败为 resilientSecretStore.test.js,Windows 权限语义基线既有失败)
- 前端 lint + 测试 + 构建通过,产物中 LargeStockMonitor chunk 已消失
- 运行时验证:/api/large-stock-monitor/* 返回 404,页面与登录不受影响
|
2026-09-23 16:07:04 +08:00 |
|
134
|
66e0ddf709
|
fix: 用箱仓库存补齐滞后的配件库存
|
2026-09-23 15:42:46 +08:00 |
|
|
|
2bc949099b
|
feat: 新增大货库存监控(26 仓)
按「库存监控」表格在侧边栏增加一级/二级菜单与共用页面
(路由 /planning/large-stock-monitor/:warehouseSlug)。
后端:
- 新增 largeStockMonitorConfig.js:26 仓配置,含 wms_co_id / 快照仓名 / routeKey / slug 映射
- 新增 largeStockMonitor.js:config / overview / sku-list 三个接口
- 新增 largeStockMonitorFlow.js:采购进仓、采购退货、销售出仓、销售退货四类单据流水取数
- 新增 verify-large-stock-monitor.js:26 仓端到端校验脚本
- index.js:挂载 /api/large-stock-monitor 路由
口径说明:
- 库存周转天数 = 月度发货总件数 / 月度日均库存件数 × 100%,下沉到 SQL CASE WHEN 计算
- 四级分级(滞销预警/慢流/呆滞/僵尸)按库龄 + 周转率双维度判定
- 期末数量取聚水潭实际库存 jst_inventoryInfo(按 wms_co_id 单仓),
不用 pm_stockMonitor.jsStock —— 后者 warehouse 是「归属仓」口径,
会把已调拨到外仓的货仍计在本仓名下(崔桥工厂仓因此虚高约 2.2 万)
- 截止时刻统一为快照日次日 01:00(跑批时点),库龄/分级均以此为基准,不再用 GETDATE()
前端:
- 新增 LargeStockMonitor 页面、18 列定义、API 封装与样式
- 路由与侧边栏:26 条二级菜单 + 权限点
冲突处理:
- 主仓库已下线 /api/dashboard(backend/src/api/dashboard.js 被移除),
相应删除 dashboardRoutes 的 require 与挂载,避免后端启动时 require 失败崩溃
- 保留主仓库新增的「模块化库存监控」菜单组及其子项
|
2026-09-23 13:42:58 +08:00 |
|
|
|
b3f4d1af64
|
feat: 客退数据监控五仓看板与本地运行稳定性加固
功能:
- 退货库存预警:横林二仓/苏北/睢宁/山东青岗集/河南洛宁 五张看板,
按各仓客退上架仓对应的自定义库存位取数(各仓位不同:横林/苏北/睢宁 c1,山东 c2)
- 支持导入聚水潭「箱及仓位库存」导出文件覆盖创建时间、件数、供应商
(副本只有仓库级数量,没有箱级维度,真实上架时间只能靠导入)
- 退货入库核销与每日库存监控:状态落本地系统库,含定时任务与差异清单
- 服务端导出(xlsx/csv),不受列表分页与展示上限约束
稳定性:
- 前端幂等请求在后端重启窗口内自动退避重连,不再直接抛 500
- 后端补齐统一 JSON 错误兜底与 /api JSON 404,异常不再返回 HTML
- 隧道 ssh 改为绝对路径解析并隐藏窗口,避免非交互式启动 ENOENT 与黑窗弹窗
- 业务库 DATETIME 按北京时间解析(useUTC: false),修复时间显示整体 +8 小时
合并:与上游「隧道断线自愈 + 配置负缓存」为同一问题的两份实现,
本分支采用上游方案(带 TTL 的负缓存 + 统一失效函数 + 单测)。
|
2026-09-23 11:32:16 +08:00 |
|
134
|
b8e60a19d2
|
fix: MKH刷新改用实时订单库存口径
|
2026-09-23 11:12:08 +08:00 |
|
134
|
fa91b9242c
|
fix: 根治MKH同步后旧请求覆盖最新数据
|
2026-09-23 11:05:28 +08:00 |
|
|
|
97a93766e8
|
Merge pull request 'fix: MKH-BOM 配件仓位仓名改用 wms_co_id 关联,修正误显示「常州简尚家居有限公司」' (#22) from codex/mkh-pack-warehouse-join-0919 into main
|
2026-09-22 23:58:40 +08:00 |
|
|
|
f4303c0aed
|
Merge pull request 'fix: 隧道断线自愈 + 修复配置负缓存永久固化(根治「隧道一断即整栈不可用 / 必须重启后端」)' (#21) from codex/tunnel-selfheal-config-cache-0922 into main
|
2026-09-22 23:58:24 +08:00 |
|
|
|
a58fc7d67b
|
Merge pull request 'fix: MKH-BOM 修复在途旧查询回写缓存,导致「同步最新数据」点完仍是旧数据' (#20) from codex/mkh-cache-stale-write-fix-0922 into main
|
2026-09-22 23:58:04 +08:00 |
|
|
|
38fa3f2127
|
fix: 隧道断线自愈 + 修复配置负缓存永久固化
远端 RST 会把隧道反复踢掉(09-20 实测当天断 5 次,每次存活 15~25 分钟)。原先的
实现把「一次网络抖动」放大成「整个开发栈不可用」,根因有两处,本次一并修掉。
1) scripts/start-remote.mjs —— 隧道断了却拉着应用陪葬
隧道进程 exit 时直接 stopChildren(),把后端和前端一起杀掉,于是每一次 RST 都
升级成一次「网站打不开」,还得靠外部守护清残留、整树重启才能恢复。
改为「退避重连隧道本身,后端/前端进程不受影响」——这正是 autossh 的语义
(autossh 只负责重启 ssh,从不牵连被它服务的应用)。建立失败走 1s→30s 指数
退避,建立成功即重置退避。
顺带补齐保活参数:TCPKeepAlive=yes、ConnectTimeout=10,探活间隔 30s → 15s,
以便更快发现已被对端 RST 的死连接。
2) backend/src/config/cloudDatabase.js —— 配置负缓存被永久固化
系统库读取失败时把「空候选」写进缓存,而入口判断是
`if (cachedCloudConfigCandidates)` —— [] 在 JS 里是 truthy,于是这次失败被
永久固化:之后永不重试,直接抛「业务数据库尚未配置」500,隧道恢复了也没用,
必须重启后端。
改为「带 TTL 的负缓存」(默认 30s,可用 CLOUD_DB_CONFIG_NEGATIVE_TTL_MS 调整):
入口用 `!== null` 判断,失败态到期自动重新解析,使隧道恢复后无需人工干预。
缓存清理收敛到 invalidateCloudConfigCache() 单点,避免日后只清数组、忘了清
TTL 时间戳而退化回「永不过期」。同时让「测试连接」入口显式失效,保证用户改完
配置点测试能立即看到真实结果。
顺带把请求超时默认值 600000ms → 60000ms:10 分钟 × maxAttempts=2 最坏挂
20 分钟,用户体感就是「卡死」;冷查实测 16~42s,60s 仍有充足余量。
验证:
- 新增 backend/test/cloudDatabaseConfigCache.test.js,锁定负缓存三段语义
(TTL 内不重复解析 / 到期必须重试 / 上游恢复后自动复原且成功态不被 TTL 淘汰);
test/remote-access.test.mjs 补隧道保活参数、退避曲线,以及「自愈循环不得调用
stopChildren」的防腐化断言。
- 两处均做对照组实验:去掉保护后测试如实报错(负缓存 → 报 TTL 到期未重试;
隧道 → 把 stopChildren 加回去即被用例抓住),证明用例真能拦住回归。
- 后端全量 340 项 / 339 通过,唯一失败为 resilientSecretStore 的 Windows 权限
断言(环境固有,与本次无关);check-syntax 通过。
- 本地实测:kill 掉隧道进程后 1 秒内自动重建(PID 36268 → 15816),后端进程
PID 未变(29580)、/health 仍返回 200。
|
2026-09-22 19:32:40 +08:00 |
|