-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathrates.go
121 lines (109 loc) · 2.43 KB
/
rates.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
package vat
import (
"strings"
"time"
)
var euCountries = []string{
"BE", "BG", "CZ", "DK", "DE", "EE", "EL", "ES", "FR", "HR", "IE",
"IT", "CY", "LV", "LT", "LU", "HU", "MT", "NL", "AT", "PL", "PT",
"RO", "SI", "SK", "FI", "SE", "UK",
}
// reference:
// http://ec.europa.eu/taxation_customs/resources/documents/taxation/vat/how_vat_works/rates/vat_rates_en.pdf
// last updated: Jan 1st, 2017
type Rates struct {
Since time.Time
Countries map[string]float64
}
var standardRates = []Rates{
{
Since: since(2015, 3, 6),
Countries: map[string]float64{
"BE": 21,
"BG": 20,
"CZ": 21,
"DK": 25,
"DE": 19,
"EE": 20,
"EL": 23,
"ES": 21,
"FR": 20,
"HR": 25,
"IE": 23,
"IT": 22,
"CY": 19,
"LV": 21,
"LT": 21,
"LU": 17,
"HU": 27,
"MT": 18,
"NL": 21,
"AT": 20,
"PL": 23,
"PT": 23,
"RO": 24,
"SI": 22,
"SK": 20,
"FI": 24,
"SE": 25,
"UK": 20,
},
},
{
Since: since(2017, 1, 1),
Countries: map[string]float64{
"EL": 24,
"RO": 19,
},
},
{
Since: since(2020, 7, 1),
Countries: map[string]float64{
"DE": 16,
},
},
{
Since: since(2021, 1, 1),
Countries: map[string]float64{
"DE": 19,
},
},
// add new rates at bottom ...
}
// StandardRate returns VAT rate in EU country at time.Now()
func StandardRate(countryCode string) (rate float64, ok bool) {
return StandardRateAtDate(countryCode, time.Now())
}
// StandardRateAtDate returns VAT rate in EU country at given date
func StandardRateAtDate(countryCode string, date time.Time) (rate float64, ok bool) {
return find(standardRates, strings.ToUpper(countryCode), date)
}
// find finds rate in given []Rate slice
func find(rates []Rates, countryCode string, date time.Time) (rate float64, ok bool) {
// TODO: order by Since field
for i := len(rates) - 1; i >= 0; i-- {
if date.After(rates[i].Since) {
if rate, ok := rates[i].Countries[countryCode]; ok {
return rate, true
}
}
}
return 0, false
}
// Countries returns a list of all EU countries
func Countries() []string {
return euCountries
}
// IsEUCountry returns true if countryCode is EU country
func IsEUCountry(countryCode string) bool {
for _, c := range euCountries {
if c == strings.ToUpper(countryCode) {
return true
}
}
return false
}
// since is a helper returning time.Time for Year, Month, Day
func since(year, month, day int) time.Time {
return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
}