diff --git a/Gemfile.lock b/Gemfile.lock index f0763c355..12840698a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -395,7 +395,7 @@ GEM railties (>= 4) request_store (~> 1.0) logstash-event (1.2.02) - loofah (2.19.0) + loofah (2.19.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -536,8 +536,8 @@ GEM activesupport (>= 4.2) choice (~> 0.2.0) ruby-graphviz (~> 1.2) - rails-html-sanitizer (1.4.3) - loofah (~> 2.3) + rails-html-sanitizer (1.4.4) + loofah (~> 2.19, >= 2.19.1) rails-i18n (7.0.3) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) diff --git a/app/components/editable_champ/editable_champ_component.rb b/app/components/editable_champ/editable_champ_component.rb index a705c1f6f..d3a314511 100644 --- a/app/components/editable_champ/editable_champ_component.rb +++ b/app/components/editable_champ/editable_champ_component.rb @@ -23,7 +23,7 @@ class EditableChamp::EditableChampComponent < ApplicationComponent "hidden": !@champ.visible? ), id: @champ.input_group_id, - data: { controller: stimulus_controller, block: @champ.block? } + data: { controller: stimulus_controller } } end diff --git a/app/components/editable_champ/editable_champ_component/editable_champ_component.html.haml b/app/components/editable_champ/editable_champ_component/editable_champ_component.html.haml index d0f4362d9..b98f43654 100644 --- a/app/components/editable_champ/editable_champ_component/editable_champ_component.html.haml +++ b/app/components/editable_champ/editable_champ_component/editable_champ_component.html.haml @@ -9,5 +9,5 @@ - if @champ.type_champ == "titre_identite" %p.notice Carte nationale d’identité (uniquement le recto), passeport, titre de séjour ou autre justificatif d’identité. - = @form.hidden_field :id, value: @champ.id, data: @champ.block? ? { id: true } : {} + = @form.hidden_field :id, value: @champ.id = render component_class.new(form: @form, champ: @champ, seen_at: @seen_at) diff --git a/app/components/types_de_champ_editor/block_component.rb b/app/components/types_de_champ_editor/block_component.rb index e0010ee48..22cf4bdaa 100644 --- a/app/components/types_de_champ_editor/block_component.rb +++ b/app/components/types_de_champ_editor/block_component.rb @@ -1,8 +1,7 @@ class TypesDeChampEditor::BlockComponent < ApplicationComponent - def initialize(block:, coordinates:, upper_coordinates: []) + def initialize(block:, coordinates:) @block = block @coordinates = coordinates - @upper_coordinates = upper_coordinates end private diff --git a/app/components/types_de_champ_editor/block_component/block_component.html.haml b/app/components/types_de_champ_editor/block_component/block_component.html.haml index 770b47671..59d07c80a 100644 --- a/app/components/types_de_champ_editor/block_component/block_component.html.haml +++ b/app/components/types_de_champ_editor/block_component/block_component.html.haml @@ -1,3 +1,3 @@ %ul.types-de-champ-block{ id: block_id, data: sortable_options } - @coordinates.each.with_index do |coordinate, i| - = render TypesDeChampEditor::ChampComponent.new(coordinate: coordinate, upper_coordinates: @upper_coordinates + @coordinates.take(i)) + = render TypesDeChampEditor::ChampComponent.new(coordinate: coordinate, upper_coordinates: @coordinates.take(i)) diff --git a/app/components/types_de_champ_editor/champ_component.rb b/app/components/types_de_champ_editor/champ_component.rb index 856d0d06a..6160d7790 100644 --- a/app/components/types_de_champ_editor/champ_component.rb +++ b/app/components/types_de_champ_editor/champ_component.rb @@ -118,6 +118,6 @@ class TypesDeChampEditor::ChampComponent < ApplicationComponent end def conditional_enabled? - !type_de_champ.private? + !type_de_champ.private? && !coordinate.child? end end diff --git a/app/components/types_de_champ_editor/champ_component/champ_component.html.haml b/app/components/types_de_champ_editor/champ_component/champ_component.html.haml index 5a8d36080..830bb3aab 100644 --- a/app/components/types_de_champ_editor/champ_component/champ_component.html.haml +++ b/app/components/types_de_champ_editor/champ_component/champ_component.html.haml @@ -87,7 +87,7 @@ - if type_de_champ.block? .flex.justify-start.section.ml-1 .editor-block.flex-grow.cell - = render TypesDeChampEditor::BlockComponent.new(block: coordinate, coordinates: coordinate.revision_types_de_champ, upper_coordinates: @upper_coordinates) + = render TypesDeChampEditor::BlockComponent.new(block: coordinate, coordinates: coordinate.revision_types_de_champ) = render TypesDeChampEditor::AddChampButtonComponent.new(revision: coordinate.revision, parent: coordinate, is_annotation: coordinate.private?) - if conditional_enabled? diff --git a/app/controllers/administrateurs/conditions_controller.rb b/app/controllers/administrateurs/conditions_controller.rb index d646a568f..4df461e0e 100644 --- a/app/controllers/administrateurs/conditions_controller.rb +++ b/app/controllers/administrateurs/conditions_controller.rb @@ -55,13 +55,7 @@ module Administrateurs def retrieve_coordinate_and_uppers @tdc = draft_revision.find_and_ensure_exclusive_use(params[:stable_id]) @coordinate = draft_revision.coordinate_for(@tdc) - - upper_coordinates = @coordinate.upper_siblings - if @coordinate.child? - upper_coordinates += @coordinate.parent.upper_siblings - end - - @upper_tdcs = upper_coordinates.map(&:type_de_champ) + @upper_tdcs = @coordinate.upper_siblings.map(&:type_de_champ) end def draft_revision diff --git a/app/controllers/instructeurs/dossiers_controller.rb b/app/controllers/instructeurs/dossiers_controller.rb index 6bf5fd869..9e2f110d6 100644 --- a/app/controllers/instructeurs/dossiers_controller.rb +++ b/app/controllers/instructeurs/dossiers_controller.rb @@ -212,7 +212,7 @@ module Instructeurs def update_annotations dossier_with_champs.assign_attributes(champs_private_params) - if dossier.champs_private.any?(&:changed?) + if dossier.champs_private_all.any?(&:changed?) dossier.last_champ_private_updated_at = Time.zone.now end dossier.save @@ -286,10 +286,12 @@ module Instructeurs end def champs_private_params - params.require(:dossier).permit(champs_private_attributes: [ + champs_params = params.require(:dossier).permit(champs_private_attributes: [ :id, :primary_value, :secondary_value, :piece_justificative_file, :value_other, :external_id, :numero_allocataire, :code_postal, :departement, :code_departement, :value, value: [], champs_attributes: [:id, :_destroy, :value, :primary_value, :secondary_value, :piece_justificative_file, :value_other, :external_id, :numero_allocataire, :code_postal, :departement, :code_departement, value: []] ]) + champs_params[:champs_private_all_attributes] = champs_params.delete(:champs_private_attributes) || {} + champs_params end def mark_demande_as_read diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index f23dd1faf..6aa397d38 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -391,14 +391,13 @@ module Users [params[:page].to_i, 1].max end - # FIXME: require(:dossier) when all the champs are united - def champs_params - params.permit(dossier: { - champs_public_attributes: [ - :id, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :identifiant, :numero_fiscal, :reference_avis, :ine, :piece_justificative_file, :departement, :code_departement, value: [], - champs_attributes: [:id, :_destroy, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :identifiant, :numero_fiscal, :reference_avis, :ine, :piece_justificative_file, :departement, :code_departement, value: []] - ] - }) + def champs_public_params + champs_params = params.require(:dossier).permit(champs_public_attributes: [ + :id, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :identifiant, :numero_fiscal, :reference_avis, :ine, :piece_justificative_file, :departement, :code_departement, value: [], + champs_attributes: [:id, :_destroy, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :identifiant, :numero_fiscal, :reference_avis, :ine, :piece_justificative_file, :departement, :code_departement, value: []] + ]) + champs_params[:champs_public_all_attributes] = champs_params.delete(:champs_public_attributes) || {} + champs_params end def dossier_scope @@ -454,23 +453,16 @@ module Users def update_dossier_and_compute_errors errors = [] - if champs_params[:dossier] - @dossier.assign_attributes(champs_params[:dossier]) - # FIXME: in some cases a removed repetition bloc row is submitted. - # In this case it will be treated as a new record, and the action will fail. - @dossier.champs_public.filter(&:block?).each do |champ| - champ.champs = champ.champs.filter(&:persisted?) - end - if @dossier.champs_public.any?(&:changed_for_autosave?) - @dossier.last_champ_updated_at = Time.zone.now - end - if !@dossier.save(**validation_options) - errors += @dossier.errors.full_messages - end + @dossier.assign_attributes(champs_public_params) + if @dossier.champs_public_all.any?(&:changed_for_autosave?) + @dossier.last_champ_updated_at = Time.zone.now + end + if !@dossier.save(**validation_options) + errors += @dossier.errors.full_messages + end - if should_change_groupe_instructeur? - @dossier.assign_to_groupe_instructeur(groupe_instructeur_from_params) - end + if should_change_groupe_instructeur? + @dossier.assign_to_groupe_instructeur(groupe_instructeur_from_params) end if dossier.en_construction? diff --git a/app/helpers/procedure_helper.rb b/app/helpers/procedure_helper.rb index 3e2f62b6e..7152824ba 100644 --- a/app/helpers/procedure_helper.rb +++ b/app/helpers/procedure_helper.rb @@ -66,4 +66,20 @@ module ProcedureHelper minutes = (seconds / 60.0).round [1, minutes].max end + + def admin_procedures_back_path(procedure) + statut = if procedure.discarded? + 'supprimees' + else + case procedure.aasm_state + when 'brouillon' + 'brouillons' + when 'close', 'depubliee' + 'archivees' + else + 'publiees' + end + end + admin_procedures_path(statut:) + end end diff --git a/app/javascript/controllers/autosave_controller.ts b/app/javascript/controllers/autosave_controller.ts index 93fd4f190..6c7746b33 100644 --- a/app/javascript/controllers/autosave_controller.ts +++ b/app/javascript/controllers/autosave_controller.ts @@ -201,19 +201,10 @@ export class AutosaveController extends ApplicationController { private get inputs() { const element = this.element as HTMLElement; - const inputs = [ + return [ ...element.querySelectorAll( 'input:not([type=file]), textarea, select' ) ].filter((element) => !element.disabled); - - const parent = this.element.closest('[data-block]'); - if (parent) { - return [ - ...inputs, - ...parent.querySelectorAll('input[data-id]') - ]; - } - return inputs; } } diff --git a/app/models/batch_operation.rb b/app/models/batch_operation.rb index b91a72ddc..65ff18c8b 100644 --- a/app/models/batch_operation.rb +++ b/app/models/batch_operation.rb @@ -40,10 +40,10 @@ class BatchOperation < ApplicationRecord } def dossiers_safe_scope(dossier_ids = self.dossier_ids) - query = Dossier.joins(:procedure) - .where(procedure: { id: instructeur.procedures.ids }) - .where(id: dossier_ids) + query = instructeur + .dossiers .visible_by_administration + .where(id: dossier_ids) case operation when BatchOperation.operations.fetch(:archiver) then query.not_archived.state_termine diff --git a/app/models/champ.rb b/app/models/champ.rb index 86332ab3f..7d95b352d 100644 --- a/app/models/champ.rb +++ b/app/models/champ.rb @@ -178,10 +178,10 @@ class Champ < ApplicationRecord # attributes. So instead of the field index, this method uses the champ id; which gives us an independent and # predictable input name. def input_name - if parent_id - "#{parent.input_name}[champs_attributes][#{id}]" + if private? + "dossier[champs_private_attributes][#{id}]" else - "dossier[#{champs_attributes_accessor}][#{id}]" + "dossier[champs_public_attributes][#{id}]" end end @@ -239,21 +239,13 @@ class Champ < ApplicationRecord private def champs_for_condition - dossier.champs.filter { _1.row.nil? || _1.row == row } + private? ? dossier.champs_private : dossier.champs_public end def html_id "#{stable_id}-#{id}" end - def champs_attributes_accessor - if private? - "champs_private_attributes" - else - "champs_public_attributes" - end - end - def needs_dossier_id? !dossier_id && parent_id end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 379ac34cf..510a34659 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -83,7 +83,9 @@ class Dossier < ApplicationRecord has_many :champs_public, -> { root.public_ordered }, class_name: 'Champ', inverse_of: false, dependent: :destroy has_many :champs_private, -> { root.private_ordered }, class_name: 'Champ', inverse_of: false, dependent: :destroy has_many :champs_public_all, -> { public_only }, class_name: 'Champ', inverse_of: false - has_many :prefilled_champs_public, -> { root.public_only.prefilled }, class_name: 'Champ', inverse_of: false, dependent: :destroy + has_many :champs_private_all, -> { private_only }, class_name: 'Champ', inverse_of: false + has_many :prefilled_champs_public, -> { root.public_only.prefilled }, class_name: 'Champ', inverse_of: false + has_many :commentaires, inverse_of: :dossier, dependent: :destroy has_many :invites, dependent: :destroy has_many :follows, -> { active }, inverse_of: :dossier @@ -153,6 +155,8 @@ class Dossier < ApplicationRecord accepts_nested_attributes_for :champs_public accepts_nested_attributes_for :champs_private + accepts_nested_attributes_for :champs_public_all + accepts_nested_attributes_for :champs_private_all include AASM diff --git a/app/models/dossier_preloader.rb b/app/models/dossier_preloader.rb index b0c1a8049..417304202 100644 --- a/app/models/dossier_preloader.rb +++ b/app/models/dossier_preloader.rb @@ -79,6 +79,8 @@ class DossierPreloader champs_public, champs_private = champs.partition(&:public?) dossier.association(:champs).target = [] + dossier.association(:champs_public_all).target = [] + dossier.association(:champs_private_all).target = [] load_champs(dossier, :champs_public, champs_public, dossier, children_by_parent) load_champs(dossier, :champs_private, champs_private, dossier, children_by_parent) @@ -91,6 +93,8 @@ class DossierPreloader end def load_champs(parent, name, champs, dossier, children_by_parent) + return if champs.empty? + champs.each do |champ| champ.association(:dossier).target = dossier @@ -98,8 +102,15 @@ class DossierPreloader champ.association(:parent).target = parent end end + dossier.association(:champs).target += champs + if champs.first.public? + dossier.association(:champs_public_all).target += champs + else + dossier.association(:champs_private_all).target += champs + end + parent.association(name).target = champs.sort_by do |champ| [champ.row, positions[dossier.revision_id][champ.type_de_champ_id]] end diff --git a/app/views/administrateurs/procedures/annotations.html.haml b/app/views/administrateurs/procedures/annotations.html.haml index 1027ad34f..6221df5f9 100644 --- a/app/views/administrateurs/procedures/annotations.html.haml +++ b/app/views/administrateurs/procedures/annotations.html.haml @@ -1,5 +1,5 @@ = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], [@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)], ['Configuration des annotations privées']], preview: true } diff --git a/app/views/administrateurs/procedures/champs.html.haml b/app/views/administrateurs/procedures/champs.html.haml index 20dfb5dab..29c917af7 100644 --- a/app/views/administrateurs/procedures/champs.html.haml +++ b/app/views/administrateurs/procedures/champs.html.haml @@ -1,5 +1,5 @@ = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], [@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)], ['Configuration des champs']], preview: @procedure.draft_revision.valid? } diff --git a/app/views/administrateurs/procedures/close.html.haml b/app/views/administrateurs/procedures/close.html.haml index 57a608611..52ed9aaa2 100644 --- a/app/views/administrateurs/procedures/close.html.haml +++ b/app/views/administrateurs/procedures/close.html.haml @@ -1,5 +1,5 @@ = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], ["#{@procedure.libelle.truncate_words(10)} - archiver"]], metadatas: true } diff --git a/app/views/administrateurs/procedures/edit.html.haml b/app/views/administrateurs/procedures/edit.html.haml index e8ff47733..a46cdd144 100644 --- a/app/views/administrateurs/procedures/edit.html.haml +++ b/app/views/administrateurs/procedures/edit.html.haml @@ -1,7 +1,7 @@ - content_for(:root_class, 'scroll-margins-for-sticky-footer') = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], [@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)], ['Description']] } .procedure-form diff --git a/app/views/administrateurs/procedures/jeton.html.haml b/app/views/administrateurs/procedures/jeton.html.haml index 3e5bde7ee..7385ffdbd 100644 --- a/app/views/administrateurs/procedures/jeton.html.haml +++ b/app/views/administrateurs/procedures/jeton.html.haml @@ -1,5 +1,5 @@ = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], [@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)], ['Jeton']] } diff --git a/app/views/administrateurs/procedures/modifications.html.haml b/app/views/administrateurs/procedures/modifications.html.haml index 744be1b1a..a120dc50a 100644 --- a/app/views/administrateurs/procedures/modifications.html.haml +++ b/app/views/administrateurs/procedures/modifications.html.haml @@ -1,5 +1,5 @@ = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], [@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)], ['Modifications']] } .container diff --git a/app/views/administrateurs/procedures/monavis.html.haml b/app/views/administrateurs/procedures/monavis.html.haml index 6f42dc319..a48024209 100644 --- a/app/views/administrateurs/procedures/monavis.html.haml +++ b/app/views/administrateurs/procedures/monavis.html.haml @@ -1,5 +1,5 @@ = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], [@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)], ['MonAvis']] } diff --git a/app/views/administrateurs/procedures/new.html.haml b/app/views/administrateurs/procedures/new.html.haml index 68daee102..6fa4ee0c7 100644 --- a/app/views/administrateurs/procedures/new.html.haml +++ b/app/views/administrateurs/procedures/new.html.haml @@ -1,7 +1,7 @@ - content_for(:root_class, 'scroll-margins-for-sticky-footer') = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], ['Nouvelle']] } .procedure-form diff --git a/app/views/administrateurs/procedures/publication.html.haml b/app/views/administrateurs/procedures/publication.html.haml index 334e92c24..9efa4a883 100644 --- a/app/views/administrateurs/procedures/publication.html.haml +++ b/app/views/administrateurs/procedures/publication.html.haml @@ -1,6 +1,6 @@ = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], [@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)], ['Publication']] } .container diff --git a/app/views/administrateurs/procedures/show.html.haml b/app/views/administrateurs/procedures/show.html.haml index 5c2f673b4..66f218b2e 100644 --- a/app/views/administrateurs/procedures/show.html.haml +++ b/app/views/administrateurs/procedures/show.html.haml @@ -1,5 +1,5 @@ = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], ["#{@procedure.libelle.truncate_words(10)}"]], metadatas: true } diff --git a/app/views/administrateurs/procedures/transfert.html.haml b/app/views/administrateurs/procedures/transfert.html.haml index 8be1b1f8c..1ea1c1af2 100644 --- a/app/views/administrateurs/procedures/transfert.html.haml +++ b/app/views/administrateurs/procedures/transfert.html.haml @@ -1,5 +1,5 @@ = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], [@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)], ['Transfert']] } .container diff --git a/app/views/administrateurs/procedures/zones.html.haml b/app/views/administrateurs/procedures/zones.html.haml index 737825a6d..d854d5206 100644 --- a/app/views/administrateurs/procedures/zones.html.haml +++ b/app/views/administrateurs/procedures/zones.html.haml @@ -1,7 +1,7 @@ - content_for(:root_class, 'scroll-margins-for-sticky-footer') = render partial: 'administrateurs/breadcrumbs', - locals: { steps: [['Démarches', admin_procedures_path], + locals: { steps: [['Démarches', admin_procedures_back_path(@procedure)], [@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)], ['Description']] } .container diff --git a/db/schema.rb b/db/schema.rb index becdf28c5..309bb650c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -220,7 +220,7 @@ ActiveRecord::Schema.define(version: 2022_12_05_144624) do t.string "external_id" t.string "fetch_external_data_exceptions", array: true t.bigint "parent_id" - t.boolean "prefilled", default: false + t.boolean "prefilled" t.boolean "private", default: false, null: false t.datetime "rebased_at" t.integer "row" diff --git a/spec/controllers/administrateurs/conditions_controller_spec.rb b/spec/controllers/administrateurs/conditions_controller_spec.rb index 3552a848b..2b34060ab 100644 --- a/spec/controllers/administrateurs/conditions_controller_spec.rb +++ b/spec/controllers/administrateurs/conditions_controller_spec.rb @@ -1,159 +1,118 @@ describe Administrateurs::ConditionsController, type: :controller do include Logic + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :integer_number }] * 3) } + let(:first_coordinate) { procedure.draft_revision.revision_types_de_champ.first } + let(:second_coordinate) { procedure.draft_revision.revision_types_de_champ.first } + let(:third_coordinate) { procedure.draft_revision.revision_types_de_champ.first } + let(:first_tdc) { procedure.draft_revision.types_de_champ.first } + let(:second_tdc) { procedure.draft_revision.types_de_champ.second } + let(:third_tdc) { procedure.draft_revision.types_de_champ.third } + before { sign_in(procedure.administrateurs.first.user) } - context 'without bloc repetition' do - let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :integer_number }] * 3) } - let(:first_tdc) { procedure.draft_revision.types_de_champ.first } - let(:second_tdc) { procedure.draft_revision.types_de_champ.second } - let(:third_tdc) { procedure.draft_revision.types_de_champ.third } + let(:default_params) do + { + procedure_id: procedure.id, + stable_id: third_tdc.stable_id + } + end - before { sign_in(procedure.administrateurs.first.user) } + describe '#update' do + before { post :update, params: params, format: :turbo_stream } - let(:default_params) do + let(:params) { default_params.merge(type_de_champ: { condition_form: condition_form }) } + + let(:condition_form) do { - procedure_id: procedure.id, - stable_id: third_tdc.stable_id + rows: [ + { + targeted_champ: champ_value(first_tdc.stable_id).to_json, + operator_name: Logic::Eq.name, + value: '2' + } + ] } end - describe '#update' do - before { post :update, params: params, format: :turbo_stream } - - let(:params) { default_params.merge(type_de_champ: { condition_form: condition_form }) } - - let(:condition_form) do - { - rows: [ - { - targeted_champ: champ_value(first_tdc.stable_id).to_json, - operator_name: Logic::Eq.name, - value: '2' - } - ] - } - end - - it do - expect(third_tdc.reload.condition).to eq(ds_eq(champ_value(first_tdc.stable_id), constant(2))) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) - expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) - end - end - - describe '#add_row' do - before { post :add_row, params: default_params, format: :turbo_stream } - - it do - expect(third_tdc.reload.condition).to eq(empty_operator(empty, empty)) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) - expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) - end - end - - describe '#delete_row' do - before { delete :delete_row, params: params.merge(row_index: 0), format: :turbo_stream } - - let(:params) { default_params.merge(type_de_champ: { condition_form: condition_form }) } - - let(:condition_form) do - { - rows: [ - { - targeted_champ: champ_value(1).to_json, - operator_name: Logic::Eq.name, - value: '2' - } - ] - } - end - - it do - expect(third_tdc.reload.condition).to eq(nil) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) - expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) - end - end - - describe '#destroy' do - before do - second_tdc.update(condition: empty_operator(empty, empty)) - delete :destroy, params: default_params, format: :turbo_stream - end - - it do - expect(third_tdc.reload.condition).to eq(nil) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) - expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) - end - end - - describe '#change_targeted_champ' do - before do - second_tdc.update(condition: empty_operator(empty, empty)) - patch :change_targeted_champ, params: params, format: :turbo_stream - end - - let(:params) { default_params.merge(type_de_champ: { condition_form: condition_form }) } - - let(:condition_form) do - { - rows: [ - { - targeted_champ: champ_value(second_tdc.stable_id).to_json, - operator_name: Logic::EmptyOperator.name, - value: empty.to_json - } - ] - } - end - - it do - expect(third_tdc.reload.condition).to eq(ds_eq(champ_value(second_tdc.stable_id), constant(0))) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) - expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) - end + it do + expect(third_tdc.reload.condition).to eq(ds_eq(champ_value(first_tdc.stable_id), constant(2))) + expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) + expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) end end - context 'with a repetiton bloc' do - let(:procedure) do - create(:procedure, types_de_champ_public: [ - { type: :integer_number, libelle: 'top_1' }, - { - type: :repetition, - libelle: 'repetition', - children: [ - { type: :integer_number, libelle: 'child_1' }, - { type: :integer_number, libelle: 'child_2' } - ] - } - ]) - end - let(:tdcs) { procedure.draft_revision.types_de_champ } - let(:top) { tdcs.find_by(libelle: 'top_1') } - let(:repetition) { tdcs.find_by(libelle: 'repetition') } - let(:child_1) { tdcs.find_by(libelle: 'child_1') } - let(:child_2) { tdcs.find_by(libelle: 'child_2') } + describe '#add_row' do + before { post :add_row, params: default_params, format: :turbo_stream } - let(:default_params) do + it do + expect(third_tdc.reload.condition).to eq(empty_operator(empty, empty)) + expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) + expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) + end + end + + describe '#delete_row' do + before { delete :delete_row, params: params.merge(row_index: 0), format: :turbo_stream } + + let(:params) { default_params.merge(type_de_champ: { condition_form: condition_form }) } + + let(:condition_form) do { - procedure_id: procedure.id, - stable_id: child_2.stable_id + rows: [ + { + targeted_champ: champ_value(1).to_json, + operator_name: Logic::Eq.name, + value: '2' + } + ] } end - describe '#add_row' do - before do - post :add_row, params: default_params, format: :turbo_stream - end + it do + expect(third_tdc.reload.condition).to eq(nil) + expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) + expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) + end + end - it do - expect(child_2.reload.condition).to eq(empty_operator(empty, empty)) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(child_2)) - expect(assigns(:upper_tdcs)).to eq([child_1, top]) - end + describe '#destroy' do + before do + second_tdc.update(condition: empty_operator(empty, empty)) + delete :destroy, params: default_params, format: :turbo_stream + end + + it do + expect(third_tdc.reload.condition).to eq(nil) + expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) + expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) + end + end + + describe '#change_targeted_champ' do + before do + second_tdc.update(condition: empty_operator(empty, empty)) + patch :change_targeted_champ, params: params, format: :turbo_stream + end + + let(:params) { default_params.merge(type_de_champ: { condition_form: condition_form }) } + + let(:condition_form) do + { + rows: [ + { + targeted_champ: champ_value(second_tdc.stable_id).to_json, + operator_name: Logic::EmptyOperator.name, + value: empty.to_json + } + ] + } + end + + it do + expect(third_tdc.reload.condition).to eq(ds_eq(champ_value(second_tdc.stable_id), constant(0))) + expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) + expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) end end end diff --git a/spec/controllers/instructeurs/dossiers_controller_spec.rb b/spec/controllers/instructeurs/dossiers_controller_spec.rb index 287fdd2c5..75d61e993 100644 --- a/spec/controllers/instructeurs/dossiers_controller_spec.rb +++ b/spec/controllers/instructeurs/dossiers_controller_spec.rb @@ -793,11 +793,8 @@ describe Instructeurs::DossiersController, type: :controller do secondary_value: 'secondary' }, '3': { - id: champ_repetition.id, - champs_attributes: { - id: champ_repetition.champs.first.id, - value: 'text' - } + id: champ_repetition.champs.first.id, + value: 'text' } } } diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb index da4bb9f9e..478792f2d 100644 --- a/spec/controllers/users/dossiers_controller_spec.rb +++ b/spec/controllers/users/dossiers_controller_spec.rb @@ -494,7 +494,7 @@ describe Users::DossiersController, type: :controller do { id: dossier.id, dossier: { - champs_public_attributes: {} + champs_public_attributes: [{ value: '' }] } } end @@ -506,16 +506,6 @@ describe Users::DossiersController, type: :controller do end end - context 'when dossier has no champ' do - let(:submit_payload) { { id: dossier.id } } - - it 'does not raise any errors' do - subject - - expect(response).to have_http_status(:ok) - end - end - context 'when the user has an invitation but is not the owner' do let(:dossier) { create(:dossier) } let!(:invite) { create(:invite, dossier: dossier, user: user) } @@ -664,16 +654,6 @@ describe Users::DossiersController, type: :controller do it { expect(flash.alert).to eq(['Le champ l doit être rempli.']) } end - context 'when dossier has no champ' do - let(:submit_payload) { { id: dossier.id } } - - it 'does not raise any errors' do - subject - - expect(response).to have_http_status(:ok) - end - end - context 'when the user has an invitation but is not the owner' do let(:dossier) { create(:dossier, :en_construction) } let!(:invite) { create(:invite, dossier: dossier, user: user) } diff --git a/spec/models/champ_spec.rb b/spec/models/champ_spec.rb index 6ef81bde5..75e2d61a4 100644 --- a/spec/models/champ_spec.rb +++ b/spec/models/champ_spec.rb @@ -599,12 +599,12 @@ describe Champ do context "when has parent" do let(:champ) { create(:champ_text, parent: create(:champ_text)) } - it { expect(champ.input_name).to eq "dossier[champs_public_attributes][#{champ.parent_id}][champs_attributes][#{champ.id}]" } + it { expect(champ.input_name).to eq "dossier[champs_public_attributes][#{champ.id}]" } end context "when has private parent" do let(:champ) { create(:champ_text, private: true, parent: create(:champ_text, private: true)) } - it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.parent_id}][champs_attributes][#{champ.id}]" } + it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.id}]" } end end end diff --git a/spec/models/concern/dossier_prefillable_concern_spec.rb b/spec/models/concern/dossier_prefillable_concern_spec.rb index ddf79fe65..9cd2b16d8 100644 --- a/spec/models/concern/dossier_prefillable_concern_spec.rb +++ b/spec/models/concern/dossier_prefillable_concern_spec.rb @@ -50,7 +50,7 @@ RSpec.describe DossierPrefillableConcern do end it "still marks it as prefilled" do - expect { fill }.to change { dossier.champs_public.first.prefilled }.from(false).to(true) + expect { fill }.to change { dossier.champs_public.first.prefilled }.from(nil).to(true) end end end diff --git a/spec/models/dossier_preloader_spec.rb b/spec/models/dossier_preloader_spec.rb index 8287b0606..cf8ca625e 100644 --- a/spec/models/dossier_preloader_spec.rb +++ b/spec/models/dossier_preloader_spec.rb @@ -26,8 +26,16 @@ describe DossierPreloader do expect(first_child.type).to eq('Champs::TextChamp') expect(repetition.id).not_to eq(first_child.id) + expect(subject.champs.first.dossier).to eq(subject) + expect(subject.champs_public_all.first.dossier).to eq(subject) expect(subject.champs_public.first.dossier).to eq(subject) + expect(subject.champs_public.first.type_de_champ.piece_justificative_template.attached?).to eq(false) + + expect(subject.champs.first.conditional?).to eq(false) + expect(subject.champs_public_all.first.conditional?).to eq(false) + expect(subject.champs_public.first.conditional?).to eq(false) + expect(first_child.parent).to eq(repetition) end diff --git a/spec/system/users/brouillon_spec.rb b/spec/system/users/brouillon_spec.rb index 9d810530a..8714a0ce9 100644 --- a/spec/system/users/brouillon_spec.rb +++ b/spec/system/users/brouillon_spec.rb @@ -289,87 +289,52 @@ describe 'The user' do include Logic context 'with a repetition' do - let(:stable_id) { 999 } - let(:condition) { greater_than_eq(champ_value(stable_id), constant(18)) } let(:procedure) do - create(:procedure, :published, :for_individual, - types_de_champ_public: [ - { type: :integer_number, libelle: 'age', stable_id: }, - { - type: :repetition, libelle: 'repetition', condition:, children: [ - { type: :text, libelle: 'nom', mandatory: true } - ] - } - ]) + procedure = create(:procedure, :published, :for_individual, + types_de_champ_public: [ + { type: :integer_number, libelle: 'age' }, + { + type: :repetition, libelle: 'repetition', children: [ + { type: :text, libelle: 'nom', mandatory: true } + ] + } + ]) + + age = procedure.published_revision.types_de_champ.where(libelle: 'age').first + repetition = procedure.published_revision.types_de_champ.repetition.first + repetition.update(condition: greater_than_eq(champ_value(age.stable_id), constant(18))) + + procedure end scenario 'submit a dossier with an hidden mandatory champ within a repetition', js: true do log_in(user, procedure) fill_individual - fill_in('age', with: 10) click_on 'Déposer le dossier' expect(page).to have_current_path(merci_dossier_path(user_dossier)) end end - context 'with a condition inside repetition' do - let(:a_stable_id) { 999 } - let(:b_stable_id) { 9999 } - let(:a_condition) { ds_eq(champ_value(a_stable_id), constant(true)) } - let(:b_condition) { ds_eq(champ_value(b_stable_id), constant(true)) } - let(:condition) { ds_or([a_condition, b_condition]) } - let(:procedure) do - create(:procedure, :published, :for_individual, - types_de_champ_public: [ - { type: :checkbox, libelle: 'champ_a', stable_id: a_stable_id }, - { - type: :repetition, libelle: 'repetition', children: [ - { type: :checkbox, libelle: 'champ_b', stable_id: b_stable_id }, - { type: :text, libelle: 'champ_c', condition: } - ] - } - ]) - end - - scenario 'fill a dossier', js: true do - log_in(user, procedure) - - fill_individual - - expect(page).to have_no_css('label', text: 'champ_c', visible: true) - check('champ_a') - wait_for_autosave - - expect(page).to have_css('label', text: 'champ_c', visible: true) - uncheck('champ_a') - wait_for_autosave - - expect(page).to have_no_css('label', text: 'champ_c', visible: true) - check('champ_b') - wait_for_autosave - - expect(page).to have_css('label', text: 'champ_c', visible: true) - end - end - context 'with a required conditionnal champ' do - let(:stable_id) { 999 } - let(:condition) { greater_than_eq(champ_value(stable_id), constant(18)) } let(:procedure) do - create(:procedure, :published, :for_individual, - types_de_champ_public: [ - { type: :integer_number, libelle: 'age', stable_id: }, - { type: :text, libelle: 'nom', mandatory: true, condition: } - ]) + procedure = create(:procedure, :published, :for_individual, + types_de_champ_public: [ + { type: :integer_number, libelle: 'age' }, + { type: :text, libelle: 'nom', mandatory: true } + ]) + + age, nom = procedure.draft_revision.types_de_champ.all + nom.update(condition: greater_than_eq(champ_value(age.stable_id), constant(18))) + + procedure end scenario 'submit a dossier with an hidden mandatory champ ', js: true do log_in(user, procedure) fill_individual - click_on 'Déposer le dossier' expect(page).to have_current_path(merci_dossier_path(user_dossier)) end @@ -388,21 +353,23 @@ describe 'The user' do end context 'with a visibilite in cascade' do - let(:age_stable_id) { 999 } - let(:permis_stable_id) { 9999 } - let(:tonnage_stable_id) { 99999 } - let(:permis_condition) { greater_than_eq(champ_value(age_stable_id), constant(18)) } - let(:tonnage_condition) { ds_eq(champ_value(permis_stable_id), constant(true)) } - let(:parking_condition) { less_than_eq(champ_value(tonnage_stable_id), constant(20)) } - let(:procedure) do - create(:procedure, :published, :for_individual, - types_de_champ_public: [ - { type: :integer_number, libelle: 'age', stable_id: age_stable_id }, - { type: :yes_no, libelle: 'permis de conduire', stable_id: permis_stable_id, condition: permis_condition }, - { type: :integer_number, libelle: 'tonnage', stable_id: tonnage_stable_id, condition: tonnage_condition }, - { type: :text, libelle: 'parking', condition: parking_condition } - ]) + procedure = create(:procedure, :for_individual).tap do |p| + p.draft_revision.add_type_de_champ(type_champ: :integer_number, libelle: 'age') + p.draft_revision.add_type_de_champ(type_champ: :yes_no, libelle: 'permis de conduire') + p.draft_revision.add_type_de_champ(type_champ: :integer_number, libelle: 'tonnage') + p.draft_revision.add_type_de_champ(type_champ: :text, libelle: 'parking') + end + + age, permis, tonnage, parking = procedure.draft_revision.types_de_champ.all + + permis.update(condition: greater_than_eq(champ_value(age.stable_id), constant(18))) + tonnage.update(condition: ds_eq(champ_value(permis.stable_id), constant(true))) + parking.update(condition: less_than_eq(champ_value(tonnage.stable_id), constant(20))) + + procedure.publish! + + procedure end scenario 'fill a dossier', js: true do