Created
June 27, 2019 10:03
-
-
Save henrik/bedf70f301e48512334263120c89e220 to your computer and use it in GitHub Desktop.
Validate Spanish NIFs ("CIFs") in Ruby.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# By "organization number" we mean an organization NIF (Spanish tax identification number). We don't mean personal NIFs such as DNI/NIE (see `SpanishIdentityNumber` for that). | |
# | |
# This class also supports personal NIFs starting with the letters K, L or M, though it's inaccurate to call these "organization numbers". More about these: https://translate.google.co.uk/translate?sl=auto&tl=en&u=https%3A%2F%2Fes.wikipedia.org%2Fwiki%2FN%25C3%25BAmero_de_identificaci%25C3%25B3n_fiscal | |
# | |
# It's easier to support them than not to, and means that any such users can provide this number, even though it's represented a bit inaccurately in our system. They're likely to be very rare. Feel free to think up a way to represent it more accurately. (Renaming `spanish_organization_number` to something like `non_dni_or_nie_spanish_tax_identification_number`?) | |
class SpanishOrganizationNumber | |
# NIFs do not have the letter prefixes "I" and "O" since those can be confused for the digits "1" and "0". | |
# Don't know why "T" is not a prefix. | |
# "X", "Y" and "Z" are NIE prefixes, so they're not used for NIFs that are not NIEs. | |
RE = /\A[ABCDEFGHIJKLMNOPQRSUVW]\d{7}[\dA-Z]\z/ | |
PREFIXES_THAT_HAVE_A_LETTER_AS_CHECK_SUM = %w[ N P Q R S W ] | |
def self.valid?(number) | |
number = number.to_s.upcase.strip | |
return false unless number.match?(RE) | |
central_digits = number[1, 7] | |
sum = central_digits.each_char.with_index.sum { |digit_string, zero_based_index| | |
digit = digit_string.to_i | |
index = zero_based_index + 1 | |
if index.odd? | |
double = digit * 2 | |
(double / 10) + (double % 10) | |
else | |
digit | |
end | |
} | |
digit = (10 - sum.to_s.last.to_i) | |
digit = 0 if digit == 10 | |
check_sum = | |
if PREFIXES_THAT_HAVE_A_LETTER_AS_CHECK_SUM.include?(number[0]) | |
"JABCDEFGHI"[digit] | |
else | |
digit.to_s | |
end | |
number[-1] == check_sum | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "spec_helper" | |
require "spanish_organization_number" | |
describe SpanishOrganizationNumber, ".valid?" do | |
it "is true for a valid organization NIF" do | |
expect(SpanishOrganizationNumber.valid?("B08670408")).to be true | |
expect(SpanishOrganizationNumber.valid?("Q5355054G")).to be true | |
end | |
it "is false for a NIF that doesn't match the checksum" do | |
expect(SpanishOrganizationNumber.valid?("B08670409")).to be false | |
end | |
it "is false for a NIF with an invalid prefix letter" do | |
expect(SpanishOrganizationNumber.valid?("T08670408")).to be false | |
end | |
it "is false for a number that doesn't match the format at all" do | |
expect(SpanishOrganizationNumber.valid?("ABC123")).to be false | |
end | |
it "is false for nil" do | |
expect(SpanishOrganizationNumber.valid?(nil)).to be false | |
end | |
it "is false for the empty string" do | |
expect(SpanishOrganizationNumber.valid?("")).to be false | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment