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 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