privat_bank_business_api 0.2.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 +6 -0
- data/CHANGELOG.md +12 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +123 -0
- data/Rakefile +12 -0
- data/lib/pb_api/base_transformer.rb +19 -0
- data/lib/pb_api/client.rb +41 -0
- data/lib/pb_api/models/balance.rb +79 -0
- data/lib/pb_api/models/base_struct.rb +30 -0
- data/lib/pb_api/models/transaction.rb +114 -0
- data/lib/pb_api/pagination_helper.rb +73 -0
- data/lib/pb_api/resource.rb +97 -0
- data/lib/pb_api/resources/balance_resource.rb +40 -0
- data/lib/pb_api/resources/transaction_resource.rb +105 -0
- data/lib/pb_api/transformers/balance_transformer.rb +35 -0
- data/lib/pb_api/transformers/transaction_transformer.rb +46 -0
- data/lib/pb_api/types.rb +8 -0
- data/lib/pb_api/version.rb +5 -0
- data/lib/pb_api.rb +34 -0
- data/sig/privat_bank_buisness_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 +17 -0
- data/sorbet/tapioca/config.yml +13 -0
- data/sorbet/tapioca/require.rb +8 -0
- metadata +231 -0
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PbAPI
|
4
|
+
module Models
|
5
|
+
# Transaction model
|
6
|
+
#
|
7
|
+
# It automatically defines two money helper methods:
|
8
|
+
# - amount_money: converts the 'amount' field to Money.
|
9
|
+
# - amount_uah_money: converts the 'amount_uah' field to Money using UAH.
|
10
|
+
class Transaction < BaseStruct
|
11
|
+
# ЄДРПОУ одержувача / Recipient code
|
12
|
+
attribute :recipient_code, Types::String
|
13
|
+
|
14
|
+
# МФО одержувача / Recipient bank code
|
15
|
+
attribute :recipient_bank_code, Types::String
|
16
|
+
|
17
|
+
# Рахунок одержувача / Recipient account
|
18
|
+
attribute :recipient_account, Types::String
|
19
|
+
|
20
|
+
# Назва одержувача / Recipient name
|
21
|
+
attribute :recipient_name, Types::String
|
22
|
+
|
23
|
+
# Банк одержувача / Recipient bank name
|
24
|
+
attribute :recipient_bank_name, Types::String
|
25
|
+
|
26
|
+
# Місто банку одержувача / Recipient bank city
|
27
|
+
attribute :recipient_bank_city, Types::String
|
28
|
+
|
29
|
+
# ЄДРПОУ контрагента / Counterparty code
|
30
|
+
attribute :counterparty_code, Types::String
|
31
|
+
|
32
|
+
# МФО контрагента / Counterparty bank code
|
33
|
+
attribute :counterparty_bank_code, Types::String
|
34
|
+
|
35
|
+
# Рахунок контрагента / Counterparty account
|
36
|
+
attribute :counterparty_account, Types::String
|
37
|
+
|
38
|
+
# Назва контрагента / Counterparty name
|
39
|
+
attribute :counterparty_name, Types::String
|
40
|
+
|
41
|
+
# Банк контрагента / Counterparty bank name
|
42
|
+
attribute :counterparty_bank_name, Types::String
|
43
|
+
|
44
|
+
# Місто банку контрагента / Counterparty bank city
|
45
|
+
attribute :counterparty_bank_city, Types::String
|
46
|
+
|
47
|
+
# Валюта / Currency
|
48
|
+
attribute :currency, Types::String
|
49
|
+
|
50
|
+
# Ознака реальності проведення (r,i) / Indicates if the transaction is real (r) or imaginary (i)
|
51
|
+
attribute :real, Types::String
|
52
|
+
|
53
|
+
# Стан транзакції: p - проводиться, t - сторнована, r - проведена, n - забракована
|
54
|
+
# / Transaction status: p - processing, t - reversed, r - completed, n - rejected
|
55
|
+
attribute :status, Types::String
|
56
|
+
|
57
|
+
# Тип платіжного документа / Document type
|
58
|
+
attribute :document_type, Types::String
|
59
|
+
|
60
|
+
# Номер документа / Document number
|
61
|
+
attribute :document_number, Types::String
|
62
|
+
|
63
|
+
# Клієнтська дата (дд.мм.рррр) / Client date (dd.mm.yyyy)
|
64
|
+
attribute :client_date, Types::Params::DateTime
|
65
|
+
|
66
|
+
# Дата валютування (дд.мм.рррр) / Valuation date (dd.mm.yyyy)
|
67
|
+
attribute :valuation_date, Types::Params::DateTime
|
68
|
+
|
69
|
+
# Підстава платежу / Payment reason
|
70
|
+
attribute :reason, Types::String
|
71
|
+
|
72
|
+
# Сума / Amount
|
73
|
+
attribute :amount, Types::Coercible::Decimal
|
74
|
+
|
75
|
+
# Сума в національній валюті (грн) / Amount in UAH (national currency)
|
76
|
+
attribute :amount_uah, Types::Coercible::Decimal
|
77
|
+
|
78
|
+
# Референс проведення / Transaction reference
|
79
|
+
attribute :reference, Types::String
|
80
|
+
|
81
|
+
# Номер з/п всередині проведення / Internal sequence number within the transaction
|
82
|
+
attribute :reference_number, Types::String
|
83
|
+
|
84
|
+
# Час проведення (HH:MM) / Transaction time (HH:MM)
|
85
|
+
attribute :valuation_time, Types::JSON::Time
|
86
|
+
|
87
|
+
# Дата і час валютування (дд.мм.рррр HH:MM:SS) / Valuation date and time (dd.mm.yyyy HH:MM:SS)
|
88
|
+
attribute :valuation_date_time, Types::Params::DateTime
|
89
|
+
|
90
|
+
# ID транзакції / Transaction ID
|
91
|
+
attribute :id, Types::String
|
92
|
+
|
93
|
+
# Тип транзакції дебет/кредит (D, C) / Transaction type (debit/credit: D, C)
|
94
|
+
attribute :transaction_type, Types::String
|
95
|
+
|
96
|
+
# Референс платежу сервісу / Service payment reference
|
97
|
+
attribute :service_reference, Types::String
|
98
|
+
|
99
|
+
# Технічний ідентифікатор транзакції / Technical transaction ID
|
100
|
+
attribute :technical_id, Types::String
|
101
|
+
|
102
|
+
MONEY_FIELDS = %i[
|
103
|
+
amount amount_uah
|
104
|
+
].freeze
|
105
|
+
|
106
|
+
MONEY_FIELDS.each do |field|
|
107
|
+
define_method("#{field}_money") do
|
108
|
+
currency_to_use = field.to_s.end_with?("_uah") ? "UAH" : currency
|
109
|
+
Money.from_amount(public_send(field), currency_to_use)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PbAPI
|
4
|
+
# PaginationHelper provides pagination functionality by yielding individual items
|
5
|
+
# from paginated HTTP responses.
|
6
|
+
# @example
|
7
|
+
# Example of usage:
|
8
|
+
# class BalanceResource < PbAPI::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
|
+
# PbAPI::PaginationHelper
|
13
|
+
# .load(uri: uri, params_hash: params_hash, key: "balances", type: PbAPI::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, Types::Array.of(Types::Any)
|
22
|
+
# @!attribute [r] next_page_exists
|
23
|
+
# @return [Boolean] Indicates if the next page exists.
|
24
|
+
attribute :next_page_exists, Types::Bool
|
25
|
+
# @!attribute [r] next_page_id
|
26
|
+
# @return [Any, nil] The identifier for the next page.
|
27
|
+
attribute :next_page_id, 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
|
+
Enumerator.new do |yielder|
|
41
|
+
last_page_id = 0
|
42
|
+
loop do
|
43
|
+
# The block is used to perform the HTTP request, decoupling the helper from the client.
|
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 && processed.next_page_id != last_page_id
|
48
|
+
|
49
|
+
last_page_id = params_hash[:followId] = processed.next_page_id
|
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
|
+
|
63
|
+
transformer = type.transformer
|
64
|
+
transformed = transformer.call(body[key])
|
65
|
+
# Create an array of Balance models from the transformed hashes
|
66
|
+
new(
|
67
|
+
data: transformed.map { |hash| type.new(hash) },
|
68
|
+
next_page_exists: body["exist_next_page"],
|
69
|
+
next_page_id: body["next_page_id"]
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module PbAPI
|
5
|
+
# internal
|
6
|
+
class Resource
|
7
|
+
DATE_FORMAT_STRING = "%d-%m-%Y"
|
8
|
+
attr_reader :client
|
9
|
+
|
10
|
+
def initialize(client)
|
11
|
+
@client = client
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Builds the query parameters hash for API requests.
|
16
|
+
#
|
17
|
+
# This method generates a hash of query parameters based on the provided options.
|
18
|
+
# It is designed to work with multiple endpoints:
|
19
|
+
#
|
20
|
+
# 1. **Date Interval Endpoints** (e.g., balances or transactions):
|
21
|
+
# - Requires :start_date (formatted as DD-MM-YYYY)
|
22
|
+
# - Optionally includes :end_date (formatted as DD-MM-YYYY)
|
23
|
+
# - :acc (account IBAN) is optional; if omitted, data for all active accounts are returned.
|
24
|
+
#
|
25
|
+
# 2. **Interim/Final Endpoints** (for getting partial or final data):
|
26
|
+
# - Date parameters are omitted.
|
27
|
+
# - Only :acc, :follow_id, and :limit are used.
|
28
|
+
#
|
29
|
+
# Additionally, if the API response contains:
|
30
|
+
# - "exist_next_page" as true, then the "next_page_id" value should be passed in subsequent requests
|
31
|
+
# using the :follow_id parameter.
|
32
|
+
#
|
33
|
+
# @param start_date [Date, nil] the starting date (required for date interval endpoints)
|
34
|
+
# @param end_date [Date, nil] the ending date (optional)
|
35
|
+
# @param account [String, nil] the account number (IBAN); mapped to :acc in the query
|
36
|
+
# @param follow_id [String, nil] identifier for the next page of results (pagination)
|
37
|
+
# @param limit [Integer] number of records per page (default: 20, maximum recommended: 100)
|
38
|
+
#
|
39
|
+
# @return [Hash] the query parameters hash to be appended to the request URL
|
40
|
+
def form_query(start_date: nil, end_date: nil, account: nil, follow_id: nil, limit: 20)
|
41
|
+
params = {}
|
42
|
+
# For date interval endpoints, only add date parameters if provided.
|
43
|
+
params[:startDate] = start_date.strftime(DATE_FORMAT_STRING) if start_date
|
44
|
+
params[:endDate] = end_date.strftime(DATE_FORMAT_STRING) if end_date
|
45
|
+
# Account number is expected under the key :acc by the API.
|
46
|
+
params[:acc] = account if account
|
47
|
+
# Pagination parameter.
|
48
|
+
params[:followId] = follow_id if follow_id
|
49
|
+
# Set limit for results per page.
|
50
|
+
params[:limit] = limit
|
51
|
+
params
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def get_request(url, params: {}, headers: {})
|
57
|
+
handle_response client.connection.get(url, params, headers)
|
58
|
+
end
|
59
|
+
|
60
|
+
def post_request(url, body:, headers: {})
|
61
|
+
handle_response client.connection.post(url, body, headers)
|
62
|
+
end
|
63
|
+
|
64
|
+
def patch_request(url, body:, headers: {})
|
65
|
+
handle_response client.connection.patch(url, body, headers)
|
66
|
+
end
|
67
|
+
|
68
|
+
def put_request(url, body:, headers: {})
|
69
|
+
handle_response client.connection.put(url, body, headers)
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_request(url, params: {}, headers: {})
|
73
|
+
handle_response client.connection.delete(url, params, headers)
|
74
|
+
end
|
75
|
+
|
76
|
+
def handle_response(response)
|
77
|
+
case response.status
|
78
|
+
when 400
|
79
|
+
raise Error, "Your request was malformed. #{response.body["message"]}"
|
80
|
+
when 401
|
81
|
+
raise Error, "You did not supply valid authentication credentials. #{response.body["message"]}"
|
82
|
+
when 403
|
83
|
+
raise Error, "You are not allowed to perform that action. #{response.body["message"]}"
|
84
|
+
when 404
|
85
|
+
raise Error, "No results were found for your request. #{response.body["message"]}"
|
86
|
+
when 429
|
87
|
+
raise Error, "Your request exceeded the API rate limit. #{response.body["message"]}"
|
88
|
+
when 500
|
89
|
+
raise Error, "We were unable to perform the request due to server-side problems. #{response.body["message"]}"
|
90
|
+
else
|
91
|
+
raise Error, response.body["message"] unless response.status == 200
|
92
|
+
end
|
93
|
+
|
94
|
+
response
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module PbAPI
|
5
|
+
module Resources
|
6
|
+
# see api docs
|
7
|
+
class BalanceResource < PbAPI::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
|
+
PbAPI::PaginationHelper
|
13
|
+
.paginate(params_hash:, key: "balances", type: PbAPI::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<PbAPI::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,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module PbAPI
|
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 TransactionResource < PbAPI::Resource
|
17
|
+
# TODO: make common method private, or refactor it into a parent class. In all classes
|
18
|
+
|
19
|
+
##
|
20
|
+
# Executes a paginated request for transactions.
|
21
|
+
#
|
22
|
+
# @param uri [String] the API endpoint URI (e.g., "statements/transactions",
|
23
|
+
# "statements/transactions/interim", or "statements/transactions/final").
|
24
|
+
# @param query_params [Hash] the query parameters generated by form_query.
|
25
|
+
#
|
26
|
+
# @return [Enumerator] an enumerator that yields each transaction as it is fetched.
|
27
|
+
def common(uri:, query_params:)
|
28
|
+
PbAPI::PaginationHelper
|
29
|
+
.paginate(params_hash: query_params, key: "transactions", type: PbAPI::Models::Transaction) do |params|
|
30
|
+
get_request(uri, params: params)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Retrieves transactions for a specified date range.
|
36
|
+
#
|
37
|
+
# This method is used when you need to filter transactions by a start (and optional end) date.
|
38
|
+
# @example
|
39
|
+
# transactions = PbAPI::Client.transactions.list(
|
40
|
+
# start_date: Date.new(2025, 2, 1),
|
41
|
+
# end_date: Date.new(2025, 2, 28),
|
42
|
+
# account: "UA1234567890",
|
43
|
+
# results_per_page: 50
|
44
|
+
# )
|
45
|
+
#
|
46
|
+
# @param start_date [Date] the starting date (required).
|
47
|
+
# @param end_date [Date, nil] the ending date (optional).
|
48
|
+
# @param account [String, nil] the account IBAN (optional). If omitted, data for all active accounts are returned.
|
49
|
+
# @param next_page_id [String, nil] an identifier for the next page (pagination).
|
50
|
+
# @param results_per_page [Integer] number of records per page (default: 20; maximum recommended: 100).
|
51
|
+
#
|
52
|
+
# @return [Enumerator] an enumerator that yields transaction objects.
|
53
|
+
def list(start_date:, end_date: nil, account: nil, next_page_id: nil, results_per_page: 20)
|
54
|
+
query_params = form_query(
|
55
|
+
start_date:,
|
56
|
+
end_date:,
|
57
|
+
account:,
|
58
|
+
follow_id: next_page_id,
|
59
|
+
limit: results_per_page
|
60
|
+
)
|
61
|
+
common(uri: "statements/transactions", query_params: query_params)
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Retrieves interim transactions.
|
66
|
+
#
|
67
|
+
# Interim endpoints do not require date parameters; they return transactions
|
68
|
+
# for the period from the last day to today.
|
69
|
+
#
|
70
|
+
# @param account [String, nil] the account IBAN (optional).
|
71
|
+
# @param next_page_id [String, nil] an identifier for the next page (pagination).
|
72
|
+
# @param results_per_page [Integer] number of records per page (default: 20).
|
73
|
+
#
|
74
|
+
# @return [Enumerator] an enumerator that yields interim transaction objects.
|
75
|
+
def list_interim(account: nil, next_page_id: nil, results_per_page: 20)
|
76
|
+
query_params = form_query(
|
77
|
+
account: account,
|
78
|
+
follow_id: next_page_id,
|
79
|
+
limit: results_per_page
|
80
|
+
)
|
81
|
+
common(uri: "statements/transactions/interim", query_params: query_params)
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Retrieves final transactions.
|
86
|
+
#
|
87
|
+
# Final endpoints return transactions for the final (last) day.
|
88
|
+
# Like the interim endpoint, date parameters are not required.
|
89
|
+
#
|
90
|
+
# @param account [String, nil] the account IBAN (optional).
|
91
|
+
# @param next_page_id [String, nil] an identifier for the next page (pagination).
|
92
|
+
# @param results_per_page [Integer] number of records per page (default: 20).
|
93
|
+
#
|
94
|
+
# @return [Enumerator] an enumerator that yields final transaction objects.
|
95
|
+
def list_final(account: nil, next_page_id: nil, results_per_page: 20)
|
96
|
+
query_params = form_query(
|
97
|
+
account: account,
|
98
|
+
follow_id: next_page_id,
|
99
|
+
limit: results_per_page
|
100
|
+
)
|
101
|
+
common(uri: "statements/transactions/final", query_params: query_params)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PbAPI
|
4
|
+
module Transformers
|
5
|
+
# balance field name mappings
|
6
|
+
class BalanceTransformer < PbAPI::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,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PbAPI
|
4
|
+
module Transformers
|
5
|
+
# transaction field name mappings
|
6
|
+
class TransactionTransformer < PbAPI::BaseTransformer
|
7
|
+
# Define the mapping for keys that need renaming
|
8
|
+
# rubocop:disable Layout/HashAlignment
|
9
|
+
KEY_MAPPING = {
|
10
|
+
"AUT_MY_CRF" => :recipient_code,
|
11
|
+
"AUT_MY_MFO" => :recipient_bank_code,
|
12
|
+
"AUT_MY_ACC" => :recipient_account,
|
13
|
+
"AUT_MY_NAM" => :recipient_name,
|
14
|
+
"AUT_MY_MFO_NAME" => :recipient_bank_name,
|
15
|
+
"AUT_MY_MFO_CITY" => :recipient_bank_city,
|
16
|
+
"AUT_CNTR_CRF" => :counterparty_code,
|
17
|
+
"AUT_CNTR_MFO" => :counterparty_bank_code,
|
18
|
+
"AUT_CNTR_ACC" => :counterparty_account,
|
19
|
+
"AUT_CNTR_NAM" => :counterparty_name,
|
20
|
+
"AUT_CNTR_MFO_NAME" => :counterparty_bank_name,
|
21
|
+
"AUT_CNTR_MFO_CITY" => :counterparty_bank_city,
|
22
|
+
"CCY" => :currency,
|
23
|
+
"FL_REAL" => :real,
|
24
|
+
"PR_PR" => :status,
|
25
|
+
"DOC_TYP" => :document_type,
|
26
|
+
"NUM_DOC" => :document_number,
|
27
|
+
"DAT_KL" => :client_date,
|
28
|
+
"DAT_OD" => :valuation_date,
|
29
|
+
"OSND" => :reason,
|
30
|
+
"SUM" => :amount,
|
31
|
+
"SUM_E" => :amount_uah,
|
32
|
+
"REF" => :reference,
|
33
|
+
"REFN" => :reference_number,
|
34
|
+
"TIM_P" => :valuation_time,
|
35
|
+
"DATE_TIME_DAT_OD_TIM_P" => :valuation_date_time,
|
36
|
+
"ID" => :id,
|
37
|
+
"TRANTYPE" => :transaction_type,
|
38
|
+
"DLR" => :service_reference,
|
39
|
+
"TECHNICAL_TRANSACTION_ID" => :technical_id
|
40
|
+
}.freeze
|
41
|
+
# rubocop:enable Layout/HashAlignment
|
42
|
+
|
43
|
+
build_pipeline(KEY_MAPPING)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/pb_api/types.rb
ADDED
data/lib/pb_api.rb
ADDED
@@ -0,0 +1,34 @@
|
|
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
|
+
|
11
|
+
require_relative "pb_api/version"
|
12
|
+
require_relative "pb_api/types"
|
13
|
+
require_relative "pb_api/client"
|
14
|
+
require_relative "pb_api/resource"
|
15
|
+
require_relative "pb_api/base_transformer"
|
16
|
+
require_relative "pb_api/models/base_struct"
|
17
|
+
|
18
|
+
require_relative "pb_api/resources/balance_resource"
|
19
|
+
require_relative "pb_api/transformers/balance_transformer"
|
20
|
+
require_relative "pb_api/models/balance"
|
21
|
+
|
22
|
+
require_relative "pb_api/resources/transaction_resource"
|
23
|
+
require_relative "pb_api/transformers/transaction_transformer"
|
24
|
+
require_relative "pb_api/models/transaction"
|
25
|
+
require_relative "pb_api/pagination_helper"
|
26
|
+
|
27
|
+
# Main entry point for the gem, use client = PbAPI::Client.new(api_token: "token") to start using the API.
|
28
|
+
module PbAPI
|
29
|
+
class Error < StandardError; end
|
30
|
+
|
31
|
+
def self.logger
|
32
|
+
@@logger ||= defined?(Rails) ? Rails.logger : Logger.new($stdout, progname: "PbApi") # rubocop:disable Style/ClassVars
|
33
|
+
end
|
34
|
+
end
|
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
|