Merge branch 'dev'

This commit is contained in:
gregoirenovel 2018-10-16 13:29:00 +02:00
commit ccb6fd63af
63 changed files with 612 additions and 126 deletions

View file

@ -2,7 +2,8 @@ module TypeDeChampHelper
TOGGLES = {
TypeDeChamp.type_champs.fetch(:piece_justificative) => :champ_pj?,
TypeDeChamp.type_champs.fetch(:siret) => :champ_siret?,
TypeDeChamp.type_champs.fetch(:linked_drop_down_list) => :champ_linked_dropdown?
TypeDeChamp.type_champs.fetch(:linked_drop_down_list) => :champ_linked_dropdown?,
TypeDeChamp.type_champs.fetch(:carte) => :champ_carte?
}
def tdc_options

View file

@ -21,4 +21,21 @@ class DossierMailer < ApplicationMailer
mail(to: dossier.user.email, subject: subject)
end
def notify_undelete_to_user(dossier)
@dossier = dossier
@dossier_kind = dossier.brouillon? ? 'brouillon' : 'dossier'
@subject = "Votre #{@dossier_kind} #{@dossier.id} est à nouveau accessible"
mail(to: dossier.user.email, subject: @subject)
end
def notify_unmigrated_to_user(dossier, new_procedure)
@dossier = dossier
@dossier_kind = dossier.brouillon? ? 'brouillon' : 'dossier'
@subject = "Changement de procédure pour votre #{@dossier_kind} #{@dossier.id}"
@new_procedure = new_procedure
mail(to: dossier.user.email, subject: @subject)
end
end

View file

@ -0,0 +1,29 @@
class Champs::CarteChamp < Champ
has_many :geo_areas, dependent: :destroy
# We are not using scopes here as we want to access
# the following collections on unsaved records.
def cadastres
geo_areas.select do |area|
area.source == GeoArea.sources.fetch(:cadastre)
end
end
def quartiers_prioritaires
geo_areas.select do |area|
area.source == GeoArea.sources.fetch(:quartier_prioritaire)
end
end
def position
if dossier.present?
dossier.geo_position
else
lon = "2.428462"
lat = "46.538192"
zoom = "13"
{ lon: lon, lat: lat, zoom: zoom }
end
end
end

26
app/models/geo_area.rb Normal file
View file

@ -0,0 +1,26 @@
class GeoArea < ApplicationRecord
belongs_to :champ
store :properties, accessors: [
:surface_intersection,
:surface_parcelle,
:numero,
:feuille,
:section,
:code_dep,
:nom_com,
:code_com,
:code_arr,
:code,
:nom,
:commune
]
enum source: {
quartier_prioritaire: 'quartier_prioritaire',
cadastre: 'cadastre'
}
scope :quartiers_prioritaires, -> { where(source: sources.fetch(:quartier_prioritaire)) }
scope :cadastres, -> { where(source: sources.fetch(:cadastre)) }
end

View file

@ -25,11 +25,14 @@ class TypeDeChamp < ApplicationRecord
explication: 'explication',
dossier_link: 'dossier_link',
piece_justificative: 'piece_justificative',
siret: 'siret'
siret: 'siret',
carte: 'carte'
}
belongs_to :procedure
store :options, accessors: [:cadastres, :quartiers_prioritaires]
after_initialize :set_dynamic_type
attr_reader :dynamic_type

View file

@ -0,0 +1,2 @@
class TypesDeChamp::CarteTypeDeChamp < TypesDeChamp::TypeDeChampBase
end

View file

@ -0,0 +1,15 @@
- content_for(:title, @subject)
%h1 Bonjour,
%p
En raison dun incident, votre
= link_to("#{@dossier_kind} n° #{@dossier.id}", dossier_url(@dossier))
sur la procédure «&nbsp;#{@dossier.procedure.libelle}&nbsp;» a été inaccessible pendant quelques jours.
Laccès est à présent à nouveau possible. Nous vous présentons nos excuses pour toute gène occasionnée.
%p
Bonne journée,
%p
L'équipe demarches-simplifiees.fr

View file

@ -0,0 +1,26 @@
- content_for(:title, @subject)
%h1 Bonjour,
%p
Vous avez commencé un #{@dossier_kind},
= link_to("n° #{@dossier.id}", dossier_url(@dossier))
sur la procédure «&nbsp;#{@dossier.procedure.libelle}&nbsp;».
En raison dun changement dans la procédure, votre #{@dossier_kind} a été inaccessible pendant quelques jours.
Laccès est à présent à nouveau possible.
%p
Malheureusement, en raison des changements dans le procédure, vous ne pourrez pas mener à terme le #{@dossier_kind} commencé.
Si votre démarche est toujours dactualité, nous vous invitons à la recommencer sur
= link_to("la nouvelle procédure", commencer_url(@new_procedure.path))
\.
%p
Nous avons pris des mesures pour nous assurer quun tel désagrément ne se reproduise pas,
et vous présentons nos excuses pour la gène occasionnée.
%p
Bonne journée,
%p
L'équipe demarches-simplifiees.fr

