Merge pull request #9738 from colinux/validate-pending-correction
ETQ usager modifiant un dossier en construction je n'ai plus besoin de cocher la case de correction effectuée
This commit is contained in:
commit
15ff65429b
15 changed files with 175 additions and 53 deletions
|
@ -12,12 +12,18 @@ class Dossiers::ErrorsFullMessagesComponent < ApplicationComponent
|
||||||
formated_errors = @errors.to_enum # ActiveModel::Errors.to_a is an alias to full_messages, we don't want that
|
formated_errors = @errors.to_enum # ActiveModel::Errors.to_a is an alias to full_messages, we don't want that
|
||||||
.to_a # but enum.to_a gives back an array
|
.to_a # but enum.to_a gives back an array
|
||||||
.uniq { |error| [error.inner_error.base] } # dedup cumulated errors from dossier.champs, dossier.champs_public, dossier.champs_private which run the validator one time per association
|
.uniq { |error| [error.inner_error.base] } # dedup cumulated errors from dossier.champs, dossier.champs_public, dossier.champs_private which run the validator one time per association
|
||||||
.map { |error| to_error_descriptor(error.message, error.inner_error.base) }
|
.map { |error| to_error_descriptor(error) }
|
||||||
yield(Array(formated_errors[0..2]), Array(formated_errors[3..]))
|
yield(Array(formated_errors[0..2]), Array(formated_errors[3..]))
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_error_descriptor(str_error, model)
|
def to_error_descriptor(error)
|
||||||
ErrorDescriptor.new("##{model.labelledby_id}", model.libelle.truncate(200), str_error)
|
model = error.inner_error.base
|
||||||
|
|
||||||
|
if model.respond_to?(:libelle) # a Champ or something acting as a Champ
|
||||||
|
ErrorDescriptor.new("##{model.labelledby_id}", model.libelle.truncate(200), error.message)
|
||||||
|
else
|
||||||
|
ErrorDescriptor.new("##{model.model_name.singular}_#{error.attribute}", model.class.human_attribute_name(error.attribute), error.message)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render?
|
def render?
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Dossiers::PendingCorrectionCheckboxComponent < ApplicationComponent
|
||||||
|
attr_reader :dossier
|
||||||
|
|
||||||
|
# Pass the editing fork origin, ie. dossier en construction holding the correction
|
||||||
|
def initialize(dossier:)
|
||||||
|
@dossier = dossier
|
||||||
|
end
|
||||||
|
|
||||||
|
def render?
|
||||||
|
return false unless dossier.procedure.sva_svr_enabled?
|
||||||
|
|
||||||
|
dossier.pending_correction?
|
||||||
|
end
|
||||||
|
|
||||||
|
def error? = dossier.errors.include?(:pending_correction)
|
||||||
|
|
||||||
|
def error_message
|
||||||
|
dossier.errors.generate_message(:pending_correction, :blank)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_box_aria_attributes
|
||||||
|
return unless error?
|
||||||
|
|
||||||
|
{ describedby: :dossier_pending_correction_error_messages }
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
en:
|
||||||
|
confirm_label: I certify that I have made all corrections requested by the administration.
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
fr:
|
||||||
|
confirm_label: Je certifie avoir effectué toutes les corrections demandées par l’administration.
|
|
@ -0,0 +1,10 @@
|
||||||
|
.fr-checkbox-group.fr-my-3w{ class: class_names("fr-checkbox-group--error" => error?) }
|
||||||
|
= check_box_tag field_name(:dossier, :pending_correction), "1", false, form: "form-submit-en-construction", required: true, aria: check_box_aria_attributes
|
||||||
|
%label.fr-label{ for: :dossier_pending_correction }
|
||||||
|
= t('.confirm_label')
|
||||||
|
= render EditableChamp::AsteriskMandatoryComponent.new
|
||||||
|
|
||||||
|
- if error?
|
||||||
|
#dossier_pending_correction_error_messages.fr-messages-group{ aria: { live: "assertlive" } }
|
||||||
|
%p.fr-message.fr-message--error= error_message
|
||||||
|
|
|
@ -250,19 +250,23 @@ module Users
|
||||||
|
|
||||||
def submit_en_construction
|
def submit_en_construction
|
||||||
@dossier = dossier_with_champs(pj_template: false)
|
@dossier = dossier_with_champs(pj_template: false)
|
||||||
|
editing_fork_origin = @dossier.editing_fork_origin
|
||||||
|
|
||||||
|
if cast_bool(params.dig(:dossier, :pending_correction))
|
||||||
|
editing_fork_origin.resolve_pending_correction
|
||||||
|
end
|
||||||
|
|
||||||
@errors = submit_dossier_and_compute_errors
|
@errors = submit_dossier_and_compute_errors
|
||||||
|
|
||||||
if @errors.blank?
|
if @errors.blank?
|
||||||
pending_correction_confirm = cast_bool(params.dig(:dossier, :pending_correction_confirm))
|
|
||||||
editing_fork_origin = @dossier.editing_fork_origin
|
|
||||||
editing_fork_origin.merge_fork(@dossier)
|
editing_fork_origin.merge_fork(@dossier)
|
||||||
editing_fork_origin.submit_en_construction!(pending_correction_confirm:)
|
editing_fork_origin.submit_en_construction!
|
||||||
|
|
||||||
redirect_to dossier_path(editing_fork_origin)
|
redirect_to dossier_path(editing_fork_origin)
|
||||||
else
|
else
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
@dossier = @dossier.editing_fork_origin
|
@dossier = editing_fork_origin
|
||||||
render :modifier
|
render :modifier
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -537,10 +541,18 @@ module Users
|
||||||
@dossier.validate(:champs_public_value)
|
@dossier.validate(:champs_public_value)
|
||||||
|
|
||||||
errors = @dossier.errors
|
errors = @dossier.errors
|
||||||
@dossier.check_mandatory_and_visible_champs.map do |error_on_champ|
|
@dossier.check_mandatory_and_visible_champs.each do |error_on_champ|
|
||||||
errors.import(error_on_champ)
|
errors.import(error_on_champ)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if @dossier.editing_fork_origin&.pending_correction?
|
||||||
|
@dossier.editing_fork_origin.validate(:champs_public_value)
|
||||||
|
@dossier.editing_fork_origin.errors.where(:pending_correction).each do |error|
|
||||||
|
errors.import(error)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
errors
|
errors
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ module DossierCorrectableConcern
|
||||||
|
|
||||||
scope :with_pending_corrections, -> { joins(:corrections).where(corrections: { resolved_at: nil }) }
|
scope :with_pending_corrections, -> { joins(:corrections).where(corrections: { resolved_at: nil }) }
|
||||||
|
|
||||||
|
validate :validate_pending_correction, on: :champs_public_value
|
||||||
|
|
||||||
def flag_as_pending_correction!(commentaire, reason = nil)
|
def flag_as_pending_correction!(commentaire, reason = nil)
|
||||||
return unless may_flag_as_pending_correction?
|
return unless may_flag_as_pending_correction?
|
||||||
|
|
||||||
|
@ -38,11 +40,26 @@ module DossierCorrectableConcern
|
||||||
pending_corrections.exists?
|
pending_corrections.exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resolve_pending_correction
|
||||||
|
return if pending_correction.nil?
|
||||||
|
|
||||||
|
pending_correction.resolved_at = Time.current
|
||||||
|
end
|
||||||
|
|
||||||
def resolve_pending_correction!
|
def resolve_pending_correction!
|
||||||
pending_corrections.update!(resolved_at: Time.current)
|
resolve_pending_correction
|
||||||
|
pending_correction&.save!
|
||||||
|
|
||||||
pending_corrections.reset
|
pending_corrections.reset
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_pending_correction
|
||||||
|
return unless procedure.sva_svr_enabled?
|
||||||
|
return if pending_correction.nil? || pending_correction.resolved?
|
||||||
|
|
||||||
|
errors.add(:pending_correction, :blank)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def log_pending_correction_operation(commentaire, reason)
|
def log_pending_correction_operation(commentaire, reason)
|
||||||
|
|
|
@ -888,16 +888,14 @@ class Dossier < ApplicationRecord
|
||||||
RoutingEngine.compute(self)
|
RoutingEngine.compute(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def submit_en_construction!(pending_correction_confirm: false)
|
def submit_en_construction!
|
||||||
self.traitements.submit_en_construction
|
self.traitements.submit_en_construction
|
||||||
save!
|
save!
|
||||||
|
|
||||||
RoutingEngine.compute(self)
|
RoutingEngine.compute(self)
|
||||||
|
|
||||||
if pending_correction_confirm
|
resolve_pending_correction!
|
||||||
resolve_pending_correction!
|
process_sva_svr!
|
||||||
process_sva_svr!
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_passer_en_instruction(h)
|
def after_passer_en_instruction(h)
|
||||||
|
|
|
@ -24,10 +24,6 @@
|
||||||
|
|
||||||
= render EditableChamp::SectionComponent.new(champs: dossier_for_editing.champs_public)
|
= render EditableChamp::SectionComponent.new(champs: dossier_for_editing.champs_public)
|
||||||
|
|
||||||
- if dossier.pending_correction?
|
= render Dossiers::PendingCorrectionCheckboxComponent.new(dossier: dossier)
|
||||||
.fr-checkbox-group.fr-my-3w
|
|
||||||
= check_box_tag field_name(:dossier, :pending_correction_confirm), "1", false, form: "form-submit-en-construction"
|
|
||||||
%label.fr-label{ for: :dossier_pending_correction_confirm }= t('views.shared.dossiers.edit.pending_correction.confirm_label')
|
|
||||||
|
|
||||||
|
|
||||||
= render Dossiers::EditFooterComponent.new(dossier: dossier_for_editing, annotation: false)
|
= render Dossiers::EditFooterComponent.new(dossier: dossier_for_editing, annotation: false)
|
||||||
|
|
|
@ -333,8 +333,6 @@ en:
|
||||||
updated_at: "Updated on %{datetime}"
|
updated_at: "Updated on %{datetime}"
|
||||||
edit:
|
edit:
|
||||||
autosave: Your file is automatically saved after each modification. You can close the window at any time and pick up where you left off later.
|
autosave: Your file is automatically saved after each modification. You can close the window at any time and pick up where you left off later.
|
||||||
pending_correction:
|
|
||||||
confirm_label: I certify that I have made all corrections requested by the administration.
|
|
||||||
messages:
|
messages:
|
||||||
form:
|
form:
|
||||||
send_message: "Send message"
|
send_message: "Send message"
|
||||||
|
|
|
@ -333,8 +333,6 @@ fr:
|
||||||
updated_at: "Modifié le %{datetime}"
|
updated_at: "Modifié le %{datetime}"
|
||||||
edit:
|
edit:
|
||||||
autosave: Votre dossier est enregistré automatiquement après chaque modification. Vous pouvez à tout moment fermer la fenêtre et reprendre plus tard là où vous en étiez.
|
autosave: Votre dossier est enregistré automatiquement après chaque modification. Vous pouvez à tout moment fermer la fenêtre et reprendre plus tard là où vous en étiez.
|
||||||
pending_correction:
|
|
||||||
confirm_label: Je certifie avoir effectué toutes les corrections demandées par l’administration.
|
|
||||||
messages:
|
messages:
|
||||||
form:
|
form:
|
||||||
send_message: "Envoyer le message"
|
send_message: "Envoyer le message"
|
||||||
|
|
|
@ -8,6 +8,7 @@ en:
|
||||||
dossier:
|
dossier:
|
||||||
id: "File number"
|
id: "File number"
|
||||||
state: "State"
|
state: "State"
|
||||||
|
pending_correction: Requested correction
|
||||||
dossier/state: &state
|
dossier/state: &state
|
||||||
brouillon: "Draft"
|
brouillon: "Draft"
|
||||||
en_construction: "In progress"
|
en_construction: "In progress"
|
||||||
|
@ -24,3 +25,9 @@ en:
|
||||||
state: "State"
|
state: "State"
|
||||||
traitement/state:
|
traitement/state:
|
||||||
<<: *state
|
<<: *state
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
dossier:
|
||||||
|
attributes:
|
||||||
|
pending_correction:
|
||||||
|
blank: Check to confirm that you have made the requested corrections.
|
||||||
|
|
|
@ -12,6 +12,7 @@ fr:
|
||||||
date_previsionnelle: "La date de début prévisionnelle"
|
date_previsionnelle: "La date de début prévisionnelle"
|
||||||
state: "État"
|
state: "État"
|
||||||
autorisation_donnees: Acceptation des CGU
|
autorisation_donnees: Acceptation des CGU
|
||||||
|
pending_correction: Demande de correction
|
||||||
dossier/state: &state
|
dossier/state: &state
|
||||||
brouillon: "Brouillon"
|
brouillon: "Brouillon"
|
||||||
en_construction: "En construction"
|
en_construction: "En construction"
|
||||||
|
@ -28,3 +29,9 @@ fr:
|
||||||
state: "État"
|
state: "État"
|
||||||
traitement/state:
|
traitement/state:
|
||||||
<<: *state
|
<<: *state
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
dossier:
|
||||||
|
attributes:
|
||||||
|
pending_correction:
|
||||||
|
blank: "Cochez la case indiquant avoir effectué les corrections demandées."
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RSpec.describe Dossiers::PendingCorrectionCheckboxComponent, type: :component do
|
||||||
|
subject { render_inline(described_class.new(dossier:)) }
|
||||||
|
|
||||||
|
let(:procedure) { create(:procedure) }
|
||||||
|
let(:dossier) { create(:dossier, :en_construction, procedure:) }
|
||||||
|
|
||||||
|
context 'when dossier has no pending correction' do
|
||||||
|
it 'renders nothing' do
|
||||||
|
expect(subject.to_html).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when dossier has pending correction' do
|
||||||
|
before do
|
||||||
|
create(:dossier_correction, dossier:)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders nothing' do
|
||||||
|
expect(subject.to_html).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when procedure is sva' do
|
||||||
|
let(:procedure) { create(:procedure, :sva) }
|
||||||
|
|
||||||
|
it 'renders a checkbox' do
|
||||||
|
expect(subject).to have_selector('input[type="checkbox"][name="dossier[pending_correction]"]')
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there are error on checkbox' do
|
||||||
|
before do
|
||||||
|
dossier.errors.add(:pending_correction, :blank)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders the error' do
|
||||||
|
expect(subject).to have_content("Cochez la case")
|
||||||
|
expect(subject).to have_selector('.fr-checkbox-group--error')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -567,50 +567,46 @@ describe Users::DossiersController, type: :controller do
|
||||||
context "when there are pending correction" do
|
context "when there are pending correction" do
|
||||||
let!(:correction) { create(:dossier_correction, dossier: dossier) }
|
let!(:correction) { create(:dossier_correction, dossier: dossier) }
|
||||||
|
|
||||||
subject { post :submit_en_construction, params: { id: dossier.id, dossier: { pending_correction_confirm: "1" } } }
|
subject { post :submit_en_construction, params: { id: dossier.id } }
|
||||||
|
|
||||||
it "resolve correction" do
|
it "resolves correction automatically" do
|
||||||
expect { subject }.to change { correction.reload.resolved_at }.to be_truthy
|
expect { subject }.to change { correction.reload.resolved_at }.to be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when procedure has sva enabled' do
|
context 'when procedure has sva enabled' do
|
||||||
let(:procedure) { create(:procedure, :sva) }
|
let(:procedure) { create(:procedure, :sva) }
|
||||||
let!(:dossier) { create(:dossier, :en_construction, procedure:, user:) }
|
let(:dossier) { create(:dossier, :en_construction, procedure:, user:) }
|
||||||
|
let!(:correction) { create(:dossier_correction, dossier: dossier) }
|
||||||
|
|
||||||
it 'passe automatiquement en instruction' do
|
subject { post :submit_en_construction, params: { id: dossier.id, dossier: { pending_correction: pending_correction_value } } }
|
||||||
expect(dossier.pending_correction?).to be_truthy
|
|
||||||
|
|
||||||
subject
|
context 'when resolving correction' do
|
||||||
dossier.reload
|
let(:pending_correction_value) { "1" }
|
||||||
|
it 'passe automatiquement en instruction' do
|
||||||
|
expect(dossier.pending_correction?).to be_truthy
|
||||||
|
|
||||||
expect(dossier).to be_en_instruction
|
subject
|
||||||
expect(dossier.pending_correction?).to be_falsey
|
dossier.reload
|
||||||
expect(dossier.en_instruction_at).to within(5.seconds).of(Time.current)
|
|
||||||
|
expect(dossier).to be_en_instruction
|
||||||
|
expect(dossier.pending_correction?).to be_falsey
|
||||||
|
expect(dossier.en_instruction_at).to within(5.seconds).of(Time.current)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when there is sva without confirming correction' do
|
context 'when not resolving correction' do
|
||||||
let!(:correction) { create(:dossier_correction, dossier: dossier) }
|
render_views
|
||||||
|
|
||||||
subject { post :submit_en_construction, params: { id: dossier.id } }
|
let(:pending_correction_value) { "" }
|
||||||
|
it 'does not passe automatiquement en instruction' do
|
||||||
|
subject
|
||||||
|
dossier.reload
|
||||||
|
|
||||||
it "does not resolve correction" do
|
expect(dossier).to be_en_construction
|
||||||
expect { subject }.not_to change { correction.reload.resolved_at }
|
expect(dossier.pending_correction?).to be_truthy
|
||||||
end
|
|
||||||
|
|
||||||
context 'when procedure has sva enabled' do
|
expect(response.body).to include("Cochez la case")
|
||||||
let(:procedure) { create(:procedure, :sva) }
|
end
|
||||||
let!(:dossier) { create(:dossier, :en_construction, procedure:, user:) }
|
|
||||||
|
|
||||||
it 'does not passe automatiquement en instruction' do
|
|
||||||
expect(dossier.pending_correction?).to be_truthy
|
|
||||||
|
|
||||||
subject
|
|
||||||
dossier.reload
|
|
||||||
|
|
||||||
expect(dossier).to be_en_construction
|
|
||||||
expect(dossier.pending_correction?).to be_truthy
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue