-
-
Notifications
You must be signed in to change notification settings - Fork 572
Expand file tree
/
Copy pathitems_flow_query.rb
More file actions
79 lines (75 loc) · 3.66 KB
/
items_flow_query.rb
File metadata and controls
79 lines (75 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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