diff options
author | Romain Gonçalves <me@rgoncalves.se> | 2024-07-09 10:04:00 +0200 |
---|---|---|
committer | Romain Gonçalves <me@rgoncalves.se> | 2024-07-09 10:07:47 +0200 |
commit | 28d5c1c212a06d599160f96cbe0e6c88840ab367 (patch) | |
tree | e3504a070c0b212c93db5251c54b324c3ff39380 | |
download | invoiceg-trunk.tar.gz |
inittrunk
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | contrib/Makefile | 5 | ||||
-rw-r--r-- | contrib/invoice-01.md | 28 | ||||
-rw-r--r-- | contrib/metadata.yml | 13 | ||||
-rw-r--r-- | contrib/template.html | 204 | ||||
-rw-r--r-- | go.mod | 12 | ||||
-rw-r--r-- | go.sum | 15 | ||||
-rw-r--r-- | main.go | 31 |
8 files changed, 310 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9c6bdfa --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +contrib/invoice*.html +contrib/invoice*.pdf diff --git a/contrib/Makefile b/contrib/Makefile new file mode 100644 index 0000000..e04d380 --- /dev/null +++ b/contrib/Makefile @@ -0,0 +1,5 @@ +invoice-01.pdf: invoice-01.md + pandoc -s -t html --template template.html --metadata-file metadata.yml $^ | tee invoice-01.html | weasyprint - $@ + +clean: + - rm invoice-01.pdf invoice-01.html diff --git a/contrib/invoice-01.md b/contrib/invoice-01.md new file mode 100644 index 0000000..74705ae --- /dev/null +++ b/contrib/invoice-01.md @@ -0,0 +1,28 @@ +--- +number: "0001" +date: 2024-07-08 +due_date: 2024-08-01 + +notes: ":3" + +currency: EUR + +client: + name: Example + address: Ex Ample, Elpam Xe + email: hello@example.org + +services: + - name: Programming + comment: Lorem ipsum + rate: 1 + qty: 1 + sum: 1 + + - name: System administration + rate: 2.5 + qty: 10 + sum: 25 + +total: 26 +--- diff --git a/contrib/metadata.yml b/contrib/metadata.yml new file mode 100644 index 0000000..61a633c --- /dev/null +++ b/contrib/metadata.yml @@ -0,0 +1,13 @@ +--- + +author: + name: John Smith + address: 123 Sesame St, Cloud, Earth + email: john@smi.th + website: https://smi.th + phone: "+101010101" + +bank: + name: ABC + iban: 2323232323 + swift: LLLLLLXXX diff --git a/contrib/template.html b/contrib/template.html new file mode 100644 index 0000000..458af62 --- /dev/null +++ b/contrib/template.html @@ -0,0 +1,204 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"/> + <style> + * { + margin: 0; + padding: 0; + font-family: monospace, monospace; + font-size: 14px; + color: #111; + } + + @page { + size: A4 portrait; + margin: 16mm; + } + + 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 { + position: fixed; + bottom: 0; + width: 100%; + } + + table * { + vertical-align: top; + } + + p.comment { + color: #444; + margin-left: .5em; + } + + #services table { + border-collapse: collapse; + margin: 2em 0 2em 0; + } + + #services table tr th:last-child, + #services table tr td:last-child { + text-align: right; + } + + #services table thead tr th:first-child { + width: 60%; + } + + #services table tfoot, table thead { + border-bottom: solid 1px black; + } + + #services table tfoot { + border-top: solid 1px black; + } + + #services table tfoot td { + font-weight: 700; + } + + #services table { + width: 100%; + } + + #author { + width: 60%; + } + + #header-title h2 { + width: 60%; + } + + #bank table { + width: 50%; + } + + #metadata { + width: 40%; + } + + #metadata table { + width: 100%; + } + + </style> +</head> + +<body> + + <header> + <article id="author"> + <h2>Invoice from</h2> + <ul> + <li>${ author.name }</li> + <li>${ author.address }</li> + <li><a href="${ author.website }">${ author.website }</a></li> + <li><a href="mailto:${ author.email }">${ author.email }</a></li> + <li><a href="tel:${ author.phone }">${ author.phone }</a></li> + </ul> + </article> + + <article id="metadata"> + <table> + <tr><td><h2>Invoice</h2></td><td> #${ number }</td></tr> + <tr><td>issued at:</td><td> ${ date }</td></tr> + <tr><td>due at:</td><td> ${ due_date }</td></tr> + </table> + </article> + </header> + + <section> + <article id="client"> + <h2>Invoice for</h2> + <ul> + <li>${ client.name }</li> + <li>${ client.address }</li> + <li>${ client.email }</li> + </ul> + </article> + ${ if(notes) } + <article id="notes"> + <p>${ notes }</p> + </article> + ${ endif } + </section> + + <section> + <article id="services"> + <table> + <thead> + <tr> + <th>Description</th> + <th>Rate</th> + <th>Quantity</th> + <th>Amount</th> + </tr> + </thead> + <tbody> + ${ for(services) } + <tr> + <td> + ${ it.name } + ${ if(it.comment) } + <p class="comment">${ it.comment }</p> + ${ endif } + </td> + <td>${ it.rate }</td> + <td>${ it.qty }</td> + <td>${ it.sum }</td> + </tr> + ${ endfor } + </tbody> + <tfoot> + <tr> + <td colspan="3">Total in ${ currency }</td> + <td>${ total }</td> + </tr> + </tfoot> + </table> + </article> + </section> + + <footer> + <hr> + <article id="bank"> + <h2>Bank details</h2> + <table> + <tr><td>name:</td><td> ${ bank.name }</td></tr> + <tr><td>SWIFT:</td><td> ${ bank.swift }</td></tr> + <tr><td>IBAN:</td><td> ${ bank.iban }</td></tr> + </table> + </article> + </footer> +</body> +</html> @@ -0,0 +1,12 @@ +module main.go + +go 1.22.5 + +require ( + github.com/fatih/color v1.17.0 // indirect + github.com/goccy/go-yaml v1.11.3 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect +) @@ -0,0 +1,15 @@ +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= +github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= @@ -0,0 +1,31 @@ +package main + +import ( + "os" + "fmt" + "html/template" + "github.com/goccy/go-yaml" +) + +func check(e error) { + if e != nil { + fmt.Println(e) + panic(e) + } +} + +func main() { + template_file, err := os.ReadFile(os.Args[1]) + check(err) + + data_file, err := os.ReadFile(os.Args[2]) + check(err) + + template_obj, err := template.New("template").Parse(string(template_file)) + check(err) + + data_raw, err := yaml.Marshal(string(data_file)) + check(err) + + template_obj.Execute(os.Stdout, data_raw) +} |