|
|
@@ -7,6 +7,7 @@ using Business.EntityFrameworkCore;
|
|
|
using Business.EntityFrameworkCore.SqlRepositories;
|
|
|
using Business.PriorityManagement;
|
|
|
using Business.ResourceExamineManagement.Dto;
|
|
|
+using Business.StructuredDB.SaleFcst;
|
|
|
using Business.StructuredDB.WMS;
|
|
|
using EFCore.BulkExtensions;
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
@@ -145,18 +146,33 @@ namespace Business.ResourceExamineManagement
|
|
|
private IRepository<b_purchase_occupy, long> _mysql_purchase_occupy;
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 替代群组
|
|
|
+ /// 替代方案
|
|
|
/// </summary>
|
|
|
private readonly IRepository<mo_ic_substitute,long> _ic_substitute;
|
|
|
/// <summary>
|
|
|
- /// 替代群组
|
|
|
+ /// 替代方案群组
|
|
|
/// </summary>
|
|
|
private readonly IRepository<mo_ic_substitute_group,long> _ic_substitute_group;
|
|
|
/// <summary>
|
|
|
- /// 替代群组
|
|
|
+ /// 替代明细
|
|
|
/// </summary>
|
|
|
private readonly IRepository<mo_ic_substitute_group_detail,long> _ic_substitute_group_detail;
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 替代方案
|
|
|
+ /// </summary>
|
|
|
+ private readonly IRepository<ic_substitute, long> _mysql_ic_substitute;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 替代方案群组
|
|
|
+ /// </summary>
|
|
|
+ private readonly IRepository<ic_substitute_group, long> _mysql_ic_substitute_group;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 替代明细
|
|
|
+ /// </summary>
|
|
|
+ private readonly IRepository<ic_substitute_group_detail, long> _mysql_ic_substitute_group_detail;
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// 生产工单主表
|
|
|
/// </summary>
|
|
|
@@ -347,6 +363,18 @@ namespace Business.ResourceExamineManagement
|
|
|
/// </summary>
|
|
|
public List<HolidayMaster> holidays = new List<HolidayMaster>();
|
|
|
private readonly IUnitOfWorkManager _unitOfWorkManager;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 补货模型
|
|
|
+ /// </summary>
|
|
|
+ private IRepository<ReplenishmentModel, long> _replenishmentModel;
|
|
|
+ private IRepository<DomesticTerminalFcst, long> _domesticTerminalFcst;
|
|
|
+ private ISqlRepository<ASNBOLShipperDetail> _ASNBOLShipperDetail;
|
|
|
+ private IRepository<StandardItemModelSet, long> _standardItemModelSet;
|
|
|
+ private ISqlRepository<InvTransHist> _invTransHist;
|
|
|
+ private ISqlRepository<SAPInv> _SAPInv;
|
|
|
+ private IRepository<srm_purchase, long> _srmPurchase;
|
|
|
+ private ISqlRepository<MonthlyShipmentPlan> _monthlyShipmentPlan;
|
|
|
#endregion
|
|
|
|
|
|
#region 构造函数
|
|
|
@@ -440,6 +468,17 @@ namespace Business.ResourceExamineManagement
|
|
|
ISqlRepository<ItemPackMaster> itemPackMaster,
|
|
|
ISqlRepository<GeneralizedCodeMaster> generalizedCodeMaster,
|
|
|
ISqlRepository<ScheduleResultOpMaster> scheduleResultOpMaster,
|
|
|
+ IRepository<ic_substitute, long> mysql_ic_substitute,
|
|
|
+ IRepository<ic_substitute_group, long> mysql_ic_substitute_group,
|
|
|
+ IRepository<ic_substitute_group_detail, long> mysql_ic_substitute_group_detail,
|
|
|
+ IRepository<ReplenishmentModel, long> replenishmentModel,
|
|
|
+ IRepository<DomesticTerminalFcst, long> domesticTerminalFcst,
|
|
|
+ ISqlRepository<ASNBOLShipperDetail> ASNBOLShipperDetail,
|
|
|
+ IRepository<StandardItemModelSet, long> standardItemModelSet,
|
|
|
+ ISqlRepository<InvTransHist> invTransHist,
|
|
|
+ ISqlRepository<SAPInv> SAPInv,
|
|
|
+ ISqlRepository<MonthlyShipmentPlan> monthlyShipmentPlan,
|
|
|
+ IRepository<srm_purchase, long> srmPurchase,
|
|
|
IUnitOfWorkManager unitOfWorkManager
|
|
|
)
|
|
|
{
|
|
|
@@ -460,6 +499,9 @@ namespace Business.ResourceExamineManagement
|
|
|
_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;
|
|
|
_mes_morder = mes_morder;
|
|
|
_mes_moentry = mes_moentry;
|
|
|
_mes_mooccupy = mes_mooccupy;
|
|
|
@@ -525,6 +567,14 @@ namespace Business.ResourceExamineManagement
|
|
|
_generalizedCodeMaster = generalizedCodeMaster;
|
|
|
_unitOfWorkManager = unitOfWorkManager;
|
|
|
_scheduleResultOpMaster = scheduleResultOpMaster;
|
|
|
+ _replenishmentModel = replenishmentModel;
|
|
|
+ _domesticTerminalFcst = domesticTerminalFcst;
|
|
|
+ _standardItemModelSet = standardItemModelSet;
|
|
|
+ _invTransHist = invTransHist;
|
|
|
+ _SAPInv = SAPInv;
|
|
|
+ _monthlyShipmentPlan = monthlyShipmentPlan;
|
|
|
+ _srmPurchase = srmPurchase;
|
|
|
+ _businessDbContext = businessDbContext;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
@@ -961,24 +1011,24 @@ namespace Business.ResourceExamineManagement
|
|
|
//物料、供应商为相同才允许合并。
|
|
|
var idList = AnalysisIdList(ids);
|
|
|
List<srm_pr_main> prlist = _mysql_srm_pr_main.GetListAsync(s => idList.Contains(s.Id)).Result;
|
|
|
- if (prlist.Where(s => s.state == 0).Count() > 0)
|
|
|
- {
|
|
|
- return JsonConvert.SerializeObject("所选包含已关闭采购申请,请重新选择。");
|
|
|
- }
|
|
|
- if (prlist.Where(s => s.state == 2).Count() > 0)
|
|
|
- {
|
|
|
- return JsonConvert.SerializeObject("所选包含已提交评审采购申请,请重新选择。");
|
|
|
- }
|
|
|
- if (prlist.Where(s => s.state == 4).Count() > 0)
|
|
|
- {
|
|
|
- return JsonConvert.SerializeObject("所选包含已评审通过采购申请,请重新选择。");
|
|
|
- }
|
|
|
if (prlist.Any())
|
|
|
{
|
|
|
- var list = prlist.GroupBy(s => new { s.icitem_id, s.pr_purchaseid });
|
|
|
+ if (prlist.Where(s => s.state == 0).Count() > 0)
|
|
|
+ {
|
|
|
+ return JsonConvert.SerializeObject("所选包含已关闭采购申请,请重新选择。");
|
|
|
+ }
|
|
|
+ if (prlist.Where(s => s.state == 2).Count() > 0)
|
|
|
+ {
|
|
|
+ return JsonConvert.SerializeObject("所选包含已提交评审采购申请,请重新选择。");
|
|
|
+ }
|
|
|
+ if (prlist.Where(s => s.state == 4).Count() > 0)
|
|
|
+ {
|
|
|
+ return JsonConvert.SerializeObject("所选包含已评审通过采购申请,请重新选择。");
|
|
|
+ }
|
|
|
+ var list = prlist.GroupBy(s => new { s.icitem_id, s.pr_purchaseid, s.IsRequireGoods });
|
|
|
if (list.Count() > 1)
|
|
|
{
|
|
|
- return JsonConvert.SerializeObject("所选行的物料编码,供应商名称必须相同");
|
|
|
+ return JsonConvert.SerializeObject("所选行的物料编码、供应商名称、采购类型必须相同");
|
|
|
}
|
|
|
}
|
|
|
else {
|
|
|
@@ -1007,8 +1057,8 @@ namespace Business.ResourceExamineManagement
|
|
|
srm_Pr.pr_psend_date = prlist.Min(s => s.pr_psend_date);//计划下单日期
|
|
|
srm_Pr.pr_parrive_date = prlist.Min(s => s.pr_parrive_date);//计划到达日期
|
|
|
srm_Pr.pr_rarrive_date = prlist.Min(s => s.pr_rarrive_date);//需求到货日期
|
|
|
- srm_Pr.pr_sysprice = prlist.Sum(s => s.pr_rqty) * prlist[0].pr_price * (1 + prlist[0].pr_rate);//系统价格(含税)
|
|
|
- srm_Pr.pr_orderprice = prlist.Sum(s => s.pr_rqty) * prlist[0].pr_price * (1 + prlist[0].pr_rate);//订单价格(含税)
|
|
|
+ //srm_Pr.pr_sysprice = prlist.Sum(s => s.pr_rqty) * prlist[0].pr_price * (1 + prlist[0].pr_rate);//系统价格(含税)
|
|
|
+ srm_Pr.pr_orderprice = prlist.Sum(s => s.pr_aqty) * prlist[0].pr_sysprice;//订单价格(含税)
|
|
|
/*srm_Pr.icitem_id = returnlist.item_id;//物料id
|
|
|
srm_Pr.icitem_name = returnlist.item_name;//物料名称
|
|
|
srm_Pr.pr_order_type = 1;//单据类型
|
|
|
@@ -1062,15 +1112,15 @@ namespace Business.ResourceExamineManagement
|
|
|
var moPrlist = ObjectMapper.Map<List<srm_pr_main>, List<mo_srm_pr_main>>(prlist);
|
|
|
foreach (var pr in prlist)
|
|
|
{
|
|
|
- bool bl = pr.sentry_id == null;
|
|
|
- //找到是否生成了新的PR
|
|
|
- //var newPr = insetPrList.Find(s => s.pr_purchaseid == pr.pr_purchaseid && s.icitem_id == pr.icitem_id && (s.sentry_id == null) == bl);
|
|
|
- var newPr = insetPrList.Find(s => s.pr_purchaseid == pr.pr_purchaseid && s.icitem_id == pr.icitem_id);
|
|
|
+ bool bl = pr.sentry_id == null;//区分是销售订单和非销售订单的合并。
|
|
|
+ //找到是否生成了新的PR 当前数据是否已经产生合并,则不再合并。
|
|
|
+ var newPr = insetPrList.Find(s => s.pr_purchaseid == pr.pr_purchaseid && s.icitem_id == pr.icitem_id && s.IsRequireGoods == pr.IsRequireGoods && (s.sentry_id == null) == bl);
|
|
|
+ //var newPr = insetPrList.Find(s => s.pr_purchaseid == pr.pr_purchaseid && s.icitem_id == pr.icitem_id);
|
|
|
if (newPr == null)
|
|
|
{
|
|
|
//有多条才进行合并
|
|
|
- //var ilist = prlist.Where(s => s.pr_purchaseid == pr.pr_purchaseid && s.icitem_id == pr.icitem_id && (s.sentry_id == null) == bl).ToList();
|
|
|
- var ilist = prlist.Where(s => s.pr_purchaseid == pr.pr_purchaseid && s.icitem_id == pr.icitem_id).ToList();
|
|
|
+ var ilist = prlist.Where(s => s.pr_purchaseid == pr.pr_purchaseid && s.icitem_id == pr.icitem_id && s.IsRequireGoods == pr.IsRequireGoods && (s.sentry_id == null) == bl).ToList();
|
|
|
+ //var ilist = prlist.Where(s => s.pr_purchaseid == pr.pr_purchaseid && s.icitem_id == pr.icitem_id).ToList();
|
|
|
if (ilist.Count > 1)
|
|
|
{
|
|
|
var icitem = ic_Items.Find(s => s.Id == pr.icitem_id);
|
|
|
@@ -1095,8 +1145,8 @@ namespace Business.ResourceExamineManagement
|
|
|
newPr.pr_sarrive_date = newPr.pr_rarrive_date;//系统建议到达日期(建议到货日期)
|
|
|
newPr.pr_parrive_date = newPr.pr_rarrive_date;//计划到达日期
|
|
|
|
|
|
- newPr.pr_sysprice = newPr.pr_rqty * pr.pr_price * (1 + pr.pr_rate);//系统价格(含税)
|
|
|
- newPr.pr_orderprice = newPr.pr_rqty * pr.pr_price * (1 + pr.pr_rate);//订单价格(含税)
|
|
|
+ //newPr.pr_sysprice = newPr.pr_rqty * pr.pr_price * (1 + pr.pr_rate);//系统价格(含税)
|
|
|
+ newPr.pr_orderprice = newPr.pr_aqty * pr.pr_sysprice;//订单价格(含税)
|
|
|
ilist.ForEach(s => { s.refer_pr_billno = newPr.pr_billno; });
|
|
|
insetPrList.Add(newPr);
|
|
|
ilist.ForEach(s => { s.state = 0; });
|
|
|
@@ -1257,7 +1307,8 @@ namespace Business.ResourceExamineManagement
|
|
|
DateTime toTime = new DateTime(2023, 7, 6);
|
|
|
DateTime starttime = toTime.AddDays(1);
|
|
|
DateTime endtime = toTime.AddDays(8);
|
|
|
- List<srm_pr_main> prlist = _mysql_srm_pr_main.GetListAsync(s => s.company_id.ToString() == companyid && s.pr_rarrive_date >= starttime && s.pr_rarrive_date <= endtime && (s.state == 1|| s.state == 2 || s.state == 3)).Result;
|
|
|
+ List<srm_pr_main> prlist = _mysql_srm_pr_main.GetListAsync(s => s.company_id.ToString() == companyid && s.IsRequireGoods == 0 && s.pr_rarrive_date >= starttime &&
|
|
|
+ s.pr_rarrive_date <= endtime && (s.state == 1|| s.state == 2 || s.state == 3)).Result;
|
|
|
|
|
|
if (prlist.Any())
|
|
|
{
|
|
|
@@ -1279,7 +1330,7 @@ namespace Business.ResourceExamineManagement
|
|
|
}
|
|
|
if (poaction.polist.Any())
|
|
|
{
|
|
|
- _businessDbContext.BulkInsert(poaction.polist);
|
|
|
+ _businessDbContext.BulkInsert(poaction.polist);
|
|
|
}
|
|
|
if (poaction.poOccupiesList.Any())
|
|
|
{
|
|
|
@@ -1288,6 +1339,7 @@ namespace Business.ResourceExamineManagement
|
|
|
|
|
|
if (poaction.poMasterList.Any())
|
|
|
{
|
|
|
+ poaction.poMasterList.ForEach(s => { s.ReqBy = "DO"; });
|
|
|
_purOrdMaster.Insert(poaction.poMasterList);
|
|
|
//快开平台用自增列RecId关联,所以需要插入后再查给明细表赋相应的值
|
|
|
List<string> nbrs = poaction.poMasterList.Select(a => a.PurOrd).ToList();
|
|
|
@@ -1303,15 +1355,15 @@ namespace Business.ResourceExamineManagement
|
|
|
catch (Exception e)
|
|
|
{
|
|
|
unitOfWork.Dispose();
|
|
|
- new NLogHelper("ResourceExamineAppService").WriteLog("PrApprove", "采购申请单合并失败:" + e.Message, _currentTenant.Id.ToString());
|
|
|
- return JsonConvert.SerializeObject("合并失败,请联系管理员。");
|
|
|
+ new NLogHelper("ResourceExamineAppService").WriteLog("PrAutoApprove", "要货令转采购订单失败:" + e.Message, _currentTenant.Id.ToString());
|
|
|
+ return JsonConvert.SerializeObject("要货令转采购订单失败,请联系管理员。");
|
|
|
}
|
|
|
}
|
|
|
return JsonConvert.SerializeObject("ok");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- return JsonConvert.SerializeObject("没有需要审核的采购申请单。");
|
|
|
+ return JsonConvert.SerializeObject("没有需要审核的要货令。");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1322,27 +1374,30 @@ namespace Business.ResourceExamineManagement
|
|
|
/// <returns></returns>
|
|
|
public async Task<string> PrApprove(string ids)
|
|
|
{
|
|
|
- //物料、供应商为相同才允许合并。
|
|
|
var idList = AnalysisIdList(ids);
|
|
|
List<srm_pr_main> prlist = _mysql_srm_pr_main.GetListAsync(s => idList.Contains(s.Id)).Result;
|
|
|
if (!prlist.Any())
|
|
|
{
|
|
|
- return JsonConvert.SerializeObject("所选采购申请单未找到,请刷新界面重新操作。");
|
|
|
+ return JsonConvert.SerializeObject("所选要货令未找到,请刷新界面重新操作。");
|
|
|
}
|
|
|
if (prlist.Where(s => s.state == 0).Count() > 0)
|
|
|
{
|
|
|
- return JsonConvert.SerializeObject("所选包含已关闭采购申请,请重新选择。");
|
|
|
+ return JsonConvert.SerializeObject("所选包含已关闭要货令,请重新选择。");
|
|
|
}
|
|
|
if (prlist.Where(s => s.state == 3).Count() > 0)
|
|
|
{
|
|
|
- return JsonConvert.SerializeObject("所选包含评审未通过采购申请,请重新选择。");
|
|
|
+ return JsonConvert.SerializeObject("所选包含评审未通过要货令,请重新选择。");
|
|
|
+ }
|
|
|
+ if (prlist.Where(s => s.IsRequireGoods == 0).Count() > 0)
|
|
|
+ {
|
|
|
+ return JsonConvert.SerializeObject("包含采购申请,不允许与要货令转采购订单。");
|
|
|
}
|
|
|
List<srm_purchase> purchaselist = _mysql_srm_purchase.GetListAsync(s => prlist.Select(c => c.icitem_id).Contains(s.icitem_id) && prlist.Select(c => c.pr_purchaseid).Contains(s.supplier_id)).Result;
|
|
|
List<srm_supplier> itemsupplierList = _mysql_srm_supplier.GetListAsync(s => prlist.Select(c => c.pr_purchaseid).Contains(s.Id)).Result;
|
|
|
var purclist = purchaselist.GroupBy(s => new { s.supplier_type, s.supplier_id });
|
|
|
if (purclist.Count() > 1)
|
|
|
{
|
|
|
- return JsonConvert.SerializeObject("采购申请单的采购类别必须相同。");
|
|
|
+ return JsonConvert.SerializeObject("要货令的供应类别必须相同。");
|
|
|
}
|
|
|
List<ic_item> ic_Items = _mysql_ic_item.GetListAsync(s => prlist.Select(c => c.icitem_id).Contains(s.Id)).Result;
|
|
|
PoActionListDto poaction = new PoActionListDto();
|
|
|
@@ -1369,6 +1424,7 @@ namespace Business.ResourceExamineManagement
|
|
|
|
|
|
if (poaction.poMasterList.Any())
|
|
|
{
|
|
|
+ poaction.poMasterList.ForEach(s => { s.ReqBy = "DO"; });
|
|
|
_purOrdMaster.Insert(poaction.poMasterList);
|
|
|
//快开平台用自增列RecId关联,所以需要插入后再查给明细表赋相应的值
|
|
|
List<string> nbrs = poaction.poMasterList.Select(a => a.PurOrd).ToList();
|
|
|
@@ -1384,8 +1440,8 @@ namespace Business.ResourceExamineManagement
|
|
|
catch (Exception e)
|
|
|
{
|
|
|
unitOfWork.Dispose();
|
|
|
- new NLogHelper("ResourceExamineAppService").WriteLog("PrApprove", "采购申请单合并失败:" + e.Message, _currentTenant.Id.ToString());
|
|
|
- return JsonConvert.SerializeObject("合并失败,请联系管理员。");
|
|
|
+ new NLogHelper("ResourceExamineAppService").WriteLog("PrApprove", "要货令转采购订单失败:" + e.Message, _currentTenant.Id.ToString());
|
|
|
+ return JsonConvert.SerializeObject("要货令转采购订单失败,请联系管理员。");
|
|
|
}
|
|
|
}
|
|
|
return JsonConvert.SerializeObject("ok");
|
|
|
@@ -1496,6 +1552,7 @@ namespace Business.ResourceExamineManagement
|
|
|
if (newExm != null)
|
|
|
{
|
|
|
se.progress = "3";
|
|
|
+ se.rstate = 1;
|
|
|
se.sys_material_date = newExm.sys_material_date;
|
|
|
se.sys_capacity_date = newExm.sys_capacity_date;
|
|
|
//如果计算记录有工单id,则代表有生成工单,而不是占用计划工单
|
|
|
@@ -1535,8 +1592,9 @@ namespace Business.ResourceExamineManagement
|
|
|
moderlist = ObjectMapper.Map<List<mo_mes_morder>, List<mes_morder>>(WriteMorder);
|
|
|
|
|
|
List<RoutingOpDetail> allRoutings = _routingOpDetail.Select(p => moderlist.Select(m => m.product_code).Contains(p.RoutingCode));
|
|
|
+ List<b_bom_child_examine> childExamineList = _mysql_bom_child_examine.GetListAsync(c => exmResult.Select(x => x.Id).Contains(c.examine_id.GetValueOrDefault())).Result;
|
|
|
//同步工单
|
|
|
- CreateWorkOrdDates(moderlist, allRoutings, workOrds, workOrdRoutings, workOrdDetails);
|
|
|
+ CreateWorkOrdDates(moderlist, allRoutings, workOrds, workOrdRoutings, workOrdDetails, exmResult, childExamineList);
|
|
|
}
|
|
|
//当前订单号所关联的最新计算结果里的占用记录
|
|
|
List<mo_mes_mooccupy> mooccupyList = await _mes_mooccupy.GetListAsync(s => seIds.Contains(s.moo_id_billid.Value) && bangidList.Contains(s.bang_id.Value));
|
|
|
@@ -2033,7 +2091,7 @@ namespace Business.ResourceExamineManagement
|
|
|
podetail.netprice = item.pr_price;
|
|
|
podetail.netmoney = item.pr_aqty.GetValueOrDefault() * item.pr_price.GetValueOrDefault();
|
|
|
podetail.rate = item.pr_rate;
|
|
|
- podetail.price = item.pr_orderprice / item.pr_aqty;
|
|
|
+ podetail.price = item.pr_sysprice;
|
|
|
podetail.total_price = item.pr_orderprice;
|
|
|
podetail.taxamount = item.pr_orderprice.GetValueOrDefault() - podetail.netmoney;
|
|
|
podetail.plan_qty = item.pr_aqty;
|
|
|
@@ -2102,7 +2160,7 @@ namespace Business.ResourceExamineManagement
|
|
|
srm_Po_Occupy.GenerateNewId(help.NextId());
|
|
|
//srm_Po_Occupy.bang_id = bangid;
|
|
|
srm_Po_Occupy.morder_mo = c.pr_mono;
|
|
|
- srm_Po_Occupy.qty = c.pr_aqty;
|
|
|
+ srm_Po_Occupy.qty = c.pr_rqty;
|
|
|
srm_Po_Occupy.eid = c.sentry_id;
|
|
|
srm_Po_Occupy.polist_id = p.Id;
|
|
|
srm_Po_Occupy.polist_row = p.polist_row;
|
|
|
@@ -2519,6 +2577,7 @@ namespace Business.ResourceExamineManagement
|
|
|
{
|
|
|
List<WorkOrdRouting> alllist = workordRList.Where(s => s.WorkOrd == work).ToList();
|
|
|
List<WorkOrdRouting> parentlist = alllist.Where(s => s.WorkOrd == work && s.ParentOp == 0).ToList();
|
|
|
+ //非关键工序也要添加
|
|
|
copyList.AddRange(parentlist.Where(s => s.MilestoneOp == false).ToList());
|
|
|
GetChildOP(parentlist, alllist, copyList);
|
|
|
}
|
|
|
@@ -3543,26 +3602,6 @@ namespace Business.ResourceExamineManagement
|
|
|
return Wildcard.Replace(serialNumber, formData);
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// 生产排产
|
|
|
- /// </summary>
|
|
|
- /// <param name="workOrd"></param>
|
|
|
- /// <returns></returns>
|
|
|
- /// <exception cref="NotImplementedException"></exception>
|
|
|
- public async Task<string> ProductionSchedule(string workOrd,string domain)
|
|
|
- {
|
|
|
- List<string> workOrds = workOrd.Split(",").ToList();
|
|
|
- if (workOrds.Count == 0)
|
|
|
- {
|
|
|
- return "没有需要排产的工单。";
|
|
|
- }
|
|
|
- //获取工单数据
|
|
|
- var workOrdMasters = _workOrdMaster.Select(p => workOrds.Contains(p.WorkOrd) && p.Domain == domain);
|
|
|
- //排产
|
|
|
- //await _productionScheduleAppService.DoProductSchedule(workOrdMasters, workOrdMasters[0].Domain, 1);
|
|
|
- return "ok";
|
|
|
- }
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// 生成领料单
|
|
|
/// </summary>
|
|
|
@@ -3704,7 +3743,7 @@ namespace Business.ResourceExamineManagement
|
|
|
/// </summary>
|
|
|
/// <param name="morders"></param>
|
|
|
/// <param name="allRoutings">工艺路线数据</param>
|
|
|
- public void CreateWorkOrdDates(List<mes_morder> morders, List<RoutingOpDetail> allRoutings, List<WorkOrdMaster> workOrds, List<WorkOrdRouting> workOrdRoutings, List<WorkOrdDetail> workOrdDetails)
|
|
|
+ public void CreateWorkOrdDates(List<mes_morder> morders, List<RoutingOpDetail> allRoutings, List<WorkOrdMaster> workOrds, List<WorkOrdRouting> workOrdRoutings, List<WorkOrdDetail> workOrdDetails, List<b_examine_result> exmResult, List<b_bom_child_examine> childExamineList)
|
|
|
{
|
|
|
//工单主表
|
|
|
WorkOrdMaster workOrd;
|
|
|
@@ -3755,7 +3794,43 @@ namespace Business.ResourceExamineManagement
|
|
|
workOrdRoutings.Add(woRouting);
|
|
|
}
|
|
|
|
|
|
- List<ProductStructureMaster> curStructures = GetProductStructure(item.product_code, workOrd.QtyOrded, item.factory_id.ToString());
|
|
|
+ var exm = exmResult.Find(s => s.morder_id == item.Id);
|
|
|
+ if (exm != null)
|
|
|
+ {
|
|
|
+ var childs = childExamineList.Where(s => s.examine_id == exm.Id && s.is_use == true).ToList();
|
|
|
+ List<b_bom_child_examine> returnList = new List<b_bom_child_examine>();
|
|
|
+ GetWorkDetalis(childs.Where(s => s.level == 2).ToList(), returnList, childs);
|
|
|
+ if (returnList.Any())
|
|
|
+ {
|
|
|
+ foreach (var structure in returnList)
|
|
|
+ {
|
|
|
+ woDetail = workOrdDetails.Find(s => s.ItemNum == structure.item_number && s.WorkOrd == item.morder_no);
|
|
|
+ if (woDetail == null)
|
|
|
+ {
|
|
|
+ //添加工单的物料信息
|
|
|
+ woDetail = new WorkOrdDetail();
|
|
|
+ woDetail.Domain = item.factory_id.ToString();
|
|
|
+ woDetail.WorkOrd = item.morder_no;
|
|
|
+ woDetail.Op = structure.Op;
|
|
|
+ woDetail.ItemNum = structure.item_number;
|
|
|
+ woDetail.QtyRequired = structure.needCount.GetValueOrDefault();
|
|
|
+ woDetail.QtyPosted = 0m;
|
|
|
+ woDetail.QtyReturned = 0m;
|
|
|
+ woDetail.FrozenBOMQty = structure.needCount.GetValueOrDefault();
|
|
|
+ woDetail.Status = "";
|
|
|
+ woDetail.IsActive = true;
|
|
|
+ woDetail.CreateTime = DateTime.Now;
|
|
|
+ workOrdDetails.Add(woDetail);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ woDetail.QtyRequired += structure.needCount.GetValueOrDefault();
|
|
|
+ woDetail.FrozenBOMQty += structure.needCount.GetValueOrDefault();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /*List<ProductStructureMaster> curStructures = GetProductStructure(item.product_code, workOrd.QtyOrded, item.factory_id.ToString());
|
|
|
foreach (var structure in curStructures)
|
|
|
{
|
|
|
woDetail = workOrdDetails.Find(s => s.ItemNum == structure.ComponentItem);
|
|
|
@@ -3776,12 +3851,30 @@ namespace Business.ResourceExamineManagement
|
|
|
woDetail.CreateTime = DateTime.Now;
|
|
|
workOrdDetails.Add(woDetail);
|
|
|
}
|
|
|
- else {
|
|
|
+ else
|
|
|
+ {
|
|
|
woDetail.QtyRequired += structure.Qty;
|
|
|
woDetail.FrozenBOMQty += structure.Qty;
|
|
|
}
|
|
|
- }
|
|
|
+ }*/
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取虚拟件明细
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="dtl"></param>
|
|
|
+ /// <param name="returnList"></param>
|
|
|
+ /// <param name="childs"></param>
|
|
|
+ public void GetWorkDetalis(List<b_bom_child_examine> dtl, List<b_bom_child_examine> returnList, List<b_bom_child_examine> childs)
|
|
|
+ {
|
|
|
+ returnList.AddRange(dtl);
|
|
|
+ var rst = childs.Where(s => dtl.Where(x => x.erp_cls == 4).Select(c => c.fid).Contains(s.parent_id.GetValueOrDefault())).ToList();
|
|
|
+ if (rst.Any())
|
|
|
+ {
|
|
|
+ GetWorkDetalis(rst, returnList, childs);
|
|
|
}
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -3864,5 +3957,980 @@ namespace Business.ResourceExamineManagement
|
|
|
}
|
|
|
_productExamineAppService.CalcSuggestTime(sentrys, kittingTimes, icitemlist);
|
|
|
}
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 替代方案保存
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="dto"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<string> SubstituteSave(SubstituteDto dto)
|
|
|
+ {
|
|
|
+ ic_substitute stt;
|
|
|
+ if (dto.id == null)
|
|
|
+ {
|
|
|
+ if (_mysql_ic_substitute.GetListAsync(s => s.substitute_code == dto.scode).Result.Count > 0)
|
|
|
+ {
|
|
|
+ return "已存在【" + dto.scode + "】替代方案。";
|
|
|
+ }
|
|
|
+ var check = SubstituteSaveBeforCheck(dto);
|
|
|
+ if (check != "ok")
|
|
|
+ {
|
|
|
+ return check;
|
|
|
+ }
|
|
|
+ //新增
|
|
|
+ stt = new ic_substitute();
|
|
|
+ stt.GenerateNewId(help.NextId());
|
|
|
+ stt.substitute_code = dto.scode;
|
|
|
+ stt.substitute_mode = dto.smode;
|
|
|
+ stt.substitute_strategy = dto.sstrategy;
|
|
|
+ stt.create_by = dto.create_by;
|
|
|
+ stt.create_by_name = dto.create_by_name;
|
|
|
+ stt.create_time = DateTime.Now;
|
|
|
+ stt.update_by = dto.create_by;
|
|
|
+ stt.update_by_name = dto.create_by_name;
|
|
|
+ stt.update_time = DateTime.Now;
|
|
|
+ stt.tenant_id = dto.tenant_id;
|
|
|
+ stt.company_id = dto.company_id;
|
|
|
+ stt.factory_id = dto.factory_id;
|
|
|
+ List<ic_substitute_group> glist = new List<ic_substitute_group>();
|
|
|
+ List<ic_substitute_group_detail> dlist = new List<ic_substitute_group_detail>();
|
|
|
+ SubstituteSaveGenerate(dto, stt, glist, dlist);
|
|
|
+ using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ _businessDbContext.BulkInsert(new List<ic_substitute> { stt });
|
|
|
+ if (glist.Any())
|
|
|
+ {
|
|
|
+ _businessDbContext.BulkInsert(glist);
|
|
|
+ }
|
|
|
+ if (dlist.Any())
|
|
|
+ {
|
|
|
+ _businessDbContext.BulkInsert(dlist);
|
|
|
+ }
|
|
|
+ await unitOfWork.CompleteAsync();
|
|
|
+ return "ok";
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ new NLogHelper("ResourceExamineAppService").WriteLog("SubstituteSave", "替代方案保存失败:" + e.Message, _currentTenant.Id.ToString());
|
|
|
+ unitOfWork.Dispose();
|
|
|
+ return "保存失败,请联系管理员。";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //修改
|
|
|
+ stt = _mysql_ic_substitute.FirstAsync(s => s.Id == dto.id.Value).Result;
|
|
|
+ if (stt != null)
|
|
|
+ {
|
|
|
+ if (_mysql_ic_substitute.GetListAsync(s => s.Id != dto.id && s.substitute_code == dto.scode && s.company_id == dto.company_id && s.factory_id == dto.factory_id).Result.Count > 0)
|
|
|
+ {
|
|
|
+ return "已存在【" + dto.scode + "】替代方案。";
|
|
|
+ }
|
|
|
+ if (_mysql_ic_bom_child.GetListAsync(s => s.substitute_code == stt.substitute_code).Result.Count() > 0)
|
|
|
+ {
|
|
|
+ return "替代方案已被关联使用,不允许修改。";
|
|
|
+ }
|
|
|
+ var check = SubstituteSaveBeforCheck(dto);
|
|
|
+ if (check != "ok")
|
|
|
+ {
|
|
|
+ return check;
|
|
|
+ }
|
|
|
+ stt.substitute_code = dto.scode;
|
|
|
+ stt.substitute_mode = dto.smode;
|
|
|
+ stt.substitute_strategy = dto.sstrategy;
|
|
|
+ stt.update_by = dto.create_by;
|
|
|
+ stt.update_by_name = dto.create_by_name;
|
|
|
+ stt.update_time = DateTime.Now;
|
|
|
+ List<ic_substitute_group> glist = new List<ic_substitute_group>();
|
|
|
+ List<ic_substitute_group_detail> dlist = new List<ic_substitute_group_detail>();
|
|
|
+ SubstituteSaveGenerate(dto, stt, glist, dlist);
|
|
|
+
|
|
|
+ var delgList = _mysql_ic_substitute_group.GetListAsync(s => s.substitute_group_id == stt.Id).Result;
|
|
|
+ var deldList = _mysql_ic_substitute_group_detail.GetListAsync(s => delgList.Select(c => c.Id).Contains(s.substitute_group_id)).Result;
|
|
|
+
|
|
|
+ using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ _businessDbContext.BulkUpdate(new List<ic_substitute> { stt });
|
|
|
+ if (delgList.Any())
|
|
|
+ {
|
|
|
+ await _mysql_ic_substitute_group.HardDeleteAsync(delgList);
|
|
|
+ }
|
|
|
+ if (deldList.Any())
|
|
|
+ {
|
|
|
+ await _mysql_ic_substitute_group_detail.HardDeleteAsync(deldList);
|
|
|
+ }
|
|
|
+ if (glist.Any())
|
|
|
+ {
|
|
|
+ _businessDbContext.BulkInsert(glist);
|
|
|
+ }
|
|
|
+ if (dlist.Any())
|
|
|
+ {
|
|
|
+ _businessDbContext.BulkInsert(dlist);
|
|
|
+ }
|
|
|
+ return "ok";
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ new NLogHelper("ResourceExamineAppService").WriteLog("SubstituteSave", "替代方案保存失败:" + e.Message, _currentTenant.Id.ToString());
|
|
|
+ unitOfWork.Dispose();
|
|
|
+ return "保存失败,请联系管理员。";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return "当前方案已被删除,请刷新重试。";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 校验
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="dto"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public string SubstituteSaveBeforCheck(SubstituteDto dto)
|
|
|
+ {
|
|
|
+ if (!dto.srows.Any())
|
|
|
+ {
|
|
|
+ return "替代明细不能为空。";
|
|
|
+ }
|
|
|
+ if (dto.srows.Where(s => s.field_83817a9f5a15a4f78686105c694b0a39 == "是").Count() == 0)
|
|
|
+ {
|
|
|
+ return "请设置替代方案里的标准件。";
|
|
|
+ }
|
|
|
+ if (dto.srows.Where(s => s.field_83817a9f5a15a4f78686105c694b0a39 == "否").Count() == 0)
|
|
|
+ {
|
|
|
+ return "请设置替代方案里的替代件。";
|
|
|
+ }
|
|
|
+ if (dto.srows.Select(s => s.field_f8988ed2955a264f8f762faaed2c5f6a.GetValueOrDefault()).Count() < 2)
|
|
|
+ {
|
|
|
+ return "替代方案最低存在两个优先级。";
|
|
|
+ }
|
|
|
+ //判断同一个优先级里,相同是否标准料
|
|
|
+ foreach (var r in dto.srows)
|
|
|
+ {
|
|
|
+ if (dto.srows.Where(s => s.field_f8988ed2955a264f8f762faaed2c5f6a == r.field_f8988ed2955a264f8f762faaed2c5f6a && s.field_83817a9f5a15a4f78686105c694b0a39 != r.field_83817a9f5a15a4f78686105c694b0a39).Count() > 0)
|
|
|
+ {
|
|
|
+ return "同优先级群组里不允许既有标准件又有替代件。";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /*if (dto.srows.GroupBy(s => new { s.field_f8988ed2955a264f8f762faaed2c5f6a, s.field_83817a9f5a15a4f78686105c694b0a39 }).Where(g => g.Count() > 1).Count() > 0)
|
|
|
+ {
|
|
|
+ return "同优先级群组里不允许既有标准件又有替代件。";
|
|
|
+ }*/
|
|
|
+ return "ok";
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 组装数据
|
|
|
+ /// </summary>
|
|
|
+ public void SubstituteSaveGenerate(SubstituteDto dto, ic_substitute stt, List<ic_substitute_group> glist, List<ic_substitute_group_detail> dlist)
|
|
|
+ {
|
|
|
+ dto.srows.ForEach(s =>
|
|
|
+ {
|
|
|
+ ic_substitute_group g = glist.Where(x => x.order_num == s.field_f8988ed2955a264f8f762faaed2c5f6a.GetValueOrDefault()).FirstOrDefault();
|
|
|
+ if (g == null)
|
|
|
+ {
|
|
|
+ g = new ic_substitute_group();
|
|
|
+ g.GenerateNewId(help.NextId());
|
|
|
+ g.substitute_group_id = stt.Id;
|
|
|
+ g.substitute_code = stt.substitute_code;
|
|
|
+ g.replace_name = s.substitute_code;
|
|
|
+ g.order_num = s.field_f8988ed2955a264f8f762faaed2c5f6a.GetValueOrDefault();
|
|
|
+ g.main_material = s.field_83817a9f5a15a4f78686105c694b0a39 == "是" ? 1 : 0;
|
|
|
+ g.update_by = dto.create_by;
|
|
|
+ g.update_by_name = dto.create_by_name;
|
|
|
+ g.update_time = DateTime.Now;
|
|
|
+ g.tenant_id = dto.tenant_id;
|
|
|
+ g.company_id = dto.company_id;
|
|
|
+ g.factory_id = dto.factory_id;
|
|
|
+ glist.Add(g);
|
|
|
+ }
|
|
|
+ ic_substitute_group_detail d = new ic_substitute_group_detail();
|
|
|
+ d.GenerateNewId(help.NextId());
|
|
|
+ d.substitute_group_id = g.Id;
|
|
|
+ d.substitute_code = stt.substitute_code;
|
|
|
+ d.icitem_id = s.icitem_id.GetValueOrDefault();
|
|
|
+ d.icitem_number = s.icitem_number;
|
|
|
+ d.seq = s.seq;
|
|
|
+ d.replace_qty = s.replace_qty;
|
|
|
+ d.update_by = dto.create_by;
|
|
|
+ d.update_by_name = dto.create_by_name;
|
|
|
+ d.update_time = DateTime.Now;
|
|
|
+ d.tenant_id = dto.tenant_id;
|
|
|
+ d.company_id = dto.company_id;
|
|
|
+ d.factory_id = dto.factory_id;
|
|
|
+ dlist.Add(d);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 手动排产接口
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="domain"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ /// <exception cref="NotImplementedException"></exception>
|
|
|
+ public async Task<string> ProductionSchedule(string domain)
|
|
|
+ {
|
|
|
+ //获取排产锁定期
|
|
|
+ var generalizedCodeMaster = _generalizedCodeMaster.Select(p => p.FldName == "SystemConfig" && p.Val == "WorkOrderLockPeriod" && p.Domain == domain && p.IsActive).FirstOrDefault();
|
|
|
+ decimal lockDays = generalizedCodeMaster != null ? generalizedCodeMaster.UDeci1 : 0;
|
|
|
+
|
|
|
+ //获取需要排产的工单(获取四周的工单:正常工单+已审批通过的特殊工单)
|
|
|
+ DateTime endDate = DateTime.Now.Date.AddDays(28).AddDays(1);
|
|
|
+ //取数开始时间需要排除掉锁定期内的工单
|
|
|
+ DateTime startDate = DateTime.Now.Date.AddDays(1).AddDays((double)lockDays);
|
|
|
+ var workOrds = _workOrdMaster.Select(p => p.IsActive && p.Domain == domain && p.OrdDate < endDate && p.OrdDate >= startDate && string.IsNullOrEmpty(p.Status) && (string.IsNullOrEmpty(p.Typed) || (!string.IsNullOrEmpty(p.Typed) && p.BusinessID > 0))).ToList();
|
|
|
+ await _productionScheduleAppService.DoProductSchedule(workOrds, domain, 2);
|
|
|
+ return "ok";
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// BOM关联替代方案
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="dto"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<string> BindingSubstitute(BindingSubstituteDto dto)
|
|
|
+ {
|
|
|
+ var list = _mysql_ic_bom_child.GetListAsync(s => s.bom_id == dto.id && s.tenant_id == dto.tenant_id && s.company_id == dto.company_id && s.factory_id == dto.factory_id).Result;
|
|
|
+
|
|
|
+ if (dto.bomDetail.Any())
|
|
|
+ {
|
|
|
+ list.ForEach(s => { s.substitute_code = ""; s.haveicsubs = 0; });
|
|
|
+ var codeList = dto.bomDetail.Where(s => string.IsNullOrEmpty(s.substitute_code) == false).Select(x => x.substitute_code).Distinct().ToList();
|
|
|
+ if (codeList.Any())
|
|
|
+ {
|
|
|
+ var subGdtls = _mysql_ic_substitute_group.GetListAsync(s => s.tenant_id == dto.tenant_id && s.company_id == dto.company_id && s.factory_id == dto.factory_id && codeList.Contains(s.substitute_code)).Result;
|
|
|
+ var subDetalis = _mysql_ic_substitute_group_detail.GetListAsync(s => s.tenant_id == dto.tenant_id && s.company_id == dto.company_id && s.factory_id == dto.factory_id && codeList.Contains(s.substitute_code)).Result;
|
|
|
+ foreach (var code in codeList)
|
|
|
+ {
|
|
|
+ var g = subGdtls.Find(s => s.substitute_code == code && s.main_material == 1);
|
|
|
+ if (g != null)
|
|
|
+ {
|
|
|
+ var dtls = subDetalis.Where(s => s.substitute_group_id == g.Id).ToList();
|
|
|
+ foreach (var dtl in dtls)
|
|
|
+ {
|
|
|
+ var l = list.Find(s => s.item_number == dtl.icitem_number && s.qty == dtl.replace_qty);
|
|
|
+ if (l == null)
|
|
|
+ {
|
|
|
+ return "当前替代方案【" + code + "】的标准件未找到相同数量相同物料的BOM明细。";
|
|
|
+ }
|
|
|
+ if (string.IsNullOrEmpty(l.substitute_code))
|
|
|
+ {
|
|
|
+ l.haveicsubs = 1;
|
|
|
+ l.substitute_code = code;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return "当前替代方案【" + code + "】的标准件【" + l.item_number + "】与替代方案【" + l.substitute_code + "】冲突。";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return "当前替代方案【" + code + "】未设置标准件。";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ await _mysql_ic_bom_child.UpdateManyAsync(list);
|
|
|
+ }
|
|
|
+ return "ok";
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<string> WeekPlan(InputDto input)
|
|
|
+ {
|
|
|
+
|
|
|
+ //1.获取补货模型全局参数
|
|
|
+ ReplenishmentDto replenishmentDto = GetROPParam();
|
|
|
+
|
|
|
+ //到了配置的更新时间才更新
|
|
|
+ if (DateTime.Now.Day != replenishmentDto.SaleFcstEntryDate)
|
|
|
+ return "不在更新时间日期";
|
|
|
+
|
|
|
+
|
|
|
+ //获取月度发货计划
|
|
|
+ string planMonth = $"{DateTime.Now.AddMonths(1).Year}-{DateTime.Now.AddMonths(months: 1).Month}";
|
|
|
+ var planList = _monthlyShipmentPlan.Select(a => a.PlanMonth == planMonth && !a.IsDeleted);
|
|
|
+ var monthPlanList = ObjectMapper.Map<List<MonthlyShipmentPlan>, List<MonthlyShipmentPlanDto>>(planList);
|
|
|
+ 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;
|
|
|
+ //获取补货模型前一个周期和未来N个周期的数据
|
|
|
+ var ropModelList = _replenishmentModel.GetListAsync(a => a.zero_based_seqno >= 0 && a.zero_based_seqno <= replenishmentDto.UpdateWeeks).Result;
|
|
|
+ //发货计划物料列表
|
|
|
+ List<string> planItemList = planList?.Select(a => a.SAPItemNumber).ToList();
|
|
|
+ //补货模型物料列表
|
|
|
+ List<string> ropItemList = ropModelList?.Where(c => c.zero_based_seqno == 0).Select(a => a.number).ToList();
|
|
|
+ //第一次算或者新品物料列表
|
|
|
+ List<string> nohistoryItemList = planItemList.Except(ropItemList).ToList();
|
|
|
+ var sapItemInv = _SAPInv.Select(a => nohistoryItemList.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.ShipDate >= getMonthStartTime(-1) && a.ShipDate <= getMonthEndTime(-1) && a.RealQty > 0 && planItemList.Contains(a.ContainerItem));
|
|
|
+
|
|
|
+ //按照物料分组统计出货金额
|
|
|
+ var itemGroup = shipList.GroupBy(p => p.ContainerItem)
|
|
|
+ .Select(p => new ASNBOLShipperDetail
|
|
|
+ {
|
|
|
+ QtyToShip = p.Sum(a => a.QtyToShip),
|
|
|
+ ContainerItem = p.Key
|
|
|
+ }).ToList();
|
|
|
+
|
|
|
+ monthPlanList?.ForEach(a =>
|
|
|
+ {
|
|
|
+ //物料属性:0.配置类 1.自制 2.委外加工 3.外购 4.虚拟件
|
|
|
+ a.erp_cls = itemList.Find(s => s.number == a.SAPItemNumber)?.erp_cls;
|
|
|
+ if (mesItemList.Find(s => s.ItemNum == a.SAPItemNumber) != null)
|
|
|
+ {
|
|
|
+ a.stock_turnover = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber).StockTurnOver;
|
|
|
+ a.PLT = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber)?.PurLT;
|
|
|
+ a.IsLongPeriod = a.PLT >= replenishmentDto.LongPeriodDay;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ a.stock_turnover = 4;
|
|
|
+ }
|
|
|
+ if (srm_purchaseList.Find(s => s.number == a.SAPItemNumber) != null)
|
|
|
+ {
|
|
|
+ a.PLT = srm_purchaseList.Find(s => s.number == a.SAPItemNumber).lead_time;
|
|
|
+ a.IsLongPeriod = a.PLT >= replenishmentDto.LongPeriodDay;
|
|
|
+ }
|
|
|
+ //存在物料该物料编码表示之前算过,否则表示第一次算或者是新品
|
|
|
+ //之前算过,取算法模型数据,不存在表示第一次算要取默认值
|
|
|
+ if (ropModelList != null && ropModelList.Any(a => a.zero_based_seqno == 0))
|
|
|
+ {
|
|
|
+ a.actual_period_start_instock = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (sapItemInv.Find(s => s.MATNR == a.SAPItemNumber) != null)
|
|
|
+ {
|
|
|
+ a.actual_period_start_instock = Convert.ToDecimal(sapItemInv.Find(s => s.MATNR == a.SAPItemNumber).LABST);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ a.actual_period_start_instock = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ //第一周需要更新参数,其他周不要更新
|
|
|
+ if (WeekOfMonth(DateTime.Now, 1) == 1)
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+ //每算一次都要把所有zero_based_seqno减去1
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ List<DomesticTerminalFcst> domesticFcst = _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;
|
|
|
+
|
|
|
+ var modelList = domesticFcst?.Select(a => a.Model);
|
|
|
+ var ItemModelSetList = _standardItemModelSet.GetListAsync(a => a.tenant_id == input.tenant_id && a.company_id == input.company_id && modelList.Contains(a.Model) && !a.IsDeleted).Result;
|
|
|
+ if (ItemModelSetList == null)
|
|
|
+ {
|
|
|
+ return "库存数据不存在";
|
|
|
+ }
|
|
|
+ var itemNumList = ItemModelSetList?.Select(a => a.ItemNumber).ToList();
|
|
|
+ List<mo_ic_bom> boms = _ic_bom.GetListAsync(p => itemNumList.Contains(p.item_number) && p.factory_id == input.factory_id && p.company_id == input.company_id && !p.IsDeleted).Result.ToList();
|
|
|
+ var pretreatments = _mysql_b_bom_pretreatment.GetListAsync(s => boms.Select(c => c.mysql_id).ToList().Contains(s.sourceid)).Result;
|
|
|
+ List<mo_ic_bom> autoCreates = new List<mo_ic_bom>();
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return "OK";
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 每月15号更新周计划参数(考虑多次执行的情况)
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="input"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<string> WeekPlanParms(InputDto input)
|
|
|
+ {
|
|
|
+ //1.获取补货模型全局参数
|
|
|
+ ReplenishmentDto replenishmentDto = GetROPParam();
|
|
|
+
|
|
|
+ //到了配置的更新时间才更新
|
|
|
+ if (DateTime.Now.Day != replenishmentDto.SaleFcstEntryDate)
|
|
|
+ return "不在更新时间日期";
|
|
|
+
|
|
|
+ //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 = _replenishmentModel.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)).Where(s => s.ShipDate >= getMonthStartTime(-1) && s.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)).Where(s => s.ShipDate.Value >= getMonthStartTime(0) && s.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<ReplenishmentModel> addList = new List<ReplenishmentModel>();
|
|
|
+ List<ReplenishmentModel> updateList = new List<ReplenishmentModel>();//更新上一个月的实际出库数量
|
|
|
+ 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 =>
|
|
|
+ {
|
|
|
+ ReplenishmentModel rop = new ReplenishmentModel();
|
|
|
+ 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 _replenishmentModel.InsertManyAsync(addList);
|
|
|
+ await _replenishmentModel.UpdateManyAsync(updateList);
|
|
|
+ var ropModeAllList = _replenishmentModel.GetListAsync(a => a.year != DateTime.Now.Year && a.seqno != DateTime.Now.Month && a.isparam).Result;
|
|
|
+ ropModeAllList?.ForEach(item => { item.seqno = item.seqno - 1; });
|
|
|
+ await _replenishmentModel.UpdateManyAsync(ropModeAllList);
|
|
|
+ return "OK";
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// GK和HW平台成品周计划
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="planDtos"></param>
|
|
|
+ /// <param name="input"></param>
|
|
|
+ /// <param name="nohistoryItemList"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public string PlatformWeekPlan(InputDto input)
|
|
|
+ {
|
|
|
+ //1.获取补货模型全局参数
|
|
|
+ ReplenishmentDto replenishmentDto = GetROPParam();
|
|
|
+
|
|
|
+ //到了配置的更新时间才更新
|
|
|
+ if (DateTime.Now.Day != replenishmentDto.SaleFcstEntryDate)
|
|
|
+ return "不在更新时间日期";
|
|
|
+
|
|
|
+
|
|
|
+ //获取月度发货计划
|
|
|
+ string planMonth = $"{DateTime.Now.AddMonths(1).Year}-{DateTime.Now.AddMonths(months: 1).Month}";
|
|
|
+ var planList = _monthlyShipmentPlan.Select(a => a.PlanMonth == planMonth && !a.IsDeleted);
|
|
|
+ var monthPlanList = ObjectMapper.Map<List<MonthlyShipmentPlan>, List<MonthlyShipmentPlanDto>>(planList);
|
|
|
+ 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;
|
|
|
+ //获取补货模型前一个周期和未来N个周期的数据
|
|
|
+ var ropModelList = _replenishmentModel.GetListAsync(a => a.zero_based_seqno >= 0 && a.zero_based_seqno <= replenishmentDto.UpdateWeeks).Result;
|
|
|
+ //发货计划物料列表
|
|
|
+ List<string> planItemList = planList?.Select(a => a.SAPItemNumber).ToList();
|
|
|
+ //补货模型物料列表
|
|
|
+ List<string> ropItemList = ropModelList?.Where(c => c.zero_based_seqno == 0).Select(a => a.number).ToList();
|
|
|
+ //第一次算或者新品物料列表
|
|
|
+ List<string> nohistoryItemList = planItemList.Except(ropItemList).ToList();
|
|
|
+ var sapItemInv = _SAPInv.Select(a => nohistoryItemList.Contains(a.MATNR) && a.WERKS == input.factory_id.ToString());
|
|
|
+
|
|
|
+ //1.6、获取成品库存、灭菌库存、在制库存(会从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 shipList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.ShipDate >= getMonthStartTime(-1) && a.ShipDate <= getMonthEndTime(-1) && a.RealQty > 0 && planItemList.Contains(a.ContainerItem));
|
|
|
+
|
|
|
+ //按照物料分组统计出货金额
|
|
|
+ var itemGroup = shipList.GroupBy(p => p.ContainerItem)
|
|
|
+ .Select(p => new ASNBOLShipperDetail
|
|
|
+ {
|
|
|
+ Price = p.Sum(a => a.QtyToShip),
|
|
|
+ ContainerItem = p.Key
|
|
|
+ }).ToList();
|
|
|
+
|
|
|
+ monthPlanList?.ForEach(a =>
|
|
|
+ {
|
|
|
+ //物料属性:0.配置类 1.自制 2.委外加工 3.外购 4.虚拟件
|
|
|
+ a.erp_cls = itemList.Find(s => s.number == a.SAPItemNumber)?.erp_cls;
|
|
|
+ if (mesItemList.Find(s => s.ItemNum == a.SAPItemNumber) != null)
|
|
|
+ {
|
|
|
+ a.stock_turnover = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber).StockTurnOver;
|
|
|
+ a.PLT = mesItemList.Find(s => s.ItemNum == a.SAPItemNumber)?.PurLT;
|
|
|
+ a.IsLongPeriod = a.PLT >= replenishmentDto.LongPeriodDay;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ a.stock_turnover = 4;
|
|
|
+ }
|
|
|
+ if (srm_purchaseList.Find(s => s.number == a.SAPItemNumber) != null)
|
|
|
+ {
|
|
|
+ a.PLT = srm_purchaseList.Find(s => s.number == a.SAPItemNumber).lead_time;
|
|
|
+ a.IsLongPeriod = a.PLT >= replenishmentDto.LongPeriodDay;
|
|
|
+ }
|
|
|
+ //存在物料该物料编码表示之前算过,否则表示第一次算或者是新品
|
|
|
+ //之前算过,取算法模型数据,不存在表示第一次算要取默认值
|
|
|
+ if (ropModelList != null && ropModelList.Any(a => a.zero_based_seqno == 0))
|
|
|
+ {
|
|
|
+ a.actual_period_start_instock = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (sapItemInv.Find(s => s.MATNR == a.SAPItemNumber) != null)
|
|
|
+ {
|
|
|
+ a.actual_period_start_instock = Convert.ToDecimal(sapItemInv.Find(s => s.MATNR == a.SAPItemNumber).LABST);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ a.actual_period_start_instock = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ //第一周需要更新参数,其他周不要更新
|
|
|
+ if (WeekOfMonth(DateTime.Now, 1) == 1)
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+ //每算一次都要把所有zero_based_seqno减去1
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ List<DomesticTerminalFcst> domesticFcst = _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;
|
|
|
+
|
|
|
+ var modelList = domesticFcst?.Select(a => a.Model);
|
|
|
+ var ItemModelSetList = _standardItemModelSet.GetListAsync(a => a.tenant_id == input.tenant_id && a.company_id == input.company_id && modelList.Contains(a.Model) && !a.IsDeleted).Result;
|
|
|
+ if (ItemModelSetList == null)
|
|
|
+ {
|
|
|
+ return "库存数据不存在";
|
|
|
+ }
|
|
|
+ var itemNumList = ItemModelSetList?.Select(a => a.ItemNumber).ToList();
|
|
|
+ List<mo_ic_bom> boms = _ic_bom.GetListAsync(p => itemNumList.Contains(p.item_number) && p.factory_id == input.factory_id && p.company_id == input.company_id && !p.IsDeleted).Result.ToList();
|
|
|
+ var pretreatments = _mysql_b_bom_pretreatment.GetListAsync(s => boms.Select(c => c.mysql_id).ToList().Contains(s.sourceid)).Result;
|
|
|
+ List<mo_ic_bom> autoCreates = new List<mo_ic_bom>();
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return "OK";
|
|
|
+ }
|
|
|
+
|
|
|
+ public ReplenishmentDto GetROPParam()
|
|
|
+ {
|
|
|
+ ReplenishmentDto replenishmentDto = new ReplenishmentDto();
|
|
|
+ replenishmentDto.ReplenishmentCalcPeriod = "W";
|
|
|
+ replenishmentDto.HistoryOutStockMonth = 2;
|
|
|
+ replenishmentDto.SaleFcstMonth = 2;
|
|
|
+ replenishmentDto.SaleFcstEntryDate = 27;
|
|
|
+ replenishmentDto.UpdateWeeks = 12;
|
|
|
+ replenishmentDto.WeekPlanUpdateDay = 7;//每周日更新
|
|
|
+ replenishmentDto.LongPeriodDay = 60;
|
|
|
+ return replenishmentDto;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 计算ABC分类和FMR分类
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="replenishmentModels"></param>
|
|
|
+ public void CalcFMRAndABC(List<ReplenishmentModel> replenishmentModels, ReplenishmentDto replenishmentDto, InputDto input)
|
|
|
+ {
|
|
|
+ var itemNumList = replenishmentModels?.Select(a => a.number).ToList();
|
|
|
+ //发货出库记录
|
|
|
+ var shipList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.ShipDate >= DateTime.Now.AddMonths(replenishmentDto.HistoryOutStockMonth * -1) && a.RealQty > 0 && itemNumList.Contains(a.ContainerItem));
|
|
|
+ //领料出库记录
|
|
|
+ //var pickbilllist = _NbrDetail.Select(a => a.Domain == input.factory_id.ToString() && a.Type == "SM" && a.IsActive && a.UpdateTime >= DateTime.Now.AddMonths(replenishmentDto.HistoryOutStockMonth * -1) && itemNumList.Contains(a.ItemNum));
|
|
|
+ var pickbilllist = _invTransHist.Select(a => a.Domain == input.factory_id.ToString() && a.TransType == "iss-wo" && a.IsActive && a.CreateTime >= DateTime.Now.AddMonths(replenishmentDto.HistoryOutStockMonth * -1) && itemNumList.Contains(a.ItemNum));
|
|
|
+ //总的移库次数
|
|
|
+ int totalCount = shipList.Count() + pickbilllist.Count();
|
|
|
+ //平均出库次数
|
|
|
+ decimal avgOutStock = totalCount / replenishmentDto.HistoryOutStockMonth;
|
|
|
+
|
|
|
+ //总出货金额
|
|
|
+ decimal? totalPrice = shipList.Sum(a => a.Price * a.QtyToShip);
|
|
|
+ //按照物料分组统计出货金额
|
|
|
+ var itemGroup = shipList.GroupBy(p => p.ContainerItem)
|
|
|
+ .Select(p => new ASNBOLShipperDetail
|
|
|
+ {
|
|
|
+ Price = p.Sum(a => a.Price * a.QtyToShip) * 100 / totalPrice,
|
|
|
+ ContainerItem = p.Key
|
|
|
+ }).ToList().OrderByDescending(c => c.Price).ThenByDescending(c => c.ContainerItem);
|
|
|
+ var AIndex = (int)Math.Ceiling(itemGroup.Count() * 0.75);//A类:0-75%
|
|
|
+ var BIndex = (int)Math.Ceiling(itemGroup.Count() * 0.9) - AIndex;//A类:75%-90%
|
|
|
+ var CIndex = itemGroup.Count() - AIndex - BIndex;//A类:90%-100%
|
|
|
+ var AItem = itemGroup.Take(AIndex);
|
|
|
+ var BItem = itemGroup.Skip(AIndex).Take(BIndex);
|
|
|
+ var CItem = itemGroup.Skip(AIndex + BIndex).Take(CIndex);
|
|
|
+ replenishmentModels?.ForEach(replenishmentModel =>
|
|
|
+ {
|
|
|
+ if (AItem.Any(a => a.ContainerItem == replenishmentModel.number))
|
|
|
+ {
|
|
|
+ replenishmentModel.abc = "A";//金额占比前75%的物料划为A类
|
|
|
+ }
|
|
|
+ else if (BItem.Any(a => a.ContainerItem == replenishmentModel.number))
|
|
|
+ {
|
|
|
+ replenishmentModel.abc = "B";//金额占比前75%-90%的物料划为A类
|
|
|
+ }
|
|
|
+ else if (CItem.Any(a => a.ContainerItem == replenishmentModel.number))
|
|
|
+ {
|
|
|
+ replenishmentModel.abc = "C";//金额占比后10%的物料划为A类
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ replenishmentModel.abc = "B";//原材料默认为B
|
|
|
+ }
|
|
|
+ int itemMoveCount = shipList.Count(a => a.ContainerItem == replenishmentModel.number) + pickbilllist.Count(a => a.ItemNum == replenishmentModel.number);
|
|
|
+ if (itemMoveCount >= avgOutStock)
|
|
|
+ {
|
|
|
+ replenishmentModel.fmr = "F";
|
|
|
+ }
|
|
|
+ else if (itemMoveCount >= avgOutStock / 2 && itemMoveCount < avgOutStock || itemMoveCount == 0)
|
|
|
+ {
|
|
|
+ replenishmentModel.fmr = "M";//没有出库移库记录的默认为M
|
|
|
+ }
|
|
|
+ else if (itemMoveCount < avgOutStock / 2)
|
|
|
+ {
|
|
|
+ replenishmentModel.fmr = "R";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (replenishmentModel.abc == "A" && replenishmentModel.fmr == "R")
|
|
|
+ {
|
|
|
+ replenishmentModel.service_level_pct = (decimal?)0.8;
|
|
|
+ }
|
|
|
+ if (replenishmentModel.abc != "C" && replenishmentModel.fmr != "R")
|
|
|
+ {
|
|
|
+ replenishmentModel.service_level_pct = (decimal?)0.96;
|
|
|
+ }
|
|
|
+ if (replenishmentModel.abc == "C" || (replenishmentModel.abc == "B" && replenishmentModel.fmr == "R"))
|
|
|
+ {
|
|
|
+ replenishmentModel.service_level_pct = (decimal?)0.9;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 计算ABC分类和FMR分类
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="replenishmentModels"></param>
|
|
|
+ public void CalcFMRAndABC(ReplenishmentModel replenishmentModel, ReplenishmentDto replenishmentDto, InputDto input)
|
|
|
+ {
|
|
|
+ //发货出库记录
|
|
|
+ var shipList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.ShipDate >= DateTime.Now.AddMonths(replenishmentDto.HistoryOutStockMonth * -1) && a.RealQty > 0 && replenishmentModel.number == a.ContainerItem);
|
|
|
+ //领料出库记录
|
|
|
+ //var pickbilllist = _NbrDetail.Select(a => a.Domain == input.factory_id.ToString() && a.Type == "SM" && a.IsActive && a.UpdateTime >= DateTime.Now.AddMonths(replenishmentDto.HistoryOutStockMonth * -1) && itemNumList.Contains(a.ItemNum));
|
|
|
+ var pickbilllist = _invTransHist.Select(a => a.Domain == input.factory_id.ToString() && a.TransType == "iss-wo" && a.IsActive && a.CreateTime >= DateTime.Now.AddMonths(replenishmentDto.HistoryOutStockMonth * -1) && replenishmentModel.number == a.ItemNum);
|
|
|
+ //总的移库次数
|
|
|
+ int totalCount = shipList.Count() + pickbilllist.Count();
|
|
|
+ //平均出库次数
|
|
|
+ decimal avgOutStock = totalCount / replenishmentDto.HistoryOutStockMonth;
|
|
|
+
|
|
|
+ //总出货金额
|
|
|
+ decimal? totalPrice = shipList.Sum(a => a.Price * a.QtyToShip);
|
|
|
+ //按照物料分组统计出货金额
|
|
|
+ var itemGroup = shipList.GroupBy(p => p.ContainerItem)
|
|
|
+ .Select(p => new ASNBOLShipperDetail
|
|
|
+ {
|
|
|
+ Price = p.Sum(a => a.Price * a.QtyToShip) * 100 / totalPrice,
|
|
|
+ ContainerItem = p.Key
|
|
|
+ }).ToList().OrderByDescending(c => c.Price).ThenByDescending(c => c.ContainerItem);
|
|
|
+ var AIndex = (int)Math.Ceiling(itemGroup.Count() * 0.75);//A类:0-75%
|
|
|
+ var BIndex = (int)Math.Ceiling(itemGroup.Count() * 0.9) - AIndex;//A类:75%-90%
|
|
|
+ var CIndex = itemGroup.Count() - AIndex - BIndex;//A类:90%-100%
|
|
|
+ var AItem = itemGroup.Take(AIndex);
|
|
|
+ var BItem = itemGroup.Skip(AIndex).Take(BIndex);
|
|
|
+ var CItem = itemGroup.Skip(AIndex + BIndex).Take(CIndex);
|
|
|
+ if (AItem.Any(a => a.ContainerItem == replenishmentModel.number))
|
|
|
+ {
|
|
|
+ replenishmentModel.abc = "A";//金额占比前75%的物料划为A类
|
|
|
+ }
|
|
|
+ else if (BItem.Any(a => a.ContainerItem == replenishmentModel.number))
|
|
|
+ {
|
|
|
+ replenishmentModel.abc = "B";//金额占比前75%-90%的物料划为B类
|
|
|
+ }
|
|
|
+ else if (CItem.Any(a => a.ContainerItem == replenishmentModel.number))
|
|
|
+ {
|
|
|
+ replenishmentModel.abc = "C";//金额占比后10%的物料划为C类
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ replenishmentModel.abc = "B";//原材料默认为B
|
|
|
+ }
|
|
|
+ int itemMoveCount = shipList.Count(a => a.ContainerItem == replenishmentModel.number) + pickbilllist.Count(a => a.ItemNum == replenishmentModel.number);
|
|
|
+ if (itemMoveCount >= avgOutStock)
|
|
|
+ {
|
|
|
+ replenishmentModel.fmr = "F";
|
|
|
+ }
|
|
|
+ else if (itemMoveCount >= avgOutStock / 2 && itemMoveCount < avgOutStock || itemMoveCount == 0)
|
|
|
+ {
|
|
|
+ replenishmentModel.fmr = "M";//没有出库移库记录的默认为M
|
|
|
+ }
|
|
|
+ else if (itemMoveCount < avgOutStock / 2)
|
|
|
+ {
|
|
|
+ replenishmentModel.fmr = "R";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (replenishmentModel.abc == "A" && replenishmentModel.fmr == "R")
|
|
|
+ {
|
|
|
+ replenishmentModel.service_level_pct = (decimal?)0.8;
|
|
|
+ }
|
|
|
+ if (replenishmentModel.fmr != "R")
|
|
|
+ {
|
|
|
+ replenishmentModel.service_level_pct = (decimal?)0.96;
|
|
|
+ }
|
|
|
+ if (replenishmentModel.abc != "A" && replenishmentModel.fmr == "R")
|
|
|
+ {
|
|
|
+ replenishmentModel.service_level_pct = (decimal?)0.9;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 算平均月需求数量
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="planList">发货计划</param>
|
|
|
+ /// <param name="itemGroup"></param>
|
|
|
+ /// <param name="itemNum"></param>
|
|
|
+ /// <param name="month"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public decimal CalcAvgDemand(List<MonthlyShipmentPlan> list, string itemNum)
|
|
|
+ {
|
|
|
+ return list.Where(i => i.SAPItemNumber == itemNum).Select(a => a.Qty).Average();
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ ///
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="list">补货模型</param>
|
|
|
+ /// <param name="MQty">本月实际出库</param>
|
|
|
+ /// <param name="replenishmentDto">全局参数</param>
|
|
|
+ /// <param name="itemNum">物料编码</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public decimal CalcAvgOutStock(List<ReplenishmentModel> list, ReplenishmentDto replenishmentDto, decimal MQty, string itemNum)
|
|
|
+ {
|
|
|
+ return (list.Where(i => i.number == itemNum && i.zero_based_seqno > 1 - replenishmentDto.HistoryOutStockMonth && i.zero_based_seqno <= 0).Select(a => a.actual_out_qty.Value).Sum() + MQty) / (replenishmentDto.HistoryOutStockMonth + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ public double CalcVariance(List<MonthlyShipmentPlan> list, string itemNum)
|
|
|
+ {
|
|
|
+ var avg = CalcAvgDemand(list, itemNum);
|
|
|
+ var nums = list.Where(i => i.SAPItemNumber == itemNum).Select(a => a.Qty);
|
|
|
+ if (nums.Count() <= 1)
|
|
|
+ return 0;
|
|
|
+ return Math.Sqrt(nums.Sum(x => Math.Pow(Convert.ToDouble(x) - Convert.ToDouble(avg), 2)) / (nums.Count() - 1));
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取指定日期在为一年中为第几周
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="dt">指定时间</param>
|
|
|
+ /// <reutrn>返回第几周</reutrn>
|
|
|
+ public static int GetWeekOfYear(DateTime dt)
|
|
|
+ {
|
|
|
+
|
|
|
+ System.Globalization.GregorianCalendar gc = new System.Globalization.GregorianCalendar();
|
|
|
+ int weekOfYear = gc.GetWeekOfYear(dt, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Monday);
|
|
|
+ return weekOfYear;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取指定日期在该月的第几周
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="day"></param>
|
|
|
+ /// <param name="WeekStart">1表示周一至周日为一周,2表示周日至周六为一周</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static int WeekOfMonth(DateTime day, int WeekStart)
|
|
|
+ {
|
|
|
+ DateTime FirstofMonth = Convert.ToDateTime(day.Date.Year + "-" + day.Date.Month + "-" + 1);
|
|
|
+
|
|
|
+ int i = (int)FirstofMonth.Date.DayOfWeek;
|
|
|
+ if (i == 0)
|
|
|
+ {
|
|
|
+ i = 7;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (WeekStart == 1)
|
|
|
+ {
|
|
|
+ return (day.Date.Day + i - 2) / 7 + 1;
|
|
|
+ }
|
|
|
+ if (WeekStart == 2)
|
|
|
+ {
|
|
|
+ return (day.Date.Day + i - 1) / 7;
|
|
|
+
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ //获取上周开始时间
|
|
|
+ public static DateTime getPreWeekStartTime()
|
|
|
+ {
|
|
|
+ var weekday = (int)DateTime.Now.DayOfWeek;
|
|
|
+ return Convert.ToDateTime(DateTime.Now.AddDays(-7 - weekday + 1).ToString("yyyy-MM-dd 00:00:00.000"));
|
|
|
+ }
|
|
|
+ //获取上周结束时间
|
|
|
+ public static DateTime getPreWeekEndTime()
|
|
|
+ {
|
|
|
+ int weekday = (int)DateTime.Now.DayOfWeek;
|
|
|
+ return Convert.ToDateTime(DateTime.Now.AddDays(weekday - 7 + 1).ToString("yyyy-MM-dd 23:59:59.000"));
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取上个月开始时间
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="months"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static DateTime getPreMonthStartTime()
|
|
|
+ {
|
|
|
+ return Convert.ToDateTime(DateTime.Now.AddMonths(-1).AddDays(1 - DateTime.Now.Day).ToString("yyyy-MM-dd 00:00:00.000"));
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取上月结束时间
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="months"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static DateTime getPreMonthEndTime()
|
|
|
+ {
|
|
|
+ return Convert.ToDateTime(DateTime.Now.AddDays(-DateTime.Now.Day).ToString("yyyy-MM-dd 23:59:59.000"));
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取前后某个,整数月开始时间
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="months">正数表示后多少个月的第一天,负数为前多少个月第一天</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static DateTime getMonthStartTime(int months)
|
|
|
+ {
|
|
|
+ return getPreMonthStartTime().AddMonths(months + 1);
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取前后某个,整数月结束时间
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="months">正数表示后多少个月的第一天,负数为前多少个月第一天</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static DateTime getMonthEndTime(int months)
|
|
|
+ {
|
|
|
+ return getPreMonthEndTime().AddMonths(months + 1);
|
|
|
+ }
|
|
|
}
|
|
|
}
|