uk_account_validator_auctionet 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rubocop.yml +11 -0
- data/.travis.yml +14 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +23 -0
- data/README.md +51 -0
- data/Rakefile +11 -0
- data/data/scsubtab.txt +21 -0
- data/data/valacdos.txt +1074 -0
- data/features/allow_hyphens_in_sort_codes.feature +9 -0
- data/features/exceptions.feature +49 -0
- data/features/invalid_formats.feature +33 -0
- data/features/modulus10.feature +18 -0
- data/features/modulus11.feature +18 -0
- data/features/modulus_weight.feature +26 -0
- data/features/modulus_weights_table.feature +14 -0
- data/features/step_definitions/basics.rb +23 -0
- data/features/step_definitions/modulus_weight.rb +7 -0
- data/features/step_definitions/modulus_weights_table.rb +13 -0
- data/features/support/env.rb +2 -0
- data/features/two_modulus_check.feature +25 -0
- data/lib/uk_account_validator.rb +57 -0
- data/lib/uk_account_validator/backports/array_bsearch_index.rb +33 -0
- data/lib/uk_account_validator/exceptions/base_exception.rb +65 -0
- data/lib/uk_account_validator/exceptions/exception_1.rb +10 -0
- data/lib/uk_account_validator/exceptions/exception_10.rb +18 -0
- data/lib/uk_account_validator/exceptions/exception_12.rb +9 -0
- data/lib/uk_account_validator/exceptions/exception_14.rb +30 -0
- data/lib/uk_account_validator/exceptions/exception_2_9.rb +68 -0
- data/lib/uk_account_validator/exceptions/exception_3.rb +10 -0
- data/lib/uk_account_validator/exceptions/exception_4.rb +16 -0
- data/lib/uk_account_validator/exceptions/exception_5.rb +48 -0
- data/lib/uk_account_validator/exceptions/exception_6.rb +16 -0
- data/lib/uk_account_validator/exceptions/exception_7.rb +9 -0
- data/lib/uk_account_validator/exceptions/exception_8.rb +7 -0
- data/lib/uk_account_validator/modulus_weight.rb +35 -0
- data/lib/uk_account_validator/modulus_weights_table.rb +35 -0
- data/lib/uk_account_validator/number_indices.rb +18 -0
- data/lib/uk_account_validator/validator.rb +92 -0
- data/lib/uk_account_validator/validators/base_validator.rb +28 -0
- data/lib/uk_account_validator/validators/double_alternate.rb +35 -0
- data/lib/uk_account_validator/validators/modulus10.rb +9 -0
- data/lib/uk_account_validator/validators/modulus11.rb +9 -0
- data/lib/uk_account_validator/validators/standard_modulus.rb +30 -0
- data/lib/uk_account_validator/version.rb +3 -0
- data/uk_account_validator.gemspec +22 -0
- metadata +104 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
Feature: Exceptions
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I create a new checker
|
5
|
+
|
6
|
+
Scenario Outline: Valid Codes
|
7
|
+
Given I have a sort code <sortcode>
|
8
|
+
And I have an account number <accountnumber>
|
9
|
+
|
10
|
+
Then the combination is valid
|
11
|
+
|
12
|
+
Examples:
|
13
|
+
| test | description | sortcode | accountnumber |
|
14
|
+
| 4 | Exception 10 & 11 where first check passes and second check fails. | 871427 | 46238510 |
|
15
|
+
| 5 | Exception 10 & 11 where first check fails and second check passes. | 872427 | 46238510 |
|
16
|
+
| 6 | Exception 10 where in the account number ab=09 and the g=9. The first check passes and second check fails. | 871427 | 09123496 |
|
17
|
+
| 7 | Exception 10 where in the account number ab=99 and the g=9. The first check passes and the second check fails. | 871427 | 99123496 |
|
18
|
+
| 8 | Exception 3, and the sorting code is the start of a range. As c=6 the second check should be ignored. | 820000 | 73688637 |
|
19
|
+
| 9 | Exception 3, and the sorting code is the end of a range. As c=9 the second check should be ignored. | 827999 | 73988638 |
|
20
|
+
| 10 | Exception 3. As c!=6 or 9 perform both checks pass. | 827101 | 28748352 |
|
21
|
+
| 11 | Exception 4 where the remainder is equal to the checkdigit. | 134020 | 63849203 |
|
22
|
+
| 12 | Exception 1 - ensures that 27 has been added to the accumulated total and passes double alternate modulus check. | 118765 | 64371389 |
|
23
|
+
| 13 | Exception 6 where the account fails standard check but is a foreign currency account. | 200915 | 41011166 |
|
24
|
+
| 14 | Exception 5 where the check passes. | 938611 | 07806039 |
|
25
|
+
| 15 | Exception 5 where the check passes with substitution. | 938600 | 42368003 |
|
26
|
+
| 16 | Exception 5 where both checks produce a remainder of 0 and pass. | 938063 | 55065200 |
|
27
|
+
| 17 | Exception 7 where passes but would fail the standard check. | 772798 | 99345694 |
|
28
|
+
| 18 | Exception 8 where the check passes. | 086090 | 06774744 |
|
29
|
+
| 19 | Exception 2 & 9 where the first check passes. | 309070 | 02355688 |
|
30
|
+
| 20 | Exception 2 & 9 where the first check fails and second check passes with substitution. | 309070 | 12345668 |
|
31
|
+
| 21 | Exception 2 & 9 where a!=0 and g!=9 and passes. | 309070 | 12345677 |
|
32
|
+
| 22 | Exception 2 & 9 where a!=0 and g=9 and passes. | 309070 | 99345694 |
|
33
|
+
| 31 | Exception 12/13 where passes modulus 11 check | 074456 | 12345112 |
|
34
|
+
| 32 | Exception 12/13 where passes the modulus 11 check | 070116 | 34012583 |
|
35
|
+
| 33 | Exception 12/13 where fails the modulus 11 check, but passes the modulus 10 check. | 074456 | 11104102 |
|
36
|
+
| 34 | Exception 14 where the first check fails and the second check passes. | 180002 | 00000190 |
|
37
|
+
|
38
|
+
Scenario Outline: Invalid Codes
|
39
|
+
Given I have a sort code <sortcode>
|
40
|
+
And I have an account number <accountnumber>
|
41
|
+
|
42
|
+
Then the combination is invalid
|
43
|
+
|
44
|
+
Examples:
|
45
|
+
| test | description | sortcode | accountnumber |
|
46
|
+
| 23 | Exception 5 where the first checkdigit is correct and the second incorrect. | 938063 | 15764273 |
|
47
|
+
| 24 | Exception 5 where the first checkdigit is incorrect and the second correct. | 938063 | 15764264 |
|
48
|
+
| 25 | Exception 5 where the first checkdigit is incorrect with a remainder of 1. | 938063 | 15763217 |
|
49
|
+
| 26 | Exception 1 where it fails double alternate check. | 118765 | 64371388 |
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Feature: Account number and sort code must be in recognised format
|
2
|
+
Background:
|
3
|
+
Given I create a new checker
|
4
|
+
|
5
|
+
Scenario: Account number contains letters
|
6
|
+
Given I have a sort code 089999
|
7
|
+
And I have an account number abcdefgh
|
8
|
+
|
9
|
+
Then the combination is invalid
|
10
|
+
|
11
|
+
Scenario: Account number must be at least 6 digits
|
12
|
+
Given I have a sort code 089999
|
13
|
+
And I have an account number 66374
|
14
|
+
|
15
|
+
Then the combination is invalid
|
16
|
+
|
17
|
+
Scenario: Account number may not be more than 10 digits
|
18
|
+
Given I have a sort code 089999
|
19
|
+
And I have an account number 66374958663
|
20
|
+
|
21
|
+
Then the combination is invalid
|
22
|
+
|
23
|
+
Scenario: The sort code may not be less than 6 digits
|
24
|
+
Given I have a sort code 08999
|
25
|
+
And I have an account number 66374958
|
26
|
+
|
27
|
+
Then the combination is invalid
|
28
|
+
|
29
|
+
Scenario: The sort code may not be more than 6 digits
|
30
|
+
Given I have a sort code 0899999
|
31
|
+
And I have an account number 66374958
|
32
|
+
|
33
|
+
Then the combination is invalid
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: Modulus 10 Checking
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I create a new checker
|
5
|
+
|
6
|
+
Scenario: 1) Pass modulus 10 check
|
7
|
+
Given I have a sort code 089999
|
8
|
+
And I have an account number 66374958
|
9
|
+
|
10
|
+
Then the modulus is MOD10
|
11
|
+
And the combination is valid
|
12
|
+
|
13
|
+
Scenario: 29) Fail modulus 10 check
|
14
|
+
Given I have a sort code 089999
|
15
|
+
And I have an account number 66374959
|
16
|
+
|
17
|
+
Then the modulus is MOD10
|
18
|
+
And the combination is invalid
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: Modulus 11 Checking
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I create a new checker
|
5
|
+
|
6
|
+
Scenario: 2) Pass modulus 11 check
|
7
|
+
Given I have a sort code 107999
|
8
|
+
And I have an account number 88837491
|
9
|
+
|
10
|
+
Then the modulus is MOD11
|
11
|
+
And the combination is valid
|
12
|
+
|
13
|
+
Scenario: 30) Fail modulus 11 check
|
14
|
+
Given I have a sort code 107999
|
15
|
+
And I have an account number 88837493
|
16
|
+
|
17
|
+
Then the modulus is MOD11
|
18
|
+
And the combination is invalid
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Feature: Modulus Weight
|
2
|
+
|
3
|
+
Scenario: Reading Weights
|
4
|
+
Given I have the following weight data:
|
5
|
+
"""
|
6
|
+
070116 070116 MOD11 0 0 7 6 5 8 9 4 5 6 7 8 9 -1 12
|
7
|
+
"""
|
8
|
+
|
9
|
+
Then the weight's sort_code_start is 070116
|
10
|
+
And the weight's sort_code_end is 070116
|
11
|
+
And the weight's modulus is MOD11
|
12
|
+
And the weight's u is 0
|
13
|
+
And the weight's v is 0
|
14
|
+
And the weight's w is 7
|
15
|
+
And the weight's x is 6
|
16
|
+
And the weight's y is 5
|
17
|
+
And the weight's z is 8
|
18
|
+
And the weight's a is 9
|
19
|
+
And the weight's b is 4
|
20
|
+
And the weight's c is 5
|
21
|
+
And the weight's d is 6
|
22
|
+
And the weight's e is 7
|
23
|
+
And the weight's f is 8
|
24
|
+
And the weight's g is 9
|
25
|
+
And the weight's h is -1
|
26
|
+
And the weight's exception is 12
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Feature: Modulus Weight Table
|
2
|
+
|
3
|
+
Scenario: Finding appropriate modulus weight
|
4
|
+
Given I have a modulus weight table loaded from data/valacdos.txt
|
5
|
+
|
6
|
+
Then the modulus for sort code 010004 is MOD11
|
7
|
+
And the modulus for sort code 010005 is MOD11
|
8
|
+
And the modulus for sort code 016714 is MOD11
|
9
|
+
And the modulus for sort code 016715 is MOD11
|
10
|
+
|
11
|
+
Scenario: Sort code doesn't exist
|
12
|
+
Given I have a modulus weight table loaded from data/valacdos.txt
|
13
|
+
|
14
|
+
Then the modulus for sort code 020000 cannot be found
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Given(/^I create a new checker$/) do
|
2
|
+
@checker = UkAccountValidator::Validator.new
|
3
|
+
end
|
4
|
+
|
5
|
+
Given(/^I have a sort code (\S+)$/) do |sort_code|
|
6
|
+
@checker.sort_code = sort_code
|
7
|
+
end
|
8
|
+
|
9
|
+
Given(/^I have an account number (\S+)$/) do |acc_number|
|
10
|
+
@checker.account_number = acc_number
|
11
|
+
end
|
12
|
+
|
13
|
+
Then(/^the modulus is (\S+)$/) do |modulus|
|
14
|
+
expect(@checker.modulus_weights.first.modulus).to eq modulus
|
15
|
+
end
|
16
|
+
|
17
|
+
Then(/^the combination is valid$/) do
|
18
|
+
expect(@checker.valid?).to be true
|
19
|
+
end
|
20
|
+
|
21
|
+
Then(/^the combination is invalid$/) do
|
22
|
+
expect(@checker.valid?).to be false
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Given(/^I have a modulus weight table loaded from (.+?)$/) do |file_path|
|
2
|
+
@table = UkAccountValidator::ModulusWeightsTable.new(
|
3
|
+
File.join(File.dirname(__FILE__), '../..', file_path)
|
4
|
+
)
|
5
|
+
end
|
6
|
+
|
7
|
+
Then(/^the modulus for sort code (\d+) is (\S+)$/) do |sort_code, mod|
|
8
|
+
expect(@table.find(sort_code).first.modulus).to eq mod
|
9
|
+
end
|
10
|
+
|
11
|
+
Then(/^the modulus for sort code (\d+) cannot be found$/) do |sort_code|
|
12
|
+
expect(@table.find(sort_code)).to match_array([])
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Feature: Two Modulus Checks
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I create a new checker
|
5
|
+
|
6
|
+
Scenario Outline: Valid Codes
|
7
|
+
Given I have a sort code <sortcode>
|
8
|
+
And I have an account number <accountnumber>
|
9
|
+
|
10
|
+
Then the combination is valid
|
11
|
+
|
12
|
+
Examples:
|
13
|
+
| test | description | sortcode | accountnumber |
|
14
|
+
| 3 | Pass modulus 11 and double alternate checks. | 202959 | 63748472 |
|
15
|
+
|
16
|
+
Scenario Outline: Invalid Codes
|
17
|
+
Given I have a sort code <sortcode>
|
18
|
+
And I have an account number <accountnumber>
|
19
|
+
|
20
|
+
Then the combination is invalid
|
21
|
+
|
22
|
+
Examples:
|
23
|
+
| test | description | sortcode | accountnumber |
|
24
|
+
| 27 | Pass modulus 11 check and fail double alternate check. | 203099 | 66831036 |
|
25
|
+
| 28 | Fail modulus 11 check and pass double alternate check. | 203099 | 58716970 |
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'uk_account_validator/backports/array_bsearch_index'
|
2
|
+
|
3
|
+
require 'uk_account_validator/number_indices.rb'
|
4
|
+
require 'uk_account_validator/validator.rb'
|
5
|
+
require 'uk_account_validator/modulus_weight.rb'
|
6
|
+
require 'uk_account_validator/modulus_weights_table.rb'
|
7
|
+
|
8
|
+
require 'uk_account_validator/validators/base_validator.rb'
|
9
|
+
require 'uk_account_validator/validators/standard_modulus.rb'
|
10
|
+
require 'uk_account_validator/validators/modulus10.rb'
|
11
|
+
require 'uk_account_validator/validators/modulus11.rb'
|
12
|
+
require 'uk_account_validator/validators/double_alternate.rb'
|
13
|
+
|
14
|
+
require 'uk_account_validator/exceptions/base_exception.rb'
|
15
|
+
require 'uk_account_validator/exceptions/exception_1.rb'
|
16
|
+
require 'uk_account_validator/exceptions/exception_2_9.rb'
|
17
|
+
require 'uk_account_validator/exceptions/exception_3.rb'
|
18
|
+
require 'uk_account_validator/exceptions/exception_4.rb'
|
19
|
+
require 'uk_account_validator/exceptions/exception_5.rb'
|
20
|
+
require 'uk_account_validator/exceptions/exception_6.rb'
|
21
|
+
require 'uk_account_validator/exceptions/exception_7.rb'
|
22
|
+
require 'uk_account_validator/exceptions/exception_8.rb'
|
23
|
+
require 'uk_account_validator/exceptions/exception_10.rb'
|
24
|
+
require 'uk_account_validator/exceptions/exception_12.rb'
|
25
|
+
require 'uk_account_validator/exceptions/exception_14.rb'
|
26
|
+
|
27
|
+
module UkAccountValidator
|
28
|
+
def self.modulus_weights_table
|
29
|
+
@modulus_weights_table ||= read_modulus_weights_table
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.sort_code_substitution
|
33
|
+
@sort_code_substitution ||= read_sort_code_substitution
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def self.modulus_weights_table_file
|
39
|
+
File.join(File.dirname(__FILE__), '../data/valacdos.txt')
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.read_modulus_weights_table
|
43
|
+
ModulusWeightsTable.new(modulus_weights_table_file)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.sort_code_substitution_file
|
47
|
+
File.join(File.dirname(__FILE__), '../data/scsubtab.txt')
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.read_sort_code_substitution
|
51
|
+
@substitutions ||= Hash[
|
52
|
+
File.readlines(UkAccountValidator.sort_code_substitution_file).map do |line|
|
53
|
+
line.split(' ')
|
54
|
+
end
|
55
|
+
]
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Copied from backports gem
|
2
|
+
unless Array.method_defined? :bsearch_index
|
3
|
+
class Array
|
4
|
+
def bsearch_index
|
5
|
+
return to_enum(__method__) unless block_given?
|
6
|
+
from = 0
|
7
|
+
to = size - 1
|
8
|
+
satisfied = nil
|
9
|
+
while from <= to do
|
10
|
+
midpoint = (from + to).div(2)
|
11
|
+
result = yield(self[midpoint])
|
12
|
+
case result
|
13
|
+
when Numeric
|
14
|
+
return midpoint if result == 0
|
15
|
+
result = result < 0
|
16
|
+
when true
|
17
|
+
satisfied = midpoint
|
18
|
+
when nil, false
|
19
|
+
# nothing to do
|
20
|
+
else
|
21
|
+
raise TypeError, "wrong argument type #{result.class} (must be numeric, true, false or nil)"
|
22
|
+
end
|
23
|
+
|
24
|
+
if result
|
25
|
+
to = midpoint - 1
|
26
|
+
else
|
27
|
+
from = midpoint + 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
satisfied
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class BaseException
|
2
|
+
include NumberIndices
|
3
|
+
|
4
|
+
attr_reader :modulus_weight, :account_number, :sort_code, :check_number
|
5
|
+
|
6
|
+
def initialize(modulus_weight, account_number, sort_code, check_number)
|
7
|
+
@modulus_weight = modulus_weight
|
8
|
+
@account_number = account_number
|
9
|
+
@sort_code = sort_code
|
10
|
+
@check_number = check_number
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.allow_any?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def override_test?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the new modulus weight after applying the exception.
|
22
|
+
def replace_weight(_test_digits)
|
23
|
+
return modulus_weight
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the new total after any adjustments
|
27
|
+
def after_calculate_total(total, _test_digits)
|
28
|
+
return total
|
29
|
+
end
|
30
|
+
|
31
|
+
def apply_account_number_substitutions
|
32
|
+
return account_number
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the new sort code after substitutions
|
36
|
+
def apply_sort_code_substitutions
|
37
|
+
return sort_code
|
38
|
+
end
|
39
|
+
|
40
|
+
# Useful functions
|
41
|
+
|
42
|
+
# Zero all weights
|
43
|
+
def zero_all
|
44
|
+
UkAccountValidator::ModulusWeight.new(
|
45
|
+
modulus_weight.sort_code_start,
|
46
|
+
modulus_weight.sort_code_end,
|
47
|
+
modulus_weight.modulus,
|
48
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
49
|
+
modulus_weight.exception
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Zero weights for u to b
|
54
|
+
def zero_u_b
|
55
|
+
UkAccountValidator::ModulusWeight.new(
|
56
|
+
modulus_weight.sort_code_start,
|
57
|
+
modulus_weight.sort_code_end,
|
58
|
+
modulus_weight.modulus,
|
59
|
+
0, 0, 0, 0, 0, 0, 0, 0,
|
60
|
+
modulus_weight.c, modulus_weight.d, modulus_weight.e,
|
61
|
+
modulus_weight.f, modulus_weight.g, modulus_weight.h,
|
62
|
+
modulus_weight.exception
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Perform the double alternate check except:
|
2
|
+
# Add 27 to the total (ie before you divide by 10)
|
3
|
+
# This effectively places a financial institution number (580149) before the
|
4
|
+
# sorting code and account number which is subject to the alternate doubling as
|
5
|
+
# well.
|
6
|
+
class Exception1 < BaseException
|
7
|
+
def after_calculate_total(total, _test_digits)
|
8
|
+
return total + 27
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# For the exception 10 check, if ab = 09 or ab = 99 and g = 9, zeroise weighting
|
2
|
+
# positions u-b.
|
3
|
+
class Exception10 < BaseException
|
4
|
+
def self.allow_any?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def replace_weight(test_digits)
|
9
|
+
# if ab = 09 or 99 and g=9, zeroise weighting positions u-b.
|
10
|
+
a = test_digits[NUMBER_INDEX[:a]]
|
11
|
+
b = test_digits[NUMBER_INDEX[:b]]
|
12
|
+
|
13
|
+
return zero_u_b if (a == 0 && b == 9) ||
|
14
|
+
(a == 9 && b == 9 && test_digits[NUMBER_INDEX[:g]] == 9)
|
15
|
+
|
16
|
+
return modulus_weight
|
17
|
+
end
|
18
|
+
end
|