Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mathie/5813044 to your computer and use it in GitHub Desktop.
Save mathie/5813044 to your computer and use it in GitHub Desktop.
--==============================
-- OmniFocus > Prepare Task Completion Report
-- Version 2.0.0
-- Written By: Ben Waldie <ben@automatedworkflows.com>
-- http://www.automatedworkflows.com
-- Description: This script retrieves a list of OmniFocus tasks completed today, yesterday, this week, last week, or this month. It then summarizes the tasks in a new Evernote note.
-- Version History:
-- 1.0.0 - Initial release
-- 2.0.0 - Added support for including full project paths, context names, estimate time, start dates, modification dates, completion dates, and notes in task reports.
--==============================
-- This property controls whether full project paths (including parent folders) are displayed
property includeFullProjectPaths : true
-- These properties control whether additional task content is displayed
property includeTaskContext : true
property includeTaskEstimatedTime : true
property includeTaskStartDate : true
property includeTaskModificationDate : false
property includeTaskCompletionDate : true
property includeTaskNotes : true
-- This setting specifies a name for the new note
property noteNamedAfterDateRange : true
property evernoteNotebook : "Journal"
-- Extract some more properties for the bits I want to change
property defaultReport : "Today"
property startOfWeek : Monday
property endOfWeek : Sunday
property appendToExistingNote : true
-- Prompt the user to choose a scope for the report
activate
set theReportScope to choose from list {"Today", "Yesterday", "This Week", "Last Week", "This Month"} default items {defaultReport} with prompt "Generate a report for:" with title "OmniFocus Completed Task Report"
if theReportScope = false then return
set theReportScope to item 1 of theReportScope
-- Calculate the task start and end dates, based on the specified scope
set theStartDate to current date
set hours of theStartDate to 0
set minutes of theStartDate to 0
set seconds of theStartDate to 0
set theEndDate to theStartDate + (23 * hours) + (59 * minutes) + 59
if theReportScope = "Today" then
set theDateRange to date string of theStartDate
set singleDay to true
else if theReportScope = "Yesterday" then
set theStartDate to theStartDate - 1 * days
set theEndDate to theEndDate - 1 * days
set theDateRange to date string of theStartDate
set singleDay to true
else if theReportScope = "This Week" then
repeat until (weekday of theStartDate) = startOfWeek
set theStartDate to theStartDate - 1 * days
end repeat
repeat until (weekday of theEndDate) = endOfWeek
set theEndDate to theEndDate + 1 * days
end repeat
set theDateRange to (date string of theStartDate) & " through " & (date string of theEndDate)
set singleDay to false
else if theReportScope = "Last Week" then
set theStartDate to theStartDate - 7 * days
set theEndDate to theEndDate - 7 * days
repeat until (weekday of theStartDate) = startOfWeek
set theStartDate to theStartDate - 1 * days
end repeat
repeat until (weekday of theEndDate) = endOfWeek
set theEndDate to theEndDate + 1 * days
end repeat
set theDateRange to (date string of theStartDate) & " through " & (date string of theEndDate)
set singleDay to false
else if theReportScope = "This Month" then
repeat until (day of theStartDate) = 1
set theStartDate to theStartDate - 1 * days
end repeat
repeat until (month of theEndDate) is not equal to (month of theStartDate)
set theEndDate to theEndDate + 1 * days
end repeat
set theEndDate to theEndDate - 1 * days
set theDateRange to (date string of theStartDate) & " through " & (date string of theEndDate)
set singleDay to false
end if
-- Begin preparing the task list as HTML.
set theProgressDetail to "<h2>" & theDateRange & "</h2><br>"
-- Retrieve a list of projects modified within the specified scope
set modifiedTasksDetected to false
tell application "OmniFocus"
tell front document
set theModifiedProjects to every flattened project where its modification date is greater than theStartDate
-- Loop through any detected projects
repeat with a from 1 to length of theModifiedProjects
set theCurrentProject to item a of theModifiedProjects
-- Retrieve any project tasks modified within the specified scope
set theCompletedTasks to (every flattened task of theCurrentProject where its completed = true and modification date is greater than theStartDate and modification date is less than theEndDate and number of tasks = 0)
-- Process the project if tasks were found
if theCompletedTasks is not equal to {} then
set modifiedTasksDetected to true
-- Append the project folder path to the project name
set theProjectFolderPath to ""
if includeFullProjectPaths = true then
set theProjectFolderPath to getProjectFolderPath(theCurrentProject) of me
if theProjectFolderPath is not equal to "" then set theProjectFolderPath to theProjectFolderPath & " > "
end if
-- Append the project name to the report
set theProgressDetail to theProgressDetail & "<h3>" & theProjectFolderPath & name of theCurrentProject & "</h3>" & return & "<br><ul>"
-- Loop through the detected tasks for the project
repeat with b from 1 to length of theCompletedTasks
set theCurrentTask to item b of theCompletedTasks
-- Append the tasks's name to the task list
set theProgressDetail to theProgressDetail & "<li>" & name of theCurrentTask
-- Append the context to the task detail
if includeTaskContext = true then
set theContext to context of theCurrentTask
if theContext is not equal to missing value then set theProgressDetail to theProgressDetail & " <span style=\"color: gray\">(" & name of theContext & ")</span>"
end if
-- Set up a variable for the task detail, if relevant
set theTaskDetail to ""
-- Append the estimated time to the task detail
if includeTaskEstimatedTime = true then set theTaskDetail to appendTaskDetail(theTaskDetail, estimated minutes of theCurrentTask, "Estimated Time", " minutes") of me
-- Append the start date to the task detail
if includeTaskStartDate = true then
set theTaskStartDate to start date of theCurrentTask
if theTaskStartDate is not equal to missing value then set theTaskStartDate to date string of theTaskStartDate
set theTaskDetail to appendTaskDetail(theTaskDetail, theTaskStartDate, "Start on", "") of me
end if
-- Append the modification date to the task detail
if includeTaskModificationDate = true then
set theModificationDate to modification date of theCurrentTask
if singleDay = true then set theModificationDate to time string of theModificationDate
set theTaskDetail to appendTaskDetail(theTaskDetail, theModificationDate, "Last modified at", "") of me
end if
-- Append the completion date to the task detail
if includeTaskCompletionDate = true then
set theCompletionDate to completion date of theCurrentTask
if singleDay = true then set theCompletionDate to time string of theCompletionDate
set theTaskDetail to appendTaskDetail(theTaskDetail, theCompletionDate, "Completed at", "") of me
end if
-- Append the task's notes to the task detail
if includeTaskNotes = true then set theTaskDetail to appendTaskDetail(theTaskDetail, note of theCurrentTask, "Note", "") of me
-- Append the task detail to the task list
if theTaskDetail is not equal to "" then
set theProgressDetail to theProgressDetail & "<br><p style=\"color: gray\">" & theTaskDetail & "</p>"
end if
-- Finish adding the task's HTML to the list
set theProgressDetail to theProgressDetail & "</li>" & return
end repeat
set theProgressDetail to theProgressDetail & "</ul>" & return
end if
end repeat
end tell
end tell
-- Notify the user if no projects or tasks were found
if modifiedTasksDetected = false then
display alert "OmniFocus Completed Task Report" message "No modified tasks were found for " & theReportScope & "."
return
end if
if noteNamedAfterDateRange = true then
set theRealNoteName to theDateRange
else
set theRealNoteName to theNoteName
end if
-- Create the note in Evernote.
tell application "Evernote"
activate
if appendToExistingNote = true then
set theMatchingNotes to find notes "notebook:\"" & evernoteNotebook & "\" intitle:\"" & theRealNoteName & "\""
if theMatchingNotes is not equal to {} then
set theNote to item 1 of theMatchingNotes
append theNote html "<br><hr><br>" & theProgressDetail
else
set theProgressDetail to "<html><body><h1>Completed Tasks</h1><br>" & theProgressDetail & "</body></html>"
set theNote to create note notebook evernoteNotebook title theRealNoteName with html theProgressDetail
end if
else
set theProgressDetail to "<html><body><h1>Completed Tasks</h1><br>" & theProgressDetail & "</body></html>"
set theNote to create note notebook evernoteNotebook title theRealNoteName with html theProgressDetail
end if
end tell
-- This handler gets the folder path for a project
on getProjectFolderPath(theProject)
tell application "OmniFocus"
set theFolderPath to ""
if folder of theProject exists then
set theFolder to folder of theProject
repeat
if theFolderPath is not equal to "" then set theFolderPath to " : " & theFolderPath
set theFolderPath to name of theFolder & theFolderPath
if class of container of theFolder = folder then
set theFolder to container of theFolder
else
exit repeat
end if
end repeat
end if
if theFolderPath = "" then set theFolderPath to ""
return theFolderPath
end tell
end getProjectFolderPath
-- This handler appends a value to the task detail
on appendTaskDetail(theTaskDetail, theValue, thePrefix, theSuffix)
if theValue = missing value or theValue = "" then
return theTaskDetail
else
if theTaskDetail is not equal to "" then set theTaskDetail to theTaskDetail & "<br>"
set theValue to theValue & theSuffix
return theTaskDetail & thePrefix & ": " & theValue
end if
end appendTaskDetail
@mathie
Copy link
Author

