Merge pull request #9873 from demarches-simplifiees/files_recovery
ETQ usager, agent de la fonction publique territoriale, je peux récupérer les dossiers d'un collègue absent
This commit is contained in:
commit
ca413a1035
28 changed files with 1406 additions and 12 deletions
|
@ -40,10 +40,10 @@
|
|||
- elsif @state == 'choix'
|
||||
= form_for :choice,
|
||||
method: :patch,
|
||||
data: { controller: 'radio-enabled-submit' },
|
||||
data: { controller: 'enable-submit-if-checked' },
|
||||
url: wizard_admin_procedure_groupe_instructeurs_path(@procedure) do |f|
|
||||
|
||||
%div{ data: { 'action': "click->radio-enabled-submit#click" } }
|
||||
%div{ data: { 'action': "click->enable-submit-if-checked#click" } }
|
||||
= render Dsfr::RadioButtonListComponent.new(form: f,
|
||||
target: :state,
|
||||
buttons: [ { label: 'À partir d’un champ', value: 'routage_simple', hint: 'crée les groupes en fonction d’un champ du formulaire' } ,
|
||||
|
@ -54,4 +54,4 @@
|
|||
%li
|
||||
= link_to 'Retour', options_admin_procedure_groupe_instructeurs_path(@procedure), class: 'fr-btn fr-btn--secondary'
|
||||
%li
|
||||
%button.fr-btn{ disabled: true, data: { 'radio-enabled-submit-target': 'submit' } } Continuer
|
||||
%button.fr-btn{ disabled: true, data: { 'enable-submit-if-checked-target': 'submit' } } Continuer
|
||||
|
|
|
@ -35,6 +35,9 @@ class AgentConnect::AgentController < ApplicationController
|
|||
instructeur.update(agent_connect_id: user_info['sub'])
|
||||
end
|
||||
|
||||
aci = AgentConnectInformation.find_or_initialize_by(instructeur:)
|
||||
aci.update(user_info.slice('given_name', 'usual_name', 'email', 'sub', 'siret', 'organizational_unit', 'belonging_population', 'phone'))
|
||||
|
||||
sign_in(:user, instructeur.user)
|
||||
|
||||
redirect_to instructeur_procedures_path
|
||||
|
|
83
app/controllers/recoveries_controller.rb
Normal file
83
app/controllers/recoveries_controller.rb
Normal file
|
@ -0,0 +1,83 @@
|
|||
class RecoveriesController < ApplicationController
|
||||
before_action :ensure_agent_connect_is_used, except: [:nature, :post_nature, :support]
|
||||
before_action :ensure_collectivite_territoriale, except: [:nature, :post_nature, :support]
|
||||
|
||||
def nature
|
||||
end
|
||||
|
||||
def post_nature
|
||||
if nature_params == 'collectivite'
|
||||
redirect_to identification_recovery_path
|
||||
else
|
||||
redirect_to support_recovery_path(error: :other_nature)
|
||||
end
|
||||
end
|
||||
|
||||
def identification
|
||||
@structure_name = structure_name
|
||||
end
|
||||
|
||||
def post_identification
|
||||
# cipher previous_user email
|
||||
# to avoid leaks in the url
|
||||
ciphered_email = cipher(previous_email)
|
||||
|
||||
redirect_to selection_recovery_path(ciphered_email:)
|
||||
end
|
||||
|
||||
def selection
|
||||
@previous_email = uncipher(params[:ciphered_email])
|
||||
|
||||
previous_user = User.find_by(email: @previous_email)
|
||||
|
||||
@recoverables = RecoveryService
|
||||
.recoverable_procedures(previous_user:, siret:)
|
||||
|
||||
redirect_to support_recovery_path(error: :no_dossier) if @recoverables.empty?
|
||||
end
|
||||
|
||||
def post_selection
|
||||
previous_user = User.find_by(email: previous_email)
|
||||
|
||||
RecoveryService.recover_procedure!(previous_user:,
|
||||
next_user: current_user,
|
||||
siret:,
|
||||
procedure_ids:)
|
||||
|
||||
redirect_to terminee_recovery_path
|
||||
end
|
||||
|
||||
def terminee
|
||||
end
|
||||
|
||||
def support
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def nature_params = params[:nature]
|
||||
def siret = current_instructeur.agent_connect_information.siret
|
||||
def previous_email = params[:previous_email]
|
||||
def procedure_ids = params[:procedure_ids].map(&:to_i)
|
||||
|
||||
def cipher(email) = message_verifier.generate(email, purpose: :agent_files_recovery, expires_in: 1.hour)
|
||||
def uncipher(email) = message_verifier.verified(email, purpose: :agent_files_recovery) rescue nil
|
||||
|
||||
def structure_name
|
||||
# we know that the structure exists because
|
||||
# of the ensure_collectivite_territoriale guard
|
||||
APIRechercheEntreprisesService.new.(siret:).value![:nom_complet]
|
||||
end
|
||||
|
||||
def ensure_agent_connect_is_used
|
||||
if current_instructeur&.agent_connect_information.nil?
|
||||
redirect_to support_recovery_path(error: :must_use_agent_connect)
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_collectivite_territoriale
|
||||
if !APIRechercheEntreprisesService.collectivite_territoriale?(siret:)
|
||||
redirect_to support_recovery_path(error: 'not_collectivite_territoriale')
|
||||
end
|
||||
end
|
||||
end
|
16
app/helpers/recovery_selection_helper.rb
Normal file
16
app/helpers/recovery_selection_helper.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
module RecoverySelectionHelper
|
||||
def recoverable_id_and_libelles(recoverables)
|
||||
recoverables
|
||||
.map { |r| [r[:procedure_id], nice_libelle(r)] }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def nice_libelle(recoverable)
|
||||
sanitize(
|
||||
"Nº #{number_with_html_delimiter(recoverable[:procedure_id])}" \
|
||||
" - #{recoverable[:libelle]} " \
|
||||
"#{tag.span(pluralize(recoverable[:count], 'dossier'), class: 'fr-tag fr-tag--sm')}"
|
||||
)
|
||||
end
|
||||
end
|
|
@ -1,14 +1,17 @@
|
|||
import { Controller } from '@hotwired/stimulus';
|
||||
|
||||
export class RadioEnabledSubmitController extends Controller {
|
||||
export class EnableSubmitIfCheckedController extends Controller {
|
||||
static targets = ['submit'];
|
||||
declare readonly submitTarget: HTMLButtonElement;
|
||||
|
||||
click() {
|
||||
if (
|
||||
this.element.querySelectorAll('input[type="radio"]:checked').length > 0
|
||||
this.element.querySelectorAll('input[type="radio"]:checked').length > 0 ||
|
||||
this.element.querySelectorAll('input[type="checkbox"]:checked').length > 0
|
||||
) {
|
||||
this.submitTarget.disabled = false;
|
||||
} else {
|
||||
this.submitTarget.disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
3
app/models/agent_connect_information.rb
Normal file
3
app/models/agent_connect_information.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class AgentConnectInformation < ApplicationRecord
|
||||
belongs_to :instructeur
|
||||
end
|
|
@ -2,6 +2,8 @@ class Instructeur < ApplicationRecord
|
|||
include UserFindByConcern
|
||||
has_and_belongs_to_many :administrateurs
|
||||
|
||||
has_one :agent_connect_information, dependent: :destroy
|
||||
|
||||
has_many :assign_to, dependent: :destroy
|
||||
has_many :groupe_instructeurs, -> { order(:label) }, through: :assign_to
|
||||
has_many :unordered_groupe_instructeurs, through: :assign_to, source: :groupe_instructeur
|
||||
|
|
|
@ -12,9 +12,9 @@ class AgentConnectService
|
|||
nonce = SecureRandom.hex(16)
|
||||
|
||||
uri = client.authorization_uri(
|
||||
scope: [:openid, :email],
|
||||
state: state,
|
||||
nonce: nonce,
|
||||
scope: [:openid, :email, :given_name, :usual_name, :organizational_unit, :belonging_population, :siret],
|
||||
state:,
|
||||
nonce:,
|
||||
acr_values: 'eidas1'
|
||||
)
|
||||
|
||||
|
|
35
app/services/api_recherche_entreprises_service.rb
Normal file
35
app/services/api_recherche_entreprises_service.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
class APIRechercheEntreprisesService
|
||||
include Dry::Monads[:result]
|
||||
|
||||
def self.collectivite_territoriale?(siret:)
|
||||
response = APIRechercheEntreprisesService.new.call(siret:)
|
||||
|
||||
return false if response.failure?
|
||||
|
||||
response.success&.dig(:complements, :collectivite_territoriale).present?
|
||||
end
|
||||
|
||||
def call(siret:)
|
||||
result = API::Client.new.(url: "#{url}?q=#{siret}")
|
||||
|
||||
return result if result.failure?
|
||||
|
||||
body = result.success.body
|
||||
|
||||
return Success(nil) if body[:results].empty?
|
||||
|
||||
# the api returns the matching structure in the first element if it exists
|
||||
structure = body[:results][0]
|
||||
|
||||
# safety check : the api does fuzzy matching, so we need to check that the siret matches
|
||||
return Failure() if structure[:matching_etablissements].all? { _1[:siret] != siret }
|
||||
|
||||
Success(structure)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def url
|
||||
"#{API_RECHERCHE_ENTREPRISE_URL}/search"
|
||||
end
|
||||
end
|
37
app/services/recovery_service.rb
Normal file
37
app/services/recovery_service.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
class RecoveryService
|
||||
def self.recoverable_procedures(previous_user:, siret:)
|
||||
return [] if previous_user.nil?
|
||||
|
||||
previous_user.dossiers
|
||||
.includes(:procedure)
|
||||
.joins(:etablissement)
|
||||
.where(etablissements: { siret: })
|
||||
.pluck('procedures.id, procedures.libelle')
|
||||
.tally
|
||||
.map { |(procedure_id, libelle), count| { procedure_id:, libelle:, count: } }
|
||||
.sort_by { |h| [-h[:count], h[:libelle]] }
|
||||
end
|
||||
|
||||
def self.recover_procedure!(previous_user:, next_user:, siret:, procedure_ids:)
|
||||
recoverable_procedure_ids = recoverable_procedures(previous_user: previous_user, siret: siret)
|
||||
.map { _1[:procedure_id] }
|
||||
|
||||
dossiers = procedure_ids
|
||||
.filter { |id| id.in?(recoverable_procedure_ids) }
|
||||
.then do |p_ids|
|
||||
previous_user.dossiers.joins(:procedure)
|
||||
.where(procedure: { id: p_ids })
|
||||
end
|
||||
|
||||
dossiers.pluck(:id).map do |id|
|
||||
{
|
||||
dossier_id: id,
|
||||
from: previous_user.email,
|
||||
from_support: false,
|
||||
to: next_user.email
|
||||
}
|
||||
end.then { |array| DossierTransferLog.create(array) }
|
||||
|
||||
dossiers.update_all(user_id: next_user.id)
|
||||
end
|
||||
end
|
|
@ -9,10 +9,10 @@
|
|||
%h1 Routage à partir d’un champ
|
||||
= form_for :create_simple_routing,
|
||||
method: :post,
|
||||
data: { controller: 'radio-enabled-submit' },
|
||||
data: { controller: 'enable-submit-if-checked' },
|
||||
url: create_simple_routing_admin_procedure_groupe_instructeurs_path(@procedure) do |f|
|
||||
|
||||
%div{ data: { 'action': "click->radio-enabled-submit#click" } }
|
||||
%div{ data: { 'action': "click->enable-submit-if-checked#click" } }
|
||||
.notice
|
||||
Sélectionner le champ à partir duquel créer des groupes d’instructeurs
|
||||
- buttons_content = @procedure.active_revision.routable_types_de_champ.map { |tdc| { label: tdc.libelle, value: tdc.stable_id } }
|
||||
|
@ -24,4 +24,4 @@
|
|||
%li
|
||||
= link_to 'Retour', options_admin_procedure_groupe_instructeurs_path(@procedure, state: :choix), class: 'fr-btn fr-btn--secondary'
|
||||
%li
|
||||
%button.fr-btn{ disabled: true, data: { disable_with: 'Création des groupes…', 'radio-enabled-submit-target': 'submit' } } Créer les groupes
|
||||
%button.fr-btn{ disabled: true, data: { disable_with: 'Création des groupes…', 'enable-submit-if-checked-target': 'submit' } } Créer les groupes
|
||||
|
|
21
app/views/recoveries/identification.html.haml
Normal file
21
app/views/recoveries/identification.html.haml
Normal file
|
@ -0,0 +1,21 @@
|
|||
- content_for(:title) { "Identification du propriétaire" }
|
||||
|
||||
.fr-container.fr-my-6w
|
||||
%h1 Récupération de dossiers
|
||||
|
||||
%h2 Identification du propriétaire des dossiers
|
||||
|
||||
%p Votre organisation est « #{@structure_name} » identifiée par le SIRET #{current_instructeur.agent_connect_information.siret}
|
||||
= form_with do |f|
|
||||
.fr-input-group
|
||||
%label.fr-label{ for: "email" }
|
||||
Email du propriétaire des dossiers
|
||||
%span.fr-hint-text= t('email', scope: [:activerecord, :attributes, :default_attributes, :hints])
|
||||
|
||||
= f.email_field :previous_email,
|
||||
required: true,
|
||||
autocomplete: 'off',
|
||||
class: 'fr-input width-66',
|
||||
id: 'email'
|
||||
|
||||
%button.fr-btn Continuer
|
18
app/views/recoveries/nature.html.haml
Normal file
18
app/views/recoveries/nature.html.haml
Normal file
|
@ -0,0 +1,18 @@
|
|||
- content_for(:title) { "Nature des dossiers" }
|
||||
|
||||
.fr-container.fr-my-6w
|
||||
%h1.fr-h1 Récupération de dossiers
|
||||
|
||||
%h2.fr-h2 Nature des dossiers
|
||||
= form_with data: { controller: 'enable-submit-if-checked' } do |f|
|
||||
|
||||
- buttons = [{ label: 'des dossiers concernant une collectivité territoriale',
|
||||
value: 'collectivite',
|
||||
hint: '(DETR, autres demandes de subvention, consultation du domaine, ...)' },
|
||||
{ label: 'autre', value: 'autre'}]
|
||||
|
||||
%div{ data: { 'action': "click->enable-submit-if-checked#click" } }
|
||||
= render Dsfr::RadioButtonListComponent.new(form: f, target: :nature, buttons: buttons) do
|
||||
%legend#radio-hint-element-legend.fr-fieldset__legend--regular.fr-fieldset__legend Quel type de dossier souhaitez vous récupérer ?
|
||||
|
||||
%button.fr-btn{ disabled: true, data: { 'enable-submit-if-checked-target': 'submit' } } Continuer
|
20
app/views/recoveries/selection.html.haml
Normal file
20
app/views/recoveries/selection.html.haml
Normal file
|
@ -0,0 +1,20 @@
|
|||
- content_for(:title) { "Sélection des démarches" }
|
||||
|
||||
.fr-container.fr-my-6w
|
||||
%h1.fr-h1 Récupération de dossiers
|
||||
|
||||
%h2.fr-h2 Sélection des démarches
|
||||
= form_tag nil, data: { controller: 'enable-submit-if-checked' } do
|
||||
%fieldset#checkboxes.fr-fieldset{ 'aria-labelledby': "checkboxes-legend checkboxes-messages",
|
||||
data: { 'action': "click->enable-submit-if-checked#click" } }
|
||||
%legend#checkboxes-legend.fr-fieldset__legend--regular.fr-fieldset__legend
|
||||
Sélectionner les démarches que vous souhaitez récuperer.
|
||||
|
||||
- recoverable_id_and_libelles(@recoverables).each do |procedure_id, libelle|
|
||||
.fr-fieldset__element
|
||||
.fr-checkbox-group
|
||||
= check_box_tag 'procedure_ids[]', procedure_id, false, class: 'fr-checkbox', id: procedure_id
|
||||
= label_tag procedure_id, libelle, class: 'fr-label'
|
||||
|
||||
= hidden_field_tag 'previous_email', @previous_email
|
||||
%button.fr-btn{ disabled: true, data: { 'enable-submit-if-checked-target': 'submit' } } Continuer
|
36
app/views/recoveries/support.html.haml
Normal file
36
app/views/recoveries/support.html.haml
Normal file
|
@ -0,0 +1,36 @@
|
|||
- content_for(:title) { "Contactez le support" }
|
||||
|
||||
.fr-container.fr-my-6w
|
||||
%h1.fr-h1 Récupération de dossiers
|
||||
|
||||
- case params[:error]
|
||||
- when 'other_nature', 'not_collectivite_territoriale'
|
||||
%p Votre situation nécessite un traitement particulier.
|
||||
|
||||
= mail_to(CONTACT_EMAIL,
|
||||
'Contactez le support',
|
||||
subject: 'Récupération de dossiers',
|
||||
class: 'fr-btn')
|
||||
|
||||
- when 'must_use_agent_connect'
|
||||
%p Vous devez utiliser le portail AgentConnect pour récupérer vos dossiers.
|
||||
|
||||
= link_to(agent_connect_login_path, class: "fr-btn fr-connect") do
|
||||
%span.fr-connect__login
|
||||
= t('signin_with', scope: [:agent_connect, :agent, :index])
|
||||
%span.fr-connect__brand AgentConnect
|
||||
|
||||
%p Vous n'avez pas encore de compte AgentConnect ? Vous pouvez en créer un en utilisant MonComptePro.
|
||||
= link_to 'MonComptePro', 'https://moncomptepro.beta.gouv.fr', class: 'fr-btn'
|
||||
|
||||
- when 'no_dossier'
|
||||
%p Lʼadresse email « #{cookies[:retrieve_email]} » que vous avez renseignée nʼa pas de dossier concernant votre organisation.
|
||||
|
||||
%ul.fr-btns-group.fr-btns-group--inline
|
||||
%li
|
||||
= link_to 'Essayer avec une autre adresse email', identification_recovery_path, class: 'fr-btn'
|
||||
%li
|
||||
= mail_to(CONTACT_EMAIL,
|
||||
'Contactez le support',
|
||||
subject: 'Récupération de dossiers',
|
||||
class: 'fr-btn fr-btn--secondary')
|
10
app/views/recoveries/terminee.html.haml
Normal file
10
app/views/recoveries/terminee.html.haml
Normal file
|
@ -0,0 +1,10 @@
|
|||
- content_for(:title) { "Récupération terminée" }
|
||||
|
||||
.fr-container.fr-my-6w
|
||||
%h1.fr-h1 Récupération de dossiers
|
||||
|
||||
%h2.fr-h2 Récupération terminée
|
||||
|
||||
%p Les dossiers vous ont été réaffectés.
|
||||
|
||||
= link_to "Voir mes dossiers", dossiers_path, class: "fr-btn"
|
|
@ -8,6 +8,7 @@ API_PARTICULIER_URL = ENV.fetch("API_PARTICULIER_URL", "https://particulier.api.
|
|||
API_TCHAP_URL = ENV.fetch("API_TCHAP_URL", "https://matrix.agent.tchap.gouv.fr/_matrix/identity/api/v1")
|
||||
API_COJO_URL = ENV.fetch("API_COJO_URL", nil)
|
||||
API_RNF_URL = ENV.fetch("API_RNF_URL", "https://rnf.dso.numerique-interieur.com")
|
||||
API_RECHERCHE_ENTREPRISE_URL = ENV.fetch("API_RECHERCHE_ENTREPRISE_URL", "https://recherche-entreprises.api.gouv.fr")
|
||||
HELPSCOUT_API_URL = ENV.fetch("HELPSCOUT_API_URL", "https://api.helpscout.net/v2")
|
||||
SENDINBLUE_API_URL = ENV.fetch("SENDINBLUE_API_URL", "https://in-automate.sendinblue.com/api/v2")
|
||||
SENDINBLUE_API_V3_URL = ENV.fetch("SENDINBLUE_API_V3_URL", "https://api.sendinblue.com/v3")
|
||||
|
|
|
@ -699,6 +699,20 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resource :recovery, only: [], path: :recuperation_de_dossiers do
|
||||
collection do
|
||||
get :nature
|
||||
post :nature, action: :post_nature
|
||||
get :identification
|
||||
post :identification, action: :post_identification
|
||||
get :selection
|
||||
post :selection, action: :post_selection
|
||||
get :terminee
|
||||
get :support
|
||||
end
|
||||
|
||||
root action: :nature
|
||||
end
|
||||
#
|
||||
# Legacy routes
|
||||
#
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
class CreateAgentConnectInformations < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table :agent_connect_informations do |t|
|
||||
t.references :instructeur, null: false, foreign_key: true
|
||||
t.string :given_name, null: false
|
||||
t.string :usual_name, null: false
|
||||
t.string :email, null: false
|
||||
t.string :sub, null: false
|
||||
t.string :siret
|
||||
t.string :organizational_unit
|
||||
t.string :belonging_population
|
||||
t.string :phone
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
16
db/schema.rb
16
db/schema.rb
|
@ -91,6 +91,21 @@ ActiveRecord::Schema[7.0].define(version: 2024_02_27_163855) do
|
|||
t.index ["procedure_id"], name: "index_administrateurs_procedures_on_procedure_id"
|
||||
end
|
||||
|
||||
create_table "agent_connect_informations", force: :cascade do |t|
|
||||
t.string "belonging_population"
|
||||
t.datetime "created_at", null: false
|
||||
t.string "email", null: false
|
||||
t.string "given_name", null: false
|
||||
t.bigint "instructeur_id", null: false
|
||||
t.string "organizational_unit"
|
||||
t.string "phone"
|
||||
t.string "siret"
|
||||
t.string "sub", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "usual_name", null: false
|
||||
t.index ["instructeur_id"], name: "index_agent_connect_informations_on_instructeur_id"
|
||||
end
|
||||
|
||||
create_table "api_tokens", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||
t.bigint "administrateur_id", null: false
|
||||
t.bigint "allowed_procedure_ids", array: true
|
||||
|
@ -1179,6 +1194,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_02_27_163855) do
|
|||
add_foreign_key "administrateurs_instructeurs", "instructeurs"
|
||||
add_foreign_key "administrateurs_procedures", "administrateurs"
|
||||
add_foreign_key "administrateurs_procedures", "procedures"
|
||||
add_foreign_key "agent_connect_informations", "instructeurs"
|
||||
add_foreign_key "api_tokens", "administrateurs"
|
||||
add_foreign_key "archives_groupe_instructeurs", "archives"
|
||||
add_foreign_key "archives_groupe_instructeurs", "groupe_instructeurs"
|
||||
|
|
|
@ -30,7 +30,7 @@ describe AgentConnect::AgentController, type: :controller do
|
|||
context 'when the callback code is correct' do
|
||||
let(:code) { 'correct' }
|
||||
let(:state) { original_state }
|
||||
let(:user_info) { { 'sub' => 'sub', 'email' => ' I@email.com' } }
|
||||
let(:user_info) { { 'sub' => 'sub', 'email' => ' I@email.com', 'given_name' => 'given', 'usual_name' => 'usual' } }
|
||||
|
||||
context 'and user_info returns some info' do
|
||||
before do
|
||||
|
|
139
spec/controllers/recoveries_controller_spec.rb
Normal file
139
spec/controllers/recoveries_controller_spec.rb
Normal file
|
@ -0,0 +1,139 @@
|
|||
describe RecoveriesController, type: :controller do
|
||||
include Dry::Monads[:result]
|
||||
|
||||
describe 'GET #nature' do
|
||||
subject { get :nature }
|
||||
|
||||
it { is_expected.to have_http_status(:success) }
|
||||
end
|
||||
|
||||
describe 'POST #post_nature' do
|
||||
subject { post :post_nature, params: { nature: nature } }
|
||||
|
||||
context 'when nature is collectivite' do
|
||||
let(:nature) { 'collectivite' }
|
||||
|
||||
it { is_expected.to redirect_to(identification_recovery_path) }
|
||||
end
|
||||
|
||||
context 'when nature is not collectivite' do
|
||||
let(:nature) { 'other' }
|
||||
|
||||
it { is_expected.to redirect_to(support_recovery_path(error: :other_nature)) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Get #support' do
|
||||
subject { get :support }
|
||||
|
||||
it { is_expected.to have_http_status(:success) }
|
||||
end
|
||||
|
||||
describe 'ensure_agent_connect_is_used' do
|
||||
subject { post :selection }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:ensure_collectivite_territoriale).and_return(true)
|
||||
allow(controller).to receive(:selection).and_return(true)
|
||||
end
|
||||
|
||||
context 'when agent connect is used' do
|
||||
let(:instructeur) { create(:instructeur, :with_agent_connect_information) }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:current_instructeur).and_return(instructeur)
|
||||
end
|
||||
|
||||
it { is_expected.to have_http_status(:success) }
|
||||
end
|
||||
|
||||
context 'when agent connect is not used' do
|
||||
it { is_expected.to redirect_to(support_recovery_path(error: :must_use_agent_connect)) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'ensure_collectivite_territoriale' do
|
||||
subject { post :selection }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:ensure_agent_connect_is_used).and_return(true)
|
||||
allow(controller).to receive(:siret).and_return('123')
|
||||
allow(controller).to receive(:selection).and_return(true)
|
||||
end
|
||||
|
||||
context 'when collectivite territoriale' do
|
||||
before do
|
||||
allow(APIRechercheEntreprisesService).to receive(:collectivite_territoriale?).and_return(true)
|
||||
end
|
||||
|
||||
it { is_expected.to have_http_status(:success) }
|
||||
end
|
||||
|
||||
context 'when not collectivite territoriale' do
|
||||
before do
|
||||
allow(APIRechercheEntreprisesService).to receive(:collectivite_territoriale?).and_return(false)
|
||||
end
|
||||
|
||||
it { is_expected.to redirect_to(support_recovery_path(error: 'not_collectivite_territoriale')) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the current instructeur used agent connect and works for a collectivite territoriale' do
|
||||
let(:instructeur) { create(:instructeur, :with_agent_connect_information) }
|
||||
let(:api_recherche_result) do
|
||||
{ nom_complet: 'name', complements: { collectivite_territoriale: { is: :present } } }
|
||||
end
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:current_instructeur).and_return(instructeur)
|
||||
allow_any_instance_of(APIRechercheEntreprisesService).to receive(:call)
|
||||
.and_return(Success(api_recherche_result))
|
||||
end
|
||||
|
||||
describe 'GET #identification' do
|
||||
subject { get :identification }
|
||||
|
||||
it { is_expected.to have_http_status(:success) }
|
||||
end
|
||||
|
||||
describe 'POST #post_identification' do
|
||||
subject { post :post_identification, params: { previous_email: 'email@a.com' } }
|
||||
|
||||
it do
|
||||
response = subject
|
||||
expect(response).to have_http_status(:redirect)
|
||||
expect(response.location).to start_with(selection_recovery_url)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #selection' do
|
||||
subject { get :selection }
|
||||
|
||||
context 'when there are no recoverable procedures' do
|
||||
before do
|
||||
allow(RecoveryService).to receive(:recoverable_procedures).and_return([])
|
||||
end
|
||||
|
||||
it { is_expected.to redirect_to(support_recovery_path(error: :no_dossier)) }
|
||||
end
|
||||
|
||||
context 'when there are recoverable procedures' do
|
||||
let(:recoverable_procedures) { [[1, 'libelle', 2]] }
|
||||
|
||||
before do
|
||||
allow(RecoveryService).to receive(:recoverable_procedures).and_return(recoverable_procedures)
|
||||
end
|
||||
|
||||
it { is_expected.to have_http_status(:success) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #post_selection' do
|
||||
subject { post :post_selection, params: { procedure_ids: [1] } }
|
||||
|
||||
before { expect(RecoveryService).to receive(:recover_procedure!) }
|
||||
|
||||
it { is_expected.to redirect_to(terminee_recovery_path) }
|
||||
end
|
||||
end
|
||||
end
|
12
spec/factories/agent_connect_information.rb
Normal file
12
spec/factories/agent_connect_information.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
FactoryBot.define do
|
||||
factory :agent_connect_information do
|
||||
email { 'i@agent_connect.fr' }
|
||||
given_name { 'John' }
|
||||
usual_name { 'Doe' }
|
||||
sub { '123456789' }
|
||||
siret { '12345678901234' }
|
||||
organizational_unit { 'Ministère A.M.E.R.' }
|
||||
belonging_population { 'stagiaire' }
|
||||
phone { '0123456789' }
|
||||
end
|
||||
end
|
|
@ -10,5 +10,11 @@ FactoryBot.define do
|
|||
email { generate(:instructeur_email) }
|
||||
password { 'somethingverycomplated!' }
|
||||
end
|
||||
|
||||
trait :with_agent_connect_information do
|
||||
after(:create) do |instructeur, _evaluator|
|
||||
create(:agent_connect_information, instructeur: instructeur)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
640
spec/fixtures/files/api_recherche_entreprises/col_ter_20006541500016.json
vendored
Normal file
640
spec/fixtures/files/api_recherche_entreprises/col_ter_20006541500016.json
vendored
Normal file
|
@ -0,0 +1,640 @@
|
|||
{
|
||||
"results": [
|
||||
{
|
||||
"siren": "200065415",
|
||||
"nom_complet": "COMMUNE DE LA HAGUE",
|
||||
"nom_raison_sociale": "COMMUNE DE LA HAGUE",
|
||||
"sigle": null,
|
||||
"nombre_etablissements": 51,
|
||||
"nombre_etablissements_ouverts": 48,
|
||||
"siege": {
|
||||
"activite_principale": "84.11Z",
|
||||
"activite_principale_registre_metier": null,
|
||||
"annee_tranche_effectif_salarie": "2021",
|
||||
"adresse": "8 RUE DES TOHAGUES 50440 LA HAGUE",
|
||||
"caractere_employeur": null,
|
||||
"cedex": null,
|
||||
"code_pays_etranger": null,
|
||||
"code_postal": "50440",
|
||||
"commune": "50041",
|
||||
"complement_adresse": null,
|
||||
"coordonnees": "49.66215,-1.830805",
|
||||
"date_creation": "2017-01-01",
|
||||
"date_debut_activite": "2017-01-01",
|
||||
"date_mise_a_jour": "2023-11-27T13:18:35",
|
||||
"departement": "50",
|
||||
"distribution_speciale": null,
|
||||
"est_siege": true,
|
||||
"etat_administratif": "A",
|
||||
"geo_adresse": "8 Rue des Tohagues 50440 La Hague",
|
||||
"geo_id": "50041_0120_00008",
|
||||
"indice_repetition": null,
|
||||
"latitude": "49.66215",
|
||||
"libelle_cedex": null,
|
||||
"libelle_commune": "LA HAGUE",
|
||||
"libelle_commune_etranger": null,
|
||||
"libelle_pays_etranger": null,
|
||||
"libelle_voie": "DES TOHAGUES",
|
||||
"liste_enseignes": [
|
||||
"MAIRIE"
|
||||
],
|
||||
"liste_finess": null,
|
||||
"liste_id_bio": null,
|
||||
"liste_idcc": [
|
||||
"5021"
|
||||
],
|
||||
"liste_id_organisme_formation": null,
|
||||
"liste_rge": null,
|
||||
"liste_uai": null,
|
||||
"longitude": "-1.830805",
|
||||
"nom_commercial": null,
|
||||
"numero_voie": "8",
|
||||
"region": "28",
|
||||
"siret": "20006541500016",
|
||||
"tranche_effectif_salarie": "32",
|
||||
"type_voie": "RUE"
|
||||
},
|
||||
"activite_principale": "84.11Z",
|
||||
"categorie_entreprise": "ETI",
|
||||
"caractere_employeur": null,
|
||||
"annee_categorie_entreprise": "2021",
|
||||
"date_creation": "2017-01-01",
|
||||
"date_mise_a_jour": "2023-11-30T10:17:45",
|
||||
"dirigeants": [],
|
||||
"etat_administratif": "A",
|
||||
"nature_juridique": "7210",
|
||||
"section_activite_principale": "O",
|
||||
"tranche_effectif_salarie": "32",
|
||||
"annee_tranche_effectif_salarie": "2021",
|
||||
"statut_diffusion": "O",
|
||||
"matching_etablissements": [
|
||||
{
|
||||
"activite_principale": "84.11Z",
|
||||
"annee_tranche_effectif_salarie": "2021",
|
||||
"adresse": "8 RUE DES TOHAGUES 50440 LA HAGUE",
|
||||
"caractere_employeur": null,
|
||||
"code_postal": "50440",
|
||||
"commune": "50041",
|
||||
"date_creation": "2017-01-01",
|
||||
"date_debut_activite": "2017-01-01",
|
||||
"est_siege": true,
|
||||
"etat_administratif": "A",
|
||||
"geo_id": "50041_0120_00008",
|
||||
"latitude": "49.66215",
|
||||
"libelle_commune": "LA HAGUE",
|
||||
"liste_enseignes": [
|
||||
"MAIRIE"
|
||||
],
|
||||
"liste_finess": null,
|
||||
"liste_id_bio": null,
|
||||
"liste_idcc": [
|
||||
"5021"
|
||||
],
|
||||
"liste_id_organisme_formation": null,
|
||||
"liste_rge": null,
|
||||
"liste_uai": null,
|
||||
"longitude": "-1.830805",
|
||||
"nom_commercial": null,
|
||||
"region": "28",
|
||||
"siret": "20006541500016",
|
||||
"tranche_effectif_salarie": "32"
|
||||
}
|
||||
],
|
||||
"finances": {},
|
||||
"complements": {
|
||||
"collectivite_territoriale": {
|
||||
"code": "50041",
|
||||
"code_insee": "50041",
|
||||
"elus": [
|
||||
{
|
||||
"nom": "ADOUE",
|
||||
"prenoms": "Chantal",
|
||||
"annee_de_naissance": "19/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "ALLENO",
|
||||
"prenoms": "Gwladys",
|
||||
"annee_de_naissance": "04/0",
|
||||
"fonction": "8ème adjoint au Maire",
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "BEAUMONT",
|
||||
"prenoms": "Monique",
|
||||
"annee_de_naissance": "29/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "BECQUET",
|
||||
"prenoms": "Dominique",
|
||||
"annee_de_naissance": "17/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "BEDEL",
|
||||
"prenoms": "Pauline",
|
||||
"annee_de_naissance": "29/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "BELHOMME",
|
||||
"prenoms": "Dominique",
|
||||
"annee_de_naissance": "12/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "BELHOMME",
|
||||
"prenoms": "Jérôme",
|
||||
"annee_de_naissance": "14/0",
|
||||
"fonction": "1er adjoint au Maire",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "BELHOMME",
|
||||
"prenoms": "Jérôme",
|
||||
"annee_de_naissance": "14/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "BONNISSENT",
|
||||
"prenoms": "Marie-Suzanne",
|
||||
"annee_de_naissance": "05/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "CANOVILLE",
|
||||
"prenoms": "Laurent",
|
||||
"annee_de_naissance": "29/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "CERVANTÈS",
|
||||
"prenoms": "Simon",
|
||||
"annee_de_naissance": "06/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "CHARDOT",
|
||||
"prenoms": "Mélanie",
|
||||
"annee_de_naissance": "12/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "CHARLES",
|
||||
"prenoms": "Véronique",
|
||||
"annee_de_naissance": "04/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "COLLET",
|
||||
"prenoms": "Christian",
|
||||
"annee_de_naissance": "20/1",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "CRANOIS",
|
||||
"prenoms": "Louis",
|
||||
"annee_de_naissance": "16/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "DALMONT",
|
||||
"prenoms": "Hubert",
|
||||
"annee_de_naissance": "29/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "DAMOURETTE",
|
||||
"prenoms": "Etienne",
|
||||
"annee_de_naissance": "02/1",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "DELACOUR",
|
||||
"prenoms": "Thérèse",
|
||||
"annee_de_naissance": "31/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "DESBOIS",
|
||||
"prenoms": "Noëmie",
|
||||
"annee_de_naissance": "14/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "DIGARD",
|
||||
"prenoms": "Antoine",
|
||||
"annee_de_naissance": "03/0",
|
||||
"fonction": "3ème adjoint au Maire",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "DIGARD",
|
||||
"prenoms": "Antoine",
|
||||
"annee_de_naissance": "03/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "DUBOST",
|
||||
"prenoms": "Hubert",
|
||||
"annee_de_naissance": "17/1",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "DUBOST",
|
||||
"prenoms": "Nathalie",
|
||||
"annee_de_naissance": "07/0",
|
||||
"fonction": "4ème adjoint au Maire",
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "FLEURY",
|
||||
"prenoms": "Jean-Marie",
|
||||
"annee_de_naissance": "21/0",
|
||||
"fonction": "11ème adjoint au Maire",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "FRACHET",
|
||||
"prenoms": "Nadine",
|
||||
"annee_de_naissance": "26/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "FRIGOUT",
|
||||
"prenoms": "Jean-Marc",
|
||||
"annee_de_naissance": "20/1",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "GASNIER",
|
||||
"prenoms": "Philippe",
|
||||
"annee_de_naissance": "22/1",
|
||||
"fonction": "5ème adjoint au Maire",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "GASNIER",
|
||||
"prenoms": "Philippe",
|
||||
"annee_de_naissance": "22/1",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "GAUMAIN",
|
||||
"prenoms": "Mathieu",
|
||||
"annee_de_naissance": "06/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "GOACHET",
|
||||
"prenoms": "Joseph",
|
||||
"annee_de_naissance": "27/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "GROF",
|
||||
"prenoms": "Béatrice",
|
||||
"annee_de_naissance": "17/0",
|
||||
"fonction": "2ème adjoint au Maire",
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "GUILLEMETTE",
|
||||
"prenoms": "Nathalie",
|
||||
"annee_de_naissance": "30/0",
|
||||
"fonction": "6ème adjoint au Maire",
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "HAMELIN",
|
||||
"prenoms": "Magali",
|
||||
"annee_de_naissance": "16/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "HENRY",
|
||||
"prenoms": "Claude",
|
||||
"annee_de_naissance": "30/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "JACQUET-ROCQUET",
|
||||
"prenoms": "Sophie",
|
||||
"annee_de_naissance": "26/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "JOURDAIN",
|
||||
"prenoms": "Patrick",
|
||||
"annee_de_naissance": "28/0",
|
||||
"fonction": "7ème adjoint au Maire",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "JOURDAIN",
|
||||
"prenoms": "Patrick",
|
||||
"annee_de_naissance": "28/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "JUMELIN",
|
||||
"prenoms": "Pascale",
|
||||
"annee_de_naissance": "24/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "LADVENU",
|
||||
"prenoms": "Nathalie",
|
||||
"annee_de_naissance": "14/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "LAGALLE",
|
||||
"prenoms": "Marie-Laure",
|
||||
"annee_de_naissance": "23/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "LAPPREND",
|
||||
"prenoms": "Marie",
|
||||
"annee_de_naissance": "08/1",
|
||||
"fonction": "10ème adjoint au Maire",
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "LARGERIE",
|
||||
"prenoms": "Anne",
|
||||
"annee_de_naissance": "03/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "LAVENU",
|
||||
"prenoms": "Patrick",
|
||||
"annee_de_naissance": "01/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "LECOSTEY",
|
||||
"prenoms": "Fabrice",
|
||||
"annee_de_naissance": "25/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "LECOSTEY",
|
||||
"prenoms": "Jean",
|
||||
"annee_de_naissance": "14/1",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "LEDAUPHIN",
|
||||
"prenoms": "Nathalie",
|
||||
"annee_de_naissance": "05/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "LEFRÉTEUR",
|
||||
"prenoms": "Emmanuel",
|
||||
"annee_de_naissance": "10/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "LEGELEUX",
|
||||
"prenoms": "Yann",
|
||||
"annee_de_naissance": "20/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "LELONG",
|
||||
"prenoms": "Nadine",
|
||||
"annee_de_naissance": "29/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "LELONG",
|
||||
"prenoms": "Sébastien",
|
||||
"annee_de_naissance": "15/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "LERENDU",
|
||||
"prenoms": "Patrick",
|
||||
"annee_de_naissance": "08/1",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "LESEIGNEUR-COURVAL",
|
||||
"prenoms": "Thérèse",
|
||||
"annee_de_naissance": "22/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "LETOURNEUR",
|
||||
"prenoms": "Bruno",
|
||||
"annee_de_naissance": "21/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "LUPO",
|
||||
"prenoms": "Antoine",
|
||||
"annee_de_naissance": "16/1",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "MAHIER",
|
||||
"prenoms": "Manuela",
|
||||
"annee_de_naissance": "30/1",
|
||||
"fonction": "Maire",
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "MAUGÉ",
|
||||
"prenoms": "Caroline",
|
||||
"annee_de_naissance": "13/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "MERCIER",
|
||||
"prenoms": "Philippe",
|
||||
"annee_de_naissance": "06/0",
|
||||
"fonction": "9ème adjoint au Maire",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "MERCIER",
|
||||
"prenoms": "Philippe",
|
||||
"annee_de_naissance": "06/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "MONHUREL",
|
||||
"prenoms": "Pascal",
|
||||
"annee_de_naissance": "23/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "NICOLLE",
|
||||
"prenoms": "Stéphanie",
|
||||
"annee_de_naissance": "21/1",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "NOEL",
|
||||
"prenoms": "Nelly",
|
||||
"annee_de_naissance": "24/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "PELLERIN",
|
||||
"prenoms": "Eric",
|
||||
"annee_de_naissance": "17/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "PERROTTE",
|
||||
"prenoms": "Thomas",
|
||||
"annee_de_naissance": "15/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "RENOUF",
|
||||
"prenoms": "Jean-Luc",
|
||||
"annee_de_naissance": "17/0",
|
||||
"fonction": "Maire délégué",
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "ROUCAN",
|
||||
"prenoms": "Robert",
|
||||
"annee_de_naissance": "27/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "SANSON",
|
||||
"prenoms": "Fabienne",
|
||||
"annee_de_naissance": "10/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "SANSON",
|
||||
"prenoms": "Noël",
|
||||
"annee_de_naissance": "25/1",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "SEBIRE",
|
||||
"prenoms": "Marine",
|
||||
"annee_de_naissance": "07/0",
|
||||
"fonction": null,
|
||||
"sexe": "F"
|
||||
},
|
||||
{
|
||||
"nom": "TARDIF",
|
||||
"prenoms": "Pierre",
|
||||
"annee_de_naissance": "13/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "TESTELIN",
|
||||
"prenoms": "Sébastien",
|
||||
"annee_de_naissance": "03/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "TOLLEMER",
|
||||
"prenoms": "Pierre",
|
||||
"annee_de_naissance": "05/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
},
|
||||
{
|
||||
"nom": "TRAVERT",
|
||||
"prenoms": "Laurent",
|
||||
"annee_de_naissance": "24/0",
|
||||
"fonction": null,
|
||||
"sexe": "M"
|
||||
}
|
||||
],
|
||||
"niveau": "commune"
|
||||
},
|
||||
"convention_collective_renseignee": true,
|
||||
"egapro_renseignee": false,
|
||||
"est_association": false,
|
||||
"est_bio": false,
|
||||
"est_entrepreneur_individuel": false,
|
||||
"est_entrepreneur_spectacle": true,
|
||||
"est_ess": false,
|
||||
"est_finess": false,
|
||||
"est_organisme_formation": false,
|
||||
"est_qualiopi": false,
|
||||
"liste_id_organisme_formation": null,
|
||||
"est_rge": false,
|
||||
"est_service_public": true,
|
||||
"est_societe_mission": false,
|
||||
"est_uai": true,
|
||||
"identifiant_association": null,
|
||||
"statut_entrepreneur_spectacle": "valide"
|
||||
}
|
||||
}
|
||||
],
|
||||
"total_results": 1,
|
||||
"page": 1,
|
||||
"per_page": 10,
|
||||
"total_pages": 1
|
||||
}
|
122
spec/fixtures/files/api_recherche_entreprises/dinum_13002526500013.json
vendored
Normal file
122
spec/fixtures/files/api_recherche_entreprises/dinum_13002526500013.json
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
{
|
||||
"results": [
|
||||
{
|
||||
"siren": "130025265",
|
||||
"nom_complet": "DIRECTION INTERMINISTERIELLE DU NUMERIQUE (DINUM)",
|
||||
"nom_raison_sociale": "DIRECTION INTERMINISTERIELLE DU NUMERIQUE",
|
||||
"sigle": "DINUM",
|
||||
"nombre_etablissements": 1,
|
||||
"nombre_etablissements_ouverts": 1,
|
||||
"siege": {
|
||||
"activite_principale": "84.11Z",
|
||||
"activite_principale_registre_metier": null,
|
||||
"annee_tranche_effectif_salarie": "2021",
|
||||
"adresse": "20 AV DE SEGUR 75007 PARIS 7",
|
||||
"caractere_employeur": null,
|
||||
"cedex": null,
|
||||
"code_pays_etranger": null,
|
||||
"code_postal": "75007",
|
||||
"commune": "75107",
|
||||
"complement_adresse": null,
|
||||
"coordonnees": "48.850699,2.308628",
|
||||
"date_creation": "2017-05-24",
|
||||
"date_debut_activite": "2017-05-24",
|
||||
"date_mise_a_jour": "2023-11-27T13:16:04",
|
||||
"departement": "75",
|
||||
"distribution_speciale": null,
|
||||
"est_siege": true,
|
||||
"etat_administratif": "A",
|
||||
"geo_adresse": "20 Avenue de Ségur 75007 Paris",
|
||||
"geo_id": "75107_8909_00020",
|
||||
"indice_repetition": null,
|
||||
"latitude": "48.850699",
|
||||
"libelle_cedex": null,
|
||||
"libelle_commune": "PARIS 7",
|
||||
"libelle_commune_etranger": null,
|
||||
"libelle_pays_etranger": null,
|
||||
"libelle_voie": "DE SEGUR",
|
||||
"liste_enseignes": null,
|
||||
"liste_finess": null,
|
||||
"liste_id_bio": null,
|
||||
"liste_idcc": null,
|
||||
"liste_id_organisme_formation": null,
|
||||
"liste_rge": null,
|
||||
"liste_uai": null,
|
||||
"longitude": "2.308628",
|
||||
"nom_commercial": null,
|
||||
"numero_voie": "20",
|
||||
"region": "11",
|
||||
"siret": "13002526500013",
|
||||
"tranche_effectif_salarie": "22",
|
||||
"type_voie": "AV"
|
||||
},
|
||||
"activite_principale": "84.11Z",
|
||||
"categorie_entreprise": "PME",
|
||||
"caractere_employeur": null,
|
||||
"annee_categorie_entreprise": "2021",
|
||||
"date_creation": "2017-05-24",
|
||||
"date_mise_a_jour": "2023-11-30T10:17:13",
|
||||
"dirigeants": [],
|
||||
"etat_administratif": "A",
|
||||
"nature_juridique": "7120",
|
||||
"section_activite_principale": "O",
|
||||
"tranche_effectif_salarie": "22",
|
||||
"annee_tranche_effectif_salarie": "2021",
|
||||
"statut_diffusion": "O",
|
||||
"matching_etablissements": [
|
||||
{
|
||||
"activite_principale": "84.11Z",
|
||||
"annee_tranche_effectif_salarie": "2021",
|
||||
"adresse": "20 AV DE SEGUR 75007 PARIS 7",
|
||||
"caractere_employeur": null,
|
||||
"code_postal": "75007",
|
||||
"commune": "75107",
|
||||
"date_creation": "2017-05-24",
|
||||
"date_debut_activite": "2017-05-24",
|
||||
"est_siege": true,
|
||||
"etat_administratif": "A",
|
||||
"geo_id": "75107_8909_00020",
|
||||
"latitude": "48.850699",
|
||||
"libelle_commune": "PARIS 7",
|
||||
"liste_enseignes": null,
|
||||
"liste_finess": null,
|
||||
"liste_id_bio": null,
|
||||
"liste_idcc": null,
|
||||
"liste_id_organisme_formation": null,
|
||||
"liste_rge": null,
|
||||
"liste_uai": null,
|
||||
"longitude": "2.308628",
|
||||
"nom_commercial": null,
|
||||
"region": "11",
|
||||
"siret": "13002526500013",
|
||||
"tranche_effectif_salarie": "22"
|
||||
}
|
||||
],
|
||||
"finances": {},
|
||||
"complements": {
|
||||
"collectivite_territoriale": null,
|
||||
"convention_collective_renseignee": false,
|
||||
"egapro_renseignee": false,
|
||||
"est_association": false,
|
||||
"est_bio": false,
|
||||
"est_entrepreneur_individuel": false,
|
||||
"est_entrepreneur_spectacle": false,
|
||||
"est_ess": false,
|
||||
"est_finess": false,
|
||||
"est_organisme_formation": false,
|
||||
"est_qualiopi": false,
|
||||
"liste_id_organisme_formation": null,
|
||||
"est_rge": false,
|
||||
"est_service_public": true,
|
||||
"est_societe_mission": false,
|
||||
"est_uai": false,
|
||||
"identifiant_association": null,
|
||||
"statut_entrepreneur_spectacle": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"total_results": 1,
|
||||
"page": 1,
|
||||
"per_page": 10,
|
||||
"total_pages": 1
|
||||
}
|
60
spec/services/api_recherche_entreprise_service_spec.rb
Normal file
60
spec/services/api_recherche_entreprise_service_spec.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
describe 'APIRechercheEntreprisesService' do
|
||||
include Dry::Monads[:result]
|
||||
OK = Data.define(:body, :response)
|
||||
|
||||
def load_json(file_name)
|
||||
Rails.root.join("spec/fixtures/files/api_recherche_entreprises/#{file_name}.json")
|
||||
.then { File.read(_1) }
|
||||
.then { JSON.parse(_1).with_indifferent_access }
|
||||
end
|
||||
|
||||
let(:col_ter_json) { load_json('col_ter_20006541500016') }
|
||||
let(:dinum_json) { load_json('dinum_13002526500013') }
|
||||
|
||||
describe '.collectivite_territoriale' do
|
||||
let(:client_response) { Success(OK[json_response, '']) }
|
||||
|
||||
subject { APIRechercheEntreprisesService.collectivite_territoriale?(siret:) }
|
||||
|
||||
before { expect_any_instance_of(API::Client).to receive(:call).and_return(client_response) }
|
||||
|
||||
context 'when the api returns some results' do
|
||||
let(:json_response) { col_ter_json }
|
||||
|
||||
context 'and the siret match' do
|
||||
context 'and the structure is a collectivite territoriale' do
|
||||
let(:siret) { '20006541500016' }
|
||||
|
||||
it { is_expected.to be true }
|
||||
end
|
||||
|
||||
context 'and the structure is not a collectivite territoriale' do
|
||||
let(:json_response) { dinum_json }
|
||||
let(:siret) { '13002526500013' }
|
||||
|
||||
it { is_expected.to be false }
|
||||
end
|
||||
end
|
||||
|
||||
context 'and the siret does not match' do
|
||||
let(:siret) { '20006541500666' }
|
||||
|
||||
it { is_expected.to be false }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the api returns no result' do
|
||||
let(:json_response) { { results: [] } }
|
||||
let(:siret) { '20006541500016' }
|
||||
|
||||
it { is_expected.to be false }
|
||||
end
|
||||
|
||||
context 'when the api returns an error' do
|
||||
let(:client_response) { Failure() }
|
||||
let(:siret) { '20006541500016' }
|
||||
|
||||
it { is_expected.to be false }
|
||||
end
|
||||
end
|
||||
end
|
80
spec/services/recovery_service_spec.rb
Normal file
80
spec/services/recovery_service_spec.rb
Normal file
|
@ -0,0 +1,80 @@
|
|||
RSpec.describe RecoveryService, type: :service do
|
||||
describe '.recoverable_procedures' do
|
||||
subject { described_class.recoverable_procedures(previous_user:, siret:) }
|
||||
|
||||
context 'when the previous_user is nil' do
|
||||
let(:previous_user) { nil }
|
||||
let(:siret) { '123' }
|
||||
|
||||
it 'returns []' do
|
||||
expect(subject).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the previous_user has some dossiers' do
|
||||
let(:previous_user) { create(:user) }
|
||||
|
||||
let(:procedure_1) { create(:procedure) }
|
||||
let(:siret) { '123' }
|
||||
|
||||
let(:procedure_2) { create(:procedure) }
|
||||
let(:another_siret) { 'another_123' }
|
||||
|
||||
before do
|
||||
3.times do
|
||||
create(:dossier, procedure: procedure_1,
|
||||
etablissement: create(:etablissement, siret:),
|
||||
user: previous_user)
|
||||
end
|
||||
|
||||
create(:dossier, procedure: procedure_2,
|
||||
etablissement: create(:etablissement, siret: another_siret),
|
||||
user: previous_user)
|
||||
end
|
||||
|
||||
it 'returns the procedures with their count' do
|
||||
expect(subject).to eq([{ procedure_id: procedure_1.id, libelle: procedure_1.libelle, count: 3 }])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.recover_procedure!' do
|
||||
subject { described_class.recover_procedure!(previous_user:, next_user:, siret:, procedure_ids:) }
|
||||
|
||||
context 'when the previous_user has some dossiers' do
|
||||
let!(:previous_user) { create(:user) }
|
||||
let!(:next_user) { create(:user) }
|
||||
|
||||
let!(:procedure_1) { create(:procedure) }
|
||||
let!(:siret) { '123' }
|
||||
|
||||
let!(:procedure_2) { create(:procedure) }
|
||||
let!(:another_siret) { 'another_123' }
|
||||
|
||||
let!(:dossiers_to_recover) do
|
||||
3.times do
|
||||
create(:dossier, procedure: procedure_1,
|
||||
etablissement: create(:etablissement, siret:),
|
||||
user: previous_user)
|
||||
end
|
||||
end
|
||||
|
||||
let!(:dossiers_not_to_recover) do
|
||||
create(:dossier, procedure: procedure_2,
|
||||
etablissement: create(:etablissement, siret: another_siret),
|
||||
user: previous_user)
|
||||
end
|
||||
|
||||
let(:procedure_ids) { [procedure_1.id] }
|
||||
|
||||
it 'moves the files to the next user' do
|
||||
subject
|
||||
expect(next_user.dossiers.count).to eq(3)
|
||||
|
||||
dossier_transfer_log = next_user.dossiers.first.transfer_logs.first
|
||||
expect(dossier_transfer_log.from).to eq(previous_user.email)
|
||||
expect(dossier_transfer_log.to).to eq(next_user.email)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue