diff --git a/app/services/default_stock_location.rb b/app/services/default_stock_location.rb new file mode 100644 index 0000000000..9269f17743 --- /dev/null +++ b/app/services/default_stock_location.rb @@ -0,0 +1,19 @@ +# Encapsulates the concept of default stock location that OFN has, as explained +# in https://github.com/openfoodfoundation/openfoodnetwork/wiki/Spree-Upgrade%3A-Stock-locations +class DefaultStockLocation + NAME = 'default'.freeze + + def self.create! + country = Spree::Country.find_by_iso(ENV['DEFAULT_COUNTRY_CODE']) + state = country.states.first + Spree::StockLocation.create!(name: NAME, country_id: country.id, state_id: state.id) + end + + def self.destroy_all + Spree::StockLocation.where(name: NAME).destroy_all + end + + def self.find_or_create + Spree::StockLocation.find_or_create_by_name(NAME) + end +end diff --git a/db/migrate/20180906094641_add_uniqueness_of_variant_id_to_spree_stock_items.rb b/db/migrate/20180906094641_add_uniqueness_of_variant_id_to_spree_stock_items.rb index bc7713f428..93b2853208 100644 --- a/db/migrate/20180906094641_add_uniqueness_of_variant_id_to_spree_stock_items.rb +++ b/db/migrate/20180906094641_add_uniqueness_of_variant_id_to_spree_stock_items.rb @@ -1,3 +1,6 @@ +# Since OFN has only a single default StockLocation, variants in OFN can only +# have a stock item. By adding this unique index we constraint that at DB level +# ensuring data integrity. class AddUniquenessOfVariantIdToSpreeStockItems < ActiveRecord::Migration def change add_index :spree_stock_items, :variant_id, unique: true diff --git a/db/seeds.rb b/db/seeds.rb index 17e5bf91b7..9f0868cb6b 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -50,3 +50,5 @@ end spree_user = Spree::User.first spree_user && spree_user.confirm! + +DefaultStockLocation.create! diff --git a/spec/factories.rb b/spec/factories.rb index 58273f7cb5..742f943ed7 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -657,7 +657,10 @@ end FactoryBot.modify do factory :stock_location, class: Spree::StockLocation do # keeps the test stock_location unique - initialize_with { Spree::StockLocation.find_or_create_by_name(name)} + initialize_with { DefaultStockLocation.find_or_create } + + # Ensures the name attribute is not assigned after instantiating the default location + transient { name 'default' } end factory :shipment, class: Spree::Shipment do diff --git a/spec/models/concerns/variant_stock_spec.rb b/spec/models/concerns/variant_stock_spec.rb index 36fc33df24..2943b7575b 100644 --- a/spec/models/concerns/variant_stock_spec.rb +++ b/spec/models/concerns/variant_stock_spec.rb @@ -141,21 +141,6 @@ describe VariantStock do end describe '#on_demand=' do - context 'when the variant has multiple stock items' do - let(:variant) { create(:variant) } - - before do - # Spree creates a stock_item for each variant when creating a stock - # location by means of #propagate_variant - create(:stock_location, name: 'location') - create(:stock_location, name: 'another location') - end - - it 'raises' do - expect { variant.on_demand = true }.to raise_error(StandardError) - end - end - context 'when the variant has a stock item' do let(:variant) { create(:variant, on_demand: true) } diff --git a/spec/services/default_stock_location_spec.rb b/spec/services/default_stock_location_spec.rb new file mode 100644 index 0000000000..8d91d7da83 --- /dev/null +++ b/spec/services/default_stock_location_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe DefaultStockLocation do + describe '.create!' do + it "names the location 'OFN default'" do + stock_location = described_class.create! + expect(stock_location.name).to eq('default') + end + + it 'sets the location in the default country' do + default_country = Spree::Country.find_by_iso(ENV['DEFAULT_COUNTRY_CODE']) + stock_location = described_class.create! + expect(stock_location.country).to eq(default_country) + end + + it 'sets the first state in the country' do + default_country = Spree::Country.find_by_iso(ENV['DEFAULT_COUNTRY_CODE']) + stock_location = described_class.create! + expect(stock_location.state).to eq(default_country.states.first) + end + end + + describe '.destroy_all' do + it "removes all stock locations named 'default'" do + create(:stock_location, name: 'default') + + expect { described_class.destroy_all } + .to change { Spree::StockLocation.count }.to(0) + end + end + + describe '.find_or_create' do + context 'when a location named default already exists' do + let!(:location) do + country = create(:country) + state = create(:state, country: country) + Spree::StockLocation.create!( + name: 'default', + country_id: country.id, + state_id: state.id + ) + end + + it 'returns the location' do + expect(described_class.find_or_create).to eq(location) + end + + it 'does not create any other location' do + expect { described_class.find_or_create }.not_to change(Spree::StockLocation, :count) + end + end + + context 'when a location named default does not exist' do + it 'returns the location' do + location = described_class.find_or_create + expect(location.name).to eq('default') + end + + it 'does not create any other location' do + expect { described_class.find_or_create } + .to change(Spree::StockLocation, :count).from(0).to(1) + end + end + end +end