zhengly 2 éve
szülő
commit
6427702dd8

+ 131 - 21
MicroServices/Business/Business.Application/SaleForecastManagement/AnnualProductionOutlineAppService.cs

@@ -6,6 +6,7 @@ using Business.EntityFrameworkCore.SqlRepositories;
 using Business.SaleForecast;
 using Business.StructuredDB.SaleFcst;
 using Business.StructuredDB.WMS;
+using Microsoft.EntityFrameworkCore.Infrastructure;
 using NetTopologySuite.Algorithm;
 using RazorEngine;
 using Spire.Pdf.General.Render.Decode.Jpeg2000.j2k.wavelet.synthesis;
@@ -20,6 +21,7 @@ using Volo.Abp.DependencyInjection;
 using Volo.Abp.Domain.Repositories;
 using Volo.Abp.MultiTenancy;
 using Volo.Abp.Uow;
+using ZstdSharp.Unsafe;
 using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
 
 namespace Business.SaleForecastManagement
@@ -69,6 +71,23 @@ namespace Business.SaleForecastManagement
         /// 平台库存表
         /// </summary>
         private readonly IRepository<WMS_PlatformInventory, long> _PlatformInventory;
+        /// <summary>
+        /// 已发货记录
+        /// </summary>
+        private ISqlRepository<ASNBOLShipperDetail> _ASNBOLShipperDetail;
+        /// <summary>
+        /// 工单工艺路线明细
+        /// </summary>
+        private ISqlRepository<WorkOrdRouting> _workOrdRouting;
+        /// <summary>
+        /// 补货模型
+        /// </summary>
+        private IRepository<ReplenishmentModel, long> _replenishmentModel;
+        /// <summary>
+        /// 主生产计划
+        /// </summary>
+        private IRepository<ProductionMasterPlan, long> _productionMasterPlan;
+
 
         /// <summary>
         /// 雪花算法
@@ -90,18 +109,26 @@ namespace Business.SaleForecastManagement
             ISqlRepository<ProdLineDetail> prodLineDetail,
             IRepository<WMS_PlatformInventory, long> PlatformInventory,
             ISqlRepository<RoutingOpDetail> routingOpDetail,
-            ISqlRepository<LocationDetail> locationDetail
+            ISqlRepository<ASNBOLShipperDetail> ASNBOLShipperDetail,
+            ISqlRepository<WorkOrdRouting> workOrdRouting,
+            ISqlRepository<LocationDetail> locationDetail,
+            IRepository<ReplenishmentModel, long> replenishmentModel,
+            IRepository<ProductionMasterPlan, long> productionMasterPlan
             )
         {
             _unitOfWorkManager = unitOfWorkManager;
             _currentTenant = currentTenant;
             _PlatformInventory = PlatformInventory;
             _prodLineDetail = prodLineDetail;
+            _workOrdRouting = workOrdRouting;
             _routingOpDetail = routingOpDetail;
             _locationDetail = locationDetail;
+            _ASNBOLShipperDetail = ASNBOLShipperDetail;
             _yearDemandManagement = yearDemandManagement;
             _yearDemandManagementHistory = yearDemandManagementHistory;
             _annualProductionOutline = annualProductionOutline;
+            _replenishmentModel = replenishmentModel;
+            _productionMasterPlan = productionMasterPlan;
         }
         #endregion
         /// <summary>
@@ -121,42 +148,76 @@ namespace Business.SaleForecastManagement
             List<ProdLineDetail> prodLines = _prodLineDetail.Select(p => yearDemands.Select(m => m.SAPItemNumber).Contains(p.Part) && p.Domain == input.factory_id.ToString() && p.IsActive && routingOpList.Select(m => m.Op).Contains(p.Op)).OrderBy(x => x.Sequence).ToList();
             List<LocationDetail> locations = _locationDetail.Select(x => yearDemands.Select(m => m.SAPItemNumber).Contains(x.ItemNum) && x.Domain == input.factory_id.ToString() && x.IsActive).ToList();
             //平台库存
