git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/money/vat/rates.go (about) 1 package vat 2 3 import ( 4 "strings" 5 "time" 6 ) 7 8 var euCountries = []string{ 9 "BE", "BG", "CZ", "DK", "DE", "EE", "EL", "ES", "FR", "HR", "IE", 10 "IT", "CY", "LV", "LT", "LU", "HU", "MT", "NL", "AT", "PL", "PT", 11 "RO", "SI", "SK", "FI", "SE", // "UK", 12 } 13 14 // reference: 15 // http://ec.europa.eu/taxation_customs/resources/documents/taxation/vat/how_vat_works/rates/vat_rates_en.pdf 16 // last updated: Jan 1st, 2017 17 18 type Rates struct { 19 Since time.Time 20 Countries map[string]float64 21 } 22 23 var standardRates = []Rates{ 24 { 25 Since: since(2015, 3, 6), 26 Countries: map[string]float64{ 27 "BE": 21, 28 "BG": 20, 29 "CZ": 21, 30 "DK": 25, 31 "DE": 19, 32 "EE": 20, 33 "EL": 23, 34 "ES": 21, 35 "FR": 20, 36 "HR": 25, 37 "IE": 23, 38 "IT": 22, 39 "CY": 19, 40 "LV": 21, 41 "LT": 21, 42 "LU": 17, 43 "HU": 27, 44 "MT": 18, 45 "NL": 21, 46 "AT": 20, 47 "PL": 23, 48 "PT": 23, 49 "RO": 24, 50 "SI": 22, 51 "SK": 20, 52 "FI": 24, 53 "SE": 25, 54 // "UK": 20, 55 }, 56 }, 57 { 58 Since: since(2017, 1, 1), 59 Countries: map[string]float64{ 60 "EL": 24, 61 "RO": 19, 62 }, 63 }, 64 { 65 Since: since(2020, 7, 1), 66 Countries: map[string]float64{ 67 "DE": 16, 68 }, 69 }, 70 { 71 Since: since(2021, 1, 1), 72 Countries: map[string]float64{ 73 "DE": 19, 74 }, 75 }, 76 77 // add new rates at bottom ... 78 } 79 80 // StandardRate returns VAT rate in EU country at time.Now() 81 func StandardRate(countryCode string) (rate float64, ok bool) { 82 return StandardRateAtDate(countryCode, time.Now()) 83 } 84 85 // StandardRateAtDate returns VAT rate in EU country at given date 86 func StandardRateAtDate(countryCode string, date time.Time) (rate float64, ok bool) { 87 return find(standardRates, strings.ToUpper(countryCode), date) 88 } 89 90 // find finds rate in given []Rate slice 91 func find(rates []Rates, countryCode string, date time.Time) (rate float64, ok bool) { 92 // TODO: order by Since field 93 for i := len(rates) - 1; i >= 0; i-- { 94 if date.After(rates[i].Since) { 95 if rate, ok := rates[i].Countries[countryCode]; ok { 96 return rate, true 97 } 98 } 99 } 100 return 0, false 101 } 102 103 // Countries returns a list of all EU countries 104 func Countries() []string { 105 return euCountries 106 } 107 108 // IsEUCountry returns true if countryCode is EU country 109 func IsEUCountry(countryCode string) bool { 110 for _, c := range euCountries { 111 if c == strings.ToUpper(countryCode) { 112 return true 113 } 114 } 115 return false 116 } 117 118 // since is a helper returning time.Time for Year, Month, Day 119 func since(year, month, day int) time.Time { 120 return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC) 121 }