International Invoices (if you live in the right parts of the world)
Our newest feature, international invoices turned out to be quite tricky: which languages to offer for which countries? Then, there are different regulations for what has to appear on invoices – and, this is based not only on the country of the hotel, but also of the customer. Did you know that many Polish companies will only reimburse your travel expenses when you print that company’s tax id? Neither did we.
But in the end, we managed, and here you go: with apaleo you can now generate legally okay invoices for Finland (in Finnish, English and Swedish) and Germany (in German and English). And we have a recipe for how to roll that out for the rest of the world.
Today we want to share our story: a journey from despair and overwhelming complexity to a neat little feature. Enjoy.
Our favourite source of reliable or random information, the interwebs, is pretty quiet when it comes to invoicing requirements for all the countries. The second best source, fun text books and laws always seem to written in the language of the country they are relevant for. Unfortunately, our Finnish or Japanese aren’t great, and we resorted to unorthodox methods: travelling the world, collecting invoices from all over the place, asking hotel owners we know for examples, calling friends (“Hey, we haven’t talked in months! How are you and can you send me a sample invoice?”)
That was quite fun, and it worked, but we figured doing that for all of the world in advance would delay that feature by a few decades.
Divide and conquer
The solution to that was to focus on what we needed now: not international invoices for everything and everywhere, but only for the countries we already have customers in. Plus a methodology for how to extend that to other countries with little and predictable efforts. The feature’s description changed to “With zero configuration efforts for the hotel, support invoices that will make business travellers from most countries happy, in the country’s official languages plus English, for one specific country where we know at least one experienced hotelier”, and the hardcore problem from the beginning could be split up into three okay-ish easy research-tasks:
- What data do companies require on invoices, in order to accept them for travel expenses?
- What are the official or important languages of country X?
- How does a legally okay invoice look like for country X?
The first one is independent on the country the hotel is located in and a one-time effort, the second one is really simple, and the last one is just asking the previously mentioned experienced hotelier to tell us everything he knows and send us examples.
The magic pipeline
The last piece in the puzzle was finding an implementation paradigm to make supporting new countries a less-than-one-hour task. Which wasn’t exactly a no-brainer, as there are so many aspects to that:
- using the right date, time and money formatting (country specific)
- translating user data (language specific)
- translating static texts (language specific)
- displaying the legally required information (country specific)
The first and second point can be super nicely handled in dotnet core, which makes data preprocessing the first step in our pipeline. All steps after this one are completely oblivious to formatting or translating, and just render it as they get it. Extending that part to support more languages / locals is exactly no work at all – it just magically works.
Next, we process partials. Those are parts which are common for multiple countries, like the header (date, recipient) and footer (hotel address, bank details, …), and can be shared. This requires a little additional work when a new language comes in, as we translated the static texts from point three directly in the partials. We expect to create 0 to 2 new partials, when adding a new country. Getting closer to 0, the more countries we have.
Last, the main template and the partials are assembled. Each country has one template in each supported language, making this the only point that requires real work.
And very last, we need to add a new value to the enum of supported countries.
We timed it, and it’s totally doable in less than an hour. Which is not bad, for rolling out to a whole new country.
How to use it?
Now you’re probably wondering how you can use it on the API, right? On the POST invoice endpoint in the Finance module, specify the language you want. And we take care of the rest.
We hope you like it!
❤ Your apaleo team