using System; using System.Diagnostics; using System.Dynamic; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Security.Policy; using System.Text; using System.Threading.Tasks; using Aop.Api.Domain; using Aspose.Cells; using JNPF; using JNPF.Common.Contracts; using JNPF.Common.Core.Manager; using JNPF.Common.Dtos.VisualDev; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Manager; using JNPF.Common.Security; using JNPF.FriendlyException; using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.System; using JNPF.VisualDev.Entitys; using JNPF.VisualDev.Interfaces; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.CodeAnalysis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using NetTaste; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NPOI.OpenXmlFormats.Dml; using NPOI.SS.Formula.Functions; using Org.BouncyCastle.Crypto; using SqlSugar; using Tnb.BasicData.Entities; using Tnb.Common.Extension; using Tnb.Common.Redis; using Tnb.Common.Utils; using Tnb.ProductionMgr.Entities; using Tnb.ProductionMgr.Entities.Entity; using Tnb.QcMgr.Entities; using Tnb.WarehouseMgr.Entities; using Tnb.WarehouseMgr.Entities.Configs; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto; using Tnb.WarehouseMgr.Entities.Dto.Inputs; using Tnb.WarehouseMgr.Entities.Dto.Outputs; using Tnb.WarehouseMgr.Entities.Dto.Queries; using Tnb.WarehouseMgr.Entities.Entity; using Tnb.WarehouseMgr.Entities.Enums; using Tnb.WarehouseMgr.Interfaces; using static NPOI.HSSF.Util.HSSFColor; using Tnb.BasicData; using System.Reflection; using NPOI.SS.Format; using Aspose.Cells.Drawing; using SQLitePCL; using Tnb.BasicData.Entities.Entity; using Tnb.BasicData.Interfaces; namespace Tnb.WarehouseMgr { /// /// 库房业务类(出入库) /// public class WareHouseService : DevServBase, IWareHouseService { private readonly ISqlSugarClient _db; private readonly IDictionaryDataService _dictionaryDataService; private readonly IBillRullService _billRullService; private readonly IUserManager _userManager; private readonly ICacheManager _cacheManager; private readonly IElevatorControlService _elevatorControlService; private readonly IWmsCarryBindService _wmsCarryBindService; private readonly IWmsCarryUnbindService _wmsCarryUnbindService; private readonly IWmsOutinStockDetailService _wmsOutinStockDetailService; private static ISqlSugarClient db_agvElevatorTaskExceptionHandles; private readonly IThirdApiRecordService _thirdApiRecordService; private static readonly Dictionary _elevatorAgvCtlStatusMap = new(StringComparer.OrdinalIgnoreCase); private readonly ElevatorControlConfiguration _eleCtlCfg = App.Configuration.Build(); private static Dictionary locMap = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly IConfiguration _configuration; private readonly StackExRedisHelper _redisData; private readonly IVisualDevService _visualDevService; private readonly IRunService _runService; public static SemaphoreSlim s_floor2CreatePretask = new(1); public static SemaphoreSlim s_taskCommonCreatePretask = new(1); public static SemaphoreSlim s_taskGenPreTask = new(1); public Func AddUnExecuteTask { get; set; } public SemaphoreSlim _s_GenTaskExecute { get { return s_GenTaskExecute; } } public SemaphoreSlim s_taskExecuteSemaphore_YCLInstock { get { return _s_taskExecuteSemaphore_YCLInstock; } } public SemaphoreSlim s_taskExecuteSemaphore_YCLOutstock { get { return _s_taskExecuteSemaphore_YCLOutstock; } } public SemaphoreSlim s_taskExecuteSemaphore_F1ZCCInstock { get { return _s_taskExecuteSemaphore_F1ZCCInstock; } } public SemaphoreSlim s_taskExecuteSemaphore_F1ZCCOutstock { get { return _s_taskExecuteSemaphore_F1ZCCOutstock; } } public SemaphoreSlim s_taskExecuteSemaphore_F2ZCCInstock { get { return _s_taskExecuteSemaphore_F2ZCCInstock; } } public SemaphoreSlim s_taskExecuteSemaphore_F2ZCCOutstock { get { return _s_taskExecuteSemaphore_F2ZCCOutstock; } } public Dictionary s_elevatortaskDic { get { return _s_elevatortaskDic; } } public List db_ElevatorTaskExceptionHandles { get { return _db_ElevatorTaskExceptionHandles; } } /// /// WCS请求 /// public Dictionary s_elevatortaskWCSRequestDic { get { return _s_elevatortaskWCSRequestDic; } } public WareHouseService(ISqlSugarRepository repository, IDictionaryDataService dictionaryDataService, StackExRedisHelper redisData, IBillRullService billRullService, IUserManager userManager, ICacheManager cacheManager, IElevatorControlService elevatorControlService, IWmsCarryBindService wmsCarryBindService, IWmsCarryUnbindService wmsCarryUnbindService, IRunService runService, IVisualDevService visualDevService, IThirdApiRecordService thirdApiRecordService, IWmsOutinStockDetailService wmsOutinStockDetailService //IConfiguration configuration ) : base(repository.AsSugarClient()) { _db = repository.AsSugarClient(); _dictionaryDataService = dictionaryDataService; _billRullService = billRullService; _userManager = userManager; _cacheManager = cacheManager; _elevatorControlService = elevatorControlService; _redisData = redisData; _wmsCarryBindService = wmsCarryBindService; _wmsCarryUnbindService = wmsCarryUnbindService; _runService = runService; _visualDevService = visualDevService; _thirdApiRecordService = thirdApiRecordService; _wmsOutinStockDetailService = wmsOutinStockDetailService; //_configuration = configuration; } /// /// 根据载具Id带出库位、仓库信息 /// /// 载具id /// /// returns: ///
{ ///
carry_id:载具Id ///
carry_name:载具名称 ///
location_id:库位Id ///
location_name:库位名称 ///
warehouse_id:库房Id ///
warehouse_name:库房名称 ///
} ///
[HttpGet] public async Task GetLocationAndWorkHouseByCarryId([FromRoute] string carryId) { var items = await _db.Queryable().LeftJoin((a, b) => a.location_id == b.id) .LeftJoin((a, b, c) => b.wh_id == c.id) .Where(a => a.id == carryId) .Select((a, b, c) => new { carry_id = a.id, a.carry_name, location_id = b.id, b.location_name, warehouse_id = c.id, warehouse_name = c.whname, }) .ToListAsync(); return items ?? Enumerable.Empty(); } /// /// 库房业务,入库、出库申请新增修改功能 /// /// /// [HttpPost] public async Task ApplyFor(InOutStockApplyforUpInput input) { if (input == null) { throw new ArgumentNullException(nameof(input)); } async Task _updateLocalFunc(InOutStockApplyforUpInput input) where TStockD : BaseEntity, new() where TStockCode : BaseEntity, IInOutStockCode, new() { TStockD instockD = input.Adapt(); global::System.Collections.Generic.List? stockCodes = input.InstockCodes?.Adapt>(); if (stockCodes?.Count > 0) { stockCodes.ForEach(x => { if (x.id.IsNullOrWhiteSpace()) { x.id = SnowflakeIdHelper.NextId(); } x.bill_d_id = instockD.id; }); } return await Update(instockD, stockCodes!); } bool isOk = input.inoutStockType switch { EnumInOutStockType.In => await _updateLocalFunc(input), EnumInOutStockType.Out => await _updateLocalFunc(input), _ => throw new ArgumentOutOfRangeException(nameof(input.inoutStockType), $"Not expected EnumInOutStockType value: {input.inoutStockType}"), }; if (!isOk) { throw Oops.Oh(ErrorCode.COM1001); } } /// /// 根据明细Id获取出入库明细信息 /// /// [HttpGet] public async Task GetInOutStockCodesById([FromQuery] InOutStockDetailQuery input) { dynamic? result = input.inoutStockType switch { EnumInOutStockType.In => await FetchInOutStockCodesById(input.bill_d_id), EnumInOutStockType.Out => await FetchInOutStockCodesById(input.bill_d_id), _ => throw new NotImplementedException(), }; return result ?? Enumerable.Empty(); } /// /// 入库策略 /// /// [HttpGet] public async Task> InStockStrategy([FromQuery] InStockStrategyQuery input) { List items = new(); try { var db = input.dbConn; if (input.dbConn == null) { db = _db.CopyNew(); } WmsInstockPolicies policy = await db.Queryable().Where(it => it.status == 1 && (string.IsNullOrEmpty(input.PolicyCode)|| it.bill_code == input.PolicyCode)).FirstAsync(); if (policy == null) { throw new AppFriendlyException("没有可用的策略", 500); } List busyPassages = new(); if (input.AvoidBusyPassage) { busyPassages = await db.Queryable() .InnerJoin((a, b) => (a.status != WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID && a.status != WmsWareHouseConst.PRETASK_BILL_STATUS_CANCEL_ID) && (b.id == a.startlocation_id || b.id == a.endlocation_id)) .Where((a, b) => b.wh_id == input.warehouse_id) .Where((a, b) => b.is_type == ((int)EnumLocationType.存储库位).ToString()) .WhereIF(!string.IsNullOrEmpty(input.Region_id), (a, b) => b.region_id == input.Region_id) .Select((a, b) => b.passage).ToListAsync(); } Expression> whereExp = Expressionable.Create() .And(it => it.wh_id == input.warehouse_id) .And(it => it.is_lock == 0) .And(it => it.is_type == ((int)EnumLocationType.存储库位).ToString()) .And(it => it.is_use == ((int)EnumCarryStatus.空闲).ToString()) .AndIF(!string.IsNullOrEmpty(input.Region_id), it => it.region_id == input.Region_id) .AndIF(input.AvoidBusyPassage, it => !busyPassages.Contains(it.passage)) .AndIF(!string.IsNullOrEmpty(input.passage), it => it.passage == input.passage) .ToExpression(); items = await db.Queryable().Where(whereExp).OrderBy(policy.policy).ToListAsync(); } catch (Exception) { throw; } return items.Take(input.Size).ToList(); } /// /// 入库策略 /// /// [HttpGet] public async Task> InStockStrategyBCK([FromQuery] InStockStrategyQuery input) { List items = new(); try { var db = input.dbConn; if (input.dbConn == null) { db = _db.CopyNew(); } WmsInstockPolicies policy = await db.Queryable().Where(it => it.status == 1).FirstAsync(); if (policy == null) { throw new AppFriendlyException("没有可用的策略", 500); } Expression> whereExp = Expressionable.Create() .And(it => it.wh_id == input.warehouse_id) .And(it => it.is_lock == 0) .And(it => it.is_type == ((int)EnumLocationType.分拣库位).ToString()) .And(it => it.is_use == ((int)EnumCarryStatus.空闲).ToString()) .ToExpression(); items = await db.Queryable().Where(whereExp).OrderBy(policy.policy).ToListAsync(); } catch (Exception) { throw; } return items.Take(input.Size).ToList(); } /// /// 包材库2楼入库策略 /// /// [HttpGet] public async Task> BCKF2InStockStrategy([FromQuery] InStockStrategyQuery input) { List items = new(); try { var db = input.dbConn; if (input.dbConn == null) { db = _db.CopyNew(); } WmsInstockPolicies policy = await db.Queryable().Where(it => it.status == 1).FirstAsync(); if (policy == null) { throw new AppFriendlyException("没有可用的策略", 500); } Expression> whereExp = Expressionable.Create() .And(it => it.wh_id == input.warehouse_id) .And(it => it.is_lock == 0) .And(it => it.is_type == ((int)EnumLocationType.出入库位).ToString()) .And(it => it.is_use == ((int)EnumCarryStatus.空闲).ToString()) .ToExpression(); items = await db.Queryable().Where(whereExp).OrderBy(policy.policy).ToListAsync(); } catch (Exception) { throw; } return items.Take(input.Size).ToList(); } /// /// 是否为一楼出库工位 /// /// /// public string[] GetFloor1OutstockLocation() { return new string[23] { "30018211902485", "34355463261205", "34355450098709", "34355446145813" , "34355443336981", "34355440377365", "34355436327189", "34355432397077", "34355428852501", "34355424568341" , "34355421064213", "34355416966165", "34355407509269", "34355402216469", "34355397484565", "34355394965013" , "34355391740181", "34355387110933", "34355383562005", "34355377989397", "34355374481173", "34355369617173" , "30018211902485"}; } /// /// 是否为二楼包材出库工位 /// /// /// public string[] GetFloor2BCOutstockLocation() { return new string[1] { "30018211902485" }; } /// /// 是否为供料三工位库位 /// /// /// public string[] GetFloor1GLSGWOutstockLocation() { return new string[5] { WmsWareHouseConst.Floor1GLSGWOutstockStation1 , WmsWareHouseConst.Floor1GLSGWOutstockStation2 , WmsWareHouseConst.Floor1GLSGWOutstockStation3, WmsWareHouseConst.Floor1GLSGWOutstockStation4, WmsWareHouseConst.Floor1GLSGWOutstockStation5 }; } /// /// 是否为原材料调拨出库库位 /// /// /// public string[] GetFloor1YCLDBOutstockLocation() { return new string[3] { WmsWareHouseConst.Floor1OutstockStation1 , WmsWareHouseConst.Floor1OutstockStation2 , WmsWareHouseConst.Floor1OutstockStation3 }; } /// /// 是否为外协三工位库位 /// /// /// public string[] GetFloor1WXSGWOutstockLocation() { return new string[3] { WmsWareHouseConst.Floor1WXSGWOutstockStation1 , WmsWareHouseConst.Floor1WXSGWOutstockStation2 , WmsWareHouseConst.Floor1WXSGWOutstockStation3 }; } ///// ///// 是否为二楼(一楼外协三存位送上来)入暂存仓起点 ///// ///// ///// //public string[] GetFloor2WX2ZCCStartLocation() //{ // return new string[3] { WmsWareHouseConst.Floor1WXSGWOutstockStation1 , WmsWareHouseConst.Floor1WXSGWOutstockStation2 // , WmsWareHouseConst.Floor1WXSGWOutstockStation3 }; //} /// /// 出库策略-销售出库下发 /// /// [HttpGet] public async Task>> OutStockStrategy_saleRelease([FromQuery] OutStockStrategyQuery input) { Expressionable whereExprable = Expressionable.Create() .And((a, b, c) => a.is_lock == 0 && c.is_lock == 0) .And((a, b, c) => !string.IsNullOrEmpty(a.location_id)) .And((a, b, c) => c.is_type == ((int)EnumLocationType.存储库位).ToString()) .And((a, b, c) => a.out_status == "0") .And((a, b, c) => c.wh_id == input.warehouse_id) .AndIF(!string.IsNullOrEmpty(input.material_id), (a, b, c) => b.material_id == input.material_id) .AndIF(!string.IsNullOrEmpty(input.code_batch), (a, b, c) => b.code_batch == input.code_batch) .AndIF(!string.IsNullOrEmpty(input.material_specification), (a, b, c) => b.material_specification == input.material_specification) .AndIF(!string.IsNullOrEmpty(input.container_no), (a, b, c) => b.container_no == input.container_no) .AndIF(!string.IsNullOrEmpty(input.carrystd_id), (a, b, c) => a.carrystd_id == input.carrystd_id) .AndIF(!string.IsNullOrEmpty(input.Region_id), (a, b, c) => c.region_id == input.Region_id); Expression> carryStatusFilterExp = !input.material_id.IsNullOrWhiteSpace() ? (a, b, c) => a.carry_status == ((int)EnumCarryStatus.占用).ToString() : (a, b, c) => a.carry_status == ((int)EnumCarryStatus.空闲).ToString(); _ = whereExprable.And(carryStatusFilterExp); Expression> whereExpr = whereExprable.ToExpression(); var cyDb = input.dbConn; if (input.dbConn == null) { cyDb = _db.CopyNew(); } List> items = cyDb.Queryable().LeftJoin((a, b) => a.id == b.carry_id) .LeftJoin((a, b, c) => a.location_id == c.id) .Where(whereExpr) //.OrderByIF((a,b,c)=>SqlFunc.IsNullOrEmpty()) .OrderBy("b.codeqty") .Select((a, b, c) => new { WmsCarryH = a, WmsCarryCode = b, BasLocation = c, codeqty = b.codeqty }).ToList().Select(r => { // 如果可出库数量已经扣减完 if (input.qty <= 0) { return new Tuple("", r.WmsCarryH, r.WmsCarryCode, r.BasLocation); } // 扣减可出库数量 input.qty = input.qty - r.codeqty; // 出库数量与托盘上的数量不一致需要进行分拣 if (input.qty < 0) { r.WmsCarryCode.codeqty = input.qty + r.codeqty; return new Tuple("分拣任务", r.WmsCarryH, r.WmsCarryCode, r.BasLocation); } else { // 正常预任务出库 return new Tuple("预任务", r.WmsCarryH, r.WmsCarryCode, r.BasLocation); } }).Where(r => r.Item1 != "").ToList(); return items; } public async Task> OutStockStrategy([FromQuery] OutStockStrategyQuery input) { var cyDb = input.dbConn; if (input.dbConn == null) { cyDb = _db.CopyNew(); } List busyPassages = new(); if (input.AvoidBusyPassage) { busyPassages = await cyDb.Queryable() .InnerJoin((a, b) => (a.status != WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID && a.status != WmsWareHouseConst.PRETASK_BILL_STATUS_CANCEL_ID) && (b.id == a.startlocation_id || b.id == a.endlocation_id)) .Where((a, b) => b.wh_id == input.warehouse_id) .Where((a, b) => b.is_type == ((int)EnumLocationType.存储库位).ToString()) .WhereIF(!string.IsNullOrEmpty(input.Region_id), (a, b) => b.region_id == input.Region_id) .Select((a, b) => b.passage).ToListAsync(); } Expressionable whereExprable = Expressionable.Create() .And((a, b, c) => a.is_lock == 0 && c.is_lock == 0) .And((a, b, c) => !string.IsNullOrEmpty(a.location_id)) .And((a, b, c) => c.is_type == ((int)EnumLocationType.存储库位).ToString()) .And((a, b, c) => a.out_status == "0") .And((a, b, c) => c.wh_id == input.warehouse_id) .AndIF(!string.IsNullOrEmpty(input.material_id), (a, b, c) => b.material_id == input.material_id) .AndIF(!string.IsNullOrEmpty(input.code_batch), (a, b, c) => b.code_batch == input.code_batch) .AndIF(!string.IsNullOrEmpty(input.material_specification), (a, b, c) => b.material_specification == input.material_specification) .AndIF(!string.IsNullOrEmpty(input.container_no), (a, b, c) => b.container_no == input.container_no) .AndIF(!string.IsNullOrEmpty(input.carrystd_id), (a, b, c) => a.carrystd_id == input.carrystd_id) .AndIF(input.AvoidBusyPassage, (a, b, c) => !busyPassages.Contains(c.passage)) .AndIF(!string.IsNullOrEmpty(input.Region_id), (a, b, c) => c.region_id == input.Region_id); if (input.filter_carry_status) { Expression> carryStatusFilterExp = !input.material_id.IsNullOrWhiteSpace() ? (a, b, c) => a.carry_status == ((int)EnumCarryStatus.占用).ToString() : (a, b, c) => a.carry_status == ((int)EnumCarryStatus.空闲).ToString(); _ = whereExprable.And(carryStatusFilterExp); } Expression> whereExpr = whereExprable.ToExpression(); WmsOutstockPolicies policy = await cyDb.Queryable().Where(it => it.status == 1 && (string.IsNullOrEmpty(input.PolicyCode) || it.bill_code == input.PolicyCode)).FirstAsync(); if (policy == null) { throw new AppFriendlyException("没有可用策略", 500); } List items = await cyDb.Queryable().LeftJoin((a, b) => a.id == b.carry_id) .LeftJoin((a, b, c) => a.location_id == c.id) .Where(whereExpr) //.OrderByIF((a,b,c)=>SqlFunc.IsNullOrEmpty()) .OrderBy(policy.policy) .Select() .ToListAsync(); items = items.DistinctBy(r => r.id).ToList(); return input.Size > 0 ? items.Take(input.Size).ToList() : items; } /// /// 缓存仓出库策略 /// /// /// /// public async Task> OutStockStrategyHCC([FromQuery] OutStockStrategyQuery input) { Expressionable whereExprable = Expressionable.Create() .And((a, b, c) => a.is_lock == 0 && c.is_lock == 0) .And((a, b, c) => !string.IsNullOrEmpty(a.location_id)) .And((a, b, c) => c.is_type == ((int)EnumLocationType.存储库位).ToString()) .And((a, b, c) => a.out_status == "0") .And((a, b, c) => c.wh_id == input.warehouse_id) .AndIF(!string.IsNullOrEmpty(input.material_id), (a, b, c) => b.material_id == input.material_id) .AndIF(!string.IsNullOrEmpty(input.code_batch), (a, b, c) => b.code_batch == input.code_batch) .AndIF(!string.IsNullOrEmpty(input.material_specification), (a, b, c) => b.material_specification == input.material_specification) .AndIF(!string.IsNullOrEmpty(input.container_no), (a, b, c) => b.container_no == input.container_no) .AndIF(!string.IsNullOrEmpty(input.carrystd_id), (a, b, c) => a.carrystd_id == input.carrystd_id); Expression> carryStatusFilterExp = !input.material_id.IsNullOrWhiteSpace() ? (a, b, c) => a.carry_status == ((int)EnumCarryStatus.占用).ToString() : (a, b, c) => a.carry_status == ((int)EnumCarryStatus.空闲).ToString(); _ = whereExprable.And(carryStatusFilterExp); Expression> whereExpr = whereExprable.ToExpression(); SqlSugarClient cyDb = _db.CopyNew(); WmsInstockPolicies policy = await cyDb.Queryable().Where(it => it.status == 1).FirstAsync(); if (policy == null) { throw new AppFriendlyException("没有可用策略", 500); } List items = await cyDb.Queryable().LeftJoin((a, b) => a.id == b.carry_id) .LeftJoin((a, b, c) => a.location_id == c.id) .Where(whereExpr) //.OrderByIF((a,b,c)=>SqlFunc.IsNullOrEmpty()) .OrderBy(policy.policy) .Select() .ToListAsync(); items = items.Distinct().ToList(); return input.Size > 0 ? items.Take(input.Size).ToList() : items; } /// /// 1->2出库策略 /// /// /// /// public async Task>> OutStockStrategyZCC2Floor2([FromQuery] OutStockStrategyZCC2Floor2Query input) { var cyDb = input.dbConn; if (input.dbConn == null) { cyDb = _db.CopyNew(); } Expressionable whereExprable = Expressionable.Create() .And((a, b, c) => a.is_lock == 0 && c.is_lock == 0) .And((a, b, c) => !string.IsNullOrEmpty(a.location_id)) .And((a, b, c) => c.is_type == ((int)EnumLocationType.存储库位).ToString()) .And((a, b, c) => a.out_status == "0") .And((a, b, c) => c.wh_id == input.warehouse_id) .AndIF(!string.IsNullOrEmpty(input.material_id), (a, b, c) => b.material_id == input.material_id) .AndIF(!string.IsNullOrEmpty(input.code_batch), (a, b, c) => b.code_batch == input.code_batch) .AndIF(!string.IsNullOrEmpty(input.material_specification), (a, b, c) => b.material_specification == input.material_specification) .AndIF(!string.IsNullOrEmpty(input.container_no), (a, b, c) => b.container_no == input.container_no) .AndIF(!string.IsNullOrEmpty(input.carrystd_id), (a, b, c) => a.carrystd_id == input.carrystd_id); Expression> carryStatusFilterExp = !input.material_id.IsNullOrWhiteSpace() ? (a, b, c) => a.carry_status == ((int)EnumCarryStatus.占用).ToString() : (a, b, c) => a.carry_status == ((int)EnumCarryStatus.空闲).ToString(); _ = whereExprable.And(carryStatusFilterExp); Expression> whereExpr = whereExprable.ToExpression(); WmsInstockPolicies policy = await cyDb.Queryable().Where(it => it.status == 1).FirstAsync(); if (policy == null) { throw new AppFriendlyException("没有可用策略", 500); } #region 只解决少数情况(比如只有60 59 60 60四个料箱,下发180,要取60 60 60) 其它情况不考虑 List>? carrysDESC = new List>(); var itemsDESC = await cyDb.Queryable().LeftJoin((a, b) => a.id == b.carry_id) .LeftJoin((a, b, c) => a.location_id == c.id) .Where(whereExpr) //.OrderByIF((a,b,c)=>SqlFunc.IsNullOrEmpty()) //.OrderBy(policy.policy) .OrderBy("codeqty desc,a.location_code,layers,loc_line,loc_column") .Select((a, b) => new { wmsCarryH = a, wmsCarryCode = b }) .ToListAsync(); itemsDESC = itemsDESC.Distinct().ToList(); // 数量正序 List>? carrysASC = new List>(); var itemsASC = await cyDb.Queryable().LeftJoin((a, b) => a.id == b.carry_id) .LeftJoin((a, b, c) => a.location_id == c.id) .Where(whereExpr) //.OrderByIF((a,b,c)=>SqlFunc.IsNullOrEmpty()) //.OrderBy(policy.policy) .OrderBy("codeqty asc,a.location_code,layers,loc_line,loc_column") .Select((a, b) => new { wmsCarryH = a, wmsCarryCode = b }) .ToListAsync(); itemsASC = itemsASC.Distinct().ToList(); // 6个下发一条任务链 int move_num = 6; // 剩余分配数 { decimal? needOut = input.needOut; int endlocation_index = 0; BasLocation endlocation_ssx = null; for (int i = 0; i < itemsDESC.Count; i++) { WmsCarryH wmsCarryH = itemsDESC[i].wmsCarryH; WmsCarryCode wmsCarryCode = itemsDESC[i].wmsCarryCode; if (needOut <= 0) { break; } // 每6个重新获取一次终点 if (i % move_num == 0) { endlocation_ssx = await cyDb.Queryable().Where(r => input.endlocations.Contains(r.id)).OrderBy("is_lock, task_nums, location_code").FirstAsync(); } // 查找是否有一个料箱可以正好满足剩余需求数量(目前只做这个额外判断,其它情形不考虑) bool isFind = false; for (int j = i + 1; j < itemsDESC.Count; j++) { WmsCarryCode _wmsCarryCode = itemsDESC[j].wmsCarryCode; if (_wmsCarryCode.codeqty == needOut) { needOut -= _wmsCarryCode.codeqty; WmsCarryH _wmsCarryH = itemsDESC[j].wmsCarryH; await cyDb.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1).Where(it => endlocation_ssx.id == it.id).ExecuteCommandAsync(); carrysDESC.Add(new Tuple(_wmsCarryH, _wmsCarryCode.codeqty, endlocation_ssx)); isFind = true; break; } } if (isFind) break; // 目前只支持一个料箱只有一个物料 needOut -= wmsCarryCode.codeqty; await cyDb.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1).Where(it => endlocation_ssx.id == it.id).ExecuteCommandAsync(); carrysDESC.Add(new Tuple(wmsCarryH, wmsCarryCode.codeqty, endlocation_ssx)); } if (needOut > 0) { throw new AppFriendlyException($"物料{input.material_code}没有足够的库存!,缺失数量为{needOut}", 500); } } { decimal? needOut = input.needOut; int endlocation_index = 0; BasLocation endlocation_ssx = null; for (int i = 0; i < itemsASC.Count; i++) { WmsCarryH wmsCarryH = itemsASC[i].wmsCarryH; WmsCarryCode wmsCarryCode = itemsASC[i].wmsCarryCode; if (needOut <= 0) { break; } // 每6个重新获取一次终点 if (i % move_num == 0) { endlocation_ssx = await cyDb.Queryable().Where(r => input.endlocations.Contains(r.id)).OrderBy("is_lock, task_nums, location_code").FirstAsync(); } // 查找是否有一个料箱可以正好满足剩余需求数量(目前只做这个额外判断,其它情形不考虑) bool isFind = false; for (int j = i + 1; j < itemsASC.Count; j++) { WmsCarryCode _wmsCarryCode = itemsASC[j].wmsCarryCode; if (_wmsCarryCode.codeqty == needOut) { needOut -= _wmsCarryCode.codeqty; WmsCarryH _wmsCarryH = itemsASC[j].wmsCarryH; await cyDb.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1).Where(it => endlocation_ssx.id == it.id).ExecuteCommandAsync(); carrysASC.Add(new Tuple(_wmsCarryH, _wmsCarryCode.codeqty, endlocation_ssx)); isFind = true; break; } } if (isFind) break; // 目前只支持一个料箱只有一个物料 needOut -= wmsCarryCode.codeqty; await cyDb.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1).Where(it => endlocation_ssx.id == it.id).ExecuteCommandAsync(); carrysASC.Add(new Tuple(wmsCarryH, wmsCarryCode.codeqty, endlocation_ssx)); } if (needOut > 0) { throw new AppFriendlyException($"物料{input.material_code}没有足够的库存!,缺失数量为{needOut}", 500); } } #endregion List>? carrys = new List>(); if (carrysDESC.Count == carrysASC.Count) { return carrysDESC.Sum(r => r.Item2) <= carrysASC.Sum(r => r.Item2) ? carrysDESC : carrysASC; } else { return carrysDESC.Count <= carrysASC.Count ? carrysDESC : carrysASC; } } /// /// 判断CTU是否可以放货 /// /// [HttpPost] [AllowAnonymous] public async Task CheckPut(CheckPutInput input) { Logger.Information("联核请求CheckPut接口传入参数为:" + JsonConvert.SerializeObject(input)); Dictionary putdic = new Dictionary(); putdic.Add("SSX-011-006", new string[] { "YTCS", "AllowEmptyIn_CS06" }); putdic.Add("SSX-021-007", new string[] { "东面提升机输送线", "出库输送线7允许入箱" }); putdic.Add("SSX-121-009", new string[] { "东面提升机输送线", "上升降机9允许入箱" }); putdic.Add("SSX-121-010", new string[] { "东面提升机输送线", "上升降机10允许入箱" }); putdic.Add("SSX-021-003", new string[] { "YTCS", "AllowCtuEmptyIn_CS03" }); putdic.Add("SSX-021-001", new string[] { "YTCS", "AllowCtuEmptyIn_CS01" }); putdic.Add("ZSSSXCTU02", new string[] { "YTCS", "AllowCtuFullOut_CS04", }); putdic.Add("ZSSSXCTU01", new string[] { "YTCS", "AllowCtuFullOut_CS02", }); var strs = new string[] { }; if (!putdic.ContainsKey(input.targetName)) throw new AppFriendlyException("点位" + input.targetName + "不存在", 500); strs = putdic.Where(p => p.Key == input.targetName).First().Value; bool flag = await _redisData.HashExists(strs[0], strs[1]); if (!flag) { throw new AppFriendlyException("点位" + input.targetName + "不存在", 500); } string data = await _redisData.GetHash(strs[0], strs[1]); Logger.Information("wcs请求CheckPut接口查询X2Server数据:" + data); JObject? res = JsonConvert.DeserializeObject(data); bool result = res != null && res["Value"] != null && res["StatusCode"].ToString() == "0" ? res.Value("Value") : false; if (!result) throw new AppFriendlyException("点位" + input.targetName + "不可放", 500); Logger.Information("wcs请求CheckPut接口结果:CTU可放货" + data); } /// /// 判断CTU是否可以取货 /// /// public async Task Check(string code, string action) { Logger.Information($"【Check】 判断KIVA是否可以{action} {code}"); Dictionary putdic = new Dictionary(); Dictionary getdic = new Dictionary(); putdic.Add("ZSSSXCTU02", new string[] { "YTCS", "AllowAgvFullIn_CS04", }); putdic.Add("ZSSSXCTU01", new string[] { "YTCS", "AllowAgvFullIn_CS02", }); getdic.Add("ZSSSXCTU01", new string[] { "YTCS", "AllowAgvEmptyOut_CS01" }); getdic.Add("ZSSSXCTU02", new string[] { "YTCS", "AllowAgvEmptyOut_CS03" }); #region 注塑车间点位 putdic.Add("ZS-C01-1", new string[] { "hxjC", "A2允许入空箱", }); getdic.Add("ZS-C01-2", new string[] { "hxjC", "A2允许取满箱" }); putdic.Add("ZS-C02-1", new string[] { "hxjC", "A3允许入空箱", }); getdic.Add("ZS-C02-2", new string[] { "hxjC", "A3允许取满箱" }); putdic.Add("ZS-C03-1", new string[] { "hxjC", "A4允许入空箱", }); getdic.Add("ZS-C03-2", new string[] { "hxjC", "A4允许取满箱" }); putdic.Add("ZS-C04-1", new string[] { "hxjC", "A5允许入空箱", }); getdic.Add("ZS-C04-2", new string[] { "hxjC", "A5允许取满箱" }); putdic.Add("ZS-C05-1", new string[] { "hxjC", "A6允许入空箱", }); getdic.Add("ZS-C05-2", new string[] { "hxjC", "A6允许取满箱" }); putdic.Add("ZS-C06-1", new string[] { "hxjC", "A7允许入空箱", }); getdic.Add("ZS-C06-2", new string[] { "hxjC", "A7允许取满箱" }); putdic.Add("ZS-C07-1", new string[] { "hxjC", "A8允许入空箱", }); getdic.Add("ZS-C07-2", new string[] { "hxjC", "A8允许取满箱" }); putdic.Add("ZS-C08-1", new string[] { "hxjC", "A9允许入空箱", }); getdic.Add("ZS-C08-2", new string[] { "hxjC", "A9允许取满箱" }); putdic.Add("ZS-C09-1", new string[] { "hxjC", "A10允许入空箱", }); getdic.Add("ZS-C09-2", new string[] { "hxjC", "A10允许取满箱" }); putdic.Add("ZS-C10-1", new string[] { "hxjC", "A11允许入空箱", }); getdic.Add("ZS-C10-2", new string[] { "hxjC", "A11允许取满箱" }); putdic.Add("ZS-C11-1", new string[] { "hxjC", "A12允许入空箱", }); getdic.Add("ZS-C11-2", new string[] { "hxjC", "A12允许取满箱" }); putdic.Add("ZS-C12-1", new string[] { "hxjC", "A13允许入空箱", }); getdic.Add("ZS-C12-2", new string[] { "hxjC", "A13允许取满箱" }); putdic.Add("ZS-C13-1", new string[] { "hxjC", "A14允许入空箱", }); getdic.Add("ZS-C13-2", new string[] { "hxjC", "A14允许取满箱" }); putdic.Add("ZS-C14-1", new string[] { "hxjC", "A1允许入空箱", }); getdic.Add("ZS-C14-2", new string[] { "hxjC", "A1允许取满箱" }); //putdic.Add("ZS-A01-1", new string[] { "hxjA", "A3允许入空箱", }); //getdic.Add("ZS-A01-2", new string[] { "hxjA", "A3允许取满箱" }); //putdic.Add("ZS-A02-1", new string[] { "hxjA", "A4允许入空箱", }); //getdic.Add("ZS-A02-2", new string[] { "hxjA", "A4允许取满箱" }); //putdic.Add("ZS-A03-1", new string[] { "hxjA", "A5允许入空箱", }); //getdic.Add("ZS-A03-2", new string[] { "hxjA", "A5允许取满箱" }); //putdic.Add("ZS-D06-1", new string[] { "hxjA", "A6允许入空箱", }); //getdic.Add("ZS-D06-2", new string[] { "hxjA", "A6允许取满箱" }); //putdic.Add("ZS-A05-1", new string[] { "hxjA", "A7允许入空箱", }); //getdic.Add("ZS-A05-2", new string[] { "hxjA", "A7允许取满箱" }); //putdic.Add("ZS-A06-1", new string[] { "hxjA", "A8允许入空箱", }); //getdic.Add("ZS-A06-2", new string[] { "hxjA", "A8允许取满箱" }); putdic.Add("ZS-A07-1", new string[] { "hxjA", "A9允许入空箱", }); getdic.Add("ZS-A07-2", new string[] { "hxjA", "A9允许取满箱" }); putdic.Add("ZS-A08-1", new string[] { "hxjA", "A10允许入空箱", }); getdic.Add("ZS-A08-2", new string[] { "hxjA", "A10允许取满箱" }); putdic.Add("ZS-D01-1", new string[] { "hxjA", "A1允许入空箱", }); getdic.Add("ZS-D01-2", new string[] { "hxjA", "A1允许取满箱" }); putdic.Add("ZS-D02-1", new string[] { "hxjA", "A2允许入空箱", }); getdic.Add("ZS-D02-2", new string[] { "hxjA", "A2允许取满箱" }); putdic.Add("ZS-D03-1", new string[] { "hxjA", "A3允许入空箱", }); getdic.Add("ZS-D03-2", new string[] { "hxjA", "A3允许取满箱" }); putdic.Add("ZS-D04-1", new string[] { "hxjA", "A4允许入空箱", }); getdic.Add("ZS-D04-2", new string[] { "hxjA", "A4允许取满箱" }); putdic.Add("ZS-D05-1", new string[] { "hxjA", "A5允许入空箱", }); getdic.Add("ZS-D05-2", new string[] { "hxjA", "A5允许取满箱" }); putdic.Add("ZS-D06-1", new string[] { "hxjA", "A6允许入空箱", }); getdic.Add("ZS-D06-2", new string[] { "hxjA", "A6允许取满箱" }); putdic.Add("ZS-D07-1", new string[] { "hxjA", "A7允许入空箱", }); getdic.Add("ZS-D07-2", new string[] { "hxjA", "A7允许取满箱" }); putdic.Add("ZS-D08-1", new string[] { "hxjA", "A8允许入空箱", }); getdic.Add("ZS-D08-2", new string[] { "hxjA", "A8允许取满箱" }); putdic.Add("ZS-A09-1", new string[] { "hxjA", "A11允许入空箱", }); getdic.Add("ZS-A09-2", new string[] { "hxjA", "A11允许取满箱" }); putdic.Add("ZS-A10-1", new string[] { "hxjA", "A12允许入空箱", }); getdic.Add("ZS-A10-2", new string[] { "hxjA", "A12允许取满箱" }); putdic.Add("ZS-A11-1", new string[] { "hxjA", "A13允许入空箱", }); getdic.Add("ZS-A11-2", new string[] { "hxjA", "A13允许取满箱" }); putdic.Add("ZS-A12-1", new string[] { "hxjA", "A14允许入空箱", }); getdic.Add("ZS-A12-2", new string[] { "hxjA", "A14允许取满箱" }); #endregion var strs = new string[] { }; if (action == "LOAD")//取货 { if (!getdic.ContainsKey(code)) { return false; } strs = getdic.Where(p => p.Key == code).First().Value; bool flag = await _redisData.HashExists(strs[0], strs[1]); Logger.Information($"【Check】{action} 判断KIVA是否可以取货(信号是否存在) 获取{code}的标签{strs[1]}是否存在 结果为:{flag} "); if (!flag) { throw new Exception($"【Check】{action} 判断KIVA是否可以取货(信号是否存在) 获取{code}的标签{strs[1]}是否存在 结果为:{flag} "); } string data = _redisData.GetHash(strs[0], strs[1]).Result; JObject? res = JsonConvert.DeserializeObject(data); bool result = res != null && res["Value"] != null && res["StatusCode"].ToString() == "0" ? res.Value("Value") : false; Logger.Information($"【Check】{action} 判断KIVA是否可以取货(信号是否允许) 获取{code}的标签{strs[1]}信号值 结果为:{result} "); if (!result) { throw new Exception($"【Check】{action} 判断KIVA是否可以取货(信号是否允许) 获取{code}的标签{strs[1]}信号值 结果为:{result} "); } return true; } else if (action == "UNLOAD")//放货 { if (!putdic.ContainsKey(code)) return false; strs = putdic.Where(p => p.Key == code).First().Value; bool flag = await _redisData.HashExists(strs[0], strs[1]); Logger.Information($"【Check】 判断CTU是否可以放货(信号是否存在) 获取{code}的标签{strs[1]}是否存在 结果为:{flag} "); if (!flag) { throw new Exception($"【Check】 判断CTU是否可以放货(信号是否存在) 获取{code}的标签{strs[1]}是否存在 结果为:{flag} "); } string data = _redisData.GetHash(strs[0], strs[1]).Result; JObject? res = JsonConvert.DeserializeObject(data); bool result = res != null && res["Value"] != null && res["StatusCode"].ToString() == "0" ? res.Value("Value") : false; Logger.Information($"【Check】 判断CTU是否可以放货(信号是否允许) 获取{code}的标签{strs[1]}信号值 结果为:{result}"); if (!result) { throw new Exception($"【Check】 判断CTU是否可以放货(信号是否允许) 获取{code}的标签{strs[1]}信号值 结果为:{result} "); } return true; } return false; } public async Task SsxControl(WmsDistaskH disTask, string action) { Logger.Information($"输送线控制SsxControl传入参数: {JsonConvert.SerializeObject(disTask)} {action}"); Dictionary putdic = new Dictionary(); Dictionary getdic = new Dictionary(); getdic.Add("SSX-021-005", new string[] { "YTCS", "FullOut_CS05Done", "true" }); getdic.Add("SSX-111-011", new string[] { "东面提升机输送线", "下升降机11出箱完毕", "true" }); getdic.Add("SSX-111-012", new string[] { "东面提升机输送线", "下升降机12出箱完毕", "true" }); getdic.Add("ZZ-01-02", new string[] { "外包装箱码垛线", "WBZX_x1_take_mtp", "true" }); getdic.Add("ZZ-02-02", new string[] { "外包装箱码垛线", "WBZX_x2_take_mtp", "true" }); getdic.Add("ZSSSXCTU02", new string[] { "YTCS", "右输送线上层允许出箱3", "true" }); getdic.Add("ZSSSXCTU01", new string[] { "YTCS", "左输送线上层允许出箱1", "true" }); getdic.Add("SSX-011-008", new string[] { "东面提升机输送线", "入库输送线8出箱完毕", "true" }); getdic.Add("ZS-C01-2", new string[] { "hxjC", "A2AGV允许入满箱", "true" }); getdic.Add("ZS-C02-2", new string[] { "hxjC", "A3AGV允许入满箱", "true" }); getdic.Add("ZS-C03-2", new string[] { "hxjC", "A4AGV允许入满箱", "true" }); getdic.Add("ZS-C04-2", new string[] { "hxjC", "A5AGV允许入满箱", "true" }); getdic.Add("ZS-C05-2", new string[] { "hxjC", "A6AGV允许入满箱", "true" }); getdic.Add("ZS-C06-2", new string[] { "hxjC", "A7AGV允许入满箱", "true" }); getdic.Add("ZS-C07-2", new string[] { "hxjC", "A8AGV允许入满箱", "true" }); getdic.Add("ZS-C08-2", new string[] { "hxjC", "A9AGV允许入满箱", "true" }); getdic.Add("ZS-C09-2", new string[] { "hxjC", "A10AGV允许入满箱", "true" }); getdic.Add("ZS-C10-2", new string[] { "hxjC", "A11AGV允许入满箱", "true" }); getdic.Add("ZS-C11-2", new string[] { "hxjC", "A12AGV允许入满箱", "true" }); getdic.Add("ZS-C12-2", new string[] { "hxjC", "A13AGV允许入满箱", "true" }); getdic.Add("ZS-C13-2", new string[] { "hxjC", "A14AGV允许入满箱", "true" }); getdic.Add("ZS-C14-2", new string[] { "hxjC", "A1AGV允许入满箱", "true" }); //getdic.Add("ZS-A01-2", new string[] { "hxjA", "A3AGV允许入满箱", "true" }); //getdic.Add("ZS-A02-2", new string[] { "hxjA", "A4AGV允许入满箱", "true" }); //getdic.Add("ZS-A03-2", new string[] { "hxjA", "A5AGV允许入满箱", "true" }); //getdic.Add("ZS-D06-2", new string[] { "hxjA", "A6AGV允许入满箱", "true" }); //getdic.Add("ZS-A05-2", new string[] { "hxjA", "A7AGV允许入满箱", "true" }); //getdic.Add("ZS-A06-2", new string[] { "hxjA", "A8AGV允许入满箱", "true" }); getdic.Add("ZS-A07-2", new string[] { "hxjA", "A9AGV允许入满箱", "true" }); getdic.Add("ZS-A08-2", new string[] { "hxjA", "A10AGV允许入满箱", "true" }); getdic.Add("ZS-A09-2", new string[] { "hxjA", "A11AGV允许入满箱", "true" }); getdic.Add("ZS-A10-2", new string[] { "hxjA", "A12AGV允许入满箱", "true" }); getdic.Add("ZS-A11-2", new string[] { "hxjA", "A13AGV允许入满箱", "true" }); getdic.Add("ZS-A12-2", new string[] { "hxjA", "A14AGV允许入满箱", "true" }); getdic.Add("ZS-D01-2", new string[] { "hxjA", "A1AGV允许入满箱", "true" }); getdic.Add("ZS-D02-2", new string[] { "hxjA", "A2AGV允许入满箱", "true" }); getdic.Add("ZS-D03-2", new string[] { "hxjA", "A3AGV允许入满箱", "true" }); getdic.Add("ZS-D04-2", new string[] { "hxjA", "A4AGV允许入满箱", "true" }); getdic.Add("ZS-D05-2", new string[] { "hxjA", "A5AGV允许入满箱", "true" }); getdic.Add("ZS-D06-2", new string[] { "hxjA", "A6AGV允许入满箱", "true" }); getdic.Add("ZS-D07-2", new string[] { "hxjA", "A7AGV允许入满箱", "true" }); getdic.Add("ZS-D08-2", new string[] { "hxjA", "A8AGV允许入满箱", "true" }); putdic.Add("SSX-021-007", new string[] { "东面提升机输送线", "出库输送线7入箱完毕", "true" }); putdic.Add("SSX-011-006", new string[] { "YTCS", "EmptyIn_CS06Done", "true" }); putdic.Add("SSX-021-003", new string[] { "YTCS", "AgvFullIn_CS03Done", "true" }); putdic.Add("SSX-021-001", new string[] { "YTCS", "CtuEmptyIn_CS01Done", "true" }); putdic.Add("ZSSSXCTU02", new string[] { "YTCS", "右输送线下层允许入箱4", "true" }); putdic.Add("ZSSSXCTU01", new string[] { "YTCS", "左输送线下层允许入箱2", "true" }); putdic.Add("SSX-121-009", new string[] { "东面提升机输送线", "上升降机9入箱完毕", "true" }); putdic.Add("SSX-121-010", new string[] { "东面提升机输送线", "上升降机10入箱完毕", "true" }); putdic.Add("YCLCKBGW", new string[] { "CP8", "PutDoneEmptyBox", "true" }); putdic.Add("ZS-C01-1", new string[] { "hxjC", "A2AGV允许出空箱", "true" }); putdic.Add("ZS-C02-1", new string[] { "hxjC", "A3AGV允许出空箱", "true" }); putdic.Add("ZS-C03-1", new string[] { "hxjC", "A4AGV允许出空箱", "true" }); putdic.Add("ZS-C04-1", new string[] { "hxjC", "A5AGV允许出空箱", "true" }); putdic.Add("ZS-C05-1", new string[] { "hxjC", "A6AGV允许出空箱", "true" }); putdic.Add("ZS-C06-1", new string[] { "hxjC", "A7AGV允许出空箱", "true" }); putdic.Add("ZS-C07-1", new string[] { "hxjC", "A8AGV允许出空箱", "true" }); putdic.Add("ZS-C08-1", new string[] { "hxjC", "A9AGV允许出空箱", "true" }); putdic.Add("ZS-C09-1", new string[] { "hxjC", "A10AGV允许出空箱", "true" }); putdic.Add("ZS-C10-1", new string[] { "hxjC", "A11AGV允许出空箱", "true" }); putdic.Add("ZS-C11-1", new string[] { "hxjC", "A12AGV允许出空箱", "true" }); putdic.Add("ZS-C12-1", new string[] { "hxjC", "A13AGV允许出空箱", "true" }); putdic.Add("ZS-C13-1", new string[] { "hxjC", "A14AGV允许出空箱", "true" }); putdic.Add("ZS-C14-1", new string[] { "hxjC", "A1AGV允许出空箱", "true" }); //putdic.Add("ZS-A01-1", new string[] { "hxjA", "A3AGV允许出空箱", "true" }); //putdic.Add("ZS-A02-1", new string[] { "hxjA", "A4AGV允许出空箱", "true" }); //putdic.Add("ZS-A03-1", new string[] { "hxjA", "A5AGV允许出空箱", "true" }); //putdic.Add("ZS-D06-1", new string[] { "hxjA", "A6AGV允许出空箱", "true" }); //putdic.Add("ZS-A05-1", new string[] { "hxjA", "A7AGV允许出空箱", "true" }); //putdic.Add("ZS-A06-1", new string[] { "hxjA", "A8AGV允许出空箱", "true" }); putdic.Add("ZS-A07-1", new string[] { "hxjA", "A9AGV允许出空箱", "true" }); putdic.Add("ZS-A08-1", new string[] { "hxjA", "A10AGV允许出空箱", "true" }); putdic.Add("ZS-A09-1", new string[] { "hxjA", "A11AGV允许出空箱", "true" }); putdic.Add("ZS-A10-1", new string[] { "hxjA", "A12AGV允许出空箱", "true" }); putdic.Add("ZS-A11-1", new string[] { "hxjA", "A13AGV允许出空箱", "true" }); putdic.Add("ZS-A12-1", new string[] { "hxjA", "A14AGV允许出空箱", "true" }); // D线 待改成配置 putdic.Add("ZS-D01-1", new string[] { "hxjA", "A1AGV允许出空箱", "true" }); putdic.Add("ZS-D02-1", new string[] { "hxjA", "A2AGV允许出空箱", "true" }); putdic.Add("ZS-D03-1", new string[] { "hxjA", "A3AGV允许出空箱", "true" }); putdic.Add("ZS-D04-1", new string[] { "hxjA", "A4AGV允许出空箱", "true" }); putdic.Add("ZS-D05-1", new string[] { "hxjA", "A5AGV允许出空箱", "true" }); putdic.Add("ZS-D06-1", new string[] { "hxjA", "A6AGV允许出空箱", "true" }); putdic.Add("ZS-D07-1", new string[] { "hxjA", "A7AGV允许出空箱", "true" }); putdic.Add("ZS-D08-1", new string[] { "hxjA", "A8AGV允许出空箱", "true" }); if (action == "LOAD")//取货 { if (getdic.Keys.Contains(disTask.startlocation_code)) { var strarr = getdic.Where(p => p.Key == disTask.startlocation_code).First().Value; Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = strarr[0], ["token"] = _eleCtlCfg.token, ["TagName"] = strarr[1], ["Value"] = strarr[2], }; Logger.Information($"SsxControlLOAD:{JsonConvert.SerializeObject(dicCommand)}"); var str = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand); Logger.Information($"SsxControlLOAD:{str}"); //Logger.Information($"SsxControlUNLOAD - 控制后查询:{_redisData.GetHash(strarr[0], strarr[1]).Result}"); } } else if (action == "UNLOAD")//放货 { if (putdic.Keys.Contains(disTask.endlocation_code)) { var strarr = putdic.Where(p => p.Key == disTask.endlocation_code).First().Value; Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = strarr[0], ["token"] = _eleCtlCfg.token, ["TagName"] = strarr[1], ["Value"] = strarr[2], }; Logger.Information($"SsxControlUNLOAD:{JsonConvert.SerializeObject(dicCommand)}"); var str = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand); Logger.Information($"SsxControlUNLOAD:{str}"); //Logger.Information($"SsxControlUNLOAD - 控制后查询:{_redisData.GetHash(strarr[0], strarr[1]).Result}"); } } } public async Task SsxControl_complete(WmsDistaskH disTask, string action) { Logger.Information($"输送线控制SsxControl_complete传入参数: {JsonConvert.SerializeObject(disTask)} {action}"); Dictionary putdic = new Dictionary(); Dictionary getdic = new Dictionary(); getdic.Add("SSX-021-005", new string[] { "YTCS", "FullOut_CS05Done", "true" }); getdic.Add("SSX-111-011", new string[] { "东面提升机输送线", "下升降机11出箱完毕", "true" }); getdic.Add("SSX-111-012", new string[] { "东面提升机输送线", "下升降机12出箱完毕", "true" }); getdic.Add("ZZ-01-02", new string[] { "外包装箱码垛线", "WBZX_x1_take_mtp", "true" }); getdic.Add("ZZ-02-02", new string[] { "外包装箱码垛线", "WBZX_x2_take_mtp", "true" }); getdic.Add("ZSSSXCTU02", new string[] { "YTCS", "右输送线上层允许出箱3", "true" }); getdic.Add("ZSSSXCTU01", new string[] { "YTCS", "左输送线上层允许出箱1", "true" }); getdic.Add("SSX-011-008", new string[] { "东面提升机输送线", "入库输送线8出箱完毕", "true" }); getdic.Add("ZS-C01-2", new string[] { "hxjC", "A2AGV允许入满箱", "true" }); getdic.Add("ZS-C02-2", new string[] { "hxjC", "A3AGV允许入满箱", "true" }); getdic.Add("ZS-C03-2", new string[] { "hxjC", "A4AGV允许入满箱", "true" }); getdic.Add("ZS-C04-2", new string[] { "hxjC", "A5AGV允许入满箱", "true" }); getdic.Add("ZS-C05-2", new string[] { "hxjC", "A6AGV允许入满箱", "true" }); getdic.Add("ZS-C06-2", new string[] { "hxjC", "A7AGV允许入满箱", "true" }); getdic.Add("ZS-C07-2", new string[] { "hxjC", "A8AGV允许入满箱", "true" }); getdic.Add("ZS-C08-2", new string[] { "hxjC", "A9AGV允许入满箱", "true" }); getdic.Add("ZS-C09-2", new string[] { "hxjC", "A10AGV允许入满箱", "true" }); getdic.Add("ZS-C10-2", new string[] { "hxjC", "A11AGV允许入满箱", "true" }); getdic.Add("ZS-C11-2", new string[] { "hxjC", "A12AGV允许入满箱", "true" }); getdic.Add("ZS-C12-2", new string[] { "hxjC", "A13AGV允许入满箱", "true" }); getdic.Add("ZS-C13-2", new string[] { "hxjC", "A14AGV允许入满箱", "true" }); getdic.Add("ZS-C14-2", new string[] { "hxjC", "A1AGV允许入满箱", "true" }); //getdic.Add("ZS-A01-2", new string[] { "hxjA", "A3AGV允许入满箱", "true" }); //getdic.Add("ZS-A02-2", new string[] { "hxjA", "A4AGV允许入满箱", "true" }); //getdic.Add("ZS-A03-2", new string[] { "hxjA", "A5AGV允许入满箱", "true" }); //getdic.Add("ZS-D06-2", new string[] { "hxjA", "A6AGV允许入满箱", "true" }); //getdic.Add("ZS-A05-2", new string[] { "hxjA", "A7AGV允许入满箱", "true" }); //getdic.Add("ZS-A06-2", new string[] { "hxjA", "A8AGV允许入满箱", "true" }); getdic.Add("ZS-A07-2", new string[] { "hxjA", "A9AGV允许入满箱", "true" }); getdic.Add("ZS-A08-2", new string[] { "hxjA", "A10AGV允许入满箱", "true" }); getdic.Add("ZS-A09-2", new string[] { "hxjA", "A11AGV允许入满箱", "true" }); getdic.Add("ZS-A10-2", new string[] { "hxjA", "A12AGV允许入满箱", "true" }); getdic.Add("ZS-A11-2", new string[] { "hxjA", "A13AGV允许入满箱", "true" }); getdic.Add("ZS-A12-2", new string[] { "hxjA", "A14AGV允许入满箱", "true" }); getdic.Add("ZS-D01-2", new string[] { "hxjA", "A1AGV允许入满箱", "false" }); getdic.Add("ZS-D02-2", new string[] { "hxjA", "A2AGV允许入满箱", "false" }); getdic.Add("ZS-D03-2", new string[] { "hxjA", "A3AGV允许入满箱", "false" }); getdic.Add("ZS-D04-2", new string[] { "hxjA", "A4AGV允许入满箱", "false" }); getdic.Add("ZS-D05-2", new string[] { "hxjA", "A5AGV允许入满箱", "false" }); getdic.Add("ZS-D06-2", new string[] { "hxjA", "A6AGV允许入满箱", "false" }); getdic.Add("ZS-D07-2", new string[] { "hxjA", "A7AGV允许入满箱", "false" }); getdic.Add("ZS-D08-2", new string[] { "hxjA", "A8AGV允许入满箱", "false" }); putdic.Add("SSX-021-007", new string[] { "东面提升机输送线", "出库输送线7入箱完毕", "true" }); putdic.Add("SSX-011-006", new string[] { "YTCS", "EmptyIn_CS06Done", "true" }); putdic.Add("SSX-021-003", new string[] { "YTCS", "AgvFullIn_CS03Done", "true" }); putdic.Add("SSX-021-001", new string[] { "YTCS", "CtuEmptyIn_CS01Done", "true" }); putdic.Add("ZSSSXCTU02", new string[] { "YTCS", "右输送线下层允许入箱4", "true" }); putdic.Add("ZSSSXCTU01", new string[] { "YTCS", "左输送线下层允许入箱2", "true" }); putdic.Add("SSX-121-009", new string[] { "东面提升机输送线", "上升降机9入箱完毕", "true" }); putdic.Add("SSX-121-010", new string[] { "东面提升机输送线", "上升降机10入箱完毕", "true" }); putdic.Add("YCLCKBGW", new string[] { "CP8", "PutDoneEmptyBox", "true" }); putdic.Add("ZS-C01-1", new string[] { "hxjC", "A2AGV允许出空箱", "true" }); putdic.Add("ZS-C02-1", new string[] { "hxjC", "A3AGV允许出空箱", "true" }); putdic.Add("ZS-C03-1", new string[] { "hxjC", "A4AGV允许出空箱", "true" }); putdic.Add("ZS-C04-1", new string[] { "hxjC", "A5AGV允许出空箱", "true" }); putdic.Add("ZS-C05-1", new string[] { "hxjC", "A6AGV允许出空箱", "true" }); putdic.Add("ZS-C06-1", new string[] { "hxjC", "A7AGV允许出空箱", "true" }); putdic.Add("ZS-C07-1", new string[] { "hxjC", "A8AGV允许出空箱", "true" }); putdic.Add("ZS-C08-1", new string[] { "hxjC", "A9AGV允许出空箱", "true" }); putdic.Add("ZS-C09-1", new string[] { "hxjC", "A10AGV允许出空箱", "true" }); putdic.Add("ZS-C10-1", new string[] { "hxjC", "A11AGV允许出空箱", "true" }); putdic.Add("ZS-C11-1", new string[] { "hxjC", "A12AGV允许出空箱", "true" }); putdic.Add("ZS-C12-1", new string[] { "hxjC", "A13AGV允许出空箱", "true" }); putdic.Add("ZS-C13-1", new string[] { "hxjC", "A14AGV允许出空箱", "true" }); putdic.Add("ZS-C14-1", new string[] { "hxjC", "A1AGV允许出空箱", "true" }); //putdic.Add("ZS-A01-1", new string[] { "hxjA", "A3AGV允许出空箱", "true" }); //putdic.Add("ZS-A02-1", new string[] { "hxjA", "A4AGV允许出空箱", "true" }); //putdic.Add("ZS-A03-1", new string[] { "hxjA", "A5AGV允许出空箱", "true" }); //putdic.Add("ZS-D06-1", new string[] { "hxjA", "A6AGV允许出空箱", "false" }); //putdic.Add("ZS-A05-1", new string[] { "hxjA", "A7AGV允许出空箱", "true" }); //putdic.Add("ZS-A06-1", new string[] { "hxjA", "A8AGV允许出空箱", "true" }); putdic.Add("ZS-A07-1", new string[] { "hxjA", "A9AGV允许出空箱", "true" }); putdic.Add("ZS-A08-1", new string[] { "hxjA", "A10AGV允许出空箱", "true" }); putdic.Add("ZS-A09-1", new string[] { "hxjA", "A11AGV允许出空箱", "true" }); putdic.Add("ZS-A10-1", new string[] { "hxjA", "A12AGV允许出空箱", "true" }); putdic.Add("ZS-A11-1", new string[] { "hxjA", "A13AGV允许出空箱", "false" }); putdic.Add("ZS-A12-1", new string[] { "hxjA", "A14AGV允许出空箱", "true" }); // D线 待改成配置 putdic.Add("ZS-D01-1", new string[] { "hxjA", "A1AGV允许出空箱", "false" }); putdic.Add("ZS-D02-1", new string[] { "hxjA", "A2AGV允许出空箱", "false" }); putdic.Add("ZS-D03-1", new string[] { "hxjA", "A3AGV允许出空箱", "false" }); putdic.Add("ZS-D04-1", new string[] { "hxjA", "A4AGV允许出空箱", "false" }); putdic.Add("ZS-D05-1", new string[] { "hxjA", "A5AGV允许出空箱", "false" }); putdic.Add("ZS-D06-1", new string[] { "hxjA", "A6AGV允许出空箱", "false" }); putdic.Add("ZS-D07-1", new string[] { "hxjA", "A7AGV允许出空箱", "false" }); putdic.Add("ZS-D08-1", new string[] { "hxjA", "A8AGV允许出空箱", "false" }); if (action == "LOAD")//取货 { if (getdic.Keys.Contains(disTask.startlocation_code)) { var strarr = getdic.Where(p => p.Key == disTask.startlocation_code).First().Value; Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = strarr[0], ["token"] = _eleCtlCfg.token, ["TagName"] = strarr[1], ["Value"] = strarr[2], }; Logger.Information($"SsxControlLOAD:{JsonConvert.SerializeObject(dicCommand)}"); var str = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand); Logger.Information($"SsxControlLOAD:{str}"); //Logger.Information($"SsxControlUNLOAD - 控制后查询:{_redisData.GetHash(strarr[0], strarr[1]).Result}"); } } else if (action == "UNLOAD")//放货 { if (putdic.Keys.Contains(disTask.endlocation_code)) { var strarr = putdic.Where(p => p.Key == disTask.endlocation_code).First().Value; Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = strarr[0], ["token"] = _eleCtlCfg.token, ["TagName"] = strarr[1], ["Value"] = strarr[2], }; Logger.Information($"SsxControlUNLOAD:{JsonConvert.SerializeObject(dicCommand)}"); var str = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand); Logger.Information($"SsxControlUNLOAD:{str}"); //Logger.Information($"SsxControlUNLOAD - 控制后查询:{_redisData.GetHash(strarr[0], strarr[1]).Result}"); } } } /// /// 二楼机械臂 /// /// public async Task Floor2MechanicalConfirm(WmsDistaskH disTask, string action) { List rackAreaPointsUp = new List(); List rackAreaPointsDown = new List(); // 二楼上升降区料架区点位 rackAreaPointsUp.Add("AS01"); rackAreaPointsUp.Add("AS02"); // 二楼下升降区料架区点位 rackAreaPointsDown.Add("AX01"); rackAreaPointsDown.Add("AX02"); try { List basLocations = _db.Queryable().Where(r => (r.location_code == disTask.endlocation_code || r.location_code == disTask.startlocation_code) && r.wh_id != "33780009364245").ToList(); // 暂存仓内任务 if (disTask.area_code == "E" && basLocations.Count() == 0) { await _db.Ado.BeginTranAsync(); Logger.Information($"【二楼机械臂Floor2MechanicalComplete】收到到货确认信号 传入参数: {disTask.bill_code} {action}"); if (action == "UNLOAD") { // 去料架区放货 if (rackAreaPointsUp.Contains(disTask.endlocation_code) || rackAreaPointsDown.Contains(disTask.endlocation_code)) { ISugarQueryable WmsMechanicalArmHs = _db.Queryable().Where(r => r.location_code == disTask.endlocation_code); if (WmsMechanicalArmHs.Count() == 0) { Logger.Information($"【二楼机械臂Floor2MechanicalComplete】 任务执行终点{disTask.endpoint_code} 与料架区的点位不匹配"); throw new Exception($"【二楼机械臂Floor2MechanicalComplete】 任务执行终点{disTask.endpoint_code} 与料架区的点位不匹配"); } WmsMechanicalArmH target = WmsMechanicalArmHs.First(); // 回写料架和AGV确认 await _db.Updateable().SetColumns(r => new WmsMechanicalArmH { agvconfirm = 1, rackid = disTask.carry_id, rackcode = disTask.carry_code }).Where(r => r.id == target.id).ExecuteCommandAsync(); Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV已到货 {disTask.endpoint_code} 更新缓存表{target.id}"); if (rackAreaPointsDown.Contains(disTask.endlocation_code)) { int LXCount = _db.Queryable().Where(a => a.carry_id == disTask.carry_id).Count(); // 绑定料架 await _db.Updateable().SetColumns(r => new WmsMechanicalArmH { mechanicalconfirm = 1, maxnum = LXCount }).Where(r => r.id == target.id).ExecuteCommandAsync(); Logger.LogInformation($@"【送满托到下升降区】 料架{target.rackid}下的料箱开始生成预任务"); bool pretask_result = await Floor2EmptyCarryCreateZZCPretask(disTask.carry_id); if (pretask_result) { Logger.LogInformation($@"【送满托到下升降区】 料架{target.rackid}下的料箱生成预任务完成"); } else { Logger.LogInformation($@"【送满托到下升降区】 料架{target.rackid}下的料箱生成预任务失败"); throw new Exception($@"【送满托到下升降区】 料架{target.rackid}下的料箱生成预任务失败"); } } } else // 去暂存仓放货 { // 回写料架料箱绑定表的库位 ISugarQueryable WmsCarryCodes = _db.Queryable() .InnerJoin((a, b) => b.membercarry_id == a.carry_id) .Where((a, b) => b.carry_id == disTask.carry_id); var WmsCarryCodeList = WmsCarryCodes.ToList(); WmsCarryCodeList.ForEach(r => { r.location_id = disTask.endlocation_id; r.location_code = disTask.endlocation_code; }); await _db.Updateable(WmsCarryCodeList).ExecuteCommandAsync(); } } else { // 去暂存仓取货 if (rackAreaPointsUp.Contains(disTask.endlocation_code) || rackAreaPointsDown.Contains(disTask.endlocation_code)) { Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV在暂存仓取货确认完成"); } else // 去料架区取货 { ISugarQueryable WmsMechanicalArmHs = _db.Queryable().Where(r => r.location_code == disTask.startlocation_code); if (WmsMechanicalArmHs.Count() == 0) { Logger.Information($"【二楼机械臂Floor2MechanicalComplete】 任务执行终点{disTask.endpoint_code} 与料架区的点位不匹配"); throw new Exception($"【二楼机械臂Floor2MechanicalComplete】 任务执行终点{disTask.endpoint_code} 与料架区的点位不匹配"); } WmsMechanicalArmH target = WmsMechanicalArmHs.First(); if (target.note == "上升降机") { bool result = await Floor2UpDownMachinecode_SetTag($"上升降机满托{target.stackingposition}移走", "true"); Logger.LogInformation($@"【上升降机】设定升上升降机满托{target.stackingposition}移走 结果为 {result}"); if (!result) { throw new Exception($@"【上升降机】设定升上升降机满托{target.stackingposition}移走 结果为 {result}"); } // 更新料架在二楼配送的目标工位 // todo erp工位字段取数位置未确定 WmsMaterialTransferD wmsMaterialTransferD = await _db.Queryable() .LeftJoin((a, b) => a.id == b.bill_id).Where((a, b) => a.bill_code == target.outbill) .Select((a, b) => b).FirstAsync(); if (wmsMaterialTransferD == null) { Logger.LogWarning($@"【上升降机】 发生异常!,转库单{target.outbill}没有载具明细"); // 转库单删除 不执行后续,不返回失败是为了不卡流程 return; } string targetWorkstation = wmsMaterialTransferD.station_code; if (string.IsNullOrEmpty(wmsMaterialTransferD.station_code)) { throw new Exception($@"【上升降机】 发生异常!,转库单{target.outbill}的工位为空"); } Logger.LogInformation($@"【上升降机】更新料架 {target.rackcode} 在二楼配送的目标工位 {targetWorkstation}"); await _db.Updateable().SetColumns(r => new WmsCarryH { work_station = targetWorkstation, material_tranfer_billid = wmsMaterialTransferD.bill_id }).Where(r => r.id == target.rackid).ExecuteCommandAsync(); } else if (target.note == "下升降机") { bool result = await Floor2UpDownMachinecode_SetTag($"下升降机空托{target.stackingposition}移走", "true"); Logger.LogInformation($@"【上升降机】设定升下升降机空托{target.stackingposition}移走 结果为 {result}"); if (!result) { throw new Exception($@"【上升降机】设定升下升降机空托{target.stackingposition}移走 结果为 {result}"); } } // 重置料架区 await _db.Updateable().SetColumns(r => new WmsMechanicalArmH { stackingcount = 0, barcodes = "", outbill = "", maxnum = 0, iscreatepretask = 0, rackcode = "", rackid = "", agvconfirm = 0, mechanicalconfirm = 0 }).Where(r => r.id == target.id).ExecuteCommandAsync(); Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV在料架区取货完成"); } } await _db.Ado.CommitTranAsync(); } } catch(Exception ex) { Logger.LogError("【Floor2MechanicalComplete】" + ex.ToString()); await _db.Ado.RollbackTranAsync(); throw; } } /// /// 二楼机械臂 /// /// public async Task Floor2MechanicalComplete(WmsDistaskH disTask, string action) { List rackAreaPointsUp = new List(); List rackAreaPointsDown = new List(); // 二楼上升降区料架区点位 rackAreaPointsUp.Add("AS01"); rackAreaPointsUp.Add("AS02"); // 二楼下升降区料架区点位 rackAreaPointsDown.Add("AX01"); rackAreaPointsDown.Add("AX02"); try { List basLocations = _db.Queryable().Where(r => (r.location_code == disTask.endlocation_code || r.location_code == disTask.startlocation_code) && r.wh_id != "33780009364245").ToList(); // 暂存仓内任务 if (disTask.area_code == "E" && basLocations.Count() == 0) { Logger.Information($"【二楼机械臂Floor2MechanicalComplete】收到到货完成信号 传入参数: {disTask.bill_code} {action}"); if (action == "UNLOAD") { // 去料架区放货 if (rackAreaPointsUp.Contains(disTask.endlocation_code) || rackAreaPointsDown.Contains(disTask.endlocation_code)) { ISugarQueryable WmsMechanicalArmHs = _db.Queryable().Where(r => r.location_code == disTask.endlocation_code); if (WmsMechanicalArmHs.Count() == 0) { Logger.Information($"【二楼机械臂Floor2MechanicalComplete】 任务执行终点{disTask.endpoint_code} 与料架区的点位不匹配"); throw new Exception($"【二楼机械臂Floor2MechanicalComplete】 任务执行终点{disTask.endpoint_code} 与料架区的点位不匹配"); } WmsMechanicalArmH target = WmsMechanicalArmHs.First(); // 下升降机写满托数量和送到信号 if (rackAreaPointsDown.Contains(disTask.endlocation_code)) { int LXCount = _db.Queryable().Where(a => a.carry_id == disTask.carry_id).Count(); bool result = await Floor2UpDownMachinecode_SetTag($"下升降机满托{target.stackingposition}数量", LXCount.ToString()); Logger.LogInformation($@"【送满托到下升降区】设定下升降机满托{target.stackingposition}满托数量为 {LXCount} 结果为 {result}"); if (!result) { throw new Exception($"下升降机满托{target.stackingposition}数量 写入失败"); } // 尝试写入满托送到信号 bool result下升降机空托送到 = await Floor2UpDownMachinecode_SetTag($"下升降机满托{target.stackingposition}送到", "true"); Logger.LogInformation($@"【送满托到下升降区】回写 下升降机满托{target.stackingposition}送到 结果为{result下升降机空托送到}"); if (!result下升降机空托送到) { throw new Exception($"下升降机满托{target.stackingposition}送到 写入失败"); } } } else // 去暂存仓放货 { } } else { // 去暂存仓取货 if (rackAreaPointsUp.Contains(disTask.endlocation_code) || rackAreaPointsDown.Contains(disTask.endlocation_code)) { Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV在暂存仓取货完成"); } else // 去料架区取货 { } } } } catch (Exception ex) { Logger.LogError("【Floor2MechanicalComplete】" + ex.ToString()); throw; } } private async Task Floor2UpDownMachinecode_SetTag(string tag, string value) { string DevName = "东面提升机输送线"; Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = DevName, ["token"] = _eleCtlCfg.token, ["TagName"] = tag, ["Value"] = value, }; string result = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand); return result.Contains("Ok"); // 测试 //string DevName = "东面提升机输送线"; //JObject valueJson = new JObject(); //valueJson["Value"] = value; //_redisData.SetHash(DevName, tag, valueJson.ToString()); //return true; } /// /// 生成任务执行 /// /// [HttpPost] public async Task GenTaskExecute() { if (s_GenTaskExecute.CurrentCount == 0) { return; } await s_GenTaskExecute.WaitAsync(); Stopwatch sw = Stopwatch.StartNew(); CancellationTokenSource agvCts = new(); SqlSugarClient db = _db.CopyNew(); try { await CTUTaskExecute(); //获取所有未下发的预任务申请 Logger.Information("【GenTaskExecute】 开始获取未下发的预任务..."); ISugarQueryable sugarQueryable = db.Queryable() .LeftJoin((a, b) => a.carry_id == b.id) .InnerJoin((a, b, c) => a.area_id == c.id) .InnerJoin((a, b, c, d) => a.endlocation_id == d.id && d.is_use == "0") .Where((a, b) => a.status == WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID && !string.IsNullOrWhiteSpace(a.startlocation_id) // 载具为空时 不校验载具当前位置是否与预任务起点相同 && (string.IsNullOrEmpty(a.carry_id) || (!string.IsNullOrEmpty(a.carry_id) && a.startlocation_id == b.location_id))) .OrderBy(a => new { a.bill_code }) .OrderByDescending(a => new { priority = SqlFunc.Desc(a.priority) }) .Select((a, b, c, d) => new WmsPretaskH { move_num = c.move_num, third_eqp_type = c.third_eqp_type, }, true); Logger.Information($"【GenTaskExecute】 获取到{sugarQueryable.Count()}条可执行的预任务..."); if (sugarQueryable.Count() == 0) return; //Logger.Information("【GenTaskExecute】 执行SQL: " + sugarQueryable.ToSqlString()); List preTasks = await sugarQueryable.ToListAsync(); //List executedPreTasks = await db.Queryable().Where(it => it.status != WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID && it.status != WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID).ToListAsync(); List agvElevatorTasks = preTasks .Where(it => it.endlocation_code.StartsWith("DT", StringComparison.OrdinalIgnoreCase) && !it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)) .ToList(); var elePreTasks = preTasks.Where(it => it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList(); var normalPreTasks = preTasks.Where(it => it.area_code != "B" && !agvElevatorTasks.Concat(elePreTasks).Select(x => x.endlocation_code).Contains(it.endlocation_code)).ToList(); //Logger.Information("【GenTaskExecute】 电梯预任务elePreTasks:" + JsonConvert.SerializeObject(elePreTasks)); //Logger.Information("【GenTaskExecute】 AGV/CTU/KIVA预任务normalPreTasks:" + JsonConvert.SerializeObject(normalPreTasks)); //Logger.Information("【GenTaskExecute】 AGV电梯预任务agvElevatorTasks:" + JsonConvert.SerializeObject(agvElevatorTasks)); /* IEnumerable firstEleGrp = agvElevatorTasks.GroupBy(g => g.endlocation_code).Select(t => t.OrderBy(o => o.bill_code).FirstOrDefault()); agvElevatorTasks = firstEleGrp?.ToList() ?? Enumerable.Empty().ToList()!; */ //如果电梯任务,预Agv任务存在相同目标库位,删除Agv任务保证电梯任务先行 var equalEndLocPreTasks = elePreTasks.Select(x => x.endlocation_code).Intersect(agvElevatorTasks.Select(x => x.endlocation_code)); if (equalEndLocPreTasks.Any()) { Logger.Information("【GenTaskExecute】 执行:如果电梯任务,预Agv任务存在相同目标库位,删除Agv任务保证电梯任务先行 "); agvElevatorTasks = agvElevatorTasks.Where(x => !equalEndLocPreTasks.Contains(x.endlocation_code)).ToList(); } #region 原材料仓同巷道任务出库控制同时只发一条 // 原材料仓的未完成任务 List wmspretasks_ycl = await db.Queryable() .InnerJoin((a, b) => a.endlocation_id == b.id) .InnerJoin((a, b, c) => a.area_id == c.id) .InnerJoin((a, b, c, d) => a.startlocation_id == d.id) .Where((a, b, c, d) => a.status != WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID && a.status != WmsWareHouseConst.PRETASK_BILL_STATUS_CANCEL_ID && b.is_use == "0" && d.is_type == "0" && b.wh_id == WmsWareHouseConst.WAREHOUSE_YCL_ID) .Select((a, b, c, d) => new WmsPretaskH { move_num = c.move_num, third_eqp_type = c.third_eqp_type, passage = d.passage }, true) .ToListAsync(); // 原材料仓的执行中任务 List wmspretasksrun_ycl = wmspretasks_ycl.Where(r => r.status == WmsWareHouseConst.PRETASK_BILL_STATUS_YXF_ID || r.status == WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID).ToList(); // 过滤normalPreTasks中的原材料仓的任务 normalPreTasks = normalPreTasks.Where(r => !wmspretasks_ycl.Select(a => a.id).Contains(r.id)).ToList(); // 过滤原材料仓同巷道的正在执行的任务 var yclTasks = wmspretasks_ycl.Where(r => !wmspretasksrun_ycl.Select(a => a.passage).Contains(r.passage)).ToList(); // 过滤重复巷道的预任务 yclTasks = yclTasks.OrderBy(r => r.passage).GroupBy(r => r.passage).Select(r => { return r.ToList()[0]; }).OrderBy(r => r.bill_code).ToList(); normalPreTasks = normalPreTasks.Concat(yclTasks).ToList(); #endregion #region 三楼三四号梯如果与判断一托下有冲突 #region 电梯第三次改动 // 到暂存区的未完成任务 List wmsdistasks_agvElevator = await db.Queryable() .InnerJoin((a, b) => a.endlocation_id == b.id) .Where((a, b) => a.status != WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID && a.status != WmsWareHouseConst.TASK_BILL_STATUS_CANCEL_ID && b.region_id == WmsWareHouseConst.REGION_CPOutstockCache_ID) .ToListAsync(); // 到暂存区的未完成预任务 List wmspretasks_agvElevator = await db.Queryable() .InnerJoin((a, b) => a.endlocation_id == b.id) .InnerJoin((a, b, c) => a.area_id == c.id) .Where((a, b) => a.status != WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID && a.status != WmsWareHouseConst.PRETASK_BILL_STATUS_CANCEL_ID && b.region_id == WmsWareHouseConst.REGION_CPOutstockCache_ID && b.is_use == "0") .Select((a, b, c) => new WmsPretaskH { move_num = c.move_num, third_eqp_type = c.third_eqp_type, }, true) .ToListAsync(); // 过滤normalPreTasks中的到三楼暂存区任务 normalPreTasks = normalPreTasks.Where(r => !wmspretasks_agvElevator.Select(a => a.endlocation_id).Contains(r.endlocation_id)).ToList(); // 过滤到三楼暂存区同目标库位的正在执行的任务 var cacheLocTasks = wmspretasks_agvElevator.Where(r => !wmsdistasks_agvElevator.Select(a => a.endlocation_id).Contains(r.endlocation_id)).ToList(); // 过滤重复目标库位的预任务 cacheLocTasks = cacheLocTasks.OrderBy(r => r.endlocation_code).GroupBy(r => r.endlocation_code).Select(r => { return r.ToList()[0]; }).OrderBy(r => r.bill_code).ToList(); normalPreTasks = normalPreTasks.Concat(cacheLocTasks).ToList(); #endregion if (s_elevatortaskWCSRequestDic.Count > 0) { for (int index_agvElevatorTasks = 0; index_agvElevatorTasks < agvElevatorTasks.Count; index_agvElevatorTasks++) { WmsPretaskH wmsPretaskH = agvElevatorTasks[index_agvElevatorTasks]; string area_code = ""; // 找到电梯任务的电梯区域 if (wmsPretaskH.start_floor == "3" && wmsPretaskH.end_floor == "3") { if (wmsPretaskH.endlocation_code == "DT-3-3") { area_code = "ELE03"; } else if (wmsPretaskH.endlocation_code == "DT-3-4") { area_code = "ELE04"; } } // 如果不是三楼三四号梯出货 if (string.IsNullOrEmpty(area_code)) { continue; } SemaphoreSlim s_elevatortaskWCSRequest = s_elevatortaskWCSRequestDic[area_code]; if (s_elevatortaskWCSRequest.CurrentCount == 0) { Logger.Information($"【GenTaskExecute】 获取到AGV到电梯{area_code}的预任务{wmsPretaskH.bill_code}正在执行一托下判断,此时不下发任务"); agvElevatorTasks.RemoveAt(index_agvElevatorTasks); index_agvElevatorTasks--; } else { Logger.Information($"【GenTaskExecute】AGV到电梯{area_code}的预任务{wmsPretaskH.bill_code}没有在执行一托下判断,正常下发任务"); } } } #endregion preTasks = normalPreTasks.Concat(agvElevatorTasks).Concat(elePreTasks).ToList(); if (preTasks.Count() == 0) return; //一楼中储仓CTU List ids = preTasks.Select(x => x.id).Distinct().ToList(); List? preTaskCodes = await db.Queryable().Where(it => ids.Contains(it.bill_id)).ToListAsync(); if (preTasks.Count > 0) { //根据预任务管理区分组,获取到所有分组后的预任务,遍历每个预任务 是否为任务链,通过管理区ID List> preTaskGroups = preTasks.GroupBy(g => g.area_code).ToList(); List disTasks = new(); List distaskCodes = new(); foreach (IGrouping? itGroup in preTaskGroups) { List items = itGroup.Adapt>(); for (int i = 0, cnt = items.Count; i < cnt; i++) { items[i].id = SnowflakeIdHelper.NextId(); items[i].create_time = DateTime.Now; items[i].status = WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID; } int moveNum = itGroup.First().move_num; int itemsCount = items.Count; int mod = itemsCount % moveNum > 0 ? (itemsCount / moveNum) + 1 : itemsCount / moveNum; WmsDistaskH[] arrary = items.ToArray(); //for (int i = 1; i <= mod; i++) { if (moveNum >= 1) { List areaPreTasks = itGroup.ToList(); if (areaPreTasks.Any(x => x.third_eqp_type.ToEnum() != EnumTaskChainType.CTU)) { Logger.Information("非CTU任务链生成"); for (int i = 0; i < items.Count; i++) { var num = (i + 1); var x = items[i]; string groupCode = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE).Result; x.is_chain = 0; x.groups = groupCode; x.bill_code = $"{groupCode}-1"; } } else if ((moveNum >= areaPreTasks.Count && areaPreTasks.Count > 1) || moveNum <= areaPreTasks.Count) { Logger.Information("CTU任务链生成"); string groupCode = await _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE); items.ForEach(x => x.is_chain = 1); int start = 0; int end = Math.Min(itemsCount, moveNum); List arrList = new(mod); while (start < itemsCount) { WmsDistaskH[] subArray = arrary[start..end]; arrList.Add(subArray); start = end; end = Math.Min(end + moveNum, arrary.Length); } foreach (WmsDistaskH[] arr in arrList) { for (int j = 1, len = arr.Length; j <= len; j++) { arr[j - 1].groups = groupCode; arr[j - 1].bill_code = $"{groupCode}-{j}"; } } } Logger.Information($"已生成任务执行编码"); } } if (preTaskCodes?.Count > 0) { foreach (WmsDistaskH disTask in items) { List curPreTaskCodes = preTaskCodes.FindAll(x => x.bill_id == disTask.pretask_id); List curDisTaskCodes = curPreTaskCodes.Adapt>(); curDisTaskCodes.ForEach(x => { x.id = SnowflakeIdHelper.NextId(); x.bill_id = disTask.id; x.create_time = DateTime.Now; }); distaskCodes.AddRange(curDisTaskCodes); } } disTasks.AddRange(items); } await db.Ado.BeginTranAsync(); int row = await db.Insertable(disTasks).ExecuteCommandAsync(); Logger.Information("【GenTaskExecute】 插入任务执行表数据: " + JsonConvert.SerializeObject(disTasks)); if (preTaskCodes?.Count > 0) { row = await db.Insertable(distaskCodes).ExecuteCommandAsync(); Logger.Information("【GenTaskExecute】 插入任务执行条码表数据: " + JsonConvert.SerializeObject(disTasks)); } if (row > 0) { List preTaskIds = preTasks.Select(x => x.id).ToList(); List preTaskBill_codes = preTasks.Select(x => x.bill_code).ToList(); row = await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_YXF_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync(); Logger.Information("【GenTaskExecute】 更改这些预任务执行状态为 已下发: " + JsonConvert.SerializeObject(preTaskBill_codes)); } await db.Ado.CommitTranAsync(); Logger.Information("【GenTaskExecute】 预任务执行完成"); Logger.Information($"【GenTaskExecute】_eleCtlCfg.Environment={_eleCtlCfg.Environment}"); if (string.Equals(_eleCtlCfg.Environment, ElevatorConsts.EnvironmentName, StringComparison.OrdinalIgnoreCase)) { //呼梯操作 //获取目标库位为电梯库位的任务 Logger.Information("【GenTaskExecute】操作设备"); var agvDTTasks = disTasks.Where(it => it.endlocation_code.StartsWith("DT", StringComparison.OrdinalIgnoreCase) && !it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList(); foreach (var task in agvDTTasks) { ElevagorInfoQuery q = new() { endlocation_id = task.endlocation_id, taskCode = task.bill_code }; Logger.Information($"【GenTaskExecute】呼梯时 根据任务单号获取电梯参数 {JsonConvert.SerializeObject(q)}"); var e = await FindElevatorFromPars(q); Logger.Information($"【GenTaskExecute】呼梯时 根据任务单号获取电梯结果 {JsonConvert.SerializeObject(e)}"); var tags = _eleCtlCfg.tags; (int sysStatus, int runStatus, int floorNo, int doorStatus, int agvStatus) = await _elevatorControlService.GetElevatorStatus(e.elevator_code, tags, CancellationToken.None); Logger.Information($"【GenTaskExecute】 电梯当前状态->系统状态:{sysStatus.ToEnum()},运行状态:{runStatus.ToEnum()},Agv状态:{agvStatus.ToEnum()},当前楼层:{floorNo},电梯占用状态{s_eleUseStatusDic[e.device_id]}"); var curFloor = await GetRealFloor(e.elevator_code, e.end_floor); if (e != null && s_eleUseStatusDic[e.device_id] == (int)EnumElevatorUseStatus.空闲 && curFloor != floorNo) { task.device_id = e.device_id; } } _ = CallingLanding(agvDTTasks); //执行电梯任务 List? elevatorTasks = disTasks.Where(it => it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList(); Logger.Information($"【GenTaskExecute】当前电梯任务数:{elevatorTasks?.Count ?? 0}"); if (elevatorTasks?.Count > 0) { List> elevatorTaskGroup = elevatorTasks.GroupBy(r => $"{r.endlocation_code} {r.end_floor}").ToList(); foreach (IGrouping group in elevatorTaskGroup) { List wmsDistaskHs = group.ToList(); ElevagorInfoQuery q = new() { endlocation_id = wmsDistaskHs[0].endlocation_id, taskCode = wmsDistaskHs[0].bill_code }; Logger.Information($"【GenTaskExecute】执行电梯任务时 根据任务单号获取电梯参数 {JsonConvert.SerializeObject(q)}"); var e = await FindElevatorFromPars(q); Logger.Information($"【GenTaskExecute】执行电梯任务时 根据任务单号获取电梯结果 {JsonConvert.SerializeObject(e)}"); // 三、四号梯发货带两托货进定时任务 string[] doubleCarryRunElevators = new string[2] { "Elevator3","Elevator4" }; if (doubleCarryRunElevators.Contains(e.elevator_code) && wmsDistaskHs[0].end_floor == 1) { //Logger.Information($"【GenTaskExecute】判断为三四号梯任务"); //Logger.Information($"【GenTaskExecute】现在有{group.Count()}托货"); //// 电梯内放置两托货呼叫电梯下 //if (group.Count() == 2) //{ // if (e != null) // { // wmsDistaskHs[0].device_id = e.device_id; // wmsDistaskHs[1].device_id = e.device_id; // } // Logger.Information($"【GenTaskExecute】呼叫电梯"); // _ = ExecuteTargetFloorTask(wmsDistaskHs); //} //// 一托货 //else if (group.Count() == 1) //{ // // 如果当前电梯没有执行中的任务 则呼叫电梯下 // if (_db.Queryable().Where(r => r.status != WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID // && r.status != WmsWareHouseConst.TASK_BILL_STATUS_CANCEL_ID && r.endlocation_id == wmsDistaskHs[0].startlocation_id).Count() == 0) // { // Logger.Information($"【GenTaskExecute】判断为三四号梯任务 没有执行中的任务 呼叫电梯"); // if (e != null) // { // wmsDistaskHs[0].device_id = e.device_id; // } // _ = ExecuteTargetFloorTask(wmsDistaskHs); // } //} //else //{ // Logger.LogError($"电梯 {e.elevator_code} 待执行的电梯任务数异常 目前是{group.Count()} 超过了两托"); //} } else { //Logger.Information($"【GenTaskExecute】判断为非三四号梯任务"); //if (e != null) //{ // wmsDistaskHs[0].device_id = e.device_id; //} //Logger.Information($"【GenTaskExecute】呼叫电梯"); //_ = ExecuteTargetFloorTask(wmsDistaskHs); } } } List agvTasks = disTasks.Where(it => !it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList(); if (agvTasks?.Count > 0) { Logger.Information($"【GenTaskExecute】Agv任务数量:{agvTasks.Count},taskCodes:{string.Join(",", agvTasks.Select(x => x.bill_code).Distinct())}"); _ = AgvDispatch(agvTasks, agvCts.Token); } } } } catch (Exception ex) when (ex is HttpRequestException hReqEx) { agvCts.Cancel(); } catch (Exception ex) { Logger.Error("【GenTaskExecute】任务执行时出现错误", ex); Logger.Error(ex.StackTrace!); await db.Ado.RollbackTranAsync(); throw; } finally { _ = s_GenTaskExecute.Release(); agvCts.Dispose(); sw.Stop(); Logger.Information($"【GenTaskExecute】 任务执行耗时{sw.ElapsedMilliseconds}毫秒"); } } /// /// 获取电梯根据任务单号 /// /// /// taskCode:子任务编号 /// endlocation_id:目标库位ID /// /// public async Task FindElevatorFromPars(ElevagorInfoQuery input) { var whereExpable = Expressionable.Create() .And((a, b, c) => a.enabled == 1); Logger.Information($"【FindElevatorFromPars】 {JsonConvert.SerializeObject(input)}"); if (!input.taskCode.IsNullOrEmpty()) { whereExpable.AndIF(!SqlFunc.IsNullOrEmpty(input.taskCode), (a, b, c) => c.bill_code == input.taskCode); } if (!input.endlocation_id.IsNullOrEmpty()) { whereExpable.AndIF(!SqlFunc.IsNullOrEmpty(input.endlocation_id), (a, b, c) => b.location_id == input.endlocation_id); } if (!input.startlocation_id.IsNullOrEmpty()) { whereExpable.AndIF(!SqlFunc.IsNullOrEmpty(input.startlocation_id), (a, b, c) => b.location_id == input.startlocation_id); } var db = _db.CopyNew(); #region 如果是出到三楼出库缓存区 List queryable_f3outstock = db.Queryable() .InnerJoin((a, b) => a.endlocation_id == b.id) .InnerJoin((a, b, c) => a.endlocation_code == c.startlocation_code) .InnerJoin((a, b, c, d) => c.endlocation_code == d.location_code) .InnerJoin((a, b, c, d, e) => d.bill_id == e.id) .Where((a, b, c, d, e) => a.endlocation_id == input.endlocation_id && a.bill_code == input.taskCode && b.region_id == WmsWareHouseConst.REGION_CPOutstockCache_ID) .Select((a, b, c, d, e) => new WmsElevatorH { bill_code = a.bill_code, device_id = e.elevator_id, end_floor = a.end_floor }).ToList(); if (queryable_f3outstock.Count() > 0) { var ele_f3outstock = queryable_f3outstock[0]; return ele_f3outstock; } #endregion ISugarQueryable queryable = db.Queryable().InnerJoin((a, b) => a.id == b.bill_id) .InnerJoin((a, b, c) => b.location_code == c.endlocation_code || b.location_code == c.startlocation_code) .Where(whereExpable.ToExpression()) .WhereIF(!SqlFunc.IsNullOrEmpty(input.sourceName) && SqlFunc.StartsWith("DT-R", input.sourceName), (a, b, c) => c.startpoint_code == input.sourceName) .WhereIF(!SqlFunc.IsNullOrEmpty(input.sourceName) && SqlFunc.StartsWith("DT-C", input.sourceName), (a, b, c) => c.endpoint_code == input.sourceName) .Select((a, b, c) => new WmsElevatorH { bill_code = c.bill_code, device_id = a.elevator_id, end_floor = c.end_floor }, true); var ele = await queryable.FirstAsync(); Logger.Information($"【FindElevatorFromPars】 " + queryable.ToSqlString()); return ele; } #region CTU /// /// 生成CTU任务执行 /// /// [HttpPost] public async Task CTUTaskExecute() { try { Dictionary indic = new Dictionary(); indic.Add("SSX-021-005", new string[] { "YTCS", "CallCtuFullIn_CS05" }); indic.Add("SSX-111-011", new string[] { "东面提升机输送线", "下升降机11呼叫CTU" }); indic.Add("SSX-111-012", new string[] { "东面提升机输送线", "下升降机12呼叫CTU" }); var db = _db.CopyNew(); List CTUTasks = await db.Queryable() .InnerJoin((a, b) => a.area_id == b.id) .Where(a => a.status == WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID) .Where((a, b) => b.code == "B")//一楼中储仓 .OrderBy(a => a.create_id) .Select((a, b) => new WmsPretaskH { move_num = b.move_num, third_eqp_type = b.third_eqp_type, }, true).ToListAsync(); if (CTUTasks.Count == 0) return; List TaskCodes = await db.Queryable().Where(it => CTUTasks.Select(p => p.id).ToList().Contains(it.bill_id)).ToListAsync(); //Logger.Information($@"【CTUTaskExecute】 获取任务TaskCodes: {JsonConvert.SerializeObject(TaskCodes)}"); var InTasks = CTUTasks.Where(a => a.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID).ToList(); var OutTasks = CTUTasks.Where(a => a.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID || a.task_type == WmsWareHouseConst.BIZTYPE_WMSTRANSFER_ID).ToList(); //Logger.Information($@"【CTUTaskExecute】 获取任务InTasks: {JsonConvert.SerializeObject(InTasks)}"); //Logger.Information($@"【CTUTaskExecute】 获取任务OutTasks: {JsonConvert.SerializeObject(OutTasks)}"); var OriginDistaskHs = await db.Queryable() .InnerJoin((a, b) => a.area_id == b.id) .Where((a, b) => b.code == "B" && a.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID) .OrderBy(a => a.bill_code) .ToListAsync(); //Logger.Information($@"【CTUTaskExecute】 OriginDistaskHs: {JsonConvert.SerializeObject(OriginDistaskHs)}"); List DistaskHs = new List(); List UpDistaskHs = new List(); List DistaskCodes = new List(); var inCtuExec = new List(); var outCtuExec = new List(); foreach (var item in InTasks) { /* if (indic.Keys.Contains(item.startlocation_code)) { var strs = indic.Where(p => p.Key == item.startlocation_code).First().Value; bool flag = _redisData.HashExist(strs[0], strs[1]).Result; if (!flag) continue; string data = _redisData.GetHash(strs[0], strs[1]).Result; JObject? res = JsonConvert.DeserializeObject(data); bool result = res != null && res["Value"] != null ? res.Value("Value") : false; if (!result) continue; }*/ WmsDistaskH distaskH = item.Adapt(); distaskH.id = SnowflakeIdHelper.NextId(); distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID; distaskH.is_chain = 1; distaskH.create_time = DateTime.Now; var billcode = GetBillCode(OriginDistaskHs, DistaskHs, distaskH); distaskH.groups = billcode.Substring(0, billcode.Length - 2); distaskH.bill_code = billcode; var num = int.Parse(distaskH.bill_code.Substring(billcode.Length - 1, 1)); Logger.Information($@"【CTUTaskExecute】 比对billcode:{num}和单次搬运数量move_num:{item.move_num},如果一致 会添加到inCtuExec"); if (num == item.move_num) { distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID; inCtuExec.Add(distaskH); if (OriginDistaskHs.Where(p => p.groups == distaskH.groups).Any()) { OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID); UpDistaskHs.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList()); inCtuExec.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList()); } if (DistaskHs.Where(p => p.groups == distaskH.groups).Any()) { DistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID); inCtuExec.AddRange(DistaskHs.Where(p => p.groups == distaskH.groups).ToList()); } } List preTaskCodes = TaskCodes.FindAll(x => x.bill_id == distaskH.pretask_id); List disTaskCodes = preTaskCodes.Adapt>(); disTaskCodes.ForEach(x => { x.id = SnowflakeIdHelper.NextId(); x.bill_id = distaskH.id; x.create_time = DateTime.Now; }); DistaskHs.Add(distaskH); DistaskCodes.AddRange(disTaskCodes); } foreach (var item in OutTasks) { WmsDistaskH distaskH = item.Adapt(); distaskH.id = SnowflakeIdHelper.NextId(); distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID; distaskH.is_chain = 1; distaskH.create_time = DateTime.Now; var billcode = GetBillCode(OriginDistaskHs, DistaskHs, distaskH); distaskH.groups = billcode.Substring(0, billcode.Length - 2); distaskH.bill_code = billcode; var num = int.Parse(distaskH.bill_code.Substring(billcode.Length - 1, 1)); Logger.Information($@"【CTUTaskExecute】 比对billcode:{num}和单次搬运数量move_num:{item.move_num},如果一致 会添加到outCtuExec"); if (num == item.move_num) { distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID; outCtuExec.Add(distaskH); if (OriginDistaskHs.Where(p => p.groups == distaskH.groups).Any()) { OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID); UpDistaskHs.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList()); outCtuExec.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList()); } if (DistaskHs.Where(p => p.groups == distaskH.groups).Any()) { DistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID); outCtuExec.AddRange(DistaskHs.Where(p => p.groups == distaskH.groups).ToList()); } } List preTaskCodes = TaskCodes.FindAll(x => x.bill_id == distaskH.pretask_id); List disTaskCodes = preTaskCodes.Adapt>(); disTaskCodes.ForEach(x => { x.id = SnowflakeIdHelper.NextId(); x.bill_id = distaskH.id; x.create_time = DateTime.Now; }); DistaskHs.Add(distaskH); DistaskCodes.AddRange(disTaskCodes); } await db.Ado.BeginTranAsync(); int row = 0; if (UpDistaskHs.Count > 0) { await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID }).Where(it => UpDistaskHs.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync(); } if (DistaskHs.Count > 0) { row = await db.Insertable(DistaskHs).ExecuteCommandAsync(); } if (DistaskCodes.Count > 0) { await db.Insertable(DistaskCodes).ExecuteCommandAsync(); } if (row > 0) { List preTaskIds = DistaskHs.Select(x => x.pretask_id).ToList(); await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_YXF_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync(); } await db.Ado.CommitTranAsync(); //判断 Logger.Information($"【CTUTaskExecute】 判断单据状态(status)是否为待执行 {JsonConvert.SerializeObject(DistaskHs)}"); if (DistaskHs.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID).Any()) { var time = int.Parse(db.Queryable().Where(P => P.key == "getinterval").First().value); timer = new Timer(TimerExec, null, TimeSpan.FromMinutes(time), TimeSpan.FromMinutes(time)); } //Logger.Information($@"【CTUTaskExecute】 可执行的CTU任务inCtuExec: {JsonConvert.SerializeObject(inCtuExec)}"); if (inCtuExec.Count > 0) { Logger.Information($"开始执行CTU入库任务: {JsonConvert.SerializeObject(inCtuExec)}"); //呼叫ctu入库 // await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_RUNING_ID }).Where(it => inCtuExec.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync(); // await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => inCtuExec.Select(x => x.pretask_id).ToList().Contains(it.id)).ExecuteCommandAsync(); CancellationTokenSource Ctu = new(); await CallingCTU(inCtuExec, Ctu.Token, 1); Ctu.Dispose(); } //Logger.Information($@"【CTUTaskExecute】 可执行的CTU任务outCtuExec: {JsonConvert.SerializeObject(outCtuExec)}"); if (outCtuExec.Count > 0) { Logger.Information($"开始执行CTU出库任务: {JsonConvert.SerializeObject(outCtuExec)}"); //呼叫ctu出库 // await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_RUNING_ID }).Where(it => outCtuExec.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync(); // await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => outCtuExec.Select(x => x.pretask_id).ToList().Contains(it.id)).ExecuteCommandAsync(); CancellationTokenSource Ctu = new(); await CallingCTU(outCtuExec, Ctu.Token, 0); Ctu.Dispose(); } } catch (Exception ex) { throw; } } //判断生成bill_code private string GetBillCode(List OriginDistaskH, List NewdistaskHs, WmsDistaskH distaskH) { string BillCode = string.Empty; //入库 if (distaskH.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID) { var orgdistaskHs = OriginDistaskH.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID && p.startpoint_id == distaskH.startpoint_id).ToList(); var newdistaskHs = NewdistaskHs.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID && p.startpoint_id == distaskH.startpoint_id).ToList(); if ((orgdistaskHs.Count + newdistaskHs.Count) == 0) { var groups = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE).Result; BillCode = $"{groups}-1"; } else { var groups = orgdistaskHs.Count > 0 ? orgdistaskHs.First().groups : newdistaskHs.First().groups; BillCode = $"{groups}-" + (orgdistaskHs.Count + newdistaskHs.Count + 1); } } else if (distaskH.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID || distaskH.task_type == WmsWareHouseConst.BIZTYPE_WMSTRANSFER_ID) { var orgdistaskHs = OriginDistaskH.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID && p.endpoint_id == distaskH.endpoint_id).ToList(); var newdistaskHs = NewdistaskHs.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID && p.endpoint_id == distaskH.endpoint_id).ToList(); if ((orgdistaskHs.Count + newdistaskHs.Count) == 0) { var groups = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE).Result; BillCode = $"{groups}-1"; } else { var groups = orgdistaskHs.Count > 0 ? orgdistaskHs.First().groups : newdistaskHs.First().groups; BillCode = $"{groups}-" + (orgdistaskHs.Count + newdistaskHs.Count + 1); } } return BillCode; } private Timer? timer; private async void TimerExec(object e) { try { SqlSugarClient db = _db.CopyNew(); var list = db.Queryable().InnerJoin((a, b) => a.area_id == b.id) .Where((a, b) => b.code == "B" && a.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID) .OrderBy(a => a.bill_code) .ToList(); var data = list.GroupBy(p => p.groups).Select(p => new { groups = p.Key, time = p.Max(a => a.create_time) }).ToList(); var date = DateTime.Now; var time = int.Parse(db.Queryable().Where(P => P.key == "getinterval").First().value); foreach (var item in data) { if (date.Subtract(item.time).Minutes >= time) { var execlist = list.Where(p => p.groups == item.groups).ToList(); await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID }).Where(it => execlist.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync(); // await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => execlist.Select(x => x.pretask_id).ToList().Contains(it.id)).ExecuteCommandAsync(); CancellationTokenSource Ctu = new(); int type = execlist.First().task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID ? 1 : 0; await CallingCTU(execlist, Ctu.Token, type); Ctu.Dispose(); } } } catch (Exception ex) { } finally { timer?.Dispose(); } } private async Task CallingCTU(List distaskHs, CancellationToken token, int type) { try { AgvRequestConfig requestCfg = App.Configuration.Build(); string url = requestCfg.AgvRequestUrls.CreateTaskChainUrl; var taskChainCodeDic = distaskHs.Where(t => !t.groups.IsNullOrWhiteSpace()).GroupBy(g => g.groups!) .ToDictionary(x => x.Key, x => x.Select(it => new { taskCode = it.bill_code, sourceName = it.startpoint_code, targetName = it.endpoint_code, containerCode = it.carry_code, })); foreach ((string k, object v) in taskChainCodeDic) { dynamic reqBody = new ExpandoObject(); reqBody.taskChainCode = k; reqBody.type = (int)EnumTaskChainType.CTU; reqBody.sequential = false; reqBody.taskChainPriority = 0; reqBody.taskList = v; reqBody.inOut = type; Logger.Information($"【CallingCTU】 CTU任务下发 开始请求联核/task-chain/create接口 请求地址:{url} 请求参数:{JsonConvert.SerializeObject(reqBody)} type:{(type == 0 ? "CTU出库" : "CTU入库")}"); dynamic respBody = await HttpClientHelper.PostStreamAsync(url, reqBody, token); Logger.Information($"【CallingCTU】 CTU任务下发 接收到联核/task-chain/create接口信息:{respBody}"); } } catch (Exception ex) { Logger.Information($"【CallingCTU】 CTU任务下发 请求联核/task-chain/create接口失败 异常信息:{ex}"); } } #endregion /// /// 呼梯操作 /// /// /// public async Task CallingLanding(List agvDTTasks) { Logger.Information($"【GenTaskExecute】呼梯任务数:{agvDTTasks.Count}"); List<(string endlocation_code, string device_id, string id, int start_floor)> endLocCodes = agvDTTasks.Where(r => !string.IsNullOrEmpty(r.device_id)) .Select(it => (it.endlocation_code, it.device_id, it.id, it.start_floor)).ToList(); var callLiftCnt = endLocCodes?.Count ?? 0; Logger.Information($"【GenTaskExecute】实际可呼梯任务数:{callLiftCnt}"); if (endLocCodes?.Count > 0) { if (endLocCodes.Select(x => x.device_id).All(x => !x.IsNullOrWhiteSpace())) { Logger.Information("【GenTaskExecute】呼梯操作"); // todo } else { Logger.Error("【GenTaskExecute】呼梯失败,没有设备ID"); return; } } Logger.Information($"【CallingLanding】 开始呼梯操作............."); try { foreach ((_, string devId, string disTaskId, int floorNO) in endLocCodes) { Logger.Information($"【CallingLanding】 devId:{devId}"); if (!s_elevatorMap.TryGetValue(devId, out object? elevatorCode)) { continue; } string? devName = elevatorCode.ToString(); Logger.Information($"【CallingLanding】 电梯编号:{devName}"); Logger.Information($"【CallingLanding】 当前:{devName.Match(@"\d+")}#梯"); await _elevatorControlService.WriteTagAsync(devName, ElevatorConsts.AGVControl, 1); (int sysStatus, int runStatus, int curFloorNo, int doorStatus, int agvStatus) eleStatusMulti = (-1, -1, -1, -1, -1); Logger.Information("【CallingLanding】 获取电梯AGV运行状态"); if (!_elevatorAgvCtlStatusMap.TryGetValue(devId, out int agvCtlStatus) || agvCtlStatus != (int)EnumAgvStatus.AGV运行状态) { var tags = new[] { "SysStatus", "RunStatus", "FloorNo", "DoorStatus", "AGVStatus" }; do { eleStatusMulti = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None); await Task.Delay(1000); } while (eleStatusMulti.agvStatus != (int)EnumAgvStatus.AGV运行状态); Logger.Information($"{devName.Match(@"\d+")}#, 当前Agv状态:{eleStatusMulti.agvStatus.ToEnum()}"); _elevatorAgvCtlStatusMap[devId] = eleStatusMulti.agvStatus; } else { Logger.Information("【CallingLanding】 AGV运行状态:" + agvCtlStatus); } Logger.Information($"【CallingLanding】 任务开始目标楼层为:{floorNO}"); int floorN = await GetRealFloor(devName, floorNO); //如果电梯在当前楼层则不呼梯 if (floorN == eleStatusMulti.curFloorNo) { Logger.Information($"【CallingLanding】 {devName.Match(@"\d+")}#,在当前楼层,无需呼梯"); continue; } Logger.Information($"【CallingLanding】 实际目标楼层为:{floorN}"); WmsElevatorUnexecute elevatorQueueItem = new() { distask_id = disTaskId, elevator_id = devId, elevator_code = devName, floor = floorN, //5代表4楼 task_status = "待执行", create_id = _userManager.UserId, create_time = DateTime.Now }; List elevatorQueue = await _db.Queryable().Where(it => it.distask_id == disTaskId && it.task_status == "执行中").ToListAsync(); Logger.Information($"【CallingLanding】 电梯{devName}状态为{s_eleUseStatusDic[devId]}"); Logger.Information($"【CallingLanding】 电梯{devName} 任务id{disTaskId} 执行中的队列数量为{elevatorQueue.Count}"); if ((elevatorQueue.IsNull() || elevatorQueue.Count < 1) && floorN != eleStatusMulti.curFloorNo && s_eleUseStatusDic[devId] == (int)EnumElevatorUseStatus.空闲) { Logger.Information($"【CallingLanding】 判断当前电梯{devName.Match(@"\d+")}#梯 无任务在做执行呼梯"); elevatorQueueItem.task_status = "执行中"; bool callLiftRes = await _elevatorControlService.CallLift(devName, floorN, CancellationToken.None); string successful = "成功", fail = "失败"; string callLiftResult = callLiftRes ? successful : fail; Logger.Information($"{devName.Match(@"\d+")}#, 呼梯结果:{callLiftResult}"); } else { Logger.Information("【CallingLanding】 当前有任务在做,不会呼梯"); } //如果当前电梯有任务在做,将当前呼梯任务放入待执行队列 _ = await _db.Insertable(elevatorQueueItem).ExecuteCommandAsync(); Logger.Information("【CallingLanding】 呼梯任务执行完成"); } } catch (Exception ex) { Logger.Error("【CallingLanding】 呼梯操作错误", ex); Logger.Error($"【CallingLanding】 呼梯操作错误堆栈跟踪:{Environment.NewLine}{ex.StackTrace}"); throw; } } /// /// 执行到目标楼层电梯任务 /// /// /// public async Task ExecuteTargetFloorTask(List disTasks, ISqlSugarClient db = null) { //收到放货确认通知,向电梯发送到3楼的指令 Logger.Information($"开始执行电梯任务,任务:{string.Join(",", disTasks.Select(r => r.bill_code))}"); var disTask = disTasks[0]; Logger.Information($"disTask.require_id={disTask.require_id}"); List disTaskIds = new() { disTasks[0].id }; if (disTasks.Count == 2) { disTaskIds.Add(disTasks[1].id); } string devName = ""; try { if (!s_elevatorMap.TryGetValue(disTask.device_id, out object? elevatorCode)) { Logger.Information($"开始执行电梯任务,没有取到设备{disTask.device_id}的 elevatorCode! s_elevatorMap: {JsonConvert.SerializeObject(s_elevatorMap)}"); return; } devName = s_elevatorMap[disTask.device_id]?.ToString() ?? _eleCtlCfg.DevName3; // 回写act_start_date之前会发给wcs重置深浅位,没回写就是没发 if (disTasks[0].act_start_date == null) { TaskExecuteAfterUpInput teaUpInput = new() { disTaskIds = disTaskIds, }; await TaskExecuteAfter(teaUpInput, db); string[] doubleCarryRunElevators = { "Elevator3","Elevator4" }; if (doubleCarryRunElevators.Contains(devName) && disTasks[0].end_floor == 1) { AgvRequestConfig requestCfg = App.Configuration.Build(); string url = requestCfg.AgvRequestUrls.thirdFloorUrl; dynamic reqBody = new ExpandoObject(); reqBody.floor = devName == "Elevator3" ? "03" : "04"; reqBody.isDown = true; CancellationTokenSource Ctu = new(); Logger.Information($"【ElevatorTaskExceptionHandle】 电梯{devName}下行 开始请求WCS lift/thirdFloor接口 请求地址:{url} 请求参数:{JsonConvert.SerializeObject(reqBody)} "); dynamic respBody = await HttpClientHelper.PostStreamAsync(url, reqBody, Ctu.Token); Logger.Information($"【ElevatorTaskExceptionHandle】 电梯{devName}下行 接收到WCS lift/thirdFloor接口信息:{respBody}"); JObject respBodyobj = JObject.Parse(respBody); if (respBodyobj["code"].ToString() != "200") { throw new Exception($"通知WCS电梯{devName}下行接口调用错误"); } else { Logger.Information($"通知WCS电梯{devName}下行接口调用成功"); } List carryHs = await db.Queryable().Where(r => disTasks.Select(r => r.carry_id).Contains(r.id)).ToListAsync(); carryHs.ForEach(r => { r.location_id = disTask.endlocation_id; r.location_code = disTask.endlocation_code; }); await db.Updateable(carryHs).ExecuteCommandAsync(); #region 电梯第三次改动 var _floor3FirstSelectElevator = await db_agvElevatorTaskExceptionHandles.Queryable().Where(p => p.key == "floor3FirstSelectElevator").FirstAsync(); // 一托下且当前电梯组还没有后续任务且首选电梯为当前电梯的情况下,切换首选电梯为另一部 int task_nums = db.Queryable().Where(r => r.elevator_group == "2").Sum(r => r.task_nums); if (disTaskIds.Count == 1 && task_nums == 1 && devName == _floor3FirstSelectElevator.value) { await ChangeSelectedElevator(db); } #endregion } } } catch { throw; } finally { SemaphoreSlim s_elevatortaskWCSRequest = s_elevatortaskWCSRequestDic[disTask.area_code]; s_elevatortaskWCSRequest.Release(); } try { var tags = new[] { "SysStatus", "RunStatus", "FloorNo", "DoorStatus", "AGVStatus" }; (int sysStatus, int runStatus, int curFloorNo, int doorStatus, int agvStatus) eleStatusMulti = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None); if (eleStatusMulti.agvStatus != (int)EnumAgvStatus.AGV运行状态) { _ = await _elevatorControlService.WriteTagAsync(devName, ElevatorConsts.AGVControl, 1); } if (!_elevatorAgvCtlStatusMap.TryGetValue(disTask.id, out int agvCtlStatus) || agvCtlStatus != (int)EnumAgvStatus.AGV运行状态) { do { eleStatusMulti = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None); Logger.Information($"{devName.Match(@"\d+")}#, 当前Agv状态:{eleStatusMulti.agvStatus.ToEnum()}"); await Task.Delay(1000); } while (eleStatusMulti.agvStatus != (int)EnumAgvStatus.AGV运行状态); Logger.Information($"{devName.Match(@"\d+")}#, 当前Agv状态:{eleStatusMulti.agvStatus.ToEnum()}"); _elevatorAgvCtlStatusMap[disTask.id] = eleStatusMulti.agvStatus; } int doorStatus = -1; bool closeDoorRes = await _elevatorControlService.SendOpenCloseCmd(devName, 4); //向电梯发送前门关门指令 Logger.Information($"{devName.Match(@"\d+")}#梯 关门结果:{closeDoorRes}"); // 检查门状态 int checkCloseDoor = 0; do { checkCloseDoor++; doorStatus = await _elevatorControlService.GetTagAsync(devName, ElevatorConsts.DoorStatus); Logger.Information($"第{checkCloseDoor}次 {devName.Match(@"\d+")}#梯 当前门状态:{doorStatus}"); // 30次后重试 if (checkCloseDoor >= 30) { throw new Exception($"电梯{devName}关门状态判断已达30次,即将重新执行这批电梯任务"); } await Task.Delay(1000); } while (doorStatus != 4); Logger.Information($"第{checkCloseDoor}次 结束判断 {devName.Match(@"\d+")}#梯 当前门状态:{doorStatus}"); int floor = await GetRealFloor(devName, disTask.end_floor); //电梯任务手动执行任务状态上报 (int sysStatus, int runStatus, int floorNo, int doorStatus, int agvStatus) tuple = (-1, -1, -1, -1, -1); tuple = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None); Logger.Information($"{devName.Match(@"\d+")}#梯 目标楼层:{floor} 当前楼层:{tuple.floorNo}"); Logger.Information($"{devName.Match(@"\d+")}#梯 开始呼梯 {devName}到{floor}"); //发送到目标楼的指令 dynamic result = await _elevatorControlService.WriteTagAsync(devName, ElevatorConsts.FloorExecute, floor); // 检查电梯下行状态 int checkRunDoor = 0; do { checkRunDoor++; tuple = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None); Logger.Information($"第{checkRunDoor}次 {devName.Match(@"\d+")}#梯 sysStatus:{tuple.sysStatus},runStatus:{tuple.runStatus},当前楼层floorNo:{tuple.floorNo},目标楼层{floor}"); // 180次后重试 if (checkRunDoor >= 180) { throw new Exception($"电梯{devName}运行状态判断已达180次,即将重新执行这批电梯任务"); } await Task.Delay(1000); } while (tuple.sysStatus != 3 || tuple.runStatus != 0 || floor != tuple.floorNo); Logger.Information($"第{checkRunDoor}次 结束判断 {devName.Match(@"\d+")}#梯 sysStatus:{tuple.sysStatus},runStatus:{tuple.runStatus},当前楼层floorNo:{tuple.floorNo},目标楼层disTask.end_floor={floor}"); if (tuple.sysStatus.ToEnum() == EnumSysStatus.正常状态 && tuple.runStatus.ToEnum() == EnumRunStatus.停梯) { TaskCompleUpInput tcUpInput = new() { disTaskIds = disTaskIds, }; await TaskComplate(tcUpInput, db); Logger.Information($"{devName.Match(@"\d+")}#梯 电梯任务执行完成"); } } catch (Exception ex) { Logger.LogWarning($"执行到目标楼层电梯任务失败{ex.Message}"); Logger.LogWarning($"执行到目标楼层电梯任务失败{ex.StackTrace}"); throw; } } /// /// Agv调度 /// /// /// /// private async Task AgvDispatch(List disTasks, CancellationToken token) { Logger.Information("【AgvDispatch】 Agv任务执行...."); List kiva = new List(); // 一楼中储仓 kiva.Add("ZSSSXCTU02"); kiva.Add("ZSSSXCTU01"); List floor2 = new List(); // 二楼暂存仓 //floor2.Add("AS01"); //floor2.Add("AS02"); //floor2.Add("AX01"); //floor2.Add("AX02"); // 三、四号梯发货带两托货 string[] doubleCarryRunElevators = { "29815764588053","29815767573013" }; string[] doubleCarryRunElevatorsF1Code = { "DT-1-3","DT-1-4" }; //调用AGV创建任务链接口 try { AgvRequestConfig requestCfg = App.Configuration.Build(); string url = requestCfg.AgvRequestUrls.CreateTaskChainUrl; Logger.Information($"【AgvDispatch】 Agv任务执行的disTasks:{JsonConvert.SerializeObject(disTasks)}"); var taskChainCodeDic = disTasks.Where(t => !t.groups.IsNullOrWhiteSpace()).GroupBy(g => g.groups!) .ToDictionary(x => x.Key, x => x.Select(it => new { taskCode = it.bill_code, sourceName = it.startpoint_code, targetName = it.endpoint_code, containerCode = it.carry_code, shelfNumber = it.area_code == "E" ? it.carry_code : "" // 二楼暂存仓传料架 })); Logger.Information($"【AgvDispatch】 Agv任务执行的taskChainCodeDic:{JsonConvert.SerializeObject(taskChainCodeDic)}"); foreach ((string k, object v) in taskChainCodeDic) { var dis = disTasks.Where(p => p.groups == k).First(); dynamic reqBody = new ExpandoObject(); reqBody.taskChainCode = k; reqBody.type = (int)EnumTaskChainType.AGV; if (kiva.Contains(dis.startlocation_code) || kiva.Contains(dis.endlocation_code) //|| floor2.Contains(dis.startlocation_code) || floor2.Contains(dis.endlocation_code) ) { reqBody.type = (int)EnumTaskChainType.KIVA; } // 如果管理区是E(二楼暂存仓和二楼缓存仓) 统一发KIVA if (dis.area_code == "E") { reqBody.type = (int)EnumTaskChainType.KIVA; } // 三四号电梯出货 暂存仓到三楼电梯以及一楼电梯出库任务发type5 if ((dis.startlocation_code.Contains("CPOutstockCache") && dis.endlocation_code.Contains("DT")) || doubleCarryRunElevatorsF1Code.Contains(dis.startlocation_code)) { reqBody.type = (int)EnumTaskChainType.电梯载两托货; } // 原材料仓使用优先级 if (dis.area_code == "A") { reqBody.sequential = true; reqBody.taskChainPriority = dis.priority; } else { reqBody.sequential = false; reqBody.taskChainPriority = 0; } reqBody.taskList = v; reqBody.floor = dis.end_floor; Logger.Information($"【AgvDispatch】 Agv任务执行 开始请求联核/task-chain/create接口 请求地址:{url} 请求参数:{JsonConvert.SerializeObject(reqBody)} "); dynamic respBody = await HttpClientHelper.PostStreamAsync(url, reqBody, token); Logger.Information($"【AgvDispatch】 Agv任务执行 接收到联核/task-chain/create接口信息:{respBody}"); } } catch (Exception ex) { Logger.Information($"【AgvDispatch】 agv任务执行 请求联核/task-chain/create接口失败 异常信息:{ex}"); throw; } } /// /// 任务执行 /// /// /// [HttpPost] public async Task TaskExecute(TaskExecuteUpInput input) { try { List disTasks = await _db.Queryable().Where(a => input.disTaskIds.Contains(a.id)).ToListAsync(); foreach (WmsDistaskH wmsDistaskH in disTasks) { WmsCarryH wmsCarryH = await _db.Queryable().Where(r => r.location_id == wmsDistaskH.startlocation_id && r.carry_code != wmsDistaskH.carry_code).FirstAsync(); BasLocation startlocation = await _db.Queryable().Where(r => r.location_code == wmsDistaskH.startlocation_code).FirstAsync(); if (wmsCarryH != null && startlocation.is_type == ((int)(EnumLocationType.存储库位)).ToString()) { throw Oops.Bah($"任务单{wmsDistaskH.bill_code}的起点库位{wmsDistaskH.startlocation_code}是存储库位,且已被载具{wmsCarryH.carry_code}占用!"); } } await _db.Ado.BeginTranAsync(); //更任务执行 for (int i = 0, cnt = input.disTaskIds.Count; i < cnt; i++) { _ = input.EqpIds?.Count > 0 ? await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID, device_id = input.EqpIds[i] }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync() : await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync(); //await _db.Updateable().SetColumns(it => setColVal).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync(); } List preTaskIds = await _db.Queryable().Where(it => input.disTaskIds.Contains(it.id)).Select(it => it.pretask_id).ToListAsync(); if (preTaskIds.Count > 0) { //更预任务申请表状态 _ = await _db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync(); } await _db.Ado.CommitTranAsync(); } catch (Exception ex) { Logger.Error("任务执行失败", ex); await _db.Ado.RollbackTranAsync(); throw; } } /// /// 任务执行取操作返回(后续操作) /// /// [HttpPost] public async Task TaskExecuteAfter(TaskExecuteAfterUpInput input, ISqlSugarClient dbConn = null) { //更新任务执行表单据状态 var db = dbConn; if (dbConn == null) db = _db.CopyNew(); try { await db.Ado.BeginTranAsync(); _ = await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_RUNING_ID, act_start_date = DateTime.Now }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync(); //清空载具库位数据 var carryAndLocIds = await db.Queryable().Where(it => input.disTaskIds.Contains(it.id)).Select(it => new { it.carry_id, it.startlocation_id }).ToListAsync(); if (carryAndLocIds?.Count > 0) { List carryIds = carryAndLocIds.Select(x => x.carry_id).ToList(); _ = await db.Updateable().SetColumns(it => new WmsCarryH { location_id = null, location_code = null }).Where(it => carryIds.Contains(it.id)).ExecuteCommandAsync(); } //更新起始库位,状态改为空闲、锁定状态,未锁定 if (carryAndLocIds?.Count > 0) { List startLocationIds = carryAndLocIds.Select(x => x.startlocation_id).ToList(); _ = await db.Updateable().SetColumns(it => new BasLocation { is_use = ((int)EnumCarryStatus.空闲).ToString(), is_lock = 0, carry_count = it.carry_count - 1 }).Where(it => startLocationIds.Contains(it.id)).ExecuteCommandAsync(); } List disTasks = db.Queryable().Where(r => input.disTaskIds.Contains(r.id)).ToList(); foreach (WmsDistaskH disTask in disTasks) { // 出电梯减一托盘数 if (disTask.startlocation_code.Contains("DT") && !disTask.endlocation_code.Contains("DT")) { ElevagorInfoQuery q = new() { startlocation_id = disTask.startlocation_id, taskCode = disTask.bill_code }; Logger.Information($"【ElevatorTaskExceptionHandle】执行电梯任务时 根据任务单号获取电梯参数 {JsonConvert.SerializeObject(q)}"); var e = await FindElevatorFromPars(q); Logger.Information($"【ElevatorTaskExceptionHandle】执行电梯任务时 根据任务单号获取电梯结果 {JsonConvert.SerializeObject(e)}"); await _db.Updateable().SetColumns(r => new WmsElevatorH { carry_count = r.carry_count - 1 }).Where(r => r.elevator_id == e.device_id).ExecuteCommandAsync(); } } await db.Ado.CommitTranAsync(); } catch (Exception ex) { Logger.Error("设备取返回操作失败", ex); await db.Ado.RollbackTranAsync(); } } [HttpPost] public async Task TaskComplate(TaskCompleUpInput input) { List disTasks = await _db.Queryable().Where(a => input.disTaskIds.Contains(a.id)).ToListAsync(); foreach (WmsDistaskH wmsDistaskH in disTasks) { WmsCarryH wmsCarryH = await _db.Queryable().Where(r => r.location_id == wmsDistaskH.endlocation_id && r.carry_code != wmsDistaskH.carry_code).FirstAsync(); BasLocation endlocation = await _db.Queryable().Where(r => r.location_code == wmsDistaskH.endlocation_code).FirstAsync(); if (wmsCarryH != null && endlocation.is_type == ((int)(EnumLocationType.存储库位)).ToString()) { throw Oops.Bah($"任务单{wmsDistaskH.bill_code}的终点库位{wmsDistaskH.endlocation_code}是存储库位,且已被载具{wmsCarryH.carry_code}占用!"); } } await TaskComplate(input, _db); } /// /// 任务完成 /// /// [NonAction] public async Task TaskComplate(TaskCompleUpInput input, ISqlSugarClient dbConn = null) { var db = dbConn; if (dbConn == null) db = _db.CopyNew(); try { Logger.Information($"【TaskComplate】 开始执行TaskComplate {JsonConvert.SerializeObject(input)}"); await db.Ado.BeginTranAsync(); //更新任务执行表,单据状态为 完成 _ = await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID, act_end_date = DateTime.Now }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync(); List disTasks = await db.Queryable().InnerJoin((a, b) => a.carry_id == b.id).Where(a => input.disTaskIds.Contains(a.id)).Select((a, b) => new WmsDistaskH { carry_status = b.carry_status }, true).ToListAsync(); Logger.Information($"【TaskComplate】 disTasks 值 {JsonConvert.SerializeObject(disTasks)}"); if (disTasks?.Count > 0) { // 更新预任务申请表,单据状态为 已完成 List preTaskIds = disTasks.Select(x => x.pretask_id).ToList(); _ = await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync(); #region 电梯 WmsElevatorH wmsElevatorH = await db.Queryable().Where(r => disTasks.Select(x => x.area_code).Contains(r.area_code)).FirstAsync(); if (wmsElevatorH != null) { Logger.LogInformation($"【TaskComplate】更新前电梯{disTasks[0].area_code}信息{JsonConvert.SerializeObject(wmsElevatorH)}"); //更新电梯任务数量 int eleUpdateRow = 0; foreach (var disTask in disTasks) { eleUpdateRow += await db.Updateable().SetColumns(it => new WmsElevatorH { task_nums = it.task_nums - 1 }).Where(it => disTask.area_code == it.area_code).ExecuteCommandAsync(); } Logger.LogInformation($"【TaskComplate】更新电梯{disTasks[0].area_code}任务行数{eleUpdateRow}"); } foreach (var disTask in disTasks) { // 进电梯任务加一托盘数 if (disTask.endlocation_code.Contains("DT") && !disTask.startlocation_code.Contains("DT")) { ElevagorInfoQuery q = new() { endlocation_id = disTask.endlocation_id, taskCode = disTask.bill_code }; Logger.Information($"【ElevatorTaskExceptionHandle】执行电梯任务时 根据任务单号获取电梯参数 {JsonConvert.SerializeObject(q)}"); var e = await FindElevatorFromPars(q); Logger.Information($"【ElevatorTaskExceptionHandle】执行电梯任务时 根据任务单号获取电梯结果 {JsonConvert.SerializeObject(e)}"); await _db.Updateable().SetColumns(r => new WmsElevatorH { carry_count = r.carry_count + 1 }).Where(r => r.elevator_id == e.device_id).ExecuteCommandAsync(); } } #endregion // 更新任务数量 _ = await db.Updateable().SetColumns(it => new BasLocation { task_nums = it.task_nums - 1 }).Where(it => disTasks.Select(x => x.endlocation_code).Contains(it.location_code)).ExecuteCommandAsync(); //更新载具,锁定状态为未锁定,更新载具的库位当前任务的目标库位 List<(string carry_id, string carry_status, string endlocation_id, string endlocation_code)> multiList = disTasks.Select(it => (it.carry_id, it.carry_status, it.endlocation_id, it.endlocation_code)).ToList(); Dictionary locWhIdMap = await db.Queryable().Where(it => multiList.Select(x => x.endlocation_id).Contains(it.id)).ToDictionaryAsync(it => it.id, it => it.wh_id); Dictionary locTypeMap = await db.Queryable().Where(it => multiList.Select(x => x.endlocation_id).Contains(it.id)).ToDictionaryAsync(it => it.id, it => it.is_type); Dictionary locCarrycountMap = await db.Queryable().Where(it => multiList.Select(x => x.endlocation_id).Contains(it.id)).ToDictionaryAsync(it => it.id, it => it.carry_count); List carryIts = new(); List carryCodeIts = new(); List locIts = new(); Logger.Information($"【TaskComplate】 multiList 值 {JsonConvert.SerializeObject(multiList)}"); for (int i = 0, cnt = multiList.Count; i < cnt; i++) { WmsCarryH carry = new() { id = multiList[i].carry_id, is_lock = 0, location_id = multiList[i].endlocation_id, location_code = multiList[i].endlocation_code, instock_time = DateTime.Now }; string endLocId = multiList[i].endlocation_id; WmsCarryH wmsCarryH = await db.Queryable().Where(r => r.id == carry.id).FirstAsync(); // 同步料架下的载具位置 if (wmsCarryH != null && wmsCarryH.carrystd_id == WmsWareHouseConst.CARRY_LJSTD_ID) { List carrys = db.Queryable() .InnerJoin((a, b) => a.membercarry_id == b.id).Where((a, b) => a.carry_id == carry.id).Select((a, b) => b).ToList(); carrys.ForEach(r => { r.location_id = carry.location_id; r.location_code = carry.location_code; carryIts.Add(r); }); } List carrycodes = db.Queryable().Where(r => r.carry_id == carry.id).ToList(); carrycodes.ForEach(r => { r.warehouse_id = locWhIdMap.ContainsKey(endLocId) ? locWhIdMap[endLocId].ToString() : ""; r.location_id = multiList[i].endlocation_id; r.location_code = multiList[i].endlocation_code; carryCodeIts.Add(r); }); carryIts.Add(carry); BasLocation loc = new() { id = multiList[i].endlocation_id, is_lock = 0, carry_count = locCarrycountMap[endLocId] == null || string.IsNullOrEmpty(locCarrycountMap[endLocId].ToString()) ? 1: int.Parse(locCarrycountMap[endLocId].ToString()) + 1, is_use = string.IsNullOrEmpty(multiList[i].carry_status) ? ((int)EnumCarryStatus.占用).ToString() : multiList[i].carry_status }; if (!string.IsNullOrEmpty(multiList[i].carry_status)) { loc.is_use = ((int)EnumCarryStatus.占用).ToString(); } // 如果是出入库位 完成后解除占用 string? is_type = locTypeMap.ContainsKey(endLocId) ? locTypeMap[endLocId].ToString() : ""; if (is_type == ((int)EnumLocationType.出入库位).ToString()) loc.is_use = ((int)EnumCarryStatus.空闲).ToString(); locIts.Add(loc); } _ = await db.Updateable(carryIts).UpdateColumns(it => new { it.is_lock, it.location_id, it.location_code, it.instock_time }).ExecuteCommandAsync(); Logger.Information($"【TaskComplate】 更新载具 {JsonConvert.SerializeObject(carryIts)}"); //更新条码的库位和仓库信息 _ = await db.Updateable(carryCodeIts).UpdateColumns(it => new { it.warehouse_id, it.location_id, it.location_code }).ExecuteCommandAsync(); //更新库位信息,使用状态为 使用,锁定状态为未锁定 _ = await db.Updateable(locIts).UpdateColumns(it => new { it.is_use, it.is_lock, it.carry_count }).ExecuteCommandAsync(); Logger.Information($"【TaskComplate】 更新库位 {JsonConvert.SerializeObject(locIts)}"); /* var loginType= _userManager?.LoginType ?? "web"; Log.Information($"_userManager.LoginType={loginType}"); */ //更新业务主表的单据状态 foreach (WmsDistaskH? dt in disTasks) { AddOutinStockDetailInput addOutinStockDetailInput = new AddOutinStockDetailInput(); addOutinStockDetailInput.disTask = dt; addOutinStockDetailInput.start_warehouse_id = locWhIdMap.ContainsKey(dt.startlocation_id) ? locWhIdMap[dt.startlocation_id].ToString() : ""; addOutinStockDetailInput.end_warehouse_id = locWhIdMap.ContainsKey(dt.endlocation_id) ? locWhIdMap[dt.endlocation_id].ToString() : ""; await _wmsOutinStockDetailService.AddOutinStockDetail(addOutinStockDetailInput, db); #region todo 移到service中 // 销售出库 if (dt.biz_type == WmsWareHouseConst.BIZTYPE_WMSSALERELEASE_ID) { // TODO 一楼工位放货完成后更新出库明细的实际出库数量 if (dt.start_floor == 1 && dt.end_floor == 1) { WmsCarryCode wmsCarryCode = await db.Queryable().Where(r => r.carry_id == dt.carry_id).FirstAsync(); await db.Updateable().SetColumns(r => r.purchase_prqty == r.purchase_prqty + wmsCarryCode.codeqty).Where(r => r.id == dt.require_id).ExecuteCommandAsync(); CarryCodeUnbindInput carryCodeUnbindInput = new CarryCodeUnbindInput(); carryCodeUnbindInput.carry_id = dt.carry_id; await _wmsCarryUnbindService.CarryCodeUnbind(carryCodeUnbindInput, db); } } // 成品调拨入库 else if (dt.biz_type == WmsWareHouseConst.BIZTYPE_WMSTRANSFERINSTOCK_ID) { if (dt.start_floor == 3 && dt.end_floor == 3) { WmsCarryCode wmsCarryCode = await db.Queryable().Where(r => r.carry_id == dt.carry_id).FirstAsync(); await db.Updateable().SetColumns(r => r.qty == r.qty + wmsCarryCode.codeqty).Where(r => r.id == dt.require_id).ExecuteCommandAsync(); } } // 二楼物料呼叫任务结束后清空工位信息 else if (dt.biz_type == "FloorCallMaterial") { await db.Updateable().SetColumns(r => new WmsCarryH { work_station = "" }).Where(r => r.id == dt.carry_id).ExecuteCommandAsync(); //await QTRK2BIP(dt, db); // require_code是任务单 //string mo_task_code = dt.require_code; } else if (dt.biz_type == "erp_qtrk") { await QTRK2BIP(dt, db); } #endregion List disTaskCodes = await db.Queryable().Where(it => it.bill_id == dt.id).ToListAsync(); WareHouseUpInput upInput = new() { bizTypeId = dt.biz_type, requireId = dt.require_id!, require_code = dt.require_code!, source_id = dt.source_id! , source_code = dt.source_code!, distaskCodes = disTaskCodes, carryIds = disTasks.Select(x => x.carry_id).ToList(), bill_code = dt.bill_code!,area_code= dt.area_code!,wmsDistaskH = dt! }; /*if (!_userManager?.LoginType.IsNullOrEmpty() ?? false) { upInput.loginType = "app"; } else { upInput.loginType = "web"; }*/ upInput.loginType = "web";//(!string.IsNullOrEmpty(_userManager?.LoginType) ? "app" : "web") ?? "web"; if (dt.is_sign == 1 && dt.chain_type == "3") { await DoUpdate(upInput); } } } Logger.Information($"【TaskComplate】 任务操作完成提交事务 {string.Join(",", input.disTaskIds)}"); await db.Ado.CommitTranAsync(); Logger.Information($"【TaskComplate】 任务操作完成 {string.Join(",", input.disTaskIds)}"); } catch (Exception ex) { Logger.Error($"任务结束失败", ex); Logger.Error($"任务结束失败堆栈异常", ex); await db.Ado.RollbackTranAsync(); throw; } finally { _ = GenTaskExecute(); } } async Task QTRK2BIP(WmsDistaskH? dt, ISqlSugarClient db) { if (string.IsNullOrEmpty(dt.source_id)) { Logger.LogWarning($"上传其它入库到BIP时,转库单ID为空,无法上传 任务信息:{JsonConvert.SerializeObject(dt)}"); return; } WmsMaterialTransfer wmsMaterialTransfer = await db.Queryable().SingleAsync(x => x.id == dt.source_id); //自制的不调erp接口 if (string.IsNullOrEmpty(wmsMaterialTransfer.erp_bill_code)) { return; } List wmsMaterialTransferDs = await db.Queryable().Where(x => x.bill_id == dt.source_id).ToListAsync(); List materialIds = wmsMaterialTransferDs.Select(x => x.material_id).Distinct().ToList(); List unitCodes = wmsMaterialTransferDs.Select(x => x.unit_id).Distinct().ToList(); List unitDatas = await db.Queryable() .LeftJoin((x, y) => x.Id == y.DictionaryTypeId) .Where((x, y) => x.EnCode == DictConst.MeasurementUnit && unitCodes.Contains(y.EnCode)) .Select((x, y) => y) .ToListAsync(); WmsMaterialTransferCarry wmsMaterialTransferCarry = await db.Queryable().Where(x=>x.bill_id==wmsMaterialTransfer.id).FirstAsync(); string carryId = wmsMaterialTransferCarry?.carry_id ?? ""; List wmsCarryCodes = await db.Queryable() .Where(a => a.carry_id == carryId) .ToListAsync(); List supplierIds = wmsCarryCodes.Select(x => x.auxprop_gys).Distinct().ToList(); List ids = new List(); //ids.Add(wmsMaterialTransfer.create_id); ids.Add(WmsWareHouseConst.AdministratorOrgId); ids.Add(wmsMaterialTransfer.warehouse_instock); ids.AddRange(materialIds); ids.AddRange(supplierIds); ids.AddRange(unitDatas.Select(x => x.Id).ToList()); string userId = wmsMaterialTransfer.create_id ?? WmsWareHouseConst.AdministratorUserId; ids.Add(userId); List erpExtendFields = await db.Queryable().Where(x => ids.Contains(x.table_id)).ToListAsync(); //string erpCreateId = erpExtendFields.Find(x => x.table_id == userId)?.user_id ?? WmsWareHouseConst.ERPUSERID; string erpCreateId = WmsWareHouseConst.ERPUSERID; ErpExtendField erpOrg = erpExtendFields.Find(x => x.table_id == (wmsMaterialTransfer.org_id ?? WmsWareHouseConst.AdministratorOrgId)); string nowStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); List erpWarehouserelaHs = await _db.Queryable().Where(x => x.id != null).ToListAsync(); BasWarehouse basWarehouse = await db.Queryable().SingleAsync(x => x.id == wmsMaterialTransfer.warehouse_instock); string whcode = basWarehouse?.whcode ?? ""; List> requestData = new List>(); Dictionary erpRequestData = new Dictionary(); erpRequestData.Add("approver", erpCreateId); erpRequestData.Add("billmaker", erpCreateId); erpRequestData.Add("corpoid", erpOrg.corpoid); erpRequestData.Add("corpvid", erpOrg.corpvid); erpRequestData.Add("creationtime", nowStr); erpRequestData.Add("creator", erpCreateId); erpRequestData.Add("ctrantypeid", "0001H11000000000D310"); // erpRequestData.Add("cwarehouseid",erpExtendFields.Find(x=>x.table_id==wmsMaterialTransfer.warehouse_instock)?.cotherwhid ?? ""); // erpRequestData.Add("cwarehouseid", wmsMaterialTransfer.erp_warehouse_instock); erpRequestData.Add("cwarehouseid", erpWarehouserelaHs.Find(x => x.erp_warehousecode == wmsMaterialTransfer.erp_warehouse_instock)?.erp_warehouseid ?? ""); erpRequestData.Add("cwhsmanagerid", ""); erpRequestData.Add("dbilldate", nowStr); erpRequestData.Add("dmakedate", nowStr); erpRequestData.Add("ntotalnum", wmsMaterialTransferDs.Sum(x => x.qty)); erpRequestData.Add("pk_group", erpOrg.pk_group); erpRequestData.Add("pk_org", erpOrg.pk_org); erpRequestData.Add("pk_org_v", erpOrg.pk_org_v); erpRequestData.Add("vbillcode", wmsMaterialTransfer.bill_code); erpRequestData.Add("vtrantypecode", "4A-02"); List> erpRequestDataDetails = new List>(); foreach (WmsMaterialTransferD item in wmsMaterialTransferDs) { WmsMaterialTransferCarry wmsMaterialTransferCarryItem = await db.Queryable().Where(x=>x.mat_bill_id==item.id).FirstAsync(); string wmsMaterialTransferCarryItemCarryId = wmsMaterialTransferCarryItem?.carry_id ?? ""; WmsCarryCode wmsCarryCode = await db.Queryable().Where(x => x.carry_id == wmsMaterialTransferCarryItemCarryId).FirstAsync(); erpRequestDataDetails.Add(new Dictionary() { ["cbodytranstypecode"] = "4A-02", ["cbodywarehouseid"] = erpWarehouserelaHs.Find(x => x.erp_warehousecode == wmsMaterialTransfer.erp_warehouse_instock)?.erp_warehouseid ?? "", //["cgeneralbid"] = erpWarehouserelaHs.Find(x => x.wms_warehousecode == whcode)?.erp_warehouseid ?? "", ["cgeneralbid"] = null, ["cgeneralhid"] = null, ["cmaterialoid"] = erpExtendFields.Find(x => x.table_id == item.material_id)?.cmaterialoid ?? "", ["cmaterialvid"] = erpExtendFields.Find(x => x.table_id == item.material_id)?.cmaterialvid ?? "", ["corpoid"] = erpOrg.corpoid, ["corpvid"] = erpOrg.corpvid, // ["crowno"] = (wmsMaterialTransferDs.FindIndex(x => x.id == item.id) + 1) * 10, ["crowno"] = item.lineno, ["cunitid"] = erpExtendFields.Find(x => x.table_id == (unitDatas.Find(x => x.EnCode == item.unit_id)?.Id ?? ""))?.cunitid ?? "", ["cvendorid"] = erpExtendFields.Find(x => x.table_id == wmsCarryCode?.auxprop_gys)?.supplier_id ?? "", ["cvendorvid"] = erpExtendFields.Find(x => x.table_id == wmsCarryCode?.auxprop_gys)?.supplier_vid ?? "", ["dbizdate"] = nowStr, ["nnum"] = item.qty, ["pk_group"] = erpOrg.pk_group, ["pk_org"] = erpOrg.pk_org, ["pk_org_v"] = erpOrg.pk_org_v, ["csourcebillbid"] = item.erp_line_pk, ["csourcebillhid"] = wmsMaterialTransfer.erp_pk, ["vbatchcode"] = item.code_batch, ["vfree1"] = wmsCarryCode?.auxprop_xph, }); } erpRequestData.Add("dtls", erpRequestDataDetails); requestData.Add(erpRequestData); BasFactoryConfig config = await db.Queryable().FirstAsync(x => x.enabled == 1 && x.key == FactoryConfigConst.BIPURL); ThirdWebapiRecord thirdWebapiRecord = new ThirdWebapiRecord(); thirdWebapiRecord.id = SnowflakeIdHelper.NextId(); thirdWebapiRecord.third_name = WmsWareHouseConst.BIP; thirdWebapiRecord.name = "其它入库"; thirdWebapiRecord.method = "POST"; // thirdWebapiRecord.url = config.value + "uapws/rest/generalin/save"; thirdWebapiRecord.url = WmsWareHouseConst.BIP_DOMAIN + "uapws/rest/generalin/save"; thirdWebapiRecord.request_data = JsonConvert.SerializeObject(requestData); thirdWebapiRecord.create_time = DateTime.Now; thirdWebapiRecord.remark = $"原材料转库单wms_material_transfer:{wmsMaterialTransfer.bill_code},erp转库单:{wmsMaterialTransfer.erp_bill_code}"; await db.Insertable(thirdWebapiRecord).ExecuteCommandAsync(); BasFactoryConfig callErp = await _db.Queryable().FirstAsync(x => x.enabled == 1 && x.key == FactoryConfigConst.CALLERP); if(callErp.value=="1"){ await _thirdApiRecordService.Send(new List { thirdWebapiRecord }, "自动", _db); } } /// /// 出入库策略启用、禁用状态修改 /// /// /// [HttpPost] public async Task ModifyPoliciesStatus(ModifyEnabledInput input) { async Task _updateStatus(ModifyEnabledInput input) where T : BaseEntity, IUpdatePoliciesStatus, new() { T obj = new() { status = input.status }; _ = await _db.Updateable(obj).UpdateColumns(it => it.status).Where(it => input.ids.Contains(it.id)).ExecuteCommandAsync(); } switch (input.strategyType) { case EnumInOutStockType.In: await _updateStatus(input); break; case EnumInOutStockType.Out: await _updateStatus(input); break; } } /// /// 生成预任务 /// /// 预任务集合 /// 预任务编码集合 /// public async Task GenPreTask(List preTasks, List preTaskCodes, ISqlSugarClient dbConn = null) { try { await s_taskGenPreTask.WaitAsync(); var db = _db; if (dbConn != null) db = dbConn; //如果预任务出现起终库位相同,则删除对应预任务 //modifiy by ly on 20230922 将当前预任务操作者设为四场管理员 preTasks.ForEach(pt => { pt.org_id = WmsWareHouseConst.AdministratorOrgId; pt.create_id = WmsWareHouseConst.AdministratorUserId; }); if (preTasks.FindAll(it => it.startlocation_id == it.endlocation_id)?.Count > 0) { _ = preTasks.RemoveAll(it => it.startlocation_id == it.endlocation_id); } List> grpList = preTasks.OrderBy(o => o.bill_code).GroupBy(g => g.carry_id).ToList(); if (grpList?.Count > 0) { foreach (IGrouping? grp in grpList) { WmsPretaskH[] arr = grp.ToArray(); if (arr.Length > 1) { WmsPretaskH[] subArr = arr[..^1]; System.Array.ForEach(subArr, a => a.chain_type = "1"); } } } int row = await db.Insertable(preTasks).ExecuteCommandAsync(); if (preTaskCodes?.Count > 0) { row = await db.Insertable(preTaskCodes).ExecuteCommandAsync(); } var eleP = preTasks.Find(x => x.area_code.Contains("ELE")); if (eleP != null) { row = await db.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1).Where(it => it.area_code == eleP.area_code).ExecuteCommandAsync(); } // 累加终点库位任务数 row = await db.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1) .Where(it => preTasks.Select(r => r.endlocation_id).Contains(it.id)).ExecuteCommandAsync(); if (row == 0) { throw new Exception($"点位{string.Join(',', preTasks.Select(r => r.endpoint_code))}绑定的库位id为{string.Join(',', preTasks.Select(r => r.endlocation_id))}的库位不存在"); } return row > 0; } catch (Exception ex) { throw; } finally { s_taskGenPreTask.Release(); } } /// /// 生成预任务后续处理 /// /// [NonAction] public async Task GenInStockTaskHandleAfter(GenPreTaskUpInput input, Expression> setCarryColumnsExp, Expression> setLocaionColumbExp, ISqlSugarClient dbConn = null) { try { var db = _db; if (dbConn != null) db = dbConn; //根据生成的预任务,插入预任务操作记录 if (input.PreTaskRecord != null) { _ = await db.Insertable(input.PreTaskRecord).ExecuteCommandAsync(); } if (input.PreTaskHandleCodes.Count > 0) { _ = await db.Insertable(input.PreTaskHandleCodes).ExecuteCommandAsync(); } //根据载具ID,更新是否锁定和赋值起始库位 if (setCarryColumnsExp != null) { Expression> whereExp = input.CarryIds?.Count > 0 ? it => input.CarryIds.Contains(it.id) : it => it.id == input.CarryId; _ = await db.Updateable().SetColumns(setCarryColumnsExp).Where(whereExp).ExecuteCommandAsync(); } if (input.CarryStartLocationId.IsNullOrWhiteSpace() == false) { _ = await db.Updateable().SetColumns(setLocaionColumbExp).Where(it => input.LocationIds.Contains(it.id)).ExecuteCommandAsync(); } //根据所有库位更新库位的锁定状态为“锁定” if (setLocaionColumbExp != null && input.LocationIds?.Count > 0) { _ = await db.Updateable().SetColumns(setLocaionColumbExp).Where(it => input.LocationIds.Contains(it.id)).ExecuteCommandAsync(); } } catch (Exception ex) { Logger.LogError("【GenInStockTaskHandleAfter】" + ex.Message); Logger.LogError("【GenInStockTaskHandleAfter】" + ex.StackTrace); throw; } } /// /// 路径算法 /// /// /// /// [NonAction] public async Task> PathAlgorithms(string pStartId, string pEndId) { /* var sp= await _db.Queryable().Where(it => it.id == pStartId).FirstAsync(); var ep = await _db.Queryable().Where(it => it.id == pEndId).FirstAsync(); if (sp.area_code == "B" || ep.area_code == "B") { List Points = new List(); var zp = await _db.Queryable().Where(it => it.point_code == "ZSCJZJD").FirstAsync(); Points.Add(sp); Points.Add(ep); Points.Add(zp); Points.ForEach(p => { p.area_code = zp.area_code; p.area_id = zp.area_id; }); return Points; }*/ List wmsPointHs = await _db.Queryable().Where(it => it.status == 1).ToListAsync(); List points = new List(); // 待验证 算法太慢 电梯不跑算法 电梯起终点仓库对应表 BasLocation startlocation = await _db.Queryable().InnerJoin((a, b) => a.id == b.location_id).Where((a, b) => b.id == pStartId).FirstAsync(); BasLocation endlocation = await _db.Queryable().InnerJoin((a, b) => a.id == b.location_id).Where((a, b) => b.id == pEndId).FirstAsync(); // 后续可整理成配置表 #region 电梯第三次次改动弃用 //if (startlocation.wh_id == WmsWareHouseConst.WAREHOUSE_CP_ID && endlocation.wh_id == WmsWareHouseConst.WAREHOUSE_CPCRK_ID) //{ // WmsElevatorH wmsElevatorH = await _db.Queryable().Where(it => it.elevator_group == "2" && it.enabled == 1).OrderBy(r => r.task_nums).FirstAsync(); // string elevatorSno = wmsElevatorH.elevator_code.Replace("Elevator", ""); // List locations = await _db.Queryable() // .InnerJoin((a, b) => a.id == b.location_id) // .InnerJoin((a, b, c) => b.id == c.point_id) // .InnerJoin((a, b, c, d) => d.id == c.endpoint_id) // .Where((a, b, c, d) => a.wh_id == WmsWareHouseConst.WAREHOUSE_CP_ID // && a.is_lock == 0 && a.is_use == "0" // && a.region_id == WmsWareHouseConst.REGION_CPOutstockCache_ID && d.point_code == $"DT-3-{elevatorSno}") // .Select((a, b, c, d) => new BasLocation // { // location_code = a.location_code, // extras = d.point_code // }).OrderBy("a.location_code, d.point_code").ToListAsync(); // // 如果没有空闲库位 再找一下另一个电梯的缓存区有没有空闲库位 // if (locations.Count == 0) // { // elevatorSno = elevatorSno == "3" ? "4" : "3"; // locations = await _db.Queryable() // .InnerJoin((a, b) => a.id == b.location_id) // .InnerJoin((a, b, c) => b.id == c.point_id) // .InnerJoin((a, b, c, d) => d.id == c.endpoint_id) // .Where((a, b, c, d) => a.wh_id == WmsWareHouseConst.WAREHOUSE_CP_ID // && a.is_lock == 0 && a.is_use == "0" // && a.region_id == WmsWareHouseConst.REGION_CPOutstockCache_ID && d.point_code == $"DT-3-{elevatorSno}") // .Select((a, b, c, d) => new BasLocation // { // location_code = a.location_code, // extras = d.point_code // }).OrderBy("a.location_code, d.point_code").ToListAsync(); // } // if (locations.Count == 0) // { // throw new AppFriendlyException($"三楼发货时,没有可用的暂存库位可以使用", 500); // } // BasLocation cache_location = locations.First(); // // 到暂存区 // points.Add(wmsPointHs.Where(r => r.id == pStartId).First()); // points.Add(wmsPointHs.Where(r => r.location_code == cache_location.location_code).First()); // // 到电梯 // WmsPointH cacheOut_point = wmsPointHs.Where(r => r.location_code == cache_location.location_code).First().Copy(); // WmsPointH DT_C_point = wmsPointHs.Where(r => r.point_code == $"DT-C-03-0{elevatorSno}").First().Copy(); // cacheOut_point.area_code = "FC"; // DT_C_point.area_code = "FC"; // points.Add(cacheOut_point); // points.Add(DT_C_point); // // 到一楼 // points.Add(wmsPointHs.Where(r => r.point_code == $"DT-3-{elevatorSno}").First()); // points.Add(wmsPointHs.Where(r => r.point_code == $"DT-1-{elevatorSno}").First()); // points.Add(wmsPointHs.Where(r => r.point_code == $"DT-R-01-0{elevatorSno}").First()); // points.Add(wmsPointHs.Where(r => r.id == pEndId).First()); //} #endregion //1-3 if (startlocation.wh_id == WmsWareHouseConst.WAREHOUSE_CPCRK_ID && endlocation.wh_id == WmsWareHouseConst.WAREHOUSE_CP_ID) { WmsElevatorH wmsElevatorH = await _db.Queryable().Where(it => it.elevator_group == "2" && it.enabled == 1).OrderBy(r => r.task_nums).FirstAsync(); string elevatorSno = wmsElevatorH.elevator_code.Replace("Elevator", ""); points.Add(wmsPointHs.Where(r => r.id == pStartId).First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-01-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-1-{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-3-{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-03-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.id == pEndId).First()); } // 2-4 else if(startlocation.wh_id == WmsWareHouseConst.WAREHOUSE_ZZXBK_ID && endlocation.wh_id == WmsWareHouseConst.WAREHOUSE_DMJC_ID) { WmsElevatorH wmsElevatorH = await _db.Queryable().Where(it => it.elevator_group == "1" && it.enabled == 1).OrderBy(r => r.task_nums).FirstAsync(); string elevatorSno = wmsElevatorH.elevator_code.Replace("Elevator", ""); points.Add(wmsPointHs.Where(r => r.id == pStartId).First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-C-02-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-02-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-04-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-R-04-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.id == pEndId).First()); } // 1-4 else if(startlocation.wh_id == WmsWareHouseConst.WAREHOUSE_F1BCK_ID && endlocation.wh_id == WmsWareHouseConst.WAREHOUSE_BCK_ID) { WmsElevatorH wmsElevatorH = await _db.Queryable().Where(it => it.elevator_group == "1" && it.enabled == 1).OrderBy(r => r.task_nums).FirstAsync(); string elevatorSno = wmsElevatorH.elevator_code.Replace("Elevator", ""); points.Add(wmsPointHs.Where(r => r.id == pStartId).First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-C-01-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-01-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-04-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-R-04-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.id == pEndId).First()); } // 4-2 else if (startlocation.wh_id == WmsWareHouseConst.WAREHOUSE_BCK_ID && endlocation.wh_id == WmsWareHouseConst.WAREHOUSE_F2BCQ_ID) { WmsElevatorH wmsElevatorH = await _db.Queryable().Where(it => it.elevator_group == "1" && it.enabled == 1).OrderBy(r => r.task_nums).FirstAsync(); string elevatorSno = wmsElevatorH.elevator_code.Replace("Elevator", ""); points.Add(wmsPointHs.Where(r => r.id == pStartId).First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-C-04-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-04-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-02-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-R-02-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.id == pEndId).First()); } // 4-3 else if (startlocation.wh_id == WmsWareHouseConst.WAREHOUSE_MJC_ID && endlocation.wh_id == WmsWareHouseConst.WAREHOUSE_CP_ID) { WmsElevatorH wmsElevatorH = await _db.Queryable().Where(it => it.elevator_group == "2" && it.enabled == 1).OrderBy(r => r.task_nums).FirstAsync(); string elevatorSno = wmsElevatorH.elevator_code.Replace("Elevator", ""); points.Add(wmsPointHs.Where(r => r.id == pStartId).First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-04-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-4-{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-3-{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-03-0{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.id == pEndId).First()); } else { List roads = await _db.Queryable().Where(it => it.status == 1).ToListAsync(); points = await LocPathCalcAlgorithms(pStartId, pEndId, roads); } //Logger.Information($"起点{startlocation.location_code} 终点{endlocation.location_code} 获取到路径 {JsonConvert.SerializeObject(points)}"); //if (points.Count < 6) //{ // throw new AppFriendlyException($"路径错误,需要检查路径配置{JsonConvert.SerializeObject(points)}", 500); //} //List wmsRoads = await _db.Queryable().Where(r => r.startpoint_id == pStartId).ToListAsync(); //if (wmsRoads?.FindAll(x => x.endpoint_code != null && x.location_code.Contains("dt", StringComparison.OrdinalIgnoreCase))?.Count > 0) //{ //} //List wmsRoads = await _db.Queryable().Where(r => r.startpoint_id == pStartId).ToListAsync(); //try //{ // if (points?.FindAll(x => x.location_code != null && x.location_code.Contains("dt", StringComparison.OrdinalIgnoreCase))?.Count > 0) // { // //查询当前电梯点 // List curEleDs = await _db.Queryable().InnerJoin((a, b) => a.bill_id == b.id).Where((a, b) => points.Select(x => x.id).Contains(a.point_id)).ToListAsync(); // Logger.Information($"curEleDs==null :{curEleDs == null},curEleDs:{string.Join(",", curEleDs.Select(x => x.bill_id))}"); // //如果有电梯点,则会进行电梯的均匀分配 // if (curEleDs?.Count > 0) // { // //当前电梯 // WmsElevatorH curEle = await _db.Queryable().SingleAsync(it => it.id == curEleDs.First().bill_id); // //同电梯组电梯 // List sGpEle = await _db.Queryable().Where(it => it.elevator_group == curEle.elevator_group && it.id != curEle.id && it.enabled == 1).ToListAsync(); // if (curEle.enabled == 0 && (sGpEle == null || sGpEle.Count < 1)) // { // throw new AppFriendlyException("电梯被禁用或未配置", 500); // } // if ((sGpEle == null || sGpEle.Count < 1) && curEle.enabled == 1) // { // return points; // } // if (sGpEle?.Count > 0 && curEle.enabled == 0) // { // return points; // } // //判断电梯组中各电梯任务数 // if (sGpEle.FindAll(x => Math.Abs(x.task_nums - curEle.task_nums) % 2 == 1)?.Count > 0) // { // List sGpDs = await _db.Queryable().Where(it => it.bill_id == sGpEle.First().id).ToListAsync(); // if (sGpDs?.Count > 0) // { // List sGpPoints = await _db.Queryable().Where(it => sGpDs.Select(x => x.point_id).Contains(it.id)).ToListAsync(); // string sFEndId = sGpDs.Single(x => x.floor == curEleDs.First().floor).point_id; // string eFStartId = sGpDs.Single(x => x.floor == curEleDs.Last().floor).point_id; // List sFPoints = await LocPathCalcAlgorithms(pStartId, sFEndId, roads); // List elePoints = new(); // foreach (WmsElevatorD pt in curEleDs) // { // WmsPointH? elePoint = sGpPoints.Find(x => x.floor == pt.floor); // if (elePoint != null) // { // elePoints.Add(elePoint); // } // } // List eFPoints = await LocPathCalcAlgorithms(eFStartId, pEndId, roads); // _ = elePoints.Remove(elePoints.First()); // _ = elePoints.Remove(elePoints.Last()); // points.Clear(); // points.AddRange(sFPoints); // points.AddRange(elePoints); // points.AddRange(eFPoints); // } // } // } // } //} //catch (Exception ex) //{ // Logger.Error("路径算法异常", ex); // throw; //} return points; } /// /// 路径算法 当出现多个载具同时出库,可能需要进入电梯时 /// /// /// /// /// [NonAction] public async Task> PathAlgorithmsEle(string pStartId, string pEndId, int ele) { List roads = await _db.Queryable().Where(it => it.status == 1).ToListAsync(); List points = await LocPathCalcAlgorithms(pStartId, pEndId, roads); try { if (points.FindAll(x => x.location_code != null && x.location_code.Contains("dt", StringComparison.OrdinalIgnoreCase))?.Count > 0) { //查询当前电梯点 List curEleDs = await _db.Queryable().Where(it => points.Select(x => x.id).Contains(it.point_id)).ToListAsync(); //如果有电梯点,则会进行电梯的均匀分配 if (curEleDs?.Count > 0) { //当前电梯 WmsElevatorH curEle = await _db.Queryable().SingleAsync(it => it.id == curEleDs.First().bill_id && it.enabled == 1); //同电梯组电梯 List sGpEle = await _db.Queryable().Where(it => it.elevator_group == curEle.elevator_group && it.id != curEle.id && it.enabled == 1).ToListAsync(); if (curEle == null && sGpEle?.Count > 0) { throw new AppFriendlyException("电梯被禁用或未配置", 500); } if (ele % 2 == 1) { //判断电梯组中各电梯任务数 if (curEle == null || sGpEle.FindAll(x => Math.Abs(x.task_nums - curEle.task_nums) % 2 == 1)?.Count > 0) { List sGpDs = await _db.Queryable().Where(it => it.bill_id == sGpEle.First().id).ToListAsync(); if (sGpDs?.Count > 0) { List sGpPoints = await _db.Queryable().Where(it => sGpDs.Select(x => x.point_id).Contains(it.id)).ToListAsync(); string sFEndId = sGpDs.Single(x => x.floor == curEleDs.First().floor).point_id; string eFStartId = sGpDs.Single(x => x.floor == curEleDs.Last().floor).point_id; List sFPoints = await LocPathCalcAlgorithms(pStartId, sFEndId, roads); List elePoints = new(); foreach (WmsElevatorD pt in curEleDs) { WmsPointH? elePoint = sGpPoints.Find(x => x.floor == pt.floor); if (elePoint != null) { elePoints.Add(elePoint); } } List eFPoints = await LocPathCalcAlgorithms(eFStartId, pEndId, roads); _ = elePoints.Remove(elePoints.First()); _ = elePoints.Remove(elePoints.Last()); points.Clear(); points.AddRange(sFPoints); points.AddRange(elePoints); points.AddRange(eFPoints); } } } } } } catch (Exception ex) { Logger.Error("路径算法异常", ex); throw; } return points; } #region PrivateMethods private async Task> LocPathCalcAlgorithms(string pStartId, string pEndId, List roads) { Logger.Information($"【LocPathCalcAlgorithms】开始执行 pStartId:{pStartId} pEndId:{pEndId}"); Stopwatch stopwatch = Stopwatch.StartNew(); #region dp //List results = new(); //var points = await _db.Queryable().ToListAsync(); //Dictionary isVisited = roads.Select(x => x.startpoint_id).Distinct().ToDictionary(x => x, x => false); //List pointIds = new(); //List codes = new(); //Dp dp = new(); //dynamic obj = new ExpandoObject(); //obj.isArrivedEpoint = false; //dp.DpFunc(roads, pointIds, isVisited, pStartId, pEndId, obj); //foreach (var pid in pointIds) //{ // var point = points.Find(x => x.id == pid); // if (point != null) // { // results.Add(point); // } //} //return results; #endregion #region dijkstra List results = new(); try { List? points = await _db.Queryable().ToListAsync(); WmsPointH? startObj = points.Find(x => x.id == pStartId); WmsPointH? endObj = points.Find(x => x.id == pEndId); int sIndex = points.IndexOf(startObj); int eIndex = points.IndexOf(endObj); if (eIndex < sIndex) { (eIndex, sIndex) = (sIndex, eIndex); (points[eIndex], points[sIndex]) = (points[sIndex], points[eIndex]); } string[] vexs = points.Select(p => p.id).ToArray(); EData[] edges = new EData[roads.Count]; for (int i = 0; i < edges.Length; i++) { string start = roads[i].startpoint_id; string end = roads[i].endpoint_id; int weight = roads[i].distance; edges[i] = new EData(start, end, weight); } Dijkstra pG = new(vexs, edges); int[] prev = new int[pG.mVexs.Length]; int[] dist = new int[pG.mVexs.Length]; List vertexs = new() { startObj }; pG.CalcDijkstra(sIndex, prev, dist); List pointIds = points.Select(p => p.id).ToList(); Stack result = new(); GetPoints(pointIds, prev, result, eIndex); results = new() { startObj }; if (points?.Count > 0) { //points.Where(it => result.Contains(it.id)); foreach (string i in result) { WmsPointH? point = points?.Find(x => x.id == i); if (point != null) { results.Add(point); } } } } catch (Exception ex) { Logger.Error("路径算法错误", ex); throw; } finally { stopwatch.Stop(); Logger.Information($"【LocPathCalcAlgorithms】耗时{stopwatch.ElapsedMilliseconds}"); } return results; #endregion } /// /// 获取匹配的最短路径节点 /// /// /// /// /// /// /// private void MatchPoint(List results, List roads, List shortestPathPoints, Dictionary isVisited, string pStartId, string pEndId) { List sRoads = roads.Where(x => x.startpoint_id == pStartId).ToList(); for (int j = 0; j < sRoads.Count; j++) { WmsPointH? sPoint = shortestPathPoints.Find(x => x.id == sRoads[j].endpoint_id); if (sPoint != null && isVisited.ContainsKey(sPoint.id) && !isVisited[sPoint.id] && sPoint.id != pEndId) { string code = sPoint.point_code; results.Add(sPoint); isVisited[sPoint.id] = true; MatchPoint(results, roads, shortestPathPoints, isVisited, sPoint.id, pEndId); } } } /// /// 根据终止节点获取最短路径顶点 /// /// /// /// /// private static void GetPoints(List pointIds, int[] prev, Stack result, int eIdx) { int index = eIdx; while (index != 0) { result.Push(pointIds[index]); index = prev[index]; } } private async Task Update(T1 entity, List entities) where T1 : BaseEntity, new() where T2 : BaseEntity, new() { bool isOk = false; try { await _db.Ado.BeginTranAsync(); isOk = await _db.Updateable(entity).ExecuteCommandHasChangeAsync(); if (entities?.Count > 0) { int row = await _db.Storageable(entities).ExecuteCommandAsync(); isOk = row > 0; } await _db.Ado.CommitTranAsync(); } catch (Exception) { await _db.Ado.RollbackTranAsync(); } return isOk; } /// /// 根据明细Id获取出入库明细信息 /// /// 出入库明细 /// 明细输出类 /// 出入库条码 /// 明细Id /// private async Task FetchInOutStockCodesById(string billDId) where TStockD : BaseEntity, new() where TOutput : IInOutStockDetail, new() where TStockCode : BaseEntity, IInOutStockCode, new() { Dictionary dic = await _dictionaryDataService.GetDictionaryByTypeId(WmsWareHouseConst.WMS_INSTOCK_D_BILL_STATUS_TYPEID); List data = await _db.Queryable() .Where(a => a.id == billDId) .Select(a => new TOutput { CodeDetails = SqlFunc.Subqueryable().Where(it => it.bill_d_id == a.id).ToList(), }, true) .Mapper(it => { it.line_status = it.line_status != null && dic.ContainsKey(key: it.line_status) ? dic[it.line_status]?.ToString() : ""; it.warehouse_id = _db.Queryable().Single(y => y.id == it.warehouse_id)?.whname ?? ""; }) .ToListAsync(); return data; } /// /// 二楼kiva把料架送到下升降机后生成中储仓入库任务 /// /// 料架id /// public async Task Floor2EmptyCarryCreateZZCPretask(string rackid) { try { await s_floor2CreatePretask.WaitAsync(); List wmsCarryCodes = _db.Queryable().Where(r => r.carry_id == rackid).ToList(); int move_num = 6; string[] startlocations = new string[2] { WmsWareHouseConst.ZZCSSX111011, WmsWareHouseConst.ZZCSSX111012 }; BasLocation startLocation = null; int index = 0; await _s_taskExecuteSemaphore_F1ZCCInstock.WaitAsync(); await _db.Ado.BeginTranAsync(); foreach (WmsCarryD wmsCarryD in wmsCarryCodes) { //入库取终点 //出库起点 InStockStrategyQuery inStockStrategyInput = new() { warehouse_id = WmsWareHouseConst.WAREHOUSE_ZC_ID, Size = 1 }; List endLocations = await InStockStrategy(inStockStrategyInput); if (endLocations.Count == 0) { throw new Exception("没有可用的入库库位"); } // 每6个重新获取一次起点 if (index % move_num == 0) { startLocation = await _db.Queryable().Where(r => startlocations.Contains(r.id)).OrderBy("is_lock, task_nums, location_code").FirstAsync(); } BasLocation endLocation = endLocations[0]; WmsCarryH carry = await _db.Queryable().SingleAsync(it => it.carry_code == wmsCarryD.membercarry_code); await _db.Updateable().SetColumns(r => new WmsCarryH { location_id = startLocation.id, location_code = startLocation.location_code, }).Where(r => r.id == carry.id).ExecuteCommandAsync(); bool isMatch = await IsCarryAndLocationMatchByCarryStd(carry, endLocation); if (!isMatch) { throw new Exception("库位与载具规格不匹配"); } CommonCreatePretaskInput commonCreatePretaskInput = new CommonCreatePretaskInput(); commonCreatePretaskInput.startlocation_id = startLocation.id; commonCreatePretaskInput.endlocation_id = endLocation.id; commonCreatePretaskInput.carry_id = wmsCarryD.membercarry_id; commonCreatePretaskInput.carry_code = wmsCarryD.membercarry_code; commonCreatePretaskInput.task_type = WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID; commonCreatePretaskInput.biz_type = WmsWareHouseConst.BIZTYPE_WMSEMPTYINSTOCK_ID; commonCreatePretaskInput.isExcuteMission = false; commonCreatePretaskInput.moduleConsts = ModuleConsts.MODULE_WMSEMPTYINSTOCK_ID; VisualDevModelDataCrInput visualDevInput = new VisualDevModelDataCrInput(); visualDevInput.data = new Dictionary(); visualDevInput.data.Add("bill_code", ""); visualDevInput.data.Add("biz_type", WmsWareHouseConst.BIZTYPE_WMSEMPTYINSTOCK_ID); visualDevInput.data.Add("carry_code", wmsCarryD.membercarry_code); visualDevInput.data.Add("carry_id", wmsCarryD.membercarry_id); //visualDevInput.data.Add("create_id", ""); visualDevInput.data.Add("create_time", ""); visualDevInput.data.Add("flowId", ""); visualDevInput.data.Add("id", ""); visualDevInput.data.Add("location_id", startLocation.id); visualDevInput.data.Add("modify_id", ""); visualDevInput.data.Add("modify_time", ""); //visualDevInput.data.Add("org_id", ""); visualDevInput.data.Add("status", WmsWareHouseConst.BILLSTATUS_ADD_ID); visualDevInput.data.Add("warehouse_id", WmsWareHouseConst.WAREHOUSE_ZC_ID); commonCreatePretaskInput.visualDevInput = visualDevInput; Logger.LogInformation($"【送满托到下升降区】 开始生成一楼CTU预任务 起点{startLocation.location_code} 终点{endLocation.location_code} 料箱 {wmsCarryD.membercarry_code}"); await _db.Updateable().SetColumns(it => it.is_lock == 1).Where(r => r.id == endLocations[0].id).ExecuteCommandAsync(); await _db.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1).Where(r => r.id == startLocation.id).ExecuteCommandAsync(); Entities.Dto.Outputs.Result res = await CommonCreatePretask(commonCreatePretaskInput, _db); if (res.code == JNPF.Common.Enums.HttpStatusCode.OK) { } else { throw new Exception($"【二楼kiva把料架送到下升降机后生成中储仓入库任务】 未成功生成预任务 起点{startLocation.location_code} 终点{endLocation.location_code} 料箱 {wmsCarryD.membercarry_code}"); } index++; } await _db.Ado.CommitTranAsync(); return true; } catch(Exception ex) { Logger.LogInformation($"【二楼kiva把料架送到下升降机后生成中储仓入库任务】:{ex}"); s_floor2CreatePretask.Release(); await _db.Ado.RollbackTranAsync(); return false; } finally { _s_taskExecuteSemaphore_F1ZCCInstock.Release(); s_floor2CreatePretask.Release(); } } #endregion #region 通用接口 /// /// 生成预任务接口 CTU需要传task_type /// /// /// [HttpPost, NonUnify, AllowAnonymous] public async Task CommonCreatePretask(CommonCreatePretaskInput input, ISqlSugarClient dbConn = null) { var db = _db; if (dbConn != null) db = dbConn; { await s_taskCommonCreatePretask.WaitAsync(); Logger.LogInformation($"【createPretask】 接收到请求 参数:{JsonConvert.SerializeObject(input)}"); try { WmsPointH? sPoint = null; WmsPointH? ePoint = null; if (!string.IsNullOrEmpty(input.startlocation_id)) { sPoint = await db.Queryable().FirstAsync(it => it.location_id == input.startlocation_id); } if (!string.IsNullOrEmpty(input.endlocation_id)) { ePoint = await db.Queryable().FirstAsync(it => it.location_id == input.endlocation_id); } if (sPoint == null) { throw new Exception($"库位{input.startlocation_id} 的起点点位未维护"); } if (ePoint == null) { throw new Exception($"库位{input.endlocation_id} 的终点点位未维护"); } List points = new List(); if (sPoint.area_code != ePoint.area_code) { Logger.LogInformation($"【createPretask】 起点 {sPoint.point_code} 终点 {ePoint.point_code}"); points = await PathAlgorithms(sPoint.id, ePoint.id); if (points.Count <= 2) { throw new AppFriendlyException($"sPoint {sPoint.point_code} ePoint{ePoint.point_code}该路径不存在", 500); } } else { points.Add(sPoint); points.Add(ePoint); } //根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序) WmsPretaskH preTask = null; string bill_code = await _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE); string carry_id = ""; string carry_code = ""; WmsCarryH wmsCarryH = null; if (!string.IsNullOrEmpty(input.carry_id) && !string.IsNullOrEmpty(input.carry_code)) { carry_id = input.carry_id; carry_code = input.carry_code; } // 如果指定了carry_id else if (!string.IsNullOrEmpty(input.carry_id)) { wmsCarryH = db.Queryable().Where(r => r.id == input.carry_id).First(); carry_id = wmsCarryH.id; carry_code = wmsCarryH.carry_code; } // carry_code else if (!string.IsNullOrEmpty(input.carry_code)) { wmsCarryH = db.Queryable().Where(r => r.carry_code == input.carry_code).First(); carry_id = wmsCarryH.id; carry_code = wmsCarryH.carry_code; } if (input.visualDevInput != null) { //在线开发moduleConsts VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(input.moduleConsts, true); await _runService.Create(templateEntity, input.visualDevInput); input.require_id = input.visualDevInput.data["ReturnIdentity"].ToString() ?? ""; input.require_code = input.visualDevInput.data["bill_code"].ToString() ?? ""; } List preTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it => { WmsPointH? sPoint = it.FirstOrDefault(); WmsPointH? ePoint = it.LastOrDefault(); preTask = new() { org_id = _userManager.User?.OrganizeId, startlocation_id = sPoint?.location_id!, startlocation_code = sPoint?.location_code!, endlocation_id = ePoint?.location_id!, endlocation_code = ePoint?.location_code!, start_floor = sPoint?.floor.ToString(), end_floor = ePoint?.floor.ToString(), startpoint_id = sPoint?.id!, startpoint_code = sPoint?.point_code!, endpoint_id = ePoint?.id!, endpoint_code = ePoint?.point_code!, bill_code = bill_code, status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID, biz_type = !string.IsNullOrEmpty(input.biz_type) ? input.biz_type : "", task_type = !string.IsNullOrEmpty(input.task_type) ? input.task_type : "", carry_id = carry_id, carry_code = carry_code, area_id = sPoint?.area_id!, area_code = it.Key, source_id = input.source_id, source_code = input.source_code, require_id = input.require_id, require_code = input.require_code, create_id = _userManager.UserId, create_time = DateTime.Now, priority = input.priority }; return preTask; }).ToList(); //更新页面 //赋值签收状态 Logger.LogInformation($"【CommonCreatePretask】 开始执行 GenPreTask {JsonConvert.SerializeObject(preTasks)}"); bool result = await GenPreTask(preTasks, null!, db); Logger.LogInformation($"【CommonCreatePretask】 GenPreTask 结果 {result}"); if (result) { GenPreTaskUpInput preTaskUpInput = new() { RquireId = input.require_id, CarryId = carry_id, CarryStartLocationId = points.FirstOrDefault()!.location_id!, CarryStartLocationCode = points.FirstOrDefault()!.location_code!, LocationIds = points.Select(x => x.location_id).ToList()! }; //根据载具移入Id,回更单据状态 _ = await db.Updateable().SetColumns(it => new WmsMoveInstock { status = WmsWareHouseConst.BILLSTATUS_ON_ID }).Where(it => it.id == preTaskUpInput.RquireId).ExecuteCommandAsync(); Expression> wmsCarryHChangeExp = a => new WmsCarryH { is_lock = 1 }; if (input.isChangeCarryLoc2StartLoc) { wmsCarryHChangeExp = a => new WmsCarryH { is_lock = 1, location_id = preTaskUpInput.CarryStartLocationId, location_code = preTaskUpInput.CarryStartLocationCode }; } else { wmsCarryHChangeExp = a => new WmsCarryH { is_lock = 1 }; } await GenInStockTaskHandleAfter(preTaskUpInput, wmsCarryHChangeExp, it => new BasLocation { is_lock = 1 }, db); Logger.LogInformation($"【CommonCreatePretask】 成功生成预任务:{preTasks.First().bill_code}"); JObject keyValuePairs = new JObject(); JArray array = JArray.Parse(JsonConvert.SerializeObject(preTasks.Select(r => r.id))); keyValuePairs["pretaskids"] = array; return await ToApiResult(JNPF.Common.Enums.HttpStatusCode.OK, "成功", keyValuePairs); } else { throw new AppFriendlyException("生成预任务失败(可能是因为预任务起点与终点相同)", 500); } } catch (Exception ex) { Logger.LogInformation($"【CommonCreatePretask】 {ex.Message}"); Logger.LogInformation($"【CommonCreatePretask】 {ex.StackTrace}"); //if (!db.Ado.Transaction.IsNull()) // await db.Ado.CommitTranAsync(); return await ToApiResult(JNPF.Common.Enums.HttpStatusCode.InternalServerError, ex.Message); } finally { s_taskCommonCreatePretask.Release(); if (input.isExcuteMission) { GenTaskExecute(); } } } } /// /// 可下发载具查询 /// /// /// /// [HttpPost, NonUnify, AllowAnonymous] public async Task CarryMaterialInventory(CarryMaterialInventoryInput input) { try { if (string.IsNullOrEmpty(input.biz_type)) throw new AppFriendlyException("业务类型不可为空", 500); if (string.IsNullOrEmpty(input.source_id)) throw new AppFriendlyException("来源单据id不可为空", 500); if (string.IsNullOrEmpty(input.warehouse_code)) throw new AppFriendlyException("出库仓库不可为空", 500); if (string.IsNullOrEmpty(input.material_id)) throw new AppFriendlyException("物料id不可为空", 500); if (string.IsNullOrEmpty(input.code_batch)) throw new AppFriendlyException("批号不可为空", 500); BasWarehouse basWarehouse = await _db.Queryable().Where(r => r.whcode == input.warehouse_code).FirstAsync(); // 下发数量 decimal? qty = 0; switch (input.biz_type) { case WmsWareHouseConst.BIZTYPE_WmsRawmatTransferoutstock_ID: { WmsRawmatTransferoutstockD wmsRawmatTransferoutstockD = await _db.Queryable().Where(r => r.id == input.source_id).FirstAsync(); if (wmsRawmatTransferoutstockD == null) throw new AppFriendlyException($"来源单据{input.source_id}不存在", 500); qty = wmsRawmatTransferoutstockD.qty - wmsRawmatTransferoutstockD.actual_qty; break; } case WmsWareHouseConst.BIZTYPE_WmsRawmatOutstock_ID: { WmsRawmatOutstockD wmsRawmatOutstockD = await _db.Queryable().Where(r => r.id == input.source_id).FirstAsync(); if (wmsRawmatOutstockD == null) throw new AppFriendlyException($"来源单据{input.source_id}不存在", 500); qty = wmsRawmatOutstockD.qty - wmsRawmatOutstockD.actual_outstock_qty; break; } case WmsWareHouseConst.BIZTYPE_WmsPurchaseReturn_ID: { WmsPurchaseReturnD wmsPurchaseReturnD = await _db.Queryable().Where(r => r.id == input.source_id).FirstAsync(); if (wmsPurchaseReturnD == null) throw new AppFriendlyException($"来源单据{input.source_id}不存在", 500); qty = wmsPurchaseReturnD.qty - wmsPurchaseReturnD.actual_qty; break; } } switch (basWarehouse.id) { case WmsWareHouseConst.WAREHOUSE_YCL_ID: { OutStockStrategyQuery outStockStrategyInput = new() { warehouse_id = WmsWareHouseConst.WAREHOUSE_YCL_ID, material_id = input.material_id, code_batch = input.code_batch, Size = 100, Region_id = WmsWareHouseConst.REGION_Purchase_ID, PolicyCode = WmsWareHouseConst.POLICY_YCLOUTSTOCK }; List items = await OutStockStrategy(outStockStrategyInput); var wmsCarryCodes = await _db.Queryable() .InnerJoin((a, b) => a.carry_id == b.id) .InnerJoin((a, b, c) => a.material_id == c.id) .Where((a, b, c) => items.Select(r => r.id).Contains(a.carry_id)) .Select((a, b, c) => new { carry_id = a.carry_id, carry_code = b.carry_code, material_id = c.id, material_code = c.code, material_name = c.name, material_specification = c.material_specification, barcode = a.barcode, code_batch = a.code_batch, qty = a.codeqty }) .ToListAsync(); var wmsCarryCodesOrderByQty = wmsCarryCodes.GroupBy(r => new { r.carry_id, r.material_id, r.code_batch }) .Select(g => { var list = g.ToList(); decimal sumqty = g.Sum(r => r.qty); var newg = new { carry_id = list[0].carry_id, carry_code = list[0].carry_code, material_id = list[0].material_id, material_code = list[0].material_code, material_name = list[0].material_name, material_specification = list[0].material_specification, barcode = list[0].barcode, code_batch = list[0].code_batch, qty = sumqty }; return newg; }); bool isFindSortCarry = false; var wmsCarryCodesSum = wmsCarryCodesOrderByQty.OrderBy(r => r.qty).Select(g => { decimal sumqty = g.qty; decimal? remainQty = qty - sumqty; // 首次小于0则需要分拣 if (qty > 0 && remainQty < 0 && !isFindSortCarry) isFindSortCarry = true; else isFindSortCarry = false; var newg = new { carry_id = g.carry_id, carry_code = g.carry_code, material_id = g.material_id, material_code = g.material_code, material_name = g.material_name, material_specification = g.material_specification, barcode = g.barcode, code_batch = g.code_batch, qty = sumqty, sign_qty = isFindSortCarry ? qty : // 签收数量 (qty > 0 ? sumqty : 0), // qty > 0时签收数量就是载具物料数量 isSortCarry = isFindSortCarry, // 是否为分拣载具 isSelect = isFindSortCarry || remainQty > 0, // 是否勾选 }; qty -= sumqty; return newg; }); return await ToApiResult(JNPF.Common.Enums.HttpStatusCode.OK, "成功", wmsCarryCodesSum); } default: { throw new AppFriendlyException("此仓库业务未完善", 500); } } } catch (Exception ex) { await _db.Ado.RollbackTranAsync(); return await ToApiResult(JNPF.Common.Enums.HttpStatusCode.InternalServerError, ex.Message); } } public async Task CreateCodeRules(string prefix, string custom, int watercodeLength) { try { await _s_taskExecuteSemaphore_codeRules.WaitAsync(); string watercode = ""; int? waternumber = 1; BasCoderules basCoderules = await _db.Queryable().Where(r => r.prefix == prefix && r.custom == custom).FirstAsync(); if (basCoderules == null) { watercode = "1"; BasCoderules basCoderulesIns = new BasCoderules(); basCoderulesIns.create_time = DateTime.Now; basCoderulesIns.prefix = prefix; basCoderulesIns.custom = custom; basCoderulesIns.waternumber = waternumber; await _db.Insertable(basCoderulesIns).ExecuteCommandAsync(); watercode = waternumber.ToString().PadLeft(watercodeLength, '0'); } else { waternumber = basCoderules.waternumber; waternumber++; await _db.Updateable().SetColumns(r => r.waternumber == waternumber).Where(r => r.id == basCoderules.id).ExecuteCommandAsync(); watercode = waternumber.ToString().PadLeft(watercodeLength, '0'); } return watercode; } catch(Exception ex) { throw; } finally { _s_taskExecuteSemaphore_codeRules.Release(); } } public SemaphoreSlim GetSemaphore(string type, string warehouse_id, string region_id = "") { Logger.LogInformation($"【GetSemaphore】type:{type} warehouse_id:{warehouse_id} region_id:{region_id}"); SemaphoreSlim result = null; switch (warehouse_id) { case WmsWareHouseConst.WAREHOUSE_ZC_ID: { if (type == "outstock") result = _s_taskExecuteSemaphore_F1ZCCOutstock; else if (type == "instock") result = _s_taskExecuteSemaphore_F1ZCCInstock; break; } case WmsWareHouseConst.WAREHOUSE_HCC_ID: { if (type == "outstock") result = _s_taskExecuteSemaphore_F2HCCOutstock; else if (type == "instock") result = _s_taskExecuteSemaphore_F2HCCInstock; break; } case WmsWareHouseConst.WAREHOUSE_YCL_ID: { if (type == "outstock") result = _s_taskExecuteSemaphore_YCLOutstock; else if (type == "instock") result = _s_taskExecuteSemaphore_YCLInstock; break; } case WmsWareHouseConst.WAREHOUSE_CP_ID: { if (type == "outstock") result = _s_taskExecuteSemaphore_F3CPOutstock; else if (type == "instock") result = _s_taskExecuteSemaphore_F3CPInstock; break; } case WmsWareHouseConst.WAREHOUSE_ZCC_ID: { if (type == "outstock") result = _s_taskExecuteSemaphore_F2ZCCOutstock; else if (type == "instock") result = _s_taskExecuteSemaphore_F2ZCCInstock; break; } case WmsWareHouseConst.WAREHOUSE_DMJC_ID: { if (type == "outstock") result = _s_taskExecuteSemaphore_F4DMJCOutstock; else if (type == "instock") result = _s_taskExecuteSemaphore_F4DMJCInstock; break; } case WmsWareHouseConst.WAREHOUSE_BCK_ID: { if (type == "outstock") result = _s_taskExecuteSemaphore_F4BCKOutstock; else if (type == "instock") result = _s_taskExecuteSemaphore_F4BCKInstock; break; } case WmsWareHouseConst.WAREHOUSE_F2BCQ_ID: { if (type == "outstock") result = _s_taskExecuteSemaphore_F2BCQOutstock; else if (type == "instock") result = _s_taskExecuteSemaphore_F2BCQInstock; break; } } return result; } #endregion /// /// 电梯第三次改动 生成Agv到电梯任务 /// /// public async Task AgvelevatorTimerTaskExceptionHandle() { if (s_agvElevatortaskDic.CurrentCount == 0) return; LoggerAgvElevatorTask.Information($"三楼出货检查暂存区"); await s_agvElevatortaskDic.WaitAsync(); if (db_agvElevatorTaskExceptionHandles == null) db_agvElevatorTaskExceptionHandles = _db.CopyNew(); try { var floor3outstock = await db_agvElevatorTaskExceptionHandles.Queryable().Where(p => p.key == "floor3outstock").FirstAsync(); if (floor3outstock != null && floor3outstock.value == "0") return; await db_agvElevatorTaskExceptionHandles.Ado.BeginTranAsync(); // 获取暂存区需要生成任务的库位 List agvElevatorStartLocs = await db_agvElevatorTaskExceptionHandles.Queryable() .Where(r => r.region_id == WmsWareHouseConst.REGION_CPOutstockCache_ID && r.is_use == "1" && r.is_lock == 0).ToListAsync(); if (agvElevatorStartLocs.Count > 0) { LoggerAgvElevatorTask.Information($"【AgvelevatorTimerTaskExceptionHandle】检查到需要下发到一楼任务的暂存区库位{agvElevatorStartLocs.Count}条 {string.Join(',', agvElevatorStartLocs.Select(x => x.location_code))}"); List> elevatorTaskGroup = agvElevatorStartLocs.GroupBy(r => r.region_id).ToList(); foreach (IGrouping group in elevatorTaskGroup) { List locs = group.ToList(); LoggerAgvElevatorTask.LogWarning($"即将下发{locs.Count}条任务"); for (int i = 0; i < locs.Count; i++) { // 交替选择缓存区库位 var YCLInnerTransfer = await db_agvElevatorTaskExceptionHandles.Queryable().Where(p => p.key == "floor3CurOutCacheLocation").FirstAsync(); if (YCLInnerTransfer.value == null || (YCLInnerTransfer.value != "3楼发货左" && YCLInnerTransfer.value != "3楼发货右")) throw new AppFriendlyException($"工厂配置->三楼出库暂存区当前出库分区 项配置错误!需要配置值为【3楼发货左】或【3楼发货右】", 500); BasLocation startloc = null; // 如果没切换就是当前发货区 string 切换发货区 = YCLInnerTransfer.value; if (group.Key == WmsWareHouseConst.REGION_CPOutstockCache_ID) { List locations = await db_agvElevatorTaskExceptionHandles.Queryable() .InnerJoin((a, b) => a.id == b.location_id) .Where((a, b) => b.name == 切换发货区 && a.is_use == "1" && a.is_lock == 0).OrderBy("a.location_code").ToListAsync(); startloc = locations.FirstOrDefault(); #region 如果当前侧没有可用库位 切换另一侧继续发货,但是因为不能同时发两托同侧的货到同个电梯,所以必须保证当前优先级电梯是接第一托货 // 交替出的时候可能会选不到库位,做特殊处理 if (startloc == null) { LoggerAgvElevatorTask.LogInformation($"交替到{YCLInnerTransfer.value} 进行发货的时候,没有货物可以发"); var _floor3FirstSelectElevatorTasknums = await db_agvElevatorTaskExceptionHandles.Queryable().Where(p => p.key == "floor3FirstSelectElevatorTasknums").FirstAsync(); 切换发货区 = YCLInnerTransfer.value == "3楼发货左" ? "3楼发货右" : "3楼发货左"; LoggerAgvElevatorTask.LogInformation($"再次交替到{切换发货区} 进行发货"); await db_agvElevatorTaskExceptionHandles.Updateable().SetColumns(r => r.value == 切换发货区) .Where(r => r.key == "floor3CurOutCacheLocation").ExecuteCommandAsync(); locations = await db_agvElevatorTaskExceptionHandles.Queryable() .InnerJoin((a, b) => a.id == b.location_id) .Where((a, b) => b.name == 切换发货区 && a.is_use == "1" && a.is_lock == 0).OrderBy("a.location_code").ToListAsync(); startloc = locations.FirstOrDefault(); // 如果还是选不到 if (startloc == null) { throw new Exception($"再次交替到{切换发货区} 进行发货,仍然没有货可发,属于暂存区数据异常"); } var _floor3FirstSelectElevator = await db_agvElevatorTaskExceptionHandles.Queryable().Where(p => p.key == "floor3FirstSelectElevator").FirstAsync(); // 如果当前优先级电梯是空托盘 切换发货区之后不需要切换电梯 if (_floor3FirstSelectElevatorTasknums.value == "2") { LoggerAgvElevatorTask.LogInformation($"当前优先级电梯{_floor3FirstSelectElevator.value}是空托盘 切换发货区之后不需要切换电梯"); } // 如果当前优先级电梯不是空托盘 切换发货区之后还需要切换电梯 else { LoggerAgvElevatorTask.LogInformation($"当前优先级电梯{_floor3FirstSelectElevator.value}不是空托盘 切换发货区之后还需要切换电梯"); string 切换电梯 = _floor3FirstSelectElevator.value == "Elevator3" ? "Elevator4" : "Elevator3"; LoggerAgvElevatorTask.LogInformation($"交替到{切换电梯} 进行发货"); WmsElevatorH _wmsElevatorH = await db_agvElevatorTaskExceptionHandles.Queryable().Where(r => r.elevator_code == 切换电梯).FirstAsync(); // 仅切换电梯后 如果一托任务在等第二托时要做特殊处理 if (_wmsElevatorH.task_nums == 1) { await ChangeSelectedElevator(db_agvElevatorTaskExceptionHandles, "1"); } else { // 选择另一个电梯座位首选电梯 await ChangeSelectedElevator(db_agvElevatorTaskExceptionHandles); } } } #endregion } List wmsCarryHs = await db_agvElevatorTaskExceptionHandles.Queryable().Where(r => r.location_id == startloc.id).ToListAsync(); if (wmsCarryHs.Count > 1) { LoggerAgvElevatorTask.LogWarning($"暂存区库位{startloc.location_code}上存在多个托盘{string.Join(',', wmsCarryHs.Select(x => x.carry_code))}"); continue; } if (wmsCarryHs.Count == 0) { LoggerAgvElevatorTask.LogWarning($"暂存区库位{startloc.location_code}上不存在托盘"); continue; } // 选一楼出货库位 List outLocations = await db_agvElevatorTaskExceptionHandles.Queryable() .Where(r => GetFloor1OutstockLocation().Contains(r.id) && r.is_lock == 0 && r.is_use == "0") .OrderBy("location_code" + (切换发货区 == "3楼发货左" ? " desc" : "")).ToListAsync(); if (outLocations.Count == 0) { LoggerAgvElevatorTask.LogWarning($"一楼没有可用的出货库位"); continue; } BasLocation outLocation = outLocations.FirstOrDefault(); WmsPointH outPoint = await db_agvElevatorTaskExceptionHandles.Queryable().FirstAsync(it => it.location_id == outLocation.id); WmsCarryH wmsCarryH = wmsCarryHs.FirstOrDefault(); WmsElevatorH wmsElevatorH = null; string elevatorSno = ""; // 选电梯 if (group.Key == WmsWareHouseConst.REGION_CPOutstockCache_ID) { var floor3FirstSelectElevator = await db_agvElevatorTaskExceptionHandles.Queryable().Where(p => p.key == "floor3FirstSelectElevator").FirstAsync(); var floor3FirstSelectElevatorTasknums = await db_agvElevatorTaskExceptionHandles.Queryable().Where(p => p.key == "floor3FirstSelectElevatorTasknums").FirstAsync(); wmsElevatorH = await db_agvElevatorTaskExceptionHandles.Queryable().Where(r => r.elevator_code == floor3FirstSelectElevator.value).FirstAsync(); elevatorSno = wmsElevatorH.elevator_code.Replace("Elevator", ""); // 检查有没有同时从同个暂存区分区发到同个电梯任务 //if (wmsElevatorH.task_nums + wmsElevatorH.carry_count > 0) //{ // List currentAreaLocs = await db_agvElevatorTaskExceptionHandles.Queryable().Where(r => r.name == 切换发货区).Select(r => r.location_code).ToListAsync(); // // 同个暂存分区同个电梯的托盘 // List _carrys = await db_agvElevatorTaskExceptionHandles.Queryable() // .InnerJoin((a, b) => currentAreaLocs.Contains(a.startlocation_code) && a.carry_code == b.carry_code // && a.endlocation_code == b.startlocation_code && a.endlocation_code == $"DT-3-{elevatorSno}") // .Where((a, b) => (a.status != WmsWareHouseConst.PRETASK_BILL_STATUS_CANCEL_ID && a.status != WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID) // || (b.status != WmsWareHouseConst.PRETASK_BILL_STATUS_CANCEL_ID && b.status != WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID)).Select((a, b) => a.carry_code).ToListAsync(); // if (_carrys.Count > 0) // { // LoggerAgvElevatorTask.LogInformation($"出现同时从同个暂存区分区发到同个电梯{wmsElevatorH.elevator_code}的托盘{string.Join(',', _carrys)},等待托盘任务完成"); // continue; // } //} floor3FirstSelectElevatorTasknums.value = (int.Parse(floor3FirstSelectElevatorTasknums.value) - 1).ToString(); if (floor3FirstSelectElevatorTasknums.value == "0") { await ChangeSelectedElevator(db_agvElevatorTaskExceptionHandles); } else { // 仅切换电梯后 如果一托任务在等第二托时要做特殊处理 //if (wmsElevatorH.task_nums == 1) //{ // await ChangeSelectedElevator(db_agvElevatorTaskExceptionHandles); // elevatorSno = elevatorSno == "3" ? "4" : "3"; //} //else { // 剩余可放托数 await db_agvElevatorTaskExceptionHandles.Updateable().SetColumns(r => r.value == floor3FirstSelectElevatorTasknums.value) .Where(r => r.key == "floor3FirstSelectElevatorTasknums").ExecuteCommandAsync(); } } } List wmsPointHs = await db_agvElevatorTaskExceptionHandles.Queryable().Where(it => it.status == 1).ToListAsync(); List points = new List(); // 到电梯 WmsPointH cacheOut_point = wmsPointHs.Where(r => r.location_code == startloc.location_code).First().Copy(); WmsPointH DT_C_point = wmsPointHs.Where(r => r.point_code == $"DT-C-03-0{elevatorSno}").First().Copy(); cacheOut_point.area_code = "FC"; DT_C_point.area_code = "FC"; points.Add(cacheOut_point); points.Add(DT_C_point); // 到一楼 points.Add(wmsPointHs.Where(r => r.point_code == $"DT-3-{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-1-{elevatorSno}").First()); points.Add(wmsPointHs.Where(r => r.point_code == $"DT-R-01-0{elevatorSno}").First()); points.Add(outPoint); //根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序) if (points?.Count > 0) { List preTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it => { WmsPointH? sPoint = it.FirstOrDefault(); WmsPointH? ePoint = it.LastOrDefault(); WmsPretaskH preTask = new() { org_id = WmsWareHouseConst.AdministratorOrgId, startlocation_id = sPoint?.location_id!, startlocation_code = sPoint?.location_code!, endlocation_id = ePoint?.location_id!, endlocation_code = ePoint?.location_code!, start_floor = sPoint?.floor.ToString(), end_floor = ePoint?.floor.ToString(), startpoint_id = sPoint?.id!, startpoint_code = sPoint?.point_code!, endpoint_id = ePoint?.id!, endpoint_code = ePoint?.point_code!, bill_code = _billRullService!.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(), status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID, biz_type = wmsCarryH.biz_type, task_type = WmsWareHouseConst.WMS_PRETASK_TRANSFER_TYPE_ID }; preTask.carry_id = wmsCarryH.id; preTask.carry_code = wmsCarryH.carry_code; preTask.area_id = sPoint?.area_id!; preTask.area_code = it.Key; // 载具记录 require_id todo preTask.require_id = wmsCarryH.require_id; preTask.require_code = ""; preTask.create_id = _userManager.UserId; preTask.create_time = DateTime.Now; return preTask; }).ToList(); bool isOk = await GenPreTask(preTasks, null!, db_agvElevatorTaskExceptionHandles); if (isOk) { LoggerAgvElevatorTask.LogInformation($"成功下发预任务 {string.Join(',', preTasks.Select(r => r.bill_code))}"); LoggerAgvElevatorTask.LogInformation($"成功下发载具 {string.Join(',', preTasks.Select(r => r.carry_code).Distinct())}"); //查询库位表 BasLocation location = await db_agvElevatorTaskExceptionHandles.Queryable().SingleAsync(it => it.id == startloc.id); { //载具加锁,增加库位信息 _ = await db_agvElevatorTaskExceptionHandles.Updateable().SetColumns(it => new WmsCarryH { carry_status = ((int)EnumCarryStatus.占用).ToString(), is_lock = 1, location_id = startloc.id, location_code = location.location_code }).Where(it => it.id == wmsCarryH.id).ExecuteCommandAsync(); } await db_agvElevatorTaskExceptionHandles.Updateable().SetColumns(r => r.value == (切换发货区 == "3楼发货左" ? "3楼发货右" : "3楼发货左")) .Where(r => r.key == "floor3CurOutCacheLocation").ExecuteCommandAsync(); //所有库位加锁 string?[] ids = new[] { startloc.id, preTasks[0].endlocation_id, outLocation.id }; _ = await db_agvElevatorTaskExceptionHandles.Updateable().SetColumns(it => new BasLocation { is_lock = 1 }).Where(it => ids.Contains(it.id)).ExecuteCommandAsync(); } else { throw new Exception("预任务生成失败"); } } } } await db_agvElevatorTaskExceptionHandles.Ado.CommitTranAsync(); } } catch (ObjectDisposedException ex) { LoggerAgvElevatorTask.LogWarning($"【AgvelevatorTimerTaskExceptionHandle】 数据库连接异常:{ex.Message}"); LoggerAgvElevatorTask.LogWarning($"【AgvelevatorTimerTaskExceptionHandle】 数据库连接异常:{ex.StackTrace}"); if (ex.Source == "Npgsql") db_agvElevatorTaskExceptionHandles = _db.CopyNew(); } catch (Exception ex) { Console.WriteLine("【AgvelevatorTimerTaskExceptionHandle】" + ex.Message); LoggerAgvElevatorTask.LogError($"【AgvelevatorTimerTaskExceptionHandle】 {ex.Message}"); LoggerAgvElevatorTask.LogError($"【AgvelevatorTimerTaskExceptionHandle】 {ex.StackTrace}"); // 数据库连接断开时会报错 try { await db_agvElevatorTaskExceptionHandles.Ado.RollbackTranAsync(); } catch { }; } finally { s_agvElevatortaskDic.Release(); } } async Task ChangeSelectedElevator(ISqlSugarClient db, string maxposcount = "2") { BasFactoryConfig floor3FirstSelectElevator = await db.Queryable().Where(r => r.key == "floor3FirstSelectElevator").FirstAsync(); string elevator = floor3FirstSelectElevator.value == "Elevator3" ? "Elevator4" : "Elevator3"; LoggerAgvElevatorTask.LogInformation($"重置首选电梯为{elevator}"); // 选择另一个电梯座位首选电梯 await db.Updateable().SetColumns(r => r.value == elevator) .Where(r => r.key == "floor3FirstSelectElevator").ExecuteCommandAsync(); await db.Updateable().SetColumns(r => r.value == maxposcount) .Where(r => r.key == "floor3FirstSelectElevatorTasknums").ExecuteCommandAsync(); } } }