From 580c6145d03771418bf01260fd5190e8cfaf93d7 Mon Sep 17 00:00:00 2001 From: Frederic Merizen Date: Thu, 2 Aug 2018 18:38:54 +0200 Subject: [PATCH] Migrate nutriscore dossiers from old procedure to new procedure --- lib/tasks/2018_07_31_nutriscore.rake | 108 +++++++++++++ lib/tasks/dossier_procedure_migrator.rb | 161 ++++++++++++++++++++ spec/lib/rake/2018_07_31_nutriscore_spec.rb | 126 +++++++++++++++ 3 files changed, 395 insertions(+) create mode 100644 lib/tasks/2018_07_31_nutriscore.rake create mode 100644 lib/tasks/dossier_procedure_migrator.rb create mode 100644 spec/lib/rake/2018_07_31_nutriscore_spec.rb diff --git a/lib/tasks/2018_07_31_nutriscore.rake b/lib/tasks/2018_07_31_nutriscore.rake new file mode 100644 index 000000000..4f48664d3 --- /dev/null +++ b/lib/tasks/2018_07_31_nutriscore.rake @@ -0,0 +1,108 @@ +require Rails.root.join("lib", "tasks", "task_helper") + +namespace :'2018_07_31_nutriscore' do + task migrate_dossiers: :environment do + source_procedure_id = ENV['SOURCE_PROCEDURE_ID'] || 4861 + destination_procedure_id = ENV['DESTINATION_PROCEDURE_ID'] || 7009 + + source_procedure = Procedure.find(source_procedure_id) + destination_procedure = Procedure.find(destination_procedure_id) + + mapping = Class.new(Tasks::DossierProcedureMigrator::ChampMapping) do + def initialize(source_procedure, destination_procedure) + super + setup_champ_mapping + end + + def setup_champ_mapping + siret_order_place = 2 + fonction_order_place = 9 + zone_geographique_header_order_place = 18 + pays_commercialisation_order_place = 19 + header_engagement_order_place = 20 + + champ_opts = { header_engagement_order_place => { source_overrides: { 'libelle' => 'PARTIE 3 : ENGAGEMENT DE L’EXPLOITANT' }, destination_overrides: { 'libelle' => 'PARTIE 4 : ENGAGEMENT DE L’EXPLOITANT' } } } + + pays_drop_down_values = "FRANCE\r\nACORES, MADERE\r\nAFGHANISTAN\r\nAFRIQUE DU SUD\r\nALASKA\r\nALBANIE\r\nALGERIE\r\nALLEMAGNE\r\nANDORRE\r\nANGOLA\r\nANGUILLA\r\nANTIGUA-ET-BARBUDA\r\nANTILLES NEERLANDAISES\r\nARABIE SAOUDITE\r\nARGENTINE\r\nARMENIE\r\nARUBA\r\nAUSTRALIE\r\nAUTRICHE\r\nAZERBAIDJAN\r\nBAHAMAS\r\nBAHREIN\r\nBANGLADESH\r\nBARBADE\r\nBELGIQUE\r\nBELIZE\r\nBENIN\r\nBERMUDES\r\nBHOUTAN\r\nBIELORUSSIE\r\nBIRMANIE\r\nBOLIVIE\r\nBONAIRE, SAINT EUSTACHE ET SABA\r\nBOSNIE-HERZEGOVINE\r\nBOTSWANA\r\nBOUVET (ILE)\r\nBRESIL\r\nBRUNEI\r\nBULGARIE\r\nBURKINA\r\nBURUNDI\r\nCAIMANES (ILES)\r\nCAMBODGE\r\nCAMEROUN\r\nCAMEROUN ET TOGO\r\nCANADA\r\nCANARIES (ILES)\r\nCAP-VERT\r\nCENTRAFRICAINE (REPUBLIQUE)\r\nCHILI\r\nCHINE\r\nCHRISTMAS (ILE)\r\nCHYPRE\r\nCLIPPERTON (ILE)\r\nCOCOS ou KEELING (ILES)\r\nCOLOMBIE\r\nCOMORES\r\nCONGO\r\nCONGO (REPUBLIQUE DEMOCRATIQUE)\r\nCOOK (ILES)\r\nCOREE\r\nCOREE (REPUBLIQUE DE)\r\nCOREE (REPUBLIQUE POPULAIRE DEMOCRATIQUE DE)\r\nCOSTA RICA\r\nCOTE D'IVOIRE\r\nCROATIE\r\nCUBA\r\nCURAÇAO\r\nDANEMARK\r\nDJIBOUTI\r\nDOMINICAINE (REPUBLIQUE)\r\nDOMINIQUE\r\nEGYPTE\r\nEL SALVADOR\r\nEMIRATS ARABES UNIS\r\nEQUATEUR\r\nERYTHREE\r\nESPAGNE\r\nESTONIE\r\nETATS MALAIS NON FEDERES\r\nETATS-UNIS\r\nETHIOPIE\r\nEX-REPUBLIQUE YOUGOSLAVE DE MACEDOINE\r\nFEROE (ILES)\r\nFIDJI\r\nFINLANDE\r\nGABON\r\nGAMBIE\r\nGEORGIE\r\nGEORGIE DU SUD ET LES ILES SANDWICH DU SUD\r\nGHANA\r\nGIBRALTAR\r\nGOA\r\nGRECE\r\nGRENADE\r\nGROENLAND\r\nGUADELOUPE\r\nGUAM\r\nGUATEMALA\r\nGUERNESEY\r\nGUINEE\r\nGUINEE EQUATORIALE\r\nGUINEE-BISSAU\r\nGUYANA\r\nGUYANE\r\nHAITI\r\nHAWAII (ILES)\r\nHEARD ET MACDONALD (ILES)\r\nHONDURAS\r\nHONG-KONG\r\nHONGRIE\r\nILES PORTUGAISES DE L'OCEAN INDIEN\r\nINDE\r\nINDONESIE\r\nIRAN\r\nIRAQ\r\nIRLANDE, ou EIRE\r\nISLANDE\r\nISRAEL\r\nITALIE\r\nJAMAIQUE\r\nJAPON\r\nJERSEY\r\nJORDANIE\r\nKAMTCHATKA\r\nKAZAKHSTAN\r\nKENYA\r\nKIRGHIZISTAN\r\nKIRIBATI\r\nKOSOVO\r\nKOWEIT\r\nLA REUNION\r\nLABRADOR\r\nLAOS\r\nLESOTHO\r\nLETTONIE\r\nLIBAN\r\nLIBERIA\r\nLIBYE\r\nLIECHTENSTEIN\r\nLITUANIE\r\nLUXEMBOURG\r\nMACAO\r\nMADAGASCAR\r\nMALAISIE\r\nMALAWI\r\nMALDIVES\r\nMALI\r\nMALOUINES, OU FALKLAND (ILES)\r\nMALTE\r\nMAN (ILE)\r\nMANDCHOURIE\r\nMARIANNES DU NORD (ILES)\r\nMAROC\r\nMARSHALL (ILES)\r\nMARTINIQUE\r\nMAURICE\r\nMAURITANIE\r\nMAYOTTE\r\nMEXIQUE\r\nMICRONESIE (ETATS FEDERES DE)\r\nMOLDAVIE\r\nMONACO\r\nMONGOLIE\r\nMONTENEGRO\r\nMONTSERRAT\r\nMOZAMBIQUE\r\nNAMIBIE\r\nNAURU\r\nNEPAL\r\nNICARAGUA\r\nNIGER\r\nNIGERIA\r\nNIUE\r\nNORFOLK (ILE)\r\nNORVEGE\r\nNOUVELLE-CALEDONIE\r\nNOUVELLE-ZELANDE\r\nOCEAN INDIEN (TERRITOIRE BRITANNIQUE DE L')\r\nOMAN\r\nOUGANDA\r\nOUZBEKISTAN\r\nPAKISTAN\r\nPALAOS (ILES)\r\nPALESTINE (Etat de)\r\nPANAMA\r\nPAPOUASIE-NOUVELLE-GUINEE\r\nPARAGUAY\r\nPAYS-BAS\r\nPEROU\r\nPHILIPPINES\r\nPITCAIRN (ILE)\r\nPOLOGNE\r\nPOLYNESIE FRANCAISE\r\nPORTO RICO\r\nPORTUGAL\r\nPOSSESSIONS BRITANNIQUES AU PROCHE-ORIENT\r\nPRESIDES\r\nPROVINCES ESPAGNOLES D'AFRIQUE\r\nQATAR\r\nREPUBLIQUE DEMOCRATIQUE ALLEMANDE\r\nREPUBLIQUE FEDERALE D'ALLEMAGNE\r\nROUMANIE\r\nROYAUME-UNI\r\nRUSSIE\r\nRWANDA\r\nSAHARA OCCIDENTAL\r\nSAINT-BARTHELEMY\r\nSAINT-CHRISTOPHE-ET-NIEVES\r\nSAINT-MARIN\r\nSAINT-MARTIN\r\nSAINT-MARTIN (PARTIE NEERLANDAISE)\r\nSAINT-PIERRE-ET-MIQUELON\r\nSAINT-VINCENT-ET-LES GRENADINES\r\nSAINTE HELENE, ASCENSION ET TRISTAN DA CUNHA\r\nSAINTE-LUCIE\r\nSALOMON (ILES)\r\nSAMOA AMERICAINES\r\nSAMOA OCCIDENTALES\r\nSAO TOME-ET-PRINCIPE\r\nSENEGAL\r\nSERBIE\r\nSEYCHELLES\r\nSIBERIE\r\nSIERRA LEONE\r\nSINGAPOUR\r\nSLOVAQUIE\r\nSLOVENIE\r\nSOMALIE\r\nSOUDAN\r\nSOUDAN ANGLO-EGYPTIEN, KENYA, OUGANDA\r\nSOUDAN DU SUD\r\nSRI LANKA\r\nSUEDE\r\nSUISSE\r\nSURINAME\r\nSVALBARD et ILE JAN MAYEN\r\nSWAZILAND\r\nSYRIE\r\nTADJIKISTAN\r\nTAIWAN\r\nTANGER\r\nTANZANIE\r\nTCHAD\r\nTCHECOSLOVAQUIE\r\nTCHEQUE (REPUBLIQUE)\r\nTERR. DES ETATS-UNIS D'AMERIQUE EN AMERIQUE\r\nTERR. DES ETATS-UNIS D'AMERIQUE EN OCEANIE\r\nTERR. DU ROYAUME-UNI DANS L'ATLANTIQUE SUD\r\nTERRE-NEUVE\r\nTERRES AUSTRALES FRANCAISES\r\nTERRITOIRES DU ROYAUME-UNI AUX ANTILLES\r\nTHAILANDE\r\nTIMOR ORIENTAL\r\nTOGO\r\nTOKELAU\r\nTONGA\r\nTRINITE-ET-TOBAGO\r\nTUNISIE\r\nTURKESTAN RUSSE\r\nTURKMENISTAN\r\nTURKS ET CAIQUES (ILES)\r\nTURQUIE\r\nTURQUIE D'EUROPE\r\nTUVALU\r\nUKRAINE\r\nURUGUAY\r\nVANUATU\r\nVATICAN, ou SAINT-SIEGE\r\nVENEZUELA\r\nVIERGES BRITANNIQUES (ILES)\r\nVIERGES DES ETATS-UNIS (ILES)\r\nVIET NAM\r\nVIET NAM DU NORD\r\nVIET NAM DU SUD\r\nWALLIS-ET-FUTUNA\r\nYEMEN\r\nYEMEN (REPUBLIQUE ARABE DU)\r\nYEMEN DEMOCRATIQUE\r\nZAMBIE\r\nZANZIBAR\r\nZIMBABWE" + + ((0..(zone_geographique_header_order_place - 1)).to_a - [siret_order_place, fonction_order_place]).each do |i| + map_source_to_destination_champ(i, i, **(champ_opts[i] || {})) + end + + ((pays_commercialisation_order_place + 1)..25).each do |i| + map_source_to_destination_champ(i - 2, i, **(champ_opts[i] || {})) + end + + discard_source_champ( + TypesDeChamp::TextTypeDeChamp.new( + type_champ: 'text', + order_place: siret_order_place, + libelle: 'Numéro SIRET' + ) + ) + + discard_source_champ( + TypesDeChamp::TextTypeDeChamp.new( + type_champ: 'text', + order_place: fonction_order_place, + libelle: 'Fonction' + ) + ) + + compute_destination_champ( + TypesDeChamp::TextTypeDeChamp.new( + type_champ: 'text', + order_place: fonction_order_place, + libelle: 'Fonction', + mandatory: true + ) + ) do |d, target_tdc| + c = d.champs.joins(:type_de_champ).find_by(types_de_champ: { order_place: fonction_order_place }) + + target_tdc.champ.create( + value: c&.value || 'Non renseigné', + dossier: d + ) + end + + compute_destination_champ( + TypesDeChamp::SiretTypeDeChamp.new( + type_champ: 'siret', + order_place: siret_order_place, + libelle: 'Numéro SIRET' + ) + ) do |d, target_tdc| + target_tdc.champ.create( + value: d.etablissement&.siret, + etablissement: d.etablissement, + dossier: d + ) + end + + compute_destination_champ( + TypesDeChamp::HeaderSectionTypeDeChamp.new( + type_champ: 'header_section', + order_place: 18, + libelle: 'PARTIE 3 : ZONE GEOGRAPHIQUE' + ) + ) do |d, target_tdc| + target_tdc.champ.create(dossier: d) + end + + compute_destination_champ( + TypesDeChamp::MultipleDropDownListTypeDeChamp.new( + type_champ: 'multiple_drop_down_list', + order_place: 19, + libelle: 'Pays de commercialisation', + drop_down_list: DropDownList.new(value: pays_drop_down_values) + ) + ) do |d, target_tdc| + target_tdc.champ.create(dossier: d, value: JSON.unparse(['FRANCE'])) + end + end + end.new(source_procedure, destination_procedure) + + Tasks::DossierProcedureMigrator.new(source_procedure, destination_procedure, mapping).migrate_procedure + AutoReceiveDossiersForProcedureJob.set(cron: "* * * * *").perform_later(destination_procedure_id, 'accepte') + end +end diff --git a/lib/tasks/dossier_procedure_migrator.rb b/lib/tasks/dossier_procedure_migrator.rb new file mode 100644 index 000000000..f5833b52f --- /dev/null +++ b/lib/tasks/dossier_procedure_migrator.rb @@ -0,0 +1,161 @@ +module Tasks + class DossierProcedureMigrator + # Migrates dossiers from an old source procedure to a revised destination procedure. + + class ChampMapping + attr_reader :expected_source_types_de_champ + attr_reader :expected_destination_types_de_champ + + def initialize(source_procedure, destination_procedure) + @source_procedure = source_procedure + @destination_procedure = destination_procedure + + @expected_source_types_de_champ = {} + @expected_destination_types_de_champ = {} + @source_to_destination_mapping = {} + @source_champs_to_discard = Set[] + @destination_champ_computations = [] + end + + def destination_type_de_champ(champ) + @source_to_destination_mapping[champ.type_de_champ.order_place] + end + + def discard_champ?(champ) + @source_champs_to_discard.member?(champ.type_de_champ.order_place) + end + + def compute_new_champs(dossier) + @destination_champ_computations.each do |tdc, block| + dossier.champs << block.call(dossier, tdc) + end + end + + private + + def map_source_to_destination_champ(source_order_place, destination_order_place, source_overrides: {}, destination_overrides: {}) + destination_type_de_champ = @destination_procedure.types_de_champ.find_by(order_place: destination_order_place) + @expected_source_types_de_champ[source_order_place] = + type_de_champ_to_expectation(destination_type_de_champ) + .merge!(source_overrides) + @expected_destination_types_de_champ[destination_order_place] = + type_de_champ_to_expectation(@source_procedure.types_de_champ.find_by(order_place: source_order_place)) + .merge!({ "mandatory" => false }) # Even if the source was mandatory, it’s ok for the destination to be optional + .merge!(destination_overrides) + @source_to_destination_mapping[source_order_place] = destination_type_de_champ + end + + def discard_source_champ(source_type_de_champ) + @expected_source_types_de_champ[source_type_de_champ.order_place] = type_de_champ_to_expectation(source_type_de_champ) + @source_champs_to_discard << source_type_de_champ.order_place + end + + def compute_destination_champ(destination_type_de_champ, &block) + @expected_destination_types_de_champ[destination_type_de_champ.order_place] = type_de_champ_to_expectation(destination_type_de_champ) + @destination_champ_computations << [@destination_procedure.types_de_champ.find_by(order_place: destination_type_de_champ.order_place), block] + end + + def type_de_champ_to_expectation(tdc) + if tdc.present? + expectation = tdc.as_json(only: [:libelle, :type, :type_champ, :mandatory]) + expectation['drop_down'] = tdc.drop_down_list.presence&.options&.presence + expectation + else + {} + end + end + end + + def initialize(source_procedure, destination_procedure, champ_mapping) + @source_procedure = source_procedure + @destination_procedure = destination_procedure + @champ_mapping = champ_mapping + end + + def migrate_procedure + check_consistency + migrate_dossiers + migrate_gestionnaires + publish_destination_procedure_in_place_of_source + end + + def check_consistency + check_same_administrateur + check_source_destination_champs_consistency + end + + def check_same_administrateur + if @source_procedure.administrateur != @destination_procedure.administrateur + raise "Mismatching administrateurs #{@source_procedure.administrateur&.email} → #{@destination_procedure.administrateur&.email}" + end + end + + def check_source_destination_champs_consistency + check_champs_consistency('source', @champ_mapping.expected_source_types_de_champ, @source_procedure.types_de_champ) + check_champs_consistency('destination', @champ_mapping.expected_destination_types_de_champ, @destination_procedure.types_de_champ) + end + + def check_champs_consistency(label, expected_tdcs, actual_tdcs) + if actual_tdcs.size != expected_tdcs.size + raise "Incorrect #{label} size #{actual_tdcs.size} (expected #{expected_tdcs.size})" + end + actual_tdcs.each { |tdc| check_champ_consistency(label, expected_tdcs[tdc.order_place], tdc) } + end + + def check_champ_consistency(label, expected_tdc, actual_tdc) + errors = [] + if actual_tdc.libelle != expected_tdc['libelle'] + errors.append("incorrect libelle #{actual_tdc.libelle} (expected #{expected_tdc['libelle']})") + end + if actual_tdc.type != expected_tdc['type'] + errors.append("incorrect type #{actual_tdc.type} (expected #{expected_tdc['type']})") + end + if actual_tdc.type_champ != expected_tdc['type_champ'] + errors.append("incorrect type champ #{actual_tdc.type_champ} (expected #{expected_tdc['type_champ']})") + end + if (!actual_tdc.mandatory) && expected_tdc['mandatory'] + errors.append("champ should be mandatory") + end + drop_down = actual_tdc.drop_down_list.presence&.options&.presence + if drop_down != expected_tdc['drop_down'] + errors.append("incorrect drop down list #{drop_down} (expected #{expected_tdc['drop_down']})") + end + if errors.present? + fail "On #{label} type de champ #{actual_tdc.order_place} (#{actual_tdc.libelle}) " + errors.join(', ') + end + end + + def migrate_dossiers + @source_procedure.dossiers.find_each(batch_size: 100) do |d| + # Since we’re going to iterate and change the champs at the same time, + # we use to_a to make the list static and avoid nasty surprises + original_champs = d.champs.to_a + + @champ_mapping.compute_new_champs(d) + + original_champs.each do |c| + tdc_to = @champ_mapping.destination_type_de_champ(c) + if tdc_to.present? + c.update(type_de_champ: tdc_to) + elsif @champ_mapping.discard_champ?(c) + d.champs.destroy(c) + else + fail "Unhandled source type de champ #{c.type_de_champ.order_place}" + end + end + + # Use update_columns to avoid triggering build_default_champs + d.update_columns(procedure_id: @destination_procedure.id) + end + end + + def migrate_gestionnaires + @source_procedure.gestionnaires.find_each(batch_size: 100) { |g| g.assign_to_procedure(@destination_procedure) } + end + + def publish_destination_procedure_in_place_of_source + @destination_procedure.publish!(@source_procedure.path) + @source_procedure.archive + end + end +end diff --git a/spec/lib/rake/2018_07_31_nutriscore_spec.rb b/spec/lib/rake/2018_07_31_nutriscore_spec.rb new file mode 100644 index 000000000..4fda852aa --- /dev/null +++ b/spec/lib/rake/2018_07_31_nutriscore_spec.rb @@ -0,0 +1,126 @@ +require 'spec_helper' + +describe '2018_07_31_nutriscore' do + let(:gestionnaire) { create(:gestionnaire) } + let(:proc_from) do + proc_from = create(:procedure, :published) + ((0..23).to_a - [1, 2, 9, 18]).each do |i| + proc_from.types_de_champ << create(:type_de_champ_text, order_place: i, procedure: proc_from) + end + proc_from.types_de_champ << create(:type_de_champ_text, order_place: 9, libelle: 'Fonction', procedure: proc_from) + proc_from.types_de_champ << create(:type_de_champ_header_section, order_place: 18, libelle: 'PARTIE 3 : ENGAGEMENT DE L’EXPLOITANT', procedure: proc_from) + proc_from.save + proc_from + end + let!(:type_champ_from) { create(:type_de_champ_textarea, order_place: 1, libelle: 'texte', procedure: proc_from) } + let!(:type_champ_siret_from) { create(:type_de_champ_text, order_place: 2, libelle: 'Numéro SIRET', procedure: proc_from) } + let!(:type_champ_fonction_from) {} + + let(:etablissement) { create(:etablissement) } + let!(:dossier) { create(:dossier, procedure: proc_from, etablissement: etablissement) } + + let(:proc_to) do + proc_to = create(:procedure, administrateur: proc_from.administrateur) + ((0..17).to_a - [1, 2, 9]).each do |i| + libelle = proc_from.types_de_champ.find_by(order_place: i).libelle + proc_to.types_de_champ << create(:type_de_champ_text, order_place: i, libelle: libelle, procedure: proc_to) + end + proc_to.types_de_champ << create(:type_de_champ_header_section, order_place: 18, libelle: 'PARTIE 3 : ZONE GEOGRAPHIQUE', procedure: proc_to) + proc_to.types_de_champ << create( + :type_de_champ_multiple_drop_down_list, + order_place: 19, + libelle: 'Pays de commercialisation', + drop_down_list: create(:drop_down_list, value: (Champs::PaysChamp.pays - ['----']).join("\r\n")), + procedure: proc_to + ) + proc_to.types_de_champ << create(:type_de_champ_header_section, order_place: 20, libelle: 'PARTIE 4 : ENGAGEMENT DE L’EXPLOITANT', procedure: proc_to) + (21..25).each do |i| + libelle = proc_from.types_de_champ.find_by(order_place: i - 2).libelle + proc_to.types_de_champ << create(:type_de_champ_text, order_place: i, libelle: libelle, procedure: proc_to) + end + proc_to.save + proc_to + end + let!(:type_champ_to) { create(:type_de_champ_textarea, order_place: 1, libelle: 'texte', procedure: proc_to) } + let!(:type_champ_siret_to) { create(:type_de_champ_siret, order_place: 2, libelle: 'Numéro SIRET', procedure: proc_to) } + let!(:type_champ_fonction_to) { create(:type_de_champ_text, order_place: 9, libelle: 'Fonction', mandatory: true, procedure: proc_to) } + + let(:rake_task) { Rake::Task['2018_07_31_nutriscore:migrate_dossiers'] } + + def run_task + ENV['SOURCE_PROCEDURE_ID'] = proc_from.id.to_s + ENV['DESTINATION_PROCEDURE_ID'] = proc_to.id.to_s + rake_task.invoke + dossier.reload + proc_from.reload + proc_to.reload + end + + after { rake_task.reenable } + + context 'on happy path' do + before do + gestionnaire.assign_to_procedure(proc_from) + run_task + end + + it { expect(dossier.procedure).to eq(proc_to) } + it { expect(dossier.champs.pluck(:type_de_champ_id)).to match_array(proc_to.types_de_champ.pluck(:id)) } + it { expect(dossier.champs.find_by(type_de_champ: type_champ_siret_to).value).to eq(etablissement.siret) } + it { expect(dossier.champs.find_by(type_de_champ: type_champ_siret_to).etablissement).to eq(etablissement) } + it { expect(proc_from).to be_archivee } + it { expect(proc_to).to be_publiee } + it { expect(proc_to.gestionnaires).to eq([gestionnaire]) } + end + + context 'detecting error conditions' do + context 'with administrateur mismatch' do + let(:proc_to) { create(:procedure) } + + it { expect { run_task }.to raise_exception(/^Mismatching administrateurs/) } + end + + context 'with champ count mismatch' do + before { create(:type_de_champ_textarea, order_place: 26, libelle: 'texte', procedure: proc_to) } + + it { expect { run_task }.to raise_exception('Incorrect destination size 27 (expected 26)') } + end + + context 'with champ libelle mismatch' do + let!(:type_champ_to) { create(:type_de_champ_textarea, order_place: 1, libelle: 'autre texte', procedure: proc_to) } + + it { expect { run_task }.to raise_exception(/incorrect libelle texte \(expected autre texte\)$/) } + end + + context 'with champ type mismatch' do + let!(:type_champ_to) { create(:type_de_champ_text, order_place: 1, libelle: 'texte', procedure: proc_to) } + + it { expect { run_task }.to raise_exception(/incorrect type TypesDeChamp::TextareaTypeDeChamp \(expected TypesDeChamp::TextTypeDeChamp\), incorrect type champ textarea \(expected text\)$/) } + end + + context 'with champ mandatoriness mismatch' do + let!(:type_champ_to) { create(:type_de_champ_textarea, order_place: 1, libelle: 'texte', mandatory: true, procedure: proc_to) } + + it { expect { run_task }.to raise_exception(/champ should be mandatory$/) } + end + + context 'with dropdown mismatch' do + let!(:type_champ_from) { create(:type_de_champ_drop_down_list, order_place: 1, libelle: 'dropdown', drop_down_list: create(:drop_down_list, value: 'something'), procedure: proc_from) } + let!(:type_champ_to) { create(:type_de_champ_drop_down_list, order_place: 1, libelle: 'dropdown', drop_down_list: create(:drop_down_list, value: 'something else'), procedure: proc_to) } + + it { expect { run_task }.to raise_exception(/incorrect drop down list \["", "something"\] \(expected \["", "something else"\]\)$/) } + end + + context 'with siret mismatch on source' do + let!(:type_champ_siret_from) { create(:type_de_champ_textarea, order_place: 2, libelle: 'Numéro SIRET', procedure: proc_from) } + + it { expect { run_task }.to raise_exception(/incorrect type TypesDeChamp::TextareaTypeDeChamp \(expected TypesDeChamp::TextTypeDeChamp\), incorrect type champ textarea \(expected text\)$/) } + end + + context 'with siret mismatch on destination' do + let!(:type_champ_siret_to) { create(:type_de_champ_text, order_place: 2, libelle: 'Numéro SIRET', procedure: proc_to) } + + it { expect { run_task }.to raise_exception(/incorrect type TypesDeChamp::TextTypeDeChamp \(expected TypesDeChamp::SiretTypeDeChamp\), incorrect type champ text \(expected siret\)$/) } + end + end +end