belvo 0.3.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.
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'belvo/http'
4
+ require 'belvo/exceptions'
5
+ require 'belvo/resources'
6
+
7
+ module Belvo
8
+ # Allows easy access to Belvo API servers.
9
+ class Client
10
+ # Current Belvo API session
11
+ # @return [APISession]
12
+ attr_reader :session
13
+
14
+ # @param secret_key_id [String]
15
+ # @param secret_key_password [String]
16
+ # @param url [String, nil] API host URL, can be set from the environment
17
+ # using the variable name BELVO_API_URL
18
+ # @return [APISession] Authenticated Belvo API session
19
+ def initialize(secret_key_id, secret_key_password, url = nil)
20
+ (belvo_api_url = url) || ENV['BELVO_API_URL']
21
+ raise BelvoAPIError, 'You need to provide a URL.' if belvo_api_url.nil?
22
+
23
+ @session = Belvo::APISession.new(belvo_api_url)
24
+
25
+ return if @session.login(secret_key_id, secret_key_password)
26
+
27
+ raise BelvoAPIError, 'Login failed.'
28
+ end
29
+
30
+ # Provides access to Links resource
31
+ # @return [Link]
32
+ def links
33
+ @links = Link.new @session
34
+ end
35
+
36
+ # Provides access to Accounts resource
37
+ # @return [Account]
38
+ def accounts
39
+ @accounts = Account.new @session
40
+ end
41
+
42
+ # Provides access to Transactions resource
43
+ # @return [Transaction]
44
+ def transactions
45
+ @transactions = Transaction.new @session
46
+ end
47
+
48
+ # Provides access to Owners resource
49
+ # @return [Owner]
50
+ def owners
51
+ @owners = Owner.new @session
52
+ end
53
+
54
+ # Provides access to Balances resource
55
+ # @return [Balance]
56
+ def balances
57
+ @balances = Balance.new @session
58
+ end
59
+
60
+ # Provides access to Statements resource
61
+ # @return [Statement]
62
+ def statements
63
+ @statements = Statement.new @session
64
+ end
65
+
66
+ # Provides access to Invoices resource
67
+ # @return [Invoice]
68
+ def invoices
69
+ @invoices = Invoice.new @session
70
+ end
71
+
72
+ # Provides access to TaxReturns resource
73
+ # @return [TaxReturn]
74
+ def tax_returns
75
+ @tax_returns = TaxReturn.new @session
76
+ end
77
+
78
+ # Provides access to Instituions resource
79
+ # @return [Institution]
80
+ def institutions
81
+ @institutions = Institution.new @session
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Belvo
4
+ # Belvo API base error
5
+ class BelvoAPIError < StandardError
6
+ # @param message [String] Error short description
7
+ def initialize(message)
8
+ super(message)
9
+ end
10
+ end
11
+
12
+ # Generic request error, any response with status different than 2xx.
13
+ class RequestError < BelvoAPIError
14
+ # HTTP code returned by Belvo API
15
+ # @return [Integer]
16
+ attr_reader :status_code
17
+
18
+ # Error message returned by Belvo API
19
+ # @return [JSON]
20
+ attr_reader :detail
21
+
22
+ # @param message [String] Error short description
23
+ # @param status_code [Integer] HTTP code
24
+ # @param detail [JSON] Detailed error(s) description
25
+ def initialize(message, status_code, detail)
26
+ super(message)
27
+ @status_code = status_code
28
+ @detail = detail
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'faraday_middleware'
5
+ require 'typhoeus'
6
+ require 'typhoeus/adapters/faraday'
7
+
8
+ require 'belvo/version'
9
+ require 'belvo/exceptions'
10
+
11
+ module Belvo
12
+ # Describes a Belvo API session
13
+ class APISession
14
+ # @param url [String] Belvo API host url
15
+ # @return [Faraday::Connection]
16
+ def initialize(url)
17
+ @url = format('%<url>s/api/', url: url)
18
+ @session = Faraday::Connection.new(url: @url) do |faraday|
19
+ faraday.adapter :typhoeus
20
+ faraday.response :json
21
+ faraday.headers = {
22
+ 'Content-Type' => 'application/json',
23
+ 'User-Agent' => format(
24
+ 'belvo-ruby (%<version>s)',
25
+ version: Belvo::VERSION
26
+ )
27
+ }
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # Raise an error if the response code is not 2XX.
34
+ # @param response [Faraday::Response]
35
+ # @return [Faraday::Response]
36
+ def raise_for_status(response)
37
+ unless response.success?
38
+ raise RequestError.new(
39
+ 'Request error',
40
+ response.status,
41
+ response.body.to_s
42
+ )
43
+ end
44
+ response
45
+ end
46
+
47
+ # Set and validate authentication credentials
48
+ # @return [Boolean] True if credentials are valid to authenticate
49
+ # to Belvo API else False.
50
+ def authenticate
51
+ @session.basic_auth(@key_id, @key_password)
52
+ response = @session.get('')
53
+ response.success?
54
+ end
55
+
56
+ # Perform GET request to a Belvo API endpoint. Needed for Detail and List.
57
+ # @param path [String] API Endpoint
58
+ # @param params [Hash] Params to be send as querystring
59
+ # @return [Faraday::Response]
60
+ # @raise [RequestError] If response code is different than 2XX
61
+ def get(path, params: nil)
62
+ params = {} if params.nil?
63
+ response = @session.get(path) do |req|
64
+ req.params = params
65
+ end
66
+ raise_for_status response
67
+ end
68
+
69
+ public
70
+
71
+ # Authenticate to Belvo API using the given credentials.
72
+ # @param secret_key_id [String]
73
+ # @param secret_key_password [String]
74
+ # @return [Boolean] True if credentials are valid to authenticate
75
+ # to Belvo API else False.
76
+ def login(secret_key_id, secret_key_password)
77
+ @key_id = secret_key_id
78
+ @key_password = secret_key_password
79
+
80
+ authenticate
81
+ end
82
+
83
+ # List results from an API endpoint. It will yield all results following
84
+ # pagination's next page, if any.
85
+ # @param path [String] API endpoint
86
+ # @param params [Hash] Params to be send as querystring
87
+ # @yield [Hash] Each result
88
+ # @raise [RequestError] If response code is different than 2XX
89
+ def list(path, params: nil)
90
+ params = {} if params.nil?
91
+ loop do
92
+ response = get(path, params: params)
93
+ response.body['results'].each do |item|
94
+ yield item if block_given?
95
+ end
96
+
97
+ break unless response.body['next']
98
+
99
+ path = response.body['next']
100
+ params = nil
101
+ end
102
+ end
103
+
104
+ # Show specific resource details
105
+ # @param path [String] API endpoint
106
+ # @param id [String] Resource UUID
107
+ # @param params [Hash] Params to be send as querystring
108
+ # @return [Hash] Resource details
109
+ # @raise [RequestError] If response code is different than 2XX
110
+ def detail(path, id, params: nil)
111
+ params = {} if params.nil?
112
+
113
+ resource_path = format('%<path>s%<id>s/', path: path, id: id)
114
+ response = get(resource_path, params)
115
+
116
+ raise_for_status response
117
+ response.body
118
+ end
119
+
120
+ # Perform a POST request to an API endpoint
121
+ # @param path [String] API endpoint
122
+ # @param data [object] JSON parseable object
123
+ # @return [Hash] Response details
124
+ # @raise [RequestError] If response code is different than 2XX
125
+ def post(path, data)
126
+ response = @session.post(path, data.to_json)
127
+ raise_for_status response
128
+ response.body
129
+ end
130
+
131
+ # Perform a PUT request to an specific resource
132
+ # @param path [String] API endpoint
133
+ # @param id [String] Resource UUID
134
+ # @param data [object] JSON parseable object
135
+ # @return [Hash] Response details
136
+ # @raise [RequestError] If response code is different than 2XX
137
+ def put(path, id, data)
138
+ url = format('%<path>s%<id>s/', path: path, id: id)
139
+ response = @session.put(url, data.to_json)
140
+ raise_for_status response
141
+ response.body
142
+ end
143
+
144
+ # Perform a PATCH request to an API endpoint
145
+ # @param path [String] API endpoint
146
+ # @param data [object] JSON parseable object
147
+ # @return [Hash] Response details
148
+ # @raise [RequestError] If response code is different than 2XX
149
+ def patch(path, data)
150
+ response = @session.patch(path, data.to_json)
151
+ raise_for_status response
152
+ response.body
153
+ end
154
+
155
+ # Delete existing resource
156
+ # @param path [String] API endpoint
157
+ # @param id [String] Resource UUID
158
+ # @return [Boolean] true if resource is successfully deleted else false
159
+ def delete(path, id)
160
+ resource_path = format('%<path>s%<id>s/', path: path, id: id)
161
+ response = @session.delete(resource_path)
162
+ response.success?
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday/options'
4
+
5
+ module Belvo
6
+ # @!class LinkOptions < Faraday::Options
7
+ # Contains the configurable properties for a Link
8
+ # @!attribute access_mode [rw] Link access mode (SINGLE or RECURRENT)
9
+ # @!attribute token [rw] OTP token required by the institution
10
+ # @!attribute encryption_key [rw] Custom encryption key
11
+ class LinkOptions < Faraday::Options.new(
12
+ :access_mode,
13
+ :token,
14
+ :encryption_key
15
+ )
16
+ end
17
+
18
+ # @!class AccountOptions < Faraday::Options
19
+ # Contains the configurable properties for an Account
20
+ # @!attribute save_data [rw] Should data be persisted or not.
21
+ # @!attribute token [rw] OTP token required by the institution
22
+ # @!attribute encryption_key [rw] Custom encryption key
23
+ class AccountOptions < Faraday::Options.new(
24
+ :save_data,
25
+ :token,
26
+ :encryption_key
27
+ )
28
+ end
29
+
30
+ # @!class TransactionOptions < Faraday::Options
31
+ # Contains configurable properties for a Transaction
32
+ # @!attribute date_to [rw] Date string (YYYY-MM-DD)
33
+ # @!attribute account [rw] Account ID (UUID)
34
+ # @!attribute save_data [rw] Should data be persisted or not.
35
+ # @!attribute token [rw] OTP token required by the institution
36
+ # @!attribute encryption_key [rw] Custom encryption key
37
+ class TransactionOptions < Faraday::Options.new(
38
+ :date_to,
39
+ :account,
40
+ :token,
41
+ :encryption_key,
42
+ :save_data
43
+ )
44
+ end
45
+
46
+ # @!class OwnerOptions < Faraday::Options
47
+ # Contains configurable properties of an Owner
48
+ # @!attribute save_data [rw] Should data be persisted or not.
49
+ # @!attribute token [rw] OTP token required by the institution
50
+ # @!attribute encryption_key [rw] Custom encryption key
51
+ class OwnerOptions < Faraday::Options.new(:token, :encryption_key, :save_data)
52
+ end
53
+
54
+ # @!class BalanceOptions < Faraday::Options
55
+ # Contains configurable properties of a Balance
56
+ # @!attribute date_to [rw] Date string (YYYY-MM-DD)
57
+ # @!attribute account [rw] Account ID (UUID)
58
+ # @!attribute save_data [rw] Should data be persisted or not.
59
+ # @!attribute token [rw] OTP token required by the institution
60
+ # @!attribute encryption_key [rw] Custom encryption key
61
+ class BalanceOptions < Faraday::Options.new(
62
+ :date_to,
63
+ :account,
64
+ :token,
65
+ :encryption_key,
66
+ :save_data
67
+ )
68
+ end
69
+
70
+ # @!class StatementOptions < Faraday::Options
71
+ # Contains configurable properties of a Statement
72
+ # @!attribute save_data [rw] Should data be persisted or not.
73
+ # @!attribute token [rw] OTP token required by the institution
74
+ # @!attribute encryption_key [rw] Custom encryption key
75
+ # @!attribute attach_pdf [rw] Should the PDF file be included in the
76
+ # response or not.
77
+ class StatementOptions < Faraday::Options.new(
78
+ :token,
79
+ :encryption_key,
80
+ :save_data,
81
+ :attach_pdf
82
+ )
83
+ end
84
+
85
+ # @!class InvoiceOptions < Faraday::Options
86
+ # Contains configurable properties of an Invoice
87
+ # @!attribute save_data [rw] Should data be persisted or not.
88
+ # @!attribute token [rw] OTP token required by the institution
89
+ # @!attribute encryption_key [rw] Custom encryption key
90
+ # @!attribute attach_xml [rw] Should the XML file be included in the
91
+ # response or not.
92
+ class InvoiceOptions < Faraday::Options.new(
93
+ :save_data,
94
+ :token,
95
+ :encryption_key,
96
+ :attach_xml
97
+ )
98
+ end
99
+
100
+ # @!class TaxReturnOptions < Faraday::Options
101
+ # Contains configurable properties of a TaxReturn
102
+ # @!attribute save_data [rw] Should data be persisted or not.
103
+ # @!attribute token [rw] OTP token required by the institution
104
+ # @!attribute encryption_key [rw] Custom encryption key
105
+ # @!attribute attach_pdf [rw] Should the PDF file be included in the
106
+ # response or not.
107
+ class TaxReturnOptions < Faraday::Options.new(
108
+ :token,
109
+ :encryption_key,
110
+ :save_data,
111
+ :attach_pdf
112
+ )
113
+ end
114
+ end
@@ -0,0 +1,343 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require 'belvo/options'
5
+
6
+ module Belvo
7
+ # Represents a consumable REST resource from Belvo API
8
+ class Resource
9
+ # Resource API endpoint
10
+ # @return [String] the API endpoint
11
+ attr_reader :endpoint
12
+
13
+ # @param session [APISession] current Belvo API session
14
+ def initialize(session)
15
+ @session = session
16
+ end
17
+
18
+ # Remove nil values from a request body
19
+ # @param body [Hash] request body
20
+ # @return [Hash] body without nil values
21
+ def clean(body:)
22
+ body.delete_if { |_key, value| value.nil? }
23
+ end
24
+
25
+ # List all results
26
+ # @return [Array]
27
+ # @raise [RequestError] If response code is different than 2XX
28
+ def list
29
+ results = []
30
+ @session.list(@endpoint) { |item| results.push item }
31
+ results
32
+ end
33
+
34
+ # Show specific resource details
35
+ # @param id [String] Resource UUID
36
+ # @return [Hash]
37
+ # @raise [RequestError] If response code is different than 2XX
38
+ def detail(id:)
39
+ @session.detail(@endpoint, id)
40
+ end
41
+
42
+ # Delete existing resource
43
+ # @param id [String] Resource UUID
44
+ # @return [Boolean] true if resource is successfully deleted else false
45
+ def delete(id:)
46
+ @session.delete(@endpoint, id)
47
+ end
48
+
49
+ # Resume data extraction session. Use this method after you have received a
50
+ # HTTP 428 response.
51
+ # @param session_id [String] Session UUID included in the 428 response
52
+ # @param link [String, nil] Link UUID
53
+ # @raise [RequestError] If response code is different than 2XX
54
+ def resume(session_id:, token:, link: nil)
55
+ data = { session: session_id, token: token, link: link }
56
+ @session.patch(@endpoint, data)
57
+ end
58
+ end
59
+
60
+ # A Link is a set of credentials associated to a end-user access
61
+ class Link < Resource
62
+ class AccessMode
63
+ # Use single to do ad hoc one-time requests
64
+ SINGLE = 'single'
65
+ # Use recurrent to have Belvo refresh your link data on a daily basis
66
+ RECURRENT = 'recurrent'
67
+ end
68
+
69
+ def initialize(session)
70
+ super(session)
71
+ @endpoint = 'links/'
72
+ end
73
+
74
+ # Register a new link
75
+ # @param institution [String] Institution name
76
+ # @param username [String] End-user username
77
+ # @param password [String] End-user password
78
+ # @param password2 [String, nil] End-user secondary password, if any
79
+ # @param options [LinkOptions] Configurable properties
80
+ # @return [Hash] created link details
81
+ # @raise [RequestError] If response code is different than 2XX
82
+ def register(
83
+ institution:,
84
+ username:,
85
+ password:,
86
+ password2: nil,
87
+ options: nil
88
+ )
89
+ options = LinkOptions.from(options)
90
+ body = {
91
+ institution: institution,
92
+ username: username,
93
+ password: password,
94
+ password2: password2,
95
+ token: options.token,
96
+ encryption_key: options.encryption_key,
97
+ access_mode: options.access_mode || AccessMode::SINGLE
98
+ }.merge(options)
99
+ body = clean body: body
100
+ @session.post(@endpoint, body)
101
+ end
102
+
103
+ # Allows to change password, password2 or setting a custom encryption key
104
+ # @param id [String] Link UUID
105
+ # @param password [String] End-user password
106
+ # @param password2 [String, nil] End-user secondary password, if any
107
+ # @param options [LinkOptions] Configurable properties
108
+ # @return [Hash] link details
109
+ # @raise [RequestError] If response code is different than 2XX
110
+ def update(id:, password:, password2: nil, options: nil)
111
+ options = LinkOptions.from(options)
112
+ body = {
113
+ password: password,
114
+ password2: password2,
115
+ token: options.token,
116
+ encryption_key: options.encryption_key
117
+ }.merge(options)
118
+ body = clean body: body
119
+ @session.put(@endpoint, id, body)
120
+ end
121
+ end
122
+
123
+ # An Account is the representation of a bank account inside a financial
124
+ # institution.
125
+ class Account < Resource
126
+ def initialize(session)
127
+ super(session)
128
+ @endpoint = 'accounts/'
129
+ end
130
+
131
+ # Retrieve accounts from an existing link
132
+ # @param link [String] Link UUID
133
+ # @param options [AccountOptions] Configurable properties
134
+ # @return [Hash] created link details
135
+ # @raise [RequestError] If response code is different than 2XX
136
+ def retrieve(link:, options: nil)
137
+ options = AccountOptions.from(options)
138
+ body = {
139
+ link: link,
140
+ token: options.token,
141
+ encryption_key: options.encryption_key,
142
+ save_data: options.save_data || true
143
+ }.merge(options)
144
+ body = clean body: body
145
+ @session.post(@endpoint, body)
146
+ end
147
+ end
148
+
149
+ # A Transaction contains the detailed information of each movement inside an
150
+ # Account.
151
+ class Transaction < Resource
152
+ def initialize(session)
153
+ super(session)
154
+ @endpoint = 'transactions/'
155
+ end
156
+
157
+ # Retrieve transactions from an existing link
158
+ # @param link [String] Link UUID
159
+ # @param date_from [String] Date string (YYYY-MM-DD)
160
+ # @param options [TransactionOptions] Configurable properties
161
+ # @return [Hash] created link details
162
+ # @raise [RequestError] If response code is different than 2XX
163
+ def retrieve(link:, date_from:, options: nil)
164
+ options = TransactionOptions.from(options)
165
+ date_to = options.date_to || Date.today.to_s
166
+ body = {
167
+ link: link,
168
+ date_from: date_from,
169
+ date_to: date_to,
170
+ token: options.token,
171
+ account: options.account,
172
+ encryption_key: options.encryption_key,
173
+ save_data: options.save_data || true
174
+ }.merge(options)
175
+ body = clean body: body
176
+ @session.post(@endpoint, body)
177
+ end
178
+ end
179
+
180
+ # An Owner represents the person who has access to a Link and is the owner
181
+ # of all the Accounts inside the Link
182
+ class Owner < Resource
183
+ def initialize(session)
184
+ super(session)
185
+ @endpoint = 'owners/'
186
+ end
187
+
188
+ # Retrieve owners from an existing link
189
+ # @param link [String] Link UUID
190
+ # @param options [OwnerOptions] Configurable properties
191
+ # @return [Hash] created link details
192
+ # @raise [RequestError] If response code is different than 2XX
193
+ def retrieve(link:, options: nil)
194
+ options = OwnerOptions.from(options)
195
+ body = {
196
+ link: link,
197
+ token: options.token,
198
+ encryption_key: options.encryption_key,
199
+ save_data: options.save_data || true
200
+ }.merge(options)
201
+ body = clean body: body
202
+ @session.post(@endpoint, body)
203
+ end
204
+ end
205
+
206
+ # A Balance represents the financial status of an Account at a given time.
207
+ class Balance < Resource
208
+ def initialize(session)
209
+ super(session)
210
+ @endpoint = 'balances/'
211
+ end
212
+
213
+ # Retrieve balances from a specific account or all accounts from a
214
+ # specific link
215
+ # @param link [String] Link UUID
216
+ # @param date_from [String] Date string (YYYY-MM-DD)
217
+ # @param options [BalanceOptions] Configurable properties
218
+ # @return [Hash] created link details
219
+ # @raise [RequestError] If response code is different than 2XX
220
+ def retrieve(link:, date_from:, options: nil)
221
+ options = BalanceOptions.from(options)
222
+ date_to = options.date_to || Date.today.to_s
223
+ body = {
224
+ link: link,
225
+ date_from: date_from,
226
+ date_to: date_to,
227
+ token: options.token,
228
+ account: options.account,
229
+ encryption_key: options.encryption_key,
230
+ save_data: options.save_data || true
231
+ }.merge(options)
232
+ body = clean body: body
233
+ @session.post(@endpoint, body)
234
+ end
235
+ end
236
+
237
+ # A Statement contains a resume of monthly Transactions inside an Account.
238
+ class Statement < Resource
239
+ def initialize(session)
240
+ super(session)
241
+ @endpoint = 'statements/'
242
+ end
243
+
244
+ # Retrieve statements information from a specific banking link.
245
+ # @param link [String] Link UUID
246
+ # @param year [Integer]
247
+ # @param month [Integer]
248
+ # @param options [StatementOptions] Configurable properties
249
+ # @return [Hash] created link details
250
+ # @raise [RequestError] If response code is different than 2XX
251
+ def retrieve(link:, account:, year:, month:, options: nil)
252
+ options = StatementOptions.from(options)
253
+ body = {
254
+ link: link,
255
+ account: account,
256
+ year: year,
257
+ month: month,
258
+ token: options.token,
259
+ encryption_key: options.encryption_key,
260
+ save_data: options.save_data || true,
261
+ attach_pdf: options.attach_pdf
262
+ }.merge(options)
263
+ body = clean body: body
264
+ @session.post(@endpoint, body)
265
+ end
266
+ end
267
+
268
+ # An Invoice is the representation of an electronic invoice, that can be
269
+ # received or sent, by a business or an individual and has been uploaded
270
+ # to the fiscal institution website
271
+ class Invoice < Resource
272
+ def initialize(session)
273
+ super(session)
274
+ @endpoint = 'invoices/'
275
+ end
276
+
277
+ # @param link [String] Link UUID
278
+ # @param date_from [String] Date string (YYYY-MM-DD)
279
+ # @param date_to [String] Date string (YYYY-MM-DD)
280
+ # @param options [InvoiceOptions] Configurable properties
281
+ # @return [Hash] created link details
282
+ # @raise [RequestError] If response code is different than 2XX
283
+ def retrieve(link:, date_from:, date_to:, type:, options: nil)
284
+ options = InvoiceOptions.from(options)
285
+ body = {
286
+ link: link,
287
+ date_from: date_from,
288
+ date_to: date_to,
289
+ type: type,
290
+ token: options.token,
291
+ encryption_key: options.encryption_key,
292
+ save_data: options.save_data || true,
293
+ attach_xml: options.attach_xml
294
+ }.merge(options)
295
+ body = clean body: body
296
+ @session.post(@endpoint, body)
297
+ end
298
+ end
299
+
300
+ # A Tax return is the representation of the tax return document sent every
301
+ # year by a person or a business to the tax authority in the country.
302
+ class TaxReturn < Resource
303
+ def initialize(session)
304
+ super(session)
305
+ @endpoint = 'tax-returns/'
306
+ end
307
+
308
+ # Retrieve tax returns information from a specific fiscal link.
309
+ # @param link [String] Link UUID
310
+ # @param year_from [Integer]
311
+ # @param year_to [Integer]
312
+ # @param options [TaxReturnOptions] Configurable properties
313
+ # @return [Hash] created link details
314
+ # @raise [RequestError] If response code is different than 2XX
315
+ def retrieve(link:, year_from:, year_to:, options: nil)
316
+ options = TaxReturnOptions.from(options)
317
+ body = {
318
+ link: link,
319
+ year_from: year_from,
320
+ year_to: year_to,
321
+ token: options.token,
322
+ encryption_key: options.encryption_key,
323
+ save_data: options.save_data || true,
324
+ attach_pdf: options.attach_pdf
325
+ }.merge(options)
326
+ body = clean body: body
327
+ @session.post(@endpoint, body)
328
+ end
329
+
330
+ def resume(_session_id, _token, _link: nil)
331
+ raise NotImplementedError 'TaxReturn does not support resuming a session.'
332
+ end
333
+ end
334
+
335
+ # An Institution is an entity that Belvo can access information from. It can
336
+ # be a bank or fiscal type of institutions such as the SAT in Mexico.
337
+ class Institution < Resource
338
+ def initialize(session)
339
+ super(session)
340
+ @endpoint = 'institutions/'
341
+ end
342
+ end
343
+ end