commit
906b226049
42 changed files with 469 additions and 132 deletions
|
@ -67,10 +67,6 @@ class ApplicationController < ActionController::Base
|
||||||
Flipper.enabled?(feature_name, current_user)
|
Flipper.enabled?(feature_name, current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def feature_enabled_for?(feature_name, item)
|
|
||||||
Flipper.enabled?(feature_name, item)
|
|
||||||
end
|
|
||||||
|
|
||||||
def authenticate_logged_user!
|
def authenticate_logged_user!
|
||||||
if instructeur_signed_in?
|
if instructeur_signed_in?
|
||||||
authenticate_instructeur!
|
authenticate_instructeur!
|
||||||
|
|
|
@ -72,7 +72,7 @@ module Instructeurs
|
||||||
|
|
||||||
def create_avis
|
def create_avis
|
||||||
@procedure = Procedure.find(params[:procedure_id])
|
@procedure = Procedure.find(params[:procedure_id])
|
||||||
if !feature_enabled_for?(:expert_not_allowed_to_invite, @procedure)
|
if !@procedure.feature_enabled?(:expert_not_allowed_to_invite)
|
||||||
@new_avis = create_avis_from_params(avis.dossier, avis.confidentiel)
|
@new_avis = create_avis_from_params(avis.dossier, avis.confidentiel)
|
||||||
|
|
||||||
if @new_avis.nil?
|
if @new_avis.nil?
|
||||||
|
|
|
@ -72,7 +72,8 @@ module Instructeurs
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_to_instructeurs
|
def send_to_instructeurs
|
||||||
recipients = Instructeur.find(JSON.parse(params[:recipients]))
|
recipients = params['recipients'].presence || [].to_json
|
||||||
|
recipients = Instructeur.find(JSON.parse(recipients))
|
||||||
|
|
||||||
recipients.each do |recipient|
|
recipients.each do |recipient|
|
||||||
recipient.follow(dossier)
|
recipient.follow(dossier)
|
||||||
|
|
|
@ -138,7 +138,8 @@ module Instructeurs
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_displayed_fields
|
def update_displayed_fields
|
||||||
procedure_presentation.update_displayed_fields(JSON.parse(params[:values]))
|
values = params['values'].presence || [].to_json
|
||||||
|
procedure_presentation.update_displayed_fields(JSON.parse(values))
|
||||||
|
|
||||||
redirect_back(fallback_location: instructeur_procedure_url(procedure))
|
redirect_back(fallback_location: instructeur_procedure_url(procedure))
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,32 @@ class API::V2::Context < GraphQL::Query::Context
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def internal_use?
|
||||||
|
self[:internal_use]
|
||||||
|
end
|
||||||
|
|
||||||
|
def authorized_demarche?(demarche)
|
||||||
|
if internal_use?
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
# We are caching authorization logic because it is called for each node
|
||||||
|
# of the requested graph and can be expensive. Context is reset per request so it is safe.
|
||||||
|
self[:authorized] ||= Hash.new do |hash, demarche_id|
|
||||||
|
# Compute the hash value dynamically when first requested
|
||||||
|
authorized_administrateur = demarche.administrateurs.find do |administrateur|
|
||||||
|
if self[:token]
|
||||||
|
administrateur.valid_api_token?(self[:token])
|
||||||
|
else
|
||||||
|
administrateur.id == self[:administrateur_id]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
hash[demarche_id] = authorized_administrateur.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
self[:authorized][demarche.id]
|
||||||
|
end
|
||||||
|
|
||||||
class HasFragment < GraphQL::Language::Visitor
|
class HasFragment < GraphQL::Language::Visitor
|
||||||
def initialize(document, name)
|
def initialize(document, name)
|
||||||
super(document)
|
super(document)
|
||||||
|
|
27
app/graphql/loaders/champ.rb
Normal file
27
app/graphql/loaders/champ.rb
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# references:
|
||||||
|
# https://github.com/Shopify/graphql-batch/blob/master/examples/record_loader.rb
|
||||||
|
|
||||||
|
module Loaders
|
||||||
|
class Champ < GraphQL::Batch::Loader
|
||||||
|
def initialize(dossier, private: false)
|
||||||
|
@where = { dossier: dossier, private: private }
|
||||||
|
end
|
||||||
|
|
||||||
|
def load(key)
|
||||||
|
super(key.to_i)
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform(keys)
|
||||||
|
query(keys).each { |record| fulfill(record.stable_id, [record].compact) }
|
||||||
|
keys.each { |key| fulfill(key, nil) unless fulfilled?(key) }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def query(keys)
|
||||||
|
::Champ.where(@where)
|
||||||
|
.includes(:type_de_champ)
|
||||||
|
.where(types_de_champ: { stable_id: keys })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,11 +3,13 @@
|
||||||
|
|
||||||
module Loaders
|
module Loaders
|
||||||
class Record < GraphQL::Batch::Loader
|
class Record < GraphQL::Batch::Loader
|
||||||
def initialize(model, column: model.primary_key, where: nil)
|
def initialize(model, column: model.primary_key, where: nil, includes: nil, array: false)
|
||||||
@model = model
|
@model = model
|
||||||
@column = column.to_s
|
@column = column.to_s
|
||||||
@column_type = model.type_for_attribute(@column)
|
@column_type = model.type_for_attribute(@column)
|
||||||
@where = where
|
@where = where
|
||||||
|
@includes = includes
|
||||||
|
@array = array
|
||||||
end
|
end
|
||||||
|
|
||||||
def load(key)
|
def load(key)
|
||||||
|
@ -15,7 +17,10 @@ module Loaders
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform(keys)
|
def perform(keys)
|
||||||
query(keys).each { |record| fulfill(record.public_send(@column), record) }
|
query(keys).each do |record|
|
||||||
|
fulfilled_value = @array ? [record].compact : record
|
||||||
|
fulfill(record.public_send(@column), fulfilled_value)
|
||||||
|
end
|
||||||
keys.each { |key| fulfill(key, nil) unless fulfilled?(key) }
|
keys.each { |key| fulfill(key, nil) unless fulfilled?(key) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -24,6 +29,7 @@ module Loaders
|
||||||
def query(keys)
|
def query(keys)
|
||||||
scope = @model
|
scope = @model
|
||||||
scope = scope.where(@where) if @where
|
scope = scope.where(@where) if @where
|
||||||
|
scope = scope.includes(@includes) if @includes
|
||||||
scope.where(@column => keys)
|
scope.where(@column => keys)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -508,15 +508,15 @@ type DirectUpload {
|
||||||
Un dossier
|
Un dossier
|
||||||
"""
|
"""
|
||||||
type Dossier {
|
type Dossier {
|
||||||
annotations: [Champ!]!
|
annotations(id: ID): [Champ!]!
|
||||||
archived: Boolean!
|
archived: Boolean!
|
||||||
|
|
||||||
"""
|
"""
|
||||||
L’URL de l’attestation au format PDF.
|
L’URL de l’attestation au format PDF.
|
||||||
"""
|
"""
|
||||||
attestation: File
|
attestation: File
|
||||||
avis: [Avis!]!
|
avis(id: ID): [Avis!]!
|
||||||
champs: [Champ!]!
|
champs(id: ID): [Champ!]!
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Date de la dernière modification.
|
Date de la dernière modification.
|
||||||
|
@ -546,7 +546,7 @@ type Dossier {
|
||||||
groupeInstructeur: GroupeInstructeur!
|
groupeInstructeur: GroupeInstructeur!
|
||||||
id: ID!
|
id: ID!
|
||||||
instructeurs: [Profile!]!
|
instructeurs: [Profile!]!
|
||||||
messages: [Message!]!
|
messages(id: ID): [Message!]!
|
||||||
motivation: String
|
motivation: String
|
||||||
motivationAttachment: File
|
motivationAttachment: File
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,4 @@
|
||||||
module Types
|
module Types
|
||||||
class BaseObject < GraphQL::Schema::Object
|
class BaseObject < GraphQL::Schema::Object
|
||||||
def self.authorized_demarche?(demarche, context)
|
|
||||||
# We are caching authorization logic because it is called for each node
|
|
||||||
# of the requested graph and can be expensive. Context is reset per request so it is safe.
|
|
||||||
context[:authorized] ||= {}
|
|
||||||
if context[:authorized][demarche.id]
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
administrateur = demarche.administrateurs.find do |administrateur|
|
|
||||||
if context[:token]
|
|
||||||
administrateur.valid_api_token?(context[:token])
|
|
||||||
else
|
|
||||||
administrateur.id == context[:administrateur_id]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if administrateur
|
|
||||||
context[:authorized][demarche.id] = true
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -88,7 +88,7 @@ module Types
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.authorized?(object, context)
|
def self.authorized?(object, context)
|
||||||
authorized_demarche?(object, context)
|
context.authorized_demarche?(object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,11 +35,19 @@ module Types
|
||||||
field :demandeur, Types::DemandeurType, null: false
|
field :demandeur, Types::DemandeurType, null: false
|
||||||
|
|
||||||
field :instructeurs, [Types::ProfileType], null: false
|
field :instructeurs, [Types::ProfileType], null: false
|
||||||
field :messages, [Types::MessageType], null: false
|
|
||||||
field :avis, [Types::AvisType], null: false
|
|
||||||
|
|
||||||
field :champs, [Types::ChampType], null: false
|
field :messages, [Types::MessageType], null: false do
|
||||||
field :annotations, [Types::ChampType], null: false
|
argument :id, ID, required: false
|
||||||
|
end
|
||||||
|
field :avis, [Types::AvisType], null: false do
|
||||||
|
argument :id, ID, required: false
|
||||||
|
end
|
||||||
|
field :champs, [Types::ChampType], null: false do
|
||||||
|
argument :id, ID, required: false
|
||||||
|
end
|
||||||
|
field :annotations, [Types::ChampType], null: false do
|
||||||
|
argument :id, ID, required: false
|
||||||
|
end
|
||||||
|
|
||||||
def state
|
def state
|
||||||
object.state
|
object.state
|
||||||
|
@ -69,20 +77,44 @@ module Types
|
||||||
Loaders::Association.for(object.class, :followers_instructeurs).load(object)
|
Loaders::Association.for(object.class, :followers_instructeurs).load(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def messages
|
def messages(id: nil)
|
||||||
Loaders::Association.for(object.class, commentaires: [:instructeur, :user]).load(object)
|
if id.present?
|
||||||
|
Loaders::Record
|
||||||
|
.for(Commentaire, where: { dossier: object }, includes: [:instructeur, :user], array: true)
|
||||||
|
.load(ApplicationRecord.id_from_typed_id(id))
|
||||||
|
else
|
||||||
|
Loaders::Association.for(object.class, commentaires: [:instructeur, :user]).load(object)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def avis
|
def avis(id: nil)
|
||||||
Loaders::Association.for(object.class, avis: [:instructeur, :claimant]).load(object)
|
if id.present?
|
||||||
|
Loaders::Record
|
||||||
|
.for(Avis, where: { dossier: object }, includes: [:instructeur, :claimant], array: true)
|
||||||
|
.load(ApplicationRecord.id_from_typed_id(id))
|
||||||
|
else
|
||||||
|
Loaders::Association.for(object.class, avis: [:instructeur, :claimant]).load(object)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def champs
|
def champs(id: nil)
|
||||||
Loaders::Association.for(object.class, champs: [:type_de_champ]).load(object)
|
if id.present?
|
||||||
|
Loaders::Champ
|
||||||
|
.for(object, private: false)
|
||||||
|
.load(ApplicationRecord.id_from_typed_id(id))
|
||||||
|
else
|
||||||
|
Loaders::Association.for(object.class, champs: :type_de_champ).load(object)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def annotations
|
def annotations(id: nil)
|
||||||
Loaders::Association.for(object.class, champs_private: [:type_de_champ]).load(object)
|
if id.present?
|
||||||
|
Loaders::Champ
|
||||||
|
.for(object, private: true)
|
||||||
|
.load(ApplicationRecord.id_from_typed_id(id))
|
||||||
|
else
|
||||||
|
Loaders::Association.for(object.class, champs_private: :type_de_champ).load(object)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def pdf
|
def pdf
|
||||||
|
@ -110,7 +142,7 @@ module Types
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.authorized?(object, context)
|
def self.authorized?(object, context)
|
||||||
authorized_demarche?(object.procedure, context)
|
context.authorized_demarche?(object.procedure)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,7 @@ module Types
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.authorized?(object, context)
|
def self.authorized?(object, context)
|
||||||
authorized_demarche?(object.procedure, context)
|
context.authorized_demarche?(object.procedure)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,7 +19,11 @@ module Types
|
||||||
end
|
end
|
||||||
|
|
||||||
def dossier(number:)
|
def dossier(number:)
|
||||||
Dossier.state_not_brouillon.for_api_v2.find(number)
|
if context.internal_use?
|
||||||
|
Dossier.state_not_brouillon.with_discarded.for_api_v2.find(number)
|
||||||
|
else
|
||||||
|
Dossier.state_not_brouillon.for_api_v2.find(number)
|
||||||
|
end
|
||||||
rescue => e
|
rescue => e
|
||||||
raise GraphQL::ExecutionError.new(e.message, extensions: { code: :not_found })
|
raise GraphQL::ExecutionError.new(e.message, extensions: { code: :not_found })
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,8 +2,4 @@ module FlipperHelper
|
||||||
def feature_enabled?(feature_name)
|
def feature_enabled?(feature_name)
|
||||||
Flipper.enabled?(feature_name, current_user)
|
Flipper.enabled?(feature_name, current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def feature_enabled_for?(feature_name, item)
|
|
||||||
Flipper.enabled?(feature_name, item)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const queryClient = new QueryClient({
|
||||||
});
|
});
|
||||||
|
|
||||||
function buildURL(scope, term) {
|
function buildURL(scope, term) {
|
||||||
term = encodeURIComponent(term);
|
term = encodeURIComponent(term.replace(/\(|\)/g, ''));
|
||||||
if (scope === 'adresse') {
|
if (scope === 'adresse') {
|
||||||
return `${api_adresse_url}/search?q=${term}&limit=5`;
|
return `${api_adresse_url}/search?q=${term}&limit=5`;
|
||||||
} else if (scope === 'annuaire-education') {
|
} else if (scope === 'annuaire-education') {
|
||||||
|
@ -42,7 +42,12 @@ async function defaultQueryFn({ queryKey: [scope, term] }) {
|
||||||
|
|
||||||
const url = buildURL(scope, term);
|
const url = buildURL(scope, term);
|
||||||
const [options, controller] = buildOptions();
|
const [options, controller] = buildOptions();
|
||||||
const promise = fetch(url, options).then((response) => response.json());
|
const promise = fetch(url, options).then((response) => {
|
||||||
|
if (response.ok) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
throw new Error(`Error fetching from "${scope}" API`);
|
||||||
|
});
|
||||||
promise.cancel = () => controller && controller.abort();
|
promise.cancel = () => controller && controller.abort();
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,10 @@ class ApplicationRecord < ActiveRecord::Base
|
||||||
raise ActiveRecord::RecordNotFound, e.message
|
raise ActiveRecord::RecordNotFound, e.message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.id_from_typed_id(id)
|
||||||
|
GraphQL::Schema::UniqueWithinType.decode(id)[1]
|
||||||
|
end
|
||||||
|
|
||||||
def to_typed_id
|
def to_typed_id
|
||||||
GraphQL::Schema::UniqueWithinType.encode(self.class.name, id)
|
GraphQL::Schema::UniqueWithinType.encode(self.class.name, id)
|
||||||
end
|
end
|
||||||
|
|
|
@ -418,6 +418,14 @@ class Dossier < ApplicationRecord
|
||||||
Dossier.en_construction_close_to_expiration.where(id: self).present?
|
Dossier.en_construction_close_to_expiration.where(id: self).present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show_groupe_instructeur_details?
|
||||||
|
procedure.routee? && (!procedure.feature_enabled?(:procedure_routage_api) || !defaut_groupe_instructeur?)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_groupe_instructeur_selector?
|
||||||
|
procedure.routee? && !procedure.feature_enabled?(:procedure_routage_api)
|
||||||
|
end
|
||||||
|
|
||||||
def assign_to_groupe_instructeur(groupe_instructeur, author = nil)
|
def assign_to_groupe_instructeur(groupe_instructeur, author = nil)
|
||||||
if groupe_instructeur.procedure == procedure && groupe_instructeur != self.groupe_instructeur
|
if groupe_instructeur.procedure == procedure && groupe_instructeur != self.groupe_instructeur
|
||||||
if update(groupe_instructeur: groupe_instructeur, groupe_instructeur_updated_at: Time.zone.now)
|
if update(groupe_instructeur: groupe_instructeur, groupe_instructeur_updated_at: Time.zone.now)
|
||||||
|
@ -832,6 +840,10 @@ class Dossier < ApplicationRecord
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def defaut_groupe_instructeur?
|
||||||
|
groupe_instructeur == procedure.defaut_groupe_instructeur
|
||||||
|
end
|
||||||
|
|
||||||
def geo_areas
|
def geo_areas
|
||||||
champs.includes(:geo_areas).flat_map(&:geo_areas) + champs_private.includes(:geo_areas).flat_map(&:geo_areas)
|
champs.includes(:geo_areas).flat_map(&:geo_areas) + champs_private.includes(:geo_areas).flat_map(&:geo_areas)
|
||||||
end
|
end
|
||||||
|
|
|
@ -80,7 +80,25 @@ class DossierOperationLog < ApplicationRecord
|
||||||
if author.nil?
|
if author.nil?
|
||||||
nil
|
nil
|
||||||
else
|
else
|
||||||
OperationAuthorSerializer.new(author).as_json
|
{
|
||||||
|
id: serialize_author_id(author),
|
||||||
|
email: author.email
|
||||||
|
}.as_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.serialize_author_id(object)
|
||||||
|
case object
|
||||||
|
when User
|
||||||
|
"Usager##{object.id}"
|
||||||
|
when Instructeur
|
||||||
|
"Instructeur##{object.id}"
|
||||||
|
when Administrateur
|
||||||
|
"Administrateur##{object.id}"
|
||||||
|
when SuperAdmin
|
||||||
|
"Manager##{object.id}"
|
||||||
|
else
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -96,11 +114,11 @@ class DossierOperationLog < ApplicationRecord
|
||||||
else
|
else
|
||||||
case subject
|
case subject
|
||||||
when Dossier
|
when Dossier
|
||||||
DossierSerializer.new(subject).as_json
|
SerializerService.dossier(subject)
|
||||||
when Champ
|
when Champ
|
||||||
ChampSerializer.new(subject).as_json
|
SerializerService.champ(subject)
|
||||||
when Avis
|
when Avis
|
||||||
AvisSerializer.new(subject).as_json
|
SerializerService.avis(subject)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
# procedure_id :bigint not null
|
# procedure_id :bigint not null
|
||||||
#
|
#
|
||||||
class GroupeInstructeur < ApplicationRecord
|
class GroupeInstructeur < ApplicationRecord
|
||||||
DEFAULT_LABEL = 'défaut'
|
DEFAUT_LABEL = 'défaut'
|
||||||
belongs_to :procedure, -> { with_discarded }, inverse_of: :groupe_instructeurs, optional: false
|
belongs_to :procedure, -> { with_discarded }, inverse_of: :groupe_instructeurs, optional: false
|
||||||
has_many :assign_tos, dependent: :destroy
|
has_many :assign_tos, dependent: :destroy
|
||||||
has_many :instructeurs, through: :assign_tos
|
has_many :instructeurs, through: :assign_tos
|
||||||
|
|
|
@ -135,7 +135,7 @@ class Procedure < ApplicationRecord
|
||||||
has_one :refused_mail, class_name: "Mails::RefusedMail", dependent: :destroy
|
has_one :refused_mail, class_name: "Mails::RefusedMail", dependent: :destroy
|
||||||
has_one :without_continuation_mail, class_name: "Mails::WithoutContinuationMail", dependent: :destroy
|
has_one :without_continuation_mail, class_name: "Mails::WithoutContinuationMail", dependent: :destroy
|
||||||
|
|
||||||
has_one :defaut_groupe_instructeur, -> { order(:id) }, class_name: 'GroupeInstructeur', inverse_of: :procedure
|
has_one :defaut_groupe_instructeur, -> { order(:label) }, class_name: 'GroupeInstructeur', inverse_of: :procedure
|
||||||
|
|
||||||
has_one_attached :logo
|
has_one_attached :logo
|
||||||
has_one_attached :notice
|
has_one_attached :notice
|
||||||
|
@ -221,7 +221,7 @@ class Procedure < ApplicationRecord
|
||||||
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
|
||||||
after_create :ensure_default_groupe_instructeur
|
after_create :ensure_defaut_groupe_instructeur
|
||||||
|
|
||||||
include AASM
|
include AASM
|
||||||
|
|
||||||
|
@ -342,6 +342,10 @@ class Procedure < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def feature_enabled?(feature)
|
||||||
|
Flipper.enabled?(feature, self)
|
||||||
|
end
|
||||||
|
|
||||||
# Warning: dossier after_save build_default_champs must be removed
|
# Warning: dossier after_save build_default_champs must be removed
|
||||||
# to save a dossier created from this method
|
# to save a dossier created from this method
|
||||||
def new_dossier
|
def new_dossier
|
||||||
|
@ -541,9 +545,12 @@ class Procedure < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def populate_champ_stable_ids
|
def populate_champ_stable_ids
|
||||||
TypeDeChamp.where(procedure: self, stable_id: nil).find_each do |type_de_champ|
|
TypeDeChamp
|
||||||
type_de_champ.update_column(:stable_id, type_de_champ.id)
|
.joins(:revisions)
|
||||||
end
|
.where(procedure_revisions: { procedure_id: id }, stable_id: nil)
|
||||||
|
.find_each do |type_de_champ|
|
||||||
|
type_de_champ.update_column(:stable_id, type_de_champ.id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def missing_steps
|
def missing_steps
|
||||||
|
@ -715,9 +722,9 @@ class Procedure < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_default_groupe_instructeur
|
def ensure_defaut_groupe_instructeur
|
||||||
if self.groupe_instructeurs.empty?
|
if self.groupe_instructeurs.empty?
|
||||||
groupe_instructeurs.create(label: GroupeInstructeur::DEFAULT_LABEL)
|
groupe_instructeurs.create(label: GroupeInstructeur::DEFAUT_LABEL)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
class OperationAuthorSerializer < ActiveModel::Serializer
|
|
||||||
attributes :id, :email
|
|
||||||
|
|
||||||
def id
|
|
||||||
case object
|
|
||||||
when User
|
|
||||||
"Usager##{object.id}"
|
|
||||||
when Instructeur
|
|
||||||
"Instructeur##{object.id}"
|
|
||||||
when Administrateur
|
|
||||||
"Administrateur##{object.id}"
|
|
||||||
when SuperAdmin
|
|
||||||
"Manager##{object.id}"
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
233
app/services/serializer_service.rb
Normal file
233
app/services/serializer_service.rb
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
class SerializerService
|
||||||
|
def self.dossier(dossier)
|
||||||
|
data = execute_query('serializeDossier', { number: dossier.id })
|
||||||
|
data && data['dossier']
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.avis(avis)
|
||||||
|
data = execute_query('serializeAvis', { number: avis.dossier_id, id: avis.to_typed_id })
|
||||||
|
data && data['dossier']['avis'].first
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.champ(champ)
|
||||||
|
if champ.private?
|
||||||
|
data = execute_query('serializeAnnotation', { number: champ.dossier_id, id: champ.to_typed_id })
|
||||||
|
data && data['dossier']['annotations'].first
|
||||||
|
else
|
||||||
|
data = execute_query('serializeChamp', { number: champ.dossier_id, id: champ.to_typed_id })
|
||||||
|
data && data['dossier']['champs'].first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.execute_query(operation_name, variables)
|
||||||
|
result = API::V2::Schema.execute(QUERY,
|
||||||
|
variables: variables,
|
||||||
|
context: { internal_use: true },
|
||||||
|
operation_name: operation_name)
|
||||||
|
if result['errors'].present?
|
||||||
|
raise result['errors'].first['message']
|
||||||
|
end
|
||||||
|
result['data']
|
||||||
|
end
|
||||||
|
|
||||||
|
QUERY = <<-'GRAPHQL'
|
||||||
|
query serializeDossier($number: Int!) {
|
||||||
|
dossier(number: $number) {
|
||||||
|
...DossierFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query serializeAvis($number: Int!, $id: ID!) {
|
||||||
|
dossier(number: $number) {
|
||||||
|
avis(id: $id) {
|
||||||
|
...AvisFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query serializeChamp($number: Int!, $id: ID!) {
|
||||||
|
dossier(number: $number) {
|
||||||
|
champs(id: $id) {
|
||||||
|
...RootChampFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query serializeAnnotation($number: Int!, $id: ID!) {
|
||||||
|
dossier(number: $number) {
|
||||||
|
annotations(id: $id) {
|
||||||
|
...RootChampFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment DossierFragment on Dossier {
|
||||||
|
id
|
||||||
|
number
|
||||||
|
archived
|
||||||
|
state
|
||||||
|
dateDerniereModification
|
||||||
|
datePassageEnConstruction
|
||||||
|
datePassageEnInstruction
|
||||||
|
dateTraitement
|
||||||
|
instructeurs {
|
||||||
|
email
|
||||||
|
}
|
||||||
|
groupeInstructeur {
|
||||||
|
label
|
||||||
|
}
|
||||||
|
champs {
|
||||||
|
...RootChampFragment
|
||||||
|
}
|
||||||
|
annotations {
|
||||||
|
...RootChampFragment
|
||||||
|
}
|
||||||
|
avis {
|
||||||
|
...AvisFragment
|
||||||
|
}
|
||||||
|
demandeur {
|
||||||
|
... on PersonnePhysique {
|
||||||
|
civilite
|
||||||
|
nom
|
||||||
|
prenom
|
||||||
|
dateDeNaissance
|
||||||
|
}
|
||||||
|
...PersonneMoraleFragment
|
||||||
|
}
|
||||||
|
motivation
|
||||||
|
motivationAttachment {
|
||||||
|
byteSize
|
||||||
|
checksum
|
||||||
|
filename
|
||||||
|
contentType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment AvisFragment on Avis {
|
||||||
|
id
|
||||||
|
question
|
||||||
|
reponse
|
||||||
|
dateQuestion
|
||||||
|
dateReponse
|
||||||
|
instructeur {
|
||||||
|
email
|
||||||
|
}
|
||||||
|
expert {
|
||||||
|
email
|
||||||
|
}
|
||||||
|
attachment {
|
||||||
|
byteSize
|
||||||
|
checksum
|
||||||
|
filename
|
||||||
|
contentType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment ChampFragment on Champ {
|
||||||
|
id
|
||||||
|
label
|
||||||
|
stringValue
|
||||||
|
... on SiretChamp {
|
||||||
|
etablissement {
|
||||||
|
...PersonneMoraleFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on LinkedDropDownListChamp {
|
||||||
|
primaryValue
|
||||||
|
secondaryValue
|
||||||
|
}
|
||||||
|
... on MultipleDropDownListChamp {
|
||||||
|
values
|
||||||
|
}
|
||||||
|
... on PieceJustificativeChamp {
|
||||||
|
file {
|
||||||
|
byteSize
|
||||||
|
checksum
|
||||||
|
filename
|
||||||
|
contentType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on AddressChamp {
|
||||||
|
address {
|
||||||
|
...AddressFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment RootChampFragment on Champ {
|
||||||
|
...ChampFragment
|
||||||
|
... on RepetitionChamp {
|
||||||
|
champs {
|
||||||
|
...ChampFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on CarteChamp {
|
||||||
|
geoAreas {
|
||||||
|
source
|
||||||
|
geometry {
|
||||||
|
type
|
||||||
|
coordinates
|
||||||
|
}
|
||||||
|
... on ParcelleCadastrale {
|
||||||
|
codeArr
|
||||||
|
codeCom
|
||||||
|
codeDep
|
||||||
|
feuille
|
||||||
|
nomCom
|
||||||
|
numero
|
||||||
|
section
|
||||||
|
surfaceParcelle
|
||||||
|
surfaceIntersection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment PersonneMoraleFragment on PersonneMorale {
|
||||||
|
siret
|
||||||
|
siegeSocial
|
||||||
|
naf
|
||||||
|
libelleNaf
|
||||||
|
address {
|
||||||
|
...AddressFragment
|
||||||
|
}
|
||||||
|
entreprise {
|
||||||
|
siren
|
||||||
|
capitalSocial
|
||||||
|
numeroTvaIntracommunautaire
|
||||||
|
formeJuridique
|
||||||
|
formeJuridiqueCode
|
||||||
|
nomCommercial
|
||||||
|
raisonSociale
|
||||||
|
siretSiegeSocial
|
||||||
|
codeEffectifEntreprise
|
||||||
|
dateCreation
|
||||||
|
nom
|
||||||
|
prenom
|
||||||
|
}
|
||||||
|
association {
|
||||||
|
rna
|
||||||
|
titre
|
||||||
|
objet
|
||||||
|
dateCreation
|
||||||
|
dateDeclaration
|
||||||
|
datePublication
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment AddressFragment on Address {
|
||||||
|
label
|
||||||
|
type
|
||||||
|
streetAddress
|
||||||
|
streetNumber
|
||||||
|
streetName
|
||||||
|
postalCode
|
||||||
|
cityName
|
||||||
|
cityCode
|
||||||
|
departmentName
|
||||||
|
departmentCode
|
||||||
|
regionName
|
||||||
|
regionCode
|
||||||
|
}
|
||||||
|
GRAPHQL
|
||||||
|
end
|
|
@ -41,7 +41,7 @@
|
||||||
= link_to 'Voir mes dossiers en cours', dossiers_path, class: ['button large expand primary']
|
= link_to 'Voir mes dossiers en cours', dossiers_path, class: ['button large expand primary']
|
||||||
= link_to 'Commencer un nouveau dossier', url_for_new_dossier(@procedure), class: ['button large expand']
|
= link_to 'Commencer un nouveau dossier', url_for_new_dossier(@procedure), class: ['button large expand']
|
||||||
|
|
||||||
- if feature_enabled_for?(:dossier_pdf_vide, @procedure)
|
- if @procedure.feature_enabled?(:dossier_pdf_vide)
|
||||||
- pdf_link = commencer_dossier_vide_path(path: @procedure.path)
|
- pdf_link = commencer_dossier_vide_path(path: @procedure.path)
|
||||||
- if @procedure.brouillon?
|
- if @procedure.brouillon?
|
||||||
- pdf_link = commencer_dossier_vide_test_path(path: @procedure.path)
|
- pdf_link = commencer_dossier_vide_test_path(path: @procedure.path)
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
.send-wrapper
|
.send-wrapper
|
||||||
= f.submit 'Envoyer votre avis', class: 'button send'
|
= f.submit 'Envoyer votre avis', class: 'button send'
|
||||||
|
|
||||||
- if !@dossier.termine? && !feature_enabled_for?(:expert_not_allowed_to_invite, @avis.procedure)
|
- if !@dossier.termine? && !@avis.procedure.feature_enabled?(:expert_not_allowed_to_invite)
|
||||||
= render partial: "instructeurs/shared/avis/form", locals: { url: avis_instructeur_avis_path(@avis.procedure, @avis), linked_dossiers: @dossier.linked_dossiers_for(current_instructeur), must_be_confidentiel: @avis.confidentiel?, avis: @new_avis }
|
= render partial: "instructeurs/shared/avis/form", locals: { url: avis_instructeur_avis_path(@avis.procedure, @avis), linked_dossiers: @dossier.linked_dossiers_for(current_instructeur), must_be_confidentiel: @avis.confidentiel?, avis: @new_avis }
|
||||||
|
|
||||||
- if @dossier.avis_for(current_instructeur).present?
|
- if @dossier.avis_for(current_instructeur).present?
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
-# only display the coronavirus to usagers (instructeurs know there are delays) when they are logged in, or on the public pages.
|
-# only display the coronavirus to usagers (instructeurs know there are delays) when they are logged in, or on the public pages.
|
||||||
- if user_signed_in?
|
- if user_signed_in?
|
||||||
- if dossier.present? && feature_enabled_for?(:coronavirus_banner, dossier.procedure)
|
- if dossier.present? && dossier.procedure.feature_enabled?(:coronavirus_banner)
|
||||||
= render partial: 'layouts/coronavirus_banner'
|
= render partial: 'layouts/coronavirus_banner'
|
||||||
- else
|
- else
|
||||||
- if procedure.present? && feature_enabled_for?(:coronavirus_banner, procedure)
|
- if procedure.present? && procedure.feature_enabled?(:coronavirus_banner)
|
||||||
= render partial: 'layouts/coronavirus_banner'
|
= render partial: 'layouts/coronavirus_banner'
|
||||||
|
|
||||||
%header.new-header{ class: current_page?(root_path) ? nil : "new-header-with-border", role: 'banner' }
|
%header.new-header{ class: current_page?(root_path) ? nil : "new-header-with-border", role: 'banner' }
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%th Liste des experts
|
%th Liste des experts
|
||||||
- if feature_enabled_for?(:make_experts_notifiable, @procedure)
|
- if @procedure.feature_enabled?(:make_experts_notifiable)
|
||||||
%th Notifier des décisions sur les dossiers
|
%th Notifier des décisions sur les dossiers
|
||||||
%tbody
|
%tbody
|
||||||
- @experts_procedure.each do |expert_procedure|
|
- @experts_procedure.each do |expert_procedure|
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
%td
|
%td
|
||||||
%span.icon.person
|
%span.icon.person
|
||||||
= expert_procedure.expert.email
|
= expert_procedure.expert.email
|
||||||
- if feature_enabled_for?(:make_experts_notifiable, @procedure)
|
- if @procedure.feature_enabled?(:make_experts_notifiable)
|
||||||
%td
|
%td
|
||||||
= form_for expert_procedure,
|
= form_for expert_procedure,
|
||||||
url: admin_procedure_update_allow_decision_access_path(expert_procedure: expert_procedure),
|
url: admin_procedure_update_allow_decision_access_path(expert_procedure: expert_procedure),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
%table.table.vertical.dossier-champs
|
%table.table.vertical.dossier-champs
|
||||||
%tbody
|
%tbody
|
||||||
- if dossier.procedure.routee?
|
- if dossier.show_groupe_instructeur_details?
|
||||||
%th= dossier.procedure.routing_criteria_name
|
%th= dossier.procedure.routing_criteria_name
|
||||||
%td{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) }= dossier.groupe_instructeur.label
|
%td{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) }= dossier.groupe_instructeur.label
|
||||||
%td.updated-at
|
%td.updated-at
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
%hr
|
%hr
|
||||||
|
|
||||||
- if dossier.procedure.routee?
|
- if dossier.show_groupe_instructeur_selector?
|
||||||
= f.label :groupe_instructeur_id do
|
= f.label :groupe_instructeur_id do
|
||||||
= dossier.procedure.routing_criteria_name
|
= dossier.procedure.routing_criteria_name
|
||||||
%span.mandatory *
|
%span.mandatory *
|
||||||
|
|
|
@ -25,14 +25,21 @@ end
|
||||||
|
|
||||||
# A list of features to be deployed on first push
|
# A list of features to be deployed on first push
|
||||||
features = [
|
features = [
|
||||||
|
:administrateur_routage,
|
||||||
:administrateur_web_hook,
|
:administrateur_web_hook,
|
||||||
|
:carte_ign,
|
||||||
|
:coronavirus_banner,
|
||||||
|
:dossier_pdf_vide,
|
||||||
|
:expert_not_allowed_to_invite,
|
||||||
|
:hide_instructeur_email,
|
||||||
:insee_api_v3,
|
:insee_api_v3,
|
||||||
:instructeur_bypass_email_login_token,
|
:instructeur_bypass_email_login_token,
|
||||||
|
:localization,
|
||||||
:maintenance_mode,
|
:maintenance_mode,
|
||||||
|
:make_experts_notifiable,
|
||||||
:mini_profiler,
|
:mini_profiler,
|
||||||
:xray,
|
:procedure_routage_api,
|
||||||
:carte_ign,
|
:xray
|
||||||
:localization
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def database_exists?
|
def database_exists?
|
||||||
|
|
|
@ -5,8 +5,8 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
let(:administrateur) { create(:administrateur) }
|
let(:administrateur) { create(:administrateur) }
|
||||||
let(:administration) { create(:administration) }
|
let(:administration) { create(:administration) }
|
||||||
let(:instructeurs) { [instructeur] }
|
let(:instructeurs) { [instructeur] }
|
||||||
let(:procedure) { create(:procedure, :published, instructeurs: instructeurs) }
|
let(:procedure) { create(:procedure, :published, :for_individual, instructeurs: instructeurs) }
|
||||||
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) }
|
||||||
let(:fake_justificatif) { fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf') }
|
let(:fake_justificatif) { fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf') }
|
||||||
|
|
||||||
before { sign_in(instructeur.user) }
|
before { sign_in(instructeur.user) }
|
||||||
|
@ -328,7 +328,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
context 'when the attestation template uses the motivation field' do
|
context 'when the attestation template uses the motivation field' do
|
||||||
let(:emailable) { false }
|
let(:emailable) { false }
|
||||||
let(:template) { create(:attestation_template) }
|
let(:template) { create(:attestation_template) }
|
||||||
let(:procedure) { create(:procedure, :published, attestation_template: template, instructeurs: [instructeur]) }
|
let(:procedure) { create(:procedure, :published, :for_individual, attestation_template: template, instructeurs: [instructeur]) }
|
||||||
|
|
||||||
subject do
|
subject do
|
||||||
post :terminer, params: {
|
post :terminer, params: {
|
||||||
|
@ -552,6 +552,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
describe "#show" do
|
describe "#show" do
|
||||||
context "when the dossier is exported as PDF" do
|
context "when the dossier is exported as PDF" do
|
||||||
let(:instructeur) { create(:instructeur) }
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
let(:procedure) { create(:procedure, :published, instructeurs: instructeurs) }
|
||||||
let(:dossier) do
|
let(:dossier) do
|
||||||
create(:dossier,
|
create(:dossier,
|
||||||
:accepte,
|
:accepte,
|
||||||
|
|
|
@ -20,7 +20,7 @@ describe Manager::DossiersController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#restore' do
|
describe '#restore' do
|
||||||
let(:dossier) { create(:dossier, :en_construction) }
|
let(:dossier) { create(:dossier, :en_construction, :with_individual) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
dossier.discard_and_keep_track!(super_admin, :manager_request)
|
dossier.discard_and_keep_track!(super_admin, :manager_request)
|
||||||
|
|
|
@ -46,7 +46,7 @@ describe Manager::ProceduresController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#restore' do
|
describe '#restore' do
|
||||||
let(:dossier) { create(:dossier, :en_construction) }
|
let(:dossier) { create(:dossier, :en_construction, :with_individual) }
|
||||||
let(:procedure) { dossier.procedure }
|
let(:procedure) { dossier.procedure }
|
||||||
let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) }
|
let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) }
|
||||||
let(:operations) { dossier.dossier_operation_logs.map(&:operation).map(&:to_sym) }
|
let(:operations) { dossier.dossier_operation_logs.map(&:operation).map(&:to_sym) }
|
||||||
|
|
|
@ -2,7 +2,7 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do
|
||||||
render_views
|
render_views
|
||||||
|
|
||||||
let(:admin) { create(:administrateur) }
|
let(:admin) { create(:administrateur) }
|
||||||
let(:procedure) { create(:procedure, :published, administrateurs: [admin]) }
|
let(:procedure) { create(:procedure, :published, :for_individual, administrateurs: [admin]) }
|
||||||
let!(:gi_1_1) { procedure.defaut_groupe_instructeur }
|
let!(:gi_1_1) { procedure.defaut_groupe_instructeur }
|
||||||
|
|
||||||
let(:procedure2) { create(:procedure, :published) }
|
let(:procedure2) { create(:procedure, :published) }
|
||||||
|
@ -137,9 +137,9 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do
|
||||||
|
|
||||||
describe '#reaffecter' do
|
describe '#reaffecter' do
|
||||||
let!(:gi_1_2) { procedure.groupe_instructeurs.create(label: 'groupe instructeur 2') }
|
let!(:gi_1_2) { procedure.groupe_instructeurs.create(label: 'groupe instructeur 2') }
|
||||||
let!(:dossier12) { create(:dossier, :en_construction, procedure: procedure, groupe_instructeur: gi_1_1) }
|
let!(:dossier12) { create(:dossier, :en_construction, :with_individual, procedure: procedure, groupe_instructeur: gi_1_1) }
|
||||||
let!(:dossier_discarded) do
|
let!(:dossier_discarded) do
|
||||||
dossier = create(:dossier, :en_construction, procedure: procedure, groupe_instructeur: gi_1_1)
|
dossier = create(:dossier, :en_construction, :with_individual, procedure: procedure, groupe_instructeur: gi_1_1)
|
||||||
dossier.discard!
|
dossier.discard!
|
||||||
dossier
|
dossier
|
||||||
end
|
end
|
||||||
|
|
|
@ -101,7 +101,7 @@ FactoryBot.define do
|
||||||
|
|
||||||
trait :routee do
|
trait :routee do
|
||||||
after(:create) do |procedure, _evaluator|
|
after(:create) do |procedure, _evaluator|
|
||||||
procedure.groupe_instructeurs.create(label: '2nd groupe')
|
procedure.groupe_instructeurs.create(label: 'deuxième groupe')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ feature 'Instructing a dossier:' do
|
||||||
let!(:instructeur) { create(:instructeur, password: password) }
|
let!(:instructeur) { create(:instructeur, password: password) }
|
||||||
|
|
||||||
let!(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
|
let!(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
|
||||||
let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
let!(:dossier) { create(:dossier, :en_construction, :with_entreprise, procedure: procedure) }
|
||||||
context 'the instructeur is also a user' do
|
context 'the instructeur is also a user' do
|
||||||
scenario 'a instructeur can fill a dossier' do
|
scenario 'a instructeur can fill a dossier' do
|
||||||
visit commencer_path(path: procedure.path)
|
visit commencer_path(path: procedure.path)
|
||||||
|
|
|
@ -4,10 +4,10 @@ RSpec.describe Cron::DeclarativeProceduresJob, type: :job do
|
||||||
let(:instruction_date) { date + 120 }
|
let(:instruction_date) { date + 120 }
|
||||||
|
|
||||||
let(:state) { nil }
|
let(:state) { nil }
|
||||||
let(:procedure) { create(:procedure, :published, :with_instructeur, declarative_with_state: state) }
|
let(:procedure) { create(:procedure, :published, :for_individual, :with_instructeur, declarative_with_state: state) }
|
||||||
let(:nouveau_dossier1) { create(:dossier, :en_construction, procedure: procedure) }
|
let(:nouveau_dossier1) { create(:dossier, :en_construction, :with_individual, procedure: procedure) }
|
||||||
let(:nouveau_dossier2) { create(:dossier, :en_construction, procedure: procedure) }
|
let(:nouveau_dossier2) { create(:dossier, :en_construction, :with_individual, procedure: procedure) }
|
||||||
let(:dossier_recu) { create(:dossier, :en_instruction, procedure: procedure) }
|
let(:dossier_recu) { create(:dossier, :en_instruction, :with_individual, procedure: procedure) }
|
||||||
let(:dossier_brouillon) { create(:dossier, procedure: procedure) }
|
let(:dossier_brouillon) { create(:dossier, procedure: procedure) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
RSpec.describe Cron::DiscardedDossiersDeletionJob, type: :job do
|
RSpec.describe Cron::DiscardedDossiersDeletionJob, type: :job do
|
||||||
describe '#perform' do
|
describe '#perform' do
|
||||||
let(:instructeur) { create(:instructeur) }
|
let(:instructeur) { create(:instructeur) }
|
||||||
let(:dossier) { create(:dossier, state, hidden_at: hidden_at) }
|
let(:dossier) { create(:dossier, :with_individual, state) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
# hack to add passer_en_instruction and supprimer to dossier.dossier_operation_logs
|
# hack to add passer_en_instruction and supprimer to dossier.dossier_operation_logs
|
||||||
dossier.send(:log_dossier_operation, instructeur, :passer_en_instruction, dossier)
|
dossier.send(:log_dossier_operation, instructeur, :passer_en_instruction, dossier)
|
||||||
dossier.send(:log_dossier_operation, instructeur, :supprimer, dossier)
|
dossier.send(:log_dossier_operation, instructeur, :supprimer, dossier)
|
||||||
|
dossier.update_column(:hidden_at, hidden_at)
|
||||||
|
|
||||||
Cron::DiscardedDossiersDeletionJob.perform_now
|
Cron::DiscardedDossiersDeletionJob.perform_now
|
||||||
end
|
end
|
||||||
|
@ -35,7 +36,7 @@ RSpec.describe Cron::DiscardedDossiersDeletionJob, type: :job do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
[:brouillon, :en_construction, :en_instruction, :accepte, :refuse, :sans_suite].each do |state|
|
[:en_construction, :en_instruction, :accepte, :refuse, :sans_suite].each do |state|
|
||||||
context "with a dossier #{state}" do
|
context "with a dossier #{state}" do
|
||||||
let(:state) { state }
|
let(:state) { state }
|
||||||
|
|
||||||
|
|
|
@ -354,8 +354,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#update_state_dates' do
|
describe '#update_state_dates' do
|
||||||
let(:state) { Dossier.states.fetch(:brouillon) }
|
let(:dossier) { create(:dossier, :brouillon, :with_individual) }
|
||||||
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) }
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
|
||||||
|
@ -381,7 +380,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when dossier is en_instruction' do
|
context 'when dossier is en_instruction' do
|
||||||
let(:state) { Dossier.states.fetch(:en_construction) }
|
let(:dossier) { create(:dossier, :en_construction, :with_individual) }
|
||||||
let(:instructeur) { create(:instructeur) }
|
let(:instructeur) { create(:instructeur) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -402,7 +401,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when dossier is accepte' do
|
context 'when dossier is accepte' do
|
||||||
let(:state) { Dossier.states.fetch(:en_instruction) }
|
let(:dossier) { create(:dossier, :en_instruction, :with_individual) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
dossier.accepter!(instructeur, nil, nil)
|
dossier.accepter!(instructeur, nil, nil)
|
||||||
|
@ -415,7 +414,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when dossier is refuse' do
|
context 'when dossier is refuse' do
|
||||||
let(:state) { Dossier.states.fetch(:en_instruction) }
|
let(:dossier) { create(:dossier, :en_instruction, :with_individual) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
dossier.refuser!(instructeur, nil, nil)
|
dossier.refuser!(instructeur, nil, nil)
|
||||||
|
@ -427,7 +426,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when dossier is sans_suite' do
|
context 'when dossier is sans_suite' do
|
||||||
let(:state) { Dossier.states.fetch(:en_instruction) }
|
let(:dossier) { create(:dossier, :en_instruction, :with_individual) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
dossier.classer_sans_suite!(instructeur, nil, nil)
|
dossier.classer_sans_suite!(instructeur, nil, nil)
|
||||||
|
@ -469,11 +468,11 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#unfollow_stale_instructeurs" do
|
describe "#unfollow_stale_instructeurs" do
|
||||||
let(:procedure) { create(:procedure, :published) }
|
let(:procedure) { create(:procedure, :published, :for_individual) }
|
||||||
let(:instructeur) { create(:instructeur) }
|
let(:instructeur) { create(:instructeur) }
|
||||||
let(:new_groupe_instructeur) { create(:groupe_instructeur, procedure: procedure) }
|
let(:new_groupe_instructeur) { create(:groupe_instructeur, procedure: procedure) }
|
||||||
let(:instructeur2) { create(:instructeur, groupe_instructeurs: [procedure.defaut_groupe_instructeur, new_groupe_instructeur]) }
|
let(:instructeur2) { create(:instructeur, groupe_instructeurs: [procedure.defaut_groupe_instructeur, new_groupe_instructeur]) }
|
||||||
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) }
|
||||||
let(:last_operation) { DossierOperationLog.last }
|
let(:last_operation) { DossierOperationLog.last }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -918,7 +917,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#accepter!' do
|
describe '#accepter!' do
|
||||||
let(:dossier) { create(:dossier, :en_instruction) }
|
let(:dossier) { create(:dossier, :en_instruction, :with_individual) }
|
||||||
let(:last_operation) { dossier.dossier_operation_logs.last }
|
let(:last_operation) { dossier.dossier_operation_logs.last }
|
||||||
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
|
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
|
||||||
let!(:instructeur) { create(:instructeur) }
|
let!(:instructeur) { create(:instructeur) }
|
||||||
|
@ -953,7 +952,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#accepter_automatiquement!' do
|
describe '#accepter_automatiquement!' do
|
||||||
let(:dossier) { create(:dossier, :en_construction) }
|
let(:dossier) { create(:dossier, :en_construction, :with_individual) }
|
||||||
let(:last_operation) { dossier.dossier_operation_logs.last }
|
let(:last_operation) { dossier.dossier_operation_logs.last }
|
||||||
let!(:now) { Time.zone.parse('01/01/2100') }
|
let!(:now) { Time.zone.parse('01/01/2100') }
|
||||||
let(:attestation) { Attestation.new }
|
let(:attestation) { Attestation.new }
|
||||||
|
@ -1372,7 +1371,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "remove_titres_identite!" do
|
describe "remove_titres_identite!" do
|
||||||
let(:dossier) { create(:dossier, :en_instruction, :followed) }
|
let(:dossier) { create(:dossier, :en_instruction, :followed, :with_individual) }
|
||||||
let(:type_de_champ_titre_identite) { create(:type_de_champ_titre_identite, procedure: dossier.procedure) }
|
let(:type_de_champ_titre_identite) { create(:type_de_champ_titre_identite, procedure: dossier.procedure) }
|
||||||
let(:champ_titre_identite) { create(:champ_titre_identite, type_de_champ: type_de_champ_titre_identite) }
|
let(:champ_titre_identite) { create(:champ_titre_identite, type_de_champ: type_de_champ_titre_identite) }
|
||||||
let(:type_de_champ_titre_identite_vide) { create(:type_de_champ_titre_identite, procedure: dossier.procedure) }
|
let(:type_de_champ_titre_identite_vide) { create(:type_de_champ_titre_identite, procedure: dossier.procedure) }
|
||||||
|
@ -1412,7 +1411,7 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'en_construction' do
|
context 'en_construction' do
|
||||||
let(:dossier) { create(:dossier, :en_construction, :followed) }
|
let(:dossier) { create(:dossier, :en_construction, :followed, :with_individual) }
|
||||||
|
|
||||||
it "clean up titres identite on accepter_automatiquement" do
|
it "clean up titres identite on accepter_automatiquement" do
|
||||||
expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy
|
expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy
|
||||||
|
|
|
@ -529,7 +529,7 @@ describe Instructeur, type: :model do
|
||||||
let(:instructeur_a) { create(:instructeur, groupe_instructeurs: [procedure_a.defaut_groupe_instructeur]) }
|
let(:instructeur_a) { create(:instructeur, groupe_instructeurs: [procedure_a.defaut_groupe_instructeur]) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
gi2 = procedure_a.groupe_instructeurs.create(label: '2')
|
gi2 = procedure_a.groupe_instructeurs.create(label: 'gi2')
|
||||||
|
|
||||||
instructeur_a.groupe_instructeurs << gi2
|
instructeur_a.groupe_instructeurs << gi2
|
||||||
end
|
end
|
||||||
|
|
|
@ -730,8 +730,8 @@ describe ProcedurePresentation do
|
||||||
context 'for groupe_instructeur table' do
|
context 'for groupe_instructeur table' do
|
||||||
let(:filter) { [{ 'table' => 'groupe_instructeur', 'column' => 'label', 'value' => 'défaut' }] }
|
let(:filter) { [{ 'table' => 'groupe_instructeur', 'column' => 'label', 'value' => 'défaut' }] }
|
||||||
|
|
||||||
let!(:gi_2) { procedure.groupe_instructeurs.create(label: '2') }
|
let!(:gi_2) { procedure.groupe_instructeurs.create(label: 'gi2') }
|
||||||
let!(:gi_3) { procedure.groupe_instructeurs.create(label: '3') }
|
let!(:gi_3) { procedure.groupe_instructeurs.create(label: 'gi3') }
|
||||||
|
|
||||||
let!(:kept_dossier) { create(:dossier, procedure: procedure) }
|
let!(:kept_dossier) { create(:dossier, procedure: procedure) }
|
||||||
let!(:discarded_dossier) { create(:dossier, procedure: procedure, groupe_instructeur: gi_2) }
|
let!(:discarded_dossier) { create(:dossier, procedure: procedure, groupe_instructeur: gi_2) }
|
||||||
|
@ -742,7 +742,7 @@ describe ProcedurePresentation do
|
||||||
let(:filter) do
|
let(:filter) do
|
||||||
[
|
[
|
||||||
{ 'table' => 'groupe_instructeur', 'column' => 'label', 'value' => 'défaut' },
|
{ 'table' => 'groupe_instructeur', 'column' => 'label', 'value' => 'défaut' },
|
||||||
{ 'table' => 'groupe_instructeur', 'column' => 'label', 'value' => '3' }
|
{ 'table' => 'groupe_instructeur', 'column' => 'label', 'value' => 'gi3' }
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -466,7 +466,7 @@ describe Procedure do
|
||||||
|
|
||||||
it 'should have a default groupe instructeur' do
|
it 'should have a default groupe instructeur' do
|
||||||
expect(subject.groupe_instructeurs.size).to eq(1)
|
expect(subject.groupe_instructeurs.size).to eq(1)
|
||||||
expect(subject.groupe_instructeurs.first.label).to eq(GroupeInstructeur::DEFAULT_LABEL)
|
expect(subject.groupe_instructeurs.first.label).to eq(GroupeInstructeur::DEFAUT_LABEL)
|
||||||
expect(subject.groupe_instructeurs.first.instructeurs.size).to eq(0)
|
expect(subject.groupe_instructeurs.first.instructeurs.size).to eq(0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1011,7 +1011,7 @@ describe Procedure do
|
||||||
let!(:procedure) { create(:procedure) }
|
let!(:procedure) { create(:procedure) }
|
||||||
|
|
||||||
it { expect(procedure.groupe_instructeurs.count).to eq(1) }
|
it { expect(procedure.groupe_instructeurs.count).to eq(1) }
|
||||||
it { expect(procedure.groupe_instructeurs.first.label).to eq(GroupeInstructeur::DEFAULT_LABEL) }
|
it { expect(procedure.groupe_instructeurs.first.label).to eq(GroupeInstructeur::DEFAUT_LABEL) }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.missing_instructeurs?' do
|
describe '.missing_instructeurs?' do
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe ExpiredDossiersDeletionService do
|
||||||
let(:date_not_expired) { Date.today - procedure.duree_conservation_dossiers_dans_ds.months + 2.months }
|
let(:date_not_expired) { Date.today - procedure.duree_conservation_dossiers_dans_ds.months + 2.months }
|
||||||
|
|
||||||
context 'send messages for dossiers expiring soon and delete expired' do
|
context 'send messages for dossiers expiring soon and delete expired' do
|
||||||
let!(:expired_brouillon) { create(:dossier, procedure: procedure, created_at: date_expired, brouillon_close_to_expiration_notice_sent_at: today - (warning_period + 1.day)) }
|
let!(:expired_brouillon) { create(:dossier, procedure: procedure, created_at: date_expired, brouillon_close_to_expiration_notice_sent_at: today - (warning_period + 3.days)) }
|
||||||
let!(:brouillon_close_to_expiration) { create(:dossier, procedure: procedure, created_at: date_close_to_expiration) }
|
let!(:brouillon_close_to_expiration) { create(:dossier, procedure: procedure, created_at: date_close_to_expiration) }
|
||||||
let!(:brouillon_close_but_with_notice_sent) { create(:dossier, procedure: procedure, created_at: date_close_to_expiration, brouillon_close_to_expiration_notice_sent_at: Time.zone.now) }
|
let!(:brouillon_close_but_with_notice_sent) { create(:dossier, procedure: procedure, created_at: date_close_to_expiration, brouillon_close_to_expiration_notice_sent_at: Time.zone.now) }
|
||||||
let!(:valid_brouillon) { create(:dossier, procedure: procedure, created_at: date_not_expired) }
|
let!(:valid_brouillon) { create(:dossier, procedure: procedure, created_at: date_not_expired) }
|
||||||
|
|
Loading…
Reference in a new issue