Add the customer name to the invoice’s PDF file name

This was requested by Oriol; there are no other technical or legal
requirements for this.

I can not simply append the customer name to the file because it could
have characters that are not valid in file name depending on the
operating system, so i have to “slugify” it.

Closes #65
This commit is contained in:
jordi fita mas 2023-07-07 11:32:59 +02:00
parent c174fb447c
commit 1164210d84
8 changed files with 33 additions and 4 deletions

3
debian/control vendored
View File

@ -10,8 +10,9 @@ Build-Depends:
golang-github-jackc-pgx-v4-dev, golang-github-jackc-pgx-v4-dev,
golang-github-julienschmidt-httprouter-dev, golang-github-julienschmidt-httprouter-dev,
golang-github-leonelquinteros-gotext-dev, golang-github-leonelquinteros-gotext-dev,
golang-golang-x-text-dev, golang-github-rainycape-unidecode-dev,
golang-github-tealeg-xlsx-dev, golang-github-tealeg-xlsx-dev,
golang-golang-x-text-dev,
postgresql-all (>= 217~), postgresql-all (>= 217~),
sqitch, sqitch,
pgtap, pgtap,

1
go.mod
View File

@ -7,6 +7,7 @@ require (
github.com/jackc/pgx/v4 v4.15.0 github.com/jackc/pgx/v4 v4.15.0
github.com/julienschmidt/httprouter v1.3.0 github.com/julienschmidt/httprouter v1.3.0
github.com/leonelquinteros/gotext v1.5.0 github.com/leonelquinteros/gotext v1.5.0
github.com/rainycape/unidecode v0.0.0-20150906181237-c9cf8cdbbfe8
github.com/tealeg/xlsx v0.0.0-20181024002044-dbf71b6a931e github.com/tealeg/xlsx v0.0.0-20181024002044-dbf71b6a931e
golang.org/x/text v0.7.0 golang.org/x/text v0.7.0
) )

2
go.sum
View File

@ -92,6 +92,8 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rainycape/unidecode v0.0.0-20150906181237-c9cf8cdbbfe8 h1:iZTHFqK/oFrjyFDkiw5U/RjQxkMlkpq6tHQIO407i+s=
github.com/rainycape/unidecode v0.0.0-20150906181237-c9cf8cdbbfe8/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=

View File

@ -658,7 +658,7 @@ func mustWriteInvoicesPdf(r *http.Request, slugs []string) []byte {
if inv == nil { if inv == nil {
continue continue
} }
f, err := w.Create(inv.Number + ".pdf") f, err := w.Create(fmt.Sprintf("%s-%s.pdf", inv.Number, slugify(inv.Invoicee.Name)))
if err != nil { if err != nil {
panic(err) panic(err)
} }

22
pkg/slug.go Normal file
View File

@ -0,0 +1,22 @@
package pkg
import (
"github.com/rainycape/unidecode"
"regexp"
"strings"
)
var (
nonValidChars = regexp.MustCompile("[^a-z0-9-_]")
multipleDashes = regexp.MustCompile("-+")
)
func slugify(s string) (slug string) {
slug = strings.TrimSpace(s)
slug = unidecode.Unidecode(slug)
slug = strings.ToLower(slug)
slug = nonValidChars.ReplaceAllString(slug, "-")
slug = multipleDashes.ReplaceAllString(slug, "-")
slug = strings.Trim(slug, "-_")
return slug
}

View File

@ -86,6 +86,9 @@ func mustRenderTemplate(wr io.Writer, r *http.Request, layout string, filename s
sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"} sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
return humanizeBytes(bytes, 1024, sizes) return humanizeBytes(bytes, 1024, sizes)
}, },
"slugify": func(s string) string {
return slugify(s)
},
}) })
if _, err := t.ParseFiles(templateFile(filename), templateFile(layout), templateFile("form.gohtml")); err != nil { if _, err := t.ParseFiles(templateFile(filename), templateFile(layout), templateFile("form.gohtml")); err != nil {
panic(err) panic(err)

View File

@ -104,7 +104,7 @@
<td class="numeric">{{ .Total|formatPrice }}</td> <td class="numeric">{{ .Total|formatPrice }}</td>
{{- $title = .Number | printf (pgettext "Download invoice %s" "action") -}} {{- $title = .Number | printf (pgettext "Download invoice %s" "action") -}}
<td class="invoice-download"><a href="{{ companyURI "/invoices/"}}{{ .Slug }}.pdf" <td class="invoice-download"><a href="{{ companyURI "/invoices/"}}{{ .Slug }}.pdf"
download="{{ .Number}}.pdf" download="{{ .Number}}-{{ .CustomerName | slugify}}.pdf"
title="{{( pgettext "Download invoice" "action" )}}" title="{{( pgettext "Download invoice" "action" )}}"
aria-label="{{ $title }}"><i aria-label="{{ $title }}"><i
class="ri-download-line"></i></a></td> class="ri-download-line"></i></a></td>

View File

@ -19,7 +19,7 @@
href="{{ companyURI "/invoices/"}}{{ .Slug }}/edit">{{( pgettext "Edit" "action" )}}</a> href="{{ companyURI "/invoices/"}}{{ .Slug }}/edit">{{( pgettext "Edit" "action" )}}</a>
<a class="primary button" <a class="primary button"
href="{{ companyURI "/invoices/" }}{{ .Slug }}.pdf" href="{{ companyURI "/invoices/" }}{{ .Slug }}.pdf"
download="{{ .Number}}.pdf">{{( pgettext "Download invoice" "action" )}}</a> download="{{ .Number}}-{{ .Invoicee.Name | slugify }}.pdf">{{( pgettext "Download invoice" "action" )}}</a>
</p> </p>
</nav> </nav>
{{- end }} {{- end }}