Last active
May 15, 2020 07:26
-
-
Save henrik/daf364fb7e22b3b10cad to your computer and use it in GitHub Desktop.
Validate Danish organization numbers (CVR). Uses https://github.com/barsoom/attr_extras.
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
# Danish "CVR-nummer". | |
# | |
# A 7 digit serial number followed by a mod-11 check digit: | |
# https://erhvervsstyrelsen.dk/modulus-11-kontrol | |
# | |
# Search for real CVRs, to see examples: https://datacvr.virk.dk/data/ | |
# E.g. 35408002, 30715063. | |
class DanishOrganizationNumber | |
MOD_11_WEIGHTS = [ 2, 7, 6, 5, 4, 3, 2 ] | |
pattr_initialize :string | |
def valid? | |
return false unless string.match(/\A[\s\d-]+\z/) | |
return false unless digits.length == 8 | |
return false unless valid_check_digit? | |
true | |
end | |
private | |
def valid_check_digit? | |
serial = digits[0, 7] | |
expected_check_digit = digits[-1] | |
weighted_serials = serial.zip(MOD_11_WEIGHTS).map { |digit, weight| digit * weight } | |
mod = weighted_serials.sum % 11 | |
actual_check_digit = mod == 0 ? 0 : 11 - mod | |
actual_check_digit == expected_check_digit | |
end | |
def digits | |
@digits ||= string.to_s.gsub(/\D/, "").chars.map(&:to_i) | |
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 "danish_organization_number" | |
describe DanishOrganizationNumber, "#valid?" do | |
it "is true for an 8-digit string with valid check digit" do | |
expect_valid "35408002" | |
end | |
it "accounts for the special case of a 0 check digit" do | |
expect_valid "25472020" | |
end | |
it "allows '-' separators" do | |
expect_valid "35-40-80-02" | |
end | |
it "allows whitespace separators" do | |
expect_valid " 35 40 80 02" | |
end | |
it "does not allow extra text" do | |
expect_invalid "foo 35408002 bar" | |
end | |
it "rejects too-short strings" do | |
expect_invalid "123" | |
end | |
it "rejects strings with invalid check digit" do | |
expect_invalid "35408003" | |
end | |
# Let's validate some real examples to make sure we got it right. | |
# From: https://datacvr.virk.dk/data/ | |
%w[ 37272884 25555619 21459895 35408002 ].each do |number| | |
it "accepts real-life number #{number}" do | |
expect_valid number | |
end | |
end | |
private | |
def expect_valid(number) | |
expect(DanishOrganizationNumber.new(number).valid?).to be_true | |
end | |
def expect_invalid(number) | |
expect(DanishOrganizationNumber.new(number).valid?).to be_false | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment