iso-iban 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/LICENSE.txt +8 -0
- data/README.markdown +45 -0
- data/Rakefile +19 -0
- data/data/iso-iban/specs.yaml +838 -0
- data/iso-iban.gemspec +42 -0
- data/lib/iso/iban.rb +324 -0
- data/lib/iso/iban/autoload.rb +5 -0
- data/lib/iso/iban/specification.rb +128 -0
- data/lib/iso/iban/version.rb +18 -0
- data/test/data/test_spec.yaml +23 -0
- data/test/lib/helper.rb +86 -0
- data/test/runner.rb +20 -0
- data/test/tmp/test_spec.yaml +23 -0
- data/test/unit/lib/iso/iban.rb +117 -0
- metadata +61 -0
data/iso-iban.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "iso-iban"
|
5
|
+
s.version = "0.0.1"
|
6
|
+
s.authors = "Stefan Rusterholz"
|
7
|
+
s.email = "stefan.rusterholz@gmail.com"
|
8
|
+
s.homepage = "https://github.com/apeiros/iso-iban"
|
9
|
+
s.license = 'BSD 2-Clause'
|
10
|
+
|
11
|
+
s.description = <<-DESCRIPTION.gsub(/^ /, '').chomp
|
12
|
+
ISO::IBAN implements IBAN (International Bank Account Number) specification as per ISO 13616-1.
|
13
|
+
It provides methods to generate valid IBAN numbers from components, or to validate a given IBAN.
|
14
|
+
DESCRIPTION
|
15
|
+
s.summary = <<-SUMMARY.gsub(/^ /, '').chomp
|
16
|
+
Utilities for International Bank Account Numbers (IBAN) as per ISO 13616-1.
|
17
|
+
SUMMARY
|
18
|
+
|
19
|
+
s.files =
|
20
|
+
Dir['bin/**/*'] +
|
21
|
+
Dir['data/**/*'] +
|
22
|
+
Dir['documentation/**/*'] +
|
23
|
+
Dir['lib/**/*'] +
|
24
|
+
Dir['rake/**/*'] +
|
25
|
+
Dir['test/**/*'] +
|
26
|
+
Dir['*.gemspec'] +
|
27
|
+
%w[
|
28
|
+
.yardopts
|
29
|
+
LICENSE.txt
|
30
|
+
Rakefile
|
31
|
+
README.markdown
|
32
|
+
]
|
33
|
+
|
34
|
+
if File.directory?('bin') then
|
35
|
+
s.executables = Dir.chdir('bin') { Dir.glob('**/*').select { |f| File.executable?(f) } }
|
36
|
+
end
|
37
|
+
|
38
|
+
s.required_ruby_version = ">= 1.9.2"
|
39
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1")
|
40
|
+
s.rubygems_version = "1.3.1"
|
41
|
+
s.specification_version = 3
|
42
|
+
end
|
data/lib/iso/iban.rb
ADDED
@@ -0,0 +1,324 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'iso/iban/specification'
|
4
|
+
require 'iso/iban/version'
|
5
|
+
|
6
|
+
module ISO
|
7
|
+
|
8
|
+
# IBAN - ISO 13616-1
|
9
|
+
#
|
10
|
+
# General IBAN Information
|
11
|
+
# ========================
|
12
|
+
#
|
13
|
+
# * What is an IBAN?
|
14
|
+
# IBAN stands for International Bank Account Number. It is the ISO 13616
|
15
|
+
# international standard for numbering bank accounts. In 2006, the
|
16
|
+
# International Organization for Standardization (ISO) designated SWIFT as
|
17
|
+
# the Registration Authority for ISO 13616.
|
18
|
+
#
|
19
|
+
# * Use
|
20
|
+
# The IBAN facilitates the communication and processing of cross-border
|
21
|
+
# transactions. It allows exchanging account identification details in a
|
22
|
+
# machine-readable form.
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# The ISO 13616 IBAN Standard
|
26
|
+
# ===========================
|
27
|
+
#
|
28
|
+
# * Structure
|
29
|
+
# The IBAN structure is defined in ISO 13616-1 and consists of a two-letter
|
30
|
+
# ISO 3166-1 country code, followed by two check digits and up to thirty
|
31
|
+
# alphanumeric characters for a BBAN (Basic Bank Account Number) which has a
|
32
|
+
# fixed length per country and, included within it, a bank identifier with a
|
33
|
+
# fixed position and a fixed length per country. The check digits are
|
34
|
+
# calculated based on the scheme defined in ISO/IEC 7064 (MOD97-10).
|
35
|
+
#
|
36
|
+
# * Terms and definitions
|
37
|
+
# Bank identifier: The identifier that uniquely identifies the financial
|
38
|
+
# institution and, when appropriate, the branch of that financial institution
|
39
|
+
# servicing an account
|
40
|
+
#
|
41
|
+
# `In this registry, the branch identifier format is shown specifically, when
|
42
|
+
# present.`
|
43
|
+
#
|
44
|
+
# *BBAN*: basic bank account number: The identifier that uniquely identifies
|
45
|
+
# an individual account, at a specific financial institution, in a particular
|
46
|
+
# country. The BBAN includes a bank identifier of the financial institution
|
47
|
+
# servicing that account.
|
48
|
+
# *IBAN*: international bank account number: The expanded version of the
|
49
|
+
# basic bank account number (BBAN), intended for use internationally. The
|
50
|
+
# IBAN uniquely identifies an individual account, at a specific financial
|
51
|
+
# institution, in a particular country.
|
52
|
+
#
|
53
|
+
# * Submitters
|
54
|
+
# Nationally-agreed, ISO13616-compliant IBAN formats are submitted to the
|
55
|
+
# registration authority exclusively by the National Standards Body or the
|
56
|
+
# National Central Bank of the country.
|
57
|
+
class IBAN
|
58
|
+
include Comparable
|
59
|
+
|
60
|
+
# Character code translation used to convert an IBAN into its numeric
|
61
|
+
# (digits-only) form
|
62
|
+
CharacterCodes = Hash[('0'..'9').zip('0'..'9')+('a'..'z').zip(10..35)+('A'..'Z').zip(10..35)]
|
63
|
+
|
64
|
+
# All specifications, see ISO::IBAN::Specification
|
65
|
+
@specifications = nil
|
66
|
+
|
67
|
+
# Load the IBAN specifications file, which determines how the IBAN
|
68
|
+
# for any given country looks like.
|
69
|
+
#
|
70
|
+
# It will use the following sources in this order (first one which exists wins)
|
71
|
+
#
|
72
|
+
# * Path passed as spec_file parameter
|
73
|
+
# * Path provided by the env variable IBAN_SPECIFICATIONS
|
74
|
+
# * The file ../data/iso-iban/specs.yaml relative to the lib dir
|
75
|
+
# * The Gem datadir path
|
76
|
+
#
|
77
|
+
# @param [String] spec_file
|
78
|
+
# Override the default specifications file path.
|
79
|
+
#
|
80
|
+
# @return [self]
|
81
|
+
def self.load_specifications(spec_file=nil)
|
82
|
+
if spec_file then
|
83
|
+
# do nothing
|
84
|
+
elsif ENV['IBAN_SPECIFICATIONS'] then
|
85
|
+
spec_file = ENV['IBAN_SPECIFICATIONS']
|
86
|
+
else
|
87
|
+
spec_file = File.expand_path('../../../../data/iso-iban/specs.yaml', __FILE__)
|
88
|
+
spec_file = Gem.datadir('iso-iban')+'/specs.yaml' if defined?(Gem) && !File.file?(spec_file)
|
89
|
+
end
|
90
|
+
|
91
|
+
@specifications = ISO::IBAN::Specification.load_yaml(spec_file)
|
92
|
+
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
# @return [Hash<String => ISO::IBAN::Specification>]
|
97
|
+
# A hash with the country (ISO3166 2-letter) as key and the specification for that country as value
|
98
|
+
def self.specifications
|
99
|
+
@specifications || raise("No specifications have been loaded yet.")
|
100
|
+
end
|
101
|
+
|
102
|
+
# @param [String] a2_country_code
|
103
|
+
# The country (ISO3166 2-letter), e.g. 'CH' or 'DE'.
|
104
|
+
#
|
105
|
+
# @return [ISO::IBAN::Specification]
|
106
|
+
# The specification for the given country
|
107
|
+
def self.specification(a2_country_code, *default, &default_block)
|
108
|
+
specifications.fetch(a2_country_code, *default, &default_block)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @param [String] iban
|
112
|
+
# An IBAN number, either in compact or human format.
|
113
|
+
#
|
114
|
+
# @return [true, false]
|
115
|
+
# Whether the IBAN is valid.
|
116
|
+
# See {#validate} for details.
|
117
|
+
def self.valid?(iban)
|
118
|
+
new(iban).valid?
|
119
|
+
end
|
120
|
+
|
121
|
+
# @param [String] iban
|
122
|
+
# An IBAN number, either in compact or human format.
|
123
|
+
#
|
124
|
+
# @return [Array<Symbol>]
|
125
|
+
# An array with a code of all validation errors, empty if valid.
|
126
|
+
# See {#validate} for details.
|
127
|
+
def self.validate(iban)
|
128
|
+
new(iban).validate
|
129
|
+
end
|
130
|
+
|
131
|
+
# @param [String] iban
|
132
|
+
# The IBAN in either compact or human readable form.
|
133
|
+
#
|
134
|
+
# @return [String]
|
135
|
+
# The IBAN in compact form.
|
136
|
+
def self.strip(iban)
|
137
|
+
iban.tr(' -', '')
|
138
|
+
end
|
139
|
+
|
140
|
+
# Generate an IBAN from country code and components, automatically filling in the checksum.
|
141
|
+
#
|
142
|
+
# @example Generate an IBAN for UBS Switzerland with account number '12345'
|
143
|
+
# ISO::IBAN.generate('CH', '216', '12345') # => #<ISO::IBAN CH92 0021 6000 0000 1234 5>
|
144
|
+
#
|
145
|
+
# @param [String] country
|
146
|
+
# The ISO-3166 2-letter country code.
|
147
|
+
#
|
148
|
+
def self.generate(country, *components)
|
149
|
+
spec = specification(country)
|
150
|
+
justified = spec.component_lengths.zip(components).map { |length, component| component.rjust(length, "0") }
|
151
|
+
iban = new(country+'??'+justified.join(''))
|
152
|
+
iban.update_checksum!
|
153
|
+
|
154
|
+
iban
|
155
|
+
end
|
156
|
+
|
157
|
+
# Converts a String into its digits-only form, i.e. all characters a-z are replaced with their corresponding
|
158
|
+
# digit sequences, according to the IBAN specification.
|
159
|
+
#
|
160
|
+
# @param [String] string
|
161
|
+
# The string to convert into its numeric form.
|
162
|
+
#
|
163
|
+
# @return [String] The string in its numeric, digits-only form.
|
164
|
+
def self.numerify(string)
|
165
|
+
string.downcase.gsub(/\D/) { |char|
|
166
|
+
CharacterCodes.fetch(char) {
|
167
|
+
raise ArgumentError, "The string contains an invalid character #{char.inspect}"
|
168
|
+
}
|
169
|
+
}.to_i
|
170
|
+
end
|
171
|
+
|
172
|
+
# @return [String] The standard form of the IBAN for machine communication, without spaces.
|
173
|
+
attr_reader :compact
|
174
|
+
|
175
|
+
# @return [String] The ISO-3166 2-letter country code.
|
176
|
+
attr_reader :country
|
177
|
+
|
178
|
+
# @return [ISO::IBAN::Specification] The specification for this IBAN (determined by its country).
|
179
|
+
attr_reader :specification
|
180
|
+
|
181
|
+
# @param [String] iban
|
182
|
+
# The IBAN number, either in formatted, human readable or in compact form.
|
183
|
+
def initialize(iban)
|
184
|
+
raise ArgumentError, "String expected for iban, but got #{iban.class}" unless iban.is_a?(String)
|
185
|
+
|
186
|
+
@compact = self.class.strip(iban)
|
187
|
+
@country = iban[0,2]
|
188
|
+
@specification = self.class.specification(@country, nil)
|
189
|
+
end
|
190
|
+
|
191
|
+
# @example Formatted IBAN
|
192
|
+
#
|
193
|
+
# ISO::IBAN.new('CH')
|
194
|
+
#
|
195
|
+
# @return [String] The IBAN in its formatted form, which is more human readable than the compact form.
|
196
|
+
def formatted
|
197
|
+
@_formatted ||= @compact.gsub(/.{4}(?=.)/, '\0 ')
|
198
|
+
end
|
199
|
+
|
200
|
+
# @return [String]
|
201
|
+
# IBAN in its numeric form, i.e. all characters a-z are replaced with their corresponding
|
202
|
+
# digit sequences.
|
203
|
+
def numeric
|
204
|
+
self.class.numerify(@compact[4..-1]+@compact[0,4])
|
205
|
+
end
|
206
|
+
|
207
|
+
# @return [true, false]
|
208
|
+
# Whether the IBAN is valid.
|
209
|
+
# See {#validate} for details.
|
210
|
+
def valid?
|
211
|
+
validate.empty?
|
212
|
+
end
|
213
|
+
|
214
|
+
# Validation error codes:
|
215
|
+
#
|
216
|
+
# * :invalid_country
|
217
|
+
# * :invalid_checksum
|
218
|
+
# * :invalid_length
|
219
|
+
# * :invalid_format
|
220
|
+
#
|
221
|
+
# Invalid country means the country is unknown (char 1 & 2 in the IBAN).
|
222
|
+
# Invalid checksum means the two check digits (char 3 & 4 in the IBAN).
|
223
|
+
# Invalid length means the IBAN does not comply with the length specified for the country of that IBAN.
|
224
|
+
# Invalid format means the IBAN does not comply with the format specified for the country of that IBAN.
|
225
|
+
#
|
226
|
+
# @return [Array<Symbol>] An array with a code of all validation errors, empty if valid.
|
227
|
+
def validate
|
228
|
+
errors = []
|
229
|
+
errors << :invalid_country unless valid_country?
|
230
|
+
errors << :invalid_checksum unless valid_checksum?
|
231
|
+
errors << :invalid_length unless valid_length?
|
232
|
+
errors << :invalid_format unless valid_format?
|
233
|
+
|
234
|
+
errors
|
235
|
+
end
|
236
|
+
|
237
|
+
# @return [String] The checksum digits in the IBAN.
|
238
|
+
def checksum_digits
|
239
|
+
@compact[2,2]
|
240
|
+
end
|
241
|
+
|
242
|
+
# @return [String] The BBAN of the IBAN.
|
243
|
+
def bban
|
244
|
+
@compact[4..-1]
|
245
|
+
end
|
246
|
+
|
247
|
+
# @return [String, nil] The bank code part of the IBAN, nil if not applicable.
|
248
|
+
def bank_code
|
249
|
+
if @specification && @specification.bank_position_from && @specification.bank_position_to
|
250
|
+
@compact[@specification.bank_position_from..@specification.bank_position_to]
|
251
|
+
else
|
252
|
+
nil
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
# @return [String, nil] The branch code part of the IBAN, nil if not applicable.
|
257
|
+
def branch_code
|
258
|
+
if @specification && @specification.branch_position_from && @specification.branch_position_to
|
259
|
+
@compact[@specification.branch_position_from..@specification.branch_position_to]
|
260
|
+
else
|
261
|
+
nil
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# @return [String] The account code part of the IBAN.
|
266
|
+
def account_code
|
267
|
+
@compact[((@specification.branch_position_to || @specification.bank_position_to || 3)+1)..-1]
|
268
|
+
end
|
269
|
+
|
270
|
+
# @return [true, false] Whether the country of the IBAN is valid.
|
271
|
+
def valid_country?
|
272
|
+
@specification ? true : false
|
273
|
+
end
|
274
|
+
|
275
|
+
# @return [true, false] Whether the format of the IBAN is valid.
|
276
|
+
def valid_format?
|
277
|
+
specification && specification.iban_regex =~ @compact ? true : false
|
278
|
+
end
|
279
|
+
|
280
|
+
# @return [true, false] Whether the length of the IBAN is valid.
|
281
|
+
def valid_length?
|
282
|
+
specification && @compact.size == specification.iban_length ? true : false
|
283
|
+
end
|
284
|
+
|
285
|
+
# @return [true, false] Whether the checksum of the IBAN is valid.
|
286
|
+
def valid_checksum?
|
287
|
+
numeric % 97 == 1
|
288
|
+
end
|
289
|
+
|
290
|
+
# See Object#<=>
|
291
|
+
#
|
292
|
+
# @return [-1, 0, 1, nil]
|
293
|
+
def <=>(other)
|
294
|
+
other.respond_to?(:compact) ? @compact <=> other.compact : nil
|
295
|
+
end
|
296
|
+
|
297
|
+
# Requires that the checksum digits were left as '??', replaces them with
|
298
|
+
# the proper checksum.
|
299
|
+
#
|
300
|
+
# @return [self]
|
301
|
+
def update_checksum!
|
302
|
+
raise "Checksum digit placeholders missing" unless @compact[2,2] == '??'
|
303
|
+
|
304
|
+
@compact[2,2] = calculated_check_digits
|
305
|
+
|
306
|
+
self
|
307
|
+
end
|
308
|
+
|
309
|
+
# @return [String] The check-digits as calculated from the IBAN.
|
310
|
+
def calculated_check_digits
|
311
|
+
"%02d" % (98-(self.class.numerify(bban+@country)*100)%97)
|
312
|
+
end
|
313
|
+
|
314
|
+
# See Object#inspect
|
315
|
+
def inspect
|
316
|
+
sprintf "#<%p %s>", self.class, formatted
|
317
|
+
end
|
318
|
+
|
319
|
+
# @return [String] The compact form of the IBAN as a String.
|
320
|
+
def to_s
|
321
|
+
@compact.dup
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ISO
|
4
|
+
class IBAN
|
5
|
+
|
6
|
+
# Specification of the IBAN format for one country. Every country has its
|
7
|
+
# own specification of the IBAN format.
|
8
|
+
# SWIFT is the official authority where those formats are registered.
|
9
|
+
class Specification
|
10
|
+
|
11
|
+
# A mapping from SWIFT structure specification to PCRE regex.
|
12
|
+
StructureCodes = {
|
13
|
+
'n' => '\d',
|
14
|
+
'a' => '[A-Z]',
|
15
|
+
'c' => '[A-Za-z0-9]',
|
16
|
+
'e' => ' ',
|
17
|
+
}
|
18
|
+
|
19
|
+
# Load the specifications YAML.
|
20
|
+
#
|
21
|
+
# @return [Hash<String => ISO::IBAN::Specification>]
|
22
|
+
def self.load_yaml(path)
|
23
|
+
Hash[YAML.load_file(path).map { |country, spec| [country, new(*spec)] }]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Parse the SWIFT provided file (which sadly is a mess).
|
27
|
+
#
|
28
|
+
# @return [Array<ISO::IBAN::Specification>] an array with all specifications.
|
29
|
+
def self.parse_file(path)
|
30
|
+
File.read(path, encoding: Encoding::Windows_1252).encode(Encoding::UTF_8).split("\r\n").tap(&:shift).flat_map { |line|
|
31
|
+
country_name, country_codes, iban_structure, iban_length, bban_structure, bban_length, bank_position = line.split(/\t/).values_at(0,1,11,12,4,5,6)
|
32
|
+
codes = country_codes.size == 2 ? [country_codes] : country_codes.scan(/\b[A-Z]{2}\b/)
|
33
|
+
bank_position_from, bank_position_to, branch_position_from, branch_position_to = bank_position.match(/(?:[Pp]ositions?|) (\d+)-(\d+)(?:.*Branch identifier positions?: (\d+)-(\d+))?/).captures.map { |pos| pos && pos.to_i+3 }
|
34
|
+
|
35
|
+
codes.map { |a2_country_code|
|
36
|
+
new(
|
37
|
+
country_name.strip,
|
38
|
+
a2_country_code,
|
39
|
+
iban_structure.strip,
|
40
|
+
iban_length.to_i,
|
41
|
+
bban_structure.strip,
|
42
|
+
bban_length.to_i,
|
43
|
+
bank_position_from,
|
44
|
+
bank_position_to,
|
45
|
+
branch_position_from,
|
46
|
+
branch_position_to
|
47
|
+
)
|
48
|
+
}
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
# *n: Digits (numeric characters 0 to 9 only)
|
53
|
+
# *a: Upper case letters (alphabetic characters A-Z only)
|
54
|
+
# *c: upper and lower case alphanumeric characters (A-Z, a-z and 0-9)
|
55
|
+
# *e: blank space
|
56
|
+
# *nn!: fixed length
|
57
|
+
# *nn: maximum length
|
58
|
+
#
|
59
|
+
# Example: "AL2!n8!n16!c"
|
60
|
+
def self.structure_regex(structure, anchored=true)
|
61
|
+
source = structure.scan(/([A-Z]+)|(\d+)(!?)([nac])/).map { |exact, length, fixed, code|
|
62
|
+
if exact
|
63
|
+
Regexp.escape(exact)
|
64
|
+
else
|
65
|
+
StructureCodes[code]+(fixed ? "{#{length}}" : "{,#{length}}")
|
66
|
+
end
|
67
|
+
}.join('')
|
68
|
+
|
69
|
+
anchored ? /\A#{source}\z/ : /#{source}/
|
70
|
+
end
|
71
|
+
|
72
|
+
attr_reader :country_name,
|
73
|
+
:a2_country_code,
|
74
|
+
:iban_structure,
|
75
|
+
:iban_length,
|
76
|
+
:bban_structure,
|
77
|
+
:bban_length,
|
78
|
+
:bank_position_from,
|
79
|
+
:bank_position_to,
|
80
|
+
:branch_position_from,
|
81
|
+
:branch_position_to
|
82
|
+
|
83
|
+
def initialize(country_name, a2_country_code, iban_structure, iban_length, bban_structure, bban_length, bank_position_from, bank_position_to, branch_position_from, branch_position_to)
|
84
|
+
@country_name = country_name
|
85
|
+
@a2_country_code = a2_country_code
|
86
|
+
@iban_structure = iban_structure
|
87
|
+
@iban_length = iban_length
|
88
|
+
@bban_structure = bban_structure
|
89
|
+
@bban_length = bban_length
|
90
|
+
@bank_position_from = bank_position_from
|
91
|
+
@bank_position_to = bank_position_to
|
92
|
+
@branch_position_from = branch_position_from
|
93
|
+
@branch_position_to = branch_position_to
|
94
|
+
end
|
95
|
+
|
96
|
+
# @return [Regexp] A regex to verify the structure of the IBAN.
|
97
|
+
def iban_regex
|
98
|
+
@iban_regex ||= self.class.structure_regex(@iban_structure)
|
99
|
+
end
|
100
|
+
|
101
|
+
# @return [Regexp] A regex to identify the structure of the IBAN, without anchors.
|
102
|
+
def unanchored_iban_regex
|
103
|
+
self.class.structure_regex(@iban_structure, false)
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Array<Integer>] An array with the lengths of all components.
|
107
|
+
def component_lengths
|
108
|
+
@bban_structure.scan(/\d+/).map(&:to_i)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Array] An array with the Specification properties. Used for serialization.
|
112
|
+
def to_a
|
113
|
+
[
|
114
|
+
@country_name,
|
115
|
+
@a2_country_code,
|
116
|
+
@iban_structure,
|
117
|
+
@iban_length,
|
118
|
+
@bban_structure,
|
119
|
+
@bban_length,
|
120
|
+
@bank_position_from,
|
121
|
+
@bank_position_to,
|
122
|
+
@branch_position_from,
|
123
|
+
@branch_position_to,
|
124
|
+
]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|