commit
811c8daacd
42 changed files with 366 additions and 157 deletions
|
@ -689,6 +689,7 @@ Rails/CreateTableWithTimestamps:
|
||||||
- db/migrate/2016*.rb
|
- db/migrate/2016*.rb
|
||||||
- db/migrate/2017*.rb
|
- db/migrate/2017*.rb
|
||||||
- db/migrate/2018*.rb
|
- db/migrate/2018*.rb
|
||||||
|
- db/migrate/20200630140356_create_traitements.rb
|
||||||
|
|
||||||
Rails/Date:
|
Rails/Date:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
20
Gemfile.lock
20
Gemfile.lock
|
@ -97,7 +97,7 @@ GEM
|
||||||
aes_key_wrap (1.0.1)
|
aes_key_wrap (1.0.1)
|
||||||
after_party (1.11.2)
|
after_party (1.11.2)
|
||||||
anchored (1.1.0)
|
anchored (1.1.0)
|
||||||
ast (2.4.0)
|
ast (2.4.1)
|
||||||
attr_required (1.0.1)
|
attr_required (1.0.1)
|
||||||
autoprefixer-rails (9.7.6)
|
autoprefixer-rails (9.7.6)
|
||||||
execjs
|
execjs
|
||||||
|
@ -342,7 +342,7 @@ GEM
|
||||||
rails-dom-testing (>= 1, < 3)
|
rails-dom-testing (>= 1, < 3)
|
||||||
railties (>= 4.2.0)
|
railties (>= 4.2.0)
|
||||||
thor (>= 0.14, < 2.0)
|
thor (>= 0.14, < 2.0)
|
||||||
json-jwt (1.11.0)
|
json-jwt (1.13.0)
|
||||||
activesupport (>= 4.2)
|
activesupport (>= 4.2)
|
||||||
aes_key_wrap
|
aes_key_wrap
|
||||||
bindata
|
bindata
|
||||||
|
@ -407,7 +407,7 @@ GEM
|
||||||
nenv (0.3.0)
|
nenv (0.3.0)
|
||||||
netrc (0.11.0)
|
netrc (0.11.0)
|
||||||
nio4r (2.5.2)
|
nio4r (2.5.2)
|
||||||
nokogiri (1.10.9)
|
nokogiri (1.10.10)
|
||||||
mini_portile2 (~> 2.4.0)
|
mini_portile2 (~> 2.4.0)
|
||||||
notiffany (0.1.3)
|
notiffany (0.1.3)
|
||||||
nenv (~> 0.1)
|
nenv (~> 0.1)
|
||||||
|
@ -442,9 +442,9 @@ GEM
|
||||||
validate_url
|
validate_url
|
||||||
webfinger (>= 1.0.1)
|
webfinger (>= 1.0.1)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
parallel (1.19.1)
|
parallel (1.19.2)
|
||||||
parser (2.7.1.0)
|
parser (2.7.1.4)
|
||||||
ast (~> 2.4.0)
|
ast (~> 2.4.1)
|
||||||
pdf-core (0.7.0)
|
pdf-core (0.7.0)
|
||||||
pg (1.2.3)
|
pg (1.2.3)
|
||||||
phonelib (0.6.43)
|
phonelib (0.6.43)
|
||||||
|
@ -475,22 +475,22 @@ GEM
|
||||||
byebug (~> 11.0)
|
byebug (~> 11.0)
|
||||||
pry (~> 0.13.0)
|
pry (~> 0.13.0)
|
||||||
public_suffix (4.0.4)
|
public_suffix (4.0.4)
|
||||||
puma (4.3.3)
|
puma (4.3.5)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
pundit (2.1.0)
|
pundit (2.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
raabro (1.1.6)
|
raabro (1.1.6)
|
||||||
rack (2.0.9)
|
rack (2.2.3)
|
||||||
rack-attack (6.2.2)
|
rack-attack (6.2.2)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rack-mini-profiler (2.0.1)
|
rack-mini-profiler (2.0.1)
|
||||||
rack (>= 1.2.0)
|
rack (>= 1.2.0)
|
||||||
rack-oauth2 (1.12.0)
|
rack-oauth2 (1.15.0)
|
||||||
activesupport
|
activesupport
|
||||||
attr_required
|
attr_required
|
||||||
httpclient
|
httpclient
|
||||||
json-jwt (>= 1.11.0)
|
json-jwt (>= 1.11.0)
|
||||||
rack (< 2.1)
|
rack (>= 2.1.0)
|
||||||
rack-protection (2.0.8.1)
|
rack-protection (2.0.8.1)
|
||||||
rack
|
rack
|
||||||
rack-proxy (0.6.5)
|
rack-proxy (0.6.5)
|
||||||
|
|
4
Procfile
4
Procfile
|
@ -1,2 +1,2 @@
|
||||||
server: bin/rails server -p 3000
|
server: RAILS_QUEUE_ADAPTER=delayed_job bin/rails server -p 3000
|
||||||
jobs: bin/delayed_job run
|
jobs: bin/rake jobs:work
|
||||||
|
|
22
README.md
22
README.md
|
@ -22,9 +22,6 @@ Vous souhaitez y apporter des changements ou des améliorations ? Lisez notre [
|
||||||
|
|
||||||
- rbenv : voir https://github.com/rbenv/rbenv-installer#rbenv-installer--doctor-scripts
|
- rbenv : voir https://github.com/rbenv/rbenv-installer#rbenv-installer--doctor-scripts
|
||||||
- Yarn : voir https://yarnpkg.com/en/docs/install
|
- Yarn : voir https://yarnpkg.com/en/docs/install
|
||||||
- Overmind :
|
|
||||||
* Mac : `brew install overmind`
|
|
||||||
* Linux : voir https://github.com/DarthSim/overmind#installation
|
|
||||||
|
|
||||||
#### Tests
|
#### Tests
|
||||||
|
|
||||||
|
@ -60,9 +57,18 @@ Afin d'initialiser l'environnement de développement, exécutez la commande suiv
|
||||||
|
|
||||||
### Lancement de l'application
|
### Lancement de l'application
|
||||||
|
|
||||||
overmind start
|
On lance le serveur d'application ainsi :
|
||||||
|
|
||||||
L'application tourne à l'adresse `http://localhost:3000`.
|
bin/rails server
|
||||||
|
|
||||||
|
L'application tourne alors à l'adresse `http://localhost:3000`, et utilise le mécanisme par défaut de rails pour les tâches asynchrones.
|
||||||
|
C'est ce qu'on veut dans la plupart des cas. Une exception: ça ne joue pas les tâches cron.
|
||||||
|
|
||||||
|
Pour être une peu plus proche du comportement de production, et jouer les tâches cron, on peut lancer la message queue
|
||||||
|
dans un service dédié, et indiquer à rails d'utiliser delayed_job:
|
||||||
|
|
||||||
|
bin/rake jobs:work
|
||||||
|
RAILS_QUEUE_ADAPTER=delayed_job bin/rails server
|
||||||
|
|
||||||
### Utilisateurs de test
|
### Utilisateurs de test
|
||||||
|
|
||||||
|
@ -107,12 +113,6 @@ Pour exécuter les tests de l'application, plusieurs possibilités :
|
||||||
|
|
||||||
rails generate after_party:task task_name
|
rails generate after_party:task task_name
|
||||||
|
|
||||||
### Debug
|
|
||||||
|
|
||||||
Une fois `overmind` lancé, et un breakpoint `byebug` inséré dans le code, il faut se connecter au process `server` dans un nouveau terminal afin d'intéragir avec byebug :
|
|
||||||
|
|
||||||
overmind connect server
|
|
||||||
|
|
||||||
### Linting
|
### Linting
|
||||||
|
|
||||||
Le projet utilise plusieurs linters pour vérifier la lisibilité et la qualité du code.
|
Le projet utilise plusieurs linters pour vérifier la lisibilité et la qualité du code.
|
||||||
|
|
|
@ -249,9 +249,11 @@ class StatsController < ApplicationController
|
||||||
min_date = 11.months.ago
|
min_date = 11.months.ago
|
||||||
max_date = Time.zone.now.to_date
|
max_date = Time.zone.now.to_date
|
||||||
|
|
||||||
processed_dossiers = dossiers
|
processed_dossiers = Traitement.includes(:dossier)
|
||||||
|
.where(dossier_id: dossiers)
|
||||||
|
.where('dossiers.state' => Dossier::TERMINE)
|
||||||
.where(:processed_at => min_date..max_date)
|
.where(:processed_at => min_date..max_date)
|
||||||
.pluck(:groupe_instructeur_id, :en_construction_at, :processed_at)
|
.pluck('dossiers.groupe_instructeur_id', 'dossiers.en_construction_at', :processed_at)
|
||||||
|
|
||||||
# Group dossiers by month
|
# Group dossiers by month
|
||||||
processed_dossiers_by_month = processed_dossiers
|
processed_dossiers_by_month = processed_dossiers
|
||||||
|
@ -290,11 +292,13 @@ class StatsController < ApplicationController
|
||||||
min_date = 11.months.ago
|
min_date = 11.months.ago
|
||||||
max_date = Time.zone.now.to_date
|
max_date = Time.zone.now.to_date
|
||||||
|
|
||||||
processed_dossiers = dossiers
|
processed_dossiers = Traitement.includes(:dossier)
|
||||||
|
.where(dossier: dossiers)
|
||||||
|
.where('dossiers.state' => Dossier::TERMINE)
|
||||||
.where(:processed_at => min_date..max_date)
|
.where(:processed_at => min_date..max_date)
|
||||||
.pluck(
|
.pluck(
|
||||||
:groupe_instructeur_id,
|
'dossiers.groupe_instructeur_id',
|
||||||
Arel.sql('EXTRACT(EPOCH FROM (en_construction_at - created_at)) / 60 AS processing_time'),
|
Arel.sql('EXTRACT(EPOCH FROM (dossiers.en_construction_at - dossiers.created_at)) / 60 AS processing_time'),
|
||||||
:processed_at
|
:processed_at
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ module Users
|
||||||
errors = update_dossier_and_compute_errors
|
errors = update_dossier_and_compute_errors
|
||||||
|
|
||||||
if passage_en_construction? && errors.blank?
|
if passage_en_construction? && errors.blank?
|
||||||
@dossier.en_construction!
|
@dossier.passer_en_construction!
|
||||||
NotificationMailer.send_initiated_notification(@dossier).deliver_later
|
NotificationMailer.send_initiated_notification(@dossier).deliver_later
|
||||||
@dossier.groupe_instructeur.instructeurs.with_instant_email_dossier_notifications.each do |instructeur|
|
@dossier.groupe_instructeur.instructeurs.with_instant_email_dossier_notifications.each do |instructeur|
|
||||||
DossierMailer.notify_new_dossier_depose_to_instructeur(@dossier, instructeur.email).deliver_later
|
DossierMailer.notify_new_dossier_depose_to_instructeur(@dossier, instructeur.email).deliver_later
|
||||||
|
|
|
@ -9,6 +9,10 @@ class ApiEntreprise::Job < ApplicationJob
|
||||||
error(self, exception)
|
error(self, exception)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def error(job, exception)
|
||||||
|
# override ApplicationJob#error to avoid reporting to sentry
|
||||||
|
end
|
||||||
|
|
||||||
def max_attempts
|
def max_attempts
|
||||||
ENV.fetch("MAX_ATTEMPTS_API_ENTREPRISE_JOBS", DEFAULT_MAX_ATTEMPTS_API_ENTREPRISE_JOBS).to_i
|
ENV.fetch("MAX_ATTEMPTS_API_ENTREPRISE_JOBS", DEFAULT_MAX_ATTEMPTS_API_ENTREPRISE_JOBS).to_i
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,6 +42,7 @@ class Dossier < ApplicationRecord
|
||||||
has_many :followers_instructeurs, through: :follows, source: :instructeur
|
has_many :followers_instructeurs, through: :follows, source: :instructeur
|
||||||
has_many :previous_followers_instructeurs, -> { distinct }, through: :previous_follows, source: :instructeur
|
has_many :previous_followers_instructeurs, -> { distinct }, through: :previous_follows, source: :instructeur
|
||||||
has_many :avis, inverse_of: :dossier, dependent: :destroy
|
has_many :avis, inverse_of: :dossier, dependent: :destroy
|
||||||
|
has_many :traitements, -> { order(:processed_at) }, inverse_of: :dossier, dependent: :destroy
|
||||||
|
|
||||||
has_many :dossier_operation_logs, -> { order(:created_at) }, dependent: :nullify, inverse_of: :dossier
|
has_many :dossier_operation_logs, -> { order(:created_at) }, dependent: :nullify, inverse_of: :dossier
|
||||||
|
|
||||||
|
@ -128,6 +129,7 @@ class Dossier < ApplicationRecord
|
||||||
:individual,
|
:individual,
|
||||||
:followers_instructeurs,
|
:followers_instructeurs,
|
||||||
:avis,
|
:avis,
|
||||||
|
:traitements,
|
||||||
etablissement: :champ,
|
etablissement: :champ,
|
||||||
champs: {
|
champs: {
|
||||||
etablissement: :champ,
|
etablissement: :champ,
|
||||||
|
@ -172,6 +174,7 @@ class Dossier < ApplicationRecord
|
||||||
justificatif_motivation_attachment: :blob,
|
justificatif_motivation_attachment: :blob,
|
||||||
attestation: [],
|
attestation: [],
|
||||||
avis: { piece_justificative_file_attachment: :blob },
|
avis: { piece_justificative_file_attachment: :blob },
|
||||||
|
traitements: [],
|
||||||
etablissement: [],
|
etablissement: [],
|
||||||
individual: [],
|
individual: [],
|
||||||
user: [])
|
user: [])
|
||||||
|
@ -198,10 +201,9 @@ class Dossier < ApplicationRecord
|
||||||
.joins(:procedure)
|
.joins(:procedure)
|
||||||
.where("dossiers.en_instruction_at + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION })
|
.where("dossiers.en_instruction_at + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION })
|
||||||
end
|
end
|
||||||
scope :termine_close_to_expiration, -> do
|
def self.termine_close_to_expiration
|
||||||
state_termine
|
dossier_ids = Traitement.termine_close_to_expiration.pluck(:dossier_id).uniq
|
||||||
.joins(:procedure)
|
Dossier.where(id: dossier_ids)
|
||||||
.where("dossiers.processed_at + (duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: INTERVAL_BEFORE_EXPIRATION })
|
|
||||||
end
|
end
|
||||||
|
|
||||||
scope :brouillon_expired, -> do
|
scope :brouillon_expired, -> do
|
||||||
|
@ -249,7 +251,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
scope :for_procedure, -> (procedure) { includes(:user, :groupe_instructeur).where(groupe_instructeurs: { procedure: procedure }) }
|
scope :for_procedure, -> (procedure) { includes(:user, :groupe_instructeur).where(groupe_instructeurs: { procedure: procedure }) }
|
||||||
scope :for_api_v2, -> { includes(procedure: [:administrateurs], etablissement: [], individual: []) }
|
scope :for_api_v2, -> { includes(procedure: [:administrateurs], etablissement: [], individual: [], traitements: []) }
|
||||||
|
|
||||||
scope :with_notifications, -> do
|
scope :with_notifications, -> do
|
||||||
# This scope is meant to be composed, typically with Instructeur.followed_dossiers, which means that the :follows table is already INNER JOINed;
|
# This scope is meant to be composed, typically with Instructeur.followed_dossiers, which means that the :follows table is already INNER JOINed;
|
||||||
|
@ -282,7 +284,6 @@ class Dossier < ApplicationRecord
|
||||||
delegate :types_de_champ, to: :procedure
|
delegate :types_de_champ, to: :procedure
|
||||||
delegate :france_connect_information, to: :user
|
delegate :france_connect_information, to: :user
|
||||||
|
|
||||||
before_validation :update_state_dates, if: -> { state_changed? }
|
|
||||||
before_save :build_default_champs, if: Proc.new { groupe_instructeur_id_was.nil? }
|
before_save :build_default_champs, if: Proc.new { groupe_instructeur_id_was.nil? }
|
||||||
before_save :update_search_terms
|
before_save :update_search_terms
|
||||||
|
|
||||||
|
@ -294,6 +295,16 @@ class Dossier < ApplicationRecord
|
||||||
validates :individual, presence: true, if: -> { procedure.for_individual? }
|
validates :individual, presence: true, if: -> { procedure.for_individual? }
|
||||||
validates :groupe_instructeur, presence: true
|
validates :groupe_instructeur, presence: true
|
||||||
|
|
||||||
|
def motivation
|
||||||
|
return nil if !termine?
|
||||||
|
traitements.any? ? traitements.last.motivation : read_attribute(:motivation)
|
||||||
|
end
|
||||||
|
|
||||||
|
def processed_at
|
||||||
|
return nil if !termine?
|
||||||
|
traitements.any? ? traitements.last.processed_at : read_attribute(:processed_at)
|
||||||
|
end
|
||||||
|
|
||||||
def update_search_terms
|
def update_search_terms
|
||||||
self.search_terms = [
|
self.search_terms = [
|
||||||
user&.email,
|
user&.email,
|
||||||
|
@ -508,27 +519,29 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def after_passer_en_construction
|
||||||
|
update!(en_construction_at: Time.zone.now) if self.en_construction_at.nil?
|
||||||
|
end
|
||||||
|
|
||||||
def after_passer_en_instruction(instructeur)
|
def after_passer_en_instruction(instructeur)
|
||||||
instructeur.follow(self)
|
instructeur.follow(self)
|
||||||
|
|
||||||
|
update!(en_instruction_at: Time.zone.now) if self.en_instruction_at.nil?
|
||||||
log_dossier_operation(instructeur, :passer_en_instruction)
|
log_dossier_operation(instructeur, :passer_en_instruction)
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_passer_automatiquement_en_instruction
|
def after_passer_automatiquement_en_instruction
|
||||||
|
update!(en_instruction_at: Time.zone.now) if self.en_instruction_at.nil?
|
||||||
log_automatic_dossier_operation(:passer_en_instruction)
|
log_automatic_dossier_operation(:passer_en_instruction)
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_repasser_en_construction(instructeur)
|
def after_repasser_en_construction(instructeur)
|
||||||
self.en_instruction_at = nil
|
|
||||||
|
|
||||||
save!
|
|
||||||
log_dossier_operation(instructeur, :repasser_en_construction)
|
log_dossier_operation(instructeur, :repasser_en_construction)
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_repasser_en_instruction(instructeur)
|
def after_repasser_en_instruction(instructeur)
|
||||||
self.archived = false
|
self.archived = false
|
||||||
self.processed_at = nil
|
self.en_instruction_at = Time.zone.now
|
||||||
self.motivation = nil
|
|
||||||
attestation&.destroy
|
attestation&.destroy
|
||||||
|
|
||||||
save!
|
save!
|
||||||
|
@ -537,7 +550,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_accepter(instructeur, motivation, justificatif = nil)
|
def after_accepter(instructeur, motivation, justificatif = nil)
|
||||||
self.motivation = motivation
|
self.traitements.build(state: Dossier.states.fetch(:accepte), instructeur_email: instructeur.email, motivation: motivation, processed_at: Time.zone.now)
|
||||||
|
|
||||||
if justificatif
|
if justificatif
|
||||||
self.justificatif_motivation.attach(justificatif)
|
self.justificatif_motivation.attach(justificatif)
|
||||||
|
@ -553,6 +566,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_accepter_automatiquement
|
def after_accepter_automatiquement
|
||||||
|
self.traitements.build(state: Dossier.states.fetch(:accepte), instructeur_email: nil, motivation: nil, processed_at: Time.zone.now)
|
||||||
self.en_instruction_at ||= Time.zone.now
|
self.en_instruction_at ||= Time.zone.now
|
||||||
|
|
||||||
if attestation.nil?
|
if attestation.nil?
|
||||||
|
@ -565,7 +579,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_refuser(instructeur, motivation, justificatif = nil)
|
def after_refuser(instructeur, motivation, justificatif = nil)
|
||||||
self.motivation = motivation
|
self.traitements.build(state: Dossier.states.fetch(:refuse), instructeur_email: instructeur.email, motivation: motivation, processed_at: Time.zone.now)
|
||||||
|
|
||||||
if justificatif
|
if justificatif
|
||||||
self.justificatif_motivation.attach(justificatif)
|
self.justificatif_motivation.attach(justificatif)
|
||||||
|
@ -577,7 +591,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_classer_sans_suite(instructeur, motivation, justificatif = nil)
|
def after_classer_sans_suite(instructeur, motivation, justificatif = nil)
|
||||||
self.motivation = motivation
|
self.traitements.build(state: Dossier.states.fetch(:sans_suite), instructeur_email: instructeur.email, motivation: motivation, processed_at: Time.zone.now)
|
||||||
|
|
||||||
if justificatif
|
if justificatif
|
||||||
self.justificatif_motivation.attach(justificatif)
|
self.justificatif_motivation.attach(justificatif)
|
||||||
|
@ -766,16 +780,6 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_state_dates
|
|
||||||
if en_construction? && !self.en_construction_at
|
|
||||||
self.en_construction_at = Time.zone.now
|
|
||||||
elsif en_instruction? && !self.en_instruction_at
|
|
||||||
self.en_instruction_at = Time.zone.now
|
|
||||||
elsif TERMINE.include?(state) && !self.processed_at
|
|
||||||
self.processed_at = Time.zone.now
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def send_dossier_received
|
def send_dossier_received
|
||||||
if saved_change_to_state? && en_instruction? && !procedure.declarative_accepte?
|
if saved_change_to_state? && en_instruction? && !procedure.declarative_accepte?
|
||||||
NotificationMailer.send_dossier_received(self).deliver_later
|
NotificationMailer.send_dossier_received(self).deliver_later
|
||||||
|
|
|
@ -161,7 +161,7 @@ class Instructeur < ApplicationRecord
|
||||||
h = {
|
h = {
|
||||||
nb_en_construction: groupe.dossiers.en_construction.count,
|
nb_en_construction: groupe.dossiers.en_construction.count,
|
||||||
nb_en_instruction: groupe.dossiers.en_instruction.count,
|
nb_en_instruction: groupe.dossiers.en_instruction.count,
|
||||||
nb_accepted: groupe.dossiers.accepte.where(processed_at: Time.zone.yesterday.beginning_of_day..Time.zone.yesterday.end_of_day).count,
|
nb_accepted: Traitement.where(dossier: groupe.dossiers.accepte, processed_at: Time.zone.yesterday.beginning_of_day..Time.zone.yesterday.end_of_day).count,
|
||||||
nb_notification: notifications_for_procedure(procedure, :not_archived).count
|
nb_notification: notifications_for_procedure(procedure, :not_archived).count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,8 @@ class Procedure < ApplicationRecord
|
||||||
], size: { less_than: 20.megabytes }
|
], size: { less_than: 20.megabytes }
|
||||||
|
|
||||||
validates :logo, content_type: ['image/png', 'image/jpg', 'image/jpeg'], size: { less_than: 5.megabytes }
|
validates :logo, content_type: ['image/png', 'image/jpg', 'image/jpeg'], size: { less_than: 5.megabytes }
|
||||||
|
validates :api_entreprise_token, jwt_token: true, allow_blank: true
|
||||||
|
|
||||||
before_save :update_juridique_required
|
before_save :update_juridique_required
|
||||||
after_initialize :ensure_path_exists
|
after_initialize :ensure_path_exists
|
||||||
before_save :ensure_path_exists
|
before_save :ensure_path_exists
|
||||||
|
@ -438,7 +440,15 @@ class Procedure < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def usual_traitement_time
|
def usual_traitement_time
|
||||||
percentile_time(:en_construction_at, :processed_at, 90)
|
times = Traitement.includes(:dossier)
|
||||||
|
.where(state: Dossier::TERMINE)
|
||||||
|
.where(processed_at: 1.month.ago..Time.zone.now)
|
||||||
|
.pluck('dossiers.en_construction_at', :processed_at)
|
||||||
|
.map { |(en_construction_at, processed_at)| processed_at - en_construction_at }
|
||||||
|
|
||||||
|
if times.present?
|
||||||
|
times.percentile(90).ceil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def populate_champ_stable_ids
|
def populate_champ_stable_ids
|
||||||
|
@ -610,18 +620,6 @@ class Procedure < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def percentile_time(start_attribute, end_attribute, p)
|
|
||||||
times = dossiers
|
|
||||||
.where.not(start_attribute => nil, end_attribute => nil)
|
|
||||||
.where(end_attribute => 1.month.ago..Time.zone.now)
|
|
||||||
.pluck(start_attribute, end_attribute)
|
|
||||||
.map { |(start_date, end_date)| end_date - start_date }
|
|
||||||
|
|
||||||
if times.present?
|
|
||||||
times.percentile(p).ceil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ensure_path_exists
|
def ensure_path_exists
|
||||||
if self.path.blank?
|
if self.path.blank?
|
||||||
self.path = SecureRandom.uuid
|
self.path = SecureRandom.uuid
|
||||||
|
|
10
app/models/traitement.rb
Normal file
10
app/models/traitement.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
class Traitement < ApplicationRecord
|
||||||
|
belongs_to :dossier
|
||||||
|
|
||||||
|
scope :termine_close_to_expiration, -> do
|
||||||
|
joins(dossier: :procedure)
|
||||||
|
.where(state: Dossier::TERMINE)
|
||||||
|
.where('dossiers.state' => Dossier::TERMINE)
|
||||||
|
.where("traitements.processed_at + (procedures.duree_conservation_dossiers_dans_ds * INTERVAL '1 month') - INTERVAL :expires_in < :now", { now: Time.zone.now, expires_in: Dossier::INTERVAL_BEFORE_EXPIRATION })
|
||||||
|
end
|
||||||
|
end
|
|
@ -82,7 +82,12 @@ class TypeDeChamp < ApplicationRecord
|
||||||
|
|
||||||
before_validation :check_mandatory
|
before_validation :check_mandatory
|
||||||
before_save :remove_piece_justificative_template, if: -> { type_champ_changed? }
|
before_save :remove_piece_justificative_template, if: -> { type_champ_changed? }
|
||||||
before_validation :remove_drop_down_list, if: -> { type_champ_changed? }
|
before_save :remove_drop_down_list, if: -> { type_champ_changed? }
|
||||||
|
before_save :remove_repetition, if: -> { type_champ_changed? }
|
||||||
|
|
||||||
|
after_save if: -> { @remove_piece_justificative_template } do
|
||||||
|
piece_justificative_template.purge_later
|
||||||
|
end
|
||||||
|
|
||||||
def valid?(context = nil)
|
def valid?(context = nil)
|
||||||
super
|
super
|
||||||
|
@ -292,7 +297,7 @@ class TypeDeChamp < ApplicationRecord
|
||||||
|
|
||||||
def remove_piece_justificative_template
|
def remove_piece_justificative_template
|
||||||
if !piece_justificative? && piece_justificative_template.attached?
|
if !piece_justificative? && piece_justificative_template.attached?
|
||||||
piece_justificative_template.purge_later
|
@remove_piece_justificative_template = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -302,4 +307,10 @@ class TypeDeChamp < ApplicationRecord
|
||||||
self.drop_down_options = nil
|
self.drop_down_options = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_repetition
|
||||||
|
if !repetition?
|
||||||
|
types_de_champ.destroy_all
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
9
app/validators/jwt_token_validator.rb
Normal file
9
app/validators/jwt_token_validator.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
class JwtTokenValidator < ActiveModel::EachValidator
|
||||||
|
def validate_each(record, attribute, value)
|
||||||
|
begin
|
||||||
|
JWT.decode value, nil, false
|
||||||
|
rescue
|
||||||
|
record.errors[attribute] << (options[:message] || "n'est pas un jeton valide")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -156,7 +156,7 @@ def add_etats_dossier(pdf, dossier)
|
||||||
if dossier.en_instruction_at.present?
|
if dossier.en_instruction_at.present?
|
||||||
format_in_2_columns(pdf, "En instruction le", try_format_date(dossier.en_instruction_at))
|
format_in_2_columns(pdf, "En instruction le", try_format_date(dossier.en_instruction_at))
|
||||||
end
|
end
|
||||||
if dossier.processed_at?.present?
|
if dossier.processed_at.present?
|
||||||
format_in_2_columns(pdf, "Décision le", try_format_date(dossier.processed_at))
|
format_in_2_columns(pdf, "Décision le", try_format_date(dossier.processed_at))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
.tab-title Décisions rendues
|
||||||
|
- if traitements.any?
|
||||||
|
%ul.tab-list
|
||||||
|
- traitements.each do |traitement|
|
||||||
|
- if traitement.instructeur_email.present?
|
||||||
|
%li
|
||||||
|
= "Le #{l(traitement.processed_at, format: '%d %B %Y à %R')}, "
|
||||||
|
= traitement.instructeur_email
|
||||||
|
a
|
||||||
|
%strong= t(traitement.state, scope: 'activerecord.attributes.traitement.state').downcase
|
||||||
|
ce dossier
|
||||||
|
- else
|
||||||
|
%li
|
||||||
|
= "Le #{l(traitement.processed_at, format: '%d %B %Y à %R')}, "
|
||||||
|
ce dossier a été
|
||||||
|
%strong= t(traitement.state, scope: 'activerecord.attributes.traitement.state').downcase
|
||||||
|
- else
|
||||||
|
%p.tab-paragraph Aucune décision n'a été rendue
|
||||||
|
|
|
@ -13,3 +13,5 @@
|
||||||
= render partial: 'instructeurs/dossiers/personnes_impliquees_block', locals: { emails_collection: @avis_emails, title: "Personnes à qui un avis a été demandé", blank: "Aucun avis n'a été demandé" }
|
= render partial: 'instructeurs/dossiers/personnes_impliquees_block', locals: { emails_collection: @avis_emails, title: "Personnes à qui un avis a été demandé", blank: "Aucun avis n'a été demandé" }
|
||||||
|
|
||||||
= render partial: 'instructeurs/dossiers/personnes_impliquees_block', locals: { emails_collection: @invites_emails, title: "Personnes invitées à consulter ce dossier", blank: "Aucune personne n'a été invitée à consulter ce dossier" }
|
= render partial: 'instructeurs/dossiers/personnes_impliquees_block', locals: { emails_collection: @invites_emails, title: "Personnes invitées à consulter ce dossier", blank: "Aucune personne n'a été invitée à consulter ce dossier" }
|
||||||
|
|
||||||
|
= render partial: 'instructeurs/dossiers/decisions_rendues_block', locals: { traitements: @dossier.traitements }
|
||||||
|
|
|
@ -68,13 +68,20 @@
|
||||||
.cta-panel-wrapper
|
.cta-panel-wrapper
|
||||||
%div
|
%div
|
||||||
%h2.cta-panel-title Une question, un problème ?
|
%h2.cta-panel-title Une question, un problème ?
|
||||||
%p.cta-panel-explanation Notre équipe est disponible pour vous renseigner et vous aider
|
%p.cta-panel-explanation La réponse est dans l’aide en ligne
|
||||||
%div
|
%div
|
||||||
= contact_link "Contactez-nous",
|
= link_to "Accéder à l’aide en ligne", FAQ_URL,
|
||||||
tags: 'landing',
|
|
||||||
class: "cta-panel-button-white",
|
class: "cta-panel-button-white",
|
||||||
target: "_blank",
|
target: "_blank",
|
||||||
rel: "noopener noreferrer"
|
rel: "noopener noreferrer"
|
||||||
|
-# We temporarily disable the link to the contact page on the homepage
|
||||||
|
-# %p.cta-panel-explanation Notre équipe est disponible pour vous renseigner et vous aider
|
||||||
|
-# %div
|
||||||
|
-# = contact_link "Contactez-nous",
|
||||||
|
-# tags: 'landing',
|
||||||
|
-# class: "cta-panel-button-white",
|
||||||
|
-# target: "_blank",
|
||||||
|
-# rel: "noopener noreferrer"
|
||||||
|
|
||||||
.landing-panel
|
.landing-panel
|
||||||
.container
|
.container
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
include FileUtils
|
|
||||||
|
|
||||||
# path to your application root.
|
# path to your application root.
|
||||||
APP_ROOT = File.expand_path('..', __dir__)
|
APP_ROOT = File.expand_path('..', __dir__)
|
||||||
|
@ -9,13 +8,15 @@ def system!(*args)
|
||||||
system(*args) || abort("\n== Command #{args} failed ==")
|
system(*args) || abort("\n== Command #{args} failed ==")
|
||||||
end
|
end
|
||||||
|
|
||||||
chdir APP_ROOT do
|
FileUtils.chdir APP_ROOT do
|
||||||
# This script is a starting point to setup your application.
|
# This script is a starting point to setup your application.
|
||||||
# Add necessary setup steps to this file.
|
# Add necessary setup steps to this file.
|
||||||
|
|
||||||
puts "\n== Installing dependencies =="
|
puts "\n== Installing dependencies =="
|
||||||
system! 'gem install bundler --conservative'
|
system! 'gem install bundler --conservative'
|
||||||
system('bundle check') || system!('bundle install')
|
system('bundle check') || system!('bundle install')
|
||||||
|
|
||||||
|
# Install JavaScript dependencies
|
||||||
system! 'bin/yarn install'
|
system! 'bin/yarn install'
|
||||||
|
|
||||||
puts "\n== Updating webdrivers =="
|
puts "\n== Updating webdrivers =="
|
||||||
|
@ -23,7 +24,7 @@ chdir APP_ROOT do
|
||||||
|
|
||||||
puts "\n== Copying sample files =="
|
puts "\n== Copying sample files =="
|
||||||
unless File.exist?('.env')
|
unless File.exist?('.env')
|
||||||
cp 'config/env.example', '.env'
|
FileUtils.cp 'config/env.example', '.env'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create the database, load the schema, and initialize it with the seed data
|
# Create the database, load the schema, and initialize it with the seed data
|
||||||
|
@ -34,5 +35,5 @@ chdir APP_ROOT do
|
||||||
system! 'bin/rails log:clear tmp:clear'
|
system! 'bin/rails log:clear tmp:clear'
|
||||||
|
|
||||||
puts "\n== Done =="
|
puts "\n== Done =="
|
||||||
puts "You can now start the application server with `overmind start`."
|
puts "You can now start the application server with `bin/rails server`."
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
include FileUtils
|
|
||||||
|
|
||||||
# path to your application root.
|
# path to your application root.
|
||||||
APP_ROOT = File.expand_path('..', __dir__)
|
APP_ROOT = File.expand_path('..', __dir__)
|
||||||
|
@ -9,7 +8,7 @@ def system!(*args)
|
||||||
system(*args) || abort("\n== Command #{args} failed ==")
|
system(*args) || abort("\n== Command #{args} failed ==")
|
||||||
end
|
end
|
||||||
|
|
||||||
chdir APP_ROOT do
|
FileUtils.chdir APP_ROOT do
|
||||||
# This script is a way to update your development environment automatically.
|
# This script is a way to update your development environment automatically.
|
||||||
# Add necessary update steps to this file.
|
# Add necessary update steps to this file.
|
||||||
|
|
||||||
|
@ -31,5 +30,5 @@ chdir APP_ROOT do
|
||||||
system! 'bin/rails log:clear'
|
system! 'bin/rails log:clear'
|
||||||
|
|
||||||
puts "\n== Done =="
|
puts "\n== Done =="
|
||||||
puts "You can now start (or restart) the application server with `overmind start`."
|
puts "You can now start (or restart) the application server with `bin/rails server`."
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,7 +36,7 @@ Rails.application.configure do
|
||||||
# Debug mode disables concatenation and preprocessing of assets.
|
# Debug mode disables concatenation and preprocessing of assets.
|
||||||
# This option may cause significant delays in view rendering with a large
|
# This option may cause significant delays in view rendering with a large
|
||||||
# number of complex assets.
|
# number of complex assets.
|
||||||
config.assets.debug = false
|
config.assets.debug = true
|
||||||
|
|
||||||
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
|
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
|
||||||
# yet still be able to expire them through the digest params.
|
# yet still be able to expire them through the digest params.
|
||||||
|
@ -83,10 +83,9 @@ Rails.application.configure do
|
||||||
# Raises error for missing translations
|
# Raises error for missing translations
|
||||||
# config.action_view.raise_on_missing_translations = true
|
# config.action_view.raise_on_missing_translations = true
|
||||||
|
|
||||||
# This is useful to run rails in development with :async queue adapter
|
# We use the async adapter by default, but delayed_job can be set using
|
||||||
if ENV['RAILS_QUEUE_ADAPTER']
|
# RAILS_QUEUE_ADAPTER=delayed_job bin/rails server
|
||||||
config.active_job.queue_adapter = ENV['RAILS_QUEUE_ADAPTER'].to_sym
|
config.active_job.queue_adapter = ENV.fetch('RAILS_QUEUE_ADAPTER', 'async').to_sym
|
||||||
end
|
|
||||||
|
|
||||||
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
|
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,13 +9,13 @@ fr:
|
||||||
montant_projet: 'Le montant du projet'
|
montant_projet: 'Le montant du projet'
|
||||||
montant_aide_demande: "Le montant d’aide demandée"
|
montant_aide_demande: "Le montant d’aide demandée"
|
||||||
date_previsionnelle: "La date de début prévisionnelle"
|
date_previsionnelle: "La date de début prévisionnelle"
|
||||||
state:
|
state: &state
|
||||||
brouillon: "Brouillon"
|
brouillon: "Brouillon"
|
||||||
en_construction: "En construction"
|
en_construction: "En construction"
|
||||||
en_instruction: "En instruction"
|
en_instruction: "En instruction"
|
||||||
accepte: "Accepté"
|
accepte: "Accepté"
|
||||||
refuse: "Refusé"
|
refuse: "Refusé"
|
||||||
sans_suite: "Sans suite"
|
sans_suite: "Classé sans suite"
|
||||||
autorisation_donnees: Acceptation des CGU
|
autorisation_donnees: Acceptation des CGU
|
||||||
state/brouillon: Brouillon
|
state/brouillon: Brouillon
|
||||||
state/en_construction: En construction
|
state/en_construction: En construction
|
||||||
|
@ -23,3 +23,6 @@ fr:
|
||||||
state/accepte: Accepté
|
state/accepte: Accepté
|
||||||
state/refuse: Refusé
|
state/refuse: Refusé
|
||||||
state/sans_suite: Sans suite
|
state/sans_suite: Sans suite
|
||||||
|
traitement:
|
||||||
|
state:
|
||||||
|
<<: *state
|
||||||
|
|
|
@ -77,7 +77,7 @@ test:
|
||||||
secret_key_base: aa52abc3f3a629d04a61e9899a24c12f52b24c679cbf45f8ec0cdcc64ab9526d673adca84212882dff3911ac98e0c32ec4729ca7b3429ba18ef4dfd1bd18bc7a
|
secret_key_base: aa52abc3f3a629d04a61e9899a24c12f52b24c679cbf45f8ec0cdcc64ab9526d673adca84212882dff3911ac98e0c32ec4729ca7b3429ba18ef4dfd1bd18bc7a
|
||||||
signing_key: aef3153a9829fa4ba10acb02927ac855df6b92795b1ad265d654443c4b14a017
|
signing_key: aef3153a9829fa4ba10acb02927ac855df6b92795b1ad265d654443c4b14a017
|
||||||
api_entreprise:
|
api_entreprise:
|
||||||
key: api_entreprise_test_key
|
key: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik9oIHllYWgiLCJpYXQiOjE1MTYyMzkwMjJ9.f06sBo3q2Yxnw_TYPFUEs0CozBmcV-XniH_DeKNWzKE"
|
||||||
pipedrive:
|
pipedrive:
|
||||||
key: pipedrive_test_key
|
key: pipedrive_test_key
|
||||||
france_connect_particulier:
|
france_connect_particulier:
|
||||||
|
|
11
db/migrate/20200630140356_create_traitements.rb
Normal file
11
db/migrate/20200630140356_create_traitements.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
class CreateTraitements < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_table :traitements do |t|
|
||||||
|
t.references :dossier, foreign_key: true
|
||||||
|
t.references :instructeur, foreign_key: true
|
||||||
|
t.string :motivation
|
||||||
|
t.string :state
|
||||||
|
t.timestamp :processed_at
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,6 @@
|
||||||
|
class RemoveInstructeurIdAndAddInstructeurEmailToTraitements < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :traitements, :instructeur_email, :string
|
||||||
|
remove_column :traitements, :instructeur_id
|
||||||
|
end
|
||||||
|
end
|
12
db/schema.rb
12
db/schema.rb
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2020_06_11_122406) do
|
ActiveRecord::Schema.define(version: 2020_07_07_082256) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -560,6 +560,15 @@ ActiveRecord::Schema.define(version: 2020_06_11_122406) do
|
||||||
t.string "version", null: false
|
t.string "version", null: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "traitements", force: :cascade do |t|
|
||||||
|
t.bigint "dossier_id"
|
||||||
|
t.string "motivation"
|
||||||
|
t.string "state"
|
||||||
|
t.datetime "processed_at"
|
||||||
|
t.string "instructeur_email"
|
||||||
|
t.index ["dossier_id"], name: "index_traitements_on_dossier_id"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "trusted_device_tokens", force: :cascade do |t|
|
create_table "trusted_device_tokens", force: :cascade do |t|
|
||||||
t.string "token", null: false
|
t.string "token", null: false
|
||||||
t.bigint "instructeur_id"
|
t.bigint "instructeur_id"
|
||||||
|
@ -660,6 +669,7 @@ ActiveRecord::Schema.define(version: 2020_06_11_122406) do
|
||||||
add_foreign_key "received_mails", "procedures"
|
add_foreign_key "received_mails", "procedures"
|
||||||
add_foreign_key "refused_mails", "procedures"
|
add_foreign_key "refused_mails", "procedures"
|
||||||
add_foreign_key "services", "administrateurs"
|
add_foreign_key "services", "administrateurs"
|
||||||
|
add_foreign_key "traitements", "dossiers"
|
||||||
add_foreign_key "trusted_device_tokens", "instructeurs"
|
add_foreign_key "trusted_device_tokens", "instructeurs"
|
||||||
add_foreign_key "types_de_champ", "types_de_champ", column: "parent_id"
|
add_foreign_key "types_de_champ", "types_de_champ", column: "parent_id"
|
||||||
add_foreign_key "users", "administrateurs"
|
add_foreign_key "users", "administrateurs"
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: add_traitements_from_dossiers'
|
||||||
|
task add_traitements_from_dossiers: :environment do
|
||||||
|
puts "Running deploy task 'add_traitements_from_dossiers'"
|
||||||
|
|
||||||
|
dossiers_termines = Dossier.state_termine
|
||||||
|
progress = ProgressReport.new(dossiers_termines.count)
|
||||||
|
dossiers_termines.find_each do |dossier|
|
||||||
|
dossier.traitements.create!(state: dossier.state, motivation: dossier.motivation, processed_at: dossier.processed_at)
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
# 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: '20200630154829'
|
||||||
|
end
|
||||||
|
end
|
|
@ -596,7 +596,7 @@ describe API::V2::GraphqlController do
|
||||||
it "should fail" do
|
it "should fail" do
|
||||||
expect(gql_errors).to eq(nil)
|
expect(gql_errors).to eq(nil)
|
||||||
expect(gql_data).to eq(dossierRefuser: {
|
expect(gql_data).to eq(dossierRefuser: {
|
||||||
errors: [{ message: "Le dossier est déjà sans suite" }],
|
errors: [{ message: "Le dossier est déjà classé sans suite" }],
|
||||||
dossier: nil
|
dossier: nil
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
|
@ -194,7 +194,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
describe '#terminer' do
|
describe '#terminer' do
|
||||||
context "with refuser" do
|
context "with refuser" do
|
||||||
before do
|
before do
|
||||||
dossier.en_instruction!
|
dossier.passer_en_instruction!(instructeur)
|
||||||
sign_in(instructeur.user)
|
sign_in(instructeur.user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
|
|
||||||
context "with classer_sans_suite" do
|
context "with classer_sans_suite" do
|
||||||
before do
|
before do
|
||||||
dossier.en_instruction!
|
dossier.passer_en_instruction!(instructeur)
|
||||||
sign_in(instructeur.user)
|
sign_in(instructeur.user)
|
||||||
end
|
end
|
||||||
context 'without attachment' do
|
context 'without attachment' do
|
||||||
|
@ -277,7 +277,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
|
|
||||||
context "with accepter" do
|
context "with accepter" do
|
||||||
before do
|
before do
|
||||||
dossier.en_instruction!
|
dossier.passer_en_instruction!(instructeur)
|
||||||
sign_in(instructeur.user)
|
sign_in(instructeur.user)
|
||||||
|
|
||||||
expect(NotificationMailer).to receive(:send_closed_notification)
|
expect(NotificationMailer).to receive(:send_closed_notification)
|
||||||
|
|
|
@ -312,10 +312,11 @@ describe NewAdministrateur::ProceduresController, type: :controller do
|
||||||
|
|
||||||
describe 'PATCH #jeton' do
|
describe 'PATCH #jeton' do
|
||||||
let(:procedure) { create(:procedure, administrateur: admin) }
|
let(:procedure) { create(:procedure, administrateur: admin) }
|
||||||
|
let(:valid_token) { "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" }
|
||||||
|
|
||||||
it "update api_entreprise_token" do
|
it "update api_entreprise_token" do
|
||||||
patch :update_jeton, params: { id: procedure.id, procedure: { api_entreprise_token: 'ceci-est-un-jeton' } }
|
patch :update_jeton, params: { id: procedure.id, procedure: { api_entreprise_token: valid_token } }
|
||||||
expect(procedure.reload.api_entreprise_token).to eq('ceci-est-un-jeton')
|
expect(procedure.reload.api_entreprise_token).to eq(valid_token)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -106,26 +106,23 @@ describe StatsController, type: :controller do
|
||||||
before do
|
before do
|
||||||
procedure_1 = FactoryBot.create(:procedure)
|
procedure_1 = FactoryBot.create(:procedure)
|
||||||
procedure_2 = FactoryBot.create(:procedure)
|
procedure_2 = FactoryBot.create(:procedure)
|
||||||
dossier_p1_a = FactoryBot.create(:dossier,
|
dossier_p1_a = FactoryBot.create(:dossier, :accepte,
|
||||||
:procedure => procedure_1,
|
:procedure => procedure_1,
|
||||||
:en_construction_at => 2.months.ago.beginning_of_month,
|
:en_construction_at => 2.months.ago.beginning_of_month,
|
||||||
:processed_at => 2.months.ago.beginning_of_month + 3.days)
|
:processed_at => 2.months.ago.beginning_of_month + 3.days)
|
||||||
dossier_p1_b = FactoryBot.create(:dossier,
|
dossier_p1_b = FactoryBot.create(:dossier, :accepte,
|
||||||
:procedure => procedure_1,
|
:procedure => procedure_1,
|
||||||
:en_construction_at => 2.months.ago.beginning_of_month,
|
:en_construction_at => 2.months.ago.beginning_of_month,
|
||||||
:processed_at => 2.months.ago.beginning_of_month + 1.day)
|
:processed_at => 2.months.ago.beginning_of_month + 1.day)
|
||||||
dossier_p1_c = FactoryBot.create(:dossier,
|
dossier_p1_c = FactoryBot.create(:dossier, :accepte,
|
||||||
:procedure => procedure_1,
|
:procedure => procedure_1,
|
||||||
:en_construction_at => 1.month.ago.beginning_of_month,
|
:en_construction_at => 1.month.ago.beginning_of_month,
|
||||||
:processed_at => 1.month.ago.beginning_of_month + 5.days)
|
:processed_at => 1.month.ago.beginning_of_month + 5.days)
|
||||||
dossier_p2_a = FactoryBot.create(:dossier,
|
dossier_p2_a = FactoryBot.create(:dossier, :accepte,
|
||||||
:procedure => procedure_2,
|
:procedure => procedure_2,
|
||||||
:en_construction_at => 2.months.ago.beginning_of_month,
|
:en_construction_at => 2.months.ago.beginning_of_month,
|
||||||
:processed_at => 2.months.ago.beginning_of_month + 4.days)
|
:processed_at => 2.months.ago.beginning_of_month + 4.days)
|
||||||
|
|
||||||
# Write directly in the DB to avoid the before_validation hook
|
|
||||||
Dossier.update_all(state: Dossier.states.fetch(:accepte))
|
|
||||||
|
|
||||||
@expected_hash = {
|
@expected_hash = {
|
||||||
(2.months.ago.beginning_of_month).to_s => 3.0,
|
(2.months.ago.beginning_of_month).to_s => 3.0,
|
||||||
(1.month.ago.beginning_of_month).to_s => 5.0
|
(1.month.ago.beginning_of_month).to_s => 5.0
|
||||||
|
@ -154,30 +151,27 @@ describe StatsController, type: :controller do
|
||||||
before do
|
before do
|
||||||
procedure_1 = FactoryBot.create(:procedure, :with_type_de_champ, :types_de_champ_count => 24)
|
procedure_1 = FactoryBot.create(:procedure, :with_type_de_champ, :types_de_champ_count => 24)
|
||||||
procedure_2 = FactoryBot.create(:procedure, :with_type_de_champ, :types_de_champ_count => 48)
|
procedure_2 = FactoryBot.create(:procedure, :with_type_de_champ, :types_de_champ_count => 48)
|
||||||
dossier_p1_a = FactoryBot.create(:dossier,
|
dossier_p1_a = FactoryBot.create(:dossier, :accepte,
|
||||||
:procedure => procedure_1,
|
:procedure => procedure_1,
|
||||||
:created_at => 2.months.ago.beginning_of_month,
|
:created_at => 2.months.ago.beginning_of_month,
|
||||||
:en_construction_at => 2.months.ago.beginning_of_month + 30.minutes,
|
:en_construction_at => 2.months.ago.beginning_of_month + 30.minutes,
|
||||||
:processed_at => 2.months.ago.beginning_of_month + 1.day)
|
:processed_at => 2.months.ago.beginning_of_month + 1.day)
|
||||||
dossier_p1_b = FactoryBot.create(:dossier,
|
dossier_p1_b = FactoryBot.create(:dossier, :accepte,
|
||||||
:procedure => procedure_1,
|
:procedure => procedure_1,
|
||||||
:created_at => 2.months.ago.beginning_of_month,
|
:created_at => 2.months.ago.beginning_of_month,
|
||||||
:en_construction_at => 2.months.ago.beginning_of_month + 10.minutes,
|
:en_construction_at => 2.months.ago.beginning_of_month + 10.minutes,
|
||||||
:processed_at => 2.months.ago.beginning_of_month + 1.day)
|
:processed_at => 2.months.ago.beginning_of_month + 1.day)
|
||||||
dossier_p1_c = FactoryBot.create(:dossier,
|
dossier_p1_c = FactoryBot.create(:dossier, :accepte,
|
||||||
:procedure => procedure_1,
|
:procedure => procedure_1,
|
||||||
:created_at => 1.month.ago.beginning_of_month,
|
:created_at => 1.month.ago.beginning_of_month,
|
||||||
:en_construction_at => 1.month.ago.beginning_of_month + 50.minutes,
|
:en_construction_at => 1.month.ago.beginning_of_month + 50.minutes,
|
||||||
:processed_at => 1.month.ago.beginning_of_month + 1.day)
|
:processed_at => 1.month.ago.beginning_of_month + 1.day)
|
||||||
dossier_p2_a = FactoryBot.create(:dossier,
|
dossier_p2_a = FactoryBot.create(:dossier, :accepte,
|
||||||
:procedure => procedure_2,
|
:procedure => procedure_2,
|
||||||
:created_at => 2.months.ago.beginning_of_month,
|
:created_at => 2.months.ago.beginning_of_month,
|
||||||
:en_construction_at => 2.months.ago.beginning_of_month + 80.minutes,
|
:en_construction_at => 2.months.ago.beginning_of_month + 80.minutes,
|
||||||
:processed_at => 2.months.ago.beginning_of_month + 1.day)
|
:processed_at => 2.months.ago.beginning_of_month + 1.day)
|
||||||
|
|
||||||
# Write directly in the DB to avoid the before_validation hook
|
|
||||||
Dossier.update_all(state: Dossier.states.fetch(:accepte))
|
|
||||||
|
|
||||||
@expected_hash = {
|
@expected_hash = {
|
||||||
(2.months.ago.beginning_of_month).to_s => 30.0,
|
(2.months.ago.beginning_of_month).to_s => 30.0,
|
||||||
(1.month.ago.beginning_of_month).to_s => 50.0
|
(1.month.ago.beginning_of_month).to_s => 50.0
|
||||||
|
|
|
@ -657,7 +657,7 @@ describe Users::DossiersController, type: :controller do
|
||||||
let!(:invite) { create(:invite, dossier: dossier, user: user) }
|
let!(:invite) { create(:invite, dossier: dossier, user: user) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
dossier.en_construction!
|
dossier.passer_en_construction!
|
||||||
subject
|
subject
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -127,11 +127,23 @@ FactoryBot.define do
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :accepte do
|
trait :accepte do
|
||||||
after(:create) do |dossier, _evaluator|
|
transient do
|
||||||
|
motivation { nil }
|
||||||
|
processed_at { nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:create) do |dossier, evaluator|
|
||||||
dossier.state = Dossier.states.fetch(:accepte)
|
dossier.state = Dossier.states.fetch(:accepte)
|
||||||
dossier.en_construction_at ||= dossier.created_at + 1.minute
|
processed_at = evaluator.processed_at
|
||||||
dossier.en_instruction_at ||= dossier.en_construction_at + 1.minute
|
if processed_at.present?
|
||||||
dossier.processed_at ||= dossier.en_instruction_at + 1.minute
|
dossier.en_construction_at ||= processed_at - 2.minutes
|
||||||
|
dossier.en_instruction_at ||= processed_at - 1.minute
|
||||||
|
dossier.traitements.build(state: Dossier.states.fetch(:accepte), processed_at: processed_at, motivation: evaluator.motivation)
|
||||||
|
else
|
||||||
|
dossier.en_construction_at ||= dossier.created_at + 1.minute
|
||||||
|
dossier.en_instruction_at ||= dossier.en_construction_at + 1.minute
|
||||||
|
dossier.traitements.build(state: Dossier.states.fetch(:accepte), processed_at: dossier.en_instruction_at + 1.minute, motivation: evaluator.motivation)
|
||||||
|
end
|
||||||
dossier.save!
|
dossier.save!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -141,7 +153,7 @@ FactoryBot.define do
|
||||||
dossier.state = Dossier.states.fetch(:refuse)
|
dossier.state = Dossier.states.fetch(:refuse)
|
||||||
dossier.en_construction_at ||= dossier.created_at + 1.minute
|
dossier.en_construction_at ||= dossier.created_at + 1.minute
|
||||||
dossier.en_instruction_at ||= dossier.en_construction_at + 1.minute
|
dossier.en_instruction_at ||= dossier.en_construction_at + 1.minute
|
||||||
dossier.processed_at ||= dossier.en_instruction_at + 1.minute
|
dossier.traitements.build(state: Dossier.states.fetch(:refuse), processed_at: dossier.en_instruction_at + 1.minute)
|
||||||
dossier.save!
|
dossier.save!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -151,14 +163,14 @@ FactoryBot.define do
|
||||||
dossier.state = Dossier.states.fetch(:sans_suite)
|
dossier.state = Dossier.states.fetch(:sans_suite)
|
||||||
dossier.en_construction_at ||= dossier.created_at + 1.minute
|
dossier.en_construction_at ||= dossier.created_at + 1.minute
|
||||||
dossier.en_instruction_at ||= dossier.en_construction_at + 1.minute
|
dossier.en_instruction_at ||= dossier.en_construction_at + 1.minute
|
||||||
dossier.processed_at ||= dossier.en_instruction_at + 1.minute
|
dossier.traitements.build(state: Dossier.states.fetch(:sans_suite), processed_at: dossier.en_instruction_at + 1.minute)
|
||||||
dossier.save!
|
dossier.save!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :with_motivation do
|
trait :with_motivation do
|
||||||
after(:create) do |dossier, _evaluator|
|
after(:create) do |dossier, _evaluator|
|
||||||
dossier.motivation = case dossier.state
|
motivation = case dossier.state
|
||||||
when Dossier.states.fetch(:refuse)
|
when Dossier.states.fetch(:refuse)
|
||||||
'L’entreprise concernée n’est pas agréée.'
|
'L’entreprise concernée n’est pas agréée.'
|
||||||
when Dossier.states.fetch(:sans_suite)
|
when Dossier.states.fetch(:sans_suite)
|
||||||
|
@ -166,6 +178,7 @@ FactoryBot.define do
|
||||||
else
|
else
|
||||||
'Vous avez validé les conditions.'
|
'Vous avez validé les conditions.'
|
||||||
end
|
end
|
||||||
|
dossier.traitements.last.update!(motivation: motivation)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,12 @@ FactoryBot.define do
|
||||||
end
|
end
|
||||||
factory :type_de_champ_repetition do
|
factory :type_de_champ_repetition do
|
||||||
type_champ { TypeDeChamp.type_champs.fetch(:repetition) }
|
type_champ { TypeDeChamp.type_champs.fetch(:repetition) }
|
||||||
|
|
||||||
|
trait :with_types_de_champ do
|
||||||
|
after(:build) do |type_de_champ, _evaluator|
|
||||||
|
type_de_champ.types_de_champ << create(:type_de_champ, libelle: 'sub type de champ')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :private do
|
trait :private do
|
||||||
|
|
|
@ -156,7 +156,7 @@ RSpec.describe DossierHelper, type: :helper do
|
||||||
|
|
||||||
it 'sans_suite is traité' do
|
it 'sans_suite is traité' do
|
||||||
dossier.sans_suite!
|
dossier.sans_suite!
|
||||||
expect(subject).to eq('Sans suite')
|
expect(subject).to eq('Classé sans suite')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'refuse is traité' do
|
it 'refuse is traité' do
|
||||||
|
|
|
@ -62,13 +62,13 @@ describe ApiEntreprise::API do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with specific token for procedure' do
|
context 'with specific token for procedure' do
|
||||||
let(:token) { 'token-for-demarche' }
|
let(:token) { "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" }
|
||||||
let(:procedure) { create(:procedure, api_entreprise_token: token) }
|
let(:procedure) { create(:procedure, api_entreprise_token: token) }
|
||||||
let(:procedure_id) { procedure.id }
|
let(:procedure_id) { procedure.id }
|
||||||
|
|
||||||
it 'call api-entreprise with specfic token' do
|
it 'call api-entreprise with specfic token' do
|
||||||
subject
|
subject
|
||||||
expect(WebMock).to have_requested(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=token-for-demarche/)
|
expect(WebMock).to have_requested(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=#{token}/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ describe TagsSubstitutionConcern, type: :model do
|
||||||
let(:individual) { nil }
|
let(:individual) { nil }
|
||||||
let(:etablissement) { create(:etablissement) }
|
let(:etablissement) { create(:etablissement) }
|
||||||
let!(:dossier) { create(:dossier, procedure: procedure, individual: individual, etablissement: etablissement) }
|
let!(:dossier) { create(:dossier, procedure: procedure, individual: individual, etablissement: etablissement) }
|
||||||
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
|
||||||
before { Timecop.freeze(Time.zone.now) }
|
before { Timecop.freeze(Time.zone.now) }
|
||||||
|
|
||||||
|
@ -242,7 +243,7 @@ describe TagsSubstitutionConcern, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the dossier has a motivation' do
|
context 'when the dossier has a motivation' do
|
||||||
let(:dossier) { create(:dossier, motivation: 'motivation') }
|
let(:dossier) { create(:dossier, :accepte, motivation: 'motivation') }
|
||||||
|
|
||||||
context 'and the template has some dossier tags' do
|
context 'and the template has some dossier tags' do
|
||||||
let(:template) { '--motivation-- --numéro du dossier--' }
|
let(:template) { '--motivation-- --numéro du dossier--' }
|
||||||
|
@ -318,9 +319,13 @@ describe TagsSubstitutionConcern, type: :model do
|
||||||
|
|
||||||
context "when using a date tag" do
|
context "when using a date tag" do
|
||||||
before do
|
before do
|
||||||
dossier.en_construction_at = Time.zone.local(2001, 2, 3)
|
Timecop.freeze(Time.zone.local(2001, 2, 3))
|
||||||
dossier.en_instruction_at = Time.zone.local(2004, 5, 6)
|
dossier.passer_en_construction!
|
||||||
dossier.processed_at = Time.zone.local(2007, 8, 9)
|
Timecop.freeze(Time.zone.local(2004, 5, 6))
|
||||||
|
dossier.passer_en_instruction!(instructeur)
|
||||||
|
Timecop.freeze(Time.zone.local(2007, 8, 9))
|
||||||
|
dossier.accepter!(instructeur, nil, nil)
|
||||||
|
Timecop.return
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with date de dépôt" do
|
context "with date de dépôt" do
|
||||||
|
|
|
@ -209,8 +209,17 @@ describe Dossier do
|
||||||
let(:date1) { 1.day.ago }
|
let(:date1) { 1.day.ago }
|
||||||
let(:date2) { 1.hour.ago }
|
let(:date2) { 1.hour.ago }
|
||||||
let(:date3) { 1.minute.ago }
|
let(:date3) { 1.minute.ago }
|
||||||
let(:dossier) { create(:dossier, :with_entreprise, user: user, procedure: procedure, en_construction_at: date1, en_instruction_at: date2, processed_at: date3, motivation: "Motivation") }
|
let(:dossier) do
|
||||||
let!(:follow) { create(:follow, instructeur: instructeur, dossier: dossier) }
|
d = create(:dossier, :with_entreprise, user: user, procedure: procedure)
|
||||||
|
Timecop.freeze(date1)
|
||||||
|
d.passer_en_construction!
|
||||||
|
Timecop.freeze(date2)
|
||||||
|
d.passer_en_instruction!(instructeur)
|
||||||
|
Timecop.freeze(date3)
|
||||||
|
d.accepter!(instructeur, "Motivation", nil)
|
||||||
|
Timecop.return
|
||||||
|
d
|
||||||
|
end
|
||||||
|
|
||||||
describe "followers_instructeurs" do
|
describe "followers_instructeurs" do
|
||||||
let(:non_following_instructeur) { create(:instructeur) }
|
let(:non_following_instructeur) { create(:instructeur) }
|
||||||
|
@ -346,13 +355,14 @@ describe Dossier do
|
||||||
let(:state) { Dossier.states.fetch(:brouillon) }
|
let(:state) { Dossier.states.fetch(:brouillon) }
|
||||||
let(:dossier) { create(:dossier, state: state) }
|
let(:dossier) { create(:dossier, state: state) }
|
||||||
let(:beginning_of_day) { Time.zone.now.beginning_of_day }
|
let(:beginning_of_day) { Time.zone.now.beginning_of_day }
|
||||||
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
|
||||||
before { Timecop.freeze(beginning_of_day) }
|
before { Timecop.freeze(beginning_of_day) }
|
||||||
after { Timecop.return }
|
after { Timecop.return }
|
||||||
|
|
||||||
context 'when dossier is en_construction' do
|
context 'when dossier is en_construction' do
|
||||||
before do
|
before do
|
||||||
dossier.en_construction!
|
dossier.passer_en_construction!
|
||||||
dossier.reload
|
dossier.reload
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -361,8 +371,8 @@ describe Dossier do
|
||||||
|
|
||||||
it 'should keep first en_construction_at date' do
|
it 'should keep first en_construction_at date' do
|
||||||
Timecop.return
|
Timecop.return
|
||||||
dossier.en_instruction!
|
dossier.passer_en_instruction!(instructeur)
|
||||||
dossier.en_construction!
|
dossier.repasser_en_construction!(instructeur)
|
||||||
|
|
||||||
expect(dossier.en_construction_at).to eq(beginning_of_day)
|
expect(dossier.en_construction_at).to eq(beginning_of_day)
|
||||||
end
|
end
|
||||||
|
@ -370,9 +380,10 @@ describe Dossier do
|
||||||
|
|
||||||
context 'when dossier is en_instruction' do
|
context 'when dossier is en_instruction' do
|
||||||
let(:state) { Dossier.states.fetch(:en_construction) }
|
let(:state) { Dossier.states.fetch(:en_construction) }
|
||||||
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
dossier.en_instruction!
|
dossier.passer_en_instruction!(instructeur)
|
||||||
dossier.reload
|
dossier.reload
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -381,39 +392,48 @@ describe Dossier do
|
||||||
|
|
||||||
it 'should keep first en_instruction_at date if dossier is set to en_construction again' do
|
it 'should keep first en_instruction_at date if dossier is set to en_construction again' do
|
||||||
Timecop.return
|
Timecop.return
|
||||||
dossier.en_construction!
|
dossier.repasser_en_construction!(instructeur)
|
||||||
dossier.en_instruction!
|
dossier.passer_en_instruction!(instructeur)
|
||||||
|
|
||||||
expect(dossier.en_instruction_at).to eq(beginning_of_day)
|
expect(dossier.en_instruction_at).to eq(beginning_of_day)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_examples 'dossier is processed' do |new_state|
|
|
||||||
before do
|
|
||||||
dossier.update(state: new_state)
|
|
||||||
dossier.reload
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(dossier.state).to eq(new_state) }
|
|
||||||
it { expect(dossier.processed_at).to eq(beginning_of_day) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when dossier is accepte' do
|
context 'when dossier is accepte' do
|
||||||
let(:state) { Dossier.states.fetch(:en_instruction) }
|
let(:state) { Dossier.states.fetch(:en_instruction) }
|
||||||
|
|
||||||
it_behaves_like 'dossier is processed', Dossier.states.fetch(:accepte)
|
before do
|
||||||
|
dossier.accepter!(instructeur, nil, nil)
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect(dossier.state).to eq(Dossier.states.fetch(:accepte)) }
|
||||||
|
it { expect(dossier.traitements.last.processed_at).to eq(beginning_of_day) }
|
||||||
|
it { expect(dossier.processed_at).to eq(beginning_of_day) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when dossier is refuse' do
|
context 'when dossier is refuse' do
|
||||||
let(:state) { Dossier.states.fetch(:en_instruction) }
|
let(:state) { Dossier.states.fetch(:en_instruction) }
|
||||||
|
|
||||||
it_behaves_like 'dossier is processed', Dossier.states.fetch(:refuse)
|
before do
|
||||||
|
dossier.refuser!(instructeur, nil, nil)
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect(dossier.state).to eq(Dossier.states.fetch(:refuse)) }
|
||||||
|
it { expect(dossier.processed_at).to eq(beginning_of_day) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when dossier is sans_suite' do
|
context 'when dossier is sans_suite' do
|
||||||
let(:state) { Dossier.states.fetch(:en_instruction) }
|
let(:state) { Dossier.states.fetch(:en_instruction) }
|
||||||
|
|
||||||
it_behaves_like 'dossier is processed', Dossier.states.fetch(:sans_suite)
|
before do
|
||||||
|
dossier.classer_sans_suite!(instructeur, nil, nil)
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect(dossier.state).to eq(Dossier.states.fetch(:sans_suite)) }
|
||||||
|
it { expect(dossier.processed_at).to eq(beginning_of_day) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -478,13 +498,14 @@ describe Dossier do
|
||||||
describe "#send_dossier_received" do
|
describe "#send_dossier_received" do
|
||||||
let(:procedure) { create(:procedure) }
|
let(:procedure) { create(:procedure) }
|
||||||
let(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction)) }
|
let(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction)) }
|
||||||
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(NotificationMailer).to receive(:send_dossier_received).and_return(double(deliver_later: nil))
|
allow(NotificationMailer).to receive(:send_dossier_received).and_return(double(deliver_later: nil))
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sends an email when the dossier becomes en_instruction" do
|
it "sends an email when the dossier becomes en_instruction" do
|
||||||
dossier.en_instruction!
|
dossier.passer_en_instruction!(instructeur)
|
||||||
expect(NotificationMailer).to have_received(:send_dossier_received).with(dossier)
|
expect(NotificationMailer).to have_received(:send_dossier_received).with(dossier)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -777,6 +798,7 @@ describe Dossier do
|
||||||
|
|
||||||
describe 'webhook' do
|
describe 'webhook' do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:dossier) { create(:dossier) }
|
||||||
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
|
||||||
it 'should not call webhook' do
|
it 'should not call webhook' do
|
||||||
expect {
|
expect {
|
||||||
|
@ -788,19 +810,19 @@ describe Dossier do
|
||||||
dossier.procedure.update_column(:web_hook_url, '/webhook.json')
|
dossier.procedure.update_column(:web_hook_url, '/webhook.json')
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
dossier.update_column(:motivation, 'bonjour')
|
dossier.update_column(:search_terms, 'bonjour')
|
||||||
}.to_not have_enqueued_job(WebHookJob)
|
}.to_not have_enqueued_job(WebHookJob)
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
dossier.en_construction!
|
dossier.passer_en_construction!
|
||||||
}.to have_enqueued_job(WebHookJob)
|
}.to have_enqueued_job(WebHookJob)
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
dossier.update_column(:motivation, 'bonjour2')
|
dossier.update_column(:search_terms, 'bonjour2')
|
||||||
}.to_not have_enqueued_job(WebHookJob)
|
}.to_not have_enqueued_job(WebHookJob)
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
dossier.en_instruction!
|
dossier.passer_en_instruction!(instructeur)
|
||||||
}.to have_enqueued_job(WebHookJob)
|
}.to have_enqueued_job(WebHookJob)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -891,8 +913,11 @@ describe Dossier do
|
||||||
|
|
||||||
after { Timecop.return }
|
after { Timecop.return }
|
||||||
|
|
||||||
|
it { expect(dossier.traitements.last.motivation).to eq('motivation') }
|
||||||
it { expect(dossier.motivation).to eq('motivation') }
|
it { expect(dossier.motivation).to eq('motivation') }
|
||||||
|
it { expect(dossier.traitements.last.instructeur_email).to eq(instructeur.email) }
|
||||||
it { expect(dossier.en_instruction_at).to eq(dossier.en_instruction_at) }
|
it { expect(dossier.en_instruction_at).to eq(dossier.en_instruction_at) }
|
||||||
|
it { expect(dossier.traitements.last.processed_at).to eq(now) }
|
||||||
it { expect(dossier.processed_at).to eq(now) }
|
it { expect(dossier.processed_at).to eq(now) }
|
||||||
it { expect(dossier.state).to eq('accepte') }
|
it { expect(dossier.state).to eq('accepte') }
|
||||||
it { expect(last_operation.operation).to eq('accepter') }
|
it { expect(last_operation.operation).to eq('accepter') }
|
||||||
|
|
|
@ -478,7 +478,7 @@ describe Instructeur, type: :model do
|
||||||
before do
|
before do
|
||||||
procedure_to_assign.update(declarative_with_state: "accepte")
|
procedure_to_assign.update(declarative_with_state: "accepte")
|
||||||
DeclarativeProceduresJob.new.perform
|
DeclarativeProceduresJob.new.perform
|
||||||
dossier.update(processed_at: Time.zone.yesterday.beginning_of_day)
|
dossier.traitements.last.update(processed_at: Time.zone.yesterday.beginning_of_day)
|
||||||
dossier.reload
|
dossier.reload
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -205,6 +205,13 @@ describe Procedure do
|
||||||
it { expect(procedure.valid?).to eq(false) }
|
it { expect(procedure.valid?).to eq(false) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'api_entreprise_token' do
|
||||||
|
let(:valid_token) { "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" }
|
||||||
|
let(:invalid_token) { 'plouf' }
|
||||||
|
it { is_expected.to allow_value(valid_token).for(:api_entreprise_token) }
|
||||||
|
it { is_expected.not_to allow_value(invalid_token).for(:api_entreprise_token) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when juridique_required is false' do
|
context 'when juridique_required is false' do
|
||||||
|
@ -335,7 +342,7 @@ describe Procedure do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'api_entreprise_token_expired?' do
|
describe 'api_entreprise_token_expired?' do
|
||||||
let(:token) { "mon-token" }
|
let(:token) { "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" }
|
||||||
let(:procedure) { create(:procedure, api_entreprise_token: token) }
|
let(:procedure) { create(:procedure, api_entreprise_token: token) }
|
||||||
let(:payload) {
|
let(:payload) {
|
||||||
[
|
[
|
||||||
|
@ -958,8 +965,7 @@ describe Procedure do
|
||||||
let(:procedure) { create(:procedure) }
|
let(:procedure) { create(:procedure) }
|
||||||
|
|
||||||
def create_dossier(construction_date:, instruction_date:, processed_date:)
|
def create_dossier(construction_date:, instruction_date:, processed_date:)
|
||||||
dossier = create(:dossier, :accepte, procedure: procedure)
|
dossier = create(:dossier, :accepte, procedure: procedure, en_construction_at: construction_date, en_instruction_at: instruction_date, processed_at: processed_date)
|
||||||
dossier.update!(en_construction_at: construction_date, en_instruction_at: instruction_date, processed_at: processed_date)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
|
|
@ -48,7 +48,7 @@ shared_examples 'type_de_champ_spec' do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'remove piece_justificative_template' do
|
context 'changing the type_champ from a piece_justificative' do
|
||||||
context 'when the tdc is piece_justificative' do
|
context 'when the tdc is piece_justificative' do
|
||||||
let(:template_double) { double('template', attached?: attached, purge_later: true) }
|
let(:template_double) { double('template', attached?: attached, purge_later: true) }
|
||||||
let(:tdc) { create(:type_de_champ_piece_justificative) }
|
let(:tdc) { create(:type_de_champ_piece_justificative) }
|
||||||
|
@ -89,6 +89,48 @@ shared_examples 'type_de_champ_spec' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'changing the type_champ from a repetition' do
|
||||||
|
let(:tdc) { create(:type_de_champ_repetition, :with_types_de_champ) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
tdc.update_attribute('type_champ', target_type_champ)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the target type_champ is not repetition' do
|
||||||
|
let(:target_type_champ) { TypeDeChamp.type_champs.fetch(:text) }
|
||||||
|
|
||||||
|
it 'removes the children types de champ' do
|
||||||
|
expect(tdc.types_de_champ).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'changing the type_champ from a drop_down_list' do
|
||||||
|
let(:tdc) { create(:type_de_champ_drop_down_list) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
tdc.update_attribute('type_champ', target_type_champ)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the target type_champ is not drop_down_list' do
|
||||||
|
let(:target_type_champ) { TypeDeChamp.type_champs.fetch(:text) }
|
||||||
|
|
||||||
|
it { expect(tdc.drop_down_options).to be_nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the target type_champ is linked_drop_down_list' do
|
||||||
|
let(:target_type_champ) { TypeDeChamp.type_champs.fetch(:linked_drop_down_list) }
|
||||||
|
|
||||||
|
it { expect(tdc.drop_down_options).to be_present }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the target type_champ is multiple_drop_down_list' do
|
||||||
|
let(:target_type_champ) { TypeDeChamp.type_champs.fetch(:multiple_drop_down_list) }
|
||||||
|
|
||||||
|
it { expect(tdc.drop_down_options).to be_present }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'delegate validation to dynamic type' do
|
context 'delegate validation to dynamic type' do
|
||||||
subject { build(:type_de_champ_text) }
|
subject { build(:type_de_champ_text) }
|
||||||
let(:dynamic_type) do
|
let(:dynamic_type) do
|
||||||
|
|
|
@ -8,7 +8,8 @@ describe ApiEntrepriseService do
|
||||||
let(:siret) { '41816609600051' }
|
let(:siret) { '41816609600051' }
|
||||||
let(:etablissements_status) { 200 }
|
let(:etablissements_status) { 200 }
|
||||||
let(:etablissements_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') }
|
let(:etablissements_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') }
|
||||||
let(:procedure) { create(:procedure, api_entreprise_token: 'un-jeton') }
|
let(:valid_token) { "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" }
|
||||||
|
let(:procedure) { create(:procedure, api_entreprise_token: valid_token) }
|
||||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||||
let(:subject) { ApiEntrepriseService.create_etablissement(dossier, siret, procedure.id) }
|
let(:subject) { ApiEntrepriseService.create_etablissement(dossier, siret, procedure.id) }
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ describe NotificationService do
|
||||||
before do
|
before do
|
||||||
procedure.update(declarative_with_state: "accepte")
|
procedure.update(declarative_with_state: "accepte")
|
||||||
DeclarativeProceduresJob.new.perform
|
DeclarativeProceduresJob.new.perform
|
||||||
dossier.update(processed_at: Time.zone.yesterday.beginning_of_day)
|
dossier.traitements.last.update!(processed_at: Time.zone.yesterday.beginning_of_day)
|
||||||
dossier.reload
|
dossier.reload
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue