Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing IVA tax codes for individuals and foreign business #25

Merged
merged 3 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: "1.20.4"
go-version: "1.21.5"
id: go

- name: Check out code
Expand Down
14 changes: 12 additions & 2 deletions address.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package fatturapa

import (
"github.com/invopop/gobl/l10n"
"github.com/invopop/gobl/org"
)

const (
foreignCAP = "00000"
)

// address from IndirizzoType
type address struct {
Indirizzo string // Street
Expand All @@ -15,14 +20,19 @@ type address struct {
}

func newAddress(addr *org.Address) *address {
return &address{
ad := &address{
Indirizzo: addressStreet(addr),
NumeroCivico: addr.Number,
CAP: addr.Code,
Comune: addr.Locality,
Provincia: addr.Region,
Nazione: addr.Country.String(),
}
if addr.Country == l10n.IT {
ad.CAP = addr.Code
} else {
ad.CAP = foreignCAP
}
return ad
}

func addressStreet(address *org.Address) string {
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module github.com/invopop/gobl.fatturapa

go 1.19
go 1.20

require (
github.com/invopop/gobl v0.67.0
github.com/invopop/gobl v0.67.3
github.com/invopop/xmldsig v0.8.0
github.com/magefile/mage v1.14.0
github.com/spf13/cobra v1.7.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ 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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/invopop/gobl v0.67.0 h1:9c28iBunAWYUILIMGkx1zFH/cC5srH5wp9pAb4223MA=
github.com/invopop/gobl v0.67.0/go.mod h1:Jau+ajdfUCBPVH9VMor6aeYq3S9o7HuSNm07QxxxomE=
github.com/invopop/gobl v0.67.3 h1:My3e65q+ERZVBEtksjV3nMs5nw+wlOohe8Jptf6vKwA=
github.com/invopop/gobl v0.67.3/go.mod h1:Jau+ajdfUCBPVH9VMor6aeYq3S9o7HuSNm07QxxxomE=
github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/invopop/validation v0.3.0 h1:o260kbjXzoBO/ypXDSSrCLL7SxEFUXBsX09YTE9AxZw=
Expand Down
5 changes: 2 additions & 3 deletions items.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"strconv"

"github.com/invopop/gobl/bill"
"github.com/invopop/gobl/cbc"
"github.com/invopop/gobl/i18n"
"github.com/invopop/gobl/regimes/it"
"github.com/invopop/gobl/tax"
Expand Down Expand Up @@ -119,9 +118,9 @@ func extractLinePriceAdjustments(line *bill.Line) []*scontoMaggiorazione {
func findRiferimentoNormativo(rateTotal *tax.RateTotal) string {
def := regime.ExtensionDef(it.ExtKeySDINature)

nature := rateTotal.Ext[it.ExtKeySDINature]
nature := rateTotal.Ext[it.ExtKeySDINature].Code()
for _, c := range def.Codes {
if c.Code == cbc.Code(nature) {
if c.Code == nature {
return c.Name[i18n.IT]
}
}
Expand Down
20 changes: 12 additions & 8 deletions parties.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
)

const (
statoLiquidazioneDefault = "LN"
euCitizenTaxCodeDefault = "0000000"
nonEUCitizenTaxCodeDefault = "99999999999"
statoLiquidazioneDefault = "LN"
nonITCitizenTaxCodeDefault = "0000000"
nonEUBusinessTaxCodeDefault = "OO99999999999"
)

type supplier struct {
Expand Down Expand Up @@ -111,10 +111,8 @@ func newCessionarioCommittente(c *org.Party) *customer {
if c.TaxID != nil {
if isCodiceFiscale(c.TaxID) {
da.CodiceFiscale = c.TaxID.Code.String()
} else if isEUCountry(c.TaxID.Country) {
da.IdFiscaleIVA = customerFiscaleIVA(c.TaxID, euCitizenTaxCodeDefault)
} else {
da.IdFiscaleIVA = customerFiscaleIVA(c.TaxID, nonEUCitizenTaxCodeDefault)
da.IdFiscaleIVA = customerFiscaleIVA(c.TaxID)
}
}

Expand Down Expand Up @@ -153,11 +151,17 @@ func newContatti(party *org.Party) *contatti {
return c
}

func customerFiscaleIVA(id *tax.Identity, fallBack string) *taxID {
func customerFiscaleIVA(id *tax.Identity) *taxID {
idCodice := id.Code.String()

if idCodice == "" {
idCodice = fallBack
// Assume private individual
idCodice = nonITCitizenTaxCodeDefault
} else {
// Must be a company with a local tax ID
if !isEUCountry(id.Country) {
idCodice = nonEUBusinessTaxCodeDefault
}
}

return &taxID{
Expand Down
6 changes: 3 additions & 3 deletions parties_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func TestPartiesCustomer(t *testing.T) {
assert.Equal(t, "0000000", c.DatiAnagrafici.IdFiscaleIVA.IdCodice)
})

t.Run("should contain customer info for non-EU citizen with Tax ID given", func(t *testing.T) {
t.Run("should replace customer ID info for non-EU citizen with Tax ID given", func(t *testing.T) {
env := test.LoadTestFile("invoice-simple.json")
test.ModifyInvoice(env, func(inv *bill.Invoice) {
inv.Customer.TaxID.Code = "09823876432"
Expand All @@ -129,7 +129,7 @@ func TestPartiesCustomer(t *testing.T) {
c := doc.FatturaElettronicaHeader.CessionarioCommittente

assert.Equal(t, "GB", c.DatiAnagrafici.IdFiscaleIVA.IdPaese)
assert.Equal(t, "09823876432", c.DatiAnagrafici.IdFiscaleIVA.IdCodice)
assert.Equal(t, "OO99999999999", c.DatiAnagrafici.IdFiscaleIVA.IdCodice)
})

t.Run("should contain customer info for non-EU citizen with no Tax ID given", func(t *testing.T) {
Expand All @@ -145,7 +145,7 @@ func TestPartiesCustomer(t *testing.T) {
c := doc.FatturaElettronicaHeader.CessionarioCommittente

assert.Equal(t, "JP", c.DatiAnagrafici.IdFiscaleIVA.IdPaese)
assert.Equal(t, "99999999999", c.DatiAnagrafici.IdFiscaleIVA.IdCodice)
assert.Equal(t, "0000000", c.DatiAnagrafici.IdFiscaleIVA.IdCodice)
})

t.Run("should not fail if missing key data", func(t *testing.T) {
Expand Down
141 changes: 141 additions & 0 deletions test/data/invoice-hotel-private.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{
"$schema": "https://gobl.org/draft-0/envelope",
"head": {
"uuid": "679a2f25-7483-11ec-9722-7ea2cb436ff6",
"dig": {
"alg": "sha256",
"val": "AAAA"
}
},
"doc": {
"$schema": "https://gobl.org/draft-0/bill/invoice",
"type": "standard",
"series": "SAMPLE",
"code": "003",
"issue_date": "2023-05-21",
"currency": "EUR",
"tax": {
"prices_include": "VAT"
},
"supplier": {
"name": "Hotel California",
"tax_id": {
"country": "IT",
"code": "12345678903"
},
"addresses": [
{
"num": "102",
"street": "Via California",
"locality": "Palermo",
"region": "PA",
"code": "33213",
"country": "IT"
}
],
"registration": {
"currency": "EUR",
"office": "RM",
"entry": "123456"
}
},
"customer": {
"name": "Random Person",
"tax_id": {
"country": "GB"
},
"addresses": [
{
"num": "23",
"street": "Main Street",
"locality": "London",
"code": "W1 A2",
"country": "GB"
}
]
},
"lines": [
{
"i": 1,
"quantity": "1",
"item": {
"name": "Tassa di Soggiorno",
"price": "1.00"
},
"sum": "1.00",
"taxes": [
{
"cat": "VAT",
"rate": "exempt",
"ext": {
"it-sdi-nature": "N1"
}
}
],
"total": "1.00"
},
{
"i": 2,
"quantity": "1",
"item": {
"name": "Camera Matrimoniale",
"price": "125.00"
},
"sum": "125.00",
"taxes": [
{
"cat": "VAT",
"rate": "intermediate",
"percent": "10.0%"
}
],
"total": "125.00"
}
],
"payment": {
"advances": [
{
"date": "2023-05-01",
"key": "card",
"desc": "deposit",
"amount": "29.00"
}
]
},
"totals": {
"sum": "126.00",
"tax_included": "11.36",
"total": "114.64",
"taxes": {
"categories": [
{
"code": "VAT",
"rates": [
{
"key": "exempt",
"ext": {
"it-sdi-nature": "N1"
},
"base": "1.00",
"amount": "0.00"
},
{
"key": "intermediate",
"base": "113.6364",
"percent": "10.0%",
"amount": "11.3636"
}
],
"amount": "11.3636"
}
],
"sum": "11.3636"
},
"tax": "11.36",
"total_with_tax": "126.00",
"payable": "126.00",
"advance": "29.00",
"due": "97.00"
}
}
}
Loading