I closed my transcription business a month ago but still had some outstanding invoices to collect, and they all lived in Freshbooks. However, I canceled my Freshbooks subscription -- prepaid through mid-July 2023 -- and so needed to download all the info, at least about the outstanding invoices1.
I figured, though, that I may as well download the entire archive of clients and invoices -- 10+ years' worth! -- for future marketing purposes, and just to have a nice record of the business.
Luckily, I had published this Python library for interacting with the Freshbooks API, which got me most of the way towards downloading, serializing and storing all the client and invoice data.
> mkdir all_my_invoices && cd $_
> virtualenv env && source env/bin/activate
> pip install ipython simplejson avt-fresh
import avt_fresh
import json as j
import pathlib as p
cl = avt_fresh.ApiClient(client_secret="...", client_id="...", redirect_uri="...", account_id="...")
clients = cl.get_all_clients()
client_ids = [c.client_id for c in clients]
clients_json = []
for client in clients:
d = c._asdict()
del d['email_contact_id_lookup']
del d['contact_id_email_lookup']
clients_json.append(d)
p.Path('all_my_clients.json').write_text(j.dumps(clients_json, indent=2))
import avt_fresh
import simplejson as json
import pathlib as p
cl = avt_fresh.ApiClient(client_secret="...", client_id="...", redirect_uri="...", account_id="...")
def get_and_serialize_all_invoices_for_client(client_id):
invs = cl.get_all_invoices_for_client_id(client_id)
serialized = []
for i in invs:
d = i._asdict()
for key, val in d.items():
if isinstance(val, dt.date):
d[key] = val.toordinal()
# some data
del d['allowed_gateways']
del d['line_description_line_id_dict']
del d['line_id_line_dict']
new_lines = []
for l in d['lines']:
dl = l._asdict()
for key, val in dl.items():
if isinstance(val, dt.date):
dl[key] = val.toordinal()
new_lines.append(dl)
d['lines'] = new_lines
serialized.append(d)
return serialized
clients = json.loads(p.Path('all_my_clients.json').read_text())
invoices = {}
for client_id in client_ids:
invoices[client_id] = get_and_serialize_all_invoices_for_client(client_id)
p.Path('all_client_invoices.json').write_text(json.dumps(invoices, indent=2))
I'm not sure how likely I am to circle back and improve this library since I don't expect to use Freshbooks again in the future. However, there are a few low-hanging fruits which would make it a little nicer to work with, especially when it comes to serialization:
dataclasses
instead of NamedTuples
serialize
method which handles the date
and
Decimal
objects
I should mention that Freshbooks is the only SaaS I've run into that will immediately shut your account down when you cancel your account, even if you've already paid for a year's subscription! I had to beg them to give me a brief window of access in order to perform the above steps -- five days to be exact, even though I still had 2+ weeks left in the prepaid subscription.↩