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
4 changes: 3 additions & 1 deletion app/controllers/distributions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def index
@total_value_paginated_distributions = @distribution_totals.slice(*paginated_ids).values.sum(&:value)
@total_items_paginated_distributions = @distribution_totals.slice(*paginated_ids).values.sum(&:quantity)
@selected_item_category = filter_params[:by_item_category_id].presence
@reporting_categories = Item.reporting_categories_for_select
@selected_reporting_category = filter_params[:by_reporting_category].presence
@selected_partner = filter_params[:by_partner]
@selected_status = filter_params[:by_state]
@selected_location = filter_params[:by_location]
Expand Down Expand Up @@ -325,7 +327,7 @@ def filter_params

params
.require(:filters)
.permit(:by_item_id, :by_item_category_id, :by_partner, :by_state, :by_location, :date_range)
.permit(:by_item_id, :by_item_category_id, :by_reporting_category, :by_partner, :by_state, :by_location, :date_range)
end

def perform_inventory_check
Expand Down
1 change: 1 addition & 0 deletions app/models/distribution.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class Distribution < ApplicationRecord
scope :by_item_id, ->(item_id) { includes(:items).where(items: { id: item_id }) }
# partner scope to allow filtering by partner
scope :by_item_category_id, ->(item_category_id) { includes(:items).where(items: { item_category_id: item_category_id }) }
scope :by_reporting_category, ->(reporting_category) { includes(:items).where(items: { reporting_category: reporting_category }) }
scope :by_partner, ->(partner_id) { where(partner_id: partner_id) }
# location scope to allow filtering distributions by location
scope :by_location, ->(storage_location_id) { where(storage_location_id: storage_location_id) }
Expand Down
11 changes: 11 additions & 0 deletions app/services/exports/export_distributions_csv_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ def base_table
},
"Comments" => ->(distribution) {
distribution.comment
},
"Reporting Category" => ->(distribution) {
distribution.line_items.map { |li| li.item.reporting_category_humanized }.uniq.compact.sort.join(", ")
}
}
end
Expand All @@ -98,6 +101,8 @@ def item_quantity_header_col_name
"Total Number of #{filtered_item_name}"
elsif @filters[:by_item_category_id].present?
"Total Number of #{filtered_item_category_name}"
elsif @filters[:by_reporting_category].present?
"Total Number of #{filtered_reporting_category_name}"
else
"Total Items"
end
Expand All @@ -108,6 +113,8 @@ def item_value_header_col_name
"Total Value of #{filtered_item_name}"
elsif @filters[:by_item_category_id].present?
"Total Value of #{filtered_item_category_name}"
elsif @filters[:by_reporting_category].present?
"Total Value of #{filtered_reporting_category_name}"
else
"Total Value"
end
Expand All @@ -121,6 +128,10 @@ def filtered_item_category_name
@filtered_item_category ||= ItemCategory.find(@filters[:by_item_category_id].to_i).name
end

def filtered_reporting_category_name
@filtered_reporting_category ||= Item.reporting_categories_for_select.find { |rc| rc.id == @filters[:by_reporting_category] }&.name
end

def base_headers
base_table.keys
end
Expand Down
4 changes: 2 additions & 2 deletions app/views/distributions/_distribution_total.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<td></td>
<td></td>
<td class="overall-total-items text-right">
<%= number_with_delimiter(@total_items_paginated_distributions, :delimiter => ',') %> (This page)
<%= number_with_delimiter(@total_items_paginated_distributions, :delimiter => ',') %> <%= quantity_label %> (This page)
<br>
<%= number_with_delimiter(@total_items_all_distributions, :delimiter => ',') %> (Total)
<%= number_with_delimiter(@total_items_all_distributions, :delimiter => ',') %> <%= quantity_label %> (Total)
</td>
<td class="overall-total-value text-right">
<strong><%= dollar_value(@total_value_paginated_distributions) %></strong> (This page)
Expand Down
19 changes: 18 additions & 1 deletion app/views/distributions/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
<%= filter_select(label: "Filter by Item Category", scope: :by_item_category_id, collection: @item_categories, selected: @selected_item_category) %>
</div>
<% end %>
<div class="form-group col-lg-2 col-md-2 col-sm-6 col-xs-12">
<%= filter_select(label: "Filter by Reporting Category", scope: :by_reporting_category, collection: @reporting_categories, selected: @selected_reporting_category) %>
</div>
<% if @partners.present? %>
<div class="form-group col-lg-2 col-md-2 col-sm-6 col-xs-12">
<%= filter_select(label: "Filter by Partner", scope: :by_partner, collection: @partners, selected: @selected_partner) %>
Expand Down Expand Up @@ -105,12 +108,15 @@

<% filtered_item_name = @selected_item ? @items.find { |i| i.id == filter_params[:by_item_id].to_i }&.name : nil %>
<% filtered_category_name = @selected_item_category ? @item_categories.find { |ic| ic.id == filter_params[:by_item_category_id].to_i }&.name : nil %>
<% filtered_reporting_category_name = @selected_reporting_category ? @reporting_categories.find { |rc| rc.id == filter_params[:by_reporting_category] }&.name : nil %>

<!-- Quantity -->
<% if filtered_item_name %>
<th class="numeric">Total <%= filtered_item_name %></th>
<% elsif filtered_category_name %>
<th class="numeric">Total in <%= filtered_category_name %></th>
<% elsif filtered_reporting_category_name %>
<th class="numeric">Total <%= filtered_reporting_category_name %></th>
<% else %>
<th class="numeric">Total Items</th>
<% end %>
Expand All @@ -121,6 +127,8 @@
<th class="numeric">Value of <%= filtered_item_name %></th>
<% elsif filtered_category_name %>
<th class="numeric">Value of <%= filtered_category_name %></th>
<% elsif filtered_reporting_category_name %>
<th class="numeric">Value of <%= filtered_reporting_category_name %></th>
<% else %>
<th class="numeric">Total Value</th>
<% end %>
Expand All @@ -137,7 +145,16 @@
<%= render partial: "distribution_row", collection: @paginated_distributions %>
</tbody>
<tfoot>
<%= render partial: "distribution_total" %>
<% if filtered_item_name %>
<% quantity_label = filtered_item_name %>
<% elsif filtered_category_name %>
<% quantity_label = "in #{filtered_category_name}" %>
<% elsif filtered_reporting_category_name %>
<% quantity_label = filtered_reporting_category_name %>
<% else %>
<% quantity_label = "Items" %>
<% end %>
<%= render partial: "distribution_total", locals: { quantity_label: quantity_label } %>
</tfoot>
</table>
</div>
Expand Down
57 changes: 57 additions & 0 deletions spec/requests/distributions_requests_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,63 @@
end
end

context "when filtering by reporting category" do
let!(:item_pads) { create(:item, reporting_category: "pads", value_in_cents: 100, organization: organization) }
let!(:item_diapers) { create(:item, reporting_category: "disposable_diapers", value_in_cents: 100, organization: organization) }
let!(:distribution_pads) { create(:distribution, :with_items, item: item_pads, item_quantity: 5, organization: organization) }
let!(:distribution_diapers) { create(:distribution, :with_items, item: item_diapers, item_quantity: 8, organization: organization) }
let(:params) { { filters: { by_reporting_category: "pads" } } }

it "only shows distributions containing items with the given reporting category" do
get distributions_path, params: params

expect(assigns(:distributions)).to include(distribution_pads)
expect(assigns(:distributions)).not_to include(distribution_diapers)
end

it "includes the reporting category filter select in the page" do
get distributions_path

page = Nokogiri::HTML(response.body)
reporting_category_select = page.at_css("select[name='filters[by_reporting_category]']")
expect(reporting_category_select).to be_present
expect(reporting_category_select.text).to include("Pads")
end

it "annotates the quantity and value column headers with the reporting category name" do
get distributions_path, params: params

page = Nokogiri::HTML(response.body)
quantity_header, value_header = page.css("table thead tr th.numeric")
expect(quantity_header.text).to eq("Total Pads")
expect(value_header.text).to eq("Value of Pads")
end

it "exports only matching distributions to CSV with annotated headers and a Reporting Category column" do
get distributions_path(format: :csv, filters: params[:filters])

csv = CSV.parse(response.body, headers: true)
expect(csv.headers).to include("Reporting Category")
expect(csv.headers).to include("Total Number of Pads")
expect(csv.headers).to include("Total Value of Pads")
expect(csv.count).to eq(1)
expect(csv.first["Reporting Category"]).to eq("Pads")
end

context "when also filtering by item" do
let(:combined_params) { { filters: { by_item_id: item_pads.id, by_reporting_category: "pads" } } }

it "uses the item name in the column headers, not the reporting category" do
get distributions_path, params: combined_params

page = Nokogiri::HTML(response.body)
quantity_header, value_header = page.css("table thead tr th.numeric")
expect(quantity_header.text).to eq("Total #{item_pads.name}")
expect(value_header.text).to eq("Value of #{item_pads.name}")
end
end
end

context "when filtering by item category id" do
let!(:item_category) { create(:item_category, organization:) }
let!(:item_category_2) { create(:item_category, organization:) }
Expand Down
Loading
Loading