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.ChangeBoxRecord; using WMS.Web.Core.Dto.Erp; using WMS.Web.Core.Dto.InStock; using WMS.Web.Core.Dto.InStockTask; using WMS.Web.Core.Dto.Inventory; using WMS.Web.Core.Dto.Login; 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.Mappers; using WMS.Web.Domain.Values; namespace WMS.Web.Domain.Services { /// /// 入库单服务 /// public class InStockService : IInStockService { private readonly IMapper _mapper; private readonly IErpService _erpService; private readonly ILoginService _loginService; private readonly ISerialNumberService _serialNumberService; private readonly IChangeMoveBoxService _changeMoveBoxService; private readonly IBoxRepositories _boxRepositories; private readonly IBoxInventoryService _boxInventoryService; private readonly IBasicsRepositories _basicsRepositories; private readonly IInStockRepositories _inStockRepositories; private readonly IInStockTaskRepositories _inStockTaskRepositories; private readonly IErpBasicDataExtendService _erpBasicDataExtendService; public InStockService(IMapper mapper, IErpService erpService, IBoxInventoryService boxInventoryService, ISerialNumberService serialNumberService, ILoginService loginService, IBoxRepositories boxRepositories, IBasicsRepositories basicsRepositories, IErpBasicDataExtendService erpBasicDataExtendService, IChangeMoveBoxService changeMoveBoxService, IInStockRepositories inStockRepositories, IInStockTaskRepositories inStockTaskRepositories) { _mapper = mapper; _erpService = erpService; _loginService = loginService; _boxInventoryService = boxInventoryService; _serialNumberService = serialNumberService; _boxRepositories = boxRepositories; _changeMoveBoxService = changeMoveBoxService; _basicsRepositories = basicsRepositories; _inStockRepositories = inStockRepositories; _inStockTaskRepositories = inStockTaskRepositories; _erpBasicDataExtendService = erpBasicDataExtendService; } /// /// 同步-金蝶 /// /// /// public async Task Sync(OperateRequest dto) { return Result.ReSuccess(); } /// /// 收货 /// /// /// /// public async Task Receive(UpdateInStockTaskRequest dto, LoginInDto loginInfo) { IDbContextTransaction _transaction = _basicsRepositories.GetTransaction(); bool isRollback = false; bool isTransaction = false; var result = await this.Update(dto, loginInfo.UserInfo.StaffId, true, isTransaction); if (!result.IsSuccess) isRollback = true; //提交事务 var isSuccess = _basicsRepositories.CommitTransaction(isRollback, _transaction); if (!isSuccess) return Result.ReFailure(ResultCodes.DateWriteError); return Result.ReSuccess(); } /// /// 上架-采购订单 /// /// /// /// public async Task Shelf(PurchaseShelfRequest instock, LoginInDto loginInfo) { IDbContextTransaction _transaction = _basicsRepositories.GetTransaction(); bool isRollback = false; bool isTransaction = false; //1.添加入库单:(同步金蝶在save方法里面进行) var save_result = await this.ShelfSave(instock, InstockType.Purchase, loginInfo, isTransaction); if (!save_result.IsSuccess) isRollback = true; { //2.修改入库任务单 var ids = instock.Details.GroupBy(x => x.TaskId).Select(x => x.Key).ToList(); var result = await this.UpdateRange(ids, loginInfo.UserInfo.StaffId, false, isTransaction); if (!result.IsSuccess) isRollback = true; } //提交事务 var isSuccess = _basicsRepositories.CommitTransaction(isRollback, _transaction); if (!isSuccess) return Result.ReFailure(ResultCodes.DateWriteError); return Result.ReSuccess(); } /// /// 非采购单上架 /// /// /// /// public async Task ShelfNoPurchase(NoPurchaseShelfRequest dto, LoginInDto loginInDto) { IDbContextTransaction _transaction = _basicsRepositories.GetTransaction(); bool isRollback = false; bool isTransaction = false; //保存非采购上架的数据 var shelfSave_result = await this.ShelfNoPurchaseSave(dto, loginInDto, isTransaction); if (!shelfSave_result.IsSuccess) isRollback = true; //提交事务 var isSuccess = _basicsRepositories.CommitTransaction(isRollback, _transaction); if (!isSuccess) return Result.ReFailure(ResultCodes.DateWriteError); return Result.ReSuccess(); } /// /// 获取任务单:根据箱号信息 /// /// /// public async Task> GetInfoByBox(string boxBillNo) { //1.获取物料集合 var materials_result = await _erpService.BillQueryForMaterial(); var materials = new List(); if (materials_result.IsSuccess) materials = materials_result.Data.ToList(); //1.先判断:箱号已经绑定了入库任务单中;备注:业务说法就是箱是否收货了 var tast = await _inStockTaskRepositories.GetBy(boxBillNo); if (tast == null) return Result.ReFailure(ResultCodes.Box_NoBind_Task_Data); //2.找到箱对应的物料信息 var box = await _boxRepositories.GetByNo(boxBillNo); if (box == null) return Result.ReFailure(ResultCodes.BoxNoData); //2.1判断箱是否上架过了 var isExist = await _inStockRepositories.IsExistBy(box.Id); if(isExist) return Result.ReFailure(ResultCodes.BoxIsTrueShelf); //3.组装返回数据 var result = _mapper.Map(tast); result.BoxId = box.Id; foreach (var item in tast.Details) { //3.1判断当前物料是否相同 var current_box_det = box.Details.Where(x => x.MaterialId == item.MaterialId).FirstOrDefault(); if (current_box_det==null) continue; //3.2映射返回明细对象 var task_detail = _mapper.Map(item); task_detail.BoxMaterialQty = current_box_det.Qty; task_detail.MaterialName = _erpBasicDataExtendService.GetMaterialName(materials, task_detail.MaterialId); task_detail.MaterialNumber = _erpBasicDataExtendService.GetMaterialNumber(materials, task_detail.MaterialId); task_detail.Specifications = _erpBasicDataExtendService.GetMaterialSpecifications(materials, task_detail.MaterialId); result.Details.Add(task_detail); } return Result.ReSuccess(result); } /// /// 采购上架-保存 /// /// /// /// /// private async Task ShelfSave(PurchaseShelfRequest dto, InstockType type, LoginInDto loginInfo, bool isTransaction = true) { var entity = new InStock(); entity.Type = type; entity.Method = InventoryInOutMethod.Box; entity.Details = _mapper.Map>(dto.Details); entity.Create(loginInfo.UserInfo.StaffId); //需要填写序列号 //需要修改库存 //需要同步金蝶 entity = await _inStockRepositories.Add(entity, isTransaction); if (entity == null) return Result.ReFailure(ResultCodes.DateWriteError); //同步金蝶后,反写任务单的已交数量 var taskId= dto.Details.GroupBy(x => x.TaskId).Select(x=>x.Key).FirstOrDefault(); var task= await _inStockTaskRepositories.Get(taskId); if (task != null) { task.Details.ForEach(x => { var current_dto_det = dto.Details.Where(x => x.MaterialId == x.MaterialId).FirstOrDefault(); if (current_dto_det != null) x.DeliveredQty = current_dto_det.Qty; }); task=await _inStockTaskRepositories.Update(task,isTransaction); if(task==null) return Result.ReFailure(ResultCodes.DateWriteError); } //保存成功后:序列号跟踪流程添加 var serialNumber_result = await _serialNumberService.InStock(entity, loginInfo, isTransaction); if (!serialNumber_result.IsSuccess) return serialNumber_result; //箱库存变动 var dtoDatas = new List(); dtoDatas.Add(entity); var boxInventoryResult = await _boxInventoryService.GenerateInStockBox(dtoDatas, isTransaction); if (!boxInventoryResult.IsSuccess) return boxInventoryResult; return Result.ReSuccess(); } /// /// 非采购上架-保存 /// /// /// /// /// private async Task ShelfNoPurchaseSave(NoPurchaseShelfRequest dto, LoginInDto loginInfo, bool isTransaction = true) { //1.获取来源单 var task = await _inStockTaskRepositories.Get(dto.TaskId); if (task == null) return Result.ReFailure(ResultCodes.SourceBillNoDateError); //2.生成:入库单 var entity = new InStock(); entity.Type = task.Type; entity.Method = dto.ShelfMethod == (int)ShelfMethod.Box ? InventoryInOutMethod.Box : InventoryInOutMethod.Product; entity.Details = new List(); var temps = new List(); //3.遍历:box信息,并拼装入库单明细 foreach (var box in dto.Boxs) { //3.1先数据映射 var dets = _mapper.Map>(box.Details); //3.2遍历赋值:boxID和仓库和仓位和来源单和供应商和组织 dets.ForEach(item => { item.TaskId = dto.TaskId; item.SourceBillNo = task.SourceBillNo; item.BoxId = box.BoxId; item.SubStockId = dto.SubStockId; item.StockCode = dto.StockCode; var taskDet = task.Details.Where(x => x.MaterialId == item.MaterialId).FirstOrDefault(); item.SupplierId = taskDet.SupplierId; item.OrgId = taskDet.OrgId; }); //3.3添加到临时集合中 temps.AddRange(dets); } //3.4给对象明细赋值 entity.Details = temps; //4.创建 entity.Create(loginInfo.UserInfo.StaffId); //5.1保存入库单信息 entity = await _inStockRepositories.Add(entity, isTransaction); if (entity == null) return Result.ReFailure(ResultCodes.DateWriteError); //6.当按产品上架:就要调用改箱的操作; if (dto.ShelfMethod == (int)ShelfMethod.Product) { var dto_box = dto.Boxs.FirstOrDefault(); var changeBox = new SaveChangeBoxRecordRequest(); changeBox.DestBoxId = dto_box.BoxId; foreach (var item in dto_box.Details) { var changeBoxRD = new SaveChangeBoxRecordDetailsRequest(); changeBoxRD.MaterialId = item.MaterialId; changeBoxRD.Qty = item.Qty; changeBoxRD.SerialNumbers = item.SerialNumbers; } //改箱保存操作 var changeBoxSave_Result = await _changeMoveBoxService.ChangeBoxSave(changeBox, loginInfo, isTransaction); if (!changeBoxSave_Result.IsSuccess) return changeBoxSave_Result; } //6.1序列号跟踪流程添加;备注:和上面的改箱操作后会记录序列号轨迹不冲突; var serialNumber_result = await _serialNumberService.InStock(entity, loginInfo, isTransaction); if (!serialNumber_result.IsSuccess) return serialNumber_result; //箱库存变动 var dtoDatas = new List(); dtoDatas.Add(entity); var boxInventoryResult = await _boxInventoryService.GenerateInStockBox(dtoDatas, isTransaction); if (!boxInventoryResult.IsSuccess) return boxInventoryResult; return Result.ReSuccess(); } /// /// 修改-入库任务信息 /// /// /// /// /// /// public async Task> Update(UpdateInStockTaskRequest dto, int staffId, bool? isReceive, bool isTransaction = true, bool isNoPurchaseShelf = false) { var entity = await _inStockTaskRepositories.Get(dto.Id); if (entity == null) return Result.ReFailure(ResultCodes.DateWriteError); entity = _mapper.Map(dto, entity); ////子集单独映射:这个弃用;这个不好的地方就是,前端必须拿到全部的boxs集合一起给到后端处理; //entity.Boxs = _mapper.ToMapList(dto.Boxs, entity.Boxs); //子集单独映射:box子集单独组装获取;这个好处就是前端就只传新增的box过来; foreach (var item in dto.Boxs) { var box = _mapper.Map(item); entity.Boxs.Add(box); } //子集单独映射 entity.Details = _mapper.ToMapList(dto.Details, entity.Details); if (isNoPurchaseShelf) entity.NoPurchaseShelf(staffId); else { if (isReceive.HasValue && isReceive.Value) entity.Receive(staffId); else entity.Shelf(staffId); } var result = await _inStockTaskRepositories.Update(entity, isTransaction); if (result != null) return Result.ReSuccess(entity); else return Result.ReFailure(ResultCodes.DateWriteError); } /// /// 批量修改-入库任务信息 /// /// /// /// /// /// public async Task UpdateRange(List ids, int staffId, bool isReceive, bool isTransaction = true) { var entitys = await _inStockTaskRepositories.GetList(ids); if (entitys == null || entitys.Count == 0) return Result.ReFailure(ResultCodes.DateWriteError); foreach (var item in entitys) { if (isReceive) item.Receive(staffId); else item.Shelf(staffId); } var isSuccess = await _inStockTaskRepositories.UpdateRange(entitys, isTransaction); if (isSuccess) return Result.ReSuccess(); else return Result.ReFailure(ResultCodes.DateWriteError); } /// /// 采购订单物料明细和箱物料明细-对比 /// /// /// public async Task> Contrast(ContrastMaterialsRequest dto) { //1.找到任务单的明细信息 var task = await _inStockTaskRepositories.Get(dto.TaskId); if (task == null) return Result.ReFailure(ResultCodes.OrderNoData); //1.1筛选出对应仓库的明细 var task_details = task.Details.Where(x => x.StockCode == dto.StockCode).ToList(); //2.找到箱对应的物料信息:多个箱 var boxs = await _boxRepositories.GetEntityListByNos(dto.BoxBillNos); if (boxs == null || boxs.Count == 0) return Result.ReFailure(ResultCodes.BoxNoData); //合并多个箱明细的数据:相同物料数量合并 var boxDetails = boxs.SelectMany(x => x.Details).GroupBy(x => x.MaterialId).Select(x => new { MaterialId = x.Key, Qty = x.Sum(t => t.Qty) }).ToList(); //3.比对:false为比对失败; bool isRight = boxDetails.All(x => task_details.Any(t => t.MaterialId == x.MaterialId && t.AccruedQty >= x.Qty)) && boxDetails.Count <= task_details.Count; if (!isRight) return Result.ReFailure(ResultCodes.ContrastError); //4.是否任务单存在绑定箱号判断:存在的话,就不能收货或者非采购上架 bool isHave = task.Boxs.Where(x => dto.BoxBillNos.Contains(x.BoxBillNo)).Any(); if (isHave) return Result.ReFailure(ResultCodes.BoxHaveError); //4.返回对比结果:true为比对成功,并把箱ID和箱号返回 var response = new ContrastMaterialsResponse(); foreach (var box in boxs) { var r_box = new ContrastBoxResponse(); r_box.BoxBillNo = box.BoxBillNo; r_box.BoxId = box.Id; r_box.TotalCount = box.Details.Sum(x => x.Qty); r_box.Details = _mapper.Map>(box.Details); response.Boxs.Add(r_box); } return Result.ReSuccess(response); } } }