banktools-se 0.0.1
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.
- 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
|