Skip to content

Commit

Permalink
Skip sync if object.customer is blank. Fixes #842 (#845)
Browse files Browse the repository at this point in the history
* Skip sync if object.customer is blank. Fixes #842

* Add tests for nil customer syncing
  • Loading branch information
excid3 committed Sep 5, 2023
1 parent 07a37fa commit eb4f1c5
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

### Unreleased

* [Stripe] Skip sync if object is not attached to a customer. Fixes #842

### 6.8.0

* Update to Stripe `2023-08-16` API version
Expand Down
12 changes: 8 additions & 4 deletions lib/pay/stripe/charge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ class Charge
def self.sync(charge_id, object: nil, stripe_account: nil, try: 0, retries: 1)
# Skip loading the latest charge details from the API if we already have it
object ||= ::Stripe::Charge.retrieve({id: charge_id, expand: ["invoice.total_discount_amounts.discount", "invoice.total_tax_amounts.tax_rate", "refunds"]}, {stripe_account: stripe_account}.compact)

# Ignore charges without a Customer
return if object.customer.blank?
if object.customer.blank?
Rails.logger.debug "Stripe Charge #{object.id} does not have a customer"
return
end

pay_customer = Pay::Customer.find_by(processor: :stripe, processor_id: object.customer)
return unless pay_customer
if pay_customer.blank?
Rails.logger.debug "Pay::Customer #{object.customer} is not in the database while syncing Stripe Charge #{object.id}"
return
end

refunds = []
object.refunds.auto_paging_each { |refund| refunds << refund }
Expand Down
9 changes: 8 additions & 1 deletion lib/pay/stripe/payment_method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,16 @@ def self.sync_setup_intent(id, stripe_account: nil)
# Syncs PaymentMethod objects from Stripe
def self.sync(id, object: nil, stripe_account: nil, try: 0, retries: 1)
object ||= ::Stripe::PaymentMethod.retrieve(id, {stripe_account: stripe_account}.compact)
if object.customer.blank?
Rails.logger.debug "Stripe PaymentMethod #{object.id} does not have a customer"
return
end

pay_customer = Pay::Customer.find_by(processor: :stripe, processor_id: object.customer)
return unless pay_customer
if pay_customer.blank?
Rails.logger.debug "Pay::Customer #{object.customer} is not in the database while syncing Stripe PaymentMethod #{object.id}"
return
end

default_payment_method_id = pay_customer.customer.invoice_settings.default_payment_method
default = (id == default_payment_method_id)
Expand Down
9 changes: 8 additions & 1 deletion lib/pay/stripe/subscription.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,16 @@ class Subscription
def self.sync(subscription_id, object: nil, name: nil, stripe_account: nil, try: 0, retries: 1)
# Skip loading the latest subscription details from the API if we already have it
object ||= ::Stripe::Subscription.retrieve({id: subscription_id}.merge(expand_options), {stripe_account: stripe_account}.compact)
if object.customer.blank?
Rails.logger.debug "Stripe Subscription #{object.id} does not have a customer"
return
end

pay_customer = Pay::Customer.find_by(processor: :stripe, processor_id: object.customer)
return unless pay_customer
if pay_customer.blank?
Rails.logger.debug "Pay::Customer #{object.customer} is not in the database while syncing Stripe Subscription #{object.id}"
return
end

attributes = {
application_fee_percent: object.application_fee_percent,
Expand Down
6 changes: 6 additions & 0 deletions test/pay/stripe/charge_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ class Pay::Stripe::ChargeTest < ActiveSupport::TestCase
end
end

test "stripe sync skips charge without customer" do
@pay_customer.update!(processor_id: nil)
pay_charge = Pay::Stripe::Charge.sync("123", object: fake_stripe_charge(customer: nil))
assert_nil pay_charge
end

test "sync stripe charge ignores when customer is nil" do
assert_no_difference "Pay::Charge.count" do
Pay::Stripe::Charge.sync("123", object: fake_stripe_charge(customer: nil))
Expand Down
81 changes: 81 additions & 0 deletions test/pay/stripe/payment_method_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
require "test_helper"

class Pay::Stripe::PaymentMethodTest < ActiveSupport::TestCase
setup do
@pay_customer = pay_customers(:stripe)
end

test "Stripe sync returns Pay::PaymentMethod" do
::Stripe::Customer.stubs(:retrieve).returns(::Stripe::Customer.construct_from(invoice_settings: {default_payment_method: nil}))
pay_payment_method = Pay::Stripe::PaymentMethod.sync("pm_123", object: fake_stripe_payment_method)
assert pay_payment_method.is_a?(Pay::PaymentMethod)
refute pay_payment_method.default?
end

test "Stripe sync sets default if payment method is default in invoice settings" do
::Stripe::Customer.stubs(:retrieve).returns(::Stripe::Customer.construct_from(invoice_settings: {default_payment_method: "pm_123"}))
pay_payment_method = Pay::Stripe::PaymentMethod.sync("pm_123", object: fake_stripe_payment_method)
assert pay_payment_method.default?
end

test "Stripe sync skips PaymentMethod without customer" do
@pay_customer.update!(processor_id: nil)
pay_payment_method = Pay::Stripe::PaymentMethod.sync("pm_123", object: fake_stripe_payment_method(customer: nil))
assert_nil pay_payment_method
end

private

def fake_stripe_payment_method(**values)
values.reverse_merge!(
id: "pm_123",
object: "payment_method",
billing_details: {
address: {
city: nil,
country: nil,
line1: nil,
line2: nil,
postal_code: "42424",
state: nil
},
email: "jenny@example.com",
name: nil,
phone: "+15555555555"
},
card: {
brand: "visa",
checks: {
address_line1_check: nil,
address_postal_code_check: nil,
cvc_check: "pass"
},
country: "US",
exp_month: 8,
exp_year: 2024,
fingerprint: "eLihtj2HTMlWeL7e",
funding: "credit",
generated_from: nil,
last4: "4242",
networks: {
available: [
"visa"
],
preferred: nil
},
three_d_secure_usage: {
supported: true
},
wallet: nil
},
created: 123456789,
customer: "cus_1234",
livemode: false,
metadata: {
order_id: "123456789"
},
type: "card"
)
::Stripe::PaymentMethod.construct_from(values)
end
end
6 changes: 6 additions & 0 deletions test/pay/stripe/subscription_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ class Pay::Stripe::SubscriptionTest < ActiveSupport::TestCase
@pay_customer = pay_customers(:stripe)
end

test "stripe sync skips subscription without customer" do
@pay_customer.update!(processor_id: nil)
pay_subscription = Pay::Stripe::Subscription.sync("123", object: fake_stripe_subscription(customer: nil, status: "past_due"))
assert_nil pay_subscription
end

test "stripe past_due is not active" do
pay_subscription = Pay::Stripe::Subscription.sync("123", object: fake_stripe_subscription(status: "past_due"))
refute pay_subscription.active?
Expand Down

0 comments on commit eb4f1c5

Please sign in to comment.