banktools-se 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.markdown +23 -13
- data/lib/banktools-se/account.rb +20 -56
- data/lib/banktools-se/account/clearing_number.rb +53 -0
- data/lib/banktools-se/bankgiro.rb +2 -2
- data/lib/banktools-se/bankgiro/ocr.rb +14 -10
- data/lib/banktools-se/plusgiro.rb +2 -2
- data/lib/banktools-se/version.rb +1 -1
- data/spec/account_spec.rb +0 -3
- data/spec/bankgiro_spec.rb +8 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56417ca1fa0b99e2d5c754563686051cc73c0387
|
4
|
+
data.tar.gz: 7abf1933594e2ff146fe570a5b935e41ab996e14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 920c68e4e3cdfed665e6242256952f5cd770ed3e25faab56cd8cbb33b76ffec39d38d1fcfed12a0a0cda67dde11cafc0b6a91c51274bcbc163d4108f18b6c2bc
|
7
|
+
data.tar.gz: 3176a6146b0380d9db063b82e343dce699918ab2537fb7cd419d4bc3321fd07bd085a9d3847baf15abe7ad5068b4dbd9e00bfb5128d41978406fd41c203c7c7c
|
data/.travis.yml
CHANGED
data/README.markdown
CHANGED
@@ -8,24 +8,13 @@ Ruby gem to validate, normalize/prettify and to some extent interpret
|
|
8
8
|
* Swedish plusgiro numbers
|
9
9
|
* Swedish bankgiro numbers
|
10
10
|
|
11
|
+
It can also generate and unpack Bankgiro OCR numbers (reference codes) with a check digit, optional length digit and optional padding digits.
|
12
|
+
|
11
13
|
This gem does what it can to weed out invalid numbers but errs on the side of allowing too much, in the absence of good specifications, so be advised that a "valid" number might still be incorrect.
|
12
14
|
|
13
15
|
Inspired by [iulianu/iban-tools](https://github.com/iulianu/iban-tools). Please consider contributing gems for your country.
|
14
16
|
|
15
17
|
|
16
|
-
## Installation
|
17
|
-
|
18
|
-
With Bundler for e.g. Ruby on Rails, add this to your `Gemfile`:
|
19
|
-
|
20
|
-
gem 'banktools-se', :git => 'git://github.com/barsoom/banktools-se.git'
|
21
|
-
|
22
|
-
and run
|
23
|
-
|
24
|
-
bundle
|
25
|
-
|
26
|
-
to install it.
|
27
|
-
|
28
|
-
|
29
18
|
## Usage
|
30
19
|
|
31
20
|
# Bankgiro
|
@@ -95,6 +84,21 @@ to install it.
|
|
95
84
|
BankTools::SE::Errors::UNKNOWN_CLEARING_NUMBER # => :unknown_clearing_number
|
96
85
|
|
97
86
|
|
87
|
+
## Installation
|
88
|
+
|
89
|
+
Add this line to your application's Gemfile:
|
90
|
+
|
91
|
+
gem 'banktools-se'
|
92
|
+
|
93
|
+
And then execute:
|
94
|
+
|
95
|
+
$ bundle
|
96
|
+
|
97
|
+
Or install it yourself as:
|
98
|
+
|
99
|
+
$ gem install banktools-se
|
100
|
+
|
101
|
+
|
98
102
|
## TODO
|
99
103
|
|
100
104
|
Possible improvements to make:
|
@@ -102,6 +106,12 @@ Possible improvements to make:
|
|
102
106
|
* Luhn validation based on [BGC docs](http://www.bgc.se/upload/Gemensamt/Trycksaker/Manualer/BG910.pdf).
|
103
107
|
|
104
108
|
|
109
|
+
## Also see
|
110
|
+
|
111
|
+
* [BankTools::DE (German)](https://github.com/barsoom/banktools-de)
|
112
|
+
* [iban-tools](https://github.com/iulianu/iban-tools)
|
113
|
+
|
114
|
+
|
105
115
|
## Credits and license
|
106
116
|
|
107
117
|
By [Henrik Nyh](http://henrik.nyh.se/) for [Barsoom](http://barsoom.se) under the MIT license:
|
data/lib/banktools-se/account.rb
CHANGED
@@ -1,56 +1,14 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
# http://www.bgc.se/upload/Gemensamt/Trycksaker/Manualer/BG910.pdf
|
4
|
+
|
5
|
+
require "banktools-se/account/clearing_number"
|
6
|
+
|
3
7
|
module BankTools
|
4
8
|
module SE
|
5
9
|
class Account
|
6
|
-
|
7
|
-
# http://www.bgc.se/upload/Gemensamt/Trycksaker/Manualer/BG910.pdf
|
8
|
-
|
9
10
|
DEFAULT_SERIAL_NUMBER_LENGTH = 7
|
10
|
-
|
11
|
-
CLEARING_NUMBER_MAP = {
|
12
|
-
1100..1199 => { :name => "Nordea" },
|
13
|
-
1200..1399 => { :name => "Danske Bank" },
|
14
|
-
1400..2099 => { :name => "Nordea" },
|
15
|
-
2300..2399 => { :name => "Ålandsbanken" },
|
16
|
-
2400..2499 => { :name => "Danske Bank" },
|
17
|
-
3000..3299 => { :name => "Nordea" },
|
18
|
-
3300..3300 => { :name => "Nordea", :serial_number_length => 10, :luhn_for_serial => true }, # Personkonto.
|
19
|
-
3301..3399 => { :name => "Nordea" },
|
20
|
-
3400..3409 => { :name => "Länsförsäkringar Bank" },
|
21
|
-
3410..3781 => { :name => "Nordea" },
|
22
|
-
3782..3782 => { :name => "Nordea", :serial_number_length => 10, :luhn_for_serial => true }, # Personkonto.
|
23
|
-
3783..4999 => { :name => "Nordea" },
|
24
|
-
5000..5999 => { :name => "SEB" },
|
25
|
-
6000..6999 => { :name => "Handelsbanken", :serial_number_length => 9 },
|
26
|
-
7000..7999 => { :name => "Swedbank" },
|
27
|
-
# Can be fewer chars but must be zero-filled, so let's call it 10.
|
28
|
-
8000..8999 => { :name => "Swedbank", :serial_number_length => 10, :checksum_for_clearing => true, :zerofill => true },
|
29
|
-
9020..9029 => { :name => "Länsförsäkringar Bank" },
|
30
|
-
9040..9049 => { :name => "Citibank" },
|
31
|
-
9060..9069 => { :name => "Länsförsäkringar Bank" },
|
32
|
-
9090..9099 => { :name => "Royal Bank of Scotland" },
|
33
|
-
9100..9109 => { :name => "Nordnet Bank" },
|
34
|
-
9120..9124 => { :name => "SEB" },
|
35
|
-
9130..9149 => { :name => "SEB" },
|
36
|
-
9150..9169 => { :name => "Skandiabanken" },
|
37
|
-
9170..9179 => { :name => "Ikano Bank" },
|
38
|
-
9180..9189 => { :name => "Danske Bank", :serial_number_length => 10 },
|
39
|
-
9190..9199 => { :name => "Den Norske Bank" },
|
40
|
-
9230..9239 => { :name => "Marginalen Bank" },
|
41
|
-
9250..9259 => { :name => "SBAB" },
|
42
|
-
9260..9269 => { :name => "Den Norske Bank" },
|
43
|
-
9270..9279 => { :name => "ICA Banken" },
|
44
|
-
9280..9289 => { :name => "Resurs Bank" },
|
45
|
-
9300..9349 => { :name => "Sparbanken Öresund", :serial_number_length => 10, :zerofill => true },
|
46
|
-
9400..9449 => { :name => "Forex Bank" },
|
47
|
-
9460..9469 => { :name => "GE Money Bank" },
|
48
|
-
9470..9479 => { :name => "Fortis Bank" },
|
49
|
-
9500..9549 => { :name => "Nordea/Plusgirot", :serial_number_length => 1..10 },
|
50
|
-
9550..9569 => { :name => "Avanza Bank" },
|
51
|
-
9570..9579 => { :name => "Sparbanken Syd", :serial_number_length => 10, :zerofill => true},
|
52
|
-
9960..9969 => { :name => "Nordea/Plusgirot", :serial_number_length => 1..10 },
|
53
|
-
}
|
11
|
+
CLEARING_NUMBER_MAP = ClearingNumber::MAP
|
54
12
|
|
55
13
|
attr_reader :number
|
56
14
|
|
@@ -67,10 +25,10 @@ module BankTools
|
|
67
25
|
|
68
26
|
errors << Errors::TOO_SHORT if serial_number.length < min_length
|
69
27
|
errors << Errors::TOO_LONG if serial_number.length > max_length
|
70
|
-
errors << Errors::INVALID_CHARACTERS if number.to_s.match(/[
|
28
|
+
errors << Errors::INVALID_CHARACTERS if number.to_s.match(/[^\d -]/)
|
71
29
|
|
72
30
|
if luhn_for_serial?
|
73
|
-
errors << Errors::BAD_CHECKSUM unless
|
31
|
+
errors << Errors::BAD_CHECKSUM unless Utils.valid_luhn?(serial_number)
|
74
32
|
end
|
75
33
|
|
76
34
|
errors << Errors::UNKNOWN_CLEARING_NUMBER unless bank
|
@@ -99,7 +57,12 @@ module BankTools
|
|
99
57
|
|
100
58
|
def serial_number
|
101
59
|
number = digits.slice(clearing_number_length..-1) || ""
|
102
|
-
|
60
|
+
|
61
|
+
if zerofill?
|
62
|
+
number.rjust(serial_number_length, "0")
|
63
|
+
else
|
64
|
+
number
|
65
|
+
end
|
103
66
|
end
|
104
67
|
|
105
68
|
private
|
@@ -110,15 +73,13 @@ module BankTools
|
|
110
73
|
|
111
74
|
def bank_data
|
112
75
|
number = digits[0,4].to_i
|
113
|
-
_, found_data = CLEARING_NUMBER_MAP.find
|
114
|
-
interval.include?(number)
|
115
|
-
end
|
76
|
+
_, found_data = CLEARING_NUMBER_MAP.find { |interval, data| interval.include?(number) }
|
116
77
|
found_data || {}
|
117
78
|
end
|
118
79
|
|
119
80
|
def min_length
|
120
81
|
if bank_data
|
121
|
-
Array(
|
82
|
+
Array(serial_number_length).first
|
122
83
|
else
|
123
84
|
0
|
124
85
|
end
|
@@ -126,13 +87,17 @@ module BankTools
|
|
126
87
|
|
127
88
|
def max_length
|
128
89
|
if bank_data
|
129
|
-
Array(
|
90
|
+
Array(serial_number_length).last +
|
130
91
|
(checksum_for_clearing? ? 1 : 0)
|
131
92
|
else
|
132
93
|
1/0.0 # Infinity.
|
133
94
|
end
|
134
95
|
end
|
135
96
|
|
97
|
+
def serial_number_length
|
98
|
+
bank_data.fetch(:serial_number_length, DEFAULT_SERIAL_NUMBER_LENGTH)
|
99
|
+
end
|
100
|
+
|
136
101
|
def luhn_for_serial?
|
137
102
|
bank_data[:luhn_for_serial]
|
138
103
|
end
|
@@ -148,7 +113,6 @@ module BankTools
|
|
148
113
|
def zerofill?
|
149
114
|
!!bank_data[:zerofill]
|
150
115
|
end
|
151
|
-
|
152
116
|
end
|
153
117
|
end
|
154
118
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module BankTools
|
4
|
+
module SE
|
5
|
+
class Account
|
6
|
+
module ClearingNumber
|
7
|
+
MAP = {
|
8
|
+
1100..1199 => { name: "Nordea" },
|
9
|
+
1200..1399 => { name: "Danske Bank" },
|
10
|
+
1400..2099 => { name: "Nordea" },
|
11
|
+
2300..2399 => { name: "Ålandsbanken" },
|
12
|
+
2400..2499 => { name: "Danske Bank" },
|
13
|
+
3000..3299 => { name: "Nordea" },
|
14
|
+
3300..3300 => { name: "Nordea", serial_number_length: 10, luhn_for_serial: true }, # Personkonto.
|
15
|
+
3301..3399 => { name: "Nordea" },
|
16
|
+
3400..3409 => { name: "Länsförsäkringar Bank" },
|
17
|
+
3410..3781 => { name: "Nordea" },
|
18
|
+
3782..3782 => { name: "Nordea", serial_number_length: 10, luhn_for_serial: true }, # Personkonto.
|
19
|
+
3783..4999 => { name: "Nordea" },
|
20
|
+
5000..5999 => { name: "SEB" },
|
21
|
+
6000..6999 => { name: "Handelsbanken", serial_number_length: 9 },
|
22
|
+
7000..7999 => { name: "Swedbank" },
|
23
|
+
# Can be fewer chars but must be zero-filled, so let's call it 10.
|
24
|
+
8000..8999 => { name: "Swedbank", serial_number_length: 10, checksum_for_clearing: true, zerofill: true },
|
25
|
+
9020..9029 => { name: "Länsförsäkringar Bank" },
|
26
|
+
9040..9049 => { name: "Citibank" },
|
27
|
+
9060..9069 => { name: "Länsförsäkringar Bank" },
|
28
|
+
9090..9099 => { name: "Royal Bank of Scotland" },
|
29
|
+
9100..9109 => { name: "Nordnet Bank" },
|
30
|
+
9120..9124 => { name: "SEB" },
|
31
|
+
9130..9149 => { name: "SEB" },
|
32
|
+
9150..9169 => { name: "Skandiabanken" },
|
33
|
+
9170..9179 => { name: "Ikano Bank" },
|
34
|
+
9180..9189 => { name: "Danske Bank", serial_number_length: 10 },
|
35
|
+
9190..9199 => { name: "Den Norske Bank" },
|
36
|
+
9230..9239 => { name: "Marginalen Bank" },
|
37
|
+
9250..9259 => { name: "SBAB" },
|
38
|
+
9260..9269 => { name: "Den Norske Bank" },
|
39
|
+
9270..9279 => { name: "ICA Banken" },
|
40
|
+
9280..9289 => { name: "Resurs Bank" },
|
41
|
+
9300..9349 => { name: "Sparbanken Öresund", serial_number_length: 10, zerofill: true },
|
42
|
+
9400..9449 => { name: "Forex Bank" },
|
43
|
+
9460..9469 => { name: "GE Money Bank" },
|
44
|
+
9470..9479 => { name: "Fortis Bank" },
|
45
|
+
9500..9549 => { name: "Nordea/Plusgirot", serial_number_length: 1..10 },
|
46
|
+
9550..9569 => { name: "Avanza Bank" },
|
47
|
+
9570..9579 => { name: "Sparbanken Syd", serial_number_length: 10, zerofill: true },
|
48
|
+
9960..9969 => { name: "Nordea/Plusgirot", serial_number_length: 1..10 },
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -29,7 +29,7 @@ module BankTools
|
|
29
29
|
errors << Errors::TOO_SHORT if digits.length < 7
|
30
30
|
errors << Errors::TOO_LONG if digits.length > 8
|
31
31
|
errors << Errors::INVALID_CHARACTERS if number.to_s.match(/[^0-9 -]/)
|
32
|
-
errors << Errors::BAD_CHECKSUM unless
|
32
|
+
errors << Errors::BAD_CHECKSUM unless Utils.valid_luhn?(number)
|
33
33
|
|
34
34
|
errors
|
35
35
|
end
|
@@ -43,7 +43,7 @@ module BankTools
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def fundraising?
|
46
|
-
valid? && digits.match(
|
46
|
+
valid? && digits.match(/\A90[0-4]/)
|
47
47
|
end
|
48
48
|
|
49
49
|
private
|
@@ -6,35 +6,39 @@ module BankTools
|
|
6
6
|
class InvalidOCR < StandardError; end
|
7
7
|
class OverlongOCR < InvalidOCR; end
|
8
8
|
class BadChecksum < InvalidOCR; end
|
9
|
+
class MustBeNumeric < InvalidOCR; end
|
9
10
|
|
10
11
|
class OCR
|
11
|
-
|
12
|
-
|
13
|
-
pad = opts.fetch(:pad, nil)
|
12
|
+
MIN_LENGTH = 2
|
13
|
+
MAX_LENGTH = 25
|
14
14
|
|
15
|
+
def self.number_to_ocr(number, opts = {})
|
15
16
|
number = number.to_s
|
17
|
+
add_length_digit = opts.fetch(:length_digit, false)
|
18
|
+
pad = opts.fetch(:pad, "").to_s
|
16
19
|
|
17
|
-
|
18
|
-
|
20
|
+
raise MustBeNumeric unless number.match(/\A\d+\z/)
|
21
|
+
# Padding isn't something BGC specifies, but we needed it to support a legacy scheme.
|
22
|
+
number += pad
|
19
23
|
# Adding 2: 1 length digit, 1 check digit.
|
20
24
|
number += ((number.length + 2) % 10).to_s if add_length_digit
|
21
25
|
|
22
26
|
number_with_ocr = number + Utils.luhn_checksum(number).to_s
|
23
27
|
|
24
28
|
length = number_with_ocr.length
|
25
|
-
if length >
|
26
|
-
raise OverlongOCR, "Bankgiro OCR must be
|
29
|
+
if length > MAX_LENGTH
|
30
|
+
raise OverlongOCR, "Bankgiro OCR must be #{MIN_LENGTH} - #{MAX_LENGTH} characters (this one would be #{length} characters)"
|
27
31
|
end
|
28
32
|
|
29
33
|
number_with_ocr
|
30
34
|
end
|
31
35
|
|
32
36
|
def self.number_from_ocr(number, opts = {})
|
33
|
-
strip_length_digit = opts.fetch(:length_digit, false)
|
34
|
-
strip_padding = opts.fetch(:pad, "")
|
35
|
-
|
36
37
|
number = number.to_s
|
38
|
+
strip_length_digit = opts.fetch(:length_digit, false)
|
39
|
+
strip_padding = opts.fetch(:pad, "").to_s
|
37
40
|
|
41
|
+
raise MustBeNumeric unless number.match(/\A\d+\z/)
|
38
42
|
raise BadChecksum unless Utils.valid_luhn?(number)
|
39
43
|
|
40
44
|
digits_to_chop = 1 # Checksum.
|
@@ -21,7 +21,7 @@ module BankTools
|
|
21
21
|
errors << Errors::TOO_SHORT if digits.length < 2
|
22
22
|
errors << Errors::TOO_LONG if digits.length > 8
|
23
23
|
errors << Errors::INVALID_CHARACTERS if number.to_s.match(/[^0-9 -]/)
|
24
|
-
errors << Errors::BAD_CHECKSUM unless
|
24
|
+
errors << Errors::BAD_CHECKSUM unless Utils.valid_luhn?(number)
|
25
25
|
|
26
26
|
errors
|
27
27
|
end
|
@@ -39,7 +39,7 @@ module BankTools
|
|
39
39
|
# http://www.plusgirot.se/Om+PlusGirot/90-konton/508552.html
|
40
40
|
# http://www.insamlingskontroll.se/
|
41
41
|
def fundraising?
|
42
|
-
valid? && digits.match(
|
42
|
+
valid? && digits.match(/\A90\d{5}$/)
|
43
43
|
end
|
44
44
|
|
45
45
|
private
|
data/lib/banktools-se/version.rb
CHANGED
data/spec/account_spec.rb
CHANGED
@@ -142,9 +142,6 @@ describe BankTools::SE::Account do
|
|
142
142
|
BankTools::SE::Account.new("12").serial_number.should == ""
|
143
143
|
end
|
144
144
|
|
145
|
-
it "should manage pre-zerofilled account numbers" do
|
146
|
-
BankTools::SE::Account.new("8000-2-0800000002").should be_valid
|
147
|
-
end
|
148
145
|
end
|
149
146
|
|
150
147
|
describe "#normalize" do
|
data/spec/bankgiro_spec.rb
CHANGED
@@ -105,6 +105,10 @@ describe BankTools::SE::Bankgiro do
|
|
105
105
|
it "raises if resulting number is > 25 digits" do
|
106
106
|
expect { BankTools::SE::Bankgiro.number_to_ocr("1234567890123456789012345") }.to raise_error(BankTools::SE::Bankgiro::OverlongOCR)
|
107
107
|
end
|
108
|
+
|
109
|
+
it "raises if input is non-numeric" do
|
110
|
+
expect { BankTools::SE::Bankgiro.number_to_ocr("garbage") }.to raise_error(BankTools::SE::Bankgiro::MustBeNumeric)
|
111
|
+
end
|
108
112
|
end
|
109
113
|
|
110
114
|
describe ".number_from_ocr" do
|
@@ -127,5 +131,9 @@ describe BankTools::SE::Bankgiro do
|
|
127
131
|
it "raises if checksum is wrong" do
|
128
132
|
expect { BankTools::SE::Bankgiro.number_from_ocr("1231") }.to raise_error(BankTools::SE::Bankgiro::BadChecksum)
|
129
133
|
end
|
134
|
+
|
135
|
+
it "raises if input is non-numeric" do
|
136
|
+
expect { BankTools::SE::Bankgiro.number_from_ocr("garbage") }.to raise_error(BankTools::SE::Bankgiro::MustBeNumeric)
|
137
|
+
end
|
130
138
|
end
|
131
139
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: banktools-se
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henrik Nyh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -81,6 +81,7 @@ files:
|
|
81
81
|
- banktools-se.gemspec
|
82
82
|
- lib/banktools-se.rb
|
83
83
|
- lib/banktools-se/account.rb
|
84
|
+
- lib/banktools-se/account/clearing_number.rb
|
84
85
|
- lib/banktools-se/bankgiro.rb
|
85
86
|
- lib/banktools-se/bankgiro/ocr.rb
|
86
87
|
- lib/banktools-se/errors.rb
|