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; /// /// 库存快照 /// [ApiDescriptionSettings(ApplicationConst.WmsStockSnapshotDetailsGroupName, Order = 100)] public class WmsStockSnapshotService : IDynamicApiController, ITransient { private readonly SqlSugarRepository _v_wms_stock_quanrRep; private readonly SqlSugarRepository _wmsStockSnapshotRep; private readonly SqlSugarRepository _wmsStockSnapshotDetails; private readonly SqlSugarRepository _wmsStockSnapshotGroupRep; private readonly SqlSugarRepository _repWmsRecordTrans; private readonly SqlSugarRepository _wmsLogActionRep; private readonly SqlSugarRepository _wmsRecordTransRep; /// /// 构造函数 /// public WmsStockSnapshotService(SqlSugarRepository v_wms_stock_quanrRep, SqlSugarRepository wmsStockSnapshotRep, SqlSugarRepository wmsStockSnapshotDetails, SqlSugarRepository wmsLogActionRep, SqlSugarRepository wmsRecordTransRep, SqlSugarRepository wmsStockSnapshotGroupRep, SqlSugarRepository 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; } /// /// 获取库存快照分页 /// /// [HttpGet] [ApiDescriptionSettings(Name = "GetStockSnapshotPage", Description = "获取库存快照分页")] [Description("/WmsStockSnapshot/GetStockSnapshotPage")] public async Task GetStockSnapshotPage() { } /// /// 添加库存快照 /// /// [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(); 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(); 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 addWmsStockSnapshotGroupList = new List(); 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; } } } /// /// 历史库存查询 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "HistorialStockPage", Description = "历史库存查询")] [Description("/WmsStockSnapshot/HistorialStockPage")] public async Task> 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() { }; //} 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() { }; } // var newStockSnapshotList = new List(); //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(); 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(); //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); } /// /// 分页查询库存快照 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Page")] [Description("WmsStockSnapshot/Page")] public async Task> Page(WmsStockSnapshotInput input) { var query = CommonPageFilter(input); return await query.OrderBuilder(input, "", "SnapshotDate").ToPagedListAsync(input.Page, input.PageSize); } #region 私有方法 /// /// 公共查询库存快照条件 /// /// /// private ISugarQueryable 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(); return query; } /// /// 重复性验证 /// /// 验证对象 /// 是否是编辑 /// private async Task CheckExist(WmsStockSnapshot input, bool isEdit = false) { //没有配置组合校验,不需要验重 //没有配置单独校验,不需要验重 } /// /// 根据组合校验和单独校验验证数据是否已存在-导入时验证 /// /// /// private async Task CheckExisitForImport(List inputs) { if (inputs?.Count <= 0) { throw Oops.Oh($"导入数据不能为空"); } //根据组合校验验证表格中中是否已存在相同数据 //根据单独校验验证表格中中是否已存在相同数据 } #endregion }