ibandit 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ibandit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Grey Baker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-30 00:00:00.000000000 Z
11
+ date: 2015-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
- version: 0.28.0
47
+ version: 0.29.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: 0.28.0
54
+ version: 0.29.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: sax-machine
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -112,14 +112,18 @@ files:
112
112
  - lib/ibandit/errors.rb
113
113
  - lib/ibandit/german_details_converter.rb
114
114
  - lib/ibandit/iban.rb
115
- - lib/ibandit/iban_builder.rb
115
+ - lib/ibandit/iban_assembler.rb
116
+ - lib/ibandit/iban_splitter.rb
117
+ - lib/ibandit/local_details_cleaner.rb
116
118
  - lib/ibandit/version.rb
117
119
  - spec/fixtures/germany_integration_test_cases.json
118
120
  - spec/fixtures/germany_unit_test_cases.json
119
121
  - spec/ibandit/check_digit_spec.rb
120
122
  - spec/ibandit/german_details_converter_spec.rb
121
- - spec/ibandit/iban_builder_spec.rb
123
+ - spec/ibandit/iban_assembler_spec.rb
122
124
  - spec/ibandit/iban_spec.rb
125
+ - spec/ibandit/iban_splitter_spec.rb
126
+ - spec/ibandit/local_details_cleaner_spec.rb
123
127
  - spec/spec_helper.rb
124
128
  homepage: https://github.com/gocardless/ibandit
125
129
  licenses:
