module Effective module Providers module Stripe extend ActiveSupport::Concern def stripe_charge @order ||= Effective::Order.find(stripe_charge_params[:effective_order_id]) @stripe_charge = Effective::Providers::StripeCharge.new(stripe_charge_params) @stripe_charge.order = @order EffectiveOrders.authorized?(self, :update, @order) if @stripe_charge.valid? && (response = process_stripe_charge(@stripe_charge)) != false order_purchased( details: response, provider: (EffectiveOrders.stripe_connect_enabled ? 'stripe_connect' : 'stripe'), card: (response['charge']['card']['brand'] rescue nil) ) else @page_title = 'Checkout' flash.now[:danger] = @stripe_charge.errors.full_messages.to_sentence render :checkout_step2 end end private def process_stripe_charge(charge) Effective::Order.transaction do begin @buyer = Customer.for_user(charge.order.user) @buyer.update_card!(charge.token) if EffectiveOrders.stripe_connect_enabled return charge_with_stripe_connect(charge, @buyer) else return charge_with_stripe(charge, @buyer) end rescue => e charge.errors.add(:base, "Unable to process order with Stripe. Your credit card has not been charged. Message: \"#{e.message}\".") raise ActiveRecord::Rollback end end false end def charge_with_stripe(charge, buyer) results = {subscriptions: {}, charge: nil} # Process subscriptions. charge.subscriptions.each do |subscription| next if subscription.stripe_plan_id.blank? stripe_subscription = if subscription.stripe_coupon_id.present? buyer.stripe_customer.subscriptions.create({plan: subscription.stripe_plan_id, coupon: subscription.stripe_coupon_id}) else buyer.stripe_customer.subscriptions.create({plan: subscription.stripe_plan.id}) end subscription.stripe_subscription_id = stripe_subscription.id subscription.save! results[:subscriptions][subscription.stripe_plan_id] = JSON.parse(stripe_subscription.to_json) end # Process regular order_items. amount = charge.order_items.map { |oi| oi.total }.sum # A positive integer in cents representing how much to charge the card. The minimum amount is 50 cents. description = "Charge for Order ##{charge.order.to_param}" if amount > 0 results[:charge] = JSON.parse(::Stripe::Charge.create( amount: amount, currency: EffectiveOrders.stripe[:currency], customer: buyer.stripe_customer.id, description: description ).to_json) end results end def charge_with_stripe_connect(charge, buyer) # Go through and create Stripe::Tokens for each seller items = charge.order_items.group_by(&:seller) results = {} # We do all these Tokens first, so if one throws an exception no charges are made items.each do |seller, _| seller.token = ::Stripe::Token.create({customer: buyer.stripe_customer.id}, seller.stripe_connect_access_token) end # Make one charge per seller, for all his order_items items.each do |seller, order_items| amount = order_items.map { |oi| oi.total }.sum description = "Charge for Order ##{charge.order.to_param} with OrderItems ##{order_items.map(&:id).join(', #')}" application_fee = order_items.sum(&:stripe_connect_application_fee) results[seller.id] = JSON.parse(::Stripe::Charge.create( { amount: amount, currency: EffectiveOrders.stripe[:currency], card: seller.token.id, description: description, application_fee: application_fee }, seller.stripe_connect_access_token ).to_json) end results end # StrongParameters def stripe_charge_params begin params.require(:effective_providers_stripe_charge).permit(:token, :effective_order_id) rescue => e params[:effective_providers_stripe_charge] end end end end end