ibandit 1.12.0 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f0083e6ead39b150f21564cf99eed6dd2af43f1116127a95ac4a8ba020c5e37
4
- data.tar.gz: 79858e3247d419d61154b6f99274c44664255ee814edaffb4a08a8a4d9dc4346
3
+ metadata.gz: a67c31f07d7b33b4f60998d4e4fd97473c72c36f23817bb07e5d1d632fa7aba9
4
+ data.tar.gz: 680db335cd4e6697c45f42550145ed5cce83262ab83eb6abb0d929579cfb00fb
5
5
  SHA512:
6
- metadata.gz: 5ad2acab721cce23b63c9c84a6126001df08b3f4205ba57ea63a90bbcd4649a0af2f251b871933a08a755e5a9c6df11f582b8e8dcea6520089c26d4cf1c285ea
7
- data.tar.gz: 30c4e57ec85de9bf28433a811e5c08b2ca3a83f4fa0dcce714526a2a9afce03da39298c732a6e7269106d430d1c26ae9777869dfb1d843ffbb202a8558b46261
6
+ metadata.gz: 5498e32bae4a3779c2a5965d3b71c375ee823582803bbf2e78a7667476cbd7af6be0b7bbdd101a14bd678bd262653e14f481a52cbe8a65a728a10e0916441557
7
+ data.tar.gz: 8d4314276d23c4cc338d9b31d634a48fef8ad4c4c3aface176d99361550a9dbf15a83429ed90fc22aacec48dd5f3ac20dcf12af675535d97d52fe3453ba3f4b5
@@ -7,7 +7,7 @@ jobs:
7
7
  validate:
8
8
  strategy:
9
9
  matrix:
10
- ruby-version: [2.6, 2.7, 3.0, 3.1]
10
+ ruby-version: ["2.6", "2.7", "3.0", "3.1", "3.2"]
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
13
  - uses: actions/checkout@v3
data/.rubocop.yml CHANGED
@@ -4,7 +4,7 @@ inherit_gem:
4
4
  require: rubocop-rails
5
5
 
6
6
  AllCops:
7
- TargetRubyVersion: 2.5
7
+ TargetRubyVersion: 3.2
8
8
 
9
9
  # Limit lines to 90 characters.
10
10
  Layout/LineLength:
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.1.0
1
+ 3.2.1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 1.14.0 - March 28, 2023
2
+
3
+ - Update IBAN registry #233
4
+ - Add GL and FO to the IBAN constructor for local details
5
+
6
+ ## 1.13.0 - March 6, 2023
7
+
8
+ - Update BLZ data - BLZ_20230306
9
+
1
10
  ## 1.12.0 - December 5, 2022
2
11
 
3
12
  - Update BLZ data - BLZ_20221205
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ # rubocop:disable Layout/LineLength
5
+
4
6
  # Script for parsing the IBAN registry (IBAN_Registry.txt) and IBAN structures
5
7
  # (IBANSTRUCTURE.xml) files from SWIFT.
6
8
  require "csv"
@@ -22,143 +24,240 @@ end
22
24
 
23
25
  class Report
24
26
  include SAXMachine
25
- elements "ibanstructure", as: :countries, class: Country
27
+ elements "ibanstructure_v2", as: :countries, class: Country
26
28
  end
27
29
 
