Expense reports and saving to iCloud

In last night’s post, I pointed out a deficiency in the script:

I wanted the script to save the document, but that caused nothing but grief. First, I wanted to be able to save it to iCloud, but no matter how I tried to get it to save into a subfolder of ~/Library/Mobile Documents, I got an error message, usually about permissions. Saving to my Desktop folder sometimes worked, but sometimes also led to permissions errors. My sense is that this is a sandboxing thing, and that I’ll never figure it out. So I gave up. Saving the document manually isn’t that hard.

This morning, I woke up to a solution from reader Andrew Kemp:

@drdrang Got Numbers to save in iCloud with folder (system attribute “HOME”) & “/Library/Mobile Documents/com~Apple~Numbers/Documents/“
  — Andrew Kemp (@ajwk100) Fri Nov 25 2016 11:19 AM

The system attribute command is simply a way of getting environment variables, so

system attribute "HOME"

returns the Unix-style path to the user’s home directory. What Andrew is telling me here is to build a path to the iCloud folder on my Mac use the alternate syntax for saving a Numbers document in AppleScript. In other words, don’t specify the path to the file using AppleScript’s usual colon-delimited system, use the good ol’ Unix slash-delimited system.

I was skeptical, because I knew I’d tried Unix paths before and they failed. But I must have done something wrong in those previous attempts. Maybe I used a tilde, thinking it would expand to the home directory; maybe I tried to escape a space in one of the folder names and messed up. Whatever the problem was, it’s now gone. I’ve been able to run the updated script repeatedly from both of my Macs and it’s always saved the expense report to iCloud, just as I wanted.

Big thanks to Andrew for getting me straightened out.

Here’s the updated script in full:

 1:  set today to (do shell script "date \"+%b %-e, %Y\"")
 3:  -- get the project number from the user
 4:  display dialog "Project number:" default answer "GB"
 5:  set project to text returned of result
 7:  -- get the receipt image files
 8:  set dfolder to ((path to home folder as text) & "Dropbox:") as alias
 9:  set receipts to (choose file with prompt "Select the receipt files" default location dfolder with multiple selections allowed)
11:  -- open the report template and set the date
12:  tell application "Numbers"
13:    activate
14:    set doc to (make new document with properties {document template:template "Expenses"})
15:    delay 1 -- might need to wait for Numbers to launch
16:    tell doc
17:      tell sheet 1
18:        tell table 3 to set value of cell 1 of column 2 to today
19:      end tell
20:    end tell
21:  end tell
23:  -- set up variables for placing images and entering values
24:  set x to 750
25:  set y to 50
26:  set i to 2
28:  -- cycle through all the receipt files
29:  repeat with imageFile in receipts
30:    -- get the file name w/o extension
31:    tell application "Finder"
32:      set filename to name of imageFile
33:      set fileExt to name extension of imageFile
34:      set filename to text 1 thru -((length of fileExt) + 2) of filename
35:    end tell
37:    -- extract the date, description, and amount from the file name
38:    set oldDelimiters to AppleScript's text item delimiters
39:    set AppleScript's text item delimiters to "+"
40:    set {rdate, desc, amt} to text items of filename
41:    set AppleScript's text item delimiters to oldDelimiters
43:    -- back to the spreadsheet
44:    tell application "Numbers"
45:      tell doc
46:        tell sheet 1
47:          -- add the image to the spreadsheet
48:          set thisImage to make new image with properties {file:imageFile}
49:          tell thisImage
50:            set position to {x, y}
51:            set height to 400 -- retains aspect ratio
52:          end tell
53:          -- enter the values
54:          tell table 2
55:            set value of cell i of column 1 to rdate
56:            set value of cell i of column 2 to project
57:            set value of cell i of column 3 to desc
58:            set value of cell i of column 4 to amt
59:          end tell
60:          -- update for the next receipt
61:          set x to x + 20
62:          set y to y + 20
63:          set i to i + 1
64:        end tell -- sheet 1
65:      end tell -- doc
66:    end tell -- Numbers
68:  end repeat
70:  -- save the report in iCloud
71:  set saveName to (do shell script "date \"+%Y%m%d-\"") & project & ".numbers"
72:  set savePath to (system attribute "HOME") & "/Library/Mobile Documents/com~apple~Numbers/Documents/"
73:  tell application "Numbers" to save doc in (savePath & saveName)

The new stuff is all at the bottom, Lines 70–73. You may be slightly confused by the path to iCloud. First, if you look in Finder, you’ll see that the “Mobile Documents” folder is weird—it doesn’t have a reveal triangle next to it.

Mobile Documents in Finder

If you double-click it, you’ll be taken to iCloud Drive, which has folders associated with various apps.

iCloud Drive folder on Mac

This view, unfortunately, doesn’t give you any sense of where these folders are on your computer. To get that, you have to use the Terminal:

$ cd ~/Library/Mobile\ Documents/
$ ls
<bunch of stuff>
$ cd com~apple~Numbers
$ ls
$ cd Documents
<list of Numbers docs in iCloud Drive>

So in Unix terms, the path to your iCloud Drive numbers folder is

~/Library/Mobile Documents/com~apple~Numbers/Documents

The Finder hides the funny-looking stuff from you and makes it appear as if you’re looking directly at some off-site disk.

So now, after running the AppleScript (and giving it a project number of 11111), the results look like this:

Expense report after automatic saving

As you can see in the title bar, the document has been named according to the date and the project number, and it’s in iCloud, easily accessible from my Macs, my iPhone, and my iPad.

One of the many things I have to be thankful for is a cadre of readers like Andrew who fix my mistakes and point me in the right direction.