Files
openfoodnetwork/lib/stripe/credit_card_cloner.rb
2020-12-10 12:17:42 -08:00

72 lines
2.7 KiB
Ruby

# frozen_string_literal: true
# Here we clone (or find a clone of)
# - a card (card_*) or payment_method (pm_*) stored (in a customer) in a platform account into
# - a payment method (pm_*) (in a new customer) in a connected account
#
# This is required when using the Stripe Payment Intents API:
# - the customer and payment methods are stored in the platform account
# so that they can be re-used across multiple sellers
# - when a card needs to be charged, we need to clone (or find the clone)
# in the seller's stripe account
#
# To avoid creating a new clone of the card/customer each time the card is charged or
# authorized (e.g. for SCA), we attach metadata { clone: true } to the card the first time we
# clone it and look for a card with the same fingerprint (hash of the card number) and
# that metadata key to avoid cloning it multiple times.
require 'stripe/credit_card_clone_finder'
module Stripe
class CreditCardCloner
def initialize(card, stripe_account)
@card = card
@stripe_account = stripe_account
end
def find_or_clone
cloned_card = Stripe::CreditCardCloneFinder.new(@card, @stripe_account).find_cloned_card
cloned_card || clone
end
private
def clone
new_payment_method = clone_payment_method
# If no customer is given, it will clone the payment method only
return [nil, new_payment_method.id] if @card.gateway_customer_profile_id.blank?
new_customer = Stripe::Customer.create({ email: @card.user.email },
stripe_account: @stripe_account)
attach_payment_method_to_customer(new_payment_method.id,
new_customer.id)
add_metadata_to_payment_method(new_payment_method.id)
[new_customer.id, new_payment_method.id]
end
def clone_payment_method
platform_acct_payment_method_id = @card.gateway_payment_profile_id
customer_id = @card.gateway_customer_profile_id
Stripe::PaymentMethod.create({ customer: customer_id,
payment_method: platform_acct_payment_method_id },
stripe_account: @stripe_account)
end
def attach_payment_method_to_customer(payment_method_id, customer_id)
Stripe::PaymentMethod.attach(payment_method_id,
{ customer: customer_id },
stripe_account: @stripe_account)
end
def add_metadata_to_payment_method(payment_method_id)
Stripe::PaymentMethod.update(payment_method_id,
{ metadata: { "ofn-clone": true } },
stripe_account: @stripe_account)
end
end
end