Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stripe customer creation is performed without processor reconciliation for existing Stripe customers #831

Closed
btonic opened this issue Jul 12, 2023 · 9 comments

Comments

@btonic
Copy link
Contributor

btonic commented Jul 12, 2023

I was working on a project in a development environment when I ran into an interesting situation where duplicate Stripe customers are created if the Rails application using pay-rails is not aware of existing Stripe customers already stored by Stripe with the same customer attributes (e.g. email).

I encountered this by creating subscriptions and charges for a User within the project I'm developing, then resetting the project's Rails database, thus clearing all references to the Stripe processor values, and re-starting the application with the clean database. Attempting to create more subscriptions and charges on the same Stripe customer (e.g. Rails User with same email address) creates a new Stripe customer with the same email associated, resulting in a duplicate customer within Stripe.

I don't think that this is technically a bug, as I could see it being the Rails app's responsibility to reconcile this situation (such as calling update_customer with the appropriate processor_id), as no duplicates would occur if the application is aware of all created Stripe customers (which would be typical and expected for a production environment). However, I think if this is intended functionality, it might require more prominent documentation, and potentially a configuration option for processor customer reconciliation to make things "just work" in an opinionated way.

Reproduction

Assuming the following User definition:

class User < ApplicationRecord
  pay_customer default_payment_processor :stripe
end

When a User is created, the payment_processor holds null values related to the customer object:

#<Pay::Customer:0x0000562180830ed0
 id: 1,
 owner_type: "User",
 owner_id: 2,
 processor: "stripe",
 processor_id: nil,
 default: true,
 data: nil,
 deleted_at: nil,
 created_at: Tue, 11 Jul 2023 20:34:08.985920000 UTC +00:00,
 updated_at: Tue, 11 Jul 2023 20:34:08.985920000 UTC +00:00,
 plan: nil,
 quantity: nil,
 payment_method_token: nil>

Attempting to sync subscriptions using cur_user.payment_processor.sync_subscriptions results in the creation of a new Stripe customer, and the Stripe customer id is stored as the processor_id. The creation of the Stripe customer is done without attempting to identify if a Stripe customer already exists (within Stripe, not the Rails application) with the same email or other customer attributes, and as a result, two Stripe customers with the same attributes exist.

@excid3
Copy link
Collaborator

excid3 commented Jul 12, 2023

This is expected.

If you want to only have a single Stripe::Customer for an email address, you can use Stripe's API to lookup the customer ID and assign it to the Pay::Customer.

@btonic
Copy link
Contributor Author

btonic commented Jul 12, 2023

Sweet, thank you for the guidance @excid3 ! Is this potentially something we would want to document for the processor? If so, I can open a PR for a first draft real quickly. :)

@excid3
Copy link
Collaborator

excid3 commented Jul 12, 2023

That would be great!

I believe Paddle returns a new Customer for each new subscription, so it doesn't work quite like Stripe. So it probably makes sense to just document this situation and maybe in the future we could do a helper method or something for just Stripe & Braintree or whatever.

@btonic
Copy link
Contributor Author

btonic commented Jul 12, 2023

Perfect, sounds good. I'll get that PR in shortly!

@excid3
Copy link
Collaborator

excid3 commented Jul 12, 2023

Awesome, thank you!

@btonic
Copy link
Contributor Author

btonic commented Jul 12, 2023

I'm working on a section for backfilling Subscriptions and Charges for a reconciled Pay::Customer, and from perusing the source for Pay, I only found a sync_subscriptions. The sync_subscriptions properly backfills subscriptions and charges associated to those subscriptions, but I do not see an equivalent method for backfilling charges related to standard payments (e.g. single charges not associated with a subscription).

Is there a method that exists for backfilling charges not associated with a subscription?

@excid3
Copy link
Collaborator

excid3 commented Jul 12, 2023

I don't believe we've added one yet.

You can do it with something like Stripe::Charge.list.auto_paging_each { |charge| Pay::Stripe::Charge.sync(charge.id) }

@btonic
Copy link
Contributor Author

btonic commented Jul 12, 2023

Perfect, I'm going to note that in the documentation I'm working on, then file an issue to create a method for it. It would likely be a good beginner contribution to Pay! :)

@btonic
Copy link
Contributor Author

btonic commented Jul 13, 2023

Draft PR has been opened in #832 . I'll be marking this for review later today most likely!

@excid3 excid3 closed this as completed Jul 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants