From 814f4e6a3e28c06bd60e53171748721ae365c2da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Romain=20Gon=C3=A7alves?= Date: Sun, 29 Sep 2024 15:27:01 +0200 Subject: init: invoice-gen and examples --- .gitignore | 2 + examples/invoice-2024-001.yml | 55 +++++++++++++++ examples/quote-2024-001.yml | 55 +++++++++++++++ invoice-gen | 14 ++++ templates/company.gohtml | 10 +++ templates/invoice.gohtml | 118 +++++++++++++++++++++++++++++++ templates/styles.css | 159 ++++++++++++++++++++++++++++++++++++++++++ templates/template.gohtml | 55 +++++++++++++++ templates/terms.gohtml | 7 ++ templates/translations.yml | 79 +++++++++++++++++++++ 10 files changed, 554 insertions(+) create mode 100644 .gitignore create mode 100644 examples/invoice-2024-001.yml create mode 100644 examples/quote-2024-001.yml create mode 100755 invoice-gen create mode 100644 templates/company.gohtml create mode 100644 templates/invoice.gohtml create mode 100644 templates/styles.css create mode 100644 templates/template.gohtml create mode 100644 templates/terms.gohtml create mode 100644 templates/translations.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f47bc6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +examples/*.html +examples/*.pdf diff --git a/examples/invoice-2024-001.yml b/examples/invoice-2024-001.yml new file mode 100644 index 0000000..d032cc8 --- /dev/null +++ b/examples/invoice-2024-001.yml @@ -0,0 +1,55 @@ +--- + +number: 2024-001 +date: 2024-07-09 +due_date: 2024-08-01 +type: invoice + +notes: + en: Thank you for your business! + fr: Merci pour votre confiance ! + +author: + name: NAME + address: ADDRESS + email: EMAIL + website: WEBSITE + phone: "+123456789" + +bank: + name: BANK + iban: FFFFFFF + swift: PPXXXX + +tax: + vat: + en: No applicable VAT number. + fr: Pas de numéro de TVA applicable. + siret: abcde + +client: + name: NAME + address: ADDRESS + email: EMAIL + +items: + - name: + en: Programming + fr: Programmation + comment: + en: Lorem ipsum + fr: Ipsum lorem + rate: 1 + qty: 1 + sum: 1 + + - name: + en: System administration + fr: Administration de systèmes informatiques + comment: null + rate: 2.5 + qty: 10 + sum: 25 + +total: 26 +currency: EUR diff --git a/examples/quote-2024-001.yml b/examples/quote-2024-001.yml new file mode 100644 index 0000000..48ba442 --- /dev/null +++ b/examples/quote-2024-001.yml @@ -0,0 +1,55 @@ +--- + +number: 2024-001 +date: 2024-07-09 +due_date: 2024-08-01 +type: quote + +notes: + en: Thank you for your business! + fr: Merci pour votre confiance ! + +author: + name: NAME + address: ADDRESS + email: EMAIL + website: WEBSITE + phone: "+123456789" + +bank: + name: BANK + iban: FFFFFFF + swift: PPXXXX + +tax: + vat: + en: No applicable VAT number. + fr: Pas de numéro de TVA applicable. + siret: abcde + +client: + name: NAME + address: ADDRESS + email: EMAIL + +items: + - name: + en: Programming + fr: Programmation + comment: + en: Lorem ipsum + fr: Ipsum lorem + rate: 1 + qty: 1 + sum: 1 + + - name: + en: System administration + fr: Administration de systèmes informatiques + comment: null + rate: 2.5 + qty: 10 + sum: 25 + +total: 26 +currency: EUR diff --git a/invoice-gen b/invoice-gen new file mode 100755 index 0000000..b82050c --- /dev/null +++ b/invoice-gen @@ -0,0 +1,14 @@ +#!/bin/sh + +set -xe + +test -f "${1}" +filename="$(echo "${1}" | rev | cut -d "." -f 2- | rev)" +template="templates/template.gohtml" + +gomplate \ + -c data="${1}" \ + -c translations=templates/translations.yml \ + -f "${template}" \ + | tee "${filename}.html" \ + | weasyprint - "${filename}.pdf" diff --git a/templates/company.gohtml b/templates/company.gohtml new file mode 100644 index 0000000..f3a9cf6 --- /dev/null +++ b/templates/company.gohtml @@ -0,0 +1,10 @@ + + +
+
diff --git a/templates/invoice.gohtml b/templates/invoice.gohtml new file mode 100644 index 0000000..fe7fece --- /dev/null +++ b/templates/invoice.gohtml @@ -0,0 +1,118 @@ +
+
+

{{ index .translations.invoice_from .ctx.lang }}

+ {{ tpl (file.Read "templates/company.gohtml") + (dict + "ctx" .ctx + "data" .data + "translations" .translations) }} +
+ + +
+ +
+
+

{{ index .translations.invoice_to .ctx.lang }}

+
    +
  • {{ .data.client.name }}
  • +
  • {{ .data.client.address }}
  • +
  • {{ .data.client.email }}
  • +
+
+
+ +
+
+ + + + + + + + + + + {{ $ctx := .ctx }} + {{ range .data.items }} + + + + + + + {{ end }} + + + + + + + +
{{ index .translations.item .ctx.lang }}{{ index .translations.rate .ctx.lang }}{{ index .translations.quantity .ctx.lang }}{{ index .translations.amount .ctx.lang }}
+ {{ index .name $ctx.lang }} + {{ if (has .comment $ctx.lang) }} +

{{ index .comment $ctx.lang }}

+ {{ end }} +
{{ .rate }}{{ .qty }}{{ .sum }}
{{ index .translations.total_in .ctx.lang }} {{ .data.currency }}{{ .data.total }}
+
+
+ +
+ {{ if .data.notes }} +
+

{{ index .data.notes .ctx.lang }}

+
+ {{ end }} +
+ + diff --git a/templates/styles.css b/templates/styles.css new file mode 100644 index 0000000..cb0b736 --- /dev/null +++ b/templates/styles.css @@ -0,0 +1,159 @@ +@page { + size: A4 portrait; + margin: 16mm; + + @bottom-right-corner { + content: counter(page) '/' counter(pages); + margin-left: 1em; + } +} + +@media print { + footer { + position: absolute; + bottom: 0; + } +} + +@media screen { + html { + margin: 4em auto 4em auto; + width: 60em; + } + + body > section:not(:first-child) { + margin-top: 12em; + } +} + +/* */ + +* { + margin: 0; + padding: 0; + font-family: monospace, monospace; + font-size: 14px; + color: #111; +} + +h1, h2, h3 { + margin: 0; + color: #444; +} + +h2 { + font-size: 1.2em; +} + +ul li { + list-style: none; +} + +a, a:visited { + color: #000; +} + +article { + margin-top: 2em; + margin-bottom: 2em; +} + +header article { + margin: 0; +} + +header { + display: flex; +} + +footer { + width: 100%; +} + +body > section { + break-before: always; +} + +/* table */ + +table * { + vertical-align: top; +} + +table { + border-collapse: collapse; +} + +table { + width: 100% +} + +/* items */ + +article.items table { + width: 100%; + margin: 4em 0 4em 0; +} + +article.items table tr th:last-child, +article.items table tr td:last-child { + text-align: right; +} + +article.items table thead tr th:first-child { + width: 60%; +} + +article.items table tfoot, table thead { + border-bottom: solid 1px black; +} + +article.items table tfoot { + border-top: solid 1px black; +} + +article.items table tfoot td { + font-weight: 700; +} + +/* metadata */ + +article.metadata { + width: 40%; +} + +article.metadata table { + width: 100%; +} + +article.metadata table tr td:first-child { + width: 50%; +} + +/* */ + +article.tax table tr td:first-child, +article.bank table tr td:first-child { + width: 20%; +} + + +article.company { + width: 60%; +} + +article.bank { + padding-top: 1em; + border-top: solid 1px #444; +} + +article.annex p { + background-color: #000; + color: #fff; + font-weight: 700; +} + +p.comment { + color: #444; + margin-left: .5em; +} diff --git a/templates/template.gohtml b/templates/template.gohtml new file mode 100644 index 0000000..911bfdd --- /dev/null +++ b/templates/template.gohtml @@ -0,0 +1,55 @@ + + + + + + + + +
+ {{ tpl (file.Read "templates/invoice.gohtml") + (dict + "ctx" (dict "lang" "fr") + "data" .data + "translations" .translations) }} +
+ +
+
+

annexe 01: facture en anglais / invoice

+
+ {{ tpl (file.Read "templates/invoice.gohtml") + (dict + "ctx" (dict "lang" "en") + "data" .data + "translations" .translations) }} +
+ + + + + diff --git a/templates/terms.gohtml b/templates/terms.gohtml new file mode 100644 index 0000000..34ac778 --- /dev/null +++ b/templates/terms.gohtml @@ -0,0 +1,7 @@ +
+ {{ tpl (file.Read "templates/company.gohtml") + (dict + "ctx" .ctx + "data" .data + "translations" .translations) }} +
diff --git a/templates/translations.yml b/templates/translations.yml new file mode 100644 index 0000000..7a9a1f2 --- /dev/null +++ b/templates/translations.yml @@ -0,0 +1,79 @@ +--- + +# invoice + +invoice: + en: Invoice + fr: Facture + +invoice_issued_at: + en: issued at + fr: émise le + +invoice_due_at: + en: due at + fr: échéance le + +# quote + +quote: + en: Quote + fr: Devis + +quote_issued_at: + en: issued at + fr: émis le + +# company + +invoice_from: + en: Invoice from + fr: Entreprise + +# client + +invoice_to: + en: Invoice to + fr: Client + +# item + +item: + en: Item + fr: Item + +rate: + en: Rate + fr: Taux + +quantity: + en: Quantity + fr: Quantité + +amount: + en: Amount + fr: Montant + +total_in: + en: Total in + fr: Total en + +# bank + +bank_details: + en: Bank details + fr: Coordonnées bancaires + +bank_name: + en: bank + fr: banque + +# tax + +tax_details: + en: Tax details + fr: Taxes + +tax_vat: + en: VAT + fr: TVA -- cgit v1.2.3