diff --git a/app/models/spree/variant_decorator.rb b/app/models/spree/variant_decorator.rb index 2947efc282..3a97048c7c 100644 --- a/app/models/spree/variant_decorator.rb +++ b/app/models/spree/variant_decorator.rb @@ -1,5 +1,6 @@ require 'open_food_network/enterprise_fee_calculator' require 'open_food_network/variant_and_line_item_naming' +require 'open_food_network/variant_stock' require 'open_food_network/products_cache' Spree::Variant.class_eval do @@ -9,6 +10,7 @@ Spree::Variant.class_eval do # removing the Spree method to prevent error. remove_method :options_text if instance_methods(false).include? :options_text include OpenFoodNetwork::VariantAndLineItemNaming + include OpenFoodNetwork::VariantStock has_many :exchange_variants has_many :exchanges, through: :exchange_variants diff --git a/lib/open_food_network/variant_stock.rb b/lib/open_food_network/variant_stock.rb new file mode 100644 index 0000000000..fba38ebd57 --- /dev/null +++ b/lib/open_food_network/variant_stock.rb @@ -0,0 +1,80 @@ +require 'active_support/concern' + +# These methods were available in Spree 1, but were removed in Spree 2. +# We would still like to use them. Therefore we use only a single stock location +# (default stock location) and use it to track the `count_on_hand` value that +# was previously a database column on variants. +# +# We may decide to deprecate these methods after we designed the Network feature. +module OpenFoodNetwork + module VariantStock + extend ActiveSupport::Concern + + included do + after_save :save_stock + end + + def on_hand + if on_demand + Float::INFINITY + else + total_on_hand + end + end + + def count_on_hand + total_on_hand + end + + def on_hand=(new_level) + error = 'Cannot set on_hand value when Spree::Config[:track_inventory_levels] is false' + raise error unless Spree::Config.track_inventory_levels + + self.count_on_hand = new_level + end + + def count_on_hand=(new_level) + raise_error_if_no_stock_item_available + overwrite_stock_levels new_level + end + + def on_demand + stock_items.any?(&:backorderable?) + end + + def on_demand=(new_value) + raise_error_if_no_stock_item_available + + # There should be only one at the default stock location. + stock_items.each do |item| + item.backorderable = new_value + end + end + + private + + def save_stock + stock_items.each(&:save) + end + + def raise_error_if_no_stock_item_available + message = 'You need to save the variant to create a stock item before you can set stock levels.' + raise message if stock_items.empty? + end + + # Backwards compatible setting of stock levels in Spree 2.0. + # It would be better to use `Spree::StockItem.adjust_count_on_hand` which + # takes a value to add to the current stock level and uses proper locking. + # But this should work the same as in Spree 1.3. + def overwrite_stock_levels(new_level) + stock_items.first.send :count_on_hand=, new_level + + # There shouldn't be any other stock items, because we should have only one + # stock location. But in case there are, the total should be new_level, + # so all others need to be zero. + stock_items[1..-1].each do |item| + item.send :count_on_hand=, 0 + end + end + end +end diff --git a/spec/controllers/spree/orders_controller_spec.rb b/spec/controllers/spree/orders_controller_spec.rb index fbcd5ec107..4d96ae051c 100644 --- a/spec/controllers/spree/orders_controller_spec.rb +++ b/spec/controllers/spree/orders_controller_spec.rb @@ -82,8 +82,8 @@ describe Spree::OrdersController, type: :controller do describe "generating stock levels" do let!(:order) { create(:order) } let!(:li) { create(:line_item, order: order, variant: v, quantity: 2, max_quantity: 3) } - let!(:v) { create(:variant, count_on_hand: 4) } - let!(:v2) { create(:variant, count_on_hand: 2) } + let!(:v) { create(:variant, on_hand: 4) } + let!(:v2) { create(:variant, on_hand: 2) } before do order.reload @@ -107,7 +107,7 @@ describe Spree::OrdersController, type: :controller do end describe "encoding Infinity" do - let!(:v) { create(:variant, on_demand: true, count_on_hand: 0) } + let!(:v) { create(:variant, on_demand: true, on_hand: 0) } it "encodes Infinity as a large, finite integer" do controller.stock_levels(order, [v.id]).should == diff --git a/spec/factories.rb b/spec/factories.rb index f8f66b699a..c405e09c9a 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -459,7 +459,17 @@ FactoryBot.define do end factory :simple_product, parent: :base_product do - on_hand 5 + transient do + on_demand { false } + on_hand { 5 } + end + after(:create) do |product, evaluator| + product.variants.first.tap do |variant| + variant.on_demand = evaluator.on_demand + variant.count_on_hand = evaluator.on_hand + variant.save + end + end end end @@ -487,8 +497,19 @@ FactoryBot.modify do end factory :variant do + transient do + on_demand { false } + on_hand { 5 } + end + unit_value 1 unit_description '' + + after(:create) do |variant, evaluator| + variant.on_demand = evaluator.on_demand + variant.count_on_hand = evaluator.on_hand + variant.save + end end factory :shipping_method do diff --git a/spec/jobs/subscription_placement_job_spec.rb b/spec/jobs/subscription_placement_job_spec.rb index b1013081d6..453b155962 100644 --- a/spec/jobs/subscription_placement_job_spec.rb +++ b/spec/jobs/subscription_placement_job_spec.rb @@ -64,9 +64,9 @@ describe SubscriptionPlacementJob do let(:shop) { order_cycle.coordinator } let(:order) { create(:order, order_cycle: order_cycle, distributor: shop) } let(:ex) { create(:exchange, :order_cycle => order_cycle, :sender => shop, :receiver => shop, :incoming => false) } - let(:variant1) { create(:variant, count_on_hand: 5) } - let(:variant2) { create(:variant, count_on_hand: 5) } - let(:variant3) { create(:variant, count_on_hand: 5) } + let(:variant1) { create(:variant, on_hand: 5) } + let(:variant2) { create(:variant, on_hand: 5) } + let(:variant3) { create(:variant, on_hand: 5) } let!(:line_item1) { create(:line_item, order: order, variant: variant1, quantity: 3) } let!(:line_item2) { create(:line_item, order: order, variant: variant2, quantity: 3) } let!(:line_item3) { create(:line_item, order: order, variant: variant3, quantity: 3) } diff --git a/spec/lib/open_food_network/lettuce_share_report_spec.rb b/spec/lib/open_food_network/lettuce_share_report_spec.rb index 5a871cfbbb..99a9254abd 100644 --- a/spec/lib/open_food_network/lettuce_share_report_spec.rb +++ b/spec/lib/open_food_network/lettuce_share_report_spec.rb @@ -36,7 +36,7 @@ module OpenFoodNetwork describe "lists" do let(:v2) { create(:variant) } let(:v3) { create(:variant) } - let(:v4) { create(:variant, count_on_hand: 0, on_demand: true) } + let(:v4) { create(:variant, on_hand: 0, on_demand: true) } let(:hub_address) { create(:address, :address1 => "distributor address", :city => 'The Shire', :zipcode => "1234") } let(:hub) { create(:distributor_enterprise, :address => hub_address) } let(:v2o) { create(:variant_override, hub: hub, variant: v2) } diff --git a/spec/lib/open_food_network/scope_variant_to_hub_spec.rb b/spec/lib/open_food_network/scope_variant_to_hub_spec.rb index c3b2f2f8ec..ac79d943ac 100644 --- a/spec/lib/open_food_network/scope_variant_to_hub_spec.rb +++ b/spec/lib/open_food_network/scope_variant_to_hub_spec.rb @@ -3,7 +3,7 @@ require 'open_food_network/scope_variant_to_hub' module OpenFoodNetwork describe ScopeVariantToHub do let(:hub) { create(:distributor_enterprise) } - let(:v) { create(:variant, price: 11.11, count_on_hand: 1, on_demand: true, sku: "VARIANTSKU") } + let(:v) { create(:variant, price: 11.11, on_hand: 1, on_demand: true, sku: "VARIANTSKU") } let(:vo) { create(:variant_override, hub: hub, variant: v, price: 22.22, count_on_hand: 2, on_demand: false, sku: "VOSKU") } let(:vo_price_only) { create(:variant_override, hub: hub, variant: v, price: 22.22, count_on_hand: nil) } let(:scoper) { ScopeVariantToHub.new(hub) } diff --git a/spec/models/variant_override_spec.rb b/spec/models/variant_override_spec.rb index 0a07fdd1af..8275e82013 100644 --- a/spec/models/variant_override_spec.rb +++ b/spec/models/variant_override_spec.rb @@ -59,7 +59,7 @@ describe VariantOverride do describe "looking up count on hand" do it "returns the numeric stock level when present" do - VariantOverride.create!(variant: variant, hub: hub, count_on_hand: 12) + VariantOverride.create!(variant: variant, hub: hub, on_hand: 12) VariantOverride.count_on_hand_for(hub, variant).should == 12 end diff --git a/spec/services/subscription_form_spec.rb b/spec/services/subscription_form_spec.rb index 2f4a19953e..3e2e8f5842 100644 --- a/spec/services/subscription_form_spec.rb +++ b/spec/services/subscription_form_spec.rb @@ -7,7 +7,7 @@ describe SubscriptionForm do let!(:product3) { create(:product, supplier: shop) } let!(:variant1) { create(:variant, product: product1, unit_value: '100', price: 12.00, option_values: []) } let!(:variant2) { create(:variant, product: product2, unit_value: '1000', price: 6.00, option_values: []) } - let!(:variant3) { create(:variant, product: product2, unit_value: '1000', price: 2.50, option_values: [], count_on_hand: 1) } + let!(:variant3) { create(:variant, product: product2, unit_value: '1000', price: 2.50, option_values: [], on_hand: 1) } let!(:enterprise_fee) { create(:enterprise_fee, amount: 1.75) } let!(:order_cycle1) { create(:simple_order_cycle, coordinator: shop, orders_open_at: 9.days.ago, orders_close_at: 2.days.ago) } let!(:order_cycle2) { create(:simple_order_cycle, coordinator: shop, orders_open_at: 2.days.ago, orders_close_at: 5.days.from_now) }