Files
openfoodnetwork/spec/system/admin/variant_overrides_spec.rb
Maikel Linke a3ec3e74ae Hide stock level of on-demand inventory items
We changed to tracking stock of on-demand items to be able to place
backorders. This is mostly hidden in the app but was still visible on
the inventory page. Now we are hiding that here, too.
2025-01-09 10:06:04 +11:00

569 lines
25 KiB
Ruby

# frozen_string_literal: true
require 'system_helper'
RSpec.describe "
Managing a hub's inventory
I want to override the stock level and price of products
Without affecting other hubs that share the same products
" do
include AdminHelper
include AuthenticationHelper
include WebHelper
context "as the manager of a hub" do
let!(:hub) { create(:distributor_enterprise) }
let!(:hub2) { create(:distributor_enterprise) }
let!(:producer) { create(:supplier_enterprise) }
let!(:producer_managed) { create(:supplier_enterprise) }
let!(:producer_related) { create(:supplier_enterprise) }
let!(:producer_unrelated) { create(:supplier_enterprise) }
let!(:er1) {
create(:enterprise_relationship, parent: producer, child: hub,
permissions_list: [:create_variant_overrides])
}
let!(:er2) {
create(:enterprise_relationship, parent: producer_related, child: hub,
permissions_list: [:create_variant_overrides])
}
let(:user) { create(:user, enterprises: [hub, producer_managed]) }
before { login_as user }
describe "selecting a hub" do
let!(:er1) {
create(:enterprise_relationship, parent: hub2, child: producer_managed,
permissions_list: [:add_to_order_cycle])
} # This er should not confer ability to create VOs for hub2
it "displays a list of hub choices (ie. only those managed by the user)" do
visit spree.admin_dashboard_path
click_link 'Products'
click_link 'Inventory'
# Selects the hub automatically when only one is available
expect(page).to have_select2 'hub_id', options: [hub.name]
end
end
context "when inventory_items exist for variants" do
let!(:product) {
create(:simple_product, supplier_id: producer.id, variant_unit: 'weight',
variant_unit_scale: 1)
}
let!(:variant) { create(:variant, product:, unit_value: 1, price: 1.23, on_hand: 12) }
let!(:inventory_item) { create(:inventory_item, enterprise: hub, variant: ) }
let!(:product_managed) {
create(:simple_product, supplier_id: producer_managed.id, variant_unit: 'weight',
variant_unit_scale: 1)
}
let!(:variant_managed) {
create(:variant, product: product_managed, supplier: producer_managed, unit_value: 3,
price: 3.65, on_hand: 2)
}
let!(:inventory_item_managed) {
create(:inventory_item, enterprise: hub, variant: variant_managed )
}
let!(:product_related) { create(:simple_product, supplier_id: producer_related.id) }
let!(:variant_related) {
create(:variant, product: product_related, supplier: producer_related, unit_value: 2,
price: 2.34, on_hand: 23)
}
let!(:inventory_item_related) {
create(:inventory_item, enterprise: hub, variant: variant_related )
}
let!(:product_unrelated) { create(:simple_product, supplier_id: producer_unrelated.id) }
context "when a hub is selected" do
before do
visit '/admin/inventory'
select2_select hub.name, from: 'hub_id'
end
context "with no overrides" do
it "displays the list of products with variants" do
expect(page).to have_table_row ['Producer', 'Product', 'Price', 'On Hand', 'On Demand?']
expect(page).to have_table_row ['', product.name, '', '', '']
within "tr#v_#{variant.id}" do |tr|
expect(tr).to have_content(producer.name)
end
expect(page).to have_input "variant-overrides-#{variant.id}-price", placeholder: '1.23'
expect(page).to have_input "variant-overrides-#{variant.id}-count_on_hand",
placeholder: '12'
expect(page).to have_table_row ['', product_related.name, '', '', '']
within "tr#v_#{variant_related.id}" do |tr|
expect(tr).to have_content(producer_related.name)
end
expect(page).to have_input "variant-overrides-#{variant_related.id}-price",
placeholder: '2.34'
expect(page).to have_input "variant-overrides-#{variant_related.id}-count_on_hand",
placeholder: '23'
# filters the products to those the hub can override
expect(page).not_to have_content producer_managed.name
expect(page).not_to have_content product_managed.name
expect(page).not_to have_content producer_unrelated.name
expect(page).not_to have_content product_unrelated.name
# Filters based on the producer select filter
expect(page).to have_selector "#v_#{variant.id}"
expect(page).to have_selector "#v_#{variant_related.id}"
select2_select producer.name, from: 'producer_filter'
expect(page).to have_selector "#v_#{variant.id}"
expect(page).not_to have_selector "#v_#{variant_related.id}"
select2_select 'All', from: 'producer_filter'
# Filters based on the quick search box
expect(page).to have_selector "#v_#{variant.id}"
expect(page).to have_selector "#v_#{variant_related.id}"
fill_in 'query', with: product.name
expect(page).to have_selector "#v_#{variant.id}"
expect(page).not_to have_selector "#v_#{variant_related.id}"
fill_in 'query', with: ''
# Clears the filters
expect(page).to have_selector "tr#v_#{variant.id}"
expect(page).to have_selector "tr#v_#{variant_related.id}"
select2_select producer.name, from: 'producer_filter'
fill_in 'query', with: product_related.name
expect(page).not_to have_selector "tr#v_#{variant.id}"
expect(page).not_to have_selector "tr#v_#{variant_related.id}"
click_button 'Clear All'
expect(page).to have_selector "tr#v_#{variant.id}"
expect(page).to have_selector "tr#v_#{variant_related.id}"
# Show/Hide products
toggle_columns "Hide"
expect(page).to have_selector "tr#v_#{variant.id}"
expect(page).to have_selector "tr#v_#{variant_related.id}"
within "tr#v_#{variant.id}" do
click_button 'Hide'
end
expect(page).not_to have_selector "tr#v_#{variant.id}"
expect(page).to have_selector "tr#v_#{variant_related.id}"
first("div#views-dropdown").click
first("div#views-dropdown div.menu div.menu_item", text: "Hidden Products").click
expect(page).to have_selector "tr#v_#{variant.id}"
expect(page).not_to have_selector "tr#v_#{variant_related.id}"
within "tr#v_#{variant.id}" do
click_button 'Add'
end
expect(page).not_to have_selector "tr#v_#{variant.id}"
expect(page).not_to have_selector "tr#v_#{variant_related.id}"
first("div#views-dropdown").click
first("div#views-dropdown div.menu div.menu_item", text: "Inventory Products").click
expect(page).to have_selector "tr#v_#{variant.id}"
expect(page).to have_selector "tr#v_#{variant_related.id}"
end
it "creates new overrides" do
toggle_columns "SKU"
fill_in "variant-overrides-#{variant.id}-sku", with: 'NEWSKU'
fill_in "variant-overrides-#{variant.id}-price", with: '777.77'
select_on_demand variant, :no
fill_in "variant-overrides-#{variant.id}-count_on_hand", with: '123'
expect(page).to have_content "Changes to one override remain unsaved."
expect do
click_button 'Save Changes'
expect(page).to have_content "Changes saved."
end.to change { VariantOverride.count }.by(1)
vo = VariantOverride.last
expect(vo.variant_id).to eq(variant.id)
expect(vo.hub_id).to eq(hub.id)
expect(vo.sku).to eq("NEWSKU")
expect(vo.price).to eq(777.77)
expect(vo.on_demand).to eq(false)
expect(vo.count_on_hand).to eq(123)
end
describe "creating and then updating the new override" do
it "updates the same override instead of creating a duplicate" do
# When I create a new override
fill_in "variant-overrides-#{variant.id}-price", with: '777.77'
select_on_demand variant, :no
fill_in "variant-overrides-#{variant.id}-count_on_hand", with: '123'
expect(page).to have_content "Changes to one override remain unsaved."
expect do
click_button 'Save Changes'
expect(page).to have_content "Changes saved."
end.to change { VariantOverride.count }.by(1)
# And I update its settings without reloading the page
fill_in "variant-overrides-#{variant.id}-price", with: '111.11'
fill_in "variant-overrides-#{variant.id}-count_on_hand", with: '111'
expect(page).to have_content "Changes to one override remain unsaved."
# Then I shouldn't see a new override
expect do
click_button 'Save Changes'
expect(page).to have_content "Changes saved."
end.to change { VariantOverride.count }.by(0)
# And the override should be updated
vo = VariantOverride.last
expect(vo.variant_id).to eq(variant.id)
expect(vo.hub_id).to eq(hub.id)
expect(vo.price).to eq(111.11)
expect(vo.on_demand).to eq(false)
expect(vo.count_on_hand).to eq(111)
end
end
it "displays an error when unauthorised to access the page" do
fill_in "variant-overrides-#{variant.id}-price", with: '777.77'
fill_in "variant-overrides-#{variant.id}-count_on_hand", with: '123'
expect(page).to have_content "Changes to one override remain unsaved."
# Set a user without suficient permissions
allow_any_instance_of(Spree::Admin::BaseController).to receive(:current_spree_user)
.and_return(build(:user))
expect do
click_button 'Save Changes'
# We need to wait_until because the save action is not fast enough
# for the have_content matcher
wait_until { page.find("#status-message").text != "Saving..." }
expect(page).to have_content "I couldn't get authorisation to save those changes, " \
"so they remain unsaved."
end.to change { VariantOverride.count }.by(0)
end
it "displays an error when unauthorised to update a particular override" do
fill_in "variant-overrides-#{variant_related.id}-price", with: '777.77'
fill_in "variant-overrides-#{variant_related.id}-count_on_hand", with: '123'
expect(page).to have_content "Changes to one override remain unsaved."
er2.destroy
expect do
click_button 'Save Changes'
expect(page).to have_content "I couldn't get authorisation to save those changes, " \
"so they remain unsaved."
end.to change { VariantOverride.count }.by(0)
end
end
context "with overrides" do
let!(:vo) {
create(
:variant_override,
on_demand: true, count_on_hand: -5,
variant:, hub:, price: 77.77, default_stock: 1000, resettable: true,
tag_list: ["tag1", "tag2", "tag3"]
)
}
let!(:vo_no_auth) {
create(:variant_override, variant:, hub: hub2, price: 1, count_on_hand: 2)
}
let!(:product2) {
create(:simple_product, supplier_id: producer.id, variant_unit: 'weight',
variant_unit_scale: 1)
}
let!(:variant2) {
create(:variant, product: product2, unit_value: 8, price: 1.00, on_hand: 12)
}
let!(:inventory_item2) { create(:inventory_item, enterprise: hub, variant: variant2) }
let!(:vo_no_reset) {
create(:variant_override, variant: variant2, hub:, price: 3.99, count_on_hand: 40,
default_stock: 100, resettable: false)
}
let!(:variant3) {
create(:variant, product:, unit_value: 2, price: 5.00, on_hand: 6)
}
let!(:vo3) {
create(:variant_override, variant: variant3, hub:, price: 6, count_on_hand: 7,
sku: "SOMESKU", default_stock: 100, resettable: false)
}
let!(:inventory_item3) { create(:inventory_item, enterprise: hub, variant: variant3) }
before do
visit '/admin/inventory'
select2_select hub.name, from: 'hub_id'
end
it "product values are affected by overrides" do
expect(page).to have_input "variant-overrides-#{variant.id}-price",
with: '77.77', placeholder: '1.23'
expect(page).to have_input "variant-overrides-#{variant.id}-count_on_hand",
with: "", placeholder: 'On demand'
expect(page).to have_select "variant-overrides-#{variant.id}-on_demand",
selected: 'Yes'
expect(page).to have_input "variant-overrides-#{variant2.id}-count_on_hand",
with: "40", placeholder: ""
end
it "updates existing overrides" do
fill_in "variant-overrides-#{variant.id}-price", with: '22.22'
select_on_demand variant, :no
fill_in "variant-overrides-#{variant.id}-count_on_hand", with: '8888'
expect(page).to have_content "Changes to one override remain unsaved."
expect do
click_button 'Save Changes'
expect(page).to have_content "Changes saved."
end.to change { VariantOverride.count }.by(0)
vo.reload
expect(vo.variant_id).to eq(variant.id)
expect(vo.hub_id).to eq(hub.id)
expect(vo.price).to eq(22.22)
expect(vo.on_demand).to eq(false)
expect(vo.count_on_hand).to eq(8888)
end
it "updates on_demand settings" do
select_on_demand variant, :no
click_button 'Save Changes'
expect(page).to have_content 'Changes saved.'
vo.reload
expect(vo.on_demand).to eq(false)
select_on_demand variant, :yes
click_button 'Save Changes'
expect(page).to have_content 'Changes saved.'
vo.reload
expect(vo.on_demand).to eq(true)
select_on_demand variant, :use_producer_settings
click_button 'Save Changes'
expect(page).to have_content 'Changes saved.'
vo.reload
expect(vo.on_demand).to be_nil
end
# Any new fields added to the VO model need to be added to this test
it "deletes overrides when values are cleared" do
toggle_columns "Enable Stock Reset?", "Tags"
# Clearing values by 'inheriting'
toggle_columns "Inherit?"
check "variant-overrides-#{variant3.id}-inherit"
# Hide the Inherit column again. When that column is visible, the
# size of the Tags column is too short and tags can't be removed.
# This is a bug and the next line can be removed once it is fixed:
# https://github.com/openfoodfoundation/openfoodnetwork/issues/3310
toggle_columns "Inherit?"
# Clearing values manually
fill_in "variant-overrides-#{variant.id}-price", with: ''
select_on_demand variant, :use_producer_settings
fill_in "variant-overrides-#{variant.id}-default_stock", with: ''
within "tr#v_#{variant.id}" do
vo.tag_list.each do |tag|
within "li.tag-item", text: "#{tag}" do
find("a.remove-button").click
end
end
end
page.uncheck "variant-overrides-#{variant.id}-resettable"
expect(page).to have_content "Changes to 2 overrides remain unsaved."
expect do
click_button 'Save Changes'
expect(page).to have_content "Changes saved."
end.to change { VariantOverride.count }.by(-2)
expect(VariantOverride.where(id: vo.id)).to be_empty
expect(VariantOverride.where(id: vo3.id)).to be_empty
end
it "resets stock to defaults" do
first("div#bulk-actions-dropdown").click
first("div#bulk-actions-dropdown div.menu div.menu_item",
text: "Reset Stock Levels To Defaults").click
expect(page).to have_content 'Stocks reset to defaults.'
vo.reload
expect(page).to have_input "variant-overrides-#{variant.id}-count_on_hand",
with: "1000", placeholder: ""
expect(vo.count_on_hand).to eq(1000)
end
it "doesn't reset stock levels if the behaviour is disabled" do
first("div#bulk-actions-dropdown").click
first("div#bulk-actions-dropdown div.menu div.menu_item",
text: "Reset Stock Levels To Defaults").click
vo_no_reset.reload
expect(page).to have_input "variant-overrides-#{variant2.id}-count_on_hand",
with: "40", placeholder: ""
expect(vo_no_reset.count_on_hand).to eq(40)
end
it "prompts to save changes before reset if any are pending" do
fill_in "variant-overrides-#{variant.id}-price", with: '200'
first("div#bulk-actions-dropdown").click
first("div#bulk-actions-dropdown div.menu div.menu_item",
text: "Reset Stock Levels To Defaults").click
expect(page).to have_content "Save changes first"
end
describe "ensuring that on demand and count on hand settings are compatible" do
it "clears count on hand when not limited stock" do
# It clears count_on_hand when selecting true on_demand.
select_on_demand variant, :no
fill_in "variant-overrides-#{variant.id}-count_on_hand", with: "200"
select_on_demand variant, :yes
expect(page).to have_input "variant-overrides-#{variant.id}-count_on_hand", with: ""
# It clears count_on_hand when selecting nil on_demand.
select_on_demand variant, :no
fill_in "variant-overrides-#{variant.id}-count_on_hand", with: "200"
select_on_demand variant, :use_producer_settings
expect(page).to have_input "variant-overrides-#{variant.id}-count_on_hand", with: ""
# It saves the changes.
click_button 'Save Changes'
expect(page).to have_content 'Changes saved.'
vo.reload
expect(vo.count_on_hand).to be_nil
expect(vo.on_demand).to be_nil
end
it "provides explanation when attempting to save variant override with incompatible " \
"stock settings" do
# Successfully change stock settings.
select_on_demand variant, :no
fill_in "variant-overrides-#{variant.id}-count_on_hand", with: "1111"
click_button 'Save Changes'
expect(page).to have_content 'Changes saved.'
# Make stock settings incompatible.
select_on_demand variant, :no
fill_in "variant-overrides-#{variant.id}-count_on_hand", with: ""
# It does not save the changes.
click_button 'Save Changes'
expect(page).to have_content 'must be specified because forcing limited stock'
expect(page).not_to have_content 'Changes saved.'
vo.reload
expect(vo.count_on_hand).to eq(1111)
expect(vo.on_demand).to eq(false)
end
end
end
end
end
describe "when manually placing an order" do
let!(:order_cycle) { create(:order_cycle_with_overrides, name: "Overidden") }
let(:distributor) { order_cycle.distributors.first }
let(:product) { order_cycle.products.first }
before do
login_as_admin
visit spree.new_admin_order_path
select2_select distributor.name, from: 'order_distributor_id'
select2_select order_cycle.name, from: 'order_order_cycle_id'
click_button 'Next'
click_link "Order Details"
end
# Reproducing a bug, issue #1446
it "shows the overridden price" do
select2_select product.name, from: 'add_variant_id', search: true
find('button.add_variant').click
expect(page).to have_selector("table.index tbody tr") # Wait for JS
expect(page).to have_content(product.variants.first.variant_overrides.first.price)
end
end
describe "when inventory_items do not exist for variants" do
let!(:product) {
create(:simple_product, supplier_id: producer.id, variant_unit: 'weight',
variant_unit_scale: 1)
}
let!(:variant1) {
create(:variant, product:, unit_value: 1, price: 1.23, on_hand: 12)
}
let!(:variant2) { create(:variant, product:, unit_value: 2, price: 4.56, on_hand: 3) }
context "when a hub is selected" do
before do
visit '/admin/inventory'
select2_select hub.name, from: 'hub_id'
end
it "alerts the user to the presence of new products, and allows them to be added " \
"or hidden" do
expect(page).not_to have_selector "table#variant-overrides tr#v_#{variant1.id}"
expect(page).not_to have_selector "table#variant-overrides tr#v_#{variant2.id}"
expect(page).to have_selector '.alert-row span.message',
text: "There are 1 new products available to add to your " \
"inventory."
click_button "Review Now"
expect(page).to have_table_row ['Producer', 'Product', 'Variant', 'Add', 'Hide']
expect(page).to have_selector "table#new-products tr#v_#{variant1.id}"
expect(page).to have_selector "table#new-products tr#v_#{variant2.id}"
within "table#new-products tr#v_#{variant1.id}" do
click_button 'Add'
end
within "table#new-products tr#v_#{variant2.id}" do
click_button 'Hide'
end
expect(page).not_to have_selector "table#new-products tr#v_#{variant1.id}"
expect(page).not_to have_selector "table#new-products tr#v_#{variant2.id}"
click_button "Back to my inventory"
expect(page).to have_selector "table#variant-overrides tr#v_#{variant1.id}"
expect(page).not_to have_selector "table#variant-overrides tr#v_#{variant2.id}"
first("div#views-dropdown").click
first("div#views-dropdown div.menu div.menu_item", text: "Hidden Products").click
expect(page).not_to have_selector "table#hidden-products tr#v_#{variant1.id}"
expect(page).to have_selector "table#hidden-products tr#v_#{variant2.id}"
end
end
end
end
context "as the manager of a farm shop" do
it "shows more than 100 products in my inventory" do
supplier = create(:supplier_enterprise, sells: "own")
inventory_items = (1..101).map do
product = create(:simple_product, supplier_id: supplier.id)
InventoryItem.create!(
enterprise: supplier,
variant: product.variants.first
)
end
first_variant = inventory_items.first.variant
last_variant = inventory_items.last.variant
first_variant.product.update!(name: "A First Product")
last_variant.product.update!(name: "Z Last Product")
login_as supplier.users.first
visit admin_inventory_path
expect(page).to have_text first_variant.name
expect(page).to have_text first_variant.supplier.name
expect(page).to have_selector "tr.product", count: 10
expect(page).to have_button "Show more"
expect(page).to have_button "Show all (91 More)"
click_button "Show all (91 More)"
expect(page).to have_selector "tr.product", count: 101
expect(page).to have_text last_variant.name
end
end
def select_on_demand(variant, value_sym)
option_label = I18n.t(value_sym, scope: "js.variant_overrides.on_demand")
select option_label, from: "variant-overrides-#{variant.id}-on_demand"
end
end