solidus_sicoob 0.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/models/solidus_sicoob/gateway.rb +25 -13
- data/app/models/solidus_sicoob/pix_payment_source.rb +16 -20
- data/app/models/solidus_sicoob/sicoob_client.rb +54 -0
- data/app/models/solidus_sicoob/sicoob_pix.rb +116 -74
- data/lib/solidus_sicoob/version.rb +1 -1
- data/lib/solidus_sicoob.rb +1 -0
- metadata +18 -7
- data/app/models/solidus_sicoob/account.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7a4f9670199d754eaa022b29ea83a32fb129dfa21f2ed1f73e3f76801012154
|
4
|
+
data.tar.gz: 0aa13e2ac755ad8057db230b794a7d00a91b5d1d0b0a4e2788e97d13f4615aa5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c59f36b5cc30bc52b1bf7e1af12030b81a838b17a02df27a88c11bce71d84e54a82910465fec933d57c11d903fc8bfb4798f954137518a26bf931c6c8a5fdce1
|
7
|
+
data.tar.gz: 43c49c1ee24e96c535007c66bcd5f71108e5755cfd3a0c361824f45ec7f43a58e9f5fa9264e059b487410fb6addf1b27fbd44e2c6227459ddd730fe49e091169
|
@@ -3,23 +3,33 @@ module SolidusSicoob
|
|
3
3
|
def initialize(options)
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
successful_response("Pagamento realizado", sicoob_payment.txid)
|
11
|
-
else
|
12
|
-
failure_response(sicoob_payment.internal_error || "Ocorreu um erro no pagamento.")
|
13
|
-
end
|
6
|
+
def void(transaction_id, options = {})
|
7
|
+
# Respondendo com falha pois atualmente todo pedido concluido ja teve seu pagamento processado
|
8
|
+
# e nesse caso o credit é mais adequado (Ao cancelar um pedido pela interface, o 'void' é chamado, se ele retornar falha o Solidus chama o 'credit')
|
9
|
+
failure_response("Pagamento já processado")
|
14
10
|
end
|
15
11
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
12
|
+
def credit(money, transaction_id, options = {})
|
13
|
+
payment = Spree::Payment.find_by(response_code: transaction_id)
|
14
|
+
payment_source = payment.source
|
15
|
+
refund = payment_source.refund!(amount: converted_money(money))
|
16
|
+
if refund.status == "DEVOLVIDO"
|
17
|
+
response = successful_response("Pagamento reembolsado (#{refund.status})", transaction_id)
|
18
|
+
payment.log_entries.create(parsed_payment_response_details_with_fallback: response)
|
19
|
+
successful_response("Reembolso realizado", refund.id)
|
20
|
+
else
|
21
|
+
response = successful_response("Pagamento não reembolsado - #{refund.status} - #{refund.try(:motivo)}", transaction_id)
|
22
|
+
payment.log_entries.create(parsed_payment_response_details_with_fallback: response)
|
23
|
+
successful_response("Erro ao reembolsar", refund.id)
|
24
|
+
end
|
19
25
|
end
|
20
26
|
|
21
27
|
private
|
22
28
|
|
29
|
+
def converted_money(money)
|
30
|
+
money / 100.0
|
31
|
+
end
|
32
|
+
|
23
33
|
def successful_response(message, transaction_id)
|
24
34
|
ActiveMerchant::Billing::Response.new(
|
25
35
|
true,
|
@@ -29,10 +39,12 @@ module SolidusSicoob
|
|
29
39
|
)
|
30
40
|
end
|
31
41
|
|
32
|
-
def failure_response(message)
|
42
|
+
def failure_response(message, transaction_id = nil)
|
33
43
|
ActiveMerchant::Billing::Response.new(
|
34
44
|
false,
|
35
|
-
message
|
45
|
+
message,
|
46
|
+
{},
|
47
|
+
authorization: transaction_id
|
36
48
|
)
|
37
49
|
end
|
38
50
|
end
|
@@ -1,21 +1,5 @@
|
|
1
1
|
module SolidusSicoob
|
2
2
|
class PixPaymentSource < Spree::PaymentSource
|
3
|
-
def actions
|
4
|
-
%w[]
|
5
|
-
end
|
6
|
-
|
7
|
-
def can_capture?(payment)
|
8
|
-
payment.pending? || payment.checkout?
|
9
|
-
end
|
10
|
-
|
11
|
-
def can_void?(payment)
|
12
|
-
payment.can_void?
|
13
|
-
end
|
14
|
-
|
15
|
-
def can_credit?(payment)
|
16
|
-
payment.completed? && payment.credit_allowed > 0
|
17
|
-
end
|
18
|
-
|
19
3
|
def expired?
|
20
4
|
expiration.nil? || expiration.past?
|
21
5
|
end
|
@@ -29,12 +13,24 @@ module SolidusSicoob
|
|
29
13
|
end
|
30
14
|
|
31
15
|
def paid?
|
32
|
-
|
33
|
-
|
16
|
+
payment_method.pix_paid?(payments.sole)
|
17
|
+
end
|
18
|
+
|
19
|
+
def void!
|
20
|
+
payment_method.invalidate_payment(payments.sole)
|
21
|
+
end
|
22
|
+
|
23
|
+
def refund!(amount: nil)
|
24
|
+
payment_method.refund_payment(payments.sole, amount: amount)
|
34
25
|
end
|
35
26
|
|
36
|
-
|
37
|
-
|
27
|
+
# Definir para sempre false pois atualmente não implementados o void do Solidus
|
28
|
+
def can_void?(payment)
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
def can_credit?(payment)
|
33
|
+
payment.completed? && payment.credit_allowed > 0
|
38
34
|
end
|
39
35
|
end
|
40
36
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module SolidusSicoob
|
2
|
+
class SicoobClient
|
3
|
+
def self.for_payment_method(payment_method)
|
4
|
+
client_class = payment_method.preferred_test_mode ? SicoobClientSandbox : SicoobClientProduction
|
5
|
+
client_class.new(payment_method)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module PaymentMethodSyncable
|
10
|
+
attr_accessor :payment_method
|
11
|
+
|
12
|
+
def initialize(payment_method)
|
13
|
+
@payment_method = payment_method
|
14
|
+
super(
|
15
|
+
client_id: payment_method.preferred_client_id,
|
16
|
+
chave_pix: payment_method.preferred_chave_pix,
|
17
|
+
crt: temp_file(payment_method.preferred_crt).path,
|
18
|
+
key: temp_file(payment_method.preferred_key).path,
|
19
|
+
access_token: payment_method.preferred_access_token,
|
20
|
+
token_expires_at: payment_method.preferred_token_expires_at.to_datetime,
|
21
|
+
test_mode: payment_method.preferred_test_mode
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def refresh_token
|
26
|
+
super
|
27
|
+
sync_payment_method_tokens
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def sync_payment_method_tokens
|
33
|
+
payment_method.update!(
|
34
|
+
preferred_access_token: access_token,
|
35
|
+
preferred_token_expires_at: token_expires_at
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def temp_file(content)
|
40
|
+
t = Tempfile.new
|
41
|
+
t << content
|
42
|
+
t.close
|
43
|
+
t
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class SicoobClientSandbox < ::SicoobApi::ClientSandbox
|
48
|
+
include PaymentMethodSyncable
|
49
|
+
end
|
50
|
+
|
51
|
+
class SicoobClientProduction < ::SicoobApi::ClientProduction
|
52
|
+
include PaymentMethodSyncable
|
53
|
+
end
|
54
|
+
end
|
@@ -4,6 +4,8 @@ module SolidusSicoob
|
|
4
4
|
preference :chave_pix, :string
|
5
5
|
preference :crt, :text
|
6
6
|
preference :key, :text
|
7
|
+
preference :access_token, :string
|
8
|
+
preference :token_expires_at, :string
|
7
9
|
|
8
10
|
def payment_source_class
|
9
11
|
PixPaymentSource
|
@@ -26,24 +28,22 @@ module SolidusSicoob
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def find_payment(txid)
|
29
|
-
|
30
|
-
client.get_payment(txid)
|
31
|
+
sicoob_client.get_payment(txid)
|
31
32
|
end
|
32
33
|
|
33
34
|
def webhook
|
34
|
-
|
35
|
-
client.get_webhook
|
35
|
+
sicoob_client.get_webhook
|
36
36
|
end
|
37
37
|
|
38
38
|
def update_webhook(url)
|
39
|
-
|
40
|
-
|
41
|
-
client.get_webhook
|
39
|
+
sicoob_client.update_webhook(url)
|
40
|
+
sicoob_client.get_webhook
|
42
41
|
end
|
43
42
|
|
44
43
|
def create_payment(order)
|
45
44
|
existing_payment = find_existing_payment(order)
|
46
45
|
return existing_payment if payment_is_usable?(existing_payment, order)
|
46
|
+
invalidate_valid_payments(order, existing_payment&.id)
|
47
47
|
|
48
48
|
payment = order.payments.new(amount: order.total, payment_method: self)
|
49
49
|
payment.source = init_source(order)
|
@@ -54,31 +54,52 @@ module SolidusSicoob
|
|
54
54
|
payment
|
55
55
|
end
|
56
56
|
|
57
|
-
def
|
58
|
-
|
57
|
+
def purchase(money, source, _options = {})
|
58
|
+
sicoob_payment = source.retrieve_from_api
|
59
|
+
sync(source.payments.sole, sicoob_payment)
|
60
|
+
if sicoob_payment.status == "CONCLUIDA"
|
61
|
+
successful_response("Pagamento realizado", status: source.status, internal_detail: "")
|
62
|
+
else
|
63
|
+
failure_response("Pagamento não realizado", status: source.status, internal_detail: "")
|
64
|
+
end
|
65
|
+
end
|
59
66
|
|
60
|
-
|
61
|
-
|
67
|
+
def invalidate_payment(payment)
|
68
|
+
txid = payment.source&.txid
|
69
|
+
return false if txid.nil?
|
70
|
+
sicoob_payment = find_payment(payment.source.txid)
|
71
|
+
sync(payment, sicoob_payment)
|
72
|
+
return false unless payment.checkout?
|
62
73
|
|
63
|
-
sicoob_payment.
|
64
|
-
|
65
|
-
|
74
|
+
sicoob_payment = sicoob_client.update_payment(payment_id: txid, status: "REMOVIDA_PELO_USUARIO_RECEBEDOR")
|
75
|
+
sync(payment, sicoob_payment)
|
76
|
+
end
|
77
|
+
|
78
|
+
def pix_paid? payment
|
79
|
+
return false unless payment.source&.txid
|
80
|
+
sicoob_payment = find_payment(payment.source.txid)
|
81
|
+
paid_amount = total_paid(sicoob_payment)
|
82
|
+
sicoob_payment.status == "CONCLUIDA" && paid_amount >= payment.amount
|
66
83
|
end
|
67
84
|
|
68
|
-
def
|
69
|
-
|
85
|
+
def refund_payment(payment, amount: nil, refund_nature: nil, description: nil)
|
86
|
+
amount ||= payment.amount
|
87
|
+
refund_nature ||= "ORIGINAL"
|
88
|
+
sicoob_client.refund_payment(end_to_end_id: payment.source.e2e_id, amount: amount, refund_nature: refund_nature, description: description)
|
70
89
|
end
|
71
90
|
|
72
|
-
def
|
73
|
-
|
74
|
-
!inter_payment.paid?
|
91
|
+
def puts_qrcode(payment)
|
92
|
+
puts RQRCode::QRCode.new(payment.pix_code).to_s(dark: "██", light: " ")
|
75
93
|
end
|
76
94
|
|
77
95
|
private
|
78
96
|
|
97
|
+
def sicoob_client
|
98
|
+
SicoobClient.for_payment_method(self)
|
99
|
+
end
|
100
|
+
|
79
101
|
def create_sicoob_payment(payment_source)
|
80
|
-
|
81
|
-
client.create_payment(
|
102
|
+
sicoob_client.create_payment(
|
82
103
|
amount: payment_source.amount,
|
83
104
|
payer_tax_id: payment_source.payer_tax_id,
|
84
105
|
payer_name: payment_source.payer_name,
|
@@ -87,7 +108,8 @@ module SolidusSicoob
|
|
87
108
|
end
|
88
109
|
|
89
110
|
def find_existing_payment(order)
|
90
|
-
|
111
|
+
available_payments = order.payments.where(state: ["checkout", "pending"])
|
112
|
+
pix_payments = available_payments.where(payment_method: self)
|
91
113
|
raise "More than one valid payment for #{order.number}" if pix_payments.count > 1
|
92
114
|
|
93
115
|
pix_payments.first
|
@@ -99,85 +121,105 @@ module SolidusSicoob
|
|
99
121
|
payment.source.active? && payment.amount == order.total
|
100
122
|
end
|
101
123
|
|
124
|
+
def init_source(order)
|
125
|
+
PixPaymentSource.new(
|
126
|
+
amount: order.total,
|
127
|
+
payer_name: order.ship_address.name,
|
128
|
+
payer_tax_id: order.tax_id,
|
129
|
+
payment_method: self
|
130
|
+
)
|
131
|
+
end
|
132
|
+
|
102
133
|
def process_payment_response(payment, sicoob_payment)
|
103
134
|
payment.update(response_code: sicoob_payment.txid)
|
104
135
|
payment.source.update(
|
105
136
|
txid: sicoob_payment.txid,
|
106
|
-
pix_code: sicoob_payment.
|
107
|
-
qr_code_svg: sicoob_payment
|
137
|
+
pix_code: sicoob_payment.brcode || sicoob_payment.qrCode,
|
138
|
+
qr_code_svg: qr_code(sicoob_payment),
|
108
139
|
status: sicoob_payment.status,
|
109
|
-
expiration: sicoob_payment
|
140
|
+
expiration: expiration_date(sicoob_payment)
|
110
141
|
)
|
111
|
-
|
112
|
-
|
113
|
-
handle_payment_error(payment, sicoob_payment)
|
114
|
-
else
|
115
|
-
update_payment_status(payment, sicoob_payment)
|
116
|
-
end
|
142
|
+
payment.update(response_code: sicoob_payment.txid)
|
143
|
+
sync(payment, sicoob_payment)
|
117
144
|
end
|
118
145
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
146
|
+
def sync(payment, sicoob_payment)
|
147
|
+
paid_amount = total_paid(sicoob_payment)
|
148
|
+
payment.source.update!(status: sicoob_payment.status, paid_amount: paid_amount, e2e_id: end_to_end(sicoob_payment))
|
149
|
+
|
150
|
+
if sicoob_payment.status == "CONCLUIDA" && paid_amount >= payment.amount
|
151
|
+
approve_payment(payment)
|
152
|
+
elsif sicoob_payment.status == "CONCLUIDA"
|
153
|
+
raise "Payment paid with value less than the created - #{sicoob_payment.txid}"
|
154
|
+
elsif sicoob_payment.status != "ATIVA" || payment.source.expired?
|
155
|
+
invalid_payment(payment)
|
122
156
|
end
|
123
|
-
payment.source.update(status: status)
|
124
157
|
end
|
125
158
|
|
126
|
-
def
|
127
|
-
payment.
|
128
|
-
|
129
|
-
|
159
|
+
def approve_payment(payment)
|
160
|
+
payment.complete
|
161
|
+
payment_source = payment.source
|
162
|
+
payment_source.update! status: payment.state
|
163
|
+
response = successful_response("Pagamento realizado", status: payment_source.status, internal_detail: "")
|
130
164
|
payment.log_entries.create(parsed_payment_response_details_with_fallback: response)
|
131
|
-
payment.source.update(internal_error: error_message, status: "error")
|
132
165
|
end
|
133
166
|
|
134
|
-
def
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
end
|
167
|
+
def invalid_payment payment
|
168
|
+
return false unless payment.checkout?
|
169
|
+
if payment.checkout?
|
170
|
+
payment.invalidate!
|
171
|
+
else
|
172
|
+
payment.failure!
|
173
|
+
end
|
142
174
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
chave_pix: preferences[:chave_pix],
|
148
|
-
crt: temp_file(preferences[:crt]).path,
|
149
|
-
key: temp_file(preferences[:key]).path,
|
150
|
-
token: account&.token,
|
151
|
-
token_expires_at: account&.expires_at
|
152
|
-
)
|
153
|
-
SolidusSicoob::Account.upsert(
|
154
|
-
{token: client.token, expires_at: client.token_expires_at, chave_pix: client.chave_pix,
|
155
|
-
spree_payment_method_id: id}, unique_by: :chave_pix
|
156
|
-
)
|
157
|
-
client
|
175
|
+
payment_source = payment.source
|
176
|
+
payment_source.update!(status: payment.state)
|
177
|
+
response = failure_response("Pagamento invalidado", status: payment_source.status, internal_detail: "")
|
178
|
+
payment.log_entries.create(parsed_payment_response_details_with_fallback: response)
|
158
179
|
end
|
159
180
|
|
160
|
-
def
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
181
|
+
def invalidate_valid_payments order, existing_payment_id
|
182
|
+
available_payments = order.payments.where(state: ["checkout", "pending"])
|
183
|
+
available_payments.where.not(id: existing_payment_id).each do |payment|
|
184
|
+
payment.source.void!
|
185
|
+
end
|
165
186
|
end
|
166
187
|
|
167
|
-
def successful_response
|
188
|
+
def successful_response message, status:, internal_detail:
|
189
|
+
full_message = message + " - " + status + ": " + internal_detail
|
168
190
|
ActiveMerchant::Billing::Response.new(
|
169
191
|
true,
|
170
|
-
|
171
|
-
{},
|
172
|
-
authorization: transaction_id
|
192
|
+
full_message
|
173
193
|
)
|
174
194
|
end
|
175
195
|
|
176
|
-
def failure_response
|
196
|
+
def failure_response message, status:, internal_detail:
|
197
|
+
full_message = message + " - " + status + ": " + internal_detail
|
177
198
|
ActiveMerchant::Billing::Response.new(
|
178
199
|
false,
|
179
|
-
|
200
|
+
full_message
|
180
201
|
)
|
181
202
|
end
|
203
|
+
|
204
|
+
def qr_code(sicoob_payment, module_size: 4)
|
205
|
+
code = sicoob_payment.brcode || sicoob_payment.qrCode
|
206
|
+
qr = RQRCode::QRCode.new(code, size: 10, level: :l)
|
207
|
+
qr.as_svg(module_size: module_size)
|
208
|
+
end
|
209
|
+
|
210
|
+
def expiration_date(sicoob_payment)
|
211
|
+
return nil unless sicoob_payment.calendario.criacao
|
212
|
+
Time.new(sicoob_payment.calendario.criacao) + sicoob_payment.calendario.expiracao
|
213
|
+
end
|
214
|
+
|
215
|
+
def total_paid(sicoob_payment)
|
216
|
+
return nil unless sicoob_payment["pix"] && sicoob_payment.pix.any?
|
217
|
+
Float(sicoob_payment.pix[0].valor)
|
218
|
+
end
|
219
|
+
|
220
|
+
def end_to_end(sicoob_payment)
|
221
|
+
return nil unless sicoob_payment["pix"] && sicoob_payment.pix.any?
|
222
|
+
sicoob_payment.pix[0].endToEndId
|
223
|
+
end
|
182
224
|
end
|
183
225
|
end
|
data/lib/solidus_sicoob.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solidus_sicoob
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hamilton
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: solidus_core
|
@@ -66,6 +65,20 @@ dependencies:
|
|
66
65
|
- - ">="
|
67
66
|
- !ruby/object:Gem::Version
|
68
67
|
version: '0'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: rqrcode
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
69
82
|
description: ''
|
70
83
|
email: hamilton@todasessascoisas.com.br
|
71
84
|
executables: []
|
@@ -73,9 +86,9 @@ extensions: []
|
|
73
86
|
extra_rdoc_files: []
|
74
87
|
files:
|
75
88
|
- README.md
|
76
|
-
- app/models/solidus_sicoob/account.rb
|
77
89
|
- app/models/solidus_sicoob/gateway.rb
|
78
90
|
- app/models/solidus_sicoob/pix_payment_source.rb
|
91
|
+
- app/models/solidus_sicoob/sicoob_client.rb
|
79
92
|
- app/models/solidus_sicoob/sicoob_pix.rb
|
80
93
|
- app/views/spree/admin/payments/source_forms/_sicoob_pix.html.erb
|
81
94
|
- app/views/spree/admin/payments/source_views/_sicoob_pix.html.erb
|
@@ -89,7 +102,6 @@ files:
|
|
89
102
|
homepage: https://github.com/todasessascoisas/solidus_sicoob
|
90
103
|
licenses: []
|
91
104
|
metadata: {}
|
92
|
-
post_install_message:
|
93
105
|
rdoc_options: []
|
94
106
|
require_paths:
|
95
107
|
- lib
|
@@ -107,8 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
119
|
- !ruby/object:Gem::Version
|
108
120
|
version: '0'
|
109
121
|
requirements: []
|
110
|
-
rubygems_version: 3.
|
111
|
-
signing_key:
|
122
|
+
rubygems_version: 3.6.9
|
112
123
|
specification_version: 4
|
113
124
|
summary: ''
|
114
125
|
test_files: []
|