bs2_api 1.2.2 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +6 -1
- data/Gemfile +7 -2
- data/Gemfile.lock +5 -2
- data/README.md +41 -1
- data/lib/bs2_api/entities/async_request.rb +45 -0
- data/lib/bs2_api/entities/async_response.rb +39 -0
- data/lib/bs2_api/entities/async_status.rb +73 -0
- data/lib/bs2_api/entities/pix_key.rb +1 -1
- data/lib/bs2_api/payment/async.rb +105 -0
- data/lib/bs2_api/payment/base.rb +27 -23
- data/lib/bs2_api/payment/detail.rb +21 -7
- data/lib/bs2_api/pix/detail.rb +52 -0
- data/lib/bs2_api/refund/pix/create.rb +56 -0
- data/lib/bs2_api/refund/pix/detail.rb +58 -0
- data/lib/bs2_api/request/auth.rb +38 -11
- data/lib/bs2_api/version.rb +1 -1
- data/lib/bs2_api.rb +15 -6
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ba55ce23aae59313a798b0b5d983e29b7a5ef279810d795b513b99888196811
|
4
|
+
data.tar.gz: c61832cf0382e1d9b1be22615963303d6f3c4e8bfdf2fe217cd2292e4082a5a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b5a00b54f7c859977f81041da155713e625988f5432c76e6f3d8d6c5f1448594685e6c7933690cabae03c5cec08a35c4f22a07fec4e7908ab5d0226fca9e746
|
7
|
+
data.tar.gz: 9c74747a9be8e1f0b064e46de4a8a8345c1f162417e7c155fabeab98f3c00999f0e712bb942c2f4599d0e584c33c3d92e675df0beb71a015d37f6a71b270681e
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
bs2_api (1.2
|
4
|
+
bs2_api (1.3.2)
|
5
5
|
activesupport
|
6
6
|
builder
|
7
7
|
bundler
|
@@ -26,6 +26,8 @@ GEM
|
|
26
26
|
rexml
|
27
27
|
diff-lcs (1.4.4)
|
28
28
|
dotenv (2.7.6)
|
29
|
+
factory_bot (6.2.1)
|
30
|
+
activesupport (>= 5.0.0)
|
29
31
|
hashdiff (1.0.1)
|
30
32
|
httparty (0.18.1)
|
31
33
|
mime-types (~> 3.0)
|
@@ -80,7 +82,8 @@ PLATFORMS
|
|
80
82
|
DEPENDENCIES
|
81
83
|
bs2_api!
|
82
84
|
dotenv (~> 2.7, >= 2.7.6)
|
83
|
-
|
85
|
+
factory_bot (~> 6.1)
|
86
|
+
pry-byebug (~> 3.7)
|
84
87
|
rspec (~> 3.10)
|
85
88
|
uuid (~> 2.3, >= 2.3.9)
|
86
89
|
vcr (~> 6.0)
|
data/README.md
CHANGED
@@ -147,6 +147,46 @@ payment.class
|
|
147
147
|
=> Bs2Api::Entities::Payment
|
148
148
|
```
|
149
149
|
|
150
|
+
|
151
|
+
### Async API
|
152
|
+
Add initial asyc BS2 API implementation.
|
153
|
+
|
154
|
+
The API allows to pass multiple request all at once. In order to do so you must:
|
155
|
+
1. Create `Bs2Api::Payment::Async`
|
156
|
+
2. Create one or more PIX keys
|
157
|
+
3. For each PIX key create `Bs2Api::Entities::AsyncRequest` passing in the PIX key, internal identifier and the value of the transaction
|
158
|
+
4. Add each async request to the async payment via `Bs2Api::Payment::Async#add_request`
|
159
|
+
5. When all requests are added call `Bs2Api::Payment::Async#call`
|
160
|
+
6. In the response you will get list of payments of type `Bs2Api::Entities::AsyncResponse` whose confirmation will be sent via webhook
|
161
|
+
6.1 If even one of the requests has invalid data, the response will be 400 and we won't get anything via webhook
|
162
|
+
7. If the response from 6 was 202 but we don't get a webhook notification we should start polling the response manually. This is done by calling `Bs2Api::Payment::Async::check_payment_status`. It has one parameter the `Bs2Api::Entities::AsyncResponse#request_id`.The result from this will be `Bs2Api::Entities::AsyncStatus`, using it you can check if the payment was rejected or confirmed.
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
pix_key = Bs2Api::Entities::PixKey.new(
|
166
|
+
key: 'joao@gmail.com',
|
167
|
+
type: 'EMAIL'
|
168
|
+
)
|
169
|
+
|
170
|
+
async_request = Bs2Api::Entities::AsyncRequest.new(
|
171
|
+
pix_key: pix_key,
|
172
|
+
value: 10.0,
|
173
|
+
identificator: 'payment1'
|
174
|
+
)
|
175
|
+
|
176
|
+
async_payment = Bs2Api::Payment::Async.new
|
177
|
+
async_payment.add_request(async_request)
|
178
|
+
|
179
|
+
response_list = async_payment.call
|
180
|
+
|
181
|
+
# Wait for webhook if notification does not arrive (for example for the first item)
|
182
|
+
response_status = Bs2Api::Payment::Async.check_payment_status(response_list[0].request_id)
|
183
|
+
|
184
|
+
# Check the status
|
185
|
+
if response_status.rejected?
|
186
|
+
puts response_status.rejection_description
|
187
|
+
end
|
188
|
+
```
|
189
|
+
|
150
190
|
### Classes de erros:
|
151
191
|
```ruby
|
152
192
|
# Todos erros herdam de:
|
@@ -166,4 +206,4 @@ Bs2Api::Errors::Unauthorized
|
|
166
206
|
|
167
207
|
### Observações
|
168
208
|
- Método `call` retorna o próprio objeto
|
169
|
-
- Em caso de retorno diferente de sucesso na comunicação com a API do Bs2, um erro sempre será lançado.
|
209
|
+
- Em caso de retorno diferente de sucesso na comunicação com a API do Bs2, um erro sempre será lançado.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bs2Api
|
4
|
+
module Entities
|
5
|
+
# Used by Bs2Api::Payment::Async. This class stores
|
6
|
+
# PIX key, user defined identificador for the key and
|
7
|
+
# the value to be transfered. Bs2Api::Payment::Async
|
8
|
+
# sends a bucket of AsyncRequest and in the response
|
9
|
+
# we get a list of passed payments. The identificador
|
10
|
+
# can be used to keep track of the transactino in the
|
11
|
+
# response.
|
12
|
+
class AsyncRequest
|
13
|
+
attr_accessor :identificator, :pix_key, :value
|
14
|
+
|
15
|
+
ALLOWED_PIX_KEY_TYPES = %w[
|
16
|
+
CPF
|
17
|
+
CNPJ
|
18
|
+
EMAIL
|
19
|
+
EVP
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
def initialize(args = {})
|
23
|
+
@pix_key = args[:pix_key]
|
24
|
+
raise Errors::InvalidPixKey unless ALLOWED_PIX_KEY_TYPES.include? @pix_key.type
|
25
|
+
|
26
|
+
@identificator = args.fetch(:identificator)
|
27
|
+
@value = args[:value]
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_hash
|
31
|
+
ActiveSupport::HashWithIndifferentAccess.new(
|
32
|
+
{
|
33
|
+
identificador: @identificator,
|
34
|
+
chave: @pix_key.to_hash,
|
35
|
+
valor: @value
|
36
|
+
}
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_json(*)
|
41
|
+
to_hash.to_json
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bs2Api
|
4
|
+
module Entities
|
5
|
+
# After we send async payment request via calling Bs2Api::Payment::Async#call
|
6
|
+
# the API is expected to return array of JSON objects describing each payment
|
7
|
+
# this class is used to wrap those JSON objects
|
8
|
+
# identificator is optional and is for internal purposes it won't be sent via
|
9
|
+
# the webhook when the payment confirmation is done.
|
10
|
+
# request_id is the id of the payment which the bank will send via webhook
|
11
|
+
class AsyncResponse
|
12
|
+
attr_accessor :identificator, :pix_key, :value, :error, :request_id
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def from_response(input_hash)
|
16
|
+
pix_key = PixKey.new(
|
17
|
+
key: input_hash['chave']['valor'],
|
18
|
+
type: input_hash['chave']['tipo']
|
19
|
+
)
|
20
|
+
AsyncResponse.new(
|
21
|
+
identificator: input_hash['identificador'],
|
22
|
+
pix_key: pix_key,
|
23
|
+
value: input_hash['valor'],
|
24
|
+
error: input_hash['erros'],
|
25
|
+
request_id: input_hash['solicitacaoId']
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(args = {})
|
31
|
+
@identificator = args.fetch(:identificator, '')
|
32
|
+
@pix_key = args[:pix_key]
|
33
|
+
@value = args[:value]
|
34
|
+
@error = args[:error]
|
35
|
+
@request_id = args[:request_id]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bs2Api
|
4
|
+
module Entities
|
5
|
+
# Used with Bs2Api::Payment::Async. When we call
|
6
|
+
# Bs2Api::Payment::Async#call we expect to get data for each
|
7
|
+
# item in the bucket via webhook. If we don't get webhooks in
|
8
|
+
# a few seconds (roughly about 10s) we should start polling the
|
9
|
+
# status of the payment by calling # Bs2Api::Payment::Async::check_payment_status.
|
10
|
+
# The following # class is used to wrap the result of
|
11
|
+
# Bs2Api::Payment::Async::check_payment_status
|
12
|
+
class AsyncStatus
|
13
|
+
attr_accessor :request_id, :payment_id, :end_to_end_id, :status,
|
14
|
+
:agency, :number, :pix_key, :value, :free_field,
|
15
|
+
:rejection_description, :error_description
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Parses the has from the response body of
|
19
|
+
# Bs2Api::Payment::Async::check_payment_status
|
20
|
+
# @param[Hash] The response body as a hash with string keys
|
21
|
+
def from_response(hash)
|
22
|
+
new(
|
23
|
+
request_id: hash['solicitacaoId'],
|
24
|
+
payment_id: hash['pagamentoId'],
|
25
|
+
end_to_end_id: hash['endToEndId'],
|
26
|
+
status: STATUS[hash['status']],
|
27
|
+
agency: hash['agencia'],
|
28
|
+
number: hash['numero'],
|
29
|
+
pix_key: Bs2Api::Entities::PixKey.from_response(hash['chave']),
|
30
|
+
value: hash['valor'],
|
31
|
+
free_field: hash['campoLivre'],
|
32
|
+
rejection_description: hash['rejeitadoDescricao'],
|
33
|
+
error_description: hash['erroDescricao']
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
STATUS = {
|
39
|
+
'Realizado' => :awaiting_validation,
|
40
|
+
'Iniciado' => :in_process,
|
41
|
+
'Confirmado' => :confirmed,
|
42
|
+
'Rejeitado' => :rejected,
|
43
|
+
'Erro' => :error
|
44
|
+
}.freeze
|
45
|
+
|
46
|
+
def initialize(args = {})
|
47
|
+
@request_id = args[:request_id]
|
48
|
+
@payment_id = args[:payment_id]
|
49
|
+
@end_to_end_id = args[:end_to_end_id]
|
50
|
+
@status = args[:status]
|
51
|
+
@agency = args[:agency]
|
52
|
+
@number = args[:number]
|
53
|
+
@pix_key = args[:pix_key]
|
54
|
+
@value = args[:value]
|
55
|
+
@free_field = args[:free_field]
|
56
|
+
@rejection_description = args[:rejection_description]
|
57
|
+
@error_description = args[:error_description]
|
58
|
+
end
|
59
|
+
|
60
|
+
def rejected?
|
61
|
+
@status == :rejected
|
62
|
+
end
|
63
|
+
|
64
|
+
def confirmed?
|
65
|
+
@status == :confirmed
|
66
|
+
end
|
67
|
+
|
68
|
+
def error?
|
69
|
+
@status == :error
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bs2Api
|
4
|
+
module Payment
|
5
|
+
# Class used to store a bucket of requests which will be sent
|
6
|
+
# altogether.
|
7
|
+
class Async < Base
|
8
|
+
attr_reader :requests
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Check the status of a request manually. Usually we will be notified
|
12
|
+
# via webhook, but in case we do not get notification for a specific
|
13
|
+
# payment we need to start to poll the BS2 API manually.
|
14
|
+
#
|
15
|
+
# @param[String] request_id The id (SolicitacaoId) for the payment
|
16
|
+
# returned by Bs2Api::Payment::Async#call
|
17
|
+
# @param[String] client_id ID of the client issued by BS2 used for
|
18
|
+
# authorizatino. Optional, if not passed the default will be used
|
19
|
+
# @param[String] client_secret The password for the account with
|
20
|
+
# id client_id. Optional, if not passed the default will be used.
|
21
|
+
def check_payment_status(
|
22
|
+
request_id,
|
23
|
+
client_id: Bs2Api.configuration.client_id,
|
24
|
+
client_secret: Bs2Api.configuration.client_secret
|
25
|
+
)
|
26
|
+
url = request_status_url(request_id)
|
27
|
+
bearer_token = Bs2Api::Request::Auth.token(
|
28
|
+
client_id: client_id,
|
29
|
+
client_secret: client_secret
|
30
|
+
)
|
31
|
+
headers = { 'Authorization': "Bearer #{bearer_token}" }
|
32
|
+
response = HTTParty.get(url, headers: headers)
|
33
|
+
Bs2Api::Entities::AsyncStatus.from_response response.parsed_response
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# The url where one can manually check the status of an async request
|
39
|
+
#
|
40
|
+
# @param[String] request_id The id (SolicitacaoId) for the payment
|
41
|
+
# returned by Bs2Api::Payment::Async#call
|
42
|
+
def request_status_url(request_id)
|
43
|
+
"#{Bs2Api.endpoint}/pix/direto/forintegration/v1/pagamentos/chave/solicitacoes/#{request_id}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(
|
48
|
+
client_id: Bs2Api.configuration.client_id,
|
49
|
+
client_secret: Bs2Api.configuration.client_secret
|
50
|
+
)
|
51
|
+
@client_id = client_id
|
52
|
+
@client_secret = client_secret
|
53
|
+
@requests = []
|
54
|
+
end
|
55
|
+
|
56
|
+
# Push request into the request bucker. This will not send the request.
|
57
|
+
# When Bs2Api::Payment::Async#call is called all requeststs from the bucket
|
58
|
+
# will be sent simultaneously
|
59
|
+
#
|
60
|
+
# @param[Bs2Api::Entities::AsyncRequest] The async request which is going
|
61
|
+
# to be placed in the bucket
|
62
|
+
def add_request(request)
|
63
|
+
@requests << request
|
64
|
+
end
|
65
|
+
|
66
|
+
# Get the size of the bucket list
|
67
|
+
def requests_count
|
68
|
+
@requests.length
|
69
|
+
end
|
70
|
+
|
71
|
+
# The response from call differs from Payment::Base#call because
|
72
|
+
# for the async method we get 202 and a list of payment transactions IDs
|
73
|
+
# Later on we will notified via webhook for all payments transactions
|
74
|
+
# which were successful.
|
75
|
+
#
|
76
|
+
# @important The API call will fail if even one of the bucket items has
|
77
|
+
# data (PIX key, value, etc).
|
78
|
+
#
|
79
|
+
# @return[Hash] List of payments which we should expect to be confirmed via
|
80
|
+
# webhook. The response will contain field "SolicitacaoId" genreated by BS2
|
81
|
+
# this ID is used to match the payment in the webhook
|
82
|
+
def call
|
83
|
+
response = post_request
|
84
|
+
raise Bs2Api::Errors::BadRequest, ::Util::Response.parse_error(response) unless response.code == 202
|
85
|
+
|
86
|
+
response.parsed_response.map do |async_response|
|
87
|
+
Bs2Api::Entities::AsyncResponse.from_response(async_response)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# The url which will be called in order to send the bucket request for processing
|
94
|
+
def url
|
95
|
+
"#{Bs2Api.endpoint}/pix/direto/forintegration/v1/pagamentos/chave/solicitacoes"
|
96
|
+
end
|
97
|
+
|
98
|
+
def payload
|
99
|
+
{
|
100
|
+
"solicitacoes": @requests
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/bs2_api/payment/base.rb
CHANGED
@@ -16,29 +16,33 @@ module Bs2Api
|
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
}
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
19
|
+
|
20
|
+
def post_request
|
21
|
+
HTTParty.post(url, headers: headers, body: payload.to_json)
|
22
|
+
end
|
23
|
+
|
24
|
+
def headers
|
25
|
+
{
|
26
|
+
'Content-Type': 'application/json',
|
27
|
+
'Accept': 'application/json',
|
28
|
+
'Authorization': "Bearer #{bearer_token}"
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def bearer_token
|
33
|
+
Bs2Api::Request::Auth.token(
|
34
|
+
client_id: @client_id || Bs2Api.configuration.client_id,
|
35
|
+
client_secret: @client_secret || Bs2Api.configuration.client_secret
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def payload
|
40
|
+
raise NoMethodError, "Missing #{__method__} to #{self.class}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def url
|
44
|
+
raise NoMethodError, "Missing #{__method__} to #{self.class}"
|
45
|
+
end
|
42
46
|
end
|
43
47
|
end
|
44
48
|
end
|
@@ -3,7 +3,13 @@ module Bs2Api
|
|
3
3
|
class Detail < Base
|
4
4
|
attr_reader :success
|
5
5
|
|
6
|
-
def initialize
|
6
|
+
def initialize(
|
7
|
+
payment_id,
|
8
|
+
client_id: Bs2Api.configuration.client_id,
|
9
|
+
client_secret: Bs2Api.configuration.client_secret
|
10
|
+
)
|
11
|
+
@client_id = client_id
|
12
|
+
@client_secret = client_secret
|
7
13
|
@payment_id = payment_id
|
8
14
|
end
|
9
15
|
|
@@ -15,13 +21,21 @@ module Bs2Api
|
|
15
21
|
end
|
16
22
|
|
17
23
|
private
|
18
|
-
def url
|
19
|
-
"#{Bs2Api.endpoint}/pix/direto/forintegration/v1/pagamentos/#{@payment_id}"
|
20
|
-
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
def url
|
26
|
+
"#{Bs2Api.endpoint}/pix/direto/forintegration/v1/pagamentos/#{@payment_id}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def detail_request
|
30
|
+
HTTParty.get(url, headers: headers)
|
31
|
+
end
|
32
|
+
|
33
|
+
def bearer_token
|
34
|
+
Bs2Api::Request::Auth.token(
|
35
|
+
client_id: @client_id,
|
36
|
+
client_secret: @client_secret
|
37
|
+
)
|
38
|
+
end
|
25
39
|
end
|
26
40
|
end
|
27
41
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Bs2Api
|
2
|
+
module Pix
|
3
|
+
class Detail
|
4
|
+
def initialize(
|
5
|
+
client_id:,
|
6
|
+
client_secret:,
|
7
|
+
end_to_end_id:,
|
8
|
+
time_range:,
|
9
|
+
transaction_id: nil,
|
10
|
+
proxy: nil
|
11
|
+
)
|
12
|
+
@client_id = client_id
|
13
|
+
@client_secret = client_secret
|
14
|
+
@end_to_end_id = end_to_end_id
|
15
|
+
@time_range = time_range
|
16
|
+
@transaction_id = transaction_id
|
17
|
+
@proxy = proxy
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
url = "#{Bs2Api.endpoint}/pix/direto/forintegration/v1/recebimentos/#{@end_to_end_id}/recebimento"
|
22
|
+
|
23
|
+
access_token = Bs2Api::Request::Auth.token(
|
24
|
+
client_id: @client_id,
|
25
|
+
client_secret: @client_secret
|
26
|
+
)
|
27
|
+
|
28
|
+
response = HTTParty.get(
|
29
|
+
url,
|
30
|
+
http_proxyaddr: @proxy&.host,
|
31
|
+
http_proxyport: @proxy&.port,
|
32
|
+
http_proxyuser: @proxy&.user,
|
33
|
+
http_proxypass: @proxy&.password,
|
34
|
+
headers: {
|
35
|
+
'Content-Type' => 'application/json',
|
36
|
+
'Accept' => 'application/json',
|
37
|
+
'Authorization' => "Bearer #{access_token}",
|
38
|
+
},
|
39
|
+
query: {
|
40
|
+
Inicio: @time_range.begin.iso8601,
|
41
|
+
Fim: @time_range.end.iso8601,
|
42
|
+
TxId: @transaction_id,
|
43
|
+
}
|
44
|
+
)
|
45
|
+
|
46
|
+
raise response.body unless response.success?
|
47
|
+
|
48
|
+
response.body
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bs2Api
|
4
|
+
module Refund
|
5
|
+
module Pix
|
6
|
+
class Create
|
7
|
+
def initialize(
|
8
|
+
client_id:,
|
9
|
+
client_secret:,
|
10
|
+
end_to_end_id:,
|
11
|
+
transaction_id:,
|
12
|
+
value:,
|
13
|
+
proxy: nil
|
14
|
+
)
|
15
|
+
@client_id = client_id
|
16
|
+
@client_secret = client_secret
|
17
|
+
@end_to_end_id = end_to_end_id
|
18
|
+
@transaction_id = transaction_id
|
19
|
+
@value = value
|
20
|
+
@proxy = proxy
|
21
|
+
end
|
22
|
+
|
23
|
+
# https://devs.bs2.com/manual/pix-clientes/#tag/Devolucoes-Cliente/paths/~1pix~1direto~1forintegration~1v1~1pix~1{e2eid}~1devolucao~1{idExterno}/put
|
24
|
+
def call
|
25
|
+
url = "#{Bs2Api.endpoint}/pix/direto/forintegration/v1/pix/#{@end_to_end_id}/devolucao/#{@transaction_id}"
|
26
|
+
|
27
|
+
access_token = Bs2Api::Request::Auth.token(
|
28
|
+
client_id: @client_id,
|
29
|
+
client_secret: @client_secret
|
30
|
+
)
|
31
|
+
|
32
|
+
# TODO: is PUT the right method?
|
33
|
+
response = HTTParty.put(
|
34
|
+
url,
|
35
|
+
http_proxyaddr: @proxy&.host,
|
36
|
+
http_proxyport: @proxy&.port,
|
37
|
+
http_proxyuser: @proxy&.user,
|
38
|
+
http_proxypass: @proxy&.password,
|
39
|
+
headers: {
|
40
|
+
'Content-Type' => 'application/json',
|
41
|
+
'Accept' => 'application/json',
|
42
|
+
'Authorization' => "Bearer #{access_token}",
|
43
|
+
},
|
44
|
+
body: {
|
45
|
+
valor: value
|
46
|
+
}.to_json
|
47
|
+
)
|
48
|
+
|
49
|
+
raise response.body unless response.success?
|
50
|
+
|
51
|
+
response.body
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Bs2Api
|
2
|
+
module Refund
|
3
|
+
module Pix
|
4
|
+
class Detail
|
5
|
+
STATUSES = {
|
6
|
+
'EM_PROCESSAMENTO' => :processing,
|
7
|
+
'DEVOLVIDO' => :refunded,
|
8
|
+
'NAO_REALIZADO' => :not_achieved,
|
9
|
+
}.transform_keys(&:downcase).freeze
|
10
|
+
|
11
|
+
def initialize(
|
12
|
+
client_id:,
|
13
|
+
client_secret:,
|
14
|
+
end_to_end_id:,
|
15
|
+
transaction_id:,
|
16
|
+
proxy: nil
|
17
|
+
)
|
18
|
+
@client_id = client_id
|
19
|
+
@client_secret = client_secret
|
20
|
+
@end_to_end_id = end_to_end_id
|
21
|
+
@transaction_id = transaction_id
|
22
|
+
@proxy = proxy
|
23
|
+
end
|
24
|
+
|
25
|
+
# https://devs.bs2.com/manual/pix-clientes/#tag/Devolucoes-Cliente/paths/~1pix~1direto~1forintegration~1v1~1pix~1{e2eid}~1devolucao~1{idExterno}/get
|
26
|
+
def call
|
27
|
+
url = "#{Bs2Api.endpoint}/pix/direto/forintegration/v1/pix/#{@end_to_end_id}/devolucao/#{@transaction_id}"
|
28
|
+
|
29
|
+
access_token = Bs2Api::Request::Auth.token(
|
30
|
+
client_id: @client_id,
|
31
|
+
client_secret: @client_secret
|
32
|
+
)
|
33
|
+
|
34
|
+
response = HTTParty.get(
|
35
|
+
url,
|
36
|
+
http_proxyaddr: @proxy&.host,
|
37
|
+
http_proxyport: @proxy&.port,
|
38
|
+
http_proxyuser: @proxy&.user,
|
39
|
+
http_proxypass: @proxy&.password,
|
40
|
+
headers: {
|
41
|
+
'Content-Type' => 'application/json',
|
42
|
+
'Accept' => 'application/json',
|
43
|
+
'Authorization' => "Bearer #{access_token}",
|
44
|
+
}
|
45
|
+
)
|
46
|
+
|
47
|
+
raise response.body unless response.success?
|
48
|
+
|
49
|
+
response.body
|
50
|
+
end
|
51
|
+
|
52
|
+
def status
|
53
|
+
@status ||= STATUSES.fetch(call.fetch('status'))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/bs2_api/request/auth.rb
CHANGED
@@ -3,28 +3,55 @@
|
|
3
3
|
module Bs2Api
|
4
4
|
module Request
|
5
5
|
class Auth
|
6
|
+
# TODO: See which scopes are required.
|
7
|
+
SCOPES = [
|
8
|
+
'saldo',
|
9
|
+
'extrato',
|
10
|
+
'pagamento',
|
11
|
+
'transferencia',
|
12
|
+
'cobv.write',
|
13
|
+
'cobv.read',
|
14
|
+
'comprovante',
|
15
|
+
'webhook-mov-conta',
|
16
|
+
'aprovacoes',
|
17
|
+
'pagamento-tributo',
|
18
|
+
'webhook-conclusao-transf',
|
19
|
+
'webhook-conclusao-pag',
|
20
|
+
'cob.write',
|
21
|
+
'cob.read',
|
22
|
+
'pix.write',
|
23
|
+
'pix.read',
|
24
|
+
'dict.write',
|
25
|
+
'dict.read',
|
26
|
+
'webhook.read',
|
27
|
+
'webhook.write',
|
28
|
+
].freeze
|
29
|
+
|
6
30
|
class << self
|
7
|
-
def token
|
31
|
+
def token(
|
32
|
+
client_id: Bs2Api.configuration.client_id,
|
33
|
+
client_secret: Bs2Api.configuration.client_secret
|
34
|
+
)
|
8
35
|
Bs2Api.configuration.valid?
|
9
36
|
|
10
|
-
response = create_session
|
37
|
+
response = create_session(client_id, client_secret)
|
11
38
|
|
12
|
-
raise Bs2Api::Errors::Unauthorized, response[
|
13
|
-
raise Bs2Api::Errors::BadRequest, response[
|
14
|
-
raise Bs2Api::Errors::ServerError, response.body
|
39
|
+
raise Bs2Api::Errors::Unauthorized, response['error_description'] if response.unauthorized?
|
40
|
+
raise Bs2Api::Errors::BadRequest, response['error_description'] if response.bad_request?
|
41
|
+
raise Bs2Api::Errors::ServerError, response.body unless response.success?
|
15
42
|
|
16
|
-
response[
|
43
|
+
response['access_token']
|
17
44
|
end
|
18
45
|
|
19
46
|
private
|
20
|
-
def create_session
|
47
|
+
def create_session(client_id, client_secret)
|
21
48
|
HTTParty.post(
|
22
49
|
auth_url,
|
23
50
|
headers: headers,
|
24
51
|
body: body,
|
25
52
|
basic_auth: {
|
26
|
-
username:
|
27
|
-
password:
|
53
|
+
username: client_id,
|
54
|
+
password: client_secret
|
28
55
|
}
|
29
56
|
)
|
30
57
|
end
|
@@ -39,14 +66,14 @@ module Bs2Api
|
|
39
66
|
def body
|
40
67
|
{
|
41
68
|
grant_type: "client_credentials",
|
42
|
-
scope:
|
69
|
+
scope: SCOPES.join("\s")
|
43
70
|
}.to_query
|
44
71
|
end
|
45
72
|
|
46
73
|
def auth_url
|
47
74
|
"#{Bs2Api.endpoint}/auth/oauth/v2/token"
|
48
75
|
end
|
49
|
-
|
76
|
+
end
|
50
77
|
end
|
51
78
|
end
|
52
79
|
end
|
data/lib/bs2_api/version.rb
CHANGED
data/lib/bs2_api.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
5
|
+
require 'active_support/core_ext/hash/except'
|
6
|
+
require 'active_support/core_ext/object/to_query'
|
7
|
+
require 'active_support/core_ext/object/blank'
|
7
8
|
|
8
9
|
require 'bs2_api/version'
|
9
10
|
require 'bs2_api/configuration'
|
@@ -26,20 +27,28 @@ require 'bs2_api/entities/bank'
|
|
26
27
|
require 'bs2_api/entities/customer'
|
27
28
|
require 'bs2_api/entities/payment'
|
28
29
|
require 'bs2_api/entities/pix_key'
|
30
|
+
require 'bs2_api/entities/async_request'
|
31
|
+
require 'bs2_api/entities/async_response'
|
32
|
+
require 'bs2_api/entities/async_status'
|
29
33
|
|
30
34
|
require 'bs2_api/payment/base'
|
31
35
|
require 'bs2_api/payment/key'
|
32
36
|
require 'bs2_api/payment/manual'
|
33
37
|
require 'bs2_api/payment/confirmation'
|
34
38
|
require 'bs2_api/payment/detail'
|
39
|
+
require 'bs2_api/payment/async'
|
35
40
|
|
36
41
|
require 'bs2_api/request/auth'
|
37
42
|
|
43
|
+
|
44
|
+
require 'bs2_api/refund/pix/create'
|
45
|
+
require 'bs2_api/refund/pix/detail'
|
46
|
+
|
38
47
|
module Bs2Api
|
39
48
|
ENDPOINT = {
|
40
49
|
production: 'https://api.bs2.com',
|
41
50
|
sandbox: 'https://apihmz.bancobonsucesso.com.br'
|
42
|
-
}
|
51
|
+
}.freeze
|
43
52
|
|
44
53
|
class << self
|
45
54
|
attr_writer :configuration
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bs2_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kim Pastro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: builder
|
@@ -201,6 +201,9 @@ files:
|
|
201
201
|
- lib/bs2_api.rb
|
202
202
|
- lib/bs2_api/configuration.rb
|
203
203
|
- lib/bs2_api/entities/account.rb
|
204
|
+
- lib/bs2_api/entities/async_request.rb
|
205
|
+
- lib/bs2_api/entities/async_response.rb
|
206
|
+
- lib/bs2_api/entities/async_status.rb
|
204
207
|
- lib/bs2_api/entities/bank.rb
|
205
208
|
- lib/bs2_api/entities/customer.rb
|
206
209
|
- lib/bs2_api/entities/payment.rb
|
@@ -215,11 +218,15 @@ files:
|
|
215
218
|
- lib/bs2_api/errors/missing_configuration.rb
|
216
219
|
- lib/bs2_api/errors/server_error.rb
|
217
220
|
- lib/bs2_api/errors/unauthorized.rb
|
221
|
+
- lib/bs2_api/payment/async.rb
|
218
222
|
- lib/bs2_api/payment/base.rb
|
219
223
|
- lib/bs2_api/payment/confirmation.rb
|
220
224
|
- lib/bs2_api/payment/detail.rb
|
221
225
|
- lib/bs2_api/payment/key.rb
|
222
226
|
- lib/bs2_api/payment/manual.rb
|
227
|
+
- lib/bs2_api/pix/detail.rb
|
228
|
+
- lib/bs2_api/refund/pix/create.rb
|
229
|
+
- lib/bs2_api/refund/pix/detail.rb
|
223
230
|
- lib/bs2_api/request/auth.rb
|
224
231
|
- lib/bs2_api/util/response.rb
|
225
232
|
- lib/bs2_api/version.rb
|