Module: Europe::Vat

Defined in:
lib/europe/vat/vat.rb,
lib/europe/vat/batch.rb,
lib/europe/vat/rates.rb,
lib/europe/vat/format.rb

Overview

VAT

Defined Under Namespace

Modules: Batch, Format, Rates

Constant Summary collapse

API_URL =
'https://ec.europa.eu/taxation_customs/vies/rest-api/check-vat-number'
HEADERS =
{
  'Content-Type' => 'application/json',
  'Accept' => 'application/json'
}.freeze
VIES_ERRORS =
{
  'INVALID_INPUT' => :invalid_input,
  'GLOBAL_MAX_CONCURRENT_REQ' => :rate_limited,
  'MS_MAX_CONCURRENT_REQ' => :rate_limited,
  'SERVICE_UNAVAILABLE' => :service_unavailable,
  'MS_UNAVAILABLE' => :ms_unavailable,
  'TIMEOUT' => :timeout
}.freeze

Class Method Summary collapse

Class Method Details

.batch_result(token) ⇒ Object



67
68
69
# File 'lib/europe/vat/vat.rb', line 67

def self.batch_result(token)
  Batch.result(token)
end

.batch_status(token) ⇒ Object



63
64
65
# File 'lib/europe/vat/vat.rb', line 63

def self.batch_status(token)
  Batch.status(token)
end

.batch_validate(vat_numbers, requester: nil) ⇒ Object



59
60
61
# File 'lib/europe/vat/vat.rb', line 59

def self.batch_validate(vat_numbers, requester: nil)
  Batch.validate(vat_numbers, requester: requester)
end

.charge_vat?(origin_country, number) ⇒ Boolean

Returns:

  • (Boolean)


97
98
99
100
101
102
# File 'lib/europe/vat/vat.rb', line 97

def self.charge_vat?(origin_country, number)
  return false if number.nil? || number.empty?

  Europe::Vat::Fromat::VAT_REGEX.key?(origin_country.to_sym) ||
    Europe::Vat::Fromat::VAT_REGEX.key?(number[0..1].to_sym)
end

.convert_date(date) ⇒ Object



91
92
93
94
95
# File 'lib/europe/vat/vat.rb', line 91

def self.convert_date(date)
  return unless date

  Date.parse(date)
end

.handle_error_response(response) ⇒ Object



71
72
73
74
75
76
77
# File 'lib/europe/vat/vat.rb', line 71

def self.handle_error_response(response)
  body = JSON.parse(response.body)
  error_code = body.dig('errorWrappers', 0, 'error')
  VIES_ERRORS[error_code] || :service_error
rescue JSON::ParserError
  :service_error
end

.send_request(country_code, number) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/europe/vat/vat.rb', line 104

def self.send_request(country_code, number)
  uri = URI.parse(API_URL)

  Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    request = Net::HTTP::Post.new(uri.request_uri, HEADERS)
    request.body = JSON.generate(
      countryCode: country_code,
      vatNumber: number
    )
    http.request(request)
  end
end

.setup_response(response) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
# File 'lib/europe/vat/vat.rb', line 79

def self.setup_response(response)
  body = JSON.parse(response.body)
  {
    valid: body['valid'] == true,
    country_code: body['countryCode'],
    vat_number: body['vatNumber'],
    request_date: convert_date(body['requestDate']),
    name: body['name'],
    address: body['address']
  }
end

.validate(number) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/europe/vat/vat.rb', line 30

def self.validate(number)
  return :invalid_input if number.size < 4

  response = send_request(number[0..1], number[2..-1])
  return handle_error_response(response) unless response.is_a?(Net::HTTPSuccess)

  setup_response(response)
rescue Net::OpenTimeout, Net::ReadTimeout
  :timeout
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, SocketError, OpenSSL::SSL::SSLError
  :service_unavailable
end

.validate_with_country_code(country_code, number) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/europe/vat/vat.rb', line 43

def self.validate_with_country_code(country_code, number)
  return :invalid_input if number.size < 4

  # Remove country code from number if it's present
  number = number[2..-1] if number[0..1].upcase.to_s == country_code.to_s

  response = send_request(country_code, number)
  return handle_error_response(response) unless response.is_a?(Net::HTTPSuccess)

  setup_response(response)
rescue Net::OpenTimeout, Net::ReadTimeout
  :timeout
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, SocketError, OpenSSL::SSL::SSLError
  :service_unavailable
end