Pārlūkot izejas kodu

产能计算调整

heteng 3 gadi atpakaļ
vecāks
revīzija
5521f1de86

+ 5 - 0
MicroServices/Business/Business.Application.Contracts/Dto/KittingTimeDto.cs

@@ -16,6 +16,11 @@ namespace Business.Dto
         /// </summary>
         public long sentry_id { get; set; }
 
+        /// <summary>
+        /// 物料编码
+        /// </summary>
+        public string ItemNum { get; set; }
+
         /// <summary>
         /// 系统建议交期(产能)
         /// </summary>

+ 6 - 6
MicroServices/Business/Business.Application.Contracts/ResourceExamineManagement/Dto/ProdExamineParamDto.cs

@@ -12,18 +12,18 @@ namespace Business.ResourceExamineManagement.Dto
     public class ProdExamineParamDto
     {
         /// <summary>
-        /// bom编号
+        /// 物料编码
         /// </summary>
-        public string? bom_number { get; set; }
+        public string ItemNum { get; set; }
 
         /// <summary>
-        /// bom版本
+        /// 订单行数量
         /// </summary>
-        public string? version { get; set; }
+        public decimal QtyOrd { get; set; }
 
         /// <summary>
-        /// 生产件数
+        /// 计划开始时间
         /// </summary>
-        public int packages { get; set; }
+        public DateTime PlanStart { get; set; }
     }
 }

+ 86 - 227
MicroServices/Business/Business.Application/ResourceExamineManagement/ProductExamineAppService.cs

@@ -21,24 +21,34 @@ namespace Business.ResourceExamineManagement
     {
         #region 服务
         /// <summary>
-        /// 工艺路径
+        /// 生产线明细表
         /// </summary>
-        public List<mo_mes_technique> techs = new List<mo_mes_technique>();
+        public List<ProdLineDetail> prodLines = new List<ProdLineDetail>();
 
         /// <summary>
-        /// 工艺关联工序
+        /// 标准工艺路径表
         /// </summary>
-        public List<mo_mes_tech_process> tech_Processes = new List<mo_mes_tech_process>();
+        public List<RoutingOpDetail> routingOps = new List<RoutingOpDetail>();
 
         /// <summary>
-        /// 工序
+        /// 排产记录表
         /// </summary>
-        public List<mo_mes_process> process = new List<mo_mes_process>();
+        public List<PeriodSequenceDet> periodSequences = new List<PeriodSequenceDet>();
 
         /// <summary>
-        /// 工艺工序关联工位
+        /// 工作日历
         /// </summary>
-        public List<mo_mes_tech_proc_workshop> tech_Proc_Workshops = new List<mo_mes_tech_proc_workshop>();
+        public List<ShopCalendarWorkCtr> calendarWorks = new List<ShopCalendarWorkCtr>();
+
+        /// <summary>
+        /// 休息时间段
+        /// </summary>
+        public List<QualityLineWorkDetail> qualityLineWorks = new List<QualityLineWorkDetail>();
+
+        /// <summary>
+        /// 节假日
+        /// </summary>
+        public List<HolidayMaster> holidays = new List<HolidayMaster>();
 
         #endregion
 
@@ -50,255 +60,104 @@ namespace Business.ResourceExamineManagement
         }
 
         /// <summary>
-        /// 产能计算
+        /// 产能计算-批量
         /// </summary>
