Merge pull request #3848 from betagouv/dev

2019-05-07-01
This commit is contained in:
Keirua 2019-05-07 16:13:32 +02:00 committed by GitHub
commit 4cedddb6d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 332 additions and 300 deletions

View file

@ -43,4 +43,12 @@
padding-left: $default-spacer * 1.5;
}
}
.optional-justificatif {
margin-bottom: 16px;
}
input[data-direct-upload-url] {
width: 100%;
}
}

View file

@ -93,16 +93,17 @@ module Gestionnaires
def terminer
motivation = params[:dossier] && params[:dossier][:motivation]
justificatif = params[:dossier] && params[:dossier][:justificatif_motivation]
case params[:process_action]
when "refuser"
dossier.refuser!(current_gestionnaire, motivation)
dossier.refuser!(current_gestionnaire, motivation, justificatif)
flash.notice = "Dossier considéré comme refusé."
when "classer_sans_suite"
dossier.classer_sans_suite!(current_gestionnaire, motivation)
dossier.classer_sans_suite!(current_gestionnaire, motivation, justificatif)
flash.notice = "Dossier considéré comme sans suite."
when "accepter"
dossier.accepter!(current_gestionnaire, motivation)
dossier.accepter!(current_gestionnaire, motivation, justificatif)
flash.notice = "Dossier traité avec succès."
end

View file

@ -0,0 +1,46 @@
module NewAdministrateur
class ProcedureAdministrateursController < AdministrateurController
before_action :retrieve_procedure
def index
end
def create
email = params.require(:administrateur)[:email]&.strip&.downcase
# Find the admin
administrateur = Administrateur.find_by(email: email)
if administrateur.nil?
flash.alert = "Ladministrateur « #{email} » nexiste pas. Invitez-le à demander un compte administrateur à laddresse <a href=#{new_demande_url}>#{new_demande_url}</a>."
return
end
# Prevent duplicates (also enforced in the database in administrateurs_procedures)
if @procedure.administrateurs.include?(administrateur)
flash.alert = "Ladministrateur « #{administrateur.email} » est déjà administrateur de « #{@procedure.libelle} »."
return
end
# Actually add the admin
@procedure.administrateurs << administrateur
@administrateur = administrateur
flash.notice = "Ladministrateur « #{administrateur.email} » a été ajouté à la démarche « #{@procedure.libelle} »."
end
def destroy
administrateur = @procedure.administrateurs.find(params[:id])
# Prevent self-removal (Also enforced in the UI)
if administrateur == current_administrateur
flash.error = "Vous ne pouvez pas vous retirer vous-même dune démarche."
end
# Actually remove the admin
@procedure.administrateurs.delete(administrateur)
@administrateur = administrateur
flash.notice = "Ladministrateur \« #{administrateur.email} » a été retiré de la démarche « #{@procedure.libelle} »."
rescue ActiveRecord::ActiveRecordError => e
flash.alert = e.message
end
end
end

View file

@ -11,3 +11,8 @@ export function motivationCancel() {
document.querySelectorAll('.motivation').forEach(hide);
show(document.querySelector('.dropdown-items'));
}
export function showImportJustificatif(name) {
show(document.querySelector('#justificatif_motivation_import_' + name));
hide(document.querySelector('#justificatif_motivation_suggest_' + name));
}

View file

@ -29,7 +29,11 @@ import '../new_design/champs/repetition';
import { toggleCondidentielExplanation } from '../new_design/avis';
import { scrollMessagerie } from '../new_design/messagerie';
import { showMotivation, motivationCancel } from '../new_design/state-button';
import {
showMotivation,
motivationCancel,
showImportJustificatif
} from '../new_design/state-button';
import { toggleChart } from '../new_design/toggle-chart';
import { replaceSemicolonByComma } from '../new_design/avis';
@ -40,6 +44,7 @@ const DS = {
scrollMessagerie,
showMotivation,
motivationCancel,
showImportJustificatif,
toggleChart,
replaceSemicolonByComma
};

View file

@ -10,8 +10,12 @@ addEventListener(INITIALIZE_EVENT, ({ target, detail: { id, file } }) => {
ProgressBar.init(target, id, file);
});
addEventListener(START_EVENT, ({ detail: { id } }) => {
addEventListener(START_EVENT, ({ target, detail: { id } }) => {
ProgressBar.start(id);
const button = target.form.querySelector('button.primary');
if (button) {
delete button.dataset.confirm;
}
});
addEventListener(PROGRESS_EVENT, ({ detail: { id, progress } }) => {

View file

@ -2,4 +2,8 @@ class Champs::PaysChamp < Champs::TextChamp
def self.pays
ApiGeo::API.pays.pluck(:nom)
end
def self.disabled_options
pays.select { |v| (v =~ /^--.*--$/).present? }
end
end

View file

@ -59,7 +59,13 @@ module TagsSubstitutionConcern
{
libelle: 'lien attestation',
description: '',
lambda: -> (d) { external_link(attestation_dossier_url(d)) },
lambda: -> (d) {
links = [external_link(attestation_dossier_url(d))]
if d.justificatif_motivation.attached?
links.push external_link("Télécharger le justificatif", url_for_justificatif_motivation(d))
end
links.join "<br />\n"
},
available_for_states: [Dossier.states.fetch(:accepte)]
}
]
@ -138,8 +144,14 @@ module TagsSubstitutionConcern
end
end
def external_link(url)
link_to(url, url, target: '_blank', rel: 'noopener')
def external_link(url, title = nil)
link_to(title || url, url, target: '_blank', rel: 'noopener')
end
def url_for_justificatif_motivation(dossier)
if dossier.justificatif_motivation.attached?
Rails.application.routes.url_helpers.url_for(dossier.justificatif_motivation)
end
end
def dossier_tags

View file

@ -20,6 +20,8 @@ class Dossier < ApplicationRecord
has_one :attestation, dependent: :destroy
has_many :pieces_justificatives, dependent: :destroy
has_one_attached :justificatif_motivation
has_many :champs, -> { root.public_only.ordered }, dependent: :destroy
has_many :champs_private, -> { root.private_only.ordered }, class_name: 'Champ', dependent: :destroy
has_many :commentaires, dependent: :destroy
@ -296,10 +298,12 @@ class Dossier < ApplicationRecord
log_dossier_operation(gestionnaire, :repasser_en_construction)
end
def accepter!(gestionnaire, motivation)
def accepter!(gestionnaire, motivation, justificatif = nil)
self.motivation = motivation
self.en_instruction_at ||= Time.zone.now
if justificatif
self.justificatif_motivation.attach(justificatif)
end
accepte!
if attestation.nil?
@ -330,20 +334,24 @@ class Dossier < ApplicationRecord
DeletedDossier.create_from_dossier(self)
end
def refuser!(gestionnaire, motivation)
def refuser!(gestionnaire, motivation, justificatif = nil)
self.motivation = motivation
self.en_instruction_at ||= Time.zone.now
if justificatif
self.justificatif_motivation.attach(justificatif)
end
refuse!
NotificationMailer.send_refused_notification(self).deliver_later
log_dossier_operation(gestionnaire, :refuser)
end
def classer_sans_suite!(gestionnaire, motivation)
def classer_sans_suite!(gestionnaire, motivation, justificatif = nil)
self.motivation = motivation
self.en_instruction_at ||= Time.zone.now
if justificatif
self.justificatif_motivation.attach(justificatif)
end
sans_suite!
NotificationMailer.send_without_continuation_notification(self).deliver_later

View file

@ -1,6 +1,8 @@
require Rails.root.join('lib', 'percentile')
class Procedure < ApplicationRecord
self.ignored_columns = [:administrateur_id]
MAX_DUREE_CONSERVATION = 36
has_many :types_de_piece_justificative, -> { ordered }, dependent: :destroy
@ -17,7 +19,7 @@ class Procedure < ApplicationRecord
has_many :assign_to, dependent: :destroy
has_many :administrateurs_procedures
has_many :administrateurs, through: :administrateurs_procedures
has_many :administrateurs, through: :administrateurs_procedures, after_remove: -> (procedure, _admin) { procedure.validate! }
has_many :gestionnaires, through: :assign_to
has_one :initiated_mail, class_name: "Mails::InitiatedMail", dependent: :destroy
@ -57,6 +59,7 @@ class Procedure < ApplicationRecord
validates :libelle, presence: true, allow_blank: false, allow_nil: false
validates :description, presence: true, allow_blank: false, allow_nil: false
validates :administrateurs, presence: true
validate :check_juridique
validates :path, format: { with: /\A[a-z0-9_\-]{3,50}\z/ }, uniqueness: { scope: :aasm_state, case_sensitive: false }, presence: true, allow_blank: false, allow_nil: true
# FIXME: remove duree_conservation_required flag once all procedures are converted to the new style

View file

@ -22,6 +22,7 @@ class DossierSerializer < ActiveModel::Serializer
has_many :champs_private
has_many :pieces_justificatives
has_many :types_de_piece_justificative
has_one :justificatif_motivation
has_many :champs, serializer: ChampSerializer
@ -52,6 +53,12 @@ class DossierSerializer < ActiveModel::Serializer
PiecesJustificativesService.serialize_champs_as_pjs(object)
end
def justificatif_motivation
if object.justificatif_motivation.attached?
Rails.application.routes.url_helpers.url_for(object.justificatif_motivation)
end
end
def types_de_piece_justificative
ActiveModelSerializers::SerializableResource.new(object.types_de_piece_justificative).serializable_hash +
PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object)

View file

@ -60,6 +60,7 @@
- if dossier.motivation.present?
%h4 Motivation
%p.dossier-motivation= dossier.motivation
= render partial: 'new_user/dossiers/show/download_justificatif', locals: { dossier: dossier }
- if dossier.attestation.present?
%h4 Attestation

View file

@ -28,6 +28,10 @@
%li= unspecified_annotations_privee.libelle
- else
= text_area :dossier, :motivation, class: 'motivation-text-area', placeholder: placeholder, required: true
.optional-justificatif{ id: "justificatif_motivation_suggest_#{popup_class}", onclick: "DS.showImportJustificatif('#{popup_class}');" }
.button Ajouter un justificatif (optionnel)
.hidden{ id: "justificatif_motivation_import_#{popup_class}" }
= file_field :dossier, :justificatif_motivation, direct_upload: true
.text-right
- if title == 'Accepter' && dossier.procedure.attestation_template&.activated?
= link_to "Voir l'attestation", apercu_attestation_gestionnaire_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener', class: 'button', title: "Voir l'attestation qui sera envoyée au demandeur"

View file

@ -19,7 +19,7 @@
= stylesheet_link_tag 'new_design/new_application', media: 'all', 'data-turbolinks-track': 'reload'
= stylesheet_link_tag 'new_design/print', media: 'print', 'data-turbolinks-track': 'reload'
= Gon::Base.render_data(camel_case: true, init: true)
= Gon::Base.render_data(camel_case: true, init: true, nonce: request.content_security_policy_nonce)
- if Rails.env.development?
= stylesheet_link_tag :xray

View file

@ -27,6 +27,10 @@
- if @procedure.missing_steps.include?(:service)
%p.missing-steps (à compléter)
%a#onglet-administrateurs{ href: url_for(procedure_administrateurs_path(@procedure)) }
.procedure-list-element{ class: ('active' if active == 'Administrateurs') }
Administrateurs
%a#onglet-instructeurs{ href: url_for(admin_procedure_instructeurs_path(@procedure)) }
.procedure-list-element{ class: ('active' if active == 'Instructeurs') }
Instructeurs

View file

@ -0,0 +1,13 @@
%tr{ id: "procedure-#{@procedure.id}-administrateur-#{administrateur.id}" }
%td= administrateur.email
%td= administrateur.created_at.strftime('%d/%m/%Y %H:%M')
%td= administrateur.registration_state
%td
- if administrateur == current_administrateur
Cest vous !
- else
= link_to 'Retirer',
[@procedure, administrateur],
method: :delete,
'data-confirm': "Retirer « #{administrateur.email} » des administrateurs de « #{@procedure.libelle} » ?",
remote: true

View file

@ -0,0 +1,6 @@
= render_flash(sticky: true)
- if @administrateur
= append_to_element("#procedure-#{@procedure.id}-administrateurs",
partial: 'administrateur',
locals: { administrateur: @administrateur })
document.getElementById('procedure-#{@procedure.id}-new_administrateur').reset()

View file

@ -0,0 +1,4 @@
= render_flash(sticky: true)
- if @administrateur
= remove_element("#procedure-#{@procedure.id}-administrateur-#{@administrateur.id}")

View file

@ -0,0 +1,26 @@
= render partial: 'new_administrateur/breadcrumbs',
locals: { steps: [link_to('Démarches', admin_procedures_path),
link_to(@procedure.libelle, admin_procedure_path(@procedure)),
'Administrateurs'], preview: false }
.container
%h1 Administrateurs de « #{@procedure.libelle} »
%table.table
%thead
%th= 'Adresse email'
%th= 'Enregistré le'
%th= 'État'
%tbody{ id: "procedure-#{@procedure.id}-administrateurs" }
= render partial: 'administrateur', collection: @procedure.administrateurs.order(:email)
%tfoot
%tr
%th{ colspan: 4 }
= form_for @procedure.administrateurs.new,
url: { controller: 'procedure_administrateurs' },
html: { class: 'form', id: "procedure-#{@procedure.id}-new_administrateur" } ,
remote: true do |f|
= f.label :email do
Ajouter un administrateur
%span.notice= "Renseignez lemail dun administrateur déjà enregistré sur demarches-simplifiees.fr pour lui permettre de modifier « #{@procedure.libelle} »."
= f.email_field :email, placeholder: 'marie.dupont@exemple.fr', required: true
= f.submit 'Ajouter comme administrateur', class: 'button primary send'

View file

@ -0,0 +1,7 @@
- if dossier.present?
- justificatif = dossier.justificatif_motivation
- if dossier.justificatif_motivation.attached? and dossier.justificatif_motivation.virus_scanner.safe?
.action
= link_to (justificatif), target: '_blank', class: 'button primary' do
%span.icon.download
Télécharger le justificatif

View file

@ -1,7 +1,7 @@
.container
- if dossier.en_construction_at.present?
.card
= render partial: "shared/dossiers/horodatage", locals: { dossier: dossier }
= render partial: "shared/dossiers/infos_generales", locals: { dossier: dossier }
.tab-title Identité du demandeur
.card

View file

@ -1,5 +0,0 @@
%table.table.vertical.dossier-champs
%tbody
%tr
%th.libelle Déposé le :
%td= l(dossier.en_construction_at, format: '%d %B %Y')

View file

@ -0,0 +1,11 @@
%table.table.vertical.dossier-champs
%tbody
%tr
%th.libelle Déposé le :
%td= l(dossier.en_construction_at, format: '%d %B %Y')
- if dossier.justificatif_motivation.attached?
%tr
%th.libelle Justificatif :
%td
.action
= render partial: 'shared/piece_jointe/pj_link', locals: { object: dossier, pj: dossier.justificatif_motivation }

View file

@ -1,4 +1,5 @@
= form.select :value,
Champs::PaysChamp.pays,
disabled: Champs::PaysChamp.disabled_options,
include_blank: true,
required: champ.mandatory?

View file

@ -50,12 +50,15 @@
%h3 Motif de lacceptation
%blockquote= dossier.motivation
= render partial: 'new_user/dossiers/show/download_justificatif', locals: { dossier: dossier }
- if dossier.attestation.present?
.action
= link_to attestation_dossier_path(dossier), target: '_blank', rel: 'noopener', class: 'button primary' do
%span.icon.download
Télécharger lattestation
- elsif dossier.refuse?
.refuse
%p.decision
@ -68,6 +71,7 @@
%h3 Motif du refus
%blockquote= dossier.motivation
= render partial: 'new_user/dossiers/show/download_justificatif', locals: { dossier: @dossier }
.action
= link_to 'Envoyer un message à ladministration', messagerie_dossier_url(dossier, anchor: 'new_commentaire'), class: 'button'
@ -79,6 +83,8 @@
= succeed '.' do
%strong sans suite
= render partial: 'new_user/dossiers/show/download_justificatif', locals: { dossier: @dossier }
- if dossier.motivation.present?
%h3 Motif du classement sans suite
%blockquote= dossier.motivation

View file

@ -59,6 +59,9 @@ Rails.application.configure do
port: 3000
}
# Use Content-Security-Policy-Report-Only instead of Content-Security-Policy
config.content_security_policy_report_only = true
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true

View file

@ -109,5 +109,7 @@ Rails.application.configure do
host: ENV['APP_HOST']
}
config.content_security_policy_report_only = true
config.lograge.enabled = ENV['LOGRAGE_ENABLED'] == 'enabled'
end

View file

@ -45,6 +45,9 @@ Rails.application.configure do
protocol: :http
}
# Use Content-Security-Policy-Report-Only instead of Content-Security-Policy
config.content_security_policy_report_only = true
config.active_job.queue_adapter = :test
config.active_storage.service = :test

View file

@ -0,0 +1,23 @@
Rails.application.config.content_security_policy do |policy|
# En cas de non respect d'une des règles, faire un POST sur cette URL
policy.report_uri "https://e30e0ed9c14194254481124271b34a72.report-uri.com/r/d/csp/reportOnly"
# Whitelist image
policy.img_src :self, "https://*.openstreetmap.org"
# Whitelist JS: nous, sendinblue et matomo, et… miniprofiler :(
if Rails.env.development?
# https://github.com/MiniProfiler/rack-mini-profiler/issues/327
policy.script_src :self, "https://sibautomation.com", "//stats.data.gouv.fr", :unsafe_eval, :unsafe_inline
else
policy.script_src :self, "https://sibautomation.com", "//stats.data.gouv.fr"
end
# Génération d'un nonce pour les balises script inline qu'on maitrise (Gon)
Rails.application.config.content_security_policy_nonce_generator = -> _request { SecureRandom.base64(16) }
# Pour les CSS, on a beaucoup de style inline et quelques balises <style>
# c'est trop compliqué pour être rectifié immédiatement (et sans valeur ajoutée:
# c'est hardcodé dans les vues, donc pas injectable).
policy.style_src :self, :unsafe_inline
# Pour tout le reste, par défaut on accepte uniquement ce qui vient de chez nous
# et dans la notification on inclue la source de l'erreur
policy.default_src :self, :data, :report_sample
end

View file

@ -374,6 +374,8 @@ Rails.application.routes.draw do
get 'annotations'
end
resources :administrateurs, controller: 'procedure_administrateurs', only: [:index, :create, :destroy]
resources :types_de_champ, only: [:create, :update, :destroy] do
member do
patch :move

View file

@ -1,32 +0,0 @@
namespace :after_party do
desc 'Deployment task: add_path_to_procedures'
task add_path_to_procedures: :environment do
puts "Running deploy task 'add_path_to_procedures'"
def print_procedure(procedure)
puts "#{procedure.id}##{procedure.path} - #{procedure.errors.full_messages}"
end
puts "Démarches publiées :"
Procedure.publiees.where(path: nil).find_each do |procedure|
procedure.path = procedure.path
if !procedure.save
print_procedure(procedure)
end
end
puts "Démarches archivées :"
Procedure.archivees.where(path: nil).find_each do |procedure|
if procedure.procedure_path.present?
procedure.path = procedure.path
if !procedure.save
print_procedure(procedure)
end
end
end
# Update task as completed. If you remove the line below, the task will
# run with every deploy (or every time you call after_party:run).
AfterParty::TaskRecord.create version: '20180913161001'
end
end

View file

@ -1,209 +0,0 @@
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

@ -1,10 +0,0 @@
namespace :after_party do
desc 'Deployment task: remove_invite_gestionnaires'
task remove_invite_gestionnaires: :environment do
InviteGestionnaire.destroy_all
# Update task as completed. If you remove the line below, the task will
# run with every deploy (or every time you call after_party:run).
AfterParty::TaskRecord.create version: '20181010102500'
end
end

View file

@ -139,7 +139,7 @@ describe API::V1::DossiersController do
let!(:dossier) { Timecop.freeze(date_creation) { create(:dossier, :with_entreprise, :en_construction, procedure: procedure, motivation: "Motivation") } }
let(:dossier_id) { dossier.id }
let(:body) { JSON.parse(retour.body, symbolize_names: true) }
let(:field_list) { [:id, :created_at, :updated_at, :archived, :individual, :entreprise, :etablissement, :cerfa, :types_de_piece_justificative, :pieces_justificatives, :champs, :champs_private, :commentaires, :state, :simplified_state, :initiated_at, :processed_at, :received_at, :motivation, :email, :instructeurs] }
let(:field_list) { [:id, :created_at, :updated_at, :archived, :individual, :entreprise, :etablissement, :cerfa, :types_de_piece_justificative, :pieces_justificatives, :champs, :champs_private, :commentaires, :state, :simplified_state, :initiated_at, :processed_at, :received_at, :motivation, :email, :instructeurs, :justificatif_motivation] }
subject { body[:dossier] }
it 'return REST code 200', :show_in_doc do

View file

@ -7,6 +7,7 @@ describe Gestionnaires::DossiersController, type: :controller do
let(:gestionnaires) { [gestionnaire] }
let(:procedure) { create(:procedure, :published, gestionnaires: gestionnaires) }
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
let(:fake_justificatif) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') }
before { sign_in(gestionnaire) }
@ -141,6 +142,7 @@ describe Gestionnaires::DossiersController, type: :controller do
sign_in gestionnaire
end
context 'simple refusal' do
subject { post :terminer, params: { process_action: "refuser", procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' }
it 'change state to refuse' do
@ -148,6 +150,7 @@ describe Gestionnaires::DossiersController, type: :controller do
dossier.reload
expect(dossier.state).to eq(Dossier.states.fetch(:refuse))
expect(dossier.justificatif_motivation).to_not be_attached
end
it 'Notification email is sent' do
@ -157,16 +160,29 @@ describe Gestionnaires::DossiersController, type: :controller do
subject
end
end
context 'refusal with a justificatif' do
subject { post :terminer, params: { process_action: "refuser", procedure_id: procedure.id, dossier_id: dossier.id, dossier: { justificatif_motivation: fake_justificatif } }, format: 'js' }
it 'attachs a justificatif' do
subject
dossier.reload
expect(dossier.state).to eq(Dossier.states.fetch(:refuse))
expect(dossier.justificatif_motivation).to be_attached
end
it { expect(subject.body).to include('.state-button') }
end
end
context "with classer_sans_suite" do
before do
dossier.en_instruction!
sign_in gestionnaire
end
context 'without attachment' do
subject { post :terminer, params: { process_action: "classer_sans_suite", procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' }
it 'change state to sans_suite' do
@ -174,6 +190,7 @@ describe Gestionnaires::DossiersController, type: :controller do
dossier.reload
expect(dossier.state).to eq(Dossier.states.fetch(:sans_suite))
expect(dossier.justificatif_motivation).to_not be_attached
end
it 'Notification email is sent' do
@ -187,6 +204,21 @@ describe Gestionnaires::DossiersController, type: :controller do
it { expect(subject.body).to include('.state-button') }
end
context 'with attachment' do
subject { post :terminer, params: { process_action: "classer_sans_suite", procedure_id: procedure.id, dossier_id: dossier.id, dossier: { justificatif_motivation: fake_justificatif } }, format: 'js' }
it 'change state to sans_suite' do
subject
dossier.reload
expect(dossier.state).to eq(Dossier.states.fetch(:sans_suite))
expect(dossier.justificatif_motivation).to be_attached
end
it { expect(subject.body).to include('.state-button') }
end
end
context "with accepter" do
before do
dossier.en_instruction!
@ -206,6 +238,7 @@ describe Gestionnaires::DossiersController, type: :controller do
dossier.reload
expect(dossier.state).to eq(Dossier.states.fetch(:accepte))
expect(dossier.justificatif_motivation).to_not be_attached
end
context 'when the dossier does not have any attestation' do
@ -261,6 +294,20 @@ describe Gestionnaires::DossiersController, type: :controller do
it { subject }
end
context 'with an attachment' do
subject { post :terminer, params: { process_action: "accepter", procedure_id: procedure.id, dossier_id: dossier.id, dossier: { justificatif_motivation: fake_justificatif } }, format: 'js' }
it 'change state to accepte' do
subject
dossier.reload
expect(dossier.state).to eq(Dossier.states.fetch(:accepte))
expect(dossier.justificatif_motivation).to be_attached
end
it { expect(subject.body).to include('.state-button') }
end
end
end

View file

@ -5,6 +5,7 @@ describe MailTemplateConcern do
let(:dossier) { create(:dossier, procedure: procedure) }
let(:dossier2) { create(:dossier, procedure: procedure) }
let(:initiated_mail) { create(:initiated_mail, procedure: procedure) }
let(:justificatif) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') }
shared_examples "can replace tokens in template" do
describe 'with no token to replace' do
@ -74,10 +75,21 @@ describe MailTemplateConcern do
mail.body = "--lien attestation--"
end
describe "in closed mail" do
describe "in closed mail without justificatif" do
let(:mail) { create(:closed_mail, procedure: procedure) }
it { is_expected.to eq("<a target=\"_blank\" rel=\"noopener\" href=\"http://localhost:3000/dossiers/#{dossier.id}/attestation\">http://localhost:3000/dossiers/#{dossier.id}/attestation</a>") }
it { is_expected.to_not include("Télécharger le justificatif") }
end
describe "in closed mail with justificatif" do
before do
dossier.justificatif_motivation.attach(justificatif)
end
let(:mail) { create(:closed_mail, procedure: procedure) }
it { is_expected.to eq("<a target=\"_blank\" rel=\"noopener\" href=\"http://localhost:3000/dossiers/#{dossier.id}/attestation\">http://localhost:3000/dossiers/#{dossier.id}/attestation</a>") }
it { expect(dossier.justificatif_motivation).to be_attached }
it { is_expected.to include("<a target=\"_blank\" rel=\"noopener\" href=\"http://localhost:3000/dossiers/#{dossier.id}/attestation\">http://localhost:3000/dossiers/#{dossier.id}/attestation</a>") }
it { is_expected.to include("Télécharger le justificatif") }
end
describe "in refuse mail" do
@ -85,6 +97,12 @@ describe MailTemplateConcern do
it { is_expected.to eq("--lien attestation--") }
end
describe "in without continuation mail" do
let(:mail) { create(:without_continuation_mail, procedure: procedure) }
it { is_expected.to eq("--lien attestation--") }
end
end
end

View file

@ -168,6 +168,10 @@ describe Procedure do
it { is_expected.to allow_value('URRSAF').for(:organisation) }
end
context 'administrateurs' do
it { is_expected.not_to allow_value([]).for(:administrateurs) }
end
context 'juridique' do
it { is_expected.not_to allow_value(nil).for(:cadre_juridique) }
it { is_expected.to allow_value('text').for(:cadre_juridique) }