using System.Linq; using System.Linq.Expressions; using JNPF.Common.Core.Manager; using JNPF.Common.Dtos.VisualDev; using JNPF.Common.Extension; using JNPF.Common.Security; using JNPF.EventBus; using JNPF.FriendlyException; using JNPF.Systems.Interfaces.System; using JNPF.VisualDev; using JNPF.VisualDev.Entitys; using JNPF.VisualDev.Interfaces; using Mapster; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; using SqlSugar; using Tnb.BasicData.Entities; using Tnb.WarehouseMgr.Entities; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto; using Tnb.WarehouseMgr.Entities.Dto.Outputs; using Tnb.WarehouseMgr.Entities.Dto.Queries; using Tnb.WarehouseMgr.Entities.Enums; using Tnb.WarehouseMgr.Interfaces; namespace Tnb.WarehouseMgr { /// /// 盘点任务 /// [OverideVisualDev(ModuleConsts.MODULE_WMSCHECKTASK_ID)] public class WmsCheckTaskService : BaseWareHouseService { private readonly ISqlSugarClient _db; private readonly IWareHouseService _warehouseService; private readonly IUserManager _userManager; private readonly IVisualDevService _visualDevService; private readonly IRunService _runService; private readonly IBillRullService _billRullService; private static Dictionary _carryMap = new(); public WmsCheckTaskService( ISqlSugarRepository repository, IWareHouseService wareHouseService, IVisualDevService visualDevService, IRunService runService, IBillRullService billRullService, IUserManager userManager, IEventPublisher eventPublisher ) { _db = repository.AsSugarClient(); _warehouseService = wareHouseService; _visualDevService = visualDevService; _runService = runService; _billRullService = billRullService; _userManager = userManager; OverideFuncs.CreateAsync = Create; } private async Task Create(VisualDevModelDataCrInput input) { int row = 1; if (input == null) { throw new ArgumentNullException(nameof(input)); } try { await _db.Ado.BeginTranAsync(); if (input.data?.Count > 0) { string? checkType = input.data[nameof(WmsCheckstockH.checkstock_type)]?.ToString(); if (!checkType.IsNullOrEmpty()) { List billStatus = new() { WmsWareHouseConst.TASK_BILL_STATUS_CANCEL_ID, WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID, }; Expression> filter = Expressionable.Create() .And((a, b) => b.wh_id == input.data[nameof(WmsCheckstockH.warehouse_id)].ToString()) .And((a, b) => b.is_type == ((int)EnumLocationType.存储库位).ToString()) .And((a, b) => !billStatus.Contains(a.status)) .ToExpression(); List>> queryTasks = new() { Task.Run(() => FetchDisTasks((a, b) => a.startlocation_id == b.id, filter)), Task.Run(() => FetchDisTasks((a, b) => a.endlocation_id == b.id, filter)) }; List[] disTasks = await Task.WhenAll(queryTasks); if (disTasks?.Length > 0 && disTasks.Any(list => list?.Count > 0)) { throw new AppFriendlyException("该仓库还有未完成的任务,不允许盘点!", 500); } VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(ModuleConsts.MODULE_WMSCHECKTASK_ID, true); await _runService.Create(templateEntity, input); List carryCodes = new(); List details = new(); switch (checkType!.ToEnum()) { case EnumCheckType.全库盘点: carryCodes = await _db.Queryable().InnerJoin((a, b) => a.id == b.location_id) .Where(a => a.wh_id == input.data[nameof(WmsCheckstockH.warehouse_id)].ToString() && a.is_type == ((int)EnumLocationType.存储库位).ToString()) .Select() .ToListAsync(); carryCodes ??= Enumerable.Empty().ToList(); List? checkStockDs = carryCodes.Adapt>(); var prQtyDic = checkStockDs.GroupBy(g => new { g.carry_id, g.material_id, g.code_batch }).ToDictionary(x => x.Key, x => x.Sum(d => d.codeqty)); foreach ((object k, decimal v) in prQtyDic) { WmsCheckstockD? checkstockD = checkStockDs?.Find(x => string.Equals(k, $"{x.carry_id}{x.material_id}{x.code_batch}")); if (checkstockD != null) { checkstockD.id = SnowflakeIdHelper.NextId(); checkstockD.create_id = _userManager.UserId; checkstockD.create_time = DateTime.Now; checkstockD.pr_qty = v; details.Add(checkstockD); } } _ = await _db.Insertable(details).ExecuteCommandAsync(); break; case EnumCheckType.物料盘点: break; case EnumCheckType.批次盘点: break; } //生成预任务信息 if (details.Count > 0 && carryCodes.Count > 0) { // 判断当前仓库是否有盘点签收配置 var wcsConf = await _db.Queryable().Where(it => it.warehouse_id == input.data[nameof(WmsCheckstockH.warehouse_id)].ToString() && it.enabled == 1) .FirstAsync(); BasLocation[] endLocs = Array.Empty(); int randomIndex = 0; if (wcsConf != null) { if (wcsConf.location_id == null) { throw new AppFriendlyException("盘点签收配置库位为空,请查看配置!", 500); } JArray? jsonArr = null; jsonArr = JArray.Parse(wcsConf.location_id); string?[] locArr = jsonArr.Select(x => x.ToObject()).ToArray(); if (locArr != null) { endLocs = await _db.Queryable().Where(it => it.wh_id == input.data[nameof(WmsCheckstockH.warehouse_id)].ToString() && locArr.Contains(it.id)).ToArrayAsync(); randomIndex = new Random().Next(0, endLocs.GetUpperBound(0)); } else { throw new AppFriendlyException("盘点签收配置有误,请查看配置!", 500); } } else { string[] locTypes = new[] { ((int)EnumLocationType.出库库位).ToString(), ((int)EnumLocationType.出入库位).ToString() }; endLocs = await _db.Queryable().Where(it => it.wh_id == input.data[nameof(WmsCheckstockH.warehouse_id)].ToString() && locTypes.Contains(it.is_type)).ToArrayAsync(); randomIndex = new Random().Next(0, endLocs.GetUpperBound(0)); } List carrys = await _db.Queryable().Where(it => carryCodes.Select(x => x.carry_id).Distinct().Contains(it.id)).ToListAsync(); List curDetails = details.DistinctBy(x => x.carry_id).ToList(); List curCarryCodes = carryCodes.FindAll(x => curDetails.Select(d => d.carry_id).Contains(x.carry_id)); if (curCarryCodes.Count > 0) { List preTasks = new(); List locIds = new(); foreach (WmsCarryH item in carrys) { WmsPointH? sPoint = await _db.Queryable().FirstAsync(it => it.location_id == item.location_id); WmsPointH? ePoint = await _db.Queryable().FirstAsync(it => it.location_id == endLocs[randomIndex].id); if (sPoint != null && ePoint != null) { List points = await _warehouseService.PathAlgorithms(sPoint.id, ePoint.id); if (points.Count <= 2) { throw new AppFriendlyException("该路径不存在", 500); } if (points?.Count > 0) { locIds.AddRange(points.Select(x => x.location_id).ToList()!); List curPreTasks = 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 = _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(), bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(), status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID, biz_type = WmsWareHouseConst.BIZTYPE_WMSCHECKOUTSTOCK_ID, task_type = WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID, carry_id = item.id, carry_code = item.carry_code!, area_id = sPoint?.area_id!, area_code = it.Key, require_id = input.data["ReturnIdentity"].ToString(), require_code = input.data[nameof(WmsCheckstockH.checkstock_code)]?.ToString(), create_id = _userManager.UserId, create_time = DateTime.Now }; return preTask; }).ToList(); if (endLocs[randomIndex].is_sign == 0) { curPreTasks[^1].is_sign = 0; } preTasks.AddRange(curPreTasks); } } } List pretaskCodes = new(); foreach (WmsPretaskH pt in preTasks) { List partCodes = carryCodes.FindAll(x => x.carry_id == pt.carry_id).Distinct().ToList(); List curPreTaskCodes = partCodes.Adapt>(); curPreTaskCodes.ForEach(x => { x.id = SnowflakeIdHelper.NextId(); x.bill_id = pt.id; x.create_time = DateTime.Now; }); pretaskCodes.AddRange(curPreTaskCodes); } bool isOk = await _warehouseService.GenPreTask(preTasks, pretaskCodes); if (isOk) { _ = await _db.Updateable().SetColumns(it => it.status == ((int)EnumCheckStatus.盘点中).ToString()).ExecuteCommandAsync(); GenPreTaskUpInput genPreTaskAfterUpInput = new() { CarryIds = preTasks.Select(x => x.carry_id).ToList(), LocationIds = new HashSet(locIds).ToList() }; await _warehouseService.GenInStockTaskHandleAfter(genPreTaskAfterUpInput, it => new WmsCarryH { is_lock = 1 }, it => new BasLocation { is_lock = 1 }); } } } } } await _db.Ado.CommitTranAsync(); } catch (Exception) { row = 0; await _db.Ado.RollbackTranAsync(); throw; } finally { await InvokeGenPretaskExcute(); } return Task.FromResult(row); } private Task> FetchDisTasks(Expression> joinExp, Expression> whereExp) { return _db.CopyNew().Queryable().InnerJoin(joinExp).Where(whereExp).Select().ToListAsync(); } /// /// 根据盘点类型获取任务明细 /// /// ///
{ ///
warehouse_id:仓库ID ///
CheckType:盘点类型 0 全库盘点、1 物料盘点 2 区域盘点 ///
material_id:物料ID ///
regionIds: 区域ID列表 ///
} /// /// [HttpGet] public async Task GetTaskDetailByCheckType([FromQuery] CheckDetailQuery input) { if (_carryMap.Count == 0) { _carryMap = await _db.Queryable().ToDictionaryAsync(x => x.id, x => x.carry_code); } var filterExpable = Expressionable.Create() .And((a, b, c) => a.wh_id == input.warehouse_id) .And((a, b, c) => a.is_type == ((int)EnumLocationType.存储库位).ToString()) .And((a, b, c) => c.is_lock == 0); filterExpable = input.CheckType switch { EnumCheckType.物料盘点 => filterExpable.AndIF(!string.IsNullOrEmpty(input.material_id), (a, b, c) => b.material_id == input.material_id), EnumCheckType.批次盘点 => filterExpable.AndIF(input.regionIds?.Count > 0, (a, b, c) => input.regionIds.Contains(a.region_id)), _ => filterExpable, }; var carryCodes = await _db.Queryable().InnerJoin((a, b) => a.id == b.location_id) .InnerJoin((a, b, c) => b.carry_id == c.id) .Where(filterExpable.ToExpression()) .Select() .ToListAsync(); List outputs = carryCodes.GroupBy(g => new { g.material_code, g.code_batch, g.location_code, g.carry_id }).Select(x => new WmsCheckstockD { material_code = x.Key.material_code, code_batch = x.Key.code_batch, carry_id = x.Key.carry_id, carry_code = _carryMap[x.Key.carry_id]?.ToString() ?? string.Empty, location_id = x.FirstOrDefault(y => y.location_code == x.Key.location_code)?.location_id ?? string.Empty, location_code = x.Key.location_code, pr_qty = x.Sum(d => d.codeqty), closing_status = WmsWareHouseConst.CLOSINGSTATUS_WJS_ID, qty = 0, }) .ToList(); return outputs; } } }