using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using HH.WCS.JingyuNongfu.wms; using HH.WCS.JingyuNongfu.util; using SqlSugar.Extensions; using Newtonsoft.Json; using System.Reflection; namespace HH.WCS.JingyuNongfu.process { /// /// 成品流程 /// internal class ProcessHelperCP { private static Dictionary itemHeights = new Dictionary(); static ProcessHelperCP() { new SqlHelper().CreateTable(new List { typeof(MoveOrderNotice), typeof(InOutRecord), typeof(PgZsjReportMesInfo), typeof(PgFdjReportMesFeedInfo), typeof(PgReportFluxInfo), }); var db = new SqlHelper().GetInstance(); var list = db.Queryable().ToList(); if (list.Count > 0) { list.ForEach(a => { if (!itemHeights.Keys.Contains(a.S_ITEM_NAME)) { itemHeights.Add(a.S_ITEM_NAME, a.S_ITEM_LAYER); } }); } } /// /// 根据物料信息获取托盘高度 /// /// /// internal static int GetTrayHeightByItem(string itemCode) { var result = 0; if (itemHeights.Keys.Contains(itemCode)) { result = itemHeights[itemCode]; } else { var db = new SqlHelper().GetInstance(); var itemInfo = db.Queryable().Where(a => a.S_ITEM_CODE == itemCode).First(); if (itemInfo != null) { result = itemInfo.S_ITEM_LAYER; itemHeights.Add(itemCode, itemInfo.S_ITEM_LAYER); } } return result; } /// /// 获取物料二层高度 /// /// 物料名称 /// 物料层高 /// 托盘类型 /// internal static int GetTrayHeight(string itemCode, string itemLayer, string irayType) { var result = 0; //if (itemHeights.Keys.Contains(itemCode + "_" + itemLayer + "_" + itemLayer)) //{ // result = itemHeights[itemCode + "_" + itemLayer + "_" + itemLayer]; //} //else //{ var db = new SqlHelper().GetInstance(); var itemInfo = db.Queryable().Where(a => a.S_ITEM_CODE == itemCode && a.S_ITEM_MODEL == itemLayer && a.S_TRAY_TYPE == irayType).First(); if (itemInfo != null) { result = itemInfo.S_ITEM_LAYER; //itemHeights.Add(itemCode + "_" + itemLayer + "_" + itemLayer, itemInfo.S_ITEM_LAYER); } // } return result; } /// /// 获取物料层高 /// /// /// internal static int GetTrayHeightByTray(string trayCode) { var result = 0; var db = new SqlHelper().GetInstance(); var cntr = db.Queryable().Where(a => a.S_CNTR_CODE.Contains(trayCode)).Includes(a => a.CntrItemRel).First(); if (cntr != null && cntr.CntrItemRel != null) { //根据物料名称、物料层数、托盘类型找物料层高 result = GetTrayHeight(cntr.CntrItemRel.S_ITEM_CODE, cntr.CntrItemRel.S_ITEM_MODEL, cntr.S_TYPE); } else { LogHelper.Info("未获取cntr信息", "HosttoagvTask"); } return result; } /// /// 获取富勒物料层高 /// /// /// internal static int GetTrayHeightByTrayFL(string trayCode) { var result = 0; int itemLayer = 0; var db = new SqlHelper().GetInstance(); var cntrfl = db.Queryable().Where(a => a.trayCode.Contains(trayCode)).First(); if (cntrfl != null) { itemLayer = int.Parse(cntrfl.itemLayer); var cntr = db.Queryable().Where(a => a.S_CNTR_CODE.Contains(trayCode)).Includes(a => a.CntrItemRel).First(); if (cntr != null && cntr.CntrItemRel != null) { //根据物料名称、物料层数、托盘类型找物料层高 result = GetTrayHeight(cntr.CntrItemRel.S_ITEM_CODE, itemLayer.ToString(), cntr.S_TYPE); } } else { LogHelper.Info("未找到富勒cntr信息", "HosttoagvTask"); } return result; } /// /// 成品下线 /// /// /// /// internal static void InStock(WorkOrder1 workOrder, string loc) { try { //判断最大任务数,如果执行中的任务大于等于最大任务数,不生成任务 if (!TaskHelper.GetTaskByMaxtask(workOrder, loc)) { LogHelper.Info($"执行中任务数量大于等于最大任务限制,不生成任务", "成品"); return; } //根据工单查询对应物料信息 var db = new SqlHelper().GetInstance(); ItemInfo item = null; if (workOrder.withCode == "是") { //使用富勒数据 // List trayInfos = GetThirdPartTrayInfo(workOrder.S_WorkNo); List trayInfos = GetThirdPartTrayInfoByDeviceName(workOrder.S_PLineNo); if (trayInfos.Count == 2) { workOrder.S_ItemLayer = trayInfos[0].itemLayer; } else { LogHelper.Info("未获取到富勒托盘号", "成品"); return; } } if (workOrder.withCode == "是") { item = db.Queryable().Where(a => a.S_ITEM_CODE == workOrder.S_ItemCode && a.S_TRAY_TYPE == workOrder.S_TrayType && a.S_ITEM_MODEL == workOrder.S_ItemLayer.ToString()).First(); } else { item = db.Queryable().Where(a => a.S_ITEM_NAME == workOrder.SQL_ItemName && a.S_TRAY_TYPE == workOrder.S_TrayType && a.S_ITEM_MODEL == workOrder.S_ItemLayer.ToString()).First(); } var itemCode = ""; var itemName = ""; var itemTrayType = ""; var itemModel = ""; if (item != null) { itemCode = item.S_ITEM_CODE; itemName = item.S_ITEM_NAME; itemTrayType = item.S_TRAY_TYPE; itemModel = item.S_ITEM_MODEL; } else { LogHelper.Info("未获取物料信息", "成品"); } var listZones = new List { }; if (!string.IsNullOrEmpty(workOrder.SQL_Area)) { listZones.Add(workOrder.SQL_Area); if (!string.IsNullOrEmpty(workOrder.SQL_Area1)) { listZones.Add(workOrder.SQL_Area1); } if (!string.IsNullOrEmpty(workOrder.SQL_Area2)) { listZones.Add(workOrder.SQL_Area2); } } else { listZones.AddRange(GetZones(workOrder.SQL_ItemName)); } //按物料名称查找库区 //var code1 = LocationHelper.GenerateCntrNo() + "_" + height; //var code2 = LocationHelper.GenerateCntrNo() + "_" + height; //var tray = $"{code1}-{code2}"; string tray = ""; string batchNo = ""; var count = "1"; if (workOrder.withCode == "是") { //使用富勒数据 // List trayInfos = GetThirdPartTrayInfo(workOrder.S_WorkNo); List trayInfos = GetThirdPartTrayInfoByDeviceName(workOrder.S_PLineNo); if (trayInfos.Count == 2) { tray = $"{trayInfos[0].trayCode},{trayInfos[1].trayCode}"; count = $"{trayInfos[0].trayNum},{trayInfos[1].trayNum}"; batchNo = trayInfos[0].batchNo + ',' + trayInfos[1].batchNo; itemCode = $"{workOrder.S_ItemCode}"; } else { Console.WriteLine("未获取到富勒托盘号"); return; } } else { batchNo = DateTime.Now.ToString("yyyyMMdd") + workOrder.S_PLineNo; } Location end = null; Console.WriteLine($"查找同品相 同设备 {itemCode} {batchNo}"); if (item == null) { Console.WriteLine("查询物料信息出错"); return; } int maxLayer = item.N_MaxLayer; Console.WriteLine($"层数:{maxLayer}"); for (int i = 0; i < listZones.Count; i++) { LogHelper.Info("库区" + listZones[i], "成品"); //LogHelper.Info($"任务:{workOrder.S_PLineNo},产线{workOrder.S_WorkNo}", "成品"); //end = LocationHelper.GetLocation4InFinish(listZones[i], workOrder.SQL_ItemCode, workOrder.size); end = GetLocation4InSameSrc(listZones[i], itemCode, batchNo, workOrder.S_TrayType, maxLayer); if (end != null) { // LogHelper.Info($"方法(GetLocation4InSameSrc)选择货位{end.S_LOC_CODE}", "成品"); break; } } if (end == null) { Console.WriteLine("查找空排"); for (int i = 0; i < listZones.Count; i++) { Console.WriteLine("库区" + listZones[i]); end = GetLocation4InEmptyRow(listZones[i], workOrder.S_TrayType); if (end != null) { // LogHelper.Info($"方法(GetLocation4InEmptyRow)选择货位{end.S_LOC_CODE}", "成品"); break; } } } //if (end == null) //{ // Console.WriteLine($"查找同品相 不同设备 {itemCode} {batchNo}"); // for (int i = 0; i < listZones.Count; i++) // { // Console.WriteLine("库区" + listZones[i]); // end = GetLocation4InAnySrc(listZones[i], itemCode, batchNo, workOrder.S_TrayType, maxLayer); // if (end != null) // { // LogHelper.Info($"方法(GetLocation4InAnySrc)选择货位{end.S_LOC_CODE}", "成品"); // break; // } // } //} if (end != null) { LogHelper.Info($"任务:{workOrder.S_PLineNo},终点库区{end.S_LOC_CODE},物料编码{itemCode},批次号{batchNo},下线托盘类型{workOrder.S_TrayType},层数{maxLayer}", "HosttoagvTask"); //生成托盘号 string[] traylist = null; if (workOrder.withCode != "是") { tray = $"{ContainerHelper.GenerateCntrNo()},{ContainerHelper.GenerateCntrNo()}"; traylist = tray.Split(','); } else { traylist = tray.Split(','); } int cg = 0; //计算层高 if (end.N_CURRENT_NUM == 0) { cg = 1; } else if (end.N_CURRENT_NUM == 2) { cg = 2; } else if (end.N_CURRENT_NUM == 4) { cg = 3; } //判断任务终点有无相同任务 if (TaskHelper.GetTaskByEndandlayer(end.S_LOC_CODE, cg)) { if (ContainerHelper.CreateCntrItem(traylist, itemCode, itemName, workOrder.S_TrayType, batchNo, count, itemModel, itemTrayType, workOrder.S_WorkNo)) { //创建入库搬运任务 if (!TaskProcess.CreateTransport(loc, end.S_LOC_CODE, "成品下线", new List { tray }, 1, cg, 1, 80, workOrder.S_WorkNo, workOrder.withCode)) { //任务创建失败删除创建的托盘 if (ContainerHelper.DeleteCntrItem(tray.Split(','))) { LogHelper.Info($"任务创建失败删除托盘{tray}", "成品"); } else { LogHelper.Info($"任务创建失败删除托盘{tray}失败", "成品"); } } } } else { LogHelper.Info($"任务终点{end.S_LOC_CODE},层高:{cg}有执行中的任务,不生成任务", "成品"); } } } catch (Exception ex) { throw ex; } } /// /// 顶升机下线 /// /// /// internal static void DsjStock(string startLoc, string endLoc) { string bussType = ""; string cntrtype = ""; if (startLoc == "LYP-1-1") { bussType = "顶升机留样品下线"; cntrtype = "留样品"; } else if (startLoc == "FL-1-1") { bussType = "顶升机废料下线"; cntrtype = "废料"; } else if (startLoc == "ZX-1-1") { bussType = "顶升机空托下线"; cntrtype = "纸箱空托"; } string tray = ContainerHelper.GenerateCntrNo(); try { if (ContainerHelper.CreateCntrItem(tray, cntrtype)) { TaskProcess.CreateTransport(startLoc, endLoc, bussType, new List { tray }, 1, 1, 1, 80); } } catch (Exception ex) { LogHelper.Info($"DsjStock-Error:{ex.ToString()}", "顶升机"); } } /// /// 获取富勒托盘数据 /// /// /// private static List GetThirdPartTrayInfo(string workNo) { var db = new SqlHelper().GetInstance(); return db.Queryable().Where(a => a.workNo == workNo).ToList(); } /// /// 获取富勒托盘数据 /// /// /// private static List GetThirdPartTrayInfoByDeviceName(string deviceName) { var db = new SqlHelper().GetInstance(); return db.Queryable().Where(a => a.deviceName == deviceName).ToList(); } /// /// 同品相 同设备 同批次 的可以入同一排 /// /// /// /// /// public static Location GetLocation4InSameSrc(string area0, string itemCode, string itemBatch, string trayType, int maxLayer = 2) { Location result = null; //string itemBatch = DateTime.Now.ToString("yyMMdd"); try { itemBatch = itemBatch.Split(',')[0]; var area = area0 + "_" + GetType(trayType); LogHelper.Info("成品满托入库 GetLocation4InSameSrc:" + area, "成品"); bool flag = false; var usedRows = GetUsedRow(area0, GetType(trayType), ref flag); if (flag) { LogHelper.Info($"当前库区{area}不可用,被其它尺寸托盘占用,直接返回"); return null; } //1.0 获取每一排最大的列 //1.1 判断当前数量是不是满的,如果是满的并且是最大列,需要排除 var listMaxCol = new SqlHelper().GetInstance().Queryable().Where(a => a.S_AREA_CODE == area).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList(); //1.1 查到所有有托盘的排 var db = new SqlHelper().GetInstance(); var list = db.Queryable().Where(a => a.N_CURRENT_NUM > 0 && a.S_AREA_CODE == area).Includes(a => a.LocCntrRel, a => a.CntrItemRel).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList(); // Console.WriteLine($"查到所有有托盘的排 {list.Count}"); // LogHelper.Info($"查到所有有托盘的排 {list.Count}", "HosttoagvTask"); ////查询移库工单相同库区的数据 //var listykstart = db.Queryable().Where(a => a.start_area== area0).ToList(); //var listykend = db.Queryable().Where(a => a.end_area== area0).ToList(); if (list.Count > 0) { //1.2 查找其它尺寸有托盘或者锁定的排 for (int i = list.Count - 1; i >= 0; i--) { LogHelper.Info("成品满托入库 GetLocation4InSameSrc:剩余排数" + list.Count, "成品"); var remove = false; //排除已经锁定的货位 和 放满了且是最大列的货位 // LogHelper.Info("成品满托入库 GetLocation4InSameSrc:11111", "成品"); if (list[i].S_LOCK_STATE.Trim() != "无" || (list[i].N_CURRENT_NUM == 4 && listMaxCol.Count(a => a.S_LOC_CODE == list[i].S_LOC_CODE) > 0)) { // Console.WriteLine($"排除已经锁定的货位 和 放满了且是最大列的货位 排{list[i].N_ROW}"); LogHelper.Info($"排除已经锁定的货位 和 放满了且是最大列的货位 排{list[i].N_ROW}", "成品"); remove = list.Remove(list[i]); } else { // LogHelper.Info("成品满托入库 GetLocation4InSameSrc:2222", "成品"); //排有锁也排除 var other = db.Queryable().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.S_LOCK_STATE.Trim() != "无").First(); if (other != null) { //Console.WriteLine($"排除有锁的排{list[i].N_ROW}"); LogHelper.Info($"排除有锁的排{list[i].N_ROW}", "成品"); remove = list.Remove(list[i]); } //LogHelper.Info("成品满托入库 GetLocation4InSameSrc:3333", "成品"); } if (!remove) { //判断是否被其它库区占用了 // LogHelper.Info($"判断是否被其它库区占用了 {list[i].N_ROW}", "成品"); if (usedRows.Contains(list[i].N_ROW)) { LogHelper.Info($"被其他库区占用{list[i].N_ROW}", "成品"); remove = list.Remove(list[i]); } } } //LogHelper.Info($"有托盘排数为{list.Count}","成品"); LogHelper.Info("成品满托入库 GetLocation4InSameSrc:开始计算排数" + list.Count, "成品"); if (list.Count > 0) { //1.3 遍历判断物料类型是否相同 //Console.WriteLine("遍历判断物料类型是否相同"); // LogHelper.Info($"遍历判断物料类型是否相同", "成品"); for (int i = 0; i < list.Count(); i++) { //Console.WriteLine($"货位{list[i].S_LOC_CODE} 物料{list[i].LocCntrRel.CntrItemRel.S_ITEM_CODE} 批次{list[i].LocCntrRel.CntrItemRel.S_BATCH_NO}"); //todo 还需要判断锁 #region 满托盘判断 物料信息相同,并且批次里面的设备相同 //var ssss = itemBatch.Substring(6).Trim(); if (list[i].LocCntrRel != null && list[i].LocCntrRel.CntrItemRel != null && list[i].LocCntrRel.CntrItemRel.S_ITEM_CODE.Trim() == itemCode && list[i].LocCntrRel.CntrItemRel.S_BATCH_NO.Contains(itemBatch.Substring(6).Trim()) && list[i].LocCntrRel.CntrItemRel.S_BATCH_NO.Length == itemBatch.Length) { // LogHelper.Info($"有托盘的货位{list[i].S_LOC_CODE} 当前数量={list[i].N_CURRENT_NUM} 容量={list[i].N_CAPACITY},入库数量={maxLayer}", "成品"); if (list[i].N_CAPACITY - list[i].N_CURRENT_NUM >= maxLayer) { //堆叠,判断批次里面的日期是不是相同的 //LogHelper.Info("堆叠,判断批次里面的日期是不是相同的", "成品"); // if (list[i].LocCntrRel.CntrItemRel.S_BATCH_NO.Trim() == itemBatch) // { result = list[i]; // Console.WriteLine("判断是不是单托"); //if (list[i].LocCntrRel.S_CNTR_CODE.Contains(',')) //{ // result = list[i]; //} //else //{ // //一层是单托,入库放后面一个位置 // Console.WriteLine("一层是单托,入库放后面一个位置"); // result = db.Queryable().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.N_COL > list[i].N_COL).First(); //} // } // else // { //排除批次不一样 //Console.WriteLine("批次不一样空一个位置"); // LogHelper.Info($" 货位{list[i].S_LOC_CODE},货位批次号{list[i].LocCntrRel.CntrItemRel.S_BATCH_NO.Trim()}和任务批次号{itemBatch}不同,批次不一样空一个位置", "成品"); // result = db.Queryable().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.N_COL > (list[i].N_COL + 1)).First(); //return null; // } } else { //LogHelper.Info($"货位当前数量{list[i].N_CURRENT_NUM },存放数量{maxLayer}", "成品"); //选择后面空位,判断批次里面日期是不是相同的 // Console.WriteLine($"判断批次是不是相同的"); // if (list[i].LocCntrRel.CntrItemRel.S_BATCH_NO.Trim() == itemBatch) // { // LogHelper.Info($"S_AREA_CODE={area},N_ROW={list[i].N_ROW},N_COL>{list[i].N_COL}", "成品"); result = db.Queryable().Where(a => a.S_AREA_CODE.Trim() == area.Trim() && a.N_ROW == list[i].N_ROW && a.N_COL > list[i].N_COL).OrderBy(a => a.N_COL).First(); //if (result != null) //{ // LogHelper.Info($"{result.S_LOC_CODE}", "成品"); //} //LogHelper.Info($"{list[i]}货位满,批次号相同找后一个空货位", "成品"); //} // else // { //LogHelper.Info($"{list[i]}货位满,批次号不同,隔一个空位", "成品"); // result = db.Queryable().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.N_COL > (list[i].N_COL + 1)).First(); //return null; // } } if (result != null && (!string.IsNullOrEmpty(result.C_ENABLE) && result.C_ENABLE == "禁用")) { //禁用了选择后面一个货位 result = db.Queryable().OrderBy(a => a.N_COL).Where(a => (string.IsNullOrEmpty(a.C_ENABLE) || a.C_ENABLE.Trim() != "禁用") && a.S_AREA_CODE == area && a.N_ROW == result.N_ROW && a.N_COL > result.N_COL).First(); //LogHelper.Info($"禁用选择后一个货位{result}", "成品"); } if (result != null) { break; } //根据容器编码获取容器信息 var ctrlCode = list[i].LocCntrRel.CntrItemRel.S_CNTR_CODE.Trim(); var ctrl = ContainerHelper.GetCntr(ctrlCode); //托盘类型不一样隔一排位置 if (ctrl.S_TYPE != trayType) { Console.WriteLine("托盘类型不一样隔一排"); break; } } else { LogHelper.Info($"货位{list[i].S_LOC_CODE}不允许堆叠,托盘:{list[i].LocCntrRel.S_CNTR_CODE},容器货品{list[i].LocCntrRel.CntrItemRel},托盘物料编码{list[i].LocCntrRel.CntrItemRel.S_ITEM_CODE.Trim()},订单物料编码:{itemCode} ,批次号{list[i].LocCntrRel.CntrItemRel.S_BATCH_NO}是否含有{itemBatch.Substring(6).Trim()},物料编码长度{list[i].LocCntrRel.CntrItemRel.S_BATCH_NO.Length}是否相等{itemBatch.Length},有与上一个货位不同的地方", "成品"); } #endregion } } else { LogHelper.Info($"有托盘的排数为0", "成品"); } } } catch (Exception ex) { //Console.WriteLine("GetLocation4InFinish:" + ex.Message + ex.StackTrace); LogHelper.Info("GetLocation4InSameSrc:" + ex.Message, "成品"); } return result; } /// /// 成品入库移库完成记录信息需要上报给富勒 /// /// /// internal static void AddTaskStatus(WMSTask mst, bool move = false) { try { //无码的不需要写入中间表 if (mst.S_CNTRS.Length != 25) { var db = new SqlHelper().GetInstance(); var model = new InOutRecord { TrayInfo = mst.S_CNTRS }; model.EndArea = mst.S_END_LOC.Substring(0, 1) + mst.S_END_LOC.Split('-')[1]; if (move) { model.IsMove = 1; model.StartArea = mst.S_START_LOC.Substring(0, 1) + mst.S_START_LOC.Split('-')[1]; } else { var cir = db.Queryable().Where(a => a.S_CNTR_CODE == mst.S_CNTRS).Includes(a => a.CntrItemRel).First(); if (cir != null && cir.CntrItemRel != null) { model.WorkOrder = cir.CntrItemRel.workOrder; } else { LogHelper.Info($"写入 InOutRecord 失败 托盘{mst.S_CNTRS}物料信息不存在"); } } var res = db.Insertable(model).ExecuteCommand(); } } catch (Exception ex) { LogHelper.Info($"写入 InOutRecord 失败{ex.Message}"); } } /// /// 查找空排 /// /// /// /// /// /// public static Location GetLocation4InEmptyRow(string area0, string trayType) { Location result = null; try { var db = new SqlHelper().GetInstance(); var area = area0 + "_" + GetType(trayType); Console.WriteLine("成品满托入库 GetLocation4InEmptyRow:" + area); //var usedRows = GetUsedRow(area0, GetType(trayType)); bool flag = false; var usedRows = GetUsedRow(area0, GetType(trayType), ref flag); LogHelper.Info("usedRows信息" + JsonConvert.SerializeObject(usedRows), "成品"); if (flag) { return null; } //todo 还需要判断锁 #region 查找所有数量是空的排 //Console.WriteLine("查找所有数量是空的排"); //2.0 简化查询只查每一排第一列 var list = db.Queryable().Where(a => a.S_AREA_CODE == area).OrderBy(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList().Where(a => a.N_CURRENT_NUM == 0).ToList(); // LogHelper.Info($"库区编码:{area}", "成品"); if (list.Count > 0) { // LogHelper.Info($"list.Count:{list.Count},", "成品"); //2.1 选一个空排 for (int i = 0; i < list.Count; i++) { if (!usedRows.Contains(list[i].N_ROW)) { //LogHelper.Info($"area0:{area0} llist[i].N_ROW:{list[i].N_ROW},GetType(trayType):{GetType(trayType)}", "成品"); //判断其它库区排是否有锁定 if (!CheckLockedRow(area0, GetType(trayType), list[i].N_ROW)) { //LogHelper.Info($"area:{area},N_ROW :{list[i].N_ROW}", "成品"); var other = db.Queryable().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.S_LOCK_STATE.Trim() != "无").First(); //LogHelper.Info($"other:{other},list[i].S_LOCK_STATE.Trim() :{list[i].S_LOCK_STATE.Trim() }", "成品"); if (list[i].S_LOCK_STATE.Trim() == "无" && other == null) { //二次校验当前排所有货位都是空的,防止系统数据错乱 // LogHelper.Info($"i:{i} llist[i].N_ROW:{list[i].N_ROW},area:{area}", "成品"); var rowSumInfo = db.Queryable().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW).Select(a => new { sum = SqlFunc.AggregateSum(a.N_CURRENT_NUM) }).First(); //LogHelper.Info($"rowSumInfo.sum:{rowSumInfo.sum}", "成品"); if (rowSumInfo.sum == 0) { result = list[i]; break; } } } } } } else { LogHelper.Info($"根据库区:{area},找不到空排", "成品"); } #endregion if (result != null && (!string.IsNullOrEmpty(result.C_ENABLE) && result.C_ENABLE == "禁用")) { //禁用了选择后面一个货位 //Console.WriteLine("禁用了选择后面一个货位"); result = db.Queryable().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == result.N_ROW && (string.IsNullOrEmpty(a.C_ENABLE) || a.C_ENABLE != "禁用") && a.N_COL > result.N_COL).First(); LogHelper.Info("货位信息" + JsonConvert.SerializeObject(result), "HosttoagvTask"); } } catch (Exception ex) { //Console.WriteLine("GetLocation4InFinish:" + ex.Message + ex.StackTrace); LogHelper.Error("GetLocation4InEmptyRow:" + ex.Message, ex); } return result; } /// /// 同品相 不同设备的可以入同一排 /// /// /// /// /// /// public static Location GetLocation4InAnySrc(string area0, string itemCode, string itemBatch, string trayType, int maxLayer = 2) { Location result = null; try { var area = area0 + "_" + GetType(trayType); Console.WriteLine("成品满托入库 GetLocation4InAnySrc:" + area); //var usedRows = GetUsedRow(area0, GetType(trayType)); bool flag = false; var usedRows = GetUsedRow(area0, GetType(trayType), ref flag); if (flag) { return null; } //1.0 获取每一排最大的列 //1.1 判断当前数量是不是满的,如果是满的并且是最大列,需要排除 var listMaxCol = new SqlHelper().GetInstance().Queryable().Where(a => a.S_AREA_CODE == area).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList(); //1.1 查到所有有托盘的排 Console.WriteLine("查到所有有托盘的排 "); var db = new SqlHelper().GetInstance(); var list = db.Queryable().Where(a => a.N_CURRENT_NUM > 0 && a.S_AREA_CODE == area).Includes(a => a.LocCntrRel, a => a.CntrItemRel).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList(); if (list.Count > 0) { //1.2 查找其它尺寸有托盘或者锁定的排 for (int i = list.Count - 1; i >= 0; i--) { var remove = false; //排除已经锁定的货位 和 放满了且是最大列的货位 if (list[i].S_LOCK_STATE.Trim() != "无" || (list[i].N_CURRENT_NUM == 4 && listMaxCol.Count(a => a.S_LOC_CODE == list[i].S_LOC_CODE) > 0)) { LogHelper.Info($"排除已经锁定的货位 和 放满了且是最大列的货位 排{list[i].N_ROW}", "成品"); remove = list.Remove(list[i]); } else { //排有锁也排除 var other = db.Queryable().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.S_LOCK_STATE.Trim() != "无").First(); if (other != null) { LogHelper.Info($"排除有锁的排{list[i].N_ROW}", "成品"); remove = list.Remove(list[i]); } } if (!remove) { //判断是否被其它库区占用了 if (usedRows.Contains(list[i].N_ROW)) { remove = list.Remove(list[i]); LogHelper.Info($"被其他库区占用{list[i].N_ROW}", "成品"); } } } Console.WriteLine($"有托盘排数为{list.Count}"); if (list.Count > 0) { //1.3 遍历判断物料类型是否相同 Console.WriteLine("遍历判断物料类型是否相同"); for (int i = 0; i < list.Count; i++) { //todo 还需要判断锁 #region 空托盘或者满托盘判断 ,如果是空托盘 托盘物料信息为空 if (list[i].LocCntrRel != null && list[i].LocCntrRel.CntrItemRel != null) { LogHelper.Info($"货位{list[i].S_LOC_CODE} 物料{list[i].LocCntrRel.CntrItemRel.S_ITEM_CODE} 批次{list[i].LocCntrRel.CntrItemRel.S_BATCH_NO}", "成品"); if (list[i].LocCntrRel.CntrItemRel.S_ITEM_CODE.Trim() == itemCode && list[i].LocCntrRel.CntrItemRel.S_BATCH_NO.Length == itemBatch.Length) { LogHelper.Info($"不同设备生产排;有托盘的货位{list[i].S_LOC_CODE} 当前数量={list[i].N_CURRENT_NUM} 容量={list[i].N_CAPACITY},入库数量={maxLayer}", "成品"); if (list[i].N_CAPACITY - list[i].N_CURRENT_NUM >= maxLayer) { //堆叠,判断批次是不是相同的,不是相同的放到后面 // Console.WriteLine("堆叠,判断批次里面日期是不是相同的,不是相同的放到后面"); //if (list[i].LocCntrRel.CntrItemRel.S_BATCH_NO.Substring(0, itemBatch.Length - 2) == itemBatch.Substring(0, itemBatch.Length - 2)) { //判断是不是单托 result = list[i]; //Console.WriteLine("判断是不是单托"); //if (list[i].LocCntrRel.S_CNTR_CODE.Contains(',')) //{ // result = list[i]; //} //else //{ // //一层是单托,入库放后面一个位置 // Console.WriteLine("一层是单托,入库放后面一个位置"); // result = db.Queryable().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.N_COL > list[i].N_COL).First(); //} //} //else { // //批次不一样空一个位置 // Console.WriteLine("批次不一样空一个位置"); // result = db.Queryable().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.N_COL > (list[i].N_COL + 1)).First(); //} } else { LogHelper.Info($"货位{list[i].S_LOC_CODE}满,选择后面货位", "成品"); //选择后面空位,判断批次是不是相同的,不是相同的放到后面 // LogHelper.Info("选择后面空位,判断批次是不是相同的,不是相同的放到后面", "成品"); if (list[i].LocCntrRel.CntrItemRel.S_BATCH_NO.Substring(0, itemBatch.Length - 2) == itemBatch.Substring(0, itemBatch.Length - 2)) { result = db.Queryable().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.N_COL > list[i].N_COL).OrderBy(a => a.N_COL).First(); LogHelper.Info($"{list[i]}货位满,批次号相同找后一个空货位", "成品"); } else { LogHelper.Info($"{list[i]}货位满,批次号不同,隔一个空位", "成品"); result = db.Queryable().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.N_COL > (list[i].N_COL + 1)).First(); } } if (result != null && result.C_ENABLE != "禁用") { break; } //根据容器编码获取容器信息 var ctrlCode = list[i].LocCntrRel.CntrItemRel.S_CNTR_CODE.Trim(); var ctrl = ContainerHelper.GetCntr(ctrlCode); //托盘类型不一样隔一排 if (ctrl.S_TYPE != trayType) { Console.WriteLine("托盘类型不一样隔一排"); break; } } } #endregion } } } if (result != null && (!string.IsNullOrEmpty(result.C_ENABLE) && result.C_ENABLE == "禁用")) { //禁用了选择后面一个货位 //Console.WriteLine("禁用了选择后面一个货位"); LogHelper.Info($"禁用货位{result.S_LOC_CODE},库区编码{area},排{result.N_ROW},列{result.N_COL}", "成品"); result = db.Queryable().OrderBy(a => a.N_COL).Where(a => (string.IsNullOrEmpty(a.C_ENABLE) || a.C_ENABLE.Trim() != "禁用") && a.S_AREA_CODE == area && a.N_ROW == result.N_ROW && a.N_COL > result.N_COL).First(); // LogHelper.Info($"禁用选择后一个货位{result}", "成品"); } } catch (Exception ex) { //Console.WriteLine("GetLocation4InFinish:" + ex.Message + ex.StackTrace); LogHelper.Error("GetLocation4InFinish:" + ex.Message, ex); } return result; } /// /// 根据物料信息获取入库优先级 /// /// /// /// private static List GetZones(string ItemName) { var list = new List(); var db = new SqlHelper().GetInstance(); var itemZonePris = db.Queryable().Where(a => a.S_ITEM_NAME == ItemName).ToList(); if (itemZonePris.Count > 0) { list = itemZonePris.OrderBy(a => a.S_PRIORITY).Select(a => a.S_AREA_CODE).ToList(); } return list; } /// /// 根据托盘类型获取库区后缀 /// /// /// public static string GetType(string trayType) { var res = ""; switch (trayType) { case "集化板": res = "J"; break; case "大板": res = "D"; break; case "小板": res = "X"; break; case "超托板": res = "C"; break; case "集化板前后超托": res = "JC2"; break; case "大板前后超托": res = "DC"; break; case "小板前后超托": res = "XC"; break; case "集化板四面超托": res = "JC4"; break; } return res; } /// /// 根据库区和排号找托盘类型 /// /// /// /// public static string GetTypebyrow(string kq, int row) { var res = ""; string trayType = ""; var db = new SqlHelper().GetInstance(); //string[] reslist = new string[] { "D", "J", "X", "JC2", "DC", "XC", "JC" }; foreach (var item in areaTypes) { var list = db.Queryable().Where(a => a.S_AREA_CODE == kq + "_" + item && a.N_ROW == row && a.N_CURRENT_NUM > 0).ToList(); if (list.Count > 0) { trayType = item; break; } } switch (trayType) { case "J": res = "集化板"; break; case "D": res = "大板"; break; case "X": res = "小板"; break; case "C": res = "超托板"; break; case "JC2": res = "集化板前后超托"; break; case "DC": res = "大板前后超托"; break; case "XC": res = "小板前后超托"; break; case "JC4": res = "集化板四面超托"; break; } return res; } /// /// 库区后缀 /// private static List areaTypes = new List { "J", "D", "X", "JC2", "DC", "XC", "JC4", "C" }; public static List GetOtherAreas(string baseArea, string size) { var res = new List(); var at = GetType(size); for (int i = 0; i < areaTypes.Count; i++) { if (areaTypes[i] != at) { res.Add(baseArea + "_" + areaTypes[i]); } } return res; } /// /// 获取被占用的排号 /// /// /// /// /// private static List GetUsedRow(string area0, string areaType, ref bool flag) { //如果当前库区是C,有任意库区任意排不是C整区不能入 //如果当前库区不是C,但是有任意排有C整区不能入 bool intercept = false; var db = new SqlHelper().GetInstance(); var res = new List(); areaTypes.Where(b => b != areaType).ToList().ForEach(b => { //判断库区排有没有被占用 var area = area0 + "_" + b; //有托盘的其他库区的排要排除 var list = db.Queryable().Where(a => a.N_CURRENT_NUM > 0 && a.S_AREA_CODE == area).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList(); if (list.Count > 0) { res.AddRange(list.Select(c => c.N_ROW).ToList()); //if (areaType == "C") //{ // Console.WriteLine($"当前库区是{areaType},JDX库区有托盘,不可用"); // intercept = true; //} //else //{ // if (b == "C") // { // Console.WriteLine($"当前库区是{areaType},C库区有托盘,不可用"); // intercept = true; // } //} } //有锁的其他库区的排要排除 var listsuo = db.Queryable().Where(a => a.S_LOCK_STATE != "无" && a.S_AREA_CODE == area).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList(); if (listsuo.Count > 0) { res.AddRange(listsuo.Select(c => c.N_ROW).ToList()); } }); flag = intercept; //有移库任务的排也需要排除 var list1 = db.Queryable().Where(a => (a.SQL_State == "执行中" || a.SQL_State == "暂停") && a.start_area == area0).ToList(); if (list1.Count > 0) { list1.ForEach(a => { LogHelper.Info($"移库任务{a.SQL_WorkNo}:起点排{a.start_row}有移库任务", "成品"); res.Add(a.start_row); // res.Add(a.end_row); }); } var list2 = db.Queryable().Where(a => (a.SQL_State == "执行中" || a.SQL_State == "暂停") && a.end_area == area0).ToList(); if (list2.Count > 0) { list2.ForEach(a => { LogHelper.Info($"移库任务{a.SQL_WorkNo}:终点排{a.end_row}有移库任务", "成品"); // res.Add(a.start_row); res.Add(a.end_row); }); } return res; } private static bool CheckLockedRow(string area0, string areaType, int row) { var res = false; areaTypes.Where(b => b != areaType).ToList().ForEach(b => { //判断库区排有没有被占用 var area = area0 + "_" + b; var db = new SqlHelper().GetInstance(); var other = db.Queryable().Where(a => a.S_AREA_CODE == area && a.N_ROW == row && a.S_LOCK_STATE.Trim() != "无").First(); if (other != null) { res = true; } }); return res; } internal static void CpAuto() { FinishedMoveAuto(); //EmptyAuto(); } internal static void EmptyAuto() { //空框区zoneType=3 自动转运入库 var startZone = Settings.cpZones.Where(a => a.zoneType == 3).FirstOrDefault(); var db = new SqlHelper().GetInstance(); var otherTaskCount = db.Queryable().Count(a => a.S_TYPE == "空托转运入库" && a.S_B_STATE != "完成" && a.S_B_STATE != "取消"); if (otherTaskCount == 0 && startZone != null) { var listSize = new List { "大板", "小板", "集化板" }; listSize.ForEach(s => { var list1 = db.Queryable().OrderByDescending(a => a.priority).Where(a => a.cntrType == s).ToList(); if (list1.Count > 0) { list1.ForEach(a => { var start = LocationHelper.GetLocation4OutEmptyNotStack(startZone.zone[0], a.startRow, s); if (start != null) { Console.WriteLine("准备创建 自动转运入库"); //创建入库搬运任务 var cntrList = LocationHelper.GetLocCntr(start.S_LOC_CODE); if (cntrList.Count > 0) { Console.WriteLine($"托盘类型 {cntrList[0].Container.S_TYPE}"); Location end = null; //查找空托入库库区 List list = list1.Where(b => b.startRow == a.startRow).ToList(); if (list.Count > 0) { Console.WriteLine("查找空托盘排"); for (int i = 0; i < list.Count; i++) { end = GetLocation4EmptyCntrIn(list[i].endArea, list[i].endRow, cntrList[0].Container.S_TYPE); if (end != null) { break; } } //if (end == null) { // Console.WriteLine("查找空排"); // for (int i = 0; i < list.Count; i++) { // Console.WriteLine("库区" + list[i]); // end = GetLocation4InEmptyRow(list[i].endArea, cntrList[0].Container.S_TYPE); // if (end != null) { // break; // } // } //} } if (end != null) { TaskProcess.CreateTransport(start.S_LOC_CODE, end.S_LOC_CODE, "空托转运入库", new List { cntrList[0].S_CNTR_CODE.Trim() }, 1, end.N_CURRENT_NUM + 1, 1, 80); } } else { Console.WriteLine($"{start.S_LOC_CODE}未找到托盘"); } } else { Console.WriteLine("空托转运入库 起点没找到托盘"); } }); } }); } } private static List GetCPEmptyArea(string cntrType) { var db = new SqlHelper().GetInstance(); var list = db.Queryable().OrderByDescending(a => a.priority).Where(a => a.cntrType == cntrType).ToList(); return list; } private static List GetCPEmptyArea(string cntrType, int startRow) { var db = new SqlHelper().GetInstance(); var list = db.Queryable().OrderByDescending(a => a.priority).Where(a => a.cntrType == cntrType && a.startRow == startRow).ToList(); return list; } public static Location GetLocation4EmptyCntrIn(string area0, string trayType) { Location result = null; //string itemBatch = DateTime.Now.ToString("yyMMdd"); try { var area = area0 + "_" + GetType(trayType); Console.WriteLine("成品空托入库 GetLocation4EmptyCntrIn:" + area); bool flag = false; var usedRows = GetUsedRow(area0, GetType(trayType), ref flag); if (flag) { Console.WriteLine("当前库区不可用,被其它尺寸托盘占用,直接返回"); return null; } //1.0 获取每一排最大的列 //1.1 判断当前数量是不是满的,如果是满的并且是最大列,需要排除 var listMaxCol = new SqlHelper().GetInstance().Queryable().Where(a => a.S_AREA_CODE == area).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList(); //1.1 查到所有有托盘的排 var db = new SqlHelper().GetInstance(); var list = db.Queryable().Where(a => a.N_CURRENT_NUM > 0 && a.S_AREA_CODE == area).Includes(a => a.LocCntrRel, a => a.CntrItemRel).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList(); Console.WriteLine($"查到所有有托盘的排 {list.Count}"); if (list.Count > 0) { //1.2 查找其它尺寸有托盘或者锁定的排 for (int i = list.Count - 1; i >= 0; i--) { var remove = false; //排除已经锁定的货位 和 放满了且是最大列的货位 if (list[i].S_LOCK_STATE.Trim() != "无" || (list[i].N_CURRENT_NUM == list[i].N_CAPACITY && listMaxCol.Count(a => a.S_LOC_CODE == list[i].S_LOC_CODE) > 0)) { Console.WriteLine($"排除已经锁定的货位 和 放满了且是最大列的货位 排{list[i].N_ROW}"); remove = list.Remove(list[i]); } else { //排有锁也排除 var other = db.Queryable().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.S_LOCK_STATE.Trim() != "无").First(); if (other != null) { Console.WriteLine($"排除有锁的排{list[i].N_ROW}"); remove = list.Remove(list[i]); } } if (!remove) { //判断是否被其它库区占用了 Console.WriteLine("判断是否被其它库区占用了"); if (usedRows.Contains(list[i].N_ROW)) { remove = list.Remove(list[i]); } } } Console.WriteLine($"有托盘排数为{list.Count}"); if (list.Count > 0) { //1.3 遍历判断物料类型是否相同 Console.WriteLine("遍历判断是不是空托盘"); for (int i = 0; i < list.Count; i++) { //todo 还需要判断锁 #region 满托盘判断 物料信息相同,并且批次里面的设备相同 if (list[i].LocCntrRel != null && list[i].LocCntrRel.CntrItemRel == null) { Console.WriteLine($"有托盘的货位{list[i].S_LOC_CODE} 当前数量={list[i].N_CURRENT_NUM} 容量={list[i].N_CAPACITY}"); if (list[i].N_CURRENT_NUM < list[i].N_CAPACITY) { result = list[i]; } else { //选择后面空位 result = db.Queryable().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.N_COL > list[i].N_COL).OrderBy(a => a.N_COL).First(); } if (result != null && result.C_ENABLE != "禁用") { break; } } #endregion } } } if (result != null && (!string.IsNullOrEmpty(result.C_ENABLE) && result.C_ENABLE == "禁用")) { //禁用了选择后面一个货位 //Console.WriteLine("禁用了选择后面一个货位"); result = db.Queryable().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == result.N_ROW && (string.IsNullOrEmpty(a.C_ENABLE) || a.C_ENABLE != "禁用") && a.N_COL > result.N_COL).First(); } } catch (Exception ex) { //Console.WriteLine("GetLocation4InFinish:" + ex.Message + ex.StackTrace); LogHelper.Error("GetLocation4EmptyCntrIn:" + ex.Message, ex); } return result; } public static Location GetLocation4EmptyCntrIn(string area0, int row, string trayType) { Location result = null; //string itemBatch = DateTime.Now.ToString("yyMMdd"); try { var area = area0 + "_" + GetType(trayType); Console.WriteLine($"成品空托入库 GetLocation4EmptyCntrIn:{area} - {row}"); bool flag = false; var usedRows = GetUsedRow(area0, GetType(trayType), ref flag); if (flag) { Console.WriteLine("当前库区不可用,被其它尺寸托盘占用,直接返回"); return null; } if (!usedRows.Contains(row)) { // var db = new SqlHelper().GetInstance(); var list = db.Queryable().Where(a => a.N_CURRENT_NUM > 0 && a.N_ROW == row && a.S_AREA_CODE == area).Includes(a => a.LocCntrRel, a => a.CntrItemRel).OrderByDescending(a => a.N_COL).ToList(); if (list.Count(a => a.S_LOCK_STATE != "无") == 0) { //没有锁 if (list.Count > 0) { var last = list.OrderByDescending(a => a.N_COL).FirstOrDefault(); if (last.LocCntrRel != null && last.LocCntrRel.CntrItemRel == null) { //是空托盘 if (last.N_CURRENT_NUM == 1) { result = last; } else { result = db.Queryable().Where(a => a.N_ROW == row && a.S_AREA_CODE == area && a.N_COL > last.N_COL).OrderBy(a => a.N_COL).First(); } } } else { //当前排没有托盘是空排,判断有没有被其它库区锁定 if (!CheckLockedRow(area0, GetType(trayType), row)) { //没有锁住入最小位置 result = db.Queryable().Where(a => a.N_ROW == row && a.S_AREA_CODE == area).OrderBy(a => a.N_COL).First(); } } if (result != null && (!string.IsNullOrEmpty(result.C_ENABLE) && result.C_ENABLE == "禁用")) { //禁用了选择后面一个货位 //Console.WriteLine("禁用了选择后面一个货位"); result = db.Queryable().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == result.N_ROW && (string.IsNullOrEmpty(a.C_ENABLE) || a.C_ENABLE != "禁用") && a.N_COL > result.N_COL).First(); } } } } catch (Exception ex) { //Console.WriteLine("GetLocation4InFinish:" + ex.Message + ex.StackTrace); LogHelper.Error("GetLocation4EmptyCntrIn:" + ex.Message, ex); } return result; } private static bool CheckStartRow(string baseArea, int row, string size) { //判断起点库区排有托盘 bool res = false; var area = baseArea + "_" + GetType(size); var db = new SqlHelper().GetInstance(); res = db.Queryable().Count(l => l.S_AREA_CODE == area && l.N_ROW == row && l.N_CURRENT_NUM > 0) > 0; return res; } private static bool CheckEndRow(string baseArea, int row, string size) { //判断终点库区排有相同托盘,或者没有其他托盘 bool res = false; var area = baseArea + "_" + GetType(size); var db = new SqlHelper().GetInstance(); res = db.Queryable().Count(l => l.S_AREA_CODE == area && l.N_ROW == row && l.N_CURRENT_NUM > 0) > 0; if (!res) { //终点排没有托盘,判断是否有其他尺寸的托盘 LogHelper.Info($"移库任务:终点排没有托盘,判断是否有其他尺寸的托盘"); var list = GetOtherAreas(baseArea, size); var res1 = true; for (int i = 0; i < list.Count; i++) { res1 = db.Queryable().Count(l => l.S_AREA_CODE == list[i] && l.N_ROW == row && l.N_CURRENT_NUM > 0) == 0; if (!res1) { LogHelper.Info($"移库任务:库区{list[i]},排{row},存在托盘"); break; } } res = res1; } return res; } /// /// 移库 /// internal static void FinishedMoveAuto() { try { var db = new SqlHelper().GetInstance(); //检查 var listUnlock = db.Queryable().Where(a => a.SQL_State == "已完成" && a.IsUnlock != "1").ToList(); if (listUnlock.Count > 0) { listUnlock.ForEach(a => { //根据起点排,起点库区查询托盘类型 string tptype = GetTypebyrow(a.start_area, a.start_row); var startArea = a.start_area + "_" + GetType(tptype); var endArea = a.end_area + "_" + GetType(tptype); AddMoveOrderNotice(a.SQL_WorkNo, startArea, a.start_row, endArea, a.end_row); if (a.IsUnlock != "1") { //手动移库货位解锁上报 YiKuUnLockRow(a.start_area + "-" + a.start_row.ToString() + "," + a.end_area + "-" + a.end_row.ToString(), a.SQL_WorkNo, false, startArea, endArea, a.start_row, a.end_row); } a.IsUnlock = "1"; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.IsUnlock, it.T_MODIFY }).ExecuteCommand(); }); } var list = db.Queryable().Where(a => a.SQL_State == "执行中").ToList(); if (list.Count > 0) { //判断是否有其它任务相同起点排或者相同终点排,如果有优先级更高,当前工单不做 //Console.WriteLine("成品移库,判断是否有其它任务相同起点排或者相同终点排,如果有优先级更高,当前工单不做"); list.ForEach(a => { //根据起点排,起点库区查询托盘类型 string tptype = GetTypebyrow(a.start_area, a.start_row); //var other = list.OrderByDescending(b => b.priority).Where(b => b.S_ID != a.S_ID && ((b.start_area == a.start_area && b.start_row == a.start_row) || (b.end_area == a.end_area && b.end_row == a.end_row))).FirstOrDefault(); //if (other == null || (a.priority > other.priority || (a.priority == other.priority && a.T_CREATE < other.T_CREATE))) { //准备移库 var startArea = a.start_area + "_" + GetType(tptype); var endArea = a.end_area + "_" + GetType(tptype); AddMoveOrderNotice(a.SQL_WorkNo, startArea, a.start_row, endArea, a.end_row, false); //判断是否有执行中的任务 if (IsTask(a.SQL_WorkNo)) { //判断起点排是否有正确托盘、终点排有托盘,如果没托盘是否有其他尺寸托 if (!CheckStartRow(a.start_area, a.start_row, tptype)) { a.note = $"起点库区、排没有找到{tptype}托盘"; a.SQL_State = "已完成"; a.IsUnlock = "1"; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.SQL_State, it.note, it.IsUnlock, it.T_MODIFY }).ExecuteCommand(); AddMoveOrderNotice(a.SQL_WorkNo, startArea, a.start_row, endArea, a.end_row); //货位解锁上报 LogHelper.Info($"移库任务:{a.SQL_WorkNo}=> 起点库区、排没有找到{tptype}托盘,任务改成完成"); YiKuUnLockRow(a.start_area + "-" + a.start_row.ToString() + "," + a.end_area + "-" + a.end_row.ToString(), a.SQL_WorkNo, false, startArea, endArea, a.start_row, a.end_row); return; } } if (!CheckEndRow(a.end_area, a.end_row, tptype)) { a.note = $"终点库区、排有其他尺寸托盘"; a.SQL_State = "已完成"; a.IsUnlock = "1"; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.SQL_State, it.note, it.IsUnlock, it.T_MODIFY }).ExecuteCommand(); AddMoveOrderNotice(a.SQL_WorkNo, startArea, a.start_row, endArea, a.end_row); //货位解锁上报 LogHelper.Info($"移库任务:{a.SQL_WorkNo}=> 终点库区、排有其他尺寸托盘,任务改成完成"); YiKuUnLockRow(a.start_area + "-" + a.start_row.ToString() + "," + a.end_area + "-" + a.end_row.ToString(), a.SQL_WorkNo, false, startArea, endArea, a.start_row, a.end_row); return; } //起点排的货位全部查询 Console.WriteLine("准备移库"); if (a.current >= a.number) { a.note = $"已经完成入库数量"; a.SQL_State = "已完成"; a.IsUnlock = "1"; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.SQL_State, it.note, it.IsUnlock, it.T_MODIFY }).ExecuteCommand(); AddMoveOrderNotice(a.SQL_WorkNo, startArea, a.start_row, endArea, a.end_row); //货位解锁上报 LogHelper.Info($"移库任务:{a.SQL_WorkNo}=> 已经完成入库数量,任务改成完成"); YiKuUnLockRow(a.start_area + "-" + a.start_row.ToString() + "," + a.end_area + "-" + a.end_row.ToString(), a.SQL_WorkNo, false, startArea, endArea, a.start_row, a.end_row); return; } var listStarts = new SqlHelper().GetList(b => b.S_AREA_CODE.Trim() == startArea && b.N_ROW == a.start_row); if (listStarts.Count > 0 && listStarts.Count(b => b.S_LOCK_STATE.Trim() != "无") == 0) { //列从大到小找一个满托 //Console.WriteLine("列从大到小找一个满托"); var start = listStarts.OrderByDescending(l => l.N_COL).Where(l => l.N_CURRENT_NUM > 0).FirstOrDefault(); if (start != null) { var cntrList = LocationHelper.GetLocCntr(start.S_LOC_CODE); var cntr = cntrList.OrderByDescending(c => c.T_CREATE).Take(2).ToList(); var cirStart = ContainerHelper.GetCntrItemRel(cntr[0].S_CNTR_CODE); // string tp = cntr.ToString(); string tp = string.Join(",", cntr.Select(t => t.S_CNTR_CODE).ToArray()); //查找终点 //Console.WriteLine("查找终点"); var listEnds = new SqlHelper().GetList(b => b.S_AREA_CODE.Trim() == endArea && b.N_ROW == a.end_row);// && b.C_ENABLE != "禁用" if (listEnds.Count > 0 && listStarts.Count(b => b.S_LOCK_STATE.Trim() != "无") == 0 && listEnds.Count(b => b.S_LOCK_STATE.Trim() != "无") == 0) { //从大到小找个满的,然后选择后面一个空位 //Console.WriteLine("从大到小找个满的"); var full = listEnds.OrderByDescending(l => l.N_COL).Where(l => l.N_CURRENT_NUM > 0).FirstOrDefault(); if (full == null) { var end = listEnds.Where(loc => loc.C_ENABLE != "禁用").OrderBy(loc => loc.N_COL).FirstOrDefault(); int cg = 0; //计算层高 if (end.N_CURRENT_NUM == 0) { cg = 1; } else if (end.N_CURRENT_NUM == 2) { cg = 2; } else if (end.N_CURRENT_NUM == 4) { cg = 3; } //创建任务 //Console.WriteLine("没有满托,选一个最小的空位"); TaskProcess.CreateTransport(start.S_LOC_CODE, end.S_LOC_CODE, "成品移库", new List { tp.Trim() }, cntrList.Count / 2, cg, 1, 1, a.SQL_WorkNo); a.current++; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.current, it.T_MODIFY }).ExecuteCommand(); //货位锁定上报 YiKuUnLockRow(a.start_area + "-" + a.start_row.ToString() + "," + a.end_area + "-" + a.end_row.ToString(), a.SQL_WorkNo, true, startArea, endArea, a.start_row, a.end_row); } else { var cntrFull = LocationHelper.GetLocCntr(full.S_LOC_CODE); var cirEnd = ContainerHelper.GetCntrItemRel(cntrFull[0].S_CNTR_CODE); if (cirStart[0].S_ITEM_CODE.Trim() != cirEnd[0].S_ITEM_CODE.Trim()) { //物料信息不一样,直接结束工单 //Console.WriteLine("物料信息不一样,直接结束工单"); a.note = "物料信息不一样,工单结束"; a.SQL_State = "已完成"; a.IsUnlock = "1"; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.SQL_State, it.note, it.IsUnlock, it.T_MODIFY }).ExecuteCommand(); AddMoveOrderNotice(a.SQL_WorkNo, startArea, a.start_row, endArea, a.end_row); LogHelper.Info($"移库任务:{a.SQL_WorkNo}=> 物料信息不一样,工单结束,任务改成完成"); //货位解锁上报 YiKuUnLockRow(a.start_area + "-" + a.start_row.ToString() + "," + a.end_area + "-" + a.end_row.ToString(), a.SQL_WorkNo, false, startArea, endArea, a.start_row, a.end_row); } else { //判断批次是不是一样 //if (cirStart[0].S_BATCH_NO.Substring(0, 6) == cirEnd[0].S_BATCH_NO.Substring(0, 6)) { //Console.WriteLine("批次一样"); //判断满托位有几个托盘,如果是4个托盘,直接找后一位 if (cntrFull.Count == 4) { //Console.WriteLine("货位满了,选择后一个货位"); var after = listEnds.OrderBy(loc => loc.N_COL).Where(loc => loc.N_COL > full.N_COL && loc.C_ENABLE != "禁用").FirstOrDefault(); //创建任务 if (after != null) { int cg = 0; //计算层高 if (after.N_CURRENT_NUM == 0) { cg = 1; } else if (after.N_CURRENT_NUM == 2) { cg = 2; } else if (after.N_CURRENT_NUM == 4) { cg = 3; } TaskProcess.CreateTransport(start.S_LOC_CODE, after.S_LOC_CODE, "成品移库", new List { tp.Trim() }, cntrList.Count / 2, cg, 1, 1, a.SQL_WorkNo); a.current++; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.current, it.T_MODIFY }).ExecuteCommand(); //货位锁定上报 YiKuUnLockRow(a.start_area + "-" + a.start_row.ToString() + "," + a.end_area + "-" + a.end_row.ToString(), a.SQL_WorkNo, true, startArea, endArea, a.start_row, a.end_row); } } else { //如果是1个托盘,要判断是单托还是双托 //Console.WriteLine("如果是1个托盘,要判断是单托还是双托"); //if (cntrFull[0].S_CNTR_CODE.Contains(',')) // { //创建任务 //Console.WriteLine("双托,可以卸货"); int cg = 0; //计算层高 if (full.N_CURRENT_NUM == 0) { cg = 1; } else if (full.N_CURRENT_NUM == 2) { cg = 2; } else if (full.N_CURRENT_NUM == 4) { cg = 3; } TaskProcess.CreateTransport(start.S_LOC_CODE, full.S_LOC_CODE, "成品移库", new List { tp.Trim() }, cntrList.Count / 2, cg, 1, 1, a.SQL_WorkNo); a.current++; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.current, it.T_MODIFY }).ExecuteCommand(); //货位锁定上报 YiKuUnLockRow(a.start_area + "-" + a.start_row.ToString() + "," + a.end_area + "-" + a.end_row.ToString(), a.SQL_WorkNo, true, startArea, endArea, a.start_row, a.end_row); // } //else //{ // //单托不可以卸货 // //Console.WriteLine("单托不可以卸货,选择后一个货位"); // var after = listEnds.OrderBy(loc => loc.N_COL).Where(loc => loc.N_COL > full.N_COL && loc.C_ENABLE != "禁用").FirstOrDefault(); // //创建任务 // if (after != null) // { // TaskProcess.CreateTransport(start.S_LOC_CODE, after.S_LOC_CODE, "成品移库", new List { cntr.S_CNTR_CODE.Trim() }, cntrList.Count, 1); // a.current++; // a.T_MODIFY = DateTime.Now; // db.Updateable(a).UpdateColumns(it => new { it.current, it.T_MODIFY }).ExecuteCommand(); // } // else // { // //终点排满了,自动结束 // //Console.WriteLine("终点满了或不可入,工单结束"); // a.note = "终点满了或不可入,工单结束"; // a.SQL_State = "已完成"; // a.IsUnlock = "1"; // a.T_MODIFY = DateTime.Now; // db.Updateable(a).UpdateColumns(it => new { it.SQL_State, it.note, it.IsUnlock, it.T_MODIFY }).ExecuteCommand(); // AddMoveOrderNotice(a.SQL_WorkNo, startArea, a.start_row, endArea, a.end_row); // } //} } //} //else { // //批次不一样,空一格 // //Console.WriteLine("批次不一样,空一格"); // var after = listEnds.OrderBy(loc => loc.N_COL).Where(loc => loc.N_COL > (full.N_COL + 1) && loc.C_ENABLE != "禁用").FirstOrDefault(); // if (after != null) { // TaskProcess.CreateTransport(start.S_LOC_CODE, after.S_LOC_CODE, "成品移库", new List { cntr.S_CNTR_CODE.Trim() }, cntrList.Count, 1); // } // else { // //终点排满了,自动结束 // //Console.WriteLine("终点满了或不可入,工单结束"); // a.note = "终点满了或不可入,工单结束"; // a.SQL_State = "已完成"; // a.IsUnlock = "1"; // db.Updateable(a).UpdateColumns(it => new { it.SQL_State, it.note, it.IsUnlock }).ExecuteCommand(); // AddMoveOrderNotice(a.SQL_WorkNo, startArea, a.start_row, endArea, a.end_row); // } //} } } } } else { if (IsTask(a.SQL_WorkNo)) { //起点排没有托盘了,更新工单状态为完成 a.note = "起点没托盘,工单结束"; a.SQL_State = "已完成"; a.IsUnlock = "1"; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.SQL_State, it.note, it.IsUnlock, it.T_MODIFY }).ExecuteCommand(); AddMoveOrderNotice(a.SQL_WorkNo, startArea, a.start_row, endArea, a.end_row); //货位解锁上报 LogHelper.Info($"移库任务:{a.SQL_WorkNo}=> 起点没托盘,工单结束,任务改成完成"); YiKuUnLockRow(a.start_area + "-" + a.start_row.ToString() + "," + a.end_area + "-" + a.end_row.ToString(), a.SQL_WorkNo, false, startArea, endArea, a.start_row, a.end_row); } } } }); } } catch (Exception ex) { //Console.WriteLine("FinishedMoveAuto:" + ex.Message); LogHelper.Error("FinishedMoveAuto:" + ex.Message, ex); } } private static void AddMoveOrderNotice(string moveOrder, string start_area, int start_row, string end_area, int end_row, bool complete = true) { var db = new SqlHelper().GetInstance(); var start = db.Queryable().Where(a => a.S_AREA_CODE == start_area && a.N_ROW == start_row).First(); var end = db.Queryable().Where(a => a.S_AREA_CODE == end_area && a.N_ROW == end_row).First(); if (start != null && end != null) { var startArea = start.S_LOC_CODE.Substring(0, 1) + start.N_ROW; var endArea = end.S_LOC_CODE.Substring(0, 1) + end.N_ROW; var old = db.Queryable().Where(a => a.OrderNo == moveOrder).First(); if (!complete) { if (old == null) { old = new MoveOrderNotice { OrderNo = moveOrder }; old.StartArea = startArea; old.EndArea = endArea; db.Insertable(old).ExecuteCommand(); } } else { if (old != null) { old.State = 1; old.IsNotice = 0; db.Updateable(old).UpdateColumns(it => new { it.State, it.IsNotice }).ExecuteCommand(); } } } } internal static Location GetLocation4EmptyCntrOut(string size) { Location start = null; var db = new SqlHelper().GetInstance(); var list = db.Queryable().ToList(); if (list.Count > 0) { for (int i = 0; i < list.Count; i++) { start = GetLocation4EmptyOut(list[i].area, list[i].row, size); if (start != null) { break; } } } return start; } public static Location GetLocation4EmptyOut(string area0, string trayType) { Location result = null; try { var area = area0 + "_" + GetType(trayType); Console.WriteLine("成品空托出库 GetLocation4EmptyOut:" + area); //var usedRows = GetUsedRow(area0, GetType(trayType)); bool flag = false; var usedRows = GetUsedRow(area0, GetType(trayType), ref flag); if (flag) { return null; } //1.0 获取每一排最大的列 //1.1 判断当前数量是不是满的,如果是满的并且是最大列,需要排除 var listMaxCol = new SqlHelper().GetInstance().Queryable().Where(a => a.S_AREA_CODE == area).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList(); //1.1 查到所有有托盘的排 Console.WriteLine("查到所有有托盘的排 "); var db = new SqlHelper().GetInstance(); var list = db.Queryable().Where(a => a.N_CURRENT_NUM > 0 && a.S_AREA_CODE == area).Includes(a => a.LocCntrRel, a => a.CntrItemRel).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList(); if (list.Count > 0) { //1.2 查找其它尺寸有托盘或者锁定的排 for (int i = list.Count - 1; i >= 0; i--) { var remove = false; //排除已经锁定的货位 if (list[i].S_LOCK_STATE.Trim() != "无") { remove = list.Remove(list[i]); } else { //排有锁也排除 var other = db.Queryable().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.S_LOCK_STATE.Trim() != "无").First(); if (other != null) { //Console.WriteLine($"排除有锁的排{list[i].N_ROW}"); remove = list.Remove(list[i]); } } if (!remove) { //判断是否被其它库区占用了 if (usedRows.Contains(list[i].N_ROW)) { remove = list.Remove(list[i]); } } } Console.WriteLine($"有托盘排数为{list.Count}"); if (list.Count > 0) { //1.3 遍历判断物料类型是否相同 Console.WriteLine("遍历判断是否为空托盘"); for (int i = 0; i < list.Count; i++) { if (list[i].LocCntrRel != null && list[i].LocCntrRel.CntrItemRel == null) { result = list[i]; if (result != null) { break; } } } } } } catch (Exception ex) { LogHelper.Error("GetLocation4EmptyOut:" + ex.Message, ex); } return result; } public static Location GetLocation4EmptyOut(string area0, int row, string trayType) { Location result = null; try { var area = area0 + "_" + GetType(trayType); Console.WriteLine($"成品空托出库 GetLocation4EmptyOut: {area} - {row}"); var list = new SqlHelper().GetInstance().Queryable().Where(a => a.S_AREA_CODE == area && a.N_ROW == row && a.N_CURRENT_NUM > 0).Includes(a => a.LocCntrRel, a => a.CntrItemRel).ToList(); if (list.Count > 0 && list.Count(a => a.S_LOCK_STATE != "无") == 0) { //当前排没有锁 //判断托盘类型是否一致 var start = list.OrderByDescending(a => a.N_COL).FirstOrDefault(); if (start.LocCntrRel != null && start.LocCntrRel.CntrItemRel == null) { result = start; } } } catch (Exception ex) { LogHelper.Error("GetLocation4EmptyOut:" + ex.Message, ex); } return result; } /// /// 移库 上报锁定或解锁库位(排) /// /// public static void YiKuUnLockRow(string row, string worno, bool state, string startarea, string endarea, int startrow, int endrow) { // var db = new SqlHelper().GetInstance(); //检查 //var Startloc = db.Queryable().Where(a => a.S_AREA_CODE == startarea && a.N_ROW == startrow).ToList(); //var Endloc = db.Queryable().Where(a => a.S_AREA_CODE == endarea && a.N_ROW == endrow).ToList(); // 第一次生成任务上报锁定货位 // 接触货位判断是不是生成过货位 // 排锁上报格式:库区加排号 如:(C04-1) if (state) { //判断是否第一条任务,第一条任务上报锁定排 var task = TaskHelper.GetTaskBySrcNo(worno); if (task.Count == 1) { //移库锁定货位上报 TaskProcess.AreaRowLockState(row, state); #region 排锁 弃用 //移库起点终点排添加移库锁 //Startloc.ForEach(a => //{ // LocationHelper.LockLoc(a.S_LOC_CODE, "移库锁"); //}); //Endloc.ForEach(a => //{ // LocationHelper.LockLoc(a.S_LOC_CODE, "移库锁"); //}); #endregion } } else { //判断是否创建任务,创建任务上传解锁排 var task = TaskHelper.GetTaskBySrcNo(worno); if (task.Count >= 1) { //移库解锁定货位上报 TaskProcess.AreaRowLockState(row, state); #region 排锁 弃用 //移库起点终点排解锁 //Startloc.ForEach(a => //{ // LocationHelper.LockLoc(a.S_LOC_CODE, "无"); //}); //Endloc.ForEach(a => //{ // LocationHelper.LockLoc(a.S_LOC_CODE, "无"); //}); #endregion } } } /// /// 根据移库单号判断移库任务是否全部完成 /// /// /// public static bool IsTask(string worno) { bool res = true; var db = new SqlHelper().GetInstance(); //判断是否有未完成的任务 var task = TaskHelper.GetTaskBySrcNo(worno); List taskbystate = task.FindAll(a => a.S_B_STATE != "完成").ToList(); taskbystate = taskbystate.FindAll(a => a.S_B_STATE != "强制完成").ToList(); if (taskbystate.Count > 0) { res = false; } return res; } } }