using Business.Core.Utilities; using Business.Domain; using Business.Dto; using Business.EntityFrameworkCore; using Business.EntityFrameworkCore.SqlRepositories; using Business.PriorityManagement; using Business.ReplenishmentManagement; using Business.ResourceExamineManagement.Dto; using Business.ResourceExamineManagement; using Business.StructuredDB.SaleFcst; using Business.StructuredDB.WMS; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Volo.Abp.Application.Services; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; using Newtonsoft.Json; using EFCore.BulkExtensions; using Business.Core.Enum; using Org.BouncyCastle.Crypto; using Business.StructuredDB.Replenishment; using System.ComponentModel.Design; using Newtonsoft.Json.Linq; using MathNet.Numerics.RootFinding; namespace Business.Replenishment { /// /// 产能分析 /// public class ReplenishmentAppService : ApplicationService, IReplenishmentAppService, ITransientDependency { #region 服务 /// /// 雪花算法 /// SnowFlake help = new SnowFlake(); private readonly IRepository _replenishmentROP; private readonly IRepository _domesticTerminalFcst; private readonly ISqlRepository _ASNBOLShipperDetail; private readonly IRepository _standardItemModelSet; private readonly ISqlRepository _invTransHist; private readonly ISqlRepository _SAPInv; private readonly IRepository _srmPurchase; private readonly ISqlRepository _monthlyShipmentPlan; private readonly ISqlRepository _generalizedCodeMaster; private readonly ISqlRepository _rf_serialnumber; private readonly ISqlRepository _locationDetail; private readonly IRepository _ic_item; private readonly IRepository _mysql_ic_item; private readonly ISqlRepository _itemMaster; private readonly IRepository _srm_pr_main; private readonly IRepository _mysql_srm_pr_main; private readonly IRepository _srm_po_occupy; private readonly IRepository _mysql_srm_po_occupy; private readonly IRepository _mes_morder; private readonly IRepository _mes_moentry; private readonly IRepository _mes_mooccupy; private readonly IRepository _mysql_mes_mooccupy; private readonly IRepository _mysql_b_bom_pretreatment; private readonly ISqlRepository _workOrdMaster; private readonly ISqlRepository _prodLineDetail; private readonly IRepository _ic_bom; private readonly IRepository _mysql_ic_bom; private readonly IRepository _ic_bom_child; private readonly IRepository _mysql_ic_bom_child; private readonly ISqlRepository _holidayMaster; private readonly IRepository _ic_item_stockoccupy; private readonly IRepository _mysql_ic_item_stockoccupy; private readonly IRepository _ic_item_stock; private readonly IRepository _mysql_ic_item_stock; private readonly IRepository _ic_substitute; private readonly IRepository _ic_substitute_group; private readonly IRepository _ic_substitute_group_detail; private readonly IRepository _mysql_ic_substitute; private readonly IRepository _mysql_ic_substitute_group; private readonly IRepository _mysql_ic_substitute_group_detail; private readonly IRepository _mysql_mes_moentry; private readonly ISqlRepository _workOrdDetail; private readonly IRepository _srm_po_list; private readonly IRepository _mysql_srm_po_list; private readonly ISqlRepository _routingOpDetail; private readonly ISqlRepository _productStructureMaster; private readonly ISqlRepository _shopCalendarWorkCtr; private readonly ISqlRepository _periodSequenceDet; private readonly ISqlRepository _qualityLineWorkDetail; private readonly IRepository _srm_po_main; private readonly IRepository _mysql_srm_po_main; private readonly IRepository _srm_purchase; private readonly IRepository _mysql_srm_purchase; private readonly IRepository _mysql_mes_morder; private readonly IRepository _mysql_crm_seorderentry; private readonly IRepository _mes_oorder; private readonly ISqlRepository _scheduleResultOpMaster; private readonly IRepository _productionMasterPlan; /// /// 年度销售预测 /// private IRepository _yearDemandManagement; /// /// 年度销售预测历史记录 /// private IRepository _yearDemandManagementHistory; /// /// 年度生产大纲 /// private IRepository _replenishmentAnnualProduction; /// /// 平台库存表 /// private readonly IRepository _PlatformInventory; /// /// 工单工艺路线明细 /// private ISqlRepository _workOrdRouting; /// /// 月度产能共识表 /// private IRepository _monthlyProdCapacity; /// /// 月度产能共识明细表 /// private IRepository _monthlyProdCapacityDtl; /// /// 计划订单表 /// private IRepository _crm_planorder; /// /// 平台库存表 /// private IRepository _platformInventory; /// /// 在途检查 /// private readonly PurchaseOrderAppService _purchaseOrderAppService; /// /// 计算BOM平铺物料情况 /// private readonly CalcBomViewAppService _CalcBomViewAppService; /// /// 预处理 /// private readonly PretreatmentAppService _pretreatmentAppService; /// /// 产能检查 /// private readonly ProductExamineAppService _productExamineAppService; /// /// 资源检查入参 /// private readonly SeorderentryDto param = new SeorderentryDto(); /// /// 生产线明细表 /// public List prodLines = new List(); /// /// 标准工艺路径表 /// public List routingOps = new List(); /// /// 排产记录表 /// public List periodSequences = new List(); /// /// 工作日历 /// public List calendarWorks = new List(); /// /// 休息时间段 /// public List qualityLineWorks = new List(); /// /// 节假日 /// public List holidays = new List(); private List leadTimeList; private List supplierList; private readonly BusinessBangDbContext _businessBangDbContext; private readonly BusinessDbContext _businessDbContext; private readonly ICurrentTenant _currentTenant; private readonly IUnitOfWorkManager _unitOfWorkManager; #endregion #region 构造函数 /// /// 构造函数 /// public ReplenishmentAppService( IRepository replenishmentROP, IRepository domesticTerminalFcst, ISqlRepository ASNBOLShipperDetail, IRepository standardItemModelSet, ISqlRepository invTransHist, ISqlRepository SAPInv, IRepository srmPurchase, ISqlRepository monthlyShipmentPlan, ISqlRepository generalizedCodeMaster, ISqlRepository rf_serialnumber, ISqlRepository locationDetail, IRepository ic_item, IRepository mysql_ic_item, ISqlRepository itemMaster, IRepository srm_pr_main, IRepository mysql_srm_pr_main, IRepository srm_po_occupy, IRepository mysql_srm_po_occupy, IRepository mes_morder, IRepository mes_moentry, IRepository mes_mooccupy, IRepository mysql_mes_mooccupy, IRepository mysql_b_bom_pretreatment, ISqlRepository workOrdMaster, ISqlRepository prodLineDetail, IRepository ic_bom, IRepository mysql_ic_bom, IRepository ic_bom_child, IRepository mysql_ic_bom_child, ISqlRepository holidayMaster, IRepository ic_item_stockoccupy, IRepository mysql_ic_item_stockoccupy, IRepository ic_item_stock, IRepository mysql_ic_item_stock, IRepository ic_substitute, IRepository ic_substitute_group, IRepository ic_substitute_group_detail, IRepository mysql_ic_substitute, IRepository mysql_ic_substitute_group, IRepository mysql_ic_substitute_group_detail, IRepository mysql_mes_moentry, ISqlRepository workOrdDetail, IRepository srm_po_list, IRepository mysql_srm_po_list, ISqlRepository routingOpDetail, ISqlRepository productStructureMaster, ISqlRepository shopCalendarWorkCtr, ISqlRepository periodSequenceDet, ISqlRepository qualityLineWorkDetail, IRepository srm_po_main, IRepository mysql_srm_po_main, IRepository srm_purchase, IRepository mysql_srm_purchase, IRepository mysql_mes_morder, IRepository mysql_crm_seorderentry, IRepository mes_oorder, ISqlRepository scheduleResultOpMaster, IRepository productionMasterPlan, IRepository yearDemandManagement, IRepository replenishmentAnnualProduction, IRepository yearDemandManagementHistory, IRepository PlatformInventory, ISqlRepository workOrdRouting, IRepository monthlyProdCapacity, IRepository monthlyProdCapacityDtl, IRepository crm_planorder, IRepository platformInventory, PretreatmentAppService pretreatmentAppService, PurchaseOrderAppService purchaseOrderAppService, CalcBomViewAppService CalcBomViewAppService, ProductExamineAppService productExamineAppService, BusinessBangDbContext businessBangDbContext, BusinessDbContext businessDbContext, ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager) { _replenishmentROP = replenishmentROP; _domesticTerminalFcst = domesticTerminalFcst; _ASNBOLShipperDetail = ASNBOLShipperDetail; _standardItemModelSet = standardItemModelSet; _invTransHist = invTransHist; _SAPInv = SAPInv; _srmPurchase = srmPurchase; _monthlyShipmentPlan = monthlyShipmentPlan; _generalizedCodeMaster = generalizedCodeMaster; _rf_serialnumber=rf_serialnumber; _locationDetail = locationDetail; _ic_item = ic_item; _mysql_ic_item = mysql_ic_item; _itemMaster = itemMaster; _srm_pr_main= srm_pr_main; _mysql_srm_pr_main= mysql_srm_pr_main; _srm_po_occupy = srm_po_occupy; _mysql_srm_po_occupy = mysql_srm_po_occupy; _mes_morder= mes_morder; _mes_moentry = mes_moentry; _mes_mooccupy = mes_mooccupy; _mysql_mes_mooccupy = mysql_mes_mooccupy; _mysql_b_bom_pretreatment = mysql_b_bom_pretreatment; _workOrdMaster = workOrdMaster; _prodLineDetail = prodLineDetail; _ic_bom = ic_bom; _mysql_ic_bom = mysql_ic_bom; _ic_bom_child = ic_bom_child; _mysql_ic_bom_child = mysql_ic_bom_child; _holidayMaster = holidayMaster; _ic_item_stockoccupy = ic_item_stockoccupy; _mysql_ic_item_stockoccupy = mysql_ic_item_stockoccupy; _ic_item_stock = ic_item_stock; _mysql_ic_item_stock = mysql_ic_item_stock; _ic_substitute = ic_substitute; _ic_substitute_group= ic_substitute_group; _ic_substitute_group_detail= ic_substitute_group_detail; _mysql_ic_substitute= mysql_ic_substitute; _mysql_ic_substitute_group= mysql_ic_substitute_group; _mysql_ic_substitute_group_detail= mysql_ic_substitute_group_detail; _mysql_mes_moentry = mysql_mes_moentry; _workOrdDetail = workOrdDetail; _srm_po_list = srm_po_list; _mysql_srm_po_list = mysql_srm_po_list; _routingOpDetail = routingOpDetail; _productStructureMaster = productStructureMaster; _shopCalendarWorkCtr=shopCalendarWorkCtr; _periodSequenceDet = periodSequenceDet; _qualityLineWorkDetail= qualityLineWorkDetail; _srm_po_main= srm_po_main; _mysql_srm_po_main= mysql_srm_po_main; _srm_purchase= srm_purchase; _mysql_srm_purchase = mysql_srm_purchase; _mysql_mes_morder = mysql_mes_morder; _mysql_crm_seorderentry = mysql_crm_seorderentry; _mes_oorder = mes_oorder; _scheduleResultOpMaster = scheduleResultOpMaster; _productionMasterPlan=productionMasterPlan; _PlatformInventory = PlatformInventory; _workOrdRouting = workOrdRouting; _ASNBOLShipperDetail = ASNBOLShipperDetail; _yearDemandManagement = yearDemandManagement; _yearDemandManagementHistory = yearDemandManagementHistory; _replenishmentAnnualProduction = replenishmentAnnualProduction; _holidayMaster = holidayMaster; _monthlyProdCapacity = monthlyProdCapacity; _monthlyProdCapacityDtl = monthlyProdCapacityDtl; _crm_planorder = crm_planorder; _platformInventory = platformInventory; _pretreatmentAppService = pretreatmentAppService; _CalcBomViewAppService = CalcBomViewAppService; _purchaseOrderAppService = purchaseOrderAppService; _productExamineAppService = productExamineAppService; _currentTenant =currentTenant; _businessBangDbContext= businessBangDbContext; _businessDbContext = businessDbContext; _unitOfWorkManager = unitOfWorkManager; } #endregion /// /// 生成年度生产大纲 /// /// /// /// public async Task SaveAnnualProductionOutline(InputDto input) { //获取当前导入或修改数据 List 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 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 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 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 = _replenishmentROP.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 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(); Dictionary dictInProduction = new Dictionary(); //按照工单循环 //某工单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; if (dictInProduction.ContainsKey(MaxOp.ItemNum)) { dictInProduction[MaxOp.ItemNum] += InProductionQty.Value; } else { dictInProduction.Add(MaxOp.ItemNum, InProductionQty.Value); } } #endregion //年度生产大纲实体 List annualProductionOutlines = new List(); List frontYearDemand = new List(); 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(); decimal itemInProduct = 0; if(dictInProduction.ContainsKey(item.SAPItemNumber)) { itemInProduct = dictInProduction[item.SAPItemNumber]; } 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)) + itemInProduct + 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; } //生成年度生产大纲 ReplenishmentAnnualProduction annualProductionOutline = new ReplenishmentAnnualProduction(); 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 _replenishmentAnnualProduction.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"; } /// /// 生成主计划 /// /// /// public async Task SaveProductionMasterPlan(InputDto input) { //计算当前年月的N0,N+1,N+2 List planMons = new List(); 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"; } /// /// 更新年度生产大纲 /// /// /// /// public async Task DemandAnalysis(InputDto input) { string productResult=await SaveAnnualProductionOutline(input); if(productResult!="OK") return productResult; string ropResult=await CalcROP(input); if(ropResult!="OK") return ropResult; return "OK|刷新成功!"; } /// /// 计算当月有多少个周末 /// /// /// /// private int CalcWeekDays(int days, DateTime startDay) { int sumDays = 0; for (int i = 0; i < days; i++) { int weekDays = (int)startDay.AddDays(i).DayOfWeek; if (weekDays == 0 || weekDays == 6) { sumDays++; } } return sumDays; } /// /// 生成整体需求计划 /// /// /// /// //public async Task OverallDemandPlan(InputDto input) //{ // //1.1、获取海外销售预测数据 // List 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(); // //1.2、获取平台预测收集数据 // List 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(); // //1.3、获取国内终端预测-T1汇总数据 // List 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(); // //计算当前年月的N+1,N+2 // string strN0 = input.year.ToString() + "-" + input.month.ToString("00"); // 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"); // newYear = newMonth == 12 ? newYear + 1 : newYear; // newMonth = newMonth == 12 ? 1 : newMonth + 1; // string strN2 = newYear.ToString() + "-" + newMonth.ToString("00"); // //整体需求计划 // List plans = new List(); // //计算海外 // List hwModels = overseasSales.Select(p => p.Model).Distinct().ToList(); // int OrderNum = 1; // foreach (var item in hwModels) // { // var curFcsts = overseasSales.Where(p => p.Model == item).ToList(); // OverallDemandPlan plan = new OverallDemandPlan(); // plan.Area = "海外"; // plan.Model = item; // plan.PlanMonth = strN0; // plan.Qty = curFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty); // plan.OrderNum = OrderNum; // plans.Add(plan); // plan = new OverallDemandPlan(); // plan.Area = "海外"; // plan.Model = item; // plan.PlanMonth = strN1; // plan.Qty = curFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty); // plan.OrderNum = OrderNum; // plans.Add(plan); // plan = new OverallDemandPlan(); // plan.Area = "海外"; // plan.Model = item; // plan.PlanMonth = strN2; // plan.Qty = curFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty); // plan.OrderNum = OrderNum; // plans.Add(plan); // OrderNum += 1; // } // //计算国内 // List gnModels = domesticFcsts.Select(p => p.Model).ToList(); // gnModels.AddRange(platformFcsts.Select(p => p.Model).ToList()); // gnModels = gnModels.Distinct().ToList(); // OrderNum = 1; // foreach (var item in gnModels) // { // var curDFcsts = domesticFcsts.Where(p => p.Model == item).ToList(); // var curPFcsts = platformFcsts.Where(p => p.Model == item).ToList(); // OverallDemandPlan plan = new OverallDemandPlan(); // plan.Area = "国内"; // plan.Model = item; // plan.PlanMonth = strN0; // plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty); // plan.OrderNum = OrderNum; // plans.Add(plan); // plan = new OverallDemandPlan(); // plan.Area = "国内"; // plan.Model = item; // plan.PlanMonth = strN1; // plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty); // plan.OrderNum = OrderNum; // plans.Add(plan); // plan = new OverallDemandPlan(); // plan.Area = "国内"; // plan.Model = item; // plan.PlanMonth = strN2; // plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty); // plan.OrderNum = OrderNum; // plans.Add(plan); // OrderNum += 1; // } // plans.ForEach(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.org_id = input.org_id; // p.create_by = input.create_by; // p.create_by_name = input.create_by_name; // p.create_time = DateTime.Now; // }); // //保存数据 // using (var unitOfWork = _unitOfWorkManager.Begin(false, true)) // { // try // { // //先删除 // 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); // //保存整体需求计划 // await _overallDemandPlan.InsertManyAsync(plans); // await unitOfWork.CompleteAsync(); // } // catch (Exception e) // { // unitOfWork.Dispose(); // new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("OverallDemandPlan", "生成【" + input.year + "年" + input.month + "月】整体需求计划失败:" + e.Message, _currentTenant.Id.ToString()); // return "NO|" + e.Message; // }; // } // return "OK|刷新成功!"; //} /// /// 调整ROP和最高库存水位 /// /// /// public async Task CalcROP(InputDto input) { //1.获取补货模型全局参数 ReplenishmentDto replenishmentDto = GetROPParam(input.factory_id.ToString()); //Step1:按照瑞奇、两大平台分别根据历史出库数据和预测出货数据计算ROP //Step2:计算瑞奇的M-M+2共12周补货(每次补EOP/4),计算海王的M-M+2共12周补货(每次补EOP/4),计算国科的M-M+2共12周补货(每次补EOP/4) //Step3:汇总Step2所有补货,为工厂的制造需求 //Step4:按照Step3制造需求做资源检查,按月统计各物料消耗预测 //Step5:按照各SKU的历史出库数据和Step4里计算的预测消耗数量计算参数 //Step6:计算各SKU的12周采购补货 //获取月度发货计划(一次导入三个月的销售预测),因为是固定格式yyyy-MM所以可以用字符串比较,避免写很多字符串判断相等 string planMonth = $"{DateTime.Now.Year}-{DateTime.Now.Month.ToString("00")}"; string planMonthMax = $"{DateTime.Now.AddMonths(replenishmentDto.SaleFcstMonth).Year}-{DateTime.Now.AddMonths(replenishmentDto.SaleFcstMonth).Month.ToString("00")}"; var planList = _monthlyShipmentPlan.Select(a => a.PlanMonth.CompareTo(planMonth) >= 0 && a.PlanMonth.CompareTo(planMonthMax) <= 0 && !a.IsDeleted).ToList(); var itemList = _ic_item.GetListAsync(a => planList.Select(p => p.SAPItemNumber).Contains(a.number) && a.tenant_id == input.tenant_id && a.company_id == input.company_id && !a.IsDeleted).Result; var mesItemList = _itemMaster.Select(a => planList.Select(p => p.SAPItemNumber).Contains(a.ItemNum) && a.Domain == input.factory_id.ToString() && a.IsActive); var srm_purchaseList = _srmPurchase.GetListAsync(a => planList.Select(p => p.SAPItemNumber).Contains(a.number) && a.tenant_id == input.tenant_id && a.company_id == input.company_id && !a.IsDeleted).Result; //获取补货模型前H周期和未来F个周期的数据 var ropModelList = _replenishmentROP.GetListAsync(a => a.zero_based_seqno >= -1 * replenishmentDto.HistoryOutStockMonth && a.zero_based_seqno <= replenishmentDto.SaleFcstMonth).Result; //发货计划物料列表 List planItemList = planList?.Select(a => a.SAPItemNumber).ToList(); //获取成品库存、灭菌库存、在制库存(会从SAP同步的库存表更新到LocationDetail、ic_item表中) //List sAPInvs = _SAPInv.Select(p => p.WERKS == input.factory_id.ToString() && itemNums.Contains(p.MATNR)); var locations = _locationDetail.Select(p => p.Domain == input.factory_id.ToString() && planList.Select(a => a.SAPItemNumber).Contains(p.ItemNum) && p.IsActive); var sapItemInv = _SAPInv.Select(a => planItemList.Contains(a.MATNR) && a.WERKS == input.factory_id.ToString()); //取上一个月发货出库记录 var 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) && a.ShipDate >= getMonthStartTime(-1) && a.ShipDate <= getMonthEndTime(-1)); //取本月发货出库记录 var shipMList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.RealQty > 0 && planItemList.Contains(a.ContainerItem) && a.ShipDate >= getMonthStartTime(0) && a.ShipDate <= DateTime.Now); //按照物料分组统计出货金额 var itemGroup = shipList.GroupBy(p => p.ContainerItem) .Select(p => new ASNBOLShipperDetail { QtyToShip = p.Sum(a => a.QtyToShip), ContainerItem = p.Key }).ToList(); //按照物料分组统计出货金额 var itemMGroup = shipMList.GroupBy(p => p.ContainerItem) .Select(p => new ASNBOLShipperDetail { QtyToShip = p.Sum(a => a.QtyToShip), ContainerItem = p.Key }).ToList(); List addList = new List(); List updateList = new List();//更新上一个月的实际出库数量 var mathtool = new MathNet.Numerics.Distributions.Normal(); ropModelList?.Where(r => r.isparam && r.seqno == DateTime.Now.AddMonths(-1).Month && r.year == DateTime.Now.AddMonths(-1).Year).ToList()?.ForEach (m => { if (itemGroup.Any(a => a.ContainerItem == m.number)) { m.actual_out_qty = itemGroup.Find(a => a.ContainerItem == m.number)?.QtyToShip; updateList.Add(m); } }); //需要按照成品资源检查计算原材料 planList?.Where(s => s.PlanMonth == planMonth).ToList()?.ForEach(a => { ReplenishmentROP rop = new ReplenishmentROP(); rop.number = a.SAPItemNumber; var icItem = itemList.Find(s => s.number == a.SAPItemNumber); if (icItem != null) { rop.name = icItem.name; rop.model = a.Model; rop.erp_cls = icItem.erp_cls; //物料属性: 0.配置类 1.自制 2.委外加工 3.外购 4.虚拟件 rop.fversion = icItem.fversion; rop.min_pack_qty = icItem.minpackqty; rop.moq = icItem.moq; } rop.actual_period_start_instock = 0; if (rop.distributionchannel == "海王" || rop.distributionchannel == "国科") { rop.actual_period_start_instock = locations.Find(l => l.ItemNum == a.SAPItemNumber)?.QtyOnHand; } else { rop.actual_period_start_instock = sapItemInv.Find(s => s.MATNR == a.SAPItemNumber)?.LABST.ToDecimal(); } rop.distributionchannel = a.DistributionChannel; rop.lifecycle = a.LifeCycle; rop.area = a.Area; rop.plan_out_qty = Math.Ceiling(a.Qty); rop.actual_out_qty = 0; if (itemMGroup.Any(m => m.ContainerItem == a.SAPItemNumber)) { rop.actual_out_qty = itemMGroup.Find(m => m.ContainerItem == a.SAPItemNumber)?.QtyToShip; } rop.year = DateTime.Now.Year; rop.long_period = "Y"; rop.short_period = "M"; rop.seqno = DateTime.Now.Month; rop.zero_based_seqno = 0; rop.period_start_date = getMonthStartTime(0); rop.period_end_date = getMonthEndTime(0); rop.monthl_avg_demand = CalcAvgDemand(planList, a.SAPItemNumber); rop.monthl_avg_demand_variance = Math.Ceiling(Convert.ToDecimal(CalcVariance(planList, a.SAPItemNumber))); rop.monthl_avg_outstock = CalcAvgOutStock(ropModelList, replenishmentDto, rop.actual_out_qty.Value, a.SAPItemNumber); if (mesItemList.Find(s => s.ItemNum == a.SAPItemNumber) != null) { rop.stock_turnover = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber).StockTurnOver; rop.supply_leadtime = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber)?.PurLT; rop.stock_turnover = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber)?.StockTurnOver; } else { rop.stock_turnover = 4; } if (srm_purchaseList.Find(s => s.number == a.SAPItemNumber) != null) { rop.supply_leadtime = srm_purchaseList.Find(s => s.number == a.SAPItemNumber).lead_time; } CalcFMRAndABC(rop, replenishmentDto, input); rop.security_stock = Math.Ceiling((decimal)(mathtool.InverseCumulativeDistribution((double)rop.service_level_pct.Value) * (double)rop.monthl_avg_demand_variance)); rop.eop = Math.Ceiling(rop.monthl_avg_demand.Value * rop.supply_leadtime.Value / DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month)); rop.rop_computed = rop.security_stock + rop.eop; rop.max_stock_level = rop.monthl_avg_outstock * (12 / rop.stock_turnover); rop.rop_revised = Math.Min(rop.rop_computed.Value, rop.max_stock_level.Value); rop.isparam = true; rop.tenant_id = input.tenant_id; rop.factory_id = input.factory_id; rop.create_time = DateTime.Now; rop.org_id = input.org_id; addList.Add(rop); }); addList?.ForEach(item => { item.GenerateNewId(help.NextId()); }); await _replenishmentROP.InsertManyAsync(addList); await _replenishmentROP.UpdateManyAsync(updateList); var ropModeAllList = _replenishmentROP.GetListAsync(a => a.year != DateTime.Now.Year && a.seqno != DateTime.Now.Month && a.isparam).Result; ropModeAllList?.ForEach(item => { item.seqno = item.seqno - 1; }); await _replenishmentROP.UpdateManyAsync(ropModeAllList); return "OK"; } /// /// 根据月计划生产周计划 /// /// /// public async Task CalcWeekPlan(InputDto input) { //1.获取补货模型全局参数 ReplenishmentDto replenishmentDto = GetROPParam(input.factory_id.ToString()); //Step1:按照瑞奇、两大平台分别根据历史出库数据和预测出货数据计算ROP //Step2:计算瑞奇的M-M+2共12周补货(每次补EOP/4),计算海王的M-M+2共12周补货(每次补EOP/4),计算国科的M-M+2共12周补货(每次补EOP/4) //Step3:汇总Step2所有补货,为工厂的制造需求 //Step4:按照Step3制造需求做资源检查,按月统计各物料消耗预测 //Step5:按照各SKU的历史出库数据和Step4里计算的预测消耗数量计算参数 //Step6:计算各SKU的12周采购补货 //获取月度发货计划(一次导入三个月的销售预测),因为是固定格式yyyy-MM所以可以用字符串比较,避免写很多字符串判断相等 string planMonth = $"{DateTime.Now.Year}-{DateTime.Now.Month.ToString("00")}"; string planMonthMax = $"{DateTime.Now.AddMonths(replenishmentDto.SaleFcstMonth).Year}-{DateTime.Now.AddMonths(replenishmentDto.SaleFcstMonth).Month.ToString("00")}"; var planList = _monthlyShipmentPlan.Select(a => a.PlanMonth.CompareTo(planMonth) >= 0 && a.PlanMonth.CompareTo(planMonthMax) <= 0 && !a.IsDeleted).ToList(); var itemList = _ic_item.GetListAsync(a => planList.Select(p => p.SAPItemNumber).Contains(a.number) && a.tenant_id == input.tenant_id && a.company_id == input.company_id && !a.IsDeleted).Result; var mesItemList = _itemMaster.Select(a => planList.Select(p => p.SAPItemNumber).Contains(a.ItemNum) && a.Domain == input.factory_id.ToString() && a.IsActive); var srm_purchaseList = _srmPurchase.GetListAsync(a => planList.Select(p => p.SAPItemNumber).Contains(a.number) && a.tenant_id == input.tenant_id && a.company_id == input.company_id && !a.IsDeleted).Result; //获取补货模型前H周期和未来F个周期的数据 var ropModelList = _replenishmentROP.GetListAsync(a => a.zero_based_seqno >= -1 * replenishmentDto.HistoryOutStockMonth && a.zero_based_seqno <= replenishmentDto.SaleFcstMonth).Result; //发货计划物料列表 List planItemList = planList?.Select(a => a.SAPItemNumber).ToList(); //获取成品库存、灭菌库存、在制库存(会从SAP同步的库存表更新到LocationDetail、ic_item表中) //List sAPInvs = _SAPInv.Select(p => p.WERKS == input.factory_id.ToString() && itemNums.Contains(p.MATNR)); var locations = _locationDetail.Select(p => p.Domain == input.factory_id.ToString() && planList.Select(a => a.SAPItemNumber).Contains(p.ItemNum) && p.IsActive); var sapItemInv = _SAPInv.Select(a => planItemList.Contains(a.MATNR) && a.WERKS == input.factory_id.ToString()); //取上一个月发货出库记录 var 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) && a.ShipDate >= getMonthStartTime(-1) && a.ShipDate <= getMonthEndTime(-1)); //取本月发货出库记录 var shipMList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.RealQty > 0 && planItemList.Contains(a.ContainerItem) && a.ShipDate >= getMonthStartTime(0) && a.ShipDate <= DateTime.Now); //按照物料分组统计出货金额 var itemGroup = shipList.GroupBy(p => p.ContainerItem) .Select(p => new ASNBOLShipperDetail { QtyToShip = p.Sum(a => a.QtyToShip), ContainerItem = p.Key }).ToList(); //按照物料分组统计出货金额 var itemMGroup = shipMList.GroupBy(p => p.ContainerItem) .Select(p => new ASNBOLShipperDetail { QtyToShip = p.Sum(a => a.QtyToShip), ContainerItem = p.Key }).ToList(); List addList = new List(); List updateList = new List();//更新上一个月的实际出库数量 var mathtool = new MathNet.Numerics.Distributions.Normal(); ropModelList?.Where(r => r.isparam && r.seqno == DateTime.Now.AddMonths(-1).Month && r.year == DateTime.Now.AddMonths(-1).Year).ToList()?.ForEach (m => { if (itemGroup.Any(a => a.ContainerItem == m.number)) { m.actual_out_qty = itemGroup.Find(a => a.ContainerItem == m.number)?.QtyToShip; updateList.Add(m); } }); //需要按照成品资源检查计算原材料 planList?.Where(s => s.PlanMonth == planMonth).ToList()?.ForEach(a => { ReplenishmentROP rop = new ReplenishmentROP(); rop.number = a.SAPItemNumber; var icItem = itemList.Find(s => s.number == a.SAPItemNumber); if (icItem != null) { rop.name = icItem.name; rop.model = a.Model; rop.erp_cls = icItem.erp_cls; //物料属性: 0.配置类 1.自制 2.委外加工 3.外购 4.虚拟件 rop.fversion = icItem.fversion; rop.min_pack_qty = icItem.minpackqty; rop.moq = icItem.moq; } rop.actual_period_start_instock = 0; if (rop.distributionchannel == "海王" || rop.distributionchannel == "国科") { rop.actual_period_start_instock = locations.Find(l => l.ItemNum == a.SAPItemNumber)?.QtyOnHand; } else { rop.actual_period_start_instock = sapItemInv.Find(s => s.MATNR == a.SAPItemNumber)?.LABST.ToDecimal(); } rop.distributionchannel = a.DistributionChannel; rop.lifecycle = a.LifeCycle; rop.area = a.Area; rop.plan_out_qty = Math.Ceiling(a.Qty); rop.actual_out_qty = 0; if (itemMGroup.Any(m => m.ContainerItem == a.SAPItemNumber)) { rop.actual_out_qty = itemMGroup.Find(m => m.ContainerItem == a.SAPItemNumber)?.QtyToShip; } rop.year = DateTime.Now.Year; rop.long_period = "Y"; rop.short_period = "M"; rop.seqno = DateTime.Now.Month; rop.zero_based_seqno = 0; rop.period_start_date = getMonthStartTime(0); rop.period_end_date = getMonthEndTime(0); rop.monthl_avg_demand = CalcAvgDemand(planList, a.SAPItemNumber); rop.monthl_avg_demand_variance = Math.Ceiling(Convert.ToDecimal(CalcVariance(planList, a.SAPItemNumber))); rop.monthl_avg_outstock = CalcAvgOutStock(ropModelList, replenishmentDto, rop.actual_out_qty.Value, a.SAPItemNumber); if (mesItemList.Find(s => s.ItemNum == a.SAPItemNumber) != null) { rop.stock_turnover = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber).StockTurnOver; rop.supply_leadtime = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber)?.PurLT; rop.stock_turnover = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber)?.StockTurnOver; } else { rop.stock_turnover = 4; } if (srm_purchaseList.Find(s => s.number == a.SAPItemNumber) != null) { rop.supply_leadtime = srm_purchaseList.Find(s => s.number == a.SAPItemNumber).lead_time; } CalcFMRAndABC(rop, replenishmentDto, input); rop.security_stock = Math.Ceiling((decimal)(mathtool.InverseCumulativeDistribution((double)rop.service_level_pct.Value) * (double)rop.monthl_avg_demand_variance)); rop.eop = Math.Ceiling(rop.monthl_avg_demand.Value * rop.supply_leadtime.Value / DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month)); rop.rop_computed = rop.security_stock + rop.eop; rop.max_stock_level = rop.monthl_avg_outstock * (12 / rop.stock_turnover); rop.rop_revised = Math.Min(rop.rop_computed.Value, rop.max_stock_level.Value); rop.isparam = true; rop.tenant_id = input.tenant_id; rop.factory_id = input.factory_id; rop.create_time = DateTime.Now; rop.org_id = input.org_id; addList.Add(rop); }); addList?.ForEach(item => { item.GenerateNewId(help.NextId()); }); await _replenishmentROP.InsertManyAsync(addList); await _replenishmentROP.UpdateManyAsync(updateList); var ropModeAllList = _replenishmentROP.GetListAsync(a => a.year != DateTime.Now.Year && a.seqno != DateTime.Now.Month && a.isparam).Result; ropModeAllList?.ForEach(item => { item.seqno = item.seqno - 1; }); await _replenishmentROP.UpdateManyAsync(ropModeAllList); return "OK"; } /// /// 计划工单齐套检查 /// /// /// public async Task PlanOrderResourceCheck(List Mes_Morders,InputDto input) { //先排除锁定期内的工单 //优先级排序 var sysSet = _generalizedCodeMaster.Select(s => s.FldName == "SystemConfig" && s.Val == "WorkOrderLockPeriod" && s.Domain == input.company_id.ToString()).ToList(); decimal lookDay = 0; if (sysSet.Any()) { //锁定期 lookDay = sysSet[0].UDeci1; } lookDay = lookDay == 0 ? 7 : lookDay; DateTime lookTime = DateTime.Now.Date.AddDays((double)lookDay); Mes_Morders = Mes_Morders.Where(s => s.moentry_sys_stime > lookTime || s.moentry_sys_stime == null).OrderBy(s => s.moentry_sys_stime).ToList(); if (Mes_Morders.Any()) { Mes_Morders.ForEach(s => { s.moentry_sys_stime = DateTime.Now.Date.AddDays((double)lookDay + 1); }); List monolist = Mes_Morders.Select(c => c.morder_no).ToList(); //清理PR的占用。 //如果PR没有转PO,则PR没有合并,就删除,有合并,就减少合并后的PR的数量。 var prlist = _mysql_srm_pr_main.GetListAsync(s => monolist.Contains(s.pr_mono)).Result; List alllist = new List(); List updatelist = new List(); List dellist = new List(); RecursionGetDbPr2(prlist, alllist); foreach (var pr in prlist) { //找到没有关闭的PR,如果关联上的PR都是已关闭,则说明已经转了PO。 //TODO:解决Database operation expected to affect 1 row(s) but actually affected 0 row(s). 如果业务逻辑有问题自行修改 var getPr = RerunPr(pr, alllist); if (getPr != null) { if (getPr.pr_aqty - pr.pr_aqty <= 0) { //删除这个pr,没有小于0则是更新 dellist.Add(getPr); } else { getPr.pr_aqty = getPr.pr_aqty - pr.pr_aqty; updatelist.Add(getPr); } } } List occupy = await _mysql_srm_po_occupy.GetListAsync(s => monolist.Contains(s.morder_mo)); _businessDbContext.BulkDelete(occupy); if (updatelist.Any()) { _businessDbContext.BulkUpdate(updatelist); } if (dellist.Any()) { _businessDbContext.BulkDelete(dellist); } //清理掉库存占用 var itemstockoccupy = _mysql_ic_item_stockoccupy.GetListAsync(s => monolist.Contains(s.morder_mo)).Result; if (itemstockoccupy.Any()) { _businessDbContext.BulkDelete(itemstockoccupy); } //清理锁定期外的排程数据. var periodList = _periodSequenceDet.Select(s => monolist.Contains(s.WorkOrds)); if (periodList.Any()) { _periodSequenceDet.Delete(s => monolist.Contains(s.WorkOrds)); } var schedulList = _scheduleResultOpMaster.Select(s => monolist.Contains(s.WorkOrd)); if (schedulList.Any()) { _scheduleResultOpMaster.Delete(s => monolist.Contains(s.WorkOrd)); } //只走计划工单 var rtn = await OrderKittingCheck(Mes_Morders, true); } else { return "未查找到对应的计划工单,请联系管理员。"; } return "ok"; } //找到没有关闭的PR,做数量的减少 public srm_pr_main RerunPr(srm_pr_main pr, List referlist) { //如果当前PR已经关闭,则检查合并数据 if (pr.state == 0) { //已关闭,并且没有关联数据,则代表转PO了。 var refPr = referlist.Find(s => s.pr_billno == pr.refer_pr_billno); //如果有关联,继续往下查 if (refPr != null) { return RerunPr(refPr, referlist); } else { return null; } } else { return pr; } } /// /// 递归寻找PR,找到合并后的PR /// public void RecursionGetDbPr2(List list, List referlist) { List prlist = _mysql_srm_pr_main.GetListAsync(s => list.Select(c => c.refer_pr_billno).Contains(s.pr_billno)).Result; if (prlist.Any()) { referlist.AddRange(prlist); RecursionGetDbPr2(prlist, referlist); } } /// /// 工单检查物料齐套 /// /// public async Task OrderKittingCheck(List mo_Mes_Morders, bool planCheck = false) { //资源检查结果 PschedDto rtn = new PschedDto(); //资源检查明细list List examines = new List(); OrderCheckDto input = new OrderCheckDto(); if (mo_Mes_Morders.Any()) { input.company_id = mo_Mes_Morders[0].company_id; input.factoryId = mo_Mes_Morders[0].factory_id.GetValueOrDefault(); } //资源检查入参全局变量赋值 param.company_id = input.company_id; param.factoryId = input.factoryId; param.checkflag = false; param.checkPlan = planCheck; //生成当前计算bangid long bangid = help.NextId(); /*List mo_Mes_Morders = _mes_morder.GetManyByCondition(x => x.start_time > DateTime .Now.Date.AddDays(1) && x.start_time < DateTime .Now.Date.AddDays(input.Day) && x.morder_state == MorderEnum.Initial_state && !x.IsDeleted && x.tenant_id == param.tenantId && x.bang_id == bangid).Result; List mo_Mes_Moentries = _mes_moentry.GetManyByCondition(x=> mo_Mes_Morders.Select(s => s.id).Contains(x.moentry_moid.Value)).Result;*/ var morderIdList = mo_Mes_Morders.Select(s => s.Id).ToList(); List mo_Mes_Moentries = _mysql_mes_moentry.GetListAsync(x => morderIdList.Contains(x.moentry_moid.Value)).Result; //获取订单行数据 List sentrys = _mysql_crm_seorderentry.GetListAsync(p => p.company_id == input.company_id && p.factory_id == input.factoryId && !p.IsDeleted && mo_Mes_Moentries.Select(x => x.soentry_id).Contains(p.Id)).Result; //删除同步Mysql后旧数据 await DeleteMySqlOldData(sentrys); List boms = _ic_bom.GetListAsync(p => mo_Mes_Morders.Select(m => m.bom_number).Contains(p.bom_number) && p.factory_id == input.factoryId && p.company_id == input.company_id && !p.IsDeleted).Result.ToList(); //物料bom List bomlist = new List(); //物料bom明细 List bomchildlist = new List(); //物料信息 List icitemlist = new List(); //替代关系 List sublist = new List(); List suballlist = new List(); List subdtllist = new List(); //物料库存表 List stocklist = new List(); //物料占用记录 List sklist = new List(); //sorder=null 是因为齐套检查不需要生成工单、采购、委外等信息,所以不需要关联的工单信息传递进去。 var pretreatments = _mysql_b_bom_pretreatment.GetListAsync(s => boms.Select(c => c.mysql_id).ToList().Contains(s.sourceid)).Result; List autoCreates = new List(); boms.ForEach(p => { if (!pretreatments.Where(s => s.sourceid == p.mysql_id).Any()) { autoCreates.Add(p); } }); if (autoCreates.Any()) { AutoCreateBomBill(param.company_id.ToString(), autoCreates); pretreatments = _mysql_b_bom_pretreatment.GetListAsync(s => boms.Select(c => c.mysql_id).ToList().Contains(s.sourceid)).Result; } //数据库快照-同步mysql库数据到mongoDB中 await DbSnapShot(input.company_id, input.factoryId, bangid, pretreatments); DataInitialization(boms, bangid, icitemlist, stocklist, pretreatments, sklist); if (!planCheck) { //如果是齐套检查,则不考虑其他数据的占用,只看原材料库存 sklist = new List(); } _CalcBomViewAppService.param = param; foreach (var item in mo_Mes_Morders) { var moentry = mo_Mes_Moentries.Find(s => s.moentry_moid == item.Id); if (moentry == null) { continue; } var sentry = sentrys.Find(s => s.Id == moentry.soentry_id); //工单资源检查信息 ExamineResult dtl = new ExamineResult(); dtl.morder_id = item.Id; dtl.morder_no = item.morder_no; dtl.bangid = bangid; dtl.order_statr_time = item.start_time; dtl.bom_number = item.bom_number; dtl.need_qty = item.need_number.GetValueOrDefault(); //获取当前物料bom数据 var childBom = boms.Where(p => p.bom_number == item.bom_number).FirstOrDefault(); var itemPrelist = pretreatments.Where(s => s.sourceid == childBom.mysql_id).ToList(); if (!itemPrelist.Any()) { continue; } var getBomList = ObjectMapper.Map, List>(itemPrelist); if (sentry != null) { dtl.sentry_id = sentry.Id; getBomList.ForEach(s => s.sentry_id = item.Id); } _CalcBomViewAppService.newStockOccList = new List(); _CalcBomViewAppService.mes_morder = item; //库存初始化 _CalcBomViewAppService.BomStock(getBomList, stocklist, bangid); //计算 _CalcBomViewAppService.CalcView(getBomList, bangid, item.need_number.GetValueOrDefault(), item.start_time, sklist, sentry, item.urgent, icitemlist); //TODO:最晚开始时间 var curFacDtl = leadTimeList.FirstOrDefault(p => p.item_id == childBom.icitem_id); //物料齐套时间 dtl.kitting_times = getBomList.Where(p => p.is_use && p.kitting_time != null).OrderByDescending(m => m.kitting_time).First().kitting_time.GetValueOrDefault(); //替代关系展开list dtl.BomChildExamineList = getBomList; //添加订单行开工信息 examines.Add(dtl); } rtn.examines = examines; if (planCheck) { //如果有计划工单,则需要生成pr po oo List prmainlist = new List(); if (_CalcBomViewAppService.SRMPRDtoList.Any()) { List> prlist = _CalcBomViewAppService.SRMPRDtoList.Where(f => f.srm_Pr_Main != null).Select(s => s.srm_Pr_Main).ToList(); List list = new List(); foreach (var pr in prlist) { foreach (var item in pr) { list.Add(item); prmainlist.Add(item); } } if (list.Any()) rtn.srm_pr_list = _CalcBomViewAppService.SRMPRDtoList; } //获取工单数据 var workOrdMasters = _workOrdMaster.Select(p => mo_Mes_Morders.Select(c => c.morder_no).Contains(p.WorkOrd)); workOrdMasters.ForEach(s => { var mo = mo_Mes_Morders.Find(m => m.morder_no == s.WorkOrd); if (mo != null) { //锁定期 s.OrdDate = mo.moentry_sys_stime; s.DueDate = mo.moentry_sys_stime; } }); //优先级排序 workOrdMasters = workOrdMasters.OrderBy(s => s.OrdDate).ToList(); //排产 //await _productionScheduleAppService.DoProductSchedule(workOrdMasters, param.factoryId.ToString()); foreach (var wod in workOrdMasters) { var morder = mo_Mes_Morders.Find(s => s.morder_no == wod.WorkOrd); morder.moentry_sys_stime = wod.OrdDate; morder.moentry_sys_etime = wod.DueDate; /*var exa = rtn.examines.Find(s => s.morder_no == wod.WorkOrd); exa.latest_times = morder.moentry_sys_etime.GetValueOrDefault().Date.AddDays(1);*/ //根据排产后得日期,反推PR。 var wkordPrList = prmainlist.Where(s => s.pr_mono == wod.WorkOrd).ToList(); //反算所有的PR,根据时间减去提前期 //按最大预处理时间倒排 var moIcitems = icitemlist.Where(s => wkordPrList.Select(c => c.icitem_id).Contains(s.mysql_id)).ToList(); var maxTime = moIcitems.Max(s => s.clean_leadtime.GetValueOrDefault()); wkordPrList.ForEach(pr => { var ts = pr.pr_parrive_date - pr.pr_psend_date; //var icitem = icitemlist.Find(s => s.mysql_id == pr.icitem_id); //var bce = exa.BomChildExamineList.Find(s => s.item_id == pr.icitem_id && s.num == pr.num); pr.pr_sarrive_date = morder.moentry_sys_stime.Value.AddDays((double)(0 - maxTime - 1));//到货还需要向前推 物料的预处理时间。到货日期必须提前一天到 pr.pr_ssend_date = pr.pr_sarrive_date.GetValueOrDefault().AddDays(0 - ts.Value.Days); if (pr.pr_ssend_date < DateTime.Now.Date.AddDays(1)) { pr.pr_ssend_date = DateTime.Now.Date.AddDays(1); } }); } using (var unitOfWork = _unitOfWorkManager.Begin(false, true)) { try { _businessDbContext.BulkUpdate(mo_Mes_Morders); if (prmainlist.Any()) { var pr_mainlist = ObjectMapper.Map, List>(prmainlist); _businessDbContext.BulkInsert(pr_mainlist); } if (_CalcBomViewAppService.newStockOccList.Any()) { var stockoccupylist = ObjectMapper.Map, List>(_CalcBomViewAppService.newStockOccList); stockoccupylist.ForEach(s => { s.create_time = DateTime.Now; s.tenant_id = param.company_id.GetValueOrDefault(); s.company_id = param.company_id; s.factory_id = param.factoryId; }); _businessDbContext.BulkInsert(stockoccupylist); } if (_CalcBomViewAppService.srm_Po_OccupiesInsert.Any()) { _CalcBomViewAppService.srm_Po_OccupiesInsert.ForEach(s => { s.company_id = param.company_id; s.factory_id = param.factoryId; }); await _srm_po_occupy.InsertManyAsync(_CalcBomViewAppService.srm_Po_OccupiesInsert); } await unitOfWork.CompleteAsync(); } catch (Exception e) { unitOfWork.Dispose(); new NLogHelper("ResourceExamineAppService").WriteLog("OrderKittingCheck", "工单检查数据更新失败:" + e.Message, _currentTenant.Id.ToString()); } } } //检查结果写入数据库 await ExamineResultInsertDBAsync(examines); //清空快照数据 await ClearSnapShot(bangid); return rtn; } public async Task ExamineResultInsertDBAsync(List examines) { //检查结果写入数据库 List examineList = new List(); List bomExamineList = new List(); List mooccupyList = new List(); List moorderList = new List(); List ooderList = new List(); List purchaseList = new List(); List purchaseoccupyList = new List(); foreach (var ex in examines) { var b_ex = ObjectMapper.Map(ex); b_ex.GenerateNewId(help.NextId());// = help.NextId(); if (_CalcBomViewAppService.mordersInsertList.Any()) { var moentry = _CalcBomViewAppService.moentriesInsertList.Where(s => s.soentry_id == b_ex.sentry_id).FirstOrDefault(); if (moentry != null) { var sentryMo = _CalcBomViewAppService.mordersInsertList.Where(s => s.mysql_id == moentry.moentry_moid).FirstOrDefault(); if (sentryMo != null) { b_ex.morder_id = sentryMo.mysql_id; b_ex.morder_no = sentryMo.morder_no; } } } b_ex.create_time = DateTime.Now; b_ex.company_id = param.company_id; b_ex.tenant_id = param.company_id; b_ex.factory_id = param.factoryId; examineList.Add(b_ex); ex.BomChildExamineList.ForEach(s => { var bc_ex = ObjectMapper.Map(s); bc_ex.GenerateNewId(help.NextId()); bc_ex.examine_id = b_ex.Id; bc_ex.company_id = param.company_id; bc_ex.tenant_id = param.company_id; bc_ex.factory_id = param.factoryId; bc_ex.create_time = DateTime.Now; bomExamineList.Add(bc_ex); if (s.mo_occupy_list != null) { var olist = ObjectMapper.Map, List>(s.mo_occupy_list); olist.ForEach(o => { o.bom_child_examine_id = bc_ex.Id; o.company_id = param.company_id; o.tenant_id = param.company_id; o.factory_id = param.factoryId; }); mooccupyList.AddRange(olist); } if (s.make_list != null) { var mlist = ObjectMapper.Map, List>(s.make_list); mlist.ForEach(o => { o.bom_child_examine_id = bc_ex.Id; o.company_id = param.company_id; o.tenant_id = param.company_id; o.factory_id = param.factoryId; }); moorderList.AddRange(mlist); } if (s.subcontracting_list != null) { var slist = ObjectMapper.Map, List>(s.subcontracting_list); slist.ForEach(o => { o.bom_child_examine_id = bc_ex.Id; o.company_id = param.company_id; o.tenant_id = param.company_id; o.factory_id = param.factoryId; }); ooderList.AddRange(slist); } if (s.purchase_list != null) { var plist = ObjectMapper.Map, List>(s.purchase_list); plist.ForEach(o => { o.bom_child_examine_id = bc_ex.Id; o.company_id = param.company_id; o.tenant_id = param.company_id; o.factory_id = param.factoryId; }); purchaseList.AddRange(plist); } if (s.purchase_occupy_list != null) { var purlist = ObjectMapper.Map, List>(s.purchase_occupy_list); purlist.ForEach(o => { o.bom_child_examine_id = bc_ex.Id; o.company_id = param.company_id; o.tenant_id = param.company_id; o.factory_id = param.factoryId; }); purchaseoccupyList.AddRange(purlist); } }); } using (var unitOfWork = _unitOfWorkManager.Begin(false, true)) { try { if (examineList.Any()) { _businessBangDbContext.BulkInsert(examineList); } if (bomExamineList.Any()) { _businessBangDbContext.BulkInsert(bomExamineList.OrderBy(s => s.num_order).ToList()); } if (mooccupyList.Any()) { _businessBangDbContext.BulkInsert(mooccupyList); } if (moorderList.Any()) { _businessBangDbContext.BulkInsert(moorderList); } if (ooderList.Any()) { _businessBangDbContext.BulkInsert(ooderList); } if (purchaseList.Any()) { _businessBangDbContext.BulkInsert(purchaseList); } if (purchaseoccupyList.Any()) { _businessBangDbContext.BulkInsert(purchaseoccupyList); } await unitOfWork.CompleteAsync(); } catch (Exception e) { new NLogHelper("ResourceExamineAppService").WriteLog("ReceiveResult", "资源检查计算结果相关数据更新失败:" + e.Message, _currentTenant.Id.ToString()); unitOfWork.Dispose(); } } } /// /// 删除旧订单行数据 /// /// /// /// /// public async Task DeleteMySqlOldData(List soentry_id) { List sentryids = soentry_id.Select(p => p.Id).ToList(); //删除工单相关表数据 /*var mes_moentry = _mysql_mes_moentry.GetListAsync(x => sentryids.Contains(x.soentry_id.Value)).Result; var mes_morder = _mysql_mes_morder.GetListAsync(x => mes_moentry.Select(p => p.moentry_moid).ToList().Contains(x.Id)).Result; if (mes_moentry.Count > 0) { await _mysql_mes_moentry.DeleteManyAsync(mes_moentry); } if (mes_morder.Count > 0) { await _mysql_mes_morder.DeleteManyAsync(mes_morder); }*/ var mysql_mes_mooccupy = _mysql_mes_mooccupy.GetListAsync(x => soentry_id.Select(p => p.Id).Contains(x.moo_id_billid.Value)).Result; if (mysql_mes_mooccupy.Count > 0) { await _mysql_mes_mooccupy.DeleteManyAsync(mysql_mes_mooccupy); } /*var srm_pr_main = _mysql_srm_pr_main.GetListAsync(x => soentry_id.Select(p => p.Id).Contains(x.sentry_id.GetValueOrDefault())).Result; if (srm_pr_main.Count > 0) { await _mysql_srm_pr_main.DeleteManyAsync(srm_pr_main); }*/ /*var mes_oorders = _mysql_mes_oorder.GetListAsync(x => soentry_id.Select(p => p.Id).Contains(x.sentry_id.GetValueOrDefault())).Result; if (mes_oorders.Count > 0) { await _mysql_mes_oorder.DeleteManyAsync(mes_oorders); }*/ } /// /// 数据库快照 /// /// public async Task DbSnapShot(long? companyId, long factoryId, long bangid, List pretreatments) { //TODO:申老师明确后续需要调整 根据需要使用的字段,来同步表数据。 //同步物料库存数据 根据预处理,来只找出部分数据同步。 List itemIds = pretreatments.Select(s => s.item_id.GetValueOrDefault()).ToList(); //var icitemStokc = _mysql_ic_item_stock.GetListAsync(p => p.tenant_id == tenantId && p.factory_id == factoryId).Result; var icitemStokc = _mysql_ic_item_stock.GetListAsync(p => p.company_id == companyId && itemIds.Contains(p.icitem_id)).Result; if (icitemStokc.Count > 0) { List numbers = pretreatments.Select(s => s.item_number).ToList(); var locStock = _locationDetail.Select(a => numbers.Contains(a.ItemNum) && a.IsActive && a.Domain == factoryId.ToString()); //设置当前计算bangid icitemStokc.ForEach(item => { item.bang_id = bangid; var pret = pretreatments.Find(s => s.item_id == item.icitem_id); if (pret != null) { item.sqty = locStock.Where(s => s.ItemNum == pret.item_number).Sum(p => p.QtyOnHand); } }); var moIcitemStokc = ObjectMapper.Map, List>(icitemStokc); moIcitemStokc.ForEach(item => { item.GenerateNewId(help.NextId()); }); //插入数据 await _ic_item_stock.InsertManyAsync(moIcitemStokc); } var workordmsters = _workOrdMaster.Select(s => s.Domain == factoryId.ToString() && s.Status.ToLower() != "c"); if (workordmsters.Any()) { //根据工单表找到工单明细,然后根据DOP工单占用记录,对比工单明细发货数量,来做冲销。 var workdetails = _workOrdDetail.Select(s => workordmsters.Select(c => c.WorkOrd).Contains(s.WorkOrd)); //物料库存占用记录表 var item_occupy = _mysql_ic_item_stockoccupy.GetListAsync(p => p.company_id == companyId && itemIds.Contains(p.icitem_id) && workordmsters.Select(c => c.WorkOrd).Contains(p.morder_mo)).Result; if (item_occupy.Any()) { item_occupy.ForEach(s => { //TODO:对发布数量和占用数量进行对冲,因为目前没有处理不同层级下使用相同物料的占用的问题。dop占用有项次号,而wms的发布数量明细没有项次号 var wdtl = workdetails.Where(x => x.WorkOrd == s.morder_mo && x.ItemNum == s.icitem_number).ToList(); if (wdtl.Any()) { foreach (var dtl in wdtl) { if (s.quantity - dtl.QtyPosted > 0) { s.quantity -= dtl.QtyPosted; dtl.QtyPosted = 0; } else { dtl.QtyPosted -= s.quantity; s.quantity = 0; } } } }); item_occupy = item_occupy.Where(s => s.quantity > 0).ToList(); if (item_occupy.Count > 0) { var mo_item_occupy = ObjectMapper.Map, List>(item_occupy); mo_item_occupy.ForEach(item => { item.GenerateNewId(help.NextId()); item.bang_id = bangid; }); await _ic_item_stockoccupy.InsertManyAsync(mo_item_occupy); } } //工单主表 var mes_morder = _mysql_mes_morder.GetListAsync(x => x.company_id == companyId && x.factory_id == factoryId && workordmsters.Select(c => c.WorkOrd).Contains(x.morder_no)).Result; if (mes_morder.Count > 0) { mes_morder.ForEach(item => { item.bang_id = bangid; }); var moMes_morder = ObjectMapper.Map, List>(mes_morder); moMes_morder.ForEach(item => { item.GenerateNewId(help.NextId()); }); await _mes_morder.InsertManyAsync(moMes_morder); } //工单子表 var mes_moentry = _mysql_mes_moentry.GetListAsync(x => x.company_id == companyId && x.factory_id == factoryId).Result; if (mes_moentry.Count > 0) { mes_moentry.ForEach(item => { item.bang_id = bangid; }); var moMes_moentry = ObjectMapper.Map, List>(mes_moentry); moMes_moentry.ForEach(item => { item.GenerateNewId(help.NextId()); }); await _mes_moentry.InsertManyAsync(moMes_moentry); } //在制工单占用记录表 var mes_mooccupy = _mysql_mes_mooccupy.GetListAsync(x => x.company_id == companyId && x.factory_id == factoryId && mes_morder.Select(c => c.morder_no).Contains(x.moo_mo)).Result; if (mes_mooccupy.Count > 0) { var moMes_mooccupy = ObjectMapper.Map, List>(mes_mooccupy); moMes_mooccupy.ForEach(item => { item.GenerateNewId(help.NextId()); item.bang_id = bangid; }); await _mes_mooccupy.InsertManyAsync(moMes_mooccupy); } } //TODO:要不要根据某些条件只同步有效的数据 //采购订单 var srm_po_main = _mysql_srm_po_main.GetListAsync(x => x.company_id == companyId && x.factory_id == factoryId).Result; if (srm_po_main.Count > 0) { var moSrm_po_main = ObjectMapper.Map, List>(srm_po_main); moSrm_po_main.ForEach(item => { item.GenerateNewId(help.NextId()); item.bang_id = bangid; }); await _srm_po_main.InsertManyAsync(moSrm_po_main); } //采购订单明细 var srm_po_list = _mysql_srm_po_list.GetListAsync(x => x.company_id == companyId && x.factory_id == factoryId).Result; if (srm_po_list.Count > 0) { var moSrm_po_list = ObjectMapper.Map, List>(srm_po_list); moSrm_po_list.ForEach(item => { item.GenerateNewId(help.NextId()); item.bang_id = bangid; }); await _srm_po_list.InsertManyAsync(moSrm_po_list); } //采购订单占用详情 var srm_po_occupy = _mysql_srm_po_occupy.GetListAsync(x => x.company_id == companyId && x.factory_id == factoryId).Result; if (srm_po_occupy.Count > 0) { var moSrm_po_occupy = ObjectMapper.Map, List>(srm_po_occupy); moSrm_po_occupy.ForEach(item => { item.GenerateNewId(help.NextId()); item.bang_id = bangid; }); await _srm_po_occupy.InsertManyAsync(moSrm_po_occupy); } } /// /// 清处数据库快照 /// /// public async Task ClearSnapShot(long bangid) { //清除物料库存数据 await _ic_item_stock.DeleteAsync(p => p.bang_id == bangid); //清除工单占用记录表 //await _mes_mooccupy.DeleteAsync(p => p.bang_id == bangid); //清除工单主表 //await _mes_morder.Delete(p => p.bang_id == bangid); //清除工单子表 //await _mes_moentry.Delete(p => p.bang_id == bangid); //清除采购订单 await _srm_po_main.DeleteAsync(p => p.bang_id == bangid); //清除采购订单明细 await _srm_po_list.DeleteAsync(p => p.bang_id == bangid); //清除采购订单占用详情 //await _srm_po_occupy.DeleteAsync(p => p.bang_id == bangid); } /// /// 物料数据计算前准备 /// /// /// /// /// /// /// /// /// /// /// /// /// public void DataInitialization(List boms, long bangid, List icitemlist, List stocklist, List pretreatments, List sklist) { List itemIds = pretreatments.Select(p => p.item_id.GetValueOrDefault()).ToList(); icitemlist.AddRange(_ic_item.GetListAsync(p => itemIds.Contains(p.mysql_id) && !p.IsDeleted).Result); #region 1、数据准备 //1.1、获取产能检查相关数据 //产品物料编码 List itemnums = pretreatments.Where(p => p.level == 1).Select(p => p.item_number).Distinct().ToList(); //产线明细 prodLines = _prodLineDetail.Select(p => itemnums.Contains(p.Part)).ToList(); //标准工序 routingOps = _routingOpDetail.Select(p => itemnums.Contains(p.RoutingCode)).ToList(); List lines = prodLines.Select(p => p.Line).Distinct().ToList(); //工作日历 calendarWorks = _shopCalendarWorkCtr.Select(p => lines.Contains(p.ProdLine)).ToList(); //休息日 qualityLineWorks = _qualityLineWorkDetail.Select(p => lines.Contains(p.ProdLine)).ToList(); //节假日 holidays = _holidayMaster.Select(p => p.Dated >= DateTime.Now.Date); //主工单 List mo_Mes_Morders = _mes_morder.GetListAsync(x => boms.Select(p => p.bom_number).Contains(x.bom_number) && (x.morder_state != MorderEnum.Accomplish_state || x.morder_state != MorderEnum.Close_state && x.morder_icitem_type != MorderEnum.XgwyMorder) && x.company_id == param.company_id && x.bang_id == bangid).Result; List moids = mo_Mes_Morders.Select(p => p.mysql_id).ToList(); List mo_Mes_Moentry = _mes_moentry.GetListAsync(x => moids.Contains(x.moentry_moid)).Result; //工单占用表 List mes_mooccupyList = _mes_mooccupy.GetListAsync(x => x.moo_state == 1 && !x.IsDeleted && x.company_id == param.company_id && boms.Select(p => p.item_number).Contains(x.fitem_number) && x.bang_id == bangid).Result; //物料采购订单明细 var poDetailList = _srm_po_list.GetListAsync(x => icitemlist.Select(p => p.mysql_id).ToList().Contains(x.icitem_id.Value) && x.bang_id == bangid && x.state == 1 && x.rstate == 1 && !x.IsDeleted).Result; //采购订单占用数据 var poOccupys = _srm_po_occupy.GetListAsync(x => poDetailList.Select(p => p.Id).ToList().Contains(x.polist_id) && x.bang_id == bangid && !x.IsDeleted).Result; #endregion //处理一下已经插入得占用记录 //物料库存 stocklist.AddRange(_ic_item_stock.GetListAsync(p => p.factory_id == param.factoryId && p.bang_id == bangid && itemIds.Contains(p.icitem_id)).Result); //物料库存占用表 sklist.AddRange(_ic_item_stockoccupy.GetListAsync(x => x.bang_id == bangid && !x.IsDeleted).Result); //物料提前期 leadTimeList = GetLeadTime(icitemlist, param.company_id, param.factoryId);//提前期列表 supplierList = GetSupplier(itemIds, param.company_id, param.factoryId);//供应商列表 _CalcBomViewAppService.leadTimeList = leadTimeList; _CalcBomViewAppService.supplierList = supplierList; //资源检查添加产线工序等数据 _CalcBomViewAppService.prodLines = prodLines; _CalcBomViewAppService.routingOps = routingOps; _CalcBomViewAppService.calendarWorks = calendarWorks; _CalcBomViewAppService.qualityLineWorks = qualityLineWorks; _CalcBomViewAppService.holidays = holidays; _CalcBomViewAppService.mordersList = mo_Mes_Morders;//工单 _CalcBomViewAppService.moentriesList = mo_Mes_Moentry;//工单子表 _CalcBomViewAppService.mooccupyAllList = mes_mooccupyList;//工单占用表 _CalcBomViewAppService.srm_Po_Lists = poDetailList; //采购明细 _CalcBomViewAppService.srm_Po_Occupies = poOccupys; //采购占用表 _CalcBomViewAppService.ic_item_List = icitemlist; //物料表 } public void GenerateSort(List returnlist) { int level = returnlist.Max(s => s.level); returnlist.ForEach(s => { int num = level - s.level; if (num > 0) { s.num_order = long.Parse((s.num_order * Math.Pow(1000, num)).ToString()); } }); } /// /// 根据物料id获取物料4个提前期 /// /// 物料id /// 企业id /// 工厂id /// private List GetLeadTime(List icItemIds, long? companyId, long factoryid) { return icItemIds.Where(p => p.factory_id == factoryid && p.company_id == companyId && !p.IsDeleted). Select(x => new ICItemLeadTimeDto { item_id = x.mysql_id, transportation_leadtime = x.transportation_leadtime, stock_leadtime = x.stock_leadtime, production_leadtime = x.production_leadtime, order_leadtime = x.order_leadtime, minorderqty = x.minorderqty, put_integer = x.put_integer, minpackqty = x.minpackqty, ordissu_days = x.ordissu_days }).AsQueryable().ToList(); } //根据物料id获取物料供应商 private List GetSupplier(List icItemIds, long? companyId, long factoryid) { return _srm_purchase.GetListAsync(p => icItemIds.Contains(p.icitem_id) && p.company_id == companyId && p.factory_id == factoryid && !p.IsDeleted).Result; } /// /// 物料和BOM前置数据准备 /// /// /// /// /// /// /// /// public void IcItemPretreatment(List boms, List bomlist, List bomchildlist, List icitemlist, List sublist, List suballlist, List subdtllist) { //获取物料bom,物料bom明细 GetIcBomData(boms, bomlist, bomchildlist); //根据明细集合查出所有得替代关系表数据集合 List codeList = bomchildlist.Select(c => c.substitute_code).Distinct().ToList(); sublist.AddRange(_ic_substitute.GetListAsync(p => codeList.Contains(p.substitute_code) && !p.IsDeleted).Result); List subidlist = sublist.Select(c => c.mysql_id).Distinct().ToList(); suballlist.AddRange(_ic_substitute_group.GetListAsync(p => subidlist.Contains(p.substitute_group_id) && !p.IsDeleted).Result); List suballidlist = suballlist.Select(c => c.mysql_id).Distinct().ToList(); subdtllist.AddRange(_ic_substitute_group_detail.GetListAsync(p => suballidlist.Contains(p.substitute_group_id) && !p.IsDeleted).Result); //获取物料数据 List itemIds = bomlist.Select(p => p.icitem_id).ToList(); itemIds.AddRange(bomchildlist.Select(p => p.icitem_id).ToList()); itemIds.AddRange(subdtllist.Select(p => p.icitem_id).ToList()); icitemlist.AddRange(_ic_item.GetListAsync(p => itemIds.Contains(p.mysql_id) && !p.IsDeleted).Result); } /// /// 递归:获取icbom,icbomchild数据 /// /// /// /// public void GetIcBomData(List icBoms, List bomlist, List bomchildlist) { if (icBoms.Count == 0) { return; } //添加物料bom数据 foreach (var ib in icBoms) { if (!bomlist.Exists(s => s.mysql_id == ib.mysql_id)) { bomlist.Add(ib); } } //获取物料bom明细数据 //List childList = _ic_bom_child.GetManyByCondition(p => icBoms.Select(m => m.mysql_id).Contains(p.bom_id) && p.use_status == 1 && p.tenant_id == param.tenantId && p.factory_id == param.factoryId && !p.IsDeleted).Result.ToList(); List childList = _ic_bom_child.GetListAsync(p => icBoms.Select(m => m.mysql_id).Contains(p.bom_id) && p.company_id == param.company_id && !p.IsDeleted).Result.ToList(); //没有明细数据,终止 if (childList.Count == 0) { return; } foreach (var bchild in childList) { if (!bomchildlist.Exists(s => s.mysql_id == bchild.mysql_id)) { bomchildlist.Add(bchild); } } //通过物料bom明细数据反查物料bom数据 var boms = _ic_bom.GetListAsync(p => childList.Select(m => m.icitem_id).ToList().Contains(p.icitem_id) && p.use_status == 1 && p.company_id == param.company_id && !p.IsDeleted).Result.ToList(); foreach (var chd in childList) { var curBoms = boms.Where(p => p.icitem_id == chd.icitem_id).ToList(); GetIcBomData(curBoms, bomlist, bomchildlist); } } /// /// 自动生成BOM预处理清单 /// public void AutoCreateBomBill(string companyid, List ic_Boms = null) { ic_Boms ??= _ic_bom.GetListAsync(p => p.company_id.ToString() == companyid && (p.bom_number == "10100012_V1.0" || p.bom_number == "10100241_V1.0" || p.bom_number == "BOM00042070") && !p.IsDeleted).Result.ToList(); var pretreatment = _mysql_b_bom_pretreatment.GetListAsync(s => ic_Boms.Select(c => c.mysql_id).ToList().Contains(s.sourceid)).Result; param.company_id = long.Parse(companyid); //物料bom List bomlist = new List(); List bomchildlist = new List(); //物料信息 List icitemlist = new List(); //替代关系 List sublist = new List(); List suballlist = new List(); List subdtllist = new List(); IcItemPretreatment(ic_Boms, bomlist, bomchildlist, icitemlist, sublist, suballlist, subdtllist); List deleteList = new List(); List addList = new List(); foreach (var bom in ic_Boms) { var pret = pretreatment.Find(s => s.sourceid == bom.mysql_id && s.bom_id == bom.mysql_id); if (pret != null) { if (pret.version == bom.version) { //如果存在,且版本相同,则不需要处理 continue; } //版本不同则重新生成 deleteList.Add(pret); } //bom层级组装 var getBomList = _pretreatmentAppService.BomPretreatment(bom.mysql_id, bomlist, bomchildlist, icitemlist); //bom替代关系组装 _pretreatmentAppService.BomSubstitute(getBomList, bomlist, bomchildlist, icitemlist, sublist, suballlist, subdtllist); GenerateSort(getBomList); var list = ObjectMapper.Map, List>(getBomList); list.ForEach(s => { s.sourceid = bom.mysql_id; s.company_id = bom.company_id; s.tenant_id = bom.tenant_id; s.factory_id = bom.factory_id; }); addList.AddRange(list); } if (deleteList.Any()) { _businessDbContext.BulkDelete(deleteList); } if (addList.Any()) { _businessDbContext.BulkInsert(addList); //await _mysql_b_bom_pretreatment.InsertManyAsync(addList); } } /// /// 检查所有成品半成品原材料是否需要补货先判断SS再判断ROP /// /// /// public async Task DayCheckAllByFinalGoods(InputDto input) { //先找成品,就是年度销售预测 //_replenishmentModel. return "OK"; } /// /// 生产长周期物料PR /// /// 需要传入工厂编码 /// public async Task CalcLongPeriodItemPR(InputDto input) { //取年份最大的数据 int yearMax=DateTime.Now.Year; yearMax=_businessDbContext.ReplenishmentAnnualProduction.Where(m => m.factory_id ==input.factory_id && !m.IsDeleted).Max(m => (int?)m.Year).GetValueOrDefault(); var productList = _replenishmentAnnualProduction.GetListAsync(a => a.Year == yearMax && !a.IsDeleted && a.factory_id == input.factory_id).Result.OrderBy(s=>s.OrderNum).ToList(); var itemList= productList.Select(a=>a.SAPItemNumber).ToList(); var planList=_mysql_ic_item.GetListAsync(a=>itemList.Contains(a.number) && a.factory_id==input.factory_id && !a.IsDeleted).Result.ToList(); var mesItem=_itemMaster.Select(a => itemList.Contains(a.ItemNum) &&a.IsActive && a.Domain==input.factory_id.ToString()); var bomList = _mysql_ic_bom.GetListAsync(a => itemList.Contains(a.item_number) && !a.IsDeleted && a.factory_id == input.factory_id).Result; List moList=new List(); List moentryList = new List(); for (int i = 0;i< productList.Count();i++) { var ic_item = planList.Find(x => x.number == productList[i].SAPItemNumber); var bom = bomList.Find(a => a.item_number == productList[i].SAPItemNumber); mes_morder mes_Morder = new mes_morder(); mes_Morder.GenerateNewId(help.NextId()); mes_Morder.morder_type = MorderEnum.XsMorder; //mes_Morder.morder_icitem_type mes_Morder.work_order_type = MorderEnum.CgMorder; mes_Morder.morder_state = MorderEnum.Initial_state; mes_Morder.morder_no = GetMaxSerialNumber(457253186445381); mes_Morder.fms_number = ic_item.fms_number; mes_Morder.bom_number = bom.bom_number; mes_Morder.fmodel = ic_item.model; mes_Morder.urgent = 1; mes_Morder.moentry_startup_status = 0; mes_Morder.tenant_id = input.tenant_id; mes_Morder.factory_id = input.factory_id; mes_Morder.company_id = input.company_id; mes_Morder.org_id = input.org_id; mes_Morder.product_code = ic_item.number; mes_Morder.product_name = ic_item.name; mes_Morder.morder_date = DateTime.Now.Date.AddDays(1); mes_Morder.moentry_sys_etime = Convert.ToDateTime(productList[i].PlanMonth + "-01"); //mes_Morder.morder_fstate = "计划"; //TODO:目前没有取值位置 mes_Morder.moentry_prd = null; mes_Morder.moentry_prdname = null; mes_Morder.moentry_wrkc = null; mes_Morder.moentry_wrkcname = null; mes_Morder.picking_qty = 0; //TODO:可删除主表字段 mes_Morder.unit = ic_item.unit; mes_Morder.morder_production_number = productList[i].Qty; mes_Morder.need_number = productList[i].Qty; mes_Morder.remaining_number = 0; mes_Morder.create_time = DateTime.Now; //生成工单子表数据 mes_moentry mes_Moentry = new mes_moentry(); mes_Moentry.GenerateNewId(help.NextId()); mes_Moentry.moentry_moid = mes_Morder.Id; mes_Moentry.moentry_mono = mes_Morder.morder_no; mes_Moentry.unit = ic_item.unit; mes_Moentry.morder_production_number = productList[i].Qty; mes_Moentry.need_number = productList[i].Qty; mes_Moentry.remaining_number = 0; mes_Moentry.tenant_id = input.tenant_id; mes_Moentry.factory_id = input.factory_id; mes_Moentry.company_id = input.company_id; mes_Moentry.org_id = input.org_id; mes_Moentry.create_time = DateTime.Now; moList.Add(mes_Morder); moentryList.Add(mes_Moentry); } await _mysql_mes_morder.InsertManyAsync(moList); await _mysql_mes_moentry.InsertManyAsync(moentryList); await PlanOrderResourceCheck(moList,input); return "OK"; } /// /// 得到一个流水号的最大流水号 /// /// 流水号id /// json数据,可以用json中的某个字段值作为通配符字替换流水号格式。 /// public string GetMaxSerialNumber(long id, JObject? formData = null) { var modelList = _rf_serialnumber.Select(s => s.Id == id); if (modelList == null || modelList.Count < 1) { return string.Empty; } var model = modelList[0]; int max = model.CurrentNumber + 1; var date = DateTime.Now; var lastDate = model.LastTime; switch (model.NumberType) { case 1: //年流水 if (date.Year > lastDate.Year) { max = 1; } break; case 2: //月流水 if (date.Year > lastDate.Year || date.Month > lastDate.Month) { max = 1; } break; case 3: //日流水 if (date.Year > lastDate.Year || date.Month > lastDate.Month || date.Day > lastDate.Day) { max = 1; } break; } string number = max.ToString().PadLeft(model.NumberSize, '0'); string serialNumber = string.IsNullOrWhiteSpace(model.Format) ? number : model.Format.ContainsIgnoreCase("{number}") ? model.Format.ReplaceIgnoreCase("{number}", number) : model.Format + number; //更新当前编号和最后时间 model.LastTime = date; model.CurrentNumber = max; _rf_serialnumber.Update(model); return Wildcard.Replace(serialNumber, formData); } public ReplenishmentDto GetROPParam(string domain) { //select [Domain],Val,Ufld1,UDeci1 from GeneralizedCodeMaster where [Domain] = '1001' AND FldName ='SystemConfig' // AND Val IN('ReplenishmentCalcPeriod', 'HistoryOutStockMonth', 'SaleFcstMonth', 'SaleFcstEntryDate', 'UpdateWeeks', 'WeekPlanUpdateDay', 'LongPeriodDay') List list = new List(); list.Add("ReplenishmentCalcPeriod"); list.Add("HistoryOutStockMonth"); list.Add("SaleFcstMonth"); list.Add("SaleFcstEntryDate"); list.Add("UpdateWeeks"); list.Add("WeekPlanUpdateDay"); list.Add("LongPeriodDay"); var configList = _generalizedCodeMaster.Select(a => a.Domain == domain && a.FldName == "SystemConfig" && list.Contains(a.Val)); ReplenishmentDto replenishmentDto = new ReplenishmentDto(); replenishmentDto.HistoryOutStockMonth = 3; replenishmentDto.ReplenishmentCalcPeriod = "W"; replenishmentDto.HistoryOutStockMonth = 2; replenishmentDto.SaleFcstMonth = 2; replenishmentDto.SaleFcstEntryDate = 27; replenishmentDto.UpdateWeeks = 12; replenishmentDto.WeekPlanUpdateDay = 7;//每周日更新 replenishmentDto.LongPeriodDay = 60; if (configList?.Find(a => a.Val == "HistoryOutStockMonth") != null) { replenishmentDto.HistoryOutStockMonth = (int)configList?.Find(a => a.Val == "HistoryOutStockMonth").UDeci1; } if (configList?.Find(a => a.Val == "ReplenishmentCalcPeriod") != null) { switch (configList?.Find(a => a.Val == "ReplenishmentCalcPeriod").Ufld1) { case "月": replenishmentDto.ReplenishmentCalcPeriod = "M"; break; case "周": replenishmentDto.ReplenishmentCalcPeriod = "W"; break; case "": replenishmentDto.ReplenishmentCalcPeriod = "D"; break; default: replenishmentDto.ReplenishmentCalcPeriod = "W"; break; } } if (configList?.Find(a => a.Val == "SaleFcstMonth") != null) { replenishmentDto.SaleFcstMonth = (int)configList?.Find(a => a.Val == "SaleFcstMonth").UDeci1; } if (configList?.Find(a => a.Val == "SaleFcstEntryDate") != null) { replenishmentDto.SaleFcstEntryDate = (int)configList?.Find(a => a.Val == "SaleFcstEntryDate").UDeci1; } if (configList?.Find(a => a.Val == "UpdateWeeks") != null) { replenishmentDto.UpdateWeeks = (int)configList?.Find(a => a.Val == "UpdateWeeks").UDeci1; } if (configList?.Find(a => a.Val == "WeekPlanUpdateDay") != null) { switch (configList?.Find(a => a.Val == "WeekPlanUpdateDay").Ufld1) { case "周一": replenishmentDto.WeekPlanUpdateDay = 1; break; case "周二": replenishmentDto.WeekPlanUpdateDay = 2; break; case "周三": replenishmentDto.WeekPlanUpdateDay = 3; break; case "周四": replenishmentDto.WeekPlanUpdateDay = 4; break; case "周五": replenishmentDto.WeekPlanUpdateDay = 5; break; case "周六": replenishmentDto.WeekPlanUpdateDay = 6; break; case "周日": replenishmentDto.WeekPlanUpdateDay = 7; break; default: replenishmentDto.WeekPlanUpdateDay = 7; break; } } if (configList?.Find(a => a.Val == "LongPeriodDay") != null) { replenishmentDto.LongPeriodDay = (int)configList?.Find(a => a.Val == "LongPeriodDay").UDeci1; } return replenishmentDto; } /// /// 计算ABC分类和FMR分类 /// /// /// /// /// 1为全部一起算,2为成品算成品原材料算原材料 public void CalcFMRAndABC(List replenishmentModels, ReplenishmentDto replenishmentDto, InputDto input, int type) { var itemNumList = replenishmentModels?.Select(a => a.number).ToList(); //发货出库记录 var shipList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.ShipDate >= DateTime.Now.AddMonths(-6) && a.RealQty > 0 && itemNumList.Contains(a.ContainerItem)); //领料出库记录 //var pickbilllist = _NbrDetail.Select(a => a.Domain == input.factory_id.ToString() && a.Type == "SM" && a.IsActive && a.UpdateTime >= DateTime.Now.AddMonths(replenishmentDto.HistoryOutStockMonth * -1) && itemNumList.Contains(a.ItemNum)); var pickbilllist = _invTransHist.Select(a => a.Domain == input.factory_id.ToString() && a.TransType == "iss-wo" && a.IsActive && a.CreateTime >= DateTime.Now.AddMonths(-6) && itemNumList.Contains(a.ItemNum)); //总的移库次数 int totalCount = shipList.Count() + pickbilllist.Count(); //平均出库次数 decimal avgOutStock = totalCount / replenishmentDto.HistoryOutStockMonth; //总出货金额 decimal? totalPrice = shipList.Sum(a => a.Price * a.QtyToShip); //按照物料分组统计出货金额 var itemGroup = shipList.GroupBy(p => p.ContainerItem) .Select(p => new ASNBOLShipperDetail { Price = p.Sum(a => a.Price * a.QtyToShip) * 100 / totalPrice, ContainerItem = p.Key }).ToList().OrderByDescending(c => c.Price).ThenByDescending(c => c.ContainerItem); var AIndex = (int)Math.Ceiling(itemGroup.Count() * 0.75);//A类:0-75% var BIndex = (int)Math.Ceiling(itemGroup.Count() * 0.9) - AIndex;//A类:75%-90% var CIndex = itemGroup.Count() - AIndex - BIndex;//A类:90%-100% var AItem = itemGroup.Take(AIndex); var BItem = itemGroup.Skip(AIndex).Take(BIndex); var CItem = itemGroup.Skip(AIndex + BIndex).Take(CIndex); replenishmentModels?.ForEach(replenishmentModel => { if (AItem.Any(a => a.ContainerItem == replenishmentModel.number)) { replenishmentModel.abc = "A";//金额占比前75%的物料划为A类 } else if (BItem.Any(a => a.ContainerItem == replenishmentModel.number)) { replenishmentModel.abc = "B";//金额占比前75%-90%的物料划为A类 } else if (CItem.Any(a => a.ContainerItem == replenishmentModel.number)) { replenishmentModel.abc = "C";//金额占比后10%的物料划为A类 } else { replenishmentModel.abc = "B";//原材料默认为B } int itemMoveCount = shipList.Count(a => a.ContainerItem == replenishmentModel.number) + pickbilllist.Count(a => a.ItemNum == replenishmentModel.number); if (itemMoveCount >= avgOutStock) { replenishmentModel.fmr = "F"; } else if (itemMoveCount >= avgOutStock / 2 && itemMoveCount < avgOutStock || itemMoveCount == 0) { replenishmentModel.fmr = "M";//没有出库移库记录的默认为M } else if (itemMoveCount < avgOutStock / 2) { replenishmentModel.fmr = "R"; } if (replenishmentModel.abc == "A" && replenishmentModel.fmr == "R") { replenishmentModel.service_level_pct = (decimal?)0.8; } if (replenishmentModel.abc != "C" && replenishmentModel.fmr != "R") { replenishmentModel.service_level_pct = (decimal?)0.96; } if (replenishmentModel.abc == "C" || (replenishmentModel.abc == "B" && replenishmentModel.fmr == "R")) { replenishmentModel.service_level_pct = (decimal?)0.9; } }); } /// /// 计算ABC分类和FMR分类 /// /// public void CalcFMRAndABC(ReplenishmentROP replenishmentModel, ReplenishmentDto replenishmentDto, InputDto input) { //发货出库记录 var shipList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.ShipDate >= DateTime.Now.AddMonths(-6) && a.RealQty > 0 && replenishmentModel.number == a.ContainerItem); //领料出库记录 //var pickbilllist = _NbrDetail.Select(a => a.Domain == input.factory_id.ToString() && a.Type == "SM" && a.IsActive && a.UpdateTime >= DateTime.Now.AddMonths(replenishmentDto.HistoryOutStockMonth * -1) && itemNumList.Contains(a.ItemNum)); var pickbilllist = _invTransHist.Select(a => a.Domain == input.factory_id.ToString() && a.TransType == "iss-wo" && a.IsActive && a.CreateTime >= DateTime.Now.AddMonths(-6) && replenishmentModel.number == a.ItemNum); //总的移库次数 int totalCount = shipList.Count() + pickbilllist.Count(); //平均出库次数 decimal avgOutStock = totalCount / replenishmentDto.HistoryOutStockMonth; //总出货金额 decimal? totalPrice = shipList.Sum(a => a.Price * a.QtyToShip); //按照物料分组统计出货金额 var itemGroup = shipList.GroupBy(p => p.ContainerItem) .Select(p => new ASNBOLShipperDetail { Price = p.Sum(a => a.Price * a.QtyToShip) * 100 / totalPrice, ContainerItem = p.Key }).ToList().OrderByDescending(c => c.Price).ThenByDescending(c => c.ContainerItem); var AIndex = (int)Math.Ceiling(itemGroup.Count() * 0.75);//A类:0-75% var BIndex = (int)Math.Ceiling(itemGroup.Count() * 0.9) - AIndex;//A类:75%-90% var CIndex = itemGroup.Count() - AIndex - BIndex;//A类:90%-100% var AItem = itemGroup.Take(AIndex); var BItem = itemGroup.Skip(AIndex).Take(BIndex); var CItem = itemGroup.Skip(AIndex + BIndex).Take(CIndex); if (AItem.Any(a => a.ContainerItem == replenishmentModel.number)) { replenishmentModel.abc = "A";//金额占比前75%的物料划为A类 } else if (BItem.Any(a => a.ContainerItem == replenishmentModel.number)) { replenishmentModel.abc = "B";//金额占比前75%-90%的物料划为B类 } else if (CItem.Any(a => a.ContainerItem == replenishmentModel.number)) { replenishmentModel.abc = "C";//金额占比后10%的物料划为C类 } else { replenishmentModel.abc = "B";//原材料默认为B } int itemMoveCount = shipList.Count(a => a.ContainerItem == replenishmentModel.number) + pickbilllist.Count(a => a.ItemNum == replenishmentModel.number); if (itemMoveCount >= avgOutStock) { replenishmentModel.fmr = "F"; } else if (itemMoveCount >= avgOutStock / 2 && itemMoveCount < avgOutStock || itemMoveCount == 0) { replenishmentModel.fmr = "M";//没有出库移库记录的默认为M } else if (itemMoveCount < avgOutStock / 2) { replenishmentModel.fmr = "R"; } if (replenishmentModel.abc == "A" && replenishmentModel.fmr == "R") { replenishmentModel.service_level_pct = (decimal?)0.8; } if (replenishmentModel.fmr != "R") { replenishmentModel.service_level_pct = (decimal?)0.96; } if (replenishmentModel.abc != "A" && replenishmentModel.fmr == "R") { replenishmentModel.service_level_pct = (decimal?)0.9; } } /// /// 算平均月需求数量 /// /// 发货计划 /// /// /// /// public decimal CalcAvgDemand(List list, string itemNum) { return list.Where(i => i.SAPItemNumber == itemNum).Select(a => a.Qty).Average(); } /// /// /// /// 补货模型 /// 本月实际出库 /// 全局参数 /// 物料编码 /// public decimal CalcAvgOutStock(List list, ReplenishmentDto replenishmentDto, decimal MQty, string itemNum) { return (list.Where(i => i.number == itemNum && i.zero_based_seqno > 1 - replenishmentDto.HistoryOutStockMonth && i.zero_based_seqno <= 0).Select(a => a.actual_out_qty.Value).Sum() + MQty) / (replenishmentDto.HistoryOutStockMonth + 1); } public double CalcVariance(List list, string itemNum) { var avg = CalcAvgDemand(list, itemNum); var nums = list.Where(i => i.SAPItemNumber == itemNum).Select(a => a.Qty); if (nums.Count() <= 1) return 0; return Math.Sqrt(nums.Sum(x => Math.Pow(Convert.ToDouble(x) - Convert.ToDouble(avg), 2)) / (nums.Count() - 1)); } /// /// 获取指定日期在为一年中为第几周 /// /// 指定时间 /// 返回第几周 public static int GetWeekOfYear(DateTime dt) { System.Globalization.GregorianCalendar gc = new System.Globalization.GregorianCalendar(); int weekOfYear = gc.GetWeekOfYear(dt, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Monday); return weekOfYear; } /// /// 获取指定日期在该月的第几周 /// /// /// 1表示周一至周日为一周,2表示周日至周六为一周 /// public static int WeekOfMonth(DateTime day, int WeekStart) { DateTime FirstofMonth = Convert.ToDateTime(day.Date.Year + "-" + day.Date.Month + "-" + 1); int i = (int)FirstofMonth.Date.DayOfWeek; if (i == 0) { i = 7; } if (WeekStart == 1) { return (day.Date.Day + i - 2) / 7 + 1; } if (WeekStart == 2) { return (day.Date.Day + i - 1) / 7; } return 0; } //获取上周开始时间 public static DateTime getPreWeekStartTime() { var weekday = (int)DateTime.Now.DayOfWeek; return Convert.ToDateTime(DateTime.Now.AddDays(-7 - weekday + 1).ToString("yyyy-MM-dd 00:00:00.000")); } //获取上周结束时间 public static DateTime getPreWeekEndTime() { int weekday = (int)DateTime.Now.DayOfWeek; return Convert.ToDateTime(DateTime.Now.AddDays(weekday - 7 + 1).ToString("yyyy-MM-dd 23:59:59.000")); } /// /// 获取上个月开始时间 /// /// /// public static DateTime getPreMonthStartTime() { return Convert.ToDateTime(DateTime.Now.AddMonths(-1).AddDays(1 - DateTime.Now.Day).ToString("yyyy-MM-dd 00:00:00.000")); } /// /// 获取上月结束时间 /// /// /// public static DateTime getPreMonthEndTime() { return Convert.ToDateTime(DateTime.Now.AddDays(-DateTime.Now.Day).ToString("yyyy-MM-dd 23:59:59.000")); } /// /// 获取前后某个,整数月开始时间 /// /// 正数表示后多少个月的第一天,负数为前多少个月第一天 /// public static DateTime getMonthStartTime(int months) { return getPreMonthStartTime().AddMonths(months + 1); } /// /// 获取前后某个,整数月结束时间 /// /// 正数表示后多少个月的第一天,负数为前多少个月第一天 /// public static DateTime getMonthEndTime(int months) { return getPreMonthEndTime().AddMonths(months + 1); } } }