Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prescripteur : permettre la création de compte candidat sans candidater #5462

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

EwenKorr
Copy link
Contributor

@EwenKorr EwenKorr commented Jan 24, 2025

🤔 Pourquoi ?

On veut permettre aux prescripteurs de créer un compte candidat, sans forcément postuler pour le candidat dans l'immédiat.

(pour le Contexte et besoin métier, voir la carte Notion)

🍰 Comment ?

Grâce à l'extraction du parcours de création de compte candidat, on peut maintenant ajouter assez facilement un nouveau tunnel 🎉

Il y a plusieurs modifications (voir commits et messages de commits pour plus de détails) :

  • ajout d'un attribut created_by_presciber_organization dans le profil du candidat
  • sur la page Candidats, afficher tous les candidats
    • pour qui on a candidaté
    • qui ont été créés par un membre de notre organisation prescriptrice actuelle
  • à la création d'un candidat, soit on trouve un compte existant, soit on en crée un nouveau, et dans tous les cas on arrive à la fiche candidat.

🏝️ Comment tester ?

En tant que prescripteur, aller à la page Candidats, cliquer sur Créer un compte candidat. Essayer les cas suivant :

  • un vrai nouveau candidat : à la fin du processus, on retourne à la page Candidats avec un message toast de succès
  • un candidat qui existe déjà (retrouvé par son NIR ou son adresse email) : on a un message qui confirme qu'on l'a trouvé, et on "Postule pour ce candidat" (le bandeau "Vous postulez actuellement pour XX" est présent)

💻 Captures d'écran

@EwenKorr EwenKorr added 1-recette-jetable [Payé à l’heure] Crée une recette jetable sur CC ajouté Ajouté dans le changelog. labels Jan 24, 2025
@EwenKorr EwenKorr self-assigned this Jan 24, 2025
@EwenKorr
Copy link
Contributor Author

Il n'y a pas les tests, mais c'est fonctionnellement testable. Je passerai lundi en recette.

itou/www/job_seekers_views/views.py Show resolved Hide resolved
itou/www/job_seekers_views/views.py Outdated Show resolved Hide resolved
itou/www/job_seekers_views/views.py Show resolved Hide resolved
itou/www/job_seekers_views/views.py Outdated Show resolved Hide resolved
Copy link

🥁 La recette jetable est prête ! 👉 Je veux tester cette PR !

@EwenKorr EwenKorr force-pushed the ewen/create-jobseeker-standalone branch 6 times, most recently from c5f7c9f to b2f411a Compare January 28, 2025 15:31
@EwenKorr
Copy link
Contributor Author

Je vais proposer un commit en plus : changer la modale "candidat trouvé avec le nir ou l'email" en fonction de l'existence d'un candidat dans la liste Mes candidats. Cf https://www.notion.so/plateforme-inclusion/Apr-s-avoir-tent-de-cr-er-un-compte-candidat-qui-existe-d-j-dans-ma-liste-188e8fa5c35b809699c7ef55931c4913?pvs=4

Je n'aurais pas le temps de le finir aujourd'hui.

@EwenKorr EwenKorr marked this pull request as ready for review January 28, 2025 16:31
@EwenKorr EwenKorr force-pushed the ewen/create-jobseeker-standalone branch from b2f411a to 1c00d55 Compare January 28, 2025 16:41
Copy link
Contributor

@tonial tonial left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jolie PR avec plein de petits commits ❤️ .

J'ai tout relu sauf TestStandaloneCreateAsPrescriber que je relirai demain dès l'aube.
En attendant je pousse déjà ces commentaires pour ne pas risquer de les perdre.

EDIT: c'est bon, j'ai fini ma relecture

itou/www/job_seekers_views/views.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_list.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_list.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_list.py Outdated Show resolved Hide resolved
itou/www/job_seekers_views/views.py Show resolved Hide resolved
tests/www/job_seekers_views/test_list.py Outdated Show resolved Hide resolved
@@ -94,6 +94,8 @@ <h3 class="modal-title" id="nir-confirmation-label">Utilisateur trouvé</h3>
<p>
{% if is_gps|default:False %}
Si ce n'est pas le bénéficiaire que vous souhaitez suivre, cliquez sur « Suivre un autre bénéficiaire » afin de modifier le numéro de sécurité sociale.
{% elif standalone_creation|default:False %}
Le compte de ce candidat sera ajouté à votre liste une fois que vous aurez postulé pour lui.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Il n'est pas affiché dès qu'on le crée, même sans candidature créée ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Le texte de cette modale n'apparaît que quand on a trouvé un candidat, déjà créé.
Et donc, pour l'utilisateur qui voit cette modale, il faut effectivement qu'il postule pour lui pour qu'il soit ajouté à sa liste.

Je travaille à une autre version de cette modale, cf ce retour de recette https://www.notion.so/gip-inclusion/Apr-s-avoir-tent-de-cr-er-un-compte-candidat-qui-existe-d-j-dans-ma-liste-18a5f321b60481779b76f24cb930f7e4?pvs=4

En gros, on aurait :

  • le cas GPS
  • le cas postuler classique
  • le cas "le candidat existe, mais n'est pas dans votre liste" => postulez pour lui pour le voir apparaître
  • le cas "le candidat existe, et est déjà dans votre liste"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ce sera dans une autre PR.

itou/templates/job_seekers_views/list.html Show resolved Hide resolved
itou/www/job_seekers_views/views.py Outdated Show resolved Hide resolved
Comment on lines 161 to 165
if self.request.user.is_prescriber and self.request.current_organization is not None:
return Q(jobseeker_profile__created_by_prescriber_organization=self.request.current_organization)
elif self.request.user.is_prescriber:
# Prescriber without organization: display job seekers created by them, without organization
return Q(created_by=self.request.user, jobseeker_profile__created_by_prescriber_organization=None)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Je trouve ces règles perturbantes: rejoindre une organisation fait perdre la visibilité sur les candidats que l'on suivait individuellement.
Cela me semblerait plus logique de suivre les même règles que pour les candidatures:

if user.is_prescriber:
if organization:
return self.filter(
(Q(sender=user) & Q(sender_prescriber_organization__isnull=True))
| Q(sender_prescriber_organization=organization)
)
else:
return self.filter(sender=user)

Ou encore mieux: donner accès à tous et rajouter un filtre sur l'organisation créatrice.

Ensuite, à une époque le métier avait émis le besoin de pouvoir "archiver" un candidat (que l'on sait par exemple ne plus suivre): on met ce besoin en attente pour le moment j'imagine ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ou encore mieux: donner accès à tous et rajouter un filtre sur l'organisation créatrice.

Gros +1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Les règles métier sur la carte Notion (mais je vais en rediscuter avec Marion) :

Règles d’affichage du candidat créé :

  • Si j’ai créé le candidat sans être rattaché à une orga -> il s’affiche dans la liste
  • Si j’ai créé le candidat à partir d’une orga à laquelle j’appartiens -> il s’affiche dans la liste
  • Si j’ai créé le candidat à partir d’une orga à laquelle je n’appartiens plus -> il ne s’affiche plus dans ma liste

Ou encore mieux: donner accès à tous et rajouter un filtre sur l'organisation créatrice.

Je ne suis pas sûr de comprendre : donner accès à tous les prescripteurs (= tous les prescripteurs voient leurs candidats, created_by=request.user) et filtre sur orga créatrice (created_by_prescriber_organization=request.current_organization). Comment joindre les deux ?


Ensuite, à une époque le métier avait émis le besoin de pouvoir "archiver" un candidat (que l'on sait par exemple ne plus suivre): on met ce besoin en attente pour le moment j'imagine ?

Je pense qu'on verra ça après oui.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moi je verrais bien:

filter = Q(created_by=self.request.user)
if self.request.current_organization:
    filter |= Q(jobseeker_profile__created_by_prescriber_organization=self.request.current_organization))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

J'ai fait un petit fixup qui sera fusionné au commit précédent avec cette règle.
Elle est un petit peu différente de la règle des candidatures (dans laquelle on ne voit que ses candidatures "individuelles" et les candidatures faites pour une orga, pas les candidatures qu'on a faites pour d'autres orga).

Au pire, ça pourra assez facilement être adapté au besoin.

itou/www/job_seekers_views/views.py Outdated Show resolved Hide resolved
@@ -278,6 +278,7 @@ def __init__(self):
self.hire_process = None
self.prescription_proces = None
self.auto_prescription_process = None
self.standalone_creation = None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tous ces booléens ressemblent beaucoup à la liste des tunnels.
Si on sépare/spécialise sender en prescription & auto_prescription on aura du 1 pour 1, et on s'évitera tous ces not self.hire_process and not self.is_gps and ... en cascade dans le setup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Je suis pour !
Je me note de nettoyer ça après.

Comment on lines 1016 to 1022
created_by_prescriber_organization = models.ForeignKey(
PrescriberOrganization,
verbose_name="créé par un membre de l'organisation",
on_delete=models.RESTRICT,
null=True,
blank=True,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Si en effet ça ne devrait concerner que les candidats, je ne suis pas convaincu par le fait de stocker created_by et created_by_org dans deux tables différentes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Et donc il faudrait déplacer created_by dans JobSeekerProfile ?
(vu qu'on va être amenés à ajouter d'autres infos du même style dans ce modèle, cf https://www.notion.so/gip-inclusion/infos-perso-candidat-Afficher-l-auteur-de-la-mise-jour-de-chaque-section-de-donn-es-perso-du-cand-18a5f321b604810688edfbb413cf7c49

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plutôt l'inverse car created_by est utilisé pour tout type de profil.

C'est pas critique, mais ce sont 2 données assez proches que j'aurais bien stocké au même endroit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

En vrai, je me demande si le created_by est pertinent pour les autres types d'utilisateur 😅
Audit mis à part (mais des logs techniques pourraient faire l'affaire), il n'est utilisé que pour savoir si tel autre utilisateur a le droit de modifier les infos d'un candidat...

Copy link
Contributor Author

@EwenKorr EwenKorr Jan 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Et puis à created_by_org s'ajouterait created_by_company
Deux attributs inutiles pour tous les utilisateurs à part les candidats. ⚖️ 🤷

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

=> select kind, count(*) from users_user where created_by_id is not null group by kind;
    kind    |  count  
------------+---------
 employer   |       9
 job_seeker | 1050212
 prescriber |      32
(3 rows)

👀

@EwenKorr EwenKorr force-pushed the ewen/create-jobseeker-standalone branch 5 times, most recently from 26ee65b to c09b6b3 Compare January 30, 2025 14:29
@xavfernandez
Copy link
Contributor

Tu as un un ChickNIR dans un des messages de commit :)

@EwenKorr EwenKorr force-pushed the ewen/create-jobseeker-standalone branch 2 times, most recently from 4370480 to b74a0cd Compare January 31, 2025 07:35
@EwenKorr EwenKorr requested a review from xavfernandez January 31, 2025 07:41
tests/www/job_seekers_views/test_list.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_create_or_update.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_create_or_update.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_create_or_update.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_create_or_update.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_create_or_update.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_create_or_update.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_create_or_update.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_create_or_update.py Outdated Show resolved Hide resolved
tests/www/job_seekers_views/test_create_or_update.py Outdated Show resolved Hide resolved
@EwenKorr
Copy link
Contributor Author

EwenKorr commented Feb 5, 2025

Est-ce que vous voyez autre chose à améliorer ? cc @xavfernandez notamment 😁

The code says that employers cannot acces `job_seekers_views:list`,
let's test that.
It is used in job_seekers_views only.
…mplates

In CheckNIR and SearchByEmail views, we used to hide the company block for
GPS only, but in another case there is no company as well: the
standalone creation of a job seeker.
In order to be able to list job seekers created by our colleagues in a
prescriber organization.
@EwenKorr EwenKorr force-pushed the ewen/create-jobseeker-standalone branch from 276ec20 to ebdef42 Compare February 5, 2025 09:01
Refactor an assertContains(…, html=True) test with lots of html classes.
In `job_seekers_views:list`, show not only the job seekers that we
applied for, but also the ones that were created by members of my
prescriber organization, as saved in
`job_seeker.jobseeker_profile.created_by_prescriber_organization`.

The rule is the following:
- display all job seekers created by the user
- display all job seekers created for the organization
  (ie. the users had this orga as `current_organization` at creation)
When a job seeker is created by a prescriber (for a prescription or GPS
or any tunnel), save the current organization in the job seeker's profile.
…dats"

A prescriber can create a new job seeker, without applying for them
directly from the "Mes candidats" page.

If a job seeker is found at step CheckNIR or SearchByEmail, then we
follow the "Postuler pour ce candidat" process.
Otherwise, we create the job seeker, set
`created_by_prescriber_organization` to the current organization and
redirect to "Mes candidats".
Add matomo tags in:
- button Créer un compte candidat (list page)
- button Créer le compte candidat (creation step end page)
@EwenKorr EwenKorr force-pushed the ewen/create-jobseeker-standalone branch from ebdef42 to a1cc39d Compare February 5, 2025 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1-recette-jetable [Payé à l’heure] Crée une recette jetable sur CC ajouté Ajouté dans le changelog.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants