|
|
@@ -5,9 +5,11 @@ using Business.EntityFrameworkCore;
|
|
|
using Business.EntityFrameworkCore.SqlRepositories;
|
|
|
using Business.Model.MES.IC;
|
|
|
using Business.Model.Production;
|
|
|
+using EFCore.BulkExtensions;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Collections.Immutable;
|
|
|
+using System.Globalization;
|
|
|
using System.Linq;
|
|
|
using System.Threading.Tasks;
|
|
|
using Volo.Abp.Application.Services;
|
|
|
@@ -154,7 +156,8 @@ namespace Business.Quartz
|
|
|
public async Task DoProductShcedule()
|
|
|
{
|
|
|
//1、获取需要排产的工单:Status为空且IsActive==1
|
|
|
- List<WorkOrdMaster> workOrds = _workOrdMaster.Select(p => string.IsNullOrEmpty(p.Status) && p.IsActive == 1).Result;
|
|
|
+ //List<WorkOrdMaster> workOrds = _workOrdMaster.Select(p => string.IsNullOrEmpty(p.Status) && p.IsActive == 1).Result;
|
|
|
+ List<WorkOrdMaster> workOrds = _workOrdMaster.Select(p => p.WorkOrd == "Test0000001").Result;
|
|
|
if (workOrds.Count == 0)
|
|
|
{
|
|
|
return;
|
|
|
@@ -163,19 +166,19 @@ namespace Business.Quartz
|
|
|
DateTime earlist = workOrds.Min(p => p.OrdDate.GetValueOrDefault()).Date;
|
|
|
//2、获取数据
|
|
|
//获取工单工艺路径数据
|
|
|
- List<WorkOrdRouting> workOrdRoutings = _workOrdRouting.Select(p => workOrds.Select(m => m.WorkOrd).Contains(p.WorkOrd) && p.Domain == "1001" && p.Status != "C" && p.IsActive == 1).Result;
|
|
|
+ List<WorkOrdRouting> workOrdRoutings = _workOrdRouting.Select(p => workOrds.Select(m => m.WorkOrd).Contains(p.WorkOrd) && p.Domain == "1001" && p.Status != "C" && p.IsActive).Result;
|
|
|
//获取物料对应的生产线信息:物料、工序对应的生产线
|
|
|
- List<ProdLineDetail> prodLines = _prodLineDetail.Select(p => workOrds.Select(m => m.ItemNum).Contains(p.Part) && p.Domain == "1001" && p.IsActive == 1).Result;
|
|
|
+ List<ProdLineDetail> prodLines = _prodLineDetail.Select(p => workOrds.Select(m => m.ItemNum).Contains(p.Part) && p.Domain == "1001" && p.IsActive).Result;
|
|
|
//获取生产周期数据
|
|
|
- List<PeriodSequenceDet> dbPeriodSequences = _periodSequenceDet.Select(p=> workOrds.Select(m => m.ItemNum).Contains(p.ItemNum) && p.PlanDate >= earlist && p.Domain == "1001" && p.IsActive == 1).Result;
|
|
|
+ List<PeriodSequenceDet> dbPeriodSequences = _periodSequenceDet.Select(p=> workOrds.Select(m => m.ItemNum).Contains(p.ItemNum) && p.PlanDate >= earlist && p.Domain == "1001" && p.IsActive).Result;
|
|
|
//获取当前日期往后的排产记录数据
|
|
|
List<ScheduleResultOpMaster> dbSchedules = _scheduleResultOpMaster.Select(p => workOrds.Select(m => m.ItemNum).Contains(p.ItemNum) && p.WorkDate >= earlist && p.Domain == "1001").Result;
|
|
|
//获取工作日历数据
|
|
|
- calendars = _shopCalendarWorkCtr.Select(p=>p.Domain == "1001" && p.IsActive == 1).Result;
|
|
|
+ calendars = _shopCalendarWorkCtr.Select(p=>p.Domain == "1001" && p.IsActive).Result;
|
|
|
//获取产线休息记录数据
|
|
|
- qualityLines = _qualityLineWorkDetail.Select(p => p.Domain == "1001" && p.IsActive == 1).Result;
|
|
|
+ qualityLines = _qualityLineWorkDetail.Select(p => p.Domain == "1001" && p.IsActive).Result;
|
|
|
//获取节假日记录数据
|
|
|
- holidays = _holidayMaster.Select(p => p.Domain == "1001" && p.IsActive == 1 && p.Dated >= earlist).Result;
|
|
|
+ holidays = _holidayMaster.Select(p => p.Domain == "1001" && p.IsActive && p.Dated >= earlist).Result;
|
|
|
|
|
|
//3、排产
|
|
|
//排产异常记录
|
|
|
@@ -252,12 +255,12 @@ namespace Business.Quartz
|
|
|
|
|
|
//更新工单表
|
|
|
item.Status = "w";
|
|
|
- await _workOrdMaster.Update(item);
|
|
|
}
|
|
|
+ _businessDbContext.UpdateRange(workOrds);
|
|
|
//记录排产数据
|
|
|
- await _businessDbContext.PeriodSequenceDet.BulkInsertAsync(periodSequenceDtls);
|
|
|
- await _businessDbContext.ScheduleResultOpMaster.BulkInsertAsync(scheduleMasters);
|
|
|
- await _businessDbContext.ScheduleExceptionMaster.BulkInsertAsync(scheduleExceptions);
|
|
|
+ _businessDbContext.BulkInsert(periodSequenceDtls);
|
|
|
+ _businessDbContext.BulkInsert(scheduleMasters);
|
|
|
+ _businessDbContext.BulkInsert(scheduleExceptions);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -282,7 +285,7 @@ namespace Business.Quartz
|
|
|
//当前产线的工作日历
|
|
|
var mLCalendars = calendars.Where(p => p.ProdLine == item.Line).ToList();
|
|
|
//当前产线的每天休息时间记录
|
|
|
- var mlqtyWorkDtls = qualityLines.Where(p => p.ProdLine == item.Line).ToList();
|
|
|
+ var mlqtyWorkDtls = qualityLines.Where(p => p.ProdLine == item.Line).OrderBy(p => p.Line).ToList();
|
|
|
|
|
|
//产线已排产数量
|
|
|
decimal sumQty = 0m;
|
|
|
@@ -296,15 +299,17 @@ namespace Business.Quartz
|
|
|
{
|
|
|
//子产线获取实际排产开始日期
|
|
|
//获取父级排产开始时间
|
|
|
- DateTime parentStartTime = lineStarts.First(p => p.Op == item.ParentOp).StartTime;
|
|
|
+ DateTime parentStartTime = lineStarts.First(p => p.ChdParentOps.Contains(item.ParentOp)).StartTime;
|
|
|
workStartTime = DealChildStartTime(parentStartTime, item.SetupTime, mLCalendars, mlqtyWorkDtls);
|
|
|
}
|
|
|
//记录产线排产开始时间
|
|
|
- lineStarts.Add(new LineStartDto {
|
|
|
+ lineStarts.Add(new LineStartDto
|
|
|
+ {
|
|
|
level = item.level,
|
|
|
Line = item.Line,
|
|
|
- Op= item.Op,
|
|
|
- StartTime = workStartTime
|
|
|
+ Op = item.Op,
|
|
|
+ StartTime = workStartTime,
|
|
|
+ ChdParentOps = item.ChdParentOps
|
|
|
});
|
|
|
//排产
|
|
|
while (sumQty < workOrd.QtyOrded)
|
|
|
@@ -324,7 +329,8 @@ namespace Business.Quartz
|
|
|
Period = 1,//目前只考虑一班制
|
|
|
OrdQty = dto.ProductQty,
|
|
|
WorkOrds = workOrd.WorkOrd,
|
|
|
- IsActive = 1
|
|
|
+ Op = item.Op,
|
|
|
+ IsActive = true
|
|
|
});
|
|
|
//记录排产记录
|
|
|
curScheduleRsts.Add(new ScheduleResultOpMaster
|
|
|
@@ -338,7 +344,7 @@ namespace Business.Quartz
|
|
|
WorkQty = dto.ProductQty,
|
|
|
WorkStartTime = dto.StartTime,
|
|
|
WorkEndTime = dto.EndTime,
|
|
|
- CreatTime = DateTime.Now
|
|
|
+ CreateTime = DateTime.Now
|
|
|
});
|
|
|
//累计已排产数量
|
|
|
sumQty += dto.ProductQty;
|
|
|
@@ -350,7 +356,7 @@ namespace Business.Quartz
|
|
|
//剩余需要排产的数量
|
|
|
decimal residueQty = workOrd.QtyOrded - sumQty;
|
|
|
//剩余数量生产需要时长(分钟)
|
|
|
- decimal workTime = residueQty / item.Rate * 60;
|
|
|
+ decimal workTime = Math.Ceiling(residueQty / item.Rate * 60);
|
|
|
//获取当天的工作时间段
|
|
|
List<LineWorkPointDto> workPoints = DealWorkDayToLevels(workStartTime, mLCalendars.First(p => p.WeekDay == (int)workStartTime.DayOfWeek), mlqtyWorkDtls);
|
|
|
var curPoint = workPoints.First(p => p.StartPoint >= workStartTime && workStartTime <= p.EndPoint);
|
|
|
@@ -378,6 +384,7 @@ namespace Business.Quartz
|
|
|
nextMins -= p.WorkMinutes;
|
|
|
}
|
|
|
}
|
|
|
+ sumQty = workOrd.QtyOrded;
|
|
|
//记录生产周期
|
|
|
curSequences.Add(new PeriodSequenceDet
|
|
|
{
|
|
|
@@ -388,7 +395,8 @@ namespace Business.Quartz
|
|
|
Period = 1,//目前只考虑一班制
|
|
|
OrdQty = residueQty,
|
|
|
WorkOrds = workOrd.WorkOrd,
|
|
|
- IsActive = 1
|
|
|
+ Op = item.Op,
|
|
|
+ IsActive = true
|
|
|
});
|
|
|
//记录排产记录
|
|
|
curScheduleRsts.Add(new ScheduleResultOpMaster
|
|
|
@@ -402,7 +410,7 @@ namespace Business.Quartz
|
|
|
WorkQty = residueQty,
|
|
|
WorkStartTime = workStartTime,
|
|
|
WorkEndTime = workEndTime,
|
|
|
- CreatTime = DateTime.Now
|
|
|
+ CreateTime = DateTime.Now
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
@@ -445,7 +453,7 @@ namespace Business.Quartz
|
|
|
scheduledDto.EffTime += (decimal)span.TotalHours;
|
|
|
}
|
|
|
//计算当天的产能
|
|
|
- scheduledDto.ProductQty = scheduledDto.EffTime * routingDto.Rate;
|
|
|
+ scheduledDto.ProductQty = Math.Floor(scheduledDto.EffTime * routingDto.Rate);
|
|
|
return scheduledDto;
|
|
|
}
|
|
|
|
|
|
@@ -462,12 +470,48 @@ namespace Business.Quartz
|
|
|
DateTime actStart = startTime;
|
|
|
//开始时间是周几
|
|
|
int weekDay = (int)startTime.DayOfWeek;
|
|
|
+ //判断当天是否是工作日
|
|
|
+ bool isWorkDay = CheckIsWorkDay(startTime);
|
|
|
+ if (!isWorkDay)//不是工作日
|
|
|
+ {
|
|
|
+ //获取下一个工作日开始时间
|
|
|
+ actStart = GetNextWorkDay(weekDay, startTime, curCalendars);
|
|
|
+ return actStart;
|
|
|
+ }
|
|
|
+
|
|
|
//当天的工作日历
|
|
|
var shopCal = curCalendars.Where(p => p.WeekDay == weekDay).First();
|
|
|
//当前日期的工作时间段
|
|
|
List<LineWorkPointDto> workPoints = DealWorkDayToLevels(startTime, shopCal, curQtyDtls);
|
|
|
//计算starttime处于那个工作时间段
|
|
|
var curPoint = workPoints.Where(p => startTime >= p.StartPoint && startTime <= p.EndPoint).FirstOrDefault();
|
|
|
+ if (curPoint == null)//不处于工作时间段
|
|
|
+ {
|
|
|
+ //开始时间小于当天工作开始时间
|
|
|
+ if (startTime < workPoints.First().StartPoint)
|
|
|
+ {
|
|
|
+ actStart = workPoints.First().StartPoint;
|
|
|
+ }
|
|
|
+ //开始时间大于当前工作结束时间
|
|
|
+ else if (startTime > workPoints.Last().EndPoint)
|
|
|
+ {
|
|
|
+ //获取下一个工作日开始时间
|
|
|
+ actStart = GetNextWorkDay(weekDay, startTime, curCalendars);
|
|
|
+ }
|
|
|
+ else {//开始时间位于当天的休息时间段
|
|
|
+ foreach (var item in workPoints)
|
|
|
+ {
|
|
|
+ //获取下一个时间段
|
|
|
+ var next = workPoints.First(p=>p.Level == item.Level + 1);
|
|
|
+ if (item.EndPoint < startTime && startTime < next.StartPoint)
|
|
|
+ {
|
|
|
+ actStart = next.StartPoint;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return actStart;
|
|
|
+ }
|
|
|
if (startTime != curPoint.EndPoint)
|
|
|
{
|
|
|
return actStart;
|
|
|
@@ -483,6 +527,33 @@ namespace Business.Quartz
|
|
|
return actStart;
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 判断当天是否是工作日
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="dateTime"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public bool CheckIsWorkDay(DateTime dateTime)
|
|
|
+ {
|
|
|
+ bool isWorkDay = true;
|
|
|
+ //周几
|
|
|
+ int weekDay = (int)dateTime.DayOfWeek;
|
|
|
+ //判断当天是否是工作日
|
|
|
+ if (weekDay == 0 || weekDay == 6)//周六或者周日,需要判断是否调休,需要加班
|
|
|
+ {
|
|
|
+ if (!holidays.Exists(p => p.Dated.GetValueOrDefault().Date == dateTime.Date && p.Ufld1 == "调休"))//不是调休
|
|
|
+ {
|
|
|
+ isWorkDay = false;
|
|
|
+ }
|
|
|
+ return isWorkDay;
|
|
|
+ }
|
|
|
+ //不是周六周日,需要判断是不是节假日
|
|
|
+ if (holidays.Exists(p => p.Dated.GetValueOrDefault().Date == dateTime.Date && p.Ufld1 == "休假"))//是节假日
|
|
|
+ {
|
|
|
+ isWorkDay = false;
|
|
|
+ }
|
|
|
+ return isWorkDay;
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// 计算子产线实际排产开始时间
|
|
|
/// </summary>
|
|
|
@@ -574,6 +645,7 @@ namespace Business.Quartz
|
|
|
//下一天是周几
|
|
|
int nextWeekDay = (weekDay + 1) % 7;
|
|
|
var calendar = curCalendars.FirstOrDefault(p=>p.WeekDay == nextWeekDay);
|
|
|
+ string strStart = calendar.ShiftsStart1.ToString("0.00").Replace(".", ":");
|
|
|
//判断下一天是否是工作日
|
|
|
if (nextWeekDay == 0 || nextWeekDay == 6)//下一天是周六或者周日,需要判断是否调休,需要加班
|
|
|
{
|
|
|
@@ -582,7 +654,7 @@ namespace Business.Quartz
|
|
|
//递归继续找下一个工作日
|
|
|
GetNextWorkDay(nextWeekDay, nextDate, curCalendars);
|
|
|
}
|
|
|
- rtnData = nextDate.AddHours((double)calendar.ShiftsStart1);
|
|
|
+ rtnData = Convert.ToDateTime(nextDate.ToString("yyyy-MM-dd") + " " + strStart);
|
|
|
return rtnData;
|
|
|
}
|
|
|
//下一天不是周六周日,需要判断是不是节假日
|
|
|
@@ -591,7 +663,7 @@ namespace Business.Quartz
|
|
|
//递归继续找下一个工作日
|
|
|
GetNextWorkDay(nextWeekDay, nextDate, curCalendars);
|
|
|
}
|
|
|
- rtnData = nextDate.AddHours((double)calendar.ShiftsStart1);
|
|
|
+ rtnData = Convert.ToDateTime(nextDate.ToString("yyyy-MM-dd") + " " + strStart);
|
|
|
return rtnData;
|
|
|
}
|
|
|
|
|
|
@@ -609,6 +681,7 @@ namespace Business.Quartz
|
|
|
//前一天是周几
|
|
|
int preWeekDay = (int)preDate.DayOfWeek;
|
|
|
var calendar = curCalendars.FirstOrDefault(p => p.WeekDay == preWeekDay);
|
|
|
+ string strStart = calendar.ShiftsStart1.ToString("0.00").Replace(".", ":");
|
|
|
//判断前一天是否是工作日
|
|
|
if (preWeekDay == 0 || preWeekDay == 6)//前一天是周六或者周日,需要判断是否调休,需要加班
|
|
|
{
|
|
|
@@ -617,7 +690,7 @@ namespace Business.Quartz
|
|
|
//递归继续找下一个工作日
|
|
|
GetPreWorkDay(preDate, curCalendars);
|
|
|
}
|
|
|
- rtnData = preDate.AddHours((double)calendar.ShiftsStart1);
|
|
|
+ rtnData = Convert.ToDateTime(preDate.ToString("yyyy-MM-dd") + " " + strStart);
|
|
|
return rtnData;
|
|
|
}
|
|
|
//前一天不是周六周日,需要判断是不是节假日
|
|
|
@@ -626,7 +699,7 @@ namespace Business.Quartz
|
|
|
//递归继续找前一个工作日
|
|
|
GetPreWorkDay(preDate, curCalendars);
|
|
|
}
|
|
|
- rtnData = preDate.AddHours((double)calendar.ShiftsStart1);
|
|
|
+ rtnData = Convert.ToDateTime(preDate.ToString("yyyy-MM-dd") + " " + strStart);
|
|
|
return rtnData;
|
|
|
}
|
|
|
|
|
|
@@ -644,7 +717,8 @@ namespace Business.Quartz
|
|
|
//排产记录结束日期是周几
|
|
|
int weekDay = (int)startTime.DayOfWeek;
|
|
|
//计算当天的开工时间点,停工时间点
|
|
|
- DateTime dayStartPoint = startTime.Date.AddHours(Convert.ToDouble(shopCal.ShiftsStart1));
|
|
|
+ string strStart = shopCal.ShiftsStart1.ToString("0.00").Replace(".", ":");
|
|
|
+ DateTime dayStartPoint = Convert.ToDateTime(date + " "+ strStart);
|
|
|
DateTime dayEndPoint = dayStartPoint.AddHours(Convert.ToDouble(shopCal.ShiftsHours1));
|
|
|
//工作时间段
|
|
|
List<LineWorkPointDto> workPoints = new List<LineWorkPointDto>();
|
|
|
@@ -702,6 +776,13 @@ namespace Business.Quartz
|
|
|
dto.ParentOp = lastOp.ParentOp;
|
|
|
dto.level = 1;
|
|
|
dto.Op = lastOp.OP;
|
|
|
+ dto.ChdParentOps = new List<int>();
|
|
|
+ //获取当前层级工序中有子级的工序集合
|
|
|
+ var childs = woRuntings.Where(p => firsts.Select(m => m.OP).Contains(p.ParentOp)).Select(m => m.ParentOp).Distinct().ToList();
|
|
|
+ if (childs.Count() > 0)
|
|
|
+ {
|
|
|
+ dto.ChdParentOps = childs;
|
|
|
+ }
|
|
|
//主工序对应的产线(目前只考虑一个产品对应一条产线的情况)
|
|
|
var line = prodLines.Where(p => p.Part == lastOp.ItemNum && p.Op == lastOp.OP).FirstOrDefault();
|
|
|
if (line != null) {
|
|
|
@@ -748,6 +829,13 @@ namespace Business.Quartz
|
|
|
dto.Op = lastOp.OP;
|
|
|
dto.ParentOp = lastOp.ParentOp;
|
|
|
dto.level = level + 1;
|
|
|
+ dto.ChdParentOps = new List<int>();
|
|
|
+ //获取当前层级工序中有子级的工序集合
|
|
|
+ var childs = woRuntings.Where(p => curLevels.Where(p => p.ParentOp == item).Select(m => m.OP).Contains(p.ParentOp)).Select(m => m.ParentOp).Distinct().ToList();
|
|
|
+ if (childs.Count() > 0)
|
|
|
+ {
|
|
|
+ dto.ChdParentOps = childs;
|
|
|
+ }
|
|
|
//当前层级工序对应的产线
|
|
|
var maxRateLine = prodLines.Where(p => p.Part == lastOp.ItemNum && p.Op == lastOp.OP).OrderByDescending(p => p.Rate).FirstOrDefault();
|
|
|
if (maxRateLine != null)
|