Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions core/app/models/spree/stock_movement.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module Spree
class StockMovement < Spree::Base
QUANTITY_LIMITS = {
max: 2**31 - 1,
min: -2**31
}.freeze

belongs_to :stock_item, class_name: 'Spree::StockItem', inverse_of: :stock_movements
belongs_to :originator, polymorphic: true

Expand All @@ -8,19 +13,19 @@ class StockMovement < Spree::Base
with_options presence: true do
validates :stock_item
validates :quantity, numericality: {
greater_than_or_equal_to: -2**31,
less_than_or_equal_to: 2**31 - 1,
only_integer: true,
allow_nil: true
}
greater_than_or_equal_to: QUANTITY_LIMITS[:min],
less_than_or_equal_to: QUANTITY_LIMITS[:max],
only_integer: true,
allow_nil: true
}
end

scope :recent, -> { order(created_at: :desc) }

self.whitelisted_ransackable_attributes = ['quantity']

def readonly?
!new_record?
persisted?
end

private
Expand Down
136 changes: 100 additions & 36 deletions core/spec/models/spree/stock_movement_spec.rb
Original file line number Diff line number Diff line change
@@ -1,55 +1,119 @@
require 'spec_helper'

describe Spree::StockMovement, :type => :model do
let(:stock_location) { create(:stock_location_with_items) }
let(:stock_item) { stock_location.stock_items.order(:id).first }
subject { build(:stock_movement, stock_item: stock_item) }

it 'should belong to a stock item' do
expect(subject).to respond_to(:stock_item)
describe 'Constants' do
describe 'QUANTITY_LIMITS[:max]' do
it 'return 2**31 - 1' do
expect(Spree::StockMovement::QUANTITY_LIMITS[:max]).to eq(2**31 - 1)
end
end

describe 'QUANTITY_LIMITS[:min]' do
it 'return -2**31' do
expect(Spree::StockMovement::QUANTITY_LIMITS[:min]).to eq(-2**31)
end
end
end

it 'is readonly unless new' do
subject.save
expect {
subject.save
}.to raise_error(ActiveRecord::ReadOnlyRecord)
describe 'Associations' do
it { is_expected.to belong_to(:stock_item).class_name('Spree::StockItem').inverse_of(:stock_movements) }
it { is_expected.to belong_to(:originator) }
end

it 'does not update count on hand when track inventory levels is false' do
Spree::Config[:track_inventory_levels] = false
subject.quantity = 1
subject.save
stock_item.reload
expect(stock_item.count_on_hand).to eq(10)
describe 'Validations' do
it do
is_expected.to validate_presence_of(:stock_item)
end

it do
is_expected.to validate_presence_of(:quantity)
end

it do
is_expected.to validate_numericality_of(:quantity).
is_greater_than_or_equal_to(Spree::StockMovement::QUANTITY_LIMITS[:min]).
is_less_than_or_equal_to(Spree::StockMovement::QUANTITY_LIMITS[:max]).only_integer.allow_nil
end
end

it 'does not update count on hand when variant inventory tracking is off' do
stock_item.variant.track_inventory = false
subject.quantity = 1
subject.save
stock_item.reload
expect(stock_item.count_on_hand).to eq(10)
describe 'Callbacks' do
it { is_expected.to callback(:update_stock_item_quantity).after(:create) }
end

context "when quantity is negative" do
context "after save" do
it "should decrement the stock item count on hand" do
subject.quantity = -1
subject.save
stock_item.reload
expect(stock_item.count_on_hand).to eq(9)
describe 'Scope' do
describe '.recent' do
it 'should order chronologically by created at' do
expect(Spree::StockMovement.recent.to_sql).
to eq Spree::StockMovement.unscoped.order(created_at: :desc).to_sql
end
end
end

context "when quantity is positive" do
context "after save" do
it "should increment the stock item count on hand" do
subject.quantity = 1
subject.save
stock_item.reload
expect(stock_item.count_on_hand).to eq(11)
describe 'whitelisted ransackable attributes' do
it 'returns amount attribute' do
expect(Spree::StockMovement.whitelisted_ransackable_attributes).to eq(['quantity'])
end
end

describe 'Insatance Methods' do
let(:stock_location) { create(:stock_location_with_items) }
let(:stock_item) { stock_location.stock_items.order(:id).first }

describe '#readonly?' do
let(:stock_movement) { create(:stock_movement, stock_item: stock_item) }
it 'should not update a persisted record' do
expect { stock_movement.save }.to raise_error(ActiveRecord::ReadOnlyRecord)
end
end

describe '#update_stock_item_quantity' do
let(:stock_movement) { build(:stock_movement, stock_item: stock_item) }

context 'when track inventory levels is false' do
before do
Spree::Config[:track_inventory_levels] = false
stock_movement.quantity = 1
stock_movement.save
stock_item.reload
end
it 'does not update count on hand' do
expect(stock_item.count_on_hand).to eq(10)
end
end

context 'when track inventory tracking is off' do
before do
stock_item.variant.track_inventory = false
stock_movement.quantity = 1
stock_movement.save
stock_item.reload
end
it 'does not update count on hand' do
expect(stock_item.count_on_hand).to eq(10)
end
end

context 'when quantity is negative' do
before do
stock_movement.quantity = -1
stock_movement.save
stock_item.reload
end
it 'should decrement the stock item count on hand' do
expect(stock_item.count_on_hand).to eq(9)
end
end

context "when quantity is positive" do
before do
stock_movement.quantity = 1
stock_movement.save
stock_item.reload
end
it "should increment the stock item count on hand" do
expect(stock_item.count_on_hand).to eq(11)
end
end
end
end
Expand Down