Pārlūkot izejas kodu

排产添加特殊工单排产

heteng 2 gadi atpakaļ
vecāks
revīzija
53932ae1d1

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

@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Business.Dto
+{
+    /// <summary>
+    /// 特殊工单排产Dto
+    /// </summary>
+    public class WorkOrdMstDto
+    {
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string WorkOrd { get; set; }
+
+        /// <summary>
+        /// 物料编号
+        /// </summary>
+        public string ItemNum { get; set; }
+
+        /// <summary>
+        /// 工单数量
+        /// </summary>
+        public decimal QtyOrded { get; set; }
+
+        /// <summary>
+        /// 工单生产时长(分钟)
+        /// </summary>
+        public decimal LbrVar { get; set; }
+
+        /// <summary>
+        /// 已排产时长(分钟)
+        /// </summary>
+        public decimal Worked { get; set; }
+
+        /// <summary>
+        /// 已排产数量
+        /// </summary>
+        public decimal QtyWorked { get; set; }
+
+        /// <summary>
+        /// 工序
+        /// </summary>
+        public int Op { get; set; }
+    }
+}

+ 378 - 88
MicroServices/Business/Business.Application/ResourceExamineManagement/ProductionScheduleAppService.cs

@@ -183,7 +183,7 @@ namespace Business.ResourceExamineManagement
         #endregion
 
         /// <summary>
-        /// 执行生产排产
+        /// 生产排产-定时任务
         /// </summary>
         public async void DoExt()
         {
@@ -191,24 +191,21 @@ namespace Business.ResourceExamineManagement
             IConfiguration configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).Build();
             domain = configuration.GetConnectionString("Factory_id");
 
-            //获取提前期
-            var generalizedCodeMaster = _generalizedCodeMaster.Select(x => x.FldName == "SystemConfig" && x.Val == "WorkOrderLockPeriod" && x.Domain == domain).FirstOrDefault();
-            decimal Udecil = 0;
-            if (generalizedCodeMaster != null)
-            {
-                Udecil = generalizedCodeMaster.UDeci1;
-            }
-            //排产取4周工单排产
-            DateTime dateTime = DateTime.Now.AddDays(30);
-            DateTime date = DateTime.Now.AddDays((double)Udecil);
-            var workOrds = _workOrdMaster.Select(x => x.IsActive && x.Domain == domain && x.OrdDate < dateTime && x.OrdDate > date && x.Status == "初始").ToList();
+            //获取排产锁定期
+            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.AddWeeks(4).AddDays(1);
+            DateTime startDate = DateTime.Now.Date;
+            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 DoProductSchedule(workOrds, domain, 1);
         }
 
         /// <summary>
         /// 生产排产
         /// </summary>
-        /// <param name="workOrds">工单:定时任务执行时count=0;资源检查调用count>0</param>
+        /// <param name="workOrds">工单</param>
         /// <param name="factoryid">工单的工厂id</param>
         /// <param name="type">排产类型:1-自动排产;2-手动排产</param>
         /// <returns></returns>
@@ -223,9 +220,16 @@ namespace Business.ResourceExamineManagement
             //获取排产工单的最早计划开工日期
             DateTime earlist = DateTime.Now.Date.AddDays(1);
 
+            //特殊工单指定时间开工,不需要计算产能,只需要计算时长即可
+            var tsWorkOrds = workOrds.Where(p => !string.IsNullOrEmpty(p.Typed)).ToList();
+            //正常工单
+            var zcWorkOrds = workOrds.Where(p => string.IsNullOrEmpty(p.Typed)).ToList();
+
             //2、获取数据
             //获取工单工艺路径数据
             List<WorkOrdRouting> workOrdRoutings = _workOrdRouting.Select(p => workOrds.Select(m => m.WorkOrd).Contains(p.WorkOrd) && p.ParentOp == 0 && p.Domain == domain && p.Status != "C" && p.IsActive);
+            //特殊工单的工艺路线
+            List<WorkOrdRouting> tsWoRoutings = workOrdRoutings.Where(p => tsWorkOrds.Select(m => m.WorkOrd).Contains(p.WorkOrd)).ToList();
             //获取物料对应的生产线信息:物料、工序对应的生产线
             List<ProdLineDetail> prodLines = _prodLineDetail.Select(p => workOrds.Select(m => m.ItemNum).Contains(p.Part) && p.Domain == domain && p.IsActive);
             List<string> lines = prodLines.Select(p => p.Line).ToList();
@@ -233,9 +237,9 @@ namespace Business.ResourceExamineManagement
             prodLineDetailRunCrews = _prodLineDetailRunCrew.Select(x => prodLines.Select(p => p.RecID).Contains(x.ProdLineDetailRecID) && x.IsActive && x.Domain == domain).ToList();
             //获取加班设置
             resourceOccupancyTimes = _resourceOccupancyTime.Select(x => prodLines.Select(p => p.Line).Contains(x.Resource) && x.IsActive && x.Domain == domain && x.StartTime.Value > DateTime.Now).ToList();
-            //获取生产周期数据
+            //获取生产周期数据,TODO:需要过滤锁定期之外的工单
             List<PeriodSequenceDet> dbPeriodSequences = _periodSequenceDet.Select(p => lines.Contains(p.Line) && p.PlanDate >= earlist && p.Domain == domain && p.IsActive);
-            //获取当前日期往后的排产记录数据
+            //获取当前日期往后的排产记录数据,TODO:需要过滤锁定期之外的工单
             List<ScheduleResultOpMaster> dbSchedules = _scheduleResultOpMaster.Select(p => lines.Contains(p.Line) && p.WorkDate >= earlist && p.Domain == domain);
             //获取工作日历数据:产线的工作日历+默认的工作日历
             calendars = _shopCalendarWorkCtr.Select(p => (lines.Contains(p.ProdLine) || string.IsNullOrEmpty(p.ProdLine)) && p.Domain == domain && p.IsActive);
@@ -273,7 +277,9 @@ namespace Business.ResourceExamineManagement
             //排产结果
             List<ScheduleResultOpMaster> allResults = new List<ScheduleResultOpMaster>();
             allResults.AddRange(dbSchedules);
