From 3b1575b5bcc7b9735bfc3643262ab608a3ec27e6 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 30 Jul 2024 15:31:01 +0200 Subject: [PATCH] WIP --- .../api/public/v1/dossiers_controller.rb | 2 +- app/controllers/api/v1/dossiers_controller.rb | 1 + .../champs/repetition_controller.rb | 7 +- app/controllers/users/commencer_controller.rb | 2 +- app/controllers/users/dossiers_controller.rb | 2 +- ...ssier_modifier_annotation_ajouter_ligne.rb | 2 +- app/graphql/types/dossier_type.rb | 4 +- app/lib/data_fixer/dossier_champs_missing.rb | 81 ----------- app/models/attestation_template.rb | 8 +- app/models/champ.rb | 20 +-- app/models/champs/repetition_champ.rb | 29 ++-- .../concerns/champs_validate_concern.rb | 8 +- app/models/concerns/dossier_champs_concern.rb | 75 +++++++--- app/models/concerns/dossier_clone_concern.rb | 36 +---- app/models/concerns/dossier_rebase_concern.rb | 40 +----- app/models/dossier.rb | 136 +++++++++--------- app/models/dossier_preloader.rb | 57 +------- app/models/procedure.rb | 14 -- app/models/procedure_revision.rb | 25 +--- .../procedure_revision_type_de_champ.rb | 4 +- .../prefill_repetition_type_de_champ.rb | 3 +- app/serializers/champ_serializer.rb | 4 +- app/serializers/dossier_serializer.rb | 8 +- .../_instruction_button_motivation.html.haml | 2 +- ...0240321081721_remove_champs_foreign_key.rb | 5 + db/schema.rb | 1 - .../api/v2/graphql_controller_spec.rb | 40 +----- .../champs/repetition_controller_spec.rb | 2 +- spec/factories/champ.rb | 24 ++-- spec/factories/dossier.rb | 59 ++++---- spec/graphql/annotation_spec.rb | 2 +- .../data_fixer/dossier_champs_missing_spec.rb | 2 +- spec/lib/recovery/dossier_life_cycle_spec.rb | 2 +- spec/models/champ_spec.rb | 31 +--- .../concerns/dossier_champs_concern_spec.rb | 7 +- .../concerns/dossier_clone_concern_spec.rb | 11 +- .../concerns/dossier_rebase_concern_spec.rb | 37 +++-- .../dossier_searchable_concern_spec.rb | 6 +- .../concerns/dossier_sections_concern_spec.rb | 12 +- .../tags_substitution_concern_spec.rb | 2 +- spec/models/dossier_spec.rb | 60 +++----- .../pieces_justificatives_service_spec.rb | 12 +- .../services/procedure_export_service_spec.rb | 2 +- .../procedure_export_service_zip_spec.rb | 2 +- ...ustificative_file_not_visible_task_spec.rb | 2 +- 45 files changed, 324 insertions(+), 567 deletions(-) delete mode 100644 app/lib/data_fixer/dossier_champs_missing.rb create mode 100644 db/migrate/20240321081721_remove_champs_foreign_key.rb diff --git a/app/controllers/api/public/v1/dossiers_controller.rb b/app/controllers/api/public/v1/dossiers_controller.rb index 86d45502896..5e2fa63d8e0 100644 --- a/app/controllers/api/public/v1/dossiers_controller.rb +++ b/app/controllers/api/public/v1/dossiers_controller.rb @@ -7,7 +7,7 @@ def create state: Dossier.states.fetch(:brouillon), prefilled: true ) - dossier.build_default_individual + dossier.build_default_values if dossier.save dossier.prefill!(PrefillChamps.new(dossier, params.to_unsafe_h).to_a, PrefillIdentity.new(dossier, params.to_unsafe_h).to_h) render json: serialize_dossier(dossier), status: :created diff --git a/app/controllers/api/v1/dossiers_controller.rb b/app/controllers/api/v1/dossiers_controller.rb index c42739d1c5e..263d98325b5 100644 --- a/app/controllers/api/v1/dossiers_controller.rb +++ b/app/controllers/api/v1/dossiers_controller.rb @@ -16,6 +16,7 @@ def index def show dossier = @dossiers.for_api.find(params[:id]) + DossierPreloader.load_one(dossier) render json: { dossier: DossierSerializer.new(dossier).as_json } rescue ActiveRecord::RecordNotFound diff --git a/app/controllers/champs/repetition_controller.rb b/app/controllers/champs/repetition_controller.rb index 6a09dd275bd..444eba7b65c 100644 --- a/app/controllers/champs/repetition_controller.rb +++ b/app/controllers/champs/repetition_controller.rb @@ -1,13 +1,12 @@ class Champs::RepetitionController < Champs::ChampController def add - row = @champ.add_row(@champ.dossier.revision) - @first_champ_id = row.map(&:focusable_input_id).compact.first - @row_id = row.first&.row_id + @row_id = @champ.add_row(updated_by: current_user.email) + @first_champ_id = @champ.focusable_input_id @row_number = @row_id.nil? ? 0 : @champ.row_ids.find_index(@row_id) + 1 end def remove - @champ.remove_row(params[:row_id]) + @champ.remove_row(params[:row_id], updated_by: current_user.email) @to_remove = "safe-row-selector-#{params[:row_id]}" @to_focus = @champ.focusable_input_id || helpers.dom_id(@champ, :create_repetition) end diff --git a/app/controllers/users/commencer_controller.rb b/app/controllers/users/commencer_controller.rb index 3cbecefe0fd..f88d73af883 100644 --- a/app/controllers/users/commencer_controller.rb +++ b/app/controllers/users/commencer_controller.rb @@ -116,7 +116,7 @@ def build_prefilled_dossier state: Dossier.states.fetch(:brouillon), prefilled: true ) - @prefilled_dossier.build_default_individual + @prefilled_dossier.build_default_values if @prefilled_dossier.save @prefilled_dossier.prefill!(PrefillChamps.new(@prefilled_dossier, params.to_unsafe_h).to_a, PrefillIdentity.new(@prefilled_dossier, params.to_unsafe_h).to_h) end diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index 709730e0ff7..c25bde71e51 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -391,7 +391,7 @@ def new user: current_user, state: Dossier.states.fetch(:brouillon) ) - dossier.build_default_individual + dossier.build_default_values dossier.save! DossierMailer.with(dossier:).notify_new_draft.deliver_later diff --git a/app/graphql/mutations/dossier_modifier_annotation_ajouter_ligne.rb b/app/graphql/mutations/dossier_modifier_annotation_ajouter_ligne.rb index 260cb2734e5..f9ccf2721c9 100644 --- a/app/graphql/mutations/dossier_modifier_annotation_ajouter_ligne.rb +++ b/app/graphql/mutations/dossier_modifier_annotation_ajouter_ligne.rb @@ -14,7 +14,7 @@ def resolve(dossier:, annotation_id:, instructeur:) return { errors: ["L’annotation \"#{annotation_id}\" n’existe pas"] } end - annotation.add_row(dossier.revision) + annotation.add_row(updated_by: instructeur.email) { annotation:, errors: nil } end diff --git a/app/graphql/types/dossier_type.rb b/app/graphql/types/dossier_type.rb index 783b0e3326b..eabf776138c 100644 --- a/app/graphql/types/dossier_type.rb +++ b/app/graphql/types/dossier_type.rb @@ -168,7 +168,7 @@ def champs(id: nil) .for(object, private: false) .load(ApplicationRecord.id_from_typed_id(id)) else - object.champs_for_revision(scope: :public, root: true).filter(&:visible?) + object.project_champs_public.filter(&:visible?) end end @@ -178,7 +178,7 @@ def annotations(id: nil) .for(object, private: true) .load(ApplicationRecord.id_from_typed_id(id)) else - object.champs_for_revision(scope: :private, root: true).filter(&:visible?) + object.project_champs_private.filter(&:visible?) end end diff --git a/app/lib/data_fixer/dossier_champs_missing.rb b/app/lib/data_fixer/dossier_champs_missing.rb deleted file mode 100644 index 64e8eefb18d..00000000000 --- a/app/lib/data_fixer/dossier_champs_missing.rb +++ /dev/null @@ -1,81 +0,0 @@ -# some race condition (regarding double submit of dossier.passer_en_construction!) might remove champs -# until now we haven't decided to push a stronger fix than an UI change -# so we might have to recreate some deleted champs and notify administration -class DataFixer::DossierChampsMissing - def fix - fixed_on_origin = apply_fix(@original_dossier) - - fixed_on_other = Dossier.where(editing_fork_origin_id: @original_dossier.id) - .map(&method(:apply_fix)) - - [fixed_on_origin, fixed_on_other.sum].sum - end - - private - - attr_reader :original_dossier - - def initialize(dossier:) - @original_dossier = dossier - end - - def apply_fix(dossier) - added_champs_root = fix_champs_root(dossier) - added_champs_in_repetition = fix_champs_in_repetition(dossier) - - added_champs = added_champs_root + added_champs_in_repetition - if !added_champs.empty? - dossier.save! - log_champs_added(dossier, added_champs) - added_champs.size - else - 0 - end - end - - def fix_champs_root(dossier) - champs_root, _ = dossier.champs.partition { _1.parent_id.blank? } - expected_tdcs = dossier.revision.revision_types_de_champ.filter { _1.parent.blank? }.map(&:type_de_champ) - - expected_tdcs.filter { !champs_root.map(&:stable_id).include?(_1.stable_id) } - .map do |missing_tdc| - champ_root_missing = missing_tdc.build_champ - - dossier.champs_public << champ_root_missing - champ_root_missing - end - end - - def fix_champs_in_repetition(dossier) - champs_repetition, _ = dossier.champs.partition(&:repetition?) - - champs_repetition.flat_map do |champ_repetition| - champ_repetition_missing = champ_repetition.rows.flat_map do |row| - row_id = row.first.row_id - expected_tdcs = dossier.revision.children_of(champ_repetition.type_de_champ) - row_tdcs = row.map(&:type_de_champ) - - (expected_tdcs - row_tdcs).map do |missing_tdc| - champ_repetition_missing = missing_tdc.build_champ(row_id: row_id) - champ_repetition.champs << champ_repetition_missing - champ_repetition_missing - end - end - end - end - - def log_champs_added(dossier, added_champs) - app_traces = caller.reject { _1.match?(%r{/ruby/.+/gems/}) }.map { _1.sub(Rails.root.to_s, "") } - - payload = { - message: "DataFixer::DossierChampsMissing", - dossier_id: dossier.id, - champs_ids: added_champs.map(&:id).join(","), - caller: app_traces - } - - logger = Lograge.logger || Rails.logger - - logger.info payload.to_json - end -end diff --git a/app/models/attestation_template.rb b/app/models/attestation_template.rb index 98a5dbe0013..b8c6f86b049 100644 --- a/app/models/attestation_template.rb +++ b/app/models/attestation_template.rb @@ -85,13 +85,13 @@ def attestation_for(dossier) end def unspecified_champs_for_dossier(dossier) - champs_by_stable_id = dossier.champs_for_revision(root: true).index_by { "tdc#{_1.stable_id}" } + champs_by_stable_id = dossier.revision.types_de_champ.index_by { "tdc#{_1.stable_id}" } used_tags.filter_map do |used_tag| - corresponding_champ = champs_by_stable_id[used_tag] + corresponding_type_de_champ = champs_by_stable_id[used_tag] - if corresponding_champ && corresponding_champ.blank? - corresponding_champ + if corresponding_type_de_champ && dossier.project_champ(corresponding_type_de_champ, nil).blank? + corresponding_type_de_champ end end end diff --git a/app/models/champ.rb b/app/models/champ.rb index e336ce6c5c1..fc9ed2a2cc3 100644 --- a/app/models/champ.rb +++ b/app/models/champ.rb @@ -1,18 +1,18 @@ class Champ < ApplicationRecord + self.ignored_columns += [:parent_id] + include ChampConditionalConcern include ChampsValidateConcern self.ignored_columns += [:type_de_champ_id] belongs_to :dossier, inverse_of: false, touch: true, optional: false - belongs_to :parent, class_name: 'Champ', optional: true has_many_attached :piece_justificative_file # We declare champ specific relationships (Champs::CarteChamp, Champs::SiretChamp and Champs::RepetitionChamp) # here because otherwise we can't easily use includes in our queries. has_many :geo_areas, -> { order(:created_at) }, dependent: :destroy, inverse_of: :champ belongs_to :etablissement, optional: true, dependent: :destroy - has_many :champs, foreign_key: :parent_id, inverse_of: :parent delegate :procedure, to: :dossier @@ -81,18 +81,18 @@ def type_de_champ scope :root, -> { where(parent_id: nil) } scope :prefilled, -> { where(prefilled: true) } - before_create :set_dossier_id, if: :needs_dossier_id? - before_validation :set_dossier_id, if: :needs_dossier_id? before_save :cleanup_if_empty before_save :normalize after_update_commit :fetch_external_data_later + store_accessor :value_json, :row_deleted_at + def public? !private? end def child? - parent_id.present? + row_id.present? && !repetition? end # used for the `required` html attribute @@ -229,7 +229,7 @@ def update_with_external_data!(data:) end def clone(fork = false) - champ_attributes = [:parent_id, :private, :row_id, :type, :stable_id, :stream] + champ_attributes = [:private, :row_id, :type, :stable_id, :stream] value_attributes = fork || !private? ? [:value, :value_json, :data, :external_id] : [] relationships = fork || !private? ? [:etablissement, :geo_areas] : [] @@ -262,14 +262,6 @@ def html_id "champ-#{public_id}" end - def needs_dossier_id? - !dossier_id && parent_id - end - - def set_dossier_id - self.dossier_id = parent.dossier_id - end - def cleanup_if_empty if fetch_external_data? && persisted? && external_id_changed? self.data = nil diff --git a/app/models/champs/repetition_champ.rb b/app/models/champs/repetition_champ.rb index 7035488dbc0..18e2e7947f8 100644 --- a/app/models/champs/repetition_champ.rb +++ b/app/models/champs/repetition_champ.rb @@ -1,33 +1,20 @@ class Champs::RepetitionChamp < Champ - accepts_nested_attributes_for :champs + delegate :libelle_for_export, to: :type_de_champ def rows - dossier - .champs_for_revision(scope: type_de_champ) - .group_by(&:row_id) - .sort - .map(&:second) + dossier.project_rows_for(type_de_champ) end def row_ids - rows.map { _1.first.row_id } + dossier.repetition_row_ids(type_de_champ) end - def add_row(revision) - added_champs = [] - transaction do - row_id = ULID.generate - revision.children_of(type_de_champ).each do |type_de_champ| - added_champs << type_de_champ.build_champ(row_id:) - end - self.champs << added_champs - end - added_champs + def add_row(updated_by:) + dossier.repetition_add_row(type_de_champ, updated_by:) end - def remove_row(row_id) - dossier.champs.where(row_id:).destroy_all - dossier.champs.reload + def remove_row(row_id, updated_by:) + dossier.repetition_remove_row(type_de_champ, row_id, updated_by:) end def focusable_input_id @@ -35,7 +22,7 @@ def focusable_input_id end def blank? - champs.empty? + row_ids.empty? end def search_terms diff --git a/app/models/concerns/champs_validate_concern.rb b/app/models/concerns/champs_validate_concern.rb index d04a29c5c46..988f1d38233 100644 --- a/app/models/concerns/champs_validate_concern.rb +++ b/app/models/concerns/champs_validate_concern.rb @@ -14,9 +14,9 @@ def valid_champ_value? def validate_champ_value? case validation_context when :champs_public_value - public? && visible? + public? && in_dossier_revision? && visible? when :champs_private_value - private? && visible? + private? && in_dossier_revision? && visible? else false end @@ -25,5 +25,9 @@ def validate_champ_value? def validate_champ_value_or_prefill? validate_champ_value? || validation_context == :prefill end + + def in_dossier_revision? + dossier.revision.types_de_champ.any? { _1.stable_id = stable_id } + end end end diff --git a/app/models/concerns/dossier_champs_concern.rb b/app/models/concerns/dossier_champs_concern.rb index c1350e1f38c..2a656d26300 100644 --- a/app/models/concerns/dossier_champs_concern.rb +++ b/app/models/concerns/dossier_champs_concern.rb @@ -1,21 +1,10 @@ module DossierChampsConcern extend ActiveSupport::Concern - def champs_for_revision(scope: nil, root: false) + def champs_for_revision(scope: nil) champs_index = champs.group_by(&:stable_id) - # Due to some bad data we can have multiple copies of the same champ. Ignore extra copy. - .transform_values { _1.sort_by(&:id).uniq(&:row_id) } - - if scope.is_a?(TypeDeChamp) - revision - .children_of(scope) - .flat_map { champs_index[_1.stable_id] || [] } - .filter(&:child?) # TODO: remove once bad data (child champ without a row id) is cleaned - else - revision - .types_de_champ_for(scope:, root:) - .flat_map { champs_index[_1.stable_id] || [] } - end + revision.types_de_champ_for(scope:) + .flat_map { champs_index[_1.stable_id] || [] } end # Get all the champs values for the types de champ in the final list. @@ -72,6 +61,54 @@ def update_champs_attributes(attributes, scope, updated_by:) assign_attributes(champs_attributes:) end + def project_champs_public + revision.types_de_champ_public.map { project_champ(_1, nil) } + end + + def project_champs_private + revision.types_de_champ_private.map { project_champ(_1, nil) } + end + + def repetition_row_ids(type_de_champ) + stable_ids = [type_de_champ.stable_id] + revision.children_of(type_de_champ).map(&:stable_id) + champs.filter { _1.stable_id.in?(stable_ids) && _1.row_id.present? && _1.row_deleted_at.blank? } + .map(&:row_id) + .uniq + .sort + end + + def repetition_add_row(type_de_champ, updated_by:) + row_id = ULID.generate + champ_for_update(type_de_champ, row_id, updated_by:).save! + @champs_by_public_id = nil + row_id + end + + def repetition_remove_row(type_de_champ, row_id, updated_by:) + row_champ = champ_for_update(type_de_champ, row_id, updated_by:) + row_champ.row_deleted_at = Time.zone.now + + transaction do + champs.where(row_id:).where.not(stable_id: type_de_champ.stable_id).destroy_all + row_champ.save! + end + champs.reload + @champs_by_public_id = nil + end + + def project_rows_for(type_de_champ) + types_de_champ = revision.children_of(type_de_champ) + repetition_row_ids(type_de_champ).map do |row_id| + types_de_champ.map { project_champ(_1, row_id) } + end + end + + def reload + super.tap do + @champs_by_public_id = nil + end + end + private def champs_by_public_id @@ -94,6 +131,9 @@ def champ_attributes_by_public_id(public_id, attributes, scope, updated_by:) end def champ_with_attributes_for_update(type_de_champ, row_id, updated_by:) + if type_de_champ.repetition? && row_id.nil? + raise ArgumentError, "row_id is required for repetition champ" + end attributes = type_de_champ.params_for_champ # TODO: Once we have the right index in place, we should change this to use `create_or_find_by` instead of `find_or_create_by` champ = champs @@ -111,13 +151,6 @@ def champ_with_attributes_for_update(type_de_champ, row_id, updated_by:) attributes[:data] = nil end - parent = revision.parent_of(type_de_champ) - if parent.present? - attributes[:parent] = champs.find { _1.stable_id == parent.stable_id } - else - attributes[:parent] = nil - end - @champs_by_public_id = nil [champ, attributes] diff --git a/app/models/concerns/dossier_clone_concern.rb b/app/models/concerns/dossier_clone_concern.rb index 913af3e45a0..6014219042a 100644 --- a/app/models/concerns/dossier_clone_concern.rb +++ b/app/models/concerns/dossier_clone_concern.rb @@ -80,9 +80,7 @@ def clone(user: nil, fork: false) dossier_attributes += [:groupe_instructeur_id] if fork relationships = [:individual, :etablissement] - cloned_champs = champs_for_revision - .index_by(&:id) - .transform_values { [_1, _1.clone(fork)] } + cloned_champs = champs.map { [_1, _1.clone(fork)] } cloned_dossier = deep_clone(only: dossier_attributes, include: relationships) do |original, kopy| ClonePiecesJustificativesService.clone_attachments(original, kopy) @@ -96,9 +94,8 @@ def clone(user: nil, fork: false) kopy.user = user || original.user kopy.state = Dossier.states.fetch(:brouillon) - kopy.champs = cloned_champs.values.map do |(_, champ)| + kopy.champs = cloned_champs.map do |(_, champ)| champ.dossier = kopy - champ.parent = cloned_champs[champ.parent_id].second if champ.child? champ end end @@ -115,7 +112,7 @@ def clone(user: nil, fork: false) end if fork - cloned_champs.values.each do |(original, champ)| + cloned_champs.each do |(original, champ)| champ.update_columns(created_at: original.created_at, updated_at: original.updated_at) end end @@ -147,35 +144,16 @@ def forked_groupe_instructeur_changed? end def apply_diff(diff) - champs_index = (champs_for_revision(scope: :public) + diff[:added]).index_by(&:public_id) + champs_index = champs.index_by(&:public_id) diff[:added].each do |champ| - if champ.child? - champ.update_columns(dossier_id: id, parent_id: champs_index.fetch(champ.parent.public_id).id) - else - champ.update_column(:dossier_id, id) - end + champ.update_column(:dossier_id, id) end - champs_to_remove = [] diff[:updated].each do |champ| old_champ = champs_index.fetch(champ.public_id) - champs_to_remove << old_champ - - if champ.child? - # we need to do that in order to avoid a foreign key constraint - old_champ.update(row_id: nil) - champ.update_columns(dossier_id: id, parent_id: champs_index.fetch(champ.parent.public_id).id) - else - champ.update_column(:dossier_id, id) - end + old_champ.destroy! + champ.update_column(:dossier_id, id) end - - champs_to_remove += diff[:removed] - children_champs_to_remove, root_champs_to_remove = champs_to_remove.partition(&:child?) - - children_champs_to_remove.each(&:destroy!) - Champ.where(parent_id: root_champs_to_remove.map(&:id)).destroy_all - root_champs_to_remove.each(&:destroy!) end end diff --git a/app/models/concerns/dossier_rebase_concern.rb b/app/models/concerns/dossier_rebase_concern.rb index 1420bab39b5..de8d1907fd1 100644 --- a/app/models/concerns/dossier_rebase_concern.rb +++ b/app/models/concerns/dossier_rebase_concern.rb @@ -62,23 +62,18 @@ def rebase .transform_values { Champ.where(id: _1) } .tap { _1.default = Champ.none } - # remove champ - children_champ, root_champ = changes_by_op[:remove].partition(&:child?) - children_champ.each { champs_by_stable_id[_1.stable_id].destroy_all } - root_champ.each { champs_by_stable_id[_1.stable_id].destroy_all } - # update champ changes_by_op[:update].each { apply(_1, champs_by_stable_id[_1.stable_id]) } # update dossier revision update_column(:revision_id, target_revision.id) - # add champ (after changing dossier revision to avoid errors) + # add repetition champs rows changes_by_op[:add] .map { target_coordinates_by_stable_id[_1.stable_id] } - # add parent champs first so we can then add children - .sort_by { _1.child? ? 1 : 0 } - .each { add_new_champs_for_revision(_1) } + .map(&:type_de_champ) + .filter { _1.repetition? && (_1.mandatory? || _1.private?) } + .each { add_repetition_row_for_revision(_1) } end def apply(change, champs) @@ -115,30 +110,9 @@ def apply(change, champs) end end - def add_new_champs_for_revision(target_coordinate) - if target_coordinate.child? - # If this type de champ is a child, we create a new champ for each row of the parent - parent_stable_id = target_coordinate.parent.stable_id - - champs.filter { _1.stable_id == parent_stable_id }.each do |champ_repetition| - if champ_repetition.champs.present? - champ_repetition.champs.map(&:row_id).uniq.each do |row_id| - champs << create_champ(target_coordinate, champ_repetition, row_id:) - end - elsif target_coordinate.parent.mandatory? - champs << create_champ(target_coordinate, champ_repetition, row_id: ULID.generate) - end - end - else - create_champ(target_coordinate, self) - end - end - - def create_champ(target_coordinate, parent, row_id: nil) - target_coordinate - .type_de_champ - .build_champ(rebased_at: Time.zone.now, row_id:) - .tap { parent.champs << _1 } + def add_repetition_row_for_revision(type_de_champ) + champ = type_de_champ.build_champ(dossier: self, row_id: ULID.generate) + champ.save! end def purge_piece_justificative_file(champ) diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 63bbb2c59c3..de509d1ab0a 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -43,13 +43,9 @@ class Dossier < ApplicationRecord has_one_attached :justificatif_motivation - has_many :champs - # We have to remove champs in a particular order - champs with a reference to a parent have to be - # removed first, otherwise we get a foreign key constraint error. - has_many :champs_to_destroy, -> { order(:parent_id) }, class_name: 'Champ', inverse_of: false, dependent: :destroy + has_many :champs, inverse_of: :dossier, dependent: :destroy has_many :champs_public, -> { root.public_only }, class_name: 'Champ', inverse_of: false has_many :champs_private, -> { root.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 :preloaded_commentaires, -> { includes(:dossier_correction, piece_jointe_attachments: :blob) }, class_name: 'Commentaire', inverse_of: :dossier @@ -141,8 +137,6 @@ def classer_sans_suite(motivation: nil, instructeur: nil, processed_at: Time.zon after_destroy_commit :log_destroy accepts_nested_attributes_for :champs - accepts_nested_attributes_for :champs_public - accepts_nested_attributes_for :champs_private accepts_nested_attributes_for :individual include AASM @@ -268,33 +262,16 @@ def classer_sans_suite(motivation: nil, instructeur: nil, processed_at: Time.zon scope :en_cours, -> { not_archived.state_en_construction_ou_instruction } scope :without_followers, -> { where.missing(:follows) } scope :with_followers, -> { left_outer_joins(:follows).where.not(follows: { id: nil }) } - scope :with_champs, -> { - includes(champs_public: [ - :geo_areas, - piece_justificative_file_attachments: :blob, - champs: [piece_justificative_file_attachments: :blob] - ]) - } - scope :brouillons_recently_updated, -> { updated_since(2.days.ago).state_brouillon.order_by_updated_at } - scope :with_annotations, -> { - includes(champs_private: [ - :geo_areas, - piece_justificative_file_attachments: :blob, - champs: [piece_justificative_file_attachments: :blob] - ]) - } scope :for_api, -> { - with_champs - .with_annotations - .includes(commentaires: { piece_jointe_attachments: :blob }, - justificatif_motivation_attachment: :blob, - attestation: [], - avis: { piece_justificative_file_attachment: :blob }, - traitement: [], - etablissement: [], - individual: [], - user: []) + includes(commentaires: { piece_jointe_attachments: :blob }, + justificatif_motivation_attachment: :blob, + attestation: [], + avis: { piece_justificative_file_attachment: :blob }, + traitement: [], + etablissement: [], + individual: [], + user: []) } scope :with_notifiable_procedure, -> (opts = { notify_on_closed: false }) do @@ -429,7 +406,6 @@ def classer_sans_suite(motivation: nil, instructeur: nil, processed_at: Time.zon delegate :siret, :siren, to: :etablissement, allow_nil: true delegate :france_connected_with_one_identity?, to: :user, allow_nil: true - before_save :build_default_champs_for_new_dossier, if: Proc.new { revision_id_was.nil? && parent_dossier_id.nil? && editing_fork_origin_id.nil? } after_save :send_web_hook @@ -439,8 +415,6 @@ def classer_sans_suite(motivation: nil, instructeur: nil, processed_at: Time.zon validates :mandataire_last_name, presence: true, if: :for_tiers? validates :for_tiers, inclusion: { in: [true, false] }, if: -> { revision&.procedure&.for_individual? } - validates_associated :prefilled_champs_public, on: :champs_public_value - def types_de_champ_public types_de_champ end @@ -489,29 +463,9 @@ def motivation end end - def build_default_champs_for_new_dossier - revision.build_champs_public(self).each do |champ| - champs_public << champ - end - revision.build_champs_private(self).each do |champ| - champs_private << champ - end - champs_public.filter { _1.repetition? && _1.mandatory? }.each do |champ| - champ.add_row(revision) - end - champs_private.filter(&:repetition?).each do |champ| - champ.add_row(revision) - end - end - - def build_default_individual - if procedure.for_individual? && individual.blank? - self.individual = if france_connected_with_one_identity? - Individual.from_france_connect(user.france_connect_informations.first) - else - Individual.new - end - end + def build_default_values + build_default_individual + build_default_champs end def en_construction_ou_instruction? @@ -562,7 +516,7 @@ def blocked_with_pending_correction? def can_passer_en_construction? return true if !revision.ineligibilite_enabled || !revision.ineligibilite_rules - !revision.ineligibilite_rules.compute(champs_for_revision(scope: :public)) + !revision.ineligibilite_rules.compute(project_champs_public) end def can_passer_en_instruction? @@ -947,7 +901,7 @@ def previously_termine? end def remove_titres_identite! - champs_public.filter(&:titre_identite?).map(&:piece_justificative_file).each(&:purge_later) + champs.filter(&:titre_identite?).map(&:piece_justificative_file).each(&:purge_later) end def remove_piece_justificative_file_not_visible! @@ -960,14 +914,21 @@ def remove_piece_justificative_file_not_visible! end def check_mandatory_and_visible_champs - champs_for_revision(scope: :public) - .filter { _1.child? ? _1.parent.visible? : true } - .filter(&:visible?) - .filter(&:mandatory_blank?) - .map do |champ| - champ.errors.add(:value, :missing) + project_champs_public.filter(&:visible?).each do |champ| + if champ.mandatory_blank? + error = champ.errors.add(:value, :missing) + errors.import(error) + end + if champ.repetition? + champ.rows.each do |row| + row.filter(&:visible?).filter(&:mandatory_blank?).each do |champ| + error = champ.errors.add(:value, :missing) + errors.import(error) + end + end end - .each { errors.import(_1) } + end + errors end def demander_un_avis!(avis) @@ -1162,7 +1123,7 @@ def user_from_france_connect? end def has_annotations? - revision.revision_types_de_champ_private.present? + revision.types_de_champ_private.present? end def hide_info_with_accuse_lecture? @@ -1187,6 +1148,45 @@ def track_can_passer_en_construction private + def build_default_champs + build_default_champs_public + build_default_champs_private + end + + def build_default_champs_public + return if champs.any?(&:public?) + + self.champs += revision.types_de_champ_public.filter_map do |type_de_champ| + if type_de_champ.repetition? && type_de_champ.mandatory? + type_de_champ.build_champ(dossier: self, row_id: ULID.generate) + elsif !type_de_champ.non_fillable? + type_de_champ.build_champ(dossier: self) + end + end + end + + def build_default_champs_private + return if champs.any?(&:private?) + + self.champs += revision.types_de_champ_private.filter_map do |type_de_champ| + if type_de_champ.repetition? + type_de_champ.build_champ(dossier: self, row_id: ULID.generate) + elsif !type_de_champ.non_fillable? + type_de_champ.build_champ(dossier: self) + end + end + end + + def build_default_individual + if procedure.for_individual? && individual.blank? + self.individual = if france_connected_with_one_identity? + Individual.from_france_connect(user.france_connect_informations.first) + else + Individual.new + end + end + end + def create_missing_traitemets if en_construction_at.present? && traitements.en_construction.empty? self.traitements.passer_en_construction(processed_at: en_construction_at) diff --git a/app/models/dossier_preloader.rb b/app/models/dossier_preloader.rb index dddf21ec56d..d2b79599d63 100644 --- a/app/models/dossier_preloader.rb +++ b/app/models/dossier_preloader.rb @@ -41,12 +41,6 @@ def revisions .index_by(&:id) end - # returns: { revision_id : { stable_id : position } } - def positions - @positions ||= revisions - .transform_values { |revision| revision.revision_types_de_champ.map { [_1.stable_id, _1.position] }.to_h } - end - def load_dossiers(dossiers, pj_template: false) to_include = @includes_for_champ.dup to_include << [piece_justificative_file_attachments: :blob] @@ -56,16 +50,10 @@ def load_dossiers(dossiers, pj_template: false) .where(dossier_id: dossiers) .to_a - children_champs, root_champs = all_champs.partition(&:child?) - champs_by_dossier = root_champs.group_by(&:dossier_id) - champs_by_dossier_by_parent = children_champs - .group_by(&:dossier_id) - .transform_values do |champs| - champs.group_by(&:parent_id) - end + champs_by_dossier = all_champs.group_by(&:dossier_id) dossiers.each do |dossier| - load_dossier(dossier, champs_by_dossier[dossier.id] || [], champs_by_dossier_by_parent[dossier.id] || {}) + load_dossier(dossier, champs_by_dossier[dossier.id] || []) end load_etablissements(all_champs) @@ -84,17 +72,15 @@ def load_etablissements(champs) end end - def load_dossier(dossier, champs, children_by_parent = {}) + def load_dossier(dossier, champs) revision = revisions[dossier.revision_id] if revision.present? dossier.association(:revision).target = revision end - - champs_public, champs_private = champs.partition(&:public?) - - dossier.association(:champs).target = [] - load_champs(dossier, :champs_public, champs_public, dossier, children_by_parent) - load_champs(dossier, :champs_private, champs_private, dossier, children_by_parent) + dossier.association(:champs).target = champs + champs.each do |champ| + champ.association(:dossier).target = dossier + end # We need to do this because of the check on `Etablissement#champ` in # `Etablissement#libelle_for_export`. By assigning `nil` to `target` we mark association @@ -103,33 +89,4 @@ def load_dossier(dossier, champs, children_by_parent = {}) dossier.etablissement.association(:champ).target = nil end end - - def load_champs(parent, name, champs, dossier, children_by_parent) - if champs.empty? - parent.association(name).target = [] # tells to Rails association has been loaded - return - end - - champs.each do |champ| - champ.association(:dossier).target = dossier - - if parent.is_a?(Champ) - champ.association(:parent).target = parent - end - end - - dossier.association(:champs).target += champs - - parent.association(name).target = champs - .filter { positions[dossier.revision_id][_1.stable_id].present? } - .sort_by { [_1.row_id, positions[dossier.revision_id][_1.stable_id]] } - - # Load children champs - champs.filter(&:block?).each do |parent_champ| - champs = children_by_parent[parent_champ.id] || [] - parent_champ.association(:dossier).target = dossier - - load_champs(parent_champ, :champs, champs, dossier, children_by_parent) - end - end end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index c336dcce52f..4075931d6cb 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -236,20 +236,6 @@ def revisions_with_pending_dossiers includes(:draft_revision, :published_revision, administrateurs: :user) } - scope :for_download, -> { - includes( - :groupe_instructeurs, - dossiers: { - champs_public: [ - piece_justificative_file_attachments: :blob, - champs: [ - piece_justificative_file_attachments: :blob - ] - ] - } - ) - } - validates :libelle, presence: true, allow_blank: false, allow_nil: false validates :description, presence: true, allow_blank: false, allow_nil: false validates :administrateurs, presence: true diff --git a/app/models/procedure_revision.rb b/app/models/procedure_revision.rb index c6e0df7c53d..1a761b342b0 100644 --- a/app/models/procedure_revision.rb +++ b/app/models/procedure_revision.rb @@ -35,16 +35,6 @@ class ProcedureRevision < ApplicationRecord serialize :ineligibilite_rules, LogicSerializer - def build_champs_public(dossier) - # reload: it can be out of sync in test if some tdcs are added wihtout using add_tdc - types_de_champ_public.reload.map { _1.build_champ(dossier:) } - end - - def build_champs_private(dossier) - # reload: it can be out of sync in test if some tdcs are added wihtout using add_tdc - types_de_champ_private.reload.map { _1.build_champ(dossier:) } - end - def add_type_de_champ(params) parent_stable_id = params.delete(:parent_stable_id) parent_coordinate, _ = coordinate_and_tdc(parent_stable_id) @@ -170,26 +160,21 @@ def dossier_for_preview(user) .find_or_initialize_by(revision: self, user: user, for_procedure_preview: true, state: Dossier.states.fetch(:brouillon)) if dossier.new_record? - dossier.build_default_individual + dossier.build_default_values dossier.save! end dossier end - def types_de_champ_for(scope: nil, root: false) - # We return an unordered collection - return types_de_champ if !root && scope.nil? - return types_de_champ.filter { scope == :public ? _1.public? : _1.private? } if !root - - # We return an ordered collection + def types_de_champ_for(scope: nil) case scope when :public - types_de_champ_public + types_de_champ.filter(&:public?) when :private - types_de_champ_private + types_de_champ.filter(&:private?) else - types_de_champ_public + types_de_champ_private + types_de_champ end end diff --git a/app/models/procedure_revision_type_de_champ.rb b/app/models/procedure_revision_type_de_champ.rb index 506e205f742..ccd5a01e143 100644 --- a/app/models/procedure_revision_type_de_champ.rb +++ b/app/models/procedure_revision_type_de_champ.rb @@ -30,8 +30,8 @@ def empty? end def siblings - if parent_id.present? - revision.revision_types_de_champ.where(parent_id: parent_id).ordered + if child? + revision.revision_types_de_champ.where(parent_id:).ordered elsif private? revision.revision_types_de_champ_private else diff --git a/app/models/types_de_champ/prefill_repetition_type_de_champ.rb b/app/models/types_de_champ/prefill_repetition_type_de_champ.rb index a61e7119d5c..42b6b2b10b3 100644 --- a/app/models/types_de_champ/prefill_repetition_type_de_champ.rb +++ b/app/models/types_de_champ/prefill_repetition_type_de_champ.rb @@ -54,8 +54,7 @@ def initialize(champ, repetition, index, revision) def to_assignable_attributes return unless repetition.is_a?(Hash) - row = champ.rows[index] || champ.add_row(revision) - row_id = row.first.row_id + row_id = champ.row_ids[index] || champ.add_row(updated_by: nil) repetition.map do |key, value| next unless key.is_a?(String) && key.starts_with?("champ_") diff --git a/app/serializers/champ_serializer.rb b/app/serializers/champ_serializer.rb index 003f611a57a..3446efaeab4 100644 --- a/app/serializers/champ_serializer.rb +++ b/app/serializers/champ_serializer.rb @@ -47,9 +47,7 @@ def read_attribute_for_serialization(attribute) def rows object.dossier - .champs_for_revision(scope: object.type_de_champ) - .group_by(&:row_id) - .values + .project_rows_for(object.type_de_champ) .map.with_index(1) { |champs, index| Row.new(index:, champs:) } end diff --git a/app/serializers/dossier_serializer.rb b/app/serializers/dossier_serializer.rb index 81e783bba0e..5c88a876d35 100644 --- a/app/serializers/dossier_serializer.rb +++ b/app/serializers/dossier_serializer.rb @@ -30,7 +30,7 @@ class DossierSerializer < ActiveModel::Serializer has_many :champs, serializer: ChampSerializer def champs - champs = object.champs_public.reject { |c| c.type_de_champ.old_pj.present? } + champs = object.project_champs_public.reject { |c| c.type_de_champ.old_pj.present? } if object.expose_legacy_carto_api? champ_carte = champs.find do |champ| @@ -50,12 +50,16 @@ def champs champs end + def champs_private + object.project_champs_private + end + def cerfa [] end def pieces_justificatives - object.champs_public.filter { |champ| champ.type_de_champ.old_pj }.map do |champ| + object.project_champs_public.filter { |champ| champ.type_de_champ.old_pj }.map do |champ| { created_at: champ.created_at&.in_time_zone('UTC'), type_de_piece_justificative_id: champ.type_de_champ.old_pj[:stable_id], diff --git a/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml b/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml index 76b4d576e72..56c83c6854b 100644 --- a/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml +++ b/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml @@ -12,7 +12,7 @@ - if unspecified_attestation_champs.present? .warning Attention, les valeurs suivantes n’ont pas été renseignées mais sont nécessaires pour pouvoir envoyer une attestation valide : - - unspecified_annotations_privees, unspecified_champs = unspecified_attestation_champs.partition(&:private) + - unspecified_annotations_privees, unspecified_champs = unspecified_attestation_champs.partition(&:private?) - if unspecified_champs.present? %h4 Champs de la demande diff --git a/db/migrate/20240321081721_remove_champs_foreign_key.rb b/db/migrate/20240321081721_remove_champs_foreign_key.rb new file mode 100644 index 00000000000..4f3032ecd04 --- /dev/null +++ b/db/migrate/20240321081721_remove_champs_foreign_key.rb @@ -0,0 +1,5 @@ +class RemoveChampsForeignKey < ActiveRecord::Migration[7.0] + def change + remove_foreign_key :champs, column: :parent_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 0544b546ca6..bf73339f721 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1221,7 +1221,6 @@ add_foreign_key "avis", "experts_procedures" add_foreign_key "batch_operations", "instructeurs" add_foreign_key "bulk_messages", "procedures" - add_foreign_key "champs", "champs", column: "parent_id" add_foreign_key "champs", "dossiers" add_foreign_key "champs", "etablissements" add_foreign_key "champs", "types_de_champ" diff --git a/spec/controllers/api/v2/graphql_controller_spec.rb b/spec/controllers/api/v2/graphql_controller_spec.rb index ec5275d8e21..0cfbf1f6ef7 100644 --- a/spec/controllers/api/v2/graphql_controller_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_spec.rb @@ -513,7 +513,7 @@ def format_type_champ(type_champ) avis: [] ) - expected_champs = dossier.champs_public.map do |champ| + expected_champs = dossier.project_champs_public.map do |champ| { id: champ.to_typed_id, label: champ.libelle, @@ -768,44 +768,6 @@ def format_type_champ(type_champ) end end - describe "deletedDossiers" do - let(:query) do - "{ - demarche(number: #{procedure.id}) { - deletedDossiers { - nodes { - id - number - state - reason - dateSupression - } - } - } - }" - end - let(:deleted_dossier) { create(:deleted_dossier, procedure: procedure) } - - before { deleted_dossier } - - it "should be returned" do - expect(gql_errors).to eq(nil) - expect(gql_data).to eq(demarche: { - deletedDossiers: { - nodes: [ - { - id: deleted_dossier.to_typed_id, - number: deleted_dossier.dossier_id, - state: deleted_dossier.state, - reason: deleted_dossier.reason, - dateSupression: deleted_dossier.deleted_at.iso8601 - } - ] - } - }) - end - end - describe "champ piece_justificative" do let(:types_de_champ_public) { [{ type: :piece_justificative }] } let(:champ) { dossier.champs.first } diff --git a/spec/controllers/champs/repetition_controller_spec.rb b/spec/controllers/champs/repetition_controller_spec.rb index 3b80b5c32fb..3a535d0d6f6 100644 --- a/spec/controllers/champs/repetition_controller_spec.rb +++ b/spec/controllers/champs/repetition_controller_spec.rb @@ -7,7 +7,7 @@ it 'removes repetition' do rows, repetitions = dossier.champs.partition(&:child?) repetition = repetitions.first - expect { delete :remove, params: { dossier_id: repetition.dossier, stable_id: repetition.stable_id, row_id: rows.first.row_id }, format: :turbo_stream } + expect { delete :remove, params: { dossier_id: dossier, stable_id: repetition.stable_id, row_id: rows.first.row_id }, format: :turbo_stream } .to change { dossier.reload.champs.size }.from(3).to(1) end end diff --git a/spec/factories/champ.rb b/spec/factories/champ.rb index 6bb952dfba0..770f7fa6c53 100644 --- a/spec/factories/champ.rb +++ b/spec/factories/champ.rb @@ -186,16 +186,20 @@ rows { 2 } end - after(:build) do |champ_repetition, evaluator| - revision = champ_repetition.type_de_champ.procedure.active_revision - parent = revision.revision_types_de_champ.find { _1.type_de_champ == champ_repetition.type_de_champ } - types_de_champ = revision.revision_types_de_champ.filter { _1.parent == parent }.map(&:type_de_champ) - - evaluator.rows.times do - row_id = ULID.generate - champ_repetition.champs << types_de_champ.map do |type_de_champ| - attrs = { dossier: champ_repetition.dossier, parent: champ_repetition, private: champ_repetition.private?, stable_id: type_de_champ.stable_id, row_id: } - build(:"champ_do_not_use_#{type_de_champ.type_champ}", **attrs) + after(:create) do |champ_repetition, evaluator| + revision = champ_repetition.dossier.revision + type_de_champ = champ_repetition.type_de_champ + types_de_champ = revision.children_of(type_de_champ) + + evaluator.rows.times do |n| + attrs = { dossier: champ_repetition.dossier, private: type_de_champ.private?, row_id: ULID.generate } + if n == 0 + champ_repetition.update_column(:row_id, attrs[:row_id]) + else + create(:champ_do_not_use_repetition, rows: 0, stable_id: type_de_champ.stable_id, **attrs) + end + types_de_champ.each do |type_de_champ| + create(:"champ_do_not_use_#{type_de_champ.type_champ}", stable_id: type_de_champ.stable_id, **attrs) end end end diff --git a/spec/factories/dossier.rb b/spec/factories/dossier.rb index 133f242e1d2..0753c9e5353 100644 --- a/spec/factories/dossier.rb +++ b/spec/factories/dossier.rb @@ -9,6 +9,8 @@ individual { association(:individual, :empty, dossier: instance, strategy: :build) if procedure.for_individual? } transient do + populate_champs { false } + populate_annotations { false } for_individual? { false } # For now a dossier must use a `create`d procedure, even if the dossier is only built (and not created). # This is because saving the dossier fails when the procedure has not been saved beforehand @@ -17,6 +19,35 @@ procedure { create(:procedure, :published, :with_type_de_champ, :with_type_de_champ_private, for_individual: for_individual?) } end + after(:create) do |dossier, evaluator| + if evaluator.populate_champs + dossier.revision.types_de_champ_public.each do |type_de_champ| + value = if type_de_champ.simple_drop_down_list? + type_de_champ.drop_down_list_enabled_non_empty_options.first + elsif type_de_champ.multiple_drop_down_list? + type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json + end + attrs = { stable_id: type_de_champ.stable_id, dossier:, value: }.compact + create(:"champ_do_not_use_#{type_de_champ.type_champ}", **attrs) + end + end + + if evaluator.populate_annotations + dossier.revision.types_de_champ_private.each do |type_de_champ| + value = if type_de_champ.simple_drop_down_list? + type_de_champ.drop_down_list_enabled_non_empty_options.first + elsif type_de_champ.multiple_drop_down_list? + type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json + end + attrs = { stable_id: type_de_champ.stable_id, dossier:, private: true, value: }.compact + create(:"champ_do_not_use_#{type_de_champ.type_champ}", **attrs) + end + end + + dossier.build_default_values + dossier.reload + end + trait :with_entreprise do transient do as_degraded_mode { false } @@ -261,35 +292,11 @@ end trait :with_populated_champs do - after(:create) do |dossier, _evaluator| - dossier.champs_to_destroy.where(private: false).destroy_all - dossier.types_de_champ.each do |type_de_champ| - value = if type_de_champ.simple_drop_down_list? - type_de_champ.drop_down_list_enabled_non_empty_options.first - elsif type_de_champ.multiple_drop_down_list? - type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json - end - attrs = { stable_id: type_de_champ.stable_id, dossier:, value: }.compact - create(:"champ_do_not_use_#{type_de_champ.type_champ}", **attrs) - end - dossier.reload - end + populate_champs { true } end trait :with_populated_annotations do - after(:create) do |dossier, _evaluator| - dossier.champs_to_destroy.where(private: true).destroy_all - dossier.types_de_champ_private.each do |type_de_champ| - value = if type_de_champ.simple_drop_down_list? - type_de_champ.drop_down_list_enabled_non_empty_options.first - elsif type_de_champ.multiple_drop_down_list? - type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json - end - attrs = { stable_id: type_de_champ.stable_id, dossier:, private: true, value: }.compact - create(:"champ_do_not_use_#{type_de_champ.type_champ}", **attrs) - end - dossier.reload - end + populate_annotations { true } end trait :prefilled do diff --git a/spec/graphql/annotation_spec.rb b/spec/graphql/annotation_spec.rb index 324a0d09d21..19c4e8be2de 100644 --- a/spec/graphql/annotation_spec.rb +++ b/spec/graphql/annotation_spec.rb @@ -3,7 +3,7 @@ let(:procedure) { create(:procedure, :published, :for_individual, types_de_champ_private: [{ type: :repetition, children: [{ libelle: 'Nom' }, { type: :integer_number, libelle: 'Age' }] }, {}], administrateurs: [admin]) } let(:dossiers) { [] } let(:instructeur) { create(:instructeur, followed_dossiers: dossiers) } - let(:champs_private) { dossier.champs_for_revision(scope: :private, root: true) } + let(:champs_private) { dossier.project_champs_private } let(:query) { '' } let(:context) { { administrateur_id: admin.id, procedure_ids: admin.procedure_ids, write_access: true } } diff --git a/spec/lib/data_fixer/dossier_champs_missing_spec.rb b/spec/lib/data_fixer/dossier_champs_missing_spec.rb index f5ce3bbbed5..715966e05b6 100644 --- a/spec/lib/data_fixer/dossier_champs_missing_spec.rb +++ b/spec/lib/data_fixer/dossier_champs_missing_spec.rb @@ -40,7 +40,7 @@ let(:initial_champ_count) { dossier.champs.count } before do initial_champ_count - champ_repetition.champs.first.destroy + dossier.champs.find(&:child?).destroy end subject { described_class.new(dossier:).fix } diff --git a/spec/lib/recovery/dossier_life_cycle_spec.rb b/spec/lib/recovery/dossier_life_cycle_spec.rb index daae7c868bd..9e42e1cc7dc 100644 --- a/spec/lib/recovery/dossier_life_cycle_spec.rb +++ b/spec/lib/recovery/dossier_life_cycle_spec.rb @@ -15,7 +15,7 @@ let(:dossier) do d = create(:dossier, procedure:) - repetition(d).add_row(d.revision) + repetition(d).add_row(updated_by: d.user.email) pj_champ(d).piece_justificative_file.attach(some_file) carte(d).update(geo_areas: [geo_area]) d.etablissement = create(:etablissement, :with_exercices) diff --git a/spec/models/champ_spec.rb b/spec/models/champ_spec.rb index fe457faff94..391c9c25540 100644 --- a/spec/models/champ_spec.rb +++ b/spec/models/champ_spec.rb @@ -58,17 +58,6 @@ end end - describe "associations" do - it { is_expected.to belong_to(:dossier) } - - context 'when the parent dossier is discarded' do - let(:discarded_dossier) { create(:dossier, :discarded) } - subject(:champ) { discarded_dossier.champs_public.first } - - it { expect(champ.reload.dossier).to eq discarded_dossier } - end - end - describe "normalization" do it "should remove null bytes before save" do champ = Champ.new(value: "foo\u0000bar") @@ -85,7 +74,7 @@ end describe '#public_only' do - let(:dossier) { create(:dossier) } + let(:dossier) { create(:dossier, :with_populated_champs, :with_populated_annotations) } it 'partition public and private' do expect(dossier.champs_public.count).to eq(1) @@ -95,7 +84,7 @@ describe '#public_ordered' do let(:procedure) { create(:simple_procedure) } - let(:dossier) { create(:dossier, procedure: procedure) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure: procedure) } context 'when a procedure has 2 revisions' do it 'does not duplicate the champs' do @@ -107,7 +96,7 @@ describe '#private_ordered' do let(:procedure) { create(:procedure, :with_type_de_champ_private) } - let(:dossier) { create(:dossier, procedure: procedure) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure: procedure) } context 'when a procedure has 2 revisions' do before { procedure.publish } @@ -123,14 +112,14 @@ let(:procedure) do create(:procedure, types_de_champ_public: [{}, { type: :header_section }, { type: :repetition, mandatory: true, children: [{ type: :header_section }] }], types_de_champ_private: [{}, { type: :header_section }]) end - let(:dossier) { create(:dossier, procedure: procedure) } + let(:dossier) { create(:dossier, :with_populated_champs, :with_populated_annotations, procedure: procedure) } let(:public_champ) { dossier.champs_public.first } let(:private_champ) { dossier.champs_private.first } let(:champ_in_repetition) { dossier.champs_public.find(&:repetition?).champs.first } let(:standalone_champ) { build(:champ, type_de_champ: build(:type_de_champ), dossier: build(:dossier)) } let(:public_sections) { dossier.champs_public.filter(&:header_section?) } let(:private_sections) { dossier.champs_private.filter(&:header_section?) } - let(:sections_in_repetition) { champ_in_repetition.parent.champs.filter(&:header_section?) } + let(:sections_in_repetition) { dossier.champs.filter(&:child?).filter(&:header_section?) } it 'returns the sibling sections of a champ' do expect(public_sections).not_to be_empty @@ -597,16 +586,6 @@ let(:champ) { Champs::TextChamp.new(private: true) } it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.public_id}]" } end - - context "when has parent" do - let(:champ) { Champs::TextChamp.new(parent: Champs::TextChamp.new) } - it { expect(champ.input_name).to eq "dossier[champs_public_attributes][#{champ.public_id}]" } - end - - context "when has private parent" do - let(:champ) { Champs::TextChamp.new(private: true, parent: Champs::TextChamp.new(private: true)) } - it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.public_id}]" } - end end describe 'dom_id' do diff --git a/spec/models/concerns/dossier_champs_concern_spec.rb b/spec/models/concerns/dossier_champs_concern_spec.rb index 42d22a3407b..39cc8543aea 100644 --- a/spec/models/concerns/dossier_champs_concern_spec.rb +++ b/spec/models/concerns/dossier_champs_concern_spec.rb @@ -15,7 +15,7 @@ { type: :text, libelle: "Une annotation", stable_id: 995 } ] end - let(:dossier) { create(:dossier, procedure:) } + let(:dossier) { create(:dossier, :with_populated_champs, :with_populated_annotations, procedure:) } describe "#find_type_de_champ_by_stable_id(public)" do subject { dossier.find_type_de_champ_by_stable_id(992, :public) } @@ -48,7 +48,6 @@ it { expect(subject.persisted?).to be_truthy expect(subject.row_id).to eq(row_id) - expect(subject.parent_id).not_to be_nil } end @@ -93,7 +92,7 @@ subject { dossier.champs_for_export(dossier.revision.types_de_champ_public) } it { expect(subject.size).to eq(4) } - it { expect(subject.first).to eq(["Un champ text", nil]) } + it { expect(subject.first).to eq(["Un champ text", 'text']) } end describe "#champs_for_prefill" do @@ -138,7 +137,6 @@ it { expect(subject.persisted?).to be_truthy expect(subject.row_id).to eq(row_id) - expect(subject.parent_id).not_to be_nil } end @@ -158,7 +156,6 @@ expect(subject.persisted?).to be_truthy expect(subject.is_a?(Champs::TextChamp)).to be_truthy expect(subject.row_id).to eq(row_id) - expect(subject.parent_id).not_to be_nil } end end diff --git a/spec/models/concerns/dossier_clone_concern_spec.rb b/spec/models/concerns/dossier_clone_concern_spec.rb index 95506167278..6a1734597fa 100644 --- a/spec/models/concerns/dossier_clone_concern_spec.rb +++ b/spec/models/concerns/dossier_clone_concern_spec.rb @@ -330,8 +330,11 @@ subject { dossier.merge_fork(forked_dossier) } context 'with updated champ' do + let(:type_de_champ_repetition) { TypeDeChamp.find_by(stable_id: 993) } + let(:type_de_champ_in_repetition) { TypeDeChamp.find_by(stable_id: 994) } + let(:row_id) { dossier.repetition_row_ids(type_de_champ_repetition).first } let(:updated_champ) { forked_dossier.champs.find { _1.stable_id == 99 } } - let(:updated_repetition_champ) { forked_dossier.champs.find { _1.stable_id == 994 } } + let(:updated_repetition_champ) { forked_dossier.champ_for_update(type_de_champ_in_repetition, row_id, updated_by: 'test') } before do dossier.champs.each do |champ| @@ -344,9 +347,11 @@ it { expect { subject }.to change { dossier.reload.champs.size }.by(0) } it { expect { subject }.not_to change { dossier.reload.champs.order(:created_at).reject { _1.stable_id.in?([99, 994]) }.map(&:value) } } - it { expect { subject }.to have_enqueued_job(DossierIndexSearchTermsJob).with(dossier) } it { expect { subject }.to change { dossier.reload.champs.find { _1.stable_id == 99 }.value }.from('old value').to('new value') } - it { expect { subject }.to change { dossier.reload.champs.find { _1.stable_id == 994 }.value }.from('old value').to('new value in repetition') } + it do + expect { subject }.to have_enqueued_job(DossierIndexSearchTermsJob).with(dossier) + expect(dossier.reload.champs.find { _1.stable_id == 994 }.value).to eq('new value in repetition') + end it 'fork is hidden after merge' do subject diff --git a/spec/models/concerns/dossier_rebase_concern_spec.rb b/spec/models/concerns/dossier_rebase_concern_spec.rb index 574ca25f4e2..72148e1983d 100644 --- a/spec/models/concerns/dossier_rebase_concern_spec.rb +++ b/spec/models/concerns/dossier_rebase_concern_spec.rb @@ -291,19 +291,19 @@ let(:datetime_type_de_champ) { types_de_champ.find { _1.stable_id == 103 } } let(:yes_no_type_de_champ) { types_de_champ.find { _1.stable_id == 104 } } - let(:text_champ) { dossier.champs_public.find { _1.stable_id == 1 } } - let(:repetition_champ) { dossier.champs_public.find { _1.stable_id == 101 } } - let(:datetime_champ) { dossier.champs_public.find { _1.stable_id == 103 } } + let(:text_champ) { dossier.champs.find { _1.stable_id == 1 } } + let(:repetition_champ) { dossier.champs.find { _1.stable_id == 101 } } + let(:datetime_champ) { dossier.champs.find { _1.stable_id == 103 } } - let(:rebased_text_champ) { dossier.champs_public.find { _1.stable_id == 1 } } - let(:rebased_repetition_champ) { dossier.champs_public.find { _1.stable_id == 101 } } - let(:rebased_datetime_champ) { dossier.champs_public.find { _1.stable_id == 103 } } - let(:rebased_number_champ) { dossier.champs_public.find { _1.stable_id == 105 } } + let(:rebased_text_champ) { dossier.champs.find { _1.stable_id == 1 } } + let(:rebased_repetition_champ) { dossier.champs.find { _1.stable_id == 101 } } + let(:rebased_datetime_champ) { dossier.champs.find { _1.stable_id == 103 } } + let(:rebased_number_champ) { dossier.champs.find { _1.stable_id == 105 } } - let(:rebased_new_repetition_champ) { dossier.champs_public.find { _1.libelle == "une autre repetition" } } + let(:rebased_new_repetition_champ) { dossier.champs.find { _1.libelle == "une autre repetition" } } let(:private_text_type_de_champ) { types_de_champ.find { _1.stable_id == 11 } } - let(:rebased_private_text_champ) { dossier.champs_private.find { _1.stable_id == 11 } } + let(:rebased_private_text_champ) { dossier.champs.find { _1.stable_id == 11 } } context "when revision is published" do before do @@ -344,15 +344,14 @@ datetime_champ.update(value: Time.zone.now.to_s) text_champ.update(value: 'bonjour') # Add two rows then remove previous to last row in order to create a "hole" in the sequence - repetition_champ.add_row(repetition_champ.dossier.revision) - repetition_champ.add_row(repetition_champ.dossier.revision) - repetition_champ.champs.where(row_id: repetition_champ.rows[-2].first.row_id).destroy_all - repetition_champ.reload + repetition_champ.add_row(updated_by: "test") + repetition_champ.add_row(updated_by: "test") + repetition_champ.remove_row(repetition_champ.row_ids[-2], updated_by: "test") end it "updates the brouillon champs with the latest revision changes" do expect(dossier.revision).to eq(procedure.published_revision) - expect(dossier.champs_public.size).to eq(5) + expect(dossier.project_champs_public.size).to eq(5) expect(dossier.champs.count(&:public?)).to eq(7) expect(repetition_champ.rows.size).to eq(2) expect(repetition_champ.rows[0].size).to eq(1) @@ -365,10 +364,10 @@ expect(procedure.revisions.size).to eq(3) expect(dossier.revision).to eq(procedure.published_revision) - expect(dossier.champs_public.size).to eq(7) - expect(dossier.champs.count(&:public?)).to eq(13) + expect(dossier.project_champs_public.size).to eq(7) + expect(dossier.champs.count(&:public?)).to eq(8) expect(rebased_text_champ.value).to eq(text_champ.value) - expect(rebased_text_champ.type_de_champ).not_to eq(text_champ.type_de_champ) + expect(rebased_text_champ.type_de_champ).not_to eq(text_type_de_champ) expect(rebased_datetime_champ.type_champ).to eq(TypeDeChamp.type_champs.fetch(:date)) expect(rebased_datetime_champ.value).to be_nil expect(rebased_repetition_champ.rows.size).to eq(2) @@ -725,8 +724,8 @@ def child_types_champ = dossier.revision.revision_types_de_champ_public.first.re parent.update(type_champ: :integer_number) end - it { expect { subject }.to change { dossier.champs_public.first.champs.count }.from(2).to(0) } - it { expect { subject }.to change { Champ.count }.from(3).to(1) } + it { expect { subject }.to change { dossier.project_champs_public.count }.from(1).to(1) } + it { expect { subject }.to change { Champ.count }.from(1).to(1) } end end end diff --git a/spec/models/concerns/dossier_searchable_concern_spec.rb b/spec/models/concerns/dossier_searchable_concern_spec.rb index 273a2e3fe51..ae78f3a10b9 100644 --- a/spec/models/concerns/dossier_searchable_concern_spec.rb +++ b/spec/models/concerns/dossier_searchable_concern_spec.rb @@ -36,10 +36,8 @@ end it "update columns en construction" do - dossier.update( - champs_public_attributes: [{ id: champ_public.id, value: 'nouvelle valeur publique' }], - champs_private_attributes: [{ id: champ_private.id, value: 'nouvelle valeur privee' }] - ) + dossier.update_champs_attributes({ champ_public.public_id => { value: 'nouvelle valeur publique' } }, :public, updated_by: 'test') + dossier.update_champs_attributes({ champ_private.public_id => { value: 'nouvelle valeur privee' } }, :private, updated_by: 'test') assert_enqueued_jobs(1, only: DossierIndexSearchTermsJob) do dossier.passer_en_construction diff --git a/spec/models/concerns/dossier_sections_concern_spec.rb b/spec/models/concerns/dossier_sections_concern_spec.rb index 32c27972ae5..88e5edb14fd 100644 --- a/spec/models/concerns/dossier_sections_concern_spec.rb +++ b/spec/models/concerns/dossier_sections_concern_spec.rb @@ -48,12 +48,12 @@ describe '#index_for_section_header' do include Logic let(:number_stable_id) { 99 } - let(:types_de_champ) { - [ - { type: :header_section, libelle: "Infos" }, { type: :integer_number, stable_id: number_stable_id }, - { type: :header_section, libelle: "Details", condition: ds_eq(champ_value(99), constant(5)) }, { type: :header_section, libelle: "Conclusion" } - ] -} + let(:types_de_champ) do + [ + { type: :header_section, libelle: "Infos" }, { type: :integer_number, stable_id: number_stable_id }, + { type: :header_section, libelle: "Details", condition: ds_eq(champ_value(99), constant(5)) }, { type: :header_section, libelle: "Conclusion" } + ] + end let(:procedure) { create(:procedure, :for_individual, types_de_champ_public: types_de_champ) } let(:dossier) { create(:dossier, procedure: procedure) } diff --git a/spec/models/concerns/tags_substitution_concern_spec.rb b/spec/models/concerns/tags_substitution_concern_spec.rb index b0c7c5398f8..3f20d7916ff 100644 --- a/spec/models/concerns/tags_substitution_concern_spec.rb +++ b/spec/models/concerns/tags_substitution_concern_spec.rb @@ -233,7 +233,7 @@ def procedure before do repetition = dossier.champs_public .find { |champ| champ.libelle == 'Répétition' } - repetition.add_row(dossier.revision) + repetition.add_row(updated_by: 'test') paul_champs, pierre_champs = repetition.rows paul_champs.first.update(value: 'Paul') diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index b1bf110fc23..f676dbc3632 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -302,22 +302,12 @@ subject { dossier } - describe '#create' do - let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private) } - let(:dossier) { create(:dossier, procedure: procedure, user: user) } - - it 'builds public and private champs' do - expect(dossier.champs_public.count).to eq(1) - expect(dossier.champs_private.count).to eq(1) - end - end - - describe '#build_default_individual' do + describe '#build_default_values' do let(:dossier) { build(:dossier, procedure: procedure, user: user) } subject do dossier.individual = nil - dossier.build_default_individual + dossier.build_default_values end context 'when the dossier belongs to a procedure for individuals' do @@ -513,7 +503,7 @@ context 'when piece_justificative' do let(:types_de_champ_public) { [{ type: :piece_justificative }] } - let(:champ) { dossier.champs_for_revision(scope: :public).find(&:piece_justificative?) } + let(:champ) { dossier.project_champs_public.find(&:piece_justificative?) } context 'when not visible' do let(:visible) { false } @@ -528,7 +518,7 @@ context 'when titre identite' do let(:types_de_champ_public) { [{ type: :titre_identite }] } - let(:champ) { dossier.champs_for_revision(scope: :public).find(&:piece_justificative?) } + let(:champ) { dossier.project_champs_public.find(&:piece_justificative?) } context 'when not visible' do let(:visible) { false } @@ -726,10 +716,10 @@ end describe "#unspecified_attestation_champs" do - let(:procedure) { create(:procedure, attestation_template: attestation_template, types_de_champ_public: types_de_champ, types_de_champ_private: types_de_champ_private) } - let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) } + let(:procedure) { create(:procedure, attestation_template:, types_de_champ_public:, types_de_champ_private:) } + let(:dossier) { create(:dossier, :en_instruction, procedure:) } - let(:types_de_champ) { [tdc_1, tdc_2, tdc_3, tdc_4] } + let(:types_de_champ_public) { [tdc_1, tdc_2, tdc_3, tdc_4] } let(:types_de_champ_private) { [tdc_5, tdc_6, tdc_7, tdc_8] } let(:tdc_1) { { libelle: "specified champ-in-title" } } @@ -742,7 +732,7 @@ let(:tdc_8) { { libelle: "unspecified annotation privée-in-body" } } before do - (dossier.champs_public + dossier.champs_private) + (dossier.project_champs_public + dossier.project_champs_private) .filter { |c| c.libelle.match?(/^specified/) } .each { |c| c.update_attribute(:value, "specified") } end @@ -797,7 +787,7 @@ let(:attestation_template) { build(:attestation_template, :v2) } before do - tdc_content = (types_de_champ + types_de_champ_private).filter_map do |tdc_config| + tdc_content = (types_de_champ_public + types_de_champ_private).filter_map do |tdc_config| next if tdc_config[:libelle].include?("in-title") { @@ -1606,7 +1596,7 @@ context "with mandatory champs" do let(:type_de_champ) { { mandatory: true } } - let(:champ_with_error) { dossier.champs_public.first } + let(:champ_with_error) { dossier.champs.first } before do champ_with_error.value = nil @@ -1615,7 +1605,7 @@ it 'should have errors' do expect(errors).not_to be_empty - expect(errors.first.full_message).to eq("doit être rempli") + expect(errors.first.full_message).to eq("Le champ « Value » doit être rempli") end context "conditionaly visible" do @@ -1648,7 +1638,7 @@ it 'should have errors' do expect(errors).not_to be_empty - expect(errors.first.full_message).to eq("doit être rempli") + expect(errors.first.full_message).to eq("Le champ « Value » doit être rempli") end end end @@ -1657,41 +1647,37 @@ let(:type_de_champ) { { type: :repetition, mandatory: true, children: [{ mandatory: true }] } } let(:revision) { procedure.active_revision } let(:type_de_champ_repetition) { revision.types_de_champ.first } + let(:row_id) { dossier.champs.first.row_ids.first } context "when no champs" do - let(:champ_with_error) { dossier.champs_public.first } - it 'should have errors' do - dossier.champs_public.first.champs.destroy_all - expect(dossier.champs_public.first.rows).to be_empty + dossier.repetition_remove_row(type_de_champ_repetition, row_id, updated_by: 'test') + expect(dossier.champs.first.rows).to be_empty expect(errors).not_to be_empty - expect(errors.first.full_message).to eq("doit être rempli") + expect(errors.first.full_message).to eq("Le champ « Value » doit être rempli") end end context "when mandatory champ inside repetition" do - let(:champ_with_error) { dossier.champs_public.first.champs.first } - it 'should have errors' do - expect(dossier.champs_public.first.rows).not_to be_empty - expect(errors.first.full_message).to eq("doit être rempli") + expect(dossier.champs.first.rows).not_to be_empty + expect(errors.first.full_message).to eq("Le champ « Value » doit être rempli") end context "conditionaly visible" do - let(:champ_with_error) { dossier.champs_public.second.champs.first } let(:types_de_champ) { [{ type: :yes_no, stable_id: 99, mandatory: false }, type_de_champ] } let(:type_de_champ) { { type: :repetition, mandatory: true, children: [{ mandatory: true }], condition: ds_eq(champ_value(99), constant(true)) } } it 'should not have errors' do - expect(dossier.champs_public.second.rows).not_to be_empty + expect(dossier.champs.second.rows).not_to be_empty expect(errors).to be_empty end it 'should have errors' do - dossier.champs_public.first.update(value: 'true') - expect(dossier.champs_public.second.rows).not_to be_empty + dossier.champs.first.update(value: 'true') + expect(dossier.champs.second.rows).not_to be_empty expect(errors).not_to be_empty - expect(errors.first.full_message).to eq("doit être rempli") + expect(errors.first.full_message).to eq("Le champ « Value » doit être rempli") end end end @@ -2025,7 +2011,7 @@ procedure.publish! dossier procedure.draft_revision.remove_type_de_champ(text_type_de_champ.stable_id) - coordinate = procedure.draft_revision.add_type_de_champ(type_champ: TypeDeChamp.type_champs.fetch(:text), libelle: 'New text field', after_stable_id: repetition_champ.stable_id) + coordinate = procedure.draft_revision.add_type_de_champ(type_champ: TypeDeChamp.type_champs.fetch(:text), libelle: 'New text field', after_stable_id: repetition_type_de_champ.stable_id) procedure.draft_revision.find_and_ensure_exclusive_use(yes_no_type_de_champ.stable_id).update(libelle: 'Updated yes/no') procedure.draft_revision.find_and_ensure_exclusive_use(commune_type_de_champ.stable_id).update(libelle: 'Commune de naissance') procedure.draft_revision.find_and_ensure_exclusive_use(repetition_type_de_champ.stable_id).update(libelle: 'Repetition') diff --git a/spec/services/pieces_justificatives_service_spec.rb b/spec/services/pieces_justificatives_service_spec.rb index 9c999588cde..9a9d736d555 100644 --- a/spec/services/pieces_justificatives_service_spec.rb +++ b/spec/services/pieces_justificatives_service_spec.rb @@ -54,11 +54,11 @@ def attachments(champ) = champ.piece_justificative_file.attachments let(:second_champ) { repetition(dossier).champs.second } before do - repetition(dossier).add_row(dossier.revision) + repetition(dossier).add_row(updated_by: 'test') attach_file_to_champ(first_champ) attach_file_to_champ(first_champ) - repetition(dossier).add_row(dossier.revision) + repetition(dossier).add_row(updated_by: 'test') attach_file_to_champ(second_champ) end @@ -525,11 +525,11 @@ def repetition(d, index:) = d.champs_public.filter(&:repetition?)[index] repet_0 = repetition(dossier_1, index: 0) repet_1 = repetition(dossier_1, index: 1) - repet_0.add_row(dossier_1.revision) - repet_0.add_row(dossier_1.revision) + repet_0.add_row(updated_by: dossier_1.user.email) + repet_0.add_row(updated_by: dossier_1.user.email) - repet_1.add_row(dossier_1.revision) - repet_1.add_row(dossier_1.revision) + repet_1.add_row(updated_by: dossier_1.user.email) + repet_1.add_row(updated_by: dossier_1.user.email) end it do diff --git a/spec/services/procedure_export_service_spec.rb b/spec/services/procedure_export_service_spec.rb index 5863ea454ea..40b69a94b38 100644 --- a/spec/services/procedure_export_service_spec.rb +++ b/spec/services/procedure_export_service_spec.rb @@ -415,7 +415,7 @@ context 'with empty repetition' do before do dossiers.flat_map { |dossier| dossier.champs_public.filter(&:repetition?) }.each do |champ| - champ.champs.destroy_all + Champ.where(row_id: champ.row_ids).destroy_all end end diff --git a/spec/services/procedure_export_service_zip_spec.rb b/spec/services/procedure_export_service_zip_spec.rb index 4b8b78e6033..3dab3aea385 100644 --- a/spec/services/procedure_export_service_zip_spec.rb +++ b/spec/services/procedure_export_service_zip_spec.rb @@ -13,7 +13,7 @@ def attachments(champ) = champ.piece_justificative_file.attachments dossiers.each do |dossier| attach_file_to_champ(pj_champ(dossier)) - repetition(dossier).add_row(dossier.revision) + repetition(dossier).add_row(updated_by: 'test') attach_file_to_champ(repetition(dossier).champs.first) attach_file_to_champ(repetition(dossier).champs.first) diff --git a/spec/tasks/maintenance/remove_piece_justificative_file_not_visible_task_spec.rb b/spec/tasks/maintenance/remove_piece_justificative_file_not_visible_task_spec.rb index d6d52631f88..1a61eed7f3f 100644 --- a/spec/tasks/maintenance/remove_piece_justificative_file_not_visible_task_spec.rb +++ b/spec/tasks/maintenance/remove_piece_justificative_file_not_visible_task_spec.rb @@ -13,7 +13,7 @@ module Maintenance before { expect(champ).to receive(:visible?).and_return(visible) } context 'when piece_justificative' do - let(:champ) { dossier.champs_for_revision(scope: :public).find(&:piece_justificative?) } + let(:champ) { dossier.project_champs_public.find(&:piece_justificative?) } context 'when not visible' do let(:visible) { false }