Compare commits
base: MALIO-DEV/Starseed:027e80cc4b7e6543a713db5eadd5b9ebc610c6f0
MALIO-DEV/Starseed:develop
MALIO-DEV/Starseed:feature/ERP-61-sidebar-i18n-clients
MALIO-DEV/Starseed:feat/admin-tables-filter-pagination
MALIO-DEV/Starseed:main
MALIO-DEV/Starseed:v0.1.63
MALIO-DEV/Starseed:v0.1.62
MALIO-DEV/Starseed:v0.1.61
MALIO-DEV/Starseed:v0.1.60
MALIO-DEV/Starseed:v0.1.59
MALIO-DEV/Starseed:v0.1.58
MALIO-DEV/Starseed:v0.1.57
MALIO-DEV/Starseed:v0.1.56
MALIO-DEV/Starseed:v0.1.55
MALIO-DEV/Starseed:v0.1.54
MALIO-DEV/Starseed:v0.1.53
MALIO-DEV/Starseed:v0.1.52
MALIO-DEV/Starseed:v0.1.51
MALIO-DEV/Starseed:v0.1.50
MALIO-DEV/Starseed:v0.1.49
MALIO-DEV/Starseed:v0.1.48
MALIO-DEV/Starseed:v0.1.47
MALIO-DEV/Starseed:v0.1.46
MALIO-DEV/Starseed:v0.1.45
MALIO-DEV/Starseed:v0.1.44
MALIO-DEV/Starseed:v0.1.43
MALIO-DEV/Starseed:v0.1.42
MALIO-DEV/Starseed:v0.1.41
MALIO-DEV/Starseed:v0.1.40
MALIO-DEV/Starseed:v0.1.39
MALIO-DEV/Starseed:v0.1.38
MALIO-DEV/Starseed:v0.1.37
MALIO-DEV/Starseed:v0.1.36
MALIO-DEV/Starseed:v0.1.35
MALIO-DEV/Starseed:v0.1.34
MALIO-DEV/Starseed:v0.1.33
MALIO-DEV/Starseed:v0.1.32
MALIO-DEV/Starseed:v0.1.31
MALIO-DEV/Starseed:v0.1.30
MALIO-DEV/Starseed:v0.1.29
MALIO-DEV/Starseed:v0.1.28
MALIO-DEV/Starseed:v0.1.27
MALIO-DEV/Starseed:v0.1.26
MALIO-DEV/Starseed:v0.1.25
MALIO-DEV/Starseed:v0.1.24
MALIO-DEV/Starseed:v0.1.23
MALIO-DEV/Starseed:v0.1.22
MALIO-DEV/Starseed:v0.1.21
MALIO-DEV/Starseed:v0.1.20
MALIO-DEV/Starseed:v0.1.19
MALIO-DEV/Starseed:v0.1.18
MALIO-DEV/Starseed:v0.1.17
MALIO-DEV/Starseed:v0.1.16
MALIO-DEV/Starseed:v0.1.15
MALIO-DEV/Starseed:v0.1.14
MALIO-DEV/Starseed:v0.1.13
MALIO-DEV/Starseed:v0.1.12
MALIO-DEV/Starseed:v0.1.11
MALIO-DEV/Starseed:v0.1.10
MALIO-DEV/Starseed:v0.1.9
MALIO-DEV/Starseed:v0.1.8
MALIO-DEV/Starseed:v0.1.7
MALIO-DEV/Starseed:v0.1.6
MALIO-DEV/Starseed:v0.1.5
MALIO-DEV/Starseed:v0.1.4
MALIO-DEV/Starseed:v0.1.3
MALIO-DEV/Starseed:v0.1.2
MALIO-DEV/Starseed:v0.1.1
MALIO-DEV/Starseed:v0.1.0
..
compare: MALIO-DEV/Starseed:a048be1cf7b4c4a95bcc8caaeded8d4778dd27e5
MALIO-DEV/Starseed:feature/ERP-61-sidebar-i18n-clients
MALIO-DEV/Starseed:develop
MALIO-DEV/Starseed:feat/admin-tables-filter-pagination
MALIO-DEV/Starseed:main
MALIO-DEV/Starseed:v0.1.63
MALIO-DEV/Starseed:v0.1.62
MALIO-DEV/Starseed:v0.1.61
MALIO-DEV/Starseed:v0.1.60
MALIO-DEV/Starseed:v0.1.59
MALIO-DEV/Starseed:v0.1.58
MALIO-DEV/Starseed:v0.1.57
MALIO-DEV/Starseed:v0.1.56
MALIO-DEV/Starseed:v0.1.55
MALIO-DEV/Starseed:v0.1.54
MALIO-DEV/Starseed:v0.1.53
MALIO-DEV/Starseed:v0.1.52
MALIO-DEV/Starseed:v0.1.51
MALIO-DEV/Starseed:v0.1.50
MALIO-DEV/Starseed:v0.1.49
MALIO-DEV/Starseed:v0.1.48
MALIO-DEV/Starseed:v0.1.47
MALIO-DEV/Starseed:v0.1.46
MALIO-DEV/Starseed:v0.1.45
MALIO-DEV/Starseed:v0.1.44
MALIO-DEV/Starseed:v0.1.43
MALIO-DEV/Starseed:v0.1.42
MALIO-DEV/Starseed:v0.1.41
MALIO-DEV/Starseed:v0.1.40
MALIO-DEV/Starseed:v0.1.39
MALIO-DEV/Starseed:v0.1.38
MALIO-DEV/Starseed:v0.1.37
MALIO-DEV/Starseed:v0.1.36
MALIO-DEV/Starseed:v0.1.35
MALIO-DEV/Starseed:v0.1.34
MALIO-DEV/Starseed:v0.1.33
MALIO-DEV/Starseed:v0.1.32
MALIO-DEV/Starseed:v0.1.31
MALIO-DEV/Starseed:v0.1.30
MALIO-DEV/Starseed:v0.1.29
MALIO-DEV/Starseed:v0.1.28
MALIO-DEV/Starseed:v0.1.27
MALIO-DEV/Starseed:v0.1.26
MALIO-DEV/Starseed:v0.1.25
MALIO-DEV/Starseed:v0.1.24
MALIO-DEV/Starseed:v0.1.23
MALIO-DEV/Starseed:v0.1.22
MALIO-DEV/Starseed:v0.1.21
MALIO-DEV/Starseed:v0.1.20
MALIO-DEV/Starseed:v0.1.19
MALIO-DEV/Starseed:v0.1.18
MALIO-DEV/Starseed:v0.1.17
MALIO-DEV/Starseed:v0.1.16
MALIO-DEV/Starseed:v0.1.15
MALIO-DEV/Starseed:v0.1.14
MALIO-DEV/Starseed:v0.1.13
MALIO-DEV/Starseed:v0.1.12
MALIO-DEV/Starseed:v0.1.11
MALIO-DEV/Starseed:v0.1.10
MALIO-DEV/Starseed:v0.1.9
MALIO-DEV/Starseed:v0.1.8
MALIO-DEV/Starseed:v0.1.7
MALIO-DEV/Starseed:v0.1.6
MALIO-DEV/Starseed:v0.1.5
MALIO-DEV/Starseed:v0.1.4
MALIO-DEV/Starseed:v0.1.3
MALIO-DEV/Starseed:v0.1.2
MALIO-DEV/Starseed:v0.1.1
MALIO-DEV/Starseed:v0.1.0
11 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a048be1cf7 | test(commercial) : cover RG-1.01..1.29 except role-gated (M1) | ||
|
|
710dd97cc2 | feat(commercial) : add clients XLSX export endpoint | ||
|
|
bd25a6ff3e | feat(shared) : add reusable XLSX spreadsheet exporter | ||
|
|
59bd21592e |
feat(commercial) : add client sub-resources processors (contacts/addresses/ribs)
Expose les sous-ressources Contacts / Adresses / RIB du repertoire clients
(M1, spec § 4.5) :
- 3 Processors dedies (ClientContactProcessor, ClientAddressProcessor,
ClientRibProcessor) : normalisation serveur reutilisant ClientFieldNormalizer
(RG-1.19 capitalize, RG-1.20 telephones chiffres, RG-1.21 emails/billingEmail
lowercase) + regles metier.
- Operations API Platform :
- POST /api/clients/{id}/contacts|addresses, PATCH/DELETE /api/client_contacts|addresses/{id}
(security commercial.clients.manage)
- POST /api/clients/{id}/ribs, PATCH/DELETE /api/client_ribs/{id}
(security commercial.clients.accounting.manage)
- GET item par sous-ressource (lecture unitaire) ; pas de GET collection
autonome (lecture via le parent, non concernee par la pagination ERP-72).
- Regles de gestion :
- RG-1.13 : DELETE du dernier RIB d'un client en reglement LCR -> 409.
- RG-1.14 : DELETE du dernier contact d'un client -> 409 (completude front au M1).
- RG-1.05 : prenom OU nom du contact obligatoire -> 422.
- Validations deja portees par l'entite et desormais exercees : Assert\Count(min:1)
sur ClientAddress.sites (RG-1.10), Assert\Regex code postal (RG-1.09),
Assert\Iban / Assert\Bic sur ClientRib.
- SiteReferenceDenormalizer : resout les IRIs /api/sites vers SiteInterface
(meme pattern que CategoryReferenceDenormalizer, sans import cross-module).
- Ajout de symfony/intl, requis par Assert\Bic.
Tests : ClientSubResourceApiTest (13 cas) couvrant CRUD, normalisation,
RG-1.13/1.14, gating 403 sur client_ribs sans accounting.manage. Suite back
complete au vert (383 tests).
|
||
|
|
d581f4a901 |
feat(commercial) : expose accounting referentials read-only API
Expose TvaMode, PaymentDelay, PaymentType et Bank en lecture seule (GetCollection + Get), security commercial.clients.view au niveau operations + ressource. Aucune ecriture declaree -> POST/PATCH/DELETE renvoient 405. Tri par defaut position ASC puis label ASC (spec M1 § 4.7). Pagination serveur conservee (ERP-72) avec paginationClientEnabled pour activer l'echappatoire ?pagination=false (alimenter un select sans pagination). Endpoints : GET /api/tva_modes, /api/payment_delays, /api/payment_types, /api/banks. Tests fonctionnels : 200 + seed, tri position/label, 405 ecritures, 403 sans permission, 401 anonyme, pagination toggle. |
||
|
|
488ed4c94b | fix(commercial) : flatten clients route | ||
|
|
f6505c94d8 |
feat(commercial) : declare commercial.clients permissions + sync RBAC mirrors
Ajoute CommercialModule::permissions() (5 codes commercial.clients.* : view, manage, accounting.view, accounting.manage, archive) — alignes sur les is_granted deja references par ERP-55 (Client ApiResource, ClientProcessor, ClientReadGroupContextBuilder). Synchronise les 3 sources RBAC (regle ABSOLUE n8) : item sidebar "Repertoire clients" (commercial.clients.view), persona user-full dans personas.ts et SeedE2ECommand.php, cle i18n sidebar.commercial.clients. Les roles metier Bureau/Compta/Commerciale/Usine sont seedes par ERP-74 : les 5 permissions sont mappees ici sur le seul persona technique user-full en attendant, sans creer de nouveau persona (regle n7). |
||
|
|
4ddfc0943b | fix(commercial) : robust gating + strict category denormalizer + provider via EM (review ERP-55) | ||
|
|
1b3e3ea499 |
feat(commercial) : add Client API Platform provider + processor + business rules
Branche l'API REST du repertoire clients (M1) sur l'entite Client preparee en ERP-54. Operations GetCollection / Get / Post / Patch (pas de Delete au M1 : l'archivage passe par PATCH isArchived). ClientProvider : - liste paginee (Paginator ORM, aligne sur la convention ERP-72) + echappatoire ?pagination=false - exclut archives + soft-deletes par defaut (RG-1.24), ?includeArchived=true reintegre les archives (RG-1.25) - tri companyName ASC (RG-1.26), filtres ?search (fuzzy companyName/lastName/ email) et ?categoryType=<code> - detail : 404 sur soft-delete, embarque contacts/adresses/ribs ClientProcessor : - normalisation serveur via ClientFieldNormalizer (RG-1.18 a 1.21) - 409 sur doublon de nom de societe (RG-1.16) ; 409 dedie sur conflit de restauration (RG-1.23) - gating par onglet : champ comptable -> accounting.manage, isArchived -> archive, mode strict 403 sur tout le payload (RG-1.28) ; archivage exclusif (RG-1.22) + pose/retrait archivedAt - regles metier RG-1.01 (prenom/nom), RG-1.03 (distributor/broker exclusifs + controle du type de categorie), RG-1.12 (Virement -> banque), RG-1.13 (LCR -> >= 1 RIB), RG-1.04 (completude Information pour le role Commerciale) Lecture comptable conditionnelle : ClientReadGroupContextBuilder ajoute le groupe client:read:accounting selon commercial.clients.accounting.view. Resolution des references categorie : CategoryReferenceDenormalizer resout les IRI vers Category quand la propriete est type-hintee par le contrat CategoryInterface (denormalisation impossible sur une interface sinon). Contrats Shared : - CategoryInterface::getCategoryTypeCode() (implemente par Category) pour la verification de type sans import inter-modules - BusinessRoleAwareInterface (implemente par User) + BusinessRoles::COMMERCIALE pour detecter le role metier ; le code de role sera seede par ERP-74 et reutilise par ERP-59/60. RG-1.04 reste dormante tant qu'aucun user ne porte ce role. Coordination stack : - chaines de permission commercial.clients.* referencees ici, declarees en ERP-59 (tests RBAC complets en ERP-60) - config globale de pagination (itemsPerPage client, max 50) portee par ERP-72 - referentiels comptables (PaymentType/Bank/...) exposes en ERP-56 Tests : 31 tests Commercial (integration admin sur les regles metier + unitaires sur le gating, RG-1.04/1.12/1.13 et le context builder). Suite complete verte (339 tests). |
||
|
|
b495e4030a |
[ERP-54] Créer les entités Client + sous-entités + référentiels (#29)
Auto Tag Develop / tag (push) Failing after 28s
## Contexte Ticket Lesstime **#54** (1.1 / Backend / M) — spec `docs/specs/M1-clients/spec-back.md` § 3.4 / § 3.5. > 🔗 **MR stackée sur ERP-53** — cible `feature/ERP-53-migrer-tables-client-m1`, **pas** `develop`. À repointer vers `develop` quand ERP-53 sera mergé (cf. `STACK-BRANCHES-PROCEDURE.md`). Le diff ne montre que les fichiers d'ERP-54. ## Contenu **9 entités** (`src/Module/Commercial/Domain/Entity/`) : - Métier : `Client`, `ClientContact`, `ClientAddress`, `ClientRib` — `#[Auditable]` + Timestampable/Blamable. - Référentiels statiques lecture seule : `TvaMode`, `PaymentDelay`, `PaymentType`, `Bank` — whitelistés dans `EntitiesAreTimestampableBlamableTest::EXCLUDED`. **8 repositories** interfaces (`Domain/Repository/`) + impl Doctrine (`Infrastructure/Doctrine/`). > La spec § 3.5 ne définit que 8 entités (4 métier + 4 référentiels) ; pas de 9ᵉ entité malgré la formulation « 9 paires » du ticket. ## Décisions - **Aucun `#[ApiResource]` dans ce ticket** : le bloc ApiResource du `Client` (§ 3.4) référence `ClientProvider`/`ClientProcessor` = périmètre **ERP-55**. L'inclure casserait `cache:clear`/`make test`/`schema:validate`. Les entités sont des entités Doctrine pures (ORM + Assert + Groups). Endpoints lecture seule des référentiels → ticket dédié. - **Q4** : `Client` sans `#[ORM\UniqueConstraint]` — unicité du nom de société portée par l'index partiel Postgres `uq_client_company_name_active` (inexprimable en attribut ORM). - **Audit RIB (29/05)** : aucun `#[AuditIgnore]` sur `ClientRib.iban`/`bic` (tous champs audités, audit admin-only). - **Cross-module (règle n°1)** : M2M `Category` via le contrat `Shared\Domain\Contract\CategoryInterface` + `resolve_target_entities` (pas d'import direct Catalog→Commercial) ; `ClientAddress.sites` via `SiteInterface` existant. ## Infra nécessaire (découvert pendant le dev) - `doctrine.yaml` : mapping ORM du module `Commercial` (mappings explicites par module) + résolution `CategoryInterface → Category`. - `CommercialReferentialFixtures` **créée** (n'existait pas — ERP-53 avait seedé les CategoryType côté Catalog) : re-seed idempotent des 4 référentiels, sinon vidés au `db-reset` (désormais tables mappées). - `ColumnCommentsCatalog` étendu (colonnes M1) pour le chemin `schema:update`/test — sinon `ColumnsHaveSqlCommentTest` (garde-fou n°12) échoue. - Migration retrofit `Version20260528120000` (ERP-67) rendue résiliente (`$schema->hasTable()`) : elle rejouait tout le catalogue mais s'exécute avant la création des tables M1 → `relation tva_mode does not exist`. Conforme à son docblock (« les futures migrations posent leurs propres COMMENT »). - `makefile test-db-setup` : recréation de l'index partiel `uq_client_company_name_active` (analogue de la ligne existante pour `category`). ## Vérifications - `make php-cs-fixer-allow-risky` ✓ - `make db-reset` ✓ (bout en bout ; 4 référentiels + 4 CategoryType présents, 2 index partiels créés) - `make test` ✓ **312/312** (Architecture vert, 0 régression M0) - `doctrine:schema:validate` : Mapping **OK** ; « not in sync » = bruit cosmétique pré-existant du projet (clear COMMENT hors-ORM, drop index partiels, renommages d'index). Seul diff introduit : renommage cosmétique de l'index M2M `idx_client_category_category` (même colonne) — aucun écart de type/colonne/FK vs migration ERP-53. --------- Co-authored-by: admin malio <malio@yuno.malio.fr> Co-authored-by: Matthieu <contact@malio.fr> Co-authored-by: Matthieu <mtholot19@gmail.com> Reviewed-on: #29 Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> |
||
|
|
56cf492dcc |
[ERP-53] Migrer les tables Client + sous-collections + référentiels comptables (#27)
Auto Tag Develop / tag (push) Failing after 20s
## Contexte Ticket Lesstime : **#53** (ERP-53) — premier ticket back du M1 (Répertoire clients). Spec back : `docs/specs/M1-clients/spec-back.md` § 3.2 + § 3.3. ## Implémentation - Migration Doctrine `migrations/Version20260601000000.php` (12 tables) + fixture `CategoryTypeFixtures`. - **4 référentiels comptables** seedés : `tva_mode` (3), `payment_delay` (3), `payment_type` (4), `bank` (3). - **Table `client`** : 31 colonnes (formulaire + Information + Comptabilité + archive + soft-delete + Timestampable/Blamable). - **4 sous-collections** : `client_category` (M2M), `client_contact`, `client_address`, `client_rib` + **3 jointures** d'adresse (`client_address_site`, `client_address_contact`, `client_address_category`). - **4 CHECK** : mutex distributor/broker, contact name, address prospect exclusif, billing email conditionnel. - **1 index partiel unique** : `uq_client_company_name_active` sur `LOWER(company_name) WHERE is_archived=false AND deleted_at IS NULL` (décision Q4 — **pas** d'unicité siren/email). - **Seed `category_type`** : DISTRIBUTEUR / COURTIER / SECTEUR / AUTRE (`ON CONFLICT (code) DO NOTHING` en migration pour la prod, + fixture idempotente pour dev/test purgés). - `COMMENT ON COLUMN` sur **chaque** colonne (convention ERP-67, garde-fou vert). ## RG couvertes (niveau BDD) RG-1.03 (mutex distrib/broker), RG-1.05 (contact name), RG-1.06/07/08 (adresse prospect exclusif), RG-1.11 (billing email), RG-1.16 (unicité company_name — RG-1.15/1.17 supprimées par Q4), RG-1.22 (is_archived + archived_at). ## Écarts assumés vs spec (cf. docblock migration + cahier de test du ticket) 1. **Namespace `migrations/` racine** au lieu de `App\Module\Commercial\…` : vérifié empiriquement que Doctrine 3.9.6 (AlphabeticalComparator → strcmp FQCN) trierait le namespace Commercial **avant** `DoctrineMigrations` → migration client exécutée avant user/category/site → échec FK sur base vide. Le namespace racine garantit l'ordre par timestamp. 2. **DDL aligné Doctrine** : `INT GENERATED BY DEFAULT AS IDENTITY` + `TIMESTAMP(0) WITHOUT TIME ZONE` (et non SERIAL/TIMESTAMPTZ) → forward-compatible avec les entités du ticket 1.1 (schema:update no-op). 3. **Seed `category_type (code, label)` sans `position`** : la table M0 n'a pas de colonne `position` (coquille du pseudo-SQL § 3.3). > **Note ERP-54** : à l'arrivée des entités Client*, `schema:update` droppera leurs COMMENT + l'index partiel. Prévoir l'ajout au `ColumnCommentsCatalog` + recréation de l'index dans `test-db-setup` (pattern `uq_category_name_type_active`). ## Tests - `make php-cs-fixer-allow-risky` ✓ - `make db-reset` ✓ + vérifications psql manuelles (8 cas : CHECK, unicité partielle, archivage, siren/email dupliqués, seeds) - `make test` ✓ — **312 tests OK, 0 régression** --------- Co-authored-by: Matthieu <contact@malio.fr> Co-authored-by: Matthieu <mtholot19@gmail.com> Reviewed-on: #27 Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> |