-
Notifications
You must be signed in to change notification settings - Fork 2
/
parties.go
217 lines (187 loc) · 5.73 KB
/
parties.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package fatturapa
import (
"github.com/invopop/gobl/addons/it/sdi"
"github.com/invopop/gobl/cbc"
"github.com/invopop/gobl/l10n"
"github.com/invopop/gobl/org"
"github.com/invopop/gobl/regimes/it"
"github.com/invopop/gobl/tax"
)
const (
statoLiquidazioneDefault = "LN"
nonITCitizenTaxCodeDefault = "0000000"
nonEUBusinessTaxCodeDefault = "OO99999999999"
)
// Supplier describes the seller/provider of the invoice.
type Supplier struct {
Identity *Identity `xml:"DatiAnagrafici"`
Address *Address `xml:"Sede"`
PermanentEstablishment *PermanentEstablishment `xml:"StabileOrganizzazione,omitempty"`
Registration *Registration `xml:"IscrizioneREA,omitempty"`
Contact *Contact `xml:"Contatti,omitempty"`
}
// Customer contains the details about who the invoice is addressed to.
type Customer struct {
Identity *Identity `xml:"DatiAnagrafici"`
Address *Address `xml:"Sede"`
}
// Identity (DatiAnagrafici) contains information related to an individual or company
type Identity struct {
TaxID *TaxID `xml:"IdFiscaleIVA,omitempty"` // nolint:revive
FiscalCode string `xml:"CodiceFiscale,omitempty"`
Profile *Profile `xml:"Anagrafica"`
// FiscaleRegime identifies the tax system to be applied
// Has the form RFXX where XX is numeric; required only for the supplier
FiscalRegime string `xml:"RegimeFiscale,omitempty"`
}
// TaxID is the VAT identification number consisting of a country code and the
// actual VAT number.
type TaxID struct {
Country string `xml:"IdPaese"` // ISO 3166-1 alpha-2 country code
Code string `xml:"IdCodice"`
}
// PermanentEstablishment (StabileOrganizzazione) to be filled in if the seller/provider
// is not resident, but has a permanent establishment in Italy
type PermanentEstablishment struct {
Street string `xml:"Indirizzo"`
Number string `xml:"NumeroCivico,omitempty"`
PostCode string `xml:"CAP"`
Locality string `xml:"Comune"`
Region string `xml:"Provincia,omitempty"` // Province initials (2 characters) for IT country
Country string `xml:"Nazione"` // Country code ISO alpha-2
}
// Profile contains identity data of the seller/provider
type Profile struct {
// Name of the organization
Name string `xml:"Denominazione,omitempty"`
// Natural person's first or given name if no "Denominazione" is provided
Given string `xml:"Nome,omitempty"`
// Surname of the person
Surname string `xml:"Cognome,omitempty"`
// Title of the person
Title string `xml:"Titolo,omitempty"`
// EORI (Economic Operator Registration and Identification) code
EORI string `xml:"CodEORI,omitempty"`
}
// Registration contains information related to the company registration details (REA)
type Registration struct {
// Initials of the province where the company's Registry Office is located
Office string `xml:"Ufficio,omitempty"`
// Company's REA registration number
Entry string `xml:"NumeroREA,omitempty"`
// Company's share capital
Capital string `xml:"CapitaleSociale,omitempty"`
// Indication of whether the Company is in liquidation or not.
// Possible values: LS (in liquidation), LN (not in liquidation)
LiquidationState string `xml:"StatoLiquidazione,omitempty"`
}
// Contact describes how the party can be contacted
type Contact struct {
Telephone string `xml:"Telefono,omitempty"`
Email string `xml:"Email,omitempty"`
}
func newSupplier(s *org.Party) *Supplier {
ns := &Supplier{
Identity: &Identity{
TaxID: &TaxID{
Country: s.TaxID.Country.String(),
Code: s.TaxID.Code.String(),
},
Profile: newProfile(s),
},
Registration: newRegistration(s),
Contact: newContact(s),
}
if v, ok := s.Ext[sdi.ExtKeyFiscalRegime]; ok {
ns.Identity.FiscalRegime = v.String()
} else {
ns.Identity.FiscalRegime = "RF01"
}
if len(s.Addresses) > 0 {
ns.Address = newAddress(s.Addresses[0])
}
return ns
}
func newCustomer(c *org.Party) *Customer {
if c == nil {
return nil
}
nc := new(Customer)
if len(c.Addresses) > 0 {
nc.Address = newAddress(c.Addresses[0])
}
da := &Identity{
Profile: newProfile(c),
}
if c.TaxID != nil {
da.TaxID = customerTaxID(c.TaxID)
}
if id := org.IdentityForKey(c.Identities, it.IdentityKeyFiscalCode); id != nil {
da.FiscalCode = id.Code.String()
}
nc.Identity = da
return nc
}
func newProfile(party *org.Party) *Profile {
if party.TaxID == nil || party.TaxID.Code == cbc.CodeEmpty {
// not a company
if len(party.People) > 0 {
name := party.People[0].Name
return &Profile{
Given: name.Given,
Surname: name.Surname,
Title: name.Prefix,
}
}
}
return &Profile{
Name: party.Name,
}
}
func newContact(party *org.Party) *Contact {
c := new(Contact)
if len(party.Emails) > 0 {
c.Email = party.Emails[0].Address
}
if len(party.Telephones) > 0 {
c.Telephone = party.Telephones[0].Number
}
return c
}
func customerTaxID(id *tax.Identity) *TaxID {
code := id.Code.String()
if code == "" {
if id.Country.Code() == l10n.IT {
return nil
}
// Assume private individual
code = nonITCitizenTaxCodeDefault
} else {
// Must be a company with a local tax ID
if !isEUCountry(id.Country.Code()) {
code = nonEUBusinessTaxCodeDefault
}
}
return &TaxID{
Country: id.Country.String(),
Code: code,
}
}
func newRegistration(supplier *org.Party) *Registration {
if supplier.Registration == nil {
return nil
}
capital := supplier.Registration.Capital
var capitalFormatted string
if capital == nil {
capitalFormatted = ""
} else {
capitalFormatted = capital.Rescale(2).String()
}
return &Registration{
Office: supplier.Registration.Office,
Entry: supplier.Registration.Entry,
Capital: capitalFormatted,
LiquidationState: statoLiquidazioneDefault,
}
}