ibandit 0.5.0 → 0.6.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 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: