using PlcSiemens.Core.Extension; using ServiceCenter.Extensions; using ServiceCenter.Logs; using ServiceCenter.SqlSugars; using SqlSugar; using System.ComponentModel; using WCS.Core; using WCS.Entity; using WCS.Entity.Protocol.Station; using WCS.WorkEngineering.Extensions; using WCS.WorkEngineering.Worlds; using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags; using TaskStatus = WCS.Entity.TaskStatus; namespace WCS.WorkEngineering.Systems { /// /// 分流点 /// [BelongTo(typeof(SortingBranchWorld))] [Description("环形库分流点")] public class 环形库分流点 : DeviceSystem> { protected override bool ParallelDo => true; protected override bool SaveLogsToFile => true; public override void Do(Device obj) { if (obj.Data.VoucherNo != obj.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{obj.Data.VoucherNo}-DB521:{obj.Data2.VoucherNo}", LogLevelEnum.High); if (obj.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low); if (!obj.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low); if (obj.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid); //处理异常任务 if (obj.Data2.TaskNumber == 1) { obj.Data.TaskNumber = 591; obj.Data.GoodsStart = obj.Entity.Code.ToShort(); obj.Data.GoodsEnd = 591; obj.Data.VoucherNo++; World.Log($"执行记录:任务号[{591}]-[{obj.Data.VoucherNo}]"); } var isPut = false; short nextAdd = 0; SqlSugarHelper.Do(_db => { var db = _db.Default; var taskInfo = db.Queryable().First(v => v.ID == obj.Data2.TaskNumber && v.Status == TaskStatus.WaitingToExecute) ?? throw new KnownException($"未找到对应的WCS任务{obj.Data2.TaskNumber}", LogLevelEnum.Mid); switch (obj.Data4.Length) { case 9: isPut = Allot09Or18(db, taskInfo, obj); nextAdd = 455; break; case 18: nextAdd = 442; taskInfo.AddrNext = nextAdd.ToString(); taskInfo.Status = TaskStatus.FinishOfShunt; taskInfo.EditTime = DateTime.Now; taskInfo.WarehouseCode += "R"; taskInfo.AddrTo = "Robot"; taskInfo.GoodsType = obj.Data4.Length.ToInt(); db.Updateable(taskInfo).ExecuteCommand(); taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流"); isPut = true; obj.Data.CmdType = StationCmd.Res6; break; case 50: nextAdd = 424; taskInfo.AddrNext = nextAdd.ToString(); taskInfo.Status = TaskStatus.FinishOfShunt; taskInfo.EditTime = DateTime.Now; taskInfo.WarehouseCode += "R"; taskInfo.AddrTo = "Robot"; taskInfo.GoodsType = obj.Data4.Length.ToInt(); db.Updateable(taskInfo).ExecuteCommand(); taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流"); isPut = true; break; case 34: nextAdd = 433; taskInfo.AddrNext = nextAdd.ToString(); taskInfo.Status = TaskStatus.FinishOfShunt; taskInfo.EditTime = DateTime.Now; taskInfo.WarehouseCode += "R"; taskInfo.AddrTo = "Robot"; taskInfo.GoodsType = obj.Data4.Length.ToInt(); db.Updateable(taskInfo).ExecuteCommand(); taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流"); isPut = true; break; } }); if (!isPut) return; obj.Data.TaskNumber = obj.Data2.TaskNumber; obj.Data.GoodsStart = obj.Entity.Code.ToShort(); obj.Data.GoodsEnd = nextAdd; obj.Data.VoucherNo++; World.Log($"执行记录:任务号[{obj.Data2.TaskNumber}]-[{obj.Data.VoucherNo}]"); } public override bool Select(Device dev) { return dev.HasFlag(DeviceFlags.环形库分流点); } /// /// 计算非零九或18的去向 /// /// /// /// /// public bool AllotNot09Or18(SqlSugarScopeProvider db, WCS_TaskInfo taskInfo, Device obj) { return false; } /// /// 计算09/18去向 /// /// /// /// /// public bool Allot09Or18(SqlSugarScopeProvider db, WCS_TaskInfo taskInfo, Device obj) { //TODO:暂时不来考虑动态计算可前往的目标 var nextAdd = taskInfo.WarehouseCode switch { "1N" => "455", "1S" => "455", "2N" => "455", "2S" => "455", "3N" => "455", "3S" => "455", _ => "0" }; //获取这个地址的下一个地址集合 var cacheLineDevList = Device.All.First(x => x.Code == nextAdd).Targets.Where(x => x.HasFlag(DeviceFlags.桁架缓存放行点)); var cacheLineCodes = cacheLineDevList.Select(x => x.Code.ToShort()); var cacheLineList = db.Queryable().Includes(x => x.Locations).ToList(); #region 跟据缓存信息寻找可以到达的缓存点 //找到当前任务可用的缓存线信息 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); if (cacheLine != null)//这个任务可以直接去一条线体,不需要新建缓存信息 { //找到这条线体中序号最小的一条位信息 非空置且无货 var cacheLoc = cacheLine.Locations.Where(x => x is { InStock: false, IsEmpty: false }).MinBy(x => x.XYNo); if (cacheLoc != null) { cacheLoc = db.Queryable().Single(x => x.Id == cacheLoc.Id); cacheLoc.InStock = true; cacheLoc.TaskId = taskInfo.ID; cacheLoc.EditTime = DateTime.Now; db.Updateable(cacheLoc).ExecuteCommand(); //WCS任务相关信息 taskInfo.Status = TaskStatus.FinishOfShunt; taskInfo.AddrNext = cacheLine.LocationNo.ToString(); taskInfo.EditWho = "WCS"; taskInfo.EditTime = DateTime.Now; taskInfo.GoodsType = obj.Data4.Length.ToInt(); db.Updateable(taskInfo).ExecuteCommand(); taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}"); return true; } } #endregion 跟据缓存信息寻找可以到达的缓存点 #region 初始化一个信息的缓存信息 //TODO:暂时不处理就近分线的逻辑 var devCode = cacheLineDevList.Select(x => x.Code.ToShort()).FirstOrDefault(x => !cacheLineList.Select(s => s.LocationNo).Contains(x)); if (devCode == 0) { World.Log($"无可用线体:{taskInfo.ID}"); return false; } var result = false; //未结束且包含当前物料编号的垛形,按时间排序,创建时间早的优先分配 var palletizingList = db.Queryable() .Includes(x => x.Layers, r => r.Rows, l => l.Locs) .Where(x => !x.Finish) .Where(x => x.MatCodeList.Contains(taskInfo.MatCode)) .OrderBy(x => x.AddTime) .ToList(); foreach (var palletizing in palletizingList) { //当前任务已经分配结束,进入下一次迭代 if (result) continue; //未结束且包含当前物料编号的层,按层号排序,层号小的优先分配 var layers = palletizing.Layers.Where(x => x is { IsEmpty: false, Finish: false }) .Where(x => x.MatCodeList.Contains(taskInfo.MatCode)) .OrderBy(x => x.LayerNo) .ToList(); //未找到可用层,进入下一次迭代 if (!layers.Any()) continue; foreach (var layer in layers) { //当前任务已经分配结束,进入下一次迭代 if (result) continue; //未结束,未预分配缓存线信息且包含当前物料编号的行,行号小的优先分配 var rows = layer.Rows.Where(x => x is { IsEmpty: false, Finish: false }) .Where(x => x.CacheLineId == 0) .Where(x => x.MatCodeList.Contains(taskInfo.MatCode)) .ToList(); //未找到可用行,进入下一次迭代 if (!rows.Any()) continue; var palletizingRow = rows.MinBy(x => x.RowNo); //开始初始化缓存位信息 cacheLine = new WCS_CacheLine() { LocationNo = devCode, AddTime = DateTime.Now, PalletizingRowId = palletizingRow.Id, InStock = false, Put = false, IsTruss = false, MatCodeList = palletizingRow.MatCodeList }; var res = db.Insertable(cacheLine).ExecuteReturnEntity(); palletizingRow = db.Queryable().Includes(x => x.Locs).Single(x => x.Id == palletizingRow.Id); palletizingRow.Locs = palletizingRow.Locs.OrderBy(x => x.XYNo).ToList(); palletizingRow.CacheLineId = res.Id; palletizingRow.EditTime = DateTime.Now; db.Updateable(palletizingRow).ExecuteCommand(); for (var i = 0; i < palletizingRow.Locs.Count; i++) { var loc = new WCS_CacheLineLoc() { XYNo = palletizingRow.Locs[i].XYNo, InStock = i == 0, IsEmpty = palletizingRow.Locs[i].IsEmpty, MatCode = palletizingRow.Locs[i].MatCode, TaskId = i == 0 ? taskInfo.ID : 0, CacheLineId = res.Id }; db.Insertable(loc).ExecuteCommand(); } taskInfo.Status = TaskStatus.FinishOfShunt; taskInfo.AddrNext = devCode.ToString(); taskInfo.EditWho = "WCS"; taskInfo.EditTime = DateTime.Now; taskInfo.GoodsType = obj.Data4.Length.ToInt(); db.Updateable(taskInfo).ExecuteCommand(); taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}"); result = true; } } if (!result) { taskInfo.InitStackStructure(db); } return result; ////找到所有当前轮子可以去的垛形 //var palletizingList = db.Queryable() // .Includes(x => x.Layers, r => r.Rows, l => l.Locs) // .Where(x => x.MatCodeList.Contains(taskInfo.MatCode) && !x.Finish).ToList() // .Where(x => x.Layers.SelectMany(x => x.Rows).Any(r => r.LineCode == null)) // .OrderBy(x => x.AddTime).ToList(); ////如果没有对应的垛形信息就初始化一个垛形信息 //if (palletizingList.Count <= 0) //{ // taskInfo.InitStackStructure(db); // return false; //} //var b = palletizingList.Select(palletizing => palletizing.Layers // .Where(x => !x.IsEmpty) // .Where(x => !x.Finish) // .Where(x => x.MatCodeList.Contains(taskInfo.MatCode)) // .Where(x => x.Rows.Any(r => r is { IsEmpty: false, Finish: false } && r.MatCodeList.Contains(taskInfo.MatCode) && r.CacheLineId == 0)) // .MinBy(x => x.LayerNo)).Where(x => x != null); //foreach (var palletizingLayer in b) //{ // //如果没有哪一层需要这个物料号,就初始化一个新的垛形信息 // if (palletizingLayer == null) // { // taskInfo.InitStackStructure(db); // return false; // } // //再找行:未空置、未结束 // var palletizingRow = palletizingLayer.Rows.Where(x => x is { IsEmpty: false, Finish: false } && x.MatCodeList.Contains(taskInfo.MatCode) && x.CacheLineId == 0) // .MinBy(x => x.RowNo); // //如果没有哪一行需要这个物料号,就初始化一个新的垛形信息 // if (palletizingRow == null) // { // taskInfo.InitStackStructure(db); // return false; // } // //走到这一步就表示没有哪一段线体缓存了当前物料,需要选一段新的线体进行缓存 // //TODO:暂时不处理就近分线的逻辑 // //获取一个当前可以使用的分配锁 // var devCode = cacheLineDevList.Select(x => x.Code.ToShort()).FirstOrDefault(x => !cacheLineList.Select(s => s.LocationNo).Contains(x)); // if (devCode == 0) // { // World.Log($"无可用线体:{taskInfo.ID}"); // return false; // } // //开始初始化缓存位信息 // cacheLine = new WCS_CacheLine() // { // LocationNo = devCode, // AddTime = DateTime.Now, // PalletizingRowId = palletizingRow.Id, // InStock = false, // Put = false, // IsTruss = false, // MatCodeList = palletizingRow.MatCodeList // }; // var res = db.Insertable(cacheLine).ExecuteReturnEntity(); // palletizingRow = db.Queryable().Includes(x => x.Locs).Single(x => x.Id == palletizingRow.Id); // palletizingRow.Locs = palletizingRow.Locs.OrderBy(x => x.XYNo).ToList(); // palletizingRow.CacheLineId = res.Id; // palletizingRow.EditTime = DateTime.Now; // db.Updateable(palletizingRow).ExecuteCommand(); // for (var i = 0; i < palletizingRow.Locs.Count; i++) // { // var loc = new WCS_CacheLineLoc() // { // XYNo = palletizingRow.Locs[i].XYNo, // InStock = i == 0, // IsEmpty = palletizingRow.Locs[i].IsEmpty, // MatCode = palletizingRow.Locs[i].MatCode, // TaskId = i == 0 ? taskInfo.ID : 0, // CacheLineId = res.Id // }; // db.Insertable(loc).ExecuteCommand(); // } // taskInfo.Status = TaskStatus.FinishOfShunt; // taskInfo.AddrNext = devCode.ToString(); // taskInfo.EditWho = "WCS"; // taskInfo.EditTime = DateTime.Now; // taskInfo.GoodsType = obj.Data4.Length.ToInt(); // db.Updateable(taskInfo).ExecuteCommand(); // taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}"); // return true; //} #endregion 初始化一个信息的缓存信息 } } }