private IEnumerable <JobLogDB.EventLogMaterial> CreateUnloadMaterial(MessageState state, string pal, IReadOnlyList <LogEntry> oldEvents = null) { var oldMat = FindMaterial(pal, oldEvents)[0]; var ret = new List <JobLogDB.EventLogMaterial>(); string partName = ""; int count = 1; if (state.PartCompletedMessagesBySetup.Count > 0) { // use highest setup value var msgs = state.PartCompletedMessagesBySetup.ElementAt(state.PartCompletedMessagesBySetup.Count - 1).Value; count = msgs.Count; partName = msgs[0].PartName; } Log.Debug("During unload, found {cnt} parts with name {part} that were unloaded/completed", count, partName); _log.SetDetailsForMaterialID(oldMat.MaterialID, null, partName, null); if (_settings.SerialType == BlackMaple.MachineFramework.SerialType.AssignOneSerialPerCycle || _settings.SerialType == BlackMaple.MachineFramework.SerialType.AssignOneSerialPerMaterial ) { _log.RecordSerialForMaterialID(oldMat, _settings.ConvertMaterialIDToSerial(oldMat.MaterialID).PadLeft(_settings.SerialLength, '0'), state.LastSeenMessage.TimeUTC); } ret.Add(oldMat); var oldMatDetails = _log.GetMaterialDetails(oldMat.MaterialID); //allocate new materials, one per completed part in addition to the existing one for (int i = 1; i < count; i++) { var newId = _log.AllocateMaterialID(oldMatDetails.JobUnique, oldMatDetails.PartName, 1); var newMat = new JobLogDB.EventLogMaterial() { MaterialID = newId, Process = 1, Face = "" }; if (_settings.SerialType == BlackMaple.MachineFramework.SerialType.AssignOneSerialPerCycle) { _log.RecordSerialForMaterialID(newMat, oldMatDetails.Serial, state.LastSeenMessage.TimeUTC); } else if (_settings.SerialType == BlackMaple.MachineFramework.SerialType.AssignOneSerialPerMaterial) { _log.RecordSerialForMaterialID(newMat, _settings.ConvertMaterialIDToSerial(newId).PadLeft(_settings.SerialLength, '0'), state.LastSeenMessage.TimeUTC); } ret.Add(newMat); } return(ret); }
private static void AddUnloads(JobLogDB log, IEnumerable <LoadAction> currentActions, PalletStatus pallet, TimeSpan?elapsedLoadTime, List <BlackMaple.MachineWatchInterface.LogEntry> oldCycles, CurrentStatus status) { // For some reason, sometimes parts to unload don't show up in PalletSubStatus table. // So create them here if that happens foreach (var unload in currentActions) { if (unload.LoadEvent) { continue; } if (unload.LoadStation != pallet.CurrentPalletLocation.Num) { continue; } var matIDs = new Queue <long>(FindMatIDsFromOldCycles(oldCycles, unload.Unique, unload.Process)); status.Jobs.TryGetValue(unload.Unique, out InProcessJob job); for (int i = 0; i < unload.Qty; i += 1) { string face = unload.Process.ToString(); long matID = -1; if (matIDs.Count > 0) { matID = matIDs.Dequeue(); } var matDetails = log.GetMaterialDetails(matID); var inProcMat = new InProcessMaterial() { MaterialID = matID, JobUnique = unload.Unique, PartName = unload.Part, Process = unload.Process, Path = unload.Path, Serial = matDetails?.Serial, WorkorderId = matDetails?.Workorder, SignaledInspections = log.LookupInspectionDecisions(matID) .Where(x => x.Inspect) .Select(x => x.InspType) .ToList(), Location = new InProcessMaterialLocation() { Type = InProcessMaterialLocation.LocType.OnPallet, Pallet = pallet.Pallet, Face = unload.Process }, Action = new InProcessMaterialAction() { Type = InProcessMaterialAction.ActionType.UnloadToCompletedMaterial, ElapsedLoadUnloadTime = elapsedLoadTime } }; if (job != null) { if (unload.Process == job.NumProcesses) { inProcMat.Action.Type = InProcessMaterialAction.ActionType.UnloadToInProcess; } var queue = job.GetOutputQueue(process: unload.Process, path: unload.Path); if (!string.IsNullOrEmpty(queue)) { inProcMat.Action.UnloadIntoQueue = queue; } } status.Material.Add(inProcMat); } } }
private static void AddLoads(JobLogDB log, IEnumerable <LoadAction> currentLoads, string pallet, PalletLocation palLoc, TimeSpan?elapsedLoadTime, CurrentStatus curStatus) { var queuedMats = new Dictionary <string, List <BlackMaple.MachineFramework.JobLogDB.QueuedMaterial> >(); //process remaining loads/unloads (already processed ones have been removed from currentLoads) foreach (var operation in currentLoads) { if (!operation.LoadEvent || operation.LoadStation != palLoc.Num) { continue; } for (int i = 0; i < operation.Qty; i++) { List <BlackMaple.MachineFramework.JobLogDB.QueuedMaterial> queuedMat = null; if (curStatus.Jobs.ContainsKey(operation.Unique)) { var queue = curStatus.Jobs[operation.Unique].GetInputQueue(process: operation.Process, path: operation.Path); if (!string.IsNullOrEmpty(queue)) { //only lookup each queue once if (queuedMats.ContainsKey(queue)) { queuedMat = queuedMats[queue]; } else { queuedMat = log.GetMaterialInQueue(queue).ToList(); queuedMats.Add(queue, queuedMat); } } } long matId = -1; string serial = null; string workId = null; var loc = new InProcessMaterialLocation() { Type = InProcessMaterialLocation.LocType.Free }; if (queuedMat != null) { var mat = queuedMat .Where(m => m.Unique == operation.Unique) .Select(m => (JobLogDB.QueuedMaterial?)m) .DefaultIfEmpty(null) .First(); if (mat.HasValue) { matId = mat.Value.MaterialID; loc = new InProcessMaterialLocation() { Type = InProcessMaterialLocation.LocType.InQueue, CurrentQueue = mat.Value.Queue, QueuePosition = mat.Value.Position, }; queuedMat.RemoveAll(m => m.MaterialID == mat.Value.MaterialID); var matDetails = log.GetMaterialDetails(matId); serial = matDetails?.Serial; workId = matDetails?.Workorder; } } var inProcMat = new InProcessMaterial() { MaterialID = matId, JobUnique = operation.Unique, PartName = operation.Part, Process = operation.Process, Path = operation.Path, Serial = serial, WorkorderId = workId, Location = loc, Action = new InProcessMaterialAction() { Type = InProcessMaterialAction.ActionType.Loading, LoadOntoPallet = pallet, LoadOntoFace = operation.Process, ProcessAfterLoad = operation.Process, PathAfterLoad = operation.Path, ElapsedLoadUnloadTime = elapsedLoadTime } }; curStatus.Material.Add(inProcMat); } } }
public static CurrentStatus Build(JobDB jobDB, JobLogDB log, FMSSettings fmsSettings, IMachineGroupName machineGroupName, IQueueSyncFault queueSyncFault, MazakDbType dbType, MazakAllData mazakData, DateTime utcNow) { //Load process and path numbers Dictionary <string, int> uniqueToMaxPath; Dictionary <string, int> uniqueToMaxProcess; CalculateMaxProcAndPath(mazakData, out uniqueToMaxPath, out uniqueToMaxProcess); var currentLoads = new List <LoadAction>(mazakData.LoadActions); var curStatus = new CurrentStatus(); foreach (var k in fmsSettings.Queues) { curStatus.QueueSizes[k.Key] = k.Value; } if (mazakData.Alarms != null) { foreach (var alarm in mazakData.Alarms) { if (!string.IsNullOrEmpty(alarm.AlarmMessage)) { curStatus.Alarms.Add(alarm.AlarmMessage); } } } if (queueSyncFault.CurrentQueueMismatch) { curStatus.Alarms.Add("Queue contents and Mazak schedule quantity mismatch."); } var jobsBySchID = new Dictionary <long, InProcessJob>(); var pathBySchID = new Dictionary <long, MazakPart.IProcToPath>(); foreach (var schRow in mazakData.Schedules) { if (!MazakPart.IsSailPart(schRow.PartName)) { continue; } MazakPartRow partRow = null; foreach (var p in mazakData.Parts) { if (p.PartName == schRow.PartName) { partRow = p; break; } } if (partRow == null) { continue; } //Parse data from the database var partName = partRow.PartName; int loc = partName.IndexOf(':'); if (loc >= 0) { partName = partName.Substring(0, loc); } string jobUnique = ""; MazakPart.IProcToPath procToPath = null; bool manual = false; if (!string.IsNullOrEmpty(partRow.Comment)) { MazakPart.ParseComment(partRow.Comment, out jobUnique, out procToPath, out manual); } if (!uniqueToMaxProcess.ContainsKey(jobUnique)) { continue; } int numProc = uniqueToMaxProcess[jobUnique]; int maxProc1Path = uniqueToMaxPath[jobUnique]; InProcessJob job; //Create or lookup the job if (curStatus.Jobs.ContainsKey(jobUnique)) { job = curStatus.Jobs[jobUnique]; } else { var jobPaths = new int[numProc]; for (int i = 0; i < numProc; i++) { jobPaths[i] = maxProc1Path; } job = new InProcessJob(jobUnique, numProc, jobPaths); job.PartName = partName; job.JobCopiedToSystem = true; curStatus.Jobs.Add(jobUnique, job); } jobsBySchID.Add(schRow.Id, job); pathBySchID.Add(schRow.Id, procToPath); //Job Basics job.SetPlannedCyclesOnFirstProcess(procToPath.PathForProc(proc: 1), schRow.PlanQuantity); AddCompletedToJob(schRow, job, procToPath); job.Priority = schRow.Priority; if (((HoldPattern.HoldMode)schRow.HoldMode) == HoldPattern.HoldMode.FullHold) { job.HoldEntireJob.UserHold = true; } else { job.HoldEntireJob.UserHold = false; } AddRoutingToJob(mazakData, partRow, job, machineGroupName, procToPath, dbType); } var loadedJobs = new HashSet <string>(); foreach (var j in jobsBySchID.Values) { if (loadedJobs.Contains(j.UniqueStr)) { continue; } loadedJobs.Add(j.UniqueStr); AddDataFromJobDB(jobDB, j); } //Now add pallets foreach (var palRow in mazakData.Pallets) { if (palRow.PalletNumber > 0 && !curStatus.Pallets.ContainsKey(palRow.PalletNumber.ToString())) { var palName = palRow.PalletNumber.ToString(); var palLoc = FindPalletLocation(machineGroupName, mazakData, dbType, palRow.PalletNumber); //Create the pallet PalletStatus status = new PalletStatus() { Pallet = palName, CurrentPalletLocation = palLoc, FixtureOnPallet = palRow.Fixture, NumFaces = 1, OnHold = false }; curStatus.Pallets.Add(status.Pallet, status); var oldCycles = log.CurrentPalletLog(palName); //Add the material currently on the pallet foreach (var palSub in mazakData.PalletSubStatuses) { if (palSub.PalletNumber != palRow.PalletNumber) { continue; } if (palSub.FixQuantity <= 0) { continue; } if (!jobsBySchID.ContainsKey(palSub.ScheduleID)) { continue; } status.NumFaces = Math.Max(status.NumFaces, palSub.PartProcessNumber); var job = jobsBySchID[palSub.ScheduleID]; var procToPath = pathBySchID[palSub.ScheduleID]; var matIDs = new Queue <long>(FindMatIDsFromOldCycles(oldCycles, job.UniqueStr, palSub.PartProcessNumber)); for (int i = 1; i <= palSub.FixQuantity; i++) { int face = palSub.PartProcessNumber; long matID = -1; if (matIDs.Count > 0) { matID = matIDs.Dequeue(); } var matDetails = log.GetMaterialDetails(matID); var inProcMat = new InProcessMaterial() { MaterialID = matID, JobUnique = job.UniqueStr, PartName = job.PartName, Process = palSub.PartProcessNumber, Path = procToPath.PathForProc(palSub.PartProcessNumber), Serial = matDetails?.Serial, WorkorderId = matDetails?.Workorder, SignaledInspections = log.LookupInspectionDecisions(matID) .Where(x => x.Inspect) .Select(x => x.InspType) .Distinct() .ToList(), LastCompletedMachiningRouteStopIndex = oldCycles.Any( c => c.LogType == LogType.MachineCycle && !c.StartOfCycle && c.Material.Any(m => m.MaterialID == matID && m.Process == palSub.PartProcessNumber) ) ? (int?)0 : null, Location = new InProcessMaterialLocation() { Type = InProcessMaterialLocation.LocType.OnPallet, Pallet = status.Pallet, Face = face }, Action = new InProcessMaterialAction() { Type = InProcessMaterialAction.ActionType.Waiting } }; curStatus.Material.Add(inProcMat); //check for unloading or transfer var loadNext = CheckLoadOfNextProcess(currentLoads, job.UniqueStr, palSub.PartProcessNumber, palLoc); var unload = CheckUnload(currentLoads, job.UniqueStr, palSub.PartProcessNumber, palLoc); if (loadNext != null) { var start = FindLoadStartFromOldCycles(oldCycles, matID); inProcMat.Action = new InProcessMaterialAction() { Type = InProcessMaterialAction.ActionType.Loading, LoadOntoFace = palSub.PartProcessNumber + 1, LoadOntoPallet = status.Pallet, ProcessAfterLoad = palSub.PartProcessNumber + 1, PathAfterLoad = procToPath.PathForProc(palSub.PartProcessNumber + 1), ElapsedLoadUnloadTime = start != null ? (TimeSpan?)utcNow.Subtract(start.EndTimeUTC) : null }; } else if (unload != null) { var start = FindLoadStartFromOldCycles(oldCycles, matID); inProcMat.Action = new InProcessMaterialAction() { Type = palSub.PartProcessNumber == job.NumProcesses ? InProcessMaterialAction.ActionType.UnloadToCompletedMaterial : InProcessMaterialAction.ActionType.UnloadToInProcess, UnloadIntoQueue = job.GetOutputQueue( process: palSub.PartProcessNumber, path: procToPath.PathForProc(palSub.PartProcessNumber)), ElapsedLoadUnloadTime = start != null ? (TimeSpan?)utcNow.Subtract(start.EndTimeUTC) : null }; } else { // detect if machining var start = FindMachineStartFromOldCycles(oldCycles, matID); if (start != null) { var machStop = job.GetMachiningStop(inProcMat.Process, inProcMat.Path).FirstOrDefault(); var elapsedTime = utcNow.Subtract(start.EndTimeUTC); inProcMat.Action = new InProcessMaterialAction() { Type = InProcessMaterialAction.ActionType.Machining, ElapsedMachiningTime = elapsedTime, ExpectedRemainingMachiningTime = machStop != null?machStop.ExpectedCycleTime.Subtract(elapsedTime) : TimeSpan.Zero }; } } } } if (palLoc.Location == PalletLocationEnum.LoadUnload) { var start = FindLoadStartFromOldCycles(oldCycles); var elapsedLoad = start != null ? (TimeSpan?)utcNow.Subtract(start.EndTimeUTC) : null; AddLoads(log, currentLoads, status.Pallet, palLoc, elapsedLoad, curStatus); AddUnloads(log, currentLoads, status, elapsedLoad, oldCycles, curStatus); } } } //now queued var seenMatIds = new HashSet <long>(curStatus.Material.Select(m => m.MaterialID)); foreach (var mat in log.GetMaterialInAllQueues()) { // material could be in the process of being loaded if (seenMatIds.Contains(mat.MaterialID)) { continue; } var matLogs = log.GetLogForMaterial(mat.MaterialID); int lastProc = 0; foreach (var entry in log.GetLogForMaterial(mat.MaterialID)) { foreach (var entryMat in entry.Material) { if (entryMat.MaterialID == mat.MaterialID) { lastProc = Math.Max(lastProc, entryMat.Process); } } } var matDetails = log.GetMaterialDetails(mat.MaterialID); curStatus.Material.Add(new InProcessMaterial() { MaterialID = mat.MaterialID, JobUnique = mat.Unique, PartName = mat.PartName, Process = lastProc, Path = 1, Serial = matDetails?.Serial, WorkorderId = matDetails?.Workorder, SignaledInspections = log.LookupInspectionDecisions(mat.MaterialID) .Where(x => x.Inspect) .Select(x => x.InspType) .Distinct() .ToList(), Location = new InProcessMaterialLocation() { Type = InProcessMaterialLocation.LocType.InQueue, CurrentQueue = mat.Queue, QueuePosition = mat.Position, }, Action = new InProcessMaterialAction() { Type = InProcessMaterialAction.ActionType.Waiting } }); } var notCopied = jobDB.LoadJobsNotCopiedToSystem(DateTime.UtcNow.AddHours(-WriteJobs.JobLookbackHours), DateTime.UtcNow); foreach (var j in notCopied.Jobs) { if (curStatus.Jobs.ContainsKey(j.UniqueStr)) { //The copy to the cell succeeded but the DB has not yet been updated. //The thread which copies jobs will soon notice and update the database //so we can ignore it for now. } else { curStatus.Jobs.Add(j.UniqueStr, new InProcessJob(j)); } } foreach (var j in curStatus.Jobs) { foreach (var d in jobDB.LoadDecrementsForJob(j.Value.UniqueStr)) { j.Value.Decrements.Add(d); } } return(curStatus); }
public void ConvertsMaterialFromV17() { // existing v17 file has the following data in it var now = new DateTime(2018, 7, 12, 5, 6, 7, DateTimeKind.Utc); var mat1_1 = new LogMaterial(1, "uuu1", 1, "part1", 2, "serial1", "work1", face: "A"); var mat1_2 = new LogMaterial(1, "uuu1", 2, "part1", 2, "serial1", "work1", face: "B"); var mat2_1 = new LogMaterial(2, "uuu1", 1, "part1", 2, "serial2", "", face: "C"); var mat2_2 = new LogMaterial(2, "uuu1", 1, "part1", 2, "serial2", "", face: "D"); var mat3 = new LogMaterial(3, "uuu2", 1, "part2", 1, "", "work3", face: "E"); _log.GetLogEntries(now, now.AddDays(1)).Should().BeEquivalentTo(new[] { new LogEntry( cntr: -1, mat: new [] { mat1_1, mat2_1 }, pal: "3", ty: LogType.MachineCycle, locName: "MC", locNum: 1, prog: "proggg", start: false, endTime: now, result: "result", endOfRoute: false ), new LogEntry( cntr: -1, mat: new [] { mat1_2, mat2_2 }, pal: "5", ty: LogType.MachineCycle, locName: "MC", locNum: 1, prog: "proggg2", start: false, endTime: now.AddMinutes(10), result: "result2", endOfRoute: false ), new LogEntry( cntr: -1, mat: new [] { mat1_1 }, pal: "", ty: LogType.PartMark, locName: "Mark", locNum: 1, prog: "MARK", start: false, endTime: now.AddMinutes(20), result: "serial1", endOfRoute: false ), new LogEntry( cntr: -1, mat: new [] { mat1_1 }, pal: "", ty: LogType.OrderAssignment, locName: "Order", locNum: 1, prog: "", start: false, endTime: now.AddMinutes(30), result: "work1", endOfRoute: false ), new LogEntry( cntr: -1, mat: new [] { mat2_2 }, pal: "", ty: LogType.PartMark, locName: "Mark", locNum: 1, prog: "MARK", start: false, endTime: now.AddMinutes(40), result: "serial2", endOfRoute: false ), new LogEntry( cntr: -1, mat: new [] { mat3 }, pal: "1", ty: LogType.LoadUnloadCycle, locName: "L/U", locNum: 5, prog: "LOAD", start: false, endTime: now.AddMinutes(50), result: "LOAD", endOfRoute: false ), new LogEntry( cntr: -1, mat: new [] { mat3 }, pal: "", ty: LogType.OrderAssignment, locName: "Order", locNum: 1, prog: "", start: false, endTime: now.AddMinutes(60), result: "work3", endOfRoute: false ), }, options => options.Excluding(x => x.Counter) ); _log.GetMaterialDetails(1).Should().BeEquivalentTo(new MaterialDetails() { MaterialID = 1, JobUnique = "uuu1", PartName = "part1", NumProcesses = 2, Workorder = "work1", Serial = "serial1", Paths = new System.Collections.Generic.Dictionary <int, int>() }); _log.GetMaterialDetails(2).Should().BeEquivalentTo(new MaterialDetails() { MaterialID = 2, JobUnique = "uuu1", PartName = "part1", NumProcesses = 2, Workorder = null, Serial = "serial2", Paths = new System.Collections.Generic.Dictionary <int, int>() }); _log.GetMaterialDetails(3).Should().BeEquivalentTo(new MaterialDetails() { MaterialID = 3, JobUnique = "uuu2", PartName = "part2", NumProcesses = 1, Workorder = "work3", Serial = null, Paths = new System.Collections.Generic.Dictionary <int, int>() }); }