diff --git a/app/controllers/solidus_stripe/intents_controller.rb b/app/controllers/solidus_stripe/intents_controller.rb index a98173f1..5398e588 100644 --- a/app/controllers/solidus_stripe/intents_controller.rb +++ b/app/controllers/solidus_stripe/intents_controller.rb @@ -50,16 +50,14 @@ def generate_payment_response end def create_payment_intent + intent_options = SolidusStripe::PrepareOptionsForIntentService.call( + current_order, + stripe + ) stripe.create_intent( (current_order.total * 100).to_i, params[:stripe_payment_method_id], - description: "Solidus Order ID: #{current_order.number} (pending)", - currency: current_order.currency, - confirmation_method: 'automatic', - capture_method: 'manual', - confirm: true, - setup_future_usage: 'off_session', - metadata: { order_id: current_order.id } + intent_options ) end end diff --git a/app/models/solidus_stripe/prepare_options_for_intent_service.rb b/app/models/solidus_stripe/prepare_options_for_intent_service.rb new file mode 100644 index 00000000..48c46ff6 --- /dev/null +++ b/app/models/solidus_stripe/prepare_options_for_intent_service.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module SolidusStripe + class PrepareOptionsForIntentService + attr_reader :order, :payment_method + + def self.call(...) + new(...).call + end + + def initialize(order, payment_method) + @order = order + @payment_method = payment_method + end + + def call + options = { + description: "Solidus Order ID: #{order.number} (pending)", + currency: order.currency, + confirmation_method: 'automatic', + capture_method: 'manual', + confirm: true, + setup_future_usage: 'off_session', + metadata: { order_id: order.id }, + } + options.merge!(connect_options) if payment_method.preferred_stripe_connect + options + end + + private + + def connect_options + return unless payment_method.preferred_stripe_connect + + opts = { + application_fee_amount: SolidusStripe.configuration.application_fee + } + + case payment_method.preferred_connected_mode + when 'direct_charge' + opts.merge!(stripe_account: connected_account) + when 'destination_charge' + opts.merge!(transfer_data: { destination: connected_account }) + end + opts + end + + def connected_account + payment_method.preferred_connected_account + end + end +end diff --git a/app/models/spree/payment_method/stripe_credit_card.rb b/app/models/spree/payment_method/stripe_credit_card.rb index fb707580..004f524c 100644 --- a/app/models/spree/payment_method/stripe_credit_card.rb +++ b/app/models/spree/payment_method/stripe_credit_card.rb @@ -8,6 +8,9 @@ class StripeCreditCard < Spree::PaymentMethod::CreditCard preference :stripe_country, :string preference :v3_elements, :boolean preference :v3_intents, :boolean + preference :stripe_connect, :boolean + preference :connected_mode, :string, default: 'direct_charge' + preference :connected_account, :string CARD_TYPE_MAPPING = { 'American Express' => 'american_express', diff --git a/lib/solidus_stripe/configuration.rb b/lib/solidus_stripe/configuration.rb index 0c6eb54f..8e5af620 100644 --- a/lib/solidus_stripe/configuration.rb +++ b/lib/solidus_stripe/configuration.rb @@ -5,6 +5,7 @@ class Configuration # Define here the settings for this extensions, e.g.: # # attr_accessor :my_setting + attr_accessor :application_fee end class << self diff --git a/spec/models/solidus_stripe/prepare_options_for_intent_service_spec.rb b/spec/models/solidus_stripe/prepare_options_for_intent_service_spec.rb new file mode 100644 index 00000000..632d9db2 --- /dev/null +++ b/spec/models/solidus_stripe/prepare_options_for_intent_service_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe SolidusStripe::PrepareOptionsForIntentService do + let(:order) { create(:order_with_line_items) } + let(:payment_method) { + Spree::PaymentMethod::StripeCreditCard.create( + name: 'Stripe', + preferred_secret_key: 'secret', + preferred_publishable_key: 'published', + preferred_stripe_connect: stripe_connect, + preferred_connected_account: 'connect_account', + preferred_connected_mode: connected_mode + ) + } + let(:connected_mode) { 'direct_charge' } + let(:service) { described_class.new(order, payment_method) } + let(:intent_options) { service.call } + + context 'without stripe connect' do + let(:stripe_connect) { false } + + it 'dont has any connect attributes' do + expect(intent_options[:application_fee]).to be_nil + end + end + + context 'with stripe connect' do + let(:stripe_connect) { true } + + before do + SolidusStripe.configure do |app| + app.application_fee = 5 + end + end + + it 'has application_fee option' do + expect(intent_options[:application_fee_amount]).to eq(5) + end + + it 'has stripe_account option' do + expect(intent_options[:stripe_account]).to eq('connect_account') + end + + context 'with destination_charge mode' do + let(:connected_mode) { 'destination_charge' } + + it 'has transfer_destionation option' do + expect(intent_options[:transfer_data][:destination]).to eq('connect_account') + end + + it 'doesnt have stripe_account option' do + expect(intent_options[:stripe_account]).to be_nil + end + end + end +end