pay 2.7.1 → 3.0.2

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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +34 -715
  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 +54 -17
  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 +108 -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/templates/billable_migration.rb +1 -0
  21. data/lib/pay/attributes.rb +74 -0
  22. data/lib/pay/billable/sync_customer.rb +30 -0
  23. data/lib/pay/braintree/billable.rb +133 -110
  24. data/lib/pay/braintree/payment_method.rb +42 -0
  25. data/lib/pay/braintree/subscription.rb +9 -12
  26. data/lib/pay/braintree/webhooks/subscription_canceled.rb +1 -1
  27. data/lib/pay/braintree/webhooks/subscription_charged_successfully.rb +4 -4
  28. data/lib/pay/braintree/webhooks/subscription_charged_unsuccessfully.rb +1 -1
  29. data/lib/pay/braintree/webhooks/subscription_expired.rb +1 -1
  30. data/lib/pay/braintree/webhooks/subscription_trial_ended.rb +2 -2
  31. data/lib/pay/braintree/webhooks/subscription_went_active.rb +1 -1
  32. data/lib/pay/braintree/webhooks/subscription_went_past_due.rb +1 -1
  33. data/lib/pay/braintree.rb +3 -2
  34. data/lib/pay/engine.rb +6 -1
  35. data/lib/pay/fake_processor/billable.rb +45 -21
  36. data/lib/pay/fake_processor/payment_method.rb +21 -0
  37. data/lib/pay/fake_processor/subscription.rb +11 -8
  38. data/lib/pay/fake_processor.rb +2 -1
  39. data/lib/pay/nano_id.rb +13 -0
  40. data/lib/pay/paddle/billable.rb +18 -48
  41. data/lib/pay/paddle/charge.rb +5 -5
  42. data/lib/pay/paddle/payment_method.rb +60 -0
  43. data/lib/pay/paddle/response.rb +0 -0
  44. data/lib/pay/paddle/subscription.rb +49 -8
  45. data/lib/pay/paddle/webhooks/subscription_cancelled.rb +6 -3
  46. data/lib/pay/paddle/webhooks/subscription_created.rb +1 -40
  47. data/lib/pay/paddle/webhooks/subscription_payment_refunded.rb +3 -3
  48. data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +26 -28
  49. data/lib/pay/paddle/webhooks/subscription_updated.rb +2 -2
  50. data/lib/pay/paddle.rb +7 -3
  51. data/lib/pay/payment.rb +1 -1
  52. data/lib/pay/receipts.rb +35 -7
  53. data/lib/pay/stripe/billable.rb +75 -76
  54. data/lib/pay/stripe/charge.rb +44 -17
  55. data/lib/pay/stripe/merchant.rb +10 -10
  56. data/lib/pay/stripe/payment_method.rb +61 -0
  57. data/lib/pay/stripe/subscription.rb +55 -22
  58. data/lib/pay/stripe/webhooks/account_updated.rb +2 -3
  59. data/lib/pay/stripe/webhooks/charge_refunded.rb +1 -1
  60. data/lib/pay/stripe/webhooks/charge_succeeded.rb +2 -2
  61. data/lib/pay/stripe/webhooks/checkout_session_async_payment_succeeded.rb +3 -1
  62. data/lib/pay/stripe/webhooks/checkout_session_completed.rb +3 -1
  63. data/lib/pay/stripe/webhooks/customer_deleted.rb +7 -15
  64. data/lib/pay/stripe/webhooks/customer_updated.rb +10 -3
  65. data/lib/pay/stripe/webhooks/payment_action_required.rb +2 -2
  66. data/lib/pay/stripe/webhooks/payment_intent_succeeded.rb +6 -8
  67. data/lib/pay/stripe/webhooks/payment_method_attached.rb +15 -0
  68. data/lib/pay/stripe/webhooks/payment_method_detached.rb +12 -0
  69. data/lib/pay/stripe/webhooks/payment_method_updated.rb +10 -4
  70. data/lib/pay/stripe/webhooks/subscription_created.rb +1 -1
  71. data/lib/pay/stripe/webhooks/subscription_deleted.rb +2 -1
  72. data/lib/pay/stripe/webhooks/subscription_renewing.rb +12 -2
  73. data/lib/pay/stripe.rb +6 -3
  74. data/lib/pay/version.rb +1 -1
  75. data/lib/pay/webhooks/delegator.rb +4 -0
  76. data/lib/pay/webhooks/process_job.rb +9 -0
  77. data/lib/pay/webhooks.rb +1 -0
  78. data/lib/pay.rb +7 -78
  79. data/lib/tasks/pay.rake +20 -0
  80. metadata +23 -36
  81. data/app/models/pay.rb +0 -5
  82. data/db/migrate/20170205020145_create_pay_subscriptions.rb +0 -17
  83. data/db/migrate/20170727235816_create_pay_charges.rb +0 -18
  84. data/db/migrate/20190816015720_add_status_to_pay_subscriptions.rb +0 -14
  85. data/db/migrate/20200603134434_add_data_to_pay_models.rb +0 -6
  86. data/db/migrate/20210309004259_add_data_to_pay_billable.rb +0 -10
  87. data/db/migrate/20210406215234_add_currency_to_pay_charges.rb +0 -5
  88. data/db/migrate/20210406215506_add_application_fee_to_pay_models.rb +0 -7
  89. data/lib/pay/billable/sync_email.rb +0 -40
  90. data/lib/pay/billable.rb +0 -172
@@ -3,35 +3,55 @@ module Pay
3
3
  class Charge
4
4
  attr_reader :pay_charge
5
5
 
6
- delegate :processor_id, :owner, :stripe_account, to: :pay_charge
6
+ delegate :processor_id, :stripe_account, to: :pay_charge
7
7
 
8
- def self.sync(charge_id, object: nil)
9
- object ||= ::Stripe::Charge.retrieve(id: charge_id)
10
- owner = Pay.find_billable(processor: :stripe, processor_id: object.customer)
11
- return unless owner
8
+ def self.sync(charge_id, object: nil, stripe_account: nil, try: 0, retries: 1)
9
+ # Skip loading the latest charge details from the API if we already have it
10
+ object ||= ::Stripe::Charge.retrieve(charge_id, {stripe_account: stripe_account}.compact)
12
11
 
12
+ pay_customer = Pay::Customer.find_by(processor: :stripe, processor_id: object.customer)
13
+ return unless pay_customer
14
+
15
+ payment_method = object.payment_method_details.send(object.payment_method_details.type)
13
16
  attrs = {
14
17
  amount: object.amount,
15
18
  amount_refunded: object.amount_refunded,
16
19
  application_fee_amount: object.application_fee_amount,
17
- card_exp_month: object.payment_method_details.card.exp_month,
18
- card_exp_year: object.payment_method_details.card.exp_year,
19
- card_last4: object.payment_method_details.card.last4,
20
- card_type: object.payment_method_details.card.brand,
21
20
  created_at: Time.at(object.created),
22
21
  currency: object.currency,
23
- stripe_account: owner.stripe_account
22
+ stripe_account: pay_customer.stripe_account,
23
+ metadata: object.metadata,
24
+ payment_method_type: object.payment_method_details.type,
25
+ brand: payment_method.try(:brand)&.capitalize,
26
+ last4: payment_method.try(:last4).to_s,
27
+ exp_month: payment_method.try(:exp_month).to_s,
28
+ exp_year: payment_method.try(:exp_year).to_s,
29
+ bank: payment_method.try(:bank_name) || payment_method.try(:bank) # eps, fpx, ideal, p24, acss_debit, etc
24
30
  }
25
31
 
26
32
  # Associate charge with subscription if we can
27
33
  if object.invoice
28
- invoice = (object.invoice.is_a?(::Stripe::Invoice) ? object.invoice : ::Stripe::Invoice.retrieve(object.invoice))
29
- attrs[:subscription] = Pay::Subscription.find_by(processor: :stripe, processor_id: invoice.subscription)
34
+ invoice = (object.invoice.is_a?(::Stripe::Invoice) ? object.invoice : ::Stripe::Invoice.retrieve(object.invoice, {stripe_account: stripe_account}.compact))
35
+ attrs[:subscription] = pay_customer.subscriptions.find_by(processor_id: invoice.subscription)
30
36
  end
31
37
 
32
- pay_charge = owner.charges.find_or_initialize_by(processor: :stripe, processor_id: object.id)
33
- pay_charge.update(attrs)
34
- pay_charge
38
+ # Update or create the charge
39
+ if (pay_charge = pay_customer.charges.find_by(processor_id: object.id))
40
+ pay_charge.with_lock do
41
+ pay_charge.update!(attrs)
42
+ end
43
+ pay_charge
44
+ else
45
+ pay_customer.charges.create!(attrs.merge(processor_id: object.id))
46
+ end
47
+ rescue ActiveRecord::RecordInvalid
48
+ try += 1
49
+ if try <= retries
50
+ sleep 0.1
51
+ retry
52
+ else
53
+ raise
54
+ end
35
55
  end
36
56
 
37
57
  def initialize(pay_charge)
@@ -39,7 +59,7 @@ module Pay
39
59
  end
40
60
 
41
61
  def charge
42
- ::Stripe::Charge.retrieve({id: processor_id, expand: ["customer", "invoice.subscription"]}, {stripe_account: stripe_account})
62
+ ::Stripe::Charge.retrieve({id: processor_id, expand: ["customer", "invoice.subscription"]}, stripe_options)
43
63
  rescue ::Stripe::StripeError => e
44
64
  raise Pay::Stripe::Error, e
45
65
  end
@@ -50,11 +70,18 @@ module Pay
50
70
  # refund!(5_00)
51
71
  # refund!(5_00, refund_application_fee: true)
52
72
  def refund!(amount_to_refund, **options)
53
- ::Stripe::Refund.create(options.merge(charge: processor_id, amount: amount_to_refund), {stripe_account: stripe_account})
73
+ ::Stripe::Refund.create(options.merge(charge: processor_id, amount: amount_to_refund), stripe_options)
54
74
  pay_charge.update(amount_refunded: amount_to_refund)
55
75
  rescue ::Stripe::StripeError => e
56
76
  raise Pay::Stripe::Error, e
57
77
  end
78
+
79
+ private
80
+
81
+ # Options for Stripe requests
82
+ def stripe_options
83
+ {stripe_account: stripe_account}.compact
84
+ end
58
85
  end
59
86
  end
60
87
  end
@@ -1,13 +1,13 @@
1
1
  module Pay
2
2
  module Stripe
3
3
  class Merchant
4
- attr_reader :merchant
4
+ attr_reader :pay_merchant
5
5
 
6
- delegate :stripe_connect_account_id,
7
- to: :merchant
6
+ delegate :processor_id,
7
+ to: :pay_merchant
8
8
 
9
- def initialize(merchant)
10
- @merchant = merchant
9
+ def initialize(pay_merchant)
10
+ @pay_merchant = pay_merchant
11
11
  end
12
12
 
13
13
  def create_account(**options)
@@ -20,21 +20,21 @@ module Pay
20
20
  }
21
21
 
22
22
  stripe_account = ::Stripe::Account.create(defaults.merge(options))
23
- merchant.update(stripe_connect_account_id: stripe_account.id)
23
+ pay_merchant.update(processor_id: stripe_account.id)
24
24
  stripe_account
25
25
  rescue ::Stripe::StripeError => e
26
26
  raise Pay::Stripe::Error, e
27
27
  end
28
28
 
29
29
  def account
30
- ::Stripe::Account.retrieve(stripe_connect_account_id)
30
+ ::Stripe::Account.retrieve(processor_id)
31
31
  rescue ::Stripe::StripeError => e
32
32
  raise Pay::Stripe::Error, e
33
33
  end
34
34
 
35
35
  def account_link(refresh_url:, return_url:, type: "account_onboarding", **options)
