mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-20 04:59:16 +00:00
Merge pull request #13961 from mkllnk/taler-checkout-stock-error
Taler checkout stock error
This commit is contained in:
@@ -13,6 +13,9 @@ CAPYBARA_MAX_WAIT_TIME="10"
|
||||
# successful fallback to `en`.
|
||||
LOCALE="en_TST"
|
||||
|
||||
# For multilingual - ENV doesn't have array so pass it as string with commas
|
||||
AVAILABLE_LOCALES="en_TST,es,pt"
|
||||
|
||||
OFN_REDIS_JOBS_URL="redis://localhost:6379/2"
|
||||
|
||||
SECRET_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
@@ -2,15 +2,36 @@
|
||||
|
||||
module PaymentGateways
|
||||
class TalerController < BaseController
|
||||
include OrderStockCheck
|
||||
include OrderCompletion
|
||||
|
||||
class StockError < StandardError
|
||||
end
|
||||
|
||||
# The Taler merchant backend has taken the payment.
|
||||
# Now we just need to confirm that and update our local database
|
||||
# before finalising the order.
|
||||
def confirm
|
||||
payment = Spree::Payment.find(params[:payment_id])
|
||||
|
||||
# Process payment early because it's probably paid already.
|
||||
# We want to capture that before any validations raise errors.
|
||||
unless payment.process!
|
||||
return redirect_to order_failed_route(step: "payment")
|
||||
end
|
||||
|
||||
@order = payment.order
|
||||
process_payment_completion!
|
||||
OrderLocker.lock_order_and_variants(@order) do
|
||||
raise StockError unless sufficient_stock?
|
||||
|
||||
process_payment_completion!
|
||||
end
|
||||
rescue Spree::Core::GatewayError => e
|
||||
flash[:notice] = e.message
|
||||
redirect_to order_failed_route(step: "payment")
|
||||
rescue StockError
|
||||
flash[:notice] = t("checkout.payment_cancelled_due_to_stock")
|
||||
redirect_to main_app.checkout_step_path(step: "details")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -674,8 +674,6 @@ module Spree
|
||||
end
|
||||
|
||||
def process_each_payment
|
||||
raise Core::GatewayError, Spree.t(:no_pending_payments) if pending_payments.empty?
|
||||
|
||||
pending_payments.each do |payment|
|
||||
if payment.amount.zero? && zero_priced_order?
|
||||
payment.update_columns(state: "completed", captured_at: Time.zone.now)
|
||||
|
||||
@@ -158,10 +158,10 @@ module Openfoodnetwork
|
||||
# Activate observers that should always be running.
|
||||
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
||||
|
||||
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
||||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
||||
# The default locale is set in the environment.
|
||||
config.i18n.default_locale = OpenFoodNetwork::I18nConfig.default_locale
|
||||
config.i18n.available_locales = OpenFoodNetwork::I18nConfig.available_locales
|
||||
config.i18n.fallbacks = OpenFoodNetwork::I18nConfig.fallbacks
|
||||
I18n.locale = config.i18n.locale = config.i18n.default_locale
|
||||
|
||||
# Calculate digests for locale files so we can know when they change
|
||||
|
||||
@@ -111,8 +111,6 @@ Rails.application.configure do
|
||||
# Raises error for missing translations.
|
||||
# config.i18n.raise_on_missing_translations = true
|
||||
|
||||
config.i18n.fallbacks = [:en]
|
||||
|
||||
# Annotate rendered view with file names.
|
||||
# config.action_view.annotate_rendered_view_with_filenames = true
|
||||
|
||||
|
||||
@@ -91,10 +91,6 @@ Rails.application.configure do
|
||||
# Use https in email links
|
||||
config.action_mailer.default_url_options = { protocol: 'https' }
|
||||
|
||||
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
||||
# the I18n.default_locale when a translation cannot be found).
|
||||
config.i18n.fallbacks = [:en]
|
||||
|
||||
# Send deprecation notices to registered listeners
|
||||
config.active_support.deprecation = :notify
|
||||
|
||||
|
||||
@@ -60,10 +60,6 @@ Openfoodnetwork::Application.configure do
|
||||
# Enable threaded mode
|
||||
# config.threadsafe!
|
||||
|
||||
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
||||
# the I18n.default_locale when a translation can not be found)
|
||||
config.i18n.fallbacks = [:en]
|
||||
|
||||
# Send deprecation notices to registered listeners
|
||||
config.active_support.deprecation = :notify
|
||||
end
|
||||
|
||||
@@ -89,12 +89,6 @@ Rails.application.configure do
|
||||
# Raises error for missing translations.
|
||||
config.i18n.raise_on_missing_translations = true
|
||||
|
||||
# Tests assume English text on the site.
|
||||
config.i18n.default_locale = "en"
|
||||
config.i18n.available_locales = ['en', 'es', 'pt']
|
||||
config.i18n.fallbacks = [:en]
|
||||
I18n.locale = config.i18n.locale = config.i18n.default_locale
|
||||
|
||||
# Annotate rendered view with file names.
|
||||
# config.action_view.annotate_rendered_view_with_filenames = true
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ module OpenFoodNetwork
|
||||
(selectable_locales + [default_locale, source_locale]).uniq
|
||||
end
|
||||
|
||||
def self.fallbacks
|
||||
[default_locale, source_locale].uniq
|
||||
end
|
||||
|
||||
# The default locale that is used when the user doesn't have a preference.
|
||||
def self.default_locale
|
||||
ENV["LOCALE"] || ENV["I18N_LOCALE"] || source_locale
|
||||
|
||||
@@ -15,7 +15,7 @@ RSpec.describe I18nHelper do
|
||||
|
||||
it "sets the default locale" do
|
||||
helper.set_locale
|
||||
expect(I18n.locale).to eq :en
|
||||
expect(I18n.locale).to eq :en_TST
|
||||
end
|
||||
|
||||
it "sets the chosen locale" do
|
||||
@@ -36,11 +36,11 @@ RSpec.describe I18nHelper do
|
||||
it "ignores unavailable locales" do
|
||||
allow(helper).to receive(:params) { { locale: "xx" } }
|
||||
helper.set_locale
|
||||
expect(I18n.locale).to eq :en
|
||||
expect(I18n.locale).to eq :en_TST
|
||||
end
|
||||
|
||||
it "remembers the last chosen locale" do
|
||||
allow(helper).to receive(:params) { { locale: "en" } }
|
||||
allow(helper).to receive(:params) { { locale: "en_TST" } }
|
||||
helper.set_locale
|
||||
|
||||
allow(helper).to receive(:params) { { locale: "es" } }
|
||||
@@ -71,7 +71,7 @@ RSpec.describe I18nHelper do
|
||||
|
||||
allow(helper).to receive(:params) { {} }
|
||||
helper.set_locale
|
||||
expect(I18n.locale).to eq :en
|
||||
expect(I18n.locale).to eq :en_TST
|
||||
end
|
||||
end
|
||||
|
||||
@@ -82,7 +82,7 @@ RSpec.describe I18nHelper do
|
||||
|
||||
it "sets the default locale" do
|
||||
helper.set_locale
|
||||
expect(I18n.locale).to eq :en
|
||||
expect(I18n.locale).to eq :en_TST
|
||||
end
|
||||
|
||||
it "sets the chosen locale" do
|
||||
@@ -102,7 +102,7 @@ RSpec.describe I18nHelper do
|
||||
end
|
||||
|
||||
it "remembers the last chosen locale" do
|
||||
allow(helper).to receive(:params) { { locale: "en" } }
|
||||
allow(helper).to receive(:params) { { locale: "en_TST" } }
|
||||
helper.set_locale
|
||||
|
||||
allow(helper).to receive(:params) { { locale: "es" } }
|
||||
|
||||
@@ -282,11 +282,6 @@ RSpec.describe Spree::Order do
|
||||
let(:payment) { build(:payment) }
|
||||
before { allow(order).to receive_messages pending_payments: [payment], total: 10 }
|
||||
|
||||
it "returns false if no pending_payments available" do
|
||||
allow(order).to receive_messages pending_payments: []
|
||||
expect(order.process_payments!).to be_falsy
|
||||
end
|
||||
|
||||
context "when the processing is sucessful" do
|
||||
it "processes the payments" do
|
||||
expect(payment).to receive(:process!)
|
||||
|
||||
@@ -3,16 +3,19 @@
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe "/payment_gateways/taler/:id" do
|
||||
it "completes the order", :vcr do
|
||||
shop = create(:distributor_enterprise)
|
||||
taler = Spree::PaymentMethod::Taler.create!(
|
||||
let(:shop) { create(:distributor_enterprise) }
|
||||
let(:taler) {
|
||||
Spree::PaymentMethod::Taler.create!(
|
||||
name: "Taler",
|
||||
environment: "test",
|
||||
distributors: [shop],
|
||||
preferred_backend_url: "https://backend.demo.taler.net/instances/sandbox",
|
||||
preferred_api_key: "sandbox",
|
||||
)
|
||||
order = create(:order_ready_for_confirmation, payment_method: taler)
|
||||
}
|
||||
let!(:order) { create(:order_ready_for_confirmation, payment_method: taler) }
|
||||
|
||||
it "completes the order", :vcr do
|
||||
payment = Spree::Payment.last
|
||||
payment.update!(
|
||||
source: taler,
|
||||
@@ -30,4 +33,65 @@ RSpec.describe "/payment_gateways/taler/:id" do
|
||||
payment.reload
|
||||
expect(payment.state).to eq "completed"
|
||||
end
|
||||
|
||||
it "redirects when payment invalid" do
|
||||
payment = Spree::Payment.last
|
||||
payment.update!(
|
||||
source: taler,
|
||||
payment_method: taler,
|
||||
state: "processing", # invalid state to start processing again
|
||||
)
|
||||
|
||||
get payment_gateways_confirm_taler_path(payment_id: payment.id)
|
||||
expect(response).to redirect_to "/checkout/payment"
|
||||
|
||||
payment.reload
|
||||
expect(payment.state).to eq "processing"
|
||||
|
||||
order.reload
|
||||
expect(order.state).to eq "confirmation"
|
||||
end
|
||||
|
||||
it "redirects when payment failed" do
|
||||
payment = Spree::Payment.last
|
||||
payment.update!(
|
||||
source: taler,
|
||||
payment_method: taler,
|
||||
response_code: "2026.020-03R3ETNZZ0DVA",
|
||||
)
|
||||
|
||||
allow_any_instance_of(Taler::Order)
|
||||
.to receive(:fetch).with("order_status").and_return("claimed")
|
||||
|
||||
get payment_gateways_confirm_taler_path(payment_id: payment.id)
|
||||
expect(response).to redirect_to "/checkout/payment"
|
||||
|
||||
payment.reload
|
||||
expect(payment.state).to eq "failed"
|
||||
|
||||
order.reload
|
||||
expect(order.state).to eq "confirmation"
|
||||
end
|
||||
|
||||
it "handles all variants going out of stock" do
|
||||
payment = Spree::Payment.last
|
||||
payment.update!(
|
||||
source: taler,
|
||||
payment_method: taler,
|
||||
response_code: "2026.020-03R3ETNZZ0DVA",
|
||||
)
|
||||
|
||||
allow_any_instance_of(Taler::Order)
|
||||
.to receive(:fetch).with("order_status").and_return("paid")
|
||||
order.line_items[0].variant.on_hand = 0
|
||||
|
||||
get payment_gateways_confirm_taler_path(payment_id: payment.id)
|
||||
expect(response).to redirect_to "/checkout/details"
|
||||
|
||||
payment.reload
|
||||
expect(payment.state).to eq "completed"
|
||||
|
||||
order.reload
|
||||
expect(order.state).to eq "confirmation"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -152,7 +152,7 @@ RSpec.configure do |config|
|
||||
|
||||
# Reset locale for all specs.
|
||||
config.around(:each) do |example|
|
||||
locale = ENV.fetch('LOCALE', 'en_TST')
|
||||
locale = OpenFoodNetwork::I18nConfig.default_locale
|
||||
I18n.with_locale(locale) { example.run }
|
||||
end
|
||||
|
||||
|
||||
@@ -27,10 +27,6 @@ module WebHelper
|
||||
yield
|
||||
end
|
||||
|
||||
def set_i18n_locale(locale = 'en')
|
||||
page.execute_script("I18n.locale = '#{locale}'")
|
||||
end
|
||||
|
||||
def pick_i18n_locale
|
||||
page.evaluate_script("I18n.locale;")
|
||||
end
|
||||
|
||||
@@ -10,17 +10,12 @@ RSpec.describe 'Multilingual' do
|
||||
|
||||
before do
|
||||
login_as admin_user
|
||||
visit spree.admin_dashboard_path
|
||||
end
|
||||
|
||||
it 'has three locales available' do
|
||||
expect(Rails.application.config.i18n[:default_locale]).to eq 'en'
|
||||
expect(Rails.application.config.i18n[:locale]).to eq 'en'
|
||||
expect(Rails.application.config.i18n[:available_locales]).to eq ['en', 'es', 'pt']
|
||||
end
|
||||
|
||||
it 'can switch language by params' do
|
||||
expect(pick_i18n_locale).to eq 'en'
|
||||
visit spree.admin_dashboard_path
|
||||
|
||||
expect(pick_i18n_locale).to eq 'en_TST'
|
||||
expect(get_i18n_translation('spree_admin_overview_enterprises_header')).to eq 'My Enterprises'
|
||||
expect(page).to have_content 'My Enterprises'
|
||||
expect(admin_user.locale).to be_nil
|
||||
@@ -36,9 +31,9 @@ RSpec.describe 'Multilingual' do
|
||||
|
||||
it 'fallbacks to default_locale' do
|
||||
visit spree.admin_dashboard_path(locale: 'it')
|
||||
expect(pick_i18n_locale).to eq 'en'
|
||||
expect(pick_i18n_locale).to eq 'en_TST'
|
||||
expect(get_i18n_translation('spree_admin_overview_enterprises_header')).to eq 'My Enterprises'
|
||||
expect(page).to have_content 'My Enterprises'
|
||||
expect(admin_user.locale).to be_nil
|
||||
expect(admin_user.reload.locale).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -273,7 +273,7 @@ RSpec.describe "Authentication" do
|
||||
expect_logged_in
|
||||
|
||||
expect(page).to have_content 'SHOP NOW'
|
||||
expect(user.reload.locale).to eq "en"
|
||||
expect(user.reload.locale).to eq "en_TST"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ RSpec.describe "As a consumer, I want to checkout my order" do
|
||||
|
||||
before do
|
||||
login_as(user)
|
||||
visit checkout_path
|
||||
end
|
||||
|
||||
context "payment step" do
|
||||
@@ -67,6 +66,7 @@ RSpec.describe "As a consumer, I want to checkout my order" do
|
||||
|
||||
context "with a transaction fee" do
|
||||
before do
|
||||
visit checkout_path
|
||||
click_button "Next - Order summary"
|
||||
end
|
||||
|
||||
@@ -84,6 +84,7 @@ RSpec.describe "As a consumer, I want to checkout my order" do
|
||||
|
||||
context "after completing the order" do
|
||||
before do
|
||||
visit checkout_path
|
||||
click_on "Complete order"
|
||||
end
|
||||
it_behaves_like "displays the transaction fee", "order confirmation"
|
||||
@@ -277,7 +278,7 @@ RSpec.describe "As a consumer, I want to checkout my order" do
|
||||
|
||||
describe "choosing" do
|
||||
shared_examples "different payment methods" do |pay_method|
|
||||
context "checking out with #{pay_method}", if: pay_method.eql?("Stripe SCA") == false do
|
||||
context "checking out with #{pay_method}" do
|
||||
before do
|
||||
visit checkout_step_path(:payment)
|
||||
end
|
||||
@@ -291,46 +292,9 @@ RSpec.describe "As a consumer, I want to checkout my order" do
|
||||
expect(order.reload.state).to eq "complete"
|
||||
end
|
||||
end
|
||||
|
||||
context "for Stripe SCA", if: pay_method.eql?("Stripe SCA") do
|
||||
around do |example|
|
||||
with_stripe_setup { example.run }
|
||||
end
|
||||
|
||||
before do
|
||||
stripe_enable
|
||||
visit checkout_step_path(:payment)
|
||||
end
|
||||
|
||||
it "selects Stripe SCA and proceeds to the summary step" do
|
||||
choose pay_method.to_s
|
||||
fill_out_card_details
|
||||
click_on "Next - Order summary"
|
||||
proceed_to_summary
|
||||
end
|
||||
|
||||
context "when saving card" do
|
||||
it "selects Stripe SCA and proceeds to the summary step" do
|
||||
stub_customers_post_request(email: order.user.email)
|
||||
stub_payment_method_attach_request
|
||||
|
||||
choose pay_method.to_s
|
||||
fill_out_card_details
|
||||
check "Save card for future use"
|
||||
|
||||
click_on "Next - Order summary"
|
||||
proceed_to_summary
|
||||
|
||||
# Verify card has been saved with correct stripe IDs
|
||||
user_credit_card = order.reload.user.credit_cards.first
|
||||
expect(user_credit_card.gateway_payment_profile_id).to eq "pm_123"
|
||||
expect(user_credit_card.gateway_customer_profile_id).to eq "cus_A123"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "shared examples" do
|
||||
describe "payment method" do
|
||||
let!(:cash) { create(:payment_method, distributors: [distributor], name: "Cash") }
|
||||
|
||||
context "Cash" do
|
||||
@@ -365,7 +329,40 @@ RSpec.describe "As a consumer, I want to checkout my order" do
|
||||
create(:stripe_sca_payment_method, distributors: [distributor], name: "Stripe SCA")
|
||||
}
|
||||
|
||||
it_behaves_like "different payment methods", "Stripe SCA"
|
||||
around do |example|
|
||||
with_stripe_setup { example.run }
|
||||
end
|
||||
|
||||
before do
|
||||
stripe_enable
|
||||
visit checkout_step_path(:payment)
|
||||
end
|
||||
|
||||
it "selects Stripe SCA and proceeds to the summary step" do
|
||||
choose "Stripe SCA"
|
||||
fill_out_card_details
|
||||
click_on "Next - Order summary"
|
||||
proceed_to_summary
|
||||
end
|
||||
|
||||
context "when saving card" do
|
||||
it "selects Stripe SCA and proceeds to the summary step" do
|
||||
stub_customers_post_request(email: order.user.email)
|
||||
stub_payment_method_attach_request
|
||||
|
||||
choose "Stripe SCA"
|
||||
fill_out_card_details
|
||||
check "Save card for future use"
|
||||
|
||||
click_on "Next - Order summary"
|
||||
proceed_to_summary
|
||||
|
||||
# Verify card has been saved with correct stripe IDs
|
||||
user_credit_card = order.reload.user.credit_cards.first
|
||||
expect(user_credit_card.gateway_payment_profile_id).to eq "pm_123"
|
||||
expect(user_credit_card.gateway_customer_profile_id).to eq "cus_A123"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "Taler" do
|
||||
|
||||
@@ -5,189 +5,72 @@ require 'system_helper'
|
||||
RSpec.describe 'Multilingual' do
|
||||
include AuthenticationHelper
|
||||
include WebHelper
|
||||
include ShopWorkflow
|
||||
include UIComponentHelper
|
||||
include CookieHelper
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it 'has three locales available' do
|
||||
expect(Rails.application.config.i18n[:default_locale]).to eq 'en'
|
||||
expect(Rails.application.config.i18n[:locale]).to eq 'en'
|
||||
expect(Rails.application.config.i18n[:available_locales]).to eq ['en', 'es', 'pt']
|
||||
expect(Rails.application.config.i18n[:default_locale]).to eq 'en_TST'
|
||||
expect(Rails.application.config.i18n[:locale]).to eq 'en_TST'
|
||||
expect(Rails.application.config.i18n[:available_locales]).to eq ['en_TST', 'es', 'pt', 'en']
|
||||
end
|
||||
|
||||
it '18n-js fallsback to default language' do
|
||||
# in backend it doesn't until we change enforce_available_locales to `true`
|
||||
it 'can switch language by params' do
|
||||
visit root_path
|
||||
set_i18n_locale('it')
|
||||
expect(pick_i18n_locale).to eq 'en_TST'
|
||||
expect(get_i18n_translation('label_shops')).to eq 'Shops'
|
||||
expect(cookies_name).not_to include('locale')
|
||||
expect(page).to have_content 'SHOPS'
|
||||
|
||||
visit root_path(locale: 'es')
|
||||
expect(pick_i18n_locale).to eq 'es'
|
||||
expect(get_i18n_translation('label_shops')).to eq 'Tiendas'
|
||||
expect_menu_and_cookie_in_es
|
||||
|
||||
# it is not in the list of available of available_locales
|
||||
visit root_path(locale: 'it')
|
||||
expect(pick_i18n_locale).to eq 'es'
|
||||
expect(get_i18n_translation('label_shops')).to eq 'Tiendas'
|
||||
expect_menu_and_cookie_in_es
|
||||
end
|
||||
|
||||
context 'can switch language by params' do
|
||||
it 'in root path' do
|
||||
visit root_path
|
||||
expect(pick_i18n_locale).to eq 'en'
|
||||
expect(get_i18n_translation('label_shops')).to eq 'Shops'
|
||||
expect(cookies_name).not_to include('locale')
|
||||
expect(page).to have_content 'SHOPS'
|
||||
it 'updates user locale from cookie if it is empty' do
|
||||
visit root_path(locale: 'es')
|
||||
|
||||
visit root_path(locale: 'es')
|
||||
expect(pick_i18n_locale).to eq 'es'
|
||||
expect(get_i18n_translation('label_shops')).to eq 'Tiendas'
|
||||
expect_menu_and_cookie_in_es
|
||||
expect_menu_and_cookie_in_es
|
||||
expect(user.locale).to be_nil
|
||||
login_as user
|
||||
visit root_path
|
||||
|
||||
# it is not in the list of available of available_locales
|
||||
visit root_path(locale: 'it')
|
||||
expect(pick_i18n_locale).to eq 'es'
|
||||
expect(get_i18n_translation('label_shops')).to eq 'Tiendas'
|
||||
expect_menu_and_cookie_in_es
|
||||
end
|
||||
expect_menu_and_cookie_in_es
|
||||
|
||||
context 'with a product in the cart' do
|
||||
let(:distributor) { create(:distributor_enterprise, with_payment_and_shipping: true) }
|
||||
let!(:order_cycle) {
|
||||
create(:simple_order_cycle, distributors: [distributor], variants: [product.variants.first])
|
||||
}
|
||||
let(:product) { create(:simple_product) }
|
||||
let(:order) { create(:order, order_cycle:, distributor:) }
|
||||
# The user's locale is not changed if the language was chosen before
|
||||
# login. Is it a bug or a feature? Probably not important...
|
||||
expect(user.reload.locale).to eq nil
|
||||
|
||||
before do
|
||||
pick_order order
|
||||
add_product_to_cart order, product, quantity: 1
|
||||
end
|
||||
visit root_path(locale: 'es')
|
||||
expect(user.reload.locale).to eq 'es'
|
||||
|
||||
it "in the cart page" do
|
||||
visit main_app.cart_path(locale: 'es')
|
||||
logout
|
||||
|
||||
expect_menu_and_cookie_in_es
|
||||
expect(page).to have_content 'Precio'
|
||||
end
|
||||
|
||||
it "visiting checkout as a guest user" do
|
||||
visit checkout_path(locale: 'es')
|
||||
|
||||
expect_menu_and_cookie_in_es
|
||||
expect(page).to have_content 'Iniciar sesión'
|
||||
end
|
||||
end
|
||||
expect_menu_and_cookie_in_es
|
||||
expect(page).to have_content '¿Estás interesada en entrar en Open Food Network?'
|
||||
end
|
||||
|
||||
context 'with user' do
|
||||
let(:user) { create(:user) }
|
||||
it "allows switching language via the main navigation" do
|
||||
visit root_path
|
||||
|
||||
it 'updates user locale from cookie if it is empty' do
|
||||
visit root_path(locale: 'es')
|
||||
expect(page).to have_content 'SHOPS'
|
||||
|
||||
expect_menu_and_cookie_in_es
|
||||
expect(user.locale).to be_nil
|
||||
login_as user
|
||||
visit root_path
|
||||
find('.language-switcher').click
|
||||
within '.language-switcher .dropdown' do
|
||||
expect(page).not_to have_link 'English'
|
||||
expect(page).to have_link 'Español'
|
||||
|
||||
expect_menu_and_cookie_in_es
|
||||
click_link 'Español'
|
||||
end
|
||||
|
||||
it 'updates user locale and stays in cookie after logout' do
|
||||
login_as user
|
||||
|
||||
visit root_path(locale: 'es')
|
||||
user.reload
|
||||
|
||||
expect(user.locale).to eq 'es'
|
||||
|
||||
logout
|
||||
|
||||
expect_menu_and_cookie_in_es
|
||||
expect(page).to have_content '¿Estás interesada en entrar en Open Food Network?'
|
||||
end
|
||||
|
||||
context "visiting checkout as logged user" do
|
||||
let!(:zone) { create(:zone_with_member) }
|
||||
let(:supplier) { create(:supplier_enterprise) }
|
||||
let(:distributor) { create(:distributor_enterprise, charges_sales_tax: true) }
|
||||
let(:product) {
|
||||
create(:taxed_product, supplier_id: supplier.id, price: 10, zone:)
|
||||
}
|
||||
let(:variant) { product.variants.first }
|
||||
let!(:order_cycle) {
|
||||
create(:simple_order_cycle, suppliers: [supplier], distributors: [distributor],
|
||||
coordinator: create(:distributor_enterprise),
|
||||
variants: [variant])
|
||||
}
|
||||
|
||||
let(:free_shipping) {
|
||||
create(:shipping_method, require_ship_address: false)
|
||||
}
|
||||
let!(:payment) {
|
||||
create(:payment_method, distributors: [distributor],
|
||||
name: "Payment")
|
||||
}
|
||||
let(:order) {
|
||||
create(:order_ready_for_confirmation, distributor:)
|
||||
}
|
||||
before do
|
||||
pick_order order
|
||||
login_as user
|
||||
end
|
||||
|
||||
it "on the details step" do
|
||||
visit checkout_step_path(:details, locale: 'es')
|
||||
|
||||
expect_menu_and_cookie_in_es
|
||||
expect(page).to have_content "Sus detalles"
|
||||
end
|
||||
|
||||
it "on the payment step" do
|
||||
visit checkout_step_path(:payment, locale: 'es')
|
||||
|
||||
expect_menu_and_cookie_in_es
|
||||
expect(page).to have_content "Puede revisar y confirmar su pedido"
|
||||
end
|
||||
|
||||
it "on the summary step" do
|
||||
visit checkout_step_path(:summary, locale: 'es')
|
||||
|
||||
expect_menu_and_cookie_in_es
|
||||
expect(page).to have_content "Detalles de entrega"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "using the language switcher UI" do
|
||||
context "when there is only one language available" do
|
||||
before do
|
||||
allow(ENV).to receive(:[]).and_call_original
|
||||
allow(ENV).to receive(:[]).with("LOCALE").and_return("en")
|
||||
allow(ENV).to receive(:[]).with("AVAILABLE_LOCALES").and_return("en")
|
||||
end
|
||||
|
||||
it "hides the dropdown language menu" do
|
||||
visit root_path
|
||||
expect(page).not_to have_css 'ul.right li.language-switcher.has-dropdown'
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are multiple languages available" do
|
||||
before do
|
||||
allow(ENV).to receive(:[]).and_call_original
|
||||
allow(ENV).to receive(:[]).with("LOCALE").and_return("en")
|
||||
allow(ENV).to receive(:[]).with("AVAILABLE_LOCALES").and_return("en,es")
|
||||
end
|
||||
|
||||
it "allows switching language via the main navigation" do
|
||||
visit root_path
|
||||
|
||||
expect(page).to have_content 'SHOPS'
|
||||
|
||||
find('.language-switcher').click
|
||||
within '.language-switcher .dropdown' do
|
||||
expect(page).not_to have_link 'English', href: '/locales/en'
|
||||
expect(page).to have_link 'Español', href: '/locales/es'
|
||||
|
||||
find('li a[href="/locales/es"]').click
|
||||
end
|
||||
|
||||
expect_menu_and_cookie_in_es
|
||||
end
|
||||
end
|
||||
expect_menu_and_cookie_in_es
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -3,221 +3,34 @@
|
||||
require 'system_helper'
|
||||
|
||||
RSpec.describe "Check out with Stripe" do
|
||||
include AuthenticationHelper
|
||||
include ShopWorkflow
|
||||
include CheckoutRequestsHelper
|
||||
include StripeHelper
|
||||
include StripeStubs
|
||||
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let!(:order_cycle) {
|
||||
create(:simple_order_cycle, distributors: [distributor], variants: [variant])
|
||||
}
|
||||
let(:product) { create(:product, price: 10) }
|
||||
let(:variant) { product.variants.first }
|
||||
let(:order) {
|
||||
create(:order, order_cycle:, distributor:, bill_address_id: nil,
|
||||
ship_address_id: nil)
|
||||
}
|
||||
|
||||
let(:shipping_with_fee) {
|
||||
create(:shipping_method, require_ship_address: false, name: "Donkeys",
|
||||
calculator: Calculator::FlatRate.new(preferred_amount: 4.56))
|
||||
}
|
||||
let(:free_shipping) { create(:shipping_method) }
|
||||
let!(:check_with_fee) {
|
||||
create(:payment_method, distributors: [distributor],
|
||||
calculator: Calculator::FlatRate.new(preferred_amount: 5.67))
|
||||
}
|
||||
|
||||
around do |example|
|
||||
with_stripe_setup { example.run }
|
||||
end
|
||||
|
||||
before do
|
||||
stripe_enable
|
||||
pick_order order
|
||||
add_product_to_cart order, product
|
||||
distributor.shipping_methods << [shipping_with_fee, free_shipping]
|
||||
end
|
||||
|
||||
pending "using Stripe SCA" do
|
||||
let!(:stripe_account) { create(:stripe_account, enterprise: distributor) }
|
||||
let!(:stripe_sca_payment_method) {
|
||||
create(:stripe_sca_payment_method, distributors: [distributor])
|
||||
}
|
||||
let!(:shipping_method) { create(:shipping_method) }
|
||||
let(:error_message) { "Card was declined: insufficient funds." }
|
||||
|
||||
before do
|
||||
stub_payment_intent_get_request
|
||||
stub_payment_methods_post_request
|
||||
end
|
||||
|
||||
describe "using Stripe SCA" do
|
||||
context "with guest checkout" do
|
||||
before do
|
||||
stub_retrieve_payment_method_request("pm_123")
|
||||
stub_list_customers_request(email: order.user.email, response: {})
|
||||
stub_get_customer_payment_methods_request(customer: "cus_A456", response: {})
|
||||
end
|
||||
|
||||
context "when the card is accepted" do
|
||||
before do
|
||||
stub_payment_intents_post_request(order:)
|
||||
stub_successful_capture_request order:
|
||||
end
|
||||
|
||||
it "completes checkout successfully" do
|
||||
checkout_with_stripe
|
||||
|
||||
expect(page).to have_content "Confirmed"
|
||||
expect(page.find("#amount-paid").text).to have_content "$19.99"
|
||||
|
||||
expect(order.reload.completed?).to eq true
|
||||
expect(order.payments.first.state).to eq "completed"
|
||||
end
|
||||
it "completes checkout successfully"
|
||||
end
|
||||
|
||||
context "when the card is rejected" do
|
||||
before do
|
||||
stub_payment_intents_post_request(order:)
|
||||
stub_failed_capture_request order:, response: { message: error_message }
|
||||
end
|
||||
|
||||
it "shows an error message from the Stripe response" do
|
||||
checkout_with_stripe
|
||||
|
||||
expect(page).to have_content error_message
|
||||
expect(order.reload.state).to eq "cart"
|
||||
expect(order.payments.first.state).to eq "failed"
|
||||
end
|
||||
it "shows an error message from the Stripe response"
|
||||
end
|
||||
|
||||
context "when the card needs extra SCA authorization" do
|
||||
before do
|
||||
stripe_redirect_url = checkout_path(payment_intent: "pi_123")
|
||||
stub_payment_intents_post_request_with_redirect order:,
|
||||
redirect_url: stripe_redirect_url
|
||||
end
|
||||
|
||||
describe "and the authorization succeeds" do
|
||||
before do
|
||||
stub_successful_capture_request order:
|
||||
end
|
||||
|
||||
it "completes checkout successfully" do
|
||||
checkout_with_stripe
|
||||
|
||||
# We make stripe return stripe_redirect_url (which is already sending the user back
|
||||
# to the checkout) as if the authorization was done. We can then control the actual
|
||||
# authorization or failure of the payment through the mock
|
||||
# stub_successful_capture_request
|
||||
|
||||
expect(page).to have_content "Confirmed"
|
||||
expect(order.reload.completed?).to eq true
|
||||
expect(order.payments.first.state).to eq "completed"
|
||||
end
|
||||
it "completes checkout successfully"
|
||||
end
|
||||
|
||||
describe "and the authorization fails" do
|
||||
before do
|
||||
stub_failed_capture_request order:, response: { message: error_message }
|
||||
end
|
||||
|
||||
it "shows an error message from the Stripe response" do
|
||||
checkout_with_stripe
|
||||
|
||||
# We make stripe return stripe_redirect_url (which is already sending the user back to
|
||||
# the checkout) as if the authorization was done. We can then control the actual
|
||||
# authorization or failure of the payment through the mock stub_failed_capture_request
|
||||
expect(page).to have_content error_message
|
||||
expect(order.reload.state).to eq "cart"
|
||||
expect(order.payments.first.state).to eq "failed"
|
||||
end
|
||||
it "shows an error message from the Stripe response"
|
||||
end
|
||||
end
|
||||
|
||||
context "with multiple payment attempts; one failed and one succeeded" do
|
||||
before do
|
||||
stub_payment_intents_post_request order:
|
||||
end
|
||||
|
||||
it "records failed payment attempt and allows order completion" do
|
||||
# First payment attempt is rejected
|
||||
stub_failed_capture_request(order:, response: { message: error_message })
|
||||
checkout_with_stripe
|
||||
expect(page).to have_content error_message
|
||||
|
||||
expect(order.reload.payments.count).to eq 1
|
||||
expect(order.state).to eq "cart"
|
||||
expect(order.payments.first.state).to eq "failed"
|
||||
|
||||
# Second payment attempt is accepted
|
||||
stub_successful_capture_request(order:)
|
||||
place_order
|
||||
expect(page).to have_content "Confirmed"
|
||||
|
||||
expect(order.reload.payments.count).to eq 2
|
||||
expect(order.state).to eq "complete"
|
||||
expect(order.payments.last.state).to eq "completed"
|
||||
end
|
||||
it "records failed payment attempt and allows order completion"
|
||||
end
|
||||
end
|
||||
|
||||
context "with a logged in user" do
|
||||
let(:user) { order.user }
|
||||
|
||||
before do
|
||||
login_as user
|
||||
end
|
||||
|
||||
context "saving a card and re-using it" do
|
||||
before do
|
||||
stub_retrieve_payment_method_request("pm_123")
|
||||
stub_list_customers_request(email: order.user.email, response: {})
|
||||
stub_get_customer_payment_methods_request(customer: "cus_A456", response: {})
|
||||
stub_get_customer_payment_methods_request(customer: "cus_A123", response: {})
|
||||
stub_payment_methods_post_request(
|
||||
request: { payment_method: "pm_123", customer: "cus_A123" },
|
||||
response: { pm_id: "pm_123" }
|
||||
)
|
||||
stub_add_metadata_request(payment_method: "pm_123", response: {})
|
||||
stub_payment_intents_post_request(order:)
|
||||
stub_successful_capture_request(order:)
|
||||
stub_customers_post_request email: "test@test.com" # First checkout with default details
|
||||
stub_customers_post_request email: user.email # Second checkout with saved user details
|
||||
stub_payment_method_attach_request
|
||||
end
|
||||
|
||||
it "allows saving a card and re-using it" do
|
||||
checkout_with_stripe guest_checkout: false, remember_card: true
|
||||
|
||||
expect(page).to have_content "Confirmed"
|
||||
expect(order.reload.completed?).to eq true
|
||||
expect(order.payments.first.state).to eq "completed"
|
||||
|
||||
# Verify card has been saved with correct stripe IDs
|
||||
user_credit_card = order.reload.user.credit_cards.first
|
||||
expect(user_credit_card.gateway_payment_profile_id).to eq "pm_123"
|
||||
expect(user_credit_card.gateway_customer_profile_id).to eq "cus_A123"
|
||||
|
||||
# Prepare a second order
|
||||
new_order = create(:order, user:, order_cycle:,
|
||||
distributor:, bill_address_id: nil,
|
||||
ship_address_id: nil)
|
||||
pick_order(new_order)
|
||||
add_product_to_cart(new_order, product, quantity: 10)
|
||||
stub_payment_intents_post_request order: new_order
|
||||
stub_successful_capture_request order: new_order
|
||||
|
||||
# Checkout with saved card
|
||||
visit checkout_path
|
||||
choose free_shipping.name
|
||||
choose stripe_sca_payment_method.name
|
||||
expect(page).to have_content "Use a saved card"
|
||||
expect(page).to have_select 'selected_card', selected: "Visa x-4242 Exp:10/2050"
|
||||
place_order
|
||||
end
|
||||
it "allows saving a card and re-using it"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user