diff --git a/CHANGELOG.md b/CHANGELOG.md index 0984f4a59..108cee230 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Added +- `regimes/au`: New tax regime for Australia — GST and ABN tax identity validation (weighted modulus-89 checksum). +- `regimes/nz`: New tax regime for New Zealand — GST, IRD number validation (weighted modulus-11 checksum), and te reo Māori (`mi`) translations. - `bill`: `PaymentDetails.Payer` party — the party responsible for making payment of the invoice if not the customer, the counterpart of the existing `Payee`. ## [v0.501.0] - 2026-06-16 diff --git a/data/regimes/au.json b/data/regimes/au.json new file mode 100644 index 000000000..a2e913f95 --- /dev/null +++ b/data/regimes/au.json @@ -0,0 +1,88 @@ +{ + "$schema": "https://gobl.org/draft-0/tax/regime-def", + "name": { + "en": "Australia" + }, + "description": { + "en": "Australia's Goods and Services Tax (GST) is a broad-based tax of 10%\napplied to most goods, services and other items sold or consumed in\nAustralia. It is administered by the Australian Taxation Office (ATO).\n\nBusinesses are identified by their Australian Business Number (ABN), an\n11-digit identifier whose validity is confirmed with a weighted\nmodulus-89 check." + }, + "sources": [ + { + "title": { + "en": "ATO - GST" + }, + "url": "https://www.ato.gov.au/businesses-and-organisations/gst-excise-and-indirect-taxes/gst" + } + ], + "time_zone": "Australia/Sydney", + "country": "AU", + "currency": "AUD", + "tax_scheme": "GST", + "categories": [ + { + "code": "GST", + "name": { + "en": "GST" + }, + "title": { + "en": "Goods and Services Tax" + }, + "keys": [ + { + "key": "standard", + "name": { + "en": "Standard" + } + }, + { + "key": "zero", + "name": { + "en": "Zero" + } + }, + { + "key": "exempt", + "name": { + "en": "Exempt" + }, + "no_percent": true + }, + { + "key": "outside-scope", + "name": { + "en": "Outside scope" + }, + "no_percent": true + } + ], + "rates": [ + { + "rate": "general", + "keys": [ + "standard" + ], + "name": { + "en": "Standard Rate" + }, + "desc": { + "en": "Applies to most goods and services unless they are GST-free or input-taxed." + }, + "values": [ + { + "since": "2000-07-01", + "percent": "10.0%" + } + ] + } + ], + "sources": [ + { + "title": { + "en": "ATO - GST" + }, + "url": "https://www.ato.gov.au/businesses-and-organisations/gst-excise-and-indirect-taxes/gst" + } + ] + } + ] +} \ No newline at end of file diff --git a/data/regimes/nz.json b/data/regimes/nz.json new file mode 100644 index 000000000..6492163ac --- /dev/null +++ b/data/regimes/nz.json @@ -0,0 +1,94 @@ +{ + "$schema": "https://gobl.org/draft-0/tax/regime-def", + "name": { + "en": "New Zealand", + "mi": "Aotearoa" + }, + "description": { + "en": "New Zealand's Goods and Services Tax (GST) is a broad-based tax of 15%\napplied to most goods and services supplied in New Zealand. It is\nadministered by Inland Revenue (IRD).\n\nBusinesses are identified by their IRD number, an 8 or 9 digit\nidentifier whose validity is confirmed with a weighted modulus-11 check." + }, + "sources": [ + { + "title": { + "en": "Inland Revenue - GST", + "mi": "Te Tari Taake - GST" + }, + "url": "https://www.ird.govt.nz/gst" + } + ], + "time_zone": "Pacific/Auckland", + "country": "NZ", + "currency": "NZD", + "tax_scheme": "GST", + "categories": [ + { + "code": "GST", + "name": { + "en": "GST", + "mi": "GST" + }, + "title": { + "en": "Goods and Services Tax", + "mi": "Tāke mō ngā Rawa me ngā Ratonga" + }, + "keys": [ + { + "key": "standard", + "name": { + "en": "Standard" + } + }, + { + "key": "zero", + "name": { + "en": "Zero" + } + }, + { + "key": "exempt", + "name": { + "en": "Exempt" + }, + "no_percent": true + }, + { + "key": "outside-scope", + "name": { + "en": "Outside scope" + }, + "no_percent": true + } + ], + "rates": [ + { + "rate": "general", + "keys": [ + "standard" + ], + "name": { + "en": "Standard Rate", + "mi": "Pāpātanga Paerewa" + }, + "desc": { + "en": "Applies to most goods and services unless they are zero-rated or exempt.", + "mi": "Ka pā ki te nuinga o ngā rawa me ngā ratonga ki te kore rātou e tāke-kore, e tāke-whakawātea rānei." + }, + "values": [ + { + "since": "2010-10-01", + "percent": "15.0%" + } + ] + } + ], + "sources": [ + { + "title": { + "en": "Inland Revenue - GST rate" + }, + "url": "https://www.ird.govt.nz/gst" + } + ] + } + ] +} \ No newline at end of file diff --git a/data/rules/au.json b/data/rules/au.json new file mode 100644 index 000000000..1dc872eea --- /dev/null +++ b/data/rules/au.json @@ -0,0 +1,32 @@ +{ + "id": "GOBL-AU", + "package": "au", + "subsets": [ + { + "id": "GOBL-AU-TAX-IDENTITY", + "object": "tax.Identity", + "subsets": [ + { + "guard": "code in [AU]", + "subsets": [ + { + "field": "code", + "assert": [ + { + "id": "GOBL-AU-TAX-IDENTITY-01", + "desc": "invoice tax id code must be a valid 11-digit ABN", + "tests": "matches ^[0-9]{11}$" + }, + { + "id": "GOBL-AU-TAX-IDENTITY-02", + "desc": "invoice tax id code checksum must be valid", + "tests": "valid" + } + ] + } + ] + } + ] + } + ] +} diff --git a/data/rules/nz.json b/data/rules/nz.json new file mode 100644 index 000000000..3495322ec --- /dev/null +++ b/data/rules/nz.json @@ -0,0 +1,32 @@ +{ + "id": "GOBL-NZ", + "package": "nz", + "subsets": [ + { + "id": "GOBL-NZ-TAX-IDENTITY", + "object": "tax.Identity", + "subsets": [ + { + "guard": "code in [NZ]", + "subsets": [ + { + "field": "code", + "assert": [ + { + "id": "GOBL-NZ-TAX-IDENTITY-01", + "desc": "invoice tax id code must be a valid IRD number", + "tests": "matches ^[0-9]{8,9}$" + }, + { + "id": "GOBL-NZ-TAX-IDENTITY-02", + "desc": "invoice tax id code checksum must be valid", + "tests": "valid" + } + ] + } + ] + } + ] + } + ] +} diff --git a/data/schemas/tax/regime-code.json b/data/schemas/tax/regime-code.json index c4edd54f5..84ed0c999 100644 --- a/data/schemas/tax/regime-code.json +++ b/data/schemas/tax/regime-code.json @@ -17,6 +17,10 @@ "const": "AT", "title": "Austria" }, + { + "const": "AU", + "title": "Australia" + }, { "const": "BE", "title": "Belgium" @@ -85,6 +89,10 @@ "const": "NO", "title": "Norway" }, + { + "const": "NZ", + "title": "New Zealand" + }, { "const": "PL", "title": "Poland" diff --git a/regimes/au/au.go b/regimes/au/au.go new file mode 100644 index 000000000..c5aab4974 --- /dev/null +++ b/regimes/au/au.go @@ -0,0 +1,56 @@ +// Package au provides the tax regime definition for Australia. +package au + +import ( + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/currency" + "github.com/invopop/gobl/i18n" + "github.com/invopop/gobl/norm" + "github.com/invopop/gobl/pkg/here" + "github.com/invopop/gobl/rules" + "github.com/invopop/gobl/tax" +) + +// CountryCode is the tax country code for Australia. +const CountryCode = "AU" + +func init() { + tax.RegisterRegimeDef(New()) + rules.Register("au", rules.GOBL.Add(CountryCode), + taxIdentityRules(), + ) + norm.Register( + norm.When(tax.IdentityIn(CountryCode), norm.For(normalizeTaxIdentity)), + ) +} + +// New provides the tax regime definition for Australia. +func New() *tax.RegimeDef { + return &tax.RegimeDef{ + Country: CountryCode, + Currency: currency.AUD, + TaxScheme: tax.CategoryGST, + Name: i18n.String{ + i18n.EN: "Australia", + }, + Description: i18n.String{ + i18n.EN: here.Doc(` + Australia's Goods and Services Tax (GST) is a broad-based tax of 10% + applied to most goods, services and other items sold or consumed in + Australia. It is administered by the Australian Taxation Office (ATO). + + Businesses are identified by their Australian Business Number (ABN), an + 11-digit identifier whose validity is confirmed with a weighted + modulus-89 check. + `), + }, + Sources: []*cbc.Source{ + { + Title: i18n.NewString("ATO - GST"), + URL: "https://www.ato.gov.au/businesses-and-organisations/gst-excise-and-indirect-taxes/gst", + }, + }, + TimeZone: "Australia/Sydney", + Categories: taxCategories(), + } +} diff --git a/regimes/au/tax_categories.go b/regimes/au/tax_categories.go new file mode 100644 index 000000000..fcf71a1c0 --- /dev/null +++ b/regimes/au/tax_categories.go @@ -0,0 +1,49 @@ +package au + +import ( + "github.com/invopop/gobl/cal" + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/i18n" + "github.com/invopop/gobl/num" + "github.com/invopop/gobl/tax" +) + +func taxCategories() []*tax.CategoryDef { + return []*tax.CategoryDef{ + { + Code: tax.CategoryGST, + Name: i18n.String{ + i18n.EN: "GST", + }, + Title: i18n.String{ + i18n.EN: "Goods and Services Tax", + }, + Retained: false, + Keys: tax.GlobalGSTKeys(), + Rates: []*tax.RateDef{ + { + Keys: []cbc.Key{tax.KeyStandard}, + Rate: tax.RateGeneral, + Name: i18n.String{ + i18n.EN: "Standard Rate", + }, + Description: i18n.String{ + i18n.EN: "Applies to most goods and services unless they are GST-free or input-taxed.", + }, + Values: []*tax.RateValueDef{ + { + Since: cal.NewDate(2000, 7, 1), + Percent: num.MakePercentage(100, 3), + }, + }, + }, + }, + Sources: []*cbc.Source{ + { + Title: i18n.NewString("ATO - GST"), + URL: "https://www.ato.gov.au/businesses-and-organisations/gst-excise-and-indirect-taxes/gst", + }, + }, + }, + } +} diff --git a/regimes/au/tax_identity.go b/regimes/au/tax_identity.go new file mode 100644 index 000000000..013b6283c --- /dev/null +++ b/regimes/au/tax_identity.go @@ -0,0 +1,62 @@ +package au + +import ( + "regexp" + + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/rules" + "github.com/invopop/gobl/rules/is" + "github.com/invopop/gobl/tax" +) + +// abnRegexp matches the basic shape of an Australian Business Number: 11 digits. +var abnRegexp = regexp.MustCompile(`^[0-9]{11}$`) + +// abnWeights are the position weights used by the ABN check-digit algorithm. +var abnWeights = []int{10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19} + +// normalizeTaxIdentity strips whitespace, separators and country prefix from an +// Australian Business Number. +func normalizeTaxIdentity(tID *tax.Identity) { + tax.NormalizeIdentity(tID) +} + +func taxIdentityRules() *rules.Set { + return rules.For(new(tax.Identity), + rules.When(tax.IdentityIn(CountryCode), + rules.Field("code", + rules.Assert("01", "invoice tax id code must be a valid 11-digit ABN", + is.MatchesRegexp(abnRegexp)), + rules.Assert("02", "invoice tax id code checksum must be valid", + is.Func("valid", isValidTaxIdentityCode)), + ), + ), + ) +} + +// isValidTaxIdentityCode reports whether the value is an ABN with valid check +// digits. Empty or non-conforming values are left to the format rule above. +func isValidTaxIdentityCode(value any) bool { + code, ok := value.(cbc.Code) + if !ok || code == "" { + return true + } + return validABN(code.String()) +} + +// validABN reports whether code is a structurally valid ABN with correct check +// digits, using the ATO weighted modulus-89 algorithm. +func validABN(code string) bool { + if len(code) != len(abnWeights) { + return false + } + sum := 0 + for i, w := range abnWeights { + d := int(code[i] - '0') + if i == 0 { + d-- // subtract 1 from the leading digit + } + sum += d * w + } + return sum%89 == 0 +} diff --git a/regimes/au/tax_identity_test.go b/regimes/au/tax_identity_test.go new file mode 100644 index 000000000..beed3cbde --- /dev/null +++ b/regimes/au/tax_identity_test.go @@ -0,0 +1,80 @@ +package au_test + +import ( + "testing" + + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/norm" + _ "github.com/invopop/gobl/regimes/au" + "github.com/invopop/gobl/rules" + "github.com/invopop/gobl/tax" + "github.com/stretchr/testify/assert" +) + +func TestTaxIdentityRules(t *testing.T) { + validate := func(code cbc.Code) error { + return rules.Validate(&tax.Identity{Country: "AU", Code: code}) + } + + t.Run("valid ABN (ATO)", func(t *testing.T) { + assert.NoError(t, validate("51824753556")) + }) + + t.Run("valid ABN", func(t *testing.T) { + assert.NoError(t, validate("83914571673")) + }) + + t.Run("empty code is allowed", func(t *testing.T) { + assert.NoError(t, validate("")) + }) + + t.Run("invalid check digits", func(t *testing.T) { + err := validate("51824753557") + assert.ErrorContains(t, err, "IDENTITY-02") + }) + + t.Run("too short", func(t *testing.T) { + err := validate("5182475355") + assert.ErrorContains(t, err, "IDENTITY-01") + }) + + t.Run("too long", func(t *testing.T) { + err := validate("518247535560") + assert.ErrorContains(t, err, "IDENTITY-01") + }) + + t.Run("contains letters", func(t *testing.T) { + err := validate("5182475355A") + assert.ErrorContains(t, err, "IDENTITY-01") + }) + + t.Run("special characters", func(t *testing.T) { + err := validate("51-824753-556") + assert.ErrorContains(t, err, "IDENTITY-01") + }) +} + +func TestTaxIdentityNormalization(t *testing.T) { + t.Run("nil identity is safe", func(t *testing.T) { + var tID *tax.Identity + assert.NotPanics(t, func() { norm.Normalize(tID) }) + }) + + t.Run("normalizes identity", func(t *testing.T) { + tID := &tax.Identity{Country: "AU", Code: "51824753556"} + norm.Normalize(tID) + assert.Equal(t, cbc.Code("51824753556"), tID.Code) + }) + + t.Run("empty code is left untouched", func(t *testing.T) { + tID := &tax.Identity{Country: "AU", Code: ""} + norm.Normalize(tID) + assert.Equal(t, cbc.Code(""), tID.Code) + }) + + t.Run("strips whitespace and country prefix", func(t *testing.T) { + tID := &tax.Identity{Country: "AU", Code: " AU 51 824 753 556 "} + norm.Normalize(tID) + assert.Equal(t, cbc.Code("51824753556"), tID.Code) + }) +} diff --git a/regimes/nz/nz.go b/regimes/nz/nz.go new file mode 100644 index 000000000..c192e3892 --- /dev/null +++ b/regimes/nz/nz.go @@ -0,0 +1,59 @@ +// Package nz provides the tax regime definition for New Zealand. +package nz + +import ( + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/currency" + "github.com/invopop/gobl/i18n" + "github.com/invopop/gobl/norm" + "github.com/invopop/gobl/pkg/here" + "github.com/invopop/gobl/rules" + "github.com/invopop/gobl/tax" +) + +// CountryCode is the tax country code for New Zealand. +const CountryCode = "NZ" + +func init() { + tax.RegisterRegimeDef(New()) + rules.Register("nz", rules.GOBL.Add(CountryCode), + taxIdentityRules(), + ) + norm.Register( + norm.When(tax.IdentityIn(CountryCode), norm.For(normalizeTaxIdentity)), + ) +} + +// New provides the tax regime definition for New Zealand. +func New() *tax.RegimeDef { + return &tax.RegimeDef{ + Country: CountryCode, + Currency: currency.NZD, + TaxScheme: tax.CategoryGST, + Name: i18n.String{ + i18n.EN: "New Zealand", + i18n.MI: "Aotearoa", + }, + Description: i18n.String{ + i18n.EN: here.Doc(` + New Zealand's Goods and Services Tax (GST) is a broad-based tax of 15% + applied to most goods and services supplied in New Zealand. It is + administered by Inland Revenue (IRD). + + Businesses are identified by their IRD number, an 8 or 9 digit + identifier whose validity is confirmed with a weighted modulus-11 check. + `), + }, + Sources: []*cbc.Source{ + { + Title: i18n.String{ + i18n.EN: "Inland Revenue - GST", + i18n.MI: "Te Tari Taake - GST", + }, + URL: "https://www.ird.govt.nz/gst", + }, + }, + TimeZone: "Pacific/Auckland", + Categories: taxCategories(), + } +} diff --git a/regimes/nz/tax_categories.go b/regimes/nz/tax_categories.go new file mode 100644 index 000000000..00f22813e --- /dev/null +++ b/regimes/nz/tax_categories.go @@ -0,0 +1,53 @@ +package nz + +import ( + "github.com/invopop/gobl/cal" + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/i18n" + "github.com/invopop/gobl/num" + "github.com/invopop/gobl/tax" +) + +func taxCategories() []*tax.CategoryDef { + return []*tax.CategoryDef{ + { + Code: tax.CategoryGST, + Name: i18n.String{ + i18n.EN: "GST", + i18n.MI: "GST", + }, + Title: i18n.String{ + i18n.EN: "Goods and Services Tax", + i18n.MI: "Tāke mō ngā Rawa me ngā Ratonga", + }, + Retained: false, + Keys: tax.GlobalGSTKeys(), + Rates: []*tax.RateDef{ + { + Keys: []cbc.Key{tax.KeyStandard}, + Rate: tax.RateGeneral, + Name: i18n.String{ + i18n.EN: "Standard Rate", + i18n.MI: "Pāpātanga Paerewa", + }, + Description: i18n.String{ + i18n.EN: "Applies to most goods and services unless they are zero-rated or exempt.", + i18n.MI: "Ka pā ki te nuinga o ngā rawa me ngā ratonga ki te kore rātou e tāke-kore, e tāke-whakawātea rānei.", + }, + Values: []*tax.RateValueDef{ + { + Since: cal.NewDate(2010, 10, 1), + Percent: num.MakePercentage(150, 3), + }, + }, + }, + }, + Sources: []*cbc.Source{ + { + Title: i18n.NewString("Inland Revenue - GST rate"), + URL: "https://www.ird.govt.nz/gst", + }, + }, + }, + } +} diff --git a/regimes/nz/tax_identity.go b/regimes/nz/tax_identity.go new file mode 100644 index 000000000..d9fa026c4 --- /dev/null +++ b/regimes/nz/tax_identity.go @@ -0,0 +1,98 @@ +package nz + +import ( + "regexp" + "strconv" + + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/rules" + "github.com/invopop/gobl/rules/is" + "github.com/invopop/gobl/tax" +) + +// irdRegexp matches the basic shape of a New Zealand IRD number: 8 or 9 digits. +var irdRegexp = regexp.MustCompile(`^[0-9]{8,9}$`) + +// IRD numbers must fall within this inclusive range to be considered valid. +const ( + irdMin = 10000000 + irdMax = 200000000 +) + +// irdWeights are the primary weighting factors applied to the IRD base number. +var irdWeights = []int{3, 2, 7, 6, 5, 4, 3, 2} + +// irdWeightsSecondary are the weighting factors used when the primary check +// digit calculation yields 10. +var irdWeightsSecondary = []int{7, 4, 3, 2, 5, 2, 7, 6} + +// normalizeTaxIdentity strips whitespace, separators and country prefix from a +// New Zealand IRD number. +func normalizeTaxIdentity(tID *tax.Identity) { + tax.NormalizeIdentity(tID) +} + +func taxIdentityRules() *rules.Set { + return rules.For(new(tax.Identity), + rules.When(tax.IdentityIn(CountryCode), + rules.Field("code", + rules.Assert("01", "invoice tax id code must be a valid IRD number", + is.MatchesRegexp(irdRegexp)), + rules.Assert("02", "invoice tax id code checksum must be valid", + is.Func("valid", isValidTaxIdentityCode)), + ), + ), + ) +} + +// isValidTaxIdentityCode reports whether the value is an IRD number within range +// and with a valid check digit. Empty or non-conforming values are left to the +// format rule above. +func isValidTaxIdentityCode(value any) bool { + code, ok := value.(cbc.Code) + if !ok || code == "" { + return true + } + return validIRD(code.String()) +} + +// validIRD reports whether code is a valid New Zealand IRD number, applying the +// Inland Revenue weighted modulus-11 check-digit algorithm. +func validIRD(code string) bool { + n, err := strconv.Atoi(code) + if err != nil || n < irdMin || n > irdMax { + return false + } + + // Left-pad to 9 digits so the base is always the first 8 digits and the + // check digit the 9th. + if len(code) == 8 { + code = "0" + code + } + + check := int(code[8] - '0') + + calc := irdCheckDigit(code, irdWeights) + if calc == 10 { + // Re-run with the secondary weights when the first pass is inconclusive. + calc = irdCheckDigit(code, irdWeightsSecondary) + if calc == 10 { + return false + } + } + return calc == check +} + +// irdCheckDigit returns the expected check digit for the base (first 8 digits) +// of code given a set of weights. +func irdCheckDigit(code string, weights []int) int { + sum := 0 + for i, w := range weights { + sum += int(code[i]-'0') * w + } + rem := sum % 11 + if rem == 0 { + return 0 + } + return 11 - rem +} diff --git a/regimes/nz/tax_identity_test.go b/regimes/nz/tax_identity_test.go new file mode 100644 index 000000000..a99bdbbe2 --- /dev/null +++ b/regimes/nz/tax_identity_test.go @@ -0,0 +1,85 @@ +package nz_test + +import ( + "testing" + + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/norm" + _ "github.com/invopop/gobl/regimes/nz" + "github.com/invopop/gobl/rules" + "github.com/invopop/gobl/tax" + "github.com/stretchr/testify/assert" +) + +func TestTaxIdentityRules(t *testing.T) { + validate := func(code cbc.Code) error { + return rules.Validate(&tax.Identity{Country: "NZ", Code: code}) + } + + t.Run("valid 8-digit IRD", func(t *testing.T) { + assert.NoError(t, validate("49091850")) + }) + + t.Run("valid 9-digit IRD using secondary weights", func(t *testing.T) { + assert.NoError(t, validate("136410132")) + }) + + t.Run("empty code is allowed", func(t *testing.T) { + assert.NoError(t, validate("")) + }) + + t.Run("invalid check digit", func(t *testing.T) { + err := validate("49091851") + assert.ErrorContains(t, err, "IDENTITY-02") + }) + + t.Run("below valid range", func(t *testing.T) { + err := validate("09999999") + assert.ErrorContains(t, err, "IDENTITY-02") + }) + + t.Run("too short", func(t *testing.T) { + err := validate("4909185") + assert.ErrorContains(t, err, "IDENTITY-01") + }) + + t.Run("too long", func(t *testing.T) { + err := validate("1364101320") + assert.ErrorContains(t, err, "IDENTITY-01") + }) + + t.Run("contains letters", func(t *testing.T) { + err := validate("4909185A") + assert.ErrorContains(t, err, "IDENTITY-01") + }) + + t.Run("special characters", func(t *testing.T) { + err := validate("49-091-850") + assert.ErrorContains(t, err, "IDENTITY-01") + }) +} + +func TestTaxIdentityNormalization(t *testing.T) { + t.Run("nil identity is safe", func(t *testing.T) { + var tID *tax.Identity + assert.NotPanics(t, func() { norm.Normalize(tID) }) + }) + + t.Run("normalizes identity", func(t *testing.T) { + tID := &tax.Identity{Country: "NZ", Code: "49091850"} + norm.Normalize(tID) + assert.Equal(t, cbc.Code("49091850"), tID.Code) + }) + + t.Run("empty code is left untouched", func(t *testing.T) { + tID := &tax.Identity{Country: "NZ", Code: ""} + norm.Normalize(tID) + assert.Equal(t, cbc.Code(""), tID.Code) + }) + + t.Run("strips whitespace and country prefix", func(t *testing.T) { + tID := &tax.Identity{Country: "NZ", Code: " NZ 49-091-850 "} + norm.Normalize(tID) + assert.Equal(t, cbc.Code("49091850"), tID.Code) + }) +} diff --git a/regimes/regimes.go b/regimes/regimes.go index 1ca5cdd5d..9ed248127 100644 --- a/regimes/regimes.go +++ b/regimes/regimes.go @@ -8,6 +8,7 @@ import ( _ "github.com/invopop/gobl/regimes/ae" _ "github.com/invopop/gobl/regimes/ar" _ "github.com/invopop/gobl/regimes/at" + _ "github.com/invopop/gobl/regimes/au" _ "github.com/invopop/gobl/regimes/be" _ "github.com/invopop/gobl/regimes/br" _ "github.com/invopop/gobl/regimes/ca" @@ -25,6 +26,7 @@ import ( _ "github.com/invopop/gobl/regimes/mx" _ "github.com/invopop/gobl/regimes/nl" _ "github.com/invopop/gobl/regimes/no" + _ "github.com/invopop/gobl/regimes/nz" _ "github.com/invopop/gobl/regimes/pl" _ "github.com/invopop/gobl/regimes/pt" _ "github.com/invopop/gobl/regimes/sa"