pay 2.7.0 → 3.0.1

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.

Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -696
  3. data/app/controllers/pay/webhooks/braintree_controller.rb +10 -3
  4. data/app/controllers/pay/webhooks/paddle_controller.rb +7 -8
  5. data/app/controllers/pay/webhooks/stripe_controller.rb +6 -3
  6. data/app/jobs/pay/{email_sync_job.rb → customer_sync_job.rb} +3 -4
  7. data/app/models/pay/application_record.rb +1 -5
  8. data/app/models/pay/charge.rb +31 -18
  9. data/app/models/pay/customer.rb +87 -0
  10. data/app/models/pay/merchant.rb +19 -0
  11. data/app/models/pay/payment_method.rb +41 -0
  12. data/app/models/pay/subscription.rb +42 -30
  13. data/app/models/pay/webhook.rb +36 -0
  14. data/app/views/layouts/pay/application.html.erb +2 -3
  15. data/app/views/pay/payments/show.html.erb +109 -81
  16. data/app/views/pay/user_mailer/receipt.html.erb +2 -2
  17. data/app/views/pay/user_mailer/refund.html.erb +2 -2
  18. data/config/locales/en.yml +1 -1
  19. data/db/migrate/1_create_pay_tables.rb +72 -0
  20. data/lib/generators/active_record/billable_generator.rb +44 -0
  21. data/lib/generators/active_record/merchant_generator.rb +44 -0
  22. data/lib/generators/active_record/templates/billable_migration.rb +17 -0
  23. data/lib/generators/active_record/templates/merchant_migration.rb +12 -0
  24. data/lib/generators/pay/{pay_generator.rb → billable_generator.rb} +2 -3
  25. data/lib/generators/pay/merchant_generator.rb +17 -0
  26. data/lib/generators/pay/orm_helpers.rb +10 -6
  27. data/lib/pay/adapter.rb +9 -0
  28. data/lib/pay/attributes.rb +74 -0
  29. data/lib/pay/billable/sync_customer.rb +30 -0
  30. data/lib/pay/braintree/billable.rb +133 -110
  31. data/lib/pay/braintree/payment_method.rb +42 -0
  32. data/lib/pay/braintree/subscription.rb +9 -12
  33. data/lib/pay/braintree/webhooks/subscription_canceled.rb +1 -1
  34. data/lib/pay/braintree/webhooks/subscription_charged_successfully.rb +4 -4
  35. data/lib/pay/braintree/webhooks/subscription_charged_unsuccessfully.rb +1 -1
  36. data/lib/pay/braintree/webhooks/subscription_expired.rb +1 -1
  37. data/lib/pay/braintree/webhooks/subscription_trial_ended.rb +2 -2
  38. data/lib/pay/braintree/webhooks/subscription_went_active.rb +1 -1
  39. data/lib/pay/braintree/webhooks/subscription_went_past_due.rb +1 -1
  40. data/lib/pay/braintree.rb +3 -2
  41. data/lib/pay/engine.rb +6 -1
  42. data/lib/pay/env.rb +8 -0
  43. data/lib/pay/fake_processor/billable.rb +45 -21
  44. data/lib/pay/fake_processor/payment_method.rb +21 -0
  45. data/lib/pay/fake_processor/subscription.rb +11 -8
  46. data/lib/pay/fake_processor.rb +2 -1
  47. data/lib/pay/nano_id.rb +13 -0
  48. data/lib/pay/paddle/billable.rb +18 -48
  49. data/lib/pay/paddle/charge.rb +5 -5
  50. data/lib/pay/paddle/payment_method.rb +60 -0
  51. data/lib/pay/paddle/response.rb +0 -0
  52. data/lib/pay/paddle/subscription.rb +49 -8
  53. data/lib/pay/paddle/webhooks/subscription_cancelled.rb +6 -3
  54. data/lib/pay/paddle/webhooks/subscription_created.rb +1 -40
  55. data/lib/pay/paddle/webhooks/subscription_payment_refunded.rb +3 -3
  56. data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +26 -28
  57. data/lib/pay/paddle/webhooks/subscription_updated.rb +2 -2
  58. data/lib/pay/paddle.rb +7 -3
  59. data/lib/pay/payment.rb +1 -1
  60. data/lib/pay/receipts.rb +35 -7
  61. data/lib/pay/stripe/billable.rb +80 -102
  62. data/lib/pay/stripe/charge.rb +59 -3
  63. data/lib/pay/stripe/merchant.rb +10 -10
  64. data/lib/pay/stripe/payment_method.rb +61 -0
  65. data/lib/pay/stripe/subscription.rb +70 -8
  66. data/lib/pay/stripe/webhooks/account_updated.rb +2 -3
  67. data/lib/pay/stripe/webhooks/charge_refunded.rb +2 -7
  68. data/lib/pay/stripe/webhooks/charge_succeeded.rb +2 -8
  69. data/lib/pay/stripe/webhooks/checkout_session_async_payment_succeeded.rb +15 -0
  70. data/lib/pay/stripe/webhooks/checkout_session_completed.rb +15 -0
  71. data/lib/pay/stripe/webhooks/customer_deleted.rb +7 -15
  72. data/lib/pay/stripe/webhooks/customer_updated.rb +10 -3
  73. data/lib/pay/stripe/webhooks/payment_action_required.rb +2 -2
  74. data/lib/pay/stripe/webhooks/payment_intent_succeeded.rb +6 -14
  75. data/lib/pay/stripe/webhooks/payment_method_attached.rb +15 -0
  76. data/lib/pay/stripe/webhooks/payment_method_detached.rb +12 -0
  77. data/lib/pay/stripe/webhooks/payment_method_updated.rb +10 -4
  78. data/lib/pay/stripe/webhooks/subscription_created.rb +1 -36
  79. data/lib/pay/stripe/webhooks/subscription_deleted.rb +2 -9
  80. data/lib/pay/stripe/webhooks/subscription_renewing.rb +14 -6
  81. data/lib/pay/stripe/webhooks/subscription_updated.rb +1 -29
  82. data/lib/pay/stripe.rb +12 -3
  83. data/lib/pay/version.rb +1 -1
  84. data/lib/pay/webhooks/delegator.rb +4 -0
  85. data/lib/pay/webhooks/process_job.rb +9 -0
  86. data/lib/pay/webhooks.rb +1 -0
  87. data/lib/pay.rb +7 -78
  88. data/lib/tasks/pay.rake +20 -0
  89. metadata +31 -39
  90. data/app/models/pay.rb +0 -5
  91. data/db/migrate/20170205020145_create_pay_subscriptions.rb +0 -17
  92. data/db/migrate/20170727235816_create_pay_charges.rb +0 -18
  93. data/db/migrate/20190816015720_add_status_to_pay_subscriptions.rb +0 -14
  94. data/db/migrate/20200603134434_add_data_to_pay_models.rb +0 -15
  95. data/db/migrate/20210309004259_add_data_to_pay_billable.rb +0 -19
  96. data/db/migrate/20210406215234_add_currency_to_pay_charges.rb +0 -5
  97. data/db/migrate/20210406215506_add_application_fee_to_pay_models.rb +0 -7
  98. data/lib/generators/active_record/pay_generator.rb +0 -58
  99. data/lib/generators/active_record/templates/migration.rb +0 -9
  100. data/lib/pay/billable/sync_email.rb +0 -40
  101. data/lib/pay/billable.rb +0 -172
