tinker-pay-ruby-sdk 0.1.0 → 0.6.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/.rubocop.yml +0 -1
- data/README.md +232 -107
- data/lib/tinker/api/base_manager.rb +73 -10
- data/lib/tinker/api/payout_manager.rb +31 -0
- data/lib/tinker/api/subscription_manager.rb +122 -0
- data/lib/tinker/api/transaction_manager.rb +33 -0
- data/lib/tinker/auth/authentication_manager.rb +32 -7
- data/lib/tinker/config/configuration.rb +21 -3
- data/lib/tinker/config/endpoints.rb +10 -5
- data/lib/tinker/enum/gateway.rb +1 -0
- data/lib/tinker/enum/payment_status.rb +11 -0
- data/lib/tinker/exception/api_exception.rb +18 -2
- data/lib/tinker/exception/feature_not_supported_exception.rb +28 -0
- data/lib/tinker/http/http_client.rb +24 -4
- data/lib/tinker/model/api_meta.rb +23 -0
- data/lib/tinker/model/cancellation_result.rb +14 -0
- data/lib/tinker/model/checkout_cancellation.rb +8 -0
- data/lib/tinker/model/dto/callback_data_dto.rb +4 -8
- data/lib/tinker/model/dto/cancellation_request.rb +17 -0
- data/lib/tinker/model/dto/create_subscription_plan_request_dto.rb +32 -0
- data/lib/tinker/model/dto/create_subscription_request_dto.rb +30 -0
- data/lib/tinker/model/dto/initiate_payment_request_dto.rb +10 -2
- data/lib/tinker/model/dto/initiation_data_dto.rb +10 -11
- data/lib/tinker/model/dto/managed_checkout.rb +25 -0
- data/lib/tinker/model/dto/payout_request.rb +18 -0
- data/lib/tinker/model/dto/query_data_dto.rb +4 -8
- data/lib/tinker/model/dto/query_payment_request_dto.rb +1 -1
- data/lib/tinker/model/dto/refund_request.rb +17 -0
- data/lib/tinker/model/dto/subscription_customer_dto.rb +28 -0
- data/lib/tinker/model/lifecycle_resource.rb +28 -0
- data/lib/tinker/model/payout.rb +8 -0
- data/lib/tinker/model/payout_result.rb +14 -0
- data/lib/tinker/model/refund.rb +8 -0
- data/lib/tinker/model/refund_result.rb +15 -0
- data/lib/tinker/model/transaction.rb +2 -7
- data/lib/tinker/payments.rb +21 -4
- data/lib/tinker/version.rb +1 -1
- data/lib/tinker/webhook/dto/invoice_event_data_dto.rb +5 -4
- data/lib/tinker/webhook/dto/onboarding_event_data_dto.rb +19 -0
- data/lib/tinker/webhook/dto/payment_event_data_dto.rb +4 -8
- data/lib/tinker/webhook/dto/settlement_event_data_dto.rb +8 -5
- data/lib/tinker/webhook/dto/subscription_event_data_dto.rb +12 -6
- data/lib/tinker/webhook/webhook_event.rb +44 -3
- data/lib/tinker/webhook/webhook_handler.rb +42 -0
- data/lib/tinker.rb +19 -0
- metadata +27 -8
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tinker
|
|
4
|
+
module Model
|
|
5
|
+
module Dto
|
|
6
|
+
# Exact integer minor-unit prices for managed recurring billing.
|
|
7
|
+
class ManagedCheckout
|
|
8
|
+
def initialize(external_customer_id:, email:, name:, currency:, unit_amount:, quantity:,
|
|
9
|
+
interval:, return_url:, idempotency_key:, trial_days: 0, trial_end: nil)
|
|
10
|
+
@payload = {
|
|
11
|
+
external_customer_id: external_customer_id, email: email, name: name, currency: currency,
|
|
12
|
+
unit_amount: unit_amount, quantity: quantity, interval: interval, return_url: return_url,
|
|
13
|
+
idempotency_key: idempotency_key
|
|
14
|
+
}
|
|
15
|
+
@payload[:trial_days] = trial_days if trial_days.positive?
|
|
16
|
+
@payload[:trial_end] = trial_end.to_i if trial_end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_hash
|
|
20
|
+
@payload.dup
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tinker
|
|
4
|
+
module Model
|
|
5
|
+
module Dto
|
|
6
|
+
class PayoutRequest
|
|
7
|
+
def initialize(payout_method_id:, amount:, currency:, expected_fee_amount:)
|
|
8
|
+
@payload = { payout_method_id: payout_method_id, amount: amount, currency: currency,
|
|
9
|
+
expected_fee_amount: expected_fee_amount }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_hash
|
|
13
|
+
@payload.dup
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -4,22 +4,18 @@ module Tinker
|
|
|
4
4
|
module Model
|
|
5
5
|
module Dto
|
|
6
6
|
class QueryDataDto
|
|
7
|
-
attr_reader :id, :status, :reference, :amount, :currency, :paid_at, :created_at, :channel
|
|
7
|
+
attr_reader :id, :status, :reference, :amount, :currency, :paid_at, :created_at, :channel, :country
|
|
8
8
|
|
|
9
9
|
def initialize(data)
|
|
10
10
|
@id = data['id']
|
|
11
|
-
|
|
12
|
-
@status = begin
|
|
13
|
-
Tinker::Enum::PaymentStatus.const_get(status_value.upcase)
|
|
14
|
-
rescue NameError
|
|
15
|
-
Tinker::Enum::PaymentStatus::PENDING
|
|
16
|
-
end
|
|
11
|
+
@status = Tinker::Enum::PaymentStatus.parse(data['status'])
|
|
17
12
|
@reference = data['reference']
|
|
18
13
|
@amount = data['amount'].to_f
|
|
19
14
|
@currency = data['currency']
|
|
20
15
|
@paid_at = data['paid_at']
|
|
21
16
|
@created_at = data['created_at']
|
|
22
17
|
@channel = data['channel']
|
|
18
|
+
@country = data['country']
|
|
23
19
|
end
|
|
24
20
|
|
|
25
21
|
def to_hash
|
|
@@ -32,7 +28,7 @@ module Tinker
|
|
|
32
28
|
paid_at: @paid_at,
|
|
33
29
|
created_at: @created_at,
|
|
34
30
|
channel: @channel
|
|
35
|
-
}
|
|
31
|
+
}.merge(@country ? { country: @country } : {})
|
|
36
32
|
end
|
|
37
33
|
end
|
|
38
34
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tinker
|
|
4
|
+
module Model
|
|
5
|
+
module Dto
|
|
6
|
+
class RefundRequest
|
|
7
|
+
def initialize(reason:, amount: nil, note: nil)
|
|
8
|
+
@payload = { reason: reason, amount: amount, note: note }.compact
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_hash
|
|
12
|
+
@payload.dup
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tinker
|
|
4
|
+
module Model
|
|
5
|
+
module Dto
|
|
6
|
+
class SubscriptionCustomerDto
|
|
7
|
+
def initialize(external_customer_id:, name:, email: nil, phone: nil, metadata: nil)
|
|
8
|
+
@external_customer_id = external_customer_id
|
|
9
|
+
@name = name
|
|
10
|
+
@email = email
|
|
11
|
+
@phone = phone
|
|
12
|
+
@metadata = metadata
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_hash
|
|
16
|
+
payload = {
|
|
17
|
+
external_customer_id: @external_customer_id,
|
|
18
|
+
name: @name
|
|
19
|
+
}
|
|
20
|
+
payload[:email] = @email if @email
|
|
21
|
+
payload[:phone] = @phone if @phone
|
|
22
|
+
payload[:metadata] = @metadata if @metadata
|
|
23
|
+
payload
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tinker
|
|
4
|
+
module Model
|
|
5
|
+
# Keep provider-independent status and all additive response fields.
|
|
6
|
+
class LifecycleResource
|
|
7
|
+
def initialize(data)
|
|
8
|
+
@data = data.dup
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def id
|
|
12
|
+
@data['id']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def status
|
|
16
|
+
@data['status']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def [](key)
|
|
20
|
+
@data[key.to_s]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_hash
|
|
24
|
+
@data.dup
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tinker
|
|
4
|
+
module Model
|
|
5
|
+
class PayoutResult
|
|
6
|
+
attr_reader :withdrawal, :replayed
|
|
7
|
+
|
|
8
|
+
def initialize(data)
|
|
9
|
+
@withdrawal = Payout.new(data.fetch('withdrawal'))
|
|
10
|
+
@replayed = data['replayed'] == true
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tinker
|
|
4
|
+
module Model
|
|
5
|
+
class RefundResult
|
|
6
|
+
attr_reader :refund, :replayed, :payment
|
|
7
|
+
|
|
8
|
+
def initialize(data)
|
|
9
|
+
@refund = Refund.new(data.fetch('refund'))
|
|
10
|
+
@replayed = data['replayed'] == true
|
|
11
|
+
@payment = data.fetch('payment', {})
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -6,7 +6,7 @@ module Tinker
|
|
|
6
6
|
attr_reader :status, :initiation_data, :query_data, :callback_data
|
|
7
7
|
|
|
8
8
|
def initialize(data)
|
|
9
|
-
if data['payment_reference'] && !data['id']
|
|
9
|
+
if (data['paymentReference'] || data['payment_reference']) && !data['id']
|
|
10
10
|
@initiation_data = Dto::InitiationDataDto.new(data)
|
|
11
11
|
@query_data = nil
|
|
12
12
|
@callback_data = nil
|
|
@@ -20,12 +20,7 @@ module Tinker
|
|
|
20
20
|
@initiation_data = nil
|
|
21
21
|
@query_data = nil
|
|
22
22
|
@callback_data = nil
|
|
23
|
-
|
|
24
|
-
@status = begin
|
|
25
|
-
Enum::PaymentStatus.const_get(status_value.upcase)
|
|
26
|
-
rescue NameError
|
|
27
|
-
Enum::PaymentStatus::PENDING
|
|
28
|
-
end
|
|
23
|
+
@status = Enum::PaymentStatus.parse(data['status'])
|
|
29
24
|
end
|
|
30
25
|
end
|
|
31
26
|
|
data/lib/tinker/payments.rb
CHANGED
|
@@ -7,16 +7,17 @@ require_relative 'http/http_client'
|
|
|
7
7
|
require_relative 'auth/authentication_manager'
|
|
8
8
|
require_relative 'api/base_manager'
|
|
9
9
|
require_relative 'api/transaction_manager'
|
|
10
|
+
require_relative 'api/subscription_manager'
|
|
11
|
+
require_relative 'api/payout_manager'
|
|
10
12
|
require_relative 'webhook/webhook_handler'
|
|
11
13
|
|
|
12
14
|
module Tinker
|
|
13
15
|
class Payments
|
|
14
|
-
def initialize(api_public_key:, api_secret_key:, http_client: nil)
|
|
15
|
-
@config = Config::Configuration.new(api_public_key: api_public_key, api_secret_key: api_secret_key
|
|
16
|
+
def initialize(api_public_key:, api_secret_key:, http_client: nil, base_url: nil)
|
|
17
|
+
@config = Config::Configuration.new(api_public_key: api_public_key, api_secret_key: api_secret_key,
|
|
18
|
+
base_url: base_url)
|
|
16
19
|
@http_client = http_client || Http::HttpClient.new
|
|
17
20
|
@auth_manager = Auth::AuthenticationManager.new(config: @config, http_client: @http_client)
|
|
18
|
-
@transactions_manager = nil
|
|
19
|
-
@webhook_handler = nil
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
def transactions
|
|
@@ -27,8 +28,24 @@ module Tinker
|
|
|
27
28
|
)
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
def subscriptions
|
|
32
|
+
@subscriptions ||= Api::SubscriptionManager.new(
|
|
33
|
+
config: @config,
|
|
34
|
+
http_client: @http_client,
|
|
35
|
+
auth_manager: @auth_manager
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def payouts
|
|
40
|
+
@payouts ||= Api::PayoutManager.new(config: @config, http_client: @http_client, auth_manager: @auth_manager)
|
|
41
|
+
end
|
|
42
|
+
|
|
30
43
|
def webhooks
|
|
31
44
|
@webhooks ||= Webhook::WebhookHandler.new
|
|
32
45
|
end
|
|
46
|
+
|
|
47
|
+
def last_auth_meta
|
|
48
|
+
@auth_manager.last_meta
|
|
49
|
+
end
|
|
33
50
|
end
|
|
34
51
|
end
|
data/lib/tinker/version.rb
CHANGED
|
@@ -7,11 +7,11 @@ module Tinker
|
|
|
7
7
|
attr_reader :id, :status, :invoice_number, :amount, :currency, :subscription_id, :created_at, :paid_at
|
|
8
8
|
|
|
9
9
|
def initialize(data)
|
|
10
|
-
@id = data['id']
|
|
11
|
-
@status = data['status']
|
|
10
|
+
@id = data['invoice_id'] || data['id']
|
|
11
|
+
@status = data['status'] || ''
|
|
12
12
|
@invoice_number = data['invoice_number'] || ''
|
|
13
|
-
@amount = data['amount'].to_f
|
|
14
|
-
@currency = data['currency']
|
|
13
|
+
@amount = (data['amount'] || 0).to_f
|
|
14
|
+
@currency = data['currency'] || ''
|
|
15
15
|
@subscription_id = data['subscription_id'] || ''
|
|
16
16
|
@created_at = data['created_at'] || ''
|
|
17
17
|
@paid_at = data['paid_at']
|
|
@@ -20,6 +20,7 @@ module Tinker
|
|
|
20
20
|
def to_hash
|
|
21
21
|
{
|
|
22
22
|
id: @id,
|
|
23
|
+
invoice_id: @id,
|
|
23
24
|
status: @status,
|
|
24
25
|
invoice_number: @invoice_number,
|
|
25
26
|
amount: @amount,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tinker
|
|
4
|
+
module Webhook
|
|
5
|
+
module Dto
|
|
6
|
+
class OnboardingEventDataDto
|
|
7
|
+
attr_reader :message
|
|
8
|
+
|
|
9
|
+
def initialize(data)
|
|
10
|
+
@message = data.fetch('message', '').to_s
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_hash
|
|
14
|
+
{ 'message' => @message }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -4,22 +4,18 @@ module Tinker
|
|
|
4
4
|
module Webhook
|
|
5
5
|
module Dto
|
|
6
6
|
class PaymentEventDataDto
|
|
7
|
-
attr_reader :id, :status, :reference, :amount, :currency, :channel, :created_at, :paid_at
|
|
7
|
+
attr_reader :id, :status, :reference, :amount, :currency, :channel, :created_at, :paid_at, :country
|
|
8
8
|
|
|
9
9
|
def initialize(data)
|
|
10
10
|
@id = data['id']
|
|
11
|
-
|
|
12
|
-
@status = begin
|
|
13
|
-
Tinker::Enum::PaymentStatus.const_get(status_value.upcase)
|
|
14
|
-
rescue NameError
|
|
15
|
-
Tinker::Enum::PaymentStatus::PENDING
|
|
16
|
-
end
|
|
11
|
+
@status = Tinker::Enum::PaymentStatus.parse(data['status'])
|
|
17
12
|
@reference = data['reference']
|
|
18
13
|
@amount = data['amount'].to_f
|
|
19
14
|
@currency = data['currency']
|
|
20
15
|
@channel = data['channel']
|
|
21
16
|
@created_at = data['created_at']
|
|
22
17
|
@paid_at = data['paid_at']
|
|
18
|
+
@country = data['country']
|
|
23
19
|
end
|
|
24
20
|
|
|
25
21
|
def to_hash
|
|
@@ -32,7 +28,7 @@ module Tinker
|
|
|
32
28
|
'channel' => @channel,
|
|
33
29
|
'created_at' => @created_at,
|
|
34
30
|
'paid_at' => @paid_at
|
|
35
|
-
}
|
|
31
|
+
}.merge(@country ? { 'country' => @country } : {})
|
|
36
32
|
end
|
|
37
33
|
end
|
|
38
34
|
end
|
|
@@ -4,13 +4,14 @@ module Tinker
|
|
|
4
4
|
module Webhook
|
|
5
5
|
module Dto
|
|
6
6
|
class SettlementEventDataDto
|
|
7
|
-
attr_reader :id, :status, :amount, :currency, :settlement_date, :created_at, :processed_at
|
|
7
|
+
attr_reader :id, :status, :amount, :net_amount, :currency, :settlement_date, :created_at, :processed_at
|
|
8
8
|
|
|
9
9
|
def initialize(data)
|
|
10
|
-
@id = data['id']
|
|
11
|
-
@status = data['status']
|
|
12
|
-
@amount = data['amount'].to_f
|
|
13
|
-
@
|
|
10
|
+
@id = data['settlement_id'] || data['id']
|
|
11
|
+
@status = data['status'] || ''
|
|
12
|
+
@amount = (data['amount'] || 0).to_f
|
|
13
|
+
@net_amount = data['net_amount']&.to_f
|
|
14
|
+
@currency = data['currency'] || ''
|
|
14
15
|
@settlement_date = data['settlement_date'] || ''
|
|
15
16
|
@created_at = data['created_at'] || ''
|
|
16
17
|
@processed_at = data['processed_at']
|
|
@@ -19,8 +20,10 @@ module Tinker
|
|
|
19
20
|
def to_hash
|
|
20
21
|
{
|
|
21
22
|
id: @id,
|
|
23
|
+
settlement_id: @id,
|
|
22
24
|
status: @status,
|
|
23
25
|
amount: @amount,
|
|
26
|
+
net_amount: @net_amount,
|
|
24
27
|
currency: @currency,
|
|
25
28
|
settlement_date: @settlement_date,
|
|
26
29
|
created_at: @created_at,
|
|
@@ -4,14 +4,17 @@ module Tinker
|
|
|
4
4
|
module Webhook
|
|
5
5
|
module Dto
|
|
6
6
|
class SubscriptionEventDataDto
|
|
7
|
-
attr_reader :id, :status, :plan_id, :
|
|
7
|
+
attr_reader :id, :status, :plan_id, :account_id, :current_period_start, :current_period_end, :created_at,
|
|
8
|
+
:cancelled_at, :paused_at, :reactivated_at
|
|
8
9
|
|
|
9
10
|
def initialize(data)
|
|
10
|
-
@id = data['id']
|
|
11
|
-
@status = data['status']
|
|
11
|
+
@id = data['subscription_id'] || data['id']
|
|
12
|
+
@status = data['status'] || ''
|
|
12
13
|
@plan_id = data['plan_id'] || ''
|
|
13
|
-
@
|
|
14
|
-
@
|
|
14
|
+
@account_id = data['account_id'] || data['customer_id'] || ''
|
|
15
|
+
@current_period_start = data['current_period_start']
|
|
16
|
+
@current_period_end = data['current_period_end']
|
|
17
|
+
@created_at = data['created_at'] || @current_period_start || ''
|
|
15
18
|
@cancelled_at = data['cancelled_at']
|
|
16
19
|
@paused_at = data['paused_at']
|
|
17
20
|
@reactivated_at = data['reactivated_at']
|
|
@@ -20,9 +23,12 @@ module Tinker
|
|
|
20
23
|
def to_hash
|
|
21
24
|
{
|
|
22
25
|
id: @id,
|
|
26
|
+
subscription_id: @id,
|
|
23
27
|
status: @status,
|
|
24
28
|
plan_id: @plan_id,
|
|
25
|
-
|
|
29
|
+
account_id: @account_id,
|
|
30
|
+
current_period_start: @current_period_start,
|
|
31
|
+
current_period_end: @current_period_end,
|
|
26
32
|
created_at: @created_at,
|
|
27
33
|
cancelled_at: @cancelled_at,
|
|
28
34
|
paused_at: @paused_at,
|
|
@@ -3,18 +3,45 @@
|
|
|
3
3
|
module Tinker
|
|
4
4
|
module Webhook
|
|
5
5
|
class WebhookEvent
|
|
6
|
-
attr_reader :id, :type, :source, :timestamp, :data, :meta, :security
|
|
6
|
+
attr_reader :id, :type, :source, :timestamp, :data, :meta, :security, :raw_data, :raw_meta
|
|
7
7
|
|
|
8
8
|
def initialize(payload)
|
|
9
9
|
@id = payload['id']
|
|
10
10
|
@type = payload['type']
|
|
11
11
|
@source = payload['source']
|
|
12
12
|
@timestamp = payload['timestamp']
|
|
13
|
-
@
|
|
14
|
-
@
|
|
13
|
+
@raw_data = payload['data'].is_a?(Hash) ? payload['data'] : {}
|
|
14
|
+
@raw_meta = payload['meta'].is_a?(Hash) ? payload['meta'] : {}
|
|
15
|
+
@data = create_event_data(@raw_data, @source)
|
|
16
|
+
@meta = WebhookMeta.new(@raw_meta)
|
|
15
17
|
@security = WebhookSecurity.new(payload['security'] || {})
|
|
16
18
|
end
|
|
17
19
|
|
|
20
|
+
def onboarding_event?
|
|
21
|
+
@source == 'onboarding'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Verify the signature before acknowledging a setup test.
|
|
25
|
+
def setup_test?
|
|
26
|
+
onboarding_event? && @type == 'setup.webhook_test'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def onboarding_data
|
|
30
|
+
@data.is_a?(Dto::OnboardingEventDataDto) ? @data : nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def cancellation_data
|
|
34
|
+
@data.is_a?(Model::CheckoutCancellation) ? @data : nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def refund_data
|
|
38
|
+
@data.is_a?(Model::Refund) ? @data : nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def payout_data
|
|
42
|
+
@data.is_a?(Model::Payout) ? @data : nil
|
|
43
|
+
end
|
|
44
|
+
|
|
18
45
|
def payment_event?
|
|
19
46
|
@source == 'payment'
|
|
20
47
|
end
|
|
@@ -57,7 +84,21 @@ module Tinker
|
|
|
57
84
|
private
|
|
58
85
|
|
|
59
86
|
def create_event_data(data, source)
|
|
87
|
+
resource_types = {
|
|
88
|
+
'checkout.cancellation.updated' => Model::CheckoutCancellation,
|
|
89
|
+
'refund.updated' => Model::Refund,
|
|
90
|
+
'withdrawal.updated' => Model::Payout
|
|
91
|
+
}
|
|
92
|
+
resource_type = resource_types[@type.to_s.sub(/\.v[^.]+\z/, '')] if source == 'payment'
|
|
93
|
+
return resource_type.new(data.fetch('resource', {})) if resource_type
|
|
94
|
+
|
|
95
|
+
source_event_data(data, source)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def source_event_data(data, source)
|
|
60
99
|
case source
|
|
100
|
+
when 'onboarding'
|
|
101
|
+
Dto::OnboardingEventDataDto.new(data)
|
|
61
102
|
when 'payment'
|
|
62
103
|
Dto::PaymentEventDataDto.new(data)
|
|
63
104
|
when 'subscription'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'json'
|
|
4
|
+
require 'openssl'
|
|
4
5
|
|
|
5
6
|
module Tinker
|
|
6
7
|
module Webhook
|
|
@@ -30,6 +31,47 @@ module Tinker
|
|
|
30
31
|
event = handle(payload)
|
|
31
32
|
event.to_transaction
|
|
32
33
|
end
|
|
34
|
+
|
|
35
|
+
def verify_signature(payload_or_event, webhook_secret)
|
|
36
|
+
return false if webhook_secret.nil? || webhook_secret.empty?
|
|
37
|
+
|
|
38
|
+
event = payload_or_event.is_a?(WebhookEvent) ? payload_or_event : handle(payload_or_event)
|
|
39
|
+
signature = event.security.signature
|
|
40
|
+
return false unless event.security.algorithm == 'HMAC-SHA256' && signature&.start_with?('sha256=')
|
|
41
|
+
|
|
42
|
+
computed = computed_signature(event, webhook_secret)
|
|
43
|
+
return false unless signature.bytesize == computed.bytesize
|
|
44
|
+
|
|
45
|
+
OpenSSL.fixed_length_secure_compare(signature, computed)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def sort_maps(value)
|
|
51
|
+
case value
|
|
52
|
+
when Hash
|
|
53
|
+
value.keys.sort.to_h { |key| [key, sort_maps(value[key])] }
|
|
54
|
+
when Array
|
|
55
|
+
value.map { |item| sort_maps(item) }
|
|
56
|
+
else
|
|
57
|
+
value
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def computed_signature(event, webhook_secret)
|
|
62
|
+
payload_without_security = {
|
|
63
|
+
id: event.id,
|
|
64
|
+
type: event.type,
|
|
65
|
+
source: event.source,
|
|
66
|
+
timestamp: event.timestamp,
|
|
67
|
+
data: sort_maps(event.raw_data),
|
|
68
|
+
meta: sort_maps(event.raw_meta)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
encoded = JSON.generate(payload_without_security)
|
|
72
|
+
encoded = encoded.gsub(/[<>&\u2028\u2029]/) { |char| format('\\u%04x', char.ord) }
|
|
73
|
+
"sha256=#{OpenSSL::HMAC.hexdigest('SHA256', webhook_secret, encoded)}"
|
|
74
|
+
end
|
|
33
75
|
end
|
|
34
76
|
end
|
|
35
77
|
end
|
data/lib/tinker.rb
CHANGED
|
@@ -5,6 +5,7 @@ require_relative 'tinker/config/configuration'
|
|
|
5
5
|
require_relative 'tinker/config/endpoints'
|
|
6
6
|
require_relative 'tinker/exception/exception_code'
|
|
7
7
|
require_relative 'tinker/exception/api_exception'
|
|
8
|
+
require_relative 'tinker/exception/feature_not_supported_exception'
|
|
8
9
|
require_relative 'tinker/exception/network_exception'
|
|
9
10
|
require_relative 'tinker/exception/authentication_exception'
|
|
10
11
|
require_relative 'tinker/exception/invalid_payload_exception'
|
|
@@ -16,12 +17,19 @@ require_relative 'tinker/http/http_client'
|
|
|
16
17
|
require_relative 'tinker/auth/authentication_manager'
|
|
17
18
|
require_relative 'tinker/api/base_manager'
|
|
18
19
|
require_relative 'tinker/api/transaction_manager'
|
|
20
|
+
require_relative 'tinker/api/subscription_manager'
|
|
19
21
|
require_relative 'tinker/model/dto/initiate_payment_request_dto'
|
|
20
22
|
require_relative 'tinker/model/dto/query_payment_request_dto'
|
|
23
|
+
require_relative 'tinker/model/dto/create_subscription_plan_request_dto'
|
|
24
|
+
require_relative 'tinker/model/dto/subscription_customer_dto'
|
|
25
|
+
require_relative 'tinker/model/dto/create_subscription_request_dto'
|
|
26
|
+
require_relative 'tinker/model/dto/managed_checkout'
|
|
21
27
|
require_relative 'tinker/model/dto/initiation_data_dto'
|
|
22
28
|
require_relative 'tinker/model/dto/query_data_dto'
|
|
23
29
|
require_relative 'tinker/model/dto/callback_data_dto'
|
|
30
|
+
require_relative 'tinker/model/api_meta'
|
|
24
31
|
require_relative 'tinker/model/transaction'
|
|
32
|
+
require_relative 'tinker/webhook/dto/onboarding_event_data_dto'
|
|
25
33
|
require_relative 'tinker/webhook/dto/payment_event_data_dto'
|
|
26
34
|
require_relative 'tinker/webhook/dto/subscription_event_data_dto'
|
|
27
35
|
require_relative 'tinker/webhook/dto/invoice_event_data_dto'
|
|
@@ -30,4 +38,15 @@ require_relative 'tinker/webhook/webhook_meta'
|
|
|
30
38
|
require_relative 'tinker/webhook/webhook_security'
|
|
31
39
|
require_relative 'tinker/webhook/webhook_event'
|
|
32
40
|
require_relative 'tinker/webhook/webhook_handler'
|
|
41
|
+
require_relative 'tinker/model/lifecycle_resource'
|
|
42
|
+
require_relative 'tinker/model/refund'
|
|
43
|
+
require_relative 'tinker/model/payout'
|
|
44
|
+
require_relative 'tinker/model/checkout_cancellation'
|
|
45
|
+
require_relative 'tinker/model/refund_result'
|
|
46
|
+
require_relative 'tinker/model/payout_result'
|
|
47
|
+
require_relative 'tinker/model/cancellation_result'
|
|
48
|
+
require_relative 'tinker/model/dto/refund_request'
|
|
49
|
+
require_relative 'tinker/model/dto/payout_request'
|
|
50
|
+
require_relative 'tinker/model/dto/cancellation_request'
|
|
51
|
+
require_relative 'tinker/api/payout_manager'
|
|
33
52
|
require_relative 'tinker/payments'
|