pay 2.6.11 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pay might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +35 -693
- data/app/controllers/pay/webhooks/braintree_controller.rb +10 -3
- data/app/controllers/pay/webhooks/paddle_controller.rb +7 -8
- data/app/controllers/pay/webhooks/stripe_controller.rb +6 -3
- data/app/jobs/pay/{email_sync_job.rb → customer_sync_job.rb} +3 -4
- data/app/models/pay/application_record.rb +1 -5
- data/app/models/pay/charge.rb +32 -17
- data/app/models/pay/customer.rb +87 -0
- data/app/models/pay/merchant.rb +19 -0
- data/app/models/pay/payment_method.rb +41 -0
- data/app/models/pay/subscription.rb +34 -30
- data/app/models/pay/webhook.rb +36 -0
- data/app/views/layouts/pay/application.html.erb +2 -3
- data/app/views/pay/payments/show.html.erb +109 -81
- data/app/views/pay/user_mailer/receipt.html.erb +2 -2
- data/app/views/pay/user_mailer/refund.html.erb +2 -2
- data/config/locales/en.yml +1 -1
- data/db/migrate/1_create_pay_tables.rb +72 -0
- data/lib/generators/active_record/billable_generator.rb +44 -0
- data/lib/generators/active_record/merchant_generator.rb +44 -0
- data/lib/generators/active_record/templates/billable_migration.rb +17 -0
- data/lib/generators/active_record/templates/merchant_migration.rb +12 -0
- data/lib/generators/pay/{pay_generator.rb → billable_generator.rb} +2 -3
- data/lib/generators/pay/merchant_generator.rb +17 -0
- data/lib/generators/pay/orm_helpers.rb +10 -6
- data/lib/pay/adapter.rb +22 -0
- data/lib/pay/attributes.rb +74 -0
- data/lib/pay/billable/sync_customer.rb +30 -0
- data/lib/pay/braintree/billable.rb +130 -105
- data/lib/pay/braintree/payment_method.rb +33 -0
- data/lib/pay/braintree/subscription.rb +9 -12
- data/lib/pay/braintree/webhooks/subscription_canceled.rb +1 -1
- data/lib/pay/braintree/webhooks/subscription_charged_successfully.rb +4 -4
- data/lib/pay/braintree/webhooks/subscription_charged_unsuccessfully.rb +1 -1
- data/lib/pay/braintree/webhooks/subscription_expired.rb +1 -1
- data/lib/pay/braintree/webhooks/subscription_trial_ended.rb +2 -2
- data/lib/pay/braintree/webhooks/subscription_went_active.rb +1 -1
- data/lib/pay/braintree/webhooks/subscription_went_past_due.rb +1 -1
- data/lib/pay/braintree.rb +3 -2
- data/lib/pay/engine.rb +6 -1
- data/lib/pay/env.rb +8 -0
- data/lib/pay/fake_processor/billable.rb +45 -21
- data/lib/pay/fake_processor/payment_method.rb +21 -0
- data/lib/pay/fake_processor/subscription.rb +11 -8
- data/lib/pay/fake_processor.rb +2 -1
- data/lib/pay/merchant.rb +37 -0
- data/lib/pay/nano_id.rb +13 -0
- data/lib/pay/paddle/billable.rb +18 -48
- data/lib/pay/paddle/charge.rb +5 -5
- data/lib/pay/paddle/payment_method.rb +58 -0
- data/lib/pay/paddle/response.rb +0 -0
- data/lib/pay/paddle/subscription.rb +49 -8
- data/lib/pay/paddle/webhooks/subscription_cancelled.rb +6 -3
- data/lib/pay/paddle/webhooks/subscription_created.rb +1 -40
- data/lib/pay/paddle/webhooks/subscription_payment_refunded.rb +3 -3
- data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +23 -23
- data/lib/pay/paddle/webhooks/subscription_updated.rb +2 -2
- data/lib/pay/paddle.rb +7 -3
- data/lib/pay/payment.rb +1 -1
- data/lib/pay/receipts.rb +35 -7
- data/lib/pay/stripe/billable.rb +82 -93
- data/lib/pay/stripe/charge.rb +65 -4
- data/lib/pay/stripe/merchant.rb +66 -0
- data/lib/pay/stripe/payment_method.rb +61 -0
- data/lib/pay/stripe/subscription.rb +91 -24
- data/lib/pay/stripe/webhooks/account_updated.rb +16 -0
- data/lib/pay/stripe/webhooks/charge_refunded.rb +2 -7
- data/lib/pay/stripe/webhooks/charge_succeeded.rb +2 -8
- data/lib/pay/stripe/webhooks/checkout_session_async_payment_succeeded.rb +15 -0
- data/lib/pay/stripe/webhooks/checkout_session_completed.rb +15 -0
- data/lib/pay/stripe/webhooks/customer_deleted.rb +7 -15
- data/lib/pay/stripe/webhooks/customer_updated.rb +10 -3
- data/lib/pay/stripe/webhooks/payment_action_required.rb +2 -2
- data/lib/pay/stripe/webhooks/payment_intent_succeeded.rb +6 -14
- data/lib/pay/stripe/webhooks/payment_method_attached.rb +15 -0
- data/lib/pay/stripe/webhooks/payment_method_detached.rb +12 -0
- data/lib/pay/stripe/webhooks/payment_method_updated.rb +10 -4
- data/lib/pay/stripe/webhooks/subscription_created.rb +1 -35
- data/lib/pay/stripe/webhooks/subscription_deleted.rb +2 -9
- data/lib/pay/stripe/webhooks/subscription_renewing.rb +14 -6
- data/lib/pay/stripe/webhooks/subscription_updated.rb +1 -28
- data/lib/pay/stripe.rb +17 -3
- data/lib/pay/version.rb +1 -1
- data/lib/pay/webhooks/delegator.rb +4 -0
- data/lib/pay/webhooks/process_job.rb +9 -0
- data/lib/pay/webhooks.rb +1 -0
- data/lib/pay.rb +8 -57
- metadata +34 -36
- data/db/migrate/20170205020145_create_pay_subscriptions.rb +0 -17
- data/db/migrate/20170727235816_create_pay_charges.rb +0 -18
- data/db/migrate/20190816015720_add_status_to_pay_subscriptions.rb +0 -14
- data/db/migrate/20200603134434_add_data_to_pay_models.rb +0 -22
- data/db/migrate/20210423235138_add_currency_to_pay_charges.rb +0 -5
- data/lib/generators/active_record/pay_generator.rb +0 -58
- data/lib/generators/active_record/templates/migration.rb +0 -9
- data/lib/pay/billable/sync_email.rb +0 -40
- data/lib/pay/billable.rb +0 -168
data/lib/pay/nano_id.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Pay
|
2
|
+
module NanoId
|
3
|
+
# Generates unique IDs - faster than UUID
|
4
|
+
ALPHABET = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".freeze
|
5
|
+
ALPHABET_SIZE = ALPHABET.size
|
6
|
+
|
7
|
+
def self.generate(size: 21)
|
8
|
+
id = ""
|
9
|
+
size.times { id << ALPHABET[(Random.rand * ALPHABET_SIZE).floor] }
|
10
|
+
id
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/pay/paddle/billable.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
module Pay
|
2
2
|
module Paddle
|
3
3
|
class Billable
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :pay_customer
|
5
5
|
|
6
6
|
delegate :processor_id,
|
7
7
|
:processor_id?,
|
8
8
|
:email,
|
9
9
|
:customer_name,
|
10
10
|
:card_token,
|
11
|
-
to: :
|
11
|
+
to: :pay_customer
|
12
12
|
|
13
|
-
def initialize(
|
14
|
-
@
|
13
|
+
def initialize(pay_customer)
|
14
|
+
@pay_customer = pay_customer
|
15
15
|
end
|
16
16
|
|
17
17
|
def customer
|
@@ -19,17 +19,23 @@ module Pay
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def charge(amount, options = {})
|
22
|
-
subscription =
|
22
|
+
subscription = pay_customer.subscription
|
23
23
|
return unless subscription.processor_id
|
24
24
|
raise Pay::Error, "A charge_name is required to create a one-time charge" if options[:charge_name].nil?
|
25
|
+
|
25
26
|
response = PaddlePay::Subscription::Charge.create(subscription.processor_id, amount.to_f / 100, options[:charge_name], options)
|
26
|
-
|
27
|
-
|
28
|
-
amount:
|
29
|
-
card_type: processor_subscription(subscription.processor_id).payment_information[:payment_method],
|
27
|
+
|
28
|
+
attributes = {
|
29
|
+
amount: (response[:amount].to_f * 100).to_i,
|
30
30
|
paddle_receipt_url: response[:receipt_url],
|
31
31
|
created_at: Time.zone.parse(response[:payment_date])
|
32
|
-
|
32
|
+
}
|
33
|
+
|
34
|
+
# Lookup subscription payment method details
|
35
|
+
attributes.merge! Pay::Paddle::PaymentMethod.payment_method_details_for(subscription_id: subscription.processor_id)
|
36
|
+
|
37
|
+
charge = pay_customer.charges.find_or_initialize_by(processor_id: response[:invoice_id])
|
38
|
+
charge.update(attributes)
|
33
39
|
charge
|
34
40
|
rescue ::PaddlePay::PaddlePayError => e
|
35
41
|
raise Pay::Paddle::Error, e
|
@@ -39,8 +45,8 @@ module Pay
|
|
39
45
|
# pass
|
40
46
|
end
|
41
47
|
|
42
|
-
def
|
43
|
-
|
48
|
+
def add_payment_method(token, default: true)
|
49
|
+
Pay::Paddle::PaymentMethod.sync(self)
|
44
50
|
end
|
45
51
|
|
46
52
|
def update_email!
|
@@ -58,42 +64,6 @@ module Pay
|
|
58
64
|
rescue ::PaddlePay::PaddlePayError => e
|
59
65
|
raise Pay::Paddle::Error, e
|
60
66
|
end
|
61
|
-
|
62
|
-
def invoice!(options = {})
|
63
|
-
# pass
|
64
|
-
end
|
65
|
-
|
66
|
-
def upcoming_invoice
|
67
|
-
# pass
|
68
|
-
end
|
69
|
-
|
70
|
-
def sync_payment_information
|
71
|
-
billable.update!(payment_information(billable.subscription.processor_id))
|
72
|
-
rescue ::PaddlePay::PaddlePayError => e
|
73
|
-
raise Pay::Paddle::Error, e
|
74
|
-
end
|
75
|
-
|
76
|
-
def payment_information(subscription_id)
|
77
|
-
subscription_user = PaddlePay::Subscription::User.list({subscription_id: subscription_id}).try(:first)
|
78
|
-
payment_information = subscription_user ? subscription_user[:payment_information] : nil
|
79
|
-
return {} if payment_information.nil?
|
80
|
-
|
81
|
-
case payment_information[:payment_method]
|
82
|
-
when "card"
|
83
|
-
{
|
84
|
-
card_type: payment_information[:card_type],
|
85
|
-
card_last4: payment_information[:last_four_digits],
|
86
|
-
card_exp_month: payment_information[:expiry_date].split("/").first,
|
87
|
-
card_exp_year: payment_information[:expiry_date].split("/").last
|
88
|
-
}
|
89
|
-
when "paypal"
|
90
|
-
{
|
91
|
-
card_type: "PayPal"
|
92
|
-
}
|
93
|
-
else
|
94
|
-
{}
|
95
|
-
end
|
96
|
-
end
|
97
67
|
end
|
98
68
|
end
|
99
69
|
end
|
data/lib/pay/paddle/charge.rb
CHANGED
@@ -3,15 +3,15 @@ module Pay
|
|
3
3
|
class Charge
|
4
4
|
attr_reader :pay_charge
|
5
5
|
|
6
|
-
delegate :processor_id, :
|
6
|
+
delegate :processor_id, :customer, to: :pay_charge
|
7
7
|
|
8
8
|
def initialize(pay_charge)
|
9
9
|
@pay_charge = pay_charge
|
10
10
|
end
|
11
11
|
|
12
12
|
def charge
|
13
|
-
return unless
|
14
|
-
payments = PaddlePay::Subscription::Payment.list({subscription_id:
|
13
|
+
return unless customer.subscription
|
14
|
+
payments = PaddlePay::Subscription::Payment.list({subscription_id: customer.subscription.processor_id})
|
15
15
|
charges = payments.select { |p| p[:id].to_s == processor_id }
|
16
16
|
charges.try(:first)
|
17
17
|
rescue ::PaddlePay::PaddlePayError => e
|
@@ -19,8 +19,8 @@ module Pay
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def refund!(amount_to_refund)
|
22
|
-
return unless
|
23
|
-
payments = PaddlePay::Subscription::Payment.list({subscription_id:
|
22
|
+
return unless customer.subscription
|
23
|
+
payments = PaddlePay::Subscription::Payment.list({subscription_id: customer.subscription.processor_id, is_paid: 1})
|
24
24
|
if payments.count > 0
|
25
25
|
PaddlePay::Subscription::Payment.refund(payments.last[:id], {amount: amount_to_refund})
|
26
26
|
pay_charge.update(amount_refunded: amount_to_refund)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Pay
|
2
|
+
module Paddle
|
3
|
+
class PaymentMethod
|
4
|
+
attr_reader :pay_payment_method
|
5
|
+
|
6
|
+
delegate :customer, :processor_id, to: :pay_payment_method
|
7
|
+
|
8
|
+
# Paddle doesn't provide PaymentMethod IDs, so we have to lookup via the Customer
|
9
|
+
def self.sync(pay_customer:, attributes: nil)
|
10
|
+
payment_method = pay_customer.default_payment_method || pay_customer.build_default_payment_method
|
11
|
+
payment_method.processor_id ||= NanoId.generate
|
12
|
+
|
13
|
+
# Lookup payment method from API unless passed in
|
14
|
+
attributes ||= payment_method_details_for(subscription_id: pay_customer.subscription.processor_id)
|
15
|
+
|
16
|
+
payment_method.update!(attributes)
|
17
|
+
payment_method
|
18
|
+
rescue ::PaddlePay::PaddlePayError => e
|
19
|
+
raise Pay::Paddle::Error, e
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.payment_method_details_for(subscription_id:)
|
23
|
+
subscription_user = PaddlePay::Subscription::User.list({subscription_id: subscription_id}).try(:first)
|
24
|
+
payment_information = subscription_user ? subscription_user[:payment_information] : {}
|
25
|
+
|
26
|
+
case payment_information[:payment_method]
|
27
|
+
when "card"
|
28
|
+
{
|
29
|
+
payment_method_type: :card,
|
30
|
+
brand: payment_information[:card_type],
|
31
|
+
last4: payment_information[:last_four_digits],
|
32
|
+
exp_month: payment_information[:expiry_date].split("/").first,
|
33
|
+
exp_year: payment_information[:expiry_date].split("/").last
|
34
|
+
}
|
35
|
+
when "paypal"
|
36
|
+
{
|
37
|
+
payment_method_type: :paypal,
|
38
|
+
brand: "PayPal"
|
39
|
+
}
|
40
|
+
else
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(pay_payment_method)
|
46
|
+
@pay_payment_method = pay_payment_method
|
47
|
+
end
|
48
|
+
|
49
|
+
# Sets payment method as default
|
50
|
+
def make_default!
|
51
|
+
end
|
52
|
+
|
53
|
+
# Remove payment method
|
54
|
+
def detach
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
File without changes
|
@@ -20,6 +20,49 @@ module Pay
|
|
20
20
|
:trial_ends_at,
|
21
21
|
to: :pay_subscription
|
22
22
|
|
23
|
+
def self.sync(subscription_id, object: nil, name: Pay.default_product_name)
|
24
|
+
# Passthrough is not return from this API, so we can't use that
|
25
|
+
object ||= OpenStruct.new PaddlePay::Subscription::User.list({subscription_id: subscription_id}).try(:first)
|
26
|
+
|
27
|
+
pay_customer = Pay::Customer.find_by(processor: :paddle, processor_id: object.user_id)
|
28
|
+
|
29
|
+
# If passthrough exists (only on webhooks) we can use it to create the Pay::Customer
|
30
|
+
if pay_customer.nil? && object.passthrough
|
31
|
+
owner = Pay::Paddle.owner_from_passthrough(object.passthrough)
|
32
|
+
pay_customer = owner&.set_payment_processor(:paddle, processor_id: object.user_id)
|
33
|
+
end
|
34
|
+
|
35
|
+
return unless pay_customer
|
36
|
+
|
37
|
+
attributes = {
|
38
|
+
paddle_cancel_url: object.cancel_url,
|
39
|
+
paddle_update_url: object.update_url,
|
40
|
+
processor_plan: object.plan_id || object.subscription_plan_id,
|
41
|
+
quantity: object.quantity,
|
42
|
+
status: object.state || object.status
|
43
|
+
}
|
44
|
+
|
45
|
+
# If paused or delete while on trial, set ends_at to match
|
46
|
+
case attributes[:status]
|
47
|
+
when "trialing"
|
48
|
+
attributes[:trial_ends_at] = Time.zone.parse(object.next_bill_date)
|
49
|
+
attributes[:ends_at] = nil
|
50
|
+
when "paused", "deleted"
|
51
|
+
attributes[:trial_ends_at] = nil
|
52
|
+
attributes[:ends_at] = Time.zone.parse(object.next_bill_date)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Update or create the subscription
|
56
|
+
if (pay_subscription = pay_customer.subscriptions.find_by(processor_id: object.subscription_id))
|
57
|
+
pay_subscription.with_lock do
|
58
|
+
pay_subscription.update!(attributes)
|
59
|
+
end
|
60
|
+
pay_subscription
|
61
|
+
else
|
62
|
+
pay_customer.subscriptions.create!(attributes.merge(name: name, processor_id: object.subscription_id))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
23
66
|
def initialize(pay_subscription)
|
24
67
|
@pay_subscription = pay_subscription
|
25
68
|
end
|
@@ -32,26 +75,22 @@ module Pay
|
|
32
75
|
end
|
33
76
|
|
34
77
|
def cancel
|
35
|
-
|
78
|
+
ends_at = on_trial? ? trial_ends_at : processor_subscription.next_payment[:date]
|
36
79
|
PaddlePay::Subscription::User.cancel(processor_id)
|
37
|
-
|
38
|
-
pay_subscription.update(status: :canceled, ends_at: trial_ends_at)
|
39
|
-
else
|
40
|
-
pay_subscription.update(status: :canceled, ends_at: Time.zone.parse(subscription.next_payment[:date]))
|
41
|
-
end
|
80
|
+
pay_subscription.update(status: :canceled, ends_at: ends_at)
|
42
81
|
rescue ::PaddlePay::PaddlePayError => e
|
43
82
|
raise Pay::Paddle::Error, e
|
44
83
|
end
|
45
84
|
|
46
85
|
def cancel_now!
|
47
86
|
PaddlePay::Subscription::User.cancel(processor_id)
|
48
|
-
pay_subscription.update(status: :canceled, ends_at: Time.
|
87
|
+
pay_subscription.update(status: :canceled, ends_at: Time.current)
|
49
88
|
rescue ::PaddlePay::PaddlePayError => e
|
50
89
|
raise Pay::Paddle::Error, e
|
51
90
|
end
|
52
91
|
|
53
92
|
def on_grace_period?
|
54
|
-
canceled? && Time.
|
93
|
+
canceled? && Time.current < ends_at || paused? && Time.current < paddle_paused_from
|
55
94
|
end
|
56
95
|
|
57
96
|
def paused?
|
@@ -79,6 +118,8 @@ module Pay
|
|
79
118
|
end
|
80
119
|
|
81
120
|
def swap(plan)
|
121
|
+
raise ArgumentError, "plan must be a string" unless plan.is_a?(String)
|
122
|
+
|
82
123
|
attributes = {plan_id: plan, prorate: prorate}
|
83
124
|
attributes[:quantity] = quantity if quantity?
|
84
125
|
PaddlePay::Subscription::User.update(processor_id, attributes)
|
@@ -3,14 +3,17 @@ module Pay
|
|
3
3
|
module Webhooks
|
4
4
|
class SubscriptionCancelled
|
5
5
|
def call(event)
|
6
|
-
|
6
|
+
pay_subscription = Pay::Subscription.find_by_processor_and_id(:paddle, event.subscription_id)
|
7
7
|
|
8
8
|
# We couldn't find the subscription for some reason, maybe it's from another service
|
9
|
-
return if
|
9
|
+
return if pay_subscription.nil?
|
10
10
|
|
11
11
|
# User canceled subscriptions have an ends_at
|
12
12
|
# Automatically canceled subscriptions need this value set
|
13
|
-
|
13
|
+
pay_subscription.update!(ends_at: Time.zone.parse(event.cancellation_effective_date)) if pay_subscription.ends_at.blank? && event.cancellation_effective_date.present?
|
14
|
+
|
15
|
+
# Paddle doesn't allow reusing customers, so we should remove their payment methods
|
16
|
+
pay_subscription.customer.payment_methods.destroy_all
|
14
17
|
end
|
15
18
|
end
|
16
19
|
end
|
@@ -3,46 +3,7 @@ module Pay
|
|
3
3
|
module Webhooks
|
4
4
|
class SubscriptionCreated
|
5
5
|
def call(event)
|
6
|
-
|
7
|
-
subscription = Pay.subscription_model.find_by(processor: :paddle, processor_id: event["subscription_id"])
|
8
|
-
|
9
|
-
# Create the subscription in the database if we don't have it already
|
10
|
-
if subscription.nil?
|
11
|
-
|
12
|
-
# The customer could already be in the database
|
13
|
-
owner = Pay.find_billable(processor: :paddle, processor_id: event["user_id"])
|
14
|
-
|
15
|
-
if owner.nil?
|
16
|
-
owner = Pay::Paddle.owner_from_passthrough(event["passthrough"])
|
17
|
-
owner&.update!(processor: "paddle", processor_id: event["user_id"])
|
18
|
-
end
|
19
|
-
|
20
|
-
if owner.nil?
|
21
|
-
Rails.logger.error("[Pay] Unable to find Pay::Billable with owner: '#{event["passthrough"]}'. Searched these models: #{Pay.billable_models.join(", ")}")
|
22
|
-
return
|
23
|
-
end
|
24
|
-
|
25
|
-
subscription = Pay.subscription_model.new(owner: owner, name: Pay.default_product_name, processor: "paddle", processor_id: event["subscription_id"], status: :active)
|
26
|
-
end
|
27
|
-
|
28
|
-
subscription.quantity = event["quantity"]
|
29
|
-
subscription.processor_plan = event["subscription_plan_id"]
|
30
|
-
subscription.paddle_update_url = event["update_url"]
|
31
|
-
subscription.paddle_cancel_url = event["cancel_url"]
|
32
|
-
subscription.trial_ends_at = Time.zone.parse(event["next_bill_date"]) if event["status"] == "trialing"
|
33
|
-
|
34
|
-
# If user was on trial, their subscription ends at the end of the trial
|
35
|
-
subscription.ends_at = if ["paused", "deleted"].include?(event["status"]) && subscription.on_trial?
|
36
|
-
subscription.trial_ends_at
|
37
|
-
|
38
|
-
# User wasn't on trial, so subscription ends at period end
|
39
|
-
elsif ["paused", "deleted"].include?(event["status"])
|
40
|
-
Time.zone.parse(event["next_bill_date"])
|
41
|
-
|
42
|
-
# Subscription isn't marked to cancel at period end
|
43
|
-
end
|
44
|
-
|
45
|
-
subscription.save!
|
6
|
+
Pay::Paddle::Subscription.sync(event.subscription_id, object: event)
|
46
7
|
end
|
47
8
|
end
|
48
9
|
end
|
@@ -3,11 +3,11 @@ module Pay
|
|
3
3
|
module Webhooks
|
4
4
|
class SubscriptionPaymentRefunded
|
5
5
|
def call(event)
|
6
|
-
charge = Pay.
|
6
|
+
charge = Pay::Charge.find_by_processor_and_id(:paddle, event.subscription_payment_id)
|
7
7
|
return unless charge.present?
|
8
8
|
|
9
|
-
charge.update(amount_refunded:
|
10
|
-
notify_user(charge.owner, charge)
|
9
|
+
charge.update(amount_refunded: (event.gross_refund.to_f * 100).to_i)
|
10
|
+
notify_user(charge.customer.owner, charge)
|
11
11
|
end
|
12
12
|
|
13
13
|
def notify_user(billable, charge)
|
@@ -3,41 +3,41 @@ module Pay
|
|
3
3
|
module Webhooks
|
4
4
|
class SubscriptionPaymentSucceeded
|
5
5
|
def call(event)
|
6
|
-
|
6
|
+
pay_customer = Pay::Customer.find_by(processor: :paddle, processor_id: event.user_id)
|
7
7
|
|
8
|
-
if
|
9
|
-
|
10
|
-
|
8
|
+
if pay_customer.nil?
|
9
|
+
owner = Pay::Paddle.owner_from_passthrough(event.passthrough)
|
10
|
+
pay_customer = owner&.set_payment_processor :paddle, processor_id: event.user_id
|
11
11
|
end
|
12
12
|
|
13
|
-
if
|
14
|
-
Rails.logger.error("[Pay] Unable to find Pay::
|
13
|
+
if pay_customer.nil?
|
14
|
+
Rails.logger.error("[Pay] Unable to find Pay::Customer with: '#{event.passthrough}'")
|
15
15
|
return
|
16
16
|
end
|
17
17
|
|
18
|
-
return if
|
18
|
+
return if pay_customer.charges.where(processor_id: event.subscription_payment_id).any?
|
19
19
|
|
20
|
-
charge = create_charge(
|
21
|
-
notify_user(
|
20
|
+
charge = create_charge(pay_customer, event)
|
21
|
+
notify_user(pay_customer.owner, charge)
|
22
22
|
end
|
23
23
|
|
24
|
-
def create_charge(
|
25
|
-
|
26
|
-
processor: :paddle,
|
27
|
-
processor_id: event["subscription_payment_id"]
|
28
|
-
)
|
24
|
+
def create_charge(pay_customer, event)
|
25
|
+
payment_method_details = Pay::Paddle::PaymentMethod.payment_method_details_for(subscription_id: event.subscription_id)
|
29
26
|
|
30
|
-
|
31
|
-
amount:
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
attributes = {
|
28
|
+
amount: (event.sale_gross.to_f * 100).to_i,
|
29
|
+
created_at: Time.zone.parse(event.event_time),
|
30
|
+
currency: event.currency,
|
31
|
+
paddle_receipt_url: event.receipt_url,
|
32
|
+
subscription: pay_customer.subscriptions.find_by(processor_id: event.subscription_id),
|
33
|
+
metadata: Pay::Paddle.parse_passthrough(event.passthrough).except("owner_sgid")
|
34
|
+
}.merge(payment_method_details)
|
36
35
|
|
37
|
-
|
36
|
+
charge = pay_customer.charges.find_or_initialize_by(processor_id: event.subscription_payment_id)
|
37
|
+
charge.update!(attributes)
|
38
38
|
|
39
|
-
|
40
|
-
|
39
|
+
# Update customer's payment method
|
40
|
+
Pay::Paddle::PaymentMethod.sync(pay_customer: pay_customer, attributes: payment_method_details)
|
41
41
|
|
42
42
|
charge
|
43
43
|
end
|