-
Notifications
You must be signed in to change notification settings - Fork 0
/
tin.go
113 lines (96 loc) · 2.54 KB
/
tin.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
// Package tin contains the first function that a user will call to lookup a TIN number.
package tin
import (
"context"
"github.com/invopop/gobl.tin/api"
"github.com/invopop/gobl/bill"
"github.com/invopop/gobl/org"
"github.com/invopop/gobl/tax"
cmap "github.com/orcaman/concurrent-map/v2"
)
// Client encapsulates the TIN lookup logic.
type Client struct {
cache cmap.ConcurrentMap[string, bool]
}
// New creates a new Client instance.
func New() *Client {
return &Client{
cache: cmap.New[bool](),
}
}
// Lookup checks the validity of the TIN number
//
// There are three cases:
//
// 1. If the input is an invoice, it will check the TIN of the customer and supplier
//
// 2. If the input is a party, it will check the TIN of the party.
//
// 3. If the input is a tax ID, it will check the TIN.
func (c *Client) Lookup(ctx context.Context, in any) error {
// 3 cases: invoice, party or tax ID
switch in := in.(type) {
case *bill.Invoice:
return c.lookupInvoice(ctx, in)
case *org.Party:
return c.lookupParty(ctx, in)
case *tax.Identity:
return c.lookupTaxID(ctx, in)
default:
return ErrInput.WithMessage("invalid input type")
}
}
func (c *Client) lookupTaxID(ctx context.Context, tid *tax.Identity) error {
// check the cache
var response bool
var err error
var ok bool
key := tid.String()
if response, ok = c.cache.Get(key); !ok {
validator := api.GetLookupAPI(tid.Country)
if validator == nil {
return ErrNotSupported.WithMessage("country code not supported")
}
response, err = validator.LookupTIN(ctx, tid)
if err != nil {
return ErrNetwork.WithMessage(err.Error())
}
c.cache.Set(key, response)
}
if !response {
return ErrInvalid.WithMessage("TIN is invalid")
}
return nil
}
func (c *Client) lookupParty(ctx context.Context, party *org.Party) error {
tid := party.TaxID
if tid == nil {
return ErrInput.WithMessage("no tax ID provided")
}
return c.lookupTaxID(ctx, tid)
}
func (c *Client) lookupInvoice(ctx context.Context, inv *bill.Invoice) error {
customer := inv.Customer
if customer == nil {
return ErrInput.WithMessage("no customer found")
}
errCust := c.lookupParty(ctx, customer)
if errCust != nil {
if e, ok := errCust.(*Error); ok {
return e.WithMessage("Customer: " + e.Error())
}
return errCust
}
supplier := inv.Supplier
if supplier == nil {
return ErrInput.WithMessage("no supplier found")
}
errSupp := c.lookupParty(ctx, supplier)
if errSupp != nil {
if e, ok := errSupp.(*Error); ok {
return e.WithMessage("Supplier: " + e.Error())
}
return errSupp
}
return nil
}