Merge pull request #9310 from demarches-simplifiees/feat-graphql-dossier-corrections
API graphql: expose les demandes de corrections
This commit is contained in:
commit
03da5725d4
26 changed files with 210 additions and 57 deletions
|
@ -48,7 +48,7 @@
|
||||||
- menu.with_item(class: "inactive form-inside fr-pt-1v") do
|
- menu.with_item(class: "inactive form-inside fr-pt-1v") do
|
||||||
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier:,
|
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier:,
|
||||||
visible: false,
|
visible: false,
|
||||||
form_path: pending_correction_instructeur_dossier_path(dossier.procedure, dossier, kind: :incomplete),
|
form_path: pending_correction_instructeur_dossier_path(dossier.procedure, dossier, reason: :incomplete),
|
||||||
placeholder: 'Expliquez au demandeur comment compléter son dossier',
|
placeholder: 'Expliquez au demandeur comment compléter son dossier',
|
||||||
popup_class: 'pending_completion',
|
popup_class: 'pending_completion',
|
||||||
button_justificatif_label: "Ajouter une pièce jointe (facultatif)",
|
button_justificatif_label: "Ajouter une pièce jointe (facultatif)",
|
||||||
|
|
|
@ -235,7 +235,7 @@ module Instructeurs
|
||||||
commentaire = CommentaireService.build(current_instructeur, dossier, { body: message, piece_jointe: })
|
commentaire = CommentaireService.build(current_instructeur, dossier, { body: message, piece_jointe: })
|
||||||
|
|
||||||
if commentaire.valid?
|
if commentaire.valid?
|
||||||
dossier.flag_as_pending_correction!(commentaire, params[:kind].presence)
|
dossier.flag_as_pending_correction!(commentaire, params[:reason].presence)
|
||||||
dossier.update!(last_commentaire_updated_at: Time.zone.now)
|
dossier.update!(last_commentaire_updated_at: Time.zone.now)
|
||||||
current_instructeur.follow(dossier)
|
current_instructeur.follow(dossier)
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,19 @@ module Mutations
|
||||||
argument :instructeur_id, ID, required: true, loads: Types::ProfileType
|
argument :instructeur_id, ID, required: true, loads: Types::ProfileType
|
||||||
argument :body, String, required: true
|
argument :body, String, required: true
|
||||||
argument :attachment, ID, required: false
|
argument :attachment, ID, required: false
|
||||||
|
argument :correction, Types::CorrectionType::CorrectionReason, 'Préciser qu’il s’agit d’une demande de correction. Le dossier repasssera en construction.', required: false
|
||||||
|
|
||||||
field :message, Types::MessageType, null: true
|
field :message, Types::MessageType, null: true
|
||||||
field :errors, [Types::ValidationErrorType], null: true
|
field :errors, [Types::ValidationErrorType], null: true
|
||||||
|
|
||||||
def resolve(dossier:, instructeur:, body:, attachment: nil)
|
def resolve(dossier:, instructeur:, body:, attachment: nil, correction: nil)
|
||||||
message = CommentaireService.create(instructeur, dossier, body: body, piece_jointe: attachment)
|
message = CommentaireService.create(instructeur, dossier, body: body, piece_jointe: attachment)
|
||||||
|
|
||||||
if message.errors.empty?
|
if message.errors.empty?
|
||||||
|
if correction
|
||||||
|
dossier.flag_as_pending_correction!(message, correction)
|
||||||
|
end
|
||||||
|
|
||||||
{ message: }
|
{ message: }
|
||||||
else
|
else
|
||||||
{ errors: message.errors.full_messages }
|
{ errors: message.errors.full_messages }
|
||||||
|
|
|
@ -542,6 +542,23 @@ GeoJSON coordinates
|
||||||
"""
|
"""
|
||||||
scalar Coordinates
|
scalar Coordinates
|
||||||
|
|
||||||
|
type Correction {
|
||||||
|
dateResolution: ISO8601DateTime
|
||||||
|
reason: CorrectionReason!
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CorrectionReason {
|
||||||
|
"""
|
||||||
|
Le dossier est incomplet et nécessite d’être complété
|
||||||
|
"""
|
||||||
|
incomplete
|
||||||
|
|
||||||
|
"""
|
||||||
|
Le dossier n’est pas valide et nécessite une correction
|
||||||
|
"""
|
||||||
|
incorrect
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Autogenerated input type of CreateDirectUpload
|
Autogenerated input type of CreateDirectUpload
|
||||||
"""
|
"""
|
||||||
|
@ -1301,6 +1318,11 @@ type Dossier {
|
||||||
"""
|
"""
|
||||||
dateDepot: ISO8601DateTime!
|
dateDepot: ISO8601DateTime!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Date de la dernière demande de correction qui n’a pas encore été traitée par l’usager.
|
||||||
|
"""
|
||||||
|
dateDerniereCorrectionEnAttente: ISO8601DateTime
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Date de la dernière modification.
|
Date de la dernière modification.
|
||||||
"""
|
"""
|
||||||
|
@ -1568,6 +1590,11 @@ input DossierEnvoyerMessageInput {
|
||||||
A unique identifier for the client performing the mutation.
|
A unique identifier for the client performing the mutation.
|
||||||
"""
|
"""
|
||||||
clientMutationId: String
|
clientMutationId: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Préciser qu’il s’agit d’une demande de correction. Le dossier repasssera en construction.
|
||||||
|
"""
|
||||||
|
correction: CorrectionReason
|
||||||
dossierId: ID!
|
dossierId: ID!
|
||||||
instructeurId: ID!
|
instructeurId: ID!
|
||||||
}
|
}
|
||||||
|
@ -2826,6 +2853,7 @@ type Message {
|
||||||
attachment: File @deprecated(reason: "Utilisez le champ `attachments` à la place.")
|
attachment: File @deprecated(reason: "Utilisez le champ `attachments` à la place.")
|
||||||
attachments: [File!]!
|
attachments: [File!]!
|
||||||
body: String!
|
body: String!
|
||||||
|
correction: Correction
|
||||||
createdAt: ISO8601DateTime!
|
createdAt: ISO8601DateTime!
|
||||||
email: String!
|
email: String!
|
||||||
id: ID!
|
id: ID!
|
||||||
|
|
23
app/graphql/types/correction_type.rb
Normal file
23
app/graphql/types/correction_type.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
module Types
|
||||||
|
class CorrectionType < Types::BaseObject
|
||||||
|
class CorrectionReason < Types::BaseEnum
|
||||||
|
# i18n-tasks-use t('dossier_correction.reasons.incorrect'), t('dossier_correction.reasons.incomplete')
|
||||||
|
DossierCorrection.reasons.each do |symbol_name, string_name|
|
||||||
|
value(string_name,
|
||||||
|
I18n.t(symbol_name, scope: [:activerecord, :attributes, :dossier_correction, :reasons]),
|
||||||
|
value: symbol_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
field :reason, CorrectionReason, null: false
|
||||||
|
field :date_resolution, GraphQL::Types::ISO8601DateTime, null: true
|
||||||
|
|
||||||
|
def date_resolution
|
||||||
|
object.resolved_at
|
||||||
|
end
|
||||||
|
|
||||||
|
def message
|
||||||
|
object.commentaire
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -30,6 +30,8 @@ module Types
|
||||||
field :date_suppression_par_administration, GraphQL::Types::ISO8601DateTime, "Date de la suppression par l’administration.", null: true, method: :hidden_by_administration_at
|
field :date_suppression_par_administration, GraphQL::Types::ISO8601DateTime, "Date de la suppression par l’administration.", null: true, method: :hidden_by_administration_at
|
||||||
field :date_expiration, GraphQL::Types::ISO8601DateTime, "Date d’expiration.", null: true
|
field :date_expiration, GraphQL::Types::ISO8601DateTime, "Date d’expiration.", null: true
|
||||||
|
|
||||||
|
field :date_derniere_correction_en_attente, GraphQL::Types::ISO8601DateTime, "Date de la dernière demande de correction qui n’a pas encore été traitée par l’usager.", null: true
|
||||||
|
|
||||||
field :archived, Boolean, null: false
|
field :archived, Boolean, null: false
|
||||||
|
|
||||||
field :connection_usager, ConnectionUsager, null: false
|
field :connection_usager, ConnectionUsager, null: false
|
||||||
|
@ -75,6 +77,10 @@ module Types
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def date_derniere_correction_en_attente
|
||||||
|
Loaders::Association.for(object.class, :pending_correction).load(object).then { _1&.created_at }
|
||||||
|
end
|
||||||
|
|
||||||
def connection_usager
|
def connection_usager
|
||||||
if object.user_deleted?
|
if object.user_deleted?
|
||||||
:deleted
|
:deleted
|
||||||
|
|
|
@ -10,9 +10,14 @@ module Types
|
||||||
field :attachments, [Types::File], null: false, extensions: [
|
field :attachments, [Types::File], null: false, extensions: [
|
||||||
{ Extensions::Attachment => { attachment: :piece_jointe, as: :multiple } }
|
{ Extensions::Attachment => { attachment: :piece_jointe, as: :multiple } }
|
||||||
]
|
]
|
||||||
|
field :correction, CorrectionType, null: true
|
||||||
|
|
||||||
def body
|
def body
|
||||||
object.body.nil? ? "" : object.body
|
object.body.nil? ? "" : object.body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def correction
|
||||||
|
Loaders::Association.for(object.class, :dossier_correction).load(object)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,17 +5,18 @@ module DossierCorrectableConcern
|
||||||
A_CORRIGER = 'a_corriger'
|
A_CORRIGER = 'a_corriger'
|
||||||
has_many :corrections, class_name: 'DossierCorrection', dependent: :destroy
|
has_many :corrections, class_name: 'DossierCorrection', dependent: :destroy
|
||||||
has_many :pending_corrections, -> { DossierCorrection.pending }, class_name: 'DossierCorrection', inverse_of: :dossier
|
has_many :pending_corrections, -> { DossierCorrection.pending }, class_name: 'DossierCorrection', inverse_of: :dossier
|
||||||
|
has_one :pending_correction, -> { DossierCorrection.pending }, class_name: 'DossierCorrection', inverse_of: :dossier
|
||||||
|
|
||||||
scope :with_pending_corrections, -> { joins(:corrections).where(corrections: { resolved_at: nil }) }
|
scope :with_pending_corrections, -> { joins(:corrections).where(corrections: { resolved_at: nil }) }
|
||||||
|
|
||||||
def flag_as_pending_correction!(commentaire, kind = nil)
|
def flag_as_pending_correction!(commentaire, reason = nil)
|
||||||
return unless may_flag_as_pending_correction?
|
return unless may_flag_as_pending_correction?
|
||||||
|
|
||||||
kind ||= :correction
|
reason ||= :incorrect
|
||||||
|
|
||||||
corrections.create!(commentaire:, kind:)
|
corrections.create!(commentaire:, reason:)
|
||||||
|
|
||||||
log_pending_correction_operation(commentaire, kind) if procedure.sva_svr_enabled?
|
log_pending_correction_operation(commentaire, reason) if procedure.sva_svr_enabled?
|
||||||
|
|
||||||
return if en_construction?
|
return if en_construction?
|
||||||
|
|
||||||
|
@ -37,10 +38,6 @@ module DossierCorrectableConcern
|
||||||
pending_corrections.exists?
|
pending_corrections.exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pending_correction
|
|
||||||
pending_corrections.first
|
|
||||||
end
|
|
||||||
|
|
||||||
def resolve_pending_correction!
|
def resolve_pending_correction!
|
||||||
pending_corrections.update!(resolved_at: Time.current)
|
pending_corrections.update!(resolved_at: Time.current)
|
||||||
pending_corrections.reset
|
pending_corrections.reset
|
||||||
|
@ -48,9 +45,9 @@ module DossierCorrectableConcern
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def log_pending_correction_operation(commentaire, kind)
|
def log_pending_correction_operation(commentaire, reason)
|
||||||
operation = case kind.to_sym
|
operation = case reason.to_sym
|
||||||
when :correction
|
when :incorrect
|
||||||
"demander_une_correction"
|
"demander_une_correction"
|
||||||
when :incomplete
|
when :incomplete
|
||||||
"demander_a_completer"
|
"demander_a_completer"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Table name: dossier_corrections
|
# Table name: dossier_corrections
|
||||||
#
|
#
|
||||||
# id :bigint not null, primary key
|
# id :bigint not null, primary key
|
||||||
# kind :string default("correction"), not null
|
# reason :string default("incorrect"), not null
|
||||||
# resolved_at :datetime
|
# resolved_at :datetime
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
|
@ -14,11 +14,13 @@ class DossierCorrection < ApplicationRecord
|
||||||
belongs_to :dossier
|
belongs_to :dossier
|
||||||
belongs_to :commentaire
|
belongs_to :commentaire
|
||||||
|
|
||||||
|
self.ignored_columns += ['kind']
|
||||||
|
|
||||||
validates_associated :commentaire
|
validates_associated :commentaire
|
||||||
|
|
||||||
scope :pending, -> { where(resolved_at: nil) }
|
scope :pending, -> { where(resolved_at: nil) }
|
||||||
|
|
||||||
enum kind: { correction: 'correction', incomplete: 'incomplete' }
|
enum reason: { incorrect: 'incorrect', incomplete: 'incomplete' }, _prefix: :dossier
|
||||||
|
|
||||||
def resolved?
|
def resolved?
|
||||||
resolved_at.present?
|
resolved_at.present?
|
||||||
|
|
|
@ -47,13 +47,13 @@ class SVASVRDecisionDateCalculatorService
|
||||||
def determine_start_date
|
def determine_start_date
|
||||||
return dossier.depose_at.to_date if dossier.corrections.empty?
|
return dossier.depose_at.to_date if dossier.corrections.empty?
|
||||||
return latest_correction_date if resume_method == :reset
|
return latest_correction_date if resume_method == :reset
|
||||||
return latest_incomplete_correction_date if dossier.corrections.any?(&:incomplete?)
|
return latest_incomplete_correction_date if dossier.corrections.any?(&:dossier_incomplete?)
|
||||||
|
|
||||||
dossier.depose_at.to_date
|
dossier.depose_at.to_date
|
||||||
end
|
end
|
||||||
|
|
||||||
def latest_incomplete_correction_date
|
def latest_incomplete_correction_date
|
||||||
correction_date dossier.corrections.filter(&:incomplete?).max_by(&:resolved_at)
|
correction_date dossier.corrections.filter(&:dossier_incomplete?).max_by(&:resolved_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
def latest_correction_date
|
def latest_correction_date
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
|
|
||||||
%p= t(:hello, scope: [:views, :shared, :greetings])
|
%p= t(:hello, scope: [:views, :shared, :greetings])
|
||||||
|
|
||||||
%p= t(".#{@correction.kind}.explanation_html", dossier_id: @dossier.id, libelle_demarche: @dossier.procedure.libelle)
|
%p= t(".#{@correction.reason}.explanation_html", dossier_id: @dossier.id, libelle_demarche: @dossier.procedure.libelle)
|
||||||
%p= t('.link')
|
%p= t('.link')
|
||||||
= round_button(t('.access_message'), messagerie_dossier_url(@dossier), :primary)
|
= round_button(t('.access_message'), messagerie_dossier_url(@dossier), :primary)
|
||||||
|
|
||||||
- if @dossier.sva_svr_decision_on.present?
|
- if @dossier.sva_svr_decision_on.present?
|
||||||
%p= t(".#{@correction.kind}.sva_svr", rule_name: t(@dossier.procedure.sva? ? :sva : :svr, scope: 'shared.procedures.sva_svr_rule_name'))
|
%p= t(".#{@correction.reason}.sva_svr", rule_name: t(@dossier.procedure.sva? ? :sva : :svr, scope: 'shared.procedures.sva_svr_rule_name'))
|
||||||
|
|
||||||
= render 'layouts/mailers/signature', service: @service
|
= render 'layouts/mailers/signature', service: @service
|
||||||
|
|
||||||
|
|
7
config/locales/models/dossier_correction/en.yml
Normal file
7
config/locales/models/dossier_correction/en.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
en:
|
||||||
|
activerecord:
|
||||||
|
attributes:
|
||||||
|
dossier_correction:
|
||||||
|
reasons:
|
||||||
|
incorrect: "The file is invalid and needs to be corrected"
|
||||||
|
incomplete: "The file is incomplete and needs to be completed"
|
7
config/locales/models/dossier_correction/fr.yml
Normal file
7
config/locales/models/dossier_correction/fr.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
fr:
|
||||||
|
activerecord:
|
||||||
|
attributes:
|
||||||
|
dossier_correction:
|
||||||
|
reasons:
|
||||||
|
incorrect: "Le dossier n’est pas valide et nécessite une correction"
|
||||||
|
incomplete: "Le dossier est incomplet et nécessite d’être complété"
|
|
@ -3,7 +3,7 @@ en:
|
||||||
dossier_mailer:
|
dossier_mailer:
|
||||||
notify_pending_correction:
|
notify_pending_correction:
|
||||||
subject: You need to modify your file no. %{dossier_id} « %{libelle_demarche} »
|
subject: You need to modify your file no. %{dossier_id} « %{libelle_demarche} »
|
||||||
correction:
|
incorrect:
|
||||||
explanation_html:
|
explanation_html:
|
||||||
In order to continue its instruction, <strong>an instructor requested you to edit information</strong> to your file no. %{dossier_id} of the « %{libelle_demarche} » procedure.
|
In order to continue its instruction, <strong>an instructor requested you to edit information</strong> to your file no. %{dossier_id} of the « %{libelle_demarche} » procedure.
|
||||||
sva_svr:
|
sva_svr:
|
||||||
|
|
|
@ -3,7 +3,7 @@ fr:
|
||||||
dossier_mailer:
|
dossier_mailer:
|
||||||
notify_pending_correction:
|
notify_pending_correction:
|
||||||
subject: Vous devez corriger votre dossier nº %{dossier_id} « %{libelle_demarche} »
|
subject: Vous devez corriger votre dossier nº %{dossier_id} « %{libelle_demarche} »
|
||||||
correction:
|
incorrect:
|
||||||
explanation_html:
|
explanation_html:
|
||||||
Afin de poursuivre son instruction, <strong>un instructeur vous demande d’apporter des corrections</strong> à votre dossier nº %{dossier_id} de la démarche « %{libelle_demarche} ».
|
Afin de poursuivre son instruction, <strong>un instructeur vous demande d’apporter des corrections</strong> à votre dossier nº %{dossier_id} de la démarche « %{libelle_demarche} ».
|
||||||
sva_svr:
|
sva_svr:
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddReasonToDossierCorrections < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
add_column :dossier_corrections, :reason, :string, default: 'incorrect', null: false
|
||||||
|
end
|
||||||
|
end
|
|
@ -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[7.0].define(version: 2023_07_18_113920) do
|
ActiveRecord::Schema[7.0].define(version: 2023_07_19_112020) 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 "pgcrypto"
|
enable_extension "pgcrypto"
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -337,6 +337,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_07_18_113920) do
|
||||||
t.datetime "resolved_at", precision: 6
|
t.datetime "resolved_at", precision: 6
|
||||||
t.datetime "updated_at", precision: 6, null: false
|
t.datetime "updated_at", precision: 6, null: false
|
||||||
t.string "kind", default: "correction", null: false
|
t.string "kind", default: "correction", null: false
|
||||||
|
t.string "reason", default: "incorrect", null: false
|
||||||
t.index ["commentaire_id"], name: "index_dossier_corrections_on_commentaire_id"
|
t.index ["commentaire_id"], name: "index_dossier_corrections_on_commentaire_id"
|
||||||
t.index ["dossier_id"], name: "index_dossier_corrections_on_dossier_id"
|
t.index ["dossier_id"], name: "index_dossier_corrections_on_dossier_id"
|
||||||
t.index ["resolved_at"], name: "index_dossier_corrections_on_resolved_at", where: "((resolved_at IS NULL) OR (resolved_at IS NOT NULL))"
|
t.index ["resolved_at"], name: "index_dossier_corrections_on_resolved_at", where: "((resolved_at IS NULL) OR (resolved_at IS NOT NULL))"
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: backfill_default_dossier_correction_reason'
|
||||||
|
task backfill_dossier_correction_reason: :environment do
|
||||||
|
puts "Running deploy task 'backfill_default_dossier_correction_reason'"
|
||||||
|
|
||||||
|
DossierCorrection.where(kind: 'correction').update_all(reason: 'incorrect')
|
||||||
|
DossierCorrection.where(kind: 'incomplete').update_all(reason: 'incomplete')
|
||||||
|
|
||||||
|
# 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: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||||
|
end
|
||||||
|
end
|
|
@ -972,6 +972,23 @@ describe API::V2::GraphqlController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with correction' do
|
||||||
|
let(:input) { super().merge(correction: :incorrect) }
|
||||||
|
|
||||||
|
it 'should create a correction' do
|
||||||
|
expect(gql_data).to eq(dossierEnvoyerMessage: {
|
||||||
|
message: {
|
||||||
|
body: "Bonjour"
|
||||||
|
},
|
||||||
|
errors: nil
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(dossier).to be_pending_correction
|
||||||
|
expect(dossier.pending_correction).to be_dossier_incorrect
|
||||||
|
expect(dossier.pending_correction.commentaire.body).to eq("Bonjour")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'schema error' do
|
context 'schema error' do
|
||||||
let(:input) do
|
let(:input) do
|
||||||
{
|
{
|
||||||
|
|
|
@ -503,13 +503,13 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
describe '#pending_correction' do
|
describe '#pending_correction' do
|
||||||
let(:message) { 'do that' }
|
let(:message) { 'do that' }
|
||||||
let(:justificatif) { nil }
|
let(:justificatif) { nil }
|
||||||
let(:kind) { nil }
|
let(:reason) { nil }
|
||||||
|
|
||||||
subject do
|
subject do
|
||||||
post :pending_correction, params: {
|
post :pending_correction, params: {
|
||||||
procedure_id: procedure.id, dossier_id: dossier.id,
|
procedure_id: procedure.id, dossier_id: dossier.id,
|
||||||
dossier: { motivation: message, justificatif_motivation: justificatif },
|
dossier: { motivation: message, justificatif_motivation: justificatif },
|
||||||
kind:
|
reason:
|
||||||
}, format: :turbo_stream
|
}, format: :turbo_stream
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -535,7 +535,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
|
|
||||||
expect(dossier.reload).to be_en_construction
|
expect(dossier.reload).to be_en_construction
|
||||||
expect(dossier).to be_pending_correction
|
expect(dossier).to be_pending_correction
|
||||||
expect(dossier.corrections.last).to be_correction
|
expect(dossier.corrections.last).to be_dossier_incorrect
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'create a comment with text body' do
|
it 'create a comment with text body' do
|
||||||
|
@ -544,10 +544,10 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'flagged as incomplete' do
|
context 'flagged as incomplete' do
|
||||||
let(:kind) { 'incomplete' }
|
let(:reason) { 'incomplete' }
|
||||||
|
|
||||||
it 'create a correction of incomplete kind' do
|
it 'create a correction of incomplete reason' do
|
||||||
expect(dossier.corrections.last).to be_incomplete
|
expect(dossier.corrections.last).to be_dossier_incomplete
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :dossier_correction do
|
factory :dossier_correction do
|
||||||
dossier
|
dossier
|
||||||
commentaire
|
commentaire { association :commentaire, dossier: dossier }
|
||||||
kind { :correction }
|
reason { :incorrect }
|
||||||
resolved_at { nil }
|
resolved_at { nil }
|
||||||
|
|
||||||
trait :resolved do
|
trait :resolved do
|
||||||
|
|
|
@ -241,6 +241,19 @@ RSpec.describe Types::DossierType, type: :graphql do
|
||||||
|
|
||||||
it {
|
it {
|
||||||
expect(data[:dossier][:messages]).not_to be_nil
|
expect(data[:dossier][:messages]).not_to be_nil
|
||||||
|
expect(data[:dossier][:messages][0][:correction]).to be_nil
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'dossier with pending correction' do
|
||||||
|
let(:dossier) { create(:dossier, :en_construction) }
|
||||||
|
let!(:correction) { create(:dossier_correction, dossier:) }
|
||||||
|
let(:query) { DOSSIER_WITH_CORRECTION_QUERY }
|
||||||
|
let(:variables) { { number: dossier.id } }
|
||||||
|
|
||||||
|
it {
|
||||||
|
expect(data[:dossier][:messages][0][:correction]).to eq({ reason: "incorrect", dateResolution: nil })
|
||||||
|
expect(data[:dossier][:dateDerniereCorrectionEnAttente]).not_to be_nil
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -412,6 +425,21 @@ RSpec.describe Types::DossierType, type: :graphql do
|
||||||
}
|
}
|
||||||
GRAPHQL
|
GRAPHQL
|
||||||
|
|
||||||
|
DOSSIER_WITH_CORRECTION_QUERY = <<-GRAPHQL
|
||||||
|
query($number: Int!) {
|
||||||
|
dossier(number: $number) {
|
||||||
|
dateDerniereCorrectionEnAttente
|
||||||
|
messages {
|
||||||
|
body
|
||||||
|
correction {
|
||||||
|
reason
|
||||||
|
dateResolution
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GRAPHQL
|
||||||
|
|
||||||
DOSSIER_WITH_SELECTED_CHAMP_QUERY = <<-GRAPHQL
|
DOSSIER_WITH_SELECTED_CHAMP_QUERY = <<-GRAPHQL
|
||||||
query($number: Int!, $id: ID!) {
|
query($number: Int!, $id: ID!) {
|
||||||
dossier(number: $number) {
|
dossier(number: $number) {
|
||||||
|
|
|
@ -233,21 +233,21 @@ RSpec.describe DossierMailer, type: :mailer do
|
||||||
let(:procedure) { create(:procedure) }
|
let(:procedure) { create(:procedure) }
|
||||||
let(:dossier) { create(:dossier, :en_construction, procedure:, sva_svr_decision_on:) }
|
let(:dossier) { create(:dossier, :en_construction, procedure:, sva_svr_decision_on:) }
|
||||||
let(:sva_svr_decision_on) { nil }
|
let(:sva_svr_decision_on) { nil }
|
||||||
let(:kind) { :correction }
|
let(:reason) { :incorrect }
|
||||||
let(:commentaire) { create(:commentaire, dossier:) }
|
let(:commentaire) { create(:commentaire, dossier:) }
|
||||||
|
|
||||||
subject {
|
subject {
|
||||||
dossier.flag_as_pending_correction!(commentaire, kind)
|
dossier.flag_as_pending_correction!(commentaire, reason)
|
||||||
described_class.with(commentaire:).notify_pending_correction
|
described_class.with(commentaire:).notify_pending_correction
|
||||||
}
|
}
|
||||||
|
|
||||||
context 'kind is correction' do
|
context 'reason is incorrect' do
|
||||||
it { expect(subject.subject).to eq("Vous devez corriger votre dossier nº #{dossier.id} « #{dossier.procedure.libelle} »") }
|
it { expect(subject.subject).to eq("Vous devez corriger votre dossier nº #{dossier.id} « #{dossier.procedure.libelle} »") }
|
||||||
it { expect(subject.body).to include("apporter des corrections") }
|
it { expect(subject.body).to include("apporter des corrections") }
|
||||||
it { expect(subject.body).not_to include("Silence") }
|
it { expect(subject.body).not_to include("Silence") }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'sva with kind is correction' do
|
context 'sva with reason is incorrect' do
|
||||||
let(:sva_svr_decision_on) { Date.tomorrow }
|
let(:sva_svr_decision_on) { Date.tomorrow }
|
||||||
let(:procedure) { create(:procedure, :sva) }
|
let(:procedure) { create(:procedure, :sva) }
|
||||||
|
|
||||||
|
@ -257,9 +257,9 @@ RSpec.describe DossierMailer, type: :mailer do
|
||||||
it { expect(subject.body).to include("suspendu") }
|
it { expect(subject.body).to include("suspendu") }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'sva with kind is incomplete' do
|
context 'sva with reason is incomplete' do
|
||||||
let(:sva_svr_decision_on) { Date.tomorrow }
|
let(:sva_svr_decision_on) { Date.tomorrow }
|
||||||
let(:kind) { :incomplete }
|
let(:reason) { :incomplete }
|
||||||
let(:procedure) { create(:procedure, :sva) }
|
let(:procedure) { create(:procedure, :sva) }
|
||||||
|
|
||||||
it { expect(subject.body).to include("compléter") }
|
it { expect(subject.body).to include("compléter") }
|
||||||
|
@ -267,9 +267,9 @@ RSpec.describe DossierMailer, type: :mailer do
|
||||||
it { expect(subject.body).to include("réinitialisé") }
|
it { expect(subject.body).to include("réinitialisé") }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'svr with kind is incomplete' do
|
context 'svr with reason is incomplete' do
|
||||||
let(:sva_svr_decision_on) { Date.tomorrow }
|
let(:sva_svr_decision_on) { Date.tomorrow }
|
||||||
let(:kind) { :incomplete }
|
let(:reason) { :incomplete }
|
||||||
let(:procedure) { create(:procedure, :svr) }
|
let(:procedure) { create(:procedure, :svr) }
|
||||||
|
|
||||||
it { expect(subject.body).to include("compléter") }
|
it { expect(subject.body).to include("compléter") }
|
||||||
|
|
|
@ -36,12 +36,12 @@ describe DossierCorrectableConcern do
|
||||||
context 'when dossier is en_construction' do
|
context 'when dossier is en_construction' do
|
||||||
it 'creates a correction' do
|
it 'creates a correction' do
|
||||||
expect { flag }.to change { dossier.corrections.pending.count }.by(1)
|
expect { flag }.to change { dossier.corrections.pending.count }.by(1)
|
||||||
expect(dossier.corrections.last).to be_correction
|
expect(dossier.corrections.last).to be_dossier_incorrect
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'created a correction of incomplete kind' do
|
it 'created a correction of incomplete kind' do
|
||||||
expect { dossier.flag_as_pending_correction!(commentaire, "incomplete") }.to change { dossier.corrections.pending.count }.by(1)
|
expect { dossier.flag_as_pending_correction!(commentaire, "incomplete") }.to change { dossier.corrections.pending.count }.by(1)
|
||||||
expect(dossier.corrections.last).to be_incomplete
|
expect(dossier.corrections.last).to be_dossier_incomplete
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not change dossier state' do
|
it 'does not change dossier state' do
|
||||||
|
|
|
@ -1072,30 +1072,38 @@ describe Dossier, type: :model do
|
||||||
let(:last_operation) { dossier.dossier_operation_logs.last }
|
let(:last_operation) { dossier.dossier_operation_logs.last }
|
||||||
let(:operation_serialized) { last_operation.data }
|
let(:operation_serialized) { last_operation.data }
|
||||||
let(:instructeur) { create(:instructeur) }
|
let(:instructeur) { create(:instructeur) }
|
||||||
let!(:correction) { create(:dossier_correction, dossier:) }
|
let!(:correction) { create(:dossier_correction, dossier:) } # correction has a commentaire
|
||||||
|
|
||||||
before { dossier.passer_en_instruction!(instructeur: instructeur) }
|
subject(:passer_en_instruction) { dossier.passer_en_instruction!(instructeur: instructeur) }
|
||||||
|
|
||||||
it { expect(dossier.state).to eq('en_instruction') }
|
it do
|
||||||
it { expect(dossier.followers_instructeurs).to include(instructeur) }
|
passer_en_instruction
|
||||||
it { expect(dossier.en_construction_close_to_expiration_notice_sent_at).to be_nil }
|
|
||||||
it { expect(last_operation.operation).to eq('passer_en_instruction') }
|
expect(dossier.state).to eq('en_instruction')
|
||||||
it { expect(last_operation.automatic_operation?).to be_falsey }
|
expect(dossier.followers_instructeurs).to include(instructeur)
|
||||||
it { expect(operation_serialized['operation']).to eq('passer_en_instruction') }
|
expect(dossier.en_construction_close_to_expiration_notice_sent_at).to be_nil
|
||||||
it { expect(operation_serialized['dossier_id']).to eq(dossier.id) }
|
expect(last_operation.operation).to eq('passer_en_instruction')
|
||||||
it { expect(operation_serialized['executed_at']).to eq(last_operation.executed_at.iso8601) }
|
expect(last_operation.automatic_operation?).to be_falsey
|
||||||
it { expect(dossier.commentaires.count).to eq(1) }
|
expect(operation_serialized['operation']).to eq('passer_en_instruction')
|
||||||
|
expect(operation_serialized['dossier_id']).to eq(dossier.id)
|
||||||
|
expect(operation_serialized['executed_at']).to eq(last_operation.executed_at.iso8601)
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect { passer_en_instruction }.to change { dossier.commentaires.count }.by(1) }
|
||||||
|
|
||||||
it "resolve pending correction" do
|
it "resolve pending correction" do
|
||||||
|
passer_en_instruction
|
||||||
|
|
||||||
expect(dossier.pending_correction?).to be_falsey
|
expect(dossier.pending_correction?).to be_falsey
|
||||||
expect(correction.reload.resolved_at).to be_present
|
expect(correction.reload.resolved_at).to be_present
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates a commentaire in the messagerie with expected wording' do
|
it 'creates a commentaire in the messagerie with expected wording' do
|
||||||
email_template = dossier.procedure.mail_template_for(Dossier.states.fetch(:en_instruction))
|
passer_en_instruction
|
||||||
commentaire = dossier.commentaires.first
|
|
||||||
|
email_template = dossier.procedure.mail_template_for(Dossier.states.fetch(:en_instruction))
|
||||||
|
commentaire = dossier.commentaires.last
|
||||||
|
|
||||||
expect(dossier.commentaires.count).to eq(1)
|
|
||||||
expect(commentaire.body).to include(email_template.subject_for_dossier(dossier), email_template.body_for_dossier(dossier))
|
expect(commentaire.body).to include(email_template.subject_for_dossier(dossier), email_template.body_for_dossier(dossier))
|
||||||
expect(commentaire.dossier).to eq(dossier)
|
expect(commentaire.dossier).to eq(dossier)
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,7 +59,7 @@ describe SVASVRDecisionDateCalculatorService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'there is a pending correction kind = correct' do
|
context 'there is a pending correction reason = incorrect' do
|
||||||
before do
|
before do
|
||||||
travel_to DateTime.new(2023, 5, 30, 18) do
|
travel_to DateTime.new(2023, 5, 30, 18) do
|
||||||
dossier.flag_as_pending_correction!(build(:commentaire, dossier:))
|
dossier.flag_as_pending_correction!(build(:commentaire, dossier:))
|
||||||
|
@ -73,7 +73,7 @@ describe SVASVRDecisionDateCalculatorService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'there is a pending correction kind = incomplete' do
|
context 'there is a pending correction reason = incomplete' do
|
||||||
before do
|
before do
|
||||||
travel_to DateTime.new(2023, 5, 30, 18) do
|
travel_to DateTime.new(2023, 5, 30, 18) do
|
||||||
dossier.flag_as_pending_correction!(build(:commentaire, dossier:), :incomplete)
|
dossier.flag_as_pending_correction!(build(:commentaire, dossier:), :incomplete)
|
||||||
|
|
Loading…
Add table
Reference in a new issue