using HH.WCS.Mobox3.YNJT_BZP.api;
|
using HH.WCS.Mobox3.YNJT_BZP.dispatch;
|
using HH.WCS.Mobox3.YNJT_BZP.models;
|
using HH.WCS.Mobox3.YNJT_BZP.models.other;
|
using HH.WCS.Mobox3.YNJT_BZP.util;
|
using Newtonsoft.Json;
|
using NLog.Fluent;
|
using SqlSugar;
|
using System;
|
using System.Collections;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Reflection;
|
using System.Runtime.Remoting.Messaging;
|
using System.Text;
|
using System.Threading.Tasks;
|
using static HH.WCS.Mobox3.YNJT_BZP.api.ApiModel;
|
using static HH.WCS.Mobox3.YNJT_BZP.api.WmsController;
|
|
namespace HH.WCS.Mobox3.YNJT_BZP.wms {
|
/// <summary>
|
/// wms管到作业
|
/// </summary>
|
internal class WMSHelper {
|
internal static string GenerateTaskNo() {
|
var id = SYSHelper.GetSerialNumber("作业号", "OP");
|
var date = DateTime.Now.ToString("yyMMdd");
|
return $"OP{date}{id.ToString().PadLeft(4, '0')}";
|
}
|
internal static string GenerateSortingNo() {
|
var id = SYSHelper.GetSerialNumber("分拣单", "SO");
|
var date = DateTime.Now.ToString("yyMMdd");
|
return $"SO{date}{id.ToString().PadLeft(4, '0')}";
|
}
|
internal static List<WMSTask> GetOperationListByState(string state) {
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<WMSTask>().Where(a => a.S_B_STATE == state).ToList();
|
}
|
internal static List<WMSTask> GetOperationListByState(int state) {
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<WMSTask>().Where(a => a.N_B_STATE == state).ToList();
|
}
|
internal static List<WMSTask> GetWaitingOperationList() {
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<WMSTask>().Where(a => a.N_B_STATE == 0 || a.N_B_STATE == 3).ToList();
|
}
|
internal static PutawayOrder GetPutawayOrder(string no) {
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<PutawayOrder>().Where(a => a.S_NO == no).First();
|
}
|
internal static bool CreatePutawayOrder(PutawayOrder model) {
|
var db = new SqlHelper<object>().GetInstance();
|
var result = db.Insertable<PutawayOrder>(model).ExecuteCommand() > 0;
|
db.Insertable<PutawayDetail>(model.Details).ExecuteCommand();
|
return result;
|
}
|
|
internal static PutawayDetail GetPutawayOrderDetail(string no, string item_code) {
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<PutawayDetail>().Where(a => a.S_PUTAWAY_NO == no && a.S_ITEM_CODE == item_code).First();
|
}
|
internal static PutawayDetail GetPutawayOrderDetail(string item_code) {
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<PutawayDetail>().Where(a => a.S_ITEM_CODE == item_code && a.F_QTY - a.F_ACC_B_QTY > 0).OrderByDescending(a => a.T_CREATE).First();
|
}
|
|
internal static void UpdatePutawayOrderDetailQty(PutawayDetail model) {
|
var db = new SqlHelper<object>().GetInstance();
|
db.Updateable(model).UpdateColumns(it => new { it.F_ACC_B_QTY }).ExecuteCommand();
|
}
|
|
|
internal static ShippingOrder GetShippingOrder(string no) {
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<ShippingOrder>().Includes(a => a.Details).Where(a => a.S_NO == no).First();
|
}
|
internal static bool CreateShippingOrder(ShippingOrder model) {
|
var db = new SqlHelper<object>().GetInstance();
|
var result = db.Insertable<ShippingOrder>(model).ExecuteCommand() > 0;
|
db.Insertable<ShippingDetail>(model.Details).ExecuteCommand();
|
return result;
|
}
|
|
internal static bool CreateSortingOrder(List<string> list) {
|
var res = false;
|
//遍历获取发货单,然后判断库存,如果全都没库存,则不生成分拣单,如果有生成分拣单
|
//更新波次单,即使只有一个发货单也更新波次单
|
var db = new SqlHelper<object>().GetInstance();
|
var sortingOrderNo = "";
|
SortingOrder sortingOrder = null;
|
try {
|
db.BeginTran();
|
list.ForEach(a => {
|
var so = db.Queryable<ShippingOrder>().Includes(s => s.Details).Where(s => s.S_NO == a).First();
|
//判断库存,只有已经入库的才可以计算,码盘的不算,入库后出库途中的也要计算,码盘后默认叫待入库,入库后叫正常
|
//生成出库任务,只有托盘位置在立库才需要创建出库任务(先写死立库)
|
//只有全部分拣完成才允许回库(一个托盘可能对应多个分拣明细)
|
|
//查找仓库量表和库区量表,出库单需要定位仓库和库区了,出库定位物理库区就行,入库可能物料库区还要区分逻辑库区
|
|
//暂时只查仓库量表(量表如何重置,查找所有查找C_ENABLE=N的,判断如果在仓库中,改成Y,然后统计)
|
|
//生成分拣单时候增加仓库量表分配量,生成分拣单明细时候,增加库区量表分配量
|
if (so != null && so.Details.Count > 0) {
|
var fail = true;
|
for (int i = 0; i < so.Details.Count; i++) {
|
var whi = db.Queryable<WHInventory>().Where(w => w.S_ITEM_CODE == so.Details[i].S_ITEM_CODE).First();
|
if (whi != null && whi.F_QTY - whi.F_ALLOC_QTY > 0) {
|
//有货就出
|
float qty = whi.F_QTY - whi.F_ALLOC_QTY > so.Details[i].F_QTY ? so.Details[i].F_QTY : whi.F_QTY - whi.F_ALLOC_QTY;
|
fail = false;
|
//有可用库存,生成分拣单
|
if (sortingOrderNo == "") {
|
sortingOrderNo = GenerateSortingNo();
|
sortingOrder = new SortingOrder
|
{
|
S_NO = sortingOrderNo,
|
S_SHIPPING_NO = so.S_NO,
|
Composes = new List<SortingCompose>()
|
};
|
//创建分拣单
|
db.Insertable(sortingOrder).ExecuteCommand();
|
}
|
else {
|
//获取最新分拣单
|
sortingOrder = db.Queryable<SortingOrder>().Includes(s => s.Composes).Where(s => s.S_NO == sortingOrderNo).First();
|
//更新分拣单中的发货单单号
|
sortingOrder.S_SHIPPING_NO = sortingOrder.S_SHIPPING_NO + ";" + so.S_NO;
|
sortingOrder.T_MODIFY = DateTime.Now;
|
db.Updateable(sortingOrder).UpdateColumns(it => new { it.S_SHIPPING_NO, it.T_MODIFY }).ExecuteCommand();
|
}
|
//查询分拣单子表(正常情况还需要增加批次判断)
|
var soc = db.Queryable<SortingCompose>().Where(s => s.S_ITEM_CODE == so.Details[i].S_ITEM_CODE && s.S_SORTING_NO == sortingOrder.S_NO).First();
|
if (soc == null) {
|
soc = new SortingCompose
|
{
|
S_ITEM_CODE = so.Details[i].S_ITEM_CODE,
|
S_SORTING_NO = sortingOrder.S_NO,
|
F_QTY = qty,
|
N_ROW_NO = sortingOrder.Composes.Count() + 1,
|
S_BATCH_NO = so.Details[i].S_BATCH_NO
|
};
|
|
//创建分拣单子表
|
db.Insertable(soc).ExecuteCommand();
|
}
|
else {
|
soc.F_QTY += qty;
|
soc.T_MODIFY = DateTime.Now;
|
//更新分拣单子表
|
db.Updateable(soc).UpdateColumns(it => new { it.F_QTY, it.T_MODIFY }).ExecuteCommand();
|
}
|
//更新仓库量表分配量
|
whi.F_ALLOC_QTY += qty;
|
whi.T_MODIFY = DateTime.Now;
|
db.Updateable(whi).UpdateColumns(it => new { it.F_ALLOC_QTY, it.T_MODIFY }).ExecuteCommand();
|
//跟新发货单子表配货数量
|
so.Details[i].F_ACC_D_QTY += qty;
|
so.Details[i].T_MODIFY = DateTime.Now;
|
db.Updateable(so.Details[i]).UpdateColumns(it => new { it.F_ACC_D_QTY, it.T_MODIFY }).ExecuteCommand();
|
}
|
|
}
|
//更新发货单状态
|
so.N_B_STATE = fail ? 5 : 1;
|
if (fail) {
|
so.S_NOTE = "没有库存";
|
}
|
so.S_WAVE_CODE = sortingOrderNo;
|
so.T_MODIFY = DateTime.Now;
|
db.Updateable(so).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY, it.S_WAVE_CODE, it.S_NOTE }).ExecuteCommand();
|
|
}
|
|
|
//查找库区内托盘生成托盘明细(包括分拣中)怎么判断库内?查找货位绑定?还是托盘上加标识比较好,如果是整托出的,分拣确认后去掉分拣标识。
|
//1、只有码盘入库后的才需要加标识,分拣回的不用,分拣回的标识还在,没有变。写死码盘入的完成后加标识,整托分拣的去掉标识,防止后面重新码盘脏数据
|
//2、或者关联查询库内的,只给分拣出的加标识,每次分拣回再把标识清除了(如果不清除带标识的会很多,还不如全部加标识),整托的清除。
|
//综合选择还是方案1,这样创建分拣明细,只需要托盘物料两表查询就能定位托盘(如果信息不准,可以重置),方案2需要货位、托盘、物料三表联查
|
|
//暂时不计库区,标识用容器表 C_ENABLE 来判断,表示能不能出库
|
|
//执行分拣创建任务,遍历分拣明细中的托盘,如果在仓库就出库,如果不在就不用出库
|
|
|
});
|
//全部分拣单生成之后将分拣单状态设置为开始配货,波次号为发货单
|
sortingOrder = db.Queryable<SortingOrder>().Where(s => s.S_NO == sortingOrderNo).First();
|
sortingOrder.N_B_STATE = 1;
|
sortingOrder.T_MODIFY = DateTime.Now;
|
db.Updateable(sortingOrder).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY }).ExecuteCommand();
|
db.CommitTran();
|
res = true;
|
}
|
catch (Exception ex) {
|
Console.WriteLine(ex.Message);
|
db.RollbackTran();
|
}
|
return res;
|
|
}
|
|
internal static List<SortingDetail> GetSortingDetailByCntr(string cntr) {
|
var db = new SqlHelper<object>().GetInstance();
|
var result = db.Queryable<SortingDetail>().Where(a => a.S_CNTR_CODE == cntr && a.N_B_STATE != 2).ToList();
|
return result;
|
}
|
|
internal static bool CreateWmsTask(WMSTask wmsTask) {
|
try {
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Insertable<WMSTask>(wmsTask).ExecuteCommand() > 0;
|
}
|
catch (Exception ex) {
|
Console.WriteLine(ex.Message);
|
throw;
|
}
|
}
|
|
internal static WMSTask GetWmsTaskByCntr(string cntr, bool active = true) {
|
WMSTask result = null;
|
var db = new SqlHelper<object>().GetInstance();
|
if (active) {
|
result = db.Queryable<WMSTask>().Where(a => a.S_CNTR_CODE.Contains(cntr) && a.N_B_STATE < 2).OrderByDescending(a =>a.T_CREATE).First();
|
}
|
else {
|
result = db.Queryable<WMSTask>().Where(a => a.S_CNTR_CODE.Contains(cntr)).OrderByDescending(a => a.T_CREATE).First();
|
}
|
return result;
|
}
|
|
internal static Location GetEnd(WMSTask a) {
|
throw new NotImplementedException();
|
}
|
|
internal static Location GetStart(WMSTask a) {
|
throw new NotImplementedException();
|
}
|
|
internal static void UpdateTaskState(WMSTask task) {
|
var db = new SqlHelper<object>().GetInstance();
|
task.T_MODIFY = DateTime.Now;
|
task.S_B_STATE = WMSTask.GetStateStr(task.N_B_STATE);
|
db.Updateable<WMSTask>(task).UpdateColumns(a => new { a.N_B_STATE, a.S_B_STATE, a.T_MODIFY }).ExecuteCommand();
|
}
|
|
internal static bool UpdateTaskEnd(WMSTask a) {
|
var db = new SqlHelper<object>().GetInstance();
|
a.T_MODIFY = DateTime.Now;
|
return db.Updateable<WMSTask>(a).UpdateColumns(it => new { it.S_END_LOC,it.S_END_AREA, it.T_MODIFY }).ExecuteCommand() > 0;
|
}
|
|
internal static WMSTask GetWmsTask(string code) {
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<WMSTask>().Where(a => a.S_CODE == code).First();
|
}
|
|
|
/// <summary>
|
/// 类似农夫堆叠
|
/// </summary>
|
/// <param name="item"></param>
|
/// <param name="endArea"></param>
|
/// <returns></returns>
|
/// <exception cref="NotImplementedException"></exception>
|
internal static Location GetInstockEnd(string item, string endArea) {
|
Location end = null;
|
end = GetLocation4InAnySrc(endArea, item);
|
if (end == null)
|
{
|
end = GetLocation4InEmptyRow(endArea);
|
}
|
return end;
|
}
|
public static Location GetLocation4InAnySrc(string area, string itemCode) {
|
Location result = null;
|
|
try {
|
Console.WriteLine("成品满托入库 GetLocation4InAnySrc:" + area);
|
|
//1.0 获取每一排最大的列
|
//1.1 判断当前数量是不是满的,如果是满的并且是最大列,需要排除
|
var listMaxCol = new SqlHelper<Location>().GetInstance().Queryable<Location>().Where(a => a.S_AREA_CODE == area ).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList();
|
//1.1 查到所有有托盘的排
|
Console.WriteLine("查到所有有托盘的排 ");
|
var db = new SqlHelper<object>().GetInstance();
|
var list = db.Queryable<Location>().Where(a => a.N_CURRENT_NUM > 0 && a.S_AREA_CODE == area ).Includes(a => a.LocCntrRel, a => a.CntrItemRel).OrderByDescending(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList();
|
if (list.Count > 0) {
|
//1.2 查找其它尺寸有托盘或者锁定的排
|
for (int i = list.Count - 1; i >= 0; i--) {
|
//排除已经锁定的货位 和 放满了且是最大列的货位
|
if (list[i].N_LOCK_STATE != 0 || (list[i].N_CURRENT_NUM == list[i].N_CAPACITY && listMaxCol.Count(a => a.S_CODE == list[i].S_CODE) > 0)) {
|
Console.WriteLine($"排除已经锁定的货位 和 放满了且是最大列的货位 排{list[i].N_ROW}");
|
list.Remove(list[i]);
|
}
|
else {
|
//排有锁也排除
|
var other = db.Queryable<Location>().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.S_LOCK_STATE != "无" && a.N_LOCK_STATE != 0).First();
|
if (other != null) {
|
Console.WriteLine($"排除有锁的排{list[i].N_ROW}");
|
list.Remove(list[i]);
|
}
|
}
|
}
|
Console.WriteLine($"有托盘排数为{list.Count}");
|
if (list.Count > 0) {
|
|
//1.3 遍历判断物料类型是否相同
|
Console.WriteLine("遍历判断物料类型是否相同");
|
for (int i = 0; i < list.Count; i++) {
|
//todo 还需要判断锁
|
if (list[i].LocCntrRel != null && list[i].LocCntrRel.CntrItemRel != null) {
|
Console.WriteLine($"货位{list[i].S_CODE} 物料{list[i].LocCntrRel.CntrItemRel.S_ITEM_CODE}");
|
if (list[i].LocCntrRel.CntrItemRel.S_ITEM_CODE == itemCode) {
|
if (list[i].N_CURRENT_NUM < list[i].N_CAPACITY) {
|
result = list[i];
|
}
|
else {
|
Console.WriteLine("选择后面空位");
|
result = db.Queryable<Location>().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.N_COL > list[i].N_COL && a.C_ENABLE == "Y").OrderBy(a => a.N_COL).First();
|
}
|
|
if (result != null)
|
{
|
break;
|
}
|
}
|
}
|
|
}
|
}
|
}
|
|
if (result != null && (!string.IsNullOrEmpty(result.C_ENABLE) && (result.C_ENABLE == "禁用" || result.C_ENABLE == "N"))) {
|
//禁用了选择后面一个货位
|
//Console.WriteLine("禁用了选择后面一个货位");
|
result = db.Queryable<Location>().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == result.N_ROW && (string.IsNullOrEmpty(a.C_ENABLE) || (a.C_ENABLE != "禁用" && a.C_ENABLE != "N")) && a.N_COL > result.N_COL).First();
|
}
|
}
|
catch (Exception ex) {
|
LogHelper.Error("GetLocation4InFinish:" + ex.Message, ex);
|
}
|
return result;
|
}
|
public static Location GetLocation4InEmptyRow(string area) {
|
Location result = null;
|
try {
|
var db = new SqlHelper<object>().GetInstance();
|
|
#region 查找所有数量是空的排
|
//Console.WriteLine("查找所有数量是空的排");
|
//2.0 简化查询只查每一排第一列
|
var list = db.Queryable<Location>().Where(a => a.S_AREA_CODE == area).OrderBy(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList().Where(a => a.N_CURRENT_NUM == 0 ).ToList();
|
//2.1 选一个空排
|
for (int i = 0; i < list.Count; i++) {
|
var other = db.Queryable<Location>().Where(a => a.S_AREA_CODE == area && a.N_ROW == list[i].N_ROW && a.S_LOCK_STATE != "无").First();
|
if (list[i].N_LOCK_STATE == 0 && other == null) {
|
//二次校验当前排所有货位都是空的,防止系统数据错乱
|
var rowSumInfo = db.Queryable<Location>().Where(l => l.S_AREA_CODE == area && l.N_ROW == list[i].N_ROW && l.N_CURRENT_NUM != 0).Count();
|
if (rowSumInfo == 0) {
|
result = list[i];
|
break;
|
}
|
}
|
}
|
#endregion
|
|
if (result != null && (!string.IsNullOrEmpty(result.C_ENABLE) && (result.C_ENABLE == "禁用" || result.C_ENABLE == "N"))) {
|
//禁用了选择后面一个货位
|
Console.WriteLine("禁用了选择后面一个货位");
|
result = db.Queryable<Location>().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == area && a.N_ROW == result.N_ROW && (string.IsNullOrEmpty(a.C_ENABLE) || (a.C_ENABLE != "禁用" && a.C_ENABLE != "N")) && a.N_COL > result.N_COL).First();
|
}
|
}
|
catch (Exception ex) {
|
|
LogHelper.Error("GetLocation4InEmptyRow:" + ex.Message, ex);
|
}
|
return result;
|
}
|
|
public static Location GetLocation4InEmptyRow()
|
{
|
Location result = null;
|
try
|
{
|
var db = new SqlHelper<object>().GetInstance();
|
|
#region 查找所有数量是空的排
|
//Console.WriteLine("查找所有数量是空的排");
|
//2.0 简化查询只查每一排第一列
|
var list = db.Queryable<Location>().OrderBy(a => a.N_COL).Take(1).PartitionBy(a => a.N_ROW).ToList().Where(a => a.N_CURRENT_NUM == 0).ToList();
|
//2.1 选一个空排
|
for (int i = 0; i < list.Count; i++)
|
{
|
var other = db.Queryable<Location>().Where(a => a.S_AREA_CODE == list[i].S_AREA_CODE && a.N_ROW == list[i].N_ROW && a.S_LOCK_STATE != "无").First();
|
if (list[i].N_LOCK_STATE == 0 && other == null)
|
{
|
//二次校验当前排所有货位都是空的,防止系统数据错乱
|
var rowSumInfo = db.Queryable<Location>().Where(l => l.S_AREA_CODE == list[i].S_AREA_CODE && l.N_ROW == list[i].N_ROW && l.N_CURRENT_NUM != 0).Count();
|
if (rowSumInfo == 0)
|
{
|
result = list[i];
|
break;
|
}
|
}
|
}
|
#endregion
|
|
if (result != null && (!string.IsNullOrEmpty(result.C_ENABLE) && (result.C_ENABLE == "禁用" || result.C_ENABLE == "N")))
|
{
|
//禁用了选择后面一个货位
|
Console.WriteLine("禁用了选择后面一个货位");
|
result = db.Queryable<Location>().OrderBy(a => a.N_COL).Where(a => a.S_AREA_CODE == result.S_AREA_CODE && a.N_ROW == result.N_ROW && (string.IsNullOrEmpty(a.C_ENABLE) || (a.C_ENABLE != "禁用" && a.C_ENABLE != "N")) && a.N_COL > result.N_COL).First();
|
}
|
}
|
catch (Exception ex)
|
{
|
|
LogHelper.Error("GetLocation4InEmptyRow:" + ex.Message, ex);
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 获取空托开始货位
|
/// </summary>
|
/// <param name="trayType"></param>
|
/// <param name="exclude">是否排除母拖缓存位 0.不排除 1.排除</param>
|
/// <returns></returns>
|
public static Location GetEmptyTrayStartLoc(int trayType ,int exclude = 1)
|
{
|
Location result = null;
|
try
|
{
|
// 1、查询当前库区-排-物料 有托盘的货位
|
var db = new SqlHelper<object>().GetInstance();
|
var query = db.Queryable<Location>()
|
.LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
|
.LeftJoin<Container>((a, b, c) => b.S_CNTR_CODE == c.S_CODE)
|
.LeftJoin<CntrItemRel>((a, b, c, d) => c.S_CODE == d.S_CNTR_CODE)
|
.Where((a, b, c, d) => a.S_AREA_CODE == Settings.storeAreaCode && (trayType == 0 && a.N_CURRENT_NUM == 1 || trayType > 0 && a.N_CURRENT_NUM > 0) && a.N_LOCK_STATE == 0 && (a.C_ENABLE != "禁用" && a.C_ENABLE != "N") && c.N_TYPE == trayType && d.S_ITEM_CODE == null);
|
|
if (exclude == 1)
|
{
|
List<string> bufferInLocs = Settings.baseTrayBufferLocList.Select(a => a.bufferInLoc).ToList();
|
query = query.Where((a, b, c, d) => !bufferInLocs.Contains(a.S_CODE));
|
}
|
else
|
{
|
List<string> bufferInLocs = Settings.baseTrayBufferLocList.Select(a => a.bufferInLoc).ToList();
|
query = query.OrderByDescending((a, b, c, d) => bufferInLocs.Contains(a.S_CODE));
|
}
|
|
result = query.OrderByDescending((a, b, c, d) => a.N_LAYER).First();
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info("获取空托开始货位错误:" + ex.Message, "WMS");
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 入库前检查母拖数量是否满足
|
/// </summary>
|
/// <returns></returns>
|
public static bool CheckBaseTrayNum()
|
{
|
bool result = false;
|
try
|
{
|
// 1、查询当前库区-排-物料 有托盘的货位
|
var db = new SqlHelper<object>().GetInstance();
|
// 查询库内母拖数量
|
var baseTrayNum = db.Queryable<Location>()
|
.LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
|
.LeftJoin<Container>((a, b, c) => b.S_CNTR_CODE == c.S_CODE)
|
.Where((a, b, c) => a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && (a.C_ENABLE != "禁用" && a.C_ENABLE != "N") && c.N_TYPE == 0)
|
.Count();
|
|
var taskTrayNum = db.Queryable<WMSTask>()
|
.LeftJoin<Container>((a, b) => a.S_CNTR_CODE == b.S_CODE)
|
.Where((a, b) => a.N_B_STATE < 2 && b.N_TYPE == 0)
|
.Count();
|
|
if (baseTrayNum - taskTrayNum > 0) {
|
result = true;
|
}
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info("检查母拖数量错误:" + ex.Message, "WMS");
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 获取出库开始货位
|
/// 出库策略:
|
/// 1.先入先出
|
/// 2.不合格、未生效 、失效 物料不允许出库
|
/// </summary>
|
/// <param name="itemCode"></param>
|
/// <param name="jbLoc"></param>
|
/// <param name="trayCode"></param>
|
/// <returns></returns>
|
public static Location GetoutStockStartLoc(string itemCode ,string trayCode = null ,string jbLoc = null)
|
{
|
LogHelper.Info("【获取出库开始货位】", "WMS");
|
var db = new SqlHelper<object>().GetInstance();
|
Location loc = null;
|
try
|
{
|
var query = db.Queryable<Location>()
|
.LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
|
.LeftJoin<CntrItemRel>((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
|
.Where((a, b, c) => a.S_AREA_CODE == Settings.storeAreaCode
|
&& a.N_CURRENT_NUM > 0
|
&& a.N_LOCK_STATE == 0
|
&& c.S_ITEM_CODE == itemCode
|
&& c.S_FOVRAGE != "Y"
|
&& c.S_ITEM_STATE == "OK"
|
&& SqlFunc.ToDate(c.S_EFFECTIVE_TIME) <= SqlFunc.GetDate() // 生效时间早于当前时间
|
&& SqlFunc.ToDate(c.S_EXPIRATION_TIME) >= SqlFunc.GetDate() // 失效时间晚于当前时间
|
&& c.S_EFFECTIVE_TIME != null
|
&& c.S_EXPIRATION_TIME != null
|
);
|
|
if (trayCode != null)
|
{
|
query = query.Where((a, b, c) => c.S_CNTR_CODE == trayCode);
|
}
|
|
if (jbLoc != null)
|
{
|
List<int> roadwayList = new List<int>();
|
var agvJBLoc = Settings.getAgvJBLoc(jbLoc);
|
if (agvJBLoc != null)
|
{
|
roadwayList = agvJBLoc.roadway;
|
query = query.Where((a, b, c) => roadwayList.Contains(a.N_ROADWAY));
|
}
|
}
|
|
// 先入先出
|
loc = query.OrderBy((a, b, c) => c.T_CREATE) .OrderByDescending((a, b, c) => a.N_LAYER).First();
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"【获取出库开始货位】内部错误,错误原因:{ex.Message}","WMS");
|
}
|
return loc;
|
}
|
|
/// <summary>
|
/// 获取入库终点货位
|
/// 入库策略
|
/// 1.巷道均衡
|
/// 2.物料均衡
|
/// </summary>
|
/// <param name="locCode"></param>
|
/// <param name="trayType"></param>
|
/// <param name="inWay">入库方式 1.自动入库 2.人工入库</param>
|
/// <returns></returns>
|
public static Location GetInstockEndLoc(int trayType , string locCode = null , int inWay = 1 ,string itemCode = null)
|
{
|
LogHelper.Info("【获取入库终点货位】开始获取入库终点货位", "WMS");
|
var db = new SqlHelper<object>().GetInstance();
|
Location loc = null;
|
try
|
{
|
// 托盘 1.带束 2.胎侧 3.BEC 入巷道 1-5 进行混放 ; 4.内衬 5.帘布 6.胎圈 入巷道 6-7 ;其中内衬、帘布放5-8层 胎圈放 1-4 层
|
List<int> roadwayList = null;
|
List<int> layerList = null;
|
if (locCode != null)
|
{
|
var agvJBLoc = Settings.getAgvJBLoc(locCode);
|
if (agvJBLoc != null)
|
{
|
roadwayList = agvJBLoc.roadway;
|
}
|
}
|
else
|
{
|
if (trayType > 0 && trayType <= 3)
|
{
|
roadwayList = new List<int>() { 1, 2, 3, 4, 5 };
|
}
|
else
|
{
|
roadwayList = new List<int>() { 6,7 };
|
}
|
}
|
|
// 确定物料的入库层数
|
if (trayType > 0 && trayType <= 3)
|
{
|
layerList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
}
|
else if (trayType > 3 && trayType <= 5)
|
{
|
layerList = new List<int>() { 5, 6, 7, 8 };
|
}
|
else
|
{
|
layerList = new List<int>() { 1, 2, 3, 4 };
|
}
|
|
LogHelper.Info("【获取入库终点货位】查询是否有满足条件的空货位", "WMS");
|
var locList = db.Queryable<Location>()
|
.Where(a => a.S_AREA_CODE == Settings.storeAreaCode
|
&& a.N_CURRENT_NUM == 0
|
&& a.N_LOCK_STATE == 0
|
&& a.C_ENABLE == "Y"
|
&& roadwayList.Contains(a.N_ROADWAY)
|
&& layerList.Contains(a.N_LAYER) )
|
.OrderBy(l => l.N_LAYER)
|
.ToList();
|
|
if (locList.Count == 0)
|
{
|
LogHelper.Info("【获取入库终点货位】没有满足条件的空货位", "WMS");
|
return loc;
|
}
|
else
|
{
|
LogHelper.Info($"【获取入库终点货位】满足条件的空货位数量:{locList.Count}", "WMS");
|
}
|
|
LogHelper.Info($"【获取入库终点货位】开始查询巷道的容积率", "WMS");
|
var roadwayVolumeList = db.Queryable<Location>()
|
.Where(a => a.N_CURRENT_NUM == 0 && a.S_AREA_CODE == Settings.storeAreaCode && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y" && roadwayList.Contains(a.N_ROADWAY) && layerList.Contains(a.N_LAYER))
|
.GroupBy(a => a.N_ROADWAY)
|
.Select(a => new { roadway = a.N_ROADWAY , num = SqlFunc.AggregateDistinctCount(a.S_CODE)})
|
.OrderBy(a => a.num)
|
.ToList();
|
LogHelper.Info($"【获取入库终点货位】查询巷道的容积率,并按从小到大排序:{JsonConvert.SerializeObject(roadwayVolumeList)}", "WMS");
|
|
Dictionary<int,int> roadwayDic = new Dictionary<int,int>();
|
foreach (var item in roadwayVolumeList)
|
{
|
roadwayDic.Add(item.roadway, item.num);
|
}
|
|
LogHelper.Info($"【获取入库终点货位】开始查询巷道的同物料数量", "WMS");
|
var roadwayItemNumList = db.Queryable<Location>()
|
.LeftJoin<LocCntrRel>((a,b) => a.S_CODE == b.S_LOC_CODE)
|
.LeftJoin<CntrItemRel>((a,b,c) => b.S_CNTR_CODE == c.S_CNTR_CODE )
|
.Where((a, b, c) => a.S_AREA_CODE == Settings.storeAreaCode && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y" && roadwayList.Contains(a.N_ROADWAY) && layerList.Contains(a.N_LAYER))
|
.GroupBy((a, b, c) => a.N_ROADWAY)
|
.Select((a, b, c) => new { roadway = a.N_ROADWAY, volumNum = SqlFunc.AggregateDistinctCount(c.S_ITEM_CODE == itemCode) })
|
.ToList();
|
LogHelper.Info($"【获取入库终点货位】查询巷道的同物料数量,并按从小到到排序:{JsonConvert.SerializeObject(roadwayItemNumList)}", "WMS");
|
|
roadwayItemNumList = roadwayItemNumList.OrderBy(a => a.volumNum).ThenBy(a => roadwayDic[a.roadway]).ToList();
|
|
if (inWay == 1)
|
{
|
LogHelper.Info($"【获取入库终点货位】开始循环查询巷道对应接驳位的状态", "WMS");
|
foreach (var roadwayVolume in roadwayItemNumList)
|
{
|
int roadway = roadwayVolume.roadway;
|
LogHelper.Info($"【获取入库终点货位】查询巷道内堆垛机的设备状态", "WMS");
|
|
List<string> deviceNos = new List<string>() { roadway.ToString()};
|
LogHelper.Info($"调用WCS的设备状态查询接口,参数:{deviceNos}", "WMS");
|
var deviceStatuses = WCSDispatch.getDeviceStatus(deviceNos);
|
|
var agvJbLocList = Settings.getAgvJBLocList( roadway, 1);
|
if (agvJbLocList.Count > 0)
|
{
|
foreach (var agvLocCode in agvJbLocList)
|
{
|
var agvLoc = LocationHelper.GetLoc(agvLocCode);
|
if (agvLoc != null && agvLoc.N_LOCK_STATE == 0 && agvLoc.C_ENABLE == "Y")
|
{
|
LogHelper.Info($"【查询入库终点货位】,接驳位:{agvLoc.S_CODE}状态正常,查询巷道:{roadway}的空货位");
|
loc = db.Queryable<Location>()
|
.Where(a => a.N_CURRENT_NUM == 0 && a.S_AREA_CODE == Settings.storeAreaCode && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y" && a.N_ROADWAY == roadway && layerList.Contains(a.N_LAYER))
|
.OrderBy(l => l.N_LAYER)
|
.First();
|
if (loc != null)
|
{
|
return loc;
|
}
|
else
|
{
|
LogHelper.Info($"【查询入库终点货位】,没有查询巷道:{roadway}的空货位,跳过此巷道");
|
}
|
}
|
else
|
{
|
LogHelper.Info($"【查询入库终点货位】,接驳位:{agvLoc.S_CODE},暂时不可用,跳过此巷道");
|
}
|
}
|
}
|
}
|
}
|
else if (inWay == 2)
|
{
|
// 查询空货位
|
loc = db.Queryable<Location>()
|
.Where(a => a.N_CURRENT_NUM == 0 && a.S_AREA_CODE == Settings.storeAreaCode && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y" && roadwayList.Contains(a.N_ROADWAY) && layerList.Contains(a.N_LAYER))
|
.OrderBy(l => l.N_LAYER)
|
.First();
|
if (loc != null)
|
{
|
return loc;
|
}
|
else
|
{
|
LogHelper.Info($"【查询入库终点货位】,巷道:{JsonConvert.SerializeObject(roadwayList)}内没有空货位");
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Error("【查询入库终点货位】内部错误,错误原因:" + ex.Message, ex);
|
}
|
return loc;
|
}
|
|
|
/// <summary>
|
/// 获取缓存区货位
|
/// </summary>
|
/// <returns></returns>
|
public static Location getErrorBufferAreaLoc()
|
{
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.errorBufferArea && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
|
}
|
|
/// <summary>
|
/// 获取库区排的货位列表
|
/// </summary>
|
/// <param name="area"></param>
|
/// <param name="row"></param>
|
/// <returns></returns>
|
public static List<Location> GetLocationList(string area , int row) {
|
List<Location> result = new List<Location> ();
|
try {
|
var db = new SqlHelper<object>().GetInstance();
|
result = db.Queryable<Location>().Where(a => a.S_AREA_CODE == area && a.N_ROW == row).Includes(a => a.LocCntrRel, a => a.CntrItemRel).ToList();
|
}
|
catch (Exception ex) {
|
LogHelper.Error("GetLocationList:" + ex.Message, ex);
|
}
|
return result;
|
}
|
|
public static bool updateShiftOrderDetail(TN_YiKuDetail detail) {
|
bool result = false;
|
var db = new SqlHelper<object>().GetInstance();
|
LogHelper.Info("移库完成数量变更参数:" + JsonConvert.SerializeObject(detail), "TSSG");
|
result = db.Updateable<TN_YiKuDetail>()
|
.SetColumns(a => new TN_YiKuDetail() { N_COMPLETE_NUM = a.N_COMPLETE_NUM + 1 })
|
.Where(a => a.S_NO == detail.S_NO
|
&& a.S_START_AREA == detail.S_START_AREA
|
&& a.S_START_ROW == detail.S_START_ROW
|
&& a.S_END_AREA == detail.S_END_AREA
|
&& a.S_END_ROW == detail.S_END_ROW
|
)
|
.ExecuteCommand() > 0;
|
|
var completeResult = db.Queryable<TN_YiKuDetail>().Where(a => a.S_NO == detail.S_NO && a.N_QTY > a.N_COMPLETE_NUM).Count() == 0;
|
if(completeResult) {
|
result = db.Updateable<TN_YiKuOrder>().SetColumns(a => new TN_YiKuOrder() { S_B_STATE = "完成" }).Where(a => a.S_NO == detail.S_NO).ExecuteCommand() > 0;
|
}
|
return result;
|
}
|
|
/// <summary>
|
///获取空托缓存信号列表
|
/// </summary>
|
/// <returns></returns>
|
public static List<EmptyTrayBuffer> getEmptyTrayBufferList()
|
{
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<EmptyTrayBuffer>().Where(a => a.IS_CREATED == "N").ToList();
|
}
|
|
/// <summary>
|
/// 添加空托缓存信号
|
/// </summary>
|
/// <param name="emptyTrayBuffer"></param>
|
/// <returns></returns>
|
public static bool addEmptyTrayBuffer(EmptyTrayBuffer emptyTrayBuffer)
|
{
|
bool result = true;
|
var db = new SqlHelper<object>().GetInstance();
|
result = db.Insertable<EmptyTrayBuffer>(emptyTrayBuffer).ExecuteCommand() > 0;
|
return result;
|
}
|
|
/// <summary>
|
/// 更新空托缓存信号
|
/// </summary>
|
/// <param name="emptyTrayBuffer"></param>
|
/// <returns></returns>
|
public static bool updateEmptyTrayBuffer(EmptyTrayBuffer emptyTrayBuffer)
|
{
|
bool result = true;
|
var db = new SqlHelper<object>().GetInstance();
|
result = db.Updateable<EmptyTrayBuffer>(emptyTrayBuffer).ExecuteCommand() > 0;
|
return result;
|
}
|
|
/// <summary>
|
/// 批量添加物料条码信息
|
/// </summary>
|
/// <returns></returns>
|
public static bool batchAddItemBarcodeInfo(List<ItemBarcodeInfo> itemBarcodeInfos)
|
{
|
bool result = true;
|
var db = new SqlHelper<object>().GetInstance();
|
try
|
{
|
db.BeginTran();
|
itemBarcodeInfos.ForEach(item => {
|
var itemBarcodeInfo = db.Queryable<ItemBarcodeInfo>().Where(a => a.S_BC_ENTRIED == item.S_BC_ENTRIED).First();
|
if (itemBarcodeInfo == null)
|
{
|
var bo = db.Insertable<ItemBarcodeInfo>(item).ExecuteCommand() > 0;
|
if (!bo)
|
{
|
result = false;
|
LogHelper.Info($"添加物料条码信息失败,物料条码信息:{JsonConvert.SerializeObject(item)}", "GT");
|
}
|
}
|
});
|
if (result)
|
{
|
db.CommitTran();
|
}
|
else
|
{
|
db.RollbackTran();
|
}
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"添加物料条码信息错误,错误信息:{ex.Message}", "GT");
|
db.RollbackTran();
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 批量更新物料状态
|
/// </summary>
|
/// <returns></returns>
|
public static bool batchUpdateItemStatus(List<UpdateMatlStatus> updateMatlStatuses)
|
{
|
bool result = true;
|
var db = new SqlHelper<object>().GetInstance();
|
try
|
{
|
db.BeginTran();
|
updateMatlStatuses.ForEach(update => {
|
var itemBarcodeInfo = db.Queryable<ItemBarcodeInfo>().Where(a => a.S_BC_ENTRIED == update.bc_entried).First();
|
if (itemBarcodeInfo != null)
|
{
|
itemBarcodeInfo.S_JDGE = update.jdge;
|
db.Updateable(itemBarcodeInfo).ExecuteCommand();
|
var cntrItemRel = db.Queryable<CntrItemRel>().Where(a => a.S_CG_ID == update.bc_entried).First();
|
if (cntrItemRel != null)
|
{
|
// 将MES的物料状态转化成WMS可识别的物料状态
|
if (update.jdge == "" || update.jdge == null)
|
{
|
update.jdge = "OK";
|
}
|
else if (update.jdge != "OK")
|
{
|
update.jdge = "HOLD";
|
}
|
db.Updateable<CntrItemRel>().SetColumns(a => new CntrItemRel() { S_ITEM_STATE = update.jdge }).Where(a => a.S_CG_ID == update.bc_entried).ExecuteCommand();
|
}
|
}
|
});
|
db.CommitTran();
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"批量更新物料状态错误,错误信息:{ex.Message}", "GT");
|
db.RollbackTran();
|
result = false;
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 批量更新物料状态
|
/// </summary>
|
/// <returns></returns>
|
public static bool batchUpdateMatlTimeConfig(List<Overage> overages)
|
{
|
bool result = true;
|
var db = new SqlHelper<object>().GetInstance();
|
try
|
{
|
db.BeginTran();
|
foreach (Overage overage in overages)
|
{
|
var overage1 = db.Queryable<Overage>().Where(a => a.RECID == overage.RECID).First();
|
if (overage1 != null)
|
{
|
overage1.MCNGRP = overage.MCNGRP;
|
overage1.ITEMPATT = overage.ITEMPATT;
|
overage1.OVERAGE = overage.OVERAGE;
|
overage1.MINHOUR = overage.MINHOUR;
|
overage1.FLAG_STS = overage.FLAG_STS;
|
db.Updateable(overage1).ExecuteCommand();
|
}
|
else
|
{
|
db.Insertable(overage).ExecuteCommand();
|
}
|
}
|
db.CommitTran();
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"批量更新物料存放时间配置信息错误,错误信息:{ex.Message}", "GT");
|
db.RollbackTran();
|
result = false;
|
}
|
return result;
|
}
|
/// <summary>
|
/// 查询物料存放时间配置信息
|
/// </summary>
|
/// <param name="bc_entried"></param>
|
/// <returns></returns>
|
public static Overage getOverage(string bc_entried)
|
{
|
|
var db = new SqlHelper<object>().GetInstance();
|
|
// 直接执行 SQL(参数化查询)
|
var sql = "SELECT get_ovg_bar(@barcode, @mcngrp) AS overage_value";
|
var sql1 = "SELECT get_minhour_bar(@barcode, @mcngrp) AS overage_value";
|
|
// 使用匿名对象传递参数
|
var ovg_bar = db.Ado.SqlQuery<int>(sql, new { barcode = bc_entried, mcngrp = "1"}).First();
|
var minhour_bar = db.Ado.SqlQuery<float>(sql1, new { barcode = bc_entried, mcngrp = "1"}).First();
|
Overage overage = new Overage()
|
{
|
MINHOUR = minhour_bar,
|
OVERAGE = ovg_bar
|
};
|
return overage;
|
}
|
|
/// <summary>
|
/// 添加同步数据时间记录
|
/// </summary>
|
/// <param name="record"></param>
|
/// <returns></returns>
|
public static bool addSynDataTimeReord(SynDataTimeRecord record)
|
{
|
bool result = true;
|
var db = new SqlHelper<object>().GetInstance();
|
try
|
{
|
db.BeginTran();
|
var synDataTimeRecord = db.Queryable<SynDataTimeRecord>().Where(a => a.S_SYN_TIME == record.S_SYN_TIME && a.RECORD_TABLE == record.RECORD_TABLE).First();
|
if (synDataTimeRecord == null)
|
{
|
result = db.Insertable(record).ExecuteCommand() > 0;
|
}
|
else
|
{
|
synDataTimeRecord.N_SYN_NUM = record.N_SYN_NUM;
|
synDataTimeRecord.S_SYN_TIME = record.S_SYN_TIME;
|
result = db.Updateable(synDataTimeRecord).ExecuteCommand() > 0;
|
}
|
|
if (result)
|
{
|
db.CommitTran();
|
}
|
else
|
{
|
db.RollbackTran();
|
}
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"添加数据同步时间记录错误,错误信息:{ex.Message}", "GT");
|
db.RollbackTran();
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 查询上一次的同步时间
|
/// </summary>
|
/// <param name="recordTable"></param>
|
/// <returns></returns>
|
public static SynDataTimeRecord getLastDataSynTime(string recordTable)
|
{
|
var db = new SqlHelper<object>().GetInstance();
|
return db.Queryable<SynDataTimeRecord>().Where(a => a.RECORD_TABLE == recordTable).OrderByDescending(a => a.T_CREATE).First();
|
}
|
}
|
}
|