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;
namespace Admin.NET.Application;
///
/// 波次单分配服务
///
[ApiDescriptionSettings(ApplicationConst.WmsTaskGroupName, Order = 100)]
public class WmsSortDispenseService : IDynamicApiController, ITransient
{
///
/// 是否正在执行分配方法
///
private static bool isRuning_Fun_Dispense = false;
private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
private readonly SqlSugarRepository _wmsContainerSortRep;
private readonly SqlSugarRepository _v_wms_stock_quanRep;
private readonly SqlSugarRepository _v_wms_stock_quan_for_useRep;
private readonly SqlSugarRepository _wmsOrderSortDetailsRep;
//private readonly SqlSugarRepository _wmsStockQuanLockRep;
private readonly SqlSugarRepository _wmsOrderSortRep;
private readonly SqlSugarRepository _wmsOrderMovementDetailsRep;
private readonly SqlSugarRepository _wmsOrderMovementRep;
private readonly SqlSugarRepository _wmsTaskRep;
private readonly SqlSugarRepository _wmsRecordPredetermineDispenseRep;
private readonly SqlSugarRepository _v_wmsOrderMovementDetailsRep;
public WmsSortDispenseService(
SqlSugarRepository v_wmsOrderMovementDetailsRep,
SqlSugarRepository wmsContainerSortRep,
SqlSugarRepository v_wms_stock_quanRep,
SqlSugarRepository v_wms_stock_quan_for_useRep,
//SqlSugarRepository wmsStockQuanLockRep,
SqlSugarRepository wmsOrderSortDetailsRep,
SqlSugarRepository wmsOrderSortRep,
SqlSugarRepository wmsOrderMovementDetailsRep,
SqlSugarRepository wmsOrderMovementRep,
SqlSugarRepository wmsTaskRep,
SqlSugarRepository wmsRecordPredetermineDispenseRep)
{
_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;
}
///
/// 波次分配
///
///
///
[HttpPost]
[ApiDescriptionSettings(Name = "SortDispense")]
[Description("WmsSortDispense/SortDispense")]
public async Task SortDispense(List input)
{
try
{
if (isRuning_Fun_Dispense)
{
throw Oops.Oh("程序正忙,请稍后再试");
}
await semaphoreSlim.WaitAsync();
isRuning_Fun_Dispense = true;
return await SortDispenseFaction(input);
}
catch (Exception ex)
{
throw Oops.Oh(ex.Message);
}
finally
{
semaphoreSlim.Release();
isRuning_Fun_Dispense = false;
}
}
#region 私有方法
///
/// 分配
///
///
///
private async Task SortDispenseFaction(List input)
{
/**
* 获取分配物料库存信息
* 获取当前分配锁定库存信息
* 校验可用库存-历史分配锁定库存 是否满足分配
* 新增分配锁定库存
* 修改下架单明细分配数
* 新增事务
* 新增操作日期
*/
var updateWmsOrderMoveDetailsList = new List();//修改的移动单明细
var addWmsRecordPredetermineDispenseList = new List();
List sortNoList = input.Select(x => x.SortNo).ToList();
//获取波次单所有明细
var allOrderSortDetails = await _wmsOrderSortDetailsRep.GetListAsync(u => sortNoList.Contains(u.SortNo));
if (allOrderSortDetails?.Count <= 0)
{
throw Oops.Oh("波次单明细不存在");
}
//本次下发波次单明细
var currentOrderSortDetails = allOrderSortDetails.Where(u => input.Select(x => x.SortDetailsId).Contains(u.Id)).ToList();
if (currentOrderSortDetails?.Count <= 0)
{
throw Oops.Oh("本次下发的波次单明细不存在");
}
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 allOrderrMovementDetails = await _wmsOrderMovementDetailsRep.GetListAsync(u => moveNoList.Contains(u.MovementNo));
if (allOrderrMovementDetails?.Count <= 0)
{
throw Oops.Oh("下架单明细不存在");
}
// 查找物料库存
List materialCodeList = input.Select(x => x.MaterialCode).Distinct().ToList();
//根据物料编码获取物料跟踪码的可用库存信息)
var allStockQuanUseList = await _v_wms_stock_quan_for_useRep.GetListAsync(x => materialCodeList.Contains(x.MaterialCode));
if (allStockQuanUseList?.Count <= 0)
{
throw Oops.Oh("所有物料都没有库存");
}
//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("本次分配的下架单明细不存在");
}
#region 处理分配
decimal historyDispenseQuantity = v_movementDetails.DispenseQuantity;//下架单的历史分配数量
decimal allQuantity = movementDetails.Quantity - historyDispenseQuantity;//下架单明细剩余可分配数量
decimal occQuantity = inputItem.SendQuantity;//当前实际分配数量
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 = allStockQuanUseList.Where(x => x.AvailableQty > 0 && x.MaterialCode == movementDetails.MaterialCode)
.OrderBy(x => x.ContainerCode).ThenBy(x => x.PlaceCode).ThenBy(x => x.RecordInsertTime).ToList();
//寻找库存原则:按照先入先出原则 RecordInsertTime 排升序
//同一个物料尽量从同一个库位取
if (findStockQuanList.Count() <= 0)
{
//缺料
throw Oops.Oh("物料编号" + movementDetails.MaterialCode + $"库存数量不足,分配数量:{occQuantity},库存可用数量:0");
}
var sumQty = findStockQuanList.Sum(x => x.AvailableQty);
if (sumQty < occQuantity)
{
throw Oops.Oh("物料编号" + movementDetails.MaterialCode + $"库存数量不足,分配数量:{occQuantity},库存可用数量:{sumQty}");
}
//处理后未分配的数量,多个同一个物料多个库存数据的情况,循环处理下发
decimal currentIssueQuantity = occQuantity;
List snCodeList = new List();//下发的库存SNCode,存在使用多个情况
foreach (var stockQuanItem in findStockQuanList)
{
if (currentIssueQuantity > 0)
{
//当前物料波次锁定库存
var currentStockQuanLockQty = findStockQuanList.Where(x => x.SNCode == stockQuanItem.SNCode).Sum(x => x.Quantity);
//当前物料可用库存
var currentUsedQuantity = stockQuanItem.AvailableQty;
//循环库存信息 处理下发数
if (currentUsedQuantity >= currentIssueQuantity)//分配数量小于等于库存
{
currentIssueQuantity = 0;//全部分配,不在处理
}
else
{
//当前分配数未能完全分配,累计分配数
currentIssueQuantity = currentIssueQuantity - currentUsedQuantity;
}
//累计使用的库存跟踪码
snCodeList.Add(stockQuanItem.SNCode);
//创建分配记录
//TODO 之前单据明细已经预配,如何处理????
var addWmsRecordPredetermineDispense = CommonCreateWmsRecordPredetermineDispense(movementDetails, occQuantity, stockQuanItem);
addWmsRecordPredetermineDispenseList.Add(addWmsRecordPredetermineDispense);
if (currentIssueQuantity == 0)
{
break;
}
}
else
{
break;
}
}
//movementDetails.DispenseQuantity += occQuantity;//累计分配数
//预配数等于分配数
movementDetails.PredetermineQuantity += occQuantity;
updateWmsOrderMoveDetailsList.Add(movementDetails);//更新下架单明细
#endregion
}
var _tenant = _wmsOrderMovementDetailsRep.AsTenant();
try
{
#region 事务内执行操作
await _wmsOrderMovementDetailsRep.UpdateRangeAsync(updateWmsOrderMoveDetailsList);
await _wmsRecordPredetermineDispenseRep.InsertRangeAsync(addWmsRecordPredetermineDispenseList);
#endregion
await _tenant.CommitTranAsync();
}
catch (Exception ex)
{
await _tenant.RollbackTranAsync();
throw;
}
return 1;
}
/////
///// 移动单分配
/////
/////
/////
//private async Task LockMovePredetermine(List input)
//{
// var addWmsStockQuanLockList = new List();//新增的锁定库存信息
// var updateWmsOrderMoveDetailsList = new List();//修改的移动单明细
// var updateWmsOrderMoveList = new List();//修改的移动单
// //TODO 添加事务记录
// List sortNoList = input.Select(x => x.movementNo).ToList();
// // 获取所有波次单
// //Expression> 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 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 currentIssueQuantity = occQuantity;
// List snCodeList = new List();//下发的库存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 (currentIssueQuantity > 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 >= currentIssueQuantity)//下发数量小于等于库存
// {
// currentIssueQuantity = 0;//全部下发,不在处理
// }
// else
// {
// //当前下发数未能完全下发,累计下发数
// currentIssueQuantity = currentIssueQuantity - currentUsedQuantity;
// }
// //累计使用的库存跟踪码
// snCodeList.Add(stockQuanItem.SNCode);
// //创建锁定库存
// var addWmsStockQuanLock = CommonCreateWmsStockQuanLock(item, occQuantity, stockQuanItem);
// //创建分拣信息
// var addWmsContainerSort = CommonCreateWmsContainerSort(item, movementOrder, sortMovementDetails, occQuantity, addWmsStockQuanLock);
// addWmsStockQuanLockList.Add(addWmsStockQuanLock);
// if (currentIssueQuantity == 0)
// {
// break;
// }
// }
// else
// {
// break;
// }
// }
// if (currentIssueQuantity > 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;
//}
///
/// 创建记录分配信息公共方法
///
///
///
///
///
private static WmsRecordPredetermineDispense CommonCreateWmsRecordPredetermineDispense(WmsOrderMovementDetails item, decimal occQuantity, 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 = occQuantity,
MovementLineNumber = item.LineNumber,//下架单行号
MovementNo = item.MovementNo,//下架单号
SNCode = item.SNCode,//用于分配的库存跟踪码
Batch = stockQuanItem.Batch,//批次号
AreaCode = stockQuanItem.AreaCode,//库区编码
AreaName = stockQuanItem.AreaName,//库区名称
PlaceCode = stockQuanItem.PlaceCode,
PlaceName = stockQuanItem.PlaceName,
ContainerCode = stockQuanItem.ContainerCode,
ContainerName = stockQuanItem.ContainerName,
Remarks = "",
};
}
#endregion
}