Applescript – Split activity in completed and remaining sub tasks

When managing a project with Merlin you create your tasks and assign them to your resources. As your resources work on their task, you as a PM update your project by entering the actual values. That means, you enter the percentage of the completed work and the actual start date. If updating the tasks in absolute mode, you can enter the actual work or remaining work and duration.

Next time the resource works on the task, and reports its progress to update the data, you enter the new ‘% complete’ and if updating the tasks in absolute mode, the amount of actual work and remaining work so far.

Some users however would like to be able to pause the works on a task, to plan the remaining work sometime later on. This is also a good idea, if wanting to vary the utilization of a resource on a task in time.  So to do so in Merlin, you would need to create two tasks. One for the first part of the works on the task, and a second for the remaining.

To quicken this procedure, we wrote an applescript sample which requires Merlin 2.8.4 or newer, and creates the two sub-activities based on the planned and actual values of the task in progress.

If interested, feel free to download, use or modify as you like. 

(*     Scripting with Merlin 2

    You may incorporate this ProjectWizards sample code into your program(s) without
    restriction.  This ProjectWizards sample code has been provided "AS IS" and the
    responsibility for its operation is yours.  You are not permitted to
    redistribute this ProjectWizards sample code as "ProjectWizards sample code" after having
    made changes.  If you're going to redistribute the code, we require
    that you make it clear that the code was descended from ProjectWizards sample
    code, but that you've made changes.

    Copyright ® 2012-2014 ProjectWizards, Melle, Germany. All rights reserved.

    This script splits tasks in progress into two tasks; a completed and a remaining task.
    It handles assignments and absolute updated actual values defined on the task.
    It does not split assignments, milestones or activity groups.
    It won't split tasks which are completed, or not yet started.

        Just select the task you want to split and call this script.
    Version info: 1.0
    Author: Vicky Stamatopoulou
    Date: May 2012
    
    Version info: 1.2
    Author: Vicky Stamatopoulou
    Date: June 2014
    Info: the script will now run on Mavericks too, revised the error and error reporting handing

*)
----

property howthisworksDialogString : "Please select the activity you would like to split into completed and remaining tasks and restart this script."
property TheActivityDialogString : "The activity "
property isPlannedForDialogString : " is planned for "
property splitinto2DialogString : ". Would you like to split it into completed and remaining work tasks?"
property howMuchLeadDialogString : "How much lead/lag in days would you need? Leave entry blank for zero lead."
property errorDialogString : "This script splits activities in progress having a given work. It cannot split activity groups, assignments, milestones, elements and completed or not yet started activities."
property completedDialogueString : "Nothing to split! Activity already completed. "
property notStartedDialogueString : "Nothing to split! Activity hadn't been started yet. "
property noWorkDialogueString : "Nothing to split! Activity has no given work. "
property milestoneDialogueString : "Nothing to split! Milestone selected. "
property assignmentDialogueString : "Nothing to split! Assignment selected. "
property projectDialogueString : "Nothing to split! Project row selected. "
property groupDialogueString : "Nothing to split! Group row selected. "

global myStrings
set myStrings to {howthisworksDialogString, projectDialogueString, groupDialogueString, assignmentDialogueString, milestoneDialogueString, notStartedDialogueString, completedDialogueString, noWorkDialogueString}


on reportError(errorNumber)
    global myStrings
    -- errors: 
    -- 1 nothing selected
    -- 2 for project
    -- 3 group
    -- 4 assignment
    -- 5 milestone
    -- 6 not started
    -- 7 completed
    -- 8 no work
    
    activate
    set displayMessage to ""
    set displayMessage to item (errorNumber) of myStrings
    
    tell application "Merlin" to display dialog displayMessage & return & return & errorDialogString buttons {"OK"} default button 1 with icon 0
    
    
end reportError