View file

@ -13,6 +13,8 @@ Flipflop.configure do
title: "Champ SIRET"
feature :champ_linked_dropdown,
title: "Champ double menu déroulant"
feature :champ_carte,
title: "Champ Carte"
end
feature :web_hook

View file

@ -0,0 +1,14 @@
class CreateGeoAreas < ActiveRecord::Migration[5.2]
def change
create_table :geo_areas do |t|
t.string :source, index: true
t.jsonb :geometry
t.jsonb :properties
t.references :champ, foreign_key: true, index: true
end
add_column :types_de_champ, :options, :jsonb
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2018_10_10_070424) do
ActiveRecord::Schema.define(version: 2018_10_10_183331) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -342,6 +342,15 @@ ActiveRecord::Schema.define(version: 2018_10_10_070424) do
t.index ["user_id"], name: "index_france_connect_informations_on_user_id"
end
create_table "geo_areas", force: :cascade do |t|
t.string "source"
t.jsonb "geometry"
t.jsonb "properties"
t.bigint "champ_id"
t.index ["champ_id"], name: "index_geo_areas_on_champ_id"
t.index ["source"], name: "index_geo_areas_on_source"
end
create_table "gestionnaires", id: :serial, force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
@ -544,6 +553,7 @@ ActiveRecord::Schema.define(version: 2018_10_10_070424) do
t.boolean "private", default: false, null: false
t.datetime "created_at"
t.datetime "updated_at"
t.jsonb "options"
t.index ["private"], name: "index_types_de_champ_on_private"
end
@ -608,6 +618,7 @@ ActiveRecord::Schema.define(version: 2018_10_10_070424) do
add_foreign_key "commentaires", "dossiers"
add_foreign_key "dossiers", "users"
add_foreign_key "feedbacks", "users"
add_foreign_key "geo_areas", "champs"
add_foreign_key "initiated_mails", "procedures"
add_foreign_key "procedure_paths", "administrateurs"
add_foreign_key "procedure_paths", "procedures"

View file

@ -9,12 +9,7 @@ namespace :'2018_07_31_nutriscore' do
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
def setup_mapping
siret_order_place = 2
fonction_order_place = 9
zone_geographique_header_order_place = 18
@ -100,7 +95,7 @@ namespace :'2018_07_31_nutriscore' do
target_tdc.champ.create(dossier: d, value: JSON.unparse(['FRANCE']))
end
end
end.new(source_procedure, destination_procedure)
end
Tasks::DossierProcedureMigrator.new(source_procedure, destination_procedure, mapping).migrate_procedure
AutoReceiveDossiersForProcedureJob.set(cron: "* * * * *").perform_later(destination_procedure_id, 'accepte')

View file

@ -0,0 +1,209 @@
require Rails.root.join("lib", "tasks", "task_helper")
namespace :after_party do
desc 'Deployment task: restore_deleted_dossiers'
task restore_deleted_dossiers: :environment do
Class.new do
def run
rake_puts "Running deploy task 'restore_deleted_dossiers'"
restore_candidats_libres_deleted_dossiers
restore_neph_deleted_dossiers
AfterParty::TaskRecord.create version: '20181009130216'
end
def restore_candidats_libres_deleted_dossiers
mapping = Class.new(Tasks::DossierProcedureMigrator::ChampMapping) do
def setup_mapping
champ_opts = {
16 => {
source_overrides: { 'libelle' => 'Adresse postale du candidat' },
destination_overrides: { 'libelle' => 'Adresse postale complète du candidat' }
}
}
(0..23).each do |i|
map_source_to_destination_champ(i, i, **(champ_opts[i] || {}))
end
end
end
private_mapping = Class.new(Tasks::DossierProcedureMigrator::ChampMapping) do
def setup_mapping
compute_destination_champ(
TypeDeChamp.new(
type_champ: 'datetime',
order_place: 0,
libelle: 'Date et heure de convocation',
mandatory: false
)
) do |d, target_tdc|
target_tdc.champ.create(dossier: d)
end
compute_destination_champ(
TypeDeChamp.new(
type_champ: 'text',
order_place: 1,
libelle: 'Lieu de convocation',
mandatory: false
)
) do |d, target_tdc|
target_tdc.champ.create(dossier: d)
end
compute_destination_champ(
TypeDeChamp.new(
type_champ: 'address',
order_place: 2,
libelle: 'Adresse centre examen',
mandatory: false
)
) do |d, target_tdc|
target_tdc.champ.create(dossier: d)
end
end
end
pj_mapping = Class.new(Tasks::DossierProcedureMigrator::PieceJustificativeMapping) do
def setup_mapping
(0..3).each do |i|
map_source_to_destination_pj(i, i + 2)
end
leave_destination_pj_blank(
TypeDePieceJustificative.new(
order_place: 0,
libelle: "Télécharger la Charte de l'accompagnateur"
)
)
leave_destination_pj_blank(
TypeDePieceJustificative.new(
order_place: 1,
libelle: "Télécharger l'attestation d'assurance"
)
)
end
end
restore_deleted_dossiers(4860, 8603, mapping, private_mapping, pj_mapping)
end
def restore_neph_deleted_dossiers
mapping = Class.new(Tasks::DossierProcedureMigrator::ChampMapping) do
def can_migrate?(dossier)
!(dossier.termine? ||
dossier.champs.joins(:type_de_champ).find_by(types_de_champ: { order_place: 3 }).value&.include?('"Demande de duplicata de dossier d\'inscription (suite perte)"'))
end
def setup_mapping
champ_opts = {
3 => {
source_overrides: { 'drop_down' => ["", "Demande de réactualisation du numéro NEPH", "Demande de communication du numéro NEPH", "Demande de duplicata de dossier d'inscription (suite perte)", "Demande de correction sur le Fichier National des Permis de conduire"] },
destination_overrides: { 'drop_down' => ["", "Demande de réactualisation du numéro NEPH", "Demande de communication du numéro NEPH", "Demande de correction sur le Fichier National des Permis de conduire"] }
}
}
(0..14).each do |i|
map_source_to_destination_champ(i, i, **(champ_opts[i] || {}))
end
(16..22).each do |i|
map_source_to_destination_champ(i, i + 2, **(champ_opts[i] || {}))
end
discard_source_champ(
TypeDeChamp.new(
type_champ: 'address',
order_place: 15,
libelle: 'Adresse du candidat'
)
)
compute_destination_champ(
TypeDeChamp.new(
type_champ: 'address',
order_place: 15,
libelle: 'Adresse du candidat',
mandatory: true
)
) do |d, target_tdc|
value = d.champs.joins(:type_de_champ).find_by(types_de_champ: { order_place: 3 }).value
if !d.brouillon?
value ||= 'non renseigné'
end
target_tdc.champ.create(dossier: d, value: value)
end
compute_destination_champ(
TypeDeChamp.new(
type_champ: 'address',
order_place: 16,
libelle: 'Code postal',
mandatory: true
)
) do |d, target_tdc|
target_tdc.champ.create(dossier: d, value: d.brouillon? ? nil : 'non renseigné')
end
compute_destination_champ(
TypeDeChamp.new(
type_champ: 'address',
order_place: 17,
libelle: 'Ville',
mandatory: true
)
) do |d, target_tdc|
target_tdc.champ.create(dossier: d, value: d.brouillon? ? nil : 'non renseigné')
end
end
end
private_mapping = Class.new(Tasks::DossierProcedureMigrator::ChampMapping) do
def setup_mapping
(0..2).each do |i|
map_source_to_destination_champ(i, i)
end
end
end
pj_mapping = Class.new(Tasks::DossierProcedureMigrator::PieceJustificativeMapping) do
def setup_mapping
(0..3).each do |i|
map_source_to_destination_pj(i, i)
end
end
end
restore_deleted_dossiers(6388, 8770, mapping, private_mapping, pj_mapping)
end
def restore_deleted_dossiers(deleted_procedure_id, new_procedure_id, champ_mapping, champ_private_mapping, pj_mapping)
source_procedure = Procedure.unscoped.find(deleted_procedure_id)
destination_procedure = Procedure.find(new_procedure_id)
deleted_dossiers = Dossier.unscoped
.where(procedure_id: deleted_procedure_id)
.where('dossiers.hidden_at >= ?', source_procedure.hidden_at)
deleted_dossier_ids = deleted_dossiers.pluck(:id).to_a
deleted_dossiers.update_all(hidden_at: nil)
source_procedure
.update_columns(
hidden_at: nil,
archived_at: source_procedure.hidden_at,
aasm_state: :archivee
)
migrator = Tasks::DossierProcedureMigrator.new(source_procedure, destination_procedure, champ_mapping, champ_private_mapping, pj_mapping) do |dossier|
DossierMailer.notify_undelete_to_user(dossier).deliver_later
end
migrator.check_consistency
migrator.migrate_dossiers
source_procedure.dossiers.where(id: deleted_dossier_ids).find_each do |dossier|
if dossier.termine?
DossierMailer.notify_undelete_to_user(dossier).deliver_later
else
rake_puts "Dossier #{dossier.id} non migré\n"
DossierMailer.notify_unmigrated_to_user(dossier, destination_procedure).deliver_later
end
end
end
end.new.run
end
end

View file

@ -3,18 +3,54 @@ module Tasks
# 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)
def initialize(source_procedure, destination_procedure, is_private)
@source_procedure = source_procedure
@destination_procedure = destination_procedure
@is_private = is_private
@expected_source_types_de_champ = {}
@expected_destination_types_de_champ = {}
@source_to_destination_mapping = {}
@source_champs_to_discard = Set[]
@destination_champ_computations = []
setup_mapping
end
def check_source_destination_consistency
check_champs_consistency("#{privacy_label}source", @expected_source_types_de_champ, types_de_champ(@source_procedure))
check_champs_consistency("#{privacy_label}destination", @expected_destination_types_de_champ, types_de_champ(@destination_procedure))
end
def can_migrate?(dossier)
true
end
def migrate(dossier)
# Since were 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 = champs(dossier).to_a
compute_new_champs(dossier)
original_champs.each do |c|
tdc_to = destination_type_de_champ(c)
if tdc_to.present?
c.update_columns(type_de_champ_id: tdc_to.id)
elsif discard_champ?(c)
champs(dossier).destroy(c)
else
fail "Unhandled source #{privacy_label}type de champ #{c.type_de_champ.order_place}"
end
end
end
private
def compute_new_champs(dossier)
@destination_champ_computations.each do |tdc, block|
champs(dossier) << block.call(dossier, tdc)
end
end
def destination_type_de_champ(champ)
@ -25,21 +61,55 @@ module Tasks
@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)
def setup_mapping
end
def champs(dossier)
@is_private ? dossier.champs_private : dossier.champs
end
def types_de_champ(procedure)
@is_private ? procedure.types_de_champ_private : procedure.types_de_champ
end
def privacy_label
@is_private ? 'private ' : ''
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_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
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)
destination_type_de_champ = types_de_champ(@destination_procedure).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))
type_de_champ_to_expectation(types_de_champ(@source_procedure).find_by(order_place: source_order_place))
.merge!({ "mandatory" => false }) # Even if the source was mandatory, its ok for the destination to be optional
.merge!(destination_overrides)
@source_to_destination_mapping[source_order_place] = destination_type_de_champ
@ -52,7 +122,7 @@ module Tasks
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]
@destination_champ_computations << [types_de_champ(@destination_procedure).find_by(order_place: destination_type_de_champ.order_place), block]
end
def type_de_champ_to_expectation(tdc)
@ -66,10 +136,113 @@ module Tasks
end
end
def initialize(source_procedure, destination_procedure, champ_mapping)
class PieceJustificativeMapping
def initialize(source_procedure, destination_procedure)
@source_procedure = source_procedure
@destination_procedure = destination_procedure
@expected_source_pj = {}
@expected_destination_pj = {}
@source_to_destination_mapping = {}
setup_mapping
end
def check_source_destination_consistency
check_pjs_consistency('source', @expected_source_pj, @source_procedure.types_de_piece_justificative)
check_pjs_consistency('destination', @expected_destination_pj, @destination_procedure.types_de_piece_justificative)
end
def can_migrate?(dossier)
true
end
def migrate(dossier)
# Since were going to iterate and change the pjs at the same time,
# we use to_a to make the list static and avoid nasty surprises
original_pjs = dossier.pieces_justificatives.to_a
original_pjs.each do |pj|
pj_to = destination_pj(pj)
if pj_to.present?
pj.update_columns(type_de_piece_justificative_id: pj_to.id)
elsif discard_pj?(pj)
dossier.pieces_justificatives.destroy(pj)
else
fail "Unhandled source pièce justificative #{c.type_de_piece_justificative.order_place}"
end
end
end
private
def destination_pj(pj)
@source_to_destination_mapping[pj.order_place]
end
def discard_pj?(champ)
@source_pjs_to_discard.member?(pj.order_place)
end
def setup_mapping
end
def map_source_to_destination_pj(source_order_place, destination_order_place, source_overrides: {}, destination_overrides: {})
destination_pj = @destination_procedure.types_de_piece_justificative.find_by(order_place: destination_order_place)
@expected_source_pj[source_order_place] =
pj_to_expectation(destination_pj)
.merge!(source_overrides)
@expected_destination_pj[destination_order_place] =
pj_to_expectation(@source_procedure.types_de_piece_justificative.find_by(order_place: source_order_place))
.merge!({ "mandatory" => false }) # Even if the source was mandatory, its ok for the destination to be optional
.merge!(destination_overrides)
@source_to_destination_mapping[source_order_place] = destination_pj
end
def discard_source_pj(source_pj)
@expected_source_pj[source_pj.order_place] = pj_to_expectation(source_pj)
@source_pjs_to_discard << source_pj.order_place
end
def leave_destination_pj_blank(destination_pj)
@expected_destination_pj[destination_pj.order_place] = pj_to_expectation(destination_pj)
end
def pj_to_expectation(pj)
pj&.as_json(only: [:libelle, :mandatory]) || {}
end
def check_pjs_consistency(label, expected_pjs, actual_pjs)
if actual_pjs.size != expected_pjs.size
raise "Incorrect #{label} pièce justificative count #{actual_pjs.size} (expected #{expected_pjs.size})"
end
actual_pjs.each { |pj| check_pj_consistency(label, expected_pjs[pj.order_place], pj) }
end
def check_pj_consistency(label, expected_pj, actual_pj)
errors = []
if actual_pj.libelle != expected_pj['libelle']
errors.append("incorrect libelle #{actual_pj.libelle} (expected #{expected_pj['libelle']})")
end
if (!actual_pj.mandatory) && expected_pj['mandatory']
errors.append("pj should be mandatory")
end
if errors.present?
fail "On #{label} type de pièce justificative #{actual_pj.order_place} (#{actual_pj.libelle}) " + errors.join(', ')
end
end
end
def initialize(source_procedure, destination_procedure, champ_mapping, private_champ_mapping = ChampMapping, piece_justificative_mapping = PieceJustificativeMapping, &block)
@source_procedure = source_procedure
@destination_procedure = destination_procedure
@champ_mapping = champ_mapping
@champ_mapping = champ_mapping.new(source_procedure, destination_procedure, false)
@private_champ_mapping = private_champ_mapping.new(source_procedure, destination_procedure, true)
@piece_justificative_mapping = piece_justificative_mapping.new(source_procedure, destination_procedure)
if block_given?
@on_dossier_migration = block
end
end
def migrate_procedure
@ -81,7 +254,9 @@ module Tasks
def check_consistency
check_same_administrateur
check_source_destination_champs_consistency
@champ_mapping.check_source_destination_consistency
@private_champ_mapping.check_source_destination_consistency
@piece_justificative_mapping.check_source_destination_consistency
end
def check_same_administrateur
@ -90,59 +265,17 @@ module Tasks
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_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 were 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
if @champ_mapping.can_migrate?(d) && @private_champ_mapping.can_migrate?(d) && @piece_justificative_mapping.can_migrate?(d)
@champ_mapping.migrate(d)
@private_champ_mapping.migrate(d)
@piece_justificative_mapping.migrate(d)
@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
# Use update_columns to avoid triggering build_default_champs
d.update_columns(procedure_id: @destination_procedure.id)
@on_dossier_migration&.call(d)
end
# Use update_columns to avoid triggering build_default_champs
d.update_columns(procedure_id: @destination_procedure.id)
end
end

View file

@ -3,12 +3,12 @@ describe Admin::AttestationTemplatesController, type: :controller do
let!(:attestation_template) { create(:attestation_template) }
let(:admin) { create(:administrateur) }
let!(:procedure) { create :procedure, administrateur: admin, attestation_template: attestation_template }
let(:logo) { fixture_file_upload('spec/fixtures/white.png', 'image/png') }
let(:logo2) { fixture_file_upload('spec/fixtures/white.png', 'image/png') }
let(:signature) { fixture_file_upload('spec/fixtures/black.png', 'image/png') }
let(:signature2) { fixture_file_upload('spec/fixtures/black.png', 'image/png') }
let(:interlaced_logo) { fixture_file_upload('spec/fixtures/interlaced-black.png', 'image/png') }
let(:uninterlaced_logo) { fixture_file_upload('spec/fixtures/uninterlaced-black.png', 'image/png') }
let(:logo) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') }
let(:logo2) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') }
let(:signature) { fixture_file_upload('spec/fixtures/files/black.png', 'image/png') }
let(:signature2) { fixture_file_upload('spec/fixtures/files/black.png', 'image/png') }
let(:interlaced_logo) { fixture_file_upload('spec/fixtures/files/interlaced-black.png', 'image/png') }
let(:uninterlaced_logo) { fixture_file_upload('spec/fixtures/files/uninterlaced-black.png', 'image/png') }
before do
sign_in admin

View file

@ -81,7 +81,7 @@ describe NewGestionnaire::AvisController, type: :controller do
end
context "with a file" do
let(:file) { Rack::Test::UploadedFile.new("./spec/support/files/piece_justificative_0.pdf", 'application/pdf') }
let(:file) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') }
it do
subject

View file

@ -267,7 +267,7 @@ describe NewGestionnaire::DossiersController, type: :controller do
describe "#create_commentaire" do
let(:saved_commentaire) { dossier.commentaires.first }
let(:body) { "avant\napres" }
let(:file) { Rack::Test::UploadedFile.new("./spec/support/files/piece_justificative_0.pdf", 'application/pdf') }
let(:file) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') }
let(:scan_result) { true }
subject {

View file

@ -617,7 +617,7 @@ describe NewUser::DossiersController, type: :controller do
let(:dossier) { create(:dossier, :en_construction, user: user) }
let(:saved_commentaire) { dossier.commentaires.first }
let(:body) { "avant\napres" }
let(:file) { Rack::Test::UploadedFile.new("./spec/support/files/piece_justificative_0.pdf", 'application/pdf') }
let(:file) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') }
let(:scan_result) { true }
subject {

View file

@ -15,7 +15,7 @@ describe Users::DossiersController, type: :controller do
let(:user) { create :user }
let(:exercices_status) { 200 }
let(:exercices_body) { File.read('spec/support/files/api_entreprise/exercices.json') }
let(:exercices_body) { File.read('spec/fixtures/files/api_entreprise/exercices.json') }
let(:siren) { '440117620' }
let(:siret) { '44011762001530' }
@ -199,10 +199,10 @@ describe Users::DossiersController, type: :controller do
.to_return(status: 404, body: 'fake body')
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
.to_return(status: status_entreprise_call, body: File.read('spec/support/files/api_entreprise/etablissements.json'))
.to_return(status: status_entreprise_call, body: File.read('spec/fixtures/files/api_entreprise/etablissements.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(status: status_entreprise_call, body: File.read('spec/support/files/api_entreprise/entreprises.json'))
.to_return(status: status_entreprise_call, body: File.read('spec/fixtures/files/api_entreprise/entreprises.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/#{siret}?.*token=/)
.to_return(status: exercices_status, body: exercices_body)
@ -280,7 +280,7 @@ describe Users::DossiersController, type: :controller do
context 'when siren have rna informations' do
let(:rna_status) { 200 }
let(:rna_body) { File.read('spec/support/files/api_entreprise/associations.json') }
let(:rna_body) { File.read('spec/fixtures/files/api_entreprise/associations.json') }
it 'creates rna information for entreprise' do
subject

View file

@ -1,11 +1,11 @@
FactoryBot.define do
factory :piece_justificative do
trait :rib do
content { Rack::Test::UploadedFile.new("./spec/support/files/RIB.pdf", 'application/pdf') }
content { Rack::Test::UploadedFile.new("./spec/fixtures/files/RIB.pdf", 'application/pdf') }
end
trait :contrat do
content { Rack::Test::UploadedFile.new("./spec/support/files/Contrat.pdf", 'application/pdf') }
content { Rack::Test::UploadedFile.new("./spec/fixtures/files/Contrat.pdf", 'application/pdf') }
end
end
end

View file

@ -84,6 +84,9 @@ FactoryBot.define do
factory :type_de_champ_siret do
type_champ { TypeDeChamp.type_champs.fetch(:siret) }
end
factory :type_de_champ_carte do
type_champ { TypeDeChamp.type_champs.fetch(:carte) }
end
trait :private do
private { true }

View file

@ -39,7 +39,7 @@ feature 'The user' do
check('engagement')
fill_in('dossier_link', with: '123')
# do not know how to make it work...
# find('form input[type="file"]').set(Rails.root.join('spec/fixtures/white.png'))
# find('form input[type="file"]').set(Rails.root.join('spec/fixtures/files/white.png'))
click_on 'Enregistrer le brouillon'

View file

@ -31,12 +31,12 @@ feature 'user path for dossier creation' do
context 'sets siret' do
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
.to_return(body: File.read('spec/support/files/api_entreprise/etablissements.json', status: 200))
.to_return(body: File.read('spec/fixtures/files/api_entreprise/etablissements.json', status: 200))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/entreprises.json'))
.to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/entreprises.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/#{siret}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/exercices.json'))
.to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/exercices.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/associations\/#{siret}?.*token=/)
.to_return(status: 404, body: '')

View file

@ -67,11 +67,11 @@ feature 'As a User I wanna create a dossier' do
expect(page).to have_current_path(users_dossier_path(procedure_with_siret.dossiers.last.id.to_s))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/etablissements.json'))
.to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/etablissements.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/entreprises.json'))
.to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/entreprises.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/#{siret}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/exercices.json'))
.to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/exercices.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/associations\/#{siret}?.*token=/)
.to_return(status: 404, body: '')

View file

@ -27,11 +27,11 @@ feature 'user arrive on siret page' do
context 'when enter a siret', js: true do
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/etablissements.json'))
.to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/etablissements.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/entreprises.json'))
.to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/entreprises.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/#{siret}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/exercices.json'))
.to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/exercices.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/associations\/#{siret}?.*token=/)
.to_return(status: 404, body: '')

View file

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 67 B

View file

Before

Width:  |  Height:  |  Size: 214 B

After

Width:  |  Height:  |  Size: 214 B

View file

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View file

Before

Width:  |  Height:  |  Size: 165 B

After

Width:  |  Height:  |  Size: 165 B

View file

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 67 B

View file

@ -3,7 +3,7 @@ require 'spec_helper'
describe ApiAdresse::AddressAdapter do
describe '#get_suggestions' do
let(:request) { 'Paris' }
let(:response) { File.open('spec/support/files/api_adresse/search_results.json') }
let(:response) { File.open('spec/fixtures/files/api_adresse/search_results.json') }
let(:status) { 200 }
subject { described_class.new(request).get_suggestions }
@ -19,7 +19,7 @@ describe ApiAdresse::AddressAdapter do
end
context 'when address return an empty list' do
let(:response) { File.open('spec/support/files/api_adresse/search_no_results.json') }
let(:response) { File.open('spec/fixtures/files/api_adresse/search_no_results.json') }
it { expect(subject.size).to eq 0 }
it { is_expected.to be_an_instance_of Array }

View file

@ -21,7 +21,7 @@ describe ApiCarto::API do
end
context 'when request return 500' do
let(:geojson) { File.read('spec/support/files/api_carto/request_qp.json') }
let(:geojson) { File.read('spec/fixtures/files/api_carto/request_qp.json') }
let(:status) { 500 }
let(:body) { 'toto' }
@ -31,7 +31,7 @@ describe ApiCarto::API do
end
context 'when geojson exist' do
let(:geojson) { File.read('spec/support/files/api_carto/request_qp.json') }
let(:geojson) { File.read('spec/fixtures/files/api_carto/request_qp.json') }
let(:status) { 200 }
let(:body) { 'toto' }
@ -40,7 +40,7 @@ describe ApiCarto::API do
end
context 'when geojson is at format JSON' do
let(:geojson) { JSON.parse(File.read('spec/support/files/api_carto/request_qp.json')) }
let(:geojson) { JSON.parse(File.read('spec/fixtures/files/api_carto/request_qp.json')) }
it 'returns response body' do
expect(subject).to eq(body)
@ -69,7 +69,7 @@ describe ApiCarto::API do
end
context 'when geojson exist' do
let(:geojson) { File.read('spec/support/files/api_carto/request_cadastre.json') }
let(:geojson) { File.read('spec/fixtures/files/api_carto/request_cadastre.json') }
let(:status) { 200 }
let(:body) { 'toto' }
@ -78,7 +78,7 @@ describe ApiCarto::API do
end
context 'when geojson is at format JSON' do
let(:geojson) { JSON.parse(File.read('spec/support/files/api_carto/request_cadastre.json')) }
let(:geojson) { JSON.parse(File.read('spec/fixtures/files/api_carto/request_cadastre.json')) }
it 'returns response body' do
expect(subject).to eq(body)

View file

@ -13,7 +13,7 @@ describe ApiCarto::CadastreAdapter do
context 'coordinates are filled' do
let(:coordinates) { '[[2.252728, 43.27151][2.323223, 32.835332]]' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/api_carto/response_cadastre.json') }
let(:body) { File.read('spec/fixtures/files/api_carto/response_cadastre.json') }
it { expect(subject).to be_a_instance_of(Array) }
it { expect(subject.size).to eq(16) }

View file

@ -13,7 +13,7 @@ describe ApiCarto::QuartiersPrioritairesAdapter do
context 'coordinates are filled' do
let(:coordinates) { '[[2.252728, 43.27151][2.323223, 32.835332]]' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/api_carto/response_qp.json') }
let(:body) { File.read('spec/fixtures/files/api_carto/response_qp.json') }
it { expect(subject).to be_a_instance_of(Array) }

View file

@ -20,7 +20,7 @@ describe ApiEntreprise::API do
context 'when siret exist' do
let(:siren) { '418166096' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/api_entreprise/entreprises.json') }
let(:body) { File.read('spec/fixtures/files/api_entreprise/entreprises.json') }
it 'returns response body' do
expect(subject).to eq(JSON.parse(body, symbolize_names: true))
@ -48,7 +48,7 @@ describe ApiEntreprise::API do
context 'when siret exists' do
let(:siret) { '41816609600051' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/api_entreprise/etablissements.json') }
let(:body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') }
it 'returns body' do
expect(subject).to eq(JSON.parse(body, symbolize_names: true))
@ -79,7 +79,7 @@ describe ApiEntreprise::API do
let(:siret) { '41816609600051' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/api_entreprise/exercices.json') }
let(:body) { File.read('spec/fixtures/files/api_entreprise/exercices.json') }
it 'raises RestClient::Unauthorized' do
expect(subject).to eq(JSON.parse(body, symbolize_names: true))
@ -108,7 +108,7 @@ describe ApiEntreprise::API do
context 'when siren exists' do
let(:siren) { '418166096' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/api_entreprise/associations.json') }
let(:body) { File.read('spec/fixtures/files/api_entreprise/associations.json') }
it { expect(subject).to eq(JSON.parse(body, symbolize_names: true)) }
end

View file

@ -8,7 +8,7 @@ describe ApiEntreprise::EntrepriseAdapter do
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(body: File.read('spec/support/files/api_entreprise/entreprises.json', status: 200))
.to_return(body: File.read('spec/fixtures/files/api_entreprise/entreprises.json', status: 200))
end
it '#to_params class est une Hash ?' do

View file

@ -9,7 +9,7 @@ describe ApiEntreprise::EtablissementAdapter do
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
.to_return(body: File.read('spec/support/files/api_entreprise/etablissements.json', status: 200))
.to_return(body: File.read('spec/fixtures/files/api_entreprise/etablissements.json', status: 200))
end
it '#to_params class est une Hash ?' do

View file

@ -7,7 +7,7 @@ describe ApiEntreprise::ExercicesAdapter do
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/.*token=/)
.to_return(body: File.read('spec/support/files/api_entreprise/exercices.json', status: 200))
.to_return(body: File.read('spec/fixtures/files/api_entreprise/exercices.json', status: 200))
end
it '#to_params class est un Hash ?' do

View file

@ -3,7 +3,7 @@ require 'spec_helper'
describe ApiEntreprise::RNAAdapter do
let(:siret) { '50480511000013' }
let(:procedure_id) { 22 }
let(:body) { File.read('spec/support/files/api_entreprise/associations.json') }
let(:body) { File.read('spec/fixtures/files/api_entreprise/associations.json') }
let(:status) { 200 }
let(:adapter) { described_class.new(siret, procedure_id) }

View file

@ -57,8 +57,8 @@ describe AttestationTemplate, type: :model do
describe 'dup' do
before do
@logo = File.open('spec/fixtures/white.png')
@signature = File.open('spec/fixtures/black.png')
@logo = File.open('spec/fixtures/files/white.png')
@signature = File.open('spec/fixtures/files/black.png')
end
after do
@ -113,8 +113,8 @@ describe AttestationTemplate, type: :model do
end
before do
@logo = File.open('spec/fixtures/white.png')
@signature = File.open('spec/fixtures/black.png')
@logo = File.open('spec/fixtures/files/white.png')
@signature = File.open('spec/fixtures/files/black.png')
Timecop.freeze(Time.now)
end

View file

@ -13,7 +13,7 @@ describe PieceJustificative do
subject { piece_justificative.empty? }
context 'when content exist' do
let(:content) { File.open('./spec/support/files/piece_justificative_388.pdf') }
let(:content) { File.open('./spec/fixtures/files/piece_justificative_388.pdf') }
it { is_expected.to be_falsey }
end
end

View file

@ -345,8 +345,8 @@ describe Procedure do
let(:from_library) { false }
before do
@logo = File.open('spec/fixtures/white.png')
@signature = File.open('spec/fixtures/black.png')
@logo = File.open('spec/fixtures/files/white.png')
@signature = File.open('spec/fixtures/files/black.png')
@attestation_template = create(:attestation_template, procedure: procedure, logo: @logo, signature: @signature)
@procedure = procedure.clone(procedure.administrateur, from_library)
@procedure.save

View file

@ -10,7 +10,7 @@ describe QuartierPrioritaire do
describe 'geometry' do
let(:qp) { create :quartier_prioritaire, geometry: qp_geometry }
let(:qp_geometry) { File.open('spec/support/files/qp_geometry_value.txt').read }
let(:qp_geometry) { File.open('spec/fixtures/files/qp_geometry_value.txt').read }
subject { qp.geometry }

View file

@ -32,7 +32,7 @@ describe CommentaireService do
end
context 'when it has a file' do
let(:file) { Rack::Test::UploadedFile.new("./spec/support/files/piece_justificative_0.pdf", 'application/pdf') }
let(:file) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') }
it 'saves the attached file' do
expect(commentaire.file).to be_present

View file

@ -1,7 +1,7 @@
require 'spec_helper'
describe 'admin/procedures/edit.html.haml', type: :view, vcr: { cassette_name: 'admin_procedure_edit' } do
let(:logo) { Rack::Test::UploadedFile.new("./spec/support/files/logo_test_procedure.png", 'image/png') }
let(:logo) { Rack::Test::UploadedFile.new("./spec/fixtures/files/logo_test_procedure.png", 'image/png') }
let(:procedure) { create(:procedure, logo: logo) }
before do