banktools-se 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Guardfile +6 -0
- data/README.markdown +108 -0
- data/Rakefile +6 -0
- data/banktools-se.gemspec +23 -0
- data/lib/banktools-se/account.rb +161 -0
- data/lib/banktools-se/bankgiro.rb +48 -0
- data/lib/banktools-se/plusgiro.rb +53 -0
- data/lib/banktools-se/utils.rb +19 -0
- data/lib/banktools-se/version.rb +5 -0
- data/lib/banktools-se.rb +5 -0
- data/spec/account_spec.rb +176 -0
- data/spec/bankgiro_spec.rb +95 -0
- data/spec/plusgiro_spec.rb +100 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/utils_spec.rb +36 -0
- metadata +129 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# Swedish bank tools
|
2
|
+
|
3
|
+
Ruby gem to validate, normalize/prettify and to some extent interpret
|
4
|
+
|
5
|
+
* Swedish bank account numbers
|
6
|
+
* Swedish plusgiro numbers
|
7
|
+
* Swedish bankgiro numbers
|
8
|
+
|
9
|
+
Inspired by [iulianu/iban-tools](https://github.com/iulianu/iban-tools). Please consider contributing gems for your country.
|
10
|
+
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
With Bundler for e.g. Ruby on Rails, add this to your `Gemfile`:
|
15
|
+
|
16
|
+
gem 'banktools-se', :git => 'git://github.com/barsoom/banktools-se.git'
|
17
|
+
|
18
|
+
and run
|
19
|
+
|
20
|
+
bundle
|
21
|
+
|
22
|
+
to install it.
|
23
|
+
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
# Bankgiro
|
28
|
+
|
29
|
+
valid_account = BankTools::SE::Bankgiro.new(" 5402968 1 ")
|
30
|
+
valid_account.valid? # => true
|
31
|
+
valid_account.errors # => []
|
32
|
+
valid_account.normalize # => "5402-9681"
|
33
|
+
|
34
|
+
bad_account = BankTools::SE::Bankgiro.new(" 1X ")
|
35
|
+
bad_account.valid? # => false
|
36
|
+
bad_account.errors # => [ :too_short, :invalid_characters, :bad_checksum ]
|
37
|
+
bad_account.normalize # => " 1 "
|
38
|
+
|
39
|
+
# 90-konto
|
40
|
+
fundraising_account = BankTools::SE::Bankgiro.new("902-0033")
|
41
|
+
fundraising_account.fundraising? # => true
|
42
|
+
|
43
|
+
|
44
|
+
# Plusgiro
|
45
|
+
|
46
|
+
valid_account = BankTools::SE::Plusgiro.new("2865434")
|
47
|
+
valid_account.valid? # => true
|
48
|
+
valid_account.errors # => []
|
49
|
+
valid_account.normalize # => "28 65 53-4"
|
50
|
+
|
51
|
+
bad_account = BankTools::SE::Plusgiro.new(" 1X ")
|
52
|
+
bad_account.valid? # => false
|
53
|
+
bad_account.errors # => [ :too_short, :invalid_characters, :bad_checksum ]
|
54
|
+
bad_account.normalize # => " 1 "
|
55
|
+
|
56
|
+
# 90-konto
|
57
|
+
fundraising_account = BankTools::SE::Plusgiro.new("90 20 03-3")
|
58
|
+
fundraising_account.fundraising? # => true
|
59
|
+
|
60
|
+
|
61
|
+
# Bank account
|
62
|
+
|
63
|
+
valid_account = BankTools::SE::Account.new("1100-0000000")
|
64
|
+
valid_account.valid? # => true
|
65
|
+
valid_account.errors # => []
|
66
|
+
valid_account.bank # => "Nordea"
|
67
|
+
valid_account.normalize # => "11000000007"
|
68
|
+
|
69
|
+
bad_account = BankTools::SE::Account.new(" 0000-0000000X ")
|
70
|
+
bad_account.valid? # => false
|
71
|
+
bad_account.errors # => [ :invalid_characters, :unknown_clearing_number ]
|
72
|
+
bad_account.bank # => nil
|
73
|
+
bad_account.normalize # => " 0000-0000000X "
|
74
|
+
|
75
|
+
|
76
|
+
## TODO
|
77
|
+
|
78
|
+
Possible improvements to make:
|
79
|
+
|
80
|
+
* Handle [Swedbank zerofill](http://www.danskebank.se/sv-se/eBanking-content/text-pages/Pages/Bankliste2.aspx).
|
81
|
+
* Handle [Sparbanken zerofill](http://www.danskebank.se/sv-se/eBanking-content/text-pages/Pages/Bankliste2.aspx).
|
82
|
+
* Look into just what bank account numbers need Luhn validation of which part.
|
83
|
+
|
84
|
+
|
85
|
+
## Credits and license
|
86
|
+
|
87
|
+
By [Henrik Nyh](http://henrik.nyh.se/) for [Barsoom](http://barsoom.se) under the MIT license:
|
88
|
+
|
89
|
+
> Copyright (c) 2011 Barsoom AB
|
90
|
+
>
|
91
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
92
|
+
> of this software and associated documentation files (the "Software"), to deal
|
93
|
+
> in the Software without restriction, including without limitation the rights
|
94
|
+
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
95
|
+
> copies of the Software, and to permit persons to whom the Software is
|
96
|
+
> furnished to do so, subject to the following conditions:
|
97
|
+
>
|
98
|
+
> The above copyright notice and this permission notice shall be included in
|
99
|
+
> all copies or substantial portions of the Software.
|
100
|
+
>
|
101
|
+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
102
|
+
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
103
|
+
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
104
|
+
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
105
|
+
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
106
|
+
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
107
|
+
> THE SOFTWARE.
|
108
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "banktools-se/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "banktools-se"
|
7
|
+
s.version = BankTools::SE::VERSION
|
8
|
+
s.authors = ["Henrik Nyh"]
|
9
|
+
s.email = ["henrik@barsoom.se"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Validate and normalize Swedish bank account numbers, plusgiro and bankgiro.}
|
12
|
+
|
13
|
+
s.rubyforge_project = "banktools-se"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_development_dependency "rspec"
|
21
|
+
s.add_development_dependency "guard"
|
22
|
+
s.add_development_dependency "guard-rspec"
|
23
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module BankTools
|
4
|
+
module SE
|
5
|
+
class Account
|
6
|
+
|
7
|
+
# http://sv.wikipedia.org/wiki/Lista_%C3%B6ver_clearingnummer_till_svenska_banker
|
8
|
+
# Max lengths from
|
9
|
+
# http://www.danskebank.se/sv-se/eBanking-content/text-pages/Pages/Bankliste2.aspx
|
10
|
+
# Min lengths are educated guesses based on the above and
|
11
|
+
# http://sv.wikipedia.org/wiki/Bankkonto
|
12
|
+
# When it's uncertain, let's error on the side of allowing too much.
|
13
|
+
# 1..99 means we have no idea.
|
14
|
+
|
15
|
+
DEFAULT_SERIAL_NUMBER_LENGTH = 7
|
16
|
+
|
17
|
+
CLEARING_NUMBER_MAP = {
|
18
|
+
1100..1199 => { :name => "Nordea" },
|
19
|
+
1200..1399 => { :name => "Danske Bank" },
|
20
|
+
1400..2099 => { :name => "Nordea" },
|
21
|
+
2300..2309 => { :name => "JP Nordiska", :serial_number_length => 1..99 },
|
22
|
+
2310..2310 => { :name => "Ålandsbanken" },
|
23
|
+
2311..2399 => { :name => "JP Nordiska", :serial_number_length => 1..99 },
|
24
|
+
2950..2950 => { :name => "Sambox", :serial_number_length => 1..99 },
|
25
|
+
3000..3299 => { :name => "Nordea" },
|
26
|
+
3300..3300 => { :name => "Nordea", :serial_number_length => 10, :luhn_for_serial => true }, # Personkonto.
|
27
|
+
3301..3399 => { :name => "Nordea" },
|
28
|
+
3400..3409 => { :name => "Länsförsäkringar Bank" },
|
29
|
+
3410..3781 => { :name => "Nordea" },
|
30
|
+
3782..3782 => { :name => "Nordea", :serial_number_length => 10, :luhn_for_serial => true }, # Personkonto.
|
31
|
+
3783..4999 => { :name => "Nordea" },
|
32
|
+
5000..5999 => { :name => "SEB" },
|
33
|
+
6000..6999 => { :name => "Handelsbanken", :serial_number_length => 9 },
|
34
|
+
7000..7120 => { :name => "Swedbank" },
|
35
|
+
7121..7122 => { :name => "Sparbanken i Enköping", :serial_number_length => 7..10 }, # 7? 10? Who knows.
|
36
|
+
7123..7999 => { :name => "Swedbank" },
|
37
|
+
8000..8999 => { :name => "Swedbank och fristående Sparbanker", :serial_number_length => 10, :checksum_for_clearing => true },
|
38
|
+
9020..9029 => { :name => "Länsförsäkringar Bank" },
|
39
|
+
9040..9049 => { :name => "Citibank" },
|
40
|
+
9050..9059 => { :name => "HSB Bank", :serial_number_length => 1..99 },
|
41
|
+
9060..9069 => { :name => "Länsförsäkringar Bank" },
|
42
|
+
9080..9080 => { :name => "Calyon Bank", :serial_number_length => 1..99 },
|
43
|
+
9090..9099 => { :name => "ABN AMRO", :serial_number_length => 1..99 },
|
44
|
+
9100..9100 => { :name => "Nordnet Bank" },
|
45
|
+
9120..9124 => { :name => "SEB" },
|
46
|
+
9130..9149 => { :name => "SEB" },
|
47
|
+
9150..9169 => { :name => "Skandiabanken" },
|
48
|
+
9170..9179 => { :name => "Ikano Bank" },
|
49
|
+
9180..9189 => { :name => "Danske Bank" },
|
50
|
+
9190..9199 => { :name => "Den Norske Bank" },
|
51
|
+
9200..9209 => { :name => "Stadshypotek Bank", :serial_number_length => 1..99 },
|
52
|
+
9230..9230 => { :name => "Bank2" },
|
53
|
+
9231..9239 => { :name => "SalusAnsvar Bank", :serial_number_length => 1..99 },
|
54
|
+
9260..9269 => { :name => "Gjensidige NOR Sparebank", :serial_number_length => 1..99 },
|
55
|
+
9270..9279 => { :name => "ICA Banken" },
|
56
|
+
9280..9289 => { :name => "Resurs Bank" },
|
57
|
+
9290..9299 => { :name => "Coop Bank", :serial_number_length => 1..99 },
|
58
|
+
9300..9349 => { :name => "Sparbanken Öresund", :serial_number_length => 10 },
|
59
|
+
9400..9400 => { :name => "Forex Bank" },
|
60
|
+
9460..9460 => { :name => "GE Money Bank" },
|
61
|
+
9469..9469 => { :name => "GE Money Bank" },
|
62
|
+
9500..9547 => { :name => "Plusgirot Bank", :serial_number_length => 10 },
|
63
|
+
9548..9548 => { :name => "Ekobanken", :serial_number_length => 1..99 },
|
64
|
+
9549..9549 => { :name => "JAK Medlemsbank", :serial_number_length => 1..99 },
|
65
|
+
9550..9550 => { :name => "Avanza Bank" },
|
66
|
+
9960..9969 => { :name => "Plusgirot Bank", :serial_number_length => 10 },
|
67
|
+
}
|
68
|
+
|
69
|
+
attr_reader :number
|
70
|
+
|
71
|
+
def initialize(number)
|
72
|
+
@number = number
|
73
|
+
end
|
74
|
+
|
75
|
+
def valid?
|
76
|
+
errors.empty?
|
77
|
+
end
|
78
|
+
|
79
|
+
def errors
|
80
|
+
errors = []
|
81
|
+
|
82
|
+
errors << :too_short if serial_number.length < min_length
|
83
|
+
errors << :too_long if serial_number.length > max_length
|
84
|
+
errors << :invalid_characters if number.to_s.match(/[^0-9 -]/)
|
85
|
+
|
86
|
+
if luhn_for_serial?
|
87
|
+
errors << :bad_checksum unless BankTools::SE::Utils.valid_luhn?(serial_number)
|
88
|
+
end
|
89
|
+
|
90
|
+
errors << :unknown_clearing_number unless bank
|
91
|
+
|
92
|
+
errors
|
93
|
+
end
|
94
|
+
|
95
|
+
def normalize
|
96
|
+
if valid?
|
97
|
+
[ clearing_number, serial_number ].join("-")
|
98
|
+
else
|
99
|
+
number
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def bank
|
104
|
+
bank_data[:name]
|
105
|
+
end
|
106
|
+
|
107
|
+
def clearing_number
|
108
|
+
digits[0,4]
|
109
|
+
end
|
110
|
+
|
111
|
+
def serial_number
|
112
|
+
value = digits[4..-1] || ""
|
113
|
+
if checksum_for_clearing? && value.length == max_length
|
114
|
+
value[1..-1]
|
115
|
+
else
|
116
|
+
value
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def bank_data
|
123
|
+
number = clearing_number.to_i
|
124
|
+
_, found_data = CLEARING_NUMBER_MAP.find do |interval, data|
|
125
|
+
interval.include?(number)
|
126
|
+
end
|
127
|
+
found_data || {}
|
128
|
+
end
|
129
|
+
|
130
|
+
def min_length
|
131
|
+
if bank_data
|
132
|
+
Array(bank_data[:serial_number_length] || DEFAULT_SERIAL_NUMBER_LENGTH).first
|
133
|
+
else
|
134
|
+
0
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def max_length
|
139
|
+
if bank_data
|
140
|
+
Array(bank_data[:serial_number_length] || DEFAULT_SERIAL_NUMBER_LENGTH).last +
|
141
|
+
(checksum_for_clearing? ? 1 : 0)
|
142
|
+
else
|
143
|
+
1/0.0 # Infinity.
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def luhn_for_serial?
|
148
|
+
bank_data[:luhn_for_serial]
|
149
|
+
end
|
150
|
+
|
151
|
+
def checksum_for_clearing?
|
152
|
+
bank_data[:checksum_for_clearing]
|
153
|
+
end
|
154
|
+
|
155
|
+
def digits
|
156
|
+
number.to_s.gsub(/\D/, '')
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module BankTools
|
2
|
+
module SE
|
3
|
+
class Bankgiro
|
4
|
+
|
5
|
+
# http://sv.wikipedia.org/wiki/Bankgirot#Bankgironummer
|
6
|
+
|
7
|
+
attr_reader :number
|
8
|
+
|
9
|
+
def initialize(number)
|
10
|
+
@number = number
|
11
|
+
end
|
12
|
+
|
13
|
+
def valid?
|
14
|
+
errors.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def errors
|
18
|
+
errors = []
|
19
|
+
|
20
|
+
errors << :too_short if digits.length < 7
|
21
|
+
errors << :too_long if digits.length > 8
|
22
|
+
errors << :invalid_characters if number.to_s.match(/[^0-9 -]/)
|
23
|
+
errors << :bad_checksum unless BankTools::SE::Utils.valid_luhn?(number)
|
24
|
+
|
25
|
+
errors
|
26
|
+
end
|
27
|
+
|
28
|
+
def normalize
|
29
|
+
if valid?
|
30
|
+
digits.split(/(\d{4})$/).join("-")
|
31
|
+
else
|
32
|
+
number
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def fundraising?
|
37
|
+
valid? && digits.match(/^90[0-4]/)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def digits
|
43
|
+
number.to_s.gsub(/\D/, '')
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module BankTools
|
2
|
+
module SE
|
3
|
+
class Plusgiro
|
4
|
+
|
5
|
+
# Could sadly not find anything more authoritative than
|
6
|
+
# http://pellesoft.se/communicate/forum/view.aspx?msgid=267449&forumid=63&sum=0
|
7
|
+
|
8
|
+
attr_reader :number
|
9
|
+
|
10
|
+
def initialize(number)
|
11
|
+
@number = number
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
errors.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def errors
|
19
|
+
errors = []
|
20
|
+
|
21
|
+
errors << :too_short if digits.length < 2
|
22
|
+
errors << :too_long if digits.length > 8
|
23
|
+
errors << :invalid_characters if number.to_s.match(/[^0-9 -]/)
|
24
|
+
errors << :bad_checksum unless BankTools::SE::Utils.valid_luhn?(number)
|
25
|
+
|
26
|
+
errors
|
27
|
+
end
|
28
|
+
|
29
|
+
def normalize
|
30
|
+
if valid?
|
31
|
+
pre, pairs, post = digits.split(/(\d{2}*)(\d)$/)
|
32
|
+
pairs = pairs.split(/(\d\d)/).reject { |x| x.empty? }
|
33
|
+
[ pre, pairs.join(" "), "-", post ].join
|
34
|
+
else
|
35
|
+
number
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# http://www.plusgirot.se/Om+PlusGirot/90-konton/508552.html
|
40
|
+
# http://www.insamlingskontroll.se/
|
41
|
+
def fundraising?
|
42
|
+
valid? && digits.match(/^90\d{5}$/)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def digits
|
48
|
+
number.to_s.gsub(/\D/, '')
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module BankTools
|
2
|
+
module SE
|
3
|
+
module Utils
|
4
|
+
|
5
|
+
# Based on http://blog.internautdesign.com/2007/4/18/ruby-luhn-check-aka-mod-10-formula
|
6
|
+
require "enumerator"
|
7
|
+
def self.valid_luhn?(number)
|
8
|
+
digits = number.to_s.scan(/\d/).reverse.map { |x| x.to_i }
|
9
|
+
digits = digits.enum_with_index.map { |d, i|
|
10
|
+
d *= 2 if i.odd?
|
11
|
+
d > 9 ? d - 9 : d
|
12
|
+
}
|
13
|
+
sum = digits.inject(0) { |m, x| m + x }
|
14
|
+
sum % 10 == 0
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/banktools-se.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
require "banktools-se"
|
5
|
+
|
6
|
+
describe BankTools::SE::Account do
|
7
|
+
|
8
|
+
it "should initialize" do
|
9
|
+
BankTools::SE::Account.new("foo").should be_a(BankTools::SE::Account)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#valid?" do
|
13
|
+
|
14
|
+
it "should be true with no errors" do
|
15
|
+
account = BankTools::SE::Account.new("foo")
|
16
|
+
account.stub!(:errors).and_return([])
|
17
|
+
account.should be_valid
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should be false with errors" do
|
21
|
+
account = BankTools::SE::Account.new("foo")
|
22
|
+
account.stub!(:errors).and_return([:error])
|
23
|
+
account.should_not be_valid
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#errors" do
|
29
|
+
[
|
30
|
+
"1100-0000000", # Nordea.
|
31
|
+
"1155-0000000", # Nordea.
|
32
|
+
"1199-0000000", # Nordea.
|
33
|
+
"1200-0000000", # Danske Bank.
|
34
|
+
"1400-0000000", # Nordea.
|
35
|
+
"2300-00", # JP Nordiska.
|
36
|
+
"2310-0000000", # Ålandsbanken.
|
37
|
+
"2311-00", # JP Nordiska.
|
38
|
+
"2950-00", # Sambox.
|
39
|
+
"3000-0000000", # Nordea.
|
40
|
+
"3300-800928-6249", # Nordea personkonto.
|
41
|
+
"3301-0000000", # Nordea.
|
42
|
+
"3400-0000000", # Länsförsäkringar Bank.
|
43
|
+
"3410-0000000", # Nordea.
|
44
|
+
"3782-800928-6249", # Nordea personkonto.
|
45
|
+
"3783-0000000", # Nordea.
|
46
|
+
"5000-0000000", # SEB.
|
47
|
+
"6000-000000000", # Handelsbanken.
|
48
|
+
"7000-0000000", # Swedbank.
|
49
|
+
"7121-0000000", # Sparbanken i Enköping.
|
50
|
+
"7123-0000000", # Swedbank.
|
51
|
+
"8000-0000000000", # Swedbank/Sparbanker.
|
52
|
+
"8000-2-0000000000", # Swedbank/Sparbanker with clearing number checksum.
|
53
|
+
"9020-0000000", # Länsförsäkringar Bank.
|
54
|
+
"9040-0000000", # Citibank.
|
55
|
+
"9050-00", # HSB Bank.
|
56
|
+
"9060-0000000", # Länsförsäkringar Bank.
|
57
|
+
"9080-00", # Calyon Bank.
|
58
|
+
"9090-00", # ABN AMBRO.
|
59
|
+
"9100-0000000", # Nordnet Bank.
|
60
|
+
"9120-0000000", # SEB.
|
61
|
+
"9130-0000000", # SEB.
|
62
|
+
"9150-0000000", # Skandiabanken.
|
63
|
+
"9170-0000000", # Ikano Bank.
|
64
|
+
"9180-0000000", # Danske Bank.
|
65
|
+
"9190-0000000", # Den Norske Bank.
|
66
|
+
"9200-00", # Stadshypotek Bank.
|
67
|
+
"9230-0000000", # Bank2.
|
68
|
+
"9231-00", # SalusAnsvar Bank.
|
69
|
+
"9260-00", # Gjensidige NOR Sparebank.
|
70
|
+
"9270-0000000", # ICA Banken.
|
71
|
+
"9280-0000000", # Resurs Bank.
|
72
|
+
"9290-00", # Coop Bank.
|
73
|
+
"9300-0000000000", # Sparbanken Öresund.
|
74
|
+
"9400-0000000", # Forex Bank.
|
75
|
+
"9460-0000000", # GE Money Bank.
|
76
|
+
"9469-0000000", # GE Money Bank.
|
77
|
+
"9500-0000000000", # Plusgirot Bank.
|
78
|
+
"9548-00", # Ekobanken.
|
79
|
+
"9549-00", # JAK Medlemsbank.
|
80
|
+
"9550-0000000", # Avanza Bank.
|
81
|
+
"9960-0000000000", # Plusgirot Bank.
|
82
|
+
|
83
|
+
].each do |number|
|
84
|
+
it "should be empty for a valid number like #{number}" do
|
85
|
+
BankTools::SE::Account.new(number).errors.should == []
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should include :too_short for numbers shorter than the bank allows" do
|
90
|
+
BankTools::SE::Account.new("11007").errors.should include(:too_short)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should include :too_long for numbers longer than the bank allows" do
|
94
|
+
BankTools::SE::Account.new("1100000000007").errors.should include(:too_long)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should not include :too_long for Swedbank/Sparbanker numbers with clearing checksum" do
|
98
|
+
BankTools::SE::Account.new("8000-2-0000000000").errors.should_not include(:too_long)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should include :invalid_characters for numbers with other character than digits, spaces and dashes" do
|
102
|
+
BankTools::SE::Account.new("1 2-3X").errors.should include(:invalid_characters)
|
103
|
+
BankTools::SE::Account.new("1 2-3").errors.should_not include(:invalid_characters)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should include :bad_checksum for Nordea personkonto if the serial Luhn/mod 10 checksum is incorrect" do
|
107
|
+
BankTools::SE::Utils.valid_luhn?("800928-6249").should be_true
|
108
|
+
BankTools::SE::Utils.valid_luhn?("3300-800928-6249").should be_false
|
109
|
+
BankTools::SE::Account.new("3300-800928-6249").errors.should_not include(:bad_checksum)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should include :unknown_clearing_number if the clearing number is unknown" do
|
113
|
+
BankTools::SE::Account.new("10000000009").errors.should include(:unknown_clearing_number)
|
114
|
+
BankTools::SE::Account.new("11000000007").errors.should_not include(:unknown_clearing_number)
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#bank" do
|
120
|
+
|
121
|
+
it "should return the bank for the current clearing number" do
|
122
|
+
BankTools::SE::Account.new("11000000007").bank.should == "Nordea"
|
123
|
+
BankTools::SE::Account.new("11550000001").bank.should == "Nordea"
|
124
|
+
BankTools::SE::Account.new("11990000009").bank.should == "Nordea"
|
125
|
+
BankTools::SE::Account.new("12000000005").bank.should == "Danske Bank"
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should return nil for unknown clearing numbers" do
|
129
|
+
BankTools::SE::Account.new("10000000009").bank.should be_nil
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "#clearing_number" do
|
135
|
+
|
136
|
+
it "should be the first four digits" do
|
137
|
+
BankTools::SE::Account.new("12345678").clearing_number.should == "1234"
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "#serial_number" do
|
143
|
+
|
144
|
+
it "should be the digits after the first four digits" do
|
145
|
+
BankTools::SE::Account.new("12345678").serial_number.should == "5678"
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should be the empty string if there aren't enough numbers" do
|
149
|
+
BankTools::SE::Account.new("12").serial_number.should == ""
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should exclude any Swedbank/Sparbanker clearing checksum" do
|
153
|
+
BankTools::SE::Account.new("8000-2-0000000000").serial_number.should == "0000000000"
|
154
|
+
BankTools::SE::Account.new("8000-0000000000").serial_number.should == "0000000000"
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "#normalize" do
|
160
|
+
|
161
|
+
it "should normalize to clearing number dash serial number" do
|
162
|
+
account = BankTools::SE::Account.new("11000000007").normalize.should == "1100-0000007"
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should remove any Swedbank/Sparbanker clearing checksum" do
|
166
|
+
BankTools::SE::Account.new("8000-2-0000000000").normalize.should == "8000-0000000000"
|
167
|
+
BankTools::SE::Account.new("8000-0000000000").normalize.should == "8000-0000000000"
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should not attempt to normalize invalid numbers" do
|
171
|
+
account = BankTools::SE::Account.new(" 1-2-3 ").normalize.should == " 1-2-3 "
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "banktools-se"
|
3
|
+
|
4
|
+
describe BankTools::SE::Bankgiro do
|
5
|
+
|
6
|
+
it "should initialize" do
|
7
|
+
BankTools::SE::Bankgiro.new("foo").should be_a(BankTools::SE::Bankgiro)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#valid?" do
|
11
|
+
|
12
|
+
it "should be true with no errors" do
|
13
|
+
account = BankTools::SE::Bankgiro.new("foo")
|
14
|
+
account.stub!(:errors).and_return([])
|
15
|
+
account.should be_valid
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be false with errors" do
|
19
|
+
account = BankTools::SE::Bankgiro.new("foo")
|
20
|
+
account.stub!(:errors).and_return([:error])
|
21
|
+
account.should_not be_valid
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#errors" do
|
27
|
+
# From http://www.carnegie.se/sv/Carnegie-fonder/Kopa-fonder/Bankgironummer/
|
28
|
+
[
|
29
|
+
"5402-9681",
|
30
|
+
"297-3675",
|
31
|
+
"640-5070",
|
32
|
+
].each do |number|
|
33
|
+
it "should be empty for a valid number like #{number}" do
|
34
|
+
BankTools::SE::Bankgiro.new(number).errors.should be_empty
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should include :too_short for numbers shorter than 7 digits" do
|
39
|
+
BankTools::SE::Bankgiro.new(nil).errors.should include(:too_short)
|
40
|
+
BankTools::SE::Bankgiro.new("").errors.should include(:too_short)
|
41
|
+
BankTools::SE::Bankgiro.new("54-0296").errors.should include(:too_short)
|
42
|
+
BankTools::SE::Bankgiro.new("54---------0296").errors.should include(:too_short)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should include :too_long for numbers longer than 8 digits" do
|
46
|
+
BankTools::SE::Bankgiro.new("5402-96810").errors.should include(:too_long)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should include :invalid_characters for numbers with other character than digits, spaces and dashes" do
|
50
|
+
BankTools::SE::Bankgiro.new("5402-9681X").errors.should include(:invalid_characters)
|
51
|
+
BankTools::SE::Bankgiro.new(" 5 4 0 2 - 9 6 8 1 ").errors.should_not include(:invalid_characters)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should include :bad_checksum if the Luhn/mod 10 checksum is incorrect" do
|
55
|
+
BankTools::SE::Bankgiro.new("5402-9682").errors.should include(:bad_checksum)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#normalize" do
|
61
|
+
|
62
|
+
it "should normalize 7-digit numbers to NNN-NNNN" do
|
63
|
+
account = BankTools::SE::Bankgiro.new(" 6-40 - 5070")
|
64
|
+
account.normalize.should == "640-5070"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should normalize 8-digit numbers to NNNN-NNNN" do
|
68
|
+
account = BankTools::SE::Bankgiro.new(" 5-4-0-2-9-6- 81- ")
|
69
|
+
account.normalize.should == "5402-9681"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should not attempt to normalize invalid numbers" do
|
73
|
+
account = BankTools::SE::Bankgiro.new(" 1-2-3 ")
|
74
|
+
account.normalize.should == " 1-2-3 "
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#fundraising? (90-konto)" do
|
80
|
+
|
81
|
+
it "should be true for the number series 900-nnnn to 904-nnnn" do
|
82
|
+
BankTools::SE::Bankgiro.new("902-0033").should be_fundraising
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should be false for invalid numbers in the right series" do
|
86
|
+
BankTools::SE::Bankgiro.new("902-0034").should_not be_fundraising
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should be false for numbers outside the right series" do
|
90
|
+
BankTools::SE::Bankgiro.new("5402-9681").should_not be_fundraising
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "banktools-se"
|
3
|
+
|
4
|
+
describe BankTools::SE::Plusgiro do
|
5
|
+
|
6
|
+
it "should initialize" do
|
7
|
+
BankTools::SE::Plusgiro.new("foo").should be_a(BankTools::SE::Plusgiro)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#valid?" do
|
11
|
+
|
12
|
+
it "should be true with no errors" do
|
13
|
+
account = BankTools::SE::Plusgiro.new("foo")
|
14
|
+
account.stub!(:errors).and_return([])
|
15
|
+
account.should be_valid
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be false with errors" do
|
19
|
+
account = BankTools::SE::Plusgiro.new("foo")
|
20
|
+
account.stub!(:errors).and_return([:error])
|
21
|
+
account.should_not be_valid
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#errors" do
|
27
|
+
[
|
28
|
+
"28 65 43-4", # IKEA
|
29
|
+
"410 54 68-5", # IKEA
|
30
|
+
"4-2", # Sveriges riksbank
|
31
|
+
].each do |number|
|
32
|
+
it "should be empty for a valid number like #{number}" do
|
33
|
+
BankTools::SE::Plusgiro.new(number).errors.should be_empty
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should include :too_short for numbers shorter than 2 digits" do
|
38
|
+
BankTools::SE::Plusgiro.new(nil).errors.should include(:too_short)
|
39
|
+
BankTools::SE::Plusgiro.new("").errors.should include(:too_short)
|
40
|
+
BankTools::SE::Plusgiro.new("1").errors.should include(:too_short)
|
41
|
+
BankTools::SE::Plusgiro.new("1---------").errors.should include(:too_short)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should include :too_long for numbers longer than 8 digits" do
|
45
|
+
BankTools::SE::Plusgiro.new("410 54 68-51").errors.should include(:too_long)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should include :invalid_characters for numbers with other character than digits, spaces and dashes" do
|
49
|
+
BankTools::SE::Plusgiro.new("410 54 68-5X").errors.should include(:invalid_characters)
|
50
|
+
BankTools::SE::Plusgiro.new("4 1 0 5 4 6 8 - 5 ").errors.should_not include(:invalid_characters)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should include :bad_checksum if the Luhn/mod 10 checksum is incorrect" do
|
54
|
+
BankTools::SE::Plusgiro.new("410 54 68-6").errors.should include(:bad_checksum)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#normalize" do
|
60
|
+
|
61
|
+
it "should normalize short numbers to the format N-N" do
|
62
|
+
account = BankTools::SE::Plusgiro.new(" 4 - 2")
|
63
|
+
account.normalize.should == "4-2"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should normalize odd-length numbers to the format NN NN NN-N" do
|
67
|
+
account = BankTools::SE::Plusgiro.new("2865434")
|
68
|
+
account.normalize.should == "28 65 43-4"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should normalize even-length numbers to the format NNN NN NN-N" do
|
72
|
+
account = BankTools::SE::Plusgiro.new("41054685")
|
73
|
+
account.normalize.should == "410 54 68-5"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should not attempt to normalize invalid numbers" do
|
77
|
+
account = BankTools::SE::Plusgiro.new(" 1-2-3 ")
|
78
|
+
account.normalize.should == " 1-2-3 "
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#fundraising? (90-konto)" do
|
84
|
+
|
85
|
+
it "should be true for the number series 90-nnnn" do
|
86
|
+
BankTools::SE::Plusgiro.new("90 20 03-3").should be_fundraising
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should be false for invalid numbers in the right series" do
|
90
|
+
BankTools::SE::Plusgiro.new("90 20 03-4").should_not be_fundraising
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should be false for numbers outside the right series" do
|
94
|
+
BankTools::SE::Plusgiro.new("4-2").should_not be_fundraising
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/utils_spec.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "banktools-se/utils"
|
3
|
+
|
4
|
+
describe BankTools::SE::Utils, "valid_luhn?" do
|
5
|
+
|
6
|
+
[
|
7
|
+
"00",
|
8
|
+
"18",
|
9
|
+
"26",
|
10
|
+
"34",
|
11
|
+
"42",
|
12
|
+
"59",
|
13
|
+
"67",
|
14
|
+
"75",
|
15
|
+
"83",
|
16
|
+
"91",
|
17
|
+
"109",
|
18
|
+
"117",
|
19
|
+
"5402-9681",
|
20
|
+
].each do |number|
|
21
|
+
it "should allow a valid number like #{number}" do
|
22
|
+
BankTools::SE::Utils.valid_luhn?(number).should be_true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
[
|
27
|
+
"01",
|
28
|
+
"118",
|
29
|
+
"5402-9682",
|
30
|
+
].each do |number|
|
31
|
+
it "should disallow an invalid number like #{number}" do
|
32
|
+
BankTools::SE::Utils.valid_luhn?(number).should be_false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: banktools-se
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Henrik Nyh
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-10-12 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: guard
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: guard-rspec
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
description:
|
64
|
+
email:
|
65
|
+
- henrik@barsoom.se
|
66
|
+
executables: []
|
67
|
+
|
68
|
+
extensions: []
|
69
|
+
|
70
|
+
extra_rdoc_files: []
|
71
|
+
|
72
|
+
files:
|
73
|
+
- .gitignore
|
74
|
+
- Gemfile
|
75
|
+
- Guardfile
|
76
|
+
- README.markdown
|
77
|
+
- Rakefile
|
78
|
+
- banktools-se.gemspec
|
79
|
+
- lib/banktools-se.rb
|
80
|
+
- lib/banktools-se/account.rb
|
81
|
+
- lib/banktools-se/bankgiro.rb
|
82
|
+
- lib/banktools-se/plusgiro.rb
|
83
|
+
- lib/banktools-se/utils.rb
|
84
|
+
- lib/banktools-se/version.rb
|
85
|
+
- spec/account_spec.rb
|
86
|
+
- spec/bankgiro_spec.rb
|
87
|
+
- spec/plusgiro_spec.rb
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
- spec/utils_spec.rb
|
90
|
+
has_rdoc: true
|
91
|
+
homepage: ""
|
92
|
+
licenses: []
|
93
|
+
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
hash: 3
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
requirements: []
|
118
|
+
|
119
|
+
rubyforge_project: banktools-se
|
120
|
+
rubygems_version: 1.5.3
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: Validate and normalize Swedish bank account numbers, plusgiro and bankgiro.
|
124
|
+
test_files:
|
125
|
+
- spec/account_spec.rb
|
126
|
+
- spec/bankgiro_spec.rb
|
127
|
+
- spec/plusgiro_spec.rb
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
- spec/utils_spec.rb
|