feat(commercial) : catégories de type Adresse pour les blocs adresse (client + fournisseur) (#147)
Auto Tag Develop / tag (push) Successful in 12s

## Objectif

Introduit un `CategoryType` dédié **ADRESSE** (module Catalog) consommé par le champ « Catégorie » des blocs adresse, en remplacement de la réutilisation détournée des types CLIENT / FOURNISSEUR.

## Changements

**Backend**
- Migration de seed du type ADRESSE + 6 catégories : Siège, Contact issues, Facturation, Livraison, Approvisionnement, Méthaniseur (idempotente, réversible) ; fixtures alignées.
- `ClientAddress` : validation blacklist (DISTRIBUTEUR/COURTIER) remplacée par une whitelist « catégories de type ADRESSE uniquement ».
- `SupplierAddress` : type requis FOURNISSEUR → ADRESSE (le bloc principal fournisseur reste en FOURNISSEUR).

**Frontend**
- Ref dédiée `addressCategories` (`?typeCode=ADRESSE`) dans les composables référentiels client et fournisseur.
- Pages new/edit client et fournisseur câblées sur les blocs adresse.

**Tests**
- `CategoryAdresseSeedTest` (miroir du test PRESTATAIRE).
- Adaptation des tests d'adresse client/fournisseur (sémantique whitelist ADRESSE) + helper `createAddressCategory()`.

## Vérifications
- Back : suites Catalog + Architecture + adresse/fournisseur vertes (le flake JWT connu du hook est sans rapport, tests verts en isolation).
- Front : Vitest vert (composables référentiels + ciblés).
- php-cs-fixer : 0 correction ; eslint : OK.

Reviewed-on: #147
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #147.
This commit is contained in:
2026-06-25 07:26:21 +00:00
committed by Autin
parent 2e50a760c6
commit efded9fd40
22 changed files with 444 additions and 168 deletions
@@ -0,0 +1,110 @@
<?php
declare(strict_types=1);
namespace App\Tests\Module\Catalog\Api;
use App\Module\Catalog\Domain\Entity\CategoryType;
/**
* Tests du seed de la taxonomie ADRESSE cote API.
*
* Le multi-select « Categorie » des blocs adresse (client + fournisseur) consomme
* `GET /api/categories?typeCode=ADRESSE`. Ce test prouve que :
* - le filtre `?typeCode=ADRESSE` ne renvoie QUE les categories du type ADRESSE
* (aucune fuite de categorie d'un autre type) ;
* - chaque membre renvoye porte bien le type ADRESSE dans `categoryTypes`.
*
* NB : la base de test est purgee de toute categorie / type entre chaque test
* (cf. AbstractCatalogApiTestCase::cleanupCatalogTestData), donc le type et les
* categories ADRESSE sont materialises ici (et non lus depuis le seed de la
* migration / fixture, qui ne survit pas a la purge). On valide ainsi le contrat
* du filtre sur le code reel `ADRESSE`. La presence du seed apres un
* `make db-reset` reel est, elle, verifiee par l'idempotence des fixtures.
*
* @internal
*/
final class CategoryAdresseSeedTest extends AbstractCatalogApiTestCase
{
/**
* Categories de demonstration seedees par la migration / fixture ADRESSE.
*/
private const array ADDRESS_CATEGORIES = [
'Siège',
'Contact issues',
'Facturation',
'Livraison',
'Approvisionnement',
'Méthaniseur',
];
public function testTypeCodeAdresseReturnsOnlyAddressCategories(): void
{
$addressType = $this->getOrCreateAdresseType();
foreach (self::ADDRESS_CATEGORIES as $name) {
$this->createCategory($name, $addressType);
}
// Bruit : un type + une categorie d'un autre type ne doivent PAS fuiter.
$noiseType = $this->createCategoryType('TEST_CLIENT', 'Test Client');
$this->createCategory(self::TEST_CATEGORY_PREFIX.'noise', $noiseType);
$client = $this->createAdminClient();
$response = $client->request('GET', '/api/categories?typeCode=ADRESSE&pagination=false');
self::assertSame(200, $response->getStatusCode());
$members = $response->toArray()['member'];
$names = array_map(static fn (array $m): string => $m['name'], $members);
sort($names);
$expected = self::ADDRESS_CATEGORIES;
sort($expected);
self::assertSame(
$expected,
$names,
'Le filtre ?typeCode=ADRESSE doit ne renvoyer QUE les categories du type ADRESSE.',
);
// Chaque categorie remontee doit PORTER le type ADRESSE.
foreach ($members as $member) {
self::assertContains('ADRESSE', array_column($member['categoryTypes'], 'code'));
}
}
public function testTypeCodeAdresseKeepsHydraPagination(): void
{
$addressType = $this->getOrCreateAdresseType();
$this->createCategory('Siège', $addressType);
$client = $this->createAdminClient();
$response = $client->request('GET', '/api/categories?typeCode=ADRESSE');
self::assertSame(200, $response->getStatusCode());
$data = $response->toArray();
self::assertArrayHasKey('totalItems', $data, 'Le filtre ne doit pas casser la pagination Hydra.');
self::assertArrayHasKey('member', $data);
foreach ($data['member'] as $member) {
self::assertContains('ADRESSE', array_column($member['categoryTypes'], 'code'));
}
}
/**
* Recupere le type ADRESSE reel, ou le cree s'il est absent. Le code `ADRESSE`
* est seede par CategoryTypeFixtures (present en debut de suite), mais le
* cleanup purge tous les `category_type` entre les tests : selon l'ordre
* d'execution, le type peut donc exister ou non. Le get-or-create rend le test
* robuste sans dependre du seed ni le dupliquer.
*/
private function getOrCreateAdresseType(): CategoryType
{
$em = $this->getEm();
$existing = $em->getRepository(CategoryType::class)->findOneBy(['code' => 'ADRESSE']);
if ($existing instanceof CategoryType) {
return $existing;
}
return $this->createCategoryType('ADRESSE', 'Adresse');
}
}