|
|
@@ -18,6 +18,7 @@ using Microsoft.Extensions.Configuration;
|
|
|
using MongoDB.Driver.Linq;
|
|
|
using Amazon.Runtime.Internal.Util;
|
|
|
using IdentityModel.Client;
|
|
|
+using Amazon.Runtime;
|
|
|
|
|
|
namespace Business.ResourceExamineManagement
|
|
|
{
|
|
|
@@ -196,8 +197,9 @@ namespace Business.ResourceExamineManagement
|
|
|
decimal lockDays = generalizedCodeMaster != null ? generalizedCodeMaster.UDeci1 : 0;
|
|
|
|
|
|
//获取需要排产的工单(获取四周的工单:正常工单+已审批通过的特殊工单)
|
|
|
- DateTime endDate = DateTime.Now.Date.AddWeeks(4).AddDays(1);
|
|
|
- DateTime startDate = DateTime.Now.Date;
|
|
|
+ DateTime endDate = DateTime.Now.Date.AddDays(28).AddDays(1);
|
|
|
+ //取数开始时间需要排除掉锁定期内的工单
|
|
|
+ DateTime startDate = DateTime.Now.Date.AddDays(1).AddDays((double)lockDays);
|
|
|
var workOrds = _workOrdMaster.Select(p => p.IsActive && p.Domain == domain && p.OrdDate < endDate && p.OrdDate >= startDate && string.IsNullOrEmpty(p.Status) && (string.IsNullOrEmpty(p.Typed) || (!string.IsNullOrEmpty(p.Typed) && p.BusinessID >0 ))).ToList();
|
|
|
await DoProductSchedule(workOrds, domain, 1);
|
|
|
}
|
|
|
@@ -205,7 +207,7 @@ namespace Business.ResourceExamineManagement
|
|
|
/// <summary>
|
|
|
/// 生产排产
|
|
|
/// </summary>
|
|
|
- /// <param name="workOrds">工单</param>
|
|
|
+ /// <param name="workOrds">需要重新排产的工单</param>
|
|
|
/// <param name="factoryid">工单的工厂id</param>
|
|
|
/// <param name="type">排产类型:1-自动排产;2-手动排产</param>
|
|
|
/// <returns></returns>
|
|
|
@@ -236,10 +238,15 @@ 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);
|
|
|
+ //获取锁定期之外的工单排产数据
|
|
|
+ List<PeriodSequenceDet> delPeriodSequences = dbPeriodSequences.Where(p => workOrds.Select(m => m.WorkOrd).Contains(p.WorkOrds)).ToList();
|
|
|
+ List<ScheduleResultOpMaster> delSchedules = dbSchedules.Where(p => workOrds.Select(m => m.WorkOrd).Contains(p.WorkOrd)).ToList();
|
|
|
+ //产线占用记录排除锁定期之前的工单
|
|
|
+ dbSchedules = dbSchedules.Where(p => !workOrds.Select(m => m.WorkOrd).Contains(p.WorkOrd)).ToList();
|
|
|
//获取工作日历数据:产线的工作日历+默认的工作日历
|
|
|
calendars = _shopCalendarWorkCtr.Select(p => (lines.Contains(p.ProdLine) || string.IsNullOrEmpty(p.ProdLine)) && p.Domain == domain && p.IsActive);
|
|
|
//获取产线休息记录数据
|
|
|
@@ -302,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,
|
|
|
@@ -313,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);
|
|
|
@@ -331,8 +339,12 @@ namespace Business.ResourceExamineManagement
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
- //记录排产数据
|
|
|
+ //更新工单计划开工时间、计划结束时间
|
|
|
_workOrdMaster.Update(workOrds);
|
|
|
+ //删除锁定期之外的工单排产记录
|
|
|
+ _periodSequenceDet.Delete(delPeriodSequences);
|
|
|
+ _scheduleResultOpMaster.Delete(delSchedules);
|
|
|
+ //保存排产记录
|
|
|
_periodSequenceDet.Insert(periodSequenceDtls);
|
|
|
_scheduleResultOpMaster.Insert(scheduleMasters);
|
|
|
scope.Complete();
|
|
|
@@ -361,7 +373,7 @@ namespace Business.ResourceExamineManagement
|
|
|
{
|
|
|
if (!string.IsNullOrEmpty(item.Typed))//特殊工单
|
|
|
{
|
|
|
- //只需要校验有没有维护工艺路线即可
|
|
|
+ //校验有没有维护工艺路线即可
|
|
|
var routings = workOrdRoutings.Where(p=>p.ItemNum == item.ItemNum).ToList();
|
|
|
if (!routings.Any())
|
|
|
{
|
|
|
@@ -374,6 +386,36 @@ namespace Business.ResourceExamineManagement
|
|
|
entity.Type = type == 1 ? "自动排产" : "手动排产";
|
|
|
exceptions.Add(entity);
|
|
|
}
|
|
|
+
|
|
|
+ //获取当前产线维护的工作日历
|
|
|
+ var lineCals = calendars.Where(p => p.ProdLine == item.ProdLine).ToList();
|
|
|
+ //获取默认工作日历
|
|
|
+ var mrCals = calendars.Where(p => string.IsNullOrEmpty(p.ProdLine)).ToList();
|
|
|
+ if (!lineCals.Any())//当前产线未维护工作日历
|
|
|
+ {
|
|
|
+ if (!mrCals.Any() || mrCals.Select(p => p.WeekDay).Distinct().Count() != 7)
|
|
|
+ {
|
|
|
+ entity = new ScheduleExceptionMaster();
|
|
|
+ entity.Domain = item.Domain;
|
|
|
+ entity.WorkOrd = item.WorkOrd;
|
|
|
+ entity.ItemNum = item.ItemNum;
|
|
|
+ entity.CreateTime = DateTime.Now;
|
|
|
+ entity.Remark = "排产异常:产线[" + item.ProdLine + "]没有维护工作日历且标准工作日历未维护完全,请维护后再操作!";
|
|
|
+ entity.Type = type == 1 ? "自动排产" : "手动排产";
|
|
|
+ exceptions.Add(entity);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (lineCals.Select(p => p.WeekDay).Distinct().Count() != 7)//当前产线维护了工作日历,但是没有维护完全
|
|
|
+ {
|
|
|
+ entity = new ScheduleExceptionMaster();
|
|
|
+ entity.Domain = item.Domain;
|
|
|
+ entity.WorkOrd = item.WorkOrd;
|
|
|
+ entity.ItemNum = item.ItemNum;
|
|
|
+ entity.CreateTime = DateTime.Now;
|
|
|
+ entity.Remark = "排产异常:产线[" + item.ProdLine + "]工作日历没有维护完整,请维护后再操作!";
|
|
|
+ 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();
|
|
|
@@ -526,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();
|
|
|
//获取当天的产能
|
|
|
@@ -555,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)//当前工作时间段即可满足产能
|
|
|
{
|
|
|
- if (p.WorkMinutes >= nextMins)
|
|
|
+ endTime = beginTime.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)
|
|
|
{
|
|
|
- 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
|
|
|
@@ -647,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);
|
|
|
@@ -705,7 +844,8 @@ namespace Business.ResourceExamineManagement
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- else//当天的可用产能不满足特殊工单生产时长,则当天产能全部排特殊工单
|
|
|
+ //当天的可用产能不满足特殊工单生产时长,则当天产能全部排特殊工单(至少最后一个特殊工单的生产时长不能满足)
|
|
|
+ else
|
|
|
{
|
|
|
decimal residueTime = dto.EffTime;//当天产能剩余产能(分钟)
|
|
|
DateTime beginTime = workStartTime;//排产开始时间
|
|
|
@@ -718,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);
|
|
|
@@ -745,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
|
|
|
{
|
|
|
@@ -774,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);
|
|
|
@@ -830,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;
|
|
|
}
|
|
|
}
|
|
|
//记录已排产特殊工单
|
|
|
@@ -850,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)
|
|
|
@@ -2552,7 +2739,7 @@ namespace Business.ResourceExamineManagement
|
|
|
{
|
|
|
foreach (var item in workOrds)
|
|
|
{
|
|
|
- //工单的生产时长(分钟)
|
|
|
+ //工单生产时长(分钟)
|
|
|
decimal sumTimes = item.LbrVar;
|
|
|
//工单的排产开始时间
|
|
|
DateTime workStartTime = item.OrdDate;
|
|
|
@@ -2578,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);
|
|
|
//记录生产周期
|
|
|
@@ -2614,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;
|
|
|
@@ -2640,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
|
|
|
{
|
|
|
@@ -2682,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>
|