-            var platformInvList = _PlatformInventory.GetListAsync(a => yearDemands.Select(m => m.SAPItemNumber).Contains(a.SAPItemNumber) && a.tenant_id == input.tenant_id && a.factory_id == input.factory_id).Result;
-            //取上一个月发货出库记录
-            //IEnumerable<ASNBOLShipperDetail> shipList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.RealQty > 0 && planItemList.Contains(a.ContainerItem)).Where(s => s.ShipDate >= getMonthStartTime(-1) && s.ShipDate <= getMonthEndTime(-1));
-            //在制  -- 工单计划中的数量   工单数量-完成数=生产中的在制
+            var platformInvList = _PlatformInventory.GetListAsync(a => yearDemands.Select(m => m.SAPItemNumber).Contains(a.SAPItemNumber) && a.tenant_id == input.tenant_id && a.factory_id == input.factory_id && !a.IsDeleted).Result;
+            var replenishmentModels = _replenishmentModel.GetListAsync(x => !x.IsDeleted && x.isparam && yearDemands.Select(m => m.SAPItemNumber).Contains(x.number)).Result.ToList();
+            // 获取某年某月的起始日期和结束日期
+            int year = input.year;
+            int month = DateTime.Now.Month;
+            DateTime start = new DateTime(year, month, 1);
+            DateTime end = start.AddMonths(1).AddDays(-1);
+            //取当月发货出库记录
+            var shipList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.RealQty > 0 && yearDemands.Select(p => p.SAPItemNumber).Contains(a.ContainerItem)).Where(s => s.ShipDate >= start && s.ShipDate <= end);
+            #region 在制数量
+            //获取在制数量 获取工单数取每年4月到12月底的工单
+            DateTime startYear = new DateTime(year, 4, 1);
+            DateTime endYear = new DateTime(year, 12, 31);
+            List<WorkOrdRouting> workOrdRoutings = _workOrdRouting.Select(x => x.IsActive && x.QtyComplete > 0 && x.Domain == input.factory_id.ToString()).Where(p => p.DueDate >= startYear && p.DueDate <= endYear).ToList();
+            decimal? InProductionQty = 0.00m;
+            var workOrds = workOrdRoutings.GroupBy(x => x.WorkOrd).ToList();
+            //按照工单循环
+            //某工单10-90工序   Max(10-80工序QtyComplete)-90工序QtyComplete =在制数量
+            foreach (var item in workOrds)
+            {
+                var workOrdRoutingList = workOrdRoutings.Where(x => x.WorkOrd == item.Key).OrderByDescending(o => o.OP).ToList();
+                //找出最大工序
+                var MaxOp = workOrdRoutingList.FirstOrDefault();
+                //查询出其他工序最大值
+                var MaxQtyComplete = workOrdRoutingList.Where(x => x.RecID != MaxOp.RecID).ToList().Max(o => o.QtyComplete);
+                InProductionQty += MaxQtyComplete - MaxOp.QtyComplete;
+            }
+            #endregion
             //年度生产大纲实体
             List<AnnualProductionOutline> annualProductionOutlines = new List<AnnualProductionOutline>();
             List<YearDemandManagement> frontYearDemand = new List<YearDemandManagement>();
             foreach (var item in yearDemands)
             {
                 var routingOp = routingOps.Where(x => x.RoutingCode == item.SAPItemNumber).ToList();
+                //组装标准工时
                 var Assembly = routingOp.Where(x => x.Descr == "组装").FirstOrDefault();
+                //热封标准工时
                 var HeatSealing = routingOp.Where(x => x.Descr == "热封").FirstOrDefault();
+                //包装标准工时
                 var Packaging = routingOp.Where(x => x.Descr == "包装").FirstOrDefault();
                 var prodLine = prodLines.Where(x => x.Part == item.SAPItemNumber).OrderBy(x => x.Sequence).FirstOrDefault();
                 //不同库位库存数量
                 var locationList = locations.Where(x => x.ItemNum == item.SAPItemNumber).ToList();
+                //平台数据
                 var platformInvs = platformInvList.Where(x => x.SAPItemNumber == item.SAPItemNumber).ToList();
-                var QtySum = yearDemands.Where(x => x.SAPItemNumber == item.SAPItemNumber).ToList();
+                //销售预测 对应 Excel中公式 AVERAGE 如果预测为0不参与计算排产批量
+                var QtySum = yearDemands.Where(x => x.SAPItemNumber == item.SAPItemNumber && x.Qty > 0).ToList();
                 //排产批量:(AVG(1 - 12月销售预测)/ 100 )=(0.45 = 1 小数向上取整)  *100 = 100
                 var pcpl = Math.Ceiling(QtySum.Sum(p => p.Qty) / QtySum.Count()) * 100;
-                //库存合计 + 在制+已发货
-                var locationSum = (locationList.Count == 0 ? 0 : locationList.Sum(x => x.QtyOnHand)) + (platformInvs.Count == 0 ? 0 : platformInvs.Sum(x => x.InventoryQuantity));
-                //if (annualProductionOutlines.Count > 0)
-                //{
+                //库存合计 + 在制+已发货 + 灭菌中 TODO: 灭菌中取值待确定
+                var ship = shipList.Where(x => x.ContainerItem == item.SAPItemNumber).ToList();
+                var locationSum = (locationList.Count == 0 ? 0 : locationList.Sum(x => x.QtyOnHand)) + (platformInvs.Count == 0 ? 0 : platformInvs.Sum(x => x.InventoryQuantity)) + (ship.Count == 0 ? 0 : ship.Sum(x => x.RealQty)) + InProductionQty + 0;
                 //前面N个月的生产数量
                 var frontQtySum = annualProductionOutlines.Sum(x => x.Qty);
-                var num = (locationSum + frontQtySum) - frontYearDemand.Sum(m => m.Qty) - item.Qty / 2;
+                //生产数量:3月为例子,if((库存合计和前2月生产数量)-(前2个月销售预测数据+安全库存)-当月销售预测数据 / 2 < 0)
+                // { 排产批量 * ((-(库存合计+前2个月生产数量)) +  (安全库存+前2个月销售预测) + 当月销售预测 / 2 ) / 排产批量 ) } else {0}
+                decimal ProduceQty = 0.00m;
+                //判断库存是否满足需要,满足则不用生产
+                var num = (locationSum.Value + frontQtySum) - frontYearDemand.Sum(m => m.Qty) + 0 - item.Qty / 2;
                 if (num < 0)
                 {
-                    num = pcpl * Math.Ceiling((-(locationSum + frontQtySum)) + frontYearDemand.Sum(m => m.Qty) + item.Qty / 2);
+                    ProduceQty = pcpl * Math.Ceiling((-(locationSum.Value + frontQtySum)) + (frontYearDemand.Sum(m => m.Qty) + 0) + item.Qty / 2);
                 }
-                // }
-                //生产数量:3月为例子,(库存和前2月生产数量)-(前2个月销售预测数据)-当月销售预测数据 / 2 < 0  else 排产批量 *((-库存合计数量 + 前2个月销售预测数量 + 当月销售预测数量 / 2)/ 批量排产)
+                else
+                {
+                    ProduceQty = 0;
+                }
+
                 //生成年度生产大纲
                 AnnualProductionOutline annualProductionOutline = new AnnualProductionOutline();
-                //TODO:取值
                 annualProductionOutline.Year = item.Year;
                 annualProductionOutline.Area = item.Area;
                 annualProductionOutline.ProdLine = item.ProdLine;
@@ -166,12 +227,12 @@ namespace Business.SaleForecastManagement
                 annualProductionOutline.Model = item.Model;
                 annualProductionOutline.Languages = item.Languages;
                 annualProductionOutline.PlanMonth = item.PlanMonth;
-                annualProductionOutline.Qty = num;
+                annualProductionOutline.Qty = ProduceQty;
                 annualProductionOutline.StandardHours = (Assembly == null ? 0 : Assembly.RunTime) + (HeatSealing == null ? 0 : HeatSealing.RunTime) + (Packaging == null ? 0 : Packaging.RunTime);
                 //组装热封包装工时乘以数量 =单月工时
-                annualProductionOutline.AssemblyHours = Assembly == null ? 0 : Assembly.RunTime * num;
-                annualProductionOutline.HeatSealingHours = HeatSealing == null ? 0 : HeatSealing.RunTime * num;
-                annualProductionOutline.PackagingHours = Packaging == null ? 0 : Packaging.RunTime * num;
+                annualProductionOutline.AssemblyHours = Assembly == null ? 0 : Assembly.RunTime * ProduceQty;
+                annualProductionOutline.HeatSealingHours = HeatSealing == null ? 0 : HeatSealing.RunTime * ProduceQty;
+                annualProductionOutline.PackagingHours = Packaging == null ? 0 : Packaging.RunTime * ProduceQty;
                 annualProductionOutline.Totalhours = annualProductionOutline.AssemblyHours + annualProductionOutline.HeatSealingHours + annualProductionOutline.Totalhours;
                 annualProductionOutline.OrderNum = item.OrderNum;
                 annualProductionOutlines.Add(annualProductionOutline);
@@ -182,17 +243,66 @@ namespace Business.SaleForecastManagement
             {
                 try
                 {
-                    await _annualProductionOutline.InsertManyAsync(annualProductionOutlines);
+                    //await _annualProductionOutline.InsertManyAsync(annualProductionOutlines);
+                    await unitOfWork.CompleteAsync();
+                }
+                catch (Exception e)
+                {
+                    unitOfWork.Dispose();
+                    new NLogHelper("AnnualProductionOutlineAppService").WriteLog("SaveAnnualProductionOutline", "【" + input.year + "年" + "】年度生成大纲生成失败:" + e.Message, _currentTenant.Id.ToString());
+                    return "NO|" + e.Message;
+                };
+            }
+            return "OK";
+        }
+
+        /// <summary>
+        /// 生成主计划
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        public async Task<string> SaveProductionMasterPlan(InputDto input)
+        {
+            //计算当前年月的N0,N+1,N+2
+            List<string> planMons = new List<string>();
+            string strN0 = input.year.ToString() + "-" + input.month.ToString("00");
+            planMons.Add(strN0);
+            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");
+            planMons.Add(strN1);
+            newYear = newMonth == 12 ? newYear + 1 : newYear;
+            newMonth = newMonth == 12 ? 1 : newMonth + 1;
+            string strN2 = newYear.ToString() + "-" + newMonth.ToString("00");
+            planMons.Add(strN2);
+            //N0,N+1,N+2月度发货计划
+            var productionMasterPlan = _productionMasterPlan.GetListAsync(x => x.Year == input.year && !x.IsDeleted && x.tenant_id == input.tenant_id && x.company_id == input.company_id && x.factory_id == input.factory_id && planMons.Contains(x.PlanMonth)).Result.OrderBy(p => p.OrderNum).ThenBy(o => o.PlanMonth).ToList();
+            foreach (var item in productionMasterPlan)
+            {
+
+            }
+
+
+
+
+
+            //保存数据
+            using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
+            {
+                try
+                {
+                    //await _annualProductionOutline.InsertManyAsync(annualProductionOutlines);
                     await unitOfWork.CompleteAsync();
                 }
                 catch (Exception e)
                 {
                     unitOfWork.Dispose();
-                    new NLogHelper("AnnualProductionOutlineAppService").WriteLog("SaveAnnualProductionOutline", "【" + input.year + "年" + "】月度需求预测更新失败:" + e.Message, _currentTenant.Id.ToString());
+                    new NLogHelper("AnnualProductionOutlineAppService").WriteLog("SaveProductionMasterPlan", "【" + input.year + "年" + "】主计划生成失败:" + e.Message, _currentTenant.Id.ToString());
                     return "NO|" + e.Message;
                 };
             }
             return "OK";
+
         }
     }
 }

+ 6 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/WorkOrdRouting.cs

@@ -80,6 +80,12 @@ namespace Business.Domain
         /// </summary>
         [Comment("订单数量")]
         public decimal? QtyOrded { get; set; }
+        /// <summary>
+        /// 报工数量
+        /// </summary>
+        [Comment("报工数量")]
+        public decimal? QtyComplete { get; set; }
+        
 
         /// <summary>
         /// 工序清场时长(小时)

+ 9 - 0
MicroServices/Business/Business.HttpApi/Controllers/AnnualProductionOutlineController.cs

@@ -22,6 +22,15 @@ namespace Business.Controllers
         /// 年度生产大纲
         /// </summary>
         private readonly IAnnualProductionOutlineAppService _IAnnualProductionOutlineAppService;
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="MonthlyCapacityLoadAppService"></param>
+        public AnnualProductionOutlineController(IAnnualProductionOutlineAppService MonthlyCapacityLoadAppService)
+        {
+            _IAnnualProductionOutlineAppService = MonthlyCapacityLoadAppService;
+        }
         /// <summary>
         /// 月度需求分析
         /// </summary>