afterbanks-psd2-api-ruby 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 74a77be49119cc3b5c78ebcdb319db8f2fb0dc240d9c7374c5a65bfeee4086ca
4
+ data.tar.gz: 75d2475c8af58adfb6cf21954057a7076f8367da1b31f9dc0315fa0e05e79d72
5
+ SHA512:
6
+ metadata.gz: f8978cabe120ef0cdfc65618af4515587f2120c6c0272e0deeffee291f1c0f87a3b25e78079bdc8075594205cc408c83485372361895178596a94f2d6c058cd1
7
+ data.tar.gz: 6b01263e08c321231c7e93111e1752ab9dc4e20b36d45018f35238a59c9bd0cfb90a04ee59160abbd3b531b12b3857010c2dd807d9bf1d103c58c1b162fb56de
@@ -0,0 +1,44 @@
1
+ version: 2.1
2
+
3
+ executors:
4
+ gem-executor:
5
+ working_directory: ~/tmp/afterbanks-psd2-api-ruby
6
+ docker:
7
+ - image: cimg/ruby:3.0.6
8
+ environment:
9
+ TZ: "Europe/Madrid"
10
+
11
+ jobs:
12
+ build-test-gem:
13
+ executor: gem-executor
14
+ steps:
15
+ - checkout
16
+
17
+ - run:
18
+ name: Update bundler
19
+ command: gem install bundler -v 2.2.5
20
+
21
+ - restore_cache:
22
+ keys:
23
+ - afterbanks-psd2-api-ruby-bundle-v2-{{ checksum "Gemfile.lock" }}
24
+ - afterbanks-psd2-api-ruby-bundle-v2-
25
+
26
+ - run: bundle install
27
+
28
+ - save_cache:
29
+ key: afterbanks-psd2-api-ruby-bundle-v2-{{ checksum "Gemfile.lock" }}
30
+ paths:
31
+ - vendor/bundle
32
+
33
+ - run:
34
+ name: Run rspec
35
+ command: bundle exec rspec spec/
36
+
37
+ - run:
38
+ name: Run Rubocop
39
+ command: bundle exec rubocop
40
+
41
+ workflows:
42
+ build-test-gem:
43
+ jobs:
44
+ - build-test-gem
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg/*
2
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,75 @@
1
+ inherit_from: .rubocop_exclusions.yml
2
+
3
+ AllCops:
4
+ DisabledByDefault: true
5
+ SuggestExtensions: false
6
+ TargetRubyVersion: 2.6.6
7
+
8
+ Documentation:
9
+ Enabled: false
10
+
11
+ # Enable Bundler department
12
+ Bundler:
13
+ Enabled: true
14
+
15
+ # Enable lint department
16
+ Lint:
17
+ Enabled: true
18
+
19
+ # Enabling layout department
20
+ Layout:
21
+ Enabled: true
22
+
23
+ # Enabling Security department
24
+ Security:
25
+ Enabled: true
26
+
27
+ Layout/MultilineMethodCallIndentation:
28
+ Enabled: true
29
+ EnforcedStyle: indented_relative_to_receiver
30
+
31
+ Style/CollectionMethods:
32
+ Enabled: true
33
+ PreferredMethods:
34
+ # inject seems more common in the community.
35
+ inject: "reduce"
36
+ collect: "map"
37
+
38
+ Lint/BooleanSymbol:
39
+ Exclude:
40
+ - app/uploaders/attachment_uploader.rb
41
+
42
+ Layout/BlockAlignment:
43
+ EnforcedStyleAlignWith: start_of_block
44
+
45
+ Layout/HashAlignment:
46
+ AllowMultipleStyles: true
47
+ EnforcedHashRocketStyle: table
48
+ EnforcedColonStyle: table
49
+
50
+ Layout/SpaceBeforeBrackets: # (new in 1.7)
51
+ Enabled: true
52
+ Lint/AmbiguousAssignment: # (new in 1.7)
53
+ Enabled: true
54
+ Lint/DeprecatedConstants: # (new in 1.8)
55
+ Enabled: true
56
+ Lint/DuplicateBranch: # (new in 1.3)
57
+ Enabled: true
58
+ Lint/DuplicateRegexpCharacterClassElement: # (new in 1.1)
59
+ Enabled: true
60
+ Lint/EmptyBlock: # (new in 1.1)
61
+ Enabled: true
62
+ Lint/EmptyClass: # (new in 1.3)
63
+ Enabled: true
64
+ Lint/LambdaWithoutLiteralBlock: # (new in 1.8)
65
+ Enabled: true
66
+ Lint/NoReturnInBeginEndBlocks: # (new in 1.2)
67
+ Enabled: true
68
+ Lint/RedundantDirGlobSort: # (new in 1.8)
69
+ Enabled: true
70
+ Lint/ToEnumArguments: # (new in 1.1)
71
+ Enabled: true
72
+ Lint/UnexpectedBlockArity: # (new in 1.5)
73
+ Enabled: true
74
+ Lint/UnmodifiedReduceAccumulator: # (new in 1.1)
75
+ Enabled: true
@@ -0,0 +1,10 @@
1
+ # Offense count: 1
2
+ Lint/MissingSuper:
3
+ Exclude:
4
+ - 'lib/afterbanks_psd2/collection.rb'
5
+
6
+ # Offense count: 2
7
+ Security/MarshalLoad:
8
+ Exclude:
9
+ - 'spec/afterbanks_psd2/resources/bank_spec.rb'
10
+ - 'spec/afterbanks_psd2/resources/user_spec.rb'
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in afterbanks.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,90 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ afterbanks-psd2-api-ruby (0.1.0)
5
+ rest-client (~> 2.0.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ addressable (2.7.0)
11
+ public_suffix (>= 2.0.2, < 5.0)
12
+ ast (2.4.1)
13
+ crack (0.4.3)
14
+ safe_yaml (~> 1.0.0)
15
+ diff-lcs (1.3)
16
+ domain_name (0.5.20190701)
17
+ unf (>= 0.0.5, < 1.0.0)
18
+ hashdiff (1.0.1)
19
+ http-cookie (1.0.3)
20
+ domain_name (~> 0.5)
21
+ mime-types (3.3.1)
22
+ mime-types-data (~> 3.2015)
23
+ mime-types-data (3.2020.1104)
24
+ netrc (0.11.0)
25
+ parallel (1.19.1)
26
+ parser (3.0.0.0)
27
+ ast (~> 2.4.1)
28
+ public_suffix (4.0.5)
29
+ rainbow (3.0.0)
30
+ rake (13.0.3)
31
+ regexp_parser (2.0.3)
32
+ rest-client (2.0.2)
33
+ http-cookie (>= 1.0.2, < 2.0)
34
+ mime-types (>= 1.16, < 4.0)
35
+ netrc (~> 0.8)
36
+ rexml (3.1.9)
37
+ rspec (3.7.0)
38
+ rspec-core (~> 3.7.0)
39
+ rspec-expectations (~> 3.7.0)
40
+ rspec-mocks (~> 3.7.0)
41
+ rspec-core (3.7.0)
42
+ rspec-support (~> 3.7.0)
43
+ rspec-expectations (3.7.0)
44
+ diff-lcs (>= 1.2.0, < 2.0)
45
+ rspec-support (~> 3.7.0)
46
+ rspec-mocks (3.7.0)
47
+ diff-lcs (>= 1.2.0, < 2.0)
48
+ rspec-support (~> 3.7.0)
49
+ rspec-support (3.7.0)
50
+ rubocop (1.8.1)
51
+ parallel (~> 1.10)
52
+ parser (>= 3.0.0.0)
53
+ rainbow (>= 2.2.2, < 4.0)
54
+ regexp_parser (>= 1.8, < 3.0)
55
+ rexml
56
+ rubocop-ast (>= 1.2.0, < 2.0)
57
+ ruby-progressbar (~> 1.7)
58
+ unicode-display_width (>= 1.4.0, < 3.0)
59
+ rubocop-ast (1.4.0)
60
+ parser (>= 2.7.1.5)
61
+ rubocop-rspec (2.1.0)
62
+ rubocop (~> 1.0)
63
+ rubocop-ast (>= 1.1.0)
64
+ ruby-progressbar (1.10.1)
65
+ safe_yaml (1.0.5)
66
+ timecop (0.9.2)
67
+ unf (0.1.4)
68
+ unf_ext
69
+ unf_ext (0.0.7.7)
70
+ unicode-display_width (1.6.0)
71
+ webmock (3.8.3)
72
+ addressable (>= 2.3.6)
73
+ crack (>= 0.3.2)
74
+ hashdiff (>= 0.4.0, < 2.0.0)
75
+
76
+ PLATFORMS
77
+ ruby
78
+
79
+ DEPENDENCIES
80
+ afterbanks-psd2-api-ruby!
81
+ bundler
82
+ rake
83
+ rspec
84
+ rubocop
85
+ rubocop-rspec
86
+ timecop
87
+ webmock
88
+
89
+ BUNDLED WITH
90
+ 2.1.4
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # Ruby client for the Afterbanks PSD2 API
2
+
3
+ [![CircleCI](https://circleci.com/gh/quipuapp/afterbanks-psd2-api-ruby.svg?style=shield)](https://circleci.com/gh/quipuapp/afterbanks-psd2-api-ruby)
4
+
5
+ This is a Ruby client for the Afterbanks' PSD2 API
6
+
7
+ Installation
8
+ ---------
9
+
10
+ Install the gem (`gem install afterbanks-psd2-api-ruby`) or include it in your Gemfile and `bundle`.
11
+
12
+ Configuration
13
+ ---------
14
+
15
+ Just set the service key by doing this:
16
+
17
+ ```ruby
18
+ AfterbanksPSD2.servicekey = 'yourservicekey'
19
+ ```
20
+
21
+ Or, if you use it in a Rails application, create an initializer with this content:
22
+
23
+ ```ruby
24
+ require 'afterbanks_psd2'
25
+
26
+ AfterbanksPSD2.configure do |config|
27
+ config.servicekey = 'yourservicekey'
28
+ end
29
+ ```
30
+
31
+ You can set a `logger` as well.
32
+
33
+ Changelog
34
+ ---------
35
+
36
+ * 0.1.0 First full version, including resource wrapping (banks, user, accounts, transactions), error coverage and support for logging
37
+
38
+ TODO
39
+ ----
40
+
41
+ * Full usage for each resource
42
+ * Proper explanation of the `AfterbanksPSD2:Error` and its subclasses
43
+
44
+ List of Error
45
+ ------------
46
+
47
+ * `1` -> GenericError
48
+ * `50` -> IncorrectParametersError (When call API)
49
+ * `C000` -> GenericConsentError
50
+ * `C001` -> InvalidConsentError
51
+ * `C002` -> ConsentWithUnfinalizedProcessError
52
+ * `C003` -> ProductMismatchConsentError
53
+ * `C004` -> ExpiredConsentError
54
+ * `C005` -> MaximumNumberOfCallsReachedConsentError
55
+ * `T000` -> GenericTransactionError
56
+ * `T001` -> InvalidConsentForProductError
57
+
58
+
59
+
60
+ About Afterbanks
61
+ ------------
62
+
63
+ * [Public site](https://www.afterbanks.com)
64
+ * [Documentation](https://app.swaggerhub.com/apis/Afterbanks/Afterbanks-PSD2-ES)
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'afterbanks_psd2/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'afterbanks-psd2-api-ruby'
9
+ spec.version = AfterbanksPSD2::VERSION
10
+ spec.authors = ['Florent Lemaitre']
11
+ spec.email = ['flemaitre@sellsy.com']
12
+
13
+ spec.summary = "Ruby client for the Afterbanks' PSD2 API"
14
+ spec.homepage = 'https://getquipu.com'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_dependency 'rest-client', '~> 2.0.2'
24
+
25
+ spec.add_development_dependency 'bundler'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'rspec'
28
+ spec.add_development_dependency 'rubocop'
29
+ spec.add_development_dependency 'rubocop-rspec'
30
+ spec.add_development_dependency 'timecop'
31
+ spec.add_development_dependency 'webmock'
32
+ end
@@ -0,0 +1,133 @@
1
+ require 'rest-client'
2
+ require 'json'
3
+
4
+ module AfterbanksPSD2
5
+ class << self
6
+ def configuration
7
+ @configuration ||= Configuration.new
8
+ end
9
+
10
+ def configure
11
+ yield(configuration)
12
+ end
13
+
14
+ def api_call(method:, path:, params: {}, options: {})
15
+ api_url = ENV['AFTERBANKS_API_URL'] || 'https://apipsd2.afterbanks.com'
16
+ url = api_url + path
17
+
18
+ request_params = { method: method, url: url }
19
+
20
+ if options[:timeout]
21
+ request_params.merge!(timeout: options[:timeout])
22
+ end
23
+
24
+ if method == :post
25
+ request_params.merge!(payload: params)
26
+ else
27
+ request_params.merge!(headers: { params: params })
28
+ end
29
+
30
+ response = begin
31
+ RestClient::Request.execute(**request_params)
32
+ rescue RestClient::BadRequest, RestClient::ExpectationFailed => bad_request
33
+ # Check
34
+ bad_request.response
35
+ rescue RestClient::Exceptions::ReadTimeout
36
+ log_request(
37
+ method: method,
38
+ url: url,
39
+ params: params
40
+ )
41
+
42
+ raise
43
+ end
44
+
45
+ debug_id = response.headers[:debug_id]
46
+
47
+ log_request(
48
+ method: method,
49
+ url: url,
50
+ params: params,
51
+ debug_id: debug_id
52
+ )
53
+
54
+ response_body = JSON.parse(response.body)
55
+
56
+ treat_errors_if_any(
57
+ response_body: response_body,
58
+ debug_id: debug_id
59
+ )
60
+
61
+ [response_body, debug_id]
62
+ end
63
+
64
+ def log_request(method:, url:, params: {}, debug_id: nil)
65
+ logger = AfterbanksPSD2.configuration.logger
66
+ return if logger.nil?
67
+
68
+ now = Time.now
69
+
70
+ safe_params = {}
71
+ params.each do |key, value|
72
+ safe_value = if %w{servicekey}.include?(key.to_s)
73
+ "<masked>"
74
+ else
75
+ value
76
+ end
77
+
78
+ safe_value = safe_value.to_s if safe_value.is_a?(Symbol)
79
+
80
+ safe_params[key] = safe_value
81
+ end
82
+
83
+ logger.info(
84
+ message: 'Afterbanks PSD2 request',
85
+ method: method.upcase.to_s,
86
+ url: url,
87
+ time: now.to_s,
88
+ timestamp: now.to_i,
89
+ debug_id: debug_id || 'none',
90
+ params: safe_params
91
+ )
92
+ end
93
+
94
+ def treat_errors_if_any(response_body:, debug_id:)
95
+ return unless response_body.is_a?(Hash)
96
+
97
+ code = response_body['code']
98
+ integer_code = code.to_i
99
+ if integer_code.to_s == code
100
+ code = integer_code
101
+ end
102
+
103
+ message = response_body['message']
104
+
105
+ error_info = { message: message, debug_id: debug_id }
106
+
107
+ case code
108
+ when 1
109
+ raise GenericError.new(**error_info)
110
+ when 50
111
+ raise IncorrectParametersError.new(**error_info)
112
+ when 'C000'
113
+ raise GenericConsentError.new(**error_info)
114
+ when 'C001'
115
+ raise InvalidConsentError.new(**error_info)
116
+ when 'C002'
117
+ raise ConsentWithUnfinalizedProcessError.new(**error_info)
118
+ when 'C003'
119
+ raise ProductMismatchConsentError.new(**error_info)
120
+ when 'C004'
121
+ raise ExpiredConsentError.new(**error_info)
122
+ when 'C005'
123
+ raise MaximumNumberOfCallsReachedConsentError.new(**error_info)
124
+ when 'T000'
125
+ raise GenericTransactionError.new(**error_info)
126
+ when 'T001'
127
+ raise InvalidConsentForProductError.new(**error_info)
128
+ end
129
+
130
+ nil
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,9 @@
1
+ module AfterbanksPSD2
2
+ class Collection < Array
3
+ def initialize(response, item_klass)
4
+ response.each do |item|
5
+ self << item_klass.new(item)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module AfterbanksPSD2
2
+ class Configuration
3
+ attr_accessor :servicekey, :logger
4
+ end
5
+ end
@@ -0,0 +1,76 @@
1
+ module AfterbanksPSD2
2
+ class Error < ::StandardError
3
+ attr_reader :message, :debug_id
4
+
5
+ def initialize(message:, debug_id:)
6
+ super
7
+
8
+ @message = message
9
+ @debug_id = debug_id
10
+ end
11
+
12
+ def code
13
+ raise 'Not implemented'
14
+ end
15
+ end
16
+
17
+ class GenericError < Error
18
+ def code
19
+ 1
20
+ end
21
+ end
22
+
23
+ class IncorrectParametersError < Error
24
+ def code
25
+ 50
26
+ end
27
+ end
28
+
29
+ class GenericConsentError < Error
30
+ def code
31
+ 'C000'
32
+ end
33
+ end
34
+
35
+ class InvalidConsentError < Error
36
+ def code
37
+ 'C001'
38
+ end
39
+ end
40
+
41
+ class ConsentWithUnfinalizedProcessError < Error
42
+ def code
43
+ 'C002'
44
+ end
45
+ end
46
+
47
+ class ProductMismatchConsentError < Error
48
+ def code
49
+ 'C003'
50
+ end
51
+ end
52
+
53
+ class ExpiredConsentError < Error
54
+ def code
55
+ 'C004'
56
+ end
57
+ end
58
+
59
+ class MaximumNumberOfCallsReachedConsentError < Error
60
+ def code
61
+ 'C005'
62
+ end
63
+ end
64
+
65
+ class GenericTransactionError < Error
66
+ def code
67
+ 'T000'
68
+ end
69
+ end
70
+
71
+ class InvalidConsentForProductError < Error
72
+ def code
73
+ 'T001'
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,89 @@
1
+ module AfterbanksPSD2
2
+ class Resource
3
+ def initialize(data)
4
+ data = sanitize_data(data)
5
+ generate_attr_readers
6
+ set_data(data)
7
+ end
8
+
9
+ def fields_information
10
+ self.class.fields_information
11
+ end
12
+
13
+ private
14
+
15
+ def sanitize_data(data)
16
+ data.reduce({}) do |hash, (key, value)|
17
+ hash[key.to_sym] = value
18
+
19
+ hash
20
+ end
21
+ end
22
+
23
+ def generate_attr_readers
24
+ fields_information.each do |field, _|
25
+ define_singleton_method(field) do
26
+ instance_variable_get("@#{field}")
27
+ end
28
+ end
29
+ end
30
+
31
+ def set_data(data)
32
+ fields_information.each do |official_name, field_information|
33
+ raw_value = nil
34
+
35
+ if (original_name = field_information[:original_name])
36
+ raw_value = data[original_name]
37
+ end
38
+
39
+ raw_value ||= data[official_name]
40
+
41
+ next if raw_value.nil?
42
+
43
+ type = field_information[:type]
44
+ value = value_for(raw_value, type)
45
+
46
+ instance_variable_set("@#{official_name}", value)
47
+ end
48
+ end
49
+
50
+ def value_for(raw_value, type)
51
+ case type
52
+ when :boolean
53
+ [true, "1", 1].include?(raw_value)
54
+ when :date
55
+ if raw_value.is_a?(Date)
56
+ raw_value
57
+ else
58
+ Date.parse(raw_value)
59
+ end
60
+ else
61
+ raw_value
62
+ end
63
+ end
64
+
65
+ def marshal_dump
66
+ dump = {}
67
+
68
+ fields_information.each do |field, _|
69
+ dump[field] = send(field)
70
+ end
71
+
72
+ dump
73
+ end
74
+
75
+ def marshal_load(serialized_resource)
76
+ initialize(serialized_resource)
77
+ end
78
+
79
+ class << self
80
+ def fields_information
81
+ @fields_information
82
+ end
83
+
84
+ def has_fields(fields_information)
85
+ @fields_information = fields_information
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,37 @@
1
+ module AfterbanksPSD2
2
+ class Account < Resource
3
+ has_fields product: { type: :string },
4
+ type: { type: :string },
5
+ balance: { type: :decimal },
6
+ countable_balance: { type: :decimal },
7
+ arranged_balance: { type: :decimal },
8
+ currency: { type: :string },
9
+ description: { type: :string },
10
+ iban: { type: :string },
11
+ is_owner: { type: :boolean },
12
+ holders: { type: :hash }
13
+
14
+ def self.list(token:)
15
+ params = {
16
+ servicekey: AfterbanksPSD2.configuration.servicekey,
17
+ token: token,
18
+ products: 'GLOBAL'
19
+ }
20
+
21
+ response, debug_id = AfterbanksPSD2.api_call(
22
+ method: :post,
23
+ path: '/transactions/',
24
+ params: params
25
+ )
26
+
27
+ Response.new(
28
+ result: Collection.new(
29
+ response,
30
+ self
31
+ ),
32
+ body: response,
33
+ debug_id: debug_id
34
+ )
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,73 @@
1
+ module AfterbanksPSD2
2
+ class Bank < Resource
3
+ has_fields country_code: { type: :string, original_name: :countryCode },
4
+ service: { type: :string },
5
+ swift: { type: :string },
6
+ fullname: { type: :string },
7
+ image: { type: :string },
8
+ image_svg: { type: :string, original_name: :imageSVG },
9
+ payments_supported: { type: :boolean, original_name: :paymentsSupported }
10
+
11
+ def self.list(ordered: false, country_codes: nil)
12
+ response, debug_id = AfterbanksPSD2.api_call(
13
+ method: :get,
14
+ path: '/listOfSupportedBanks/'
15
+ )
16
+
17
+ Response.new(
18
+ result: Collection.new(
19
+ banks_information_for(
20
+ response: response,
21
+ ordered: ordered,
22
+ country_codes: country_codes
23
+ ),
24
+ self
25
+ ),
26
+ body: response,
27
+ debug_id: debug_id
28
+ )
29
+ end
30
+
31
+ def self.banks_information_for(response:, ordered:, country_codes:)
32
+ country_codes = country_codes.map(&:upcase) unless country_codes.nil?
33
+ banks_information = []
34
+
35
+ response.each do |bank_information|
36
+ next if country_codes && !country_codes.include?(bank_information['countryCode'])
37
+
38
+ bank_information['fullname'] = bank_name_for(bank_information: bank_information)
39
+
40
+ banks_information << bank_information
41
+ end
42
+
43
+ if ordered
44
+ banks_information.sort! do |bank_information1, bank_information2|
45
+ bank_information1['fullname'].downcase <=> bank_information2['fullname'].downcase
46
+ end
47
+ end
48
+
49
+ banks_information
50
+ end
51
+
52
+ def self.bank_name_for(bank_information:)
53
+ service = bank_information['service']
54
+
55
+ # Name changes:
56
+
57
+ # 1. Rename Caja Ingenieros into Caixa d'Enginyers (most known name)
58
+ return "Caixa d'Enginyers" if service == 'cajaingenieros'
59
+
60
+ # 2. Rename Caixa Guisona into Caixa Guissona (fix typo)
61
+ return "Caixa Guissona" if service == 'caixaguissona'
62
+
63
+ # 3. Rename Caixa burriana into Caixa Burriana (fix typo)
64
+ return "Caixa Burriana" if service == 'caixaruralburriana'
65
+
66
+ bank_information['fullname']
67
+ end
68
+
69
+ def self.bank_id_for(bank_information:)
70
+ bank_information['service'].split("_").first
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,71 @@
1
+ module AfterbanksPSD2
2
+ class Transaction < Resource
3
+ has_fields date: { type: :date },
4
+ date2: { type: :date },
5
+ amount: { type: :decimal },
6
+ description: { type: :string },
7
+ balance: { type: :decimal },
8
+ transaction_id: { type: :string, original_name: :transactionId },
9
+ category_id: { type: :integer, original_name: :categoryId },
10
+ account: { type: :afterbankspsd2_account }
11
+
12
+ def self.list(token:, products:, start_date:)
13
+ params = {
14
+ servicekey: AfterbanksPSD2.configuration.servicekey,
15
+ token: token,
16
+ products: products,
17
+ startDate: start_date.strftime("%d-%m-%Y")
18
+ }
19
+
20
+ # if the start_date is older than 90 days, we need to increase timeout to 2 hours
21
+ if start_date < Date.today << 3
22
+ options = {
23
+ timeout: 7200
24
+ }
25
+ end
26
+
27
+ response, debug_id = AfterbanksPSD2.api_call(
28
+ method: :post,
29
+ path: '/transactions/',
30
+ params: params,
31
+ options: options
32
+ )
33
+
34
+ Response.new(
35
+ result: Collection.new(
36
+ transactions_information_for(
37
+ response: response,
38
+ products: products
39
+ ),
40
+ self
41
+ ),
42
+ body: response,
43
+ debug_id: debug_id
44
+ )
45
+ end
46
+
47
+ def self.transactions_information_for(response:, products:)
48
+ transactions_information = []
49
+ products_array = products.split(",")
50
+
51
+ response.each do |account_information|
52
+ product = account_information['product']
53
+
54
+ next unless products_array.include?(product)
55
+
56
+ transactions = account_information['transactions']
57
+ next if transactions.nil? || transactions.empty?
58
+
59
+ account = AfterbanksPSD2::Account.new(account_information)
60
+
61
+ transactions.each do |transaction|
62
+ transaction['account'] = account
63
+ end
64
+
65
+ transactions_information += transactions
66
+ end
67
+
68
+ transactions_information
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,25 @@
1
+ module AfterbanksPSD2
2
+ class User < Resource
3
+ has_fields limit: { type: :integer },
4
+ counter: { type: :integer },
5
+ remaining_calls: { type: :integer },
6
+ date_renewal: { type: :date },
7
+ detail: { type: :string }
8
+
9
+ def self.get
10
+ response, debug_id = AfterbanksPSD2.api_call(
11
+ method: :post,
12
+ path: '/me/',
13
+ params: {
14
+ servicekey: AfterbanksPSD2.configuration.servicekey
15
+ }
16
+ )
17
+
18
+ Response.new(
19
+ result: new(response),
20
+ body: response,
21
+ debug_id: debug_id
22
+ )
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ module AfterbanksPSD2
2
+ class Response
3
+ attr_accessor :result, :body, :debug_id
4
+
5
+ def initialize(result:, body:, debug_id:)
6
+ @result = result
7
+ @body = body
8
+ @debug_id = debug_id
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module AfterbanksPSD2
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,12 @@
1
+ require 'afterbanks_psd2/version'
2
+ require 'afterbanks_psd2/configuration'
3
+ require 'afterbanks_psd2/base'
4
+ require 'afterbanks_psd2/error'
5
+ require 'afterbanks_psd2/resource'
6
+ require 'afterbanks_psd2/response'
7
+ require 'afterbanks_psd2/collection'
8
+
9
+ require 'afterbanks_psd2/resources/bank'
10
+ require 'afterbanks_psd2/resources/user'
11
+ require 'afterbanks_psd2/resources/account'
12
+ require 'afterbanks_psd2/resources/transaction'
metadata ADDED
@@ -0,0 +1,176 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: afterbanks-psd2-api-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Florent Lemaitre
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-10-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
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: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: timecop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: webmock
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description:
126
+ email:
127
+ - flemaitre@sellsy.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".circleci/config.yml"
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".rubocop.yml"
136
+ - ".rubocop_exclusions.yml"
137
+ - Gemfile
138
+ - Gemfile.lock
139
+ - README.md
140
+ - Rakefile
141
+ - afterbanks_psd2.gemspec
142
+ - lib/afterbanks_psd2.rb
143
+ - lib/afterbanks_psd2/base.rb
144
+ - lib/afterbanks_psd2/collection.rb
145
+ - lib/afterbanks_psd2/configuration.rb
146
+ - lib/afterbanks_psd2/error.rb
147
+ - lib/afterbanks_psd2/resource.rb
148
+ - lib/afterbanks_psd2/resources/account.rb
149
+ - lib/afterbanks_psd2/resources/bank.rb
150
+ - lib/afterbanks_psd2/resources/transaction.rb
151
+ - lib/afterbanks_psd2/resources/user.rb
152
+ - lib/afterbanks_psd2/response.rb
153
+ - lib/afterbanks_psd2/version.rb
154
+ homepage: https://getquipu.com
155
+ licenses: []
156
+ metadata: {}
157
+ post_install_message:
158
+ rdoc_options: []
159
+ require_paths:
160
+ - lib
161
+ required_ruby_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ requirements: []
172
+ rubygems_version: 3.2.33
173
+ signing_key:
174
+ specification_version: 4
175
+ summary: Ruby client for the Afterbanks' PSD2 API
176
+ test_files: []