Skip to content

Commit

Permalink
Merge pull request #225 from invopop/valid-regimes
Browse files Browse the repository at this point in the history
Validating all regimes, with scenario tag validation
  • Loading branch information
samlown authored Dec 5, 2023
2 parents 833ea04 + 5e31e7a commit bc24b6b
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 19 deletions.
6 changes: 3 additions & 3 deletions regimes/co/corrections.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ var correctionMethodList = []*tax.KeyDefinition{
},
{
Key: CorrectionMethodKeyOther,
Desc: i18n.String{
i18n.EN: "Otros.",
i18n.ES: "Other.",
Name: i18n.String{
i18n.EN: "Other",
i18n.ES: "Otros",
},
Map: cbc.CodeMap{
KeyDIAN: "5",
Expand Down
13 changes: 13 additions & 0 deletions regimes/common/invoice_tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ var invoiceTags = []*tax.KeyDefinition{
i18n.DE: "Kundensätze",
},
},

// Partial invoice document, implying that this is only a first part
// and a final invoice for the remaining amount will be made later.
// A few regimes use this tag to classify invoices, notably Italy.
{
Key: tax.TagPartial,
Name: i18n.String{
i18n.EN: "Partial",
i18n.ES: "Parcial",
i18n.IT: "Parziale",
i18n.DE: "Teilweise",
},
},
}

// InvoiceTags returns a list of common invoice tag key
Expand Down
6 changes: 5 additions & 1 deletion regimes/pt/tax_categories.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ var taxCategories = []*tax.Category{
},
},
{
Key: tax.RateExempt,
Key: tax.RateExempt,
Name: i18n.String{
i18n.EN: "Exempt",
i18n.PT: "Isento",
},
Exempt: true,
Map: cbc.CodeMap{
KeyATTaxCode: TaxCodeExempt,
Expand Down
30 changes: 22 additions & 8 deletions tax/regime.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,14 @@ func (r *Regime) CorrectionDefinitionFor(schema string) *CorrectionDefinition {
// Validate enures the region definition is valid, including all
// subsequent categories.
func (r *Regime) Validate() error {
err := validation.ValidateStruct(r,
return r.ValidateWithContext(context.Background())
}

// ValidateWithContext enures the region definition is valid, including all
// subsequent categories, and passes through the context.
func (r *Regime) ValidateWithContext(ctx context.Context) error {
ctx = context.WithValue(ctx, KeyRegime, r)
err := validation.ValidateStructWithContext(ctx, r,
validation.Field(&r.Country, validation.Required),
validation.Field(&r.Name, validation.Required),
validation.Field(&r.Description),
Expand Down Expand Up @@ -466,9 +473,9 @@ func ValidateStructWithRegime(ctx context.Context, obj interface{}, fields ...*v
return ValidateInRegime(ctx, obj)
}

// Validate ensures the Category's contents are correct.
func (c *Category) Validate() error {
err := validation.ValidateStruct(c,
// ValidateWithContext ensures the Category's contents are correct.
func (c *Category) ValidateWithContext(ctx context.Context) error {
err := validation.ValidateStructWithContext(ctx, c,
validation.Field(&c.Code, validation.Required),
validation.Field(&c.Name, validation.Required),
validation.Field(&c.Title, validation.Required),
Expand Down Expand Up @@ -500,17 +507,20 @@ func (s *Source) Validate() error {
)
}

// Validate checks that our tax definition is valid. This is only really
// ValidateWithContext checks that our tax definition is valid. This is only really
// meant to be used when testing new regional tax definitions.
func (r *Rate) Validate() error {
err := validation.ValidateStruct(r,
func (r *Rate) ValidateWithContext(ctx context.Context) error {
reg := ctx.Value(KeyRegime).(*Regime)
err := validation.ValidateStructWithContext(ctx, r,
validation.Field(&r.Key, validation.Required),
validation.Field(&r.Name, validation.Required),
validation.Field(&r.Values,
validation.When(r.Exempt, validation.Nil),
validation.By(checkRateValuesOrder),
),
validation.Field(&r.Extensions),
validation.Field(&r.Extensions,
validation.Each(InKeyDefs(reg.Extensions)),
),
validation.Field(&r.Map),
validation.Field(&r.Meta),
)
Expand Down Expand Up @@ -542,6 +552,10 @@ func checkRateValuesOrder(list interface{}) error {
// loop through and check order of Since value
for i := range values {
v := values[i]
if len(v.Zones) > 0 {
// TODO: check zone order also
continue
}
if date != nil && date.IsValid() {
if v.Since.IsValid() && !v.Since.Before(date.Date) {
return errors.New("invalid date order")
Expand Down
16 changes: 16 additions & 0 deletions tax/regimes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package tax_test

import (
"testing"

"github.com/invopop/gobl/tax"
"github.com/stretchr/testify/assert"
)

func TestAllRegimes(t *testing.T) {
for _, r := range tax.AllRegimes() {
t.Run(r.Name.String(), func(t *testing.T) {
assert.NoError(t, r.Validate())
})
}
}
18 changes: 11 additions & 7 deletions tax/scenario.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package tax

import (
"context"

"github.com/invopop/gobl/cbc"
"github.com/invopop/gobl/i18n"
"github.com/invopop/validation"
Expand Down Expand Up @@ -47,9 +49,9 @@ type ScenarioSummary struct {
Meta cbc.Meta
}

// Validate checks the scenario set for errors.
func (ss *ScenarioSet) Validate() error {
err := validation.ValidateStruct(ss,
// ValidateWithContext checks the scenario set for errors.
func (ss *ScenarioSet) ValidateWithContext(ctx context.Context) error {
err := validation.ValidateStructWithContext(ctx, ss,
validation.Field(&ss.Schema, validation.Required),
validation.Field(&ss.List, validation.Required),
)
Expand Down Expand Up @@ -115,11 +117,13 @@ func (s *Scenario) hasTags(docTags []cbc.Key) bool {
return false
}

// Validate checks the scenario for errors.
func (s *Scenario) Validate() error {
err := validation.ValidateStruct(s,
// ValidateWithContext checks the scenario for errors, using the regime in the context
// to validate the list of tags.
func (s *Scenario) ValidateWithContext(ctx context.Context) error {
r := ctx.Value(KeyRegime).(*Regime)
err := validation.ValidateStructWithContext(ctx, s,
validation.Field(&s.Types),
validation.Field(&s.Tags),
validation.Field(&s.Tags, validation.Each(InKeyDefs(r.Tags))),
validation.Field(&s.Name),
validation.Field(&s.Note),
validation.Field(&s.Codes),
Expand Down

0 comments on commit bc24b6b

Please sign in to comment.