fintoc 0.1.0 → 1.0.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/pull_request_template.md +47 -0
  3. data/.github/workflows/ci.yml +46 -0
  4. data/.rubocop.yml +14 -7
  5. data/CHANGELOG.md +40 -0
  6. data/Gemfile +20 -1
  7. data/Gemfile.lock +237 -61
  8. data/README.md +286 -42
  9. data/Rakefile +3 -3
  10. data/fintoc.gemspec +3 -7
  11. data/lib/config/initializers/money.rb +5 -0
  12. data/lib/fintoc/base_client.rb +150 -0
  13. data/lib/fintoc/client.rb +14 -123
  14. data/lib/fintoc/constants.rb +4 -3
  15. data/lib/fintoc/errors.rb +139 -15
  16. data/lib/fintoc/jws.rb +83 -0
  17. data/lib/fintoc/utils.rb +2 -2
  18. data/lib/fintoc/v1/client/client.rb +12 -0
  19. data/lib/fintoc/v1/managers/links_manager.rb +46 -0
  20. data/lib/fintoc/v1/resources/account.rb +95 -0
  21. data/lib/fintoc/v1/resources/balance.rb +27 -0
  22. data/lib/fintoc/v1/resources/institution.rb +21 -0
  23. data/lib/fintoc/v1/resources/link.rb +85 -0
  24. data/lib/fintoc/v1/resources/movement.rb +62 -0
  25. data/lib/fintoc/v1/resources/transfer_account.rb +24 -0
  26. data/lib/fintoc/v2/client/client.rb +37 -0
  27. data/lib/fintoc/v2/managers/account_numbers_manager.rb +59 -0
  28. data/lib/fintoc/v2/managers/account_verifications_manager.rb +45 -0
  29. data/lib/fintoc/v2/managers/accounts_manager.rb +54 -0
  30. data/lib/fintoc/v2/managers/entities_manager.rb +36 -0
  31. data/lib/fintoc/v2/managers/simulate_manager.rb +30 -0
  32. data/lib/fintoc/v2/managers/transfers_manager.rb +56 -0
  33. data/lib/fintoc/v2/resources/account.rb +105 -0
  34. data/lib/fintoc/v2/resources/account_number.rb +105 -0
  35. data/lib/fintoc/v2/resources/account_verification.rb +73 -0
  36. data/lib/fintoc/v2/resources/entity.rb +51 -0
  37. data/lib/fintoc/v2/resources/transfer.rb +131 -0
  38. data/lib/fintoc/version.rb +1 -1
  39. data/lib/fintoc/webhook_signature.rb +73 -0
  40. data/lib/fintoc.rb +3 -0
  41. data/lib/tasks/simplecov_config.rb +19 -0
  42. metadata +35 -83
  43. data/lib/fintoc/resources/account.rb +0 -84
  44. data/lib/fintoc/resources/balance.rb +0 -24
  45. data/lib/fintoc/resources/institution.rb +0 -18
  46. data/lib/fintoc/resources/link.rb +0 -83
  47. data/lib/fintoc/resources/movement.rb +0 -55
  48. data/lib/fintoc/resources/transfer_account.rb +0 -22
data/README.md CHANGED
@@ -13,18 +13,30 @@ Do yourself a favor: go grab some ice cubes by installing this refreshing librar
13
13
  ## Table of contents
14
14
 
15
15
  - [Fintoc meets Ruby](#fintoc-meets-ruby)
16
+ - [Why?](#why)
16
17
  - [Table of contents](#table-of-contents)
17
- - [How to install](#how-to-install)
18
+ - [How to Install](#how-to-install)
18
19
  - [Quickstart](#quickstart)
20
+ - [Client Architecture](#client-architecture)
21
+ - [**API V1 Client**](#api-v1-client)
22
+ - [**API V2 Client**](#api-v2-client)
23
+ - [**Backward compatibility**](#backward-compatibility)
19
24
  - [Documentation](#documentation)
20
25
  - [Examples](#examples)
21
- - [Get accounts](#get-accounts)
22
- - [Get movements](#get-movements)
23
- - [Dependencies](#dependencies)
24
- - [How to test…](#how-to-test)
25
- - [Roadmap](#roadmap)
26
- - [Acknowledgements](#acknowledgements)
27
-
26
+ - [Movements API Examples](#movements-api-examples)
27
+ - [Get accounts](#get-accounts)
28
+ - [Get movements](#get-movements)
29
+ - [Transfers API Examples](#transfers-api-examples)
30
+ - [Entities](#entities)
31
+ - [Transfer Accounts](#transfer-accounts)
32
+ - [Account Numbers](#account-numbers)
33
+ - [Transfers](#transfers)
34
+ - [Simulate](#simulate)
35
+ - [Account Verifications](#account-verifications)
36
+ - [Development](#development)
37
+ - [Dependencies](#dependencies)
38
+ - [Setup](#setup)
39
+ - [Contributing](#contributing)
28
40
 
29
41
  ## How to Install
30
42
 
@@ -36,11 +48,11 @@ gem 'fintoc'
36
48
 
37
49
  And then execute:
38
50
 
39
- $ bundle install
51
+ $ bundle install
40
52
 
41
53
  Or install it yourself as:
42
54
 
43
- $ gem install fintoc
55
+ $ gem install fintoc
44
56
 
45
57
  ## Quickstart
46
58
 
@@ -51,37 +63,121 @@ Or install it yourself as:
51
63
  ```ruby
52
64
  require 'fintoc'
53
65
 
54
- client = Fintoc::Client.new('sk_test_9c8d8CeyBTx1VcJzuDgpm4H-bywJCeSx')
55
- link = client.get_link('6n12zLmai3lLE9Dq_token_gvEJi8FrBge4fb3cz7Wp856W')
66
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
67
+ link = client.v1.links.get('link_token')
56
68
  account = link.find(type: 'checking_account')
57
69
 
58
- # Get the las 30 movements
59
- movements = account.get_movements
70
+ # Get the last 30 movements
71
+ movements = account.movements.list
60
72
 
61
73
  # Or get all the movements since a specific date
62
- movements = account.get_movements(since: '2020-08-15')
63
-
74
+ movements = account.movements.list(since: '2020-08-15')
64
75
  ```
76
+
65
77
  And that’s it!
66
78
 
79
+ ## Client Architecture
80
+
81
+ The Fintoc Ruby client is organized into separate clients that mirror the official API structure:
82
+
83
+ ### **API V1 Client**
84
+
85
+ The API client currently provides access to part of the Movements API:
86
+
87
+ ```ruby
88
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
89
+
90
+ # Link management
91
+ links = client.v1.links.list
92
+ link = client.v1.links.get('link_token')
93
+ client.v1.links.delete('link_id')
94
+
95
+ # Account access
96
+ account = link.find(id: account_id)
97
+ ```
98
+
99
+ ### **API V2 Client**
100
+
101
+ The API V2 client currently provides access to part of the Transfers API:
102
+
103
+ ```ruby
104
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
105
+
106
+ # Entities
107
+ entities = client.v2.entities.list
108
+ entity = client.v2.entities.get('entity_id')
109
+
110
+ # Transfer Accounts
111
+ accounts = client.v2.accounts.list
112
+ account = client.v2.accounts.get('account_id')
113
+ account = client.v2.accounts.create(entity_id: 'entity_id', description: 'My Account')
114
+ client.v2.accounts.update('account_id', description: 'Updated')
115
+
116
+ # Account Numbers
117
+ account_numbers = client.v2.account_numbers.list
118
+ account_number = client.v2.account_numbers.get('account_number_id')
119
+ account_number = client.v2.account_numbers.create(account_id: 'account_id', description: 'Main')
120
+ client.v2.account_numbers.update('account_number_id', description: 'Updated')
121
+
122
+ # Transfers
123
+ transfers = client.v2.transfers.list
124
+ transfer = client.v2.transfers.get('transfer_id')
125
+ transfer = client.v2.transfers.create(
126
+ amount: 1000,
127
+ currency: 'CLP',
128
+ account_id: 'account_id',
129
+ counterparty: {...}
130
+ )
131
+ client.v2.transfers.return('transfer_id')
132
+
133
+ # Simulate
134
+ simulated_transfer = client.v2.simulate.receive_transfer(
135
+ account_number_id: 'account_number_id',
136
+ amount: 1000,
137
+ currency: 'CLP'
138
+ )
139
+
140
+ # Account Verifications
141
+ account_verifications = client.v2.account_verifications.list
142
+ account_verification = client.v2.account_verifications.get('account_verification_id')
143
+ account_verification = client.v2.account_verifications.create(account_number: 'account_number')
144
+
145
+ # TODO: Movements
146
+ ```
147
+
148
+ ### **Backward compatibility**
149
+
150
+ The methods of the previous `Fintoc::Client` class implementation are kept for backward compatibility purposes.
151
+
152
+ ```ruby
153
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
154
+
155
+ link = client.get_link('link_token')
156
+ links = client.get_links
157
+ client.delete_link(link.id)
158
+ account = client.get_account('link_token', 'account_id')
159
+ ```
160
+
67
161
  ## Documentation
68
162
 
69
- This client supports all Fintoc API endpoints. For complete information about the API, head to the [docs](https://docs.fintoc.com/reference).
163
+ This client does not support all Fintoc API endpoints yet. For complete information about the API, head to the [docs](https://docs.fintoc.com/reference).
70
164
 
71
165
  ## Examples
72
166
 
73
- ### Get accounts
167
+ ### Movements API Examples
168
+
169
+ #### Get accounts
74
170
 
75
171
  ```ruby
76
172
  require 'fintoc'
77
173
 
78
- client = Fintoc::Client.new('api_key')
79
- link = client.get_link('link_token')
174
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
175
+ link = client.v1.links.get('link_token')
80
176
  puts link.accounts
81
177
 
82
178
  # Or... you can pretty print all the accounts in a Link
83
179
 
84
- link = client.get_link('link_token')
180
+ link = client.v1.links.get('link_token')
85
181
  link.show_accounts
86
182
 
87
183
  ```
@@ -91,8 +187,8 @@ If you want to find a specific account in a link, you can use **find**. You can
91
187
  ```ruby
92
188
  require 'fintoc'
93
189
 
94
- client = Fintoc::Client.new('api_key')
95
- link = client.get_link('link_token')
190
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
191
+ link = client.v1.links.get('link_token')
96
192
  account = link.find(type: 'checking_account')
97
193
 
98
194
  # Or by number
@@ -107,8 +203,8 @@ You can also search for multiple accounts matching a specific criteria with **fi
107
203
  ```ruby
108
204
  require 'fintoc'
109
205
 
110
- client = Fintoc::Client.new('api_key')
111
- link = client.get_link('link_token')
206
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
207
+ link = client.v1.links.get('link_token')
112
208
  accounts = link.find_all(currency: 'CLP')
113
209
  ```
114
210
 
@@ -117,50 +213,198 @@ To update the account balance you can use **update_balance**:
117
213
  ```ruby
118
214
  require 'fintoc'
119
215
 
120
- client = Fintoc::Client.new('api_key')
121
- link = client.get_link('link_token')
216
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
217
+ link = client.v1.links.get('link_token')
122
218
  account = link.find(number: '1111111')
123
219
  account.update_balance
124
220
  ```
125
221
 
126
- ### Get movements
222
+ #### Get movements
127
223
 
128
224
  ```ruby
129
225
  require 'fintoc'
130
226
  require 'time'
131
227
 
132
- client = Fintoc::Client.new('api_key')
133
- link = client.get_link('link_token')
228
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
229
+ link = client.v1.links.get('link_token')
134
230
  account = link.find(type: 'checking_account')
135
231
 
136
232
  # You can get the account movements since a specific DateTime
137
233
  yesterday = DateTime.now - 1
138
- account.get_movements(since: yesterday)
234
+ account.movements.list(since: yesterday)
139
235
 
140
236
  # Or you can use an ISO 8601 formatted string representation of the Date
141
- account.get_movements(since: '2020-01-01')
237
+ account.movements.list(since: '2020-01-01')
142
238
 
143
239
  # You can also set how many movements you want per_page
144
- account.get_movements(since: '2020-01-01', per_page: 100)
240
+ account.movements.list(since: '2020-01-01', per_page: 100)
241
+ ```
242
+
243
+ Calling **movements.list** without arguments gets the last 30 movements of the account
244
+
245
+ ### Transfers API Examples
246
+
247
+ #### Entities
248
+
249
+ ```ruby
250
+ require 'fintoc'
251
+
252
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
253
+
254
+ # Get all entities
255
+ entities = client.v2.entities.list
256
+
257
+ # Get a specific entity
258
+ entity = client.v2.entities.get('entity_id')
259
+ ```
260
+
261
+ You can also list entities with pagination:
262
+
263
+ ```ruby
264
+ # Get entities with pagination
265
+ entities = client.v2.entities.list(limit: 10, starting_after: 'entity_id')
266
+ ```
267
+
268
+ #### Transfer Accounts
269
+
270
+ ```ruby
271
+ require 'fintoc'
272
+
273
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
274
+
275
+ # Create a transfer account
276
+ account = client.v2.accounts.create(
277
+ entity_id: 'entity_id',
278
+ description: 'My Business Account'
279
+ )
280
+
281
+ # Get a specific account
282
+ account = client.v2.accounts.get('account_id')
283
+
284
+ # List all accounts
285
+ accounts = client.v2.accounts.list
286
+
287
+ # Update an account
288
+ updated_account = client.v2.accounts.update('account_id', description: 'Updated Description')
289
+ ```
290
+
291
+ #### Account Numbers
292
+
293
+ ```ruby
294
+ require 'fintoc'
295
+
296
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
297
+
298
+ # Create an account number
299
+ account_number = client.v2.account_numbers.create(
300
+ account_id: 'account_id',
301
+ description: 'Main account number'
302
+ )
303
+
304
+ # Get a specific account number
305
+ account_number = client.v2.account_numbers.get('account_number_id')
306
+
307
+ # List all account numbers
308
+ account_numbers = client.v2.account_numbers.list
309
+
310
+ # Update an account number
311
+ updated_account_number = client.v2.account_numbers.update(
312
+ 'account_number_id',
313
+ description: 'Updated account number'
314
+ )
315
+ ```
316
+
317
+ #### Transfers
318
+
319
+ ```ruby
320
+ require 'fintoc'
321
+
322
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
323
+
324
+ # Create a transfer
325
+ transfer = client.v2.transfers.create(
326
+ amount: 10000,
327
+ currency: 'CLP',
328
+ account_id: 'account_id',
329
+ counterparty: {
330
+ name: 'John Doe',
331
+ rut: '12345678-9',
332
+ email: 'john@example.com',
333
+ bank: 'banco_de_chile',
334
+ account_type: 'checking_account',
335
+ account_number: '1234567890'
336
+ }
337
+ )
338
+
339
+ # Get a specific transfer
340
+ transfer = client.v2.transfers.get('transfer_id')
341
+
342
+ # List all transfers
343
+ transfers = client.v2.transfers.list
344
+
345
+ # Return a transfer
346
+ returned_transfer = client.v2.transfers.return('transfer_id')
145
347
  ```
146
348
 
147
- Calling **get_movements** without arguments gets the last 30 movements of the account
349
+ #### Simulate
350
+
351
+ ```ruby
352
+ require 'fintoc'
353
+
354
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
355
+
356
+ # Simulate receiving a transfer
357
+ simulated_transfer = client.v2.simulate.receive_transfer(
358
+ account_number_id: 'account_number_id',
359
+ amount: 5000,
360
+ currency: 'CLP'
361
+ )
362
+ ```
148
363
 
149
- ## Dependencies
364
+ #### Account Verifications
150
365
 
151
- This project relies on the following packages:
366
+ ```ruby
367
+ require 'fintoc'
152
368
 
153
- - [**http.rb**](https://github.com/httprb/http)
154
- - [**tabulate**](https://github.com/roylez/tabulate)
369
+ client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
155
370
 
156
- ## How to test…
371
+ # Create an account verification
372
+ account_verification = client.v2.account_verifications.create(account_number: 'account_number')
157
373
 
158
- You can run all the tests just by running:
374
+ # Get a specific account verification
375
+ account_verification = client.v2.account_verifications.get('account_verification_id')
159
376
 
377
+ # List all account verifications
378
+ account_verifications = client.v2.account_verifications.list
160
379
  ```
161
- rspec
380
+
381
+ ## Development
382
+
383
+ ### Dependencies
384
+
385
+ This gem supports **Ruby 2.3+** but development requires modern tooling:
386
+
387
+ - **Ruby:** 2.3+ (3.2+ recommended for development)
388
+ - **Bundler:** 2.7+ (for development)
389
+ - **Git:** For version control
390
+
391
+ ### Setup
392
+
393
+ ```bash
394
+ # Clone the repository
395
+ git clone https://github.com/fintoc-com/fintoc-ruby.git
396
+ cd fintoc-ruby
397
+
398
+ # Install dependencies (requires Bundler 2.7+)
399
+ bundle install
400
+
401
+ # Run tests
402
+ bundle exec rspec
403
+
404
+ # Run linting
405
+ bundle exec rubocop
162
406
  ```
163
407
 
164
408
  ## Contributing
165
409
 
166
- Bug reports and pull requests are welcome on GitHub at https://github.com/fintoc-com/fintoc.
410
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/fintoc-com/fintoc-ruby](https://github.com/fintoc-com/fintoc-ruby).
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
data/fintoc.gemspec CHANGED
@@ -9,12 +9,13 @@ Gem::Specification.new do |spec|
9
9
  spec.summary = 'The official Ruby client for the Fintoc API.'
10
10
  spec.description = 'The official Ruby client for the Fintoc API.'
11
11
  spec.homepage = 'https://github.com/fintoc-com/fintoc-ruby'
12
- spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
12
+ spec.required_ruby_version = Gem::Requirement.new('>= 3.2.2')
13
13
 
14
14
  # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
15
15
 
16
16
  spec.metadata['homepage_uri'] = spec.homepage
17
17
  spec.metadata['source_code_uri'] = 'https://github.com/fintoc-com/fintoc-ruby'
18
+ spec.metadata['rubygems_mfa_required'] = 'true'
18
19
  # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
19
20
 
20
21
  # Specify which files should be added to the gem when it is released.
@@ -26,11 +27,6 @@ Gem::Specification.new do |spec|
26
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
28
  spec.require_paths = ['lib']
28
29
  spec.add_dependency 'http'
30
+ spec.add_dependency 'money-rails'
29
31
  spec.add_dependency 'tabulate'
30
- spec.add_development_dependency 'rspec', '~> 3.0'
31
- spec.add_development_dependency 'rubocop', '~> 0.81.0'
32
- spec.add_development_dependency 'rubocop-performance'
33
- spec.add_development_dependency 'rubocop-rspec'
34
- spec.add_development_dependency 'vcr'
35
- spec.add_development_dependency 'webmock'
36
32
  end
@@ -0,0 +1,5 @@
1
+ require 'money-rails'
2
+
3
+ MoneyRails.configure do |config|
4
+ config.locale_backend = :currency
5
+ end
@@ -0,0 +1,150 @@
1
+ require 'http'
2
+ require 'json'
3
+ require 'fintoc/utils'
4
+ require 'fintoc/errors'
5
+ require 'fintoc/constants'
6
+ require 'fintoc/version'
7
+ require 'fintoc/jws'
8
+
9
+ module Fintoc
10
+ class BaseClient
11
+ include Utils
12
+
13
+ attr_accessor :default_params
14
+
15
+ def initialize(api_key, jws_private_key: nil)
16
+ @api_key = api_key
17
+ @user_agent = "fintoc-ruby/#{Fintoc::VERSION}"
18
+ @headers = { Authorization: "Bearer #{@api_key}", 'User-Agent': @user_agent }
19
+ @link_headers = nil
20
+ @link_header_pattern = '<(?<url>.*)>;\s*rel="(?<rel>.*)"'
21
+ @default_params = {}
22
+ @jws = jws_private_key ? Fintoc::JWS.new(jws_private_key) : nil
23
+ end
24
+
25
+ def get(version: :v1)
26
+ request('get', version: version)
27
+ end
28
+
29
+ def delete(version: :v1)
30
+ request('delete', version: version)
31
+ end
32
+
33
+ def post(version: :v1, use_jws: false)
34
+ request('post', version: version, use_jws: use_jws)
35
+ end
36
+
37
+ def patch(version: :v1, use_jws: false)
38
+ request('patch', version: version, use_jws: use_jws)
39
+ end
40
+
41
+ def request(method, version: :v1, use_jws: false)
42
+ proc do |resource, **kwargs|
43
+ parameters = params(method, **kwargs)
44
+ response = make_request(method, resource, parameters, version: version, use_jws: use_jws)
45
+ content = JSON.parse(response.body, symbolize_names: true)
46
+
47
+ if response.status.client_error? || response.status.server_error?
48
+ raise_custom_error(content[:error])
49
+ end
50
+
51
+ @link_headers = response.headers.get('link')
52
+ content
53
+ end
54
+ end
55
+
56
+ def fetch_next
57
+ next_ = link_headers['next']
58
+ Enumerator.new do |yielder|
59
+ while next_
60
+ yielder << get.call(next_)
61
+ next_ = link_headers['next']
62
+ end
63
+ end
64
+ end
65
+
66
+ def to_s
67
+ visible_chars = 8
68
+ visible_key = @api_key.slice(0, visible_chars)
69
+ hidden_part = '*' * (@api_key.size - visible_chars)
70
+ "#{self.class.name}(🔑=#{visible_key + hidden_part})"
71
+ end
72
+
73
+ private
74
+
75
+ def client
76
+ @client ||= HTTP.headers(@headers)
77
+ end
78
+
79
+ def parse_headers(dict, link)
80
+ matches = link.strip.match(@link_header_pattern)
81
+ dict[matches[:rel]] = matches[:url]
82
+ dict
83
+ end
84
+
85
+ def build_url(resource, version: :v1)
86
+ base_url = version == :v2 ? Fintoc::Constants::BASE_URL_V2 : Fintoc::Constants::BASE_URL
87
+ "#{Fintoc::Constants::SCHEME}#{base_url}#{resource}"
88
+ end
89
+
90
+ def should_use_jws?(method, use_jws)
91
+ use_jws && @jws && %w[post patch put].include?(method.downcase)
92
+ end
93
+
94
+ def make_request(method, resource, parameters, version: :v1, use_jws: false)
95
+ # this is to handle url returned in the link headers
96
+ # I'm sure there is a better and more clever way to solve this
97
+ if resource.start_with? 'https'
98
+ return client.send(method, resource)
99
+ end
100
+
101
+ url = build_url(resource, version:)
102
+
103
+ if should_use_jws?(method, use_jws)
104
+ request_body = parameters[:json]&.to_json || ''
105
+ jws_signature = @jws.generate_signature(request_body)
106
+
107
+ return client.headers('Fintoc-JWS-Signature' => jws_signature).send(method, url, parameters)
108
+ end
109
+
110
+ client.send(method, url, parameters)
111
+ end
112
+
113
+ def params(method, **kwargs)
114
+ if method == 'get'
115
+ { params: { **@default_params, **kwargs } }
116
+ else
117
+ { json: { **@default_params, **kwargs } }
118
+ end
119
+ end
120
+
121
+ def raise_custom_error(error)
122
+ raise error_class(error[:code]).new(error[:message], error[:doc_url])
123
+ end
124
+
125
+ def error_class(snake_code)
126
+ pascal_klass_name = Utils.snake_to_pascal(snake_code)
127
+ # this conditional klass_name is to handle InternalServerError custom error class
128
+ # without this the error class name would be like InternalServerErrorError (^-^)
129
+ klass =
130
+ pascal_klass_name.end_with?('Error') ? pascal_klass_name : "#{pascal_klass_name}Error"
131
+ Module.const_get("Fintoc::Errors::#{klass}")
132
+ end
133
+
134
+ # rubocop:disable Layout/LineLength
135
+ # This attribute getter parses the link headers using some regex 24K magic in the air...
136
+ # Ex.
137
+ # <https://api.fintoc.com/v1/links?page=1>; rel="first", <https://api.fintoc.com/v1/links?page=1>; rel="last"
138
+ # this helps to handle pagination see: https://fintoc.com/docs#paginacion
139
+ # return a hash like { first:"https://api.fintoc.com/v1/links?page=1" }
140
+ #
141
+ # @param link_headers [String]
142
+ # @return [Hash]
143
+ # rubocop:enable Layout/LineLength
144
+ def link_headers
145
+ return if @link_headers.nil?
146
+
147
+ @link_headers[0].split(',').reduce({}) { |dict, link| parse_headers(dict, link) }
148
+ end
149
+ end
150
+ end