-
Notifications
You must be signed in to change notification settings - Fork 0
/
goblhtml.go
137 lines (118 loc) · 3.28 KB
/
goblhtml.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Package goblhtml provides a simple way to render HTML documents from GOBL envelopes.
package goblhtml
import (
"bytes"
"context"
"fmt"
"time"
"github.com/invopop/ctxi18n/i18n"
"github.com/invopop/gobl"
"github.com/invopop/gobl.html/components"
"github.com/invopop/gobl.html/internal"
srclocales "github.com/invopop/gobl.html/locales"
"github.com/invopop/gobl/bill"
"github.com/invopop/gobl/currency"
"github.com/invopop/gobl/num"
"github.com/invopop/gobl/org"
)
const (
defaultLocale i18n.Code = "en"
)
// locales contains the database of locales defined for this package.
var locales *i18n.Locales
func init() {
// Locales are loaded into a global variable for this package so that
// users can continue to use their own locales outside of this one.
locales = new(i18n.Locales)
if err := locales.LoadWithDefault(srclocales.Content, defaultLocale); err != nil {
panic(fmt.Errorf("loading locales: %w", err))
}
}
// Option defines a configuration option to use for rendering.
type Option func(*internal.Opts)
// WithLogo overrides whatever logo was defined in the original envelope,
// if at all, using the provided logo according to the document type.
func WithLogo(logo *org.Image) Option {
return func(o *internal.Opts) {
o.Logo = logo
}
}
// WithNotes adds the provided string to the envelope notes.
func WithNotes(txt string) Option {
return func(o *internal.Opts) {
o.Notes = txt
}
}
// WithLocale sets the locale to use for rendering.
func WithLocale(locale i18n.Code) Option {
return func(o *internal.Opts) {
o.Locale = locale
}
}
// WithCalFormatter prepares simple date and datetime formatting.
func WithCalFormatter(date, dateTime string, loc *time.Location) Option {
return func(o *internal.Opts) {
cf := internal.CalFormatterISO
if date != "" {
cf.Date = date
}
if dateTime != "" {
cf.DateTime = dateTime
}
if loc != nil {
cf.Location = loc
}
o.CalFormatter = &cf
}
}
// WithNumFormatter defines a customer number formatter to use instead of
// that provided by default for the currency.
func WithNumFormatter(nf num.Formatter) Option {
return func(o *internal.Opts) {
o.NumFormatter = &nf
}
}
// WithEmbeddedStylesheets indicates that the stylesheets should be embedded
// inside the HTML document as opposed to links.
func WithEmbeddedStylesheets() Option {
return func(o *internal.Opts) {
o.EmbedStylesheets = true
}
}
// Render takes the GOBL envelope and attempts to render an HTML document
// from it.
func Render(ctx context.Context, env *gobl.Envelope, opts ...Option) ([]byte, error) {
o := new(internal.Opts)
for _, opt := range opts {
opt(o)
}
// Prepare the Locale
if o.Locale == "" {
o.Locale = defaultLocale
}
l := locales.Match(string(o.Locale))
if l == nil {
l = locales.Get(defaultLocale)
}
ctx = l.WithContext(ctx)
// Extract the currency to use for formatting
if o.NumFormatter == nil {
cur := currency.EUR
switch doc := env.Extract().(type) {
case *bill.Invoice:
cur = doc.Currency
}
nf := cur.Def().Formatter()
o.NumFormatter = &nf
}
if o.CalFormatter == nil {
o.CalFormatter = &internal.CalFormatterISO
}
ctx = internal.WithOptions(ctx, o)
out := components.Envelope(env)
buf := new(bytes.Buffer)
if err := out.Render(ctx, buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}