-        /// <param name="packages">件数</param>
-        /// <returns>生产时长</returns>
-        public decimal ProductiveExamine(ProdExamineParamDto param)
+        /// <param name="param">产能检查入参</param>
+        /// <returns>生产时长(天)</returns>
+        public DateTime ProductiveExamine(ProdExamineParamDto param)
         {
-            if (param.packages <= 0)
-            {
-                //throw new NotImplementedException("产能计算参数有误!");
-            }
-            //过滤数据
-            //1.1、获取工艺路径数据
-            mo_mes_technique curTech = techs.FirstOrDefault(p => p.bom == param.bom_number && p.bomver == param.version);
-            if (curTech == null)
+            //生产结束时间
+            DateTime planEnd = param.PlanStart.Date;
+            if (param.QtyOrd <= 0)
             {
-                return param.packages * 20;
-                //throw new NotImplementedException("工艺路径不存在,请调整!");
+                return planEnd;
             }
-            //1.2、获取工艺关联工序数据
-            List<mo_mes_tech_process> curTechProcess = tech_Processes.Where(p => p.tech_id == curTech.mysql_id).ToList();
-            if (curTechProcess.Count == 0)
+            //获取当前产品的工艺路线:主产线,最后一道工序
+            var curRoutingOps = routingOps.Where(p => p.RoutingCode == param.ItemNum && p.ParentOp == 0).OrderByDescending(p => p.Op).ToList();
+            if (curRoutingOps.Count() == 0)
             {
-                return param.packages * 20;
-                //throw new NotImplementedException("当前工艺路径没有配置工序,请调整!");
+                return planEnd;
             }
-            //1.3、获取工序数据
-            List<mo_mes_process> curProcess = process.Where(p => curTechProcess.Select(m => m.proc_id).Contains(p.mysql_id)).ToList();
-            if (curProcess.Count == 0)
-            {
-                return param.packages * 20;
-                //throw new NotImplementedException("工序数据不存在,请调整!");
-            }
-            //1.4、获取工位数据
-            List<mo_mes_tech_proc_workshop> curWorkShops = tech_Proc_Workshops.Where(p=> curTechProcess.Select(m=>m.mysql_id).Contains(p.tech_proc_id)).ToList(); ;
-
-            //2、获取工艺路径下的第一层级工序:目前只考虑第一层级
-            List<mo_mes_tech_process> fistLevels = curTechProcess.Where(p => p.parentprocid == curTech.mysql_id).ToList();
-            if (fistLevels.Count == 0)
-            {
-                return param.packages * 20;
-                //throw new NotImplementedException("当前工艺路径没有配置工序,请调整!");
-            }
-            //工艺预处理
-            List<TechProcDto> teches = TechProcPretreatment(fistLevels,param.packages);
-            decimal sumTimes = teches.OrderByDescending(p => p.sumTimes).First().sumTimes;
-            return sumTimes;
-        }
-
-        /// <summary>
-        /// 工序预处理,按照多分支生成多条单独的工艺路径
-        /// </summary>
-        /// <param name="proc">当前工序</param>
-        /// <param name="processes">工艺关联工序list</param>
-        /// <param name="packages">生产件数</param>
-        /// <returns></returns>
-        private List<TechProcDto> TechProcPretreatment(List<mo_mes_tech_process> processes,int packages)
-        { 
-            //工艺路径预处理dto
-            List<TechProcDto> techProcDtos = new List<TechProcDto>();
-            TechProcDto dto;
-            //获取下一步工序id
-            List<long> nextProcIds = processes.Where(p=>p.nextprocid != null).Select(p => p.nextprocid.GetValueOrDefault()).ToList();
-            //获取起点工序
-            var startProcs = processes.Where(p => !nextProcIds.Contains(p.proc_id)).ToList();
-            //递归处理工序返回值
-            List<mo_mes_tech_process> rtnList;
-            for (int i = 0; i < startProcs.Count; i++)
+            var lastOp = curRoutingOps.Last();
+            //获取产线
+            var curProdLine = prodLines.FirstOrDefault(p => p.Part == param.ItemNum && p.Op == lastOp.Op);
+            if (curProdLine == null)
             {
-                dto = new TechProcDto();
-                rtnList = new List<mo_mes_tech_process>();
-                GetNextProc(startProcs[i], processes, rtnList);
-                dto.serialno = i + 1;
-                dto.processes = rtnList;
-                //dto.details = CalcTakeTimeByLq(rtnList, packages);//通过Lq计算
-                dto.details = CalcTakeTimeByLqt(rtnList, packages);//通过Lqt计算
-                dto.sumTimes = dto.details.Sum(p=>p.wait_time);
-                techProcDtos.Add(dto);
+                return planEnd;
             }
-            return techProcDtos;
-        }
-
-        /// <summary>
-        /// 递归:根据起始工序,获取后续工序
-        /// </summary>
-        /// <param name="proc"></param>
-        /// <param name="processes"></param>
-        /// <param name="rtnList"></param>
-        private void GetNextProc(mo_mes_tech_process proc, List<mo_mes_tech_process> processes, List<mo_mes_tech_process> rtnList)
-        {
-            rtnList.Add(proc);
-            //下一工序id为null,终止
-            if (proc?.nextprocid == null)
+            //获取产线工作日历
+            var curCalendars = calendarWorks.Where(p => p.ProdLine == curProdLine.Line).ToList();
+            if (curCalendars.Count() == 0 || curCalendars.Count() != 0)
             {
-                return;
+                return planEnd;
             }
-            //获取下一个工序
-            var nextProc = processes.FirstOrDefault(p=>p.proc_id == proc.nextprocid);
-            if (nextProc == null) 
+            //获取产线休息时间
+            var curqualityLines = qualityLineWorks.Where(p=>p.ProdLine == curProdLine.Line).ToList();
+            //生产数量
+            decimal sumAmount = 0m;
+            do
             {
-                return;
-            }
-            GetNextProc(nextProc, processes, rtnList);
+                //获取工作日
+                planEnd = GetNextWorkDay(planEnd, curCalendars);
+                //计算工作日的产能
+                sumAmount += CalcCapacity(planEnd, curProdLine, curCalendars, curqualityLines);
+                planEnd.AddDays(1);
+            } while (sumAmount < param.QtyOrd);
+            return planEnd.AddDays(-1);
         }
 
         /// <summary>
-        /// 通过Lq计算工艺耗时
+        /// 获取工作日
         /// </summary>
-        /// <param name="Processes"></param>
-        /// <param name="packages"></param>
+        /// <param name="weekDay">当前周几</param>
+        /// <param name="startTime">开始时间:年-月-日</param>
+        /// <param name="curCalendars">当前产线的工作日历</param>
         /// <returns></returns>
-        private List<StartTimeDto> CalcTakeTimeByLq(List<mo_mes_tech_process> Processes, int packages)
+        public DateTime GetNextWorkDay(DateTime startTime, List<ShopCalendarWorkCtr> curCalendars)
         {
-            //工序需要等待时间记录
-            List<StartTimeDto> starts = new List<StartTimeDto>();
-            StartTimeDto dto;
-            foreach (var chd in Processes)
+            DateTime rtnData = startTime;
+            int weekDay = (int)startTime.DayOfWeek;
+            var calendar = curCalendars.FirstOrDefault(p => p.WeekDay == weekDay);
+            //判断当天是否是工作日
+            if (weekDay == 0 || weekDay == 6)//周六,周日
             {
-                dto = new StartTimeDto();
-                if (chd.nextprocid == null)//最后一个工序
-                {
-                    //计算最后一个工序耗时
-                    dto = CalcProcTakeTimeByLq(chd, packages, packages);
-                }
-                else
+                if (!holidays.Exists(p => p.Dated.GetValueOrDefault().Date == startTime && p.Ufld1 == "调班"))//今天是周末
                 {
-                    dto = CalcProcTakeTimeByLq(chd, chd.lq.GetValueOrDefault(), packages);
+                    //递归继续找下一个工作日
+                    rtnData = GetNextWorkDay(startTime.AddDays(1), curCalendars);
+                    return rtnData;
                 }
-                //添加记录
-                starts.Add(dto);
+                return rtnData;
             }
-            return starts;
-        }
-
-        /// <summary>
-        /// 通过Lq计算当前工序前置准备时间
-        /// </summary>
-        /// <param name="proc"></param>
-        /// <param name="quantity">LeadQuantity to Start Next</param>
-        /// <param name="packages">件数</param>
-        /// <returns></returns>
-        private StartTimeDto CalcProcTakeTimeByLq(mo_mes_tech_process proc, decimal quantity, int packages)
-        {
-            //记录当前工序耗时
-            StartTimeDto dto = new StartTimeDto();
-            //添加耗时记录
-            dto.tech_id = proc.tech_id;
-            dto.proc_id = proc.proc_id;
-            dto.nextproc_id = proc.nextprocid;
-            if (proc.wctype == 1)//人工型:数量/uph(一小时生产数量)*60(小时转换为分钟)/wsinuse(工位数)
+            //今天不是周六周日,需要判断是不是节假日
+            if (holidays.Exists(p => p.Dated.GetValueOrDefault().Date == startTime && p.Ufld1 == "休假"))//是节假日
             {
-                if ( proc.uph.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0)
-                {
-                    throw new NotImplementedException("当前工序uph或wsinuse参数配置错误,请调整!");
-                }
-                dto.wait_time = quantity / proc.uph.GetValueOrDefault() * 60 / proc.wsinuse.GetValueOrDefault();
-                dto.take_time = packages / proc.uph.GetValueOrDefault() * 60 / proc.wsinuse.GetValueOrDefault();
+                //递归继续找下一个工作日
+                rtnData = GetNextWorkDay(startTime.AddDays(1), curCalendars);
+                return rtnData;
             }
-            else if (proc.wctype == 2)//流水线型:数量*ct(生产一件所需时间)/wsinuse(工位数)
-            {
-                if (proc.ct.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0)
-                {
-                    throw new NotImplementedException("当前工序ct或wsinuse参数配置错误,请调整!");
-                }
-                dto.wait_time = quantity * proc.ct.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault();
-                dto.take_time = packages * proc.ct.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault();
-            }
-            else if (proc.wctype == 3)//设备型:向上取整(数量/一次可加工数量/wsinuse(工位数))*ct(老化一次所需时间)
-            {
-                if (proc.upe.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0|| proc.ct.GetValueOrDefault() == 0)
-                {
-                    throw new NotImplementedException("当前工序upe或ct或wsinuse参数配置错误,请调整!");
-                }
-                dto.wait_time = Math.Ceiling(quantity / proc.upe.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault()) * proc.ct.GetValueOrDefault();
-                dto.take_time = Math.Ceiling(packages / proc.upe.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault()) * proc.ct.GetValueOrDefault();
-            }
-            return dto;
+            return rtnData;
         }
 
         /// <summary>
