feat(commercial) : export XLSX fournisseurs (SupplierExportController, SIREN gaté accounting.view) (ERP-91)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m3s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m7s

Export XLSX du répertoire fournisseurs (spec § 4.6), jumeau de l'export client M1.

- SupplierExportController avec #[Route(priority: 1)] (anti-conflit API Platform {id}),
  is_granted('commercial.suppliers.view'). Mêmes filtres que la liste
  (includeArchived/archivedOnly/search/categoryCode/siteId) via createListQueryBuilder()
  partagé avec le SupplierProvider ; non archivés par défaut.
- Colonnes : Nom, Contact principal (SupplierContact de plus petit position — ERP-106),
  Tél principal/secondaire, Email, Catégories (CSV), Sites (CSV), SIREN (omis sans
  accounting.view), Date de création.
- hydrateContacts() ajouté au repository (chargement batché des contacts en une requête
  IN, anti-N+1) — méthode dédiée à l'export, la liste paginée n'embarque pas les contacts.
- Tables supplier* ajoutées à ColumnCommentsCatalog : leurs COMMENT (posés par la
  migration ERP-85) étaient dropés par le schema:update --force du test-db-setup et non
  restaurés, cassant ColumnsHaveSqlCommentTest dès un re-setup de la base de test.
- Test fonctionnel SupplierExportControllerTest (9 cas).
This commit is contained in:
Matthieu
2026-06-05 14:56:50 +02:00
parent 58cbfe4437
commit c6a0a51810
5 changed files with 729 additions and 0 deletions
@@ -102,6 +102,31 @@ class DoctrineSupplierRepository extends ServiceEntityRepository implements Supp
;
}
public function hydrateContacts(array $suppliers): void
{
$ids = [];
foreach ($suppliers as $supplier) {
$id = $supplier->getId();
if (null !== $id) {
$ids[] = $id;
}
}
if ([] === $ids) {
return;
}
// Une seule requete IN bornee : remplit la collection `contacts` des MEMES
// instances Supplier (identity map). Tri par position pour que le « contact
// principal » (plus petit position) soit deterministe a l'export (§ 4.6).
$this->createQueryBuilder('s')
->leftJoin('s.contacts', 'sc')->addSelect('sc')
->where('s.id IN (:ids)')->setParameter('ids', $ids)
->orderBy('sc.position', 'ASC')
->getQuery()
->getResult()
;
}
/**
* Recherche fuzzy insensible a la casse sur companyName ET sur les contacts
* lies (firstName / lastName / email) — decision D1, refonte-contact (§ 4.1).