using AutoMapper; using Microsoft.EntityFrameworkCore.Storage; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Json; 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 ISerialNumbersRepositories _serialNumbersRepositories; private readonly IInStockTaskBoxRepositories _inStockTaskBoxRepositories; 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; private readonly IBoxInventoryRepositories _boxInventoryRepositories; public InStockService(IMapper mapper, ISerialNumbersRepositories serialNumbersRepositories, IErpService erpService, IBoxInventoryService boxInventoryService, ISerialNumberService serialNumberService, ILoginService loginService, IBoxRepositories boxRepositories, IBasicsRepositories basicsRepositories, IErpBasicDataExtendService erpBasicDataExtendService, IChangeMoveBoxService changeMoveBoxService, IInStockTaskBoxRepositories inStockTaskBoxRepositories, IInStockRepositories inStockRepositories, IInStockTaskRepositories inStockTaskRepositories, IBoxInventoryRepositories boxInventoryRepositories) { _mapper = mapper; _erpService = erpService; _loginService = loginService; _boxInventoryService = boxInventoryService; _serialNumberService = serialNumberService; _boxRepositories = boxRepositories; _changeMoveBoxService = changeMoveBoxService; _basicsRepositories = basicsRepositories; _inStockRepositories = inStockRepositories; _inStockTaskBoxRepositories = inStockTaskBoxRepositories; _inStockTaskRepositories = inStockTaskRepositories; _erpBasicDataExtendService = erpBasicDataExtendService; _serialNumbersRepositories = serialNumbersRepositories; _boxInventoryRepositories = boxInventoryRepositories; } /// /// 同步-金蝶 /// /// /// 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.Receive(dto, loginInfo.UserInfo.StaffId, 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; //提交事务 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 shelfSave_result; return Result.ReSuccess(); } /// /// 获取任务单:根据箱号信息 /// /// /// public async Task> GetInfoByBox(BoxInStockTaskRequest dto) { //1.获取物料集合 var materials_result = await _erpService.BillQueryForMaterial(); var materials = new List(); if (materials_result.IsSuccess) materials = materials_result.Data.ToList(); //1.先判断:箱号已经绑定了入库任务单中;备注:业务说法就是箱是否收货了 var tast_box = await _inStockTaskBoxRepositories.GetBy(dto.BoxBillNo); if (tast_box == null) return Result.ReFailure(ResultCodes.Box_NoBind_Task_Data); //1.2找到任务单 var tast = await _inStockTaskRepositories.Get(tast_box.TaskId); if (tast == null) return Result.ReFailure(ResultCodes.InStockTaskNoData); //1.2.1判断箱子绑定的物料明细数据的仓库,是不是用户所选的仓库;不是则提示:箱号仓库不对 foreach (var item in tast_box.Details) { var tast_det = tast.Details.Where(t => t.ErpDetailId == item.ErpDetailId).FirstOrDefault(); if (tast_det != null && tast_det.StockCode != dto.StockCode) return Result.ReFailure(ResultCodes.BoxBindTaskDetailsIdNotChoose); } //2.找到箱对应的物料信息 var box = await _boxRepositories.GetByNo(dto.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 = new BoxInStockTaskDto(); result.SourceBillNo = tast.SourceBillNo; result.TaskId = tast.Id; result.BoxId = box.Id; //获取:当前箱的与收货绑定的信息 foreach (var item in tast_box.Details) { var current_task_det = tast.Details.Where(x => x.ErpDetailId == item.ErpDetailId).FirstOrDefault(); if (current_task_det != null) { //3.2映射返回明细对象 var box_task_detail = new BoxDetailsInStockTaskDto(); box_task_detail.SupplierId = current_task_det.SupplierId; box_task_detail.OrgId = current_task_det.OrgId; box_task_detail.ReceiveQty = current_task_det.ReceiveQty; box_task_detail.AccruedQty = current_task_det.AccruedQty; box_task_detail.ErpDetailId = item.ErpDetailId; box_task_detail.MaterialId = item.MaterialId; box_task_detail.BoxMaterialQty = item.ReceiveQty; box_task_detail.MaterialName = _erpBasicDataExtendService.GetMaterialName(materials, item.MaterialId); box_task_detail.MaterialNumber = _erpBasicDataExtendService.GetMaterialNumber(materials, item.MaterialId); box_task_detail.Specifications = _erpBasicDataExtendService.GetMaterialSpecifications(materials, item.MaterialId); result.Details.Add(box_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); //序列号集:箱里面的 var serialNumbers = await _serialNumbersRepositories.GetEntityListByBoxIds(dto.Details.GroupBy(x => x.BoxId).Select(x => x.Key).ToList()); //赋值序列号 entity.Details.ForEach(x => { var current_box_serNums = serialNumbers.Where(t => t.BoxId == x.BoxId).ToList(); if (current_box_serNums != null) { var current_box_mat_serNums = current_box_serNums.Where(t => t.MaterialId == x.MaterialId).Select(t => t.SerialNumber).ToList(); x.SerialNumbers.AddRange(current_box_mat_serNums); } }); 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_entityDets = dto.Details.Where(t => t.ErpDetailId == x.ErpDetailId).ToList(); if (current_entityDets != null && current_entityDets.Count != 0 && x.ErpDetailId == current_entityDets.FirstOrDefault().ErpDetailId) { var current_entityDet_matQty = current_entityDets.Sum(x => x.Qty); x.DeliveredQty = x.ReceiveQty; x.RealityQty = x.RealityQty + current_entityDet_matQty; } }); task.Shelf(loginInfo.UserInfo.StaffId); 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.1过滤的明细:0数量入库的明细要过滤掉 dto.Boxs.ForEach(x => { x.Details.RemoveAll(t => t.Qty == 0); }); //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; item.OrgCode = dto.OrgCode; item.OrgId = task.Details.Select(x => x.OrgId).FirstOrDefault(); }); //3.3添加到临时集合中 temps.AddRange(dets); } //3.4给对象明细赋值 entity.Details = temps; //4.创建 entity.Create(loginInfo.UserInfo.StaffId); //序列号集:箱里面的 var serialNumbers = await _serialNumbersRepositories.GetEntityListByBoxIds(dto.Boxs.GroupBy(x => x.BoxId).Select(x => x.Key).ToList()); if (dto.ShelfMethod == (int)ShelfMethod.Box) { //赋值序列号 entity.Details.ForEach(x => { var current_box_serNums = serialNumbers.Where(t => t.BoxId == x.BoxId).ToList(); if (current_box_serNums != null) { var current_box_mat_serNums = current_box_serNums.Where(t => t.MaterialId == x.MaterialId).Select(t => t.SerialNumber).ToList(); x.SerialNumbers.AddRange(current_box_mat_serNums); } }); } //5.1保存入库单信息 entity = await _inStockRepositories.Add(entity, isTransaction); if (entity == null) return Result.ReFailure(ResultCodes.DateWriteError); //同步金蝶后,反写任务单的已交数量 if (task != null) { task.Details.ForEach(x => { var current_entityDets = entity.Details.Where(t => t.ErpDetailId == x.ErpDetailId).ToList(); if (current_entityDets != null && current_entityDets.Count != 0 && x.ErpDetailId == current_entityDets.FirstOrDefault().ErpDetailId) { var current_entityDet_matQty = current_entityDets.Sum(x => x.Qty); x.ReceiveQty = x.ReceiveQty + current_entityDet_matQty; x.DeliveredQty = x.ReceiveQty; x.RealityQty = x.RealityQty + current_entityDet_matQty; } }); task.NoPurchaseShelf(loginInfo.UserInfo.StaffId); task = await _inStockTaskRepositories.Update(task, isTransaction); if (task == null) return Result.ReFailure(ResultCodes.DateWriteError); } //6.当按产品上架:就要调用改箱的操作; if (dto.ShelfMethod == (int)ShelfMethod.Product) { //通过序列号,获取序列号对应的箱 var cureent_serialNumbs = await _serialNumbersRepositories.GetEntityList(dto.Boxs.SelectMany(x => x.Details).SelectMany(x => x.SerialNumbers).ToList()); var current_boxIds = cureent_serialNumbs.GroupBy(x => x.BoxId).Select(x => x.Key).ToList(); //要改箱的数据集合 var ganenrateChangeBoxs = new List(); //当前按产品上架的箱子 var dto_box = dto.Boxs.FirstOrDefault(); //遍历:序列号对应多个箱 foreach (var boxId in current_boxIds) { if (dto_box.BoxId != boxId) { //遍历:明细 var changeBox = new SaveChangeBoxRecordRequest(); changeBox.DestBoxId = dto_box.BoxId; changeBox.SrcBoxId = boxId; changeBox.SubStockId = dto.SubStockId; foreach (var item in dto_box.Details) { var changeBoxRD = new SaveChangeBoxRecordDetailsRequest(); changeBoxRD.MaterialId = item.MaterialId; changeBoxRD.Qty = item.Qty; changeBoxRD.SerialNumbers = item.SerialNumbers; changeBox.Details.Add(changeBoxRD); } ganenrateChangeBoxs.Add(changeBox); } } //改箱保存操作 var changeBoxSave_Result = await _changeMoveBoxService.ChangeBoxSave(ganenrateChangeBoxs, 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> Receive(UpdateInStockTaskRequest dto, int staffId, bool isTransaction) { //1.修改任务单的数据 var entity = await _inStockTaskRepositories.Get(dto.Id); if (entity == null) return Result.ReFailure(ResultCodes.DateWriteError); entity = _mapper.Map(dto, entity); entity.Receive(staffId); //子集单独映射 entity.Details.ForEach(x => { //当前明细收货的明细:可以通过erp明细ID获取唯一一个;并变更收货数量 var current_dto_det = dto.Details.Where(x => x.ErpDetailId == x.ErpDetailId).FirstOrDefault(); if (current_dto_det != null && x.ErpDetailId == current_dto_det.ErpDetailId) x.ReceiveQty = x.ReceiveQty + current_dto_det.ReceiveQty; }); //2.修改箱和任务单的绑定关系,先判断箱没有被收货过 var taskBoxList = await _inStockTaskBoxRepositories.GetListBy(entity.Id); var dto_boxIds = dto.Boxs.GroupBy(x => x.BoxId).Select(x => x.Key).ToList(); var isHaveBox = taskBoxList.Where(x => dto_boxIds.Contains(x.BoxId)).Any(); if (isHaveBox) return Result.ReFailure(ResultCodes.InStockTaskBoxIsHaveData); //3.组装绑定关系表,要添加的集合 var boxEntitys = await _boxRepositories.GetEntityList(dto_boxIds); var taskBoxAdd = new List(); foreach (var item in dto.Boxs) { var taskBox = _mapper.Map(item); taskBox.TaskId = entity.Id; var current_dto_box_dets = boxEntitys.Where(x => x.Id == item.BoxId).SelectMany(x => x.Details).ToList(); taskBox.Details = _mapper.Map>(current_dto_box_dets); taskBox.Details.ForEach(x => { x.ErpDetailId = item.ErpDetailId; }); taskBoxAdd.Add(taskBox); } var isSuccess = await _inStockTaskBoxRepositories.AddRange(taskBoxAdd, isTransaction); if (!isSuccess) return Result.ReFailure(ResultCodes.DateWriteError); //数据库操作 var result = await _inStockTaskRepositories.Update(entity, isTransaction); if (result == null) return Result.ReFailure(ResultCodes.DateWriteError); return Result.ReSuccess(entity); } /// /// 批量修改-入库任务信息 /// /// /// /// /// /// 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 boxInventory = await _boxInventoryRepositories.GetList(boxs.Select(x => x.Id).ToList()); if (boxInventory != null && boxInventory.Count != 0) return Result.ReFailure(ResultCodes.BoxInventoryHaveInventoryError); //合并多个箱明细的数据:相同物料数量合并 var boxDetails = boxs.SelectMany(x => x.Details).GroupBy(x => x.MaterialId).Select(x => new { MaterialId = x.Key, Qty = x.Sum(t => t.Qty) }).ToList(); //采购单:要对比数量 if (task.Type == InstockType.Purchase) { //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) { var qtyIsError = boxDetails.All(x => task_details.Any(t => t.MaterialId == x.MaterialId && t.AccruedQty < x.Qty)); if (boxDetails.Count > task_details.Count && qtyIsError) return Result.ReFailure(ResultCodes.Contrast_Purchase_Error); else if (qtyIsError) return Result.ReFailure(ResultCodes.Contrast_Qty_Error); else return Result.ReFailure(ResultCodes.Contrast_Purchase_Count_Error); } } //非采购单:不要对比数量,只对比物料 else { //3.比对:false为比对失败; bool isRight = boxDetails.All(x => task_details.Any(t => t.MaterialId == x.MaterialId)) && boxDetails.Count <= task_details.Count; if (!isRight) return Result.ReFailure(ResultCodes.Contrast_Count_Error); } //4.是否任务单存在绑定箱号判断:存在的话,就不能收货或者非采购上架 var taskBoxList = await _inStockTaskBoxRepositories.GetListBy(dto.BoxBillNos); if (taskBoxList != null && taskBoxList.Count != 0) 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); } } }