Skip to content

Instantly share code, notes, and snippets.

@spaghetticode
Created January 4, 2019 08:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spaghetticode/35dd0d91625a65d75aee32e383af795c to your computer and use it in GitHub Desktop.
Save spaghetticode/35dd0d91625a65d75aee32e383af795c to your computer and use it in GitHub Desktop.
Specs to expose stock validation issues on Solidus checkout confirm page
require 'spec_helper'
describe "Checkout confirm page", type: :feature do
include_context 'checkout setup'
context 'when there is not enough stock at the default stock location' do
context "when the product is not backorderable" do
let(:user) { create(:user) }
let(:order) { Spree::TestingSupport::OrderWalkthrough.up_to(:payment) }
let(:order_product) { order.products.first }
let(:order_stock_item) { order_product.stock_items.first }
before do
order_stock_item.update! backorderable: false
allow_any_instance_of(Spree::CheckoutController).to receive_messages(current_order: order)
allow_any_instance_of(Spree::CheckoutController).to receive_messages(try_spree_current_user: user)
allow_any_instance_of(Spree::OrdersController).to receive_messages(try_spree_current_user: user)
end
context 'when there are not other backorderable stock locations' do
before { visit spree.checkout_state_path(:confirm) }
it 'redirects to cart page and shows an unavailable product message' do
expect(page).to have_content "#{order_product.name} became unavailable"
expect(page).to have_current_path spree.cart_path
end
end
context 'when there is another backorderable stock location' do
before do
create :stock_location, backorderable_default: true, default: false
visit spree.checkout_state_path(:confirm)
end
it "redirects to the delivery checkout page and shows an availability changed message" do
click_button "Place Order"
expect(page).to have_content "#{order_product.name} availability changed. Please restart the checkout process"
expect(page).to have_current_path spree.checkout_state_path(:delivery)
end
end
end
end
end
@spaghetticode
Copy link
Author

When two users try to purchase the last item remaining from a non-backordeable stock location at the same time then the last one will experience an unhandled error Spree::Order::InsufficientStock. This happens only if there is a second backorderable stock location for the product.

The error is generated by the method Spree::Order#validate_line_item_availability triggered by this state machine guard:

before_transition to: :complete, do: :validate_line_item_availability

So, controller validations (provided here via before_action :ensure_sufficient_stock_lines) are following a different path, calling different methods, and this causes that error to be raised later in the order finalization process. Unifying the process seems to me the most reasonable way to fix the issue.

@spaghetticode
Copy link
Author

On Solidus < 2.7 the issue is a bit more involuted, as `Spree::Stock::AvailabilityValidator does not exist yet and its equivalent code is spread among many different models.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment