Commit cc46620492b701b3c0819587cc97f1784f6214b5

Authored by “wangming”
1 parent c11a79f9

fix(xsckd): 显式落库 ly/djzt/skmx,按来源调整免审与审核拦截

- 销售出库单保存时显式写入 ly、djzt、skmx,避免 Mapster 未映射导致不落库
- 免审逻辑改为:ly 非空且非「后台」则免审,保留备注「抖音订单:」兼容
- 通用审核路径增加回滚与非后台来源无需审核提示;更新相关文案
- 同步前端与 Dashboard、PACKAGE_README 调整

Made-with: Cursor
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/detail-view.vue
... ... @@ -320,6 +320,7 @@ export default {
320 320 if (ly == null || ly === '') return '无'
321 321 if (ly === '门店') return '门店(收银台)'
322 322 if (ly === '抖音订单') return '抖音订单'
  323 + if (ly === '后台') return '后台'
323 324 return ly
324 325 },
325 326 formatDjrq(ts) {
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/index.vue
... ... @@ -240,14 +240,14 @@
240 240 this.getskzhOptions();
241 241 },
242 242 methods: {
243   - /** 收银台/抖音等:不走 ERP 二级审核、仅查看 */
  243 + /** 非「后台」来源:不走 ERP 审核(与后端 IsSalesOutboundSkipErpAudit 一致;ly 空视为后台需审) */
244 244 isSkipErpAuditSource(row) {
245 245 if (!row) return false
246   - const ly = row.ly
247   - if (ly === '门店' || ly === '抖音订单' || ly === '抖音抓单') return true
248 246 const bz = row.bz != null && row.bz !== '' ? String(row.bz).trim() : ''
249 247 if (bz.startsWith('抖音订单:')) return true
250   - return false
  248 + const ly = row.ly != null && row.ly !== '' ? String(row.ly).trim() : ''
  249 + if (ly === '') return false
  250 + return ly !== '后台'
251 251 },
252 252 /** 后台来源且草稿可编辑 */
253 253 canEditDraft(row) {
... ... @@ -272,6 +272,7 @@
272 272 if (ly == null || ly === '') return '无'
273 273 if (ly === '门店') return '门店(收银台)'
274 274 if (ly === '抖音订单') return '抖音订单'
  275 + if (ly === '后台') return '后台'
275 276 return ly
276 277 },
277 278 // ✅ 原价:优先使用后端存储的 ydje(与收银台订单原价一致),无则用 收款+优惠 兼容旧数据
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtXsckdService.cs
... ... @@ -832,6 +832,11 @@ namespace NCC.Extend.WtXsckd
832 832 entity.Ydje = input.ydje;
833 833 entity.Cbje = input.cbje;
834 834 entity.Bjsx = input.bjsx;
  835 + // 收银台/抖音等 JSON 为小写 ly、djzt、skmx;Mapster 在部分环境下未映射到实体 Pascal 属性,
  836 + // 配合 Insertable(ignoreNullColumn: true) 会导致整列不落库 → 免审与待办过滤失效。显式写入。
  837 + entity.Ly = input.ly;
  838 + entity.Djzt = input.djzt;
  839 + entity.Skmx = input.skmx;
835 840  
836 841 // 获取用户ID(匿名访问时为null或空字符串)
837 842 string? userId = null;
... ... @@ -1587,7 +1592,7 @@ namespace NCC.Extend.WtXsckd
1587 1592 var oldHeader = await _db.Queryable<WtXsckdEntity>().FirstAsync(p => p.Id == id);
1588 1593 var oldMxList = await _db.Queryable<WtXsckdMxEntity>().Where(u => u.Djbh == id).ToListAsync();
1589 1594 if (IsSalesOutboundSkipErpAudit(oldHeader))
1590   - throw NCCException.Bah("收银台或抖音等外部来源的销售出库单不允许在此修改");
  1595 + throw NCCException.Bah("非后台来源的销售出库单不允许在此修改");
1591 1596 var entity = input.Adapt<WtXsckdEntity>();
1592 1597 entity.Bjsx = input.bjsx;
1593 1598  
... ... @@ -2861,23 +2866,20 @@ LIMIT {offset}, {pageSize}&quot;;
2861 2866 }
2862 2867  
2863 2868 /// <summary>
2864   - /// 销售出库单是否跳过 ERP 二级审核:收银台「门店」、抖音「抖音订单/抖音抓单」、或备注为抖音发货脚本格式(抖音订单:…)。
  2869 + /// 销售出库单是否跳过 ERP 审核:仅「单据来源 ly 为后台或空(未标记,视同后台录入需审)」走审核;
  2870 + /// ly 有值且不为「后台」则免审;备注「抖音订单:」开头免审(兼容早期仅写备注的抖音单)。
