SyncDOPAppService.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. using Business.Core.Utilities;
  2. using Business.Domain;
  3. using Business.Dto;
  4. using Business.EntityFrameworkCore.SqlRepositories;
  5. using Business.StructuredDB.WMS;
  6. using Newtonsoft.Json;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Threading.Tasks;
  11. using Volo.Abp.Application.Services;
  12. using Volo.Abp.DependencyInjection;
  13. using Volo.Abp.Domain.Repositories;
  14. using Volo.Abp.MultiTenancy;
  15. using Volo.Abp.Uow;
  16. using IUnitOfWorkManager = Volo.Abp.Uow.IUnitOfWorkManager;
  17. namespace Business.DOP
  18. {
  19. //DOP
  20. public class SyncDOPAppService : ApplicationService, ISyncDOPAppService, ITransientDependency
  21. {
  22. #region 服务
  23. /// <summary>
  24. /// 平台规格型号对照表
  25. /// </summary>
  26. private readonly IRepository<WMS_PlatformSpecificationComparison, long> _PlatformSpecificationComparison;
  27. /// <summary>
  28. /// 平台库存表
  29. /// </summary>
  30. private readonly IRepository<WMS_PlatformInventory, long> _PlatformInventory;
  31. /// <summary>
  32. /// SAP库存表
  33. /// </summary>
  34. private readonly ISqlRepository<SAPInv> _sapInvRepository;
  35. /// <summary>
  36. /// SAP库存表
  37. /// </summary>
  38. private readonly ISqlRepository<ItemMaster> _itemMasterRepository;
  39. /// <summary>
  40. /// 国内终端预测
  41. /// </summary>
  42. private IRepository<DomesticTerminalFcst, long> _domesticTerminalFcst;
  43. /// <summary>
  44. /// 海外销售预测
  45. /// </summary>
  46. private IRepository<OverseasSaleFcst, long> _overseasSaleFcst;
  47. /// <summary>
  48. /// 标准物料规格型号设置表
  49. /// </summary>
  50. private IRepository<StandardItemModelSet, long> _standardItemModelSet;
  51. private IRepository<PlatStockMonitorSetting, long> _platStockMonitorSetting;
  52. private IRepository<YearDemandManagement, long> _yearDemandManagement;
  53. private IRepository<ic_item, long> _ic_item;
  54. /// <summary>
  55. /// 平台预测收集
  56. /// </summary>
  57. private IRepository<PlatformFcstCollect, long> _platformFcstCollect;
  58. /// <summary>
  59. /// 节假日记录表
  60. /// </summary>
  61. private ISqlRepository<HolidayMaster> _holidayMaster;
  62. /// <summary>
  63. /// 雪花算法
  64. /// </summary>
  65. SnowFlake snowFlake = new SnowFlake();
  66. /// <summary>
  67. /// 事务
  68. /// </summary>
  69. private readonly IUnitOfWorkManager _unitOfWorkManager;
  70. private readonly ICurrentTenant _currentTenant;
  71. #endregion
  72. #region 构造函数
  73. /// <summary>
  74. /// 构造函数
  75. /// </summary>
  76. public SyncDOPAppService(
  77. IRepository<WMS_PlatformSpecificationComparison, long> PlatformSpecificationComparison,
  78. IRepository<WMS_PlatformInventory, long> PlatformInventory,
  79. ISqlRepository<SAPInv> sapInvRepository,
  80. IRepository<DomesticTerminalFcst, long> domesticTerminalFcst,
  81. IRepository<OverseasSaleFcst, long> overseasSaleFcst,
  82. IRepository<StandardItemModelSet, long> standardItemModelSet,
  83. ISqlRepository<ItemMaster> itemMasterRepository,
  84. IRepository<PlatStockMonitorSetting, long> platStockMonitorSetting,
  85. IRepository<YearDemandManagement, long> yearDemandManagement,
  86. IRepository<PlatformFcstCollect, long> platformFcstCollect,
  87. ISqlRepository<HolidayMaster> holidayMaster,
  88. IRepository<ic_item, long> ic_item,
  89. IUnitOfWorkManager unitOfWorkManager,
  90. ICurrentTenant currentTenant
  91. )
  92. {
  93. _PlatformSpecificationComparison = PlatformSpecificationComparison;
  94. _PlatformInventory = PlatformInventory;
  95. _sapInvRepository = sapInvRepository;
  96. _domesticTerminalFcst = domesticTerminalFcst;
  97. _overseasSaleFcst = overseasSaleFcst;
  98. _standardItemModelSet = standardItemModelSet;
  99. _itemMasterRepository = itemMasterRepository;
  100. _platStockMonitorSetting = platStockMonitorSetting;
  101. _yearDemandManagement=yearDemandManagement;
  102. _holidayMaster = holidayMaster;
  103. _platformFcstCollect = platformFcstCollect;
  104. _ic_item = ic_item;
  105. _currentTenant = currentTenant;
  106. _unitOfWorkManager = unitOfWorkManager;
  107. }
  108. #endregion
  109. /// <summary>
  110. /// 海王平台成品监控
  111. /// </summary>
  112. /// <returns></returns>
  113. /// <exception cref="NotImplementedException"></exception>
  114. public async Task<string> SyncPlatformFinishedProductMonitoringHW(List<PlatformInventoryDto> platformInventoryDtoList)
  115. {
  116. var ret = SavePlatformFinishedProductMonitoringAsync(platformInventoryDtoList, 1);
  117. return await ret;
  118. }
  119. /// <summary>
  120. /// 国科平台成品监控
  121. /// </summary>
  122. /// <returns></returns>
  123. /// <exception cref="NotImplementedException"></exception>
  124. public async Task<string> SyncPlatformFinishedProductMonitoringGK(List<PlatformInventoryDto> platformInventoryDtoList)
  125. {
  126. var ret = SavePlatformFinishedProductMonitoringAsync(platformInventoryDtoList, 2);
  127. return await ret;
  128. }
  129. /// <summary>
  130. /// 保存库存信息
  131. /// </summary>
  132. /// <param name="platformInventoryDtoList"></param>
  133. /// <param name="type">1海王,2国科</param>
  134. public async Task<string> SavePlatformFinishedProductMonitoringAsync(List<PlatformInventoryDto> platformInventoryDtoList, int type)
  135. {
  136. if (platformInventoryDtoList.Count == 0)
  137. {
  138. return JsonConvert.SerializeObject("成品库存为空!");
  139. }
  140. List<WMS_PlatformInventory> platformInventoryInsert = new List<WMS_PlatformInventory>();
  141. List<WMS_PlatformInventory> platformInventoryDel;
  142. if (type == 1)
  143. {
  144. platformInventoryDel = _PlatformInventory.GetListAsync(x => x.Code == "HW0001").Result;
  145. }
  146. else
  147. {
  148. platformInventoryDel = _PlatformInventory.GetListAsync(x => x.Code == "HW0002").Result;
  149. }
  150. foreach (var item in platformInventoryDtoList)
  151. {
  152. WMS_PlatformInventory platformInventory = new WMS_PlatformInventory();
  153. platformInventory.GenerateNewId(snowFlake.NextId());
  154. platformInventory.Location = item.Location;
  155. platformInventory.SpecificationModel = item.SpecificationModel;
  156. platformInventory.BatchNumber = item.BatchNumber;
  157. platformInventory.InventoryQuantity = item.InventoryQuantity.GetValueOrDefault();
  158. platformInventory.PeriodOfValidity = item.PeriodOfValidity.GetValueOrDefault();
  159. if (type == 1)
  160. {
  161. platformInventory.Code = "HW0001";
  162. }
  163. else
  164. {
  165. platformInventory.Code = "GK0001";
  166. }
  167. platformInventoryInsert.Add(platformInventory);
  168. }
  169. using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
  170. {
  171. try
  172. {
  173. //先删后插
  174. await _PlatformInventory.DeleteManyAsync(platformInventoryDel);
  175. await _PlatformInventory.InsertManyAsync(platformInventoryInsert);
  176. await unitOfWork.CompleteAsync();
  177. }
  178. catch (Exception e)
  179. {
  180. new NLogHelper("SyncDOPAppService").WriteLog("PlatformFinishedProductMonitoringAsyncMerge", "接口异常:" + e.Message);
  181. unitOfWork.Dispose();
  182. return JsonConvert.SerializeObject(e.Message);
  183. }
  184. }
  185. return JsonConvert.SerializeObject("ok");
  186. }
  187. /// <summary>
  188. /// 库存监控数据报表接口
  189. /// </summary>
  190. /// <returns></returns>
  191. public async Task<string> InventoryMonitoring(InputDto input)
  192. {
  193. List<InventoryMonitoringDto> inventoryMonitoringDtos= new List<InventoryMonitoringDto>();
  194. var ItemModelSetList = _standardItemModelSet.GetListAsync(a => a.tenant_id == input.tenant_id && a.company_id == input.company_id && !a.IsDeleted).Result;
  195. if (ItemModelSetList == null)
  196. {
  197. new NLogHelper("SyncDOPAppService").WriteLog("InventoryMonitoring", "库存数据不存在", _currentTenant.Id.ToString());
  198. //throw new NotImplementedException("订单数据不存在!");
  199. return "库存数据不存在";
  200. }
  201. ItemModelSetList.ForEach(a =>
  202. {
  203. inventoryMonitoringDtos.Add(new InventoryMonitoringDto { Model=a.Model, ItemNumber=a.ItemNumber, FactoryInv=0,GKInv=0,HWInv=0, ReplenishCycle=a.ReplenishCycle });
  204. });
  205. var ItemList = ItemModelSetList.Select(a => a.ItemNumber);
  206. var modelList = ItemModelSetList.Select(a => a.Model);
  207. var ItemInvList = _sapInvRepository.Select(a => ItemList.Contains(a.MATNR) && a.WERKS == input.factory_id.ToString());
  208. int year = DateTime.Now.AddMonths(1).Year;
  209. int month = DateTime.Now.AddMonths(1).Month;
  210. string planMonth = $"{year}-01";
  211. string planMonthCurrent = $"{year}-{DateTime.Now.AddMonths(1).ToString("MM")}";
  212. var platformInvList = _PlatformInventory.GetListAsync(a => modelList.Contains(a.SpecificationModel) && a.tenant_id == input.tenant_id && a.factory_id == input.factory_id).Result;
  213. 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;
  214. 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);
  215. 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;
  216. 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;
  217. 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;
  218. 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;
  219. inventoryMonitoringDtos.ForEach(a =>
  220. {
  221. //产品线和系列
  222. var itemProdRange = yearDemandList.Find(b => b.Model == a.Model);
  223. if (itemProdRange != null)
  224. {
  225. a.ProLine = itemProdRange.ProdLine;
  226. a.Series = itemProdRange.ProdRange;
  227. }
  228. //工厂库存
  229. var itemSap = ItemInvList.Find(b => b.MATNR == a.ItemNumber);
  230. if(itemSap!=null)
  231. a.FactoryInv =itemSap.LABST;
  232. //国科库存
  233. var platformInventoryGK= platformInvList.Find(b => b.SpecificationModel == a.Model && b.Code== "HW0002");
  234. if (platformInventoryGK != null)
  235. a.GKInv = platformInventoryGK.InventoryQuantity;
  236. //海王库存
  237. var platformInventoryHW = platformInvList.Find(b => b.SpecificationModel == a.Model && b.Code == "HW0001");
  238. if (platformInventoryHW != null)
  239. a.HWInv = platformInventoryHW.InventoryQuantity;
  240. //全域库存
  241. a.TotalInv = a.FactoryInv + a.GKInv + a.HWInv;
  242. //T1月需求
  243. var t1 = domesticTerminalFcstList.Find(b => b.TypeEnum == 2);
  244. if (t1 != null)
  245. {
  246. a.T1MonthlyDemand = t1.Qty;
  247. }
  248. //T1补货点
  249. decimal rop = 0.0m;
  250. //获取当月天数
  251. int days = DateTime.DaysInMonth(year, month);
  252. //计算当前月的周末天数
  253. int weeks = CalcWeekDays(days, DateTime.Now.AddDays(1 - DateTime.Now.Day).AddMonths(1));
  254. //获取当前年月的节假日设置
  255. var curHolidays = holidays.Where(p => p.Dated.Value.Year == DateTime.Now.AddMonths(1).Year && p.Dated.Value.Month == DateTime.Now.AddMonths(1).Month).ToList();
  256. //当月工作天数
  257. int workDays = days - weeks - curHolidays.Where(p => p.Ufld1 == "休假").Count() + curHolidays.Where(p => p.Ufld1 == "调班").Count();
  258. decimal packQty = 1m;//最小包装单位
  259. var curItem = items.FirstOrDefault(p => p.number == a.ItemNumber);
  260. packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
  261. //rop = (需求量/月工作天数*补货周期)=>按照最小包装单位元整
  262. rop = Math.Ceiling(a.T1MonthlyDemand / workDays * a.ReplenishCycle / packQty) * packQty;
  263. a.ReplenishmentPoint = rop;
  264. //国科预估需求
  265. var gk = domesticTerminalFcstList.Find(a => a.TypeEnum == 5);
  266. if (gk != null)
  267. {
  268. a.GKEstimatedDemand = gk.Qty;
  269. }
  270. //海王预估需求
  271. var hw = domesticTerminalFcstList.Find(a => a.TypeEnum == 4);
  272. if (hw != null)
  273. {
  274. a.HWEstimatedDemand = hw.Qty;
  275. }
  276. //T2总体需求
  277. //a.TotalDemand = a.GKEstimatedDemand + a.HWEstimatedDemand;
  278. var t2 = domesticTerminalFcstList.Find(a => a.TypeEnum == 3);
  279. if (t2 != null)
  280. {
  281. a.T2TotalDemand = t2.Qty;
  282. }
  283. //总终端需求
  284. a.TotalTerminalDemand = a.T1MonthlyDemand + a.ReplenishmentPoint + a.GKEstimatedDemand + a.HWEstimatedDemand + a.T2TotalDemand;
  285. //工厂平台覆盖月
  286. a.FactoryCoveragePlatformMonth = Math.Round(a.FactoryInv / a.T1MonthlyDemand,2);
  287. //国科库存最高最低覆盖月
  288. var prodTypeGK=platformFcstCollectList?.Find(b => b.Model == a.Model && b.Platform == "国科");
  289. if(prodTypeGK!=null)
  290. {
  291. var prodTypeSettingGK = platStockMonitorSettingList?.Find(b => b.ProdType == prodTypeGK.ProdType && b.Platform == "国科");
  292. if(prodTypeSettingGK!=null)
  293. {
  294. a.GKCoverageMaxMonth = prodTypeSettingGK.MaxTimes;
  295. a.GKCoverageMinMonth = prodTypeSettingGK.MinTimes;
  296. }else
  297. {
  298. a.GKCoverageMaxMonth = 0;
  299. a.GKCoverageMinMonth = 0;
  300. }
  301. }
  302. //国科库存覆盖月
  303. a.GKCoverageMonth = Math.Round(a.GKInv / a.GKEstimatedDemand, 2);
  304. //海王库存最高最低覆盖月
  305. var prodTypeHW = platformFcstCollectList?.Find(b => b.Model == a.Model && b.Platform == "海王");
  306. if (prodTypeHW != null)
  307. {
  308. var prodTypeSettingHW = platStockMonitorSettingList?.Find(b => b.ProdType == prodTypeHW.ProdType && b.Platform == "海王");
  309. if(prodTypeSettingHW != null)
  310. {
  311. a.HWCoverageMaxMonth = prodTypeSettingHW.MaxTimes;
  312. a.HWCoverageMinMonth = prodTypeSettingHW.MinTimes;
  313. }else
  314. {
  315. a.HWCoverageMaxMonth = 0;
  316. a.HWCoverageMinMonth = 0;
  317. }
  318. }
  319. //海王库存覆盖月
  320. a.HWCoverageMonth = Math.Round(a.HWInv / a.HWEstimatedDemand, 2);
  321. //全域覆盖
  322. a.TotalCoverageMonth = Math.Round(a.TotalInv / a.TotalTerminalDemand, 2);
  323. //T1库存监控
  324. if (a.FactoryInv < a.ReplenishmentPoint)
  325. {
  326. a.T1MonitoringResult = "按照补货点补货";
  327. }
  328. else
  329. {
  330. a.T1MonitoringResult = a.FactoryCoveragePlatformMonth > 6 ? "库存超出6个月阈值" : "正常覆盖范围";
  331. }
  332. //国科库存监控
  333. a.GKMonitoringResult = a.GKCoverageMonth > a.GKCoverageMaxMonth ? "库存高于最高库存水位警戒" : a.GKCoverageMonth < a.GKCoverageMinMonth ? "库存低于最低库存水位,紧急补货" : "正常周转";
  334. //海王库存监控
  335. a.HWMonitoringResult = a.HWCoverageMonth > a.HWCoverageMaxMonth ? "库存高于最高库存水位警戒" : a.HWCoverageMonth < a.HWCoverageMinMonth ? "库存低于最低库存水位,紧急补货" : "正常周转";
  336. //推荐决策
  337. if (a.TotalCoverageMonth <= 3)
  338. {
  339. a.RecommendDecision = "紧急补货";
  340. }
  341. else
  342. if (a.TotalCoverageMonth <=6)
  343. {
  344. a.RecommendDecision = "需要补货";
  345. }
  346. else
  347. if (a.TotalCoverageMonth <=9)
  348. {
  349. a.RecommendDecision = "正常库存";
  350. }
  351. else
  352. if (a.TotalCoverageMonth <= 24)
  353. {
  354. a.RecommendDecision = "关注库存";
  355. }
  356. else
  357. {
  358. a.RecommendDecision = "呆滞";
  359. }
  360. });
  361. return JsonConvert.SerializeObject(inventoryMonitoringDtos);
  362. }
  363. /// <summary>
  364. /// 计算当月有多少个周末
  365. /// </summary>
  366. /// <param name="days"></param>
  367. /// <param name="startDay"></param>
  368. /// <returns></returns>
  369. private int CalcWeekDays(int days, DateTime startDay)
  370. {
  371. int sumDays = 0;
  372. for (int i = 0; i < days; i++)
  373. {
  374. int weekDays = (int)startDay.AddDays(i).DayOfWeek;
  375. if (weekDays == 0 || weekDays == 6)
  376. {
  377. sumDays++;
  378. }
  379. }
  380. return sumDays;
  381. }
  382. }
  383. }