banktools-se 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in bank-tools-se.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard 'rspec', :version => 2, :cli => "--color" do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/banktools-se/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec" }
5
+ watch('spec/spec_helper.rb') { "spec" }
6
+ end
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,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -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
@@ -0,0 +1,5 @@
1
+ module BankTools
2
+ module SE
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ require "banktools-se/version"
2
+ require "banktools-se/utils"
3
+ require "banktools-se/bankgiro"
4
+ require "banktools-se/plusgiro"
5
+ require "banktools-se/account"
@@ -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
@@ -0,0 +1,5 @@
1
+ RSpec.configure do |config|
2
+ config.treat_symbols_as_metadata_keys_with_true_values = true
3
+ config.filter_run :focus => true
4
+ config.run_all_when_everything_filtered = true
5
+ end
@@ -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