diff --git a/app/services/variants_stock_levels.rb b/app/services/variants_stock_levels.rb index 69dbc49dee..73f6e68278 100644 --- a/app/services/variants_stock_levels.rb +++ b/app/services/variants_stock_levels.rb @@ -1,45 +1,46 @@ # Report the stock levels of: # - all variants in the order # - all requested variant ids +require 'open_food_network/scope_variant_to_hub' + class VariantsStockLevels def call(order, requested_variant_ids) variant_stock_levels = variant_stock_levels(order.line_items) - # Variants are not scoped here and so the stock levels reported are incorrect - # See cart_controller_spec for more details and #3222 order_variant_ids = variant_stock_levels.keys missing_variant_ids = requested_variant_ids - order_variant_ids missing_variant_ids.each do |variant_id| - variant = Spree::Variant.find(variant_id) + variant = scoped_variant(order.distributor, Spree::Variant.find(variant_id)) variant_stock_levels[variant_id] = { quantity: 0, max_quantity: 0, on_hand: variant.on_hand, on_demand: variant.on_demand } end - # The code above is most probably dead code, this bugsnag notification will confirm it - notify_bugsnag(order, requested_variant_ids, order_variant_ids) if missing_variant_ids.present? - variant_stock_levels end private - def notify_bugsnag(order, requested_variant_ids, order_variant_ids) - error_msg = "VariantsStockLevels.call with variants in the request that are not in the order" - Bugsnag.notify(RuntimeError.new(error_msg), - requested_variant_ids: requested_variant_ids.as_json, - order_variant_ids: order_variant_ids.as_json, - order: order.as_json, - line_items: order.line_items.as_json) - end - def variant_stock_levels(line_items) Hash[ line_items.map do |line_item| - [line_item.variant.id, + variant = scoped_variant(line_item.order.distributor, line_item.variant) + + [variant.id, { quantity: line_item.quantity, max_quantity: line_item.max_quantity, - on_hand: line_item.variant.on_hand, - on_demand: line_item.variant.on_demand }] + on_hand: variant.on_hand, + on_demand: variant.on_demand }] end ] end + + def scoped_variant(distributor, variant) + return variant if distributor.blank? + + scoper(distributor).scope(variant) + variant + end + + def scoper(distributor) + @scoper ||= OpenFoodNetwork::ScopeVariantToHub.new(distributor) + end end diff --git a/spec/services/variants_stock_levels_spec.rb b/spec/services/variants_stock_levels_spec.rb index f4a77d7018..5977845665 100644 --- a/spec/services/variants_stock_levels_spec.rb +++ b/spec/services/variants_stock_levels_spec.rb @@ -48,4 +48,53 @@ describe VariantsStockLevels do ) end end + + describe "when the variant has an override" do + let!(:distributor) { create(:distributor_enterprise) } + let(:supplier) { variant_in_the_order.product.supplier } + let!(:order_cycle) { + create(:simple_order_cycle, suppliers: [supplier], distributors: [distributor], + variants: [variant_in_the_order, variant_not_in_the_order]) + } + let!(:variant_override_in_order) { + create(:variant_override, hub: distributor, + variant: variant_in_the_order, + count_on_hand: 200) + } + let!(:variant_override_not_in_order) { + create(:variant_override, hub: distributor, + variant: variant_not_in_the_order, + count_on_hand: 201) + } + + before do + order.order_cycle = order_cycle + order.distributor = distributor + order.save + end + + context "when the variant is in the order" do + it "returns the on_hand value of the override" do + expect(variant_stock_levels.call(order, [variant_in_the_order.id])).to eq( + variant_in_the_order.id => { + quantity: 2, max_quantity: 3, on_hand: 200, on_demand: false + } + ) + end + end + + context "with variants that are not in the order" do + it "returns the on_hand value of the override" do + variant_ids = [variant_in_the_order.id, variant_not_in_the_order.id] + expect(variant_stock_levels.call(order, variant_ids)).to eq( + variant_in_the_order.id => { + quantity: 2, max_quantity: 3, on_hand: 200, on_demand: false + }, + variant_not_in_the_order.id => { + quantity: 0, max_quantity: 0, on_hand: 201, on_demand: false + } + ) + end + end + end end