From 490199550d6d8dc79379d46db5bc0933b5ffb30b Mon Sep 17 00:00:00 2001 From: Sam Lown Date: Fri, 3 May 2024 21:57:41 +0000 Subject: [PATCH] Moving to simpler package names, adding mx region specific stuff --- cmd/gobl.html/main.go | 2 +- cmd/gobl.html/serve.go | 56 ++- .../{billing => bill}/invoice/customer.templ | 8 +- .../invoice/customer_templ.go | 8 +- .../{billing => bill}/invoice/invoice.templ | 21 +- .../invoice/invoice_templ.go | 13 +- .../{billing => bill}/invoice/line_support.go | 5 +- .../{billing => bill}/invoice/lines.templ | 10 +- .../{billing => bill}/invoice/lines_templ.go | 140 +++--- .../{billing => bill}/invoice/notes.templ | 0 .../{billing => bill}/invoice/notes_templ.go | 0 .../{billing => bill}/invoice/payment.templ | 0 .../invoice/payment_templ.go | 12 +- .../{billing => bill}/invoice/summary.templ | 35 +- .../invoice/summary_templ.go | 137 +++--- .../{billing => bill}/invoice/supplier.templ | 8 +- .../invoice/supplier_templ.go | 8 +- .../{billing => bill}/invoice/taxes.templ | 8 +- .../{billing => bill}/invoice/taxes_templ.go | 19 +- .../{billing => bill}/invoice/totals.templ | 0 .../{billing => bill}/invoice/totals_templ.go | 0 components/components.go | 3 + components/envelope.templ | 2 +- components/envelope_templ.go | 2 +- components/{organizing => org}/address.templ | 5 +- .../{organizing => org}/address_templ.go | 7 +- components/{organizing => org}/party.templ | 5 +- components/{organizing => org}/party_templ.go | 95 ++-- components/regimes/co/dian.templ | 5 +- components/regimes/es/ticketbai.templ | 20 +- components/regimes/es/ticketbai_templ.go | 2 +- components/regimes/mx/cfdi.templ | 13 + components/regimes/mx/cfdi_templ.go | 46 ++ components/regimes/mx/complements.templ | 287 +++++++++++ components/regimes/mx/complements_templ.go | 456 ++++++++++++++++++ components/regimes/mx/line.templ | 18 + components/regimes/mx/line_templ.go | 56 +++ components/regimes/mx/mx.go | 3 + components/regimes/mx/signatures.templ | 105 ++++ components/regimes/mx/signatures_templ.go | 226 +++++++++ components/t/i18n.templ | 19 +- components/t/i18n_templ.go | 19 +- components/t/t.go | 55 ++- examples/invoice-limited-company.json | 3 - examples/invoice-mx.json | 208 ++++++++ examples/mx-food-voucher.json | 177 +++++++ examples/mx-fuel-balance.json | 204 ++++++++ go.mod | 8 +- go.sum | 12 +- goblhtml.go | 117 ++++- locales/de/app.yml | 2 +- locales/en/app.yml | 6 +- locales/es/app.yml | 3 +- locales/fr/app.yml | 24 +- 54 files changed, 2407 insertions(+), 296 deletions(-) rename components/{billing => bill}/invoice/customer.templ (54%) rename components/{billing => bill}/invoice/customer_templ.go (89%) rename components/{billing => bill}/invoice/invoice.templ (95%) rename components/{billing => bill}/invoice/invoice_templ.go (94%) rename components/{billing => bill}/invoice/line_support.go (92%) rename components/{billing => bill}/invoice/lines.templ (95%) rename components/{billing => bill}/invoice/lines_templ.go (95%) rename components/{billing => bill}/invoice/notes.templ (100%) rename components/{billing => bill}/invoice/notes_templ.go (100%) rename components/{billing => bill}/invoice/payment.templ (100%) rename components/{billing => bill}/invoice/payment_templ.go (98%) rename components/{billing => bill}/invoice/summary.templ (77%) rename components/{billing => bill}/invoice/summary_templ.go (79%) rename components/{billing => bill}/invoice/supplier.templ (54%) rename components/{billing => bill}/invoice/supplier_templ.go (89%) rename components/{billing => bill}/invoice/taxes.templ (89%) rename components/{billing => bill}/invoice/taxes_templ.go (95%) rename components/{billing => bill}/invoice/totals.templ (100%) rename components/{billing => bill}/invoice/totals_templ.go (100%) create mode 100644 components/components.go rename components/{organizing => org}/address.templ (95%) rename components/{organizing => org}/address_templ.go (98%) rename components/{organizing => org}/party.templ (97%) rename components/{organizing => org}/party_templ.go (90%) create mode 100644 components/regimes/mx/cfdi.templ create mode 100644 components/regimes/mx/cfdi_templ.go create mode 100644 components/regimes/mx/complements.templ create mode 100644 components/regimes/mx/complements_templ.go create mode 100644 components/regimes/mx/line.templ create mode 100644 components/regimes/mx/line_templ.go create mode 100644 components/regimes/mx/mx.go create mode 100644 components/regimes/mx/signatures.templ create mode 100644 components/regimes/mx/signatures_templ.go create mode 100644 examples/invoice-mx.json create mode 100644 examples/mx-food-voucher.json create mode 100644 examples/mx-fuel-balance.json diff --git a/cmd/gobl.html/main.go b/cmd/gobl.html/main.go index dc57d43..e77c508 100644 --- a/cmd/gobl.html/main.go +++ b/cmd/gobl.html/main.go @@ -28,7 +28,7 @@ func run() error { ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer cancel() - if err := ctxi18n.Load(locales.Content); err != nil { + if err := ctxi18n.LoadWithDefault(locales.Content, "en"); err != nil { return fmt.Errorf("loading locales: %w", err) } diff --git a/cmd/gobl.html/serve.go b/cmd/gobl.html/serve.go index 871ed45..9262c03 100644 --- a/cmd/gobl.html/serve.go +++ b/cmd/gobl.html/serve.go @@ -11,10 +11,11 @@ import ( "strings" "time" - "github.com/invopop/ctxi18n" + "github.com/invopop/ctxi18n/i18n" "github.com/invopop/gobl" goblhtml "github.com/invopop/gobl.html" "github.com/invopop/gobl.html/pkg/pdf" + "github.com/invopop/gobl/org" "github.com/labstack/echo/v4" "github.com/spf13/cobra" ) @@ -83,24 +84,30 @@ func (s *serveOpts) runE(cmd *cobra.Command, args []string) error { return startErr } -func (s *serveOpts) render(c echo.Context, env *gobl.Envelope) ([]byte, error) { +func (s *serveOpts) render(c echo.Context, req *options, env *gobl.Envelope) ([]byte, error) { + ctx := c.Request().Context() var err error - locale := c.QueryParam("locale") - if locale == "" { - locale = "en" + // Prepare the request options + opts := make([]goblhtml.Option, 0) + if req.DateFormat != "" { + opts = append(opts, goblhtml.WithCalFormatter(req.DateFormat, "", time.UTC)) } + opts = append(opts, goblhtml.WithLocale(req.Locale)) - fmt.Printf("LOCALE: %v\n", locale) - - // Set the locale to English to start with - ctx := c.Request().Context() - ctx, err = ctxi18n.WithLocale(ctx, locale) - if err != nil { - return nil, fmt.Errorf("setting locale: %w", err) + // Add some of the extras to the output + if req.LogoURL != "" { + logo := &org.Image{ + URL: req.LogoURL, + Height: req.LogoHeight, + } + opts = append(opts, goblhtml.WithLogo(logo)) + } + if req.Notes != "" { + opts = append(opts, goblhtml.WithNotes(req.Notes)) } - out, err := goblhtml.Render(ctx, env) + out, err := goblhtml.Render(ctx, env, opts...) if err != nil { return nil, fmt.Errorf("generating html: %w", err) } @@ -108,12 +115,25 @@ func (s *serveOpts) render(c echo.Context, env *gobl.Envelope) ([]byte, error) { return out, nil } +type options struct { + Filename string `param:"filename"` + Locale i18n.Code `query:"locale"` + DateFormat string `query:"date_format"` + LogoURL string `query:"logo_url"` + LogoHeight int32 `query:"logo_height"` + Notes string `query:"notes"` +} + func (s *serveOpts) generate(c echo.Context) error { - filename := c.Param("filename") - ext := filepath.Ext(filename) - filename = strings.TrimSuffix(filename, ext) + ".json" + req := new(options) + if err := c.Bind(req); err != nil { + return fmt.Errorf("binding options: %w", err) + } + + ext := filepath.Ext(req.Filename) + req.Filename = strings.TrimSuffix(req.Filename, ext) + ".json" - ed, err := os.ReadFile(filepath.Join("./examples", filename)) + ed, err := os.ReadFile(filepath.Join("./examples", req.Filename)) if err != nil { return fmt.Errorf("loading file: %w", err) } @@ -123,7 +143,7 @@ func (s *serveOpts) generate(c echo.Context) error { return fmt.Errorf("unmarshalling file: %w", err) } - data, err := s.render(c, env) + data, err := s.render(c, req, env) if err != nil { return err } diff --git a/components/billing/invoice/customer.templ b/components/bill/invoice/customer.templ similarity index 54% rename from components/billing/invoice/customer.templ rename to components/bill/invoice/customer.templ index 5e4e4fb..6e53f2c 100644 --- a/components/billing/invoice/customer.templ +++ b/components/bill/invoice/customer.templ @@ -1,16 +1,16 @@ package invoice import ( - "github.com/invopop/gobl/org" - "github.com/invopop/gobl.html/components/organizing" + "github.com/invopop/gobl/bill" + "github.com/invopop/gobl.html/components/org" "github.com/invopop/gobl.html/components/t" ) -templ customer(party *org.Party) { +templ customer(inv *bill.Invoice) {

@t.T("billing.invoice.customer.title")

- @organizing.Party(party) + @org.Party(inv.Customer)
} diff --git a/components/billing/invoice/customer_templ.go b/components/bill/invoice/customer_templ.go similarity index 89% rename from components/billing/invoice/customer_templ.go rename to components/bill/invoice/customer_templ.go index 80fa5b8..bb1699c 100644 --- a/components/billing/invoice/customer_templ.go +++ b/components/bill/invoice/customer_templ.go @@ -11,12 +11,12 @@ import "io" import "bytes" import ( - "github.com/invopop/gobl.html/components/organizing" + "github.com/invopop/gobl.html/components/org" "github.com/invopop/gobl.html/components/t" - "github.com/invopop/gobl/org" + "github.com/invopop/gobl/bill" ) -func customer(party *org.Party) templ.Component { +func customer(inv *bill.Invoice) templ.Component { return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) if !templ_7745c5c3_IsBuffer { @@ -41,7 +41,7 @@ func customer(party *org.Party) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = organizing.Party(party).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = org.Party(inv.Customer).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/components/billing/invoice/invoice.templ b/components/bill/invoice/invoice.templ similarity index 95% rename from components/billing/invoice/invoice.templ rename to components/bill/invoice/invoice.templ index ed29712..e8ba2e2 100644 --- a/components/billing/invoice/invoice.templ +++ b/components/bill/invoice/invoice.templ @@ -11,6 +11,7 @@ import ( "github.com/invopop/gobl.html/components/regimes/es" "github.com/invopop/gobl.html/components/regimes/co" + "github.com/invopop/gobl.html/components/regimes/mx" ) // Invoice renders a complete GOBL bill.Invoice object. @@ -100,7 +101,6 @@ templ Invoice(env *gobl.Envelope, inv *bill.Invoice) { order: 5; padding-top: 6mm; padding-bottom: 0mm; - } section.lines h2 { display: none; @@ -139,6 +139,12 @@ templ Invoice(env *gobl.Envelope, inv *bill.Invoice) { section.lines .label { font-weight: 500; } + section.lines .description .extensions { + display: block; + } + section.lines .description .extensions .label { + font-weight: 500; + } div.totals { order: 8; display: flex; @@ -263,13 +269,13 @@ templ Invoice(env *gobl.Envelope, inv *bill.Invoice) { section.notes .note { margin-bottom: 3mm; } - section.extensions { + .extensions section { break-inside: avoid; padding-top: 6mm; padding-bottom: 6mm; border-bottom: 0.5px solid #E5E7EB; } - section.extensions:empty { + .extensions:empty { display: none; } .org-party .name { @@ -287,9 +293,9 @@ templ Invoice(env *gobl.Envelope, inv *bill.Invoice) { @summary(inv)
- @supplier(inv.Supplier) + @supplier(inv) if inv.Customer != nil { - @customer(inv.Customer) + @customer(inv) }
@@ -300,11 +306,12 @@ templ Invoice(env *gobl.Envelope, inv *bill.Invoice) { @payment(inv) @notes(inv) -
+
// Region specific information @es.TicketBAIQR(env) @co.DIANQR(env, inv) -
+ @mx.CFDI(env, inv) + } diff --git a/components/billing/invoice/invoice_templ.go b/components/bill/invoice/invoice_templ.go similarity index 94% rename from components/billing/invoice/invoice_templ.go rename to components/bill/invoice/invoice_templ.go index fc4cccc..7468530 100644 --- a/components/billing/invoice/invoice_templ.go +++ b/components/bill/invoice/invoice_templ.go @@ -21,6 +21,7 @@ import ( "github.com/invopop/gobl.html/components/regimes/co" "github.com/invopop/gobl.html/components/regimes/es" + "github.com/invopop/gobl.html/components/regimes/mx" ) // Invoice renders a complete GOBL bill.Invoice object. @@ -53,12 +54,12 @@ func Invoice(env *gobl.Envelope, inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = supplier(inv.Supplier).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = supplier(inv).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if inv.Customer != nil { - templ_7745c5c3_Err = customer(inv.Customer).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = customer(inv).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -107,6 +108,10 @@ func Invoice(env *gobl.Envelope, inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } + templ_7745c5c3_Err = mx.CFDI(env, inv).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err @@ -172,7 +177,7 @@ func title(inv *bill.Invoice) templ.Component { var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(supplierAlias(inv)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/invoice.templ`, Line: 317, Col: 25} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/invoice.templ`, Line: 324, Col: 25} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -198,7 +203,7 @@ func title(inv *bill.Invoice) templ.Component { var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(code(inv.Series, inv.Code)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/invoice.templ`, Line: 325, Col: 31} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/invoice.templ`, Line: 332, Col: 31} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { diff --git a/components/billing/invoice/line_support.go b/components/bill/invoice/line_support.go similarity index 92% rename from components/billing/invoice/line_support.go rename to components/bill/invoice/line_support.go index 5cf5dcb..8ce550c 100644 --- a/components/billing/invoice/line_support.go +++ b/components/bill/invoice/line_support.go @@ -34,7 +34,10 @@ func prepareLineSupport(inv *bill.Invoice) *lineSupport { ls.units = true } for _, combo := range l.Taxes { - cats = addCategory(cats, r.Category(combo.Category)) + cat := r.Category(combo.Category) + if cat != nil { + cats = addCategory(cats, cat) + } } } for _, row := range inv.Discounts { diff --git a/components/billing/invoice/lines.templ b/components/bill/invoice/lines.templ similarity index 95% rename from components/billing/invoice/lines.templ rename to components/bill/invoice/lines.templ index 42801c0..950d3d3 100644 --- a/components/billing/invoice/lines.templ +++ b/components/bill/invoice/lines.templ @@ -5,6 +5,7 @@ import ( "github.com/invopop/gobl/bill" "github.com/invopop/gobl.html/components/t" + "github.com/invopop/gobl.html/components/regimes/mx" ) templ lines(inv *bill.Invoice) { @@ -45,7 +46,7 @@ templ linesWithSupport(inv *bill.Invoice, ls *lineSupport) { for _, cat := range ls.categories { - { cat.Name.String() } + { cat.Name.In(t.Lang(ctx)) } } if ls.discounts { @@ -98,6 +99,7 @@ templ line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) {
{ l.Item.Description } } + @mx.LineExtensions(l) @t.L(l.Quantity) @@ -117,7 +119,11 @@ templ line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) { for _, cat := range ls.categories { if combo := l.Taxes.Get(cat.Code); combo != nil { - @t.L(*combo.Percent) + if combo.Percent != nil { + @t.L(*combo.Percent) + } else { + — + } } else { } diff --git a/components/billing/invoice/lines_templ.go b/components/bill/invoice/lines_templ.go similarity index 95% rename from components/billing/invoice/lines_templ.go rename to components/bill/invoice/lines_templ.go index f30a091..4614150 100644 --- a/components/billing/invoice/lines_templ.go +++ b/components/bill/invoice/lines_templ.go @@ -13,6 +13,7 @@ import "bytes" import ( "fmt" + "github.com/invopop/gobl.html/components/regimes/mx" "github.com/invopop/gobl.html/components/t" "github.com/invopop/gobl/bill" ) @@ -155,9 +156,9 @@ func linesWithSupport(inv *bill.Invoice, ls *lineSupport) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var4 string - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(cat.Name.String()) + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(cat.Name.In(t.Lang(ctx))) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 47, Col: 26} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 48, Col: 33} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { @@ -285,7 +286,7 @@ func line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) templ.Component { var templ_7745c5c3_Var7 string templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprint(l.Index)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 83, Col: 24} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 84, Col: 24} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { @@ -304,7 +305,7 @@ func line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) templ.Component { var templ_7745c5c3_Var8 string templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(l.Item.Ref) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 88, Col: 17} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 89, Col: 17} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) if templ_7745c5c3_Err != nil { @@ -328,7 +329,7 @@ func line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) templ.Component { var templ_7745c5c3_Var9 string templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(l.Item.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 95, Col: 22} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 96, Col: 22} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) if templ_7745c5c3_Err != nil { @@ -346,7 +347,7 @@ func line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) templ.Component { var templ_7745c5c3_Var10 string templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(l.Item.Description) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 98, Col: 31} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 99, Col: 31} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) if templ_7745c5c3_Err != nil { @@ -357,6 +358,10 @@ func line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) templ.Component { return templ_7745c5c3_Err } } + templ_7745c5c3_Err = mx.LineExtensions(l).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 33) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err @@ -378,7 +383,7 @@ func line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) templ.Component { var templ_7745c5c3_Var11 string templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(string(l.Item.Unit)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 107, Col: 26} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 109, Col: 26} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) if templ_7745c5c3_Err != nil { @@ -413,23 +418,30 @@ func line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) templ.Component { return templ_7745c5c3_Err } if combo := l.Taxes.Get(cat.Code); combo != nil { - templ_7745c5c3_Err = t.L(*combo.Percent).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err + if combo.Percent != nil { + templ_7745c5c3_Err = t.L(*combo.Percent).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 41) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } } } else { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 41) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 42) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 42) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 43) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } if ls.discounts { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 43) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 44) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -437,13 +449,13 @@ func line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 44) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 45) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } if ls.charges { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 45) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 46) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -451,12 +463,12 @@ func line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 46) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 47) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 47) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 48) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -464,7 +476,7 @@ func line(_ *bill.Invoice, l *bill.Line, ls *lineSupport) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 48) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 49) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -555,7 +567,7 @@ func discountsBody(inv *bill.Invoice, ls *lineSupport) templ.Component { } ctx = templ.ClearChildren(ctx) if len(inv.Discounts) > 0 { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 49) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 50) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -565,7 +577,7 @@ func discountsBody(inv *bill.Invoice, ls *lineSupport) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 50) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 51) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -590,25 +602,25 @@ func discountRow(row *bill.Discount, ls *lineSupport) templ.Component { templ_7745c5c3_Var15 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 51) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 52) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var16 string templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("D%d", row.Index)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 174, Col: 34} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 180, Col: 34} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 52) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 53) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if ls.refs { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 53) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 54) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -616,47 +628,47 @@ func discountRow(row *bill.Discount, ls *lineSupport) templ.Component { var templ_7745c5c3_Var17 string templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(row.Ref) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 179, Col: 14} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 185, Col: 14} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 54) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 55) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 55) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 56) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 56) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 57) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var18 string templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(row.Reason) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 186, Col: 15} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 192, Col: 15} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 57) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 58) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if ls.units { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 58) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 59) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 59) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 60) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -666,17 +678,17 @@ func discountRow(row *bill.Discount, ls *lineSupport) templ.Component { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 60) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 61) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 61) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 62) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } for _, cat := range ls.categories { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 62) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 63) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -686,29 +698,29 @@ func discountRow(row *bill.Discount, ls *lineSupport) templ.Component { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 63) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 64) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 64) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 65) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } if ls.discounts { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 65) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 66) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } if ls.charges { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 66) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 67) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 67) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 68) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -716,7 +728,7 @@ func discountRow(row *bill.Discount, ls *lineSupport) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 68) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 69) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -741,7 +753,7 @@ func chargesBody(inv *bill.Invoice, ls *lineSupport) templ.Component { } ctx = templ.ClearChildren(ctx) if len(inv.Charges) > 0 { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 69) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 70) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -751,7 +763,7 @@ func chargesBody(inv *bill.Invoice, ls *lineSupport) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 70) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 71) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -776,25 +788,25 @@ func chargeRow(row *bill.Charge, ls *lineSupport) templ.Component { templ_7745c5c3_Var20 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 71) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 72) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var21 string templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("C%d", row.Index)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 241, Col: 34} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 247, Col: 34} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 72) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 73) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if ls.refs { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 73) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 74) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -802,47 +814,47 @@ func chargeRow(row *bill.Charge, ls *lineSupport) templ.Component { var templ_7745c5c3_Var22 string templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(row.Ref) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 246, Col: 14} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 252, Col: 14} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 74) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 75) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 75) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 76) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 76) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 77) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var23 string templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(row.Reason) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/lines.templ`, Line: 253, Col: 15} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/lines.templ`, Line: 259, Col: 15} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 77) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 78) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if ls.units { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 78) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 79) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 79) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 80) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -852,17 +864,17 @@ func chargeRow(row *bill.Charge, ls *lineSupport) templ.Component { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 80) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 81) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 81) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 82) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } for _, cat := range ls.categories { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 82) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 83) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -872,29 +884,29 @@ func chargeRow(row *bill.Charge, ls *lineSupport) templ.Component { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 83) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 84) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 84) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 85) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } if ls.discounts { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 85) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 86) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } if ls.charges { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 86) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 87) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 87) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 88) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -902,7 +914,7 @@ func chargeRow(row *bill.Charge, ls *lineSupport) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 88) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 89) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/components/billing/invoice/notes.templ b/components/bill/invoice/notes.templ similarity index 100% rename from components/billing/invoice/notes.templ rename to components/bill/invoice/notes.templ diff --git a/components/billing/invoice/notes_templ.go b/components/bill/invoice/notes_templ.go similarity index 100% rename from components/billing/invoice/notes_templ.go rename to components/bill/invoice/notes_templ.go diff --git a/components/billing/invoice/payment.templ b/components/bill/invoice/payment.templ similarity index 100% rename from components/billing/invoice/payment.templ rename to components/bill/invoice/payment.templ diff --git a/components/billing/invoice/payment_templ.go b/components/bill/invoice/payment_templ.go similarity index 98% rename from components/billing/invoice/payment_templ.go rename to components/bill/invoice/payment_templ.go index 0f8dc4e..abde8a3 100644 --- a/components/billing/invoice/payment_templ.go +++ b/components/bill/invoice/payment_templ.go @@ -129,7 +129,7 @@ func paymentInstructions(inst *pay.Instructions) templ.Component { var templ_7745c5c3_Var5 string templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(pm) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/payment.templ`, Line: 36, Col: 10} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/payment.templ`, Line: 36, Col: 10} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { @@ -156,7 +156,7 @@ func paymentInstructions(inst *pay.Instructions) templ.Component { var templ_7745c5c3_Var6 string templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(inst.Ref) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/payment.templ`, Line: 46, Col: 16} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/payment.templ`, Line: 46, Col: 16} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { @@ -237,7 +237,7 @@ func paymentInstructions(inst *pay.Instructions) templ.Component { var templ_7745c5c3_Var7 string templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(inst.Notes) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/payment.templ`, Line: 80, Col: 18} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/payment.templ`, Line: 80, Col: 18} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { @@ -391,7 +391,7 @@ func paymentTerms(terms *pay.Terms) templ.Component { var templ_7745c5c3_Var11 string templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(paymentTermsKeyName(ctx, terms)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/payment.templ`, Line: 122, Col: 39} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/payment.templ`, Line: 122, Col: 39} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) if templ_7745c5c3_Err != nil { @@ -418,7 +418,7 @@ func paymentTerms(terms *pay.Terms) templ.Component { var templ_7745c5c3_Var12 string templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(terms.Notes) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/payment.templ`, Line: 132, Col: 19} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/payment.templ`, Line: 132, Col: 19} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) if templ_7745c5c3_Err != nil { @@ -506,7 +506,7 @@ func paymentDueDates(terms *pay.Terms) templ.Component { var templ_7745c5c3_Var14 string templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(dd.Notes) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/payment.templ`, Line: 161, Col: 16} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/payment.templ`, Line: 161, Col: 16} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { diff --git a/components/billing/invoice/summary.templ b/components/bill/invoice/summary.templ similarity index 77% rename from components/billing/invoice/summary.templ rename to components/bill/invoice/summary.templ index fa53e61..8258175 100644 --- a/components/billing/invoice/summary.templ +++ b/components/bill/invoice/summary.templ @@ -1,8 +1,12 @@ package invoice import ( + "strings" + "github.com/invopop/gobl/bill" "github.com/invopop/gobl/cal" + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/tax" "github.com/invopop/ctxi18n/i18n" "github.com/invopop/gobl.html/components/t" "github.com/invopop/gobl/currency" @@ -20,7 +24,7 @@ templ summary(inv *bill.Invoice) { @t.T(".issue_date") - { inv.IssueDate.String() } + @t.L(inv.IssueDate)
  • @@ -37,7 +41,7 @@ templ summary(inv *bill.Invoice) { @t.T(".value_date") - { inv.ValueDate.String() } + @t.L(inv.ValueDate)
  • } @@ -47,7 +51,7 @@ templ summary(inv *bill.Invoice) { @t.T(".operation_date") - { inv.OperationDate.String() } + @t.L(inv.OperationDate) } @@ -61,7 +65,7 @@ templ summary(inv *bill.Invoice) { if pre.IssueDate != nil { - { pre.IssueDate.String() } + @t.L(pre.IssueDate) } if pre.Reason != "" { @@ -74,6 +78,20 @@ templ summary(inv *bill.Invoice) { if inv.Ordering != nil { @summaryOrderingRows(inv) } + if inv.Tax != nil { + for k, v := range inv.Tax.Ext { + if label := mapTaxExtension(ctx, k, v); label != "" { +
  • + + { label } + + + { v.String() } + +
  • + } + } + } } @@ -119,3 +137,12 @@ func currencyName(ctx context.Context, cur currency.Code) string { name := i18n.T(ctx, "currencies."+string(cur), i18n.Default(def.Name)) return i18n.T(ctx, "billing.invoice.summary.currency_value", i18n.M{"desc": name, "code": cur}) } + +func mapTaxExtension(ctx context.Context, k cbc.Key, v tax.ExtValue) string { + // find the key translation + label := i18n.T(ctx, ".ext_map."+k.String()) + if strings.HasPrefix(label, "!") { // if match found + return "" + } + return label +} diff --git a/components/billing/invoice/summary_templ.go b/components/bill/invoice/summary_templ.go similarity index 79% rename from components/billing/invoice/summary_templ.go rename to components/bill/invoice/summary_templ.go index a3b64dc..3486b3e 100644 --- a/components/billing/invoice/summary_templ.go +++ b/components/bill/invoice/summary_templ.go @@ -11,11 +11,15 @@ import "io" import "bytes" import ( + "strings" + "github.com/invopop/ctxi18n/i18n" "github.com/invopop/gobl.html/components/t" "github.com/invopop/gobl/bill" "github.com/invopop/gobl/cal" + "github.com/invopop/gobl/cbc" "github.com/invopop/gobl/currency" + "github.com/invopop/gobl/tax" ) func summary(inv *bill.Invoice) templ.Component { @@ -61,12 +65,7 @@ func summary(inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var3 string - templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(inv.IssueDate.String()) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/summary.templ`, Line: 22, Col: 30} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + templ_7745c5c3_Err = t.L(inv.IssueDate).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -82,12 +81,12 @@ func summary(inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var4 string - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(currencyName(ctx, inv.Currency)) + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(currencyName(ctx, inv.Currency)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/summary.templ`, Line: 30, Col: 39} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/summary.templ`, Line: 34, Col: 39} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -108,12 +107,7 @@ func summary(inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var5 string - templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(inv.ValueDate.String()) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/summary.templ`, Line: 39, Col: 31} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + templ_7745c5c3_Err = t.L(inv.ValueDate).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -135,12 +129,7 @@ func summary(inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var6 string - templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(inv.OperationDate.String()) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/summary.templ`, Line: 49, Col: 35} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) + templ_7745c5c3_Err = t.L(inv.OperationDate).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -162,12 +151,12 @@ func summary(inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var7 string - templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(code(pre.Series, pre.Code)) + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(code(pre.Series, pre.Code)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/summary.templ`, Line: 59, Col: 35} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/summary.templ`, Line: 63, Col: 35} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -180,12 +169,7 @@ func summary(inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var8 string - templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(pre.IssueDate.String()) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/summary.templ`, Line: 63, Col: 32} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + templ_7745c5c3_Err = t.L(pre.IssueDate).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -199,12 +183,12 @@ func summary(inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var9 string - templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(pre.Reason) + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(pre.Reason) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/summary.templ`, Line: 68, Col: 20} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/summary.templ`, Line: 72, Col: 20} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -224,7 +208,43 @@ func summary(inv *bill.Invoice) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 22) + if inv.Tax != nil { + for k, v := range inv.Tax.Ext { + if label := mapTaxExtension(ctx, k, v); label != "" { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 22) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(label) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/summary.templ`, Line: 85, Col: 16} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 23) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(v.String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/summary.templ`, Line: 88, Col: 21} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 24) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 25) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -237,7 +257,7 @@ func summary(inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 23) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 26) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -256,13 +276,13 @@ func summaryOrderingRows(inv *bill.Invoice) templ.Component { defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var10 := templ.GetChildren(ctx) - if templ_7745c5c3_Var10 == nil { - templ_7745c5c3_Var10 = templ.NopComponent + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent } ctx = templ.ClearChildren(ctx) if inv.Ordering.Code != "" { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 24) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 27) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -270,20 +290,20 @@ func summaryOrderingRows(inv *bill.Invoice) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 25) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 28) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var11 string - templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(inv.Ordering.Code) + var templ_7745c5c3_Var9 string + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(inv.Ordering.Code) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/summary.templ`, Line: 88, Col: 23} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/summary.templ`, Line: 106, Col: 23} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 26) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 29) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -309,12 +329,12 @@ func summaryOrderPeriodRows(p *cal.Period) templ.Component { defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var12 := templ.GetChildren(ctx) - if templ_7745c5c3_Var12 == nil { - templ_7745c5c3_Var12 = templ.NopComponent + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 27) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 30) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -329,7 +349,7 @@ func summaryOrderPeriodRows(p *cal.Period) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 28) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 31) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -337,7 +357,7 @@ func summaryOrderPeriodRows(p *cal.Period) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 29) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 32) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -357,3 +377,12 @@ func currencyName(ctx context.Context, cur currency.Code) string { name := i18n.T(ctx, "currencies."+string(cur), i18n.Default(def.Name)) return i18n.T(ctx, "billing.invoice.summary.currency_value", i18n.M{"desc": name, "code": cur}) } + +func mapTaxExtension(ctx context.Context, k cbc.Key, v tax.ExtValue) string { + // find the key translation + label := i18n.T(ctx, ".ext_map."+k.String()) + if strings.HasPrefix(label, "!") { // if match found + return "" + } + return label +} diff --git a/components/billing/invoice/supplier.templ b/components/bill/invoice/supplier.templ similarity index 54% rename from components/billing/invoice/supplier.templ rename to components/bill/invoice/supplier.templ index ba6e63c..9d44fcb 100644 --- a/components/billing/invoice/supplier.templ +++ b/components/bill/invoice/supplier.templ @@ -1,16 +1,16 @@ package invoice import ( - "github.com/invopop/gobl/org" - "github.com/invopop/gobl.html/components/organizing" + "github.com/invopop/gobl/bill" + "github.com/invopop/gobl.html/components/org" "github.com/invopop/gobl.html/components/t" ) -templ supplier(party *org.Party) { +templ supplier(inv *bill.Invoice) {

    @t.T("billing.invoice.supplier.title")

    - @organizing.Party(party) + @org.Party(inv.Supplier)
    } diff --git a/components/billing/invoice/supplier_templ.go b/components/bill/invoice/supplier_templ.go similarity index 89% rename from components/billing/invoice/supplier_templ.go rename to components/bill/invoice/supplier_templ.go index 1282e4e..6c27e88 100644 --- a/components/billing/invoice/supplier_templ.go +++ b/components/bill/invoice/supplier_templ.go @@ -11,12 +11,12 @@ import "io" import "bytes" import ( - "github.com/invopop/gobl.html/components/organizing" + "github.com/invopop/gobl.html/components/org" "github.com/invopop/gobl.html/components/t" - "github.com/invopop/gobl/org" + "github.com/invopop/gobl/bill" ) -func supplier(party *org.Party) templ.Component { +func supplier(inv *bill.Invoice) templ.Component { return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) if !templ_7745c5c3_IsBuffer { @@ -41,7 +41,7 @@ func supplier(party *org.Party) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = organizing.Party(party).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = org.Party(inv.Supplier).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/components/billing/invoice/taxes.templ b/components/bill/invoice/taxes.templ similarity index 89% rename from components/billing/invoice/taxes.templ rename to components/bill/invoice/taxes.templ index e4d0064..c9de366 100644 --- a/components/billing/invoice/taxes.templ +++ b/components/bill/invoice/taxes.templ @@ -49,7 +49,7 @@ templ taxRateRow(inv *bill.Invoice, cat *tax.CategoryTotal, rate *tax.RateTotal, if span > 0 { - { taxCategoryTotalName(inv, cat) } + { taxCategoryTotalName(ctx, inv, cat) } } @@ -62,6 +62,8 @@ templ taxRateRow(inv *bill.Invoice, cat *tax.CategoryTotal, rate *tax.RateTotal, } else { @t.L(*rate.Percent) } + } else { + — } if rate.Surcharge != nil { +@t.P(rate.Surcharge.Percent) @@ -89,8 +91,8 @@ func taxCategoryRowSpan(ct *tax.CategoryTotal, row int) int { return 0 } -func taxCategoryTotalName(inv *bill.Invoice, cat *tax.CategoryTotal) string { +func taxCategoryTotalName(ctx context.Context, inv *bill.Invoice, cat *tax.CategoryTotal) string { r := inv.TaxRegime() category := r.Category(cat.Code) - return category.Name.String() + return category.Name.In(t.Lang(ctx)) } diff --git a/components/billing/invoice/taxes_templ.go b/components/bill/invoice/taxes_templ.go similarity index 95% rename from components/billing/invoice/taxes_templ.go rename to components/bill/invoice/taxes_templ.go index 0466b63..a183813 100644 --- a/components/billing/invoice/taxes_templ.go +++ b/components/bill/invoice/taxes_templ.go @@ -150,9 +150,9 @@ func taxRateRow(inv *bill.Invoice, cat *tax.CategoryTotal, rate *tax.RateTotal, return templ_7745c5c3_Err } var templ_7745c5c3_Var4 string - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(taxCategoryTotalName(inv, cat)) + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(taxCategoryTotalName(ctx, inv, cat)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/billing/invoice/taxes.templ`, Line: 51, Col: 36} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/bill/invoice/taxes.templ`, Line: 51, Col: 41} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { @@ -187,14 +187,19 @@ func taxRateRow(inv *bill.Invoice, cat *tax.CategoryTotal, rate *tax.RateTotal, return templ_7745c5c3_Err } } + } else { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 16) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } } if rate.Surcharge != nil { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 16) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 17) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 17) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 18) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -209,7 +214,7 @@ func taxRateRow(inv *bill.Invoice, cat *tax.CategoryTotal, rate *tax.RateTotal, return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 18) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 19) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -232,8 +237,8 @@ func taxCategoryRowSpan(ct *tax.CategoryTotal, row int) int { return 0 } -func taxCategoryTotalName(inv *bill.Invoice, cat *tax.CategoryTotal) string { +func taxCategoryTotalName(ctx context.Context, inv *bill.Invoice, cat *tax.CategoryTotal) string { r := inv.TaxRegime() category := r.Category(cat.Code) - return category.Name.String() + return category.Name.In(t.Lang(ctx)) } diff --git a/components/billing/invoice/totals.templ b/components/bill/invoice/totals.templ similarity index 100% rename from components/billing/invoice/totals.templ rename to components/bill/invoice/totals.templ diff --git a/components/billing/invoice/totals_templ.go b/components/bill/invoice/totals_templ.go similarity index 100% rename from components/billing/invoice/totals_templ.go rename to components/bill/invoice/totals_templ.go diff --git a/components/components.go b/components/components.go new file mode 100644 index 0000000..fa9914f --- /dev/null +++ b/components/components.go @@ -0,0 +1,3 @@ +// Package components defines all the templ components that will be used +// to render GOBL envelopes. +package components diff --git a/components/envelope.templ b/components/envelope.templ index a2defeb..27ab13a 100644 --- a/components/envelope.templ +++ b/components/envelope.templ @@ -4,7 +4,7 @@ import ( "github.com/invopop/gobl" "github.com/invopop/gobl/bill" "github.com/invopop/gobl/note" - "github.com/invopop/gobl.html/components/billing/invoice" + "github.com/invopop/gobl.html/components/bill/invoice" "github.com/invopop/gobl.html/components/notes" ) diff --git a/components/envelope_templ.go b/components/envelope_templ.go index 38d12c4..ce683e6 100644 --- a/components/envelope_templ.go +++ b/components/envelope_templ.go @@ -12,7 +12,7 @@ import "bytes" import ( "github.com/invopop/gobl" - "github.com/invopop/gobl.html/components/billing/invoice" + "github.com/invopop/gobl.html/components/bill/invoice" "github.com/invopop/gobl.html/components/notes" "github.com/invopop/gobl/bill" "github.com/invopop/gobl/note" diff --git a/components/organizing/address.templ b/components/org/address.templ similarity index 95% rename from components/organizing/address.templ rename to components/org/address.templ index ea191b5..9860413 100644 --- a/components/organizing/address.templ +++ b/components/org/address.templ @@ -1,4 +1,4 @@ -package organizing +package org import ( "strings" @@ -48,6 +48,9 @@ func buildAddressLines(addr *org.Address) []string { if addr.Region != "" { lines = append(lines, addr.Region) } + if addr.Code != "" { + lines = append(lines, addr.Code) + } return lines } diff --git a/components/organizing/address_templ.go b/components/org/address_templ.go similarity index 98% rename from components/organizing/address_templ.go rename to components/org/address_templ.go index 79facc3..4dc82d9 100644 --- a/components/organizing/address_templ.go +++ b/components/org/address_templ.go @@ -1,7 +1,7 @@ // Code generated by templ - DO NOT EDIT. // templ: version: v0.2.590 -package organizing +package org //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -117,7 +117,7 @@ func addressLines(addr *org.Address) templ.Component { var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(buildAddressLines(addr), ", ")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/organizing/address.templ`, Line: 31, Col: 47} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/org/address.templ`, Line: 31, Col: 47} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { @@ -156,6 +156,9 @@ func buildAddressLines(addr *org.Address) []string { if addr.Region != "" { lines = append(lines, addr.Region) } + if addr.Code != "" { + lines = append(lines, addr.Code) + } return lines } diff --git a/components/organizing/party.templ b/components/org/party.templ similarity index 97% rename from components/organizing/party.templ rename to components/org/party.templ index 78598c1..c37660f 100644 --- a/components/organizing/party.templ +++ b/components/org/party.templ @@ -1,4 +1,4 @@ -package organizing +package org import ( "strings" @@ -16,6 +16,9 @@ templ Party(party *org.Party) {
    @t.Scope("organizing.party") {
    { party.Name }
    + if party.Alias != "" { +
    { party.Alias }
    + } for _, a := range party.Addresses { @AddressWithLabel(a) } diff --git a/components/organizing/party_templ.go b/components/org/party_templ.go similarity index 90% rename from components/organizing/party_templ.go rename to components/org/party_templ.go index 1584224..bb98a75 100644 --- a/components/organizing/party_templ.go +++ b/components/org/party_templ.go @@ -1,7 +1,7 @@ // Code generated by templ - DO NOT EDIT. // templ: version: v0.2.590 -package organizing +package org //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -52,7 +52,7 @@ func Party(party *org.Party) templ.Component { var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(party.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/organizing/party.templ`, Line: 17, Col: 33} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/org/party.templ`, Line: 17, Col: 33} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -62,13 +62,32 @@ func Party(party *org.Party) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } + if party.Alias != "" { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(party.Alias) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/org/party.templ`, Line: 19, Col: 36} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } for _, a := range party.Addresses { templ_7745c5c3_Err = AddressWithLabel(a).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -78,7 +97,7 @@ func Party(party *org.Party) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -88,7 +107,7 @@ func Party(party *org.Party) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 8) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -98,7 +117,7 @@ func Party(party *org.Party) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 9) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -106,7 +125,7 @@ func Party(party *org.Party) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 8) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 10) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -125,7 +144,7 @@ func Party(party *org.Party) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 9) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 11) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -144,12 +163,12 @@ func taxID(party *org.Party) templ.Component { defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var4 := templ.GetChildren(ctx) - if templ_7745c5c3_Var4 == nil { - templ_7745c5c3_Var4 = templ.NopComponent + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 10) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 12) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -157,7 +176,7 @@ func taxID(party *org.Party) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 11) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 13) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -176,13 +195,13 @@ func telephones(tels []*org.Telephone) templ.Component { defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var5 := templ.GetChildren(ctx) - if templ_7745c5c3_Var5 == nil { - templ_7745c5c3_Var5 = templ.NopComponent + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent } ctx = templ.ClearChildren(ctx) for _, tel := range tels { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 12) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 14) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -197,7 +216,7 @@ func telephones(tels []*org.Telephone) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 13) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 15) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -217,12 +236,12 @@ func emails(emails []*org.Email) templ.Component { defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var6 := templ.GetChildren(ctx) - if templ_7745c5c3_Var6 == nil { - templ_7745c5c3_Var6 = templ.NopComponent + templ_7745c5c3_Var7 := templ.GetChildren(ctx) + if templ_7745c5c3_Var7 == nil { + templ_7745c5c3_Var7 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 14) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 16) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -230,7 +249,7 @@ func emails(emails []*org.Email) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 15) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 17) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -249,13 +268,13 @@ func identities(idents []*org.Identity) templ.Component { defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var7 := templ.GetChildren(ctx) - if templ_7745c5c3_Var7 == nil { - templ_7745c5c3_Var7 = templ.NopComponent + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent } ctx = templ.ClearChildren(ctx) for _, ident := range idents { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 16) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 18) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -263,7 +282,7 @@ func identities(idents []*org.Identity) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 17) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 19) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -283,27 +302,27 @@ func partyExtensions(party *org.Party) templ.Component { defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var8 := templ.GetChildren(ctx) - if templ_7745c5c3_Var8 == nil { - templ_7745c5c3_Var8 = templ.NopComponent + templ_7745c5c3_Var9 := templ.GetChildren(ctx) + if templ_7745c5c3_Var9 == nil { + templ_7745c5c3_Var9 = templ.NopComponent } ctx = templ.ClearChildren(ctx) for k, v := range party.Ext { if txt := mapPartyExtension(ctx, k, v); txt != "" { - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 18) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 20) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var9 string - templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(txt) + var templ_7745c5c3_Var10 string + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(txt) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/organizing/party.templ`, Line: 74, Col: 9} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/org/party.templ`, Line: 77, Col: 9} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 19) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 21) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -354,6 +373,8 @@ func taxIDLabel(ctx context.Context, party *org.Party) string { return "NIT" case l10n.MX: return "RFC" + case l10n.FR: + return "TVA" default: return i18n.T(ctx, ".labels.default") } diff --git a/components/regimes/co/dian.templ b/components/regimes/co/dian.templ index 588199c..113f2b8 100644 --- a/components/regimes/co/dian.templ +++ b/components/regimes/co/dian.templ @@ -25,7 +25,6 @@ templ generateQR(inv *bill.Invoice, code, qr string) { - -
    + } func dianURL(qr string) string { diff --git a/components/regimes/es/ticketbai.templ b/components/regimes/es/ticketbai.templ index 4637d19..8cce362 100644 --- a/components/regimes/es/ticketbai.templ +++ b/components/regimes/es/ticketbai.templ @@ -35,16 +35,18 @@ templ generateTicketBAIQR(code, qr string) { height: 25mm; } -
    - + } func ticketbaiCode(env *gobl.Envelope) string { diff --git a/components/regimes/es/ticketbai_templ.go b/components/regimes/es/ticketbai_templ.go index cee480b..4e240ca 100644 --- a/components/regimes/es/ticketbai_templ.go +++ b/components/regimes/es/ticketbai_templ.go @@ -65,7 +65,7 @@ func generateTicketBAIQR(code, qr string) templ.Component { var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(code) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/es/ticketbai.templ`, Line: 39, Col: 9} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/es/ticketbai.templ`, Line: 40, Col: 10} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { diff --git a/components/regimes/mx/cfdi.templ b/components/regimes/mx/cfdi.templ new file mode 100644 index 0000000..3826ff6 --- /dev/null +++ b/components/regimes/mx/cfdi.templ @@ -0,0 +1,13 @@ +package mx + +import ( + "github.com/invopop/gobl" + "github.com/invopop/gobl/bill" +) + +templ CFDI(env *gobl.Envelope, inv *bill.Invoice) { + @complements(inv) + if hasSignatures(env) { + @signatures(env.Head) + } +} diff --git a/components/regimes/mx/cfdi_templ.go b/components/regimes/mx/cfdi_templ.go new file mode 100644 index 0000000..1cefbf6 --- /dev/null +++ b/components/regimes/mx/cfdi_templ.go @@ -0,0 +1,46 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.590 +package mx + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +import ( + "github.com/invopop/gobl" + "github.com/invopop/gobl/bill" +) + +func CFDI(env *gobl.Envelope, inv *bill.Invoice) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = complements(inv).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if hasSignatures(env) { + templ_7745c5c3_Err = signatures(env.Head).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/components/regimes/mx/complements.templ b/components/regimes/mx/complements.templ new file mode 100644 index 0000000..d164991 --- /dev/null +++ b/components/regimes/mx/complements.templ @@ -0,0 +1,287 @@ +package mx + +import ( + "fmt" + + "github.com/invopop/gobl/bill" + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/num" + "github.com/invopop/gobl/regimes/mx" + "github.com/invopop/gobl/tax" + "github.com/invopop/gobl.html/components/t" + "github.com/invopop/gobl/currency" +) + +templ complements(inv *bill.Invoice) { + for _, c := range inv.Complements { + switch obj := c.Instance().(type) { + case *mx.FoodVouchers: + @foodVouchers(obj) + case *mx.FuelAccountBalance: + @fuelAccountBalance(obj) + } + } +} + +templ foodVouchers(fv *mx.FoodVouchers) { + +
    +

    + Complemento de Vales de Despensa +

    + + + + + + + + + + + + + + + for i, line := range fv.Lines { + + + + + if line.Employee != nil { + + + + + } else { + + } + + + } + + + + + + + +
    #IDFechaRFCCURPNombreSeg. SocialImporte
    + { fmt.Sprint(i+1) } + + { line.EWalletID.String() } + + @t.L(line.IssueDateTime) + + { line.Employee.TaxCode.String() } + + { line.Employee.CURP.String() } + + { line.Employee.Name } + + { line.Employee.SocialSecurity.String() } + + + + @t.LM(line.Amount) +
    + Total: + + @t.LM(fv.Total) +
    +
    +} + +templ fuelAccountBalance(b *mx.FuelAccountBalance) { + + +} + +func fuelAccountTaxTotal(b *mx.FuelAccountBalance, code cbc.Code) num.Amount { + sum := currency.MXN.Def().Zero() + for _, line := range b.Lines { + if a := fuelAccountTax(line.Taxes, code); a != nil { + sum = sum.Add(*a) + } + } + return sum +} + +func fuelAccountTotal(line *mx.FuelAccountLine) num.Amount { + sum := line.Total + for _, t := range line.Taxes { + sum = sum.Add(t.Amount) + } + return sum +} + +func fuelAccountTax(taxes []*mx.FuelAccountTax, code cbc.Code) *num.Amount { + for _, row := range taxes { + if row.Category == code { + return &row.Amount + } + } + return nil +} diff --git a/components/regimes/mx/complements_templ.go b/components/regimes/mx/complements_templ.go new file mode 100644 index 0000000..7b7704c --- /dev/null +++ b/components/regimes/mx/complements_templ.go @@ -0,0 +1,456 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.590 +package mx + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +import ( + "fmt" + + "github.com/invopop/gobl.html/components/t" + "github.com/invopop/gobl/bill" + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/currency" + "github.com/invopop/gobl/num" + "github.com/invopop/gobl/regimes/mx" + "github.com/invopop/gobl/tax" +) + +func complements(inv *bill.Invoice) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + for _, c := range inv.Complements { + switch obj := c.Instance().(type) { + case *mx.FoodVouchers: + templ_7745c5c3_Err = foodVouchers(obj).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + case *mx.FuelAccountBalance: + templ_7745c5c3_Err = fuelAccountBalance(obj).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func foodVouchers(fv *mx.FoodVouchers) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for i, line := range fv.Lines { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprint(i + 1)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 81, Col: 24} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(line.EWalletID.String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 84, Col: 32} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.L(line.IssueDateTime).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if line.Employee != nil { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(line.Employee.TaxCode.String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 91, Col: 40} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(line.Employee.CURP.String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 94, Col: 37} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 8) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(line.Employee.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 97, Col: 28} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 9) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(line.Employee.SocialSecurity.String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 100, Col: 47} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 10) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 11) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 12) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.LM(line.Amount).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 13) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 14) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.LM(fv.Total).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 15) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func fuelAccountBalance(b *mx.FuelAccountBalance) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var9 := templ.GetChildren(ctx) + if templ_7745c5c3_Var9 == nil { + templ_7745c5c3_Var9 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 16) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, line := range b.Lines { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 17) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var10 string + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(line.EWalletID.String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 187, Col: 32} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 18) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.L(line.PurchaseDateTime).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 19) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var11 string + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(line.VendorTaxCode.String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 193, Col: 36} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 20) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var12 string + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(line.ServiceStationCode.String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 196, Col: 41} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 21) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var13 string + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(line.PurchaseCode.String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 199, Col: 35} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 22) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.L(line.Quantity).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 23) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if line.Item != nil { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 24) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.LM(line.Item.Price).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if u := string(line.Item.Unit); u != "" { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 25) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var14 string + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(string(line.Item.Unit)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 208, Col: 34} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 26) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var15 string + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(line.Item.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/complements.templ`, Line: 212, Col: 24} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 27) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 28) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 29) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.LM(line.Total).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 30) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if a := fuelAccountTax(line.Taxes, tax.CategoryVAT); a != nil { + templ_7745c5c3_Err = t.LM(*a).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 31) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if a := fuelAccountTax(line.Taxes, mx.TaxCategoryIEPS); a != nil { + templ_7745c5c3_Err = t.LM(*a).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 32) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.LM(fuelAccountTotal(line)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 33) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 34) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.LM(b.Subtotal).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 35) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.LM(fuelAccountTaxTotal(b, tax.CategoryVAT)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 36) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.LM(fuelAccountTaxTotal(b, mx.TaxCategoryIEPS)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 37) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = t.LM(b.Total).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 38) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func fuelAccountTaxTotal(b *mx.FuelAccountBalance, code cbc.Code) num.Amount { + sum := currency.MXN.Def().Zero() + for _, line := range b.Lines { + if a := fuelAccountTax(line.Taxes, code); a != nil { + sum = sum.Add(*a) + } + } + return sum +} + +func fuelAccountTotal(line *mx.FuelAccountLine) num.Amount { + sum := line.Total + for _, t := range line.Taxes { + sum = sum.Add(t.Amount) + } + return sum +} + +func fuelAccountTax(taxes []*mx.FuelAccountTax, code cbc.Code) *num.Amount { + for _, row := range taxes { + if row.Category == code { + return &row.Amount + } + } + return nil +} diff --git a/components/regimes/mx/line.templ b/components/regimes/mx/line.templ new file mode 100644 index 0000000..844ba99 --- /dev/null +++ b/components/regimes/mx/line.templ @@ -0,0 +1,18 @@ +package mx + +import ( + "github.com/invopop/gobl/bill" + "github.com/invopop/gobl/regimes/mx" +) + +// LineExtensions will add extra information to the line for Mexico. +templ LineExtensions(line *bill.Line) { + if line.Item.Ext.Has(mx.ExtKeyCFDIProdServ) { + + Clave SAT: + + { line.Item.Ext[mx.ExtKeyCFDIProdServ].String() } + + + } +} diff --git a/components/regimes/mx/line_templ.go b/components/regimes/mx/line_templ.go new file mode 100644 index 0000000..0019066 --- /dev/null +++ b/components/regimes/mx/line_templ.go @@ -0,0 +1,56 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.590 +package mx + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +import ( + "github.com/invopop/gobl/bill" + "github.com/invopop/gobl/regimes/mx" +) + +// LineExtensions will add extra information to the line for Mexico. +func LineExtensions(line *bill.Line) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + if line.Item.Ext.Has(mx.ExtKeyCFDIProdServ) { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(line.Item.Ext[mx.ExtKeyCFDIProdServ].String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/line.templ`, Line: 13, Col: 51} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/components/regimes/mx/mx.go b/components/regimes/mx/mx.go new file mode 100644 index 0000000..22bab8e --- /dev/null +++ b/components/regimes/mx/mx.go @@ -0,0 +1,3 @@ +// Package mx provides additional templates and helper methods +// for the Mexican tax regime. +package mx diff --git a/components/regimes/mx/signatures.templ b/components/regimes/mx/signatures.templ new file mode 100644 index 0000000..3a7a89d --- /dev/null +++ b/components/regimes/mx/signatures.templ @@ -0,0 +1,105 @@ +package mx + +import ( + "github.com/invopop/gobl" + "github.com/invopop/gobl/head" + "github.com/invopop/gobl/regimes/mx" + "github.com/invopop/gobl.html/components/images" +) + +templ signatures(h *head.Header) { + +
    + if qr := satURL(h); qr != "" { + + } +
    + if st := h.GetStamp(mx.StampSATUUID); st != nil { +
    + Folio Fiscal: + { st.Value } +
    + } + if st := h.GetStamp(mx.StampSATTimestamp); st != nil { +
    + Fecha y hora de certificación: + { st.Value } +
    + } + if st := h.GetStamp(mx.StampCFDISignature); st != nil { +
    + Sello digital del CFDI + if st := h.GetStamp(mx.StampCFDISerial); st != nil { + Serie: { st.Value } + } + { st.Value } +
    + } + if st := h.GetStamp(mx.StampSATSignature); st != nil { +
    + Sello digital del SAT + if st := h.GetStamp(mx.StampSATSerial); st != nil { + Serie: { st.Value } + } + { st.Value } +
    + } + if st := h.GetStamp(mx.StampSATChain); st != nil { +
    + Cadena Original del complemento de certificación digital del SAT + { st.Value } +
    + } +
    + Este documento es una represetnación impresa de un CFDI. +
    +
    +
    +} + +func satURL(h *head.Header) string { + st := h.GetStamp(mx.StampSATURL) + if st == nil { + return "" + } + return st.Value +} + +func hasSignatures(env *gobl.Envelope) bool { + return env.Head.GetStamp(mx.StampSATChain) != nil +} diff --git a/components/regimes/mx/signatures_templ.go b/components/regimes/mx/signatures_templ.go new file mode 100644 index 0000000..97a611d --- /dev/null +++ b/components/regimes/mx/signatures_templ.go @@ -0,0 +1,226 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.590 +package mx + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +import ( + "github.com/invopop/gobl" + "github.com/invopop/gobl.html/components/images" + "github.com/invopop/gobl/head" + "github.com/invopop/gobl/regimes/mx" +) + +func signatures(h *head.Header) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 1) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if qr := satURL(h); qr != "" { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 2) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 templ.SafeURL = templ.URL(qr) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var2))) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 3) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = images.QR(qr).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 4) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 5) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if st := h.GetStamp(mx.StampSATUUID); st != nil { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 6) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(st.Value) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/signatures.templ`, Line: 54, Col: 35} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 7) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if st := h.GetStamp(mx.StampSATTimestamp); st != nil { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 8) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(st.Value) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/signatures.templ`, Line: 60, Col: 35} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 9) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if st := h.GetStamp(mx.StampCFDISignature); st != nil { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 10) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if st := h.GetStamp(mx.StampCFDISerial); st != nil { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 11) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(st.Value) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/signatures.templ`, Line: 67, Col: 64} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 12) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 13) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(st.Value) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/signatures.templ`, Line: 69, Col: 39} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 14) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if st := h.GetStamp(mx.StampSATSignature); st != nil { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 15) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if st := h.GetStamp(mx.StampSATSerial); st != nil { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 16) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(st.Value) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/signatures.templ`, Line: 76, Col: 64} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 17) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 18) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(st.Value) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/signatures.templ`, Line: 78, Col: 39} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 19) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if st := h.GetStamp(mx.StampSATChain); st != nil { + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 20) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var9 string + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(st.Value) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/regimes/mx/signatures.templ`, Line: 84, Col: 39} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 21) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ.WriteWatchModeString(templ_7745c5c3_Buffer, 22) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func satURL(h *head.Header) string { + st := h.GetStamp(mx.StampSATURL) + if st == nil { + return "" + } + return st.Value +} + +func hasSignatures(env *gobl.Envelope) bool { + return env.Head.GetStamp(mx.StampSATChain) != nil +} diff --git a/components/t/i18n.templ b/components/t/i18n.templ index 1395521..c323019 100644 --- a/components/t/i18n.templ +++ b/components/t/i18n.templ @@ -17,8 +17,8 @@ templ N(key string, n int, args ...any) { { i18n.N(ctx, key, n, args...) } } -// L localizes a GOBL num.Amount or num.Percentage according to the rules -// defined in the context. +// L localizes a GOBL num.Amount, num.Percentage, cal.DateTime, or cal.Date according +// to the rules defined in the context. templ L(a any) { { localize(ctx, a) } } @@ -42,21 +42,26 @@ templ Scope(key string) { } func localize(ctx context.Context, a any) string { - f := GetFormatter(ctx).WithoutUnit() switch v := a.(type) { case num.Amount: - return f.Amount(v) + nf := numFormatter(ctx).WithoutUnit() + return nf.Amount(v) case num.Percentage: - return f.Percentage(v) + nf := numFormatter(ctx).WithoutUnit() + return nf.Percentage(v) + case cal.DateTime: + cf := calFormatter(ctx) + return v.In(cf.Location).Format(cf.DateTime) case cal.Date: - return v.String() + cf := calFormatter(ctx) + return v.Time().Format(cf.Date) default: return "!(UNKOWN TYPE)" } } func localizeMoney(ctx context.Context, a num.Amount) string { - f := GetFormatter(ctx) + f := numFormatter(ctx) return f.Amount(a) } diff --git a/components/t/i18n_templ.go b/components/t/i18n_templ.go index 52997c5..658c59e 100644 --- a/components/t/i18n_templ.go +++ b/components/t/i18n_templ.go @@ -77,8 +77,8 @@ func N(key string, n int, args ...any) templ.Component { }) } -// L localizes a GOBL num.Amount or num.Percentage according to the rules -// defined in the context. +// L localizes a GOBL num.Amount, num.Percentage, cal.DateTime, or cal.Date according +// to the rules defined in the context. func L(a any) templ.Component { return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) @@ -197,21 +197,26 @@ func Scope(key string) templ.Component { } func localize(ctx context.Context, a any) string { - f := GetFormatter(ctx).WithoutUnit() switch v := a.(type) { case num.Amount: - return f.Amount(v) + nf := numFormatter(ctx).WithoutUnit() + return nf.Amount(v) case num.Percentage: - return f.Percentage(v) + nf := numFormatter(ctx).WithoutUnit() + return nf.Percentage(v) + case cal.DateTime: + cf := calFormatter(ctx) + return v.In(cf.Location).Format(cf.DateTime) case cal.Date: - return v.String() + cf := calFormatter(ctx) + return v.Time().Format(cf.Date) default: return "!(UNKOWN TYPE)" } } func localizeMoney(ctx context.Context, a num.Amount) string { - f := GetFormatter(ctx) + f := numFormatter(ctx) return f.Amount(a) } diff --git a/components/t/t.go b/components/t/t.go index a7de9db..e08413e 100644 --- a/components/t/t.go +++ b/components/t/t.go @@ -3,27 +3,68 @@ package t import ( "context" + "time" + "github.com/invopop/ctxi18n/i18n" + gi18n "github.com/invopop/gobl/i18n" "github.com/invopop/gobl/num" ) type formatterKey string const ( - formatterCTXKey formatterKey = "formatter" + numFormatterCTXKey formatterKey = "num" + calFormatterCTXKey formatterKey = "cal" ) -// WithFormatter prepares the context with a formatter to use +// CalFormatter defines a simple date and datetime formatter +type CalFormatter struct { + Date string // Golang date format for dates, e.g. `02/01/2006` + Location *time.Location + DateTime string // Date-time format +} + +// CalFormatterISO is the default formatter for dates and times based on +// the recommended ISO 8601 formatting. +var CalFormatterISO = CalFormatter{ + Date: "2006-01-02", + DateTime: "2006-01-02 15:04", + Location: time.UTC, +} + +// WithNumFormatter prepares the context with a formatter to use // later. The formatter should be prepared according to the currency // defined in the document. -func WithFormatter(ctx context.Context, f num.Formatter) context.Context { - return context.WithValue(ctx, formatterCTXKey, f) +func WithNumFormatter(ctx context.Context, f num.Formatter) context.Context { + return context.WithValue(ctx, numFormatterCTXKey, f) } -// GetFormatter returns the formatter currently in the context. -func GetFormatter(ctx context.Context) num.Formatter { - if f, ok := ctx.Value(formatterCTXKey).(num.Formatter); ok { +// WithCalFormatter prepares a simple date and datetime formatter for +// use with the localization functions. +func WithCalFormatter(ctx context.Context, f CalFormatter) context.Context { + return context.WithValue(ctx, calFormatterCTXKey, f) +} + +// numFormatter returns the formatter currently in the context. +func numFormatter(ctx context.Context) num.Formatter { + if f, ok := ctx.Value(numFormatterCTXKey).(num.Formatter); ok { return f } return num.MakeFormatter(".", ",") } + +func calFormatter(ctx context.Context) CalFormatter { + if f, ok := ctx.Value(calFormatterCTXKey).(CalFormatter); ok { + return f + } + return CalFormatterISO +} + +// Lang provides the current locale code from the context. +func Lang(ctx context.Context) gi18n.Lang { + l := i18n.GetLocale(ctx) + if l != nil { + return gi18n.Lang(l.Code().String()) + } + return gi18n.EN // fallback to english +} diff --git a/examples/invoice-limited-company.json b/examples/invoice-limited-company.json index cf6e699..7fbdf22 100644 --- a/examples/invoice-limited-company.json +++ b/examples/invoice-limited-company.json @@ -13,9 +13,6 @@ "code": "FAKE20220001", "issue_date": "2022-02-01", "currency": "EUR", - "tax": { - "prices_include": "VAT" - }, "supplier": { "name": "Biz España S.L.", "tax_id": { diff --git a/examples/invoice-mx.json b/examples/invoice-mx.json new file mode 100644 index 0000000..34deea4 --- /dev/null +++ b/examples/invoice-mx.json @@ -0,0 +1,208 @@ +{ + "$schema": "https://gobl.org/draft-0/envelope", + "head": { + "uuid": "66c60bf0-0310-11ef-b734-ffb5249031a5", + "dig": { + "alg": "sha256", + "val": "af841193c49d68b81bde32cbb74361c5a36d4a586f6e26b57c455c3ba899eb3a" + }, + "stamps": [ + { + "prv": "sat-uuid", + "val": "187501fc-3e99-4034-bcb1-7429ee841bb1" + }, + { + "prv": "cfdi-sig", + "val": "eMreWl4lUV+D3r1bQnQf4oOAlpJIDBHf5f4vwE/JsrE8orTIeJnaMWmh8nGWRHRXMnsrGpbPmYWpUL2yym2YEWz8by+BWt2B5wKkKWuwt3mhdxeyhUPY22x7AtIF9GFmfvRX5rpQkmhKCxojjkxsv+3JoW1ppN2Db88ZgJIV1UxcHguObSQ01mw9zhaRx4Uoxhri9wPHxRvbQX7jSuFhSs6uiOyH4z5L+MB9WgrilJQOInHXFIIisnRQ99U5O+UMZoJrXWS16iFgo2ccOCteS61whEOZIgNAZYJ/CkKQeDLuZDcCFihMX9tPYL/3nLiaqDFSS9fvrbjhLdp1+hv+oQ==" + }, + { + "prv": "cfdi-serial", + "val": "30001000000500003416" + }, + { + "prv": "sat-sig", + "val": "YrFWG5lHOTvdrPjlL2AG6SDu0CSkd3lst3NR6ROCsRqTX3j6jVr7hBOyJXev5JkeWbEuLgGmVv+pNuHRoeaoQaQsfFaYM39Zfar5ow/iGIcLfOrUei60l7aicsK2Yx87IWY8CNr5ZZmlQ8Nr/HWp6I7CThWx+6H14+qnSX7PYIK/gkSWr5ZoOVUZvkukZoOgSzaah0DFNa4w6s6RjXjwCwkWavdf4QFg/VSZzs6RquJkFgkVBo1hDyXIlKRpGa03674RujuKtTAsoSZBPDERDj0Lc1hqh11cK0Hlm2TVLHA63P4zwKDvA3XLRUEXr6upbwDv3CxiDL0JXRurmkowEg==" + }, + { + "prv": "sat-serial", + "val": "30001000000500003456" + }, + { + "prv": "sat-timestamp", + "val": "2024-04-25T09:19:41" + }, + { + "prv": "sat-chain", + "val": "||1.1|187501fc-3e99-4034-bcb1-7429ee841bb1|2024-04-25T09:19:41|SPR190613I52|eMreWl4lUV+D3r1bQnQf4oOAlpJIDBHf5f4vwE/JsrE8orTIeJnaMWmh8nGWRHRXMnsrGpbPmYWpUL2yym2YEWz8by+BWt2B5wKkKWuwt3mhdxeyhUPY22x7AtIF9GFmfvRX5rpQkmhKCxojjkxsv+3JoW1ppN2Db88ZgJIV1UxcHguObSQ01mw9zhaRx4Uoxhri9wPHxRvbQX7jSuFhSs6uiOyH4z5L+MB9WgrilJQOInHXFIIisnRQ99U5O+UMZoJrXWS16iFgo2ccOCteS61whEOZIgNAZYJ/CkKQeDLuZDcCFihMX9tPYL/3nLiaqDFSS9fvrbjhLdp1+hv+oQ==|30001000000500003456||" + }, + { + "prv": "sat-url", + "val": "https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?fe=mkowEg%3D%3D&id=187501fc-3e99-4034-bcb1-7429ee841bb1&re=EKU9003173C9&rr=EKU9003173C9&tt=201.36" + } + ] + }, + "doc": { + "$schema": "https://gobl.org/draft-0/bill/invoice", + "uuid": "018f15aa-7b12-742a-8526-4ca463c4bb7e", + "type": "standard", + "series": "LMC", + "code": "0010", + "issue_date": "2024-04-25", + "currency": "MXN", + "tax": { + "ext": { + "mx-cfdi-issue-place": "26015" + } + }, + "supplier": { + "name": "ESCUELA KEMPER URGATE", + "tax_id": { + "country": "MX", + "code": "EKU9003173C9" + }, + "ext": { + "mx-cfdi-fiscal-regime": "601" + } + }, + "customer": { + "name": "UNIVERSIDAD ROBOTICA ESPAÑOLA", + "tax_id": { + "country": "MX", + "code": "URE180429TM6" + }, + "ext": { + "mx-cfdi-fiscal-regime": "601", + "mx-cfdi-post-code": "86991", + "mx-cfdi-use": "G01" + } + }, + "lines": [ + { + "i": 1, + "quantity": "2", + "item": { + "name": "Cigarros", + "price": "200.2020", + "unit": "piece", + "ext": { + "mx-cfdi-prod-serv": "50211502" + } + }, + "sum": "400.4040", + "discounts": [ + { + "percent": "25.0%", + "amount": "100.1010" + } + ], + "taxes": [ + { + "cat": "VAT", + "rate": "standard", + "percent": "16.0%" + }, + { + "cat": "RVAT", + "percent": "10.6667%" + }, + { + "cat": "ISR", + "percent": "10%" + } + ], + "total": "200.2020" + }, + { + "i": 2, + "quantity": "1", + "item": { + "name": "Cerveza", + "price": "10.50", + "unit": "piece", + "ext": { + "mx-cfdi-prod-serv": "50211502" + } + }, + "sum": "10.50", + "taxes": [ + { + "cat": "VAT", + "rate": "exempt" + } + ], + "total": "10.50" + } + ], + "payment": { + "terms": { + "notes": "Pago a 30 días." + }, + "advances": [ + { + "key": "credit-transfer", + "description": "Top-up payment", + "percent": "100%", + "amount": "201.36" + } + ] + }, + "totals": { + "sum": "210.70", + "total": "210.70", + "taxes": { + "categories": [ + { + "code": "VAT", + "rates": [ + { + "key": "standard", + "base": "200.20", + "percent": "16.0%", + "amount": "32.03" + }, + { + "key": "exempt", + "base": "10.50", + "amount": "0.00" + } + ], + "amount": "32.03" + }, + { + "code": "RVAT", + "retained": true, + "rates": [ + { + "base": "200.20", + "percent": "10.6667%", + "amount": "21.35" + } + ], + "amount": "21.35" + }, + { + "code": "ISR", + "retained": true, + "rates": [ + { + "base": "200.20", + "percent": "10%", + "amount": "20.02" + } + ], + "amount": "20.02" + } + ], + "sum": "-9.34" + }, + "tax": "-9.34", + "total_with_tax": "201.36", + "payable": "201.36", + "advance": "201.36", + "due": "0.00" + } + }, + "sigs": [ + "eyJhbGciOiJFUzI1NiIsImtpZCI6ImRmNTBiNjkzLWUxODMtNDQxZS1iODk2LWM3MmFkZTczZjNiMSJ9.eyJ1dWlkIjoiNjZjNjBiZjAtMDMxMC0xMWVmLWI3MzQtZmZiNTI0OTAzMWE1IiwiZGlnIjp7ImFsZyI6InNoYTI1NiIsInZhbCI6ImFmODQxMTkzYzQ5ZDY4YjgxYmRlMzJjYmI3NDM2MWM1YTM2ZDRhNTg2ZjZlMjZiNTdjNDU1YzNiYTg5OWViM2EifSwic3RhbXBzIjpbeyJwcnYiOiJzYXQtdXVpZCIsInZhbCI6IjE4NzUwMWZjLTNlOTktNDAzNC1iY2IxLTc0MjllZTg0MWJiMSJ9LHsicHJ2IjoiY2ZkaS1zaWciLCJ2YWwiOiJlTXJlV2w0bFVWK0QzcjFiUW5RZjRvT0FscEpJREJIZjVmNHZ3RS9Kc3JFOG9yVEllSm5hTVdtaDhuR1dSSFJYTW5zckdwYlBtWVdwVUwyeXltMllFV3o4YnkrQld0MkI1d0trS1d1d3QzbWhkeGV5aFVQWTIyeDdBdElGOUdGbWZ2Ulg1cnBRa21oS0N4b2pqa3hzdiszSm9XMXBwTjJEYjg4WmdKSVYxVXhjSGd1T2JTUTAxbXc5emhhUng0VW94aHJpOXdQSHhSdmJRWDdqU3VGaFNzNnVpT3lINHo1TCtNQjlXZ3JpbEpRT0luSFhGSUlpc25SUTk5VTVPK1VNWm9KclhXUzE2aUZnbzJjY09DdGVTNjF3aEVPWklnTkFaWUovQ2tLUWVETHVaRGNDRmloTVg5dFBZTC8zbkxpYXFERlNTOWZ2cmJqaExkcDEraHYrb1E9PSJ9LHsicHJ2IjoiY2ZkaS1zZXJpYWwiLCJ2YWwiOiIzMDAwMTAwMDAwMDUwMDAwMzQxNiJ9LHsicHJ2Ijoic2F0LXNpZyIsInZhbCI6IllyRldHNWxIT1R2ZHJQamxMMkFHNlNEdTBDU2tkM2xzdDNOUjZST0NzUnFUWDNqNmpWcjdoQk95SlhldjVKa2VXYkV1TGdHbVZ2K3BOdUhSb2Vhb1FhUXNmRmFZTTM5WmZhcjVvdy9pR0ljTGZPclVlaTYwbDdhaWNzSzJZeDg3SVdZOENOcjVaWm1sUThOci9IV3A2STdDVGhXeCs2SDE0K3FuU1g3UFlJSy9na1NXcjVab09WVVp2a3VrWm9PZ1N6YWFoMERGTmE0dzZzNlJqWGp3Q3drV2F2ZGY0UUZnL1ZTWnpzNlJxdUprRmdrVkJvMWhEeVhJbEtScEdhMDM2NzRSdWp1S3RUQXNvU1pCUERFUkRqMExjMWhxaDExY0swSGxtMlRWTEhBNjNQNHp3S0R2QTNYTFJVRVhyNnVwYndEdjNDeGlETDBKWFJ1cm1rb3dFZz09In0seyJwcnYiOiJzYXQtc2VyaWFsIiwidmFsIjoiMzAwMDEwMDAwMDA1MDAwMDM0NTYifSx7InBydiI6InNhdC10aW1lc3RhbXAiLCJ2YWwiOiIyMDI0LTA0LTI1VDA5OjE5OjQxIn0seyJwcnYiOiJzYXQtY2hhaW4iLCJ2YWwiOiJ8fDEuMXwxODc1MDFmYy0zZTk5LTQwMzQtYmNiMS03NDI5ZWU4NDFiYjF8MjAyNC0wNC0yNVQwOToxOTo0MXxTUFIxOTA2MTNJNTJ8ZU1yZVdsNGxVVitEM3IxYlFuUWY0b09BbHBKSURCSGY1ZjR2d0UvSnNyRThvclRJZUpuYU1XbWg4bkdXUkhSWE1uc3JHcGJQbVlXcFVMMnl5bTJZRVd6OGJ5K0JXdDJCNXdLa0tXdXd0M21oZHhleWhVUFkyMng3QXRJRjlHRm1mdlJYNXJwUWttaEtDeG9qamt4c3YrM0pvVzFwcE4yRGI4OFpnSklWMVV4Y0hndU9iU1EwMW13OXpoYVJ4NFVveGhyaTl3UEh4UnZiUVg3alN1RmhTczZ1aU95SDR6NUwrTUI5V2dyaWxKUU9JbkhYRklJaXNuUlE5OVU1TytVTVpvSnJYV1MxNmlGZ28yY2NPQ3RlUzYxd2hFT1pJZ05BWllKL0NrS1FlREx1WkRjQ0ZpaE1YOXRQWUwvM25MaWFxREZTUzlmdnJiamhMZHAxK2h2K29RPT18MzAwMDEwMDAwMDA1MDAwMDM0NTZ8fCJ9LHsicHJ2Ijoic2F0LXVybCIsInZhbCI6Imh0dHBzOi8vdmVyaWZpY2FjZmRpLmZhY3R1cmFlbGVjdHJvbmljYS5zYXQuZ29iLm14L2RlZmF1bHQuYXNweD9mZT1ta293RWclM0QlM0RcdTAwMjZpZD0xODc1MDFmYy0zZTk5LTQwMzQtYmNiMS03NDI5ZWU4NDFiYjFcdTAwMjZyZT1FS1U5MDAzMTczQzlcdTAwMjZycj1FS1U5MDAzMTczQzlcdTAwMjZ0dD0yMDEuMzYifV19.wq88xyl_XoxwAqxqp3xz4-T-XmPE-ye2eTJ_lC7nWcsE2iRXfMFTMNJwiijag-vjDSOFsToVlZonW1BnBOu_RA" + ] +} diff --git a/examples/mx-food-voucher.json b/examples/mx-food-voucher.json new file mode 100644 index 0000000..8c69fd0 --- /dev/null +++ b/examples/mx-food-voucher.json @@ -0,0 +1,177 @@ +{ + "$schema": "https://gobl.org/draft-0/envelope", + "head": { + "uuid": "c82905b0-061b-11ef-9fc5-12007b149b55", + "dig": { + "alg": "sha256", + "val": "9c6271f3ece643f1b5ee74edb9d044d72e01402a39c5d85216aeca59d9d15f0e" + }, + "stamps": [ + { + "prv": "sat-uuid", + "val": "b7ed8978-f0d7-48c5-b547-daf9ac54aa4a" + }, + { + "prv": "cfdi-sig", + "val": "Qk+hftgbpSYMqcc7BoBzGOctcNbDypP4IiHfzgf4mJuraxGEFbo8JEfS6BOzfqXojVLbRxPkXE83fqzWdnowOhOmi0Mvk3CdlTZNZ9i2i7hJv6cwfHXMTPpeOxfptuv2AzhFX7O14gS2szeai5yJIcT+d8/W6H0zN6b/2S12GkMdik0tyF8XRtQQat4Q1jxQzslOp46brROc0Xuobc7/jogq2ib7oaJEu7qDKhjYAkH7BHMaLMJgeC6eVeHUkkrr7RVTkH75H4wteKZNuP85E/F12nCkbMSQq7uplzRuLyO6YEkyIWxpT+0Gqtcb6pziYk8wqwP1pVsVZZ4Q0PPOsw==" + }, + { + "prv": "cfdi-serial", + "val": "30001000000500003416" + }, + { + "prv": "sat-sig", + "val": "MQWzFEvDEWag8sM8OWjlCS1DmrZWe+/1VtGsxDz8ycSH1yh8aoUGV3lKezQy190TnB2mncusGvFoUpbDhrk0tlRpTGT2+68/43yb0RZ+yWTVCrd09sCzRk/Dct+oyUKWr2AYYxA0Jt7ECyR4DQfPQYbPF4shsmcerMWxsbMUKqR43shvsb5QTxk/yA6CiWx3z/+uSxvJitUoUihAtFeBBdiNnKVBcG7ifWNJaoaBL03UOm1Ro77rGvUfYuxqqI02Fav98iv9eS//YmGzUTpz0Uvc9Lut+MRqkBvs3G/PBiJvO5Yi6I2PhzNo0O7z9SD6P9WnmufmVI9JFCbHVk+PNg==" + }, + { + "prv": "sat-serial", + "val": "30001000000500003456" + }, + { + "prv": "sat-timestamp", + "val": "2024-04-29T07:16:10" + }, + { + "prv": "sat-chain", + "val": "||1.1|b7ed8978-f0d7-48c5-b547-daf9ac54aa4a|2024-04-29T07:16:10|SPR190613I52|Qk+hftgbpSYMqcc7BoBzGOctcNbDypP4IiHfzgf4mJuraxGEFbo8JEfS6BOzfqXojVLbRxPkXE83fqzWdnowOhOmi0Mvk3CdlTZNZ9i2i7hJv6cwfHXMTPpeOxfptuv2AzhFX7O14gS2szeai5yJIcT+d8/W6H0zN6b/2S12GkMdik0tyF8XRtQQat4Q1jxQzslOp46brROc0Xuobc7/jogq2ib7oaJEu7qDKhjYAkH7BHMaLMJgeC6eVeHUkkrr7RVTkH75H4wteKZNuP85E/F12nCkbMSQq7uplzRuLyO6YEkyIWxpT+0Gqtcb6pziYk8wqwP1pVsVZZ4Q0PPOsw==|30001000000500003456||" + }, + { + "prv": "sat-url", + "val": "https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?id=b7ed8978-f0d7-48c5-b547-daf9ac54aa4a&tt=0.01&re=EKU9003173C9&rr=EKU9003173C9&fe=Vk+PNg==" + } + ] + }, + "doc": { + "$schema": "https://gobl.org/draft-0/bill/invoice", + "uuid": "018f299e-3a8c-7c07-a3a1-8f57909de0e0", + "type": "standard", + "series": "IN2024", + "code": "0001", + "issue_date": "2024-04-29", + "currency": "MXN", + "tax": { + "ext": { + "mx-cfdi-issue-place": "26015" + } + }, + "supplier": { + "name": "ESCUELA KEMPER URGATE", + "tax_id": { + "country": "MX", + "code": "EKU9003173C9" + }, + "ext": { + "mx-cfdi-fiscal-regime": "601", + "mx-cfdi-post-code": "26015" + } + }, + "customer": { + "name": "UNIVERSIDAD ROBOTICA ESPAÑOLA", + "tax_id": { + "country": "MX", + "code": "URE180429TM6" + }, + "ext": { + "mx-cfdi-fiscal-regime": "601", + "mx-cfdi-post-code": "86991", + "mx-cfdi-use": "G01" + } + }, + "lines": [ + { + "i": 1, + "quantity": "1", + "item": { + "name": "Dispersión de Despensa", + "price": "0.02", + "unit": "E48", + "ext": { + "mx-cfdi-prod-serv": "84141602" + } + }, + "sum": "0.02", + "discounts": [ + { + "amount": "0.01" + } + ], + "taxes": [ + { + "cat": "VAT", + "rate": "exempt" + } + ], + "total": "0.01" + } + ], + "payment": { + "advances": [ + { + "key": "credit-transfer", + "description": "Transferencia electrónica de fondos", + "amount": "0.00" + } + ] + }, + "totals": { + "sum": "0.01", + "total": "0.01", + "taxes": { + "categories": [ + { + "code": "VAT", + "rates": [ + { + "key": "exempt", + "base": "0.01", + "amount": "0.00" + } + ], + "amount": "0.00" + } + ], + "sum": "0.00" + }, + "tax": "0.00", + "total_with_tax": "0.01", + "payable": "0.01", + "advance": "0.00", + "due": "0.01" + }, + "complements": [ + { + "$schema": "https://gobl.org/draft-0/regimes/mx/food-vouchers", + "employer_registration": "nan", + "account_number": "N.A.", + "total": "200.00", + "lines": [ + { + "e_wallet_id": "ABC1234", + "issue_date_time": "2022-07-19T10:20:30", + "employee": { + "tax_code": "JUFA7608212V6", + "curp": "JUFA760821MDFRRR00", + "name": "Adriana Juarez Fernández", + "social_security": "12345678901" + }, + "amount": "100.00" + }, + { + "e_wallet_id": "BCD4321", + "issue_date_time": "2022-08-20T11:20:30", + "employee": { + "tax_code": "KAHO641101B39", + "curp": "KAHO641101HDFRRR00", + "name": "Oscar Kala Haak", + "social_security": "12345678905" + }, + "amount": "100.00" + } + ] + } + ] + }, + "sigs": [ + "eyJhbGciOiJFUzI1NiIsImtpZCI6IjQ4ZDFiNjRlLWY0ZmMtNDQ3NC1iZWJhLWYxZDA4YTdmZjcwMSJ9.eyJ1dWlkIjoiYzgyOTA1YjAtMDYxYi0xMWVmLTlmYzUtMTIwMDdiMTQ5YjU1IiwiZGlnIjp7ImFsZyI6InNoYTI1NiIsInZhbCI6IjljNjI3MWYzZWNlNjQzZjFiNWVlNzRlZGI5ZDA0NGQ3MmUwMTQwMmEzOWM1ZDg1MjE2YWVjYTU5ZDlkMTVmMGUifSwic3RhbXBzIjpbeyJwcnYiOiJzYXQtdXVpZCIsInZhbCI6ImI3ZWQ4OTc4LWYwZDctNDhjNS1iNTQ3LWRhZjlhYzU0YWE0YSJ9LHsicHJ2IjoiY2ZkaS1zaWciLCJ2YWwiOiJRaytoZnRnYnBTWU1xY2M3Qm9CekdPY3RjTmJEeXBQNElpSGZ6Z2Y0bUp1cmF4R0VGYm84SkVmUzZCT3pmcVhvalZMYlJ4UGtYRTgzZnF6V2Rub3dPaE9taTBNdmszQ2RsVFpOWjlpMmk3aEp2NmN3ZkhYTVRQcGVPeGZwdHV2MkF6aEZYN08xNGdTMnN6ZWFpNXlKSWNUK2Q4L1c2SDB6TjZiLzJTMTJHa01kaWswdHlGOFhSdFFRYXQ0UTFqeFF6c2xPcDQ2YnJST2MwWHVvYmM3L2pvZ3EyaWI3b2FKRXU3cURLaGpZQWtIN0JITWFMTUpnZUM2ZVZlSFVra3JyN1JWVGtINzVINHd0ZUtaTnVQODVFL0YxMm5Da2JNU1FxN3VwbHpSdUx5TzZZRWt5SVd4cFQrMEdxdGNiNnB6aVlrOHdxd1AxcFZzVlpaNFEwUFBPc3c9PSJ9LHsicHJ2IjoiY2ZkaS1zZXJpYWwiLCJ2YWwiOiIzMDAwMTAwMDAwMDUwMDAwMzQxNiJ9LHsicHJ2Ijoic2F0LXNpZyIsInZhbCI6Ik1RV3pGRXZERVdhZzhzTThPV2psQ1MxRG1yWldlKy8xVnRHc3hEejh5Y1NIMXloOGFvVUdWM2xLZXpReTE5MFRuQjJtbmN1c0d2Rm9VcGJEaHJrMHRsUnBUR1QyKzY4LzQzeWIwUloreVdUVkNyZDA5c0N6UmsvRGN0K295VUtXcjJBWVl4QTBKdDdFQ3lSNERRZlBRWWJQRjRzaHNtY2VyTVd4c2JNVUtxUjQzc2h2c2I1UVR4ay95QTZDaVd4M3ovK3VTeHZKaXRVb1VpaEF0RmVCQmRpTm5LVkJjRzdpZldOSmFvYUJMMDNVT20xUm83N3JHdlVmWXV4cXFJMDJGYXY5OGl2OWVTLy9ZbUd6VVRwejBVdmM5THV0K01ScWtCdnMzRy9QQmlKdk81WWk2STJQaHpObzBPN3o5U0Q2UDlXbm11Zm1WSTlKRkNiSFZrK1BOZz09In0seyJwcnYiOiJzYXQtc2VyaWFsIiwidmFsIjoiMzAwMDEwMDAwMDA1MDAwMDM0NTYifSx7InBydiI6InNhdC10aW1lc3RhbXAiLCJ2YWwiOiIyMDI0LTA0LTI5VDA3OjE2OjEwIn0seyJwcnYiOiJzYXQtY2hhaW4iLCJ2YWwiOiJ8fDEuMXxiN2VkODk3OC1mMGQ3LTQ4YzUtYjU0Ny1kYWY5YWM1NGFhNGF8MjAyNC0wNC0yOVQwNzoxNjoxMHxTUFIxOTA2MTNJNTJ8UWsraGZ0Z2JwU1lNcWNjN0JvQnpHT2N0Y05iRHlwUDRJaUhmemdmNG1KdXJheEdFRmJvOEpFZlM2Qk96ZnFYb2pWTGJSeFBrWEU4M2Zxeldkbm93T2hPbWkwTXZrM0NkbFRaTlo5aTJpN2hKdjZjd2ZIWE1UUHBlT3hmcHR1djJBemhGWDdPMTRnUzJzemVhaTV5SkljVCtkOC9XNkgwek42Yi8yUzEyR2tNZGlrMHR5RjhYUnRRUWF0NFExanhRenNsT3A0NmJyUk9jMFh1b2JjNy9qb2dxMmliN29hSkV1N3FES2hqWUFrSDdCSE1hTE1KZ2VDNmVWZUhVa2tycjdSVlRrSDc1SDR3dGVLWk51UDg1RS9GMTJuQ2tiTVNRcTd1cGx6UnVMeU82WUVreUlXeHBUKzBHcXRjYjZwemlZazh3cXdQMXBWc1ZaWjRRMFBQT3N3PT18MzAwMDEwMDAwMDA1MDAwMDM0NTZ8fCJ9LHsicHJ2Ijoic2F0LXVybCIsInZhbCI6Imh0dHBzOi8vdmVyaWZpY2FjZmRpLmZhY3R1cmFlbGVjdHJvbmljYS5zYXQuZ29iLm14L2RlZmF1bHQuYXNweD9pZD1iN2VkODk3OC1mMGQ3LTQ4YzUtYjU0Ny1kYWY5YWM1NGFhNGFcdTAwMjZ0dD0wLjAxXHUwMDI2cmU9RUtVOTAwMzE3M0M5XHUwMDI2cnI9RUtVOTAwMzE3M0M5XHUwMDI2ZmU9VmsrUE5nPT0ifV19.x-F9HsBfr6l6sICqUOzmQbTbXSP16U4g-By4xviuWOFFB58soJ5p7Sf2LM6rpCh4sR0DGYpkp3C40PBI9Cm4tg" + ] +} \ No newline at end of file diff --git a/examples/mx-fuel-balance.json b/examples/mx-fuel-balance.json new file mode 100644 index 0000000..e90d6ab --- /dev/null +++ b/examples/mx-fuel-balance.json @@ -0,0 +1,204 @@ +{ + "$schema": "https://gobl.org/draft-0/envelope", + "head": { + "uuid": "018f2bca-aa98-763e-8ab3-3aa63cb37cbf", + "dig": { + "alg": "sha256", + "val": "9d6c17ff308384400472973c00e0bfaf7b376f38f066759f14e9f454e7396d58" + }, + "stamps": [ + { + "prv": "sat-uuid", + "val": "e212d624-4812-4987-9499-0d552d5fbeee" + }, + { + "prv": "cfdi-sig", + "val": "e64nyfKdZUH0VQW6cmj8X8RVJyo8REDJ/IX78NSY4gFEgvgVbTerC8qyewNFz2uhPQCPRRqQg5I18dw0iFeghmE6eqyp/r8ap3Gl3xLz+zbhJyuHEh6tYrJbGF82lmcaIC8iXkBWeAc6hYREG3dZP3f1CeHx8HrUlDxTi5qYzfNONLha9sVvw6GaxpPJw/Fg8pschNNB9qzi/1MKniNaE+nXa1TdRblg/XGptARySkL+L7cLwitfsWjysUc1j3fayaeHaqenndRi9RzuSrVZzyq3FN3Cmtp8j1AGUsEUfKUNZPCLV1xBKZgWs2i0Fb5IF5kcTCbA/TrGK9biyx2PLw==" + }, + { + "prv": "cfdi-serial", + "val": "30001000000500003416" + }, + { + "prv": "sat-sig", + "val": "W3R199ZxrwmgSMPnecd0KzO/M8oY12OQX6j1c9G2jhQPLAf1jZoq3A4fqFpflSzpE+b8taUfsDBzprpb5Vo/cZvvOB0pxk5q7zVXWOoicafc5GkBw38emLftCej2VowLIHRd956x++xcEcx+GJNCTaOXi5gd5fC76KnHGKrCbOBfUtFJXSo8bTQRQjJf4zkK6wWl76ua4oZbeUcTtCFA/J+6lJzYPmP7ggpXM+fEcawK1oa2f+2KAwkxTfTLxKSDSAfnyrhlLL2215hWDG4K3W4Tf5xLvzKprQ0NTbxDpXxnXbkpWUaLDuu+7MX6BfWRQk9RbX/L7Vue5Aq9ydJcVQ==" + }, + { + "prv": "sat-serial", + "val": "30001000000500003456" + }, + { + "prv": "sat-timestamp", + "val": "2024-04-29T15:47:56" + }, + { + "prv": "sat-chain", + "val": "||1.1|e212d624-4812-4987-9499-0d552d5fbeee|2024-04-29T15:47:56|SPR190613I52|e64nyfKdZUH0VQW6cmj8X8RVJyo8REDJ/IX78NSY4gFEgvgVbTerC8qyewNFz2uhPQCPRRqQg5I18dw0iFeghmE6eqyp/r8ap3Gl3xLz+zbhJyuHEh6tYrJbGF82lmcaIC8iXkBWeAc6hYREG3dZP3f1CeHx8HrUlDxTi5qYzfNONLha9sVvw6GaxpPJw/Fg8pschNNB9qzi/1MKniNaE+nXa1TdRblg/XGptARySkL+L7cLwitfsWjysUc1j3fayaeHaqenndRi9RzuSrVZzyq3FN3Cmtp8j1AGUsEUfKUNZPCLV1xBKZgWs2i0Fb5IF5kcTCbA/TrGK9biyx2PLw==|30001000000500003456||" + }, + { + "prv": "sat-url", + "val": "https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?id=e212d624-4812-4987-9499-0d552d5fbeee&tt=0.01&re=EKU9003173C9&rr=EKU9003173C9&fe=ydJcVQ==" + } + ] + }, + "doc": { + "$schema": "https://gobl.org/draft-0/bill/invoice", + "uuid": "018f2bca-aa98-7652-bad7-915ecd50274c", + "type": "standard", + "series": "IN2024", + "code": "0003", + "issue_date": "2024-04-29", + "currency": "MXN", + "tax": { + "ext": { + "mx-cfdi-issue-place": "26015" + } + }, + "supplier": { + "name": "ESCUELA KEMPER URGATE", + "tax_id": { + "country": "MX", + "code": "EKU9003173C9" + }, + "ext": { + "mx-cfdi-fiscal-regime": "601", + "mx-cfdi-post-code": "26015" + } + }, + "customer": { + "name": "UNIVERSIDAD ROBOTICA ESPAÑOLA", + "tax_id": { + "country": "MX", + "code": "URE180429TM6" + }, + "ext": { + "mx-cfdi-fiscal-regime": "601", + "mx-cfdi-post-code": "86991", + "mx-cfdi-use": "G01" + } + }, + "lines": [ + { + "i": 1, + "quantity": "1", + "item": { + "name": "Dispersión de Despensa", + "price": "0.01", + "ext": { + "mx-cfdi-prod-serv": "80141628" + } + }, + "sum": "0.01", + "taxes": [ + { + "cat": "VAT", + "rate": "standard", + "percent": "16.0%" + } + ], + "total": "0.01" + } + ], + "payment": { + "advances": [ + { + "key": "credit-transfer", + "description": "Transferencia electrónica de fondos", + "amount": "0.00" + } + ] + }, + "totals": { + "sum": "0.01", + "total": "0.01", + "taxes": { + "categories": [ + { + "code": "VAT", + "rates": [ + { + "key": "standard", + "base": "0.01", + "percent": "16.0%", + "amount": "0.00" + } + ], + "amount": "0.00" + } + ], + "sum": "0.00" + }, + "tax": "0.00", + "total_with_tax": "0.01", + "payable": "0.01", + "advance": "0.00", + "due": "0.01" + }, + "complements": [ + { + "$schema": "https://gobl.org/draft-0/regimes/mx/fuel-account-balance", + "account_number": "N.A", + "subtotal": "246.13", + "total": "400.00", + "lines": [ + { + "e_wallet_id": "1234", + "purchase_date_time": "2022-07-19T10:20:30", + "vendor_tax_code": "EKU9003173C9", + "service_station_code": "8171650", + "quantity": "9.661", + "item": { + "type": "3", + "unit": "l", + "name": "Diesel", + "price": "12.743" + }, + "purchase_code": "2794668", + "total": "123.11", + "taxes": [ + { + "cat": "VAT", + "percent": "16.00%", + "amount": "19.70" + }, + { + "cat": "IEPS", + "rate": "5.9195", + "amount": "57.19" + } + ] + }, + { + "e_wallet_id": "1234", + "purchase_date_time": "2022-08-19T10:20:30", + "vendor_tax_code": "EKU9003173C9", + "service_station_code": "8171667", + "quantity": "9.680", + "item": { + "type": "1", + "name": "Gas. Magna", + "price": "12.709" + }, + "purchase_code": "2794669", + "total": "123.02", + "taxes": [ + { + "cat": "VAT", + "percent": "16.00%", + "amount": "19.68" + }, + { + "cat": "IEPS", + "rate": "5.9195", + "amount": "57.30" + } + ] + } + ] + } + ] + }, + "sigs": [ + "eyJhbGciOiJFUzI1NiIsImtpZCI6IjY2NjJhM2U1LTRhZjgtNDNiYy05ODJmLTE3NDZlOWM3ZWYzOSJ9.eyJ1dWlkIjoiMDE4ZjJiY2EtYWE5OC03NjNlLThhYjMtM2FhNjNjYjM3Y2JmIiwiZGlnIjp7ImFsZyI6InNoYTI1NiIsInZhbCI6IjlkNmMxN2ZmMzA4Mzg0NDAwNDcyOTczYzAwZTBiZmFmN2IzNzZmMzhmMDY2NzU5ZjE0ZTlmNDU0ZTczOTZkNTgifSwic3RhbXBzIjpbeyJwcnYiOiJzYXQtdXVpZCIsInZhbCI6ImUyMTJkNjI0LTQ4MTItNDk4Ny05NDk5LTBkNTUyZDVmYmVlZSJ9LHsicHJ2IjoiY2ZkaS1zaWciLCJ2YWwiOiJlNjRueWZLZFpVSDBWUVc2Y21qOFg4UlZKeW84UkVESi9JWDc4TlNZNGdGRWd2Z1ZiVGVyQzhxeWV3TkZ6MnVoUFFDUFJScVFnNUkxOGR3MGlGZWdobUU2ZXF5cC9yOGFwM0dsM3hMeit6YmhKeXVIRWg2dFlySmJHRjgybG1jYUlDOGlYa0JXZUFjNmhZUkVHM2RaUDNmMUNlSHg4SHJVbER4VGk1cVl6Zk5PTkxoYTlzVnZ3NkdheHBQSncvRmc4cHNjaE5OQjlxemkvMU1LbmlOYUUrblhhMVRkUmJsZy9YR3B0QVJ5U2tMK0w3Y0x3aXRmc1dqeXNVYzFqM2ZheWFlSGFxZW5uZFJpOVJ6dVNyVlp6eXEzRk4zQ210cDhqMUFHVXNFVWZLVU5aUENMVjF4QktaZ1dzMmkwRmI1SUY1a2NUQ2JBL1RyR0s5Yml5eDJQTHc9PSJ9LHsicHJ2IjoiY2ZkaS1zZXJpYWwiLCJ2YWwiOiIzMDAwMTAwMDAwMDUwMDAwMzQxNiJ9LHsicHJ2Ijoic2F0LXNpZyIsInZhbCI6IlczUjE5OVp4cndtZ1NNUG5lY2QwS3pPL004b1kxMk9RWDZqMWM5RzJqaFFQTEFmMWpab3EzQTRmcUZwZmxTenBFK2I4dGFVZnNEQnpwcnBiNVZvL2NadnZPQjBweGs1cTd6VlhXT29pY2FmYzVHa0J3MzhlbUxmdENlajJWb3dMSUhSZDk1NngrK3hjRWN4K0dKTkNUYU9YaTVnZDVmQzc2S25IR0tyQ2JPQmZVdEZKWFNvOGJUUVJRakpmNHprSzZ3V2w3NnVhNG9aYmVVY1R0Q0ZBL0orNmxKellQbVA3Z2dwWE0rZkVjYXdLMW9hMmYrMktBd2t4VGZUTHhLU0RTQWZueXJobExMMjIxNWhXREc0SzNXNFRmNXhMdnpLcHJRME5UYnhEcFh4blhia3BXVWFMRHV1KzdNWDZCZldSUWs5UmJYL0w3VnVlNUFxOXlkSmNWUT09In0seyJwcnYiOiJzYXQtc2VyaWFsIiwidmFsIjoiMzAwMDEwMDAwMDA1MDAwMDM0NTYifSx7InBydiI6InNhdC10aW1lc3RhbXAiLCJ2YWwiOiIyMDI0LTA0LTI5VDE1OjQ3OjU2In0seyJwcnYiOiJzYXQtY2hhaW4iLCJ2YWwiOiJ8fDEuMXxlMjEyZDYyNC00ODEyLTQ5ODctOTQ5OS0wZDU1MmQ1ZmJlZWV8MjAyNC0wNC0yOVQxNTo0Nzo1NnxTUFIxOTA2MTNJNTJ8ZTY0bnlmS2RaVUgwVlFXNmNtajhYOFJWSnlvOFJFREovSVg3OE5TWTRnRkVndmdWYlRlckM4cXlld05GejJ1aFBRQ1BSUnFRZzVJMThkdzBpRmVnaG1FNmVxeXAvcjhhcDNHbDN4THoremJoSnl1SEVoNnRZckpiR0Y4MmxtY2FJQzhpWGtCV2VBYzZoWVJFRzNkWlAzZjFDZUh4OEhyVWxEeFRpNXFZemZOT05MaGE5c1Z2dzZHYXhwUEp3L0ZnOHBzY2hOTkI5cXppLzFNS25pTmFFK25YYTFUZFJibGcvWEdwdEFSeVNrTCtMN2NMd2l0ZnNXanlzVWMxajNmYXlhZUhhcWVubmRSaTlSenVTclZaenlxM0ZOM0NtdHA4ajFBR1VzRVVmS1VOWlBDTFYxeEJLWmdXczJpMEZiNUlGNWtjVENiQS9UckdLOWJpeXgyUEx3PT18MzAwMDEwMDAwMDA1MDAwMDM0NTZ8fCJ9LHsicHJ2Ijoic2F0LXVybCIsInZhbCI6Imh0dHBzOi8vdmVyaWZpY2FjZmRpLmZhY3R1cmFlbGVjdHJvbmljYS5zYXQuZ29iLm14L2RlZmF1bHQuYXNweD9pZD1lMjEyZDYyNC00ODEyLTQ5ODctOTQ5OS0wZDU1MmQ1ZmJlZWVcdTAwMjZ0dD0wLjAxXHUwMDI2cmU9RUtVOTAwMzE3M0M5XHUwMDI2cnI9RUtVOTAwMzE3M0M5XHUwMDI2ZmU9eWRKY1ZRPT0ifV19.dzKTxx37FhlBmmP-1R8mJk9lPul0cWB2X5MjYLWaQe56Wi3Xf7nRqH82FW-YEhXvTC1urI7PgJtMo09CNxzhLg" + ] +} diff --git a/go.mod b/go.mod index 72a6ec6..44be47a 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.22.1 require ( github.com/a-h/templ v0.2.598 github.com/go-resty/resty/v2 v2.12.0 - github.com/invopop/ctxi18n v0.4.0 - github.com/invopop/gobl v0.71.0 + github.com/invopop/ctxi18n v0.6.0 + github.com/invopop/gobl v0.74.2-0.20240429205753-51d26c7ca2f8 github.com/invopop/princepdf v0.0.0-20240408123340-585be3cab91a github.com/labstack/echo/v4 v4.11.4 github.com/piglig/go-qr v0.2.4 @@ -23,7 +23,7 @@ require ( github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/invopop/jsonschema v0.12.0 // indirect github.com/invopop/validation v0.3.0 // indirect @@ -47,3 +47,5 @@ require ( golang.org/x/text v0.14.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +// replace github.com/invopop/gobl => ../gobl diff --git a/go.sum b/go.sum index 1c2ff8f..d134d57 100644 --- a/go.sum +++ b/go.sum @@ -20,14 +20,18 @@ github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/ctxi18n v0.4.0 h1:wj8dMqjevUtsXkUt/EmvUXoYWZQJN8uSbfCSblVMJLU= github.com/invopop/ctxi18n v0.4.0/go.mod h1:1Osw+JGYA+anHt0Z4reF36r5FtGHYjGQ+m1X7keIhPc= -github.com/invopop/gobl v0.71.0 h1:GOlIw0EhJYIXeTUU3Mld0OMaFZbNxGj2V6XugtzHKH0= -github.com/invopop/gobl v0.71.0/go.mod h1:fe+jhOCarDr5AH9z9s2QlJ1o20Atr3mBsKYVcscxzlw= +github.com/invopop/ctxi18n v0.5.0 h1:veT4ZBr8qXEu3USRyS2UvQshFVVtTjkQOYiq8FkATMc= +github.com/invopop/ctxi18n v0.5.0/go.mod h1:1Osw+JGYA+anHt0Z4reF36r5FtGHYjGQ+m1X7keIhPc= +github.com/invopop/ctxi18n v0.6.0 h1:Qm3ZL/kK4EKvmLI3U2ETN2rWrtSTaxXrcA6ZUY9aVGE= +github.com/invopop/ctxi18n v0.6.0/go.mod h1:1Osw+JGYA+anHt0Z4reF36r5FtGHYjGQ+m1X7keIhPc= +github.com/invopop/gobl v0.74.2-0.20240429205753-51d26c7ca2f8 h1:1EPYjNWXRiW7n80XmBSLcO9MfOlilVxLUj3l+Iy/6Ng= +github.com/invopop/gobl v0.74.2-0.20240429205753-51d26c7ca2f8/go.mod h1:3ixShxX1jlOKo5Rw22HVQh3jXnK9AZa7Twcw7L92qn0= github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/invopop/princepdf v0.0.0-20240408123340-585be3cab91a h1:xt18LlIfizLkFgLi+vK/m2SWOsAbQwVwQgbkzxKY0eU= diff --git a/goblhtml.go b/goblhtml.go index b5ce046..1402c3b 100644 --- a/goblhtml.go +++ b/goblhtml.go @@ -3,27 +3,130 @@ package goblhtml import ( "bytes" "context" + "fmt" + "time" + "github.com/invopop/ctxi18n" + "github.com/invopop/ctxi18n/i18n" "github.com/invopop/gobl" "github.com/invopop/gobl.html/components" "github.com/invopop/gobl.html/components/t" "github.com/invopop/gobl/bill" "github.com/invopop/gobl/currency" + "github.com/invopop/gobl/num" + "github.com/invopop/gobl/org" ) +const ( + defaultLanguage i18n.Code = "en" +) + +// Option defines a configuration option to use for rendering. +type Option func(*options) + +type options struct { + locale i18n.Code + calFormatter *t.CalFormatter + numFormatter *num.Formatter + logo *org.Image + notes string +} + +// 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 *options) { + o.logo = logo + } +} + +// WithNotes adds the provided string to the envelope notes. +func WithNotes(txt string) Option { + return func(o *options) { + o.notes = txt + } +} + +// WithLocale sets the locale to use for rendering. +func WithLocale(locale i18n.Code) Option { + return func(o *options) { + o.locale = locale + } +} + +// WithCalFormatter prepares simple date and datetime formatting. +func WithCalFormatter(date, dateTime string, loc *time.Location) Option { + return func(o *options) { + cf := t.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 *options) { + o.numFormatter = &nf + } +} + // Render takes the GOBL envelope and attempts to render an HTML document // from it. -func Render(ctx context.Context, env *gobl.Envelope) ([]byte, error) { - out := components.Envelope(env) +func Render(ctx context.Context, env *gobl.Envelope, opts ...Option) ([]byte, error) { + conf := new(options) + for _, opt := range opts { + opt(conf) + } + + // Prepare the Locale + if conf.locale == "" { + conf.locale = defaultLanguage + } + ctx, err := ctxi18n.WithLocale(ctx, string(conf.locale)) + if err != nil { + return nil, fmt.Errorf("preparing locale: %w", err) + } + + // Is there a calendar formatter? + if conf.calFormatter != nil { + ctx = t.WithCalFormatter(ctx, *conf.calFormatter) + } - cur := currency.EUR // Extract the currency to use for formatting - switch doc := env.Extract().(type) { - case *bill.Invoice: - cur = doc.Currency + if conf.numFormatter == nil { + cur := currency.EUR + switch doc := env.Extract().(type) { + case *bill.Invoice: + cur = doc.Currency + } + nf := cur.Def().Formatter() + conf.numFormatter = &nf + } + ctx = t.WithNumFormatter(ctx, *conf.numFormatter) + + // Does a logo need to be replaced? + if conf.logo != nil { + switch doc := env.Extract().(type) { + case *bill.Invoice: + doc.Supplier.Logos = []*org.Image{conf.logo} + } + } + + // Any additional notes? + if conf.notes != "" { + env.Head.Notes = conf.notes } - ctx = t.WithFormatter(ctx, cur.Def().Formatter()) + out := components.Envelope(env) buf := new(bytes.Buffer) if err := out.Render(ctx, buf); err != nil { return nil, err diff --git a/locales/de/app.yml b/locales/de/app.yml index cd19c39..661947f 100644 --- a/locales/de/app.yml +++ b/locales/de/app.yml @@ -129,7 +129,7 @@ de: identity_code: "Identitätscode" po_box: "Postfach %{po_box}" labels: - default: "Steuernummer" + default: "Steuercode" ext: "%{label}: %{value}" ext_map: # Stellen Sie sicher, dass diese Liste in allen Sprachen auf dem neuesten Stand ist! diff --git a/locales/en/app.yml b/locales/en/app.yml index ed52a48..1f0bcb0 100644 --- a/locales/en/app.yml +++ b/locales/en/app.yml @@ -23,6 +23,8 @@ en: order_period: "Period" order_period_label: "%{label}" order_period_range: "%{start} to %{end}" + ext_map: + mx-cfdi-issue-place: "Place of Issue" supplier: title: "Supplier" @@ -132,8 +134,10 @@ en: default: "Tax Code" ext: "%{label}: %{value}" ext_map: - # Ensure this list is up to date in all locales! co-dian-municipality: "Municipality" + mx-cfdi-fiscal-regime: "Régimen Fiscal" + mx-cfdi-post-code: "Lugar" + mx-cfdi-use: "Uso CFDI" address: label: "%{label}:" country: "(%{country})" diff --git a/locales/es/app.yml b/locales/es/app.yml index 3acfbc3..7257430 100644 --- a/locales/es/app.yml +++ b/locales/es/app.yml @@ -23,6 +23,8 @@ es: order_period: "Período" order_period_label: "%{label}" order_period_range: "%{start} a %{end}" + ext_map: + mx-cfdi-issue-place: "Lugar de Expedición" supplier: title: "Proveedor" @@ -132,7 +134,6 @@ es: default: "Código Fiscal" ext: "%{label}: %{value}" ext_map: - # Asegúrese de que esta lista esté actualizada en todos los idiomas! co-dian-municipality: "Municipio" address: label: "%{label}:" diff --git a/locales/fr/app.yml b/locales/fr/app.yml index 89578f6..cc637fa 100644 --- a/locales/fr/app.yml +++ b/locales/fr/app.yml @@ -99,30 +99,30 @@ fr: section: "Section %{id}" page: "Page %{id}" entry: "Entrée %{id}" - inscription: "Inscrit dans :" + inscription: "Inscrit dans:" regimes: co: - cufe: "CUFE : %{cufe}" - cude: "CUDE : %{cude}" - preceding_cufe: "CUFE Facture précédente : %{cufe}" + cufe: "CUFE: %{cufe}" + cude: "CUDE: %{cude}" + preceding_cufe: "CUFE Facture précédente: %{cufe}" organizing: party: - tax_id: "%{label} : (%{country}) %{code}" - tel: "Tél : %{num}" - tel_label: "Tél : %{num} (%{label})" + tax_id: "%{label}: (%{country}) %{code}" + tel: "Tél: %{num}" + tel_label: "Tél: %{num} (%{label})" email: - one: "Email : %{addr}" - other: "Emails : %{addr}" + one: "Email: %{addr}" + other: "Emails: %{addr}" email_label: "%{addr} (%{label})" - identity: "%{label} : %{code}" + identity: "%{label}: %{code}" identity_code: "Code d'identité" po_box: "Boîte postale %{po_box}" labels: default: "Code fiscal" - ext: "%{label} : %{value}" + ext: "%{label}: %{value}" ext_map: # Assurez-vous que cette liste est à jour dans toutes les langues ! co-dian-municipality: "Municipalité" address: - label: "%{label} :" + label: "%{label}" country: "(%{country})"