feat(stats#index): update Stat model to also query DossierDeleted in stats computation
tech(question): discard_and_keep_track! ; are we really keeping track with default_scope { kept } ? feat(stats): add DeletedDossier in Stat computations Revert "tech(question): discard_and_keep_track! ; are we really keeping track with default_scope { kept } ?" This reverts commit d1155b7eeaaf1a9f80189e59667e109541fcb089. feat(stats): support deleted_dossiers for last_four_months_hash and cumulative_hash. extract sanitize query & merge hashes in methdos clean(rubocop): lint with rubocop Update db/migrate/20211126080118_add_index_to_deleted_at_to_deleted_dossiers.rb Co-authored-by: LeSim <mail@simon.lehericey.net> fix(rubocop): avoid uneeded allocation fix(migration): add concurrent index with expected synthax fix(brakeman): add ignore message since group date_trunc evaluation is used by only ourself
This commit is contained in:
parent
783b0ed9f0
commit
970e43efb8
5 changed files with 225 additions and 37 deletions
|
@ -19,7 +19,7 @@
|
|||
class Stat < ApplicationRecord
|
||||
class << self
|
||||
def update_stats
|
||||
states = dossiers_states
|
||||
states = sum_hashes(dossiers_states, deleted_dossiers_states)
|
||||
stat = Stat.first || Stat.new
|
||||
|
||||
stat.update(
|
||||
|
@ -30,8 +30,14 @@ class Stat < ApplicationRecord
|
|||
dossiers_deposes_entre_60_et_30_jours: states['dossiers_deposes_entre_60_et_30_jours'],
|
||||
dossiers_not_brouillon: states['not_brouillon'],
|
||||
dossiers_termines: states['termines'],
|
||||
dossiers_cumulative: cumulative_hash(Dossier.state_not_brouillon, :en_construction_at),
|
||||
dossiers_in_the_last_4_months: last_four_months_hash(Dossier.state_not_brouillon, :en_construction_at),
|
||||
dossiers_cumulative: cumulative_hash([
|
||||
[Dossier.state_not_brouillon, :en_construction_at],
|
||||
[DeletedDossier.where.not(state: :brouillon), :deleted_at]
|
||||
]),
|
||||
dossiers_in_the_last_4_months: last_four_months_hash([
|
||||
[Dossier.state_not_brouillon, :en_construction_at],
|
||||
[DeletedDossier.where.not(state: :brouillon), :deleted_at]
|
||||
]),
|
||||
administrations_partenaires: AdministrateursProcedure.joins(:procedure).merge(Procedure.publiees_ou_closes).select('distinct administrateur_id').count
|
||||
)
|
||||
end
|
||||
|
@ -39,55 +45,83 @@ class Stat < ApplicationRecord
|
|||
private
|
||||
|
||||
def dossiers_states
|
||||
query = <<-EOF
|
||||
SELECT
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' ) AS "not_brouillon",
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' and en_construction_at BETWEEN :one_month_ago AND :now ) AS "dossiers_depose_avant_30_jours",
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' and en_construction_at BETWEEN :two_months_ago AND :one_month_ago ) AS "dossiers_deposes_entre_60_et_30_jours",
|
||||
COUNT(*) FILTER ( WHERE state = 'brouillon' ) AS "brouillon",
|
||||
COUNT(*) FILTER ( WHERE state = 'en_construction' ) AS "en_construction",
|
||||
COUNT(*) FILTER ( WHERE state = 'en_instruction' ) AS "en_instruction",
|
||||
COUNT(*) FILTER ( WHERE state in ('accepte', 'refuse', 'sans_suite') ) AS "termines"
|
||||
FROM dossiers
|
||||
WHERE hidden_at IS NULL
|
||||
sanitize_and_exec(Dossier, <<-EOF
|
||||
SELECT
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' ) AS "not_brouillon",
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' and en_construction_at BETWEEN :one_month_ago AND :now ) AS "dossiers_depose_avant_30_jours",
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' and en_construction_at BETWEEN :two_months_ago AND :one_month_ago ) AS "dossiers_deposes_entre_60_et_30_jours",
|
||||
COUNT(*) FILTER ( WHERE state = 'brouillon' ) AS "brouillon",
|
||||
COUNT(*) FILTER ( WHERE state = 'en_construction' ) AS "en_construction",
|
||||
COUNT(*) FILTER ( WHERE state = 'en_instruction' ) AS "en_instruction",
|
||||
COUNT(*) FILTER ( WHERE state in ('accepte', 'refuse', 'sans_suite') ) AS "termines"
|
||||
FROM dossiers
|
||||
WHERE hidden_at IS NULL
|
||||
EOF
|
||||
|
||||
sanitized_query = ActiveRecord::Base.sanitize_sql([
|
||||
query,
|
||||
now: Time.zone.now,
|
||||
one_month_ago: 1.month.ago,
|
||||
two_months_ago: 2.months.ago
|
||||
])
|
||||
|
||||
Dossier.connection.select_all(sanitized_query).first
|
||||
)
|
||||
end
|
||||
|
||||
def last_four_months_hash(association, date_attribute)
|
||||
min_date = 3.months.ago.beginning_of_month.to_date
|
||||
def deleted_dossiers_states
|
||||
sanitize_and_exec(DeletedDossier, <<-EOF
|
||||
SELECT
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' ) AS "not_brouillon",
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' and deleted_at BETWEEN :one_month_ago AND :now ) AS "dossiers_depose_avant_30_jours",
|
||||
COUNT(*) FILTER ( WHERE state != 'brouillon' and deleted_at BETWEEN :two_months_ago AND :one_month_ago ) AS "dossiers_deposes_entre_60_et_30_jours",
|
||||
COUNT(*) FILTER ( WHERE state = 'brouillon' ) AS "brouillon",
|
||||
COUNT(*) FILTER ( WHERE state = 'en_construction' ) AS "en_construction",
|
||||
COUNT(*) FILTER ( WHERE state = 'en_instruction' ) AS "en_instruction",
|
||||
COUNT(*) FILTER ( WHERE state in ('accepte', 'refuse', 'sans_suite') ) AS "termines"
|
||||
FROM deleted_dossiers
|
||||
EOF
|
||||
)
|
||||
end
|
||||
|
||||
association
|
||||
.where(date_attribute => min_date..max_date)
|
||||
.group("DATE_TRUNC('month', #{date_attribute})")
|
||||
.count
|
||||
def last_four_months_hash(associations_with_date_attribute)
|
||||
min_date = 3.months.ago.beginning_of_month.to_date
|
||||
timeseries = associations_with_date_attribute.map do |association, date_attribute|
|
||||
association
|
||||
.where(date_attribute => min_date..max_date)
|
||||
.group("DATE_TRUNC('month', #{date_attribute})")
|
||||
.count
|
||||
end
|
||||
|
||||
sum_hashes(*timeseries)
|
||||
.to_a
|
||||
.sort_by { |a| a[0] }
|
||||
.map { |e| [I18n.l(e.first, format: "%B %Y"), e.last] }
|
||||
end
|
||||
|
||||
def cumulative_hash(association, date_attribute)
|
||||
def cumulative_hash(associations_with_date_attribute)
|
||||
timeseries = associations_with_date_attribute.map do |association, date_attribute|
|
||||
association
|
||||
.where("#{date_attribute} < ?", max_date)
|
||||
.group("DATE_TRUNC('month', #{date_attribute})")
|
||||
.count
|
||||
end
|
||||
|
||||
sum = 0
|
||||
association
|
||||
.where("#{date_attribute} < ?", max_date)
|
||||
.group("DATE_TRUNC('month', #{date_attribute})")
|
||||
.count
|
||||
sum_hashes(*timeseries)
|
||||
.to_a
|
||||
.sort_by { |a| a[0] }
|
||||
.map { |x, y| { x => (sum += y) } }
|
||||
.reduce({}, :merge)
|
||||
end
|
||||
|
||||
def sum_hashes(*hashes)
|
||||
{}.merge(*hashes) { |_k, hash_one_value, hash_two_value| hash_one_value + hash_two_value }
|
||||
end
|
||||
|
||||
def max_date
|
||||
Time.zone.now.beginning_of_month - 1.second
|
||||
end
|
||||
|
||||
def sanitize_and_exec(model, query)
|
||||
sanitized_query = ActiveRecord::Base.sanitize_sql([
|
||||
query,
|
||||
now: Time.zone.now,
|
||||
one_month_ago: 1.month.ago,
|
||||
two_months_ago: 2.months.ago
|
||||
])
|
||||
model.connection.select_all(sanitized_query).first
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue