|
|
@@ -775,7 +775,7 @@ namespace Business.Replenishment
|
|
|
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 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(-6) && 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);
|
|
|
@@ -1035,11 +1035,160 @@ namespace Business.Replenishment
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
+ /// 每天补货
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="input"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<string> CalcDayPlan(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<string> planItemList = planList?.Select(a => a.SAPItemNumber).ToList();
|
|
|
+ //获取成品库存、灭菌库存、在制库存(会从SAP同步的库存表更新到LocationDetail、ic_item表中)
|
|
|
+ //List<SAPInv> 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<ReplenishmentROP> addList = new List<ReplenishmentROP>();
|
|
|
+ List<ReplenishmentROP> updateList = new List<ReplenishmentROP>();//更新上一个月的实际出库数量
|
|
|
+ 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";
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
/// 计划工单齐套检查
|
|
|
/// </summary>
|
|
|
/// <param name="input"></param>
|
|
|
/// <returns></returns>
|
|
|
- public async Task<string> PlanOrderResourceCheck(List<mes_morder> Mes_Morders,InputDto input)
|
|
|
+ public async Task<string> PlanOrderResourceCheck(List<mes_morder> Mes_Morders, List<mes_moentry> moentryList, InputDto input)
|
|
|
{
|
|
|
//先排除锁定期内的工单 //优先级排序
|
|
|
var sysSet = _generalizedCodeMaster.Select(s => s.FldName == "SystemConfig" && s.Val == "WorkOrderLockPeriod" && s.Domain == input.company_id.ToString()).ToList();
|
|
|
@@ -1111,7 +1260,7 @@ namespace Business.Replenishment
|
|
|
_scheduleResultOpMaster.Delete(s => monolist.Contains(s.WorkOrd));
|
|
|
}
|
|
|
//只走计划工单
|
|
|
- var rtn = await OrderKittingCheck(Mes_Morders, true);
|
|
|
+ var rtn = await OrderKittingCheck(Mes_Morders, moentryList, true);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
@@ -1161,7 +1310,7 @@ namespace Business.Replenishment
|
|
|
/// 工单检查物料齐套
|
|
|
/// </summary>
|
|
|
/// <param name="input"></param>
|
|
|
- public async Task<PschedDto> OrderKittingCheck(List<mes_morder> mo_Mes_Morders, bool planCheck = false)
|
|
|
+ public async Task<PschedDto> OrderKittingCheck(List<mes_morder> mo_Mes_Morders, List<mes_moentry> moentryList, bool planCheck = false)
|
|
|
{
|
|
|
//资源检查结果
|
|
|
PschedDto rtn = new PschedDto();
|
|
|
@@ -1189,8 +1338,8 @@ namespace Business.Replenishment
|
|
|
|
|
|
var morderIdList = mo_Mes_Morders.Select(s => s.Id).ToList();
|
|
|
|
|
|
- List<mes_moentry> mo_Mes_Moentries = _mysql_mes_moentry.GetListAsync(x => morderIdList.Contains(x.moentry_moid.Value)).Result;
|
|
|
-
|
|
|
+ //List<mes_moentry> mo_Mes_Moentries = _mysql_mes_moentry.GetListAsync(x => morderIdList.Contains(x.moentry_moid.Value)).Result;
|
|
|
+ List<mes_moentry> mo_Mes_Moentries = moentryList;
|
|
|
//获取订单行数据
|
|
|
List<crm_seorderentry> 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;
|
|
|
|
|
|
@@ -1699,6 +1848,15 @@ namespace Business.Replenishment
|
|
|
moSrm_po_occupy.ForEach(item => { item.GenerateNewId(help.NextId()); item.bang_id = bangid; });
|
|
|
await _srm_po_occupy.InsertManyAsync(moSrm_po_occupy);
|
|
|
}
|
|
|
+
|
|
|
+ //pr
|
|
|
+ var srm_pr_main = _mysql_srm_pr_main.GetListAsync(x => x.company_id == companyId && x.factory_id == factoryId && itemIds.Contains(x.icitem_id.GetValueOrDefault())).Result;
|
|
|
+ if (srm_pr_main.Count > 0)
|
|
|
+ {
|
|
|
+ var moSrm_pr_main = ObjectMapper.Map<List<srm_pr_main>, List<mo_srm_pr_main>>(srm_pr_main);
|
|
|
+ moSrm_pr_main.ForEach(item => { item.GenerateNewId(help.NextId()); item.bang_id = bangid; });
|
|
|
+ await _srm_pr_main.InsertManyAsync(moSrm_pr_main);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -1727,6 +1885,9 @@ namespace Business.Replenishment
|
|
|
|
|
|
//清除采购订单占用详情
|
|
|
//await _srm_po_occupy.DeleteAsync(p => p.bang_id == bangid);
|
|
|
+
|
|
|
+ //清除PR
|
|
|
+ await _srm_pr_main.DeleteAsync(p => p.bang_id == bangid);
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1778,6 +1939,7 @@ namespace Business.Replenishment
|
|
|
var poDetailList = _srm_po_list.GetListAsync(x => icitemlist.Select(p => p.mysql_id).ToList().Contains(x.icitem_id.Value) && x.bang_id == bangid && x.state == 1 && x.rstate == 1 && !x.IsDeleted).Result;
|
|
|
//采购订单占用数据
|
|
|
var poOccupys = _srm_po_occupy.GetListAsync(x => poDetailList.Select(p => p.Id).ToList().Contains(x.polist_id) && x.bang_id == bangid && !x.IsDeleted).Result;
|
|
|
+ var srm_pr_mains = _srm_pr_main.GetListAsync(x => icitemlist.Select(p => p.mysql_id).ToList().Contains(x.icitem_id.Value) && x.bang_id == bangid && x.state == 0 && !x.IsDeleted).Result;
|
|
|
#endregion
|
|
|
|
|
|
//处理一下已经插入得占用记录
|
|
|
@@ -1808,6 +1970,7 @@ namespace Business.Replenishment
|
|
|
_CalcBomViewAppService.srm_Po_Lists = poDetailList; //采购明细
|
|
|
_CalcBomViewAppService.srm_Po_Occupies = poOccupys; //采购占用表
|
|
|
_CalcBomViewAppService.ic_item_List = icitemlist; //物料表
|
|
|
+ _CalcBomViewAppService.srm_Pr_Mains = srm_pr_mains;//PR
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2015,10 +2178,9 @@ namespace Business.Replenishment
|
|
|
/// <returns></returns>
|
|
|
public async Task<string> CalcLongPeriodItemPR(InputDto input)
|
|
|
{
|
|
|
- //取年份最大的数据
|
|
|
- int yearMax=DateTime.Now.Year;
|
|
|
- yearMax=_businessDbContext.ReplenishmentAnnualProduction.Where(m => m.factory_id ==input.factory_id && !m.IsDeleted).Max(m => (int?)m.Year).GetValueOrDefault();
|
|
|
- var productList = _replenishmentAnnualProduction.GetListAsync(a => a.Year == yearMax && !a.IsDeleted && a.factory_id == input.factory_id).Result.OrderBy(s=>s.OrderNum).ToList();
|
|
|
+ //获取未来六个月数据
|
|
|
+ var monthlist = GetSixPlanMonth();
|
|
|
+ var productList = _replenishmentAnnualProduction.GetListAsync(a => monthlist.Contains(a.PlanMonth) && !a.IsDeleted && a.factory_id == input.factory_id).Result.OrderBy(s=>s.OrderNum).ToList();
|
|
|
var itemList= productList.Select(a=>a.SAPItemNumber).ToList();
|
|
|
var planList=_mysql_ic_item.GetListAsync(a=>itemList.Contains(a.number) && a.factory_id==input.factory_id && !a.IsDeleted).Result.ToList();
|
|
|
var mesItem=_itemMaster.Select(a => itemList.Contains(a.ItemNum) &&a.IsActive && a.Domain==input.factory_id.ToString());
|
|
|
@@ -2082,7 +2244,7 @@ namespace Business.Replenishment
|
|
|
}
|
|
|
await _mysql_mes_morder.InsertManyAsync(moList);
|
|
|
await _mysql_mes_moentry.InsertManyAsync(moentryList);
|
|
|
- await PlanOrderResourceCheck(moList,input);
|
|
|
+ await PlanOrderResourceCheck(moList,moentryList,input);
|
|
|
return "OK";
|
|
|
}
|
|
|
|
|
|
@@ -2513,5 +2675,16 @@ namespace Business.Replenishment
|
|
|
{
|
|
|
return getPreMonthEndTime().AddMonths(months + 1);
|
|
|
}
|
|
|
+
|
|
|
+ public List<string> GetSixPlanMonth()
|
|
|
+ {
|
|
|
+ List<string> result=new List<string>();
|
|
|
+ for(int i=0;i<6;i++)
|
|
|
+ {
|
|
|
+ var months = DateTime.Now.AddMonths(i + 1);
|
|
|
+ result.Add($"{months.Year}-{months.Month}");
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
}
|
|
|
}
|