2865 2871 /// </summary>
2866 2872 private static bool IsSalesOutboundSkipErpAudit(WtXsckdEntity entity)
2867 2873 {
2868 2874 if (entity == null) return false;
2869 2875 if (!string.Equals(entity.Djlx, "销售出库单", StringComparison.Ordinal)) return false;
2870   - var ly = entity.Ly?.Trim();
2871   - if (!string.IsNullOrEmpty(ly))
2872   - {
2873   - if (string.Equals(ly, "门店", StringComparison.Ordinal)) return true;
2874   - if (string.Equals(ly, "抖音订单", StringComparison.Ordinal)) return true;
2875   - if (string.Equals(ly, "抖音抓单", StringComparison.Ordinal)) return true;
2876   - }
2877 2876 var bz = entity.Bz?.Trim();
2878 2877 if (!string.IsNullOrEmpty(bz) && bz.StartsWith("抖音订单:", StringComparison.Ordinal))
2879 2878 return true;
2880   - return false;
  2879 + var ly = entity.Ly?.Trim();
  2880 + if (string.IsNullOrEmpty(ly))
  2881 + return false;
  2882 + return !string.Equals(ly, "后台", StringComparison.Ordinal);
2881 2883 }
2882 2884  
2883 2885 /// <summary>
... ... @@ -2905,10 +2907,22 @@ LIMIT {offset}, {pageSize}&quot;;
2905 2907  
2906 2908 var entity = await _db.Queryable<WtXsckdEntity>().Where(x => x.Id == id).FirstAsync();
2907 2909 if (entity == null)
  2910 + {
  2911 + _db.RollbackTran();
2908 2912 return new { success = false, message = "单据不存在" };
  2913 + }
2909 2914  
2910 2915 if (!string.IsNullOrEmpty(expectedDjlx) && entity.Djlx != expectedDjlx)
  2916 + {
  2917 + _db.RollbackTran();
2911 2918 return new { success = false, message = $"该单据不是{expectedDjlx},无法审核" };
  2919 + }
  2920 +
  2921 + if (entity.Djlx == "销售出库单" && IsSalesOutboundSkipErpAudit(entity))
  2922 + {
  2923 + _db.RollbackTran();
  2924 + return new { success = false, message = "非后台来源的销售出库单无需在此审核" };
  2925 + }
2912 2926  
2913 2927 var actualDjlx = entity.Djlx;
2914 2928  
... ... @@ -3108,7 +3122,7 @@ LIMIT {offset}, {pageSize}&quot;;
3108 3122 }
3109 3123  
3110 3124 /// <summary>
3111   - /// 审核销售出库单(支持两级审核)。收银台「门店」、抖音「抖音订单」等外部来源无需在此审核。
  3125 + /// 审核销售出库单(支持两级审核)。仅单据来源为「后台」或未标记来源的需审;其它来源无需在此审核。
3112 3126 /// </summary>
3113 3127 /// <param name="id">销售出库单主键</param>
3114 3128 [HttpPost("ApproveSalesOutbound/{id}")]
... ... @@ -3116,7 +3130,7 @@ LIMIT {offset}, {pageSize}&quot;;
3116 3130 {
3117 3131 var header = await _db.Queryable<WtXsckdEntity>().FirstAsync(p => p.Id == id);
3118 3132 if (header != null && IsSalesOutboundSkipErpAudit(header))
3119   - return new { success = false, message = "收银台或抖音等外部来源的销售出库单无需在此审核" };
  3133 + return new { success = false, message = "非后台来源的销售出库单无需在此审核" };
3120 3134 return await ApproveDocument(id, "销售出库单", input?.remark);
3121 3135 }
3122 3136  
... ... @@ -3156,7 +3170,7 @@ LIMIT {offset}, {pageSize}&quot;;
3156 3170 return new { success = false, message = $"该单据不是{expectedDjlx},无法操作" };
3157 3171  
3158 3172 if (entity.Djlx == "销售出库单" && IsSalesOutboundSkipErpAudit(entity))
3159   - return new { success = false, message = "收银台或抖音等外部来源的销售出库单无需在此审核" };
  3173 + return new { success = false, message = "非后台来源的销售出库单无需在此审核" };
