using System;
|
using System.Collections.Generic;
|
using System.IO;
|
using System.Linq;
|
using Model.ModelDto.SysDto;
|
using SqlSugar;
|
using WMS.DAL;
|
using WMS.Entity.BllAsnEntity;
|
using WMS.Entity.Context;
|
using WMS.Entity.DataEntity;
|
using WMS.Entity.LogEntity;
|
using WMS.Entity.SysEntity;
|
|
namespace WMS.BLL.Logic
|
{
|
/// <summary>
|
/// 分配库位
|
/// </summary>
|
public class AllotLocation
|
{
|
|
|
/// <summary>
|
/// 获取密集库合适的巷道(适用项目:JC34)
|
/// </summary>
|
/// <param name="roadways">巷道集合</param>
|
/// <param name="areaList">区域集合</param>
|
/// <param name="lotNo">批次号</param>
|
/// <returns></returns>
|
public string GetMiJiSuiTableRoad(string house, List<string> roadways, List<string> areaList, string sku, string lotNo = "")
|
{
|
|
var db = DataContext.Db;
|
|
var dataStock = db.Queryable<DataStockDetail>().Where(m => m.IsDel == "0" && m.WareHouseNo == house && m.SkuNo == sku);
|
if (!string.IsNullOrWhiteSpace(lotNo))
|
{
|
dataStock = dataStock.Where(m => m.LotNo == lotNo);
|
}
|
//库存查找相同物料/批次的巷道
|
var yiYouRoad = dataStock.GroupBy(m => m.RoadwayNo).Select(m => m.RoadwayNo).OrderBy(m => m).ToList();
|
foreach (var l in yiYouRoad)
|
{
|
// 判断当前巷道(组)是否有空余储位
|
|
var locateCount = db.Queryable<SysStorageLocat>().Count(m => m.Status == "0" && m.Flag == "0" && areaList.Contains(m.AreaNo) && m.RoadwayNo == l);
|
|
var bindNum = db.Queryable<LogTask>().Where(m => m.IsDel == "0" && (m.Status == "0" || m.Status == "1") && m.EndRoadway == l)
|
.GroupBy(m => m.PalletNo).Select(m => m.PalletNo).Count();
|
if (locateCount - bindNum > 0)
|
{
|
return l;
|
}
|
|
}
|
//获取库存内已有物料的巷道
|
var dataStockRoad = db.Queryable<DataStockDetail>().Where(m => m.IsDel == "0" && m.WareHouseNo == house).GroupBy(m => m.RoadwayNo).OrderBy(m => m.RoadwayNo).Select(m => m.RoadwayNo).ToList();
|
//排除掉已有物料的巷道
|
|
roadways = roadways.Where(m => !dataStockRoad.Contains(m)).ToList();
|
foreach (var l in roadways)
|
{
|
var bl = true;
|
//判断当前巷道(组)是否有任务
|
var taskList = db.Queryable<LogTask>().Where(m => m.IsDel == "0" && m.EndRoadway == l && (m.Status == "0" || m.Status == "1")).ToList();
|
if (taskList.Count > 0)
|
{
|
//判断物料批次是否和当前一致
|
foreach (var item in taskList)
|
{
|
var palletBind = db.Queryable<BllPalletUpShelf>().First(m => m.IsDel == "0" && m.TaskNo == item.TaskNo);
|
if (palletBind != null)
|
{
|
if (palletBind.SkuNo !=sku || palletBind.LotNo != lotNo)
|
{
|
bl = false;
|
continue;
|
}
|
|
}
|
}
|
if (bl)
|
{
|
// 判断当前巷道(组)是否有空余储位
|
|
var locateCount = db.Queryable<SysStorageLocat>().Count(m => m.Status == "0" && m.Flag == "0" && areaList.Contains(m.AreaNo) && m.RoadwayNo == l);
|
|
var bindNum = db.Queryable<LogTask>().Where(m => m.IsDel == "0" && (m.Status == "0" || m.Status == "1") && m.EndRoadway == l)
|
.GroupBy(m => m.PalletNo).Select(m => m.PalletNo).Count();
|
if (locateCount - bindNum > 0)
|
{
|
return l;
|
}
|
}
|
}
|
}
|
return "";
|
|
}
|
|
/// <summary>
|
/// 获取密集库合适的储位(适用项目:JC34)
|
/// </summary>
|
/// <param name="roadways">巷道集合</param>
|
/// <param name="areaList">区域集合</param>
|
/// <param name="lotNo">批次号</param>
|
/// <returns></returns>
|
public SysStorageLocat GetMiJiSuiTableLocate(SysStorageRoadway roadway, List<string> areaList, string sku, string lotNo = "")
|
{
|
|
var db = DataContext.Db;
|
|
// 判断当前巷道(组)是否有空余储位
|
var locateList = db.Queryable<SysStorageLocat>().Where(m => m.IsDel == "0" && m.RoadwayNo == roadway.RoadwayNo && areaList.Contains(m.AreaNo)).ToList();
|
if (locateList.Count(m => m.Status == "0") > 0)
|
{
|
var bl = GetLocateASCOrDesc(roadway.RoadwayNo);
|
|
var locate = locateList.OrderBy(m => m.LocatNo).First();
|
|
if (bl)
|
{
|
locate = locateList.OrderByDescending(m => m.LocatNo).First();
|
}
|
var bl2 = MiJiLocateIsOk(locate, bl); //验证储位是否可入库方法
|
if (bl2)
|
{
|
return locate;
|
}
|
}
|
|
|
return null;
|
|
}
|
|
/// <summary>
|
/// 获取储位的排列顺序
|
/// </summary>
|
/// <param name="roadStr"></param>
|
/// <returns>true:desc倒序 false:asc正序</returns>
|
public bool GetLocateASCOrDesc(string roadStr)
|
{
|
var db = DataContext.Db;
|
|
var locate = db.Queryable<SysStorageLocat>().First(m => m.IsDel == "0" && m.RoadwayNo == roadStr);
|
var a = locate.LocatNo.Substring(2,2);//储位列
|
var b = locate.AisleOne.Substring(2, 2);//通道口列
|
return int.Parse(a) < int.Parse(b);
|
}
|
|
/// <summary>
|
/// 验证储位是否可入库
|
/// </summary>
|
/// <param name="locate"></param>
|
/// <returns></returns>
|
private bool MiJiLocateIsOk(SysStorageLocat locate,bool bl)
|
{
|
|
var db = DataContext.Db;
|
var a = int.Parse(locate.LocatNo.Substring(2, 2));//储位列
|
var b = int.Parse(locate.AisleOne.Substring(2, 2));//通道口列
|
var str1 = new List<string>() { "0", "3", "5" };
|
var str2 = new List<string>() { "1", "2", "4" };
|
var locatList1 = db.Queryable<SysStorageLocat>().Where(m => m.IsDel == "0" && m.RoadwayNo == locate.RoadwayNo && m.Column < a).ToList();
|
var locatList2 = db.Queryable<SysStorageLocat>().Where(m => m.IsDel == "0" && m.RoadwayNo == locate.RoadwayNo && m.Column > a).ToList();
|
if (bl)
|
{
|
if (locatList1.Count(m => str1.Contains(m.Status)) > 0)
|
{
|
return false;
|
}
|
if (locatList2.Count(m => str2.Contains(m.Status)) > 0)
|
{
|
return false;
|
}
|
}
|
else
|
{
|
if (locatList1.Count(m => str2.Contains(m.Status)) > 0)
|
{
|
return false;
|
}
|
if (locatList2.Count(m => str1.Contains(m.Status)) > 0)
|
{
|
return false;
|
}
|
}
|
return true;
|
|
}
|
|
/// <summary>
|
/// 获取合适的库位
|
/// </summary>
|
/// <param name="houseNo">仓库号</param>
|
/// <param name="areaList">区域集合</param>
|
/// <param name="roadwayNo">巷道号(可空)</param>
|
/// <returns></returns>
|
public SysStorageLocat GetSuiTableLocate(string houseNo, List<string> areaList,string roadwayNo = "")
|
{
|
try
|
{
|
var db = DataContext.Db;
|
/* 1.先判断仓库(立库或者平库)
|
* 2.如果是立库 再判断是否指定巷道号
|
*/
|
var house = db.Queryable<SysWareHouse>().First(m => m.WareHouseNo == houseNo);
|
if (house == null)
|
{
|
throw new Exception($"未查询到{houseNo}仓库信息");
|
}
|
|
var roadList = db.Queryable<SysStorageLocat>().Where(m => m.WareHouseNo == houseNo && areaList.Contains(m.AreaNo) )
|
.GroupBy(m=>m.RoadwayNo).Select(m=>m.RoadwayNo).ToList();
|
|
//数据字典(获取字典中仓库类型)
|
var dic = db.Queryable<SysDictionary>().First(m => m.Id.ToString() == house.Type);
|
switch (dic.DictName)
|
{
|
//指定巷道
|
case "立体库" when !string.IsNullOrWhiteSpace(roadwayNo):
|
{
|
var roadwayList = new List<SysStorageRoadway>();
|
var roadway = db.Queryable<SysStorageRoadway>().First(m => m.RoadwayNo == roadwayNo);
|
if (roadway == null)
|
{
|
throw new Exception($"未查询到{roadwayNo}巷道信息");
|
}
|
|
if (!roadList.Contains(roadwayNo))
|
{
|
throw new Exception("当前物料存放区域未在指定巷道中");
|
}
|
if (roadway.Status == "1")
|
{
|
throw new Exception($"{roadwayNo}巷道已停用");
|
}
|
|
//查询该巷道并且标志为正常的的储位
|
roadwayList.Add(roadway);
|
var locate = GetLocateByRoadways(roadwayList,areaList,true,houseNo);
|
if (locate == null)
|
{
|
throw new Exception($"{roadwayNo}巷道没有合适的空储位");
|
}
|
return locate;
|
}
|
//立体库没有指定巷道(循环巷道根据优先级分配)
|
case "立体库" when string.IsNullOrWhiteSpace(roadwayNo):
|
{
|
var roadwayList = db.Queryable<SysStorageRoadway>().Where(m => m.WareHouseNo == houseNo && m.Status == "0" && roadList.Contains(m.RoadwayNo)).OrderBy(m => new { m.Priority, m.RoadwayNo }).ToList();
|
|
var locate = GetLocateByRoadways(roadwayList,areaList,false, houseNo);
|
if (locate == null)
|
{
|
throw new Exception($"{houseNo}仓库已启用的巷道中没有合适的空储位");
|
}
|
return locate;
|
}
|
//平库 该代码块目前是错误的逻辑、后期有库位信息了改
|
case "平库":
|
{
|
//查询该巷道并且标志为正常的的储位
|
var locates = db.Queryable<SysStorageLocat>()
|
.Where(m => m.WareHouseNo == houseNo && m.Flag == "0" && m.Status == "0")
|
.OrderBy(m => new { m.Layer, m.Column, m.Row }).ToList();
|
return locates.First();
|
}
|
//没有仓库类型
|
default:
|
throw new Exception($"未查询到{houseNo}仓库类型信息,无法为其分配储位");
|
}
|
}
|
catch (Exception e)
|
{
|
throw new Exception(e.Message);
|
}
|
}
|
|
/// <summary>
|
/// 获取合适空储位信息(根据巷道集合判断)
|
/// </summary>
|
/// <param name="roadways">巷道集合</param>
|
/// <param name="areaList">区域集合</param>
|
/// <param name="isRoadway">是否指定巷道</param>
|
/// <returns></returns>
|
private SysStorageLocat GetLocateByRoadways(List<SysStorageRoadway> roadways,List<string> areaList,bool isRoadway = false ,string houseNo = "W01")
|
{
|
try
|
{
|
var db = DataContext.Db;
|
#region 入库分配规则
|
|
var funSet = db.Queryable<SysFunSetting>().First(m => m.IsDel == "0" && m.FunSetName == "储位分配上下" && m.IsEnable == "NO");
|
var funSet2 = db.Queryable<SysFunSetting>().First(m => m.IsDel == "0" && m.FunSetName == "储位分配左右" && m.IsEnable == "NO");
|
var funSet3 = db.Queryable<SysFunSetting>().First(m => m.IsDel == "0" && m.FunSetName == "储位跳巷分配" && m.IsEnable == "NO");
|
|
var topOrBom = 1; // 储位分配上下 0 上 1 下
|
var leftOrRight = 0; // 储位分配上下 0 左 1 右
|
var laneAllot = 0; //储位跳巷分配 0:跳着分配(一个一个分配)1:巷道按照优先级分配,同优先级顺序分配(一个巷道满了再分配下一个的巷道储位)
|
if (funSet != null)
|
{
|
switch (funSet.SetValue)
|
{
|
case "Top":
|
topOrBom = 0;//立库储位分配由上往下分配
|
break;
|
case "Bottom":
|
topOrBom = 1;//立库储位分配由下往上分配
|
break;
|
default:
|
topOrBom = 1;// 默认:由下往上
|
break;
|
}
|
}
|
if (funSet2 != null)
|
{
|
switch (funSet2.SetValue)
|
{
|
case "Left":
|
leftOrRight = 0;//立库储位分配由上往下分配
|
break;
|
case "Right":
|
leftOrRight = 1;//立库储位分配由下往上分配
|
break;
|
default:
|
leftOrRight = 1;// 默认:由下往上
|
break;
|
}
|
}
|
if (funSet3 != null)
|
{
|
switch (funSet3.SetValue)
|
{
|
case "JumpLaneAllot":
|
laneAllot = 0;//立库储位分配 巷道同优先级巷道跳着分配(一个一个分配)
|
break;
|
case "RankLaneAllot":
|
laneAllot = 1;//立库储位分配 巷道按照优先级分配,同优先级顺序分配(一个巷道满了再分配下一个的巷道储位)
|
break;
|
default:
|
laneAllot = 1;// 默认 跳着分配
|
break;
|
}
|
}
|
#endregion
|
|
#region MyRegion
|
|
SysStorageLocat locate = null; // 储位信息
|
//SysStorageLocat log = db.Ado.SqlQuerySingle<SysStorageLocat>("select * from SysStorageLocat where LocatNo = (select Top(1) LocatNo from BllPalletBind order by CreateTime desc)"); //巷道最后一次使用记录
|
SysRoadwayUseLog log= db.Ado.SqlQuerySingle<SysRoadwayUseLog>($"select Top(1) * from SysRoadwayUseLog where IsDel=0 and WareHouseNo ='{houseNo}' order by CreateTime desc"); //巷道最后一次使用记录
|
|
if (laneAllot == 0)//跳巷道平均分配
|
{
|
//如果同级巷道有多条则查上次位置日志
|
if (roadways.Count > 1)
|
{
|
log = db.Queryable<SysRoadwayUseLog>().Where(m=>m.WareHouseNo == houseNo).OrderByDescending(l => l.Id).First();
|
}
|
//取各巷道所有排第一个合适位
|
foreach (var l in roadways)
|
{
|
if (!isRoadway)
|
{
|
//如果上次是当前巷道则跳出
|
if (log != null && l.RoadwayNo == log.RoadwayNo)
|
{
|
continue;
|
}
|
}
|
var list = new List<string>();
|
var count = 0;
|
do
|
{
|
locate = GetLocateByRoadway(l.RoadwayNo, topOrBom, leftOrRight, areaList, list, ref count);
|
if (locate != null)
|
{
|
list.Add(locate.LocatNo);
|
var isOk = LocateIsOk(locate);
|
if (!isOk)
|
{
|
locate = null;
|
}
|
if (isOk)
|
{
|
break;
|
}
|
}
|
|
|
} while (count != 0 && locate == null);//当查询储位数量不等0 并且储位为空时,再次循环巷道、区域查找储位
|
|
}
|
//如果跳巷道并且未找到合适空储位,则跳到最后一次使用的巷道查询
|
if (!isRoadway)
|
{
|
if (locate == null)
|
{
|
if (log != null)
|
{
|
var list = new List<string>();
|
var count = 0;
|
do
|
{
|
locate = GetLocateByRoadway(log.RoadwayNo, topOrBom, leftOrRight, areaList, list, ref count);
|
if (locate != null)
|
{
|
list.Add(locate.LocatNo);
|
var isOk = LocateIsOk(locate);
|
if (!isOk)
|
{
|
locate = null;
|
}
|
}
|
|
|
} while (count != 0 && locate == null);//当查询储位数量不等0 并且储位为空时,再次循环巷道、区域查找储位
|
|
|
}
|
}
|
}
|
}
|
else//按照巷道优先级分配
|
{
|
foreach (var item in roadways)
|
{
|
var list = new List<string>();
|
var count = 0;
|
do
|
{
|
locate = GetLocateByRoadway(item.RoadwayNo, topOrBom, leftOrRight, areaList, list, ref count);
|
if (locate != null)
|
{
|
list.Add(locate.LocatNo);
|
var isOk = LocateIsOk(locate);
|
if (!isOk)
|
{
|
locate = null;
|
}
|
if (isOk)
|
{
|
break;
|
}
|
}
|
|
|
} while (count != 0 && locate == null);//当查询储位数量不等0 并且储位为空时,再次循环巷道、区域查找储位
|
|
}
|
}
|
|
#endregion
|
|
return locate;
|
}
|
catch (Exception e)
|
{
|
throw new Exception(e.Message);
|
}
|
}
|
|
/// <summary>
|
/// 取当前巷最优位置
|
/// </summary>
|
/// <param name="roadwayNo">巷道号</param>
|
/// <param name="topOrBom">储位分配上下 0 上 1 下</param>
|
/// <param name="leftOrRight">储位分配上下 0 左 1 右</param>
|
/// <param name="areaList">区域集合</param>
|
/// <param name="locateNoStr">排除的储位集合</param>
|
/// <returns></returns>
|
private SysStorageLocat GetLocateByRoadway(string roadwayNo, int topOrBom, int leftOrRight,List<string> areaList,List<string> locateNoStr,ref int count)
|
{
|
var db = DataContext.Db;
|
var str = "";
|
foreach (var item in locateNoStr)
|
{
|
if (str == "")
|
{
|
str += item;
|
}
|
str += "," + item;
|
}
|
if (str == "")
|
{
|
str = "''";
|
}
|
//查询该巷道并且标志为正常的的储位
|
SysStorageLocat data;
|
|
foreach (var area in areaList)
|
{
|
var sql = $@"select * from SysStorageLocat where IsDel = 0 and Flag = 0 and [Status] = 0 and RoadwayNo = '{roadwayNo}' and AreaNo = '{area}' and LocatNo not in({str}) ";
|
sql += "order by ";
|
sql += topOrBom == 0 ? "Layer desc, " : "Layer, ";
|
sql += leftOrRight == 0 ? "[Column], " : "[Column] desc, ";
|
sql += " Row desc, Depth desc; ";
|
|
|
var locateList = db.Ado.SqlQuery<SysStorageLocat>(sql);
|
data = locateList.FirstOrDefault();
|
count = locateList.Count;
|
if (data != null)
|
{
|
return data;
|
}
|
}
|
|
return null;
|
|
|
|
}
|
|
/// <summary>
|
/// 验证储位是否可入库
|
/// </summary>
|
/// <param name="locate"></param>
|
/// <returns></returns>
|
private bool LocateIsOk(SysStorageLocat locate)
|
{
|
try
|
{
|
Common common = new Common();
|
if (locate.Depth == "01")
|
{
|
|
var locate2 = common.GetLocateNoDepth2("W01", locate.LocatNo);
|
var str = new List<string>() { "0", "3", "5" };
|
|
if (str.Contains(locate2.Status))
|
{
|
return false;
|
}
|
return true;
|
}
|
else
|
{
|
var locate2 = common.GetLocateNoDepth1("W01", locate.LocatNo);
|
var str = new List<string>() { "1", "2", "4" };
|
|
if (str.Contains(locate2.Status))
|
{
|
return false;
|
}
|
return true;
|
|
}
|
}
|
catch
|
{
|
return false;
|
}
|
}
|
|
/// <summary>
|
/// 获取平库储位 JC23四楼专用
|
/// </summary>
|
/// <param name="area">区域</param>
|
/// <param name="soNo">出库单据号</param>
|
/// <param name="sku">物料</param>
|
/// <returns></returns>
|
public SysStorageLocat GetPingLocate(string soNo,string sku)
|
{
|
try
|
{
|
var db = DataContext.Db;
|
var house = "W02";
|
var area = new List<string>()
|
{
|
"B01","B02"
|
};
|
//四楼所有储位集合
|
var locateList = db.Queryable<SysStorageLocat>().Where(m=>m.IsDel == "0" && m.WareHouseNo == house && area.Contains(m.AreaNo)).ToList();
|
//储位Str集合
|
var locateStr = locateList.Select(m => m.LocatNo).ToList();
|
//库存在四楼平库的托盘
|
var stockDetail = db.Queryable<DataStockDetail>().Where(m => m.IsDel == "0" && locateStr.Contains(m.LocatNo)).ToList();
|
|
var detailLocate = stockDetail.Where(m=>m.SONo == soNo && m.SkuNo == sku).Select(m=>m.AreaNo).Distinct().ToList();
|
if (detailLocate.Count != 0)
|
{
|
//判断是否有合适的巷道储位
|
foreach (var item in detailLocate)
|
{
|
var locateList2 = locateList.Where(m => m.AreaNo == item).ToList();
|
if (locateList2.Count(m=>m.Status == "0" && m.Flag == "0") == 0)
|
{
|
continue;
|
}
|
var locate = locateList2.Where(m => m.Flag == "0" && m.Status == "0").OrderBy(m => new { m.Layer, m.Column, m.Row }).First();
|
return locate;
|
}
|
}
|
//查找新的巷道出库
|
foreach (var item2 in area)
|
{
|
var locateList2 = locateList.Where(m => m.AreaNo == item2).ToList();
|
if (locateList2.Count(m => m.Status != "0" && m.Flag == "0") > 0)
|
{
|
continue;
|
}
|
var locate = locateList2.Where(m => m.Flag == "0" && m.Status == "0").OrderBy(m => new { m.Layer, m.Column, m.Row }).First();
|
return locate;
|
}
|
return null;
|
}
|
catch (Exception e)
|
{
|
throw new Exception(e.Message);
|
}
|
}
|
|
|
}
|
}
|