feat: le mandataire compose le groupement et envoie les invitations (FAS-573 US M3) - #494
Open
lordinatrice wants to merge 8 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Cette PR étend le parcours candidat / groupement pour permettre au mandataire de composer le groupement (ajout/retrait de co‑traitants), de résoudre la raison sociale via API Entreprise, puis de confirmer la composition et déclencher l’envoi des invitations par email.
Changes:
- Ajout de 2 nouvelles étapes au wizard groupement :
grouping_compositionetgrouping_composition_confirmation(+ endpoints Turbo pour ajouter/retirer des membres). - Ajout de la résolution SIRET → raison sociale (
FetchCompanyName) et persistance dansGroupingMember#company_name. - Envoi d’invitations (token + email) et page publique de consultation d’invitation.
Reviewed changes
Copilot reviewed 44 out of 44 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| spec/requests/candidate/grouping_wizard_spec.rb | Ajoute la couverture request du wizard (composition, ajout/retrait Turbo, confirmation). |
| spec/requests/candidate/grouping_invitations_spec.rb | Couvre l’accès à une invitation via token (200/404). |
| spec/organizers/fetch_company_name_spec.rb | Teste l’organizer FetchCompanyName (succès/échec/credentials manquants). |
| spec/models/market_application_spec.rb | Ajoute la logique de step requis grouping_composition côté modèle. |
| spec/models/grouping_member_spec.rb | Ajoute la couverture de validation SIRET et du flag invitation_sent?. |
| spec/mailers/previews/grouping_invitation_mailer_preview.rb | Ajoute un preview pour l’email d’invitation. |
| spec/mailers/grouping_invitation_mailer_spec.rb | Ajoute la spec du mailer d’invitation (to/from/contenu). |
| spec/interactors/fetch_company_name/make_request_spec.rb | Teste l’interactor HTTP de récupération des données entreprise. |
| spec/interactors/fetch_company_name/extract_name_spec.rb | Teste l’extraction de raison_sociale et la gestion JSON invalide. |
| spec/interactors/candidate/remove_grouping_member_spec.rb | Teste la suppression d’un co‑traitant (selon statut invitation / appartenance). |
| spec/interactors/candidate/confirm_grouping_composition_spec.rb | Teste génération token + envoi email + cas déjà invité + cas sans co‑traitant. |
| spec/interactors/candidate/add_grouping_member_spec.rb | Teste validations (SIRET/email) + stockage company_name + gestion erreurs API. |
| features/step_definitions/grouping_composition_steps.rb | Ajoute les steps Cucumber du parcours de composition. |
| features/step_definitions/candidacy_mode_steps.rb | Ajoute un step d’assertion de navigation vers la composition. |
| features/grouping_legal_type.feature | Met à jour le scénario pour rediriger vers la composition. |
| features/grouping_composition.feature | Ajoute la feature Cucumber du parcours complet (JS) de composition & invitations. |
| db/schema.rb | Ajoute la colonne company_name sur grouping_members (schema principal). |
| db/queue_schema.rb | Ajoute la colonne company_name sur grouping_members (queue schema). |
| db/migrate/20260804154855_add_company_name_to_grouping_members.rb | Migration d’ajout de company_name à grouping_members. |
| config/routes.rb | Ajoute routes invitation publique + endpoints members (POST/DELETE) du wizard. |
| config/locales/fr.yml | Ajoute traductions UI wizard + validations + mailer invitation. |
| app/views/grouping_invitation_mailer/invitation.text.erb | Template texte de l’email d’invitation. |
| app/views/grouping_invitation_mailer/invitation.html.erb | Template HTML de l’email (ViewComponent). |
| app/views/candidate/grouping_wizard/grouping_composition.html.erb | Nouvelle vue étape composition. |
| app/views/candidate/grouping_wizard/grouping_composition_confirmation.html.erb | Nouvelle vue récap + confirmation/envoi invitations. |
| app/views/candidate/grouping_wizard/_members_table.html.erb | Partial table des membres (statuts, suppression Turbo). |
| app/views/candidate/grouping_wizard/_member_form.html.erb | Partial formulaire ajout co‑traitant (Turbo + Stimulus). |
| app/views/candidate/grouping_wizard/_composition_actions.html.erb | Actions bas de page (back/continue avec aria-disabled). |
| app/views/candidate/grouping_invitations/show.html.erb | Vue “invitation en cours de traitement”. |
| app/organizers/fetch_company_name.rb | Nouvel organizer FetchCompanyName. |
| app/models/market_application.rb | Ajoute grouping_composition_choice_required? et intégration au wizard. |
| app/models/grouping_member.rb | Ajoute company_name, validation unicité SIRET par groupement, invitation_sent?. |
| app/mailers/grouping_invitation_mailer.rb | Nouveau mailer d’invitation co‑traitant. |
| app/javascript/controllers/enable_on_fill_controller.js | Nouveau controller Stimulus pour activer le bouton quand champs remplis. |
| app/interactors/fetch_company_name/make_request.rb | Interactor pour requête API Entreprise (endpoint + credentials check). |
| app/interactors/fetch_company_name/extract_name.rb | Interactor pour parser JSON et extraire raison_sociale. |
| app/interactors/candidate/remove_grouping_member.rb | Interactor suppression co‑traitant (bloque si déjà invité). |
| app/interactors/candidate/confirm_grouping_composition.rb | Interactor confirmation: token + deliver_later invitation. |
| app/interactors/candidate/add_grouping_member.rb | Interactor ajout co‑traitant (validations + fetch company_name + erreurs). |
| app/controllers/candidate/grouping_wizard_controller.rb | Étend le wizard: show/confirm + endpoints Turbo create/destroy member. |
| app/controllers/candidate/grouping_invitations_controller.rb | Contrôleur public d’affichage d’invitation via token. |
| app/components/grouping_invitation_email_component.rb | Nouveau composant email d’invitation (logo inline). |
| app/components/grouping_invitation_email_component.html.erb | Template HTML email invitation (layout mail). |
| app/assets/stylesheets/application.css | Styles pour l’UI de composition (actions, formulaire, table). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| fill_in I18n.t('candidate.grouping_compositions.email_label'), with: email | ||
| find_button(I18n.t('candidate.grouping_compositions.add_button'), disabled: false).click | ||
|
|
||
| within('#grouping_members_table') { page.has_content?(siret) } || page.has_css?('.fr-error-text') |
lordinatrice
force-pushed
the
feature/fas-573-groupement-composition-invitations
branch
from
August 11, 2026 14:40
615e9d3 to
f388c10
Compare
lordinatrice
force-pushed
the
feature/fas-572-wicked-groupement-wizard
branch
from
August 13, 2026 13:59
478ef21 to
6200111
Compare
…cked Remplace les 2 controllers par un unique Candidate::GroupingWizardController basé sur Wicked (même pattern que MarketApplicationsController), où Précédent/Continuer naviguent toujours d'un cran réel dans une séquence figée plutôt que de recalculer la destination à chaque clic. Centralise la cascade de résolution "prochaine étape requise" dans MarketApplication#next_required_wizard_step, utilisée par sessions_controller, ApplicationModeGuard et l'API éditeur (api/v1/market_applications_controller) pour éviter les divergences entre ces 3 points d'entrée.
Vérifie qu'une reconnexion via magic link pendant le funnel groupement d'une candidature mixte ramène bien sur l'étape en attente côté groupement, plutôt que de perdre ce funnel au profit de la candidature solo.
…n mixte - update_application_mode redirige désormais vers l'étape courante si le mode est déjà choisi, au lieu d'accepter un PATCH qui écrasait le mode (et orphelinait le Grouping existant) sans passer par le garde-fou GET. - sign_in_candidate propage désormais le user au groupement counterpart d'une candidature mixte, pas seulement à l'application solo signée. Sans ça, groupement_counterpart (filtré par user_id) ne retrouvait plus le counterpart après une connexion différée, cassant la redirection du wizard pour ce candidat.
lordinatrice
force-pushed
the
feature/fas-572-wicked-groupement-wizard
branch
from
August 13, 2026 15:39
6200111 to
d026168
Compare
Ajoute company_name (résolue via API Entreprise à l'ajout d'un co-traitant), la validation d'unicité du SIRET dans un groupement, le rejet du SIRET du mandataire pour un co-traitant, et invitation_sent? pour distinguer les co-traitants déjà invités.
lordinatrice
force-pushed
the
feature/fas-573-groupement-composition-invitations
branch
from
August 13, 2026 15:49
f388c10 to
62e42be
Compare
…API Entreprise Interroge l'API Entreprise (SIRENE) pour résoudre la raison sociale d'un co-traitant à partir de son SIRET, afin de l'afficher dans le tableau de composition du groupement sans que le mandataire ait à la saisir. Remplace FetchBuyerName, qui faisait le même appel mais n'avait aucun appelant applicatif (FetchPublicMarketBuyerNameJob utilise le pipeline Insee, pas cet organizer).
Étend GroupingWizardController avec le step grouping_composition et les sous-routes Turbo Stream create_member/destroy_member. Le mandataire ajoute un co-traitant par SIRET+email (résolution automatique de la raison sociale, retrait possible tant que l'invitation n'a pas été envoyée).
…nvoyées Ajoute le step grouping_composition_confirmation : récapitulatif du groupement, confirmation qui déclenche l'envoi d'un email d'invitation à chaque co-traitant (GroupingInvitationMailer). Ajoute la route placeholder de consultation de l'invitation par le co-traitant (grouping_invitations#show), le contenu de la page viendra dans un ticket dédié.
Couvre l'ajout/retrait de co-traitant, les erreurs de validation (SIRET invalide, déjà présent, propre SIRET du mandataire, email invalide) et la confirmation avec envoi des invitations.
lordinatrice
force-pushed
the
feature/fas-573-groupement-composition-invitations
branch
from
August 14, 2026 13:08
62e42be to
ab5fbab
Compare
lordinatrice
force-pushed
the
feature/fas-572-wicked-groupement-wizard
branch
3 times, most recently
from
August 18, 2026 13:36
cf4e442 to
21c2921
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Résumé
GroupingMemberpour porter la composition du groupement (co-traitants, statuts d'invitation).FetchRaisonSociale).Candidate::AddGroupingMember,Candidate::RemoveGroupingMember).Candidate::ConfirmGroupingComposition,GroupingInvitationMailer).Test plan
bundle exec rspec— suite complète vertebundle exec cucumber features/grouping_composition.feature— tout passebin/rubocop— aucun problème