36
36
  ::Stripe::AccountLink.create({
37
- account: stripe_connect_account_id,
37
+ account: processor_id,
38
38
  refresh_url: refresh_url,
39
39
  return_url: return_url,
40
40
  type: type
@@ -45,7 +45,7 @@ module Pay
45
45
 
46
46
  # A single-use login link for Express accounts to access their Stripe dashboard
47
47
  def login_link(**options)
48
- ::Stripe::Account.create_login_link(stripe_connect_account_id)
48
+ ::Stripe::Account.create_login_link(processor_id)
49
49
  rescue ::Stripe::StripeError => e
50
50
  raise Pay::Stripe::Error, e
51
51
  end
@@ -56,7 +56,7 @@ module Pay
56
56
  ::Stripe::Transfer.create({
57
57
  amount: amount,
58
58
  currency: currency,
59
- destination: stripe_connect_account_id
59
+ destination: processor_id
60
60
  }.merge(options))
61
61
  rescue ::Stripe::StripeError => e
62
62
  raise Pay::Stripe::Error, e
@@ -0,0 +1,61 @@
1
+ module Pay
2
+ module Stripe
3
+ class PaymentMethod
4
+ attr_reader :pay_payment_method
5
+
6
+ delegate :customer, :processor_id, to: :pay_payment_method
7
+
8
+ def initialize(pay_payment_method)
9
+ @pay_payment_method = pay_payment_method
10
+ end
11
+
12
+ def self.sync(id, object: nil, stripe_account: nil, try: 0, retries: 1)
13
+ object ||= ::Stripe::PaymentMethod.retrieve(id, {stripe_account: stripe_account}.compact)
14
+
15
+ pay_customer = Pay::Customer.find_by(processor: :stripe, processor_id: object.customer)
16
+ return unless pay_customer
17
+
18
+ default_payment_method_id = pay_customer.customer.invoice_settings.default_payment_method
19
+ default = (id == default_payment_method_id)
20
+
21
+ attributes = extract_attributes(object).merge(default: default)
22
+
23
+ pay_customer.payment_methods.update_all(default: false) if default
24
+ pay_payment_method = pay_customer.payment_methods.where(processor_id: object.id).first_or_initialize
25
+ pay_payment_method.update!(attributes)
26
+ pay_payment_method
27
+ end
28
+
29
+ # Extracts payment method details from a Stripe::PaymentMethod object
30
+ def self.extract_attributes(payment_method)
31
+ details = payment_method.send(payment_method.type)
32
+
33
+ {
34
+ payment_method_type: payment_method.type,
35
+ brand: details.try(:brand)&.capitalize,
36
+ last4: details.try(:last4).to_s,
37
+ exp_month: details.try(:exp_month).to_s,
38
+ exp_year: details.try(:exp_year).to_s,
39
+ bank: details.try(:bank_name) || details.try(:bank) # eps, fpx, ideal, p24, acss_debit, etc
40
+ }
41
+ end
42
+
43
+ # Sets payment method as default
44
+ def make_default!
45
+ ::Stripe::Customer.update(customer.processor_id, {invoice_settings: {default_payment_method: processor_id}}, stripe_options)
46
+ end
47
+
48
+ # Remove payment method
49
+ def detach
50
+ ::Stripe::PaymentMethod.detach(processor_id, stripe_options)
51
+ end
52
+
53
+ private
54
+
55
+ # Options for Stripe requests
56
+ def stripe_options
57
+ {stripe_account: customer.stripe_account}.compact
58
+ end
59
+ end
60
+ end
61
+ end
@@ -8,7 +8,6 @@ module Pay
8
8
  :ends_at,
9
9
  :name,
10
10
  :on_trial?,
11
- :owner,
12
11
  :processor_id,
13
12
  :processor_plan,
14
13
  :processor_subscription,
@@ -20,33 +19,56 @@ module Pay
20
19
  :trial_ends_at,
21
20
  to: :pay_subscription
22
21
 
23
- def self.sync(subscription_id, object: nil, name: Pay.default_product_name)
22
+ def self.sync(subscription_id, object: nil, name: Pay.default_product_name, stripe_account: nil, try: 0, retries: 1)
24
23
  # Skip loading the latest subscription details from the API if we already have it
25
- object ||= ::Stripe::Subscription.retrieve(id: subscription_id, expand: ["pending_setup_intent", "latest_invoice.payment_intent"])
24
+ object ||= ::Stripe::Subscription.retrieve({id: subscription_id, expand: ["pending_setup_intent", "latest_invoice.payment_intent", "latest_invoice.charge.invoice"]}, {stripe_account: stripe_account}.compact)
26
25
 
27
- owner = Pay.find_billable(processor: :stripe, processor_id: object.customer)
28
- return unless owner
26
+ pay_customer = Pay::Customer.find_by(processor: :stripe, processor_id: object.customer)
27
+ return unless pay_customer
29
28
 
30
29
  attributes = {
31
30
  application_fee_percent: object.application_fee_percent,
32
31
  processor_plan: object.plan.id,
33
32
  quantity: object.quantity,
34
- name: name,
35
33
  status: object.status,
36
- stripe_account: owner.stripe_account,
37
- trial_ends_at: (object.trial_end ? Time.at(object.trial_end) : nil)
34
+ stripe_account: pay_customer.stripe_account,
35
+ trial_ends_at: (object.trial_end ? Time.at(object.trial_end) : nil),
36
+ metadata: object.metadata
38
37
  }
39
38
 
40
- # Subscriptions cancelling in the future
41
- attributes[:ends_at] = Time.at(object.current_period_end) if object.cancel_at_period_end
42
-
43
- # Fully cancelled subscription
44
- attributes[:ends_at] = Time.at(object.ended_at) if object.ended_at
39
+ attributes[:ends_at] = if object.ended_at
40
+ # Fully cancelled subscription
41
+ Time.at(object.ended_at)
42
+ elsif object.cancel_at
43
+ # subscription cancelling in the future
44
+ Time.at(object.cancel_at)
45
+ elsif object.cancel_at_period_end
46
+ # Subscriptions cancelling in the future
47
+ Time.at(object.current_period_end)
48
+ end
45
49
 
46
50
  # Update or create the subscription
47
- pay_subscription = owner.subscriptions.find_or_initialize_by(processor: :stripe, processor_id: object.id)
48
- pay_subscription.update(attributes)
51
+ pay_subscription = pay_customer.subscriptions.find_by(processor_id: object.id)
52
+ if pay_subscription
53
+ pay_subscription.with_lock { pay_subscription.update!(attributes) }
54
+ else
55
+ pay_subscription = pay_customer.subscriptions.create!(attributes.merge(name: name, processor_id: object.id))
56
+ end
57
+
58
+ # Sync the latest charge if we already have it loaded (like during subscrbe), otherwise, let webhooks take care of creating it
59
+ if (charge = object.try(:latest_invoice).try(:charge)) && charge.try(:status) == "succeeded"
60
+ Pay::Stripe::Charge.sync(charge.id, object: charge)
61
+ end
62
+
49
63
  pay_subscription
64
+ rescue ActiveRecord::RecordInvalid
65
+ try += 1
66
+ if try <= retries
67
+ sleep 0.1
68
+ retry
69
+ else
70
+ raise
71
+ end
50
72
  end
51
73
 
52
74
  def initialize(pay_subscription)
@@ -54,31 +76,33 @@ module Pay
54
76
  end
55
77
 
56
78
  def subscription(**options)
57
- ::Stripe::Subscription.retrieve(options.merge(id: processor_id))
79
+ options[:id] = processor_id
80
+ options[:expand] ||= ["pending_setup_intent", "latest_invoice.payment_intent", "latest_invoice.charge.invoice"]
81
+ ::Stripe::Subscription.retrieve(options, {stripe_account: stripe_account}.compact)
58
82
  end
59
83
 
60
84
  def cancel
61
- stripe_sub = ::Stripe::Subscription.update(processor_id, {cancel_at_period_end: true}, {stripe_account: stripe_account})
85
+ stripe_sub = ::Stripe::Subscription.update(processor_id, {cancel_at_period_end: true}, stripe_options)
62
86
  pay_subscription.update(ends_at: (on_trial? ? trial_ends_at : Time.at(stripe_sub.current_period_end)))
63
87
  rescue ::Stripe::StripeError => e
64
88
  raise Pay::Stripe::Error, e
65
89
  end
66
90
 
67
91
  def cancel_now!
68
- ::Stripe::Subscription.delete(processor_id, {stripe_account: stripe_account})
92
+ ::Stripe::Subscription.delete(processor_id, {}, stripe_options)
69
93
  pay_subscription.update(ends_at: Time.current, status: :canceled)
70
94
  rescue ::Stripe::StripeError => e
71
95
  raise Pay::Stripe::Error, e
72
96
  end
73
97
 
74
98
  def change_quantity(quantity)
75
- ::Stripe::Subscription.update(processor_id, quantity: quantity)
99
+ ::Stripe::Subscription.update(processor_id, {quantity: quantity}, stripe_options)
76
100
  rescue ::Stripe::StripeError => e
77
101
  raise Pay::Stripe::Error, e
78
102
  end
79
103
 
80
104
  def on_grace_period?
81
- canceled? && Time.zone.now < ends_at
105
+ canceled? && Time.current < ends_at
82
106
  end
83
107
 
84
108
  def paused?
@@ -101,13 +125,15 @@ module Pay
101
125
  trial_end: (on_trial? ? trial_ends_at.to_i : "now"),
102
126
  cancel_at_period_end: false
103
127
  },
104
- {stripe_account: stripe_account}
128
+ stripe_options
105
129
  )
