Skip to content

Commit a1d71fc

Browse files
authored
Trend reports are based on distribution/donation/purchase issued date (#4769)
* Modify HistoricalTrendService to return quantity of distributed/donated/purchased items over the past year * Modify HistoricalTrendService tests * Refactor HistoricalTrendService
1 parent 20cf220 commit a1d71fc

File tree

2 files changed

+39
-22
lines changed

2 files changed

+39
-22
lines changed

app/services/historical_trend_service.rb

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,36 @@ def initialize(organization_id, type)
44
@type = type
55
end
66

7+
# Returns: [{:name=>"Adult Briefs (XXL)", :data=>[0, 0, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0], :visible=>false}]
8+
# :data contains quantity from 11 months ago to current month
79
def series
8-
# Preload line_items with a single query to avoid N+1 queries.
9-
items_with_line_items = @organization.items.active
10-
.includes(:line_items)
11-
.where(line_items: {itemizable_type: @type, created_at: 1.year.ago.beginning_of_month..Time.current})
12-
.order(:name)
10+
type_symbol = @type.tableize.to_sym # :distributions, :donations, :purchases
11+
records_for_type = @organization.send(type_symbol)
12+
.includes(items: :line_items)
13+
.where(issued_at: 1.year.ago.beginning_of_month..Time.current)
1314

14-
month_offset = [*1..12].rotate(Time.zone.today.month)
15-
default_dates = (1..12).index_with { |i| 0 }
15+
array_of_items = []
1616

17-
items_with_line_items.each_with_object([]) do |item, array_of_items|
18-
dates = default_dates.deep_dup
17+
records_for_type.each do |record|
18+
index = record.issued_at.month - Date.current.month - 1
1919

20-
item.line_items.each do |line_item|
21-
month = line_item.created_at.month
22-
index = month_offset.index(month) + 1
23-
dates[index] = dates[index] + line_item.quantity
24-
end
20+
record.line_items.each do |line_item|
21+
name = line_item.item.name
22+
quantity = line_item.quantity
23+
next if quantity.zero?
2524

26-
array_of_items << {name: item.name, data: dates.values, visible: false} unless dates.values.sum.zero?
25+
existing_item = array_of_items.find { |item| item[:name] == name }
26+
if existing_item
27+
quantity_per_month = existing_item[:data]
28+
quantity_per_month[index] += quantity
29+
else
30+
quantity_per_month = Array.new(12, 0)
31+
quantity_per_month[index] += quantity
32+
array_of_items << {name:, data: quantity_per_month, visible: false}
33+
end
34+
end
2735
end
36+
37+
array_of_items.sort_by { |item| item[:name] }
2838
end
2939
end

spec/services/historical_trend_service_spec.rb

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,29 @@
44
let(:service) { described_class.new(organization.id, type) }
55

66
describe "#series" do
7-
let!(:item1) { create(:item, organization: organization, name: "Item 1") }
8-
let!(:item2) { create(:item, organization: organization, name: "Item 2") }
7+
let(:item1) { create(:item, organization: organization, name: "Item 1") }
8+
let(:item2) { create(:item, organization: organization, name: "Item 2") }
9+
let(:donation1) { create(:donation, organization:, issued_at: Date.current) }
10+
let(:donation2) { create(:donation, organization:, issued_at: 2.months.ago) }
911
let!(:line_items) do
1012
(0..11).map do |n|
11-
create(:line_item, item: item1, itemizable_type: type, quantity: 10 * (n + 1), created_at: n.months.ago)
13+
create(:line_item, item: item1, itemizable_type: type, itemizable_id: donation1.id, quantity: 10, created_at: n.months.ago)
1214
end
1315
end
14-
let!(:line_item2) { create(:line_item, item: item2, itemizable_type: type, quantity: 60, created_at: 6.months.ago) }
15-
let!(:line_item3) { create(:line_item, item: item2, itemizable_type: type, quantity: 30, created_at: 3.months.ago) }
16+
let!(:line_item2) { create(:line_item, item: item2, itemizable_type: type, itemizable_id: donation2.id, quantity: 60, created_at: 6.months.ago) }
17+
let!(:line_item3) { create(:line_item, item: item2, itemizable_type: type, itemizable_id: donation2.id, quantity: 30, created_at: 3.months.ago) }
1618

1719
it "returns an array of items with their monthly data" do
1820
expected_result = [
19-
{name: "Item 1", data: [120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20, 10], visible: false},
20-
{name: "Item 2", data: [0, 0, 0, 0, 0, 60, 0, 0, 30, 0, 0, 0], visible: false}
21+
{name: "Item 1", data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120], visible: false},
22+
{name: "Item 2", data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0], visible: false}
2123
]
2224
expect(service.series).to eq(expected_result)
2325
end
26+
27+
it "the last data point is the quantity for the current month" do
28+
item1_quantities = service.series.first[:data]
29+
expect(item1_quantities.last).to be(line_items.pluck(:quantity).sum)
30+
end
2431
end
2532
end

0 commit comments

Comments
 (0)