---
suivi: 1180
date: 2026-08-04
sujet: Commercial — bouton + Nouveau partenaire (agence) à la volée
chantier: commercialisation
type: feature
statut: poussé
hash: ebfa4605
fichiers:
  - database/migrations/2026_08_04_120000_create_fournisseur_creations_commercial_table.php
  - app/Models/FournisseurCreationCommercial.php
  - app/Models/Fournisseur.php
  - app/Support/Commercial/FournisseurPartenaireCommercialService.php
  - app/Http/Controllers/FournisseurController.php
  - routes/web.php
  - resources/js/Components/Commercialisation/NouveauPartenaireModal.vue
  - resources/js/Components/Commercialisation/LotsGrillePanel.vue
  - resources/js/Pages/Programmes/Acquereur/Show.vue
  - tests/Unit/FournisseurPartenaireCommercial1180Test.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - public/build/
  - docs/suivi/SUIVI_1180_nouveau_partenaire_volee.md
---

## PROMPT ENVOYÉ

SUIVI #1180 — bouton + Nouveau partenaire sur réservation, contrôle doublon
serveur non contournable, traçabilité origine hors colonne Sage, permission
dédiée, cohabitation saisie libre #1174.

## SYNTHÈSE

### Fiches lues
- `SUIVI_1156` — recherche serveur `/fournisseurs/search`, notaire pas partenaire.
- `SUIVI_1174` — saisie libre agence + exclusion mutuelle FK ↔ texte.
- `SUIVI_1154` / `#1121` — pas de catégorie/rôle fournisseurs ; 3985 actifs.

### OBJET 1 — Doublon serveur
`FournisseurPartenaireCommercialService::trouverCandidats` : nom via
`FournisseurDoublonDetector::normalizeNom` (casse/accents/ponctuation) + SIRET
exact normalisé. `store` refuse si candidats sans `force_apres_doublons=true`
(re-contrôle serveur à chaque POST). UI : vérifier → voir candidats →
sélectionner OU confirmer création.

### OBJET 2 — Traçabilité (retenu)
Aucune colonne `origine`/`source` sur `fournisseurs` (table sync Intacct).
**Mécanisme** : table `fournisseur_creations_commercial`
(`fournisseur_id`, `user_id`, `source=reservation_form`, `reservation_id?`,
`created_at`). Innocuité Sage : pas de `dirty_sage`, pas d’`intacct_id`, aucun
appel `creerFournisseur` / push.

### OBJET 3 — Création minimale + Intacct
Création locale : `nom`, `siret` optionnel (max 14 chiffres), `statut=actif`.
Sans IBAN/SIRET : **ne part pas vers Intacct** (pas d’id Sage, dirty=0). La
demande Intacct classique reste le chemin pour un vendeur Sage. SIRET > 14 →
erreur visible (anti SQLSTATE 22001 du 31/07).

### OBJET 4 — Saisie libre #1174
Bouton uniquement si case libre décochée. Après création : FK renseignée, texte
vidé. **19 résas texte seul** : pas de reprise auto (data-fix fournisseurs).

### OBJET 5 — Permission
Pas de `fournisseurs.creer`. **Retenu** : `demandes_fournisseurs.ecriture`
(existe déjà, GS_ENVOL). Contrôle serveur via `AssertsFeaturePermission` (pas
`$this->authorize()`). Pas `acquereurs.ecriture` seul.

### Mapping UI
| Libellé | Posté | DB | Back |
|---------|-------|-----|------|
| Agence recherche | `agence_fournisseur_id` | FK | fournisseurs |
| + Nouveau partenaire | modal → create | + log | service #1180 |
| Saisie libre | toggle client | `agence_nom` | #1174 |

## DÉPLOIEMENT-TEST

1. `git pull` ; `migrate --force` ; `optimize:clear` ; `view:clear` ; `journal:sync`
2. Tests 1–11 du prompt (doublon, force, endpoint direct, SIRET, libre, permission)
3. KPI remises ; cohérence 0

## LEÇON

Créer dans un référentiel sync Sage sans garde-fou produit des doublons
comptables. Contrôle doublon serveur + log d’origine hors table sync + pas de
`dirty_sage` sur création partielle.
