|
|
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 AngleSharp.Dom;
|
using Admin.NET.Application.CommonHelper;
|
namespace Admin.NET.Application;
|
/// <summary>
|
/// 下架单分配服务
|
/// </summary>
|
[ApiDescriptionSettings(ApplicationConst.WmsTaskGroupName, Order = 100)]
|
public class WmsDispenseService : IDynamicApiController, ITransient
|
{
|
/// <summary>
|
/// 是否正在执行分配方法
|
/// </summary>
|
private static bool isRuning_Fun_Dispense = false;
|
/// <summary>
|
/// 是否正在执行修改分配方法
|
/// </summary>
|
private static bool isRuning_Fun_UpdateDispense = false;
|
|
private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
|
private static SemaphoreSlim semaphoreSlimForUpdate = new SemaphoreSlim(1, 1);
|
|
private readonly SqlSugarRepository<WmsContainerSort> _wmsContainerSortRep;
|
private readonly SqlSugarRepository<v_wms_stock_quan> _v_wms_stock_quanRep;
|
private readonly SqlSugarRepository<v_wms_stock_quan_for_use> _v_wms_stock_quan_for_useRep;
|
|
private readonly SqlSugarRepository<WmsOrderSortDetails> _wmsOrderSortDetailsRep;
|
//private readonly SqlSugarRepository<WmsStockQuanLock> _wmsStockQuanLockRep;
|
private readonly SqlSugarRepository<WmsOrderSort> _wmsOrderSortRep;
|
private readonly SqlSugarRepository<WmsOrderMovementDetails> _wmsOrderMovementDetailsRep;
|
private readonly SqlSugarRepository<WmsOrderMovement> _wmsOrderMovementRep;
|
private readonly SqlSugarRepository<WmsTask> _wmsTaskRep;
|
private readonly SqlSugarRepository<WmsRecordPredetermineDispense> _wmsRecordPredetermineDispenseRep;
|
private readonly SqlSugarRepository<WmsRecordPredDispHistory> _wmsRecordPredDispHistoryRep;
|
private readonly SqlSugarRepository<V_WmsOrderMovementDetails> _v_wmsOrderMovementDetailsRep;
|
|
|
|
public WmsDispenseService(
|
SqlSugarRepository<WmsRecordPredDispHistory> wmsRecordPredDispHistoryRep,
|
SqlSugarRepository<V_WmsOrderMovementDetails> v_wmsOrderMovementDetailsRep,
|
SqlSugarRepository<WmsContainerSort> wmsContainerSortRep,
|
SqlSugarRepository<v_wms_stock_quan> v_wms_stock_quanRep,
|
SqlSugarRepository<v_wms_stock_quan_for_use> v_wms_stock_quan_for_useRep,
|
//SqlSugarRepository<WmsStockQuanLock> wmsStockQuanLockRep,
|
SqlSugarRepository<WmsOrderSortDetails> wmsOrderSortDetailsRep,
|
SqlSugarRepository<WmsOrderSort> wmsOrderSortRep,
|
SqlSugarRepository<WmsOrderMovementDetails> wmsOrderMovementDetailsRep,
|
SqlSugarRepository<WmsOrderMovement> wmsOrderMovementRep,
|
SqlSugarRepository<WmsTask> wmsTaskRep,
|
SqlSugarRepository<WmsRecordPredetermineDispense> wmsRecordPredetermineDispenseRep)
|
{
|
_wmsRecordPredDispHistoryRep = wmsRecordPredDispHistoryRep;
|
_v_wmsOrderMovementDetailsRep = v_wmsOrderMovementDetailsRep;
|
_wmsContainerSortRep = wmsContainerSortRep;
|
_v_wms_stock_quanRep = v_wms_stock_quanRep;
|
_v_wms_stock_quan_for_useRep = v_wms_stock_quan_for_useRep;
|
|
//_wmsStockQuanLockRep = wmsStockQuanLockRep;
|
_wmsOrderSortDetailsRep = wmsOrderSortDetailsRep;
|
_wmsOrderSortRep = wmsOrderSortRep;
|
_wmsOrderMovementDetailsRep = wmsOrderMovementDetailsRep;
|
_wmsOrderMovementRep = wmsOrderMovementRep;
|
_wmsTaskRep = wmsTaskRep;
|
_wmsRecordPredetermineDispenseRep = wmsRecordPredetermineDispenseRep;
|
}
|
|
|
|
/// <summary>
|
/// 自动分配
|
/// </summary>
|
/// <param name="input"></param>
|
/// <returns></returns>
|
[HttpPost]
|
[ApiDescriptionSettings(Name = "Dispense")]
|
[Description("WmsDispense/Dispense")]
|
public async Task<int> Dispense(List<DispenseInput> input)
|
{
|
try
|
{
|
if (isRuning_Fun_Dispense)
|
{
|
throw Oops.Oh("程序正忙,请稍后再试");
|
}
|
await semaphoreSlim.WaitAsync();
|
|
isRuning_Fun_Dispense = true;
|
|
return await DispenseFaction(input);
|
|
}
|
catch (Exception ex)
|
{
|
throw Oops.Oh(ex.Message);
|
}
|
finally
|
{
|
semaphoreSlim.Release();
|
isRuning_Fun_Dispense = false;
|
}
|
}
|
|
/// <summary>
|
/// 取消分配
|
/// </summary>
|
/// <param name="input"></param>
|
/// <returns></returns>
|
[HttpPost]
|
[ApiDescriptionSettings(Name = "CancelDispenseForRecord")]
|
[Description("WmsDispense/CancelDispenseForRecord")]
|
public async Task<int> CancelDispenseForRecord(CancelDispenseInput input)
|
{
|
try
|
{
|
if (isRuning_Fun_Dispense)
|
{
|
throw Oops.Oh("程序正忙,请稍后再试");
|
}
|
await semaphoreSlim.WaitAsync();
|
|
isRuning_Fun_Dispense = true;
|
|
return await CancelDispenseForRecordFaction(input);
|
|
}
|
catch (Exception ex)
|
{
|
throw Oops.Oh(ex.Message);
|
}
|
finally
|
{
|
semaphoreSlim.Release();
|
isRuning_Fun_Dispense = false;
|
}
|
}
|
|
|
/// <summary>
|
/// 修改分配
|
/// </summary>
|
/// <param name="input"></param>
|
/// <returns></returns>
|
[HttpPost]
|
[ApiDescriptionSettings(Name = "UpdateDispense")]
|
[Description("WmsDispense/UpdateDispense")]
|
public async Task<int> UpdateDispense(UpdateDispenseInput input)
|
{
|
throw Oops.Oh("此方法已废弃");
|
/*
|
try
|
{
|
if (isRuning_Fun_UpdateDispense)
|
{
|
throw Oops.Oh("程序正忙,请稍后再试");
|
}
|
await semaphoreSlimForUpdate.WaitAsync();
|
|
isRuning_Fun_UpdateDispense = true;
|
|
return await UpdateDispenseFaction(input);
|
|
}
|
catch (Exception ex)
|
{
|
throw Oops.Oh(ex.Message);
|
}
|
finally
|
{
|
semaphoreSlimForUpdate.Release();
|
isRuning_Fun_UpdateDispense = false;
|
}
|
//*/
|
}
|
|
|
|
#region 私有方法
|
|
|
/// <summary>
|
/// 自动分配/指定库存分配
|
/// </summary>
|
/// <param name="input"></param>
|
/// <returns></returns>
|
private async Task<int> DispenseFaction(List<DispenseInput> input)
|
{
|
|
/**
|
* 获取分配物料库存信息
|
* 获取当前分配锁定库存信息
|
* 校验可用库存-历史分配锁定库存 是否满足分配
|
* 新增分配锁定库存
|
* 修改下架单明细分配数
|
* 新增事务
|
* 新增操作日期
|
*/
|
|
if (input.First().Flag != 1 && input.First().Flag != 2)
|
{
|
throw Oops.Oh("分配标记不正确");
|
}
|
bool isHandFlag = false;
|
if (input.First().Flag == 2)
|
{
|
isHandFlag = true;
|
//明细不能为空
|
foreach (var item in input)
|
{
|
if (item.dispenseDetailsForHand?.Count <= 0)
|
{
|
throw Oops.Oh("下架单" + item.MovementNo + "行号" + item.LineNumber + "物料编号" + item.MaterialCode + $"分配的明细不能为空");
|
}
|
item.SendQuantity = item.dispenseDetailsForHand.Sum(x => x.DispenseQuantity);
|
}
|
}
|
|
//var addWmsStockQuanLockList = new List<WmsStockQuanLock>();//新增的锁定库存信息
|
//var updateWmsStockQuanLockList = new List<WmsStockQuanLock>();//修改的锁定库存信息
|
|
|
var updateWmsOrderMoveDetailsList = new List<WmsOrderMovementDetails>();//修改的移动单明细
|
var updateWmsOrderMoveList = new List<WmsOrderMovement>();//修改的移动单
|
var addWmsRecordPredetermineDispenseList = new List<WmsRecordPredetermineDispense>();
|
|
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();
|
|
|
//获取本次操作的下架单和下架单明细
|
|
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));
|
|
|
|
////根据物料编码获取物料跟踪码的可用库存信息-已排除掉分配、下发锁定库存
|
var allStockQuanUseList = await _v_wms_stock_quan_for_useRep.GetListAsync(x => materialCodeList.Contains(x.MaterialCode));
|
|
|
//获取下架单明细的物料预配锁定库存
|
//var allDetailsPredetermineList = await _wmsStockQuanLockRep.GetListAsync(x => x.LockType == LockTypeEnum.预配 && x.IsDelete == false);
|
var allDetailsPredetermineList = await LockStroreHelper.GetPreListAsync(materialCodeList, _wmsOrderMovementDetailsRep);
|
|
|
|
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("本次分配的下架单明细不存在");
|
}
|
|
if (!isHandFlag)
|
{
|
#region 处理自动分配
|
decimal historyDispenseQuantity = v_movementDetails.DispenseQuantity;//下架单的历史分配数量
|
|
decimal allQuantity = movementDetails.Quantity - historyDispenseQuantity;//下架单明细剩余可分配数量
|
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的库存
|
List<string> querySNList = new List<string>();
|
if (isHandFlag)
|
{
|
querySNList = inputItem.dispenseDetailsForHand.Select(x => x.SNCode).ToList();
|
}
|
var findStockQuanList = allStockQuanUseList.Where(x => x.AvailableQty > 0 && x.MaterialCode == movementDetails.MaterialCode)
|
.WhereIF(querySNList.Count > 0, x => querySNList.Contains(x.SNCode)) // 支持 手动分配的情况 【Editby shaocx,2024-07-12】
|
.OrderBy(x => x.ContainerCode).ThenBy(x => x.PlaceCode).ThenBy(x => x.RecordInsertTime).ToList();
|
if (findStockQuanList?.Count == 0)
|
{
|
throw Oops.Oh("下架单" + movementDetails.MovementNo + "行号" + movementDetails.LineNumber + "物料编号" + movementDetails.MaterialCode + $"没有找到可分配的库存");
|
}
|
|
//寻找库存原则:按照先入先出原则 RecordInsertTime 排升序
|
|
//物料跟踪码可用库存-没有排除预配锁定库存
|
var sumQty = findStockQuanList.Sum(x => x.AvailableQty);
|
|
|
var itemMovementDetailsKey = inputItem.MovementNo + inputItem.LineNumber;
|
|
//获取当前下架单明细的物料预配锁定库存
|
var currentDetailsPredetermine = allDetailsPredetermineList.Where(x => itemMovementDetailsKey.Equals(x.MovementNo + x.LineNumber)).ToList();
|
|
//获取其他下架单明细的物料预配锁定库存
|
var otherDetailsPredetermineList = allDetailsPredetermineList.Where(x => !itemMovementDetailsKey.Equals(x.MovementNo + x.LineNumber)).ToList();
|
//其他单据预配锁定库存
|
var orherPredetermineQty = otherDetailsPredetermineList.Sum(u => u.Quantity);
|
orherPredetermineQty = orherPredetermineQty < 0 ? 0 : orherPredetermineQty;
|
|
//当前可分配库存要排除掉其他单据预配锁定库存
|
if (sumQty < occQuantity - orherPredetermineQty)
|
{
|
throw Oops.Oh("物料编号" + movementDetails.MaterialCode + $"库存数量不足,分配数量:{occQuantity},库存可用数量:{sumQty}");
|
}
|
|
//处理后未分配的数量,多个同一个物料多个库存数据的情况,循环处理下发
|
decimal currentDispenseQuantity = occQuantity;
|
decimal changeQty = 0;//本次变更数量
|
|
List<string> snCodeList = new List<string>();//下发的库存SNCode,存在使用多个情况
|
foreach (var stockQuanItem in findStockQuanList)
|
{
|
if (currentDispenseQuantity > 0)
|
{
|
//当前物料波次锁定库存
|
var currentStockQuanLockQty = findStockQuanList.Where(x => x.SNCode == stockQuanItem.SNCode)
|
.Sum(x => x.Quantity);
|
//当前物料可用库存
|
var currentUsedQuantity = stockQuanItem.AvailableQty;
|
|
//循环库存信息 处理下发数
|
if (currentUsedQuantity >= currentDispenseQuantity)//分配数量小于等于库存
|
{
|
changeQty = currentDispenseQuantity;
|
currentDispenseQuantity = 0;//全部分配,不在处理
|
}
|
else
|
{
|
changeQty = currentUsedQuantity;
|
//当前分配数未能完全分配,累计分配数
|
currentDispenseQuantity = currentDispenseQuantity - currentUsedQuantity;
|
}
|
//累计使用的库存跟踪码
|
snCodeList.Add(stockQuanItem.SNCode);
|
|
|
//创建分配记录
|
var addWmsRecordPredetermineDispense = CommonCreateWmsRecordPredetermineDispense(movementDetails, changeQty, stockQuanItem);
|
|
|
addWmsRecordPredetermineDispenseList.Add(addWmsRecordPredetermineDispense);
|
|
|
if (currentDispenseQuantity == 0)
|
{
|
break;
|
}
|
|
|
}
|
else
|
{
|
break;
|
}
|
|
}
|
if (currentDispenseQuantity > 0)
|
{
|
throw Oops.Oh("下架单" + movementDetails.MovementNo + "行号" + movementDetails.LineNumber + "物料编号" + movementDetails.MaterialCode + $"(本次需求分配数{occQuantity}),还剩余{currentDispenseQuantity}未分配");
|
}
|
|
v_movementDetails.DispenseQuantity += occQuantity;//累计分配数
|
|
/*
|
//处理当前下架单明细实际使用的预配锁定库存
|
//根据分配数扣减预配锁定库存的锁定使用数
|
decimal currentPredetermineLockQty = occQuantity;
|
if (currentDetailsPredetermine?.Count == 0)
|
{
|
////创建锁定库存
|
var addWmsStockQuanLock = LockStroreHelper.CommonCreateWmsStockQuanLockForPredetermine(movementDetails, occQuantity);
|
addWmsStockQuanLockList.Add(addWmsStockQuanLock);
|
}
|
else
|
{
|
currentDetailsPredetermine.First().Quantity += occQuantity;
|
updateWmsStockQuanLockList.Add(currentDetailsPredetermine.First());
|
}
|
//*/
|
|
//预配数等于分配数
|
|
if (movementDetails.PredetermineQuantity < v_movementDetails.DispenseQuantity)
|
{
|
movementDetails.PredetermineQuantity = v_movementDetails.DispenseQuantity;
|
}
|
|
|
movementOrder.IsDispense = true;//标记为已分配
|
updateWmsOrderMoveList.Add(movementOrder);//更新下架单
|
updateWmsOrderMoveDetailsList.Add(movementDetails);//更新下架单明细
|
#endregion
|
}
|
else
|
{
|
#region 处理指定库存分配
|
decimal historyDispenseQuantity = v_movementDetails.DispenseQuantity;//下架单的历史分配数量
|
|
decimal allQuantity = movementDetails.Quantity - historyDispenseQuantity;//下架单明细剩余可分配数量
|
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的库存
|
List<string> querySNList = new List<string>();
|
if (isHandFlag)
|
{
|
querySNList = inputItem.dispenseDetailsForHand.Select(x => x.SNCode).ToList();
|
}
|
var findStockQuanList = allStockQuanUseList.Where(x => x.AvailableQty > 0 && x.MaterialCode == movementDetails.MaterialCode)
|
.WhereIF(querySNList.Count > 0, x => querySNList.Contains(x.SNCode)) // 支持 手动分配的情况 【Editby shaocx,2024-07-12】
|
.OrderBy(x => x.ContainerCode).ThenBy(x => x.PlaceCode).ThenBy(x => x.RecordInsertTime).ToList();
|
if (findStockQuanList?.Count == 0)
|
{
|
throw Oops.Oh("下架单" + movementDetails.MovementNo + "行号" + movementDetails.LineNumber + "物料编号" + movementDetails.MaterialCode + $"没有找到可分配的库存");
|
}
|
if (findStockQuanList.Count != inputItem.dispenseDetailsForHand.Count)
|
{
|
throw Oops.Oh("下架单" + movementDetails.MovementNo + "行号" + movementDetails.LineNumber + "物料编号" + movementDetails.MaterialCode + $",寻找的库存条数{findStockQuanList.Count}不等于预期处理条数{inputItem.dispenseDetailsForHand.Count}");
|
}
|
|
|
//物料跟踪码可用库存-没有排除预配锁定库存
|
var sumQty = findStockQuanList.Sum(x => x.AvailableQty);
|
|
|
var itemMovementDetailsKey = inputItem.MovementNo + inputItem.LineNumber;
|
|
//获取当前下架单明细的物料预配锁定库存
|
var currentDetailsPredetermine = allDetailsPredetermineList.Where(x => itemMovementDetailsKey.Equals(x.MovementNo + x.LineNumber)).ToList();
|
|
//获取其他下架单明细的物料预配锁定库存
|
var otherDetailsPredetermineList = allDetailsPredetermineList.Where(x => !itemMovementDetailsKey.Equals(x.MovementNo + x.LineNumber)).ToList();
|
//其他单据预配锁定库存
|
var orherPredetermineQty = otherDetailsPredetermineList.Sum(u => u.Quantity);
|
orherPredetermineQty = orherPredetermineQty < 0 ? 0 : orherPredetermineQty;
|
|
//当前可分配库存要排除掉其他单据预配锁定库存
|
if (sumQty < occQuantity - orherPredetermineQty)
|
{
|
throw Oops.Oh("物料编号" + movementDetails.MaterialCode + $"库存数量不足,分配数量:{occQuantity},库存可用数量:{sumQty}");
|
}
|
|
|
|
|
|
foreach (var stockQuanItem in findStockQuanList)
|
{//这里的每次循环就是处理 每个指定库存的数据
|
|
var singleDispenseDetailsItem = inputItem.dispenseDetailsForHand.Where(x => x.SNCode == stockQuanItem.SNCode).FirstOrDefault();
|
|
decimal currentDispenseQuantity = singleDispenseDetailsItem.DispenseQuantity;
|
|
//当前物料波次锁定库存
|
var currentStockQuanLockQty = findStockQuanList.Where(x => x.SNCode == stockQuanItem.SNCode)
|
.Sum(x => x.Quantity);
|
//当前物料可用库存
|
var currentUsedQuantity = stockQuanItem.AvailableQty;
|
|
//循环库存信息 处理下发数
|
if (currentUsedQuantity >= currentDispenseQuantity)//分配数量小于等于库存
|
{//正常
|
|
}
|
else
|
{
|
throw Oops.Oh("物料编号" + movementDetails.MaterialCode + $"计算库存数量不足,分配数量:{currentDispenseQuantity},库存可用数量:{currentUsedQuantity}");
|
}
|
|
|
|
//创建分配记录
|
var addWmsRecordPredetermineDispense = CommonCreateWmsRecordPredetermineDispense(movementDetails, currentDispenseQuantity, stockQuanItem);
|
|
|
addWmsRecordPredetermineDispenseList.Add(addWmsRecordPredetermineDispense);
|
|
|
|
}
|
|
|
v_movementDetails.DispenseQuantity += occQuantity;//累计分配数
|
|
/*
|
//处理当前下架单明细实际使用的预配锁定库存
|
//根据分配数扣减预配锁定库存的锁定使用数
|
decimal currentPredetermineLockQty = occQuantity;
|
if (currentDetailsPredetermine?.Count == 0)
|
{
|
////创建锁定库存
|
var addWmsStockQuanLock = LockStroreHelper.CommonCreateWmsStockQuanLockForPredetermine(movementDetails, occQuantity);
|
addWmsStockQuanLockList.Add(addWmsStockQuanLock);
|
}
|
else
|
{
|
currentDetailsPredetermine.First().Quantity += occQuantity;
|
updateWmsStockQuanLockList.Add(currentDetailsPredetermine.First());
|
}
|
//*/
|
|
//预配数等于分配数
|
|
if (movementDetails.PredetermineQuantity < v_movementDetails.DispenseQuantity)
|
{
|
movementDetails.PredetermineQuantity = v_movementDetails.DispenseQuantity;
|
}
|
|
|
movementOrder.IsDispense = true;//标记为已分配
|
updateWmsOrderMoveList.Add(movementOrder);//更新下架单
|
updateWmsOrderMoveDetailsList.Add(movementDetails);//更新下架单明细
|
#endregion
|
}
|
}
|
|
//处理分配历史表
|
List<WmsRecordPredDispHistory> addWmsRecordPredDispHistoryList = addWmsRecordPredetermineDispenseList.Adapt<List<WmsRecordPredDispHistory>>();
|
foreach (var item in addWmsRecordPredDispHistoryList)
|
{
|
item.Remarks = "分配操作";
|
}
|
|
var _tenant = _wmsOrderMovementDetailsRep.AsTenant();
|
|
try
|
{
|
#region 事务内执行操作
|
|
//await _wmsStockQuanLockRep.InsertRangeAsync(addWmsStockQuanLockList);
|
//await _wmsStockQuanLockRep.UpdateRangeAsync(updateWmsStockQuanLockList);
|
|
|
await _wmsOrderMovementDetailsRep.UpdateRangeAsync(updateWmsOrderMoveDetailsList);
|
await _wmsOrderMovementRep.UpdateRangeAsync(updateWmsOrderMoveList);
|
await _wmsRecordPredetermineDispenseRep.InsertRangeAsync(addWmsRecordPredetermineDispenseList);
|
await _wmsRecordPredDispHistoryRep.InsertRangeAsync(addWmsRecordPredDispHistoryList);
|
#endregion
|
|
await _tenant.CommitTranAsync();
|
}
|
catch (Exception ex)
|
{
|
|
await _tenant.RollbackTranAsync();
|
throw;
|
}
|
|
|
|
|
|
|
|
|
return 1;
|
}
|
|
|
|
/// <summary>
|
/// 取消分配
|
/// </summary>
|
/// <param name="input"></param>
|
/// <returns></returns>
|
private async Task<int> CancelDispenseForRecordFaction(CancelDispenseInput input)
|
{
|
|
//var addWmsStockQuanLockList = new List<WmsStockQuanLock>();//新增的锁定库存信息
|
|
List<v_wms_stock_quan_for_use> allStockQuanUseList = new List<v_wms_stock_quan_for_use>();//选择分配的可用库存信息
|
|
|
//获取当前修改的分配记录
|
List<WmsRecordPredetermineDispense> updateRecordList = await _wmsRecordPredetermineDispenseRep.GetListAsync(u => u.MovementNo == input.MovementNo);
|
|
WmsRecordPredetermineDispense updateRecord = updateRecordList.FirstOrDefault(u => u.Id == input.Id);
|
if (updateRecord == null)
|
{
|
throw Oops.Oh($"下架单{updateRecord.MovementNo}不存在");
|
}
|
|
#region 处理旧的的分配
|
|
|
//取消要修改的分配记录
|
updateRecord.PDRecordStatus = PDRecordStatusEnum.已取消;
|
updateRecord.PDRecordStatusName = PDRecordStatusEnum.已取消.GetDescription();
|
updateRecord.Remarks = "取消分配";
|
|
|
|
#endregion
|
|
WmsOrderMovementDetails movementDetails = await _wmsOrderMovementDetailsRep.AsQueryable().FirstAsync(p => p.MovementNo == updateRecord.MovementNo && p.LineNumber == updateRecord.MovementLineNumber);
|
if (movementDetails == null)
|
{
|
throw Oops.Oh($"下架单{updateRecord.MovementNo}的行号{updateRecord.MovementLineNumber}不存在");
|
}
|
V_WmsOrderMovementDetails v_movementDetails = await _v_wmsOrderMovementDetailsRep.AsQueryable().FirstAsync(p => p.MovementNo == updateRecord.MovementNo && p.LineNumber == updateRecord.MovementLineNumber);
|
if (v_movementDetails == null)
|
{
|
throw Oops.Oh($"下架单{updateRecord.MovementNo}的行号{updateRecord.MovementLineNumber}不存在");
|
}
|
v_movementDetails.DispenseQuantity -= updateRecord.Quantity;
|
if (v_movementDetails.DispenseQuantity < 0)
|
{
|
throw Oops.Oh($"下架单{updateRecord.MovementNo}的行号{updateRecord.MovementLineNumber}的已分配数量{v_movementDetails.DispenseQuantity}不能小于要取消的分配数量{updateRecord.Quantity}");
|
}
|
|
WmsOrderMovement movementOrder = await _wmsOrderMovementRep.AsQueryable().FirstAsync(p => p.OrderNo == updateRecord.MovementNo);
|
if (movementOrder == null)
|
{
|
throw Oops.Oh($"下架单{updateRecord.MovementNo}不存在");
|
}
|
//判断如果没有任何分配记录了,就更新状态
|
if (updateRecordList.Where(x => x.PDRecordStatus == PDRecordStatusEnum.已分配).Count() > 0)
|
{
|
|
}
|
else
|
{
|
movementOrder.IsDispense = false;//标记为未分配
|
}
|
|
|
//处理分配历史表
|
WmsRecordPredDispHistory addWmsRecordPredDispHistory = updateRecord.Adapt<WmsRecordPredDispHistory>();
|
addWmsRecordPredDispHistory.Id = Yitter.IdGenerator.YitIdHelper.NextId();
|
addWmsRecordPredDispHistory.Quantity = -addWmsRecordPredDispHistory.Quantity;
|
addWmsRecordPredDispHistory.Remarks = "取消分配";
|
|
|
var _tenant = _wmsOrderMovementRep.AsTenant();
|
|
try
|
{
|
#region 事务内执行操作
|
|
await _wmsOrderMovementRep.UpdateAsync(movementOrder);
|
await _wmsOrderMovementDetailsRep.UpdateAsync(movementDetails);
|
|
//await _wmsStockQuanLockRep.InsertRangeAsync(addWmsStockQuanLockList);
|
|
await _wmsRecordPredetermineDispenseRep.UpdateAsync(updateRecord);
|
|
await _wmsRecordPredDispHistoryRep.InsertAsync(addWmsRecordPredDispHistory);
|
#endregion
|
|
await _tenant.CommitTranAsync();
|
}
|
catch (Exception ex)
|
{
|
|
await _tenant.RollbackTranAsync();
|
throw;
|
}
|
|
|
|
|
|
|
|
|
return 1;
|
}
|
|
|
|
/// <summary>
|
/// 修改分配 验证分配操作入参
|
/// </summary>
|
/// <param name="input"></param>
|
/// <param name="allStockQuanUseList"></param>
|
/// <param name="updateRecord"></param>
|
/// <returns></returns>
|
|
private async Task<WmsRecordPredetermineDispense> ValidateInput(UpdateDispenseInput input, List<v_wms_stock_quan_for_use> allStockQuanUseList)
|
{
|
|
//一次只能编辑一个分配记录
|
|
if (string.IsNullOrWhiteSpace(input.SNCode))
|
{
|
throw Oops.Oh("分配的库存跟踪码不能为空");
|
}
|
|
|
if (input.Id <= 0)
|
{
|
|
throw Oops.Oh("要修改的分配记录不能为空");
|
}
|
//获取当前修改的分配记录
|
WmsRecordPredetermineDispense updateRecord = await _wmsRecordPredetermineDispenseRep.GetFirstAsync(u => u.Id == input.Id);
|
|
if (updateRecord == null)
|
{
|
throw Oops.Oh("分配记录不存在");
|
}
|
|
|
//TODO 暂不支持修改分配数
|
//if (input.SendQuantity <= 0)
|
//{
|
// throw Oops.Oh("修改后的分配数量必须大于0");
|
//}
|
|
|
// 查找物料库存
|
List<string> snCodeList = ParamHelper.GetStringParamToList(input.SNCode);
|
|
|
if (updateRecord.PDRecordStatus != PDRecordStatusEnum.已分配)
|
{
|
throw Oops.Oh($"分配记录状态是{updateRecord.PDRecordStatus.GetDescription()}");
|
}
|
|
//根据物料编码获取物料跟踪码的可用库存信息)
|
var stockQuanUseList = await _v_wms_stock_quan_for_useRep.GetListAsync(x => snCodeList.Contains(x.SNCode));
|
if (stockQuanUseList?.Count <= 0)
|
{
|
throw Oops.Oh("修改分配的库存跟踪码未获取到可用库存");
|
}
|
|
allStockQuanUseList.AddRange(stockQuanUseList);
|
return updateRecord;
|
}
|
|
|
|
|
|
///// <summary>
|
///// 移动单分配
|
///// </summary>
|
///// <param name="input"></param>
|
///// <returns></returns>
|
//private async Task<int> LockMovePredetermine(List<WmsOrderMovePredetermineInput> input)
|
//{
|
|
|
|
// var addWmsStockQuanLockList = new List<WmsStockQuanLock>();//新增的锁定库存信息
|
// var updateWmsOrderMoveDetailsList = new List<WmsOrderMovementDetails>();//修改的移动单明细
|
// var updateWmsOrderMoveList = new List<WmsOrderMovement>();//修改的移动单
|
// //TODO 添加事务记录
|
|
// List<string> sortNoList = input.Select(x => x.movementNo).ToList();
|
// // 获取所有波次单
|
|
// //Expression<Func<WmsOrderSort, bool>> predicate = u => sortNoList.Contains(u.SortNo);
|
// var allWmsOrderSortList = await _wmsOrderMovementRep.GetListAsync(u => sortNoList.Contains(u.OrderNo));
|
// if (allWmsOrderSortList?.Count <= 0)
|
// {
|
// throw Oops.Oh("下架单不存在");
|
// }
|
|
// //获取波次单所有明细
|
// var allOrderSortDetails = await _wmsOrderMovementDetailsRep.GetListAsync(u => sortNoList.Contains(u.MovementNo));
|
// if (allOrderSortDetails?.Count <= 0)
|
// {
|
// throw Oops.Oh("下架单明细不存在");
|
// }
|
|
// //本次下发波次单明细
|
// var currentOrderSortDetails = allOrderSortDetails.Where(u => input.Select(x => x.Id).Contains(u.Id)).ToList();
|
// if (currentOrderSortDetails?.Count <= 0)
|
// {
|
// throw Oops.Oh("本次操作的下架单明细不存在");
|
// }
|
|
|
// // 查找物料库存
|
// List<string> materialCodeList = currentOrderSortDetails.Select(x => x.MaterialCode).Distinct().ToList();
|
|
// //获取可操作下发的库存信息-(未排除锁定库存)库存状态已上架、质检状态合格、非虚拟库位
|
// var queryParam = ExpressionHelper.GetStockQuanForIssueOutTask();
|
// queryParam.And(x => materialCodeList.Contains(x.MaterialCode));
|
// var allStockQuanList = await _v_wms_stock_quanRep.GetListAsync(queryParam);
|
// if (allStockQuanList?.Count <= 0)
|
// {
|
// throw Oops.Oh("所有物料都没有库存");
|
// }
|
|
// //获取所有物料锁定库存
|
// var allStockQuanLockList = await _wmsStockQuanLockRep.GetListAsync(x => materialCodeList.Contains(x.MaterialCode));
|
// //波次下发物料锁定库存
|
// var allStockQuanLockForSortList = allStockQuanLockList.Where(x => x.LockType == LockTypeEnum.分配 && x.IsDelete == false).ToList();
|
// //TODO 分配分配锁定库存
|
|
// var movementDetailsKeyList = currentOrderSortDetails.Select(x => x.RelationNo + x.RelationNoLineNumber).ToList();
|
// var movementDetailsList = await _wmsOrderMovementDetailsRep.GetListAsync(x => movementDetailsKeyList.Contains(x.MovementNo + x.LineNumber));
|
// var queryOrderIds = movementDetailsList.Select(x => x.MovementId).Distinct().ToList();
|
// var orderMovementList = await _wmsOrderMovementRep.GetListAsync(x => queryOrderIds.Contains(x.Id));
|
|
// foreach (var inputItem in input)
|
// {
|
// var item = currentOrderSortDetails.FirstOrDefault(x => x.Id == inputItem.Id);
|
|
// WmsOrderMovement movementOrder = orderMovementList.FirstOrDefault(p => p.OrderNo == item.MovementNo);
|
// if (movementOrder == null)
|
// {
|
// throw Oops.Oh("本次分配的下架单不存在");
|
// }
|
// //TODO 校验下架单状态
|
// var sortMovementDetails = movementDetailsList.FirstOrDefault(f => f.MovementNo == item.RelationNo && f.LineNumber == item.RelationNoLineNumber);
|
// if (sortMovementDetails == null)
|
// {
|
// throw Oops.Oh("本次分配的下架单明细不存在");
|
// }
|
// #region 处理下发
|
// decimal issueQuantity = item.PredetermineQuantity ;//下架单的历史分配数量
|
|
// decimal allQuantity = item.Quantity - issueQuantity;//当前未下发数量
|
// decimal occQuantity = inputItem.SendQuantity;//当前实际下发数量
|
// if (allQuantity <= 0)
|
// {
|
// throw Oops.Oh("下架单" + item.MovementNo + "行号" + item.LineNumber + "物料编号" + item.MaterialCode + $"已全部分配");
|
// }
|
// if (occQuantity > allQuantity)
|
// {
|
// throw Oops.Oh("下架单" + item.MovementNo + "行号" + item.LineNumber + "物料编号" + item.MaterialCode + $"本次分配需求数量{occQuantity}大于未分配数{allQuantity}");
|
// }
|
|
// // 根据物料找出库存列表中数量大于0的库存
|
// var findStockQuanList = allStockQuanList.Where(x => (x.Quantity) > 0 && x.MaterialCode == item.MaterialCode)
|
// .OrderBy(x => x.ContainerCode).ThenBy(x => x.PlaceCode).ThenBy(x => x.RecordInsertTime).ToList();
|
// //寻找库存原则:按照先入先出原则 RecordInsertTime 排升序
|
// //同一个物料尽量从同一个库位取
|
// if (findStockQuanList.Count() <= 0)
|
// {
|
// //缺料
|
// throw Oops.Oh("物料编号" + item.MaterialCode + $"库存数量不足,分配需求数量:{occQuantity},库存可用数量:0");
|
// }
|
|
// var sumQty = findStockQuanList.Where(o => o.MaterialCode == item.MaterialCode).Sum(x => x.Quantity);
|
// //波次下发 实际锁定库存
|
// var lockQtyForSort = allStockQuanLockForSortList.Where(o => o.MaterialCode == item.MaterialCode).Sum(x => x.Quantity);
|
// //TODO 去掉分配分配锁定库存
|
// var usedQty = (sumQty - lockQtyForSort) <= 0 ? 0 : (sumQty - lockQtyForSort);
|
// if (usedQty < occQuantity)
|
// {
|
// throw Oops.Oh("物料编号" + item.MaterialCode + $"库存数量不足,分配需求数量:{occQuantity},库存可用数量:{usedQty}");
|
// }
|
|
// //处理后未下发的数量,多个同一个物料多个库存数据的情况,循环处理下发
|
// decimal currentDispenseQuantity = occQuantity;
|
|
// List<string> snCodeList = new List<string>();//下发的库存SNCode,存在使用多个情况
|
// foreach (var stockQuanItem in findStockQuanList)
|
// {
|
// //库位属性是 封存和禁出的,不能操作下架
|
// if (stockQuanItem.PlaceStatus == PlaceStatusEnum.封存)
|
// {
|
// throw Oops.Oh($"库位编号{stockQuanItem.PlaceCode}库位属性是{PlaceStatusEnum.封存.GetDescription()}");
|
// }
|
// if (stockQuanItem.PlaceStatus == PlaceStatusEnum.禁出)
|
// {
|
// throw Oops.Oh($"库位编号{stockQuanItem.PlaceCode}库位属性是{PlaceStatusEnum.禁出.GetDescription()}");
|
// }
|
|
// if (currentDispenseQuantity > 0)
|
// {
|
// //当前物料波次锁定库存
|
// var currentStockQuanLockQty = allStockQuanLockForSortList.Where(x => x.SNCode == stockQuanItem.SNCode).Sum(x => x.Quantity);
|
// //当前物料可用库存
|
// var currentUsedQuantity = (stockQuanItem.Quantity - currentStockQuanLockQty);
|
// currentUsedQuantity = currentUsedQuantity <= 0 ? 0 : currentUsedQuantity;
|
|
// //循环库存信息 处理下发数
|
// if (currentUsedQuantity >= currentDispenseQuantity)//下发数量小于等于库存
|
// {
|
|
// currentDispenseQuantity = 0;//全部下发,不在处理
|
|
// }
|
// else
|
// {
|
// //当前下发数未能完全下发,累计下发数
|
// currentDispenseQuantity = currentDispenseQuantity - currentUsedQuantity;
|
|
// }
|
// //累计使用的库存跟踪码
|
// snCodeList.Add(stockQuanItem.SNCode);
|
|
|
|
// //创建锁定库存
|
// var addWmsStockQuanLock = CommonCreateWmsStockQuanLock(item, occQuantity, stockQuanItem);
|
|
// //创建分拣信息
|
// var addWmsContainerSort = CommonCreateWmsContainerSort(item, movementOrder, sortMovementDetails, occQuantity, addWmsStockQuanLock);
|
|
|
|
|
|
// addWmsStockQuanLockList.Add(addWmsStockQuanLock);
|
|
// if (currentDispenseQuantity == 0)
|
// {
|
// break;
|
// }
|
|
|
// }
|
// else
|
// {
|
// break;
|
// }
|
// }
|
|
// if (currentDispenseQuantity > 0)
|
// {
|
// throw Oops.Oh("物料编号" + item.MaterialCode + $"库存数量不足");
|
|
// }
|
|
// //更新波次单的已下发数量
|
// item.SNCode = string.Join(",", snCodeList.Distinct().ToList());
|
|
// decimal lastIssueQuantity = issueQuantity + occQuantity;//下架单单的历史分配数
|
// item.PredetermineQuantity = lastIssueQuantity;//累计分配数
|
|
// //更新波次单明细的状态
|
// OrderHelper.UpdateOrderMovementDetailsStatus(item);
|
// updateWmsOrderSortDetailsList.Add(item);
|
|
// #endregion
|
// }
|
|
// foreach (var item in allWmsOrderSortList)
|
// {
|
// var updateOrderSortDetails = allOrderSortDetails.Where(w => w.MovementId == item.Id).ToList();
|
// ////计算 波次单单的状态
|
// OrderHelper.UpdatOrderSortStatus(updateOrderSortDetails, item);
|
// updateWmsOrderSortList.Add(item);
|
// }
|
|
|
|
// if (addWmsContainerSortList?.Count <= 0)
|
// {
|
|
|
// throw Oops.Oh("没有可下发的物料,库存全部不足");
|
|
// }
|
|
|
|
// var _tenant = _wmsContainerSortRep.AsTenant();
|
|
// try
|
// {
|
// #region 事务内执行操作
|
// await _wmsStockQuanLockRep.InsertRangeAsync(addWmsStockQuanLockList);
|
// await _wmsOrderSortRep.UpdateRangeAsync(updateWmsOrderSortList);
|
// await _wmsOrderSortDetailsRep.UpdateRangeAsync(updateWmsOrderSortDetailsList);
|
// #endregion
|
|
// await _tenant.CommitTranAsync();
|
// }
|
// catch (Exception ex)
|
// {
|
|
// await _tenant.RollbackTranAsync();
|
// throw;
|
// }
|
|
|
|
|
|
|
|
|
// return 1;
|
//}
|
|
|
|
|
|
|
|
|
/// <summary>
|
/// 创建记录分配信息-新建分配用
|
/// </summary>
|
/// <param name="item"></param>
|
/// <param name="changeQty"></param>
|
/// <param name="stockQuanItem"></param>
|
/// <returns></returns>
|
private static WmsRecordPredetermineDispense CommonCreateWmsRecordPredetermineDispense(WmsOrderMovementDetails item, decimal changeQty, v_wms_stock_quan_for_use stockQuanItem)
|
{
|
|
return new WmsRecordPredetermineDispense()
|
{
|
Id = Yitter.IdGenerator.YitIdHelper.NextId(),
|
PDRecordType = PDRecordTypeEnum.分配,
|
PDRecordTypeName = PDRecordTypeEnum.分配.GetDescription(),
|
PDRecordStatus = PDRecordStatusEnum.已分配,
|
PDRecordStatusName = PDRecordStatusEnum.已分配.GetDescription(),
|
MaterialCode = item.MaterialCode,
|
MaterialName = item.MaterialName,
|
Quantity = changeQty,
|
MovementLineNumber = item.LineNumber,//下架单行号
|
MovementNo = item.MovementNo,//下架单号
|
SNCode = stockQuanItem.SNCode,//用于分配的库存跟踪码
|
Batch = stockQuanItem.Batch,//批次号
|
SupplierBatch = stockQuanItem.SupplierBatch,//供应商批次号
|
AreaCode = stockQuanItem.AreaCode,//库区编码
|
AreaName = stockQuanItem.AreaName,//库区名称
|
PlaceCode = stockQuanItem.PlaceCode,
|
PlaceName = stockQuanItem.PlaceName,
|
ContainerCode = stockQuanItem.ContainerCode,
|
ContainerName = stockQuanItem.ContainerName,
|
Remarks = "",
|
|
};
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|