MonthlyCapacityLoadAppService.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. using Azure.Identity;
  2. using Business.Core.Utilities;
  3. using Business.Domain;
  4. using Business.Dto;
  5. using Business.EntityFrameworkCore.SqlRepositories;
  6. using Business.ResourceExamineManagement.Dto;
  7. using Business.SaleForecast;
  8. using Business.StructuredDB.WMS;
  9. using Microsoft.CodeAnalysis.CSharp.Syntax;
  10. using Spire.Pdf.General.Render.Decode.Jpeg2000.j2k.quantization;
  11. using System;
  12. using System.Collections.Generic;
  13. using System.Linq;
  14. using System.Runtime.CompilerServices;
  15. using System.Threading.Tasks;
  16. using ThoughtWorks.QRCode.Geom;
  17. using Volo.Abp.Application.Services;
  18. using Volo.Abp.DependencyInjection;
  19. using Volo.Abp.Domain.Repositories;
  20. using Volo.Abp.MultiTenancy;
  21. using Volo.Abp.Uow;
  22. using Volo.Abp.Validation.Localization;
  23. namespace Business.SaleForecastManagement
  24. {
  25. /// <summary>
  26. /// 产能分析
  27. /// </summary>
  28. public class MonthlyCapacityLoadAppService : ApplicationService, IMonthlyCapacityLoadAppService, ITransientDependency
  29. {
  30. #region 服务
  31. /// <summary>
  32. /// 物料
  33. /// </summary>
  34. private IRepository<ic_item, long> _ic_item;
  35. /// <summary>
  36. /// 生产线明细
  37. /// </summary>
  38. private ISqlRepository<ProdLineDetail> _prodLineDetail;
  39. /// <summary>
  40. /// 工作日历数据
  41. /// </summary>
  42. private ISqlRepository<ShopCalendarWorkCtr> _shopCalendarWorkCtr;
  43. /// <summary>
  44. /// 产线休息时间记录表
  45. /// </summary>
  46. private ISqlRepository<QualityLineWorkDetail> _qualityLineWorkDetail;
  47. /// <summary>
  48. /// 节假日记录表
  49. /// </summary>
  50. private ISqlRepository<HolidayMaster> _holidayMaster;
  51. /// <summary>
  52. /// 工作单元
  53. /// </summary>
  54. private readonly IUnitOfWorkManager _unitOfWorkManager;
  55. /// <summary>
  56. /// 日志
  57. /// </summary>
  58. private readonly ICurrentTenant _currentTenant;
  59. /// <summary>
  60. /// 年度生产需求大纲
  61. /// </summary>
  62. private IRepository<YearDemandManagement, long> _yearDemandManagement;
  63. /// <summary>
  64. /// 年度生产需求大纲历史记录
  65. /// </summary>
  66. private IRepository<YearDemandManagementHistory, long> _yearDemandManagementHistory;
  67. /// <summary>
  68. /// 国内终端预测
  69. /// </summary>
  70. private IRepository<DomesticTerminalFcst, long> _domesticTerminalFcst;
  71. /// <summary>
  72. /// 海外销售预测
  73. /// </summary>
  74. private IRepository<OverseasSaleFcst, long> _overseasSaleFcst;
  75. /// <summary>
  76. /// 平台预测收集
  77. /// </summary>
  78. private IRepository<PlatformFcstCollect, long> _platformFcstCollect;
  79. /// <summary>
  80. /// 标准物料规格型号设置表
  81. /// </summary>
  82. private IRepository<StandardItemModelSet,long> _standardItemModelSet;
  83. /// <summary>
  84. /// 库存明细表
  85. /// </summary>
  86. private ISqlRepository<LocationDetail> _locationDetail;
  87. /// <summary>
  88. /// 工单
  89. /// </summary>
  90. private ISqlRepository<WorkOrdMaster> _workOrdMaster;
  91. /// <summary>
  92. /// 整体需求计划
  93. /// </summary>
  94. private IRepository<OverallDemandPlan, long> _overallDemandPlan;
  95. /// <summary>
  96. /// 月度产能共识表
  97. /// </summary>
  98. private IRepository<MonthlyProdCapacity, long> _monthlyProdCapacity;
  99. /// <summary>
  100. /// 月度产能共识明细表
  101. /// </summary>
  102. private IRepository<MonthlyProdCapacityDtl, long> _monthlyProdCapacityDtl;
  103. /// <summary>
  104. /// SKU版本维护表
  105. /// </summary>
  106. private IRepository<SkuVersionSet, long> _skuVersionSet;
  107. /// <summary>
  108. /// 计划订单表
  109. /// </summary>
  110. private IRepository<crm_planorder, long> _crm_planorder;
  111. /// <summary>
  112. /// 平台库存监控月份
  113. /// </summary>
  114. private IRepository<PlatStockMonitorSetting, long> _platStockMonitorSetting;
  115. /// <summary>
  116. /// 平台库存表
  117. /// </summary>
  118. private IRepository<WMS_PlatformInventory, long> _platformInventory;
  119. /// <summary>
  120. /// 参数设置表
  121. /// </summary>
  122. private ISqlRepository<GeneralizedCodeMaster> _generalizedCodeMaster;
  123. /// <summary>
  124. /// 雪花算法
  125. /// </summary>
  126. SnowFlake help = new SnowFlake();
  127. #endregion
  128. #region 构造函数
  129. /// <summary>
  130. /// 构造函数
  131. /// </summary>
  132. public MonthlyCapacityLoadAppService(
  133. IRepository<ic_item, long> ic_item,
  134. ISqlRepository<ProdLineDetail> prodLineDetail,
  135. ISqlRepository<ShopCalendarWorkCtr> shopCalendarWorkCtr,
  136. ISqlRepository<QualityLineWorkDetail> qualityLineWorkDetail,
  137. ISqlRepository<HolidayMaster> holidayMaster,
  138. IRepository<MonthlyProdCapacity, long> monthlyProdCapacity,
  139. IUnitOfWorkManager unitOfWorkManager,
  140. ICurrentTenant currentTenant,
  141. IRepository<StandardItemModelSet,long> standardItemModelSet,
  142. IRepository<YearDemandManagement, long> yearDemandManagement,
  143. IRepository<DomesticTerminalFcst, long> domesticTerminalFcst,
  144. IRepository<OverseasSaleFcst, long> overseasSaleFcst,
  145. IRepository<PlatformFcstCollect, long> platformFcstCollect,
  146. IRepository<YearDemandManagementHistory, long> yearDemandManagementHistory,
  147. ISqlRepository<LocationDetail> locationDetail,
  148. ISqlRepository<WorkOrdMaster> workOrdMaster,
  149. IRepository<OverallDemandPlan, long> overallDemandPlan,
  150. IRepository<MonthlyProdCapacityDtl, long> monthlyProdCapacityDtl,
  151. IRepository<SkuVersionSet, long> skuVersionSet,
  152. IRepository<crm_planorder, long> crm_planorder,
  153. IRepository<PlatStockMonitorSetting, long> platStockMonitorSetting,
  154. IRepository<WMS_PlatformInventory, long> platformInventory,
  155. ISqlRepository<GeneralizedCodeMaster> generalizedCodeMaster
  156. )
  157. {
  158. _ic_item = ic_item;
  159. _prodLineDetail = prodLineDetail;
  160. _shopCalendarWorkCtr = shopCalendarWorkCtr;
  161. _qualityLineWorkDetail = qualityLineWorkDetail;
  162. _holidayMaster = holidayMaster;
  163. _monthlyProdCapacity = monthlyProdCapacity;
  164. _unitOfWorkManager = unitOfWorkManager;
  165. _currentTenant = currentTenant;
  166. _standardItemModelSet = standardItemModelSet;
  167. _yearDemandManagement= yearDemandManagement;
  168. _domesticTerminalFcst= domesticTerminalFcst;
  169. _overseasSaleFcst = overseasSaleFcst;
  170. _platformFcstCollect= platformFcstCollect;
  171. _yearDemandManagementHistory= yearDemandManagementHistory;
  172. _locationDetail = locationDetail;
  173. _workOrdMaster = workOrdMaster;
  174. _overallDemandPlan = overallDemandPlan;
  175. _monthlyProdCapacityDtl = monthlyProdCapacityDtl;
  176. _skuVersionSet= skuVersionSet;
  177. _crm_planorder= crm_planorder;
  178. _platStockMonitorSetting = platStockMonitorSetting;
  179. _platformInventory = platformInventory;
  180. _generalizedCodeMaster = generalizedCodeMaster;
  181. }
  182. #endregion
  183. /// <summary>
  184. /// 月度需求预测更新
  185. /// </summary>
  186. /// <param name="input"></param>
  187. /// <returns></returns>
  188. /// <exception cref="NotImplementedException"></exception>
  189. public async Task<string> DemandAnalysis(InputDto input)
  190. {
  191. //1.0 获取当前年年度生产需求大纲
  192. 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();
  193. //1.0 获取下一年年度生产大纲
  194. 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();
  195. //记录历史版本:当前年+下一年
  196. var updateMonth = input.year.ToString() + "-" + input.month.ToString("00");
  197. var histories = ObjectMapper.Map<List<YearDemandManagement>, List<YearDemandManagementHistory>>(yearDemands);
  198. histories.ForEach(p => {
  199. p.UpdateMonth = updateMonth;
  200. });
  201. var nextHistories = ObjectMapper.Map<List<YearDemandManagement>, List<YearDemandManagementHistory>>(nextYearDemands);
  202. nextHistories.ForEach(p => {
  203. p.UpdateMonth = updateMonth;
  204. });
  205. //1.1、获取海外销售预测数据
  206. 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;
  207. //1.2、获取平台预测收集数据
  208. 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;
  209. //1.3、获取国内终端预测-T1汇总数据
  210. 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;
  211. //1.3.1、获取T2-海王,T2-国科数据
  212. List<DomesticTerminalFcst> T2Fcsts = _domesticTerminalFcst.GetListAsync(p => (p.TypeEnum == 4 || p.TypeEnum == 5) && 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;
  213. //1.4、根据年度生产大纲,获取规格型号对应的补货周期
  214. List<string> allModels = yearDemands.Select(p=>p.Model).Distinct().ToList();
  215. if (nextYearDemands.Any())
  216. {
  217. allModels.AddRange(nextYearDemands.Select(p => p.Model).ToList());
  218. allModels = allModels.Distinct().ToList();
  219. }
  220. 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;
  221. //1.5、获取规格型号对应的标准SKU数据:获取最小包装单位
  222. List<string> itemNums = standards.Select(p=>p.ItemNumber).Distinct().ToList();
  223. 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;
  224. //1.6、获取成品库存、灭菌库存
  225. //List<LocationDetail> locations = _locationDetail.Select(p=>p.Domain == input.factory_id.ToString() && p.IsActive && itemNums.Contains(p.ItemNum));
  226. //1.7、获取在制库存:计划开始时间、计划结束时间都在本月,并且未关闭的工单
  227. //DateTime monStart = Convert.ToDateTime(input.year + "-" + input.month + "-01");
  228. //DateTime monEnd = monStart.AddMonths(1).AddDays(-1);
  229. //List<WorkOrdMaster> workOrds = _workOrdMaster.Select(p=>p.Domain);
  230. //1.9、获取节假日设置
  231. 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);
  232. //2.0、获取平台库存监控月份设置
  233. List<PlatStockMonitorSetting> monitorSettings = _platStockMonitorSetting.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;
  234. #region 数据校验
  235. //1、校验当前年的年度生产大纲是否导入
  236. if (!yearDemands.Any())
  237. {
  238. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年的年度生产需求后再操作!", _currentTenant.Id.ToString());
  239. return "NO|请导入" + input.year + "年的年度生产需求后再操作!";
  240. }
  241. //2、如果当前月份大于10,则需校验下一年的年度生产大纲
  242. if (input.month > 10 && !nextYearDemands.Any())
  243. {
  244. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + (input.year+1) + "年的年度生产需求后再操作!", _currentTenant.Id.ToString());
  245. return "NO|请导入" + (input.year + 1) + "年的年度生产需求后再操作!";
  246. }
  247. //3、校验当前月份的海外销售预测是否导入
  248. if (!overseasSales.Any())
  249. {
  250. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月海外销售预测后再操作!", _currentTenant.Id.ToString());
  251. return "NO|请导入" + input.year + "年" + input.month + "月海外销售预测后再操作!";
  252. }
  253. //4、校验当前月份的平台预测收集是否导入
  254. if (!platformFcsts.Any())
  255. {
  256. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月平台需求收集后再操作!", _currentTenant.Id.ToString());
  257. return "NO|请导入" + input.year + "年" + input.month + "月平台需求收集后再操作!";
  258. }
  259. //5、校验当前月份的国内终端预测是否导入
  260. if (!domesticFcst.Any())
  261. {
  262. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月国内终端预测后再操作!", _currentTenant.Id.ToString());
  263. return "NO|请导入" + input.year + "年" + input.month + "月国内终端预测后再操作!";
  264. }
  265. //6、校验终端+平台导入的规格型号是否已维护标准SKU
  266. if (allModels.Count() != standards.Count())
  267. {
  268. allModels.RemoveAll(standards.Select(p=>p.Model).ToList());
  269. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "规格型号【" + string.Join(",",allModels) + "】没有维护标准SKU,请维护后再操作!", _currentTenant.Id.ToString());
  270. return "NO|规格型号【" + string.Join(",", allModels) + "】没有维护标准SKU,请维护后再操作!";
  271. }
  272. //7、校验是否已维护补货周期
  273. var zeros = standards.Where(p => p.ReplenishCycle == 0).ToList();
  274. if (zeros.Any())
  275. {
  276. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "规格型号【" + string.Join(",", zeros.Select(p=>p.Model).ToList()) + "】没有维护补货周期,请维护后再操作!", _currentTenant.Id.ToString());
  277. return "NO|规格型号【" + string.Join(",", zeros.Select(p => p.Model).ToList()) + "】没有维护补货周期,请维护后再操作!";
  278. }
  279. #endregion
  280. //计算当前年月的N0,N+1,N+2
  281. List<string> planMons = new List<string>();
  282. int newYear = input.month == 12 ? input.year + 1 : input.year;
  283. int newMonth = input.month == 12 ? 1 : input.month + 1;
  284. string strN1 = newYear.ToString() + "-" + newMonth.ToString("00");
  285. planMons.Add(strN1);
  286. newYear = newMonth == 12 ? newYear + 1 : newYear;
  287. newMonth = newMonth == 12 ? 1 : newMonth + 1;
  288. string strN2 = newYear.ToString() + "-" + newMonth.ToString("00");
  289. planMons.Add(strN2);
  290. //需要回写的数据
  291. List<YearDemandManagement> updates = new List<YearDemandManagement>();
  292. #region 计算国内终端预测,回写年度生产大纲
  293. //获取导入的T1、平台数据
  294. List<string> gnModels = new List<string>();
  295. if (domesticFcst.Any())
  296. {
  297. gnModels.AddRange(domesticFcst.Select(p => p.Model).ToList());
  298. }
  299. if (platformFcsts.Any())
  300. {
  301. gnModels.AddRange(platformFcsts.Select(p => p.Model).ToList());
  302. }
  303. gnModels = gnModels.Distinct().ToList();
  304. foreach (var gnModel in gnModels)
  305. {
  306. //N+1月
  307. YearDemandManagement monthN1 = new YearDemandManagement();
  308. //N+2月
  309. YearDemandManagement monthN2 = new YearDemandManagement();
  310. //获取需要回写的数据
  311. if (input.month < 11)
  312. {
  313. monthN1 = yearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN1);
  314. monthN2 = yearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN2);
  315. }
  316. if (input.month == 11)
  317. {
  318. monthN1 = yearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN1);
  319. monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN2);
  320. }
  321. if (input.month == 12)
  322. {
  323. monthN1 = nextYearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN1);
  324. monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN2);
  325. }
  326. if (monthN1 == null || monthN2 == null)
  327. {
  328. continue;
  329. }
  330. //T1
  331. var sumT1N1 = domesticFcst.Where(p => p.Model == gnModel && p.PlanMonth == strN1).Sum(p=>p.Qty);
  332. var sumT1N2 = domesticFcst.Where(p => p.Model == gnModel && p.PlanMonth == strN2).Sum(p => p.Qty);
  333. //平台
  334. var sumPN1 = platformFcsts.Where(p => p.Model == gnModel && p.PlanMonth == strN1).Sum(p => p.Qty);
  335. var sumPN2 = platformFcsts.Where(p => p.Model == gnModel && p.PlanMonth == strN2).Sum(p => p.Qty);
  336. //合计
  337. var sumN1 = sumT1N1+ sumPN1;
  338. var sumN2 = sumT1N2 + sumPN2;
  339. //当前规格型号对应标准SKU的最小包装单位、补货周期
  340. var curStd = standards.FirstOrDefault(p => p.Model == gnModel);
  341. decimal packQty = 1m;//最小包装单位
  342. decimal cycle = 0m;//补货周期
  343. if (curStd != null)
  344. {
  345. var curItem = items.FirstOrDefault(p => p.number == curStd.ItemNumber);
  346. packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
  347. cycle = curStd.ReplenishCycle;
  348. }
  349. //TODO:获取成品库存、在制库存、灭菌库存,参与计算
  350. //N+1月使用N+2月的再订货点参与计算
  351. decimal rop = CalcRop(strN2+"-01", sumN2, packQty, holidays, cycle);
  352. monthN1.Qty = Math.Ceiling((sumN1 / 2 + sumN2 / 2 + rop - 0 - 0 - 0) / packQty) * packQty;
  353. //N+2月使用本月的需求量,下一月的工作天数
  354. rop = CalcRop(Convert.ToDateTime(strN2 + "-01").AddMonths(1).ToString("yyyy-MM-dd"), sumN2, packQty, holidays, cycle);
  355. monthN2.Qty = Math.Ceiling((sumN2 + rop - 0 - 0 - 0) / packQty) * packQty;
  356. //负数置0
  357. monthN1.Qty = monthN1.Qty < 0 ? 0m : monthN1.Qty;
  358. monthN2.Qty = monthN2.Qty < 0 ? 0m : monthN2.Qty;
  359. //记录需要回写的数据
  360. updates.Add(monthN1);
  361. updates.Add(monthN2);
  362. }
  363. #endregion
  364. #region 海外销售预测,回写年度生产大纲
  365. List<string> hwModels = overseasSales.Select(p => p.Model).Distinct().ToList();
  366. foreach (var hwModel in hwModels)
  367. {
  368. //N+1月
  369. YearDemandManagement monthN1 = new YearDemandManagement();
  370. //N+2月
  371. YearDemandManagement monthN2 = new YearDemandManagement();
  372. //获取需要回写的数据
  373. if (input.month < 11)
  374. {
  375. monthN1 = yearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN1);
  376. monthN2 = yearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN2);
  377. }
  378. if (input.month == 11)
  379. {
  380. monthN1 = yearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN1);
  381. monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN2);
  382. }
  383. if (input.month == 12)
  384. {
  385. monthN1 = nextYearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN1);
  386. monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN2);
  387. }
  388. if (monthN1 == null || monthN2 == null) {
  389. continue;
  390. }
  391. var sumN1 = overseasSales.Where(p => p.Model == hwModel && p.PlanMonth == strN1).Sum(p => p.Qty);
  392. var sumN2 = overseasSales.Where(p => p.Model == hwModel && p.PlanMonth == strN2).Sum(p => p.Qty);
  393. //当前规格型号对应标准SKU的最小包装单位、补货周期
  394. var curStd = standards.FirstOrDefault(p => p.Model == hwModel);
  395. decimal packQty = 1m;//最小包装单位
  396. if (curStd != null)
  397. {
  398. var curItem = items.FirstOrDefault(p => p.number == curStd.ItemNumber);
  399. packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
  400. }
  401. //海外生产需求量=当月的50%+下一月的50%-成品库存-在制库存-灭菌库存
  402. //TODO:获取成品库存、在制库存、灭菌库存,参与运算
  403. //计算N+1月,N+2月
  404. monthN1.Qty = Math.Ceiling((sumN1 / 2 + sumN2 / 2 - 0 - 0 - 0) / packQty) * packQty;
  405. monthN2.Qty = Math.Ceiling((sumN2 - 0 - 0 - 0) / packQty) *packQty; ;
  406. //负数置0
  407. monthN1.Qty = monthN1.Qty < 0 ? 0m : monthN1.Qty;
  408. monthN2.Qty = monthN2.Qty < 0 ? 0m : monthN2.Qty;
  409. //记录需要回写的数据
  410. updates.Add(monthN1);
  411. updates.Add(monthN2);
  412. }
  413. #endregion
  414. //生成月度产能共识
  415. var capacityDto = CapacityAnalysis(input, updates, planMons);
  416. //生成下一个月的补货计划
  417. var nextMonPFcsts = platformFcsts.Where(p => p.PlanMonth == strN2).ToList();
  418. var nextMonDFcsts = domesticFcst.Where(p => p.PlanMonth == strN2).ToList();
  419. var nextMonT2Fcsts = T2Fcsts.Where(p => p.PlanMonth == strN2).ToList();
  420. var nextMonMonitors = monitorSettings.Where(p => p.PlanMonth == strN1).ToList();
  421. var replenishs = MonthlyReplenish(input, nextMonPFcsts, nextMonDFcsts, nextMonT2Fcsts, standards, items, holidays, nextMonMonitors);
  422. //保存数据
  423. using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
  424. {
  425. try
  426. {
  427. //判断是否存在当前年月的历史版本,不存在则插入
  428. 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;
  429. if (!dbHistory.Any())
  430. {
  431. await _yearDemandManagementHistory.InsertManyAsync(histories);
  432. }
  433. if (input.month > 10)
  434. {
  435. //判断是否存在下一年月的历史版本,不存在则插入
  436. 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;
  437. if (!dbHistory.Any())
  438. {
  439. await _yearDemandManagementHistory.InsertManyAsync(nextHistories);
  440. }
  441. }
  442. //回写年度生产大纲
  443. await _yearDemandManagement.UpdateManyAsync(updates);
  444. //先删除产能共识、产能共识明细
  445. await _monthlyProdCapacity.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);
  446. await _monthlyProdCapacityDtl.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);
  447. await _monthlyProdCapacity.InsertManyAsync(capacityDto.mains);
  448. await _monthlyProdCapacityDtl.InsertManyAsync(capacityDto.details);
  449. //生成下一月的补货计划
  450. await _crm_planorder.HardDeleteAsync(p=>p.PlanMonth == strN1 && p.Source =="系统运算" && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id);
  451. await _crm_planorder.InsertManyAsync(replenishs);
  452. await unitOfWork.CompleteAsync();
  453. }
  454. catch (Exception e)
  455. {
  456. unitOfWork.Dispose();
  457. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "【" + input.year + "年" + input.month + "月】月度需求预测更新失败:" + e.Message, _currentTenant.Id.ToString());
  458. return "NO|" + e.Message;
  459. };
  460. }
  461. return "OK|修订成功!";
  462. }
  463. /// <summary>
  464. /// 生成月度产能共识
  465. /// </summary>
  466. /// <param name="input"></param>
  467. /// <returns></returns>
  468. public MonthlyCapacityDto CapacityAnalysis(InputDto input,List<YearDemandManagement> yearDemands, List<string> planMons)
  469. {
  470. //1、获取数据
  471. //1.1 根据规格型号获取物料数据
  472. List<string> models = yearDemands.Select(p => p.Model).Distinct().ToList();
  473. 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).Result;
  474. //1.3 根据物料编码获取产线数据
  475. List<ProdLineDetail> lineDtls = _prodLineDetail.Select(p => standards.Select(m => m.ItemNumber).Contains(p.Part) && p.Domain == input.factory_id.ToString() && p.IsActive).OrderBy(p => p.Line).ToList();
  476. //1.4 根据产线获取工作日历数据和产线休息配置数据
  477. List<ShopCalendarWorkCtr> calendars = _shopCalendarWorkCtr.Select(p => lineDtls.Select(m => m.Line).Contains(p.ProdLine) && p.Domain == input.factory_id.ToString() && p.IsActive);
  478. List<QualityLineWorkDetail> lineWorks = _qualityLineWorkDetail.Select(p => lineDtls.Select(m => m.Line).Contains(p.ProdLine) && p.Domain == input.factory_id.ToString() && p.IsActive);
  479. //1.5 获取当前年和下一年的节假日配置数据
  480. 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);
  481. //月度产能共识表
  482. List<MonthlyProdCapacity> capacities = new List<MonthlyProdCapacity>();
  483. //月度产能共识明细表
  484. List<MonthlyProdCapacityDtl> capacityDtls = new List<MonthlyProdCapacityDtl>();
  485. //产线
  486. List<string> lines = lineDtls.Select(p => p.Line).Distinct().ToList();
  487. foreach (var item in lines)
  488. {
  489. //计算每天工作时间
  490. var curCal = calendars.FirstOrDefault(p => p.ProdLine == item);
  491. if (curCal == null)
  492. {
  493. continue;
  494. }
  495. foreach (var pm in planMons)
  496. {
  497. //添加月度产能共识产能效率数据
  498. MonthlyProdCapacity dtl = new MonthlyProdCapacity();
  499. dtl.Year = input.year;
  500. dtl.Month = input.month;
  501. dtl.PlanMonth = pm;
  502. dtl.ProdLine = item;
  503. dtl.DailyWorks = curCal.ShiftsHours1 + curCal.ShiftsHours2 + curCal.ShiftsHours3 + curCal.ShiftsHours4;
  504. dtl.FlightQty = 1;
  505. //计算当月工作天数
  506. var curHoildays = holidays.Where(p => p.Dated.Value.Year == Convert.ToInt16(pm.Substring(0,4)) && p.Dated.Value.Month == Convert.ToInt16(pm.Substring(5, 2))).ToList();
  507. //当月天数
  508. int days = DateTime.DaysInMonth(input.year, input.month);
  509. //当月周末天数
  510. int weekDays = CalcWeekDays(days, Convert.ToDateTime(pm + "-01"));
  511. dtl.MonthWorks = days - weekDays - curHoildays.Where(p => p.Ufld1 == "休假").Count() + curHoildays.Where(p => p.Ufld1 == "调班").Count();
  512. dtl.AvailableTimes = dtl.DailyWorks * dtl.MonthWorks;
  513. //计算产线耗时
  514. var curLines = lineDtls.Where(p => p.Line == item).ToList();
  515. decimal sumTimes = 0.00m;
  516. List<ProdLineDto> lineDtos = new List<ProdLineDto>();
  517. foreach (var ld in curLines)
  518. {
  519. if (lineDtos.Exists(p=>p.Part == ld.Part && p.Line == ld.Line))
  520. {
  521. continue;
  522. }
  523. var curStand = standards.FirstOrDefault(p => p.ItemNumber == ld.Part);
  524. if (curStand == null)
  525. {
  526. continue;
  527. }
  528. var curDemands = yearDemands.Where(p => p.Model == curStand.Model && p.PlanMonth == pm).ToList();
  529. var line = curLines.Where(p=>p.Part == ld.Part && p.Line == ld.Line).OrderByDescending(p => p.Op).First();
  530. sumTimes += line.Rate == 0 ? 0 : (Math.Ceiling(curDemands.Sum(p => p.Qty) / line.Rate));
  531. MonthlyProdCapacityDtl capacityDtl = new MonthlyProdCapacityDtl();
  532. capacityDtl.Year = input.year;
  533. capacityDtl.Month = input.month;
  534. capacityDtl.PlanMonth = pm;
  535. capacityDtl.ProdLine = item;
  536. capacityDtl.Model = curStand.Model;
  537. capacityDtl.Qty = curDemands.Sum(p => p.Qty);
  538. capacityDtl.tenant_id = input.tenant_id;
  539. capacityDtl.company_id = input.company_id;
  540. capacityDtl.factory_id = input.factory_id;
  541. capacityDtl.org_id = input.org_id;
  542. capacityDtl.create_by = input.create_by;
  543. capacityDtl.create_by_name = input.create_by_name;
  544. capacityDtl.create_time = DateTime.Now;
  545. capacityDtls.Add(capacityDtl);
  546. lineDtos.Add(new ProdLineDto {
  547. Part = ld.Part,
  548. Line= ld.Line
  549. });
  550. }
  551. dtl.NeedWorks = sumTimes;
  552. dtl.ProdRate = 100;
  553. dtl.Rate = dtl.AvailableTimes == 0 ? 0 : Math.Floor(dtl.NeedWorks / dtl.AvailableTimes * 100);
  554. dtl.IsOverTime = dtl.NeedWorks > dtl.AvailableTimes ? "是" : "否";
  555. dtl.OverTimes = dtl.IsOverTime == "是" ? (dtl.NeedWorks - dtl.AvailableTimes) : 0;
  556. dtl.tenant_id = input.tenant_id;
  557. dtl.company_id= input.company_id;
  558. dtl.factory_id = input.factory_id;
  559. dtl.org_id= input.org_id;
  560. dtl.create_by= input.create_by;
  561. dtl.create_by_name = input.create_by_name;
  562. dtl.create_time = DateTime.Now;
  563. capacities.Add(dtl);
  564. }
  565. }
  566. return new MonthlyCapacityDto{
  567. mains = capacities,
  568. details = capacityDtls
  569. };
  570. }
  571. /// <summary>
  572. /// T1、平台自动补货
  573. /// </summary>
  574. /// <param name="input"></param>
  575. /// <param name="platformFcsts">平台预测</param>
  576. /// <param name="domesticFcsts">T1预测</param>
  577. /// <param name="standards">标准SKU设置</param>
  578. /// <param name="items">物料</param>
  579. /// <param name="holidays">节假日</param>
  580. /// <param name="monitorSettings">库存监控月份设置</param>
  581. /// <returns></returns>
  582. public List<crm_planorder> MonthlyReplenish(InputDto input, List<PlatformFcstCollect> platformFcsts, List<DomesticTerminalFcst> domesticFcsts, List<DomesticTerminalFcst> T2Fcsts, List<StandardItemModelSet> standards, List<ic_item> items, List<HolidayMaster> holidays, List<PlatStockMonitorSetting> monitorSettings)
  583. {
  584. List<crm_planorder> planorders = new List<crm_planorder>();
  585. //获取T1、平台预测数据中规格型号对应的不同版本的物料编码
  586. var T1Models = domesticFcsts.Select(p => p.Model).Distinct().ToList();
  587. var PModels = platformFcsts.Select(p => p.Model).Distinct().ToList();
  588. List<string> models = T1Models;
  589. models.AddRange(PModels);
  590. models = models.Distinct().ToList();
  591. List<SkuVersionSet> skus = _skuVersionSet.GetListAsync(p=>models.Contains(p.Model) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id).Result;
  592. //获取T1库存
  593. List<string> itemNums = skus.Select(p=>p.ItemNum).Distinct().ToList();
  594. List<LocationDetail> locationDetails = _locationDetail.Select(p=> itemNums.Contains(p.ItemNum) && p.Domain == input.factory_id.ToString() && p.IsActive);
  595. //获取临期库存设置
  596. GeneralizedCodeMaster master = _generalizedCodeMaster.Select(p=>p.Domain == input.factory_id.ToString() && p.IsActive && p.Val == "LongPeriodItemPlanMonth").FirstOrDefault();
  597. int month = master == null ? 0 : Convert.ToInt16(master.UDeci1);
  598. DateTime strTime = Convert.ToDateTime(platformFcsts[0].PlanMonth + "-01").AddMonths(month);
  599. //获取平台库存
  600. List<WMS_PlatformInventory> pInventories = _platformInventory.GetListAsync(p=> p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && p.PeriodOfValidity >= strTime).Result;
  601. //计算T1补货
  602. foreach (var item in T1Models)
  603. {
  604. //获取当前规格型号对应的预测数据
  605. var curFcsts = domesticFcsts.Where(p=>p.Model == item).ToList();
  606. //当前规格型号对应的库存数量
  607. decimal sumQty = 0.00m;
  608. //当前的物料版本
  609. var curSkus = skus.Where(p => p.Model == item).ToList();
  610. if (curSkus.Any())
  611. {
  612. sumQty = locationDetails.Where(p => curSkus.Select(p => p.ItemNum).Contains(p.ItemNum)).Sum(p => p.QtyOnHand);
  613. }
  614. //计算Rop
  615. //当前规格型号对应标准SKU的最小包装单位、补货周期
  616. var curStd = standards.FirstOrDefault(p => p.Model == item);
  617. decimal packQty = 1m;//最小包装单位
  618. decimal cycle = 0m;//补货周期
  619. if (curStd != null)
  620. {
  621. var curItem = items.FirstOrDefault(p => p.number == curStd.ItemNumber);
  622. packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
  623. cycle = curStd.ReplenishCycle;
  624. }
  625. //TODO:获取成品库存、在制库存、灭菌库存,参与计算
  626. //N+1月使用N+2月的再订货点参与计算
  627. decimal rop = CalcRop(curFcsts[0].PlanMonth + "-01", curFcsts.Sum(p=>p.Qty), packQty, holidays, cycle);
  628. if(sumQty < rop)
  629. {
  630. planorders.Add(new crm_planorder {
  631. PlanMonth = curFcsts[0].PlanMonth,
  632. Model = curFcsts[0].Model,
  633. ItemNum = curStd?.ItemNumber,
  634. ProdLine = curFcsts[0].ProdLine,
  635. ProdType = "",
  636. Qty = rop,
  637. Type = "计划单-T1直发补货",
  638. Source = "系统运算",
  639. tenant_id = input.tenant_id,
  640. company_id= input.company_id,
  641. factory_id= input.factory_id,
  642. org_id= input.org_id,
  643. create_by= input.create_by,
  644. create_by_name= input.create_by_name,
  645. create_time = DateTime.Now
  646. });
  647. }
  648. }
  649. //计算平台补货:海王+国科
  650. foreach (var item in PModels)
  651. {
  652. }
  653. return planorders;
  654. }
  655. /// <summary>
  656. /// 计算再订货点
  657. /// </summary>
  658. /// <param name="planMonth">计划年月(yyyy-MM-dd)</param>
  659. /// <param name="qty">需求量</param>
  660. /// <param name="qty">最小包装数量</param>
  661. /// <param name="holidays">节假日</param>
  662. /// <param name="replenishCycle">补货周期</param>
  663. /// <returns></returns>
  664. private decimal CalcRop(string planMonth,decimal qty,decimal packQty,List<HolidayMaster> holidays,decimal replenishCycle)
  665. {
  666. decimal rop = 0.0m;
  667. //获取当月天数
  668. int year = Convert.ToInt16(planMonth.Substring(0, 4));
  669. int month = Convert.ToInt16(planMonth.Substring(5, 2));
  670. int days = DateTime.DaysInMonth(year, month);
  671. //计算当前月的周末天数
  672. int weeks = CalcWeekDays(days, Convert.ToDateTime(planMonth));
  673. //获取当前年月的节假日设置
  674. var curHolidays = holidays.Where(p => p.Dated.Value.Year == year && p.Dated.Value.Month == month).ToList();
  675. //当月工作天数
  676. int workDays = days - weeks - curHolidays.Where(p => p.Ufld1 == "休假").Count() + curHolidays.Where(p => p.Ufld1 == "调班").Count();
  677. //rop = (需求量/月工作天数*补货周期)=>按照最小包装单位元整
  678. rop = Math.Ceiling(qty / workDays * replenishCycle / packQty) * packQty;
  679. return rop;
  680. }
  681. /// <summary>
  682. /// 计算当月有多少个周末
  683. /// </summary>
  684. /// <param name="days"></param>
  685. /// <param name="startDay"></param>
  686. /// <returns></returns>
  687. private int CalcWeekDays(int days, DateTime startDay)
  688. {
  689. int sumDays = 0;
  690. for (int i = 0; i < days; i++)
  691. {
  692. int weekDays = (int)startDay.AddDays(i).DayOfWeek;
  693. if (weekDays == 0 || weekDays == 6)
  694. {
  695. sumDays++;
  696. }
  697. }
  698. return sumDays;
  699. }
  700. /// <summary>
  701. /// 生成整体需求计划
  702. /// </summary>
  703. /// <param name="input"></param>
  704. /// <returns></returns>
  705. /// <exception cref="NotImplementedException"></exception>
  706. public async Task<string> OverallDemandPlan(InputDto input)
  707. {
  708. //1.1、获取海外销售预测数据
  709. 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();
  710. //1.2、获取平台预测收集数据
  711. 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();
  712. //1.3、获取国内终端预测-T1汇总数据
  713. 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();
  714. //计算当前年月的N+1,N+2
  715. string strN0 = input.year.ToString() + "-" + input.month.ToString("00");
  716. int newYear = input.month == 12 ? input.year + 1 : input.year;
  717. int newMonth = input.month == 12 ? 1 : input.month + 1;
  718. string strN1 = newYear.ToString() + "-" + newMonth.ToString("00");
  719. newYear = newMonth == 12 ? newYear + 1 : newYear;
  720. newMonth = newMonth == 12 ? 1 : newMonth + 1;
  721. string strN2 = newYear.ToString() + "-" + newMonth.ToString("00");
  722. //整体需求计划
  723. List<OverallDemandPlan> plans = new List<OverallDemandPlan>();
  724. //计算海外
  725. List<string> hwModels = overseasSales.Select(p => p.Model).Distinct().ToList();
  726. int OrderNum = 1;
  727. foreach (var item in hwModels)
  728. {
  729. var curFcsts = overseasSales.Where(p => p.Model == item).ToList();
  730. OverallDemandPlan plan = new OverallDemandPlan();
  731. plan.Area = "海外";
  732. plan.Model = item;
  733. plan.PlanMonth = strN0;
  734. plan.Qty = curFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty);
  735. plan.OrderNum = OrderNum;
  736. plans.Add(plan);
  737. plan = new OverallDemandPlan();
  738. plan.Area = "海外";
  739. plan.Model = item;
  740. plan.PlanMonth = strN1;
  741. plan.Qty = curFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty);
  742. plan.OrderNum = OrderNum;
  743. plans.Add(plan);
  744. plan = new OverallDemandPlan();
  745. plan.Area = "海外";
  746. plan.Model = item;
  747. plan.PlanMonth = strN2;
  748. plan.Qty = curFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty);
  749. plan.OrderNum = OrderNum;
  750. plans.Add(plan);
  751. OrderNum += 1;
  752. }
  753. //计算国内
  754. List<string> gnModels = domesticFcsts.Select(p=>p.Model).ToList();
  755. gnModels.AddRange(platformFcsts.Select(p => p.Model).ToList());
  756. gnModels = gnModels.Distinct().ToList();
  757. OrderNum = 1;
  758. foreach (var item in gnModels)
  759. {
  760. var curDFcsts = domesticFcsts.Where(p => p.Model == item).ToList();
  761. var curPFcsts = platformFcsts.Where(p => p.Model == item).ToList();
  762. OverallDemandPlan plan = new OverallDemandPlan();
  763. plan.Area = "国内";
  764. plan.Model = item;
  765. plan.PlanMonth = strN0;
  766. plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty);
  767. plan.OrderNum = OrderNum;
  768. plans.Add(plan);
  769. plan = new OverallDemandPlan();
  770. plan.Area = "国内";
  771. plan.Model = item;
  772. plan.PlanMonth = strN1;
  773. plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty);
  774. plan.OrderNum = OrderNum;
  775. plans.Add(plan);
  776. plan = new OverallDemandPlan();
  777. plan.Area = "国内";
  778. plan.Model = item;
  779. plan.PlanMonth = strN2;
  780. plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty);
  781. plan.OrderNum = OrderNum;
  782. plans.Add(plan);
  783. OrderNum += 1;
  784. }
  785. plans.ForEach(p => {
  786. p.Year= input.year;
  787. p.Month= input.month;
  788. p.tenant_id = input.tenant_id;
  789. p.company_id = input.company_id;
  790. p.factory_id= input.factory_id;
  791. p.org_id= input.org_id;
  792. p.create_by = input.create_by;
  793. p.create_by_name= input.create_by_name;
  794. p.create_time = DateTime.Now;
  795. });
  796. //保存数据
  797. using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
  798. {
  799. try
  800. {
  801. //先删除
  802. 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);
  803. //保存整体需求计划
  804. await _overallDemandPlan.InsertManyAsync(plans);
  805. await unitOfWork.CompleteAsync();
  806. }
  807. catch (Exception e)
  808. {
  809. unitOfWork.Dispose();
  810. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("OverallDemandPlan", "生成【" + input.year + "年" + input.month + "月】整体需求计划失败:" + e.Message, _currentTenant.Id.ToString());
  811. return "NO|" + e.Message;
  812. };
  813. }
  814. return "OK|刷新成功!";
  815. }
  816. }
  817. }