stats: move date formatting out of the Stat model

Before this commit, the monthly dossiers count was serialized into the
Stat record using human-formatted dates, as:

```ruby
s.dossiers_in_the_last_4_months = {
  "octobre 2021"=>409592,
  "novembre 2021"=>497823,
  "décembre 2021"=>38170,
  "janvier 2022"=>0
}
```

Turns out the ordering of keys in a serialized hash is not guaranteed.
After a round-trip to the database, the keys will be wrongly sorted.

Instead we want to save raw Date objects, which will preserve the
ordering. The date formatting can be applied at display-time by the
controller.

Fix #6848
This commit is contained in:
Pierre de La Morinerie 2022-02-02 08:17:43 +00:00
parent 7c4bb4d1cf
commit e6cf07b810
3 changed files with 53 additions and 34 deletions

View file

@ -31,7 +31,7 @@ class StatsController < ApplicationController
@procedures_in_the_last_4_months = last_four_months_serie(procedures, :published_at)
@dossiers_cumulative = stat.dossiers_cumulative
@dossiers_in_the_last_4_months = stat.dossiers_in_the_last_4_months
@dossiers_in_the_last_4_months = format_keys_as_months(stat.dossiers_in_the_last_4_months)
end
def download
@ -136,11 +136,18 @@ class StatsController < ApplicationController
end
end
def format_keys_as_months(series)
series.transform_keys do |k|
date = k.is_a?(Date) ? k : (Date.parse(k) rescue k)
l(date, format: "%B %Y")
end
end
def last_four_months_serie(association, date_attribute)
association
series = association
.group_by_month(date_attribute, last: 4, current: super_admin_signed_in?)
.count
.transform_keys { |date| l(date, format: "%B %Y") }
format_keys_as_months(series)
end
def cumulative_month_serie(association, date_attribute)

View file

@ -80,11 +80,7 @@ class Stat < ApplicationRecord
association.group_by_month(date_attribute, last: 4, current: false).count
end
month_serie(sum_hashes(*timeseries))
end
def month_serie(date_serie)
date_serie.keys.sort.each_with_object({}) { |date, h| h[I18n.l(date, format: "%B %Y")] = date_serie[date] }
sum_hashes(*timeseries).sort.to_h
end
def cumulative_month_serie(associations_with_date_attribute)

View file

@ -57,24 +57,30 @@ describe Stat do
create(:dossier, state: :en_construction, depose_at: i.months.ago)
create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago)
end
rs = Stat.send(:cumulative_month_serie, [
[Dossier.state_not_brouillon, :depose_at],
[DeletedDossier.where.not(state: :brouillon), :deleted_at]
s = Stat.new({
dossiers_cumulative:
Stat.send(:cumulative_month_serie, [
[Dossier.state_not_brouillon, :depose_at],
[DeletedDossier.where.not(state: :brouillon), :deleted_at]
])
})
s.save!
s.reload
# Use `Hash#to_a` to also test the key ordering
expect(s.dossiers_cumulative.to_a).to eq([
[formatted_n_months_ago(12), 2],
[formatted_n_months_ago(11), 4],
[formatted_n_months_ago(10), 6],
[formatted_n_months_ago(9), 8],
[formatted_n_months_ago(8), 10],
[formatted_n_months_ago(7), 12],
[formatted_n_months_ago(6), 14],
[formatted_n_months_ago(5), 16],
[formatted_n_months_ago(4), 18],
[formatted_n_months_ago(3), 20],
[formatted_n_months_ago(2), 22],
[formatted_n_months_ago(1), 24]
])
expect(rs).to eq({
12 => 2,
11 => 4,
10 => 6,
9 => 8,
8 => 10,
7 => 12,
6 => 14,
5 => 16,
4 => 18,
3 => 20,
2 => 22,
1 => 24
}.transform_keys { |i| i.months.ago.beginning_of_month.to_date })
end
end
@ -85,16 +91,22 @@ describe Stat do
create(:dossier, state: :en_construction, depose_at: i.months.ago)
create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago)
end
rs = Stat.send(:last_four_months_serie, [
[Dossier.state_not_brouillon, :depose_at],
[DeletedDossier.where.not(state: :brouillon), :deleted_at]
])
expect(rs).to eq({
"juillet 2021" => 2,
"août 2021" => 2,
"septembre 2021" => 2,
"octobre 2021" => 2
s = Stat.new({
dossiers_in_the_last_4_months:
Stat.send(:last_four_months_serie, [
[Dossier.state_not_brouillon, :depose_at],
[DeletedDossier.where.not(state: :brouillon), :deleted_at]
])
})
s.save!
s.reload
# Use `Hash#to_a` to also test the key ordering
expect(s.dossiers_in_the_last_4_months.to_a).to eq([
['2021-07-01', 2],
['2021-08-01', 2],
['2021-09-01', 2],
['2021-10-01', 2]
])
end
end
end
@ -104,4 +116,8 @@ describe Stat do
expect(Stat.send(:sum_hashes, *[{ a: 1, b: 2, d: 5 }, { a: 2, b: 3, c: 5 }])).to eq({ a: 3, b: 5, c: 5, d: 5 })
end
end
def formatted_n_months_ago(i)
i.months.ago.beginning_of_month.to_date.to_s
end
end