环形库分流点.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. using PlcSiemens.Core.Extension;
  2. using ServiceCenter.Extensions;
  3. using ServiceCenter.Logs;
  4. using ServiceCenter.SqlSugars;
  5. using SqlSugar;
  6. using System.ComponentModel;
  7. using WCS.Core;
  8. using WCS.Entity;
  9. using WCS.Entity.Protocol.Station;
  10. using WCS.WorkEngineering.Extensions;
  11. using WCS.WorkEngineering.Worlds;
  12. using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags;
  13. using TaskStatus = WCS.Entity.TaskStatus;
  14. namespace WCS.WorkEngineering.Systems
  15. {
  16. /// <summary>
  17. /// 分流点
  18. /// </summary>
  19. [BelongTo(typeof(SortingBranchWorld))]
  20. [Description("环形库分流点")]
  21. public class 环形库分流点 : DeviceSystem<Device<IStation520, IStation521, IStation523, IStation91>>
  22. {
  23. protected override bool ParallelDo => true;
  24. protected override bool SaveLogsToFile => true;
  25. public override void Do(Device<IStation520, IStation521, IStation523, IStation91> obj)
  26. {
  27. if (obj.Data.VoucherNo != obj.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{obj.Data.VoucherNo}-DB521:{obj.Data2.VoucherNo}", LogLevelEnum.High);
  28. if (obj.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low);
  29. if (!obj.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low);
  30. if (obj.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid);
  31. //处理异常任务
  32. if (obj.Data2.TaskNumber == 1)
  33. {
  34. obj.Data.TaskNumber = 591;
  35. obj.Data.GoodsStart = obj.Entity.Code.ToShort();
  36. obj.Data.GoodsEnd = 591;
  37. obj.Data.VoucherNo++;
  38. World.Log($"执行记录:任务号[{591}]-[{obj.Data.VoucherNo}]");
  39. }
  40. var isPut = false;
  41. short nextAdd = 0;
  42. SqlSugarHelper.Do(_db =>
  43. {
  44. var db = _db.Default;
  45. var taskInfo = db.Queryable<WCS_TaskInfo>().First(v => v.ID == obj.Data2.TaskNumber && v.Status == TaskStatus.WaitingToExecute) ?? throw new KnownException($"未找到对应的WCS任务{obj.Data2.TaskNumber}", LogLevelEnum.Mid);
  46. switch (obj.Data4.Length)
  47. {
  48. case 9:
  49. isPut = Allot09Or18(db, taskInfo, obj);
  50. nextAdd = 455;
  51. break;
  52. case 18:
  53. nextAdd = 442;
  54. taskInfo.AddrNext = nextAdd.ToString();
  55. taskInfo.Status = TaskStatus.FinishOfShunt;
  56. taskInfo.EditTime = DateTime.Now;
  57. taskInfo.WarehouseCode += "R";
  58. taskInfo.AddrTo = "Robot";
  59. taskInfo.GoodsType = obj.Data4.Length.ToInt();
  60. db.Updateable(taskInfo).ExecuteCommand();
  61. taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流");
  62. isPut = true;
  63. obj.Data.CmdType = StationCmd.Res6;
  64. break;
  65. case 50:
  66. nextAdd = 424;
  67. taskInfo.AddrNext = nextAdd.ToString();
  68. taskInfo.Status = TaskStatus.FinishOfShunt;
  69. taskInfo.EditTime = DateTime.Now;
  70. taskInfo.WarehouseCode += "R";
  71. taskInfo.AddrTo = "Robot";
  72. taskInfo.GoodsType = obj.Data4.Length.ToInt();
  73. db.Updateable(taskInfo).ExecuteCommand();
  74. taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流");
  75. isPut = true;
  76. break;
  77. case 34:
  78. nextAdd = 433;
  79. taskInfo.AddrNext = nextAdd.ToString();
  80. taskInfo.Status = TaskStatus.FinishOfShunt;
  81. taskInfo.EditTime = DateTime.Now;
  82. taskInfo.WarehouseCode += "R";
  83. taskInfo.AddrTo = "Robot";
  84. taskInfo.GoodsType = obj.Data4.Length.ToInt();
  85. db.Updateable(taskInfo).ExecuteCommand();
  86. taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流");
  87. isPut = true;
  88. break;
  89. }
  90. });
  91. if (!isPut) return;
  92. obj.Data.TaskNumber = obj.Data2.TaskNumber;
  93. obj.Data.GoodsStart = obj.Entity.Code.ToShort();
  94. obj.Data.GoodsEnd = nextAdd;
  95. obj.Data.VoucherNo++;
  96. World.Log($"执行记录:任务号[{obj.Data2.TaskNumber}]-[{obj.Data.VoucherNo}]");
  97. }
  98. public override bool Select(Device dev)
  99. {
  100. return dev.HasFlag(DeviceFlags.环形库分流点);
  101. }
  102. /// <summary>
  103. /// 计算非零九或18的去向
  104. /// </summary>
  105. /// <param name="db"></param>
  106. /// <param name="taskInfo"></param>
  107. /// <param name="obj"></param>
  108. /// <returns></returns>
  109. public bool AllotNot09Or18(SqlSugarScopeProvider db, WCS_TaskInfo taskInfo, Device<IStation520, IStation521, IStation523, IStation91> obj)
  110. {
  111. return false;
  112. }
  113. /// <summary>
  114. /// 计算09/18去向
  115. /// </summary>
  116. /// <param name="db"></param>
  117. /// <param name="taskInfo"></param>
  118. /// <param name="obj"></param>
  119. /// <returns></returns>
  120. public bool Allot09Or18(SqlSugarScopeProvider db, WCS_TaskInfo taskInfo, Device<IStation520, IStation521, IStation523, IStation91> obj)
  121. {
  122. //TODO:暂时不来考虑动态计算可前往的目标
  123. var nextAdd = taskInfo.WarehouseCode switch
  124. {
  125. "1N" => "455",
  126. "1S" => "455",
  127. "2N" => "455",
  128. "2S" => "455",
  129. "3N" => "455",
  130. "3S" => "455",
  131. _ => "0"
  132. };
  133. //获取这个地址的下一个地址集合
  134. var cacheLineDevList = Device.All.First(x => x.Code == nextAdd).Targets.Where(x => x.HasFlag(DeviceFlags.桁架缓存放行点));
  135. var cacheLineCodes = cacheLineDevList.Select(x => x.Code.ToShort());
  136. var cacheLineList = db.Queryable<WCS_CacheLine>().Includes(x => x.Locations).ToList();
  137. #region 跟据缓存信息寻找可以到达的缓存点
  138. //找到当前任务可用的缓存线信息
  139. var cacheLine = cacheLineList.Where(x => x.Locations.Any(l => l is { InStock: false, IsEmpty: false })).FirstOrDefault(x => cacheLineCodes.Contains(x.LocationNo) && x.MatCodeList.Contains(taskInfo.MatCode) && !x.InStock);
  140. if (cacheLine != null)//这个任务可以直接去一条线体,不需要新建缓存信息
  141. {
  142. //找到这条线体中序号最小的一条位信息 非空置且无货
  143. var cacheLoc = cacheLine.Locations.Where(x => x is { InStock: false, IsEmpty: false }).MinBy(x => x.XYNo);
  144. if (cacheLoc != null)
  145. {
  146. cacheLoc = db.Queryable<WCS_CacheLineLoc>().Single(x => x.Id == cacheLoc.Id);
  147. cacheLoc.InStock = true;
  148. cacheLoc.TaskId = taskInfo.ID;
  149. cacheLoc.EditTime = DateTime.Now;
  150. db.Updateable(cacheLoc).ExecuteCommand();
  151. //WCS任务相关信息
  152. taskInfo.Status = TaskStatus.FinishOfShunt;
  153. taskInfo.AddrNext = cacheLine.LocationNo.ToString();
  154. taskInfo.EditWho = "WCS";
  155. taskInfo.EditTime = DateTime.Now;
  156. taskInfo.GoodsType = obj.Data4.Length.ToInt();
  157. db.Updateable(taskInfo).ExecuteCommand();
  158. taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}");
  159. return true;
  160. }
  161. }
  162. #endregion 跟据缓存信息寻找可以到达的缓存点
  163. #region 初始化一个信息的缓存信息
  164. //TODO:暂时不处理就近分线的逻辑
  165. var devCode = cacheLineDevList.Select(x => x.Code.ToShort()).FirstOrDefault(x => !cacheLineList.Select(s => s.LocationNo).Contains(x));
  166. if (devCode == 0)
  167. {
  168. World.Log($"无可用线体:{taskInfo.ID}");
  169. return false;
  170. }
  171. var result = false;
  172. //未结束且包含当前物料编号的垛形,按时间排序,创建时间早的优先分配
  173. var palletizingList = db.Queryable<WCS_Palletizing>()
  174. .Includes(x => x.Layers, r => r.Rows, l => l.Locs)
  175. .Where(x => !x.Finish)
  176. .Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
  177. .OrderBy(x => x.AddTime)
  178. .ToList();
  179. foreach (var palletizing in palletizingList)
  180. {
  181. //当前任务已经分配结束,进入下一次迭代
  182. if (result) continue;
  183. //未结束且包含当前物料编号的层,按层号排序,层号小的优先分配
  184. var layers = palletizing.Layers.Where(x => x is { IsEmpty: false, Finish: false })
  185. .Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
  186. .OrderBy(x => x.LayerNo)
  187. .ToList();
  188. //未找到可用层,进入下一次迭代
  189. if (!layers.Any()) continue;
  190. foreach (var layer in layers)
  191. {
  192. //当前任务已经分配结束,进入下一次迭代
  193. if (result) continue;
  194. //未结束,未预分配缓存线信息且包含当前物料编号的行,行号小的优先分配
  195. var rows = layer.Rows.Where(x => x is { IsEmpty: false, Finish: false })
  196. .Where(x => x.CacheLineId == 0)
  197. .Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
  198. .ToList();
  199. //未找到可用行,进入下一次迭代
  200. if (!rows.Any()) continue;
  201. var palletizingRow = rows.MinBy(x => x.RowNo);
  202. //开始初始化缓存位信息
  203. cacheLine = new WCS_CacheLine()
  204. {
  205. LocationNo = devCode,
  206. AddTime = DateTime.Now,
  207. PalletizingRowId = palletizingRow.Id,
  208. InStock = false,
  209. Put = false,
  210. IsTruss = false,
  211. MatCodeList = palletizingRow.MatCodeList
  212. };
  213. var res = db.Insertable(cacheLine).ExecuteReturnEntity();
  214. palletizingRow = db.Queryable<WCS_PalletizingRow>().Includes(x => x.Locs).Single(x => x.Id == palletizingRow.Id);
  215. palletizingRow.Locs = palletizingRow.Locs.OrderBy(x => x.XYNo).ToList();
  216. palletizingRow.CacheLineId = res.Id;
  217. palletizingRow.EditTime = DateTime.Now;
  218. db.Updateable(palletizingRow).ExecuteCommand();
  219. for (var i = 0; i < palletizingRow.Locs.Count; i++)
  220. {
  221. var loc = new WCS_CacheLineLoc()
  222. {
  223. XYNo = palletizingRow.Locs[i].XYNo,
  224. InStock = i == 0,
  225. IsEmpty = palletizingRow.Locs[i].IsEmpty,
  226. MatCode = palletizingRow.Locs[i].MatCode,
  227. TaskId = i == 0 ? taskInfo.ID : 0,
  228. CacheLineId = res.Id
  229. };
  230. db.Insertable(loc).ExecuteCommand();
  231. }
  232. taskInfo.Status = TaskStatus.FinishOfShunt;
  233. taskInfo.AddrNext = devCode.ToString();
  234. taskInfo.EditWho = "WCS";
  235. taskInfo.EditTime = DateTime.Now;
  236. taskInfo.GoodsType = obj.Data4.Length.ToInt();
  237. db.Updateable(taskInfo).ExecuteCommand();
  238. taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}");
  239. result = true;
  240. }
  241. }
  242. if (!result)
  243. {
  244. taskInfo.InitStackStructure(db);
  245. }
  246. return result;
  247. ////找到所有当前轮子可以去的垛形
  248. //var palletizingList = db.Queryable<WCS_Palletizing>()
  249. // .Includes(x => x.Layers, r => r.Rows, l => l.Locs)
  250. // .Where(x => x.MatCodeList.Contains(taskInfo.MatCode) && !x.Finish).ToList()
  251. // .Where(x => x.Layers.SelectMany(x => x.Rows).Any(r => r.LineCode == null))
  252. // .OrderBy(x => x.AddTime).ToList();
  253. ////如果没有对应的垛形信息就初始化一个垛形信息
  254. //if (palletizingList.Count <= 0)
  255. //{
  256. // taskInfo.InitStackStructure(db);
  257. // return false;
  258. //}
  259. //var b = palletizingList.Select(palletizing => palletizing.Layers
  260. // .Where(x => !x.IsEmpty)
  261. // .Where(x => !x.Finish)
  262. // .Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
  263. // .Where(x => x.Rows.Any(r => r is { IsEmpty: false, Finish: false } && r.MatCodeList.Contains(taskInfo.MatCode) && r.CacheLineId == 0))
  264. // .MinBy(x => x.LayerNo)).Where(x => x != null);
  265. //foreach (var palletizingLayer in b)
  266. //{
  267. // //如果没有哪一层需要这个物料号,就初始化一个新的垛形信息
  268. // if (palletizingLayer == null)
  269. // {
  270. // taskInfo.InitStackStructure(db);
  271. // return false;
  272. // }
  273. // //再找行:未空置、未结束
  274. // var palletizingRow = palletizingLayer.Rows.Where(x => x is { IsEmpty: false, Finish: false } && x.MatCodeList.Contains(taskInfo.MatCode) && x.CacheLineId == 0)
  275. // .MinBy(x => x.RowNo);
  276. // //如果没有哪一行需要这个物料号,就初始化一个新的垛形信息
  277. // if (palletizingRow == null)
  278. // {
  279. // taskInfo.InitStackStructure(db);
  280. // return false;
  281. // }
  282. // //走到这一步就表示没有哪一段线体缓存了当前物料,需要选一段新的线体进行缓存
  283. // //TODO:暂时不处理就近分线的逻辑
  284. // //获取一个当前可以使用的分配锁
  285. // var devCode = cacheLineDevList.Select(x => x.Code.ToShort()).FirstOrDefault(x => !cacheLineList.Select(s => s.LocationNo).Contains(x));
  286. // if (devCode == 0)
  287. // {
  288. // World.Log($"无可用线体:{taskInfo.ID}");
  289. // return false;
  290. // }
  291. // //开始初始化缓存位信息
  292. // cacheLine = new WCS_CacheLine()
  293. // {
  294. // LocationNo = devCode,
  295. // AddTime = DateTime.Now,
  296. // PalletizingRowId = palletizingRow.Id,
  297. // InStock = false,
  298. // Put = false,
  299. // IsTruss = false,
  300. // MatCodeList = palletizingRow.MatCodeList
  301. // };
  302. // var res = db.Insertable(cacheLine).ExecuteReturnEntity();
  303. // palletizingRow = db.Queryable<WCS_PalletizingRow>().Includes(x => x.Locs).Single(x => x.Id == palletizingRow.Id);
  304. // palletizingRow.Locs = palletizingRow.Locs.OrderBy(x => x.XYNo).ToList();
  305. // palletizingRow.CacheLineId = res.Id;
  306. // palletizingRow.EditTime = DateTime.Now;
  307. // db.Updateable(palletizingRow).ExecuteCommand();
  308. // for (var i = 0; i < palletizingRow.Locs.Count; i++)
  309. // {
  310. // var loc = new WCS_CacheLineLoc()
  311. // {
  312. // XYNo = palletizingRow.Locs[i].XYNo,
  313. // InStock = i == 0,
  314. // IsEmpty = palletizingRow.Locs[i].IsEmpty,
  315. // MatCode = palletizingRow.Locs[i].MatCode,
  316. // TaskId = i == 0 ? taskInfo.ID : 0,
  317. // CacheLineId = res.Id
  318. // };
  319. // db.Insertable(loc).ExecuteCommand();
  320. // }
  321. // taskInfo.Status = TaskStatus.FinishOfShunt;
  322. // taskInfo.AddrNext = devCode.ToString();
  323. // taskInfo.EditWho = "WCS";
  324. // taskInfo.EditTime = DateTime.Now;
  325. // taskInfo.GoodsType = obj.Data4.Length.ToInt();
  326. // db.Updateable(taskInfo).ExecuteCommand();
  327. // taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}");
  328. // return true;
  329. //}
  330. #endregion 初始化一个信息的缓存信息
  331. }
  332. }
  333. }