on checkToRun(anItem)
    global errorStatus
    -- errors: 
    -- 1 no selection
    -- 2 for project
    -- 3 group
    -- 4 assignment
    -- 5 milestone
    -- 6 not started
    -- 7 completed
    -- 8 no work
    
    tell application "Merlin"
        
        if (class of anItem is project) then
            set errorStatus to 2
            return false
        end if
        if (is milestone of anItem is true) then
            set errorStatus to 5
            return false
        end if
        
        -- do not handle zero work and zero duration
        set TheWork to given planned work of anItem
        if TheWork is missing value then
            set errorStatus to 3
            return false
        end if
        
        if (class of anItem is assignment) then
            set errorStatus to 4
            return false
        end if
        -- check groups
        try
            assignments of anItem
        on error
            set errorStatus to 3
            return false
        end try
        
        
        
        -- do not handle completed tasks or not yet started ones
        set theCompleteness to given actual completion of anItem
        if theCompleteness is missing value then set theCompleteness to actual completion of anItem
        
        if (theCompleteness is 1) or (theCompleteness is 0) then
            
            
            if theCompleteness is 0 then set errorStatus to 6
            if theCompleteness is 1 then set errorStatus to 7
            
        end if
        
        
        if errorStatus > 0 then
            return false
        else
            return true
        end if
    end tell
end checkToRun


tell application "Merlin"
    
    activate
    set errorStatus to 0
    try
        -- get selection
        set myselection to selected object of main window of document 1 as specifier
        
    on error
        set errorStatus to 1
    end try
    -- get activity information
    
    if errorStatus is 0 and checkToRun(myselection) of me then
        
        tell myselection
            set TheActivity to title
            set TheWork to given planned work
            set TheExpectedWork to expected work
            set TheActualWork to actual work
            set remainingWork to given remaining work
            
            set theCompleteness to given actual completion
            if theCompleteness is missing value then set theCompleteness to actual completion
            
        end tell
        
        
        try
            -- get assignement information
            set TheResource to assigned resource of myselection as list
            set TheResourceName to (names of TheResource) as list
            set TheActualStart to actual start date of myselection
        end try
        
        tell TheWork
            set TheAmount to amount
            set TheFloating to floating as boolean
            set TheRelativeError to relative error as integer
            set TheUnit to unit
            
        end tell
        
        try
            set dialogResult to display dialog TheActivityDialogString & TheActivity & isPlannedForDialogString & TheAmount & " " & TheUnit & splitinto2DialogString buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" with icon 2
            
            
            if button returned of dialogResult is "OK" then
                
                set TheActualWorkAmount to amount of TheActualWork
                set TheUnit to unit of TheActualWork
                
                -- Prompt for lead/lag
                set TheLead to display dialog howMuchLeadDialogString default answer "" buttons {"OK"} default button 1 with icon 2
                
                set TheLead to text returned of TheLead
                if TheLead is "" then set TheLead to "0d"
                
                -- create completed task
                set TheNewOne to (make new activity) as specifier
                tell TheNewOne
                    set given planned work to {amount:TheActualWorkAmount, unit:TheUnit, floating:TheFloating, relative error:TheRelativeError}
                    set title to "part 1"
                    
                    set given actual completion to 1
                    set actual start date to TheActualStart
                    
                end tell
                
                if remainingWork is missing value then
                    set remainingWorkAmount to (amount of TheWork) - (theCompleteness * (amount of TheWork))
                    set TheUnit to unit of TheWork
                    
                else
                    set remainingWorkAmount to amount of remainingWork
                    set TheUnit to unit of remainingWork
                end if
                
                -- create remaining task
                set TheNewSec to (make new activity) as specifier
                tell TheNewSec
                    set given planned work to {amount:remainingWorkAmount, unit:TheUnit}
                    set title to "part 2"
                end tell
                
                -- relate activities finish to start
                set TheRelation to relate TheNewOne to TheNewSec
                -- set lead/lag onto linkage
                set buffer duration of TheRelation to TheLead
                repeat with aRes in TheResource
                    tell aRes
                        -- do assignements
                        try
                            assign resource to activity TheNewOne
                            assign resource to activity TheNewSec
                        end try
                    end tell
                end repeat
                
                -- group the activities under the selection
                move TheNewOne to the end of every activity of myselection
                move TheNewSec to the end of every activity of myselection
                tell myselection
                    set given planned work to {amount:0, unit:TheUnit, floating:TheFloating, relative error:TheRelativeError}
                end tell
            end if
        on error number -128
            --don't do anything        
        end try
    else
        reportError(errorStatus) of me
    end if
    
end tell

Update: June 6th, 2014
Modified script for better error handling and Mavericks support

Download: split_activity.applescript.zip

If considering putting the script in the scripts folder of Merlin, you should make sure the script is saved in the file format ‘Text’ for it to be able to show currently the duration of the planned work of the selected task. This solves a general Applescript issue mentioned here.