339066778d
after a dossier creation, only the instructeurs that belong to the group instructeur of the dossier, and who want notif will be notified by mail
1031 lines
35 KiB
Ruby
1031 lines
35 KiB
Ruby
describe Users::DossiersController, type: :controller do
|
||
let(:user) { create(:user) }
|
||
|
||
describe 'before_actions' do
|
||
it 'are present' do
|
||
before_actions = Users::DossiersController
|
||
._process_action_callbacks
|
||
.filter { |process_action_callbacks| process_action_callbacks.kind == :before }
|
||
.map(&:filter)
|
||
|
||
expect(before_actions).to include(:ensure_ownership!, :ensure_ownership_or_invitation!, :forbid_invite_submission!)
|
||
end
|
||
end
|
||
|
||
shared_examples_for 'does not redirect nor flash' do
|
||
before { @controller.send(ensure_authorized) }
|
||
|
||
it { expect(@controller).not_to have_received(:redirect_to) }
|
||
it { expect(flash.alert).to eq(nil) }
|
||
end
|
||
|
||
shared_examples_for 'redirects and flashes' do
|
||
before { @controller.send(ensure_authorized) }
|
||
|
||
it { expect(@controller).to have_received(:redirect_to).with(root_path) }
|
||
it { expect(flash.alert).to eq("Vous n'avez pas accès à ce dossier") }
|
||
end
|
||
|
||
describe '#ensure_ownership!' do
|
||
let(:user) { create(:user) }
|
||
let(:asked_dossier) { create(:dossier) }
|
||
let(:ensure_authorized) { :ensure_ownership! }
|
||
|
||
before do
|
||
@controller.params = @controller.params.merge(dossier_id: asked_dossier.id)
|
||
expect(@controller).to receive(:current_user).and_return(user)
|
||
allow(@controller).to receive(:redirect_to)
|
||
end
|
||
|
||
context 'when a user asks for their own dossier' do
|
||
let(:asked_dossier) { create(:dossier, user: user) }
|
||
|
||
it_behaves_like 'does not redirect nor flash'
|
||
end
|
||
|
||
context 'when a user asks for another dossier' do
|
||
it_behaves_like 'redirects and flashes'
|
||
end
|
||
|
||
context 'when an invite asks for a dossier where they were invited' do
|
||
before { create(:invite, dossier: asked_dossier, user: user) }
|
||
|
||
it_behaves_like 'redirects and flashes'
|
||
end
|
||
|
||
context 'when an invite asks for another dossier' do
|
||
before { create(:invite, dossier: create(:dossier), user: user) }
|
||
|
||
it_behaves_like 'redirects and flashes'
|
||
end
|
||
end
|
||
|
||
describe '#ensure_ownership_or_invitation!' do
|
||
let(:user) { create(:user) }
|
||
let(:asked_dossier) { create(:dossier) }
|
||
let(:ensure_authorized) { :ensure_ownership_or_invitation! }
|
||
|
||
before do
|
||
@controller.params = @controller.params.merge(dossier_id: asked_dossier.id)
|
||
expect(@controller).to receive(:current_user).and_return(user)
|
||
allow(@controller).to receive(:redirect_to)
|
||
end
|
||
|
||
context 'when a user asks for their own dossier' do
|
||
let(:asked_dossier) { create(:dossier, user: user) }
|
||
|
||
it_behaves_like 'does not redirect nor flash'
|
||
end
|
||
|
||
context 'when a user asks for another dossier' do
|
||
it_behaves_like 'redirects and flashes'
|
||
end
|
||
|
||
context 'when an invite asks for a dossier where they were invited' do
|
||
before { create(:invite, dossier: asked_dossier, user: user) }
|
||
|
||
it_behaves_like 'does not redirect nor flash'
|
||
end
|
||
|
||
context 'when an invite asks for another dossier' do
|
||
before { create(:invite, dossier: create(:dossier), user: user) }
|
||
|
||
it_behaves_like 'redirects and flashes'
|
||
end
|
||
end
|
||
|
||
describe "#forbid_invite_submission!" do
|
||
let(:user) { create(:user) }
|
||
let(:asked_dossier) { create(:dossier) }
|
||
let(:ensure_authorized) { :forbid_invite_submission! }
|
||
let(:submit) { true }
|
||
|
||
before do
|
||
@controller.params = @controller.params.merge(dossier_id: asked_dossier.id, submit_draft: submit)
|
||
allow(@controller).to receive(:current_user).and_return(user)
|
||
allow(@controller).to receive(:redirect_to)
|
||
end
|
||
|
||
context 'when a user save their own draft' do
|
||
let(:asked_dossier) { create(:dossier, user: user) }
|
||
let(:submit) { false }
|
||
|
||
it_behaves_like 'does not redirect nor flash'
|
||
end
|
||
|
||
context 'when a user submit their own dossier' do
|
||
let(:asked_dossier) { create(:dossier, user: user) }
|
||
let(:submit) { true }
|
||
|
||
it_behaves_like 'does not redirect nor flash'
|
||
end
|
||
|
||
context 'when an invite save the draft for a dossier where they where invited' do
|
||
before { create(:invite, dossier: asked_dossier, user: user) }
|
||
let(:submit) { false }
|
||
|
||
it_behaves_like 'does not redirect nor flash'
|
||
end
|
||
|
||
context 'when an invite submit a dossier where they where invited' do
|
||
before { create(:invite, dossier: asked_dossier, user: user) }
|
||
let(:submit) { true }
|
||
|
||
it_behaves_like 'redirects and flashes'
|
||
end
|
||
end
|
||
|
||
describe 'attestation' do
|
||
before { sign_in(user) }
|
||
|
||
context 'when a dossier has an attestation' do
|
||
let(:dossier) { create(:dossier, :accepte, attestation: create(:attestation, :with_pdf), user: user) }
|
||
|
||
it 'redirects to attestation pdf' do
|
||
get :attestation, params: { id: dossier.id }
|
||
expect(response.location).to match '/rails/active_storage/disk/'
|
||
end
|
||
end
|
||
end
|
||
|
||
describe 'update_identite' do
|
||
let(:procedure) { create(:procedure, :for_individual) }
|
||
let(:dossier) { create(:dossier, user: user, procedure: procedure) }
|
||
|
||
subject { post :update_identite, params: { id: dossier.id, individual: individual_params } }
|
||
|
||
before do
|
||
sign_in(user)
|
||
subject
|
||
end
|
||
|
||
context 'with correct individual and dossier params' do
|
||
let(:individual_params) { { gender: 'M', nom: 'Mouse', prenom: 'Mickey' } }
|
||
|
||
it do
|
||
expect(response).to redirect_to(brouillon_dossier_path(dossier))
|
||
end
|
||
end
|
||
|
||
context 'when the identite cannot be updated by the user' do
|
||
let(:dossier) { create(:dossier, :with_individual, :en_instruction, user: user, procedure: procedure) }
|
||
let(:individual_params) { { gender: 'M', nom: 'Mouse', prenom: 'Mickey' } }
|
||
|
||
it 'redirects to the dossiers list' do
|
||
expect(response).to redirect_to(dossiers_path)
|
||
expect(flash.alert).to eq('Votre dossier ne peut plus être modifié')
|
||
end
|
||
end
|
||
|
||
context 'with incorrect individual and dossier params' do
|
||
let(:individual_params) { { gender: '', nom: '', prenom: '' } }
|
||
|
||
it do
|
||
expect(response).not_to have_http_status(:redirect)
|
||
expect(flash[:alert]).to include("Civilité doit être rempli", "Nom doit être rempli", "Prénom doit être rempli")
|
||
end
|
||
end
|
||
end
|
||
|
||
describe '#siret' do
|
||
before { sign_in(user) }
|
||
let!(:dossier) { create(:dossier, user: user) }
|
||
|
||
subject { get :siret, params: { id: dossier.id } }
|
||
|
||
it { is_expected.to render_template(:siret) }
|
||
end
|
||
|
||
describe '#update_siret' do
|
||
let(:dossier) { create(:dossier, user: user) }
|
||
let(:siret) { params_siret.delete(' ') }
|
||
let(:siren) { siret[0..8] }
|
||
|
||
let(:api_etablissement_status) { 200 }
|
||
let(:api_etablissement_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') }
|
||
|
||
let(:api_entreprise_status) { 200 }
|
||
let(:api_entreprise_body) { File.read('spec/fixtures/files/api_entreprise/entreprises.json') }
|
||
|
||
let(:api_entreprise_effectifs_mensuels_status) { 200 }
|
||
let(:api_entreprise_effectifs_mensuels_body) { File.read('spec/fixtures/files/api_entreprise/effectifs.json') }
|
||
let(:annee) { "2020" }
|
||
let(:mois) { "02" }
|
||
|
||
let(:api_entreprise_effectifs_annuels_status) { 200 }
|
||
let(:api_entreprise_effectifs_annuels_body) { File.read('spec/fixtures/files/api_entreprise/effectifs_annuels.json') }
|
||
|
||
let(:api_exercices_status) { 200 }
|
||
let(:api_exercices_body) { File.read('spec/fixtures/files/api_entreprise/exercices.json') }
|
||
|
||
let(:api_association_status) { 200 }
|
||
let(:api_association_body) { File.read('spec/fixtures/files/api_entreprise/associations.json') }
|
||
|
||
def stub_api_entreprise_requests
|
||
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
|
||
.to_return(status: api_etablissement_status, body: api_etablissement_body)
|
||
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
|
||
.to_return(status: api_entreprise_status, body: api_entreprise_body)
|
||
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/#{siret}?.*token=/)
|
||
.to_return(status: api_exercices_status, body: api_exercices_body)
|
||
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/associations\/#{siret}?.*token=/)
|
||
.to_return(status: api_association_status, body: api_association_body)
|
||
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/effectifs_mensuels_acoss_covid\/#{annee}\/#{mois}\/entreprise\/#{siren}?.*token=/)
|
||
.to_return(body: api_entreprise_effectifs_mensuels_body, status: api_entreprise_effectifs_mensuels_status)
|
||
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/effectifs_annuels_acoss_covid\/#{siren}?.*token=/)
|
||
.to_return(body: api_entreprise_effectifs_annuels_body, status: api_entreprise_effectifs_annuels_status)
|
||
end
|
||
|
||
before do
|
||
sign_in(user)
|
||
stub_api_entreprise_requests
|
||
end
|
||
before { Timecop.freeze(Time.zone.local(2020, 3, 14)) }
|
||
after { Timecop.return }
|
||
|
||
subject! { post :update_siret, params: { id: dossier.id, user: { siret: params_siret } } }
|
||
|
||
shared_examples 'SIRET informations are successfully saved' do
|
||
it do
|
||
dossier.reload
|
||
user.reload
|
||
|
||
expect(dossier.etablissement).to be_present
|
||
expect(dossier.autorisation_donnees).to be(true)
|
||
expect(user.siret).to eq(siret)
|
||
|
||
expect(response).to redirect_to(etablissement_dossier_path)
|
||
end
|
||
end
|
||
|
||
shared_examples 'the request fails with an error' do |error|
|
||
it 'doesn’t save an etablissement' do
|
||
expect(dossier.reload.etablissement).to be_nil
|
||
end
|
||
|
||
it 'displays the SIRET that was sent by the user in the form' do
|
||
expect(controller.current_user.siret).to eq(siret)
|
||
end
|
||
|
||
it 'renders an error' do
|
||
expect(flash.alert).to eq(error)
|
||
expect(response).to render_template(:siret)
|
||
end
|
||
end
|
||
|
||
context 'with an invalid SIRET' do
|
||
let(:params_siret) { '000 000' }
|
||
|
||
it_behaves_like 'the request fails with an error', ['Siret Le numéro SIRET doit comporter 14 chiffres']
|
||
end
|
||
|
||
context 'with a valid SIRET' do
|
||
let(:params_siret) { '418 166 096 00051' }
|
||
context 'When API-Entreprise is down' do
|
||
let(:api_etablissement_status) { 502 }
|
||
let(:api_body_status) { File.read('spec/fixtures/files/api_entreprise/exercices_unavailable.json') }
|
||
|
||
it_behaves_like 'the request fails with an error', I18n.t('errors.messages.siret_network_error')
|
||
end
|
||
|
||
context 'when API-Entreprise doesn’t know this SIRET' do
|
||
let(:api_etablissement_status) { 404 }
|
||
let(:api_body_status) { '' }
|
||
|
||
it_behaves_like 'the request fails with an error', I18n.t('errors.messages.siret_unknown')
|
||
end
|
||
|
||
context 'when the API returns no Entreprise' do
|
||
let(:api_entreprise_status) { 404 }
|
||
let(:api_entreprise_body) { '' }
|
||
|
||
it_behaves_like 'the request fails with an error', I18n.t('errors.messages.siret_unknown')
|
||
end
|
||
|
||
context 'when the API returns no Exercices' do
|
||
let(:api_exercices_status) { 404 }
|
||
let(:api_exercices_body) { '' }
|
||
|
||
it_behaves_like 'SIRET informations are successfully saved'
|
||
|
||
it 'doesn’t save the etablissement exercices' do
|
||
expect(dossier.reload.etablissement.exercices).to be_empty
|
||
end
|
||
end
|
||
|
||
context 'when the RNA doesn’t have informations on the SIRET' do
|
||
let(:api_association_status) { 404 }
|
||
let(:api_association_body) { '' }
|
||
|
||
it_behaves_like 'SIRET informations are successfully saved'
|
||
|
||
it 'doesn’t save the RNA informations' do
|
||
expect(dossier.reload.etablissement.association?).to be(false)
|
||
end
|
||
end
|
||
|
||
context 'when all API informations available' do
|
||
it_behaves_like 'SIRET informations are successfully saved'
|
||
|
||
it 'saves the associated informations on the etablissement' do
|
||
dossier.reload
|
||
expect(dossier.etablissement.entreprise).to be_present
|
||
expect(dossier.etablissement.exercices).to be_present
|
||
expect(dossier.etablissement.association?).to be(true)
|
||
expect(dossier.etablissement.entreprise_effectif_mensuel).to be_present
|
||
expect(dossier.etablissement.entreprise_effectif_annuel).to be_present
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
describe '#etablissement' do
|
||
let(:dossier) { create(:dossier, :with_entreprise, user: user) }
|
||
|
||
before { sign_in(user) }
|
||
|
||
subject { get :etablissement, params: { id: dossier.id } }
|
||
|
||
it { is_expected.to render_template(:etablissement) }
|
||
|
||
context 'when the dossier has no etablissement yet' do
|
||
let(:dossier) { create(:dossier, user: user) }
|
||
it { is_expected.to redirect_to siret_dossier_path(dossier) }
|
||
end
|
||
end
|
||
|
||
describe '#brouillon' do
|
||
before { sign_in(user) }
|
||
let!(:dossier) { create(:dossier, user: user, autorisation_donnees: true) }
|
||
|
||
subject { get :brouillon, params: { id: dossier.id } }
|
||
|
||
context 'when autorisation_donnees is checked' do
|
||
it { is_expected.to render_template(:brouillon) }
|
||
end
|
||
|
||
context 'when autorisation_donnees is not checked' do
|
||
before { dossier.update_columns(autorisation_donnees: false) }
|
||
|
||
context 'when the dossier is for personne morale' do
|
||
it { is_expected.to redirect_to(siret_dossier_path(dossier)) }
|
||
end
|
||
|
||
context 'when the dossier is for an personne physique' do
|
||
before { dossier.procedure.update(for_individual: true) }
|
||
|
||
it { is_expected.to redirect_to(identite_dossier_path(dossier)) }
|
||
end
|
||
end
|
||
end
|
||
|
||
describe '#edit' do
|
||
before { sign_in(user) }
|
||
let!(:dossier) { create(:dossier, user: user) }
|
||
|
||
it 'returns the edit page' do
|
||
get :brouillon, params: { id: dossier.id }
|
||
expect(response).to have_http_status(:success)
|
||
end
|
||
end
|
||
|
||
describe '#update_brouillon' do
|
||
before { sign_in(user) }
|
||
|
||
let!(:dossier) { create(:dossier, user: user) }
|
||
let(:first_champ) { dossier.champs.first }
|
||
let(:value) { 'beautiful value' }
|
||
let(:now) { Time.zone.parse('01/01/2100') }
|
||
let(:submit_payload) do
|
||
{
|
||
id: dossier.id,
|
||
dossier: {
|
||
champs_attributes: {
|
||
id: first_champ.id,
|
||
value: value
|
||
}
|
||
}
|
||
}
|
||
end
|
||
let(:payload) { submit_payload.merge(submit_draft: true) }
|
||
|
||
subject do
|
||
Timecop.freeze(now) do
|
||
patch :update_brouillon, params: payload
|
||
end
|
||
end
|
||
|
||
context 'when the dossier cannot be updated by the user' do
|
||
let!(:dossier) { create(:dossier, :en_instruction, user: user) }
|
||
|
||
it 'redirects to the dossiers list' do
|
||
subject
|
||
|
||
expect(response).to redirect_to(dossiers_path)
|
||
expect(flash.alert).to eq('Votre dossier ne peut plus être modifié')
|
||
end
|
||
end
|
||
|
||
context 'when dossier can be updated by the owner' do
|
||
it 'updates the champs' do
|
||
subject
|
||
|
||
expect(response).to redirect_to(merci_dossier_path(dossier))
|
||
expect(first_champ.reload.value).to eq('beautiful value')
|
||
expect(dossier.reload.updated_at.year).to eq(2100)
|
||
expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_construction))
|
||
end
|
||
|
||
context 'with instructeurs ok to be notified instantly' do
|
||
let!(:instructeur_with_instant_email_dossier) { create(:instructeur) }
|
||
let!(:instructeur_without_instant_email_dossier) { create(:instructeur) }
|
||
|
||
before do
|
||
allow(DossierMailer).to receive(:notify_new_dossier_depose_to_instructeur).and_return(double(deliver_later: nil))
|
||
create(:assign_to, instructeur: instructeur_with_instant_email_dossier, procedure: dossier.procedure, instant_email_dossier_notifications_enabled: true, groupe_instructeur: dossier.procedure.defaut_groupe_instructeur)
|
||
create(:assign_to, instructeur: instructeur_without_instant_email_dossier, procedure: dossier.procedure, instant_email_dossier_notifications_enabled: false, groupe_instructeur: dossier.procedure.defaut_groupe_instructeur)
|
||
end
|
||
|
||
it "sends notification mail to instructeurs" do
|
||
subject
|
||
|
||
expect(DossierMailer).to have_received(:notify_new_dossier_depose_to_instructeur).once.with(dossier, instructeur_with_instant_email_dossier.email)
|
||
expect(DossierMailer).not_to have_received(:notify_new_dossier_depose_to_instructeur).with(dossier, instructeur_without_instant_email_dossier.email)
|
||
end
|
||
end
|
||
|
||
context 'with procedure routee' do
|
||
let(:procedure) { create(:procedure, :routee, :with_type_de_champ) }
|
||
let(:dossier_group) { create(:groupe_instructeur, procedure: procedure) }
|
||
let(:another_group) { create(:groupe_instructeur, procedure: procedure) }
|
||
let(:instructeur_of_dossier) { create(:instructeur) }
|
||
let(:instructeur_in_another_group) { create(:instructeur) }
|
||
let!(:dossier) { create(:dossier, groupe_instructeur: dossier_group, user: user) }
|
||
|
||
before do
|
||
allow(DossierMailer).to receive(:notify_new_dossier_depose_to_instructeur).and_return(double(deliver_later: nil))
|
||
create(:assign_to, instructeur: instructeur_of_dossier, procedure: dossier.procedure, instant_email_dossier_notifications_enabled: true, groupe_instructeur: dossier_group)
|
||
create(:assign_to, instructeur: instructeur_in_another_group, procedure: dossier.procedure, instant_email_dossier_notifications_enabled: true, groupe_instructeur: another_group)
|
||
end
|
||
|
||
it "sends notification mail to instructeurs in the correct group instructeur" do
|
||
subject
|
||
|
||
expect(DossierMailer).to have_received(:notify_new_dossier_depose_to_instructeur).once.with(dossier, instructeur_of_dossier.email)
|
||
expect(DossierMailer).not_to have_received(:notify_new_dossier_depose_to_instructeur).with(dossier, instructeur_in_another_group.email)
|
||
end
|
||
end
|
||
|
||
context "on an closed procedure" do
|
||
before { dossier.procedure.close! }
|
||
|
||
it "it does not change state" do
|
||
subject
|
||
|
||
expect(response).not_to redirect_to(merci_dossier_path(dossier))
|
||
expect(dossier.reload.state).to eq(Dossier.states.fetch(:brouillon))
|
||
end
|
||
end
|
||
end
|
||
|
||
it 'sends an email only on the first #update_brouillon' do
|
||
delivery = double
|
||
expect(delivery).to receive(:deliver_later).with(no_args)
|
||
|
||
expect(NotificationMailer).to receive(:send_initiated_notification)
|
||
.and_return(delivery)
|
||
|
||
subject
|
||
|
||
expect(NotificationMailer).not_to receive(:send_initiated_notification)
|
||
|
||
subject
|
||
end
|
||
|
||
context 'when the update fails' do
|
||
before do
|
||
expect_any_instance_of(Dossier).to receive(:save).and_return(false)
|
||
expect_any_instance_of(Dossier).to receive(:errors)
|
||
.and_return(double(full_messages: ['nop']))
|
||
|
||
subject
|
||
end
|
||
|
||
it { expect(response).to render_template(:brouillon) }
|
||
it { expect(flash.alert).to eq(['nop']) }
|
||
|
||
it 'does not send an email' do
|
||
expect(NotificationMailer).not_to receive(:send_initiated_notification)
|
||
|
||
subject
|
||
end
|
||
end
|
||
|
||
context 'when a mandatory champ is missing' do
|
||
let(:value) { nil }
|
||
|
||
before do
|
||
first_champ.type_de_champ.update(mandatory: true, libelle: 'l')
|
||
subject
|
||
end
|
||
|
||
it { expect(response).to render_template(:brouillon) }
|
||
it { expect(flash.alert).to eq(['Le champ l doit être rempli.']) }
|
||
|
||
context 'and the user saves a draft' do
|
||
let(:payload) { submit_payload.except(:submit_draft) }
|
||
|
||
it { expect(response).to render_template(:brouillon) }
|
||
it { expect(flash.notice).to eq('Votre brouillon a bien été sauvegardé.') }
|
||
it { expect(dossier.reload.state).to eq(Dossier.states.fetch(:brouillon)) }
|
||
|
||
context 'and the dossier is in construction' do
|
||
let!(:dossier) { create(:dossier, :en_construction, user: user) }
|
||
|
||
it { expect(response).to render_template(:brouillon) }
|
||
it { expect(flash.alert).to eq(['Le champ l doit être rempli.']) }
|
||
end
|
||
end
|
||
end
|
||
|
||
context 'when dossier has no champ' do
|
||
let(:submit_payload) { { id: dossier.id } }
|
||
|
||
it 'does not raise any errors' do
|
||
subject
|
||
|
||
expect(response).to redirect_to(merci_dossier_path(dossier))
|
||
end
|
||
end
|
||
|
||
context 'when the user has an invitation but is not the owner' do
|
||
let(:dossier) { create(:dossier) }
|
||
let!(:invite) { create(:invite, dossier: dossier, user: user) }
|
||
|
||
context 'and the invite saves a draft' do
|
||
let(:payload) { submit_payload.except(:submit_draft) }
|
||
|
||
before do
|
||
first_champ.type_de_champ.update(mandatory: true, libelle: 'l')
|
||
subject
|
||
end
|
||
|
||
it { expect(response).to render_template(:brouillon) }
|
||
it { expect(flash.notice).to eq('Votre brouillon a bien été sauvegardé.') }
|
||
it { expect(dossier.reload.state).to eq(Dossier.states.fetch(:brouillon)) }
|
||
end
|
||
|
||
context 'and the invite tries to submit the dossier' do
|
||
before { subject }
|
||
|
||
it { expect(response).to redirect_to(root_path) }
|
||
it { expect(flash.alert).to eq("Vous n'avez pas accès à ce dossier") }
|
||
end
|
||
end
|
||
end
|
||
|
||
describe '#update' do
|
||
before { sign_in(user) }
|
||
|
||
let(:procedure) { create(:procedure, :published, :with_type_de_champ, :with_piece_justificative) }
|
||
let!(:dossier) { create(:dossier, :en_construction, user: user, procedure: procedure) }
|
||
let(:first_champ) { dossier.champs.first }
|
||
let(:piece_justificative_champ) { dossier.champs.last }
|
||
let(:value) { 'beautiful value' }
|
||
let(:file) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') }
|
||
let(:now) { Time.zone.parse('01/01/2100') }
|
||
|
||
let(:submit_payload) do
|
||
{
|
||
id: dossier.id,
|
||
dossier: {
|
||
champs_attributes: {
|
||
id: first_champ.id,
|
||
value: value
|
||
}
|
||
}
|
||
}
|
||
end
|
||
let(:payload) { submit_payload }
|
||
|
||
subject do
|
||
Timecop.freeze(now) do
|
||
patch :update, params: payload
|
||
end
|
||
end
|
||
|
||
context 'when the dossier cannot be updated by the user' do
|
||
let!(:dossier) { create(:dossier, :en_instruction, user: user) }
|
||
|
||
it 'redirects to the dossiers list' do
|
||
subject
|
||
|
||
expect(response).to redirect_to(dossiers_path)
|
||
expect(flash.alert).to eq('Votre dossier ne peut plus être modifié')
|
||
end
|
||
end
|
||
|
||
context 'when dossier can be updated by the owner' do
|
||
it 'updates the champs' do
|
||
subject
|
||
|
||
expect(response).to redirect_to(demande_dossier_path(dossier))
|
||
expect(first_champ.reload.value).to eq('beautiful value')
|
||
expect(dossier.reload.updated_at.year).to eq(2100)
|
||
expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_construction))
|
||
end
|
||
|
||
context 'when only files champs are modified' do
|
||
let(:submit_payload) do
|
||
{
|
||
id: dossier.id,
|
||
dossier: {
|
||
champs_attributes: {
|
||
id: piece_justificative_champ.id,
|
||
piece_justificative_file: file
|
||
}
|
||
}
|
||
}
|
||
end
|
||
|
||
it 'updates the dossier modification date' do
|
||
subject
|
||
expect(dossier.reload.updated_at.year).to eq(2100)
|
||
end
|
||
end
|
||
end
|
||
|
||
context 'when the update fails' do
|
||
before do
|
||
expect_any_instance_of(Dossier).to receive(:save).and_return(false)
|
||
expect_any_instance_of(Dossier).to receive(:errors)
|
||
.and_return(double(full_messages: ['nop']))
|
||
|
||
subject
|
||
end
|
||
|
||
it { expect(response).to render_template(:modifier) }
|
||
it { expect(flash.alert).to eq(['nop']) }
|
||
|
||
it 'does not send an email' do
|
||
expect(NotificationMailer).not_to receive(:send_initiated_notification)
|
||
|
||
subject
|
||
end
|
||
end
|
||
|
||
context 'when a mandatory champ is missing' do
|
||
let(:value) { nil }
|
||
|
||
before do
|
||
first_champ.type_de_champ.update(mandatory: true, libelle: 'l')
|
||
subject
|
||
end
|
||
|
||
it { expect(response).to render_template(:modifier) }
|
||
it { expect(flash.alert).to eq(['Le champ l doit être rempli.']) }
|
||
end
|
||
|
||
context 'when dossier has no champ' do
|
||
let(:submit_payload) { { id: dossier.id } }
|
||
|
||
it 'does not raise any errors' do
|
||
subject
|
||
|
||
expect(response).to redirect_to(demande_dossier_path(dossier))
|
||
end
|
||
end
|
||
|
||
context 'when the user has an invitation but is not the owner' do
|
||
let(:dossier) { create(:dossier) }
|
||
let!(:invite) { create(:invite, dossier: dossier, user: user) }
|
||
|
||
before do
|
||
dossier.en_construction!
|
||
subject
|
||
end
|
||
|
||
it { expect(first_champ.reload.value).to eq('beautiful value') }
|
||
it { expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_construction)) }
|
||
it { expect(response).to redirect_to(demande_dossier_path(dossier)) }
|
||
end
|
||
end
|
||
|
||
describe '#index' do
|
||
before { sign_in(user) }
|
||
|
||
context 'when the user does not have any dossiers' do
|
||
before { get(:index) }
|
||
|
||
it { expect(assigns(:current_tab)).to eq('mes-dossiers') }
|
||
end
|
||
|
||
context 'when the user only have its own dossiers' do
|
||
let!(:own_dossier) { create(:dossier, user: user) }
|
||
|
||
before { get(:index) }
|
||
|
||
it { expect(assigns(:current_tab)).to eq('mes-dossiers') }
|
||
it { expect(assigns(:dossiers)).to match([own_dossier]) }
|
||
end
|
||
|
||
context 'when the user only have some dossiers invites' do
|
||
let!(:invite) { create(:invite, dossier: create(:dossier), user: user) }
|
||
|
||
before { get(:index) }
|
||
|
||
it { expect(assigns(:current_tab)).to eq('dossiers-invites') }
|
||
it { expect(assigns(:dossiers)).to match([invite.dossier]) }
|
||
end
|
||
|
||
context 'when the user has both' do
|
||
let!(:own_dossier) { create(:dossier, user: user) }
|
||
let!(:invite) { create(:invite, dossier: create(:dossier), user: user) }
|
||
|
||
context 'and there is no current_tab param' do
|
||
before { get(:index) }
|
||
|
||
it { expect(assigns(:current_tab)).to eq('mes-dossiers') }
|
||
end
|
||
|
||
context 'and there is "dossiers-invites" param' do
|
||
before { get(:index, params: { current_tab: 'dossiers-invites' }) }
|
||
|
||
it { expect(assigns(:current_tab)).to eq('dossiers-invites') }
|
||
end
|
||
|
||
context 'and there is "mes-dossiers" param' do
|
||
before { get(:index, params: { current_tab: 'mes-dossiers' }) }
|
||
|
||
it { expect(assigns(:current_tab)).to eq('mes-dossiers') }
|
||
end
|
||
end
|
||
|
||
describe 'sort order' do
|
||
before do
|
||
Timecop.freeze(4.days.ago) { create(:dossier, user: user) }
|
||
Timecop.freeze(2.days.ago) { create(:dossier, user: user) }
|
||
Timecop.freeze(4.days.ago) { create(:invite, dossier: create(:dossier), user: user) }
|
||
Timecop.freeze(2.days.ago) { create(:invite, dossier: create(:dossier), user: user) }
|
||
get(:index)
|
||
end
|
||
|
||
it 'displays the most recently updated dossiers first' do
|
||
expect(assigns(:user_dossiers).first.updated_at.to_date).to eq(2.days.ago.to_date)
|
||
expect(assigns(:user_dossiers).second.updated_at.to_date).to eq(4.days.ago.to_date)
|
||
expect(assigns(:dossiers_invites).first.updated_at.to_date).to eq(2.days.ago.to_date)
|
||
expect(assigns(:dossiers_invites).second.updated_at.to_date).to eq(4.days.ago.to_date)
|
||
end
|
||
end
|
||
end
|
||
|
||
describe '#show' do
|
||
before do
|
||
sign_in(user)
|
||
end
|
||
|
||
context 'with default output' do
|
||
subject! { get(:show, params: { id: dossier.id }) }
|
||
|
||
context 'when the dossier is a brouillon' do
|
||
let(:dossier) { create(:dossier, user: user) }
|
||
it { is_expected.to redirect_to(brouillon_dossier_path(dossier)) }
|
||
end
|
||
|
||
context 'when the dossier has been submitted' do
|
||
let(:dossier) { create(:dossier, :en_construction, user: user) }
|
||
it { expect(assigns(:dossier)).to eq(dossier) }
|
||
it { is_expected.to render_template(:show) }
|
||
end
|
||
end
|
||
|
||
context "with PDF output" do
|
||
let(:procedure) { create(:procedure) }
|
||
let(:dossier) {
|
||
create(:dossier,
|
||
:accepte,
|
||
:with_all_champs,
|
||
:with_motivation,
|
||
:with_commentaires,
|
||
procedure: procedure,
|
||
user: user)
|
||
}
|
||
subject! { get(:show, params: { id: dossier.id, format: :pdf }) }
|
||
|
||
context 'when the dossier is a brouillon' do
|
||
let(:dossier) { create(:dossier, user: user) }
|
||
it { is_expected.to redirect_to(brouillon_dossier_path(dossier)) }
|
||
end
|
||
|
||
context 'when the dossier has been submitted' do
|
||
it { expect(assigns(:include_infos_administration)).to eq(false) }
|
||
it { expect(response).to render_template 'dossiers/show' }
|
||
end
|
||
end
|
||
end
|
||
|
||
describe '#formulaire' do
|
||
let(:dossier) { create(:dossier, :en_construction, user: user) }
|
||
|
||
before do
|
||
sign_in(user)
|
||
end
|
||
|
||
subject! { get(:demande, params: { id: dossier.id }) }
|
||
|
||
it { expect(assigns(:dossier)).to eq(dossier) }
|
||
it { is_expected.to render_template(:demande) }
|
||
end
|
||
|
||
describe "#create_commentaire" do
|
||
let(:instructeur_with_instant_message) { create(:instructeur) }
|
||
let(:instructeur_without_instant_message) { create(:instructeur) }
|
||
let(:procedure) { create(:procedure, :published) }
|
||
let(:dossier) { create(:dossier, :en_construction, procedure: procedure, user: user) }
|
||
let(:saved_commentaire) { dossier.commentaires.first }
|
||
let(:body) { "avant\napres" }
|
||
let(:file) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') }
|
||
let(:scan_result) { true }
|
||
|
||
subject {
|
||
post :create_commentaire, params: {
|
||
id: dossier.id,
|
||
commentaire: {
|
||
body: body,
|
||
piece_jointe: file
|
||
}
|
||
}
|
||
}
|
||
|
||
before do
|
||
sign_in(user)
|
||
allow(ClamavService).to receive(:safe_file?).and_return(scan_result)
|
||
allow(DossierMailer).to receive(:notify_new_commentaire_to_instructeur).and_return(double(deliver_later: nil))
|
||
instructeur_with_instant_message.follow(dossier)
|
||
instructeur_without_instant_message.follow(dossier)
|
||
create(:assign_to, instructeur: instructeur_with_instant_message, procedure: procedure, instant_email_message_notifications_enabled: true, groupe_instructeur: procedure.defaut_groupe_instructeur)
|
||
create(:assign_to, instructeur: instructeur_without_instant_message, procedure: procedure, instant_email_message_notifications_enabled: false, groupe_instructeur: procedure.defaut_groupe_instructeur)
|
||
end
|
||
|
||
it "creates a commentaire" do
|
||
expect { subject }.to change(Commentaire, :count).by(1)
|
||
|
||
expect(response).to redirect_to(messagerie_dossier_path(dossier))
|
||
expect(DossierMailer).to have_received(:notify_new_commentaire_to_instructeur).with(dossier, instructeur_with_instant_message.email)
|
||
expect(DossierMailer).not_to have_received(:notify_new_commentaire_to_instructeur).with(dossier, instructeur_without_instant_message.email)
|
||
expect(flash.notice).to be_present
|
||
end
|
||
end
|
||
|
||
describe '#ask_deletion' do
|
||
before { sign_in(user) }
|
||
|
||
subject { post :ask_deletion, params: { id: dossier.id } }
|
||
|
||
shared_examples_for "the dossier can not be deleted" do
|
||
it "doesn’t notify the deletion" do
|
||
expect(DossierMailer).not_to receive(:notify_deletion_to_administration)
|
||
expect(DossierMailer).not_to receive(:notify_deletion_to_user)
|
||
subject
|
||
end
|
||
|
||
it "doesn’t delete the dossier" do
|
||
subject
|
||
expect(Dossier.find_by(id: dossier.id)).not_to eq(nil)
|
||
expect(dossier.procedure.deleted_dossiers.count).to eq(0)
|
||
end
|
||
end
|
||
|
||
context 'when dossier is owned by signed in user' do
|
||
let(:dossier) { create(:dossier, :en_construction, user: user, autorisation_donnees: true) }
|
||
|
||
it "notifies the user and the admin of the deletion" do
|
||
expect(DossierMailer).to receive(:notify_deletion_to_administration).with(kind_of(DeletedDossier), dossier.procedure.administrateurs.first.email).and_return(double(deliver_later: nil))
|
||
expect(DossierMailer).to receive(:notify_deletion_to_user).with(kind_of(DeletedDossier), dossier.user.email).and_return(double(deliver_later: nil))
|
||
subject
|
||
end
|
||
|
||
it "deletes the dossier" do
|
||
procedure = dossier.procedure
|
||
dossier_id = dossier.id
|
||
subject
|
||
expect(Dossier.find_by(id: dossier_id)).to eq(nil)
|
||
expect(procedure.deleted_dossiers.count).to eq(1)
|
||
expect(procedure.deleted_dossiers.first.dossier_id).to eq(dossier_id)
|
||
end
|
||
|
||
it { is_expected.to redirect_to(dossiers_path) }
|
||
|
||
context "and the instruction has started" do
|
||
let(:dossier) { create(:dossier, :en_instruction, user: user, autorisation_donnees: true) }
|
||
|
||
it_behaves_like "the dossier can not be deleted"
|
||
it { is_expected.to redirect_to(dossier_path(dossier)) }
|
||
end
|
||
end
|
||
|
||
context 'when dossier is not owned by signed in user' do
|
||
let(:user2) { create(:user) }
|
||
let(:dossier) { create(:dossier, user: user2, autorisation_donnees: true) }
|
||
|
||
it_behaves_like "the dossier can not be deleted"
|
||
it { is_expected.to redirect_to(root_path) }
|
||
end
|
||
end
|
||
|
||
describe '#new' do
|
||
let(:procedure) { create(:procedure, :published) }
|
||
let(:procedure_id) { procedure.id }
|
||
|
||
subject { get :new, params: { procedure_id: procedure_id } }
|
||
|
||
it 'clears the stored procedure context' do
|
||
subject
|
||
expect(controller.stored_location_for(:user)).to be nil
|
||
end
|
||
|
||
context 'when params procedure_id is present' do
|
||
context 'when procedure_id is valid' do
|
||
context 'when user is logged in' do
|
||
before do
|
||
sign_in user
|
||
end
|
||
|
||
it { is_expected.to have_http_status(302) }
|
||
it { expect { subject }.to change(Dossier, :count).by 1 }
|
||
context 'when procedure is for entreprise' do
|
||
it { is_expected.to redirect_to siret_dossier_path(id: Dossier.last) }
|
||
end
|
||
|
||
context 'when procedure is for particulier' do
|
||
let(:procedure) { create(:procedure, :published, :for_individual) }
|
||
it { is_expected.to redirect_to identite_dossier_path(id: Dossier.last) }
|
||
end
|
||
|
||
context 'when procedure is closed' do
|
||
let(:procedure) { create(:procedure, :closed) }
|
||
|
||
it { is_expected.to redirect_to dossiers_path }
|
||
end
|
||
end
|
||
context 'when user is not logged' do
|
||
it { is_expected.to have_http_status(302) }
|
||
it { is_expected.to redirect_to new_user_session_path }
|
||
end
|
||
end
|
||
|
||
context 'when procedure_id is not valid' do
|
||
let(:procedure_id) { 0 }
|
||
|
||
before do
|
||
sign_in user
|
||
end
|
||
|
||
it { is_expected.to redirect_to dossiers_path }
|
||
end
|
||
|
||
context 'when procedure is not published' do
|
||
let(:procedure) { create(:procedure) }
|
||
|
||
before do
|
||
sign_in user
|
||
end
|
||
|
||
it { is_expected.to redirect_to dossiers_path }
|
||
|
||
context 'and brouillon param is passed' do
|
||
subject { get :new, params: { procedure_id: procedure_id, brouillon: true } }
|
||
|
||
it { is_expected.to have_http_status(302) }
|
||
it { is_expected.to redirect_to siret_dossier_path(id: Dossier.last) }
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
describe "#dossier_for_help" do
|
||
before do
|
||
sign_in(user)
|
||
controller.params[:dossier_id] = dossier_id.to_s
|
||
end
|
||
|
||
subject { controller.dossier_for_help }
|
||
|
||
context 'when the id matches an existing dossier' do
|
||
let(:dossier) { create(:dossier) }
|
||
let(:dossier_id) { dossier.id }
|
||
|
||
it { is_expected.to eq dossier }
|
||
end
|
||
|
||
context 'when the id doesn’t match an existing dossier' do
|
||
let(:dossier_id) { 9999999 }
|
||
it { is_expected.to be nil }
|
||
end
|
||
|
||
context 'when the id is empty' do
|
||
let(:dossier_id) { nil }
|
||
it { is_expected.to be_falsy }
|
||
end
|
||
end
|
||
end
|