require 'rails_helper' module Spree RSpec.describe StockLocation, type: :model do subject { create(:stock_location_with_items, backorderable_default: true) } let(:stock_item) { subject.stock_items.order(:id).first } let(:variant) { stock_item.variant } it 'creates stock_items for all variants' do expect(subject.stock_items.count).to eq Variant.count end context "handling stock items" do let!(:variant) { create(:variant) } context "given a variant" do subject { StockLocation.create(name: "testing", propagate_all_variants: false) } context "set up" do it "creates stock item" do expect(subject).to receive(:propagate_variant) subject.set_up_stock_item(variant) end context "stock item exists" do let!(:stock_item) { subject.propagate_variant(variant) } it "returns existing stock item" do expect(subject.set_up_stock_item(variant)).to eq(stock_item) end end end context "propagate variants" do let(:stock_item) { subject.propagate_variant(variant) } it "creates a new stock item" do expect { subject.propagate_variant(variant) }.to change{ StockItem.count }.by(1) end context "passes backorderable default config" do context "true" do before { subject.backorderable_default = true } it { expect(stock_item.backorderable).to be true } end context "false" do before { subject.backorderable_default = false } it { expect(stock_item.backorderable).to be false } end end end context "propagate all variants" do subject { StockLocation.new(name: "testing") } context "true" do before { subject.propagate_all_variants = true } specify do expect(subject).to receive(:propagate_variant).at_least(:once) subject.save! end end context "false" do before { subject.propagate_all_variants = false } specify do expect(subject).not_to receive(:propagate_variant) subject.save! end end end end end it 'finds a stock_item for a variant' do stock_item = subject.stock_item(variant) expect(stock_item.count_on_hand).to eq 10 end it 'finds a stock_item for a variant by id' do stock_item = subject.stock_item(variant.id) expect(stock_item.variant).to eq variant end it 'returns nil when stock_item is not found for variant' do stock_item = subject.stock_item(0) expect(stock_item).to be_nil end describe '#stock_item_or_create' do before do variant = create(:variant) variant.stock_items.each(&:really_destroy!) variant.save end it 'creates a stock_item if not found for a variant' do stock_item = subject.stock_item_or_create(variant) expect(stock_item.variant).to eq variant end it 'creates a stock_item if not found for a variant_id' do stock_item = subject.stock_item_or_create(variant.id) expect(stock_item.variant).to eq variant end end it 'finds a count_on_hand for a variant' do expect(subject.count_on_hand(variant)).to eq 10 end it 'finds determines if you a variant is backorderable' do expect(subject.backorderable?(variant)).to be true end it 'restocks a variant with a positive stock movement' do originator = double expect(subject).to receive(:move).with(variant, 5, originator) subject.restock(variant, 5, originator) end it 'unstocks a variant with a negative stock movement' do originator = double expect(subject).to receive(:move).with(variant, -5, originator) subject.unstock(variant, 5, originator) end it 'it creates a stock_movement' do expect { subject.move variant, 5 }.to change { subject.stock_movements.where(stock_item_id: stock_item).count }.by(1) end it 'can be deactivated' do create(:stock_location, active: true) create(:stock_location, active: false) expect(Spree::StockLocation.active.count).to eq 1 end it 'ensures only one stock location is default at a time' do first = create(:stock_location, active: true, default: true) second = create(:stock_location, active: true, default: true) expect(first.reload.default).to eq false expect(second.reload.default).to eq true first.default = true first.save! expect(first.reload.default).to eq true expect(second.reload.default).to eq false end context 'fill_status' do it 'all on_hand with no backordered' do on_hand, backordered = subject.fill_status(variant, 5) expect(on_hand).to eq 5 expect(backordered).to eq 0 end it 'some on_hand with some backordered' do on_hand, backordered = subject.fill_status(variant, 20) expect(on_hand).to eq 10 expect(backordered).to eq 10 end it 'zero on_hand with all backordered' do stock_item.set_count_on_hand(0) on_hand, backordered = subject.fill_status(variant, 20) expect(on_hand).to eq 0 expect(backordered).to eq 20 end context 'when backordering is not allowed' do before do stock_item.update!(backorderable: false) end it 'all on_hand' do stock_item.set_count_on_hand(10) on_hand, backordered = subject.fill_status(variant, 5) expect(on_hand).to eq 5 expect(backordered).to eq 0 end it 'some on_hand' do stock_item.set_count_on_hand(10) on_hand, backordered = subject.fill_status(variant, 20) expect(on_hand).to eq 10 expect(backordered).to eq 0 end it 'zero on_hand' do stock_item.set_count_on_hand(0) on_hand, backordered = subject.fill_status(variant, 20) expect(on_hand).to eq 0 expect(backordered).to eq 0 end end context 'without stock_items' do subject { create(:stock_location) } let(:variant) { create(:base_variant) } it 'zero on_hand and backordered' do subject variant.stock_items.each(&:really_destroy!) on_hand, backordered = subject.fill_status(variant, 1) expect(on_hand).to eq 0 expect(backordered).to eq 0 end end context 'with soft-deleted stock_items' do subject { create(:stock_location) } let(:variant) { create(:base_variant) } it 'zero on_hand and backordered' do subject variant.stock_items.discard_all on_hand, backordered = subject.fill_status(variant, 1) expect(on_hand).to eq 0 expect(backordered).to eq 0 end end end context '#state_text' do context 'state is blank' do subject { StockLocation.create(name: "testing", state: nil, state_name: 'virginia') } specify { expect(subject.state_text).to eq('virginia') } end context 'both name and abbr is present' do let(:state) { stub_model(Spree::State, name: 'virginia', abbr: 'va') } subject { StockLocation.create(name: "testing", state: state, state_name: nil) } specify { expect(subject.state_text).to eq('va') } end context 'only name is present' do let(:state) { stub_model(Spree::State, name: 'virginia', abbr: nil) } subject { StockLocation.create(name: "testing", state: state, state_name: nil) } specify { expect(subject.state_text).to eq('virginia') } end end describe "#move" do let!(:variant) { create(:variant) } def move subject.move(variant, quantity) end context "no stock item exists" do before { subject.stock_items.each(&:really_destroy!) } context "positive movement" do let(:quantity) { 1 } it "creates a stock item" do expect { move }.to change { subject.stock_items.count }.by 1 end end # We should not be creating stock items that do not exist # for the sake of a negative movement. context "negative movement" do let(:quantity) { -1 } it "raises an error" do expect { expect { move }.to raise_error StockLocation::InvalidMovementError }.not_to change { subject.stock_items.count } end end end end end end