using Admin.NET.Core.Service; using Admin.NET.Application.Entity; using Microsoft.AspNetCore.Http; using System.Data; using System.Web; using System.Text; using static SKIT.FlurlHttpClient.Wechat.Api.Models.ChannelsECLeagueHeadSupplierOrderGetResponse.Types.CommssionOrder.Types; using System.Linq.Expressions; using Furion.LinqBuilder; using System.Linq; using Admin.NET.Application.CommonHelper; using DocumentFormat.OpenXml.Office.CustomUI; namespace Admin.NET.Application; /// /// 容器分拣信息服务 /// [ApiDescriptionSettings(ApplicationConst.WmsTaskGroupName, Order = 100)] public class WmsPredetermineService : IDynamicApiController, ITransient { /// /// 是否正在执行预配方法 /// private static bool isRuning_Fun_Predetermine = false; private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); private readonly SqlSugarRepository _wmsContainerSortRep; private readonly SqlSugarRepository _v_wms_stock_quanRep; private readonly SqlSugarRepository _wmsOrderSortDetailsRep; //private readonly SqlSugarRepository _wmsStockQuanLockRep; private readonly SqlSugarRepository _wmsOrderSortRep; private readonly SqlSugarRepository _wmsOrderMovementDetailsRep; private readonly SqlSugarRepository _v_wmsOrderMovementDetailsRep; private readonly SqlSugarRepository _wmsOrderMovementRep; private readonly SqlSugarRepository _wmsTaskRep; private readonly SqlSugarRepository _wmsRecordPredDispHistoryRep; private readonly SqlSugarRepository _v_wms_stock_quan_use_groupRep; public WmsPredetermineService( SqlSugarRepository v_wmsOrderMovementDetailsRep, SqlSugarRepository wmsContainerSortRep, SqlSugarRepository v_wms_stock_quanRep, //SqlSugarRepository wmsStockQuanLockRep, SqlSugarRepository wmsOrderSortDetailsRep, SqlSugarRepository wmsOrderSortRep, SqlSugarRepository wmsOrderMovementDetailsRep, SqlSugarRepository wmsOrderMovementRep, SqlSugarRepository wmsTaskRep, SqlSugarRepository wmsRecordPredDispHistoryRep, SqlSugarRepository v_wms_stock_quan_use_groupRep) { _wmsContainerSortRep = wmsContainerSortRep; _v_wms_stock_quanRep = v_wms_stock_quanRep; //_wmsStockQuanLockRep = wmsStockQuanLockRep; _wmsOrderSortDetailsRep = wmsOrderSortDetailsRep; _wmsOrderSortRep = wmsOrderSortRep; _wmsOrderMovementDetailsRep = wmsOrderMovementDetailsRep; _wmsOrderMovementRep = wmsOrderMovementRep; _wmsTaskRep = wmsTaskRep; _wmsRecordPredDispHistoryRep = wmsRecordPredDispHistoryRep; _v_wms_stock_quan_use_groupRep = v_wms_stock_quan_use_groupRep; _v_wmsOrderMovementDetailsRep = v_wmsOrderMovementDetailsRep; } /// /// 预配 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Predetermine")] [Description("WmsPredetermine/Predetermine")] public async Task Predetermine(List input) { try { if (isRuning_Fun_Predetermine) { throw Oops.Oh("程序正忙,请稍后再试"); } await semaphoreSlim.WaitAsync(); isRuning_Fun_Predetermine = true; return await PredetermineFaction(input); } catch (Exception ex) { throw Oops.Oh(ex.Message); } finally { semaphoreSlim.Release(); isRuning_Fun_Predetermine = false; } } /// /// 取消预配 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "CancelPredetermine")] [Description("WmsPredetermine/CancelPredetermine")] public async Task CancelPredetermine(List input) { try { if (isRuning_Fun_Predetermine) { throw Oops.Oh("程序正忙,请稍后再试"); } await semaphoreSlim.WaitAsync(); isRuning_Fun_Predetermine = true; return await PredetermineFaction(input, true); } catch (Exception ex) { throw Oops.Oh(ex.Message); } finally { semaphoreSlim.Release(); isRuning_Fun_Predetermine = false; } } /// /// 预配/取消预配 /// /// /// /// private async Task PredetermineFaction(List input, bool isCancel = false) { /** * 获取预配物料库存信息 * 获取当前预配锁定库存信息 * 校验可用库存-历史预配锁定库存 是否满足预配 * 新增预配锁定库存 * 修改下架单明细预配数 * 新增事务 * 新增操作日期 */ List addWmsRecordPredDispHistoryList = new List();//新增的预配历史记录 //var addWmsStockQuanLockList = new List();//新增的锁定库存信息 //var updateWmsStockQuanLockList = new List();//更新的锁定库存信息 var updateWmsOrderMoveDetailsList = new List();//修改的移动单明细 //var updateWmsOrderMoveList = new List();//修改的移动单 List moveNoList = input.Select(s => s.MovementNo).ToList(); var allWmsOrderSortList = await _wmsOrderMovementRep.GetListAsync(u => moveNoList.Contains(u.OrderNo)); if (allWmsOrderSortList?.Count <= 0) { throw Oops.Oh("下架单不存在"); } //获取下架单所有明细 var allOrderSortDetails = await _wmsOrderMovementDetailsRep.GetListAsync(u => moveNoList.Contains(u.MovementNo)); if (allOrderSortDetails?.Count <= 0) { throw Oops.Oh("下架单明细不存在"); } // 查找物料库存 List materialCodeList = input.Select(x => x.MaterialCode).Distinct().ToList(); List allStockQuanGroupList = null; if (!isCancel) { //根据物料编码获取物料汇总库存(同一个物料号分组汇总v_wms_stock_quan_for_use视图查询到细分到跟踪码的库存信息) allStockQuanGroupList = await _v_wms_stock_quan_use_groupRep.GetListAsync(x => materialCodeList.Contains(x.MaterialCode) && x.UseQty > 0); if (allStockQuanGroupList?.Count <= 0) { throw Oops.Oh("所有物料都没有库存"); } } ////获取所有物料锁定库存 //var allStockQuanLockList = await _wmsStockQuanLockRep.GetListAsync(x => materialCodeList.Contains(x.MaterialCode)); ////物料预配锁定库存 //var allStockQuanLockForPredetermineList = allStockQuanLockList.Where(x => x.LockType == LockTypeEnum.预配 && x.IsDelete == false).ToList(); //TODO 分配预配锁定库存 //获取本次操作的下架单和下架单明细 var currentMovementDetailsKeyList = input.Select(x => x.MovementNo + x.LineNumber).ToList(); var currentMovementDetailsList = await _wmsOrderMovementDetailsRep.GetListAsync(x => currentMovementDetailsKeyList.Contains(x.MovementNo + x.LineNumber)); var v_currentMovementDetailsList = await _v_wmsOrderMovementDetailsRep.GetListAsync(x => currentMovementDetailsKeyList.Contains(x.MovementNo + x.LineNumber)); var queryOrderIds = currentMovementDetailsList.Select(x => x.MovementId).Distinct().ToList(); var currentOrderMovementList = await _wmsOrderMovementRep.GetListAsync(x => queryOrderIds.Contains(x.Id)); foreach (var inputItem in input) { WmsOrderMovement movementOrder = currentOrderMovementList.FirstOrDefault(p => p.OrderNo == inputItem.MovementNo); if (movementOrder == null) { throw Oops.Oh("本次分配的下架单不存在"); } //TODO 校验下架单状态 var movementDetails = currentMovementDetailsList.FirstOrDefault(x => x.MovementNo == inputItem.MovementNo && x.LineNumber == inputItem.LineNumber); if (movementDetails == null) { throw Oops.Oh("本次分配的下架单明细不存在"); } var v_movementDetails = v_currentMovementDetailsList.FirstOrDefault(x => x.MovementNo == inputItem.MovementNo && x.LineNumber == inputItem.LineNumber); if (v_movementDetails == null) { throw Oops.Oh("本次分配的下架单明细不存在"); } var addWmsRecordPredDispHistory = new WmsRecordPredDispHistory() { PDRecordType = PDRecordTypeEnum.预配, PDRecordTypeName = PDRecordTypeEnum.预配.ToString(), Quantity = inputItem.SendQuantity, MovementNo = movementDetails.MovementNo, MovementLineNumber = movementDetails.LineNumber, MaterialCode = movementDetails.MaterialCode, MaterialName = movementDetails.MaterialName, Remarks = "预配操作" }; if (!isCancel) { #region 处理预配 decimal historyPredetermineQuantity = movementDetails.PredetermineQuantity;//下架单的历史预配数量 decimal allQuantity = movementDetails.Quantity - historyPredetermineQuantity;//下架单明细剩余可预配数量 decimal occQuantity = inputItem.SendQuantity;//当前实际预配数量 if ((occQuantity) <= 0) { throw Oops.Oh("下架单" + movementDetails.MovementNo + "行号" + movementDetails.LineNumber + "物料编号" + movementDetails.MaterialCode + $"(本次预配数{occQuantity})不能小于等于0"); } if (allQuantity <= 0) { throw Oops.Oh("下架单" + movementDetails.MovementNo + "行号" + movementDetails.LineNumber + "物料编号" + movementDetails.MaterialCode + $"已全部预配"); } if (occQuantity > allQuantity) { throw Oops.Oh("下架单" + movementDetails.MovementNo + "行号" + movementDetails.LineNumber + "物料编号" + movementDetails.MaterialCode + $"本次预配数量{occQuantity}大于剩余可预配数{allQuantity}"); } // 根据物料找出库存列表中数量大于0的库存 var findStockQuanList = allStockQuanGroupList.Where(x => (x.UseQty) > 0 && x.MaterialCode == movementDetails.MaterialCode).ToList(); //寻找库存原则:按照先入先出原则 RecordInsertTime 排升序 //同一个物料尽量从同一个库位取 if (findStockQuanList.Count() <= 0) { //缺料 throw Oops.Oh("物料编号" + movementDetails.MaterialCode + $"库存数量不足,预配数量:{occQuantity},库存可用数量:0"); } var sumQty = findStockQuanList.Sum(x => x.UseQty); if (sumQty < occQuantity) { throw Oops.Oh("物料编号" + movementDetails.MaterialCode + $"库存数量不足,预配数量:{occQuantity},库存可用数量:{sumQty}"); } //处理后未下发的数量,多个同一个物料多个库存数据的情况,循环处理下发 decimal currentIssueQuantity = occQuantity; ////创建锁定库存 //var addWmsStockQuanLock = LockStroreHelper.CommonCreateWmsStockQuanLockForPredetermine(movementDetails, occQuantity); movementDetails.PredetermineQuantity += occQuantity;//累计预配数 //addWmsStockQuanLockList.Add(addWmsStockQuanLock);//添加预配锁定库存 updateWmsOrderMoveDetailsList.Add(movementDetails);//更新下架单明细 #endregion } else { addWmsRecordPredDispHistory.Remarks = "取消预配"; addWmsRecordPredDispHistory.Quantity = -inputItem.PredetermineQuantity; #region 处理取消预配 decimal historyPredetermineQuantity = movementDetails.PredetermineQuantity;//下架单的历史预配数量 decimal occQuantity = inputItem.PredetermineQuantity;//当前实际取消预配数量 if ((occQuantity) <= 0) { throw Oops.Oh("下架单" + movementDetails.MovementNo + "行号" + movementDetails.LineNumber + "物料编号" + movementDetails.MaterialCode + $"(本次取消预配数{occQuantity})不能小于等于0"); } if ((historyPredetermineQuantity - occQuantity) < 0) { throw Oops.Oh("下架单" + movementDetails.MovementNo + "行号" + movementDetails.LineNumber + "物料编号" + movementDetails.MaterialCode + $"(已预配数量{historyPredetermineQuantity}减去本次取消预配数{occQuantity})不能小于0"); } if (v_movementDetails.DispenseQuantity > (historyPredetermineQuantity - occQuantity)) { throw Oops.Oh("下架单" + movementDetails.MovementNo + "行号" + movementDetails.LineNumber + "物料编号" + movementDetails.MaterialCode + $"已分配数{v_movementDetails.DispenseQuantity}不能大于(已预配数量{historyPredetermineQuantity}减去本次取消预配数{occQuantity})"); } //处理后未下发的数量,多个同一个物料多个库存数据的情况,循环处理下发 decimal currentIssueQuantity = occQuantity; /* //查询锁定库存 List wmsStockQuanLocks = await _wmsStockQuanLockRep.GetListAsync(x => x.IsDelete == false && x.MovementNo == inputItem.MovementNo && x.MovementLineNumber == inputItem.LineNumber && x.LockType == LockTypeEnum.预配 && (x.Quantity) > 0 ); foreach (var stockQuanLock in wmsStockQuanLocks) { if (currentIssueQuantity <= 0) break; if (currentIssueQuantity <= (stockQuanLock.Quantity)) { stockQuanLock.Quantity = (stockQuanLock.Quantity) - currentIssueQuantity; if (stockQuanLock.Quantity == 0) { stockQuanLock.IsDelete = true; } } else {//本次循环不够扣 currentIssueQuantity -= (stockQuanLock.Quantity); stockQuanLock.IsDelete = true; stockQuanLock.Quantity = 0; } updateWmsStockQuanLockList.Add(stockQuanLock);//添加预配锁定库存 } //*/ movementDetails.PredetermineQuantity -= occQuantity;//累计预配数 updateWmsOrderMoveDetailsList.Add(movementDetails);//更新下架单明细 #endregion } addWmsRecordPredDispHistoryList.Add(addWmsRecordPredDispHistory); } var _tenant = _wmsOrderMovementDetailsRep.AsTenant(); try { #region 事务内执行操作 //await _wmsStockQuanLockRep.InsertRangeAsync(addWmsStockQuanLockList); /* foreach (var item in updateWmsStockQuanLockList) { if (item.IsDelete) { await _wmsStockQuanLockRep.DeleteAsync(item);//物理删除 } else { await _wmsStockQuanLockRep.UpdateAsync(item); } } //*/ await _wmsOrderMovementDetailsRep.UpdateRangeAsync(updateWmsOrderMoveDetailsList); await _wmsRecordPredDispHistoryRep.InsertRangeAsync(addWmsRecordPredDispHistoryList); #endregion await _tenant.CommitTranAsync(); } catch (Exception ex) { await _tenant.RollbackTranAsync(); throw; } return 1; } #region 私有方法 #endregion }