|
|
@@ -1,9 +1,12 @@
|
|
|
using Business.Core.Utilities;
|
|
|
+using Business.Domain;
|
|
|
using Business.Dto;
|
|
|
+using Business.EntityFrameworkCore.SqlRepositories;
|
|
|
using Business.StructuredDB.WMS;
|
|
|
using Newtonsoft.Json;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
using System.Threading.Tasks;
|
|
|
using Volo.Abp.Application.Services;
|
|
|
using Volo.Abp.DependencyInjection;
|
|
|
@@ -26,6 +29,47 @@ namespace Business.DOP
|
|
|
/// 平台库存表
|
|
|
/// </summary>
|
|
|
private readonly IRepository<WMS_PlatformInventory, long> _PlatformInventory;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// SAP库存表
|
|
|
+ /// </summary>
|
|
|
+ private readonly ISqlRepository<SAPInv> _sapInvRepository;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// SAP库存表
|
|
|
+ /// </summary>
|
|
|
+ private readonly ISqlRepository<ItemMaster> _itemMasterRepository;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 国内终端预测
|
|
|
+ /// </summary>
|
|
|
+ private IRepository<DomesticTerminalFcst, long> _domesticTerminalFcst;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 海外销售预测
|
|
|
+ /// </summary>
|
|
|
+ private IRepository<OverseasSaleFcst, long> _overseasSaleFcst;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 标准物料规格型号设置表
|
|
|
+ /// </summary>
|
|
|
+ private IRepository<StandardItemModelSet, long> _standardItemModelSet;
|
|
|
+
|
|
|
+ private IRepository<PlatStockMonitorSetting, long> _platStockMonitorSetting;
|
|
|
+
|
|
|
+ private IRepository<YearDemandManagement, long> _yearDemandManagement;
|
|
|
+
|
|
|
+ private IRepository<ic_item, long> _ic_item;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 平台预测收集
|
|
|
+ /// </summary>
|
|
|
+ private IRepository<PlatformFcstCollect, long> _platformFcstCollect;
|
|
|
+ /// <summary>
|
|
|
+ /// 节假日记录表
|
|
|
+ /// </summary>
|
|
|
+ private ISqlRepository<HolidayMaster> _holidayMaster;
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// 雪花算法
|
|
|
/// </summary>
|
|
|
@@ -34,6 +78,8 @@ namespace Business.DOP
|
|
|
/// 事务
|
|
|
/// </summary>
|
|
|
private readonly IUnitOfWorkManager _unitOfWorkManager;
|
|
|
+
|
|
|
+ private readonly ICurrentTenant _currentTenant;
|
|
|
#endregion
|
|
|
#region 构造函数
|
|
|
/// <summary>
|
|
|
@@ -42,12 +88,33 @@ namespace Business.DOP
|
|
|
public SyncDOPAppService(
|
|
|
IRepository<WMS_PlatformSpecificationComparison, long> PlatformSpecificationComparison,
|
|
|
IRepository<WMS_PlatformInventory, long> PlatformInventory,
|
|
|
- IUnitOfWorkManager unitOfWorkManager,
|
|
|
- ICurrentTenant currentTenant
|
|
|
+ ISqlRepository<SAPInv> sapInvRepository,
|
|
|
+ IRepository<DomesticTerminalFcst, long> domesticTerminalFcst,
|
|
|
+ IRepository<OverseasSaleFcst, long> overseasSaleFcst,
|
|
|
+ IRepository<StandardItemModelSet, long> standardItemModelSet,
|
|
|
+ ISqlRepository<ItemMaster> itemMasterRepository,
|
|
|
+ IRepository<PlatStockMonitorSetting, long> platStockMonitorSetting,
|
|
|
+ IRepository<YearDemandManagement, long> yearDemandManagement,
|
|
|
+ IRepository<PlatformFcstCollect, long> platformFcstCollect,
|
|
|
+ ISqlRepository<HolidayMaster> holidayMaster,
|
|
|
+ IRepository<ic_item, long> ic_item,
|
|
|
+ IUnitOfWorkManager unitOfWorkManager,
|
|
|
+ ICurrentTenant currentTenant
|
|
|
)
|
|
|
{
|
|
|
_PlatformSpecificationComparison = PlatformSpecificationComparison;
|
|
|
_PlatformInventory = PlatformInventory;
|
|
|
+ _sapInvRepository = sapInvRepository;
|
|
|
+ _domesticTerminalFcst = domesticTerminalFcst;
|
|
|
+ _overseasSaleFcst = overseasSaleFcst;
|
|
|
+ _standardItemModelSet = standardItemModelSet;
|
|
|
+ _itemMasterRepository = itemMasterRepository;
|
|
|
+ _platStockMonitorSetting = platStockMonitorSetting;
|
|
|
+ _yearDemandManagement=yearDemandManagement;
|
|
|
+ _holidayMaster = holidayMaster;
|
|
|
+ _platformFcstCollect = platformFcstCollect;
|
|
|
+ _ic_item = ic_item;
|
|
|
+ _currentTenant = currentTenant;
|
|
|
_unitOfWorkManager = unitOfWorkManager;
|
|
|
}
|
|
|
#endregion
|
|
|
@@ -130,5 +197,211 @@ namespace Business.DOP
|
|
|
}
|
|
|
return JsonConvert.SerializeObject("ok");
|
|
|
}
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 库存监控数据报表接口
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<string> InventoryMonitoring(InputDto input)
|
|
|
+ {
|
|
|
+ List<InventoryMonitoringDto> inventoryMonitoringDtos= new List<InventoryMonitoringDto>();
|
|
|
+ var ItemModelSetList = _standardItemModelSet.GetListAsync(a => a.tenant_id == input.tenant_id && a.company_id == input.company_id && !a.IsDeleted).Result;
|
|
|
+ if (ItemModelSetList == null)
|
|
|
+ {
|
|
|
+ new NLogHelper("SyncDOPAppService").WriteLog("InventoryMonitoring", "库存数据不存在", _currentTenant.Id.ToString());
|
|
|
+ //throw new NotImplementedException("订单数据不存在!");
|
|
|
+ return "库存数据不存在";
|
|
|
+ }
|
|
|
+ ItemModelSetList.ForEach(a =>
|
|
|
+ {
|
|
|
+ inventoryMonitoringDtos.Add(new InventoryMonitoringDto { Model=a.Model, ItemNumber=a.ItemNumber, FactoryInv=0,GKInv=0,HWInv=0, ReplenishCycle=a.ReplenishCycle });
|
|
|
+ });
|
|
|
+ var ItemList = ItemModelSetList.Select(a => a.ItemNumber);
|
|
|
+ var modelList = ItemModelSetList.Select(a => a.Model);
|
|
|
+ var ItemInvList = _sapInvRepository.Select(a => ItemList.Contains(a.MATNR) && a.WERKS == input.factory_id.ToString());
|
|
|
+ int year = DateTime.Now.AddMonths(1).Year;
|
|
|
+ int month = DateTime.Now.AddMonths(1).Month;
|
|
|
+ string planMonth = $"{year}-01";
|
|
|
+ string planMonthCurrent = $"{year}-{DateTime.Now.AddMonths(1).ToString("MM")}";
|
|
|
+ var platformInvList = _PlatformInventory.GetListAsync(a => modelList.Contains(a.SpecificationModel) && a.tenant_id == input.tenant_id && a.factory_id == input.factory_id).Result;
|
|
|
+ var yearDemandList= _yearDemandManagement.GetListAsync(a=>a.Year== year && a.PlanMonth == planMonth && a.tenant_id== input.tenant_id && a.company_id == input.company_id && !a.IsDeleted).Result;
|
|
|
+ List<HolidayMaster> holidays = _holidayMaster.Select(p => (p.Dated.Value.Year == year || p.Dated.Value.Year == (year + 1)) && p.Domain == input.factory_id.ToString() && p.IsActive);
|
|
|
+ List<ic_item> items = _ic_item.GetListAsync(p => ItemList.Contains(p.number) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
+ var platformFcstCollectList= _platformFcstCollect.GetListAsync(p=>p.PlanMonth== planMonthCurrent && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
+ var platStockMonitorSettingList = _platStockMonitorSetting.GetListAsync(p => p.PlanMonth == planMonthCurrent && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
+ var domesticTerminalFcstList = _domesticTerminalFcst.GetListAsync(p => p.PlanMonth == planMonthCurrent && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
+ inventoryMonitoringDtos.ForEach(a =>
|
|
|
+ {
|
|
|
+ //产品线和系列
|
|
|
+ var itemProdRange = yearDemandList.Find(b => b.Model == a.Model);
|
|
|
+ if (itemProdRange != null)
|
|
|
+ a.ProLine = itemProdRange.ProdLine;
|
|
|
+ a.Series= itemProdRange.ProdRange;
|
|
|
+
|
|
|
+ //工厂库存
|
|
|
+ var itemSap = ItemInvList.Find(b => b.MATNR == a.ItemNumber);
|
|
|
+ if(itemSap!=null)
|
|
|
+ a.FactoryInv = itemSap.LABST.ToDecimal();
|
|
|
+ //国科库存
|
|
|
+ var platformInventoryGK= platformInvList.Find(b => b.SpecificationModel == a.Model && b.Code== "HW0002");
|
|
|
+ if (platformInventoryGK != null)
|
|
|
+ a.GKInv = platformInventoryGK.InventoryQuantity;
|
|
|
+ //海王库存
|
|
|
+ var platformInventoryHW = platformInvList.Find(b => b.SpecificationModel == a.Model && b.Code == "HW0001");
|
|
|
+ if (platformInventoryHW != null)
|
|
|
+ a.HWInv = platformInventoryHW.InventoryQuantity;
|
|
|
+
|
|
|
+ //全域库存
|
|
|
+ a.TotalInv = a.FactoryInv + a.GKInv + a.HWInv;
|
|
|
+
|
|
|
+ //T1月需求
|
|
|
+ var t1 = domesticTerminalFcstList.Find(a => a.TypeEnum == 2);
|
|
|
+ if (t1 != null)
|
|
|
+ {
|
|
|
+ a.T1MonthlyDemand = t1.Qty;
|
|
|
+ }
|
|
|
+ //T1补货点
|
|
|
+ decimal rop = 0.0m;
|
|
|
+ //获取当月天数
|
|
|
+ int days = DateTime.DaysInMonth(year, month);
|
|
|
+ //计算当前月的周末天数
|
|
|
+ int weeks = CalcWeekDays(days, DateTime.Now.AddDays(1 - DateTime.Now.Day).AddMonths(1));
|
|
|
+ //获取当前年月的节假日设置
|
|
|
+ var curHolidays = holidays.Where(p => p.Dated.Value.Year == DateTime.Now.AddMonths(1).Year && p.Dated.Value.Month == DateTime.Now.AddMonths(1).Month).ToList();
|
|
|
+ //当月工作天数
|
|
|
+ int workDays = days - weeks - curHolidays.Where(p => p.Ufld1 == "休假").Count() + curHolidays.Where(p => p.Ufld1 == "调班").Count();
|
|
|
+ decimal packQty = 1m;//最小包装单位
|
|
|
+ var curItem = items.FirstOrDefault(p => p.number == a.ItemNumber);
|
|
|
+ packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
|
|
|
+ //rop = (需求量/月工作天数*补货周期)=>按照最小包装单位元整
|
|
|
+ rop = Math.Ceiling(a.T1MonthlyDemand / workDays * a.ReplenishCycle / packQty) * packQty;
|
|
|
+ a.ReplenishmentPoint = rop;
|
|
|
+
|
|
|
+ //国科预估需求
|
|
|
+ var gk = domesticTerminalFcstList.Find(a => a.TypeEnum == 5);
|
|
|
+ if (gk != null)
|
|
|
+ {
|
|
|
+ a.GKEstimatedDemand = gk.Qty;
|
|
|
+ }
|
|
|
+ //海王预估需求
|
|
|
+ var hw = domesticTerminalFcstList.Find(a => a.TypeEnum == 4);
|
|
|
+ if (hw != null)
|
|
|
+ {
|
|
|
+ a.HWEstimatedDemand = hw.Qty;
|
|
|
+ }
|
|
|
+ //T2总体需求
|
|
|
+ //a.TotalDemand = a.GKEstimatedDemand + a.HWEstimatedDemand;
|
|
|
+ var t2 = domesticTerminalFcstList.Find(a => a.TypeEnum == 3);
|
|
|
+ if (t2 != null)
|
|
|
+ {
|
|
|
+ a.T2TotalDemand = t2.Qty;
|
|
|
+ }
|
|
|
+ //总终端需求
|
|
|
+ a.TotalTerminalDemand = a.T1MonthlyDemand + a.ReplenishmentPoint + a.GKEstimatedDemand + a.HWEstimatedDemand + a.T2TotalDemand;
|
|
|
+ //工厂平台覆盖月
|
|
|
+ a.FactoryCoveragePlatformMonth = a.FactoryInv / a.T1MonthlyDemand;
|
|
|
+ //国科库存最高最低覆盖月
|
|
|
+ var prodTypeGK=platformFcstCollectList?.Find(a => a.Model == a.Model && a.Platform == "国科");
|
|
|
+ if(prodTypeGK!=null)
|
|
|
+ {
|
|
|
+ var prodTypeSettingGK = platStockMonitorSettingList?.Find(a => a.ProdType == prodTypeGK.ProdType && a.Platform == "国科");
|
|
|
+ if(prodTypeSettingGK!=null)
|
|
|
+ {
|
|
|
+ a.GKCoverageMaxMonth = prodTypeSettingGK.MaxTimes;
|
|
|
+ a.GKCoverageMinMonth = prodTypeSettingGK.MinTimes;
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ a.GKCoverageMaxMonth = 0;
|
|
|
+ a.GKCoverageMinMonth = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //国科库存覆盖月
|
|
|
+ a.GKCoverageMonth = a.GKInv / a.GKEstimatedDemand;
|
|
|
+
|
|
|
+
|
|
|
+ //海王库存最高最低覆盖月
|
|
|
+ var prodTypeHW = platformFcstCollectList?.Find(a => a.Model == a.Model && a.Platform == "海王");
|
|
|
+ if (prodTypeHW != null)
|
|
|
+ {
|
|
|
+ var prodTypeSettingHW = platStockMonitorSettingList?.Find(a => a.ProdType == prodTypeHW.ProdType && a.Platform == "海王");
|
|
|
+ if(prodTypeSettingHW != null)
|
|
|
+ {
|
|
|
+ a.GKCoverageMaxMonth = prodTypeSettingHW.MaxTimes;
|
|
|
+ a.GKCoverageMinMonth = prodTypeSettingHW.MinTimes;
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ a.GKCoverageMaxMonth = 0;
|
|
|
+ a.GKCoverageMinMonth = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //海王库存覆盖月
|
|
|
+ a.HWCoverageMonth = a.HWInv / a.HWEstimatedDemand;
|
|
|
+ //全域覆盖
|
|
|
+ a.TotalCoverageMonth = a.TotalInv / a.TotalTerminalDemand;
|
|
|
+
|
|
|
+ //T1库存监控
|
|
|
+ if (a.FactoryInv < a.ReplenishmentPoint)
|
|
|
+ {
|
|
|
+ a.T1MonitoringResult = "按照补货点补货";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ a.T1MonitoringResult = a.FactoryCoveragePlatformMonth > 6 ? "库存超出6个月阈值" : "正常覆盖范围";
|
|
|
+ }
|
|
|
+ //国科库存监控
|
|
|
+ a.GKMonitoringResult = a.GKCoverageMonth > a.GKCoverageMaxMonth ? "库存高于最高库存水位警戒" : a.GKCoverageMonth < a.GKCoverageMinMonth ? "库存低于最低库存水位,紧急补货" : "正常周转";
|
|
|
+ //海王库存监控
|
|
|
+ a.HWMonitoringResult = a.HWCoverageMonth > a.HWCoverageMaxMonth ? "库存高于最高库存水位警戒" : a.HWCoverageMonth < a.HWCoverageMinMonth ? "库存低于最低库存水位,紧急补货" : "正常周转";
|
|
|
+
|
|
|
+ //推荐决策
|
|
|
+ if (a.TotalCoverageMonth < 3)
|
|
|
+ {
|
|
|
+ a.RecommendDecision = "紧急补货";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ if (a.TotalCoverageMonth < 6)
|
|
|
+ {
|
|
|
+ a.RecommendDecision = "需要补货";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ if (a.TotalCoverageMonth < 9)
|
|
|
+ {
|
|
|
+ a.RecommendDecision = "正常库存";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ if (a.TotalCoverageMonth < 24)
|
|
|
+ {
|
|
|
+ a.RecommendDecision = "关注库存";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ a.RecommendDecision = "呆滞";
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return JsonConvert.SerializeObject(inventoryMonitoringDtos);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 计算当月有多少个周末
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="days"></param>
|
|
|
+ /// <param name="startDay"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private int CalcWeekDays(int days, DateTime startDay)
|
|
|
+ {
|
|
|
+ int sumDays = 0;
|
|
|
+ for (int i = 0; i < days; i++)
|
|
|
+ {
|
|
|
+ int weekDays = (int)startDay.AddDays(i).DayOfWeek;
|
|
|
+ if (weekDays == 0 || weekDays == 6)
|
|
|
+ {
|
|
|
+ sumDays++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return sumDays;
|
|
|
+ }
|
|
|
}
|
|
|
}
|