investec_open_api 1.1.1 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2dd0d8bf1f96bd2938b03a10a769c4a133756250d2241339d0c852f40e0af16b
4
- data.tar.gz: 04fbd85515e99a1cf8f4bd016ad1d9f32eb69e1c5e49bb74a510d3e4db81183a
3
+ metadata.gz: b63be4cb913b87e7b56c0a1ba3eab66a09b853991d09bec6c42eb9ba6e0a091e
4
+ data.tar.gz: e61aa2281d0ddf0dfc48e9f3782dab1999ce69b48ae137a833648ce1f5ac350d
5
5
  SHA512:
6
- metadata.gz: 00a186874f8951b24da32ad631b354c72a3f8dba0a50b660d1307d258596b3aeb1e116e29a77775f20b5db6f861c6f4dcb55c4cb6dff8727b25ab72ac117f314
7
- data.tar.gz: 859a6740f4d34260b0d026cb4d8ee3f647722cdcd714885fb0c60f90ebc6872b03a70dde2233f3e761586d5e811d9d6c2c172e6ce3e94658ee3add71dae522c2
6
+ metadata.gz: ef318fa461e96b6fd1bb3f3421f833ad8104e82efc8f457c8c364c99bf14ba0c5409e4dd4d19d77d87ae74da19d50380781259723c669be319ffe5a3670f28dd
7
+ data.tar.gz: 88f1874026696d1cfc9f2af7f6d37329d3f8a40599fb72ef66109fb3a7bffe5e1ff5f814bf782e920b76194a5da501d4fbcb7ca99580615f17c8d929c5b880fb
data/.gitignore CHANGED
@@ -6,6 +6,9 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /.idea/
9
10
 
10
11
  # rspec failure tracking
11
12
  .rspec_status
13
+ .env
14
+ investec_open_api*.gem
data/CODE_OF_CONDUCT.md CHANGED
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
55
55
  ## Enforcement
56
56
 
57
57
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at mkk0856@gmail.com. All
58
+ reported by contacting the project team at community@make.dev. All
59
59
  complaints will be reviewed and investigated and will result in a response that
60
60
  is deemed necessary and appropriate to the circumstances. The project team is
61
61
  obligated to maintain confidentiality with regard to the reporter of an incident.
data/Gemfile CHANGED
@@ -4,3 +4,5 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  gem 'pry'
7
+
8
+ gem "faker", "~> 3.4"
data/Gemfile.lock CHANGED
@@ -1,129 +1,66 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- investec_open_api (1.1.1)
5
- active_attr
4
+ investec_open_api (2.1.0)
6
5
  faraday
7
- faraday_middleware
8
6
  money
9
7
 
10
8
  GEM
11
9
  remote: https://rubygems.org/
12
10
  specs:
13
- actionpack (7.0.4.3)
14
- actionview (= 7.0.4.3)
15
- activesupport (= 7.0.4.3)
16
- rack (~> 2.0, >= 2.2.0)
17
- rack-test (>= 0.6.3)
18
- rails-dom-testing (~> 2.0)
19
- rails-html-sanitizer (~> 1.0, >= 1.2.0)
20
- actionview (7.0.4.3)
21
- activesupport (= 7.0.4.3)
22
- builder (~> 3.1)
23
- erubi (~> 1.4)
24
- rails-dom-testing (~> 2.0)
25
- rails-html-sanitizer (~> 1.1, >= 1.2.0)
26
- active_attr (0.15.4)
27
- actionpack (>= 3.0.2, < 7.1)
28
- activemodel (>= 3.0.2, < 7.1)
29
- activesupport (>= 3.0.2, < 7.1)
30
- activemodel (7.0.4.3)
31
- activesupport (= 7.0.4.3)
32
- activesupport (7.0.4.3)
33
- concurrent-ruby (~> 1.0, >= 1.0.2)
34
- i18n (>= 1.6, < 2)
35
- minitest (>= 5.1)
36
- tzinfo (~> 2.0)
37
- addressable (2.8.4)
11
+ addressable (2.8.6)
38
12
  public_suffix (>= 2.0.2, < 6.0)
39
- builder (3.2.4)
13
+ bigdecimal (3.1.7)
40
14
  coderay (1.1.3)
41
- concurrent-ruby (1.2.2)
42
- crack (0.4.5)
15
+ concurrent-ruby (1.2.3)
16
+ crack (1.0.0)
17
+ bigdecimal
43
18
  rexml
44
- crass (1.0.6)
45
- diff-lcs (1.4.4)
46
- erubi (1.12.0)
47
- faraday (1.10.3)
48
- faraday-em_http (~> 1.0)
49
- faraday-em_synchrony (~> 1.0)
50
- faraday-excon (~> 1.1)
51
- faraday-httpclient (~> 1.0)
52
- faraday-multipart (~> 1.0)
53
- faraday-net_http (~> 1.0)
54
- faraday-net_http_persistent (~> 1.0)
55
- faraday-patron (~> 1.0)
56
- faraday-rack (~> 1.0)
57
- faraday-retry (~> 1.0)
58
- ruby2_keywords (>= 0.0.4)
59
- faraday-em_http (1.0.0)
60
- faraday-em_synchrony (1.0.0)
61
- faraday-excon (1.1.0)
62
- faraday-httpclient (1.0.1)
63
- faraday-multipart (1.0.4)
64
- multipart-post (~> 2)
65
- faraday-net_http (1.0.1)
66
- faraday-net_http_persistent (1.2.0)
67
- faraday-patron (1.0.0)
68
- faraday-rack (1.0.0)
69
- faraday-retry (1.0.3)
70
- faraday_middleware (1.2.0)
71
- faraday (~> 1.0)
72
- hashdiff (1.0.1)
73
- i18n (1.13.0)
19
+ diff-lcs (1.5.1)
20
+ faker (3.4.2)
21
+ i18n (>= 1.8.11, < 2)
22
+ faraday (2.9.0)
23
+ faraday-net_http (>= 2.0, < 3.2)
24
+ faraday-net_http (3.1.0)
25
+ net-http
26
+ hashdiff (1.1.0)
27
+ i18n (1.14.4)
74
28
  concurrent-ruby (~> 1.0)
75
- loofah (2.20.0)
76
- crass (~> 1.0.2)
77
- nokogiri (>= 1.5.9)
78
29
  method_source (1.0.0)
79
- mini_portile2 (2.8.2)
80
- minitest (5.18.0)
81
- money (6.16.0)
30
+ money (6.19.0)
82
31
  i18n (>= 0.6.4, <= 2)
83
- multipart-post (2.3.0)
84
- nokogiri (1.14.3)
85
- mini_portile2 (~> 2.8.0)
86
- racc (~> 1.4)
32
+ net-http (0.4.1)
33
+ uri
87
34
  pry (0.14.2)
88
35
  coderay (~> 1.1)
89
36
  method_source (~> 1.0)
90
- public_suffix (5.0.1)
91
- racc (1.6.2)
92
- rack (2.2.7)
93
- rack-test (2.1.0)
94
- rack (>= 1.3)
95
- rails-dom-testing (2.0.3)
96
- activesupport (>= 4.2.0)
97
- nokogiri (>= 1.6)
98
- rails-html-sanitizer (1.5.0)
99
- loofah (~> 2.19, >= 2.19.1)
100
- rake (12.3.3)
101
- rexml (3.2.5)
102
- rspec (3.9.0)
103
- rspec-core (~> 3.9.0)
104
- rspec-expectations (~> 3.9.0)
105
- rspec-mocks (~> 3.9.0)
106
- rspec-core (3.9.2)
107
- rspec-support (~> 3.9.3)
108
- rspec-expectations (3.9.2)
37
+ public_suffix (5.0.5)
38
+ rake (13.2.1)
39
+ rexml (3.2.6)
40
+ rspec (3.13.0)
41
+ rspec-core (~> 3.13.0)
42
+ rspec-expectations (~> 3.13.0)
43
+ rspec-mocks (~> 3.13.0)
44
+ rspec-core (3.13.0)
45
+ rspec-support (~> 3.13.0)
46
+ rspec-expectations (3.13.0)
109
47
  diff-lcs (>= 1.2.0, < 2.0)
