diff --git a/CHANGELOG.md b/CHANGELOG.md index 05a52ca4..5fba9e5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Fixed - `bill.Invoice` - remove empty taxes instances. +- `tax.Identity` - support Calculate method to normalize IDs. ## [v0.202.0] diff --git a/org/party.go b/org/party.go index f9b84182..a9188aba 100644 --- a/org/party.go +++ b/org/party.go @@ -48,6 +48,13 @@ type Party struct { Meta cbc.Meta `json:"meta,omitempty" jsonschema:"title=Meta"` } +// Calculate will perform basic normalization of the party's data without +// using any tax regime or addon. +func (p *Party) Calculate() error { + p.Normalize(nil) + return nil +} + // Normalize will try to normalize the party's data. func (p *Party) Normalize(normalizers tax.Normalizers) { if p == nil { diff --git a/org/party_test.go b/org/party_test.go index 5ed3fd7a..bd1ced11 100644 --- a/org/party_test.go +++ b/org/party_test.go @@ -22,27 +22,44 @@ func TestEmailValidation(t *testing.T) { assert.EqualError(t, invalid.Validate(), "addr: must be a valid email address.") } -func TestPartyCalculate(t *testing.T) { - party := org.Party{ - Name: "Invopop", - TaxID: &tax.Identity{ - Country: "ES", - Code: "423 429 12.G", - }, - } - party.Normalize(nil) - assert.Equal(t, "ES", party.TaxID.Country.String()) - assert.Equal(t, "ES42342912G", party.TaxID.String()) - - party = org.Party{ - Name: "Invopop", - TaxID: &tax.Identity{ - Country: "ZZ", // no country has ZZ! - Code: "423 429 12.G", - }, - } - party.Normalize(nil) // unknown entry should not cause problem - assert.Equal(t, "42342912G", party.TaxID.Code.String()) +func TestPartyNormalize(t *testing.T) { + t.Run("for known regime", func(t *testing.T) { + party := org.Party{ + Name: "Invopop", + TaxID: &tax.Identity{ + Country: "ES", + Code: "423 429 12.G", + }, + } + party.Normalize(nil) + assert.Equal(t, "ES", party.TaxID.Country.String()) + assert.Equal(t, "ES42342912G", party.TaxID.String()) + }) + + t.Run("for known regime with Calculate", func(t *testing.T) { + party := org.Party{ + Name: "Invopop", + TaxID: &tax.Identity{ + Country: "ES", + Code: "423 429 12.G", + }, + } + assert.NoError(t, party.Calculate()) + assert.Equal(t, "ES", party.TaxID.Country.String()) + assert.Equal(t, "ES42342912G", party.TaxID.String()) + }) + + t.Run("for unknown regime", func(t *testing.T) { + party := org.Party{ + Name: "Invopop", + TaxID: &tax.Identity{ + Country: "ZZ", // no country has ZZ! + Code: "423 429 12.G", + }, + } + party.Normalize(nil) // unknown entry should not cause problem + assert.Equal(t, "42342912G", party.TaxID.Code.String()) + }) } func TestPartyAddressNill(t *testing.T) { diff --git a/regimes/es/examples/out/party.json b/regimes/es/examples/out/party.json new file mode 100644 index 00000000..f92f650e --- /dev/null +++ b/regimes/es/examples/out/party.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://gobl.org/draft-0/envelope", + "head": { + "uuid": "8a51fd30-2a27-11ee-be56-0242ac120002", + "dig": { + "alg": "sha256", + "val": "eb13b8883977bbd80419ce394072232e235c13c9325a4dda3693da85d86f3396" + } + }, + "doc": { + "$schema": "https://gobl.org/draft-0/org/party", + "uuid": "0192a13b-7f85-7429-a635-b269f6eb5295", + "name": "Provide One S.L.", + "tax_id": { + "country": "ES", + "code": "B98602642" + }, + "addresses": [ + { + "num": "42", + "street": "Calle Pradillo", + "locality": "Madrid", + "region": "Madrid", + "code": "28002", + "country": "ES" + } + ], + "emails": [ + { + "addr": "billing@example.com" + } + ] + } +} \ No newline at end of file diff --git a/regimes/es/examples/out/tax-identity.json b/regimes/es/examples/out/tax-identity.json new file mode 100644 index 00000000..273d1864 --- /dev/null +++ b/regimes/es/examples/out/tax-identity.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://gobl.org/draft-0/envelope", + "head": { + "uuid": "8a51fd30-2a27-11ee-be56-0242ac120002", + "dig": { + "alg": "sha256", + "val": "3630785426ac28dd900af9bd1ea51cf5ed783896dfe954773ad1d88058267453" + } + }, + "doc": { + "$schema": "https://gobl.org/draft-0/tax/identity", + "country": "ES", + "code": "B98602642" + } +} \ No newline at end of file diff --git a/regimes/es/examples/party.yaml b/regimes/es/examples/party.yaml new file mode 100644 index 00000000..e78730f6 --- /dev/null +++ b/regimes/es/examples/party.yaml @@ -0,0 +1,15 @@ +$schema: "https://gobl.org/draft-0/org/party" +uuid: "0192a13b-7f85-7429-a635-b269f6eb5295" +tax_id: + country: "ES" + code: "B-986.026.42" # test normalization +name: "Provide One S.L." +emails: + - addr: "billing@example.com" +addresses: + - num: "42" + street: "Calle Pradillo" + locality: "Madrid" + region: "Madrid" + code: "28002" + country: "ES" diff --git a/regimes/es/examples/tax-identity.yaml b/regimes/es/examples/tax-identity.yaml new file mode 100644 index 00000000..431dbf98 --- /dev/null +++ b/regimes/es/examples/tax-identity.yaml @@ -0,0 +1,3 @@ +$schema: "https://gobl.org/draft-0/tax/identity" +country: "ES" +code: "B-986.026.42" # test normalization diff --git a/tax/identity.go b/tax/identity.go index 7fd51b9a..ddcba831 100644 --- a/tax/identity.go +++ b/tax/identity.go @@ -98,6 +98,12 @@ func (id *Identity) Regime() *RegimeDef { return regimes.For(id.Country.Code()) } +// Calculate will simply perform normalization. +func (id *Identity) Calculate() error { + id.Normalize() + return nil +} + // Normalize will attempt to perform a regional tax normalization // on the tax identity. Identities are an exception to the normal // normalization rules as they cannot be normalized using addons. diff --git a/tax/identity_test.go b/tax/identity_test.go index a18bcaa6..e3cef616 100644 --- a/tax/identity_test.go +++ b/tax/identity_test.go @@ -102,4 +102,13 @@ func TestIdentityNormalize(t *testing.T) { tID.Normalize() assert.Equal(t, tID.Code.String(), "39356000000") // adds 2 0s on end }) + t.Run("with calculate method", func(t *testing.T) { + tID := &tax.Identity{ + Country: "FR", + Code: " 356000000 ", + } + err := tID.Calculate() + assert.NoError(t, err) + assert.Equal(t, tID.Code.String(), "39356000000") + }) }