SupplierShipmentService.cs 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129
  1. using Admin.NET.Plugin.AiDOP.ProcurementExecution.Dto;
  2. using Admin.NET.Plugin.AiDOP.ProcurementExecution.Entity;
  3. using Yitter.IdGenerator;
  4. namespace Admin.NET.Plugin.AiDOP.ProcurementExecution;
  5. /// <summary>
  6. /// S4 供应商发货单(列表 + 表单)
  7. /// </summary>
  8. [ApiDescriptionSettings(Order = 321, Description = "S4供应商发货单")]
  9. [Route("api/ProcurementExecution")]
  10. [AllowAnonymous]
  11. [NonUnify]
  12. public class SupplierShipmentService : IDynamicApiController, ITransient
  13. {
  14. private readonly ISqlSugarClient _db;
  15. private readonly SqlSugarRepository<ScmShd> _masterRep;
  16. private readonly SqlSugarRepository<ScmShdzb> _detailRep;
  17. private readonly UserManager _userManager;
  18. private const int ShpcSerialWidth = 3; // yyMMdd + 3位流水:260508001
  19. private const int LabelXhStart = 10001;
  20. public SupplierShipmentService(
  21. ISqlSugarClient db,
  22. SqlSugarRepository<ScmShd> masterRep,
  23. SqlSugarRepository<ScmShdzb> detailRep,
  24. UserManager userManager)
  25. {
  26. _db = db;
  27. _masterRep = masterRep;
  28. _detailRep = detailRep;
  29. _userManager = userManager;
  30. }
  31. [DisplayName("供应商发货单列表")]
  32. [HttpGet("supplier-shipment/list")]
  33. public async Task<object> GetList([FromQuery] SupplierShipmentListInput input)
  34. {
  35. var pars = new List<SugarParameter>();
  36. var conditions = new List<string> { "IFNULL(m.state, 1) <> 0" };
  37. if (!string.IsNullOrWhiteSpace(input.JhshrqFrom))
  38. {
  39. conditions.Add("m.jhshrq >= @jhshrqFrom");
  40. pars.Add(new SugarParameter("@jhshrqFrom", input.JhshrqFrom.Trim()));
  41. }
  42. if (!string.IsNullOrWhiteSpace(input.Gysmc))
  43. {
  44. conditions.Add("m.sh_purchase_name LIKE @gysmc");
  45. pars.Add(new SugarParameter("@gysmc", $"%{input.Gysmc.Trim()}%"));
  46. }
  47. if (!string.IsNullOrWhiteSpace(input.Shddh))
  48. {
  49. conditions.Add("m.shddh LIKE @shddh");
  50. pars.Add(new SugarParameter("@shddh", $"%{input.Shddh.Trim()}%"));
  51. }
  52. if (!string.IsNullOrWhiteSpace(input.Wldh))
  53. {
  54. conditions.Add("m.wldh LIKE @wldh");
  55. pars.Add(new SugarParameter("@wldh", $"%{input.Wldh.Trim()}%"));
  56. }
  57. if (!string.IsNullOrWhiteSpace(input.PoBill))
  58. {
  59. conditions.Add("m.po_bill LIKE @poBill");
  60. pars.Add(new SugarParameter("@poBill", $"%{input.PoBill.Trim()}%"));
  61. }
  62. if (!string.IsNullOrWhiteSpace(input.ShMaterialCode))
  63. {
  64. conditions.Add("m.sh_material_code LIKE @shMaterialCode");
  65. pars.Add(new SugarParameter("@shMaterialCode", $"%{input.ShMaterialCode.Trim()}%"));
  66. }
  67. if (!string.IsNullOrWhiteSpace(input.Shzt))
  68. {
  69. conditions.Add("m.shzt = @shzt");
  70. pars.Add(new SugarParameter("@shzt", input.Shzt.Trim()));
  71. }
  72. if (!string.IsNullOrWhiteSpace(input.Shpc))
  73. {
  74. conditions.Add("m.shpc LIKE @shpc");
  75. pars.Add(new SugarParameter("@shpc", $"%{input.Shpc.Trim()}%"));
  76. }
  77. var where = $" WHERE {string.Join(" AND ", conditions)} ";
  78. var orderBy = BuildListOrderBy(input.SortField, input.SortOrder);
  79. var offset = (input.Page - 1) * input.PageSize;
  80. var wrapped = $"{BuildListSql()} {where}";
  81. var total = await _db.Ado.GetIntAsync($"SELECT COUNT(*) FROM ({wrapped}) t", pars);
  82. var list = await _db.Ado.SqlQueryAsync<SupplierShipmentListRow>(
  83. $"SELECT * FROM ({wrapped}) t {orderBy} LIMIT {input.PageSize} OFFSET {offset}", pars);
  84. return new { total, page = input.Page, pageSize = input.PageSize, list };
  85. }
  86. [DisplayName("获取发货单详情")]
  87. [HttpGet("supplier-shipment/{id:long}")]
  88. public async Task<object> GetDetail(long id)
  89. {
  90. var master = await _masterRep.GetFirstAsync(x => x.Id == id) ?? throw Oops.Oh("发货单不存在");
  91. var details = await _detailRep.AsQueryable().Where(x => x.Glid == id.ToString()).OrderBy(x => x.Hh).ToListAsync();
  92. return new
  93. {
  94. id = master.Id,
  95. shddh = master.Shddh,
  96. jhshrq = master.Jhshrq,
  97. wlsc = master.Wlsc,
  98. yjdhrq = master.Yjdhrq,
  99. shPurchaseName = master.ShPurchaseName,
  100. shPurchaseNum = master.ShPurchaseNum,
  101. wldh = master.Wldh,
  102. sfpc = master.Sfpc ?? 0,
  103. chbg = master.Chbg,
  104. pcsm = master.Pcsm,
  105. state = master.State ?? 1,
  106. details = details.Select(d => new
  107. {
  108. id = d.Id,
  109. hh = d.Hh,
  110. poBill = d.PoBill,
  111. poBillLine = d.PoBillLine,
  112. orderType = d.OrderType,
  113. shMaterialCode = d.ShMaterialCode,
  114. shMaterialName = d.ShMaterialName,
  115. th = d.Th,
  116. shDeliveryQuantity = d.ShDeliveryQuantity,
  117. bzsl = d.Bzsl,
  118. bqsl = d.Bqsl,
  119. shMaterialDw = d.ShMaterialDw,
  120. scrq = d.Scrq,
  121. scph = d.Scph,
  122. remarks = d.Remarks,
  123. djsl = d.Djsl,
  124. jybb = d.Jybb,
  125. jhdbh = d.Jhdbh
  126. })
  127. };
  128. }
  129. [DisplayName("发货单新增草稿")]
  130. [HttpGet("supplier-shipment/create-draft")]
  131. public async Task<object> GetCreateDraft([FromQuery] string ids)
  132. {
  133. var pars = new List<SugarParameter> { new("@ids", ids) };
  134. var rows = await _db.Ado.SqlQueryAsync<SupplierShipmentDraftRow>(
  135. """
  136. SELECT
  137. CAST(IFNULL(ds.id, p.RecID) AS CHAR(50)) AS sourceId,
  138. ds.suppliercode AS gysdm,
  139. ds.supplier AS gysmc,
  140. p.PurOrd AS poBill,
  141. p.Line AS poBillLine,
  142. p.Potype AS orderType,
  143. p.ItemNum AS shMaterialCode,
  144. im.Descr AS shMaterialName,
  145. IFNULL(im.Drawing, p.Drawing) AS th,
  146. IFNULL(ds.SchedQty, p.QtyOrded - p.RctQty - p.ReceiptQty + p.QtyReturned) AS shDeliveryQuantity,
  147. p.StdPackQty AS bzsl,
  148. p.UM AS shMaterialDw,
  149. (p.QtyOrded - p.RctQty - p.ReceiptQty + p.QtyReturned) AS djsl,
  150. ds.DSNum AS jhdbh,
  151. im.Descr1 AS shMaterialGgxh
  152. FROM PurOrdDetail p
  153. LEFT JOIN srm_polist_ds ds ON p.PurOrd = ds.ponumber AND p.Line = ds.poline
  154. LEFT JOIN ItemMaster im ON p.ItemNum = im.ItemNum
  155. WHERE FIND_IN_SET(CAST(IFNULL(ds.id, p.RecID) AS CHAR(50)), REPLACE(IFNULL(@ids, ''), ' ', '')) > 0
  156. ORDER BY p.PurOrd, p.Line
  157. """, pars);
  158. if (rows.Count == 0)
  159. throw Oops.Oh("未找到可生成的交货明细");
  160. return new
  161. {
  162. shddh = string.Empty,
  163. jhshrq = DateTime.Now.ToString("yyyy-MM-dd"),
  164. wlsc = string.Empty,
  165. yjdhrq = string.Empty,
  166. shPurchaseName = rows[0].Gysmc,
  167. shPurchaseNum = rows[0].Gysdm,
  168. wldh = string.Empty,
  169. sfpc = 0,
  170. chbg = string.Empty,
  171. pcsm = string.Empty,
  172. details = rows.Select((r, i) => new
  173. {
  174. id = (long?)null,
  175. hh = i + 1,
  176. poBill = r.PoBill,
  177. poBillLine = r.PoBillLine?.ToString(),
  178. orderType = r.OrderType,
  179. shMaterialCode = r.ShMaterialCode,
  180. shMaterialName = r.ShMaterialName,
  181. th = r.Th,
  182. shDeliveryQuantity = r.ShDeliveryQuantity,
  183. bzsl = r.Bzsl,
  184. bqsl = 0,
  185. shMaterialDw = r.ShMaterialDw,
  186. scrq = string.Empty,
  187. scph = string.Empty,
  188. remarks = string.Empty,
  189. djsl = r.Djsl,
  190. jybb = string.Empty,
  191. jhdbh = r.Jhdbh
  192. })
  193. };
  194. }
  195. [DisplayName("保存发货单")]
  196. [ApiDescriptionSettings(Name = "SaveSupplierShipment"), HttpPost("supplier-shipment/save")]
  197. public async Task<object> Save([FromBody] SupplierShipmentSaveInput input)
  198. {
  199. var now = DateTime.Now;
  200. var userId = _userManager.UserId.ToString();
  201. var userName = _userManager.Account ?? "system";
  202. var shipDate = string.IsNullOrWhiteSpace(input.Jhshrq) ? now.ToString("yyyy-MM-dd") : input.Jhshrq!.Trim();
  203. if (input.Id is null or 0)
  204. {
  205. var newId = YitIdHelper.NextId();
  206. var entity = new ScmShd
  207. {
  208. Id = newId,
  209. Shddh = string.IsNullOrWhiteSpace(input.Shddh) ? $"SH{DateTime.Now:yyyyMMddHHmmss}" : input.Shddh!.Trim(),
  210. Jhshrq = shipDate,
  211. Wlsc = input.Wlsc,
  212. Yjdhrq = input.Yjdhrq,
  213. ShPurchaseName = input.ShPurchaseName,
  214. ShPurchaseNum = input.ShPurchaseNum,
  215. Wldh = input.Wldh,
  216. Sfpc = input.Sfpc ?? 0,
  217. Chbg = input.Chbg,
  218. Pcsm = input.Pcsm,
  219. State = 1,
  220. Shzt = "待收",
  221. Tjrid = userId,
  222. Tjrxm = userName,
  223. Tjrq = now.ToString("yyyy-MM-dd")
  224. };
  225. await _masterRep.InsertAsync(entity);
  226. await SaveDetailsAsync(newId, input.Details);
  227. return new { id = newId, message = "新增成功" };
  228. }
  229. var master = await _masterRep.GetFirstAsync(x => x.Id == input.Id.Value) ?? throw Oops.Oh("发货单不存在");
  230. master.Shddh = input.Shddh;
  231. master.Jhshrq = shipDate;
  232. master.Wlsc = input.Wlsc;
  233. master.Yjdhrq = input.Yjdhrq;
  234. master.ShPurchaseName = input.ShPurchaseName;
  235. master.ShPurchaseNum = input.ShPurchaseNum;
  236. master.Wldh = input.Wldh;
  237. master.Sfpc = input.Sfpc ?? 0;
  238. master.Chbg = input.Chbg;
  239. master.Pcsm = input.Pcsm;
  240. await _masterRep.UpdateAsync(master);
  241. await SaveDetailsAsync(input.Id.Value, input.Details);
  242. return new { id = input.Id, message = "编辑成功" };
  243. }
  244. [DisplayName("删除发货单")]
  245. [ApiDescriptionSettings(Name = "DeleteSupplierShipment"), HttpPost("supplier-shipment/delete")]
  246. public async Task<object> Delete([FromBody] SupplierShipmentDeleteInput input)
  247. {
  248. var master = await _masterRep.GetFirstAsync(x => x.Id == input.Id) ?? throw Oops.Oh("发货单不存在");
  249. master.State = 0;
  250. await _masterRep.UpdateAsync(master);
  251. return new { message = "删除成功" };
  252. }
  253. [DisplayName("生成标签(预留)")]
  254. [HttpPost("supplier-shipment/generate-label")]
  255. public async Task<object> GenerateLabel([FromBody] SupplierShipmentOperationInput input)
  256. {
  257. if (input.Id <= 0)
  258. throw Oops.Oh("缺少发货单ID(id)");
  259. var userName = _userManager.Account ?? "system";
  260. var master = await _masterRep.GetFirstAsync(x => x.Id == input.Id) ?? throw Oops.Oh("发货单不存在");
  261. if (string.IsNullOrWhiteSpace(master.Shddh))
  262. throw Oops.Oh("发货单缺少发货单编号(shddh)");
  263. var shddh = master.Shddh.Trim();
  264. var gysmc = master.ShPurchaseName ?? string.Empty;
  265. var gysdm = master.ShPurchaseNum ?? string.Empty;
  266. // Domain(工厂编码)
  267. var domain = await _db.Ado.GetStringAsync(
  268. "SELECT Domain FROM GeneralizedCodeMaster WHERE FldName='SystemConfig' AND Val='CompanyCode' LIMIT 1");
  269. domain = string.IsNullOrWhiteSpace(domain) ? string.Empty : domain.Trim();
  270. string? lockKey = null;
  271. try
  272. {
  273. var tran = await _db.Ado.UseTranAsync(async () =>
  274. {
  275. // 1) 归档旧标签
  276. await _db.Ado.ExecuteCommandAsync(
  277. """
  278. INSERT INTO scm_shbqhis
  279. (glid, sh_material_code, sh_material_name, sh_material_ggxh, sh_delivery_quantity,
  280. sh_material_dw, remarks, bzsl, order_type, po_billno, shdh, shdhh, scrq, scph, xh,
  281. gysdm, gysmc, po_billline, bbh, th, yt, ccrq, shpc, jhdbh, jhdhh)
  282. SELECT
  283. glid, sh_material_code, sh_material_name, sh_material_ggxh, sh_delivery_quantity,
  284. sh_material_dw, remarks, bzsl, order_type, po_billno, shdh, shdhh, scrq, scph, xh,
  285. gysdm, gysmc, po_billline, bbh, th, yt, ccrq, shpc, jhdbh, jhdhh
  286. FROM scm_shbq WHERE shdh=@shdh;
  287. """,
  288. new List<SugarParameter> { new("@shdh", shddh) });
  289. await _db.Ado.ExecuteCommandAsync(
  290. "DELETE FROM scm_shbq WHERE shdh=@shdh",
  291. new List<SugarParameter> { new("@shdh", shddh) });
  292. // 2) 需要补 shpc 的明细(按物料+供应商批号去重)
  293. var needShpc = await _db.Ado.SqlQueryAsync<NeedShpcRow>(
  294. """
  295. SELECT DISTINCT
  296. b.sh_material_code AS wlbm,
  297. IFNULL(b.scph, '') AS scph
  298. FROM scm_shd a
  299. INNER JOIN scm_shdzb b ON a.id = b.glid
  300. WHERE a.shddh = @shddh
  301. AND IFNULL(b.sh_material_code, '') <> ''
  302. AND IFNULL(b.shpc, '') = '';
  303. """,
  304. new List<SugarParameter> { new("@shddh", shddh) });
  305. if (needShpc.Count > 0)
  306. {
  307. // 并发安全:按天加锁 + 取最大流水 + 批量生成
  308. var prefix = DateTime.Now.ToString("yyMMdd");
  309. lockKey = $"scm_shpc_seq_{prefix}";
  310. await AcquireMySqlLockAsync(lockKey, 10);
  311. var nextSerial = await GetNextDailySerialAsync(prefix, domain);
  312. var pairs = needShpc
  313. .OrderBy(x => x.Wlbm ?? string.Empty)
  314. .ThenBy(x => x.Scph ?? string.Empty)
  315. .Select((x, idx) => new
  316. {
  317. x.Wlbm,
  318. x.Scph,
  319. Shpc = $"{prefix}{(nextSerial + idx).ToString().PadLeft(ShpcSerialWidth, '0')}"
  320. })
  321. .ToList();
  322. // 更新 scm_shdzb.shpc(同一发货单下:物料+供应商批号相同的行统一批次号)
  323. foreach (var p in pairs)
  324. {
  325. await _db.Ado.ExecuteCommandAsync(
  326. """
  327. UPDATE scm_shdzb b
  328. INNER JOIN scm_shd a ON a.id = b.glid
  329. SET b.shpc = @shpc
  330. WHERE a.shddh = @shddh
  331. AND b.sh_material_code = @wlbm
  332. AND IFNULL(b.scph, '') = IFNULL(@scph, '')
  333. AND IFNULL(b.shpc, '') = '';
  334. """,
  335. new List<SugarParameter>
  336. {
  337. new("@shpc", p.Shpc),
  338. new("@shddh", shddh),
  339. new("@wlbm", p.Wlbm ?? string.Empty),
  340. new("@scph", p.Scph ?? string.Empty),
  341. });
  342. }
  343. // 兼容:如果线上存在 scm_shdshph,则同步写入(仓库脚本里未包含该表)
  344. var shdshphExists = await TableExistsAsync("scm_shdshph");
  345. if (shdshphExists)
  346. {
  347. foreach (var p in pairs)
  348. {
  349. await _db.Ado.ExecuteCommandAsync(
  350. """
  351. INSERT INTO scm_shdshph (shpc, wlbm, scph, shdh, xh, gysdm, create_time)
  352. SELECT @shpc, @wlbm, @scph, @shdh, @xh, @gysdm, NOW()
  353. FROM DUAL
  354. WHERE NOT EXISTS (
  355. SELECT 1 FROM scm_shdshph
  356. WHERE shdh=@shdh AND wlbm=@wlbm AND IFNULL(scph,'')=IFNULL(@scph,'')
  357. );
  358. """,
  359. new List<SugarParameter>
  360. {
  361. new("@shpc", p.Shpc),
  362. new("@wlbm", p.Wlbm ?? string.Empty),
  363. new("@scph", p.Scph ?? string.Empty),
  364. new("@shdh", shddh),
  365. new("@xh", p.Shpc),
  366. new("@gysdm", gysdm),
  367. });
  368. }
  369. }
  370. // 推进 NbrControl.NextValue,确保续号(仅当没有历史 shpc 且使用了 NbrControl 作为起点时也能正确续)
  371. // 这里直接推进到“本批次最后一个流水号”,下次取号将从 NextValue+1 开始。
  372. var lastSerial = nextSerial + pairs.Count - 1;
  373. await BumpNbrControlNextValueAsync(domain, lastSerial);
  374. }
  375. // 3) 补 jhdhh(同一发货单:为空的明细按 id 递增,起始 max(jhdhh) or 1000)
  376. var shdid = await _db.Ado.GetLongAsync(
  377. "SELECT id FROM scm_shd WHERE shddh=@shddh LIMIT 1",
  378. new List<SugarParameter> { new("@shddh", shddh) });
  379. var startNo = await _db.Ado.GetIntAsync(
  380. "SELECT IFNULL(MAX(CAST(IFNULL(jhdhh,'') AS SIGNED)), 1000) FROM scm_shdzb WHERE glid=@glid",
  381. new List<SugarParameter> { new("@glid", shdid.ToString()) });
  382. var jhdhhNeed = await _db.Ado.SqlQueryAsync<IdOnlyRow>(
  383. "SELECT id FROM scm_shdzb WHERE glid=@glid AND IFNULL(jhdhh,'')='' ORDER BY id",
  384. new List<SugarParameter> { new("@glid", shdid.ToString()) });
  385. var seq = startNo;
  386. foreach (var r in jhdhhNeed)
  387. {
  388. seq++;
  389. await _db.Ado.ExecuteCommandAsync(
  390. "UPDATE scm_shdzb SET jhdhh=@jhdhh WHERE id=@id",
  391. new List<SugarParameter>
  392. {
  393. new("@jhdhh", seq.ToString()),
  394. new("@id", r.Id)
  395. });
  396. }
  397. // 4) 生成 scm_shbq(按 bqsl 拆分;每箱 bzsl,最后一箱余数)
  398. var sourceRows = await _db.Ado.SqlQueryAsync<LabelSourceRow>(
  399. """
  400. SELECT
  401. a.shddh AS shddh,
  402. b.id AS detailId,
  403. b.glid AS glid,
  404. b.sh_material_code AS wlbm,
  405. b.sh_material_name AS wlmc,
  406. b.sh_material_ggxh AS ggxh,
  407. b.sh_delivery_quantity AS shsl,
  408. b.sh_material_dw AS dw,
  409. b.remarks AS bz,
  410. b.bzsl AS bzsl,
  411. b.bqsl AS bqsl,
  412. b.order_type AS ddlx,
  413. b.po_bill AS ddh,
  414. CAST(IFNULL(b.po_billline, '0') AS SIGNED) AS po_billline,
  415. b.hh AS hh,
  416. b.scrq AS scrq,
  417. b.scph AS scph,
  418. IFNULL(im.Drawing, pd.Drawing) AS th,
  419. IFNULL(im.Rev, pd.Rev) AS bbh,
  420. a.sh_purchase_name AS gysmc,
  421. a.sh_purchase_num AS gysdm,
  422. pm.Usage AS usage,
  423. b.ccrq AS ccrq,
  424. a.jhshrq AS jhshrq,
  425. b.jhdbh AS jhdbh,
  426. b.jhdhh AS jhdhh,
  427. b.shpc AS shpc
  428. FROM scm_shd a
  429. INNER JOIN scm_shdzb b ON a.id = b.glid
  430. LEFT JOIN PurOrdMaster pm ON pm.PurOrd = b.po_bill
  431. LEFT JOIN PurOrdDetail pd ON pd.PurOrd = b.po_bill AND pd.Line = b.po_billline
  432. LEFT JOIN ItemMaster im ON im.ItemNum = b.sh_material_code
  433. WHERE a.shddh = @shddh;
  434. """,
  435. new List<SugarParameter> { new("@shddh", shddh) });
  436. foreach (var row in sourceRows)
  437. {
  438. var totalQty = row.Shsl ?? 0m;
  439. var packQty = row.Bzsl ?? 0m;
  440. var labelCnt = (int)Math.Max(0, row.Bqsl ?? 0m);
  441. if (totalQty <= 0 || labelCnt <= 0)
  442. continue;
  443. var xh = LabelXhStart;
  444. var remainQty = totalQty;
  445. var remainLabels = labelCnt;
  446. // 多箱:前 N-1 箱按包装数量
  447. while (remainLabels > 1)
  448. {
  449. await InsertLabelAsync(shddh, row, packQty, xh, gysdm, gysmc);
  450. remainQty -= packQty;
  451. remainLabels--;
  452. xh++;
  453. }
  454. if (remainQty > 0)
  455. {
  456. await InsertLabelAsync(shddh, row, remainQty, xh, gysdm, gysmc);
  457. }
  458. }
  459. // 5) 更新发货单状态
  460. await _db.Ado.ExecuteCommandAsync(
  461. "UPDATE scm_shd SET shzt='待收', state=2, dycs=0 WHERE shddh=@shddh",
  462. new List<SugarParameter> { new("@shddh", shddh) });
  463. // 6) MissedPrint:作废旧未打印(U)
  464. await _db.Ado.ExecuteCommandAsync(
  465. """
  466. UPDATE MissedPrint SET
  467. PurOrd = CONCAT('作废_', IFNULL(PurOrd, '')),
  468. BarCode = CONCAT(CAST(RecID AS CHAR(20)), '_', IFNULL(BarCode, '')),
  469. Status = 'C',
  470. RelatedBarCode = '',
  471. UpdateTime = NOW(),
  472. UpdateUser = @u
  473. WHERE Domain = @domain
  474. AND ShipperNbr = @shddh
  475. AND Status = 'U';
  476. """,
  477. new List<SugarParameter>
  478. {
  479. new("@u", userName),
  480. new("@domain", domain),
  481. new("@shddh", shddh),
  482. });
  483. // 7) MissedPrint:插入待打印(U)
  484. await _db.Ado.ExecuteCommandAsync(
  485. """
  486. INSERT INTO MissedPrint
  487. (
  488. Domain, Site, PrintTime,
  489. ItemNum, Descr, Product, Carton, OrdNbr,
  490. PackingQty, Qty, Location, Status,
  491. Supply, LotSerial, CartonQty, BarCode,
  492. MoldNum, SuppLotSerial, ShipperNbr, ShipperLine,
  493. ProdDate, PurOrd, PurLine, PurQty, WorkOrd,
  494. LabelFormat, StandItem, EffSize, GP12CheckedQty, NetWeight,
  495. Remark, CreateTime, UpdateTime, CreateUser, UpdateUser,
  496. LevelChar, PurOrdDetBatchNbr, FirmString5, ExpireDate,
  497. Printer, Company, Checker, Position
  498. )
  499. SELECT
  500. @domain AS Domain,
  501. @domain AS Site,
  502. NULL AS PrintTime,
  503. s.sh_material_code AS ItemNum,
  504. s.sh_material_name AS Descr,
  505. s.sh_material_ggxh AS Product,
  506. RIGHT(s.xh, 4) AS Carton,
  507. s.po_billno AS OrdNbr,
  508. s.bzsl AS PackingQty,
  509. s.sh_delivery_quantity AS Qty,
  510. NULL AS Location,
  511. 'U' AS Status,
  512. s.gysdm AS Supply,
  513. s.shpc AS LotSerial,
  514. 1 AS CartonQty,
  515. s.xh AS BarCode,
  516. NULL AS MoldNum,
  517. s.scph AS SuppLotSerial,
  518. s.shdh AS ShipperNbr,
  519. s.shdhh AS ShipperLine,
  520. STR_TO_DATE(s.scrq, '%Y-%m-%d') AS ProdDate,
  521. s.po_billno AS PurOrd,
  522. s.po_billline AS PurLine,
  523. s.sh_delivery_quantity AS PurQty,
  524. NULL AS WorkOrd,
  525. 'cl01' AS LabelFormat,
  526. s.po_billno AS StandItem,
  527. s.po_billline AS EffSize,
  528. s.sh_delivery_quantity AS GP12CheckedQty,
  529. 0 AS NetWeight,
  530. s.remarks AS Remark,
  531. NOW() AS CreateTime,
  532. NOW() AS UpdateTime,
  533. @u AS CreateUser,
  534. @u AS UpdateUser,
  535. s.bbh AS LevelChar,
  536. s.jhdbh AS PurOrdDetBatchNbr,
  537. p.ActiveRlseID1 AS FirmString5,
  538. CASE
  539. WHEN i.SuppWarranty = 1 THEN
  540. CASE
  541. WHEN UPPER(i.WarrantyCode)='D' THEN DATE_ADD(STR_TO_DATE(s.scrq, '%Y-%m-%d'), INTERVAL IFNULL(i.DaysBetweenPM,0) DAY)
  542. WHEN UPPER(i.WarrantyCode)='Y' THEN DATE_ADD(STR_TO_DATE(s.scrq, '%Y-%m-%d'), INTERVAL IFNULL(i.DaysBetweenPM,0) YEAR)
  543. WHEN UPPER(i.WarrantyCode)='M' THEN DATE_ADD(STR_TO_DATE(s.scrq, '%Y-%m-%d'), INTERVAL IFNULL(i.DaysBetweenPM,0) MONTH)
  544. ELSE DATE_ADD(STR_TO_DATE(s.scrq, '%Y-%m-%d'), INTERVAL IFNULL(i.DaysBetweenPM,0) DAY)
  545. END
  546. ELSE NULL
  547. END AS ExpireDate,
  548. '' AS Printer,
  549. '' AS Company,
  550. '' AS Checker,
  551. '' AS Position
  552. FROM scm_shbq s
  553. LEFT JOIN PurOrdDetail p ON p.PurOrd = s.po_billno AND p.Line = s.po_billline
  554. LEFT JOIN ItemMaster i ON i.ItemNum = s.sh_material_code
  555. WHERE s.shdh = @shddh;
  556. """,
  557. new List<SugarParameter>
  558. {
  559. new("@domain", domain),
  560. new("@u", userName),
  561. new("@shddh", shddh),
  562. });
  563. });
  564. if (!tran.IsSuccess)
  565. {
  566. var msg = $"生成标签失败,{tran.ErrorMessage}";
  567. return new { success = false, msg, message = msg };
  568. }
  569. var ok = "生成标签成功!";
  570. return new { success = true, msg = ok, message = ok };
  571. }
  572. finally
  573. {
  574. if (!string.IsNullOrWhiteSpace(lockKey))
  575. {
  576. await ReleaseMySqlLockAsync(lockKey);
  577. }
  578. }
  579. }
  580. private async Task InsertLabelAsync(string shddh, LabelSourceRow row, decimal qty, int xh, string gysdm, string gysmc)
  581. {
  582. var jhdhh3 = Right(row.Jhdhh, 3);
  583. var xh4 = Right(xh.ToString(), 4);
  584. var bar = $"{shddh}{jhdhh3}{xh4}";
  585. await _db.Ado.ExecuteCommandAsync(
  586. """
  587. INSERT INTO scm_shbq
  588. (glid, sh_material_code, sh_material_name, sh_material_ggxh, sh_delivery_quantity,
  589. sh_material_dw, remarks, bzsl, order_type, po_billno, shdh, shdhh, scrq, scph, xh,
  590. gysdm, gysmc, po_billline, bbh, th, yt, ccrq, shpc, jhdbh, jhdhh)
  591. VALUES
  592. (@glid, @wlbm, @wlmc, @ggxh, @qty,
  593. @dw, @bz, @bzsl, @ddlx, @ddh, @shdh, @hh, @scrq, @scph, @xh,
  594. @gysdm, @gysmc, @pohh, @bbh, @th, @yt, @ccrq, @shpc, @jhdbh, @jhdhh);
  595. """,
  596. new List<SugarParameter>
  597. {
  598. new("@glid", row.DetailId),
  599. new("@wlbm", row.Wlbm ?? string.Empty),
  600. new("@wlmc", row.Wlmc ?? string.Empty),
  601. new("@ggxh", row.Ggxh ?? string.Empty),
  602. new("@qty", qty),
  603. new("@dw", row.Dw ?? string.Empty),
  604. new("@bz", row.Bz ?? string.Empty),
  605. new("@bzsl", row.Bzsl ?? 0m),
  606. new("@ddlx", row.Ddlx ?? string.Empty),
  607. new("@ddh", row.Ddh ?? string.Empty),
  608. new("@shdh", shddh),
  609. new("@hh", row.Hh ?? 0),
  610. new("@scrq", row.Scrq ?? string.Empty),
  611. new("@scph", row.Scph ?? string.Empty),
  612. new("@xh", bar),
  613. new("@gysdm", gysdm),
  614. new("@gysmc", gysmc),
  615. new("@pohh", row.PoBillLine ?? 0),
  616. new("@bbh", row.Bbh ?? string.Empty),
  617. new("@th", row.Th ?? string.Empty),
  618. new("@yt", row.Usage ?? string.Empty),
  619. new("@ccrq", row.Ccrq ?? string.Empty),
  620. new("@shpc", row.Shpc ?? string.Empty),
  621. new("@jhdbh", row.Jhdbh ?? string.Empty),
  622. new("@jhdhh", row.Jhdhh ?? string.Empty),
  623. });
  624. }
  625. private static string Right(string? s, int len)
  626. {
  627. if (string.IsNullOrEmpty(s)) return new string('0', len);
  628. var t = s.Trim();
  629. return t.Length <= len ? t.PadLeft(len, '0') : t[^len..];
  630. }
  631. private async Task AcquireMySqlLockAsync(string key, int timeoutSeconds)
  632. {
  633. var ok = await _db.Ado.GetIntAsync("SELECT GET_LOCK(@k, @t)", new List<SugarParameter>
  634. {
  635. new("@k", key),
  636. new("@t", timeoutSeconds),
  637. });
  638. if (ok != 1)
  639. throw Oops.Oh($"生成批次号锁等待超时({key})");
  640. }
  641. private Task ReleaseMySqlLockAsync(string key)
  642. => _db.Ado.ExecuteCommandAsync("SELECT RELEASE_LOCK(@k)", new List<SugarParameter> { new("@k", key) });
  643. private async Task<int> GetNextDailySerialAsync(string prefix, string domain)
  644. {
  645. // 从已存在的批次号中取当天最大流水:yyMMdd + 3位
  646. // 优先 scm_shdzb,其次 scm_shbq(兼容历史数据来源)
  647. var max1 = await _db.Ado.GetStringAsync(
  648. "SELECT MAX(shpc) FROM scm_shdzb WHERE shpc LIKE @pfx",
  649. new List<SugarParameter> { new("@pfx", $"{prefix}%") });
  650. var max2 = await _db.Ado.GetStringAsync(
  651. "SELECT MAX(shpc) FROM scm_shbq WHERE shpc LIKE @pfx",
  652. new List<SugarParameter> { new("@pfx", $"{prefix}%") });
  653. var max = string.CompareOrdinal(max1 ?? string.Empty, max2 ?? string.Empty) >= 0 ? max1 : max2;
  654. if (string.IsNullOrWhiteSpace(max) || max!.Length < prefix.Length + ShpcSerialWidth)
  655. {
  656. // 兜底:读取 NbrControl(NbrType='WoLot')的 NextValue + 1
  657. // 说明:有些环境可能会清理历史批次号表;此时用 NbrControl 保证连续。
  658. var nv = await _db.Ado.GetIntAsync(
  659. """
  660. SELECT IFNULL(NextValue, 0)
  661. FROM NbrControl
  662. WHERE NbrType='WoLot'
  663. AND (
  664. domain_code = @d
  665. OR Domain = @d
  666. OR IFNULL(@d,'') = ''
  667. )
  668. ORDER BY RecID
  669. LIMIT 1
  670. """,
  671. new List<SugarParameter> { new("@d", domain ?? string.Empty) });
  672. // 用户要求:NextValue+1 为下一流水号起点
  673. return Math.Max(1, nv + 1);
  674. }
  675. var suffix = max.Substring(prefix.Length);
  676. return int.TryParse(suffix, out var n) ? n + 1 : 1;
  677. }
  678. private async Task BumpNbrControlNextValueAsync(string domain, int lastSerial)
  679. {
  680. // 保守推进:仅当新值更大时更新,避免其它流程并发推进导致回退。
  681. await _db.Ado.ExecuteCommandAsync(
  682. """
  683. UPDATE NbrControl
  684. SET NextValue = CASE
  685. WHEN IFNULL(NextValue, 0) < @v THEN @v
  686. ELSE IFNULL(NextValue, 0)
  687. END,
  688. UpdateTime = NOW()
  689. WHERE NbrType = 'WoLot'
  690. AND (
  691. domain_code = @d
  692. OR Domain = @d
  693. OR IFNULL(@d,'') = ''
  694. );
  695. """,
  696. new List<SugarParameter>
  697. {
  698. new("@d", domain ?? string.Empty),
  699. new("@v", lastSerial),
  700. });
  701. }
  702. private async Task<bool> TableExistsAsync(string tableName)
  703. {
  704. var cnt = await _db.Ado.GetIntAsync(
  705. """
  706. SELECT COUNT(*)
  707. FROM information_schema.tables
  708. WHERE table_schema = DATABASE()
  709. AND table_name = @t
  710. """,
  711. new List<SugarParameter> { new("@t", tableName) });
  712. return cnt > 0;
  713. }
  714. private sealed class NeedShpcRow
  715. {
  716. public string? Wlbm { get; set; }
  717. public string? Scph { get; set; }
  718. }
  719. private sealed class IdOnlyRow
  720. {
  721. public long Id { get; set; }
  722. }
  723. private sealed class LabelSourceRow
  724. {
  725. public string? Shddh { get; set; }
  726. public long DetailId { get; set; }
  727. public string? Glid { get; set; }
  728. public string? Wlbm { get; set; }
  729. public string? Wlmc { get; set; }
  730. public string? Ggxh { get; set; }
  731. public decimal? Shsl { get; set; }
  732. public string? Dw { get; set; }
  733. public string? Bz { get; set; }
  734. public decimal? Bzsl { get; set; }
  735. public decimal? Bqsl { get; set; }
  736. public string? Ddlx { get; set; }
  737. public string? Ddh { get; set; }
  738. public int? PoBillLine { get; set; }
  739. public int? Hh { get; set; }
  740. public string? Scrq { get; set; }
  741. public string? Scph { get; set; }
  742. public string? Th { get; set; }
  743. public string? Bbh { get; set; }
  744. public string? Usage { get; set; }
  745. public string? Ccrq { get; set; }
  746. public string? Jhdbh { get; set; }
  747. public string? Jhdhh { get; set; }
  748. public string? Shpc { get; set; }
  749. }
  750. [DisplayName("打印送货单(预留)")]
  751. [HttpPost("supplier-shipment/print-shipping-note")]
  752. public Task<object> PrintShippingNote([FromBody] SupplierShipmentOperationInput input)
  753. => Task.FromResult<object>(new { message = $"发货单{input.Id}:功能预留,暂未启用" });
  754. [DisplayName("打印标签(预留)")]
  755. [HttpPost("supplier-shipment/print-label")]
  756. public Task<object> PrintLabel([FromBody] SupplierShipmentOperationInput input)
  757. => Task.FromResult<object>(new { message = $"发货单{input.Id}:功能预留,暂未启用" });
  758. [DisplayName("发货单标签数据(scm_shbq)")]
  759. [HttpGet("supplier-shipment/label-data")]
  760. public async Task<object> GetLabelData([FromQuery] string shddh)
  761. {
  762. if (string.IsNullOrWhiteSpace(shddh))
  763. throw Oops.Oh("缺少发货单编号(shddh)");
  764. var pars = new List<SugarParameter> { new("@shddh", shddh.Trim()) };
  765. const string sql = """
  766. SELECT DISTINCT
  767. glid,
  768. sh_material_code AS wlbm,
  769. sh_material_name AS wlmc,
  770. CONCAT(IFNULL(sh_material_name, ''), IFNULL(sh_material_ggxh, '')) AS ggxh,
  771. sh_delivery_quantity AS zxsl,
  772. sh_material_dw AS dw,
  773. remarks,
  774. bzsl AS bz,
  775. order_type AS ddlx,
  776. po_billno AS ddh,
  777. shdh AS shdh,
  778. shdhh AS shdhh,
  779. DATE_FORMAT(scrq, '%Y.%m.%d') AS scrq,
  780. scph,
  781. xh,
  782. gysmc,
  783. th,
  784. bbh,
  785. yt,
  786. ccrq,
  787. shpc
  788. FROM scm_shbq
  789. WHERE shdh = @shddh
  790. """;
  791. var list = await _db.Ado.SqlQueryAsync<SupplierShipmentLabelRow>(sql, pars);
  792. return new { list };
  793. }
  794. private async Task SaveDetailsAsync(long masterId, List<SupplierShipmentDetailInput> inputDetails)
  795. {
  796. var dbDetails = await _detailRep.AsQueryable().Where(x => x.Glid == masterId.ToString()).ToListAsync();
  797. var dbById = dbDetails.ToDictionary(x => x.Id);
  798. var inputIds = new HashSet<long>(inputDetails.Where(d => d.Id is > 0).Select(d => d.Id!.Value));
  799. for (var i = 0; i < inputDetails.Count; i++)
  800. {
  801. var d = inputDetails[i];
  802. if (d.Id is > 0 && dbById.TryGetValue(d.Id.Value, out var existing))
  803. {
  804. existing.Hh = d.Hh ?? (i + 1);
  805. existing.PoBill = d.PoBill;
  806. existing.PoBillLine = d.PoBillLine;
  807. existing.OrderType = d.OrderType;
  808. existing.ShMaterialCode = d.ShMaterialCode;
  809. existing.ShMaterialName = d.ShMaterialName;
  810. existing.Th = d.Th;
  811. existing.ShDeliveryQuantity = d.ShDeliveryQuantity;
  812. existing.Bzsl = d.Bzsl;
  813. existing.Bqsl = d.Bqsl;
  814. existing.ShMaterialDw = d.ShMaterialDw;
  815. existing.Scrq = d.Scrq;
  816. existing.Scph = d.Scph;
  817. existing.Remarks = d.Remarks;
  818. existing.Djsl = d.Djsl;
  819. existing.Jybb = d.Jybb;
  820. existing.Jhdbh = d.Jhdbh;
  821. await _detailRep.UpdateAsync(existing);
  822. }
  823. else
  824. {
  825. var detail = new ScmShdzb
  826. {
  827. Id = YitIdHelper.NextId(),
  828. Glid = masterId.ToString(),
  829. Hh = d.Hh ?? (i + 1),
  830. PoBill = d.PoBill,
  831. PoBillLine = d.PoBillLine,
  832. OrderType = d.OrderType,
  833. ShMaterialCode = d.ShMaterialCode,
  834. ShMaterialName = d.ShMaterialName,
  835. Th = d.Th,
  836. ShDeliveryQuantity = d.ShDeliveryQuantity,
  837. Bzsl = d.Bzsl,
  838. Bqsl = d.Bqsl,
  839. ShMaterialDw = d.ShMaterialDw,
  840. Scrq = d.Scrq,
  841. Scph = d.Scph,
  842. Remarks = d.Remarks,
  843. Djsl = d.Djsl,
  844. Jybb = d.Jybb,
  845. Jhdbh = d.Jhdbh
  846. };
  847. await _detailRep.InsertAsync(detail);
  848. }
  849. }
  850. foreach (var old in dbDetails.Where(x => !inputIds.Contains(x.Id)))
  851. {
  852. await _detailRep.DeleteAsync(x => x.Id == old.Id);
  853. }
  854. }
  855. private static string BuildListOrderBy(string? sortField, string? sortOrder)
  856. {
  857. var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
  858. {
  859. ["shddh"] = "t.shddh",
  860. ["poBill"] = "t.po_bill",
  861. ["jhshrq"] = "t.jhshrq",
  862. ["shMaterialCode"] = "t.sh_material_code",
  863. ["shMaterialName"] = "t.sh_material_name",
  864. ["shDeliveryQuantity"] = "t.sh_delivery_quantity",
  865. ["sfpc"] = "t.sfpc",
  866. ["pcrksl"] = "t.pcrksl",
  867. ["shPurchaseName"] = "t.sh_purchase_name",
  868. ["shpc"] = "t.shpc",
  869. ["scph"] = "t.scph",
  870. ["wldh"] = "t.wldh",
  871. ["dycs"] = "t.dycs",
  872. ["shzt"] = "t.shzt"
  873. };
  874. var field = map.TryGetValue(sortField ?? string.Empty, out var sqlField) ? sqlField : "t.mid";
  875. var order = string.Equals(sortOrder, "asc", StringComparison.OrdinalIgnoreCase) ? "ASC" : "DESC";
  876. return $" ORDER BY {field} {order} ";
  877. }
  878. private static string BuildListSql() => """
  879. SELECT
  880. m.mid,
  881. m.id,
  882. m.sh_purchase_id,
  883. m.sh_purchase_name,
  884. m.sh_purchase_num,
  885. m.sh_purchase_address,
  886. m.sh_purchase_lxr,
  887. m.sh_purchase_phone,
  888. m.client,
  889. m.delivery_Address,
  890. m.expected_consignee,
  891. m.consignee_phone,
  892. m.estimated_delivery_date,
  893. m.po_billno,
  894. m.shddh,
  895. m.jhshrq,
  896. m.tjrid,
  897. m.tjrxm,
  898. m.tjrq,
  899. m.scbq,
  900. m.chbg,
  901. m.sfpc,
  902. m.pcsm,
  903. m.wlsc,
  904. m.yjdhrq,
  905. m.state,
  906. m.shzt,
  907. m.wldh,
  908. m.dycs,
  909. m.gys,
  910. m.sh_material_code,
  911. m.sh_material_name,
  912. m.sh_material_ggxh,
  913. m.hh,
  914. m.po_bill,
  915. m.shpc,
  916. m.scph,
  917. m.sh_delivery_quantity,
  918. m.th,
  919. n.rksl,
  920. n.bhgsl,
  921. n.thsl,
  922. n.zshl,
  923. n.Delivery,
  924. n.pc,
  925. l.pcrksl,
  926. po.potype,
  927. po.Usage
  928. FROM
  929. (
  930. SELECT
  931. a.id mid,
  932. b.id,
  933. a.sh_purchase_id,
  934. a.sh_purchase_name,
  935. a.sh_purchase_num,
  936. a.sh_purchase_address,
  937. a.sh_purchase_lxr,
  938. a.sh_purchase_phone,
  939. a.client,
  940. a.delivery_Address,
  941. a.expected_consignee,
  942. a.consignee_phone,
  943. a.estimated_delivery_date,
  944. a.po_billno,
  945. a.shddh,
  946. a.jhshrq,
  947. a.tjrid,
  948. a.tjrxm,
  949. a.tjrq,
  950. a.scbq,
  951. a.chbg,
  952. a.sfpc,
  953. a.pcsm,
  954. a.wlsc,
  955. a.yjdhrq,
  956. a.state,
  957. IFNULL(a.shzt, '待收') shzt,
  958. a.wldh,
  959. a.dycs,
  960. CONCAT(IFNULL(a.sh_purchase_num, ''), IFNULL(a.sh_purchase_name, '')) gys,
  961. b.sh_material_code,
  962. b.sh_material_name,
  963. b.sh_material_ggxh,
  964. b.hh,
  965. b.po_bill,
  966. c.shpc,
  967. b.scph,
  968. b.sh_delivery_quantity,
  969. b.th
  970. FROM scm_shd a
  971. LEFT JOIN scm_shdzb b ON a.id = b.glid
  972. LEFT JOIN (SELECT DISTINCT glid, shpc FROM scm_shbq) c ON b.id = c.glid
  973. ) m
  974. LEFT JOIN
  975. (
  976. SELECT
  977. Delivery,
  978. LotSerial pc,
  979. SUM(ReceiptQty) zshl,
  980. AVG(yssl) rksl,
  981. SUM(QtyReturn) bhgsl,
  982. SUM(QtyReturned) thsl
  983. FROM vscm_cgshrk
  984. GROUP BY Delivery, LotSerial
  985. ) n ON m.shddh = n.Delivery AND m.shpc = n.pc
  986. LEFT JOIN
  987. (
  988. SELECT LotSerial, SUM(QtyChange) pcrksl
  989. FROM InvTransHist
  990. WHERE QtyChange > 0 AND Reason LIKE '%收货'
  991. GROUP BY LotSerial
  992. ) l ON m.shpc = l.LotSerial
  993. LEFT JOIN PurOrdMaster po ON m.po_bill = po.purord
  994. """;
  995. private sealed class SupplierShipmentListRow
  996. {
  997. public long Mid { get; set; }
  998. public long Id { get; set; }
  999. public string? ShPurchaseName { get; set; }
  1000. public string? ShPurchaseNum { get; set; }
  1001. public string? Shddh { get; set; }
  1002. public string? Jhshrq { get; set; }
  1003. public int? Sfpc { get; set; }
  1004. public string? Wldh { get; set; }
  1005. public int? Dycs { get; set; }
  1006. public string? Shzt { get; set; }
  1007. public string? ShMaterialCode { get; set; }
  1008. public string? ShMaterialName { get; set; }
  1009. public decimal? ShDeliveryQuantity { get; set; }
  1010. public decimal? Pcrksl { get; set; }
  1011. public string? PoBill { get; set; }
  1012. public string? Usage { get; set; }
  1013. public string? Shpc { get; set; }
  1014. public string? Scph { get; set; }
  1015. public string? Th { get; set; }
  1016. public int? State { get; set; }
  1017. }
  1018. private sealed class SupplierShipmentDraftRow
  1019. {
  1020. public string? SourceId { get; set; }
  1021. public string? Gysdm { get; set; }
  1022. public string? Gysmc { get; set; }
  1023. public string? PoBill { get; set; }
  1024. public int? PoBillLine { get; set; }
  1025. public string? OrderType { get; set; }
  1026. public string? ShMaterialCode { get; set; }
  1027. public string? ShMaterialName { get; set; }
  1028. public string? Th { get; set; }
  1029. public decimal? ShDeliveryQuantity { get; set; }
  1030. public decimal? Bzsl { get; set; }
  1031. public string? ShMaterialDw { get; set; }
  1032. public decimal? Djsl { get; set; }
  1033. public string? Jhdbh { get; set; }
  1034. public string? ShMaterialGgxh { get; set; }
  1035. }
  1036. private sealed class SupplierShipmentLabelRow
  1037. {
  1038. public long? Glid { get; set; }
  1039. public string? Wlbm { get; set; }
  1040. public string? Wlmc { get; set; }
  1041. public string? Ggxh { get; set; }
  1042. public decimal? Zxsl { get; set; }
  1043. public string? Dw { get; set; }
  1044. public string? Remarks { get; set; }
  1045. public decimal? Bz { get; set; }
  1046. public string? Ddlx { get; set; }
  1047. public string? Ddh { get; set; }
  1048. public string? Shdh { get; set; }
  1049. public string? Shdhh { get; set; }
  1050. public string? Scrq { get; set; }
  1051. public string? Scph { get; set; }
  1052. public string? Xh { get; set; }
  1053. public string? Gysmc { get; set; }
  1054. public string? Th { get; set; }
  1055. public string? Bbh { get; set; }
  1056. public string? Yt { get; set; }
  1057. public string? Ccrq { get; set; }
  1058. public string? Shpc { get; set; }
  1059. }
  1060. }