perata-sdk 0.1.1 → 0.2.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/README.md +9 -1
- data/lib/perata/client.rb +3 -0
- data/lib/perata/models.rb +298 -4
- data/lib/perata/params.rb +20 -0
- data/lib/perata/services.rb +16 -0
- data/lib/perata/version.rb +1 -1
- data/lib/perata/webhooks.rb +90 -12
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e636bdc22e1cf5cb23c0d1b1f93f3154362b6ada48dcc56e780847de36f578f7
|
|
4
|
+
data.tar.gz: a29323a115321b71d10b6031b7170c6fda3e7d23e192ba1463e29afcc519d51f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5b88a3f310e277f889147d95801565704b294120a2d6dc0f9809ced9c214753c8638b3b50e5deeb94fb2c785d811fe1759de836246b41e7652352c7aa4b92532
|
|
7
|
+
data.tar.gz: b3f215424482e048dc8c24ef20262938d3f1808795573f91c9c4684529f3bd17b6992625d484106c5ebc40f92c258cdfe1a6319839e244926e7f10842300dd08
|
data/README.md
CHANGED
|
@@ -23,6 +23,7 @@ end
|
|
|
23
23
|
| Serviço | Métodos |
|
|
24
24
|
|---|---|
|
|
25
25
|
| `perata.checkouts` | `create` |
|
|
26
|
+
| `perata.customer_sessions` | `create` |
|
|
26
27
|
| `perata.customers` | `create`, `get`, `list`, `list_iter` |
|
|
27
28
|
| `perata.orders` | `list`, `list_iter` |
|
|
28
29
|
| `perata.payment_methods` | `detach`, `list`, `list_iter` |
|
|
@@ -44,8 +45,15 @@ Uma recusa da API levanta `Perata::Error`, com `status`, `code` (`invalid_reques
|
|
|
44
45
|
|
|
45
46
|
```ruby
|
|
46
47
|
event = Perata.verify_webhook(ENV.fetch("PERATA_WEBHOOK_SECRET"), request.headers, request.raw_post)
|
|
48
|
+
case event
|
|
49
|
+
when Perata::OrderWebhookEvent then puts event.type, event.data.id, event.data.installments
|
|
50
|
+
when Perata::DisputeWebhookEvent then puts event.data.provider_dispute_id
|
|
51
|
+
when Perata::UnknownWebhookEvent then nil # um tipo que esta versão ainda não conhece: event.data é o JSON
|
|
52
|
+
end
|
|
47
53
|
```
|
|
48
54
|
|
|
49
55
|
A assinatura é a do Standard Webhooks (`webhook-id`, `webhook-timestamp`, `webhook-signature`), com tolerância de 5 minutos. Passe o corpo cru, antes de interpretar; os cabeçalhos podem vir num `Hash` ou no env do Rack. Uma assinatura que não confere levanta `Perata::WebhookVerificationError`.
|
|
50
56
|
|
|
51
|
-
|
|
57
|
+
O evento é tipado: um tipo para cada dado que o webhook carrega (`OrderWebhookEvent` traz um `Order`, `DisputeWebhookEvent` a disputa, `IdentifiersWebhookEvent` os identificadores…), e o `type` diz o que aconteceu; um tipo que esta versão do SDK ainda não conhece chega como `UnknownWebhookEvent`, com os dados como vieram. Durante a rotação do segredo o cabeçalho traz mais de uma assinatura, e basta uma conferir. `Perata.verify_webhook_signature` só confere a assinatura.
|
|
58
|
+
|
|
59
|
+
Versão do SDK: 0.2.0 · contrato da API: 0.1.0
|
data/lib/perata/client.rb
CHANGED
|
@@ -32,6 +32,8 @@ module Perata
|
|
|
32
32
|
class Client
|
|
33
33
|
# @return [CheckoutsService]
|
|
34
34
|
attr_reader :checkouts
|
|
35
|
+
# @return [CustomerSessionsService]
|
|
36
|
+
attr_reader :customer_sessions
|
|
35
37
|
# @return [CustomersService]
|
|
36
38
|
attr_reader :customers
|
|
37
39
|
# @return [OrdersService]
|
|
@@ -55,6 +57,7 @@ module Perata
|
|
|
55
57
|
@timeout = timeout
|
|
56
58
|
@transport = transport
|
|
57
59
|
@checkouts = CheckoutsService.new(self)
|
|
60
|
+
@customer_sessions = CustomerSessionsService.new(self)
|
|
58
61
|
@customers = CustomersService.new(self)
|
|
59
62
|
@orders = OrdersService.new(self)
|
|
60
63
|
@payment_methods = PaymentMethodsService.new(self)
|
data/lib/perata/models.rb
CHANGED
|
@@ -3,6 +3,71 @@
|
|
|
3
3
|
# Code generated by sdk/generator. DO NOT EDIT.
|
|
4
4
|
|
|
5
5
|
module Perata
|
|
6
|
+
# BenefitGrant is a resource of Peráta's API.
|
|
7
|
+
class BenefitGrant < Model
|
|
8
|
+
MEMBERS = %i[benefit_id benefit_type created_at customer_id granted_at id is_granted is_revoked revoked_at status].freeze
|
|
9
|
+
|
|
10
|
+
# @return [String]
|
|
11
|
+
attr_reader :benefit_id
|
|
12
|
+
|
|
13
|
+
# @return [String]
|
|
14
|
+
attr_reader :benefit_type
|
|
15
|
+
|
|
16
|
+
# @return [String]
|
|
17
|
+
attr_reader :created_at
|
|
18
|
+
|
|
19
|
+
# @return [String]
|
|
20
|
+
attr_reader :customer_id
|
|
21
|
+
|
|
22
|
+
# @return [String]
|
|
23
|
+
attr_reader :granted_at
|
|
24
|
+
|
|
25
|
+
# @return [String]
|
|
26
|
+
attr_reader :id
|
|
27
|
+
|
|
28
|
+
# @return [Boolean]
|
|
29
|
+
attr_reader :is_granted
|
|
30
|
+
|
|
31
|
+
# @return [Boolean]
|
|
32
|
+
attr_reader :is_revoked
|
|
33
|
+
|
|
34
|
+
# @return [String, nil]
|
|
35
|
+
attr_reader :revoked_at
|
|
36
|
+
|
|
37
|
+
# @return [String ("granted", "revoked")]
|
|
38
|
+
attr_reader :status
|
|
39
|
+
|
|
40
|
+
def initialize(benefit_id:, benefit_type:, created_at:, customer_id:, granted_at:, id:, is_granted:, is_revoked:, revoked_at:, status:)
|
|
41
|
+
@benefit_id = benefit_id
|
|
42
|
+
@benefit_type = benefit_type
|
|
43
|
+
@created_at = created_at
|
|
44
|
+
@customer_id = customer_id
|
|
45
|
+
@granted_at = granted_at
|
|
46
|
+
@id = id
|
|
47
|
+
@is_granted = is_granted
|
|
48
|
+
@is_revoked = is_revoked
|
|
49
|
+
@revoked_at = revoked_at
|
|
50
|
+
@status = status
|
|
51
|
+
freeze
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Builds a BenefitGrant from the API's JSON.
|
|
55
|
+
def self.from_hash(data)
|
|
56
|
+
new(
|
|
57
|
+
benefit_id: data.fetch("benefit_id"),
|
|
58
|
+
benefit_type: data.fetch("benefit_type"),
|
|
59
|
+
created_at: data.fetch("created_at"),
|
|
60
|
+
customer_id: data.fetch("customer_id"),
|
|
61
|
+
granted_at: data.fetch("granted_at"),
|
|
62
|
+
id: data.fetch("id"),
|
|
63
|
+
is_granted: data.fetch("is_granted"),
|
|
64
|
+
is_revoked: data.fetch("is_revoked"),
|
|
65
|
+
revoked_at: data["revoked_at"],
|
|
66
|
+
status: data.fetch("status")
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
6
71
|
# Card is a resource of Peráta's API.
|
|
7
72
|
class Card < Model
|
|
8
73
|
MEMBERS = %i[brand exp_month exp_year last4].freeze
|
|
@@ -119,9 +184,41 @@ module Perata
|
|
|
119
184
|
end
|
|
120
185
|
end
|
|
121
186
|
|
|
187
|
+
# CustomerSession is a resource of Peráta's API.
|
|
188
|
+
class CustomerSession < Model
|
|
189
|
+
MEMBERS = %i[customer_portal_url expires_at token].freeze
|
|
190
|
+
|
|
191
|
+
# Endereço que abre o portal do cliente já autenticado.
|
|
192
|
+
# @return [String]
|
|
193
|
+
attr_reader :customer_portal_url
|
|
194
|
+
|
|
195
|
+
# @return [String]
|
|
196
|
+
attr_reader :expires_at
|
|
197
|
+
|
|
198
|
+
# Sessão do portal do cliente, já autenticada.
|
|
199
|
+
# @return [String]
|
|
200
|
+
attr_reader :token
|
|
201
|
+
|
|
202
|
+
def initialize(customer_portal_url:, expires_at:, token:)
|
|
203
|
+
@customer_portal_url = customer_portal_url
|
|
204
|
+
@expires_at = expires_at
|
|
205
|
+
@token = token
|
|
206
|
+
freeze
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Builds a CustomerSession from the API's JSON.
|
|
210
|
+
def self.from_hash(data)
|
|
211
|
+
new(
|
|
212
|
+
customer_portal_url: data.fetch("customer_portal_url"),
|
|
213
|
+
expires_at: data.fetch("expires_at"),
|
|
214
|
+
token: data.fetch("token")
|
|
215
|
+
)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
122
219
|
# Order is a resource of Peráta's API.
|
|
123
220
|
class Order < Model
|
|
124
|
-
MEMBERS = %i[amount_cents currency customer_id id paid_at price_id product_id status].freeze
|
|
221
|
+
MEMBERS = %i[amount_cents currency customer_id id installment_interest_cents installments paid_at price_id product_id status].freeze
|
|
125
222
|
|
|
126
223
|
# @return [Integer]
|
|
127
224
|
attr_reader :amount_cents
|
|
@@ -135,6 +232,14 @@ module Perata
|
|
|
135
232
|
# @return [String]
|
|
136
233
|
attr_reader :id
|
|
137
234
|
|
|
235
|
+
# Juros do parcelamento pagos pelo comprador, cobrados além de amount_cents.
|
|
236
|
+
# @return [Integer]
|
|
237
|
+
attr_reader :installment_interest_cents
|
|
238
|
+
|
|
239
|
+
# Em quantas parcelas o cartão de crédito foi cobrado; 1 à vista.
|
|
240
|
+
# @return [Integer]
|
|
241
|
+
attr_reader :installments
|
|
242
|
+
|
|
138
243
|
# @return [String, nil]
|
|
139
244
|
attr_reader :paid_at
|
|
140
245
|
|
|
@@ -147,11 +252,13 @@ module Perata
|
|
|
147
252
|
# @return [String ("open", "confirmed", "succeeded", "failed", "expired")]
|
|
148
253
|
attr_reader :status
|
|
149
254
|
|
|
150
|
-
def initialize(amount_cents:, currency:, customer_id:, id:, paid_at:, price_id:, product_id:, status:)
|
|
255
|
+
def initialize(amount_cents:, currency:, customer_id:, id:, installment_interest_cents:, installments:, paid_at:, price_id:, product_id:, status:)
|
|
151
256
|
@amount_cents = amount_cents
|
|
152
257
|
@currency = currency
|
|
153
258
|
@customer_id = customer_id
|
|
154
259
|
@id = id
|
|
260
|
+
@installment_interest_cents = installment_interest_cents
|
|
261
|
+
@installments = installments
|
|
155
262
|
@paid_at = paid_at
|
|
156
263
|
@price_id = price_id
|
|
157
264
|
@product_id = product_id
|
|
@@ -166,6 +273,8 @@ module Perata
|
|
|
166
273
|
currency: data.fetch("currency"),
|
|
167
274
|
customer_id: data.fetch("customer_id"),
|
|
168
275
|
id: data.fetch("id"),
|
|
276
|
+
installment_interest_cents: data.fetch("installment_interest_cents"),
|
|
277
|
+
installments: data.fetch("installments"),
|
|
169
278
|
paid_at: data["paid_at"],
|
|
170
279
|
price_id: data.fetch("price_id"),
|
|
171
280
|
product_id: data.fetch("product_id"),
|
|
@@ -201,7 +310,7 @@ module Perata
|
|
|
201
310
|
|
|
202
311
|
# Payment is a resource of Peráta's API.
|
|
203
312
|
class Payment < Model
|
|
204
|
-
MEMBERS = %i[amount_cents captured_cents checkout_id created_at currency customer_id id method refunded_cents state].freeze
|
|
313
|
+
MEMBERS = %i[amount_cents captured_cents checkout_id created_at currency customer_id id installment_amount_cents installment_interest_cents installments method refunded_cents state].freeze
|
|
205
314
|
|
|
206
315
|
# @return [Integer]
|
|
207
316
|
attr_reader :amount_cents
|
|
@@ -224,6 +333,18 @@ module Perata
|
|
|
224
333
|
# @return [String]
|
|
225
334
|
attr_reader :id
|
|
226
335
|
|
|
336
|
+
# Valor de uma parcela; 0 à vista.
|
|
337
|
+
# @return [Integer]
|
|
338
|
+
attr_reader :installment_amount_cents
|
|
339
|
+
|
|
340
|
+
# Juros do parcelamento dentro de amount_cents.
|
|
341
|
+
# @return [Integer]
|
|
342
|
+
attr_reader :installment_interest_cents
|
|
343
|
+
|
|
344
|
+
# Em quantas parcelas o cartão de crédito foi cobrado; 1 à vista.
|
|
345
|
+
# @return [Integer]
|
|
346
|
+
attr_reader :installments
|
|
347
|
+
|
|
227
348
|
# @return [String ("card", "pix", "boleto")]
|
|
228
349
|
attr_reader :method
|
|
229
350
|
|
|
@@ -233,7 +354,7 @@ module Perata
|
|
|
233
354
|
# @return [String ("unknown", "pending", "authorized", "captured", "refused", "canceled", "refunded", "partially_refunded")]
|
|
234
355
|
attr_reader :state
|
|
235
356
|
|
|
236
|
-
def initialize(amount_cents:, captured_cents:, checkout_id:, created_at:, currency:, customer_id:, id:, method:, refunded_cents:, state:)
|
|
357
|
+
def initialize(amount_cents:, captured_cents:, checkout_id:, created_at:, currency:, customer_id:, id:, installment_amount_cents:, installment_interest_cents:, installments:, method:, refunded_cents:, state:)
|
|
237
358
|
@amount_cents = amount_cents
|
|
238
359
|
@captured_cents = captured_cents
|
|
239
360
|
@checkout_id = checkout_id
|
|
@@ -241,6 +362,9 @@ module Perata
|
|
|
241
362
|
@currency = currency
|
|
242
363
|
@customer_id = customer_id
|
|
243
364
|
@id = id
|
|
365
|
+
@installment_amount_cents = installment_amount_cents
|
|
366
|
+
@installment_interest_cents = installment_interest_cents
|
|
367
|
+
@installments = installments
|
|
244
368
|
@method = method
|
|
245
369
|
@refunded_cents = refunded_cents
|
|
246
370
|
@state = state
|
|
@@ -257,6 +381,9 @@ module Perata
|
|
|
257
381
|
currency: data.fetch("currency"),
|
|
258
382
|
customer_id: data.fetch("customer_id"),
|
|
259
383
|
id: data.fetch("id"),
|
|
384
|
+
installment_amount_cents: data.fetch("installment_amount_cents"),
|
|
385
|
+
installment_interest_cents: data.fetch("installment_interest_cents"),
|
|
386
|
+
installments: data.fetch("installments"),
|
|
260
387
|
method: data.fetch("method"),
|
|
261
388
|
refunded_cents: data.fetch("refunded_cents"),
|
|
262
389
|
state: data.fetch("state")
|
|
@@ -524,4 +651,171 @@ module Perata
|
|
|
524
651
|
)
|
|
525
652
|
end
|
|
526
653
|
end
|
|
654
|
+
|
|
655
|
+
# WebhookCheckout is a resource of Peráta's API.
|
|
656
|
+
class WebhookCheckout < Model
|
|
657
|
+
MEMBERS = %i[amount_cents checkout_link_id created_at currency customer_id discount_cents expires_at id price_id product_id status total_cents].freeze
|
|
658
|
+
|
|
659
|
+
# @return [Integer]
|
|
660
|
+
attr_reader :amount_cents
|
|
661
|
+
|
|
662
|
+
# @return [String, nil]
|
|
663
|
+
attr_reader :checkout_link_id
|
|
664
|
+
|
|
665
|
+
# @return [String]
|
|
666
|
+
attr_reader :created_at
|
|
667
|
+
|
|
668
|
+
# @return [String ("BRL")]
|
|
669
|
+
attr_reader :currency
|
|
670
|
+
|
|
671
|
+
# Nulo até o comprador confirmar.
|
|
672
|
+
# @return [String, nil]
|
|
673
|
+
attr_reader :customer_id
|
|
674
|
+
|
|
675
|
+
# @return [Integer]
|
|
676
|
+
attr_reader :discount_cents
|
|
677
|
+
|
|
678
|
+
# @return [String]
|
|
679
|
+
attr_reader :expires_at
|
|
680
|
+
|
|
681
|
+
# @return [String]
|
|
682
|
+
attr_reader :id
|
|
683
|
+
|
|
684
|
+
# @return [String]
|
|
685
|
+
attr_reader :price_id
|
|
686
|
+
|
|
687
|
+
# @return [String]
|
|
688
|
+
attr_reader :product_id
|
|
689
|
+
|
|
690
|
+
# @return [String ("open", "confirmed", "succeeded", "failed", "expired")]
|
|
691
|
+
attr_reader :status
|
|
692
|
+
|
|
693
|
+
# @return [Integer]
|
|
694
|
+
attr_reader :total_cents
|
|
695
|
+
|
|
696
|
+
def initialize(amount_cents:, checkout_link_id:, created_at:, currency:, customer_id:, discount_cents:, expires_at:, id:, price_id:, product_id:, status:, total_cents:)
|
|
697
|
+
@amount_cents = amount_cents
|
|
698
|
+
@checkout_link_id = checkout_link_id
|
|
699
|
+
@created_at = created_at
|
|
700
|
+
@currency = currency
|
|
701
|
+
@customer_id = customer_id
|
|
702
|
+
@discount_cents = discount_cents
|
|
703
|
+
@expires_at = expires_at
|
|
704
|
+
@id = id
|
|
705
|
+
@price_id = price_id
|
|
706
|
+
@product_id = product_id
|
|
707
|
+
@status = status
|
|
708
|
+
@total_cents = total_cents
|
|
709
|
+
freeze
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
# Builds a WebhookCheckout from the API's JSON.
|
|
713
|
+
def self.from_hash(data)
|
|
714
|
+
new(
|
|
715
|
+
amount_cents: data.fetch("amount_cents"),
|
|
716
|
+
checkout_link_id: data["checkout_link_id"],
|
|
717
|
+
created_at: data.fetch("created_at"),
|
|
718
|
+
currency: data.fetch("currency"),
|
|
719
|
+
customer_id: data["customer_id"],
|
|
720
|
+
discount_cents: data.fetch("discount_cents"),
|
|
721
|
+
expires_at: data.fetch("expires_at"),
|
|
722
|
+
id: data.fetch("id"),
|
|
723
|
+
price_id: data.fetch("price_id"),
|
|
724
|
+
product_id: data.fetch("product_id"),
|
|
725
|
+
status: data.fetch("status"),
|
|
726
|
+
total_cents: data.fetch("total_cents")
|
|
727
|
+
)
|
|
728
|
+
end
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
# WebhookDispute is a resource of Peráta's API.
|
|
732
|
+
class WebhookDispute < Model
|
|
733
|
+
MEMBERS = %i[amount_cents currency customer_id decided_at due_by id invoice_id opened_at payment_id provider_dispute_id provider_reason reason source status].freeze
|
|
734
|
+
|
|
735
|
+
# Valor contestado, em centavos.
|
|
736
|
+
# @return [Integer]
|
|
737
|
+
attr_reader :amount_cents
|
|
738
|
+
|
|
739
|
+
# @return [String ("BRL")]
|
|
740
|
+
attr_reader :currency
|
|
741
|
+
|
|
742
|
+
# @return [String, nil]
|
|
743
|
+
attr_reader :customer_id
|
|
744
|
+
|
|
745
|
+
# @return [String, nil]
|
|
746
|
+
attr_reader :decided_at
|
|
747
|
+
|
|
748
|
+
# Prazo da defesa.
|
|
749
|
+
# @return [String, nil]
|
|
750
|
+
attr_reader :due_by
|
|
751
|
+
|
|
752
|
+
# @return [String]
|
|
753
|
+
attr_reader :id
|
|
754
|
+
|
|
755
|
+
# @return [String, nil]
|
|
756
|
+
attr_reader :invoice_id
|
|
757
|
+
|
|
758
|
+
# @return [String]
|
|
759
|
+
attr_reader :opened_at
|
|
760
|
+
|
|
761
|
+
# O PaymentId da venda contestada na Cielo.
|
|
762
|
+
# @return [String]
|
|
763
|
+
attr_reader :payment_id
|
|
764
|
+
|
|
765
|
+
# O número do caso na Cielo.
|
|
766
|
+
# @return [String]
|
|
767
|
+
attr_reader :provider_dispute_id
|
|
768
|
+
|
|
769
|
+
# O motivo nas palavras da Cielo.
|
|
770
|
+
# @return [String]
|
|
771
|
+
attr_reader :provider_reason
|
|
772
|
+
|
|
773
|
+
# Motivo, do conjunto fechado; unknown quando a adquirente não informou.
|
|
774
|
+
# @return [String]
|
|
775
|
+
attr_reader :reason
|
|
776
|
+
|
|
777
|
+
# @return [String ("operator", "cielo_chargeback")]
|
|
778
|
+
attr_reader :source
|
|
779
|
+
|
|
780
|
+
# @return [String ("opened", "needs_evidence", "submitted", "under_review", "won", "lost", "closed")]
|
|
781
|
+
attr_reader :status
|
|
782
|
+
|
|
783
|
+
def initialize(amount_cents:, currency:, customer_id:, decided_at:, due_by:, id:, invoice_id:, opened_at:, payment_id:, provider_dispute_id:, provider_reason:, reason:, source:, status:)
|
|
784
|
+
@amount_cents = amount_cents
|
|
785
|
+
@currency = currency
|
|
786
|
+
@customer_id = customer_id
|
|
787
|
+
@decided_at = decided_at
|
|
788
|
+
@due_by = due_by
|
|
789
|
+
@id = id
|
|
790
|
+
@invoice_id = invoice_id
|
|
791
|
+
@opened_at = opened_at
|
|
792
|
+
@payment_id = payment_id
|
|
793
|
+
@provider_dispute_id = provider_dispute_id
|
|
794
|
+
@provider_reason = provider_reason
|
|
795
|
+
@reason = reason
|
|
796
|
+
@source = source
|
|
797
|
+
@status = status
|
|
798
|
+
freeze
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
# Builds a WebhookDispute from the API's JSON.
|
|
802
|
+
def self.from_hash(data)
|
|
803
|
+
new(
|
|
804
|
+
amount_cents: data.fetch("amount_cents"),
|
|
805
|
+
currency: data.fetch("currency"),
|
|
806
|
+
customer_id: data["customer_id"],
|
|
807
|
+
decided_at: data["decided_at"],
|
|
808
|
+
due_by: data["due_by"],
|
|
809
|
+
id: data.fetch("id"),
|
|
810
|
+
invoice_id: data["invoice_id"],
|
|
811
|
+
opened_at: data.fetch("opened_at"),
|
|
812
|
+
payment_id: data.fetch("payment_id"),
|
|
813
|
+
provider_dispute_id: data.fetch("provider_dispute_id"),
|
|
814
|
+
provider_reason: data.fetch("provider_reason"),
|
|
815
|
+
reason: data.fetch("reason"),
|
|
816
|
+
source: data.fetch("source"),
|
|
817
|
+
status: data.fetch("status")
|
|
818
|
+
)
|
|
819
|
+
end
|
|
820
|
+
end
|
|
527
821
|
end
|
data/lib/perata/params.rb
CHANGED
|
@@ -48,6 +48,26 @@ module Perata
|
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
# The body of customer-sessions:create.
|
|
52
|
+
class CustomerSessionsCreateParams < Params
|
|
53
|
+
MEMBERS = %i[customer_id].freeze
|
|
54
|
+
|
|
55
|
+
# @return [String]
|
|
56
|
+
attr_reader :customer_id
|
|
57
|
+
|
|
58
|
+
def initialize(customer_id:)
|
|
59
|
+
@customer_id = customer_id
|
|
60
|
+
freeze
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# The body as the API reads it.
|
|
64
|
+
def to_wire
|
|
65
|
+
wire = {}
|
|
66
|
+
wire["customer_id"] = @customer_id
|
|
67
|
+
wire
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
51
71
|
# The body of customers:create.
|
|
52
72
|
class CustomersCreateParams < Params
|
|
53
73
|
MEMBERS = %i[email external_id name].freeze
|
data/lib/perata/services.rb
CHANGED
|
@@ -19,6 +19,22 @@ module Perata
|
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
# The API's customer-sessions.
|
|
23
|
+
class CustomerSessionsService
|
|
24
|
+
def initialize(client)
|
|
25
|
+
@client = client
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Sign a customer into the customer portal: the address opens it already signed in.
|
|
29
|
+
#
|
|
30
|
+
# @param params [CustomerSessionsCreateParams, Hash]
|
|
31
|
+
# @return [CustomerSession]
|
|
32
|
+
def create(params, idempotency_key: nil, api_key: nil)
|
|
33
|
+
data = @client.request("POST", "/api/v1/customer-sessions", body: CustomerSessionsCreateParams.coerce(params).to_wire, idempotency_key: idempotency_key, api_key: api_key)
|
|
34
|
+
CustomerSession.from_hash(data)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
22
38
|
# The API's customers.
|
|
23
39
|
class CustomersService
|
|
24
40
|
def initialize(client)
|
data/lib/perata/version.rb
CHANGED
data/lib/perata/webhooks.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Code generated by sdk/generator. DO NOT EDIT.
|
|
4
|
+
|
|
3
5
|
require "json"
|
|
4
6
|
require "openssl"
|
|
5
7
|
|
|
@@ -15,13 +17,19 @@ module Perata
|
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
#
|
|
20
|
+
# A webhook Peráta sent, verified: one subclass a kind of data
|
|
21
|
+
# (OrderWebhookEvent carries an Order…), or UnknownWebhookEvent for a type
|
|
22
|
+
# this SDK does not know yet. Within a class, +type+ says what happened.
|
|
19
23
|
class WebhookEvent < Model
|
|
20
24
|
MEMBERS = %i[id type timestamp data].freeze
|
|
21
25
|
|
|
22
|
-
# @return [String]
|
|
23
|
-
attr_reader :id
|
|
24
|
-
# @return [
|
|
26
|
+
# @return [String] the message's id, the same as the webhook-id header
|
|
27
|
+
attr_reader :id
|
|
28
|
+
# @return [String] what happened: order.paid…
|
|
29
|
+
attr_reader :type
|
|
30
|
+
# @return [String] when it happened, in RFC 3339
|
|
31
|
+
attr_reader :timestamp
|
|
32
|
+
# @return [Object] what the event carries
|
|
25
33
|
attr_reader :data
|
|
26
34
|
|
|
27
35
|
def initialize(id:, type:, timestamp:, data:)
|
|
@@ -33,16 +41,71 @@ module Perata
|
|
|
33
41
|
end
|
|
34
42
|
end
|
|
35
43
|
|
|
44
|
+
# The events that carry a BenefitGrant; +data+ is BenefitGrant.
|
|
45
|
+
class BenefitGrantWebhookEvent < WebhookEvent
|
|
46
|
+
TYPES = %w[benefit_grant.created benefit_grant.revoked benefit_grant.updated].freeze
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# The events that carry a WebhookCheckout; +data+ is WebhookCheckout.
|
|
50
|
+
class CheckoutWebhookEvent < WebhookEvent
|
|
51
|
+
TYPES = %w[checkout.created checkout.expired checkout.updated].freeze
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# The events that carry a Customer; +data+ is Customer.
|
|
55
|
+
class CustomerWebhookEvent < WebhookEvent
|
|
56
|
+
TYPES = %w[customer.created customer.deleted customer.updated].freeze
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# The events that carry a WebhookDispute; +data+ is WebhookDispute.
|
|
60
|
+
class DisputeWebhookEvent < WebhookEvent
|
|
61
|
+
TYPES = %w[dispute.lost dispute.opened dispute.won].freeze
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The events that carry the event's identifiers; +data+ is Hash{String => String}.
|
|
65
|
+
class IdentifiersWebhookEvent < WebhookEvent
|
|
66
|
+
TYPES = %w[benefit.archived benefit.created benefit.updated benefit.version_created benefit_product_link.linked benefit_product_link.unlinked checkout_link.archived checkout_link.created checkout_payment.authorized checkout_payment.canceled checkout_payment.captured checkout_payment.partially_refunded checkout_payment.refunded checkout_payment.refused checkout_session.confirmed checkout_session.expired checkout_session.failed checkout_session.opened checkout_session.succeeded customer.archived discount.created discount.deleted discount.exhausted discount.expired discount.reactivated discount.redeemed discount.updated discount_redemption.released invoice.drafted invoice.issued invoice.settled invoice.uncollectible invoice.voided price.archived price.created product.archived product.created product.updated refund.canceled refund.failed refund.requested refund.succeeded seat_allocation.opened seat_allocation.resized seat_assignment.claimed seat_assignment.invited seat_assignment.revoked usage_event.recorded usage_period.closed usage_period.opened usage_period_adjustment.created].freeze
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The events that carry an Order; +data+ is Order.
|
|
70
|
+
class OrderWebhookEvent < WebhookEvent
|
|
71
|
+
TYPES = %w[order.created order.paid order.refunded order.updated].freeze
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The events that carry a Refund; +data+ is Refund.
|
|
75
|
+
class RefundWebhookEvent < WebhookEvent
|
|
76
|
+
TYPES = %w[refund.created refund.updated].freeze
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# The events that carry a Subscription; +data+ is Subscription.
|
|
80
|
+
class SubscriptionWebhookEvent < WebhookEvent
|
|
81
|
+
TYPES = %w[subscription.active subscription.canceled subscription.created subscription.cycled subscription.past_due subscription.paused subscription.resumed subscription.revoked subscription.uncanceled subscription.updated].freeze
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# An event of a type this SDK does not know yet, its data as it was sent.
|
|
85
|
+
class UnknownWebhookEvent < WebhookEvent
|
|
86
|
+
end
|
|
87
|
+
|
|
36
88
|
# Checks a webhook Peráta sent and answers its event.
|
|
37
89
|
#
|
|
38
90
|
# The signature is an HMAC-SHA256 of +{webhook-id}.{webhook-timestamp}.{body}+
|
|
39
|
-
# under the key the endpoint's +whsec_+ secret encodes
|
|
40
|
-
#
|
|
41
|
-
#
|
|
91
|
+
# under the key the endpoint's +whsec_+ secret encodes, one of the signatures
|
|
92
|
+
# in the +webhook-signature+ header, which carries more than one while a
|
|
93
|
+
# secret is rotated. Pass the body exactly as it arrived, before parsing it;
|
|
94
|
+
# +headers+ is a hash of the request's headers, in any case, or a Rack env.
|
|
42
95
|
#
|
|
43
96
|
# @return [WebhookEvent]
|
|
44
97
|
# @raise [WebhookVerificationError]
|
|
45
98
|
def self.verify_webhook(secret, headers, body, now: Time.now)
|
|
99
|
+
verify_webhook_signature(secret, headers, body, now: now)
|
|
100
|
+
webhook_event(body.to_s.b.force_encoding(Encoding::UTF_8))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Checks a webhook's signature as verify_webhook does, without reading its
|
|
104
|
+
# body.
|
|
105
|
+
#
|
|
106
|
+
# @return [nil]
|
|
107
|
+
# @raise [WebhookVerificationError]
|
|
108
|
+
def self.verify_webhook_signature(secret, headers, body, now: Time.now)
|
|
46
109
|
key = begin
|
|
47
110
|
secret.delete_prefix("whsec_").unpack1("m0")
|
|
48
111
|
rescue ArgumentError
|
|
@@ -66,15 +129,30 @@ module Perata
|
|
|
66
129
|
rescue ArgumentError
|
|
67
130
|
next
|
|
68
131
|
end
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
event = JSON.parse(raw.force_encoding(Encoding::UTF_8))
|
|
72
|
-
return WebhookEvent.new(id: event.fetch("id"), type: event.fetch("type"), timestamp: event.fetch("timestamp"),
|
|
73
|
-
data: event["data"] || {})
|
|
132
|
+
return nil if decoded.bytesize == expected.bytesize && OpenSSL.fixed_length_secure_compare(decoded, expected)
|
|
74
133
|
end
|
|
75
134
|
raise WebhookVerificationError
|
|
76
135
|
end
|
|
77
136
|
|
|
137
|
+
# A verified body as the event its type names.
|
|
138
|
+
def self.webhook_event(raw)
|
|
139
|
+
event = JSON.parse(raw)
|
|
140
|
+
data = event["data"] || {}
|
|
141
|
+
message = { id: event.fetch("id"), type: event.fetch("type"), timestamp: event.fetch("timestamp") }
|
|
142
|
+
case message[:type]
|
|
143
|
+
when *BenefitGrantWebhookEvent::TYPES then BenefitGrantWebhookEvent.new(**message, data: BenefitGrant.from_hash(data))
|
|
144
|
+
when *CheckoutWebhookEvent::TYPES then CheckoutWebhookEvent.new(**message, data: WebhookCheckout.from_hash(data))
|
|
145
|
+
when *CustomerWebhookEvent::TYPES then CustomerWebhookEvent.new(**message, data: Customer.from_hash(data))
|
|
146
|
+
when *DisputeWebhookEvent::TYPES then DisputeWebhookEvent.new(**message, data: WebhookDispute.from_hash(data))
|
|
147
|
+
when *IdentifiersWebhookEvent::TYPES then IdentifiersWebhookEvent.new(**message, data: data)
|
|
148
|
+
when *OrderWebhookEvent::TYPES then OrderWebhookEvent.new(**message, data: Order.from_hash(data))
|
|
149
|
+
when *RefundWebhookEvent::TYPES then RefundWebhookEvent.new(**message, data: Refund.from_hash(data))
|
|
150
|
+
when *SubscriptionWebhookEvent::TYPES then SubscriptionWebhookEvent.new(**message, data: Subscription.from_hash(data))
|
|
151
|
+
else UnknownWebhookEvent.new(**message, data: data)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
private_class_method :webhook_event
|
|
155
|
+
|
|
78
156
|
# A header's value, looked up in any case; a Rack env's HTTP_WEBHOOK_ID
|
|
79
157
|
# names webhook-id.
|
|
80
158
|
def self.webhook_header(headers, name)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: perata-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peráta
|
|
@@ -45,7 +45,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
46
|
version: '0'
|
|
47
47
|
requirements: []
|
|
48
|
-
rubygems_version:
|
|
48
|
+
rubygems_version: 3.6.9
|
|
49
49
|
specification_version: 4
|
|
50
50
|
summary: 'Peráta''s SDK for Ruby: products, customers, checkouts, payments, subscriptions
|
|
51
51
|
and webhooks.'
|