using Admin.NET.Application.Entity;
|
using Admin.NET.Application.Service.WmsStockSnapshot.Dto;
|
using Admin.NET.Core;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
|
namespace Admin.NET.Application;
|
|
/// <summary>
|
/// 库存快照
|
/// </summary>
|
[ApiDescriptionSettings(ApplicationConst.WmsStockSnapshotDetailsGroupName, Order = 100)]
|
public class WmsStockSnapshotService : IDynamicApiController, ITransient
|
{
|
private readonly SqlSugarRepository<v_wms_stock_quan> _v_wms_stock_quanrRep;
|
private readonly SqlSugarRepository<WmsStockSnapshot> _wmsStockSnapshotRep;
|
private readonly SqlSugarRepository<WmsStockSnapshotDetails> _wmsStockSnapshotDetails;
|
private readonly SqlSugarRepository<WmsStockSnapshotGroup> _wmsStockSnapshotGroupRep;
|
private readonly SqlSugarRepository<WmsRecordTrans> _repWmsRecordTrans;
|
|
private readonly SqlSugarRepository<WmsLogAction> _wmsLogActionRep;
|
private readonly SqlSugarRepository<WmsRecordTrans> _wmsRecordTransRep;
|
|
|
/// <summary>
|
/// 构造函数
|
/// </summary>
|
public WmsStockSnapshotService(SqlSugarRepository<v_wms_stock_quan> v_wms_stock_quanrRep,
|
SqlSugarRepository<WmsStockSnapshot> wmsStockSnapshotRep,
|
SqlSugarRepository<WmsStockSnapshotDetails> wmsStockSnapshotDetails,
|
SqlSugarRepository<WmsLogAction> wmsLogActionRep,
|
SqlSugarRepository<WmsRecordTrans> wmsRecordTransRep, SqlSugarRepository<WmsStockSnapshotGroup> wmsStockSnapshotGroupRep, SqlSugarRepository<WmsRecordTrans> repWmsRecordTrans)
|
{
|
_wmsStockSnapshotGroupRep = wmsStockSnapshotGroupRep;
|
this._v_wms_stock_quanrRep = v_wms_stock_quanrRep;
|
this._wmsStockSnapshotRep = wmsStockSnapshotRep;
|
this._wmsStockSnapshotDetails = wmsStockSnapshotDetails;
|
this._wmsLogActionRep = wmsLogActionRep;
|
this._wmsRecordTransRep = wmsRecordTransRep;
|
_repWmsRecordTrans = repWmsRecordTrans;
|
}
|
|
/// <summary>
|
/// 获取库存快照分页
|
/// </summary>
|
/// <returns></returns>
|
[HttpGet]
|
[ApiDescriptionSettings(Name = "GetStockSnapshotPage", Description = "获取库存快照分页")]
|
[Description("/WmsStockSnapshot/GetStockSnapshotPage")]
|
public async Task GetStockSnapshotPage()
|
{
|
|
}
|
|
|
|
|
/// <summary>
|
/// 添加库存快照
|
/// </summary>
|
/// <returns></returns>
|
[HttpPost]
|
[ApiDescriptionSettings(Name = "CreateStockSnapshot", Description = "添加库存快照")]
|
[Description("/WmsStockSnapshot/CreateStockSnapshot")]
|
public async Task CreateStockSnapshot()
|
{
|
//获取当前库存
|
var stockQuanList = await _v_wms_stock_quanrRep.GetListAsync();
|
|
|
|
// 格式化为年月日字符串
|
string formattedDate = DateTime.Now.ToString("yyyyMMdd");
|
//查询当天是否有快照单号
|
var wmsStockSnapshot = await _wmsStockSnapshotRep.GetFirstAsync(u => u.SnapshotNo == "KZ" + formattedDate);
|
var stockSnapshotDetailsList = new List<WmsStockSnapshotDetails>();
|
|
|
if (wmsStockSnapshot == null)
|
{
|
|
var isExist = false;
|
|
var Id = Yitter.IdGenerator.YitIdHelper.NextId();
|
var WmsStockSnapshot = new WmsStockSnapshot
|
{
|
Id = Id,
|
SnapshotDate = formattedDate,
|
SnapshotNo = "KZ" + formattedDate,
|
Remark = formattedDate + "以执行"
|
};
|
isExist = await _wmsStockSnapshotRep.IsAnyAsync(x => x.SnapshotDate == formattedDate);
|
if (!isExist)
|
{
|
foreach (var kvp in stockQuanList)
|
{
|
var stockSnapshotDetails = kvp.Adapt<WmsStockSnapshotDetails>();
|
stockSnapshotDetails.SnapshotId = Id;
|
stockSnapshotDetails.Id = Yitter.IdGenerator.YitIdHelper.NextId();
|
stockSnapshotDetails.CreateTime = DateTime.Now;
|
stockSnapshotDetails.UpdateTime = null;
|
stockSnapshotDetails.SnapshotDate = formattedDate;
|
if (stockSnapshotDetails.SourceSNCode == null)
|
{
|
stockSnapshotDetails.SourceSNCode = "";
|
}
|
stockSnapshotDetailsList.Add(stockSnapshotDetails);
|
}
|
|
|
}
|
isExist = await _wmsStockSnapshotGroupRep.IsAnyAsync(x => x.SnapshotDate == formattedDate);
|
List<WmsStockSnapshotGroup> addWmsStockSnapshotGroupList = new List<WmsStockSnapshotGroup>();
|
if (!isExist)
|
{
|
//物料、库区分组
|
var stockQuanGroupList = stockQuanList.GroupBy(x => new { x.MaterialCode, x.MaterialName, x.AreaCode, x.AreaName, x.MaterialUnit }).Select(x => new
|
{
|
x.Key.MaterialCode,
|
x.Key.MaterialName,
|
x.Key.AreaCode,
|
x.Key.AreaName,
|
x.Key.MaterialUnit,
|
Quantity = x.Sum(s => s.Quantity)
|
}).ToList();
|
//汇总表
|
foreach (var item in stockQuanGroupList)
|
{
|
//快照汇总只记录有数量大于0且库区不为空的数据
|
if (item.Quantity > 0 && !string.IsNullOrWhiteSpace(item.AreaCode))
|
{
|
|
addWmsStockSnapshotGroupList.Add(new WmsStockSnapshotGroup()
|
{
|
Id = Yitter.IdGenerator.YitIdHelper.NextId(),
|
SnapshotId = Id,
|
SnapshotDate = formattedDate,
|
MaterialCode = item.MaterialCode,
|
MaterialName = item.MaterialName,
|
MaterialUnit = item.MaterialUnit??"",
|
AreaCode = item.AreaCode,
|
AreaName = item.AreaName,
|
Quantity = item.Quantity
|
});
|
}
|
}
|
|
|
|
}
|
|
var _tenant = _wmsStockSnapshotDetails.AsTenant();
|
try
|
{
|
|
|
await _wmsStockSnapshotRep.InsertAsync(WmsStockSnapshot);
|
await _wmsStockSnapshotDetails.InsertRangeAsync(stockSnapshotDetailsList);
|
|
await _wmsStockSnapshotGroupRep.InsertRangeAsync(addWmsStockSnapshotGroupList);
|
|
|
await _tenant.CommitTranAsync();
|
}
|
catch
|
{
|
await _tenant.RollbackTranAsync();
|
throw;
|
}
|
}
|
|
}
|
|
/// <summary>
|
/// 历史库存查询
|
/// </summary>
|
/// <param name="input"></param>
|
/// <returns></returns>
|
[HttpGet]
|
[ApiDescriptionSettings(Name = "HistorialStockPage", Description = "历史库存查询")]
|
[Description("/WmsStockSnapshot/HistorialStockPage")]
|
public async Task<SqlSugarPagedList<HistoricalInventory>> HistorialStockPage([FromQuery] HistoricalStockQuery input)
|
{
|
// 要计算 A库区的某个时间点的库存
|
//--第一步:查询库存快照表的最近一个时间点的库存 CurQty
|
//--第二步:查询来源库区 = A的,变更数量 -= 源数量,库存 = CurQty - 变更数量
|
//-- 第三步:查询目标库区 = A的,变更数量 += 目标数量,库存 = CurQty + 变更数量
|
|
//更具输入时间查询第一条快照,然后根据SnapshotId快照ID查询到最近一段时间的快照列表
|
//var StockSnapshotModel = await _wmsStockSnapshotDetails.AsQueryable()
|
// .WhereIF(!string.IsNullOrWhiteSpace(input.BegineTime.ToString()), p => p.CreateTime < input.BegineTime)
|
// .WhereIF(!string.IsNullOrWhiteSpace(input.AreaCode), p => p.AreaCode.Contains(input.AreaCode))
|
// .WhereIF(!string.IsNullOrWhiteSpace(input.MaterialCode), p => p.MaterialCode.Contains(input.MaterialCode))
|
// .OrderByDescending(p => p.CreateTime)
|
// .FirstAsync();
|
|
|
//if (StockSnapshotModel == null)
|
//{
|
// return new SqlSugarPagedList<HistoricalInventory>() { };
|
//}
|
if (input.SearchKey == null && input.MaterialCode == null && input.SnapshotId == null && input.AreaCode == null && input.BegineTime.ToString() == "0001/1/1 0:00:00" )
|
{
|
return new SqlSugarPagedList<HistoricalInventory>() { };
|
}
|
//
|
var newStockSnapshotList = new List<WmsStockSnapshotDetails>();
|
//var StockSnapshotList = await _wmsStockSnapshotDetails.AsQueryable()
|
// .WhereIF(!string.IsNullOrWhiteSpace(StockSnapshotModel.SnapshotId.ToString()),p => p.SnapshotId == StockSnapshotModel.SnapshotId)
|
// .WhereIF(!string.IsNullOrWhiteSpace(input.AreaCode), p => p.AreaCode.Contains(input.AreaCode))
|
// .WhereIF(!string.IsNullOrWhiteSpace(input.MaterialCode), p => p.MaterialCode.Contains(input.MaterialCode))
|
// .ToListAsync();
|
|
|
var HistoricalStockList = new List<HistoricalInventory>();
|
DateTime? searchDateTime = null;//选择的时间点
|
if (input.BegineTime.ToString() != "0001/1/1 0:00:00")
|
{
|
searchDateTime = Convert.ToDateTime(input.BegineTime);
|
};
|
|
//如果有时间参数 查询当天的快照汇总信息
|
var allStockSnapshotList = await _wmsStockSnapshotGroupRep.AsQueryable()
|
.WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), u =>
|
u.AreaCode.Contains(input.SearchKey.Trim())
|
|| u.MaterialCode.Contains(input.SearchKey.Trim())
|
)
|
// .WhereIF(searchDateTime!=null, p => p.SnapshotDate<= searchDateTime)
|
.WhereIF(searchDateTime != null, p => p.CreateTime <= searchDateTime)
|
.WhereIF(!string.IsNullOrWhiteSpace(input.AreaCode), p => p.AreaCode.Contains(input.AreaCode))
|
.WhereIF(!string.IsNullOrWhiteSpace(input.MaterialCode), p => p.MaterialCode.Contains(input.MaterialCode))
|
.WhereIF(input.SnapshotId > 0, p => p.SnapshotId == input.SnapshotId) //ly0813-库存快照明细页面用
|
.OrderByDescending(p => p.SnapshotDate)
|
.ToListAsync();
|
|
|
if (allStockSnapshotList.Count()==0) throw Oops.Oh("未找到库存快照");
|
//获取最接近当前查询时间点的快照日期
|
var recentlyStockSnapshot = allStockSnapshotList.OrderByDescending(p => p.CreateTime).FirstOrDefault();
|
|
//当前最近的库存快照
|
var currentStockSnapshotList = allStockSnapshotList
|
.Where( p => p.SnapshotDate == recentlyStockSnapshot.SnapshotDate)
|
.ToList();
|
|
//var wmsRecordTransList = await _repWmsRecordTrans.AsQueryable()
|
// .WhereIF(!string.IsNullOrWhiteSpace(input.BegineTime.ToString()),p => p.CreateTime >= TimeModel && p.CreateTime <= input.BegineTime)
|
// .WhereIF(!string.IsNullOrWhiteSpace(input.MaterialCode), p => p.MaterialCode == input.MaterialCode)
|
// .WhereIF(!string.IsNullOrWhiteSpace(input.AreaCode),p => p.ToAreaCode == input.AreaCode)
|
// .ToListAsync();
|
|
//如果有时间参数 查询快照当天凌晨开始到选择的时间点的事务
|
DateTime startSearchDateTime= Convert.ToDateTime(recentlyStockSnapshot.CreateTime);
|
DateTime? endSearchDateTime = searchDateTime;//选择的时间点
|
var wmsRecordTransList = await _repWmsRecordTrans.AsQueryable()
|
.Where(u=>u.SourceAreaCode != u.ToAreaCode)
|
.WhereIF(searchDateTime != null, p => p.CreateTime>= startSearchDateTime && p.CreateTime <= endSearchDateTime)
|
.WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), u =>
|
u.ToAreaCode.Contains(input.SearchKey.Trim())
|
|| u.SourceAreaCode.Contains(input.SearchKey.Trim())
|
|| u.MaterialCode.Contains(input.SearchKey.Trim())
|
)
|
.WhereIF(!string.IsNullOrWhiteSpace(input.MaterialCode), p => p.MaterialCode == input.MaterialCode)
|
.WhereIF(!string.IsNullOrWhiteSpace(input.AreaCode), p => p.ToAreaCode == input.AreaCode|| p.SourceAreaCode == input.AreaCode)
|
.ToListAsync();
|
|
|
//初始化事务记录中存在但是库存快照没有的物料信息,库存为0
|
var allStockSnapshotMaterialCodeList = allStockSnapshotList.Select(p => p.MaterialCode+p.AreaCode).Distinct().ToList();
|
//目标库区
|
var toAreaRecordTransMaterialList = wmsRecordTransList.Select(s=>new WmsStockSnapshotGroup() {
|
MaterialCode = s.MaterialCode,
|
MaterialName = s.MaterialName,
|
MaterialUnit = s.MaterialUnit,
|
Quantity = 0,
|
AreaCode = s.ToAreaCode,
|
AreaName= s.ToAreaName
|
|
|
}).Where(w=>!allStockSnapshotMaterialCodeList.Contains(w.MaterialCode+w.AreaCode)).ToList();
|
|
currentStockSnapshotList.AddRange(toAreaRecordTransMaterialList);
|
//来源库区
|
var sourceAreaRecordTransMaterialList = wmsRecordTransList.Select(s => new WmsStockSnapshotGroup()
|
{
|
MaterialCode = s.MaterialCode,
|
MaterialName = s.MaterialName,
|
MaterialUnit = s.MaterialUnit,
|
Quantity = 0,
|
AreaCode = s.SourceAreaCode,
|
AreaName = s.SourceAreaName
|
|
}).Where(w => !allStockSnapshotMaterialCodeList.Contains(w.MaterialCode+w.AreaCode)).ToList();
|
currentStockSnapshotList.AddRange(sourceAreaRecordTransMaterialList);
|
|
//循环快照库存,根据事务增减库存
|
foreach (var item in currentStockSnapshotList)
|
{
|
//--第二步:查询来源库区 = A的,变更数量 -= 源数量,库存 = CurQty - 变更数量
|
|
//来源库区等于库存的库区,目标库区不等于源库区的,表示是减库存
|
var sourceRecordTrans = wmsRecordTransList.Where( p => p.SourceAreaCode == item.AreaCode&&p.SourceAreaCode!=p.ToAreaCode && p.MaterialCode == item.MaterialCode).ToList();
|
//汇总扣减库存数
|
// var removeQty = sourceRecordTrans.Sum(p => p.ChangeQuantity);
|
var removeQty = sourceRecordTrans.Sum(p => p.ToQuantity);
|
item.Quantity-= (decimal)removeQty;
|
|
|
//-- 第三步:查询目标库区 = A的,变更数量 += 目标数量,库存 = CurQty + 变更数量
|
|
//目标库区等于库存的库区,目标库区不等于源库区的,表示是加库存
|
var toRecordTrans = wmsRecordTransList.Where(p => p.ToAreaCode == item.AreaCode && p.SourceAreaCode != p.ToAreaCode && p.MaterialCode == item.MaterialCode).ToList();
|
|
//汇总加库存数
|
// var addQty = toRecordTrans.Sum(p => p.ChangeQuantity);
|
var addQty = toRecordTrans.Sum(p => p.ToQuantity);
|
item.Quantity += (decimal)addQty;
|
|
var historicalStockModel = new HistoricalInventory()
|
{
|
MaterialCode = item.MaterialCode,
|
MaterialName = item.MaterialName,
|
MaterialUnit = item.MaterialUnit,
|
Quantity = item.Quantity,
|
AreaCode = item.AreaCode,
|
AreaName = item.AreaName,
|
};
|
HistoricalStockList.Add(historicalStockModel);
|
}
|
return HistoricalStockList.ToPagedList(input.Page, input.PageSize);
|
|
//foreach (var item in wmsRecordTransList)
|
//{
|
// //查询原来库区的库存快照,找到后进行对应库存数的增删
|
|
// var SourceAreaStock = StockSnapshotList.WhereIF(!string.IsNullOrWhiteSpace(item.SourceAreaCode), p => p.AreaCode == item.SourceAreaCode && p.MaterialCode == item.MaterialCode).FirstOrDefault();
|
|
// if (SourceAreaStock != null)
|
// {
|
// SourceAreaStock.Quantity = (decimal)(SourceAreaStock.Quantity - item.SourceQuantity);
|
// int index = StockSnapshotList.FindIndex(p => p.Id == SourceAreaStock.Id);
|
// StockSnapshotList[index] = SourceAreaStock;
|
// }
|
// var ToAreaStock = StockSnapshotList.WhereIF(!string.IsNullOrWhiteSpace(item.ToAreaCode), p => p.AreaCode == item.ToAreaCode && p.MaterialCode == item.MaterialCode).FirstOrDefault();
|
// //查询后续目标库区的库存快照,找到后进行库存的修改
|
|
// if (ToAreaStock != null)
|
// {
|
// ToAreaStock.Quantity = (decimal)(ToAreaStock.Quantity + item.SourceQuantity);
|
// int index = StockSnapshotList.FindIndex(p => p.Id == ToAreaStock.Id);
|
// StockSnapshotList[index] = ToAreaStock;
|
// }
|
//}
|
//var HistoricalStockList = new List<HistoricalInventory>();
|
//foreach(var item in StockSnapshotList)
|
//{
|
// var historicalStockModel = new HistoricalInventory()
|
// {
|
// MaterialCode = item.MaterialCode,
|
// MaterialName = item.MaterialName,
|
// MaterialUnit = item.MaterialUnit,
|
// Quantity = item.Quantity,
|
// AreaCode = item.AreaCode,
|
// AreaName = item.AreaName,
|
// };
|
// HistoricalStockList.Add(historicalStockModel);
|
//}
|
|
|
|
//var returnInfo = StockSnapshotList.GroupBy(p => p.AreaCode) // 根据 A 字段进行分组
|
// .Select(g => new HistoricalInventory()
|
// {
|
// AreaCode = g.Key, // 分组的键,即 A 字段的值
|
// AreaName =
|
|
// = g.Sum(s => s.Number) // 计算每组中 Number 字段的总和
|
// });
|
//return HistoricalStockList.ToPagedList(input.Page, input.PageSize);
|
}
|
|
|
/// <summary>
|
/// 分页查询库存快照
|
/// </summary>
|
/// <param name="input"></param>
|
/// <returns></returns>
|
[HttpPost]
|
[ApiDescriptionSettings(Name = "Page")]
|
[Description("WmsStockSnapshot/Page")]
|
public async Task<SqlSugarPagedList<WmsStockSnapshotOutput>> Page(WmsStockSnapshotInput input)
|
{
|
var query = CommonPageFilter(input);
|
return await query.OrderBuilder(input, "", "SnapshotDate").ToPagedListAsync(input.Page, input.PageSize);
|
}
|
|
|
#region 私有方法
|
/// <summary>
|
/// 公共查询库存快照条件
|
/// </summary>
|
/// <param name="input"></param>
|
/// <returns></returns>
|
private ISugarQueryable<WmsStockSnapshotOutput> CommonPageFilter(WmsStockSnapshotInput input)
|
{
|
var query = _wmsStockSnapshotRep.AsQueryable()
|
.WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), u =>
|
u.SnapshotNo.Contains(input.SearchKey.Trim())
|
|| u.Remark.Contains(input.SearchKey.Trim())
|
|| u.CreateUserName.Contains(input.SearchKey.Trim())
|
|| u.UpdateUserName.Contains(input.SearchKey.Trim())
|
|| u.SnapshotDate.Contains(input.SearchKey.Trim())
|
)
|
.WhereIF(!string.IsNullOrWhiteSpace(input.SnapshotNo), u => u.SnapshotNo.Contains(input.SnapshotNo.Trim()))
|
.WhereIF(!string.IsNullOrWhiteSpace(input.SnapshotDate), u => u.SnapshotDate.Contains(input.SnapshotDate.Trim()))
|
.Select<WmsStockSnapshotOutput>();
|
return query;
|
}
|
|
/// <summary>
|
/// 重复性验证
|
/// </summary>
|
/// <param name="input">验证对象</param>
|
/// <param name="isEdit">是否是编辑</param>
|
/// <returns></returns>
|
private async Task CheckExist(WmsStockSnapshot input, bool isEdit = false)
|
{
|
//没有配置组合校验,不需要验重
|
//没有配置单独校验,不需要验重
|
}
|
|
/// <summary>
|
/// 根据组合校验和单独校验验证数据是否已存在-导入时验证
|
/// </summary>
|
/// <param name="inputs"></param>
|
/// <returns></returns>
|
private async Task CheckExisitForImport(List<WmsStockSnapshot> inputs)
|
{
|
if (inputs?.Count <= 0)
|
{
|
throw Oops.Oh($"导入数据不能为空");
|
}
|
//根据组合校验验证表格中中是否已存在相同数据
|
//根据单独校验验证表格中中是否已存在相同数据
|
}
|
#endregion
|
}
|