diff --git a/app/assets/stylesheets/conditions_component.scss b/app/assets/stylesheets/conditions_component.scss index 055e9b4f903..59f8bf6b90c 100644 --- a/app/assets/stylesheets/conditions_component.scss +++ b/app/assets/stylesheets/conditions_component.scss @@ -57,5 +57,14 @@ form.form > .conditionnel { select.alert { border-color: $dark-red; } + + &:first-child { + padding-left: 0; + } + + &:last-child { + text-align: right; + padding-right: 0; + } } } diff --git a/app/components/conditions/ineligibilite_rules_component/ineligibilite_rules_component.html.haml b/app/components/conditions/ineligibilite_rules_component/ineligibilite_rules_component.html.haml index 547a2ad8560..3136181671f 100644 --- a/app/components/conditions/ineligibilite_rules_component/ineligibilite_rules_component.html.haml +++ b/app/components/conditions/ineligibilite_rules_component/ineligibilite_rules_component.html.haml @@ -1,21 +1,30 @@ %div{ id: dom_id(@draft_revision, :ineligibilite_rules) } = render Procedure::PendingRepublishComponent.new(procedure: @draft_revision.procedure, render_if: pending_changes?) = render Conditions::ConditionsErrorsComponent.new(conditions: condition_per_row, source_tdcs: @source_tdcs) - %fieldset.fr-fieldset - %legend.fr-mx-1w.fr-label.fr-py-0.fr-mb-1w.fr-mt-2w - Règles d’inéligibilité - %span.fr-hint-text Vous pouvez utiliser 1 ou plusieurs critère pour bloquer le dépot + .fr-fieldset + = form_for(@draft_revision, url: change_admin_procedure_ineligibilite_rules_path(@draft_revision.procedure_id), html: { id: 'ineligibilite_form', class: 'width-100' }) do |f| + .fr-fieldset__element + .fr-toggle.fr-toggle--label-left + = f.check_box :ineligibilite_enabled, class: 'fr-toggle__input', data: @opt + = f.label :ineligibilite_enabled, "Bloquer le dépôt des dossiers répondant à des conditions d’inéligibilité", data: { 'fr-checked-label': "Activé", 'fr-unchecked-label': "Désactivé" }, class: 'fr-toggle__label' + + .fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :ineligibilite_message, input_type: :text_area, opts: {rows: 5}) + + .fr-mx-1w.fr-label.fr-py-0.fr-mb-1w.fr-mt-2w + Conditions d’inéligibilité + %span.fr-hint-text Vous pouvez utiliser une ou plusieurs condtions pour bloquer le dépot. .fr-fieldset__element = form_tag admin_procedure_ineligibilite_rules_path(@draft_revision.procedure_id), method: :patch, data: { turbo: true, controller: 'autosave' }, class: 'form width-100' do .conditionnel.width-100 %table.condition-table - %thead - %tr - %th.fr-pt-0.far-left - %th.fr-pt-0.target Champ Cible - %th.fr-pt-0.operator Opérateur - %th.fr-pt-0.value Valeur - %th.fr-pt-0.delete-column + - if rows.size > 0 + %thead + %tr + %th.fr-pt-0.far-left + %th.fr-pt-0.target Champ Cible + %th.fr-pt-0.operator Opérateur + %th.fr-pt-0.value Valeur + %th.fr-pt-0.delete-column %tbody - rows.each.with_index do |(targeted_champ, operator_name, value), row_index| %tr @@ -28,15 +37,13 @@ %tr %td.text-right{ colspan: 5 }= add_condition_tag - - - = form_for(@draft_revision, url: change_admin_procedure_ineligibilite_rules_path(@draft_revision.procedure_id)) do |f| - .fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :ineligibilite_message, input_type: :text_area, opts: {rows: 5}) - .fr-fieldset__element - .fr-toggle - = f.check_box :ineligibilite_enabled, class: 'fr-toggle__input', data: @opt - = f.label :ineligibilite_enabled, "Inéligibilité des dossiers", data: { 'fr-checked-label': "Actif", 'fr-unchecked-label': "Inactif" }, class: 'fr-toggle__label' - %p.fr-hint-text Passer l’intérrupteur sur activé pour que les critères d’inéligibilité configurés s'appliquent - - - = render Procedure::FixedFooterComponent.new(procedure: @draft_revision.procedure, form: f, extra_class_names: 'fr-col-offset-md-2 fr-col-md-8') + .padded-fixed-footer + .fixed-footer + .fr-container + .fr-grid-row.fr-col-offset-md-2.fr-col-md-8 + .fr-col-12 + %ul.fr-btns-group.fr-btns-group--inline-md + %li + = link_to "Annuler et revenir à l'écran de gestion", admin_procedure_path(id: @draft_revision.procedure), class: 'fr-btn fr-btn--secondary', data: { confirm: 'Si vous avez fait des modifications elles ne seront pas sauvegardées.'} + %li + = button_tag "Enregistrer", class: "fr-btn", form: 'ineligibilite_form' diff --git a/app/components/dossiers/edit_footer_component.rb b/app/components/dossiers/edit_footer_component.rb index ac77bbfeab8..5f5bb89801a 100644 --- a/app/components/dossiers/edit_footer_component.rb +++ b/app/components/dossiers/edit_footer_component.rb @@ -1,5 +1,5 @@ class Dossiers::EditFooterComponent < ApplicationComponent - delegate :can_passer_en_construction?, :ineligibilite_rules_computable?, to: :@dossier + delegate :can_passer_en_construction?, to: :@dossier def initialize(dossier:, annotation:) @dossier = dossier @@ -27,7 +27,7 @@ def disabled_submit_buttons_options def submit_draft_button_options { class: 'fr-btn fr-btn--sm', - disabled: !owner? || ineligibilite_rules_invalid?, + disabled: !owner? || !can_passer_en_construction?, method: :post, data: { 'disable-with': t('.submitting'), controller: 'autosave-submit', turbo_force: :server } } @@ -36,17 +36,13 @@ def submit_draft_button_options def submit_en_construction_button_options { class: 'fr-btn fr-btn--sm', - disabled: ineligibilite_rules_invalid?, + disabled: !can_passer_en_construction?, method: :post, data: { 'disable-with': t('.submitting'), controller: 'autosave-submit', turbo_force: :server }, form: { id: "form-submit-en-construction" } } end - def ineligibilite_rules_invalid? - ineligibilite_rules_computable? && !can_passer_en_construction? - end - def render? !@dossier.for_procedure_preview? end diff --git a/app/components/dossiers/edit_footer_component/edit_footer_component.html.haml b/app/components/dossiers/edit_footer_component/edit_footer_component.html.haml index fb4ab8fb1e7..2f0f59b2b1a 100644 --- a/app/components/dossiers/edit_footer_component/edit_footer_component.html.haml +++ b/app/components/dossiers/edit_footer_component/edit_footer_component.html.haml @@ -3,12 +3,12 @@ = render Dossiers::AutosaveFooterComponent.new(dossier: @dossier, annotation: annotation?) - if !annotation? && @dossier.can_transition_to_en_construction? - - if ineligibilite_rules_invalid? + - if !can_passer_en_construction? = link_to t('.submit_disabled'), "#", disabled_submit_buttons_options = button_to t('.submit'), brouillon_dossier_url(@dossier), submit_draft_button_options - if @dossier.forked_with_changes? - - if ineligibilite_rules_invalid? + - if !can_passer_en_construction? = link_to t('.submit_disabled'), "#", disabled_submit_buttons_options = button_to t('.submit_changes'), modifier_dossier_url(@dossier.editing_fork_origin), submit_en_construction_button_options diff --git a/app/components/dossiers/invalid_ineligibilite_rules_component.rb b/app/components/dossiers/invalid_ineligibilite_rules_component.rb index fe45272f6bc..526bdbc94cd 100644 --- a/app/components/dossiers/invalid_ineligibilite_rules_component.rb +++ b/app/components/dossiers/invalid_ineligibilite_rules_component.rb @@ -1,5 +1,5 @@ class Dossiers::InvalidIneligibiliteRulesComponent < ApplicationComponent - delegate :can_passer_en_construction?, :ineligibilite_rules_computable?, to: :@dossier + delegate :can_passer_en_construction?, to: :@dossier def initialize(dossier:) @dossier = dossier @@ -7,7 +7,7 @@ def initialize(dossier:) end def render? - ineligibilite_rules_computable? && !can_passer_en_construction? + !can_passer_en_construction? end def error_message diff --git a/app/components/procedure/card/ineligibilite_dossier_component.rb b/app/components/procedure/card/ineligibilite_dossier_component.rb index d69e066230b..b1d371708fb 100644 --- a/app/components/procedure/card/ineligibilite_dossier_component.rb +++ b/app/components/procedure/card/ineligibilite_dossier_component.rb @@ -6,7 +6,7 @@ def initialize(procedure:) def ready? @procedure.draft_revision .conditionable_types_de_champ - .present? + .present? && @procedure.draft_revision.ineligibilite_enabled end def error? diff --git a/app/components/procedure/card/ineligibilite_dossier_component/ineligibilite_dossier_component.fr.yml b/app/components/procedure/card/ineligibilite_dossier_component/ineligibilite_dossier_component.fr.yml index d65f0d535b5..6e78d7da6fa 100644 --- a/app/components/procedure/card/ineligibilite_dossier_component/ineligibilite_dossier_component.fr.yml +++ b/app/components/procedure/card/ineligibilite_dossier_component/ineligibilite_dossier_component.fr.yml @@ -2,7 +2,7 @@ fr: title: Inéligibilité des dossiers state: - pending: Champs à configurer + pending: Désactivé ready: À configurer completed: Activé - subtitle: Gérez vos critères d’inéligibilité en fonction des champs du formulaire + subtitle: Gérez vos conditions d’inéligibilité en fonction des champs du formulaire diff --git a/app/components/procedure/card/ineligibilite_dossier_component/ineligibilite_dossier_component.html.haml b/app/components/procedure/card/ineligibilite_dossier_component/ineligibilite_dossier_component.html.haml index e82e64fad28..aeced88e678 100644 --- a/app/components/procedure/card/ineligibilite_dossier_component/ineligibilite_dossier_component.html.haml +++ b/app/components/procedure/card/ineligibilite_dossier_component/ineligibilite_dossier_component.html.haml @@ -2,11 +2,9 @@ = link_to edit_admin_procedure_ineligibilite_rules_path(@procedure), class: 'fr-tile fr-enlarge-link' do .fr-tile__body.flex.column.align-center.justify-between - if !ready? - %p.fr-badge.fr-badge--warning= t('.state.pending') + %p.fr-badge.fr-badge= t('.state.pending') - elsif error? %p.fr-badge.fr-badge--error À modifier - - elsif !completed? - %p.fr-badge.fr-badge--info= t('.state.ready') - else %p.fr-badge.fr-badge--success= t('.state.completed') %div diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index ebfa2cdb458..1fac35eae9e 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -302,13 +302,10 @@ def submit_en_construction def update @dossier = dossier.en_construction? ? dossier.find_editing_fork(dossier.user) : dossier @dossier = dossier_with_champs(pj_template: false) - @ineligibilite_rules_was_computable = @dossier.ineligibilite_rules_computable? @can_passer_en_construction_was = @dossier.can_passer_en_construction? update_dossier_and_compute_errors @dossier.index_search_terms_later if @dossier.errors.empty? - @ineligibilite_rules_is_computable = @dossier.ineligibilite_rules_computable? @can_passer_en_construction_is = @dossier.can_passer_en_construction? - @ineligibilite_rules_computable_changed = !@ineligibilite_rules_was_computable && @ineligibilite_rules_is_computable respond_to do |format| format.turbo_stream do @to_show, @to_hide, @to_update = champs_to_turbo_update(champs_public_attributes_params, dossier.champs.filter(&:public?)) diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 7a1c611a891..343baf06d0c 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -940,12 +940,9 @@ def check_mandatory_and_visible_champs .filter(&:visible?) .filter(&:mandatory_blank?) .map do |champ| - errors.import(champ.errors.add(:value, :missing)) + champ.errors.add(:value, :missing) end - end - - def ineligibilite_rules_computable? - revision.ineligibilite_rules_computable?(champs_for_revision(scope: :public)) + .each { errors.import(_1) } end def demander_un_avis!(avis) diff --git a/app/models/logic/and.rb b/app/models/logic/and.rb index 11d31a9c005..51537235f63 100644 --- a/app/models/logic/and.rb +++ b/app/models/logic/and.rb @@ -7,12 +7,5 @@ def compute(champs = []) @operands.map { |operand| operand.compute(champs) }.all? end - def computable?(champs = []) - return true if sources.blank? - - champs.filter { _1.stable_id.in?(sources) && _1.visible? } - .all? { _1.value.present? } - end - def to_s(type_de_champs) = "(#{@operands.map { |o| o.to_s(type_de_champs) }.join(' && ')})" end diff --git a/app/models/logic/binary_operator.rb b/app/models/logic/binary_operator.rb index 35f6ce1a71a..812fa0605b1 100644 --- a/app/models/logic/binary_operator.rb +++ b/app/models/logic/binary_operator.rb @@ -42,15 +42,6 @@ def compute(champs = []) l&.send(operation, r) || false end - def computable?(champs = []) - return true if sources.blank? - - visible_champs_sources = champs.filter { _1.stable_id.in?(sources) && _1.visible? } - - return false if visible_champs_sources.size != sources.size - visible_champs_sources.all? { _1.value.present? } - end - def to_s(type_de_champs) = "(#{@left.to_s(type_de_champs)} #{operation} #{@right.to_s(type_de_champs)})" def ==(other) diff --git a/app/models/logic/or.rb b/app/models/logic/or.rb index 96a0fe13323..a0e2dfeae5a 100644 --- a/app/models/logic/or.rb +++ b/app/models/logic/or.rb @@ -7,15 +7,5 @@ def compute(champs = []) @operands.map { |operand| operand.compute(champs) }.any? end - - def computable?(champs = []) - return true if sources.blank? - - visible_champs_sources = champs.filter { _1.stable_id.in?(sources) && _1.visible? } - - return false if visible_champs_sources.blank? - visible_champs_sources.all? { _1.value.present? } || compute(visible_champs_sources) - end - def to_s(type_de_champs = []) = "(#{@operands.map { |o| o.to_s(type_de_champs) }.join(' || ')})" end diff --git a/app/models/procedure_revision.rb b/app/models/procedure_revision.rb index bb7dbb43e14..0a27fec2c91 100644 --- a/app/models/procedure_revision.rb +++ b/app/models/procedure_revision.rb @@ -269,12 +269,6 @@ def conditionable_types_de_champ types_de_champ_for(scope: :public).filter(&:conditionable?) end - def ineligibilite_rules_computable?(champs) - ineligibilite_enabled && ineligibilite_rules&.computable?(champs) - ensure - champs.map(&:reset_visible) # otherwise @visible is cached, then dossier can be updated. champs are not updated - end - private def compute_estimated_fill_duration @@ -496,13 +490,6 @@ def ineligibilite_rules_are_valid? end end - def ineligibilite_rules_are_valid? - if ineligibilite_rules - ineligibilite_rules.errors(types_de_champ_for(scope: :public).to_a) - .each { errors.add(:ineligibilite_rules, :invalid) } - end - end - def replace_type_de_champ_by_clone(coordinate) cloned_type_de_champ = coordinate.type_de_champ.deep_clone do |original, kopy| ClonePiecesJustificativesService.clone_attachments(original, kopy) diff --git a/app/views/administrateurs/ineligibilite_rules/edit.html.haml b/app/views/administrateurs/ineligibilite_rules/edit.html.haml index a76a3046829..6eb91d12f1b 100644 --- a/app/views/administrateurs/ineligibilite_rules/edit.html.haml +++ b/app/views/administrateurs/ineligibilite_rules/edit.html.haml @@ -12,17 +12,17 @@ = render Dsfr::AlertComponent.new(title: nil, size: :sm, state: :info, heading_level: 'h2', extra_class_names: 'fr-my-2w') do |c| - c.with_body do %p - Les dossiers répondant à vos critères d’inéligibilité ne pourront pas être déposés. Plus d’informations sur l’inéligibilité des dossiers dans la + Les dossiers répondant à vos conditions d’inéligibilité ne pourront pas être déposés. Plus d’informations sur l’inéligibilité des dossiers dans la = link_to('doc', ELIGIBILITE_URL, title: "Document sur l’inéligibilité des dossiers", **external_link_attributes) - if !@procedure.draft_revision.conditionable_types_de_champ.present? %p.fr-mt-2w.fr-mb-2w - Pour configurer l’inéligibilité des dossiers, votre formulaire doit comporter au moins un champ supportant les critères d’inéligibilité. Il vous faut donc ajouter au moins un des champs suivant à votre formulaire : + Pour configurer l’inéligibilité des dossiers, votre formulaire doit comporter au moins un champ supportant les conditions d’inéligibilité. Il vous faut donc ajouter au moins un des champs suivant à votre formulaire : %ul - Logic::ChampValue::MANAGED_TYPE_DE_CHAMP.values.each do %li= "« #{t(_1, scope: [:activerecord, :attributes, :type_de_champ, :type_champs])} »" %p.fr-mt-2w - = link_to 'Ajouter un champ supportant les critères d’inéligibilité', champs_admin_procedure_path(@procedure), class: 'fr-link fr-icon-arrow-right-line fr-link--icon-right' + = link_to 'Ajouter un champ supportant les conditions d’inéligibilité', champs_admin_procedure_path(@procedure), class: 'fr-link fr-icon-arrow-right-line fr-link--icon-right' = render Procedure::FixedFooterComponent.new(procedure: @procedure) - else = render Conditions::IneligibiliteRulesComponent.new(draft_revision: @procedure.draft_revision) diff --git a/app/views/users/dossiers/update.turbo_stream.haml b/app/views/users/dossiers/update.turbo_stream.haml index 374291733a7..8224c1abdc6 100644 --- a/app/views/users/dossiers/update.turbo_stream.haml +++ b/app/views/users/dossiers/update.turbo_stream.haml @@ -1,8 +1,7 @@ = render partial: 'shared/dossiers/update_champs', locals: { to_show: @to_show, to_hide: @to_hide, to_update: @to_update, dossier: @dossier } - if !params.key?(:validate) - - if @ineligibilite_rules_is_computable - = turbo_stream.remove(dom_id(@dossier, :ineligibilite_rules_broken)) - - - if (@ineligibilite_rules_computable_changed && !@can_passer_en_construction_is) || (@can_passer_en_construction_was && !@can_passer_en_construction_is) + - if @can_passer_en_construction_was && !@can_passer_en_construction_is = turbo_stream.append('contenu', render(Dossiers::InvalidIneligibiliteRulesComponent.new(dossier: @dossier))) + - else @ineligibilite_rules_is_computable + = turbo_stream.remove(dom_id(@dossier, :ineligibilite_rules_broken)) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 624e141d25b..42896bd24f1 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -610,7 +610,7 @@ fr: otp_attempt: 'Code OTP (uniquement si vous avez déjà activé 2FA)' procedure: zone: La démarche est mise en œuvre par - ineligibilite_rules: "Les règles d’Inéligibilité" + ineligibilite_rules: "Les règles d’inéligibilité" champs: value: Valeur du champ default_mail_attributes: &default_mail_attributes diff --git a/config/locales/models/procedure/fr.yml b/config/locales/models/procedure/fr.yml index 85df92d73dc..5a9dfd9abfc 100644 --- a/config/locales/models/procedure/fr.yml +++ b/config/locales/models/procedure/fr.yml @@ -8,7 +8,7 @@ fr: procedure: hints: description: Décrivez en quelques lignes le contexte, la finalité, etc. - description_target_audience: Décrivez en quelques lignes les destinataires finaux de la démarche, les critères d’éligibilité s’il y en a, les pré-requis, etc. + description_target_audience: Décrivez en quelques lignes les destinataires finaux de la démarche, les conditions d’éligibilité s’il y en a, les pré-requis, etc. description_pj: Décrivez la liste des pièces jointes à fournir s’il y en a lien_site_web: "Il s'agit de la page de votre site web où le lien sera diffusé. Ex: https://exemple.gouv.fr/page_informant_sur_ma_demarche" cadre_juridique: "Exemple: 'https://www.legifrance.gouv.fr/'" diff --git a/config/locales/models/procedure_revision/fr.yml b/config/locales/models/procedure_revision/fr.yml new file mode 100644 index 00000000000..1665415aa6f --- /dev/null +++ b/config/locales/models/procedure_revision/fr.yml @@ -0,0 +1,7 @@ +fr: + activerecord: + attributes: + procedure_revision: + ineligibilite_message: Message d’inéligibilité + hints: + ineligibilite_message: "Ce message sera affiché à l’usager si son dossier est bloqué et lui expliquera la raison de son inéligibilité." diff --git a/spec/components/dossiers/edit_footer_component_spec.rb b/spec/components/dossiers/edit_footer_component_spec.rb index 40e60802b53..4b8e1a77f9f 100644 --- a/spec/components/dossiers/edit_footer_component_spec.rb +++ b/spec/components/dossiers/edit_footer_component_spec.rb @@ -10,14 +10,14 @@ let(:dossier) { create(:dossier, :brouillon) } context 'when dossier can be submitted' do - before { allow(component).to receive(:ineligibilite_rules_invalid?).and_return(false) } + before { allow(component).to receive(:can_passer_en_construction?).and_return(true) } it 'renders submit button without disabled' do expect(subject).to have_selector('button', text: 'Déposer le dossier') end end context 'when dossier can not be submitted' do - before { allow(component).to receive(:ineligibilite_rules_invalid?).and_return(true) } + before { allow(component).to receive(:can_passer_en_construction?).and_return(false) } it 'renders submit button with disabled' do expect(subject).to have_selector('a', text: 'Pourquoi je ne peux pas déposer mon dossier ?') expect(subject).to have_selector('button[disabled]', text: 'Déposer le dossier') @@ -31,7 +31,7 @@ before { allow(dossier).to receive(:forked_with_changes?).and_return(true) } context 'when dossier can be submitted' do - before { allow(component).to receive(:ineligibilite_rules_invalid?).and_return(false) } + before { allow(component).to receive(:can_passer_en_construction?).and_return(true) } it 'renders submit button without disabled' do expect(subject).to have_selector('button', text: 'Déposer les modifications') @@ -39,7 +39,7 @@ end context 'when dossier can not be submitted' do - before { allow(component).to receive(:ineligibilite_rules_invalid?).and_return(true) } + before { allow(component).to receive(:can_passer_en_construction?).and_return(false) } it 'renders submit button with disabled' do expect(subject).to have_selector('a', text: 'Pourquoi je ne peux pas déposer mon dossier ?') diff --git a/spec/components/types_de_champ_editor/editor_component_spec.rb b/spec/components/types_de_champ_editor/editor_component_spec.rb index 5b643995c4a..fb709498363 100644 --- a/spec/components/types_de_champ_editor/editor_component_spec.rb +++ b/spec/components/types_de_champ_editor/editor_component_spec.rb @@ -19,7 +19,7 @@ context 'types_de_champ_private' do let(:is_annotation) { true } it 'does not render public champs errors' do - expect(subject).to have_selector("a", "private") + expect(subject).to have_selector("a", text: "private") expect(subject).to have_text("doit comporter au moins un choix sélectionnable") expect(subject).not_to have_text("public") end diff --git a/spec/controllers/administrateurs/ineligibilite_rules_controller_spec.rb b/spec/controllers/administrateurs/ineligibilite_rules_controller_spec.rb index 5c8f94628de..2a76a054a58 100644 --- a/spec/controllers/administrateurs/ineligibilite_rules_controller_spec.rb +++ b/spec/controllers/administrateurs/ineligibilite_rules_controller_spec.rb @@ -197,14 +197,14 @@ let(:types_de_champ_public) { [] } render_views - it { expect(response.body).to have_link("Ajouter un champ supportant les critères d’inéligibilité") } + it { expect(response.body).to have_link("Ajouter un champ supportant les conditions d’inéligibilité") } end context 'rendered with tdc' do let(:types_de_champ_public) { [{ type: :yes_no }] } render_views - it { expect(response.body).not_to have_link("Ajouter un champ supportant les critères d’inéligibilité") } + it { expect(response.body).not_to have_link("Ajouter un champ supportant les conditions d’inéligibilité") } end end end diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb index 1f78b2f4af0..2a38eb7d7e5 100644 --- a/spec/controllers/users/dossiers_controller_spec.rb +++ b/spec/controllers/users/dossiers_controller_spec.rb @@ -791,26 +791,27 @@ end render_views - context 'when it pass from undefined to true' do + context 'when it switches from true to false' do let(:value) { must_be_greater_than + 1 } it 'raises popup' do subject dossier.reload expect(dossier.can_passer_en_construction?).to be_falsey - expect(assigns(:ineligibilite_rules_was_computable)).to eq(false) - expect(assigns(:ineligibilite_rules_is_computable)).to eq(true) + expect(assigns(:can_passer_en_construction_was)).to eq(true) + expect(assigns(:can_passer_en_construction_is)).to eq(false) expect(response.body).to match(ActionView::RecordIdentifier.dom_id(dossier, :ineligibilite_rules_broken)) end end - context 'when it pass from undefined to false' do + + context 'when it stays true' do let(:value) { must_be_greater_than - 1 } it 'does nothing' do subject dossier.reload expect(dossier.can_passer_en_construction?).to be_truthy - expect(assigns(:ineligibilite_rules_was_computable)).to eq(false) - expect(assigns(:ineligibilite_rules_is_computable)).to eq(true) + expect(assigns(:can_passer_en_construction_was)).to eq(true) + expect(assigns(:can_passer_en_construction_is)).to eq(true) expect(response.body).not_to have_selector("##{ActionView::RecordIdentifier.dom_id(dossier, :ineligibilite_rules_broken)}") end end diff --git a/spec/models/logic/and_spec.rb b/spec/models/logic/and_spec.rb index c0eefc8e825..67f319acb8e 100644 --- a/spec/models/logic/and_spec.rb +++ b/spec/models/logic/and_spec.rb @@ -6,42 +6,6 @@ it { expect(and_from([true, true, false]).compute).to be false } end - describe '#computable?' do - let(:champ_1) { create(:champ_integer_number, value: value_1) } - let(:champ_2) { create(:champ_integer_number, value: value_2) } - - let(:logic) do - ds_and([ - greater_than(champ_value(champ_1.stable_id), constant(1)), - less_than(champ_value(champ_2.stable_id), constant(10)) - ]) - end - - subject { logic.computable?([champ_1, champ_2]) } - - context "when none of champs.value are filled, and logic can't be computed" do - let(:value_1) { nil } - let(:value_2) { nil } - it { is_expected.to be_falsey } - end - context "when one champs has a value (that compute to false) the other has not, and logic keeps waiting for the 2nd value" do - let(:value_1) { 1 } - let(:value_2) { nil } - it { is_expected.to be_falsey } - end - context 'when all champs.value are filled, and logic can be computed' do - let(:value_1) { 1 } - let(:value_2) { 10 } - it { is_expected.to be_truthy } - end - context 'when one champs is not visible and the other has a value, and logic can be computed' do - let(:value_1) { 1 } - let(:value_2) { nil } - before { expect(champ_2).to receive(:visible?).and_return(false) } - it { is_expected.to be_truthy } - end - end - describe '#to_s' do it do expect(and_from([true, false, true]).to_s([])).to eq "(Oui && Non && Oui)" diff --git a/spec/models/logic/binary_operator_spec.rb b/spec/models/logic/binary_operator_spec.rb index f816e81e73f..b7924ebc76a 100644 --- a/spec/models/logic/binary_operator_spec.rb +++ b/spec/models/logic/binary_operator_spec.rb @@ -28,19 +28,6 @@ it { expect(greater_than(constant(2), champ_value(champ.stable_id)).sources).to eq([champ.stable_id]) } it { expect(greater_than(champ_value(champ.stable_id), champ_value(champ2.stable_id)).sources).to eq([champ.stable_id, champ2.stable_id]) } end - - describe '#computable?' do - let(:champ) { create(:champ_integer_number, value: nil) } - - it 'computable?' do - expect(greater_than(champ_value(champ.stable_id), constant(1)).computable?([])).to be(false) - expect(greater_than(champ_value(champ.stable_id), constant(1)).computable?([champ])).to be(false) - allow(champ).to receive(:value).and_return(double(present?: true)) - expect(greater_than(champ_value(champ.stable_id), constant(1)).computable?([champ])).to be(true) - allow(champ).to receive(:visible?).and_return(false) - expect(greater_than(champ_value(champ.stable_id), constant(1)).computable?([champ])).to be(false) - end - end end describe Logic::GreaterThan do diff --git a/spec/models/logic/or_spec.rb b/spec/models/logic/or_spec.rb index 82d5392fb81..1888587d2d9 100644 --- a/spec/models/logic/or_spec.rb +++ b/spec/models/logic/or_spec.rb @@ -7,49 +7,6 @@ it { expect(or_from([false, false, false]).compute).to be false } end - describe '#computable?' do - let(:champ_1) { create(:champ_integer_number, value: value_1) } - let(:champ_2) { create(:champ_integer_number, value: value_2) } - - let(:logic) do - ds_or([ - greater_than(champ_value(champ_1.stable_id), constant(1)), - less_than(champ_value(champ_2.stable_id), constant(10)) - ]) - end - - context 'with all champs' do - subject { logic.computable?([champ_1, champ_2]) } - - context "when none of champs.value are filled, or logic can't be computed" do - let(:value_1) { nil } - let(:value_2) { nil } - it { is_expected.to be_falsey } - end - context "when one champs has a value (that compute to false) the other has not, or logic keeps waiting for the 2nd value" do - let(:value_1) { 1 } - let(:value_2) { nil } - it { is_expected.to be_falsey } - end - context 'when all champs.value are filled, or logic can be computed' do - let(:value_1) { 1 } - let(:value_2) { 10 } - it { is_expected.to be_truthy } - end - context 'when one champs.value and his condition is true, or logic can be computed' do - let(:value_1) { 2 } - let(:value_2) { nil } - it { is_expected.to be_truthy } - end - context 'when one champs is not visible and the other has a value that fails, or logic can be computed' do - let(:value_1) { 1 } - let(:value_2) { nil } - before { expect(champ_2).to receive(:visible?).and_return(false) } - it { is_expected.to be_truthy } - end - end - end - describe '#to_s' do it { expect(or_from([true, false, true]).to_s).to eq "(Oui || Non || Oui)" } end diff --git a/spec/system/administrateurs/procedure_ineligibilite_spec.rb b/spec/system/administrateurs/procedure_ineligibilite_spec.rb index 9db80cf5957..e93a6ea5dfa 100644 --- a/spec/system/administrateurs/procedure_ineligibilite_spec.rb +++ b/spec/system/administrateurs/procedure_ineligibilite_spec.rb @@ -9,13 +9,13 @@ scenario 'setup eligibilite' do # explain no champ compatible visit admin_procedure_path(procedure) - expect(page).to have_content("Champs à configurer") + expect(page).to have_content("Désactivé") # explain which champs are compatible visit edit_admin_procedure_ineligibilite_rules_path(procedure) expect(page).to have_content("Inéligibilité des dossiers") - expect(page).to have_content("Pour configurer l’inéligibilité des dossiers, votre formulaire doit comporter au moins un champ supportant les critères d’inéligibilité. Il vous faut donc ajouter au moins un des champs suivant à votre formulaire : ") - click_on "Ajouter un champ supportant les critères d’inéligibilité" + expect(page).to have_content("Pour configurer l’inéligibilité des dossiers, votre formulaire doit comporter au moins un champ supportant les conditions d’inéligibilité. Il vous faut donc ajouter au moins un des champs suivant à votre formulaire : ") + click_on "Ajouter un champ supportant les conditions d’inéligibilité" # setup a compatible champ expect(page).to have_content('Champs du formulaire') @@ -32,7 +32,7 @@ # setup rules and stuffs expect(page).to have_content("Inéligibilité des dossiers") fill_in "Message d’inéligibilité", with: "vous n'etes pas eligible" - find('label', text: 'Inéligibilité des dossiers').click + find('label', text: 'Bloquer le dépôt des dossiers répondant à des conditions d’inéligibilité').click click_on "Ajouter une règle d’inéligibilité" all('select').first.select 'Un champ oui non' click_on 'Enregistrer' diff --git a/spec/system/users/dossier_ineligibilite_spec.rb b/spec/system/users/dossier_ineligibilite_spec.rb index 366dac7803c..5bbb25c7580 100644 --- a/spec/system/users/dossier_ineligibilite_spec.rb +++ b/spec/system/users/dossier_ineligibilite_spec.rb @@ -9,7 +9,7 @@ let(:published_revision) { procedure.published_revision } let(:first_tdc) { published_revision.types_de_champ.first } - let(:second_tdc) { published_revision.types_de_champ.last } + let(:second_tdc) { published_revision.types_de_champ.second } let(:ineligibilite_message) { 'sry vous pouvez aps soumettre votre dossier' } let(:eligibilite_params) { { ineligibilite_enabled: true, ineligibilite_message: } } @@ -18,8 +18,8 @@ login_as user, scope: :user end - context 'single condition' do - let(:types_de_champ_public) { [{ type: :yes_no }] } + describe 'ineligibilite_rules with a single BinaryOperator' do + let(:types_de_champ_public) { [{ type: :yes_no, stable_id: 1 }] } let(:ineligibilite_rules) { ds_eq(champ_value(first_tdc.stable_id), constant(true)) } scenario 'can submit, can not submit, reload' do @@ -28,24 +28,33 @@ expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") - # does raise error when dossier is filled with valid condition - find("label", text: "Non").click + # does raise error when dossier is filled with condition that does not match + within "#champ-1" do + find("label", text: "Non").click + end expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") - # raise error when dossier is filled with invalid condition - find("label", text: "Oui").click + # raise error when dossier is filled with condition that matches + within "#champ-1" do + find("label", text: "Oui").click + end expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: true) expect(page).to have_content("Vous ne pouvez pas déposer votre dossier") - # reload page and see error because it was filled + # reload page and see error visit brouillon_dossier_path(dossier) expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: true) expect(page).to have_content("Vous ne pouvez pas déposer votre dossier") # modal is closable, and we can change our dossier response to be eligible + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: true) within("#modal-eligibilite-rules-dialog") { click_on "Fermer" } - find("label", text: "Non").click + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) + + within "#champ-1" do + find("label", text: "Non").click + end expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) # it works, yay @@ -54,7 +63,7 @@ end end - context 'or condition' do + describe 'ineligibilite_rules with a Or' do let(:types_de_champ_public) { [{ type: :yes_no, libelle: 'l1' }, { type: :drop_down_list, libelle: 'l2', options: ['Paris', 'Marseille'] }] } let(:ineligibilite_rules) do ds_or([ @@ -69,15 +78,17 @@ expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") - # only one condition is matches, cannot submit dossier and error message is clear + # first condition matches (so ineligible), cannot submit dossier and error message is clear within "#champ-#{first_tdc.stable_id}" do find("label", text: "Oui").click end expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: true) expect(page).to have_content("Vous ne pouvez pas déposer votre dossier") + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: true) within("#modal-eligibilite-rules-dialog") { click_on "Fermer" } + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) - # only one condition does not matches, I can conitnue + # first condition does not matches, I can conitnue within "#champ-#{first_tdc.stable_id}" do find("label", text: "Non").click end @@ -88,12 +99,15 @@ click_on "Accéder à votre dossier" click_on "Modifier le dossier" - # one condition matches, means i'm blocked to send my file. + # first matches, means i'm blocked to send my file. within "#champ-#{first_tdc.stable_id}" do find("label", text: "Oui").click end expect(page).to have_selector(:button, text: "Déposer les modifications", disabled: true) + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: true) within("#modal-eligibilite-rules-dialog") { click_on "Fermer" } + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) + within "#champ-#{first_tdc.stable_id}" do find("label", text: "Non").click end @@ -104,7 +118,56 @@ find("label", text: 'Paris').click end expect(page).to have_selector(:button, text: "Déposer les modifications", disabled: true) + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: true) + within("#modal-eligibilite-rules-dialog") { click_on "Fermer" } + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) + + # none of conditions matches, i can submit + within "#champ-#{second_tdc.stable_id}" do + find("label", text: 'Marseille').click + end + + # it works, yay + click_on "Déposer les modifications" + wait_until { dossier.reload.en_construction? == true } + end + end + + describe 'ineligibilite_rules with a And and all visible champs' do + let(:types_de_champ_public) { [{ type: :yes_no, libelle: 'l1' }, { type: :drop_down_list, libelle: 'l2', options: ['Paris', 'Marseille'] }] } + let(:ineligibilite_rules) do + ds_and([ + ds_eq(champ_value(first_tdc.stable_id), constant(true)), + ds_eq(champ_value(second_tdc.stable_id), constant('Paris')) + ]) + end + + scenario 'can submit, can not submit, can edit, etc...' do + visit brouillon_dossier_path(dossier) + # no error while dossier is empty + expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) + expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") + + # only one condition is matches, can submit dossier + within "#champ-#{first_tdc.stable_id}" do + find("label", text: "Oui").click + end + expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) + expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") + + # Now test dossier modification + click_on "Déposer le dossier" + click_on "Accéder à votre dossier" + click_on "Modifier le dossier" + + # second condition matches, means i'm blocked to send my file + within "#champ-#{second_tdc.stable_id}" do + find("label", text: 'Paris').click + end + expect(page).to have_selector(:button, text: "Déposer les modifications", disabled: true) + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: true) within("#modal-eligibilite-rules-dialog") { click_on "Fermer" } + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) # none of conditions matches, i can submit within "#champ-#{second_tdc.stable_id}" do diff --git a/spec/views/shared/dossiers/_edit.html.haml_spec.rb b/spec/views/shared/dossiers/_edit.html.haml_spec.rb index 5183554d828..f6ce8f5bf32 100644 --- a/spec/views/shared/dossiers/_edit.html.haml_spec.rb +++ b/spec/views/shared/dossiers/_edit.html.haml_spec.rb @@ -155,7 +155,6 @@ let(:dossier) { create(:dossier, procedure:) } before do - allow_any_instance_of(Dossiers::InvalidIneligibiliteRulesComponent).to receive(:ineligibilite_rules_computable?).and_return(true) allow(dossier).to receive(:can_passer_en_construction?).and_return(false) end