using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using JNPF.Common.Core.Manager; using JNPF.Common.Dtos.VisualDev; using JNPF.Common.Extension; using JNPF.Common.Security; 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 SqlSugar; using Tnb.BasicData.Entities; using Tnb.WarehouseMgr.Entities; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto; using Tnb.WarehouseMgr.Entities.Enums; using Tnb.WarehouseMgr.Interfaces; namespace Tnb.WarehouseMgr { /// /// 出库申请业务类 /// [OverideVisualDev(ModuleConsts.MODULE_WMSOUTSTOCK_ID)] public class WmsOutStockService : BaseWareHouseService, IWmsOutStockService { private readonly ISqlSugarClient _db; private readonly IDictionaryDataService _dictionaryDataService; private readonly IRunService _runService; private readonly IVisualDevService _visualDevService; private readonly IWareHouseService _wareHouseService; private readonly IUserManager _userManager; private readonly IBillRullService _billRullService; public WmsOutStockService( ISqlSugarRepository repository, IDictionaryDataService dictionaryDataService, IRunService runService, IVisualDevService visualDevService, IWareHouseService wareHouseService, IUserManager userManager, IBillRullService billRullService) { _db = repository.AsSugarClient(); _dictionaryDataService = dictionaryDataService; _runService = runService; _visualDevService = visualDevService; _wareHouseService = wareHouseService; _userManager = userManager; _billRullService = billRullService; OverideFuncs.CreateAsync = OutStockApplyFor; } private async Task OutStockApplyFor(VisualDevModelDataCrInput input) { try { await _db.Ado.BeginTranAsync(); VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(ModuleConsts.MODULE_WMSOUTSTOCK_ID, true); await _runService.Create(templateEntity, input); //判断目标库位是否自动签收 var loc = await _db.Queryable().SingleAsync(it => it.id == input.data[nameof(WmsPointH.location_id)].ToString()); var carryIds = new List(); //tablefield120 出库物料明细 if (input.data.ContainsKey("tablefield120") && input.data["tablefield120"].IsNotEmptyOrNull()) { var outStockDList = input.data["tablefield120"].ToObject>(); if (outStockDList?.Count > 0) { List carryMats = new(); List carryCodes = new(); foreach (var os in outStockDList) { var carryCodesPart = await _db.Queryable().InnerJoin((a, b) => a.id == b.carry_id).InnerJoin((a, b, c) => a.location_id == c.id) .Where((a, b, c) => b.material_id == os.material_id && a.is_lock == 0 && !string.IsNullOrEmpty(a.location_id) && a.status == (int)EnumCarryStatus.占用 && c.is_type == ((int)EnumLocationType.存储库位).ToString()) .WhereIF(!string.IsNullOrEmpty(os.code_batch), (a, b) => b.code_batch == os.code_batch) .Select() .ToListAsync(); if (carryCodesPart?.Count > 0) { carryCodes.AddRange(carryCodesPart); var codeQty = carryCodes.Sum(x => x.codeqty); if (codeQty < os.pr_qty) { throw new AppFriendlyException($"需要出库[{os.pr_qty}],实际库存{codeQty},数量不足", 500); } List curCarryCodes = new(); for (int i = 0; i < carryCodesPart.Count; i++) { if (os.pr_qty > carryCodesPart[i].codeqty) { os.pr_qty -= carryCodesPart[i].codeqty; curCarryCodes.Add(carryCodesPart[i]); } else if (os.pr_qty <= carryCodesPart[i].codeqty) { carryCodesPart[i].codeqty = os.pr_qty; curCarryCodes.Add(carryCodesPart[i]); break; } } var partCarryMats = curCarryCodes.Adapt>(); for (int i = 0; i < partCarryMats.Count; i++) { partCarryMats[i].need_qty = carryCodesPart[i].codeqty; } carryMats.AddRange(partCarryMats); } } if (carryMats.Count > 0) { carryMats.ForEach(x => x.id = SnowflakeIdHelper.NextId()); carryMats = carryMats.OrderBy(o => o.create_time).GroupBy(g => new { g.carry_id, g.material_id, g.code_batch }) .Select(x => { WmsCarryMat? carryMat = x.FirstOrDefault()!; carryMat.need_qty = x.Sum(d => d.need_qty); return carryMat; }) .ToList(); await _db.Insertable(carryMats).ExecuteCommandAsync(); var dic = carryMats.DistinctBy(x => x.carry_id).ToDictionary(x => x.carry_id, x => x.need_qty); var allOutIds = new List(); var sortingOutIds = new List(); foreach (var pair in dic) { var codes = carryCodes.FindAll(x => x.carry_id == pair.Key); if (codes?.Count > 0) { if (pair.Value == codes.Sum(d => d.codeqty)) { allOutIds.Add(pair.Key); } else { sortingOutIds.Add(pair.Key); } } } carryIds = allOutIds.Concat(sortingOutIds).ToList(); await _db.Updateable().SetColumns(it => new WmsCarryH { out_status = ((int)EnumOutStatus.全部出).ToString() }).Where(it => allOutIds.Contains(it.id)).ExecuteCommandAsync(); await _db.Updateable().SetColumns(it => new WmsCarryH { out_status = ((int)EnumOutStatus.分拣出).ToString() }).Where(it => sortingOutIds.Contains(it.id)).ExecuteCommandAsync(); } var carrys = await _db.Queryable().Where(it => carryIds.Contains(it.id)).ToListAsync(); if (carrys?.Count > 0) { List preTasks = new(); List locIds = new(); foreach (var carry in carrys) { WmsPointH sPoint = null!; WmsPointH ePoint = null!; if (input.data.ContainsKey(nameof(WmsPointH.location_id))) { sPoint = await _db.Queryable().FirstAsync(it => it.location_id == carry.location_id); } if (input.data.ContainsKey(nameof(WmsPointH.location_id)) && input.data[nameof(WmsPointH.location_id)].IsNotEmptyOrNull()) { ePoint = await _db.Queryable().FirstAsync(it => it.location_id == input.data[nameof(WmsPointH.location_id)].ToString()); } if (sPoint != null && ePoint != null) { var points = await _wareHouseService.PathAlgorithms(sPoint.id, ePoint.id); locIds.AddRange(points.Select(x => x.location_id).ToList()!); //根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序) if (points?.Count > 0) { if (points.Count <= 2) throw new AppFriendlyException("该路径不存在", 500); var curPreTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it => { var sPoint = it.FirstOrDefault(); var ePoint = it.LastOrDefault(); WmsPretaskH preTask = new(); preTask.org_id = _userManager.User.OrganizeId; preTask.startlocation_id = sPoint?.location_id!; preTask.startlocation_code = sPoint?.location_code!; preTask.endlocation_id = ePoint?.location_id!; preTask.endlocation_code = ePoint?.location_code!; preTask.start_floor = sPoint?.floor.ToString(); preTask.end_floor = ePoint?.floor.ToString(); preTask.bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(); preTask.status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID; preTask.biz_type = WmsWareHouseConst.BIZTYPE_WMSOUTSTOCK_ID; preTask.task_type = WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID; preTask.carry_id = carry.id; preTask.carry_code = carry.carry_code; preTask.area_id = sPoint?.area_id!; preTask.area_code = it.Key; preTask.require_id = input.data["ReturnIdentity"].ToString(); preTask.require_code = input.data[nameof(preTask.bill_code)]?.ToString()!; preTask.create_id = _userManager.UserId; preTask.create_time = DateTime.Now; return preTask; }).ToList(); if (loc.is_sign == 0) { curPreTasks[^1].is_sign = 0; // 修改最后一个元素的是否签收值 } preTasks.AddRange(curPreTasks); } } } var isOk = await _wareHouseService.GenPreTask(preTasks, null); GenPreTaskUpInput genPreTaskAfterUpInput = new(); genPreTaskAfterUpInput.CarryIds = preTasks.Select(x => x.carry_id).ToList(); genPreTaskAfterUpInput.LocationIds = new HashSet(locIds).ToList(); await _wareHouseService.GenInStockTaskHandleAfter(genPreTaskAfterUpInput, it => new WmsCarryH { is_lock = 1 }, it => new BasLocation { is_lock = 1 }); } } else throw new AppFriendlyException($"请输入物料明细", 500); } await _db.Ado.CommitTranAsync(); } catch (Exception) { await _db.Ado.RollbackTranAsync(); throw; } return Task.FromResult(true); } /// /// 根据出库申请单ID获取申请单明细信息 /// /// /// [HttpGet] public async Task GetInStockDetailsListById([FromRoute] string billId) { var dic = await _dictionaryDataService.GetDictionaryByTypeId(WmsWareHouseConst.WMS_INSTOCK_D_BILL_STATUS_TYPEID); var items = await _db.Queryable().Where(it => it.bill_id == billId).ToListAsync(); _db.ThenMapper(items, it => it.line_status = dic.ContainsKey(it.line_status) ? dic[it.line_status]?.ToString()! : ""); return items; } } }