ibandit 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fc1eddf185fe692eb8722cb1d94f8069e21f80df
4
- data.tar.gz: b9df021973596bdfa6df1f554685af30b2038059
3
+ metadata.gz: c1df2cf95c45aa65c6c465e6e84acf90bdbe129c
4
+ data.tar.gz: eb5ec39059d88313840d5d3f97fbe60a65d9612a
5
5
  SHA512:
6
- metadata.gz: 20535679cd0fcdd19e0ce57398d3bc0f4fa539761edb4706a466c34b4934347559903a63612db1a19d73f264490896efa33285220354cc00298a5bf0518ca593
7
- data.tar.gz: aff6275493f96d55daf9a8a840b622b8c1fa97181762b0f8ef83a2e91a2f48a0d5bd868e6ef44cf48564557041c1654555ab0636059a23e2b8930d5a747f0a47
6
+ metadata.gz: d8a8c4d383522ed5295cf35495d321bd5518f3e9d487033dd3a81e4eedf49d2df3f93a2f7be89d32bc93495b01cd620cf0c7fbabab70dee71c97f82fe30679ed
7
+ data.tar.gz: 1b2c6c34acbdf70762aaa588a6e7660895e318c76d2cf0b78ce6ac24276b9836c77924560507b05d54231e9e022cab0b517b2a6adbcccf70d407dc4178152b20
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.6.0 - July 20, 2015
2
+
3
+ - Add support for Sweden
4
+
1
5
  ## 0.5.0 - July 12, 2015
2
6
 
3
7
  - Add an error for unsupported German bank details, and stop raising whilst
data/README.md CHANGED
@@ -12,7 +12,8 @@ allows you to:
12
12
  Ibandit also provides helper methods for validating some countries' local
13
13
  account details.
14
14
 
15
- The gem is kept up to date using the IBAN structure file from SWIFT.
15
+ The gem is kept up to date using the IBAN structure file from SWIFT and the
16
+ Bankleitzahl file from the Deutsche Bundesbank.
16
17
 
17
18
  ## Usage
18
19
 
@@ -309,6 +310,15 @@ iban = Ibandit::IBAN.new(
309
310
  )
310
311
  iban.iban # => "PT50000200230023843000578"
311
312
 
313
+ # San Marino
314
+ iban = Ibandit::IBAN.new(
315
+ country_code: 'SM',
316
+ bank_code: '05428',
317
+ branch_code: '11101',
318
+ account_number: '000000123456'
319
+ )
320
+ iban.iban # => "SM88X0542811101000000123456"
321
+
312
322
  # Slovakia
