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
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
79 changes: 79 additions & 0 deletions app/queries/items_flow_query.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# 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 events_with_flags as (
select it.id as item_id,
it.name as item_name,
-- in quantity for this row (0 if not matching)
case
when (e.type = 'DonationEvent' and (item->>'to_storage_location')::int = :id)
or (e.type = 'PurchaseEvent' and (item->>'to_storage_location')::int = :id)
or (e.type = 'AdjustmentEvent' and (item->>'to_storage_location')::int = :id)
or (e.type = 'TransferEvent' and (item->>'to_storage_location')::int = :id)
or (e.type = 'AuditEvent' and (item->>'to_storage_location')::int = :id)
and e.organization_id = :organization_id
then (item->>'quantity')::int
else 0
end as quantity_in,
-- out quantity normalized to positive numbers (0 if not matching)
case
when (e.type = 'DistributionEvent' and (item->>'from_storage_location')::int = :id)
or (e.type = 'AdjustmentEvent' and (item->>'from_storage_location')::int = :id)
or (e.type = 'TransferEvent' and (item->>'from_storage_location')::int = :id)
or (e.type = 'AuditEvent' and (item->>'from_storage_location')::int = :id)
and e.organization_id = :organization_id
then case when (item->>'quantity')::int < 0 then -(item->>'quantity')::int else (item->>'quantity')::int end
else 0
end as quantity_out,
-- mark rows that are relevant for the overall WHERE in original query
case
when ( (e.type = 'DonationEvent' and (item->>'to_storage_location')::int = :id)
or (e.type = 'PurchaseEvent' and (item->>'to_storage_location')::int = :id)
or (e.type = 'DistributionEvent' and (item->>'from_storage_location')::int = :id)
or (e.type = 'TransferEvent' and ((item->>'from_storage_location')::int = :id or (item->>'to_storage_location')::int = :id))
or (e.type = 'AdjustmentEvent' and (item->>'from_storage_location')::int = :id or (item->>'to_storage_location')::int = :id)
) and e.organization_id = :organization_id
then 1 else 0
end as relevant
from events e
left join lateral jsonb_array_elements(data->'items') as item on true
left join items it on it.id = (item->>'item_id')::int and it.organization_id = :organization_id
where e.created_at >= :start_date and e.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 events_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