Преглед на файлове

正常工单排产第一天,处理特殊工单排产调整

heteng преди 2 години
родител
ревизия
b9aea35171

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

@@ -55,5 +55,10 @@ namespace Business.Dto
         /// 工序
         /// </summary>
         public int Op { get; set; }
+
+        /// <summary>
+        /// 工序清场时长(分钟)
+        /// </summary>
+        public decimal WaitTime { get; set; }
     }
 }

+ 307 - 103
MicroServices/Business/Business.Application/ResourceExamineManagement/ProductionScheduleAppService.cs

@@ -197,7 +197,7 @@ namespace Business.ResourceExamineManagement
             decimal lockDays = generalizedCodeMaster != null ? generalizedCodeMaster.UDeci1 : 0;
             
             //获取需要排产的工单(获取四周的工单:正常工单+已审批通过的特殊工单)
-            DateTime endDate = DateTime.Now.Date.AddWeeks(4).AddDays(1);
+            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();
@@ -309,7 +309,7 @@ namespace Business.ResourceExamineManagement
             List<WorkOrdMstDto> workDtos = new List<WorkOrdMstDto>();
             foreach (var item in notSchedules)
             {
-                int op = tsWoRoutings.Where(p => p.WorkOrd == item.WorkOrd).OrderByDescending(p => p.OP).First().OP;
+                var curOp = tsWoRoutings.Where(p => p.WorkOrd == item.WorkOrd).OrderByDescending(p => p.OP).First();
                 workDtos.Add(new WorkOrdMstDto
                 {
                     WorkOrd = item.WorkOrd,
@@ -320,7 +320,8 @@ namespace Business.ResourceExamineManagement
                     LbrVar = item.LbrVar * 60,
                     Worked = 0,
                     QtyWorked = 0,
-                    Op = op
+                    Op = curOp.OP,
+                    WaitTime = curOp.WaitTime * 60
                 });
             }
             TsLineSchedule(workDtos, periodSequenceDtls, scheduleMasters);
@@ -567,24 +568,42 @@ namespace Business.ResourceExamineManagement
                 //记录特殊工单:获取第一天是否有特殊工单
                 List<WorkOrdMaster> fstWOMasters = tsWorkOrds.Where(p => p.ProdLine == lineStart.Line && p.OrdDate.Value.Date == workStartTime.Date).OrderBy(p => p.OrdDate).ToList();
                 List<WorkOrdMstDto> workDtos = new List<WorkOrdMstDto>();
-                foreach (var item in fstWOMasters)
-                {
-                    int op = tsWoRoutings.Where(p => p.WorkOrd == item.WorkOrd).OrderByDescending(p => p.OP).First().OP;
-                    workDtos.Add(new WorkOrdMstDto{
-                        WorkOrd = item.WorkOrd,
-                        ItemNum = item.ItemNum,
-                        QtyOrded = item.QtyOrded,
-                        LbrVar = item.LbrVar * 60,
-                        Worked = 0,
-                        QtyWorked = 0,
-                        Op = op
-                    });
-                }
                 //记录排产开始第二天及以后安排的特殊工单
                 var secWOMasters = new List<WorkOrdMaster>();
