| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239 |
- using AutoMapper;
- using Microsoft.Extensions.Logging;
- using Newtonsoft.Json;
- using SqlSugar;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using WCS.Entity.sx;
- using wms.dto;
- using wms.dto.request;
- using wms.dto.request.share;
- using wms.dto.request.sx;
- using wms.dto.response;
- using wms.dto.response.sx;
- using wms.service.Help.LayerPacking;
- using wms.service.Help.LayerPacking.model;
- using wms.service.Service;
- using wms.sqlsugar;
- using wms.sqlsugar.model.sx;
- using wms.util.Ext;
- using wms.util.Http;
- using TaskStatus = wms.dto.TaskStatus;
- namespace wms.service.Help.Packing
- {
- /// <summary>
- /// 层配装箱帮助类
- /// </summary>
- public class SxLayerPackingHelp
- {
- private readonly Repository<BaseWarecell> _wareCell;
- private readonly Repository<BillInvnow> _invNow;
- private readonly Repository<BillPboxrule> _boxRule;
- private readonly Repository<sxSysConfig> _sysconfing;
- private readonly RepositoryTask<BillTimeOutRecord> _timeoutrecord;
- private readonly ILogger<SXService> _logger;
- private readonly Repository<PalletLayerMath> _palletLayerMath;
- private readonly Repository<BillInvflow> _invFlow;
- private readonly RepositoryTask<WCS_TaskOld> _wcsTaskOld;
- private readonly Repository<BaseWarehouse> _wareHouse;
- private readonly RepositoryTask<WCS_TaskDtl> _taskDetail;
- private readonly RepositoryTask<WCS_TaskInfo> _task;
- private readonly Repository<Palletizing> _palletiz;
- private readonly ITenant _db;
- private readonly IMapper _mapper;
- private readonly object _lockerPalletizingPackTask;
- private readonly object _lockerApplyLoc;
- /// <summary>
- /// 构造函数
- /// </summary>
- public SxLayerPackingHelp(
- Repository<BaseWarecell> wareCell,
- Repository<BillInvnow> invNow,
- Repository<BillPboxrule> boxRule,
- Repository<sxSysConfig> sysconfing,
- RepositoryTask<BillTimeOutRecord> timeoutrecord,
- ILogger<SXService> logger,
- Repository<PalletLayerMath> palletLayerMath,
- Repository<BillInvflow> invFlow,
- RepositoryTask<WCS_TaskOld> wcsTaskOld,
- Repository<BaseWarehouse> wareHouse,
- RepositoryTask<WCS_TaskDtl> taskDetail,
- RepositoryTask<WCS_TaskInfo> task,
- Repository<Palletizing> palletiz,
- ITenant db,
- IMapper mapper,
- object lockerPalletizingPackTask,
- object lockerApplyLoc)
- {
- _wareCell = wareCell;
- _invNow = invNow;
- _boxRule = boxRule;
- _sysconfing = sysconfing;
- _timeoutrecord = timeoutrecord;
- _logger = logger;
- _palletLayerMath = palletLayerMath;
- _invFlow = invFlow;
- _wcsTaskOld = wcsTaskOld;
- _wareHouse = wareHouse;
- _taskDetail = taskDetail;
- _task = task;
- _palletiz = palletiz;
- _db = db;
- _mapper = mapper;
- _lockerPalletizingPackTask = lockerPalletizingPackTask;
- _lockerApplyLoc = lockerApplyLoc;
- }
- #region 获取可用库存
- /// <summary>
- /// 获取可用库存
- /// </summary>
- /// <returns></returns>
- public IEnumerable<LayerPackingProduct> GetAvailableInventory()
- {
- int timeOutHoldHours = 72;
- var timeOut = _sysconfing.GetFirst(p => p.Code == "CP_TimeOutHoldHours");
- if (timeOut != null) timeOutHoldHours = int.Parse(timeOut.SContent);
- var normalInventory = GetNormalInventory(timeOutHoldHours);
- var reworkInventory = GetReworkInventory(timeOutHoldHours);
- var torsInventory = GetTorsInventory(timeOutHoldHours);
- var torsReworkInventory = GetTorsReworkInventory(timeOutHoldHours);
- var allInventory = normalInventory
- .Union(reworkInventory)
- .Union(torsInventory)
- .Union(torsReworkInventory)
- .Distinct(new CompareProduct());
- return FilterByTunnelRestrictions(allInventory);
- }
- /// <summary>
- /// 获取非检测非重绕盘
- /// </summary>
- /// <param name="timeOutHoldHours">超时小时</param>
- /// <returns></returns>
- private IEnumerable<LayerPackingProduct> GetNormalInventory(int timeOutHoldHours)
- {
- return from loc in _wareCell.GetList(p =>
- p.IsStop == LocationStop.LocationInvoke.GetHashCode() &&
- p.StateNum == LocationState.LocationState_Full)
- join stock in _invNow.GetList(p =>
- p.InvStateCode == InvState.InvEcecState_In.ToString() &&
- p.ExecStateCode == InvLockState.InvState_Normal.ToString() &&
- p.Grade == "A" &&
- !p.IsControlpanel &&
- !p.IsTorsChk &&
- string.IsNullOrEmpty(p.PreStock) &&
- p.ContUsageQty <= 0 &&
- !p.ProductMachCode.Contains("R") &&
- (DateTime.Now - p.ProductTime).TotalHours < timeOutHoldHours)
- on loc.ContGrpBarCode equals stock.ContGrpBarCode
- join rule in _boxRule.AsQueryable().Where(p => p.PackRule == "CP").Select(p => new { p.DocsNo, p.SkuCode }).Distinct().ToList()
- on stock.InDocsNo equals rule.DocsNo
- select CreateStockTemp(loc, stock, rule.SkuCode);
- }
- /// <summary>
- /// 获取非检测重绕盘
- /// </summary>
- /// <param name="timeOutHoldHours">超时小时</param>
- /// <returns></returns>
- private IEnumerable<LayerPackingProduct> GetReworkInventory(int timeOutHoldHours)
- {
- return from loc in _wareCell.GetList(p =>
- p.IsStop == LocationStop.LocationInvoke.GetHashCode() &&
- p.StateNum == LocationState.LocationState_Full)
- join stock in _invNow.GetList(p =>
- p.InvStateCode == InvState.InvEcecState_In.ToString() &&
- p.ExecStateCode == InvLockState.InvState_Normal.ToString() &&
- p.Grade == "A" &&
- !p.IsControlpanel &&
- !p.IsTorsChk &&
- string.IsNullOrEmpty(p.PreStock) &&
- p.ContUsageQty <= 0 &&
- p.ProductMachCode.Contains("R") &&
- (DateTime.Now - p.OneInTime).TotalHours < timeOutHoldHours)
- on loc.ContGrpBarCode equals stock.ContGrpBarCode
- join rule in _boxRule.AsQueryable().Where(p => p.PackRule == "CP").Select(p => new { p.DocsNo, p.SkuCode }).Distinct().ToList()
- on stock.InDocsNo equals rule.DocsNo
- select CreateStockTemp(loc, stock, rule.SkuCode);
- }
- /// <summary>
- /// 获取已检测非重绕盘
- /// </summary>
- /// <param name="timeOutHoldHours">超时小时</param>
- /// <returns></returns>
- private IEnumerable<LayerPackingProduct> GetTorsInventory(int timeOutHoldHours)
- {
- return from loc in _wareCell.GetList(p =>
- p.IsStop == LocationStop.LocationInvoke.GetHashCode() &&
- p.StateNum == LocationState.LocationState_Full)
- join stock in _invNow.GetList(p =>
- p.InvStateCode == InvState.InvEcecState_In.ToString() &&
- p.ExecStateCode == InvLockState.InvState_Normal.ToString() &&
- p.Grade == "A" &&
- p.IsControlpanel &&
- p.IsTorsChk &&
- p.TorsChkQty > 0 &&
- string.IsNullOrEmpty(p.PreStock) &&
- !p.ProductMachCode.Contains("R") &&
- p.ContUsageQty <= 0 &&
- (DateTime.Now - p.ProductTime).TotalHours < timeOutHoldHours)
- on loc.ContGrpBarCode equals stock.ContGrpBarCode
- join rule in _boxRule.AsQueryable().Where(p => p.PackRule == "CP").Select(p => new { p.DocsNo, p.SkuCode }).Distinct().ToList()
- on stock.InDocsNo equals rule.DocsNo
- select CreateStockTemp(loc, stock, rule.SkuCode);
- }
- /// <summary>
- /// 获取已检测重绕盘
- /// </summary>
- /// <param name="timeOutHoldHours">超时小时</param>
- /// <returns></returns>
- private IEnumerable<LayerPackingProduct> GetTorsReworkInventory(int timeOutHoldHours)
- {
- return from loc in _wareCell.GetList(p =>
- p.IsStop == LocationStop.LocationInvoke.GetHashCode() &&
- p.StateNum == LocationState.LocationState_Full)
- join stock in _invNow.GetList(p =>
- p.InvStateCode == InvState.InvEcecState_In.ToString() &&
- p.ExecStateCode == InvLockState.InvState_Normal.ToString() &&
- p.Grade == "A" &&
- p.IsControlpanel &&
- p.IsTorsChk &&
- p.TorsChkQty > 0 &&
- string.IsNullOrEmpty(p.PreStock) &&
- p.ProductMachCode.Contains("R") &&
- p.ContUsageQty <= 0 &&
- (DateTime.Now - p.OneInTime).TotalHours < timeOutHoldHours)
- on loc.ContGrpBarCode equals stock.ContGrpBarCode
- join rule in _boxRule.AsQueryable().Where(p => p.PackRule == "CP").Select(p => new { p.DocsNo, p.SkuCode }).Distinct().ToList()
- on stock.InDocsNo equals rule.DocsNo
- select CreateStockTemp(loc, stock, rule.SkuCode);
- }
- /// <summary>
- /// 创建库存临时对象
- /// </summary>
- /// <param name="loc">货位信息</param>
- /// <param name="stock">库存信息</param>
- /// <param name="skuCode">sku</param>
- /// <returns></returns>
- private LayerPackingProduct CreateStockTemp(BaseWarecell loc, BillInvnow stock, string skuCode)
- {
- return new LayerPackingProduct
- {
- MatCode = stock.MatCode,
- InvBarCode = stock.InvBarCode,
- Grade = stock.Grade,
- InvStateCode = stock.InvStateCode,
- ProductTime = stock.ProductTime,
- WbGroupCode = stock.WbGroupCode,
- IsTorsChk = stock.IsTorsChk,
- TorsChkQty = stock.TorsChkQty,
- TorsChkValue = stock.TorsChkValue == null ? 0 : (decimal)stock.TorsChkValue,
- HoldTime = stock.HoldTime,
- ProductMachCode = stock.ProductMachCode,
- IsControlpanel = stock.IsControlpanel,
- HWTypeCode = stock.HWTypeCode,
- SolderCount = stock.SolderCount,
- IsRework = stock.IsRework,
- IsBlack = stock.IsBlack,
- Col = loc.Col,
- Layer = loc.Layer,
- Shelf = loc.Shelf,
- Depth = loc.Depth,
- Code = loc.Code,
- Tunnel = loc.Tunnel,
- SCRel = loc.SCRel,
- Floor = loc.Floor,
- WarehouseCode = loc.WarehouseCode,
- ContGrpBarCode = loc.ContGrpBarCode,
- ContGrpId = loc.ContGrpId,
- Id = loc.Id,
- StateNum = loc.StateNum,
- SkuCode = skuCode,
- Wind = stock.Wind,
- InDocsNo = stock.InDocsNo,
- BatchNo = stock.BatchNo
- };
- }
- /// <summary>
- /// 过滤禁用巷道
- /// </summary>
- /// <param name="inventory">可用产品</param>
- /// <returns></returns>
- public IEnumerable<LayerPackingProduct> FilterByTunnelRestrictions(IEnumerable<LayerPackingProduct> inventory)
- {
- var tunnelRestrictions = _sysconfing.GetList(p =>
- p.SType == "OutStop" && !string.IsNullOrEmpty(p.SContent));
- if (!tunnelRestrictions.Any())
- {
- return inventory;
- }
- var filteredInventory = inventory.ToList();
- // 按楼层过滤禁用巷道
- for (int floor = 1; floor <= 3; floor++)
- {
- var floorRestrictions = tunnelRestrictions
- .Where(p => p.Default2 == floor.ToString())
- .Select(x => x.Default1)
- .ToList();
- if (floorRestrictions.Any())
- {
- var restrictedContainers = filteredInventory
- .Where(p => p.Floor == floor &&
- floorRestrictions.Contains(p.Tunnel.ToString()))
- .Select(p => p.ContGrpBarCode)
- .ToList();
- filteredInventory = filteredInventory
- .Where(p => !restrictedContainers.Contains(p.ContGrpBarCode))
- .ToList();
- }
- }
- return filteredInventory;
- }
- #endregion 获取可用库存
- #region 装箱逻辑
- /// <summary>
- /// 按SKU执行装箱
- /// </summary>
- /// <param name="skuGroup"></param>
- /// <param name="boxRules"></param>
- /// <param name="inventory"></param>
- /// <returns></returns>
- public SRes ProcessSkuGroup(
- IGrouping<string, LayerPackingProduct> skuGroup,
- List<BillPboxrule> boxRules,
- IEnumerable<LayerPackingProduct> inventory)
- {
- var res = new SRes { ResCode = ResponseStatusCodeEnum.Fail.GetHashCode() };
- var skuCode = skuGroup.Key;
- var skuBoxRules = boxRules.Where(p => p.SkuCode == skuCode).OrderBy(p => p.BatchNo).ThenBy(p => p.PBoxCode);
- if (!skuBoxRules.Any())
- {
- return HandleNoBoxRuleForSku(skuCode, inventory);
- }
- var ruleGroups = skuBoxRules.GroupBy(p => new { p.Wind, p.SpoolType, p.FullCountQty });
- foreach (var ruleGroup in ruleGroups)
- {
- var result = ProcessRuleGroup(ruleGroup, inventory, skuCode);
- if (result.ResCode == ResponseStatusCodeEnum.Sucess.GetHashCode())
- {
- return result;
- }
- else
- {
- res.ResMsg += $"[{ruleGroup.Key}:{result.ResMsg}]";
- }
- }
- return res;
- }
- /// <summary>
- /// 处理装箱规则组
- /// </summary>
- /// <param name="ruleGroup">箱号</param>
- /// <param name="inventory">产品</param>
- /// <param name="skuCode">sku</param>
- /// <returns></returns>
- public SRes ProcessRuleGroup(
- IGrouping<dynamic, BillPboxrule> ruleGroup,
- IEnumerable<LayerPackingProduct> inventory,
- string skuCode)
- {
- var rule = ruleGroup.OrderBy(p => p.BatchNo).ThenBy(p => p.PBoxCode).FirstOrDefault();
- if (rule == null) return new SRes { ResCode = ResponseStatusCodeEnum.Fail.GetHashCode() };
- return ProcessSpecialSku(rule, inventory);
- }
- /// <summary>
- /// 处理特殊SKU --指不管控机器组
- /// </summary>
- /// <param name="skuCode">sku</param>
- /// <returns></returns>
- private bool IsSpecialSku(string skuCode)
- {
- return skuCode == "6210010401" || skuCode == "6210120101";
- }
- /// <summary>
- /// 处理不需要管控机器组的SKU
- /// </summary>
- /// <param name="rule"></param>
- /// <param name="inventory"></param>
- /// <returns></returns>
- public SRes ProcessSpecialSku(
- BillPboxrule rule,
- IEnumerable<LayerPackingProduct> inventory)
- {
- var res = new SRes();
- // 1. 分配库存
- var allocationResult = AllocateStock(rule, inventory, isSpecialSku: true);
- if (!allocationResult.IsSuccess)
- {
- _logger.LogError($"特殊SKU库存分配失败: {allocationResult.ErrorMessage}");
- res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
- res.ResMsg = allocationResult.ErrorMessage;
- return res;
- }
- // 2. MES验证
- var mesResult = VerifyBoxWithMes(rule.PBoxCode, rule.BatchNo);
- if (!mesResult.IsSuccess)
- {
- UpdateBoxStatus(rule, 2, mesResult.Message);
- res.ResCode = ResponseStatusCodeEnum.ErrParam.GetHashCode();
- res.ResMsg = $"MES验证失败: {mesResult.Message}";
- return res;
- }
- // 3. 预占库存
- PreOccupyInventory(rule, allocationResult.BoxInfo);
- res.ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode();
- return res;
- }
- /// <summary>
- /// 装箱
- /// </summary>
- /// <param name="rule">箱号</param>
- /// <param name="availableStock">有效库存</param>
- /// <param name="isSpecialSku">是否控制机器组</param>
- /// <param name="skuGroup">对应的分组sku</param>
- /// <returns></returns>
- public StockAllocationResult AllocateStock(
- BillPboxrule rule,
- IEnumerable<LayerPackingProduct> availableStock,
- bool isSpecialSku = false,
- IGrouping<string, LayerPackingProduct>? skuGroup = null)
- {
- var result = new StockAllocationResult();
- // 过滤符合条件的库存
- var filteredStock = FilterStock(availableStock, rule, isSpecialSku, skuGroup).ToList();
- if (!filteredStock.Any())
- {
- result.IsSuccess = false;
- result.ErrorMessage = "没有符合条件的库存";
- return result;
- }
- //构建初始装箱参数
- var constraints = new LayerPackingConstraints
- {
- P = rule.TorsChkValue,
- P1 = rule.TorsChkValueRange,
- SolderMaxCount = rule.SolderMaxCount,
- PerSolderMaxCount = rule.PerSolderMaxCount,
- ProductsPerBox = rule.FullCountQty
- };
- var config = _sysconfing.GetFirst(x => x.Code == "CP_RelaxationRatio");
- if (config != null)
- {
- constraints.BR = decimal.Parse(config.SContent);
- constraints.LR = decimal.Parse(config.Default1);
- }
- constraints.UpdateTargetValues(filteredStock);
- //开始装箱
- var layerPacking = new LayerPackingService(filteredStock, constraints);
- var layerPackingResult = layerPacking.PackBoxe();
- //装箱结果为空
- if (layerPackingResult.Boxes.Count < 1)
- {
- result.IsSuccess = false;
- result.ErrorMessage = JsonConvert.SerializeObject(layerPackingResult.FailureReasons);
- return result;
- }
- if (!layerPackingResult.IsSuccess)
- {
- result.ErrorMessage = JsonConvert.SerializeObject(layerPackingResult.FailureReasons);
- }
- result.IsSuccess = true;
- result.BoxInfo = layerPackingResult.Boxes.First();
- return result;
- }
- /// <summary>
- /// 过滤库存
- /// </summary>
- /// <param name="stock">产品</param>
- /// <param name="rule">装箱规则</param>
- /// <param name="isSpecialSku">是否管控机器组</param>
- /// <param name="skuGroup">管控机器组时用于过滤的机器组信息</param>
- /// <returns></returns>
- private IEnumerable<LayerPackingProduct> FilterStock(
- IEnumerable<LayerPackingProduct> stock,
- BillPboxrule rule,
- bool isSpecialSku,
- IGrouping<string, LayerPackingProduct>? skuGroup = null)
- {
- var filtered = stock.Where(p => p.SkuCode == rule.SkuCode);
- if (!isSpecialSku && skuGroup != null)
- {
- filtered = filtered.Where(p => p.WbGroupCode == skuGroup.Key);
- }
- if (!string.IsNullOrEmpty(rule.SpoolType))
- {
- filtered = filtered.Where(p => p.HWTypeCode == rule.SpoolType);
- }
- if (!string.IsNullOrEmpty(rule.Wind))
- {
- filtered = filtered.Where(p => p.Wind == rule.Wind);
- }
- return filtered;
- }
- #region 箱号验证
- /// <summary>
- /// 箱号验证
- /// </summary>
- /// <param name="boxCode">待验证的箱号</param>
- /// <param name="batchNo">批号</param>
- /// <returns></returns>
- public MesVerificationResult VerifyBoxWithMes(string boxCode, string batchNo)
- {
- var result = new MesVerificationResult();
- try
- {
- var boxVerifyRequest = new MesBoxVerify
- {
- HuNr = boxCode,
- Batch = batchNo
- };
- var requestId = Guid.NewGuid().ToString();
- var esbRequest = CreateEsbRequest(requestId);
- var url = wms.util.AppSettings.GetConfig("EsbMesPushUrl");
- var response = SendMesRequest(boxVerifyRequest, requestId, esbRequest, url);
- var mesResponse = JsonConvert.DeserializeObject<TorschMesResponse>(response);
- _logger.LogInformation($"MES箱号验证返回: {response}");
- result.IsSuccess = mesResponse.success;
- result.Message = mesResponse.message;
- result.RawResponse = response;
- }
- catch (Exception ex)
- {
- _logger.LogError($"MES验证异常: {ex}");
- result.IsSuccess = false;
- result.Message = "MES验证异常: " + ex.Message;
- }
- return result;
- }
- /// <summary>
- /// 创建ESB请求
- /// </summary>
- /// <param name="requestId">请求ID</param>
- /// <returns></returns>
- private EsbReq CreateEsbRequest(string requestId)
- {
- return new EsbReq
- {
- headers = new HeadersReq
- {
- serviceCode = "163K162003",
- requestId = requestId,
- TrackId = requestId,
- sourceCode = "163K"
- }
- };
- }
- /// <summary>
- /// 发送MES请求
- /// </summary>
- /// <param name="request">请求参数</param>
- /// <param name="requestId">请求ID</param>
- /// <param name="esbRequest">esb请求信息</param>
- /// <param name="_mesUrl">esb地址</param>
- /// <returns></returns>
- private string SendMesRequest(MesBoxVerify request, string requestId, EsbReq esbRequest, string _mesUrl)
- {
- return HttpUtil.PostRequest(
- _mesUrl,
- JsonConvert.SerializeObject(request),
- 30000,
- "UTF-8",
- "application/json",
- requestId,
- esbRequest.headers.sourceCode,
- esbRequest.headers.serviceCode);
- }
- #endregion 箱号验证
- #region 更新装箱/库存信息
- /// <summary>
- /// 预占用库存
- /// </summary>
- /// <param name="rule">箱号</param>
- /// <param name="boxInfo">产品信息</param>
- public SRes PreOccupyInventory(
- BillPboxrule rule,
- LayerPackingBoxInfo boxInfo)
- {
- var res = new SRes() { ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode(), ResMsg = ResponseStatusCodeEnum.Sucess.GetDescription() };
- if (boxInfo.Layers.SelectMany(x=>x.Products).Count() != rule.FullCountQty)
- {
- res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
- res.ResMsg = "成箱产品数与满箱产品数不符";
- return res;
- }
- try
- {
- _db.BeginTran();
- // 更新箱号状态为预占用
- UpdateBoxStatus(rule, 3, "箱号预占用");
- // 更新库存预占用标记
- var presign = rule.Id.ToString();
- var layerNumber = 0;
- foreach (var layer in boxInfo.Layers.OrderByDescending(x => x.TotalTorsion))
- {
- var layerProductsIds = layer.Products.Select(x => x.ContGrpId).ToList();
- _invNow.UpdateSetColumnsTrue(p => new BillInvnow
- {
- PreStock = presign,
- EditTime = DateTime.Now,
- PackingLayer = layerNumber,
- Memo = $"箱号预占用:{rule.PBoxCode}"
- }, p => layerProductsIds.Contains(p.ContGrpId));
- layerNumber++;
- }
- var containerIds = boxInfo.TotalProduct.Select(x => x.ContGrpId).ToList();
- _db.CommitTran();
- _logger.LogInformation($"{rule.PBoxCode}预占:{JsonConvert.SerializeObject(containerIds)}");
- }
- catch (Exception ex)
- {
- _logger.LogError($"箱号预占用异常: {ex}");
- _db.RollbackTran();
- res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
- res.ResMsg = ex.Message;
- }
- return res;
- }
- /// <summary>
- /// 更新箱号状态
- /// </summary>
- /// <param name="rule">箱号</param>
- /// <param name="status">状态</param>
- /// <param name="memo">备注</param>
- public void UpdateBoxStatus(BillPboxrule rule, int status, string memo)
- {
- _boxRule.UpdateSetColumnsTrue(p => new BillPboxrule
- {
- ZXStateCode = status,
- EditTime = DateTime.Now,
- Memo = memo
- }, p => p.Id == rule.Id);
- }
- #endregion 更新装箱/库存信息
- #endregion 装箱逻辑
- #region 处理无箱号可用的情况
- /// <summary>
- /// 处理没有箱号的情况
- /// </summary>
- /// <param name="inventory">产品信息</param>
- /// <returns></returns>
- public SRes HandleNoBoxRuleError(IEnumerable<LayerPackingProduct> inventory)
- {
- string msg = "SPC" + ResponseStatusCodeEnum.NotBoxRule.GetDescription();
- RedisHelper.Set("Sx:WMSErrorInfo:NoControlOut8",
- new RedisErrorInfo { Equip = "NoControlOut8", Con = msg, Time = DateTime.Now });
- _logger.LogInformation("非控制不满足装箱:" + msg);
- var docNos = inventory.GroupBy(v => v.InDocsNo).Select(p => p.Key).Distinct().ToList();
- SxPackingHelp.WreTimeOutRecord(inventory.Select(p => p.ContGrpBarCode).ToList(), $"没有箱号可以使用,单号:{JsonConvert.SerializeObject(docNos)}", _timeoutrecord, _logger);
- return new SRes
- {
- ResCode = ResponseStatusCodeEnum.NotBoxRule.GetHashCode(),
- ResMsg = msg
- };
- }
- /// <summary>
- /// 处理没有箱号可用的情况 --SKU
- /// </summary>
- /// <param name="skuCode">SKU</param>
- /// <param name="inventory">产品信息</param>
- /// <returns></returns>
- public SRes HandleNoBoxRuleForSku(string skuCode, IEnumerable<LayerPackingProduct> inventory)
- {
- var skuInventory = inventory.Where(p => p.SkuCode == skuCode);
- var docNos = inventory.GroupBy(v => v.InDocsNo).Select(p => p.Key).Distinct().ToList();
- string msg = $"没有箱号可以使用,SKU:{skuCode},单号:{JsonConvert.SerializeObject(docNos)}";
- RedisHelper.Set("Sx:WMSErrorInfo:NoControlOut9", new RedisErrorInfo { Equip = "NoControlOut9", Con = msg, Time = DateTime.Now });
- _logger.LogInformation($"非控制不满足装箱:{msg}");
- SxPackingHelp.WreTimeOutRecord(skuInventory.Select(p => p.ContGrpBarCode).ToList(), $"没有箱号可以使用,SKU:{skuCode},单号:{JsonConvert.SerializeObject(docNos)}", _timeoutrecord, _logger);
- return new SRes { ResCode = ResponseStatusCodeEnum.Fail.GetHashCode(), ResMsg = msg };
- }
- #endregion 处理无箱号可用的情况
- #region 下发装箱任务及缓存托盘
- #region 处理正在码垛的任务
- /// <summary>
- /// 处理正在码垛的任务
- /// </summary>
- public SRes ProcessActivePalletizingTasks()
- {
- var res = new SRes();
- var activePalletList = _palletiz.GetList(p =>
- p.PalletizState == 0 &&
- p.BoxRule == "CP" &&
- p.IsControlpanel == false);
- if (!activePalletList.Any())
- {
- res.ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode();
- res.ResMsg = "没有正在码垛的任务";
- return res;
- }
- // 按任务数量排序
- activePalletList = SortPalletListByTaskCount(activePalletList);
- var taskConfig = GetTaskConfiguration();
- foreach (var pallet in activePalletList)
- {
- // 检查机械手任务数量限制
- if (!CheckRobotTaskLimit(pallet.Robot, taskConfig.MaxTaskCount))
- {
- _logger.LogInformation($"{pallet.Robot}当前机械手任务数量已经超最大值{taskConfig.MaxTaskCount}");
- continue;
- }
- // 检查任务下发顺序
- if (!CheckTaskSequence(pallet, taskConfig.TaskStatus))
- {
- continue;
- }
- // 下发码垛任务
- var taskResult = CreatePalletizingTasks(pallet);
- if (taskResult.ResCode != ResponseStatusCodeEnum.Sucess.GetHashCode())
- {
- continue;
- }
- // 更新任务标识
- UpdateTaskFlag(pallet.Robot, pallet.Equip);
- }
- res.ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode();
- res.ResMsg = "正在码垛任务处理完成";
- return res;
- }
- /// <summary>
- /// 按任务数量排序码垛列表
- /// </summary>
- /// <param name="palletList">码垛列表</param>
- /// <returns>排序后的码垛列表</returns>
- private List<Palletizing> SortPalletListByTaskCount(List<Palletizing> palletList)
- {
- if (!palletList.Any())
- {
- return palletList;
- }
- // 获取每个码垛工位的未完成任务数量
- var palletIds = palletList.Select(p => p.Id).ToList();
- var taskCountQuery = _palletLayerMath
- .GetList(p => p.Istask == 0 && palletIds.Contains(p.PalletizingId))
- .GroupBy(p => p.Palletequip);
- if (!taskCountQuery.Any())
- {
- return palletList;
- }
- // 统计每个工位的任务数量
- var taskCountList = (from taskGroup in taskCountQuery
- select new TunnelCountTemp
- {
- Tunnel = taskGroup.Key,
- Count = taskGroup.Count()
- }).ToList();
- // 按任务数量降序排序码垛列表
- var sortedList = palletList.OrderByDescending(p =>
- {
- var matchedCount = taskCountList.FirstOrDefault(q => q.Tunnel == p.Equip);
- return matchedCount?.Count ?? 0;
- }).ToList();
- return sortedList;
- }
- /// <summary>
- /// 创建码垛任务
- /// </summary>
- private SRes CreatePalletizingTasks(Palletizing pallet)
- {
- var res = new SRes();
- // 获取码垛工位配置
- var equipConfig = GetPalletizingEquipConfig(pallet.Equip);
- if (equipConfig == null)
- {
- SetRedisError("NoControlOut2", $"不存在该{pallet.Equip}的码垛工位");
- res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
- res.ResMsg = $"不存在该{pallet.Equip}的码垛工位";
- return res;
- }
- // 获取待下发的码垛任务
- var palletMathList = _palletLayerMath
- .GetList(p => p.PalletizingId == pallet.Id && p.Istask == 0)
- .OrderBy(p => p.Depth)
- .Take(72);
- if (!palletMathList.Any())
- {
- SetRedisError("NoControlOut3", $"{pallet.Equip}没有新的码垛任务需要下发");
- res.ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode();
- res.ResMsg = "没有新的码垛任务需要下发";
- return res;
- }
- // 获取DocID
- var docId = GenerateDocId(pallet.Id);
- // 批量创建任务
- var taskResults = new List<SRes>();
- foreach (var palletMath in palletMathList)
- {
- var taskRes = CreateSinglePalletizingTask(palletMath, pallet, equipConfig, docId);
- if (taskRes.ResCode == ResponseStatusCodeEnum.Sucess.GetHashCode())
- {
- taskResults.Add(taskRes);
- }
- }
- res.ResCode = ResponseStatusCodeEnum.Sucess.GetHashCode();
- res.ResMsg = $"成功创建{taskResults.Count}个码垛任务";
- return res;
- }
- /// <summary>
- /// 创建单个码垛任务
- /// </summary>
- private SRes CreateSinglePalletizingTask(
- PalletLayerMath palletMath,
- Palletizing pallet,
- sxSysConfig equipConfig,
- int docId)
- {
- var res = new SRes();
- // 获取库位信息
- var cell = _wareCell.GetSingle(p =>
- p.ContGrpBarCode == palletMath.ContBarCode &&
- p.StateNum == LocationState.LocationState_Full &&
- p.ContGrpId == palletMath.ContGrpId);
- if (cell == null)
- {
- res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
- res.ResMsg = "库位信息不存在";
- return res;
- }
- // 获取库存信息
- var inventory = _invNow.GetSingle(p =>
- p.ContGrpBarCode == palletMath.ContBarCode &&
- p.InvStateCode == InvState.InvEcecState_In.ToString());
- if (inventory == null)
- {
- res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
- res.ResMsg = "库存信息不存在";
- return res;
- }
- // 处理二深位移库
- if (cell.Depth == 2)
- {
- var moveRes = SxServiceHelp.MoveTask(cell.Code, _wcsTaskOld, _wareHouse, _invNow, _wareCell, _task, _taskDetail, _db, _logger, _mapper, _lockerPalletizingPackTask, _lockerApplyLoc);
- if (!string.IsNullOrEmpty(moveRes.Memo1) && moveRes.Memo1 == "1")
- {
- SetRedisError("NoControlOut23", $"{cell.Code}库位下发移库任务失败,请检查一深货位状态");
- res.ResCode = ResponseStatusCodeEnum.Fail.GetHashCode();
- res.ResMsg = "移库任务失败";
- return res;
- }
- }
- // 创建码垛任务请求
- var taskRequest = BuildPalletizingTaskRequest(palletMath, cell, inventory, pallet, docId);
- // 调用任务创建接口
- var taskResponse = SxServiceHelp.PalletizingPackTask(taskRequest, _wareCell, _invNow, _invFlow, _task, _wcsTaskOld, _taskDetail, _db, _mapper, _lockerPalletizingPackTask);
- if (taskResponse.ResCode == ResponseStatusCodeEnum.Sucess.GetHashCode())
- {
- // 更新码垛层任务状态
- _palletLayerMath.UpdateSetColumnsTrue(
- p => new PalletLayerMath() { Istask = 1, Layer = inventory.PackingLayer },
- p => p.ContBarCode == inventory.ContGrpBarCode);
- }
- return taskResponse;
- }
- /// <summary>
- /// 获取任务配置
- /// </summary>
- private TaskConfiguration GetTaskConfiguration()
- {
- return new TaskConfiguration
- {
- TaskStatus = (TaskStatus)int.Parse(_sysconfing.GetSingle(p => p.Code == "PreNextTaskStatus").SContent),
- MaxTaskCount = int.Parse(_sysconfing.GetSingle(p => p.Code == "PreNextTaskCount").SContent)
- };
- }
- /// <summary>
- /// 获取码垛工位配置
- /// </summary>
- /// <param name="equipCode">工位编码</param>
- /// <returns>工位配置信息</returns>
- private sxSysConfig GetPalletizingEquipConfig(string equipCode)
- {
- try
- {
- // 从视图中查询码垛工位配置
- var config = _sysconfing.Context.Ado
- .SqlQuery<sxSysConfig>($"select * from WMS_ZT_01SX.dbo.V_PalletizingPack where code = '{equipCode}'")
- .FirstOrDefault();
- if (config == null)
- {
- _logger.LogWarning($"未找到工位 {equipCode} 的配置信息");
- }
- return config;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, $"获取工位 {equipCode} 配置信息时发生异常");
- return null;
- }
- }
- /// <summary>
- /// 检查任务下发顺序
- /// </summary>
- private bool CheckTaskSequence(
- Palletizing currentPallet,
- TaskStatus taskStatus)
- {
- // 找到当前机械手最早的码垛信息
- var earliestPallet = _palletiz
- .GetList(p => p.PalletizState != 1 && p.Robot == currentPallet.Robot)
- .OrderBy(p => p.Id)
- .FirstOrDefault();
- if (earliestPallet == null || currentPallet.Id == earliestPallet.Id)
- {
- return true;
- }
- // 检查是否是第3箱
- var result = CheckThirdBoxRestriction(currentPallet, earliestPallet, taskStatus);
- return result;
- }
- /// <summary>
- /// 检查第3箱限制
- /// </summary>
- private bool CheckThirdBoxRestriction(
- Palletizing currentPallet,
- Palletizing earliestPallet,
- TaskStatus taskStatus)
- {
- var robotPallets = _palletiz.GetList(p =>
- p.PalletizState != 1 &&
- p.Robot == currentPallet.Robot);
- if (robotPallets.Count < 3)
- {
- return true;
- }
- var thirdBoxId = robotPallets.OrderBy(p => p.Id).Take(3).Last().Id;
- // 如果是第3箱
- if (currentPallet.Id == thirdBoxId)
- {
- // 检查最早的箱子任务是否过了卡控点
- if (HasUnfinishedTasks(earliestPallet.Id, taskStatus))
- {
- _logger.LogInformation($"第3箱卡控同一机械手最早的箱子的码垛任务没有全部过卡控点{taskStatus.GetDescription()}");
- return false;
- }
- // 检查前两箱是否都是同一目标地址
- var firstTwoBoxes = robotPallets.Where(p => p.Id < thirdBoxId).ToList();
- if (firstTwoBoxes.Count == 2 && firstTwoBoxes.Select(p => p.Equip).Distinct().Count() == 1)
- {
- _logger.LogInformation("第3箱卡控同一机械手前面两箱都是同一目标地址,则不下第3箱任务");
- return false;
- }
- }
- else if (currentPallet.Id > thirdBoxId)
- {
- _logger.LogInformation($"同一机械手第3箱之后的任务不允许下发,码垛主表id:{currentPallet.Id}");
- return false;
- }
- return true;
- }
- /// <summary>
- /// 构建码垛任务请求
- /// </summary>
- /// <param name="palletMath">码垛层数学信息</param>
- /// <param name="cell">库位信息</param>
- /// <param name="inventory">库存信息</param>
- /// <param name="pallet">码垛主信息</param>
- /// <param name="docId">文档ID</param>
- /// <returns>码垛任务请求对象</returns>
- private PalletizingPackTaskRequest BuildPalletizingTaskRequest(
- PalletLayerMath palletMath,
- BaseWarecell cell,
- BillInvnow inventory,
- Palletizing pallet,
- int docId)
- {
- // 确定机械手
- var robot = SxServiceHelp.DetermineRoot(palletMath.Palletequip);
- // 构建任务请求
- var request = new PalletizingPackTaskRequest
- {
- // 容器条码
- Code = palletMath.ContBarCode,
- // 库位信息
- CellCode = cell.Code,
- Srm = cell.SCRel,
- Tunnel = cell.Tunnel.ToString(),
- Floor = cell.Floor,
- // 产品信息
- Grade = inventory.Grade,
- Mater = inventory.MatCode,
- SkuCode = palletMath.SkuCode,
- ProductMachCode = inventory.ProductMachCode,
- // 码垛信息
- PalletLayer = inventory.PackingLayer,
- Equip = pallet.Equip,
- PalletizingId = pallet.Id,
- Robot = robot,
- // 货物类型:1-BS80/33, 2-其他
- GoodsType = inventory.HWTypeCode == "BS80/33" ? 1 : 2,
- // 文档ID
- DocId = docId
- };
- return request;
- }
- #endregion 处理正在码垛的任务
- /// <summary>
- /// 更新码垛状态为正在码垛
- /// </summary>
- private void UpdatePalletStateToActive(long palletId)
- {
- try
- {
- _palletiz.AsUpdateable()
- .SetColumns(p => new Palletizing() { PalletizState = 0 })
- .Where(p => p.Id == palletId)
- .ExecuteCommand();
- _logger.LogInformation($"码垛任务 {palletId} 状态已更新为正在码垛");
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, $"更新码垛任务 {palletId} 状态时发生异常");
- }
- }
- #region 辅助方法
- /// <summary>
- /// 设置Redis错误信息
- /// </summary>
- private void SetRedisError(string equipCode, string message)
- {
- RedisHelper.Set($"Sx:WMSErrorInfo:{equipCode}", new RedisErrorInfo
- {
- Equip = equipCode,
- Con = message,
- Time = DateTime.Now
- });
- }
- /// <summary>
- /// 检查机械手任务数量限制
- /// </summary>
- private bool CheckRobotTaskLimit(string robot, int maxCount)
- {
- var currentCount = _task.AsQueryable()
- .With(SqlWith.NoLock)
- .Where(p => p.Status < TaskStatus.码垛抓取完成 &&
- p.Robot == robot &&
- p.BusType == "装箱码垛")
- .Count();
- return currentCount < maxCount;
- }
- /// <summary>
- /// 判断是否有未完成的任务
- /// </summary>
- private bool HasUnfinishedTasks(long palletizingId, TaskStatus taskStatus)
- {
- var hasUnfinishedMath = _palletLayerMath
- .GetList(p => p.PalletizingId == palletizingId && p.Istask == 0)
- .Any();
- var hasUnfinishedTask = _task.AsQueryable()
- .With(SqlWith.NoLock)
- .Where(p => p.PalletizingId == palletizingId && p.Status < taskStatus)
- .Any();
- return hasUnfinishedMath || hasUnfinishedTask;
- }
- /// <summary>
- /// 更新任务标识
- /// </summary>
- private void UpdateTaskFlag(string robot, string equipCode)
- {
- var currentFlag = _sysconfing.Context.Ado
- .SqlQuery<sxSysConfig>("select * from WMS_ZT_01SX.dbo.V_PalletizingPack")
- .Where(p => p.Robot == robot)
- .Max(p => p.TaskFlag);
- var newFlag = currentFlag + 1;
- _sysconfing.Context.Ado.ExecuteCommand($"update WMS_ZT_01CP.dbo.sys_config set taskflag={newFlag} where code='{equipCode}'");
- }
- /// <summary>
- /// 记录超时记录
- /// </summary>
- private void WreTimeOutRecord(List<string> containerBarcodes, string reason)
- {
- // 实现超时记录逻辑
- _logger.LogWarning($"超时记录 - 容器条码: {string.Join(",", containerBarcodes)}, 原因: {reason}");
- }
- /// <summary>
- /// 生成文档ID
- /// </summary>
- /// <param name="palletizingId">码垛ID</param>
- /// <returns>文档ID</returns>
- private int GenerateDocId(long palletizingId)
- {
- try
- {
- // 获取装箱码垛类型任务的最大DocID
- var maxDocId = _task.AsQueryable()
- .Where(p => p.BusType == "装箱码垛")
- .Max(p => (int?)p.DocID) ?? 0;
- // 默认使用最大值+1
- var currentDocId = maxDocId + 1;
- // 检查当前码垛是否已有任务,如果有则使用相同的DocID
- var existingDocId = _task.AsQueryable()
- .With(SqlWith.NoLock)
- .Where(p => p.PalletizingId == palletizingId && p.DocID > 0)
- .Max(p => (int?)p.DocID);
- if (existingDocId.HasValue)
- {
- currentDocId = existingDocId.Value;
- }
- return currentDocId;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, $"生成文档ID时发生异常,码垛ID:{palletizingId}");
- throw;
- }
- }
- #endregion 辅助方法
- #endregion 下发装箱任务及缓存托盘
- }
- }
|