Skip to content

Instantly share code, notes, and snippets.

@jarthod
Last active April 26, 2022 19:35
Show Gist options
  • Save jarthod/865b52fa388bbad53da695aa92b4be2a to your computer and use it in GitHub Desktop.
Save jarthod/865b52fa388bbad53da695aa92b4be2a to your computer and use it in GitHub Desktop.
EU VAT rates in ruby (2020) + online fetcher to verify/update rates.
module VAT
RATES = {
"AT" => 20.0,
"BE" => 21.0,
"BG" => 20.0,
"CY" => 19.0,
"CZ" => 21.0,
"DE" => 19.0,
"DK" => 25.0,
"EE" => 20.0,
"ES" => 21.0,
"FI" => 24.0,
"FR" => 20.0,
"GB" => 20.0, # not in online rates any more since Brexit
"GR" => 24.0,
"HR" => 25.0,
"HU" => 27.0,
"IE" => 23.0,
"IT" => 22.0,
"LT" => 21.0,
"LU" => 17.0,
"LV" => 21.0,
"MT" => 18.0,
"NL" => 21.0,
"PL" => 23.0,
"PT" => 23.0,
"RO" => 19.0,
"SE" => 25.0,
"SI" => 22.0,
"SK" => 20.0,
}.freeze
# updated twice a year - January & July
def self.online_rates
# https://github.com/VvanGemert/europe/blob/master/lib/europe/vat/rates.rb
require 'rexml/document'
require 'net/http'
resp = Net::HTTP.get_response(URI.parse('https://europa.eu/youreurope/business/taxation/vat/vat-rules-rates/index_en.htm'))
if resp.code.to_i == 200
rates = {}
data = resp.body.scan(%r{\<tbody\>(.*)\<\/tbody\>}m).first.first.strip
xml = REXML::Document.new("<root>#{data}</root>")
xml.first.elements.each('tr') do |result|
next if result[3].nil?
country = result[3].text.strip
next if country == ""
rate = result[5].text
# converting to ISO 3166
country = "GR" if country == "EL"
rates[country] = rate.to_f if country
end
rates
end
rescue Errno::ECONNRESET
nil
end
end
require 'rails_helper'
describe VAT do
it "uses ISO 3166-1 code" do
expect(VAT::RATES.keys).to match_array(ISO3166::Country.codes & VAT::RATES.keys)
expect(VAT::RATES['GB']).to be > 15 # GB instead of UK
expect(VAT::RATES['GR']).to be > 15 # GR instead of EL
end
it "matches countries gem rates" do
ISO3166::Country.codes.each do |code|
country = ISO3166::Country[code]
if country.in_eu? || code == "GB"
expect(VAT::RATES[code]).to eq country.vat_rates&.dig('standard')
else # Only care about Europe so far
expect(VAT::RATES[code]).to be_nil
end
end
end
it "matches online rates (+GB manually)", :requires_internet do
WebMock.allow_net_connect!
reference = VAT::online_rates
skip "Couldn't fetch online rates" if reference.nil?
expect(VAT::RATES).to eq(reference.merge("GB" => 20.0))
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment