Introduction to Billable
I decided recently to stop using Excel X to generate invoices for the occasional consulting jobs I do and looked around for an application to replace it. I am (as you might imagine) an AppleScript nut, so when I look for an application to accomplish something I want to do, I look for one that I can script so I can extend its capabilities and personalize it for my intended use if it doesn’t meet all my needs. I found Mike Zomek’s Billable (by Clickable Bliss) which advertises itself as:
Billable is an application for Mac OS X that helps you keep track of the billable services you perform for a client and then lets you create and manage invoices based on those services.In it’s latest version (version 1.2b2 was tested, but 1.2 is now released) Billable is scriptable. Billable has a very nicely done and rather straight-forward window for defining Clients, assigning services to them, and then automatically preparing an invoice which can contain logos, and is very presentable looking (See the Billable Screenshots for samples, and note that there are excellent Screencasts as well). You define yourself and/or your company in Billable’s preferences using your Address Book entry if you prefer, and there is even space for a logo to be displayed at the top of your Invoices. Nicely done. You then go on to define your clients and their “coordinates” either by importing them from your Address Book, or using a handy Client Editor provided. In the side bar of the Billable Window, each of your clients will appear as a smart folder which can appear as their labeled logo if you like, inside of which are two more folders for each client; one for Invoices and the other for Services. Not shown in the screenshots (that I found) is a view of a Service entry, so I’ve shown one in Figure 1 below:
Figure 1: A Billable Service Window
Notice that at the bottom of the Services window there is a Notes pane. More about that later. It is an important scripting aid because its contents can be read into a script variable, so I will be placing currency values that need exchange rate calculations in Notes with a flag so I can find them, and then running a script to find them all and doing the conversions for entry into the actual cost in foreign currency.
Getting Help
Like any good Apple app., not much direction beyond the screencast is needed, and the Help files are very thorough as well. All the instructions you will ever need are there and the search terms for finding them are fairly obvious. (I hate apps with arcane ways of naming things in help.) There is a Forum as well, and Mike Zomek is quite responsive to email queries for help. If you’re not happy with the default layout of an Invoice, for instance (though I thought the default to be quite adequate and used it unaltered), you can create a new template for that client’s invoices by editing a copy of the default template found inside the application itself ~/Applications/Billable.app/Contents/Resources/invoice_template.html (assuming that you put Billable in your Applications folder). Don’t edit the default – if you screw it up, no invoices. Templates use a fairly comprehensive set of tags enclosed in double braces like this {{tag}}. Using these is well-explained in the Help file; search on “Customize Invoice” and “Template” for those pages. Templates are not scriptable, however.
Scripting Billable
Why do I need Billable to be scriptable? Because Billable by itself, although quite capable of handling foreign currencies as shown in one of the screenshots, is not set up to deal with more than one at a time. In these days of connectivity I can work from home in Canada for clients that do not live here, but must then manage two things: I must invoice an foreign client in the Client’s native currency, and I must also keep track of my taxable income from those clients in Canadian dollars ($Cdn).
Billable has a fairly comprehensive Dictionary, and for the most part it behaves as you would expect it to. Scripting Billable is not rocket science and doesn’t require any hacks, GUI scripting, or strange constructions (aside from the occasional requirement to enforce order with “get” inside parentheses before going after properties). I can accomplish most of what you might want to do with it straight up. I say “most” because I didn’t see a way to select a particular set of services and print an invoice for them, so I did that by hand in Billable, which provides a handy button in the window and gives you a view pane for seeing the invoice before you print or send it.
To accomplish my goals, I made extensive use of the notes section of the Service windows. I created a Client in the Client Editor that I called “AppleScriptClient” to use for this tutorial and then made up a bunch of services. The two Client Editor window panes are shown in Figures 2 and 3 below:
Figure 2: Profile Pane of a Service Editor Page for Setting Up or Changing a Client
Figure 3: Second Pane of Client Editor Page for Setting Up or Changing a Client (note the icon)
For expenses, generally, rather than creating a new service for each, I used notes with a column of figures for individual items to be totaled for the invoice. For Canadian expenses, I headed the notes with “$Cdn” and then the figures as shown in Figure 4 below. Note the button “Quantity” is checked for expenses. I didn’t use the Quantity text box except for recurrent expenses that spanned several months (Document Storage, for example). Note that Figure 4 shows a total in the upper pane services list that is not shown below. That is an artifact: I shot the screen after I had run the script, and only modified the entry boxes below and then restored them. Figure 5 shows a typical fee-based service, i.e. consulting time.
Figure 4: A Typical Service by Quantity Entry Using Notes for Items
Figure 5: A Typical Fee-Based Service
A Script to Do Currency Conversions from Service Notes
I have intentionally left the parts of this script using redundant code rather than using a handler to deal with repeated features so each subsection is stand-alone.
tell application "Billable"
-- Get the Client (you can use the full name or an abbreviation)
set C to first item of (get companies whose abbreviation is "scpt")
(* get needed exchange rate for the day I invoice. Note that I use XE.com's Currency Update Service, which emails me the daily rates for a huge list every day, so I just find the last received and parse it for the currency I want after having set it up to use Canadian dollars as its base. There are lots of other ways to get the rate, so this is just an example*)
set MidMktExch to my getMktRate() -- CDN to US handler from Eudora mails
set Agio to 0.02 -- Canadian bank charge for buying and selling.
set Exch to MidMktExch - Agio
-- Get the Services that are not hourly, i.e., Quantity type.
repeat with S in (services of C whose rateType is "Quantity")
-- Find those services that need conversion to US dollars
tell S
if notes contains "$Cdn" then -- always the key in the first paragraph
-- Telephone is a column of numbers one to a paragraph
-- starting with the second.
if summary contains "Telephone" then
set Nts to get notes
set p to paragraphs 2 thru -1 of Nts
set Total to 0 -- causes text in note to coerce to numbers.
-- add them up. I have not made this a handler to make clearer what's going on.
repeat with N in p
set Total to Total + N
end repeat
-- convert them and update the cost in US dollars
set totalFlatFeeCost to Exch * Total
(* Update notes. Because notes are appended to the charges in an invoice, I want to make it clear to the client how they were converted. See Figure 6 below*)
set notes to Nts & return & "$" & Total & " in $Cdn converted to $" & totalFlatFeeCost & " in $US as of " & (createdAt as string) & " @ $" & Exch
else if summary contains "Storage" then
-- Convert monthly charge to US dollars
set Nts to notes
set Stor to paragraph 2 of Nts
set totalFlatFeeCost to Exch * Stor
set notes to Nts & return & "$" & Stor & " in $Cdn converted to $" & totalFlatFeeCost & " in $US as of " & (createdAt as string) & " @ $" & Exch
else if summary contains "Travel" then -- Cdn Travel
set Tnotes to notes
set tP to paragraphs 2 thru -1 of Tnotes
set Ttot to 0
-- again, add them up
repeat with p in tP
set Ttot to Ttot + (first word of p)
end repeat
set totalFlatFeeCost to Ttot * Exch
set notes to Tnotes & return & "$" & Ttot & " in $Cdn converted to $" & totalFlatFeeCost & " in $US as of " & (createdAt as string) & " @ $" & Exch
end if
end if
-- Now do expenses that were incurred in the US.
-- Get US$ meals
if summary contains "Meals" then
set M to 0
set Nts to get notes
set p to paragraphs 2 thru -1 of Nts
-- Add up the meals
repeat with aMeal in p
set M to M + aMeal
end repeat
set totalFlatFeeCost to M
set notes to Nts & return & "$" & M & " in $Cdn converted to $" & totalFlatFeeCost & " in $US as of " & (createdAt as string) & " @ $" & Exch
-- Get US Travel Expenses
else if summary contains "US Travel" then
-- Add up the costs in notes
set Unotes to (get notes)
set uPn to paragraphs 2 thru -1 of Unotes
set Utot to 0
repeat with p in uPn
set Utot to Utot + (first word of p)
end repeat
set totalFlatFeeCost to Utot
set notes to Unotes & return & "$" & Utot & " in $Cdn converted to $" & totalFlatFeeCost & " in $US as of " & (createdAt as string) & " @ $" & Exch
end if
end tell
end repeat
end tell
to getMktRate()
set MB_name to "Exch"
tell application "Eudora" to set LM to last message of mailbox "Exch"
set tid to AppleScript's text item delimiters
set AppleScript's text item delimiters to "USD United States Dollars"
set MMExch to (word 2 of paragraph 1 of text item 2 of LM) as number
set AppleScript's text item delimiters to tid
return MMExch
end getMktRate
After this script has been run on the Services for this client, things are changed in the items as shown in Figure 6 below.
Figure 6: The Service of Figure 4 After the Script Has Run
Finally, I wanted to tally up the Fee-based charges in Canadian dollars for my own tax records. The following script does that, except that it just presents a dialog at the end instead of entering it in a spreadsheet for me.
tell application "Billable"
-- Get the Client
set C to first item of (get companies whose abbreviation is "scpt")
-- get needed exchange rate for converting back.
set MidMktExch to my getMktRate() -- CDN to US handler normally
set Agio to 0.02 -- Canadian bank charge for buying and selling.
set Exch to MidMktExch - Agio
-- get the services for invoice of C
set Paid to {}
set Income to 0
set Expense to 0
set I to invoices whose client is C -- easier to do all rather than identify one.
repeat with inv in I
-- go through paid up invoices for this client
if isPaid of inv then set Paid to Paid & services of contents of inv
end repeat
repeat with S in Paid
if rateType of S is "Quantity" then
set Expense to Expense + (totalCost of S)
else
set Income to Income + (totalCost of S)
end if
end repeat
set ClientBilling to Income + Expense
set CdnIncome to Income / Exch
set N to name of C
display dialog "As of " & short date string of (current date) & return & return & "Total Paid is US$" & ClientBilling & return & return & "Canadian Taxible Income is $" & Income with title N
end tell
-- same as before. You'll have to supply your own method here.
to getMktRate()
set MB_name to "Exch"
tell application "Eudora" to set LM to last message of mailbox "Exch"
set tid to AppleScript's text item delimiters
set AppleScript's text item delimiters to "USD United States Dollars"
set MMExch to (word 2 of paragraph 1 of text item 2 of LM) as number
set AppleScript's text item delimiters to tid
return MMExch
end getMktRate
Clearly these are just examples to illustrate how the process might be done, not universal scripts.
Conclusion
Overall, I’ve been very pleased with Billable and use it for clients not shown in the ScreenShots. I recommend it to anyone who wants a simple invoicing system that can be customized using its native tags in a template for the invoice, and using AppleScripts to do any calculations you require within a Service entry. The Invoices you produce are PDFs and can be, if you choose, attached to an email for transmission to your client.
You can see the Invoice.pdf that I produced after running the first script above by clicking the thumbnail image below.
Figure 7: The Billable Invoice (PDF) After Running the First Script
Happy Scripting and Billing!