|
using HH.WMS.Common;
|
using HH.WMS.Common.Algorithm;
|
using HH.WMS.Common.Algorithm.Out;
|
using HH.WMS.DAL.Algorithm;
|
using HH.WMS.DAL.Basic;
|
using HH.WMS.Entitys.Algorithm;
|
using HH.WMS.Entitys.Basic;
|
using HH.WMS.Entitys.Common;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using HH.WMS.DAL.InStock;
|
using HH.WMS.BLL.Common;
|
using Newtonsoft.Json;
|
using HH.WMS.Entitys.Dto;
|
using HH.WMS.Entitys;
|
|
namespace HH.WMS.BLL.Algorithm
|
{
|
/// <summary>
|
/// 出库算法BLL层
|
/// </summary>
|
public class Out_AlgorBLL : BaseBLL
|
{
|
/**************计算 返回物料所在货位的算法开始/**************/
|
|
#region 非作业区 出库算法
|
/// <summary>
|
/// 返回物料 先进先出、质保期将近的先出
|
/// </summary>
|
/// <param name="model"></param>
|
/// <returns></returns>
|
//public List<OutResultEntity> Out(OutAlgorEnitty model)
|
//{
|
// List<OutResultEntity> lstResultEntity = new List<OutResultEntity>();
|
// Log.AlgorInfo("Out_AlgorBLL—Out", "出库算法开始,传入参数:" + JsonConvert.SerializeObject(model));
|
// //获取项目策略
|
// List<STRATEGYALGOREntity> lstStrategy = new List<STRATEGYALGOREntity>();
|
// HH.WMS.Entitys.Basic.AutoBomStockAreaEntity stockEntity = CreateDAL<TN_AB_B_STOCK_AREADAL>().GetStockAreaEntity(model.lstQueryItem[0].areaCode);
|
// lstStrategy = CreateDAL<TN_WM_B_STRATEGYDAL>().GetStrateListByAreaOrStock(stockEntity.CN_S_STOCK_CODE, "", "");
|
// List<string> lstStrate = lstStrategy.Select(o => o.CN_S_NAME).ToList();
|
// //if (lstStrate.Contains("JXXAlgor"))
|
// //{
|
// lstResultEntity = OutJxxFlat(model);
|
// //}
|
// //if (lstStrate.Contains("SszyAlgor"))
|
// //{
|
// // lstResultEntity = OutSszyFlat(model);
|
// //}
|
// return lstResultEntity;
|
//}
|
#endregion
|
|
#region 非作业区 平库立库出库算法,根据物料的数量出库
|
///// <summary>
|
///// 非作业区 平库立库出库算法,根据物料的数量出库
|
///// </summary>
|
///// <param name="model"></param>
|
///// <returns></returns>
|
//public List<OutResultEntity> OutJxxFlat(OutAlgorEnitty model)
|
//{
|
// Log.AlgorInfo("Out_AlgorBLL—Out", "OutJxxFlat");
|
// List<OutResultEntity> lstResultEntity = new List<OutResultEntity>();
|
// //将传递过来的参数按货主、状态、等查询条件分组
|
// List<Out_AreaItemClass> lstAreaItemGroup = GroupAreaCode(model.lstQueryItem);
|
// foreach (Out_AreaItemClass areaItemEntity in lstAreaItemGroup)
|
// {
|
// Log.AlgorInfo("Out_AlgorBLL—Out", "循环处理lstAreaItemGroup数据:" + JsonConvert.SerializeObject(areaItemEntity));
|
// string areaCode = areaItemEntity.areaCode;
|
// string itemCodes = string.Join(",", areaItemEntity.lstItem.Select(o => o.itemCode)).Replace(",", "','");
|
// //组合查询条件
|
// string strWhere = GetPropWhereStr(itemCodes, areaItemEntity.itemState, areaItemEntity.batchCode, areaItemEntity.prodBatchCode, areaItemEntity.ownerName);
|
|
// //查询该库区配置的出库策略及优先级(生产日期早先出、先进先出、出库整托优先)
|
// List<STRATEGYALGOREntity> lstStrategy = new List<STRATEGYALGOREntity>();
|
// lstStrategy = CreateDAL<TN_WM_B_STRATEGYDAL>().GetStrateListByAreaOrStock("", areaCode, "出库");
|
// List<string> lstStrate = lstStrategy.Select(o => o.CN_S_NAME).ToList();
|
|
// //获得库区中所有匹配的物料
|
// List<itemQty> v = CreateDAL<Out_AlgorDAL>().GetItemQtyJxx(strWhere, areaCode);
|
// Log.AlgorInfo("Out_AlgorBLL—Out", "List<itemQty>数据:" + JsonConvert.SerializeObject(v));
|
// //循环处理批分分配量
|
// List<itemQty> lstAllocQty = v.Select(g => new itemQty()
|
// {
|
// trayCode = g.trayCode,
|
// CN_F_ALLOC_QTY = g.CN_F_ALLOC_QTY,
|
// CN_S_OWNER = g.CN_S_OWNER,
|
// CN_S_ITEM_STATE = g.CN_S_ITEM_STATE,
|
// itemCode = g.itemCode,
|
// }).Distinct().ToList();
|
|
// int tmpAllocQty = 0;
|
// foreach (itemQty item in v)
|
// {
|
// //循环托盘物料详细数据,按生产批次早、入库批次早批分分配量
|
// tmpAllocQty = lstAllocQty.Where(o => (o.trayCode == item.trayCode && o.CN_S_OWNER == item.CN_S_OWNER && o.CN_S_ITEM_STATE == item.CN_S_ITEM_STATE && o.itemCode == item.itemCode)).FirstOrDefault().CN_F_ALLOC_QTY;
|
// if (tmpAllocQty > 0)
|
// {
|
// item.Qty = item.Qty - tmpAllocQty;
|
// lstAllocQty.Where(o => (o.trayCode == item.trayCode && o.CN_S_OWNER == item.CN_S_OWNER && o.CN_S_ITEM_STATE == item.CN_S_ITEM_STATE && o.itemCode == item.itemCode)).FirstOrDefault().CN_F_ALLOC_QTY = item.Qty - tmpAllocQty;
|
// }
|
// }
|
// v.RemoveAll(o => o.Qty <= 0);
|
|
// Log.AlgorInfo("Out_AlgorBLL—Out", "获得库区中所有匹配的物料:lstItemQty:" + JsonConvert.SerializeObject(v));
|
|
// List<string> lstCodes = v.GroupBy(a => a.locationCode).Select(o => o.Key).ToList();
|
// //到mongodb中查询每个货位的基本信息排除货位被报废的数据
|
// List<AutoBomLocationAbbreEntity> lstFalseLocation = CreateDAL<TN_WMS_LOCATIONDAL>().GetScrapLocationCode(lstCodes);
|
// lstCodes = lstFalseLocation.Select(a => a.CN_S_LOCATION_CODE).ToList();
|
// v.RemoveAll(o => lstCodes.Contains(o.locationCode));
|
|
// //循环前端物料列表
|
// foreach (itemInClass item in areaItemEntity.lstItem)
|
// {
|
// //定义返回值
|
// OutResultEntity resultEntity = new OutResultEntity();
|
// //验证过的物料货位集合
|
// List<itemQty> lstTrueItem = new List<itemQty>();
|
// //判断是否合法
|
// MsgEntity msgEntity = IsPassItem(item, v, out lstTrueItem);
|
// if (!msgEntity.Success)//不合法
|
// {
|
// resultEntity.Success = false;
|
// resultEntity.Msg = msgEntity.Msg;
|
// resultEntity.itemCode = item.itemCode;
|
// }
|
// else //合法
|
// {
|
// resultEntity.Success = true;
|
// resultEntity.itemCode = item.itemCode;
|
// /*返回时加入条件*/
|
// resultEntity.areaCode = areaItemEntity.areaCode;
|
// resultEntity.batchCode = areaItemEntity.batchCode;
|
// resultEntity.prodBatchCode = areaItemEntity.prodBatchCode;
|
// resultEntity.itemState = areaItemEntity.itemState;
|
// resultEntity.ownerName = areaItemEntity.ownerName;
|
// /*条件结束*/
|
// List<itemTrayLocation> lstResult = GetJXXTrayLocation(lstStrate, item, model.lstDevice, lstTrueItem, model.lockLocation);
|
// resultEntity.itemLocations = lstResult.GroupBy(a => new
|
// {
|
// a.agvLocationCode,
|
// a.locationCode,
|
// a.trayCode,
|
// a.trayGrid
|
// }).Select(g => new itemTrayLocation()
|
// {
|
// itemQty = g.Sum(s => s.itemQty),
|
// agvLocationCode = g.Key.agvLocationCode,
|
// locationCode = g.Key.locationCode,
|
// trayCode = g.Key.trayCode,
|
// trayGrid = g.Key.trayGrid
|
// }).ToList();
|
// }
|
// lstResultEntity.Add(resultEntity);
|
// }
|
// }
|
// return lstResultEntity;
|
//}
|
|
#endregion
|
|
|
|
public OutResultEntityNew OutNew(OutAlgorEnitty model)
|
{
|
OutResultEntityNew resultE = new OutResultEntityNew();
|
Log.AlgorInfo("Out_AlgorBLL—Out", "出库算法开始,传入参数:" + JsonConvert.SerializeObject(model));
|
|
resultE = OutCommonFlat(model);
|
|
return resultE;
|
}
|
#region 非作业区 平库立库出库算法,根据物料的数量出库
|
|
|
/// <summary>
|
/// 非作业区 平库立库出库算法,根据物料的数量出库
|
/// </summary>
|
/// <param name="model"></param>
|
/// <returns></returns>
|
public OutResultEntityNew OutCommonFlat(OutAlgorEnitty model)
|
{
|
OutResultEntityNew resultEntity = new OutResultEntityNew();
|
resultEntity.Success = true;
|
resultEntity.Msg = "";
|
try
|
{
|
#region 定义变量
|
Log.AlgorInfo("Out_AlgorBLL—Out", "OutCommonFlat");
|
StringBuilder sbWhere = new StringBuilder();
|
List<itemQty> lstAllIQ = new List<itemQty>();
|
List<trayOutItem> lstTray = new List<trayOutItem>();
|
resultEntity.lstItemNotEnough = new List<itemQueryClass>();
|
#endregion
|
|
#region 查询该库区配置的出库策略及优先级
|
List<STRATEGYALGOREntity> lstStrategy = new List<STRATEGYALGOREntity>();
|
lstStrategy = CreateDAL<TN_WM_B_STRATEGYDAL>().GetStrateListByAreaOrStock("", model.lstQueryItem[0].areaCode, "出库");
|
List<string> lstStrate = lstStrategy.OrderByDescending(a => a.CN_N_PRIORITY).Select(o => o.CN_S_CODE).ToList();
|
#endregion
|
|
#region 缓存记录托盘、货主、物料、状态对应的待分配量,循环itemQueryClass时根据结果实时更新
|
//List<itemQty> lstWaitAlloc = new List<itemQty>();
|
//List<itemQty> lstForAlloc = new List<itemQty>();
|
//foreach (itemQueryClass itemQuery in model.lstQueryItem)
|
//{
|
// lstForAlloc = CreateDAL<Out_AlgorDAL>().GetOutItemAllocQty(itemQuery.itemCode, itemQuery.itemState, itemQuery.ownerName, itemQuery.areaCode);
|
// if (lstForAlloc != null && lstForAlloc.Count > 0)
|
// {
|
// lstWaitAlloc.AddRange(lstForAlloc);
|
// }
|
//}
|
//lstWaitAlloc = lstWaitAlloc.Distinct().ToList();
|
//if (lstWaitAlloc.Count == 0)
|
//{
|
// //如果从库区中查找不到符合出库条件的托盘,则将传入物料记录到物料不足列表中反馈
|
// resultEntity.lstItemNotEnough.AddRange(model.lstQueryItem);
|
// return resultEntity;
|
//}
|
#endregion
|
|
foreach (itemQueryClass itemQuery in model.lstQueryItem)
|
{
|
Log.AlgorInfo("Out_AlgorBLL—Out", "循环处理lstQueryItem数据:" + JsonConvert.SerializeObject(itemQuery));
|
|
#region 循环处理批分分配量
|
//获得库区中所有匹配的待出库的物料库存数据
|
List<itemQty> lstIQ = CreateDAL<Out_AlgorDAL>().GetOutItemQty(itemQuery.itemCode, itemQuery.itemState, itemQuery.prodBatchCode, itemQuery.batchCode, itemQuery.ownerName, itemQuery.areaCode);
|
if (lstIQ.Count == 0)
|
{
|
resultEntity.lstItemNotEnough.Add(itemQuery);
|
continue;
|
}
|
//Log.AlgorInfo("Out_AlgorBLL—Out", "批分前库区中所有匹配的物料数据:" + JsonConvert.SerializeObject(lstIQ));
|
////过滤lstWaitAlloc中不在lstIQ中的托盘,因为这些托盘的待分配量不需要处理
|
//List<string> lstTrayCode = lstIQ.Select(o => o.trayCode).Distinct().ToList();
|
//List<itemQty> lstAllocQty = lstWaitAlloc.Where(o => o.CN_F_ALLOC_QTY > 0 && lstTrayCode.Contains(o.trayCode) && o.itemCode == itemQuery.itemCode && o.CN_S_OWNER == itemQuery.ownerName && o.CN_S_ITEM_STATE == itemQuery.itemState).Select(g => new itemQty()
|
//{
|
// trayCode = g.trayCode,
|
// CN_F_ALLOC_QTY = g.CN_F_ALLOC_QTY,
|
// CN_S_OWNER = g.CN_S_OWNER,
|
// CN_S_ITEM_STATE = g.CN_S_ITEM_STATE,
|
// itemCode = g.itemCode
|
//}).Distinct().ToList();
|
|
//decimal alloc_qty = 0;
|
//foreach (itemQty iQty in lstAllocQty)
|
//{
|
// alloc_qty = iQty.CN_F_ALLOC_QTY;
|
// //递归批分处理货位托盘中的待分配量,去除lstIQ中已经被批分的数据(已被其他分拣单占用的数据)
|
// DivideAllocQty(ref lstIQ, iQty, ref alloc_qty, lstStrate);
|
//}
|
//Log.AlgorInfo("Out_AlgorBLL—Out", "批分后库区中所有匹配的物料数据:" + JsonConvert.SerializeObject(lstIQ));
|
#endregion
|
|
#region 到mongodb中查询每个货位的基本信息,排除货位被报废的数据
|
List<string> lstCodes = lstIQ.GroupBy(a => a.locationCode).Select(o => o.Key).ToList();
|
List<AutoBomLocationAbbreEntity> lstFalseLocation = CreateDAL<TN_WMS_LOCATIONDAL>().GetScrapLocationCode(lstCodes);
|
lstCodes = lstFalseLocation.Select(a => a.CN_S_LOCATION_CODE).ToList();
|
//此时的lstIQ是去除批分量、货位无故障的可出库物料数据
|
lstIQ.RemoveAll(o => lstCodes.Contains(o.locationCode));
|
#endregion
|
|
#region 处理不满足出库数量的物料并计算可出库货位
|
|
//按照库区等查询条件分组
|
var lstItemGroup = lstIQ.GroupBy(a => new
|
{
|
a.itemCode
|
}).Select(g => (new
|
{
|
itemCode = g.Key.itemCode,
|
itemQty = g.Sum(p => p.Qty)
|
}));
|
var equalItem = lstItemGroup.Where(o => o.itemCode == itemQuery.itemCode).FirstOrDefault();
|
|
if (equalItem == null || equalItem.itemQty < itemQuery.itemQty)
|
{
|
//记录不满足出库条件的物料
|
itemQuery.itemQty = itemQuery.itemQty - equalItem.itemQty;
|
resultEntity.lstItemNotEnough.Add(itemQuery);
|
}
|
else
|
{
|
Log.AlgorInfo("Out_AlgorBLL—Out", "计算具体出库货位开始:");
|
decimal needOutQty = itemQuery.itemQty;
|
lstTray.AddRange(CalculateOutLocation(itemQuery, ref needOutQty, ref lstIQ, lstStrate));
|
//增加缓存批分量
|
//foreach (trayOutItem toItem in lstTray)
|
//{
|
// tmpItemQty = lstWaitAlloc.Where(o => o.trayCode == toItem.trayCode && o.itemCode == toItem.itemCode && o.CN_S_OWNER == toItem.ownerName && o.CN_S_ITEM_STATE == toItem.itemState).FirstOrDefault();
|
// if (tmpItemQty != null)
|
// {
|
// tmpItemQty.CN_F_ALLOC_QTY = tmpItemQty.CN_F_ALLOC_QTY + toItem.itemQty;
|
// }
|
//}
|
List<string> needLock = lstTray.Select(o => o.locationCode).Distinct().ToList();
|
foreach (string itemLoc in needLock)
|
{
|
//更新货位状态
|
if (model.lockLocation)
|
{
|
SqlExecuteResult result = CreateDAL<TN_WM_LOCATION_EXTDAL>().UpdateLocationState(itemLoc, Constants.Location_State_OutLock, "出库", null);
|
Log.AlgorInfo("Out_AlgorBLL", "货位" + itemLoc + "更改为预出库锁定,执行结果为:" + result.Success.ToString() + result.Row.ToString());
|
}
|
}
|
}
|
|
#endregion
|
}
|
resultEntity.itemLocations = lstTray;
|
}
|
catch (Exception ex)
|
{
|
resultEntity.Success = false;
|
resultEntity.Msg = ex.Message;
|
}
|
Log.AlgorInfo("Out_AlgorBLL—Out", "返回计算结果:" + JsonConvert.SerializeObject(resultEntity));
|
return resultEntity;
|
|
}
|
|
public List<trayOutItem> CalculateOutLocation(itemQueryClass itemQC, ref decimal needOutQty, ref List<itemQty> lstAllIQ, List<string> lstStrate)
|
{
|
bool isNoDivide = false;
|
bool forceDivide = false;
|
List<itemQty> lstFilterItem = CalculateItemByStegy(needOutQty, lstAllIQ, lstStrate, out isNoDivide, out forceDivide);
|
List<trayOutItem> lstTray = new List<trayOutItem>();
|
decimal tmpQty = 0;
|
List<string> lstNeedRemove = new List<string>();
|
|
|
#region 不可拆包,优先拣包装数量较大的
|
foreach (itemQty item in lstFilterItem)
|
{
|
Log.AlgorInfo("Out_AlgorBLL—Out", "循环lstFilterItem物料数据:" + JsonConvert.SerializeObject(item));
|
trayOutItem trayItem = new trayOutItem();
|
trayItem.itemCode = item.itemCode;
|
trayItem.itemState = item.CN_S_ITEM_STATE;
|
trayItem.ownerName = item.CN_S_OWNER;
|
trayItem.batchCode = item.lotNo;
|
trayItem.prodBatchCode = item.prodBatchCode;
|
trayItem.trayCode = item.trayCode;
|
trayItem.trayGrid = item.trayGrid;
|
trayItem.locationCode = item.locationCode;
|
trayItem.areaCode = itemQC.areaCode;
|
trayItem.CN_S_TIMESTAMP = item.CN_S_TIMESTAMP;
|
trayItem.packUnit = item.packUnit;
|
trayItem.packQty = item.PAKQty;
|
Log.AlgorInfo("Out_AlgorBLL—Out", "needOutQty < item.Qty:" + needOutQty.ToString() + "," + item.Qty.ToString());
|
if (needOutQty < item.Qty)
|
{
|
Log.AlgorInfo("Out_AlgorBLL—Out", "needOutQty < item.PAKQty:" + needOutQty.ToString() + "," + item.PAKQty.ToString());
|
//待出库量比该托盘中物料数量小
|
if (needOutQty >= item.PAKQty)
|
{
|
trayItem.itemQty = needOutQty - needOutQty % item.PAKQty;
|
if (item.Qty - trayItem.itemQty >= 0)
|
{
|
//降低该记录的可出库量,
|
lstAllIQ.Find(O => O.ID == item.ID).Qty = item.Qty - trayItem.itemQty;
|
}
|
else
|
{
|
lstNeedRemove.Add(item.ID);
|
}
|
needOutQty = needOutQty % item.PAKQty;
|
lstTray.Add(trayItem);
|
Log.AlgorInfo("Out_AlgorBLL—Out", "needOutQty >= item.PAKQty,trayItem:" + JsonConvert.SerializeObject(trayItem));
|
}
|
else
|
{
|
Log.AlgorInfo("Out_AlgorBLL—Out", "forceDivide:" + forceDivide.ToString());
|
if (forceDivide)
|
{
|
//库区中无不拆包可出库数据,强制拆包
|
trayItem.itemQty = needOutQty;
|
lstAllIQ.Find(O => O.ID == item.ID).Qty = item.Qty - needOutQty;
|
needOutQty = 0;
|
lstTray.Add(trayItem);
|
Log.AlgorInfo("Out_AlgorBLL—Out", "forceDivide,trayItem:" + JsonConvert.SerializeObject(trayItem));
|
}
|
else
|
{
|
//待出库量比该托盘中该单位的包装数量小,则跳出循环,寻找比该包装规格小的物料数据
|
break;
|
}
|
}
|
}
|
else
|
{
|
//待出库量比该托盘中物料数量大,将该托盘中物料全出
|
trayItem.itemQty = item.Qty;
|
lstNeedRemove.Add(item.ID);
|
needOutQty = needOutQty - item.Qty;
|
lstTray.Add(trayItem);
|
Log.AlgorInfo("Out_AlgorBLL—Out", "待出库量比该托盘中物料数量大,trayItem:" + JsonConvert.SerializeObject(trayItem));
|
}
|
|
if (needOutQty < item.PAKQty)
|
{
|
//待出库量小于规格数量则结束循环
|
break;
|
}
|
}
|
#endregion
|
|
lstAllIQ.RemoveAll(o => lstNeedRemove.Contains(o.ID));
|
if (needOutQty > 0 && lstAllIQ.Count > 0)
|
{
|
//如果未分配完则递归循环
|
lstTray.AddRange(CalculateOutLocation(itemQC, ref needOutQty, ref lstAllIQ, lstStrate));
|
}
|
return lstTray;
|
|
}
|
|
/// <summary>
|
/// 将货位中的物料数据按照策略排序
|
/// </summary>
|
/// <param name="lstIQ"></param>
|
/// <param name="lstStrate"></param>
|
/// <returns></returns>
|
public List<itemQty> CalculateItemByStegy(decimal needOutQty, List<itemQty> lstIQ, List<string> lstStrate, out bool isNoDivide, out bool forceDivide)
|
{
|
List<itemQty> lstFilterItem = lstIQ;
|
List<itemQty> lstEmptyPBC;
|
List<itemQty> lstTpm;
|
List<itemQty> lstTpm1;
|
bool IsIntegerOut = false;
|
isNoDivide = false;
|
forceDivide = false;
|
foreach (string stegy in lstStrate)
|
{
|
//逐个策略进行计算
|
switch (stegy)
|
{
|
case "RowOutFirst":
|
lstFilterItem = lstFilterItem.OrderBy(o => o.CN_S_ROW).ThenBy(o => o.CN_S_COL).ToList();
|
lstFilterItem = lstFilterItem.Where(o => o.CN_S_ROW == lstFilterItem.FirstOrDefault().CN_S_ROW && o.CN_S_COL == lstFilterItem.FirstOrDefault().CN_S_COL).ToList();
|
break;
|
case "ProductTimeOutFirst":
|
lstFilterItem = lstFilterItem.OrderBy(o => o.productDate).ToList();
|
lstFilterItem = lstFilterItem.Where(o => o.productDate == lstFilterItem.FirstOrDefault().productDate).ToList();
|
break;
|
case "FirstWarrantFirstOut":
|
lstEmptyPBC = lstFilterItem.Where(o => string.IsNullOrEmpty(o.prodBatchCode)).ToList();
|
lstFilterItem = lstFilterItem.Where(o => !string.IsNullOrEmpty(o.prodBatchCode)).OrderBy(o => o.prodBatchCode).ToList();
|
lstFilterItem.AddRange(lstEmptyPBC);
|
lstFilterItem = lstFilterItem.Where(o => o.prodBatchCode == lstFilterItem.FirstOrDefault().prodBatchCode).ToList();
|
break;
|
case "IntegerTrayFirstOut":
|
IsIntegerOut = true;
|
lstTpm = lstFilterItem.GroupBy(a => new { a.trayCode }).Select(g => new itemQty()
|
{
|
Qty = g.Sum(s => s.Qty),
|
trayCode = g.Key.trayCode
|
}).ToList();
|
lstTpm = lstTpm.OrderByDescending(o => o.Qty).ToList();
|
lstTpm1 = lstTpm.Where(o => o.Qty >= needOutQty).ToList();
|
if (lstTpm1 == null || lstTpm1.Count == 0)
|
{
|
//该托盘中总数量不满足出库需求,则找最大数量的托盘
|
lstFilterItem = lstFilterItem.Where(o => o.trayCode == lstTpm.FirstOrDefault().trayCode).ToList();
|
}
|
else
|
{
|
//该托盘中总数量满足出库需求
|
lstTpm1 = lstTpm1.OrderBy(o => o.Qty).ToList();
|
lstFilterItem = lstFilterItem.Where(o => o.trayCode == lstTpm1.FirstOrDefault().trayCode).ToList();
|
}
|
break;
|
case "NoDivideFirstOut":
|
IsIntegerOut = true;
|
isNoDivide = true;
|
lstFilterItem = lstFilterItem.OrderByDescending(o => o.PAKQty).ToList();
|
Log.AlgorInfo("Out_AlgorBLL—Out", "NoDivideFirstOut前lstFilterItem物料数据:" + JsonConvert.SerializeObject(lstFilterItem));
|
lstTpm1 = lstFilterItem.Where(o => o.PAKQty <= needOutQty).ToList();
|
if (lstTpm1.Count == 0)
|
{
|
//货位中物料匹配数据中无包装单位比待出库数量小的数据,只有拆包
|
forceDivide = true;
|
lstTpm1 = lstFilterItem.OrderBy(o => o.PAKQty).ToList();
|
//寻找最接近出库数量的包装拆包
|
lstFilterItem = lstFilterItem.Where(o => o.Qty == lstTpm1.FirstOrDefault().Qty).ToList();
|
}
|
else
|
{
|
//货位中物料匹配数据中存在包装单位比带出库数量小的数据,先计算大包装的
|
lstFilterItem = lstFilterItem.Where(o => o.PAKQty == lstTpm1.FirstOrDefault().PAKQty).ToList();
|
}
|
Log.AlgorInfo("Out_AlgorBLL—Out", "NoDivideFirstOut后lstFilterItem物料数据:" + JsonConvert.SerializeObject(lstFilterItem));
|
break;
|
}
|
if (IsIntegerOut)
|
{
|
break;
|
}
|
}
|
return lstFilterItem;
|
}
|
|
|
|
/// <summary>
|
/// 降低货位库存分配量
|
/// </summary>
|
/// <param name="lstIQ"></param>
|
/// <param name="allocItem"></param>
|
/// <param name="needDivideQty"></param>
|
/// <param name="lstStrate"></param>
|
public void DivideAllocQty(ref List<itemQty> lstIQ, itemQty allocItem, ref decimal needDivideQty, List<string> lstStrate)
|
{
|
List<itemQty> lstFilterItem = FilterItemByStegy(lstIQ.Where(o => o.trayCode == allocItem.trayCode && o.itemCode == allocItem.itemCode && o.CN_S_OWNER == allocItem.CN_S_OWNER && o.CN_S_ITEM_STATE == allocItem.CN_S_ITEM_STATE).ToList(), lstStrate);
|
decimal tmpQty = 0;
|
List<string> lstNeedRemove = new List<string>();
|
foreach (itemQty item in lstFilterItem)
|
{
|
tmpQty = needDivideQty - item.Qty;
|
if (tmpQty < 0)
|
{
|
|
//降低该记录的可出库量,并跳出循环
|
lstIQ.Find(O => O.ID == item.ID).Qty = item.Qty - needDivideQty;
|
needDivideQty = tmpQty;
|
break;
|
}
|
else
|
{
|
needDivideQty = tmpQty;
|
//删除该记录
|
lstNeedRemove.Add(item.ID);
|
|
}
|
}
|
lstIQ.RemoveAll(o => lstNeedRemove.Contains(o.ID));
|
if (needDivideQty > 0 && lstIQ.Count > 0)
|
{
|
//如果未分配完则递归循环
|
DivideAllocQty(ref lstIQ, allocItem, ref needDivideQty, lstStrate);
|
}
|
}
|
/// <summary>
|
/// 将货位中的物料数据按照策略排序
|
/// </summary>
|
/// <param name="lstIQ"></param>
|
/// <param name="lstStrate"></param>
|
/// <returns></returns>
|
public List<itemQty> FilterItemByStegy(List<itemQty> lstIQ, List<string> lstStrate)
|
{
|
List<itemQty> lstFilterItem = lstIQ;
|
List<itemQty> lstEmptyPBC;
|
foreach (string stegy in lstStrate)
|
{
|
//逐个策略进行计算
|
switch (stegy)
|
{
|
case "FirstInFirstOut":
|
lstFilterItem = lstFilterItem.OrderBy(o => o.lotNo).ToList();
|
lstFilterItem = lstFilterItem.Where(o => o.lotNo == lstFilterItem.FirstOrDefault().lotNo).ToList();
|
break;
|
case "FirstWarrantFirstOut":
|
lstEmptyPBC = lstFilterItem.Where(o => string.IsNullOrEmpty(o.prodBatchCode)).ToList();
|
lstFilterItem = lstFilterItem.Where(o => !string.IsNullOrEmpty(o.prodBatchCode)).OrderBy(o => o.prodBatchCode).ToList();
|
lstFilterItem.AddRange(lstEmptyPBC);
|
lstFilterItem = lstFilterItem.Where(o => o.prodBatchCode == lstFilterItem.FirstOrDefault().prodBatchCode).ToList();
|
break;
|
}
|
}
|
return lstFilterItem;
|
}
|
#endregion
|
|
|
|
|
#region 生成查询条件
|
/// <summary>
|
/// 生成查询条件
|
/// </summary>
|
/// <param name="itemCodes"></param>
|
/// <param name="itemState"></param>
|
/// <param name="batchCode"></param>
|
/// <param name="ownerName"></param>
|
/// <returns></returns>
|
public string GetPropWhereStr1(string itemCodes, string itemState, string batchCode, string prodBatchCode, string ownerName)
|
{
|
StringBuilder strWhere = new StringBuilder();
|
// strWhere.Append(" 1=1 ");
|
|
//物料编码
|
if (!string.IsNullOrEmpty(itemCodes))
|
{
|
strWhere.AppendLine(" AND CN_S_ITEM_CODE IN ('" + itemCodes + "') ");
|
}
|
//物料状态
|
if (!string.IsNullOrEmpty(itemState))
|
{
|
strWhere.AppendLine(" AND CN_S_ITEM_STATE = '" + itemState + "' ");
|
}
|
//批次号
|
if (!string.IsNullOrEmpty(batchCode))
|
{
|
strWhere.AppendLine(" AND CN_S_LOT_NO = '" + batchCode + "' ");
|
}
|
//生产批次号
|
if (!string.IsNullOrEmpty(prodBatchCode))
|
{
|
strWhere.AppendLine(" AND CN_S_PRODUCTION_BATCH = '" + prodBatchCode + "' ");
|
}
|
//货主
|
if (!string.IsNullOrEmpty(ownerName))
|
{
|
strWhere.AppendLine(" AND CN_S_OWNER = '" + ownerName + "' ");
|
}
|
return strWhere.ToString();
|
}
|
#endregion
|
#region 出库调用的方法 将传递过来的请求出库的物料进行分组
|
/// <summary>
|
/// 将传递过来的请求出库的物料进行分组 保证算法的执行速度
|
/// </summary>
|
/// <param name="lstAreaItem"></param>
|
/// <returns></returns>
|
private List<Out_AreaItemClass> GroupAreaCode(List<itemQueryClass> lstQueryItem)
|
{
|
//定义分组后的物料数据
|
List<Out_AreaItemClass> lstAreaItemGroup = new List<Out_AreaItemClass>();
|
if (lstQueryItem == null || lstQueryItem.Count == 0)
|
{
|
return lstAreaItemGroup;
|
}
|
//按照库区等查询条件分组
|
var v_AreaGroup = lstQueryItem.GroupBy(a => new
|
{
|
//追加条件后 需要在此处加入分组条件定义 &&&&
|
a.stockCode,
|
a.areaCode,
|
a.ownerName,
|
a.batchCode,
|
a.prodBatchCode,
|
a.itemState,
|
a.itemCode
|
}).Select(g => (new
|
{
|
//追加条件后 需要在此处加入分组条件定义 &&&&
|
stockCode = g.Key.stockCode,
|
areaCode = g.Key.areaCode,
|
ownerName = g.Key.ownerName,
|
batchCode = g.Key.batchCode,
|
prodBatchCode = g.Key.prodBatchCode,
|
itemState = g.Key.itemState,
|
itemCode = g.Key.itemCode,
|
itemQty = g.Sum(p => p.itemQty)
|
}));
|
Out_AreaItemClass areaItemEntity = new Out_AreaItemClass();
|
//循环传递的实体参数数量
|
foreach (var areaItem in v_AreaGroup)
|
{
|
//则将物料列表信息传递给分组后的列表
|
areaItemEntity.areaCode = areaItem.areaCode;
|
areaItemEntity.stockCode = areaItem.stockCode;
|
areaItemEntity.ownerName = areaItem.ownerName;
|
areaItemEntity.batchCode = areaItem.batchCode;
|
areaItemEntity.prodBatchCode = areaItem.prodBatchCode;
|
areaItemEntity.itemState = areaItem.itemState;
|
areaItemEntity.itemCode = areaItem.itemCode;
|
areaItemEntity.itemQty = decimal.Parse(areaItem.itemQty.ToString());
|
lstAreaItemGroup.Add(areaItemEntity);
|
}
|
return lstAreaItemGroup;
|
}
|
#endregion
|
|
/**************计算 返回物料所在货位的算法结束/**************/
|
|
|
/*****************计算 返回库区的算法开始/*****************/
|
|
#region 非作业区平库立库 返回库区对应出库物料的算法,该算法只算到库区可出库数量
|
/// <summary>
|
/// 出库 返回库区对应出库物料的算法,该算法只算到库区,不到货位
|
/// </summary>
|
/// <param name="model">返回库区算法传递的类</param>
|
/// <returns></returns>
|
public OutAreaResultAllEntity OutArea(List<itemQueryClass> lstQueryOut, List<areaPriorClass> lstAreaPrior)
|
{
|
Log.AlgorInfo("Out_AlgorBLL—OutArea", "算法开始,传入参数lstQueryOut:" + JsonConvert.SerializeObject(lstQueryOut) + ",lstAreaPrior:" + JsonConvert.SerializeObject(lstAreaPrior));
|
//返回数据的实体集合
|
OutAreaResultAllEntity outAreaResult = new OutAreaResultAllEntity();
|
//存放计算物料库存结果
|
List<OutAreaResultEntity> lstOutResultEntity = new List<OutAreaResultEntity>();
|
bool checkEnough = true;
|
//将传递过来的参数按货主、批次号、物料状态分组后再按物料分组
|
List<Out_AreaItemClass> lstAreaItemGroup = GroupAreaCode(lstQueryOut);
|
//循环处理
|
foreach (var i_Group in lstAreaItemGroup)
|
{
|
Log.AlgorInfo("Out_AlgorBLL—OutArea", "循环处理lstAreaItemGroup:" + i_Group.areaCode + "," + i_Group.batchCode + "," + i_Group.itemState + "," + i_Group.ownerName);
|
string stockCode = i_Group.stockCode;
|
#region 判断库存是否足够
|
//获得所有物料
|
string itemCodes = i_Group.itemCode;
|
//获得查询条件
|
string strWhere = GetPropWhereStr1(itemCodes, i_Group.itemState, i_Group.batchCode, i_Group.prodBatchCode, i_Group.ownerName);
|
//获得物料在仓库中的数量
|
List<OutAreaItemQty> lstAreaItemQty = null;
|
lstAreaItemQty = CreateDAL<TN_WM_B_AREA_QTYDAL>().GetAreaQty(strWhere, stockCode);
|
lstAreaItemQty.ForEach(x => x.areaCode = x.areaCode.Trim());
|
lstAreaItemQty.RemoveAll(o => o.Qty <= 0);
|
lstAreaItemQty = lstAreaItemQty.Join(lstAreaPrior, u => u.areaCode, d => d.areaCode, (u, d) => new { u, d })
|
.Select(o => new OutAreaItemQty
|
{
|
areaCode = o.u.areaCode,
|
itemCode = o.u.itemCode,
|
Qty = o.u.Qty,
|
Prior = o.d.Prior
|
}
|
).OrderBy(p => p.Prior).ToList();
|
|
var lstStockItemQty = lstAreaItemQty.GroupBy(a => a.itemCode).Select(g => new
|
{
|
itemCode = g.Key,
|
stockNum = g.Sum(p => p.Qty)
|
});
|
|
List<itemOutClass> lstFalseItem = new List<itemOutClass>();
|
|
#region 循环处理查询不满足出库数量的物料
|
itemOutClass outClassEntity = new itemOutClass();
|
var itemEntity = lstStockItemQty.Where(o => o.itemCode == i_Group.itemCode).SingleOrDefault();
|
if (itemEntity != null)
|
{
|
//获得仓库内该物料的数量
|
decimal qty = (decimal)i_Group.itemQty;
|
if (qty < (decimal)i_Group.itemQty)
|
{
|
outClassEntity.Success = false;
|
outClassEntity.Msg = "当前仓库中该物料的数量不满足需要出库的数量";
|
outClassEntity.itemCode = i_Group.itemCode;
|
outClassEntity.itemQty = qty;
|
lstFalseItem.Add(outClassEntity);
|
}
|
}
|
else
|
{
|
outClassEntity.Success = false;
|
outClassEntity.Msg = "在仓库中未找到该物料对应的库存数量信息";
|
outClassEntity.itemCode = i_Group.itemCode;
|
outClassEntity.itemQty = 0;
|
lstFalseItem.Add(outClassEntity);
|
}
|
#endregion
|
|
if (lstFalseItem != null && lstFalseItem.Count > 0)
|
{
|
checkEnough = false;
|
}
|
lstOutResultEntity.AddRange(GetOutAreaList(stockCode, lstAreaItemQty, i_Group, lstAreaPrior));
|
#endregion
|
|
}
|
if (!checkEnough)
|
{
|
outAreaResult.Success = false;
|
outAreaResult.Msg = "物料库存不足";
|
}
|
else
|
{
|
outAreaResult.Success = true;
|
outAreaResult.Msg = "";
|
}
|
outAreaResult.itemOutAreaResult = lstOutResultEntity;
|
Log.AlgorInfo("Out_AlgorBLL—OutArea", "计算结果outAreaResult:" + JsonConvert.SerializeObject(outAreaResult));
|
return outAreaResult;
|
}
|
#endregion
|
#region 用于计算返回库区的算法
|
/// <summary>
|
/// 用于计算返回库区的算法
|
/// </summary>
|
/// <param name="stockCode"></param>
|
/// <param name="lstAreaOutItemQty">每个库区对应的物料数量</param>
|
/// <param name="lstItem"></param>
|
/// <returns></returns>
|
private List<OutAreaResultEntity> GetOutAreaList(string stockCode, List<OutAreaItemQty> lstAreaOutItemQty, Out_AreaItemClass outAreaItem, List<areaPriorClass> lstAreaPrior)
|
{
|
List<OutAreaResultEntity> lstOutResultEntity = new List<OutAreaResultEntity>();
|
List<string> lstArea = lstAreaPrior.OrderByDescending(o => o.Prior).Select(p => p.areaCode).ToList();
|
Out_AreaItemClass divideItemEntity = new Out_AreaItemClass();
|
//则将物料列表信息传递给分组后的列表
|
decimal remainder = 0;
|
Out_AreaItemClass itemRemaind = null;
|
if (outAreaItem.itemQty >= 12)
|
{
|
remainder = outAreaItem.itemQty % 12;
|
outAreaItem.itemQty = outAreaItem.itemQty - remainder;
|
if (remainder != 0)
|
{
|
itemRemaind = new Out_AreaItemClass();
|
itemRemaind.areaCode = outAreaItem.areaCode;
|
itemRemaind.stockCode = outAreaItem.stockCode;
|
itemRemaind.ownerName = outAreaItem.ownerName;
|
itemRemaind.batchCode = outAreaItem.batchCode;
|
itemRemaind.prodBatchCode = outAreaItem.prodBatchCode;
|
itemRemaind.itemState = outAreaItem.itemState;
|
itemRemaind.itemCode = outAreaItem.itemCode;
|
itemRemaind.itemQty = remainder;
|
}
|
}
|
else
|
{
|
lstArea = lstAreaPrior.OrderBy(o => o.Prior).Select(p => p.areaCode).ToList();
|
}
|
|
//循环所有库区
|
List<itemOutClass> LstItemOut = new List<itemOutClass>();
|
for (int i = 0; i < lstArea.Count; i++)
|
{
|
#region 循环库区获取可出库物料
|
if (outAreaItem.itemQty == 0)
|
{
|
break;
|
}
|
//找到该库区下的物料
|
List<OutAreaItemQty> lst_item_Area = lstAreaOutItemQty.Where(o => o.areaCode == lstArea[i] && o.itemCode == outAreaItem.itemCode).ToList();
|
if (lst_item_Area.Count > 0)
|
{
|
foreach (OutAreaItemQty item_Area in lst_item_Area)
|
{
|
OutAreaResultEntity resultEntity = new OutAreaResultEntity();
|
resultEntity.stockCode = stockCode;
|
resultEntity.areaCode = lstArea[i];
|
resultEntity.ownerName = outAreaItem.ownerName;
|
resultEntity.batchCode = outAreaItem.batchCode;
|
resultEntity.prodBatchCode = outAreaItem.prodBatchCode;
|
resultEntity.itemState = outAreaItem.itemState;
|
//获取当前库区下可分配的物料列表
|
if (outAreaItem.itemQty > 0)
|
{
|
itemOutClass outEntity = new itemOutClass();
|
if (outAreaItem.itemQty <= item_Area.Qty)
|
{
|
//表示需求物料数量在该库区中满足要求
|
outAreaItem.itemQty = 0;
|
outEntity.itemCode = outAreaItem.itemCode;
|
outEntity.itemQty = outAreaItem.itemQty;
|
}
|
else
|
{
|
//等于该库区中的数量
|
outAreaItem.itemQty = outAreaItem.itemQty - item_Area.Qty;
|
outEntity.itemCode = outAreaItem.itemCode;
|
outEntity.itemQty = item_Area.Qty;
|
}
|
LstItemOut.Add(outEntity);
|
resultEntity.lstItem = LstItemOut;
|
lstOutResultEntity.Add(resultEntity);
|
}
|
else
|
{
|
|
break;
|
}
|
}
|
}
|
#endregion
|
}
|
//循环所有库区
|
List<itemOutClass> LstItemOutRemaind = new List<itemOutClass>();
|
if (itemRemaind != null)
|
{
|
lstArea = lstAreaPrior.OrderBy(o => o.Prior).Select(p => p.areaCode).ToList();
|
for (int i = 0; i < lstArea.Count; i++)
|
{
|
#region 循环库区获取可出库物料
|
if (itemRemaind.itemQty == 0)
|
{
|
break;
|
}
|
//找到该库区下的物料
|
List<OutAreaItemQty> lst_item_Area = lstAreaOutItemQty.Where(o => o.areaCode == lstArea[i] && o.itemCode == itemRemaind.itemCode).ToList();
|
if (lst_item_Area.Count > 0)
|
{
|
foreach (OutAreaItemQty item_Area in lst_item_Area)
|
{
|
OutAreaResultEntity resultEntity = new OutAreaResultEntity();
|
resultEntity.stockCode = stockCode;
|
resultEntity.areaCode = lstArea[i];
|
resultEntity.ownerName = itemRemaind.ownerName;
|
resultEntity.batchCode = itemRemaind.batchCode;
|
resultEntity.prodBatchCode = itemRemaind.prodBatchCode;
|
resultEntity.itemState = itemRemaind.itemState;
|
//获取当前库区下可分配的物料列表
|
if (itemRemaind.itemQty > 0)
|
{
|
itemOutClass outEntity = new itemOutClass();
|
if (itemRemaind.itemQty <= item_Area.Qty)
|
{
|
//表示需求物料数量在该库区中满足要求
|
itemRemaind.itemQty = 0;
|
outEntity.itemCode = itemRemaind.itemCode;
|
outEntity.itemQty = itemRemaind.itemQty;
|
}
|
else
|
{
|
//等于该库区中的数量
|
itemRemaind.itemQty = itemRemaind.itemQty - item_Area.Qty;
|
outEntity.itemCode = itemRemaind.itemCode;
|
outEntity.itemQty = item_Area.Qty;
|
}
|
LstItemOutRemaind.Add(outEntity);
|
resultEntity.lstItem = LstItemOutRemaind;
|
lstOutResultEntity.Add(resultEntity);
|
}
|
else
|
{
|
|
break;
|
}
|
}
|
}
|
#endregion
|
}
|
}
|
|
return lstOutResultEntity;
|
}
|
#endregion
|
|
|
//*****************计算 返回库区的算法结束/*****************/
|
|
#region 作业区出库算法入口
|
|
public OutAssignResultEntity OutAssign(OutAssignEnitty model)
|
{
|
Log.AlgorInfo("OutAssign", "出库算法参数:" + JsonConvert.SerializeObject(model));
|
OutAssignResultEntity outResult = new OutAssignResultEntity();
|
try
|
{
|
//标准出库算法
|
string areaType = CreateDAL<TN_WMS_AREADAL>().GetAreaTypeByCode(model.lstAreaPrior[0].areaCode.ToString());
|
if (areaType == Constants.Area_Struc_PingStock || areaType == Constants.Area_Struc_LiStock)
|
{
|
outResult = FlatAreaOutLocation(model);
|
}
|
else if (areaType == Constants.Area_Struc_LiuLiStock)
|
{
|
|
}
|
outResult.areaType = areaType;
|
Log.AlgorInfo("OutAssign", "出库返回结果:" + JsonConvert.SerializeObject(outResult));
|
return outResult;
|
}
|
catch (Exception ex)
|
{
|
Log.AlgorInfo("OutAssign", "异常:" + ex.Message + ex.StackTrace);
|
outResult.Msg = "算法异常," + ex.Message + ex.StackTrace;
|
return outResult;
|
}
|
}
|
|
#endregion
|
|
#region 平库出库算法
|
public OutAssignResultEntity FlatAreaOutLocation(OutAssignEnitty model)
|
{
|
OutAssignResultEntity outResult = new OutAssignResultEntity();
|
#region 传入参数判断
|
if (model == null)
|
{
|
outResult.Success = false;
|
outResult.Msg = "参数实体不能为 null !";
|
return outResult;
|
}
|
//判断指定的入作业库对象类型不能为空
|
if (string.IsNullOrEmpty(model.stockCode.ToString()))
|
{
|
outResult.Success = false;
|
outResult.Msg = "指定的出库仓库编号不能为空!";
|
return outResult;
|
}
|
//判断传入库区列表不能为空
|
if (model.lstAreaPrior == null || model.lstAreaPrior.Count == 0)
|
{
|
outResult.Success = false;
|
outResult.Msg = "指定的出作业库库区列表不能为空!";
|
return outResult;
|
}
|
#endregion
|
List<STRATEGYALGOREntity> lstStrategy = CreateDAL<TN_WM_B_STRATEGYDAL>().GetStrateListByAreaOrStock(model.stockCode, "", "出库");
|
List<string> lstStrate = lstStrategy.Select(o => o.CN_S_NAME).ToList();
|
if (lstStrate.Count > 0)
|
{
|
//如果仓库配置策略(如生产日期早先出等),则优先响应仓库策略
|
outResult = OutStockPrior(model, lstStrate);
|
}
|
else
|
{
|
//如果仓库没有配置策略则优先响应库区优先策略
|
outResult = OutAreaPrior(model);
|
|
}
|
return outResult;
|
}
|
|
|
/// <summary>
|
/// 作业区出库算法 优先仓库策略
|
/// </summary>
|
/// <param name="model"></param>
|
/// <param name="lstStrategy"></param>
|
/// <returns></returns>
|
private OutAssignResultEntity OutStockPrior(OutAssignEnitty model, List<string> lstStrategy)
|
{
|
//返回实体集合
|
OutAssignResultEntity outResult = new OutAssignResultEntity();
|
outResult.Success = false;
|
if (string.IsNullOrEmpty(model.itemCode))
|
{
|
outResult.Msg = "库区中无该规格的空托";
|
}
|
else
|
{
|
outResult.Msg = "库存不足";
|
}
|
SqlExecuteResult result = null;
|
List<Device> lstDevice = model.lstDevice;
|
string deviceCode = string.Empty;
|
AutoBomLocationAbbreEntity at_l_Entity = null;
|
List<AutoBomLocationAbbreEntity> lstTmp_Location = new List<AutoBomLocationAbbreEntity>();
|
List<AutoBomLocationAbbreEntity> lstTrueLocation = new List<AutoBomLocationAbbreEntity>();
|
string isControlQty = CreateDAL<TN_WMS_AREADAL>().GetIsControlQtyByCode(model.lstAreaPrior[0].areaCode.ToString());
|
model.lockLocation = isControlQty.Equals("Y") ? true : false;//不管控数量时,不锁定起点货位
|
outResult.isControlQty = isControlQty;
|
string areaCodes = string.Join("','", model.lstAreaPrior.Select(o => o.areaCode));
|
//获得作业区中所有匹配条件(物料等)的货位
|
List<outAssignLocation> lstCanOutL = CreateDAL<Out_AlgorDAL>().GetAssignFlatItemQty(model.itemCode, areaCodes);
|
if (lstCanOutL.Count == 0)
|
{
|
return outResult;
|
}
|
if (lstStrategy.Contains("ProductTimeOutFirst"))
|
{
|
lstCanOutL = lstCanOutL.OrderBy(o => o.productDate).ToList();
|
at_l_Entity = CreateDAL<TN_WMS_LOCATIONDAL>().GetLocationByLocationCodeAbbre(lstCanOutL[0].ToString());
|
}
|
else if (lstStrategy.Contains("InStockTimeOutFirst"))
|
{
|
lstCanOutL = lstCanOutL.OrderBy(o => o.opTime).ToList();
|
at_l_Entity = CreateDAL<TN_WMS_LOCATIONDAL>().GetLocationByLocationCodeAbbre(lstCanOutL[0].ToString());
|
}
|
|
if (at_l_Entity == null)
|
{
|
return outResult;
|
}
|
|
else
|
{
|
//更新货位状态
|
if (model.lockLocation)
|
{
|
result = CreateDAL<TN_WM_LOCATION_EXTDAL>().UpdateLocationState(at_l_Entity.CN_S_LOCATION_CODE, Constants.Location_State_OutLock, "出库", null);
|
if (result != null)
|
{
|
if (result.Success && result.Row > 0)
|
{
|
outResult.Success = true;
|
outResult.Msg = "";
|
outResult.locationCode = at_l_Entity.CN_S_LOCATION_CODE;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.CN_S_LOCATION_CODE).FirstOrDefault().trayCode;
|
}
|
else
|
{
|
outResult.Success = false;
|
outResult.Msg = "锁定出库货位失败";
|
}
|
}
|
}
|
else
|
{
|
outResult.Success = true;
|
outResult.Msg = "";
|
outResult.locationCode = at_l_Entity.CN_S_LOCATION_CODE;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.CN_S_LOCATION_CODE).FirstOrDefault().trayCode;
|
}
|
}
|
|
return outResult;
|
}
|
|
/// <summary>
|
/// 作业区出库算法 优先库区
|
/// </summary>
|
/// <param name="model"></param>
|
/// <returns></returns>
|
private OutAssignResultEntity OutAreaPrior(OutAssignEnitty model)
|
{
|
//返回实体集合
|
OutAssignResultEntity outResult = new OutAssignResultEntity();
|
outResult.Success = false;
|
if (string.IsNullOrEmpty(model.itemCode))
|
{
|
if (model.projectCode == "ys001")
|
{
|
outResult.Msg = "库区中无该规格的空托";
|
}
|
else if (model.projectCode == "hcbh")
|
{
|
outResult.Msg = "库区中无可出托盘";
|
}
|
else
|
{
|
outResult.Msg = "库区中无空托";
|
}
|
}
|
else
|
{
|
outResult.Msg = "库存不足";
|
}
|
|
List<STRATEGYALGOREntity> lstStrategy = null;
|
List<outAssignLocation> lstCanOutL = null;
|
List<Device> lstDevice = model.lstDevice;
|
string deviceCode = string.Empty;
|
List<string> lstStrate = null;
|
SqlExecuteResult result = null;
|
outAssignLocation at_l_Entity = null;
|
List<outAssignLocation> lstTmp_Location = new List<outAssignLocation>();
|
List<AutoBomLocationAbbreEntity> lstTrueLocation = new List<AutoBomLocationAbbreEntity>();
|
List<AutoBomLocationAbbreEntity> lstAllLocation = new List<AutoBomLocationAbbreEntity>();
|
//被锁定的货位
|
List<AutoBomLocationAbbreEntity> lstLockLItem = new List<AutoBomLocationAbbreEntity>();
|
List<AutoBomLocationAbbreEntity> lstLocation = new List<AutoBomLocationAbbreEntity>();
|
string isControlQty = string.Empty;
|
string isControlInv = string.Empty;
|
decimal needOutWeight = 0;
|
AutoBomItemEntity autoBomE = null;
|
if (model.projectCode == "ys001")
|
{
|
if (!string.IsNullOrEmpty(model.itemCode))
|
{
|
autoBomE = CreateDAL<TN_WMS_ITEMDAL>().GetItemEntity(model.itemCode);
|
}
|
}
|
//将传递过来的库区列表按库区出库优先级排序
|
List<areaPriorClass> lstAreaPrior = model.lstAreaPrior.OrderBy(o => o.Prior).ToList();
|
if (model.projectCode == "ntsd")
|
{
|
foreach (areaPriorClass item in lstAreaPrior)
|
{
|
List<TN_WM_TASKEntity> lstTask = CreateDAL<HH.WMS.DAL.SysMgr.TN_WM_TASKDAL>().GetTaskByAreaCode(item.areaCode);
|
item.Prior = lstTask.Count;
|
}
|
lstAreaPrior = lstAreaPrior.OrderBy(o => o.Prior).ToList();
|
Log.AlgorInfo("InAssign-FlatAreaGetLocation", "lstAreaPrior数据:" + JsonConvert.SerializeObject(lstAreaPrior));
|
}
|
|
foreach (areaPriorClass item in lstAreaPrior)
|
{
|
AutoBomStockAreaEntity areaModel = CreateDAL<TN_WMS_AREADAL>().GetModel(item.areaCode.ToString());
|
isControlQty = areaModel.CN_C_IS_CONTROL_QTY;
|
isControlInv = areaModel.CN_C_IS_INVENTORY;
|
if (model.needCalLock)
|
{
|
model.lockLocation = isControlQty.Equals("Y") ? true : false;//不管控数量时,不锁定目的货位
|
}
|
lstStrategy = CreateDAL<TN_WM_B_STRATEGYDAL>().GetStrateListByAreaOrStock("", item.areaCode, "出库");
|
lstStrate = lstStrategy.Select(o => o.CN_S_CODE).ToList();
|
if (string.IsNullOrEmpty(model.itemCode))
|
{
|
if (model.projectCode == "hcbh")
|
{
|
#region 托盘出库,忽略托盘中物料
|
lstCanOutL = CreateDAL<Out_AlgorDAL>().GetAssignFlatEmptySpecTrayBH(model.traySpec, item.areaCode);
|
if (lstCanOutL.Count == 0)
|
{
|
continue;
|
}
|
else
|
{
|
lstTrueLocation = CreateDAL<TN_WMS_LOCATIONDAL>().GetLocationByLocationCode(lstCanOutL.Select(o => o.locationCode).ToList());
|
lstCanOutL = lstCanOutL.Join(lstTrueLocation, u => u.locationCode, d => d.CN_S_LOCATION_CODE, (u, d) => new { u, d }).Select(o => new outAssignLocation
|
{
|
trayCode = o.u.trayCode,
|
locationCode = o.u.locationCode,
|
stockAreaCode = o.u.stockAreaCode,
|
useState = o.u.useState,
|
opTime = o.u.opTime,
|
productDate = o.u.productDate,
|
lotNo = o.u.lotNo,
|
CN_S_STOCK_CODE = o.d.CN_S_STOCK_CODE,
|
CN_S_ROADWAY = o.d.CN_S_ROADWAY,
|
CN_S_ROW = o.d.CN_S_ROW,
|
CN_S_COL = o.d.CN_S_COL,
|
CN_S_FLOOR = o.d.CN_S_FLOOR,
|
CN_S_LOCATION_STATE = o.d.CN_S_LOCATION_STATE
|
|
}).ToList();
|
//获取该终点对应的出库的排
|
var rowMapStr = JsonHelper.GetValue("rowMapping");
|
var rowMaps = JsonConvert.DeserializeObject<List<RowMapDto>>(rowMapStr);
|
RowMapDto rMap = rowMaps.Where(o => o.endBit == model.endBit).FirstOrDefault();
|
if (rMap != null)
|
{
|
lstCanOutL = lstCanOutL.Where(o => o.CN_S_ROW == rMap.startRow).ToList();
|
}
|
List<TN_WM_LOCATIONCODE_EXT_Entity> locationInLock = CreateDAL<TN_WM_LOCATION_EXTDAL>().GetLockLocationByState(model.stockCode.Trim(), item.areaCode, null, Constants.Location_State_InLock);
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "locationInLock数据:" + JsonConvert.SerializeObject(locationInLock));
|
foreach (TN_WM_LOCATIONCODE_EXT_Entity lEntity in locationInLock)
|
{
|
lstCanOutL.RemoveAll(o => o.CN_S_ROW == lEntity.CN_S_ROW);
|
}
|
lstTmp_Location = CalculateLocByStegy(ref lstDevice, lstCanOutL, lstStrate, out deviceCode);
|
if (lstTmp_Location.Count > 0)
|
{
|
at_l_Entity = lstTmp_Location[0];
|
#region 锁定待出库货位
|
if (at_l_Entity != null)
|
{
|
if (model.lockLocation)
|
{
|
result = CreateDAL<TN_WM_LOCATION_EXTDAL>().UpdateLocationState(at_l_Entity.locationCode, Constants.Location_State_OutLock, "出库", null);
|
if (result != null)
|
{
|
if (result.Success && result.Row > 0)
|
{
|
outResult.Success = true;
|
outResult.Msg = "";
|
outResult.locationCode = at_l_Entity.locationCode;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.locationCode).FirstOrDefault().trayCode;
|
outResult.areaCode = item.areaCode;
|
outResult.isControlQty = isControlQty;
|
outResult.isControlInv = isControlInv;
|
break;
|
}
|
|
}
|
}
|
else
|
{
|
outResult.Success = true;
|
outResult.Msg = "";
|
outResult.locationCode = at_l_Entity.locationCode;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.locationCode).FirstOrDefault().trayCode;
|
outResult.areaCode = item.areaCode;
|
outResult.isControlQty = isControlQty;
|
outResult.isControlInv = isControlInv;
|
break;
|
}
|
}
|
#endregion
|
break;
|
}
|
}
|
#endregion
|
}
|
else if (model.projectCode == "tzlj")
|
{
|
#region 泰州隆基空托盘出库
|
lstCanOutL = CreateDAL<Out_AlgorDAL>().GetAssignFlatEmptySpecTrayLJ(model.traySpec, item.areaCode);
|
if (lstCanOutL.Count == 0)
|
{
|
continue;
|
}
|
else
|
{
|
lstTrueLocation = CreateDAL<TN_WMS_LOCATIONDAL>().GetLocationByLocationCode(lstCanOutL.Select(o => o.locationCode).ToList());
|
lstCanOutL = lstCanOutL.Join(lstTrueLocation, u => u.locationCode, d => d.CN_S_LOCATION_CODE, (u, d) => new { u, d }).Select(o => new outAssignLocation
|
{
|
trayCode = o.u.trayCode,
|
locationCode = o.u.locationCode,
|
stockAreaCode = o.u.stockAreaCode,
|
useState = o.u.useState,
|
opTime = o.u.opTime,
|
productDate = o.u.productDate,
|
lotNo = o.u.lotNo,
|
CN_S_STOCK_CODE = o.d.CN_S_STOCK_CODE,
|
CN_S_ROADWAY = o.d.CN_S_ROADWAY,
|
CN_S_ROW = o.d.CN_S_ROW,
|
CN_S_COL = o.d.CN_S_COL,
|
CN_S_FLOOR = o.d.CN_S_FLOOR,
|
CN_S_LOCATION_STATE = o.d.CN_S_LOCATION_STATE
|
|
}).ToList();
|
lstTmp_Location = CalculateLocByStegy(ref lstDevice, lstCanOutL, lstStrate, out deviceCode);
|
if (lstTmp_Location.Count > 0)
|
{
|
at_l_Entity = lstTmp_Location[0];
|
#region 锁定待出库货位
|
if (at_l_Entity != null)
|
{
|
if (model.lockLocation)
|
{
|
result = CreateDAL<TN_WM_LOCATION_EXTDAL>().UpdateLocationState(at_l_Entity.locationCode, Constants.Location_State_OutLock, "出库", null);
|
if (result != null)
|
{
|
if (result.Success && result.Row > 0)
|
{
|
outResult.Success = true;
|
outResult.Msg = "";
|
outResult.locationCode = at_l_Entity.locationCode;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.locationCode).FirstOrDefault().trayCode;
|
outResult.areaCode = item.areaCode;
|
outResult.isControlQty = isControlQty;
|
outResult.isControlInv = isControlInv;
|
break;
|
}
|
|
}
|
}
|
else
|
{
|
outResult.Success = true;
|
outResult.Msg = "";
|
outResult.locationCode = at_l_Entity.locationCode;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.locationCode).FirstOrDefault().trayCode;
|
outResult.areaCode = item.areaCode;
|
outResult.isControlQty = isControlQty;
|
outResult.isControlInv = isControlInv;
|
break;
|
}
|
}
|
#endregion
|
break;
|
}
|
}
|
#endregion
|
}
|
else if (model.projectCode == "masym")
|
{
|
#region 马鞍山粤美空托盘出库
|
lstCanOutL = CreateDAL<Out_AlgorDAL>().GetAssignFlatEmptySpecTrayYM(model.traySpec, item.areaCode);
|
if (lstCanOutL.Count == 0)
|
{
|
continue;
|
}
|
else
|
{
|
lstTrueLocation = CreateDAL<TN_WMS_LOCATIONDAL>().GetLocationByLocationCode(lstCanOutL.Select(o => o.locationCode).ToList());
|
lstCanOutL = lstCanOutL.Join(lstTrueLocation, u => u.locationCode, d => d.CN_S_LOCATION_CODE, (u, d) => new { u, d }).Select(o => new outAssignLocation
|
{
|
trayCode = o.u.trayCode,
|
locationCode = o.u.locationCode,
|
stockAreaCode = o.u.stockAreaCode,
|
useState = o.u.useState,
|
opTime = o.u.opTime,
|
productDate = o.u.productDate,
|
lotNo = o.u.lotNo,
|
CN_S_STOCK_CODE = o.d.CN_S_STOCK_CODE,
|
CN_S_ROADWAY = o.d.CN_S_ROADWAY,
|
CN_S_ROW = o.d.CN_S_ROW,
|
CN_S_COL = o.d.CN_S_COL,
|
CN_S_FLOOR = o.d.CN_S_FLOOR,
|
CN_S_LOCATION_STATE = o.d.CN_S_LOCATION_STATE
|
|
}).ToList();
|
lstTmp_Location = CalculateLocByStegy(ref lstDevice, lstCanOutL, lstStrate, out deviceCode);
|
if (lstTmp_Location.Count > 0)
|
{
|
at_l_Entity = lstTmp_Location[0];
|
#region 锁定待出库货位
|
if (at_l_Entity != null)
|
{
|
if (model.lockLocation)
|
{
|
result = CreateDAL<TN_WM_LOCATION_EXTDAL>().UpdateLocationState(at_l_Entity.locationCode, Constants.Location_State_OutLock, "出库", null);
|
if (result != null)
|
{
|
if (result.Success && result.Row > 0)
|
{
|
outResult.Success = true;
|
outResult.Msg = "";
|
outResult.locationCode = at_l_Entity.locationCode;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.locationCode).FirstOrDefault().trayCode;
|
outResult.areaCode = item.areaCode;
|
outResult.isControlQty = isControlQty;
|
outResult.isControlInv = isControlInv;
|
break;
|
}
|
|
}
|
}
|
else
|
{
|
outResult.Success = true;
|
outResult.Msg = "";
|
outResult.locationCode = at_l_Entity.locationCode;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.locationCode).FirstOrDefault().trayCode;
|
outResult.areaCode = item.areaCode;
|
outResult.isControlQty = isControlQty;
|
outResult.isControlInv = isControlInv;
|
break;
|
}
|
}
|
#endregion
|
break;
|
}
|
}
|
#endregion
|
}
|
else
|
{
|
#region 空托盘出库
|
//空托盘出库,add by ly 20190102 增加根据托盘类型出库
|
lstCanOutL = CreateDAL<Out_AlgorDAL>().GetAssignFlatEmptySpecTray(model.traySpec, item.areaCode);
|
if (lstCanOutL.Count == 0)
|
{
|
continue;
|
}
|
else
|
{
|
lstTrueLocation = CreateDAL<TN_WMS_LOCATIONDAL>().GetLocationByLocationCode(lstCanOutL.Select(o => o.locationCode).ToList());
|
lstCanOutL = lstCanOutL.Join(lstTrueLocation, u => u.locationCode, d => d.CN_S_LOCATION_CODE, (u, d) => new { u, d }).Select(o => new outAssignLocation
|
{
|
trayCode = o.u.trayCode,
|
locationCode = o.u.locationCode,
|
stockAreaCode = o.u.stockAreaCode,
|
useState = o.u.useState,
|
opTime = o.u.opTime,
|
productDate = o.u.productDate,
|
lotNo = o.u.lotNo,
|
CN_S_STOCK_CODE = o.d.CN_S_STOCK_CODE,
|
CN_S_ROADWAY = o.d.CN_S_ROADWAY,
|
CN_S_ROW = o.d.CN_S_ROW,
|
CN_S_COL = o.d.CN_S_COL,
|
CN_S_FLOOR = o.d.CN_S_FLOOR,
|
CN_S_LOCATION_STATE = o.d.CN_S_LOCATION_STATE
|
|
}).ToList();
|
lstTmp_Location = CalculateLocByStegy(ref lstDevice, lstCanOutL, lstStrate, out deviceCode);
|
if (lstTmp_Location.Count > 0)
|
{
|
at_l_Entity = lstTmp_Location[0];
|
#region 锁定待出库货位
|
if (at_l_Entity != null)
|
{
|
if (model.lockLocation)
|
{
|
result = CreateDAL<TN_WM_LOCATION_EXTDAL>().UpdateLocationState(at_l_Entity.locationCode, Constants.Location_State_OutLock, "出库", null);
|
if (result != null)
|
{
|
if (result.Success && result.Row > 0)
|
{
|
outResult.Success = true;
|
outResult.Msg = "";
|
outResult.locationCode = at_l_Entity.locationCode;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.locationCode).FirstOrDefault().trayCode;
|
outResult.areaCode = item.areaCode;
|
outResult.isControlQty = isControlQty;
|
outResult.isControlInv = isControlInv;
|
break;
|
}
|
|
}
|
}
|
else
|
{
|
outResult.Success = true;
|
outResult.Msg = "";
|
outResult.locationCode = at_l_Entity.locationCode;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.locationCode).FirstOrDefault().trayCode;
|
outResult.areaCode = item.areaCode;
|
outResult.isControlQty = isControlQty;
|
outResult.isControlInv = isControlInv;
|
break;
|
}
|
}
|
#endregion
|
break;
|
}
|
}
|
#endregion
|
}
|
}
|
else
|
{
|
#region 满托盘出库
|
if (model.projectCode == "ys001")
|
{
|
#region 宇寿满托盘出库
|
// needOutWeight = autoBomE.CN_F_NW * model.itemQty;
|
needOutWeight = model.itemQty;
|
lstCanOutL = CreateDAL<Out_AlgorDAL>().GetAssignFlatItemQtyYS(model.itemCode, model.lotNo, item.areaCode);
|
lstTrueLocation = CreateDAL<TN_WMS_LOCATIONDAL>().GetLocationByLocationCode(lstCanOutL.Select(o => o.locationCode).ToList());
|
lstCanOutL = lstCanOutL.Join(lstTrueLocation, u => u.locationCode, d => d.CN_S_LOCATION_CODE, (u, d) => new { u, d }).Select(o => new outAssignLocation
|
{
|
trayCode = o.u.trayCode,
|
locationCode = o.u.locationCode,
|
stockAreaCode = o.u.stockAreaCode,
|
useState = o.u.useState,
|
opTime = o.u.opTime,
|
productDate = o.u.productDate,
|
lotNo = o.u.lotNo,
|
CN_S_STOCK_CODE = o.d.CN_S_STOCK_CODE,
|
CN_S_ROADWAY = o.d.CN_S_ROADWAY,
|
CN_S_ROW = o.d.CN_S_ROW,
|
CN_S_COL = o.d.CN_S_COL,
|
CN_S_FLOOR = o.d.CN_S_FLOOR,
|
CN_S_LOCATION_STATE = o.d.CN_S_LOCATION_STATE,
|
needWeight = needOutWeight,
|
totalWeight = o.u.totalWeight
|
}).ToList();
|
|
List<TN_WM_LOCATIONCODE_EXT_Entity> locationInLock = CreateDAL<TN_WM_LOCATION_EXTDAL>().GetLockLocationByState(model.stockCode.Trim(), item.areaCode, null, Constants.Location_State_InLock);
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "locationInLock数据:" + JsonConvert.SerializeObject(locationInLock));
|
foreach (TN_WM_LOCATIONCODE_EXT_Entity lEntity in locationInLock)
|
{
|
lstCanOutL.RemoveAll(o => o.CN_S_ROW == lEntity.CN_S_ROW && o.CN_S_COL == lEntity.CN_S_COL);
|
}
|
List<TN_WM_LOCATIONCODE_EXT_Entity> locationCheckLock = CreateDAL<TN_WM_LOCATION_EXTDAL>().GetLockLocationByState(model.stockCode.Trim(), item.areaCode, null, Constants.Location_Check_Lock);
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "locationCheckLock数据:" + JsonConvert.SerializeObject(locationCheckLock));
|
foreach (TN_WM_LOCATIONCODE_EXT_Entity lEntity in locationCheckLock)
|
{
|
lstCanOutL.RemoveAll(o => o.CN_S_ROW == lEntity.CN_S_ROW && o.CN_S_COL == lEntity.CN_S_COL);
|
}
|
List<TN_WM_LOCATIONCODE_EXT_Entity> locationCarryLock = CreateDAL<TN_WM_LOCATION_EXTDAL>().GetLockLocationByState(model.stockCode.Trim(), item.areaCode, null, Constants.Location_Carry_Lock);
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "locationCarryLock数据:" + JsonConvert.SerializeObject(locationCarryLock));
|
foreach (TN_WM_LOCATIONCODE_EXT_Entity lEntity in locationCarryLock)
|
{
|
lstCanOutL.RemoveAll(o => o.CN_S_ROW == lEntity.CN_S_ROW && o.CN_S_COL == lEntity.CN_S_COL);
|
}
|
locationInLock = CreateDAL<TN_WM_LOCATION_EXTDAL>().GetLockLocationByState(model.stockCode.Trim(), item.areaCode, null, Constants.Location_State_OutLock);
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "locationOutLock数据:" + JsonConvert.SerializeObject(locationInLock));
|
foreach (TN_WM_LOCATIONCODE_EXT_Entity lEntity in locationInLock)
|
{
|
lstCanOutL.RemoveAll(o => o.CN_S_ROW == lEntity.CN_S_ROW && o.CN_S_COL == lEntity.CN_S_COL && int.Parse(o.CN_S_FLOOR) > int.Parse(lEntity.CN_S_FLOOR));
|
}
|
|
List<AutoBomLocationAbbreEntity> lstLocationItem = CreateDAL<TN_WM_LOCATION_EXTDAL>().GetLocationByItemCode("", item.areaCode);
|
foreach (outAssignLocation outL in lstCanOutL)
|
{
|
//计算出该物料需要移动多少托盘
|
outL.moveStep = lstLocationItem.Where(o => o.CN_S_ROW == outL.CN_S_ROW && o.CN_S_COL == outL.CN_S_COL && int.Parse(o.CN_S_FLOOR) > int.Parse(outL.CN_S_FLOOR)).Count();
|
}
|
#endregion
|
}
|
|
else if (model.projectCode == "tzlj")
|
{
|
#region 隆基满托盘出库
|
List<TN_WM_LOCATIONCODE_EXT_Entity> locationInLock = new List<TN_WM_LOCATIONCODE_EXT_Entity>();
|
List<TN_WM_LOCATIONCODE_EXT_Entity> locationOutLock = new List<TN_WM_LOCATIONCODE_EXT_Entity>();
|
if (lstStrategy.Select(o => o.CN_S_CODE).ToList().Contains("FirstInLastOutLj"))
|
{
|
lstCanOutL = CreateDAL<Out_AlgorDAL>().GetAssignFlatItemQty(model.itemCode, item.areaCode);
|
lstTrueLocation = CreateDAL<TN_WMS_LOCATIONDAL>().GetLocationByLocationCode(lstCanOutL.Select(o => o.locationCode).ToList());
|
lstCanOutL = lstCanOutL.Join(lstTrueLocation, u => u.locationCode, d => d.CN_S_LOCATION_CODE, (u, d) => new { u, d }).Select(o => new outAssignLocation
|
{
|
trayCode = o.u.trayCode,
|
locationCode = o.u.locationCode,
|
stockAreaCode = o.u.stockAreaCode,
|
useState = o.u.useState,
|
opTime = o.u.opTime,
|
productDate = o.u.productDate,
|
lotNo = o.u.lotNo,
|
CN_S_STOCK_CODE = o.d.CN_S_STOCK_CODE,
|
CN_S_ROADWAY = o.d.CN_S_ROADWAY,
|
CN_S_ROW = o.d.CN_S_ROW,
|
CN_S_COL = o.d.CN_S_COL,
|
CN_S_FLOOR = o.d.CN_S_FLOOR,
|
CN_S_LOCATION_STATE = o.d.CN_S_LOCATION_STATE
|
}).ToList();
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "lstCanOutL数据:" + JsonConvert.SerializeObject(lstCanOutL));
|
locationInLock = CreateDAL<TN_WM_LOCATION_EXTDAL>().GetLockLocationByState(model.stockCode.Trim(), item.areaCode, null, Constants.Location_State_InLock);
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "locationInLock数据:" + JsonConvert.SerializeObject(locationInLock));
|
//控制有入的不能出
|
foreach (TN_WM_LOCATIONCODE_EXT_Entity lEntity in locationInLock)
|
{
|
lstCanOutL.RemoveAll(o => o.CN_S_COL == lEntity.CN_S_COL);
|
}
|
locationOutLock = CreateDAL<TN_WM_LOCATION_EXTDAL>().GetLockLocationByState(model.stockCode.Trim(), item.areaCode, null, Constants.Location_State_OutLock);
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "locationOutLock数据:" + JsonConvert.SerializeObject(locationOutLock));
|
|
}
|
if (lstStrategy.Select(o => o.CN_S_CODE).ToList().Contains("AdjoinColNoTask"))
|
{
|
foreach (TN_WM_LOCATIONCODE_EXT_Entity lEntity in locationOutLock)
|
{
|
lstCanOutL.RemoveAll(o => int.Parse(o.CN_S_COL) == int.Parse(lEntity.CN_S_COL) + 1);
|
lstCanOutL.RemoveAll(o => int.Parse(o.CN_S_COL) == int.Parse(lEntity.CN_S_COL) - 1);
|
}
|
foreach (TN_WM_LOCATIONCODE_EXT_Entity lEntity in locationInLock)
|
{
|
lstCanOutL.RemoveAll(o => int.Parse(o.CN_S_COL) == int.Parse(lEntity.CN_S_COL) + 1);
|
lstCanOutL.RemoveAll(o => int.Parse(o.CN_S_COL) == int.Parse(lEntity.CN_S_COL) - 1);
|
}
|
}
|
if (lstStrategy.Select(o => o.CN_S_CODE).ToList().Contains("FirstInLastOutLj"))
|
{
|
List<string> lstSameItemRow = lstCanOutL.Select(o => o.CN_S_COL).Distinct().ToList();
|
List<rowTaskNT> lstRowTask = new List<rowTaskNT>();
|
foreach (string sRow in lstSameItemRow)
|
{
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "sRow数据:" + sRow.ToString());
|
rowTaskNT rowT = new rowTaskNT();
|
rowT.row = sRow;
|
rowT.taskNum = locationOutLock.Where(o => o.CN_S_COL == sRow).Count();
|
rowT.canOutLocation = lstCanOutL.Where(o => o.CN_S_COL == sRow).Count();
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "rowTaskNT数据:" + JsonConvert.SerializeObject(rowT));
|
if (rowT.canOutLocation > 0)
|
{
|
lstRowTask.Add(rowT);
|
}
|
}
|
Log.AlgorInfo("OutAssign-FlatAreaOutLocation", "lstRowTask数据:" + JsonConvert.SerializeObject(lstRowTask));
|
if (lstRowTask.Count > 0)
|
{
|
lstCanOutL = lstCanOutL.Where(a => a.CN_S_COL == lstRowTask.OrderBy(o => o.taskNum).ThenByDescending(b => b.canOutLocation).FirstOrDefault().row).ToList();
|
}
|
else
|
{
|
lstCanOutL.Clear();
|
}
|
|
}
|
else
|
{
|
lstCanOutL = CreateDAL<Out_AlgorDAL>().GetAssignFlatItemQty(model.itemCode, item.areaCode);
|
lstTrueLocation = CreateDAL<TN_WMS_LOCATIONDAL>().GetLocationByLocationCode(lstCanOutL.Select(o => o.locationCode).ToList());
|
lstCanOutL = lstCanOutL.Join(lstTrueLocation, u => u.locationCode, d => d.CN_S_LOCATION_CODE, (u, d) => new { u, d }).Select(o => new outAssignLocation
|
{
|
trayCode = o.u.trayCode,
|
locationCode = o.u.locationCode,
|
stockAreaCode = o.u.stockAreaCode,
|
useState = o.u.useState,
|
opTime = o.u.opTime,
|
productDate = o.u.productDate,
|
lotNo = o.u.lotNo,
|
CN_S_STOCK_CODE = o.d.CN_S_STOCK_CODE,
|
CN_S_ROADWAY = o.d.CN_S_ROADWAY,
|
CN_S_ROW = o.d.CN_S_ROW,
|
CN_S_COL = o.d.CN_S_COL,
|
CN_S_FLOOR = o.d.CN_S_FLOOR,
|
CN_S_LOCATION_STATE = o.d.CN_S_LOCATION_STATE
|
}).ToList();
|
}
|
#endregion
|
}
|
else
|
{
|
lstCanOutL = CreateDAL<Out_AlgorDAL>().GetAssignFlatItemQty(model.itemCode, item.areaCode);
|
lstTrueLocation = CreateDAL<TN_WMS_LOCATIONDAL>().GetLocationByLocationCode(lstCanOutL.Select(o => o.locationCode).ToList());
|
lstCanOutL = lstCanOutL.Join(lstTrueLocation, u => u.locationCode, d => d.CN_S_LOCATION_CODE, (u, d) => new { u, d }).Select(o => new outAssignLocation
|
{
|
trayCode = o.u.trayCode,
|
locationCode = o.u.locationCode,
|
stockAreaCode = o.u.stockAreaCode,
|
useState = o.u.useState,
|
opTime = o.u.opTime,
|
productDate = o.u.productDate,
|
lotNo = o.u.lotNo,
|
CN_S_STOCK_CODE = o.d.CN_S_STOCK_CODE,
|
CN_S_ROADWAY = o.d.CN_S_ROADWAY,
|
CN_S_ROW = o.d.CN_S_ROW,
|
CN_S_COL = o.d.CN_S_COL,
|
CN_S_FLOOR = o.d.CN_S_FLOOR,
|
CN_S_LOCATION_STATE = o.d.CN_S_LOCATION_STATE
|
}).ToList();
|
}
|
|
Log.AlgorInfo("OutAssign-GetAssignFlatItemQty结果", JsonConvert.SerializeObject(lstCanOutL));
|
if (lstCanOutL.Count > 0)
|
{
|
//获取该库区中可用货位的信息
|
Log.AlgorInfo("OutAssign-lstStrate", JsonConvert.SerializeObject(lstStrate));
|
lstTmp_Location = CalculateLocByStegy(ref lstDevice, lstCanOutL, lstStrate, out deviceCode);
|
if (lstTmp_Location.Count > 0)
|
{
|
at_l_Entity = lstTmp_Location[0];
|
#region 锁定待出库货位
|
if (at_l_Entity != null)
|
{
|
if (model.lockLocation)
|
{
|
result = CreateDAL<TN_WM_LOCATION_EXTDAL>().UpdateLocationState(at_l_Entity.locationCode, Constants.Location_State_OutLock, "出库", null);
|
if (result != null)
|
{
|
if (result.Success && result.Row > 0)
|
{
|
outResult.Success = true;
|
if (model.projectCode == "ys001")
|
{
|
if (at_l_Entity.needWeight > at_l_Entity.totalWeight)
|
{
|
int itemQty = Decimal.ToInt32(Math.Round(at_l_Entity.totalWeight, 0));
|
outResult.Msg = "该托盘大约有该物料" + itemQty.ToString() + autoBomE.CN_S_MEASURE_UNIT + ",不满足出库数量要求,还差" + Decimal.ToInt32(model.itemQty - itemQty).ToString() + autoBomE.CN_S_MEASURE_UNIT;
|
}
|
else
|
{
|
outResult.Msg = "";
|
}
|
|
}
|
else if (model.projectCode == "ntsd")
|
{
|
if (at_l_Entity.needQty > at_l_Entity.totalQty)
|
{
|
outResult.Msg = "该托盘有该物料" + at_l_Entity.totalQty.ToString() + ",不满足出库数量要求,还差" + Decimal.ToInt32(at_l_Entity.needQty - at_l_Entity.totalQty).ToString();
|
}
|
else
|
{
|
outResult.Msg = "";
|
}
|
|
}
|
outResult.locationCode = at_l_Entity.locationCode;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.locationCode).FirstOrDefault().trayCode;
|
outResult.areaCode = item.areaCode;
|
outResult.isControlQty = isControlQty;
|
outResult.isControlInv = isControlInv;
|
break;
|
}
|
|
}
|
}
|
else
|
{
|
outResult.Success = true;
|
if (model.projectCode == "ys001")
|
{
|
if (at_l_Entity.needWeight > at_l_Entity.totalWeight)
|
{
|
int itemQty = Decimal.ToInt32(at_l_Entity.totalWeight);
|
outResult.Msg = "该托盘大约有该物料" + itemQty.ToString() + autoBomE.CN_S_MEASURE_UNIT + ",不满足出库数量要求,还差" + Decimal.ToInt32(model.itemQty - itemQty).ToString() + autoBomE.CN_S_MEASURE_UNIT;
|
}
|
else
|
{
|
outResult.Msg = "";
|
}
|
|
|
}
|
else if (model.projectCode == "ntsd")
|
{
|
if (at_l_Entity.needQty > at_l_Entity.totalQty)
|
{
|
outResult.Msg = "该托盘有该物料" + at_l_Entity.totalQty.ToString() + ",不满足出库数量要求,还差" + Decimal.ToInt32(at_l_Entity.needQty - at_l_Entity.totalQty).ToString();
|
}
|
else
|
{
|
outResult.Msg = "";
|
}
|
|
}
|
else
|
{
|
outResult.Msg = "";
|
}
|
outResult.locationCode = at_l_Entity.locationCode;
|
outResult.trayCode = lstCanOutL.Where(o => o.locationCode == at_l_Entity.locationCode).FirstOrDefault().trayCode;
|
outResult.areaCode = item.areaCode;
|
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<outAssignLocation> CalculateLocByStegy(ref List<Device> lstDevice, List<outAssignLocation> lstLocation, List<string> lstStrate, out string deviceCode)
|
{
|
List<outAssignLocation> lstFilterLoc = lstLocation;
|
deviceCode = string.Empty;
|
AlgorTacticsCommon Trctics = new AlgorTacticsCommon();
|
foreach (string stegy in lstStrate)
|
{
|
//逐个策略进行计算
|
switch (stegy)
|
{
|
case "EquipmentBalance": //设备均衡
|
lstFilterLoc = Trctics.EquipmentBalanceOut(lstDevice, lstFilterLoc, out deviceCode);
|
break;
|
case "RoadWayBalance": //巷道均衡
|
lstFilterLoc = Trctics.RoadWayBalanceOut(lstFilterLoc); ;
|
break;
|
case "NearbyBalance": //就近原则
|
lstFilterLoc = Trctics.NearbyBalanceOut(lstFilterLoc); ;
|
break;
|
case "ProductTimeOutFirst": //生产日期早先出
|
lstFilterLoc = lstFilterLoc.OrderBy(o => o.productDate).ToList();
|
lstFilterLoc = lstFilterLoc.Where(o => o.productDate == lstFilterLoc.FirstOrDefault().productDate).ToList();
|
break;
|
case "InStockTimeOutFirst": //入库时间早先出
|
lstFilterLoc = lstFilterLoc.OrderBy(o => o.opTime).ToList();
|
lstFilterLoc = lstFilterLoc.Where(o => o.opTime == lstFilterLoc.FirstOrDefault().opTime).ToList();
|
break;
|
case "SatisfyWeightFirst": //满足重量托盘先出
|
lstFilterLoc = lstFilterLoc.OrderByDescending(o => o.totalWeight).ToList();
|
if (lstFilterLoc[0].totalWeight >= lstFilterLoc[0].needWeight)
|
{
|
lstFilterLoc = lstFilterLoc.Where(o => o.totalWeight >= lstFilterLoc[0].needWeight).ToList();
|
}
|
else
|
{
|
lstFilterLoc = lstFilterLoc.Where(o => o.totalWeight == lstFilterLoc[0].totalWeight).ToList();
|
}
|
break;
|
case "MinMoveTray": //移动托盘小列先出
|
lstFilterLoc = lstFilterLoc.OrderBy(o => o.moveStep).ToList();
|
lstFilterLoc = lstFilterLoc.Where(o => o.moveStep == lstFilterLoc[0].moveStep).ToList();
|
break;
|
case "FirstInLastOut": //先进后出
|
Log.AlgorInfo("OutAssign-CalculateLocByStegy", "FirstInLastOut");
|
if (lstStrate.Contains("OutBigToSmall"))
|
{
|
Log.AlgorInfo("OutAssign-OutBigToSmall", "OutBigToSmall");
|
lstFilterLoc = lstFilterLoc.OrderBy(o => int.Parse(o.CN_S_ROW)).ThenByDescending(o => int.Parse(o.CN_S_COL)).ThenByDescending(b => int.Parse(b.CN_S_FLOOR)).ToList();
|
}
|
else if (lstStrate.Contains("OutSmallToBig"))
|
{
|
Log.AlgorInfo("OutAssign-OutSmallToBig", "OutSmallToBig");
|
lstFilterLoc = lstFilterLoc.OrderBy(o => int.Parse(o.CN_S_ROW)).ThenBy(o => int.Parse(o.CN_S_COL)).ThenByDescending(b => int.Parse(b.CN_S_FLOOR)).ToList();
|
}
|
else
|
{
|
lstFilterLoc = lstFilterLoc.OrderByDescending(o => int.Parse(o.CN_S_COL)).ThenBy(b => int.Parse(b.CN_S_FLOOR)).ToList();
|
}
|
Log.AlgorInfo("OutAssign-lstFilterLoc", JsonConvert.SerializeObject(lstFilterLoc));
|
lstFilterLoc = lstFilterLoc.Where(o => o.CN_S_COL == lstFilterLoc.FirstOrDefault().CN_S_COL && o.CN_S_FLOOR == lstFilterLoc.FirstOrDefault().CN_S_FLOOR).ToList();
|
break;
|
case "FirstInLastOutLj": //先进后出
|
Log.AlgorInfo("OutAssign-CalculateLocByStegy", "FirstInLastOut");
|
if (lstStrate.Contains("OutBigToSmall"))
|
{
|
Log.AlgorInfo("OutAssign-OutBigToSmall", "OutBigToSmall");
|
lstFilterLoc = lstFilterLoc.OrderBy(o => int.Parse(o.CN_S_ROW)).ThenByDescending(o => int.Parse(o.CN_S_COL)).ThenByDescending(b => int.Parse(b.CN_S_FLOOR)).ToList();
|
}
|
else if (lstStrate.Contains("OutSmallToBig"))
|
{
|
Log.AlgorInfo("OutAssign-OutSmallToBig", "OutSmallToBig");
|
lstFilterLoc = lstFilterLoc.OrderBy(o => int.Parse(o.CN_S_ROW)).ThenBy(o => int.Parse(o.CN_S_COL)).ThenByDescending(b => int.Parse(b.CN_S_FLOOR)).ToList();
|
}
|
else
|
{
|
lstFilterLoc = lstFilterLoc.OrderByDescending(o => o.CN_S_ROW).ThenBy(b => int.Parse(b.CN_S_FLOOR)).ToList();
|
}
|
Log.AlgorInfo("OutAssign-lstFilterLoc", JsonConvert.SerializeObject(lstFilterLoc));
|
lstFilterLoc = lstFilterLoc.Where(o => o.CN_S_ROW == lstFilterLoc.FirstOrDefault().CN_S_ROW && o.CN_S_FLOOR == lstFilterLoc.FirstOrDefault().CN_S_FLOOR).ToList();
|
break;
|
|
}
|
|
}
|
return lstFilterLoc;
|
}
|
/// <summary>
|
/// 根据入库策略筛选符合条件的货位
|
/// </summary>
|
/// <param name="lstDevice"></param>
|
/// <param name="lstLocation"></param>
|
/// <param name="lstStrate"></param>
|
/// <param name="deviceCode"></param>
|
/// <returns></returns>
|
public List<outAssignLocation> CalculateCanOutByStegy(List<outAssignLocation> lstCanOutL, List<string> lstStrate, decimal needOutWeight)
|
{
|
List<outAssignLocation> lstFilterLoc = lstCanOutL;
|
foreach (string stegy in lstStrate)
|
{
|
//逐个策略进行计算
|
switch (stegy)
|
{
|
case "ProductTimeOutFirst": //生产日期早先出
|
lstFilterLoc = lstFilterLoc.OrderBy(o => o.productDate).ToList();
|
lstFilterLoc = lstFilterLoc.Where(o => o.productDate == lstFilterLoc.FirstOrDefault().productDate).ToList();
|
break;
|
case "InStockTimeOutFirst": //入库时间早先出
|
lstFilterLoc = lstFilterLoc.OrderBy(o => o.opTime).ToList();
|
lstFilterLoc = lstFilterLoc.Where(o => o.opTime == lstFilterLoc.FirstOrDefault().opTime).ToList();
|
break;
|
|
}
|
|
}
|
return lstFilterLoc;
|
}
|
|
#endregion
|
|
}
|
}
|