none
Out of Sequence Tasks

    Pertanyaan

  • using 2007 & 2010 - anybody have a macro to detect out of sequence tasks?  I have been getting schedules from our subs that have had several - I am finding them manually now and would like to have a macro that will ID and tag.

     

    GEM

    Senin, 07 November 2011 20.12

Semua Balasan

  • GEM1941,

    What exactly do you mean by "out of sequence tasks"?

    John

    Senin, 07 November 2011 20.21
  • Task A is FS with Task B

    Task A is 70% complete

    Task B is 10% complete

    Logically that is not possible because Task B cannot start before task A is complete and thus should be at 0% until Task A is at 100%.  Nevertheless, task B has been started and statused and is thus out of sequence.

    GEM

    Senin, 07 November 2011 22.33
  • GEM1941,

    Well, what that tells me is one of two things. Either task B was not dependent on task A (i.e. the original link was incorrect), or a part of task B was able to start even though the bulk of task B is in fact dependent on task A finishing.

    In the first case, reality has overcome the plan. Once task B started, the link is null and void.

    In the second case, it may or may not be necessary to break task B into two parts, the first part being independent of task A and the second part being dependent on completion of task A and the first part of task B.

    I wouldn't necessarily say that the plan is "out of sequence". It sounds like the plan needs to be reviewed and revised to reflect an updated plan.

    Your original post asked for a macro. What exactly would the criteria be for said macro? It's possible a filter or two might be all you need.

    John

    Selasa, 08 November 2011 02.08
  • I see nothing wrong with that scenario. Unless you detail tasks to ridiculous levels of detail, that happens all the time, especially for experienced resources for whom you only need high levels of detail. I could write a macro to do what you want, but would strongly recommend not to do anything other than flag tasks that might be "out of sequence".

    Rod Gill

    The one and only Project VBA Book Rod Gill Project Management
    Selasa, 08 November 2011 05.59
    Moderator
  • John,

    You are correct - the task(s) need review and realignment/relinking etc.  However, I need to find them first.  I have a tool that captures schedule metrics (a poor man's SteelRay) and I want to be able to capture this out-of-sequence situation as well so that I can address the problem.  There are approximately 20,000 tasks in the 4 schedules I review and I am looking for an automated way to capture it. 

    GEM

    Selasa, 08 November 2011 18.59
  • GEM,

    Okay, I understand, but you still haven't given us the details about the criteria for finding those tasks. Spell out the details you want and then we can go from there.

    What is the metric tool you use?

    John

    Selasa, 08 November 2011 20.24
  • I was hoping someone had already written something - as it is, I am in the process of writing code to capture the data.

    The tool I use is a home grown set of macros and a user form that captures and displays selected schedule metrics - I call it my  poor man's SteelRay.  It's not nearly as sophisticated, but it serves my purpose.

    I go thru the database and capture data concerning links, constraints, critical paths, baselines, start/finish, BEI, past due etc. and present the data in the user form with an option to export to Excel -similar to the DCMA 14 point with some modifications

     

    GEM

    Rabu, 09 November 2011 16.03
  • GEM,

    My guess is no one has written the code because of the reasons Rod and I stated, that is, it's not something project managers worry about. However, based on the example you gave yesterday I took a stab at a macro that will identify and flag tasks I think you want to review.

    Sub logicfault()

    Dim t As Task

    Dim pt As Task

    For Each t In ActiveProject.Tasks

        t.Flag1 = False

        If Not t Is Nothing Then

            If t.Summary = False And t.Predecessors > "0" And t.PercentComplete > 0 Then

                For Each pt In t.PredecessorTasks

                    If ActiveProject.Tasks(pt.ID).PercentComplete < 100 Then

                        t.Flag1 = True

                        ActiveProject.Tasks(pt.ID).Flag1 = True

                    End If

                Next pt

            End If

        End If

    Next t

    FilterEdit Name:="LogicFault", taskfilter:=True, create:=True, overwriteexisting:=True, _

        FieldName:="flag1", test:="equals", Value:="yes", ShowInMenu:=False, showsummarytasks:=False

    FilterApply Name:="LogicFault"

    End Sub

    John

    • Disarankan sebagai Jawaban oleh Johnny X Selasa, 20 Maret 2012 01.00
    • Saran Jawaban dibatalkan oleh Johnny X Selasa, 20 Maret 2012 01.00
    Rabu, 09 November 2011 16.18
  • I actually haven't fully thought thru the SF part and it may be missing an argument, but as i almost never use them, I haven't cared.  Also i have completely ignored lags and i bet they will erroneously get tagged.  Please provide feedback if you find any other issues. 

    Sub CheckOutOfSequence()
    'This macro will flag Text30 with offending out of sequence UIDS.
    Dim t As Task
    Dim ts As Tasks
    Dim a As Assignment
    Dim pred
    Dim predcount
    OptionsCalculation AUTOMATIC:=False
    If MsgBox("WARNING: This will replace any custom data in Text30.  Do you want to continue?", vbYesNo, "Out of Sequence Macro") = vbYes Then
        Set ts = ActiveProject.Tasks
        For Each t In ts
            t.Text30 = ""
            If Not t.Summary Then
                If t.PercentComplete > 0 Then
                    predcount = 1
                    For Each pred In t.PredecessorTasks
                        ' GET THE RELATIONSHIP TYPE
                        Select Case t.TaskDependencies(predcount).Type
                            Case pjFinishToStart
                                If pred.PercentComplete < 100 Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                ElseIf pred.ActualFinish > t.ActualStart Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                End If
                            Case pjStartToStart
                                If pred.PercentComplete = 0 Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                ElseIf pred.ActualStart > t.ActualStart Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                End If
                            Case pjFinishToFinish
                                If t.PercentComplete = 100 And pred.PercentComplete < 100 Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                ElseIf t.Finish < pred.Finish Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                End If
                            Case pjStartToFinish
                                If pred.Start < t.Finish Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                End If
                        End Select
                        predcount = predcount + 1
                    Next pred
                End If
            End If
        Next t
    End If
    OptionsCalculation AUTOMATIC:=True
    End Sub
    Selasa, 20 Maret 2012 01.00
  • I added code today to account for lags!  I believe this should cover everything! Please Please Please let me know if you find any situations where this code does not work correctly.  I believe I have tested all different cases of OOS i can think of and it correctly tags everything.

    Sub CheckOutOfSequence()
    '******************************************************************************************
    '*            This macro will flag Text30 with offending out of sequence UIDS.            *
    '*            This macro was developed by Johnny "is totally awesome" Barrett             *
    '* Feel free to copy/modify/distribute/delete/steal/take-credit-for any code found within *
    '******************************************************************************************


    Dim t As Task
    Dim ts As Tasks
    Dim a As Assignment
    Dim pred As Task
    Dim predcount As Integer


    OptionsCalculation AUTOMATIC:=False
    If MsgBox("WARNING: This will replace any custom data in Text30.  Do you want to continue?", vbYesNo, "Out of Sequence Macro") = vbYes Then
        Set ts = ActiveProject.Tasks
        For Each t In ts
            t.Text30 = ""
            If Not t.Summary Then
                If t.PercentComplete > 0 Then
                    predcount = 1
                    For Each pred In t.PredecessorTasks
                        ' GET THE RELATIONSHIP TYPE
                        Select Case t.TaskDependencies(predcount).Type
                            Case pjFinishToStart
                                If pred.PercentComplete < 100 Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                ElseIf t.TaskDependencies(predcount).Lag > 0 Then
                                    If Application.DateAdd(pred.ActualFinish, (t.TaskDependencies(predcount).Lag), ActiveProject.Calendar) > t.ActualStart Then
                                        If Len(t.Text30) = 0 Then
                                            t.Text30 = pred.UniqueID
                                        Else
                                            t.Text30 = t.Text30 & "," & pred.UniqueID
                                        End If
                                    End If
                                ElseIf t.TaskDependencies(predcount).Lag < 0 Then
                                    If Application.DateSubtract(pred.ActualFinish, -(t.TaskDependencies(predcount).Lag), ActiveProject.Calendar) > t.ActualStart Then
                                        If Len(t.Text30) = 0 Then
                                            t.Text30 = pred.UniqueID
                                        Else
                                            t.Text30 = t.Text30 & "," & pred.UniqueID
                                        End If
                                    End If
                                ElseIf pred.ActualFinish > t.ActualStart Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                End If
                            Case pjStartToStart
                                If pred.PercentComplete = 0 Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                ElseIf t.TaskDependencies(predcount).Lag > 0 Then
                                    If Application.DateAdd(pred.ActualStart, (t.TaskDependencies(predcount).Lag), ActiveProject.Calendar) > t.ActualStart Then
                                        If Len(t.Text30) = 0 Then
                                            t.Text30 = pred.UniqueID
                                        Else
                                            t.Text30 = t.Text30 & "," & pred.UniqueID
                                        End If
                                    End If
                                ElseIf t.TaskDependencies(predcount).Lag < 0 Then
                                    If Application.DateSubtract(pred.ActualStart, -(t.TaskDependencies(predcount).Lag), ActiveProject.Calendar) > t.ActualStart Then
                                        If Len(t.Text30) = 0 Then
                                            t.Text30 = pred.UniqueID
                                        Else
                                            t.Text30 = t.Text30 & "," & pred.UniqueID
                                        End If
                                    End If
                                ElseIf pred.ActualStart > t.ActualStart Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                End If
                            Case pjFinishToFinish
                                If t.PercentComplete = 100 And pred.PercentComplete < 100 Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                ElseIf t.TaskDependencies(predcount).Lag > 0 Then
                                    If Application.DateAdd(pred.Finish, (t.TaskDependencies(predcount).Lag), ActiveProject.Calendar) > t.Finish Then
                                        If Len(t.Text30) = 0 Then
                                            t.Text30 = pred.UniqueID
                                        Else
                                            t.Text30 = t.Text30 & "," & pred.UniqueID
                                        End If
                                    End If
                                ElseIf t.TaskDependencies(predcount).Lag < 0 Then
                                    If Application.DateSubtract(pred.Finish, -(t.TaskDependencies(predcount).Lag), ActiveProject.Calendar) > t.Finish Then
                                        If Len(t.Text30) = 0 Then
                                            t.Text30 = pred.UniqueID
                                        Else
                                            t.Text30 = t.Text30 & "," & pred.UniqueID
                                        End If
                                    End If
                                ElseIf pred.Finish > t.Finish Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                End If
                            Case pjStartToFinish
                                If t.TaskDependencies(predcount).Lag > 0 Then
                                    If Application.DateAdd(pred.Start, (t.TaskDependencies(predcount).Lag), ActiveProject.Calendar) < t.Finish Then
                                        If Len(t.Text30) = 0 Then
                                            t.Text30 = pred.UniqueID
                                        Else
                                            t.Text30 = t.Text30 & "," & pred.UniqueID
                                        End If
                                    End If
                                ElseIf t.TaskDependencies(predcount).Lag < 0 Then
                                    If Application.DateSubtract(pred.Start, -(t.TaskDependencies(predcount).Lag), ActiveProject.Calendar) < t.Finish Then
                                        If Len(t.Text30) = 0 Then
                                            t.Text30 = pred.UniqueID
                                        Else
                                            t.Text30 = t.Text30 & "," & pred.UniqueID
                                        End If
                                    End If
                                ElseIf pred.Start < t.Finish Then
                                    If Len(t.Text30) = 0 Then
                                        t.Text30 = pred.UniqueID
                                    Else
                                        t.Text30 = t.Text30 & "," & pred.UniqueID
                                    End If
                                End If
                        End Select
                        predcount = predcount + 1
                    Next pred
                End If
            End If
        Next t
    End If
    OptionsCalculation AUTOMATIC:=True
    End Sub


    • Disarankan sebagai Jawaban oleh Johnny X Rabu, 21 Maret 2012 22.33
    Rabu, 21 Maret 2012 22.33
  • We have a free tool that does this among other things.  It is called Run!23 and is available for free at goAzTech.com:  http://www.goaztech.com/run-23-for-ms-project.aspx

    OOS is any task that is currently underway when schedule logic indicates is should not be.  Examples include actual start/finish post the Status Date and the obvious A=>B=>C  where someone takes an actual start on "B" before "A" is completely finished.

    Run!23 is available for Project 2007 and Project 2010.


    If you feel this post answered the question, please vote for it. I am also available here:
    msprojectblog.com

    Senin, 06 Agustus 2012 16.24
    Moderator
  • Johnny,

    Great code! Even 6 years later it is still one of the most thorough OOS checks I have come across. Similar structure to what I use in my macros and add-ins. Only recommended change is to use the line:

    If IsDate(t.ActualStart) Then

    rather than

    If t.PercentComplete > 0 Then

    OptionsCalculation AUTOMATIC:=False
    If MsgBox("WARNING: This will replace any custom data in Text30.  Do you want to continue?", vbYesNo, "Out of Sequence Macro") = vbYes Then
        Set ts = ActiveProject.Tasks
        For Each t In ts
            t.Text30 = ""
            If Not t.Summary Then
                If t.PercentComplete > 0 Then     <------ Replace this line ----> If IsDate(t.ActualStart) Then

    The only situations that the existing macro misses are:

    • Finish to Start OOS situation: Predecessor finished and the successor has an Actual Start but 0% progress
    • Start to Start OOS situation: Predecessor started and the successor has an Actual Start but 0% progress

    While both these situations also include improperly statused successor tasks, the OOS macro as written doesn't catch either situation. In a properly statused schedule, the macro works perfectly otherwise. Excellent macro! 

    Senin, 01 Oktober 2018 19.38
  • Agree with you Jason.  JohnnyX's code should still work for the vast majority of out-of-sequence progress cases.  Edge cases:

    1. Actual Start with no progress - as you've pointed out.

    2. Elapsed lags

    3. Percentage lags

    4. Tasks with assigned task calendars.

    (At least those are the obvious ones that I had to hit in my add-in code).

    It's interesting to read John and Rod's comments from six years ago.... 

    Out-of-sequence progress has never seemed to be as big a deal in Project as it is in other tools.  I suspect this is mainly because the major issues kinda-sorta self-resolve in Project as soon as the OOS task is complete.  (OPV, on the other hand, retains the violated logic in perpetuity, affecting Early dates of activities that may be 10 steps removed from the original violator.)

    Last week I had an associate complaining of unexpected changes to his "Critical Path" during updating in Project 2016.  It turned out that recent Project versions are not so tolerant of his bad habits relating to out-of-sequence progress.  I wrote this article after resolving.  Bottom line, with OOS progress, Project will play some tricks with Total Slack.  It's best to avoid it (OOS) altogether.     

    Senin, 01 Oktober 2018 21.43
  • Tom, Read your article. Very informative! Definitely agree with you that we should seek to avoid OOS conditions. And if they do occur, the task relationships should be modified to represent how the work is being performed. Leads us down the topic of mandatory versus discretionary task relationships as you pointed out in your article.
    Rabu, 03 Oktober 2018 15.24