Skip to content
5 changes: 5 additions & 0 deletions app/models/purchase.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class Purchase < ApplicationRecord

validates :amount_spent_in_cents, numericality: { greater_than: 0 }
validate :total_equal_to_all_categories
validate :line_items_quantity_is_positive
before_destroy :check_no_intervening_snapshot

validates :amount_spent_on_diapers_cents, numericality: { greater_than_or_equal_to: 0 }
Expand Down Expand Up @@ -140,4 +141,8 @@ def check_no_intervening_snapshot
raise "We can't delete purchases entered before #{intervening.event_time.to_date}."
end
end

def line_items_quantity_is_positive
line_items_quantity_is_at_least(1)
end
end
14 changes: 14 additions & 0 deletions spec/models/purchase_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@
expect(d).not_to be_valid
end

it "is not valid if any line item has zero quantity" do
item = create(:item)
p = build(:purchase)
p.line_items.build(item_id: item.id, quantity: 0)
Comment thread
cassxw marked this conversation as resolved.
expect(p).not_to be_valid
end

it "is not valid if any line item has negative quantity" do
item = create(:item)
p = build(:purchase)
p.line_items.build(item_id: item.id, quantity: -1)
expect(p).not_to be_valid
end

it "is valid if all categories are positive and add up to the total" do
d = build(:purchase, amount_spent_in_cents: 1150,
amount_spent_on_diapers_cents: 200,
Expand Down
113 changes: 63 additions & 50 deletions spec/queries/low_inventory_query_spec.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
RSpec.describe LowInventoryQuery do
subject { LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys } }

let(:organization) { create :organization }
let(:storage_location) { create :storage_location, organization: organization }

let(:minimum_quantity) { 0 }
let(:recommended_quantity) { 0 }
let(:inventory_item_quantity) { 100 }
let(:current_quantity) { 100 }

let(:item) do
create :item,
Expand All @@ -15,101 +13,116 @@
on_hand_recommended_quantity: recommended_quantity
end

let!(:purchase) {
create :purchase,
:with_items,
organization: organization,
storage_location: storage_location,
item: item,
item_quantity: inventory_item_quantity,
issued_at: Time.current
}
before :each do
TestInventory.create_inventory(organization, {storage_location.id => {item.id => current_quantity}})
end

context "when minimum_quantity and recommended_quantity is nil" do
let(:item) { create :item, organization: organization }
context "when minimum_quantity and recommended_quantity are zero" do
let(:minimum_quantity) { 0 }
let(:recommended_quantity) { 0 }

it { is_expected.to eq [] }
it "should return an empty array" do
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
expect(result).to be_empty
end
end

context "when minimum_quantity is 0 and recommended_quantity is nil and item quantity is 0" do
let(:item) { create :item, organization: organization }
let(:minimum_quantity) { 0 }
let(:inventory_item_quantity) { 0 }
let(:current_quantity) { 0 }

it { is_expected.to eq [] }
it "should return an empty array" do
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
expect(result).to be_empty
end
end

context "when inventory quantity is over minimum quantity" do
let(:minimum_quantity) { 50 }
let(:current_quantity) { 100 }

it { is_expected.to eq [] }
it "should return an empty array" do
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
expect(result).to be_empty
end
end

context "when minimum_quantity is equal to quantity" do
let(:minimum_quantity) { 100 }
let(:current_quantity) { 100 }

it { is_expected.to eq [] }
it "should return an empty array" do
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
expect(result).to be_empty
end
end

context "when inventory quantity drops below minimum quantity" do
let(:minimum_quantity) { 200 }
let(:current_quantity) { 100 }

it {
is_expected.to include({
it "should include the item in the low inventory list" do
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
expect(result).to include({
id: item.id,
name: item.name,
on_hand_minimum_quantity: 200,
on_hand_recommended_quantity: 0,
total_quantity: 100
})
}
end
end

context "when inventory quantity equals recommended quantity" do
let(:minimum_quantity) { 50 }
let(:recommended_quantity) { 100 }
let(:current_quantity) { 100 }

it { is_expected.to eq [] }
it "should return an empty array" do
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
expect(result).to be_empty
end
end

context "when inventory quantity drops below recommended quantity" do
let(:minimum_quantity) { 50 }
let(:recommended_quantity) { 200 }
let(:current_quantity) { 75 }

it {
is_expected.to include({
it "should include the item in the low inventory list" do
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
expect(result).to include({
id: item.id,
name: item.name,
on_hand_minimum_quantity: 0,
on_hand_minimum_quantity: 50,
on_hand_recommended_quantity: 200,
total_quantity: 100
total_quantity: 75
})
}
end
end

context "when items are in multiple storage locations" do
let(:recommended_quantity) { 300 }
let(:minimum_quantity) { 50 }
let(:recommended_quantity) { 55 }
let(:current_quantity) { 40 }
let(:secondary_storage_location) { create :storage_location, organization: organization }
let!(:secondary_purchase) {
create :purchase,
:with_items,
organization: organization,
storage_location: secondary_storage_location,
item: item,
item_quantity: inventory_item_quantity,
issued_at: Time.current
}

it {
expect(subject.count).to eq 1
}

it {
is_expected.to include({

it "should have no low inventory items when global total is above minimum" do
TestInventory.create_inventory(organization, {secondary_storage_location.id => {item.id => 17}})
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
expect(result).to be_empty
end

it "should have no low inventory items when global total is below minimum" do
TestInventory.create_inventory(organization, {secondary_storage_location.id => {item.id => 2}})
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
expect(result).to include({
id: item.id,
name: item.name,
on_hand_minimum_quantity: 0,
on_hand_recommended_quantity: 300,
total_quantity: 200
on_hand_minimum_quantity: 50,
on_hand_recommended_quantity: 55,
total_quantity: 42
})
}
end
end
end
Loading