SupplierDeliveryManagementService.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. using System.Text.Json;
  2. using Admin.NET.Plugin.AiDOP.Entity.DataPlatform;
  3. using Admin.NET.Plugin.AiDOP.ProcurementExecution.Dto;
  4. namespace Admin.NET.Plugin.AiDOP.ProcurementExecution;
  5. /// <summary>
  6. /// S4 供应商交货管理
  7. ///
  8. /// 【租户安全边界】租户一律经 <see cref="AidopTenantScope.ResolveOrThrow"/> 从认证后 JWT 解析,
  9. /// 无有效租户即拒绝,不读前端 tenantId、无默认回退。
  10. /// <para>
  11. /// 原实现:类级 <c>[AllowAnonymous]</c> + 全类 <c>AidopTenantHelper.Resolve(App.HttpContext)</c>。
  12. /// 后者解析顺序为 requestTenantId &gt; JWT claim &gt; <b>query 参数 tenantId</b> &gt; <b>DefaultTenantId 兜底</b>,
  13. /// 其自身注释即写明「不得用于业务数据的查询与写入」。两者叠加的实测后果:匿名(无 Token、无 Cookie)
  14. /// <c>GET /api/ProcurementExecution/supplier-delivery/list?tenantId=&lt;任意租户&gt;</c> 返回该租户业务数据
  15. /// (797 返回 94 条、UAT 返回 7 条、不传参数则落默认租户);同类的 4 个 HttpPost 写接口走同一条解析链。
  16. /// </para>
  17. /// </summary>
  18. [ApiDescriptionSettings(Order = 320, Description = "S4供应商交货管理")]
  19. [Route("api/ProcurementExecution")]
  20. [NonUnify]
  21. public class SupplierDeliveryManagementService : IDynamicApiController, ITransient
  22. {
  23. private readonly ISqlSugarClient _db;
  24. private readonly UserManager _userManager;
  25. public SupplierDeliveryManagementService(ISqlSugarClient db, UserManager userManager)
  26. {
  27. _db = db;
  28. _userManager = userManager;
  29. }
  30. [DisplayName("供应商交货管理列表")]
  31. [HttpGet("supplier-delivery/list")]
  32. public async Task<object> GetList([FromQuery] SupplierDeliveryListInput input)
  33. {
  34. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  35. var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
  36. var conditions = new List<string>();
  37. if (!string.IsNullOrWhiteSpace(input.Cgdd))
  38. {
  39. conditions.Add("v.cgdd LIKE @cgdd");
  40. pars.Add(new SugarParameter("@cgdd", $"%{input.Cgdd.Trim()}%"));
  41. }
  42. if (!string.IsNullOrWhiteSpace(input.DsNum))
  43. {
  44. conditions.Add("v.dsnum LIKE @dsnum");
  45. pars.Add(new SugarParameter("@dsnum", $"%{input.DsNum.Trim()}%"));
  46. }
  47. if (!string.IsNullOrWhiteSpace(input.Wlbm))
  48. {
  49. conditions.Add("v.wlbm LIKE @wlbm");
  50. pars.Add(new SugarParameter("@wlbm", $"%{input.Wlbm.Trim()}%"));
  51. }
  52. if (!string.IsNullOrWhiteSpace(input.Gys))
  53. {
  54. conditions.Add("(v.gysdm LIKE @gys OR v.gysmc LIKE @gys)");
  55. pars.Add(new SugarParameter("@gys", $"%{input.Gys.Trim()}%"));
  56. }
  57. var where = conditions.Count > 0 ? $" WHERE {string.Join(" AND ", conditions)} " : string.Empty;
  58. var orderBy = BuildOrderBy(input.SortField, input.SortOrder);
  59. var offset = (input.Page - 1) * input.PageSize;
  60. var wrapped = $"{BuildBaseSql()} {where}";
  61. var total = await _db.Ado.GetIntAsync($"SELECT COUNT(*) FROM ({wrapped}) t", pars);
  62. var list = await _db.Ado.SqlQueryAsync<SupplierDeliveryListRow>(
  63. $"SELECT * FROM ({wrapped}) t {orderBy} LIMIT {input.PageSize} OFFSET {offset}", pars);
  64. return new { total, page = input.Page, pageSize = input.PageSize, list };
  65. }
  66. [DisplayName("供应商交货管理发布")]
  67. [HttpPost("supplier-delivery/publish")]
  68. public async Task<object> Publish([FromBody] SupplierDeliveryBatchInput input)
  69. {
  70. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  71. var userId = _userManager.UserId.ToString();
  72. var userName = _userManager.Account ?? "system";
  73. var sql = """
  74. INSERT INTO `scm_jhjh_jq`
  75. (
  76. `id`,
  77. `glid1`,
  78. `wlbm`, `wlms`, `wlgg`, `cgdd`,
  79. `jhdsl`, `wjhsl`, `jhd`, `yjjhrq`, `jqhf`,
  80. `type`, `flag`, `scrq`, `scrid`, `scrxm`,
  81. `gysdm`, `gysmc`,
  82. `hfrid`, `hfrxm`, `hfsj`,
  83. `qhdj`, `ddhh`, `dw`, `bzsl`, `ly`
  84. )
  85. SELECT
  86. UUID() AS id,
  87. ds.id AS glid1,
  88. ds.itemnum AS wlbm,
  89. im.Descr AS wlms,
  90. im.Descr1 AS wlgg,
  91. ds.ponumber AS cgdd,
  92. ds.schedqty AS jhdsl,
  93. a.wjhsl AS wjhsl,
  94. ds.dsnum AS jhd,
  95. a.yjjhrq AS yjjhrq,
  96. DATE_FORMAT(DATE(a.yjjhrq), '%Y-%m-%d') AS jqhf,
  97. a.`type` AS `type`,
  98. 2 AS flag,
  99. a.scrq AS scrq,
  100. a.scrid AS scrid,
  101. a.scrxm AS scrxm,
  102. a.gysdm AS gysdm,
  103. a.gysmc AS gysmc,
  104. @hfrid AS hfrid,
  105. @hfrxm AS hfrxm,
  106. DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') AS hfsj,
  107. a.qhdj AS qhdj,
  108. a.ddhh AS ddhh,
  109. a.dw AS dw,
  110. a.bzsl AS bzsl,
  111. a.ly AS ly
  112. FROM srm_polist_ds ds
  113. LEFT JOIN ItemMaster im
  114. ON ds.itemnum = im.ItemNum
  115. AND im.tenant_id = @TenantId
  116. LEFT JOIN vscm_jhjh a
  117. ON a.cgdd = ds.ponumber
  118. AND a.ddhh = ds.poline
  119. WHERE FIND_IN_SET(CAST(ds.id AS CHAR(50)), REPLACE(IFNULL(@ids, ''), ' ', '')) > 0
  120. AND ds.tenant_id = @TenantId
  121. AND NOT EXISTS (
  122. SELECT 1 FROM scm_jhjh_jq x
  123. WHERE x.glid1 = ds.id
  124. AND FIND_IN_SET(CAST(x.glid1 AS CHAR(50)), REPLACE(IFNULL(@ids, ''), ' ', '')) > 0
  125. );
  126. """;
  127. await _db.Ado.ExecuteCommandAsync(sql, new List<SugarParameter>
  128. {
  129. new("@ids", input.Ids),
  130. new("@hfrid", userId),
  131. new("@hfrxm", userName),
  132. new("@TenantId", tenantId)
  133. });
  134. return new { message = "发布成功" };
  135. }
  136. [DisplayName("供应商交货管理按计划日期回复")]
  137. [HttpPost("supplier-delivery/reply-by-plan-date")]
  138. public async Task<object> ReplyByPlanDate([FromBody] SupplierDeliveryBatchInput input)
  139. {
  140. if (string.IsNullOrWhiteSpace(input.Ids))
  141. throw Oops.Oh("缺少勾选行ID(ids)");
  142. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  143. var userId = _userManager.UserId.ToString();
  144. var userName = _userManager.Account ?? "system";
  145. // 列表勾选 id 为 srm_polist_ds.id,须以交货计划表驱动(与发布一致),不能从 vscm_jhjh 驱动否则匹配不到行。
  146. var sql = """
  147. INSERT INTO `scm_jhjh_jq`
  148. (
  149. `id`, `glid`, `wlbm`, `wlms`, `wlgg`, `cgdd`, `jhdsl`, `wjhsl`,
  150. `jhd`, `yjjhrq`, `jqhf`, `type`, `flag`,
  151. `scrq`, `scrid`, `scrxm`,
  152. `gysdm`, `gysmc`,
  153. `hfrid`, `hfrxm`, `hfsj`,
  154. `qhdj`, `ddhh`, `dw`, `bzsl`, `ly`
  155. )
  156. SELECT
  157. UUID() AS id,
  158. ds.id AS glid,
  159. ds.itemnum AS wlbm,
  160. im.Descr AS wlms,
  161. im.Descr1 AS wlgg,
  162. ds.ponumber AS cgdd,
  163. CAST(ds.schedqty AS CHAR(50)) AS jhdsl,
  164. CAST(IFNULL(a.wjhsl, 0) AS CHAR(50)) AS wjhsl,
  165. ds.dsnum AS jhd,
  166. CAST(IFNULL(a.yjjhrq, ds.requestDate) AS CHAR(50)) AS yjjhrq,
  167. DATE_FORMAT(DATE(IFNULL(a.yjjhrq, ds.requestDate)), '%Y-%m-%d') AS jqhf,
  168. a.`type` AS `type`,
  169. 0 AS flag,
  170. a.scrq AS scrq,
  171. a.scrid AS scrid,
  172. a.scrxm AS scrxm,
  173. IFNULL(a.gysdm, ds.suppliercode) AS gysdm,
  174. IFNULL(a.gysmc, ds.supplier) AS gysmc,
  175. @userid AS hfrid,
  176. @username AS hfrxm,
  177. DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') AS hfsj,
  178. a.qhdj AS qhdj,
  179. ds.poline AS ddhh,
  180. a.dw AS dw,
  181. a.bzsl AS bzsl,
  182. a.ly AS ly
  183. FROM srm_polist_ds ds
  184. LEFT JOIN ItemMaster im
  185. ON ds.itemnum = im.ItemNum
  186. AND im.tenant_id = @TenantId
  187. LEFT JOIN vscm_jhjh a
  188. ON a.cgdd = ds.ponumber
  189. AND a.ddhh = ds.poline
  190. WHERE FIND_IN_SET(CAST(ds.id AS CHAR(50)), REPLACE(IFNULL(@ids, ''), ' ', '')) > 0
  191. AND ds.isactive = 1
  192. AND ds.status = 'P'
  193. AND ds.tenant_id = @TenantId;
  194. """;
  195. var affected = await _db.Ado.ExecuteCommandAsync(sql, new List<SugarParameter>
  196. {
  197. new("@ids", input.Ids),
  198. new("@userid", userId),
  199. new("@username", userName),
  200. new("@TenantId", tenantId),
  201. });
  202. if (affected <= 0)
  203. throw Oops.Oh("未插入任何回复记录。请确认勾选的是本列表中的交货计划行,且交货单 status=P、isactive=1。");
  204. return new { message = "按计划日期回复成功" };
  205. }
  206. [DisplayName("供应商交货管理回复交期")]
  207. [HttpPost("supplier-delivery/reply-due-date")]
  208. public async Task<object> ReplyDueDate([FromBody] SupplierDeliveryReplyDueDateInput input)
  209. {
  210. if (string.IsNullOrWhiteSpace(input.Ids))
  211. throw Oops.Oh("缺少勾选行ID(ids)");
  212. if (string.IsNullOrWhiteSpace(input.Jqhf))
  213. throw Oops.Oh("缺少交期回复日期(jqhf)");
  214. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  215. var userId = _userManager.UserId.ToString();
  216. var userName = _userManager.Account ?? "system";
  217. // 列表勾选 id 为 srm_polist_ds.id,须以交货计划表驱动(与发布一致)。
  218. var sql = """
  219. INSERT INTO `scm_jhjh_jq`
  220. (
  221. `id`,
  222. `glid`, `wlbm`, `wlms`, `wlgg`, `cgdd`,
  223. `jhdsl`, `wjhsl`, `jhd`, `yjjhrq`, `jqhf`,
  224. `type`, `flag`,
  225. `scrq`, `scrid`, `scrxm`,
  226. `gysdm`, `gysmc`,
  227. `hfrid`, `hfrxm`, `hfsj`,
  228. `qhdj`, `ddhh`, `dw`, `bzsl`, `ly`
  229. )
  230. SELECT
  231. UUID() AS id,
  232. ds.id AS glid,
  233. ds.itemnum AS wlbm,
  234. im.Descr AS wlms,
  235. im.Descr1 AS wlgg,
  236. ds.ponumber AS cgdd,
  237. CAST(ds.schedqty AS CHAR(50)) AS jhdsl,
  238. CAST(IFNULL(a.wjhsl, 0) AS CHAR(50)) AS wjhsl,
  239. ds.dsnum AS jhd,
  240. CAST(IFNULL(a.yjjhrq, ds.requestDate) AS CHAR(50)) AS yjjhrq,
  241. @jqhf AS jqhf,
  242. a.`type` AS `type`,
  243. 0 AS flag,
  244. a.scrq AS scrq,
  245. a.scrid AS scrid,
  246. a.scrxm AS scrxm,
  247. IFNULL(a.gysdm, ds.suppliercode) AS gysdm,
  248. IFNULL(a.gysmc, ds.supplier) AS gysmc,
  249. @userid AS hfrid,
  250. @username AS hfrxm,
  251. DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') AS hfsj,
  252. a.qhdj AS qhdj,
  253. ds.poline AS ddhh,
  254. a.dw AS dw,
  255. a.bzsl AS bzsl,
  256. a.ly AS ly
  257. FROM srm_polist_ds ds
  258. LEFT JOIN ItemMaster im
  259. ON ds.itemnum = im.ItemNum
  260. AND im.tenant_id = @TenantId
  261. LEFT JOIN vscm_jhjh a
  262. ON a.cgdd = ds.ponumber
  263. AND a.ddhh = ds.poline
  264. WHERE FIND_IN_SET(CAST(ds.id AS CHAR(50)), REPLACE(IFNULL(@ids, ''), ' ', '')) > 0
  265. AND ds.isactive = 1
  266. AND ds.status = 'P'
  267. AND ds.tenant_id = @TenantId;
  268. """;
  269. var affected = await _db.Ado.ExecuteCommandAsync(sql, new List<SugarParameter>
  270. {
  271. new("@ids", input.Ids),
  272. new("@jqhf", input.Jqhf.Trim()),
  273. new("@userid", userId),
  274. new("@username", userName),
  275. new("@TenantId", tenantId),
  276. });
  277. if (affected <= 0)
  278. throw Oops.Oh("未插入任何回复记录。请确认勾选的是本列表中的交货计划行,且交货单 status=P、isactive=1。");
  279. return new { message = "回复交期成功" };
  280. }
  281. [DisplayName("交货单关闭")]
  282. [HttpPost("supplier-delivery/close")]
  283. public async Task<object> CloseDelivery([FromBody] DeliveryCloseInput input)
  284. {
  285. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  286. // 检查是否已有关联的发货单明细(scm_shdzb.jhdbh = 交货单号)
  287. var shipmentCount = await _db.Ado.GetIntAsync(
  288. """
  289. SELECT COUNT(*)
  290. FROM scm_shdzb d
  291. INNER JOIN scm_shd m ON CAST(m.id AS CHAR) = d.glid
  292. WHERE d.jhdbh = @jhdbh
  293. AND m.tenant_id = @TenantId
  294. AND IFNULL(m.state, 1) <> 0
  295. """,
  296. new List<SugarParameter> { new("@jhdbh", input.DsNum), new("@TenantId", tenantId) });
  297. if (shipmentCount > 0)
  298. throw Oops.Oh("此发货单还未收完货,无法关闭交货单");
  299. await _db.Ado.ExecuteCommandAsync(
  300. "UPDATE srm_polist_ds SET status='C' WHERE DSNum=@jhdbh AND tenant_id=@TenantId",
  301. new List<SugarParameter> { new("@jhdbh", input.DsNum), new("@TenantId", tenantId) });
  302. await TryEnqueueReceiptConfirmOutboxAsync(tenantId, input.DsNum);
  303. return new { message = "交货单关闭成功" };
  304. }
  305. /// <summary>交货关闭视为收货确认信号,写 Outbox(幂等)。</summary>
  306. private async Task TryEnqueueReceiptConfirmOutboxAsync(long tenantId, string dsNum)
  307. {
  308. try
  309. {
  310. if (string.IsNullOrWhiteSpace(dsNum)) return;
  311. var payload = JsonSerializer.Serialize(new
  312. {
  313. path = "/erp/receipt/confirm",
  314. method = "POST",
  315. body = new
  316. {
  317. dsNum,
  318. status = "C",
  319. action = "S4_RECEIPT_CONFIRM"
  320. }
  321. });
  322. var exists = await _db.Ado.GetIntAsync(
  323. "SELECT COUNT(1) FROM mdp_outbox WHERE tenant_id=@tid AND target_source_code='WMS_API' AND action_code='S4_RECEIPT_CONFIRM' AND idem_key=@idem",
  324. new List<SugarParameter> { new("@tid", tenantId), new("@idem", dsNum) }) > 0;
  325. if (exists) return;
  326. await _db.Insertable(new MdpOutbox
  327. {
  328. TenantId = tenantId,
  329. TargetSourceCode = "WMS_API",
  330. ActionCode = "S4_RECEIPT_CONFIRM",
  331. IdemKey = dsNum,
  332. PayloadJson = payload,
  333. Status = 0,
  334. RetryCount = 0,
  335. CreateTime = DateTime.Now,
  336. UpdateTime = DateTime.Now
  337. }).ExecuteCommandAsync();
  338. }
  339. catch { /* Outbox 失败不影响关闭 */ }
  340. }
  341. private static string BuildOrderBy(string? sortField, string? sortOrder)
  342. {
  343. var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
  344. {
  345. ["sffb"] = "t.sffb",
  346. ["wlbm"] = "t.wlbm",
  347. ["wlms"] = "t.wlms",
  348. ["buyer"] = "t.buyer",
  349. ["gysdm"] = "t.gysdm",
  350. ["gysmc"] = "t.gysmc",
  351. ["cgdd"] = "t.cgdd",
  352. ["ddhh"] = "t.ddhh",
  353. ["jhdsl"] = "t.jhdsl",
  354. ["dfhsl"] = "t.dfhsl",
  355. ["dsnum"] = "t.dsnum",
  356. ["requestdate"] = "t.requestdate",
  357. ["schedqty"] = "t.schedqty",
  358. ["jqhfnew"] = "t.jqhfnew",
  359. ["ztsl"] = "t.ztsl",
  360. ["zsl1"] = "t.zsl1",
  361. ["rksl"] = "t.rksl",
  362. ["bhgsl"] = "t.bhgsl",
  363. ["thsl"] = "t.thsl",
  364. ["bz"] = "t.bz"
  365. };
  366. var field = map.TryGetValue(sortField ?? string.Empty, out var sqlField) ? sqlField : "t.requestdate";
  367. var order = string.Equals(sortOrder, "asc", StringComparison.OrdinalIgnoreCase) ? "ASC" : "DESC";
  368. return $" ORDER BY {field} {order} ";
  369. }
  370. private static string BuildBaseSql() => """
  371. SELECT
  372. v.*,
  373. CASE
  374. WHEN v.jhdsl - IFNULL(v.zfhl, 0) + IFNULL(v.thsl, 0) > v.wjhsl THEN v.wjhsl
  375. WHEN v.jhdsl - IFNULL(v.zfhl, 0) + IFNULL(v.thsl, 0) < 0 THEN 0
  376. ELSE v.jhdsl - IFNULL(v.zfhl, 0) + IFNULL(v.thsl, 0)
  377. END AS dfhsl,
  378. CASE
  379. WHEN IFNULL(v.zsl18, 0) - IFNULL(v.thsl, 0) <= IFNULL(v.zshl, 0) THEN 0
  380. ELSE IFNULL(v.zsl18, 0) - IFNULL(v.thsl, 0) - IFNULL(v.zshl, 0)
  381. END AS ztsl,
  382. IFNULL(v.zsl, 0) AS zsl1,
  383. v.thsl AS bhgsl,
  384. CONCAT(
  385. CASE
  386. WHEN v.sfyqnew = 'wait' OR v.sfyqnew = 'NO' THEN 'jqhfnew:yellow'
  387. WHEN v.sfyqnew = 'refuse' THEN 'jqhfnew:red'
  388. WHEN v.sfyqnew = 'OK' THEN 'jqhfnew:#99FF00'
  389. ELSE ''
  390. END,
  391. v.sffbgrdnew
  392. ) AS background,
  393. CASE
  394. WHEN v.jhdsl - IFNULL(v.zfhl, 0) + IFNULL(v.thsl, 0) <= 0 THEN '完成'
  395. ELSE '待交'
  396. END AS yjzt
  397. FROM
  398. (
  399. SELECT
  400. p.PurOrd,
  401. p.Line,
  402. p.ItemNum,
  403. s.fhsl - IFNULL(dor.thsl, 0) AS zfhl,
  404. p.ReceiptQty + p.RctQty AS zshl,
  405. i.zjsl AS zsl,
  406. CASE WHEN p.PurOrd LIKE 'DO%' THEN p.RctQty ELSE p.RctQty - IFNULL(i.zjsl, 0) END AS rksl,
  407. CASE
  408. WHEN p.PurOrd LIKE 'DO%' THEN IF(p.QtyReturned > 0, p.QtyReturned, dor.thsl)
  409. ELSE IF(p.QtyReturned > 0, p.QtyReturned, p.QtyReturned + dor.thsl)
  410. END AS thsl,
  411. s.fhsl AS zsl18,
  412. sh.jhdyj,
  413. jy.jhdzj,
  414. IFNULL(ds.SchedQty, 0) - IFNULL(sh.jhdyj, 0) AS jhddj,
  415. p.QtyOrded - p.RctQty - p.ReceiptQty + p.QtyReturned AS wjhsl,
  416. p.QtyOrded AS jhdsl,
  417. ds.SchedQty,
  418. ds.DSNum,
  419. CASE WHEN b2.id IS NULL THEN 'X' ELSE b2.hfsj END AS sffb,
  420. p.ItemNum AS wlbm,
  421. im.Descr AS wlms,
  422. ds.supplier AS gysmc,
  423. p.PurOrd AS cgdd,
  424. p.Line AS ddhh,
  425. pm.Buyer AS buyer,
  426. IFNULL(ds.requestDate, p.DueDate) AS requestdate,
  427. IFNULL(b.jqhf, '') AS jqhfnew,
  428. IFNULL(b.fpjh, '') AS fpjhnew,
  429. ds.SentQty,
  430. IFNULL(im.Drawing, p.Drawing) AS th,
  431. IFNULL(im.Rev, p.Rev) AS bbh,
  432. CAST(ds.id AS CHAR) AS id,
  433. '' AS jhd,
  434. ds.suppliercode AS gysdm,
  435. CASE WHEN IFNULL(ds.id, '') = '' THEN p.Remarks ELSE ds.Remarks END AS bz,
  436. '' AS shd,
  437. ds.id AS jhdid,
  438. p.DueDate AS jhrq,
  439. p.RecID AS polid,
  440. im.Descr1 AS wlgg,
  441. CASE WHEN b2.id IS NULL THEN '' ELSE ';sffb:#99FF00' END AS sffbgrdnew,
  442. CASE
  443. WHEN IFNULL(b.jqhf, '') = '' THEN 'wait'
  444. WHEN TIMESTAMPDIFF(DAY, IFNULL(ds.requestDate, p.DueDate), b.jqhf) <= 2 THEN 'OK'
  445. WHEN TIMESTAMPDIFF(DAY, IFNULL(ds.requestDate, p.DueDate), b.jqhf) > 2 THEN 'NO'
  446. WHEN b.jqhf = '' AND IFNULL(b.qhdj, '') <> '' THEN 'refuse'
  447. ELSE 'wait'
  448. END AS sfyqnew
  449. FROM PurOrdDetail p
  450. LEFT JOIN PurOrdMaster pm ON p.PurOrd = pm.PurOrd AND pm.tenant_id = p.tenant_id
  451. LEFT JOIN (
  452. SELECT SUM(sh_delivery_quantity) AS fhsl, po_bill, po_billline, tenant_id
  453. FROM scm_shdzb
  454. WHERE tenant_id = @TenantId
  455. GROUP BY po_bill, po_billline, tenant_id
  456. ) s ON s.po_bill = p.PurOrd AND s.po_billline = p.Line
  457. LEFT JOIN (
  458. SELECT SUM(Qty) AS zjsl, PurOrd, PurLine, tenant_id
  459. FROM MissedPrint
  460. WHERE Status = 'I' AND tenant_id = @TenantId
  461. GROUP BY PurOrd, PurLine, tenant_id
  462. ) i ON i.PurOrd = p.PurOrd AND i.PurLine = p.Line
  463. LEFT JOIN (
  464. SELECT SUM(QtyReturn) AS thsl, OrdNbr, OrdLine, tenant_id
  465. FROM PurOrdRctDetail
  466. WHERE rcttype IN ('pt', 'temp') AND tenant_id = @TenantId
  467. GROUP BY OrdNbr, OrdLine, tenant_id
  468. ) dor ON dor.OrdNbr = p.PurOrd AND dor.OrdLine = p.Line
  469. LEFT JOIN srm_polist_ds ds ON p.PurOrd = ds.ponumber AND p.Line = ds.poline AND ds.tenant_id = p.tenant_id
  470. LEFT JOIN (
  471. SELECT SUM(sh_delivery_quantity) AS jhdyj, jhdbh, tenant_id
  472. FROM scm_shdzb
  473. WHERE tenant_id = @TenantId
  474. GROUP BY jhdbh, tenant_id
  475. ) sh ON ds.dsnum = sh.jhdbh
  476. LEFT JOIN (
  477. SELECT SUM(IFNULL(Qty, 0)) AS jhdzj, PurOrdDetBatchNbr, tenant_id
  478. FROM MissedPrint
  479. WHERE Status = 'I' AND tenant_id = @TenantId
  480. GROUP BY PurOrdDetBatchNbr, tenant_id
  481. ) jy ON ds.dsnum = jy.PurOrdDetBatchNbr
  482. LEFT JOIN (
  483. SELECT glid1, MIN(id) AS id, MIN(DATE_FORMAT(hfsj, '%Y.%m.%d')) AS hfsj
  484. FROM scm_jhjh_jq
  485. WHERE flag = 2
  486. GROUP BY glid1
  487. ) b2 ON ds.id = b2.glid1
  488. LEFT JOIN ItemMaster im ON p.ItemNum = im.ItemNum AND (im.tenant_id = p.tenant_id OR p.tenant_id IS NULL)
  489. LEFT JOIN (
  490. SELECT
  491. glid,
  492. GROUP_CONCAT(CONCAT(CAST(jhdsl AS CHAR(10)), '(', DATE_FORMAT(jqhf, '%Y-%m-%d'), ')') SEPARATOR '<br>') AS fpjh,
  493. GROUP_CONCAT(qhdj SEPARATOR '') AS qhdj,
  494. MAX(jqhf) AS jqhf
  495. FROM scm_jhjh_jq
  496. WHERE flag = 0
  497. GROUP BY glid
  498. ) b ON ds.id = b.glid
  499. WHERE p.Status <> 'C'
  500. AND ds.schedqty >= 0
  501. AND ds.isactive = 1
  502. AND ds.status = 'P'
  503. AND p.tenant_id = @TenantId
  504. ) v
  505. """;
  506. private sealed class SupplierDeliveryListRow
  507. {
  508. public string? Sffb { get; set; }
  509. public string? Wlbm { get; set; }
  510. public string? Wlms { get; set; }
  511. public string? Buyer { get; set; }
  512. public string? Gysdm { get; set; }
  513. public string? Gysmc { get; set; }
  514. public string? Cgdd { get; set; }
  515. public int? Ddhh { get; set; }
  516. public decimal? Jhdsl { get; set; }
  517. public decimal? Dfhsl { get; set; }
  518. public string? Dsnum { get; set; }
  519. public DateTime? Requestdate { get; set; }
  520. public decimal? Schedqty { get; set; }
  521. public string? Jqhfnew { get; set; }
  522. public decimal? Ztsl { get; set; }
  523. public decimal? Zsl1 { get; set; }
  524. public decimal? Rksl { get; set; }
  525. public decimal? Bhgsl { get; set; }
  526. public decimal? Thsl { get; set; }
  527. public string? Bz { get; set; }
  528. public string? Id { get; set; }
  529. public decimal? Wjhsl { get; set; }
  530. public decimal? Zfhl { get; set; }
  531. }
  532. }