[ERP-78] Refonte taxonomie Catégories : type unique CLIENT + Category.code + RG-1.03/1.29 par code #42

Merged
malio merged 7 commits from feature/ERP-78-refonte-taxonomie-categories into develop 2026-06-02 08:00:43 +00:00
Owner

Refonte de la taxonomie Catégories (décision produit 01/06) : le modèle est inversé.

Modèle

  • UN SEUL category_type : CLIENT. Distributeur / Courtier / Secteur / Autre (+ catégories métier) deviennent des Category rattachées à CLIENT.
  • Filtrage métier sur un code stable porté par Category (NOT NULL, unique partiel uq_category_code), slug MAJUSCULE auto-généré du nom (CategoryCodeGenerator), figé à la création, exposé en lecture seule.

Contenu

  • M0 : Category.code (entité + migration corrective Version20260602100000 au namespace racine + COMMENT ON COLUMN + catalogue + ligne test-db-setup). Retrofit Version20260528120000 rendu conscient des colonnes.
  • Seed : type unique CLIENT, catégories codées (Distributeur→DISTRIBUTEUR, etc.), anciens types supprimés. Fixtures CategoryType/Category/Client alignées.
  • RG-1.03 : ClientProcessor::hasCategoryCode — un distributor/broker doit porter la Category de code DISTRIBUTEUR/COURTIER. Filtre liste/export categoryTypecategoryCode.
  • RG-1.29 : ClientAddress::validateCategoryCodes — denylist des codes DISTRIBUTEUR/COURTIER sur une adresse (toute autre catégorie autorisée).
  • Specs M0/M1 (back + front) amendées.

Tests

make php-cs-fixer-allow-risky OK ; make db-reset OK (type unique CLIENT + 11 catégories codées, idempotent) ; make test 443 vert. Ajouts : RG-1.03 courtier, génération/unicité/lecture-seule du code (CategoryCodeTest).

Coordination

  • #76 (#500) : RG-1.29 réécrite ici sur le nouveau modèle ; #76 ne garde que le gap 2 (mapping CHECK adresse → 422), indépendant de la taxonomie.
  • ERP-68 (#486) : fixtures démo (déjà mergées via #41) adaptées ici au type unique CLIENT + codes.
  • Front #480–483 : selects Catégorie / distributeur / courtier basés sur le code (?categoryCode=), plus le type.

Décisions actées avec le PO : code NOT NULL auto-généré (slug) ; périmètre complet (réécriture RG + fixtures déjà mergées).

Refonte de la taxonomie Catégories (décision produit 01/06) : le modèle est inversé. ## Modèle - **UN SEUL `category_type` : CLIENT**. `Distributeur` / `Courtier` / `Secteur` / `Autre` (+ catégories métier) deviennent des `Category` rattachées à CLIENT. - Filtrage métier sur un **`code` stable porté par `Category`** (NOT NULL, unique partiel `uq_category_code`), slug MAJUSCULE auto-généré du nom (`CategoryCodeGenerator`), figé à la création, exposé en **lecture seule**. ## Contenu - **M0** : `Category.code` (entité + migration corrective `Version20260602100000` au namespace racine + `COMMENT ON COLUMN` + catalogue + ligne `test-db-setup`). Retrofit `Version20260528120000` rendu conscient des colonnes. - **Seed** : type unique CLIENT, catégories codées (`Distributeur→DISTRIBUTEUR`, etc.), anciens types supprimés. Fixtures `CategoryType`/`Category`/`Client` alignées. - **RG-1.03** : `ClientProcessor::hasCategoryCode` — un distributor/broker doit porter la `Category` de code `DISTRIBUTEUR`/`COURTIER`. Filtre liste/export `categoryType` → `categoryCode`. - **RG-1.29** : `ClientAddress::validateCategoryCodes` — denylist des codes `DISTRIBUTEUR`/`COURTIER` sur une adresse (toute autre catégorie autorisée). - **Specs** M0/M1 (back + front) amendées. ## Tests `make php-cs-fixer-allow-risky` OK ; `make db-reset` OK (type unique CLIENT + 11 catégories codées, idempotent) ; `make test` **443 vert**. Ajouts : RG-1.03 courtier, génération/unicité/lecture-seule du code (`CategoryCodeTest`). ## Coordination - #76 (#500) : RG-1.29 réécrite ici sur le nouveau modèle ; #76 ne garde que le gap 2 (mapping CHECK adresse → 422), indépendant de la taxonomie. - ERP-68 (#486) : fixtures démo (déjà mergées via #41) adaptées ici au type unique CLIENT + codes. - Front #480–483 : selects Catégorie / distributeur / courtier basés sur le `code` (`?categoryCode=`), plus le type. Décisions actées avec le PO : `code` NOT NULL auto-généré (slug) ; périmètre complet (réécriture RG + fixtures déjà mergées).
matthieu added the type/featbackdbM0-CategorieM1-Client labels 2026-06-02 07:21:34 +00:00
matthieu added 5 commits 2026-06-02 07:21:34 +00:00
Nouvelle colonne Category.code (NOT NULL, unique partiel uq_category_code),
slug MAJUSCULE du nom genere par CategoryCodeGenerator et fige a la creation,
expose en lecture seule. CategoryInterface::getCode() ajoute au contrat Shared.
Retrofit COMMENT (Version20260528120000) rendu conscient des colonnes pour
tolerer l'ajout de code au catalogue.
Migration corrective Version20260602100000 (namespace racine) : ajoute
Category.code, cree le type unique CLIENT, reporte Distributeur/Courtier/
Secteur/Autre en Category codees sous CLIENT, supprime les anciens types.
Fixtures alignees (type unique CLIENT, categories codees). Index partiel
uq_category_code recree dans test-db-setup.
ClientProcessor::hasCategoryCode (ex hasCategoryType) verifie le code de la
Category (DISTRIBUTEUR/COURTIER) et non plus le type. Filtre liste/export
renomme categoryType -> categoryCode (filtre sur category.code). Tests RG-1.03
distributor + courtier ajoutes ; factory de test adaptee au type unique CLIENT.
ClientAddress::validateCategoryCodes interdit desormais les Category de code
DISTRIBUTEUR/COURTIER sur une adresse (denylist), toute autre categorie etant
autorisee. Fixtures clients alignees (tiers distributeur/courtier via Category
de code dedie).
docs : amend M0/M1 specs for category taxonomy refonte (ERP-78)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Failing after 28m47s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
5b16fd9928
Spec M1 § 3.3 (type unique CLIENT + Category.code), RG-1.03 (filtre par code),
RG-1.29 (interdiction par code), spec-front (selects par code) et note
d'evolution dans la spec M0.
Author
Owner

Review

Aucun bug bloquant. PR coherente et mergeable. Regles ABSOLUES n°1 (couplage inter-modules via CategoryInterface::getCode(), pas d'import de la classe concrete Category) et n°12 (COMMENT ON COLUMN sur category.code dans la migration ET ColumnCommentsCatalog) respectees. Suites Catalog + Commercial au vert.

2 points mineurs (non bloquants) :

1. Divergence de slug entre le backfill SQL de la migration et le slugger applicatif sur les noms accentues. Le backfill REGEXP_REPLACE(name, '[^A-Za-z0-9]+', '_', 'g') produit IND_PENDANT la ou l'AsciiSlugger translittere en INDEPENDANT. Sans impact en flux normal (table category vide en prod ; purger Doctrine en dev/test ; les 4 categories systeme de l'etape 4 ont des codes hardcodes sans slug), mais casse l'idempotence de CategoryFixtures (lookup par code) lors d'un down + up sur une base dev deja peuplee.

Backfill :

$this->addSql(<<<'SQL'
UPDATE category
SET code = LEFT(UPPER(REGEXP_REPLACE(name, '[^A-Za-z0-9]+', '_', 'g')), 50)
WHERE code IS NULL
SQL);

Slugger applicatif (reference) :

public function slugify(string $name): string
{
$slug = $this->slugger->slug($name, '_')->upper()->toString();

2. Suivi front (hors perimetre de cette PR back-only). Le CRUD admin Categorie expose encore un select categoryType a une seule option (CLIENT), et le <MalioSelectCheckbox> Categorie de l'onglet Adresse n'exclut pas encore les codes DISTRIBUTEUR / COURTIER. A traiter dans un ticket dedie (cree separement).

### Review Aucun bug bloquant. PR coherente et mergeable. Regles ABSOLUES n°1 (couplage inter-modules via `CategoryInterface::getCode()`, pas d'import de la classe concrete `Category`) et n°12 (`COMMENT ON COLUMN` sur `category.code` dans la migration ET `ColumnCommentsCatalog`) respectees. Suites Catalog + Commercial au vert. 2 points mineurs (non bloquants) : **1. Divergence de slug entre le backfill SQL de la migration et le slugger applicatif sur les noms accentues.** Le backfill `REGEXP_REPLACE(name, '[^A-Za-z0-9]+', '_', 'g')` produit `IND_PENDANT` la ou l'`AsciiSlugger` translittere en `INDEPENDANT`. Sans impact en flux normal (table `category` vide en prod ; purger Doctrine en dev/test ; les 4 categories systeme de l'etape 4 ont des codes hardcodes sans slug), mais casse l'idempotence de `CategoryFixtures` (lookup par `code`) lors d'un `down` + `up` sur une base dev deja peuplee. Backfill : https://gitea.malio.fr/MALIO-DEV/Starseed/src/commit/5b16fd9928484c5f28dc4eecc68448ad9c860ade/migrations/Version20260602100000.php#L108-L112 Slugger applicatif (reference) : https://gitea.malio.fr/MALIO-DEV/Starseed/src/commit/5b16fd9928484c5f28dc4eecc68448ad9c860ade/src/Module/Catalog/Application/Service/CategoryCodeGenerator.php#L44-L47 **2. Suivi front (hors perimetre de cette PR back-only).** Le CRUD admin Categorie expose encore un select `categoryType` a une seule option (`CLIENT`), et le `<MalioSelectCheckbox>` Categorie de l'onglet Adresse n'exclut pas encore les codes `DISTRIBUTEUR` / `COURTIER`. A traiter dans un ticket dedie (cree separement).
matthieu added 1 commit 2026-06-02 07:51:02 +00:00
fix(catalog) : align SQL backfill slug with CategoryCodeGenerator (ERP-78)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Has been cancelled
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
f3c6db28dc
Le backfill de code de la migration Version20260602100000 utilisait un slug
SQL (REGEXP_REPLACE) qui ne translitterait pas les accents : « Independant »
produisait IND_PENDANT la ou le generateur applicatif (AsciiSlugger) produit
INDEPENDANT. Le code categorie, cle censee etre deterministe entre
environnements, divergeait selon le chemin (SQL migration vs PHP runtime).

- CategoryCodeSql : source unique de l'expression SQL de slug, miroir fidele
  de CategoryCodeGenerator::slugify (translate() des accents Latin-1, trim _,
  fallback CATEGORY).
- Migration : etapes 3 et 5 du backfill branchees sur ce helper.
- CategoryCodeSqlSlugTest : garde-fou verrouillant l'egalite SQL = PHP sur le
  domaine accentue, pour empecher toute future derive (cause racine du bug).
matthieu added 1 commit 2026-06-02 07:51:36 +00:00
docs(commercial) : align spec-back on categoryCode filter (ERP-78)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m57s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m11s
8a1ebdc390
Author
Owner

Suivi review — point #1 traite (commit f3c6db2).

La divergence de slug SQL vs applicatif est corrigee : le backfill de Version20260602100000 utilise desormais CategoryCodeSql::slugExpression(), miroir fidele de CategoryCodeGenerator::slugify (translitteration des accents Latin-1). « Independant » produit INDEPENDANT cote SQL comme cote PHP.

Un garde-fou CategoryCodeSqlSlugTest verrouille l'egalite SQL = PHP sur le domaine accentue pour empecher toute derive future (la cause racine du bug). Verifie : suites Catalog + Commercial vertes, make db-reset OK, codes en base coherents.

Point #2 (adaptation front catalog/adresse) suivi hors de cette PR back-only.

**Suivi review — point #1 traite (commit f3c6db2).** La divergence de slug SQL vs applicatif est corrigee : le backfill de `Version20260602100000` utilise desormais `CategoryCodeSql::slugExpression()`, miroir fidele de `CategoryCodeGenerator::slugify` (translitteration des accents Latin-1). « Independant » produit `INDEPENDANT` cote SQL comme cote PHP. Un garde-fou `CategoryCodeSqlSlugTest` verrouille l'egalite SQL = PHP sur le domaine accentue pour empecher toute derive future (la cause racine du bug). Verifie : suites Catalog + Commercial vertes, `make db-reset` OK, codes en base coherents. Point #2 (adaptation front catalog/adresse) suivi hors de cette PR back-only.
malio merged commit 00bd02858c into develop 2026-06-02 08:00:43 +00:00
malio deleted branch feature/ERP-78-refonte-taxonomie-categories 2026-06-02 08:00:43 +00:00
Sign in to join this conversation.