diff --git a/app/models/concerns/itemizable.rb b/app/models/concerns/itemizable.rb index 5c99a490b6..a24ec13186 100644 --- a/app/models/concerns/itemizable.rb +++ b/app/models/concerns/itemizable.rb @@ -63,8 +63,8 @@ def total end def line_items_quantities - line_items.inject(Hash.new) do |hash, item| - hash[item.id] = item.quantity + line_items.inject(Hash.new) do |hash, line_item| + hash[line_item.id] = OpenStruct.new(quantity: line_item.quantity, item_id: line_item.item_id) hash end end diff --git a/app/models/storage_location.rb b/app/models/storage_location.rb index 672ccbd5cb..ae0c9f804c 100644 --- a/app/models/storage_location.rb +++ b/app/models/storage_location.rb @@ -101,16 +101,25 @@ def remove!(donation_or_purchase) log end - def adjust_from_past!(donation_or_purchase, previous_quantities) + def adjust_from_past!(donation_or_purchase, previous_line_item_values) donation_or_purchase.line_items.each do |line_item| inventory_item = InventoryItem.find_or_create_by(storage_location_id: self.id, item_id: line_item.item_id) - if previous_quantity = previous_quantities[line_item.id] + # If the item wasn't deleted by the user, then it will be present to be deleted + # here, and delete returns the item as a return value. + if previous_line_item_value = previous_line_item_values.delete(line_item.id) inventory_item.quantity += line_item.quantity - inventory_item.quantity -= previous_quantity + inventory_item.quantity -= previous_line_item_value.quantity inventory_item.save! end inventory_item.destroy! if inventory_item.quantity == 0 end + # Update storage for line items that are no longer persisted because they + # were removed durring the updated/delete process. + previous_line_item_values.values.each do |value| + inventory_item = InventoryItem.find_or_create_by(storage_location_id: self.id, item_id: value.item_id) + inventory_item.decrement!(:quantity, value.quantity) + inventory_item.destroy! if inventory_item.quantity == 0 + end end def distribute!(distribution) diff --git a/spec/controllers/donations_controller_spec.rb b/spec/controllers/donations_controller_spec.rb index 7ca69279c2..e10cb8d6d5 100644 --- a/spec/controllers/donations_controller_spec.rb +++ b/spec/controllers/donations_controller_spec.rb @@ -69,6 +69,41 @@ put :update, params: default_params.merge(id: donation.id, donation: donation_params) }.to change { donation.storage_location.inventory_items.first.quantity }.by(5) end + + describe "when removing a line item" do + it "updates storage invetory item quantity correctly" do + donation = create(:donation, :with_items, item_quantity: 10) + line_item = donation.line_items.first + line_item_params = { + "0" => { + "_destroy" => "true", + item_id: line_item.item_id, + id: line_item.id + } + } + donation_params = { source: "Donation Site", line_items_attributes: line_item_params } + expect { + put :update, params: default_params.merge(id: donation.id, donation: donation_params) + }.to change { donation.storage_location.inventory_items.first.quantity }.by(-10) + end + + it "deletes inventory item if line item and inventory item quantities are equal" do + donation = create(:donation, :with_items, item_quantity: 1) + line_item = donation.line_items.first + inventory_item = donation.storage_location.inventory_items.first + inventory_item.update(quantity: line_item.quantity) + line_item_params = { + "0" => { + "_destroy" => "true", + item_id: line_item.item_id, + id: line_item.id + } + } + donation_params = { source: "Donation Site", line_items_attributes: line_item_params } + put :update, params: default_params.merge(id: donation.id, donation: donation_params) + expect { inventory_item.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end end describe "GET #edit" do diff --git a/spec/controllers/purchases_controller_spec.rb b/spec/controllers/purchases_controller_spec.rb index 4898ea3dd7..ada75401c6 100644 --- a/spec/controllers/purchases_controller_spec.rb +++ b/spec/controllers/purchases_controller_spec.rb @@ -70,6 +70,41 @@ put :update, params: default_params.merge(id: purchase.id, purchase: purchase_params) }.to change { purchase.storage_location.inventory_items.first.quantity }.by(-5) end + + describe "when removing a line item" do + it "updates storage invetory item quantity correctly" do + purchase = create(:purchase, :with_items, item_quantity: 10) + line_item = purchase.line_items.first + line_item_params = { + "0" => { + "_destroy" => "true", + item_id: line_item.item_id, + id: line_item.id + } + } + purchase_params = { source: "Purchase Site", line_items_attributes: line_item_params } + expect { + put :update, params: default_params.merge(id: purchase.id, purchase: purchase_params) + }.to change { purchase.storage_location.inventory_items.first.quantity }.by(-10) + end + + it "deletes inventory item if line item and inventory item quantities are equal" do + purchase = create(:purchase, :with_items, item_quantity: 1) + line_item = purchase.line_items.first + inventory_item = purchase.storage_location.inventory_items.first + inventory_item.update(quantity: line_item.quantity) + line_item_params = { + "0" => { + "_destroy" => "true", + item_id: line_item.item_id, + id: line_item.id + } + } + purchase_params = { source: "Purchase Site", line_items_attributes: line_item_params } + put :update, params: default_params.merge(id: purchase.id, purchase: purchase_params) + expect { inventory_item.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end end describe "GET #edit" do