28
- # rubocop:disable Metrics/AbcSize
29
- def get_iban_structures(iban_structures_file, iban_registry_file)
30
- bban_formats = get_bban_formats(iban_registry_file)
31
-
32
- report = Report.parse(iban_structures_file)
33
- report.countries.each_with_object({}) do |country, hash|
34
- hash[country.country_code] = {
35
- bank_code_position: country.bank_code_position.to_i,
36
- bank_code_length: country.bank_code_length.to_i,
37
- branch_code_position: country.branch_code_position.to_i,
38
- branch_code_length: country.branch_code_length.to_i,
39
- account_number_position: country.account_number_position.to_i,
40
- account_number_length: country.account_number_length.to_i,
41
- total_length: country.total_length.to_i,
42
- national_id_length: country.national_id_length.to_i,
43
- }.merge(bban_formats[country.country_code])
30
+ class IbanRegistryTextFile
31
+ attr_accessor :lines, :registry
32
+
33
+ FILE_ELEMENTS = [
34
+ # 0 Data element
35
+ # 1 Name of country
36
+ # 2 IBAN prefix country code (ISO 3166)
37
+ COUNTRY_CODE = 2,
38
+ # 3 Country code includes other countries/territories
39
+ # 4 SEPA country
40
+ # 5 SEPA country also includes
41
+ # 6 Domestic account number example
42
+ DOMESTIC_ACCOUNT_NUMBER_EXAMPLE = 6,
43
+ # 7 BBAN
44
+ # 8 BBAN structure
45
+ BBAN_STRUCTURE = 8,
46
+ # 9 BBAN length
47
+ # 10 Bank identifier position within the BBAN
48
+ BANK_IDENTIFIER_POSITION = 10,
49
+ # 11 Bank identifier pattern
50
+ BANK_IDENTIFIER_PATTERN = 11,
51
+ # 12 Branch identifier position within the BBAN
52
+ BRANCH_IDENTIFIER_POSITION = 12,
53
+ # 13 Branch identifier pattern
54
+ BRANCH_IDENTIFIER_PATTERN = 13,
55
+ # 14 Bank identifier example
56
+ # 15 Branch identifier example
57
+ # 16 BBAN example
58
+ BBAN_EXAMPLE = 16,
59
+ # 17 IBAN
60
+ # 18 IBAN structure
61
+ # 19 IBAN length
62
+ # 20 Effective date
63
+ # 21 IBAN electronic format example
64
+ IBAN_EXAMPLE = 21,
65
+ ].freeze
66
+
67
+ def self.call(path = "../data/raw/IBAN_Registry.txt")
68
+ lines = CSV.read(
69
+ File.expand_path(path, __dir__),
70
+ col_sep: "\t",
71
+ headers: true,
72
+ encoding: Encoding::ISO_8859_1,
73
+ ).to_a.transpose.tap(&:shift)
74
+
75
+ new(lines).tap(&:parse)
44
76
  end
45
- end
46
- # rubocop:enable Metrics/AbcSize
47
-
48
- FILE_ELEMENTS = [
49
- # 0 Data element
50
- # 1 Name of country
51
- # 2 IBAN prefix country code (ISO 3166)
52
- COUNTRY_CODE = 2,
53
- # 3 Country code includes other countries/territories
54
- # 4 SEPA country
55
- # 5 SEPA country also includes
56
- # 6 Domestic account number example
57
- # 7 BBAN
58
- # 8 BBAN structure
59
- BBAN_STRUCTURE = 8,
60
- # 9 BBAN length
61
- # 10 Bank identifier position within the BBAN
62
- # 11 Bank identifier pattern
63
- BANK_IDENTIFIER_PATTERN = 11,
64
- # 12 Branch identifier position within the BBAN
65
- # 13 Branch identifier pattern
66
- BRANCH_IDENTIFIER_PATTERN = 13,
67
- # 14 Bank identifier example
68
- # 15 Branch identifier example
69
- # 16 BBAN example
70
- # 17 IBAN
71
- # 18 IBAN structure
72
- # 19 IBAN length
73
- # 20 Effective date
74
- # 21 IBAN electronic format example
75
- ].freeze
76
-
77
- def get_bban_formats(iban_registry_file)
78
- iban_registry_file.each_with_object({}) do |line, hash|
79
- bban_structure = line[BBAN_STRUCTURE].strip
80
-
81
- bank_code_structure = line[BANK_IDENTIFIER_PATTERN].strip
82
- branch_code_structure = line[BRANCH_IDENTIFIER_PATTERN]&.strip
83
-
84
- bank_code_structure = "" if bank_code_structure == "N/A"
85
-
86
- country_code = line[COUNTRY_CODE].strip
87
- hash[country_code] = convert_swift_convention(bban_structure,
88
- bank_code_structure,
89
- branch_code_structure)
77
+
78
+ def initialize(lines)
79
+ @lines = lines
80
+ @registry = {}
90
81
  end
91
- end
92
82
 
93
- # IBAN Registry has BBAN format (which seems to be accurate), and Bank
94
- # identifier length, which contains something roughly like the format for the
95
- # bank code and usually the branch code where applicable. This is a best attempt
96
- # to convert those from weird SWIFT-talk into regexes, and then work out the
97
- # account number format regex by taking the bank and branch code regexes off
98
- # the front of the BBAN format.
99
- #
100
- # This works about 70% of the time, the rest are overridden in
101
- # structure_additions.yml
102
- def convert_swift_convention(bban, bank, branch)
103
- bban_regex = iban_registry_to_regex(bban)
104
- bank_regex = iban_registry_to_regex(bank)
105
- branch_regex = branch.nil? ? nil : iban_registry_to_regex(branch)
106
-
107
- non_account_number_regex = [bank_regex, branch_regex].join
108
- account_number_start = (bban_regex.index(non_account_number_regex) || 0) +
109
- non_account_number_regex.length
110
- account_number_regex = bban_regex[account_number_start..-1]
111
-
112
- {
113
- bban_format: bban_regex,
114
- bank_code_format: bank_regex,
115
- branch_code_format: branch_regex,
116
- account_number_format: account_number_regex,
117
- }.compact
83
+ def parse
84
+ lines.each do |line|
85
+ country_code = clean_string(line[COUNTRY_CODE])
86
+
87
+ bban_details = convert_swift_convention(
88
+ country_code: country_code,
89
+ bban_structure: clean_string(line[BBAN_STRUCTURE]),
90
+ bank_code_structure: clean_string(line[BANK_IDENTIFIER_PATTERN]),
91
+ branch_code_structure: clean_string(line[BRANCH_IDENTIFIER_PATTERN]),
92
+ bank_identifier_position: clean_string(line[BANK_IDENTIFIER_POSITION]),
93
+ branch_identifier_position: clean_string(line[BRANCH_IDENTIFIER_POSITION]),
94
+ ) || {}
95
+
96
+ registry[country_code] = {
97
+ iban_example: clean_string(line[IBAN_EXAMPLE]),
98
+ bban_example: clean_string(line[BBAN_EXAMPLE]),
99
+ domestic_account_number_example: clean_string(line[DOMESTIC_ACCOUNT_NUMBER_EXAMPLE]),
100
+ **bban_details,
101
+ }.compact
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ def clean_string(string)
108
+ return nil if string.nil?
109
+
110
+ string.strip!
111
+ return nil if string == "N/A"
112
+
113
+ string
114
+ end
115
+
116
+ # IBAN Registry has BBAN format (which seems to be accurate), and Bank
117
+ # identifier length, which contains something roughly like the format for the
118
+ # bank code and usually the branch code where applicable. This is a best attempt
119
+ # to convert those from weird SWIFT-talk into regexes, and then work out the
120
+ # account number format regex by taking the bank and branch code regexes off
121
+ # the front of the BBAN format.
122
+ #
123
+ # This works about 90% of the time, the rest are overridden in
124
+ # structure_additions.yml
125
+ def convert_swift_convention( # rubocop:todo Metrics/AbcSize
126
+ country_code:,
127
+ bban_structure:,
128
+ branch_code_structure:,
129
+ bank_code_structure: nil,
130
+ bank_identifier_position: nil,
131
+ branch_identifier_position: nil
132
+ )
133
+ bban_regex = iban_registry_to_regex(bban_structure)
134
+ bank_regex = iban_registry_to_regex(bank_code_structure)
135
+ branch_regex = branch_code_structure.nil? ? nil : iban_registry_to_regex(branch_code_structure)
136
+
137
+ bban_ranges = create_bban_ranges(bban_structure)
138
+ ranges_to_remove = [
139
+ convert_string_range(bank_identifier_position),
140
+ convert_string_range(branch_identifier_position),
141
+ ].compact.uniq
142
+ max_bank_details_index = ranges_to_remove.map(&:last).max
143
+
144
+ _, non_bank_identifier_ranges = bban_ranges.partition do |_, range|
145
+ max_bank_details_index >= range.last
146
+ end
147
+
148
+ account_number_regex = iban_registry_to_regex(non_bank_identifier_ranges.map(&:first).join)
149
+
150
+ {
151
+ bban_format: bban_regex.source,
152
+ bank_code_format: bank_regex.source,
153
+ branch_code_format: branch_regex&.source,
154
+ account_number_format: account_number_regex.source,
155
+ }
156
+ rescue StandardError => e
157
+ puts "-----------------"
158
+ puts "Issue with: #{country_code}"
159
+ puts "\t #{e.message}"
160
+ puts "\t #{e.backtrace}"
161
+ puts "\t -----------------"
162
+ puts "\t country_code: #{country_code}"
163
+ puts "\t bban_structure: #{bban_structure}"
164
+ puts "\t branch_code_structure: #{branch_code_structure}"
165
+ puts "\t bank_code_structure: #{bank_code_structure}"
166
+ puts "\t bank_identifier_position: #{bank_identifier_position}"
167
+ puts "\t branch_identifier_position: #{branch_identifier_position}"
168
+ end
169
+
170
+ # Given "4!n4!n12!c" this returns an array that contains the ranges that cover the
171
+ # structure. Eg; [["4!n", 0..3]]
172
+ def create_bban_ranges(bban_structure)
173
+ arr = bban_structure.scan(/((\d+)![anc])/)
174
+
175
+ start = 0
176
+
177
+ arr.each_with_object([]) do |(structure, length), acc|
178
+ end_number = start + length.to_i - 1
179
+ acc.push([structure, start..end_number])
180
+ start = end_number + 1
181
+ end
182
+ end
183
+
184
+ def convert_string_range(str)
185
+ start_val, end_val = str.split("-").map(&:to_i)
186
+ (start_val - 1)..(end_val - 1)
187
+ rescue StandardError
188
+ nil
189
+ end
190
+
191
+ def iban_registry_to_regex(swift_string)
192
+ regex = swift_string.
193
+ gsub(/(\d+)!n/, '\\d{\1}').
194
+ gsub(/(\d+)!a/, '[A-Z]{\1}').
195
+ gsub(/(\d+)!c/, '[A-Z0-9]{\1}')
196
+ Regexp.new(regex)
197
+ end
118
198
  end
