MonthlyCapacityLoadAppService.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. using Business.Core.Utilities;
  2. using Business.Domain;
  3. using Business.Dto;
  4. using Business.EntityFrameworkCore.SqlRepositories;
  5. using Business.SaleForecast;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Threading.Tasks;
  10. using Volo.Abp.Application.Services;
  11. using Volo.Abp.DependencyInjection;
  12. using Volo.Abp.Domain.Repositories;
  13. using Volo.Abp.MultiTenancy;
  14. using Volo.Abp.Uow;
  15. namespace Business.SaleForecastManagement
  16. {
  17. /// <summary>
  18. /// 产能分析
  19. /// </summary>
  20. public class MonthlyCapacityLoadAppService : ApplicationService, IMonthlyCapacityLoadAppService, ITransientDependency
  21. {
  22. #region 服务
  23. /// <summary>
  24. /// 物料
  25. /// </summary>
  26. private IRepository<ic_item, long> _ic_item;
  27. /// <summary>
  28. /// 整体需求计划明细
  29. /// </summary>
  30. private ISqlRepository<OverallDemandPlanDtl> _overallDemandPlanDtl;
  31. /// <summary>
  32. /// 生产线明细
  33. /// </summary>
  34. private ISqlRepository<ProdLineDetail> _prodLineDetail;
  35. /// <summary>
  36. /// 工作日历数据
  37. /// </summary>
  38. private ISqlRepository<ShopCalendarWorkCtr> _shopCalendarWorkCtr;
  39. /// <summary>
  40. /// 产线休息时间记录表
  41. /// </summary>
  42. private ISqlRepository<QualityLineWorkDetail> _qualityLineWorkDetail;
  43. /// <summary>
  44. /// 节假日记录表
  45. /// </summary>
  46. private ISqlRepository<HolidayMaster> _holidayMaster;
  47. /// <summary>
  48. /// 月度产能共识主表
  49. /// </summary>
  50. private ISqlRepository<MonthlyProdCapacityMain> _monthlyProdCapacityMain;
  51. /// <summary>
  52. /// 月度产能共识明细表
  53. /// </summary>
  54. private ISqlRepository<MonthlyProdCapacityDtl> _monthlyProdCapacityDtl;
  55. /// <summary>
  56. /// 标准物料规格型号设置表
  57. /// </summary>
  58. private ISqlRepository<StandardItemModelSet> _standardItemModelSet;
  59. /// <summary>
  60. /// 工作单元
  61. /// </summary>
  62. private readonly IUnitOfWorkManager _unitOfWorkManager;
  63. /// <summary>
  64. /// 日志
  65. /// </summary>
  66. private readonly ICurrentTenant _currentTenant;
  67. /// <summary>
  68. /// 雪花算法
  69. /// </summary>
  70. SnowFlake help = new SnowFlake();
  71. #endregion
  72. #region 构造函数
  73. /// <summary>
  74. /// 构造函数
  75. /// </summary>
  76. public MonthlyCapacityLoadAppService(
  77. IRepository<ic_item, long> ic_item,
  78. ISqlRepository<OverallDemandPlanDtl> overallDemandPlanDtl,
  79. ISqlRepository<ProdLineDetail> prodLineDetail,
  80. ISqlRepository<ShopCalendarWorkCtr> shopCalendarWorkCtr,
  81. ISqlRepository<QualityLineWorkDetail> qualityLineWorkDetail,
  82. ISqlRepository<HolidayMaster> holidayMaster,
  83. ISqlRepository<MonthlyProdCapacityMain> monthlyProdCapacityMain,
  84. ISqlRepository<MonthlyProdCapacityDtl> monthlyProdCapacityDtl,
  85. IUnitOfWorkManager unitOfWorkManager,
  86. ICurrentTenant currentTenant,
  87. ISqlRepository<StandardItemModelSet> standardItemModelSet
  88. )
  89. {
  90. _ic_item= ic_item;
  91. _overallDemandPlanDtl= overallDemandPlanDtl;
  92. _prodLineDetail= prodLineDetail;
  93. _shopCalendarWorkCtr= shopCalendarWorkCtr;
  94. _qualityLineWorkDetail= qualityLineWorkDetail;
  95. _holidayMaster= holidayMaster;
  96. _monthlyProdCapacityMain= monthlyProdCapacityMain;
  97. _monthlyProdCapacityDtl= monthlyProdCapacityDtl;
  98. _unitOfWorkManager= unitOfWorkManager;
  99. _currentTenant= currentTenant;
  100. _standardItemModelSet= standardItemModelSet;
  101. }
  102. #endregion
  103. /// <summary>
  104. /// 产能分析
  105. /// </summary>
  106. /// <param name="input"></param>
  107. /// <returns></returns>
  108. /// <exception cref="NotImplementedException"></exception>
  109. public async Task<string> CapacityAnalysis(InputDto input)
  110. {
  111. //1、获取数据
  112. //1.1 根据年、月、版本号获取整体需求计划明细
  113. List<OverallDemandPlanDtl> planDtls = _overallDemandPlanDtl.Select(p=>p.Year == input.year && p.Month == input.month && p.Version == input.version && p.tenant_id == input.tenant_id && p.factory_id == input.factory_id).OrderBy(p=>p.ProdLine).ThenBy(p=>p.ProdRange).ThenBy(p=>p.Model).ThenBy(p=>p.PlanDate).ToList();
  114. //1.2 根据规格型号获取物料数据
  115. List<string> models = planDtls.Select(p => p.Model).Distinct().ToList();
  116. List<StandardItemModelSet> standards = _standardItemModelSet.Select(p=> models.Contains(p.Model) && p.tenant_id == input.tenant_id && p.factory_id == input.factory_id);
  117. //1.3 根据物料编码获取产线数据
  118. List<ProdLineDetail> lines = _prodLineDetail.Select(p => standards.Select(m => m.ItemNumber).Contains(p.Part) && p.Domain == input.factory_id.ToString() && p.IsActive);
  119. //1.4 根据产线获取工作日历数据和产线休息配置数据
  120. List<ShopCalendarWorkCtr> calendars = _shopCalendarWorkCtr.Select(p=> lines.Select(m=>m.Line).Contains(p.ProdLine) && p.Domain == input.factory_id.ToString() && p.IsActive);
  121. List<QualityLineWorkDetail> lineWorks = _qualityLineWorkDetail.Select(p => lines.Select(m => m.Line).Contains(p.ProdLine) && p.Domain == input.factory_id.ToString() && p.IsActive);
  122. //1.5 获取当前年和下一年的节假日配置数据
  123. 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);
  124. //月度产能共识主表
  125. List<MonthlyProdCapacityMain> capacityMains = new List<MonthlyProdCapacityMain>();
  126. //月度产能共识明细表
  127. List<MonthlyProdCapacityDtl> capacityDtls = new List<MonthlyProdCapacityDtl>();
  128. foreach (var item in planDtls)
  129. {
  130. //获取当前产品的生产线
  131. var std = standards.FirstOrDefault(p => p.Model == item.Model);
  132. if (std == null)
  133. {
  134. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("CapacityAnalysis", "规格型号【" + item.Model + "】没有维护标准物料数据", _currentTenant.Id.ToString());
  135. return "NO|规格型号【" + item.Model + "】没有维护标准物料数据,请维护后再发布!";
  136. }
  137. var curLines = lines.Where(p=>p.Part == std.ItemNumber).OrderBy(p => p.Line).ToList();
  138. //过滤产线
  139. var distLines = curLines.Select(p => p.Line).Distinct().ToList();
  140. if (distLines.Count == 0)
  141. {
  142. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("CapacityAnalysis", "物料【" + std.ItemNumber + "】没有维护产线数据", _currentTenant.Id.ToString());
  143. return "NO|物料【" + std.ItemNumber + "】没有维护产线数据,请维护后再发布!";
  144. }
  145. foreach (var dl in distLines)
  146. {
  147. //添加月度产能共识主表数据
  148. MonthlyProdCapacityMain main = new MonthlyProdCapacityMain();
  149. main.Id = help.NextId();
  150. main.Version = input.version;//整体需求计划版本号
  151. main.Year = Convert.ToInt16(item.PlanDate.Substring(0, 4));
  152. main.Month = Convert.ToInt16(item.PlanDate.Substring(4, 2));
  153. main.ProdRange = item.ProdRange;
  154. main.Model = item.Model;
  155. main.ProdQty = item.Qty;
  156. main.ProdLine = dl;
  157. main.Qty = item.Qty;
  158. main.tenant_id = item.tenant_id;
  159. main.factory_id = item.factory_id;
  160. main.Version = item.Version;
  161. main.CreateTime = DateTime.Now;
  162. capacityMains.Add(main);
  163. //添加月度产能共识产能效率数据
  164. MonthlyProdCapacityDtl dtl = new MonthlyProdCapacityDtl();
  165. dtl.MainId = main.Id;
  166. dtl.Version = input.version;
  167. dtl.Year = main.Year;
  168. dtl.Month = main.Month;
  169. dtl.ProdLine = dl;
  170. //计算每天工作时间
  171. var curCal = calendars.FirstOrDefault(p => p.ProdLine == dl);
  172. if (curCal == null) {
  173. continue;
  174. }
  175. dtl.DailyWorks = curCal.ShiftsHours1;
  176. dtl.FlightQty = 1;
  177. //计算当月工作天数
  178. var curHoildays = holidays.Where(p => p.Dated.Value.Year == main.Year && p.Dated.Value.Month == main.Month).ToList();
  179. //当月天数
  180. int days = DateTime.DaysInMonth(main.Year.Value, main.Month.Value);
  181. //当月周末天数
  182. int weekDays = CalcWeekDays(days,Convert.ToDateTime(main.Year.ToString()+"-"+main.Month.ToString()+"-01"));
  183. dtl.YearWorks= days-weekDays-curHoildays.Where(p=>p.Ufld1 == "休假").Count() + curHoildays.Where(p=>p.Ufld1 == "调班").Count();
  184. dtl.AvailableTimes= dtl.DailyWorks * dtl.FlightQty * dtl.YearWorks;
  185. //计算产线耗时
  186. var line = curLines.Where(p => p.Line == dl).OrderByDescending(p=>p.Op).First();
  187. dtl.NeedWorks= line.Rate == 0? 0:( Math.Ceiling(main.Qty.GetValueOrDefault() / line.Rate));
  188. dtl.ProdRate= 100;
  189. dtl.Rate= dtl.AvailableTimes == 0? 0: Math.Floor(dtl.NeedWorks.GetValueOrDefault()/ dtl.AvailableTimes.GetValueOrDefault() * 100);
  190. dtl.IsOverTime = dtl.NeedWorks > dtl.YearWorks ? "是" : "否";
  191. dtl.OverTimes = dtl.IsOverTime == "是" ? (dtl.NeedWorks - dtl.YearWorks) : 0;
  192. dtl.tenant_id = main.tenant_id;
  193. dtl.factory_id = main.factory_id;
  194. capacityDtls.Add(dtl);
  195. }
  196. }
  197. //保存数据
  198. using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
  199. {
  200. try
  201. {
  202. //先删除数据
  203. _monthlyProdCapacityMain.Delete(p =>p.tenant_id == input.tenant_id && p.factory_id == input.factory_id && p.Version.Contains(input.version.Substring(0, 7)));
  204. _monthlyProdCapacityDtl.Delete(p => p.tenant_id == input.tenant_id && p.factory_id == input.factory_id && p.Version.Contains(input.version.Substring(0, 7)));
  205. //插入数据
  206. _monthlyProdCapacityMain.Insert(capacityMains);
  207. _monthlyProdCapacityDtl.Insert(capacityDtls);
  208. await unitOfWork.CompleteAsync();
  209. }
  210. catch (Exception e)
  211. {
  212. unitOfWork.Dispose();
  213. new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("CapacityAnalysis", "生成【"+input.year+"年"+input.month+"月】月度产能共识失败:" + e.Message, _currentTenant.Id.ToString());
  214. return "NO|" + e.Message;
  215. };
  216. }
  217. return "OK|发布成功!";
  218. }
  219. /// <summary>
  220. /// 计算当月有多少个周末
  221. /// </summary>
  222. /// <param name="days"></param>
  223. /// <param name="startDay"></param>
  224. /// <returns></returns>
  225. private int CalcWeekDays(int days, DateTime startDay)
  226. {
  227. int sumDays = 0;
  228. for (int i = 0; i < days; i++)
  229. {
  230. int weekDays = (int)startDay.AddDays(i).DayOfWeek;
  231. if (weekDays == 0 || weekDays == 6)
  232. {
  233. sumDays++;
  234. }
  235. }
  236. return sumDays;
  237. }
  238. }
  239. }