09 Mar Hard and Soft Dependencies
<A beer in London – £4.30!>
Most problems (or opportunities of course) arise from customer queries; really, if it wasn’t for you guys keeping me on my toes I would just spend everyday cycling…. Some days I combine Project and Project Server with cycling….
Anyway, I digress; one of my customers wanted a way to differentiate between mandatory and discretionary (or hard and soft) dependencies. If you are not sure of the difference, they have a quick look here…
For my customer, the idea was that they wanted to be able to enter both hard and soft dependencies, and then implement and remove the soft logic links at their own discretion. So it gives them the ability to implement “what if” scenarios if the schedule got a little “tight”, allowing them to remove the soft dependencies effectively crashing the project. Alas Project doesn’t allow use to add a flag to the dependency type, and so I figured the following work around. Please note that this is in early developmental stages and so feel free to use this code; and if you improve on it, please let me know; and if you use it, please credit me (oh, and buy me a beer when you see me).
Step 1.
Create a text custom fields, called soft predecessor(s) unique ID using Text1; if you cannot use this field, choose another one and modify the VBA accordingly. Note in the screen shot is shows that I have changed Text2 also; in the end I didn’t use this.
Step 2.
In your favourite table, add in the columns, unique ID and the Soft predecessor(s) unique ID. We need to utilise the unique task ID, as the usual ID field can change when tasks are moved/inserted etc. Typically I add these to the left of the predecessor column (which I typically move to the left of the task name anyway – the order isn’t important, but the visibility is).
Step 3.
Add the following VBA code into a module or macro in your favourite project client…. note that there are two procedures AddSoftPredecessors and RemoveSoftPredecessors. Their individual use should be fairly self explanatory.
Sub AddSoftPredecessors()
‘ 07/03/2014 Ben Howard – ben@applepark.co.uk http://applepark.co.uk/ben-howard-blog
Dim TskID1, TskID2, TskID3 As Long
Dim Tsks As Tasks
Dim Tsk As Task
SelectAll
Set Tsks = ActiveProject.Tasks
For Each Tsk In Tsks
‘ check to see if a task exists
If Not Tsk Is Nothing Then
‘ MsgBox (Tsk.Name)
‘ Tsk.Text2 = Tsk.UniqueIDPredecessors
‘ ConCatPreds = string concat(tsk.UniqueIDPredecessors, tsk.Text1)
If Tsk.Text1 <> “” Then
‘ MsgBox (Tsk.Name & ” has a predecessor”)
‘ Tsk.Text2 = Tsk.UniqueIDPredecessors & “,” & Tsk.Text1
If Tsk.UniqueIDPredecessors <> “” Then
tempstr = Tsk.UniqueIDPredecessors & “,” & Tsk.Text1
Else
tempstr = Tsk.Text1
‘ MsgBox (Tsk.Name & ” ” & tempstr)
End If
Tsk.UniqueIDPredecessors = tempstr
Else
‘ MsgBox (Tsk.Name & ” has no predecessor”)
End If
End If
Next Tsk
End Sub
Sub RemoveSoftPredecessors()
‘ 07/03/2014 Ben Howard – ben@applepark.co.uk http://applepark.co.uk/ben-howard-blog
Dim Tsks As Tasks
Dim Tsk As Task
SelectAll
Set Tsks = ActiveProject.Tasks
For Each Tsk In Tsks
‘ check to see if a task exists
If Not Tsk Is Nothing Then
‘ check to see if we have both hard predecessors and soft predecessors
If (Tsk.UniqueIDPredecessors <> “”) And (Tsk.Text1 <> “”) Then
‘ MsgBox (Tsk.Name & ” has this chacter ” & Tsk.Text1 & ” at position ” & InStr(Tsk.UniqueIDPredecessors, Tsk.Text1) & ” in the Predecessors”)
If InStr(Tsk.UniqueIDPredecessors, Tsk.Text1) >= 0 Then
‘we know that some part of the string is matched
‘MsgBox (Tsk.Name & ” some match”)
‘MsgBox (“Unique Predecessor length of ” & Tsk.Name & “is ” & Len(Tsk.UniqueIDPredecessors))
‘Find out if the next character is a delimiter
nextchar = Mid(Tsk.UniqueIDPredecessors, InStr(Tsk.UniqueIDPredecessors, Tsk.Text1) + 1, 1)
‘ MsgBox (“next char ” & nextchar)
newstr = Replace(Tsk.UniqueIDPredecessors, Tsk.Text1 & nextchar, “”)
‘ check if there is a ‘ as the last character
If Len(newstr) > 0 And ((InStrRev(newstr, “,”) = Len(newstr))) Then
‘MsgBox (“we have a comma as the last char”)
newstr = Left(newstr, Len(newstr) – 1)
End If
‘MsgBox (“NewStr ” & newstr)
Tsk.UniqueIDPredecessors = newstr
Else
‘MsgBox (Tsk.Name & ” no match”)
End If
‘ create a new string that removes duplicates from the two strings
End If
End If
Next Tsk
End Sub
Step 4.
Whilst we are playing around with adding the VBA/Macros, we might as well assign a couple of buttons to them in the ribbon. I’ll just include the final screen shot here. If you aren’t sure how to customise the ribbon, then buy the book!
Step 5.
Enter your predecessors and dependencies as usually would. These will become your “hard” predecessors. Project schedules and accordingly based upon these dependencies and the existing constraints and task mode(s) within the project. Notice that task T2 has hard predecessors of both T3 and T1.
Step 6.
Now comes the “fun” part. In the schedule, for each task, enter the soft predecessor unique ID(s). In the UK, these are separated by a comma; if your regional settings are different, you’ll need to modify the VBA. For Task T3, I am going to create a “soft” predecessor of task T1.
Step 7.
To apply this “soft” dependency and see the effect on the schedule, click on the Add Soft Predecessors button to run the VBA.
Notice how the Unique ID Predecessor (the hard predecessor) of task T3 now equals the Soft predecessor ID, and the consequence that it this then has on the rest of the schedule (task t3 and Task T4 have both moved).
Step 8.
You can remove the effects of the soft dependency by clicking on the Remove Soft Predecessors button.
If you want to see a video of this working, click here and look for the SoftLinksMacro video file.
Enjoy, Ben.