106
130
  rescue ::Stripe::StripeError => e
107
131
  raise Pay::Stripe::Error, e
108
132
  end
109
133
 
110
134
  def swap(plan)
135
+ raise ArgumentError, "plan must be a string" unless plan.is_a?(String)
136
+
111
137
  ::Stripe::Subscription.update(
112
138
  processor_id,
113
139
  {
@@ -117,11 +143,18 @@ module Pay
117
143
  trial_end: (on_trial? ? trial_ends_at.to_i : "now"),
118
144
  quantity: quantity
119
145
  },
120
- {stripe_account: stripe_account}
146
+ stripe_options
121
147
  )
122
148
  rescue ::Stripe::StripeError => e
123
149
  raise Pay::Stripe::Error, e
124
150
  end
151
+
152
+ private
153
+
154
+ # Options for Stripe requests
155
+ def stripe_options
156
+ {stripe_account: stripe_account}.compact
157
+ end
125
158
  end
126
159
  end
127
160
  end
@@ -5,9 +5,8 @@ module Pay
5
5
  def call(event)
6
6
  object = event.data.object
7
7
 
8
- merchant = Pay.find_merchant("stripe_connect_account_id", object.id)
9
-
10
- return unless merchant.present?
8
+ merchant = Pay::Merchant.find_by(processor: :stripe, processor_id: object.id)
9
+ return unless merchant
11
10
 
