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