Merge pull request #3991 from tchak/cleanup-old-export

Supprimer le code du vieux export de xls (15/11/2019)
This commit is contained in:
Paul Chavard 2019-11-21 10:50:03 +01:00 committed by GitHub
commit 6f2779a312
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 363 additions and 916 deletions

View file

@ -185,21 +185,19 @@ module Instructeurs
end end
def download_dossiers def download_dossiers
options = params.permit(:version, :limit, :since, tables: [])
dossiers = current_instructeur.dossiers.for_procedure(procedure) dossiers = current_instructeur.dossiers.for_procedure(procedure)
respond_to do |format| respond_to do |format|
format.csv do format.csv do
send_data(procedure.to_csv(dossiers, options), send_data(procedure.to_csv(dossiers),
filename: procedure.export_filename(:csv)) filename: procedure.export_filename(:csv))
end end
format.xlsx do format.xlsx do
send_data(procedure.to_xlsx(dossiers, options), send_data(procedure.to_xlsx(dossiers),
filename: procedure.export_filename(:xlsx)) filename: procedure.export_filename(:xlsx))
end end
format.ods do format.ods do
send_data(procedure.to_ods(dossiers, options), send_data(procedure.to_ods(dossiers),
filename: procedure.export_filename(:ods)) filename: procedure.export_filename(:ods))
end end
end end

View file