mathie commented Jun 19, 2013

Extract additional configuration:

  • Name of the Evernote notebook
  • Default report (I want 'today' by default to run at the end of the day).
  • Start and end of week (Monday -> Sunday for me).

Also tweak appendTaskDetail so it doesn't if there's no data to append (instead of displaying N/A).

@mathie
Copy link
Author

mathie commented Jun 19, 2013

Now tweaked to append to an existing note instead of creating a new one each time.

@mathie
Copy link
Author

mathie commented Jun 19, 2013

Now onto personal style preferences:

  • Don't show modification date (chances are the last thing I'll do to a task is complete it, so completion and modification date are likely the same).
  • h3 for the project name, since the date range is an h2.
  • Collapse the context down into the title.
  • Don't open the note in a new window, ta.

Oh, and tweak the date-related property ifs so it actually honours the right ones.

@mathie
Copy link
Author

mathie commented Jun 19, 2013

And (finally, for now, at least):

  • Start dates are just shown as dates, not date/times.
  • If the report range is a single day, then modification/completion is just a time, not a date.

@mathie
Copy link
Author

mathie commented Jun 28, 2013

Tweaked the project fetcher to fetch projects modified between the start date and now, rather than the start date and end date. That way, when reporting on 'yesterday' (or any other historical report) it will also consider tasks completed yesterday inside projects that have been subsequently modified today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment