demarches-normaliennes/app/controllers/stats_controller.rb
Pierre de La Morinerie e6cf07b810 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
2022-02-02 14:13:53 +01:00

160 lines
4.5 KiB
Ruby

class StatsController < ApplicationController
before_action :authenticate_super_admin!, only: [:download]
MEAN_NUMBER_OF_CHAMPS_IN_A_FORM = 24.0
def index
stat = Stat.first
procedures = Procedure.publiees_ou_closes
@procedures_numbers = procedures_numbers(procedures)
@dossiers_numbers = dossiers_numbers(
stat.dossiers_not_brouillon,
stat.dossiers_depose_avant_30_jours,
stat.dossiers_deposes_entre_60_et_30_jours
)
@contact_percentage = Rails.cache.fetch("stats.contact_percentage", expires_in: 1.day) do
contact_percentage
end
@dossiers_states_for_pie = {
"Brouillon" => stat.dossiers_brouillon,
"En construction" => stat.dossiers_en_construction,
"En instruction" => stat.dossiers_en_instruction,
"Terminé" => stat.dossiers_termines
}
@procedures_cumulative = cumulative_month_serie(procedures, :published_at)
@procedures_in_the_last_4_months = last_four_months_serie(procedures, :published_at)
@dossiers_cumulative = stat.dossiers_cumulative
@dossiers_in_the_last_4_months = format_keys_as_months(stat.dossiers_in_the_last_4_months)
end
def download
headers = [
'ID du dossier',
'ID de la démarche',
'Nom de la démarche',
'ID utilisateur',
'Etat du fichier',
'Durée en brouillon',
'Durée en construction',
'Durée en instruction'
]
data = Dossier
.includes(:procedure, :user)
.in_batches
.flat_map do |dossiers|
dossiers
.pluck(
"dossiers.id",
"procedures.id",
"procedures.libelle",
"users.id",
"dossiers.state",
Arel.sql("dossiers.depose_at - dossiers.created_at"),
Arel.sql("dossiers.en_instruction_at - dossiers.depose_at"),
Arel.sql("dossiers.processed_at - dossiers.en_instruction_at")
)
end
respond_to do |format|
format.csv { send_data(SpreadsheetArchitect.to_xlsx(headers: headers, data: data), filename: "statistiques.csv") }
end
end
private
def procedures_numbers(procedures)
total = procedures.count
last_30_days_count = procedures.where(published_at: 1.month.ago..Time.zone.now).count
previous_count = procedures.where(published_at: 2.months.ago..1.month.ago).count
if previous_count != 0
evolution = (((last_30_days_count.to_f / previous_count) - 1) * 100).round(0)
else
evolution = 0
end
formatted_evolution = format("%+d", evolution)
{
total: total.to_s,
last_30_days_count: last_30_days_count.to_s,
evolution: formatted_evolution
}
end
def dossiers_numbers(total, last_30_days_count, previous_count)
if previous_count != 0
evolution = (((last_30_days_count.to_f / previous_count) - 1) * 100).round(0)
else
evolution = 0
end
formatted_evolution = format("%+d", evolution)
{
total: total.to_s,
last_30_days_count: last_30_days_count.to_s,
evolution: formatted_evolution
}
end
def contact_percentage
number_of_months = 13
from = Time.zone.today.prev_month(number_of_months)
to = Time.zone.today.prev_month
adapter = Helpscout::UserConversationsAdapter.new(from, to)
if !adapter.can_fetch_reports?
return nil
end
adapter
.reports
.map do |monthly_report|
start_date = monthly_report[:start_date].to_time.localtime
end_date = monthly_report[:end_date].to_time.localtime
replies_count = monthly_report[:replies_sent]
dossiers_count = Dossier.where(depose_at: start_date..end_date).count
monthly_contact_percentage = replies_count.fdiv(dossiers_count || 1) * 100
[I18n.l(start_date, format: '%b %y'), monthly_contact_percentage.round(1)]
end
end
def max_date
if super_admin_signed_in?
Time.zone.now
else
Time.zone.now.beginning_of_month - 1.second
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)
series = association
.group_by_month(date_attribute, last: 4, current: super_admin_signed_in?)
.count
format_keys_as_months(series)
end
def cumulative_month_serie(association, date_attribute)
sum = 0
association
.group_by_month(date_attribute, current: super_admin_signed_in?)
.count
.transform_values { |count| sum += count }
end
end