@@ -1,539 +0,0 @@
1
- module Ibandit
2
- module IBANBuilder
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.build(opts)
7
- country_code = opts.delete(:country_code)
8
-
9
- if country_code.nil?
10
- raise ArgumentError, 'You must provide a country_code'
11
- elsif !SUPPORTED_COUNTRY_CODES.include?(country_code)
12
- msg = "Don't know how to build an IBAN for country code #{country_code}"
13
- raise UnsupportedCountryError, msg
14
- else
15
- require_fields(country_code, opts)
16
- bban = send(:"build_#{country_code.downcase}_bban", opts)
17
- build_iban(country_code, bban)
18
- end
19
- end
20
-
21
- ##################################
22
- # Country-specific BBAN creation #
23
- ##################################
24
-
25
- def self.build_at_bban(opts)
26
- # Local account details format:
27
- # aaaaaaaaaaa bbbbb
28
- # Account number may be 4-11 digits long
29
- #
30
- # Local account details name(s):
31
- # Bank code: 'Bankleitzahl' or 'BLZ'
32
- # Account number: 'Kontonummer' or 'Kto.-Nr'
33
- #
34
- # BBAN-specific check digits: none
35
- #
36
- # Other check digits:
37
- # Austrian account numbers have built-in check digits. The checking
38
- # rules are not public.
39
- #
40
- # Padding:
41
- # Add leading zeros to account number if < 11 digits.
42
- [
43
- opts[:bank_code],
44
- opts[:account_number].rjust(11, '0')
45
- ].join
46
- end
47
-
48
- def self.build_be_bban(opts)
49
- # Local account details format: bbb-aaaaaaa-cc
50
- #
51
- # Local account details name(s):
52
- # Single name for all fields: "Rekeningnummer / Numéro de compte"
53
- # All fields are entered in one block, separated by hyphens for clarity
54
- #
55
- # BBAN-specific check digits: none
56
- #
57
- # Other check digits:
58
- # The last two digits of the account number are check digits, but these
59
- # are considered integral to the account number itself. See
60
- # CheckDigit#belgian for details of their calculation.
61
- #
62
- # Additional info:
63
- # The first three digits of Belgian account numbers are the bank_code,
64
- # but the account number is not considered complete without these three
65
- # numbers and the IBAN structure file includes them in its definition of
66
- # the account number. As a result, this method ignores all arguments
67
- # other than the account number.
68
- opts[:account_number].tr('-', '')
69
- end
70
-
71
- def self.build_cy_bban(opts)
72
- # Local account details format:
73
- # bbb-sssss aaaaaaaaaaaaaaaa
74
- # Account number may be 7-16 digits long
75
- #
76
- # Local account details name(s):
77
- # Bank code: 'Kodikos Trapezas'
78
- # Branch code: 'Kodikos Katastimatos'
79
- # Account number: 'Arithmos Logariasmou'
80
- #
81
- # BBAN-specific check digits: none
82
- #
83
- # Other check digits:
84
- # Some Cypriot banks may be using check digits in their account numbers,
85
- # but there's no central source of them.
86
- #
87
- # Padding:
88
- # Add leading zeros to account number if < 16 digits.
89
- #
90
- # Additional info:
91
- # Cypriot bank and branch codes are often communicated as a single code,
92
- # so this method handles being passed them together or separately.
93
- combined_bank_code = opts[:bank_code]
94
- combined_bank_code += opts[:branch_code] || ''
95
-
96
- [
97
- combined_bank_code,
98
- opts[:account_number].rjust(16, '0')
99
- ].join
100
- end
101
-
102
- def self.build_de_bban(opts)
103
- # Local account details format:
104
- # bbbbbbbb aaaaaaaaaa
105
- # Account number may be 1-10 digits long
106
- #
107
- # Local account details name(s):
108
- # Bank code: 'Bankleitzahl' or 'BLZ'
109
- # Account number: 'Kontonummer' or 'Kto.-Nr'
110
- #
111
- # BBAN-specific check digits: none
112
- #
113
- # Other check digits:
114
- # Local bank validation is carried out by matching the bank code with
115
- # the right algorithm key, then applying that bank-specific algorithm.
116
- #
117
- # Padding:
118
- # Add leading zeros to account number if < 10 digits.
119
- #
120
- # Additional info:
121
- # There are many exceptions to the way German bank details translate
122
- # into an IBAN, detailed into a 200 page document compiled by the
123
- # Bundesbank, and handled by the GermanDetailsConverter class.
124
- converted_details = GermanDetailsConverter.convert(opts)
125
-
126
- [
127
- converted_details[:bank_code],
128
- converted_details[:account_number].rjust(10, '0')
129
- ].join
130
- end
131
-
132
- def self.build_ee_bban(opts)
133
- # Local account details format:
134
- # bbaaaaaaaaaaax
135
- # Account number may be up to 14 characters long
136
- # Bank code can be found by extracted from the first two digits of the
137
- # account number and converted using the rules at
138
- # http://www.pangaliit.ee/en/settlements-and-standards/bank-codes-of-estonian-banks
139
- #
140
- # Local account details name(s):
141
- # Account number: 'Kontonumber'
142
- #
143
- # BBAN-specific check digits: none
144
- #
145
- # Other check digits:
146
- # The last digit of the account number is a check digit, but this is
147
- # built-in. An implementation of the check digit algorithm is available
148
- # in CheckDigit#estonian.
149
- #
150
- # Padding:
151
- # Add leading zeros to account number if < 14 digits.
152
- #
153
- # Additional info:
154
- # Estonian national bank details were replaced with IBANs in Feb 2014.
155
- # All Estonian payers should therefore know their IBAN.
156
- domestic_bank_code = opts[:account_number].gsub(/\A0+/, '').slice(0, 2)
157
-
158
- case domestic_bank_code
159
- when '11' then iban_bank_code = '22'
160
- when '93' then iban_bank_code = '00'
161
- else iban_bank_code = domestic_bank_code
162
- end
163
-
164
- iban_bank_code + opts[:account_number].rjust(14, '0')
165
- end
166
-
167
- def self.build_es_bban(opts)
168
- # Local account details format:
169
- # bbbb-ssss-xx-aaaaaaaaaa
170
- # Usually not separated, except by spaces or dashes
171
- #
172
- # Local account details name(s):
173
- # Full details (20 digits): Código Cuenta Cliente
174
- # Bank code (first 4 digits): Código de entidad
175
- # Branch code (next 4 digits): Código de oficina
176
- # Check digits (next 2 ditigs): Dígitos de control
177
- # Account number (final 10 digits): Número de cuenta
178
- #
179
- # BBAN-specific check digits: none
180
- #
181
- # Other check digits:
182
- # The 2 check digits described above are part of the "account number" as
183
- # defined by SWIFT. See CheckDigit#spanish for their generation.
184
- #
185
- # Padding: None
186
- #
187
- # Additional info:
188
- # This method supports being passed the component IBAN parts, as defined
189
- # by SWIFT, or a single 20 digit string.
190
- if opts.include?(:bank_code) && opts.include?(:branch_code)
191
- [
192
- opts[:bank_code],
193
- opts[:branch_code],
194
- opts[:account_number]
195
- ].join
196
- else
197
- opts[:account_number].tr('-', '')
198
- end
199
- end
200
-
201
- def self.build_fi_bban(opts)
202
- # Local account details format:
203
- # bbbbbb-aaaaaaax
204
- # Usually two joined fields separated by a hyphen
205
- #
206
- # Local account details name(s):
207
- # Full details: 'Tilinumeron rakenne'
208
- #
209
- # BBAN-specific check digits: none
210
- #
211
- # Other check digits:
212
- # The last digit of the account number is a check digit. The check digit
213
- # algorithm is available in CheckDigit#lund.
214
- #
215
- # Padding:
216
- # Finnish account numbers need to be expanded into "electronic format"
217
- # by adding zero-padding. The expansion method depends on the first
218
- # character of the bank code.
219
- if %w(4 5 6).include?(opts[:bank_code][0])
220
- [
221
- opts[:bank_code],
222
- opts[:account_number][0],
223
- opts[:account_number][1..-1].rjust(7, '0')
224
- ].join
225
- else
226
- opts[:bank_code] + opts[:account_number].rjust(8, '0')
227
- end
228
- end
229
-
230
- def self.build_fr_bban(opts)
231
- # Local account details format:
232
- # bbbbb-sssss-aaaaaaaaaaa-xx
233
- # 4 separated fields
234
- #
235
- # Local account details name(s):
236
- # Bank code (5 digits): 'Code banque'
237
- # Branch code (5 digits): 'Code guichet'
238
- # Account number (max 11 digits): 'Numéro de compte'
239
- # Check digits (2 digits): 'Clé RIB'
240
- #
241
- # BBAN-specific check digits: none
242
- #
243
- # Other check digits:
244
- # French BBANs include two "RIB key" check digits. In the SWIFT IBAN
245
- # structure definition these check digits are part of the account
246
- # number, although customers expect to see them as a separate field.
247
- # You should concatenate the account number with the entered check
248
- # digits when using this method.
249
- #
250
- # Padding: None
251
- [
252
- opts[:bank_code],
253
- opts[:branch_code],
254
- opts[:account_number]
255
- ].join
256
- end
257
-
258
- def self.build_gb_bban(opts)
259
- # Local account details format:
260
- # ssssss aaaaaaaa
261
- # 2 separated fields
262
- #
263
- # Local account details name(s):
264
- # Branch code: Sort code
265
- # Account number: Account number
266
- #
267
- # BBAN-specific check digits: none
268
- #
269
- # Other check digits:
270
- # Local bank validation is carried out on a bank-by-bank basis, and out
271
- # of scope for this gem.
272
- #
273
- # Padding:
274
- # Add leading zeros to account number if < 8 digits.
275
- #
276
- # Additional info:
277
- # UK BBANs include the first four characters of the BIC. This requires a
278
- # BIC finder lambda to be defined, or the bank_code to be supplied.
279
- branch_code = opts[:branch_code].gsub(/[-\s]/, '')
280
-
281
- if opts[:bank_code]
282
- bank_code = opts[:bank_code]
283
- else
284
- bic = Ibandit.find_bic('GB', branch_code)
285
- raise BicNotFoundError, 'BIC finder failed to find a BIC.' if bic.nil?
286
- bank_code = bic.slice(0, 4)
287
- end
288
-
289
- [
290
- bank_code,
291
- branch_code,
292
- opts[:account_number].gsub(/[-\s]/, '').rjust(8, '0')
293
- ].join
294
- end
295
-
296
- def self.build_lt_bban(opts)
297
- # Additional info:
298
- # Lithuanian national bank details were replaced with IBANs in 2004.
299
- # All Lithuanian payers should therefore know their IBAN, and are
300
- # unlikely to know how it breaks down. This method is included for
301
- # consistency with the IBAN structure only.
302
- [opts[:bank_code], opts[:account_number]].join
303
- end
304
-
305
- def self.build_lu_bban(opts)
306
- # Additional info:
307
- # Luxembourgian national bank details were replaced with IBANs in 2002.
308
- # All Luxembourgian payers should therefore know their IBAN, and are
309
- # unlikely to know how it breaks down. This method is included for
310
- # consistency with the IBAN structure only.
311
- [opts[:bank_code], opts[:account_number]].join
312
- end
313
-
314
- def self.build_lv_bban(opts)
315
- # Additional info:
316
- # Latvian national bank details were replaced with IBANs in 2004.
317
- # All Latvian payers should therefore know their IBAN, and are
318
- # unlikely to know how it breaks down. This method is included for
319
- # consistency with the IBAN structure only.
320
- [opts[:bank_code], opts[:account_number]].join
321
- end
322
-
323
- def self.build_ie_bban(opts)
324
- # Ireland uses the same BBAN construction method as the United Kingdom
325
- branch_code = opts[:branch_code].gsub(/[-\s]/, '')
326
-
327
- if opts[:bank_code]
328
- bank_code = opts[:bank_code]
329
- else
330
- bic = Ibandit.find_bic('IE', branch_code)
331
- raise BicNotFoundError, 'BIC finder failed to find a BIC.' if bic.nil?
332
- bank_code = bic.slice(0, 4)
333
- end
334
-
335
- [
336
- bank_code,
337
- branch_code,
338
- opts[:account_number].gsub(/[-\s]/, '').rjust(8, '0')
339
- ].join
340
- end
341
-
342
- def self.build_it_bban(opts)
343
- # Local account details format:
344
- # x/bbbbb/sssss/cccccccccccc
345
- # 4 fields, separated by slashes
346
- # The check digit is NOT included in the any of the other SWIFT
347
- # elements, so should be passed explicitly or left blank for it to be
348
- # calculated implicitly
349
- #
350
- # Local bank details name(s):
351
- # Check digit: 'CIN'
352
- # Bank code: 'Codice ABI'
353
- # Branch code: 'CAB'
354
- # Account number: 'Numero di conto'
355
- #
356
- # BBAN-specific check digits:
357
- # Italian BBANs include a single BBAN-specific check digit, calculated
358
- # using a bespoke algorithm. See CheckDigit#italian.
359
- #
360
- # Padding:
361
- # Add leading zeros to account number if < 10 digits.
362
- combined_code = [
363
- opts[:bank_code],
364
- opts[:branch_code],
365
- opts[:account_number].rjust(12, '0')
366
- ].join
367
-
368
- check_digit = opts[:check_digit] || CheckDigit.italian(combined_code)
369
-
370
- [check_digit, combined_code].join
371
- end
372
-
373
- def self.build_mc_bban(opts)
374
- # Monaco uses the same BBAN construction method as France
375
- build_fr_bban(opts)
376
- end
377
-
378
- def self.build_nl_bban(opts)
379
- # Local account details format:
380
- # aaaaaaaaaa
381
- # 1 field for account number only
382
- # In theory the bank code can be looked up from the account number, but
383
- # we don't currently have a way of doing so.
384
- #
385
- # Local bank details name(s):
386
- # Account number: 'Rekeningnummer'
387
- #
388
- # BBAN-specific check digits: none
389
- #
390
- # Other check digits:
391
- # A modulus 11 check can be applied to Dutch IBANs. See CheckDigit#dutch
392
- # for an implementation.
393
- #
394
- # Padding:
395
- # Add leading zeros to account number if < 10 digits.
396
- [
397
- opts[:bank_code],
398
- opts[:account_number].rjust(10, '0')
399
- ].join
400
- end
401
-
402
- def self.build_pt_bban(opts)
403
- # Local account details format:
404
- # bbbb.ssss.ccccccccccc.xx
405
- # Usually presented in one block
406
- #
407
- # Local account details name(s):
408
- # Full details: Número de Identificaçao Bancária (NIB)
409
- # Bank code: Código de Banco
410
- # Branch code: Código de Balcao
411
- # Account number: Número de conta
412
- # Local check digits: Dígitos de controlo
413
- #
414
- # BBAN-specific check digits:
415
- # Technically none, but see below
416
- #
417
- # Other check digits:
418
- # The last two digits of Portuguese account numbers, as defined by
419
- # SWIFT, are check digits, calculated using the same algorithm as the
420
- # overall IBAN check digits (i.e., mod_97_10). However, customers expect
421
- # to see these check digits as a separate field. You should concatenate
422
- # the account number with the entered check digits when using this
423
- # method.
424
- #
425
- # Additional info:
426
- # A side-effect of Portugal using the same algorithm for its local check
427
- # digits as the overall IBAN check digits is that the overall digits are
428
- # always 50.
429
- [
430
- opts[:bank_code],
431
- opts[:branch_code],
432
- opts[:account_number]
433
- ].join
434
- end
435
-
436
- def self.build_si_bban(opts)
437
- # Local account details format:
438
- # bbbbb-aaaaaaaaxx
439
- # Two fields, separated by a dash
440
- #
441
- # Local account details name(s):
442
- # Full details: Transakcijski račun
443
- #
444
- # BBAN-specific check digits: none
445
- #
446
- # Other check digits:
447
- # The last two digits of Slovenian account numbers, as defined by
448
- # SWIFT, are check digits, calculated using the same algorithm as the
449
- # overall IBAN check digits (i.e., mod_97_10).
450
- #
451
- # Additional info:
452
- # A side-effect of Slovenia using the same algorithm for its local check
453
- # digits as the overall IBAN check digits is that the overall digits are
454
- # always 56.
455
- [
456
- opts[:bank_code],
457
- opts[:account_number].rjust(10, '0')
458
- ].join
459
- end
460
-
461
- def self.build_sk_bban(opts)
462
- # Local account details format:
463
- # pppppp-aaaaaaaaaa/bbbb
464
- # Three fields (or two, if prefix and account number are merged)
465
- #
466
- # Local account details name(s):
467
- # Account number prefix: Předčíslí
468
- # Account number: číslo účtu
469
- # Bank code: 'Kód banky'
470
- #
471
- # BBAN-specific check digits: none
472
- #
473
- # Other check digits:
474
- # The last digits of the account_number_prefix and the account_number
475
- # are check digits. See CheckDigit#slovakian_prefix and
476
- # CheckDigit#slovakian_basic
477
- #
478
- # Additional info:
479
- # The SWIFT definition of a Slovakian IBAN includes both the account
480
- # number prefix and the account number. This method therefore supports
481
- # passing those fields concatenated.
482
- if opts.include?(:account_number_prefix)
483
- [
484
- opts[:bank_code],
485
- opts[:account_number_prefix].rjust(6, '0'),
486
- opts[:account_number].rjust(10, '0')
487
- ].join
488
- else
489
- [
490
- opts[:bank_code],
491
- opts[:account_number].tr('-', '').rjust(16, '0')
492
- ].join
493
- end
494
- end
495
-
496
- def self.build_sm_bban(opts)
497
- # San Marino uses the same BBAN construction method as Italy
498
- build_it_bban(opts)
499
- end
500
-
501
- ##################
502
- # Helper methods #
503
- ##################
504
-
505
- def self.require_fields(country_code, opts)
506
- required_fields(country_code).each do |arg|
507
- next if opts[arg]
508
-
509
- msg = "#{arg} is a required field when building an #{country_code} IBAN"
510
- raise ArgumentError, msg
511
- end
512
- end
513
-
514
- def self.required_fields(country_code)
515
- case country_code
516
- when 'AT', 'CY', 'DE', 'FI', 'LT', 'LU', 'LV', 'NL', 'SI', 'SK'
517
- %i(bank_code account_number)
518
- when 'BE', 'EE', 'ES'
519
- %i(account_number)
520
- when 'GB', 'IE'
521
- if Ibandit.bic_finder.nil? then %i(bank_code branch_code account_number)
522
- else %i(branch_code account_number)
523
- end
524
- else
525
- %i(bank_code branch_code account_number)
526
- end
527
- end
528
-
529
- def self.build_iban(country_code, bban)
530
- iban = [
531
- country_code,
532
- CheckDigit.iban(country_code, bban),
533
- bban
534
- ].join
535
-
536
- IBAN.new(iban)
537
- end
538
- end
539
- end