How to manage invoices with the CLI and an editor

Here’s a common thing we often hear: if you’re doing a task more than once, automize it!

A few years ago as I did my first freelance gigs, I hacked a LaTeX template I found on Internet to be able to build my own invoices. I even wrote an article in French about that.

But then, I found myself repeating the edition of the different elements of the invoice and figured that I could actually automize it some more, so that I don’t need to edit the LaTeX code itself, just the relevant elements in the LaTeX code.

That’s how I ended up creating a tool to generate invoices based on a list. It’s called CLAIT, which is a lame acronym for Command Line Accounting and Invoicing Tool, and it’s not affiliated to the CLIT.

What the tool does is take some bits of configuration in YAML, runs it against a template in LaTeX, and generate a bunch of PDF, one for each invioce. And it also caculates your montly, quarterly or yearly earnings so you can copy paste the value when you got to fill the tax form in!

How to use the tool?

Well, you shall first install it:

pip install clait

And then, you need to create a directory where you want to do your accounting. That directory will serve as a sort of repository for your accounting. CLAIT expects two files to be in that directory.

Configuration of the invoices repository

The first file: invoices_config.yaml, is to bring the information that are global to all your invoices, such as the template you need, the path to the pdflatex executable tool — which can be absurd, especially for mac users — and the elements expected by the template that has been chosen — usually the name, contact info, firm registration and bank account — which are the elements that will be used by all the invoices.

All invoices_config.yaml will contain:

format: french
    pdflatex: /usr/local/texlive/2014/bin/universal-darwin/pdflatex

And within the source key, you’ll find elements that are usually put in the header and the footer of your invoice. Typically for the french template:

    name: Ford Prefect
        - Hyperspace bypass
        - Earth
    telephone: +44 777 7777 7777
    siren: 111 222 333
    ape: 9602A
            - 00001
            - 00002
            - 00000000001
            - 42
        iban: FR42 0000 1000 0200 0000 0000 142
        bics: FOOBARFUBAR

Managing invoices in the invoices repository

The other file is the invoices list, invoices_list.yaml. There you define all the elements that will identify your customer, and your invoice:

- !invoice
  iid: 201410-001
  date: 2014-10-02
  kind: paid
  subject: Voyage en dauphin
  desc: "Pr\xE9paration et embarquation sur un dauphin \xE0 travers les mers"
  customer: !customer
    address: [Alpha du centaure]
    name: Zaphod Beeblebrox
  place: Babylon

The iid is the unique id of the invoice, that will be used as the generated invoice file name, and shown as reference on the PDF itself. it’s a choice to keep it user settable, as everybody has a different scheme, and I prefered not to automize this to avoid enforcing a way over another.

The kind key, is to define the status of the invoice. Whether it has been issued as a quote, or is a paid invoice or not. If it’s a quote, the template will be setup to state the invioce as such, and if it’s been paid, it will have a mention. Otherwise, it will contain a banner telling how you want to be paid.

The question mark words !product, !customer… Are there to help the parser identify each element and give better feedback in case of mistakes.

The products key is aimed to contain a list of products, either !product or !offer, an offer being a product of negative value (when doing a discount for example). So each product will generate a line in the invoice, and to make a multiline description you can give it a list of lines in the yaml.

  - !product
    descr: Soutien psychologique du dauphin
    price: 430
    qty: 1
  - !offer
    descr: Discount because I'm nice
    price: 20
    qty: 1

Once you’ve configured both files, you can run

clait generate

if you’re within the directory, or

clait -d /path/to/directory generate

if you’re not. If you don’t like the idea of an invoice directory, or you don’t like the default names of the files, you can also setup path for each file independently:

clait -l /path/to/invoices_list.yaml -c /path/to/invoices_config.yaml -d /path/where/to/output generate

Then you’ll find all your invoices with the iid as name, and .pdf as extension. if you want to regenerate an invoice you modified, you just delete the pdf and rerun the command.

How does the template work?

A template is defined by defining only 6 elements, the header, the footer, the product, the offer, the customer, and the invoice — which is the global template containing the others. If you want to define your own template, use an existing one as base work to adapt it to your own language and crounty specific needs.

The whole idea of the tool is to generate an invoice as a latex letter with a little logic within that will make it nicer.

So in the french template, you’ll find the functions to add products defined in the HEADER part, and the “rendering” defined in the FOOTER part. The important tip I can give, is to keep using all expected keys for each part the same way.

So, that means:

  • HEADER: expects NO paramaters,
  • INVOICE: HEADER, iid, kind, place, subject, desc, customer, products, FOOTER ;
  • PRODUCT: descr, qty, price ;
  • CUSTOMER: name, address ;
  • FOOTER: telephone, website, email, … (everything that you defined as source in the configuration file above)

Beware that a side effect of using raw python format() as a templating scheme is that whenever you need to write latex curly braces, you have to double them, such as \begin{center} will become \begin{{center}}, as all elements like {iid} will be interpreted as an expected value to receive. As the HEADER part is not parameterized, this is the only one that can be written as raw LaTeX!

Then once you wrote your template elements, you build a dict with the six elements as keys, call register_template() on it with the name of your template:

from ..formatter import register_template

register_template('my_custom_template', dict(

And finally that file shall be placed in the src/clait/format/templates directory to be automagically loaded by CLAIT. Then using format: my_custom_template in the config of your invoices repository will have you load the template you created for each invoice!

I guess we might consider at some point using one of the powerful templating engines that exists, instead of using a raw and rough way of implementing it.

Extra features

Then, having all your invoices nicely handled by the tool is a nice thing, but then every quarter or every year you need to know your income for taxes declaration. Here you can get just that using:

% clait results quarterly
Quartely results:
 2014-Q4: 631
 2015-Q1: 70.75


% clait results yearly
Yearly results:
 2014 631
 2015 70.75

And there you go! You just got to copy paste that 😉

Frontend work

Finally, I have prepared the tool to expose an UI. Just run it as clait api and your repository will be accessible through a RESTful API exposed using flask, and will offer a Redux+React UI that’s still under heavy development. The point, here, is to use a web frontend to mutate the invoices list, and eventually store it back into the YAML file.

The restful API is defined in a separate module, and the API exposed is kept as simple as possible. Here are the resources:

  • /results: gives an object with yearly, quarterly and monthly as keys and the proper matching values.
  • /invoices: with a GET, it gives the paginated list of all invoices, with a POST it creates a new invoice (DELETE is not yet implemented)
    • /invoices/<iid>: gives the invoice of invoice id: <iid>. Either it’s giving it as JSON, or the action get parameter is set to download, it will generate the PDF and offer it for download.
  • /customers: Here is a nice trick, you can get the list of the customers extracted from the existing invoices. Which is useful for doing an invoice for a customer that already exists.

No access control is setup, as the webapp is meant to be ran only locally. Maybe support for multiple users and multiple repositories might be added in a distant future?

Then any request to / is meant to offer the Redux+React webapp. But that part is yet to be finished! I’ll update the article when it will be over 😉

Look of the invoice

Finally, here’s how the invoice looks like:

The tool is located at: