| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- using Business.Core.Enum;
- using Business.Core.Utilities;
- using Business.Domain;
- using Business.Dto;
- 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;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using Volo.Abp.Application.Dtos;
- using Volo.Abp.Application.Services;
- 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
- {
- public class AnnualProductionOutlineAppService : ApplicationService, ITransientDependency, IAnnualProductionOutlineAppService
- {
- #region 服务
- /// <summary>
- /// 工作单元
- /// </summary>
- private readonly IUnitOfWorkManager _unitOfWorkManager;
- /// <summary>
- /// 日志
- /// </summary>
- private readonly ICurrentTenant _currentTenant;
- /// <summary>
- /// 年度销售预测
- /// </summary>
- private IRepository<YearDemandManagement, long> _yearDemandManagement;
- /// <summary>
- /// 年度销售预测历史记录
- /// </summary>
- private IRepository<YearDemandManagementHistory, long> _yearDemandManagementHistory;
- /// <summary>
- /// 年度生产大纲
- /// </summary>
- private IRepository<AnnualProductionOutline, long> _annualProductionOutline;
- /// <summary>
- /// 生产线明细
- /// </summary>
- private ISqlRepository<ProdLineDetail> _prodLineDetail;
- /// <summary>
- /// 标准工艺流程表
- /// </summary>
- private ISqlRepository<RoutingOpDetail> _routingOpDetail;
- /// <summary>
- /// 库存表
- /// </summary>
- private ISqlRepository<LocationDetail> _locationDetail;
- /// <summary>
- /// 平台库存表
- /// </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>
- /// 雪花算法
- /// </summary>
- SnowFlake help = new SnowFlake();
- #endregion
- #region 构造函数
- /// <summary>
- /// 构造函数
- /// </summary>
- public AnnualProductionOutlineAppService(
- IUnitOfWorkManager unitOfWorkManager,
- ICurrentTenant currentTenant,
- IRepository<YearDemandManagement, long> yearDemandManagement,
- IRepository<AnnualProductionOutline, long> annualProductionOutline,
- IRepository<YearDemandManagementHistory, long> yearDemandManagementHistory,
- ISqlRepository<ProdLineDetail> prodLineDetail,
- IRepository<WMS_PlatformInventory, long> PlatformInventory,
- ISqlRepository<RoutingOpDetail> routingOpDetail,
- 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>
- /// 生成年度生产大纲
- /// </summary>
- /// <param name="input"></param>
- /// <returns></returns>
- /// <exception cref="NotImplementedException"></exception>
- public async Task<string> SaveAnnualProductionOutline(InputDto input)
- {
- //获取当前导入或修改数据
- 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).ThenBy(o => o.PlanMonth).ToList();
- //标准工艺路径表
- List<RoutingOpDetail> routingOps = _routingOpDetail.Select(p => yearDemands.Select(m => m.SAPItemNumber).Contains(p.RoutingCode) && p.Domain == input.factory_id.ToString() && p.IsActive);
- var routingOpList = routingOps.Where(x => x.Descr == "组装").ToList();
- //生产线明细表
- 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 && !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();
- //销售预测 对应 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;
- //库存合计 + 在制+已发货 + 灭菌中 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);
- //生产数量: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)
- {
- ProduceQty = pcpl * Math.Ceiling((-(locationSum.Value + frontQtySum)) + (frontYearDemand.Sum(m => m.Qty) + 0) + item.Qty / 2);
- }
- else
- {
- ProduceQty = 0;
- }
- //生成年度生产大纲
- AnnualProductionOutline annualProductionOutline = new AnnualProductionOutline();
- annualProductionOutline.Year = item.Year;
- annualProductionOutline.Area = item.Area;
- annualProductionOutline.ProdLine = item.ProdLine;
- annualProductionOutline.ProdRange = item.ProdRange;
- annualProductionOutline.WorkshopLine = prodLine == null ? "" : prodLine.Line;
- annualProductionOutline.SAPItemNumber = item.SAPItemNumber;
- annualProductionOutline.Model = item.Model;
- annualProductionOutline.Languages = item.Languages;
- annualProductionOutline.PlanMonth = item.PlanMonth;
- 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 * 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);
- frontYearDemand.Add(item);
- }
- //保存数据
- 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());
- 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("SaveProductionMasterPlan", "【" + input.year + "年" + "】主计划生成失败:" + e.Message, _currentTenant.Id.ToString());
- return "NO|" + e.Message;
- };
- }
- return "OK";
- }
- }
- }
|