| 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; | 
| using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; | 
| using System.Reflection.Metadata; | 
|   | 
| namespace WIDESEA_OutboundService | 
| { | 
|     public class MesRworkOutboundOrderService : ServiceBase<Dt_MesRworkOutboundOrder, IMesRworkOutboundOrderRepository>, 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; | 
|         } | 
|         /// <summary> | 
|         /// 提库任务分配库存 | 
|         /// </summary> | 
|         public (List<Dt_ProStockInfo>?,Dt_MesRworkOutboundOrder?,List<Dt_OutProStockInfo>?,List<Dt_LocationInfo>) AssignMesStocks(Dt_MesRworkOutboundOrder mesRworkOutboundOrder) | 
|         { | 
|             List<Dt_ProStockInfo> proStockInfos = new List<Dt_ProStockInfo>(); | 
|             Dt_MesRworkOutboundOrder assignOutOrder= new Dt_MesRworkOutboundOrder(); | 
|             List<Dt_OutProStockInfo> outProStockInfos=new List<Dt_OutProStockInfo>(); | 
|             List<Dt_LocationInfo> locationInfos=new List<Dt_LocationInfo>(); | 
|             float needQty = mesRworkOutboundOrder.RequiredQuantity; | 
|             //查找可用库存 | 
|             List<Dt_ProStockInfo> stockInfoss = _stockService.ProStockInfoService.GetUseableStocks(mesRworkOutboundOrder); | 
|             if (!stockInfoss.Any()) | 
|             { | 
|                 throw new Exception("未找到可分配库存"); | 
|             } | 
|             //获取出库库存 | 
|             List<Dt_ProStockInfo> assignOutStocks = _stockService.ProStockInfoService.GetOutboundStocks(stockInfoss, mesRworkOutboundOrder, needQty, out float residueQuantity); | 
|             mesRworkOutboundOrder.LockQuantity += needQty - residueQuantity; | 
|             if (mesRworkOutboundOrder.RequiredQuantity > mesRworkOutboundOrder.LockQuantity) | 
|             { | 
|                 throw new Exception($"产品编码{mesRworkOutboundOrder.ProductCode},版本{mesRworkOutboundOrder.ProductVersion}可分配数量不足,可用数量{mesRworkOutboundOrder.LockQuantity}"); | 
|             } | 
|             proStockInfos.AddRange(assignOutStocks); | 
|             //分配出库的PCS数量 | 
|             float assignQuantity = needQty; | 
|             //订单明细的出库PCS数量 | 
|             float orderQuantity = mesRworkOutboundOrder.RequiredQuantity; | 
|             for (int j = 0; j < assignOutStocks.Count; j++) | 
|             { | 
|                 //出库订单明细已分配数量 | 
|                 float detailAssignQuantity = outProStockInfos.Where(x => x.OrderDetailId == mesRworkOutboundOrder.Id).Sum(x => x.AssignQuantity); | 
|   | 
|                 //所剩数量 | 
|                 float orderDetailNeedQuantity = mesRworkOutboundOrder.RequiredQuantity - detailAssignQuantity; | 
|                 //生成出库详情 | 
|                 if (orderDetailNeedQuantity > assignOutStocks[j].proStockInfoDetails.Sum(x => x.OutboundQuantity)) | 
|                 { | 
|                     mesRworkOutboundOrder.LockQuantity += assignOutStocks[j].proStockInfoDetails.Sum(x => x.OutboundQuantity); | 
|                     Dt_OutProStockInfo outStockLockInfo = _outProStockInfoService.GetOutStockLockInfo(mesRworkOutboundOrder, assignOutStocks[j], assignOutStocks[j].proStockInfoDetails.Sum(x => x.OutboundQuantity)); | 
|                     outProStockInfos.Add(outStockLockInfo); | 
|                 } | 
|                 else | 
|                 { | 
|                     Dt_OutProStockInfo outStockLockInfo = _outProStockInfoService.GetOutStockLockInfo(mesRworkOutboundOrder, assignOutStocks[j], mesRworkOutboundOrder.RequiredQuantity - detailAssignQuantity); | 
|                     outProStockInfos.Add(outStockLockInfo); | 
|                     mesRworkOutboundOrder.LockQuantity = mesRworkOutboundOrder.RequiredQuantity; | 
|                     break; | 
|                 } | 
|             } | 
|             List<string> locationArr = proStockInfos.Select(x => x.LocationCode).ToList(); | 
|   | 
|             locationInfos.AddRange(_basicService.LocationInfoService.Repository.GetLocationInfos(locationArr)); | 
|   | 
|             return (proStockInfos, mesRworkOutboundOrder, outProStockInfos, locationInfos); | 
|         } | 
|         public WebResponseContent LockOutboundStockDataUpdate(List<Dt_ProStockInfo> stockInfos, List<Dt_OutProStockInfo> outStockLockInfos, List<Dt_LocationInfo> locationInfos, LocationStatusEnum locationStatus = LocationStatusEnum.Lock, List<Dt_Task>? tasks = null) | 
|         { | 
|             try | 
|             { | 
|                 stockInfos.ForEach(x => { | 
|                     x.StockStatus = StockStatusEmun.出库锁定.ObjToInt(); | 
|                 }); | 
|                 _stockService.ProStockInfoService.Repository.UpdateData(stockInfos); | 
|                 List<Dt_ProStockInfoDetail> stockInfoDetails = new List<Dt_ProStockInfoDetail>(); | 
|                 foreach (var item in stockInfos) | 
|                 { | 
|                     stockInfoDetails.AddRange(item.proStockInfoDetails); | 
|                 } | 
|                 _stockService.ProStockInfoDetailService.Repository.UpdateData(stockInfoDetails); | 
|   | 
|                 List<Dt_OutProStockInfo> 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<Dt_OutProStockInfo> 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); | 
|             } | 
|         } | 
|         /// <summary> | 
|         /// 成品MES提库出库完后一包一包拣选 | 
|         /// </summary> | 
|         /// <returns></returns> | 
|         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<Dt_ProStockInfo>().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<Dt_ProStockInfoDetail> { 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; | 
|         } | 
|         /// <summary> | 
|         /// 库存板数据转换 | 
|         /// </summary> | 
|         /// <returns></returns> | 
|         public MesProductOutBound MesProOutBound(Dt_MesRworkOutboundOrder mesRworkOutboundOrder, List<Dt_ProStockInfoDetail> proStockInfoDetails,int SetCount,int EligiblePcsCount) | 
|         { | 
|             //获取仓库信息 | 
|             Dt_Warehouse warehouse = _basicRepository.WarehouseRepository.QueryFirst(x => x.WarehouseId == mesRworkOutboundOrder.WarehouseId); | 
|             List<MesInventoryInfo> inventoryInfos = new List<MesInventoryInfo>(); | 
|             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 MesProductOutBound MesProOutBound(Dt_MesRworkOutboundOrder mesRworkOutboundOrder, List<Dt_ProStockInfoDetail> proStockInfoDetails) | 
|         { | 
|             //获取仓库信息 | 
|             Dt_Warehouse warehouse = _basicRepository.WarehouseRepository.QueryFirst(x => x.WarehouseId == mesRworkOutboundOrder.WarehouseId); | 
|             List<MesInventoryInfo> inventoryInfos = new List<MesInventoryInfo>(); | 
|             foreach (var item in proStockInfoDetails.Where(x=>x.OutboundQuantity>0)) | 
|             { | 
|                 int setinterval = (int)item.StockPcsQty / (int)item.SETQty; | 
|                 if (setinterval == 0) | 
|                 { | 
|                     throw new Exception($"{item.BagNo}获取SET数量转换失败"); | 
|                 } | 
|                 item.OutSETQty = (int)item.OutboundQuantity / setinterval; | 
|                 if (item.OutSETQty == 0) | 
|                 { | 
|                     throw new Exception($"{item.BagNo}获取SET数量转换失败"); | 
|                 } | 
|                 MesInventoryInfo mesInventoryInfo = new MesInventoryInfo() | 
|                 { | 
|                     Warhouseno = warehouse.WarehouseCode, | 
|                     InternalPackageNumber = item.BagNo, | 
|                     SetCount = (int)item.OutSETQty, | 
|                     EligiblePcsCount = (int)item.OutboundQuantity | 
|                 }; | 
|                 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; | 
|         } | 
|         /// <summary> | 
|         /// 成品库存板同步接口 | 
|         /// </summary> | 
|         public WebResponseContent ProductOutBoundSync(MesProductOutBound model) | 
|         { | 
|             WebResponseContent content = new WebResponseContent(); | 
|             try | 
|             { | 
|                 Dt_ApiInfo apiInfo = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.WMS_MES_ProductOutBound.ToString()); | 
|                 MESRoot<MesProductOutBound> root = new MESRoot<MesProductOutBound>() | 
|                 { | 
|                     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<MesResponseContent>(); | 
|                 //调用接口 | 
|                 if (mesResponseContent.BSucc == true) | 
|                 { | 
|                     content.OK(mesResponseContent.StrMsg); | 
|                 } | 
|                 else | 
|                 { | 
|                     content.Error(mesResponseContent.StrMsg); | 
|                 } | 
|             } | 
|             catch (Exception ex) | 
|             { | 
|                 content.Error(ex.Message); | 
|             } | 
|             return content; | 
|         } | 
|     } | 
| } |