using Admin.NET.Application.CommonHelper;
using Admin.NET.Application.Entity;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Admin.NET.Application;
///
/// 锁定信息
///
public class LockInfo
{
///
/// 锁定状态
///
public LockStatusEnum LockStatus { get; set; }
///
/// 锁定原因
///
public string? LockReason { get; set; }
///
/// 锁定人
///
public string? LockUser { get; set; }
///
/// 锁定时间
///
public DateTime? LockTime { get; set; }
}
public class StockQuanHelper
{
///
/// 变更库存状态
///
///
///
///
///
public static void UpdateStockStatus(WmsStockQuan item, StockStatusEnum newStockStatus, string remark = "", string RealName = "")
{
if (!string.IsNullOrWhiteSpace(remark))
{
item.Remarks = remark;
}
//记录变更前状态
if (newStockStatus == StockStatusEnum.已冻结 || newStockStatus == StockStatusEnum.已报废 || newStockStatus == StockStatusEnum.已隔离)
{
item.OldStockStatus = item.StockStatus;
item.OldStockStatusName = item.StockStatus.GetDescription();
}
else
{
//清空历史库存状态
item.OldStockStatus = null;
item.OldStockStatusName = "";
}
//ly0806 - 冻结解冻 需要赋值: 解冻人 解冻时间
if (!string.IsNullOrWhiteSpace(RealName))
{
item.OperUser = RealName; //操作人
item.OperTime = DateTime.Now; //解冻时间
item.OperReason = remark; //原因
}
item.StockStatus = newStockStatus;
item.StockStatusName = newStockStatus.GetDescription();
}
///
/// 变更库存锁定状态
///
///
///
public static void UpdateStockLockStatus(WmsStockQuan item, LockInfo lockInfo)
{
item.LockStatus = lockInfo.LockStatus;
item.LockReason = lockInfo.LockReason;
item.LockUser = lockInfo.LockUser;
if (!item.LockTime.HasValue)
{
item.LockTime = DateTime.Now;
}
item.LockTime = lockInfo.LockTime;
}
///
/// 变更库存质检状态
///
///
///
///
public static void UpdateStockQcStatus(WmsStockQuan item, StockQcStatusEnum newStockQcStatus, string remark = "")
{
if (!string.IsNullOrWhiteSpace(remark))
{
item.Remarks = remark;
}
item.QCStatus = newStockQcStatus;
item.QCStatusName = newStockQcStatus.GetDescription();
}
///
/// 盘点关闭- 库存解冻
///
///
///
///
///
///
///
///
///
///
///
public static async Task BackStockStatusForPD(WmsBaseBusinessType wmsBaseBusinessType,
SqlSugarRepository _wmsInventoryCheckOrderDetailsRep,
SqlSugarRepository _wmsStockQuanRep,
SqlSugarRepository _v_wms_stock_quanRep,
SqlSugarRepository _wmsPlaceRep,
WmsInventoryCheckOrder entity,
List upadteWmsStockQuanList, List addWmsRecordTransList, UserManager _userManager)
{
//ly-0716
//获取盘点明细
List checkOrderDetailsList = await _wmsInventoryCheckOrderDetailsRep.AsQueryable().Where(u => u.OrderId == entity.Id && u.IsDelete == false).Select().ToListAsync();
//ly-0716
//update by liuwq 20240730
//获取盘点明细
if (checkOrderDetailsList?.Count <= 0)
{
return;//没有盘点单明细 直接返回
}
//获取盘点单据明细的 所有容器
List checkContainerCodeList = checkOrderDetailsList.Select(s => s.ContainerCode).Distinct().ToList();
//获取盘点下架容器的所有库存
var checkOutStockQuanList = await _wmsStockQuanRep.GetListAsync(u => checkContainerCodeList.Contains(u.ContainerCode) && u.IsDelete == false && u.LockStatus == LockStatusEnum.已锁定);
List snCodeList = checkOutStockQuanList.Select(s => s.SNCode).ToList();
var checkOutStockQuanViewList = await _v_wms_stock_quanRep.GetListAsync(u => snCodeList.Contains(u.SNCode));
//获取库位相信
var placeCodeList = checkOutStockQuanViewList.Select(s => s.PlaceCode).Distinct().ToList();
var allPlaeList = await _wmsPlaceRep.GetListAsync(u => placeCodeList.Contains(u.PlaceCode) && u.IsDelete == false);
//事务记录其他入参
TransferOtherDetail transferOtherDetail = new TransferOtherDetail()
{
RelationNo = entity.OrderNo,//盘点单号
RelationNoLineNumber = string.Empty,
Remarks = "",
};
List materialCodeList = checkOutStockQuanList.Select(s => s.MaterialCode).Distinct().ToList();
foreach (var item in checkOutStockQuanList)
{
var ss = GetVMmsStockQuan(checkOutStockQuanViewList, item.SNCode);
LockInfo freezeInfo = new LockInfo()
{
LockReason = wmsBaseBusinessType.BusinessTypeName,
LockTime = DateTime.Now,
LockUser = _userManager.RealName,//登录人的真实姓名
LockStatus = LockStatusEnum.未锁定,//解冻
};
StockQuanHelper.UpdateStockLockStatus(item, freezeInfo);
upadteWmsStockQuanList.Add(item);
//新增事务记录
//仅变更库存冻结状态
//获取源库存信息
var sourceStockView = StockQuanHelper.GetVMmsStockQuan(checkOutStockQuanViewList, item.SNCode);
//获取目标库位信息
//目标库存不变 新增的库存也是源库存的库位
var toPlaceInfo = BaseInfoHelper.GetPlace(sourceStockView.PlaceCode, allPlaeList);
addWmsRecordTransList.Add(LogRecordHelper.CreateWmsRecordTrans(wmsBaseBusinessType, sourceStockView, item, toPlaceInfo, transferOtherDetail));
}
}
///
/// 盘点单据完成、盘点调差- 整个容器库存解冻
///
///
///
///
///
///
///
///
///
///
///
public static async Task BackStockStatusForPD(WmsBaseBusinessType wmsBaseBusinessType,
List checkOrderDetailsList,
SqlSugarRepository _wmsStockQuanRep,
SqlSugarRepository _v_wms_stock_quanRep,
SqlSugarRepository _wmsPlaceRep,
WmsInventoryCheckOrder entity,
List upadteWmsStockQuanList, List addWmsRecordTransList, UserManager _userManager)
{
//ly-0716
//update by liuwq 20240730
//获取盘点明细
if (checkOrderDetailsList?.Count <= 0)
{
return;//没有盘点单明细 直接返回
}
//获取盘点单据明细的 所有容器
List checkContainerCodeList = checkOrderDetailsList.Select(s => s.ContainerCode).Distinct().ToList();
//获取盘点下架容器的所有库存
var checkOutStockQuanList = await _wmsStockQuanRep.GetListAsync(u => checkContainerCodeList.Contains(u.ContainerCode) && u.IsDelete == false && u.LockStatus == LockStatusEnum.已锁定);
List snCodeList = checkOutStockQuanList.Select(s => s.SNCode).ToList();
var checkOutStockQuanViewList = await _v_wms_stock_quanRep.GetListAsync(u => snCodeList.Contains(u.SNCode));
//获取库位相信
var placeCodeList = checkOutStockQuanViewList.Select(s => s.PlaceCode).Distinct().ToList();
var allPlaeList = await _wmsPlaceRep.GetListAsync(u => placeCodeList.Contains(u.PlaceCode) && u.IsDelete == false);
//事务记录其他入参
TransferOtherDetail transferOtherDetail = new TransferOtherDetail()
{
RelationNo = entity.OrderNo,//盘点单号
RelationNoLineNumber = string.Empty,
Remarks = "",
};
List materialCodeList = checkOutStockQuanList.Select(s => s.MaterialCode).Distinct().ToList();
foreach (var item in checkOutStockQuanList)
{
LockInfo freezeInfo = new LockInfo()
{
LockReason = wmsBaseBusinessType.BusinessTypeName,
LockTime = DateTime.Now,
LockUser = _userManager.RealName,//登录人的真实姓名
LockStatus = LockStatusEnum.未锁定,//解冻
};
StockQuanHelper.UpdateStockLockStatus(item, freezeInfo);
// 调差 操作的库存跟踪码,也会存在更新的库存列表 不用重复添加,调差操作会 解冻
if (!upadteWmsStockQuanList.Any(a => a.SNCode == item.SNCode))
{
upadteWmsStockQuanList.Add(item);
//新增事务记录
//仅变更库存冻结状态
//获取源库存信息
var sourceStockView = StockQuanHelper.GetVMmsStockQuan(checkOutStockQuanViewList, item.SNCode);
//获取目标库位信息
//目标库存不变 新增的库存也是源库存的库位
var toPlaceInfo = BaseInfoHelper.GetPlace(sourceStockView.PlaceCode, allPlaeList);
addWmsRecordTransList.Add(LogRecordHelper.CreateWmsRecordTrans(wmsBaseBusinessType, sourceStockView, item, toPlaceInfo, transferOtherDetail));
}
}
}
///
/// 校验库存
///
/// 1、波次下发验证
///
///
///
public static async Task ValdiateStock(int flag, List handlerDetaiList, SqlSugarRepository _wmsOrderMovementDetailsRep,
SqlSugarRepository _v_wms_stock_quan_for_useRep
)
{
var movementMatericalCodeList = handlerDetaiList.Select(x => x.MaterialCode).ToList();
//查询该物料的预配库存
var preList = await LockStroreHelper.GetPreListAsync(movementMatericalCodeList, _wmsOrderMovementDetailsRep);
//查询该物料的可用库存
var stockUseList = await _v_wms_stock_quan_for_useRep.GetListAsync(x => movementMatericalCodeList.Contains(x.MaterialCode));
if (flag == 1)
{
ValdiateStockForGroup(flag, handlerDetaiList, stockUseList, preList);
}
}
///
/// 校验 库存汇总库存
///
///
///
///
///
///
private static void ValdiateStockForGroup(int flag,
List handlerDetaiList,
List _v_wms_stock_quan_for_useList,
List preList)
{
//模拟挨个扣减,哪个不足就报错
foreach (var item in handlerDetaiList)
{
if (item.SendQuantity <= 0)
{
throw Oops.Oh($"数量大于0");
}
string materialCode = item.MaterialCode;
decimal validateQty = item.SendQuantity;
var queryKey = (item.MovementNo + item.LineNumber);
//首先查询 预配自己的库存数量
var pre_self_list = preList.Where(x => x.MaterialCode == materialCode && (x.MovementNo + x.LineNumber) == queryKey).FirstOrDefault();
//其次查询 预配其他的库存数量
var pre_other_list = preList.Where(x => x.MaterialCode == materialCode && (x.MovementNo + x.LineNumber) != queryKey).FirstOrDefault();
var pre_self_num = pre_self_list != null ? pre_self_list.PredetermineQuantity : 0;
var pre_other_num = pre_other_list != null ? pre_other_list.PredetermineQuantity : 0;
if (pre_self_num >= validateQty)
{
//说明预配给自己的库存数超过了自己需要的库存数
//扣减掉内存中的数据
pre_self_list.PredetermineQuantity -= validateQty;
}
else
{//说明预配给自己的数 少于 自己需要的数
//查询库存
var stockQuanForUseList = _v_wms_stock_quan_for_useList.Where(x => x.MaterialCode == materialCode).ToList();
//首先要模拟减去 其他的预配数
foreach (var stockQuanForUse in stockQuanForUseList)
{
if (pre_other_num <= 0) break;
if (stockQuanForUse.Quantity == 0) break;
if (stockQuanForUse.Quantity < 0)
{
throw Oops.Oh($"物料{materialCode}可用库存计算其他预配数错误,小于0,{stockQuanForUse.Quantity}");
};
if (stockQuanForUse.Quantity >= pre_other_num)
{
stockQuanForUse.Quantity -= pre_other_num;
pre_other_num = 0;
break;
}
else
{
pre_other_num -= stockQuanForUse.Quantity;
stockQuanForUse.Quantity = 0;
}
}
if (pre_other_num > 0)
{
throw Oops.Oh($"物料{materialCode}可用库存计算不足,其他预配库存还有{pre_other_num}未能分配出来");
};
//其次要模拟扣减自己需求数
foreach (var stockQuanForUse in stockQuanForUseList)
{
if (validateQty <= 0) break;
// if (stockQuanForUse.Quantity == 0) break;
if (stockQuanForUse.Quantity == 0) continue;// 如果第一个库位没了,循环处理下一个
if (stockQuanForUse.Quantity < 0)
{
throw Oops.Oh($"物料{materialCode}可用库存计算实际需求数错误,小于0,{stockQuanForUse.Quantity}");
};
if (stockQuanForUse.Quantity >= validateQty)
{
stockQuanForUse.Quantity -= validateQty;
validateQty = 0;
break;
}
else
{
validateQty -= stockQuanForUse.Quantity;
stockQuanForUse.Quantity = 0;
}
}
if (validateQty > 0)
{
throw Oops.Oh($"物料{materialCode}可用库存计算不足,本次总需求数{item.SendQuantity},缺少{validateQty}数量的可用库存");
};
}
}
}
/////
///// 校验 库存汇总库存
/////
/////
/////
/////
/////
/////
/////
/////
//public static async Task ValdiateStockForGroup(int flag,
// SqlSugarRepository _v_wms_stock_quan_for_useRep,
// WmsOrderMovementDetails wmsOrderMovementDetails, string materialCode, decimal validateQty, List preList)
//{
// //首先查询 预配自己的库存数量
// var pre_self_num = preList.Where(x => x.MaterialCode == materialCode && (x.MovementNo + x.LineNumber) == (wmsOrderMovementDetails.MovementNo + wmsOrderMovementDetails.LineNumber)).ToList().Sum(x => x.PredetermineQuantity);
// //其次查询 预配其他的库存数量
// var pre_other_num = preList.Where(x => x.MaterialCode == materialCode && (x.MovementNo + x.LineNumber) != (wmsOrderMovementDetails.MovementNo + wmsOrderMovementDetails.LineNumber)).ToList().Sum(x => x.PredetermineQuantity);
// if (pre_self_num >= validateQty)
// {
// //说明预配给自己的库存数超过了自己需要的库存数,验证通过
// }
// else
// {
// var needQty = validateQty - pre_self_num;//自己还需要除预配之外的数据
// //查询库存
// var stockQuanForUseList = await _v_wms_stock_quan_for_useRep.GetListAsync(x => x.MaterialCode == materialCode);
// var num_AvailableQty_stockQuanForUse = stockQuanForUseList.Sum(x => x.AvailableQty);
// var valQty = num_AvailableQty_stockQuanForUse - pre_other_num;
// if (valQty <= 0)
// {
// throw Oops.Oh($"物料{materialCode}可用库存不足,可用库存{num_AvailableQty_stockQuanForUse},并且预配库存为{pre_other_num}");
// }
// }
//}
/////
///// 校验 可用库存是否满足(细节到具体库存)
/////
/////
/////
/////
/////
/////
/////
/////
//public static async Task ValdiateStockForGroup33(int flag,
// SqlSugarRepository _v_wms_stock_quan_for_useRep,
// WmsOrderMovementDetails wmsOrderMovementDetails, string materialCode, decimal validateQty, List dispenseList)
//{
// //首先查询 分配自己的库存数量
// var pre_self_num = dispenseList.Where(x => x.MaterialCode == materialCode && (x.MovementNo + x.MovementLineNumber) == (wmsOrderMovementDetails.MovementNo + wmsOrderMovementDetails.LineNumber)).ToList().Sum(x => x.Quantity);
// if (pre_self_num >= validateQty)
// {
// //说明分配给自己的库存数超过了自己需要的库存数,验证通过
// }
// else
// {
// //查询库存
// var stockQuanForUseList = await _v_wms_stock_quan_for_useRep.GetListAsync(x => x.MaterialCode == materialCode);
// var num_AvailableQty_stockQuanForUse = stockQuanForUseList.Sum(x => x.AvailableQty);
// var valQty = num_AvailableQty_stockQuanForUse + pre_self_num - validateQty;
// if (valQty <= 0)
// {
// throw Oops.Oh($"物料{materialCode}可用库存不足,可用库存{num_AvailableQty_stockQuanForUse}加已分配自己的库存{pre_self_num}小于需求数量{validateQty}");
// }
// }
//}
///
/// 校验库存物料容器类型-组盘、上架用
///
///
///
///
///
///
public static async Task CheckContainerType(SqlSugarRepository _wmsMaterialRep, SqlSugarRepository _wmsContainerPackagingRep, WmsBaseContainer updateWmsContainerItem, List wmsStocks)
{
//获取库存物料基础信息的容器类型
List materialCodeList = wmsStocks.Select(v => v.MaterialCode).Distinct().ToList();
var stockQuanMaterialList = await _wmsMaterialRep.GetFirstAsync(u => materialCodeList.Contains(u.MaterialCode) && u.IsDelete == false);
//获取物料的容器类型关系
var materialContainerTypeList = await _wmsContainerPackagingRep.GetListAsync(u => materialCodeList.Contains(u.MaterialCode) && u.IsDelete == false);
//根据容器号分组 汇总相同容器的库存数
var checkStocks = wmsStocks.GroupBy(g => new { g.ContainerCode, g.MaterialCode }).Select(s => new
{
ContainerCode = s.Key.ContainerCode,
MaterialCode = s.Key.MaterialCode,
TotalQuantity = s.Sum(x => x.Quantity)
}).ToList();
foreach (var item in checkStocks)
{
//获取库存的物料信息
var currentStockQuanMaterial = stockQuanMaterialList.Where(x => x.MaterialCode == item.MaterialCode).FirstOrDefault();
if (currentStockQuanMaterial == null)
{
//物料基础信息不存在
throw Oops.Oh($"物料{item.MaterialCode}基础信息不存在!");
}
//获取物料与容器的绑定关系
var currentMaterialContainerType = materialContainerTypeList.Where(x => x.MaterialCode == item.MaterialCode).FirstOrDefault();
if (currentMaterialContainerType != null)
{
if (currentMaterialContainerType.ContainerTypeId != updateWmsContainerItem.ContainerTypeId)
{
throw Oops.Oh($"物料{item.MaterialCode}配置的容器类型是{currentMaterialContainerType.ContainerTypeName},组盘的容器类型是{updateWmsContainerItem.ContainerTypeName},两者不一致!");
}
if (item.TotalQuantity > currentMaterialContainerType.BoxQty)
{
throw Oops.Oh($"容器类型{currentMaterialContainerType.ContainerTypeName}设置的物料容器容量最大值是{currentMaterialContainerType.BoxQty},物料{item.MaterialCode}库存数量{item.TotalQuantity}已超限!");
}
}
}
}
///
/// 校验在途库区和在途容器是否存在
///
///
///
///
///
public static async Task VerifyZTPlaceAndContainerIsExist(SqlSugarRepository _repWmsPlace, SqlSugarRepository _repWmsContainer, string wmsAreaCode)
{
var ztPlace = await _repWmsPlace.GetFirstAsync(n => n.PlaceCode == ApplicationConst.DefaultZTPlaceCode_Pre + wmsAreaCode);
if (ztPlace == null) throw Oops.Oh($"在途库位{ApplicationConst.DefaultZTPlaceCode_Pre + wmsAreaCode}不存在!");
if (ztPlace.PlaceType != PlaceTypeEnum.在途库位)
{
throw Oops.Oh($"库位{ztPlace.PlaceCode}的库位类型不是在途库位!");
}
var ztContainer = await _repWmsContainer.GetFirstAsync(n => n.ContainerCode == ApplicationConst.DefaultZTContainerCode_Pre + wmsAreaCode);
if (ztContainer == null) throw Oops.Oh($"在途库容器{ApplicationConst.DefaultZTContainerCode_Pre + wmsAreaCode}不存在!");
return new ZtPlaceAndContainerOutput { ZtPlace = ztPlace, ZtContainer = ztContainer };
}
///
/// 获取在途库位
///
///
///
///
public static async Task> GetZTPlace(SqlSugarRepository _wmsPlaceRep, WmsBasePlace placeModel)
{
//查询当前库区的在途库位信息
var placeZtList = await _wmsPlaceRep.AsQueryable().Where(z => z.AreaId == placeModel.AreaId && z.PlaceType == PlaceTypeEnum.在途库位).ToListAsync();
if (placeZtList.Count == 0) throw Oops.Oh("当前库区无在途库位,请联系管理人员进行处理!");
if (placeZtList.Count > 1) throw Oops.Oh("当前库区存在多个在途库位,请联系管理人员进行处理!");
return placeZtList;
}
///
/// 根据跟踪码获取库存详情-查询库存视图表集合
///
///
///
public static v_wms_stock_quan GetVMmsStockQuan(List allStockQuanView, string snCode)
{
v_wms_stock_quan currentStockQuanView = allStockQuanView.FirstOrDefault(f => f.SNCode.Equals(snCode));
if (currentStockQuanView == null)
{
throw Oops.Oh($"跟踪码{snCode}没有获取到库存信息");
}
return currentStockQuanView;
}
}