@ -38,13 +38,6 @@ module ProcedureHelper
} }
end end
def procedure_dossiers_download_path(procedure, format:, version:)
download_dossiers_instructeur_procedure_path(format: format,
procedure_id: procedure.id,
tables: [:etablissements],
version: version)
end
private private
TOGGLES = { TOGGLES = {

View file

@ -193,7 +193,7 @@ class Procedure < ApplicationRecord
end end
def prepare_export_download(format) def prepare_export_download(format)
service = ProcedureExportV2Service.new(self, self.dossiers) service = ProcedureExportService.new(self, self.dossiers)
filename = export_filename(format) filename = export_filename(format)
case format.to_sym case format.to_sym
@ -440,26 +440,20 @@ class Procedure < ApplicationRecord
"dossiers_#{procedure_identifier}_#{Time.zone.now.strftime('%Y-%m-%d_%H-%M')}.#{format}" "dossiers_#{procedure_identifier}_#{Time.zone.now.strftime('%Y-%m-%d_%H-%M')}.#{format}"
end end
def export(dossiers, options = {}) def export(dossiers)
version = options.delete(:version) ProcedureExportService.new(self, dossiers)
if version == 'v2'
options.delete(:tables)
ProcedureExportV2Service.new(self, dossiers)
else
ProcedureExportService.new(self, dossiers, **options.to_h.symbolize_keys)
end
end end
def to_csv(dossiers, options = {}) def to_csv(dossiers)
export(dossiers, options).to_csv export(dossiers).to_csv
end end
def to_xlsx(dossiers, options = {}) def to_xlsx(dossiers)
export(dossiers, options).to_xlsx export(dossiers).to_xlsx
end end
def to_ods(dossiers, options = {}) def to_ods(dossiers)
export(dossiers, options).to_ods export(dossiers).to_ods
end end
def procedure_overview(start_date) def procedure_overview(start_date)

View file

@ -1,238 +1,76 @@
class ProcedureExportService class ProcedureExportService
include DossierHelper attr_reader :dossiers
ATTRIBUTES = [ def initialize(procedure, dossiers)
:id,
:created_at,
:updated_at,
:archived,
:email,
:state,
:initiated_at,
:received_at,
:processed_at,
:motivation,
:emails_instructeurs,
:individual_gender,
:individual_prenom,
:individual_nom,
:individual_birthdate
]
ETABLISSEMENT_ATTRIBUTES = [
:siret,
:siege_social,
:naf,
:libelle_naf,
:adresse,
:numero_voie,
:type_voie,
:nom_voie,
:complement_adresse,
:code_postal,
:localite,
:code_insee_localite
]
ENTREPRISE_ATTRIBUTES = [
:siren,
:capital_social,
:numero_tva_intracommunautaire,
:forme_juridique,
:forme_juridique_code,
:nom_commercial,
:raison_sociale,
:siret_siege_social,
:code_effectif_entreprise,
:date_creation,
:nom,
:prenom
]
def initialize(procedure, dossiers, tables: [])
@procedure = procedure @procedure = procedure
@attributes = ATTRIBUTES.dup
if procedure.routee?
@attributes << :groupe_instructeur_label
end
@dossiers = dossiers.downloadable_sorted @dossiers = dossiers.downloadable_sorted
@dossiers = @dossiers.to_a @tables = [:dossiers, :etablissements, :avis] + champs_repetables_options
@tables = tables.map(&:to_sym)
end end
def to_csv def to_csv
SpreadsheetArchitect.to_csv(to_data(:dossiers)) SpreadsheetArchitect.to_csv(options_for(:dossiers, :csv))
end end
def to_xlsx def to_xlsx
package = SpreadsheetArchitect.to_axlsx_package(to_data(:dossiers)) # We recursively build multi page spreadsheet
@tables.reduce(nil) do |package, table|
# Next we recursively build multi page spreadsheet SpreadsheetArchitect.to_axlsx_package(options_for(table, :xlsx), package)
@tables.reduce(package) do |package, table|
SpreadsheetArchitect.to_axlsx_package(to_data(table), package)
end.to_stream.read end.to_stream.read
end end
def to_ods def to_ods
spreadsheet = SpreadsheetArchitect.to_rodf_spreadsheet(to_data(:dossiers)) # We recursively build multi page spreadsheet
@tables.reduce(nil) do |spreadsheet, table|
# Next we recursively build multi page spreadsheet SpreadsheetArchitect.to_rodf_spreadsheet(options_for(table, :ods), spreadsheet)
@tables.reduce(spreadsheet) do |spreadsheet, table|
SpreadsheetArchitect.to_rodf_spreadsheet(to_data(table), spreadsheet)
end.bytes end.bytes
end end
def to_data(table)
case table
when :dossiers
dossiers_table_data
when :etablissements
etablissements_table_data
end
end
private private
def empty_table_data(sheet_name, headers = []) def etablissements
{ @etablissements ||= dossiers.flat_map do |dossier|
sheet_name: sheet_name,
headers: headers,
data: [[]]
}
end
def dossiers_table_data
if @dossiers.any?
{
sheet_name: 'Dossiers',
headers: dossiers_headers,
data: dossiers_data
}
else
empty_table_data('Dossiers', dossiers_headers)
end
end
def etablissements_table_data
@etablissements = @dossiers.flat_map do |dossier|
[dossier.champs, dossier.champs_private] [dossier.champs, dossier.champs_private]
.flatten .flatten
.filter { |champ| champ.is_a?(Champs::SiretChamp) } .filter { |champ| champ.is_a?(Champs::SiretChamp) }
end.map(&:etablissement).compact end.map(&:etablissement).compact + dossiers.map(&:etablissement).compact
if @etablissements.any?
{
sheet_name: 'Etablissements',
headers: etablissements_headers,
data: etablissements_data
}
else
empty_table_data('Etablissements', etablissements_headers)
end
end end
def dossiers_headers def avis
headers = @attributes.map(&:to_s) + @avis ||= dossiers.flat_map(&:avis)
@procedure.types_de_champ.reject(&:exclude_from_export?).map(&:libelle) +
@procedure.types_de_champ_private.reject(&:exclude_from_export?).map(&:libelle) +
ETABLISSEMENT_ATTRIBUTES.map { |key| "etablissement.#{key}" } +
ENTREPRISE_ATTRIBUTES.map { |key| "entreprise.#{key}" }
headers.map { |header| label_for_export(header) }
end end
def dossiers_data def champs_repetables
@dossiers.map do |dossier| @champs_repetables ||= dossiers.flat_map do |dossier|
values = @attributes.map do |key| [dossier.champs, dossier.champs_private]
case key .flatten
when :email .filter { |champ| champ.is_a?(Champs::RepetitionChamp) }
dossier.user.email end.group_by(&:libelle_for_export)
when :state
dossier_legacy_state(dossier)
when :initiated_at
dossier.en_construction_at
when :received_at
dossier.en_instruction_at
when :individual_prenom
dossier.individual&.prenom
when :individual_nom
dossier.individual&.nom
when :individual_birthdate
dossier.individual&.birthdate
when :individual_gender
dossier.individual&.gender
when :emails_instructeurs
dossier.followers_instructeurs.map(&:email).join(' ')
when :groupe_instructeur_label
dossier.groupe_instructeur.label
else
dossier.read_attribute(key)
end
end end
normalize_values(values) + def champs_repetables_options
dossier.champs.reject(&:exclude_from_export?).map(&:for_export) + champs_repetables.map do |libelle, champs|
dossier.champs_private.reject(&:exclude_from_export?).map(&:for_export) +
etablissement_data(dossier.etablissement)
end
end
def etablissements_headers
headers = ["dossier_id", "libelle"] +
ETABLISSEMENT_ATTRIBUTES.map { |key| "etablissement.#{key}" } +
ENTREPRISE_ATTRIBUTES.map { |key| "entreprise.#{key}" }
headers.map { |header| label_for_export(header) }
end
def etablissements_data
@etablissements.map do |etablissement|
[ [
etablissement.champ.dossier_id, libelle,
label_for_export(etablissement.champ.libelle).to_s champs.flat_map(&:rows_for_export)
] + etablissement_data(etablissement) ]
end end
end end
def etablissement_data(etablissement) DEFAULT_STYLES = {
data = ETABLISSEMENT_ATTRIBUTES.map do |key| header_style: { background_color: "000000", color: "FFFFFF", font_size: 12, bold: true },
if etablissement.present? row_style: { background_color: nil, color: "000000", font_size: 12 }
case key }
when :adresse
etablissement.adresse&.chomp&.gsub("\r\n", ' ')&.delete("\r")
else
etablissement.read_attribute(key)
end
end
end
data += ENTREPRISE_ATTRIBUTES.map do |key|
if etablissement.present?
case key
when :date_creation
etablissement.entreprise_date_creation&.to_datetime
else
etablissement.read_attribute(:"entreprise_#{key}")
end
end
end
normalize_values(data)
end
def label_for_export(label) def options_for(table, format)
label.parameterize.underscore.to_sym case table
end when :dossiers
{ instances: dossiers.to_a, sheet_name: 'Dossiers', spreadsheet_columns: :"spreadsheet_columns_#{format}" }
def normalize_values(values) when :etablissements
values.map do |value| { instances: etablissements.to_a, sheet_name: 'Etablissements' }
case value when :avis
when TrueClass, FalseClass { instances: avis.to_a, sheet_name: 'Avis' }
value.to_s when Array
else { instances: table.last, sheet_name: table.first }
value.blank? ? nil : value.to_s end.merge(DEFAULT_STYLES)
end
end
end end
end end

View file

@ -1,76 +0,0 @@
class ProcedureExportV2Service
attr_reader :dossiers
def initialize(procedure, dossiers)
@procedure = procedure
@dossiers = dossiers.downloadable_sorted
@tables = [:dossiers, :etablissements, :avis] + champs_repetables_options
end
def to_csv
SpreadsheetArchitect.to_csv(options_for(:dossiers, :csv))
end
def to_xlsx
# We recursively build multi page spreadsheet
@tables.reduce(nil) do |package, table|
SpreadsheetArchitect.to_axlsx_package(options_for(table, :xlsx), package)
end.to_stream.read
end
def to_ods
# We recursively build multi page spreadsheet
@tables.reduce(nil) do |spreadsheet, table|
SpreadsheetArchitect.to_rodf_spreadsheet(options_for(table, :ods), spreadsheet)
end.bytes
end
private
def etablissements
@etablissements ||= dossiers.flat_map do |dossier|
[dossier.champs, dossier.champs_private]
.flatten
.filter { |champ| champ.is_a?(Champs::SiretChamp) }
end.map(&:etablissement).compact + dossiers.map(&:etablissement).compact
end
def avis
@avis ||= dossiers.flat_map(&:avis)
end
def champs_repetables
@champs_repetables ||= dossiers.flat_map do |dossier|
[dossier.champs, dossier.champs_private]
.flatten
.filter { |champ| champ.is_a?(Champs::RepetitionChamp) }
end.group_by(&:libelle_for_export)
end
def champs_repetables_options
champs_repetables.map do |libelle, champs|
[
libelle,
champs.flat_map(&:rows_for_export)
]
end
end
DEFAULT_STYLES = {
header_style: { background_color: "000000", color: "FFFFFF", font_size: 12, bold: true },
row_style: { background_color: nil, color: "000000", font_size: 12 }
}
def options_for(table, format)
case table
when :dossiers
{ instances: dossiers.to_a, sheet_name: 'Dossiers', spreadsheet_columns: :"spreadsheet_columns_#{format}" }.merge(DEFAULT_STYLES)
when :etablissements
{ instances: etablissements.to_a, sheet_name: 'Etablissements' }.merge(DEFAULT_STYLES)
when :avis
{ instances: avis.to_a, sheet_name: 'Avis' }.merge(DEFAULT_STYLES)
when Array
{ instances: table.last, sheet_name: table.first }.merge(DEFAULT_STYLES)
end
end
end

View file

@ -2,9 +2,7 @@
%span.dropdown %span.dropdown
%button.button.dropdown-button %button.button.dropdown-button
Télécharger tous les dossiers Télécharger tous les dossiers
- old_format_limit_date = Date.parse("Nov 15 2019") .dropdown-content.fade-in-down{ style: 'width: 330px' }
- export_v1_enabled = old_format_limit_date > Time.zone.today
.dropdown-content.fade-in-down{ style: !export_v1_enabled ? 'width: 330px' : '' }
%ul.dropdown-items %ul.dropdown-items
%li %li
- if procedure.xlsx_export_stale? - if procedure.xlsx_export_stale?
@ -30,12 +28,3 @@
= link_to "Exporter au format .csv", download_export_instructeur_procedure_path(procedure, export_format: :csv), remote: true = link_to "Exporter au format .csv", download_export_instructeur_procedure_path(procedure, export_format: :csv), remote: true
- else - else
= link_to "Au format .csv", url_for(procedure.csv_export_file), target: "_blank", rel: "noopener" = link_to "Au format .csv", url_for(procedure.csv_export_file), target: "_blank", rel: "noopener"
- if export_v1_enabled
- old_format_message = "(ancien format, jusquau #{old_format_limit_date.strftime('%d/%m/%Y')})"
%li
= link_to "Au format .xlsx #{old_format_message}", procedure_dossiers_download_path(procedure, format: :xlsx, version: 'v1'), target: "_blank", rel: "noopener"
%li
= link_to "Au format .ods #{old_format_message}", procedure_dossiers_download_path(procedure, format: :ods, version: 'v1'), target: "_blank", rel: "noopener"
%li
= link_to "Au format .csv #{old_format_message}", procedure_dossiers_download_path(procedure, format: :csv, version: 'v1'), target: "_blank", rel: "noopener"

View file

@ -426,7 +426,7 @@ describe Instructeurs::ProceduresController, type: :controller do
context "csv" do context "csv" do
before do before do
expect_any_instance_of(Procedure).to receive(:to_csv) expect_any_instance_of(Procedure).to receive(:to_csv)
.with(instructeur.dossiers.for_procedure(procedure), {}) .with(instructeur.dossiers.for_procedure(procedure))
get :download_dossiers, params: { procedure_id: procedure.id }, format: 'csv' get :download_dossiers, params: { procedure_id: procedure.id }, format: 'csv'
end end

View file

@ -1,13 +1,21 @@
require 'spec_helper' require 'spec_helper'
require 'csv'
describe ProcedureExportService do describe ProcedureExportService do
describe 'to_data' do describe 'to_data' do
let(:procedure) { create(:procedure, :published, :with_all_champs) } let(:procedure) { create(:procedure, :published, :for_individual, :with_all_champs) }
let(:table) { :dossiers } subject do
subject { ProcedureExportService.new(procedure, procedure.dossiers).to_data(table) } Tempfile.create do |f|
f << ProcedureExportService.new(procedure, procedure.dossiers).to_xlsx
f.rewind
SimpleXlsxReader.open(f.path)
end
end
let(:headers) { subject[:headers] } let(:dossiers_sheet) { subject.sheets.first }
let(:data) { subject[:data] } let(:etablissements_sheet) { subject.sheets.second }
let(:avis_sheet) { subject.sheets.third }
let(:repetition_sheet) { subject.sheets.fourth }
before do before do
# change one tdc place to check if the header is ordered # change one tdc place to check if the header is ordered
@ -19,269 +27,324 @@ describe ProcedureExportService do
end end
context 'dossiers' do context 'dossiers' do
let(:nominal_header) do it 'should have sheets' do
[ expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis'])
:id,
:created_at,
:updated_at,
:archived,
:email,
:state,
:initiated_at,
:received_at,
:processed_at,
:motivation,
:emails_instructeurs,
:individual_gender,
:individual_prenom,
:individual_nom,
:individual_birthdate,
:textarea,
:date,
:datetime,
:number,
:decimal_number,
:integer_number,
:checkbox,
:civilite,
:email,
:phone,
:address,
:yes_no,
:simple_drop_down_list,
:multiple_drop_down_list,
:linked_drop_down_list,
:pays,
:regions,
:departements,
:engagement,
:dossier_link,
:piece_justificative,
:siret,
:carte,
:text,
:etablissement_siret,
:etablissement_siege_social,
:etablissement_naf,
:etablissement_libelle_naf,
:etablissement_adresse,
:etablissement_numero_voie,
:etablissement_type_voie,
:etablissement_nom_voie,
:etablissement_complement_adresse,
:etablissement_code_postal,
:etablissement_localite,
:etablissement_code_insee_localite,
:entreprise_siren,
:entreprise_capital_social,
:entreprise_numero_tva_intracommunautaire,
:entreprise_forme_juridique,
:entreprise_forme_juridique_code,
:entreprise_nom_commercial,
:entreprise_raison_sociale,
:entreprise_siret_siege_social,
:entreprise_code_effectif_entreprise,
:entreprise_date_creation,
:entreprise_nom,
:entreprise_prenom
]
end end
it 'should have headers' do
expect(headers).to eq(nominal_header)
end
context 'with a procedure routee' do
before { procedure.groupe_instructeurs.create(label: '2') }
let(:routee_header) { nominal_header.insert(nominal_header.index(:textarea), :groupe_instructeur_label) }
it { expect(headers).to eq(routee_header) }
end
it 'should have empty values' do
expect(data).to eq([[]])
end end
context 'with dossier' do context 'with dossier' do
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) } let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) }
let(:dossier_data) { let(:nominal_headers) do
[ [
dossier.id.to_s, "ID",
dossier.created_at.to_s, "Email",
dossier.updated_at.to_s, "Civilité",
"false", "Nom",
dossier.user.email, "Prénom",
"received", "Date de naissance",
dossier.en_construction_at.to_s, "Archivé",
dossier.en_instruction_at.to_s, "État du dossier",
nil, "Dernière mise à jour le",
nil, "Déposé le",
nil "Passé en instruction le",
] + individual_data "Traité le",
} "Motivation de la décision",
"Instructeurs",
let(:individual_data) { "textarea",
[ "date",
"M.", "datetime",
"Xavier", "number",
"Julien", "decimal_number",
"1991-11-01" "integer_number",
"checkbox",
"civilite",
"email",
"phone",
"address",
"yes_no",
"simple_drop_down_list",
"multiple_drop_down_list",
"linked_drop_down_list",
"pays",
"regions",
"departements",
"engagement",
"dossier_link",
"piece_justificative",
"siret",
"carte",
"text"
] ]
} end
let(:champs_data) { it 'should have headers' do
dossier.reload.champs.reject(&:exclude_from_export?).map(&:for_export) expect(dossiers_sheet.headers).to match(nominal_headers)
} end
let(:etablissement_data) { it 'should have data' do
Array.new(24) expect(dossiers_sheet.data.size).to eq(1)
} expect(etablissements_sheet.data.size).to eq(1)
it 'should have values' do # SimpleXlsxReader is transforming datetimes in utc... It is only used in test so we just hack around.
expect(data.first[0..14]).to eq(dossier_data) offset = dossier.en_construction_at.utc_offset
expect(data.first[15..38]).to eq(champs_data) en_construction_at = Time.zone.at(dossiers_sheet.data[0][9] - offset.seconds)
expect(data.first[39..62]).to eq(etablissement_data) en_instruction_at = Time.zone.at(dossiers_sheet.data[0][10] - offset.seconds)
expect(en_construction_at).to eq(dossier.en_construction_at.round)
expect(data).to eq([ expect(en_instruction_at).to eq(dossier.en_instruction_at.round)
dossier_data + champs_data + etablissement_data
])
end end
context 'with a procedure routee' do context 'with a procedure routee' do
before { procedure.groupe_instructeurs.create(label: '2') } before { procedure.groupe_instructeurs.create(label: '2') }
it { expect(data.first[15]).to eq('défaut') } let(:routee_header) { nominal_headers.insert(nominal_headers.index('textarea'), 'Groupe instructeur') }
it { expect(data.first.count).to eq(dossier_data.count + champs_data.count + etablissement_data.count + 1) }
it { expect(dossiers_sheet.headers).to match(routee_header) }
it { expect(dossiers_sheet.data[0][dossiers_sheet.headers.index('Groupe instructeur')]).to eq('défaut') }
end
end end
context 'and etablissement' do context 'with etablissement' do
let(:procedure) { create(:procedure, :published, :with_all_champs) }
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :with_entreprise, procedure: procedure) } let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :with_entreprise, procedure: procedure) }
let(:etablissement_data) { let(:dossier_etablissement) { etablissements_sheet.data[1] }
let(:champ_etablissement) { etablissements_sheet.data[0] }
let(:nominal_headers) do
[ [
dossier.etablissement.siret, "ID",
dossier.etablissement.siege_social.to_s, "Email",
dossier.etablissement.naf, "Entreprise raison sociale",
dossier.etablissement.libelle_naf, "Archivé",
dossier.etablissement.adresse&.chomp&.gsub("\r\n", ' ')&.delete("\r"), "État du dossier",
dossier.etablissement.numero_voie, "Dernière mise à jour le",
dossier.etablissement.type_voie, "Déposé le",
dossier.etablissement.nom_voie, "Passé en instruction le",
dossier.etablissement.complement_adresse, "Traité le",
dossier.etablissement.code_postal, "Motivation de la décision",
dossier.etablissement.localite, "Instructeurs",
dossier.etablissement.code_insee_localite, "textarea",
dossier.etablissement.entreprise_siren, "date",
dossier.etablissement.entreprise_capital_social.to_s, "datetime",
dossier.etablissement.entreprise_numero_tva_intracommunautaire, "number",
dossier.etablissement.entreprise_forme_juridique, "decimal_number",
dossier.etablissement.entreprise_forme_juridique_code, "integer_number",
dossier.etablissement.entreprise_nom_commercial, "checkbox",
dossier.etablissement.entreprise_raison_sociale, "civilite",
dossier.etablissement.entreprise_siret_siege_social, "email",
dossier.etablissement.entreprise_code_effectif_entreprise, "phone",
dossier.etablissement.entreprise_date_creation.to_datetime.to_s, "address",
dossier.etablissement.entreprise_nom, "yes_no",
dossier.etablissement.entreprise_prenom "simple_drop_down_list",
"multiple_drop_down_list",
"linked_drop_down_list",
"pays",
"regions",
"departements",
"engagement",
"dossier_link",
"piece_justificative",
"siret",
"carte",
"text"
] ]
}
let(:individual_data) {
Array.new(4)
}
it 'should have values' do
expect(data.first[0..14]).to eq(dossier_data)
expect(data.first[15..38]).to eq(champs_data)
expect(data.first[39..62]).to eq(etablissement_data)
expect(data).to eq([
dossier_data + champs_data + etablissement_data
])
end
end end
context 'as csv' do
subject do
Tempfile.create do |f|
f << ProcedureExportService.new(procedure, procedure.dossiers).to_csv
f.rewind
CSV.read(f.path)
end end
end end
context 'etablissements' do let(:nominal_headers) do
let(:table) { :etablissements } [
"ID",
"Email",
"Établissement SIRET",
"Établissement siège social",
"Établissement NAF",
"Établissement libellé NAF",
"Établissement Adresse",
"Établissement numero voie",
"Établissement type voie",
"Établissement nom voie",
"Établissement complément adresse",
"Établissement code postal",
"Établissement localité",
"Établissement code INSEE localité",
"Entreprise SIREN",
"Entreprise capital social",
"Entreprise numero TVA intracommunautaire",
"Entreprise forme juridique",
"Entreprise forme juridique code",
"Entreprise nom commercial",
"Entreprise raison sociale",
"Entreprise SIRET siège social",
"Entreprise code effectif entreprise",
"Entreprise date de création",
"Entreprise nom",
"Entreprise prénom",
"Association RNA",
"Association titre",
"Association objet",
"Association date de création",
"Association date de déclaration",
"Association date de publication",
"Archivé",
"État du dossier",
"Dernière mise à jour le",
"Déposé le",
"Passé en instruction le",
"Traité le",
"Motivation de la décision",
"Instructeurs",
"textarea",
"date",
"datetime",
"number",
"decimal_number",
"integer_number",
"checkbox",
"civilite",
"email",
"phone",
"address",
"yes_no",
"simple_drop_down_list",
"multiple_drop_down_list",
"linked_drop_down_list",
"pays",
"regions",
"departements",
"engagement",
"dossier_link",
"piece_justificative",
"siret",
"carte",
"text"
]
end
let(:dossiers_sheet_headers) { subject.first }
it 'should have headers' do it 'should have headers' do
expect(headers).to eq([ expect(dossiers_sheet_headers).to match(nominal_headers)
:dossier_id, end
:libelle, end
:etablissement_siret,
:etablissement_siege_social, it 'should have headers' do
:etablissement_naf, expect(dossiers_sheet.headers).to match(nominal_headers)
:etablissement_libelle_naf,
:etablissement_adresse, expect(etablissements_sheet.headers).to eq([
:etablissement_numero_voie, "Dossier ID",
:etablissement_type_voie, "Champ",
:etablissement_nom_voie, "Établissement SIRET",
:etablissement_complement_adresse, "Établissement siège social",
:etablissement_code_postal, "Établissement NAF",
:etablissement_localite, "Établissement libellé NAF",
:etablissement_code_insee_localite, "Établissement Adresse",
:entreprise_siren, "Établissement numero voie",
:entreprise_capital_social, "Établissement type voie",
:entreprise_numero_tva_intracommunautaire, "Établissement nom voie",
:entreprise_forme_juridique, "Établissement complément adresse",
:entreprise_forme_juridique_code, "Établissement code postal",
:entreprise_nom_commercial, "Établissement localité",
:entreprise_raison_sociale, "Établissement code INSEE localité",
:entreprise_siret_siege_social, "Entreprise SIREN",
:entreprise_code_effectif_entreprise, "Entreprise capital social",
:entreprise_date_creation, "Entreprise numero TVA intracommunautaire",
:entreprise_nom, "Entreprise forme juridique",
:entreprise_prenom "Entreprise forme juridique code",
"Entreprise nom commercial",
"Entreprise raison sociale",
"Entreprise SIRET siège social",
"Entreprise code effectif entreprise",
"Entreprise date de création",
"Entreprise nom",
"Entreprise prénom",
"Association RNA",
"Association titre",
"Association objet",
"Association date de création",
"Association date de déclaration",
"Association date de publication"
]) ])
end end
it 'should have empty values' do it 'should have data' do
expect(data).to eq([[]]) expect(etablissements_sheet.data.size).to eq(2)
expect(dossier_etablissement[1]).to eq("Dossier")
expect(champ_etablissement[1]).to eq("siret")
end
end end
context 'with dossier containing champ siret' do context 'with avis' do
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, procedure: procedure) } let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) }
let(:etablissement) { dossier.champs.find { |champ| champ.type_champ == 'siret' }.etablissement } let!(:avis) { create(:avis, :with_answer, dossier: dossier) }
let(:etablissement_data) { it 'should have headers' do
expect(avis_sheet.headers).to eq([
"Dossier ID",
"Question / Introduction",
"Réponse",
"Créé le",
"Répondu le"
])
end
it 'should have data' do
expect(avis_sheet.data.size).to eq(1)
end
end
context 'with repetitions' do
let!(:dossiers) do
[ [
dossier.id, create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure),
'siret', create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure)
etablissement.siret,
etablissement.siege_social.to_s,
etablissement.naf,
etablissement.libelle_naf,
etablissement.adresse&.chomp&.gsub("\r\n", ' ')&.delete("\r"),
etablissement.numero_voie,
etablissement.type_voie,
etablissement.nom_voie,
etablissement.complement_adresse,
etablissement.code_postal,
etablissement.localite,
etablissement.code_insee_localite,
etablissement.entreprise_siren,
etablissement.entreprise_capital_social.to_s,
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_code_effectif_entreprise,
etablissement.entreprise_date_creation.to_datetime.to_s,
etablissement.entreprise_nom,
etablissement.entreprise_prenom
] ]
} end
let(:champ_repetition) { dossiers.first.champs.find { |champ| champ.type_champ == 'repetition' } }
it 'should have values' do it 'should have sheets' do
expect(data.first).to eq(etablissement_data) expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis', champ_repetition.libelle_for_export])
end
it 'should have headers' do
expect(repetition_sheet.headers).to eq([
"Dossier ID",
"Ligne",
"Nom",
"Age"
])
end
it 'should have data' do
expect(repetition_sheet.data.size).to eq(4)
end
context 'with invalid characters' do
before do
champ_repetition.type_de_champ.update(libelle: 'A / B \ C')
end
it 'should have valid sheet name' do
expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis', "(#{champ_repetition.type_de_champ.stable_id}) A - B - C"])
end
end
context 'with non unique labels' do
let(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) }
let(:champ_repetition) { dossier.champs.find { |champ| champ.type_champ == 'repetition' } }
let(:type_de_champ_repetition) { create(:type_de_champ_repetition, procedure: procedure, libelle: champ_repetition.libelle) }
let!(:another_champ_repetition) { create(:champ_repetition, type_de_champ: type_de_champ_repetition, dossier: dossier) }
it 'should have sheets' do
expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis', champ_repetition.libelle_for_export, another_champ_repetition.libelle_for_export])
end end
end end
end end

View file

@ -1,352 +0,0 @@
require 'spec_helper'
require 'csv'
describe ProcedureExportV2Service do
describe 'to_data' do
let(:procedure) { create(:procedure, :published, :for_individual, :with_all_champs) }
subject do
Tempfile.create do |f|
f << ProcedureExportV2Service.new(procedure, procedure.dossiers).to_xlsx
f.rewind
SimpleXlsxReader.open(f.path)
end
end
let(:dossiers_sheet) { subject.sheets.first }
let(:etablissements_sheet) { subject.sheets.second }
let(:avis_sheet) { subject.sheets.third }
let(:repetition_sheet) { subject.sheets.fourth }
before do
# change one tdc place to check if the header is ordered
tdc_first = procedure.types_de_champ.first
tdc_last = procedure.types_de_champ.last
tdc_first.update(order_place: tdc_last.order_place + 1)
procedure.reload
end
context 'dossiers' do
it 'should have sheets' do
expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis'])
end
end
context 'with dossier' do
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) }
let(:nominal_headers) do
[
"ID",
"Email",
"Civilité",
"Nom",
"Prénom",
"Date de naissance",
"Archivé",
"État du dossier",
"Dernière mise à jour le",
"Déposé le",
"Passé en instruction le",
"Traité le",
"Motivation de la décision",
"Instructeurs",
"textarea",
"date",
"datetime",
"number",
"decimal_number",
"integer_number",
"checkbox",
"civilite",
"email",
"phone",
"address",
"yes_no",
"simple_drop_down_list",
"multiple_drop_down_list",
"linked_drop_down_list",
"pays",
"regions",
"departements",
"engagement",
"dossier_link",
"piece_justificative",
"siret",
"carte",
"text"
]
end
it 'should have headers' do
expect(dossiers_sheet.headers).to match(nominal_headers)
end
it 'should have data' do
expect(dossiers_sheet.data.size).to eq(1)
expect(etablissements_sheet.data.size).to eq(1)
# SimpleXlsxReader is transforming datetimes in utc... It is only used in test so we just hack around.
offset = dossier.en_construction_at.utc_offset
en_construction_at = Time.zone.at(dossiers_sheet.data[0][9] - offset.seconds)
en_instruction_at = Time.zone.at(dossiers_sheet.data[0][10] - offset.seconds)
expect(en_construction_at).to eq(dossier.en_construction_at.round)
expect(en_instruction_at).to eq(dossier.en_instruction_at.round)
end
context 'with a procedure routee' do
before { procedure.groupe_instructeurs.create(label: '2') }
let(:routee_header) { nominal_headers.insert(nominal_headers.index('textarea'), 'Groupe instructeur') }
it { expect(dossiers_sheet.headers).to match(routee_header) }
it { expect(dossiers_sheet.data[0][dossiers_sheet.headers.index('Groupe instructeur')]).to eq('défaut') }
end
end
context 'with etablissement' do
let(:procedure) { create(:procedure, :published, :with_all_champs) }
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :with_entreprise, procedure: procedure) }
let(:dossier_etablissement) { etablissements_sheet.data[1] }
let(:champ_etablissement) { etablissements_sheet.data[0] }
let(:nominal_headers) do
[
"ID",
"Email",
"Entreprise raison sociale",
"Archivé",
"État du dossier",
"Dernière mise à jour le",
"Déposé le",
"Passé en instruction le",
"Traité le",
"Motivation de la décision",
"Instructeurs",
"textarea",
"date",
"datetime",
"number",
"decimal_number",
"integer_number",
"checkbox",
"civilite",
"email",
"phone",
"address",
"yes_no",
"simple_drop_down_list",
"multiple_drop_down_list",
"linked_drop_down_list",
"pays",
"regions",
"departements",
"engagement",
"dossier_link",
"piece_justificative",
"siret",
"carte",
"text"
]
end
context 'as csv' do
subject do
Tempfile.create do |f|
f << ProcedureExportV2Service.new(procedure, procedure.dossiers).to_csv
f.rewind
CSV.read(f.path)
end
end
let(:nominal_headers) do
[
"ID",
"Email",
"Établissement SIRET",
"Établissement siège social",
"Établissement NAF",
"Établissement libellé NAF",
"Établissement Adresse",
"Établissement numero voie",
"Établissement type voie",
"Établissement nom voie",
"Établissement complément adresse",
"Établissement code postal",
"Établissement localité",
"Établissement code INSEE localité",
"Entreprise SIREN",
"Entreprise capital social",
"Entreprise numero TVA intracommunautaire",
"Entreprise forme juridique",
"Entreprise forme juridique code",
"Entreprise nom commercial",
"Entreprise raison sociale",
"Entreprise SIRET siège social",
"Entreprise code effectif entreprise",
"Entreprise date de création",
"Entreprise nom",
"Entreprise prénom",
"Association RNA",
"Association titre",
"Association objet",
"Association date de création",
"Association date de déclaration",
"Association date de publication",
"Archivé",
"État du dossier",
"Dernière mise à jour le",
"Déposé le",
"Passé en instruction le",
"Traité le",
"Motivation de la décision",
"Instructeurs",
"textarea",
"date",
"datetime",
"number",
"decimal_number",
"integer_number",
"checkbox",
"civilite",
"email",
"phone",
"address",
"yes_no",
"simple_drop_down_list",
"multiple_drop_down_list",
"linked_drop_down_list",
"pays",
"regions",
"departements",
"engagement",
"dossier_link",
"piece_justificative",
"siret",
"carte",
"text"
]
end
let(:dossiers_sheet_headers) { subject.first }
it 'should have headers' do
expect(dossiers_sheet_headers).to match(nominal_headers)
end
end
it 'should have headers' do
expect(dossiers_sheet.headers).to match(nominal_headers)
expect(etablissements_sheet.headers).to eq([
"Dossier ID",
"Champ",
"Établissement SIRET",
"Établissement siège social",
"Établissement NAF",
"Établissement libellé NAF",
"Établissement Adresse",
"Établissement numero voie",
"Établissement type voie",
"Établissement nom voie",
"Établissement complément adresse",
"Établissement code postal",
"Établissement localité",
"Établissement code INSEE localité",
"Entreprise SIREN",
"Entreprise capital social",
"Entreprise numero TVA intracommunautaire",
"Entreprise forme juridique",
"Entreprise forme juridique code",
"Entreprise nom commercial",
"Entreprise raison sociale",
"Entreprise SIRET siège social",
"Entreprise code effectif entreprise",
"Entreprise date de création",
"Entreprise nom",
"Entreprise prénom",
"Association RNA",
"Association titre",
"Association objet",
"Association date de création",
"Association date de déclaration",
"Association date de publication"
])
end
it 'should have data' do
expect(etablissements_sheet.data.size).to eq(2)
expect(dossier_etablissement[1]).to eq("Dossier")
expect(champ_etablissement[1]).to eq("siret")
end
end
context 'with avis' do
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) }
let!(:avis) { create(:avis, :with_answer, dossier: dossier) }
it 'should have headers' do
expect(avis_sheet.headers).to eq([
"Dossier ID",
"Question / Introduction",
"Réponse",
"Créé le",
"Répondu le"
])
end
it 'should have data' do
expect(avis_sheet.data.size).to eq(1)
end
end
context 'with repetitions' do
let!(:dossiers) do
[
create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure),
create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure)
]
end
let(:champ_repetition) { dossiers.first.champs.find { |champ| champ.type_champ == 'repetition' } }
it 'should have sheets' do
expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis', champ_repetition.libelle_for_export])
end
it 'should have headers' do
expect(repetition_sheet.headers).to eq([
"Dossier ID",
"Ligne",
"Nom",
"Age"
])
end
it 'should have data' do
expect(repetition_sheet.data.size).to eq(4)
end
context 'with invalid characters' do
before do
champ_repetition.type_de_champ.update(libelle: 'A / B \ C')
end
it 'should have valid sheet name' do
expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis', "(#{champ_repetition.type_de_champ.stable_id}) A - B - C"])
end
end
context 'with non unique labels' do
let(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) }
let(:champ_repetition) { dossier.champs.find { |champ| champ.type_champ == 'repetition' } }
let(:type_de_champ_repetition) { create(:type_de_champ_repetition, procedure: procedure, libelle: champ_repetition.libelle) }
let!(:another_champ_repetition) { create(:champ_repetition, type_de_champ: type_de_champ_repetition, dossier: dossier) }
it 'should have sheets' do
expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis', champ_repetition.libelle_for_export, another_champ_repetition.libelle_for_export])
end
end
end
end
end