119
199
 
120
- def iban_registry_to_regex(swift_string)
121
- swift_string.gsub(/(\d+)!([nac])/, '\2{\1}').
122
- gsub("n", '\d').
123
- gsub("a", "[A-Z]").
124
- gsub("c", "[A-Z0-9]")
200
+ class IbanStructureFile
201
+ attr_accessor :report, :iban_registry_file
202
+
203
+ def self.call(iban_registry_file, path: "../data/raw/IBANSTRUCTURE.xml")
204
+ iban_structures_file = File.read(File.expand_path(path, __dir__))
205
+ new(iban_registry_file:, iban_structures_file:).parse
206
+ end
207
+
208
+ def initialize(iban_registry_file:, iban_structures_file:)
209
+ @iban_registry_file = iban_registry_file
210
+ @report = Report.parse(iban_structures_file)
211
+ end
212
+
213
+ def parse # rubocop:todo Metrics/AbcSize
214
+ report.countries.each_with_object({}) do |country, hash|
215
+ country_bban = iban_registry_file.registry[country.country_code] || {}
216
+
217
+ hash[country.country_code] = {
218
+ bank_code_position: country.bank_code_position.to_i,
219
+ bank_code_length: country.bank_code_length.to_i,
220
+ branch_code_position: country.branch_code_position.to_i,
221
+ branch_code_length: country.branch_code_length.to_i,
222
+ account_number_position: country.account_number_position.to_i,
223
+ account_number_length: country.account_number_length.to_i,
224
+ total_length: country.total_length.to_i,
225
+ national_id_length: country.national_id_length.to_i,
226
+ **country_bban,
227
+ }
228
+ end
229
+ end
125
230
  end
126
231
 
127
232
  def merge_structures(structures, additions)
128
233
  additions.each_pair do |key, value|
129
- structures[key].merge!(value) if structures.include?(key)
234
+ structures[key].merge!(value).compact! if structures.include?(key)
130
235
  end
131
236
 
132
237
  structures
133
238
  end
134
239
 
240
+ def load_yaml_file(path)
241
+ YAML.safe_load(
242
+ File.read(File.expand_path(path, __dir__)),
243
+ permitted_classes: [Range, Symbol, Regexp],
244
+ )
245
+ end
246
+
135
247
  # Only parse the files if this file is run as an executable (not required in,
136
248
  # as it is in the specs)
137
249
  if __FILE__ == $PROGRAM_NAME