-            foreach (var item in workOrds)
+            //记录特殊工单排产结果
+            List<string> ypcWorkOrds = new List<string>();
+            foreach (var item in zcWorkOrds)
             {
                 //记录产线占用情况
                 allResults.AddRange(scheduleMasters);
@@ -283,7 +289,7 @@ namespace Business.ResourceExamineManagement
                 var curProdLines = prodLines.Where(p => p.Part == item.ItemNum).ToList();
                 
                 //产线排产
-                LineSchedule(item, curRoutings, curProdLines, periodSequenceDtls, scheduleMasters, allResults);
+                LineSchedule(item, curRoutings, curProdLines, periodSequenceDtls, scheduleMasters, allResults, tsWorkOrds, ypcWorkOrds, tsWoRoutings);
 
                 List<ScheduleResultOpMaster> scheduleList = scheduleMasters.Where(s => s.WorkOrd == item.WorkOrd).ToList();
                 if (scheduleList.Any())
@@ -324,6 +330,23 @@ namespace Business.ResourceExamineManagement
             ScheduleExceptionMaster entity;
             foreach (var item in workOrds)
             {
+                if (!string.IsNullOrEmpty(item.Typed))//特殊工单
+                {
+                    //只需要校验有没有维护工艺路线即可
+                    var routings = workOrdRoutings.Where(p=>p.ItemNum == item.ItemNum).ToList();
+                    if (!routings.Any())
+                    {
+                        entity = new ScheduleExceptionMaster();
+                        entity.Domain = item.Domain;
+                        entity.WorkOrd = item.WorkOrd;
+                        entity.ItemNum = item.ItemNum;
+                        entity.CreateTime = DateTime.Now;
+                        entity.Remark = "排产异常:工单没有维护工艺路线,请维护后再操作!";
+                        entity.Type = type == 1 ? "自动排产" : "手动排产";
+                        exceptions.Add(entity);
+                    }
+                    continue;
+                }
                 var curRoutings = workOrdRoutings.Where(p => p.ItemNum == item.ItemNum && p.MilestoneOp).OrderBy(p=>p.OP).Select(p=>p.OP).ToList();
                 //判断当前工单主产线是否设置了关键工序
                 if (!curRoutings.Any())//当前工单没有维护关键工序
@@ -440,7 +463,10 @@ namespace Business.ResourceExamineManagement
         /// <param name="periodsDet">生产周期</param>
         /// <param name="scheduleResults">排产结果</param>
         /// <param name="allResults">产线占用记录</param>
-        public void LineSchedule(WorkOrdMaster workOrd, List<WorkOrdRouting> workOrdRoutings, List<ProdLineDetail> prodLines,List<PeriodSequenceDet> periodsDet, List<ScheduleResultOpMaster> scheduleResults, List<ScheduleResultOpMaster> allResults)
+        /// <param name="tsWorkOrds">特殊工单</param>
+        /// <param name="ypcWorkOrds">已排产特殊工单的工单编号</param>
+        /// <param name="tsWoRoutings">特殊工单的工艺路线</param>
+        public void LineSchedule(WorkOrdMaster workOrd, List<WorkOrdRouting> workOrdRoutings, List<ProdLineDetail> prodLines,List<PeriodSequenceDet> periodsDet, List<ScheduleResultOpMaster> scheduleResults, List<ScheduleResultOpMaster> allResults,List<WorkOrdMaster> tsWorkOrds,List<string> ypcWorkOrds, List<WorkOrdRouting> tsWoRoutings)
         {
             //生产周期
             List<PeriodSequenceDet> curSequences = new List<PeriodSequenceDet>();
@@ -448,6 +474,7 @@ namespace Business.ResourceExamineManagement
             List<ScheduleResultOpMaster> curScheduleRsts = new List<ScheduleResultOpMaster>();
             //记录上一产线排产开始时间
             LineStartDto lineStart = new LineStartDto();
+            TimeSpan span = TimeSpan.Zero;
             //第一层级工序有几个关键工序,就有几条产线
             for (int i = 0; i < workOrdRoutings.Count; i++)
             {
@@ -471,6 +498,254 @@ namespace Business.ResourceExamineManagement
                 decimal sumTimes = 0m;
                 //产线排产开始时间
                 DateTime workStartTime = lineStart.StartTime;
+                //记录特殊工单:获取第一天是否有特殊工单
+                var 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
+                    });
+                }
+                //特殊工单工作时长
+                decimal sumTsTimes = fstWOMasters.Sum(p=>p.LbrVar);
+                //特殊工单排产结束当天占用的产能时长
+                decimal dayOccupyTimes = 0m;
+                while (sumTsTimes > 0) //产线排产开始当天安排了特殊工单,则先安排特殊工单
+                {
+                    //获取当天的产能
+                    LineScheduledDto dto = GetScheduledPoint(lineStart, workStartTime, mLCalendars, mlqtyWorkDtls);
+                    //获取当天的工作时间段
+                    var curCalendar = mLCalendars.FirstOrDefault(p => !string.IsNullOrEmpty(p.ProdLine) && p.WeekDay == (int)workStartTime.DayOfWeek);
+                    if (curCalendar == null)
+                    {
+                        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)//当天的可用产能满足特殊工单生产时长
+                    {
+                        DateTime beginTime = workStartTime;
+                        DateTime endTime = DateTime.Now;
+                        foreach (var item in workDtos)
+                        {
+                            if (item.LbrVar == item.Worked)//当前工单已排产
+                            {
+                                continue;
+                            }
+                            //工单排产完成,排产时长=工单工作时长
+                            item.Worked = item.LbrVar;
+                            //当前工单还需工作时长
+                            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)//当前工作时间段即可满足产能
+                            {
+                                endTime = beginTime.AddMinutes((double)needTime);
+                            }
+                            else
+                            {
+                                //获取后续生产时间段
+                                var nextPoints = workPoints.Where(p => p.Level > curPoint.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;
+                                }
+                            }
+                            //记录生产周期
+                            curSequences.Add(new PeriodSequenceDet
+                            {
+                                Domain = domain,
+                                Line = lineStart.Line,
+                                ItemNum = item.ItemNum,
+                                PlanDate = beginTime.Date,
+                                Period = dto.Period,
+                                OrdQty = item.QtyOrded - item.QtyWorked,
+                                WorkOrds = item.WorkOrd,
+                                Op = item.Op,
+                                IsActive = true,
+                                Status = "",
+                                CreateTime = DateTime.Now
+                            });
+                            //记录排产记录
+                            curScheduleRsts.Add(new ScheduleResultOpMaster
+                            {
+                                Domain = domain,
+                                WorkOrd = item.WorkOrd,
+                                Line = lineStart.Line,
+                                ItemNum = item.ItemNum,
+                                Op = item.Op,
+                                WorkDate = beginTime.Date,
+                                WorkQty = item.QtyOrded - item.QtyWorked,
+                                WorkStartTime = beginTime,
+                                WorkEndTime = endTime,
+                                CreateTime = DateTime.Now
+                            });
+                            //下一工单开始时间=当前工单结束时间,如果位于工作区间结尾,则为下一工作区间开始时间
+                            curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
+                            if (endTime == curPoint.EndPoint)//结束时间位于工作区间结尾
+                            {
+                                //获取后续生产时间段
+                                var nextPoint = workPoints.Where(p => p.Level == curPoint.Level + 1).FirstOrDefault();
+                                if (nextPoint != null)//存在后续工作区间
+                                {
+                                    endTime = nextPoint.StartPoint;
+                                }
+                            }
+                            beginTime = endTime;
+                        }
+                        dayOccupyTimes = sumTsTimes;
+                        if (dto.EffTime == sumTsTimes)//当天产能完全占用
+                        {
+                            //获取下一个工作日
+                            workStartTime = GetNextWorkDay((int)workStartTime.DayOfWeek, workStartTime, mLCalendars);
+                            dayOccupyTimes = 0m;
+                        }
+                        sumTsTimes = 0;//排产完毕,特殊工单时长置0
+                    }
+                    else//当天的可用产能不满足特殊工单生产时长
+                    {
+                        decimal residueTime = dto.EffTime * 60;//当天产能剩余产能(分钟)
+                        DateTime beginTime = workStartTime;//排产开始时间
+                        DateTime endTime = dto.EndTime;//排产结束时间
+                        foreach (var item in workDtos)
+                        {
+                            if (item.LbrVar == item.Worked)//当前工单已排产
+                            {
+                                continue;
+                            }
+                            //当前工单剩余待排产时长(分钟)
+                            decimal needTime = item.LbrVar - item.Worked;
+                            if (residueTime >= needTime)//当天剩余产能满足当前工单的剩余待排产时长
+                            {
+                                //计算工单排产结束时间
+                                var 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
+                                {
+                                    //获取后续生产时间段
+                                    var nextPoints = workPoints.Where(p => p.Level > curPoint.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;
+                                    }
+                                }
+                                //记录生产周期
+                                curSequences.Add(new PeriodSequenceDet
+                                {
+                                    Domain = domain,
+                                    Line = lineStart.Line,
+                                    ItemNum = item.ItemNum,
+                                    PlanDate = beginTime.Date,
+                                    Period = dto.Period,
+                                    OrdQty = item.QtyOrded - item.QtyWorked,
+                                    WorkOrds = item.WorkOrd,
+                                    Op = item.Op,
+                                    IsActive = true,
+                                    Status = "",
+                                    CreateTime = DateTime.Now
+                                });
+                                //记录排产记录
+                                curScheduleRsts.Add(new ScheduleResultOpMaster
+                                {
+                                    Domain = domain,
+                                    WorkOrd = item.WorkOrd,
+                                    Line = lineStart.Line,
+                                    ItemNum = item.ItemNum,
+                                    Op = item.Op,
+                                    WorkDate = beginTime.Date,
+                                    WorkQty = item.QtyOrded - item.QtyWorked,
+                                    WorkStartTime = beginTime,
+                                    WorkEndTime = endTime,
+                                    CreateTime = DateTime.Now
+                                });
+                                beginTime = endTime;
+                                //当前工单已排产完成,已排产时间=工单生产时长,已排产数量=工单数量
+                                item.Worked = item.LbrVar;
+                                item.QtyWorked = item.QtyWorked;
+                                //当天剩余产能
+                                residueTime -= needTime;
+                                if (residueTime == 0)
+                                {
+                                    break;
+                                }
+                            }
+                            else//当天剩余产能不满足当前工单的剩余待排产时长
+                            {
+                                //计算生产数量
+                                decimal qty = Math.Ceiling(residueTime / item.LbrVar * item.QtyOrded);
+                                //记录生产周期
+                                curSequences.Add(new PeriodSequenceDet
+                                {
+                                    Domain = domain,
+                                    Line = lineStart.Line,
+                                    ItemNum = item.ItemNum,
+                                    PlanDate = beginTime.Date,
+                                    Period = dto.Period,
+                                    OrdQty = qty,
+                                    WorkOrds = item.WorkOrd,
+                                    Op = item.Op,
+                                    IsActive = true,
+                                    Status = "",
+                                    CreateTime = DateTime.Now
+                                });
+                                //记录排产记录
+                                curScheduleRsts.Add(new ScheduleResultOpMaster
+                                {
+                                    Domain = domain,
+                                    WorkOrd = item.WorkOrd,
+                                    Line = lineStart.Line,
+                                    ItemNum = item.ItemNum,
+                                    Op = item.Op,
+                                    WorkDate = beginTime.Date,
+                                    WorkQty = qty,
+                                    WorkStartTime = beginTime,
+                                    WorkEndTime = endTime,
+                                    CreateTime = DateTime.Now
+                                });
+                                item.Worked += residueTime;
+                                item.QtyWorked += qty;
+                                residueTime = 0;
+                                break;
+                            }
+                        }
+                        //特殊工单剩余待排产时长
+                        sumTsTimes -= dto.EffTime;
+                        //获取下一个工作日
+                        workStartTime = GetNextWorkDay((int)workStartTime.DayOfWeek, workStartTime, mLCalendars);
+                    }
+                }
+                //记录排产开始第二天及以后安排的特殊工单
+                var secWOMasters = new List<WorkOrdMaster>();
                 //排产
                 while (sumQty < workOrd.QtyOrded)
                 {
@@ -533,11 +808,11 @@ namespace Business.ResourceExamineManagement
                                 {
                                     curCalendar = mLCalendars.FirstOrDefault(p => string.IsNullOrEmpty(p.ProdLine) && p.WeekDay == (int)workStartTime.DayOfWeek);
                                 }
-                                List<LineWorkPointDto> workPoints = DealWorkDayToLevels(workStartTime, curCalendar, mlqtyWorkDtls);
+                                List<LineWorkPointDto> workPoints = DealWorkDayToLevels(lineStart.Line, workStartTime, curCalendar, mlqtyWorkDtls);
                                 var curPoint = workPoints.Find(p => p.StartPoint <= workStartTime && workStartTime <= p.EndPoint);
                                 if (curPoint != null)
                                 {
-                                    TimeSpan span = curPoint.EndPoint - workStartTime;
+                                    span = curPoint.EndPoint - workStartTime;
                                     //当天工作时间段的有效生产时间
                                     decimal effMins = (decimal)span.TotalMinutes;
                                     DateTime workEndTime = workStartTime;
@@ -595,14 +870,16 @@ namespace Business.ResourceExamineManagement
                             }
                             sumTimes = lineStart.setupTime;
                         }
-                        else {
+                        else
+                        {
                             //当天的可用生产时长不能满足提前期
                             sumTimes += dto.EffTime;
                             //获取下一个工作日
                             workStartTime = GetNextWorkDay((int)workStartTime.DayOfWeek, workStartTime, mLCalendars);
                         }
                     }
-                    else {
+                    else
+                    {
                         //判断已排产数量+当天的产能是否超过工单数量
                         if (sumQty + dto.ProductQty <= workOrd.QtyOrded)//当天的产能需要全部排产
                         {
@@ -613,7 +890,7 @@ namespace Business.ResourceExamineManagement
                                 Line = lineStart.Line,
                                 ItemNum = workOrd.ItemNum,
                                 PlanDate = workStartTime.Date,
-                                Period = dto.Period,//目前只考虑一班制
+                                Period = dto.Period,
                                 OrdQty = dto.ProductQty,
                                 WorkOrds = workOrd.WorkOrd,
                                 Op = lineStart.Op,
@@ -652,65 +929,62 @@ namespace Business.ResourceExamineManagement
                             {
                                 curCalendar = mLCalendars.FirstOrDefault(p => string.IsNullOrEmpty(p.ProdLine) && p.WeekDay == (int)workStartTime.DayOfWeek);
                             }
-                            List<LineWorkPointDto> workPoints = DealWorkDayToLevels(workStartTime, curCalendar, mlqtyWorkDtls);
+                            List<LineWorkPointDto> workPoints = DealWorkDayToLevels(lineStart.Line, workStartTime, curCalendar, mlqtyWorkDtls);
                             var curPoint = workPoints.Find(p => p.StartPoint <= workStartTime && workStartTime <= p.EndPoint);
-                            if (curPoint != null)
+                            span = curPoint.EndPoint - workStartTime;
+                            //当天工作时间段的有效生产时间
+                            decimal effMins = (decimal)span.TotalMinutes;
+                            DateTime workEndTime = workStartTime;
+                            if (effMins >= workTime)//当前工作时间段即可满足产能
                             {
-                                TimeSpan span = curPoint.EndPoint - workStartTime;
-                                //当天工作时间段的有效生产时间
-                                decimal effMins = (decimal)span.TotalMinutes;
-                                DateTime workEndTime = workStartTime;
-                                if (effMins >= workTime)//当前工作时间段即可满足产能
-                                {
-                                    workEndTime = workStartTime.AddMinutes((double)workTime);
-                                }
-                                else
+                                workEndTime = workStartTime.AddMinutes((double)workTime);
+                            }
+                            else
+                            {
+                                //获取后续生产时间段
+                                var nextPoints = workPoints.Where(p => p.Level > curPoint.Level).ToList();
+                                //剩余需要工作时长
+                                decimal nextMins = workTime - effMins;
+                                foreach (var p in nextPoints)
                                 {
-                                    //获取后续生产时间段
-                                    var nextPoints = workPoints.Where(p => p.Level > curPoint.Level).ToList();
-                                    //剩余需要工作时长
-                                    decimal nextMins = workTime - effMins;
-                                    foreach (var p in nextPoints)
+                                    if (p.WorkMinutes >= nextMins)
                                     {
-                                        if (p.WorkMinutes >= nextMins)
-                                        {
-                                            workEndTime = p.StartPoint.AddMinutes((double)nextMins);
-                                            break;
-                                        }
-                                        nextMins -= p.WorkMinutes;
+                                        workEndTime = p.StartPoint.AddMinutes((double)nextMins);
+                                        break;
                                     }
+                                    nextMins -= p.WorkMinutes;
                                 }
-                                sumQty = workOrd.QtyOrded;
-                                //记录生产周期
-                                curSequences.Add(new PeriodSequenceDet
-                                {
-                                    Domain = domain,
-                                    Line = lineStart.Line,
-                                    ItemNum = workOrd.ItemNum,
-                                    PlanDate = workStartTime.Date,
-                                    Period = dto.Period,//目前只考虑一班制
-                                    OrdQty = residueQty,
-                                    WorkOrds = workOrd.WorkOrd,
-                                    Op = lineStart.Op,
-                                    IsActive = true,
-                                    Status = "",
-                                    CreateTime = DateTime.Now
-                                });
-                                //记录排产记录
-                                curScheduleRsts.Add(new ScheduleResultOpMaster
-                                {
-                                    Domain = domain,
-                                    WorkOrd = workOrd.WorkOrd,
-                                    Line = lineStart.Line,
-                                    ItemNum = workOrd.ItemNum,
-                                    Op = lineStart.Op,
-                                    WorkDate = workStartTime.Date,
-                                    WorkQty = residueQty,
-                                    WorkStartTime = workStartTime,
-                                    WorkEndTime = workEndTime,
-                                    CreateTime = DateTime.Now
-                                });
                             }
+                            sumQty = workOrd.QtyOrded;
+                            //记录生产周期
+                            curSequences.Add(new PeriodSequenceDet
+                            {
+                                Domain = domain,
+                                Line = lineStart.Line,
+                                ItemNum = workOrd.ItemNum,
+                                PlanDate = workStartTime.Date,
+                                Period = dto.Period,
+                                OrdQty = residueQty,
+                                WorkOrds = workOrd.WorkOrd,
+                                Op = lineStart.Op,
+                                IsActive = true,
+                                Status = "",
+                                CreateTime = DateTime.Now
+                            });
+                            //记录排产记录
+                            curScheduleRsts.Add(new ScheduleResultOpMaster
+                            {
+                                Domain = domain,
+                                WorkOrd = workOrd.WorkOrd,
+                                Line = lineStart.Line,
+                                ItemNum = workOrd.ItemNum,
+                                Op = lineStart.Op,
+                                WorkDate = workStartTime.Date,
+                                WorkQty = residueQty,
+                                WorkStartTime = workStartTime,
+                                WorkEndTime = workEndTime,
+                                CreateTime = DateTime.Now
+                            });
                         }
                     }
                 }
@@ -743,7 +1017,7 @@ namespace Business.ResourceExamineManagement
                 shopCal = curCalendars.Where(p =>string.IsNullOrEmpty(p.ProdLine) && p.WeekDay == weekDay).FirstOrDefault();
             }
             //当前日期的工作时间段
-            List<LineWorkPointDto> workPoints = DealWorkDayToLevels(startTime, shopCal, curQtyDtls);
+            List<LineWorkPointDto> workPoints = DealWorkDayToLevels(lineStart.Line, startTime, shopCal, curQtyDtls);
             //当天排产结束时间
             scheduledDto.EndTime = workPoints.Last().EndPoint;
             //计算starttime处于那个工作时间段
@@ -757,9 +1031,9 @@ namespace Business.ResourceExamineManagement
                 span = item.EndPoint - item.StartPoint;
                 scheduledDto.EffTime += (decimal)span.TotalHours;
             }
-            //判断产线当天有没有加班
-            var curOccupyTimes = resourceOccupancyTimes.Where(p=> p.Resource == lineStart.Line && p.StartTime.GetValueOrDefault().Date == startTime.Date).ToList();
-            scheduledDto.EffTime += curOccupyTimes.Sum(p=> Convert.ToDecimal(p.Ufld1));
+            ////判断产线当天有没有加班
+            //var curOccupyTimes = resourceOccupancyTimes.Where(p=> p.Resource == lineStart.Line && p.StartTime.GetValueOrDefault().Date == startTime.Date).ToList();
+            //scheduledDto.EffTime += curOccupyTimes.Sum(p=> Convert.ToDecimal(p.Ufld1));
             //判断当前产线的UPH
             var curRunCrews = prodLineDetailRunCrews.Where(p=>p.ProdLineDetailRecID == lineStart.RecID).ToList();
             //判断当前日期是否配置了UPH
@@ -798,7 +1072,7 @@ namespace Business.ResourceExamineManagement
             //产线工作日历:当前产线的工作日历+默认工作日历
             var curCalendars = calendars.Where(p => p.ProdLine == lines[0].Line || string.IsNullOrEmpty(p.ProdLine)).ToList();
             var curQtyDtls = qualityLines.Where(p=>p.ProdLine == lines[0].Line).ToList();
-            actStart = CalcActStartTime(actStart, curCalendars, curQtyDtls);
+            actStart = CalcActStartTime(lines[0].Line, actStart, curCalendars, curQtyDtls);
             lineStart.RecID = lines[0].RecID;
             lineStart.Line = lines[0].Line;
             lineStart.StartTime = actStart;
@@ -814,7 +1088,7 @@ namespace Business.ResourceExamineManagement
                 //产线工作日历:当前产线的工作日历+默认工作日历
                 curCalendars = calendars.Where(p => p.ProdLine == lines[i].Line || string.IsNullOrEmpty(p.ProdLine)).ToList();
                 curQtyDtls = qualityLines.Where(p => p.ProdLine == lines[i].Line).ToList();
-                StartTime = CalcActStartTime(StartTime, curCalendars, curQtyDtls);
+                StartTime = CalcActStartTime(lines[0].Line, StartTime, curCalendars, curQtyDtls);
                 if (StartTime < lineStart.StartTime)
                 {
                     lineStart.RecID = lines[i].RecID;
@@ -831,11 +1105,12 @@ namespace Business.ResourceExamineManagement
         /// <summary>
         /// 计算主产线实际排产开始时间
         /// </summary>
+        /// <param name="prodLine">生产线</param>
         /// <param name="startTime">开始时间</param>
         /// <param name="curCalendars">当前产线工作日历+默认工作日历</param>
         /// <param name="curQtyDtls">当前产线休息记录</param>
         /// <returns></returns>
-        public DateTime CalcActStartTime(DateTime startTime, List<ShopCalendarWorkCtr> curCalendars, List<QualityLineWorkDetail> curQtyDtls)
+        public DateTime CalcActStartTime(string prodLine,DateTime startTime, List<ShopCalendarWorkCtr> curCalendars, List<QualityLineWorkDetail> curQtyDtls)
         {
             //实际排产开始时间
             DateTime actStart = startTime;
@@ -858,7 +1133,7 @@ namespace Business.ResourceExamineManagement
                 shopCal = curCalendars.Where(p => string.IsNullOrEmpty(p.ProdLine) && p.WeekDay == weekDay).FirstOrDefault();
             }
             //当前日期的工作时间段
-            List<LineWorkPointDto> workPoints = DealWorkDayToLevels(startTime, shopCal, curQtyDtls);
+            List<LineWorkPointDto> workPoints = DealWorkDayToLevels(prodLine, startTime, shopCal, curQtyDtls);
             //计算starttime处于那个工作时间段
             var curPoint = workPoints.Where(p => startTime >= p.StartPoint && startTime <= p.EndPoint).FirstOrDefault();
             if (curPoint == null)//不处于工作时间段
@@ -1032,7 +1307,7 @@ namespace Business.ResourceExamineManagement
             //当前产线的休息时间设置
             var curQtyDtls = qualityLines.Where(p => p.ProdLine == line.Line).ToList();
             //当前日期的工作时间段
-            List<LineWorkPointDto> workPoints = DealWorkDayToLevels(startTime, shopCal, curQtyDtls);
+            List<LineWorkPointDto> workPoints = DealWorkDayToLevels(line.Line, startTime, shopCal, curQtyDtls);
             //计算starttime处于那个工作时间段
             var curPoint = workPoints.Where(p => startTime >= p.StartPoint && startTime <= p.EndPoint).FirstOrDefault();
             //当前时间段可用时长
@@ -1076,7 +1351,7 @@ namespace Business.ResourceExamineManagement
                 {
                     curCalendar = calendars.Where(p => string.IsNullOrEmpty(p.ProdLine) && p.WeekDay == weekDay).FirstOrDefault();
                 }
-                workPoints = DealWorkDayToLevels(nextStartTime, curCalendar, curQtyDtls).OrderBy(p => p.Level).ToList();
+                workPoints = DealWorkDayToLevels(line.Line, nextStartTime, curCalendar, curQtyDtls).OrderBy(p => p.Level).ToList();
                 //当天的工作时长(分钟)
                 decimal sumWorkMins = workPoints.Sum(p => p.WorkMinutes);
                 if (sumWorkMins >= needMinute)//当天可用提前期满足
@@ -1149,11 +1424,12 @@ namespace Business.ResourceExamineManagement
         /// <summary>
         /// 处理当前日期的工作时间段
         /// </summary>
+        /// <param name="prodLine"></param>
         /// <param name="startTime"></param>
         /// <param name="shopCal">当前产线的工作日历-周几</param>
         /// <param name="curQtyDtls">每天休息记录</param>
         /// <returns></returns>
-        public List<LineWorkPointDto> DealWorkDayToLevels(DateTime startTime, ShopCalendarWorkCtr shopCal, List<QualityLineWorkDetail> curQtyDtls)
+        public List<LineWorkPointDto> DealWorkDayToLevels(string prodLine, DateTime startTime, ShopCalendarWorkCtr shopCal, List<QualityLineWorkDetail> curQtyDtls)
         {
             //年-月-日
             string date = startTime.Date.ToString("yyyy-MM-dd");
@@ -1170,7 +1446,7 @@ namespace Business.ResourceExamineManagement
             //结束时间
             DateTime dayEndPoint = dayStartPoint.AddHours((double)(shopCal.ShiftsHours1 + shopCal.ShiftsHours2));
             dto.Level = level;
-            dto.Line = shopCal.ProdLine;
+            dto.Line = prodLine;
             dto.WeekDay = weekDay;
             dto.StartPoint = dayStartPoint;
             //按照产线休息时间切分时间段
@@ -1185,7 +1461,7 @@ namespace Business.ResourceExamineManagement
                 level++;
                 dto = new LineWorkPointDto();
                 dto.Level = level;
-                dto.Line = shopCal.ProdLine;
+                dto.Line = prodLine;
                 dto.WeekDay = weekDay;
                 dto.StartPoint = endPoint.AddMinutes(item.RestTime);
             }
@@ -1193,6 +1469,20 @@ namespace Business.ResourceExamineManagement
             span = dto.EndPoint - dto.StartPoint;
             dto.WorkMinutes = (decimal)span.TotalMinutes;
             workPoints.Add(dto);
+            //产线当天加班设置
+            var curOccupyTimes = resourceOccupancyTimes.Where(p => p.Resource == prodLine && p.StartTime.GetValueOrDefault().Date == startTime.Date).OrderBy(p=>p.StartTime).ToList();
+            foreach (var item in curOccupyTimes)
+            {
+                level++;
+                dto = new LineWorkPointDto();
+                dto.Level = level;
+                dto.Line = prodLine;
+                dto.WeekDay = weekDay;
+                dto.StartPoint = item.StartTime.GetValueOrDefault();
+                dto.EndPoint = dto.StartPoint.AddHours(Convert.ToDouble(item.Ufld1));
+                dto.WorkMinutes = Convert.ToDecimal(item.Ufld1) * 60;
+                workPoints.Add(dto);
+            }
 
             return workPoints.OrderBy(p => p.Level).ToList();
         }

+ 2 - 2
MicroServices/Business/Business.Domain/StructuredDB/MES/IC/GeneralizedCodeMaster.cs

@@ -64,9 +64,9 @@ namespace Business.Domain
         public bool IsConfirm { get; set; }
 
         /// <summary>
-        /// 数值1
+        /// 排产锁定期
         /// </summary>
-        [Comment("数值1")]
+        [Comment("排产锁定期")]
         public decimal UDeci1 { get; set; }
 
         /// <summary>

+ 13 - 1
MicroServices/Business/Business.Domain/StructuredDB/Production/WorkOrdMaster.cs

@@ -118,9 +118,21 @@ namespace Business.Domain
         public string Batch { get; set; }
 
         /// <summary>
-        /// 类型 s,销售 p,计划
+        /// 类型:正常工单-空或者Null;反之则为特殊工单
         /// </summary>
         [Comment("类型")]
         public string Typed { get; set; }
+
+        /// <summary>
+        /// 生产时长(小时)
+        /// </summary>
+        [Comment("生产时长")]
+        public decimal LbrVar { get; set; }
+
+        /// <summary>
+        /// 流程id
+        /// </summary>
+        [Comment("流程id")]
+        public long BusinessID { get; set; }
     }
 }