12
11
  merchant.update(onboarding_complete: object.charges_enabled)
13
12
  end
@@ -3,7 +3,7 @@ module Pay
3
3
  module Webhooks
4
4
  class ChargeRefunded
5
5
  def call(event)
6
- pay_charge = Pay::Stripe::Charge.sync(event.data.object.id)
6
+ pay_charge = Pay::Stripe::Charge.sync(event.data.object.id, stripe_account: event.try(:account))
7
7
  notify_user(pay_charge.owner, pay_charge) if pay_charge
8
8
  end
9
9
 
@@ -3,8 +3,8 @@ module Pay
3
3
  module Webhooks
4
4
  class ChargeSucceeded
5
5
  def call(event)
6
- pay_charge = Pay::Stripe::Charge.sync(event.data.object.id)
7
- notify_user(pay_charge.owner, pay_charge) if pay_charge
6
+ pay_charge = Pay::Stripe::Charge.sync(event.data.object.id, stripe_account: event.try(:account))
7
+ notify_user(pay_charge.customer.owner, pay_charge) if pay_charge
8
8
  end
9
9
 
10
10
  def notify_user(billable, charge)
@@ -3,8 +3,10 @@ module Pay
3
3
  module Webhooks
4
4
  class CheckoutSessionAsyncPaymentSucceeded
5
5
  def call(event)
6
+ # TODO: Also handle payment intents
7
+
6
8
  if event.data.object.subscription
7
- Pay::Stripe::Subscription.sync(event.data.object.subscription)
9
+ Pay::Stripe::Subscription.sync(event.data.object.subscription, stripe_account: event.try(:account))
8
10
  end
9
11
  end
10
12
  end
@@ -3,8 +3,10 @@ module Pay
3
3
  module Webhooks
4
4
  class CheckoutSessionCompleted
5
5
  def call(event)
6
+ # TODO: Also handle payment intents
7
+
6
8
  if event.data.object.subscription
7
- Pay::Stripe::Subscription.sync(event.data.object.subscription)
9
+ Pay::Stripe::Subscription.sync(event.data.object.subscription, stripe_account: event.try(:account))
8
10
  end
9
11
  end
10
12
  end
@@ -4,24 +4,16 @@ module Pay
4
4
  class CustomerDeleted
5
5
  def call(event)
6
6
  object = event.data.object
7
- billable = Pay.find_billable(processor: :stripe, processor_id: object.id)
7
+ pay_customer = Pay::Customer.find_by(processor: :stripe, processor_id: object.id)
8
8
 
9
- # Couldn't find user, we can skip
10
- return unless billable.present?
9
+ # Mark all subscriptions as canceled
10
+ pay_customer.subscriptions.active.update_all(ends_at: Time.current, status: "canceled")
11
11
 
12
- billable.update(
13
- processor_id: nil,
14
- trial_ends_at: nil,
15
- card_type: nil,
16
- card_last4: nil,
17
- card_exp_month: nil,
18
- card_exp_year: nil
19
- )
12
+ # Remove all payment methods
13
+ pay_customer.payment_methods.destroy_all
20
14
 
21
- billable.subscriptions.update_all(
22
- trial_ends_at: nil,
23
- ends_at: Time.zone.now
24
- )
15
+ # Mark customer as deleted
16
+ pay_customer&.update!(default: false, deleted_at: Time.current)
25
17
  end
26
18
  end
27
19
  end