using HH.WCS.Mobox3.YNJT_BZP_PT.models;
using HH.WCS.Mobox3.YNJT_PT.api;
using HH.WCS.Mobox3.YNJT_PT.dispatch;
using HH.WCS.Mobox3.YNJT_PT.models;
using HH.WCS.Mobox3.YNJT_PT.models.other;
using HH.WCS.Mobox3.YNJT_PT.util;
using Newtonsoft.Json;
using NLog.Fluent;
using SqlSugar;
using System;
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_PT.api.ApiModel;
namespace HH.WCS.Mobox3.YNJT_PT.wms {
///
/// wms管到作业
///
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 GenerateTaskGroupNo() {
var id = SYSHelper.GetSerialNumber("任务组", "GP");
var date = DateTime.Now.ToString("yyMMdd");
return $"GP{date}{id.ToString().PadLeft(4, '0')}";
}
internal static List GetOperationListByState(string state) {
var db = new SqlHelper().GetInstance();
return db.Queryable().Where(a => a.S_B_STATE == state).ToList();
}
internal static List GetOperationListByState(int state) {
var db = new SqlHelper().GetInstance();
return db.Queryable().Where(a => a.N_B_STATE == state).ToList();
}
internal static List GetWaitingOperationList() {
var db = new SqlHelper().GetInstance();
return db.Queryable().Where(a => a.N_B_STATE == 0 || a.N_B_STATE == 3).ToList();
}
internal static PutawayOrder GetPutawayOrder(string no) {
var db = new SqlHelper().GetInstance();
return db.Queryable().Where(a => a.S_NO == no).First();
}
internal static bool CreatePutawayOrder(PutawayOrder model) {
var db = new SqlHelper().GetInstance();
var result = db.Insertable(model).ExecuteCommand() > 0;
db.Insertable(model.Details).ExecuteCommand();
return result;
}
internal static PutawayDetail GetPutawayOrderDetail(string no, string item_code) {
var db = new SqlHelper().GetInstance();
return db.Queryable().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().GetInstance();
return db.Queryable().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().GetInstance();
db.Updateable(model).UpdateColumns(it => new { it.F_ACC_B_QTY }).ExecuteCommand();
}
internal static ShippingOrder GetShippingOrder(string no) {
var db = new SqlHelper().GetInstance();
return db.Queryable().Includes(a => a.Details).Where(a => a.S_NO == no).First();
}
internal static bool CreateShippingOrder(ShippingOrder model) {
var db = new SqlHelper().GetInstance();
var result = db.Insertable(model).ExecuteCommand() > 0;
db.Insertable(model.Details).ExecuteCommand();
return result;
}
internal static bool CreateWmsTask(WMSTask wmsTask) {
try {
var db = new SqlHelper().GetInstance();
return db.Insertable(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().GetInstance();
if (active) {
result = db.Queryable().Where(a => a.S_CNTR_CODE.Contains(cntr) && a.N_B_STATE < 2).First();
}
else {
result = db.Queryable().Where(a => a.S_CNTR_CODE.Contains(cntr)).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().GetInstance();
task.T_MODIFY = DateTime.Now;
task.S_B_STATE = WMSTask.GetStateStr(task.N_B_STATE);
db.Updateable(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().GetInstance();
a.T_MODIFY = DateTime.Now;
return db.Updateable(a).UpdateColumns(it => new { it.S_END_LOC, it.T_MODIFY }).ExecuteCommand() > 0;
}
internal static WMSTask GetWmsTask(string code) {
var db = new SqlHelper().GetInstance();
return db.Queryable().Where(a => a.S_CODE == code).First();
}
///
/// 获取配货完成的分拣单,每个分拣单单独创建分拣作业
///
///
internal static List GetWaitingSortingOperationList() {
var db = new SqlHelper().GetInstance();
return db.Queryable().Includes(a => a.Details).Where(a => a.N_B_STATE == 2 || a.N_B_STATE == 3).ToList();
}
///
///单个分拣单的分拣明细创建作业
///
internal static void CreateSortingOperation(SortingOrder so) {
var list = so.Details.Where(a => a.N_B_STATE == 0).ToList();
var db = new SqlHelper().GetInstance();
if (list.Count > 0) {
try {
db.BeginTran();
list.GroupBy(g => g.S_CNTR_CODE).ToList().ForEach(g => {
var cntr = g.Key;
var sdList = g.ToList();
//查询托盘货位,查到了创建任务,查不到说明在别的分拣作业中,不创建任务,需要回库后重新创建
var lcr = db.Queryable().Where(c => c.S_CNTR_CODE == cntr).First();
if (lcr != null) {
//判断托盘是否已经创建任务了,可能多个分拣明细是同一个托盘,如果创建任务了,其它分拣的要稍后,只出一次人工会搞不清楚是哪个分拣单的
var wmsTask = db.Queryable().Where(op => op.S_CNTR_CODE.Contains(cntr) && op.N_B_STATE < 2).First();
if (wmsTask == null) {
wmsTask = new WMSTask
{
S_CNTR_CODE = cntr,
S_CODE = WMSHelper.GenerateTaskNo(),
S_START_LOC = lcr.S_LOC_CODE,
S_END_LOC = "",
N_TYPE = 2,
S_TYPE = WMSTask.GetTypeStr(2),
S_OP_DEF_CODE = "",
S_OP_DEF_NAME = "分拣出立库"
};
if (db.Insertable(wmsTask).ExecuteCommand() > 0) {
LocationHelper.LockLoc(lcr.S_LOC_CODE, 2);
}
sdList.ForEach(a => {
a.N_B_STATE = 1;
a.T_MODIFY = DateTime.Now;
db.Updateable(a).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY }).ExecuteCommand();
});
}
}
//修改分拣单状态为开始作业(不代表作业全部创建了,因为有的托盘可能已经被占用了)
so.N_B_STATE = 3;
//如果所有的作业都已经创建了,就设置为作业已经创建
if (so.Details.Count(s => s.N_B_STATE == 0) == 0) {
so.N_B_STATE = 4;
}
so.T_MODIFY = DateTime.Now;
db.Updateable(so).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY }).ExecuteCommand();
});
db.CommitTran();
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
db.RollbackTran();
}
}
}
///
/// 类似农夫堆叠
///
///
///
///
///
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().GetInstance().Queryable().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().GetInstance();
var list = db.Queryable().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().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().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().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().GetInstance();
#region 查找所有数量是空的排
//Console.WriteLine("查找所有数量是空的排");
//2.0 简化查询只查每一排第一列
var list = db.Queryable().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().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().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().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 bool addOffLineRecord(OffLineRecord record)
{
bool result = false;
var db = new SqlHelper().GetInstance();
var offLineRecord = db.Queryable().Where(a => a.S_RFID == record.S_RFID).First();
if (offLineRecord != null)
{
offLineRecord.S_DEVICE_NO = record.S_DEVICE_NO;
offLineRecord.N_IS_URGENT = record.N_IS_URGENT;
offLineRecord.T_OFF_TIME = record.T_OFF_TIME;
offLineRecord.N_IS_FULL = record.N_IS_FULL;
result = db.Updateable(offLineRecord).ExecuteCommand() > 0;
}
else
{
result = db.Insertable(record).ExecuteCommand() > 0;
}
return result;
}
///
/// 查询成型机下线记录
///
///
///
public static OffLineRecord getOffLineRecord(string rfid)
{
OffLineRecord offLineRecord = null;
var db = new SqlHelper().GetInstance();
if (rfid != null)
{
offLineRecord = db.Queryable().Where(a => a.S_RFID == rfid).First();
}
return offLineRecord;
}
///
/// 查询物料条码信息
///
///
///
public static GreenTireInformation GetGreenTireInformation(string barcode)
{
GreenTireInformation greenTireInformation = null;
var db = new SqlHelper().GetInstance();
if (barcode != null)
{
greenTireInformation = db.Queryable().Where(a => a.BARCODE == barcode).First();
}
return greenTireInformation;
}
/*///
/// 查询入库终点货位
/// 入库策略:
/// 巷道内同规格数量 小于 10(暂定),按物料均衡计算,如果所有的巷道内同规格数量都大于10,则按照巷道均衡计算
///
/// 1.单货位 2.双货位
///
public static EndLocGroup getInStockEndLoc(int locNum , string itemCode)
{
var db = new SqlHelper().GetInstance();
EndLocGroup endLocGroup = new EndLocGroup();
List locations = new List();
List roadwayList = new List();
// 1.按巷道进行分组,查询每个巷道内同规格物料的数量,并从小到大排序
var roadwayItemNumOrderGroup = db.Queryable()
.LeftJoin((a,b) => a.S_CODE == b.S_LOC_CODE)
.LeftJoin((a,b,c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
.Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y" && c.S_ITEM_CODE == itemCode)
.GroupBy((a, b, c) => a.N_ROADWAY)
.Select((a, b, c) => new { roadway = a.N_ROADWAY, num = SqlFunc.AggregateCount(a.S_CODE) })
.OrderBy(a => a.num)
.ToList();
roadwayList = roadwayItemNumOrderGroup.Where(a => a.num < 10).OrderBy(a => a.num).Select(a => a.roadway).ToList();
// 2.按巷道进行分组,查询每个巷道空货位数量,并从大到小排序
if (roadwayList.Count == 0)
{
var roadwayEmptyNumOrderGroup = db.Queryable().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y")
.GroupBy(a => a.N_ROADWAY)
.Select(a => new { roadway = a.N_ROADWAY, num = SqlFunc.AggregateCount(a.S_CODE) })
.OrderByDescending(a => a.num)
.ToList();
roadwayList = roadwayEmptyNumOrderGroup.Select(a => a.roadway).ToList();
}
if (roadwayList.Count > 0)
{
// 查询单货位
foreach (var roadway in roadwayList)
{
if (locNum == 1)
{
// 查询空货位
var emptyLoc = db.Queryable().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => new { a.N_LAYER, a.N_COL }).First();
if (emptyLoc != null)
{
locations.Add(emptyLoc);
endLocGroup.endLocList = locations;
return endLocGroup;
}
}
if (locNum == 2)
{
var emptyLocList = db.Queryable().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => new { a.N_LAYER, a.N_COL }).ToList();
if (emptyLocList.Count > 0)
{
// 优先查询相邻双拖空货位
if (locations.Count == 0)
{
foreach (var loc in emptyLocList)
{
// 查询相邻左侧是否有空货位
var leftLoc = db.Queryable().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
if (leftLoc != null)
{
locations.Add(loc);
locations.Add(leftLoc);
break;
}
// 查询相邻右侧是否有空货位
var rightLoc = db.Queryable().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
if (rightLoc != null)
{
locations.Add(loc);
locations.Add(rightLoc);
break;
}
}
}
if (locations.Count < locNum)
{
// 查询不相邻的单拖货位
foreach (var loc in emptyLocList)
{
locations.Add(loc);
if (locations.Count == locNum)
{
break;
}
}
}
if (locations.Count == locNum)
{
endLocGroup.endLocList = locations;
// 校验货位是否是同巷道,是则生成任务组号
var groupNum = locations.GroupBy(a => a.N_ROADWAY).Count();
if (groupNum == 1)
{
endLocGroup.groupNo = WMSHelper.GenerateTaskGroupNo();
}
return endLocGroup;
}
}
}
}
}
return endLocGroup;
}*/
///
/// 查询入库终点货位
/// 入库策略:
/// 巷道内同规格数量 小于 10(暂定),按物料均衡计算,如果所有的巷道内同规格数量都大于10,则按照巷道均衡计算
///
///
///
///
///
///
public static EndLocGroup getInStockEndLoc(int locNum, string itemCode , int roadway = 0 ,int excludeRoadway = 0)
{
var db = new SqlHelper().GetInstance();
EndLocGroup endLocGroup = new EndLocGroup { endLocList = new List() };
// 1. 获取候选巷道列表(物料均衡或巷道均衡)
List candidateRoadways = new List();
if (roadway == 0)
{
candidateRoadways = GetCandidateRoadways(db, itemCode);
if (candidateRoadways.Count == 0) return endLocGroup;
if (excludeRoadway != 0)
{
candidateRoadways.Remove(excludeRoadway);
}
}
else
{
candidateRoadways.Add(roadway);
}
// 2. 处理单货位入库
if (locNum == 1)
{
return FindSingleLocation(db, candidateRoadways);
}
// 3. 处理双货位入库
return FindDoubleLocations(db, candidateRoadways);
}
///
/// 获取候选巷道列表(按策略排序)
///
private static List GetCandidateRoadways(SqlSugarClient db, string itemCode)
{
var list = new List();
// 策略1:巷道内同规格物料 < 10 的巷道(按数量升序)
var materialRoadwayGroup = db.Queryable()
// 表别名:a = Location, b = LocCntrRel, c = CntrItemRel
.LeftJoin((a, b) => a.S_CODE == b.S_LOC_CODE)
.LeftJoin((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
// 基础筛选条件(所有位置)
.Where((a, b, c) =>
a.S_AREA_CODE == Settings.stockArea && // 指定区域
a.N_LOCK_STATE == 0 && // 未锁定
a.C_ENABLE == "Y") // 启用状态
// 按巷道分组(使用原始表字段)
.GroupBy((a, b, c) => a.N_ROADWAY)
// 选择分组结果(包含聚合计算)
.Select((a, b, c) => new
{
Roadway = a.N_ROADWAY, // 巷道编号
// 统计满足特定条件的数量:
// 1. 当前数量=1 (a.N_CURRENT_NUM == 1)
// 2. 物料匹配 (c.S_ITEM_CODE == itemCode)
// 3. 容器关联存在 (b.S_CNTR_CODE != null)
validCount = SqlFunc.AggregateSum(SqlFunc.IIF(
a.N_CURRENT_NUM == 1 &&
c.S_ITEM_CODE == itemCode &&
b.S_CNTR_CODE != null,
1, 0))
})
.ToList();
if (materialRoadwayGroup.Count > 0)
{
list = materialRoadwayGroup.Where(a => a.validCount < 10).OrderBy(a => a.validCount).Select(a => a.Roadway).ToList();
}
if (list.Count == 0)
{
// 策略2:所有巷道按空货位数降序排序
materialRoadwayGroup = db.Queryable()
.Where(a =>
a.S_AREA_CODE == Settings.stockArea &&
a.N_CURRENT_NUM == 0 &&
a.N_LOCK_STATE == 0 &&
a.C_ENABLE == "Y")
.GroupBy(a => a.N_ROADWAY)
.Select(a => new { Roadway = a.N_ROADWAY, validCount = SqlFunc.AggregateCount(a.S_CODE) })
.ToList();
list = materialRoadwayGroup.OrderByDescending(a => a.validCount).Select(a => a.Roadway).ToList();
}
return list;
}
///
/// 查找单货位
///
private static EndLocGroup FindSingleLocation(SqlSugarClient db, List candidateRoadways)
{
foreach (var roadway in candidateRoadways)
{
var location = db.Queryable()
.Where(a =>
a.S_AREA_CODE == Settings.stockArea &&
a.N_ROADWAY == roadway &&
a.N_CURRENT_NUM == 0 &&
a.N_LOCK_STATE == 0 &&
a.C_ENABLE == "Y")
.OrderBy(a => a.N_LAYER)
.OrderBy(a => a.N_COL)
.First();
if (location != null)
{
return new EndLocGroup
{
endLocList = new List { location }
};
}
}
return new EndLocGroup();
}
///
/// 查找双货位(优化相邻货位查找)
///
private static EndLocGroup FindDoubleLocations(SqlSugarClient db, List candidateRoadways)
{
// 先尝试找相邻货位
foreach (var roadway in candidateRoadways)
{
// 一次性获取巷道所有空货位(减少DB查询)
var emptyLocs = db.Queryable()
.Where(a =>
a.S_AREA_CODE == Settings.stockArea &&
a.N_ROADWAY == roadway &&
a.N_CURRENT_NUM == 0 &&
a.N_LOCK_STATE == 0 &&
a.C_ENABLE == "Y")
.OrderBy(a => a.N_LAYER)
.OrderBy(a => a.N_COL)
.ToList();
if (emptyLocs.Count < 2) continue;
// 在内存中查找相邻货位(高性能)
var adjacentPair = FindAdjacentLocations(emptyLocs);
if (adjacentPair != null)
{
return CreateDoubleLocGroup(adjacentPair);
}
}
// 没有相邻货位时,取任意两个货位
foreach (var roadway in candidateRoadways)
{
var emptyLocs = db.Queryable()
.Where(a =>
a.S_AREA_CODE == Settings.stockArea &&
a.N_ROADWAY == roadway &&
a.N_CURRENT_NUM == 0 &&
a.N_LOCK_STATE == 0 &&
a.C_ENABLE == "Y")
.OrderBy(a => a.N_LAYER)
.OrderBy(a => a.N_COL)
.Take(2)
.ToList();
if (emptyLocs.Count == 2)
{
return CreateDoubleLocGroup(emptyLocs);
}
}
return new EndLocGroup();
}
///
/// 在内存中查找相邻货位(高效算法)
///
private static List FindAdjacentLocations(List locations)
{
// 按层->列排序,便于查找相邻
var sorted = locations
.OrderBy(l => l.N_LAYER)
.ThenBy(l => l.N_ROW)
.ThenBy(l => l.N_COL)
.ToList();
for (int i = 0; i < sorted.Count - 1; i++)
{
var current = sorted[i];
var next = sorted[i + 1];
// 判断是否同一层且相邻列
if (current.N_LAYER == next.N_LAYER &&
current.N_COL + 1 == next.N_COL)
{
return new List { current, next };
}
}
return null;
}
///
/// 创建双货位返回结果
///
private static EndLocGroup CreateDoubleLocGroup(List locations)
{
return new EndLocGroup
{
endLocList = locations,
groupNo = locations.GroupBy(a => a.N_ROADWAY).Count() == 1
? WMSHelper.GenerateTaskGroupNo()
: null
};
}
public class EndLocGroup
{
public string groupNo { get; set; }
public List endLocList { get; set; }
}
///
/// 查询出库开始货位
/// 1.计算(1.巷道不报警、2.物料状态OK、3.小于失效时间 大于等于生效时间 4.加急料先出、5.先入先出(生产时间))出库物料
/// 2.同等条件下,优先取前一托货的相邻货位(暂时不做考虑,需确定先入先出(生产时间)是按天算,还是精确到时分秒)
///
///
///
public static Location getOutStockStartLoc(string itemCode, Location prevLoc = null)
{
var db = new SqlHelper().GetInstance();
Location startLoc = null;
// 1.查询(物料状态OK ,且小于失效时间,大于等于生效时间)出库物料,并按加急料先出,先入先出(生产时间)的原则进行排序
var query = db.Queryable()
.LeftJoin((a, b) => a.S_CODE == b.S_LOC_CODE)
.LeftJoin((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
.Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea
&& a.N_CURRENT_NUM == 1
&& a.N_LOCK_STATE == 0
&& a.C_ENABLE == "Y"
&& b.S_CNTR_CODE != null
);
if (itemCode != null)
{
query = query.Where((a, b, c) => c.S_ITEM_CODE == itemCode
&& 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)
.OrderByDescending((a, b, c) => c.N_URGENT_FLAG)
.OrderBy((a, b, c) => c.S_TXNDATE);
}
else
{
query = query.Where((a, b, c) => c.S_ITEM_CODE == itemCode);
}
var outLocList = query.ToList();
if (outLocList.Count > 0)
{
foreach (var loc in outLocList)
{
// 查询巷道是否正常,异常跳过
var stackerStates = WCSDispatch.getStackerState(loc.N_ROADWAY);
if ( false /*stackerStates.Count == 0 || stackerStates[0].roadway_state == "0" || stackerStates[0].roadway_state == "3"*/)
{
continue;
}
startLoc = loc;
break;
}
}
return startLoc;
}
public class StartLocGroup
{
public string groupNo { get; set; }
public List startLocList { get; set; }
}
///
/// 查询异常区空货位
///
///
public static Location getAbnormalAreaEmptyLoc(string areaCode)
{
Location location = new Location();
var db = new SqlHelper().GetInstance();
location = db.Queryable().Where(a => a.S_AREA_CODE == areaCode && a.N_CURRENT_NUM == 0 && a.C_ENABLE == "Y" && a.N_LOCK_STATE == 0).First();
return location;
}
///
/// 查询巷道任务最少的接驳位
///
///
public static Location getMinTaskMiddleLoc(int type , int roadway = 0 , int excludeRoadway = 0)
{
Location location = new Location();
var db = new SqlHelper().GetInstance();
var query = db.Queryable()
.LeftJoin((a, b) => a.S_CODE == b.S_END_LOC && b.N_B_STATE < 3)
.Where((a, b) => a.S_AREA_CODE == Settings.stockArea);
if (roadway != 0)
{
query = query.Where((a, b) => a.N_ROADWAY == roadway);
}
if (excludeRoadway != 0)
{
query = query.Where((a, b) => a.N_ROADWAY != excludeRoadway);
}
var roadwayGroup = query.GroupBy((a, b) => a.N_ROADWAY)
.Select((a, b) => new { roadway = a.N_ROADWAY, num = SqlFunc.AggregateDistinctCount(b.S_CODE != null) })
.OrderBy(a => a.num)
.ToList();
foreach (var item in roadwayGroup)
{
var connectLoc = Settings.connectLocList.Where(a => a.roadway == item.roadway).FirstOrDefault();
if (connectLoc != null)
{
location = LocationHelper.GetLoc(connectLoc.locCode);
break;
}
}
return location;
}
///
/// 查询上线货位
///
///
///
public static Location getOnlneLoc(int type)
{
Location location = null;
var connectLoc = Settings.onLineLocList.Where(a => a.type == type).FirstOrDefault();
if (connectLoc != null)
{
location = LocationHelper.GetLoc(connectLoc.locCode);
}
return location;
}
///
/// 查询叫料异常排出位
///
///
///
public static Location getCallOutLoc(int row)
{
Location location = null;
var connectLoc = Settings.callOutLocList.Where(a => a.row == row).FirstOrDefault();
if (connectLoc != null)
{
location = LocationHelper.GetLoc(connectLoc.locCode);
}
return location;
}
///
/// 查询物料存放时间配置信息
///
///
///
public static Overage getOverage(string bc_entried)
{
var db = new SqlHelper().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(sql, new { barcode = bc_entried, mcngrp = "0" });
var minhour_bar = db.Ado.SqlQuery(sql1, new { barcode = bc_entried, mcngrp = "0" });
if (ovg_bar.Count > 0 && minhour_bar.Count > 0)
{
Overage overage = new Overage()
{
MINHOUR = minhour_bar[0],
OVERAGE = ovg_bar[0]
};
return overage;
}
return null;
}
///
/// 绑定条码物料信息
///
///
///
///
public static bool bindBarcodeItemInfo( string cntrCode,GreenTireInformation greenTireInformation)
{
bool result = false;
var db = new SqlHelper().GetInstance();
var cntrItemRel = db.Queryable().Where(a => a.S_CNTR_CODE == cntrCode).First();
if (cntrItemRel == null)
{
var overage = getOverage(greenTireInformation.BARCODE);
DateTime txndate = DateTime.Parse(greenTireInformation.TXNDATE);
DateTime minTime = txndate.AddHours(overage.MINHOUR);
DateTime maxTime = txndate.AddDays(overage.OVERAGE);
cntrItemRel = new CntrItemRel()
{
S_CG_ID = greenTireInformation.BARCODE,
S_ITEM_CODE = greenTireInformation.ITEMCODE,
S_CNTR_CODE = cntrCode,
S_CELL_NO = greenTireInformation.TIRECODE,
F_QTY = greenTireInformation.QTY,
S_MCN = greenTireInformation.MCN,
S_OPR = greenTireInformation.OPR,
S_OPR02 = greenTireInformation.OPR02,
S_OPR03 = greenTireInformation.OPR03,
S_OPR04 = greenTireInformation.OPR04,
S_WINDUP = greenTireInformation.WINDUP,
S_TXNDATE = greenTireInformation.TXNDATE,
S_DATE_SHIFT = greenTireInformation.DATE_SHIFT,
S_EFFECTIVE_TIME = minTime.ToString("yyyy-MM-dd HH:mm:ss"),
S_EXPIRATION_TIME = maxTime.ToString("yyyy-MM-dd HH:mm:ss"),
};
result = db.Insertable(cntrItemRel).ExecuteCommand() > 0;
}
else
{
var overage = getOverage(greenTireInformation.BARCODE);
DateTime txndate = DateTime.Parse(greenTireInformation.TXNDATE);
DateTime minTime = txndate.AddHours(overage.MINHOUR);
DateTime maxTime = txndate.AddDays(overage.OVERAGE);
cntrItemRel.S_CG_ID = greenTireInformation.BARCODE;
cntrItemRel.S_ITEM_CODE = greenTireInformation.ITEMCODE;
cntrItemRel.S_CNTR_CODE = cntrCode;
cntrItemRel.S_CELL_NO = greenTireInformation.TIRECODE;
cntrItemRel.F_QTY = greenTireInformation.QTY;
cntrItemRel.S_MCN = greenTireInformation.MCN;
cntrItemRel.S_OPR = greenTireInformation.OPR;
cntrItemRel.S_OPR02 = greenTireInformation.OPR02;
cntrItemRel.S_OPR03 = greenTireInformation.OPR03;
cntrItemRel.S_OPR04 = greenTireInformation.OPR04;
cntrItemRel.S_WINDUP = greenTireInformation.WINDUP;
cntrItemRel.S_TXNDATE = greenTireInformation.TXNDATE;
cntrItemRel.S_DATE_SHIFT = greenTireInformation.DATE_SHIFT;
cntrItemRel.S_EFFECTIVE_TIME = minTime.ToString("yyyy-MM-dd HH:mm:ss");
cntrItemRel.S_EXPIRATION_TIME = maxTime.ToString("yyyy-MM-dd HH:mm:ss");
result = db.Updateable(cntrItemRel).ExecuteCommand() > 0;
}
return result;
}
///
/// 查询硫化工单
///
///
///
///
///
public static ProductionShedule getProductionShedule(string dateShift ,string mcn ,string shift)
{
var db = new SqlHelper().GetInstance();
return db.Queryable().Where(a => a.DATESHIFT == dateShift && a.MCN == mcn && a.SHIFT == shift).First();
}
///
/// 查询胚胎完成硫化的数量
///
///
public static int getEmbryoFinishNum(string dateShift, string mcn, string shift)
{
var db = new SqlHelper().GetInstance();
return db.Queryable().Where(a => a.DATE_SHIFT == dateShift && a.CUR_MCN == mcn && a.CUR_SHIFT == shift).Count();
}
}
}