diff --git a/app/models/champs/repetition_champ.rb b/app/models/champs/repetition_champ.rb index e94bbf518..f8e6dfe46 100644 --- a/app/models/champs/repetition_champ.rb +++ b/app/models/champs/repetition_champ.rb @@ -40,11 +40,11 @@ class Champs::RepetitionChamp < Champ self[attribute] end - def spreadsheet_columns(types_de_champ) + def spreadsheet_columns(types_de_champ, export_template: nil) [ ['Dossier ID', :dossier_id], ['Ligne', :index] - ] + dossier.champs_for_export(types_de_champ, row_id) + ] + dossier.champ_values_for_export(types_de_champ, row_id:, export_template:) end end end diff --git a/app/models/concerns/dossier_champs_concern.rb b/app/models/concerns/dossier_champs_concern.rb index 570b744d8..f6e9baf0a 100644 --- a/app/models/concerns/dossier_champs_concern.rb +++ b/app/models/concerns/dossier_champs_concern.rb @@ -82,15 +82,6 @@ module DossierChampsConcern .map { _1.repetition? ? project_champ(_1, nil) : champ_for_update(_1, nil, updated_by: nil) } end - def champs_for_export(types_de_champ, row_id = nil) - types_de_champ.flat_map do |type_de_champ| - champ = filled_champ(type_de_champ, row_id) - type_de_champ.libelles_for_export.map do |(libelle, path)| - [libelle, type_de_champ.champ_value_for_export(champ, path)] - end - end - end - def champ_value_for_tag(type_de_champ, path = :value) champ = filled_champ(type_de_champ, nil) type_de_champ.champ_value_for_tag(champ, path) diff --git a/app/models/concerns/dossier_export_concern.rb b/app/models/concerns/dossier_export_concern.rb new file mode 100644 index 000000000..bb5449816 --- /dev/null +++ b/app/models/concerns/dossier_export_concern.rb @@ -0,0 +1,124 @@ +# frozen_string_literal: true + +module DossierExportConcern + extend ActiveSupport::Concern + + def spreadsheet_columns_csv(types_de_champ:, export_template: nil) + spreadsheet_columns(with_etablissement: true, types_de_champ:, export_template:) + end + + def spreadsheet_columns_xlsx(types_de_champ:, export_template: nil) + spreadsheet_columns(types_de_champ:, export_template:) + end + + def spreadsheet_columns_ods(types_de_champ:, export_template: nil) + spreadsheet_columns(types_de_champ:, export_template:) + end + + def champ_values_for_export(types_de_champ, row_id: nil, export_template: nil) + types_de_champ.flat_map do |type_de_champ| + champ = filled_champ(type_de_champ, row_id) + if export_template.present? + columns = export_template.columns_for_stable_id(type_de_champ.stable_id) + columns.map { [_1.libelle, type_de_champ.champ_value_for_export(champ, _1.column)] } + else + type_de_champ.libelles_for_export.map do |(libelle, path)| + [libelle, type_de_champ.champ_value_for_export(champ, path)] + end + end + end + end + + def spreadsheet_columns(types_de_champ:, with_etablissement: false, export_template: nil) + dossier_values_for_export(with_etablissement:, export_template:) + champ_values_for_export(types_de_champ, export_template:) + end + + private + + def dossier_values_for_export(with_etablissement: false, export_template: nil) + if export_template.present? + return export_template.dossier_exported_columns.map { [_1.libelle, _1.column.get_value(self)] } + end + + columns = [ + ['ID', id.to_s], + ['Email', user_email_for(:display)], + ['FranceConnect ?', user_from_france_connect?] + ] + + if procedure.for_individual? + columns += [ + ['Civilité', individual&.gender], + ['Nom', individual&.nom], + ['Prénom', individual&.prenom], + ['Dépôt pour un tiers', :for_tiers], + ['Nom du mandataire', :mandataire_last_name], + ['Prénom du mandataire', :mandataire_first_name] + ] + if procedure.ask_birthday + columns += [['Date de naissance', individual&.birthdate]] + end + elsif with_etablissement + columns += [ + ['Établissement SIRET', etablissement&.siret], + ['Établissement siège social', etablissement&.siege_social], + ['Établissement NAF', etablissement&.naf], + ['Établissement libellé NAF', etablissement&.libelle_naf], + ['Établissement Adresse', etablissement&.adresse], + ['Établissement numero voie', etablissement&.numero_voie], + ['Établissement type voie', etablissement&.type_voie], + ['Établissement nom voie', etablissement&.nom_voie], + ['Établissement complément adresse', etablissement&.complement_adresse], + ['Établissement code postal', etablissement&.code_postal], + ['Établissement localité', etablissement&.localite], + ['Établissement code INSEE localité', etablissement&.code_insee_localite], + ['Entreprise SIREN', etablissement&.entreprise_siren], + ['Entreprise capital social', etablissement&.entreprise_capital_social], + ['Entreprise numero TVA intracommunautaire', etablissement&.entreprise_numero_tva_intracommunautaire], + ['Entreprise forme juridique', etablissement&.entreprise_forme_juridique], + ['Entreprise forme juridique code', etablissement&.entreprise_forme_juridique_code], + ['Entreprise nom commercial', etablissement&.entreprise_nom_commercial], + ['Entreprise raison sociale', etablissement&.entreprise_raison_sociale], + ['Entreprise SIRET siège social', etablissement&.entreprise_siret_siege_social], + ['Entreprise code effectif entreprise', etablissement&.entreprise_code_effectif_entreprise], + ['Entreprise date de création', etablissement&.entreprise_date_creation], + ['Entreprise état administratif', etablissement&.entreprise_etat_administratif], + ['Entreprise nom', etablissement&.entreprise_nom], + ['Entreprise prénom', etablissement&.entreprise_prenom], + ['Association RNA', etablissement&.association_rna], + ['Association titre', etablissement&.association_titre], + ['Association objet', etablissement&.association_objet], + ['Association date de création', etablissement&.association_date_creation], + ['Association date de déclaration', etablissement&.association_date_declaration], + ['Association date de publication', etablissement&.association_date_publication] + ] + else + columns << ['Entreprise raison sociale', etablissement&.entreprise_raison_sociale] + end + if procedure.chorusable? && procedure.chorus_configuration.complete? + columns += [ + ['Domaine Fonctionnel', procedure.chorus_configuration.domaine_fonctionnel&.fetch("code") { '' }], + ['Référentiel De Programmation', procedure.chorus_configuration.referentiel_de_programmation&.fetch("code") { '' }], + ['Centre De Coût', procedure.chorus_configuration.centre_de_cout&.fetch("code") { '' }] + ] + end + columns += [ + ['Archivé', :archived], + ['État du dossier', Dossier.human_attribute_name("state.#{state}")], + ['Dernière mise à jour le', :updated_at], + ['Dernière mise à jour du dossier le', :last_champ_updated_at], + ['Déposé le', :depose_at], + ['Passé en instruction le', :en_instruction_at], + procedure.sva_svr_enabled? ? ["Date décision #{procedure.sva_svr_configuration.human_decision}", :sva_svr_decision_on] : nil, + ['Traité le', :processed_at], + ['Motivation de la décision', :motivation], + ['Instructeurs', followers_instructeurs.map(&:email).join(' ')] + ].compact + + if procedure.routing_enabled? + columns << ['Groupe instructeur', groupe_instructeur.label] + end + + columns + end +end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index d4586e55d..3d4b9ab9b 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -13,6 +13,7 @@ class Dossier < ApplicationRecord include DossierStateConcern include DossierChampsConcern include DossierEmptyConcern + include DossierExportConcern enum state: { brouillon: 'brouillon', @@ -944,100 +945,6 @@ class Dossier < ApplicationRecord log_dossier_operation(avis.claimant, :demander_un_avis, avis) end - def spreadsheet_columns_csv(types_de_champ:) - spreadsheet_columns(with_etablissement: true, types_de_champ: types_de_champ) - end - - def spreadsheet_columns_xlsx(types_de_champ:) - spreadsheet_columns(types_de_champ: types_de_champ) - end - - def spreadsheet_columns_ods(types_de_champ:) - spreadsheet_columns(types_de_champ: types_de_champ) - end - - def spreadsheet_columns(with_etablissement: false, types_de_champ:) - columns = [ - ['ID', id.to_s], - ['Email', user_email_for(:display)], - ['FranceConnect ?', user_from_france_connect?] - ] - - if procedure.for_individual? - columns += [ - ['Civilité', individual&.gender], - ['Nom', individual&.nom], - ['Prénom', individual&.prenom], - ['Dépôt pour un tiers', :for_tiers], - ['Nom du mandataire', :mandataire_last_name], - ['Prénom du mandataire', :mandataire_first_name] - ] - if procedure.ask_birthday - columns += [['Date de naissance', individual&.birthdate]] - end - elsif with_etablissement - columns += [ - ['Établissement SIRET', etablissement&.siret], - ['Établissement siège social', etablissement&.siege_social], - ['Établissement NAF', etablissement&.naf], - ['Établissement libellé NAF', etablissement&.libelle_naf], - ['Établissement Adresse', etablissement&.adresse], - ['Établissement numero voie', etablissement&.numero_voie], - ['Établissement type voie', etablissement&.type_voie], - ['Établissement nom voie', etablissement&.nom_voie], - ['Établissement complément adresse', etablissement&.complement_adresse], - ['Établissement code postal', etablissement&.code_postal], - ['Établissement localité', etablissement&.localite], - ['Établissement code INSEE localité', etablissement&.code_insee_localite], - ['Entreprise SIREN', etablissement&.entreprise_siren], - ['Entreprise capital social', etablissement&.entreprise_capital_social], - ['Entreprise numero TVA intracommunautaire', etablissement&.entreprise_numero_tva_intracommunautaire], - ['Entreprise forme juridique', etablissement&.entreprise_forme_juridique], - ['Entreprise forme juridique code', etablissement&.entreprise_forme_juridique_code], - ['Entreprise nom commercial', etablissement&.entreprise_nom_commercial], - ['Entreprise raison sociale', etablissement&.entreprise_raison_sociale], - ['Entreprise SIRET siège social', etablissement&.entreprise_siret_siege_social], - ['Entreprise code effectif entreprise', etablissement&.entreprise_code_effectif_entreprise], - ['Entreprise date de création', etablissement&.entreprise_date_creation], - ['Entreprise état administratif', etablissement&.entreprise_etat_administratif], - ['Entreprise nom', etablissement&.entreprise_nom], - ['Entreprise prénom', etablissement&.entreprise_prenom], - ['Association RNA', etablissement&.association_rna], - ['Association titre', etablissement&.association_titre], - ['Association objet', etablissement&.association_objet], - ['Association date de création', etablissement&.association_date_creation], - ['Association date de déclaration', etablissement&.association_date_declaration], - ['Association date de publication', etablissement&.association_date_publication] - ] - else - columns << ['Entreprise raison sociale', etablissement&.entreprise_raison_sociale] - end - if procedure.chorusable? && procedure.chorus_configuration.complete? - columns += [ - ['Domaine Fonctionnel', procedure.chorus_configuration.domaine_fonctionnel&.fetch("code") { '' }], - ['Référentiel De Programmation', procedure.chorus_configuration.referentiel_de_programmation&.fetch("code") { '' }], - ['Centre De Coût', procedure.chorus_configuration.centre_de_cout&.fetch("code") { '' }] - ] - end - columns += [ - ['Archivé', :archived], - ['État du dossier', Dossier.human_attribute_name("state.#{state}")], - ['Dernière mise à jour le', :updated_at], - ['Dernière mise à jour du dossier le', :last_champ_updated_at], - ['Déposé le', :depose_at], - ['Passé en instruction le', :en_instruction_at], - procedure.sva_svr_enabled? ? ["Date décision #{procedure.sva_svr_configuration.human_decision}", :sva_svr_decision_on] : nil, - ['Traité le', :processed_at], - ['Motivation de la décision', :motivation], - ['Instructeurs', followers_instructeurs.map(&:email).join(' ')] - ].compact - - if procedure.routing_enabled? - columns << ['Groupe instructeur', groupe_instructeur.label] - end - columns + champs_for_export(types_de_champ) - end - def linked_dossiers_for(instructeur_or_expert) dossier_ids = filled_champs.filter(&:dossier_link?).filter_map(&:value) instructeur_or_expert.dossiers.where(id: dossier_ids) diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index 729f23955..0403ac864 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -24,7 +24,6 @@ class TypeDeChamp < ApplicationRecord TYPE_DE_CHAMP_TO_CATEGORIE = { engagement_juridique: REFERENTIEL_EXTERNE, - header_section: STRUCTURE, repetition: STRUCTURE, dossier_link: STRUCTURE, diff --git a/spec/models/concerns/dossier_champs_concern_spec.rb b/spec/models/concerns/dossier_champs_concern_spec.rb index 6b864f28a..1cafd67f7 100644 --- a/spec/models/concerns/dossier_champs_concern_spec.rb +++ b/spec/models/concerns/dossier_champs_concern_spec.rb @@ -183,8 +183,8 @@ RSpec.describe DossierChampsConcern do it { row_id; subject; expect(row_id).not_to be_in(row_ids) } end - describe "#champs_for_export" do - subject { dossier.champs_for_export(dossier.revision.types_de_champ_public) } + describe "#champ_values_for_export" do + subject { dossier.champ_values_for_export(dossier.revision.types_de_champ_public) } it { expect(subject.size).to eq(4) } it { expect(subject.first).to eq(["Un champ text", nil]) } diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index 320fe595e..76e2160dd 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -1982,7 +1982,7 @@ describe Dossier, type: :model do end end - describe "champs_for_export" do + describe "champ_values_for_export" do context 'with integer_number' do let(:procedure) { create(:procedure, :published, types_de_champ_public: [{ type: :integer_number, libelle: 'c1' }]) } let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } @@ -1993,7 +1993,7 @@ describe Dossier, type: :model do expect { integer_number_type_de_champ.update(type_champ: :decimal_number) procedure.update(published_revision: procedure.draft_revision, draft_revision: procedure.create_new_revision) - }.to change { dossier.reload.champs_for_export(procedure.all_revisions_types_de_champ.not_repetition.to_a) } + }.to change { dossier.reload.champ_values_for_export(procedure.all_revisions_types_de_champ.not_repetition.to_a) } .from([["c1", 42]]).to([["c1", 42.0]]) end end @@ -2020,8 +2020,8 @@ describe Dossier, type: :model do let(:repetition_second_revision_champ) { dossier_second_revision.project_champs_public.find(&:repetition?) } let(:dossier) { create(:dossier, procedure: procedure) } let(:dossier_second_revision) { create(:dossier, procedure: procedure) } - let(:dossier_champs_for_export) { dossier.champs_for_export(procedure.types_de_champ_for_procedure_export) } - let(:dossier_second_revision_champs_for_export) { dossier_second_revision.champs_for_export(procedure.types_de_champ_for_procedure_export) } + let(:dossier_champ_values_for_export) { dossier.champ_values_for_export(procedure.types_de_champ_for_procedure_export) } + let(:dossier_second_revision_champ_values_for_export) { dossier_second_revision.champ_values_for_export(procedure.types_de_champ_for_procedure_export) } context "when procedure published" do before do @@ -2040,8 +2040,8 @@ describe Dossier, type: :model do it "should have champs from all revisions" do expect(dossier.types_de_champ.map(&:libelle)).to eq([text_type_de_champ.libelle, datetime_type_de_champ.libelle, "Yes/no", explication_type_de_champ.libelle, commune_type_de_champ.libelle, repetition_type_de_champ.libelle]) expect(dossier_second_revision.types_de_champ.map(&:libelle)).to eq([datetime_type_de_champ.libelle, "Updated yes/no", explication_type_de_champ.libelle, 'Commune de naissance', "Repetition", "New text field"]) - expect(dossier_champs_for_export.map { |(libelle)| libelle }).to eq([datetime_type_de_champ.libelle, text_type_de_champ.libelle, "Updated yes/no", "Commune de naissance", "Commune de naissance (Code INSEE)", "Commune de naissance (Département)", "New text field"]) - expect(dossier_champs_for_export).to eq(dossier_second_revision_champs_for_export) + expect(dossier_champ_values_for_export.map { |(libelle)| libelle }).to eq([datetime_type_de_champ.libelle, text_type_de_champ.libelle, "Updated yes/no", "Commune de naissance", "Commune de naissance (Code INSEE)", "Commune de naissance (Département)", "New text field"]) + expect(dossier_champ_values_for_export).to eq(dossier_second_revision_champ_values_for_export) end context 'within a repetition having a type de champs commune (multiple values for export)' do @@ -2056,7 +2056,7 @@ describe Dossier, type: :model do dossier_test = create(:dossier, procedure: proc_test) type_champs = proc_test.all_revisions_types_de_champ(parent: tdc_repetition).to_a expect(type_champs.size).to eq(1) - expect(dossier.champs_for_export(type_champs).size).to eq(3) + expect(dossier.champ_values_for_export(type_champs).size).to eq(3) end end end @@ -2065,7 +2065,7 @@ describe Dossier, type: :model do let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :text }, { type: :explication }]) } it "should not contain non-exportable types de champ" do - expect(dossier_champs_for_export.map { |(libelle)| libelle }).to eq([text_type_de_champ.libelle]) + expect(dossier_champ_values_for_export.map { |(libelle)| libelle }).to eq([text_type_de_champ.libelle]) end end end @@ -2079,7 +2079,7 @@ describe Dossier, type: :model do let(:text_tdc) { procedure.active_revision.types_de_champ_public.second } let(:tdcs) { dossier.project_champs_public.map(&:type_de_champ) } - subject { dossier.champs_for_export(tdcs) } + subject { dossier.champ_values_for_export(tdcs) } before do text_tdc.update(condition: ds_eq(champ_value(yes_no_tdc.stable_id), constant(true))) diff --git a/spec/models/types_de_champ/commune_type_de_champ_spec.rb b/spec/models/types_de_champ/commune_type_de_champ_spec.rb index 18db0b2b5..ccc66bacb 100644 --- a/spec/models/types_de_champ/commune_type_de_champ_spec.rb +++ b/spec/models/types_de_champ/commune_type_de_champ_spec.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true describe TypesDeChamp::CommuneTypeDeChamp do - let(:subject) { create(:type_de_champ_communes, libelle: 'Ma commune') } - - it { expect(subject.libelles_for_export).to match_array([['Ma commune', :value], ['Ma commune (Code INSEE)', :code], ['Ma commune (Département)', :departement]]) } + let(:tdc_commune) { create(:type_de_champ_communes, libelle: 'Ma commune') } + it { expect(tdc_commune.libelles_for_export).to match_array([['Ma commune', :value], ['Ma commune (Code INSEE)', :code], ['Ma commune (Département)', :departement]]) } end