Merge pull request #5361 from Matt-Yorkley/cart-with-soft-deletion

Cart with soft-deletion
This commit is contained in:
Pau Pérez Fabregat
2020-05-06 15:20:35 +02:00
committed by GitHub
8 changed files with 149 additions and 15 deletions

View File

@@ -11,6 +11,10 @@ module Spree
end
def total_on_hand
# Associated stock_items no longer exist if the variant has been soft-deleted. A variant
# may still be in an active cart after it's deleted, so this will mark it as out of stock.
return 0 if @variant.deleted?
stock_items.sum(&:count_on_hand)
end

View File

@@ -29,11 +29,15 @@ class CartService
variants_data.each do |variant_data|
loaded_variant = loaded_variants[variant_data[:variant_id].to_i]
if loaded_variant.deleted?
remove_deleted_variant(loaded_variant)
next
end
next unless varies_from_cart(variant_data, loaded_variant)
attempt_cart_add(
loaded_variant, variant_data[:quantity], variant_data[:max_quantity]
)
attempt_cart_add(loaded_variant, variant_data[:quantity], variant_data[:max_quantity])
end
end
@@ -41,12 +45,16 @@ class CartService
@indexed_variants ||= begin
variant_ids_in_data = variants_data.map{ |v| v[:variant_id] }
Spree::Variant.where(id: variant_ids_in_data).
Spree::Variant.with_deleted.where(id: variant_ids_in_data).
includes(:default_price, :stock_items, :product).
index_by(&:id)
end
end
def remove_deleted_variant(variant)
line_item_for_variant(variant).andand.destroy
end
def attempt_cart_add(variant, quantity, max_quantity = nil)
quantity = quantity.to_i
max_quantity = max_quantity.to_i if max_quantity

View File

@@ -8,7 +8,7 @@ class VariantsStockLevels
variant_stock_levels = variant_stock_levels(order.line_items.includes(variant: :stock_items))
order_variant_ids = variant_stock_levels.keys
missing_variants = Spree::Variant.includes(:stock_items).
missing_variants = Spree::Variant.with_deleted.includes(:stock_items).
where(id: (requested_variant_ids - order_variant_ids))
missing_variants.each do |missing_variant|

View File

@@ -429,6 +429,34 @@ feature "As a consumer I want to shop with a distributor", js: true do
end
end
end
context "when a variant is soft-deleted" do
describe "adding the soft-deleted variant to the cart" do
it "handles it as if the variant has gone out of stock" do
variant.delete
fill_in "variants[#{variant.id}]", with: '1'
expect_out_of_stock_behavior
end
end
context "when the soft-deleted variant has an associated override" do
describe "adding the soft-deleted variant to the cart" do
let!(:variant_override) {
create(:variant_override, variant: variant, hub: distributor, count_on_hand: 100)
}
it "handles it as if the variant has gone out of stock" do
variant.delete
fill_in "variants[#{variant.id}]", with: '1'
expect_out_of_stock_behavior
end
end
end
end
end
context "when no order cycles are available" do
@@ -543,4 +571,24 @@ feature "As a consumer I want to shop with a distributor", js: true do
# waiting period before submitting the data...
sleep 0.6
end
def expect_out_of_stock_behavior
wait_for_debounce
wait_until { !cart_dirty }
# Shows an "out of stock" modal, with helpful user feedback
within(".out-of-stock-modal") do
expect(page).to have_content I18n.t('js.out_of_stock.out_of_stock_text')
end
# Removes the item from the client-side cart and marks the variant as unavailable
expect(page).to have_field "variants[#{variant.id}]", with: '0', disabled: true
expect(page).to have_selector "#variant-#{variant.id}.out-of-stock"
expect(page).to have_selector "#variants_#{variant.id}[ofn-on-hand='0']"
expect(page).to have_selector "#variants_#{variant.id}[disabled='disabled']"
# We need to wait again for the cart to finish updating in Angular or the test can fail
# as the session cannot be reset properly (after the test) while it's still loading
wait_until { !cart_dirty }
end
end

View File

@@ -227,6 +227,14 @@ describe OrderCycle do
expect(oc.variants_distributed_by(d2)).not_to include p1_v_hidden, p1_v_deleted
expect(oc.variants_distributed_by(d1)).to include p2_v
end
context "with soft-deleted variants" do
it "does not consider soft-deleted variants to be currently distributed in the oc" do
p2_v.delete
expect(oc.variants_distributed_by(d1)).to_not include p2_v
end
end
end
context "when hub prefers product selection from inventory only" do

View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'spec_helper'
module Spree
module Stock
describe Quantifier do
let(:quantifier) { Spree::Stock::Quantifier.new(variant) }
let(:variant) { create(:variant, on_hand: 99) }
describe "#total_on_hand" do
context "with a soft-deleted variant" do
before do
variant.delete
end
it "returns zero stock for the variant" do
expect(quantifier.total_on_hand).to eq 0
end
end
end
end
end
end

View File

@@ -32,6 +32,11 @@ describe VariantOverride do
expect(VariantOverride.indexed(hub1)).to eq( variant => vo1 )
expect(VariantOverride.indexed(hub2)).to eq( variant => vo2 )
end
it "does not include overrides for soft-deleted variants" do
variant.delete
expect(VariantOverride.indexed(hub1)).to eq( nil => vo1 )
end
end
end

View File

@@ -15,14 +15,18 @@ describe CartService do
context "end-to-end" do
let(:order) { create(:order, distributor: distributor, order_cycle: order_cycle) }
let(:distributor) { create(:distributor_enterprise) }
let(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], variants: [v]) }
let(:order_cycle) { create(:simple_order_cycle, distributors: [distributor],
variants: [variant]) }
let(:cart_service) { CartService.new(order) }
let(:v) { create(:variant) }
let(:variant) { create(:variant) }
describe "populate" do
describe "#populate" do
it "adds a variant" do
cart_service.populate({ variants: { v.id.to_s => { quantity: '1', max_quantity: '2' } } }, true)
li = order.find_line_item_by_variant(v)
cart_service.populate(
{ variants: { variant.id.to_s => { quantity: '1', max_quantity: '2' } } },
true
)
li = order.find_line_item_by_variant(variant)
expect(li).to be
expect(li.quantity).to eq(1)
expect(li.max_quantity).to eq(2)
@@ -30,10 +34,13 @@ describe CartService do
end
it "updates a variant's quantity, max quantity and final_weight_volume" do
order.add_variant v, 1, 2
order.add_variant variant, 1, 2
cart_service.populate({ variants: { v.id.to_s => { quantity: '2', max_quantity: '3' } } }, true)
li = order.find_line_item_by_variant(v)
cart_service.populate(
{ variants: { variant.id.to_s => { quantity: '2', max_quantity: '3' } } },
true
)
li = order.find_line_item_by_variant(variant)
expect(li).to be
expect(li.quantity).to eq(2)
expect(li.max_quantity).to eq(3)
@@ -41,13 +48,43 @@ describe CartService do
end
it "removes a variant" do
order.add_variant v, 1, 2
order.add_variant variant, 1, 2
cart_service.populate({ variants: {} }, true)
order.line_items(:reload)
li = order.find_line_item_by_variant(v)
li = order.find_line_item_by_variant(variant)
expect(li).not_to be
end
context "when a variant has been soft-deleted" do
let(:relevant_line_item) { order.reload.find_line_item_by_variant(variant) }
describe "when the soft-deleted variant is not in the cart yet" do
it "does not add the deleted variant to the cart" do
variant.delete
cart_service.populate({ variants: { variant.id.to_s => { quantity: '2' } } }, true)
expect(relevant_line_item).to be_nil
expect(cart_service.errors.count).to be 0
end
end
describe "when the soft-deleted variant is already in the cart" do
let!(:existing_line_item) {
create(:line_item, variant: variant, quantity: 2, order: order)
}
it "removes the line_item from the cart" do
variant.delete
cart_service.populate({ variants: { variant.id.to_s => { quantity: '3' } } }, true)
expect(Spree::LineItem.where(id: relevant_line_item).first).to be_nil
expect(cart_service.errors.count).to be 0
end
end
end
end
end