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<TN_AreaEntitys>().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
|
|
/// <summary>
|
/// 作业区出库算法 优先库区
|
/// </summary>
|
/// <param name="model"></param>
|
/// <returns></returns>
|
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<object>().GetInstance();
|
var newDb = chi.CopyNew();
|
|
List<TN_ArithmeticEntitys> lstStrategy = null;
|
List<Location> lstCanOutL = null;
|
string deviceCode = string.Empty;
|
List<string> lstStrate = null;
|
Location at_l_Entity = null;
|
List<Location> lstTmp_Location = new List<Location>();
|
List<Location> lstTrueLocation = new List<Location>();
|
List<Location> lstAllLocation = new List<Location>();
|
List<Location> locationInLock = new List<Location>();
|
List<Location> locationOutLock = new List<Location>();
|
//被锁定的货位
|
List<Location> lstLockLItem = new List<Location>();
|
List<Location> lstLocation = new List<Location>();
|
WcsReturnEntityTwo WcsRet = new WcsReturnEntityTwo();
|
string isControlQty = string.Empty;
|
string isControlInv = string.Empty;
|
|
//将传递过来的库区列表按库区出库优先级排序
|
List<areaPriorClass> lstAreaPrior = model.lstAreaPrior.OrderByDescending(o => o.Prior).ToList();
|
foreach (areaPriorClass item in lstAreaPrior)
|
{
|
//这里判断库区是否可用 并且哪些巷道可用 且必须库区类型是立库
|
TN_AreaEntitys areaModel = newDb.Queryable<TN_AreaEntitys>().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<TN_ArithmeticEntitys>();
|
//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<TN_ArithmeticEntitys>().Where(Texp.ToExpression()).ToList();
|
lstStrate = lstStrategy.Select(o => o.S_STRATEGY_CODE).ToList();
|
|
|
//这里判断库区是否可用 并且哪些巷道可用 且必须库区类型是立库
|
var Subs = Expressionable.Create<TN_SubsidiaryEntitys>();
|
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<TN_SubsidiaryEntitys>().Where(Subs.ToExpression()).ToList();
|
|
List<TN_SubsidiaryEntitys> tNs = new List<TN_SubsidiaryEntitys>();//将不能入的接驳位放进去
|
var IsJb = newDb.Queryable<TN_IsopenBitEntitys>().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<WcsTask>().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<Location>().InnerJoin<LocCntrRel>((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).LeftJoin<CntrItemRel>((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<Location>().InnerJoin<LocCntrRel>((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).LeftJoin<CntrItemRel>((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<Location>().InnerJoin<LocCntrRel>((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).LeftJoin<CntrItemRel>((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<Location>().InnerJoin<LocCntrRel>((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).LeftJoin<CntrItemRel>((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<Location>().InnerJoin<LocCntrRel>((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).LeftJoin<CntrItemRel>((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<Location>();
|
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<Location>().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<Location>();
|
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<Location>().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<Location>();
|
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<Location>().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<Location>();
|
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<Location>().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<AssistComm>().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<Location>().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<Location, LocCntrRel, CntrItemRel>();
|
// 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<Location>().InnerJoin<LocCntrRel>((o, p) => o.S_LOC_CODE == p.S_LOC_CODE).InnerJoin<CntrItemRel>((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<Location>();
|
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<Location>().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<Location>();
|
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<Location>().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<Location>();
|
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<Location>().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<Location>();
|
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<Location>().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<AssistComm>().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<Location>().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;
|
}
|
/// <summary>
|
/// 根据入库策略筛选符合条件的货位
|
/// </summary>
|
/// <param name="lstDevice"></param>
|
/// <param name="lstLocation"></param>
|
/// <param name="lstStrate"></param>
|
/// <param name="deviceCode"></param>
|
/// <returns></returns>
|
public List<Location> CalculateLocByStegy(List<Location> lstLocation, List<string> lstStrate, out string deviceCode, string ItemCode = "")
|
{
|
List<Location> 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 巷道均衡 返回巷道对应的货位列表
|
/// <summary>
|
/// 巷道均衡策略
|
/// </summary>
|
/// <param name="lstTrueLocation">可用的货位信息数据</param>
|
/// <returns>计算后返回的实体</returns>
|
public List<Location> RoadWayBalanceOut(List<Location> lstTrueLocation)
|
{
|
//指定计算后返回的实体
|
List<Location> location_roadray = new List<Location>();
|
|
//按照巷道分组 并获得巷道中可用货位的数据
|
//之后进行倒叙 找到可用货位最多的巷道
|
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 就近原则 只返回一个货位实体
|
/// <summary>
|
/// 就近原则
|
/// </summary>
|
/// <param name="lstTrueLocation">一个巷道内的所有货位数据</param>
|
/// <returns></returns>
|
public List<Location> NearbyBalanceOut(List<Location> lstTrueLocation)
|
{
|
List<Location> lstNearLocation = new List<Location>();
|
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
|
}
|
}
|