313
323
  iban = Ibandit::IBAN.new(
314
324
  country_code: 'SK',
@@ -342,14 +352,12 @@ iban = Ibandit::IBAN.new(
342
352
  )
343
353
  iban.iban # => "ES8023100001180000012345"
344
354
 
345
- # San Marino
355
+ # Sweden
346
356
  iban = Ibandit::IBAN.new(
347
- country_code: 'SM',
348
- bank_code: '05428',
349
- branch_code: '11101',
350
- account_number: '000000123456'
357
+ country_code: 'SE',
358
+ account_number: '7507-1211203'
351
359
  )
352
- iban.iban # => "SM88X0542811101000000123456"
360
+ iban.iban # => "SE2680000000075071211203"
353
361
  ```
354
362
 
355
363
  ## Other libraries
@@ -0,0 +1,377 @@
1
+ ---
2
+ # Sources:
3
+ # - https://sv.wikipedia.org/wiki/Lista_%C3%B6ver_clearingnummer_till_svenska_banker
4
+ # - http://www.bgc.se/globalassets/dokument/tekniska-manualer/bankernaskontonummeruppbyggnad_tekniskmanual_sv.pdf
5
+ # - SWIFT IBAN data
6
+ #
7
+ # Fields:
8
+ # - Range: The range of clearing codes for this bank. Used to
9
+ # find the bank information for a given account number.
10
+ #
11
+ # - Bank: The name of the bank.
12
+ #
13
+ # - Clearing code length: Length of the clearing codes issued by this bank. This
14
+ # is 4 in all cases except Swedbank's 8000-range.
15
+ #
16
+ # - Serial number length: Length of the account number that follows the clearing
17
+ # code.
18
+ #
19
+ # - Include clearing code: Whether the clearing code is included in the IBAN account
20
+ # number.
21
+ #
22
+ # - Zerofill serial number: Whether the serial number should be zerofilled if it is
23
+ # shorter than the required serial_number_length.
24
+ #
25
+ - :range: [1100, 1199]
26
+ :bank: Nordea
27
+ :bank_code: 300
28
+ :clearing_code_length: 4
29
+ :serial_number_length: 7
30
+ :zerofill_serial_number: false
31
+ :include_clearing_code: true
32
+ - :range: [1200, 1399]
33
+ :bank: Danske Bank
34
+ :bank_code: 120
35
+ :clearing_code_length: 4
36
+ :serial_number_length: 7
37
+ :zerofill_serial_number: false
38
+ :include_clearing_code: true
39
+ - :range: [1400, 2099]
40
+ :bank: Nordea
41
+ :bank_code: 300
42
+ :clearing_code_length: 4
43
+ :serial_number_length: 7
44
+ :zerofill_serial_number: false
45
+ :include_clearing_code: true
46
+ - :range: [2300, 2399]
47
+ :bank: Ålandsbanken Sverige AB
48
+ :bank_code: 230
49
+ :clearing_code_length: 4
50
+ :serial_number_length: 7
51
+ :zerofill_serial_number: false
52
+ :include_clearing_code: true
53
+ - :range: [2400, 2499]
54
+ :bank: Danske Bank
55
+ :bank_code: 120
56
+ :clearing_code_length: 4
57
+ :serial_number_length: 7
58
+ :zerofill_serial_number: false
59
+ :include_clearing_code: true
60
+ # NOTE: We're ignoring Sambox bank (clearing number 2950) because the only
61
+ # reference I've seen is wikipedia. Sambox does have its own bank code (295)
62
+ # though, so we may want to revisit.
63
+ - :range: [3000, 3299]
64
+ :bank: Nordea
65
+ :bank_code: 300
66
+ :clearing_code_length: 4
67
+ :serial_number_length: 7
68
+ :zerofill_serial_number: false
69
+ :include_clearing_code: true
70
+ - :range: [3300, 3300]
71
+ :bank: Nordea Personkonto
72
+ # NOTE: We're routing Nordea Personkonto to the main Nordea bank code, but
73
+ # it may belong at one of the other Nordea codes we're not currently using.
74
+ :bank_code: 300
75
+ :clearing_code_length: 4
76
+ :serial_number_length: 10
77
+ :zerofill_serial_number: false
78
+ :include_clearing_code: false
79
+ - :range: [3301, 3399]
80
+ :bank: Nordea
81
+ :bank_code: 300
82
+ :clearing_code_length: 4
83
+ :serial_number_length: 7
84
+ :zerofill_serial_number: false
85
+ :include_clearing_code: true
86
+ - :range: [3400, 3409]
87
+ :bank: Länsförsäkringar Bank
88
+ :bank_code: 902
89
+ :clearing_code_length: 4
90
+ :serial_number_length: 7
91
+ :zerofill_serial_number: false
92
+ :include_clearing_code: true
93
+ - :range: [3410, 3781]
94
+ :bank: Nordea
95
+ :bank_code: 300
96
+ :clearing_code_length: 4
97
+ :serial_number_length: 7
98
+ :zerofill_serial_number: false
99
+ :include_clearing_code: true
100
+ - :range: [3782, 3782]
101
+ :bank: Nordea Personkonto
102
+ # NOTE: We're routing Nordea Personkonto to the main Nordea bank code, but
103
+ # it may belong at one of the other Nordea codes we're not currently using.
104
+ :bank_code: 300
105
+ :clearing_code_length: 4
106
+ :serial_number_length: 10
107
+ :zerofill_serial_number: false
108
+ :include_clearing_code: fase
109
+ - :range: [3783, 3999]
110
+ :bank: Nordea
111
+ :bank_code: 300
112
+ :clearing_code_length: 4
113
+ :serial_number_length: 7
114
+ :zerofill_serial_number: false
115
+ :include_clearing_code: true
116
+ - :range: [4000, 4999]
117
+ :bank: Nordea
118
+ :bank_code: 300
119
+ :clearing_code_length: 4
120
+ :serial_number_length: 7
121
+ :zerofill_serial_number: false
122
+ :include_clearing_code: true
123
+ - :range: [5000, 5999]
124
+ :bank: SEB
125
+ :bank_code: 500
126
+ :clearing_code_length: 4
127
+ :serial_number_length: 7
128
+ :zerofill_serial_number: false
129
+ :include_clearing_code: true
130
+ - :range: [6000, 6999]
131
+ :bank: Handelsbanken
132
+ :bank_code: 600
133
+ :clearing_code_length: 4
134
+ :serial_number_length: 9
135
+ :zerofill_serial_number: true
136
+ :include_clearing_code: false
137
+ - :range: [7000, 7999]
138
+ :bank: Swedbank
139
+ :bank_code: 800
140
+ :clearing_code_length: 4
141
+ :serial_number_length: 7
142
+ :zerofill_serial_number: false
143
+ :include_clearing_code: true
144
+ - :range: [8000, 8999]
145
+ # NOTE: This range also includes independent savings banks, some of which
146
+ # appear to have their own bank code. For now we always use the Swedbank bank
147
+ # code - we should revisit if we see failures as a result.
148
+ :bank: Swedbank
149
+ :bank_code: 800
150
+ :clearing_code_length: 5
151
+ :serial_number_length: 10
152
+ :zerofill_serial_number: true
153
+ :include_clearing_code: true
154
+ - :range: [9020, 9029]
155
+ :bank: Länsförsäkringar Bank
156
+ :bank_code: 902
157
+ :clearing_code_length: 4
158
+ :serial_number_length: 7
159
+ :zerofill_serial_number: false
160
+ :include_clearing_code: true
161
+ - :range: [9040, 9049]
162
+ :bank: Citibank
163
+ :bank_code: 904
164
+ :clearing_code_length: 4
165
+ :serial_number_length: 7
166
+ :zerofill_serial_number: false
167
+ :include_clearing_code: true
168
+ - :range: [9060, 9069]
169
+ :bank: Länsförsäkringar Bank
170
+ :bank_code: 902
171
+ :clearing_code_length: 4
172
+ :serial_number_length: 7
173
+ :zerofill_serial_number: false
174
+ :include_clearing_code: true
175
+ - :range: [9090, 9099]
176
+ :bank: ABN Amro
177
+ :bank_code: 909
178
+ :clearing_code_length: 4
179
+ :serial_number_length: 7
180
+ :zerofill_serial_number: false
181
+ :include_clearing_code: true
182
+ - :range: [9100, 9109]
183
+ :bank: Nordnet Bank
184
+ :bank_code: 910
185
+ :clearing_code_length: 4
186
+ :serial_number_length: 7
187
+ :zerofill_serial_number: false
188
+ :include_clearing_code: true
189
+ - :range: [9120, 9124]
190
+ :bank: SEB
191
+ :bank_code: 500
192
+ :clearing_code_length: 4
193
+ :serial_number_length: 7
194
+ :zerofill_serial_number: false
195
+ :include_clearing_code: true
196
+ - :range: [9130, 9149]
197
+ :bank: SEB
198
+ :bank_code: 500
199
+ :clearing_code_length: 4
200
+ :serial_number_length: 7
201
+ :zerofill_serial_number: false
202
+ :include_clearing_code: true
203
+ - :range: [9150, 9169]
204
+ :bank: Skandiabanken
205
+ :bank_code: 915
206
+ :clearing_code_length: 4
207
+ :serial_number_length: 7
208
+ :zerofill_serial_number: false
209
+ :include_clearing_code: true
210
+ - :range: [9170, 9179]
211
+ :bank: IKANO Bank
212
+ :bank_code: 917
213
+ :clearing_code_length: 4
214
+ :serial_number_length: 7
215
+ :zerofill_serial_number: false
216
+ :include_clearing_code: true
217
+ - :range: [9180, 9189]
218
+ :bank: Danske Bank
219
+ :bank_code: 120
220
+ :clearing_code_length: 4
221
+ :serial_number_length: 10
222
+ :zerofill_serial_number: false
223
+ :include_clearing_code: false
224
+ - :range: [9190, 9199]
225
+ :bank: Den Norske Bank
226
+ :bank_code: 919
227
+ :clearing_code_length: 4
228
+ :serial_number_length: 7
229
+ :zerofill_serial_number: false
230
+ :include_clearing_code: true
231
+ - :range: [9230, 9239]
232
+ :bank: Marginalen Bank
233
+ :bank_code: 923
234
+ :clearing_code_length: 4
235
+ :serial_number_length: 7
236
+ :zerofill_serial_number: false
237
+ :include_clearing_code: true
238
+ - :range: [9250, 9259]
239
+ :bank: SBAB
240
+ :bank_code: 925
241
+ :clearing_code_length: 4
242
+ :serial_number_length: 7
243
+ :zerofill_serial_number: false
244
+ :include_clearing_code: true
245
+ - :range: [9260, 9269]
246
+ :bank: Den Norske Bank
247
+ :bank_code: 919
248
+ :clearing_code_length: 4
249
+ :serial_number_length: 7
250
+ :zerofill_serial_number: false
251
+ :include_clearing_code: true
252
+ - :range: [9270, 9279]
253
+ :bank: ICA Banken
254
+ :bank_code: 927
255
+ :clearing_code_length: 4
256
+ :serial_number_length: 7
257
+ :zerofill_serial_number: false
258
+ :include_clearing_code: true
259
+ - :range: [9280, 9289]
260
+ :bank: Resurs Banken AB
261
+ :bank_code: 928
262
+ :clearing_code_length: 4
263
+ :serial_number_length: 7
264
+ :zerofill_serial_number: false
265
+ :include_clearing_code: true
266
+ - :range: [9300, 9329]
267
+ :bank: Sparbanken Öresund
268
+ :bank_code: 930
269
+ :clearing_code_length: 4
270
+ :serial_number_length: 10
271
+ :zerofill_serial_number: false
272
+ :include_clearing_code: false
273
+ - :range: [9330, 9349]
274
+ :bank: Sparbanken Öresund
275
+ :bank_code: 933
276
+ :clearing_code_length: 4
277
+ :serial_number_length: 10
278
+ :zerofill_serial_number: false
279
+ :include_clearing_code: false
280
+ - :range: [9390, 9399]
281
+ :bank: Landshypotek AB
282
+ :bank_code: 939
283
+ :clearing_code_length: 4
284
+ :serial_number_length: 7
285
+ :zerofill_serial_number: false
286
+ :include_clearing_code: true
287
+ - :range: [9400, 9449]
288
+ :bank: Forex Bank AB
289
+ :bank_code: 940
290
+ :clearing_code_length: 4
291
+ :serial_number_length: 7
292
+ :zerofill_serial_number: false
293
+ :include_clearing_code: true
294
+ - :range: [9460, 9469]
295
+ :bank: GE Money Bank
296
+ :bank_code: 945
297
+ :clearing_code_length: 4
298
+ :serial_number_length: 7
299
+ :zerofill_serial_number: false
300
+ :include_clearing_code: true
301
+ - :range: [9470, 9479]
302
+ :bank: BNP Paribas
303
+ :bank_code: 947
304
+ :clearing_code_length: 4
305
+ :serial_number_length: 7
306
+ :zerofill_serial_number: false
307
+ :include_clearing_code: true
308
+ - :range: [9500, 9549]
309
+ :bank: Nordea - PlusGirot
310
+ :bank_code: 950
311
+ :clearing_code_length: 4
312
+ :serial_number_length: 10
313
+ :zerofill_serial_number: true
314
+ :include_clearing_code: true
315
+ - :range: [9550, 9569]
316
+ :bank: Avanza Bank
317
+ :bank_code: 955
318
+ :clearing_code_length: 4
319
+ :serial_number_length: 7
320
+ :zerofill_serial_number: false
321
+ :include_clearing_code: true
322
+ - :range: [9570, 9579]
323
+ :bank: Sparbanken Syd
324
+ :bank_code: 957
325
+ :clearing_code_length: 4
326
+ :serial_number_length: 10
327
+ :zerofill_serial_number: false
328
+ :include_clearing_code: false
329
+ - :range: [9590, 9599]
330
+ :bank: Erik Penser AB
331
+ :bank_code: 959
332
+ :clearing_code_length: 4
333
+ :serial_number_length: 7
334
+ :zerofill_serial_number: false
335
+ :include_clearing_code: true
336
+ - :range: [9630, 9639]
337
+ :bank: "Lån & Spar Bank"
338
+ :bank_code: 963
339
+ :clearing_code_length: 4
340
+ :serial_number_length: 7
341
+ :zerofill_serial_number: false
342
+ :include_clearing_code: true
343
+ - :range: [9640, 9649]
344
+ :bank: Nordax Finans
345
+ :bank_code: 964
346
+ :clearing_code_length: 4
347
+ :serial_number_length: 7
348
+ :zerofill_serial_number: false
349
+ :include_clearing_code: true
350
+ - :range: [9660, 9669]
351
+ :bank: Amfa Bank
352
+ :bank_code: 966
353
+ :clearing_code_length: 4
354
+ :serial_number_length: 7
355
+ :zerofill_serial_number: false
356
+ :include_clearing_code: true
357
+ - :range: [9880, 9889]
358
+ :bank: Riksgälden
359
+ :bank_code: 988
360
+ :clearing_code_length: 4
361
+ :serial_number_length: 7
362
+ :zerofill_serial_number: false
363
+ :include_clearing_code: true
364
+ - :range: [9890, 9899]
365
+ :bank: Riksgälden
366
+ :bank_code: 989
367
+ :clearing_code_length: 4
368
+ :serial_number_length: 10
369
+ :zerofill_serial_number: false
370
+ :include_clearing_code: false
371
+ - :range: [9960, 9969]
372
+ :bank: Nordea - PlusGirot
373
+ :bank_code: 950
374
+ :clearing_code_length: 4
375
+ :serial_number_length: 10
376
+ :zerofill_serial_number: true
377
+ :include_clearing_code: true
data/lib/ibandit.rb CHANGED
@@ -3,6 +3,7 @@ require 'ibandit/version'
3
3
  require 'ibandit/errors'
4
4
  require 'ibandit/iban'
5
5
  require 'ibandit/german_details_converter'
6
+ require 'ibandit/swedish_details_converter'
6
7
  require 'ibandit/iban_splitter'
7
8
  require 'ibandit/iban_assembler'
8
9
  require 'ibandit/local_details_cleaner'
data/lib/ibandit/iban.rb CHANGED
@@ -69,7 +69,7 @@ module Ibandit
69
69
  valid_branch_code_format?,
70
70
  valid_account_number_format?,
71
71
  valid_local_modulus_check?,
72
- supports_iban_determination?
72
+ passes_country_specific_checks?
73
73
  ].all?
74
74
  end
75
75
 
@@ -225,6 +225,16 @@ module Ibandit
225
225
  valid_modulus_check_bank_code? && valid_modulus_check_account_number?
226
226
  end
227
227
 
228
+ def passes_country_specific_checks?
229
+ return unless valid_country_code?
230
+
231
+ case country_code
232
+ when 'DE' then supports_iban_determination?
233
+ when 'SE' then valid_swedish_details?
234
+ else true
235
+ end
236
+ end
237
+
228
238
  def supports_iban_determination?
229
239
  return unless valid_format?
230
240
  return true unless country_code == 'DE'
@@ -242,6 +252,26 @@ module Ibandit
242
252
  end
243
253
  end
244
254
 
255
+ def valid_swedish_details?
256
+ return true unless country_code == 'SE'
257
+
258
+ bank_details = { bank_code: bank_code, account_number: account_number }
259
+
260
+ unless SwedishDetailsConverter.valid_bank_code?(bank_details)
261
+ bank_code_field = bank_code.nil? ? :account_number : :bank_code
262
+ @errors[bank_code_field] = Ibandit.translate(:is_invalid)
263
+ @errors.delete(:bank_code) if bank_code.nil?
264
+ return false
265
+ end
266
+
267
+ unless SwedishDetailsConverter.valid_length?(bank_details)
268
+ @errors[:account_number] = Ibandit.translate(:is_invalid)
269
+ return false
270
+ end
271
+
272
+ true
273
+ end
274
+
245
275
  ###################
246
276
  # Private methods #
247
277
  ###################
@@ -1,7 +1,7 @@
1
1
  module Ibandit
2
2
  module IBANAssembler
3
3
  SUPPORTED_COUNTRY_CODES = %w(AT BE CY DE EE ES FI FR GB GR IE IT LT LU LV MC
4
- MT NL PT SI SK SM).freeze
4
+ MT NL PT SE SI SK SM).freeze
5
5
 
6
6
  EXCEPTION_COUNTRY_CODES = %w(IT SM BE).freeze
7
7
 
@@ -84,7 +84,7 @@ module Ibandit
84
84
 
85
85
  def self.required_fields(country_code)
86
86
  case country_code
87
- when 'AT', 'CY', 'DE', 'EE', 'FI', 'LT', 'LU', 'LV', 'NL', 'SI', 'SK'
87
+ when *%w(AT CY DE EE FI LT LU LV NL SE SI SK)
88
88
  %i(bank_code account_number)
89
89
  when 'BE'
90
90
  %i(account_number)
@@ -1,7 +1,7 @@
1
1
  module Ibandit
2
2
  module LocalDetailsCleaner
3
3
  SUPPORTED_COUNTRY_CODES = %w(AT BE CY DE EE ES FI FR GB GR IE IT LT LU LV MC
4
- MT NL PT SI SK SM).freeze
4
+ MT NL PT SE SI SK SM).freeze
5
5
 
6
6
  def self.clean(local_details)
7
7
  country_code = local_details[:country_code]
@@ -29,7 +29,7 @@ module Ibandit
29
29
  case country_code
30
30
  when 'AT', 'CY', 'DE', 'FI', 'LT', 'LU', 'LV', 'NL', 'SI', 'SK'
31
31
  %i(bank_code account_number)
32
- when 'BE', 'EE', 'ES'
32
+ when 'BE', 'EE', 'ES', 'SE'
33
33
  %i(account_number)
34
34
  when 'GB', 'IE', 'MT'
35
35
  if Ibandit.bic_finder.nil? then %i(bank_code branch_code account_number)
@@ -294,6 +294,18 @@ module Ibandit
294
294
  local_details
295
295
  end
296
296
 
297
+ def self.clean_se_details(local_details)
298
+ converted_details =
299
+ SwedishDetailsConverter.convert(local_details[:account_number])
300
+
301
+ bank_code = local_details[:bank_code] || converted_details[:bank_code]
302
+
303
+ {
304
+ bank_code: bank_code,
305
+ account_number: converted_details[:account_number]
306
+ }
307
+ end
308
+
297
309
  def self.clean_si_details(local_details)
298
310
  # Add leading zeros to account number if < 10 digits.
299
311
  {
@@ -0,0 +1,103 @@
1
+ module Ibandit
2
+ module SwedishDetailsConverter
3
+ def self.convert(account_number)
4
+ cleaned_account_number =
5
+ account_number.gsub(/[-.\s]/, '').gsub(/\A0+/, '')
6
+
7
+ bank_info = bank_info_for(cleaned_account_number.slice(0, 4))
8
+
9
+ if bank_info.nil?
10
+ return { bank_code: nil,
11
+ account_number: cleaned_account_number.rjust(17, '0') }
12
+ end
13
+
14
+ clearing_code_length = bank_info.fetch(:clearing_code_length)
15
+ serial_number_length = bank_info.fetch(:serial_number_length)
16
+
17
+ clearing_code = cleaned_account_number.slice(0, clearing_code_length)
18
+ serial_number = cleaned_account_number[clearing_code_length..-1]
19
+
20
+ if bank_info.fetch(:zerofill_serial_number)
21
+ serial_number = serial_number.rjust(serial_number_length, '0')
22
+ end
23
+
24
+ iban_account_number =
25
+ if bank_info.fetch(:include_clearing_code)
26
+ (clearing_code + serial_number).rjust(17, '0')
27
+ else
28
+ serial_number.rjust(17, '0')
29
+ end
30
+
31
+ {
32
+ bank_code: bank_info.fetch(:bank_code).to_s,
33
+ account_number: iban_account_number
34
+ }
35
+ end
36
+
37
+ def self.valid_bank_code?(bank_code: bank_code,
38
+ account_number: account_number)
39
+ possible_bank_infos = possible_bank_info_for(
40
+ bank_code: bank_code, account_number: account_number
41
+ )
42
+
43
+ possible_bank_infos.any?
44
+ end
45
+
46
+ def self.valid_length?(bank_code: bank_code, account_number: account_number)
47
+ return unless valid_bank_code?(
48
+ bank_code: bank_code, account_number: account_number
49
+ )
50
+
51
+ cleaned_account_number = account_number.gsub(/\A0+/, '')
52
+
53
+ possible_bank_infos = possible_bank_info_for(
54
+ bank_code: bank_code, account_number: account_number
55
+ )
56
+
57
+ possible_bank_infos.any? do |bank|
58
+ length = bank.fetch(:serial_number_length)
59
+ length += bank[:clearing_code_length] if bank[:include_clearing_code]
60
+
61
+ if bank[:zerofill_serial_number] && !bank[:include_clearing_code]
62
+ serial_number_length = bank.fetch(:serial_number_length)
63
+ cleaned_account_number =
64
+ cleaned_account_number.rjust(serial_number_length, '0')
65
+ end
66
+
67
+ cleaned_account_number.length == length
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def self.bank_info_for(clearing_code)
74
+ bank_info_table.find { |bank| bank[:range].include?(clearing_code.to_i) }
75
+ end
76
+ private_class_method :bank_info_for
77
+
78
+ def self.possible_bank_info_for(bank_code: bank_code,
79
+ account_number: account_number)
80
+ clearing_number = account_number.gsub(/\A0+/, '').slice(0, 4).to_i
81
+
82
+ possible_bank_infos = bank_info_table.select do |bank|
83
+ bank.fetch(:bank_code).to_s == bank_code
84
+ end
85
+
86
+ possible_bank_infos.select do |bank|
87
+ !bank[:include_clearing_code] || bank[:range].include?(clearing_number)
88
+ end
89
+ end
90
+ private_class_method :possible_bank_info_for
91
+
92
+ def self.bank_info_table
93
+ @swedish_bank_lookup ||=
94
+ begin
95
+ relative_path = '../../../data/raw/swedish_bank_lookup.yml'
96
+ raw_info = YAML.load_file(File.expand_path(relative_path, __FILE__))
97
+
98
+ raw_info.map { |bank| bank.merge(range: Range.new(*bank[:range])) }
99
+ end
100
+ end
101
+ private_class_method :bank_info_table
102
+ end
103
+ end
@@ -1,3 +1,3 @@
1
1
  module Ibandit
2
- VERSION = '0.5.0'.freeze
2
+ VERSION = '0.6.0'.freeze
3
3
  end
@@ -554,6 +554,30 @@ describe Ibandit::IBANAssembler do
554
554
  end
555
555
  end
556
556
 
557
+ context 'with SE as the country_code' do
558
+ let(:args) do
559
+ {
560
+ country_code: 'SE',
561
+ bank_code: '500',
562
+ account_number: '00000050011045825'
563
+ }
564
+ end
565
+
566
+ it { is_expected.to eq('SE0450000000050011045825') }
567
+
568
+ it_behaves_like 'allows round trips', 'SE04 5000 0000 0500 1104 5825'
569
+
570
+ context 'without a bank_code' do
571
+ before { args.delete(:bank_code) }
572
+ it { is_expected.to be_nil }
573
+ end
574
+
575
+ context 'without an account_number' do
576
+ before { args.delete(:account_number) }
577
+ it { is_expected.to be_nil }
578
+ end
579
+ end
580
+
557
581
  context 'with SI as the country_code' do
558
582
  let(:args) do
559
583
  {
@@ -1222,7 +1222,7 @@ describe Ibandit::IBAN do
1222
1222
  end
1223
1223
 
1224
1224
  describe 'supports_iban_determination?' do
1225
- subject(:valid_local_modulus_check?) { iban.supports_iban_determination? }
1225
+ subject { iban.supports_iban_determination? }
1226
1226
 
1227
1227
  context 'with unsupported account details' do
1228
1228
  let(:arg) do
@@ -1292,6 +1292,68 @@ describe Ibandit::IBAN do
1292
1292
  end
1293
1293
  end
1294
1294
  end
1295
+
1296
+ describe 'valid_swedish_details?' do
1297
+ subject { iban.valid_swedish_details? }
1298
+
1299
+ context 'with an account number that is too long' do
1300
+ let(:arg) do
1301
+ {
1302
+ country_code: 'SE',
1303
+ bank_code: '500',
1304
+ account_number: '00000543910240391'
1305
+ }
1306
+ end
1307
+
1308
+ it { is_expected.to eq(false) }
1309
+
1310
+ context 'locale en', locale: :en do
1311
+ specify do
1312
+ iban.valid_swedish_details?
1313
+ expect(iban.errors).to eq(account_number: 'is invalid')
1314
+ end
1315
+ end
1316
+ end
1317
+
1318
+ context "with an account number that doesn't have a bank code" do
1319
+ let(:arg) do
1320
+ {
1321
+ country_code: 'SE',
1322
+ bank_code: nil,
1323
+ account_number: '00000000000010011'
1324
+ }
1325
+ end
1326
+
1327
+ it { is_expected.to eq(false) }
1328
+
1329
+ context 'locale en', locale: :en do
1330
+ specify do
1331
+ iban.valid?
1332
+ expect(iban.errors).to include(account_number: 'is invalid')
1333
+ expect(iban.errors).to_not include(:bank_code)
1334
+ end
1335
+ end
1336
+ end
1337
+
1338
+ context 'with a bad bank code' do
1339
+ let(:arg) do
1340
+ {
1341
+ country_code: 'SE',
1342
+ bank_code: '902',
1343
+ account_number: '00000054391024039'
1344
+ }
1345
+ end
1346
+
1347
+ it { is_expected.to eq(false) }
1348
+
1349
+ context 'locale en', locale: :en do
1350
+ specify do
1351
+ iban.valid_swedish_details?
1352
+ expect(iban.errors).to eq(bank_code: 'is invalid')
1353
+ end
1354
+ end
1355
+ end
1356
+ end
1295
1357
  end
1296
1358
 
1297
1359
  describe '#valid?' do
@@ -1325,6 +1387,10 @@ describe Ibandit::IBAN do
1325
1387
  it 'runs local modulus checks' do
1326
1388
  expect(iban).to receive(:valid_local_modulus_check?).at_least(1)
1327
1389
  end
1390
+
1391
+ it 'runs country specific checks' do
1392
+ expect(iban).to receive(:passes_country_specific_checks?).at_least(1)
1393
+ end
1328
1394
  end
1329
1395
 
1330
1396
  context 'for a valid Albanian IBAN' do
@@ -682,6 +682,27 @@ describe Ibandit::LocalDetailsCleaner do
682
682
  end
683
683
  end
684
684
 
685
+ context 'Sweden' do
686
+ let(:country_code) { 'SE' }
687
+ let(:bank_code) { '501' }
688
+ let(:account_number) { '5013-1007270' }
689
+
690
+ its([:bank_code]) { is_expected.to eq('501') }
691
+ its([:account_number]) { is_expected.to eq('00000050131007270') }
692
+
693
+ context 'without an account number' do
694
+ let(:account_number) { nil }
695
+ it { is_expected.to eq(local_details) }
696
+ end
697
+
698
+ context 'without a bank code' do
699
+ let(:bank_code) { nil }
700
+
701
+ its([:bank_code]) { is_expected.to eq('500') }
702
+ its([:account_number]) { is_expected.to eq('00000050131007270') }
703
+ end
704
+ end
705
+
685
706
  context 'Slovenia' do
686
707
  let(:country_code) { 'SI' }
687
708
  let(:bank_code) { '19100' }
@@ -0,0 +1,237 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ibandit::SwedishDetailsConverter do
4
+ describe '.convert' do
5
+ subject { described_class.convert(account_number) }
6
+
7
+ context 'with a type-1 account number' do
8
+ let(:account_number) { '12810105723' }
9
+
10
+ its([:bank_code]) { is_expected.to eq('120') }
11
+ its([:account_number]) { is_expected.to eq('00000012810105723') }
12
+
13
+ context 'that includes hyphens' do
14
+ let(:account_number) { '1281-0105723' }
15
+
16
+ its([:bank_code]) { is_expected.to eq('120') }
17
+ its([:account_number]) { is_expected.to eq('00000012810105723') }
18
+ end
19
+
20
+ context 'that includes spaces' do
21
+ let(:account_number) { '1281 0105723' }
22
+
23
+ its([:bank_code]) { is_expected.to eq('120') }
24
+ its([:account_number]) { is_expected.to eq('00000012810105723') }
25
+ end
26
+
27
+ context 'that includes full stops' do
28
+ let(:account_number) { '1281.010.572.3' }
29
+
30
+ its([:bank_code]) { is_expected.to eq('120') }
31
+ its([:account_number]) { is_expected.to eq('00000012810105723') }
32
+ end
33
+
34
+ context 'that has been zero-padded' do
35
+ let(:account_number) { '000012810105723' }
36
+
37
+ its([:bank_code]) { is_expected.to eq('120') }
38
+ its([:account_number]) { is_expected.to eq('00000012810105723') }
39
+ end
40
+
41
+ context 'that needs the account number part to be zero-padded' do
42
+ let(:account_number) { '1281-1' }
43
+
44
+ its([:bank_code]) { is_expected.to eq('120') }
45
+ its([:account_number]) { is_expected.to eq('00000000000012811') }
46
+ end
47
+
48
+ context 'from SEB' do
49
+ let(:account_number) { '5439-10 240 39' }
50
+
51
+ its([:bank_code]) { is_expected.to eq('500') }
52
+ its([:account_number]) { is_expected.to eq('00000054391024039') }
53
+ end
54
+ end
55
+
56
+ context "with a clearing code that doesn't match any banks" do
57
+ let(:account_number) { '1001-1' }
58
+
59
+ its([:bank_code]) { is_expected.to eq(nil) }
60
+ its([:account_number]) { is_expected.to eq('00000000000010011') }
61
+ end
62
+
63
+ context 'with a Swedbank clearing code' do
64
+ let(:account_number) { '7507-1211203' }
65
+
66
+ its([:bank_code]) { is_expected.to eq('800') }
67
+ its([:account_number]) { is_expected.to eq('00000075071211203') }
68
+
69
+ context 'in the 8000s range' do
70
+ let(:account_number) { '8327-9 33395390-9' }
71
+
72
+ its([:bank_code]) { is_expected.to eq('800') }
73
+ its([:account_number]) { is_expected.to eq('00832790333953909') }
74
+ end
75
+
76
+ context 'another in the 8000s range' do
77
+ let(:account_number) { '8201-6 914357963-0' }
78
+
79
+ its([:bank_code]) { is_expected.to eq('800') }
80
+ its([:account_number]) { is_expected.to eq('00820169143579630') }
81
+ end
82
+ end
83
+
84
+ context 'with a Sparbanken Öresund clearing code' do
85
+ let(:account_number) { '9300-35299478' }
86
+
87
+ its([:bank_code]) { is_expected.to eq('930') }
88
+ its([:account_number]) { is_expected.to eq('00000000035299478') }
89
+
90
+ context 'with clearing number 9330 or above' do
91
+ let(:account_number) { '9330-5930160535' }
92
+
93
+ its([:bank_code]) { is_expected.to eq('933') }
94
+ its([:account_number]) { is_expected.to eq('00000005930160535') }
95
+ end
96
+ end
97
+
98
+ context 'with a Sparbanken Syd clearing code' do
99
+ let(:account_number) { '9570-5250093407' }
100
+
101
+ its([:bank_code]) { is_expected.to eq('957') }
102
+ its([:account_number]) { is_expected.to eq('00000005250093407') }
103
+ end
104
+
105
+ context 'with a Handelsbanken clearing code' do
106
+ let(:account_number) { '6000-806967498' }
107
+
108
+ its([:bank_code]) { is_expected.to eq('600') }
109
+ its([:account_number]) { is_expected.to eq('00000000806967498') }
110
+
111
+ context 'that has clearing code 6240' do
112
+ let(:account_number) { '6240-219161038' }
113
+
114
+ its([:bank_code]) { is_expected.to eq('600') }
115
+ its([:account_number]) { is_expected.to eq('00000000219161038') }
116
+ end
117
+
118
+ context 'that only has an 8 digit serial number' do
119
+ let(:account_number) { '6240-21916103' }
120
+
121
+ its([:bank_code]) { is_expected.to eq('600') }
122
+ its([:account_number]) { is_expected.to eq('00000000021916103') }
123
+ end
124
+ end
125
+
126
+ context 'with a Nordea PlusGirot clearing code' do
127
+ let(:account_number) { '9960-3401258276' }
128
+
129
+ its([:bank_code]) { is_expected.to eq('950') }
130
+ its([:account_number]) { is_expected.to eq('00099603401258276') }
131
+ end
132
+ end
133
+
134
+ describe '.valid_length?' do
135
+ subject do
136
+ described_class.valid_length?(bank_code: bank_code,
137
+ account_number: account_number)
138
+ end
139
+
140
+ context 'without a bank code' do
141
+ let(:account_number) { '12810105723' }
142
+ let(:bank_code) { nil }
143
+ it { is_expected.to eq(nil) }
144
+ end
145
+
146
+ context 'with an impossible bank code' do
147
+ let(:account_number) { '12810105723' }
148
+ let(:bank_code) { '500' }
149
+ it { is_expected.to eq(nil) }
150
+ end
151
+
152
+ context 'with a normal type-1 account number' do
153
+ let(:account_number) { '00000054391024039' }
154
+ let(:bank_code) { '500' }
155
+ it { is_expected.to eq(true) }
156
+
157
+ context 'that has a 6 digit serial number' do
158
+ let(:account_number) { '00000005439102403' }
159
+ let(:bank_code) { '500' }
160
+ it { is_expected.to eq(false) }
161
+ end
162
+
163
+ context 'that has an 8 digit serial number' do
164
+ let(:account_number) { '00000543910240391' }
165
+ let(:bank_code) { '500' }
166
+ it { is_expected.to eq(false) }
167
+ end
168
+ end
169
+
170
+ context 'without a Danske bank account' do
171
+ let(:account_number) { '12810105723' }
172
+ let(:bank_code) { '120' }
173
+ it { is_expected.to eq(true) }
174
+
175
+ context 'that has an 8 digit serial number' do
176
+ let(:account_number) { '00000128101057231' }
177
+ let(:bank_code) { '120' }
178
+ it { is_expected.to eq(false) }
179
+ end
180
+
181
+ context 'that has a 6 digit serial number' do
182
+ let(:account_number) { '00000001281010572' }
183
+ let(:bank_code) { '120' }
184
+ # This passes because it could be a 10 digit account number from the
185
+ # clearing code range 9180-9189.
186
+ it { is_expected.to eq(true) }
187
+ end
188
+ end
189
+
190
+ context 'with a Handelsbanken account number' do
191
+ let(:bank_code) { '600' }
192
+ let(:account_number) { '00000000219161038' }
193
+ it { is_expected.to eq(true) }
194
+
195
+ context 'that is only 8 characters long' do
196
+ let(:account_number) { '00000000021916103' }
197
+ it { is_expected.to eq(true) }
198
+ end
199
+
200
+ context 'that is 10 characters long' do
201
+ let(:account_number) { '00000002191610381' }
202
+ it { is_expected.to eq(false) }
203
+ end
204
+ end
205
+
206
+ context 'without a Nordea PlusGirot account number' do
207
+ let(:bank_code) { '950' }
208
+ let(:account_number) { '00099603401258276' }
209
+ it { is_expected.to eq(true) }
210
+ end
211
+ end
212
+
213
+ describe '.valid_bank_code?' do
214
+ subject do
215
+ described_class.valid_bank_code?(bank_code: bank_code,
216
+ account_number: account_number)
217
+ end
218
+
219
+ context 'without a bank code' do
220
+ let(:account_number) { '12810105723' }
221
+ let(:bank_code) { nil }
222
+ it { is_expected.to eq(false) }
223
+ end
224
+
225
+ context 'with an impossible bank code' do
226
+ let(:account_number) { '12810105723' }
227
+ let(:bank_code) { '500' }
228
+ it { is_expected.to eq(false) }
229
+ end
230
+
231
+ context 'with a possible bank code' do
232
+ let(:account_number) { '12810105723' }
233
+ let(:bank_code) { '120' }
234
+ it { is_expected.to eq(true) }
235
+ end
236
+ end
237
+ end
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.5.0
4
+ version: 0.6.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-07-12 00:00:00.000000000 Z
11
+ date: 2015-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -126,6 +126,7 @@ files:
126
126
  - data/raw/IBANSTRUCTURE.xml
127
127
  - data/raw/IBAN_Registry.txt
128
128
  - data/raw/structure_additions.yml
129
+ - data/raw/swedish_bank_lookup.yml
129
130
  - data/structures.yml
130
131
  - ibandit.gemspec
131
132
  - lib/ibandit.rb
@@ -136,6 +137,7 @@ files:
136
137
  - lib/ibandit/iban_assembler.rb
137
138
  - lib/ibandit/iban_splitter.rb
138
139
  - lib/ibandit/local_details_cleaner.rb
140
+ - lib/ibandit/swedish_details_converter.rb
139
141
  - lib/ibandit/version.rb
140
142
  - spec/fixtures/germany_integration_test_cases.json
141
143
  - spec/fixtures/germany_unit_test_cases.json
@@ -145,6 +147,7 @@ files:
145
147
  - spec/ibandit/iban_spec.rb
146
148
  - spec/ibandit/iban_splitter_spec.rb
147
149
  - spec/ibandit/local_details_cleaner_spec.rb
150
+ - spec/ibandit/swedish_details_converter_spec.rb
148
151
  - spec/spec_helper.rb
149
152
  homepage: https://github.com/gocardless/ibandit
150
153
  licenses: