using HH.WCS.Mobox3.NFLZ.core; using HH.WCS.Mobox3.NFLZ.device; using HH.WCS.Mobox3.NFLZ.dispatch; using HH.WCS.Mobox3.NFLZ.models; using HH.WCS.Mobox3.NFLZ.util; using HH.WCS.Mobox3.NFLZ.wms; using Newtonsoft.Json; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using static HH.WCS.Mobox3.NFLZ.api.OtherModel; using static HH.WCS.Mobox3.NFLZ.dispatch.NDC; using static HH.WCS.Mobox3.NFLZ.wms.WMSHelper.AddChangeModel; namespace HH.WCS.Mobox3.NFLZ.process { internal class TaskProcess { private static HttpHelper httpHelper = new HttpHelper(); #region 任务相关 //--------------------------------------------------任务相关-------------------------------------------------- /// /// 取货卸货完成,缓存位状态更新 /// /// /// internal static void CacheBitUpdate(WCSTask mst, bool load) { var trayCarryCount = mst.N_CNTR_COUNT > 0 ? mst.N_CNTR_COUNT : 1; if (load) { Console.WriteLine($"任务{mst.S_CODE} 货位{mst.S_START_LOC}取货完成,起点解绑容器{mst.S_CNTR_CODE}"); LogHelper.Info($"任务{mst.S_CODE} 货位{mst.S_START_LOC}取货完成,起点解绑容器{mst.S_CNTR_CODE}"); LocationHelper.UnBindingLoc(mst.S_START_LOC, mst.S_CNTR_CODE.Split(',').ToList()); } else { Console.WriteLine($"任务{mst.S_CODE} 货位{mst.S_END_LOC}卸货完成,终点绑定容器{mst.S_CNTR_CODE}"); LogHelper.Info($"任务{mst.S_CODE} 货位{mst.S_END_LOC}卸货完成,终点绑定容器{mst.S_CNTR_CODE}"); LocationHelper.BindingLoc(mst.S_END_LOC, mst.S_CNTR_CODE.Split(',').ToList()); } } /// /// 任务取消,缓存位状态更新 /// /// internal static void CacheBitCancelUpdate(WCSTask mst) { //任务取消,取货完成前的,起点的loadingCount和终点unLoadingCount都清除,取货完成的只处理终点 if (WCSHelper.CheckActionRecordExist(mst.S_CODE, 4)) { //根据客户现场要求,如果取货完成任务失败人工拉到终点,我们就当卸货完成处理;如果是人工拉走到其它区域,我们就解锁终点,删除托盘。 //终点绑定 CacheBitUpdate(mst, false); LocationHelper.UnLockLoc(mst.S_END_LOC); } else { //起点终点解锁 LocationHelper.UnLockLoc(mst.S_START_LOC); LocationHelper.UnLockLoc(mst.S_END_LOC); } } /// /// 安全请求 /// /// /// /// /// internal static void OperateReq(string no, int state, string forkliftNo, string extData) { LogHelper.Info($"收到安全请求信号:{state},任务号:{no}"); var mst = WCSHelper.GetTask(no); if (mst != null) { if (state == 1101) { //取货请求,允许进入取货,修改参数18为1101 DeviceProcess.quliao(mst); } if (state == 1103) { DeviceProcess.Xieliao(mst); } if (state == 1102 || state == 1104) { sendSing(mst, state); } } } internal static void sendSing(WCSTask wmsTask, int state = 0) { LogHelper.Info($"收到任务{wmsTask.S_CODE}信号{state},类型{wmsTask.S_TYPE}"); int devType = wmsTask.S_TYPE == "成品下线" ? 14 : 19; var plc = Settings.deviceInfos.Where(a => a.deviceType == devType).FirstOrDefault(); if (plc != null) { if (wmsTask.S_TYPE == "成品下线") { if (state == 1101) { PlcHelper.SendHex(plc.address, "3F00110D0A"); } if (state == 1102) { PlcHelper.SendHex(plc.address, "3F00100d0a"); } } if (wmsTask.S_TYPE == "栈板上线") { if (state == 1103) { PlcHelper.SendHex(plc.address, "3F00210d0a"); } if (state == 1104 || state == -1) { PlcHelper.SendHex(plc.address, "3F00200d0a"); } } if (wmsTask.S_TYPE.Contains("空托上线") || wmsTask.S_TYPE.Contains("满托上线") || wmsTask.S_TYPE.Contains("空托下线") || wmsTask.S_TYPE.Contains("满托下线")) { LogHelper.Info($"{wmsTask.S_TYPE}取消写入复位信号"); writeSignal(wmsTask); } } else LogHelper.Info("农夫临江-L6输送线 未配置"); } public static void writeSignal(WCSTask mst, int state = 0) { if (mst.S_TYPE.Contains("空托上线")) { LogHelper.Info($"{mst.S_TYPE}卸货完成,写入信号"); //根据起点判断是A口还是B口 var locCode = mst.S_END_LOC; var devInfo = Settings.deviceInfos.Where(a => a.TN_Location.Contains(locCode)).FirstOrDefault(); if (devInfo != null) { var signal = devInfo.TN_Location[0] == mst.S_END_LOC ? "3F 00 10 0D 0A" : "3F 00 20 0D 0A"; if (PlcHelper.SendHex(devInfo.address, signal)) LogHelper.Info($"{mst.S_TYPE}任务卸货完成,写入信号:{signal},ip:{devInfo.address}"); } else LogHelper.Info($"设备未找到,货位号:{mst.S_END_LOC}"); } if (mst.S_TYPE.Contains("满托上线")) { LogHelper.Info($"{mst.S_TYPE}卸货完成,写入信号"); var locCode = mst.S_END_LOC; var devInfo = Settings.deviceInfos.Where(a => a.TN_Location.Contains(locCode)).FirstOrDefault(); if (devInfo != null) { var signal = "3F 00 10 0D 0A"; if (PlcHelper.SendHex(devInfo.address, signal)) LogHelper.Info($"{mst.S_TYPE}任务卸货完成,写入信号:{signal},ip:{devInfo.address}"); } else LogHelper.Info($"设备未找到,货位号:{mst.S_END_LOC}"); } if (mst.S_TYPE.Contains("空托下线")) { LogHelper.Info($"{mst.S_TYPE}取货完成,写入信号"); var locCode = mst.S_START_LOC; var devInfo = Settings.deviceInfos.Where(a => a.TN_Location.Contains(locCode)).FirstOrDefault(); if (devInfo != null) { var signal = "3F 00 12 22 00 0D 0A"; if (PlcHelper.SendHex(devInfo.address, signal)) LogHelper.Info($"{mst.S_TYPE}任务取货完成,写入信号:{signal},ip:{devInfo.address}"); } else LogHelper.Info($"设备未找到,货位号:{mst.S_END_LOC}"); } if (mst.S_TYPE.Contains("满托下线")) { LogHelper.Info($"{mst.S_TYPE}取货完成,写入信号"); //根据起点判断是A口还是B口 var locCode = mst.S_START_LOC; var devInfo = Settings.deviceInfos.Where(a => a.TN_Location.Contains(locCode)).FirstOrDefault(); if (devInfo != null) { var signal = devInfo.TN_Location[0] == mst.S_START_LOC ? "3F 00 10 0D 0A" : "3F 00 20 0D 0A"; if (PlcHelper.SendHex(devInfo.address, signal)) LogHelper.Info($"{mst.S_TYPE}任务取货完成,写入信号:{signal},ip:{devInfo.address}"); } else LogHelper.Info($"设备未找到,货位号:{mst.S_START_LOC}"); } } internal static void UpdateAgvNo(WCSTask mst, string forkliftNo) { var db = new SqlHelper().GetInstance(); mst.S_EQ_NO = forkliftNo; db.Updateable(mst).UpdateColumns(it => new { it.S_EQ_NO }).ExecuteCommand(); } internal static void ThirdReportStatus(WCSTask mst, int state, string forkliftNo) { } /// /// 任务拦截 /// /// /// internal static bool Intercept(WCSTask mst) { var result = false; //出库任务是批量生成的,初始终点我们先给一个虚拟点,不推送。有单独的现场去判断出库缓存区光电,空了再给出库任务分配终点 if (mst.S_END_LOC.Trim() == "出库虚拟点") { result = true; } return result; } /// /// 任务状态更新处理 /// /// /// internal static void OperateStatus(WCSTask mst, int state) { if (state == 4) { claimGoodsTime(mst, state); CacheBitUpdate(mst, true); EmptyTask(mst); } if (state == 6)//卸货完成 { claimGoodsTime(mst, state); CacheBitUpdate(mst, false); } if (state == 7) { CacheBitCancelUpdate(mst); } } /// /// 瓶坯瓶盖机满托下线后生成空托上线任务 /// /// /// public static void EmptyTask(WCSTask mst) { //瓶盖注塑机空托上线,若急产急用库区没有多余的空托,则在非急产急用空托区拿空托 var db = new SqlHelper().GetInstance(); Location startLoca = null; if (mst.S_TYPE.Contains("满托下线")) { LogHelper.Info($"空托任务生成处理,任务类型:{mst.S_TYPE}"); var areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯空托" && a.enable == 1).First(); if(areaInfo != null) { startLoca = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM > 0 && a.S_LOCK_STATE == "无").OrderBy(a => a.N_COL).First(); if (startLoca != null) { LogHelper.Info("startLoca" + JsonConvert.SerializeObject(startLoca)); string taskType = ""; if (mst.S_TYPE == "注塑即产满托下线(瓶坯)") taskType = "注塑即产空托上线(瓶坯)"; if (mst.S_TYPE == "注塑库存满托下线(瓶坯)") taskType = "注塑库存空托上线(瓶坯)"; var cntrInfo = db.Queryable().Where(a => a.S_LOC_CODE == startLoca.S_CODE).First(); if (cntrInfo != null) { WMSHelper.CreateOpTask(startLoca.S_CODE, mst.S_START_LOC, "出库", taskType, cntrInfo.S_CNTR_CODE); } else LogHelper.Info($"未绑定托盘,货位号:{startLoca.S_CODE}"); } } else { LogHelper.Info($"瓶坯空托未配置"); } } if (mst.S_TYPE.Contains("空托下线")) { LogHelper.Info($"满托任务生成处理,任务类型:{mst.S_TYPE}"); string startArea = ""; LinZhiBCPWorkOrder bcpW = null; if (mst.S_TYPE.Contains("瓶坯")) { bcpW = db.Queryable().Where(a => a.S_PLineNo.Contains("农夫林芝-瓶坯翻斗机") && a.S_WorkState == "执行中").First(); } else { bcpW = db.Queryable().Where(a => a.S_PLineNo.Contains("农夫林芝-瓶盖翻斗机") && a.S_WorkState == "执行中").First(); } if (mst.S_TYPE.Contains("瓶盖")) { //瓶盖无即产即用和非即产即用 var bcpInfo = Settings.areaInfos.Where(a => a.areaName == "瓶盖非即产即用" && a.enable == 1).FirstOrDefault(); if (bcpInfo != null) { startLoca = DeviceProcess.getFDSXArea(db, bcpW, bcpInfo.areaCode); } } else { if (bcpW.S_UsingNow == "Y") { LogHelper.Info($"瓶坯即产即用A库区查找"); startArea = Settings.areaInfos.Where(a => a.areaName == "瓶坯即产即用A" && a.enable == 1).FirstOrDefault().areaCode; startLoca = DeviceProcess.getFDSXArea(db, bcpW, startArea); if (startLoca == null) { LogHelper.Info($"瓶坯即产即用A库区未找到满托,去瓶坯即产即用B库区查找"); startLoca = TaskProcess.BCPInOrOut(db, true, "瓶坯即产即用B", bcpW.S_ItemCode); } } else { startArea = Settings.areaInfos.Where(a => a.areaName == "瓶坯非即产即用" && a.enable == 1).FirstOrDefault().areaCode; startLoca = DeviceProcess.getFDSXArea(db, bcpW, startArea); } } if (startLoca != null) { LogHelper.Info("startLoca" + JsonConvert.SerializeObject(startLoca)); string taskType = ""; if (mst.S_TYPE == "翻斗机即产空托下线(瓶坯)") taskType = "翻斗机即产满托上线(瓶坯)"; if (mst.S_TYPE == "翻斗机库存空托下线(瓶坯)") taskType = "翻斗机库存满托上线(瓶坯)"; if (mst.S_TYPE == "翻斗机库存空托下线(瓶盖)") taskType = "翻斗机库存满托上线(瓶盖)"; var cntrInfo = db.Queryable().Where(a => a.S_LOC_CODE == startLoca.S_CODE).First(); if (cntrInfo != null) { WMSHelper.CreateOpTask(startLoca.S_CODE, mst.S_START_LOC, "出库", taskType, cntrInfo.S_CNTR_CODE); } else LogHelper.Info($"未绑定托盘,货位号:{startLoca.S_CODE}"); } } } private static void claimGoodsTime(WCSTask mst, int state) { //将取货完成时间存入中间表 var db = new SqlHelper().GetInstance(); if (state == 6 && (mst.S_TYPE == "栈板上线" || mst.S_TYPE.Contains("空托上线") || mst.S_TYPE.Contains("满托上线"))) { LogHelper.Info($"任务{mst.S_TYPE}卸货时间存入中间表,当前时间:{DateTime.Now}"); var cgInfo = db.Queryable().Where(a => a.Bit == mst.S_END_LOC).First(); if (cgInfo != null) { cgInfo.time = DateTime.Now; if (db.Updateable(cgInfo).UpdateColumns(a => new { a.time }).ExecuteCommand() > 0) LogHelper.Info($"数据更改成功,终点:{mst.S_END_LOC}"); } else { CGTTable cg = new CGTTable { Bit = mst.S_END_LOC, time = DateTime.Now, }; if (db.Insertable(cg).ExecuteCommand() > 0) LogHelper.Info($"数据插入成功,终点:{mst.S_END_LOC}"); } } if (state == 4 && (mst.S_TYPE.Contains("空托下线") || mst.S_TYPE.Contains("满托下线"))) { LogHelper.Info($"任务{mst.S_TYPE}取货时间存入中间表,当前时间:{DateTime.Now},点位:{mst.S_START_LOC}"); var cgInfo = db.Queryable().Where(a => a.Bit == mst.S_START_LOC).First(); if (cgInfo != null) { cgInfo.time = DateTime.Now; if (db.Updateable(cgInfo).UpdateColumns(a => new { a.time }).ExecuteCommand() > 0) LogHelper.Info($"数据更改成功,起点:{mst.S_START_LOC}"); } else { CGTTable cg = new CGTTable { Bit = mst.S_START_LOC, time = DateTime.Now, }; if (db.Insertable(cg).ExecuteCommand() > 0) LogHelper.Info($"数据插入成功,起点:{mst.S_START_LOC}"); } } } private static object locLocker = new object(); /// /// 堆叠库区出入库任务申请 /// /// /// /// /// /// /// /// /// internal static bool ApplyTN_Task(Location ls, ref List cntrs, string area, string itemCode, string itemBatch, string taskType, bool insStock = true) { var result = false; lock (locLocker) { try { if (insStock) { Console.WriteLine($"MoboxHelperCreateTask: {area}-{itemCode}-{itemBatch}-{taskType}"); var endTN_Location = GetLocation4In(area, itemCode, itemBatch, 3); if (endTN_Location != null) { var endLayer = endTN_Location.N_CURRENT_NUM == 0 ? 1 : 2; var taskNo = DateTime.Now.Ticks.ToString(); result = TaskProcess.CreateTransport(ls.S_CODE, endTN_Location.S_CODE, taskType, cntrs, 1, endLayer, 3, 70); } else { Console.WriteLine($"MoboxHelperCreateTask: 未找到终点货位"); } } else { var startTN_Location = GetLocation4Out(area, itemCode, itemBatch, 3); if (startTN_Location != null) { var startLayer = startTN_Location.N_CURRENT_NUM <= 3 ? 1 : 2; var taskNo = DateTime.Now.Ticks.ToString(); var carryCount = startTN_Location.N_CURRENT_NUM > 3 ? startTN_Location.N_CURRENT_NUM - 3 : startTN_Location.N_CURRENT_NUM; //出库要从起点获取托盘 var cntrList = LocationHelper.GetLocCntr(startTN_Location.S_CODE); if (cntrList.Count == startTN_Location.N_CURRENT_NUM) { cntrs = cntrList.OrderByDescending(a => a.T_CREATE).Take(carryCount).Select(a => a.S_CNTR_CODE.Trim()).ToList(); result = TaskProcess.CreateTransport(startTN_Location.S_CODE, ls.S_CODE, taskType, cntrs, startLayer, 1, carryCount, 65); } else { Console.WriteLine($"起点托盘数量和货位容器表不符合,请检查【货位表】和【货位容器表】"); } } } } catch (Exception ex) { Console.WriteLine("MoboxHelperCreateTask:" + ex.Message); LogHelper.Error("MoboxHelperCreateTask:" + ex.Message, ex); } } return result; } private static Location GetLocation4Out(string area, string itemCode, string itemBatch, int v) { throw new NotImplementedException(); } private static Location GetLocation4In(string area, string itemCode, string itemBatch, int v) { throw new NotImplementedException(); } /// /// 普通货架区的出入库申请 /// /// /// /// /// /// /// /// internal static bool ApplyNormalTN_Task(Location ls, ref List cntrs, string area, string taskType, string itemCode, bool insStock = true) { var result = false; lock (locLocker) { try { if (insStock) { Console.WriteLine($"MoboxHelperCreateTask: {area}-{taskType}"); var endTN_Location = new Location(); if (endTN_Location != null) { var taskNo = DateTime.Now.Ticks.ToString(); result = TaskProcess.CreateTransport(ls.S_CODE, endTN_Location.S_CODE, taskType, cntrs, 70); } else { Console.WriteLine($"MoboxHelperCreateTask: 未找到终点货位"); } } else { var startTN_Location = new Location(); if (startTN_Location != null) { //出库要从起点获取托盘 var cntrList = LocationHelper.GetLocCntr(startTN_Location.S_CODE); if (cntrList.Count == startTN_Location.N_CURRENT_NUM) { result = TaskProcess.CreateTransport(startTN_Location.S_CODE, ls.S_CODE, taskType, new List { cntrList[0].S_CNTR_CODE }, 65); } else { Console.WriteLine($"起点托盘数量和货位容器表不符合,请检查【货位表】和【货位容器表】"); } } } } catch (Exception ex) { Console.WriteLine("MoboxHelperCreateTask:" + ex.Message); LogHelper.Error("MoboxHelperCreateTask:" + ex.Message, ex); } } return result; } /// /// 推送任务 /// /// internal static bool SendTask(WCSTask mst) { var result = false; var db = new SqlHelper().GetInstance(); if (mst.N_B_STATE == 0) { try { int TsNo = 1;//下发任务类型:默认-1 坯盖-6 成品任务-5 var Extend1 = "0";//取货站点 var Extend2 = "0";//卸货站点 string Extend3 = "";//功能码 16进制转10进制 string Extend4 = "";//坯盖:托盘类型 即产即用1,非即产即用2 不区分为1 成品:取卸货层数(先单独转换为16进制,再拼接转换为10进制) string Extend5 = "";//物料高度(品相) 根据工单物料到物料表获取下发TS的物料高度 string Extend6 = "";//托盘版型 备注:小板 1,集化板 2,小板超托 3,集化板超托 4 根据工单版型转换为对应的值 string Extend7 = "";//起点列 string Extend8 = "";//终点列 int startLayer = mst.N_START_LAYER;// 起点取货层数 int endLayer = mst.N_END_LAYER;// 终点卸货层数 string workNo = mst.S_EQ_TASK_CODE;// 工单号 string trayType = mst.S_NOTE;//托盘类型-根据各自现场情况获取 var taskType = mst.S_TYPE;// 任务类型 // 获取起终点的AGV站点 查询 扩展货位表 S_PICKUP_POINT-点位层数 S_LOC_CODE-货位编码 GetAgvSite-标准获取扩展货位表数据的方法 //Extend1 = LocationHelper.GetAgvSite(mst.S_START_LOC, startLayer.ToString()); //Extend2 = LocationHelper.GetAgvSite(mst.S_END_LOC, endLayer.ToString()); //二期成品任务类型(将 成品车间 任务类型加入到此数组中,即可根据 任务类型 区分车间,并获取对应的TS参数) string[] ConveryTaskList = new string[] { "成品下线", "栈板上线", "零头下线" }; if (ConveryTaskList.Contains(taskType) || taskType.Contains("移库")) { //TsNo = 5; // //if (taskType.Contains("栈板上线")) //{ // Extend1 = db.Queryable().Where(a => a.S_CODE == mst.S_START_LOC && a.N_LAYER == mst.N_START_LAYER).First().S_AGV_SITE; // Extend2 = db.Queryable().Where(a => a.S_CODE == mst.S_END_LOC && a.N_LAYER == mst.N_END_LAYER).First().S_AGV_SITE; // // var startLoc = db.Queryable().Where(a => a.S_CODE == mst.S_START_LOC).First(); // var endLoc = db.Queryable().Where(a => a.S_CODE == mst.S_END_LOC).First(); // int startCol = int.Parse(startLoc.N_COL.ToString()); // int endCol = int.Parse(endLoc.N_COL.ToString()); // Extend7 = (startCol - 1).ToString(); // Extend8 = (endCol - 1).ToString(); //} //else //{ // // 成品任务下发参数获取 // // var startLoc = db.Queryable().Where(a => a.S_CODE == mst.S_START_LOC).First(); // var endLoc = db.Queryable().Where(a => a.S_CODE == mst.S_END_LOC).First(); // int startCol = int.Parse(startLoc.N_COL.ToString()); // int endCol = int.Parse(endLoc.N_COL.ToString()); // var startLocInfo = db.Queryable().Where(a => a.S_AREA_CODE == startLoc.S_AREA_CODE && a.N_ROW == startLoc.N_ROW && a.S_START_COL <= startCol && a.S_END_COL >= startCol).First(); // var endLocInfo = db.Queryable().Where(a => a.S_AREA_CODE == endLoc.S_AREA_CODE && a.N_ROW == endLoc.N_ROW && a.S_START_COL <= endCol && a.S_END_COL >= endCol).First(); // // if (startLocInfo != null) // { // Extend1 = mst.N_START_LAYER == 1 ? int.Parse(startLocInfo.S_First_Bit) : int.Parse(startLocInfo.S_Second_Bit); // if (trayType.Contains("集化板")) Extend1 = Extend1 + 2; // // Extend7 = (startCol - startLocInfo.S_START_COL).ToString(); // } // else LogHelper.Info($"任务异常:{mst.S_CODE},自由线段表无可用起点货位数据。起点货位编码:{mst.S_START_LOC}"); // if (endLocInfo != null) // { // Extend2 = mst.N_END_LAYER == 1 ? int.Parse(endLocInfo.S_First_Bit) : int.Parse(endLocInfo.S_Second_Bit); // Extend8 = (endCol - endLocInfo.S_START_COL).ToString(); // } // else LogHelper.Info($"任务异常:{mst.S_CODE},自由线段表无可用终点货位数据。终点货位编码:{mst.S_END_LOC}"); // // // 其他功能码可以根据任务类型自行添加(此处仅示例 移库 功能码获取方式,如果有更好的方式,可以自行修改) // if (taskType.Contains("移库")) Extend3 = Convert.ToInt32("20", 16).ToString(); // //} // ////// 获取成品工单数据(查询 成品工单表)f //if (taskType.Contains("移库")) //{ // var workInfo = db.Queryable().Where(a => a.S_WorkNo == workNo).First(); // if (workInfo != null) // { // LogHelper.Info($"{workInfo.S_ORDER_TYPE}"); // // 获取下发TS物料层数数据(查询 物料表) // if (workInfo.S_ORDER_TYPE.Contains("移库")) // { // LogHelper.Info($"物料编码:{mst.S_ITEM_CODE},栈板类型:{trayType},物料规格:{workInfo.S_ItemLayer}"); // var itemInfo1 = db.Queryable().Where(a => a.S_ITEM_CODE == mst.S_ITEM_CODE && a.S_TRAY_TYPE == trayType && a.S_ITEM_MODEL == workInfo.S_ItemLayer).First(); // if (itemInfo1 != null) // { // Extend5 = itemInfo1.S_ITEM_LAYER; // } // else // { // LogHelper.Info($"物料表未维护信息,物料编码:{mst.S_ITEM_CODE},栈板类型:{trayType},物料规格:{workInfo.S_ItemLayer}"); // } // //if (workInfo.S_ORDER_TYPE == "无码入库" && endLayer == 1) Extend5 = ""; // } // // // 根据工单中托盘类型转换为对应的下发TS参数数据 // LogHelper.Info($"S_TRAY_TYPE:{trayType}"); // LogHelper.Info($"Extend5:{Extend5}"); // int x = 0; // if (trayType == "小板") x = 1; // if (trayType == "集化板") x = 2; // if (trayType == "小板超托") x = 3; // if (trayType == "集化板超托") x = 4; // // Extend6 = x.ToString(); // // } //} //else //{ // var workInfo = db.Queryable().Where(a => a.S_WorkNo == workNo).First(); // if (workInfo != null) // { // LogHelper.Info($"{workInfo.S_ORDER_TYPE}"); // // 获取下发TS物料层数数据(查询 物料表) // if (workInfo.S_ORDER_TYPE.Contains("下线") || workInfo.S_ORDER_TYPE == "无码入库") // { // var itemInfo1 = db.Queryable().Where(a => a.S_ITEM_CODE == workInfo.S_ItemCode && a.S_TRAY_TYPE == trayType && a.S_ITEM_MODEL == workInfo.S_ItemLayer).First(); // if (itemInfo1 != null) // { // Extend5 = itemInfo1.S_ITEM_LAYER; // } // //if (workInfo.S_ORDER_TYPE == "无码入库" && endLayer == 1) Extend5 = ""; // } // // // 根据工单中托盘类型转换为对应的下发TS参数数据 // LogHelper.Info($"S_TRAY_TYPE:{trayType}"); // int x = 0; // if (trayType == "小板") x = 1; // if (trayType == "集化板") x = 2; // if (trayType == "小板超托") x = 3; // if (trayType == "集化板超托") x = 4; // // Extend6 = x.ToString(); // // } //} // //// 获取 任务参数4 DATA 数据 //string startLayerValue = Convert.ToString(startLayer, 16).ToUpper(); //string endLayerValue = Convert.ToString(endLayer, 16).ToUpper(); ////Extend4 = Convert.ToInt32(startLayerValue + endLayerValue, 16).ToString(); //Extend4 = ((startLayer * 16) + endLayer).ToString(); } else { TsNo = 1; // 坯盖任务下发参数获取 // 获取起终点的AGV站点 Extend1 = db.Queryable().Where(a => a.S_CODE == mst.S_START_LOC && a.N_LAYER == mst.N_START_LAYER).First().S_AGV_SITE; Extend2 = db.Queryable().Where(a => a.S_CODE == mst.S_END_LOC && a.N_LAYER == mst.N_END_LAYER).First().S_AGV_SITE; Extend3 = "0"; // 获取 任务参数4 DATA 数据 string startLayerValue = Convert.ToString(startLayer, 16).ToUpper(); string endLayerValue = Convert.ToString(endLayer, 16).ToUpper(); //Extend4 = Convert.ToInt32(startLayerValue + endLayerValue, 16).ToString(); Extend4 = ((startLayer * 16) + endLayer).ToString(); //Extend4 = db.Queryable().Where(a => a.S_WorkNo == workNo).First().S_UsingNow == "N" ? "2" : "1"; //瓶坯注塑机站点根据配置文件获取 if (taskType.Contains("注塑") && taskType.Contains("瓶坯")) { var devInfo = Settings.deviceInfos.Where(a => (a.TN_Location.Contains(mst.S_START_LOC) || a.TN_Location.Contains(mst.S_END_LOC)) && a.enable == 1).FirstOrDefault(); string machine = (devInfo.TN_Location[0] == mst.S_START_LOC || devInfo.TN_Location[0] == mst.S_END_LOC) ? "A" : "B"; string machineTwo = devInfo.deviceName.Split('-')[1] + machine; LogHelper.Info($"机台:{machineTwo}"); var siteInfo = Settings.pPZSJSites.Where(a => a.siteName == machineTwo && a.enable == 1).FirstOrDefault(); if (siteInfo != null) { if (taskType.Contains("空托上线")) { //改变终点站点 Extend2 = siteInfo.site[1]; } else { //改变起点站点 Extend1 = siteInfo.site[0]; } } else LogHelper.Info("配置文件未配置瓶坯注塑机站点"); } } Console.WriteLine($"[SendTask]:TaskNo={mst.S_CODE.Trim()},start={Extend1},end={Extend2}"); LogHelper.Info($"[SendTask]:TaskNo={mst.S_CODE.Trim()},start={Extend1},end={Extend2}"); bool action = true; var dic = new Dictionary(); //var dic1 = new Dictionary(); //dic.Add("Pri", mst.N_PRIORITY.ToString()); //dic.Add("No", mst.S_CODE.Trim()); dic.Add("From", Extend1); dic.Add("To", Extend2); dic.Add("Func", Extend3); dic.Add("Data", Extend4); if (ConveryTaskList.Contains(taskType) || taskType.Contains("移库")) { dic.Add("ItemHeight", Extend5); dic.Add("CntrType", Extend6); dic.Add("FromCol", Extend7); dic.Add("ToCol", Extend8); if (taskType.Contains("移库") || taskType.Contains("成品下线") || taskType.Contains("零头下线")) { LogHelper.Info($"移库:Extend5:{Extend5},Extend6:{Extend6},Extend7:{Extend7},Extend8:{Extend8},"); if (Extend5 == "" || Extend6 == "" || Extend7 == "" || Extend8 == "") { action = false; } } } if (action) { var res = new AGVResult(); res = NDC.AddNewOrderNew(TsNo,mst.N_PRIORITY,mst.S_CODE, dic); if (res != null && (res.Res.ErrCode == 0 || res.Res.ErrCode == 50009)) { mst.N_B_STATE = 1; WCSHelper.UpdateStatus(mst, "已推送"); result = true; } } } catch (Exception ex) { LogHelper.Error($"SendTaskStandard Error:{ex.Message}", ex); } //mst.N_B_STATE = 1; //WCSHelper.UpdateStatus(mst, "已推送"); //result = true; } return result; } /// /// 创建搬运任务 /// /// /// /// /// /// /// /// /// /// public static bool CreateTransport(string start, string end, string taskType, List cntrs, int startLayer, int endLayer, int trayCarryCount = 1, int priority = 1) { var result = false; //批次号存托盘号,1~3个托盘 var trayCodes = string.Join(",", cntrs); var taskNo = DateTime.Now.Ticks.ToString(); var res = WCSHelper.CreateTask(taskNo, start.Trim(), end.Trim(), taskType, priority, trayCodes, trayCarryCount, startLayer, endLayer); if (res) { result = true; //任务创建成功,起点货位出库锁定,终点货位入库锁定 LocationHelper.LockLoc(start, 1); LocationHelper.LockLoc(end, 2); } return result; } public static bool CreateTransport(string start, string end, string taskType, List cntrs, int priority = 1) { var result = false; //批次号存托盘号,1~3个托盘 var trayCodes = string.Join(",", cntrs); var taskNo = DateTime.Now.Ticks.ToString(); var res = WCSHelper.CreateTask(taskNo, start.Trim(), end.Trim(), taskType, priority, trayCodes, 1, 1, 1); if (res) { result = true; LocationHelper.LockLoc(start, 2); LocationHelper.LockLoc(end, 1); } return result; } #endregion /// /// 半成品出入库 /// /// /// /// /// /// public static Location BCPInOrOut(SqlSugarClient db, bool action, string areaName,string itemCode) { Location result = null; if (action) { //瓶盖库区,两层密集型库区 空满在同一个库区,需要区分不同排 var areaInfo = Settings.areaInfos.Where(a => a.areaName == areaName && a.enable == 1).First(); if (areaInfo != null) { //库区货位约定:列号越小越靠里 LogHelper.Info($"入库算法01:area:{areaInfo.areaCode},itemCode:{itemCode}", "WMSAlgoRithm"); try { if (result == null) { var locInfo = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM > 0).OrderBy(a => a.N_ROW).OrderByDescending(a => a.N_COL) .PartitionBy(a => a.N_ROW).Take(1) .ToList(); if (locInfo.Count > 0) { foreach (var a in locInfo) { //去掉当前货位有锁,或者为空托的货位 if (a.S_LOCK_STATE == "无") { string endItemCode = ""; var endCntrInfo = db.Queryable().Where(b => b.S_LOC_CODE == a.S_CODE).First(); if (endCntrInfo != null) { var endItemInfo = db.Queryable().Where(b => b.S_CNTR_CODE == endCntrInfo.S_CNTR_CODE).First(); if (endItemInfo != null) { endItemCode = endItemInfo.S_ITEM_CODE; } } else { LogHelper.Info($"终点货位未绑定托盘信息"); continue; } //判断是否和当前货位的物料编码相同 if (itemCode == endItemCode) { //查询当前排是否可入(判断是是否有入库锁和出库锁) var lockInfo = db.Queryable().Where(b => b.S_AREA_CODE == a.S_AREA_CODE && b.N_ROW == a.N_ROW && (b.S_LOCK_STATE == "入库锁" || b.S_LOCK_STATE == "出库锁")).First(); if (lockInfo == null) { //当前排无任务 if (a.N_CURRENT_NUM < a.N_CAPACITY) result = a; else { //查询后面当前货位后一个 result = db.Queryable().Where(b => b.S_AREA_CODE == a.S_AREA_CODE && b.N_ROW > a.N_ROW && b.S_LOCK_STATE == "无").OrderBy(b => b.N_COL).First(); } if (result != null) { break; } } } } } } if (result == null) { //todo 还需要判断锁 #region 查找所有数量是空的排 LogHelper.Info($"入库算法06:无可用货位,获取空排货位。", "WMSAlgoRithm"); //2.0 简化查询只查每一排第一列 var list = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode).OrderBy(a => a.N_ROW).OrderBy(a => a.N_COL).PartitionBy(a => a.N_ROW).ToList().Where(a => a.N_CURRENT_NUM == 0).ToList(); //2.1 选一个空排 if (list.Count > 0) { LogHelper.Info($"入库算法06:无可用货位,获取空排货位数量为:{list.Count}。", "WMSAlgoRithm"); for (int i = 0; i < list.Count; i++) { LogHelper.Info($"入库算法07:获取空排货位:货位编码:{list[i].S_CODE.Trim()},当前数量:{list[i].N_CURRENT_NUM},排号:{list[i].N_ROW},库区编码:{list[i].S_AREA_CODE.Trim()}", "WMSAlgoRithm"); if (list[i].S_LOCK_STATE.Trim().Contains("无")) { //二次校验当前排所有货位都是空的,防止系统数据错乱 int row = list[i].N_ROW; string areaCode = list[i].S_AREA_CODE.Trim(); var lockInfo = db.Queryable().Where(b => b.S_AREA_CODE == areaCode && b.N_ROW == row && (b.S_LOCK_STATE == "入库锁" || b.S_LOCK_STATE == "出库锁")).First(); if (lockInfo == null) { var locInfo1 = db.Queryable().Where(a => a.S_AREA_CODE == areaCode && a.N_ROW == row).Select(a => new { sum = SqlFunc.AggregateSum(a.N_CURRENT_NUM) }).First(); if (locInfo1 != null) { LogHelper.Info($"{locInfo1.sum},row:{row}"); if (locInfo1.sum == 0) { //空排 result = list[i]; break; } } else LogHelper.Info("未找到该排"); } else { LogHelper.Info("该排有锁"); } } } } else LogHelper.Info($"未获取到空排,库区编码:{areaInfo.areaCode}"); #endregion } } } catch (Exception ex) { Console.WriteLine("GetLocationIn:" + ex.Message + ex.StackTrace); LogHelper.Error("GetLocationIn:" + ex.Message, ex); } } else { LogHelper.Info($"入库任务 起点货位未绑定物料信息"); } } else { var areaInfo = Settings.areaInfos.Where(a => a.areaName == areaName && a.enable == 1).FirstOrDefault(); if(areaInfo != null) { var locList = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM > 0).OrderBy(a => a.N_ROW).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).Includes(a => a.LocCntrRel).ToList(); if(locList.Count > 0) { foreach(var a in locList) { if(a.S_LOCK_STATE == "无") { var cntrInfo = db.Queryable().Where(b => b.S_LOC_CODE == a.S_CODE).First(); if(cntrInfo != null) { string endItemCode = ""; var itemInfo = db.Queryable().Where(b => b.S_CNTR_CODE == cntrInfo.S_CNTR_CODE).First(); if(itemInfo != null && itemInfo.S_ITEM_CODE == itemCode) { endItemCode = itemInfo.S_ITEM_CODE; } if(endItemCode == itemCode) { //判断当前排有无锁 var lockInfo = db.Queryable().Where(b => b.S_AREA_CODE == areaInfo.areaCode && b.N_ROW == a.N_ROW && (b.S_LOCK_STATE == "入库锁" || b.S_LOCK_STATE == "出库锁")).First(); if (lockInfo == null) { result = a; break; } } } } } } } else { LogHelper.Info($"{areaName}未配置"); } } return result; } internal static Location getMStartLoc(SqlSugarClient db) { Location result = null; var areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯注塑机空托" && a.enable == 1).FirstOrDefault(); if(areaInfo != null) { var locInfo = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM > 0 && a.S_LOCK_STATE == "无").Includes(a => a.LocCntrRel).First(); if(locInfo != null) { result = locInfo; } } else { LogHelper.Info("瓶坯注塑机空托未配置"); } return result; } /// /// 瓶坯注塑满托下线 /// /// /// /// /// internal static Location BCPFullOut(SqlSugarClient db, string taskName, string itemCode) { Location result = null; if (taskName.Contains("即产")) { //即产即用工单,下线到即产即用库区 //即产即用库区有两个线边库,如果即产即用A库区满,则放到即产即用B库区,若即产即用库区都满,则放到瓶坯库区 var areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯即产即用A" && a.enable == 1).FirstOrDefault(); if(areaInfo != null) { var locInfo = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM < a.N_CAPACITY && a.S_LOCK_STATE == "无").OrderBy(a => a.N_COL).First(); if(locInfo != null) { result = locInfo; } } if (result == null) { result = TaskProcess.BCPInOrOut(db, true, "瓶坯即产即用B", itemCode); } if(result == null) { result = TaskProcess.BCPInOrOut(db, true, "瓶坯库区", itemCode); } } else { //非即产即用工单,下线到非即产即用库区 //非即产即用库区只有一个线边库,如果线边库满,则放到瓶坯库区 var areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯非即产即用" && a.enable == 1).FirstOrDefault(); if (areaInfo != null) { var locInfo = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM < a.N_CAPACITY && a.S_LOCK_STATE == "无").OrderBy(a => a.N_COL).First(); if (locInfo != null) { result = locInfo; } } if (result == null) { result = TaskProcess.BCPInOrOut(db, true, "瓶坯库区", itemCode); } } return result; } /// /// 翻斗机空托下线 /// /// /// /// /// internal static Location BCPEmptyOut(SqlSugarClient db, string taskName) { Location result = null; //翻斗机库存空托下线(瓶盖) string endAreaName = taskName.Contains("瓶盖") ? "瓶盖空托" : "瓶坯空托"; var areaInfo = Settings.areaInfos.Where(a => a.areaName == endAreaName && a.enable == 1).FirstOrDefault(); if(areaInfo != null) { var locInfo = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM > 0 && a.S_LOCK_STATE == "无").OrderBy(a => a.N_COL).First(); if(locInfo != null) { result = locInfo; } } else { LogHelper.Info($"{endAreaName}未配置"); } return result; } /// /// 半成品移库 /// /// true - 工单开启 false - 工单关闭 /// 设备 internal static void BCPYiKu(bool action, string machine) { var db = new SqlHelper().GetInstance(); Location startLoc = null; Location endLoc = null; if (action) { if(machine == "瓶坯翻斗机") { //瓶坯翻斗机 //开启,判断工单类型,根据工单类型补充对应的库区 即产即用不补充 var areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯非即产即用" && a.enable == 1).FirstOrDefault(); if (areaInfo != null) { var workInfo = db.Queryable().Where(a => a.S_PLineNo == "农夫林芝-瓶批翻斗机" && a.S_WorkState == "执行中").First(); if (workInfo.S_UsingNow == "N") { startLoc = TaskProcess.BCPInOrOut(db, false, "瓶坯库区", workInfo.S_ItemCode); endLoc = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM < a.N_CAPACITY && a.S_LOCK_STATE == "无").OrderBy(a => a.N_COL).First(); } } else { LogHelper.Info("瓶坯非即产即用未配置"); } } if (machine == "瓶坯注塑机") { //开启,查询 瓶坯空托 是否空托数量大于3托,如果不大于,则补空托 var areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯空托" && a.enable == 1).FirstOrDefault(); if(areaInfo != null) { var locList = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM > 0 && a.S_LOCK_STATE == "无").ToList(); if(locList.Count > 2) { LogHelper.Info("瓶坯空托 补空托"); startLoc = TaskProcess.BCPInOrOut(db, false, "瓶坯库区",""); endLoc = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM < a.N_CAPACITY && a.S_LOCK_STATE == "无").OrderBy(a => a.N_COL).First(); } } else { LogHelper.Info("瓶坯空托未配置"); } } if (machine == "瓶盖翻斗机") { //开启,查询 瓶盖非急产急用 物料是否满,不满则补充物料 var areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶盖非即产即用" && a.enable == 1).FirstOrDefault(); if (areaInfo != null) { var locInfo = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM < a.N_CAPACITY && a.S_LOCK_STATE == "无").First(); if(locInfo != null) { LogHelper.Info("瓶盖非即产即用 补满托"); var workInfo = db.Queryable().Where(a => a.S_PLineNo == "农夫林芝-瓶盖翻斗机" && a.S_WorkState == "执行中").First(); startLoc = TaskProcess.BCPInOrOut(db, false, "瓶盖库区", workInfo.S_ItemCode); endLoc = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM < a.N_CAPACITY && a.S_LOCK_STATE == "无").OrderBy(a => a.N_COL).First(); } } else { LogHelper.Info("瓶盖非即产即用未配置"); } } } else { if (machine == "瓶坯翻斗机") { //关闭,查询 瓶坯非即产即用 瓶坯即产即用A 瓶坯即产即用B 是否有物料,有则入库 var areaList = Settings.areaInfos.Where(a => (a.areaName == "瓶坯非即产即用" || a.areaName == "瓶坯即产即用A") && a.enable == 1).ToList(); if (areaList.Count > 0) { foreach(var a in areaList) { startLoc = db.Queryable().Where(b => b.S_AREA_CODE == a.areaCode && b.N_CURRENT_NUM > 0 && b.S_LOCK_STATE == "无").Includes(b => b.LocCntrRel).First(); if (startLoc != null) break; } } if (startLoc == null) { var areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯即产即用B" && a.enable == 1).FirstOrDefault(); if(areaInfo != null) { var locInfo = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM > 0).OrderBy(a => a.N_ROW).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).Includes(a => a.LocCntrRel).ToList(); if(locInfo.Count > 0) { foreach(var a in locInfo) { int row = a.N_ROW; var lockInfo = db.Queryable().Where(b => b.S_AREA_CODE == areaInfo.areaCode && b.N_ROW == a.N_ROW && (b.S_LOCK_STATE == "入库锁" || b.S_LOCK_STATE == "出库锁")).First(); if(lockInfo == null) { startLoc = a; } } } } } if(startLoc != null) { if (startLoc.LocCntrRel != null) { var itemInfo = db.Queryable().Where(a => a.S_CNTR_CODE == startLoc.LocCntrRel.S_CNTR_CODE).First(); if (itemInfo != null) { endLoc = TaskProcess.BCPInOrOut(db, true, "瓶坯库区", itemInfo.S_ITEM_CODE); } } } } if (machine == "瓶坯注塑机") { //关闭,查询 瓶坯空托 是否有空托,有则入库 var areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯空托" && a.enable == 1).FirstOrDefault(); if (areaInfo != null) { startLoc = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM > 0 && a.S_LOCK_STATE == "无").Includes(a => a.LocCntrRel).First(); if(startLoc != null) { endLoc = TaskProcess.BCPInOrOut(db, true, "瓶坯库区", ""); } } } if (machine == "瓶盖翻斗机") { //关闭, 1、查询 瓶盖空托 是否还有托盘,有则入库 2、查询瓶盖非即产即用 是否有物料, 有则入库 //关闭,查询 瓶坯空托 是否有空托,有则入库 //查询空托库区 var areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶盖空托" && a.enable == 1).FirstOrDefault(); if (areaInfo != null) { startLoc = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM > 0 && a.S_LOCK_STATE == "无").Includes(a => a.LocCntrRel).First(); if (startLoc != null) { endLoc = TaskProcess.BCPInOrOut(db, true, "瓶盖库区", ""); } } //查询满托库区 if(startLoc == null) { areaInfo = Settings.areaInfos.Where(a => a.areaName == "瓶盖非即产即用" && a.enable == 1).FirstOrDefault(); if (areaInfo != null) { startLoc = db.Queryable().Where(a => a.S_AREA_CODE == areaInfo.areaCode && a.N_CURRENT_NUM > 0 && a.S_LOCK_STATE == "无").Includes(a => a.LocCntrRel).First(); if (startLoc != null) { if(startLoc.LocCntrRel != null) { var itemInfo = db.Queryable().Where(a => a.S_CNTR_CODE == startLoc.LocCntrRel.S_CNTR_CODE).First(); if(itemInfo != null) { endLoc = TaskProcess.BCPInOrOut(db, true, "瓶盖库区", itemInfo.S_ITEM_CODE); } } } } } } } if (startLoc != null && endLoc != null) { WMSHelper.CreateOpTask(startLoc.S_CODE, endLoc.S_CODE, "入库", "半成品移库", startLoc.LocCntrRel.S_CNTR_CODE); } } /// /// 任务信息接口--汉和任务每个状态进行实时上传(包括任务创建时,上报 8) /// /// internal static void GeneralInterFaceFunc(WCSTask wmsTask, string taskStatus, string forkliftNo = "") { string msg = ""; var req = new SimpleResult(); var db = new SqlHelper().GetInstance(); ///同一条任务同种状态只上报一次 ///查询任务动作表,有任务相同并且任务状态相同的,就不上报(任务状态为1还要查询车号是否存在) bool flage = false; var no = wmsTask.S_CODE; var code = int.Parse(taskStatus); if (taskStatus == "1") { if (forkliftNo != "0") { if (db.Queryable().Count(a => a.S_TASK_CODE.Trim() == no.Trim() && a.N_ACTION_CODE == code) == 2) { wmsTask.S_EQ_NO = forkliftNo; flage = true; } } } else { flage = true; } if (flage) { if (WCSHelper.CheckActionRecordExist(wmsTask.S_CODE, 4) && taskStatus == "7") taskStatus = "2"; try { //获取上报接口的URL var url = Settings.thirdPartyUrls.Where(a => a.UrlNo == "1" && a.enable == 1).FirstOrDefault(); LogHelper.Info($"GeneralInterFaceFunc:任务号:{wmsTask.S_CODE},任务状态:{taskStatus},获取URL:{url}", "ThirdSystemLog"); //任务类型数据处理 string taskType = ""; var taskTypeInfo = db.Queryable().Where(a => a.taskTypeName == wmsTask.S_TYPE).First(); if (taskTypeInfo != null) taskType = taskTypeInfo.taskType; LogHelper.Info($"GeneralInterFaceFunc:任务号:{wmsTask.S_CODE},任务状态:{taskStatus},任务类型数据处理:{taskType}", "ThirdSystemLog"); //托盘物料数据处理 List cntrList = new List(wmsTask.S_CNTR_CODE.Split(','));//获取托盘数据 string itemCode = "";//物料编码 itemCode = GeneralInterFaceGetItemCodeFunc(wmsTask, db, cntrList, itemCode); LogHelper.Info($"GeneralInterFaceFunc:任务号:{wmsTask.S_CODE},任务状态:{taskStatus},物料编码:{itemCode}", "ThirdSystemLog"); List asnReferenceList = new List { };//托码数组 GeneralInterFaceGetTrayCodeFunc(wmsTask, db, asnReferenceList, cntrList); LogHelper.Info($"GeneralInterFaceFunc:任务号:{wmsTask.S_CODE},任务状态:{taskStatus},获取托盘数据:{JsonConvert.SerializeObject(asnReferenceList)}", "ThirdSystemLog"); //AGV设备信息处理 string equipmentCode = ""; string orgCode = ""; string orgName = ""; string proxyInterfaceCode = "0050"; GeneralInterFaceGetAgvDeviceInfoFunc(wmsTask, db, ref equipmentCode, ref orgCode, ref orgName, ref proxyInterfaceCode); LogHelper.Info($"GeneralInterFaceFunc:任务号:{wmsTask.S_CODE},任务状态:{taskStatus},equipmentCode:{equipmentCode},orgCode:{orgCode},orgName:{orgName},proxyInterfaceCode:{proxyInterfaceCode}", "ThirdSystemLog"); LogHelper.Info($"wmstask.t_start_time:{wmsTask.T_START_TIME}"); if (DateTime.MinValue == wmsTask.T_START_TIME) { wmsTask.T_START_TIME = null; } DateTime dateTime = taskStatus == "1" ? Convert.ToDateTime(wmsTask.T_START_TIME).AddHours(-8) : taskStatus == "2" || taskStatus == "7" ? Convert.ToDateTime(wmsTask.T_END_TIME).AddHours(-8) : taskStatus == "8" ? Convert.ToDateTime(wmsTask.T_CREATE).AddHours(-8) : DateTime.UtcNow; string createTime = GetTimeStamp(wmsTask.T_CREATE.AddHours(-8), 1, 2); string startTime = ""; //在C#中,使用DateTimeOffset.UtcNow.ToUnixTimeSeconds()方法获取Unix时间戳时,可能会多出一个毫秒。这是因为Unix时间戳是以秒为单位的,而DateTimeOffset.UtcNow返回的是UTC时间,其精度为100纳秒。 if (wmsTask.S_WORK_MODE != "agv" && !string.IsNullOrEmpty(wmsTask.S_WORK_MODE)) startTime = wmsTask.S_WORK_MODE; else { startTime = wmsTask.T_START_TIME == null ? null : GetTimeStamp(Convert.ToDateTime(wmsTask.T_START_TIME).AddHours(-8), 1, 2); if (startTime != null) { wmsTask.S_WORK_MODE = startTime; db.Updateable(wmsTask).UpdateColumns(a => new { a.S_WORK_MODE }).ExecuteCommand(); } } string endTime = wmsTask.T_END_TIME == null ? null : GetTimeStamp(Convert.ToDateTime(wmsTask.T_END_TIME).AddHours(-8), 1, 2); string businessTime = taskStatus == "1" ? startTime : taskStatus == "2" || taskStatus == "7" ? endTime : taskStatus == "8" ? createTime : GetTimeStamp(dateTime, 1, 2); string dt = wmsTask.T_START_TIME == null ? null : Convert.ToDateTime(wmsTask.T_START_TIME).AddHours(-8).ToString(); string mill = wmsTask.T_START_TIME == null ? null : Convert.ToDateTime(wmsTask.T_START_TIME).AddHours(-8).Millisecond.ToString(); LogHelper.Info($"GeneralInterFaceFunc:任务号:{wmsTask.S_CODE},任务状态:{taskStatus},任务开始时间:{wmsTask.T_START_TIME},任务转换后时间:{dt},任务号毫秒时间:{mill},转换后时间:{startTime}", "ThirdSystemLog"); string sendMsg = JsonConvert.SerializeObject(new { taskCode = wmsTask.S_CODE,//任务编码 taskStatus = taskStatus,//任务状态-任务创建成功传输 8 taskType = taskType,//任务类型-需要根据 配置表数据进行转换,转换为MES的任务类型 createTime = createTime,//需转换为 时间戳 wmsTask.T_CREATE startTime = startTime,//需转换为 时间戳 wmsTask.T_START_TIME endTime = endTime,//需转换为 时间戳 wmsTask.T_END_TIME businessTime = businessTime,//当前任务时间-需转换为 时间戳 DateTime.Now startAddress = wmsTask.S_START_LOC,//起点 endAddress = wmsTask.S_END_LOC,//终点 equipmentNo = wmsTask.S_EQ_NO,//车辆编号 equipmentCode = equipmentCode,//车辆铭牌-需要根据 配置表数据,通过 车辆编号以及工厂编码 查询对应车辆铭牌 orgCode = Settings.FactoryCode,//工厂编码 orgName = Settings.FactoryName,//工厂名称 sku = itemCode,//物料编码 asnReferenceDList = asnReferenceList,//托码数组 此次叉车叉的托盘喷码, 一次叉辆车,有两个编码 产线下线且非无码模式时传输 appliactionId = "MOBOX" //proxyInterfaceCode = proxyInterfaceCode //接口唯一标识码 固定值:0050 }); //http://yst-open-zuul-qa.idc.yst.com.cn/proxy/v1/ req = FuLeWebPost(sendMsg, "generalInterface", url.Url, true);//YKRWSD AreaRowLockState if (req != null && req.success) msg = $"GeneralInterFaceFunc:返回任务状态成功:{JsonConvert.SerializeObject(req)}!"; else msg = $"GeneralInterFaceFunc:返回任务状态失败:{JsonConvert.SerializeObject(req)}!"; } catch (Exception ex) { msg = $"GeneralInterFaceFunc Error:TaskInfo:{JsonConvert.SerializeObject(wmsTask)},TaskState:{taskStatus},ErrorMsg:{ex.Message}"; } } LogHelper.Info(msg, "ThirdSystemLog"); } /// /// FuLeWebPost /// /// 发送内容 /// 接口名称 /// 扩展参数 /// public static SimpleResult FuLeWebPost(string param, string postName, string Par1 = "", bool extend = false) { string msg = ""; string feedback = ""; SimpleResult result = new SimpleResult(); try { string webAPIUrl = ""; var httpVerify = new Settings.httpApiVerify(); if (extend) httpVerify = Settings.httpApiVerifys.Where(a => a.VerifyNo == "2" && a.Project == Settings.ProjectName && a.enable == 1).FirstOrDefault(); else httpVerify = Settings.httpApiVerifys.Where(a => a.VerifyNo == "1" && a.Project == Settings.ProjectName && a.enable == 1).FirstOrDefault(); if (httpVerify != null) { //采用接口加密方式进行传输 webAPIUrl = $"{Par1}{postName}"; string TokenMsg = ""; string timestamp = DateTime.Now.ToString("s").Replace("T", " "); TokenMsg = httpVerify.Extend[0] + "from" + httpVerify.Extend[1] + "timestamp" + timestamp; LogHelper.Info($"【FuLe Post {postName}】:加密前明文:{TokenMsg}", "ThirdSystemLog"); string TokenMsgEncrypt = CryptoDecryptHelper.GetMd5FromString(TokenMsg); LogHelper.Info($"【FuLe Post {postName}】:加密后密文:{TokenMsgEncrypt}", "ThirdSystemLog"); feedback = httpHelper.WebPost(webAPIUrl, param, "application/json", TokenMsgEncrypt, timestamp,"", extend); } else { //标准传输方式传输 webAPIUrl = $"{Par1}{postName}" + "&warehouseId=FLUXWMSDB"; feedback = httpHelper.WebPost(webAPIUrl, param); } if (!string.IsNullOrEmpty(feedback)) { LogHelper.Info(JsonConvert.SerializeObject(feedback)); msg = $"【FuLe Post {postName}】WebUrl={webAPIUrl};param={param} ;return={feedback}"; var req = JsonConvert.DeserializeObject(feedback); if (req.success) { result.success = true; msg = $"【FuLe Post {postName}】success!;WebUrl={webAPIUrl};param={param};return={feedback}"; } else { if (!string.IsNullOrEmpty(req.errMsg)) msg = $"【FuLe Post {postName}】fail!err={req.errMsg};WebUrl={webAPIUrl} ;param={param};return={feedback}"; else msg = $"【FuLe Post {postName}】fail!err={req.message};WebUrl={webAPIUrl} ;param={param};return={feedback}"; } } else { string errMsg = "can't find the address"; msg = $"【FuLe Post {postName}】fail!err={errMsg};WebUrl={webAPIUrl} ;param={param}"; } var db = new SqlHelper().GetInstance(); var RepeatUrl = db.Queryable().Where(a => a.SendMsg == param && a.UrlName == postName && a.Url == Par1).First(); if (result.success) { if (RepeatUrl != null) db.Deleteable().Where(a => a.SendMsg == param && a.UrlName == postName && a.Url == Par1).ExecuteCommand(); } else { if (RepeatUrl == null) { var RepeatInfo = new HttpRepeatSend() { SendMsg = param, UrlName = postName, Url = Par1, SendNum = 5 }; db.Insertable(RepeatInfo).ExecuteCommand(); } else { if (RepeatUrl.SendNum == 1) db.Deleteable().Where(a => a.SendMsg == param && a.UrlName == postName && a.Url == Par1).ExecuteCommand(); else { RepeatUrl.SendNum = RepeatUrl.SendNum - 1; db.Updateable(RepeatUrl).UpdateColumns(a => new { a.SendNum }).ExecuteCommand(); } } } } catch (Exception ex) { msg = $"【FuLe Post {postName}】fail!err={ex.Message}"; } LogHelper.Info(msg, "ThirdSystemLog"); return result; } /// /// 接口状态回报处理 /// public class SimpleResult { public bool success { get; set; } public int errCode { get; set; } public string errMsg { get; set; } = ""; /// /// 淳安二期-响应数据 /// public Object data { get; set; } /// /// 淳安二期-响应编码 /// public string code { get; set; } /// /// 淳安二期-响应信息 /// public string message { get; set; } /// /// 淳安二期-响应信息类型 /// public string messageType { get; set; } /// /// 淳安二期-异常 /// public Exception exception { get; set; } } /// /// 任务信息接口--获取时间戳 /// /// 数据位数:值:32|64 含义:32位|64位 /// 获取时间类型:值:1|2 含义:1-秒级 2-毫秒级 /// 获取时间Utc类型:值:1|2 含义:1-本地时间 2-Utc时间 /// public static string GetTimeStamp(DateTime dateTime, int DataBitType, int TimeType) { string timeStamp = ""; //时间戳打印 TimeSpan ts = dateTime - new DateTime(1970, 1, 1, 0, 0, 0, 0);//时间戳获取 double tsTime = TimeType == 1 ? ts.TotalSeconds : ts.TotalMilliseconds;//秒级|毫秒级时间获取 string TimeTypeInfo = TimeType == 1 ? "秒级" : "毫秒级"; timeStamp = DataBitType == 32 ? Convert.ToInt32(tsTime).ToString() : Convert.ToInt64(tsTime).ToString(); //double result = 0; //result = DataBitType == 32 ? Convert.ToInt32(tsTime) : Convert.ToInt64(tsTime); return timeStamp; } /// /// 任务信息接口--获取AGV设备信息数据 /// /// /// /// /// /// /// private static void GeneralInterFaceGetAgvDeviceInfoFunc(WCSTask wmsTask, SqlSugarClient db, ref string equipmentCode, ref string orgCode, ref string orgName, ref string proxyInterfaceCode) { if (!string.IsNullOrEmpty(wmsTask.S_EQ_NO)) { var agvDeviceInfo = db.Queryable().Where(a => a.equipmentNo == wmsTask.S_EQ_NO && a.orgCode == Settings.FactoryCode).First(); if (agvDeviceInfo != null) { equipmentCode = agvDeviceInfo.equipmentCode; orgCode = agvDeviceInfo.orgCode; orgName = agvDeviceInfo.orgName; proxyInterfaceCode = agvDeviceInfo.proxyInterfaceCode; } } } /// /// 任务信息接口--获取托盘数据 /// /// private static void GeneralInterFaceGetTrayCodeFunc(WCSTask wmsTask, SqlSugarClient db, List asnReferenceList, List cntrList) { //string SrcNo = wmsTask.S_SRC_NO?.Trim(); // ////根据任务中存放的工单号,获取工单类型--因为淳安 满托下线任务包含 下线 值,因此多判断一步,减少工单表的查询 //if (!string.IsNullOrEmpty(SrcNo) && wmsTask.S_TYPE.Contains("下线")) //{ // var workInfo = db.Queryable().Where(a => a.S_WorkNo == SrcNo).First(); // if (workInfo != null) // { // if (workInfo.S_ORDER_TYPE.Trim() != "无码入库") // { // // if (cntrList.Count > 0) // { // cntrList.ForEach(a => // { // if (!string.IsNullOrEmpty(a)) // asnReferenceList.Add(new asnReferenceDModel { asnReferenceD = a }); // }); // } // } // } //} } public class asnReferenceDModel { public string asnReferenceD { get; set; } } /// /// 任务信息接口--获取物料编码 /// /// private static string GeneralInterFaceGetItemCodeFunc(WCSTask wmsTask, SqlSugarClient db, List cntrList, string itemCode) { if (cntrList.Count > 0) { //string SrcNo = wmsTask.S_SRC_NO?.Trim(); //// 农夫网管下发的工单,物料获取方式 //if (!string.IsNullOrEmpty(SrcNo) && wmsTask.S_TYPE.Contains("下线")) //{ // var workInfo = db.Queryable().Where(a => a.S_WorkNo == SrcNo).First(); // if (workInfo != null) itemCode = workInfo.S_ItemCode; //} //// 其他的人工建立的工单,物料获取方式 //else //{ // var cntrItemInfo = db.Queryable().Where(a => a.S_CNTR_CODE == cntrList[0]).First(); // if (cntrItemInfo != null) // { // //此处查询 物料表,仅限淳安获取MES物料使用,其他工厂可自行注释;因淳安入库物料是使用 物料名称+物料层数 拼接而成,因此需要 通过物料表转换为 MES 的物料编码 // //var itemInfo = db.Queryable().Where(a => a.S_ITEM_NAME == cntrItemInfo.S_ITEM_CODE).First(); // //if (itemInfo != null) itemCode = itemInfo.S_ITEM_CODE; // itemCode = cntrItemInfo.S_ITEM_CODE; // } //} } return itemCode; } } }