# frozen_string_literal: true module SolidusStripe class CreateIntentsPaymentService attr_reader :intent_id, :stripe, :controller delegate :request, :current_order, :params, to: :controller def initialize(intent_id, stripe, controller) @intent_id, @stripe, @controller = intent_id, stripe, controller end def call invalidate_previous_payment_intents_payments if (payment = create_payment) description = "Solidus Order ID: #{payment.gateway_order_identifier}" stripe.update_intent(nil, intent_id, nil, description: description) true else invalidate_current_payment_intent false end end private def intent @intent ||= stripe.show_intent(intent_id, {}) end def invalidate_current_payment_intent stripe.cancel(intent_id) end def invalidate_previous_payment_intents_payments if stripe.v3_intents? current_order.payments.pending.where(payment_method: stripe).each(&:void_transaction!) end end def create_payment Spree::OrderUpdateAttributes.new( current_order, payment_params, request_env: request.headers.env ).apply created_payment = Spree::Payment.find_by(response_code: intent_id) created_payment&.tap { |payment| payment.update!(state: :pending) } end def payment_params { payments_attributes: [{ payment_method_id: stripe.id, amount: current_order.total, response_code: intent_id, source_attributes: { month: intent_card['exp_month'], year: intent_card['exp_year'], cc_type: intent_card['brand'], last_digits: intent_card['last4'], gateway_payment_profile_id: intent_customer_profile, name: card_holder_name || address_full_name, address_attributes: address_attributes } }] } end def intent_card intent_data['payment_method_details']['card'] end def intent_customer_profile intent.params['payment_method'] end def card_holder_name (html_payment_source_data['name'] || intent_data['billing_details']['name']).presence end def intent_data intent.params['charges']['data'][0] end def form_data params[:form_data] end def html_payment_source_data if form_data.is_a?(String) data = Rack::Utils.parse_nested_query(form_data) data['payment_source'][stripe.id.to_s] else {} end end def address_attributes html_payment_source_data['address_attributes'] || SolidusStripe::AddressFromParamsService.new(form_data).call.attributes end def address_full_name current_order.bill_address&.full_name || form_data[:recipient] end def update_stripe_payment_description description = "Solidus Order ID: #{payment.gateway_order_identifier}" stripe.update_intent(nil, intent_id, nil, description: description) end end end