using AutoMapper; using Microsoft.EntityFrameworkCore.Storage; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WMS.Web.Core.Dto; using WMS.Web.Core.Dto.Erp; using WMS.Web.Core.Dto.Inventory; using WMS.Web.Core.Dto.Login; using WMS.Web.Core.Dto.OutStock; using WMS.Web.Core.Dto.TakeStock; using WMS.Web.Core.Help; using WMS.Web.Core.Internal.Results; using WMS.Web.Domain.Entitys; using WMS.Web.Domain.Infrastructure; using WMS.Web.Domain.IService; using WMS.Web.Domain.IService.Public; using WMS.Web.Domain.Values; using WMS.Web.Domain.Values.Erp; namespace WMS.Web.Domain.Services { /// /// 出库服务 /// public class OutStockService : IOutStockService { private readonly IMapper _mapper; private readonly ILoginService _loginService; public readonly IBasicsRepositories _transactionRepositories; private readonly IOutStockRepositories _outStockRepositories; private readonly IOutStockTaskRepositories _outStockTaskRepositories; private readonly IOutStockTaskService _outStockTaskService; private readonly IErpService _erpService; private readonly ISerialNumberService _serialNumberService; private readonly IBoxInventoryService _boxInventoryService; private readonly IInventoryInOutDetailsService _inventoryInOutDetailsService; private readonly IBoxInventoryRepositories _boxInventoryRepositories; public OutStockService(IMapper mapper, ILoginService loginService, IBasicsRepositories transactionRepositories, IOutStockRepositories outStockRepositories, IOutStockTaskRepositories outStockTaskRepositories, IOutStockTaskService outStockTaskService, IErpService erpService, ISerialNumberService serialNumberService, IBoxInventoryService boxInventoryService, IInventoryInOutDetailsService inventoryInOutDetailsService, IBoxInventoryRepositories boxInventoryRepositories) { _mapper = mapper; _loginService = loginService; _transactionRepositories = transactionRepositories; _outStockRepositories = outStockRepositories; _outStockTaskRepositories = outStockTaskRepositories; _outStockTaskService = outStockTaskService; _erpService = erpService; _serialNumberService = serialNumberService; _boxInventoryService = boxInventoryService; _inventoryInOutDetailsService = inventoryInOutDetailsService; _boxInventoryRepositories = boxInventoryRepositories; } /// /// 出库单 /// /// /// /// public async Task Save(SaveOutStockRequest dto, LoginInDto loginInfo) { var outStockTask = await _outStockTaskRepositories.Get(dto.TaskId); if (outStockTask.Status == OutStockStatus.Already) return Result.ReFailure(ResultCodes.OutStockTaskAlready); if (outStockTask.Status == OutStockStatus.Repeal) return Result.ReFailure(ResultCodes.OutStockTaskRepeal); //上传的物料在任务单里没有找到不能出库 var ex = dto.Details.Select(s => s.MaterialId).Except(outStockTask.Details.Select(s => s.MaterialId)).ToList(); if (ex.Count() > 0 && dto.Method == 2) return Result.ReFailure(ResultCodes.OutStockMaterialError); //1.需要验证物料对应箱和序列号是否存在库存 //如果是按箱出库从库存拿取数据 if (dto.Method == 1) { var boxs = dto.Details.Select(s => s.BoxId).ToList(); dto.Details.Clear(); //获取箱子对应的所有库存 var boxInventoryList = await _boxInventoryRepositories.GetList(boxs); //过滤掉不同仓库和不同组织的 boxInventoryList = boxInventoryList.Where(w => w.StockCode == outStockTask.StockCode && w.OrgCode == outStockTask.OrgCode).ToList(); //组装dto var boxInventoryDetails = boxInventoryList.SelectMany(s => s.Details).ToList(); foreach (var b in boxInventoryDetails) { var num = boxInventoryDetails.Where(w => w.MaterialId == b.MaterialId).Sum(s => s.Qty); var taskDetail = outStockTask.Details.FirstOrDefault(f => f.MaterialId == b.MaterialId); if (taskDetail == null) return Result.ReFailure(ResultCodes.BoxOutStockTaskMaterialError); //箱子里该物料的总数量大于出库单(应出库数量-已出库数量) 不能出库 if (num > (taskDetail.AccruedQty - taskDetail.RealityQty)) return Result.ReFailure(ResultCodes.BoxNumberError); var box = boxInventoryList.FirstOrDefault(f => f.Id == b.Fid); if (box == null) return Result.ReFailure(ResultCodes.BoxNoData); var dtod = _mapper.Map(b); dtod.BoxId = box.BoxId; dtod.SubStockId = box.SubStockId; dto.Details.Add(dtod); } } var mIds = dto.Details.GroupBy(g => g.MaterialId).Select(s => s.Key).ToList(); OutStock entity = new OutStock(); foreach (var mid in mIds) { //任务单明细 var tDetail = outStockTask.Details.FirstOrDefault(f => f.MaterialId == mid); var dtoDetails = dto.Details.Where(w => w.MaterialId == mid); var qty = dtoDetails.Sum(s => s.Qty); if (tDetail == null) continue; var res = outStockTask.OutStock(mid, qty); if (!res.IsSuccess) return res; var outd = _mapper.Map(tDetail); //循环添加erp同步明细 foreach (var c in res.Data) { var tErpDetail = tDetail.ErpDetails.FirstOrDefault(f => f.SourceBillNo.Equals(c.sourceBillNo)); var oErpDetail = _mapper.Map(tErpDetail); oErpDetail.Qty = c.qty; outd.ErpDetails.Add(oErpDetail); } var boxs = dto.Details.Where(w => w.MaterialId == mid).ToList(); outd.BoxsDetails = _mapper.Map>(boxs); outd.Qty = qty; outd.SerialNumbers.AddRange(dtoDetails.SelectMany(s => s.SerialNumbers)); entity.Details.Add(outd); } entity.Create(loginInfo.UserInfo.StaffId, outStockTask); #region 组装库存dto List inventoryList = new List(); var boxIds = dto.Details.GroupBy(g => g.BoxId).Select(s => s.Key).ToList(); foreach (var boxId in boxIds) { var inventoryDetail = dto.Details.Where(w => w.BoxId == boxId).Select(s => new BoxInventoryGenerateDetailsDto() { MaterialId = s.MaterialId, Qty = s.Qty, SerialNumbers = s.SerialNumbers }).ToList(); BoxInventoryGenerateDto inventory = new BoxInventoryGenerateDto() { BoxId = boxId, InventoryInOutMethod = dto.Method, StockCode = outStockTask.StockCode, SubStockId = dto.Details.FirstOrDefault(f => f.BoxId == boxId)?.SubStockId ?? 0,// outStockTask.Details.First().SubStockId, Details = inventoryDetail }; inventoryList.Add(inventory); } List generateList = dto.Details.Select(s => new InventoryInOutDetailsGenerateDto() { BoxId = s.BoxId, InventoryInOutType = 2, OrderBillNo = outStockTask.BillNo, Qty = s.Qty, StockCode = outStockTask.StockCode, MaterialId = s.MaterialId, SubStockId = s.SubStockId, OrgCode = outStockTask.OrgCode, OrderType = 1, }).ToList(); #endregion IDbContextTransaction _transaction = _transactionRepositories.GetTransaction(); Result res_Rollback = Result.ReSuccess(); bool isSuccess = true; //修改库存 //var res_Inventory = await _boxInventoryService.HandlBoxInventory(inventoryList, false); //if (!res_Inventory.IsSuccess) res_Rollback = res_Inventory; if (res_Rollback.IsSuccess) { entity = await _outStockRepositories.Add(entity, false); if (entity == null) res_Rollback = Result.ReFailure(ResultCodes.DateWriteError); } if (res_Rollback.IsSuccess) { outStockTask = await _outStockTaskRepositories.Edit(outStockTask, false); if (outStockTask == null) res_Rollback = Result.ReFailure(ResultCodes.DateWriteError); } if (res_Rollback.IsSuccess) { var res_change = await _serialNumberService.OutStock(entity, loginInfo, false); if (!res_change.IsSuccess) res_Rollback = res_change; } //if (res_Rollback.IsSuccess) //{ // res_Inventory = await _inventoryInOutDetailsService.GenerateInOrOutDetails(generateList, false); // if (!res_Inventory.IsSuccess) res_Rollback = res_Inventory; //} //提交事务 isSuccess = _transactionRepositories.CommitTransaction(res_Rollback.IsSuccess ? false : true, _transaction); if (!res_Rollback.IsSuccess) return res_Rollback; if (!isSuccess) return Result.ReFailure(ResultCodes.DateWriteError); return Result.ReSuccess(); } /// /// 同步金蝶 /// /// /// public async Task Sync(OperateRequest dto, LoginInDto loginInfo) { var list = await _outStockRepositories.GetEntityList(dto.Ids); foreach (var entity in list) { if (entity.SuccessSync) continue; List failList = entity.SuccessSyncFail.Clone();//同步失败的来源单号 //找到单据里需要同步的单据 var sourcNos = entity.Details.SelectMany(s => s.ErpDetails).GroupBy(s => s.SourceBillNo).Select(s => s.Key); foreach (var s in failList) { var erp_details = entity.Details.SelectMany(s => s.ErpDetails).Select(s => s.Erp_DetailId).ToList(); var erpDto = new ErpPushDto() { FormId = FormIdParam.SAL_DELIVERYNOTICE.ToString(), Numbers = new List() { s }, Type = "", DetailsId = string.Join(",", erp_details) }; //下推金蝶 var res = await this.Push(erpDto); if (res.IsSuccess) entity.SyncSuccess(s, loginInfo.UserInfo.StaffId); else entity.SyncFail(res.Message, loginInfo.UserInfo.StaffId); } entity.SuccessSync = entity.SuccessSyncFail.Count() > 0 ? false : true; //最好一条一条执行,否则执行失败 但是金蝶那边又同步成功 就会造成数据比价乱 var isSuccess = await _outStockRepositories.Edit(entity, true); if (entity == null) return Result.ReFailure(ResultCodes.DateWriteError); } return Result.ReSuccess(); } /// /// 下推 /// /// /// private async Task Push(ErpPushDto dto) { var res = await _erpService.Push(dto); return Result.ReSuccess(); } } }