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.Attributes; 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)] [ServiceModule(BizTypeId)] public class WmsOutStockService : BaseWareHouseService, IWmsOutStockService { private const string BizTypeId = "26191522660645"; 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); } 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; } /// /// 测试 /// /// [HttpGet] public async Task Testxx() { var carryCodePropNames = typeof(WmsCarryCode).GetProperties().Select(p => p.Name); var outStockCodePropNames = typeof(WmsOutstockCode).GetProperties().Select(p => p.Name); var intersects = carryCodePropNames.Intersect(outStockCodePropNames).ToList(); var excepts = carryCodePropNames.Except(outStockCodePropNames).ToList(); var excepts2 = outStockCodePropNames.Except(carryCodePropNames).ToList(); //bill_id,bill_line,bill_d_id,bill_d_line,code_qty var str = ""; } public override async Task ModifyAsync(WareHouseUpInput input) { if (input == null) throw new ArgumentNullException("input"); try { var carryId = input.carryIds[^input.carryIds.Count]; var carry = await _db.Queryable().SingleAsync(it => it.id == carryId); if (carry != null) { var outStatus = carry.out_status.ToEnum(); if (outStatus == EnumOutStatus.全部出) { //当前载具对应的所有条码插入 var carryCodes = await _db.Queryable().Where(it => it.carry_id == carryId).ToListAsync(); var outStockCodes = carryCodes.Adapt>(); var otds = await _db.Queryable().Where(it => it.bill_id == input.requireId).ToListAsync(); outStockCodes.ForEach(x => { var billDId = otds?.Find(xx => xx.material_id == x.material_id && xx.code_batch == x.code_batch)?.id; if (billDId.IsNullOrEmpty()) { billDId = otds?.Find(xx => xx.material_id == x.material_id)?.id; } x.id = SnowflakeIdHelper.NextId(); x.bill_id = input.requireId; x.bill_d_id = billDId; x.org_id = _userManager.User.OrganizeId; x.create_id = _userManager.UserId; x.create_time = DateTime.Now; }); await _db.Insertable(outStockCodes).ExecuteCommandAsync(); var detailIds = outStockCodes.Select(x => x.bill_d_id).ToList(); var curOutstockDetails = otds.FindAll(x => detailIds.Contains(x.id)); var dic = outStockCodes.GroupBy(g => g.bill_d_id).ToDictionary(x => x.Key, x => x.Select(x => x.codeqty).ToList()); foreach (var osd in curOutstockDetails) { if (dic.ContainsKey(osd.id)) { osd.qty += dic[osd.id].Sum(d => d); if (osd.qty >= osd.pr_qty) { osd.line_status = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID; } } } await _db.Updateable(curOutstockDetails).ExecuteCommandAsync(); if (otds.All(x => x.line_status == WmsWareHouseConst.BILLSTATUS_COMPLETE_ID)) { await _db.Updateable().SetColumns(it => new WmsOutstockH { status = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID }).Where(it => it.id == input.requireId).ExecuteCommandAsync(); //如果是自动单据,需要回更上层系统 } } else if (outStatus == EnumOutStatus.分拣出) { } } } catch (Exception ex) { throw; } } } }