Skip to content

Commit e182893

Browse files
Merge pull request #5510 from cassxw/5507-disallow-purchase-zero-quantity
Disallow saving Purchase with a quantity of 0 (5507)
2 parents 2ef7f3d + 3d03560 commit e182893

File tree

3 files changed

+82
-50
lines changed

3 files changed

+82
-50
lines changed

app/models/purchase.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class Purchase < ApplicationRecord
5959

6060
validates :amount_spent_in_cents, numericality: { greater_than: 0 }
6161
validate :total_equal_to_all_categories
62+
validate :line_items_quantity_is_positive
6263
before_destroy :check_no_intervening_snapshot
6364

6465
validates :amount_spent_on_diapers_cents, numericality: { greater_than_or_equal_to: 0 }
@@ -140,4 +141,8 @@ def check_no_intervening_snapshot
140141
raise "We can't delete purchases entered before #{intervening.event_time.to_date}."
141142
end
142143
end
144+
145+
def line_items_quantity_is_positive
146+
line_items_quantity_is_at_least(1)
147+
end
143148
end

spec/models/purchase_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@
6565
expect(d).not_to be_valid
6666
end
6767

68+
it "is not valid if any line item has zero quantity" do
69+
item = create(:item)
70+
p = build(:purchase)
71+
p.line_items.build(item_id: item.id, quantity: 0)
72+
expect(p).not_to be_valid
73+
end
74+
75+
it "is not valid if any line item has negative quantity" do
76+
item = create(:item)
77+
p = build(:purchase)
78+
p.line_items.build(item_id: item.id, quantity: -1)
79+
expect(p).not_to be_valid
80+
end
81+
6882
it "is valid if all categories are positive and add up to the total" do
6983
d = build(:purchase, amount_spent_in_cents: 1150,
7084
amount_spent_on_diapers_cents: 200,
Lines changed: 63 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
RSpec.describe LowInventoryQuery do
2-
subject { LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys } }
3-
42
let(:organization) { create :organization }
53
let(:storage_location) { create :storage_location, organization: organization }
64

75
let(:minimum_quantity) { 0 }
86
let(:recommended_quantity) { 0 }
9-
let(:inventory_item_quantity) { 100 }
7+
let(:current_quantity) { 100 }
108

119
let(:item) do
1210
create :item,
@@ -15,101 +13,116 @@
1513
on_hand_recommended_quantity: recommended_quantity
1614
end
1715

18-
let!(:purchase) {
19-
create :purchase,
20-
:with_items,
21-
organization: organization,
22-
storage_location: storage_location,
23-
item: item,
24-
item_quantity: inventory_item_quantity,
25-
issued_at: Time.current
26-
}
16+
before :each do
17+
TestInventory.create_inventory(organization, {storage_location.id => {item.id => current_quantity}})
18+
end
2719

28-
context "when minimum_quantity and recommended_quantity is nil" do
29-
let(:item) { create :item, organization: organization }
20+
context "when minimum_quantity and recommended_quantity are zero" do
21+
let(:minimum_quantity) { 0 }
22+
let(:recommended_quantity) { 0 }
3023

31-
it { is_expected.to eq [] }
24+
it "should return an empty array" do
25+
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
26+
expect(result).to be_empty
27+
end
3228
end
3329

3430
context "when minimum_quantity is 0 and recommended_quantity is nil and item quantity is 0" do
35-
let(:item) { create :item, organization: organization }
3631
let(:minimum_quantity) { 0 }
37-
let(:inventory_item_quantity) { 0 }
32+
let(:current_quantity) { 0 }
3833

39-
it { is_expected.to eq [] }
34+
it "should return an empty array" do
35+
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
36+
expect(result).to be_empty
37+
end
4038
end
4139

4240
context "when inventory quantity is over minimum quantity" do
4341
let(:minimum_quantity) { 50 }
42+
let(:current_quantity) { 100 }
4443

45-
it { is_expected.to eq [] }
44+
it "should return an empty array" do
45+
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
46+
expect(result).to be_empty
47+
end
4648
end
4749

4850
context "when minimum_quantity is equal to quantity" do
4951
let(:minimum_quantity) { 100 }
52+
let(:current_quantity) { 100 }
5053

51-
it { is_expected.to eq [] }
54+
it "should return an empty array" do
55+
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
56+
expect(result).to be_empty
57+
end
5258
end
5359

5460
context "when inventory quantity drops below minimum quantity" do
5561
let(:minimum_quantity) { 200 }
62+
let(:current_quantity) { 100 }
5663

57-
it {
58-
is_expected.to include({
64+
it "should include the item in the low inventory list" do
65+
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
66+
expect(result).to include({
5967
id: item.id,
6068
name: item.name,
6169
on_hand_minimum_quantity: 200,
6270
on_hand_recommended_quantity: 0,
6371
total_quantity: 100
6472
})
65-
}
73+
end
6674
end
6775

6876
context "when inventory quantity equals recommended quantity" do
77+
let(:minimum_quantity) { 50 }
6978
let(:recommended_quantity) { 100 }
79+
let(:current_quantity) { 100 }
7080

71-
it { is_expected.to eq [] }
81+
it "should return an empty array" do
82+
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
83+
expect(result).to be_empty
84+
end
7285
end
7386

7487
context "when inventory quantity drops below recommended quantity" do
88+
let(:minimum_quantity) { 50 }
7589
let(:recommended_quantity) { 200 }
90+
let(:current_quantity) { 75 }
7691

77-
it {
78-
is_expected.to include({
92+
it "should include the item in the low inventory list" do
93+
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
94+
expect(result).to include({
7995
id: item.id,
8096
name: item.name,
81-
on_hand_minimum_quantity: 0,
97+
on_hand_minimum_quantity: 50,
8298
on_hand_recommended_quantity: 200,
83-
total_quantity: 100
99+
total_quantity: 75
84100
})
85-
}
101+
end
86102
end
87103

88104
context "when items are in multiple storage locations" do
89-
let(:recommended_quantity) { 300 }
105+
let(:minimum_quantity) { 50 }
106+
let(:recommended_quantity) { 55 }
107+
let(:current_quantity) { 40 }
90108
let(:secondary_storage_location) { create :storage_location, organization: organization }
91-
let!(:secondary_purchase) {
92-
create :purchase,
93-
:with_items,
94-
organization: organization,
95-
storage_location: secondary_storage_location,
96-
item: item,
97-
item_quantity: inventory_item_quantity,
98-
issued_at: Time.current
99-
}
100-
101-
it {
102-
expect(subject.count).to eq 1
103-
}
104-
105-
it {
106-
is_expected.to include({
109+
110+
it "should have no low inventory items when global total is above minimum" do
111+
TestInventory.create_inventory(organization, {secondary_storage_location.id => {item.id => 17}})
112+
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
113+
expect(result).to be_empty
114+
end
115+
116+
it "should have no low inventory items when global total is below minimum" do
117+
TestInventory.create_inventory(organization, {secondary_storage_location.id => {item.id => 2}})
118+
result = LowInventoryQuery.call(organization).map { |r| r.to_h.symbolize_keys }
119+
expect(result).to include({
107120
id: item.id,
108121
name: item.name,
109-
on_hand_minimum_quantity: 0,
110-
on_hand_recommended_quantity: 300,
111-
total_quantity: 200
122+
on_hand_minimum_quantity: 50,
123+
on_hand_recommended_quantity: 55,
124+
total_quantity: 42
112125
})
113-
}
126+
end
114127
end
115128
end

0 commit comments

Comments
 (0)