diff --git a/regimes/co/corrections.go b/regimes/co/corrections.go index 7ad4124d..960cc10a 100644 --- a/regimes/co/corrections.go +++ b/regimes/co/corrections.go @@ -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", diff --git a/regimes/common/invoice_tags.go b/regimes/common/invoice_tags.go index 2a41f023..66ec8535 100644 --- a/regimes/common/invoice_tags.go +++ b/regimes/common/invoice_tags.go @@ -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 diff --git a/regimes/pt/tax_categories.go b/regimes/pt/tax_categories.go index 59171fb7..6a0c3f3a 100644 --- a/regimes/pt/tax_categories.go +++ b/regimes/pt/tax_categories.go @@ -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, diff --git a/tax/regime.go b/tax/regime.go index 2ce7d157..372b5fd9 100644 --- a/tax/regime.go +++ b/tax/regime.go @@ -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), @@ -542,6 +549,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") diff --git a/tax/regimes_test.go b/tax/regimes_test.go new file mode 100644 index 00000000..f59dfba3 --- /dev/null +++ b/tax/regimes_test.go @@ -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()) + }) + } +} diff --git a/tax/scenario.go b/tax/scenario.go index 37a385e0..03c37788 100644 --- a/tax/scenario.go +++ b/tax/scenario.go @@ -1,6 +1,8 @@ package tax import ( + "context" + "github.com/invopop/gobl/cbc" "github.com/invopop/gobl/i18n" "github.com/invopop/validation" @@ -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), ) @@ -116,10 +118,11 @@ func (s *Scenario) hasTags(docTags []cbc.Key) bool { } // Validate checks the scenario for errors. -func (s *Scenario) Validate() error { - err := validation.ValidateStruct(s, +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),