using HH.WCS.Hexafluo; using HH.WCS.Hexafluo.util; using HH.WCS.Hexafluo.wms; using HH.WCS.SJML.Comm; using HH.WCS.SJML.dispatch; using HH.WCS.SJML.Entitys; using HH.WCS.ZCQTJ.Entitys; using Newtonsoft.Json; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; namespace HH.WCS.SJML.Bll { public class Out_AlgorBLL { #region 作业区出库算法入口 public OutAssignResultEntity OutAssign(OutAssignEnitty model) { LogHelper.Info("出库算法", "出库算法参数:" + JsonConvert.SerializeObject(model)); OutAssignResultEntity outResult = new OutAssignResultEntity(); outResult.errCode = ""; try { //标准出库算法 string areaType = SqlSugarHelper.Db.Queryable().Where(e => e.S_AREA_CODE == model.lstAreaPrior[0].areaCode).First()?.S_NOTE; if (areaType == Constants.Area_Struc_PingStock || areaType == Constants.Area_Struc_LiStock) { outResult = FlatAreaOutLocation(model); } else { throw new Exception("出库的库区类型 即不是平库也不是立库"); } outResult.areaType = areaType; LogHelper.Info("出库算法", "出库返回结果:" + JsonConvert.SerializeObject(outResult)); return outResult; } catch (Exception ex) { LogHelper.Info("出库算法", "异常:" + ex.Message); outResult.Msg = "算法异常," + ex.Message; outResult.errCode = "5"; return outResult; } } #endregion #region 平库-立库出库算法 public OutAssignResultEntity FlatAreaOutLocation(OutAssignEnitty model) { OutAssignResultEntity outResult = new OutAssignResultEntity(); #region 传入参数判断 if (model == null) { outResult.Success = false; outResult.errCode = "6"; outResult.Msg = "参数实体不能为 null !"; return outResult; } //判断指定的入作业库对象类型不能为空 if (string.IsNullOrEmpty(model.stockCode)) { outResult.Success = false; outResult.errCode = "6"; outResult.Msg = "指定的出库仓库编号不能为空!"; return outResult; } //判断传入库区列表不能为空 if (model.lstAreaPrior == null || model.lstAreaPrior.Count == 0) { outResult.Success = false; outResult.errCode = "6"; outResult.Msg = "指定的出作业库库区列表不能为空!"; return outResult; } #endregion outResult = OutAreaPrior(model); return outResult; } #endregion /// /// 作业区出库算法 优先库区 /// /// /// private OutAssignResultEntity OutAreaPrior(OutAssignEnitty model) { //返回实体集合 OutAssignResultEntity outResult = new OutAssignResultEntity(); outResult.Success = false; outResult.errCode = "101"; if (string.IsNullOrEmpty(model.itemCode)) { outResult.Msg = "库区中无空托"; } else { outResult.Msg = "库存不足"; } var chi = new SqlHelper().GetInstance(); var newDb = chi.CopyNew(); List lstStrategy = null; List lstCanOutL = null; string deviceCode = string.Empty; List lstStrate = null; Location at_l_Entity = null; List lstTmp_Location = new List(); List lstTrueLocation = new List(); List lstAllLocation = new List(); List locationInLock = new List(); List locationOutLock = new List(); //被锁定的货位 List lstLockLItem = new List(); List lstLocation = new List(); WcsReturnEntityTwo WcsRet = new WcsReturnEntityTwo(); string isControlQty = string.Empty; string isControlInv = string.Empty; //将传递过来的库区列表按库区出库优先级排序 List lstAreaPrior = model.lstAreaPrior.OrderByDescending(o => o.Prior).ToList(); foreach (areaPriorClass item in lstAreaPrior) { //这里判断库区是否可用 并且哪些巷道可用 且必须库区类型是立库 TN_AreaEntitys areaModel = newDb.Queryable().Where(e => e.S_AREA_CODE == item.areaCode).First(); isControlQty = areaModel.S_CONTROL_QTY; if (model.needCalLock) { model.lockLocation = isControlQty.Equals("Y") ? true : false;//不管控数量时,不锁定目的货位 } var Texp = Expressionable.Create(); //Texp.AndIF(string.IsNullOrEmpty(model.logicAreaCode), it => it.S_ZONAL_CODE == model.logicAreaCode); Texp.And(it => it.S_AREA_CODE == item.areaCode); Texp.And(it => it.S_STRATEGY_TYPE == "出库"); Texp.And(it => it.S_START_USING == "Y"); lstStrategy = newDb.Queryable().Where(Texp.ToExpression()).ToList(); lstStrate = lstStrategy.Select(o => o.S_STRATEGY_CODE).ToList(); //这里判断库区是否可用 并且哪些巷道可用 且必须库区类型是立库 var Subs = Expressionable.Create(); Subs.And(it => it.S_WH_CODE == areaModel.S_WH_CODE); Subs.And(it => it.S_AREA_CODE == item.areaCode); Subs.AndIF(!string.IsNullOrEmpty(item.S_FlowNo), it => it.S_FlowNo == item.S_FlowNo); //Subs.And(it => it.S_IS_IN_OUT == "出库"); var Subsidiary = newDb.Queryable().Where(Subs.ToExpression()).ToList(); List tNs = new List();//将不能入的接驳位放进去 var IsJb = newDb.Queryable().Where(e => e.S_IsOpen == "N").ToList(); LogHelper.Info("出库算法", "关闭的接驳位:" + JsonConvert.SerializeObject(IsJb)); var ttg = Subsidiary.FindAll(e => e.S_IS_IN_OUT == "出库" && e.S_FlowNo == item.S_FlowNo).ToList(); //如果说胎面库则调用wcs接驳位接口 查询接驳位是否可用 if (item.areaCode == "LC11M") { WcsRet = BLLCreator.Create().WcsPositionAvailableCk(model.S_TASK_NO); } foreach (var itm in ttg) { var Location = itm.S_CONNECTION.Split(',').ToList(); bool pp = true; foreach (var em in Location) { if (item.areaCode == "LC11M") { if (IsJb.FindAll(e => e.S_JbBit == em).ToList().Count() == 0 && WcsRet.available.Contains(em)) { pp = false; } } else { if (IsJb.FindAll(e => e.S_JbBit == em).ToList().Count() == 0) { pp = false; } } } if (pp) { tNs.Add(itm); } } if (string.IsNullOrEmpty(model.itemCode)) { #region 空托盘出库 //空托盘出库, 增加根据托盘类型出库 if (model.TrayType != "QB" && !string.IsNullOrEmpty(model.TrayType)) { if (model.TrayType != "KJZ") { lstCanOutL = newDb.Queryable().InnerJoin((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).LeftJoin((o, p, t) => p.S_CNTR_CODE == t.S_CNTR_CODE).Where((o, p, t) => o.N_CURRENT_NUM > 0 && o.S_LOCK_STATE == "无" && o.C_ENABLE == "Y" && p.S_TYPE == model.TrayType && string.IsNullOrEmpty(t.S_ITEM_CODE) && o.S_AREA_CODE == item.areaCode).Includes(e => e.LocCntrRel).ToList(); } else { lstCanOutL = newDb.Queryable().InnerJoin((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).LeftJoin((o, p, t) => p.S_CNTR_CODE == t.S_CNTR_CODE).Where((o, p, t) => o.N_CURRENT_NUM > 0 && o.S_LOCK_STATE == "无" && o.C_ENABLE == "Y" && p.S_TYPE.Contains(model.TrayType) && string.IsNullOrEmpty(t.S_ITEM_CODE) && o.S_AREA_CODE == item.areaCode).Includes(e => e.LocCntrRel).ToList(); } // if (model.TrayType == "35" || model.TrayType == "45") // { // lstCanOutL = SqlSugarHelper.Db.Queryable().InnerJoin((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).LeftJoin((o, p, t) => p.S_CNTR_CODE == t.S_CNTR_CODE).Where((o, p, t) => o.N_CURRENT_NUM > 0 && o.S_LOCK_STATE == "无" && o.C_ENABLE == "Y" && //(p.S_TYPE == "35" || p.S_TYPE == "45") // && string.IsNullOrEmpty(t.S_ITEM_CODE) && o.S_AREA_CODE == item.areaCode).Includes(e => e.LocCntrRel).ToList(); // } // else // { // } } else if (string.IsNullOrEmpty(model.TrayType)) { lstCanOutL = newDb.Queryable().InnerJoin((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).LeftJoin((o, p, t) => p.S_CNTR_CODE == t.S_CNTR_CODE).Where((o, p, t) => o.N_CURRENT_NUM > 0 && o.S_LOCK_STATE == "无" && o.C_ENABLE == "Y" && string.IsNullOrEmpty(p.S_TYPE) && string.IsNullOrEmpty(t.S_ITEM_CODE) && o.S_AREA_CODE == item.areaCode).Includes(e => e.LocCntrRel).ToList(); } else { lstCanOutL = newDb.Queryable().InnerJoin((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).LeftJoin((o, p, t) => p.S_CNTR_CODE == t.S_CNTR_CODE).Where((o, p, t) => o.N_CURRENT_NUM > 0 && o.S_LOCK_STATE == "无" && o.C_ENABLE == "Y" && (!p.S_TYPE.Contains("KJZ") || string.IsNullOrEmpty(p.S_TYPE)) && string.IsNullOrEmpty(t.S_ITEM_CODE) && o.S_AREA_CODE == item.areaCode).Includes(e => e.LocCntrRel).ToList(); } if (!string.IsNullOrEmpty(model.S_Roadway)) { lstCanOutL = lstCanOutL.FindAll(e => e.N_ROADWAY.ToString() == model.S_Roadway).ToList(); } LogHelper.DanInfo("出库算法", "1"); if (lstCanOutL.Count == 0) { continue; } else { outResult.errCode = "1003"; if (lstStrategy.Select(o => o.S_STRATEGY_CODE).ToList().Contains("FirstInLastOut")) { //查询这个库区所有入库锁货位 var loca = Expressionable.Create(); loca.And(it => it.S_WH_CODE == model.stockCode); loca.And(it => it.S_AREA_CODE == item.areaCode); loca.And(it => it.S_LOCK_STATE == "入库锁"); locationInLock = newDb.Queryable().Where(loca.ToExpression()).ToList(); // LogHelper.Info("出库算法", "locationInLock数据:" + JsonConvert.SerializeObject(locationInLock)); //控制有入的不能出 foreach (Location entity in locationInLock) { lstCanOutL.RemoveAll(o => o.N_ROW == entity.N_ROW && o.N_COL == entity.N_COL && o.N_LAYER == entity.N_LAYER); } //查询这个库区所有出库锁货位 var Outlo = Expressionable.Create(); Outlo.And(it => it.S_WH_CODE == model.stockCode); Outlo.And(it => it.S_AREA_CODE == item.areaCode); Outlo.And(it => it.S_LOCK_STATE == "出库锁"); locationOutLock = newDb.Queryable().Where(Outlo.ToExpression()).ToList(); // LogHelper.Info("出库算法", "locationOutLock数据:" + JsonConvert.SerializeObject(locationOutLock)); //控制有出的不能出 foreach (Location entity in locationOutLock) { lstCanOutL.RemoveAll(o => o.N_ROW == entity.N_ROW && o.N_COL == entity.N_COL && o.N_LAYER == entity.N_LAYER && o.N_SIDE > entity.N_SIDE); } //空托出库,算到外面的货位并且内侧货位有出库任务则返回没空托 // LogHelper.Info("出库算法", "locationOutLock数据:" + JsonConvert.SerializeObject(locationOutLock)); foreach (Location entity in locationOutLock) { lstCanOutL.RemoveAll(o => o.N_ROW == entity.N_ROW && o.N_COL == entity.N_COL && o.N_LAYER == entity.N_LAYER && o.N_SIDE < entity.N_SIDE); } } if (areaModel.S_AREA_TYPE == "地堆") { if (lstCanOutL.Count > 0) { var Inloca = Expressionable.Create(); Inloca.And(it => it.S_WH_CODE == model.stockCode); Inloca.And(it => it.S_AREA_CODE == item.areaCode); Inloca.And(it => it.S_LOCK_STATE == "入库锁"); locationInLock = newDb.Queryable().Where(Inloca.ToExpression()).ToList(); foreach (Location lEntity in locationInLock) { lstCanOutL.RemoveAll(o => o.N_ROW == lEntity.N_ROW); } // LogHelper.Info("出库算法", "过滤预入库锁定货位后的数据:" + JsonConvert.SerializeObject(lstCanOutL)); var Outloca = Expressionable.Create(); Outloca.And(it => it.S_WH_CODE == model.stockCode); Outloca.And(it => it.S_AREA_CODE == item.areaCode); Outloca.And(it => it.S_LOCK_STATE == "出库锁"); locationOutLock = newDb.Queryable().Where(Outloca.ToExpression()).ToList(); foreach (Location lEntity in locationOutLock) { lstCanOutL.RemoveAll(o => o.N_ROW == lEntity.N_ROW); } // LogHelper.Info("出库算法", "过滤预出库锁定货位后的数据:" + JsonConvert.SerializeObject(lstCanOutL)); lstCanOutL = lstCanOutL.OrderBy(c => c.N_ROW).ThenByDescending(e => e.N_COL).ToList(); } } if (lstCanOutL.Count == 0) { continue; } else { LogHelper.DanInfo("出库算法", "2"); if (areaModel.S_NOTE == Constants.Area_Struc_LiStock) { if (Subsidiary.Any()) { if (Subsidiary.FindAll(e => e.S_AREA_TYPE != Constants.Area_Struc_LiStock).Count() == 0) { //先排除掉不可用巷道 var SubNo = Subsidiary.FindAll(e => e.N_Y_ROADWAY == "N").ToList(); if (SubNo.Any()) { foreach (var Su in SubNo) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == Su.N_ROADWAY); } } LogHelper.DanInfo("出库算法", "3"); if (tNs.Any()) { foreach (var Su in tNs) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == Su.N_ROADWAY); LogHelper.Info("出库算法", $"接驳位关闭移除对应巷道 {Su.N_ROADWAY}"); } } LogHelper.DanInfo("出库算法", "4"); if (item.areaCode == "LC11M") { //查询几个特殊的接驳位 var Jbw1 = IsJb.Find(e => e.S_JbBit == "TMCKHCW-01"); var Jbw2 = IsJb.Find(e => e.S_JbBit == "TMCKJBW-01"); var Jbw3 = IsJb.Find(e => e.S_JbBit == "TMCKHCW-02"); var Jbw4 = IsJb.Find(e => e.S_JbBit == "TMCKJBW-04"); if (Jbw1 != null && Jbw2 != null) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 1"); } if (Jbw3 != null && Jbw4 != null) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 4); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 4"); } if (Jbw1 != null) { var jb1 = ttg.Find(e => e.N_ROADWAY == 1); if (jb1.S_CONNECTION.Contains("TMCKHCW-03")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 1"); } } if (Jbw3 != null) { var jb1 = ttg.Find(e => e.N_ROADWAY == 4); if (jb1.S_CONNECTION.Contains("TMCKHCW-06")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 4); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 4"); } } if (WcsRet.code == "0") { if (WcsRet.code == "0" && !WcsRet.available.Contains("TMCKHCW-01") && !WcsRet.available.Contains("TMCKJBW-01")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("出库算法", $"LC11M库 (WCS告知不能用) 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 1"); } if (WcsRet.code == "0" && !WcsRet.available.Contains("TMCKHCW-02") && !WcsRet.available.Contains("TMCKJBW-04")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("出库算法", $"LC11M库 (WCS告知不能用) 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 4"); } if (!WcsRet.available.Contains("TMCKHCW-01")) { var jb1 = ttg.Find(e => e.N_ROADWAY == 1); if (jb1.S_CONNECTION.Contains("TMCKHCW-03")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 1"); } } if (!WcsRet.available.Contains("TMCKHCW-02")) { var jb1 = ttg.Find(e => e.N_ROADWAY == 4); if (jb1.S_CONNECTION.Contains("TMCKHCW-06")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 4); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 4"); } } } } LogHelper.DanInfo("出库算法", "5"); var KyHwXd = lstCanOutL.GroupBy(e => e.N_ROADWAY).Select(c => c.First()).ToList(); var Sudiary = Subsidiary.GroupBy(e => e.N_ROADWAY).Select(c => c.First()).ToList(); //lstCanOutL = (from l1 in lstCanOutL // join l2 in Subsidiary // on l1.N_ROADWAY equals l2.N_ROADWAY // orderby l2.N_ROADWAY descending // select l1).ToList(); lstCanOutL = (from l1 in lstCanOutL join l2 in Sudiary on l1.N_ROADWAY equals l2.N_ROADWAY orderby l2.N_ROADWAY_PRIORITY descending select l1).ToList(); LogHelper.DanInfo("出库算法", "6"); } } } //加工货位--往对应货位数据里添加对应的托盘信 // lstCanOutL = BLLCreator.Create().LocationTrayList(lstCanOutL); lstTmp_Location = CalculateLocByStegy(lstCanOutL, lstStrate, out deviceCode); LogHelper.DanInfo("出库算法", "7"); if (lstTmp_Location.Count > 0) { at_l_Entity = lstTmp_Location[0]; #region 锁定待出库货位 if (at_l_Entity != null) { if (model.lockLocation) { newDb.BeginTran(); var I = newDb.Updateable().SetColumns(it => it.S_LOCK_STATE == "出库锁").Where(x => x.S_LOC_CODE == at_l_Entity.S_LOC_CODE && x.S_LOCK_STATE == "无").ExecuteCommand(); if (I == 0) { newDb.RollbackTran(); throw new System.Exception("锁定起点货位失败!"); } newDb.CommitTran(); LogHelper.Info("出库算法", at_l_Entity.S_LOC_CODE + "货位更改为预出库锁定,锁定影响数据结果:" + I); if (I > 0) { outResult.Success = true; outResult.Msg = ""; outResult.errCode = ""; outResult.locationCode = at_l_Entity.S_LOC_CODE; outResult.trayCode = lstCanOutL.Where(o => o.S_LOC_CODE == at_l_Entity.S_LOC_CODE).FirstOrDefault().LocCntrRel.S_CNTR_CODE; outResult.areaCode = lstCanOutL.Where(o => o.S_LOC_CODE == at_l_Entity.S_LOC_CODE).FirstOrDefault().S_AREA_CODE; outResult.isControlQty = isControlQty; outResult.isControlInv = isControlInv; break; } } else { outResult.Success = true; outResult.Msg = ""; outResult.errCode = ""; outResult.locationCode = at_l_Entity.S_LOC_CODE; outResult.trayCode = lstCanOutL.Where(o => o.S_LOC_CODE == at_l_Entity.S_LOC_CODE).FirstOrDefault().LocCntrRel.S_CNTR_CODE; outResult.areaCode = lstCanOutL.Where(o => o.S_LOC_CODE == at_l_Entity.S_LOC_CODE).FirstOrDefault().S_AREA_CODE; outResult.isControlQty = isControlQty; outResult.isControlInv = isControlInv; break; } } #endregion break; } } } #endregion } else { #region 满托盘出库 DateTime date = DateTime.Now; var areaCodes = model.lstAreaPrior.Select(o => o.areaCode).ToList(); var ca = Expressionable.Create(); // ca.And((o, p, t) => o.N_CURRENT_NUM > 0 && o.S_LOCK_STATE == "无" && o.C_ENABLE == "Y" && t.S_ITEM_CODE == model.itemCode && areaCodes.Contains(o.S_AREA_CODE)); ca.And((o, p, t) => o.N_CURRENT_NUM > 0 && o.S_LOCK_STATE == "无" && o.C_ENABLE == "Y" && t.S_ITEM_CODE == model.itemCode && o.S_AREA_CODE == item.areaCode); ca.AndIF(!string.IsNullOrEmpty(model.traySpec), (o, p, t) => t.S_ITEM_SPEC.Contains(model.traySpec)); ca.AndIF(!string.IsNullOrEmpty(model.itemState), (o, p, t) => t.S_ITEM_STATE == model.itemState && t.takeEffectTime < date && t.expireTime > date); ca.AndIF(string.IsNullOrEmpty(model.itemState), (o, p, t) => t.S_ITEM_STATE == "合格" && t.takeEffectTime < date && t.expireTime > date); lstCanOutL = newDb.Queryable().InnerJoin((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).InnerJoin((o, p, t) => p.S_CNTR_CODE == t.S_CNTR_CODE).Where(ca.ToExpression()).Includes(e => e.LocCntrRel, p => p.CntrItemRel).ToList(); if (!string.IsNullOrEmpty(model.S_Roadway)) { lstCanOutL = lstCanOutL.FindAll(e => e.N_ROADWAY.ToString() == model.S_Roadway).ToList(); } // LogHelper.Info("出库算法", "lstCanOutL数据:" + JsonConvert.SerializeObject(lstCanOutL)); if (lstStrategy.Select(o => o.S_STRATEGY_CODE).ToList().Contains("FirstInLastOut")) { //查询这个库区所有入库锁货位 var loca = Expressionable.Create(); loca.And(it => it.S_WH_CODE == model.stockCode); loca.And(it => it.S_AREA_CODE == item.areaCode); loca.And(it => it.S_LOCK_STATE == "入库锁"); locationOutLock = newDb.Queryable().Where(loca.ToExpression()).ToList(); // LogHelper.Info("出库算法", "locationInLock数据:" + JsonConvert.SerializeObject(locationInLock)); //控制有入的不能出 foreach (Location entity in locationInLock) { lstCanOutL.RemoveAll(o => o.N_ROW == entity.N_ROW && o.N_COL == entity.N_COL && o.N_LAYER == entity.N_LAYER); } //控制有出的不能出 //查询这个库区所有出库锁货位 var Outlo = Expressionable.Create(); Outlo.And(it => it.S_WH_CODE == model.stockCode); Outlo.And(it => it.S_AREA_CODE == item.areaCode); Outlo.And(it => it.S_LOCK_STATE == "出库锁"); locationOutLock = newDb.Queryable().Where(Outlo.ToExpression()).ToList(); // LogHelper.Info("出库算法", "locationOutLock数据:" + JsonConvert.SerializeObject(locationOutLock)); foreach (Location entity in locationOutLock) { lstCanOutL.RemoveAll(o => o.N_ROW == entity.N_ROW && o.N_COL == entity.N_COL && o.N_LAYER == entity.N_LAYER && o.N_SIDE > entity.N_SIDE); } //满托出库 算到外面的货位并且内侧货位有出库任务则返回没空托 // LogHelper.Info("出库算法", "locationOutLock数据:" + JsonConvert.SerializeObject(locationOutLock)); foreach (Location entity in locationOutLock) { lstCanOutL.RemoveAll(o => o.N_ROW == entity.N_ROW && o.N_COL == entity.N_COL && o.N_LAYER == entity.N_LAYER && o.N_SIDE < entity.N_SIDE); } } if (areaModel.S_AREA_TYPE == "地堆") { if (lstCanOutL.Count > 0) { var Inloca = Expressionable.Create(); Inloca.And(it => it.S_WH_CODE == model.stockCode); Inloca.And(it => it.S_AREA_CODE == item.areaCode); Inloca.And(it => it.S_LOCK_STATE == "入库锁"); locationInLock = newDb.Queryable().Where(Inloca.ToExpression()).ToList(); foreach (Location lEntity in locationInLock) { lstCanOutL.RemoveAll(o => o.N_ROW == lEntity.N_ROW); } // LogHelper.Info("出库算法", "过滤预入库锁定货位后的数据:" + JsonConvert.SerializeObject(lstCanOutL)); var Outloca = Expressionable.Create(); Outloca.And(it => it.S_WH_CODE == model.stockCode); Outloca.And(it => it.S_AREA_CODE == item.areaCode); Outloca.And(it => it.S_LOCK_STATE == "出库锁"); locationOutLock = newDb.Queryable().Where(Outloca.ToExpression()).ToList(); foreach (Location lEntity in locationOutLock) { lstCanOutL.RemoveAll(o => o.N_ROW == lEntity.N_ROW); } // LogHelper.Info("出库算法", "过滤预出库锁定货位后的数据:" + JsonConvert.SerializeObject(lstCanOutL)); lstCanOutL = lstCanOutL.OrderBy(c => c.N_ROW).ThenByDescending(e => e.N_COL).ToList(); } } if (lstCanOutL.Count > 0) { outResult.errCode = "1003"; if (areaModel.S_NOTE == Constants.Area_Struc_LiStock) { if (Subsidiary.Any()) { if (Subsidiary.FindAll(e => e.S_AREA_TYPE != Constants.Area_Struc_LiStock).Count() == 0) { //先排除掉不可用巷道 var SubNo = Subsidiary.FindAll(e => e.N_Y_ROADWAY == "N").ToList(); if (!SubNo.Any()) { foreach (var Su in SubNo) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == Su.N_ROADWAY); LogHelper.Info("出库算法", $"巷道关闭移除对应巷道 {Su.N_ROADWAY}"); } } if (tNs.Any()) { foreach (var Su in tNs) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == Su.N_ROADWAY); LogHelper.Info("出库算法", $"接驳位关闭移除对应巷道 {Su.N_ROADWAY}"); } } if (item.areaCode == "LC11M") { //查询几个特殊的接驳位 var Jbw1 = IsJb.Find(e => e.S_JbBit == "TMCKHCW-01"); var Jbw2 = IsJb.Find(e => e.S_JbBit == "TMCKJBW-01"); var Jbw3 = IsJb.Find(e => e.S_JbBit == "TMCKHCW-02"); var Jbw4 = IsJb.Find(e => e.S_JbBit == "TMCKJBW-04"); if (Jbw1 != null && Jbw2 != null) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 1"); } if (Jbw3 != null && Jbw4 != null) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 4); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 4"); } if (Jbw1 != null) { var jb1 = ttg.Find(e => e.N_ROADWAY == 1); if (jb1.S_CONNECTION.Contains("TMCKHCW-03")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 1"); } } if (Jbw3 != null) { var jb1 = ttg.Find(e => e.N_ROADWAY == 4); if (jb1.S_CONNECTION.Contains("TMCKHCW-06")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 4); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 4"); } } if (WcsRet.code == "0") { if (WcsRet.code == "0" && !WcsRet.available.Contains("TMCKHCW-01") && !WcsRet.available.Contains("TMCKJBW-01")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("出库算法", $"LC11M库 (WCS告知不能用) 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 1"); } if (WcsRet.code == "0" && !WcsRet.available.Contains("TMCKHCW-02") && !WcsRet.available.Contains("TMCKJBW-04")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("出库算法", $"LC11M库 (WCS告知不能用) 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 4"); } if (!WcsRet.available.Contains("TMCKHCW-01")) { var jb1 = ttg.Find(e => e.N_ROADWAY == 1); if (jb1.S_CONNECTION.Contains("TMCKHCW-03")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 1"); } } if (!WcsRet.available.Contains("TMCKHCW-02")) { var jb1 = ttg.Find(e => e.N_ROADWAY == 4); if (jb1.S_CONNECTION.Contains("TMCKHCW-06")) { lstCanOutL.RemoveAll(e => e.N_ROADWAY == 4); LogHelper.Info("出库算法", $"LC11M库 巷道中间的接驳位和可出巷道的接驳位都关闭了则排除巷道 4"); } } } } lstCanOutL = (from l1 in lstCanOutL join l2 in Subsidiary on l1.N_ROADWAY equals l2.N_ROADWAY orderby l2.N_ROADWAY descending select l1).ToList(); } } } //获取该库区中可用货位的信息 // LogHelper.Info("出库算法", "算法逻辑" + JsonConvert.SerializeObject(lstStrate)); // lstCanOutL = BLLCreator.Create().LocationTrayList(lstCanOutL); lstTmp_Location = CalculateLocByStegy(lstCanOutL, lstStrate, out deviceCode, model.itemCode); if (lstTmp_Location.Count > 0) { at_l_Entity = lstTmp_Location[0]; #region 锁定待出库货位 if (at_l_Entity != null) { if (model.lockLocation) { newDb.BeginTran(); var I = newDb.Updateable().SetColumns(it => it.S_LOCK_STATE == "出库锁").Where(x => x.S_LOC_CODE == at_l_Entity.S_LOC_CODE && x.S_LOCK_STATE == "无").ExecuteCommand(); if (I == 0) { newDb.RollbackTran(); throw new System.Exception("锁定起点货位失败!"); } newDb.CommitTran(); LogHelper.Info("出库算法", at_l_Entity.S_LOC_CODE + "货位更改为预出库锁定,锁定影响数据结果:" + I); if (I > 0) { outResult.Success = true; outResult.Msg = ""; outResult.errCode = ""; outResult.locationCode = at_l_Entity.S_LOC_CODE; outResult.trayCode = lstCanOutL.Where(o => o.S_LOC_CODE == at_l_Entity.S_LOC_CODE).FirstOrDefault().LocCntrRel.S_CNTR_CODE; outResult.areaCode = lstCanOutL.Where(o => o.S_LOC_CODE == at_l_Entity.S_LOC_CODE).FirstOrDefault().S_AREA_CODE; outResult.isControlQty = isControlQty; outResult.isControlInv = isControlInv; break; } } else { outResult.Success = true; outResult.Msg = ""; outResult.errCode = ""; outResult.locationCode = at_l_Entity.S_LOC_CODE; outResult.trayCode = lstCanOutL.Where(o => o.S_LOC_CODE == at_l_Entity.S_LOC_CODE).FirstOrDefault().LocCntrRel.S_CNTR_CODE; outResult.areaCode = lstCanOutL.Where(o => o.S_LOC_CODE == at_l_Entity.S_LOC_CODE).FirstOrDefault().S_AREA_CODE; outResult.isControlQty = isControlQty; outResult.isControlInv = isControlInv; break; } } #endregion break; } } #endregion } } return outResult; } /// /// 根据入库策略筛选符合条件的货位 /// /// /// /// /// /// public List CalculateLocByStegy(List lstLocation, List lstStrate, out string deviceCode, string ItemCode = "") { List lstFilterLoc = lstLocation; deviceCode = string.Empty; foreach (string stegy in lstStrate) { //逐个策略进行计算 switch (stegy) { case "RoadWayBalance": //巷道均衡 lstFilterLoc = RoadWayBalanceOut(lstFilterLoc); ; break; case "NearbyBalance": //就近原则 lstFilterLoc = NearbyBalanceOut(lstFilterLoc); ; break; case "InStockTimeOutFirst": //入库时间早先出 lstFilterLoc = lstFilterLoc.OrderBy(o => o.T_FULL_TIME).ToList(); // LogHelper.Info("出库算法", " 入库时间早先出 " + JsonConvert.SerializeObject(lstFilterLoc)); // lstFilterLoc = lstFilterLoc.Where(o => o.N_SIDE == lstFilterLoc.FirstOrDefault().N_SIDE && o.T_FULL_TIME == lstFilterLoc.FirstOrDefault().T_FULL_TIME).ToList(); break; case "productionDateOutFirst": //生产时间早先出 //LogHelper.Info("出库算法", " 生产时间早先出 排序筛选前" + JsonConvert.SerializeObject(lstFilterLoc)); if (!string.IsNullOrEmpty(ItemCode)) { var lstFilte = lstFilterLoc.OrderBy(o => Convert.ToDateTime(o.productionDate)).ToList(); if (lstFilte.Count > 0) { lstFilterLoc = lstFilterLoc.FindAll(o => o.S_LOC_CODE == lstFilte?.FirstOrDefault()?.S_LOC_CODE); LogHelper.Info("出库算法", " 生产时间早先出 " + JsonConvert.SerializeObject(lstFilterLoc)); } } // lstFilterLoc = lstFilterLoc.Where(o => o.N_SIDE == lstFilterLoc.FirstOrDefault().N_SIDE && o.T_FULL_TIME == lstFilterLoc.FirstOrDefault().T_FULL_TIME).ToList(); break; case "FirstInLastOutLj": //先进后出 LogHelper.Info("出库算法", "FirstInLastOut"); if (lstStrate.Contains("OutBigToSmall")) { LogHelper.Info("出库算法", "OutBigToSmall"); lstFilterLoc = lstFilterLoc.OrderBy(o => o.N_ROW).ThenByDescending(o => o.N_COL).ThenByDescending(b => b.N_LAYER).ToList(); } else if (lstStrate.Contains("OutSmallToBig")) { LogHelper.Info("出库算法", "OutSmallToBig"); lstFilterLoc = lstFilterLoc.OrderBy(o => o.N_ROW).ThenBy(o => o.N_COL).ThenByDescending(b => b.N_LAYER).ToList(); } else { lstFilterLoc = lstFilterLoc.OrderByDescending(o => o.N_ROW).ThenBy(b => b.N_LAYER).ToList(); } // LogHelper.Info("出库算法", JsonConvert.SerializeObject(lstFilterLoc)); lstFilterLoc = lstFilterLoc.Where(o => o.N_ROW == lstFilterLoc.FirstOrDefault().N_ROW && o.N_LAYER == lstFilterLoc.FirstOrDefault().N_LAYER).ToList(); break; } } return lstFilterLoc; } #region 巷道均衡 返回巷道对应的货位列表 /// /// 巷道均衡策略 /// /// 可用的货位信息数据 /// 计算后返回的实体 public List RoadWayBalanceOut(List lstTrueLocation) { //指定计算后返回的实体 List location_roadray = new List(); //按照巷道分组 并获得巷道中可用货位的数据 //之后进行倒叙 找到可用货位最多的巷道 var v = lstTrueLocation.GroupBy(x => x.N_ROADWAY).Select(g => (new { roadWay = g.Key, qty = g.Count() })).OrderByDescending(o => o.qty); //倒叙排列后的巷道 循环 foreach (var item in v) { //取得巷道列表中可用货位最多的巷道 并获取巷道中所有货位 location_roadray = lstTrueLocation.Where(o => o.N_ROADWAY == item.roadWay).ToList(); if (location_roadray != null && location_roadray.Count > 0) { break; } } return location_roadray; } #endregion #region 就近原则 只返回一个货位实体 /// /// 就近原则 /// /// 一个巷道内的所有货位数据 /// public List NearbyBalanceOut(List lstTrueLocation) { List lstNearLocation = new List(); if (lstTrueLocation == null || lstTrueLocation.Count == 0) { return lstNearLocation; } //先判断是否存在多个巷道,如果存在就近选择一个巷道 var location_roadray = lstTrueLocation.OrderBy(o => o.N_ROADWAY).Select(o => o.N_ROADWAY).Distinct().ToList(); if (location_roadray != null && location_roadray.Count > 1) { lstTrueLocation = lstTrueLocation.Where(o => o.N_ROADWAY == location_roadray[0]).ToList(); } //按照排分组 并获得排中可用货位的数据 var v = lstTrueLocation.GroupBy(x => x.N_ROW).Select(g => (new { row = g.Key, qty = g.Count() })).OrderByDescending(o => o.qty).ThenBy(o => o.row).ToList();//按照货位可用数量进行倒叙,找到可用货位最多的排 //如果每一排中可用货位相同,则在顺序排列,取最近的排 //找到排空货位最多的排 var v_row = lstTrueLocation.Where(o => o.N_ROW == v[0].row).ToList(); //找到最小的列 var v_col = v_row.OrderBy(o => o.N_COL).ToList(); var min_col = v_col[0].N_COL; //找到一个排下最小的列对应的所有货位 var v_f = v_row.Where(o => o.N_COL == min_col).OrderBy(o => o.N_LAYER).ToList(); //找到符合条件的层的内侧 var v_side = v_f.Where(o => o.N_LAYER == v_f[0].N_LAYER).OrderBy(o => o.N_SIDE).ToList(); var min_side = v_side[0].N_SIDE; //获得层最小的单个 lstNearLocation.Add(v_side.Where(o => o.N_SIDE == min_side).FirstOrDefault()); return lstNearLocation; } #endregion } }