138
- iban_registry_file = CSV.read(
139
- File.expand_path("../data/raw/IBAN_Registry.txt", __dir__),
140
- col_sep: "\t",
141
- headers: true,
142
- encoding: Encoding::ISO_8859_1,
143
- ).to_a.transpose
144
-
145
- iban_registry_file.shift
146
-
147
- iban_structures_file = File.read(
148
- File.expand_path("../data/raw/IBANSTRUCTURE.xml", __dir__),
149
- )
250
+ old_file = load_yaml_file("../data/structures.yml")
150
251
 
151
- iban_structures = get_iban_structures(
152
- iban_structures_file,
153
- iban_registry_file,
154
- )
252
+ iban_registry_file = IbanRegistryTextFile.call
253
+ iban_structures = IbanStructureFile.call(iban_registry_file)
155
254
 
156
- structure_additions = YAML.safe_load(
157
- File.read(File.expand_path("../data/raw/structure_additions.yml", __dir__)),
158
- permitted_classes: [Range, Symbol],
159
- )
255
+ structure_additions = load_yaml_file("../data/raw/structure_additions.yml")
160
256
 
161
257
  complete_structures = merge_structures(iban_structures, structure_additions)
258
+ pseudo_ibans = load_yaml_file("../data/raw/pseudo_ibans.yml")
259
+
260
+ complete_structures.merge!(pseudo_ibans)
162
261
 
163
262
  output_file_path = File.expand_path(
164
263
  "../data/structures.yml",
@@ -166,4 +265,12 @@ if __FILE__ == $PROGRAM_NAME
166
265
  )
167
266
 
168
267
  File.open(output_file_path, "w") { |f| f.write(complete_structures.to_yaml) }
268
+
269
+ new_countries = old_file.keys.to_set ^ complete_structures.keys.to_set
270
+ puts "New countries:"
271
+ new_countries.each do |country|
272
+ puts "#{country} #{complete_structures[country][:iban_example]} #{complete_structures[country][:domestic_account_number_example]}"
273
+ end
169
274
  end
275
+
276
+ # rubocop:enable Layout/LineLength
@@ -8,6 +8,9 @@
8
8
  '10010123':
9
9
  :check_digit_rule: '09'
10
10
  :iban_rule: '000000'
11
+ '10010200':
12
+ :check_digit_rule: '09'
13
+ :iban_rule: '000000'
11
14
  '10010300':
12
15
  :check_digit_rule: '09'
13
16
  :iban_rule: '000000'
@@ -1709,9 +1712,6 @@
1709
1712
  '25850110':
1710
1713
  :check_digit_rule: '00'
1711
1714
  :iban_rule: '000000'
1712
- '25851335':
1713
- :check_digit_rule: '00'
1714
- :iban_rule: '000000'
1715
1715
  '25851660':
1716
1716
  :check_digit_rule: '00'
1717
1717
  :iban_rule: '000000'
@@ -3155,6 +3155,9 @@
3155
3155
  '37021548':
3156
3156
  :check_digit_rule: '09'
3157
3157
  :iban_rule: '000000'
3158
+ '37027000':
3159
+ :check_digit_rule: '09'
3160
+ :iban_rule: '000000'
3158
3161
  '37030700':
3159
3162
  :check_digit_rule: '19'
3160
3163
  :iban_rule: '000000'
@@ -4622,9 +4625,6 @@
4622
4625
  '50030010':
4623
4626
  :check_digit_rule: '09'
4624
4627
  :iban_rule: '000000'
4625
- '50030100':
4626
- :check_digit_rule: '00'
4627
- :iban_rule: '000000'
4628
4628
  '50030500':
4629
4629
  :check_digit_rule: '09'
4630
4630
  :iban_rule: '000000'
@@ -4856,6 +4856,54 @@
4856
4856
  '50070024':
4857
4857
  :check_digit_rule: '63'
4858
4858
  :iban_rule: '002002'
4859
+ '50070050':
4860
+ :check_digit_rule: '09'
4861
+ :iban_rule: '000000'
4862
+ '50070051':
4863
+ :check_digit_rule: '09'
4864
+ :iban_rule: '000000'
4865
+ '50070052':
4866
+ :check_digit_rule: '09'
4867
+ :iban_rule: '000000'
4868
+ '50070053':
4869
+ :check_digit_rule: '09'
4870
+ :iban_rule: '000000'
4871
+ '50070054':
4872
+ :check_digit_rule: '09'
4873
+ :iban_rule: '000000'
4874
+ '50070055':
4875
+ :check_digit_rule: '09'
4876
+ :iban_rule: '000000'
4877
+ '50070056':
4878
+ :check_digit_rule: '09'
4879
+ :iban_rule: '000000'
4880
+ '50070057':
4881
+ :check_digit_rule: '09'
4882
+ :iban_rule: '000000'
4883
+ '50070058':
4884
+ :check_digit_rule: '09'
4885
+ :iban_rule: '000000'
4886
+ '50070059':
4887
+ :check_digit_rule: '09'
4888
+ :iban_rule: '000000'
4889
+ '50070060':
4890
+ :check_digit_rule: '09'
4891
+ :iban_rule: '000000'
4892
+ '50070061':
4893
+ :check_digit_rule: '09'
4894
+ :iban_rule: '000000'
4895
+ '50070062':
4896
+ :check_digit_rule: '09'
4897
+ :iban_rule: '000000'
4898
+ '50070063':
4899
+ :check_digit_rule: '09'
4900
+ :iban_rule: '000000'
4901
+ '50070064':
4902
+ :check_digit_rule: '09'
4903
+ :iban_rule: '000000'
4904
+ '50070065':
4905
+ :check_digit_rule: '09'
4906
+ :iban_rule: '000000'
4859
4907
  '50070324':
4860
4908
  :check_digit_rule: '63'
4861
4909
  :iban_rule: '002002'
@@ -4982,9 +5030,6 @@
4982
5030
  '50110200':
4983
5031
  :check_digit_rule: '09'
4984
5032
  :iban_rule: '000000'
4985
- '50110300':
4986
- :check_digit_rule: '10'
4987
- :iban_rule: '000000'
4988
5033
  '50110400':
4989
5034
  :check_digit_rule: '09'
4990
5035
  :iban_rule: '000000'
@@ -5473,7 +5518,7 @@
5473
5518
  :iban_rule: '002900'
5474
5519
  '51210801':
5475
5520
  :check_digit_rule: '09'
5476
- :iban_rule: '000000'
5521
+ :iban_rule: '002900'
5477
5522
  '51210802':
5478
5523
  :check_digit_rule: '09'
5479
5524
  :iban_rule: '002900'
@@ -8507,12 +8552,6 @@
8507
8552
  '70120700':
8508
8553
  :check_digit_rule: '00'
8509
8554
  :iban_rule: '000000'
8510
- '70130700':
8511
- :check_digit_rule: '09'
8512
- :iban_rule: '000000'
8513
- '70130799':
8514
- :check_digit_rule: '09'
8515
- :iban_rule: '000000'
8516
8555
  '70130800':
8517
8556
  :check_digit_rule: '88'
8518
8557
  :iban_rule: '000000'
@@ -8693,9 +8732,6 @@
8693
8732
  '70220300':
8694
8733
  :check_digit_rule: '09'
8695
8734
  :iban_rule: '000000'
8696
- '70220800':
8697
- :check_digit_rule: '07'
8698
- :iban_rule: '000000'
8699
8735
  '70220900':
8700
8736
  :check_digit_rule: '61'
8701
8737
  :iban_rule: '000000'
@@ -9483,7 +9519,7 @@
9483
9519
  :check_digit_rule: '88'
9484
9520
  :iban_rule: '000000'
9485
9521
  '75090500':
9486
- :check_digit_rule: '84'
9522
+ :check_digit_rule: '09'
9487
9523
  :iban_rule: '000000'
9488
9524
  '75090900':
9489
9525
  :check_digit_rule: '91'
@@ -10178,6 +10214,9 @@
10178
10214
  '81000000':
10179
10215
  :check_digit_rule: '09'
10180
10216
  :iban_rule: '004201'
10217
+ '81010400':
10218
+ :check_digit_rule: '27'
10219
+ :iban_rule: '000000'
10181
10220
  '81020500':
10182
10221
  :check_digit_rule: '09'
10183
10222
  :iban_rule: '000000'