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  }