iCal / Excel script finalizing

below is my current script, that has evolved from a while back when i first started this. What i want to modify is this:

  1. Is there a way to modify a calendar, instead of replacing it? for example… originally i have a calendar of to-dos made from an excel file. Later, when the excel file gets modified, it automatically looks in ical for the existing calendar, deletes and then make a new one of same name with new to-dos. INSTEAD…after the excel file is modified, I want it to look for the existing calendar, then compare the titles & dates. If they dont match the new file, then it should ONLY replace the unmatched to-dos.

  2. If #1 is not possible, then is there a way to make any new to-dos complete ONLY if the date is passed. so…if i make a new calendar and some of the dates are from last week or earlier, then they are marked as completed. If the dates are today or later, then they are NOT marked as completed.

  3. is there a way to specify the group that the new calendar should be made in?

  4. Is there a way to get the description for a to-do to be 2 variables, for example ProjectName - ReviseDate


on adding folder items to this_folder after receiving added_items
	tell application "Microsoft Excel"
		repeat with anitem in added_items
			open anitem
			print out active sheet
			set ProjectName to the value of cell "$F$4"
			set ReviseDate to the value of cell "$Z$4" as string
			tell (get value of range "D12:Z12") to set these_Dates to list 1
			my Schedule(ProjectName, ReviseDate, these_Dates)
			close front window
		end repeat
	end tell
end adding folder items to

on Schedule(ProjectName, ReviseDate, these_Dates)
	set the_titles to {"All Tooling Patterns in HK", "Rough Ceramics", "Tooling Quote Submitted", "Casting Ceramics", "Approval of Casting Ceramics", "Rough Ceramics to Tempe", "Tooling PO in HK", "Tooling Start", "Paintmaster in HK", "Production Quote Submitted", "Production Facility Confirmed", "1st Shot Samples", "Blister Layout in HK", "1st Deco Samples", "Mock-up Packaging Samples", "Packaging Artwork in HK", "EP Samples", "Production PO in HK", "Release Printing", "Release Injection", "Release Decoration", "PP Samples", "1st Shipment"}
	set tc to count the_titles
	
	tell application "iCal"
		if (exists calendar ProjectName) then delete calendar ProjectName
		set theCal to make new calendar at end of calendars with properties {title:ProjectName, color:{37500, 0, 0}, description:ReviseDate}
		tell theCal to repeat with i from 1 to tc
			set t_date to item i of these_Dates
			if (t_date is not "N/A" and t_date is not "" and t_date is not "NA" and t_date is not "on hold") then ¬
				make new todo at end of todos with properties {due date:t_date, summary:item i of the_titles, location:ReviseDate, allday event:true, status:confirmed, description:ProjectName}
		end repeat
		quit
	end tell
end Schedule

I certainly think that your item 1 is possible, and that you can revise your list of iCal todos without creating a new one every time. I do a similar thing with Palm Desktop utilizing list comparisons. When I do the update, my script first generates a list of records for every item already on the Palm, then it creates a list of records of everything that needs to be updated, and loops through that list, one record at a time, to see if it is already in the Palm database. If not, it is sent to a handler for insertion. I do not think it would be overly challenging to do the same with your Excel/iCal system.

I have been playing with your handler on Schedule(ProjectName, ReviseDate, these_Dates), but I cannot see where your location:ReviseDate does anything that can be found later on. The location property is associated with events in iCal, not with todos. Have you checked to see if the todos created by this handler can access that property? I cannot.

What I was able to do, however, was to generate a list of todos with their summaries and due dates:

tell application "iCal"
	set todo_List to {}
	repeat with atd in (get every todo of calendar "Work")
		set end of todo_List to {atd's due date, atd's summary}
	end repeat
end tell
-->{{date "Thursday, May 24, 2007 9:16:07 AM", "sic"}, {date "Friday, May 25, 2007 9:16:07 AM", "seven"}, {date "Monday, May 28, 2007 9:16:07 AM", "ten"}, {date "Monday, May 21, 2007 9:16:07 AM", "threee"}

These data would correspond to your script’s ProjectName and list of these_Dates. Therefore, you could alter your script with a third handler that accepts all the data you now send to on Schedule(ProjectName, ReviseDate, these_Dates) which would loop through everything as it does now, and check to see if an item already exists with the proper due date and ProjectName, and if not, send that data to the handler for creation of the new todo.

One important thing to keep in mind through this is formatting the list containment if/then:

set present_todos to {{date "Thursday, May 24, 2007 9:16:07 AM", "sic"}, {date "Friday, May 25, 2007 9:16:07 AM", "seven"}, {date "Monday, May 28, 2007 9:16:07 AM", "ten"}, {date "Monday, May 21, 2007 9:16:07 AM", "threee"}}

present_todos contains {date "Thursday, May 24, 2007 9:16:07 AM", "sic"}
--> false

However:

set present_todos to {{date "Thursday, May 24, 2007 9:16:07 AM", "sic"}, {date "Friday, May 25, 2007 9:16:07 AM", "seven"}, {date "Monday, May 28, 2007 9:16:07 AM", "ten"}, {date "Monday, May 21, 2007 9:16:07 AM", "threee"}}

present_todos contains {{date "Thursday, May 24, 2007 9:16:07 AM", "sic"}}
--true

The details of this little quirk can be found under the topic How to compare lists that contain sublists, which is #5 at this location.

I hope this helps, and I would be glad to assist you further on this if needed.

i understand your first part is basically pulling the list of todos from ical…but how do i compare that list with the list from excel, and then only replace the modified todos? i really don’t know much of anything with applescript…as i am just learning…but i need this script for work so that i can save 2-3 hours of frustration every day.

when i drop a new excel file into the folder…this script runs aitomatically. Its aim is to open in excel and copy the project name, and then each stage title of development (26 total) along with their corresponding dates of completion. It will then open ical and look to see if a calendar with the same project name already exists. If no, then it will create a new calendar with the list of todos.

The problem im trying to resolve, is if a calendar with same project name DOES exist, i dont want to delete the whole calendar anymore. Instead, i want to compare the one list from excel (stage titles and corresponding dates) to the second list from ical (stage titles and corresponding dates). Now, some of the stage titles and corresponding dates will match between the 2 lists, and thus should be ignored if they do match.

BUT, for the ones that don’t match, i want them to delete the old todos (the ones that don’t match in the ical list), and replace them in the same calendar with new todos based on the new list (from excel)

BTW:
here is my modified script, in which i made your “location correction” as well as modified a few other corrections. Please help me out.


on adding folder items to this_folder after receiving added_items
	tell application "Microsoft Excel"
		repeat with anitem in added_items
			open anitem
			print out active sheet
			set ProjectName to the value of cell "$F$4"
			set ReviseDate to the value of cell "$Z$4" as string
			set TRIDate to the value of cell "$S$12"
			tell (get value of range "D12:Z12") to set these_Dates to list 1
			my Schedule(ProjectName, ReviseDate, these_Dates, TRIDate)
			close front window
		end repeat
	end tell
end adding folder items to

on Schedule(ProjectName, ReviseDate, these_Dates, TRIDate)
	set the_titles to {"Toolings Due", "Rough Ceramics", "Tooling Quote", "Casting Ceramics", "Approve Castings", "Ceramics to Tempe", "Tooling PO", "Tooling Start", "Paintmasters", "Vendor Quote", "Vendor Confirmed", "1st Shot", "Blister Layout", "1st Deco", "Packaging Mock-ups", "Packaging CD", "EP", "Vendor PO", "Release Printing", "Release Injection", "Release Decoration", "PP", "1st Shipment"}
	set tc to count the_titles
	
	tell application "iCal"
		if (exists calendar ProjectName) then delete calendar ProjectName
		set theCal to make new calendar at end of calendars with properties {title:ProjectName, color:{0, 20000, 50000}, description:ReviseDate}
		tell theCal to repeat with i from 1 to tc
			set t_date to item i of these_Dates
			if (t_date is not "N/A" and t_date is not "" and t_date is not "NA" and t_date is not "on hold") then ¬
				make new todo at end of todos with properties {due date:t_date, summary:item i of the_titles, allday event:true, status:confirmed, description:ProjectName, url:ReviseDate}
		end repeat
		tell theCal to make new todo at end of todos with properties {due date:(TRIDate + weeks), summary:"TRI Files", status:confirmed, description:ProjectName, url:ReviseDate}
		quit
	end tell
end Schedule

I’m happy to help, but I may need to see either one of your Excel files, or at least a good list of the pertinent values that you extract therefrom. It would also not be a bad idea to send one of the calendars as well.

http://www.bluenotedesigns.com/milestone.zip

normally i use the original milestone (the one with earlier date) to create the first calendar.
then periodically we receive updated milestones. sometimes several updates (10) in the life of one project. but as we go on…only the later dates are changed.

i want to be able to keep the completed todos so that i can know when each event was completed and have a complete calendar for reference.

if i replace the whole calendar…then i lose the completion dates for earlier steps…not to mention i would then need to re-check all the events that have already completed.

OK, thanks, very helpful. First off, your variable ReviseDate (that you are trying to associate with the url property) is still not coming though on any of the todos. I assume that you want it visible, so that you know when the last sheet update was performed? I suggest that you add it to the ProjectName variable so that it comes up in description for each todo. In fact, I carried my suggestion to completion, so you can see for yourself if you like it.

Anyway, I have added comments along the way to hopefully explain what I have done, so you should be able to follow along. I did not test it as a droplet or folder action, or with multiple Excel sheets. Even so, it should be pretty darn close to what you are looking for.

I am still confused about one thing. In your original Schedule handler, you had a command to make a final todo (which I have moved, but left intact) based on the variable TRIDate. You then make the due date to be (TRIDate + weeks). What is that all about? I would like to know, if you don’t mind.

It could probably be cleaned up a bit more, but anyway, try this out, and let me know if it not quite right yet:

global the_titles, these_Dates --Now, these lists can be accessed at any time during execution of the script
on adding folder items to this_folder after receiving added_items
	set the_titles to {"Toolings Due", "Rough Ceramics", "Tooling Quote", "Casting Ceramics", "Approve Castings", "Ceramics to Tempe", "Tooling PO", "Tooling Start", "Paintmasters", "Vendor Quote", "Vendor Confirmed", "1st Shot", "Blister Layout", "1st Deco", "Packaging Mock-ups", "Packaging CD", "EP", "Vendor PO", "Release Printing", "Release Injection", "Release Decoration", "PP", "1st Shipment"}
	tell application "Microsoft Excel"
		repeat with anitem in added_items
			open anitem
			print out active sheet
			set ProjectName to the value of cell "$F$4"
			set ReviseDate to the value of cell "$Z$4" as string
			set TRIDate to the value of cell "$S$12"
			tell (get value of range "D12:Z12") to set these_Dates to list 1
			close front window
		end repeat
	end tell
	tell application "iCal"
		if not (exists calendar ProjectName) then --make the calendar if necessary
			make new calendar at end of calendars with properties {title:ProjectName, color:{0, 20000, 50000}, description:ReviseDate}
		end if
		set Final_todo_List to {}
		repeat with atd in (get every todo of calendar ProjectName) --Get all the current todos of the calendar.  If the calendar was just created, it will return an empty list, and should still function.
			set end of Final_todo_List to {atd's due date, atd's summary} --Create a list of all found todos with their due date and summary, which should be unique to each todo.
		end repeat
		
	end tell
	
	repeat with a_Date from 1 to (these_Dates's length) --Now, we go through each date from the Excel spreadsheet
		if Final_todo_List does not contain {{(item a_Date of these_Dates), (item a_Date of the_titles)}} then --If the list of todos gathered from iCal does not already contain the possible todo, it needs to be made fresh:
			Schedule(ProjectName, ReviseDate, a_Date, TRIDate)
		end if
	end repeat
	tell application "iCal"
		tell theCal to make new todo at end of todos with properties {due date:(TRIDate + weeks), summary:"TRI Files", status:confirmed, description:(ProjectName & " - " & ReviseDate)}
		quit
	end tell
end adding folder items to

on Schedule(ProjectName, ReviseDate, i, TRIDate) --This should now create a single todo when called
	set t_date to item i of these_Dates
	tell application "iCal"
		tell calendar ProjectName
			if (t_date is not "N/A" and t_date is not "" and t_date is not "NA" and t_date is not "on hold") then ¬
				make new todo at end of todos with properties {due date:t_date, summary:item i of the_titles, allday event:true, status:confirmed, description:(ProjectName & " - " & ReviseDate)}
		end tell
	end tell
end Schedule

thanks a lot for the help

  • i did realize the url wasnt working…but i wasn’t too concerned about that point that much yet…that was set for a later fix :smiley:

  • i am just starting to examine what you did, and how you did it, but i wanted to let you know 3 problems:

  1. it seems the script hangs or stops…as it doesnt quit ical
  2. the TRIDate does not get added
  3. when “updating” the calendar using a newer milestone, it adds the new events that dont match, but does not remove the old events it is replacing. For example…in the 2 milestones i gave you… “EP” stage has a date change, and so the old one should remove, and the new one added…instead i am left with 2 EP due dates.

side note - the TRIDate is based on the “Packaging CD”. First the “Packaging CD” is due in english, and 7 days later we need to receive the trilingual artwork files. since we dont include the “TRI Files” in the excel file, i need to have the script do extra work to take the “Packaging CD” due date, add 7 days, modify title, and make new todo.

side side note - the TRIDate would also need to be included in the comparison of 2 lists…

bluenote:

Thanks for the feedback. I neglected to change the tell theCal to tell calendar ProjectName as I had before. I also inserted an automatic todo deletion before each todo creation, so that whenever an update is detected, the old will be deleted before the new is created. Since the examination of each todo is now outside of the creation handler, your calendar will not suffer from total annihilation every time. The todos will be deleted ONLY when the Schedule handler is called, and since that handler is ONLY called when a current todo is not already present in the list, the calendar is safe.

I also altered the Schedule handler again by removing the TRIDate variable, since we are no longer using that inside of the handler.

The TRIDate todo is another story. As currently written, this todo is NOT included in the list of todos to be examined for updating, since it is not included in the list of these_Dates. Instead, at the end of each run, it is simply deleted and re-created without examination. I have never seen the creation of a due date using your syntax due date:(TRIDate + weeks) and so I am going to play with that a bit before introducing an examinatio of that todo to test for replacement.

This version should address all the issues you noted:

global the_titles, these_Dates --Now, these lists can be accessed at any time during execution of the script
on adding folder items to this_folder after receiving added_items
	set the_titles to {"Toolings Due", "Rough Ceramics", "Tooling Quote", "Casting Ceramics", "Approve Castings", "Ceramics to Tempe", "Tooling PO", "Tooling Start", "Paintmasters", "Vendor Quote", "Vendor Confirmed", "1st Shot", "Blister Layout", "1st Deco", "Packaging Mock-ups", "Packaging CD", "EP", "Vendor PO", "Release Printing", "Release Injection", "Release Decoration", "PP", "1st Shipment"}
repeat with anitem in added_items
	tell application "Microsoft Excel"
			open anitem
			print out active sheet
			set ProjectName to the value of cell "$F$4"
			set ReviseDate to the value of cell "$Z$4" as string
			set TRIDate to the value of cell "$S$12"
			tell (get value of range "D12:Z12") to set these_Dates to list 1
			close front window
	end tell
	tell application "iCal"
		if not (exists calendar ProjectName) then --make the calendar if necessary
			make new calendar at end of calendars with properties {title:ProjectName, color:{0, 20000, 50000}, description:ReviseDate}
		end if
		set Final_todo_List to {}
		repeat with atd in (get every todo of calendar ProjectName) --Get all the current todos of the calendar.  If the calendar was just created, it will return an empty list, and should still function.
			set end of Final_todo_List to {atd's due date, atd's summary} --Create a list of all found todos with their due date and summary, which should be unique to each todo.
		end repeat
	end tell
	
	repeat with a_Date from 1 to (these_Dates's length) --Now, we go through each date from the Excel spreadsheet
		if Final_todo_List does not contain {{(item a_Date of these_Dates), (item a_Date of the_titles)}} then --If the list of todos gathered from iCal does not already contain the possible todo, it needs to be made fresh:
			Schedule(ProjectName, ReviseDate, a_Date)
		end if
	end repeat
	tell application "iCal"
		tell calendar ProjectName
			delete (every todo whose summary contains "TRI files")
			make new todo at end of todos with properties {due date:(TRIDate + weeks), summary:"TRI Files", status:confirmed, description:(ProjectName & " - " & ReviseDate)}
		end tell
		quit
	end tell
end repeat
end adding folder items to

on Schedule(ProjectName, ReviseDate, i) --This should now create a single todo when called after first deleting the older one with the same summary.  
	set t_date to item i of these_Dates
	tell application "iCal"
		tell calendar ProjectName
			if (t_date is not "N/A" and t_date is not "" and t_date is not "NA" and t_date is not "on hold") then
				delete (every todo whose summary contains (item i of the_titles))
				make new todo at end of todos with properties {due date:t_date, summary:item i of the_titles, allday event:true, status:confirmed, description:(ProjectName & " - " & ReviseDate)}
			end if
		end tell
	end tell
end Schedule

man…you are much quicker than me at figuring out the problems…
that did address all of the issues i was having, but now i found a new one:

it seems that multyiple files does not work. It will open all the excel files, and print them all, but it will only create 1 calendar with its corresponding set of the todos…not all the calendars with each set of todos

Well, I have had some extra free time this weekend (rainy weather, sick kids, nothing on TV, insomnia), so I actually have enjoyed the diversion.

I have edited my last post so that the repeat is all inclusive of the Excel and initial iCal tell blocks, and should now work through all the documents.

Once again, good luck.

just wanted to let you know that im traveling right now for work…and not had much time to test it out.

i will look into it when i have more free time next week and let you. Thanks again for all the help.

sorry for the long time without responding…been crazed lately.

anyways…it works very well…but i found 2 problems:

1 - many times the dates are input to excel using 2 digits for years…which for some reason excel has issues with and calls this an error. Evidently…those dates do not get transfered into ical if it is an error in excel. So how can i have the script automatically correct all dates in the spreadsheet to change from “XX to 20XX”?

2 - is there a way to only add events that have not been completed? in other words…if its a new calendar…it all goes in. But if its updating a calendar…then it should only change dates for events that have not been completed. If the event is completed, then i dont need to update the date.