-        /// 通过Lqt计算工艺耗时
+        /// 计算当天的产能
         /// </summary>
-        /// <param name="Processes"></param>
-        /// <param name="packages"></param>
+        /// <param name="startTime"></param>
+        /// <param name="prodLine"></param>
+        /// <param name="curCalendars"></param>
+        /// <param name="curQualityLines"></param>
         /// <returns></returns>
-        private List<StartTimeDto> CalcTakeTimeByLqt(List<mo_mes_tech_process> Processes, int packages)
+        public decimal CalcCapacity(DateTime startTime,ProdLineDetail prodLine, List<ShopCalendarWorkCtr> curCalendars, List<QualityLineWorkDetail> curQualityLines)
         {
-            //工序需要等待时间记录
-            List<StartTimeDto> starts = new List<StartTimeDto>();
-            StartTimeDto dto;
-            foreach (var chd in Processes)
-            {
-                dto = new StartTimeDto();
-                //添加耗时记录
-                dto.tech_id = chd.tech_id;
-                dto.proc_id = chd.proc_id;
-                dto.nextproc_id = chd.nextprocid;
-
-                //计算当前工序生产耗时
-                dto.take_time = CalcProcTakeTime(chd, packages);
-                if (chd.nextprocid == null)//最后一个工序
-                {
-                    dto.wait_time = dto.take_time;
-                }
-                else
-                {
-                    dto.wait_time = chd.lqt.Value;
-                }
-                //添加记录
-                starts.Add(dto);
-            }
-            return starts;
+            decimal sumQty = 0m;
+            //获取休息时长(分钟)
+            decimal sumResrt = curQualityLines.Sum(p => p.RestTime);
+            //获取当天的工作时长(分钟)
+            decimal workTime = curCalendars.First(p => p.WeekDay == (int)startTime.DayOfWeek).ShiftsHours1 * 60;
+            //计算产能
+            sumQty = (workTime - sumResrt) / 60 * prodLine.Rate;
+            return sumQty;
         }
 
-        /// <summary>
-        /// 计算当前工序生产时间
-        /// </summary>
-        /// <param name="proc"></param>
-        /// <param name="packages">件数</param>
-        /// <returns></returns>
-        private decimal CalcProcTakeTime(mo_mes_tech_process proc, int packages)
-        {
-            //当前工序生产时间
-            decimal takeTiem = 0.00m;
-
-            if (proc.wctype == 1)//人工型:数量/uph(一小时生产数量)*60(小时转换为分钟)/wsinuse(工位数)
-            {
-                if (proc.uph.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0)
-                {
-                    throw new NotImplementedException("当前工序uph或wsinuse参数配置错误,请调整!");
-                }
-                takeTiem = packages / proc.uph.GetValueOrDefault() * 60 / proc.wsinuse.GetValueOrDefault();
-            }
-            else if (proc.wctype == 2)//流水线型:数量*ct(生产一件所需时间)/wsinuse(工位数)
-            {
-                if (proc.ct.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0)
-                {
-                    throw new NotImplementedException("当前工序ct或wsinuse参数配置错误,请调整!");
-                }
-                takeTiem = packages * proc.ct.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault();
-            }
-            else if (proc.wctype == 3)//设备型:向上取整(数量/一次可加工数量/wsinuse(工位数))*ct(老化一次所需时间)
-            {
-                if (proc.upe.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0 || proc.ct.GetValueOrDefault() == 0)
-                {
-                    throw new NotImplementedException("当前工序upe或ct或wsinuse参数配置错误,请调整!");
-                }
-                takeTiem = Math.Ceiling(packages / proc.upe.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault()) * proc.ct.GetValueOrDefault();
-            }
-            return takeTiem;
-        }
     }
 }