-                //特殊工单工作时长(分钟)
-                decimal sumTsTimes = fstWOMasters.Sum(p => p.LbrVar) * 60;
-                while (sumTsTimes > 0) //产线排产开始当天安排了特殊工单,则先安排特殊工单
+                //特殊工单总清场时长(分钟)
+                decimal sumCleanTimes = 0m;
+                //最后一个特殊工单的清场时长(分钟)
+                decimal lstCleanTime = 0m;
+                //新增特殊工单最后一个清场时长
+                decimal secCleanTime = 0m;
+                if (fstWOMasters.Any())
+                {
+                    foreach (var item in fstWOMasters)
+                    {
+                        var curOp = tsWoRoutings.Where(p => p.WorkOrd == item.WorkOrd).OrderByDescending(p => p.OP).First();
+                        workDtos.Add(new WorkOrdMstDto
+                        {
+                            WorkOrd = item.WorkOrd,
+                            ItemNum = item.ItemNum,
+                            QtyOrded = item.QtyOrded,
+                            LbrVar = item.LbrVar * 60,
+                            Worked = 0,
+                            QtyWorked = 0,
+                            Op = curOp.OP,
+                            WaitTime = curOp.WaitTime * 60
+                        });
+                        sumCleanTimes += curOp.WaitTime * 60;
+                    }
+                    //获取最后一个特殊工单的清场时长
+                    var last = fstWOMasters.Last();
+                    lstCleanTime = tsWoRoutings.Where(p => p.WorkOrd == last.WorkOrd).OrderByDescending(p => p.OP).First().WaitTime * 60;
+                }
+                //特殊工单排产需要考虑的时长=特殊工单工作时长(分钟)+除最后一个特殊工单之外的清场时长
+                decimal sumTsTimes = fstWOMasters.Sum(p => p.LbrVar) * 60 + sumCleanTimes - lstCleanTime;
+                //工单排产第一天标识
+                bool isFstDay = true;
+                //产线排产开始当天安排了特殊工单,则先安排特殊工单
+                while (sumTsTimes > 0)
                 {
                     secWOMasters.Clear();
                     //获取当天的产能
@@ -596,67 +615,130 @@ namespace Business.ResourceExamineManagement
                         curCalendar = mLCalendars.FirstOrDefault(p => string.IsNullOrEmpty(p.ProdLine) && p.WeekDay == (int)workStartTime.DayOfWeek);
                     }
                     List<LineWorkPointDto> workPoints = DealWorkDayToLevels(lineStart.Line, workStartTime, curCalendar, mlqtyWorkDtls);
-                    //如果当天的可用产能大于特殊工单生产时长,此时需要考虑当天是否安排了其他的特殊工单
-                    if (dto.EffTime > sumTsTimes)
+                    //特殊工单排产第一天之后:如果当天的可用产能大于特殊工单生产时长,此时需要考虑当天是否安排了其他的特殊工单
+                    if (dto.EffTime > sumTsTimes && !isFstDay)
                     {
                         //获取特殊工单
                         secWOMasters = tsWorkOrds.Where(p => p.ProdLine == lineStart.Line && p.OrdDate.Value.Date == workStartTime.Date).OrderBy(p => p.OrdDate).ToList();
-                        //此时需要过滤掉第一天的工单
-                        secWOMasters = secWOMasters.Where(p=> !workDtos.Select(m=>m.WorkOrd).Contains(p.WorkOrd)).ToList();
-                        //记录新增待排产特殊工单
-                        foreach (var item in secWOMasters)
+                        if (secWOMasters.Any())
                         {
-                            int op = tsWoRoutings.Where(p => p.WorkOrd == item.WorkOrd).OrderByDescending(p => p.OP).First().OP;
-                            workDtos.Add(new WorkOrdMstDto
+                            sumCleanTimes = 0m;
+                            //新增特殊工单最后一个清场时长
+                            secCleanTime = 0m;
+                            //记录新增待排产特殊工单
+                            foreach (var item in secWOMasters)
                             {
-                                WorkOrd = item.WorkOrd,
-                                ItemNum = item.ItemNum,
-                                QtyOrded = item.QtyOrded,
-                                LbrVar = item.LbrVar * 60,
-                                Worked = 0,
-                                QtyWorked = 0,
-                                Op = op
-                            });
+                                var curOp = tsWoRoutings.Where(p => p.WorkOrd == item.WorkOrd).OrderByDescending(p => p.OP).First();
+                                workDtos.Add(new WorkOrdMstDto
+                                {
+                                    WorkOrd = item.WorkOrd,
+                                    ItemNum = item.ItemNum,
+                                    QtyOrded = item.QtyOrded,
+                                    LbrVar = item.LbrVar * 60,
+                                    Worked = 0,
+                                    QtyWorked = 0,
+                                    Op = curOp.OP,
+                                    WaitTime = curOp.WaitTime * 60
+                                });
+                                sumCleanTimes += curOp.WaitTime * 60;
+                            }
+                            //获取最后一个特殊工单的清场时长
+                            var last = secWOMasters.Last();
+                            secCleanTime = tsWoRoutings.Where(p => p.WorkOrd == last.WorkOrd).OrderByDescending(p => p.OP).First().WaitTime * 60;
+                            //特殊工单待排产时长=前一天特殊工单到最后一个清场时长+新增的特殊工单生产时长+新增特殊工单除最后一个清场时长之外的清场时长之和
+                            sumTsTimes += (lstCleanTime + secWOMasters.Sum(p => p.LbrVar) * 60 + sumCleanTimes - secCleanTime);
+                            lstCleanTime = secCleanTime;
                         }
-                        //特殊工单待排产时长增加新增的特殊工单生产时长
-                        sumTsTimes += secWOMasters.Sum(p => p.LbrVar) * 60;
                     }
-                    if (dto.EffTime >= sumTsTimes)//当天的可用生产时长满足特殊工单生产时长
+                    //当天的可用生产时长满足特殊工单生产时长+清场时间(最后一个工单清场时间除外)
+                    if (dto.EffTime >= sumTsTimes)
                     {
+                        //可用生产时长(分钟)
+                        decimal remainTime = dto.EffTime;
                         DateTime beginTime = workStartTime;
                         DateTime endTime = dto.EndTime;
+                        //获取最后一个工单
+                        var lastWork = workDtos.Last();
+                        //开始或结束时间所处时间段
+                        var curPoint = new LineWorkPointDto();
+                        //特殊工单排产
                         foreach (var item in workDtos)
                         {
-                            if (item.LbrVar == item.Worked)//当前工单已排产,跳过
+                            //当前工单已排产,跳过
+                            if (item.LbrVar == item.Worked)
                             {
                                 continue;
                             }
-                            //当前工单还需工作时长
-                            decimal needTime = item.LbrVar - item.Worked;
-                            //计算工单排产结束时间
-                            var curPoint = workPoints.Find(p => p.StartPoint <= beginTime && beginTime <= p.EndPoint);
-                            span = curPoint.EndPoint - beginTime;
-                            //当天工作时间段的有效生产时间(分钟)
-                            decimal effMins = (decimal)span.TotalMinutes;
-                            if (effMins >= needTime)//当前工作时间段即可满足产能
+                            //当前工单排产需要时长
+                            decimal needTime = 0m;
+                            //最后一个特殊工单
+                            if (item.WorkOrd == lastWork.WorkOrd)
                             {
-                                endTime = beginTime.AddMinutes((double)needTime);
+                                //最后一个工单的生产时长+清场时长
+                                needTime = lastWork.QtyOrded - lastWork.QtyWorked + lastWork.WaitTime;
+                                //剩余可用工作时长满足最后一个特殊工单的生产时长+清场时长
+                                if (remainTime >= needTime)
+                                {
+                                    //获取排产结束时间所处以及之后的生产时间段
+                                    var nextPoints = workPoints.Where(p => p.Level >= curPoint.Level).OrderBy(p => p.Level).ToList();
+                                    //处理第一个时间段的开始时间
+                                    nextPoints[0].StartPoint = beginTime;
+                                    foreach (var p in nextPoints)
+                                    {
+                                        span = p.EndPoint - p.StartPoint;
+                                        //当前工作时间段的有效生产时间
+                                        decimal effMins = (decimal)span.TotalMinutes;
+                                        if (effMins >= needTime)
+                                        {
+                                            endTime = p.StartPoint.AddMinutes((double)needTime);
+                                            break;
+                                        }
+                                        needTime -= effMins;
+                                    }
+                                    remainTime -= needTime;
+                                }
+                                //剩余可用工作时长不能满足清场时长
+                                else
+                                {
+                                    endTime = dto.EndTime;
+                                    //还需排产的清场时间
+                                    decimal qcTime = needTime - remainTime;
+                                    endTime.AddMinutes((double)qcTime);
+                                    remainTime = 0;
+                                }
+                                //最后一个工单的清场时长
+                                lstCleanTime = 0m;
                             }
-                            else
-                            {
-                                //获取后续生产时间段
-                                var nextPoints = workPoints.Where(p => p.Level > curPoint.Level).OrderBy(p => p.Level).ToList();
-                                //剩余需要工作时长
-                                decimal nextMins = needTime - effMins;
-                                foreach (var p in nextPoints)
+                            //最后一个特殊工单之前的工单:剩余排产时长和清场时间全部排产
+                            else {
+                                //当前工单还需工作时长+工单的清场时长
+                                needTime = item.LbrVar - item.Worked + item.WaitTime;
+                                //计算工单排产结束时间
+                                curPoint = workPoints.Find(p => p.StartPoint <= beginTime && beginTime <= p.EndPoint);
+                                span = curPoint.EndPoint - beginTime;
+                                //当天工作时间段的有效生产时间(分钟)
+                                decimal effMins = (decimal)span.TotalMinutes;
+                                if (effMins >= needTime)//当前工作时间段即可满足产能
+                                {
+                                    endTime = beginTime.AddMinutes((double)needTime);
+                                }
+                                else
                                 {
-                                    if (p.WorkMinutes >= nextMins)
+                                    //获取后续生产时间段
+                                    var nextPoints = workPoints.Where(p => p.Level > curPoint.Level).OrderBy(p => p.Level).ToList();
+                                    //剩余需要工作时长
+                                    decimal nextMins = needTime - effMins;
+                                    foreach (var p in nextPoints)
                                     {
-                                        endTime = p.StartPoint.AddMinutes((double)nextMins);
-                                        break;
+                                        if (p.WorkMinutes >= nextMins)
+                                        {
+                                            endTime = p.StartPoint.AddMinutes((double)nextMins);
+                                            break;
+                                        }
+                                        nextMins -= p.WorkMinutes;
                                     }
-                                    nextMins -= p.WorkMinutes;
                                 }
+                                remainTime -= needTime;
                             }
                             //记录生产周期
                             curSequences.Add(new PeriodSequenceDet
@@ -688,54 +770,70 @@ namespace Business.ResourceExamineManagement
                                 CreateTime = DateTime.Now
                             });
                             //下一工单开始时间=当前工单结束时间,如果位于工作区间结尾,则为下一工作区间开始时间
-                            curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
-                            if (endTime == curPoint.EndPoint)//结束时间位于工作区间结尾
+                            curPoint = workPoints.FirstOrDefault(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
+                            //结束时间位于工作区间结尾
+                            if (curPoint != null && endTime == curPoint.EndPoint)
                             {
                                 //获取后续生产时间段
-                                var nextPoint = workPoints.Where(p => p.Level == curPoint.Level + 1).FirstOrDefault();
-                                if (nextPoint != null)//存在后续工作区间
+                                curPoint = workPoints.Where(p => p.Level == curPoint.Level + 1).FirstOrDefault();
+                                //存在后续工作区间
+                                if (curPoint != null)
                                 {
-                                    endTime = nextPoint.StartPoint;
+                                    endTime = curPoint.StartPoint;
                                 }
                             }
                             beginTime = endTime;
                             //工单排产完成,排产时长=工单工作时长
                             item.Worked = item.LbrVar;
                             item.QtyWorked = item.QtyOrded;
-                            sumTsTimes -= needTime;
                         }
-                        if (dto.EffTime == sumTsTimes)//当天产能完全占用
+                        //当天产能完全占用,且清场时间在下班后
+                        if (curPoint == null)
                         {
                             sumTsTimes = 0;//排产完毕,特殊工单时长置0
                             //获取下一个工作日
                             workStartTime = GetNextWorkDay((int)workStartTime.DayOfWeek, workStartTime, mLCalendars);
+                            isFstDay = true;
                             //特殊工单排产完成,占用了当天的全部产能,则需要判断下一个工作日是否存在特殊工单,如果存在,则需要继续排特殊工单
                             secWOMasters = tsWorkOrds.Where(p => p.ProdLine == lineStart.Line && p.OrdDate.Value.Date == workStartTime.Date).OrderBy(p => p.OrdDate).ToList();
-                            //此时需要过滤掉已排产的工单
-                            secWOMasters = secWOMasters.Where(p => !workDtos.Select(m => m.WorkOrd).Contains(p.WorkOrd)).ToList();
                             //记录新增待排产特殊工单
-                            foreach (var item in secWOMasters)
+                            if (secWOMasters.Any())
                             {
-                                int op = tsWoRoutings.Where(p => p.WorkOrd == item.WorkOrd).OrderByDescending(p => p.OP).First().OP;
-                                workDtos.Add(new WorkOrdMstDto
+                                sumCleanTimes = 0m;
+                                //新增特殊工单最后一个清场时长(分钟)
+                                secCleanTime = 0m;
+                                foreach (var item in secWOMasters)
                                 {
-                                    WorkOrd = item.WorkOrd,
-                                    ItemNum = item.ItemNum,
-                                    QtyOrded = item.QtyOrded,
-                                    LbrVar = item.LbrVar * 60,
-                                    Worked = 0,
-                                    QtyWorked = 0,
-                                    Op = op
-                                });
+                                    var curOp = tsWoRoutings.Where(p => p.WorkOrd == item.WorkOrd).OrderByDescending(p => p.OP).First();
+                                    workDtos.Add(new WorkOrdMstDto
+                                    {
+                                        WorkOrd = item.WorkOrd,
+                                        ItemNum = item.ItemNum,
+                                        QtyOrded = item.QtyOrded,
+                                        LbrVar = item.LbrVar * 60,
+                                        Worked = 0,
+                                        QtyWorked = 0,
+                                        Op = curOp.OP,
+                                        WaitTime = curOp.WaitTime * 60
+                                    });
+                                    sumCleanTimes += curOp.WaitTime * 60;
+                                }
+                                //获取最后一个特殊工单的清场时长
+                                var last = secWOMasters.Last();
+                                secCleanTime = tsWoRoutings.Where(p => p.WorkOrd == last.WorkOrd).OrderByDescending(p => p.OP).First().WaitTime * 60;
+                                //特殊工单待排产时长=前一天特殊工单到最后一个清场时长+新增的特殊工单生产时长+新增特殊工单除最后一个清场时长之外的清场时长之和
+                                sumTsTimes += (lstCleanTime + secWOMasters.Sum(p => p.LbrVar) * 60 + sumCleanTimes - secCleanTime);
+                                lstCleanTime = secCleanTime;
                             }
-                            //特殊工单待排产时长增加新增带排产特殊工单生产时长
-                            sumTsTimes += secWOMasters.Sum(p => p.LbrVar) * 60;
                         }
-                        else {//当天可用生产时长大于特殊工单生产时长
-                            sumTsTimes = 0;//排产完毕,特殊工单时长置0
+                        //当天可用生产时长大于特殊工单生产时长+清场时长
+                        else
+                        {
+                            //排产完毕,特殊工单时长置0
+                            sumTsTimes = 0;
                             //处理workStartTime
                             workStartTime = endTime;
-                            var curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
+                            curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
                             if (endTime == curPoint.EndPoint)
                             {
                                 var nextPoint = workPoints.Find(p => p.Level == curPoint.Level + 1);
@@ -746,7 +844,8 @@ namespace Business.ResourceExamineManagement
                             }
                         }
                     }
-                    else//当天的可用产能不满足特殊工单生产时长,则当天产能全部排特殊工单
+                    //当天的可用产能不满足特殊工单生产时长,则当天产能全部排特殊工单(至少最后一个特殊工单的生产时长不能满足)
+                    else
                     {
                         decimal residueTime = dto.EffTime;//当天产能剩余产能(分钟)
                         DateTime beginTime = workStartTime;//排产开始时间
@@ -759,7 +858,8 @@ namespace Business.ResourceExamineManagement
                             }
                             //当前工单剩余待排产时长(分钟)
                             decimal needTime = item.LbrVar - item.Worked;
-                            if (residueTime >= needTime)//当天剩余产能满足当前工单的剩余待排产时长
+                            //当天剩余产能满足当前工单的剩余待排产时长
+                            if (residueTime >= needTime)
                             {
                                 //计算工单排产结束时间
                                 var curPoint = workPoints.Find(p => p.StartPoint <= beginTime && beginTime <= p.EndPoint);
@@ -786,6 +886,50 @@ namespace Business.ResourceExamineManagement
                                         nextMins -= p.WorkMinutes;
                                     }
                                 }
+                                //当天剩余产能
+                                residueTime -= needTime;
+                                //处理清场时间,两种场景:
+                                //1、residueTime<=item.WaitTime,结束时间加上剩余清场时长
+                                if (residueTime <= item.WaitTime)
+                                {
+                                    decimal otherTime = item.WaitTime - residueTime;
+                                    endTime = dto.EndTime.AddMinutes((double)otherTime);
+                                    residueTime = 0;
+                                }
+                                //2、residueTime>item.WaitTime,剩余时长大于,清场时长,需要过滤休息时间
+                                else
+                                {
+                                    //清场时长
+                                    needTime = item.WaitTime;
+                                    //获取工单排产结束时间所处时间段
+                                    curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
+                                    span = curPoint.EndPoint - endTime;
+                                    //当前工作时间段的有效生产时间(分钟)
+                                    effMins = (decimal)span.TotalMinutes;
+                                    //当前工作时间段即可清场时长
+                                    if (effMins >= needTime)
+                                    {
+                                        endTime = endTime.AddMinutes((double)needTime);
+                                    }
+                                    else
+                                    {
+                                        //获取后续生产时间段
+                                        var nextPoints = workPoints.Where(p => p.Level > curPoint.Level).OrderBy(p => p.Level).ToList();
+                                        //剩余需要工作时长
+                                        decimal nextMins = needTime - effMins;
+                                        foreach (var p in nextPoints)
+                                        {
+                                            if (p.WorkMinutes >= nextMins)
+                                            {
+                                                endTime = p.StartPoint.AddMinutes((double)nextMins);
+                                                break;
+                                            }
+                                            nextMins -= p.WorkMinutes;
+                                        }
+                                    }
+                                    residueTime -= needTime;
+                                }
+
                                 //记录生产周期
                                 curSequences.Add(new PeriodSequenceDet
                                 {
@@ -815,27 +959,28 @@ namespace Business.ResourceExamineManagement
                                     WorkEndTime = endTime,
                                     CreateTime = DateTime.Now
                                 });
+                                //当前工单已排产完成,已排产时间=工单生产时长,已排产数量=工单数量
+                                item.Worked = item.LbrVar;
+                                item.QtyWorked = item.QtyWorked;
+
                                 beginTime = endTime;
+                                //获取结束时间所处时间段
                                 curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
-                                if (endTime == curPoint.EndPoint)
+                                if (curPoint != null && endTime == curPoint.EndPoint)
                                 {
                                     var nextPoint = workPoints.Find(p => p.Level == curPoint.Level + 1);
                                     if (nextPoint != null)
                                     {
-                                        beginTime = nextPoint.StartPoint;
+                                        endTime = nextPoint.StartPoint;
                                     }
+                                    beginTime = endTime;
                                 }
-                                //当前工单已排产完成,已排产时间=工单生产时长,已排产数量=工单数量
-                                item.Worked = item.LbrVar;
-                                item.QtyWorked = item.QtyWorked;
-                                //当天剩余产能
-                                residueTime -= needTime;
-                                if (residueTime == 0)
-                                {
+                                else {
                                     break;
                                 }
                             }
-                            else//当天剩余产能不满足当前工单的剩余待排产时长
+                            //当天剩余产能不满足当前工单的剩余待排产时长
+                            else
                             {
                                 //计算生产数量
                                 decimal qty = Math.Ceiling(residueTime / item.LbrVar * item.QtyOrded);
@@ -871,13 +1016,14 @@ namespace Business.ResourceExamineManagement
                                 item.Worked += residueTime;
                                 item.QtyWorked += qty;
                                 residueTime = 0;
+                                //特殊工单剩余待排产时长(分钟)
+                                sumTsTimes -= residueTime;
                                 break;
                             }
                         }
-                        //特殊工单剩余待排产时长(分钟)
-                        sumTsTimes -= dto.EffTime;
                         //获取下一个工作日
                         workStartTime = GetNextWorkDay((int)workStartTime.DayOfWeek, workStartTime, mLCalendars);
+                        isFstDay = false;
                     }
                 }
                 //记录已排产特殊工单
@@ -891,8 +1037,8 @@ namespace Business.ResourceExamineManagement
                 fstWOMasters.Clear();
                 workDtos.Clear();
                 sumTsTimes = 0m;
-                //正常工单排产第一天标识
-                bool isFstDay = true;
+                //工单排产第一天标识
+                isFstDay = true;
                 //前一天是否有特殊工单未排产完全
                 bool isFullPC = true;
                 while (sumQty < workOrd.QtyOrded || sumTsTimes > 0)
@@ -2593,7 +2739,7 @@ namespace Business.ResourceExamineManagement
         {
             foreach (var item in workOrds)
             {
-                //工单生产时长(分钟)
+                //工单生产时长(分钟)
                 decimal sumTimes = item.LbrVar;
                 //工单的排产开始时间
                 DateTime workStartTime = item.OrdDate;
@@ -2619,7 +2765,7 @@ namespace Business.ResourceExamineManagement
                     //获取当天的产能
                     LineScheduledDto dto = GetScheduledPoint(lineStart, workStartTime, mLCalendars, mlqtyWorkDtls);
                     //当天的可用生产时长不能满足特殊工单生产时长
-                    if (dto.EffTime <= sumTimes)
+                    if (dto.EffTime < sumTimes)
                     {
                         decimal qty = Math.Ceiling(dto.EffTime / item.LbrVar * item.QtyOrded);
                         //记录生产周期
@@ -2655,14 +2801,19 @@ namespace Business.ResourceExamineManagement
                         sumTimes -= dto.EffTime;
                         //已排产数量
                         item.QtyWorked += qty;
+                        item.Worked += dto.EffTime;
                         //继续排下一个工作日
                         workStartTime = GetNextWorkDay((int)workStartTime.DayOfWeek, workStartTime, mLCalendars);
                     }
-                    else// 最后一天的产能只能占用一部分
+                    //最后一天的产能全部占用或只能占用一部分
+                    else
                     {
                         //剩余生产时长(分钟)
                         decimal workTime = sumTimes;
+                        //排产开始时间位于哪个时间段
                         var curPoint = workPoints.Find(p => p.StartPoint <= workStartTime && workStartTime <= p.EndPoint);
+                        //结束时间位于时间段
+                        var lastPoint = new LineWorkPointDto();
                         TimeSpan span = curPoint.EndPoint - workStartTime;
                         //当前工作时间段的有效生产时间
                         decimal effMins = (decimal)span.TotalMinutes;
@@ -2681,12 +2832,45 @@ namespace Business.ResourceExamineManagement
                             {
                                 if (p.WorkMinutes >= nextMins)
                                 {
+                                    //记录结束时间位于哪个时间段
+                                    lastPoint = p;
                                     workEndTime = p.StartPoint.AddMinutes((double)nextMins);
                                     break;
                                 }
                                 nextMins -= p.WorkMinutes;
                             }
                         }
+                        //计算清场时间
+                        //剩余可用工作时长(分钟)
+                        decimal remainTime = CalcRemainWorkTime(workEndTime,workPoints);
+                        //剩余可用工作时长满足清场时长
+                        if (remainTime >= item.WaitTime)
+                        {
+                            //清场需要时长(分钟)
+                            decimal needTime = item.WaitTime;
+                            //获取排产结束时间所处以及之后的生产时间段
+                            var nextPoints = workPoints.Where(p => p.Level >= lastPoint.Level).OrderBy(p => p.Level).ToList();
+                            //处理第一个时间段的开始时间
+                            nextPoints[0].StartPoint = workEndTime;
+                            foreach (var p in nextPoints)
+                            {
+                                span = p.EndPoint - p.StartPoint;
+                                //当前工作时间段的有效生产时间
+                                effMins = (decimal)span.TotalMinutes;
+                                if (effMins >= needTime)
+                                {
+                                    workEndTime = p.StartPoint.AddMinutes((double)needTime);
+                                    break;
+                                }
+                                needTime -= effMins;
+                            }
+                        }
+                        //剩余可用工作时长不能满足清场时长
+                        else
+                        {
+                            decimal needTime = item.WaitTime - remainTime;
+                            workEndTime.AddMinutes((double)needTime);
+                        }
                         //记录生产周期
                         periodsDet.Add(new PeriodSequenceDet
                         {
@@ -2723,6 +2907,26 @@ namespace Business.ResourceExamineManagement
             }
         }
 
+        /// <summary>
+        /// 计算当天排产完成的剩余生产时长
+        /// </summary>
+        /// <param name="endTime">排产结束时间</param>
+        /// <param name="workPoints">当天的工作时间段</param>
+        /// <returns></returns>
+        public decimal CalcRemainWorkTime(DateTime endTime, List<LineWorkPointDto> workPoints)
+        {
+            decimal remainTime = 0m;
+            var curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
+            TimeSpan span = curPoint.EndPoint - endTime;
+            remainTime = (decimal)span.TotalMinutes;
+            var nextPoints = workPoints.Where(p => p.Level > curPoint.Level).OrderBy(p => p.Level).ToList();
+            foreach (var item in nextPoints)
+            {
+                remainTime += item.WorkMinutes;
+            }
+            return remainTime;
+        }
+
         /// <summary>
         /// 获取产线当天的开工时间,结束时间,有效工作时长,生产数量
         /// </summary>

+ 1 - 1
MicroServices/Business/Business.Application/ResourceExamineManagement/ResourceExamineAppService.cs

@@ -4128,7 +4128,7 @@ namespace Business.ResourceExamineManagement
             decimal lockDays = generalizedCodeMaster != null ? generalizedCodeMaster.UDeci1 : 0;
 
             //获取需要排产的工单(获取四周的工单:正常工单+已审批通过的特殊工单)
-            DateTime endDate = DateTime.Now.Date.AddWeeks(4).AddDays(1);
+            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();

+ 6 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/WorkOrdRouting.cs

@@ -81,6 +81,12 @@ namespace Business.Domain
         [Comment("订单数量")]
         public decimal? QtyOrded { get; set; }
 
+        /// <summary>
+        /// 工序清场时长(小时)
+        /// </summary>
+        [Comment("工序清场时长")]
+        public decimal WaitTime { get; set; }
+
         /// <summary>
         /// 平行加工件数,下序开工前置数量
         /// </summary>