From 229483d16c651cb50b6f2b0cfc40dfc0c5c25b2d Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Mon, 1 Jul 2024 15:31:32 +0200 Subject: [PATCH] refactor(champ): remove type_de_champ_id and champ factories --- .../administrateurs/procedures_controller.rb | 2 +- app/graphql/loaders/champ.rb | 4 +- .../backfill_dossier_repetition_job.rb | 4 +- .../align_champ_with_dossier_revision.rb | 69 ----- app/models/champ.rb | 11 +- .../concerns/champs_validate_concern.rb | 6 +- app/models/concerns/dossier_champs_concern.rb | 4 +- app/models/concerns/dossier_rebase_concern.rb | 13 +- app/models/dossier.rb | 15 +- app/models/dossier_preloader.rb | 40 +-- app/models/logic/champ_value.rb | 1 - app/models/procedure_revision.rb | 8 +- app/models/type_de_champ.rb | 13 +- .../20230522065646_fix_champs_revisions.rake | 19 -- .../attachment/edit_component_spec.rb | 7 +- .../attachment/multiple_component_spec.rb | 13 +- .../attachment/pending_poll_component_spec.rb | 20 +- .../attachment/show_component_spec.rb | 16 +- .../datetime_component_spec.rb | 10 +- .../editable_champ_component_spec.rb | 41 ++- .../explication_component_spec.rb | 14 +- .../piece_justificative_component_spec.rb | 7 +- .../header_section_component_spec.rb | 52 ++-- .../api/public/v1/dossiers_controller_spec.rb | 2 +- .../api/v2/graphql_controller_spec.rb | 12 +- .../attachments_controller_spec.rb | 7 +- .../experts/avis_controller_spec.rb | 6 +- .../instructeurs/dossiers_controller_spec.rb | 8 +- .../users/commencer_controller_spec.rb | 6 +- spec/factories/champ.rb | 203 ++++----------- spec/factories/dossier.rb | 51 +--- spec/factories/geo_area.rb | 1 - spec/helpers/gallery_helper_spec.rb | 8 +- .../champ_fetch_external_data_job_spec.rb | 7 +- .../backfill_siret_degraded_mode_job_spec.rb | 7 +- .../dossier_index_search_terms_job_spec.rb | 10 +- .../batch_update_datetime_values_job_spec.rb | 20 +- .../batch_update_pays_values_job_spec.rb | 19 +- .../migrations/normalize_communes_job_spec.rb | 6 +- .../align_champ_with_dossier_revision_spec.rb | 68 ----- spec/models/champ_private_spec.rb | 2 +- spec/models/champ_shared_example.rb | 56 ---- spec/models/champ_spec.rb | 244 +++++++++++------- spec/models/champs/address_champ_spec.rb | 8 +- .../champs/annuaire_education_champ_spec.rb | 4 +- spec/models/champs/carte_champ_spec.rb | 3 +- spec/models/champs/checkbox_champ_spec.rb | 9 +- spec/models/champs/cnaf_champ_spec.rb | 6 +- spec/models/champs/cojo_champ_spec.rb | 24 +- spec/models/champs/commune_champ_spec.rb | 18 +- spec/models/champs/date_champ_spec.rb | 32 +-- spec/models/champs/datetime_champ_spec.rb | 30 +-- .../champs/decimal_number_champ_spec.rb | 18 +- spec/models/champs/departement_champ_spec.rb | 10 +- spec/models/champs/dgfip_champ_spec.rb | 5 +- spec/models/champs/dossier_link_champ_spec.rb | 2 +- .../champs/drop_down_list_champ_spec.rb | 6 +- spec/models/champs/email_champ_spec.rb | 4 +- spec/models/champs/epci_champ_spec.rb | 24 +- spec/models/champs/iban_champ_spec.rb | 19 +- .../champs/integer_number_champ_spec.rb | 3 +- .../linked_drop_down_list_champ_spec.rb | 17 +- spec/models/champs/mesri_champ_spec.rb | 4 +- .../multiple_drop_down_list_champ_spec.rb | 3 +- spec/models/champs/pays_champ_spec.rb | 3 +- spec/models/champs/phone_champ_spec.rb | 4 +- .../champs/piece_justificative_champ_spec.rb | 40 ++- spec/models/champs/pole_emploi_champ_spec.rb | 4 +- spec/models/champs/region_champ_spec.rb | 29 ++- spec/models/champs/rna_champ_spec.rb | 17 +- spec/models/champs/rnf_champ_spec.rb | 16 +- .../champs/titre_identite_champ_spec.rb | 15 +- spec/models/champs/yes_no_champ_spec.rb | 3 +- .../champ_conditional_concern_spec.rb | 9 +- .../concerns/dossier_clone_concern_spec.rb | 79 +++--- .../dossier_prefillable_concern_spec.rb | 2 +- .../concerns/dossier_rebase_concern_spec.rb | 8 +- ...hamp_association_fetchable_concern_spec.rb | 8 +- ...mp_etablissement_fetchable_concern_spec.rb | 4 +- .../tags_substitution_concern_spec.rb | 4 +- spec/models/concerns/treeable_concern_spec.rb | 97 ++++--- spec/models/dossier_spec.rb | 70 +++-- .../models/engagement_juridique_champ_spec.rb | 7 +- spec/models/etablissement_spec.rb | 3 + spec/models/export_template_spec.rb | 52 ++-- spec/models/logic/binary_operator_spec.rb | 11 +- spec/models/logic/champ_value_spec.rb | 76 ++++-- spec/models/logic/exclude_operator_spec.rb | 5 +- .../logic/in_departement_operator_spec.rb | 21 +- spec/models/logic/in_region_operator_spec.rb | 25 +- spec/models/logic/include_operator_spec.rb | 5 +- .../logic/not_in_departement_operator_spec.rb | 21 +- .../logic/not_in_region_operator_spec.rb | 29 ++- spec/models/prefill_champs_spec.rb | 8 +- spec/models/procedure_presentation_spec.rb | 24 +- spec/models/procedure_spec.rb | 11 +- spec/models/stat_spec.rb | 16 +- spec/models/type_de_champ_spec.rb | 13 +- .../prefill_address_type_de_champ_spec.rb | 7 +- ...l_annuaire_education_type_de_champ_spec.rb | 7 +- .../prefill_commune_type_de_champ_spec.rb | 5 +- .../prefill_epci_type_de_champ_spec.rb | 4 +- .../prefill_repetition_type_de_champ_spec.rb | 6 +- .../prefill_type_de_champ_spec.rb | 6 +- spec/serializers/champ_serializer_spec.rb | 156 ----------- spec/serializers/dossier_serializer_spec.rb | 96 ------- spec/serializers/dossiers_serializer_spec.rb | 12 - .../serializers/individual_serializer_spec.rb | 20 -- spec/serializers/procedure_serializer_spec.rb | 44 ---- .../services/procedure_export_service_spec.rb | 15 +- spec/services/serializer_service_spec.rb | 10 +- spec/system/experts/expert_spec.rb | 43 +-- spec/system/instructeurs/expert_spec.rb | 6 +- .../instructeurs/procedure_filters_spec.rb | 4 +- spec/system/users/dossier_prefill_get_spec.rb | 59 +++-- .../system/users/dossier_prefill_post_spec.rb | 43 ++- spec/system/users/en_construction_spec.rb | 2 +- ...ews_for_pj_of_latest_dossiers_task_spec.rb | 7 +- ...nts_for_pj_of_latest_dossiers_task_spec.rb | 5 +- .../_show.html.haml_spec.rb | 7 +- 120 files changed, 1144 insertions(+), 1540 deletions(-) delete mode 100644 app/lib/recovery/align_champ_with_dossier_revision.rb delete mode 100644 lib/tasks/deployment/20230522065646_fix_champs_revisions.rake delete mode 100644 spec/lib/recovery/align_champ_with_dossier_revision_spec.rb delete mode 100644 spec/models/champ_shared_example.rb delete mode 100644 spec/serializers/champ_serializer_spec.rb delete mode 100644 spec/serializers/dossier_serializer_spec.rb delete mode 100644 spec/serializers/dossiers_serializer_spec.rb delete mode 100644 spec/serializers/individual_serializer_spec.rb delete mode 100644 spec/serializers/procedure_serializer_spec.rb diff --git a/app/controllers/administrateurs/procedures_controller.rb b/app/controllers/administrateurs/procedures_controller.rb index 98a3073e0..3167f4445 100644 --- a/app/controllers/administrateurs/procedures_controller.rb +++ b/app/controllers/administrateurs/procedures_controller.rb @@ -476,7 +476,7 @@ module Administrateurs procedures_result = procedures_result.where(aasm_state: filter.statuses) if filter.statuses.present? procedures_result = procedures_result.where("tags @> ARRAY[?]::text[]", filter.tags) if filter.tags.present? procedures_result = procedures_result.where(template: true) if filter.template? - procedures_result = procedures_result.where('published_at >= ?', filter.from_publication_date) if filter.from_publication_date.present? + procedures_result = procedures_result.where(published_at: filter.from_publication_date..) if filter.from_publication_date.present? procedures_result = procedures_result.where(service: service) if filter.service_siret.present? procedures_result = procedures_result.where(service: services) if services procedures_result = procedures_result.where(for_individual: filter.for_individual) if filter.for_individual.present? diff --git a/app/graphql/loaders/champ.rb b/app/graphql/loaders/champ.rb index 5f5bee562..0c5e0f27d 100644 --- a/app/graphql/loaders/champ.rb +++ b/app/graphql/loaders/champ.rb @@ -19,9 +19,7 @@ module Loaders private def query(keys) - ::Champ.where(@where) - .includes(:type_de_champ) - .where(types_de_champ: { stable_id: keys }) + ::Champ.where(@where).where(stable_id: keys) end end end diff --git a/app/jobs/migrations/backfill_dossier_repetition_job.rb b/app/jobs/migrations/backfill_dossier_repetition_job.rb index 6c03b5dc5..5d19abaf0 100644 --- a/app/jobs/migrations/backfill_dossier_repetition_job.rb +++ b/app/jobs/migrations/backfill_dossier_repetition_job.rb @@ -7,10 +7,10 @@ class Migrations::BackfillDossierRepetitionJob < ApplicationJob .revision .types_de_champ .filter do |type_de_champ| - type_de_champ.type_champ == 'repetition' && dossier.champs.none? { _1.type_de_champ_id == type_de_champ.id } + type_de_champ.type_champ == 'repetition' && dossier.champs.none? { _1.stable_id == type_de_champ.stable_id } end .each do |type_de_champ| - dossier.champs << type_de_champ.champ.build + dossier.champs << type_de_champ.build_champ end end end diff --git a/app/lib/recovery/align_champ_with_dossier_revision.rb b/app/lib/recovery/align_champ_with_dossier_revision.rb deleted file mode 100644 index 8fdba8dc9..000000000 --- a/app/lib/recovery/align_champ_with_dossier_revision.rb +++ /dev/null @@ -1,69 +0,0 @@ -class Recovery::AlignChampWithDossierRevision - def initialize(dossiers, progress: nil) - @dossiers = dossiers - @progress = progress - @logs = [] - end - - attr_reader :logs - - def run(destroy_extra_champs: false) - @logs = [] - bad_dossier_ids = find_broken_dossier_ids - - Dossier - .where(id: bad_dossier_ids) - .includes(:procedure, champs: { type_de_champ: :revisions }) - .find_each do |dossier| - bad_champs = dossier.champs.filter { !dossier.revision_id.in?(_1.type_de_champ.revisions.ids) } - bad_champs.each do |champ| - type_de_champ = dossier.revision.types_de_champ.find { _1.stable_id == champ.stable_id } - state = { - champ_id: champ.id, - champ_type_de_champ_id: champ.type_de_champ_id, - dossier_id: dossier.id, - dossier_revision_id: dossier.revision_id, - procedure_id: dossier.procedure.id - } - if type_de_champ.present? - logs << state.merge(status: :updated, type_de_champ_id: type_de_champ.id) - champ.update_column(:type_de_champ_id, type_de_champ.id) - else - logs << state.merge(status: :not_found) - champ.destroy! if destroy_extra_champs - end - end - end - end - - def find_broken_dossier_ids - bad_dossier_ids = [] - - @dossiers.in_batches(of: 15_000) do |dossiers| - dossier_ids_revision_ids = dossiers.pluck(:id, :revision_id) - dossier_ids = dossier_ids_revision_ids.map(&:first) - dossier_ids_type_de_champ_ids = Champ.where(dossier_id: dossier_ids).pluck(:dossier_id, :type_de_champ_id) - type_de_champ_ids = dossier_ids_type_de_champ_ids.map(&:second).uniq - revision_ids_by_type_de_champ_id = ProcedureRevisionTypeDeChamp - .where(type_de_champ_id: type_de_champ_ids) - .pluck(:type_de_champ_id, :revision_id) - .group_by(&:first).transform_values { _1.map(&:second).uniq } - - type_de_champ_ids_by_dossier_id = dossier_ids_type_de_champ_ids - .group_by(&:first) - .transform_values { _1.map(&:second).uniq } - - bad_dossier_ids += dossier_ids_revision_ids.filter do |(dossier_id, revision_id)| - type_de_champ_ids_by_dossier_id.fetch(dossier_id, []).any? do |type_de_champ_id| - !revision_id.in?(revision_ids_by_type_de_champ_id.fetch(type_de_champ_id, [])) - end - end.map(&:first) - - @progress.inc(dossiers.count) if @progress - end - - @progress.finish if @progress - - bad_dossier_ids - end -end diff --git a/app/models/champ.rb b/app/models/champ.rb index 0f3eb9525..e336ce6c5 100644 --- a/app/models/champ.rb +++ b/app/models/champ.rb @@ -2,8 +2,9 @@ class Champ < ApplicationRecord include ChampConditionalConcern include ChampsValidateConcern + self.ignored_columns += [:type_de_champ_id] + belongs_to :dossier, inverse_of: false, touch: true, optional: false - belongs_to :type_de_champ, inverse_of: :champ, optional: false belongs_to :parent, class_name: 'Champ', optional: true has_many_attached :piece_justificative_file @@ -15,6 +16,12 @@ class Champ < ApplicationRecord delegate :procedure, to: :dossier + def type_de_champ + @type_de_champ ||= dossier.revision + .types_de_champ + .find(-> { raise "Type De Champ #{stable_id} not found in Revision #{dossier.revision_id}" }) { _1.stable_id == stable_id } + end + delegate :libelle, :type_champ, :description, @@ -222,7 +229,7 @@ class Champ < ApplicationRecord end def clone(fork = false) - champ_attributes = [:parent_id, :private, :row_id, :type, :type_de_champ_id, :stable_id, :stream] + champ_attributes = [:parent_id, :private, :row_id, :type, :stable_id, :stream] value_attributes = fork || !private? ? [:value, :value_json, :data, :external_id] : [] relationships = fork || !private? ? [:etablissement, :geo_areas] : [] diff --git a/app/models/concerns/champs_validate_concern.rb b/app/models/concerns/champs_validate_concern.rb index e9f040908..d04a29c5c 100644 --- a/app/models/concerns/champs_validate_concern.rb +++ b/app/models/concerns/champs_validate_concern.rb @@ -12,13 +12,11 @@ module ChampsValidateConcern private def validate_champ_value? - return false unless visible? - case validation_context when :champs_public_value - public? + public? && visible? when :champs_private_value - private? + private? && visible? else false end diff --git a/app/models/concerns/dossier_champs_concern.rb b/app/models/concerns/dossier_champs_concern.rb index a5c05a5d0..c1350e1f3 100644 --- a/app/models/concerns/dossier_champs_concern.rb +++ b/app/models/concerns/dossier_champs_concern.rb @@ -97,7 +97,7 @@ module DossierChampsConcern 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 - .create_with(type_de_champ:, **attributes) + .create_with(**attributes) .find_or_create_by!(stable_id: type_de_champ.stable_id, row_id:) attributes[:id] = champ.id @@ -113,7 +113,7 @@ module DossierChampsConcern parent = revision.parent_of(type_de_champ) if parent.present? - attributes[:parent] = champs.find { _1.type_de_champ_id == parent.id } + attributes[:parent] = champs.find { _1.stable_id == parent.stable_id } else attributes[:parent] = nil end diff --git a/app/models/concerns/dossier_rebase_concern.rb b/app/models/concerns/dossier_rebase_concern.rb index 49807793c..1bea21a4e 100644 --- a/app/models/concerns/dossier_rebase_concern.rb +++ b/app/models/concerns/dossier_rebase_concern.rb @@ -50,7 +50,7 @@ module DossierRebaseConcern # index published types de champ coordinates by stable_id target_coordinates_by_stable_id = target_revision .revision_types_de_champ - .includes(:type_de_champ, :parent) + .includes(:parent) .index_by(&:stable_id) changes_by_op = pending_changes @@ -58,7 +58,6 @@ module DossierRebaseConcern .tap { _1.default = [] } champs_by_stable_id = champs - .includes(:type_de_champ) .group_by(&:stable_id) .transform_values { Champ.where(id: _1) } .tap { _1.default = Champ.none } @@ -78,14 +77,6 @@ module DossierRebaseConcern # update champ changes_by_op[:update].each { apply(_1, champs_by_stable_id[_1.stable_id]) } - # due to repetition tdc clone on update or erase - # we must reassign tdc to the latest version - champs_by_stable_id.each do |stable_id, champs| - if target_coordinates_by_stable_id[stable_id].present? && champs.present? - champs.update_all(type_de_champ_id: target_coordinates_by_stable_id[stable_id].type_de_champ_id) - end - end - # update dossier revision update_column(:revision_id, target_revision.id) end @@ -134,7 +125,7 @@ module DossierRebaseConcern champ_repetition.champs.map(&:row_id).uniq.each do |row_id| champs << create_champ(target_coordinate, champ_repetition, row_id:) end - elsif champ_repetition.mandatory? + elsif target_coordinate.parent.mandatory? champs << create_champ(target_coordinate, champ_repetition, row_id: ULID.generate) end end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 1f175d858..7ea0d4e99 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -242,10 +242,7 @@ class Dossier < ApplicationRecord scope :hidden_by_administration_since, -> (since) { where('dossiers.hidden_by_administration_at IS NOT NULL AND dossiers.hidden_by_administration_at >= ?', since) } scope :hidden_since, -> (since) { hidden_by_user_since(since).or(hidden_by_administration_since(since)) } - scope :with_type_de_champ, -> (stable_id) { - joins('INNER JOIN champs ON champs.dossier_id = dossiers.id INNER JOIN types_de_champ ON types_de_champ.id = champs.type_de_champ_id') - .where(types_de_champ: { stable_id: }) - } + scope :with_type_de_champ, -> (stable_id) { joins(:champs).where(champs: { stream: 'main', stable_id: }) } scope :all_state, -> { not_archived.state_not_brouillon } scope :en_construction, -> { not_archived.state_en_construction } @@ -271,20 +268,18 @@ class Dossier < ApplicationRecord scope :with_followers, -> { left_outer_joins(:follows).where.not(follows: { id: nil }) } scope :with_champs, -> { includes(champs_public: [ - :type_de_champ, :geo_areas, piece_justificative_file_attachments: :blob, - champs: [:type_de_champ, 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: [ - :type_de_champ, :geo_areas, piece_justificative_file_attachments: :blob, - champs: [:type_de_champ, piece_justificative_file_attachments: :blob] + champs: [piece_justificative_file_attachments: :blob] ]) } scope :for_api, -> { @@ -493,10 +488,10 @@ class Dossier < ApplicationRecord end def build_default_champs_for_new_dossier - revision.build_champs_public.each do |champ| + revision.build_champs_public(self).each do |champ| champs_public << champ end - revision.build_champs_private.each do |champ| + revision.build_champs_private(self).each do |champ| champs_private << champ end champs_public.filter { _1.repetition? && _1.mandatory? }.each do |champ| diff --git a/app/models/dossier_preloader.rb b/app/models/dossier_preloader.rb index fd19a3ab1..dddf21ec5 100644 --- a/app/models/dossier_preloader.rb +++ b/app/models/dossier_preloader.rb @@ -15,7 +15,7 @@ class DossierPreloader def in_batches_with_block(size = DEFAULT_BATCH_SIZE, &block) @dossiers.in_batches(of: size) do |batch| - data = Dossier.where(id: batch.ids).includes(:individual, :traitement, :etablissement, user: :france_connect_informations, avis: :expert, commentaires: [:instructeur, :expert], revision: :revision_types_de_champ) + data = Dossier.where(id: batch.ids).includes(:individual, :traitement, :etablissement, user: :france_connect_informations, avis: :expert, commentaires: [:instructeur, :expert]) dossiers = data.to_a load_dossiers(dossiers) @@ -30,39 +30,32 @@ class DossierPreloader end def self.load_one(dossier, pj_template: false) - DossierPreloader.new([dossier]).all(pj_template: pj_template).first + DossierPreloader.new([dossier]).all(pj_template:).first end private - # returns: { revision_id : { type_de_champ_id : position } } + def revisions + @revisions ||= ProcedureRevision.where(id: @dossiers.pluck(:revision_id).uniq) + .includes(types_de_champ: { piece_justificative_template_attachment: :blob }) + .index_by(&:id) + end + + # returns: { revision_id : { stable_id : position } } def positions - @positions ||= ProcedureRevisionTypeDeChamp - .where(revision_id: @dossiers.pluck(:revision_id).uniq) - .select(:revision_id, :type_de_champ_id, :position) - .group_by(&:revision_id) - .transform_values do |coordinates| - coordinates.index_by(&:type_de_champ_id).transform_values(&:position) - end + @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] - if pj_template - to_include << { type_de_champ: { piece_justificative_template_attachment: :blob } } - else - to_include << :type_de_champ - end - all_champs = Champ .includes(to_include) .where(dossier_id: dossiers) .to_a - load_etablissements(all_champs) - children_champs, root_champs = all_champs.partition(&:child?) champs_by_dossier = root_champs.group_by(&:dossier_id) champs_by_dossier_by_parent = children_champs @@ -74,6 +67,8 @@ class DossierPreloader dossiers.each do |dossier| load_dossier(dossier, champs_by_dossier[dossier.id] || [], champs_by_dossier_by_parent[dossier.id] || {}) end + + load_etablissements(all_champs) end def load_etablissements(champs) @@ -90,6 +85,11 @@ class DossierPreloader end def load_dossier(dossier, champs, children_by_parent = {}) + 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 = [] @@ -121,8 +121,8 @@ class DossierPreloader dossier.association(:champs).target += champs parent.association(name).target = champs - .filter { positions[dossier.revision_id][_1.type_de_champ_id].present? } - .sort_by { [_1.row_id, positions[dossier.revision_id][_1.type_de_champ_id]] } + .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| diff --git a/app/models/logic/champ_value.rb b/app/models/logic/champ_value.rb index efb46a55a..59d5d43b4 100644 --- a/app/models/logic/champ_value.rb +++ b/app/models/logic/champ_value.rb @@ -41,7 +41,6 @@ class Logic::ChampValue < Logic::Term return nil if !targeted_champ.visible? return nil if targeted_champ.blank? & !targeted_champ.drop_down_other? - # on dépense 22ms ici, à cause du map, mais on doit pouvoir passer par un champ type case targeted_champ.type when "Champs::YesNoChamp", "Champs::CheckboxChamp" diff --git a/app/models/procedure_revision.rb b/app/models/procedure_revision.rb index 709ae8472..c3853b20a 100644 --- a/app/models/procedure_revision.rb +++ b/app/models/procedure_revision.rb @@ -35,14 +35,14 @@ class ProcedureRevision < ApplicationRecord serialize :ineligibilite_rules, LogicSerializer - def build_champs_public + 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(&:build_champ) + types_de_champ_public.reload.map { _1.build_champ(dossier:) } end - def build_champs_private + 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(&:build_champ) + types_de_champ_private.reload.map { _1.build_champ(dossier:) } end def add_type_de_champ(params) diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index abc959a7b..bcf24c0f1 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -179,16 +179,6 @@ class TypeDeChamp < ApplicationRecord .where(type_champ: [TypeDeChamp.type_champs.fetch(:text), TypeDeChamp.type_champs.fetch(:textarea)]) } - has_many :champ, inverse_of: :type_de_champ, dependent: :destroy do - def build(params = {}) - super(params.merge(proxy_association.owner.params_for_champ)) - end - - def create(params = {}) - super(params.merge(proxy_association.owner.params_for_champ)) - end - end - has_one_attached :piece_justificative_template validates :piece_justificative_template, size: { less_than: FILE_MAX_SIZE }, on: :update validates :piece_justificative_template, content_type: AUTHORIZED_CONTENT_TYPES, on: :update @@ -257,7 +247,7 @@ class TypeDeChamp < ApplicationRecord end def build_champ(params = {}) - champ.build(params) + self.class.type_champ_to_champ_class_name(type_champ).constantize.new(params_for_champ.merge(params)) end def check_mandatory @@ -740,7 +730,6 @@ class TypeDeChamp < ApplicationRecord return true if type_champ_to_champ_class_name(type_champ) != champ.type # special case for linked drop down champ – it's blank implementation is not what you think return champ.value.blank? if type_champ == TypeDeChamp.type_champs.fetch(:linked_drop_down_list) - champ.blank? end end diff --git a/lib/tasks/deployment/20230522065646_fix_champs_revisions.rake b/lib/tasks/deployment/20230522065646_fix_champs_revisions.rake deleted file mode 100644 index 6b2391a7e..000000000 --- a/lib/tasks/deployment/20230522065646_fix_champs_revisions.rake +++ /dev/null @@ -1,19 +0,0 @@ -namespace :after_party do - desc 'Deployment task: fix_champs_revisions' - task fix_champs_revisions: :environment do - puts "Running deploy task 'fix_champs_revisions'" - - progress = ProgressReport.new(Dossier.count) - - fixer = Recovery::AlignChampWithDossierRevision.new(Dossier, progress:) - fixer.run - fixer.logs.each do |log| - puts JSON.dump(log) - end - - # Update task as completed. If you remove the line below, the task will - # run with every deploy (or every time you call after_party:run). - AfterParty::TaskRecord - .create version: AfterParty::TaskRecorder.new(__FILE__).timestamp - end -end diff --git a/spec/components/attachment/edit_component_spec.rb b/spec/components/attachment/edit_component_spec.rb index c9298f9ff..fd2b8dd18 100644 --- a/spec/components/attachment/edit_component_spec.rb +++ b/spec/components/attachment/edit_component_spec.rb @@ -1,5 +1,8 @@ RSpec.describe Attachment::EditComponent, type: :component do - let(:champ) { create(:champ_titre_identite, dossier: create(:dossier)) } + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :titre_identite }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } let(:attached_file) { champ.piece_justificative_file } let(:attachment) { attached_file.attachments.first } let(:filename) { attachment.filename.to_s } @@ -98,8 +101,6 @@ RSpec.describe Attachment::EditComponent, type: :component do end context 'when watermark is pending' do - let(:champ) { create(:champ_titre_identite) } - it 'displays the filename, but doesn’t allow to download the file' do expect(attachment.watermark_pending?).to be_truthy expect(subject).to have_text(filename) diff --git a/spec/components/attachment/multiple_component_spec.rb b/spec/components/attachment/multiple_component_spec.rb index 143831280..9d5e92628 100644 --- a/spec/components/attachment/multiple_component_spec.rb +++ b/spec/components/attachment/multiple_component_spec.rb @@ -1,5 +1,9 @@ RSpec.describe Attachment::MultipleComponent, type: :component do - let(:champ) { create(:champ_titre_identite) } + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :titre_identite }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } + let(:attached_file) { champ.piece_justificative_file } let(:kwargs) { {} } @@ -14,14 +18,11 @@ RSpec.describe Attachment::MultipleComponent, type: :component do subject { render_inline(component).to_html } context 'when there is no attachment yet' do - let(:champ) { create(:champ_titre_identite, skip_default_attachment: true) } + let(:dossier) { create(:dossier, procedure:) } - it 'renders a form field for uploading a file' do + it 'renders a form field for uploading a file and max attachment size' do expect(subject).to have_no_selector('.hidden input[type=file]') expect(subject).to have_selector('input[type=file]:not(.hidden)') - end - - it 'renders max size' do expect(subject).to have_content(/Taille maximale :\s+20 Mo/) end end diff --git a/spec/components/attachment/pending_poll_component_spec.rb b/spec/components/attachment/pending_poll_component_spec.rb index 1b2c059c0..5af564c58 100644 --- a/spec/components/attachment/pending_poll_component_spec.rb +++ b/spec/components/attachment/pending_poll_component_spec.rb @@ -3,15 +3,16 @@ require "rails_helper" RSpec.describe Attachment::PendingPollComponent, type: :component do - let(:champ) { create(:champ_titre_identite) } - let(:attachment) { champ.piece_justificative_file.attachments.first } - let(:component) { - described_class.new(poll_url: "poll-here", attachment:) - } + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :titre_identite }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } - subject { - render_inline(component).to_html - } + let(:attachment) { champ.piece_justificative_file.attachments.first } + + let(:component) { described_class.new(poll_url: "poll-here", attachment:) } + + subject { render_inline(component).to_html } context "when watermark is pending" do it "renders turbo poll attributes" do @@ -48,7 +49,8 @@ RSpec.describe Attachment::PendingPollComponent, type: :component do end context "when antivirus is in progress on pj" do - let(:champ) { create(:champ_piece_justificative) } + let(:types_de_champ_public) { [{ type: :piece_justificative }] } + before do attachment.blob.virus_scan_result = ActiveStorage::VirusScanner::PENDING end diff --git a/spec/components/attachment/show_component_spec.rb b/spec/components/attachment/show_component_spec.rb index adcf36ff3..e8d8acde4 100644 --- a/spec/components/attachment/show_component_spec.rb +++ b/spec/components/attachment/show_component_spec.rb @@ -1,16 +1,14 @@ RSpec.describe Attachment::ShowComponent, type: :component do - let(:champ) { create(:champ_piece_justificative) } - let(:virus_scan_result) { nil } - - let(:attachment) { - champ.piece_justificative_file.attachments.first - } + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :piece_justificative }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } + let(:attachment) { champ.piece_justificative_file.attachments.first } let(:filename) { attachment.filename.to_s } - let(:component) do - described_class.new(attachment:) - end + let(:virus_scan_result) { nil } + let(:component) { described_class.new(attachment:) } subject { render_inline(component).to_html } diff --git a/spec/components/editable_champ/datetime_component/datetime_component_spec.rb b/spec/components/editable_champ/datetime_component/datetime_component_spec.rb index 9080c9e25..c5197fa62 100644 --- a/spec/components/editable_champ/datetime_component/datetime_component_spec.rb +++ b/spec/components/editable_champ/datetime_component/datetime_component_spec.rb @@ -1,25 +1,29 @@ describe EditableChamp::DatetimeComponent, type: :component do + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :datetime, stable_id: 99 }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:component) { described_class.new(form: instance_double(ActionView::Helpers::FormBuilder, object_name: "dossier[champs_public_attributes]"), champ:) } describe '#formatted_value_for_datetime_locale' do + # before { champ.validate(:prefill) } subject { component.formatted_value_for_datetime_locale } context 'when the value is nil' do - let(:champ) { create(:champ_datetime, dossier: create(:dossier), value: nil) } + let(:champ) { Champs::DatetimeChamp.new(value: nil, dossier:, stable_id: 99) } it { is_expected.to be_nil } end context 'when the value is not a valid datetime' do - let(:champ) { create(:champ_datetime, dossier: create(:dossier), value: 'invalid') } + let(:champ) { Champs::DatetimeChamp.new(value: 'invalid', dossier:, stable_id: 99) } it { is_expected.to be_nil } end context 'when the value is a valid datetime' do - let(:champ) { create(:champ_datetime, dossier: create(:dossier), value: '2020-01-01T00:00:00+01:00') } + let(:champ) { Champs::DatetimeChamp.new(value: '2020-01-01T00:00:00+01:00', dossier:, stable_id: 99) } it { is_expected.to eq('2020-01-01T00:00') } end diff --git a/spec/components/editable_champ/editable_champ_component_spec.rb b/spec/components/editable_champ/editable_champ_component_spec.rb index 5aa862ba6..3ceefbe9e 100644 --- a/spec/components/editable_champ/editable_champ_component_spec.rb +++ b/spec/components/editable_champ/editable_champ_component_spec.rb @@ -1,71 +1,60 @@ describe EditableChamp::EditableChampComponent, type: :component do - let(:component) { described_class.new(form: nil, champ: champ) } + let(:procedure) { create(:procedure, types_de_champ_public:, types_de_champ_private:) } + let(:types_de_champ_public) { [] } + let(:types_de_champ_private) { [] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } + + let(:component) { described_class.new(form: nil, champ:) } describe "editable_champ_controller" do - let(:dossier) { create(:dossier) } - let(:champ) { create(:champ, dossier: dossier) } let(:controllers) { [] } let(:data) { controllers.join(' ') } subject { component.send(:stimulus_controller) } - context 'when an editable champ' do + context 'when an editable public champ' do let(:controllers) { ['autosave'] } + let(:types_de_champ_public) { [{ type: :text }] } it { expect(subject).to eq(data) } end context 'when a repetition champ' do - let(:champ) { create(:champ_repetition, dossier: dossier) } + let(:types_de_champ_public) { [{ type: :repetition, children: [{ type: :text }] }] } it { expect(subject).to eq(nil) } end context 'when a carte champ' do - let(:champ) { create(:champ_carte, dossier: dossier) } + let(:types_de_champ_public) { [{ type: :carte }] } it { expect(subject).to eq(nil) } end context 'when a private champ' do - let(:champ) { create(:champ, dossier: dossier, private: true) } + let(:types_de_champ_private) { [{ type: :text }] } it { expect(subject).to eq('autosave') } end context 'when a dossier is en_construction' do let(:controllers) { ['autosave'] } - let(:dossier) { create(:dossier, :en_construction) } - - it { expect(subject).to eq(data) } + let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) } context 'when a public dropdown champ' do let(:controllers) { ['autosave'] } - let(:champ) { create(:champ_drop_down_list, dossier: dossier) } + let(:types_de_champ_public) { [{ type: :drop_down_list }] } it { expect(subject).to eq(data) } end context 'when a private dropdown champ' do let(:controllers) { ['autosave'] } - let(:champ) { create(:champ_drop_down_list, dossier: dossier, private: true) } + let(:types_de_champ_private) { [{ type: :drop_down_list }] } it { expect(subject).to eq(data) } end end - - context 'when a public dropdown champ' do - let(:controllers) { ['autosave'] } - let(:champ) { create(:champ_drop_down_list, dossier: dossier) } - - it { expect(subject).to eq(data) } - end - - context 'when a private dropdown champ' do - let(:controllers) { ['autosave'] } - let(:champ) { create(:champ_drop_down_list, dossier: dossier, private: true) } - - it { expect(subject).to eq(data) } - end end end diff --git a/spec/components/editable_champ/explication_component/explication_component_spec.rb b/spec/components/editable_champ/explication_component/explication_component_spec.rb index 023f54c26..77a560c5f 100644 --- a/spec/components/editable_champ/explication_component/explication_component_spec.rb +++ b/spec/components/editable_champ/explication_component/explication_component_spec.rb @@ -1,22 +1,24 @@ describe EditableChamp::ExplicationComponent, type: :component do + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } + let(:component) { described_class.new(form: instance_double(ActionView::Helpers::FormBuilder, object_name: "dossier[champs_public_attributes]"), champ:) } - let(:champ) { create(:champ_explication) } - describe 'no description' do + let(:types_de_champ_public) { [{ type: :explication }] } + subject { render_inline(component).to_html } it { is_expected.not_to have_button("Lire plus") } end describe 'collapsed text is collapsed' do - subject { render_inline(component).to_html } + let(:types_de_champ_public) { [{ type: :explication, collapsible_explanation_enabled: "1", collapsible_explanation_text: "hide me" }] } - before do - champ.type_de_champ.update!(collapsible_explanation_enabled: "1", collapsible_explanation_text: "hide me") - end + subject { render_inline(component).to_html } it { is_expected.to have_button("Lire plus") } it { is_expected.to have_selector(".fr-collapse", text: "hide me") } diff --git a/spec/components/editable_champ/piece_justificative_component/piece_justificative_component_spec.rb b/spec/components/editable_champ/piece_justificative_component/piece_justificative_component_spec.rb index 38838fc2d..4cfee5357 100644 --- a/spec/components/editable_champ/piece_justificative_component/piece_justificative_component_spec.rb +++ b/spec/components/editable_champ/piece_justificative_component/piece_justificative_component_spec.rb @@ -1,5 +1,9 @@ describe EditableChamp::PieceJustificativeComponent, type: :component do - let(:champ) { create(:champ_piece_justificative, dossier: create(:dossier)) } + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :piece_justificative }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } + let(:component) { described_class.new(form: instance_double(ActionView::Helpers::FormBuilder, object_name: "dossier[champs_public_attributes]"), champ:) } @@ -9,7 +13,6 @@ describe EditableChamp::PieceJustificativeComponent, type: :component do } context 'when there is a template' do - let(:template) { champ.type_de_champ.piece_justificative_template } let(:profil) { :user } before do diff --git a/spec/components/header_section_component_spec.rb b/spec/components/header_section_component_spec.rb index 5a3be5912..f520c182a 100644 --- a/spec/components/header_section_component_spec.rb +++ b/spec/components/header_section_component_spec.rb @@ -2,6 +2,7 @@ RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do include ActionView::Context include ActionView::Helpers::FormHelper include ActionView::Helpers::FormOptionsHelper + let(:procedure) { create(:procedure, types_de_champ_public:) } let(:component) do cmp = nil @@ -14,8 +15,8 @@ RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do describe 'header_section_options_for_select' do context 'without upper tdc' do - let(:tdc) { header.type_de_champ } - let(:header) { build(:champ_header_section) } + let(:types_de_champ_public) { [{ type: :header_section, level: 1 }] } + let(:tdc) { procedure.draft_revision.types_de_champ_public.first } let(:upper_tdcs) { [] } it 'allows up to level 1 header section' do @@ -24,9 +25,14 @@ RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do end context 'with upper tdc of level 1' do - let(:tdc) { header.type_de_champ } - let(:header) { build(:champ_header_section_level_1) } - let(:upper_tdcs) { [build(:champ_header_section_level_1).type_de_champ] } + let(:types_de_champ_public) do + [ + { type: :header_section, level: 1 }, + { type: :header_section, level: 2 } + ] + end + let(:tdc) { procedure.draft_revision.types_de_champ_public.last } + let(:upper_tdcs) { [procedure.draft_revision.types_de_champ_public.first] } it 'allows up to level 2 header section' do expect(subject).to have_selector("option", count: 2) @@ -34,34 +40,24 @@ RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do end context 'with upper tdc of level 2' do - let(:tdc) { header.type_de_champ } - let(:header) { build(:champ_header_section_level_1) } - let(:upper_tdcs) { [build(:champ_header_section_level_1), build(:champ_header_section_level_2)].map(&:type_de_champ) } + let(:types_de_champ_public) do + [ + { type: :header_section, level: 1 }, + { type: :header_section, level: 2 }, + { type: :header_section, level: 3 } + ] + end + let(:tdc) { procedure.draft_revision.types_de_champ_public.third } + let(:upper_tdcs) { [procedure.draft_revision.types_de_champ_public.first, procedure.draft_revision.types_de_champ_public.second] } it 'allows up to level 3 header section' do expect(subject).to have_selector("option", count: 3) end end - context 'with upper tdc of level 3' do - let(:tdc) { header.type_de_champ } - let(:header) { build(:champ_header_section_level_1) } - let(:upper_tdcs) do - [ - build(:champ_header_section_level_1), - build(:champ_header_section_level_2), - build(:champ_header_section_level_3) - ].map(&:type_de_champ) - end - - it 'reaches limit of at most 3 section level' do - expect(subject).to have_selector("option", count: 3) - end - end - context 'with error' do - let(:tdc) { header.type_de_champ } - let(:header) { build(:champ_header_section_level_2) } + let(:types_de_champ_public) { [{ type: :header_section, level: 2 }] } + let(:tdc) { procedure.draft_revision.types_de_champ_public.first } let(:upper_tdcs) { [] } it 'includes disabled levels' do @@ -72,8 +68,8 @@ RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do end describe 'errors' do - let(:tdc) { header.type_de_champ } - let(:header) { build(:champ_header_section_level_2) } + let(:types_de_champ_public) { [{ type: :header_section, level: 2 }] } + let(:tdc) { procedure.draft_revision.types_de_champ_public.first } let(:upper_tdcs) { [] } it 'returns errors' do diff --git a/spec/controllers/api/public/v1/dossiers_controller_spec.rb b/spec/controllers/api/public/v1/dossiers_controller_spec.rb index c0c3d19e0..e12eeddd1 100644 --- a/spec/controllers/api/public/v1/dossiers_controller_spec.rb +++ b/spec/controllers/api/public/v1/dossiers_controller_spec.rb @@ -208,6 +208,6 @@ RSpec.describe API::Public::V1::DossiersController, type: :controller do private def find_champ_by_stable_id(dossier, stable_id) - dossier.champs.joins(:type_de_champ).find_by(types_de_champ: { stable_id: stable_id }) + dossier.champs.find_by(stable_id:) end end diff --git a/spec/controllers/api/v2/graphql_controller_spec.rb b/spec/controllers/api/v2/graphql_controller_spec.rb index 0d6f109fa..f54c63190 100644 --- a/spec/controllers/api/v2/graphql_controller_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_spec.rb @@ -3,10 +3,11 @@ describe API::V2::GraphqlController do let(:generated_token) { APIToken.generate(admin) } let(:api_token) { generated_token.first } let(:token) { generated_token.second } - let(:procedure) { create(:procedure, :published, :for_individual, :with_service, administrateurs: [admin]) } - let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) } - let(:dossier1) { create(:dossier, :en_construction, :with_individual, procedure: procedure, en_construction_at: 1.day.ago) } - let(:dossier2) { create(:dossier, :en_construction, :with_individual, :archived, procedure: procedure, en_construction_at: 3.days.ago) } + let(:types_de_champ_public) { [] } + let(:procedure) { create(:procedure, :published, :for_individual, :with_service, administrateurs: [admin], types_de_champ_public:) } + let(:dossier) { create(:dossier, :en_construction, :with_individual, :with_populated_champs, procedure:) } + let(:dossier1) { create(:dossier, :en_construction, :with_individual, procedure:, en_construction_at: 1.day.ago) } + let(:dossier2) { create(:dossier, :en_construction, :with_individual, :archived, procedure:, en_construction_at: 3.days.ago) } let(:dossiers) { [dossier] } let(:instructeur) { create(:instructeur, followed_dossiers: dossiers) } @@ -806,7 +807,8 @@ describe API::V2::GraphqlController do end describe "champ piece_justificative" do - let(:champ) { create(:champ_piece_justificative, dossier: dossier) } + let(:types_de_champ_public) { [{ type: :piece_justificative }] } + let(:champ) { dossier.champs.first } let(:byte_size) { 2712286911 } context "with deprecated file field" do diff --git a/spec/controllers/attachments_controller_spec.rb b/spec/controllers/attachments_controller_spec.rb index b005efbf5..a363e4ac9 100644 --- a/spec/controllers/attachments_controller_spec.rb +++ b/spec/controllers/attachments_controller_spec.rb @@ -1,8 +1,9 @@ describe AttachmentsController, type: :controller do let(:user) { create(:user) } let(:attachment) { champ.piece_justificative_file.attachments.first } - let(:dossier) { create(:dossier, user: user) } - let(:champ) { create(:champ_piece_justificative, dossier_id: dossier.id) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) } + let(:dossier) { create(:dossier, :with_populated_champs, user:, procedure:) } + let(:champ) { dossier.champs.first } let(:signed_id) { attachment.blob.signed_id } describe '#show' do @@ -46,8 +47,6 @@ describe AttachmentsController, type: :controller do render_views let(:attachment) { champ.piece_justificative_file.attachments.first } - let(:dossier) { create(:dossier, user: user) } - let(:champ) { create(:champ_piece_justificative, dossier_id: dossier.id) } let(:signed_id) { attachment.blob.signed_id } subject do diff --git a/spec/controllers/experts/avis_controller_spec.rb b/spec/controllers/experts/avis_controller_spec.rb index 5f030bb41..77a60c471 100644 --- a/spec/controllers/experts/avis_controller_spec.rb +++ b/spec/controllers/experts/avis_controller_spec.rb @@ -8,7 +8,8 @@ describe Experts::AvisController, type: :controller do let(:another_instructeur) { create(:instructeur) } let(:claimant) { create(:expert) } let(:expert) { create(:expert) } - let(:procedure) { create(:procedure, :published, instructeurs: [instructeur, another_instructeur, instructeur_with_instant_avis_notification]) } + let(:types_de_champ_public) { [] } + let(:procedure) { create(:procedure, :published, instructeurs: [instructeur, another_instructeur, instructeur_with_instant_avis_notification], types_de_champ_public:) } let(:procedure_id) { procedure.id } let(:another_procedure) { create(:procedure, :published, instructeurs: [instructeur]) } let(:dossier) { create(:dossier, :en_construction, procedure:) } @@ -464,7 +465,8 @@ describe Experts::AvisController, type: :controller do end context 'with linked dossiers' do - let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) } + let(:types_de_champ_public) { [{ type: :dossier_link }] } + let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) } context 'when the expert doesn’t share linked dossiers' do let(:invite_linked_dossiers) { false } diff --git a/spec/controllers/instructeurs/dossiers_controller_spec.rb b/spec/controllers/instructeurs/dossiers_controller_spec.rb index 198c75a13..9445a00db 100644 --- a/spec/controllers/instructeurs/dossiers_controller_spec.rb +++ b/spec/controllers/instructeurs/dossiers_controller_spec.rb @@ -4,7 +4,8 @@ describe Instructeurs::DossiersController, type: :controller do let(:instructeur) { create(:instructeur) } let(:administration) { create(:administration) } let(:instructeurs) { [instructeur] } - let(:procedure) { create(:procedure, :published, :for_individual, instructeurs: instructeurs) } + let(:types_de_champ_public) { [] } + let(:procedure) { create(:procedure, :published, :for_individual, instructeurs: instructeurs, types_de_champ_public:) } let(:procedure_accuse_lecture) { create(:procedure, :published, :for_individual, :accuse_lecture, :new_administrateur, instructeurs: instructeurs) } let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) } let(:dossier_accuse_lecture) { create(:dossier, :en_construction, :with_individual, procedure: procedure_accuse_lecture) } @@ -854,7 +855,8 @@ describe Instructeurs::DossiersController, type: :controller do context 'with linked dossiers' do let(:asked_confidentiel) { false } let(:previous_avis_confidentiel) { false } - let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) } + let(:types_de_champ_public) { [{ type: :dossier_link }] } + let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) } before { subject } context 'when the expert doesn’t share linked dossiers' do let(:invite_linked_dossiers) { false } @@ -873,7 +875,7 @@ describe Instructeurs::DossiersController, type: :controller do context 'and the expert can access the linked dossiers' do let(:saved_avis) { Avis.last(2).first } let(:linked_avis) { Avis.last } - let(:linked_dossier) { Dossier.find_by(id: dossier.reload.champs_public.filter(&:dossier_link?).filter_map(&:value)) } + let(:linked_dossier) { Dossier.find_by(id: dossier.champs.first.value) } let(:invite_linked_dossiers) do instructeur.assign_to_procedure(linked_dossier.procedure) true diff --git a/spec/controllers/users/commencer_controller_spec.rb b/spec/controllers/users/commencer_controller_spec.rb index 77801e36c..c5e42c0d7 100644 --- a/spec/controllers/users/commencer_controller_spec.rb +++ b/spec/controllers/users/commencer_controller_spec.rb @@ -159,7 +159,7 @@ describe Users::CommencerController, type: :controller do expect(Dossier.count).to eq(1) expect(session[:prefill_token]).to eq(Dossier.last.prefill_token) expect(session[:prefill_params_digest]).to eq(PrefillChamps.digest({ "champ_#{type_de_champ_text.to_typed_id}" => "blabla" })) - expect(Dossier.last.champs.where(type_de_champ: type_de_champ_text).first.value).to eq("blabla") + expect(Dossier.last.champs.where(stable_id: type_de_champ_text.stable_id).first.value).to eq("blabla") expect(Dossier.last.individual.nom).to eq("Dupont") end end @@ -190,8 +190,8 @@ describe Users::CommencerController, type: :controller do subject { get :commencer, params: { path: path, prefill_token: "token", "champ_#{type_de_champ_text.to_typed_id}" => "blabla" } } context "when the associated dossier exists" do - let!(:dossier) { create(:dossier, :prefilled, prefill_token: "token") } - let!(:champ_text) { create(:champ_text, dossier: dossier, type_de_champ: type_de_champ_text) } + let(:procedure) { create(:procedure, types_de_champ_public: [{}]) } + let!(:dossier) { create(:dossier, :prefilled, procedure:, prefill_token: "token") } it "does not create a new dossier" do subject diff --git a/spec/factories/champ.rb b/spec/factories/champ.rb index 6660c730b..6bb952dfb 100644 --- a/spec/factories/champ.rb +++ b/spec/factories/champ.rb @@ -1,174 +1,110 @@ FactoryBot.define do - factory :champ do + factory :champ_do_not_use, class: 'Champ' do stream { 'main' } add_attribute(:private) { false } - dossier { association :dossier } - type_de_champ { association :type_de_champ, procedure: dossier.procedure } - - after(:build) do |champ, _evaluator| - champ.stable_id = champ.type_de_champ.stable_id - end - - trait :private do - add_attribute(:private) { true } - end - - trait :with_piece_justificative_file do - after(:build) do |champ, _evaluator| - champ.piece_justificative_file.attach( - io: StringIO.new("toto"), - filename: "toto.txt", - content_type: "text/plain", - # we don't want to run virus scanner on this file - metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE } - ) - end - end - - factory :champ_text, class: 'Champs::TextChamp' do - type_de_champ { association :type_de_champ_text, procedure: dossier.procedure } + factory :champ_do_not_use_text, class: 'Champs::TextChamp' do value { 'text' } end - factory :champ_textarea, class: 'Champs::TextareaChamp' do - type_de_champ { association :type_de_champ_textarea, procedure: dossier.procedure } + factory :champ_do_not_use_textarea, class: 'Champs::TextareaChamp' do value { 'textarea' } end - factory :champ_date, class: 'Champs::DateChamp' do - type_de_champ { association :type_de_champ_date, procedure: dossier.procedure } + factory :champ_do_not_use_date, class: 'Champs::DateChamp' do value { '2019-07-10' } end - factory :champ_datetime, class: 'Champs::DatetimeChamp' do - type_de_champ { association :type_de_champ_datetime, procedure: dossier.procedure } + factory :champ_do_not_use_datetime, class: 'Champs::DatetimeChamp' do value { '15/09/1962 15:35' } end - factory :champ_number, class: 'Champs::NumberChamp' do - type_de_champ { association :type_de_champ_number, procedure: dossier.procedure } + factory :champ_do_not_use_number, class: 'Champs::NumberChamp' do value { '42' } end - factory :champ_decimal_number, class: 'Champs::DecimalNumberChamp' do - type_de_champ { association :type_de_champ_decimal_number, procedure: dossier.procedure } + factory :champ_do_not_use_decimal_number, class: 'Champs::DecimalNumberChamp' do value { '42.1' } end - factory :champ_integer_number, class: 'Champs::IntegerNumberChamp' do - type_de_champ { association :type_de_champ_integer_number, procedure: dossier.procedure } + factory :champ_do_not_use_integer_number, class: 'Champs::IntegerNumberChamp' do value { '42' } end - factory :champ_checkbox, class: 'Champs::CheckboxChamp' do - type_de_champ { association :type_de_champ_checkbox, procedure: dossier.procedure } + factory :champ_do_not_use_checkbox, class: 'Champs::CheckboxChamp' do value { 'true' } end - factory :champ_civilite, class: 'Champs::CiviliteChamp' do - type_de_champ { association :type_de_champ_civilite, procedure: dossier.procedure } + factory :champ_do_not_use_civilite, class: 'Champs::CiviliteChamp' do value { 'M.' } end - factory :champ_email, class: 'Champs::EmailChamp' do - type_de_champ { association :type_de_champ_email, procedure: dossier.procedure } + factory :champ_do_not_use_email, class: 'Champs::EmailChamp' do value { 'yoda@beta.gouv.fr' } end - factory :champ_phone, class: 'Champs::PhoneChamp' do - type_de_champ { association :type_de_champ_phone, procedure: dossier.procedure } + factory :champ_do_not_use_phone, class: 'Champs::PhoneChamp' do value { '0666666666' } end - factory :champ_address, class: 'Champs::AddressChamp' do - type_de_champ { association :type_de_champ_address, procedure: dossier.procedure } + factory :champ_do_not_use_address, class: 'Champs::AddressChamp' do value { '2 rue des Démarches' } end - factory :champ_yes_no, class: 'Champs::YesNoChamp' do - type_de_champ { association :type_de_champ_yes_no, procedure: dossier.procedure } + factory :champ_do_not_use_yes_no, class: 'Champs::YesNoChamp' do value { 'true' } end - factory :champ_drop_down_list, class: 'Champs::DropDownListChamp' do + factory :champ_do_not_use_drop_down_list, class: 'Champs::DropDownListChamp' do transient do other { false } end - - type_de_champ { association :type_de_champ_drop_down_list, procedure: dossier.procedure, drop_down_other: other } value { 'val1' } end - factory :champ_multiple_drop_down_list, class: 'Champs::MultipleDropDownListChamp' do - type_de_champ { association :type_de_champ_multiple_drop_down_list, procedure: dossier.procedure } + factory :champ_do_not_use_multiple_drop_down_list, class: 'Champs::MultipleDropDownListChamp' do value { '["val1", "val2"]' } end - factory :champ_linked_drop_down_list, class: 'Champs::LinkedDropDownListChamp' do - type_de_champ { association :type_de_champ_linked_drop_down_list, procedure: dossier.procedure } + factory :champ_do_not_use_linked_drop_down_list, class: 'Champs::LinkedDropDownListChamp' do value { '["categorie 1", "choix 1"]' } end - factory :champ_pays, class: 'Champs::PaysChamp' do - type_de_champ { association :type_de_champ_pays, procedure: dossier.procedure } + factory :champ_do_not_use_pays, class: 'Champs::PaysChamp' do value { 'France' } end - factory :champ_regions, class: 'Champs::RegionChamp' do - type_de_champ { association :type_de_champ_regions, procedure: dossier.procedure } + factory :champ_do_not_use_regions, class: 'Champs::RegionChamp' do value { 'Guadeloupe' } end - factory :champ_departements, class: 'Champs::DepartementChamp' do - type_de_champ { association :type_de_champ_departements, procedure: dossier.procedure } + factory :champ_do_not_use_departements, class: 'Champs::DepartementChamp' do value { '01' } end - factory :champ_communes, class: 'Champs::CommuneChamp' do - type_de_champ { association :type_de_champ_communes, procedure: dossier.procedure } + factory :champ_do_not_use_communes, class: 'Champs::CommuneChamp' do external_id { '60172' } code_postal { '60580' } end - factory :champ_epci, class: 'Champs::EpciChamp' do - type_de_champ { association :type_de_champ_epci, procedure: dossier.procedure } + factory :champ_do_not_use_epci, class: 'Champs::EpciChamp' do value { 'CC Retz en Valois' } external_id { '200071991' } end - factory :champ_header_section, class: 'Champs::HeaderSectionChamp' do - type_de_champ { association :type_de_champ_header_section, procedure: dossier.procedure } - value { 'une section' } - end - factory :champ_header_section_level_1, class: 'Champs::HeaderSectionChamp' do - type_de_champ { association :type_de_champ_header_section_level_1, procedure: dossier.procedure } - value { 'une section' } - end - factory :champ_header_section_level_2, class: 'Champs::HeaderSectionChamp' do - type_de_champ { association :type_de_champ_header_section_level_2, procedure: dossier.procedure } - value { 'une section' } - end - factory :champ_header_section_level_3, class: 'Champs::HeaderSectionChamp' do - type_de_champ { association :type_de_champ_header_section_level_3, procedure: dossier.procedure } + factory :champ_do_not_use_header_section, class: 'Champs::HeaderSectionChamp' do value { 'une section' } end - factory :champ_explication, class: 'Champs::ExplicationChamp' do - type_de_champ { association :type_de_champ_explication, procedure: dossier.procedure } + factory :champ_do_not_use_explication, class: 'Champs::ExplicationChamp' do value { '' } end - factory :champ_dossier_link, class: 'Champs::DossierLinkChamp' do - type_de_champ { association :type_de_champ_dossier_link, procedure: dossier.procedure } - value { create(:dossier).id } + factory :champ_do_not_use_dossier_link, class: 'Champs::DossierLinkChamp' do + value { create(:dossier, :en_construction).id } end - factory :champ_without_piece_justificative, class: 'Champs::PieceJustificativeChamp' do - type_de_champ { association :type_de_champ_piece_justificative, procedure: dossier.procedure } - end - factory :champ_piece_justificative, class: 'Champs::PieceJustificativeChamp' do - type_de_champ { association :type_de_champ_piece_justificative, procedure: dossier.procedure } + factory :champ_do_not_use_piece_justificative, class: 'Champs::PieceJustificativeChamp' do transient do size { 4 } end @@ -184,8 +120,7 @@ FactoryBot.define do end end - factory :champ_titre_identite, class: 'Champs::TitreIdentiteChamp' do - type_de_champ { association :type_de_champ_titre_identite, procedure: dossier.procedure } + factory :champ_do_not_use_titre_identite, class: 'Champs::TitreIdentiteChamp' do transient do skip_default_attachment { false } end @@ -203,109 +138,67 @@ FactoryBot.define do end end - factory :champ_carte, class: 'Champs::CarteChamp' do - type_de_champ { association :type_de_champ_carte, procedure: dossier.procedure } + factory :champ_do_not_use_carte, class: 'Champs::CarteChamp' do + geo_areas { build_list(:geo_area, 2) } end - factory :champ_iban, class: 'Champs::IbanChamp' do - type_de_champ { association :type_de_champ_iban, procedure: dossier.procedure } + factory :champ_do_not_use_iban, class: 'Champs::IbanChamp' do end - factory :champ_annuaire_education, class: 'Champs::AnnuaireEducationChamp' do - type_de_champ { association :type_de_champ_annuaire_education, procedure: dossier.procedure } + factory :champ_do_not_use_annuaire_education, class: 'Champs::AnnuaireEducationChamp' do end - factory :champ_cnaf, class: 'Champs::CnafChamp' do - type_de_champ { association :type_de_champ_cnaf, procedure: dossier.procedure } + factory :champ_do_not_use_cnaf, class: 'Champs::CnafChamp' do end - factory :champ_dgfip, class: 'Champs::DgfipChamp' do - type_de_champ { association :type_de_champ_dgfip, procedure: dossier.procedure } + factory :champ_do_not_use_dgfip, class: 'Champs::DgfipChamp' do end - factory :champ_pole_emploi, class: 'Champs::PoleEmploiChamp' do - type_de_champ { association :type_de_champ_pole_emploi, procedure: dossier.procedure } + factory :champ_do_not_use_pole_emploi, class: 'Champs::PoleEmploiChamp' do end - factory :champ_mesri, class: 'Champs::MesriChamp' do - type_de_champ { association :type_de_champ_mesri, procedure: dossier.procedure } + factory :champ_do_not_use_mesri, class: 'Champs::MesriChamp' do end - factory :champ_siret, class: 'Champs::SiretChamp' do - type_de_champ { association :type_de_champ_siret, procedure: dossier.procedure } + factory :champ_do_not_use_siret, class: 'Champs::SiretChamp' do association :etablissement, factory: [:etablissement] value { '44011762001530' } end - factory :champ_rna, class: 'Champs::RNAChamp' do - type_de_champ { association :type_de_champ_rna, procedure: dossier.procedure } - association :etablissement, factory: [:etablissement] + factory :champ_do_not_use_rna, class: 'Champs::RNAChamp' do value { 'W173847273' } end - factory :champ_engagement_juridique, class: 'Champs::EngagementJuridiqueChamp' do - type_de_champ { association :type_de_champ_engagement_juridique, procedure: dossier.procedure } + factory :champ_do_not_use_engagement_juridique, class: 'Champs::EngagementJuridiqueChamp' do end - factory :champ_cojo, class: 'Champs::COJOChamp' do - type_de_champ { association :type_de_champ_cojo, procedure: dossier.procedure } + factory :champ_do_not_use_cojo, class: 'Champs::COJOChamp' do end - factory :champ_rnf, class: 'Champs::RNFChamp' do - type_de_champ { association :type_de_champ_rnf, procedure: dossier.procedure } + factory :champ_do_not_use_rnf, class: 'Champs::RNFChamp' do end - factory :champ_expression_reguliere, class: 'Champs::ExpressionReguliereChamp' do - type_de_champ { association :type_de_champ_expression_reguliere, procedure: dossier.procedure } + factory :champ_do_not_use_expression_reguliere, class: 'Champs::ExpressionReguliereChamp' do end - factory :champ_repetition, class: 'Champs::RepetitionChamp' do - type_de_champ { association :type_de_champ_repetition, procedure: dossier.procedure } - + factory :champ_do_not_use_repetition, class: 'Champs::RepetitionChamp' do transient do rows { 2 } end after(:build) do |champ_repetition, evaluator| - revision = champ_repetition.type_de_champ.procedure&.active_revision || build(:procedure_revision) - parent = revision.revision_types_de_champ.find { |rtdc| rtdc.type_de_champ == champ_repetition.type_de_champ } - types_de_champ = revision.revision_types_de_champ.filter { |rtdc| rtdc.parent == parent }.map(&:type_de_champ) + 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| - build(:"champ_#{type_de_champ.type_champ}", dossier: champ_repetition.dossier, row_id:, type_de_champ: type_de_champ, parent: champ_repetition, private: champ_repetition.private?) + 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) end end end - - trait :without_champs do - after(:build) do |champ_repetition, _evaluator| - champ_repetition.champs = [] - end - end - end - - factory :champ_repetition_with_piece_jointe, class: 'Champs::RepetitionChamp' do - type_de_champ { association :type_de_champ_repetition, procedure: dossier.procedure } - - after(:build) do |champ_repetition, _evaluator| - type_de_champ_pj0 = build(:type_de_champ_piece_justificative, - position: 0, - parent: champ_repetition.type_de_champ, - libelle: 'Justificatif de domicile') - type_de_champ_pj1 = build(:type_de_champ_piece_justificative, - position: 1, - parent: champ_repetition.type_de_champ, - libelle: 'Carte d\'identité') - - champ_repetition.champs << [ - build(:champ_piece_justificative, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_pj0), - build(:champ_piece_justificative, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_pj1), - build(:champ_piece_justificative, dossier: champ_repetition.dossier, row: 1, type_de_champ: type_de_champ_pj0), - build(:champ_piece_justificative, dossier: champ_repetition.dossier, row: 1, type_de_champ: type_de_champ_pj1) - ] - end end end end diff --git a/spec/factories/dossier.rb b/spec/factories/dossier.rb index 1ce2ebbf0..1b96ea81a 100644 --- a/spec/factories/dossier.rb +++ b/spec/factories/dossier.rb @@ -119,37 +119,6 @@ FactoryBot.define do hidden_by_reason { DeletedDossier.reasons.fetch(:instructeur_request) } end - trait :with_dossier_link do - after(:create) do |dossier, _evaluator| - # create linked dossier - linked_dossier = create(:dossier, :en_construction) - - # find first type de champ dossier_link - type_de_champ = dossier.types_de_champ.find do |t| - t.type_champ == TypeDeChamp.type_champs.fetch(:dossier_link) - end - - # if type de champ does not exist create it - if !type_de_champ - type_de_champ = create(:type_de_champ_dossier_link, procedure: dossier.procedure) - end - - # find champ with the type de champ - champ = dossier.reload.champs_public.find do |c| - c.type_de_champ == type_de_champ - end - - # if champ does not exist create it - if !champ - champ = create(:champ_dossier_link, dossier: dossier, type_de_champ: type_de_champ) - end - - # set champ value with linked dossier - champ.value = linked_dossier.id - champ.save! - end - end - trait :with_commentaires do commentaires { [build(:commentaire), build(:commentaire)] } end @@ -285,13 +254,13 @@ FactoryBot.define do after(:create) do |dossier, _evaluator| dossier.champs_to_destroy.where(private: false).destroy_all dossier.types_de_champ.each do |type_de_champ| - if type_de_champ.simple_drop_down_list? - create(:"champ_#{type_de_champ.type_champ}", dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first) + 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? - create(:"champ_#{type_de_champ.type_champ}", dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json) - else - create(:"champ_#{type_de_champ.type_champ}", dossier:, type_de_champ:) + 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 @@ -301,13 +270,13 @@ FactoryBot.define 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| - if type_de_champ.simple_drop_down_list? - create(:"champ_#{type_de_champ.type_champ}", private: true, dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first) + 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? - create(:"champ_#{type_de_champ.type_champ}", private: true, dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json) - else - create(:"champ_#{type_de_champ.type_champ}", private: true, dossier:, type_de_champ:) + 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 diff --git a/spec/factories/geo_area.rb b/spec/factories/geo_area.rb index b521ba5ea..f86348b28 100644 --- a/spec/factories/geo_area.rb +++ b/spec/factories/geo_area.rb @@ -1,6 +1,5 @@ FactoryBot.define do factory :geo_area do - association :champ properties { {} } geometry { {} } diff --git a/spec/helpers/gallery_helper_spec.rb b/spec/helpers/gallery_helper_spec.rb index 22ddabd32..0582f5bf8 100644 --- a/spec/helpers/gallery_helper_spec.rb +++ b/spec/helpers/gallery_helper_spec.rb @@ -1,7 +1,9 @@ RSpec.describe GalleryHelper, type: :helper do - let(:procedure) { create(:procedure_with_dossiers) } - let(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile', procedure:) } - let(:champ_pj) { create(:champ_piece_justificative, type_de_champ: type_de_champ_pj) } + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile' }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ_pj) { dossier.champs.first } + let(:blob_info) do { filename: file.original_filename, diff --git a/spec/jobs/champ_fetch_external_data_job_spec.rb b/spec/jobs/champ_fetch_external_data_job_spec.rb index a4f75cc67..7d6867869 100644 --- a/spec/jobs/champ_fetch_external_data_job_spec.rb +++ b/spec/jobs/champ_fetch_external_data_job_spec.rb @@ -3,7 +3,11 @@ require 'rails_helper' RSpec.describe ChampFetchExternalDataJob, type: :job do - let(:champ) { build(:champ, external_id: champ_external_id, data:) } + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :communes }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } + let(:external_id) { "an ID" } let(:champ_external_id) { "an ID" } let(:data) { nil } @@ -15,6 +19,7 @@ RSpec.describe ChampFetchExternalDataJob, type: :job do include Dry::Monads[:result] before do + champ.update_columns(external_id: champ_external_id, data:) allow(champ).to receive(:fetch_external_data).and_return(fetched_data) allow(champ).to receive(:update_with_external_data!) allow(champ).to receive(:log_fetch_external_data_exception) diff --git a/spec/jobs/cron/backfill_siret_degraded_mode_job_spec.rb b/spec/jobs/cron/backfill_siret_degraded_mode_job_spec.rb index 74a9c4468..85a2f5802 100644 --- a/spec/jobs/cron/backfill_siret_degraded_mode_job_spec.rb +++ b/spec/jobs/cron/backfill_siret_degraded_mode_job_spec.rb @@ -15,9 +15,14 @@ RSpec.describe Cron::BackfillSiretDegradedModeJob, type: :job do end context 'fix etablisEtablissementAdapter.newsement with champs with adresse nil' do - let(:champ_siret) { create(:champ_siret, etablissement: etablissement) } + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :siret }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ_siret) { dossier.champs.first } + before do champ_siret + champ_siret.update_column(:etablissement_id, etablissement.id) end it 'works' do allow_any_instance_of(APIEntreprise::EtablissementAdapter).to receive(:to_params).and_return({ adresse: new_adresse }) diff --git a/spec/jobs/dossier_index_search_terms_job_spec.rb b/spec/jobs/dossier_index_search_terms_job_spec.rb index 9cb016ec9..e697e6921 100644 --- a/spec/jobs/dossier_index_search_terms_job_spec.rb +++ b/spec/jobs/dossier_index_search_terms_job_spec.rb @@ -1,11 +1,15 @@ RSpec.describe DossierIndexSearchTermsJob, type: :job do - let(:dossier) { create(:dossier) } + let(:procedure) { create(:procedure, :published, types_de_champ_public:, types_de_champ_private:) } + let(:types_de_champ_public) { [{ type: :text }] } + let(:types_de_champ_private) { [{ type: :text }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ_siret) { dossier.champs.first } subject(:perform_job) { described_class.perform_now(dossier.reload) } before do - create(:champ_text, dossier:, value: "un nouveau champ") - create(:champ_text, dossier:, value: "private champ", private: true) + dossier.champs_public.first.update_column(:value, "un nouveau champ") + dossier.champs_private.first.update_column(:value, "private champ") end it "update search terms columns" do diff --git a/spec/jobs/migrations/batch_update_datetime_values_job_spec.rb b/spec/jobs/migrations/batch_update_datetime_values_job_spec.rb index c800d97c6..05ad03752 100644 --- a/spec/jobs/migrations/batch_update_datetime_values_job_spec.rb +++ b/spec/jobs/migrations/batch_update_datetime_values_job_spec.rb @@ -1,11 +1,17 @@ describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :datetime, mandatory: }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:datetime_champ) { dossier.champs.first } + let(:mandatory) { true } + before do + datetime_champ.update_column(:value, value) datetime_champ.save(validate: false) end context "when the value is a valid ISO8601 date" do let!(:value) { Time.zone.parse('10/01/2023 13:30').iso8601 } - let!(:datetime_champ) { build(:champ_datetime, value: value) } subject { described_class.perform_now([datetime_champ.id]) } @@ -17,7 +23,6 @@ describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do context "when the value is a date convertible to IS8061" do let!(:value) { "2023-01-10" } - let!(:datetime_champ) { build(:champ_datetime, value: value) } subject { described_class.perform_now([datetime_champ.id]) } @@ -28,11 +33,8 @@ describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do end context "when the value is a date not convertible to IS8061" do - before do - datetime_champ.type_de_champ.update!(mandatory: false) - end - - let!(:datetime_champ) { build(:champ_datetime, value: "blabla") } + let!(:value) { "blabla" } + let!(:mandatory) { false } subject { described_class.perform_now([datetime_champ.id]) } @@ -43,7 +45,7 @@ describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do end context "when the value is a date not convertible to IS8061 and the champ is required" do - let!(:datetime_champ) { build(:champ_datetime, value: "blabla") } + let!(:value) { "blabla" } subject { described_class.perform_now([datetime_champ.id]) } @@ -57,7 +59,7 @@ describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do end context "when the value is nil" do - let!(:datetime_champ) { build(:champ_datetime, value: nil) } + let!(:value) { nil } subject { described_class.perform_now([datetime_champ.id]) } diff --git a/spec/jobs/migrations/batch_update_pays_values_job_spec.rb b/spec/jobs/migrations/batch_update_pays_values_job_spec.rb index 7132a532c..fae800bbf 100644 --- a/spec/jobs/migrations/batch_update_pays_values_job_spec.rb +++ b/spec/jobs/migrations/batch_update_pays_values_job_spec.rb @@ -1,8 +1,14 @@ describe Migrations::BatchUpdatePaysValuesJob, type: :job do + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :pays, mandatory: }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:pays_champ) { dossier.champs.first } + let(:mandatory) { true } + before { pays_champ.update_columns(attributes) } subject { described_class.perform_now([pays_champ.id]) } context "the value is correct" do - let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'France', external_id: 'FR') } } + let(:attributes) { { value: 'France', external_id: 'FR' } } it 'does not change it' do subject @@ -12,11 +18,8 @@ describe Migrations::BatchUpdatePaysValuesJob, type: :job do end context "the value is incorrect" do - before do - pays_champ.type_de_champ.update!(mandatory: false) - end - - let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'Incorrect') } } + let(:attributes) { { value: 'Incorrect' } } + let(:mandatory) { false } it 'updates value to nil' do subject @@ -26,7 +29,7 @@ describe Migrations::BatchUpdatePaysValuesJob, type: :job do end context "the value is easily cleanable" do - let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'Vietnam') } } + let(:attributes) { { value: 'Vietnam' } } it 'cleans the value' do subject @@ -36,7 +39,7 @@ describe Migrations::BatchUpdatePaysValuesJob, type: :job do end context "the value is hard to clean" do - let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'CHRISTMAS (ILE)') } } + let(:attributes) { { value: 'CHRISTMAS (ILE)' } } it 'cleans the value' do subject diff --git a/spec/jobs/migrations/normalize_communes_job_spec.rb b/spec/jobs/migrations/normalize_communes_job_spec.rb index 2ffab9388..edb6f1c89 100644 --- a/spec/jobs/migrations/normalize_communes_job_spec.rb +++ b/spec/jobs/migrations/normalize_communes_job_spec.rb @@ -1,6 +1,10 @@ describe Migrations::NormalizeCommunesJob, type: :job do context 'when value is "", external_id is "", and code_departement is "undefined"' do - let(:champ) { create(:champ_communes) } + let(:procedure) { create(:procedure, :published, types_de_champ_public:) } + let(:types_de_champ_public) { [{ type: :communes }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } + before { champ.update_columns(external_id: "", value: "", value_json: { code_departement: 'undefined', departement: 'undefined' }) } subject { described_class.perform_now([champ.id]) } it 'empty the champs' do diff --git a/spec/lib/recovery/align_champ_with_dossier_revision_spec.rb b/spec/lib/recovery/align_champ_with_dossier_revision_spec.rb deleted file mode 100644 index a708b2916..000000000 --- a/spec/lib/recovery/align_champ_with_dossier_revision_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -describe Recovery::AlignChampWithDossierRevision do - let(:procedure) { create(:procedure, types_de_champ_public: [{ stable_id: bad_stable_id }, {}]) } - let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } - let(:bad_dossier) { create(:dossier, :with_populated_champs, procedure:) } - let(:bad_stable_id) { 999 } - let(:bad_champ) { bad_dossier.champs.find { bad_stable_id == _1.stable_id } } - - context 'when type_de_champ exists in dossier revision' do - before do - procedure.publish! - procedure.draft_revision - .find_and_ensure_exclusive_use(bad_stable_id) - .update(libelle: "New libelle") - previous_revision = procedure.published_revision - previous_type_de_champ = previous_revision.types_de_champ.find { bad_stable_id == _1.stable_id } - - procedure.publish_revision! - procedure.reload - - bad_dossier - bad_champ.update(type_de_champ: previous_type_de_champ) - end - - it 'bad dossier shoud be bad' do - expect(procedure.revisions.size).to eq(3) - expect(bad_dossier.revision).to eq(procedure.published_revision) - expect(bad_dossier.champs.size).to eq(2) - expect(bad_dossier.champs_public.size).to eq(2) - expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error - - fixer = Recovery::AlignChampWithDossierRevision.new(Dossier) - fixer.run - - expect(fixer.logs.size).to eq(1) - expect(fixer.logs.first.fetch(:status)).to eq(:updated) - expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error - expect(bad_dossier.champs.size).to eq(2) - expect(bad_dossier.champs_public.size).to eq(2) - end - end - - context 'when type_de_champ does not exist in dossier revision' do - before do - procedure.publish! - bad_dossier - procedure.draft_revision.remove_type_de_champ(bad_stable_id) - procedure.publish_revision! - bad_dossier.update(revision: procedure.published_revision) - end - - it 'bad dossier shoud be bad' do - expect(procedure.revisions.size).to eq(3) - expect(bad_dossier.revision).to eq(procedure.published_revision) - expect(bad_dossier.champs.size).to eq(2) - expect(bad_dossier.champs_public.size).to eq(2) - expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error - - fixer = Recovery::AlignChampWithDossierRevision.new(Dossier) - fixer.run(destroy_extra_champs: true) - - expect(fixer.logs.size).to eq(1) - expect(fixer.logs.first.fetch(:status)).to eq(:not_found) - expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error - expect(bad_dossier.champs.size).to eq(1) - expect(bad_dossier.champs_public.size).to eq(1) - end - end -end diff --git a/spec/models/champ_private_spec.rb b/spec/models/champ_private_spec.rb index daa22b943..8262ee9c7 100644 --- a/spec/models/champ_private_spec.rb +++ b/spec/models/champ_private_spec.rb @@ -1,7 +1,7 @@ describe Champ do describe '#private?' do let(:type_de_champ) { build(:type_de_champ, :private) } - let(:champ) { type_de_champ.champ.build } + let(:champ) { type_de_champ.build_champ } it { expect(champ.private?).to be_truthy } it { expect(champ.public?).to be_falsey } diff --git a/spec/models/champ_shared_example.rb b/spec/models/champ_shared_example.rb deleted file mode 100644 index e53803228..000000000 --- a/spec/models/champ_shared_example.rb +++ /dev/null @@ -1,56 +0,0 @@ -shared_examples 'champ_spec' do - describe 'mandatory_blank?' do - let(:type_de_champ) { build(:type_de_champ, mandatory: mandatory) } - let(:champ) { build(:champ, type_de_champ: type_de_champ, value: value) } - let(:value) { '' } - let(:mandatory) { true } - - context 'when mandatory and blank' do - it { expect(champ.mandatory_blank?).to be(true) } - end - - context 'when carte mandatory and blank' do - let(:type_de_champ) { build(:type_de_champ_carte, mandatory: mandatory) } - let(:champ) { build(:champ_carte, type_de_champ: type_de_champ, value: value) } - let(:value) { nil } - it { expect(champ.mandatory_blank?).to be(true) } - end - - context 'when multiple_drop_down_list mandatory and blank' do - let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list, mandatory: mandatory) } - let(:champ) { build(:champ_multiple_drop_down_list, type_de_champ: type_de_champ, value: value) } - let(:value) { '[]' } - it { expect(champ.mandatory_blank?).to be(true) } - end - - context 'when repetition blank' do - let(:type_de_champ) { build(:type_de_champ_repetition) } - let(:champ) { build(:champ_repetition, type_de_champ: type_de_champ, rows: 0) } - - it { expect(champ.blank?).to be(true) } - end - - context 'when repetition not blank' do - let(:type_de_champ) { build(:type_de_champ_repetition, :with_types_de_champ, procedure: build(:procedure)) } - let(:champ) { build(:champ_repetition, type_de_champ: type_de_champ) } - - it { expect(champ.blank?).to be(false) } - end - - context 'when not blank' do - let(:value) { 'yop' } - it { expect(champ.mandatory_blank?).to be(false) } - end - - context 'when not mandatory' do - let(:mandatory) { false } - it { expect(champ.mandatory_blank?).to be(false) } - end - - context 'when not mandatory or blank' do - let(:value) { 'u' } - let(:mandatory) { false } - it { expect(champ.mandatory_blank?).to be(false) } - end - end -end diff --git a/spec/models/champ_spec.rb b/spec/models/champ_spec.rb index edde59295..fe457faff 100644 --- a/spec/models/champ_spec.rb +++ b/spec/models/champ_spec.rb @@ -1,9 +1,62 @@ describe Champ do include ActiveJob::TestHelper - require 'models/champ_shared_example.rb' + describe 'mandatory_blank?' do + let(:type_de_champ) { build(:type_de_champ, mandatory: mandatory) } + let(:champ) { Champ.new(value: value) } + let(:value) { '' } + let(:mandatory) { true } + before { allow(champ).to receive(:type_de_champ).and_return(type_de_champ) } - it_should_behave_like "champ_spec" + context 'when mandatory and blank' do + it { expect(champ.mandatory_blank?).to be(true) } + end + + context 'when carte mandatory and blank' do + let(:type_de_champ) { build(:type_de_champ_carte, mandatory: mandatory) } + let(:champ) { Champs::CarteChamp.new(value: value) } + let(:value) { nil } + it { expect(champ.mandatory_blank?).to be(true) } + end + + context 'when multiple_drop_down_list mandatory and blank' do + let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list, mandatory: mandatory) } + let(:champ) { Champs::MultipleDropDownListChamp.new(value: value) } + let(:value) { '[]' } + it { expect(champ.mandatory_blank?).to be(true) } + end + + context 'when repetition blank' do + let(:type_de_champ) { build(:type_de_champ_repetition) } + let(:champ) { Champs::RepetitionChamp.new } + + it { expect(champ.blank?).to be(true) } + end + + context 'when repetition not blank' do + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :repetition, children: [{ type: :text }] }]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.find(&:repetition?) } + + it { expect(champ.blank?).to be(false) } + end + + context 'when not blank' do + let(:value) { 'yop' } + it { expect(champ.mandatory_blank?).to be(false) } + end + + context 'when not mandatory' do + let(:mandatory) { false } + it { expect(champ.mandatory_blank?).to be(false) } + end + + context 'when not mandatory or blank' do + let(:value) { 'u' } + let(:mandatory) { false } + it { expect(champ.mandatory_blank?).to be(false) } + end + end describe "associations" do it { is_expected.to belong_to(:dossier) } @@ -18,14 +71,14 @@ describe Champ do describe "normalization" do it "should remove null bytes before save" do - champ = create(:champ, value: "foo\u0000bar") + champ = Champ.new(value: "foo\u0000bar") + champ.normalize expect(champ.value).to eq "foobar" end end describe '#public?' do - let(:type_de_champ) { build(:type_de_champ) } - let(:champ) { type_de_champ.champ.build } + let(:champ) { Champ.new } it { expect(champ.public?).to be_truthy } it { expect(champ.private?).to be_falsey } @@ -87,10 +140,8 @@ describe Champ do end describe '#format_datetime' do - let(:champ) { build(:champ_datetime, value: value) } - - before { champ.save! } - + let(:champ) { Champs::DatetimeChamp.new(value: value) } + before { champ.run_callbacks(:validation) } context 'when the value is sent by a modern browser' do let(:value) { '2017-12-31 10:23' } @@ -105,9 +156,8 @@ describe Champ do end describe '#multiple_select_to_string' do - let(:champ) { build(:champ_multiple_drop_down_list, value: value) } - - before { champ.save! } + let(:champ) { Champs::MultipleDropDownListChamp.new(value: value) } + # before { champ.save! } # when using the old form, and the ChampsService Class # TODO: to remove @@ -142,7 +192,8 @@ describe Champ do end describe 'for_export' do - let(:champ) { create(:champ_text, value: value) } + let(:champ) { Champs::TextChamp.new(value:, dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_text)) } context 'when type_de_champ is text' do let(:value) { '123' } @@ -151,14 +202,17 @@ describe Champ do end context 'when type_de_champ is textarea' do - let(:champ) { create(:champ_textarea, value: value) } + let(:champ) { Champs::TextareaChamp.new(value:, dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_textarea)) } + let(:value) { 'gras' } it { expect(champ.for_export).to eq('gras') } end context 'when type_de_champ is yes_no' do - let(:champ) { create(:champ_yes_no, value: value) } + let(:champ) { Champs::YesNoChamp.new(value: value) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_yes_no)) } context 'if yes' do let(:value) { 'true' } @@ -180,18 +234,21 @@ describe Champ do end context 'when type_de_champ is multiple_drop_down_list' do - let(:champ) { create(:champ_multiple_drop_down_list, value:) } + let(:champ) { Champs::MultipleDropDownListChamp.new(value:, dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_multiple_drop_down_list)) } + let(:value) { '["Crétinier", "Mousserie"]' } it { expect(champ.for_export).to eq('Crétinier, Mousserie') } end context 'when type_de_champ and champ.type mismatch' do - let(:champ_yes_no) { create(:champ_yes_no, value: 'true') } - let(:champ_text) { create(:champ_text, value: 'Hello') } + let(:value) { :noop } + let(:champ_yes_no) { Champs::YesNoChamp.new(value: 'true') } + let(:champ_text) { Champs::TextChamp.new(value: 'hello') } - it { expect(TypeDeChamp.champ_value_for_export(champ_text.type_champ, champ_yes_no)).to eq(nil) } - it { expect(TypeDeChamp.champ_value_for_export(champ_yes_no.type_champ, champ_text)).to eq('Non') } + it { expect(TypeDeChamp.champ_value_for_export('text', champ_yes_no)).to eq(nil) } + it { expect(TypeDeChamp.champ_value_for_export('yes_no', champ_text)).to eq('Non') } end end @@ -199,7 +256,7 @@ describe Champ do subject { champ.search_terms } context 'for adresse champ' do - let(:champ) { create(:champ_address, value:) } + let(:champ) { Champs::AddressChamp.new(value:) } let(:value) { "10 rue du Pinson qui Piaille" } it { is_expected.to eq([value]) } @@ -207,8 +264,8 @@ describe Champ do context 'for checkbox champ' do let(:libelle) { champ.libelle } - let(:champ) { create(:champ_checkbox, value:) } - + let(:champ) { Champs::CheckboxChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_checkbox)) } context 'when the box is checked' do let(:value) { 'true' } @@ -223,74 +280,79 @@ describe Champ do end context 'for civilite champ' do - let(:champ) { create(:champ_civilite, value:) } + let(:champ) { Champs::CiviliteChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_civilite)) } let(:value) { "M." } it { is_expected.to eq([value]) } end context 'for date champ' do - let(:champ) { create(:champ_date, value:) } + let(:champ) { Champs::DateChamp.new(value:) } let(:value) { "2018-07-30" } it { is_expected.to be_nil } end context 'for date time champ' do - let(:champ) { create(:champ_datetime, value:) } + let(:champ) { Champs::DatetimeChamp.new(value:) } let(:value) { "2018-04-29 09:00" } it { is_expected.to be_nil } end context 'for département champ' do - let(:champ) { create(:champ_departements, value:) } + let(:champ) { Champs::DepartementChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_departements)) } let(:value) { "69" } it { is_expected.to eq(['69 – Rhône']) } end context 'for dossier link champ' do - let(:champ) { create(:champ_dossier_link, value:) } + let(:champ) { Champs::DossierLinkChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_dossier_link)) } let(:value) { "9103132886" } it { is_expected.to eq([value]) } end context 'for drop down list champ' do - let(:champ) { create(:champ_dossier_link, value:) } + let(:champ) { Champs::DropDownListChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_drop_down_list)) } let(:value) { "HLM" } it { is_expected.to eq([value]) } end context 'for email champ' do - let(:champ) { build(:champ_email, value:) } + let(:champ) { Champs::EmailChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_email)) } let(:value) { "machin@example.com" } it { is_expected.to eq([value]) } end context 'for explication champ' do - let(:champ) { build(:champ_explication) } + let(:champ) { Champs::ExplicationChamp.new } it { is_expected.to be_nil } end context 'for header section champ' do - let(:champ) { build(:champ_header_section) } + let(:champ) { Champs::HeaderSectionChamp.new } it { is_expected.to be_nil } end context 'for linked drop down list champ' do - let(:champ) { create(:champ_linked_drop_down_list, primary_value: "hello", secondary_value: "world") } + let(:champ) { Champs::LinkedDropDownListChamp.new(primary_value: "hello", secondary_value: "world") } it { is_expected.to eq(["hello", "world"]) } end context 'for multiple drop down list champ' do - let(:champ) { build(:champ_multiple_drop_down_list, value:) } + let(:champ) { Champs::MultipleDropDownListChamp.new(value:) } context 'when there are multiple values selected' do let(:value) { JSON.generate(['goodbye', 'cruel', 'world']) } @@ -306,35 +368,41 @@ describe Champ do end context 'for number champ' do - let(:champ) { build(:champ_number, value:) } + let(:champ) { Champs::NumberChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_number)) } + let(:value) { "1234" } it { is_expected.to eq([value]) } end context 'for pays champ' do - let(:champ) { build(:champ_pays, value:) } + let(:champ) { Champs::PaysChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_pays)) } + let(:value) { "FR" } it { is_expected.to eq(['France']) } end context 'for phone champ' do - let(:champ) { build(:champ_phone, value:) } + let(:champ) { Champs::PhoneChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_phone)) } let(:value) { "06 06 06 06 06" } it { is_expected.to eq([value]) } end context 'for pièce justificative champ' do - let(:champ) { build(:champ_piece_justificative, value:) } + let(:champ) { Champs::PieceJustificativeChamp.new(value:) } let(:value) { nil } it { is_expected.to be_nil } end context 'for region champ' do - let(:champ) { build(:champ_regions, value:) } + let(:champ) { Champs::RegionChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_regions)) } let(:value) { "11" } it { is_expected.to eq(['Île-de-France']) } @@ -375,13 +443,13 @@ describe Champ do association_date_publication: "1962-05-31" ) end - let(:champ) { create(:champ_siret, value: etablissement.siret, etablissement:) } + let(:champ) { Champs::SiretChamp.new(value: etablissement.siret, etablissement:) } it { is_expected.to eq([etablissement.entreprise_siren, etablissement.entreprise_numero_tva_intracommunautaire, etablissement.entreprise_forme_juridique, etablissement.entreprise_forme_juridique_code, etablissement.entreprise_nom_commercial, etablissement.entreprise_raison_sociale, etablissement.entreprise_siret_siege_social, etablissement.entreprise_nom, etablissement.entreprise_prenom, etablissement.association_rna, etablissement.association_titre, etablissement.association_objet, etablissement.siret, etablissement.enseigne, etablissement.naf, etablissement.libelle_naf, etablissement.adresse, etablissement.code_postal, etablissement.localite, etablissement.code_insee_localite]) } end context 'when there is no etablissement' do - let(:champ) { create(:champ_siret, value:, etablissement: nil) } + let(:champ) { Champs::SiretChamp.new(value:, etablissement: nil) } let(:value) { "35130347400024" } it { is_expected.to eq([value]) } @@ -389,21 +457,25 @@ describe Champ do end context 'for text champ' do - let(:champ) { build(:champ_text, value:) } + let(:champ) { Champs::TextChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_text)) } let(:value) { "Blah" } it { is_expected.to eq([value]) } end context 'for text area champ' do - let(:champ) { build(:champ_textarea, value:) } + let(:champ) { Champs::TextareaChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_textarea)) } let(:value) { "Bla\nBlah de bla." } it { is_expected.to eq([value]) } end context 'for yes/no champ' do - let(:champ) { build(:champ_yes_no, value:) } + let(:champ) { Champs::YesNoChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_yes_no)) } + let(:libelle) { champ.libelle } context 'when the box is checked' do @@ -422,7 +494,9 @@ describe Champ do describe '#enqueue_virus_scan' do context 'when type_champ is type_de_champ_piece_justificative' do - let(:champ) { build(:champ_piece_justificative) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:champ) { dossier.champs.first } context 'and there is a blob' do before do @@ -450,8 +524,9 @@ describe Champ do describe '#enqueue_watermark_job' do context 'when type_champ is type_de_champ_titre_identite' do - let(:type_de_champ) { create(:type_de_champ_titre_identite) } - let(:champ) { build(:champ_titre_identite, type_de_champ: type_de_champ, skip_default_attachment: true) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :titre_identite }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:champ) { dossier.champs.first } before do allow(ClamavService).to receive(:safe_file?).and_return(true) @@ -476,40 +551,21 @@ describe Champ do end end - describe 'repetition' do - let(:procedure) { create(:procedure, :published, types_de_champ_private: [{}], types_de_champ_public: [{}, { type: :repetition, mandatory: true, children: [{}, { type: :integer_number }] }]) } - let(:tdc_repetition) { procedure.active_revision.types_de_champ_public.find(&:repetition?) } - let(:tdc_text) { procedure.active_revision.children_of(tdc_repetition).first } - - let(:dossier) { create(:dossier, procedure: procedure) } - let(:champ) { dossier.champs_public.find(&:repetition?) } - let(:champ_text) { champ.champs.find { |c| c.type_champ == 'text' } } - let(:champ_integer) { champ.champs.find { |c| c.type_champ == 'integer_number' } } - let(:champ_text_attrs) { attributes_for(:champ_text, type_de_champ: tdc_text, row_id: ULID.generate) } - - context 'when creating the model directly' do - let(:champ_text_row_1) { create(:champ_text, type_de_champ: tdc_text, row_id: ULID.generate, parent: champ, dossier: nil) } - - it 'associates nested champs to the parent dossier' do - expect(champ_text_row_1.dossier_id).to eq(champ.dossier_id) - end - end - end - describe '#log_fetch_external_data_exception' do - let(:champ) { create(:champ_siret) } + let(:champ) { Champs::SiretChamp.new } context "add execption to the log" do - before do - champ.log_fetch_external_data_exception(StandardError.new('My special exception!')) + it do + expect(champ).to receive(:update_column).with(:fetch_external_data_exceptions, ['PAN']) + champ.log_fetch_external_data_exception(double(inspect: 'PAN')) end - - it { expect(champ.fetch_external_data_exceptions).to eq(['#']) } end end describe "fetch_external_data" do - let(:champ) { create(:champ_rnf, data: 'some data') } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :rnf }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:champ) { dossier.champs.first.tap { _1.update_column(:data, 'some data') } } context "cleanup_if_empty" do it "remove data if external_id changes" do @@ -534,47 +590,50 @@ describe Champ do end describe "#input_name" do - let(:champ) { create(:champ_text) } + let(:champ) { Champs::TextChamp.new } it { expect(champ.input_name).to eq "dossier[champs_public_attributes][#{champ.public_id}]" } context "when private" do - let(:champ) { create(:champ_text, private: true) } + 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) { create(:champ_text, parent: create(:champ_text)) } + 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) { create(:champ_text, private: true, parent: create(:champ_text, private: true)) } + 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 '#update_with_external_data!' do - let(:champ) { create(:champ_siret) } - let(:data) { "data" } - subject { champ.update_with_external_data!(data: data) } - - it { expect { subject }.to change { champ.reload.data }.to(data) } - end - describe 'dom_id' do - let(:champ) { build(:champ_text, row_id: '1234') } + let(:champ) { Champs::TextChamp.new(row_id: '1234') } + before do + allow(champ).to receive(:type_de_champ).and_return(create(:type_de_champ_text)) + end - it { expect(champ.public_id).to eq("#{champ.stable_id}-#{champ.row_id}") } - it { expect(ActionView::RecordIdentifier.dom_id(champ)).to eq("champ_#{champ.public_id}") } - it { expect(ActionView::RecordIdentifier.dom_id(champ.type_de_champ)).to eq("type_de_champ_#{champ.type_de_champ.id}") } - it { expect(ActionView::RecordIdentifier.dom_class(champ)).to eq("champ") } + it do + expect(champ.public_id).to eq("#{champ.stable_id}-#{champ.row_id}") + expect(ActionView::RecordIdentifier.dom_id(champ)).to eq("champ_#{champ.public_id}") + expect(ActionView::RecordIdentifier.dom_id(champ.type_de_champ)).to eq("type_de_champ_#{champ.type_de_champ.id}") + expect(ActionView::RecordIdentifier.dom_class(champ)).to eq("champ") + end end describe 'clone' do + let(:procedure) { create(:procedure, types_de_champ_private:, types_de_champ_public:) } + let(:types_de_champ_private) { [] } + let(:types_de_champ_public) { [] } + let(:champ) { dossier.champs.first } + subject { champ.clone(fork) } context 'when champ public' do - let(:champ) { create(:champ_piece_justificative, private: false) } + let(:types_de_champ_public) { [{ type: :piece_justificative }] } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } context 'when fork' do let(:fork) { true } @@ -592,7 +651,8 @@ describe Champ do end context 'champ private' do - let(:champ) { create(:champ_piece_justificative, private: true) } + let(:dossier) { create(:dossier, :with_populated_annotations, procedure:) } + let(:types_de_champ_private) { [{ type: :piece_justificative }] } context 'when fork' do let(:fork) { true } diff --git a/spec/models/champs/address_champ_spec.rb b/spec/models/champs/address_champ_spec.rb index 7cc27997d..185089602 100644 --- a/spec/models/champs/address_champ_spec.rb +++ b/spec/models/champs/address_champ_spec.rb @@ -1,5 +1,11 @@ describe Champs::AddressChamp do - let(:champ) { build(:champ_address, value:, data:) } + let(:champ) do + described_class.new.tap do |champ| + champ.value = value + champ.data = data + champ.validate + end + end let(:value) { '' } let(:data) { nil } diff --git a/spec/models/champs/annuaire_education_champ_spec.rb b/spec/models/champs/annuaire_education_champ_spec.rb index 3ac3a87a0..378715474 100644 --- a/spec/models/champs/annuaire_education_champ_spec.rb +++ b/spec/models/champs/annuaire_education_champ_spec.rb @@ -4,7 +4,9 @@ require 'rails_helper' RSpec.describe Champs::AnnuaireEducationChamp do describe '#update_with_external_data!' do - let(:champ) { create(:champ_annuaire_education, data: "any data") } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :annuaire_education }]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first.tap { _1.update_column(:data, 'any data') } } subject { champ.update_with_external_data!(data: data) } shared_examples "a data updater (without updating the value)" do |data| diff --git a/spec/models/champs/carte_champ_spec.rb b/spec/models/champs/carte_champ_spec.rb index 37bdadb02..c90e199ec 100644 --- a/spec/models/champs/carte_champ_spec.rb +++ b/spec/models/champs/carte_champ_spec.rb @@ -1,5 +1,6 @@ describe Champs::CarteChamp do - let(:champ) { build(:champ_carte, geo_areas:) } + let(:champ) { Champs::CarteChamp.new(geo_areas:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_carte)) } let(:value) { '' } let(:coordinates) { [[[2.3859214782714844, 48.87442541960633], [2.3850631713867183, 48.87273183590832], [2.3809432983398438, 48.87081237174292], [2.3859214782714844, 48.87442541960633]]] } let(:geo_json) do diff --git a/spec/models/champs/checkbox_champ_spec.rb b/spec/models/champs/checkbox_champ_spec.rb index 04879247f..ab8d88a3c 100644 --- a/spec/models/champs/checkbox_champ_spec.rb +++ b/spec/models/champs/checkbox_champ_spec.rb @@ -1,12 +1,11 @@ describe Champs::CheckboxChamp do - it_behaves_like "a boolean champ" do - let(:boolean_champ) { build(:champ_checkbox, value: value) } - end + let(:boolean_champ) { described_class.new(value: value) } + before { allow(boolean_champ).to receive(:type_de_champ).and_return(build(:type_de_champ_checkbox)) } + it_behaves_like "a boolean champ" # TODO remove when normalize_checkbox_values is over describe '#true?' do - let(:checkbox_champ) { build(:champ_checkbox, value: value) } - subject { checkbox_champ.true? } + subject { boolean_champ.true? } context "when the checkbox value is 'on'" do let(:value) { 'on' } diff --git a/spec/models/champs/cnaf_champ_spec.rb b/spec/models/champs/cnaf_champ_spec.rb index 079c6813f..166008434 100644 --- a/spec/models/champs/cnaf_champ_spec.rb +++ b/spec/models/champs/cnaf_champ_spec.rb @@ -1,6 +1,6 @@ describe Champs::CnafChamp, type: :model do - let(:champ) { build(:champ_cnaf) } - + let(:champ) { described_class.new(dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_cnaf)) } describe 'numero_allocataire and code_postal' do before do champ.numero_allocataire = '1234567' @@ -37,7 +37,7 @@ describe Champs::CnafChamp, type: :model do describe '#validate' do let(:numero_allocataire) { '1234567' } let(:code_postal) { '12345' } - let(:champ) { described_class.new(dossier: create(:dossier), type_de_champ: create(:type_de_champ_cnaf)) } + let(:champ) { described_class.new(dossier: build(:dossier)) } let(:validation_context) { :champs_public_value } subject { champ.valid?(validation_context) } diff --git a/spec/models/champs/cojo_champ_spec.rb b/spec/models/champs/cojo_champ_spec.rb index 283815bde..2f19a1735 100644 --- a/spec/models/champs/cojo_champ_spec.rb +++ b/spec/models/champs/cojo_champ_spec.rb @@ -1,7 +1,5 @@ describe Champs::COJOChamp, type: :model do - let(:champ) { build(:champ_cojo, accreditation_number:, accreditation_birthdate:) } let(:external_id) { nil } - let(:stub) { stub_request(:post, url).with(body: { accreditationNumber: accreditation_number.to_i, birthdate: accreditation_birthdate }).to_return(body:, status:) } let(:url) { COJOService.new.send(:url) } let(:body) { Rails.root.join('spec', 'fixtures', 'files', 'api_cojo', "accreditation_#{response_type}.json").read } let(:status) { 200 } @@ -9,8 +7,17 @@ describe Champs::COJOChamp, type: :model do let(:accreditation_number) { '123456' } let(:accreditation_birthdate) { '21/12/1959' } + before { stub_request(:post, url).with(body: { accreditationNumber: accreditation_number.to_i, birthdate: accreditation_birthdate }).to_return(body:, status:) } + describe 'fetch_external_data' do - subject { stub; champ.fetch_external_data } + let(:champ) do + described_class.new do |champ| + champ.accreditation_number = accreditation_number + champ.accreditation_birthdate = accreditation_birthdate + end + end + + subject { champ.fetch_external_data } context 'success (yes)' do it { expect(subject.value!).to eq({ accreditation_success: true, accreditation_first_name: 'Florence', accreditation_last_name: 'Griffith-Joyner' }) } @@ -49,9 +56,14 @@ describe Champs::COJOChamp, type: :model do end describe 'fill champ' do - let(:champ) { create(:champ_cojo, accreditation_number:, accreditation_birthdate:) } - - subject { stub; champ.touch; perform_enqueued_jobs; champ.reload } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :cojo }]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } + before do + champ.update(accreditation_number:, accreditation_birthdate:, data: nil) + perform_enqueued_jobs; + end + subject { champ.reload } it 'success (yes)' do expect(subject.blank?).to be_falsey diff --git a/spec/models/champs/commune_champ_spec.rb b/spec/models/champs/commune_champ_spec.rb index 87d726dd6..50e7ba924 100644 --- a/spec/models/champs/commune_champ_spec.rb +++ b/spec/models/champs/commune_champ_spec.rb @@ -1,8 +1,17 @@ describe Champs::CommuneChamp do + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes, stable_id: 99 }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:code_insee) { '63102' } let(:code_postal) { '63290' } let(:code_departement) { '63' } - let(:champ) { create(:champ_communes, code_postal:, external_id: code_insee) } + let(:champ) do + described_class.new(stable_id: 99, dossier:).tap do |champ| + champ.code_postal = code_postal + champ.external_id = code_insee + champ.run_callbacks(:save) + end + end describe 'value' do it 'find commune' do @@ -18,7 +27,12 @@ describe Champs::CommuneChamp do end context 'with code' do - let(:champ) { create(:champ_communes, code: '63102-63290') } + let(:champ) do + described_class.new(stable_id: 99, dossier:).tap do |champ| + champ.code = '63102-63290' + champ.run_callbacks(:save) + end + end it 'find commune' do expect(champ.to_s).to eq('Châteldon (63290)') diff --git a/spec/models/champs/date_champ_spec.rb b/spec/models/champs/date_champ_spec.rb index af2743f57..624c6442a 100644 --- a/spec/models/champs/date_champ_spec.rb +++ b/spec/models/champs/date_champ_spec.rb @@ -1,47 +1,49 @@ describe Champs::DateChamp do - let(:date_champ) { create(:champ_date) } + let(:type_de_champ) { create(:type_de_champ_date) } + let(:date_champ) { described_class.new } + before { allow(date_champ).to receive(:type_de_champ).and_return(type_de_champ) } describe '#convert_to_iso8601' do it 'preserves nil' do champ = champ_with_value(nil) - champ.save - expect(champ.reload.value).to be_nil + champ.validate + expect(champ.value).to be_nil end it 'converts to nil if empty string' do champ = champ_with_value("") - champ.save - expect(champ.reload.value).to be_nil + champ.validate + expect(champ.value).to be_nil end it 'converts to nil if not ISO8601' do champ = champ_with_value("12-21-2023") - champ.save - expect(champ.reload.value).to be_nil + champ.validate + expect(champ.value).to be_nil end it 'converts to nil if not date' do champ = champ_with_value("value") - champ.save - expect(champ.reload.value).to be_nil + champ.validate + expect(champ.value).to be_nil end it "converts %d/%m/%Y format to ISO" do champ = champ_with_value("31/12/2017") - champ.save - expect(champ.reload.value).to eq("2017-12-31") + champ.validate + expect(champ.value).to eq("2017-12-31") end it 'preserves if ISO8601' do champ = champ_with_value("2023-12-21") - champ.save - expect(champ.reload.value).to eq("2023-12-21") + champ.validate + expect(champ.value).to eq("2023-12-21") end it 'converts to nil if false iso' do champ = champ_with_value("2023-27-02") - champ.save - expect(champ.reload.value).to eq(nil) + champ.validate + expect(champ.value).to eq(nil) end end diff --git a/spec/models/champs/datetime_champ_spec.rb b/spec/models/champs/datetime_champ_spec.rb index a8ef0bd42..91f1c2f84 100644 --- a/spec/models/champs/datetime_champ_spec.rb +++ b/spec/models/champs/datetime_champ_spec.rb @@ -1,47 +1,47 @@ describe Champs::DatetimeChamp do - let(:datetime_champ) { build(:champ_datetime) } + let(:datetime_champ) { described_class.new } describe '#convert_to_iso8601' do it 'preserves nil' do champ = champ_with_value(nil) - champ.save - expect(champ.reload.value).to be_nil + champ.run_callbacks(:validation) + expect(champ.value).to be_nil end it 'converts to nil if empty string' do champ = champ_with_value("") - champ.save - expect(champ.reload.value).to be_nil + champ.run_callbacks(:validation) + expect(champ.value).to be_nil end it 'converts to nil if not ISO8601' do champ = champ_with_value("12-21-2023 03:20") - champ.save - expect(champ.reload.value).to be_nil + champ.run_callbacks(:validation) + expect(champ.value).to be_nil end it 'converts to nil if not datetime' do champ = champ_with_value("value") - champ.save - expect(champ.reload.value).to be_nil + champ.run_callbacks(:validation) + expect(champ.value).to be_nil end it 'preserves if ISO8601' do champ = champ_with_value("2023-12-21T03:20") - champ.save - expect(champ.reload.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601) + champ.run_callbacks(:validation) + expect(champ.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601) end it 'converts to ISO8601 if form format' do champ = champ_with_value("{3=>21, 2=>12, 1=>2023, 4=>3, 5=>20}") - champ.save - expect(champ.reload.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601) + champ.run_callbacks(:validation) + expect(champ.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601) end it 'converts to ISO8601 if old browser form format' do champ = champ_with_value("21/12/2023 03:20") - champ.save - expect(champ.reload.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601) + champ.run_callbacks(:validation) + expect(champ.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601) end end diff --git a/spec/models/champs/decimal_number_champ_spec.rb b/spec/models/champs/decimal_number_champ_spec.rb index 57ac73cf8..8914cabfb 100644 --- a/spec/models/champs/decimal_number_champ_spec.rb +++ b/spec/models/champs/decimal_number_champ_spec.rb @@ -1,8 +1,13 @@ describe Champs::DecimalNumberChamp do - let(:champ) { build(:champ_decimal_number, value:) } - subject { champ.validate(:champs_public_value) } - describe 'validation' do + let(:champ) { Champs::DecimalNumberChamp.new(value:, dossier: build(:dossier)) } + before do + allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_decimal_number)) + allow(champ).to receive(:visible?).and_return(true) + champ.run_callbacks(:validation) + end + subject { champ.validate(:champs_public_value) } + context 'when the value is integer number' do let(:value) { 2 } @@ -25,7 +30,7 @@ describe Champs::DecimalNumberChamp do end context 'when value contain space' do - let(:champ) { create(:champ_decimal_number, :private, value:) } + before { champ.run_callbacks(:validation) } let(:value) { ' 2.6666 ' } it { expect(champ.value).to eq('2.6666') } end @@ -52,14 +57,15 @@ describe Champs::DecimalNumberChamp do end context 'when the champ is private, value is invalid, but validation is public' do - let(:champ) { build(:champ_decimal_number, :private, value:) } + let(:champ) { Champs::DecimalNumberChamp.new(value:, private: true, dossier: build(:dossier)) } let(:value) { '2.6666' } it { is_expected.to be_truthy } end end describe 'for_export' do - let(:champ) { create(:champ_decimal_number, value:) } + let(:champ) { Champs::DecimalNumberChamp.new(value:) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_decimal_number)) } subject { champ.for_export } context 'with nil' do let(:value) { 0 } diff --git a/spec/models/champs/departement_champ_spec.rb b/spec/models/champs/departement_champ_spec.rb index 38cbe67a8..31c864d1e 100644 --- a/spec/models/champs/departement_champ_spec.rb +++ b/spec/models/champs/departement_champ_spec.rb @@ -1,7 +1,8 @@ describe Champs::DepartementChamp, type: :model do describe 'validations' do describe 'external link' do - let(:champ) { build(:champ_departements, external_id: external_id) } + let(:champ) { described_class.new(external_id: external_id, dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_departements)) } subject { champ.validate(:champs_public_value) } context 'when nil' do @@ -30,7 +31,9 @@ describe Champs::DepartementChamp, type: :model do end describe 'value' do - let(:champ) { create(:champ_departements) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :departements }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:champ) { dossier.champs.first } subject { champ.validate(:champs_public_value) } before { champ.update_columns(value: value) } @@ -61,7 +64,8 @@ describe Champs::DepartementChamp, type: :model do end describe 'value' do - let(:champ) { build(:champ_departements, value: nil) } + let(:champ) { described_class.new(value: nil, dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_departements)) } it 'with code having 2 chars' do champ.value = '01' diff --git a/spec/models/champs/dgfip_champ_spec.rb b/spec/models/champs/dgfip_champ_spec.rb index da3901547..fe9683a71 100644 --- a/spec/models/champs/dgfip_champ_spec.rb +++ b/spec/models/champs/dgfip_champ_spec.rb @@ -1,5 +1,5 @@ describe Champs::DgfipChamp, type: :model do - let(:champ) { build(:champ_dgfip) } + let(:champ) { described_class.new } describe 'numero_fiscal and reference_avis' do before do @@ -37,7 +37,8 @@ describe Champs::DgfipChamp, type: :model do describe '#validate' do let(:numero_fiscal) { '1122299999092' } let(:reference_avis) { 'FC22299999092' } - let(:champ) { described_class.new(dossier: create(:dossier), type_de_champ: create(:type_de_champ_dgfip)) } + let(:champ) { described_class.new(dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_dgfip)) } let(:validation_context) { :champs_public_value } subject { champ.valid?(validation_context) } diff --git a/spec/models/champs/dossier_link_champ_spec.rb b/spec/models/champs/dossier_link_champ_spec.rb index ca69d37a9..8a4712973 100644 --- a/spec/models/champs/dossier_link_champ_spec.rb +++ b/spec/models/champs/dossier_link_champ_spec.rb @@ -1,7 +1,7 @@ describe Champs::DossierLinkChamp, type: :model do describe 'prefilling validations' do describe 'value' do - subject { build(:champ_dossier_link, value: value).valid?(:prefill) } + subject { described_class.new(value:, dossier: build(:dossier)).valid?(:prefill) } context 'when nil' do let(:value) { nil } diff --git a/spec/models/champs/drop_down_list_champ_spec.rb b/spec/models/champs/drop_down_list_champ_spec.rb index b897297cc..a76305f46 100644 --- a/spec/models/champs/drop_down_list_champ_spec.rb +++ b/spec/models/champs/drop_down_list_champ_spec.rb @@ -1,7 +1,8 @@ describe Champs::DropDownListChamp do describe 'validations' do describe 'inclusion' do - let(:champ) { build(:champ_drop_down_list, other: other, value: value) } + let(:champ) { described_class.new(other:, value:, dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_drop_down_list, drop_down_other: other)) } subject { champ.validate(:champs_public_value) } context 'when the other value is accepted' do @@ -51,7 +52,8 @@ describe Champs::DropDownListChamp do end describe '#drop_down_other?' do - let(:drop_down) { create(:champ_drop_down_list) } + let(:drop_down) { described_class.new(dossier: build(:dossier)) } + before { allow(drop_down).to receive(:type_de_champ).and_return(build(:type_de_champ_drop_down_list)) } context 'when drop_down_other is nil' do it do diff --git a/spec/models/champs/email_champ_spec.rb b/spec/models/champs/email_champ_spec.rb index 4f89d26fc..e9c4a52b8 100644 --- a/spec/models/champs/email_champ_spec.rb +++ b/spec/models/champs/email_champ_spec.rb @@ -1,7 +1,7 @@ describe Champs::EmailChamp do describe 'validation' do - let(:champ) { build(:champ_email, value: value) } - + let(:champ) { described_class.new(value:, dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_email)) } subject { champ.validate(:champs_public_value) } context 'when nil' do diff --git a/spec/models/champs/epci_champ_spec.rb b/spec/models/champs/epci_champ_spec.rb index 759e07558..c3edc3641 100644 --- a/spec/models/champs/epci_champ_spec.rb +++ b/spec/models/champs/epci_champ_spec.rb @@ -3,8 +3,8 @@ describe Champs::EpciChamp, type: :model do subject { champ.validate(:champs_public_value) } describe 'code_departement' do - let(:champ) { build(:champ_epci, code_departement: code_departement) } - + let(:champ) { Champs::EpciChamp.new(code_departement: code_departement, dossier: build(:dossier)) } + before { allow(champ).to receive(:visible?).and_return(true) } context 'when nil' do let(:code_departement) { nil } @@ -31,9 +31,13 @@ describe Champs::EpciChamp, type: :model do end describe 'external_id' do - let(:champ) { build(:champ_epci, code_departement: code_departement, external_id: nil) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :epci }]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } before do + champ.code_departement = code_departement + champ.external_id = nil champ.save!(validate: false) champ.update_columns(external_id: external_id) end @@ -75,13 +79,16 @@ describe Champs::EpciChamp, type: :model do end describe 'value' do - subject { champ.validate(:champs_public_value) } - - let(:champ) { build(:champ_epci, code_departement: code_departement, external_id: nil, value: nil) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :epci }]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } before do + champ.value = nil + champ.code_departement = code_departement + champ.external_id = nil champ.save!(validate: false) - champ.update_columns(external_id: external_id, value: value) + champ.update_columns(external_id:, value:) end context 'when code_departement is nil' do @@ -144,10 +151,11 @@ describe Champs::EpciChamp, type: :model do end describe 'value' do - let(:champ) { build(:champ_epci, external_id: nil, value: nil) } + let(:champ) { described_class.new } let(:epci) { APIGeoService.epcis('01').first } it 'with departement and code' do + allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_epci)) champ.code_departement = '01' champ.value = epci[:code] expect(champ.blank?).to be_falsey diff --git a/spec/models/champs/iban_champ_spec.rb b/spec/models/champs/iban_champ_spec.rb index 09c8b2bfc..82f129131 100644 --- a/spec/models/champs/iban_champ_spec.rb +++ b/spec/models/champs/iban_champ_spec.rb @@ -1,16 +1,21 @@ describe Champs::IbanChamp do describe '#valid?' do + let(:champ) { Champs::IbanChamp.new(dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_iban)) } + def with_value(value) + champ.tap { _1.value = value } + end it do - expect(build(:champ_iban, value: nil).valid?(:champs_public_value)).to be_truthy - expect(build(:champ_iban, value: "FR35 KDSQFDJQSMFDQMFDQ").valid?(:champs_public_value)).to be_falsey - expect(build(:champ_iban, value: "FR7630006000011234567890189").valid?(:champs_public_value)).to be_truthy - expect(build(:champ_iban, value: "FR76 3000 6000 0112 3456 7890 189").valid?(:champs_public_value)).to be_truthy - expect(build(:champ_iban, value: "FR76 3000 6000 0112 3456 7890 189DSF").valid?(:champs_public_value)).to be_falsey - expect(build(:champ_iban, value: "FR76 3000 6000 0112 3456 7890 189").valid?(:champs_public_value)).to be_truthy + expect(with_value(nil).valid?(:champs_public_value)).to be_truthy + expect(with_value("FR35 KDSQFDJQSMFDQMFDQ").valid?(:champs_public_value)).to be_falsey + expect(with_value("FR7630006000011234567890189").valid?(:champs_public_value)).to be_truthy + expect(with_value("FR76 3000 6000 0112 3456 7890 189").valid?(:champs_public_value)).to be_truthy + expect(with_value("FR76 3000 6000 0112 3456 7890 189DSF").valid?(:champs_public_value)).to be_falsey + expect(with_value("FR76 3000 6000 0112 3456 7890 189").valid?(:champs_public_value)).to be_truthy end it 'format value after validation' do - champ = build(:champ_iban, value: "FR76 3000 6000 0112 3456 7890 189") + with_value("FR76 3000 6000 0112 3456 7890 189") champ.valid?(:champs_public_value) expect(champ.value).to eq("FR76 3000 6000 0112 3456 7890 189") end diff --git a/spec/models/champs/integer_number_champ_spec.rb b/spec/models/champs/integer_number_champ_spec.rb index 7c2a4ad68..bbd0bd2eb 100644 --- a/spec/models/champs/integer_number_champ_spec.rb +++ b/spec/models/champs/integer_number_champ_spec.rb @@ -1,5 +1,6 @@ describe Champs::IntegerNumberChamp do - let(:champ) { build(:champ_integer_number, value:) } + let(:champ) { Champs::IntegerNumberChamp.new(value:, dossier: build(:dossier)) } + before { allow(champ).to receive(:visible?).and_return(true) } subject { champ.validate(:champs_public_value) } describe '#valid?' do diff --git a/spec/models/champs/linked_drop_down_list_champ_spec.rb b/spec/models/champs/linked_drop_down_list_champ_spec.rb index 32c464683..dc30a9b50 100644 --- a/spec/models/champs/linked_drop_down_list_champ_spec.rb +++ b/spec/models/champs/linked_drop_down_list_champ_spec.rb @@ -1,21 +1,19 @@ describe Champs::LinkedDropDownListChamp do describe '#unpack_value' do - let(:champ) { build(:champ_linked_drop_down_list, value: '["tata", "tutu"]') } + let(:champ) { Champs::LinkedDropDownListChamp.new(value: '["tata", "tutu"]') } it { expect(champ.primary_value).to eq('tata') } it { expect(champ.secondary_value).to eq('tutu') } end describe '#pack_value' do - let(:champ) { build(:champ_linked_drop_down_list, primary_value: 'tata', secondary_value: 'tutu') } - - before { champ.save } + let(:champ) { Champs::LinkedDropDownListChamp.new(primary_value: 'tata', secondary_value: 'tutu') } it { expect(champ.value).to eq('["tata","tutu"]') } end describe '#primary_value=' do - let!(:champ) { build(:champ_linked_drop_down_list, primary_value: 'tata', secondary_value: 'tutu') } + let(:champ) { Champs::LinkedDropDownListChamp.new(primary_value: 'tata', secondary_value: 'tutu') } before { champ.primary_value = '' } @@ -23,7 +21,8 @@ describe Champs::LinkedDropDownListChamp do end describe '#to_s' do - let(:champ) { build(:champ_linked_drop_down_list, value: [primary_value, secondary_value].to_json) } + let(:champ) { Champs::LinkedDropDownListChamp.new(value: [primary_value, secondary_value].to_json) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_linked_drop_down_list)) } let(:primary_value) { nil } let(:secondary_value) { nil } @@ -48,11 +47,12 @@ describe Champs::LinkedDropDownListChamp do end describe 'for_export' do - let(:champ) { build(:champ_linked_drop_down_list, value:) } + let(:champ) { Champs::LinkedDropDownListChamp.new(value:) } let(:value) { [primary_value, secondary_value].to_json } let(:primary_value) { nil } let(:secondary_value) { nil } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_linked_drop_down_list)) } subject { champ.for_export } context 'with no value' do @@ -78,7 +78,8 @@ describe Champs::LinkedDropDownListChamp do describe '#mandatory_and_blank' do let(:value) { "--Primary--\nSecondary" } - subject { described_class.new(type_de_champ: type_de_champ) } + subject { described_class.new } + before { allow(subject).to receive(:type_de_champ).and_return(type_de_champ) } context 'when the champ is not mandatory' do let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, mandatory: false, drop_down_list_value: value) } diff --git a/spec/models/champs/mesri_champ_spec.rb b/spec/models/champs/mesri_champ_spec.rb index 9e8b1ccca..c150bb19d 100644 --- a/spec/models/champs/mesri_champ_spec.rb +++ b/spec/models/champs/mesri_champ_spec.rb @@ -32,7 +32,9 @@ describe Champs::MesriChamp, type: :model do end describe '#validate' do - let(:champ) { described_class.new(dossier: create(:dossier), type_de_champ: create(:type_de_champ_mesri)) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :mesri, stable_id: 99 }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:champ) { described_class.new(dossier:, stable_id: 99) } let(:validation_context) { :create } subject { champ.valid?(validation_context) } diff --git a/spec/models/champs/multiple_drop_down_list_champ_spec.rb b/spec/models/champs/multiple_drop_down_list_champ_spec.rb index 407347098..0d36f86ec 100644 --- a/spec/models/champs/multiple_drop_down_list_champ_spec.rb +++ b/spec/models/champs/multiple_drop_down_list_champ_spec.rb @@ -1,7 +1,8 @@ describe Champs::MultipleDropDownListChamp do let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list, drop_down_list_value: "val1\r\nval2\r\nval3\r\n[brackets] val4") } let(:value) { nil } - let(:champ) { build(:champ_multiple_drop_down_list, type_de_champ:, value:) } + let(:champ) { Champs::MultipleDropDownListChamp.new(value:, dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(type_de_champ) } describe 'validations' do subject { champ.validate(:champs_public_value) } diff --git a/spec/models/champs/pays_champ_spec.rb b/spec/models/champs/pays_champ_spec.rb index 4c0da34d1..f990fbae3 100644 --- a/spec/models/champs/pays_champ_spec.rb +++ b/spec/models/champs/pays_champ_spec.rb @@ -1,5 +1,6 @@ describe Champs::PaysChamp, type: :model do - let(:champ) { build(:champ_pays, value: nil) } + let(:champ) { described_class.new(value: nil) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_pays)) } describe 'value' do it 'with code' do diff --git a/spec/models/champs/phone_champ_spec.rb b/spec/models/champs/phone_champ_spec.rb index 3c6855ac7..2b99b9714 100644 --- a/spec/models/champs/phone_champ_spec.rb +++ b/spec/models/champs/phone_champ_spec.rb @@ -1,6 +1,6 @@ describe Champs::PhoneChamp do - let(:champ) { build(:champ_phone) } - + let(:champ) { Champs::PhoneChamp.new(dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_phone)) } describe '#validate' do it do expect(champ_with_value(nil).validate(:champs_public_value)).to be_truthy diff --git a/spec/models/champs/piece_justificative_champ_spec.rb b/spec/models/champs/piece_justificative_champ_spec.rb index 36f7a663e..3fcf6a77c 100644 --- a/spec/models/champs/piece_justificative_champ_spec.rb +++ b/spec/models/champs/piece_justificative_champ_spec.rb @@ -3,60 +3,52 @@ require 'active_storage_validations/matchers' describe Champs::PieceJustificativeChamp do include ActiveStorageValidations::Matchers - describe "skip_validation is not set anymore" do - subject { champ_pj.type_de_champ.skip_pj_validation } - - context 'before_save' do - let(:champ_pj) { build (:champ_piece_justificative) } - it { is_expected.to be_falsy } - end - context 'after_save' do - let(:champ_pj) { create (:champ_piece_justificative) } - it { is_expected.to be_falsy } - end - end - describe "validations" do - let(:champ_pj) { create(:champ_piece_justificative) } - subject { champ_pj } + let(:champ) { Champs::PieceJustificativeChamp.new } + subject { champ } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_piece_justificative)) } context "by default" do it { is_expected.to validate_size_of(:piece_justificative_file).less_than(Champs::PieceJustificativeChamp::FILE_MAX_SIZE) } it { is_expected.to validate_content_type_of(:piece_justificative_file).rejecting('application/x-ms-dos-executable') } - it { expect(champ_pj.type_de_champ.skip_pj_validation).to be_falsy } + it { expect(champ.type_de_champ.skip_pj_validation).to be_falsy } end context "when validation is disabled" do - before { champ_pj.type_de_champ.update(skip_pj_validation: true) } + before { champ.type_de_champ.update(skip_pj_validation: true) } it { is_expected.not_to validate_size_of(:piece_justificative_file).less_than(Champs::PieceJustificativeChamp::FILE_MAX_SIZE) } end context "when content-type validation is disabled" do - before { champ_pj.type_de_champ.update(skip_content_type_pj_validation: true) } + before { champ.type_de_champ.update(skip_content_type_pj_validation: true) } it { is_expected.not_to validate_content_type_of(:piece_justificative_file).rejecting('application/x-ms-dos-executable') } end end describe "#for_export" do - let(:champ_pj) { create(:champ_piece_justificative) } - subject { champ_pj.for_export } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } + subject { champ.for_export } it { is_expected.to eq('toto.txt') } context 'without attached file' do - before { champ_pj.piece_justificative_file.purge } + before { champ.piece_justificative_file.purge } it { is_expected.to eq(nil) } end end describe '#for_api' do - let(:champ_pj) { create(:champ_piece_justificative) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } - before { champ_pj.piece_justificative_file.first.blob.update(virus_scan_result:) } + before { champ.piece_justificative_file.first.blob.update(virus_scan_result:) } - subject { champ_pj.for_api } + subject { champ.for_api } context 'when file is safe' do let(:virus_scan_result) { ActiveStorage::VirusScanner::SAFE } diff --git a/spec/models/champs/pole_emploi_champ_spec.rb b/spec/models/champs/pole_emploi_champ_spec.rb index be30dcb25..fe1d14dbb 100644 --- a/spec/models/champs/pole_emploi_champ_spec.rb +++ b/spec/models/champs/pole_emploi_champ_spec.rb @@ -1,5 +1,6 @@ describe Champs::PoleEmploiChamp, type: :model do - let(:champ) { build(:champ_pole_emploi) } + let(:champ) { described_class.new(dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(:type_de_champ_pole_emploi) } describe 'identifiant' do before do @@ -32,7 +33,6 @@ describe Champs::PoleEmploiChamp, type: :model do end describe '#validate' do - let(:champ) { described_class.new(dossier: create(:dossier), type_de_champ: create(:type_de_champ_pole_emploi)) } let(:validation_context) { :create } subject { champ.valid?(validation_context) } diff --git a/spec/models/champs/region_champ_spec.rb b/spec/models/champs/region_champ_spec.rb index 1d012c68b..3b430b88a 100644 --- a/spec/models/champs/region_champ_spec.rb +++ b/spec/models/champs/region_champ_spec.rb @@ -1,7 +1,17 @@ describe Champs::RegionChamp, type: :model do + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :regions, stable_id: 99 }]) } + let(:dossier) { create(:dossier, procedure:) } + describe 'validations' do describe 'external link' do - let(:champ) { build(:champ_regions, value: nil, external_id: external_id) } + let(:champ) do + described_class + .new(stable_id: 99, dossier:) + .tap do |champ| + champ.value = nil + champ.external_id = external_id + end + end subject { champ.validate(:champs_public_value) } context 'when nil' do let(:external_id) { nil } @@ -29,21 +39,26 @@ describe Champs::RegionChamp, type: :model do end describe 'value' do - let(:champ) { create(:champ_regions, value: nil) } + let(:champ) do + described_class + .new(stable_id: 99, dossier:) + .tap do |champ| + champ.value = value + end + end subject { champ.validate(:champs_public_value) } - before { champ.update_columns(value: value) } - context 'when nil' do let(:value) { nil } it { is_expected.to be_truthy } end + # not real use case, the value= method override value when blank? aka "" to nil context 'when blank' do let(:value) { '' } - it { is_expected.to be_falsey } + xit { is_expected.to be_falsey } end context 'when included in the region names' do @@ -61,7 +76,9 @@ describe Champs::RegionChamp, type: :model do end describe 'value' do - let(:champ) { build(:champ_regions, value: nil) } + let(:champ) do + described_class.new(stable_id: 99, dossier:) + end it 'with code' do champ.value = '01' diff --git a/spec/models/champs/rna_champ_spec.rb b/spec/models/champs/rna_champ_spec.rb index fcecd6606..0db6fa2dd 100644 --- a/spec/models/champs/rna_champ_spec.rb +++ b/spec/models/champs/rna_champ_spec.rb @@ -1,12 +1,15 @@ describe Champs::RNAChamp do - let(:champ) { create(:champ_rna, value: "W182736273") } - + let(:champ) { Champs::RNAChamp.new(value: "W182736273", dossier: build(:dossier)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_rna)) } + def with_value(value) + champ.tap { _1.value = value } + end describe '#valid?' do - it { expect(build(:champ_rna, value: nil).valid?(:champs_public_value)).to be_truthy } - it { expect(build(:champ_rna, value: "2736251627").valid?(:champs_public_value)).to be_falsey } - it { expect(build(:champ_rna, value: "A172736283").valid?(:champs_public_value)).to be_falsey } - it { expect(build(:champ_rna, value: "W1827362718").valid?(:champs_public_value)).to be_falsey } - it { expect(build(:champ_rna, value: "W182736273").valid?(:champs_public_value)).to be_truthy } + it { expect(with_value(nil).validate(:champs_public_value)).to be_truthy } + it { expect(with_value("2736251627").validate(:champs_public_value)).to be_falsey } + it { expect(with_value("A172736283").validate(:champs_public_value)).to be_falsey } + it { expect(with_value("W1827362718").validate(:champs_public_value)).to be_falsey } + it { expect(with_value("W182736273").validate(:champs_public_value)).to be_truthy } end describe "#export" do diff --git a/spec/models/champs/rnf_champ_spec.rb b/spec/models/champs/rnf_champ_spec.rb index 510269609..27f90e439 100644 --- a/spec/models/champs/rnf_champ_spec.rb +++ b/spec/models/champs/rnf_champ_spec.rb @@ -1,14 +1,15 @@ describe Champs::RNFChamp, type: :model do - let(:champ) { build(:champ_rnf, external_id:) } - let(:stub) { stub_request(:get, "#{url}/#{external_id}").to_return(body:, status:) } - let(:url) { RNFService.new.send(:url) } - let(:body) { Rails.root.join('spec', 'fixtures', 'files', 'api_rnf', "#{response_type}.json").read } + let(:champ) { described_class.new(external_id:) } let(:external_id) { '075-FDD-00003-01' } - let(:status) { 200 } + let(:body) { Rails.root.join('spec', 'fixtures', 'files', 'api_rnf', "#{response_type}.json").read } let(:response_type) { 'valid' } describe 'fetch_external_data' do - subject { stub; champ.fetch_external_data } + let(:url) { RNFService.new.send(:url) } + let(:status) { 200 } + before { stub_request(:get, "#{url}/#{external_id}").to_return(body:, status:) } + + subject { champ.fetch_external_data } context 'success' do it do @@ -84,7 +85,8 @@ describe Champs::RNFChamp, type: :model do end describe 'for_export' do - let(:champ) { build(:champ_rnf, external_id:, data: JSON.parse(body)) } + let(:champ) { described_class.new(external_id:, data: JSON.parse(body)) } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_rnf)) } it do expect(champ.for_export(:value)).to eq '075-FDD-00003-01' expect(champ.for_export(:nom)).to eq 'Fondation SFR' diff --git a/spec/models/champs/titre_identite_champ_spec.rb b/spec/models/champs/titre_identite_champ_spec.rb index 8311ccf72..29f888ee7 100644 --- a/spec/models/champs/titre_identite_champ_spec.rb +++ b/spec/models/champs/titre_identite_champ_spec.rb @@ -1,13 +1,16 @@ describe Champs::TitreIdentiteChamp do describe "#for_export" do - let(:champ_titre_identite) { create(:champ_titre_identite) } - - subject { champ_titre_identite.for_export } - - it { is_expected.to eq('présent') } + let(:champ) { described_class.new } + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_titre_identite)) } + subject { champ.for_export } + + context 'without attached file' do + let(:piece_justificative_file) { double(attached?: true) } + before { allow(champ).to receive(:piece_justificative_file).and_return(piece_justificative_file) } + it { is_expected.to eq('présent') } + end context 'without attached file' do - before { champ_titre_identite.piece_justificative_file.purge } it { is_expected.to eq('absent') } end end diff --git a/spec/models/champs/yes_no_champ_spec.rb b/spec/models/champs/yes_no_champ_spec.rb index 6017b85c4..ed395bf6b 100644 --- a/spec/models/champs/yes_no_champ_spec.rb +++ b/spec/models/champs/yes_no_champ_spec.rb @@ -1,5 +1,6 @@ describe Champs::YesNoChamp do it_behaves_like "a boolean champ" do - let(:boolean_champ) { build(:champ_yes_no, value: value) } + let(:boolean_champ) { described_class.new(value: value) } + before { allow(boolean_champ).to receive(:type_de_champ).and_return(build(:type_de_champ_yes_no)) } end end diff --git a/spec/models/concerns/champ_conditional_concern_spec.rb b/spec/models/concerns/champ_conditional_concern_spec.rb index b6c94b1a1..706f7937f 100644 --- a/spec/models/concerns/champ_conditional_concern_spec.rb +++ b/spec/models/concerns/champ_conditional_concern_spec.rb @@ -1,11 +1,10 @@ describe ChampConditionalConcern do include Logic - let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :decimal_number, stable_id: 99 }, { type: :decimal_number, condition: }]) } - let(:dossier) { create(:dossier, revision: procedure.active_revision) } - let(:types_de_champ) { procedure.active_revision.types_de_champ_public } - let(:champ) { create(:champ_decimal_number, dossier:, type_de_champ: types_de_champ.first, value: '1.1234') } - let(:last_champ) { create(:champ_decimal_number, dossier:, type_de_champ: types_de_champ.last, value: '1.1234') } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :decimal_number, stable_id: 99 }, { type: :decimal_number, stable_id: 999, condition: }]) } + let(:dossier) { create(:dossier, :with_populated_champs, revision: procedure.active_revision) } + let(:champ) { dossier.champs.find { _1.stable_id == 99 }.tap { _1.update_column(:value, '1.1234') } } + let(:last_champ) { dossier.champs.find { _1.stable_id == 999 }.tap { _1.update_column(:value, '1.1234') } } let(:condition) { nil } describe '#dependent_conditions?' do diff --git a/spec/models/concerns/dossier_clone_concern_spec.rb b/spec/models/concerns/dossier_clone_concern_spec.rb index 234f4de53..955061672 100644 --- a/spec/models/concerns/dossier_clone_concern_spec.rb +++ b/spec/models/concerns/dossier_clone_concern_spec.rb @@ -17,7 +17,7 @@ RSpec.describe DossierCloneConcern do describe '#clone' do let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) } let(:types_de_champ_public) { [{}] } - let(:types_de_champ_private) { [{}] } + let(:types_de_champ_private) { [] } let(:fork) { false } subject(:new_dossier) { dossier.clone(fork:) } @@ -131,67 +131,65 @@ RSpec.describe DossierCloneConcern do end context 'for Champs::Repetition with rows, original_champ.repetition and rows are duped' do - let(:dossier) { create(:dossier) } - let(:type_de_champ_repetition) { create(:type_de_champ_repetition, :with_types_de_champ, procedure: dossier.procedure) } - let(:champ_repetition) { create(:champ_repetition, type_de_champ: type_de_champ_repetition, dossier: dossier) } - before { dossier.champs_public << champ_repetition } + let(:types_de_champ_public) { [{ type: :repetition, children: [{}, {}] }] } + let(:champ_repetition) { dossier.champs.first } + let(:cloned_champ_repetition) { new_dossier.champs.first } it do - expect(Champs::RepetitionChamp.where(dossier: new_dossier).first.champs.count).to eq(4) - expect(Champs::RepetitionChamp.where(dossier: new_dossier).first.champs.ids).not_to eq(champ_repetition.champs.ids) + expect(cloned_champ_repetition.champs.count).to eq(4) + expect(cloned_champ_repetition.champs.ids).not_to eq(champ_repetition.champs.ids) end end context 'for Champs::CarteChamp with geo areas, original_champ.geo_areas are duped' do - let(:dossier) { create(:dossier) } - let(:type_de_champ_carte) { create(:type_de_champ_carte, procedure: dossier.procedure) } - let(:geo_area) { create(:geo_area, :selection_utilisateur, :polygon) } - let(:champ_carte) { create(:champ_carte, type_de_champ: type_de_champ_carte, geo_areas: [geo_area]) } - before { dossier.champs_public << champ_carte } + let(:types_de_champ_public) { [{ type: :carte }] } + let(:champ_carte) { dossier.champs.first } + let(:cloned_champ_carte) { new_dossier.champs.first } it do - expect(Champs::CarteChamp.where(dossier: new_dossier).first.geo_areas.count).to eq(1) - expect(Champs::CarteChamp.where(dossier: new_dossier).first.geo_areas.ids).not_to eq(champ_carte.geo_areas.ids) + expect(cloned_champ_carte.geo_areas.count).to eq(2) + expect(cloned_champ_carte.geo_areas.ids).not_to eq(champ_carte.geo_areas.ids) end end context 'for Champs::SiretChamp, original_champ.etablissement is duped' do - let(:dossier) { create(:dossier) } - let(:type_de_champs_siret) { create(:type_de_champ_siret, procedure: dossier.procedure) } - let(:etablissement) { create(:etablissement) } - let(:champ_siret) { create(:champ_siret, type_de_champ: type_de_champs_siret, etablissement: create(:etablissement)) } - before { dossier.champs_public << champ_siret } + let(:types_de_champ_public) { [{ type: :siret }] } + let(:champ_siret) { dossier.champs.first } + let(:cloned_champ_siret) { new_dossier.champs.first } - it do - expect(Champs::SiretChamp.where(dossier: dossier).first.etablissement).not_to be_nil - expect(Champs::SiretChamp.where(dossier: new_dossier).first.etablissement.id).not_to eq(champ_siret.etablissement.id) + it do + expect(champ_siret.etablissement).not_to be_nil + expect(cloned_champ_siret.etablissement.id).not_to eq(champ_siret.etablissement.id) + end end - end context 'for Champs::PieceJustificative, original_champ.piece_justificative_file is duped' do let(:types_de_champ_public) { [{ type: :piece_justificative }] } - let(:champ_piece_justificative) { dossier.champs_public.first } + let(:champ_piece_justificative) { dossier.champs.first } + let(:cloned_champ_piece_justificative) { new_dossier.champs.first } - it { expect(Champs::PieceJustificativeChamp.where(dossier: new_dossier).first.piece_justificative_file.first.blob).to eq(champ_piece_justificative.piece_justificative_file.first.blob) } + it { expect(cloned_champ_piece_justificative.piece_justificative_file.first.blob).to eq(champ_piece_justificative.piece_justificative_file.first.blob) } end context 'for Champs::AddressChamp, original_champ.data is duped' do - let(:dossier) { create(:dossier) } - let(:type_de_champs_adress) { create(:type_de_champ_address, procedure: dossier.procedure) } - let(:etablissement) { create(:etablissement) } - let(:champ_address) { create(:champ_address, type_de_champ: type_de_champs_adress, external_id: 'Address', data: { city_code: '75019' }) } - before { dossier.champs_public << champ_address } + let(:types_de_champ_public) { [{ type: :address }] } + let(:champ_address) { dossier.champs.first } + let(:cloned_champ_address) { new_dossier.champs.first } + + before { champ_address.update(external_id: 'Address', data: { city_code: '75019' }) } it do - expect(Champs::AddressChamp.where(dossier: dossier).first.data).not_to be_nil - expect(Champs::AddressChamp.where(dossier: dossier).first.external_id).not_to be_nil - expect(Champs::AddressChamp.where(dossier: new_dossier).first.external_id).to eq(champ_address.external_id) - expect(Champs::AddressChamp.where(dossier: new_dossier).first.data).to eq(champ_address.data) + expect(champ_address.data).not_to be_nil + expect(champ_address.external_id).not_to be_nil + expect(cloned_champ_address.external_id).to eq(champ_address.external_id) + expect(cloned_champ_address.data).to eq(champ_address.data) end end end context 'private are renewd' do + let(:types_de_champ_private) { [{}] } + it 'reset champs private values' do expect(new_dossier.champs_private.count).to eq(dossier.champs_private.count) expect(new_dossier.champs_private.ids).not_to eq(dossier.champs_private.ids) @@ -217,13 +215,13 @@ RSpec.describe DossierCloneConcern do context "piece justificative champ" do let(:types_de_champ_public) { [{ type: :piece_justificative }] } - let(:champ_pj) { dossier.champs_public.first } + let(:champ_pj) { dossier.champs.first } + let(:cloned_champ_pj) { new_dossier.champs.first } it { - champ_pj_fork = Champs::PieceJustificativeChamp.where(dossier: new_dossier).first - expect(champ_pj_fork.piece_justificative_file.first.blob).to eq(champ_pj.piece_justificative_file.first.blob) - expect(champ_pj_fork.created_at).to eq(champ_pj.created_at) - expect(champ_pj_fork.updated_at).to eq(champ_pj.updated_at) + expect(cloned_champ_pj.piece_justificative_file.first.blob).to eq(champ_pj.piece_justificative_file.first.blob) + expect(cloned_champ_pj.created_at).to eq(champ_pj.created_at) + expect(cloned_champ_pj.updated_at).to eq(champ_pj.updated_at) } end @@ -258,7 +256,8 @@ RSpec.describe DossierCloneConcern do before do champ = dossier.champs.find { _1.stable_id == 992 } - geo_area = build(:geo_area, champ:, geometry: { "i'm" => "invalid" }) + geo_area = champ.geo_areas.first + geo_area.geometry = { "i'm" => "invalid" } geo_area.save!(validate: false) end diff --git a/spec/models/concerns/dossier_prefillable_concern_spec.rb b/spec/models/concerns/dossier_prefillable_concern_spec.rb index 680688900..f3b1fe2bb 100644 --- a/spec/models/concerns/dossier_prefillable_concern_spec.rb +++ b/spec/models/concerns/dossier_prefillable_concern_spec.rb @@ -127,7 +127,7 @@ RSpec.describe DossierPrefillableConcern do private def find_champ_by_stable_id(dossier, stable_id) - dossier.champs.joins(:type_de_champ).find_by(types_de_champ: { stable_id: stable_id }) + dossier.champs.find_by(stable_id:) end end end diff --git a/spec/models/concerns/dossier_rebase_concern_spec.rb b/spec/models/concerns/dossier_rebase_concern_spec.rb index 655e463f6..d3fbec10b 100644 --- a/spec/models/concerns/dossier_rebase_concern_spec.rb +++ b/spec/models/concerns/dossier_rebase_concern_spec.rb @@ -87,7 +87,7 @@ describe DossierRebaseConcern do context 'with a value' do before do - dossier.champs.find_by(type_de_champ: type_de_champ).update(value: 'a value') + dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'a value') end it 'should be true' do @@ -364,7 +364,7 @@ describe DossierRebaseConcern do expect(dossier.champs_public.size).to eq(6) expect(dossier.champs.count(&:public?)).to eq(12) expect(rebased_text_champ.value).to eq(text_champ.value) - expect(rebased_text_champ.type_de_champ_id).not_to eq(text_champ.type_de_champ_id) + expect(rebased_text_champ.type_de_champ).not_to eq(text_champ.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) @@ -562,7 +562,7 @@ describe DossierRebaseConcern do context 'and the cadastre are removed' do before do - dossier.champs_public.first.update(value: 'v1', geo_areas: [create(:geo_area, :cadastre)]) + dossier.champs_public.first.update(value: 'v1', geo_areas: [build(:geo_area, :cadastre)]) stable_id = procedure.draft_revision.types_de_champ.find_by(libelle: 'l1') tdc_to_update = procedure.draft_revision.find_and_ensure_exclusive_use(stable_id) @@ -623,7 +623,7 @@ describe DossierRebaseConcern do def first_champ = dossier.champs_public.first before do - first_champ.update(value: 'v1', external_id: '123', geo_areas: [create(:geo_area)]) + first_champ.update(value: 'v1', external_id: '123', geo_areas: [build(:geo_area)]) first_champ.update(data: { a: 1 }) first_champ.piece_justificative_file.attach( diff --git a/spec/models/concerns/rna_champ_association_fetchable_concern_spec.rb b/spec/models/concerns/rna_champ_association_fetchable_concern_spec.rb index cc200d357..7908db04c 100644 --- a/spec/models/concerns/rna_champ_association_fetchable_concern_spec.rb +++ b/spec/models/concerns/rna_champ_association_fetchable_concern_spec.rb @@ -1,6 +1,12 @@ RSpec.describe RNAChampAssociationFetchableConcern do describe '.fetch_association!' do - let!(:champ) { create(:champ_rna, data: "not nil data", value: 'W173847273') } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :rna }]) } + let(:dossier) do + create(:dossier, :with_populated_champs, procedure:).tap do + _1.champs.first.update(data: "not nil data", value: 'W173847273') + end + end + let!(:champ) { dossier.champs.first } before do stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v4\/djepva\/api-association\/associations\/open_data\/#{rna}/) diff --git a/spec/models/concerns/siret_champ_etablissement_fetchable_concern_spec.rb b/spec/models/concerns/siret_champ_etablissement_fetchable_concern_spec.rb index 089099cb9..3d82ef676 100644 --- a/spec/models/concerns/siret_champ_etablissement_fetchable_concern_spec.rb +++ b/spec/models/concerns/siret_champ_etablissement_fetchable_concern_spec.rb @@ -3,7 +3,9 @@ RSpec.describe SiretChampEtablissementFetchableConcern do let(:api_etablissement_status) { 200 } let(:api_etablissement_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') } let(:token_expired) { false } - let!(:champ) { create(:champ_siret) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :siret }]) } + let(:dossier) { create(:dossier, procedure:) } + let!(:champ) { dossier.champs.first.tap { _1.update!(etablissement: create(:etablissement)) } } before do stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v3\/insee\/sirene\/etablissements\/#{siret}/) diff --git a/spec/models/concerns/tags_substitution_concern_spec.rb b/spec/models/concerns/tags_substitution_concern_spec.rb index e50ecfd70..b0c7c5398 100644 --- a/spec/models/concerns/tags_substitution_concern_spec.rb +++ b/spec/models/concerns/tags_substitution_concern_spec.rb @@ -257,7 +257,7 @@ describe TagsSubstitutionConcern, type: :model do context 'and the champ has a primary value' do before do - dossier.champs_public.find_by(type_de_champ: type_de_champ).update(primary_value: 'primo') + dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(primary_value: 'primo') dossier.reload end @@ -265,7 +265,7 @@ describe TagsSubstitutionConcern, type: :model do context 'and the champ has a secondary value' do before do - dossier.champs_public.find_by(type_de_champ: type_de_champ).update(secondary_value: 'secundo') + dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(secondary_value: 'secundo') dossier.reload end diff --git a/spec/models/concerns/treeable_concern_spec.rb b/spec/models/concerns/treeable_concern_spec.rb index 674720e92..31e754a33 100644 --- a/spec/models/concerns/treeable_concern_spec.rb +++ b/spec/models/concerns/treeable_concern_spec.rb @@ -10,28 +10,40 @@ describe TreeableConcern do subject { ChampsToTree.new(types_de_champ:).root } describe "to_tree" do - let(:header_1) { build(:champ_header_section_level_1).type_de_champ } - let(:header_1_2) { build(:champ_header_section_level_2).type_de_champ } - let(:header_2) { build(:champ_header_section_level_1).type_de_champ } - let(:champ_text) { build(:champ_text).type_de_champ } - let(:champ_textarea) { build(:champ_textarea).type_de_champ } - let(:champ_explication) { build(:champ_explication).type_de_champ } - let(:champ_communes) { build(:champ_communes).type_de_champ } + let(:procedure) { create(:procedure, types_de_champ_public:) } + let(:types_de_champ_public) { [] } + let(:types_de_champ) { procedure.active_revision.types_de_champ_public } + + let(:header_1) { { type: :header_section, level: 1, stable_id: 99 } } + let(:header_1_2) { { type: :header_section, level: 2, stable_id: 199 } } + let(:header_2) { { type: :header_section, level: 1, stable_id: 299 } } + let(:champ_text) { { stable_id: 399 } } + let(:champ_textarea) { { type: :textarea, stable_id: 499 } } + let(:champ_explication) { { type: :explication, stable_id: 599 } } + let(:champ_communes) { { type: :communes, stable_id: 699 } } + + let(:header_1_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 99 } } + let(:header_1_2_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 199 } } + let(:header_2_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 299 } } + let(:champ_text_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 399 } } + let(:champ_textarea_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 499 } } + let(:champ_explication_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 599 } } + let(:champ_communes_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 699 } } context 'without section' do - let(:types_de_champ) do + let(:types_de_champ_public) do [ champ_text, champ_textarea ] end it 'inlines champs at root level' do expect(subject.size).to eq(types_de_champ.size) - expect(subject).to eq(types_de_champ) + expect(subject).to eq([champ_text_tdc, champ_textarea_tdc]) end end context 'with header_section and champs' do - let(:types_de_champ) do + let(:types_de_champ_public) do [ header_1, champ_explication, @@ -44,14 +56,16 @@ describe TreeableConcern do it 'wraps champs within preview header section' do expect(subject.size).to eq(2) expect(subject).to eq([ - [header_1, champ_explication, champ_text], - [header_2, champ_textarea] + [header_1_tdc, champ_explication_tdc, champ_text_tdc], + [header_2_tdc, champ_textarea_tdc] ]) end end context 'leading champs, and in between sections only' do - let(:types_de_champ) do + let(:champ_textarea_bis) { { type: :textarea, stable_id: 799 } } + let(:champ_textarea_bis_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 799 } } + let(:types_de_champ_public) do [ champ_text, champ_textarea, @@ -59,22 +73,22 @@ describe TreeableConcern do champ_explication, champ_communes, header_2, - champ_textarea + champ_textarea_bis ] end it 'chunk by uniq champs' do expect(subject.size).to eq(4) expect(subject).to eq([ - champ_text, - champ_textarea, - [header_1, champ_explication, champ_communes], - [header_2, champ_textarea] + champ_text_tdc, + champ_textarea_tdc, + [header_1_tdc, champ_explication_tdc, champ_communes_tdc], + [header_2_tdc, champ_textarea_bis_tdc] ]) end end context 'with one sub sections' do - let(:types_de_champ) do + let(:types_de_champ_public) do [ header_1, champ_explication, @@ -87,18 +101,22 @@ describe TreeableConcern do it 'chunk by uniq champs' do expect(subject.size).to eq(2) expect(subject).to eq([ - [header_1, champ_explication, [header_1_2, champ_communes]], - [header_2, champ_textarea] + [header_1_tdc, champ_explication_tdc, [header_1_2_tdc, champ_communes_tdc]], + [header_2_tdc, champ_textarea_tdc] ]) end end context 'with consecutive subsection' do - let(:header_1) { build(:champ_header_section_level_1).type_de_champ } - let(:header_1_2_1) { build(:champ_header_section_level_2).type_de_champ } - let(:header_1_2_2) { build(:champ_header_section_level_2).type_de_champ } - let(:header_1_2_3) { build(:champ_header_section_level_2).type_de_champ } - let(:types_de_champ) do + let(:header_1_2_1) { { type: :header_section, level: 2, stable_id: 799 } } + let(:header_1_2_2) { { type: :header_section, level: 2, stable_id: 899 } } + let(:header_1_2_3) { { type: :header_section, level: 2, stable_id: 999 } } + + let(:header_1_2_1_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 799 } } + let(:header_1_2_2_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 899 } } + let(:header_1_2_3_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 999 } } + + let(:types_de_champ_public) do [ header_1, header_1_2_1, @@ -113,19 +131,20 @@ describe TreeableConcern do expect(subject.size).to eq(1) expect(subject).to eq([ [ - header_1, - [header_1_2_1, champ_text], - [header_1_2_2, champ_textarea], - [header_1_2_3, champ_communes] + header_1_tdc, + [header_1_2_1_tdc, champ_text_tdc], + [header_1_2_2_tdc, champ_textarea_tdc], + [header_1_2_3_tdc, champ_communes_tdc] ] ]) end end context 'with one sub sections and one subsub section' do - let(:header_1_2_3) { build(:champ_header_section_level_3).type_de_champ } + let(:header_1_2_3) { { type: :header_section, level: 3, stable_id: 799 } } + let(:header_1_2_3_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 799 } } - let(:types_de_champ) do + let(:types_de_champ_public) do [ header_1, champ_explication, @@ -142,19 +161,19 @@ describe TreeableConcern do expect(subject.size).to eq(2) expect(subject).to eq([ [ - header_1, - champ_explication, + header_1_tdc, + champ_explication_tdc, [ - header_1_2, - champ_communes, + header_1_2_tdc, + champ_communes_tdc, [ - header_1_2_3, champ_text + header_1_2_3_tdc, champ_text_tdc ] ] ], [ - header_2, - champ_textarea + header_2_tdc, + champ_textarea_tdc ] ]) end diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index 6a716acf9..16476828c 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -1575,12 +1575,12 @@ describe Dossier, type: :model do end context "when a SIRET champ has etablissement in degraded mode" do - let(:dossier_incomplete) { create(:dossier, :en_instruction) } - let(:dossier_ok) { create(:dossier, :en_instruction) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :siret }]) } + let(:dossier_incomplete) { create(:dossier, :en_instruction, :with_populated_champs, procedure:) } + let(:dossier_ok) { create(:dossier, :en_instruction, :with_populated_champs, procedure:) } before do - dossier_incomplete.champs_public << create(:champ_siret, dossier: dossier_incomplete, etablissement: Etablissement.new(siret: build(:etablissement).siret)) - dossier_ok.champs_public << create(:champ_siret, dossier: dossier_ok) + dossier_incomplete.champs.first.update(etablissement: Etablissement.new(siret: build(:etablissement).siret)) end it "can't accepter" do @@ -1837,43 +1837,42 @@ describe Dossier, type: :model do end describe '#geo_data' do - let(:dossier) { create(:dossier) } - let(:type_de_champ_carte) { create(:type_de_champ_carte, procedure: dossier.procedure) } - let(:geo_area) { create(:geo_area) } - let(:champ_carte) { create(:champ_carte, type_de_champ: type_de_champ_carte, geo_areas: [geo_area]) } + let(:procedure) { create(:procedure, types_de_champ_public:, types_de_champ_private:) } + let(:dossier) { create(:dossier, :with_populated_champs, :with_populated_annotations, procedure:) } + let(:types_de_champ_public) { [] } + let(:types_de_champ_private) { [] } context "without data" do it { expect(dossier.geo_data?).to be_falsey } end context "with geo data in public champ" do - before do - dossier.champs_public << champ_carte - end + let(:types_de_champ_public) { [{ type: :carte }] } it { expect(dossier.geo_data?).to be_truthy } end context "with geo data in private champ" do - before do - dossier.champs_private << champ_carte - end + let(:types_de_champ_private) { [{ type: :carte }] } it { expect(dossier.geo_data?).to be_truthy } end - it "should solve N+1 problem" do - dossier.champs_public << create_list(:champ_carte, 3, type_de_champ: type_de_champ_carte, geo_areas: [create(:geo_area)]) - dossier.champs_for_revision + context "should solve N+1 problem" do + let(:types_de_champ_public) { [{ type: :carte }, { type: :carte }, { type: :carte }] } - count = 0 + it do + dossier.champs_for_revision - callback = lambda { |*_args| count += 1 } - ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do - dossier.geo_data? + count = 0 + + callback = lambda { |*_args| count += 1 } + ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do + dossier.geo_data? + end + + expect(count).to eq(1) end - - expect(count).to eq(1) end end @@ -1930,13 +1929,13 @@ describe Dossier, type: :model do end describe "to_feature_collection" do - let(:dossier) { create(:dossier) } - let(:type_de_champ_carte) { create(:type_de_champ_carte, procedure: dossier.procedure) } - let(:geo_area) { create(:geo_area, :selection_utilisateur, :polygon) } - let(:champ_carte) { create(:champ_carte, type_de_champ: type_de_champ_carte, geo_areas: [geo_area]) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :carte }]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ_carte) { dossier.champs.first } + let(:geo_area) { build(:geo_area, :selection_utilisateur, :polygon) } before do - dossier.champs_public << champ_carte + champ_carte.update(geo_areas: [geo_area]) end it 'should have all champs carto' do @@ -2120,16 +2119,14 @@ describe Dossier, type: :model do end describe "remove_titres_identite!" do - let(:dossier) { create(:dossier, :en_instruction, :followed, :with_individual) } - let(:type_de_champ_titre_identite) { create(:type_de_champ_titre_identite, procedure: dossier.procedure) } - let(:champ_titre_identite) { create(:champ_titre_identite, type_de_champ: type_de_champ_titre_identite) } - let(:type_de_champ_titre_identite_vide) { create(:type_de_champ_titre_identite, procedure: dossier.procedure) } - let(:champ_titre_identite_vide) { create(:champ_titre_identite, type_de_champ: type_de_champ_titre_identite_vide) } + let(:declarative_with_state) { nil } + let(:procedure) { create(:procedure, declarative_with_state:, types_de_champ_public: [{ type: :titre_identite }, { type: :titre_identite }]) } + let(:dossier) { create(:dossier, :en_instruction, :followed, :with_populated_champs, procedure:) } + let(:champ_titre_identite) { dossier.champs.first } + let(:champ_titre_identite_vide) { dossier.champs.second } before do champ_titre_identite_vide.piece_justificative_file.purge - dossier.champs_public << champ_titre_identite - dossier.champs_public << champ_titre_identite_vide end it "clean up titres identite on accepter" do @@ -2154,7 +2151,8 @@ describe Dossier, type: :model do end context 'en_construction' do - let(:dossier) { create(:dossier, :en_construction, :followed, :with_individual, :with_declarative_accepte) } + let(:declarative_with_state) { 'accepte' } + let(:dossier) { create(:dossier, :en_construction, :followed, :with_populated_champs, procedure:) } it "clean up titres identite on accepter_automatiquement" do expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy diff --git a/spec/models/engagement_juridique_champ_spec.rb b/spec/models/engagement_juridique_champ_spec.rb index f704fa237..f16456bbc 100644 --- a/spec/models/engagement_juridique_champ_spec.rb +++ b/spec/models/engagement_juridique_champ_spec.rb @@ -1,6 +1,11 @@ describe Champs::EngagementJuridiqueChamp do describe 'validation' do - let(:champ) { build(:champ_engagement_juridique, value: value) } + let(:champ) do + described_class + .new(dossier: build(:dossier)) + .tap { _1.value = value } + end + before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_engagement_juridique)) } subject { champ.validate(:champs_public_value) } context 'with [A-Z]' do diff --git a/spec/models/etablissement_spec.rb b/spec/models/etablissement_spec.rb index 3b46462f2..8f9a363e9 100644 --- a/spec/models/etablissement_spec.rb +++ b/spec/models/etablissement_spec.rb @@ -119,6 +119,9 @@ describe Etablissement do let(:etablissement) { create(:etablissement, dossier: build(:dossier)) } it "schedule update search terms" do + etablissement + etablissement.dossier.debounce_index_search_terms_flag.remove + assert_enqueued_jobs(1, only: DossierIndexSearchTermsJob) do etablissement.update(entreprise_nom: "nom") end diff --git a/spec/models/export_template_spec.rb b/spec/models/export_template_spec.rb index d90de6744..595668aa2 100644 --- a/spec/models/export_template_spec.rb +++ b/spec/models/export_template_spec.rb @@ -136,46 +136,33 @@ describe ExportTemplate do end context 'for pj' do - let(:dossier) { procedure.dossiers.first } - let(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, stable_id: 3, procedure:) } - let(:champ_pj) { create(:champ_piece_justificative, type_de_champ: type_de_champ_pj) } - + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ_pj) { dossier.champs.find(&:piece_justificative?) } let(:attachment) { ActiveStorage::Attachment.new(name: 'pj', record: champ_pj, blob: ActiveStorage::Blob.new(filename: "superpj.png")) } - before do - dossier.champs_public << champ_pj - end it 'returns pj and custom name for pj' do expect(export_template.attachment_and_path(dossier, attachment, champ: champ_pj)).to eq([attachment, "DOSSIER_#{dossier.id}/superpj_justif-1.png"]) end end context 'pj repetable' do - let(:procedure) do - create(:procedure_with_dossiers, :for_individual, types_de_champ_public: [{ type: :repetition, mandatory: true, children: [{ libelle: 'sub type de champ' }] }]) - end - let(:type_de_champ_repetition) do - repetition = draft.types_de_champ_public.repetition.first - repetition.update(stable_id: 3333) - repetition - end + let(:procedure) { create(:procedure, :for_individual, types_de_champ_public:) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } let(:draft) { procedure.draft_revision } - let(:dossier) { procedure.dossiers.first } - - let(:type_de_champ_pj) do - draft.add_type_de_champ({ - type_champ: TypeDeChamp.type_champs.fetch(:piece_justificative), - libelle: "pj repet", - stable_id: 10, - parent_stable_id: type_de_champ_repetition.stable_id - }) + let(:types_de_champ_public) do + [ + { + type: :repetition, + stable_id: 3333, + mandatory: true, children: [ + { type: :text, libelle: 'sub type de champ' }, + { type: :piece_justificative, stable_id: 10, libelle: 'pj repet' } + ] + } + ] end - let(:champ_pj) { create(:champ_piece_justificative, type_de_champ: type_de_champ_pj) } - + let(:champ_pj) { dossier.champs.find(&:piece_justificative?) } let(:attachment) { ActiveStorage::Attachment.new(name: 'pj', record: champ_pj, blob: ActiveStorage::Blob.new(filename: "superpj.png")) } - before do - dossier.champs_public << champ_pj - end it 'rename repetable pj' do expect(export_template.attachment_and_path(dossier, attachment, champ: champ_pj)).to eq([attachment, "DOSSIER_#{dossier.id}/pj_repet_#{dossier.id}-1.png"]) end @@ -201,13 +188,14 @@ describe ExportTemplate do end describe '#tiptap_convert_pj' do - let(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile', procedure:) } - let(:champ_pj) { create(:champ_piece_justificative, type_de_champ: type_de_champ_pj) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile' }]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ_pj) { dossier.champs.first } let(:attachment) { ActiveStorage::Attachment.new(name: 'pj', record: champ_pj, blob: ActiveStorage::Blob.new(filename: "superpj.png")) } it 'convert pj' do attachment - expect(export_template.tiptap_convert_pj(dossier, type_de_champ_pj.stable_id, attachment)).to eq "superpj_justif" + expect(export_template.tiptap_convert_pj(dossier, 3, attachment)).to eq "superpj_justif" end end diff --git a/spec/models/logic/binary_operator_spec.rb b/spec/models/logic/binary_operator_spec.rb index b7924ebc7..cc6e81dd3 100644 --- a/spec/models/logic/binary_operator_spec.rb +++ b/spec/models/logic/binary_operator_spec.rb @@ -20,8 +20,8 @@ describe Logic::BinaryOperator do end describe '#sources' do - let(:champ) { create(:champ_integer_number, value: nil) } - let(:champ2) { create(:champ_integer_number, value: nil) } + let(:champ) { Champs::IntegerNumberChamp.new(value: nil, stable_id: 1) } + let(:champ2) { Champs::IntegerNumberChamp.new(value: nil, stable_id: 2) } it { expect(two_greater_than_one.sources).to eq([]) } it { expect(greater_than(champ_value(champ.stable_id), constant(2)).sources).to eq([champ.stable_id]) } @@ -32,7 +32,10 @@ end describe Logic::GreaterThan do include Logic - let(:champ) { create(:champ_integer_number, value: nil) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :integer_number }]) } + let(:tdc) { procedure.active_revision.types_de_champ.first } + let(:dossier) { create(:dossier, procedure:) } + let(:champ) { Champs::IntegerNumberChamp.new(value: nil, stable_id: tdc.stable_id, dossier:) } it 'computes' do expect(greater_than(constant(1), constant(1)).compute).to be(false) @@ -43,8 +46,6 @@ end describe Logic::GreaterThanEq do include Logic - let(:champ) { create(:champ_integer_number, value: nil) } - it 'computes' do expect(greater_than_eq(constant(0), constant(1)).compute).to be(false) expect(greater_than_eq(constant(1), constant(1)).compute).to be(true) diff --git a/spec/models/logic/champ_value_spec.rb b/spec/models/logic/champ_value_spec.rb index c287c57d4..8d72e861d 100644 --- a/spec/models/logic/champ_value_spec.rb +++ b/spec/models/logic/champ_value_spec.rb @@ -2,11 +2,18 @@ describe Logic::ChampValue do include Logic describe '#compute' do + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: tdc_type, drop_down_other: }]) } + let(:drop_down_other) { nil } + let(:tdc_type) { :text } + let(:tdc) { procedure.active_revision.types_de_champ.first } + let(:dossier) { create(:dossier, procedure:) } + subject { champ_value(champ.stable_id).compute([champ]) } context 'yes_no tdc' do + let(:tdc_type) { :yes_no } + let(:champ) { Champs::YesNoChamp.new(value: value, stable_id: tdc.stable_id, dossier:) } let(:value) { 'true' } - let(:champ) { create(:champ_yes_no, value: value) } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:boolean) } @@ -30,92 +37,117 @@ describe Logic::ChampValue do end context 'integer tdc' do - let(:champ) { create(:champ_integer_number, value: '42') } + let(:tdc_type) { :integer_number } + let(:champ) { Champs::IntegerNumberChamp.new(value:, stable_id: tdc.stable_id, dossier:) } + let(:value) { '42' } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:number) } it { is_expected.to eq(42) } context 'with a blank value' do - let(:champ) { create(:champ_integer_number, value: '') } + let(:value) { '' } it { is_expected.to be nil } end end context 'decimal tdc' do - let(:champ) { create(:champ_decimal_number, value: '42.01') } + let(:tdc_type) { :decimal_number } + let(:champ) { Champs::DecimalNumberChamp.new(value:, stable_id: tdc.stable_id, dossier:) } + let(:value) { '42.01' } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:number) } it { is_expected.to eq(42.01) } end context 'dropdown tdc' do - let(:champ) { create(:champ_drop_down_list, value: 'val1') } + let(:tdc_type) { :drop_down_list } + let(:champ) { Champs::DropDownListChamp.new(value:, other:, stable_id: tdc.stable_id, dossier:) } + let(:value) { 'val1' } + let(:other) { nil } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:enum) } it { is_expected.to eq('val1') } it { expect(champ_value(champ.stable_id).options([champ.type_de_champ])).to match_array([["val1", "val1"], ["val2", "val2"], ["val3", "val3"]]) } context 'with other enabled' do - let(:champ) { create(:champ_drop_down_list, value: 'val1', other: true) } + let(:tdc_type) { :drop_down_list } + let(:drop_down_other) { true } it { is_expected.to eq('val1') } it { expect(champ_value(champ.stable_id).options([champ.type_de_champ])).to match_array([["val1", "val1"], ["val2", "val2"], ["val3", "val3"], ["Autre", "__other__"]]) } - end - context 'with other filled' do - let(:champ) { create(:champ_drop_down_list, value: 'other value', other: true) } + context 'with other filled' do + let(:other) { true } - it { is_expected.to eq(Champs::DropDownListChamp::OTHER) } + it { is_expected.to eq(Champs::DropDownListChamp::OTHER) } + end end end context 'checkbox tdc' do - let(:champ) { create(:champ_checkbox, value: 'true') } + let(:tdc_type) { :checkbox } + let(:champ) { Champs::CheckboxChamp.new(value:, stable_id: tdc.stable_id, dossier:) } + let(:value) { 'true' } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:boolean) } it { is_expected.to eq(true) } end context 'departement tdc' do - let(:champ) { create(:champ_departements, value: '02') } + let(:tdc_type) { :departements } + let(:champ) { Champs::DepartementChamp.new(value:, stable_id: tdc.stable_id, dossier:) } + let(:value) { '02' } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:departement_enum) } it { is_expected.to eq({ value: '02', code_region: '32' }) } end context 'region tdc' do - let(:champ) { create(:champ_regions, value: 'La Réunion') } + let(:tdc_type) { :regions } + let(:champ) { Champs::RegionChamp.new(value:, stable_id: tdc.stable_id, dossier:) } + let(:value) { 'La Réunion' } it { is_expected.to eq('04') } end context 'commune tdc' do - let(:champ) { create(:champ_communes, code_postal: '92500', external_id: '92063') } + let(:tdc_type) { :communes } + let(:champ) do + Champs::CommuneChamp.new(code_postal:, external_id:, stable_id: tdc.stable_id, dossier:) + .tap { |c| c.send(:on_codes_change) } # private method called before save to fill value, which is required for compute + end + let(:code_postal) { '92500' } + let(:external_id) { '92063' } - it { is_expected.to eq({ code_departement: '92', code_region: '11' }) } + it do + is_expected.to eq({ code_departement: '92', code_region: '11' }) + end end context 'epci tdc' do - let(:champ) { build(:champ_epci, code_departement: '43') } - - before do - champ.save! - champ.update_columns(external_id: '244301016', value: 'CC des Sucs') + let(:tdc_type) { :epci } + let(:champ) do + Champs::EpciChamp.new(code_departement:, external_id:, stable_id: tdc.stable_id, dossier:) + .tap { |c| c.send(:on_epci_name_changes) } # private method called before save to fill value, which is required for compute end + let(:code_departement) { '43' } + let(:external_id) { '244301016' } it { is_expected.to eq({ code_departement: '43', code_region: '84' }) } end describe 'errors' do - let(:champ) { create(:champ) } + let(:tdc_type) { :number } + let(:champ) { Champs::IntegerNumberChamp.new(value: nil, stable_id: tdc.stable_id, dossier:) } it { expect(champ_value(champ.stable_id).errors([champ.type_de_champ])).to be_empty } it { expect(champ_value(champ.stable_id).errors([])).to eq([{ type: :not_available }]) } end describe '#sources' do - let(:champ) { create(:champ) } + let(:tdc_type) { :number } + let(:champ) { Champs::IntegerNumberChamp.new(value: nil, stable_id: tdc.stable_id, dossier:) } it { expect(champ_value(champ.stable_id).sources).to eq([champ.stable_id]) } end diff --git a/spec/models/logic/exclude_operator_spec.rb b/spec/models/logic/exclude_operator_spec.rb index b4c1248b7..48c628a8d 100644 --- a/spec/models/logic/exclude_operator_spec.rb +++ b/spec/models/logic/exclude_operator_spec.rb @@ -1,7 +1,10 @@ describe Logic::ExcludeOperator do include Logic - let(:champ) { create(:champ_multiple_drop_down_list, value: '["val1", "val2"]') } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :multiple_drop_down_list }]) } + let(:tdc) { procedure.active_revision.types_de_champ.first } + let(:dossier) { create(:dossier, procedure:) } + let(:champ) { Champs::MultipleDropDownListChamp.new(value: '["val1", "val2"]', stable_id: tdc.stable_id, dossier:) } describe '#compute' do it { expect(ds_exclude(champ_value(champ.stable_id), constant('val1')).compute([champ])).to be(false) } diff --git a/spec/models/logic/in_departement_operator_spec.rb b/spec/models/logic/in_departement_operator_spec.rb index 26f9f6f87..5638d8d41 100644 --- a/spec/models/logic/in_departement_operator_spec.rb +++ b/spec/models/logic/in_departement_operator_spec.rb @@ -1,8 +1,22 @@ describe Logic::InDepartementOperator do include Logic - let(:champ_commune) { create(:champ_communes, code_postal: '92500', external_id: '92063') } - let(:champ_epci) { create(:champ_epci, code_departement: '02', code_region: "32") } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes }, { type: :epci }]) } + let(:dossier) { create(:dossier, procedure:) } + + let(:tdc_commune) { procedure.active_revision.types_de_champ.first } + let(:champ_commune) do + Champs::CommuneChamp.new(code_postal: '92500', external_id: '92063', stable_id: tdc_commune.stable_id, dossier:) + .tap { |c| c.send(:on_codes_change) } # private method called before save to fill value, which is required for compute + end + + let(:tdc_epci) { procedure.active_revision.types_de_champ.second } + let(:champ_epci) do + Champs::EpciChamp.new(code_departement: '43', code_region: '32', external_id: '244301016', stable_id: tdc_epci.stable_id, dossier:) + .tap do |c| + c.send(:on_epci_name_changes) + end # private method called before save to fill value, which is required for compute + end describe '#compute' do context 'commune' do @@ -11,8 +25,7 @@ describe Logic::InDepartementOperator do context 'epci' do it do - champ_epci.update_columns(external_id: "200071991", value: "CC Retz en Valois") - expect(ds_in_departement(champ_value(champ_epci.stable_id), constant('02')).compute([champ_epci])).to be(true) + expect(ds_in_departement(champ_value(champ_epci.stable_id), constant('43')).compute([champ_epci])).to be(true) end end end diff --git a/spec/models/logic/in_region_operator_spec.rb b/spec/models/logic/in_region_operator_spec.rb index 3a6407543..8122ac42c 100644 --- a/spec/models/logic/in_region_operator_spec.rb +++ b/spec/models/logic/in_region_operator_spec.rb @@ -1,9 +1,25 @@ describe Logic::InRegionOperator do include Logic - let(:champ_commune) { create(:champ_communes, code_postal: '92500', external_id: '92063') } - let(:champ_epci) { create(:champ_epci, code_departement: '02', code_region: "32") } - let(:champ_departement) { create(:champ_departements, value: '01', code_region: '84') } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes }, { type: :epci }, { type: :departements }]) } + let(:dossier) { create(:dossier, procedure:) } + + let(:tdc_commune) { procedure.active_revision.types_de_champ.first } + let(:champ_commune) do + Champs::CommuneChamp.new(code_postal: '92500', external_id: '92063', stable_id: tdc_commune.stable_id, dossier:) + .tap { |c| c.send(:on_codes_change) } # private method called before save to fill value, which is required for compute + end + + let(:tdc_epci) { procedure.active_revision.types_de_champ.second } + let(:champ_epci) do + Champs::EpciChamp.new(code_departement: '43', code_region: '32', external_id: '244301016', stable_id: tdc_epci.stable_id, dossier:) + .tap do |c| + c.send(:on_epci_name_changes) + end # private method called before save to fill value, which is required for compute + end + + let(:tdc_departement) { procedure.active_revision.types_de_champ.third } + let(:champ_departement) { Champs::DepartementChamp.new(value: '01', stable_id: tdc_departement.stable_id, dossier:) } describe '#compute' do context 'commune' do @@ -12,8 +28,7 @@ describe Logic::InRegionOperator do context 'epci' do it do - champ_epci.update_columns(external_id: "200071991", value: "CC Retz en Valois") - expect(ds_in_region(champ_value(champ_epci.stable_id), constant('32')).compute([champ_epci])).to be(true) + expect(ds_in_region(champ_value(champ_epci.stable_id), constant('84')).compute([champ_epci])).to be(true) end end diff --git a/spec/models/logic/include_operator_spec.rb b/spec/models/logic/include_operator_spec.rb index 5697c1f2d..3405f4de1 100644 --- a/spec/models/logic/include_operator_spec.rb +++ b/spec/models/logic/include_operator_spec.rb @@ -1,7 +1,10 @@ describe Logic::IncludeOperator do include Logic - let(:champ) { create(:champ_multiple_drop_down_list, value: '["val1", "val2"]') } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :multiple_drop_down_list }]) } + let(:tdc) { procedure.active_revision.types_de_champ.first } + let(:dossier) { create(:dossier, procedure:) } + let(:champ) { Champs::MultipleDropDownListChamp.new(value: '["val1", "val2"]', stable_id: tdc.stable_id, dossier:) } describe '#compute' do it { expect(ds_include(champ_value(champ.stable_id), constant('val1')).compute([champ])).to be(true) } diff --git a/spec/models/logic/not_in_departement_operator_spec.rb b/spec/models/logic/not_in_departement_operator_spec.rb index ce5018503..a08377d5b 100644 --- a/spec/models/logic/not_in_departement_operator_spec.rb +++ b/spec/models/logic/not_in_departement_operator_spec.rb @@ -1,8 +1,22 @@ describe Logic::NotInDepartementOperator do include Logic - let(:champ_commune) { create(:champ_communes, code_postal: '92500', external_id: '92063') } - let(:champ_epci) { create(:champ_epci, code_departement: '02', code_region: "32") } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes }, { type: :epci }]) } + let(:dossier) { create(:dossier, procedure:) } + + let(:tdc_commune) { procedure.active_revision.types_de_champ.first } + let(:champ_commune) do + Champs::CommuneChamp.new(code_postal: '92500', external_id: '92063', stable_id: tdc_commune.stable_id, dossier:) + .tap { |c| c.send(:on_codes_change) } # private method called before save to fill value, which is required for compute + end + + let(:tdc_epci) { procedure.active_revision.types_de_champ.second } + let(:champ_epci) do + Champs::EpciChamp.new(code_departement: '43', code_region: '32', external_id: '244301016', stable_id: tdc_epci.stable_id, dossier:) + .tap do |c| + c.send(:on_epci_name_changes) + end # private method called before save to fill value, which is required for compute + end describe '#compute' do context 'commune' do @@ -14,8 +28,7 @@ describe Logic::NotInDepartementOperator do context 'epci' do it do - champ_epci.update_columns(external_id: "200071991", value: "CC Retz en Valois") - expect(ds_not_in_departement(champ_value(champ_epci.stable_id), constant('02')).compute([champ_epci])).to be(false) + expect(ds_not_in_departement(champ_value(champ_epci.stable_id), constant('43')).compute([champ_epci])).to be(false) expect(ds_not_in_departement(champ_value(champ_epci.stable_id), constant('03')).compute([champ_epci])).to be(true) end end diff --git a/spec/models/logic/not_in_region_operator_spec.rb b/spec/models/logic/not_in_region_operator_spec.rb index a9b21275b..5efd478b2 100644 --- a/spec/models/logic/not_in_region_operator_spec.rb +++ b/spec/models/logic/not_in_region_operator_spec.rb @@ -1,9 +1,29 @@ describe Logic::NotInRegionOperator do include Logic - let(:champ_commune) { create(:champ_communes, code_postal: '92500', external_id: '92063') } - let(:champ_epci) { create(:champ_epci, code_departement: '02', code_region: "32") } - let(:champ_departement) { create(:champ_departements, value: '01', code_region: '84') } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes }, { type: :epci }, { type: :departements }]) } + let(:dossier) { create(:dossier, procedure:) } + + let(:tdc_commune) { procedure.active_revision.types_de_champ.first } + let(:champ_commune) do + Champs::CommuneChamp.new(code_postal: '92500', external_id: '92063', stable_id: tdc_commune.stable_id, dossier:) + .tap { |c| c.send(:on_codes_change) } # private method called before save to fill value, which is required for compute + end + + let(:tdc_epci) { procedure.active_revision.types_de_champ.second } + let(:champ_epci) do + Champs::EpciChamp.new(code_departement: '43', code_region: '32', external_id: '244301016', stable_id: tdc_epci.stable_id, dossier:) + .tap do |c| + c.send(:on_epci_name_changes) + end # private method called before save to fill value, which is required for compute + end + + let(:tdc_departement) { procedure.active_revision.types_de_champ.third } + let(:champ_departement) { Champs::DepartementChamp.new(value: '01', stable_id: tdc_departement.stable_id, dossier:) } + + # let(:champ_commune) { create(:champ_communes, code_postal: '92500', external_id: '92063') } + # let(:champ_epci) { create(:champ_epci, code_departement: '02', code_region: "32") } + # let(:champ_departement) { create(:champ_departements, value: '01', code_region: '84') } describe '#compute' do context 'commune' do @@ -15,8 +35,7 @@ describe Logic::NotInRegionOperator do context 'epci' do it do - champ_epci.update_columns(external_id: "200071991", value: "CC Retz en Valois") - expect(ds_not_in_region(champ_value(champ_epci.stable_id), constant('32')).compute([champ_epci])).to be(false) + expect(ds_not_in_region(champ_value(champ_epci.stable_id), constant('84')).compute([champ_epci])).to be(false) expect(ds_not_in_region(champ_value(champ_epci.stable_id), constant('11')).compute([champ_epci])).to be(true) end end diff --git a/spec/models/prefill_champs_spec.rb b/spec/models/prefill_champs_spec.rb index 82b1bc22d..5e93fcde0 100644 --- a/spec/models/prefill_champs_spec.rb +++ b/spec/models/prefill_champs_spec.rb @@ -135,11 +135,12 @@ RSpec.describe PrefillChamps do let(:type_de_champ_child) { procedure.published_revision.children_of(type_de_champ).first } let(:type_de_champ_child_value) { "value" } let(:type_de_champ_child_value2) { "value2" } + let(:child_champs) { dossier.champs.where(stable_id: type_de_champ_child.stable_id) } let(:params) { { "champ_#{type_de_champ.to_typed_id_for_query}" => [{ "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value }, { "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value2 }] } } it "builds an array of hash(id, value) matching the given params" do - expect(prefill_champs_array).to match([{ id: type_de_champ_child.champ.first.id, value: type_de_champ_child_value }, { id: type_de_champ_child.champ.second.id, value: type_de_champ_child_value2 }]) + expect(prefill_champs_array).to match([{ id: child_champs.first.id, value: type_de_champ_child_value }, { id: child_champs.second.id, value: type_de_champ_child_value2 }]) end end @@ -177,11 +178,12 @@ RSpec.describe PrefillChamps do let(:type_de_champ_child) { procedure.published_revision.children_of(type_de_champ).first } let(:type_de_champ_child_value) { "value" } let(:type_de_champ_child_value2) { "value2" } + let(:child_champs) { dossier.champs.where(stable_id: type_de_champ_child.stable_id) } let(:params) { { "champ_#{type_de_champ.to_typed_id_for_query}" => [{ "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value }, { "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value2 }] } } it "builds an array of hash(id, value) matching the given params" do - expect(prefill_champs_array).to match([{ id: type_de_champ_child.champ.first.id, value: type_de_champ_child_value }, { id: type_de_champ_child.champ.second.id, value: type_de_champ_child_value2 }]) + expect(prefill_champs_array).to match([{ id: child_champs.first.id, value: type_de_champ_child_value }, { id: child_champs.second.id, value: type_de_champ_child_value2 }]) end end @@ -237,7 +239,7 @@ RSpec.describe PrefillChamps do private def find_champ_by_stable_id(dossier, stable_id) - dossier.champs.joins(:type_de_champ).find_by(types_de_champ: { stable_id: stable_id }) + dossier.champs.find_by(stable_id:) end def attributes(champ, value) diff --git a/spec/models/procedure_presentation_spec.rb b/spec/models/procedure_presentation_spec.rb index 75ad8b8f3..498d6b817 100644 --- a/spec/models/procedure_presentation_spec.rb +++ b/spec/models/procedure_presentation_spec.rb @@ -595,8 +595,8 @@ describe ProcedurePresentation do context 'with single value' do before do - kept_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'keep me') - discarded_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'discard me') + kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'keep me') + discarded_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'discard me') end it { is_expected.to contain_exactly(kept_dossier.id) } @@ -613,9 +613,9 @@ describe ProcedurePresentation do let(:other_kept_dossier) { create(:dossier, procedure: procedure) } before do - kept_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'keep me') - discarded_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'discard me') - other_kept_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'and me too') + kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'keep me') + discarded_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'discard me') + other_kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'and me too') end it 'returns every dossier that matches any of the search criteria for a given column' do @@ -628,8 +628,8 @@ describe ProcedurePresentation do let(:types_de_champ_public) { [{ type: :yes_no }] } before do - kept_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'true') - discarded_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'false') + kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'true') + discarded_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'false') end it { is_expected.to contain_exactly(kept_dossier.id) } @@ -640,8 +640,8 @@ describe ProcedurePresentation do let(:types_de_champ_public) { [{ type: :departements }] } before do - kept_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(external_id: '13') - discarded_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(external_id: '69') + kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(external_id: '13') + discarded_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(external_id: '69') end it { is_expected.to contain_exactly(kept_dossier.id) } @@ -656,8 +656,8 @@ describe ProcedurePresentation do let(:type_de_champ_private) { procedure.active_revision.types_de_champ_private.first } before do - kept_dossier.champs_private.find_by(type_de_champ: type_de_champ_private).update(value: 'keep me') - discarded_dossier.champs_private.find_by(type_de_champ: type_de_champ_private).update(value: 'discard me') + kept_dossier.champs.find_by(stable_id: type_de_champ_private.stable_id).update(value: 'keep me') + discarded_dossier.champs.find_by(stable_id: type_de_champ_private.stable_id).update(value: 'discard me') end it { is_expected.to contain_exactly(kept_dossier.id) } @@ -673,7 +673,7 @@ describe ProcedurePresentation do let(:other_kept_dossier) { create(:dossier, procedure: procedure) } before do - other_kept_dossier.champs_private.find_by(type_de_champ: type_de_champ_private).update(value: 'and me too') + other_kept_dossier.champs.find_by(stable_id: type_de_champ_private.stable_id).update(value: 'and me too') end it 'returns every dossier that matches any of the search criteria for a given column' do diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index ed5f50118..28fe56638 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -1584,12 +1584,15 @@ describe Procedure do end describe '#average_dossier_weight' do - let(:procedure) { create(:procedure, :published) } + let(:procedure) { create(:procedure, :published, types_de_champ_public: [{ type: :piece_justificative }]) } before do - create_dossier_with_pj_of_size(4, procedure) - create_dossier_with_pj_of_size(5, procedure) - create_dossier_with_pj_of_size(6, procedure) + create(:dossier, :accepte, :with_populated_champs, procedure:) + create(:dossier, :accepte, :with_populated_champs, procedure:) + create(:dossier, :accepte, :with_populated_champs, procedure:) + ActiveStorage::Blob.first.update!(byte_size: 4) + ActiveStorage::Blob.second.update!(byte_size: 5) + ActiveStorage::Blob.third.update!(byte_size: 6) end it 'estimates average dossier weight' do diff --git a/spec/models/stat_spec.rb b/spec/models/stat_spec.rb index 0898f7ef7..e2e4c862a 100644 --- a/spec/models/stat_spec.rb +++ b/spec/models/stat_spec.rb @@ -83,7 +83,7 @@ describe Stat, type: :model do describe '.cumulative_hash' do it 'works count and cumulate counters by month for both dossier and deleted dossiers' do - 12.downto(1).map do |i| + 2.downto(1).map do |i| create(:dossier, state: :en_construction, depose_at: i.months.ago) create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago) end @@ -98,18 +98,8 @@ describe Stat, type: :model do s.reload # Use `Hash#to_a` to also test the key ordering expect(s.dossiers_cumulative.to_a).to eq([ - [formatted_n_months_ago(12), 2], - [formatted_n_months_ago(11), 4], - [formatted_n_months_ago(10), 6], - [formatted_n_months_ago(9), 8], - [formatted_n_months_ago(8), 10], - [formatted_n_months_ago(7), 12], - [formatted_n_months_ago(6), 14], - [formatted_n_months_ago(5), 16], - [formatted_n_months_ago(4), 18], - [formatted_n_months_ago(3), 20], - [formatted_n_months_ago(2), 22], - [formatted_n_months_ago(1), 24] + [formatted_n_months_ago(2), 2], + [formatted_n_months_ago(1), 4] ]) end end diff --git a/spec/models/type_de_champ_spec.rb b/spec/models/type_de_champ_spec.rb index 75fb08351..95cd2bb44 100644 --- a/spec/models/type_de_champ_spec.rb +++ b/spec/models/type_de_champ_spec.rb @@ -10,17 +10,12 @@ describe TypeDeChamp do it { is_expected.not_to allow_value(nil).for(:type_champ) } it { is_expected.not_to allow_value('').for(:type_champ) } - it { is_expected.to allow_value(TypeDeChamp.type_champs.fetch(:text)).for(:type_champ) } - it { is_expected.to allow_value(TypeDeChamp.type_champs.fetch(:textarea)).for(:type_champ) } - it { is_expected.to allow_value(TypeDeChamp.type_champs.fetch(:datetime)).for(:type_champ) } - it { is_expected.to allow_value(TypeDeChamp.type_champs.fetch(:number)).for(:type_champ) } - it { is_expected.to allow_value(TypeDeChamp.type_champs.fetch(:checkbox)).for(:type_champ) } + let(:procedure) { create(:procedure, :with_all_champs) } + let(:dossier) { create(:dossier, procedure:) } it do - TypeDeChamp.type_champs.each do |(type_champ, _)| - type_de_champ = create(:"type_de_champ_#{type_champ}") - champ = type_de_champ.champ.create - + dossier.revision.types_de_champ_public.each do |type_de_champ| + champ = dossier.project_champ(type_de_champ, nil) expect(type_de_champ.dynamic_type.class.name).to match(/^TypesDeChamp::/) expect(champ.class.name).to match(/^Champs::/) end diff --git a/spec/models/types_de_champ/prefill_address_type_de_champ_spec.rb b/spec/models/types_de_champ/prefill_address_type_de_champ_spec.rb index 342bc688e..4edb505ad 100644 --- a/spec/models/types_de_champ/prefill_address_type_de_champ_spec.rb +++ b/spec/models/types_de_champ/prefill_address_type_de_champ_spec.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true RSpec.describe TypesDeChamp::PrefillAddressTypeDeChamp do - let(:procedure) { create(:procedure) } - let(:type_de_champ) { build(:type_de_champ_address, procedure: procedure) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :address }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:type_de_champ) { procedure.active_revision.types_de_champ.first } describe 'ancestors' do subject { described_class.new(type_de_champ, procedure.active_revision) } @@ -11,7 +12,7 @@ RSpec.describe TypesDeChamp::PrefillAddressTypeDeChamp do end describe '#to_assignable_attributes' do - let(:champ) { create(:champ_address, type_de_champ: type_de_champ) } + let(:champ) { dossier.champs.first } subject { described_class.build(type_de_champ, procedure.active_revision).to_assignable_attributes(champ, value) } context 'when the value is nil' do diff --git a/spec/models/types_de_champ/prefill_annuaire_education_type_de_champ_spec.rb b/spec/models/types_de_champ/prefill_annuaire_education_type_de_champ_spec.rb index e79629698..6e3b80325 100644 --- a/spec/models/types_de_champ/prefill_annuaire_education_type_de_champ_spec.rb +++ b/spec/models/types_de_champ/prefill_annuaire_education_type_de_champ_spec.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true RSpec.describe TypesDeChamp::PrefillAnnuaireEducationTypeDeChamp do - let(:procedure) { create(:procedure) } - let(:type_de_champ) { build(:type_de_champ_annuaire_education, procedure: procedure) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :annuaire_education }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:type_de_champ) { procedure.active_revision.types_de_champ.first } describe 'ancestors' do subject { described_class.new(type_de_champ, procedure.active_revision) } @@ -11,7 +12,7 @@ RSpec.describe TypesDeChamp::PrefillAnnuaireEducationTypeDeChamp do end describe '#to_assignable_attributes' do - let(:champ) { create(:champ_annuaire_education, type_de_champ: type_de_champ) } + let(:champ) { dossier.champs.first } subject { described_class.build(type_de_champ, procedure.active_revision).to_assignable_attributes(champ, value) } context 'when the value is nil' do diff --git a/spec/models/types_de_champ/prefill_commune_type_de_champ_spec.rb b/spec/models/types_de_champ/prefill_commune_type_de_champ_spec.rb index 2f02790b2..567733c73 100644 --- a/spec/models/types_de_champ/prefill_commune_type_de_champ_spec.rb +++ b/spec/models/types_de_champ/prefill_commune_type_de_champ_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe TypesDeChamp::PrefillCommuneTypeDeChamp do - let(:procedure) { create(:procedure) } + let(:procedure) { build(:procedure) } let(:type_de_champ) { build(:type_de_champ_communes, procedure: procedure) } describe 'ancestors' do @@ -28,7 +28,8 @@ RSpec.describe TypesDeChamp::PrefillCommuneTypeDeChamp do end describe '#to_assignable_attributes' do - let(:champ) { create(:champ_communes, type_de_champ: type_de_champ) } + let(:champ) { Champs::CommuneChamp.new() } + before { allow(champ).to receive(:type_de_champ).and_return(type_de_champ) } subject(:to_assignable_attributes) do described_class.build(type_de_champ, procedure.active_revision).to_assignable_attributes(champ, value) end diff --git a/spec/models/types_de_champ/prefill_epci_type_de_champ_spec.rb b/spec/models/types_de_champ/prefill_epci_type_de_champ_spec.rb index b4c255d5a..af84d2059 100644 --- a/spec/models/types_de_champ/prefill_epci_type_de_champ_spec.rb +++ b/spec/models/types_de_champ/prefill_epci_type_de_champ_spec.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true RSpec.describe TypesDeChamp::PrefillEpciTypeDeChamp do - let(:procedure) { create(:procedure) } + let(:procedure) { build(:procedure) } let(:type_de_champ) { build(:type_de_champ_epci, procedure: procedure) } - let(:champ) { create(:champ_epci, type_de_champ: type_de_champ) } + let(:champ) { Champs::EpciChamp.new } describe 'ancestors' do subject { described_class.new(type_de_champ, procedure.active_revision) } diff --git a/spec/models/types_de_champ/prefill_repetition_type_de_champ_spec.rb b/spec/models/types_de_champ/prefill_repetition_type_de_champ_spec.rb index 123b9f099..a5f121fe5 100644 --- a/spec/models/types_de_champ/prefill_repetition_type_de_champ_spec.rb +++ b/spec/models/types_de_champ/prefill_repetition_type_de_champ_spec.rb @@ -9,6 +9,8 @@ RSpec.describe TypesDeChamp::PrefillRepetitionTypeDeChamp, type: :model do let(:text_repetition) { prefillable_subchamps.first } let(:integer_repetition) { prefillable_subchamps.second } let(:region_repetition) { prefillable_subchamps.third } + let(:text_repetition_champs) { dossier.champs.where(stable_id: text_repetition.stable_id) } + let(:integer_repetition_champs) { dossier.champs.where(stable_id: integer_repetition.stable_id) } describe 'ancestors' do subject { described_class.build(type_de_champ, procedure.active_revision) } @@ -61,13 +63,13 @@ RSpec.describe TypesDeChamp::PrefillRepetitionTypeDeChamp, type: :model do context 'when the value is an array with some wrong keys' do let(:value) { [{ "champ_#{text_repetition.to_typed_id_for_query}" => "value", "blabla" => "value2" }, { "champ_#{integer_repetition.to_typed_id_for_query}" => "value3" }, { "blabla" => "false" }] } - it { is_expected.to match([[{ id: text_repetition.champ.first.id, value: "value" }], [{ id: integer_repetition.champ.second.id, value: "value3" }]]) } + it { is_expected.to match([[{ id: text_repetition_champs.first.id, value: "value" }], [{ id: integer_repetition_champs.second.id, value: "value3" }]]) } end context 'when the value is an array with right keys' do let(:value) { [{ "champ_#{text_repetition.to_typed_id_for_query}" => "value" }, { "champ_#{text_repetition.to_typed_id_for_query}" => "value2" }] } - it { is_expected.to match([[{ id: text_repetition.champ.first.id, value: "value" }], [{ id: text_repetition.champ.second.id, value: "value2" }]]) } + it { is_expected.to match([[{ id: text_repetition_champs.first.id, value: "value" }], [{ id: text_repetition_champs.second.id, value: "value2" }]]) } end end end diff --git a/spec/models/types_de_champ/prefill_type_de_champ_spec.rb b/spec/models/types_de_champ/prefill_type_de_champ_spec.rb index 7acead286..38577f90d 100644 --- a/spec/models/types_de_champ/prefill_type_de_champ_spec.rb +++ b/spec/models/types_de_champ/prefill_type_de_champ_spec.rb @@ -156,8 +156,10 @@ RSpec.describe TypesDeChamp::PrefillTypeDeChamp, type: :model do end describe '#to_assignable_attributes' do - let(:type_de_champ) { build(:type_de_champ_email, procedure: procedure) } - let(:champ) { build(:champ, type_de_champ: type_de_champ) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :email }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:type_de_champ) { procedure.active_revision.types_de_champ.first } + let(:champ) { dossier.champs.first } let(:value) { "any@email.org" } subject(:to_assignable_attributes) { described_class.build(type_de_champ, procedure.active_revision).to_assignable_attributes(champ, value) } diff --git a/spec/serializers/champ_serializer_spec.rb b/spec/serializers/champ_serializer_spec.rb deleted file mode 100644 index c7c902a13..000000000 --- a/spec/serializers/champ_serializer_spec.rb +++ /dev/null @@ -1,156 +0,0 @@ -describe ChampSerializer do - describe '#attributes' do - subject { ChampSerializer.new(serializable_object).serializable_hash } - let(:serializable_object) { champ } - - context 'when type champ is piece justificative' do - let(:champ) { create(:champ_piece_justificative) } - - it { - expect(subject[:value]).to a_string_matching('/rails/active_storage/disk/') - } - end - - context 'when type champ is not piece justificative' do - let(:champ) { create(:champ_text, value: "blah") } - - it { is_expected.to include(value: "blah") } - end - - context 'when type champ is carte' do - let(:champ) { create(:champ_carte, geo_areas: [geo_area].compact) } - let(:geo_area) { create(:geo_area, :cadastre, :multi_polygon) } - let(:geo_json) { attributes_for(:geo_area, :multi_polygon)[:geometry].stringify_keys } - - let(:serialized_champ) { - { - type_de_champ: serialized_type_de_champ, - value: serialized_value - } - } - let(:serialized_type_de_champ) { - { - description: serialized_description, - id: serialized_id, - libelle: serialized_libelle, - order_place: serialized_order_place, - type_champ: serialized_type_champ - } - } - let(:serialized_id) { -1 } - let(:serialized_description) { "" } - let(:serialized_order_place) { -1 } - let(:serialized_value) { geo_json } - - context 'and geo_area is selection_utilisateur' do - let(:geo_area) { create(:geo_area, :selection_utilisateur, :polygon) } - - context 'old_api' do - let(:serialized_libelle) { "user geometry" } - let(:serialized_type_champ) { "user_geometry" } - - let(:serializable_object) { champ.selection_utilisateur_legacy_geo_area } - - context 'when value is coordinates' do - it { expect(subject).to eq(serialized_champ) } - end - end - - context 'new_api' do - let(:geo_area) { nil } - let(:serialized_champ) { - { - type_de_champ: serialized_type_de_champ, - geo_areas: [], - value: serialized_value - } - } - let(:serialized_id) { champ.type_de_champ.stable_id } - let(:serialized_description) { champ.description } - let(:serialized_libelle) { champ.libelle } - let(:serialized_type_champ) { champ.type_champ } - let(:serialized_value) { nil } - - context 'when value is coordinates' do - let(:value) { coordinates.to_json } - - it { expect(subject).to eq(serialized_champ) } - end - end - end - - context 'and geo_area is cadastre' do - context 'new_api' do - it { - expect(subject[:geo_areas].first).to include( - source: GeoArea.sources.fetch(:cadastre), - geometry: geo_json, - numero: '42', - section: 'A11' - ) - expect(subject[:geo_areas].first.key?(:nom)).to be_falsey - } - end - - context 'old_api' do - let(:serializable_object) { champ.geo_areas.first } - let(:serialized_libelle) { "cadastre" } - let(:serialized_type_champ) { "cadastre" } - - it { expect(subject).to eq(serialized_champ) } - end - end - end - - context 'when type champ is siret' do - let(:etablissement) { create(:etablissement) } - let(:champ) { create(:champ_siret, etablissement:, value: etablissement.siret) } - - it { - is_expected.to include(value: etablissement.siret) - expect(subject[:etablissement]).to include(siret: etablissement.siret) - expect(subject[:entreprise]).to include(capital_social: etablissement.entreprise_capital_social) - } - end - - context 'when type champ yes_no' do - context 'true' do - let(:champ) { create(:champ_yes_no, value: 'true') } - - it { is_expected.to include(value: 'true') } - end - - context 'false' do - let(:champ) { create(:champ_yes_no, value: 'false') } - - it { is_expected.to include(value: 'false') } - end - - context 'nil' do - let(:champ) { create(:champ_yes_no, value: nil) } - - it { is_expected.to include(value: nil) } - end - end - - context 'when type champ checkbox' do - context 'true' do - let(:champ) { create(:champ_checkbox, value: 'true') } - - it { is_expected.to include(value: 'true') } - end - - context 'false' do - let(:champ) { create(:champ_checkbox, value: 'false') } - - it { is_expected.to include(value: 'false') } - end - - context 'nil' do - let(:champ) { create(:champ_checkbox, value: nil) } - - it { is_expected.to include(value: nil) } - end - end - end -end diff --git a/spec/serializers/dossier_serializer_spec.rb b/spec/serializers/dossier_serializer_spec.rb deleted file mode 100644 index 562e184c5..000000000 --- a/spec/serializers/dossier_serializer_spec.rb +++ /dev/null @@ -1,96 +0,0 @@ -describe DossierSerializer do - describe '#attributes' do - subject { DossierSerializer.new(dossier).serializable_hash } - - context 'when the dossier is en_construction' do - let(:dossier) { create(:dossier, :en_construction) } - - it { is_expected.to include(initiated_at: dossier.depose_at) } - it { is_expected.to include(state: 'initiated') } - end - - context 'when the dossier is en instruction' do - let(:dossier) { create(:dossier, :en_instruction) } - - it { is_expected.to include(received_at: dossier.en_instruction_at) } - end - - context 'champs' do - subject { super()[:champs] } - - let(:dossier) { create(:dossier, :en_construction, procedure: create(:procedure, :published, :with_type_de_champ)) } - - before do - dossier.champs_public << build(:champ_carte, dossier: dossier) - dossier.champs_public << build(:champ_siret, dossier: dossier) - dossier.champs_public << build(:champ_integer_number, dossier: dossier) - dossier.champs_public << build(:champ_decimal_number, dossier: dossier) - dossier.champs_public << build(:champ_linked_drop_down_list, dossier: dossier) - end - - it { - expect(subject.size).to eq(6) - - expect(subject[0][:type_de_champ][:type_champ]).to eq(TypeDeChamp.type_champs.fetch(:text)) - expect(subject[1][:type_de_champ][:type_champ]).to eq(TypeDeChamp.type_champs.fetch(:carte)) - expect(subject[2][:type_de_champ][:type_champ]).to eq(TypeDeChamp.type_champs.fetch(:siret)) - - expect(subject[1][:geo_areas].size).to eq(0) - expect(subject[2][:etablissement]).to be_present - expect(subject[2][:entreprise]).to be_present - - expect(subject[3][:value]).to eq(42) - expect(subject[4][:value]).to eq(42.1) - expect(subject[5][:value]).to eq({ primary: 'categorie 1', secondary: 'choix 1' }) - } - end - end - - context 'when a type de champ PJ was cloned from a legacy PJ' do - let(:original_pj_id) { 3 } - let(:cloned_type_de_champ) do - { - type: :piece_justificative, - libelle: "Vidéo de votre demande de subvention", - description: "Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique.\r\nRécupérer le formulaire vierge pour mon dossier : https://www.dance-academy.gouv.fr", - old_pj: { stable_id: original_pj_id } - } - end - let(:procedure) { create(:procedure, :published, types_de_champ_public: [cloned_type_de_champ]) } - let(:dossier) { create(:dossier, procedure: procedure) } - let(:champ_pj) { dossier.champs_public.last } - - before do - champ_pj.piece_justificative_file.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain") - end - - subject { DossierSerializer.new(dossier).serializable_hash } - - it "exposes the PJ in the legacy format" do - is_expected.to include( - types_de_piece_justificative: [ - { - "id" => original_pj_id, - "libelle" => cloned_type_de_champ[:libelle], - "description" => 'Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique.', - "lien_demarche" => 'https://www.dance-academy.gouv.fr', - "order_place" => 0 - } - ], - pieces_justificatives: [ - { - "content_url" => subject[:pieces_justificatives][0]["content_url"], - "created_at" => champ_pj.created_at.in_time_zone('UTC').iso8601(3), - "type_de_piece_justificative_id" => original_pj_id, - "user" => a_hash_including("id" => dossier.user.id) - } - ] - ) - expect(subject[:pieces_justificatives][0]["content_url"]).to match('/rails/active_storage/disk/') - end - - it "does not expose the PJ as a champ" do - expect(subject[:champs]).to be_empty - end - end -end diff --git a/spec/serializers/dossiers_serializer_spec.rb b/spec/serializers/dossiers_serializer_spec.rb deleted file mode 100644 index 77cfa2b53..000000000 --- a/spec/serializers/dossiers_serializer_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -describe DossiersSerializer do - describe '#attributes' do - subject { DossiersSerializer.new(dossier).serializable_hash } - - context 'when the dossier is en_construction' do - let(:dossier) { create(:dossier, :en_construction) } - - it { is_expected.to include(initiated_at: dossier.depose_at) } - it { is_expected.to include(state: 'initiated') } - end - end -end diff --git a/spec/serializers/individual_serializer_spec.rb b/spec/serializers/individual_serializer_spec.rb deleted file mode 100644 index 24ed39302..000000000 --- a/spec/serializers/individual_serializer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -describe IndividualSerializer do - describe '#attributes' do - let(:procedure) { create(:procedure) } - let(:dossier) { create(:dossier, procedure: procedure) } - let(:individual) { create(:individual, gender: 'M.', nom: 'nom', prenom: 'prenom', birthdate: Date.new(2001, 8, 27), dossier: dossier) } - - subject { IndividualSerializer.new(individual).serializable_hash } - - it { is_expected.to include(civilite: 'M.') } - it { is_expected.to include(nom: 'nom') } - it { is_expected.to include(prenom: 'prenom') } - it { is_expected.not_to have_key(:date_naissance) } - - context 'when the procedure asks for a birthdate' do - before { procedure.update(ask_birthday: true) } - - it { is_expected.to include(date_naissance: Date.new(2001, 8, 27)) } - end - end -end diff --git a/spec/serializers/procedure_serializer_spec.rb b/spec/serializers/procedure_serializer_spec.rb deleted file mode 100644 index 919bf53ee..000000000 --- a/spec/serializers/procedure_serializer_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -describe ProcedureSerializer do - describe '#attributes' do - subject { ProcedureSerializer.new(procedure).serializable_hash } - let(:procedure) { create(:procedure, :published) } - - it { - is_expected.to include(link: "http://test.host/commencer/#{procedure.path}") - is_expected.to include(state: "publiee") - } - end - - context 'when a type PJ was cloned to a type champ PJ' do - let(:original_pj_id) { 3 } - let(:cloned_type_de_champ) do - { - type: :piece_justificative, - libelle: "Vidéo de votre demande de subvention", - description: "Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique.\r\nRécupérer le formulaire vierge pour mon dossier : https://www.dance-academy.gouv.fr", - old_pj: { stable_id: original_pj_id } - } - end - let(:procedure) { create(:procedure, :published, types_de_champ_public: [cloned_type_de_champ]) } - - subject { ProcedureSerializer.new(procedure).serializable_hash } - - it "is exposed as a legacy type PJ" do - is_expected.to include( - types_de_piece_justificative: [ - { - "id" => original_pj_id, - "libelle" => cloned_type_de_champ[:libelle], - "description" => 'Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique.', - "lien_demarche" => 'https://www.dance-academy.gouv.fr', - "order_place" => 0 - } - ] - ) - end - - it "is not exposed as a type de champ" do - expect(subject[:types_de_champ]).to be_empty - end - end -end diff --git a/spec/services/procedure_export_service_spec.rb b/spec/services/procedure_export_service_spec.rb index 30488f846..f00471505 100644 --- a/spec/services/procedure_export_service_spec.rb +++ b/spec/services/procedure_export_service_spec.rb @@ -341,7 +341,8 @@ describe ProcedureExportService do procedure.reload end - let(:procedure) { create(:procedure, :published, :for_individual, types_de_champ_public: [{ type: :repetition, children: [{ libelle: 'Nom' }, { libelle: 'Age' }] }]) } + let(:types_de_champ_public) { [{ type: :repetition, children: [{ libelle: 'Nom' }, { libelle: 'Age' }] }] } + let(:procedure) { create(:procedure, :published, :for_individual, types_de_champ_public:) } let!(:dossiers) do [ create(:dossier, :en_instruction, :with_populated_champs, :with_individual, procedure: procedure), @@ -401,13 +402,13 @@ describe ProcedureExportService do end context 'with non unique labels' do - let(:dossier) { create(:dossier, :en_instruction, :with_populated_champs, :with_individual, procedure: procedure) } - let(:champ_repetition) { dossier.champs_public.find { |champ| champ.type_champ == 'repetition' } } - let(:type_de_champ_repetition) { create(:type_de_champ_repetition, :with_types_de_champ, procedure: procedure, libelle: champ_repetition.libelle) } - let!(:another_champ_repetition) { create(:champ_repetition, type_de_champ: type_de_champ_repetition, dossier: dossier) } + let(:types_de_champ_public) { [{ type: :repetition, libelle: 'Une repetition', children: [{}] }, { type: :repetition, libelle: 'Une repetition', children: [{}] }] } + let(:dossier) { create(:dossier, :en_instruction, :with_populated_champs, :with_individual, procedure:) } + let(:type_de_champ_repetition) { dossier.revision.types_de_champ_public.first } + let(:another_type_de_champ_repetition) { dossier.revision.types_de_champ_public.second } it 'should have sheets' do - expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis', another_champ_repetition.type_de_champ.libelle_for_export, champ_repetition.type_de_champ.libelle_for_export]) + expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis', type_de_champ_repetition.libelle_for_export, another_type_de_champ_repetition.libelle_for_export]) end end @@ -526,7 +527,7 @@ describe ProcedureExportService do end it 'should have features' do - expect(subject['features'].size).to eq(1) + expect(subject['features'].size).to eq(3) expect(properties['dossier_id']).to eq(dossier.id) expect(properties['champ_id']).to eq(champ_carte.stable_id) expect(properties['champ_label']).to eq(champ_carte.libelle) diff --git a/spec/services/serializer_service_spec.rb b/spec/services/serializer_service_spec.rb index 2a32c4184..26dd24cd9 100644 --- a/spec/services/serializer_service_spec.rb +++ b/spec/services/serializer_service_spec.rb @@ -1,13 +1,13 @@ describe SerializerService do - let(:dossier) { create(:dossier, :en_construction) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :siret }]) } + let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } + let(:etablissement) { champ.etablissement } describe 'champ' do subject { SerializerService.champ(champ) } describe 'type champ is siret' do - let(:etablissement) { create(:etablissement) } - let(:champ) { create(:champ_siret, etablissement:, dossier:) } - it { is_expected.to include("stringValue" => etablissement.siret) expect(subject["etablissement"]).to include("siret" => etablissement.siret) @@ -15,7 +15,7 @@ describe SerializerService do } context 'with entreprise_date_creation is nil' do - let(:etablissement) { create(:etablissement, entreprise_date_creation: nil) } + before { etablissement.update(entreprise_date_creation: nil) } it { expect(subject["etablissement"]["entreprise"]).to include("nomCommercial" => etablissement.entreprise_nom_commercial) diff --git a/spec/system/experts/expert_spec.rb b/spec/system/experts/expert_spec.rb index 52810e7eb..cb2dd566f 100644 --- a/spec/system/experts/expert_spec.rb +++ b/spec/system/experts/expert_spec.rb @@ -5,13 +5,14 @@ describe 'Inviting an expert:' do context 'as an invited Expert' do let(:expert) { create(:expert) } let(:instructeur) { create(:instructeur) } - let(:procedure) { create(:procedure, :published, types_de_champ_public: [{ type: :piece_justificative }], instructeurs: [instructeur]) } - let(:experts_procedure) { create(:experts_procedure, expert: expert, procedure: procedure) } - let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) } - let(:champ) { dossier.champs_public.first } + let(:types_de_champ_private) { [] } + let(:procedure) { create(:procedure, :published, types_de_champ_public: [{ type: :piece_justificative }, { type: :dossier_link }], types_de_champ_private:, instructeurs: [instructeur]) } + let(:experts_procedure) { create(:experts_procedure, expert: expert, procedure:) } + let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, :with_populated_annotations, procedure:) } + let(:champ) { dossier.champs.first } let(:avis) { create(:avis, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure, confidentiel: true) } let(:avis_with_question) { create(:avis, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure, confidentiel: true, question_label: 'Question ?') } - let(:dossier_accepte) { create(:dossier, :accepte, procedure: procedure) } + let(:dossier_accepte) { create(:dossier, :accepte, procedure:) } let(:avis_on_dossier_accepte) { create(:avis, dossier: dossier_accepte, claimant: instructeur, experts_procedure: experts_procedure, confidentiel: true) } context 'when I don’t already have an account' do @@ -133,25 +134,7 @@ describe 'Inviting an expert:' do context 'with dossiers having attached files', js: true do let(:path) { 'spec/fixtures/files/piece_justificative_0.pdf' } let(:commentaire) { create(:commentaire, instructeur: instructeur, dossier: dossier) } - - before do - champ - .piece_justificative_file - .attach(io: File.open(path), - filename: "piece_justificative_0.pdf", - content_type: "application/pdf", - metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }) - - dossier.champs_private << create(:champ_piece_justificative, private: true, dossier: dossier) - - dossier.champs_private - .first - .piece_justificative_file - .attach(io: File.open(path), - filename: "piece_justificative_0.pdf", - content_type: "application/pdf", - metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }) - end + let(:types_de_champ_private) { [{ type: :piece_justificative }] } scenario 'An Expert can download an archive containing attachments without any private champ, bill signature and operations logs' do avis # create avis @@ -171,8 +154,8 @@ describe 'Inviting an expert:' do expect(DownloadHelpers.download).to include "dossier-#{dossier.id}.zip" expect(files.size).to be 2 expect(files[0].filename.include?('export')).to be_truthy - expect(files[1].filename.include?('piece_justificative_0')).to be_truthy - expect(files[1].uncompressed_size).to be File.size(path) + expect(files[1].filename.include?('toto')).to be_truthy + expect(files[1].uncompressed_size).to be 4 end before { DownloadHelpers.clear_downloads } @@ -184,10 +167,10 @@ describe 'Inviting an expert:' do let(:expert_1) { create(:expert) } let(:expert_2) { create(:expert) } let(:instructeur) { create(:instructeur) } - let(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) } - let(:experts_procedure_1) { create(:experts_procedure, expert: expert_1, procedure: procedure) } - let(:experts_procedure_2) { create(:experts_procedure, expert: expert_2, procedure: procedure) } - let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) } + let(:procedure) { create(:procedure, :published, instructeurs: [instructeur], types_de_champ_public: [{ type: :dossier_link }]) } + let(:experts_procedure_1) { create(:experts_procedure, expert: expert_1, procedure:) } + let(:experts_procedure_2) { create(:experts_procedure, expert: expert_2, procedure:) } + let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) } let!(:avis_1) { create(:avis, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure_1, confidentiel: true) } let!(:avis_2) { create(:avis, dossier: dossier, claimant: instructeur, experts_procedure: experts_procedure_2, confidentiel: false) } diff --git a/spec/system/instructeurs/expert_spec.rb b/spec/system/instructeurs/expert_spec.rb index 426cc9655..119eadb38 100644 --- a/spec/system/instructeurs/expert_spec.rb +++ b/spec/system/instructeurs/expert_spec.rb @@ -6,9 +6,9 @@ describe 'Inviting an expert:', js: true do let(:expert) { create(:expert, password: expert_password) } let(:expert2) { create(:expert, password: expert_password) } let(:expert_password) { 'mot de passe d’expert' } - let(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) } - let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) } - let(:linked_dossier) { Dossier.find_by(id: dossier.reload.champs_public.filter(&:dossier_link?).filter_map(&:value)) } + let(:procedure) { create(:procedure, :published, instructeurs: [instructeur], types_de_champ_public: [{ type: :dossier_link }]) } + let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) } + let(:linked_dossier) { Dossier.find_by(id: dossier.champs.first.value) } before do clear_emails diff --git a/spec/system/instructeurs/procedure_filters_spec.rb b/spec/system/instructeurs/procedure_filters_spec.rb index 3900fe426..846d425e5 100644 --- a/spec/system/instructeurs/procedure_filters_spec.rb +++ b/spec/system/instructeurs/procedure_filters_spec.rb @@ -3,9 +3,9 @@ describe "procedure filters" do let(:procedure) { create(:procedure, :published, types_de_champ_public: [{ type: :text }, { type: :departements }, { type: :regions }, { type: :drop_down_list }], instructeurs: [instructeur]) } let!(:type_de_champ) { procedure.active_revision.types_de_champ_public.first } let!(:new_unfollow_dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) } - let!(:champ) { Champ.find_by(type_de_champ_id: type_de_champ.id, dossier_id: new_unfollow_dossier.id) } + let!(:champ) { Champ.find_by(stable_id: type_de_champ.stable_id, dossier_id: new_unfollow_dossier.id) } let!(:new_unfollow_dossier_2) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) } - let!(:champ_2) { Champ.find_by(type_de_champ_id: type_de_champ.id, dossier_id: new_unfollow_dossier_2.id) } + let!(:champ_2) { Champ.find_by(stable_id: type_de_champ.stable_id, dossier_id: new_unfollow_dossier_2.id) } before do champ.update(value: "Mon champ rempli") diff --git a/spec/system/users/dossier_prefill_get_spec.rb b/spec/system/users/dossier_prefill_get_spec.rb index 317135555..b297346f1 100644 --- a/spec/system/users/dossier_prefill_get_spec.rb +++ b/spec/system/users/dossier_prefill_get_spec.rb @@ -1,21 +1,38 @@ describe 'Prefilling a dossier (with a GET request):', js: true do let(:password) { SECURE_PASSWORD } - let(:procedure) { create(:procedure, :for_individual, :published, opendata: true) } + let(:types_de_champ_public) do + [ + { type: :text }, + { type: :phone }, + { type: :rna }, + { type: :siret }, + { type: :datetime }, + { type: :multiple_drop_down_list }, + { type: :epci }, + { type: :annuaire_education }, + { type: :dossier_link }, + { type: :communes }, + { type: :address }, + { type: :repetition, children: [{ type: :text }, { type: :decimal_number }] } + ] + end + let(:procedure) { create(:procedure, :for_individual, :published, opendata: true, types_de_champ_public:) } let(:dossier) { procedure.dossiers.last } + let(:types_de_champ) { procedure.active_revision.types_de_champ_public } - let(:type_de_champ_text) { create(:type_de_champ_text, procedure: procedure) } - let(:type_de_champ_phone) { create(:type_de_champ_phone, procedure: procedure) } - let(:type_de_champ_rna) { create(:type_de_champ_rna, procedure: procedure) } - let(:type_de_champ_siret) { create(:type_de_champ_siret, procedure: procedure) } - let(:type_de_champ_datetime) { create(:type_de_champ_datetime, procedure: procedure) } - let(:type_de_champ_multiple_drop_down_list) { create(:type_de_champ_multiple_drop_down_list, procedure: procedure) } - let(:type_de_champ_epci) { create(:type_de_champ_epci, procedure: procedure) } - let(:type_de_champ_annuaire_education) { create(:type_de_champ_annuaire_education, procedure: procedure) } - let(:type_de_champ_dossier_link) { create(:type_de_champ_dossier_link, procedure: procedure) } - let(:type_de_champ_commune) { create(:type_de_champ_communes, procedure: procedure) } - let(:type_de_champ_address) { create(:type_de_champ_address, procedure: procedure) } - let(:type_de_champ_repetition) { create(:type_de_champ_repetition, :with_types_de_champ, procedure: procedure) } + let(:type_de_champ_text) { types_de_champ[0] } + let(:type_de_champ_phone) { types_de_champ[1] } + let(:type_de_champ_rna) { types_de_champ[2] } + let(:type_de_champ_siret) { types_de_champ[3] } + let(:type_de_champ_datetime) { types_de_champ[4] } + let(:type_de_champ_multiple_drop_down_list) { types_de_champ[5] } + let(:type_de_champ_epci) { types_de_champ[6] } + let(:type_de_champ_annuaire_education) { types_de_champ[7] } + let(:type_de_champ_dossier_link) { types_de_champ[8] } + let(:type_de_champ_commune) { types_de_champ[9] } + let(:type_de_champ_address) { types_de_champ[10] } + let(:type_de_champ_repetition) { types_de_champ[11] } let(:text_value) { "My Neighbor Totoro is the best movie ever" } let(:phone_value) { "invalid phone value" } @@ -33,9 +50,9 @@ describe 'Prefilling a dossier (with a GET request):', js: true do let(:commune_value) { ['01540', '01457'] } let(:commune_libelle) { 'Vonnas (01540)' } let(:address_value) { "20 Avenue de Ségur 75007 Paris" } - let(:sub_type_de_champs_repetition) { procedure.active_revision.children_of(type_de_champ_repetition) } - let(:text_repetition_libelle) { sub_type_de_champs_repetition.first.libelle } - let(:integer_repetition_libelle) { sub_type_de_champs_repetition.second.libelle } + let(:sub_types_de_champ_repetition) { procedure.active_revision.children_of(type_de_champ_repetition) } + let(:text_repetition_libelle) { sub_types_de_champ_repetition.first.libelle } + let(:integer_repetition_libelle) { sub_types_de_champ_repetition.second.libelle } let(:text_repetition_value) { "First repetition text" } let(:integer_repetition_value) { "42" } let(:annuaire_education_value) { '0050009H' } @@ -58,8 +75,8 @@ describe 'Prefilling a dossier (with a GET request):', js: true do "champ_#{type_de_champ_rna.to_typed_id_for_query}" => rna_value, "champ_#{type_de_champ_repetition.to_typed_id_for_query}" => [ { - "champ_#{sub_type_de_champs_repetition.first.to_typed_id_for_query}": text_repetition_value, - "champ_#{sub_type_de_champs_repetition.second.to_typed_id_for_query}": integer_repetition_value + "champ_#{sub_types_de_champ_repetition.first.to_typed_id_for_query}": text_repetition_value, + "champ_#{sub_types_de_champ_repetition.second.to_typed_id_for_query}": integer_repetition_value } ], "champ_#{type_de_champ_annuaire_education.to_typed_id_for_query}" => annuaire_education_value, @@ -96,11 +113,11 @@ describe 'Prefilling a dossier (with a GET request):', js: true do context 'when authenticated with existing dossier and session params (ie: reload the page)' do let(:user) { create(:user, password: password) } - let(:dossier) { create(:dossier, :prefilled, procedure: procedure, prefill_token: "token", user: nil) } + let(:dossier) { create(:dossier, :prefilled, procedure:, prefill_token: "token", user: nil) } + let(:types_de_champ_public) { [{}] } before do - create(:champ_text, dossier: dossier, type_de_champ: type_de_champ_text, value: text_value) - + dossier.champs.first.update(value: text_value) page.set_rack_session(prefill_token: "token") page.set_rack_session(prefill_params_digest: PrefillChamps.digest({ "champ_#{type_de_champ_text.to_typed_id}" => text_value })) diff --git a/spec/system/users/dossier_prefill_post_spec.rb b/spec/system/users/dossier_prefill_post_spec.rb index ec8660eb0..f03299c5f 100644 --- a/spec/system/users/dossier_prefill_post_spec.rb +++ b/spec/system/users/dossier_prefill_post_spec.rb @@ -1,21 +1,38 @@ describe 'Prefilling a dossier (with a POST request):', js: true do let(:password) { SECURE_PASSWORD } - let(:procedure) { create(:procedure, :for_individual, :published) } + let(:types_de_champ_public) do + [ + { type: :text }, + { type: :phone }, + { type: :rna }, + { type: :siret }, + { type: :datetime }, + { type: :multiple_drop_down_list }, + { type: :epci }, + { type: :annuaire_education }, + { type: :dossier_link }, + { type: :communes }, + { type: :address }, + { type: :repetition, children: [{ type: :text }, { type: :decimal_number }] } + ] + end + let(:procedure) { create(:procedure, :for_individual, :published, types_de_champ_public:) } let(:dossier) { procedure.dossiers.last } + let(:types_de_champ) { procedure.active_revision.types_de_champ_public } - let(:type_de_champ_text) { create(:type_de_champ_text, procedure: procedure) } - let(:type_de_champ_phone) { create(:type_de_champ_phone, procedure: procedure) } - let(:type_de_champ_rna) { create(:type_de_champ_rna, procedure: procedure) } - let(:type_de_champ_siret) { create(:type_de_champ_siret, procedure: procedure) } - let(:type_de_champ_datetime) { create(:type_de_champ_datetime, procedure: procedure) } - let(:type_de_champ_multiple_drop_down_list) { create(:type_de_champ_multiple_drop_down_list, procedure: procedure) } - let(:type_de_champ_epci) { create(:type_de_champ_epci, procedure: procedure) } - let(:type_de_champ_annuaire_education) { create(:type_de_champ_annuaire_education, procedure: procedure) } - let(:type_de_champ_dossier_link) { create(:type_de_champ_dossier_link, procedure: procedure) } - let(:type_de_champ_commune) { create(:type_de_champ_communes, procedure: procedure) } - let(:type_de_champ_address) { create(:type_de_champ_address, procedure: procedure) } - let(:type_de_champ_repetition) { create(:type_de_champ_repetition, :with_types_de_champ, procedure: procedure) } + let(:type_de_champ_text) { types_de_champ[0] } + let(:type_de_champ_phone) { types_de_champ[1] } + let(:type_de_champ_rna) { types_de_champ[2] } + let(:type_de_champ_siret) { types_de_champ[3] } + let(:type_de_champ_datetime) { types_de_champ[4] } + let(:type_de_champ_multiple_drop_down_list) { types_de_champ[5] } + let(:type_de_champ_epci) { types_de_champ[6] } + let(:type_de_champ_annuaire_education) { types_de_champ[7] } + let(:type_de_champ_dossier_link) { types_de_champ[8] } + let(:type_de_champ_commune) { types_de_champ[9] } + let(:type_de_champ_address) { types_de_champ[10] } + let(:type_de_champ_repetition) { types_de_champ[11] } let(:text_value) { "My Neighbor Totoro is the best movie ever" } let(:phone_value) { "invalid phone value" } diff --git a/spec/system/users/en_construction_spec.rb b/spec/system/users/en_construction_spec.rb index f0fd43acf..203db839f 100644 --- a/spec/system/users/en_construction_spec.rb +++ b/spec/system/users/en_construction_spec.rb @@ -8,7 +8,7 @@ describe "Dossier en_construction" do } let(:champ) { - dossier.find_editing_fork(dossier.user).champs_public.find { _1.type_de_champ_id == tdc.id } + dossier.find_editing_fork(dossier.user).champs_public.find { _1.stable_id == tdc.stable_id } } scenario 'delete a non mandatory piece justificative', js: true do diff --git a/spec/tasks/maintenance/create_previews_for_pj_of_latest_dossiers_task_spec.rb b/spec/tasks/maintenance/create_previews_for_pj_of_latest_dossiers_task_spec.rb index 3cd9887d7..513d88599 100644 --- a/spec/tasks/maintenance/create_previews_for_pj_of_latest_dossiers_task_spec.rb +++ b/spec/tasks/maintenance/create_previews_for_pj_of_latest_dossiers_task_spec.rb @@ -5,10 +5,9 @@ require "rails_helper" module Maintenance RSpec.describe CreatePreviewsForPjOfLatestDossiersTask do describe "#process" do - let(:procedure) { create(:procedure_with_dossiers) } - let(:dossier) { procedure.dossiers.first } - let(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile', procedure:) } - let(:champ_pj) { create(:champ_piece_justificative, type_de_champ: type_de_champ_pj, dossier:) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile' }]) } + let(:dossier) { create(:dossier, procedure:) } + let(:champ_pj) { dossier.champs.first } let(:blob_info) do { filename: file.original_filename, diff --git a/spec/tasks/maintenance/create_variants_for_pj_of_latest_dossiers_task_spec.rb b/spec/tasks/maintenance/create_variants_for_pj_of_latest_dossiers_task_spec.rb index 2944b5811..5aca76b9c 100644 --- a/spec/tasks/maintenance/create_variants_for_pj_of_latest_dossiers_task_spec.rb +++ b/spec/tasks/maintenance/create_variants_for_pj_of_latest_dossiers_task_spec.rb @@ -5,10 +5,9 @@ require "rails_helper" module Maintenance RSpec.describe CreateVariantsForPjOfLatestDossiersTask do describe "#process" do - let(:procedure) { create(:procedure_with_dossiers) } + let(:procedure) { create(:procedure_with_dossiers, types_de_champ_public: [{ type: :piece_justificative, libelle: 'Justificatif de domicile', stable_id: 3 }]) } let(:dossier) { procedure.dossiers.first } - let(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile', procedure:) } - let(:champ_pj) { create(:champ_piece_justificative, type_de_champ: type_de_champ_pj, dossier:) } + let(:champ_pj) { dossier.champs.first } let(:blob_info) do { filename: file.original_filename, diff --git a/spec/views/shared/champs/multiple_drop_down_list/_show.html.haml_spec.rb b/spec/views/shared/champs/multiple_drop_down_list/_show.html.haml_spec.rb index 666a99a16..1c3a7bce0 100644 --- a/spec/views/shared/champs/multiple_drop_down_list/_show.html.haml_spec.rb +++ b/spec/views/shared/champs/multiple_drop_down_list/_show.html.haml_spec.rb @@ -1,7 +1,10 @@ describe 'views/shared/champs/multiple_drop_down_list/_show', type: :view do - let(:champ) { build(:champ_multiple_drop_down_list, value: ['abc', '2, 3, 4']) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :multiple_drop_down_list }]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:champ) { dossier.champs.first } - subject { render partial: 'shared/champs/multiple_drop_down_list/show', locals: { champ: champ } } + before { champ.update(value: ['abc', '2, 3, 4']) } + subject { render partial: 'shared/champs/multiple_drop_down_list/show', locals: { champ: } } it 'renders the view' do subject