SxLayerPackingHelp.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239
  1. using AutoMapper;
  2. using Microsoft.Extensions.Logging;
  3. using Newtonsoft.Json;
  4. using SqlSugar;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using WCS.Entity.sx;
  9. using wms.dto;
  10. using wms.dto.request;
  11. using wms.dto.request.share;
  12. using wms.dto.request.sx;
  13. using wms.dto.response;
  14. using wms.dto.response.sx;
  15. using wms.service.Help.LayerPacking;
  16. using wms.service.Help.LayerPacking.model;
  17. using wms.service.Service;
  18. using wms.sqlsugar;
  19. using wms.sqlsugar.model.sx;
  20. using wms.util.Ext;
  21. using wms.util.Http;
  22. using TaskStatus = wms.dto.TaskStatus;
  23. namespace wms.service.Help.Packing
  24. {
  25. /// <summary>
  26. /// 层配装箱帮助类
  27. /// </summary>
  28. public class SxLayerPackingHelp
  29. {
  30. private readonly Repository<BaseWarecell> _wareCell;
  31. private readonly Repository<BillInvnow> _invNow;
  32. private readonly Repository<BillPboxrule> _boxRule;
  33. private readonly Repository<sxSysConfig> _sysconfing;
  34. private readonly RepositoryTask<BillTimeOutRecord> _timeoutrecord;
  35. private readonly ILogger<SXService> _logger;
  36. private readonly Repository<PalletLayerMath> _palletLayerMath;
  37. private readonly Repository<BillInvflow> _invFlow;
  38. private readonly RepositoryTask<WCS_TaskOld> _wcsTaskOld;
  39. private readonly Repository<BaseWarehouse> _wareHouse;
  40. private readonly RepositoryTask<WCS_TaskDtl> _taskDetail;
  41. private readonly RepositoryTask<WCS_TaskInfo> _task;
  42. private readonly Repository<Palletizing> _palletiz;
  43. private readonly ITenant _db;
  44. private readonly IMapper _mapper;
  45. private readonly object _lockerPalletizingPackTask;
  46. private readonly object _lockerApplyLoc;
  47. /// <summary>
  48. /// 构造函数
  49. /// </summary>
  50. public SxLayerPackingHelp(
  51. Repository<BaseWarecell> wareCell,
  52. Repository<BillInvnow> invNow,
  53. Repository<BillPboxrule> boxRule,
  54. Repository<sxSysConfig> sysconfing,
  55. RepositoryTask<BillTimeOutRecord> timeoutrecord,
  56. ILogger<SXService> logger,
  57. Repository<PalletLayerMath> palletLayerMath,
  58. Repository<BillInvflow> invFlow,
  59. RepositoryTask<WCS_TaskOld> wcsTaskOld,
  60. Repository<BaseWarehouse> wareHouse,
  61. RepositoryTask<WCS_TaskDtl> taskDetail,
  62. RepositoryTask<WCS_TaskInfo> task,
  63. Repository<Palletizing> palletiz,
  64. ITenant db,
  65. IMapper mapper,
  66. object lockerPalletizingPackTask,
  67. object lockerApplyLoc)
  68. {
  69. _wareCell = wareCell;
  70. _invNow = invNow;
  71. _boxRule = boxRule;
  72. _sysconfing = sysconfing;
  73. _timeoutrecord = timeoutrecord;
  74. _logger = logger;
  75. _palletLayerMath = palletLayerMath;
  76. _invFlow = invFlow;
  77. _wcsTaskOld = wcsTaskOld;
  78. _wareHouse = wareHouse;
  79. _taskDetail = taskDetail;
  80. _task = task;
  81. _palletiz = palletiz;
  82. _db = db;
  83. _mapper = mapper;
  84. _lockerPalletizingPackTask = lockerPalletizingPackTask;
  85. _lockerApplyLoc = lockerApplyLoc;
  86. }
  87. #region 获取可用库存
  88. /// <summary>
  89. /// 获取可用库存
  90. /// </summary>
  91. /// <returns></returns>
  92. public IEnumerable<LayerPackingProduct> GetAvailableInventory()
  93. {
  94. int timeOutHoldHours = 72;
  95. var timeOut = _sysconfing.GetFirst(p => p.Code == "CP_TimeOutHoldHours");
  96. if (timeOut != null) timeOutHoldHours = int.Parse(timeOut.SContent);
  97. var normalInventory = GetNormalInventory(timeOutHoldHours);
  98. var reworkInventory = GetReworkInventory(timeOutHoldHours);
  99. var torsInventory = GetTorsInventory(timeOutHoldHours);
  100. var torsReworkInventory = GetTorsReworkInventory(timeOutHoldHours);
  101. var allInventory = normalInventory
  102. .Union(reworkInventory)
  103. .Union(torsInventory)
  104. .Union(torsReworkInventory)
  105. .Distinct(new CompareProduct());
  106. return FilterByTunnelRestrictions(allInventory);
  107. }
  108. /// <summary>
  109. /// 获取非检测非重绕盘
  110. /// </summary>
  111. /// <param name="timeOutHoldHours">超时小时</param>
  112. /// <returns></returns>
  113. private IEnumerable<LayerPackingProduct> GetNormalInventory(int timeOutHoldHours)
  114. {
  115. return from loc in _wareCell.GetList(p =>
  116. p.IsStop == LocationStop.LocationInvoke.GetHashCode() &&
  117. p.StateNum == LocationState.LocationState_Full)
  118. join stock in _invNow.GetList(p =>
  119. p.InvStateCode == InvState.InvEcecState_In.ToString() &&
  120. p.ExecStateCode == InvLockState.InvState_Normal.ToString() &&
  121. p.Grade == "A" &&
  122. !p.IsControlpanel &&
  123. !p.IsTorsChk &&
  124. string.IsNullOrEmpty(p.PreStock) &&
  125. p.ContUsageQty <= 0 &&
  126. !p.ProductMachCode.Contains("R") &&
  127. (DateTime.Now - p.ProductTime).TotalHours < timeOutHoldHours)
  128. on loc.ContGrpBarCode equals stock.ContGrpBarCode
  129. join rule in _boxRule.AsQueryable().Where(p => p.PackRule == "CP").Select(p => new { p.DocsNo, p.SkuCode }).Distinct().ToList()
  130. on stock.InDocsNo equals rule.DocsNo
  131. select CreateStockTemp(loc, stock, rule.SkuCode);
  132. }
  133. /// <summary>
  134. /// 获取非检测重绕盘
  135. /// </summary>
  136. /// <param name="timeOutHoldHours">超时小时</param>
  137. /// <returns></returns>
  138. private IEnumerable<LayerPackingProduct> GetReworkInventory(int timeOutHoldHours)
  139. {
  140. return from loc in _wareCell.GetList(p =>
  141. p.IsStop == LocationStop.LocationInvoke.GetHashCode() &&
  142. p.StateNum == LocationState.LocationState_Full)
  143. join stock in _invNow.GetList(p =>
  144. p.InvStateCode == InvState.InvEcecState_In.ToString() &&
  145. p.ExecStateCode == InvLockState.InvState_Normal.ToString() &&
  146. p.Grade == "A" &&
  147. !p.IsControlpanel &&
  148. !p.IsTorsChk &&
  149. string.IsNullOrEmpty(p.PreStock) &&
  150. p.ContUsageQty <= 0 &&
  151. p.ProductMachCode.Contains("R") &&
  152. (DateTime.Now - p.OneInTime).TotalHours < timeOutHoldHours)
  153. on loc.ContGrpBarCode equals stock.ContGrpBarCode
  154. join rule in _boxRule.AsQueryable().Where(p => p.PackRule == "CP").Select(p => new { p.DocsNo, p.SkuCode }).Distinct().ToList()
  155. on stock.InDocsNo equals rule.DocsNo
  156. select CreateStockTemp(loc, stock, rule.SkuCode);
  157. }
  158. /// <summary>
  159. /// 获取已检测非重绕盘
  160. /// </summary>
  161. /// <param name="timeOutHoldHours">超时小时</param>
  162. /// <returns></returns>
  163. private IEnumerable<LayerPackingProduct> GetTorsInventory(int timeOutHoldHours)
  164. {
  165. return from loc in _wareCell.GetList(p =>
  166. p.IsStop == LocationStop.LocationInvoke.GetHashCode() &&
  167. p.StateNum == LocationState.LocationState_Full)
  168. join stock in _invNow.GetList(p =>
  169. p.InvStateCode == InvState.InvEcecState_In.ToString() &&
  170. p.ExecStateCode == InvLockState.InvState_Normal.ToString() &&
  171. p.Grade == "A" &&
  172. p.IsControlpanel &&
  173. p.IsTorsChk &&
  174. p.TorsChkQty > 0 &&
  175. string.IsNullOrEmpty(p.PreStock) &&
  176. !p.ProductMachCode.Contains("R") &&
  177. p.ContUsageQty <= 0 &&
  178. (DateTime.Now - p.ProductTime).TotalHours < timeOutHoldHours)
  179. on loc.ContGrpBarCode equals stock.ContGrpBarCode
  180. join rule in _boxRule.AsQueryable().Where(p => p.PackRule == "CP").Select(p => new { p.DocsNo, p.SkuCode }).Distinct().ToList()
  181. on stock.InDocsNo equals rule.DocsNo
  182. select CreateStockTemp(loc, stock, rule.SkuCode);
  183. }
  184. /// <summary>
  185. /// 获取已检测重绕盘
  186. /// </summary>
  187. /// <param name="timeOutHoldHours">超时小时</param>
  188. /// <returns></returns>
  189. private IEnumerable<LayerPackingProduct> GetTorsReworkInventory(int timeOutHoldHours)
  190. {
  191. return from loc in _wareCell.GetList(p =>
  192. p.IsStop == LocationStop.LocationInvoke.GetHashCode() &&
  193. p.StateNum == LocationState.LocationState_Full)
  194. join stock in _invNow.GetList(p =>
  195. p.InvStateCode == InvState.InvEcecState_In.ToString() &&
  196. p.ExecStateCode == InvLockState.InvState_Normal.ToString() &&
  197. p.Grade == "A" &&
  198. p.IsControlpanel &&
  199. p.IsTorsChk &&
  200. p.TorsChkQty > 0 &&
  201. string.IsNullOrEmpty(p.PreStock) &&
  202. p.ProductMachCode.Contains("R") &&
  203. p.ContUsageQty <= 0 &&
  204. (DateTime.Now - p.OneInTime).TotalHours < timeOutHoldHours)
  205. on loc.ContGrpBarCode equals stock.ContGrpBarCode
  206. join rule in _boxRule.AsQueryable().Where(p => p.PackRule == "CP").Select(p => new { p.DocsNo, p.SkuCode }).Distinct().ToList()
  207. on stock.InDocsNo equals rule.DocsNo
  208. select CreateStockTemp(loc, stock, rule.SkuCode);
  209. }
  210. /// <summary>
  211. /// 创建库存临时对象
  212. /// </summary>
  213. /// <param name="loc">货位信息</param>
  214. /// <param name="stock">库存信息</param>
  215. /// <param name="skuCode">sku</param>
  216. /// <returns></returns>
  217. private LayerPackingProduct CreateStockTemp(BaseWarecell loc, BillInvnow stock, string skuCode)
  218. {
  219. return new LayerPackingProduct
  220. {
  221. MatCode = stock.MatCode,
  222. InvBarCode = stock.InvBarCode,
  223. Grade = stock.Grade,
  224. InvStateCode = stock.InvStateCode,
  225. ProductTime = stock.ProductTime,
  226. WbGroupCode = stock.WbGroupCode,
  227. IsTorsChk = stock.IsTorsChk,
  228. TorsChkQty = stock.TorsChkQty,
  229. TorsChkValue = stock.TorsChkValue == null ? 0 : (decimal)stock.TorsChkValue,
  230. HoldTime = stock.HoldTime,
  231. ProductMachCode = stock.ProductMachCode,
  232. IsControlpanel = stock.IsControlpanel,
  233. HWTypeCode = stock.HWTypeCode,
  234. SolderCount = stock.SolderCount,
  235. IsRework = stock.IsRework,
  236. IsBlack = stock.IsBlack,
  237. Col = loc.Col,
  238. Layer = loc.Layer,
  239. Shelf = loc.Shelf,
  240. Depth = loc.Depth,
  241. Code = loc.Code,
  242. Tunnel = loc.Tunnel,
  243. SCRel = loc.SCRel,
  244. Floor = loc.Floor,
  245. WarehouseCode = loc.WarehouseCode,
  246. ContGrpBarCode = loc.ContGrpBarCode,
  247. ContGrpId = loc.ContGrpId,
  248. Id = loc.Id,
  249. StateNum = loc.StateNum,
  250. SkuCode = skuCode,
  251. Wind = stock.Wind,
  252. InDocsNo = stock.InDocsNo,
  253. BatchNo = stock.BatchNo
  254. };
  255. }
  256. /// <summary>
  257. /// 过滤禁用巷道
  258. /// </summary>
  259. /// <param name="inventory">可用产品</param>
  260. /// <returns></returns>
  261. public IEnumerable<LayerPackingProduct> FilterByTunnelRestrictions(IEnumerable<LayerPackingProduct> inventory)
  262. {
  263. var tunnelRestrictions = _sysconfing.GetList(p =>
  264. p.SType == "OutStop" && !string.IsNullOrEmpty(p.SContent));
  265. if (!tunnelRestrictions.Any())
  266. {
  267. return inventory;
  268. }
  269. var filteredInventory = inventory.ToList();
  270. // 按楼层过滤禁用巷道
  271. for (int floor = 1; floor <= 3; floor++)
  272. {
  273. var floorRestrictions = tunnelRestrictions
  274. .Where(p => p.Default2 == floor.ToString())
  275. .Select(x => x.Default1)
  276. .ToList();
  277. if (floorRestrictions.Any())
  278. {
  279. var restrictedContainers = filteredInventory
  280. .Where(p => p.Floor == floor &&
  281. floorRestrictions.Contains(p.Tunnel.ToString()))
  282. .Select(p => p.ContGrpBarCode)
  283. .ToList();
  284. filteredInventory = filteredInventory
  285. .Where(p => !restrictedContainers.Contains(p.ContGrpBarCode))
  286. .ToList();
  287. }
  288. }
  289. return filteredInventory;
  290. }
  291. #endregion 获取可用库存
  292. #region 装箱逻辑
  293. /// <summary>
  294. /// 按SKU执行装箱
  295. /// </summary>
  296. /// <param name="skuGroup"></param>
  297. /// <param name="boxRules"></param>
  298. /// <param name="inventory"></param>
  299. /// <returns></returns>
  300. public SRes ProcessSkuGroup(
  301. IGrouping<string, LayerPackingProduct> skuGroup,
  302. List<BillPboxrule> boxRules,
  303. IEnumerable<LayerPackingProduct> inventory)
  304. {
  305. var res = new SRes { ResCode = ResponseStatusCodeEnum.Fail.GetHashCode() };
  306. var skuCode = skuGroup.Key;
  307. var skuBoxRules = boxRules.Where(p => p.SkuCode == skuCode).OrderBy(p => p.BatchNo).ThenBy(p => p.PBoxCode);
  308. if (!skuBoxRules.Any())
  309. {
  310. return HandleNoBoxRuleForSku(skuCode, inventory);
  311. }
  312. var ruleGroups = skuBoxRules.GroupBy(p => new { p.Wind, p.SpoolType, p.FullCountQty });
  313. foreach (var ruleGroup in ruleGroups)
  314. {
  315. var result = ProcessRuleGroup(ruleGroup, inventory, skuCode);
  316. if (result.ResCode == ResponseStatusCodeEnum.Sucess.GetHashCode())
  317. {
  318. return result;
  319. }
  320. else
  321. {
  322. res.ResMsg += $"[{ruleGroup.Key}:{result.ResMsg}]";
  323. }
  324. }
  325. return res;
  326. }
  327. /// <summary>
  328. /// 处理装箱规则组
  329. /// </summary>
  330. /// <param name="ruleGroup">箱号</param>
  331. /// <param name="inventory">产品</param>
  332. /// <param name="skuCode">sku</param>
  333. /// <returns></returns>
  334. public SRes ProcessRuleGroup(
  335. IGrouping<dynamic, BillPboxrule> ruleGroup,
  336. IEnumerable<LayerPackingProduct> inventory,
  337. string skuCode)
  338. {
  339. var rule = ruleGroup.OrderBy(p => p.BatchNo).ThenBy(p => p.PBoxCode).FirstOrDefault();
  340. if (rule == null) return new SRes { ResCode = ResponseStatusCodeEnum.Fail.GetHashCode() };
  341. return ProcessSpecialSku(rule, inventory);
  342. }
  343. /// <summary>
  344. /// 处理特殊SKU --指不管控机器组
  345. /// </summary>
  346. /// <param name="skuCode">sku</param>
  347. /// <returns></returns>
  348. private bool IsSpecialSku(string skuCode)
  349. {
  350. return skuCode == "6210010401" || skuCode == "6210120101";
  351. }
  352. /// <summary>
  353. /// 处理不需要管控机器组的SKU
  354. /// </summary>
  355. /// <param name="rule"></param>
  356. /// <param name="inventory"></param>
  357. /// <returns></returns>
  358. public SRes ProcessSpecialSku(
  359. BillPboxrule rule,
  360. IEnumerable<LayerPackingProduct> inventory)
  361. {
  362. var res = new SRes();
  363. // 1. 分配库存
  364. var allocationResult = AllocateStock(rule, inventory, isSpecialSku: true);
  365. if (!allocationResult.IsSuccess)
  366. {
  367. _logger.LogError($"特殊SKU库存分配失败: {allocationResult.ErrorMessage}");
  368. res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
  369. res.ResMsg = allocationResult.ErrorMessage;
  370. return res;
  371. }
  372. // 2. MES验证
  373. var mesResult = VerifyBoxWithMes(rule.PBoxCode, rule.BatchNo);
  374. if (!mesResult.IsSuccess)
  375. {
  376. UpdateBoxStatus(rule, 2, mesResult.Message);
  377. res.ResCode = ResponseStatusCodeEnum.ErrParam.GetHashCode();
  378. res.ResMsg = $"MES验证失败: {mesResult.Message}";
  379. return res;
  380. }
  381. // 3. 预占库存
  382. PreOccupyInventory(rule, allocationResult.BoxInfo);
  383. res.ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode();
  384. return res;
  385. }
  386. /// <summary>
  387. /// 装箱
  388. /// </summary>
  389. /// <param name="rule">箱号</param>
  390. /// <param name="availableStock">有效库存</param>
  391. /// <param name="isSpecialSku">是否控制机器组</param>
  392. /// <param name="skuGroup">对应的分组sku</param>
  393. /// <returns></returns>
  394. public StockAllocationResult AllocateStock(
  395. BillPboxrule rule,
  396. IEnumerable<LayerPackingProduct> availableStock,
  397. bool isSpecialSku = false,
  398. IGrouping<string, LayerPackingProduct>? skuGroup = null)
  399. {
  400. var result = new StockAllocationResult();
  401. // 过滤符合条件的库存
  402. var filteredStock = FilterStock(availableStock, rule, isSpecialSku, skuGroup).ToList();
  403. if (!filteredStock.Any())
  404. {
  405. result.IsSuccess = false;
  406. result.ErrorMessage = "没有符合条件的库存";
  407. return result;
  408. }
  409. //构建初始装箱参数
  410. var constraints = new LayerPackingConstraints
  411. {
  412. P = rule.TorsChkValue,
  413. P1 = rule.TorsChkValueRange,
  414. SolderMaxCount = rule.SolderMaxCount,
  415. PerSolderMaxCount = rule.PerSolderMaxCount,
  416. ProductsPerBox = rule.FullCountQty
  417. };
  418. var config = _sysconfing.GetFirst(x => x.Code == "CP_RelaxationRatio");
  419. if (config != null)
  420. {
  421. constraints.BR = decimal.Parse(config.SContent);
  422. constraints.LR = decimal.Parse(config.Default1);
  423. }
  424. constraints.UpdateTargetValues(filteredStock);
  425. //开始装箱
  426. var layerPacking = new LayerPackingService(filteredStock, constraints);
  427. var layerPackingResult = layerPacking.PackBoxe();
  428. //装箱结果为空
  429. if (layerPackingResult.Boxes.Count < 1)
  430. {
  431. result.IsSuccess = false;
  432. result.ErrorMessage = JsonConvert.SerializeObject(layerPackingResult.FailureReasons);
  433. return result;
  434. }
  435. if (!layerPackingResult.IsSuccess)
  436. {
  437. result.ErrorMessage = JsonConvert.SerializeObject(layerPackingResult.FailureReasons);
  438. }
  439. result.IsSuccess = true;
  440. result.BoxInfo = layerPackingResult.Boxes.First();
  441. return result;
  442. }
  443. /// <summary>
  444. /// 过滤库存
  445. /// </summary>
  446. /// <param name="stock">产品</param>
  447. /// <param name="rule">装箱规则</param>
  448. /// <param name="isSpecialSku">是否管控机器组</param>
  449. /// <param name="skuGroup">管控机器组时用于过滤的机器组信息</param>
  450. /// <returns></returns>
  451. private IEnumerable<LayerPackingProduct> FilterStock(
  452. IEnumerable<LayerPackingProduct> stock,
  453. BillPboxrule rule,
  454. bool isSpecialSku,
  455. IGrouping<string, LayerPackingProduct>? skuGroup = null)
  456. {
  457. var filtered = stock.Where(p => p.SkuCode == rule.SkuCode);
  458. if (!isSpecialSku && skuGroup != null)
  459. {
  460. filtered = filtered.Where(p => p.WbGroupCode == skuGroup.Key);
  461. }
  462. if (!string.IsNullOrEmpty(rule.SpoolType))
  463. {
  464. filtered = filtered.Where(p => p.HWTypeCode == rule.SpoolType);
  465. }
  466. if (!string.IsNullOrEmpty(rule.Wind))
  467. {
  468. filtered = filtered.Where(p => p.Wind == rule.Wind);
  469. }
  470. return filtered;
  471. }
  472. #region 箱号验证
  473. /// <summary>
  474. /// 箱号验证
  475. /// </summary>
  476. /// <param name="boxCode">待验证的箱号</param>
  477. /// <param name="batchNo">批号</param>
  478. /// <returns></returns>
  479. public MesVerificationResult VerifyBoxWithMes(string boxCode, string batchNo)
  480. {
  481. var result = new MesVerificationResult();
  482. try
  483. {
  484. var boxVerifyRequest = new MesBoxVerify
  485. {
  486. HuNr = boxCode,
  487. Batch = batchNo
  488. };
  489. var requestId = Guid.NewGuid().ToString();
  490. var esbRequest = CreateEsbRequest(requestId);
  491. var url = wms.util.AppSettings.GetConfig("EsbMesPushUrl");
  492. var response = SendMesRequest(boxVerifyRequest, requestId, esbRequest, url);
  493. var mesResponse = JsonConvert.DeserializeObject<TorschMesResponse>(response);
  494. _logger.LogInformation($"MES箱号验证返回: {response}");
  495. result.IsSuccess = mesResponse.success;
  496. result.Message = mesResponse.message;
  497. result.RawResponse = response;
  498. }
  499. catch (Exception ex)
  500. {
  501. _logger.LogError($"MES验证异常: {ex}");
  502. result.IsSuccess = false;
  503. result.Message = "MES验证异常: " + ex.Message;
  504. }
  505. return result;
  506. }
  507. /// <summary>
  508. /// 创建ESB请求
  509. /// </summary>
  510. /// <param name="requestId">请求ID</param>
  511. /// <returns></returns>
  512. private EsbReq CreateEsbRequest(string requestId)
  513. {
  514. return new EsbReq
  515. {
  516. headers = new HeadersReq
  517. {
  518. serviceCode = "163K162003",
  519. requestId = requestId,
  520. TrackId = requestId,
  521. sourceCode = "163K"
  522. }
  523. };
  524. }
  525. /// <summary>
  526. /// 发送MES请求
  527. /// </summary>
  528. /// <param name="request">请求参数</param>
  529. /// <param name="requestId">请求ID</param>
  530. /// <param name="esbRequest">esb请求信息</param>
  531. /// <param name="_mesUrl">esb地址</param>
  532. /// <returns></returns>
  533. private string SendMesRequest(MesBoxVerify request, string requestId, EsbReq esbRequest, string _mesUrl)
  534. {
  535. return HttpUtil.PostRequest(
  536. _mesUrl,
  537. JsonConvert.SerializeObject(request),
  538. 30000,
  539. "UTF-8",
  540. "application/json",
  541. requestId,
  542. esbRequest.headers.sourceCode,
  543. esbRequest.headers.serviceCode);
  544. }
  545. #endregion 箱号验证
  546. #region 更新装箱/库存信息
  547. /// <summary>
  548. /// 预占用库存
  549. /// </summary>
  550. /// <param name="rule">箱号</param>
  551. /// <param name="boxInfo">产品信息</param>
  552. public SRes PreOccupyInventory(
  553. BillPboxrule rule,
  554. LayerPackingBoxInfo boxInfo)
  555. {
  556. var res = new SRes() { ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode(), ResMsg = ResponseStatusCodeEnum.Sucess.GetDescription() };
  557. if (boxInfo.Layers.SelectMany(x=>x.Products).Count() != rule.FullCountQty)
  558. {
  559. res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
  560. res.ResMsg = "成箱产品数与满箱产品数不符";
  561. return res;
  562. }
  563. try
  564. {
  565. _db.BeginTran();
  566. // 更新箱号状态为预占用
  567. UpdateBoxStatus(rule, 3, "箱号预占用");
  568. // 更新库存预占用标记
  569. var presign = rule.Id.ToString();
  570. var layerNumber = 0;
  571. foreach (var layer in boxInfo.Layers.OrderByDescending(x => x.TotalTorsion))
  572. {
  573. var layerProductsIds = layer.Products.Select(x => x.ContGrpId).ToList();
  574. _invNow.UpdateSetColumnsTrue(p => new BillInvnow
  575. {
  576. PreStock = presign,
  577. EditTime = DateTime.Now,
  578. PackingLayer = layerNumber,
  579. Memo = $"箱号预占用:{rule.PBoxCode}"
  580. }, p => layerProductsIds.Contains(p.ContGrpId));
  581. layerNumber++;
  582. }
  583. var containerIds = boxInfo.TotalProduct.Select(x => x.ContGrpId).ToList();
  584. _db.CommitTran();
  585. _logger.LogInformation($"{rule.PBoxCode}预占:{JsonConvert.SerializeObject(containerIds)}");
  586. }
  587. catch (Exception ex)
  588. {
  589. _logger.LogError($"箱号预占用异常: {ex}");
  590. _db.RollbackTran();
  591. res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
  592. res.ResMsg = ex.Message;
  593. }
  594. return res;
  595. }
  596. /// <summary>
  597. /// 更新箱号状态
  598. /// </summary>
  599. /// <param name="rule">箱号</param>
  600. /// <param name="status">状态</param>
  601. /// <param name="memo">备注</param>
  602. public void UpdateBoxStatus(BillPboxrule rule, int status, string memo)
  603. {
  604. _boxRule.UpdateSetColumnsTrue(p => new BillPboxrule
  605. {
  606. ZXStateCode = status,
  607. EditTime = DateTime.Now,
  608. Memo = memo
  609. }, p => p.Id == rule.Id);
  610. }
  611. #endregion 更新装箱/库存信息
  612. #endregion 装箱逻辑
  613. #region 处理无箱号可用的情况
  614. /// <summary>
  615. /// 处理没有箱号的情况
  616. /// </summary>
  617. /// <param name="inventory">产品信息</param>
  618. /// <returns></returns>
  619. public SRes HandleNoBoxRuleError(IEnumerable<LayerPackingProduct> inventory)
  620. {
  621. string msg = "SPC" + ResponseStatusCodeEnum.NotBoxRule.GetDescription();
  622. RedisHelper.Set("Sx:WMSErrorInfo:NoControlOut8",
  623. new RedisErrorInfo { Equip = "NoControlOut8", Con = msg, Time = DateTime.Now });
  624. _logger.LogInformation("非控制不满足装箱:" + msg);
  625. var docNos = inventory.GroupBy(v => v.InDocsNo).Select(p => p.Key).Distinct().ToList();
  626. SxPackingHelp.WreTimeOutRecord(inventory.Select(p => p.ContGrpBarCode).ToList(), $"没有箱号可以使用,单号:{JsonConvert.SerializeObject(docNos)}", _timeoutrecord, _logger);
  627. return new SRes
  628. {
  629. ResCode = ResponseStatusCodeEnum.NotBoxRule.GetHashCode(),
  630. ResMsg = msg
  631. };
  632. }
  633. /// <summary>
  634. /// 处理没有箱号可用的情况 --SKU
  635. /// </summary>
  636. /// <param name="skuCode">SKU</param>
  637. /// <param name="inventory">产品信息</param>
  638. /// <returns></returns>
  639. public SRes HandleNoBoxRuleForSku(string skuCode, IEnumerable<LayerPackingProduct> inventory)
  640. {
  641. var skuInventory = inventory.Where(p => p.SkuCode == skuCode);
  642. var docNos = inventory.GroupBy(v => v.InDocsNo).Select(p => p.Key).Distinct().ToList();
  643. string msg = $"没有箱号可以使用,SKU:{skuCode},单号:{JsonConvert.SerializeObject(docNos)}";
  644. RedisHelper.Set("Sx:WMSErrorInfo:NoControlOut9", new RedisErrorInfo { Equip = "NoControlOut9", Con = msg, Time = DateTime.Now });
  645. _logger.LogInformation($"非控制不满足装箱:{msg}");
  646. SxPackingHelp.WreTimeOutRecord(skuInventory.Select(p => p.ContGrpBarCode).ToList(), $"没有箱号可以使用,SKU:{skuCode},单号:{JsonConvert.SerializeObject(docNos)}", _timeoutrecord, _logger);
  647. return new SRes { ResCode = ResponseStatusCodeEnum.Fail.GetHashCode(), ResMsg = msg };
  648. }
  649. #endregion 处理无箱号可用的情况
  650. #region 下发装箱任务及缓存托盘
  651. #region 处理正在码垛的任务
  652. /// <summary>
  653. /// 处理正在码垛的任务
  654. /// </summary>
  655. public SRes ProcessActivePalletizingTasks()
  656. {
  657. var res = new SRes();
  658. var activePalletList = _palletiz.GetList(p =>
  659. p.PalletizState == 0 &&
  660. p.BoxRule == "CP" &&
  661. p.IsControlpanel == false);
  662. if (!activePalletList.Any())
  663. {
  664. res.ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode();
  665. res.ResMsg = "没有正在码垛的任务";
  666. return res;
  667. }
  668. // 按任务数量排序
  669. activePalletList = SortPalletListByTaskCount(activePalletList);
  670. var taskConfig = GetTaskConfiguration();
  671. foreach (var pallet in activePalletList)
  672. {
  673. // 检查机械手任务数量限制
  674. if (!CheckRobotTaskLimit(pallet.Robot, taskConfig.MaxTaskCount))
  675. {
  676. _logger.LogInformation($"{pallet.Robot}当前机械手任务数量已经超最大值{taskConfig.MaxTaskCount}");
  677. continue;
  678. }
  679. // 检查任务下发顺序
  680. if (!CheckTaskSequence(pallet, taskConfig.TaskStatus))
  681. {
  682. continue;
  683. }
  684. // 下发码垛任务
  685. var taskResult = CreatePalletizingTasks(pallet);
  686. if (taskResult.ResCode != ResponseStatusCodeEnum.Sucess.GetHashCode())
  687. {
  688. continue;
  689. }
  690. // 更新任务标识
  691. UpdateTaskFlag(pallet.Robot, pallet.Equip);
  692. }
  693. res.ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode();
  694. res.ResMsg = "正在码垛任务处理完成";
  695. return res;
  696. }
  697. /// <summary>
  698. /// 按任务数量排序码垛列表
  699. /// </summary>
  700. /// <param name="palletList">码垛列表</param>
  701. /// <returns>排序后的码垛列表</returns>
  702. private List<Palletizing> SortPalletListByTaskCount(List<Palletizing> palletList)
  703. {
  704. if (!palletList.Any())
  705. {
  706. return palletList;
  707. }
  708. // 获取每个码垛工位的未完成任务数量
  709. var palletIds = palletList.Select(p => p.Id).ToList();
  710. var taskCountQuery = _palletLayerMath
  711. .GetList(p => p.Istask == 0 && palletIds.Contains(p.PalletizingId))
  712. .GroupBy(p => p.Palletequip);
  713. if (!taskCountQuery.Any())
  714. {
  715. return palletList;
  716. }
  717. // 统计每个工位的任务数量
  718. var taskCountList = (from taskGroup in taskCountQuery
  719. select new TunnelCountTemp
  720. {
  721. Tunnel = taskGroup.Key,
  722. Count = taskGroup.Count()
  723. }).ToList();
  724. // 按任务数量降序排序码垛列表
  725. var sortedList = palletList.OrderByDescending(p =>
  726. {
  727. var matchedCount = taskCountList.FirstOrDefault(q => q.Tunnel == p.Equip);
  728. return matchedCount?.Count ?? 0;
  729. }).ToList();
  730. return sortedList;
  731. }
  732. /// <summary>
  733. /// 创建码垛任务
  734. /// </summary>
  735. private SRes CreatePalletizingTasks(Palletizing pallet)
  736. {
  737. var res = new SRes();
  738. // 获取码垛工位配置
  739. var equipConfig = GetPalletizingEquipConfig(pallet.Equip);
  740. if (equipConfig == null)
  741. {
  742. SetRedisError("NoControlOut2", $"不存在该{pallet.Equip}的码垛工位");
  743. res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
  744. res.ResMsg = $"不存在该{pallet.Equip}的码垛工位";
  745. return res;
  746. }
  747. // 获取待下发的码垛任务
  748. var palletMathList = _palletLayerMath
  749. .GetList(p => p.PalletizingId == pallet.Id && p.Istask == 0)
  750. .OrderBy(p => p.Depth)
  751. .Take(72);
  752. if (!palletMathList.Any())
  753. {
  754. SetRedisError("NoControlOut3", $"{pallet.Equip}没有新的码垛任务需要下发");
  755. res.ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode();
  756. res.ResMsg = "没有新的码垛任务需要下发";
  757. return res;
  758. }
  759. // 获取DocID
  760. var docId = GenerateDocId(pallet.Id);
  761. // 批量创建任务
  762. var taskResults = new List<SRes>();
  763. foreach (var palletMath in palletMathList)
  764. {
  765. var taskRes = CreateSinglePalletizingTask(palletMath, pallet, equipConfig, docId);
  766. if (taskRes.ResCode == ResponseStatusCodeEnum.Sucess.GetHashCode())
  767. {
  768. taskResults.Add(taskRes);
  769. }
  770. }
  771. res.ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode();
  772. res.ResMsg = $"成功创建{taskResults.Count}个码垛任务";
  773. return res;
  774. }
  775. /// <summary>
  776. /// 创建单个码垛任务
  777. /// </summary>
  778. private SRes CreateSinglePalletizingTask(
  779. PalletLayerMath palletMath,
  780. Palletizing pallet,
  781. sxSysConfig equipConfig,
  782. int docId)
  783. {
  784. var res = new SRes();
  785. // 获取库位信息
  786. var cell = _wareCell.GetSingle(p =>
  787. p.ContGrpBarCode == palletMath.ContBarCode &&
  788. p.StateNum == LocationState.LocationState_Full &&
  789. p.ContGrpId == palletMath.ContGrpId);
  790. if (cell == null)
  791. {
  792. res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
  793. res.ResMsg = "库位信息不存在";
  794. return res;
  795. }
  796. // 获取库存信息
  797. var inventory = _invNow.GetSingle(p =>
  798. p.ContGrpBarCode == palletMath.ContBarCode &&
  799. p.InvStateCode == InvState.InvEcecState_In.ToString());
  800. if (inventory == null)
  801. {
  802. res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
  803. res.ResMsg = "库存信息不存在";
  804. return res;
  805. }
  806. // 处理二深位移库
  807. if (cell.Depth == 2)
  808. {
  809. var moveRes = SxServiceHelp.MoveTask(cell.Code, _wcsTaskOld, _wareHouse, _invNow, _wareCell, _task, _taskDetail, _db, _logger, _mapper, _lockerPalletizingPackTask, _lockerApplyLoc);
  810. if (!string.IsNullOrEmpty(moveRes.Memo1) && moveRes.Memo1 == "1")
  811. {
  812. SetRedisError("NoControlOut23", $"{cell.Code}库位下发移库任务失败,请检查一深货位状态");
  813. res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
  814. res.ResMsg = "移库任务失败";
  815. return res;
  816. }
  817. }
  818. // 创建码垛任务请求
  819. var taskRequest = BuildPalletizingTaskRequest(palletMath, cell, inventory, pallet, docId);
  820. // 调用任务创建接口
  821. var taskResponse = SxServiceHelp.PalletizingPackTask(taskRequest, _wareCell, _invNow, _invFlow, _task, _wcsTaskOld, _taskDetail, _db, _mapper, _lockerPalletizingPackTask);
  822. if (taskResponse.ResCode == ResponseStatusCodeEnum.Sucess.GetHashCode())
  823. {
  824. // 更新码垛层任务状态
  825. _palletLayerMath.UpdateSetColumnsTrue(
  826. p => new PalletLayerMath() { Istask = 1, Layer = inventory.PackingLayer },
  827. p => p.ContBarCode == inventory.ContGrpBarCode);
  828. }
  829. return taskResponse;
  830. }
  831. /// <summary>
  832. /// 获取任务配置
  833. /// </summary>
  834. private TaskConfiguration GetTaskConfiguration()
  835. {
  836. return new TaskConfiguration
  837. {
  838. TaskStatus = (TaskStatus)int.Parse(_sysconfing.GetSingle(p => p.Code == "PreNextTaskStatus").SContent),
  839. MaxTaskCount = int.Parse(_sysconfing.GetSingle(p => p.Code == "PreNextTaskCount").SContent)
  840. };
  841. }
  842. /// <summary>
  843. /// 获取码垛工位配置
  844. /// </summary>
  845. /// <param name="equipCode">工位编码</param>
  846. /// <returns>工位配置信息</returns>
  847. private sxSysConfig GetPalletizingEquipConfig(string equipCode)
  848. {
  849. try
  850. {
  851. // 从视图中查询码垛工位配置
  852. var config = _sysconfing.Context.Ado
  853. .SqlQuery<sxSysConfig>($"select * from WMS_ZT_01SX.dbo.V_PalletizingPack where code = '{equipCode}'")
  854. .FirstOrDefault();
  855. if (config == null)
  856. {
  857. _logger.LogWarning($"未找到工位 {equipCode} 的配置信息");
  858. }
  859. return config;
  860. }
  861. catch (Exception ex)
  862. {
  863. _logger.LogError(ex, $"获取工位 {equipCode} 配置信息时发生异常");
  864. return null;
  865. }
  866. }
  867. /// <summary>
  868. /// 检查任务下发顺序
  869. /// </summary>
  870. private bool CheckTaskSequence(
  871. Palletizing currentPallet,
  872. TaskStatus taskStatus)
  873. {
  874. // 找到当前机械手最早的码垛信息
  875. var earliestPallet = _palletiz
  876. .GetList(p => p.PalletizState != 1 && p.Robot == currentPallet.Robot)
  877. .OrderBy(p => p.Id)
  878. .FirstOrDefault();
  879. if (earliestPallet == null || currentPallet.Id == earliestPallet.Id)
  880. {
  881. return true;
  882. }
  883. // 检查是否是第3箱
  884. var result = CheckThirdBoxRestriction(currentPallet, earliestPallet, taskStatus);
  885. return result;
  886. }
  887. /// <summary>
  888. /// 检查第3箱限制
  889. /// </summary>
  890. private bool CheckThirdBoxRestriction(
  891. Palletizing currentPallet,
  892. Palletizing earliestPallet,
  893. TaskStatus taskStatus)
  894. {
  895. var robotPallets = _palletiz.GetList(p =>
  896. p.PalletizState != 1 &&
  897. p.Robot == currentPallet.Robot);
  898. if (robotPallets.Count < 3)
  899. {
  900. return true;
  901. }
  902. var thirdBoxId = robotPallets.OrderBy(p => p.Id).Take(3).Last().Id;
  903. // 如果是第3箱
  904. if (currentPallet.Id == thirdBoxId)
  905. {
  906. // 检查最早的箱子任务是否过了卡控点
  907. if (HasUnfinishedTasks(earliestPallet.Id, taskStatus))
  908. {
  909. _logger.LogInformation($"第3箱卡控同一机械手最早的箱子的码垛任务没有全部过卡控点{taskStatus.GetDescription()}");
  910. return false;
  911. }
  912. // 检查前两箱是否都是同一目标地址
  913. var firstTwoBoxes = robotPallets.Where(p => p.Id < thirdBoxId).ToList();
  914. if (firstTwoBoxes.Count == 2 && firstTwoBoxes.Select(p => p.Equip).Distinct().Count() == 1)
  915. {
  916. _logger.LogInformation("第3箱卡控同一机械手前面两箱都是同一目标地址,则不下第3箱任务");
  917. return false;
  918. }
  919. }
  920. else if (currentPallet.Id > thirdBoxId)
  921. {
  922. _logger.LogInformation($"同一机械手第3箱之后的任务不允许下发,码垛主表id:{currentPallet.Id}");
  923. return false;
  924. }
  925. return true;
  926. }
  927. /// <summary>
  928. /// 构建码垛任务请求
  929. /// </summary>
  930. /// <param name="palletMath">码垛层数学信息</param>
  931. /// <param name="cell">库位信息</param>
  932. /// <param name="inventory">库存信息</param>
  933. /// <param name="pallet">码垛主信息</param>
  934. /// <param name="docId">文档ID</param>
  935. /// <returns>码垛任务请求对象</returns>
  936. private PalletizingPackTaskRequest BuildPalletizingTaskRequest(
  937. PalletLayerMath palletMath,
  938. BaseWarecell cell,
  939. BillInvnow inventory,
  940. Palletizing pallet,
  941. int docId)
  942. {
  943. // 确定机械手
  944. var robot = SxServiceHelp.DetermineRoot(palletMath.Palletequip);
  945. // 构建任务请求
  946. var request = new PalletizingPackTaskRequest
  947. {
  948. // 容器条码
  949. Code = palletMath.ContBarCode,
  950. // 库位信息
  951. CellCode = cell.Code,
  952. Srm = cell.SCRel,
  953. Tunnel = cell.Tunnel.ToString(),
  954. Floor = cell.Floor,
  955. // 产品信息
  956. Grade = inventory.Grade,
  957. Mater = inventory.MatCode,
  958. SkuCode = palletMath.SkuCode,
  959. ProductMachCode = inventory.ProductMachCode,
  960. // 码垛信息
  961. PalletLayer = inventory.PackingLayer,
  962. Equip = pallet.Equip,
  963. PalletizingId = pallet.Id,
  964. Robot = robot,
  965. // 货物类型:1-BS80/33, 2-其他
  966. GoodsType = inventory.HWTypeCode == "BS80/33" ? 1 : 2,
  967. // 文档ID
  968. DocId = docId
  969. };
  970. return request;
  971. }
  972. #endregion 处理正在码垛的任务
  973. /// <summary>
  974. /// 更新码垛状态为正在码垛
  975. /// </summary>
  976. private void UpdatePalletStateToActive(long palletId)
  977. {
  978. try
  979. {
  980. _palletiz.AsUpdateable()
  981. .SetColumns(p => new Palletizing() { PalletizState = 0 })
  982. .Where(p => p.Id == palletId)
  983. .ExecuteCommand();
  984. _logger.LogInformation($"码垛任务 {palletId} 状态已更新为正在码垛");
  985. }
  986. catch (Exception ex)
  987. {
  988. _logger.LogError(ex, $"更新码垛任务 {palletId} 状态时发生异常");
  989. }
  990. }
  991. #region 辅助方法
  992. /// <summary>
  993. /// 设置Redis错误信息
  994. /// </summary>
  995. private void SetRedisError(string equipCode, string message)
  996. {
  997. RedisHelper.Set($"Sx:WMSErrorInfo:{equipCode}", new RedisErrorInfo
  998. {
  999. Equip = equipCode,
  1000. Con = message,
  1001. Time = DateTime.Now
  1002. });
  1003. }
  1004. /// <summary>
  1005. /// 检查机械手任务数量限制
  1006. /// </summary>
  1007. private bool CheckRobotTaskLimit(string robot, int maxCount)
  1008. {
  1009. var currentCount = _task.AsQueryable()
  1010. .With(SqlWith.NoLock)
  1011. .Where(p => p.Status < TaskStatus.码垛抓取完成 &&
  1012. p.Robot == robot &&
  1013. p.BusType == "装箱码垛")
  1014. .Count();
  1015. return currentCount < maxCount;
  1016. }
  1017. /// <summary>
  1018. /// 判断是否有未完成的任务
  1019. /// </summary>
  1020. private bool HasUnfinishedTasks(long palletizingId, TaskStatus taskStatus)
  1021. {
  1022. var hasUnfinishedMath = _palletLayerMath
  1023. .GetList(p => p.PalletizingId == palletizingId && p.Istask == 0)
  1024. .Any();
  1025. var hasUnfinishedTask = _task.AsQueryable()
  1026. .With(SqlWith.NoLock)
  1027. .Where(p => p.PalletizingId == palletizingId && p.Status < taskStatus)
  1028. .Any();
  1029. return hasUnfinishedMath || hasUnfinishedTask;
  1030. }
  1031. /// <summary>
  1032. /// 更新任务标识
  1033. /// </summary>
  1034. private void UpdateTaskFlag(string robot, string equipCode)
  1035. {
  1036. var currentFlag = _sysconfing.Context.Ado
  1037. .SqlQuery<sxSysConfig>("select * from WMS_ZT_01SX.dbo.V_PalletizingPack")
  1038. .Where(p => p.Robot == robot)
  1039. .Max(p => p.TaskFlag);
  1040. var newFlag = currentFlag + 1;
  1041. _sysconfing.Context.Ado.ExecuteCommand($"update WMS_ZT_01CP.dbo.sys_config set taskflag={newFlag} where code='{equipCode}'");
  1042. }
  1043. /// <summary>
  1044. /// 记录超时记录
  1045. /// </summary>
  1046. private void WreTimeOutRecord(List<string> containerBarcodes, string reason)
  1047. {
  1048. // 实现超时记录逻辑
  1049. _logger.LogWarning($"超时记录 - 容器条码: {string.Join(",", containerBarcodes)}, 原因: {reason}");
  1050. }
  1051. /// <summary>
  1052. /// 生成文档ID
  1053. /// </summary>
  1054. /// <param name="palletizingId">码垛ID</param>
  1055. /// <returns>文档ID</returns>
  1056. private int GenerateDocId(long palletizingId)
  1057. {
  1058. try
  1059. {
  1060. // 获取装箱码垛类型任务的最大DocID
  1061. var maxDocId = _task.AsQueryable()
  1062. .Where(p => p.BusType == "装箱码垛")
  1063. .Max(p => (int?)p.DocID) ?? 0;
  1064. // 默认使用最大值+1
  1065. var currentDocId = maxDocId + 1;
  1066. // 检查当前码垛是否已有任务,如果有则使用相同的DocID
  1067. var existingDocId = _task.AsQueryable()
  1068. .With(SqlWith.NoLock)
  1069. .Where(p => p.PalletizingId == palletizingId && p.DocID > 0)
  1070. .Max(p => (int?)p.DocID);
  1071. if (existingDocId.HasValue)
  1072. {
  1073. currentDocId = existingDocId.Value;
  1074. }
  1075. return currentDocId;
  1076. }
  1077. catch (Exception ex)
  1078. {
  1079. _logger.LogError(ex, $"生成文档ID时发生异常,码垛ID:{palletizingId}");
  1080. throw;
  1081. }
  1082. }
  1083. #endregion 辅助方法
  1084. #endregion 下发装箱任务及缓存托盘
  1085. }
  1086. }