|
|
@@ -1,11 +1,16 @@
|
|
|
-using Business.Core.Utilities;
|
|
|
+using Azure.Identity;
|
|
|
+using Business.Core.Utilities;
|
|
|
using Business.Domain;
|
|
|
using Business.Dto;
|
|
|
using Business.EntityFrameworkCore.SqlRepositories;
|
|
|
+using Business.ResourceExamineManagement.Dto;
|
|
|
using Business.SaleForecast;
|
|
|
+using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
|
+using Spire.Pdf.General.Render.Decode.Jpeg2000.j2k.quantization;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
+using System.Runtime.CompilerServices;
|
|
|
using System.Threading.Tasks;
|
|
|
using Volo.Abp.Application.Services;
|
|
|
using Volo.Abp.DependencyInjection;
|
|
|
@@ -26,11 +31,6 @@ namespace Business.SaleForecastManagement
|
|
|
/// </summary>
|
|
|
private IRepository<ic_item, long> _ic_item;
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// 整体需求计划明细
|
|
|
- /// </summary>
|
|
|
- private ISqlRepository<OverallDemandPlanDtl> _overallDemandPlanDtl;
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// 生产线明细
|
|
|
/// </summary>
|
|
|
@@ -76,6 +76,11 @@ namespace Business.SaleForecastManagement
|
|
|
/// </summary>
|
|
|
private IRepository<YearDemandManagement, long> _yearDemandManagement;
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 年度生产需求大纲历史记录
|
|
|
+ /// </summary>
|
|
|
+ private IRepository<YearDemandManagementHistory, long> _yearDemandManagementHistory;
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// 国内终端预测
|
|
|
/// </summary>
|
|
|
@@ -96,6 +101,21 @@ namespace Business.SaleForecastManagement
|
|
|
/// </summary>
|
|
|
private IRepository<StandardItemModelSet,long> _standardItemModelSet;
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 库存明细表
|
|
|
+ /// </summary>
|
|
|
+ private ISqlRepository<LocationDetail> _locationDetail;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 工单
|
|
|
+ /// </summary>
|
|
|
+ private ISqlRepository<WorkOrdMaster> _workOrdMaster;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 整体需求计划
|
|
|
+ /// </summary>
|
|
|
+ private IRepository<OverallDemandPlan, long> _overallDemandPlan;
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// 雪花算法
|
|
|
/// </summary>
|
|
|
@@ -108,7 +128,6 @@ namespace Business.SaleForecastManagement
|
|
|
/// </summary>
|
|
|
public MonthlyCapacityLoadAppService(
|
|
|
IRepository<ic_item, long> ic_item,
|
|
|
- ISqlRepository<OverallDemandPlanDtl> overallDemandPlanDtl,
|
|
|
ISqlRepository<ProdLineDetail> prodLineDetail,
|
|
|
ISqlRepository<ShopCalendarWorkCtr> shopCalendarWorkCtr,
|
|
|
ISqlRepository<QualityLineWorkDetail> qualityLineWorkDetail,
|
|
|
@@ -121,11 +140,14 @@ namespace Business.SaleForecastManagement
|
|
|
IRepository<YearDemandManagement, long> yearDemandManagement,
|
|
|
IRepository<DomesticTerminalFcst, long> domesticTerminalFcst,
|
|
|
IRepository<OverseasSaleFcst, long> overseasSaleFcst,
|
|
|
- IRepository<PlatformFcstCollect, long> platformFcstCollect
|
|
|
+ IRepository<PlatformFcstCollect, long> platformFcstCollect,
|
|
|
+ IRepository<YearDemandManagementHistory, long> yearDemandManagementHistory,
|
|
|
+ ISqlRepository<LocationDetail> locationDetail,
|
|
|
+ ISqlRepository<WorkOrdMaster> workOrdMaster,
|
|
|
+ IRepository<OverallDemandPlan, long> overallDemandPlan
|
|
|
)
|
|
|
{
|
|
|
_ic_item = ic_item;
|
|
|
- _overallDemandPlanDtl = overallDemandPlanDtl;
|
|
|
_prodLineDetail = prodLineDetail;
|
|
|
_shopCalendarWorkCtr = shopCalendarWorkCtr;
|
|
|
_qualityLineWorkDetail = qualityLineWorkDetail;
|
|
|
@@ -137,8 +159,12 @@ namespace Business.SaleForecastManagement
|
|
|
_standardItemModelSet = standardItemModelSet;
|
|
|
_yearDemandManagement= yearDemandManagement;
|
|
|
_domesticTerminalFcst= domesticTerminalFcst;
|
|
|
- _overallDemandPlanDtl= overallDemandPlanDtl;
|
|
|
+ _overseasSaleFcst = overseasSaleFcst;
|
|
|
_platformFcstCollect= platformFcstCollect;
|
|
|
+ _yearDemandManagementHistory= yearDemandManagementHistory;
|
|
|
+ _locationDetail = locationDetail;
|
|
|
+ _workOrdMaster = workOrdMaster;
|
|
|
+ _overallDemandPlan = overallDemandPlan;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
@@ -263,25 +289,25 @@ namespace Business.SaleForecastManagement
|
|
|
// return "OK|发布成功!";
|
|
|
//}
|
|
|
|
|
|
- ///// <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;
|
|
|
- //}
|
|
|
+ /// <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;
|
|
|
+ }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 月度需求预测更新
|
|
|
@@ -291,66 +317,415 @@ namespace Business.SaleForecastManagement
|
|
|
/// <exception cref="NotImplementedException"></exception>
|
|
|
public async Task<string> DemandAnalysis(InputDto input)
|
|
|
{
|
|
|
- //1.0 获取年度生产需求大纲
|
|
|
- List<YearDemandManagement> yearDemands = _yearDemandManagement.GetListAsync(p => p.Year == input.year && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
- if (yearDemands.Count() == 0)
|
|
|
- {
|
|
|
- new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年年度生产需求数据后再操作!", _currentTenant.Id.ToString());
|
|
|
- return "NO|请导入" + input.year + "年年度生产需求数据后再操作!";
|
|
|
- }
|
|
|
+ //1.0 获取当前年年度生产需求大纲
|
|
|
+ List<YearDemandManagement> yearDemands = _yearDemandManagement.GetListAsync(p => p.Year == input.year && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p=>p.OrderNum).ToList();
|
|
|
+ //1.0 获取下一年年度生产大纲
|
|
|
+ List<YearDemandManagement> nextYearDemands = _yearDemandManagement.GetListAsync(p => p.Year == (input.year+1) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p => p.OrderNum).ToList();
|
|
|
+ //记录历史版本:当前年+下一年
|
|
|
+ var updateMonth = input.year.ToString() + "-" + input.month.ToString("00");
|
|
|
+ var histories = ObjectMapper.Map<List<YearDemandManagement>, List<YearDemandManagementHistory>>(yearDemands);
|
|
|
+ histories.ForEach(p => {
|
|
|
+ p.UpdateMonth = updateMonth;
|
|
|
+ });
|
|
|
+ var nextHistories = ObjectMapper.Map<List<YearDemandManagement>, List<YearDemandManagementHistory>>(nextYearDemands);
|
|
|
+ nextHistories.ForEach(p => {
|
|
|
+ p.UpdateMonth = updateMonth;
|
|
|
+ });
|
|
|
//1.1、获取海外销售预测数据
|
|
|
List<OverseasSaleFcst> overseasSales = _overseasSaleFcst.GetListAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
- if (overseasSales.Count() == 0)
|
|
|
- {
|
|
|
- new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入"+input.year+"年"+input.month+"月海外预测数据后再操作!", _currentTenant.Id.ToString());
|
|
|
- return "NO|请导入"+input.year+"年"+input.month+"月海外预测数据后再操作!";
|
|
|
- }
|
|
|
//1.2、获取平台预测收集数据
|
|
|
List<PlatformFcstCollect> platformFcsts = _platformFcstCollect.GetListAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
- if (platformFcsts.Count() == 0)
|
|
|
- {
|
|
|
- new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月平台需求预测数据后再操作!", _currentTenant.Id.ToString());
|
|
|
- return "NO|请导入" + input.year + "年" + input.month + "月平台需求预测数据后再操作!";
|
|
|
- }
|
|
|
//1.3、获取国内终端预测-T1汇总数据
|
|
|
- List<DomesticTerminalFcst> domesticFcst = _domesticTerminalFcst.GetListAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
- if (domesticFcst.Count() == 0)
|
|
|
+ List<DomesticTerminalFcst> domesticFcst = _domesticTerminalFcst.GetListAsync(p =>p.TypeEnum == 2 && p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
+ //1.4、根据年度生产大纲,获取规格型号对应的补货周期
|
|
|
+ List<string> allModels = yearDemands.Select(p=>p.Model).Distinct().ToList();
|
|
|
+ if (nextYearDemands.Any())
|
|
|
{
|
|
|
- new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月国内终端预测数据后再操作!", _currentTenant.Id.ToString());
|
|
|
- return "NO|请导入" + input.year + "年" + input.month + "月国内终端预测数据后再操作!";
|
|
|
+ allModels.AddRange(nextYearDemands.Select(p => p.Model).ToList());
|
|
|
+ allModels = allModels.Distinct().ToList();
|
|
|
}
|
|
|
- //1.4、根据年度生产大纲,获取规格型号对应的补货周期
|
|
|
- List<string> models = yearDemands.Select(p=>p.Model).Distinct().ToList();
|
|
|
- List<StandardItemModelSet> standards = _standardItemModelSet.GetListAsync(p=>models.Contains(p.Model) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
- //1.5、获取规格型号对应的标准SKU数据
|
|
|
+ List<StandardItemModelSet> standards = _standardItemModelSet.GetListAsync(p => allModels.Contains(p.Model) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
+ //1.5、获取规格型号对应的标准SKU数据:获取最小包装单位
|
|
|
List<string> itemNums = standards.Select(p=>p.ItemNumber).Distinct().ToList();
|
|
|
List<ic_item> items = _ic_item.GetListAsync(p=> itemNums.Contains(p.number) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
|
|
|
+ //1.6、获取成品库存、灭菌库存
|
|
|
+ //List<LocationDetail> locations = _locationDetail.Select(p=>p.Domain == input.factory_id.ToString() && p.IsActive && itemNums.Contains(p.ItemNum));
|
|
|
+ //1.7、获取在制库存:计划开始时间、计划结束时间都在本月,并且未关闭的工单
|
|
|
+ //DateTime monStart = Convert.ToDateTime(input.year + "-" + input.month + "-01");
|
|
|
+ //DateTime monEnd = monStart.AddMonths(1).AddDays(-1);
|
|
|
+ //List<WorkOrdMaster> workOrds = _workOrdMaster.Select(p=>p.Domain);
|
|
|
+ //1.9、获取节假日设置
|
|
|
+ List<HolidayMaster> holidays = _holidayMaster.Select(p => (p.Dated.Value.Year == input.year || p.Dated.Value.Year == (input.year + 1)) && p.Domain == input.factory_id.ToString() && p.IsActive);
|
|
|
+
|
|
|
+ #region 数据校验
|
|
|
+ //1、校验当前年的年度生产大纲是否导入
|
|
|
+ if (!yearDemands.Any())
|
|
|
+ {
|
|
|
+ new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年的年度生产需求后再操作!", _currentTenant.Id.ToString());
|
|
|
+ return "NO|请导入" + input.year + "年的年度生产需求后再操作!";
|
|
|
+ }
|
|
|
+ //2、如果当前月份大于10,则需校验下一年的年度生产大纲
|
|
|
+ if (input.month > 10 && !nextYearDemands.Any())
|
|
|
+ {
|
|
|
+ new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + (input.year+1) + "年的年度生产需求后再操作!", _currentTenant.Id.ToString());
|
|
|
+ return "NO|请导入" + (input.year + 1) + "年的年度生产需求后再操作!";
|
|
|
+ }
|
|
|
+ //3、校验当前月份的海外销售预测是否导入
|
|
|
+ if (!overseasSales.Any())
|
|
|
+ {
|
|
|
+ new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月海外销售预测后再操作!", _currentTenant.Id.ToString());
|
|
|
+ return "NO|请导入" + input.year + "年" + input.month + "月海外销售预测后再操作!";
|
|
|
+ }
|
|
|
+ //4、校验当前月份的平台预测收集是否导入
|
|
|
+ if (!platformFcsts.Any())
|
|
|
+ {
|
|
|
+ new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月平台需求收集后再操作!", _currentTenant.Id.ToString());
|
|
|
+ return "NO|请导入" + input.year + "年" + input.month + "月平台需求收集后再操作!";
|
|
|
+ }
|
|
|
+ //5、校验当前月份的国内终端预测是否导入
|
|
|
+ if (!domesticFcst.Any())
|
|
|
+ {
|
|
|
+ new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月国内终端预测后再操作!", _currentTenant.Id.ToString());
|
|
|
+ return "NO|请导入" + input.year + "年" + input.month + "月国内终端预测后再操作!";
|
|
|
+ }
|
|
|
+ //6、校验终端+平台导入的规格型号是否已维护标准SKU
|
|
|
+ if (allModels.Count() != standards.Count())
|
|
|
+ {
|
|
|
+ allModels.RemoveAll(standards.Select(p=>p.Model).ToList());
|
|
|
+ new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "规格型号【" + string.Join(",",allModels) + "】没有维护标准SKU,请维护后再操作!", _currentTenant.Id.ToString());
|
|
|
+ return "NO|规格型号【" + string.Join(",", allModels) + "】没有维护标准SKU,请维护后再操作!";
|
|
|
+ }
|
|
|
+ //7、校验是否已维护补货周期
|
|
|
+ var zeros = standards.Where(p => p.ReplenishCycle == 0).ToList();
|
|
|
+ if (zeros.Any())
|
|
|
+ {
|
|
|
+ new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "规格型号【" + string.Join(",", zeros.Select(p=>p.Model).ToList()) + "】没有维护补货周期,请维护后再操作!", _currentTenant.Id.ToString());
|
|
|
+ return "NO|规格型号【" + string.Join(",", zeros.Select(p => p.Model).ToList()) + "】没有维护补货周期,请维护后再操作!";
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ //计算当前年月的N+1,N+2
|
|
|
+ int newYear = input.month == 12 ? input.year + 1 : input.year;
|
|
|
+ int newMonth = input.month == 12 ? 1 : input.month + 1;
|
|
|
+ string strN1 = newYear.ToString() + "-" + newMonth.ToString("00");
|
|
|
+ newYear = newMonth == 12 ? newYear + 1 : newYear;
|
|
|
+ newMonth = newMonth == 12 ? 1 : newMonth + 1;
|
|
|
+ string strN2 = newYear.ToString() + "-" + newMonth.ToString("00");
|
|
|
|
|
|
- //计算海外预测
|
|
|
+ //需要回写的数据
|
|
|
+ List<YearDemandManagement> updates = new List<YearDemandManagement>();
|
|
|
+ #region 计算国内终端预测,回写年度生产大纲
|
|
|
+ //获取导入的T1、平台数据
|
|
|
+ List<string> gnModels = new List<string>();
|
|
|
+ if (domesticFcst.Any())
|
|
|
+ {
|
|
|
+ gnModels.AddRange(domesticFcst.Select(p => p.Model).ToList());
|
|
|
+ }
|
|
|
+ if (platformFcsts.Any())
|
|
|
+ {
|
|
|
+ gnModels.AddRange(platformFcsts.Select(p => p.Model).ToList());
|
|
|
+ }
|
|
|
+ gnModels = gnModels.Distinct().ToList();
|
|
|
+ foreach (var gnModel in gnModels)
|
|
|
+ {
|
|
|
+ //N+1月
|
|
|
+ YearDemandManagement monthN1 = new YearDemandManagement();
|
|
|
+ //N+2月
|
|
|
+ YearDemandManagement monthN2 = new YearDemandManagement();
|
|
|
+ //获取需要回写的数据
|
|
|
+ if (input.month < 11)
|
|
|
+ {
|
|
|
+ monthN1 = yearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN1);
|
|
|
+ monthN2 = yearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN2);
|
|
|
+ }
|
|
|
+ if (input.month == 11)
|
|
|
+ {
|
|
|
+ monthN1 = yearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN1);
|
|
|
+ monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN2);
|
|
|
+ }
|
|
|
+ if (input.month == 12)
|
|
|
+ {
|
|
|
+ monthN1 = nextYearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN1);
|
|
|
+ monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN2);
|
|
|
+ }
|
|
|
+ if (monthN1 == null || monthN2 == null)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ //T1
|
|
|
+ var sumT1N1 = domesticFcst.Where(p => p.Model == gnModel && p.PlanMonth == strN1).Sum(p=>p.Qty);
|
|
|
+ var sumT1N2 = domesticFcst.Where(p => p.Model == gnModel && p.PlanMonth == strN2).Sum(p => p.Qty);
|
|
|
+ //平台
|
|
|
+ var sumPN1 = platformFcsts.Where(p => p.Model == gnModel && p.PlanMonth == strN1).Sum(p => p.Qty);
|
|
|
+ var sumPN2 = platformFcsts.Where(p => p.Model == gnModel && p.PlanMonth == strN2).Sum(p => p.Qty);
|
|
|
+ //合计
|
|
|
+ var sumN1 = sumT1N1+ sumPN1;
|
|
|
+ var sumN2 = sumT1N2 + sumPN2;
|
|
|
+
|
|
|
+ //当前规格型号对应标准SKU的最小包装单位、补货周期
|
|
|
+ var curStd = standards.FirstOrDefault(p => p.Model == gnModel);
|
|
|
+ decimal packQty = 1m;//最小包装单位
|
|
|
+ decimal cycle = 0m;//补货周期
|
|
|
+ if (curStd != null)
|
|
|
+ {
|
|
|
+ var curItem = items.FirstOrDefault(p => p.number == curStd.ItemNumber);
|
|
|
+ packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
|
|
|
+ cycle = curStd.ReplenishCycle;
|
|
|
+ }
|
|
|
+ //TODO:获取成品库存、在制库存、灭菌库存,参与计算
|
|
|
+ //N+1月使用N+2月的再订货点参与计算
|
|
|
+ decimal rop = CalcRop(strN2+"-01", sumN2, packQty, holidays, cycle);
|
|
|
+ monthN1.Qty = Math.Ceiling((sumN1 / 2 + sumN2 / 2 + rop - 0 - 0 - 0) / packQty) * packQty;
|
|
|
+ //N+2月使用本月的需求量,下一月的工作天数
|
|
|
+ rop = CalcRop(Convert.ToDateTime(strN2 + "-01").AddMonths(1).ToString("yyyy-MM-dd"), sumN2, packQty, holidays, cycle);
|
|
|
+ monthN2.Qty = Math.Ceiling((sumN2 + rop - 0 - 0 - 0) / packQty) * packQty;
|
|
|
+ //负数置0
|
|
|
+ monthN1.Qty = monthN1.Qty < 0 ? 0m : monthN1.Qty;
|
|
|
+ monthN2.Qty = monthN2.Qty < 0 ? 0m : monthN2.Qty;
|
|
|
+ //记录需要回写的数据
|
|
|
+ updates.Add(monthN1);
|
|
|
+ updates.Add(monthN2);
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 海外销售预测,回写年度生产大纲
|
|
|
+ List<string> hwModels = overseasSales.Select(p => p.Model).Distinct().ToList();
|
|
|
+ foreach (var hwModel in hwModels)
|
|
|
+ {
|
|
|
+ //N+1月
|
|
|
+ YearDemandManagement monthN1 = new YearDemandManagement();
|
|
|
+ //N+2月
|
|
|
+ YearDemandManagement monthN2 = new YearDemandManagement();
|
|
|
+ //获取需要回写的数据
|
|
|
+ if (input.month < 11)
|
|
|
+ {
|
|
|
+ monthN1 = yearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN1);
|
|
|
+ monthN2 = yearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN2);
|
|
|
+ }
|
|
|
+ if (input.month == 11)
|
|
|
+ {
|
|
|
+ monthN1 = yearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN1);
|
|
|
+ monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN2);
|
|
|
+ }
|
|
|
+ if (input.month == 12)
|
|
|
+ {
|
|
|
+ monthN1 = nextYearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN1);
|
|
|
+ monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN2);
|
|
|
+ }
|
|
|
+ if (monthN1 == null || monthN2 == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ var sumN1 = overseasSales.Where(p => p.Model == hwModel && p.PlanMonth == strN1).Sum(p => p.Qty);
|
|
|
+ var sumN2 = overseasSales.Where(p => p.Model == hwModel && p.PlanMonth == strN2).Sum(p => p.Qty);
|
|
|
+
|
|
|
+ //当前规格型号对应标准SKU的最小包装单位、补货周期
|
|
|
+ var curStd = standards.FirstOrDefault(p => p.Model == hwModel);
|
|
|
+ decimal packQty = 1m;//最小包装单位
|
|
|
+ if (curStd != null)
|
|
|
+ {
|
|
|
+ var curItem = items.FirstOrDefault(p => p.number == curStd.ItemNumber);
|
|
|
+ packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
|
|
|
+ }
|
|
|
+ //海外生产需求量=当月的50%+下一月的50%-成品库存-在制库存-灭菌库存
|
|
|
+ //TODO:获取成品库存、在制库存、灭菌库存,参与运算
|
|
|
+ //计算N+1月,N+2月
|
|
|
+ monthN1.Qty = Math.Ceiling((sumN1 / 2 + sumN2 / 2 - 0 - 0 - 0) / packQty) * packQty;
|
|
|
+ monthN2.Qty = Math.Ceiling((sumN2 - 0 - 0 - 0) / packQty) *packQty; ;
|
|
|
+ //负数置0
|
|
|
+ monthN1.Qty = monthN1.Qty < 0 ? 0m : monthN1.Qty;
|
|
|
+ monthN2.Qty = monthN2.Qty < 0 ? 0m : monthN2.Qty;
|
|
|
+ //记录需要回写的数据
|
|
|
+ updates.Add(monthN1);
|
|
|
+ updates.Add(monthN2);
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ //保存数据
|
|
|
+ using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ //判断是否存在当前年月的历史版本,不存在则插入
|
|
|
+ var dbHistory = _yearDemandManagementHistory.GetListAsync(p=>p.Year ==input.year && p.UpdateMonth == updateMonth && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id).Result;
|
|
|
+ if (!dbHistory.Any())
|
|
|
+ {
|
|
|
+ await _yearDemandManagementHistory.InsertManyAsync(histories);
|
|
|
+ }
|
|
|
+ if (input.month > 10)
|
|
|
+ {
|
|
|
+ //判断是否存在下一年月的历史版本,不存在则插入
|
|
|
+ dbHistory = _yearDemandManagementHistory.GetListAsync(p =>(p.Year == input.year + 1) && p.UpdateMonth == updateMonth && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id).Result;
|
|
|
+ if (!dbHistory.Any())
|
|
|
+ {
|
|
|
+ await _yearDemandManagementHistory.InsertManyAsync(nextHistories);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //回写年度生产大纲
|
|
|
+ await _yearDemandManagement.UpdateManyAsync(updates);
|
|
|
+ await unitOfWork.CompleteAsync();
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ unitOfWork.Dispose();
|
|
|
+ new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "【" + input.year + "年" + input.month + "月】月度需求预测更新失败:" + e.Message, _currentTenant.Id.ToString());
|
|
|
+ return "NO|" + e.Message;
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return "OK|修订成功!";
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 计算再订货点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="planMonth">计划年月(yyyy-MM-dd)</param>
|
|
|
+ /// <param name="qty">需求量</param>
|
|
|
+ /// <param name="qty">最小包装数量</param>
|
|
|
+ /// <param name="holidays">节假日</param>
|
|
|
+ /// <param name="replenishCycle">补货周期</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private decimal CalcRop(string planMonth,decimal qty,decimal packQty,List<HolidayMaster> holidays,decimal replenishCycle)
|
|
|
+ {
|
|
|
+ decimal rop = 0.0m;
|
|
|
+ //获取当月天数
|
|
|
+ int year = Convert.ToInt16(planMonth.Substring(0, 4));
|
|
|
+ int month = Convert.ToInt16(planMonth.Substring(5, 2));
|
|
|
+ int days = DateTime.DaysInMonth(year, month);
|
|
|
+ //计算当前月的周末天数
|
|
|
+ int weeks = CalcWeekDays(days, Convert.ToDateTime(planMonth));
|
|
|
+ //获取当前年月的节假日设置
|
|
|
+ var curHolidays = holidays.Where(p => p.Dated.Value.Year == year && p.Dated.Value.Month == month).ToList();
|
|
|
+ //当月工作天数
|
|
|
+ int workDays = days - weeks - curHolidays.Where(p => p.Ufld1 == "休假").Count() + curHolidays.Where(p => p.Ufld1 == "调班").Count();
|
|
|
+ //rop = (需求量/月工作天数*补货周期)=>按照最小包装单位元整
|
|
|
+ rop = Math.Ceiling(qty / workDays * replenishCycle / packQty) * packQty;
|
|
|
+ return rop;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 生成整体需求计划
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="input"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ /// <exception cref="NotImplementedException"></exception>
|
|
|
+ public async Task<string> OverallDemandPlan(InputDto input)
|
|
|
+ {
|
|
|
+ //1.1、获取海外销售预测数据
|
|
|
+ List<OverseasSaleFcst> overseasSales = _overseasSaleFcst.GetListAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p => p.OrderNum).ToList();
|
|
|
+ //1.2、获取平台预测收集数据
|
|
|
+ List<PlatformFcstCollect> platformFcsts = _platformFcstCollect.GetListAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p=>p.OrderNum).ToList();
|
|
|
+ //1.3、获取国内终端预测-T1汇总数据
|
|
|
+ List<DomesticTerminalFcst> domesticFcsts = _domesticTerminalFcst.GetListAsync(p => p.TypeEnum == 2 && p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p => p.OrderNum).ToList();
|
|
|
+
|
|
|
+ //计算当前年月的N+1,N+2
|
|
|
+ string strN0 = input.year.ToString() + "-" + input.month.ToString("00");
|
|
|
+ int newYear = input.month == 12 ? input.year + 1 : input.year;
|
|
|
+ int newMonth = input.month == 12 ? 1 : input.month + 1;
|
|
|
+ string strN1 = newYear.ToString() + "-" + newMonth.ToString("00");
|
|
|
+ newYear = newMonth == 12 ? newYear + 1 : newYear;
|
|
|
+ newMonth = newMonth == 12 ? 1 : newMonth + 1;
|
|
|
+ string strN2 = newYear.ToString() + "-" + newMonth.ToString("00");
|
|
|
+
|
|
|
+ //整体需求计划
|
|
|
+ List<OverallDemandPlan> plans = new List<OverallDemandPlan>();
|
|
|
+ //计算海外
|
|
|
+ List<string> hwModels = overseasSales.Select(p => p.Model).Distinct().ToList();
|
|
|
+ int OrderNum = 1;
|
|
|
+ foreach (var item in hwModels)
|
|
|
+ {
|
|
|
+ var curFcsts = overseasSales.Where(p => p.Model == item).ToList();
|
|
|
+ OverallDemandPlan plan = new OverallDemandPlan();
|
|
|
+ plan.Area = "海外";
|
|
|
+ plan.Model = item;
|
|
|
+ plan.PlanMonth = strN0;
|
|
|
+ plan.Qty = curFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty);
|
|
|
+ plan.OrderNum = OrderNum;
|
|
|
+ plans.Add(plan);
|
|
|
+
|
|
|
+ plan = new OverallDemandPlan();
|
|
|
+ plan.Area = "海外";
|
|
|
+ plan.Model = item;
|
|
|
+ plan.PlanMonth = strN1;
|
|
|
+ plan.Qty = curFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty);
|
|
|
+ plan.OrderNum = OrderNum;
|
|
|
+ plans.Add(plan);
|
|
|
+
|
|
|
+ plan = new OverallDemandPlan();
|
|
|
+ plan.Area = "海外";
|
|
|
+ plan.Model = item;
|
|
|
+ plan.PlanMonth = strN2;
|
|
|
+ plan.Qty = curFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty);
|
|
|
+ plan.OrderNum = OrderNum;
|
|
|
+ plans.Add(plan);
|
|
|
+
|
|
|
+ OrderNum += 1;
|
|
|
+ }
|
|
|
+ //计算国内
|
|
|
+ List<string> gnModels = domesticFcsts.Select(p=>p.Model).ToList();
|
|
|
+ gnModels.AddRange(platformFcsts.Select(p => p.Model).ToList());
|
|
|
+ gnModels = gnModels.Distinct().ToList();
|
|
|
+ OrderNum = 1;
|
|
|
+ foreach (var item in gnModels)
|
|
|
+ {
|
|
|
+ var curDFcsts = domesticFcsts.Where(p => p.Model == item).ToList();
|
|
|
+ var curPFcsts = platformFcsts.Where(p => p.Model == item).ToList();
|
|
|
+ OverallDemandPlan plan = new OverallDemandPlan();
|
|
|
+ plan.Area = "国内";
|
|
|
+ plan.Model = item;
|
|
|
+ plan.PlanMonth = strN0;
|
|
|
+ plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty);
|
|
|
+ plan.OrderNum = OrderNum;
|
|
|
+ plans.Add(plan);
|
|
|
+
|
|
|
+ plan = new OverallDemandPlan();
|
|
|
+ plan.Area = "国内";
|
|
|
+ plan.Model = item;
|
|
|
+ plan.PlanMonth = strN1;
|
|
|
+ plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty);
|
|
|
+ plan.OrderNum = OrderNum;
|
|
|
+ plans.Add(plan);
|
|
|
+
|
|
|
+ plan = new OverallDemandPlan();
|
|
|
+ plan.Area = "国内";
|
|
|
+ plan.Model = item;
|
|
|
+ plan.PlanMonth = strN2;
|
|
|
+ plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty);
|
|
|
+ plan.OrderNum = OrderNum;
|
|
|
+ plans.Add(plan);
|
|
|
+
|
|
|
+ OrderNum += 1;
|
|
|
+ }
|
|
|
|
|
|
+ plans.ForEach(p => {
|
|
|
+ p.Year= input.year;
|
|
|
+ p.Month= input.month;
|
|
|
+ p.tenant_id = input.tenant_id;
|
|
|
+ p.company_id = input.company_id;
|
|
|
+ p.factory_id= input.factory_id;
|
|
|
+ p.org_id= input.org_id;
|
|
|
+ p.create_by = input.create_by;
|
|
|
+ p.create_by_name= input.create_by_name;
|
|
|
+ p.create_time = DateTime.Now;
|
|
|
+ });
|
|
|
|
|
|
//保存数据
|
|
|
using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
- ////先删除数据
|
|
|
- //_monthlyProdCapacityMain.Delete(p => p.tenant_id == input.tenant_id && p.factory_id == input.factory_id && p.Version.Contains(input.version.Substring(0, 7)));
|
|
|
- //_monthlyProdCapacityDtl.Delete(p => p.tenant_id == input.tenant_id && p.factory_id == input.factory_id && p.Version.Contains(input.version.Substring(0, 7)));
|
|
|
-
|
|
|
- ////插入数据
|
|
|
- //_monthlyProdCapacityMain.Insert(capacityMains);
|
|
|
- //_monthlyProdCapacityDtl.Insert(capacityDtls);
|
|
|
- //await unitOfWork.CompleteAsync();
|
|
|
+ //先删除
|
|
|
+ await _overallDemandPlan.HardDeleteAsync(p=>p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id);
|
|
|
+ //保存整体需求计划
|
|
|
+ await _overallDemandPlan.InsertManyAsync(plans);
|
|
|
+ await unitOfWork.CompleteAsync();
|
|
|
}
|
|
|
catch (Exception e)
|
|
|
{
|
|
|
unitOfWork.Dispose();
|
|
|
- new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("CapacityAnalysis", "生成【" + input.year + "年" + input.month + "月】月度产能共识失败:" + e.Message, _currentTenant.Id.ToString());
|
|
|
+ new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("OverallDemandPlan", "生成【" + input.year + "年" + input.month + "月】整体需求计划失败:" + e.Message, _currentTenant.Id.ToString());
|
|
|
return "NO|" + e.Message;
|
|
|
};
|
|
|
}
|
|
|
- return "OK|发布成功!";
|
|
|
+ return "OK|刷新成功!";
|
|
|
}
|
|
|
}
|
|
|
}
|