using Business.Core.Enum;
using Business.Core.Utilities;
using Business.Domain;
using Business.Dto;
using Business.EntityFrameworkCore;
using Business.EntityFrameworkCore.SqlRepositories;
using Business.ReplenishmentManagement;
using Business.ResourceExamineManagement;
using Business.ResourceExamineManagement.Dto;
using Business.StructuredDB.MES.IC;
using Business.StructuredDB.Replenishment;
using Business.StructuredDB.SaleFcst;
using Business.StructuredDB.WMS;
using EFCore.BulkExtensions;
using Microsoft.EntityFrameworkCore;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using System;
using System.Collections;
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.ObjectMapping;
using Volo.Abp.Uow;
using static Azure.Core.HttpHeader;
namespace Business.Replenishment
{
///
/// 产能分析
///
public class ReplenishmentAppService : ApplicationService, IReplenishmentAppService, ITransientDependency
{
#region 服务
///
/// 雪花算法
///
SnowFlake help = new SnowFlake();
private readonly IRepository _replenishmentROPWeekPlan;
private readonly ISqlRepository _ASNBOLShipperDetail;
private readonly ISqlRepository _ASNBOLShipperMaster;
private readonly ISqlRepository _invTransHist;
private readonly ISqlRepository _invMaster;
private readonly ISqlRepository _SAPInv;
private readonly IRepository _srmPurchase;
private readonly ISqlRepository _monthlyShipmentPlan;
private readonly ISqlRepository _monthlyShipmentPlanHistory;
private readonly ISqlRepository _generalizedCodeMaster;
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 _mysql_srm_pr_main_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 ISqlRepository _lineMaster;
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 _qualityLineWorkDetail;
private readonly ISqlRepository _custMaster;
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_seorder;
private readonly IRepository _mysql_crm_seorderentry;
private readonly IRepository _productionMasterPlan;
private readonly IRepository _replenishmentWeekPlan;
private readonly IRepository _mysql_examine_result;
private readonly IRepository _mysql_bom_child_examine;
private readonly IRepository _replenishmentServiceLevel;
private readonly IExtSqlRepository _DMS_IN_ITEMMAPPING;
private readonly IExtSqlRepository _DMS_IN_LOCDETAIL;
private readonly IExtSqlRepository _DMS_IN_SHIPPINGDETAIL;
private readonly IRepository _ReplenishmentTurnOverSet;
///
/// 成品虚拟件工序关系表
///
private readonly ISqlRepository _productStructureOp;
///
/// 年度销售预测
///
private IRepository _yearDemandManagement;
///
/// 年度销售预测历史记录
///
private IRepository _yearDemandManagementHistory;
///
/// 年度生产大纲
///
private IRepository _replenishmentAnnualProduction;
///
/// 平台库存表
///
private readonly IRepository _PlatformInventory;
///
/// 工单工艺路线明细
///
private ISqlRepository _workOrdRouting;
///
/// 计划订单表
///
private IRepository _crm_planorder;
///
/// 平台库存表
///
private IRepository _platformInventory;
///
/// 在途检查
///
private readonly PurchaseOrderAppService _purchaseOrderAppService;
///
/// 计算BOM平铺物料情况
///
private readonly CalcBomViewAppService _CalcBomViewAppService;
///
/// 预处理
///
private readonly PretreatmentAppService _pretreatmentAppService;
private readonly SerialNumberAppService _serialNumberAppService;
///
/// 产能检查
///
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 replenishmentROPWeekPlan,
ISqlRepository ASNBOLShipperDetail,
ISqlRepository ASNBOLShipperMaster,
ISqlRepository invTransHist,
IRepository srmPurchase,
ISqlRepository monthlyShipmentPlan,
ISqlRepository monthlyShipmentPlanHistory,
ISqlRepository generalizedCodeMaster,
ISqlRepository invMaster,
ISqlRepository SAPInv,
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 mysql_srm_pr_main_occupy,
IRepository mes_morder,
IRepository mes_moentry,
IRepository mes_mooccupy,
IRepository mysql_mes_mooccupy,
IRepository mysql_b_bom_pretreatment,
ISqlRepository workOrdMaster,
ISqlRepository prodLineDetail,
ISqlRepository lineMaster,
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_seorder,
IRepository mysql_crm_seorderentry,
IRepository mes_oorder,
IRepository productionMasterPlan,
ISqlRepository productStructureOp,
IRepository yearDemandManagement,
IRepository replenishmentAnnualProduction,
IRepository yearDemandManagementHistory,
IRepository PlatformInventory,
ISqlRepository workOrdRouting,
ISqlRepository custMaster,
IRepository crm_planorder,
IRepository platformInventory,
IRepository replenishmentWeekPlan,
IRepository mysql_examine_result,
IRepository mysql_bom_child_examine,
IRepository replenishmentServiceLevel,
IExtSqlRepository DMS_IN_ITEMMAPPING,
IExtSqlRepository DMS_IN_LOCDETAIL,
IExtSqlRepository DMS_IN_SHIPPINGDETAIL,
IRepository ReplenishmentTurnOverSet,
SerialNumberAppService serialNumberAppService,
PretreatmentAppService pretreatmentAppService,
PurchaseOrderAppService purchaseOrderAppService,
CalcBomViewAppService CalcBomViewAppService,
ProductExamineAppService productExamineAppService,
BusinessBangDbContext businessBangDbContext,
BusinessDbContext businessDbContext,
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager)
{
_replenishmentROPWeekPlan = replenishmentROPWeekPlan;
_ASNBOLShipperDetail = ASNBOLShipperDetail;
_ASNBOLShipperMaster = ASNBOLShipperMaster;
_invTransHist = invTransHist;
_srmPurchase = srmPurchase;
_monthlyShipmentPlan = monthlyShipmentPlan;
_monthlyShipmentPlanHistory = monthlyShipmentPlanHistory;
_generalizedCodeMaster = generalizedCodeMaster;
_invMaster = invMaster;
_SAPInv=SAPInv;
_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;
_mysql_srm_pr_main_occupy = mysql_srm_pr_main_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;
_custMaster=custMaster;
_prodLineDetail = prodLineDetail;
_lineMaster= lineMaster;
_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;
_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_seorder = mysql_crm_seorder;
_mysql_crm_seorderentry = mysql_crm_seorderentry;
_productionMasterPlan=productionMasterPlan;
_replenishmentWeekPlan=replenishmentWeekPlan;
_mysql_examine_result = mysql_examine_result;
_mysql_bom_child_examine= mysql_bom_child_examine;
_replenishmentServiceLevel = replenishmentServiceLevel;
_productStructureOp = productStructureOp;
_PlatformInventory = PlatformInventory;
_workOrdRouting = workOrdRouting;
_ASNBOLShipperDetail = ASNBOLShipperDetail;
_yearDemandManagement = yearDemandManagement;
_yearDemandManagementHistory = yearDemandManagementHistory;
_replenishmentAnnualProduction = replenishmentAnnualProduction;
_holidayMaster = holidayMaster;
_crm_planorder = crm_planorder;
_platformInventory = platformInventory;
_DMS_IN_ITEMMAPPING = DMS_IN_ITEMMAPPING;
_DMS_IN_LOCDETAIL = DMS_IN_LOCDETAIL;
_DMS_IN_SHIPPINGDETAIL = DMS_IN_SHIPPINGDETAIL;
_ReplenishmentTurnOverSet= ReplenishmentTurnOverSet;
_serialNumberAppService= serialNumberAppService;
_pretreatmentAppService = pretreatmentAppService;
_CalcBomViewAppService = CalcBomViewAppService;
_purchaseOrderAppService = purchaseOrderAppService;
_productExamineAppService = productExamineAppService;
_currentTenant =currentTenant;
_businessBangDbContext= businessBangDbContext;
_businessDbContext = businessDbContext;
_unitOfWorkManager = unitOfWorkManager;
}
#endregion
///
/// 生成年度生产大纲
///
///
///
///
public async Task SaveAnnualProductionOutline(InputDto input)
{
//来自定时任务的请求
if(input.year==0&& input.month==0)
{
input.year = DateTime.Now.Year;
input.month = DateTime.Now.Month;
}
//每年10月份做下一年的销售预测
if(DateTime.Now.Month>=10)
{
input.year = DateTime.Now.AddYears(1).Year;
input.month = DateTime.Now.Month;
}
//获取当前导入或修改数据
List yearDemands = _yearDemandManagement.GetListAsync(p => p.Year == input.year && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p => p.OrderNum).ThenBy(o => o.PlanMonth).ToList();
if(yearDemands==null ||yearDemands.Count==0)
{
input.year = DateTime.Now.Year;
input.month = DateTime.Now.Month;
yearDemands = _yearDemandManagement.GetListAsync(p => p.Year == input.year && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p => p.OrderNum).ThenBy(o => o.PlanMonth).ToList();
}
//标准工艺路径表
var sapItemList = yearDemands.Select(m => m.SAPItemNumber).Distinct().ToList();
var planList = _mysql_ic_item.GetListAsync(a => sapItemList.Contains(a.number) && a.factory_id == input.factory_id && !a.IsDeleted).Result.ToList();
var bomList = _mysql_ic_bom.GetListAsync(a => sapItemList.Contains(a.item_number) && !a.IsDeleted && a.factory_id == input.factory_id).Result;
var planItemList = planList.Select(a => a.number).Distinct().ToList();
var expectedList = sapItemList.Except(planItemList).ToList();
if (expectedList.Count > 0)
{
return "年度销售预测物料" + string.Join(",", expectedList) + "在DOP物料表找不到!";
}
var bomItemList = bomList.Select(a => a.item_number).Distinct().ToList();
var expectedBOMList = sapItemList.Except(bomItemList).ToList();
if (expectedBOMList.Count > 0)
{
return "年度销售预测物料" + string.Join(",", expectedBOMList) + "在BOM没有维护!";
}
var itemMasterList = _itemMaster.Select(i => sapItemList.Contains(i.ItemNum) && i.Domain == input.factory_id.ToString());
List routingOps = _routingOpDetail.Select(p => sapItemList.Contains(p.RoutingCode) && p.Domain == input.factory_id.ToString() && p.IsActive);
var routingOpList = routingOps.Where(x => x.Ufld1 == "组装" && x.MilestoneOp).ToList();
//生产线明细表
List prodLines = _prodLineDetail.Select(p => sapItemList.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 lineMasters = _lineMaster.Select(p => prodLines.Select(a=>a.Line).Distinct().ToList().Contains(p.Line) && p.Domain == input.factory_id.ToString() && p.IsActive).ToList();
List locations = _invMaster.Select(x => sapItemList.Contains(x.ItemNum) && x.Domain == input.factory_id.ToString() && x.IsActive).ToList();
//平台库存
var DMSItemList = _DMS_IN_ITEMMAPPING.Select(a => sapItemList.Contains(a.CfnERPCode));
var gkhwStock = _DMS_IN_LOCDETAIL.Select(a => (a.DealerCode == "RQ000005" || a.DealerCode == "RQ000002"));
var sapInvList = _SAPInv.Select(a => a.WERKS == input.factory_id.ToString() && sapItemList.Contains(a.MATNR) && (a.SOBKZ.ToUpper() == "O"));
// 获取某年某月的起始日期和结束日期
DateTime start = new DateTime(DateTime.Now.Year, DateTime.Now.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(DateTime.Now.Year, 4, 1);
DateTime endYear = new DateTime(DateTime.Now.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
//var pretreatments = _mysql_b_bom_pretreatment.GetListAsync(s => bomList.Select(c => c.Id).ToList().Contains(s.sourceid)).Result;
//List autoCreates = new List();
//var mobomlist = ObjectMapper.Map, List>(bomList);
//mobomlist.ForEach(p =>
//{
// if (!pretreatments.Where(s => s.sourceid == p.mysql_id).Any())
// {
// autoCreates.Add(p);
// }
//});
//if (autoCreates.Any())
//{
// AutoCreateBomBill(input.company_id.ToString(), autoCreates);
// pretreatments = _mysql_b_bom_pretreatment.GetListAsync(s => bomList.Select(c => c.Id).ToList().Contains(s.sourceid)).Result;
//}
//年度生产大纲实体
List annualProductionOutlines = new List();
List frontYearDemand = new List();
for(int i=0;i< yearDemands.Count;i++)
{
if (yearDemands.Where(a => a.SAPItemNumber == yearDemands[i].SAPItemNumber).Count() != 12)
{
return "年度销售预测物料" + yearDemands[i].SAPItemNumber + "年度的12个月数据不完整或者存在重复物料!";
}
frontYearDemand.Add(yearDemands[i]);
var routingOp = routingOps.Where(x => x.RoutingCode == yearDemands[i].SAPItemNumber).ToList();
//组装标准工时
var Assembly = routingOp.Where(x => x.Ufld1 == "组装" && x.MilestoneOp).FirstOrDefault();
//热封标准工时
var HeatSealing = routingOp.Where(x => x.Ufld1 == "热封" && x.MilestoneOp).FirstOrDefault();
//包装标准工时
var Packaging = routingOp.Where(x => x.Ufld1 == "包装" && x.MilestoneOp).FirstOrDefault();
var prodLine = prodLines.Where(x => x.Part == yearDemands[i].SAPItemNumber).OrderBy(x => x.Sequence).FirstOrDefault();
//不同库位库存数量
//5008成品线边库,8001成品合格库,8000成品待检
var locationList = locations.Where(x => x.ItemNum == yearDemands[i].SAPItemNumber && (x.Location == "5008" || x.Location == "5009"|| x.Location == "5010" || x.Location == "8000" || x.Location == "8001"|| x.Location == "8002"|| x.Location == "8002"|| x.Location == "8003"|| x.Location == "8004"|| x.Location == "8005")).ToList();
//平台数据
decimal? hwStock = 0;
if (DMSItemList.Find(d => d.CfnERPCode == yearDemands[i].SAPItemNumber) != null)
{
var itemDMS = gkhwStock.Where(o => o.UPN == DMSItemList.Find(d => d.CfnERPCode == yearDemands[i].SAPItemNumber).CfnCode && o.DealerCode == "RQ000002").ToList();
if (itemDMS.Count > 0)
{
var maxDate = itemDMS.OrderByDescending(i => i.InventoryDate).First();
hwStock = itemDMS.Where(i => i.InventoryDate == maxDate.InventoryDate).Sum(q => q.Qty);
}
}
decimal? gkStock = 0;
if (DMSItemList.Find(d => d.CfnERPCode == yearDemands[i].SAPItemNumber) != null)
{
var itemDMS = gkhwStock.Where(o => o.UPN == DMSItemList.Find(d => d.CfnERPCode == yearDemands[i].SAPItemNumber).CfnCode && o.DealerCode == "RQ000005").ToList();
if (itemDMS.Count > 0)
{
var maxDate = itemDMS.OrderByDescending(i => i.InventoryDate).First();
gkStock = itemDMS.Where(i => i.InventoryDate == maxDate.InventoryDate).Sum(q => q.Qty);
}
}
//销售预测 对应 Excel中公式 AVERAGE 如果预测为0不参与计算排产批量
var QtySum = yearDemands.Where(x => x.SAPItemNumber == yearDemands[i].SAPItemNumber && x.Qty > 0).ToList();
//排产批量:(AVG(1 - 12月销售预测)/ 100 )=(0.45 = 1 小数向上取整) *100 = 100
decimal pcpl = 0;
if (QtySum != null && QtySum.Count > 0)
{
pcpl = Math.Ceiling(QtySum.Average(p => p.Qty) / 100) * 100;
}
//库存合计 + 在制+已发货 + 灭菌中
var ship = shipList.Where(x => x.ContainerItem == yearDemands[i].SAPItemNumber).ToList();
decimal itemInProduct = 0;
if (dictInProduction.ContainsKey(yearDemands[i].SAPItemNumber))
{
itemInProduct = dictInProduction[yearDemands[i].SAPItemNumber];
}
decimal? InSterilizationQty = 0.00m;
if (sapInvList.Count > 0 && sapInvList.Any(a => a.MATNR == yearDemands[i].SAPItemNumber))
{
InSterilizationQty = sapInvList.Where(a => a.MATNR == yearDemands[i].SAPItemNumber && a.SOBKZ.ToUpper()=="O").Sum(x => Convert.ToDecimal(x.LABST) + Convert.ToDecimal(x.INSME) + Convert.ToDecimal(x.SPEME));
}
var locationSum = (locationList.Count == 0 ? 0 : locationList.Sum(x => x.AvailStatusQty.GetValueOrDefault() + x.Assay.GetValueOrDefault())) + gkStock + hwStock + (ship.Count == 0 ? 0 : ship.Sum(x => x.QtyToShip)) + itemInProduct + InSterilizationQty;
//前面N个月的生产数量
var frontQtySum = annualProductionOutlines.Where(a=>a.SAPItemNumber== yearDemands[i].SAPItemNumber).Sum(x => x.Qty);
//生产数量:3月为例子,if((库存合计和前2月生产数量)-(前2个月销售预测数据)-当月销售预测数据 / 2 < 0)
// { 排产批量 * ((-(库存合计+前12个月生产数量)) + (前12个月销售预测) + 当月销售预测 / 2 ) / 排产批量 ) } else {0}
decimal ProduceQty = 0.00m;
decimal NextMonthQty = 0.00m;
if (yearDemands[i].PlanMonth.Substring(5)!="12")
{
NextMonthQty = yearDemands[i + 1].Qty;
}else
{
NextMonthQty = pcpl;
}
//判断库存是否满足需要,满足则不用生产
//安全库存
decimal? safeQty=itemMasterList.Find(a => a.ItemNum == yearDemands[i].SAPItemNumber)?.SafetyStk;
//前N个月的需求数量
decimal frontYearDemandQty = frontYearDemand.Where(f => f.SAPItemNumber == yearDemands[i].SAPItemNumber).Sum(m => m.Qty);
if(locationSum.GetValueOrDefault()+frontQtySum-safeQty-frontYearDemandQty-NextMonthQty/2<0)
{
if (pcpl == 0)
{
ProduceQty = 0;
}
else
{
ProduceQty = Math.Ceiling((-locationSum.GetValueOrDefault() - frontQtySum + safeQty.GetValueOrDefault() + frontYearDemandQty + NextMonthQty / 2) / pcpl) * pcpl;
}
}
//生成年度生产大纲
ReplenishmentAnnualProduction annualProductionOutline = new ReplenishmentAnnualProduction();
annualProductionOutline.Year = yearDemands[i].Year;
annualProductionOutline.Area = yearDemands[i].Area;
annualProductionOutline.ProdLine = yearDemands[i].ProdLine;
annualProductionOutline.ProdRange = yearDemands[i].ProdRange;
if (prodLine == null || lineMasters.Find(b => b.Line == prodLine.Line) == null)
{
annualProductionOutline.WorkshopLine = "";
}
else
{
annualProductionOutline.WorkshopLine = lineMasters.Find(b => b.Line == prodLine.Line).Describe;
}
annualProductionOutline.SAPItemNumber = yearDemands[i].SAPItemNumber;
annualProductionOutline.Model = yearDemands[i].Model;
annualProductionOutline.Languages = yearDemands[i].Languages;
annualProductionOutline.PlanMonth = yearDemands[i].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 = yearDemands[i].OrderNum;
annualProductionOutline.create_time = DateTime.Now;
annualProductionOutline.tenant_id = input.tenant_id;
annualProductionOutline.company_id = input.company_id;
annualProductionOutline.factory_id = input.factory_id;
annualProductionOutline.org_id = input.org_id;
annualProductionOutlines.Add(annualProductionOutline);
//var planBOM = bomList.Find(b => b.item_number == productList[i].SAPItemNumber);
//var pretreament = pretreatments.Where(c => c.sourceid == planBOM.Id).ToList();
//var returnlist = ObjectMapper.Map, List>(pretreament);
//returnlist = returnlist.OrderBy(s => s.num_order).ToList();
//var level1Dto = returnlist[0];
//level1Dto.needCount = productList[i].Qty;
//CaclMaterialShortage(returnlist);
//foreach (var r in returnlist)
//{
// if (r.item_number != productList[i].SAPItemNumber && r.erp_cls == 1 && !string.IsNullOrEmpty(r.bom_number))
// {
// if (r.needCount <= 0)
// continue;
// var ic_itemSub = _itemMaster.Select(x => x.ItemNum == r.item_number && x.Domain == input.factory_id.ToString());
// if (ic_itemSub.Count <= 0)
// continue;
// mes_morder mes_MorderSub = new mes_morder();
// mes_MorderSub.GenerateNewId(help.NextId());
// mes_MorderSub.morder_type = MorderEnum.JhMorder;
// mes_MorderSub.work_order_type = MorderEnum.CgMorder;
// mes_MorderSub.morder_state = "";
// var nbrlistDto = _serialNumberAppService.GetBillNo(input.factory_id.ToString(), "M5", 1, "", 1);
// if (nbrlistDto.Any())
// {
// mes_MorderSub.morder_no = nbrlistDto[0].NbrResult;
// }
// else
// {
// return "没有正确获取到工单编号,请检查";
// }
// mes_MorderSub.fms_number = "";
// mes_MorderSub.bom_number = r.bom_number;
// mes_MorderSub.fmodel = ic_itemSub[0].Descr1;
// mes_MorderSub.urgent = 1;
// mes_MorderSub.moentry_startup_status = 0;
// mes_MorderSub.tenant_id = input.tenant_id;
// mes_MorderSub.factory_id = input.factory_id;
// mes_MorderSub.company_id = input.company_id;
// mes_MorderSub.org_id = input.org_id;
// mes_MorderSub.product_code = ic_itemSub[0].ItemNum;
// mes_MorderSub.product_name = ic_itemSub[0].Descr;
// mes_MorderSub.morder_date = DateTime.Now.Date.AddDays(1);
// if (ic_itemSub[0].PurLT > 0)
// {
// mes_MorderSub.moentry_sys_stime = Convert.ToDateTime(productList[i].PlanMonth + "-01").AddDays(-ic_itemSub[0].PurLT);
// }
// else
// {
// mes_MorderSub.moentry_sys_stime = Convert.ToDateTime(productList[i].PlanMonth + "-01").AddDays(-1);
// }
// mes_MorderSub.moentry_prd = null;
// mes_MorderSub.moentry_prdname = null;
// mes_MorderSub.moentry_wrkc = null;
// mes_MorderSub.moentry_wrkcname = null;
// mes_MorderSub.picking_qty = 0;
// mes_MorderSub.unit = ic_itemSub[0].UM;
// mes_MorderSub.morder_production_number = r.needCount;
// mes_MorderSub.need_number = r.needCount;
// mes_MorderSub.remaining_number = 0;
// mes_MorderSub.create_time = DateTime.Now;
// //生成工单子表数据
// mes_moentry mes_MoentrySub = new mes_moentry();
// mes_MoentrySub.GenerateNewId(help.NextId());
// mes_MoentrySub.moentry_moid = mes_MorderSub.Id;
// mes_MoentrySub.moentry_mono = mes_MorderSub.morder_no;
// mes_MoentrySub.unit = ic_itemSub[0].UM;
// mes_MoentrySub.morder_production_number = r.needCount;
// mes_MoentrySub.need_number = r.needCount;
// mes_MoentrySub.remaining_number = 0;
// mes_MoentrySub.tenant_id = input.tenant_id;
// mes_MoentrySub.factory_id = input.factory_id;
// mes_MoentrySub.company_id = input.company_id;
// mes_MoentrySub.org_id = input.org_id;
// mes_MoentrySub.create_time = DateTime.Now;
// moList.Add(mes_MorderSub);
// moentryList.Add(mes_MoentrySub);
// }
//}
}
//保存数据
using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
{
try
{
var toDelete = _businessDbContext.ReplenishmentAnnualProduction.Where(a => a.Year == input.year && a.factory_id == input.factory_id).ToList();
await _businessDbContext.BulkDeleteAsync(toDelete);
await _businessDbContext.BulkInsertAsync(annualProductionOutlines);
await CalcLongPeriodItemPR(input);
await CalcROP(input);
await SaveProductionMasterPlan(input, annualProductionOutlines);
await CalcWeekPlan(input);
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,List annual)
{
//来自定时任务的请求
if (input.year == 0 && input.month == 0)
{
input.year = DateTime.Now.Year;
input.month = DateTime.Now.Month;
}
//计算当前年月的N0,N+1,N+2
List planMons = GetPlanMonth(4);
List productionMasters= new List();
List pre3MonthPlan = _productionMasterPlan.GetListAsync(a => GetPlanMonth(-3).Contains(a.PlanMonth) && a.factory_id == input.factory_id).Result;
//N0,N+1,N+2月度发货计划
var annualProduction = new List();
foreach (var itemMonth in planMons)
{
var annualProductionMonth = _monthlyShipmentPlan.Select(x => itemMonth==x.PlanMonth && !x.IsDeleted && x.factory_id == input.factory_id).OrderBy(p => p.PlanMonth).ThenBy(o => o.OrderNum).ToList();
if(annualProductionMonth!=null && annualProductionMonth.Count>0)
{
annualProduction.AddRange(annualProductionMonth);
}else
{
var MaxVersion=_monthlyShipmentPlanHistory.Select(a => a.factory_id == input.factory_id && !a.IsDeleted).Max(b => b.VERSION);
if(!string.IsNullOrEmpty(MaxVersion))
{
var annualProductionMonthHistory = _monthlyShipmentPlanHistory.Select(x => itemMonth == x.PlanMonth && x.VERSION == MaxVersion && !x.IsDeleted && x.factory_id == input.factory_id).OrderByDescending(v => v.VERSION).ThenBy(p => p.PlanMonth).ThenBy(o => o.OrderNum).ToList();
if (annualProductionMonthHistory != null && annualProductionMonthHistory.Count > 0)
{
var returnlist = ObjectMapper.Map, List>(annualProductionMonthHistory);
annualProduction.AddRange(returnlist);
}
}
}
}
annualProduction=annualProduction.OrderBy(p => p.PlanMonth).ThenBy(o => o.OrderNum).ToList();
var productionMasterPlan = _productionMasterPlan.GetListAsync(x => planMons.Contains(x.PlanMonth) && !x.IsDeleted && x.factory_id == input.factory_id).Result.OrderBy(p => p.PlanMonth).ThenBy(o => o.OrderNum).ToList();
List locations = _invMaster.Select(x => annualProduction.Select(m => m.SAPItemNumber).Contains(x.ItemNum) && x.Domain == input.factory_id.ToString() && x.IsActive).ToList();
var InProdcutQty=GetInProdcutQty(annualProduction.Select(m => m.SAPItemNumber).ToList(),input);
var itemStock = CalcStock(annualProduction.Select(m => m.SAPItemNumber).Distinct().ToList(),input);
//主生产计划渠道合并,只考虑瑞奇库存不考虑国科海王库存
List shipList = new List();
foreach (var item in annualProduction)
{
if (shipList.Any(a => a.SAPItemNumber == item.SAPItemNumber && a.PlanMonth == item.PlanMonth))
{
shipList.Find(b => b.SAPItemNumber == item.SAPItemNumber && b.PlanMonth == item.PlanMonth).Qty += item.Qty;
}
else
{
shipList.Add(item);
}
}
shipList.OrderBy(a => a.PlanMonth);
var shipItemList= shipList.Select(a=>a.SAPItemNumber).Distinct().ToList();
var ropPlan = _replenishmentROPWeekPlan.GetListAsync(x => shipItemList.Contains(x.number) && planMons.Contains(x.planmonth) && !x.IsDeleted && x.factory_id == input.factory_id).Result;
var sapInvList = _SAPInv.Select(a => a.WERKS == input.factory_id.ToString() && shipItemList.Contains(a.MATNR) && (a.SOBKZ.ToUpper() == "O"));
foreach (var item in shipList)
{
var ropItem = ropPlan.Find(x => x.number == item.SAPItemNumber);
if(ropItem!=null)
{
ProductionMasterPlan plan = new ProductionMasterPlan();
plan.Area = item.Area;
plan.ProdLine = item.ProdLine;
plan.ProdRange = item.ProdRange;
plan.WorkshopLine = annual.Find(a => a.PlanMonth == item.PlanMonth && a.SAPItemNumber == item.SAPItemNumber)?.WorkshopLine;
if (plan.WorkshopLine==null)
{
plan.WorkshopLine = "";
}
plan.ItemNumber = item.SAPItemNumber;
plan.Model = item.Model;
plan.Languages = item.Languages;
plan.PlanMonth = item.PlanMonth;
plan.PlanShipQty = item.Qty;
var preMonth = Convert.ToDateTime($"{plan.PlanMonth}-01").AddMonths(-1);
var preMonthStr = $"{preMonth.Year}-{preMonth.Month}";
var preMaster = productionMasters.Find(t => t.ItemNumber == plan.ItemNumber && t.PlanMonth == preMonthStr && t.factory_id == input.factory_id);
var preStock = pre3MonthPlan.Find(t => t.ItemNumber == plan.ItemNumber && t.PlanMonth == preMonthStr && t.factory_id == input.factory_id);
if (preMaster != null)
{
plan.PlanProductQty = Math.Ceiling(item.Qty -
(
preMaster.PlanStockQty -
ropItem.security_stock.GetValueOrDefault()
));//发货计划-(上个月期末库存作为本月期初库存-安全库存)
if (plan.PlanProductQty < 0)
{
plan.PlanProductQty = 0;
}
plan.PlanStockQty = Math.Ceiling(preMaster.PlanStockQty + plan.PlanProductQty - item.Qty);
}
else if (preStock != null)
{
plan.PlanProductQty = Math.Ceiling(item.Qty -
(
preStock.PlanStockQty -
ropItem.security_stock.GetValueOrDefault()
));//发货计划-(上个月期末库存作为本月期初库存-安全库存)
if (plan.PlanProductQty < 0)
{
plan.PlanProductQty = 0;
}
plan.PlanStockQty = Math.Ceiling(preStock.PlanStockQty + plan.PlanProductQty - item.Qty);
}
else
{
decimal itemStockQty = 0;
if (itemStock.Any(a => a.ItemNumber == item.SAPItemNumber))
{
itemStockQty = itemStock.Find(a => a.ItemNumber == item.SAPItemNumber).Qty;
}
decimal itemInProdcutQty = 0;
if (InProdcutQty.Any(a => a.ItemNumber == item.SAPItemNumber))
{
itemInProdcutQty = InProdcutQty.Find(a => a.ItemNumber == item.SAPItemNumber).Qty;
}
plan.PlanProductQty = item.Qty -
(itemStockQty + itemInProdcutQty - ropItem.security_stock.GetValueOrDefault()
);//发货计划-(库存+在制-安全库存)
if (plan.PlanProductQty < 0)
plan.PlanProductQty = 0;
plan.PlanStockQty = Math.Ceiling(
itemStock.Find(a => a.ItemNumber == item.SAPItemNumber).Qty +
InProdcutQty.Find(a => a.ItemNumber == item.SAPItemNumber).Qty +
plan.PlanProductQty - item.Qty);
}
if (locations.FirstOrDefault(a => a.ItemNum == item.SAPItemNumber && a.Location == "8001") != null)
{
plan.Inventory = locations.Where(a => a.ItemNum == item.SAPItemNumber && a.Location == "8001").Sum(c => c.AvailStatusQty.GetValueOrDefault() + c.Assay.GetValueOrDefault());
}
else
{
plan.Inventory = 0;
}
if (locations.FirstOrDefault(a => a.ItemNum == item.SAPItemNumber && a.Location == "8000") != null)
{
plan.Inventory1 = locations.Where(a => a.ItemNum == item.SAPItemNumber && a.Location == "8000").Sum(c => c.AvailStatusQty.GetValueOrDefault() + c.Assay.GetValueOrDefault());
}
else
{
plan.Inventory1 = 0;
}
if (locations.FirstOrDefault(a => a.ItemNum == item.SAPItemNumber && a.Location == "5008") != null)
{
plan.Inventory2 = locations.Where(a => a.ItemNum == item.SAPItemNumber && a.Location == "5008").Sum(c => c.AvailStatusQty.GetValueOrDefault() + c.Assay.GetValueOrDefault());
}
else
{
plan.Inventory2 = 0;
}
decimal InSterilizationQty = 0.00m;
if (sapInvList.Count > 0 && sapInvList.Any(a => a.MATNR == item.SAPItemNumber && a.SOBKZ.ToUpper() == "O"))
{
InSterilizationQty = sapInvList.Where(a => a.MATNR == item.SAPItemNumber && a.SOBKZ.ToUpper()=="O").Sum(x => Convert.ToDecimal(x.LABST) + Convert.ToDecimal(x.INSME) + Convert.ToDecimal(x.SPEME));
}
plan.DuringSterilization = InSterilizationQty;
plan.InProduction = InProdcutQty.Find(a => a.ItemNumber == item.SAPItemNumber).Qty;
if (pre3MonthPlan.Where(a => a.ItemNumber == item.SAPItemNumber).Count() > 0)
{
plan.EconomicLotSize = pre3MonthPlan.Where(a => a.ItemNumber == item.SAPItemNumber).Average(a => a.PlanProductQty);
}
else
{
plan.EconomicLotSize = plan.PlanProductQty;
}
plan.tenant_id = input.tenant_id;
plan.factory_id = input.factory_id;
plan.company_id = input.company_id;
plan.org_id = input.org_id;
plan.create_time = DateTime.Now;
plan.OrderNum = item.OrderNum;
productionMasters.Add(plan);
}
else
{
new NLogHelper("AnnualProductionOutlineAppService").WriteLog("SaveProductionMasterPlan", "【" + input.year + "年" + "】主计划找不到发货计划物料:" + item.SAPItemNumber, _currentTenant.Id.ToString());
}
}
//保存数据
using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
{
try
{
var planList = productionMasters.Select(a => a.PlanMonth).ToList();
await _productionMasterPlan.DeleteAsync(a => planList.Contains(a.PlanMonth) && a.factory_id == input.factory_id);
await _businessDbContext.BulkInsertAsync(productionMasters);
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 List GetInProdcutQty(List itemNumbers,InputDto input)
{
List itemQty = new List();
DateTime startYear = new DateTime(DateTime.Now.AddYears(-1).Year, 1, 1);
DateTime endYear = new DateTime(DateTime.Now.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);
}
}
itemNumbers.ForEach(a =>
{
EOPDto eOP = new EOPDto();
eOP.ItemNumber = a;
eOP.Qty = 0;
if(dictInProduction.ContainsKey(a))
eOP.Qty = dictInProduction[a];
itemQty.Add(eOP);
});
return itemQty;
}
///
/// 更新年度生产大纲
///
///
///
///
public async Task DemandAnalysis(InputDto input)
{
string productResult=await SaveAnnualProductionOutline(input);
if(productResult!="OK")
return productResult;
return "OK|刷新成功!";
}
///
/// 调整成品ROP和最高库存水位
///
///
///
public async Task CalcROP(InputDto input)
{
//来自定时任务的请求
if (input.year == 0 && input.month == 0)
{
input.year = DateTime.Now.Year;
input.month = DateTime.Now.Month;
}
//1.获取补货模型全局参数
ReplenishmentDto replenishmentDto = GetROPParam(input.factory_id.ToString());
List addList = new List();
List updateList = new List();//更新上一个月的实际出库数量
//获取存货周转率设置
var turnOverlist = _ReplenishmentTurnOverSet.GetListAsync(a => a.factory_id == input.factory_id).Result;
//获取补货模型前H周期和未来F个周期的数据
List planMonthList = new List();
for (int j = -replenishmentDto.HistoryOutStockMonth; j < replenishmentDto.SaleFcstMonth; j++)
{
string itemMonth = $"{DateTime.Now.AddMonths(j).Year}-{DateTime.Now.AddMonths(j).Month.ToString("00")}";
planMonthList.Add(itemMonth);
}
var planList = new List();
foreach (var itemMonth in planMonthList)
{
var annualProductionMonth = _monthlyShipmentPlan.Select(x => itemMonth == x.PlanMonth && !x.IsDeleted && x.factory_id == input.factory_id).OrderBy(p => p.PlanMonth).ThenBy(o => o.OrderNum).ToList();
if (annualProductionMonth != null && annualProductionMonth.Count > 0)
{
planList.AddRange(annualProductionMonth);
}
else
{
var MaxVersion = _monthlyShipmentPlanHistory.Select(a => a.factory_id == input.factory_id && !a.IsDeleted).Max(b => b.VERSION);
if (!string.IsNullOrEmpty(MaxVersion))
{
var annualProductionMonthHistory = _monthlyShipmentPlanHistory.Select(x => itemMonth == x.PlanMonth && x.VERSION == MaxVersion && !x.IsDeleted && x.factory_id == input.factory_id).OrderByDescending(v => v.VERSION).ThenBy(p => p.PlanMonth).ThenBy(o => o.OrderNum).ToList();
if (annualProductionMonthHistory != null && annualProductionMonthHistory.Count > 0)
{
var returnlist = ObjectMapper.Map, List>(annualProductionMonthHistory);
planList.AddRange(returnlist);
}
}
}
}
planList = planList.OrderBy(p => p.PlanMonth).ThenBy(o => o.OrderNum).ToList();
//获取BOM用于分解到原材料
var boms = _ic_bom.GetListAsync(a => planList.Select(p => p.SAPItemNumber).Distinct().ToList().Contains(a.item_number) && a.factory_id == input.factory_id).Result;
var planItemList = planList.Select(a => a.SAPItemNumber).Distinct().ToList();
var bomItemList=boms.Select(a=>a.item_number).Distinct().ToList();
var expectedList = planItemList.Except(bomItemList).ToList();
if(expectedList.Count>0)
{
throw new NotImplementedException("月度发货计划物料" + string.Join(",", expectedList)+"没有维护BOM!");
}
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(input.company_id.ToString(), autoCreates);
pretreatments = _mysql_b_bom_pretreatment.GetListAsync(s => boms.Select(c => c.mysql_id).ToList().Contains(s.sourceid)).Result;
}
var mesItemList = _itemMaster.Select(a => pretreatments.Select(p => p.item_number).Contains(a.ItemNum) && a.Domain == input.factory_id.ToString() && a.IsActive);
var itemProductList = _mysql_ic_item.GetListAsync(a => pretreatments.Select(p => p.item_number).Contains(a.number) && !a.IsDeleted && a.factory_id == input.factory_id).Result;
var itemList = itemProductList.Select(a => a.number).ToList();
var srm_purchaseList = _srmPurchase.GetListAsync(a => pretreatments.Select(p => p.item_number).Contains(a.number) && !a.IsDeleted).Result;
var ropModelList = _replenishmentROPWeekPlan.GetListAsync(a => itemList.Contains(a.number) && planMonthList.Contains(a.planmonth) && a.factory_id == input.factory_id).Result;
//获取成品库存、灭菌库存、在制库存(会从SAP同步的库存表更新到LocationDetail、ic_item表中)
var locations = _invMaster.Select(p => p.Domain == input.factory_id.ToString() && itemList.Contains(p.ItemNum) && p.IsActive);
//国科海王只有成品
var DMSItemList = _DMS_IN_ITEMMAPPING.Select(a => planList.Select(p => p.SAPItemNumber).ToList().Contains(a.CfnERPCode));
var gkhwStock = _DMS_IN_LOCDETAIL.Select(a => (a.DealerCode == "RQ000005" || a.DealerCode == "RQ000002"));
decimal? InProductionQty = 0.00m;
//获取在制数量 获取工单数取每年4月到12月底的工单
DateTime startYear = new DateTime(DateTime.Now.Year, 1, 1);
DateTime endYear = new DateTime(DateTime.Now.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();
var workOrds = workOrdRoutings.GroupBy(x => x.WorkOrd).ToList();
Dictionary dictItemStock = 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 (dictItemStock.ContainsKey(MaxOp.ItemNum))
{
dictItemStock[MaxOp.ItemNum] += InProductionQty.Value;
}
else
{
dictItemStock.Add(MaxOp.ItemNum, InProductionQty.Value);
}
}
foreach (var item in locations)
{
//库存合计 + 在制 + 灭菌中 (InvMaster没有过滤灭菌中状态可能已经算在可用库存中了)
//5008成品线边库,8001成品合格库,8000成品待检
if (item.Location == "5008"|| item.Location == "5009"|| item.Location == "5010" || item.Location == "8000" || item.Location == "8001"|| item.Location == "8002"|| item.Location == "8003"|| item.Location == "8004"|| item.Location == "8005")
{
if (dictItemStock.ContainsKey(item.ItemNum))
{
dictItemStock[item.ItemNum] += (item.AvailStatusQty.GetValueOrDefault() + item.Assay.GetValueOrDefault());
}
else
{
dictItemStock.Add(item.ItemNum, (item.AvailStatusQty.GetValueOrDefault() + item.Assay.GetValueOrDefault()));
}
}
}
foreach (var item in itemList)
{
if (!dictItemStock.ContainsKey(item))
{
dictItemStock.Add(item, 0);
}
}
//取过去6个月成品发货出库记录
var dateBegin = DateTime.Now.AddMonths(-6);
var datePreBegin = DateTime.Now.AddMonths(-1);
var dateEnd = DateTime.Now;
//获取瑞奇发往国科海王的记录
var gkhwList = _ASNBOLShipperMaster.Select(a => a.Domain == input.factory_id.ToString() && (a.SoldTo == "10002080" || a.SoldTo == "10001981"));
var recidList = gkhwList.Select(a => Convert.ToInt64(a.RecID)).ToList();
//获取瑞奇发货记录
var shipList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.RealQty > 0
&& itemList.Contains(a.ContainerItem) && a.ShipDate >= dateBegin && a.ShipDate <= dateEnd && !recidList.Contains(a.ASNBOLShipperRecID));//瑞奇只算瑞奇排除国科海王
//获取瑞奇上月发货记录
var shipMList = shipList.Where(a => a.ShipDate >= datePreBegin && a.ShipDate <= dateEnd).ToList();//瑞奇只算瑞奇排除国科海王
//获取国科海王发货记录
var gkItemList = planList.Where(p => p.DistributionChannel == "国科").Select(p => p.SAPItemNumber).ToList();
var DMSItemListGK = _DMS_IN_ITEMMAPPING.Select(a => gkItemList.Contains(a.CfnERPCode));
var shipListGK = _DMS_IN_SHIPPINGDETAIL.Select(a =>
DMSItemListGK.Select(g => g.CfnCode).Contains(a.UPN) && a.ParentDealerCode == "RQ000005" && a.ShipmentDate >= DateOnly.FromDateTime(dateBegin) && a.ShipmentDate <= DateOnly.FromDateTime(dateEnd));//国科
var hwItemList = planList.Where(p => p.DistributionChannel == "海王").Select(p => p.SAPItemNumber).ToList();
var DMSItemListHW = _DMS_IN_ITEMMAPPING.Select(a => hwItemList.Contains(a.CfnERPCode));
var shipListHW = _DMS_IN_SHIPPINGDETAIL.Select(a =>
DMSItemListHW.Select(g => g.CfnCode).Contains(a.UPN) && a.ParentDealerCode == "RQ000002" && a.ShipmentDate >= DateOnly.FromDateTime(dateBegin) && a.ShipmentDate <= DateOnly.FromDateTime(dateEnd));//海王
//领料出库记录
var pickbilllist = _invTransHist.Select(a => a.Domain == input.factory_id.ToString() && a.TransType == "iss-wo" && a.IsActive
&& a.CreateTime >= dateBegin && itemList.Contains(a.ItemNum));
var gkCNCCodeList = DMSItemListGK.Select(g => g.CfnCode).ToList();
var dateOnlyCurrent = DateOnly.FromDateTime(datePreBegin);
var dateOnlyNow = DateOnly.FromDateTime(dateEnd);
var shipMListGK = _DMS_IN_SHIPPINGDETAIL.Select(a =>
gkCNCCodeList.Contains(a.UPN) && a.ParentDealerCode == "RQ000005" && a.ShipmentDate >= dateOnlyCurrent && a.ShipmentDate <= dateOnlyNow);//国科
var hwCNCCodeList = DMSItemListHW.Select(g => g.CfnCode).ToList();
var shipMListHW = _DMS_IN_SHIPPINGDETAIL.Select(a =>
hwCNCCodeList.Contains(a.UPN) && a.ParentDealerCode == "RQ000002" && a.ShipmentDate >= dateOnlyCurrent && a.ShipmentDate <= dateOnlyNow);//海王
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();
var itemGroupGK = shipListGK.GroupBy(p => p.UPN)
.Select(p => new ASNBOLShipperDetail
{
QtyToShip = p.Sum(a => a.Qty),
ContainerItem = p.Key
}).ToList();
var itemMGroupGK = shipMListGK.GroupBy(p => p.UPN)
.Select(p => new ASNBOLShipperDetail
{
QtyToShip = p.Sum(a => a.Qty),
ContainerItem = p.Key
}).ToList();
var itemGroupHW = shipListHW.GroupBy(p => p.UPN)
.Select(p => new ASNBOLShipperDetail
{
QtyToShip = p.Sum(a => a.Qty),
ContainerItem = p.Key
}).ToList();
var itemMGroupHW = shipMListHW.GroupBy(p => p.UPN)
.Select(p => new ASNBOLShipperDetail
{
QtyToShip = p.Sum(a => a.Qty),
ContainerItem = p.Key
}).ToList();
var mathtool = new MathNet.Numerics.Distributions.Normal();
//更新上个月计划发货数据为实际出库数据(先算成品,原材料后面单独计算)
Dictionary preMonthRQQty = new Dictionary();
ropModelList?.Where(r => r.year == DateTime.Now.AddMonths(-1).Year && r.month == DateTime.Now.AddMonths(-1).Month).ToList()?.ForEach
(m =>
{
//只更新成品
if(planList.Any(a=>a.SAPItemNumber==m.number))
{
if (m.distributionchannel == "瑞奇")
{
preMonthRQQty.Add(m.number, m.plan_out_qty);
//成品算销售出库数量
if (itemGroup.Any(a => a.ContainerItem == m.number))
{
m.plan_out_qty = itemGroup.Find(a => a.ContainerItem == m.number)?.QtyToShip;
updateList.Add(m);
preMonthRQQty[m.number] = m.plan_out_qty;
}
}
else if (m.distributionchannel == "国科")
{
if (itemGroupGK.Any(a => a.ContainerItem == m.number))
{
m.plan_out_qty = itemGroupGK.Find(a => a.ContainerItem == m.number)?.QtyToShip;
updateList.Add(m);
}
}
else if (m.distributionchannel == "海王")
{
if (itemGroupHW.Any(a => a.ContainerItem == m.number))
{
m.plan_out_qty = itemGroupHW.Find(a => a.ContainerItem == m.number)?.QtyToShip;
updateList.Add(m);
}
}
}
});
//更新瑞奇原材料上个月出库次数(按照BOM展开合计汇总)
string planPreMonth = $"{DateTime.Now.AddMonths(-1).Year}-{DateTime.Now.AddMonths(-1).Month.ToString("00")}";
List subItem = new List();
planList.Where(a => a.DistributionChannel == "瑞奇" && a.PlanMonth == planPreMonth).ToList().ForEach(a =>
{
var planBOM = boms.Find(b => b.item_number == a.SAPItemNumber);
if(planBOM==null)
{
new NLogHelper("CalcROP").WriteLog("CalcROP", "CalcROP数据错误:" + a.SAPItemNumber+"不在BOM里", _currentTenant.Id.ToString());
}else
{
var pretreament = pretreatments.Where(c => c.sourceid == planBOM.mysql_id).ToList();
var returnlist = ObjectMapper.Map, List>(pretreament);
returnlist = returnlist.OrderBy(s => s.num_order).ToList();
var level1Dto = returnlist[0];
if (preMonthRQQty.ContainsKey(a.SAPItemNumber))
{
level1Dto.needCount = preMonthRQQty[a.SAPItemNumber].GetValueOrDefault();
}
else
{
level1Dto.needCount = a.Qty;
}
CaclMaterialShortage(returnlist);
foreach (var item in returnlist)
{
if(item.item_number!=a.SAPItemNumber)
{
if (subItem.Any(s => s.ItemNumber == item.item_number && s.PlanMonth == planPreMonth))
{
subItem.Find(s => s.ItemNumber == item.item_number && s.PlanMonth == planPreMonth).Qty += item.needCount;
}
else
{
subItem.Add(new ReplenishmentSubItemDto { ItemNumber = item.item_number, Qty = item.needCount, PlanMonth = planPreMonth });
}
}
}
}
});
ropModelList?.Where(r => r.year == DateTime.Now.AddMonths(-1).Year && r.month == DateTime.Now.AddMonths(-1).Month && r.distributionchannel=="瑞奇").ToList()?.ForEach
(m =>
{
//只更新原材料
if (!planList.Any(a => a.SAPItemNumber == m.number) && subItem.Any(s=>s.ItemNumber==m.number && s.PlanMonth==planPreMonth))
{
m.plan_out_qty = subItem.Find(s => s.ItemNumber == m.number && s.PlanMonth == planPreMonth).Qty;
updateList.Add(m);
}
});
var RQShipPlanList = planList.FindAll(s =>s.DistributionChannel == "瑞奇");
List subItemRQList=CalcMonthPlanSubItem(RQShipPlanList, boms,pretreatments);
for (int j = 0; j < replenishmentDto.SaleFcstMonth; j++)
{
string itemMonth = $"{DateTime.Now.AddMonths(j).Year}-{DateTime.Now.AddMonths(j).Month.ToString("00")}";
//先计算成品
planList?.Where(s => s.PlanMonth == itemMonth).ToList()?.ForEach(a =>
{
var icItem = itemProductList.Find(p => p.number == a.SAPItemNumber);
if (icItem != null)
{
bool isExist = ropModelList.Find(r => r.planmonth == itemMonth && r.number == a.SAPItemNumber &&r.distributionchannel==a.DistributionChannel) == null ? false : true;
var rop = new ReplenishmentROPWeekPlan();
if (isExist)
{
rop = ropModelList.Find(r => r.planmonth == itemMonth && r.number == a.SAPItemNumber &&r.distributionchannel==a.DistributionChannel);
}
rop.number = a.SAPItemNumber;
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.distributionchannel = a.DistributionChannel;
rop.lifecycle = a.LifeCycle;
rop.area = a.Area;
rop.plan_out_qty = Math.Ceiling(a.Qty);
if (planList.Where(i => i.SAPItemNumber == a.SAPItemNumber && i.DistributionChannel == a.DistributionChannel).Count() > 0)
{
rop.monthl_avg_demand = planList.Where(i => i.SAPItemNumber == a.SAPItemNumber && i.DistributionChannel == a.DistributionChannel).Average(a => a.Qty);
var nums = planList.Where(i => i.SAPItemNumber == a.SAPItemNumber && i.DistributionChannel == a.DistributionChannel).Select(a => a.Qty);
if (nums.Count() <= 1)
{
rop.monthl_avg_demand_variance = 0;
}
else
{
rop.monthl_avg_demand_variance = Math.Ceiling(Convert.ToDecimal(Math.Sqrt(nums.Sum(x => Math.Pow(Convert.ToDouble(x) - Convert.ToDouble(rop.monthl_avg_demand), 2)) / (nums.Count() - 1))));
}
}
else
{
rop.monthl_avg_demand = 0;
rop.monthl_avg_demand_variance = 0;
}
//计算月均出库
int MonthCount = 0;
decimal SumOutQty = 0;
for (int k = -1 * replenishmentDto.HistoryOutStockMonth; k < replenishmentDto.SaleFcstMonth; k++)
{
string itemMonth = $"{DateTime.Now.AddMonths(k).Year}-{DateTime.Now.AddMonths(k).Month.ToString("00")}";
if (k < 0)
{
if (ropModelList.Find(z => z.planmonth == itemMonth && z.number == a.SAPItemNumber && z.distributionchannel==a.DistributionChannel) != null)
{
SumOutQty += ropModelList.Find(z => z.planmonth == itemMonth && z.number == a.SAPItemNumber && z.distributionchannel==a.DistributionChannel).plan_out_qty.GetValueOrDefault();
MonthCount++;
}
}
else
{
if (planList.Find(z => z.PlanMonth == itemMonth && z.SAPItemNumber == a.SAPItemNumber && z.DistributionChannel==a.DistributionChannel) != null)
{
SumOutQty += planList.Find(z => z.PlanMonth == itemMonth && z.SAPItemNumber == a.SAPItemNumber && z.DistributionChannel==a.DistributionChannel).Qty;
MonthCount++;
}
}
}
if(MonthCount==0)
{
rop.monthl_avg_outstock = 0;
}else
{
rop.monthl_avg_outstock = Math.Ceiling(SumOutQty / MonthCount);
}
rop.year = DateTime.Now.AddMonths(j).Year;
rop.month = DateTime.Now.AddMonths(j).Month;
rop.planmonth = $"{DateTime.Now.AddMonths(j).Year}-{DateTime.Now.AddMonths(j).Month.ToString("00")}";
//供应提前期,成品取物料主数据维护的,原材料从货源清单取取不到取物料维护的
if(icItem.erp_cls==1)
{
rop.supply_leadtime = icItem.PurLT;//默认
}else
{
if (srm_purchaseList.Find(s => s.number ==rop.number) != null)
{
rop.supply_leadtime = srm_purchaseList.Find(s => s.number == rop.number).lead_time;
}else
{
rop.supply_leadtime = icItem.PurLT;//默认
}
}
if(rop.supply_leadtime==0)
rop.supply_leadtime = 22;//默认
//存货周转率先取规格型号,没有再取产品系列,没有取产品线,再没有取物料配置的(主要是原材料),再没有就默认
if (turnOverlist.Find(t => t.Model == rop.model) != null)
{
rop.stock_turnover = turnOverlist.Find(t => t.Model == rop.model).RQTurnOver;
}
else if (turnOverlist.Find(t => t.ProdRange == a.ProdRange) != null)
{
rop.stock_turnover = turnOverlist.Find(t => t.ProdRange == a.ProdRange).RQTurnOver;
}
else if (turnOverlist.Find(t => t.ProdLine == a.ProdLine) != null)
{
rop.stock_turnover = turnOverlist.Find(t => t.ProdLine == a.ProdLine).RQTurnOver;
}
else if (mesItemList.Find(s => s.ItemNum == a.SAPItemNumber) != null)
{
rop.stock_turnover = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber).StockTurnOver;
}
else
{
rop.stock_turnover = 4;
}
CalcFMRAndABC(rop, replenishmentDto, shipList, pickbilllist, 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.AddMonths(j).Year, DateTime.Now.AddMonths(months: j).Month));
rop.rop_computed = rop.security_stock + rop.eop;
rop.max_stock_level = rop.monthl_avg_outstock * (12 / rop.stock_turnover);
//瑞奇是ROP和最高库存值两者之间取较小的值,平台是取较大的值。
if (a.DistributionChannel != "瑞奇")
{
rop.rop_revised = Math.Max(rop.rop_computed.Value, rop.max_stock_level.Value);
}
else
{
rop.rop_revised = Math.Min(rop.rop_computed.Value, rop.max_stock_level.Value);
}
//存在上一个月补货
if (updateList.Find(r => r.number == a.SAPItemNumber && r.distributionchannel==a.DistributionChannel && r.planmonth == $"{DateTime.Now.AddMonths(j - 1).Year}-{DateTime.Now.AddMonths(j - 1).Month.ToString("00")}") != null)
{
var avaItem = updateList.Find(r => r.number == a.SAPItemNumber && r.distributionchannel == a.DistributionChannel && r.planmonth == $"{DateTime.Now.AddMonths(j - 1).Year}-{DateTime.Now.AddMonths(j - 1).Month.ToString("00")}");
rop.avaStockQty = Math.Ceiling(avaItem.avaStockQty.GetValueOrDefault() + avaItem.montheop1.GetValueOrDefault() + avaItem.montheop2.GetValueOrDefault() - a.Qty);
}
else if (addList.Find(r => r.number == a.SAPItemNumber && r.distributionchannel == a.DistributionChannel && r.planmonth == $"{DateTime.Now.AddMonths(j - 1).Year}-{DateTime.Now.AddMonths(j - 1).Month.ToString("00")}") != null)
{
var avaItem = addList.Find(r => r.number == a.SAPItemNumber && r.distributionchannel == a.DistributionChannel && r.planmonth == $"{DateTime.Now.AddMonths(j - 1).Year}-{DateTime.Now.AddMonths(j - 1).Month.ToString("00")}");
rop.avaStockQty = Math.Ceiling(avaItem.avaStockQty.GetValueOrDefault() + avaItem.montheop1.GetValueOrDefault() + avaItem.montheop2.GetValueOrDefault() - a.Qty);
}
else
{
//取实际库存
if (a.DistributionChannel == "海王")
{
if (DMSItemList.Find(d => d.CfnERPCode == rop.number) != null)
{
var itemDMS = gkhwStock.Where(o => o.UPN == DMSItemList.Find(d => d.CfnERPCode == rop.number).CfnCode && o.DealerCode == "RQ000002").ToList();
if (itemDMS.Count > 0)
{
var maxDate = itemDMS.OrderByDescending(i => i.InventoryDate).First();
rop.avaStockQty = itemDMS.Where(i => i.InventoryDate == maxDate.InventoryDate).Sum(q => q.Qty);
}
}
}
else if (a.DistributionChannel == "国科")
{
if (DMSItemList.Find(d => d.CfnERPCode == rop.number) != null)
{
var itemDMS = gkhwStock.Where(o => o.UPN == DMSItemList.Find(d => d.CfnERPCode == rop.number).CfnCode && o.DealerCode == "RQ000005").ToList();
if (itemDMS.Count > 0)
{
var maxDate = itemDMS.OrderByDescending(i => i.InventoryDate).First();
rop.avaStockQty = itemDMS.Where(i => i.InventoryDate == maxDate.InventoryDate).Sum(q => q.Qty);
}
}
}
else
{
rop.avaStockQty = dictItemStock[a.SAPItemNumber];
}
}
rop.montheop1 = rop.rop_computed > rop.avaStockQty.GetValueOrDefault() ? rop.eop : 0;
rop.montheop2 = rop.security_stock > rop.avaStockQty.GetValueOrDefault() ? rop.eop : 0;
rop.ProdLine = a.ProdLine;
rop.ProdRange = a.ProdRange;
rop.Languages = a.Languages;
rop.tenant_id = input.tenant_id;
rop.company_id = input.company_id;
rop.factory_id = input.factory_id;
rop.create_time = DateTime.Now;
rop.org_id = input.org_id;
if (isExist)
{
updateList.Add(rop);
}
else
{
addList.Add(rop);
}
}
});
//计算原材料
List subItemRQ = subItemRQList.FindAll(a=>a.PlanMonth== itemMonth);
foreach(var d in subItemRQ)
{
var icItem = itemProductList.Find(s => s.number == d.ItemNumber);
if (icItem != null && !planList.Select(r => r.SAPItemNumber).ToList().Contains(d.ItemNumber))
{
bool isExist = ropModelList.Find(r => r.planmonth == itemMonth && r.number == d.ItemNumber && r.distributionchannel == "瑞奇") == null ? false : true;
var rop = new ReplenishmentROPWeekPlan();
if (isExist)
{
rop = ropModelList.Find(r => r.planmonth == itemMonth && r.number == d.ItemNumber && r.distributionchannel == "瑞奇");
}
rop.number = d.ItemNumber;
rop.name = icItem.name;
rop.model = icItem.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.distributionchannel ="";
rop.lifecycle = "";
rop.area ="";
rop.plan_out_qty = Math.Ceiling(d.Qty);
//月均需求用几个月的发货计划按照bom展开合计计算
CalcSubItem(subItemRQList,rop,replenishmentDto, d.ItemNumber);
//计算原材料月均出库
rop.monthl_avg_outstock = Math.Ceiling(pickbilllist.Where(z => z.ItemNum == rop.number).Sum(q => q.QtyChange.GetValueOrDefault() * -1) / 6);
rop.year = DateTime.Now.AddMonths(j).Year;
rop.month = DateTime.Now.AddMonths(j).Month;
rop.planmonth = $"{DateTime.Now.AddMonths(j).Year}-{DateTime.Now.AddMonths(j).Month.ToString("00")}";
//供应提前期,成品取物料主数据维护的,原材料从货源清单取取不到取物料维护的
if (icItem.erp_cls == 1)
{
rop.supply_leadtime = icItem.PurLT;//默认
}
else
{
if (srm_purchaseList.Find(s => s.number == rop.number) != null)
{
rop.supply_leadtime = srm_purchaseList.Find(s => s.number == rop.number).lead_time;
}
else
{
rop.supply_leadtime = icItem.PurLT;//默认
}
}
if (rop.supply_leadtime == 0)
rop.supply_leadtime = 22;//默认
//原材料周转率取物料
if (mesItemList.Find(s => s.ItemNum == rop.number) != null)
{
rop.stock_turnover = mesItemList.Find(s => s.ItemNum == rop.number).StockTurnOver;
if (rop.stock_turnover == 0)
{
rop.stock_turnover = 4;
}
}
else
{
rop.stock_turnover = 4;
}
if (rop.stock_turnover == 0)
rop.stock_turnover = 4;
CalcFMRAndABC(rop, replenishmentDto, shipList, pickbilllist, 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.AddMonths(j).Year, DateTime.Now.AddMonths(j).Month));
rop.rop_computed = rop.security_stock + rop.eop;
rop.max_stock_level = rop.monthl_avg_outstock * (12 / rop.stock_turnover);
//瑞奇是ROP和最高库存值两者之间取较小的值,平台是取较大的值。
//瑞奇是ROP和最高库存值两者之间取较小的值,平台是取较大的值。
rop.rop_revised = Math.Min(rop.rop_computed.Value, rop.max_stock_level.Value);
//存在上一个月补货
if (updateList.Find(r => r.number ==d.ItemNumber && r.planmonth == $"{DateTime.Now.AddMonths(j - 1).Year}-{DateTime.Now.AddMonths(j - 1).Month.ToString("00")}") != null)
{
var avaItem = updateList.Find(r => r.number == d.ItemNumber && r.planmonth == $"{DateTime.Now.AddMonths(j - 1).Year}-{DateTime.Now.AddMonths(j - 1).Month.ToString("00")}");
rop.avaStockQty = Math.Ceiling(avaItem.avaStockQty.GetValueOrDefault() + avaItem.montheop1.GetValueOrDefault() + avaItem.montheop2.GetValueOrDefault() - d.Qty);
}
else if (addList.Find(r => r.number ==d.ItemNumber && r.planmonth == $"{DateTime.Now.AddMonths(j - 1).Year}-{DateTime.Now.AddMonths(j - 1).Month.ToString("00")}") != null)
{
var avaItem = addList.Find(r => r.number == d.ItemNumber && r.planmonth == $"{DateTime.Now.AddMonths(j - 1).Year}-{DateTime.Now.AddMonths(j - 1).Month.ToString("00")}");
rop.avaStockQty = Math.Ceiling(avaItem.avaStockQty.GetValueOrDefault() + avaItem.montheop1.GetValueOrDefault() + avaItem.montheop2.GetValueOrDefault() - d.Qty);
}
else
{
//取实际库存
//1开始的库位为原料仓
rop.avaStockQty = locations.Where(a => a.ItemNum == rop.number && a.Location.StartsWith("1")).Sum(a => a.AvailStatusQty.GetValueOrDefault() + a.Assay.GetValueOrDefault());
}
rop.montheop1 = rop.rop_computed > rop.avaStockQty.GetValueOrDefault() ? rop.eop : 0;
rop.montheop2 = rop.security_stock > rop.avaStockQty.GetValueOrDefault() ? rop.eop : 0;
rop.ProdLine = "";
rop.ProdRange = "";
rop.Languages = "";
rop.tenant_id = input.tenant_id;
rop.company_id = input.company_id;
rop.factory_id = input.factory_id;
rop.create_time = DateTime.Now;
rop.org_id = input.org_id;
if (isExist)
{
updateList.Add(rop);
}
else
{
addList.Add(rop);
}
}
}
}
addList?.ForEach(item => { item.GenerateNewId(help.NextId()); });
await _businessDbContext.BulkInsertAsync(addList);
await _businessDbContext.BulkUpdateAsync(updateList);
return "OK";
}
private List CalcMonthPlanSubItem(List planList,List boms, List pretreatments)
{
List subItemRQ = new List();
planList?.ForEach(r =>
{
var planBOM = boms.Find(b => b.item_number == r.SAPItemNumber);
if (planBOM == null)
{
new NLogHelper("CalcROP").WriteLog("CalcROP", "CalcROP数据错误:" + r.SAPItemNumber + "不在BOM里", _currentTenant.Id.ToString());
}
else
{
var pretreament = pretreatments.Where(c => c.sourceid == planBOM.mysql_id).ToList();
var returnlist = ObjectMapper.Map, List>(pretreament);
returnlist = returnlist.OrderBy(s => s.num_order).ToList();
var level1Dto = returnlist[0];
level1Dto.needCount = r.Qty;
CaclMaterialShortage(returnlist);
foreach (var item in returnlist)
{
if(item.item_number!=r.SAPItemNumber)
{
var isExist = subItemRQ.Find(s => s.ItemNumber == item.item_number && s.PlanMonth == r.PlanMonth);
if (isExist != null)
{
isExist.Qty += item.needCount;
}
else
{
subItemRQ.Add(new ReplenishmentSubItemDto { ItemNumber = item.item_number, Qty = item.needCount, PlanMonth = r.PlanMonth });
}
}
}
}
});
return subItemRQ;
}
//计算原材料月均需求和方差
public void CalcSubItem(List subItemRQ, ReplenishmentROPWeekPlan rop, ReplenishmentDto replenishmentDto,string ItemNum)
{
int MonthCount = 0;
decimal SumOutQty = 0;
for (int k = -1 * replenishmentDto.HistoryOutStockMonth; k < replenishmentDto.SaleFcstMonth; k++)
{
string itemMonth = $"{DateTime.Now.AddMonths(k).Year}-{DateTime.Now.AddMonths(k).Month.ToString("00")}";
if (subItemRQ.Find(z => z.PlanMonth == itemMonth && z.ItemNumber == ItemNum) != null)
{
SumOutQty += subItemRQ.Find(z => z.PlanMonth == itemMonth && z.ItemNumber == ItemNum).Qty;
MonthCount++;
}
}
decimal avaRequire = 0;
rop.monthl_avg_demand = 0;
rop.monthl_avg_demand_variance = 0;
if (MonthCount>0)
{
avaRequire= Math.Ceiling(SumOutQty / MonthCount);
rop.monthl_avg_demand = avaRequire;
}
if (MonthCount> 1)
{
rop.monthl_avg_demand_variance = Math.Ceiling(Convert.ToDecimal(Math.Sqrt(subItemRQ.Where(w=>w.ItemNumber==ItemNum).Sum(x => Math.Pow(Convert.ToDouble(x.Qty) - Convert.ToDouble(avaRequire), 2)) / (MonthCount - 1))));
}
}
///
/// 平铺计算物料情况
///
///
///
///
public void CaclMaterialShortage(List returnlist)
{
foreach (var item in returnlist)
{
if (item.level == 1)
{
continue;
}
//循环平铺整个资源检查的物料库存情况、缺料情况,子集缺料需要用父级缺料*子集使用数量-
var parent = returnlist.Find(s => s.fid == item.parent_id);
//当前物料总共需要数量
item.needCount = Math.Ceiling(parent.needCount * item.qty * (1 + (item.scrap.GetValueOrDefault() / 100)) + item.wastage.GetValueOrDefault());
item.needCountNoloss = parent.needCount * item.qty;
}
}
///
/// 根据月度计划生成周计划
///
///
///
public async Task CalcWeekPlan(InputDto input)
{
//1.获取补货模型全局参数
ReplenishmentDto replenishmentDto = GetROPParam(input.factory_id.ToString());
//发货计划列表,用于判断成品物料编码
//获取补货模型前H周期和未来F个周期的数据
List planMonthList = new List();
for (int j = -replenishmentDto.HistoryOutStockMonth; j < replenishmentDto.SaleFcstMonth + 1; j++)
{
string itemMonth = $"{DateTime.Now.AddMonths(j).Year}-{DateTime.Now.AddMonths(j).Month.ToString("00")}";
planMonthList.Add(itemMonth);
}
var shipPlanList = new List();
foreach (var itemMonth in planMonthList)
{
var annualProductionMonth = _monthlyShipmentPlan.Select(x => itemMonth == x.PlanMonth && !x.IsDeleted && x.factory_id == input.factory_id).OrderBy(p => p.PlanMonth).ThenBy(o => o.OrderNum).ToList();
if (annualProductionMonth != null && annualProductionMonth.Count > 0)
{
shipPlanList.AddRange(annualProductionMonth);
}
else
{
var MaxVersion = _monthlyShipmentPlanHistory.Select(a => a.factory_id == input.factory_id && !a.IsDeleted).Max(b => b.VERSION);
if (!string.IsNullOrEmpty(MaxVersion))
{
var annualProductionMonthHistory = _monthlyShipmentPlanHistory.Select(x => itemMonth == x.PlanMonth && x.VERSION == MaxVersion && !x.IsDeleted && x.factory_id == input.factory_id).OrderByDescending(v => v.VERSION).ThenBy(p => p.PlanMonth).ThenBy(o => o.OrderNum).ToList();
if (annualProductionMonthHistory != null && annualProductionMonthHistory.Count > 0)
{
var returnlist = ObjectMapper.Map, List>(annualProductionMonthHistory);
shipPlanList.AddRange(returnlist);
}
}
}
}
shipPlanList = shipPlanList.OrderBy(p => p.PlanMonth).ThenBy(o => o.OrderNum).ToList();
//滚动三个月12周的周计划,已经发布的周计划不改(TODO:删除未来未发布的周计划和工单(是否影响资源检查))
//最小经济批量
var weekPlanDelete = _replenishmentWeekPlan.GetListAsync(a => planMonthList.Contains(a.PlanMonth) && a.ProductionStatus != "已发布" && a.IsReplenishmentModel == "N" && a.factory_id == input.factory_id).Result;
var workOrderDelete = weekPlanDelete.Select(b => b.ProductionOrder).ToList();
_workOrdMaster.Delete(a => workOrderDelete.Contains(a.WorkOrd) && a.Domain == input.factory_id.ToString());
_workOrdRouting.Delete(a => workOrderDelete.Contains(a.WorkOrd) && a.Domain == input.factory_id.ToString());
_workOrdDetail.Delete(a => workOrderDelete.Contains(a.WorkOrd) && a.Domain == input.factory_id.ToString());
var deletedOrderList = _mysql_mes_morder.GetListAsync(a => workOrderDelete.Contains(a.morder_no) && a.factory_id == input.factory_id).Result;
var deletedIds = deletedOrderList.Select(a => a.Id).ToList();
await _mysql_mes_morder.HardDeleteAsync(deletedOrderList);
var deletedEntryList = _mysql_mes_moentry.GetListAsync(a => workOrderDelete.Contains(a.moentry_mono) && a.factory_id == input.factory_id).Result;
await _mysql_mes_moentry.HardDeleteAsync(deletedEntryList);
var examine_result = _mysql_examine_result.GetListAsync(a => workOrderDelete.Contains(a.morder_no) && a.factory_id == input.factory_id).Result;
List occupy = await _mysql_srm_po_occupy.GetListAsync(s => workOrderDelete.Contains(s.morder_mo));
_businessDbContext.BulkDelete(occupy);
//清理工单占用
List mooccupy = await _mysql_mes_mooccupy.GetListAsync(s => deletedIds.Contains(s.moo_id.GetValueOrDefault()));
if (mooccupy.Any())
{
_businessDbContext.BulkDelete(mooccupy);
}
//清理掉库存占用
var itemstockoccupy = _mysql_ic_item_stockoccupy.GetListAsync(s => workOrderDelete.Contains(s.morder_mo)).Result;
if (itemstockoccupy.Any())
{
_businessDbContext.BulkDelete(itemstockoccupy);
}
await _mysql_bom_child_examine.HardDeleteAsync(a => examine_result.Select(b => b.Id).ToList().Contains(a.examine_id.Value) && a.factory_id == input.factory_id);
await _mysql_examine_result.HardDeleteAsync(examine_result);
await _replenishmentWeekPlan.HardDeleteAsync(weekPlanDelete);
//月度补货模型
var planList = _replenishmentROPWeekPlan.GetListAsync(a => planMonthList.Contains(a.planmonth) && !a.IsDeleted && a.factory_id == input.factory_id).Result;
//周补货计划
var weekPlanList = _replenishmentWeekPlan.GetListAsync(a => planMonthList.Contains(a.PlanMonth) && !a.IsDeleted && a.factory_id == input.factory_id && a.IsReplenishmentModel == "Y").Result;
//周生产计划
var weekProductPlanList = _replenishmentWeekPlan.GetListAsync(a => planMonthList.Contains(a.PlanMonth) && !a.IsDeleted && a.factory_id == input.factory_id && a.IsReplenishmentModel == "N").Result;
//发货计划物料列表
List planItemList = shipPlanList?.Select(a => a.SAPItemNumber).Distinct().ToList();
var itemList = _mysql_ic_item.GetListAsync(a => planItemList.Contains(a.number) && !a.IsDeleted).Result;
var bomList = _mysql_ic_bom.GetListAsync(a => planItemList.Contains(a.item_number) && !a.IsDeleted && a.factory_id == input.factory_id).Result;
var monthPlan = _productionMasterPlan.GetListAsync(a => planItemList.Contains(a.ItemNumber) && !a.IsDeleted && a.factory_id == input.factory_id).Result;
long bang_id = help.NextId();
//获取BOM用于分解到原材料
var boms = _ic_bom.GetListAsync(a => planItemList.Contains(a.item_number) && a.factory_id == input.factory_id).Result;
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(input.company_id.ToString(), autoCreates);
pretreatments = _mysql_b_bom_pretreatment.GetListAsync(s => boms.Select(c => c.mysql_id).ToList().Contains(s.sourceid)).Result;
}
routingOps = _routingOpDetail.Select(p => p.Domain ==input.factory_id.ToString()).ToList();
//更新周补货计划
List updateRopList = new List();
List addRopList = new List();
//生成12周补货计划
for (int k = 0; k < 12; k++)
{
var weekPlanTime = GetNextMonday();
weekPlanTime = weekPlanTime.AddDays(7 * k);
string kMonth = $"{weekPlanTime.Year}-{weekPlanTime.Month.ToString("00")}";
//如果该10月有发布的2周生产计划,则周补货量=10月补货量-已发布的2周生产计划数量/剩余周次(2)
//周补货计划只计算成品,不需要到原材料
var monthWeekPlan = planList.Where(a => a.planmonth == kMonth && planItemList.Contains(a.number)).ToList();
foreach (var item in monthWeekPlan)
{
int publishedWeekCount = weekProductPlanList.Where(a => a.PlanMonth == kMonth && a.ItemNumber == item.number && a.ProductionStatus == "已发布" && a.DistributionChannel == item.distributionchannel).Count();
decimal publishedWeekQtySum = weekProductPlanList.Where(a => a.PlanMonth == kMonth && a.ItemNumber == item.number && a.ProductionStatus == "已发布" && a.DistributionChannel == item.distributionchannel).Sum(a => a.Qty);
var weekItemPlan = weekPlanList.Find(a => a.PlanMonth == kMonth && a.ItemNumber == item.number && a.WeekSeq == WeekOfMonth(weekPlanTime, 1) && a.DistributionChannel == item.distributionchannel);
if(publishedWeekCount<4)
{
if(weekItemPlan!=null)
{
weekItemPlan.Qty = Math.Ceiling((item.montheop1.GetValueOrDefault() + item.montheop2.GetValueOrDefault() - publishedWeekQtySum) / (4 - publishedWeekCount));
updateRopList.Add(weekItemPlan);
}else
{
ReplenishmentWeekPlan weekItemPlanAdd = new ReplenishmentWeekPlan();
weekItemPlanAdd.Area = item.area;
weekItemPlanAdd.Week = $"WK{GetWeekOfYear(weekPlanTime).ToString("00")}";
weekItemPlanAdd.DistributionChannel = item.distributionchannel;
weekItemPlanAdd.ProdLine = item.ProdLine;
weekItemPlanAdd.ProdRange = item.ProdRange;
weekItemPlanAdd.Model = item.model;
weekItemPlanAdd.ItemNumber = item.number;
weekItemPlanAdd.Languages = item.Languages;
weekItemPlanAdd.Qty = Math.Ceiling((item.montheop1.GetValueOrDefault() + item.montheop2.GetValueOrDefault() - publishedWeekQtySum) / (4 - publishedWeekCount));
weekItemPlanAdd.Year = weekPlanTime.Year;
weekItemPlanAdd.Month = weekPlanTime.Month;
weekItemPlanAdd.PlanMonth = $"{weekPlanTime.Year}-{weekPlanTime.Month.ToString("00")}"; ;
weekItemPlanAdd.WeekSeq = WeekOfMonth(weekPlanTime, 1);
weekItemPlanAdd.tenant_id = input.tenant_id;
weekItemPlanAdd.company_id = input.company_id;
weekItemPlanAdd.factory_id = input.factory_id;
weekItemPlanAdd.create_time = DateTime.Now;
weekItemPlanAdd.org_id = input.org_id;
weekItemPlanAdd.ItemStatus = "";
weekItemPlanAdd.IsReplenishmentModel = "Y";
addRopList.Add(weekItemPlanAdd);
}
}
}
}
await _businessDbContext.BulkInsertAsync(addRopList);
await _businessDbContext.BulkUpdateAsync(updateRopList);
//更新周生产计划
//生产线明细表
List prodLines = new List();
List lineMasters = new List