| | |
| | | using HH.WCS.HangYang.api; |
| | | using HH.WCS.HangYang.LISTA.models; |
| | | using HH.WCS.HangYang.LISTA.models.wms; |
| | | using HH.WCS.HangYang.models.other; |
| | | using HH.WCS.HangYang.util; |
| | | using Newtonsoft.Json; |
| | |
| | | using System; |
| | | using System.Collections.Concurrent; |
| | | using System.Collections.Generic; |
| | | using System.IdentityModel.Protocols.WSTrust; |
| | | using System.Linq; |
| | | using System.Linq.Expressions; |
| | | using System.Reflection; |
| | | using System.Runtime.Remoting.Messaging; |
| | | using System.Security.Cryptography; |
| | | using System.Security.Cryptography.X509Certificates; |
| | | using System.Text; |
| | | using System.Threading; |
| | |
| | | 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) |
| | |
| | | throw new NotImplementedException(); |
| | | } |
| | | |
| | | internal static Location GetStart(WMSTask a) |
| | | { |
| | | throw new NotImplementedException(); |
| | | } |
| | | |
| | | internal static void UpdateTaskState(WMSTask task) |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | |
| | | return db.Updateable<WMSTask>(a).UpdateColumns(it => new { it.S_END_LOC, 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(); |
| | | } |
| | | |
| | | |
| | | |
| | | internal static void CreateSortingOrderDetail(string so_no) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取开始配货的分拣单,一次性生成分拣明细,避免生成一半再生成,所以创建分拣明细的时候加上事务 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | internal static List<SortingOrder> GetWaitingSortingOrderList() |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | return db.Queryable<SortingOrder>().Includes(a => a.Composes).Where(a => a.N_B_STATE == 1 || a.N_B_STATE == 20).ToList(); |
| | | } |
| | | /// <summary> |
| | | /// 获取配货完成的分拣单,每个分拣单单独创建分拣作业 |
| | | /// </summary> |
| | |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | #region 杭氧WMS帮助方法 |
| | | /// <summary> |
| | | /// 新增入库单 |
| | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogHelper.Error("创建入库单失败", ex, "杭氧"); |
| | | var sugarEx = ex as SqlSugar.SqlSugarException; |
| | | if (sugarEx != null) |
| | | { |
| | | LogHelper.Error($"创建入库单SQL错误: {sugarEx.Sql}", sugarEx, "杭氧"); |
| | | } |
| | | else |
| | | { |
| | | LogHelper.Error($"创建入库单失败:{ex.Message}", ex, "杭氧"); |
| | | } |
| | | return false; |
| | | } |
| | | |
| | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogHelper.Error("创建出库单失败", ex, "杭氧"); |
| | | LogHelper.Error($"创建出库单失败:{ex.Message}", ex, "杭氧"); |
| | | return false; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 根据托盘查询货位明细 |
| | | /// </summary> |
| | | /// <param name="trayCode">托盘号</param> |
| | | /// <returns></returns> |
| | | internal static LocCntrRel GetCntrLoc(string trayCode) |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | |
| | | var locCntr = db.Queryable<LocCntrRel>().Where(a => a.S_CNTR_CODE.Trim() == trayCode).First(); |
| | | var locList = db.Queryable<Location>().Where(p => p.S_CODE == locCntr.S_LOC_CODE |
| | | && p.N_CURRENT_NUM == p.N_CAPACITY |
| | | && p.S_LOCK_STATE.Trim() == "无" |
| | | && p.S_AREA_CODE == "JXHCQ").First(); |
| | | if (locList == null) |
| | | { |
| | | return null; |
| | | } |
| | | return locCntr; |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 任务状态转换 |
| | | /// </summary> |
| | | /// <param name="state">状态号</param> |
| | |
| | | /// </summary> |
| | | /// <param name="state">配盘单状态</param> |
| | | /// <returns></returns> |
| | | internal static List<DistributionCntr> GetPickingListByState(string state) |
| | | internal static List<DistributionCntr> GetPickingListByState(int state) |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var distributionCntr = db.Queryable<DistributionCntr>().Where(a => a.S_B_STATE.Trim() == state).ToList(); |
| | | var distributionCntr = db.Queryable<DistributionCntr>().Where(a => a.N_B_STATE == state).ToList(); |
| | | return distributionCntr; |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 配盘单状态转换 |
| | | /// </summary> |
| | | /// <param name="state">状态号</param> |
| | | /// <returns></returns> |
| | | internal static string GetDistributionStateStr(int state) |
| | | { |
| | | var status = ""; |
| | | switch (state) |
| | | { |
| | | case 1: status = "已配货"; break; |
| | | case 2: status = "出库中"; break; |
| | | case 3: status = "已出库"; break; |
| | | case 4: status = "分拣完成 "; break; |
| | | |
| | | } |
| | | return status; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 修改配盘单状态 |
| | | /// </summary> |
| | | /// <param name="taskState">作业状态</param> |
| | | /// <param name="state">状态</param> |
| | | /// <param name="trayCode">托盘号</param> |
| | | /// <returns></returns> |
| | | internal static bool UpdateDistributionCntrState(string state,string trayCode) |
| | | internal static bool UpdateDistributionCntrState(int taskState, int state, string trayCode) |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var distributionCntr = db.Queryable<DistributionCntr>().Where(a => a.S_B_STATE.Trim() == "配货完成" && a.S_CNTR_CODE == trayCode ).First(); |
| | | var distributionCntr = db.Queryable<DistributionCntr>().Where(a => a.N_B_STATE == taskState && a.S_CNTR_CODE == trayCode).First(); |
| | | if (distributionCntr != null) |
| | | { |
| | | |
| | | distributionCntr.S_B_STATE = state; |
| | | distributionCntr.N_B_STATE = 2; |
| | | distributionCntr.N_B_STATE = state; |
| | | distributionCntr.S_B_STATE = GetDistributionStateStr(state); |
| | | return db.Updateable<DistributionCntr>(distributionCntr).UpdateColumns(it => new { it.S_B_STATE, it.N_B_STATE }).ExecuteCommand() > 0; |
| | | } |
| | | return false; |
| | |
| | | return res; |
| | | } |
| | | |
| | | internal static bool UpdateTask(WMSTask a, int state) |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | a.T_MODIFY = DateTime.Now; |
| | | a.N_B_STATE = state; |
| | | a.S_B_STATE = GetStateStr(state); |
| | | return db.Updateable<WMSTask>(a).UpdateColumns(it => new { it.N_B_STATE, it.S_B_STATE, it.S_CNTR_CODE, it.S_START_LOC, it.T_MODIFY }).ExecuteCommand() > 0; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 杭氧立库出入库逻辑算法 |
| | | |
| | | |
| | | /// <summary> |
| | | /// 立库入库封装算法 |
| | | /// </summary> |
| | |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var locations = db.Queryable<Location>().Where(a => a.S_AREA_CODE == inbound.areaCode).ToList(); |
| | | if(!string.IsNullOrEmpty(inbound.roadWay.ToString())) |
| | | if (inbound.roadWay != 0) |
| | | { |
| | | locations.RemoveAll(s => s.N_ROADWAY != inbound.roadWay); |
| | | } |
| | |
| | | return null; // 无可用位置 |
| | | } |
| | | private readonly ConcurrentDictionary<string, SemaphoreSlim> _locationLocks = new ConcurrentDictionary<string, SemaphoreSlim>(); |
| | | |
| | | |
| | | public async Task<LocationParams> StoreItemAsync() |
| | | { |
| | | LocationParams location = null; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 立库出库封装算法 |
| | | /// 配盘出库封装算法 |
| | | /// </summary> |
| | | public class DoubleDeepOutboundScheduler |
| | | { |
| | |
| | | |
| | | // 生成出库任务队列(含移库任务) |
| | | /// <summary> |
| | | /// 立库WMS货位出库算法(运用于配盘单出库、空托出库) |
| | | /// 立库WMS货位出库算法(运用于配盘单出库) |
| | | /// </summary> |
| | | /// <param name="outbound">出库参数</param> |
| | | /// <returns></returns> |
| | |
| | | var wmsTask = WMSHelper.GetWmsTaskList("执行", outboundItem.trayCode); |
| | | if (wmsTask == null) |
| | | { |
| | | LogHelper.Info($"未查询到在执行中的作业:{outboundItem.trayCode}!", "杭氧"); |
| | | //LogHelper.Info($"未查询到在执行中的作业:{outboundItem.trayCode}!", "杭氧"); |
| | | outboundItem.opCode = ""; |
| | | } |
| | | |
| | |
| | | .Where(x => x.S_CODE == outerLoc.S_CODE) |
| | | .ToList() |
| | | .ForEach(x => x.N_LOCK_STATE = 3); |
| | | var trayCode = ContainerHelper.GetLocCntr(outerLoc.S_CODE); |
| | | tasks.Add(new WCSTask |
| | | { |
| | | S_CODE = GenerateTaskNo(), |
| | |
| | | N_SCHEDULE_TYPE = 1, |
| | | N_B_STATE = 0, |
| | | S_B_STATE = WCSTask.GetStateStr(0), |
| | | S_CNTR_CODE = outboundItem.trayCode, |
| | | S_CNTR_CODE = trayCode.S_CNTR_CODE, |
| | | N_START_LAYER = 1, |
| | | N_END_LAYER = 1, |
| | | N_CNTR_COUNT = 1 |
| | | }); |
| | | } |
| | | else continue; |
| | | |
| | | } |
| | | else |
| | | { |
| | | //货位为空直接生成出库任务 |
| | | tasks.Add(CreateOutboundTask(targetLoc,outboundItem)); |
| | | } |
| | | } |
| | | else continue; |
| | | |
| | | else |
| | | { |
| | | continue; |
| | | } |
| | | // 2.2 生成出库任务(深位) |
| | | tasks.Add(CreateOutboundTask(targetLoc, outboundItem)); |
| | | } |
| | |
| | | // 3. 非双深位直接出库 |
| | | tasks.Add(CreateOutboundTask(targetLoc, outboundItem)); |
| | | } |
| | | break; |
| | | } |
| | | // 4. 任务排序:移库任务优先 + 高优先级优先 |
| | | return tasks; |
| | |
| | | loc.N_ROADWAY == deepLoc.N_ROADWAY && |
| | | loc.N_COL == deepLoc.N_COL && |
| | | loc.N_LAYER == deepLoc.N_LAYER && |
| | | loc.N_LOCK_STATE == 0 |
| | | loc.N_LOCK_STATE == 0 || loc.N_LOCK_STATE == 5 |
| | | ); |
| | | |
| | | private Location FindBestRelocationTarget(Location outerLoc) |
| | | { |
| | | return _allLocations |
| | | .Where(loc => |
| | | loc.N_ROADWAY == outerLoc.N_ROADWAY && |
| | | loc.N_LOCK_STATE == 0 && |
| | | loc.N_CURRENT_NUM == 0 && |
| | | loc.S_CODE != outerLoc.S_CODE) |
| | | .OrderBy(loc => loc.N_ROW == outerLoc.N_ROW ? 1 : 0) |
| | | .ThenBy(loc => loc.N_COL) |
| | | .ThenBy(loc => Math.Abs(loc.N_LAYER - outerLoc.N_LAYER)) |
| | | .FirstOrDefault(); |
| | | return _allLocations |
| | | .Where(loc => |
| | | loc.N_ROADWAY == outerLoc.N_ROADWAY && |
| | | loc.N_LOCK_STATE == 0 && |
| | | loc.N_CURRENT_NUM == 0 && |
| | | loc.S_CODE != outerLoc.S_CODE) |
| | | .OrderBy(loc => loc.N_ROW == outerLoc.N_ROW ? 1 : 0) |
| | | .ThenBy(loc => loc.N_COL) |
| | | .ThenBy(loc => Math.Abs(loc.N_LAYER - outerLoc.N_LAYER)) |
| | | .FirstOrDefault(); |
| | | } |
| | | |
| | | private WCSTask CreateOutboundTask(Location loc,Outbound outbound) => |
| | | private WCSTask CreateOutboundTask(Location loc, Outbound outbound) => |
| | | new WCSTask |
| | | { |
| | | S_CODE = GenerateTaskNo(), |
| | |
| | | S_END_LOC = outbound.endBit, |
| | | S_TYPE = outbound.taskType, |
| | | S_OP_CODE = outbound.opCode, |
| | | N_PRIORITY = 1, |
| | | N_PRIORITY = 0, |
| | | N_SCHEDULE_TYPE = 1, |
| | | N_B_STATE = 0, |
| | | S_B_STATE = WCSTask.GetStateStr(0), |
| | |
| | | _allLocations |
| | | .Where(x => x.S_CODE == outerLoc.S_CODE) |
| | | .ToList() |
| | | .ForEach(x => x.N_LOCK_STATE = 3); |
| | | .ForEach(x => x.N_LOCK_STATE = 5); |
| | | //标记深位的外侧货位为5 |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | |
| | | public class EmptyPalletOutboundScheduler |
| | | { |
| | | private readonly List<Location> _allLocations; |
| | | |
| | | public EmptyPalletOutboundScheduler(string areaCode) |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | _allLocations = db.Queryable<Location>() |
| | | .Where(a => a.S_AREA_CODE == areaCode) |
| | | .ToList(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 空托盘出库算法(自动寻找可用空托并生成任务) |
| | | /// </summary> |
| | | public List<WCSTask> GenerateEmptyPalletTasks(Outbound outbound) |
| | | { |
| | | var tasks = new List<WCSTask>(); |
| | | var foundPallets = 0; |
| | | |
| | | if (foundPallets < outbound.requiredCount) |
| | | { |
| | | var doubleDeepPallets = FindDoubleDeepEmptyPallets(); |
| | | foreach (var palletLoc in doubleDeepPallets) |
| | | { |
| | | if (IsDoubleDeepRow(palletLoc.N_ROW)) |
| | | { |
| | | var outerLoc = FindOuterLocation(palletLoc); |
| | | if (outerLoc != null) |
| | | { |
| | | if (outerLoc.N_CURRENT_NUM == outerLoc.N_CAPACITY) |
| | | { |
| | | // 优先移到深位,其次外侧 |
| | | var bestTarget = FindBestRelocationTarget(outerLoc); |
| | | if (bestTarget != null) |
| | | { |
| | | //计算到了外侧把外侧的货位锁定 |
| | | _allLocations |
| | | .Where(x => x.S_CODE == outerLoc.S_CODE) |
| | | .ToList() |
| | | .ForEach(x => x.N_LOCK_STATE = 3); |
| | | var trayCode = ContainerHelper.GetLocCntr(outerLoc.S_CODE); |
| | | |
| | | tasks.Add(new WCSTask |
| | | { |
| | | S_CODE = GenerateTaskNo(), |
| | | S_START_AREA = outerLoc.S_AREA_CODE, |
| | | S_END_AREA = bestTarget.S_AREA_CODE, |
| | | S_START_LOC = outerLoc.S_CODE, |
| | | S_END_LOC = bestTarget.S_CODE, |
| | | S_TYPE = "深位移库", |
| | | S_OP_CODE = outbound.opCode, |
| | | N_PRIORITY = 1, |
| | | N_SCHEDULE_TYPE = 1, |
| | | N_B_STATE = 0, |
| | | S_B_STATE = WCSTask.GetStateStr(0), |
| | | S_CNTR_CODE = trayCode.S_CNTR_CODE, |
| | | N_START_LAYER = 1, |
| | | N_END_LAYER = 1, |
| | | N_CNTR_COUNT = 1 |
| | | }); |
| | | } |
| | | else continue; |
| | | } |
| | | } |
| | | } |
| | | var tray = ContainerHelper.GetLocCntr(palletLoc.S_CODE); |
| | | outbound.trayCode = tray.S_CNTR_CODE; |
| | | tasks.Add(CreateEmptyPalletTask(palletLoc, outbound)); |
| | | foundPallets++; |
| | | |
| | | if (foundPallets >= outbound.requiredCount) break; |
| | | } |
| | | } |
| | | return tasks; |
| | | } |
| | | |
| | | // 关键辅助方法 |
| | | |
| | | private List<Location> FindDoubleDeepEmptyPallets() => |
| | | _allLocations.Where(loc => |
| | | loc.N_LOCK_STATE == 0 && |
| | | loc.N_CURRENT_NUM == loc.N_CAPACITY && |
| | | ContainerHelper.GetLocItemRel(loc.S_CODE) |
| | | ).OrderBy(loc => loc.N_ROW) // 按排排序 |
| | | .ThenBy(loc => loc.N_COL) |
| | | .ToList(); |
| | | |
| | | private WCSTask CreateEmptyPalletTask(Location loc, Outbound outbound) => |
| | | new WCSTask |
| | | { |
| | | S_CODE = GenerateTaskNo(), |
| | | S_START_AREA = loc.S_AREA_CODE, |
| | | S_END_AREA = outbound.endArea, |
| | | S_START_LOC = loc.S_CODE, |
| | | S_END_LOC = outbound.endBit, |
| | | S_TYPE = outbound.taskType, |
| | | S_OP_CODE = outbound.opCode, |
| | | N_PRIORITY = 0, |
| | | N_SCHEDULE_TYPE = 1, |
| | | N_B_STATE = 0, |
| | | S_B_STATE = WCSTask.GetStateStr(0), |
| | | S_CNTR_CODE = outbound.trayCode, |
| | | N_START_LAYER = 1, |
| | | N_END_LAYER = 1, |
| | | N_CNTR_COUNT = 1 |
| | | }; |
| | | |
| | | // 复用原有双深位方法 |
| | | private bool IsDoubleDeepRow(int row) => row == 1 || row == 4; |
| | | |
| | | private Location FindTargetLocation(string code) => |
| | | _allLocations.FirstOrDefault(loc => |
| | | loc.S_CODE == code && loc.N_LOCK_STATE == 0); |
| | | |
| | | //查询深位外侧的货位 |
| | | private Location FindOuterLocation(Location deepLoc) => |
| | | _allLocations.FirstOrDefault(loc => |
| | | loc.N_ROW != deepLoc.N_ROW && |
| | | loc.N_ROADWAY == deepLoc.N_ROADWAY && |
| | | loc.N_COL == deepLoc.N_COL && |
| | | loc.N_LAYER == deepLoc.N_LAYER && |
| | | loc.N_LOCK_STATE == 0 || loc.N_LOCK_STATE == 5 |
| | | ); |
| | | private Location FindBestRelocationTarget(Location outerLoc) |
| | | { |
| | | return _allLocations |
| | | .Where(loc => |
| | | loc.N_ROADWAY == outerLoc.N_ROADWAY && |
| | | loc.N_LOCK_STATE == 0 && |
| | | loc.N_CURRENT_NUM == 0 && |
| | | loc.S_CODE != outerLoc.S_CODE) |
| | | .OrderBy(loc => loc.N_ROW == outerLoc.N_ROW ? 1 : 0) |
| | | .ThenBy(loc => loc.N_COL) |
| | | .ThenBy(loc => Math.Abs(loc.N_LAYER - outerLoc.N_LAYER)) |
| | | .FirstOrDefault(); |
| | | } |
| | | private void MarkReservedLocations(List<Outbound> outbound) |
| | | { |
| | | //查询已经被锁住的货位 |
| | | var lockLoc = _allLocations |
| | | .Where(loc => loc.N_LOCK_STATE != 0) |
| | | .ToList(); |
| | | //把锁住的货位标记为占用 |
| | | foreach (var item in lockLoc) |
| | | { |
| | | if (IsDoubleDeepRow(item.N_ROW)) |
| | | { |
| | | _allLocations |
| | | .Where(x => x.S_CODE == item.S_CODE) |
| | | .ToList() |
| | | .ForEach(x => x.N_LOCK_STATE = 3); |
| | | } |
| | | } |
| | | foreach (var item in outbound) |
| | | { |
| | | var loc = FindTargetLocation(item.locCode); |
| | | if (loc != null && IsDoubleDeepRow(loc.N_ROW)) |
| | | { |
| | | // 标记该深位对应的外侧货位(如果存在) |
| | | var outerLoc = FindOuterLocation(loc); |
| | | if (outerLoc != null) |
| | | { |
| | | // 标记深位的外侧货位(避免被移库占用) |
| | | _allLocations |
| | | .Where(x => x.S_CODE == outerLoc.S_CODE) |
| | | .ToList() |
| | | .ForEach(x => x.N_LOCK_STATE = 5); |
| | | //标记深位的外侧货位为5 |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region 杭氧升降量表帮助方法 |
| | | /// <summary> |
| | | /// MD5加密 |
| | | /// </summary> |
| | | /// <param name="sInput"></param> |
| | | /// <returns></returns> |
| | | public static string GetMd5FromString(string sInput) |
| | | { |
| | | var lstData = Encoding.GetEncoding("utf-8").GetBytes(sInput); |
| | | var lstHash = new MD5CryptoServiceProvider().ComputeHash(lstData); |
| | | var result = new StringBuilder(32); |
| | | for (int i = 0; i < lstHash.Length; i++) |
| | | { |
| | | result.Append(lstHash[i].ToString("x2").ToUpper()); |
| | | } |
| | | return result.ToString(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 根据任务升量 |
| | | /// </summary> |
| | | /// <param name="task"></param> |
| | | internal static bool AddChange(WCSTask task) |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var result = true; |
| | | try |
| | | { |
| | | var itemlist = db.Queryable<CntrItemDetail>().Where(a => a.S_CNTR_CODE == task.S_CNTR_CODE).ToList(); |
| | | if (itemlist.Count > 0) |
| | | { |
| | | var url = Settings.MoboxSeverUrl + "inventory/AddChange"; |
| | | //仓库量表升量 |
| | | var req = new AddChangeModel { op_type = 5 }; |
| | | //库区量表升量 |
| | | var req2 = new AddChangeModel { op_type = 6 }; |
| | | itemlist.ForEach(a => |
| | | { |
| | | LogHelper.Info($"填充数据"); |
| | | LogHelper.Info($"添加仓库量表数据 仓库{task.S_END_WH} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); |
| | | req.item_info.Add(new AddChangeModel.itemModel |
| | | { |
| | | wh_code = task.S_END_WH, |
| | | item_code = a.S_ITEM_CODE, |
| | | item_name = a.S_ITEM_NAME, |
| | | qty = a.F_QTY |
| | | }); |
| | | LogHelper.Info($"添加库区量表数据 库区{task.S_END_AREA} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); |
| | | req2.item_info.Add(new AddChangeModel.itemModel |
| | | { |
| | | wh_code = task.S_END_WH, |
| | | area_code = task.S_END_AREA, |
| | | item_code = a.S_ITEM_CODE, |
| | | item_name = a.S_ITEM_NAME, |
| | | qty = a.F_QTY |
| | | }); |
| | | }); |
| | | var reqData = JsonConvert.SerializeObject(req); |
| | | var AppKey = Settings.AppKey; |
| | | var AppSecret = Settings.AppSecret; |
| | | var ReqTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); |
| | | //var ReqTime = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); |
| | | LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime}"); |
| | | var ReqVerify = GetMd5FromString(AppKey + AppSecret + ReqTime); |
| | | LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime} ReqVerify={ReqVerify} url={url} req={reqData}"); |
| | | var res = new HttpHelper().WebPost(url, reqData, "application/json", AppKey, ReqTime, ReqVerify); |
| | | if (!string.IsNullOrEmpty(res)) |
| | | { |
| | | LogHelper.Info($"mobox 仓库升量接口返回 {res}"); |
| | | var moboxres = JsonConvert.DeserializeObject<moboxres>(res); |
| | | if (moboxres.err_code != 0) |
| | | { |
| | | result = false; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | LogHelper.Info($"mobox 仓库升量接口返回为空"); |
| | | result = false; |
| | | } |
| | | var reqData2 = JsonConvert.SerializeObject(req2); |
| | | var ReqTime2 = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); |
| | | //var ReqTime2 = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); |
| | | LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2}"); |
| | | var ReqVerify2 = GetMd5FromString(AppKey + AppSecret + ReqTime2); |
| | | LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2} ReqVerify={ReqVerify2} url={url} req={reqData2}"); |
| | | var res2 = new HttpHelper().WebPost(url, reqData2, "application/json", AppKey, ReqTime2, ReqVerify2); |
| | | if (!string.IsNullOrEmpty(res2)) |
| | | { |
| | | LogHelper.Info($"mobox 库区升量接口返回 {res2}"); |
| | | var moboxres = JsonConvert.DeserializeObject<moboxres>(res); |
| | | if (moboxres.err_code != 0) |
| | | { |
| | | result = false; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | LogHelper.Info($"mobox 库区升量接口返回为空"); |
| | | result = false; |
| | | } |
| | | |
| | | } |
| | | else LogHelper.Info($"托盘{task.S_CNTR_CODE} 在容器货品明细中找不到数据"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogHelper.Error($"仓库升量异常 异常信息={ex.Message}", ex); |
| | | result = false; |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 根据任务降量 |
| | | /// </summary> |
| | | /// <param name="task"></param> |
| | | internal static bool DeleteChange(WCSTask wmstask) |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var result = true; |
| | | try |
| | | { |
| | | //var wmstask = db.Queryable<WCSTask>().Where(a => a == task.S_OP_CODE).First(); |
| | | if (wmstask != null) |
| | | { |
| | | var itemlist = db.Queryable<CntrItemDetail>().Where(a => a.S_CNTR_CODE == wmstask.S_CNTR_CODE).ToList(); |
| | | if (itemlist.Count > 0) |
| | | { |
| | | var url = Settings.MoboxSeverUrl + "inventory/AddChange"; |
| | | //仓库量表降量 |
| | | var req = new AddChangeModel { op_type = 8 }; |
| | | //库区量表降量 |
| | | var req2 = new AddChangeModel { op_type = 9 }; |
| | | itemlist.ForEach(a => |
| | | { |
| | | LogHelper.Info($"填充数据"); |
| | | LogHelper.Info($"减仓库量表数据 仓库{wmstask.S_START_WH} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); |
| | | req.item_info.Add(new AddChangeModel.itemModel |
| | | { |
| | | wh_code = wmstask.S_START_WH, |
| | | item_code = a.S_ITEM_CODE, |
| | | item_name = a.S_ITEM_NAME, |
| | | qty = a.F_QTY |
| | | }); |
| | | LogHelper.Info($"减库区量表数据 库区{wmstask.S_START_AREA} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); |
| | | req2.item_info.Add(new AddChangeModel.itemModel |
| | | { |
| | | wh_code = wmstask.S_START_WH, |
| | | area_code = wmstask.S_START_AREA, |
| | | item_code = a.S_ITEM_CODE, |
| | | item_name = a.S_ITEM_NAME, |
| | | qty = a.F_QTY |
| | | }); |
| | | }); |
| | | var reqData = JsonConvert.SerializeObject(req); |
| | | var AppKey = Settings.AppKey; |
| | | var AppSecret = Settings.AppSecret; |
| | | var ReqTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); |
| | | //var ReqTime = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); |
| | | LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime}"); |
| | | var ReqVerify = GetMd5FromString(AppKey + AppSecret + ReqTime); |
| | | LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime} ReqVerify={ReqVerify} url={url} req={reqData}"); |
| | | var res = new HttpHelper().WebPost(url, reqData, "application/json", AppKey, ReqTime, ReqVerify); |
| | | if (!string.IsNullOrEmpty(res)) |
| | | { |
| | | LogHelper.Info($"mobox 仓库降量接口返回 {res}"); |
| | | var moboxres = JsonConvert.DeserializeObject<moboxres>(res); |
| | | if (moboxres.err_code != 0) |
| | | { |
| | | result = false; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | LogHelper.Info($"mobox 仓库降量接口返回为空"); |
| | | result = false; |
| | | } |
| | | var reqData2 = JsonConvert.SerializeObject(req2); |
| | | var ReqTime2 = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); |
| | | //var ReqTime2 = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); |
| | | LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2}"); |
| | | var ReqVerify2 = GetMd5FromString(AppKey + AppSecret + ReqTime2); |
| | | LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2} ReqVerify={ReqVerify2} url={url} req={reqData2}"); |
| | | var res2 = new HttpHelper().WebPost(url, reqData2, "application/json", AppKey, ReqTime2, ReqVerify2); |
| | | if (!string.IsNullOrEmpty(res2)) |
| | | { |
| | | LogHelper.Info($"mobox 库区降量接口返回 {res2}"); |
| | | var moboxres = JsonConvert.DeserializeObject<moboxres>(res); |
| | | if (moboxres.err_code != 0) |
| | | { |
| | | result = false; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | LogHelper.Info($"mobox 库区降量接口返回为空"); |
| | | result = false; |
| | | } |
| | | |
| | | } |
| | | else LogHelper.Info($"托盘{wmstask.S_CNTR_CODE} 在容器货品明细中找不到数据"); |
| | | } |
| | | else LogHelper.Info($"未找到任务{wmstask.S_CODE} 对应的任务"); |
| | | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogHelper.Error($"仓库降量异常 异常信息={ex.Message}", ex); |
| | | result = false; |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | } |
| | | } |