@@ -1,17 +1,17 @@
1
1
  module Pay
2
2
  module Paddle
3
3
  class Billable
4
- attr_reader :billable
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: :billable
11
+ to: :pay_customer
12
12
 
13
- def initialize(billable)
14
- @billable = billable
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 = billable.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
- charge = billable.charges.find_or_initialize_by(processor: :paddle, processor_id: response[:invoice_id])
27
- charge.update(
28
- amount: Integer(response[:amount].to_f * 100),
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 update_card(token)
43
- sync_payment_information_from_paddle
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
@@ -3,15 +3,15 @@ module Pay
3
3
  class Charge
4
4
  attr_reader :pay_charge
5
5
 
6
- delegate :processor_id, :owner, to: :pay_charge
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 owner.subscription
14
- payments = PaddlePay::Subscription::Payment.list({subscription_id: owner.subscription.processor_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 owner.subscription
23
- payments = PaddlePay::Subscription::Payment.list({subscription_id: owner.subscription.processor_id, is_paid: 1})
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,60 @@
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
+ return unless pay_customer.subscription
11
+
12
+ payment_method = pay_customer.default_payment_method || pay_customer.build_default_payment_method
13
+ payment_method.processor_id ||= NanoId.generate
14
+
15
+ # Lookup payment method from API unless passed in
16
+ attributes ||= payment_method_details_for(subscription_id: pay_customer.subscription.processor_id)
17
+
18
+ payment_method.update!(attributes)
19
+ payment_method
20
+ rescue ::PaddlePay::PaddlePayError => e
21
+ raise Pay::Paddle::Error, e
22
+ end
23
+
24
+ def self.payment_method_details_for(subscription_id:)
25
+ subscription_user = PaddlePay::Subscription::User.list({subscription_id: subscription_id}).try(:first)
26
+ payment_information = subscription_user ? subscription_user[:payment_information] : {}
27
+
28
+ case payment_information[:payment_method]
29
+ when "card"
30
+ {
31
+ payment_method_type: :card,
32
+ brand: payment_information[:card_type],
33
+ last4: payment_information[:last_four_digits],
34
+ exp_month: payment_information[:expiry_date].split("/").first,
35
+ exp_year: payment_information[:expiry_date].split("/").last
36
+ }
37
+ when "paypal"
38
+ {
39
+ payment_method_type: :paypal,
40
+ brand: "PayPal"
41
+ }
42
+ else
43
+ {}
44
+ end
45
+ end
46
+
47
+ def initialize(pay_payment_method)
48
+ @pay_payment_method = pay_payment_method
49
+ end
50
+
51
+ # Sets payment method as default
52
+ def make_default!
53
+ end
54
+
55
+ # Remove payment method
56
+ def detach
57
+ end
58
+ end
59
+ end
60
+ 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
- subscription = processor_subscription
78
+ ends_at = on_trial? ? trial_ends_at : processor_subscription.next_payment[:date]
36
79
  PaddlePay::Subscription::User.cancel(processor_id)
37
- if on_trial?
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.zone.now)
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.zone.now < ends_at || paused? && Time.zone.now < paddle_paused_from
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
- subscription = Pay.subscription_model.find_by(processor: :paddle, processor_id: event["subscription_id"])
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 subscription.nil?
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
- subscription.update!(ends_at: Time.zone.parse(event["cancellation_effective_date"])) if subscription.ends_at.blank? && event["cancellation_effective_date"].present?
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
- # We may already have the subscription in the database, so we can update that record
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.charge_model.find_by(processor: :paddle, processor_id: event["subscription_payment_id"])
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: Integer(event["gross_refund"].to_f * 100))
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,43 +3,41 @@ module Pay
3
3
  module Webhooks
4
4
  class SubscriptionPaymentSucceeded
5
5
  def call(event)
6
- billable = Pay.find_billable(processor: :paddle, processor_id: event["user_id"])
6
+ pay_customer = Pay::Customer.find_by(processor: :paddle, processor_id: event.user_id)
7
7
 
8
- if billable.nil?
9
- billable = Pay::Paddle.owner_from_passthrough(event["passthrough"])
10
- billable&.update!(processor: "paddle", processor_id: event["user_id"])
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 billable.nil?
14
- Rails.logger.error("[Pay] Unable to find Pay::Billable with owner: '#{event["passthrough"]}'. Searched these models: #{Pay.billable_models.join(", ")}")
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 billable.charges.where(processor_id: event["subscription_payment_id"]).any?
18
+ return if pay_customer.charges.where(processor_id: event.subscription_payment_id).any?
19
19
 
20
- charge = create_charge(billable, event)
21
- notify_user(billable, charge)
20
+ charge = create_charge(pay_customer, event)
21
+ notify_user(pay_customer.owner, charge)
22
22
  end
23
23
 
24
- def create_charge(user, event)
25
- charge = user.charges.find_or_initialize_by(
26
- processor: :paddle,
27
- processor_id: event["subscription_payment_id"]
28
- )
29
-
30
- params = {
31
- amount: Integer(event["sale_gross"].to_f * 100),
32
- card_type: event["payment_method"],
33
- created_at: Time.zone.parse(event["event_time"]),
34
- currency: event["currency"],
35
- paddle_receipt_url: event["receipt_url"],
36
- subscription: Pay::Subscription.find_by(processor: :paddle, processor_id: event["subscription_id"])
37
- }
38
-
39
- payment_information = Pay::Paddle::Billable.new(user).payment_information(event["subscription_id"])
40
-
41
- charge.update(params.merge(payment_information))
42
- user.update(payment_information)
24
+ def create_charge(pay_customer, event)
25
+ payment_method_details = Pay::Paddle::PaymentMethod.payment_method_details_for(subscription_id: event.subscription_id)
26
+
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)
35
+
36
+ charge = pay_customer.charges.find_or_initialize_by(processor_id: event.subscription_payment_id)
37
+ charge.update!(attributes)
38
+
39
+ # Update customer's payment method
40
+ Pay::Paddle::PaymentMethod.sync(pay_customer: pay_customer, attributes: payment_method_details)
43
41
 
44
42
  charge
45
43
  end
@@ -3,14 +3,14 @@ module Pay
3
3
  module Webhooks
4
4
  class SubscriptionUpdated
5
5
  def call(event)
6
- subscription = Pay.subscription_model.find_by(processor: :paddle, processor_id: event["subscription_id"])
6
+ subscription = Pay::Subscription.find_by_processor_and_id(:paddle, event["subscription_id"])
7
7
 
8
8
  return if subscription.nil?
9
9
 
10
10
  case event["status"]
11
11
  when "deleted"
12
12
  subscription.status = "canceled"
13
- subscription.ends_at = Time.zone.parse(event["next_bill_date"]) || Time.zone.now if subscription.ends_at.blank?
13
+ subscription.ends_at = Time.zone.parse(event["next_bill_date"]) || Time.current if subscription.ends_at.blank?
14
14
  when "trialing"
15
15
  subscription.status = "trialing"
16
16
  subscription.trial_ends_at = Time.zone.parse(event["next_bill_date"])