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
12 changes: 10 additions & 2 deletions app/controllers/donations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ def index
# Using the @donations allows drilling down instead of always starting with the total dataset
@donations_quantity = @donations.collect(&:total_quantity).sum
@paginated_donations_quantity = @paginated_donations.collect(&:total_quantity).sum
@items = current_organization.items.alphabetized.select(:id, :name)
@total_value_all_donations = total_value(@donations)
@paginated_in_kind_value = total_value(@paginated_donations)
@total_money_raised = total_money_raised(@donations)
@storage_locations = @donations.filter_map { |donation| donation.storage_location if !donation.storage_location.discarded_at }.compact.uniq.sort
@selected_storage_location = filter_params[:at_storage_location]
@sources = @donations.collect(&:source).uniq.sort
@selected_source = filter_params[:by_source]
@selected_item = filter_params[:by_item_id]
@donation_totals = DonationTotalsService.call(current_organization.donations.class_filter(scope_filters))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, what does this even have to do with this PR? It's not even used anywhere that I can tell.

@selected_item_category = filter_params[:by_category]
@donation_sites = @donations.collect(&:donation_site).compact.uniq.sort_by { |site| site.name.downcase }
@selected_donation_site = filter_params[:from_donation_site]
Expand Down Expand Up @@ -157,8 +160,7 @@ def donation_item_params
helper_method \
def filter_params
return {} unless params.key?(:filters)

params.require(:filters).permit(:at_storage_location, :by_source, :from_donation_site, :by_product_drive, :by_product_drive_participant, :from_manufacturer, :by_category)
params.require(:filters).permit(:at_storage_location, :by_source, :from_donation_site, :by_product_drive, :by_product_drive_participant, :from_manufacturer, :by_category, :by_item_id)
end

# Omits donation_site_id or product_drive_participant_id if those aren't selected as source
Expand All @@ -170,6 +172,12 @@ def strip_unnecessary_params
params
end

def scope_filters
filter_params
.except(:date_range)
.merge(during: helpers.selected_range)
end

# If line_items have submitted with empty rows, clear those out first.
def compact_line_items
return params unless params[:donation].key?(:line_items_attributes)
Expand Down
1 change: 1 addition & 0 deletions app/models/donation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class Donation < ApplicationRecord
scope :from_manufacturer, ->(manufacturer_id) {
where(manufacturer_id: manufacturer_id)
}
scope :by_item_id, ->(item_id) { includes(:items).where(items: { id: item_id }) }

scope :by_category, ->(item_category) {
joins(line_items: {item: :item_category}).where("item_categories.name ILIKE ?", item_category)
Expand Down
32 changes: 32 additions & 0 deletions app/services/donation_totals_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class DonationTotalsService
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a query, not a service, no?

DonationTotal = Data.define(:quantity, :value)

class << self
# @param donations [Donation::ActiveRecord_Relation]
# @return [Hash<Integer, DonationTotal>]
def call(donations)
calculate_totals(donations)
end

private

# Returns a hash with quantity/value totals for each donation.
#
# @return [Hash<Integer, DonationTotal>]
def calculate_totals(donations)
donations
.left_joins(line_items: [:item])
.group("donations.id, line_items.id, items.id")
.pluck(
Arel.sql(
"donations.id,
COALESCE(SUM(line_items.quantity) OVER (PARTITION BY donations.id), 0) AS quantity,
COALESCE(SUM(COALESCE(items.value_in_cents, 0) * line_items.quantity) OVER (PARTITION BY donations.id), 0) AS value"
)
)
.to_h do |(id, quantity, value)|
[id, DonationTotal.new(quantity:, value:)]
end
end
end
end
13 changes: 10 additions & 3 deletions app/views/donations/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@
<%= filter_select(label: "Filter by Donation Site", scope: :from_donation_site, collection: @donation_sites, key: :id, value: :name, selected: @selected_donation_site) %>
</div>
<% end %>
<% if @items.present? %>
<div class="form-group col-lg-3 col-md-4 col-sm-6 col-xs-12">
<%= filter_select(label: "Filter by Item", scope: :by_item_id, collection: @items, selected: @selected_item) %>
</div>
<% end %>
<% if @item_categories.present? %>
<div class="form-group col-lg-3 col-md-4 col-sm-6 col-xs-12">
<% id = "filter_#{SecureRandom.uuid}" %>
Expand Down Expand Up @@ -116,9 +121,11 @@
<th>Date</th>
<th>Details</th>
<th>Storage Location</th>
<th class="text-right">Quantity of Items</th>
<th class="text-right">Money Raised</th>
<th class="text-right">In-kind Value</th>
<% filtered_item_name = @selected_item ? @items.find { |i| i.id == filter_params[:by_item_id].to_i }&.name : "Items" %>
<th>Quantity of <%= filtered_item_name %></th>
<th>Money Raised</th>
<th>In Kind Value</th>

<th>Comments</th>
<th class="text-right">Actions</th>
</tr>
Expand Down
16 changes: 16 additions & 0 deletions spec/system/donation_system_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@
expect(page).to have_css("table tbody tr", count: 1)
end

it "Filters by Item id" do
category_1 = create(:item_category, name: "Category 1", organization: organization)
category_2 = create(:item_category, name: "Category 2", organization: organization)
item_1 = create(:item, item_category: category_1, name: "Item 1", value_in_cents: 100)
item_2 = create(:item, item_category: category_2, name: "Item 2", value_in_cents: 200)
create(:donation, :with_items, item_quantity: 25, item: item_1)
create(:donation, :with_items, item_quantity: 30, item: item_2)
visit subject
expect(page).to have_css("table tbody tr", count: 2)
select item_1.name, from: "filters[by_item_id]"
click_button "Filter"
expect(page).to have_css("table tbody tr", count: 1)
expect(page).to have_css("table thead tr th", text: "Quantity of #{item_1.name}")
expect(page).to have_css("table td.in-kind", text: "25")
end

it "Filter by product drive participant sticks around" do
x = create(:product_drive, name: 'x')
a = create(:product_drive_participant, business_name: "A")
Expand Down
Loading