ibandit 0.2.1 → 0.3.0
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 +4 -4
- data/CHANGELOG.md +10 -3
- data/README.md +3 -0
- data/bin/build_structure_file.rb +41 -5
- data/data/raw/structure_additions.yml +43 -0
- data/data/structures.yml +157 -0
- data/ibandit.gemspec +1 -1
- data/lib/ibandit/iban.rb +147 -60
- data/lib/ibandit/iban_assembler.rb +117 -0
- data/lib/ibandit/iban_splitter.rb +66 -0
- data/lib/ibandit/local_details_cleaner.rb +298 -0
- data/lib/ibandit/version.rb +1 -1
- data/lib/ibandit.rb +9 -1
- data/spec/ibandit/iban_assembler_spec.rb +567 -0
- data/spec/ibandit/iban_spec.rb +294 -13
- data/spec/ibandit/iban_splitter_spec.rb +41 -0
- data/spec/ibandit/local_details_cleaner_spec.rb +688 -0
- metadata +10 -6
- data/lib/ibandit/iban_builder.rb +0 -539
- data/spec/ibandit/iban_builder_spec.rb +0 -892
@@ -0,0 +1,298 @@
|
|
1
|
+
module Ibandit
|
2
|
+
module LocalDetailsCleaner
|
3
|
+
SUPPORTED_COUNTRY_CODES = %w(AT BE CY DE EE ES FI FR GB IE IT LT LU LV MC NL
|
4
|
+
PT SI SK SM).freeze
|
5
|
+
|
6
|
+
def self.clean(local_details)
|
7
|
+
country_code = local_details[:country_code]
|
8
|
+
|
9
|
+
return local_details unless can_clean?(country_code, local_details)
|
10
|
+
|
11
|
+
local_details.merge(
|
12
|
+
public_send(:"clean_#{country_code.downcase}_details", local_details))
|
13
|
+
end
|
14
|
+
|
15
|
+
###########
|
16
|
+
# Helpers #
|
17
|
+
###########
|
18
|
+
|
19
|
+
def self.can_clean?(country_code, local_details)
|
20
|
+
SUPPORTED_COUNTRY_CODES.include?(country_code) &&
|
21
|
+
fields_for?(country_code, local_details)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.fields_for?(country_code, opts)
|
25
|
+
required_fields(country_code).all? { |argument| opts[argument] }
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.required_fields(country_code)
|
29
|
+
case country_code
|
30
|
+
when 'AT', 'CY', 'DE', 'FI', 'LT', 'LU', 'LV', 'NL', 'SI', 'SK'
|
31
|
+
%i(bank_code account_number)
|
32
|
+
when 'BE', 'EE', 'ES'
|
33
|
+
%i(account_number)
|
34
|
+
when 'GB', 'IE'
|
35
|
+
if Ibandit.bic_finder.nil? then %i(bank_code branch_code account_number)
|
36
|
+
else %i(branch_code account_number)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
%i(bank_code branch_code account_number)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
##########################
|
44
|
+
# Country-specific logic #
|
45
|
+
##########################
|
46
|
+
|
47
|
+
def self.clean_at_details(local_details)
|
48
|
+
# Account number may be 4-11 digits long.
|
49
|
+
# Add leading zeros to account number if < 11 digits.
|
50
|
+
return {} unless local_details[:account_number].length >= 4
|
51
|
+
{
|
52
|
+
bank_code: local_details[:bank_code],
|
53
|
+
account_number: local_details[:account_number].rjust(11, '0')
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.clean_be_details(local_details)
|
58
|
+
account_number = local_details[:account_number].tr('-', '')
|
59
|
+
|
60
|
+
{
|
61
|
+
bank_code: local_details[:bank_code] || account_number.slice(0, 3),
|
62
|
+
account_number: account_number
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.clean_cy_details(local_details)
|
67
|
+
# Account number may be 7-16 digits long.
|
68
|
+
# Add leading zeros to account number if < 16 digits.
|
69
|
+
cleaned_bank_code = local_details[:bank_code].gsub(/[-\s]/, '')
|
70
|
+
|
71
|
+
bank_code = cleaned_bank_code.slice(0, 3)
|
72
|
+
branch_code =
|
73
|
+
if local_details[:branch_code]
|
74
|
+
local_details[:branch_code]
|
75
|
+
elsif cleaned_bank_code.length > 3
|
76
|
+
cleaned_bank_code[3..-1]
|
77
|
+
end
|
78
|
+
account_number =
|
79
|
+
if local_details[:account_number].length >= 7
|
80
|
+
local_details[:account_number].rjust(16, '0')
|
81
|
+
else
|
82
|
+
local_details[:account_number]
|
83
|
+
end
|
84
|
+
|
85
|
+
{
|
86
|
+
bank_code: bank_code,
|
87
|
+
branch_code: branch_code,
|
88
|
+
account_number: account_number
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.clean_de_details(local_details)
|
93
|
+
# Account number may be up to 10 digits long.
|
94
|
+
# Add leading zeros to account number if < 10 digits.
|
95
|
+
#
|
96
|
+
# There are many exceptions to the way German bank details translate
|
97
|
+
# into an IBAN, detailed into a 200 page document compiled by the
|
98
|
+
# Bundesbank, and handled by the GermanDetailsConverter class.
|
99
|
+
converted_details = GermanDetailsConverter.convert(local_details)
|
100
|
+
|
101
|
+
return {} unless converted_details[:account_number].length >= 4
|
102
|
+
|
103
|
+
{
|
104
|
+
bank_code: converted_details[:bank_code],
|
105
|
+
account_number: converted_details[:account_number].rjust(10, '0')
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.clean_ee_details(local_details)
|
110
|
+
# Account number may be up to 14 characters long.
|
111
|
+
# Add leading zeros to account number if < 14 digits.
|
112
|
+
#
|
113
|
+
# Bank code can be found by extracted from the first two digits of the
|
114
|
+
# account number and converted using the rules at
|
115
|
+
# http://www.pangaliit.ee/en/settlements-and-standards/bank-codes-of-estonian-banks
|
116
|
+
domestic_bank_code =
|
117
|
+
local_details[:account_number].gsub(/\A0+/, '').slice(0, 2)
|
118
|
+
|
119
|
+
iban_bank_code =
|
120
|
+
case domestic_bank_code
|
121
|
+
when '11' then '22'
|
122
|
+
when '93' then '00'
|
123
|
+
else domestic_bank_code
|
124
|
+
end
|
125
|
+
|
126
|
+
account_number = local_details[:account_number].rjust(14, '0')
|
127
|
+
|
128
|
+
{ bank_code: iban_bank_code, account_number: account_number }
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.clean_es_details(local_details)
|
132
|
+
# This method supports being passed the component IBAN parts, as defined
|
133
|
+
# by SWIFT, or a single 20 digit string.
|
134
|
+
if local_details[:bank_code] && local_details[:branch_code]
|
135
|
+
bank_code = local_details[:bank_code]
|
136
|
+
branch_code = local_details[:branch_code]
|
137
|
+
account_number = local_details[:account_number]
|
138
|
+
else
|
139
|
+
cleaned_account_number = local_details[:account_number].tr('-', '')
|
140
|
+
|
141
|
+
bank_code = cleaned_account_number.slice(0, 4)
|
142
|
+
branch_code = cleaned_account_number.slice(4, 4)
|
143
|
+
account_number = cleaned_account_number[8..-1]
|
144
|
+
end
|
145
|
+
|
146
|
+
{
|
147
|
+
bank_code: bank_code,
|
148
|
+
branch_code: branch_code,
|
149
|
+
account_number: account_number
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.clean_fi_details(local_details)
|
154
|
+
# Finnish account numbers need to be expanded into "electronic format"
|
155
|
+
# by adding zero-padding. The expansion method depends on the first
|
156
|
+
# character of the bank code.
|
157
|
+
account_number =
|
158
|
+
if %w(4 5 6).include?(local_details[:bank_code][0])
|
159
|
+
[
|
160
|
+
local_details[:account_number][0],
|
161
|
+
local_details[:account_number][1..-1].rjust(7, '0')
|
162
|
+
].join
|
163
|
+
else
|
164
|
+
local_details[:account_number].rjust(8, '0')
|
165
|
+
end
|
166
|
+
|
167
|
+
{
|
168
|
+
bank_code: local_details[:bank_code],
|
169
|
+
account_number: account_number
|
170
|
+
}
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.clean_fr_details(local_details)
|
174
|
+
{
|
175
|
+
bank_code: local_details[:bank_code],
|
176
|
+
branch_code: local_details[:branch_code],
|
177
|
+
account_number: local_details[:account_number].gsub(/[-\s]/, '')
|
178
|
+
}
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.clean_gb_details(local_details)
|
182
|
+
# Account number may be 6-8 digits
|
183
|
+
# Add leading zeros to account number if < 8 digits.
|
184
|
+
branch_code = local_details[:branch_code].gsub(/[-\s]/, '')
|
185
|
+
|
186
|
+
if local_details[:bank_code]
|
187
|
+
bank_code = local_details[:bank_code]
|
188
|
+
else
|
189
|
+
bic = Ibandit.find_bic('GB', branch_code)
|
190
|
+
bank_code = bic.nil? ? nil : bic.slice(0, 4)
|
191
|
+
end
|
192
|
+
|
193
|
+
account_number = local_details[:account_number].gsub(/[-\s]/, '')
|
194
|
+
account_number = account_number.rjust(8, '0') if account_number.length > 5
|
195
|
+
|
196
|
+
{
|
197
|
+
bank_code: bank_code,
|
198
|
+
branch_code: branch_code,
|
199
|
+
account_number: account_number
|
200
|
+
}
|
201
|
+
end
|
202
|
+
|
203
|
+
def self.clean_lt_details(local_details)
|
204
|
+
# Lithuanian national bank details were replaced with IBANs in 2004.
|
205
|
+
local_details
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.clean_lu_details(local_details)
|
209
|
+
# Luxembourgian national bank details were replaced with IBANs in 2002.
|
210
|
+
local_details
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.clean_lv_details(local_details)
|
214
|
+
# Latvian national bank details were replaced with IBANs in 2004.
|
215
|
+
local_details
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.clean_ie_details(local_details)
|
219
|
+
# Ireland uses the same local details as the United Kingdom
|
220
|
+
branch_code = local_details[:branch_code].gsub(/[-\s]/, '')
|
221
|
+
|
222
|
+
if local_details[:bank_code]
|
223
|
+
bank_code = local_details[:bank_code]
|
224
|
+
else
|
225
|
+
bic = Ibandit.find_bic('IE', branch_code)
|
226
|
+
bank_code = bic.nil? ? nil : bic.slice(0, 4)
|
227
|
+
end
|
228
|
+
|
229
|
+
account_number = local_details[:account_number].gsub(/[-\s]/, '')
|
230
|
+
account_number = account_number.rjust(8, '0') if account_number.length > 5
|
231
|
+
|
232
|
+
{
|
233
|
+
bank_code: bank_code,
|
234
|
+
branch_code: branch_code,
|
235
|
+
account_number: account_number
|
236
|
+
}
|
237
|
+
end
|
238
|
+
|
239
|
+
def self.clean_it_details(local_details)
|
240
|
+
# Add leading zeros to account number if < 12 digits.
|
241
|
+
{
|
242
|
+
bank_code: local_details[:bank_code],
|
243
|
+
branch_code: local_details[:branch_code],
|
244
|
+
account_number: local_details[:account_number].rjust(12, '0')
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
def self.clean_mc_details(local_details)
|
249
|
+
# Monaco uses the same local details method as France
|
250
|
+
clean_fr_details(local_details)
|
251
|
+
end
|
252
|
+
|
253
|
+
def self.clean_nl_details(local_details)
|
254
|
+
# Add leading zeros to account number if < 10 digits.
|
255
|
+
{
|
256
|
+
bank_code: local_details[:bank_code],
|
257
|
+
account_number: local_details[:account_number].rjust(10, '0')
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
261
|
+
def self.clean_pt_details(local_details)
|
262
|
+
local_details
|
263
|
+
end
|
264
|
+
|
265
|
+
def self.clean_si_details(local_details)
|
266
|
+
# Add leading zeros to account number if < 10 digits.
|
267
|
+
{
|
268
|
+
bank_code: local_details[:bank_code],
|
269
|
+
account_number: local_details[:account_number].rjust(10, '0')
|
270
|
+
}
|
271
|
+
end
|
272
|
+
|
273
|
+
def self.clean_sk_details(local_details)
|
274
|
+
# The SWIFT definition of a Slovakian IBAN includes both the account
|
275
|
+
# number prefix and the account number. This method therefore supports
|
276
|
+
# passing those fields concatenated.
|
277
|
+
account_number =
|
278
|
+
if local_details.include?(:account_number_prefix)
|
279
|
+
[
|
280
|
+
local_details[:account_number_prefix].rjust(6, '0'),
|
281
|
+
local_details[:account_number].rjust(10, '0')
|
282
|
+
].join
|
283
|
+
else
|
284
|
+
local_details[:account_number].tr('-', '').rjust(16, '0')
|
285
|
+
end
|
286
|
+
|
287
|
+
{
|
288
|
+
bank_code: local_details[:bank_code],
|
289
|
+
account_number: account_number
|
290
|
+
}
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.clean_sm_details(local_details)
|
294
|
+
# San Marino uses the same local details method as France
|
295
|
+
clean_it_details(local_details)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
data/lib/ibandit/version.rb
CHANGED
data/lib/ibandit.rb
CHANGED
@@ -2,7 +2,9 @@ require 'ibandit/version'
|
|
2
2
|
require 'ibandit/errors'
|
3
3
|
require 'ibandit/iban'
|
4
4
|
require 'ibandit/german_details_converter'
|
5
|
-
require 'ibandit/
|
5
|
+
require 'ibandit/iban_splitter'
|
6
|
+
require 'ibandit/iban_assembler'
|
7
|
+
require 'ibandit/local_details_cleaner'
|
6
8
|
require 'ibandit/check_digit'
|
7
9
|
|
8
10
|
module Ibandit
|
@@ -13,5 +15,11 @@ module Ibandit
|
|
13
15
|
raise NotImplementedError, 'BIC finder is not defined' unless @bic_finder
|
14
16
|
@bic_finder.call(country_code, national_id)
|
15
17
|
end
|
18
|
+
|
19
|
+
def structures
|
20
|
+
@structures ||= YAML.load_file(
|
21
|
+
File.expand_path('../../data/structures.yml', __FILE__)
|
22
|
+
)
|
23
|
+
end
|
16
24
|
end
|
17
25
|
end
|