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

Sync Solidus Users and Stripe Customers #82

Open
wants to merge 1 commit into
base: v4
Choose a base branch
from

Conversation

brchristian
Copy link
Contributor

Solves #26.
Begins the solution of #74.

NOTE: This PR is an alternative (IMO a cleaner and superior one) to both #77 and #81.

The idea is that the gateway_customer_id really represents a mapping between Spree::Users and Stripe::Customers. As Stripe puts it: "You should create a Customer object when your customer creates an account with your business." This achieves that goal, with Spree::Users and Stripe::Customer now linked.

This allows us to create a very clean implementation of preserving the Stripe::Customer across multiple Solidus purchases (with both the same and different cards), across V2, Elements, and Intents. I believe it is an even better and more principled/elegant solution to #26 than either #77 and #81.

This also begins the process of shifting the solidus_stripe extension from its dependency on ActiveMerchant onto the official Stripe gem, which when complete will be I think a terrific simplification as well as giving us greater power and flexibility in how Solidus stores can take the fullest advantage of Stripe.


class AddStripeCustomerIdToUsers < SolidusSupport::Migration[5.1]
def up
add_column :spree_users, :stripe_customer_id, :string, unique: true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a concern regarding this migration. On custom authentications, the table may not be :spree_users (or Spree::User model). This migration would need to find the correct user class through Spree.user_class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I changed :spree_users to Spree.user_class.table_name.to_sym.

add_column :spree_users, :stripe_customer_id, :string, unique: true

Spree::User.includes(bill_address: :country, ship_address: :country).find_each do |u|
user_stripe_payment_sources = user&.wallet&.wallet_payment_sources&.select do |wps|
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think user here is meant to be u or probably the other way around, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, thank you! I changed it to u.

Copy link

@igorbp igorbp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @brchristian. This looks like a good start toward supporting the official stripe gem :)

I've added a few comments regarding the migration.

@brchristian
Copy link
Contributor Author

brchristian commented Oct 14, 2020

Thanks @igorbp! I appreciate the careful look. I've made both of those suggested changes and have force-pushed this PR.

Copy link

@igorbp igorbp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @brchristian. Thanks for considering my comments last time. :)

I made a few more suggestions that you might want to take a look at. I would be glad to hear your opinion about it.


def self.prepended(base)
base.after_create :create_stripe_customer
base.after_update :update_stripe_customer
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could create/update the stripe_customer only during a payment done through stripe. Also, with those callbacks, every change in the 'User' will trigger an update for the stripe_customer which in some cases won't be necessary.

# frozen_string_literal: true

module Spree
module UserDecorator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about having a dedicated class to deal with the StripeCustomer management(creation, update, delete, etc)? I don't think the User class should have knowledge about the Stripe integration, even through a decorator.


def create_stripe_customer
stripe_customer = Stripe::Customer.create(self.stripe_params)
update_column(:stripe_customer_id, stripe_customer.id)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for using update_column instead of the normal update? I don't think we should skip validations and callbacks here.

@@ -0,0 +1 @@
Stripe.api_key = Spree::PaymentMethod::StripeCreditCard.last&.preferences&.dig(:secret_key)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Stripe secret_key can also be defined in the database, which means it could be changed in the runtime. In that case, this would still have the old key. It would be better to define this during the runtime. This is also a good indication that we might need a class to handle the integration.

def up
add_column Spree.user_class.table_name.to_sym, :stripe_customer_id, :string, unique: true

Spree::User.includes(bill_address: :country, ship_address: :country).find_each do |u|
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part could be in a different migration. I believe with the custom user class situation, some users would want to deal with it themselves, and would be easier to skip a migration instead of comment this one.

@stale
Copy link

stale bot commented Nov 11, 2022

This issue has been automatically marked as stale because it has not had recent activity. It might be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Nov 11, 2022
@gsmendoza gsmendoza removed the stale label Nov 11, 2022
@elia elia added the v4.x Issues and PRs targeting the classic frontend (before v5) label Nov 29, 2022
@elia elia changed the base branch from master to v4 December 20, 2022 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v4.x Issues and PRs targeting the classic frontend (before v5)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants