mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-11 18:26:50 +00:00
Revert "Kill stripe connect"
This commit is contained in:
@@ -203,6 +203,7 @@ Layout/LineLength:
|
||||
- spec/models/spree/address_spec.rb
|
||||
- spec/models/spree/adjustment_spec.rb
|
||||
- spec/models/spree/classification_spec.rb
|
||||
- spec/models/spree/gateway/stripe_connect_spec.rb
|
||||
- spec/models/spree/inventory_unit_spec.rb
|
||||
- spec/models/spree/line_item_spec.rb
|
||||
- spec/models/spree/order/checkout_spec.rb
|
||||
|
||||
@@ -622,6 +622,7 @@ Style/NumericPredicate:
|
||||
- 'app/helpers/shared_helper.rb'
|
||||
- 'app/models/product_import/product_importer.rb'
|
||||
- 'app/models/product_import/spreadsheet_entry.rb'
|
||||
- 'app/models/spree/gateway/stripe_connect.rb'
|
||||
- 'app/models/spree/line_item.rb'
|
||||
- 'app/models/spree/order.rb'
|
||||
- 'app/models/spree/order_contents.rb'
|
||||
@@ -697,6 +698,7 @@ Style/Send:
|
||||
- 'spec/models/calculator/weight_spec.rb'
|
||||
- 'spec/models/enterprise_spec.rb'
|
||||
- 'spec/models/exchange_spec.rb'
|
||||
- 'spec/models/spree/gateway/stripe_connect_spec.rb'
|
||||
- 'spec/models/spree/order_inventory_spec.rb'
|
||||
- 'spec/models/spree/order_spec.rb'
|
||||
- 'spec/models/spree/payment_spec.rb'
|
||||
|
||||
@@ -16,7 +16,7 @@ angular.module("admin.subscriptions").controller "DetailsController", ($scope, $
|
||||
return if !newValue?
|
||||
paymentMethod = ($scope.paymentMethods.filter (pm) -> pm.id == newValue)[0]
|
||||
return unless paymentMethod?
|
||||
$scope.cardRequired = (paymentMethod.type == "Spree::Gateway::StripeSCA")
|
||||
$scope.cardRequired = (paymentMethod.type == "Spree::Gateway::StripeConnect" || paymentMethod.type == "Spree::Gateway::StripeSCA")
|
||||
$scope.loadCustomer() if $scope.cardRequired && !$scope.customer
|
||||
|
||||
$scope.loadCustomer = ->
|
||||
|
||||
@@ -145,11 +145,12 @@ module Spree
|
||||
end
|
||||
|
||||
def stripe_payment_method?
|
||||
["Spree::Gateway::StripeSCA"].include? @payment_method.try(:type)
|
||||
["Spree::Gateway::StripeConnect",
|
||||
"Spree::Gateway::StripeSCA"].include? @payment_method.try(:type)
|
||||
end
|
||||
|
||||
def stripe_provider?(provider)
|
||||
provider.name.ends_with?("StripeSCA")
|
||||
provider.name.ends_with?("StripeConnect", "StripeSCA")
|
||||
end
|
||||
|
||||
def base_params
|
||||
|
||||
109
app/models/spree/gateway/stripe_connect.rb
Normal file
109
app/models/spree/gateway/stripe_connect.rb
Normal file
@@ -0,0 +1,109 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'stripe/profile_storer'
|
||||
|
||||
module Spree
|
||||
class Gateway
|
||||
class StripeConnect < Gateway
|
||||
preference :enterprise_id, :integer
|
||||
|
||||
validate :ensure_enterprise_selected
|
||||
|
||||
def method_type
|
||||
'stripe'
|
||||
end
|
||||
|
||||
def provider_class
|
||||
ActiveMerchant::Billing::StripeGateway
|
||||
end
|
||||
|
||||
def payment_profiles_supported?
|
||||
true
|
||||
end
|
||||
|
||||
def stripe_account_id
|
||||
StripeAccount.find_by(enterprise_id: preferred_enterprise_id)&.stripe_user_id
|
||||
end
|
||||
|
||||
# NOTE: the name of this method is determined by Spree::Payment::Processing
|
||||
def purchase(money, creditcard, gateway_options)
|
||||
provider.purchase(*options_for_purchase_or_auth(money, creditcard, gateway_options))
|
||||
rescue Stripe::StripeError => e
|
||||
# This will be an error caused by generating a stripe token
|
||||
failed_activemerchant_billing_response(e.message)
|
||||
end
|
||||
|
||||
def charge_offline(money, creditcard, gateway_options)
|
||||
purchase(money, creditcard, gateway_options)
|
||||
end
|
||||
|
||||
# NOTE: the name of this method is determined by Spree::Payment::Processing
|
||||
def void(response_code, _creditcard, gateway_options)
|
||||
gateway_options[:stripe_account] = stripe_account_id
|
||||
provider.void(response_code, gateway_options)
|
||||
end
|
||||
|
||||
# NOTE: the name of this method is determined by Spree::Payment::Processing
|
||||
def credit(money, _creditcard, response_code, gateway_options)
|
||||
gateway_options[:stripe_account] = stripe_account_id
|
||||
provider.refund(money, response_code, gateway_options)
|
||||
end
|
||||
|
||||
def create_profile(payment)
|
||||
return unless payment.source.gateway_customer_profile_id.nil?
|
||||
|
||||
profile_storer = Stripe::ProfileStorer.new(payment, provider)
|
||||
profile_storer.create_customer_from_token
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# In this gateway, what we call 'secret_key' is the 'login'
|
||||
def options
|
||||
options = super
|
||||
options.merge(login: Stripe.api_key)
|
||||
end
|
||||
|
||||
def options_for_purchase_or_auth(money, creditcard, gateway_options)
|
||||
options = {}
|
||||
options[:description] = "Spree Order ID: #{gateway_options[:order_id]}"
|
||||
options[:currency] = gateway_options[:currency]
|
||||
options[:stripe_account] = stripe_account_id
|
||||
|
||||
creditcard = token_from_card_profile_ids(creditcard)
|
||||
|
||||
[money, creditcard, options]
|
||||
end
|
||||
|
||||
def token_from_card_profile_ids(creditcard)
|
||||
token_or_card_id = creditcard.gateway_payment_profile_id
|
||||
customer = creditcard.gateway_customer_profile_id
|
||||
|
||||
return nil if token_or_card_id.blank?
|
||||
|
||||
# Assume the gateway_payment_profile_id is a token generated by StripeJS
|
||||
return token_or_card_id if customer.blank?
|
||||
|
||||
# Assume the gateway_payment_profile_id is a Stripe card_id
|
||||
# So generate a new token, using the customer_id and card_id
|
||||
tokenize_instance_customer_card(customer, token_or_card_id)
|
||||
end
|
||||
|
||||
def tokenize_instance_customer_card(customer, card)
|
||||
token = Stripe::Token.create({ card: card, customer: customer },
|
||||
stripe_account: stripe_account_id)
|
||||
token.id
|
||||
end
|
||||
|
||||
def failed_activemerchant_billing_response(error_message)
|
||||
ActiveMerchant::Billing::Response.new(false, error_message)
|
||||
end
|
||||
|
||||
def ensure_enterprise_selected
|
||||
return if preferred_enterprise_id&.positive?
|
||||
|
||||
errors.add(:stripe_account_owner, I18n.t(:error_required))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
class Subscription < ApplicationRecord
|
||||
ALLOWED_PAYMENT_METHOD_TYPES = ["Spree::PaymentMethod::Check",
|
||||
"Spree::Gateway::StripeConnect",
|
||||
"Spree::Gateway::StripeSCA"].freeze
|
||||
|
||||
searchable_attributes :shop_id, :canceled_at, :paused_at
|
||||
|
||||
@@ -6,7 +6,8 @@ module Api
|
||||
delegate :serializable_hash, to: :method_serializer
|
||||
|
||||
def method_serializer
|
||||
if object.type == 'Spree::Gateway::StripeSCA'
|
||||
if object.type == 'Spree::Gateway::StripeConnect' ||
|
||||
object.type == 'Spree::Gateway::StripeSCA'
|
||||
Api::Admin::PaymentMethod::StripeSerializer.new(object)
|
||||
else
|
||||
Api::Admin::PaymentMethod::BaseSerializer.new(object)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
- case @payment_method
|
||||
- when Spree::Gateway::StripeConnect
|
||||
= render 'stripe_connect'
|
||||
- when Spree::Gateway::StripeSCA
|
||||
= render 'stripe_connect'
|
||||
- else
|
||||
|
||||
@@ -136,6 +136,7 @@ module Openfoodnetwork
|
||||
|
||||
# Register Spree payment methods
|
||||
initializer "spree.gateway.payment_methods", :after => "spree.register.payment_methods" do |app|
|
||||
app.config.spree.payment_methods << Spree::Gateway::StripeConnect
|
||||
app.config.spree.payment_methods << Spree::Gateway::StripeSCA
|
||||
app.config.spree.payment_methods << Spree::Gateway::PayPalExpress
|
||||
end
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
class RenameStripeConnectPaymentMethodsToStripeSca < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
execute "UPDATE spree_payment_methods SET type = 'Spree::Gateway::StripeSCA' WHERE type = 'Spree::Gateway::StripeConnect'"
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2021_08_17_100257) do
|
||||
ActiveRecord::Schema.define(version: 2021_06_17_203927) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
@@ -28,7 +28,8 @@ module OrderManagement
|
||||
end
|
||||
|
||||
def stripe_payment_method?
|
||||
[Spree::Gateway::StripeSCA].include? @payment.payment_method.class
|
||||
[Spree::Gateway::StripeConnect,
|
||||
Spree::Gateway::StripeSCA].include? @payment.payment_method.class
|
||||
end
|
||||
|
||||
def card_set?
|
||||
|
||||
@@ -93,6 +93,7 @@ module OrderManagement
|
||||
end
|
||||
|
||||
def stripe_payment_method?(payment_method)
|
||||
payment_method.type == "Spree::Gateway::StripeConnect" ||
|
||||
payment_method.type == "Spree::Gateway::StripeSCA"
|
||||
end
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ module OrderManagement
|
||||
end
|
||||
|
||||
context "when the payment method is a stripe payment method" do
|
||||
let(:payment_method) { create(:stripe_sca_payment_method) }
|
||||
let(:payment_method) { create(:stripe_connect_payment_method) }
|
||||
|
||||
context "and the card is already set (the payment source is a credit card)" do
|
||||
it "returns the pending payment with no change" do
|
||||
|
||||
@@ -360,9 +360,9 @@ module OrderManagement
|
||||
end
|
||||
end
|
||||
|
||||
context "when using the StripeSCA payment gateway" do
|
||||
context "when using the StripeConnect payment gateway" do
|
||||
let(:payment_method) {
|
||||
instance_double(Spree::PaymentMethod, type: "Spree::Gateway::StripeSCA")
|
||||
instance_double(Spree::PaymentMethod, type: "Spree::Gateway::StripeConnect")
|
||||
}
|
||||
before { expect(subscription).to receive(:customer).at_least(:once) { customer } }
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"spec/controllers/line_items_controller_spec.rb": 9.073998928070068,
|
||||
"spec/lib/open_food_network/address_finder_spec.rb": 8.379472494125366,
|
||||
"spec/features/admin/enterprises/index_spec.rb": 4.946447134017944,
|
||||
"spec/requests/checkout/stripe_connect_spec.rb": 7.5777587890625,
|
||||
"spec/models/spree/adjustment_spec.rb": 7.560959815979004,
|
||||
"spec/serializers/api/product_serializer_spec.rb": 8.135705709457397,
|
||||
"spec/lib/open_food_network/permissions_spec.rb": 3.799001455307007,
|
||||
@@ -232,6 +233,7 @@
|
||||
"spec/lib/tasks/enterprises_rake_spec.rb": 0.0833287239074707,
|
||||
"spec/controllers/api/taxonomies_controller_spec.rb": 0.08802604675292969,
|
||||
"spec/helpers/spree/admin/orders_helper_spec.rb": 0.0646059513092041,
|
||||
"spec/models/spree/gateway/stripe_connect_spec.rb": 0.05724668502807617,
|
||||
"spec/helpers/shop_helper_spec.rb": 0.3690376281738281,
|
||||
"spec/jobs/welcome_enterprise_job_spec.rb": 0.08383440971374512,
|
||||
"spec/jobs/confirm_order_job_spec.rb": 0.06512808799743652,
|
||||
|
||||
@@ -5,12 +5,12 @@ module OpenFoodNetwork
|
||||
def filter!(payment_methods)
|
||||
if stripe_enabled?
|
||||
payment_methods.to_a.reject! do |payment_method|
|
||||
payment_method.type.ends_with?("StripeSCA") &&
|
||||
payment_method.type.ends_with?("StripeConnect") &&
|
||||
stripe_configuration_incomplete?(payment_method)
|
||||
end
|
||||
else
|
||||
payment_methods.to_a.reject! do |payment_method|
|
||||
payment_method.type.ends_with?("StripeSCA")
|
||||
payment_method.type.ends_with?("StripeConnect")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -753,7 +753,7 @@ describe Admin::SubscriptionsController, type: :controller do
|
||||
end
|
||||
|
||||
context "when other payment methods exist" do
|
||||
let!(:stripe) { create(:stripe_sca_payment_method, distributors: [shop]) }
|
||||
let!(:stripe) { create(:stripe_connect_payment_method, distributors: [shop]) }
|
||||
let!(:paypal) {
|
||||
Spree::Gateway::PayPalExpress.create!(name: "PayPalExpress", distributor_ids: [shop.id])
|
||||
}
|
||||
|
||||
@@ -16,6 +16,126 @@ describe Spree::Admin::PaymentsController, type: :controller do
|
||||
order.reload.update_totals
|
||||
end
|
||||
|
||||
context "Stripe Connect" do
|
||||
context "requesting a refund on a payment" do
|
||||
let(:params) { { id: payment.id, order_id: order.number, e: :void } }
|
||||
|
||||
# Required for the respond override in the controller decorator to work
|
||||
before { @request.env['HTTP_REFERER'] = spree.admin_order_payments_url(payment) }
|
||||
|
||||
context "that was processed by stripe" do
|
||||
let!(:payment_method) { create(:stripe_connect_payment_method, distributors: [shop]) }
|
||||
let!(:payment) do
|
||||
create(:payment, order: order, state: 'completed', payment_method: payment_method,
|
||||
response_code: 'ch_1a2b3c', amount: order.total)
|
||||
end
|
||||
|
||||
before do
|
||||
Stripe.api_key = "sk_test_12345"
|
||||
end
|
||||
|
||||
context "where the request succeeds" do
|
||||
before do
|
||||
stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds").
|
||||
with(basic_auth: ["sk_test_12345", ""]).
|
||||
to_return(status: 200,
|
||||
body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') )
|
||||
end
|
||||
|
||||
it "voids the payment" do
|
||||
order.reload
|
||||
expect(order.payment_total).to_not eq 0
|
||||
expect(order.outstanding_balance.to_f).to eq 0
|
||||
spree_put :fire, params
|
||||
expect(payment.reload.state).to eq 'void'
|
||||
order.reload
|
||||
expect(order.payment_total).to eq 0
|
||||
expect(order.outstanding_balance.to_f).to_not eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context "where the request fails" do
|
||||
before do
|
||||
stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds").
|
||||
with(basic_auth: ["sk_test_12345", ""]).
|
||||
to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) )
|
||||
end
|
||||
|
||||
it "does not void the payment" do
|
||||
order.reload
|
||||
expect(order.payment_total).to_not eq 0
|
||||
expect(order.outstanding_balance.to_f).to eq 0
|
||||
spree_put :fire, params
|
||||
expect(payment.reload.state).to eq 'completed'
|
||||
order.reload
|
||||
expect(order.payment_total).to_not eq 0
|
||||
expect(order.outstanding_balance.to_f).to eq 0
|
||||
expect(flash[:error]).to eq "Bup-bow!"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "requesting a partial credit on a payment" do
|
||||
let(:params) { { id: payment.id, order_id: order.number, e: :credit } }
|
||||
|
||||
# Required for the respond override in the controller decorator to work
|
||||
before { @request.env['HTTP_REFERER'] = spree.admin_order_payments_url(payment) }
|
||||
|
||||
context "that was processed by stripe" do
|
||||
let!(:payment_method) { create(:stripe_connect_payment_method, distributors: [shop]) }
|
||||
let!(:payment) do
|
||||
create(:payment, order: order, state: 'completed', payment_method: payment_method,
|
||||
response_code: 'ch_1a2b3c', amount: order.total + 5)
|
||||
end
|
||||
|
||||
before do
|
||||
Stripe.api_key = "sk_test_12345"
|
||||
end
|
||||
|
||||
context "where the request succeeds" do
|
||||
before do
|
||||
stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds").
|
||||
with(basic_auth: ["sk_test_12345", ""]).
|
||||
to_return(status: 200,
|
||||
body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') )
|
||||
end
|
||||
|
||||
it "partially refunds the payment" do
|
||||
order.reload
|
||||
expect(order.payment_total).to eq order.total + 5
|
||||
expect(order.outstanding_balance.to_f).to eq(-5)
|
||||
spree_put :fire, params
|
||||
expect(payment.reload.state).to eq 'completed'
|
||||
order.reload
|
||||
expect(order.payment_total).to eq order.total
|
||||
expect(order.outstanding_balance.to_f).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context "where the request fails" do
|
||||
before do
|
||||
stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds").
|
||||
with(basic_auth: ["sk_test_12345", ""]).
|
||||
to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) )
|
||||
end
|
||||
|
||||
it "does not void the payment" do
|
||||
order.reload
|
||||
expect(order.payment_total).to eq order.total + 5
|
||||
expect(order.outstanding_balance.to_f).to eq(-5)
|
||||
spree_put :fire, params
|
||||
expect(payment.reload.state).to eq 'completed'
|
||||
order.reload
|
||||
expect(order.payment_total).to eq order.total + 5
|
||||
expect(order.outstanding_balance.to_f).to eq(-5)
|
||||
expect(flash[:error]).to eq "Bup-bow!"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "StripeSCA" do
|
||||
context "voiding a payment" do
|
||||
let(:params) { { id: payment.id, order_id: order.number, e: :void } }
|
||||
|
||||
@@ -45,11 +45,10 @@ describe Spree::Admin::PaymentsController, type: :controller do
|
||||
end
|
||||
|
||||
context "with Stripe payment where payment.process! errors out" do
|
||||
let!(:payment_method) { create(:stripe_connect_payment_method, distributors: [shop]) }
|
||||
before do
|
||||
allow_any_instance_of(Spree::Payment).to receive(:authorize!) do |payment|
|
||||
payment.update state: "pending"
|
||||
end
|
||||
allow_any_instance_of(Spree::Payment).to receive(:process_offline!).
|
||||
allow_any_instance_of(Spree::Payment).
|
||||
to receive(:process_offline!).
|
||||
and_raise(Spree::Core::GatewayError.new("Payment Gateway Error"))
|
||||
end
|
||||
|
||||
|
||||
@@ -108,12 +108,12 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
context "on a StripeSCA payment method" do
|
||||
context "on a StripeConnect payment method" do
|
||||
let!(:user) { create(:user, enterprise_limit: 2) }
|
||||
let!(:enterprise1) { create(:distributor_enterprise, owner: user) }
|
||||
let!(:enterprise2) { create(:distributor_enterprise, owner: create(:user)) }
|
||||
let!(:payment_method) {
|
||||
create(:stripe_sca_payment_method, distributor_ids: [enterprise1.id, enterprise2.id],
|
||||
create(:stripe_connect_payment_method, distributor_ids: [enterprise1.id, enterprise2.id],
|
||||
preferred_enterprise_id: enterprise2.id)
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ module Spree
|
||||
{
|
||||
id: payment_method.id,
|
||||
payment_method: {
|
||||
type: "Spree::Gateway::StripeSCA",
|
||||
type: "Spree::Gateway::StripeConnect",
|
||||
preferred_enterprise_id: enterprise1.id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,13 @@ FactoryBot.define do
|
||||
environment { 'test' }
|
||||
end
|
||||
|
||||
factory :stripe_connect_payment_method, class: Spree::Gateway::StripeConnect do
|
||||
name { 'StripeConnect' }
|
||||
environment { 'test' }
|
||||
distributors { [FactoryBot.create(:enterprise)] }
|
||||
preferred_enterprise_id { distributors.first.id }
|
||||
end
|
||||
|
||||
factory :stripe_sca_payment_method, class: Spree::Gateway::StripeSCA do
|
||||
name { 'StripeSCA' }
|
||||
environment { 'test' }
|
||||
|
||||
@@ -220,7 +220,7 @@ feature 'Subscriptions' do
|
||||
}
|
||||
let!(:schedule) { create(:schedule, order_cycles: [order_cycle]) }
|
||||
let!(:payment_method) {
|
||||
create(:stripe_sca_payment_method, name: 'Credit Card', distributors: [shop])
|
||||
create(:stripe_connect_payment_method, name: 'Credit Card', distributors: [shop])
|
||||
}
|
||||
let!(:shipping_method) { create(:shipping_method, distributors: [shop]) }
|
||||
|
||||
@@ -387,7 +387,7 @@ feature 'Subscriptions' do
|
||||
}
|
||||
let!(:payment_method) { create(:payment_method, distributors: [shop]) }
|
||||
let!(:stripe_payment_method) {
|
||||
create(:stripe_sca_payment_method, name: 'Credit Card', distributors: [shop])
|
||||
create(:stripe_connect_payment_method, name: 'Credit Card', distributors: [shop])
|
||||
}
|
||||
let!(:shipping_method) { create(:shipping_method, distributors: [shop]) }
|
||||
let!(:subscription) {
|
||||
@@ -536,7 +536,7 @@ feature 'Subscriptions' do
|
||||
let!(:enterprise_fee) { create(:enterprise_fee, amount: 1.75) }
|
||||
let!(:order_cycle) { create(:simple_order_cycle, coordinator: shop) }
|
||||
let!(:schedule) { create(:schedule, order_cycles: [order_cycle]) }
|
||||
let!(:payment_method) { create(:stripe_sca_payment_method, distributors: [shop]) }
|
||||
let!(:payment_method) { create(:stripe_connect_payment_method, distributors: [shop]) }
|
||||
let!(:shipping_method) { create(:shipping_method, distributors: [shop]) }
|
||||
|
||||
before do
|
||||
|
||||
@@ -37,6 +37,65 @@ feature "Check out with Stripe", js: true do
|
||||
distributor.shipping_methods << [shipping_with_fee, free_shipping]
|
||||
end
|
||||
|
||||
context 'login in as user' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
login_as(user)
|
||||
end
|
||||
|
||||
context "with Stripe Connect" do
|
||||
let!(:stripe_pm) do
|
||||
create(:stripe_connect_payment_method, distributors: [distributor])
|
||||
end
|
||||
|
||||
let!(:saved_card) do
|
||||
create(:credit_card,
|
||||
user_id: user.id,
|
||||
month: "01",
|
||||
year: "2025",
|
||||
cc_type: "visa",
|
||||
number: "1111111111111111",
|
||||
payment_method_id: stripe_pm.id,
|
||||
gateway_customer_profile_id: "i_am_saved")
|
||||
end
|
||||
|
||||
let!(:stripe_account) {
|
||||
create(:stripe_account, enterprise_id: distributor.id, stripe_user_id: 'some_id')
|
||||
}
|
||||
|
||||
let(:response_mock) { { id: "ch_1234", object: "charge", amount: 2000 } }
|
||||
|
||||
around do |example|
|
||||
original_stripe_connect_enabled = Spree::Config[:stripe_connect_enabled]
|
||||
example.run
|
||||
Spree::Config.set(stripe_connect_enabled: original_stripe_connect_enabled)
|
||||
end
|
||||
|
||||
before do
|
||||
stub_request(:post, "https://api.stripe.com/v1/charges")
|
||||
.with(basic_auth: ["sk_test_12345", ""])
|
||||
.to_return(status: 200, body: JSON.generate(response_mock))
|
||||
|
||||
visit checkout_path
|
||||
fill_out_form(shipping_with_fee.name, stripe_pm.name, save_default_addresses: false)
|
||||
end
|
||||
|
||||
it "allows use of a saved card" do
|
||||
# shows the saved credit card dropdown
|
||||
expect(page).to have_content I18n.t("spree.checkout.payment.stripe.used_saved_card")
|
||||
|
||||
# default card is selected, form element is not shown
|
||||
expect(page).to have_no_selector "#card-element.StripeElement"
|
||||
expect(page).to have_select 'selected_card', selected: "Visa x-1111 Exp:01/2025"
|
||||
|
||||
# allows checkout
|
||||
place_order
|
||||
expect(page).to have_content "Your order has been processed successfully"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "using Stripe SCA" do
|
||||
let!(:stripe_account) { create(:stripe_account, enterprise: distributor) }
|
||||
let!(:stripe_sca_payment_method) {
|
||||
|
||||
@@ -262,13 +262,13 @@ describe EnterprisesHelper, type: :helper do
|
||||
end
|
||||
end
|
||||
|
||||
context "when Stripe payment methods are present" do
|
||||
context "when StripeConnect payment methods are present" do
|
||||
let!(:pm3) {
|
||||
create(:stripe_sca_payment_method, distributors: [distributor],
|
||||
create(:stripe_connect_payment_method, distributors: [distributor],
|
||||
preferred_enterprise_id: distributor.id)
|
||||
}
|
||||
let!(:pm4) {
|
||||
create(:stripe_sca_payment_method, distributors: [distributor],
|
||||
create(:stripe_connect_payment_method, distributors: [distributor],
|
||||
preferred_enterprise_id: some_other_distributor.id)
|
||||
}
|
||||
let(:available_payment_methods) { helper.available_payment_methods }
|
||||
|
||||
@@ -191,26 +191,20 @@ describe SubscriptionConfirmJob do
|
||||
end
|
||||
end
|
||||
|
||||
context "Stripe SCA" do
|
||||
let(:stripe_sca_payment_method) { create(:stripe_sca_payment_method) }
|
||||
let(:stripe_sca_payment) {
|
||||
create(:payment, amount: 10, payment_method: stripe_sca_payment_method)
|
||||
context "Stripe Connect" do
|
||||
let(:stripe_connect_payment_method) { create(:stripe_connect_payment_method) }
|
||||
let(:stripe_connect_payment) {
|
||||
create(:payment, amount: 10, payment_method: stripe_connect_payment_method)
|
||||
}
|
||||
let(:provider) { double }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Stripe::CreditCardCloner).to receive(:find_or_clone) {
|
||||
["cus_123", "pm_1234"]
|
||||
}
|
||||
allow(order).to receive(:pending_payments) { [stripe_sca_payment] }
|
||||
allow(stripe_sca_payment_method).to receive(:provider) { provider }
|
||||
allow(stripe_sca_payment_method.provider).to receive(:purchase) { true }
|
||||
allow(stripe_sca_payment_method.provider).to receive(:capture) { true }
|
||||
allow(order).to receive(:pending_payments) { [stripe_connect_payment] }
|
||||
allow(stripe_connect_payment_method).to receive(:purchase) { true }
|
||||
end
|
||||
|
||||
it "runs the charges in offline mode" do
|
||||
job.send(:confirm_order!, order)
|
||||
expect(stripe_sca_payment_method.provider).to have_received(:purchase)
|
||||
expect(stripe_connect_payment_method).to have_received(:purchase)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,28 +4,24 @@ require 'spec_helper'
|
||||
|
||||
module Stripe
|
||||
describe ProfileStorer do
|
||||
include StripeStubs
|
||||
|
||||
describe "create_customer_from_token" do
|
||||
let(:stripe_payment_method) { create(:stripe_sca_payment_method) }
|
||||
let(:card) { create(:credit_card, gateway_payment_profile_id: card_id) }
|
||||
let(:payment) { create(:payment, source: card, payment_method: stripe_payment_method) }
|
||||
let(:payment) { create(:payment) }
|
||||
let(:stripe_payment_method) { create(:stripe_connect_payment_method) }
|
||||
let(:profile_storer) { Stripe::ProfileStorer.new(payment, stripe_payment_method.provider) }
|
||||
|
||||
let(:customer_id) { "cus_A123" }
|
||||
let(:card_id) { "card_2342" }
|
||||
let(:customer_response_mock) {
|
||||
{ status: 200, body: JSON.generate(id: customer_id, sources: { data: [{ id: "1" }] }) }
|
||||
}
|
||||
let(:customer_response_mock) { { status: 200, body: customer_response_body } }
|
||||
|
||||
before do
|
||||
Stripe.api_key = "sk_test_12345"
|
||||
|
||||
stub_customers_post_request(email: payment.order.email, response: customer_response_mock)
|
||||
stub_payment_method_attach_request(payment_method: card_id, customer: customer_id)
|
||||
stub_request(:post, "https://api.stripe.com/v1/customers")
|
||||
.with(basic_auth: ["sk_test_12345", ""], body: { email: payment.order.email })
|
||||
.to_return(customer_response_mock)
|
||||
end
|
||||
|
||||
context "when called from Stripe SCA" do
|
||||
context "when called from Stripe Connect" do
|
||||
let(:customer_response_body) {
|
||||
JSON.generate(id: customer_id, default_card: card_id, sources: { data: [{ id: "1" }] })
|
||||
}
|
||||
@@ -39,6 +35,10 @@ module Stripe
|
||||
end
|
||||
|
||||
context "when called from Stripe SCA" do
|
||||
let(:customer_response_body) {
|
||||
JSON.generate(customer: customer_id, id: card_id, sources: { data: [{ id: "1" }] })
|
||||
}
|
||||
|
||||
it "fetches the customer id and the card id from the correct response fields" do
|
||||
profile_storer.create_customer_from_token
|
||||
|
||||
|
||||
107
spec/models/spree/gateway/stripe_connect_spec.rb
Normal file
107
spec/models/spree/gateway/stripe_connect_spec.rb
Normal file
@@ -0,0 +1,107 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Gateway::StripeConnect, type: :model do
|
||||
let(:provider) do
|
||||
instance_double(ActiveMerchant::Billing::StripeGateway).tap do |p|
|
||||
allow(p).to receive(:purchase)
|
||||
allow(p).to receive(:authorize)
|
||||
allow(p).to receive(:capture)
|
||||
allow(p).to receive(:refund)
|
||||
end
|
||||
end
|
||||
|
||||
let(:stripe_account_id) { "acct_123" }
|
||||
|
||||
before do
|
||||
Stripe.api_key = "sk_test_123456"
|
||||
allow(subject).to receive(:stripe_account_id) { stripe_account_id }
|
||||
allow(subject).to receive(:options_for_purchase_or_auth).and_return(['money', 'cc', 'opts'])
|
||||
allow(subject).to receive(:provider).and_return provider
|
||||
end
|
||||
|
||||
describe "#token_from_card_profile_ids" do
|
||||
let(:creditcard) { double(:creditcard) }
|
||||
context "when the credit card provided has a gateway_payment_profile_id" do
|
||||
before do
|
||||
allow(creditcard).to receive(:gateway_payment_profile_id) { "token_or_card_id123" }
|
||||
allow(subject).to receive(:tokenize_instance_customer_card) { "tokenized" }
|
||||
end
|
||||
|
||||
context "when the credit card provided has a gateway_customer_profile_id" do
|
||||
before { allow(creditcard).to receive(:gateway_customer_profile_id) { "customer_id123" } }
|
||||
|
||||
it "requests a new token via tokenize_instance_customer_card" do
|
||||
result = subject.send(:token_from_card_profile_ids, creditcard)
|
||||
expect(result).to eq "tokenized"
|
||||
end
|
||||
end
|
||||
|
||||
context "when the credit card provided does not have a gateway_customer_profile_id" do
|
||||
before { allow(creditcard).to receive(:gateway_customer_profile_id) { nil } }
|
||||
it "returns the gateway_payment_profile_id (assumed to be a token already)" do
|
||||
result = subject.send(:token_from_card_profile_ids, creditcard)
|
||||
expect(result).to eq "token_or_card_id123"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the credit card provided does not have a gateway_payment_profile_id" do
|
||||
before { allow(creditcard).to receive(:gateway_payment_profile_id) { nil } }
|
||||
before { allow(creditcard).to receive(:gateway_customer_profile_id) { "customer_id123" } }
|
||||
|
||||
it "returns nil....?" do
|
||||
result = subject.send(:token_from_card_profile_ids, creditcard)
|
||||
expect(result).to be nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#tokenize_instance_customer_card" do
|
||||
let(:customer_id) { "customer123" }
|
||||
let(:card_id) { "card123" }
|
||||
let(:token_mock) { { id: "test_token123" } }
|
||||
|
||||
before do
|
||||
stub_request(:post, "https://api.stripe.com/v1/tokens")
|
||||
.with(body: { "card" => "card123", "customer" => "customer123" })
|
||||
.to_return(body: JSON.generate(token_mock))
|
||||
end
|
||||
|
||||
it "requests a new token for the customer and card from Stripe, and returns the id of the response" do
|
||||
expect(subject.send(:tokenize_instance_customer_card, customer_id,
|
||||
card_id)).to eq token_mock[:id]
|
||||
end
|
||||
end
|
||||
|
||||
describe "#credit" do
|
||||
let(:gateway_options) { { some: 'option' } }
|
||||
let(:money) { double(:money) }
|
||||
let(:response_code) { double(:response_code) }
|
||||
|
||||
before do
|
||||
subject.credit(money, double(:creditcard), response_code, gateway_options)
|
||||
end
|
||||
|
||||
it "delegates to ActiveMerchant::Billing::StripeGateway#refund" do
|
||||
expect(provider).to have_received(:refund)
|
||||
end
|
||||
|
||||
it "adds the stripe_account to the gateway options hash" do
|
||||
expect(provider).to have_received(:refund).with(money, response_code,
|
||||
hash_including(stripe_account: stripe_account_id))
|
||||
end
|
||||
end
|
||||
|
||||
describe "#charging offline" do
|
||||
let(:gateway_options) { { some: 'option' } }
|
||||
let(:money) { double(:money) }
|
||||
let(:card) { double(:creditcard) }
|
||||
|
||||
it "uses #purchase to charge offline" do
|
||||
subject.charge_offline(money, card, gateway_options)
|
||||
expect(provider).to have_received(:purchase).with('money', 'cc', 'opts')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -45,9 +45,9 @@ module Spree
|
||||
it_behaves_like "taggable", "Spree::PaymentMethod"
|
||||
end
|
||||
|
||||
describe Gateway::StripeSCA do
|
||||
describe Gateway::StripeConnect do
|
||||
subject do
|
||||
# StripeSCA needs an owner to be valid.
|
||||
# StripeConnect needs an owner to be valid.
|
||||
valid_subject.tap { |m| m.preferred_enterprise_id = shop.id }
|
||||
end
|
||||
|
||||
|
||||
@@ -1213,7 +1213,7 @@ describe Spree::Order do
|
||||
let!(:enterprise) { create(:enterprise) }
|
||||
let!(:order) { create(:order, distributor: enterprise) }
|
||||
let!(:payment_method) {
|
||||
create(:stripe_sca_payment_method, distributor_ids: [enterprise.id])
|
||||
create(:stripe_connect_payment_method, distributor_ids: [enterprise.id])
|
||||
}
|
||||
let!(:payment) { create(:payment, order: order, payment_method: payment_method) }
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ module Spree
|
||||
it "generates a clean name for known Payment Method types" do
|
||||
expect(Spree::PaymentMethod::Check.clean_name).to eq(I18n.t("spree.admin.payment_methods.providers.check"))
|
||||
expect(Spree::Gateway::PayPalExpress.clean_name).to eq(I18n.t("spree.admin.payment_methods.providers.paypalexpress"))
|
||||
expect(Spree::Gateway::StripeConnect.clean_name).to eq(I18n.t("spree.admin.payment_methods.providers.stripeconnect"))
|
||||
expect(Spree::Gateway::StripeSCA.clean_name).to eq(I18n.t("spree.admin.payment_methods.providers.stripesca"))
|
||||
expect(Spree::Gateway::BogusSimple.clean_name).to eq(I18n.t("spree.admin.payment_methods.providers.bogussimple"))
|
||||
expect(Spree::Gateway::Bogus.clean_name).to eq(I18n.t("spree.admin.payment_methods.providers.bogus"))
|
||||
|
||||
@@ -904,7 +904,7 @@ describe Spree::Payment do
|
||||
context "to Stripe payments" do
|
||||
let(:shop) { create(:enterprise) }
|
||||
let(:payment_method) {
|
||||
create(:stripe_sca_payment_method, distributor_ids: [create(:distributor_enterprise).id],
|
||||
create(:stripe_connect_payment_method, distributor_ids: [create(:distributor_enterprise).id],
|
||||
preferred_enterprise_id: shop.id)
|
||||
}
|
||||
let(:payment) {
|
||||
|
||||
310
spec/requests/checkout/stripe_connect_spec.rb
Normal file
310
spec/requests/checkout/stripe_connect_spec.rb
Normal file
@@ -0,0 +1,310 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe "checking out an order with a Stripe Connect payment method", type: :request do
|
||||
include ShopWorkflow
|
||||
include AuthenticationHelper
|
||||
include OpenFoodNetwork::ApiHelper
|
||||
|
||||
let!(:order_cycle) { create(:simple_order_cycle) }
|
||||
let!(:enterprise) { create(:distributor_enterprise) }
|
||||
let!(:shipping_method) do
|
||||
create(
|
||||
:shipping_method,
|
||||
calculator: Calculator::FlatRate.new(preferred_amount: 0),
|
||||
distributors: [enterprise]
|
||||
)
|
||||
end
|
||||
let!(:payment_method) { create(:stripe_connect_payment_method, distributors: [enterprise]) }
|
||||
let!(:stripe_account) { create(:stripe_account, enterprise: enterprise) }
|
||||
let!(:line_item) { create(:line_item, price: 12.34) }
|
||||
let!(:order) { line_item.order }
|
||||
let(:address) { create(:address) }
|
||||
let(:token) { "token123" }
|
||||
let(:new_token) { "newtoken123" }
|
||||
let(:card_id) { "card_XyZ456" }
|
||||
let(:customer_id) { "cus_A123" }
|
||||
let(:payments_attributes) do
|
||||
{
|
||||
payment_method_id: payment_method.id,
|
||||
source_attributes: {
|
||||
gateway_payment_profile_id: token,
|
||||
cc_type: "visa",
|
||||
last_digits: "4242",
|
||||
month: 10,
|
||||
year: 2025,
|
||||
first_name: 'Jill',
|
||||
last_name: 'Jeffreys'
|
||||
}
|
||||
}
|
||||
end
|
||||
let(:allowed_address_attributes) do
|
||||
[
|
||||
"firstname",
|
||||
"lastname",
|
||||
"address1",
|
||||
"address2",
|
||||
"phone",
|
||||
"city",
|
||||
"zipcode",
|
||||
"state_id",
|
||||
"country_id"
|
||||
]
|
||||
end
|
||||
let(:params) do
|
||||
{
|
||||
format: :json, order: {
|
||||
shipping_method_id: shipping_method.id,
|
||||
payments_attributes: [payments_attributes],
|
||||
bill_address_attributes: address.attributes.slice(*allowed_address_attributes),
|
||||
ship_address_attributes: address.attributes.slice(*allowed_address_attributes)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
order_cycle_distributed_variants = double(:order_cycle_distributed_variants)
|
||||
allow(OrderCycleDistributedVariants).to receive(:new) { order_cycle_distributed_variants }
|
||||
allow(order_cycle_distributed_variants).to receive(:distributes_order_variants?) { true }
|
||||
|
||||
Stripe.api_key = "sk_test_12345"
|
||||
order.update(distributor_id: enterprise.id, order_cycle_id: order_cycle.id)
|
||||
order.reload.update_totals
|
||||
set_order order
|
||||
end
|
||||
|
||||
context "when a new card is submitted" do
|
||||
let(:store_response_mock) do
|
||||
{
|
||||
status: 200,
|
||||
body: JSON.generate(
|
||||
id: customer_id,
|
||||
default_card: card_id,
|
||||
sources: { data: [{ id: "1" }] }
|
||||
)
|
||||
}
|
||||
end
|
||||
let(:token_response_mock) do
|
||||
{ status: 200, body: JSON.generate(id: new_token) }
|
||||
end
|
||||
let(:charge_response_mock) do
|
||||
{ status: 200, body: JSON.generate(id: "ch_1234", object: "charge", amount: 2000) }
|
||||
end
|
||||
|
||||
context "and the user doesn't request that the card is saved for later" do
|
||||
before do
|
||||
# Charges the card
|
||||
stub_request(:post, "https://api.stripe.com/v1/charges")
|
||||
.with(basic_auth: ["sk_test_12345", ""], body: /#{token}.*#{order.number}/)
|
||||
.to_return(charge_response_mock)
|
||||
end
|
||||
|
||||
context "and the charge request is successful" do
|
||||
it "should process the payment without storing card details" do
|
||||
put update_checkout_path, params: params
|
||||
|
||||
expect(json_response["path"]).to eq order_path(order)
|
||||
expect(order.payments.completed.count).to be 1
|
||||
|
||||
card = order.payments.completed.first.source
|
||||
|
||||
expect(card.gateway_customer_profile_id).to eq nil
|
||||
expect(card.gateway_payment_profile_id).to eq token
|
||||
expect(card.cc_type).to eq "visa"
|
||||
expect(card.last_digits).to eq "4242"
|
||||
expect(card.first_name).to eq "Jill"
|
||||
expect(card.last_name).to eq "Jeffreys"
|
||||
end
|
||||
end
|
||||
|
||||
context "when the charge request returns an error message" do
|
||||
let(:charge_response_mock) do
|
||||
{ status: 402, body: JSON.generate(error: { message: "charge-failure" }) }
|
||||
end
|
||||
|
||||
it "should not process the payment" do
|
||||
put update_checkout_path, params: params
|
||||
|
||||
expect(response.status).to be 400
|
||||
|
||||
expect(json_response["flash"]["error"]).to eq "charge-failure"
|
||||
expect(order.payments.completed.count).to be 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "and the customer requests that the card is saved for later" do
|
||||
before do
|
||||
source_attributes = params[:order][:payments_attributes][0][:source_attributes]
|
||||
source_attributes[:save_requested_by_customer] = '1'
|
||||
|
||||
# Saves the card against the user
|
||||
stub_request(:post, "https://api.stripe.com/v1/customers")
|
||||
.with(basic_auth: ["sk_test_12345", ""], body: { card: token, email: order.email })
|
||||
.to_return(store_response_mock)
|
||||
|
||||
# Requests a token from the newly saved card
|
||||
stub_request(:post, "https://api.stripe.com/v1/tokens")
|
||||
.with(body: { card: card_id, customer: customer_id })
|
||||
.to_return(token_response_mock)
|
||||
|
||||
# Charges the card
|
||||
stub_request(:post, "https://api.stripe.com/v1/charges")
|
||||
.with(
|
||||
basic_auth: ["sk_test_12345", ""],
|
||||
body: /#{token}.*#{order.number}/
|
||||
).to_return(charge_response_mock)
|
||||
end
|
||||
|
||||
context "and the store, token and charge requests are successful" do
|
||||
it "should process the payment, and stores the card/customer details" do
|
||||
put update_checkout_path, params: params
|
||||
|
||||
expect(json_response["path"]).to eq order_path(order)
|
||||
expect(order.payments.completed.count).to be 1
|
||||
|
||||
card = order.payments.completed.first.source
|
||||
|
||||
expect(card.gateway_customer_profile_id).to eq customer_id
|
||||
expect(card.gateway_payment_profile_id).to eq card_id
|
||||
expect(card.cc_type).to eq "visa"
|
||||
expect(card.last_digits).to eq "4242"
|
||||
expect(card.first_name).to eq "Jill"
|
||||
expect(card.last_name).to eq "Jeffreys"
|
||||
end
|
||||
end
|
||||
|
||||
context "when the store request returns an error message" do
|
||||
let(:store_response_mock) do
|
||||
{ status: 402, body: JSON.generate(error: { message: "store-failure" }) }
|
||||
end
|
||||
|
||||
it "should not process the payment" do
|
||||
put update_checkout_path, params: params
|
||||
|
||||
expect(response.status).to be 400
|
||||
|
||||
expect(json_response["flash"]["error"])
|
||||
.to eq(I18n.t(:spree_gateway_error_flash_for_checkout, error: 'store-failure'))
|
||||
expect(order.payments.completed.count).to be 0
|
||||
end
|
||||
end
|
||||
|
||||
context "when the charge request returns an error message" do
|
||||
let(:charge_response_mock) do
|
||||
{ status: 402, body: JSON.generate(error: { message: "charge-failure" }) }
|
||||
end
|
||||
|
||||
it "should not process the payment" do
|
||||
put update_checkout_path, params: params
|
||||
|
||||
expect(response.status).to be 400
|
||||
|
||||
expect(json_response["flash"]["error"]).to eq "charge-failure"
|
||||
expect(order.payments.completed.count).to be 0
|
||||
end
|
||||
end
|
||||
|
||||
context "when the token request returns an error message" do
|
||||
let(:token_response_mock) do
|
||||
{ status: 402, body: JSON.generate(error: { message: "token-failure" }) }
|
||||
end
|
||||
|
||||
# Note, no requests have been stubbed
|
||||
it "should not process the payment" do
|
||||
put update_checkout_path, params: params
|
||||
|
||||
expect(response.status).to be 400
|
||||
|
||||
expect(json_response["flash"]["error"]).to eq "token-failure"
|
||||
expect(order.payments.completed.count).to be 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when an existing card is submitted" do
|
||||
let(:credit_card) do
|
||||
create(
|
||||
:credit_card,
|
||||
user_id: order.user_id,
|
||||
gateway_payment_profile_id: card_id,
|
||||
gateway_customer_profile_id: customer_id,
|
||||
last_digits: "4321",
|
||||
cc_type: "master",
|
||||
first_name: "Sammy",
|
||||
last_name: "Signpost",
|
||||
month: 11, year: 2026
|
||||
)
|
||||
end
|
||||
|
||||
let(:token_response_mock) { { status: 200, body: JSON.generate(id: new_token) } }
|
||||
let(:charge_response_mock) do
|
||||
{ status: 200, body: JSON.generate(id: "ch_1234", object: "charge", amount: 2000) }
|
||||
end
|
||||
|
||||
before do
|
||||
params[:order][:existing_card_id] = credit_card.id
|
||||
login_as(order.user)
|
||||
|
||||
# Requests a token
|
||||
stub_request(:post, "https://api.stripe.com/v1/tokens")
|
||||
.with(body: { "card" => card_id, "customer" => customer_id })
|
||||
.to_return(token_response_mock)
|
||||
|
||||
# Charges the card
|
||||
stub_request(:post, "https://api.stripe.com/v1/charges")
|
||||
.with(basic_auth: ["sk_test_12345", ""], body: /#{token}.*#{order.number}/)
|
||||
.to_return(charge_response_mock)
|
||||
end
|
||||
|
||||
context "and the charge and token requests are accepted" do
|
||||
it "should process the payment, and keep the profile ids and other card details" do
|
||||
put update_checkout_path, params: params
|
||||
|
||||
expect(json_response["path"]).to eq order_path(order)
|
||||
expect(order.payments.completed.count).to be 1
|
||||
|
||||
card = order.payments.completed.first.source
|
||||
|
||||
expect(card.gateway_customer_profile_id).to eq customer_id
|
||||
expect(card.gateway_payment_profile_id).to eq card_id
|
||||
expect(card.cc_type).to eq "master"
|
||||
expect(card.last_digits).to eq "4321"
|
||||
expect(card.first_name).to eq "Sammy"
|
||||
expect(card.last_name).to eq "Signpost"
|
||||
end
|
||||
end
|
||||
|
||||
context "when the charge request returns an error message" do
|
||||
let(:charge_response_mock) do
|
||||
{ status: 402, body: JSON.generate(error: { message: "charge-failure" }) }
|
||||
end
|
||||
|
||||
it "should not process the payment" do
|
||||
put update_checkout_path, params: params
|
||||
|
||||
expect(response.status).to be 400
|
||||
|
||||
expect(json_response["flash"]["error"]).to eq "charge-failure"
|
||||
expect(order.payments.completed.count).to be 0
|
||||
end
|
||||
end
|
||||
|
||||
context "when the token request returns an error message" do
|
||||
let(:token_response_mock) do
|
||||
{ status: 402, body: JSON.generate(error: { message: "token-error" }) }
|
||||
end
|
||||
|
||||
it "should not process the payment" do
|
||||
put update_checkout_path, params: params
|
||||
|
||||
expect(response.status).to be 400
|
||||
|
||||
expect(json_response["flash"]["error"]).to eq "token-error"
|
||||
expect(order.payments.completed.count).to be 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -28,11 +28,11 @@ module StripeStubs
|
||||
end
|
||||
|
||||
# Attaches the payment method to the customer in the hub's stripe account
|
||||
def stub_payment_method_attach_request(payment_method: "pm_123", customer: "cus_A123")
|
||||
def stub_payment_method_attach_request
|
||||
stub_request(:post,
|
||||
"https://api.stripe.com/v1/payment_methods/#{payment_method}/attach")
|
||||
.with(body: { customer: customer })
|
||||
.to_return(hub_payment_method_response_mock({ pm_id: payment_method }))
|
||||
"https://api.stripe.com/v1/payment_methods/pm_123/attach")
|
||||
.with(body: { customer: "cus_A123" })
|
||||
.to_return(hub_payment_method_response_mock({ pm_id: "pm_123" }))
|
||||
end
|
||||
|
||||
def stub_retrieve_payment_method_request(payment_method_id = "pm_1234")
|
||||
|
||||
Reference in New Issue
Block a user