From 0e711832fdff9f91ac2e70b9c1038d60cb1961e8 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 04:13:21 +0800 Subject: [PATCH] Bring Spree::StockItem code from spree_core into the app --- app/models/spree/stock_item.rb | 52 +++++++++++++++++++ spec/models/spree/stock_item_spec.rb | 74 ++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 app/models/spree/stock_item.rb create mode 100644 spec/models/spree/stock_item_spec.rb diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb new file mode 100644 index 0000000000..9dc322b447 --- /dev/null +++ b/app/models/spree/stock_item.rb @@ -0,0 +1,52 @@ +module Spree + class StockItem < ActiveRecord::Base + belongs_to :stock_location, class_name: 'Spree::StockLocation' + belongs_to :variant, class_name: 'Spree::Variant' + has_many :stock_movements, dependent: :destroy + + validates_presence_of :stock_location, :variant + validates_uniqueness_of :variant_id, scope: :stock_location_id + + attr_accessible :count_on_hand, :variant, :stock_location, :backorderable, :variant_id + + delegate :weight, to: :variant + + def backordered_inventory_units + Spree::InventoryUnit.backordered_for_stock_item(self) + end + + def variant_name + variant.name + end + + def adjust_count_on_hand(value) + self.with_lock do + self.count_on_hand = self.count_on_hand + value + process_backorders if in_stock? + + self.save! + end + end + + def in_stock? + self.count_on_hand > 0 + end + + # Tells whether it's available to be included in a shipment + def available? + self.in_stock? || self.backorderable? + end + + private + def count_on_hand=(value) + write_attribute(:count_on_hand, value) + end + + def process_backorders + backordered_inventory_units.each do |unit| + return unless in_stock? + unit.fill_backorder + end + end + end +end diff --git a/spec/models/spree/stock_item_spec.rb b/spec/models/spree/stock_item_spec.rb new file mode 100644 index 0000000000..da10d44efa --- /dev/null +++ b/spec/models/spree/stock_item_spec.rb @@ -0,0 +1,74 @@ +require 'spec_helper' + +describe Spree::StockItem do + let(:stock_location) { create(:stock_location_with_items) } + + subject { stock_location.stock_items.order(:id).first } + + it 'maintains the count on hand for a variant' do + subject.count_on_hand.should eq 10 + end + + it "can return the stock item's variant's name" do + subject.variant_name.should == subject.variant.name + end + + context "available to be included in shipment" do + context "has stock" do + it { subject.should be_available } + end + + context "backorderable" do + before { subject.backorderable = true } + it { subject.should be_available } + end + + context "no stock and not backorderable" do + before do + subject.backorderable = false + subject.stub(count_on_hand: 0) + end + + it { subject.should_not be_available } + end + end + + context "adjust count_on_hand" do + let!(:current_on_hand) { subject.count_on_hand } + + it 'is updated pessimistically' do + copy = Spree::StockItem.find(subject.id) + + subject.adjust_count_on_hand(5) + subject.count_on_hand.should eq(current_on_hand + 5) + + copy.count_on_hand.should eq(current_on_hand) + copy.adjust_count_on_hand(5) + copy.count_on_hand.should eq(current_on_hand + 10) + end + + context "item out of stock (by two items)" do + let(:inventory_unit) { double('InventoryUnit') } + let(:inventory_unit_2) { double('InventoryUnit2') } + + before { subject.adjust_count_on_hand(- (current_on_hand + 2)) } + + it "doesn't process backorders" do + subject.should_not_receive(:backordered_inventory_units) + subject.adjust_count_on_hand(1) + end + + context "adds new items" do + before { subject.stub(:backordered_inventory_units => [inventory_unit, inventory_unit_2]) } + + it "fills existing backorders" do + inventory_unit.should_receive(:fill_backorder) + inventory_unit_2.should_receive(:fill_backorder) + + subject.adjust_count_on_hand(3) + subject.count_on_hand.should == 1 + end + end + end + end +end