using Newtonsoft.Json.Serialization; using Newtonsoft.Json; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WIDESEA_Common.LocationEnum; using WIDESEA_Common.StockEnum; using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Enums; using WIDESEA_Core.Helper; using WIDESEA_DTO; using WIDESEA_DTO.MES; using WIDESEA_IBasicRepository; using WIDESEA_IBasicService; using WIDESEA_IOutboundRepository; using WIDESEA_IOutboundService; using WIDESEA_IRecordService; using WIDESEA_IStockRepository; using WIDESEA_IStockService; using WIDESEA_Model.Models; using WIDESEA_OutboundRepository; using WIDESEA_Common.APIEnum; using WIDESEA_Common.OrderEnum; namespace WIDESEA_OutboundService { public class MesRworkOutboundOrderService : ServiceBase, IMesRworkOutboundOrderService { private readonly IBasicRepository _basicRepository; private readonly IStockService _stockService; private readonly IOutStockLockInfoService _outStockLockInfoService; private readonly IBasicService _basicService; private readonly IRecordService _recordService; private readonly IOutProStockInfoService _outProStockInfoService; private readonly IStockRepository _stockRepository; private readonly IOutProStockInfoRepository _outProStockInfoRepository; private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly IApiInfoRepository _apiInfoRepository; public IMesRworkOutboundOrderRepository Repository => BaseDal; public MesRworkOutboundOrderService(IMesRworkOutboundOrderRepository BaseDal, IBasicRepository basicRepository, IStockService stockService, IOutStockLockInfoService outStockLockInfoService, IBasicService basicService, IRecordService recordService, IOutProStockInfoService outProStockInfoService, IStockRepository stockRepository, IOutProStockInfoRepository outProStockInfoRepository,IUnitOfWorkManage unitOfWorkManage, IApiInfoRepository apiInfoRepository) : base(BaseDal) { _basicRepository = basicRepository; _stockService = stockService; _outStockLockInfoService = outStockLockInfoService; _basicService = basicService; _recordService = recordService; _outProStockInfoService = outProStockInfoService; _stockRepository = stockRepository; _outProStockInfoRepository = outProStockInfoRepository; _unitOfWorkManage = unitOfWorkManage; _apiInfoRepository = apiInfoRepository; } /// /// 提库任务分配库存 /// public (List?,Dt_MesRworkOutboundOrder?,List?,List) AssignMesStocks(Dt_MesRworkOutboundOrder mesRworkOutboundOrder) { List proStockInfos = new List(); Dt_MesRworkOutboundOrder assignOutOrder= new Dt_MesRworkOutboundOrder(); List outProStockInfos=new List(); List locationInfos=new List(); float originalNeedQuantity = mesRworkOutboundOrder.RequiredQuantity; float needQuantity = originalNeedQuantity; //查找可用库存 List stockInfoss = _stockService.ProStockInfoService.GetUseableStocks(mesRworkOutboundOrder); if (!stockInfoss.Any()) { throw new Exception("未找到可分配库存"); } List autoAssignStocks = _stockService.ProStockInfoService.GetOutboundStocks(stockInfoss,mesRworkOutboundOrder, needQuantity,out float residueQuantity); mesRworkOutboundOrder.LockQuantity += needQuantity - residueQuantity; autoAssignStocks.OrderBy(x => x.proStockInfoDetails.FirstOrDefault()?.StockPcsQty).ToList(); proStockInfos.AddRange(autoAssignStocks); float assignQuantity = needQuantity - residueQuantity; float orderQuantity = mesRworkOutboundOrder.RequiredQuantity; bool isCanDate = string.IsNullOrEmpty(mesRworkOutboundOrder.DateCode); for (int j = 0; j < autoAssignStocks.Count; j++) { //出库订单明细已分配数量 float detailAssignQuantity = outProStockInfos .Where(x => x.SaleOrder == mesRworkOutboundOrder.SaleOrder && x.PCode == mesRworkOutboundOrder.ProductCode && x.PVer == mesRworkOutboundOrder.ProductVersion && (isCanDate ? isCanDate : x.DateCode == mesRworkOutboundOrder.DateCode)) .Sum(x => x.AssignQuantity); //出库详情已分配数量 float palletAssignQuantity = outProStockInfos .Where(x => x.SaleOrder == mesRworkOutboundOrder.SaleOrder && x.PCode == mesRworkOutboundOrder.ProductCode && x.PVer == mesRworkOutboundOrder.ProductVersion && x.PalletCode == autoAssignStocks[j].PalletCode && (isCanDate ? isCanDate : x.DateCode == mesRworkOutboundOrder.DateCode)) .Sum(x => x.AssignQuantity); float palletOutboundQuantity = autoAssignStocks[j].proStockInfoDetails.Sum(x => x.OutboundQuantity); if (palletAssignQuantity < palletOutboundQuantity)//如果出库详情已分配数量小于托盘已分配数量,则可以继续添加该托盘出库信息 { float orderDetailNeedQuantity = mesRworkOutboundOrder.RequiredQuantity - detailAssignQuantity; if (orderDetailNeedQuantity > autoAssignStocks[j].proStockInfoDetails.Sum(x => x.OutboundQuantity) - palletAssignQuantity) { mesRworkOutboundOrder.LockQuantity += autoAssignStocks[j].proStockInfoDetails.Sum(x => x.OutboundQuantity) - palletAssignQuantity; Dt_OutProStockInfo outStockLockInfo = _outProStockInfoService.GetOutStockLockInfo(mesRworkOutboundOrder, autoAssignStocks[j], autoAssignStocks[j].proStockInfoDetails.Sum(x => x.OutboundQuantity) - palletAssignQuantity); outProStockInfos.Add(outStockLockInfo); } else { Dt_OutProStockInfo outStockLockInfo = _outProStockInfoService.GetOutStockLockInfo(mesRworkOutboundOrder, autoAssignStocks[j], mesRworkOutboundOrder.RequiredQuantity-mesRworkOutboundOrder.LockQuantity); outProStockInfos.Add(outStockLockInfo); mesRworkOutboundOrder.LockQuantity = mesRworkOutboundOrder.RequiredQuantity; break; } } } locationInfos.AddRange(_basicService.LocationInfoService.Repository.GetLocationInfos(proStockInfos.Select(x => x.LocationCode).ToList())); return (proStockInfos, mesRworkOutboundOrder, outProStockInfos, locationInfos); } public WebResponseContent LockOutboundStockDataUpdate(List stockInfos, List outStockLockInfos, List locationInfos, LocationStatusEnum locationStatus = LocationStatusEnum.Lock, List? tasks = null) { try { stockInfos.ForEach(x => { x.StockStatus = StockStatusEmun.出库锁定.ObjToInt(); }); _stockService.ProStockInfoService.Repository.UpdateData(stockInfos); List stockInfoDetails = new List(); foreach (var item in stockInfos) { stockInfoDetails.AddRange(item.proStockInfoDetails); } _stockService.ProStockInfoDetailService.Repository.UpdateData(stockInfoDetails); List addOutStockLockInfos = outStockLockInfos.Where(x => x.Id == 0).ToList(); if (addOutStockLockInfos != null && addOutStockLockInfos.Any()) { if (tasks != null) { addOutStockLockInfos.ForEach(x => { x.TaskNum = tasks.FirstOrDefault(v => v.PalletCode == x.PalletCode)?.TaskNum; }); } _outProStockInfoService.Repository.AddData(addOutStockLockInfos); } List updateOutStockLockInfos = outStockLockInfos.Where(x => x.Id > 0).ToList(); if (updateOutStockLockInfos != null && updateOutStockLockInfos.Any()) { _outProStockInfoService.Repository.UpdateData(updateOutStockLockInfos); } _recordService.LocationStatusChangeRecordSetvice.AddLocationStatusChangeRecord(locationInfos, locationStatus, LocationChangeType.OutboundAssignLocation, "", tasks?.Select(x => x.TaskNum).ToList()); _basicService.LocationInfoService.Repository.UpdateLocationStatus(locationInfos, locationStatus); return WebResponseContent.Instance.OK(); } catch (Exception ex) { return WebResponseContent.Instance.Error(ex.Message); } } /// /// 成品MES提库出库完后一包一包拣选 /// /// public WebResponseContent MesRworkOutPick(int OrderId,string InrPKCode,int Count=0) { WebResponseContent content = new WebResponseContent(); try { //获取当前的Mes提库单 Dt_MesRworkOutboundOrder rworkOutboundOrder = BaseDal.QueryFirst(x => x.Id == OrderId); if (rworkOutboundOrder == null) { return content.Error("未找到当前Mes提库单"); } if (rworkOutboundOrder.OrderStatus>=OutOrderStatusEnum.出库完成.ObjToInt()) { return content.Error("当前Mes提库单已完成或关闭"); } //根据扫描内包号获取库存 Dt_ProStockInfoDetail? proStockInfoDetail = _stockRepository.ProStockInfoDetailRepository.QueryFirst(x => x.BagNo == InrPKCode && x.ProOutDetailStatus == StockStatusEmun.出库完成.ObjToInt()); if (proStockInfoDetail == null) { return content.Error($"未找到内包{InrPKCode}信息"); } //获取库存信息 Dt_ProStockInfo? proStockInfo = _stockRepository.ProStockInfoRepository.Db.Queryable().Where(x => x.Id == proStockInfoDetail.ProStockId).Includes(x => x.proStockInfoDetails).First(); if (proStockInfo == null) { return content.Error($"未找到内包{InrPKCode}库存信息"); } //查询该托盘是否存在该单据的出库详情 Dt_OutProStockInfo outProStockInfo = _outProStockInfoRepository.QueryFirst(x => x.OrderNo == rworkOutboundOrder.TaskNo && x.PalletCode == proStockInfo.PalletCode); if (outProStockInfo == null) { return content.Error($"内包{InrPKCode}非单据{rworkOutboundOrder.TaskNo}内容"); } //判断是否整包数量 if (Count > 0) { if (Count> proStockInfoDetail.StockPcsQty) { return content.Error($"内包数量{(int)proStockInfoDetail.StockPcsQty}<出库数量{Count}"); } int setinterval = (int)proStockInfoDetail.StockPcsQty / (int)proStockInfoDetail.SETQty; if (Count % setinterval!=0) { return content.Error($"获取SET数量失败,1SET:{setinterval}PCS"); } proStockInfoDetail.OutSETQty = Count / setinterval; proStockInfoDetail.OutboundQuantity = Count; } else { proStockInfoDetail.OutSETQty = proStockInfoDetail.SETQty; proStockInfoDetail.OutboundQuantity = proStockInfoDetail.StockPcsQty; } rworkOutboundOrder.OverOutQuantity += proStockInfoDetail.OutboundQuantity; if (rworkOutboundOrder.OverOutQuantity> rworkOutboundOrder.RequiredQuantity) { return content.Error($"单据{rworkOutboundOrder.TaskNo}溢出{rworkOutboundOrder.OverOutQuantity - rworkOutboundOrder.RequiredQuantity}"); } if (rworkOutboundOrder.OverOutQuantity== rworkOutboundOrder.RequiredQuantity) { rworkOutboundOrder.OrderStatus = OutOrderStatusEnum.出库完成.ObjToInt(); } int SetCount = (int)proStockInfoDetail.OutSETQty; int EligiblePcsCount = (int)proStockInfoDetail.OutboundQuantity; _unitOfWorkManage.BeginTran(); if (proStockInfoDetail.SETQty == proStockInfoDetail.OutSETQty && proStockInfoDetail.StockPcsQty== proStockInfoDetail.OutboundQuantity) { proStockInfo.proStockInfoDetails.Remove(proStockInfoDetail); if (proStockInfo.proStockInfoDetails.Count==0) { _stockRepository.ProStockInfoRepository.DeleteAndMoveIntoHty(proStockInfo, OperateTypeEnum.自动删除); } _stockRepository.ProStockInfoDetailRepository.DeleteAndMoveIntoHty(proStockInfoDetail, OperateTypeEnum.自动删除); } else { proStockInfoDetail.SETQty -= proStockInfoDetail.OutSETQty; proStockInfoDetail.StockPcsQty -= proStockInfoDetail.OutboundQuantity; proStockInfoDetail.OutSETQty = 0; proStockInfoDetail.OutboundQuantity = 0; _stockRepository.ProStockInfoDetailRepository.UpdateData(proStockInfoDetail); } BaseDal.UpdateData(rworkOutboundOrder); //MES成品库存板出库同步 WebResponseContent responseContent = ProductOutBoundSync(MesProOutBound(rworkOutboundOrder, new List { proStockInfoDetail }, SetCount, EligiblePcsCount)); if (responseContent.Status) { throw new Exception("同步MES库存板出库失败,错误:" + responseContent.Message); } _unitOfWorkManage.CommitTran(); if (rworkOutboundOrder.OrderStatus==OutOrderStatusEnum.出库完成.ObjToInt()) { content.OK($"单号{rworkOutboundOrder.TaskNo}已完成"); } else { content.OK($"单号{rworkOutboundOrder.TaskNo},剩余:{rworkOutboundOrder.RequiredQuantity-rworkOutboundOrder.OverOutQuantity}PCS"); } } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); content.Error(ex.Message); } return content; } /// /// 库存板数据转换 /// /// public MesProductOutBound MesProOutBound(Dt_MesRworkOutboundOrder mesRworkOutboundOrder, List proStockInfoDetails,int SetCount,int EligiblePcsCount) { //获取仓库信息 Dt_Warehouse warehouse = _basicRepository.WarehouseRepository.QueryFirst(x => x.WarehouseId == mesRworkOutboundOrder.WarehouseId); List inventoryInfos = new List(); foreach (var item in proStockInfoDetails) { MesInventoryInfo mesInventoryInfo = new MesInventoryInfo() { Warhouseno = warehouse.WarehouseCode, InternalPackageNumber = item.BagNo, SetCount = SetCount, EligiblePcsCount = EligiblePcsCount }; inventoryInfos.Add(mesInventoryInfo); } MesProductOutBound mesProductOutBound = new MesProductOutBound() { TaskNo = mesRworkOutboundOrder.TaskNo, ProductCode = mesRworkOutboundOrder.ProductCode, ProductVersion = mesRworkOutboundOrder.ProductVersion, DateCode = mesRworkOutboundOrder.DateCode, SaleOrder = mesRworkOutboundOrder.SaleOrder, InventoryInfo = inventoryInfos }; return mesProductOutBound; } /// /// 成品库存板同步接口 /// public WebResponseContent ProductOutBoundSync(MesProductOutBound model) { WebResponseContent content = new WebResponseContent(); try { Dt_ApiInfo apiInfo = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.WMS_MES_ProductOutBound.ToString()); MESRoot root = new MESRoot() { From = "WMS", DateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Content = model }; JsonSerializerSettings settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }; string request = JsonConvert.SerializeObject(root, settings); string response = HttpMesHelper.Post(apiInfo.ApiAddress, request); MesResponseContent mesResponseContent = response.DeserializeObject(); //调用接口 if (mesResponseContent.BSucc == true) { content.OK(mesResponseContent.StrMsg); } else { content.Error(mesResponseContent.StrMsg); } } catch (Exception ex) { content.Error(ex.Message); } return content; } } }