客退看板首仓改为崔桥工厂仓(数据源:崔桥工厂客退临时上架仓) #41

Merged
Xkh5201314 merged 1 commits from codex/lunanting-cuiqiao-returns-001 into main 2026-09-25 14:17:26 +08:00
13 changed files with 64 additions and 44 deletions

View File

@ -25,7 +25,7 @@ const resolveScope = (value) => (['imported', 'replica'].includes(String(value))
/**
* GET /api/return-stock-warning/list —— 退货库存预警列表(客退数据监控,按仓库出数)
* warehouse: 仓库标识 henlin2 / subei / suining / shandong / henan(缺省 = 横林二仓)
* warehouse: 仓库标识 cuiqiao / subei / suining / shandong / henan(缺省 = 崔桥工厂仓)
*/
router.get('/list', async (req, res, next) => {
try {

View File

@ -665,9 +665,9 @@ async function startServer(options = {}) {
cubejsApp.use('/api/mkh-bom', authMiddleware, mkhBomRoutes);
cubejsApp.use('/api/daily-inventory', authMiddleware, dailyInventoryRoutes);
cubejsApp.use('/api/return-inventory-warning', authMiddleware, returnInventoryWarningRoutes);
// 横林二仓客退:退货入库核销 + 每日库存监控
// 崔桥工厂仓客退:退货入库核销 + 每日库存监控
cubejsApp.use('/api/return-monitor', authMiddleware, returnMonitorRoutes);
// 横林二仓客退:退货库存预警(箱及仓位库存 · 客退临时上架仓)
// 崔桥工厂仓客退:退货库存预警(箱及仓位库存 · 崔桥工厂客退临时上架仓)
cubejsApp.use('/api/return-stock-warning', authMiddleware, returnStockWarningRoutes);
// =====================

View File

@ -28,7 +28,7 @@ function startReturnMonitorScheduler() {
cron.schedule(JOB_CRON, () => {
runReturnMonitorCompare('cron').catch(() => {});
}, { timezone: TIMEZONE });
console.log(`[Scheduler] 横林二仓客退库龄核销任务已注册: ${JOB_CRON} (${TIMEZONE})`);
console.log(`[Scheduler] 崔桥工厂仓客退库龄核销任务已注册: ${JOB_CRON} (${TIMEZONE})`);
}
module.exports = { startReturnMonitorScheduler, runReturnMonitorCompare };

View File

@ -14,13 +14,21 @@
* · returnBinName = 用户口径的聚水潭仓位名,写进页面/导出的「数据来源」,便于核对;
* · returnSlot = 副本里真正取数的那一列,必须与上面的仓位名一一对应。
*
* 仓位名 → 库存位 对照(2026-09-17 实测,条件 ISNULL(col,0) > 0):
* 箱及仓位库存 · 简尚-横林二仓 · 客退临时上架仓 customize_qty_1 1274 编码 / 3271 件
* 箱及仓位库存 · 简尚-新苏北仓 · 新苏北客退上架仓 customize_qty_1 83 编码 / 317 件
* 箱及仓位库存 · 简尚-睢宁仓 · 睢宁客退上架仓 customize_qty_1 46 编码 / 173 件
* 箱及仓位库存 · 简尚-山东青岗集仓 · 青岗集客退上架仓 customize_qty_2 324 编码 / 625 件
* 仓位名 → 库存位 对照(2026-09-25 复测,条件 ISNULL(col,0) > 0):
* 箱及仓位库存 · 简尚-崔桥工厂仓 · 崔桥工厂客退临时上架仓 customize_qty_1 2 编码 / 2 件 ⚠
* 箱及仓位库存 · 简尚-新苏北仓 · 新苏北客退上架仓 customize_qty_1 75 编码 / 362 件
* 箱及仓位库存 · 简尚-睢宁仓 · 睢宁客退上架仓 customize_qty_1 98 编码 / 243 件
* 箱及仓位库存 · 简尚-山东青岗集仓 · 青岗集客退上架仓 customize_qty_2 403 编码 / 912 件
* 箱及仓位库存 · 简尚-河南洛宁仓 · 河南洛宁客退上架仓 三位全为 0(无数据)
*
* ⚠ 崔桥工厂仓(15038426)是 2026-09-25 用户指定替换横林二仓的。复测结论:
* 副本里该仓客退位只有 2 编码 / 2 件,但退货单量很大(ERP 售后单 3,115 条 +
* 奇门退款单 1,812 条,warehouse='简尚-崔桥工厂仓销退仓')——即「退货有,客退上架库存
* 没同步进副本」。全库 218 张表里没有任何「销退仓 / 客退仓 / 上架仓」命名的独立仓
* (jst_warehouseInfo 里 name 含「退」的为 0),销退仓只是退货单据里的 warehouse 文本值。
* 所以崔桥这张看板在当前副本下**必然近乎空白**,要出数只能:① 让 IT 把该仓客退上架仓
* 的库存同步进 jst_inventoryInfo 的自定义库存位;② 用页面「导入」上传聚水潭导出文件。
*
* ⚠ 副本里**没有任何仓位维度**(2026-09-17 复核:218 张表 / 5,496 个字段中,列名含
* bin / box / position / location / shelf / slot 的为 0 个;jst_sku.bin、jst_sku.other_bin、
* jst_returnAndRefundItem.box_id、jst_packInventoryInfo.bin 四个疑似字段 100% 为空)。
@ -37,20 +45,23 @@ const RETURN_SLOT_COLUMNS = ['customize_qty_1', 'customize_qty_2', 'customize_qt
const WAREHOUSE_LIST = [
{
key: 'henlin2',
// 页面标题 / 侧边栏名称
title: '横林二仓客退数据监控',
shortName: '横林二仓',
key: 'cuiqiao',
// 页面标题 / 侧边栏名称(2026-09-25 用户指定:原「横林二仓客退数据监控」改为崔桥工厂仓)
title: '崔桥工厂仓客退数据监控',
shortName: '崔桥工厂仓',
// 仓库主表 jst_warehouseInfo.wms_co_id
wmsCoId: 15033302,
warehouseName: '简尚-横林二仓',
wmsCoId: 15038426,
warehouseName: '简尚-崔桥工厂仓',
// 退货单(售后单 / 奇门退款单)里的销退仓名称,仅 firstInbound 口径用到
returnWarehouseDb: '简尚-横林二仓销退仓',
// 聚水潭「箱及仓位库存」里对应的仓位名(页面/导出的「数据来源」直接显示它)
returnBinName: '客退临时上架仓',
returnWarehouseDb: '简尚-崔桥工厂仓销退仓',
// 聚水潭「箱及仓位库存」里对应的仓位名(2026-09-25 用户指定,页面/导出直接显示它)
returnBinName: '崔桥工厂客退临时上架仓',
// 客退临时上架仓占用的自定义库存位
returnSlot: 'customize_qty_1',
// 该仓当天是否有客退在库数据(2026-09-17 实测);空仓时页面给提示
// ⚠ 2026-09-25 实测:该仓在副本 jst_inventoryInfo 里客退位只有 2 个编码 / 2 件
//(qty 总库存 92,818 件;return_qty / c2 / c3 / sale_refund_qty 全为 0)。
// 退货单是有的(ERP 售后单 3,115 条 + 奇门退款单 1,812 条),
// 说明是「客退上架仓」这一仓位没同步进副本,不是业务上没有退货。
hasReturnStock: true,
},
{
@ -106,7 +117,7 @@ const WAREHOUSE_LIST = [
},
];
const DEFAULT_WAREHOUSE_KEY = 'henlin2';
const DEFAULT_WAREHOUSE_KEY = 'cuiqiao';
const WAREHOUSE_MAP = new Map(WAREHOUSE_LIST.map((item) => [item.key, item]));

View File

@ -2,7 +2,7 @@ import request from './request';
const LONG_TIMEOUT_MS = 10 * 60 * 1000;
// 横林二仓客退:退货入库核销 + 每日库存监控看板
// 崔桥工厂仓客退:退货入库核销 + 每日库存监控看板
export const getReturnMonitorDashboard = (params = {}) => request.get(
'/api/return-monitor/dashboard',
{ params, timeout: LONG_TIMEOUT_MS }

View File

@ -3,7 +3,7 @@ import request from './request';
const LONG_TIMEOUT_MS = 10 * 60 * 1000;
// 客退数据监控(箱及仓位库存 · 客退临时上架仓)
// params.warehouse: henlin2 / subei / suining / shandong / henan(缺省 = 横林二仓)
// params.warehouse: cuiqiao / subei / suining / shandong / henan(缺省 = 崔桥工厂仓)
export const getReturnStockWarningList = (params = {}) => request.get(
'/api/return-stock-warning/list',
{ params, timeout: LONG_TIMEOUT_MS }

View File

@ -21,7 +21,7 @@ export const DEFAULT_SIDEBAR_CONFIG = {
{
key: 'returns-inventory', type: 'group', label: '退货库存监控', icon: 'inbox', visible: true, order: 75, defaultExpanded: true,
children: [
{ key: 'returns-inventory-henlin2', label: '横林二仓客退数据监控', icon: 'table', routeKey: 'returns-inventory-henlin2', visible: true, order: 10 },
{ key: 'returns-inventory-cuiqiao', label: '崔桥工厂仓客退数据监控', icon: 'table', routeKey: 'returns-inventory-cuiqiao', visible: true, order: 10 },
{ key: 'returns-inventory-subei', label: '苏北客退数据监控', icon: 'table', routeKey: 'returns-inventory-subei', visible: true, order: 20 },
{ key: 'returns-inventory-suining', label: '睢宁客退数据监控', icon: 'table', routeKey: 'returns-inventory-suining', visible: true, order: 30 },
{ key: 'returns-inventory-shandong', label: '山东客退数据监控', icon: 'table', routeKey: 'returns-inventory-shandong', visible: true, order: 40 },

View File

@ -5,7 +5,7 @@ export const SIDEBAR_PAGES = [
{ pageKey: 'dashboard_preview', path: '/planning/dev-style-preview', name: '仪表盘', category: 'planning', defaultRoles: DEFAULT_PLANNING_ROLES },
{ pageKey: 'settings', path: '/settings', name: '系统设置', category: 'system', defaultRoles: DEFAULT_SYSTEM_ROLES },
{ pageKey: 'daily_inventory', path: '/planning/operation/daily-inventory', name: '每日进销存', category: 'planning', defaultRoles: DEFAULT_PLANNING_ROLES },
{ pageKey: 'returns_inventory_henlin2', path: '/planning/operation/returns-inventory/henlin2', name: '横林二仓客退数据监控', category: 'planning', defaultRoles: DEFAULT_PLANNING_ROLES },
{ pageKey: 'returns_inventory_cuiqiao', path: '/planning/operation/returns-inventory/cuiqiao', name: '崔桥工厂仓客退数据监控', category: 'planning', defaultRoles: DEFAULT_PLANNING_ROLES },
{ pageKey: 'returns_inventory_subei', path: '/planning/operation/returns-inventory/subei', name: '苏北客退数据监控', category: 'planning', defaultRoles: DEFAULT_PLANNING_ROLES },
{ pageKey: 'returns_inventory_suining', path: '/planning/operation/returns-inventory/suining', name: '睢宁客退数据监控', category: 'planning', defaultRoles: DEFAULT_PLANNING_ROLES },
{ pageKey: 'returns_inventory_shandong', path: '/planning/operation/returns-inventory/shandong', name: '山东客退数据监控', category: 'planning', defaultRoles: DEFAULT_PLANNING_ROLES },

View File

@ -81,9 +81,9 @@ const SIDEBAR_ROUTE_MAP = {
},
'promotion-module': { path: '/planning/operation/promotion-module' },
'product-monitoring': { path: '/planning/operation/product-monitoring' },
'returns-inventory-henlin2': {
path: '/planning/operation/returns-inventory/henlin2',
activePath: '/planning/operation/returns-inventory/henlin2',
'returns-inventory-cuiqiao': {
path: '/planning/operation/returns-inventory/cuiqiao',
activePath: '/planning/operation/returns-inventory/cuiqiao',
matchMode: 'prefix',
},
'returns-inventory-subei': {

View File

@ -7,7 +7,7 @@ import './monitor.css';
/**
* 客退数据监控(按仓库出数)
*
* 同一个页面支撑 5 张看板:横林二仓 / 苏北 / 睢宁 / 山东 / 河南。
* 同一个页面支撑 5 张看板:崔桥工厂仓 / 苏北 / 睢宁 / 山东 / 河南。
* 结构完全一致,差异只有「取哪个仓」——由路由传入的 warehouseKey 决定,
* 页面本身不拼任何仓库相关的 SQL 或口径。
*
@ -31,7 +31,7 @@ const Monitor = ({ warehouseKey }) => {
{warehouse.hasReturnStock && warehouse.returnSlot !== 'customize_qty_1' ? (
<p className="rim-hero__desc" style={{ marginTop: 4 }}>
注:该仓位在业务库里占用的是 <b>{warehouse.returnSlot}</b>
(横林二仓 / 苏北 / 睢宁用的是 customize_qty_1),页面已按这个位取数。
(崔桥工厂仓 / 苏北 / 睢宁用的是 customize_qty_1),页面已按这个位取数。
</p>
) : null}
{!warehouse.hasReturnStock ? (

View File

@ -381,7 +381,7 @@ const COLUMNS = [
/**
* 客退数据监控主表(按仓库出数)
* warehouse: 仓库标识 henlin2 / subei / suining / shandong / henan,
* 透传给列表 / 导出 / 导入 / 清除导入四个接口;缺省走后端默认仓(横林二仓)
* 透传给列表 / 导出 / 导入 / 清除导入四个接口;缺省走后端默认仓(崔桥工厂仓)
*/
const StockWarning = ({ warehouse }) => {
// 前端只用来定文案(导出文件名 / 空态提示),取数与口径一律以后端返回为准

View File

@ -5,20 +5,21 @@
* 这里只负责「路由 → 仓库标识 → 页面标题/描述」的映射,不改动任何口径。
*
* 各仓的「客退上架仓」在聚水潭里的仓位名不同,占用的自定义库存位也不同
* (横林/苏北/睢宁 = customize_qty_1,山东 = customize_qty_2),文案里要如实写出来,
* 否则看数据的人会对不上聚水潭。仓位名以用户 2026-09-17 口径为准。
* (崔桥/苏北/睢宁 = customize_qty_1,山东 = customize_qty_2),文案里要如实写出来,
* 否则看数据的人会对不上聚水潭。仓位名以用户口径为准(2026-09-25 起首仓改为崔桥工厂仓)。
*/
export const DEFAULT_WAREHOUSE_KEY = 'henlin2';
export const DEFAULT_WAREHOUSE_KEY = 'cuiqiao';
export const WAREHOUSES = [
{
key: 'henlin2',
title: '横林二仓客退数据监控',
shortName: '横林二仓',
warehouseName: '简尚-横林二仓',
returnBinName: '客退临时上架仓',
key: 'cuiqiao',
title: '崔桥工厂仓客退数据监控',
shortName: '崔桥工厂仓',
warehouseName: '简尚-崔桥工厂仓',
returnBinName: '崔桥工厂客退临时上架仓',
returnSlot: 'customize_qty_1',
// 2026-09-25 实测:副本里该仓客退位只有 2 编码 / 2 件(退货单有量,库存没同步)
hasReturnStock: true,
},
{
@ -62,7 +63,7 @@ export const WAREHOUSES = [
const WAREHOUSE_MAP = new Map(WAREHOUSES.map((item) => [item.key, item]));
/** 取仓库配置,非法 key 回落到默认仓(横林二仓) */
/** 取仓库配置,非法 key 回落到默认仓(崔桥工厂仓) */
export const resolveWarehouseConfig = (key) => (
WAREHOUSE_MAP.get(String(key || '').trim()) || WAREHOUSE_MAP.get(DEFAULT_WAREHOUSE_KEY)
);

View File

@ -120,8 +120,8 @@ const router = createBrowserRouter([
// 客退数据监控(5 张看板共用同一个页面,靠 warehouseKey 区分取哪个仓;
// 单一「退货库存预警」视图,原 明细/超期/汇总/差异 四个页签已下线)
{
path: 'planning/operation/returns-inventory/henlin2',
element: renderLazyComponent(ReturnsInventoryMonitor, { warehouseKey: 'henlin2' }),
path: 'planning/operation/returns-inventory/cuiqiao',
element: renderLazyComponent(ReturnsInventoryMonitor, { warehouseKey: 'cuiqiao' }),
},
{
path: 'planning/operation/returns-inventory/subei',
@ -140,17 +140,25 @@ const router = createBrowserRouter([
element: renderLazyComponent(ReturnsInventoryMonitor, { warehouseKey: 'henan' }),
},
// 历史路径(子看板 / 页签形态)→ 统一回到主看板
{
path: 'planning/operation/returns-inventory/henlin2',
element: <Navigate to="/planning/operation/returns-inventory/cuiqiao" replace />,
},
{
path: 'planning/operation/returns-inventory/henlin2/monitor',
element: <Navigate to="/planning/operation/returns-inventory/henlin2" replace />,
element: <Navigate to="/planning/operation/returns-inventory/cuiqiao" replace />,
},
{
path: 'planning/operation/returns-inventory/henlin2/inbound',
element: <Navigate to="/planning/operation/returns-inventory/henlin2" replace />,
element: <Navigate to="/planning/operation/returns-inventory/cuiqiao" replace />,
},
{
path: 'planning/operation/returns-inventory/henlin2/stock',
element: <Navigate to="/planning/operation/returns-inventory/henlin2" replace />,
element: <Navigate to="/planning/operation/returns-inventory/cuiqiao" replace />,
},
{
path: 'planning/operation/returns-inventory/cuiqiao/monitor',
element: <Navigate to="/planning/operation/returns-inventory/cuiqiao" replace />,
},
{ path: 'planning/operation/store-checkup', element: <Navigate to={HOME_URL} replace /> },
{ path: 'planning/operation/review-analysis', element: <Navigate to={HOME_URL} replace /> },