3160 3174  
3161 3175 if (entity.Djzt == "已审核")
3162 3176 return new { success = false, message = "该单据已审核通过,如需修改请使用反审" };
... ...
Antis.Erp.Plat/netcore/src/Modularity/VisualDev/NCC.VisualDev/DashboardService.cs
... ... @@ -346,12 +346,10 @@ namespace NCC.VisualDev
346 346 {
347 347 var list = new List<FlowTodoOutput>();
348 348 list.AddRange(await QueryWtXsckdAuditTodosAsync("同价调拨单", userId, userAccount, null));
349   - // 与 ApproveSalesOutbound 一致:收银台门店、抖音来源、备注「抖音订单:」开头的不进待办
  349 + // 仅单据来源为「后台」或未标记(ly 空)的销售出库单进待办;备注「抖音订单:」同后端免审规则
350 350 list.AddRange(await QueryWtXsckdAuditTodosAsync("销售出库单", userId, userAccount,
351   - @"NOT (
352   - TRIM(IFNULL(d.ly, '')) IN ('门店', '抖音订单', '抖音抓单')
353   - OR (TRIM(IFNULL(d.bz, '')) <> '' AND TRIM(d.bz) LIKE '抖音订单:%')
354   -)"));
  351 + @"( TRIM(IFNULL(d.ly, '')) = '' OR TRIM(IFNULL(d.ly, '')) = '后台' )
  352 + AND NOT ( TRIM(IFNULL(d.bz, '')) <> '' AND TRIM(d.bz) LIKE '抖音订单:%' )"));
355 353 list.AddRange(await QueryWtXsckdAuditTodosAsync("销售退货单", userId, userAccount, null));
356 354 list.AddRange(await QueryWtXsckdAuditTodosAsync("采购入库单", userId, userAccount, null));
357 355 return list.OrderByDescending(x => x.creatorTime).ToList();
... ...
Antis.Erp.Plat/sy/PACKAGE_README.md
... ... @@ -23,6 +23,7 @@ package.bat
23 23 ```
24 24  
25 25 **注意**:Windows系统需要安装以下工具之一:
  26 +
26 27 - 7-Zip(推荐)
27 28 - WinRAR
28 29  
... ... @@ -31,6 +32,7 @@ package.bat
31 32 ## 📋 打包包含的文件
32 33  
33 34 ### HTML文件
  35 +
34 36 - `login.html` - 登录页
35 37 - `home.html` - 商品列表页
36 38 - `settlement.html` - 收银台(核心功能)
... ... @@ -39,11 +41,13 @@ package.bat
39 41 - `from.html` - 其他功能页
40 42  
41 43 ### 资源目录
  44 +
42 45 - `css/` - 样式文件
43 46 - `js/` - JavaScript库(Vue.js, jQuery等)
44 47 - `images/` - 图片资源
45 48  
46 49 ### 文档文件
  50 +
47 51 - `README.md` - 项目说明
48 52 - `QUICK_START.md` - 快速开始指南
49 53 - `API_CONFIG.md` - API配置说明
... ... @@ -51,6 +55,7 @@ package.bat
51 55 - `LAUNCH_QUICK_REFERENCE.txt` - 快速参考
52 56  
53 57 ### 启动脚本
  58 +
54 59 - `start.sh` - Linux/macOS启动脚本
55 60 - `start.bat` - Windows启动脚本
56 61 - `start_3001.sh` - 指定端口启动脚本
... ... @@ -59,6 +64,7 @@ package.bat
59 64 ## 🚫 排除的文件
60 65  
61 66 以下文件**不会**被打包:
  67 +
62 68 - `*.bak` - 备份文件
63 69 - `home copy.html` - 副本文件
64 70 - `axios-1.x/` - 开发依赖(已包含在js目录中)
... ... @@ -105,6 +111,7 @@ npx http-server . -p 8888 -c-1
105 111 ### Linux/macOS (`package.sh`)
106 112  
107 113 修改以下部分:
  114 +
108 115 ```bash
109 116 # 添加要排除的文件
110 117 EXCLUDE_LIST=(
... ... @@ -117,6 +124,7 @@ EXCLUDE_LIST=(
117 124 ### Windows (`package.bat`)
118 125  
119 126 修改文件复制部分:
  127 +
120 128 ```batch
121 129 REM 添加要复制的文件或目录
122 130 copy "your_file.txt" "%TEMP_DIR%\" >nul
... ... @@ -133,22 +141,21 @@ copy &quot;your_file.txt&quot; &quot;%TEMP_DIR%\&quot; &gt;nul
133 141  
134 142 解压后检查以下文件是否存在:
135 143  
136   -- [ ] 所有HTML文件
137   -- [ ] `css/style.css`
138   -- [ ] `js/vue.min.js`
139   -- [ ] `js/jquery.min.js`
140   -- [ ] `images/` 目录下的所有图标
141   -- [ ] 启动脚本文件
  144 +- 所有HTML文件
  145 +- `css/style.css`
  146 +- `js/vue.min.js`
  147 +- `js/jquery.min.js`
  148 +- `images/` 目录下的所有图标
  149 +- 启动脚本文件
142 150  
143 151 ## 📞 技术支持
144 152  
145 153 如有问题,请检查:
  154 +
146 155 1. 打包脚本执行权限(Linux/macOS)
147 156 2. 压缩工具是否正确安装(Windows)
148 157 3. 文件路径是否正确
149 158  
150 159 ---
151 160  
152   -**最后更新**:2025-12-22
153   -
154   -
  161 +**最后更新**:2025-12-22
155 162 \ No newline at end of file
... ...