using DBHelper; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using WCS.Core; using WCS.Entity; using WCS.Entity.Protocol; using WCS.Service.Entity; using WCS.Service.Extensions; using WCS.Service.Handlers; using WCS.Service.Helpers; using WCS.Service.Log; namespace WCS.Service.Works.Station { /// /// 涂布堆垛机放货分配目标地址 /// [WorkTitle(typeof(CoatingHandler), "涂布堆垛机放货分配目标地址")] public class 涂布堆垛机放货分配目标地址 : Work { protected override void Do(StationDeviceGroup obj) { obj.EX(stationDeviceGroup => { if (stationDeviceGroup.Items.Any(v => v.Data.VoucherNo != v.Data2.VoucherNo)) throw new WarnException($"等待执行任务,凭证号不一致"); if (stationDeviceGroup.Items.Any(v => v.Data3.Status.HasFlag(StationStatus.运行状态位))) throw new DoException("运行中"); //成功处理的任务 var finishTaskList = new List>(); DB.Do(db => { var devise = new List>(); foreach (var dev in stationDeviceGroup.Items) { //没有请求 if (dev.Data2.Request != IstationRequest.堆垛机放货完成请求目标地址) { InfoLog.INFO_INFO($"{stationDeviceGroup.Entity.CODE}无请求-堆垛机放货完成请求--4"); continue; } //没有光电 if (!dev.Data2.Status.HasFlag(IstationStatus.光电状态)) { InfoLog.INFO_WarnDb($"{dev.Entity.CODE}有请求无光电", stationDeviceGroup.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常); continue; }; devise.Add(new FinishTaskList(dev.Entity.CODE, dev.Entity.Create())); } foreach (var dev in devise) { var task = db.Default.Set().FirstOrDefault(v => v.TYPE == TaskType.出库 && v.SRMSTATION == dev.FinishCode && v.STATUS == TaskStatus.堆垛机完成) ?? throw new WarnException("无任务"); var tasks = db.Default.Set().Where(v => v.TaskGroupKey == task.TaskGroupKey); if (tasks.Any(v => v.STATUS != TaskStatus.堆垛机完成 && v.STATUS != TaskStatus.执行中)) throw new WarnException("任务异常,同组任务状态不为堆垛机完成或执行中"); task.STATUS = TaskStatus.执行中; task.CreateStatusLog(db, $"状态由[{TaskStatus.堆垛机完成}]变更为[{task.STATUS}]-{stationDeviceGroup.Entity.CODE}", this.GetType()); finishTaskList.Add(new FinishTaskList(task.ID, dev.Station)); } db.Default.SaveChanges(); }); DB.Do(db => { foreach (var finish in finishTaskList) { var task = db.Default.Set().FirstOrDefault(v => v.ID == finish.FinishCode); if (task == null) continue; finish.Station.Data.Tasknum = task.ID; finish.Station.Data.Goodsstart = finish.Station.Entity.CODE.ToShort(); finish.Station.Data.Goodsend = task.ADDRNEXT.ToShort(); finish.Station.Data.Goodsnum = finishTaskList.Count.ToShort(); finish.Station.Data.CmdType = IstationCmdType.堆垛机放货完成请求目标地址; finish.Station.Data.VoucherNo++; } }); }); } protected override bool SelectDevice(WCS_DEVICE dev) { return _devCodes.Contains(dev.CODE); } private readonly List _devCodes = new() { "G1283", "G1290", "G1292", "G1299", "G1301", "G1308", "G1310" }; } /// /// 涂布出库分配出库口 /// [WorkTitle(typeof(CoatingHandler), "涂布出库分配出库口")] public class 涂布出库分配出库口 : Work { protected override void Do(StationDeviceGroup obj) { obj.EX(stationDeviceGroup => { const string key = $"WCS:Lock:CoatingAllocationOutboundDeliveryPoint"; try { if (ProtocolProxy.YG150Redis.Get(key) != null) throw new WarnException($"[CoatingAllocationOutboundDeliveryPoint]--触发并发管控"); ProtocolProxy.YG150Redis.Set(key, key); if (stationDeviceGroup.Items.Any(v => v.Data.VoucherNo != v.Data2.VoucherNo)) throw new WarnException("等待执行任务,凭证号不一致"); if (stationDeviceGroup.Items.Any(v => v.Data3.Status.HasFlag(StationStatus.运行状态位))) throw new DoException("运行中"); var finishTaskList = new List>(); DB.Do(db => { var devise = new List>(); foreach (var dev in stationDeviceGroup.Items) { if (dev.Data2.Request != IstationRequest.请求分配目标地址) { InfoLog.INFO_INFO($"{stationDeviceGroup.Entity.CODE}无请求-分配目标地址--2"); continue; } if (!dev.Data2.Status.HasFlag(IstationStatus.光电状态)) { InfoLog.INFO_WarnDb($"{dev.Entity.CODE}有请求无光电", stationDeviceGroup.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常); continue; } if (dev.Data2.Tasknum < 10000) { InfoLog.INFO_WarnDb($"{dev.Entity.CODE}有请求有光电无任务", stationDeviceGroup.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常); continue; } devise.Add(new FinishTaskList(dev.Entity.CODE, dev.Entity.Create())); } //验证总数 if (db.Default.Set().Count(v => v.STATUS < TaskStatus.已完成 && v.ADDRNEXT == "G1") >= 3) throw new WarnException("总数已达3,流量管控"); foreach (var dev in devise) { var task = db.Default.Set().FirstOrDefault(v => v.ID == dev.Station.Data2.Tasknum) ?? throw new WarnException("无任务"); var tasks = db.Default.Set().Count(v => v.TaskGroupKey == task.TaskGroupKey); if (tasks != devise.Count) throw new WarnException($"可执行任务数{devise.Count},实际任务数{tasks}"); task.ADDRNEXT = "G1"; task.CreateStatusLog(db, $"分配目标地址{task.ADDRNEXT}", this.GetType()); finishTaskList.Add(new FinishTaskList(task.ID, dev.Station)); } db.Default.SaveChanges(); }); DB.Do(db => { foreach (var finish in finishTaskList) { var task = db.Default.Set().FirstOrDefault(v => v.ID == finish.FinishCode); if (task == null) continue; finish.Station.Data.Tasknum = task.ID; finish.Station.Data.Goodsstart = finish.Station.Entity.CODE.ToShort(); finish.Station.Data.Goodsend = task.ADDRNEXT.Replace("G", "").ToShort(); finish.Station.Data.Goodsnum = finishTaskList.Count.ToShort(); finish.Station.Data.GoodsSize = task.Length.ToShort(); finish.Station.Data.CmdType = IstationCmdType.分配目标地址; finish.Station.Data.VoucherNo++; } }); } finally { ProtocolProxy.YG150Redis.Del(key); } }); } protected override bool SelectDevice(WCS_DEVICE dev) { return _devCodes.Contains(dev.CODE); } private readonly List _devCodes = new() { "G5", "G7", "G9", "G11" }; } /// /// 涂布出库分配AGV取货点 /// [WorkTitle(typeof(CoatingHandler), "涂布出库分配AGV取货点")] public class 涂布出库分配AGV取货点 : Work { protected override void Do(StationDeviceGroup obj) { obj.EX(stationDeviceGroup => { //必须满足的条件 if (stationDeviceGroup.Items.Any(v => v.Data2.VoucherNo != v.Data.VoucherNo)) throw new WarnException("凭证号不一致"); if (stationDeviceGroup.Items.Any(v => v.Data3.Status.HasFlag(StationStatus.运行状态位))) throw new DoException("设备运行中"); //成功处理的任务 var finishTaskList = new List>(); DB.Do(db => { var devise = new List>(); //获取需要执行的设备信息 foreach (var dev in stationDeviceGroup.Items) { if (!dev.Data3.Status.HasFlag(StationStatus.低位)) { InfoLog.INFO_INFO($"{dev.Entity.CODE}--不在低位"); continue; } if (!dev.Data2.Status.HasFlag(IstationStatus.光电状态)) { InfoLog.INFO_INFO($"{dev.Entity.CODE}--没有光电"); continue; } if (dev.Data2.Request != IstationRequest.请求分配目标地址) { InfoLog.INFO_WarnDb($"{dev.Entity.CODE}--有光电没有分配目标地址请求--2", stationDeviceGroup.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常); continue; }; if (dev.Data2.Tasknum < 10000) { InfoLog.INFO_WarnDb($"{dev.Entity.CODE}--有光电有请求没有任务号", stationDeviceGroup.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常); continue; } devise.Add(new FinishTaskList(dev.Entity.CODE, dev.Entity.Create())); } if (!devise.Any()) return; //无可执行任务 //验证可执行任务数与有效任务数是否一致 var taskIds = devise.Select(dev => dev.Station.Data2.Tasknum).ToList(); var taskList = db.Default.Set().Where(v => taskIds.Contains(v.ID)).ToList(); var task1 = taskList.FirstOrDefault(); var taskCount = db.Default.Set().Count(v => v.TaskGroupKey == task1.TaskGroupKey && v.TYPE == TaskType.出库); //开始检查任务数是否匹配 if (devise.Count != taskCount) throw new WarnException($"可执行数{devise.Count},任务组任务数{taskCount},数量不匹配,{task1?.ID}-{task1?.TaskGroupKey}"); var stationList = new List>(); //开始处理需要分配目标地址的设备 foreach (var dev in devise) { var task = db.Default.Set().FirstOrDefault(v => v.ID == dev.Station.Data2.Tasknum) ?? throw new WarnException($"WCS无[{dev.Station.Data2.Tasknum}]任务信息"); var addNext = ""; switch (dev.Station.Entity.CODE) { case "1340": { var station1343 = Device.Find("1343").Create(); addNext = "1343"; if (!station1343.Data3.Status.HasFlag(StationStatus.自动) || station1343.Data2.Tasknum > 10000) addNext = "1340"; break; } case "1341": { var station1344 = Device.Find("1344").Create(); addNext = "1344"; if (!station1344.Data3.Status.HasFlag(StationStatus.自动) || station1344.Data2.Tasknum > 10000) addNext = "1341"; break; } } task.ADDRNEXT = addNext; task.CreateStatusLog(db, $"状态由[{WCS.Entity.TaskStatus.堆垛机完成}]变更为[{task.STATUS}]-{stationDeviceGroup.Entity.CODE}", this.GetType()); finishTaskList.Add(new FinishTaskList(task.ID, dev.Station)); stationList.Add(new FinishTaskList(task, dev.Station)); } #region 校验两个地址是否一致 if (stationList.Count == 2) { stationList = stationList.OrderBy(v => v.FinishCode.ADDRNEXT.ToShort()).ToList(); var task3 = stationList[0]; var task4 = stationList[1]; switch (task3.FinishCode.ADDRNEXT) { case "1343" when task4.FinishCode.ADDRNEXT == "1344": break; case "1340" when task4.FinishCode.ADDRNEXT == "1341": break; default: { var devise1 = stationList.Select(v => v.Station); foreach (var dev in devise1) { if (!dev.Data3.Status.HasFlag(StationStatus.自动)) throw new WarnException($"{dev.Entity.CODE}--不是自动"); if (dev.Data2.Tasknum > 10000) throw new WarnException($"{dev.Entity.CODE}--已有任务"); } break; } } } #endregion 校验两个地址是否一致 db.Default.SaveChanges(); }); DB.Do(db => { foreach (var finish in finishTaskList) { var task = db.Default.Set().FirstOrDefault(v => v.ID == finish.FinishCode) ?? throw new WarnException($"已完成DB任务变更,但写入PLC信息是找不到任务{finish.FinishCode}"); finish.Station.Data.Tasknum = task.ID; finish.Station.Data.Goodsstart = finish.Station.Entity.CODE.ToShort(); finish.Station.Data.Goodsend = task.ADDRNEXT.ToShort(); finish.Station.Data.GoodsSize = task.Length.ToShort(); finish.Station.Data.Goodsnum = finishTaskList.Count.ToShort(); finish.Station.Data.CmdType = IstationCmdType.分配目标地址; finish.Station.Data.VoucherNo++; InfoLog.INFO_AGV($"出库分配AGV取货点[{finish.FinishCode}]-[{finish.Station.Data.Goodsend}]"); } }); }); } protected override bool SelectDevice(WCS_DEVICE dev) { return dev.CODE == "G1340"; } } /// /// 涂布出库返回任务长度 /// [WorkTitle(typeof(CoatingHandler), "涂布出库返回任务长度")] public class 涂布出库返回任务长度 : Work { protected override void Do(StationDeviceGroup obj) { obj.EX(stationDeviceGroup => { //必须满足的条件 if (stationDeviceGroup.Items.Any(v => v.Data2.VoucherNo != v.Data.VoucherNo)) throw new WarnException("凭证号不一致"); if (stationDeviceGroup.Items.Any(v => v.Data3.Status.HasFlag(StationStatus.运行状态位))) throw new DoException("设备运行中"); //成功处理的任务 DB.Do(db => { var devise = new List>(); //获取需要执行的设备信息 foreach (var dev in stationDeviceGroup.Items) { if (dev.Data2.Request != IstationRequest.请求分配目标地址) { InfoLog.INFO_INFO($"{stationDeviceGroup.Entity.CODE}无请求-分配目标地址--2"); continue; } if (!dev.Data2.Status.HasFlag(IstationStatus.光电状态)) { InfoLog.INFO_WarnDb($"{dev.Entity.CODE}有请求无光电", stationDeviceGroup.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常); continue; } if (dev.Data2.Tasknum < 10000) { InfoLog.INFO_WarnDb($"{dev.Entity.CODE}有请求有光电无任务", stationDeviceGroup.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常); continue; } devise.Add(new FinishTaskList(dev.Entity.CODE, dev.Entity.Create())); } if (!devise.Any()) return;//无可执行任务 //验证可执行任务数与有效任务数是否一致 var taskIds = devise.Select(dev => dev.Station.Data2.Tasknum).ToList(); var taskList = db.Default.Set().Where(v => taskIds.Contains(v.ID)).ToList(); var taskCount = db.Default.Set().Count(v => v.TaskGroupKey == taskList.FirstOrDefault().TaskGroupKey && v.TYPE == TaskType.出库); if (devise.Count != taskCount) throw new WarnException($"可执行数{devise.Count},任务组任务数{taskCount},数量不匹配"); //开始处理需要分配目标地址的设备 foreach (var dev in devise) { var task = db.Default.Set().Find(dev.Station.Data2.Tasknum); if (task == null) throw new WarnException("WCS无该任务信息"); task.ADDRNEXT = "G1340"; dev.Station.Data.GoodsSize = task.Length.ToShort(); dev.Station.Data.VoucherNo++; } db.Default.SaveChanges(); }); }); } protected override bool SelectDevice(WCS_DEVICE dev) { return dev.CODE == "G1334"; } } /// /// 涂布叫料 /// [WorkTitle(typeof(CoatingHandler), "涂布叫料")] public class 涂布叫料 : Work { protected override void Do(StationDeviceGroup obj) { obj.EX(stationDeviceGroup => { #region 处理新增叫料任务 DB.Do(db => { //找到所有的AGV任务 var agvTasks = db.Default.Set().Where(v => v.TaskType == AGVTaskType.叫料) .Where(v => v.Status < AGVTaskStatus.完成).ToArray(); foreach (var tasking in agvTasks) { var position = tasking.Position; if (!ProtocolProxy.AllDatas.ContainsKey(position)) ProtocolProxy.AllDatas[position] = new ProdLineData(); var pld = ProtocolProxy.AllDatas[position] as ProdLineData; pld!.Frame = LogicHandler.Frame; pld.Code = position; pld.TaskList.Add(tasking); if (tasking.Status == AGVTaskStatus.新建) { if (stationDeviceGroup.Entity.CODE != "G1340") continue; var qty = db.Default.Set().Where(v => v.TaskType == AGVTaskType.叫料 && v.Status > AGVTaskStatus.新建 && v.Status < AGVTaskStatus.完成).Count(v => v.Position == tasking.Position); if (qty >= 4) { InfoLog.INFO_WarnDb($"{tasking.Position}正在执行的叫料任务数量已达{qty},暂停出库", stationDeviceGroup.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常); continue; }; //涂布叫料默认目标地址G1340,到达G1340后再决定是否要继续前进一步 List res; try { res = WMS.GetOutTask(tasking.Position.Replace("_OUT", ""), "G1340"); } catch (WarnException ex) { InfoLog.INFO_WarnDb($"{ex.Message}", stationDeviceGroup.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常); continue; }; res.ForEach(outTask => { var srm = Device.Find(outTask.TunnelNum).ROUTES.Where(v => v.NEXT.IsSC()).Select(v => v.NEXT).FirstOrDefault(); var loc = $"{outTask.Row}-{outTask.Colomn}-{outTask.Layer}"; var task = new WCS_TASK { TYPE = TaskType.出库, STATUS = WCS.Entity.TaskStatus.新建, ADDRFROM = loc, ADDRTO = "G1340", BARCODE = outTask.ContainerBarCode, TUNNEL = outTask.TunnelNum, WMSTASK = int.Parse(outTask.WMSTaskNum), UPDATEUSER = "WCS", SRMSTATION = "", DEVICE = srm?.CODE, AgvTask = tasking.ID, Length = outTask.Length, FLOOR = 2 }; task.TaskGetSrmStation(); db.Default.Set().Add(task); tasking.Status = AGVTaskStatus.确认; tasking.UpdateTime = DateTime.Now; db.Default.SaveChanges(); tasking.AGVStatusChange(AGVTaskStatus.确认, "变更"); }); return; } else if (tasking.AGVStatus == AGVTaskStatus.完成) { tasking.Status = tasking.AGVStatus; tasking.UpdateTime = DateTime.Now; db.Default.SaveChanges(); tasking.AGVStatusChange(tasking.AGVStatus); } else if (tasking.AGVStatus == AGVTaskStatus.取消) { tasking.Status = tasking.AGVStatus; tasking.UpdateTime = DateTime.Now; db.Default.SaveChanges(); tasking.AGVStatusChange(tasking.AGVStatus); } } }); #endregion 处理新增叫料任务 //空闲自动,停止运行 if (stationDeviceGroup.Items.Any(v => v.Data2.VoucherNo != v.Data.VoucherNo)) throw new WarnException("等待执行任务"); if (stationDeviceGroup.Items.Any(v => !v.Data3.Status.HasFlag(StationStatus.自动))) return; if (stationDeviceGroup.Items.Any(v => v.Data3.Status.HasFlag(StationStatus.运行状态位))) throw new WarnException("设备运行中"); var taskIds = new List(); stationDeviceGroup.Items.ToList().ForEach(dev => taskIds.Add(dev.Data2.Tasknum)); DB.Do(db => { var taskList = db.Default.Set().Where(v => taskIds.Contains(v.ID)); if (!taskList.Any()) return; if (taskList == null) throw new WarnException($"WCS任务号{JsonConvert.SerializeObject(taskIds)}不存在"); if (taskList.Any(v => v.TYPE != TaskType.出库)) throw new WarnException("有任务的类型不是出库"); if (taskList.Any(v => v.AgvTask == 0)) throw new WarnException("人工出库任务,请手动搬走"); var agvtask = db.Default.Set().Find(taskList.FirstOrDefault().AgvTask); if (agvtask == null) throw new WarnException($"AGV任务号{taskList.FirstOrDefault().AgvTask}不存在"); if (taskList.Count() != db.Default.Set().Count(v => v.TaskGroupKey == taskList.FirstOrDefault().TaskGroupKey && v.TYPE == TaskType.出库)) throw new WarnException("可执行任务数与实际任务数不符"); if (agvtask.Status == AGVTaskStatus.确认) { if (!stationDeviceGroup.Items.Any(v => v.Data3.Status.HasFlag(StationStatus.高位))) throw new WarnException("不在高位"); var flag = db.Default.Set() .Where(v => v.TaskType == AGVTaskType.叫料).Count(v => v.Status > AGVTaskStatus.确认 && v.Status < AGVTaskStatus.取放完成); if (flag >= 2) throw new Exception("有2未完成的AGV出库任务"); taskList.ToList().ForEach(task => { task.STATUS = WCS.Entity.TaskStatus.已完成; task.UPDATETIME = DateTime.Now; task.ENDTIME = DateTime.Now; }); agvtask.Station = stationDeviceGroup.Entity.CODE; agvtask.Status = AGVTaskStatus.执行; agvtask.UpdateTime = DateTime.Now; db.Default.SaveChanges(); agvtask.AGVStatusChange(AGVTaskStatus.执行, "变更"); } else if (agvtask.Status < agvtask.AGVStatus) { if (agvtask.AGVStatus == AGVTaskStatus.请求_允许) { if (!stationDeviceGroup.Items.Any(v => v.Data3.Status.HasFlag(StationStatus.高位))) throw new WarnException("不在高位"); if (agvtask.Status < AGVTaskStatus.执行) throw new WarnException($"AGV状态错误-{agvtask.Status}"); if (stationDeviceGroup.Items.Any(v => v.Data2.Status.HasFlag(IstationStatus.AGV取货完成信号))) throw new WarnException("任务清零信号未清除"); if (!stationDeviceGroup.Items.Any(v => v.Data2.Tasknum > 10000 && v.Data2.Status.HasFlag(IstationStatus.光电状态))) throw new DoException("没有设备有任务且有光电"); agvtask.Status = agvtask.AGVStatus; agvtask.UpdateTime = DateTime.Now; db.Default.SaveChanges(); agvtask.AGVStatusChange(agvtask.AGVStatus); } else if (agvtask.AGVStatus == AGVTaskStatus.取放完成) { if (stationDeviceGroup.Items.Any(v => v.Data2.Status.HasFlag(IstationStatus.AGV取货完成信号))) throw new WarnException("任务清零信号未清除"); if (stationDeviceGroup.Items.Any(v => v.Data2.Status.HasFlag(IstationStatus.光电状态))) throw new WarnException("AGV取货完成后依然有光电信号"); if (agvtask.Status < AGVTaskStatus.请求_允许) throw new WarnException("AGV任务状态有误"); agvtask.Status = agvtask.AGVStatus; agvtask.UpdateTime = DateTime.Now; db.Default.SaveChanges(); agvtask.AGVStatusChange(agvtask.AGVStatus); foreach (var dev in stationDeviceGroup.Items) { dev.Data.Istation521Status = IstationStatus.AGV取货完成信号; } } } }); }); } protected override bool SelectDevice(WCS_DEVICE dev) { return dev.CODE == "G1340" || dev.CODE == "G1343"; } } }