Skip to content

Instantly share code, notes, and snippets.

@aleonjob
Last active March 3, 2017 11:33
Show Gist options
  • Save aleonjob/cae2d536dda09bc2c3131e99666347eb to your computer and use it in GitHub Desktop.
Save aleonjob/cae2d536dda09bc2c3131e99666347eb to your computer and use it in GitHub Desktop.
Spanish VAT Validator for Rails
# Add this file to the config/initializers folder
#
# Use:
# class Entity < ActiveRecord::Base
# validates :vat_number, spanish_vat: true
# end
class SpanishVatValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless validate_vat(value)
record.errors[attribute] <<
(options[:message] ||
I18n.t('activerecord.errors.messages.invalid_document_number', default: 'Invalid document number'))
end
end
def validate_vat(passed_value)
return false if passed_value.nil?
value = passed_value.clone
case
when value.match(/[0-9]{8}[a-z]/i)
validate_nif(value)
when value.match(/[a-wyz][0-9]{7}[0-9a-z]/i)
validate_cif(value)
when value.match(/[x][0-9]{7,8}[a-z]/i)
validate_nie(value)
else
false
end
end
# Validates NIF
def validate_nif(value)
letters = "TRWAGMYFPDXBNJZSQVHLCKE"
check = value.slice!(value.length - 1..value.length - 1).upcase
calculated_letter = letters[value.to_i % 23].chr
check === calculated_letter
end
# Validates CIF
def validate_cif(value)
letter = value.slice!(0).chr.upcase
check = value.slice!(value.length - 1).chr.upcase
n1 = n2 = 0
for idx in 0..value.length - 1
number = value.slice!(0).chr.to_i
if (idx % 2) != 0
n1 += number
else
n2 += ((2*number) % 10) + ((2 * number) / 10)
end
end
calculated_number = (10 - ((n1 + n2) % 10)) % 10
calculated_letter = (64 + calculated_number).chr
if letter.match(/[QPNSW]/)
check.to_s == calculated_letter.to_s
else
check.to_i == calculated_number.to_i
end
end
# Validates NIE, in fact is a fake, a NIE is really a NIF with first number changed to capital 'X' letter, so we change the first X to a 0 and then try to
# pass the nif validator
def validate_nie(value)
value[0] = '0'
value.slice(0) if value.size > 9
validate_nif(value)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment