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.
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