Advertisement
Guest User

Untitled

a guest
May 20th, 2019
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.43 KB | None | 0 0
  1. # coding: utf-8
  2. class NorwegianBankAccount
  3. # Pass me any kind of string representing an account number
  4. def initialize(str)
  5. @numbers = str.gsub(/[^\d]/,'')
  6. end
  7.  
  8. # Prettified output
  9. def to_s
  10. begin
  11. parts = @numbers.split(//)
  12. formatted = [parts[0,4].join(""), parts[4,2].join(""), parts[6,5].join("")].join(".")
  13. formatted
  14. rescue => e
  15. "##{self.class.name}<#{@numbers}> (#{e})"
  16. end
  17. end
  18.  
  19. # Validation combo. Using a tuple as return value, in true Golang fashion
  20. def valid?
  21. if @numbers.length != 11
  22. return false, "Needs to be 11 digits"
  23. end
  24. if !mod_11_control(@numbers, [5,4,3,2,7,6,5,4,3,2])
  25. return false, "Invalid checksum"
  26. end
  27. return true, nil
  28. end
  29.  
  30.  
  31. # Validate an account number using mod 11 with multiplication factors.
  32. # Includes check digit for simplicity (ie 11 digits as input)
  33. def mod_11_control(account_number, factors)
  34. account_parts = account_number.split(//)
  35. account_digits = account_parts[0,10].map(&:to_i)
  36. sum = 0
  37. account_digits.each_with_index do |n, i|
  38. s = n * factors[i]
  39. sum += (n * factors[i])
  40. end
  41. check_digit = account_parts[10].to_i
  42.  
  43. remainder = sum % 11
  44. expected_check_digit = case remainder
  45. when 0 then remainder
  46. when 1 then nil
  47. else 11- remainder
  48. end
  49. return check_digit == expected_check_digit
  50. end
  51. end
  52.  
  53. class PaymentCardRecognizer
  54. def self.recognize_account_number(blocks)
  55. candidates = []
  56. blocks.each do |b|
  57. without_spaces = b.gsub(/[\s_]/,"")
  58. number_re = /KONTONR\.(?<account>\d{11})/
  59.  
  60. matches = number_re.match(without_spaces)
  61. if matches
  62. candidates << matches[:account]
  63. end
  64. end
  65.  
  66. result = candidates.first
  67. account = NorwegianBankAccount.new(result)
  68. if account.valid?
  69. return account.to_s
  70. end
  71. end
  72. end
  73.  
  74. # Unittest built in, skip for production
  75. require 'minitest/autorun'
  76.  
  77. class PaymentCardRecognizerTest < Minitest::Test
  78. def test_extract_from_actual_card
  79. blocks = [
  80. "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",
  81. "B A N K K O R T 0 0 0 0 2",
  82. "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 ."
  83. ]
  84. assert_equal "1206.44.48267", PaymentCardRecognizer.recognize_account_number(blocks)
  85. end
  86. end
  87.  
  88. class NorwegianBankAccountTest < Minitest::Test
  89. def test_invalid_length
  90. @v = NorwegianBankAccount.new("1234.56.789")
  91. valid, message = @v.valid?
  92. refute valid, "#{@v} has an incorrect length"
  93. end
  94.  
  95. def test_invalid_checksum
  96. @v = NorwegianBankAccount.new("1234.56.78901")
  97. valid, message = @v.valid?
  98. refute valid, "#{@v} has an incorrect checksum"
  99. end
  100.  
  101. def test_valid_account_number
  102. @v = NorwegianBankAccount.new("1299.14.91285")
  103. valid, message = @v.valid?
  104. assert valid, "#{@v} should be a valid account number"
  105. end
  106.  
  107. def test_crazy_input
  108. @v = NorwegianBankAccount.new("Morten Bankebiff")
  109. valid, message = @v.valid?
  110. refute valid, "#{@v} is wrong in so many ways"
  111. end
  112.  
  113. def test_ivans_account_number
  114. acct = NorwegianBankAccount.new("60210746490")
  115. valid, message = acct.valid?
  116. assert valid, "Account number ending with 0 should be valid"
  117. end
  118. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement