Skip to content

Instantly share code, notes, and snippets.

@henrik
Last active May 15, 2020 07:26
Show Gist options
  • Save henrik/daf364fb7e22b3b10cad to your computer and use it in GitHub Desktop.
Save henrik/daf364fb7e22b3b10cad to your computer and use it in GitHub Desktop.
Validate Danish organization numbers (CVR). Uses https://github.com/barsoom/attr_extras.
# 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
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