From 5c921182ea19b7d3f1323283f378a71136e8ad84 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Thu, 8 Nov 2018 16:19:17 +0000 Subject: [PATCH 1/4] procedure: rename `mean_instruction_time` to `usual_instruction_time` Ref #2970 --- app/models/procedure.rb | 6 +++--- .../new_user/dossiers/show/_status_overview.html.haml | 8 ++++---- spec/models/procedure_spec.rb | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/models/procedure.rb b/app/models/procedure.rb index c8dd7b625..d8f287ab1 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -304,15 +304,15 @@ class Procedure < ApplicationRecord end end - def mean_traitement_time + def usual_traitement_time mean_time(:en_construction_at, :processed_at) end - def mean_verification_time + def usual_verification_time mean_time(:en_construction_at, :en_instruction_at) end - def mean_instruction_time + def usual_instruction_time mean_time(:en_instruction_at, :processed_at) end diff --git a/app/views/new_user/dossiers/show/_status_overview.html.haml b/app/views/new_user/dossiers/show/_status_overview.html.haml index 167883f63..39f06f614 100644 --- a/app/views/new_user/dossiers/show/_status_overview.html.haml +++ b/app/views/new_user/dossiers/show/_status_overview.html.haml @@ -31,10 +31,10 @@ %strong votre dossier passera directement en instruction / FIXME: remove the custom procedure switch at some point - - if dossier.procedure.mean_verification_time && show_time_means + - if dossier.procedure.usual_verification_time && show_time_means - cache(dossier.procedure, expires_in: 1.week) do %p - Le temps moyen de vérification pour cette démarche est de #{distance_of_time_in_words(dossier.procedure.mean_verification_time)}. + Le temps moyen de vérification pour cette démarche est de #{distance_of_time_in_words(dossier.procedure.usual_verification_time)}. - elsif dossier.en_instruction? .en-instruction @@ -46,10 +46,10 @@ avec le résultat. / FIXME: remove the custom procedure switch at some point - - if dossier.procedure.mean_instruction_time && show_time_means + - if dossier.procedure.usual_instruction_time && show_time_means - cache(dossier.procedure, expires_in: 1.week) do %p - Le temps moyen d’instruction pour cette démarche est de #{distance_of_time_in_words(dossier.procedure.mean_instruction_time)}. + Le temps moyen d’instruction pour cette démarche est de #{distance_of_time_in_words(dossier.procedure.usual_instruction_time)}. - elsif dossier.accepte? .accepte diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 1f039cea0..a96599042 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -705,7 +705,7 @@ describe Procedure do end end - describe '#mean_instruction_time' do + describe '#usual_instruction_time' do let(:procedure) { create(:procedure) } context 'when there is only one dossier' do @@ -719,7 +719,7 @@ describe Procedure do dossier.update(en_instruction_at: instruction_date, processed_at: processed_date) end - it { expect(procedure.mean_instruction_time).to eq(1.day.to_i) } + it { expect(procedure.usual_instruction_time).to eq(1.day.to_i) } end end end From e59bec51ef7b9e434574593c9316df5250e24cf8 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Thu, 8 Nov 2018 18:09:27 +0100 Subject: [PATCH 2/4] procedure: use 90th percentile to estimate the completion delay --- app/models/procedure.rb | 12 +++++++----- lib/percentile.rb | 31 ++++++++++++++++++++++++++++++ spec/models/procedure_spec.rb | 36 +++++++++++++++++++++++------------ 3 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 lib/percentile.rb diff --git a/app/models/procedure.rb b/app/models/procedure.rb index d8f287ab1..44984c564 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -1,3 +1,5 @@ +require Rails.root.join('lib', 'percentile') + class Procedure < ApplicationRecord MAX_DUREE_CONSERVATION = 36 @@ -305,15 +307,15 @@ class Procedure < ApplicationRecord end def usual_traitement_time - mean_time(:en_construction_at, :processed_at) + percentile_time(:en_construction_at, :processed_at, 90) end def usual_verification_time - mean_time(:en_construction_at, :en_instruction_at) + percentile_time(:en_construction_at, :en_instruction_at, 90) end def usual_instruction_time - mean_time(:en_instruction_at, :processed_at) + percentile_time(:en_instruction_at, :processed_at, 90) end PATH_AVAILABLE = :available @@ -421,14 +423,14 @@ class Procedure < ApplicationRecord true end - def mean_time(start_attribute, end_attribute) + def percentile_time(start_attribute, end_attribute, p) times = dossiers .state_termine .pluck(start_attribute, end_attribute) .map { |(start_date, end_date)| end_date - start_date } if times.present? - times.sum.fdiv(times.size).ceil + times.percentile(p).ceil end end end diff --git a/lib/percentile.rb b/lib/percentile.rb new file mode 100644 index 000000000..00aa9f59c --- /dev/null +++ b/lib/percentile.rb @@ -0,0 +1,31 @@ +# Adapted from https://github.com/thirtysixthspan/descriptive_statistics + +# Copyright (c) 2010-2014 Derrick Parkhurst (derrick.parkhurst@gmail.com) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +class Array + def percentile(p) + values = self.sort + + if values.empty? + return [] + elsif values.size == 1 + return values.first + elsif p == 100 + return values.last + end + + rank = p / 100.0 * (values.size - 1) + lower, upper = values[rank.floor, 2] + lower + (upper - lower) * (rank - rank.floor) + end +end diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index a96599042..ab4fb73d7 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -708,19 +708,31 @@ describe Procedure do describe '#usual_instruction_time' do let(:procedure) { create(:procedure) } - context 'when there is only one dossier' do - let(:dossier) { create(:dossier, procedure: procedure) } - - context 'which is termine' do - before do - dossier.accepte! - processed_date = Time.zone.parse('12/12/2012') - instruction_date = processed_date - 1.day - dossier.update(en_instruction_at: instruction_date, processed_at: processed_date) - end - - it { expect(procedure.usual_instruction_time).to eq(1.day.to_i) } + before do + processed_delays.each do |delay| + dossier = create :dossier, :accepte, procedure: procedure + instruction_date = 1.month.ago + processed_date = instruction_date + delay + dossier.update!(en_instruction_at: instruction_date, processed_at: processed_date) end end + + context 'when there are several processed dossiers' do + let(:processed_delays) { [1.day, 2.days, 2.days, 2.days, 2.days, 3.days, 3.days, 3.days, 3.days, 12.days] } + + it 'returns a time representative of the dossier instruction delay' do + expect(procedure.usual_instruction_time).to be_between(3.days, 4.days) + end + end + + context 'when there is only one processed dossier' do + let(:processed_delays) { [1.day] } + it { expect(procedure.usual_instruction_time).to eq(1.day) } + end + + context 'where there is no processed dossier' do + let(:processed_delays) { [] } + it { expect(procedure.usual_instruction_time).to be_nil } + end end end From 7635aede98add818533a9ab52c1e685fb2f2067f Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Mon, 12 Nov 2018 08:39:59 +0000 Subject: [PATCH 3/4] dossier: improve wording of estimated time Ref #2970 --- app/views/new_user/dossiers/show/_status_overview.html.haml | 4 ++-- spec/features/new_user/dossier_details_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/new_user/dossiers/show/_status_overview.html.haml b/app/views/new_user/dossiers/show/_status_overview.html.haml index 39f06f614..d1e94d1e2 100644 --- a/app/views/new_user/dossiers/show/_status_overview.html.haml +++ b/app/views/new_user/dossiers/show/_status_overview.html.haml @@ -34,7 +34,7 @@ - if dossier.procedure.usual_verification_time && show_time_means - cache(dossier.procedure, expires_in: 1.week) do %p - Le temps moyen de vérification pour cette démarche est de #{distance_of_time_in_words(dossier.procedure.usual_verification_time)}. + Habituellement, les dossiers de cette démarche sont vérifiés dans un délai de #{distance_of_time_in_words(dossier.procedure.usual_verification_time)}. - elsif dossier.en_instruction? .en-instruction @@ -49,7 +49,7 @@ - if dossier.procedure.usual_instruction_time && show_time_means - cache(dossier.procedure, expires_in: 1.week) do %p - Le temps moyen d’instruction pour cette démarche est de #{distance_of_time_in_words(dossier.procedure.usual_instruction_time)}. + Habituellement, les dossiers de cette démarche sont traités dans un délai de #{distance_of_time_in_words(dossier.procedure.usual_instruction_time)}. - elsif dossier.accepte? .accepte diff --git a/spec/features/new_user/dossier_details_spec.rb b/spec/features/new_user/dossier_details_spec.rb index fd46cac7f..b24744713 100644 --- a/spec/features/new_user/dossier_details_spec.rb +++ b/spec/features/new_user/dossier_details_spec.rb @@ -23,7 +23,7 @@ describe 'Dossier details:' do visit dossier_path(dossier) end - it { expect(page).to have_text("Le temps moyen de vérification pour cette démarche est de 10 jours.") } + it { expect(page).to have_text("Habituellement, les dossiers de cette démarche sont vérifiés dans un délai de 10 jours.") } end context "when the dossier is in instruction" do @@ -34,7 +34,7 @@ describe 'Dossier details:' do visit dossier_path(dossier) end - it { expect(page).to have_text("Le temps moyen d’instruction pour cette démarche est de 2 mois.") } + it { expect(page).to have_text("Habituellement, les dossiers de cette démarche sont traités dans un délai de 2 mois.") } end end From 7a7093503acfccf20ac5c28f4fa1e25daed3e666 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Mon, 12 Nov 2018 10:22:21 +0100 Subject: [PATCH 4/4] dossier: avoid the estimated duration to dangle on a new line --- app/assets/stylesheets/new_design/status_overview.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/new_design/status_overview.scss b/app/assets/stylesheets/new_design/status_overview.scss index beede684f..1503d10cb 100644 --- a/app/assets/stylesheets/new_design/status_overview.scss +++ b/app/assets/stylesheets/new_design/status_overview.scss @@ -51,7 +51,7 @@ .brouillon, .en-construction, .en-instruction { - max-width: 600px; + max-width: 650px; margin: auto; }