lib/active_model/validations/vat_id_validator.rb
# encoding: UTF-8
require 'active_model/validator'
require 'active_support/core_ext/object/blank'
# Namespace module.
module ActiveModel
# Namespace module.
module Validations
# Validator for VAT-ID based on ActiveModel::EachValidator.
class VatIdValidator < ::ActiveModel::EachValidator
# All Countries with the vat pattern
VAT_PATTERNS = {
'AL' => /\AAL(J|K)[0-9]{8}[A-Z]\Z/, # Albania
'AR' => /\AAR[0-9]{11}\Z/, # Argentina
'AT' => /\AATU[0-9]{8}\Z/, # Austria
'AU' => /\AAU[0-9]{9}\Z/, # Australia
'BE' => /\ABE0[0-9]{9}\Z/, # Belgium
'BG' => /\ABG[0-9]{9,10}\Z/, # Bulgaria
'BO' => /\ABO/, # Bolivia
'BR' => /\ABR[0-9]{8}\Z/, # Brasil
'BY' => /\ABY[0-9]{9}\Z/, # Belarus
'CA' => /\ACA[0-9]{15}\Z/, # Canada
'CH' => /\ACHE[0-9]{9}(MWST|TVA|IVA)\Z/, # Switzerland
'CL' => /\ACL[0-9]{9}\Z/, # Chile
'CO' => /\ACO[0-9]{10}\Z/, # Colombia
'CR' => /\ACR/, # Costa Rica
'CY' => /\ACY[0-9]{8}[A-Z]\Z/, # Cyprus
'CZ' => /\ACZ[0-9]{8,10}\Z/, # Czech Republic
'DE' => /\ADE[0-9]{9}\Z/, # Germany
'DK' => /\ADK[0-9]{8}\Z/, # Denmark
'DO' => /\ADO/, # Dominican Republic
'EC' => /\AEC[0-9]{13}\Z/, # Ecuador
'EE' => /\AEE[0-9]{9}\Z/, # Estonia
'EL' => /\AEL[0-9]{9}\Z/, # Greece
'ES' => /\AES([A-Z][0-9]{8}|[0-9]{8}[A-Z]|[A-Z][0-9]{7}[A-Z])\Z/, # Spain
'FI' => /\AFI[0-9]{8}\Z/, # Finland
'FR' => /\AFR[A-Z0-9]{2}[0-9]{9}\Z/, # France
'GB' => /\AGB([0-9]{9}|[0-9]{12}|(HA|GD)[0-9]{3})\Z/, # United Kingdom
'GT' => /\AGT[0-9]{8}\Z/, # Guatemala
'HN' => /\AHN/, # Honduras
'HR' => /\AHR[0-9]{11}\Z/, # Croatia
'HU' => /\AHU[0-9]{8}\Z/, # Hungary
'IE' => /\AIE([0-9][A-Z][0-9]{5}|[0-9]{7})[A-Z]{1,2}\Z/, # Ireland
'IT' => /\AIT[0-9]{11}\Z/, # Italy
'LT' => /\ALT([0-9]{9}|[0-9]{12})\Z/, # Lithuania
'LU' => /\ALU[0-9]{8}\Z/, # Luxembourg
'LV' => /\ALV[0-9]{11}\Z/, # Latvia
'MT' => /\AMT[0-9]{8}\Z/, # Malta
'MX' => /\AMX[0-9]{12}\Z/, # Mexico
'NI' => /\ANI/, # Nicaragua
'NL' => /\ANL[0-9]{9}B[0-9]{2}\Z/, # Netherlands
'NO' => /\ANO[0-9]{9}\Z/, # Norway
'PA' => /\APA/, # Panama
'PE' => /\APE/, # Peru
'PH' => /\APH[0-9]{12}\Z/, # Philippines
'PL' => /\APL[0-9]{10}\Z/, # Poland
'PT' => /\APT[0-9]{9}\Z/, # Portugal
'PY' => /\APY/, # Paraguay
'RO' => /\ARO[1-9][0-9]{1,9}\Z/, # Romania
'RU' => /\ARU[0-9]{10}\Z/, # Russia
'SE' => /\ASE[0-9]{10}01\Z/, # Sweden
'SI' => /\ASI[0-9]{8}\Z/, # Slovenia
'SK' => /\ASK[0-9]{10}\Z/, # Slovakia
'SM' => /\ASM[0-9]{5}\Z/, # San Marino
'SV' => /\ASV/, # El Salvador
'TR' => /\ATR[0-9]{10}\Z/, # Turkey
'UA' => /\AUA[0-9]{12}\Z/, # Ukraine
'UY' => /\AUY/, # Uruguay
'VE' => /\AVE(J|G|V|E)[0-9]{9}\Z/ # Venezuela
}.freeze
# Validates an attribute of a record if it contains a valid VAT-ID.
#
# If it does not, an error is added for that attribute to the record's errors array.
#
# @param [#errors] record The record which is validated.
# @param [Symbol] attribute The record's attribute which is validated.
# @param [String, nil] value The value which is supposed to be a VAT-ID.
def validate_each(record, attribute, value)
if value.present?
value = value.gsub(/[^A-z0-9]/, '').upcase
country_code = value[0..1]
record.errors.add(attribute, :invalid) unless value =~ VAT_PATTERNS[country_code]
end
end
end
end
end