feat(admin): config sva/svr

This commit is contained in:
Colin Darie 2023-05-25 19:09:59 +02:00
parent 7a8b83cfc9
commit 8c210e6fc7
No known key found for this signature in database
GPG key ID: 4FB865FDBCA4BCC4
10 changed files with 300 additions and 0 deletions

View file

@ -0,0 +1,37 @@
# frozen_string_literal: true
class Procedure::SVASVRFormComponent < ApplicationComponent
attr_reader :procedure, :configuration
def initialize(procedure:, configuration:)
@procedure = procedure
@configuration = configuration
end
def decision_buttons
scope = ".decision_buttons"
[
{ label: t("disabled", scope:), value: "disabled" },
{ label: t("sva", scope:), value: "sva", hint: t("sva_hint", scope:) },
{ label: t("svr", scope:), value: "svr", hint: t("svr_hint", scope:) }
]
end
def resume_buttons
scope = ".resume_buttons"
[
{
value: "continue",
label: t("continue_label", scope: scope),
hint: t("continue_hint", scope: scope)
},
{
value: "reset",
label: t("reset_label", scope: scope),
hint: t("reset_hint", scope: scope)
}
]
end
end

View file

@ -0,0 +1,26 @@
---
en:
rule: Rule to apply
delay: Configuration of the delay before decision
unit_labels:
months: months
weeks: weeks
days: days
resume_method: How to calculate the delay when the applicant resubmits their corrected file?
resume_intro: |
When an instructor asks for a file to be corrected, the countdown of the delay is interrupted.
The delay resumes when the applicant resubmits their file stating that they have made the requested corrections.
submit: Apply SVA/SVR configuration
cancel: Cancel
decision_buttons:
disabled: "Disabled"
sva: "Silence Equals Acceptation (SVA)"
sva_hint: "A file is automatically accepted if no instructor has pronounced before the allotted time"
svr: "Silence Equals Rejection (SVR)"
svr_hint: "A file is automatically rejected if no instructor has pronounced before the allotted time"
resume_buttons:
continue_label: "Resume countdown from where it stopped"
continue_hint: "Example: if the instructor asks for corrections while there are 10 days left before the automatic decision, and the file is resubmitted on April 15, it will be automatically accepted on April 25, unless the instructor pronounces in the meantime or asks for corrections again"
reset_label: "Reset the delay"
reset_hint: "Example: if the file is resubmitted on April 15 and the delay is 2 months, the decision will be automatically made on June 15, unless the instructor pronounces in the meantime or asks for corrections again"
notice_new_files_only: "Information: if you activate this rule, only the newly submitted files will be subject to it."

View file

@ -0,0 +1,26 @@
---
fr:
rule: Règle à appliquer
delay: Configuration du délai avant décision
unit_labels:
months: mois
weeks: semaines
days: jours
resume_method: Comment calculer le délai lorsque le demandeur re-dépose son dossier corrigé ?
resume_intro: |
Lorsquun instructeur demande de corriger un dossier, le décompte du délai est interrompu.
Le délai reprend lorsque le demandeur redépose son dossier en déclarant avoir effectué les corrections demandées.
submit: Appliquer la configuration SVA/SVR
cancel: Annuler
decision_buttons:
disabled: "Désactivé"
sva: "Silence Vaut Accord"
sva_hint: "Un dossier est automatiquement accepté si aucun ninstructeur ne sest prononcé avant le délai imparti"
svr: "Silence Vaut Rejet"
svr_hint: "Un dossier est automatiquement refusé si aucun ninstructeur ne sest prononcé avant le délai imparti"
resume_buttons:
continue_label: "Reprendre le décompte depuis le moment où il sétait arrêté"
continue_hint: "Exemple: si linstructeur demande des corrections alors quil reste 10 jours avant la décision automatique, et que le dossier est re-déposé le 15 avril, il sera automatiquement accepté le 25 avril, sauf à ce que linstructeur se prononce dici là ou demande à nouveau des corrections"
reset_label: "Réinitialiser le délai"
reset_hint: "Exemple: si le dossier est re-déposé le 15 avril et que le délai est de 2 mois, la décision sera automatiquement prise le 15 juin, sauf à ce que linstructeur se prononce dici là ou demande à nouveau des corrections"
notice_new_files_only: "Information : si vous activez cette règle, seuls les nouveaux dossiers déposés y seront soumis."

View file

@ -0,0 +1,37 @@
= form_for [procedure, configuration], url: admin_procedure_sva_svr_path(procedure), method: :put do |f|
- if procedure.publiee?
.fr-alert.fr-alert--info.fr-alert--sm.fr-mb-4w
- if procedure.sva_svr_enabled?
%p Information : si vous désactivez cette règle, seuls les nouveaux dossiers seront impactés. Ceux déjà déjà déposés la conserveront.
- else
%p= t('.notice_new_files_only')
%fieldset.fr-fieldset
%legend.fr-fieldset__legend= t(".rule")
= render Dsfr::RadioButtonListComponent.new(form: f, target: :decision, buttons: decision_buttons, error: configuration.errors[:decision].first)
%fieldset.fr-fieldset
%legend.fr-fieldset__legend= t(".delay")
.fr-fieldset__element.fr-fieldset__element--inline
.fr-input-group
= f.number_field :period, class: 'fr-input', disabled: form_disabled?
.fr-fieldset__element.fr-fieldset__element--inline
.fr-select-group
= f.select :unit, options_for_select(SVASVRConfiguration.unit_options.map { [t(_1, scope: ".unit_labels"), _1] }, selected: configuration.unit), {}, class: 'fr-select', disabled: form_disabled?
%fieldset.fr-fieldset
%legend.fr-fieldset__legend
= t(".resume_method")
%span.fr-hint-text
= t(".resume_intro")
- if procedure.publiee? && procedure.sva_svr_enabled?
.fr-alert.fr-alert--warning.fr-alert--sm
%p Attention : un changement de ce réglage affectera les éventuels dossiers en cours.
= render Dsfr::RadioButtonListComponent.new(form: f, target: :resume, buttons: resume_buttons)
= f.submit t(".submit"), class: "fr-btn"
= link_to t(".cancel"), admin_procedure_path(procedure.id), class: "fr-btn fr-btn--secondary fr-ml-2w"

View file

@ -0,0 +1,34 @@
module Administrateurs
class SVASVRController < AdministrateurController
before_action :retrieve_procedure
def show
redirect_to edit_admin_procedure_sva_svr_path(@procedure.id)
end
def edit
@configuration = @procedure.sva_svr_configuration
end
def update
@configuration = @procedure.sva_svr_configuration
@configuration.assign_attributes(configuration_params)
if @configuration.valid?
@procedure.update!(sva_svr: @configuration.attributes)
flash.notice = "La configuration SVA/SVR a été mise à jour et prend immédiatement effet pour les nouveaux dossiers."
redirect_to admin_procedure_path(@procedure)
else
flash.now.alert = "Des erreurs empêchent la validation du SVA/SVR. Corrigez les erreurs"
render :edit
end
end
private
def configuration_params
params.require(:sva_svr_configuration).permit(:decision, :period, :unit, :resume)
end
end
end

View file

@ -0,0 +1,27 @@
module ProcedureSVASVRConcern
extend ActiveSupport::Concern
included do
def sva_svr_enabled?
sva? || svr?
end
def sva?
decision == :sva
end
def svr?
decision == :svr
end
def sva_svr_configuration
@sva_svr_configuration ||= SVASVRConfiguration.new(sva_svr)
end
private
def decision
sva_svr.fetch("decision", nil)&.to_sym
end
end
end

View file

@ -69,6 +69,7 @@ class Procedure < ApplicationRecord
include EncryptableConcern
include InitiationProcedureConcern
include ProcedureGroupeInstructeurAPIHackConcern
include ProcedureSVASVRConcern
include Discard::Model
self.discard_column = :hidden_at

View file

@ -0,0 +1,28 @@
class SVASVRConfiguration
include ActiveModel::Model
include ActiveModel::Attributes
attribute :decision, default: 'disabled'
attribute :period, default: 2
attribute :unit, default: 'months'
attribute :resume, default: 'continue'
DECISION_OPTIONS = ['disabled', 'sva', 'svr']
UNIT_OPTIONS = ['days', 'weeks', 'months']
RESUME_OPTIONS = ['continue', 'reset']
validates :decision, inclusion: { in: DECISION_OPTIONS }
validates :period, presence: true, numericality: { only_integer: true }, if: -> { enabled? }
validates :unit, presence: true, inclusion: { in: UNIT_OPTIONS }, if: -> { enabled? }
validates :resume, presence: true, inclusion: { in: RESUME_OPTIONS }, if: -> { enabled? }
def self.unit_options
UNIT_OPTIONS
end
private
def enabled?
decision != 'disabled'
end
end

View file

@ -0,0 +1,9 @@
= render partial: 'administrateurs/breadcrumbs',
locals: { steps: [['Démarches', admin_procedures_path],
["#{@procedure.libelle.truncate_words(10)}", admin_procedure_path(@procedure)],
["Configuration SVA/SVR"]] }
.fr-container.fr-my-5w
%h1.fr-h1 Règle du Silence Vaut Accord ou Silence Vaut Rejet
= render Procedure::SVASVRFormComponent.new(procedure: @procedure, configuration: @configuration)

View file

@ -0,0 +1,75 @@
require 'rails_helper'
describe SVASVRConfiguration, type: :model do
subject(:sva_svr_config) do
SVASVRConfiguration.new(
decision: decision,
period: period,
unit: unit,
resume: resume
)
end
let(:decision) { 'disabled' }
let(:period) { 2 }
let(:unit) { 'months' }
let(:resume) { 'continue' }
describe 'validations' do
context 'when decision is "disabled"' do
it 'is valid even if period, unit and resume are nil' do
sva_svr_config.period = nil
sva_svr_config.unit = nil
sva_svr_config.resume = nil
expect(sva_svr_config).to be_valid
end
end
context 'when decision is not in DECISION_OPTIONS' do
let(:decision) { 'invalid_decision' }
it 'is not valid' do
expect(sva_svr_config).not_to be_valid
end
end
context 'when decision is not "disabled"' do
let(:decision) { 'sva' }
it { expect(sva_svr_config).to be_valid }
it 'is not valid if period is nil' do
sva_svr_config.period = nil
expect(sva_svr_config).not_to be_valid
end
it 'is not valid if unit is nil or not in UNIT_OPTIONS' do
sva_svr_config.unit = nil
expect(sva_svr_config).not_to be_valid
sva_svr_config.unit = 'years'
expect(sva_svr_config).not_to be_valid
end
it 'is not valid if resume is nil or not in RESUME_OPTIONS' do
sva_svr_config.resume = nil
expect(sva_svr_config).not_to be_valid
sva_svr_config.resume = 'pause'
expect(sva_svr_config).not_to be_valid
end
it 'is not valid if period is not an integer' do
sva_svr_config.period = 3.14
expect(sva_svr_config).not_to be_valid
end
end
end
end