bank_account_tools 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,47 @@
1
+ require 'forwardable'
2
+ require 'bank_account_tools/bban'
3
+ require 'bank_account_tools/validators/iban_validator' if defined? ActiveModel
4
+
5
+ module BankAccountTools
6
+ class IBAN # International Bank Account Number
7
+ extend Forwardable
8
+ def_delegators :bban,
9
+ :account_number, :bank_identifier, :branch_identifier, :country_applies_iban?
10
+
11
+ def self.valid?(code)
12
+ new(code).valid?
13
+ end
14
+
15
+ def initialize(code)
16
+ @code = code.to_s.gsub(/\s+/, '').upcase
17
+ end
18
+
19
+ def country_code
20
+ @code[0..1]
21
+ end
22
+
23
+ def check_digits
24
+ @code[2..3]
25
+ end
26
+
27
+ def bban
28
+ @bban ||= BBAN.new(country_code, @code[4..-1])
29
+ end
30
+
31
+ def valid?
32
+ valid_check_digits? && bban.valid?
33
+ end
34
+
35
+ def valid_check_digits?
36
+ to_i % 97 == 1
37
+ end
38
+
39
+ def to_i
40
+ "#{bban}#{country_code}#{check_digits}".each_char.map { |chr| chr.to_i(36) }.join.to_i
41
+ end
42
+
43
+ def to_s(formatted=false)
44
+ formatted ? @code.gsub(/(.{4})/, '\1 ').strip : @code
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,9 @@
1
+ RSpec::Matchers.define :have_valid_bic do |attribute|
2
+ match do
3
+ actual_class_name = subject.is_a?(Class) ? subject : subject.class
4
+ actual = actual_class_name.new
5
+
6
+ expect(actual).to be_invalid
7
+ expect(actual.errors[attribute.to_sym]).to include('is of invalid format')
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ RSpec::Matchers.define :have_valid_iban do |attribute|
2
+ match do
3
+ actual_class_name = subject.is_a?(Class) ? subject : subject.class
4
+ actual = actual_class_name.new
5
+
6
+ expect(actual).to be_invalid
7
+ expect(actual.errors[attribute.to_sym]).to include('is of invalid format')
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ require_relative 'active_model/have_valid_iban'
2
+ require_relative 'active_model/have_valid_bic'
@@ -0,0 +1,7 @@
1
+ require 'active_model/validator'
2
+
3
+ class BicValidator < ActiveModel::EachValidator
4
+ def validate_each(record, attribute, value)
5
+ record.errors.add(attribute, :invalid) unless BankAccountTools::BIC.valid?(value)
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'active_model/validator'
2
+
3
+ class IbanValidator < ActiveModel::EachValidator
4
+ def validate_each(record, attribute, value)
5
+ record.errors.add(attribute, :invalid) unless BankAccountTools::IBAN.valid?(value)
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module BankAccountTools
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,19 @@
1
+ require 'bank_account_tools/version'
2
+ require 'bank_account_tools/iban'
3
+ require 'bank_account_tools/bic'
4
+ require 'bank_account_tools/bban'
5
+ require 'bank_account_tools/contact'
6
+
7
+ require 'pathname'
8
+ require 'yaml'
9
+
10
+ if defined?(::ActiveModel)
11
+ require 'bank_account_tools/validators/bic_validator'
12
+ require 'bank_account_tools/validators/iban_validator'
13
+ end
14
+
15
+ module BankAccountTools
16
+ def self.load_specifications(name)
17
+ YAML.load_file Pathname.new(__FILE__).dirname.parent + 'data' + "#{name}.yml"
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ class BankAccount
4
+ include ActiveModel::Model
5
+
6
+ attr_accessor :iban_required, :iban_optional
7
+
8
+ validates :iban_required, iban: true
9
+ validates :iban_optional, iban: true, allow_nil: true
10
+ end
11
+
12
+ describe IbanValidator do
13
+ let(:model) { BankAccount.new }
14
+
15
+ it 'is valid' do
16
+ model.iban_required = 'FR1420041010050500013M02606'
17
+
18
+ expect(model).to be_valid
19
+ end
20
+
21
+ it 'is not valid' do
22
+ model.iban_required = 'FR1420041010050500013'
23
+
24
+ expect(model).to be_invalid
25
+ expect(model.errors[:iban_required]).to include('is invalid')
26
+ end
27
+
28
+ it 'does not validate with nil value' do
29
+ model.iban_required = 'FR1420041010050500013M02606'
30
+ model.iban_optional = nil
31
+
32
+ expect(model).to be_valid
33
+ end
34
+ end
data/spec/bic_spec.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe BankAccountTools::BIC do
4
+ let(:bic) { described_class.new('ABNACHZ8XXX')}
5
+
6
+ it 'returns the right bank code' do
7
+ expect(bic.bank_code).to eq('ABNA')
8
+ end
9
+
10
+ it 'returns the right country code' do
11
+ expect(bic.country_code).to eq('CH')
12
+ end
13
+
14
+ it 'returns the right location code' do
15
+ expect(bic.location_code).to eq('Z8')
16
+ end
17
+
18
+ it 'returns the right branch code' do
19
+ expect(bic.branch_code).to eq('XXX')
20
+ end
21
+
22
+ [
23
+ 'UCJAES2MXXX',
24
+ 'ABAGATWWXXX',
25
+ 'UCJAES2MXXX'
26
+ ].each do |code|
27
+ describe code do
28
+ it 'has a valid format' do
29
+ expect(BankAccountTools::BIC.new(code)).to be_valid
30
+ end
31
+ end
32
+ end
33
+
34
+ [
35
+ '12341234', # only digits
36
+ 'UCJAES2MXAA', # branch code starts with 'X'
37
+ 'UCJAES2MAA', # too short
38
+ 'UCJAES2M0001' # too long
39
+ ].each do |code|
40
+ describe code do
41
+ it 'has an invalid format' do
42
+ expect(BankAccountTools::BIC.new(code)).not_to be_valid
43
+ end
44
+ end
45
+ end
46
+
47
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe BankAccountTools::Contact do
4
+ let(:iban) { BankAccountTools::IBAN.new('FR14 2004 1010 0505 0001 3M026 06') }
5
+ let(:bic) { BankAccountTools::BIC.new('BYLADEM1203') }
6
+ let(:contact) { BankAccountTools::Contact.new(iban, bic) }
7
+
8
+ it 'is validate' do
9
+ expect(contact).to be_valid
10
+ end
11
+
12
+ it 'has the right types' do
13
+ expect(contact.iban).to be_kind_of(BankAccountTools::IBAN)
14
+ expect(contact.bic).to be_kind_of(BankAccountTools::BIC)
15
+ end
16
+
17
+ it 'exports to_h' do
18
+ expect(contact.to_h).to eq(
19
+ iban: 'FR1420041010050500013M02606',
20
+ bic: 'BYLADEM1203'
21
+ )
22
+ end
23
+
24
+ it 'exports to_a' do
25
+ expect(contact.to_a).to eq(['FR1420041010050500013M02606', 'BYLADEM1203'])
26
+ end
27
+ end
data/spec/iban_spec.rb ADDED
@@ -0,0 +1,160 @@
1
+ require 'spec_helper'
2
+
3
+ describe BankAccountTools::IBAN do
4
+ let(:iban) { BankAccountTools::IBAN.new('FR14 2004 1010 0505 0001 3M026 06') }
5
+
6
+ it 'is valid from class method' do
7
+ expect(BankAccountTools::IBAN.valid?('FR14 2004 1010 0505 0001 3M026 06')).to be_truthy
8
+ end
9
+
10
+ it 'loads the validation rules' do
11
+ expect(BankAccountTools.load_specifications(:iban)).to be_present
12
+ expect(BankAccountTools.load_specifications(:iban)).to be_kind_of(Hash)
13
+ end
14
+
15
+ it 'should return the county code' do
16
+ expect(iban.country_code).to eq('FR')
17
+ end
18
+
19
+ it 'should return the check digits' do
20
+ expect(iban.check_digits).to eq('14')
21
+ end
22
+
23
+ it 'should return the BBAN' do
24
+ expect(iban.bban).to be_a(BankAccountTools::BBAN)
25
+ expect(iban.bban.to_s).to eq('20041010050500013M02606')
26
+ end
27
+
28
+ it 'should convert to integer value' do
29
+ expect(iban.to_i).to eq(200410100505000132202606152714)
30
+ end
31
+
32
+ it 'should convert to string' do
33
+ expect(iban.to_s).to eq('FR1420041010050500013M02606')
34
+ end
35
+
36
+ it 'should convert to formatted string' do
37
+ expect(iban.to_s(true)).to eq('FR14 2004 1010 0505 0001 3M02 606')
38
+ end
39
+
40
+ it 'respond_to? account_number' do
41
+ expect(iban.respond_to?(:account_number)).to be_truthy
42
+ end
43
+
44
+ it 'returns account_number' do
45
+ expect(iban.account_number).to eq('0500013M026')
46
+ end
47
+
48
+ it 'returns bank_identifier' do
49
+ expect(iban.bank_identifier).to eq('20041')
50
+ end
51
+
52
+ it 'returns branch_identifier' do
53
+ expect(iban.branch_identifier).to eq('01005')
54
+ end
55
+
56
+ it 'knows which countries use IBAN' do
57
+ expect(iban.country_applies_iban?).to be_truthy
58
+
59
+ expect(BankAccountTools::IBAN.new('ZZ99 123456790').country_applies_iban?).to be_falsey
60
+ end
61
+
62
+ [
63
+ 'AL47212110090000000235698741',
64
+ 'AD12 00012030200359100100',
65
+ 'AT611904300234573201',
66
+ 'BE68539007547034',
67
+ 'BA391290079401028494',
68
+ 'BG80BNBG96611020345678',
69
+ 'HR1210010051863000160',
70
+ 'CY17002001280000001200527600',
71
+ 'CZ6508000000192000145399',
72
+ 'DK5000400440116243',
73
+ 'EE382200221020145685',
74
+ 'FO1464600009692713',
75
+ 'FI2112345600000785',
76
+ 'FR1420041010050500013M02606',
77
+ 'GE29NB0000000101904917',
78
+ 'DE89370400440532013000',
79
+ 'GI75NWBK000000007099453',
80
+ 'GR1601101250000000012300695',
81
+ 'GL8964710001000206',
82
+ 'HU42117730161111101800000000',
83
+ 'IS140159260076545510730339',
84
+ 'IE29AIBK93115212345678',
85
+ 'IT60X0542811101000000123456',
86
+ 'LV80BANK0000435195001',
87
+ 'LI21088100002324013AA',
88
+ 'LT121000011101001000',
89
+ 'LU280019400644750000',
90
+ 'MK07300000000042425',
91
+ 'MT84MALT011000012345MTLCAST001S',
92
+ 'MD24AG000225100013104168',
93
+ 'MC5813488000010051108001292',
94
+ 'ME25505000012345678951',
95
+ 'NL91ABNA0417164300',
96
+ 'NO9386011117947',
97
+ 'PL27114020040000300201355387',
98
+ 'PT50000201231234567890154',
99
+ 'RO49AAAA1B31007593840000',
100
+ 'SM86U0322509800000000270100',
101
+ 'RS35260005601001611379',
102
+ 'SK3112000000198742637541',
103
+ 'SI56191000000123438',
104
+ 'ES9121000418450200051332',
105
+ 'SE3550000000054910000003',
106
+ 'CH9300762011623852957',
107
+ 'UA573543470006762462054925026',
108
+ 'GB29NWBK60161331926819',
109
+ 'DZ4000400174401001050486',
110
+ 'AO06000600000100037131174',
111
+ 'AZ21NABZ00000000137010001944',
112
+ 'BH29BMAG1299123456BH00',
113
+ 'BJ11B00610100400271101192591',
114
+ 'BR9700360305000010009795493P1',
115
+ 'VG96VPVG0000012345678901',
116
+ 'BF1030134020015400945000643',
117
+ 'BI43201011067444',
118
+ 'CM2110003001000500000605306',
119
+ 'CV64000300004547069110176',
120
+ 'FR7630007000110009970004942',
121
+ 'CG5230011000202151234567890',
122
+ 'CR0515202001026284066',
123
+ 'DO28BAGR00000001212453611324',
124
+ 'EG1100006001880800100014553',
125
+ 'GA2140002000055602673300064',
126
+ 'GT82TRAJ01020000001210029690',
127
+ 'IR580540105180021273113007',
128
+ 'IL620108000000099999999',
129
+ 'CI05A00060174100178530011852',
130
+ 'KZ176010251000042993',
131
+ 'KW74NBOK0000000000001000372151',
132
+ 'LB30099900000001001925579115',
133
+ 'MG4600005030010101914016056',
134
+ 'ML03D00890170001002120000447',
135
+ 'MR1300012000010000002037372',
136
+ 'MU17BOMM0101101030300200000MUR',
137
+ 'MZ59000100000011834194157',
138
+ 'PK24SCBL0000001171495101',
139
+ 'PS92PALS000000000400123456702',
140
+ 'PT50000200000163099310355',
141
+ 'SA0380000000608010167519',
142
+ 'SN12K00100152000025690007542',
143
+ 'TN5914207207100707129648',
144
+ 'TR330006100519786457841326',
145
+ 'AE260211000000230064016',
146
+ 'XK051212012345678906',
147
+ 'JO94CBJO0010000000000131000302',
148
+ 'QA58DOHB00001234567890ABCDEFG',
149
+ 'TL380030000000025923744',
150
+ 'SC18SSCB11010000000000001497USD',
151
+ 'ST23000200000289355710148',
152
+ 'LC55HEMM000100010012001200023015',
153
+ ].each do |code|
154
+ describe code do
155
+ it 'is valid' do
156
+ expect(BankAccountTools::IBAN.new(code)).to be_valid
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,4 @@
1
+ require 'active_model'
2
+ require 'bank_account_tools/iban'
3
+ require 'bank_account_tools/bic'
4
+ require 'bank_account_tools/contact'
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bank_account_tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Dimitar Kostov
8
+ - Kevin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-08-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.13'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.13'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '12.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '12.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '3.5'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.5'
56
+ - !ruby/object:Gem::Dependency
57
+ name: activemodel
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '4.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '4.0'
70
+ description: 'Bank account tools for dealing with IBANs/BICs: information, validation
71
+ and formatting.'
72
+ email:
73
+ - mitko.kostov@gmail.com
74
+ - kevin.melchert@gmail.com
75
+ executables: []
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - ".gitignore"
80
+ - ".rspec"
81
+ - ".travis.yml"
82
+ - Gemfile
83
+ - LICENSE
84
+ - README.md
85
+ - Rakefile
86
+ - bank_account_tools.gemspec
87
+ - data/iban.yml
88
+ - lib/bank_account_tools.rb
89
+ - lib/bank_account_tools/bban.rb
90
+ - lib/bank_account_tools/bic.rb
91
+ - lib/bank_account_tools/contact.rb
92
+ - lib/bank_account_tools/iban.rb
93
+ - lib/bank_account_tools/matchers/active_model/have_valid_bic.rb
94
+ - lib/bank_account_tools/matchers/active_model/have_valid_iban.rb
95
+ - lib/bank_account_tools/matchers/rspec.rb
96
+ - lib/bank_account_tools/validators/bic_validator.rb
97
+ - lib/bank_account_tools/validators/iban_validator.rb
98
+ - lib/bank_account_tools/version.rb
99
+ - spec/activemodel_spec.rb
100
+ - spec/bic_spec.rb
101
+ - spec/contact_spec.rb
102
+ - spec/iban_spec.rb
103
+ - spec/spec_helper.rb
104
+ homepage: https://github.com/mytrile/bank_account_tools
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 2.6.8
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Bank account tools for dealing with IBANs/BICs
128
+ test_files:
129
+ - spec/activemodel_spec.rb
130
+ - spec/bic_spec.rb
131
+ - spec/contact_spec.rb
132
+ - spec/iban_spec.rb
133
+ - spec/spec_helper.rb