Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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
8 changes: 0 additions & 8 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,6 @@ Layout/ExtraSpacing:
- 'Guardfile'
- 'app/models/barcode_item.rb'
- 'app/queries/items_by_storage_collection_query.rb'
- 'app/queries/items_in_query.rb'
- 'app/queries/items_in_total_query.rb'
- 'app/queries/items_out_query.rb'
- 'app/queries/items_out_total_query.rb'
- 'config/environments/development.rb'
- 'config/environments/test.rb'
- 'config/puma.rb'
Expand Down Expand Up @@ -169,10 +165,6 @@ Layout/MultilineMethodCallIndentation:
- 'app/models/partner_distribution.rb'
- 'app/models/storage_location.rb'
- 'app/queries/items_by_storage_collection_query.rb'
- 'app/queries/items_in_query.rb'
- 'app/queries/items_in_total_query.rb'
- 'app/queries/items_out_query.rb'
- 'app/queries/items_out_total_query.rb'
- 'app/services/reports/acquisition_report_service.rb'
- 'app/services/reports/adult_incontinence_report_service.rb'
- 'app/services/reports/children_served_report_service.rb'
Expand Down
24 changes: 16 additions & 8 deletions app/controllers/storage_locations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,14 @@ def edit
@storage_location = current_organization.storage_locations.find(params[:id])
end

# TODO: Move these queries to Query Object
def show
setup_date_range_picker
@storage_location = current_organization.storage_locations.find(params[:id])
version_date = params[:version_date].presence&.to_date
# TODO: Find a way to do these with less hard SQL. These queries have to be manually updated because they're not in-sync with the Model
@items_out = ItemsOutQuery.new(organization: current_organization, storage_location: @storage_location).call
@items_out_total = ItemsOutTotalQuery.new(organization: current_organization, storage_location: @storage_location).call
@items_in = ItemsInQuery.new(organization: current_organization, storage_location: @storage_location).call
@items_in_total = ItemsInTotalQuery.new(organization: current_organization, storage_location: @storage_location).call
@items = ItemsFlowQuery.new(storage_location: @storage_location, organization: current_organization, filter_params: date_range).call.to_a
@total_quantity_in = @items.count.positive? ? @items.first["total_quantity_in"].to_i : 0
@total_quantity_out = @items.count.positive? ? @items.first["total_quantity_out"].to_i : 0
@total_quantity_change = @total_quantity_in - @total_quantity_out
if View::Inventory.within_snapshot?(current_organization.id, version_date)
@inventory = View::Inventory.new(current_organization.id, event_time: version_date)
else
Expand Down Expand Up @@ -157,9 +156,18 @@ def include_omitted_items(existing_item_ids = [])
end

helper_method \
def filter_params
def filter_params
return {} unless params.key?(:filters)

params.require(:filters).permit(:containing)
params.require(:filters).permit(:containing, :date_range, :date_range_label)
end

def date_range
return if filter_params[:date_range].blank?

date_range = filter_params[:date_range].split(" - ")
start_date = Date.parse(date_range[0]).beginning_of_day
end_date = Date.parse(date_range[1]).end_of_day
[start_date, end_date]
end
end
83 changes: 83 additions & 0 deletions app/queries/items_flow_query.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# frozen_string_literal: true

class ItemsFlowQuery
attr_reader :organization
attr_reader :filter_params
attr_reader :storage_location

def initialize(organization:, storage_location:, filter_params: nil)
@organization = organization
@storage_location = storage_location
@filter_params = filter_params
end

