ukrsib_api 0.0.1
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 +7 -0
- data/.devcontainer/Dockerfile +17 -0
- data/.devcontainer/devcontainer.json +33 -0
- data/.devcontainer/post-create.sh +8 -0
- data/.rspec +3 -0
- data/.rubocop.yml +9 -0
- data/.vscode/settings.json +7 -0
- data/CHANGELOG.md +8 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +143 -0
- data/Rakefile +12 -0
- data/USB_API_insrt_v_1.0.22.pdf +0 -0
- data/lib/ukrsib_api/authentication.rb +178 -0
- data/lib/ukrsib_api/base_transformer.rb +19 -0
- data/lib/ukrsib_api/client.rb +46 -0
- data/lib/ukrsib_api/models/balance.rb +79 -0
- data/lib/ukrsib_api/models/base_struct.rb +30 -0
- data/lib/ukrsib_api/models/statement_party_details.rb +34 -0
- data/lib/ukrsib_api/models/statement_v3.rb +69 -0
- data/lib/ukrsib_api/models/types.rb +25 -0
- data/lib/ukrsib_api/pagination_helper.rb +72 -0
- data/lib/ukrsib_api/request_id_middleware.rb +8 -0
- data/lib/ukrsib_api/resource.rb +86 -0
- data/lib/ukrsib_api/resources/balance_resource.rb +40 -0
- data/lib/ukrsib_api/resources/statements_v3_resource.rb +35 -0
- data/lib/ukrsib_api/transformers/balance_transformer.rb +35 -0
- data/lib/ukrsib_api/transformers/statement_party_details_transformer.rb +23 -0
- data/lib/ukrsib_api/transformers/statement_v3_transformer.rb +36 -0
- data/lib/ukrsib_api/version.rb +5 -0
- data/lib/ukrsib_api.rb +39 -0
- data/sig/ukrsib_api.rbs +4 -0
- data/sorbet/config +4 -0
- data/sorbet/rbi/annotations/.gitattributes +1 -0
- data/sorbet/rbi/annotations/faraday.rbi +17 -0
- data/sorbet/rbi/annotations/rainbow.rbi +269 -0
- data/sorbet/rbi/gems/.gitattributes +1 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +585 -0
- data/sorbet/rbi/gems/benchmark@0.4.0.rbi +618 -0
- data/sorbet/rbi/gems/bigdecimal@3.1.9.rbi +9 -0
- data/sorbet/rbi/gems/concurrent-ruby@1.3.5.rbi +9 -0
- data/sorbet/rbi/gems/date@3.4.1.rbi +75 -0
- data/sorbet/rbi/gems/diff-lcs@1.6.0.rbi +1134 -0
- data/sorbet/rbi/gems/dry-core@1.1.0.rbi +9 -0
- data/sorbet/rbi/gems/dry-inflector@1.2.0.rbi +9 -0
- data/sorbet/rbi/gems/dry-logic@1.6.0.rbi +9 -0
- data/sorbet/rbi/gems/dry-struct@1.7.1.rbi +925 -0
- data/sorbet/rbi/gems/dry-transformer@1.0.1.rbi +1512 -0
- data/sorbet/rbi/gems/dry-types@1.8.2.rbi +9 -0
- data/sorbet/rbi/gems/erubi@1.13.1.rbi +155 -0
- data/sorbet/rbi/gems/faraday-em_http@1.0.0.rbi +9 -0
- data/sorbet/rbi/gems/faraday-em_synchrony@1.0.0.rbi +9 -0
- data/sorbet/rbi/gems/faraday-excon@1.1.0.rbi +9 -0
- data/sorbet/rbi/gems/faraday-httpclient@1.0.1.rbi +9 -0
- data/sorbet/rbi/gems/faraday-multipart@1.1.0.rbi +9 -0
- data/sorbet/rbi/gems/faraday-net_http@1.0.2.rbi +9 -0
- data/sorbet/rbi/gems/faraday-net_http_persistent@1.2.0.rbi +9 -0
- data/sorbet/rbi/gems/faraday-patron@1.0.0.rbi +9 -0
- data/sorbet/rbi/gems/faraday-rack@1.0.0.rbi +9 -0
- data/sorbet/rbi/gems/faraday-retry@1.0.3.rbi +9 -0
- data/sorbet/rbi/gems/faraday@1.10.4.rbi +9 -0
- data/sorbet/rbi/gems/faraday_middleware@1.2.1.rbi +9 -0
- data/sorbet/rbi/gems/i18n@1.14.7.rbi +2208 -0
- data/sorbet/rbi/gems/ice_nine@0.11.2.rbi +9 -0
- data/sorbet/rbi/gems/io-console@0.8.0.rbi +9 -0
- data/sorbet/rbi/gems/json@2.10.1.rbi +2120 -0
- data/sorbet/rbi/gems/language_server-protocol@3.17.0.4.rbi +9 -0
- data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +86 -0
- data/sorbet/rbi/gems/logger@1.6.6.rbi +940 -0
- data/sorbet/rbi/gems/money@6.19.0.rbi +2260 -0
- data/sorbet/rbi/gems/multipart-post@2.4.1.rbi +9 -0
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +159 -0
- data/sorbet/rbi/gems/parallel@1.26.3.rbi +291 -0
- data/sorbet/rbi/gems/parser@3.3.7.1.rbi +5525 -0
- data/sorbet/rbi/gems/pp@0.6.2.rbi +368 -0
- data/sorbet/rbi/gems/prettyprint@0.2.0.rbi +477 -0
- data/sorbet/rbi/gems/prism@1.3.0.rbi +41403 -0
- data/sorbet/rbi/gems/psych@5.2.3.rbi +2435 -0
- data/sorbet/rbi/gems/racc@1.8.1.rbi +164 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +403 -0
- data/sorbet/rbi/gems/rake@13.2.1.rbi +3028 -0
- data/sorbet/rbi/gems/rbi@0.2.4.rbi +4542 -0
- data/sorbet/rbi/gems/rdoc@6.12.0.rbi +12758 -0
- data/sorbet/rbi/gems/regexp_parser@2.10.0.rbi +3795 -0
- data/sorbet/rbi/gems/reline@0.6.0.rbi +2451 -0
- data/sorbet/rbi/gems/rspec-core@3.13.3.rbi +10986 -0
- data/sorbet/rbi/gems/rspec-expectations@3.13.3.rbi +8183 -0
- data/sorbet/rbi/gems/rspec-mocks@3.13.2.rbi +5341 -0
- data/sorbet/rbi/gems/rspec-support@3.13.2.rbi +1630 -0
- data/sorbet/rbi/gems/rspec@3.13.0.rbi +83 -0
- data/sorbet/rbi/gems/rubocop-ast@1.38.0.rbi +7654 -0
- data/sorbet/rbi/gems/rubocop@1.72.2.rbi +61026 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1318 -0
- data/sorbet/rbi/gems/ruby2_keywords@0.0.5.rbi +9 -0
- data/sorbet/rbi/gems/spoom@1.5.4.rbi +5026 -0
- data/sorbet/rbi/gems/stringio@3.1.5.rbi +9 -0
- data/sorbet/rbi/gems/tapioca@0.16.11.rbi +3656 -0
- data/sorbet/rbi/gems/thor@1.3.2.rbi +4378 -0
- data/sorbet/rbi/gems/unicode-display_width@3.1.4.rbi +132 -0
- data/sorbet/rbi/gems/unicode-emoji@4.0.4.rbi +251 -0
- data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +435 -0
- data/sorbet/rbi/gems/yard@0.9.37.rbi +18379 -0
- data/sorbet/rbi/gems/zeitwerk@2.7.2.rbi +9 -0
- data/sorbet/rbi/todo.rbi +15 -0
- data/sorbet/tapioca/config.yml +13 -0
- data/sorbet/tapioca/require.rb +8 -0
- metadata +236 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module UkrsibAPI
|
5
|
+
module Models
|
6
|
+
# balance model, see api docs for more info (readme)
|
7
|
+
class Balance < BaseStruct
|
8
|
+
attribute :account, Types::String
|
9
|
+
attribute :currency, Types::String
|
10
|
+
attribute :counterparty_branch, Types::String
|
11
|
+
attribute :account_branch, Types::String
|
12
|
+
attribute :account_name, Types::String
|
13
|
+
attribute :state, Types::String
|
14
|
+
attribute :account_type, Types::String
|
15
|
+
attribute :location, Types::String
|
16
|
+
|
17
|
+
# Decimal (monetary) attributes: using coercible decimals to convert string values
|
18
|
+
attribute :balance_in, Types::Coercible::Decimal
|
19
|
+
attribute :balance_in_uah, Types::Coercible::Decimal
|
20
|
+
attribute :balance_out, Types::Coercible::Decimal
|
21
|
+
attribute :balance_out_uah, Types::Coercible::Decimal
|
22
|
+
attribute :turnover_debt, Types::Coercible::Decimal
|
23
|
+
attribute :turnover_debt_uah, Types::Coercible::Decimal
|
24
|
+
attribute :turnover_cred, Types::Coercible::Decimal
|
25
|
+
attribute :turnover_cred_uah, Types::Coercible::Decimal
|
26
|
+
|
27
|
+
# DateTime attributes: using Params coercion for strings formatted as dates
|
28
|
+
attribute :last_operation_date_time, Types::Params::DateTime
|
29
|
+
attribute :open_account_reg_date_time, Types::Params::DateTime
|
30
|
+
attribute :open_account_sys_date_time, Types::Params::DateTime
|
31
|
+
attribute :close_account_date_time, Types::Params::DateTime
|
32
|
+
|
33
|
+
# Boolean attribute
|
34
|
+
attribute :final_balance, Types::Bool
|
35
|
+
|
36
|
+
# @!method balance_in_money
|
37
|
+
# @return [Money] Returns a Money object for balance_in using the model's currency.
|
38
|
+
#
|
39
|
+
# @!method balance_in_uah_money
|
40
|
+
# @return [Money] Returns a Money object for balance_in_uah using "UAH" as currency.
|
41
|
+
#
|
42
|
+
# @!method balance_out_money
|
43
|
+
# @return [Money] Returns a Money object for balance_out using the model's currency.
|
44
|
+
#
|
45
|
+
# @!method balance_out_uah_money
|
46
|
+
# @return [Money] Returns a Money object for balance_out_uah using "UAH" as currency.
|
47
|
+
#
|
48
|
+
# @!method turnover_debt_money
|
49
|
+
# @return [Money] Returns a Money object for turnover_debt using the model's currency.
|
50
|
+
#
|
51
|
+
# @!method turnover_debt_uah_money
|
52
|
+
# @return [Money] Returns a Money object for turnover_debt_uah using "UAH" as currency.
|
53
|
+
#
|
54
|
+
# @!method turnover_cred_money
|
55
|
+
# @return [Money] Returns a Money object for turnover_cred using the model's currency.
|
56
|
+
#
|
57
|
+
# @!method turnover_cred_uah_money
|
58
|
+
# @return [Money] Returns a Money object for turnover_cred_uah using "UAH" as currency.
|
59
|
+
|
60
|
+
# List of monetary attribute names.
|
61
|
+
MONEY_FIELDS = %i[
|
62
|
+
balance_in balance_in_uah
|
63
|
+
balance_out balance_out_uah
|
64
|
+
turnover_debt turnover_debt_uah
|
65
|
+
turnover_cred turnover_cred_uah
|
66
|
+
].freeze
|
67
|
+
|
68
|
+
# For each monetary field, define a method that returns a Money object.
|
69
|
+
MONEY_FIELDS.each do |field|
|
70
|
+
define_method("#{field}_money") do
|
71
|
+
# Choose the currency based on the field name: if it ends with _uah, use "UAH",
|
72
|
+
# otherwise use the model's currency.
|
73
|
+
currency_to_use = field.to_s.end_with?("_uah") ? "UAH" : currency
|
74
|
+
Money.from_amount(public_send(field), currency_to_use)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UkrsibAPI
|
4
|
+
module Models
|
5
|
+
# BaseStruct is a parent class for all models that require a transformer.
|
6
|
+
# It dynamically infers the transformer class based on the name of the child class.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
# class Balance < BaseStruct; end
|
10
|
+
# Balance.transformer # Returns UkrsibAPI::Transformers::BalanceTransformer.new
|
11
|
+
#
|
12
|
+
# class Transaction < BaseStruct; end
|
13
|
+
# Transaction.transformer # Returns UkrsibAPI::Transformers::TransactionTransformer.new
|
14
|
+
#
|
15
|
+
# This ensures that all subclasses of BaseStruct automatically have a transformer method
|
16
|
+
# without needing to redefine it in each subclass.
|
17
|
+
class BaseStruct < Dry::Struct
|
18
|
+
# Returns an instance of the transformer class inferred from the child class name.
|
19
|
+
# Example:
|
20
|
+
# class Balance < BaseStruct; end
|
21
|
+
# Balance.transformer # Returns UkrsibAPI::Transformers::BalanceTransformer.new
|
22
|
+
def self.transformer
|
23
|
+
short_name = name.split("::").last
|
24
|
+
transformer_class_name = "#{short_name}Transformer"
|
25
|
+
transformer_class = UkrsibAPI::Transformers.const_get(transformer_class_name)
|
26
|
+
transformer_class.new
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UkrsibAPI
|
4
|
+
module Models
|
5
|
+
# PartyDetails model
|
6
|
+
#
|
7
|
+
# Represents details of a party, used for both actual payer and actual recipient.
|
8
|
+
class StatementPartyDetails < BaseStruct
|
9
|
+
# Номер квартиры / Apartment number
|
10
|
+
attribute :apartment_number, Types::String.optional
|
11
|
+
|
12
|
+
# Область / Area
|
13
|
+
attribute :area, Types::String.optional
|
14
|
+
|
15
|
+
# Город / City
|
16
|
+
attribute :city, Types::String
|
17
|
+
|
18
|
+
# Код страны (ISO 3166-1) / Country code
|
19
|
+
attribute :country_code, Types::String
|
20
|
+
|
21
|
+
# Номер дома / House number
|
22
|
+
attribute :house_number, Types::String.optional
|
23
|
+
|
24
|
+
# Почтовый индекс / Postcode
|
25
|
+
attribute :postcode, Types::String.optional
|
26
|
+
|
27
|
+
# Улица / Street
|
28
|
+
attribute :street, Types::String
|
29
|
+
|
30
|
+
# Детали юридического лица / Legal entity details
|
31
|
+
attribute :legal_details, Types::Hash.optional
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UkrsibAPI
|
4
|
+
module Models
|
5
|
+
# Statement model
|
6
|
+
#
|
7
|
+
# Represents a financial statement transaction.
|
8
|
+
class StatementV3 < BaseStruct
|
9
|
+
# Банк клиента / Client bank name
|
10
|
+
attribute :client_bank_name, Types::String
|
11
|
+
|
12
|
+
# ЄДРПОУ клиента / Client code
|
13
|
+
attribute :client_code, Types::String
|
14
|
+
|
15
|
+
# IBAN клиента / Client IBAN
|
16
|
+
attribute :client_iban, Types::String
|
17
|
+
|
18
|
+
# МФО банка корреспондента / Correspondent bank MFO
|
19
|
+
attribute :correspondent_bank_mfo, Types::String
|
20
|
+
|
21
|
+
# Название банка корреспондента / Correspondent bank name
|
22
|
+
attribute :correspondent_bank_name, Types::String
|
23
|
+
|
24
|
+
# ЄДРПОУ корреспондента / Correspondent code
|
25
|
+
attribute :correspondent_code, Types::String
|
26
|
+
|
27
|
+
# IBAN корреспондента / Correspondent IBAN
|
28
|
+
attribute :correspondent_iban, Types::String
|
29
|
+
|
30
|
+
# Название корреспондента / Correspondent name
|
31
|
+
attribute :correspondent_name, Types::String
|
32
|
+
|
33
|
+
# Сумма кредита / Credit amount
|
34
|
+
attribute :credit_amount, Types::CoercibleDecimal
|
35
|
+
|
36
|
+
# Валюта / Currency
|
37
|
+
attribute :currency, Types::String
|
38
|
+
|
39
|
+
# Дата валютирования / Valuation date
|
40
|
+
attribute :valuation_date, Types::UnixTimestampWithMilliseconds.optional
|
41
|
+
|
42
|
+
# Сумма дебета / Debit amount
|
43
|
+
attribute :debit_amount, Types::CoercibleDecimal
|
44
|
+
|
45
|
+
# Дата документа / Document date
|
46
|
+
attribute :document_date, Types::UnixTimestampWithMilliseconds
|
47
|
+
|
48
|
+
# Номер документа / Document number
|
49
|
+
attribute :document_number, Types::String
|
50
|
+
|
51
|
+
# Назначение платежа / Payment purpose
|
52
|
+
attribute :payment_purpose, Types::String.optional
|
53
|
+
|
54
|
+
# Дата обработки / Processing date
|
55
|
+
attribute :processing_date, Types::UnixTimestampWithMilliseconds
|
56
|
+
|
57
|
+
# Уникальный идентификатор транзакции / Transaction reference
|
58
|
+
attribute :reference, Types::String
|
59
|
+
|
60
|
+
# Фактический плательщик / Actual payer
|
61
|
+
attribute :actual_payer, Types::Hash.optional
|
62
|
+
|
63
|
+
# Фактический получатель / Actual recipient
|
64
|
+
attribute :actual_recipient, Types::Hash.optional
|
65
|
+
|
66
|
+
attribute :budget_payment_purposes, Types::Array.of(Types::Hash).optional
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UkrsibAPI::Models
|
4
|
+
# best practices
|
5
|
+
module Types
|
6
|
+
include Dry.Types()
|
7
|
+
|
8
|
+
UnixTimestampWithMilliseconds = Types::Coercible::Integer.constructor do |value|
|
9
|
+
# Convert Unix timestamp (milliseconds) to Time object
|
10
|
+
::Time.at(value / 1000).utc if value
|
11
|
+
end
|
12
|
+
CoercibleDecimal = Types::Nominal::Decimal.constructor do |value|
|
13
|
+
case value
|
14
|
+
when Float
|
15
|
+
BigDecimal(value.to_s, 2) # Convert float to string first
|
16
|
+
else
|
17
|
+
begin
|
18
|
+
BigDecimal(value)
|
19
|
+
rescue StandardError
|
20
|
+
nil
|
21
|
+
end # Fallback for other cases
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UkrsibAPI
|
4
|
+
# PaginationHelper provides pagination functionality by yielding individual items
|
5
|
+
# from paginated HTTP responses.
|
6
|
+
# @example
|
7
|
+
# Example of usage:
|
8
|
+
# class BalanceResource < UkrsibAPI::Resource
|
9
|
+
# def common(uri, key, start_date, account, end_date)
|
10
|
+
# params_hash = form_query(start_date, account, end_date, nil, 20)
|
11
|
+
# # Pass a block to handle the HTTP request using your resource's get_request method.
|
12
|
+
# UkrsibAPI::PaginationHelper
|
13
|
+
# .load(uri: uri, params_hash: params_hash, key: "balances", type: UkrsibAPI::Models::Balance) do |uri, params|
|
14
|
+
# get_request(uri, params: params)
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
class PaginationHelper < Dry::Struct
|
19
|
+
# @!attribute [r] data
|
20
|
+
# @return [Array] Array of transformed models.
|
21
|
+
attribute :data, Models::Types::Array.of(Models::Types::Any)
|
22
|
+
# @!attribute [r] next_page_exists
|
23
|
+
# @return [Boolean] Indicates if the next page exists.
|
24
|
+
attribute :next_page_exists, Models::Types::Bool
|
25
|
+
# @!attribute [r] next_page_id
|
26
|
+
# @return [Any, nil] The identifier for the next page.
|
27
|
+
attribute :next_page_start, Models::Types::Any.optional
|
28
|
+
|
29
|
+
# Loads paginated data and yields individual items.
|
30
|
+
#
|
31
|
+
# See example of usage in the class description.
|
32
|
+
#
|
33
|
+
# @param params_hash [Hash] Query parameters for the HTTP request.
|
34
|
+
# @param key [String, Symbol] The key to extract data from the response body.
|
35
|
+
# @param type [Class] A Dry::Struct model class used for transforming each item.
|
36
|
+
# @yield [params] Must perform the HTTP request and return a response object.
|
37
|
+
# @yieldreturn [Array] The HTTP response with a 'body' method containing a hash.
|
38
|
+
# @return [Enumerator] An enumerator yielding individual items.
|
39
|
+
def self.paginate(params_hash:, key:, type:)
|
40
|
+
params_hash[:maxResult] ||= 100
|
41
|
+
params_hash[:firstResult] ||= 0
|
42
|
+
Enumerator.new do |yielder|
|
43
|
+
loop do
|
44
|
+
response = yield(params_hash)
|
45
|
+
processed = from_response(response_body: response.body, key: key, type: type)
|
46
|
+
processed.data.each { |item| yielder << item }
|
47
|
+
break unless processed.next_page_exists
|
48
|
+
|
49
|
+
params_hash[:firstResult] = params_hash[:firstResult] + params_hash[:maxResult]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Transforms the HTTP response and returns a new instance of PaginationHelper.
|
55
|
+
#
|
56
|
+
# @param response_body [Hash] The parsed HTTP response body.
|
57
|
+
# @param key [String, Symbol] The key that holds the array of items.
|
58
|
+
# @param type [Class] A Dry::Struct model class used to encapsulate each item.
|
59
|
+
# @return [PaginationHelper] An instance containing the transformed data and pagination flags.
|
60
|
+
def self.from_response(response_body:, key:, type:)
|
61
|
+
body = response_body
|
62
|
+
transformer = type.transformer
|
63
|
+
transformed = transformer.call(body[key])
|
64
|
+
new(
|
65
|
+
data: transformed.map { |hash| type.new(hash) },
|
66
|
+
next_page_exists: body["total"].to_i > (body["firstResult"].to_i + body["maxResult"].to_i),
|
67
|
+
# TODO: possible bug, >= if it is all zero based
|
68
|
+
next_page_start: body["firstResult"].to_i + body["maxResult"].to_i
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module UkrsibAPI
|
5
|
+
# internal
|
6
|
+
class Resource
|
7
|
+
attr_reader :client
|
8
|
+
|
9
|
+
def initialize(client)
|
10
|
+
@client = client
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Builds the query parameters hash for API requests.
|
15
|
+
#
|
16
|
+
# This method generates a hash of query parameters based on the provided options.
|
17
|
+
# It is designed to work with multiple endpoints:
|
18
|
+
#
|
19
|
+
# 1. **Date Interval Endpoints** (e.g., balances or transactions):
|
20
|
+
# - Requires :start_date (formatted as DD-MM-YYYY)
|
21
|
+
# - Optionally includes :end_date (formatted as DD-MM-YYYY)
|
22
|
+
# - :acc (account IBAN) is optional; if omitted, data for all active accounts are returned.
|
23
|
+
#
|
24
|
+
# 2. **Interim/Final Endpoints** (for getting partial or final data):
|
25
|
+
# - Date parameters are omitted.
|
26
|
+
# - Only :acc, :follow_id, and :limit are used.
|
27
|
+
#
|
28
|
+
# Additionally, if the API response contains:
|
29
|
+
# - "exist_next_page" as true, then the "next_page_id" value should be passed in subsequent requests
|
30
|
+
# using the :follow_id parameter.
|
31
|
+
#
|
32
|
+
# @param start_date [Date, nil] the starting date (required for date interval endpoints)
|
33
|
+
# @param end_date [Date, nil] the ending date (optional)
|
34
|
+
# @param account [String, nil] the account number (IBAN); mapped to :acc in the query
|
35
|
+
# @param follow_id [String, nil] identifier for the next page of results (pagination)
|
36
|
+
# @param limit [Integer] number of records per page (default: 20, maximum recommended: 100)
|
37
|
+
#
|
38
|
+
# @return [Hash] the query parameters hash to be appended to the request URL
|
39
|
+
def form_query(date_from:, date_to:, accounts:, first_result: 0, max_result: 100)
|
40
|
+
params = {}
|
41
|
+
# For date interval endpoints, only add date parameters if provided.
|
42
|
+
params[:dateFrom] = date_from.to_time.to_i * 1000 if date_from
|
43
|
+
params[:dateTo] = date_to.to_time.to_i * 1000 if date_to
|
44
|
+
# Account number is expected under the key :acc by the API.
|
45
|
+
params[:accounts] = accounts.join(",") if accounts.any?
|
46
|
+
|
47
|
+
# Set limit for results per page.
|
48
|
+
params[:firstResult] = first_result
|
49
|
+
params[:maxResult] = max_result
|
50
|
+
params
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def get_request(url, params: {}, headers: {})
|
56
|
+
handle_response client.connection.get(url, params, headers)
|
57
|
+
end
|
58
|
+
|
59
|
+
def post_request(url, body:, headers: {}, sign_fields: [])
|
60
|
+
sign_payload = sign_fields.map { |field| body[field] }.join("|")
|
61
|
+
headers["Sign"] = @client.auth.generate_signature(sign_payload)
|
62
|
+
handle_response client.connection.post(url, body, headers)
|
63
|
+
end
|
64
|
+
|
65
|
+
def handle_response(response)
|
66
|
+
case response.status
|
67
|
+
when 400
|
68
|
+
raise Error, "Your request was malformed. #{response.body["message"]}"
|
69
|
+
when 401
|
70
|
+
raise Error, "You did not supply valid authentication credentials. #{response.body["message"]}"
|
71
|
+
when 403
|
72
|
+
raise Error, "You are not allowed to perform that action. #{response.body["message"]}"
|
73
|
+
when 404
|
74
|
+
raise Error, "No results were found for your request. #{response.body["message"]}"
|
75
|
+
when 429
|
76
|
+
raise Error, "Your request exceeded the API rate limit. #{response.body["message"]}"
|
77
|
+
when 500
|
78
|
+
raise Error, "We were unable to perform the request due to server-side problems. #{response.body["message"]}"
|
79
|
+
else
|
80
|
+
raise Error, response.body["message"] unless response.status == 200
|
81
|
+
end
|
82
|
+
|
83
|
+
response
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module UkrsibAPI
|
5
|
+
module Resources
|
6
|
+
# see api docs
|
7
|
+
class BalanceResource < UkrsibAPI::Resource
|
8
|
+
def common(uri, _key, start_date, account, end_date)
|
9
|
+
params_hash = form_query(start_date:, account:, end_date:)
|
10
|
+
# Pass a block to handle the HTTP request using your resource's get_request method.
|
11
|
+
|
12
|
+
UkrsibAPI::PaginationHelper
|
13
|
+
.paginate(params_hash:, key: "balances", type: UkrsibAPI::Models::Balance) do |params|
|
14
|
+
get_request(uri, params: params)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get balance(s)
|
19
|
+
# start_date required
|
20
|
+
# account(iban string) and end_date optional
|
21
|
+
def list(start_date, account = nil, end_date = nil)
|
22
|
+
common("statements/balance", "balances", start_date, account, end_date)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get interim balance(s)
|
26
|
+
#
|
27
|
+
# @param start_date [String] the start date for the balance query (required)
|
28
|
+
# @param account [String, nil] the account IBAN (optional)
|
29
|
+
# @return [Array<UkrsibAPI::Models::Balance>] an array of Balance models
|
30
|
+
def list_interim(start_date, account = nil, end_date = nil)
|
31
|
+
common("statements/balance/interim", "balances", start_date, account, end_date)
|
32
|
+
end
|
33
|
+
|
34
|
+
# account = string iban, optional
|
35
|
+
def list_final(account = nil)
|
36
|
+
common("statements/balance/final", "balances", start_date, account, end_date)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module UkrsibAPI
|
5
|
+
module Resources
|
6
|
+
##
|
7
|
+
# TransactionResource is responsible for fetching transaction data from the API.
|
8
|
+
# It supports three endpoints:
|
9
|
+
#
|
10
|
+
# 1. Standard transactions endpoint (with a date interval).
|
11
|
+
# 2. Interim transactions endpoint (for data from the last day up to today).
|
12
|
+
# 3. Final transactions endpoint (for final transactions on the last day).
|
13
|
+
#
|
14
|
+
# Each endpoint is paginated. The methods in this class return an Enumerator that
|
15
|
+
# lazily fetches and yields transactions page by page.
|
16
|
+
class StatementsV3Resource < UkrsibAPI::Resource
|
17
|
+
BASE_URI = "v3/statements"
|
18
|
+
SIGN_FIELD_FORMULA = %i[accounts dateFrom dateTo firstResult maxResult].freeze
|
19
|
+
|
20
|
+
def common(uri:, query_params:)
|
21
|
+
UkrsibAPI::PaginationHelper
|
22
|
+
.paginate(params_hash: query_params, key: "data", type: UkrsibAPI::Models::StatementV3) do |params|
|
23
|
+
post_request(uri, body: params, sign_fields: SIGN_FIELD_FORMULA)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def list(accounts:, date_from:, date_to:, first_result: 0, max_result: 100)
|
28
|
+
query_params = form_query(
|
29
|
+
date_from:, date_to:, accounts:, first_result:, max_result:
|
30
|
+
)
|
31
|
+
common(uri: BASE_URI, query_params: query_params)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UkrsibAPI
|
4
|
+
module Transformers
|
5
|
+
# balance field name mappings
|
6
|
+
class BalanceTransformer < UkrsibAPI::BaseTransformer
|
7
|
+
# Define the mapping for keys that need renaming
|
8
|
+
KEY_MAPPING = {
|
9
|
+
"acc" => :account,
|
10
|
+
"atp" => :account_type,
|
11
|
+
"currency" => :currency,
|
12
|
+
"flmn" => :location,
|
13
|
+
"state" => :state,
|
14
|
+
"balanceIn" => :balance_in,
|
15
|
+
"balanceInEq" => :balance_in_uah,
|
16
|
+
"balanceOut" => :balance_out,
|
17
|
+
"balanceOutEq" => :balance_out_uah,
|
18
|
+
"turnoverDebt" => :turnover_debt,
|
19
|
+
"turnoverDebtEq" => :turnover_debt_uah,
|
20
|
+
"turnoverCred" => :turnover_cred,
|
21
|
+
"turnoverCredEq" => :turnover_cred_uah,
|
22
|
+
"bgfIBrnm" => :counterparty_branch,
|
23
|
+
"brnm" => :account_branch,
|
24
|
+
"dpd" => :last_operation_date_time,
|
25
|
+
"nameACC" => :account_name,
|
26
|
+
"date_open_acc_reg" => :open_account_reg_date_time,
|
27
|
+
"date_open_acc_sys" => :open_account_sys_date_time,
|
28
|
+
"date_close_acc" => :close_account_date_time,
|
29
|
+
"is_final_bal" => :final_balance
|
30
|
+
}.freeze
|
31
|
+
|
32
|
+
build_pipeline(KEY_MAPPING)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UkrsibAPI
|
4
|
+
module Transformers
|
5
|
+
# Transformer for party details (actual payer and recipient)
|
6
|
+
# rubocop:disable Layout/HashAlignment
|
7
|
+
class StatementPartyDetailsTransformer < UkrsibAPI::BaseTransformer
|
8
|
+
KEY_MAPPING = {
|
9
|
+
"addressApartmentNumber" => :apartment_number,
|
10
|
+
"addressArea" => :area,
|
11
|
+
"addressCity" => :city,
|
12
|
+
"addressCountryCode" => :country_code,
|
13
|
+
"addressHouseNumber" => :house_number,
|
14
|
+
"addressPostcode" => :postcode,
|
15
|
+
"addressStreet" => :street,
|
16
|
+
"legal" => :legal_details
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
build_pipeline(KEY_MAPPING)
|
20
|
+
end
|
21
|
+
# rubocop:enable Layout/HashAlignment
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UkrsibAPI
|
4
|
+
module Transformers
|
5
|
+
# Statement field name mappings
|
6
|
+
class StatementV3Transformer < UkrsibAPI::BaseTransformer
|
7
|
+
# Define the mapping for keys that need renaming
|
8
|
+
# rubocop:disable Layout/HashAlignment
|
9
|
+
KEY_MAPPING = {
|
10
|
+
"clientBankName" => :client_bank_name,
|
11
|
+
"clientCode" => :client_code,
|
12
|
+
"clientIBAN" => :client_iban,
|
13
|
+
"correspondentBankMFO" => :correspondent_bank_mfo,
|
14
|
+
"correspondentBankName" => :correspondent_bank_name,
|
15
|
+
"correspondentCode" => :correspondent_code,
|
16
|
+
"correspondentIBAN" => :correspondent_iban,
|
17
|
+
"correspondentName" => :correspondent_name,
|
18
|
+
"credit" => :credit_amount,
|
19
|
+
"currency" => :currency,
|
20
|
+
"dateValue" => :valuation_date,
|
21
|
+
"debit" => :debit_amount,
|
22
|
+
"docDate" => :document_date,
|
23
|
+
"docNumber" => :document_number,
|
24
|
+
"paymentPurpose" => :payment_purpose,
|
25
|
+
"provDate" => :processing_date,
|
26
|
+
"reference" => :reference,
|
27
|
+
"actualPayer" => :actual_payer,
|
28
|
+
"actualRecipient" => :actual_recipient,
|
29
|
+
"budgetPaymentPurposes" => :budget_payment_purposes
|
30
|
+
}.freeze
|
31
|
+
# rubocop:enable Layout/HashAlignment
|
32
|
+
|
33
|
+
build_pipeline(KEY_MAPPING)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/ukrsib_api.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "faraday"
|
5
|
+
require "faraday_middleware"
|
6
|
+
require "dry-types"
|
7
|
+
require "dry-struct"
|
8
|
+
require "dry-transformer"
|
9
|
+
require "money"
|
10
|
+
require "securerandom"
|
11
|
+
|
12
|
+
require_relative "ukrsib_api/models/types"
|
13
|
+
require_relative "ukrsib_api/resource"
|
14
|
+
require_relative "ukrsib_api/request_id_middleware"
|
15
|
+
require_relative "ukrsib_api/authentication"
|
16
|
+
require_relative "ukrsib_api/client"
|
17
|
+
require_relative "ukrsib_api/base_transformer"
|
18
|
+
require_relative "ukrsib_api/models/base_struct"
|
19
|
+
require_relative "ukrsib_api/pagination_helper"
|
20
|
+
|
21
|
+
require_relative "ukrsib_api/resources/balance_resource"
|
22
|
+
require_relative "ukrsib_api/transformers/balance_transformer"
|
23
|
+
require_relative "ukrsib_api/models/balance"
|
24
|
+
|
25
|
+
require_relative "ukrsib_api/resources/statements_v3_resource"
|
26
|
+
require_relative "ukrsib_api/transformers/statement_v3_transformer"
|
27
|
+
require_relative "ukrsib_api/transformers/statement_party_details_transformer"
|
28
|
+
require_relative "ukrsib_api/models/statement_party_details"
|
29
|
+
require_relative "ukrsib_api/models/statement_v3"
|
30
|
+
|
31
|
+
# Main entry point for the gem, use client = UkrsibAPI::Client.new(api_token: "token") to start using the API.
|
32
|
+
module UkrsibAPI
|
33
|
+
class Error < StandardError; end
|
34
|
+
class NotAuthorizedError < Error; end
|
35
|
+
|
36
|
+
def self.logger
|
37
|
+
@@logger ||= defined?(Rails) ? Rails.logger : Logger.new($stdout, progname: "UkrsibAPI") # rubocop:disable Style/ClassVars
|
38
|
+
end
|
39
|
+
end
|
data/sig/ukrsib_api.rbs
ADDED
data/sorbet/config
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
**/*.rbi linguist-vendored=true
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
3
|
+
# DO NOT EDIT MANUALLY
|
4
|
+
# This file was pulled from a central RBI files repository.
|
5
|
+
# Please run `bin/tapioca annotations` to update it.
|
6
|
+
|
7
|
+
module Faraday
|
8
|
+
class << self
|
9
|
+
sig { params(url: T.untyped, options: T::Hash[Symbol, T.untyped], block: T.nilable(T.proc.params(connection: Faraday::Connection).void)).returns(Faraday::Connection) }
|
10
|
+
def new(url = nil, options = {}, &block); end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Faraday::Response
|
15
|
+
sig { returns(T::Boolean) }
|
16
|
+
def success?; end
|
17
|
+
end
|