From ba076357c5fde65da9db98e6093356a1faf72f9a Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Wed, 22 Nov 2023 12:06:21 +0100 Subject: [PATCH] feat(dossier): submit en construction resolve automatically correction except for sva --- .../errors_full_messages_component.rb | 12 +++- .../pending_correction_checkbox_component.rb | 28 ++++++++++ ...nding_correction_checkbox_component.en.yml | 3 + ...nding_correction_checkbox_component.fr.yml | 3 + ...ng_correction_checkbox_component.html.haml | 10 ++++ app/controllers/users/dossiers_controller.rb | 22 ++++++-- .../concerns/dossier_correctable_concern.rb | 19 ++++++- app/models/dossier.rb | 8 +-- app/views/shared/dossiers/_edit.html.haml | 6 +- config/locales/en.yml | 2 - config/locales/fr.yml | 2 - config/locales/models/dossier/en.yml | 7 +++ config/locales/models/dossier/fr.yml | 7 +++ ...ding_correction_checkbox_component_spec.rb | 43 ++++++++++++++ .../users/dossiers_controller_spec.rb | 56 +++++++++---------- 15 files changed, 175 insertions(+), 53 deletions(-) create mode 100644 app/components/dossiers/pending_correction_checkbox_component.rb create mode 100644 app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.en.yml create mode 100644 app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.fr.yml create mode 100644 app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.html.haml create mode 100644 spec/components/dossiers/pending_correction_checkbox_component_spec.rb diff --git a/app/components/dossiers/errors_full_messages_component.rb b/app/components/dossiers/errors_full_messages_component.rb index 760cd3aa6..fd8bafd94 100644 --- a/app/components/dossiers/errors_full_messages_component.rb +++ b/app/components/dossiers/errors_full_messages_component.rb @@ -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 .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 - .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..])) end - def to_error_descriptor(str_error, model) - ErrorDescriptor.new("##{model.labelledby_id}", model.libelle.truncate(200), str_error) + def to_error_descriptor(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 def render? diff --git a/app/components/dossiers/pending_correction_checkbox_component.rb b/app/components/dossiers/pending_correction_checkbox_component.rb new file mode 100644 index 000000000..8eb0926f7 --- /dev/null +++ b/app/components/dossiers/pending_correction_checkbox_component.rb @@ -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 diff --git a/app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.en.yml b/app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.en.yml new file mode 100644 index 000000000..2513c1f1a --- /dev/null +++ b/app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.en.yml @@ -0,0 +1,3 @@ +--- +en: + confirm_label: I certify that I have made all corrections requested by the administration. diff --git a/app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.fr.yml b/app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.fr.yml new file mode 100644 index 000000000..649cece34 --- /dev/null +++ b/app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.fr.yml @@ -0,0 +1,3 @@ +--- +fr: + confirm_label: Je certifie avoir effectué toutes les corrections demandées par l’administration. diff --git a/app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.html.haml b/app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.html.haml new file mode 100644 index 000000000..fc27bf9bd --- /dev/null +++ b/app/components/dossiers/pending_correction_checkbox_component/pending_correction_checkbox_component.html.haml @@ -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 + diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index 88e50718b..9dc684519 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -250,19 +250,23 @@ module Users def submit_en_construction @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 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.submit_en_construction!(pending_correction_confirm:) + editing_fork_origin.submit_en_construction! redirect_to dossier_path(editing_fork_origin) else respond_to do |format| format.html do - @dossier = @dossier.editing_fork_origin + @dossier = editing_fork_origin render :modifier end @@ -537,10 +541,18 @@ module Users @dossier.validate(:champs_public_value) 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) 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 end diff --git a/app/models/concerns/dossier_correctable_concern.rb b/app/models/concerns/dossier_correctable_concern.rb index 69790fa9e..7390fef4e 100644 --- a/app/models/concerns/dossier_correctable_concern.rb +++ b/app/models/concerns/dossier_correctable_concern.rb @@ -9,6 +9,8 @@ module DossierCorrectableConcern 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) return unless may_flag_as_pending_correction? @@ -38,11 +40,26 @@ module DossierCorrectableConcern pending_corrections.exists? end + def resolve_pending_correction + return if pending_correction.nil? + + pending_correction.resolved_at = Time.current + end + def resolve_pending_correction! - pending_corrections.update!(resolved_at: Time.current) + resolve_pending_correction + pending_correction&.save! + pending_corrections.reset 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 def log_pending_correction_operation(commentaire, reason) diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 3bf8597dc..285eeff29 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -888,16 +888,14 @@ class Dossier < ApplicationRecord RoutingEngine.compute(self) end - def submit_en_construction!(pending_correction_confirm: false) + def submit_en_construction! self.traitements.submit_en_construction save! RoutingEngine.compute(self) - if pending_correction_confirm - resolve_pending_correction! - process_sva_svr! - end + resolve_pending_correction! + process_sva_svr! end def after_passer_en_instruction(h) diff --git a/app/views/shared/dossiers/_edit.html.haml b/app/views/shared/dossiers/_edit.html.haml index cac9e73d4..11d21382c 100644 --- a/app/views/shared/dossiers/_edit.html.haml +++ b/app/views/shared/dossiers/_edit.html.haml @@ -24,10 +24,6 @@ = render EditableChamp::SectionComponent.new(champs: dossier_for_editing.champs_public) - - if dossier.pending_correction? - .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::PendingCorrectionCheckboxComponent.new(dossier: dossier) = render Dossiers::EditFooterComponent.new(dossier: dossier_for_editing, annotation: false) diff --git a/config/locales/en.yml b/config/locales/en.yml index 8b97107cb..560c57f90 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -333,8 +333,6 @@ en: updated_at: "Updated on %{datetime}" 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. - pending_correction: - confirm_label: I certify that I have made all corrections requested by the administration. messages: form: send_message: "Send message" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index ace408772..e38cc5a07 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -333,8 +333,6 @@ fr: updated_at: "Modifié le %{datetime}" 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. - pending_correction: - confirm_label: Je certifie avoir effectué toutes les corrections demandées par l’administration. messages: form: send_message: "Envoyer le message" diff --git a/config/locales/models/dossier/en.yml b/config/locales/models/dossier/en.yml index ac3b34fbe..e5c5e7b04 100644 --- a/config/locales/models/dossier/en.yml +++ b/config/locales/models/dossier/en.yml @@ -8,6 +8,7 @@ en: dossier: id: "File number" state: "State" + pending_correction: Requested correction dossier/state: &state brouillon: "Draft" en_construction: "In progress" @@ -24,3 +25,9 @@ en: state: "State" traitement/state: <<: *state + errors: + models: + dossier: + attributes: + pending_correction: + blank: Check to confirm that you have made the requested corrections. diff --git a/config/locales/models/dossier/fr.yml b/config/locales/models/dossier/fr.yml index 4c5765e0f..fbc4c426b 100644 --- a/config/locales/models/dossier/fr.yml +++ b/config/locales/models/dossier/fr.yml @@ -12,6 +12,7 @@ fr: date_previsionnelle: "La date de début prévisionnelle" state: "État" autorisation_donnees: Acceptation des CGU + pending_correction: Demande de correction dossier/state: &state brouillon: "Brouillon" en_construction: "En construction" @@ -28,3 +29,9 @@ fr: state: "État" traitement/state: <<: *state + errors: + models: + dossier: + attributes: + pending_correction: + blank: "Cochez la case indiquant avoir effectué les corrections demandées." diff --git a/spec/components/dossiers/pending_correction_checkbox_component_spec.rb b/spec/components/dossiers/pending_correction_checkbox_component_spec.rb new file mode 100644 index 000000000..fe45e92c5 --- /dev/null +++ b/spec/components/dossiers/pending_correction_checkbox_component_spec.rb @@ -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 diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb index 29eb3fb49..8d97cbdc1 100644 --- a/spec/controllers/users/dossiers_controller_spec.rb +++ b/spec/controllers/users/dossiers_controller_spec.rb @@ -567,50 +567,46 @@ describe Users::DossiersController, type: :controller do context "when there are pending correction" do 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 end context 'when procedure has sva enabled' do 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 - expect(dossier.pending_correction?).to be_truthy + subject { post :submit_en_construction, params: { id: dossier.id, dossier: { pending_correction: pending_correction_value } } } - subject - dossier.reload + context 'when resolving correction' do + let(:pending_correction_value) { "1" } + it 'passe automatiquement en instruction' do + expect(dossier.pending_correction?).to be_truthy - 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) + subject + dossier.reload + + 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 - context 'when there is sva without confirming correction' do - let!(:correction) { create(:dossier_correction, dossier: dossier) } + context 'when not resolving correction' do + 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 { subject }.not_to change { correction.reload.resolved_at } - end + expect(dossier).to be_en_construction + expect(dossier.pending_correction?).to be_truthy - context 'when procedure has sva enabled' do - let(:procedure) { create(:procedure, :sva) } - 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 + expect(response.body).to include("Cochez la case") + end end end end