def call
query = <<~SQL
WITH line_items_with_flags AS (
SELECT
li.item_id,
it.name AS item_name,
-- in quantity for this row (0 if not matching)
CASE
WHEN (donations.storage_location_id = :id
OR purchases.storage_location_id = :id
OR (adjustments.storage_location_id = :id AND li.quantity > 0)
OR transfers.to_id = :id)
AND it.organization_id = :organization_id
THEN li.quantity
ELSE 0
END AS quantity_in,
-- out quantity normalized to positive numbers (0 if not matching)
CASE
WHEN (distributions.storage_location_id = :id
OR (adjustments.storage_location_id = :id AND li.quantity < 0)
OR transfers.from_id = :id)
AND it.organization_id = :organization_id
THEN CASE WHEN li.quantity < 0 THEN -li.quantity ELSE li.quantity END
ELSE 0
END AS quantity_out,
-- mark rows that are relevant for the overall WHERE in original query
CASE
WHEN (donations.storage_location_id = :id
OR purchases.storage_location_id = :id
OR distributions.storage_location_id = :id
OR transfers.from_id = :id
OR transfers.to_id = :id
OR adjustments.storage_location_id = :id)
AND it.organization_id = :organization_id
THEN 1 ELSE 0
END AS relevant
FROM line_items li
LEFT JOIN donations ON donations.id = li.itemizable_id AND li.itemizable_type = 'Donation'
LEFT JOIN purchases ON purchases.id = li.itemizable_id AND li.itemizable_type = 'Purchase'
LEFT JOIN distributions ON distributions.id = li.itemizable_id AND li.itemizable_type = 'Distribution'
LEFT JOIN adjustments ON adjustments.id = li.itemizable_id AND li.itemizable_type = 'Adjustment'
LEFT JOIN transfers ON transfers.id = li.itemizable_id AND li.itemizable_type = 'Transfer'
LEFT JOIN items it ON it.id = li.item_id
WHERE li.created_at >= :start_date AND li.created_at <= :end_date
)
SELECT
item_id,
item_name,
SUM(quantity_in) AS quantity_in,
SUM(quantity_out) AS quantity_out,
SUM(quantity_in) - SUM(quantity_out) AS change,
SUM(SUM(quantity_in)) OVER () AS total_quantity_in,
SUM(SUM(quantity_out)) OVER () AS total_quantity_out,
SUM(SUM(quantity_in) - SUM(quantity_out)) OVER () AS total_change
FROM line_items_with_flags
WHERE relevant = 1
GROUP BY item_id, item_name
ORDER BY item_name;
SQL

ActiveRecord::Base.connection.exec_query(
ActiveRecord::Base.send(:sanitize_sql_array, [query, {
id: @storage_location.id,
organization_id: @organization.id,
start_date: @filter_params ? @filter_params[0] : 20.years.ago,
end_date: @filter_params ? @filter_params[1] : Time.current.end_of_day
}])
)
end
end
29 changes: 0 additions & 29 deletions app/queries/items_in_query.rb

This file was deleted.

29 changes: 0 additions & 29 deletions app/queries/items_in_total_query.rb

This file was deleted.

29 changes: 0 additions & 29 deletions app/queries/items_out_query.rb

This file was deleted.

26 changes: 0 additions & 26 deletions app/queries/items_out_total_query.rb

This file was deleted.

7 changes: 7 additions & 0 deletions app/views/storage_locations/_item_row.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<% css_class = item_row["change"].negative? ? 'modal-body-warning-text' : '' %>
<tr id="<%= item_row["item_id"] %>">
<td><%= link_to item_row["item_name"], item_path(item_row["item_id"]) %></td>
<td><%= item_row["quantity_in"] %></td>
<td><%= item_row["quantity_out"] %></td>
<td class="<%= css_class %>"><%= item_row["change"] %></td>
</tr>
59 changes: 27 additions & 32 deletions app/views/storage_locations/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,18 @@
<div class="card card-primary card-outline card-outline-tabs">
<div class="card-header p-0 border-bottom-0">
<ul class="nav nav-tabs" id="custom-tabs-three-tab" role="tablist">
<li class="nav-item" class="active">
<a class="nav-link active" id="custom-tabs-inventory-tab" data-bs-toggle="pill" href="#custom-tabs-inventory" role="tab" aria-controls="custom-tabs-one-home-tab" aria-selected="true">Inventory</a>
<li class="nav-item <%= params.dig(:filters, :date_range).nil? ? 'active' : '' %>">
<a class="nav-link <%= params.dig(:filters, :date_range).nil? ? 'active' : '' %>" id="custom-tabs-inventory-tab" data-bs-toggle="pill" href="#custom-tabs-inventory" role="tab" aria-controls="custom-tabs-one-home-tab" aria-selected="true">Inventory</a>
</li>
<li class="nav-item">
<a class="nav-link" id="custom-tabs-inventory-in-tab" data-bs-toggle="pill" href="#custom-tabs-inventory-in" role="tab" aria-controls="custom-tabs-two-home-tab" aria-selected="false">Inventory Coming In</a>
</li>
<li class="nav-item">
<a class="nav-link" id="custom-tabs-inventory-out-tab" data-bs-toggle="pill" href="#custom-tabs-inventory-out" role="tab" aria-controls="custom-tabs-three-home-tab" aria-selected="false">Inventory Going Out</a>
<li class="nav-item <%= params.dig(:filters, :date_range).present? ? 'active' : '' %>">
<a class="nav-link <%= params.dig(:filters, :date_range).present? ? 'active' : '' %>" id="custom-tabs-inventory-flow-tab" data-bs-toggle="pill" href="#custom-tabs-inventory-flow" role="tab" aria-controls="custom-tabs-two-home-tab" aria-selected="false">Inventory Flow</a>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content" id="custom-tabs-three-tabContent">

<div class="tab-pane fade show active" id="custom-tabs-inventory" role="tabpanel" aria-labelledby="custom-tabs-one-home-tab">
<div class="tab-pane fade <%= params.dig(:filters, :date_range).nil? ? 'show active' : '' %>" id="custom-tabs-inventory" role="tabpanel" aria-labelledby="custom-tabs-one-home-tab">
<%= form_for @storage_location, method: :get do %>
Show Inventory at Date: <%= date_field_tag 'version_date', params[:version_date], min: InventoryItem::EARLIEST_VERSION, autocomplete: "on" %>
<%= filter_button(text: 'View') %>
Expand Down Expand Up @@ -131,41 +128,39 @@
</table>
</div><!-- /.box-body.table-responsive -->

<div class="tab-pane fade show" id="custom-tabs-inventory-in" role="tabpanel" aria-labelledby="custom-two-home-tab">
<table class="table">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<%= render partial: "line_item_row", collection: @items_in %>
</tbody>
<tfoot>
<tr>
<td>Total</td>
<td><%= @items_in_total %></td>
</tr>
</tfoot>
</table>
</div><!-- /.box-body.table-responsive -->

<div class="tab-pane fade show" id="custom-tabs-inventory-out" role="tabpanel" aria-labelledby="custom-tabs-three-home-tab">
<div class="tab-pane fade <%= params.dig(:filters, :date_range).present? ? 'show active' : '' %>" id="custom-tabs-inventory-flow" role="tabpanel" aria-labelledby="custom-two-home-tab">
<%= form_for @storage_location, method: :get do %>
<%= label_tag "Date Range" %>
<div class="row">
<div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
<%= render partial: "shared/date_range_picker", locals: {css_class: "form-control"} %>
</div>
<div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
<%= filter_button %>
<%= clear_filter_button %>
</div>
</div>
<% end %>
<br><br>
<table class="table">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Quantity In</th>
<th>Quantity Out</th>
<th>Change</th>
</tr>
</thead>
<tbody>
<%= render partial: "line_item_row", collection: @items_out %>
<%= render partial: "item_row", collection: @items %>
</tbody>
<tfoot>
<tr>
<td>Total</td>
<td><%= @items_out_total %></td>
<td><%= @total_quantity_in %></td>
<td><%= @total_quantity_out %></td>
<% css_class = @total_quantity_change.negative? ? 'modal-body-warning-text' : '' %>
<td class="<%= css_class %>"><%= @total_quantity_change %></td>
</tr>
</tfoot>
</table>
Expand Down
Loading