|
|
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;
|
/// <summary>
|
/// 容器分拣信息服务
|
/// </summary>
|
[ApiDescriptionSettings(ApplicationConst.WmsTaskGroupName, Order = 100)]
|
public class WmsPredetermineService : IDynamicApiController, ITransient
|
{
|
/// <summary>
|
/// 是否正在执行预配方法
|
/// </summary>
|
private static bool isRuning_Fun_Predetermine = false;
|
private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
|
|
private readonly SqlSugarRepository<WmsContainerSort> _wmsContainerSortRep;
|
private readonly SqlSugarRepository<v_wms_stock_quan> _v_wms_stock_quanRep;
|
private readonly SqlSugarRepository<WmsOrderSortDetails> _wmsOrderSortDetailsRep;
|
//private readonly SqlSugarRepository<WmsStockQuanLock> _wmsStockQuanLockRep;
|
private readonly SqlSugarRepository<WmsOrderSort> _wmsOrderSortRep;
|
private readonly SqlSugarRepository<WmsOrderMovementDetails> _wmsOrderMovementDetailsRep;
|
private readonly SqlSugarRepository<V_WmsOrderMovementDetails> _v_wmsOrderMovementDetailsRep;
|
private readonly SqlSugarRepository<WmsOrderMovement> _wmsOrderMovementRep;
|
private readonly SqlSugarRepository<WmsTask> _wmsTaskRep;
|
private readonly SqlSugarRepository<WmsRecordPredDispHistory> _wmsRecordPredDispHistoryRep;
|
private readonly SqlSugarRepository<v_wms_stock_quan_group> _v_wms_stock_quan_use_groupRep;
|
|
|
|
public WmsPredetermineService(
|
SqlSugarRepository<V_WmsOrderMovementDetails> v_wmsOrderMovementDetailsRep,
|
SqlSugarRepository<WmsContainerSort> wmsContainerSortRep,
|
SqlSugarRepository<v_wms_stock_quan> v_wms_stock_quanRep,
|
//SqlSugarRepository<WmsStockQuanLock> wmsStockQuanLockRep,
|
SqlSugarRepository<WmsOrderSortDetails> wmsOrderSortDetailsRep,
|
SqlSugarRepository<WmsOrderSort> wmsOrderSortRep,
|
SqlSugarRepository<WmsOrderMovementDetails> wmsOrderMovementDetailsRep,
|
SqlSugarRepository<WmsOrderMovement> wmsOrderMovementRep,
|
SqlSugarRepository<WmsTask> wmsTaskRep,
|
SqlSugarRepository<WmsRecordPredDispHistory> wmsRecordPredDispHistoryRep,
|
SqlSugarRepository<v_wms_stock_quan_group> 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;
|
}
|
|
|
|
|
|
|
/// <summary>
|
/// 预配
|
/// </summary>
|
/// <param name="input"></param>
|
/// <returns></returns>
|
[HttpPost]
|
[ApiDescriptionSettings(Name = "Predetermine")]
|
[Description("WmsPredetermine/Predetermine")]
|
public async Task<int> Predetermine(List<PredetermineInput> 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;
|
}
|
}
|
|
|
/// <summary>
|
/// 取消预配
|
/// </summary>
|
/// <param name="input"></param>
|
/// <returns></returns>
|
[HttpPost]
|
[ApiDescriptionSettings(Name = "CancelPredetermine")]
|
[Description("WmsPredetermine/CancelPredetermine")]
|
public async Task<int> CancelPredetermine(List<PredetermineInput> 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;
|
}
|
}
|
|
|
|
/// <summary>
|
/// 预配/取消预配
|
/// </summary>
|
/// <param name="input"></param>
|
/// <param name="isCancel"></param>
|
/// <returns></returns>
|
private async Task<int> PredetermineFaction(List<PredetermineInput> input, bool isCancel = false)
|
{
|
|
/**
|
* 获取预配物料库存信息
|
* 获取当前预配锁定库存信息
|
* 校验可用库存-历史预配锁定库存 是否满足预配
|
* 新增预配锁定库存
|
* 修改下架单明细预配数
|
* 新增事务
|
* 新增操作日期
|
*/
|
|
List<WmsRecordPredDispHistory> addWmsRecordPredDispHistoryList = new List<WmsRecordPredDispHistory>();//新增的预配历史记录
|
//var addWmsStockQuanLockList = new List<WmsStockQuanLock>();//新增的锁定库存信息
|
//var updateWmsStockQuanLockList = new List<WmsStockQuanLock>();//更新的锁定库存信息
|
var updateWmsOrderMoveDetailsList = new List<WmsOrderMovementDetails>();//修改的移动单明细
|
//var updateWmsOrderMoveList = new List<WmsOrderMovement>();//修改的移动单
|
|
List<string> 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<string> materialCodeList = input.Select(x => x.MaterialCode).Distinct().ToList();
|
|
List<v_wms_stock_quan_group> 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<WmsStockQuanLock> 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
|
|
|
|
|
}
|