using HH.WCS.Mobox3.DoubleCoin.device; using HH.WCS.Mobox3.DoubleCoin.models; using HH.WCS.Mobox3.DoubleCoin.util; using HH.WCS.Mobox3.DoubleCoin.wms; using Newtonsoft.Json; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace HH.WCS.Mobox3.DoubleCoin.core { /// /// 定时轮询任务 /// internal class Monitor { /// /// 满托下线入库,空托出库上线 /// internal static void CheckS7Devices() { if (S7Helper.ip_Plc.Count <= 0 || Settings.ProductionLines.Count <= 0) { LogHelper.Info($"没有配置S7设备信息,CheckDevices跳过", "PLC"); return; } S7Helper.RestLink(); foreach (var plcD in Settings.ProductionLines)//遍历每个产线 { Task task = Task.Run(() => { if (Settings.S7TestMoni) { LogHelper.Info($"配置文件中S7TestMoni为True,已跳过原材料生产线S7通讯的自动任务生成,如果生产线可以使用,S7TestMoni改为false"); return; } CheckDeciveModel result = new CheckDeciveModel(); var db = new SqlHelper().GetInstance(); byte[] readBytes1; try { if (S7Helper.WriteBytes(plcD.ProductionLine_IP, 10, 4, new byte[] { 1 })) { LogHelper.Info($"产线{result.LineIP}写入DB10的偏移4为1,P2_Turn on the signal = 1,成功"); } else { LogHelper.Info($"产线{result.LineIP}写入DB10的偏移4为1,P2_Turn on the signal = 1,失败"); } Task.Delay(500); // 延迟 0.5 秒,让它称重 //通过S7协议获取下位机信号 result.LineIP = plcD.ProductionLine_IP; readBytes1 = S7Helper.ReadBytes(plcD.ProductionLine_IP, 20, 0, 13); if (readBytes1 == null) { LogHelper.Info($"读取S7_PLC信息为空" + plcD.ProductionLine_IP, "PLC"); return; } result.Heart = ((readBytes1[0]) << 8) + readBytes1[1]; byte[] rfid = new byte[4] { readBytes1[2], readBytes1[3], readBytes1[4], readBytes1[5] }; string rfids16 = BitConverter.ToString(rfid); string rfids = (((readBytes1[2]) << 24) + (readBytes1[3] << 16) + (readBytes1[4] << 8) + readBytes1[5]).ToString(); LogHelper.Info($"产线容器号:{rfids},其16进制形式:{rfids16}"); result.RfidData = rfids; result.AgvAllow = (((readBytes1[6]) << 8) + readBytes1[7]); result.TaskProperties = readBytes1[8]; result.Ready = readBytes1[9]; result.CargoStatus = readBytes1[10]; result.StationStatus = readBytes1[11]; result.DestinationRequests = readBytes1[12]; result.BarcodeCode = S7Helper.ReadString(plcD.ProductionLine_IP, 20, 14, 10); var readBytes2 = S7Helper.ReadBytes(plcD.ProductionLine_IP, 20, 26, 2); result.Weight = ((readBytes2[0]) << 8) + readBytes2[1]; LogHelper.Info($"PLC解析后详细信息,{JsonConvert.SerializeObject(result)}"); } catch (Exception ex) { LogHelper.Info($"读取S7_PLC信息异常:{ex.Message}" + plcD.ProductionLine_IP, "Error"); return; } //生成满托下线入库任务 if (result.AgvAllow == 21 && result.Ready == 1 && result.DestinationRequests == 1) { LogHelper.Info($"触发开始生成满托下线入库任务"); //该产线的满托下线位置,起点 var startPoint = Settings.ProductionLines.FirstOrDefault(a => a.ProductionLine_IP == result.LineIP); if (startPoint != null)//起点存在 { var woInfo = db.Queryable().Where(a => a.S_LINE_NO == startPoint.ProductionLine_Name && a.S_B_STATE == "开启").OrderBy(b => b.T_CREATE, OrderByType.Desc).First(); if (woInfo != null)//当前产线不存在开启的最新的工单 { var startLoc = db.Queryable().First(a => a.S_LOCK_STATE == "无" && a.N_LOCK_STATE == 0 && a.S_CODE == startPoint.PointOut && a.C_ENABLE == "Y"); if (startLoc != null)//该产线的起点没锁住 { var modelCI = db.Queryable().First(i => i.S_CNTR_CODE == result.RfidData && i.S_B_STATE == "0");//查询是否有这个对应的且状态正常的容器车号子表 if (modelCI != null)//容器车号子表存在 { var cgInfo = db.Queryable().First(a => a.S_CNTR_CODE == result.RfidData); if (cgInfo != null)//有残留的容器货品明细关系表信息 { LogHelper.Info($"容器{result.RfidData}已绑定货品{cgInfo.S_ITEM_CODE},如果是其他库区的容器,想要使用,先解绑"); } else { var locCntrRel = db.Queryable().First(a => a.S_CNTR_CODE == result.RfidData); if (locCntrRel != null)//当前容器是否绑定了货位,绑定了就删除旧的再新增 { LogHelper.Info($"容器{result.RfidData}已绑定货位{locCntrRel.S_LOC_CODE},如果是其他库区的容器,想要使用,先解绑"); } else { var endLoc = db.Queryable(). Where(c => c.S_AREA_CODE == Settings.Areas[1] && c.S_LOCK_STATE == "无" && c.N_LOCK_STATE == 0 && c.N_CURRENT_NUM == 0 && SqlFunc.Subqueryable().Where(b => b.S_LOC_CODE == c.S_CODE).NotAny()//不能有货 && c.C_ENABLE == "Y"). OrderBy(o => o.T_MODIFY, OrderByType.Asc).First();//查询合适的终点货位,直接判断当前数量为0即可 if (endLoc != null) { //新增货位容器关系表 locCntrRel = new TN_Loc_Container() { S_LOC_CODE = startPoint.PointOut, S_CNTR_CODE = result.RfidData, }; TN_CG_Detail tN_CG_Detail = new TN_CG_Detail()//新增容器货品明细表 { S_CNTR_CODE = result.RfidData, S_ITEM_CODE = woInfo.S_ITEM_CODE, S_BATCH_NO = woInfo.S_BATCH_CODE, S_ITEM_SPEC = woInfo.S_ITEM_SPEC, S_SPE = woInfo.S_ITEM_SPEC, S_CAR_CODE = modelCI.S_CAR_CODE, N_ITEM_STATE = 1, S_ITEM_STATE = "待检", F_QTY = result.Weight,//这里的重量要当成数量来使用 }; var task1 = new TN_Task() { S_CODE = WCSHelper.GenerateTaskNo(), S_START_AREA = startLoc.S_AREA_CODE, S_END_AREA = endLoc.S_AREA_CODE, S_START_LOC = startLoc.S_CODE, S_END_LOC = endLoc.S_CODE, S_TYPE = "PLC满托下线入库", N_B_STATE = 0, S_B_STATE = "等待", S_CNTR_CODE = result.RfidData, S_SPEC = woInfo.S_ITEM_SPEC, }; startLoc.N_LOCK_STATE = 2; startLoc.S_LOCK_STATE = "出库锁"; startLoc.N_CURRENT_NUM = 1; startLoc.T_MODIFY = System.DateTime.Now; endLoc.N_LOCK_STATE = 1; endLoc.S_LOCK_STATE = "入库锁"; endLoc.T_MODIFY = System.DateTime.Now; using (var tran = db.Ado.UseTran()) { if (db.Insertable(task1).ExecuteCommand() > 0 && db.Updateable(startLoc).ExecuteCommand() > 0 && db.Updateable(endLoc).ExecuteCommand() > 0 && db.Insertable(locCntrRel).ExecuteCommand() > 0 && db.Insertable(tN_CG_Detail).ExecuteCommand() > 0)//创建搬送任务,起点终点容器 { tran.CommitTran(); LogHelper.Info($"生成满托下线入库任务成功,容器:{modelCI.S_CNTR_CODE},起点:{startPoint.PointOut},终点:{endLoc.S_CODE}"); Task task98 = Task.Run(() => { var target = new TN_EquipProDetail() { S_ID = tN_CG_Detail.S_ID, TASKTYPE = "PLC满托下线入库", RFID = result.RfidData, SPEC = woInfo.S_ITEM_SPEC, CARCODE = modelCI.S_CAR_CODE, WEIGHT = result.Weight, ITEMSTATE = "待检", ITEMCODE = woInfo.S_ITEM_CODE, LOGINNAME = woInfo.S_LINE_NO, SHIFT = "None", STARTLOC = startLoc.S_CODE, }; SpecHelper.InsertEquipProDetail(target); }); Task task27 = Task.Run(() => { var target = new TN_InventoryM() { S_ID = tN_CG_Detail.S_ID, RFID = result.RfidData, SPEC = woInfo.S_ITEM_SPEC, WEIGHT = result.Weight, ITEMSTATE = "待检", ITEMCODE = woInfo.S_ITEM_CODE, LOGINNAME = woInfo.S_LINE_NO, SHIFT = "None", }; SpecHelper.InsertInventoryM(target); }); } else { tran.RollbackTran(); LogHelper.Info($"生成满托下线入库任务失败,容器:{modelCI.S_CNTR_CODE},起点:{startPoint.PointOut},终点:{endLoc.S_CODE}"); } } } else { LogHelper.Info($"未找到合适的终点,容器:{modelCI.S_CNTR_CODE},需要满足:有未锁定的,当前数量为0的,属于{Settings.Areas[1]}的货位"); } } } } else { LogHelper.Info($"未找到对应的容器车号子表信息,容器{result.RfidData}"); } } else { LogHelper.Info($"此起点位置:{startPoint.PointOut}已锁住"); } } else { LogHelper.Info($"当前产线{startPoint.ProductionLine_Name}位置{startPoint.PointOut}没有开启的工单"); } } else { LogHelper.Info($"未在配置文件里找到该产线{result.LineIP}起点PointOut"); } } else { LogHelper.Info($"生成满托下线入库任务失败,不满足result.AgvAllow == 21 && result.Ready == 1 && result.DestinationRequests == 1"); } if (result.AgvAllow == 11 && result.Ready == 1) { LogHelper.Info($"触发开始生成空托出库上线任务"); var endPoint = Settings.ProductionLines.FirstOrDefault(a => a.ProductionLine_IP == result.LineIP); if (endPoint == null) { LogHelper.Info($"未找到配置信息,产线IP:{result.LineIP}"); return; } var endLoc = db.Queryable().//空托上线的终点不校验是否有货 First(a => a.S_CODE == endPoint.PointIn && a.S_LOCK_STATE == "无" && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y"); if (endLoc == null) { LogHelper.Info($"此位置:{endPoint.PointIn}已锁住或未启用"); return; } if (endLoc.N_CURRENT_NUM > 0) { LocationHelper.ErrorLocCntReset(new ErrorLocCntResetInfo() { locID = endPoint.PointIn, reqCode = 1 }); LogHelper.Info($"终点货位{endPoint.PointIn}容器数量不为0,已重置该货位"); } var startLoc = db.Queryable(). Where(o => o.S_AREA_CODE == Settings.Areas[4] && o.N_LOCK_STATE == 0 && o.S_LOCK_STATE == "无" && o.C_ENABLE == "Y" && o.N_CURRENT_NUM > 0). OrderBy(o => o.N_CURRENT_NUM, OrderByType.Desc). First(); if (startLoc == null) { LogHelper.Info($"未在{Settings.Areas[4]}找到合适的起点,需要满足:货位当前数量大于0,货位未锁定"); return; } var cntrList = db.Queryable().Where(a => a.S_LOC_CODE == startLoc.S_CODE).ToList(); if (cntrList.Count == 0) { LogHelper.Info($"起点货位{startLoc.S_CODE}未找到货位容器关系表信息"); return; } string cntrString = ""; for (int i = 0; i < cntrList.Count; i++) { if (i == cntrList.Count - 1)//最后一个字符串连接不加逗号 { cntrString += cntrList[i].S_CNTR_CODE; } else { cntrString += cntrList[i].S_CNTR_CODE + ","; } } if (WCSHelper.CreateTask(startLoc.S_CODE, endPoint.PointIn, "空托出库入线", 3, cntrString))//创建搬送任务,起点终点容器 { LocationHelper.LockLoc(startLoc.S_CODE, 2);//起点出库锁, LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁 LogHelper.Info($"生成空托出库上线任务成功,容器:{cntrString},起点:{startLoc.S_CODE}"); } else { LogHelper.Info($"生成空托出库上线任务失败,容器:{cntrString},起点:{startLoc.S_CODE}"); } } else { LogHelper.Info($"生成空托出库上线任务失败,不满足result.AgvAllow == 11 && result.Ready == 1"); } }); task.Wait(1000); } } /// /// 在复检区检测物品合格,合格的物品自动回库 /// internal static void CGOkCheck() { var db = new SqlHelper().GetInstance(); try { var startLoc = db.Queryable() .LeftJoin((o, i) => o.S_CODE == i.S_LOC_CODE) .LeftJoin((o, i, s) => i.S_CNTR_CODE == s.S_CNTR_CODE) .Where((o, i, s) => s.N_ITEM_STATE == 0 && s.S_ITEM_STATE == "合格" && o.S_AREA_CODE == Settings.Areas[7] && o.N_CURRENT_NUM > 0 && o.N_LOCK_STATE == 0 && o.S_LOCK_STATE == "无").First(); if (startLoc== null) { LogHelper.Info("复检区没有合格的物品,无需自动返回"); return; } var endLoc = db.Queryable().First(a => a.S_AREA_CODE == Settings.Areas[1] && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && SqlFunc.Subqueryable().Where(b => b.S_LOC_CODE == a.S_CODE).NotAny()//不能有货 ); if (endLoc == null) { LogHelper.Info("终点库区已满或者已全部锁住"); return; } var cginfo = db.Queryable() .LeftJoin((o, i) => o.S_CNTR_CODE == i.S_CNTR_CODE) .Where((o, i) => i.S_LOC_CODE == startLoc.S_CODE).First(); if (WCSHelper.CreateTask(startLoc.S_CODE, endLoc.S_CODE, "复检合格自动回库", 3, cginfo.S_CNTR_CODE, out string taskNo, cginfo.S_SPE))//创建搬送任务,起点终点容器 { LocationHelper.LockLoc(startLoc.S_CODE, 2);//起点出库锁, LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁 LogHelper.Info($"生成复检合格自动回库任务成功,容器号{cginfo.S_CNTR_CODE},起点{startLoc.S_CODE},终点{endLoc.S_CODE}"); Task task99 = Task.Run(() => { WMSHelper.InsertOpInfo("自动轮询", "复检合格自动回库", cginfo.S_CNTR_CODE); }); Task task27 = Task.Run(() => { var target = new TN_InventoryM() { S_ID = cginfo.S_ID, RFID = cginfo.S_CNTR_CODE, SPEC = cginfo.S_SPE, WEIGHT = cginfo.F_QTY, ITEMSTATE = cginfo.S_ITEM_STATE, ITEMCODE = cginfo.S_ITEM_CODE, LOGINNAME = "自动轮询", SHIFT = "无", }; SpecHelper.InsertInventoryM(target); }); return ; } else { LogHelper.Info($"生成复检合格自动回库任务失败,容器号{cginfo.S_CNTR_CODE},起点{startLoc.S_CODE},终点{endLoc.S_CODE}"); return; } } catch(Exception ex) { LogHelper.Error("CGOkCheck发生了异常", ex); } } /// /// 满托过期出库 过期合格回库,过期次品回炉 /// internal static void FullOutTime() { try { var db = new SqlHelper().GetInstance(); //满托过期出库 var startLoc_1 = db.Queryable() .LeftJoin((o, i) => o.S_CODE == i.S_LOC_CODE) .LeftJoin((o, i, s) => i.S_CNTR_CODE == s.S_CNTR_CODE) .Where((o, i, s) => s.N_ITEM_STATE == 3 && s.S_ITEM_STATE == "过期" && o.S_AREA_CODE == Settings.Areas[1] && o.N_CURRENT_NUM > 0 && o.N_LOCK_STATE == 0 && o.S_LOCK_STATE == "无").First(); if (startLoc_1 != null) { var endLoc_1 = db.Queryable() .Where(o => o.S_AREA_CODE == Settings.Areas[12] && SqlFunc.Subqueryable().Where(b => b.S_LOC_CODE == o.S_CODE).NotAny()//不能有货 && o.N_CURRENT_NUM == 0 && o.N_LOCK_STATE == 0 && o.S_LOCK_STATE == "无").First(); if (endLoc_1 != null) { var cntCode = db.Queryable().First(a => a.S_LOC_CODE == startLoc_1.S_CODE); var outTimeCg = db.Queryable().First(a => a.S_CNTR_CODE == cntCode.S_CNTR_CODE); if (WCSHelper.CreateTask(startLoc_1.S_CODE, endLoc_1.S_CODE, "满托过期出库", 3, outTimeCg.S_CNTR_CODE, outTimeCg.S_SPE)) { LocationHelper.LockLoc(startLoc_1.S_CODE, 2);//起点出库锁, LocationHelper.LockLoc(endLoc_1.S_CODE, 1);//终点入库锁 LogHelper.Info($"生成满托过期出库任务成功,容器号{outTimeCg.S_CNTR_CODE},起点{startLoc_1.S_CODE},终点{endLoc_1.S_CODE}"); Task task27 = Task.Run(() => { SpecHelper.DeleteInventoryM(outTimeCg.S_ID); }); } } } //过期合格回库 var startLoc_2 = db.Queryable() .LeftJoin((o, i) => o.S_CODE == i.S_LOC_CODE) .LeftJoin((o, i, s) => i.S_CNTR_CODE == s.S_CNTR_CODE) .Where((o, i, s) => s.N_ITEM_STATE == 0 && s.S_ITEM_STATE == "合格" && o.S_AREA_CODE == Settings.Areas[12] && o.N_CURRENT_NUM > 0 && o.N_LOCK_STATE == 0 && o.S_LOCK_STATE == "无").First(); if (startLoc_2 != null) { var endLoc_2 = db.Queryable() .Where(o => o.S_AREA_CODE == Settings.Areas[2] && SqlFunc.Subqueryable().Where(b => b.S_LOC_CODE == o.S_CODE).NotAny()//不能有货 && o.N_CURRENT_NUM == 0 && o.N_LOCK_STATE == 0 && o.S_LOCK_STATE == "无").First(); if (endLoc_2 != null) { var cntCode = db.Queryable().First(a => a.S_LOC_CODE == startLoc_2.S_CODE); var outTimeCg = db.Queryable().First(a => a.S_CNTR_CODE == cntCode.S_CNTR_CODE); if (WCSHelper.CreateTask(startLoc_2.S_CODE, endLoc_2.S_CODE, "过期合格回库", 3, outTimeCg.S_CNTR_CODE, outTimeCg.S_SPE)) { LocationHelper.LockLoc(startLoc_2.S_CODE, 2);//起点出库锁, LocationHelper.LockLoc(endLoc_2.S_CODE, 1);//终点入库锁 Task task27 = Task.Run(() => { var target = new TN_InventoryM() { S_ID = outTimeCg.S_ID, RFID = outTimeCg.S_CNTR_CODE, SPEC = outTimeCg.S_SPE, WEIGHT = outTimeCg.F_QTY, ITEMSTATE = outTimeCg.S_ITEM_STATE, ITEMCODE = outTimeCg.S_ITEM_CODE, LOGINNAME = "过期合格回库轮询", SHIFT = "None", }; SpecHelper.InsertInventoryM(target); }); LogHelper.Info($"生成过期合格回库任务成功,容器号{outTimeCg.S_CNTR_CODE},起点{startLoc_2.S_CODE},终点{endLoc_2.S_CODE}"); } } } //过期次品回炉 var startLoc_3 = db.Queryable() .LeftJoin((o, i) => o.S_CODE == i.S_LOC_CODE) .LeftJoin((o, i, s) => i.S_CNTR_CODE == s.S_CNTR_CODE) .Where((o, i, s) => s.N_ITEM_STATE == 2 && s.S_ITEM_STATE == "不合格" && o.S_AREA_CODE == Settings.Areas[12] && o.N_CURRENT_NUM > 0 && o.N_LOCK_STATE == 0 && o.S_LOCK_STATE == "无").First(); if (startLoc_3 != null) { var endLoc_3 = db.Queryable() .Where(o => o.S_AREA_CODE == Settings.Areas[11] && SqlFunc.Subqueryable().Where(b => b.S_LOC_CODE == o.S_CODE).NotAny()//不能有货 && o.N_CURRENT_NUM == 0 && o.N_LOCK_STATE == 0 && o.S_LOCK_STATE == "无").First(); if (endLoc_3 != null) { var cntCode = db.Queryable().First(a => a.S_LOC_CODE == startLoc_3.S_CODE); var outTimeCg = db.Queryable().First(a => a.S_CNTR_CODE == cntCode.S_CNTR_CODE); if (WCSHelper.CreateTask(startLoc_3.S_CODE, endLoc_3.S_CODE, "过期次品回炉", 3, outTimeCg.S_CNTR_CODE,out string taskno, outTimeCg.S_SPE)) { LocationHelper.LockLoc(startLoc_3.S_CODE, 2);//起点出库锁, LocationHelper.LockLoc(endLoc_3.S_CODE, 1);//终点入库锁 Task task2 = Task.Run(() => { var target = new TN_RemeltDetail() { TASKNO = taskno, CNTCODE = outTimeCg.S_CNTR_CODE, STARTLOC = startLoc_3.S_CODE, LOGINNAME = "过期次品回炉轮询", ITEMCODE = outTimeCg.S_ITEM_CODE, SPEC = outTimeCg.S_SPE, CARCODE = outTimeCg.S_CAR_CODE, WEIGHT = outTimeCg.F_QTY, REMELTTIME = DateTime.Now, SHIFT = "None", }; SpecHelper.InsertRemeltDetail(target); }); LogHelper.Info($"生成过期次品回炉任务成功,容器号{outTimeCg.S_CNTR_CODE},起点{startLoc_3.S_CODE},终点{endLoc_3.S_CODE}"); } } } } catch (Exception ex) { LogHelper.Error($"发生了异常,满托过期出库 过期合格回库,过期次品回炉 异常,{ex.Message}", ex); } } /// /// 同步TN_EquipProDetail等等 /// internal static void SynchronizationEquipPro() { try { var db = new SqlHelper().GetInstance(); // 同步 TN_EquipProDetail 与 TN_CG_Detail var targetEPD = db.Queryable().LeftJoin((o, i) => o.S_ID == i.S_ID). Where((o, i) => o.ITEMSTATE != i.S_ITEM_STATE && i.S_ITEM_STATE != "待检" && i.N_ITEM_STATE != 1).First(); if (targetEPD != null)//同步货品状态 { targetEPD.ITEMSTATE = db.Queryable().First(a => a.S_ID == targetEPD.S_ID).S_ITEM_STATE; db.Updateable(targetEPD).UpdateColumns(it => new { it.ITEMSTATE }).ExecuteCommand(); } targetEPD = db.Queryable().LeftJoin((o, i) => o.S_ID == i.S_ID). Where((o, i) => System.DateTime.Now >= o.EXPIRATION && i.S_ITEM_STATE == "待检" && i.N_ITEM_STATE == 1).First(); if (targetEPD != null)//检测出过期的货品 { targetEPD.ITEMSTATE = "过期"; db.Updateable(targetEPD).UpdateColumns(it => new { it.ITEMSTATE }).ExecuteCommand(); var cginfo = db.Queryable().First(a => a.S_ID == targetEPD.S_ID); if (cginfo != null) { cginfo.S_ITEM_STATE = "过期"; cginfo.N_ITEM_STATE = 3; db.Updateable(cginfo).UpdateColumns(it => new { it.S_ITEM_STATE, it.N_ITEM_STATE }).ExecuteCommand(); } } // 同步 TN_InventoryM 与 TN_CG_Detail var targetInM = db.Queryable().LeftJoin((o, i) => o.S_ID == i.S_ID). Where((o, i) => o.ITEMSTATE != i.S_ITEM_STATE && i.S_ITEM_STATE != "待检" && i.N_ITEM_STATE != 1).First(); if (targetInM != null)//同步货品状态 { targetInM.ITEMSTATE = db.Queryable().First(a => a.S_ID == targetInM.S_ID).S_ITEM_STATE; db.Updateable(targetInM).UpdateColumns(it => new { it.ITEMSTATE }).ExecuteCommand(); } targetInM = db.Queryable().LeftJoin((o, i) => o.S_ID == i.S_ID). Where((o, i) => System.DateTime.Now >= o.EXPIRATION && ((i.S_ITEM_STATE == "待检" && i.N_ITEM_STATE == 1) || (i.S_ITEM_STATE == "合格" && i.N_ITEM_STATE == 0)) ).First(); if (targetInM != null)//检测出已过期的货品 { targetInM.ITEMSTATE = "过期"; targetInM.EXPIRATION_DAY = "0"; db.Updateable(targetInM).UpdateColumns(it => new { it.ITEMSTATE }).ExecuteCommand(); var cginfo = db.Queryable().First(a => a.S_ID == targetInM.S_ID); if (cginfo != null) { cginfo.S_ITEM_STATE = "过期"; cginfo.N_ITEM_STATE = 3; db.Updateable(cginfo).UpdateColumns(it => new { it.S_ITEM_STATE, it.N_ITEM_STATE }).ExecuteCommand(); } } var targetInMList = db.Queryable().LeftJoin((o, i) => o.S_ID == i.S_ID). Where((o, i) => System.DateTime.Now < o.EXPIRATION && ((i.S_ITEM_STATE == "待检" && i.N_ITEM_STATE == 1) || (i.S_ITEM_STATE == "合格" && i.N_ITEM_STATE == 0)) ).ToList(); if (targetInMList.Count > 0)//检测出快过期的货品 { foreach (var item in targetInMList) { item.EXPIRATION_DAY = SpecHelper.CalculateDaysDifference(System.DateTime.Now, item.EXPIRATION).ToString(); } db.Updateable(targetInMList).UpdateColumns(it => new { it.EXPIRATION_DAY }).ExecuteCommand(); } targetInM = db.Queryable().First(a => Convert.ToInt32(a.EXPIRATION_DAY) > 0 && a.ITEMSTATE == "过期"); if (targetInM != null)//已过期的货品,剩余天数改为0 { targetInM.EXPIRATION_DAY = "0"; db.Updateable(targetInM).UpdateColumns(it => new { it.EXPIRATION_DAY }).ExecuteCommand(); } // 同步 TN_DayProDetail var curDay = System.DateTime.Now.Date; var targetEPDs = db.Queryable().Where(a => a.DOWNLINETIME >= curDay && a.DOWNLINETIME <= curDay.AddDays(1)).ToList(); var specList = targetEPDs.Select(a => a.SPEC).Distinct().ToList();//当天的货品有哪些规格 if (specList.Count>0) { foreach (var item in specList) { var targetDay = db.Queryable().First(a => a.DAYTIME == curDay && a.SPEC == item); if (targetDay == null) { targetDay = new TN_DayProDetail() { DAYTIME = curDay, SPEC = item, }; db.Insertable(targetDay).ExecuteCommand(); } else { var sumWeight = targetEPDs.Where(b=>b.SPEC == item).Sum(a => a.WEIGHT); if (targetDay.WEIGHT != sumWeight) { targetDay.WEIGHT = sumWeight; db.Updateable(targetDay).ExecuteCommand(); } else { LogHelper.Info("重量相等,同步TN_DayProDetail跳过"); } } } } else { LogHelper.Info("当天的货品规格列表为0,同步TN_DayProDetail跳过"); } // 同步 TN_WeekProSpcDetail var curWeek = System.DateTime.Now.Date.AddDays(-(int)System.DateTime.Now.DayOfWeek + 1); targetEPDs = db.Queryable().Where(a => a.DOWNLINETIME >= curWeek && a.DOWNLINETIME <= curWeek.AddDays(7)).ToList(); specList = targetEPDs.Select(a => a.SPEC).Distinct().ToList();//当周的货品有哪些规格 if (specList.Count > 0) { foreach (var item in specList) { var targetWeek = db.Queryable().First(a => a.DAYTIME == curWeek && a.SPEC == item); if (targetWeek == null) { targetWeek = new TN_WeekProDetail() { DAYTIME = curWeek, SPEC = item, }; db.Insertable(targetWeek).ExecuteCommand(); } else { var sumWeight = targetEPDs.Where(b => b.SPEC == item).Sum(a => a.WEIGHT); if (targetWeek.WEIGHT != sumWeight) { targetWeek.WEIGHT = sumWeight; db.Updateable(targetWeek).ExecuteCommand(); } else { LogHelper.Info("重量相等,同步TN_WeekProSpcDetail跳过"); } } } } else { LogHelper.Info("当周的货品规格列表为0,同步TN_WeekProSpcDetail跳过"); } // 同步 TN_MonthProSpcDetail var curMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).Date; targetEPDs = db.Queryable().Where(a => a.DOWNLINETIME >= curMonth && a.DOWNLINETIME <= curMonth.AddMonths(1)).ToList(); specList = targetEPDs.Select(a => a.SPEC).Distinct().ToList();//当月的货品有哪些规格 if (specList.Count > 0) { foreach (var item in specList) { var targetMonth = db.Queryable().First(a => a.DAYTIME == curMonth && a.SPEC == item); if (targetMonth == null) { targetMonth = new TN_MonthProDetail() { DAYTIME = curMonth, SPEC = item, }; db.Insertable(targetMonth).ExecuteCommand(); } else { var sumWeight = targetEPDs.Where(b => b.SPEC == item).Sum(a => a.WEIGHT); if (targetMonth.WEIGHT != sumWeight) { targetMonth.WEIGHT = sumWeight; db.Updateable(targetMonth).ExecuteCommand(); } else { LogHelper.Info("重量相等,同步TN_MonthProSpcDetail跳过"); } } } } else { LogHelper.Info("当月的货品规格列表为0,同步TN_MonthProSpcDetail跳过"); } // 同步 TN_YearProSpcDetail var curYear = new DateTime(DateTime.Now.Year, 1, 1).Date; targetEPDs = db.Queryable().Where(a => a.DOWNLINETIME >= curYear && a.DOWNLINETIME <= curYear.AddYears(1)).ToList(); specList = targetEPDs.Select(a => a.SPEC).Distinct().ToList();//当年的货品有哪些规格 if (specList.Count > 0) { foreach (var item in specList) { var targetYear = db.Queryable().First(a => a.DAYTIME == curYear && a.SPEC == item); if (targetYear == null) { targetYear = new TN_YearProDetail() { DAYTIME = curYear, SPEC = item, }; db.Insertable(targetYear).ExecuteCommand(); } else { var sumWeight = targetEPDs.Where(b => b.SPEC == item).Sum(a => a.WEIGHT); if (targetYear.WEIGHT != sumWeight) { targetYear.WEIGHT = sumWeight; db.Updateable(targetYear).ExecuteCommand(); } else { LogHelper.Info("重量相等,同步TN_YearProSpcDetail跳过"); } } } } else { LogHelper.Info("当年的货品规格列表为0,同步TN_YearProSpcDetail跳过"); } } catch (Exception ex) { // 获取最内层异常(通常是实际引发问题的异常) Exception innerEx = ex; while (innerEx.InnerException != null) { innerEx = innerEx.InnerException; } // 获取堆栈帧信息 var stackTrace = new System.Diagnostics.StackTrace(innerEx, true); var stackFrame = stackTrace.GetFrame(0); // 获取最顶层的堆栈帧 // 获取文件名和行号 string fileName = stackFrame.GetFileName(); int lineNumber = stackFrame.GetFileLineNumber(); LogHelper.Error($"发生了异常,同步TN_EquipProDetail异常,文件:{fileName}, 行号:{lineNumber}, 错误:{ex.Message}\r\n{ex.StackTrace}", ex); } } /// /// 同步 TN_Container 均要实时显示 /// internal static void CheckCntAndBoard() { try { var db = new SqlHelper().GetInstance(); //同步TN_Container var fullLocList = db.Queryable().Where(a => a.N_CURRENT_NUM > 0).ToList(); if (fullLocList.Count > 0) { var fullLocCntList = db.Queryable().Where(a => fullLocList.Select(b => b.S_CODE).ToList().Contains(a.S_LOC_CODE)).ToList(); var fullLocCntListStr = fullLocCntList.Select(b => b.S_CNTR_CODE).ToList(); var fullCntList = db.Queryable().Where(a => fullLocCntListStr.Contains(a.S_CODE)).ToList(); var fullCntListStr = fullCntList.Select(b => b.S_CODE).ToList(); var except = fullLocCntListStr.Except(fullCntListStr).ToList(); if (except.Count > 0) { var addCntList = new List(); foreach (var item in except) { addCntList.Add(new TN_Container() { S_CODE = item, N_DETAIL_COUNT = 1 }); } db.Insertable(addCntList).ExecuteCommand(); } } var emptyCntList = db.Queryable().Where(a => a.S_CODE != string.Empty && a.S_CODE != null).ToList(); if (emptyCntList.Count > 0) { var emptyCntListStr = emptyCntList.Select(b => b.S_CODE).ToList(); var emptyLocCntList = db.Queryable().Where(a => emptyCntListStr.Contains(a.S_CNTR_CODE)).ToList(); var emptyLocCntListStr = emptyLocCntList.Select(a => a.S_CNTR_CODE).ToList(); var deleteCntList = emptyCntListStr.Except(emptyLocCntListStr).ToList(); if (deleteCntList.Count > 0) { db.Deleteable(emptyCntList).ExecuteCommand(); } } } catch (Exception ex) { LogHelper.Error($"发生了异常,同步 TN_Container 异常,{ex.Message}", ex); } } /// /// 检测满托缓存库区不合格的物品,满托出库复检 /// internal static void CheckNoOkCg() { var db = new SqlHelper().GetInstance(); try { var startLoc = db.Queryable(). LeftJoin((o, i) => o.S_CODE == i.S_LOC_CODE). LeftJoin((o, i, s) => i.S_CNTR_CODE == s.S_CNTR_CODE). Where((o, i, s) => o.N_CURRENT_NUM == 1 && o.N_LOCK_STATE == 0 && o.S_LOCK_STATE == "无" && o.S_AREA_CODE == Settings.Areas[1] && s.N_ITEM_STATE == 2 && s.S_ITEM_STATE == "不合格").First(); if (startLoc == null) { LogHelper.Info($"未找到合适的起点货位,要求o.N_CURRENT_NUM == 1 && o.N_LOCK_STATE == 0 && o.S_LOCK_STATE == 无 && o.S_AREA_CODE == Settings.Areas[1] && s.N_ITEM_STATE ==2 && s.S_ITEM_STATE==不合格"); return; } var endLoc = db.Queryable() .Where(a => a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && SqlFunc.Subqueryable().Where(b => b.S_LOC_CODE == a.S_CODE).NotAny()//不能有货 && a.S_AREA_CODE == Settings.Areas[7]).First(); if (endLoc == null) { LogHelper.Info($"未找到合适的终点货位,要求a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == 无 && a.S_AREA_CODE == Settings.Areas[7]"); return; } var cntId = db.Queryable().First(a => a.S_LOC_CODE == startLoc.S_CODE); if (cntId == null) { LogHelper.Info($"未找到对应的容器,要求 a.S_LOC_CODE == startLoc.S_CODE"); return; } var cgInfo = db.Queryable().First(a => a.S_CNTR_CODE == cntId.S_CNTR_CODE); if (WCSHelper.CreateTask(startLoc.S_CODE, endLoc.S_CODE, "满托出库复检", 3, cntId.S_CNTR_CODE, cgInfo.S_SPE))//创建搬送任务,起点终点容器 { LocationHelper.LockLoc(startLoc.S_CODE, 2);//起点出库锁, LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁 LogHelper.Info($"生成满托出库复检任务成功,容器:{cntId.S_CNTR_CODE},起点:{startLoc.S_CODE},终点:{endLoc.S_CODE}"); Task task27 = Task.Run(() => { SpecHelper.DeleteInventoryM(cgInfo.S_ID); }); } else { LogHelper.Info($"生成满托出库复检任务失败,容器:{cntId.S_CNTR_CODE},起点:{startLoc.S_CODE},终点:{endLoc.S_CODE}"); } } catch (Exception ex) { LogHelper.Error($"发生了异常,生成满托出库复检任务失败,{ex.Message}", ex); } } /// /// 空托堆叠入库 /// internal static void CheckEmptyCnt() { var db = new SqlHelper().GetInstance(); try { var startLoc = db.Queryable(). Where(a => a.S_AREA_CODE == Settings.Areas[3] && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.N_CURRENT_NUM == a.N_CAPACITY). OrderBy(a => a.T_MODIFY, OrderByType.Desc). First(); if (startLoc == null) { LogHelper.Info($"空托堆叠区{Settings.Areas[3]}暂无堆满的空托"); return; } var endLoc = db.Queryable(). Where(a => a.S_AREA_CODE == Settings.Areas[4] && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && a.N_CURRENT_NUM == 0 && SqlFunc.Subqueryable().Where(b => b.S_LOC_CODE == a.S_CODE).NotAny() ). OrderBy(a => a.N_CURRENT_NUM, OrderByType.Asc). First(); if (endLoc == null) { LogHelper.Info($"未找到合适的终点货位,需满足{Settings.Areas[4]}里有未锁定且当前数量等于0的货位"); return; } var cntrList = db.Queryable().Where(a => a.S_LOC_CODE == startLoc.S_CODE).OrderBy(a => a.T_CREATE, OrderByType.Asc).ToList(); if (cntrList.Count < 1) { LogHelper.Info($"起点{startLoc.S_CODE}未找到货位容器关系信息"); return; } string cntrString = ""; for (int i = 0; i < cntrList.Count; i++) { if (i == cntrList.Count - 1)//最后一个字符串连接不加逗号 { cntrString += cntrList[i].S_CNTR_CODE; } else { cntrString += cntrList[i].S_CNTR_CODE + ","; } } if (WCSHelper.CreateTask(startLoc.S_CODE, endLoc.S_CODE, "空托堆叠入库", 3, cntrString))//创建搬送任务,起点终点容器 { LocationHelper.LockLoc(startLoc.S_CODE, 2);//起点出库锁, LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁 LogHelper.Info($"生成空托堆叠入库任务成功,容器:{cntrString},起点:{startLoc.S_CODE}"); } else { LogHelper.Info($"生成空托堆叠入库任务失败,容器:{cntrString},起点:{startLoc.S_CODE}"); } } catch (Exception ex) { LogHelper.Info($"空托堆叠入库异常:{ex.Message}"); } } } /// /// 与S7设备交互时的model /// public class CheckDeciveModel { /// /// 心跳 /// public int Heart { set; get; } /// /// RFID,是容器是托盘 /// public string RfidData { set; get; } /// /// 允许上下料 0=无任务,11=上料,21=下料,(请求AGV工作) /// public int AgvAllow { set; get; } /// /// 任务属性 1 OK,2称重失败,3条码失败,4 RFID读取失败 /// public int TaskProperties { set; get; } /// /// 准备就绪 0=未准备好,1=准备好 /// public int Ready { set; get; } /// /// 载货状态 0=输送线无产品,1=输送线有产品 /// public int CargoStatus { set; get; } /// /// 工位状态 0待机中,1入库方向运行中,2出库方向运行中,3设备故障 /// public int StationStatus { set; get; } /// /// 去向请求 0待机中,1到位请求 /// public int DestinationRequests { set; get; } /// /// 扫码信息 扫码枪反馈信息 /// public string BarcodeCode { set; get; } /// /// 重量 /// public float Weight { set; get; } /// /// 产线地址 /// public string LineIP { set; get; } } }