banktools-se 0.8.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 423ae55440789051d2a88262b7da03873b9359b3
4
- data.tar.gz: a8cc8599a42101869684162d84e0f957bf8fe7e3
3
+ metadata.gz: 56417ca1fa0b99e2d5c754563686051cc73c0387
4
+ data.tar.gz: 7abf1933594e2ff146fe570a5b935e41ab996e14
5
5
  SHA512:
6
- metadata.gz: 2207ad3837fa11039e03088ca5df0d96ea79e1c87150609a23a21db7581437a06e03763345fef03447a8de38f970000edeff6c932941cd99fd3d62f6d968742c
7
- data.tar.gz: d61848a2806d739bf908cc894eef42a4548aab91552780414b64d1303ed4081aa4e81c3109925e5800a44d6b4d28197315c51990bcc2d29ca1ddff0258c1a44a
6
+ metadata.gz: 920c68e4e3cdfed665e6242256952f5cd770ed3e25faab56cd8cbb33b76ffec39d38d1fcfed12a0a0cda67dde11cafc0b6a91c51274bcbc163d4108f18b6c2bc
7
+ data.tar.gz: 3176a6146b0380d9db063b82e343dce699918ab2537fb7cd419d4bc3321fd07bd085a9d3847baf15abe7ad5068b4dbd9e00bfb5128d41978406fd41c203c7c7c
@@ -1,4 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 2.1.0
3
4
  - 2.0.0
4
5
  - 1.9.3
@@ -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:
@@ -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(/[^0-9 -]/)
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 BankTools::SE::Utils.valid_luhn?(serial_number)
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
- zerofill? ? "%.#{bank_data[:serial_number_length]}d" % number.to_i(10) : number
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 do |interval, data|
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(bank_data[:serial_number_length] || DEFAULT_SERIAL_NUMBER_LENGTH).first
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(bank_data[:serial_number_length] || DEFAULT_SERIAL_NUMBER_LENGTH).last +
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 BankTools::SE::Utils.valid_luhn?(number)
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(/^90[0-4]/)
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
- def self.number_to_ocr(number, opts = {})
12
- add_length_digit = opts.fetch(:length_digit, false)
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
- number += pad if pad
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 > 25
26
- raise OverlongOCR, "Bankgiro OCR must be 2-25 characters (this one would be #{length} characters)"
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 BankTools::SE::Utils.valid_luhn?(number)
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(/^90\d{5}$/)
42
+ valid? && digits.match(/\A90\d{5}$/)
43
43
  end
44
44
 
45
45
  private
@@ -1,5 +1,5 @@
1
1
  module BankTools
2
2
  module SE
3
- VERSION = "0.8.0"
3
+ VERSION = "0.10.0"
4
4
  end
5
5
  end
@@ -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
@@ -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.8.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-17 00:00:00.000000000 Z
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