Using the Markdown template for generating pdf invoices

I was pleasantly surprised to discover the generate pdf using Markdown template function. I could achieve my first version of the invoice quickly and with a clean Markdown template. However, I noticed that currencies and time formats were not taken from the UI; currency fields seem to be rendered as numbers and dates seem to be rendered using a default locale.
I learned I can work around this using Javascript, but the code gets out of hand quickly and looses the clarity of the plain Markdown template I had in my first iteration.

I will share my template below. This are the issues I have:

  • Dates not formatted in my nl-nl locale
  • Money fields in the invoice line table formatted as plain numbers
  • I need to cache the field values before I can use them in Javascript
  • The table shorthand {{Invoice Lines: ... will require a Javascript replacement, because money fields are not using currency formatting
  • the template lacks clarity and this makes it prone to errors, which I do not want in my invoices

Alternative I consider is to use a local Pyhton script that retrieves invoice data using graphql api, generates a pdf and attaches it to the invoice in Fibery.

Any thoughts on how I can address the above issues in my current template?

This is my current template:

<%
// nl-NL and de-DE locales do not work, so go with en-US and replace
const cur = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'EUR',
  minimumFractionDigits: 2, // (0 will print 2500.10 as $2,500.1)
  maximumFractionDigits: 2, // (0 causes 2500.99 to be printed as $2,501)
});

function fmtcur(fieldName){
  return cur.format(Entity[fieldName]).replace(',', ' ').replace('.', ',');
}
%>

<!-- START OF TEMPLATE -->

![Logo Serra ICT Diensten](https://www.serraict.com/assets/img/logo.png)

### Van:
Serra ICT Diensten <br/>
Hugo de Grootstraat 58 <br/>
2613TW Delft <br/>
info@serraict.com

### Aan:
{{Customer Name}}<br/>
{{Customer Address}}<br/>
{{Customer Zipcode}} {{Customer City}}<br/>
{{Customer Email}}

### Betreft:
Factuurnummer: {{Invoice Number}}<br/>
Uw referentie: {{Customer Reference}}<br/>
Factuurdatum: {{Invoice Date}}<br/>
Vervaldatum: {{Due Date}}<br/>

# Factuur {{Name}}

### Diensten:

{{Invoice Lines:Name, Quantity, Unit Price, Total Price}}

<!--
Retrieve these values so that we can use them in Javascript
{{VAT}} {{Total Amount}} {{Total Including VAT}}
-->

Subotaal: <%= fmtcur("Total Amount") %> <br/>
BTW ({{VAT Percentage}}): <%= fmtcur("VAT") %> <br/>

__Totaal: <%= fmtcur("Total Including VAT") %> <br/>__
<br/>
<br/>


---

www.serraict.com -  \o/ more company info here \o/
3 Likes

@marijn I’m not sure if you saw the recent Oct 5 release announcement which allows using HTML & CSS to format the PDF output:

I don’t think it specifically addresses most of the concerns you listed and you still need to use javascript blocks for the type formatting issues you noted. HTML is also worse from a readability perspective. However, I feel it does give you alot more control on the overall layout and styling of your output.

There are still a few areas for improvement IMHO, but this is still quite a great leap forward for this type of use case.

Hope this is somewhat helpful :slight_smile:

2 Likes

Thank you for your input @cannibalflea . Although I have some htm and css skill, I’m a bit rusty and was hoping not needing to brush them up for the time being. I will keep it in mind as an option though.

And I do not think I can fix any of the date and money formatting issues in css, but I might be mistaken. It would be possible to generate better-looking invoices, but aesthetically they’re good enough already.

Hi @marijn

scripting engine uses some subset of node version 12, which has no nl-NL or de-DE support for number formatting.

In that template you can not only define your own functions but also use fibery context object. So you can query Fibery using standard API or even graphQL

<%
    const fibery = context.getService('fibery');

    const query = `{
      findInvoices(id: {is: "${Entity.id}"}) {
        name,
        date,
        amount
      }
    }`;

    const resp = await fibery.graphql('CRM', query);

    const invoice = resp.data.findInvoices[0];

    const formatNumber = (number) => {
      return new Intl.NumberFormat('en-EN', {
        style: 'currency',
        currency: 'EUR', 
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
      }).format(number);
    };
    %>

<%= JSON.stringify(invoice, null, 2) %>

## <%= formatNumber(invoice.amount) %>
1 Like

Thank you for your input @Viktar_Zhuk, appreciated.
I do not think I would have found out the en-EN locale “trick” by myself.

This definitely works, although I do feel I am better of scripting and templating this outside Fibery if this is the type of code required.

1 Like