ibandit 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Ibandit
2
- VERSION = '0.2.1'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
  end
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/iban_builder'
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