demarches-normaliennes/spec/models/dossier_spec.rb
Pierre de La Morinerie a8354bd103 dossiers: unify deletion of dossiers between manager and user
The code paths for deleting a dossier were different, depending on
whether the dossier was deleted by the user, or from the Manager.

This commit unifies the two code paths into one.

This has the effect of:

- An operation log is now recorded when an user deletes its own dossier;
- Gestionnaires are now notified even when the dossier is deleted from
  the Manager;
- The `support:delete_user_account` task now requires the email address
  of the author.
2019-07-16 16:22:20 +02:00

1050 lines
41 KiB
Ruby

require 'rails_helper'
describe Dossier do
include ActiveJob::TestHelper
let(:user) { create(:user) }
describe "without_followers scope" do
let!(:dossier) { create(:dossier, :followed, :with_entreprise, user: user) }
let!(:dossier2) { create(:dossier, :with_entreprise, user: user) }
it { expect(Dossier.without_followers.to_a).to eq([dossier2]) }
end
describe 'with_champs' do
let(:procedure) { create(:procedure) }
let(:dossier) { Dossier.create(user: create(:user), procedure: procedure) }
before do
create(:type_de_champ, libelle: 'l1', order_place: 1, procedure: procedure)
create(:type_de_champ, libelle: 'l3', order_place: 3, procedure: procedure)
create(:type_de_champ, libelle: 'l2', order_place: 2, procedure: procedure)
end
it do
expect(Dossier.with_champs.find(dossier.id).champs.map(&:libelle)).to match(['l1', 'l2', 'l3'])
end
end
describe 'nearing_end_of_retention' do
let(:procedure) { create(:procedure, duree_conservation_dossiers_dans_ds: 6) }
let!(:young_dossier) { create(:dossier, procedure: procedure) }
let!(:expiring_dossier) { create(:dossier, :en_instruction, en_instruction_at: 170.days.ago, procedure: procedure) }
let!(:just_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: (6.months + 1.hour + 10.seconds).ago, procedure: procedure) }
let!(:long_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: 1.year.ago, procedure: procedure) }
context 'with default delay to end of retention' do
subject { Dossier.nearing_end_of_retention }
it { is_expected.not_to include(young_dossier) }
it { is_expected.to include(expiring_dossier) }
it { is_expected.to include(just_expired_dossier) }
it { is_expected.to include(long_expired_dossier) }
end
context 'with custom delay to end of retention' do
subject { Dossier.nearing_end_of_retention('0') }
it { is_expected.not_to include(young_dossier) }
it { is_expected.not_to include(expiring_dossier) }
it { is_expected.to include(just_expired_dossier) }
it { is_expected.to include(long_expired_dossier) }
end
end
describe 'methods' do
let(:dossier) { create(:dossier, :with_entreprise, user: user) }
let(:etablissement) { dossier.etablissement }
subject { dossier }
describe '#update_search_terms' do
let(:etablissement) { build(:etablissement, entreprise_nom: 'Dupont', entreprise_prenom: 'Thomas', association_rna: '12345', association_titre: 'asso de test', association_objet: 'tests unitaires') }
let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private) }
let(:dossier) { create(:dossier, etablissement: etablissement, user: user, procedure: procedure) }
let(:france_connect_information) { build(:france_connect_information, given_name: 'Chris', family_name: 'Harrisson') }
let(:user) { build(:user, france_connect_information: france_connect_information) }
let(:champ_public) { dossier.champs.first }
let(:champ_private) { dossier.champs_private.first }
before do
champ_public.update_attribute(:value, "champ public")
champ_private.update_attribute(:value, "champ privé")
dossier.update_search_terms
end
it { expect(dossier.search_terms).to eq("#{user.email} champ public #{etablissement.entreprise_siren} #{etablissement.entreprise_numero_tva_intracommunautaire} #{etablissement.entreprise_forme_juridique} #{etablissement.entreprise_forme_juridique_code} #{etablissement.entreprise_nom_commercial} #{etablissement.entreprise_raison_sociale} #{etablissement.entreprise_siret_siege_social} #{etablissement.entreprise_nom} #{etablissement.entreprise_prenom} #{etablissement.association_rna} #{etablissement.association_titre} #{etablissement.association_objet} #{etablissement.siret} #{etablissement.naf} #{etablissement.libelle_naf} #{etablissement.adresse} #{etablissement.code_postal} #{etablissement.localite} #{etablissement.code_insee_localite}") }
it { expect(dossier.private_search_terms).to eq('champ privé') }
context 'with an update' do
before do
dossier.update(
champs_attributes: [{ id: champ_public.id, value: 'nouvelle valeur publique' }],
champs_private_attributes: [{ id: champ_private.id, value: 'nouvelle valeur privee' }]
)
end
it { expect(dossier.search_terms).to include('nouvelle valeur publique') }
it { expect(dossier.private_search_terms).to include('nouvelle valeur privee') }
end
end
describe '#types_de_piece_justificative' do
subject { dossier.types_de_piece_justificative }
it 'returns list of required piece justificative' do
expect(subject.size).to eq(2)
expect(subject).to include(TypeDePieceJustificative.find(TypeDePieceJustificative.first.id))
end
end
describe '#types_de_piece_justificative' do
subject { dossier.types_de_piece_justificative }
it 'returns list of required piece justificative' do
expect(subject.size).to eq(2)
expect(subject).to include(TypeDePieceJustificative.find(TypeDePieceJustificative.first.id))
end
end
describe '#retrieve_last_piece_justificative_by_type', vcr: { cassette_name: 'models_dossier_retrieve_last_piece_justificative_by_type' } do
let(:types_de_pj_dossier) { dossier.procedure.types_de_piece_justificative }
subject { dossier.retrieve_last_piece_justificative_by_type types_de_pj_dossier.first }
before do
create :piece_justificative, :rib, dossier: dossier, type_de_piece_justificative: types_de_pj_dossier.first
end
it 'returns piece justificative with given type' do
expect(subject.type).to eq(types_de_pj_dossier.first.id)
end
end
describe '#retrieve_all_piece_justificative_by_type' do
let(:types_de_pj_dossier) { dossier.procedure.types_de_piece_justificative }
subject { dossier.retrieve_all_piece_justificative_by_type types_de_pj_dossier.first }
before do
create :piece_justificative, :rib, dossier: dossier, type_de_piece_justificative: types_de_pj_dossier.first
end
it 'returns a list of the piece justificative' do
expect(subject).not_to be_empty
end
end
describe '#build_default_champs' do
context 'when dossier is linked to a procedure with type_de_champ_public and private' do
let(:dossier) { create(:dossier, user: user) }
it 'build all champs needed' do
expect(dossier.champs.count).to eq(1)
end
it 'build all champs_private needed' do
expect(dossier.champs_private.count).to eq(1)
end
end
end
describe '#build_default_individual' do
context 'when dossier is linked to a procedure with for_individual attr false' do
let(:dossier) { create(:dossier, user: user) }
it 'have no object created' do
expect(dossier.individual).to be_nil
end
end
context 'when dossier is linked to a procedure with for_individual attr true' do
let(:dossier) { create(:dossier, user: user, procedure: (create :procedure, for_individual: true)) }
it 'have no object created' do
expect(dossier.individual).not_to be_nil
end
end
end
describe '#save' do
subject { build(:dossier, procedure: procedure, user: user) }
let!(:procedure) { create(:procedure) }
context 'when is linked to a procedure' do
it 'creates default champs' do
expect(subject).to receive(:build_default_champs)
subject.save
end
end
context 'when is not linked to a procedure' do
subject { create(:dossier, procedure: nil, user: user) }
it 'does not create default champs' do
expect(subject).not_to receive(:build_default_champs)
subject.update(state: Dossier.states.fetch(:en_construction))
end
end
end
end
context 'when dossier is followed' do
let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private) }
let(:gestionnaire) { create(:gestionnaire) }
let(:date1) { 1.day.ago }
let(:date2) { 1.hour.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!(:follow) { create(:follow, gestionnaire: gestionnaire, dossier: dossier) }
describe "followers_gestionnaires" do
let(:non_following_gestionnaire) { create(:gestionnaire) }
subject { dossier.followers_gestionnaires }
it { expect(subject).to eq [gestionnaire] }
it { expect(subject).not_to include(non_following_gestionnaire) }
end
end
describe '#reset!' do
let!(:dossier) { create :dossier, :with_entreprise, autorisation_donnees: true }
let!(:exercice) { create :exercice, etablissement: dossier.etablissement }
subject { dossier.reset! }
it { expect(dossier.etablissement).not_to be_nil }
it { expect(dossier.etablissement.exercices).not_to be_empty }
it { expect(dossier.etablissement.exercices.size).to eq 1 }
it { expect(dossier.autorisation_donnees).to be_truthy }
it { expect { subject }.to change(Exercice, :count).by(-1) }
it { expect { subject }.to change(Etablissement, :count).by(-1) }
context 'when method reset! is call' do
before do
subject
dossier.reload
end
it { expect(dossier.etablissement).to be_nil }
it { expect(dossier.autorisation_donnees).to be_falsey }
end
end
describe '#champs' do
let(:procedure) { create(:procedure) }
let(:dossier) { Dossier.create(user: create(:user), procedure: procedure) }
before do
create(:type_de_champ, libelle: 'l1', order_place: 1, procedure: procedure)
create(:type_de_champ, libelle: 'l3', order_place: 3, procedure: procedure)
create(:type_de_champ, libelle: 'l2', order_place: 2, procedure: procedure)
end
it { expect(dossier.champs.pluck(:libelle)).to match(['l1', 'l2', 'l3']) }
end
describe '#champs_private' do
let(:procedure) { create :procedure }
let(:dossier) { Dossier.create(user: create(:user), procedure: procedure) }
before do
create :type_de_champ, :private, libelle: 'l1', order_place: 1, procedure: procedure
create :type_de_champ, :private, libelle: 'l3', order_place: 3, procedure: procedure
create :type_de_champ, :private, libelle: 'l2', order_place: 2, procedure: procedure
end
it { expect(dossier.champs_private.pluck(:libelle)).to match(['l1', 'l2', 'l3']) }
end
describe "#text_summary" do
let(:service) { create(:service, nom: 'nom du service') }
let(:procedure) { create(:procedure, libelle: "Démarche", organisation: "Organisme", service: service) }
context 'when the dossier has been en_construction' do
let(:dossier) { create :dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction), en_construction_at: "31/12/2010".to_date }
subject { dossier.text_summary }
it { is_expected.to eq("Dossier déposé le 31/12/2010 sur la démarche Démarche gérée par l'organisme nom du service") }
end
context 'when the dossier has not been en_construction' do
let(:dossier) { create :dossier, procedure: procedure, state: Dossier.states.fetch(:brouillon) }
subject { dossier.text_summary }
it { is_expected.to eq("Dossier en brouillon répondant à la démarche Démarche gérée par l'organisme nom du service") }
end
end
describe '#avis_for' do
let!(:procedure) { create(:procedure, :published) }
let!(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction)) }
let!(:gestionnaire) { create(:gestionnaire, procedures: [procedure]) }
let!(:expert_1) { create(:gestionnaire) }
let!(:expert_2) { create(:gestionnaire) }
context 'when there is a public advice asked from the dossiers gestionnaire' do
let!(:avis) { Avis.create(dossier: dossier, claimant: gestionnaire, gestionnaire: expert_1, confidentiel: false) }
it { expect(dossier.avis_for(gestionnaire)).to match([avis]) }
it { expect(dossier.avis_for(expert_1)).to match([avis]) }
it { expect(dossier.avis_for(expert_2)).to match([avis]) }
end
context 'when there is a private advice asked from the dossiers gestionnaire' do
let!(:avis) { Avis.create(dossier: dossier, claimant: gestionnaire, gestionnaire: expert_1, confidentiel: true) }
it { expect(dossier.avis_for(gestionnaire)).to match([avis]) }
it { expect(dossier.avis_for(expert_1)).to match([avis]) }
it { expect(dossier.avis_for(expert_2)).to match([]) }
end
context 'when there is a public advice asked from one expert to another' do
let!(:avis) { Avis.create(dossier: dossier, claimant: expert_1, gestionnaire: expert_2, confidentiel: false) }
it { expect(dossier.avis_for(gestionnaire)).to match([avis]) }
it { expect(dossier.avis_for(expert_1)).to match([avis]) }
it { expect(dossier.avis_for(expert_2)).to match([avis]) }
end
context 'when there is a private advice asked from one expert to another' do
let!(:avis) { Avis.create(dossier: dossier, claimant: expert_1, gestionnaire: expert_2, confidentiel: true) }
it { expect(dossier.avis_for(gestionnaire)).to match([avis]) }
it { expect(dossier.avis_for(expert_1)).to match([avis]) }
it { expect(dossier.avis_for(expert_2)).to match([avis]) }
end
context 'when they are a lot of advice' do
let!(:avis_1) { Avis.create(dossier: dossier, claimant: expert_1, gestionnaire: expert_2, confidentiel: false, created_at: Time.zone.parse('10/01/2010')) }
let!(:avis_2) { Avis.create(dossier: dossier, claimant: expert_1, gestionnaire: expert_2, confidentiel: false, created_at: Time.zone.parse('9/01/2010')) }
let!(:avis_3) { Avis.create(dossier: dossier, claimant: expert_1, gestionnaire: expert_2, confidentiel: false, created_at: Time.zone.parse('11/01/2010')) }
it { expect(dossier.avis_for(gestionnaire)).to match([avis_2, avis_1, avis_3]) }
it { expect(dossier.avis_for(expert_1)).to match([avis_2, avis_1, avis_3]) }
end
end
describe '#update_state_dates' do
let(:state) { Dossier.states.fetch(:brouillon) }
let(:dossier) { create(:dossier, state: state) }
let(:beginning_of_day) { Time.zone.now.beginning_of_day }
before { Timecop.freeze(beginning_of_day) }
after { Timecop.return }
context 'when dossier is en_construction' do
before do
dossier.en_construction!
dossier.reload
end
it { expect(dossier.state).to eq(Dossier.states.fetch(:en_construction)) }
it { expect(dossier.en_construction_at).to eq(beginning_of_day) }
it 'should keep first en_construction_at date' do
Timecop.return
dossier.en_instruction!
dossier.en_construction!
expect(dossier.en_construction_at).to eq(beginning_of_day)
end
end
context 'when dossier is en_instruction' do
let(:state) { Dossier.states.fetch(:en_construction) }
before do
dossier.en_instruction!
dossier.reload
end
it { expect(dossier.state).to eq(Dossier.states.fetch(:en_instruction)) }
it { expect(dossier.en_instruction_at).to eq(beginning_of_day) }
it 'should keep first en_instruction_at date if dossier is set to en_construction again' do
Timecop.return
dossier.en_construction!
dossier.en_instruction!
expect(dossier.en_instruction_at).to eq(beginning_of_day)
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
let(:state) { Dossier.states.fetch(:en_instruction) }
it_behaves_like 'dossier is processed', Dossier.states.fetch(:accepte)
end
context 'when dossier is refuse' do
let(:state) { Dossier.states.fetch(:en_instruction) }
it_behaves_like 'dossier is processed', Dossier.states.fetch(:refuse)
end
context 'when dossier is sans_suite' do
let(:state) { Dossier.states.fetch(:en_instruction) }
it_behaves_like 'dossier is processed', Dossier.states.fetch(:sans_suite)
end
end
describe '.downloadable_sorted' do
let(:procedure) { create(:procedure) }
let!(:dossier) { create(:dossier, :with_entreprise, procedure: procedure, state: Dossier.states.fetch(:brouillon)) }
let!(:dossier2) { create(:dossier, :with_entreprise, procedure: procedure, state: Dossier.states.fetch(:en_construction), en_construction_at: Time.zone.parse('03/01/2010')) }
let!(:dossier3) { create(:dossier, :with_entreprise, procedure: procedure, state: Dossier.states.fetch(:en_instruction), en_construction_at: Time.zone.parse('01/01/2010')) }
let!(:dossier4) { create(:dossier, :with_entreprise, procedure: procedure, state: Dossier.states.fetch(:en_instruction), archived: true, en_construction_at: Time.zone.parse('02/01/2010')) }
subject { procedure.dossiers.downloadable_sorted }
it { is_expected.to match([dossier3, dossier4, dossier2]) }
end
describe "#send_dossier_received" do
let(:procedure) { create(:procedure) }
let(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction)) }
before do
allow(NotificationMailer).to receive(:send_dossier_received).and_return(double(deliver_later: nil))
end
it "sends an email when the dossier becomes en_instruction" do
dossier.en_instruction!
expect(NotificationMailer).to have_received(:send_dossier_received).with(dossier)
end
it "does not an email when the dossier becomes accepte" do
dossier.accepte!
expect(NotificationMailer).to_not have_received(:send_dossier_received)
end
end
describe "#send_draft_notification_email" do
include Rails.application.routes.url_helpers
let(:procedure) { create(:procedure) }
let(:user) { create(:user) }
it "send an email when the dossier is created for the very first time" do
dossier = nil
expect do
perform_enqueued_jobs do
dossier = Dossier.create(procedure: procedure, state: Dossier.states.fetch(:brouillon), user: user)
end
end.to change(ActionMailer::Base.deliveries, :size).from(0).to(1)
mail = ActionMailer::Base.deliveries.last
expect(mail.subject).to eq("Retrouvez votre brouillon pour la démarche \"#{procedure.libelle}\"")
expect(mail.html_part.body).to include(dossier_url(dossier))
end
it "does not send an email when the dossier is created with a non brouillon state" do
expect { Dossier.create(procedure: procedure, state: Dossier.states.fetch(:en_construction), user: user) }.not_to change(ActionMailer::Base.deliveries, :size)
expect { Dossier.create(procedure: procedure, state: Dossier.states.fetch(:en_instruction), user: user) }.not_to change(ActionMailer::Base.deliveries, :size)
expect { Dossier.create(procedure: procedure, state: Dossier.states.fetch(:accepte), user: user) }.not_to change(ActionMailer::Base.deliveries, :size)
expect { Dossier.create(procedure: procedure, state: Dossier.states.fetch(:refuse), user: user) }.not_to change(ActionMailer::Base.deliveries, :size)
expect { Dossier.create(procedure: procedure, state: Dossier.states.fetch(:sans_suite), user: user) }.not_to change(ActionMailer::Base.deliveries, :size)
end
end
describe "#unspecified_attestation_champs" do
let(:procedure) { create(:procedure, attestation_template: attestation_template) }
let(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) }
subject { dossier.unspecified_attestation_champs.map(&:libelle) }
context "without attestation template" do
let(:attestation_template) { nil }
it { is_expected.to eq([]) }
end
context "with attestation template" do
# Test all combinations:
# - with tag specified and unspecified
# - with tag in body and tag in title
# - with tag correponsing to a champ and an annotation privée
# - with a dash in the champ libelle / tag
let(:title) { "voici --specified champ-in-title-- un --unspecified champ-in-title-- beau --specified annotation privée-in-title-- titre --unspecified annotation privée-in-title-- non --numéro du dossier--" }
let(:body) { "voici --specified champ-in-body-- un --unspecified champ-in-body-- beau --specified annotation privée-in-body-- body --unspecified annotation privée-in-body-- non ?" }
let(:attestation_template) { create(:attestation_template, title: title, body: body, activated: activated) }
context "which is disabled" do
let(:activated) { false }
it { is_expected.to eq([]) }
end
context "wich is enabled" do
let(:activated) { true }
let!(:tdc_1) { create(:type_de_champ, libelle: "specified champ-in-title", procedure: procedure) }
let!(:tdc_2) { create(:type_de_champ, libelle: "unspecified champ-in-title", procedure: procedure) }
let!(:tdc_3) { create(:type_de_champ, libelle: "specified champ-in-body", procedure: procedure) }
let!(:tdc_4) { create(:type_de_champ, libelle: "unspecified champ-in-body", procedure: procedure) }
let!(:tdc_5) { create(:type_de_champ, private: true, libelle: "specified annotation privée-in-title", procedure: procedure) }
let!(:tdc_6) { create(:type_de_champ, private: true, libelle: "unspecified annotation privée-in-title", procedure: procedure) }
let!(:tdc_7) { create(:type_de_champ, private: true, libelle: "specified annotation privée-in-body", procedure: procedure) }
let!(:tdc_8) { create(:type_de_champ, private: true, libelle: "unspecified annotation privée-in-body", procedure: procedure) }
before do
(dossier.champs + dossier.champs_private)
.select { |c| c.libelle.match?(/^specified/) }
.each { |c| c.update_attribute(:value, "specified") }
end
it do
is_expected.to eq([
"unspecified champ-in-title",
"unspecified annotation privée-in-title",
"unspecified champ-in-body",
"unspecified annotation privée-in-body"
])
end
end
end
end
describe '#build_attestation' do
let(:attestation_template) { nil }
let(:procedure) { create(:procedure, attestation_template: attestation_template) }
before :each do
dossier.attestation = dossier.build_attestation
dossier.reload
end
context 'when the dossier is in en_instruction state ' do
let!(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) }
context 'when the procedure has no attestation' do
it { expect(dossier.attestation).to be_nil }
end
context 'when the procedure has an unactivated attestation' do
let(:attestation_template) { AttestationTemplate.new(activated: false) }
it { expect(dossier.attestation).to be_nil }
end
context 'when the procedure attached has an activated attestation' do
let(:attestation_template) { AttestationTemplate.new(activated: true) }
it { expect(dossier.attestation).not_to be_nil }
end
end
end
describe ".default_scope" do
let!(:dossier) { create(:dossier, hidden_at: hidden_at) }
context "when dossier is not hidden" do
let(:hidden_at) { nil }
it { expect(Dossier.count).to eq(1) }
it { expect(Dossier.all).to include(dossier) }
end
context "when dossier is hidden" do
let(:hidden_at) { 1.day.ago }
it { expect(Dossier.count).to eq(0) }
end
end
describe 'updated_at' do
let!(:dossier) { create(:dossier) }
let(:modif_date) { Time.zone.parse('01/01/2100') }
before { Timecop.freeze(modif_date) }
after { Timecop.return }
subject do
dossier.reload
dossier.updated_at
end
it { is_expected.not_to eq(modif_date) }
context 'when a piece justificative is modified' do
before { dossier.pieces_justificatives << create(:piece_justificative, :contrat) }
it { is_expected.to eq(modif_date) }
end
context 'when a champ is modified' do
before { dossier.champs.first.update_attribute('value', 'yop') }
it { is_expected.to eq(modif_date) }
end
context 'when a commentaire is modified' do
before { dossier.commentaires << create(:commentaire) }
it { is_expected.to eq(modif_date) }
end
context 'when an avis is modified' do
before { dossier.avis << create(:avis) }
it { is_expected.to eq(modif_date) }
end
end
describe '#owner_name' do
let!(:procedure) { create(:procedure) }
subject { dossier.owner_name }
context 'when there is no entreprise or individual' do
let(:dossier) { create(:dossier, individual: nil, procedure: procedure) }
it { is_expected.to be_nil }
end
context 'when there is entreprise' do
let(:dossier) { create(:dossier, :with_entreprise, procedure: procedure) }
it { is_expected.to eq(dossier.etablissement.entreprise_raison_sociale) }
end
context 'when there is an individual' do
let(:dossier) { create(:dossier, :for_individual, procedure: procedure) }
it { is_expected.to eq("#{dossier.individual.nom} #{dossier.individual.prenom}") }
end
end
describe "#delete_and_keep_track" do
let(:dossier) { create(:dossier) }
let(:deleted_dossier) { DeletedDossier.find_by!(dossier_id: dossier.id) }
let(:last_operation) { dossier.dossier_operation_logs.last }
before do
allow(DossierMailer).to receive(:notify_deletion_to_user).and_return(double(deliver_later: nil))
allow(DossierMailer).to receive(:notify_deletion_to_administration).and_return(double(deliver_later: nil))
end
subject! { dossier.delete_and_keep_track(dossier.user) }
it 'hides the dossier' do
expect(dossier.hidden_at).to be_present
end
it 'creates a DeletedDossier record' do
expect(deleted_dossier.dossier_id).to eq dossier.id
expect(deleted_dossier.procedure).to eq dossier.procedure
expect(deleted_dossier.state).to eq dossier.state
expect(deleted_dossier.deleted_at).to be_present
end
it 'notifies the user' do
expect(DossierMailer).to have_received(:notify_deletion_to_user).with(deleted_dossier, dossier.user.email)
end
it 'records the operation in the log' do
expect(last_operation.operation).to eq("supprimer")
expect(last_operation.automatic_operation?).to be_falsey
end
context 'where gestionnaires are following the dossier' do
let(:dossier) { create(:dossier, :en_construction, :followed) }
let!(:non_following_gestionnaire) do
non_following_gestionnaire = create(:gestionnaire)
non_following_gestionnaire.procedures << dossier.procedure
non_following_gestionnaire
end
it 'notifies the following gestionnaires' do
expect(DossierMailer).to have_received(:notify_deletion_to_administration).once
expect(DossierMailer).to have_received(:notify_deletion_to_administration).with(deleted_dossier, dossier.followers_gestionnaires.first.email)
end
end
context 'when there are no following gestionnaires' do
let(:dossier) { create(:dossier, :en_construction) }
it 'notifies the procedure administrateur' do
expect(DossierMailer).to have_received(:notify_deletion_to_administration).once
expect(DossierMailer).to have_received(:notify_deletion_to_administration).with(deleted_dossier, dossier.procedure.administrateurs.first.email)
end
end
context 'when dossier is brouillon' do
let(:dossier) { create(:dossier) }
it 'do not notifies the procedure administrateur' do
expect(DossierMailer).not_to have_received(:notify_deletion_to_administration)
end
end
end
describe 'webhook' do
let(:dossier) { create(:dossier) }
it 'should not call webhook' do
expect {
dossier.accepte!
}.to_not have_enqueued_job(WebHookJob)
end
it 'should call webhook' do
dossier.procedure.update_column(:web_hook_url, '/webhook.json')
expect {
dossier.update_column(:motivation, 'bonjour')
}.to_not have_enqueued_job(WebHookJob)
expect {
dossier.en_construction!
}.to have_enqueued_job(WebHookJob)
expect {
dossier.update_column(:motivation, 'bonjour2')
}.to_not have_enqueued_job(WebHookJob)
expect {
dossier.en_instruction!
}.to have_enqueued_job(WebHookJob)
end
end
describe "#can_transition_to_en_construction?" do
let(:procedure) { create(:procedure, :published) }
let(:dossier) { create(:dossier, state: state, procedure: procedure) }
subject { dossier.can_transition_to_en_construction? }
context "dossier state is brouillon" do
let(:state) { Dossier.states.fetch(:brouillon) }
it { is_expected.to be true }
context "procedure is archived" do
before { procedure.archive }
it { is_expected.to be false }
end
end
context "dossier state is en_construction" do
let(:state) { Dossier.states.fetch(:en_construction) }
it { is_expected.to be false }
end
context "dossier state is en_instruction" do
let(:state) { Dossier.states.fetch(:en_instruction) }
it { is_expected.to be false }
end
context "dossier state is en_instruction" do
let(:state) { Dossier.states.fetch(:accepte) }
it { is_expected.to be false }
end
context "dossier state is en_instruction" do
let(:state) { Dossier.states.fetch(:refuse) }
it { is_expected.to be false }
end
context "dossier state is en_instruction" do
let(:state) { Dossier.states.fetch(:sans_suite) }
it { is_expected.to be false }
end
end
describe "#messagerie_available?" do
let(:procedure) { create(:procedure) }
let(:dossier) { create(:dossier, procedure: procedure) }
subject { dossier.messagerie_available? }
context "dossier is brouillon" do
before { dossier.state = Dossier.states.fetch(:brouillon) }
it { is_expected.to be false }
end
context "dossier is submitted" do
before { dossier.state = Dossier.states.fetch(:en_instruction) }
it { is_expected.to be true }
end
context "dossier is archived" do
before { dossier.archived = true }
it { is_expected.to be false }
end
end
context "retention date" do
let(:procedure) { create(:procedure, duree_conservation_dossiers_dans_ds: 6) }
let(:uninstructed_dossier) { create(:dossier, :en_construction, procedure: procedure) }
let(:young_dossier) { create(:dossier, :en_instruction, en_instruction_at: Time.zone.now, procedure: procedure) }
let(:just_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: 6.months.ago, procedure: procedure) }
let(:long_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: 1.year.ago, procedure: procedure) }
let(:modif_date) { Time.zone.parse('01/01/2100') }
before { Timecop.freeze(modif_date) }
after { Timecop.return }
describe "#retention_end_date" do
it { expect(uninstructed_dossier.retention_end_date).to be_nil }
it { expect(young_dossier.retention_end_date).to eq(6.months.from_now) }
it { expect(just_expired_dossier.retention_end_date).to eq(Time.zone.now) }
it { expect(long_expired_dossier.retention_end_date).to eq(6.months.ago) }
end
describe "#retention_expired?" do
it { expect(uninstructed_dossier).not_to be_retention_expired }
it { expect(young_dossier).not_to be_retention_expired }
it { expect(just_expired_dossier).to be_retention_expired }
it { expect(long_expired_dossier).to be_retention_expired }
end
end
describe '#accepter!' do
let(:dossier) { create(:dossier, :en_instruction) }
let(:last_operation) { dossier.dossier_operation_logs.last }
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
let!(:gestionnaire) { create(:gestionnaire) }
let!(:now) { Time.zone.parse('01/01/2100') }
let(:attestation) { Attestation.new }
before do
allow(NotificationMailer).to receive(:send_closed_notification).and_return(double(deliver_later: true))
allow(dossier).to receive(:build_attestation).and_return(attestation)
Timecop.freeze(now)
dossier.accepter!(gestionnaire, 'motivation')
dossier.reload
end
after { Timecop.return }
it { expect(dossier.motivation).to eq('motivation') }
it { expect(dossier.en_instruction_at).to eq(dossier.en_instruction_at) }
it { expect(dossier.processed_at).to eq(now) }
it { expect(dossier.state).to eq('accepte') }
it { expect(last_operation.operation).to eq('accepter') }
it { expect(last_operation.automatic_operation?).to be_falsey }
it { expect(operation_serialized['operation']).to eq('accepter') }
it { expect(operation_serialized['dossier_id']).to eq(dossier.id) }
it { expect(operation_serialized['executed_at']).to eq(last_operation.executed_at.iso8601) }
it { expect(NotificationMailer).to have_received(:send_closed_notification).with(dossier) }
it { expect(dossier.attestation).to eq(attestation) }
end
describe '#accepter_automatiquement!' do
let(:dossier) { create(:dossier, :en_construction) }
let(:last_operation) { dossier.dossier_operation_logs.last }
let!(:now) { Time.zone.parse('01/01/2100') }
let(:attestation) { Attestation.new }
before do
allow(NotificationMailer).to receive(:send_closed_notification).and_return(double(deliver_later: true))
allow(dossier).to receive(:build_attestation).and_return(attestation)
Timecop.freeze(now)
dossier.accepter_automatiquement!
dossier.reload
end
after { Timecop.return }
it { expect(dossier.motivation).to eq(nil) }
it { expect(dossier.en_instruction_at).to eq(now) }
it { expect(dossier.processed_at).to eq(now) }
it { expect(dossier.state).to eq('accepte') }
it { expect(last_operation.operation).to eq('accepter') }
it { expect(last_operation.automatic_operation?).to be_truthy }
it { expect(NotificationMailer).to have_received(:send_closed_notification).with(dossier) }
it { expect(dossier.attestation).to eq(attestation) }
end
describe '#passer_en_instruction!' do
let(:dossier) { create(:dossier, :en_construction) }
let(:last_operation) { dossier.dossier_operation_logs.last }
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
let(:gestionnaire) { create(:gestionnaire) }
before { dossier.passer_en_instruction!(gestionnaire) }
it { expect(dossier.state).to eq('en_instruction') }
it { expect(dossier.followers_gestionnaires).to include(gestionnaire) }
it { expect(last_operation.operation).to eq('passer_en_instruction') }
it { expect(last_operation.automatic_operation?).to be_falsey }
it { expect(operation_serialized['operation']).to eq('passer_en_instruction') }
it { expect(operation_serialized['dossier_id']).to eq(dossier.id) }
it { expect(operation_serialized['executed_at']).to eq(last_operation.executed_at.iso8601) }
end
describe '#passer_automatiquement_en_instruction!' do
let(:dossier) { create(:dossier, :en_construction) }
let(:last_operation) { dossier.dossier_operation_logs.last }
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
let(:gestionnaire) { create(:gestionnaire) }
before { dossier.passer_automatiquement_en_instruction! }
it { expect(dossier.followers_gestionnaires).not_to include(gestionnaire) }
it { expect(last_operation.operation).to eq('passer_en_instruction') }
it { expect(last_operation.automatic_operation?).to be_truthy }
it { expect(operation_serialized['operation']).to eq('passer_en_instruction') }
it { expect(operation_serialized['dossier_id']).to eq(dossier.id) }
it { expect(operation_serialized['executed_at']).to eq(last_operation.executed_at.iso8601) }
end
describe "#check_mandatory_champs" do
let(:procedure) { create(:procedure, :with_type_de_champ) }
let(:dossier) { create(:dossier, procedure: procedure) }
it 'no mandatory champs' do
expect(dossier.check_mandatory_champs).to be_empty
end
context "with mandatory champs" do
let(:procedure) { create(:procedure, :with_type_de_champ_mandatory) }
let(:champ_with_error) { dossier.champs.first }
before do
champ_with_error.value = nil
champ_with_error.save
end
it 'should have errors' do
errors = dossier.check_mandatory_champs
expect(errors).not_to be_empty
expect(errors.first).to eq("Le champ #{champ_with_error.libelle} doit être rempli.")
end
end
context "with mandatory SIRET champ" do
let(:type_de_champ) { create(:type_de_champ_siret, mandatory: true) }
let(:champ_siret) { create(:champ_siret, type_de_champ: type_de_champ) }
before do
dossier.champs << champ_siret
end
it 'should not have errors' do
errors = dossier.check_mandatory_champs
expect(errors).to be_empty
end
context "and invalid SIRET" do
before do
champ_siret.update(value: "1234")
dossier.reload
end
it 'should have errors' do
errors = dossier.check_mandatory_champs
expect(errors).not_to be_empty
expect(errors.first).to eq("Le champ #{champ_siret.libelle} doit être rempli.")
end
end
end
context "with champ repetition" do
let(:procedure) { create(:procedure) }
let(:type_de_champ_repetition) { create(:type_de_champ_repetition, mandatory: true) }
before do
procedure.types_de_champ << type_de_champ_repetition
type_de_champ_repetition.types_de_champ << create(:type_de_champ_text, mandatory: true)
end
context "when no champs" do
let(:champ_with_error) do
repetition_champ = dossier.champs.first
text_champ = repetition_champ.rows.first.first
text_champ
end
it 'should have errors' do
errors = dossier.check_mandatory_champs
expect(errors).not_to be_empty
expect(errors.first).to eq("Le champ #{champ_with_error.libelle} doit être rempli.")
end
end
context "when mandatory champ inside repetition" do
let(:champ_with_error) { dossier.champs.first.champs.first }
before do
dossier.champs.first.add_row
end
it 'should have errors' do
errors = dossier.check_mandatory_champs
expect(errors).not_to be_empty
expect(errors.first).to eq("Le champ #{champ_with_error.libelle} doit être rempli.")
end
end
end
end
describe '#repasser_en_instruction!' do
let(:dossier) { create(:dossier, :refuse, :with_attestation) }
let!(:gestionnaire) { create(:gestionnaire) }
let(:last_operation) { dossier.dossier_operation_logs.last }
before do
Timecop.freeze
allow(DossierMailer).to receive(:notify_revert_to_instruction)
.and_return(double(deliver_later: true))
dossier.repasser_en_instruction!(gestionnaire)
dossier.reload
end
it { expect(dossier.state).to eq('en_instruction') }
it { expect(dossier.processed_at).to be_nil }
it { expect(dossier.motivation).to be_nil }
it { expect(dossier.attestation).to be_nil }
it { expect(last_operation.operation).to eq('repasser_en_instruction') }
it { expect(JSON.parse(last_operation.serialized.download)['author']['email']).to eq(gestionnaire.email) }
it { expect(DossierMailer).to have_received(:notify_revert_to_instruction).with(dossier) }
after { Timecop.return }
end
describe '#attachments_downloadable?' do
let(:dossier) { create(:dossier, user: user) }
# subject { dossier.attachments_downloadable? }
context "no attachments" do
it {
expect(PiecesJustificativesService).to receive(:liste_pieces_justificatives).and_return([])
expect(dossier.attachments_downloadable?).to be false
}
end
context "with a small attachment" do
it {
expect(PiecesJustificativesService).to receive(:liste_pieces_justificatives).and_return([Champ.new])
expect(PiecesJustificativesService).to receive(:pieces_justificatives_total_size).and_return(4.megabytes)
expect(dossier.attachments_downloadable?).to be true
}
end
context "with a too large attachment" do
it {
expect(PiecesJustificativesService).to receive(:liste_pieces_justificatives).and_return([Champ.new])
expect(PiecesJustificativesService).to receive(:pieces_justificatives_total_size).and_return(100.megabytes)
expect(dossier.attachments_downloadable?).to be false
}
end
end
end