110
- rspec-support (~> 3.9.0)
111
- rspec-mocks (3.9.1)
48
+ rspec-support (~> 3.13.0)
49
+ rspec-mocks (3.13.0)
112
50
  diff-lcs (>= 1.2.0, < 2.0)
113
- rspec-support (~> 3.9.0)
114
- rspec-support (3.9.3)
115
- ruby2_keywords (0.0.5)
116
- tzinfo (2.0.6)
117
- concurrent-ruby (~> 1.0)
118
- webmock (3.18.1)
51
+ rspec-support (~> 3.13.0)
52
+ rspec-support (3.13.1)
53
+ uri (0.13.0)
54
+ webmock (3.23.0)
119
55
  addressable (>= 2.8.0)
120
56
  crack (>= 0.3.2)
121
57
  hashdiff (>= 0.4.0, < 2.0.0)
122
58
 
123
59
  PLATFORMS
124
- ruby
60
+ arm64-darwin-23
125
61
 
126
62
  DEPENDENCIES
63
+ faker (~> 3.4)
127
64
  investec_open_api!
128
65
  pry
129
66
  rake
data/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 🌟 Community-Powered Repository 🌟
2
+
3
+ This repository is crafted with ❤️ by our talented community members. It's a space for everyone to use, contribute to, and share. While it aligns with the spirit of our community, please note that this repo is not directly endorsed or supported by Investec. Always exercise caution and discretion when using or contributing to community-driven projects.
4
+
1
5
  # InvestecOpenApi Client
2
6
 
3
7
  [![Gem Version](https://badge.fury.io/rb/investec_open_api.svg)](https://badge.fury.io/rb/investec_open_api)
@@ -9,6 +13,8 @@ A simple client wrapper for the [Investec Open API](https://developer.investec.c
9
13
  - Authorize access via OAuth
10
14
  - Retrieve accounts
11
15
  - Retrieve transactions per account
16
+ - Retrieve balances per account
17
+ - Transfer between accounts
12
18
 
13
19
  ## Installation
14
20
 
@@ -30,26 +36,32 @@ Or install it yourself as:
30
36
  $ gem install investec_open_api
31
37
  ```
32
38
 
33
- Create a new initializer called `investec_open_api.rb` in `config/initializers`:
39
+ ## Configuration
40
+
41
+ To configure the client, create a new file in the root of your directory called `.env` and place the following:
42
+
43
+ ```dotenv
44
+ API_KEY='YOUR API KEY'
45
+ CLIENT_ID='YOUR CLIENT ID'
46
+ CLIENT_SECRET='YOUR CLIENT SECRET'
47
+ ```
48
+
49
+ > **Note:** you will need to register to get the above credentials.
50
+ > Follow the steps in [Enrolment in the documentation](https://developer.investec.com/programmable-banking/#enrolment).
51
+ > You can also test in sandbox mode (see [Running in Sandbox Mode](#running-in-sandbox-mode)).
52
+
53
+ Once you have set this up, configure the client using:
34
54
 
35
55
  ```ruby
36
56
  InvestecOpenApi.configuration do |config|
37
57
  config.api_key = ENV['API_KEY']
38
58
  config.client_id = ENV['CLIENT_ID']
39
59
  config.client_secret = ENV['CLIENT_SECRET']
60
+ config.base_url = ENV['BASE_URL'] # optional
40
61
  end
41
62
  ```
42
63
 
43
- Create a new file in the root of your directory called `.env` and place the following:
44
-
45
- ```
46
- API_KEY='YOUR API KEY'
47
- CLIENT_ID='YOUR CLIENT ID'
48
- CLIENT_SECRET='YOUR CLIENT SECRET'
49
- ```
50
-
51
- You will need to register to get the following credentials. Follow the steps in [Enrolment in the documentation](https://developer.investec.com/programmable-banking/#enrolment).
52
-
64
+ For Rails apps, create a new initializer called `investec_open_api.rb` in `config/initializers`:
53
65
 
54
66
  ## Usage
55
67
 
@@ -60,19 +72,72 @@ client = InvestecOpenApi::Client.new
60
72
  client.authenticate!
61
73
  ```
62
74
 
63
- Once authenticated you can retrieve your accounts:
75
+ ### Accounts
76
+
77
+ Calling `accounts` returns all of the associated accounts:
64
78
 
65
79
  ```ruby
66
80
  accounts = client.accounts
67
81
  my_account = accounts.first
68
82
  ```
69
83
 
70
- Use the ID of one of your accounts to retrieve transactions:
84
+ ### List transactions for an account
85
+
86
+ You can list your transactions by passing the account id into the `transactions` method:
87
+
88
+ ```ruby
89
+ # The dates are optional
90
+ client.transactions(my_account.id, { fromDate: "2024-01-01", toDate: "2024-01-31" })
91
+ ```
92
+
93
+ To list pending transactions use the following:
71
94
 
72
95
  ```ruby
73
- client.transactions(my_account.id)
96
+ # The dates are optional
97
+ client.pending_transactions(my_account.id, { fromDate: "2024-01-01", toDate: "2024-01-31" })
74
98
  ```
75
99
 
100
+ ### Get Balance for an account
101
+
102
+ Pass the `account_id` into the `balance` method to get the latest account balances:
103
+
104
+ ```ruby
105
+ client.balance(my_account.id)
106
+ ```
107
+
108
+ ### Inter-account transfers
109
+
110
+ To transfer between accounts, create a `InvestecOpenApi::Models::Transfer` object and pass it into the `transfer_multiple` method:
111
+
112
+ ```ruby
113
+ transfer = InvestecOpenApi::Models::Transfer.new(
114
+ beneficiary_account_id,
115
+ 1000.00, # amount as a Float
116
+ "My reference - of the account transferring from",
117
+ "Their reference - of the account transferring to"
118
+ )
119
+ client.transfer_multiple(
120
+ my_account.id,
121
+ [ transfer ],
122
+ profile_id # optional
123
+ )
124
+ ```
125
+
126
+ ## Running in Sandbox mode
127
+
128
+ To run in sandbox mode, use the following configuration:
129
+
130
+ ```ruby
131
+ InvestecOpenApi.configuration do |config|
132
+ config.api_key = "eUF4elFSRlg5N3ZPY3lRQXdsdUVVNkg2ZVB4TUE1ZVk6YVc1MlpYTjBaV010ZW1FdGNHSXRZV05qYjNWdWRITXRjMkZ1WkdKdmVBPT0="
133
+ config.client_id = "yAxzQRFX97vOcyQAwluEU6H6ePxMA5eY"
134
+ config.client_secret = "4dY0PjEYqoBrZ99r"
135
+ config.base_url = "https://openapisandbox.investec.com/"
136
+ end
137
+ ```
138
+
139
+ You can now test the API without affecting your actual account.
140
+
76
141
  ## License
77
142
 
78
143
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/bin/sandbox ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "investec_open_api"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ InvestecOpenApi.configuration do |config|
10
+ config.api_key = "eUF4elFSRlg5N3ZPY3lRQXdsdUVVNkg2ZVB4TUE1ZVk6YVc1MlpYTjBaV010ZW1FdGNHSXRZV05qYjNWdWRITXRjMkZ1WkdKdmVBPT0="
11
+ config.client_id = "yAxzQRFX97vOcyQAwluEU6H6ePxMA5eY"
12
+ config.client_secret = "4dY0PjEYqoBrZ99r"
13
+ config.base_url = "https://openapisandbox.investec.com/"
14
+ end
15
+
16
+ # (If you use this, don't forget to add pry to your Gemfile!)
17
+ require "pry"
18
+ Pry.start
19
+
20
+ # require "irb"
21
+ # IRB.start(__FILE__)
@@ -28,13 +28,12 @@ Gem::Specification.new do |spec|
28
28
  spec.require_paths = ["lib"]
29
29
 
30
30
  # add runtime dependencies
31
- spec.add_runtime_dependency 'active_attr'
32
31
  spec.add_runtime_dependency 'faraday'
33
- spec.add_runtime_dependency 'faraday_middleware'
34
32
  spec.add_runtime_dependency 'money'
35
33
 
36
34
  # add development dependencies
37
35
  spec.add_development_dependency 'rake'
38
36
  spec.add_development_dependency 'rspec'
39
37
  spec.add_development_dependency 'webmock'
38
+ spec.add_development_dependency 'faker'
40
39
  end
@@ -1,12 +1,13 @@
1
1
  require "faraday"
2
- require "faraday_middleware"
3
2
  require "investec_open_api/models/account"
4
3
  require "investec_open_api/models/transaction"
4
+ require "investec_open_api/models/balance"
5
+ require "investec_open_api/models/transfer"
5
6
  require "investec_open_api/camel_case_refinement"
7
+ require 'base64'
6
8
 
7
9
  class InvestecOpenApi::Client
8
10
  using InvestecOpenApi::CamelCaseRefinement
9
- INVESTEC_API_URL="https://openapi.investec.com/"
10
11
 
11
12
  def authenticate!
12
13
  @token = get_oauth_token["access_token"]
@@ -19,30 +20,63 @@ class InvestecOpenApi::Client
19
20
  end
20
21
  end
21
22
 
23
+ ## Get cleared transactions for an account
24
+ # @param [String] account_id The id of the account to get transactions for
25
+ # @param [Hash] options
26
+ # @option options [String] :fromDate Start date from which to get transactions
27
+ # @option options [String] :toDate End date for transactions
28
+ # @option options [String] :transactionType Type of transaction to filter by eg: CardPurchases, Deposits
22
29
  def transactions(account_id, options = {})
23
30
  endpoint_url = "za/pb/v1/accounts/#{account_id}/transactions"
31
+ perform_transaction_request(endpoint_url, options)
32
+ end
24
33
 
25
- unless options.empty?
26
- query_string = URI.encode_www_form(options.camelize)
27
- endpoint_url += "?#{query_string}"
28
- end
29
-
34
+ ## Get pending transactions for an account
35
+ # @param [String] account_id The id of the account to get pending transactions for
36
+ # @param [Hash] options
37
+ # @option options [String] :fromDate Start date from which to get pending transactions
38
+ # @option options [String] :toDate End date for pending transactions
39
+ def pending_transactions(account_id, options = {})
40
+ endpoint_url = "za/pb/v1/accounts/#{account_id}/pending-transactions"
41
+ perform_transaction_request(endpoint_url, options)
42
+ end
43
+
44
+ def balance(account_id)
45
+ endpoint_url = "za/pb/v1/accounts/#{account_id}/balance"
30
46
  response = connection.get(endpoint_url)
31
- response.body["data"]["transactions"].map do |transaction_raw|
32
- InvestecOpenApi::Models::Transaction.from_api(transaction_raw)
33
- end
47
+ raise "Error fetching balance" if response.body["data"].nil?
48
+ InvestecOpenApi::Models::Balance.from_api(response.body["data"])
49
+ end
50
+
51
+ # @param [String] account_id
52
+ # @param [Array<InvestecOpenApi::Models::Transfer>] transfers
53
+ def transfer_multiple(
54
+ account_id,
55
+ transfers,
56
+ profile_id = nil
57
+ )
58
+ endpoint_url = "za/pb/v1/accounts/#{account_id}/transfermultiple"
59
+ data = {
60
+ transferList: transfers.map(&:to_h),
61
+ }
62
+ data[:profileId] = profile_id if profile_id
63
+ response = connection.post(
64
+ endpoint_url,
65
+ JSON.generate(data)
66
+ )
67
+ response.body
34
68
  end
35
69
 
36
70
  private
37
71
 
38
72
  def get_oauth_token
39
- auth_token = Base64.strict_encode64("#{InvestecOpenApi.client_id}:#{InvestecOpenApi.client_secret}")
73
+ auth_token = ::Base64.strict_encode64("#{InvestecOpenApi.config.client_id}:#{InvestecOpenApi.config.client_secret}")
40
74
 
41
75
  response = Faraday.post(
42
- "#{INVESTEC_API_URL}identity/v2/oauth2/token",
76
+ "#{InvestecOpenApi.config.base_url}identity/v2/oauth2/token",
43
77
  { grant_type: "client_credentials" },
44
78
  {
45
- 'x-api-key' => InvestecOpenApi.api_key,
79
+ 'x-api-key' => InvestecOpenApi.config.api_key,
46
80
  'Authorization' => "Basic #{auth_token}"
47
81
  }
48
82
  )
@@ -51,7 +85,7 @@ class InvestecOpenApi::Client
51
85
  end
52
86
 
53
87
  def connection
54
- @_connection ||= Faraday.new(url: INVESTEC_API_URL) do |builder|
88
+ @_connection ||= Faraday.new(url: InvestecOpenApi.config.base_url) do |builder|
55
89
  if @token
56
90
  builder.headers["Authorization"] = "Bearer #{@token}"
57
91
  end
@@ -65,4 +99,16 @@ class InvestecOpenApi::Client
65
99
  builder.adapter Faraday.default_adapter
66
100
  end
67
101
  end
102
+
103
+ def perform_transaction_request(endpoint_url, options)
104
+ unless options.empty?
105
+ query_string = URI.encode_www_form(options.camelize)
106
+ endpoint_url += "?#{query_string}"
107
+ end
108
+
109
+ response = connection.get(endpoint_url)
110
+ response.body["data"]["transactions"].map do |transaction_raw|
111
+ InvestecOpenApi::Models::Transaction.from_api(transaction_raw)
112
+ end
113
+ end
68
114
  end
@@ -1,25 +1,19 @@
1
1
  module InvestecOpenApi::Models
2
2
  class Account < Base
3
- attribute :id
4
- attribute :number
5
- attribute :name
6
- attribute :reference_name
7
- attribute :product_name
3
+ attr_reader :id,
4
+ :number,
5
+ :name,
6
+ :reference_name,
7
+ :product_name,
8
+ :kyc_compliant,
9
+ :profile_id,
10
+ :profile_name
8
11
 
9
12
  def self.from_api(params = {})
10
- if params['accountId'].present?
11
- params['id'] = params['accountId']
12
- end
13
-
14
- if params['accountNumber'].present?
15
- params['number'] = params['accountNumber']
16
- end
17
-
18
- if params['accountName'].present?
19
- params['name'] = params['accountName']
20
- end
21
-
22
- super
13
+ rewrite_param_key(params, "accountId", "id")
14
+ rewrite_param_key(params, "accountNumber", "number")
15
+ rewrite_param_key(params, "accountName", "name")
16
+ new params
23
17
  end
24
18
  end
25
19
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InvestecOpenApi::Models
4
+ class Balance < Base
5
+ attr_reader :id,
6
+ :current_balance,
7
+ :available_balance,
8
+ :budget_balance,
9
+ :straight_balance,
10
+ :cash_balance,
11
+ :currency
12
+
13
+ def self.from_api(params = {})
14
+ rewrite_param_key(params, "accountId", "id")
15
+
16
+ convert_param_value_to_money(params, "currentBalance")
17
+ convert_param_value_to_money(params, "availableBalance")
18
+ convert_param_value_to_money(params, "budgetBalance")
19
+ convert_param_value_to_money(params, "straightBalance")
20
+ convert_param_value_to_money(params, "cashBalance")
21
+
22
+ new params
23
+ end
24
+ end
25
+ end
@@ -1,15 +1,37 @@
1
- require "active_attr"
1
+ require_relative "../string_utilities"
2
2
 
3
3
  module InvestecOpenApi::Models
4
+ using InvestecOpenApi::StringUtilities
5
+
4
6
  class Base
5
- include ActiveAttr::Model
7
+ def initialize(params)
8
+ params
9
+ .transform_keys(&:underscore)
10
+ .each { |key, value| instance_variable_set("@#{key}", value) }
11
+ end
6
12
 
7
- def self.from_api(params = {})
8
- underscored_params = params.deep_transform_keys do |key|
9
- key.underscore.to_sym
13
+ def self.rewrite_param_key(params, key, rewritten_key)
14
+ params[rewritten_key] = params[key] unless params[key].nil?
15
+ end
16
+
17
+ def self.convert_param_value_to_money(
18
+ params,
19
+ key,
20
+ currency_key = "currency",
21
+ should_make_negative = false
22
+ )
23
+ if params[key].nil?
24
+ return
10
25
  end
26
+ value_in_cents = params[key] * 100
27
+ value_in_cents = -value_in_cents if should_make_negative
28
+ params[key] = Money.from_cents(
29
+ value_in_cents,
30
+ params[currency_key])
31
+ end
11
32
 
12
- new(underscored_params)
33
+ def self.convert_param_value_to_date(params, key)
34
+ params[key] = Date.parse(params[key]) unless params[key].nil?
13
35
  end
14
36
  end
15
37
  end
@@ -2,43 +2,54 @@ require "money"
2
2
 
3
3
  module InvestecOpenApi::Models
4
4
  class Transaction < Base
5
- attribute :account_id
6
- attribute :posted_order
7
- attribute :type
8
- attribute :status
9
- attribute :card_number
10
- attribute :amount
11
- attribute :description
12
- attribute :date, type: Date
13
- attribute :posting_date, type: Date
14
- attribute :value_date, type: Date
15
- attribute :action_date, type: Date
5
+ attr_reader :id,
6
+ :account_id,
7
+ :posted_order,
8
+ :type,
9
+ :transaction_type,
10
+ :status,
11
+ :card_number,
12
+ :amount,
13
+ :description,
14
+ :running_balance,
15
+ :date,
16
+ :posting_date,
17
+ :value_date,
18
+ :action_date
16
19
 
17
- # At this point, there is no unique identifier being returned from Investec's API.
18
- # This method serves to create a stable unique identifier based on the transaction details.
19
- def id
20
- [
20
+ ## Unique identifier
21
+ # Composite key generated by Investec using the following formula:
22
+ # account_id.slice(0, 5) + posting_date.gsub(/-/, "") + posted_order.to_s.rjust(7, "0")
23
+ # This will only be populated for posted transaction on Private Bank Accounts.
24
+ # This is not a backend banking generated ID and will change if any of the properties making it up changes.
25
+ attr_reader :uuid
26
+
27
+ def initialize(params)
28
+ super
29
+ set_id
30
+ end
31
+
32
+ # Investec exposes a uuid for uniqueness so this is no longer needed (non-pending transactions).
33
+ # It is kept here for legacy purposes. It is also useful for pending transactions.
34
+ def set_id
35
+ @id = [
21
36
  amount.to_i,
22
37
  description,
23
38
  date.to_s
24
39
  ].map(&:to_s).join('-')
25
40
  end
26
41
 
27
- def self.from_api(params)
28
- if params['amount'].present?
29
- adjusted_amount = params['amount'] * 100
30
- adjusted_amount = -adjusted_amount if params['type'] == 'DEBIT'
31
-
32
- Money.rounding_mode = BigDecimal::ROUND_HALF_UP
33
- Money.locale_backend = :i18n
34
- params['amount'] = Money.from_cents(adjusted_amount, "ZAR")
35
- end
36
-
37
- if params['transactionDate']
38
- params['date'] = params['transactionDate']
39
- end
40
-
41
- super
42
+ def self.from_api(params, currency = "ZAR")
43
+ params["currency"] = currency
44
+ should_make_amount_negative = params['type'] == 'DEBIT'
45
+ convert_param_value_to_money(params, "amount", "currency", should_make_amount_negative)
46
+ convert_param_value_to_money(params, "runningBalance")
47
+ rewrite_param_key(params, "transactionDate", "date")
48
+ convert_param_value_to_date(params, "date")
49
+ convert_param_value_to_date(params, "postingDate")
50
+ convert_param_value_to_date(params, "valueDate")
51
+ convert_param_value_to_date(params, "actionDate")
52
+ new params
42
53
  end
43
54
  end
44
55
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InvestecOpenApi::Models
4
+ class Transfer
5
+ attr_reader :beneficiary_account_id, :amount, :my_reference, :their_reference
6
+
7
+ # @param [String] beneficiary_account_id
8
+ # @param [Float] amount
9
+ # @param [String] my_reference
10
+ # @param [String] their_reference
11
+ def initialize(
12
+ beneficiary_account_id,
13
+ amount,
14
+ my_reference,
15
+ their_reference
16
+ )
17
+ @beneficiary_account_id = beneficiary_account_id
18
+ @amount = amount.to_s
19
+ @my_reference = my_reference
20
+ @their_reference = their_reference
21
+ end
22
+
23
+ def to_h
24
+ {
25
+ beneficiaryAccountId: @beneficiary_account_id,
26
+ amount: @amount,
27
+ myReference: @my_reference,
28
+ theirReference: @their_reference
29
+ }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,13 @@
1
+ module InvestecOpenApi
2
+ module StringUtilities
3
+ refine String do
4
+ def underscore
5
+ self.gsub(/::/, "/")
6
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
7
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
8
+ .tr("-", "_")
9
+ .downcase
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module InvestecOpenApi
2
- VERSION = "1.1.1"
2
+ VERSION = "2.1.0"
3
3
  end
@@ -6,9 +6,29 @@ require "investec_open_api/client"
6
6
  module InvestecOpenApi
7
7
  class Error < StandardError; end
8
8
 
9
- mattr_accessor :api_key, :client_id, :client_secret, :scope
9
+ class Configuration
10
+ DEFAULT_BASE_URL = "https://openapi.investec.com/"
10
11
 
11
- def self.configuration(&block)
12
- yield self
12
+ attr_accessor :api_key,
13
+ :client_id,
14
+ :client_secret,
15
+ :scope,
16
+ :base_url
17
+
18
+ def initialize
19
+ @base_url = DEFAULT_BASE_URL
20
+
21
+ Money.locale_backend = :i18n
22
+ end
23
+ end
24
+
25
+ class << self
26
+ def config
27
+ @config ||= Configuration.new
28
+ end
29
+
30
+ def configuration
31
+ yield config
32
+ end
13
33
  end
14
34
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: investec_open_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Community Core Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-28 00:00:00.000000000 Z
11
+ date: 2024-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: active_attr
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: faraday
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -39,7 +25,7 @@ dependencies:
39
25
  - !ruby/object:Gem::Version
40
26
  version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
- name: faraday_middleware
28
+ name: money
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - ">="
@@ -53,13 +39,13 @@ dependencies:
53
39
  - !ruby/object:Gem::Version
54
40
  version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
- name: money
42
+ name: rake
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - ">="
60
46
  - !ruby/object:Gem::Version
61
47
  version: '0'
62
- type: :runtime
48
+ type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
@@ -67,7 +53,7 @@ dependencies:
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
- name: rake
56
+ name: rspec
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - ">="
@@ -81,7 +67,7 @@ dependencies:
81
67
  - !ruby/object:Gem::Version
82
68
  version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
- name: rspec
70
+ name: webmock
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - ">="
@@ -95,7 +81,7 @@ dependencies:
95
81
  - !ruby/object:Gem::Version
96
82
  version: '0'
97
83
  - !ruby/object:Gem::Dependency
98
- name: webmock
84
+ name: faker
99
85
  requirement: !ruby/object:Gem::Requirement
100
86
  requirements:
101
87
  - - ">="
@@ -118,7 +104,6 @@ files:
118
104
  - ".github/workflows/main.yml"
119
105
  - ".gitignore"
120
106
  - ".rspec"
121
- - ".ruby-version"
122
107
  - ".travis.yml"
123
108
  - CODE_OF_CONDUCT.md
124
109
  - Gemfile
@@ -127,14 +112,18 @@ files:
127
112
  - README.md
128
113
  - Rakefile
129
114
  - bin/console
115
+ - bin/sandbox
130
116
  - bin/setup
131
117
  - investec_open_api.gemspec
132
118
  - lib/investec_open_api.rb
133
119
  - lib/investec_open_api/camel_case_refinement.rb
134
120
  - lib/investec_open_api/client.rb
135
121
  - lib/investec_open_api/models/account.rb
122
+ - lib/investec_open_api/models/balance.rb
136
123
  - lib/investec_open_api/models/base.rb
137
124
  - lib/investec_open_api/models/transaction.rb
125
+ - lib/investec_open_api/models/transfer.rb
126
+ - lib/investec_open_api/string_utilities.rb
138
127
  - lib/investec_open_api/version.rb
139
128
  homepage: https://github.com/programmable-banking-community/investec_open_api
140
129
  licenses:
@@ -159,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
148
  - !ruby/object:Gem::Version
160
149
  version: '0'
161
150
  requirements: []
162
- rubygems_version: 3.4.1
151
+ rubygems_version: 3.5.16
163
152
  signing_key:
164
153
  specification_version: 4
165
154
  summary: Investec Open API Wrapper
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 3.2.0