Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # coding: utf-8
- class NorwegianBankAccount
- # Pass me any kind of string representing an account number
- def initialize(str)
- @numbers = str.gsub(/[^\d]/,'')
- end
- # Prettified output
- def to_s
- begin
- parts = @numbers.split(//)
- formatted = [parts[0,4].join(""), parts[4,2].join(""), parts[6,5].join("")].join(".")
- formatted
- rescue => e
- "##{self.class.name}<#{@numbers}> (#{e})"
- end
- end
- # Validation combo. Using a tuple as return value, in true Golang fashion
- def valid?
- if @numbers.length != 11
- return false, "Needs to be 11 digits"
- end
- if !mod_11_control(@numbers, [5,4,3,2,7,6,5,4,3,2])
- return false, "Invalid checksum"
- end
- return true, nil
- end
- # Validate an account number using mod 11 with multiplication factors.
- # Includes check digit for simplicity (ie 11 digits as input)
- def mod_11_control(account_number, factors)
- account_parts = account_number.split(//)
- account_digits = account_parts[0,10].map(&:to_i)
- sum = 0
- account_digits.each_with_index do |n, i|
- s = n * factors[i]
- sum += (n * factors[i])
- end
- check_digit = account_parts[10].to_i
- remainder = sum % 11
- expected_check_digit = case remainder
- when 0 then remainder
- when 1 then nil
- else 11- remainder
- end
- return check_digit == expected_check_digit
- end
- end
- class PaymentCardRecognizer
- def self.recognize_account_number(blocks)
- candidates = []
- blocks.each do |b|
- without_spaces = b.gsub(/[\s_]/,"")
- number_re = /KONTONR\.(?<account>\d{11})/
- matches = number_re.match(without_spaces)
- if matches
- candidates << matches[:account]
- end
- end
- result = candidates.first
- account = NorwegianBankAccount.new(result)
- if account.valid?
- return account.to_s
- end
- end
- end
- # Unittest built in, skip for production
- require 'minitest/autorun'
- class PaymentCardRecognizerTest < Minitest::Test
- def test_extract_from_actual_card
- blocks = [
- "M A R I U S M Å R N E S M A T H I E S E N K O N T O N R . 1 2 0 6 4 4 4 8 2 6 7 S I S T K O N T R O L L N R . V F W N 8 3 0 F Ø D S E L S N R . 0 9 1 1 7 0 _ 4 6 3 9 4",
- "B A N K K O R T 0 0 0 0 2",
- "I f f o u n d , p l e a s e f o r w a r d t o : D N B , R e t u r , P b . 1 6 0 0 s e n t r u m , N O - 0 0 2 1 O s l o . R e w a r d p a y a b l e ."
- ]
- assert_equal "1206.44.48267", PaymentCardRecognizer.recognize_account_number(blocks)
- end
- end
- class NorwegianBankAccountTest < Minitest::Test
- def test_invalid_length
- @v = NorwegianBankAccount.new("1234.56.789")
- valid, message = @v.valid?
- refute valid, "#{@v} has an incorrect length"
- end
- def test_invalid_checksum
- @v = NorwegianBankAccount.new("1234.56.78901")
- valid, message = @v.valid?
- refute valid, "#{@v} has an incorrect checksum"
- end
- def test_valid_account_number
- @v = NorwegianBankAccount.new("1299.14.91285")
- valid, message = @v.valid?
- assert valid, "#{@v} should be a valid account number"
- end
- def test_crazy_input
- @v = NorwegianBankAccount.new("Morten Bankebiff")
- valid, message = @v.valid?
- refute valid, "#{@v} is wrong in so many ways"
- end
- def test_ivans_account_number
- acct = NorwegianBankAccount.new("60210746490")
- valid, message = acct.valid?
- assert valid, "Account number ending with 0 should be valid"
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement