92a2d4f763
Recree le CategoryType FOURNISSEUR (unifie sur CLIENT par ERP-78) et implemente un vrai filtre ?typeCode= sur GET /api/categories (inexistant en prod). - CategoryProvider lit ?typeCode= depuis les filtres (meme pattern que includeDeleted) et le passe au repository ; naltere pas ?pagination=false. - DoctrineCategoryRepository::createListQueryBuilder joint le CategoryType et filtre sur son code (compatible Paginator ORM fetchJoinCollection). - Migration racine Version20260605120000 : seed du type FOURNISSEUR en ON CONFLICT + 5 categories de demo (Negociant, Cooperative, Producteur, Grossiste, Importateur) en NOT EXISTS. Aucune colonne creee. - CategoryTypeFixtures / CategoryFixtures etendus a FOURNISSEUR (idempotent, survit a make db-reset). - Test CategoryTypeCodeFilterTest : filtre exclusif, compat pagination Hydra, code inexistant -> liste vide.
103 lines
4.4 KiB
PHP
103 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace DoctrineMigrations;
|
|
|
|
use Doctrine\DBAL\Schema\Schema;
|
|
use Doctrine\Migrations\AbstractMigration;
|
|
|
|
/**
|
|
* ERP-84 — Taxonomie FOURNISSEUR (module Catalog, prerequis M2).
|
|
*
|
|
* Contexte : ERP-78 (Version20260602100000) a unifie la taxonomie sur un type
|
|
* unique CLIENT. Le M2 (fournisseurs) a besoin d'une taxonomie distincte : les
|
|
* categories clients (Agro-alimentaire...) ne sont pas valides pour un
|
|
* fournisseur (Negociant, Cooperative...). Decision Matthieu (02/06) : types
|
|
* distincts CLIENT / FOURNISSEUR (PRESTA a venir), chacun avec sa taxonomie.
|
|
*
|
|
* Cette migration :
|
|
* 1. recree le `category_type` FOURNISSEUR (code FOURNISSEUR, label « Fournisseur ») ;
|
|
* 2. seede quelques `Category` de demonstration rattachees a ce type.
|
|
*
|
|
* Aucune colonne creee/modifiee -> pas de `COMMENT ON COLUMN` (regle ABSOLUE n°12).
|
|
*
|
|
* Namespace racine `DoctrineMigrations` (regle ABSOLUE n°11) et NON modulaire
|
|
* Catalog : avec plusieurs migrations_paths, Doctrine Migrations 3.x trie par
|
|
* FQCN alphabetique -> une migration `App\Module\Catalog\...` passerait avant les
|
|
* `DoctrineMigrations\...` sur base vide, donc avant la creation de la table
|
|
* `category_type`. Le namespace racine garantit l'ordre par timestamp.
|
|
*
|
|
* Idempotence : `INSERT ... ON CONFLICT (code) DO NOTHING` pour le type,
|
|
* `INSERT ... SELECT ... WHERE NOT EXISTS` pour chaque categorie (aligne sur le
|
|
* pattern ERP-78 etape 4). En prod la table `category` est vide (aucune fixture
|
|
* metier). En dev/test, le purger Doctrine vide `category`/`category_type` avant
|
|
* les fixtures qui reproduisent le meme etat final (CategoryTypeFixtures /
|
|
* CategoryFixtures etendus a FOURNISSEUR).
|
|
*/
|
|
final class Version20260605120000 extends AbstractMigration
|
|
{
|
|
/**
|
|
* Categories de demonstration du type FOURNISSEUR : nom => code stable. Le
|
|
* code est la cle metier (slug MAJUSCULE du nom, miroir du
|
|
* CategoryCodeGenerator) et reste unique parmi les actifs (uq_category_code,
|
|
* partage avec les codes CLIENT — aucune collision ici).
|
|
*/
|
|
private const array SUPPLIER_CATEGORIES = [
|
|
'Négociant' => 'NEGOCIANT',
|
|
'Coopérative' => 'COOPERATIVE',
|
|
'Producteur' => 'PRODUCTEUR',
|
|
'Grossiste' => 'GROSSISTE',
|
|
'Importateur' => 'IMPORTATEUR',
|
|
];
|
|
|
|
public function getDescription(): string
|
|
{
|
|
return 'ERP-84 : recree le CategoryType FOURNISSEUR + seed des categories fournisseurs (Negociant, Cooperative...).';
|
|
}
|
|
|
|
public function up(Schema $schema): void
|
|
{
|
|
// 1. Type FOURNISSEUR (idempotent via l'index unique uq_category_type_code).
|
|
$this->addSql(<<<'SQL'
|
|
INSERT INTO category_type (code, label) VALUES ('FOURNISSEUR', 'Fournisseur')
|
|
ON CONFLICT (code) DO NOTHING
|
|
SQL);
|
|
|
|
// 2. Categories de demonstration sous FOURNISSEUR (si le code est libre
|
|
// parmi les actifs). created_at/updated_at NOT NULL -> NOW() ; le blame
|
|
// reste null (seed hors contexte HTTP, libelle « Systeme » cote front).
|
|
foreach (self::SUPPLIER_CATEGORIES as $name => $code) {
|
|
$this->addSql(<<<'SQL'
|
|
INSERT INTO category (name, code, category_type_id, created_at, updated_at)
|
|
SELECT :name, :code, ct.id, NOW(), NOW()
|
|
FROM category_type ct
|
|
WHERE ct.code = 'FOURNISSEUR'
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM category c WHERE c.code = :code AND c.deleted_at IS NULL
|
|
)
|
|
SQL, ['name' => $name, 'code' => $code]);
|
|
}
|
|
}
|
|
|
|
public function down(Schema $schema): void
|
|
{
|
|
// Best-effort : on retire d'abord les categories seedees (par code), puis
|
|
// le type s'il n'est plus reference (guard NOT EXISTS sur la FK RESTRICT).
|
|
$this->addSql(
|
|
'DELETE FROM category WHERE code IN (:codes) '
|
|
."AND category_type_id = (SELECT id FROM category_type WHERE code = 'FOURNISSEUR')",
|
|
['codes' => array_values(self::SUPPLIER_CATEGORIES)],
|
|
['codes' => \Doctrine\DBAL\ArrayParameterType::STRING],
|
|
);
|
|
|
|
$this->addSql(<<<'SQL'
|
|
DELETE FROM category_type
|
|
WHERE code = 'FOURNISSEUR'
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM category c WHERE c.category_type_id = category_type.id
|
|
)
|
|
SQL);
|
|
}
|
|
}
|