iban_calculator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +44 -0
- data/Rakefile +2 -0
- data/iban_calculator.gemspec +27 -0
- data/lib/iban_calculator/iban_bic.rb +104 -0
- data/lib/iban_calculator/invalid_data.rb +35 -0
- data/lib/iban_calculator/version.rb +3 -0
- data/lib/iban_calculator.rb +22 -0
- data/spec/iban_bic_spec.rb +244 -0
- data/spec/iban_calculator_spec.rb +51 -0
- data/spec/invalid_data_spec.rb +55 -0
- data/spec/spec_helper.rb +25 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 19c90f0379c87c7251c554191b6ee1ca82f7e7c5
|
4
|
+
data.tar.gz: 1906317a98ebfa25ec45d4bdff1a0c3d01448ab0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2210281de1e0c117cf9881d0f0adea74b8f37271a48032dc5a735a9068fdc3e49e69a990ec8bf650f893eb25c865373582a4c5d5746050f4d99f261ee4b0372a
|
7
|
+
data.tar.gz: 4d69c1cef82b442417c2a2096a408eb394f5d1ad8673cdef9c047a245625b8a2e2271e8a2d36200ea583460a15809d0cc8e6db7ef753c4f09b7692f9b2028035
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Maximilian Schulz
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# IbanCalculator
|
2
|
+
|
3
|
+
A wrapper for ibanrechner.de API. It allows converting bank account data from legacy syntax to new SEPA IBAN/BIC.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'iban_calculator'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install iban_calculator
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
In order to use iban calculator, you need to create an account at [iban-bic.com](http://www.iban-bic.com/).
|
22
|
+
|
23
|
+
In case you are using rails, configure your app like this:
|
24
|
+
|
25
|
+
# config/initializers/iban_calculator.rb
|
26
|
+
IbanCalculator.user = 'your_username',
|
27
|
+
IbanCalculator.password = 'your_password'
|
28
|
+
IbanCalculator.logger = Rails.logger
|
29
|
+
|
30
|
+
Whenever you need to convert European legacy account data to new SEPA IBAN format:
|
31
|
+
|
32
|
+
# app/models/your_model.rb
|
33
|
+
IbanCalculator.calculate_iban country: 'DE', account_number: '123', bank_code: '456'
|
34
|
+
|
35
|
+
Example data can be found at: http://www.iban-bic.com/sample_accounts.html
|
36
|
+
|
37
|
+
|
38
|
+
## Contributing
|
39
|
+
|
40
|
+
1. Fork it ( https://github.com/[my-github-username]/iban_calculator/fork )
|
41
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
42
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
43
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
44
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'iban_calculator/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "iban_calculator"
|
8
|
+
spec.version = IbanCalculator::VERSION
|
9
|
+
spec.authors = ["Maximilian Schulz"]
|
10
|
+
spec.email = ["m.schulz@kulturfluss.de"]
|
11
|
+
spec.summary = %q{Calculate IBAN and BIC for countries of Single European Payments Area (SEPA).}
|
12
|
+
spec.description = %q{At the moment the gem is just a wrapper for the ibanrechner.de API.}
|
13
|
+
spec.homepage = "https://github.com/railslove/iban_calculator"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "activesupport", "~> 4"
|
22
|
+
spec.add_dependency "savon", "~> 2"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
25
|
+
spec.add_development_dependency "rake", "~> 0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3"
|
27
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'savon'
|
2
|
+
|
3
|
+
# Return codes and their meaning:
|
4
|
+
#
|
5
|
+
# 0 = all checks were successful
|
6
|
+
#
|
7
|
+
# 1 = sub account number has been added automatically
|
8
|
+
# 2 = account number did not include a checksum
|
9
|
+
# 4 = checksum has not been checked
|
10
|
+
# 8 = bank code has not been checked
|
11
|
+
#
|
12
|
+
# 32 = A sub account number might be required, but could not be determined autoamtically
|
13
|
+
#
|
14
|
+
# 128 = checksum for account_number is invalid
|
15
|
+
# 256 = bank_code could not be found is database
|
16
|
+
# 512 = account_number has an invalid length
|
17
|
+
# 1024 = bank_code has an invalid length
|
18
|
+
# 4096 = data is missing (i.e. country code)
|
19
|
+
# 8192= country is not yet supported
|
20
|
+
#
|
21
|
+
module IbanCalculator
|
22
|
+
class IbanBic
|
23
|
+
ITALIAN_IBAN_LENGTH = 27
|
24
|
+
PREFIX_AND_CHECKSUM_LENGTH = 4
|
25
|
+
|
26
|
+
VALID_RESPONSE_CODE = 0..31
|
27
|
+
PROBABLY_VALID_RESPONSE_CODE = 32..127
|
28
|
+
SERVICE_ERROR_RESPONSE_CODE = 65536
|
29
|
+
|
30
|
+
attr_accessor :user, :password, :url, :logger
|
31
|
+
|
32
|
+
def initialize(user, password, url, logger)
|
33
|
+
self.user = user
|
34
|
+
self.password = password
|
35
|
+
self.url = url
|
36
|
+
self.logger = logger
|
37
|
+
end
|
38
|
+
|
39
|
+
# You should provide country, bank_code, and account_number. (cin, abi, and cab for Italian accounts)
|
40
|
+
def calculate_iban(attributes)
|
41
|
+
payload = iban_payload(attributes)
|
42
|
+
response = client.call(:calculate_iban, message: payload).body[:calculate_iban_response][:return]
|
43
|
+
log "iban lookup attributes=#{attributes} payload=#{payload} response=#{response}"
|
44
|
+
|
45
|
+
case return_code = response[:return_code].to_i
|
46
|
+
when VALID_RESPONSE_CODE
|
47
|
+
formatted_result(response)
|
48
|
+
when PROBABLY_VALID_RESPONSE_CODE
|
49
|
+
log "iban check needs manual check return_code=#{return_code}"
|
50
|
+
formatted_result(response)
|
51
|
+
when SERVICE_ERROR_RESPONSE_CODE
|
52
|
+
log "iban check failed return_code=#{return_code}"
|
53
|
+
fail ServiceError, 'Service could not handle the request'
|
54
|
+
else
|
55
|
+
log "iban check invalid return_code=#{return_code}"
|
56
|
+
fail InvalidData.new('Invalid input data', return_code)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def italian_account_number(attributes = {})
|
61
|
+
return {} unless attributes['country'].to_s.upcase == 'IT'
|
62
|
+
left_length = ITALIAN_IBAN_LENGTH - PREFIX_AND_CHECKSUM_LENGTH - attributes['account'].length
|
63
|
+
left_side = [attributes['cin'], attributes['abi'], attributes['cab']].join.ljust(left_length, '0')
|
64
|
+
{ 'account' => left_side + attributes['account'] }
|
65
|
+
end
|
66
|
+
|
67
|
+
def default_payload
|
68
|
+
{ country: '', bank_code: '', account: '', user: user, password: password, bic: '', legacy_mode: 0 }
|
69
|
+
end
|
70
|
+
|
71
|
+
def formatted_result(data)
|
72
|
+
{ iban: data[:iban],
|
73
|
+
bics: process_bic_candidates(data[:bic_candidates]),
|
74
|
+
country: data[:country],
|
75
|
+
bank_code: data[:bank_code],
|
76
|
+
bank: data[:bank],
|
77
|
+
account_number: data[:account_number],
|
78
|
+
updated_at: Date.parse(data[:data_age]) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def process_bic_candidates(candidates)
|
82
|
+
[candidates[:item].select { |key, value| [:bic, :zip, :city].include?(key) && value.kind_of?(String) }]
|
83
|
+
rescue
|
84
|
+
log "Could not handle candidates=#{candidates}"
|
85
|
+
fail ArgumentError, "Could not handle BIC response"
|
86
|
+
end
|
87
|
+
|
88
|
+
def iban_payload(attributes)
|
89
|
+
attributes = attributes.with_indifferent_access
|
90
|
+
attributes['account'] = attributes.delete('account_number')
|
91
|
+
normalized_attributes = attributes.merge(italian_account_number(attributes))
|
92
|
+
payload = normalized_attributes.select { |k,_| %w(country account bank_code).include?(k) }
|
93
|
+
default_payload.merge(payload.symbolize_keys)
|
94
|
+
end
|
95
|
+
|
96
|
+
def log(message)
|
97
|
+
logger.info message
|
98
|
+
end
|
99
|
+
|
100
|
+
def client
|
101
|
+
@client ||= Savon.client(wsdl: url)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module IbanCalculator
|
2
|
+
class InvalidData < StandardError
|
3
|
+
CODES = {
|
4
|
+
128 => [:account_number, [:checksum_failed]],
|
5
|
+
256 => [:bank_code, [:not_found]],
|
6
|
+
512 => [:account_number, [:invalid_length]],
|
7
|
+
1024 => [:bank_code, [:invalid_length]],
|
8
|
+
4096 => [:base, [:data_missing]],
|
9
|
+
8192 => [:country, [:not_supported]],
|
10
|
+
}
|
11
|
+
|
12
|
+
attr_accessor :errors
|
13
|
+
|
14
|
+
def initialize(msg, error_code)
|
15
|
+
self.errors = resolve_error_code(error_code)
|
16
|
+
super(msg)
|
17
|
+
end
|
18
|
+
|
19
|
+
def resolve_error_code(error_code)
|
20
|
+
known_error_codes(error_code).reduce(Hash.new([])) do |hsh, item|
|
21
|
+
error = CODES[item]
|
22
|
+
hsh[error[0]] += error[1]
|
23
|
+
hsh
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def known_error_codes(error_code)
|
28
|
+
error_codes(error_code) & CODES.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def error_codes(n)
|
32
|
+
(0..13).map { |i| n & 2**i } - [0]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'iban_calculator/version'
|
2
|
+
require 'active_support/configurable'
|
3
|
+
require 'active_support/core_ext/hash'
|
4
|
+
require 'logger'
|
5
|
+
require 'iban_calculator/iban_bic'
|
6
|
+
require 'iban_calculator/invalid_data'
|
7
|
+
|
8
|
+
module IbanCalculator
|
9
|
+
include ActiveSupport::Configurable
|
10
|
+
|
11
|
+
config_accessor(:url) { 'https://ssl.ibanrechner.de/soap/?wsdl' }
|
12
|
+
config_accessor(:user) { '' }
|
13
|
+
config_accessor(:password) { '' }
|
14
|
+
config_accessor(:logger) { Logger.new(STDOUT) }
|
15
|
+
|
16
|
+
ServiceError = Class.new(StandardError)
|
17
|
+
|
18
|
+
def self.calculate_iban(attributes = {})
|
19
|
+
client = IbanBic.new(config.user, config.password, config.url, config.logger)
|
20
|
+
client.calculate_iban(attributes)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
describe IbanCalculator::IbanBic do
|
2
|
+
subject { described_class.new('user', 'pass', 'url', Logger.new(STDOUT) ) }
|
3
|
+
|
4
|
+
before { allow(subject.logger).to receive(:info) }
|
5
|
+
|
6
|
+
describe '#italian_account_number' do
|
7
|
+
it 'returns an empty hash if not all fields are provided' do
|
8
|
+
expect(subject.italian_account_number).to eq({})
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns hash with correct account number if valid data is provided' do
|
12
|
+
expect(subject.italian_account_number(
|
13
|
+
'country' => 'IT',
|
14
|
+
'cab' => '03280',
|
15
|
+
'abi' => '03002',
|
16
|
+
'cin' => 'D',
|
17
|
+
'account' => '400162854',
|
18
|
+
)).to eq('account' => 'D0300203280000400162854')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#default_payload' do
|
23
|
+
it 'includes account data' do
|
24
|
+
expect(subject.default_payload).to match hash_including(user: 'user', password: 'pass')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#process_bic_candidates' do
|
29
|
+
context 'known single BIC payload' do
|
30
|
+
let(:payload) { valid_payload[:bic_candidates] }
|
31
|
+
|
32
|
+
it 'returns an array' do
|
33
|
+
expect(subject.process_bic_candidates(payload)).to be_kind_of(Array)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'returns its bank\'s bic' do
|
37
|
+
expect(subject.process_bic_candidates(payload).first).to match hash_including(bic: 'BYLADEM1001')
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns its bank\'s zip' do
|
41
|
+
expect(subject.process_bic_candidates(payload).first).to match hash_including(zip: '10117')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns its bank\'s city' do
|
45
|
+
expect(subject.process_bic_candidates(payload).first).to match hash_including(city: 'Berlin')
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'empty fields' do
|
49
|
+
let(:payload) { {:item=>{
|
50
|
+
:bic=>"UNCRITMM",
|
51
|
+
:zip=>{:"@xsi:type"=>"xsd:string"},
|
52
|
+
:city=>{:"@xsi:type"=>"xsd:string"},
|
53
|
+
:wwwcount=>"0",
|
54
|
+
:sampleurl=>{:"@xsi:type"=>"xsd:string"},
|
55
|
+
:"@xsi:type"=>"tns:BICStruct"
|
56
|
+
},
|
57
|
+
:"@xsi:type"=>"SOAP-ENC:Array",
|
58
|
+
:"@soap_enc:array_type"=>"tns:BICStruct[1]"} }
|
59
|
+
|
60
|
+
it 'ignores empty zip' do
|
61
|
+
expect(subject.process_bic_candidates(payload).first.keys).to_not include(:zip)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'ignores empty city' do
|
65
|
+
expect(subject.process_bic_candidates(payload).first.keys).to_not include(:city)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'unknown payload' do
|
71
|
+
let(:payload) { { :items => [], :"@xsi:type" => 'SOAP-ENC:Array' } }
|
72
|
+
|
73
|
+
it 'logs the payload' do
|
74
|
+
subject.process_bic_candidates(payload) rescue
|
75
|
+
expect(subject.logger).to have_received(:info)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'raises an exception' do
|
79
|
+
expect { subject.process_bic_candidates(payload) }.to raise_exception(ArgumentError)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#formatted_result' do
|
85
|
+
before { allow(subject).to receive(:process_bic_candidates).and_return(['data']) }
|
86
|
+
|
87
|
+
it 'returns a valid ruby date for last update date' do
|
88
|
+
expect(subject.formatted_result(valid_payload)[:updated_at]).to be_kind_of(Date)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'transforms the list of bic candidates' do
|
92
|
+
subject.formatted_result(valid_payload)
|
93
|
+
expect(subject).to have_received(:process_bic_candidates)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'includes iban' do
|
97
|
+
expect(subject.formatted_result(valid_payload).keys).to include(:iban)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#iban_payload' do
|
102
|
+
context 'italian data is provided' do
|
103
|
+
before { allow(subject).to receive(:italian_account_number).and_return({ 'account' => 'italy-123' }) }
|
104
|
+
|
105
|
+
it 'normalizes italian account data' do
|
106
|
+
subject.iban_payload({})
|
107
|
+
expect(subject).to have_received(:italian_account_number)
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'merges italian data' do
|
111
|
+
expect(subject.iban_payload({ 'country' => 'IT' })).to match(hash_including(account: 'italy-123'))
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'strips italian data' do
|
115
|
+
expect(subject.iban_payload({ 'cin' => '123' }).keys).to_not include('cin')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'adds default payload' do
|
120
|
+
expect(subject.iban_payload({}).keys).to include(:user, :password, :legacy_mode)
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'overrides default data' do
|
124
|
+
expect(subject.iban_payload({ bank_code: '123' })).to match hash_including(bank_code: '123')
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'replaces account_number with account' do
|
128
|
+
expect(subject.iban_payload({ account_number: '123' })).to match hash_including(account: '123')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '#calculate_iban' do
|
133
|
+
before { allow(subject.client).to receive(:call).and_return(response) }
|
134
|
+
|
135
|
+
context 'valid response' do
|
136
|
+
let(:response) { double(body: { calculate_iban_response: { return: valid_payload } }) }
|
137
|
+
|
138
|
+
it 'returns a formatted response' do
|
139
|
+
allow(subject).to receive(:formatted_result)
|
140
|
+
subject.calculate_iban({})
|
141
|
+
expect(subject).to have_received(:formatted_result)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'calls the client with the generated payload' do
|
145
|
+
subject.calculate_iban({})
|
146
|
+
expect(subject.client).to have_received(:call).with(:calculate_iban, message: anything)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'probably valid response' do
|
151
|
+
let(:response) { double(body: { calculate_iban_response: { return: valid_payload.merge(return_code: '32') } }) }
|
152
|
+
|
153
|
+
it 'logs a message' do
|
154
|
+
subject.calculate_iban({}) rescue IbanCalculator::InvalidData
|
155
|
+
expect(subject.logger).to have_received(:info).with(/needs manual check/)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'returns a formatted response' do
|
159
|
+
allow(subject).to receive(:formatted_result)
|
160
|
+
subject.calculate_iban({})
|
161
|
+
expect(subject).to have_received(:formatted_result)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'invalid response' do
|
166
|
+
let(:response) { double(body: { calculate_iban_response: { return: valid_payload.merge(return_code: '128') } }) }
|
167
|
+
|
168
|
+
it 'logs a message' do
|
169
|
+
subject.calculate_iban({}) rescue IbanCalculator::InvalidData
|
170
|
+
expect(subject.logger).to have_received(:info).with(/iban check invalid/)
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'fails with invalid data exception' do
|
174
|
+
expect{ subject.calculate_iban({}) }.to raise_exception(IbanCalculator::InvalidData)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'server error response' do
|
179
|
+
let(:response) { double(body: { calculate_iban_response: { return: valid_payload.merge(return_code: '65536') } }) }
|
180
|
+
|
181
|
+
it 'logs a message' do
|
182
|
+
subject.calculate_iban({}) rescue IbanCalculator::ServiceError
|
183
|
+
expect(subject.logger).to have_received(:info).with(/iban check failed/)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'fails with service error exception' do
|
187
|
+
expect{ subject.calculate_iban({}) }.to raise_exception(IbanCalculator::ServiceError)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def valid_payload
|
193
|
+
{
|
194
|
+
:iban=>"DE59120300001111236988",
|
195
|
+
:result=>"passed",
|
196
|
+
:return_code=>"0",
|
197
|
+
:ibanrueck_return_code=>{
|
198
|
+
:"@xsi:type"=>"xsd:string"
|
199
|
+
},
|
200
|
+
:checks=>{
|
201
|
+
:item=>["length", "bank_code", "account_number"],
|
202
|
+
:"@xsi:type"=>"SOAP-ENC:Array",
|
203
|
+
:"@soap_enc:array_type"=>"xsd:string[3]"
|
204
|
+
},
|
205
|
+
:bic_candidates=>{
|
206
|
+
:item=>{
|
207
|
+
:bic=>"BYLADEM1001",
|
208
|
+
:zip=>"10117",
|
209
|
+
:city=>"Berlin",
|
210
|
+
:wwwcount=>"0",
|
211
|
+
:sampleurl=>{:"@xsi:type"=>"xsd:string"},
|
212
|
+
:"@xsi:type"=>"tns:BICStruct"
|
213
|
+
},
|
214
|
+
:"@xsi:type"=>"SOAP-ENC:Array",
|
215
|
+
:"@soap_enc:array_type"=>"tns:BICStruct[1]"
|
216
|
+
},
|
217
|
+
:country=>"DE",
|
218
|
+
:bank_code=>"12030000",
|
219
|
+
:alternative_bank_code=>{:"@xsi:type"=>"xsd:string"},
|
220
|
+
:bank=>"Deutsche Kreditbank Berlin",
|
221
|
+
:bank_address=>{:"@xsi:type"=>"xsd:string"},
|
222
|
+
:bank_url=>{:"@xsi:type"=>"xsd:string"},
|
223
|
+
:branch=>{:"@xsi:type"=>"xsd:string"},
|
224
|
+
:branch_code=>{:"@xsi:type"=>"xsd:string"},
|
225
|
+
:in_scl_directory=>"yes",
|
226
|
+
:sct=>"yes",
|
227
|
+
:sdd=>"yes",
|
228
|
+
:b2b=>"yes",
|
229
|
+
:account_number=>"1011856976",
|
230
|
+
:alternative_account_number=>{:"@xsi:type"=>"xsd:string"},
|
231
|
+
:account_validation_method=>"00",
|
232
|
+
:account_validation=>"Methode 00, Konto 1111236988, BLZ 12030000, Prüfziffer 6 steht an Position 10, erwartete Prüfziffer: 6. Überblick über die Berechnung: Nimm die Ziffern auf den Positionen 1 bis 9 - hier: 1111236988 -, multipliziere sie von rechts nach links mit den Gewichten 2,1,2,1,2,1,2,1,2, addiere die Quersummen der Produkte, bilde den Rest der Division durch 10, ziehe das Ergebnis von 10 ab, und das Ergebnis modulo 10 ist die erwartete Prüfziffer.",
|
233
|
+
:length_check=>"passed",
|
234
|
+
:account_check=>"passed",
|
235
|
+
:bank_code_check=>"passed",
|
236
|
+
:bic_plausibility_check=>{:"@xsi:type"=>"xsd:string"},
|
237
|
+
:data_age=>"20140525",
|
238
|
+
:iba_nformat=>"DEkk BBBB BBBB CCCC CCCC CC",
|
239
|
+
:formatcomment=>"B = sort code (BLZ), C = account No.",
|
240
|
+
:balance=>"4",
|
241
|
+
:"@xsi:type"=>"tns:IBANCalcResStruct"
|
242
|
+
}
|
243
|
+
end
|
244
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
describe IbanCalculator do
|
2
|
+
describe '.url' do
|
3
|
+
it 'defaults to ibanrechner.de' do
|
4
|
+
expect(IbanCalculator.url).to eq('https://ssl.ibanrechner.de/soap/?wsdl')
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'allows overriding' do
|
8
|
+
IbanCalculator.url = 'http://mytest.com'
|
9
|
+
expect(IbanCalculator.url).to eq('http://mytest.com')
|
10
|
+
IbanCalculator.url = 'https://ssl.ibanrechner.de/soap/?wsdl'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.user' do
|
15
|
+
it 'defaults to ""' do
|
16
|
+
expect(IbanCalculator.user).to eq('')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'allows specifying it' do
|
20
|
+
IbanCalculator.user = 'test'
|
21
|
+
expect(IbanCalculator.user).to eq('test')
|
22
|
+
IbanCalculator.user = ''
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '.password' do
|
27
|
+
it 'defaults to ""' do
|
28
|
+
expect(IbanCalculator.password).to eq('')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'allows specifying it' do
|
32
|
+
IbanCalculator.password = 'test'
|
33
|
+
expect(IbanCalculator.password).to eq('test')
|
34
|
+
IbanCalculator.password = ''
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '.logger' do
|
39
|
+
it 'defaults to a logger instance' do
|
40
|
+
expect(IbanCalculator.logger).to be_instance_of(Logger)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'allows specifying it' do
|
44
|
+
old_logger = IbanCalculator.logger
|
45
|
+
logger = Logger.new(STDERR)
|
46
|
+
IbanCalculator.logger = logger
|
47
|
+
expect(IbanCalculator.logger).to eql(logger)
|
48
|
+
IbanCalculator.logger = old_logger
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
describe IbanCalculator::InvalidData do
|
2
|
+
subject { described_class.new('', 128) }
|
3
|
+
|
4
|
+
describe '#resolve_error_code' do
|
5
|
+
it 'handles single errors' do
|
6
|
+
expect(subject.resolve_error_code(128)).to eq(account_number: [:checksum_failed])
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'can combine multiple errors' do
|
10
|
+
expect(subject.resolve_error_code(128 + 256)).to eq(account_number: [:checksum_failed], bank_code: [:not_found])
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'can combine multiple errors of same attribute' do
|
14
|
+
expect(subject.resolve_error_code(128 + 512)).to eq(account_number: [:checksum_failed, :invalid_length])
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can combine multiple errors of same attribute' do
|
18
|
+
expect(subject.resolve_error_code(512)).to eq(account_number: [:invalid_length])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#error_codes' do
|
23
|
+
it 'ignores zeros' do
|
24
|
+
expect(subject.error_codes(0)).to eq([])
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'detects unique values' do
|
28
|
+
expect(subject.error_codes(1)).to eq([1])
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'detects compounded values' do
|
32
|
+
expect(subject.error_codes(3)).to eq([1, 2])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'detects 512' do
|
36
|
+
expect(subject.error_codes(512)).to eq([512])
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'detects compounded values up to 8192' do
|
40
|
+
expect(subject.error_codes(8193)).to eq([1, 8192])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#known_error_codes' do
|
45
|
+
it 'detects 512' do
|
46
|
+
expect(subject.known_error_codes(512)).to eq([512])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#error' do
|
51
|
+
it 'sets error on object' do
|
52
|
+
expect(described_class.new('test', 512).errors).to eq(account_number: [:invalid_length])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'iban_calculator'
|
2
|
+
|
3
|
+
RSpec.configure do |config|
|
4
|
+
config.filter_run :focus
|
5
|
+
config.run_all_when_everything_filtered = true
|
6
|
+
|
7
|
+
if config.files_to_run.one?
|
8
|
+
config.default_formatter = 'doc'
|
9
|
+
end
|
10
|
+
|
11
|
+
config.profile_examples = 3
|
12
|
+
|
13
|
+
config.order = :random
|
14
|
+
|
15
|
+
Kernel.srand config.seed
|
16
|
+
|
17
|
+
config.expect_with :rspec do |expectations|
|
18
|
+
expectations.syntax = :expect
|
19
|
+
end
|
20
|
+
|
21
|
+
config.mock_with :rspec do |mocks|
|
22
|
+
mocks.syntax = :expect
|
23
|
+
mocks.verify_partial_doubles = true
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: iban_calculator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Maximilian Schulz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: savon
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.6'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3'
|
83
|
+
description: At the moment the gem is just a wrapper for the ibanrechner.de API.
|
84
|
+
email:
|
85
|
+
- m.schulz@kulturfluss.de
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- Gemfile
|
93
|
+
- LICENSE.txt
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- iban_calculator.gemspec
|
97
|
+
- lib/iban_calculator.rb
|
98
|
+
- lib/iban_calculator/iban_bic.rb
|
99
|
+
- lib/iban_calculator/invalid_data.rb
|
100
|
+
- lib/iban_calculator/version.rb
|
101
|
+
- spec/iban_bic_spec.rb
|
102
|
+
- spec/iban_calculator_spec.rb
|
103
|
+
- spec/invalid_data_spec.rb
|
104
|
+
- spec/spec_helper.rb
|
105
|
+
homepage: https://github.com/railslove/iban_calculator
|
106
|
+
licenses:
|
107
|
+
- MIT
|
108
|
+
metadata: {}
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 2.2.2
|
126
|
+
signing_key:
|
127
|
+
specification_version: 4
|
128
|
+
summary: Calculate IBAN and BIC for countries of Single European Payments Area (SEPA).
|
129
|
+
test_files:
|
130
|
+
- spec/iban_bic_spec.rb
|
131
|
+
- spec/iban_calculator_spec.rb
|
132
|
+
- spec/invalid_data_spec.rb
|
133
|
+
- spec/spec_helper.rb
|
134
|
+
has_rdoc:
|