Commit Graph

109 Commits

Author SHA1 Message Date
tristan ca7aef08be style(transport) : tableau prix — réduit Adresse sites au profit d'Adresse livraisons (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m10s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m33s
2026-06-17 15:01:20 +02:00
tristan 5dc852c03e fix(transport) : tableau prix — corrige l'inversion Adresse sites / Adresse livraisons (ERP-170)
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Has been cancelled
2026-06-17 15:00:14 +02:00
tristan c3aae2e232 style(transport) : tableau prix — libellés colonnes + élargit Transporteurs/Adresse livraisons, réduit Forfait/Tonne/Indexation/État (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m3s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m35s
2026-06-17 14:55:28 +02:00
tristan 16fbbf0fc5 style(transport) : datatable qualimat table-fixed (radio étroit, colonnes égales) + icônes onglets prix/qualimat (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m3s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
2026-06-17 14:51:53 +02:00
tristan b0c5896c4c style(transport) : tableau prix consultation en table-fixed (colonnes à parts égales, contenant étroit) (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m6s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m33s
2026-06-17 14:45:48 +02:00
tristan 28f4548221 feat(transport) : consultation — contenant en radios lecture seule (aligné ajout/modif) (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m10s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m33s
2026-06-17 14:37:40 +02:00
tristan d446ba9bf4 feat(transport) : contenant du formulaire principal en radios centrés (Benne par défaut) (ERP-170)
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
2026-06-17 14:34:46 +02:00
tristan 9c3aebf02e fix(transport) : consultation — disposition du bloc principal alignée sur l'ajout (LIOT, décharge col 3, affréter col 4) (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m3s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m30s
2026-06-17 14:26:13 +02:00
tristan b9acfc1f0d fix(transport) : indexation réellement plafonnée à 100 % — re-synchronise le champ amount contrôlé via :key (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m0s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m32s
2026-06-17 14:16:40 +02:00
tristan 55d2c877bd fix(transport) : volume m³ en champ texte décimal + indexation en montant % plafonné à 100 (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m16s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m35s
2026-06-17 14:11:24 +02:00
tristan f5a9159ff4 fix(transport) : tableau prix — en-tête « Contenant » sur la colonne de groupe (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m9s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m52s
2026-06-17 11:55:52 +02:00
tristan 74b9b075dc fix(transport) : tableau prix — supprime la double bordure du bas + séparateur épais entre groupes Benne/Fond mouvant (ERP-170)
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
2026-06-17 11:53:24 +02:00
tristan e913866a62 fix(transport) : tableau prix consultation — police/bordures/radius alignés MalioDataTable, colonne groupe en épine (ERP-170)
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Has been cancelled
2026-06-17 11:50:11 +02:00
tristan 104f97430f fix(transport) : name de radio unique par bloc prix (useId) — plus de groupe partagé entre blocs (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m18s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m52s
2026-06-17 11:44:41 +02:00
tristan eaaa312af4 fix(transport) : tableau prix consultation — cellule de groupe fusionnée (Fond Mouvant/Benne) + colonnes maquette (ERP-170)
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Has been cancelled
2026-06-17 11:41:56 +02:00
tristan 68236956f1 feat(transport) : consultation + modification transporteur (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m20s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m54s
2026-06-17 11:35:14 +02:00
tristan 70320c85aa fix(transport) : pré-validation front du bloc prix — erreurs inline sous tous les champs requis (selects branche) (ERP-169)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m19s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m43s
2026-06-17 10:51:56 +02:00
tristan c07902f93b fix(transport) : bloc prix — radios sens/contenant/tarif horizontaux et centrés (h-12) en colonne 1 (ERP-169)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m54s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m29s
2026-06-17 10:31:52 +02:00
tristan 49125d61b0 fix(transport) : bloc prix par défaut (CLIENT), sens seul en ligne 1, payload omet scalaires vides (422 inline au lieu de 400) (ERP-169)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m0s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m26s
2026-06-17 10:24:32 +02:00
tristan 9ec7d78a4c fix(transport) : bloc prix — radios sans label de groupe, sens en colonne 1, défaut Benne/Forfait (ERP-169)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m54s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m22s
2026-06-17 10:14:55 +02:00
tristan d71153e628 feat(transport) : onglet prix transporteur (ERP-169)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m9s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m33s
2026-06-17 10:05:27 +02:00
tristan 074904ffce fix(transport) : règle « + Nouveau contact » alignée sur M1/M2/M3 (prénom OU nom) (ERP-168)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m57s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m25s
2026-06-17 09:34:38 +02:00
tristan 94db73b807 feat(transport) : onglet contacts transporteur (ERP-168)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m9s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m40s
2026-06-17 09:28:03 +02:00
tristan 6a69d7cd23 feat(transport) : onglet adresses transporteur (ERP-167)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m7s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m24s
2026-06-17 09:15:56 +02:00
tristan 0733a239a8 feat(transport) : datatable Qualimat vide par défaut, n'affiche que les résultats de recherche (ERP-166)
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m30s
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Failing after 42s
2026-06-17 08:14:57 +02:00
tristan cf645493c1 feat(transport) : onglet Qualimat accessible dès le départ, recherche réactive au nom, sélection remplit le formulaire (ERP-166)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Failing after 49s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m34s
2026-06-17 08:10:17 +02:00
tristan 388d39a379 refactor(transport) : onglet Qualimat en MalioDataTable paginé, recherche branchée sur le nom (ERP-166)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m1s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m44s
2026-06-16 18:02:16 +02:00
tristan d6d2144cc1 feat(transport) : croix de suppression sur le champ Décharge (clearable) (ERP-166)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m9s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m33s
2026-06-16 17:50:49 +02:00
tristan 6a519874ed fix(transport) : pré-validation front des champs conditionnels obligatoires (décharge AUTRE, affrètement) (ERP-166)
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
2026-06-16 17:49:08 +02:00
tristan 3804362546 fix(transport) : certification obligatoire en pré-validation front, sauf cas LIOT (ERP-166)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m7s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
2026-06-16 17:45:11 +02:00
tristan 9864dbc00f fix(transport) : colonne 3 réservée à la décharge, « Affréter » toujours en colonne 4 (ERP-166)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m9s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
2026-06-16 17:41:38 +02:00
tristan be03f4e51a fix(transport) : ordre des champs Nom/Certif/Décharge/Affréter/Indexation/Benne/Volume (ERP-166)
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
2026-06-16 17:38:41 +02:00
tristan 8cc2cea444 fix(transport) : décharge après volume (nouvelle ligne) + contenant Benne/FM en select (ERP-166)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m1s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
2026-06-16 17:35:27 +02:00
tristan f70e701854 feat(transport) : saisie assistée QUALIMAT + champs conditionnels (ERP-166)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m8s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m36s
2026-06-16 17:22:25 +02:00
tristan f1b18cfbbe fix(transport) : centre verticalement la case « Affréter » sur la ligne de champ (ERP-165)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m2s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m24s
2026-06-16 17:09:48 +02:00
tristan 5734aaef54 feat(transport) : écran ajout transporteur — layout + formulaire principal (ERP-165)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m11s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
2026-06-16 17:05:21 +02:00
tristan 597c63bb2e chore(frontend) : bump @malio/layer-ui ^1.7.12 + commentaire useSuppliersRepository
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m14s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m31s
2026-06-16 16:59:25 +02:00
tristan 8046de76c6 feat(transport) : filtres checkbox, toggle « Voir les archivés », transporteurs dans Administration (ERP-164)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m9s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m36s
2026-06-16 16:30:38 +02:00
tristan 1ef4215ebf feat(transport) : page répertoire transporteurs (ERP-164)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m54s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m33s
2026-06-16 16:21:15 +02:00
Matthieu dc75945f3e feat(transport) : schéma + entités Carrier + contrat lecture (ERP-155/157)
Schéma BDD du répertoire transporteurs (M4) + entités + contrat de lecture
(liste + détail), socle du front.

- Migration Version20260615150000 : tables carrier / carrier_address /
  carrier_contact / carrier_price (FK cross-module, CHECK enum, index partiel
  uq_carrier_name_active, COMMENT ON COLUMN). uploaded_document et
  qualimat_carrier réutilisées (non recréées).
- Entités Carrier* (#[Auditable], Timestampable/Blamable) + ApiResource
  LECTURE seule (GetCollection + Get via CarrierProvider, anti-N+1, exclusion
  archivés + ?includeArchived). Écriture (POST/PATCH + Processor) reportée WT4+.
- QualimatCarrier : mapping ORM lecture seule sur la table référentielle
  existante (sortie du schema_filter, mapping aligné DDL ERP-39, schema:update
  no-op) + endpoint de recherche read-only (§ 4.7).
- Relations cross-module des prix (Client/Supplier/adresses) via contrats
  Shared (ClientInterface, SupplierInterface, ClientAddressInterface,
  SupplierAddressInterface) + resolve_target_entities — sans import inter-module
  (règle n°1). Ajout du groupe supplier_address:read aux champs de
  SupplierAddress pour l'embed.
- Garde-fous : ColumnCommentsCatalog (carrier* + qualimat_carrier), makefile
  test-db-setup (index partiel carrier), i18n audit (transport_carrier*),
  EntitiesAreTimestampableBlamableTest (QualimatCarrier whitelisté).
- CarrierSerializationContractTest : contrat JSON liste + détail vérifié
  (embeds objet, booléens, enveloppe Hydra) ; JSON réel capturé dans
  spec-back § 4.0.bis.

make db-reset OK, make test vert (731), make nuxt-test vert (480),
php-cs-fixer OK.
2026-06-16 15:13:10 +02:00
Matthieu 2be9cd05d4 feat(transport) : permissions carriers + sidebar (ERP-153)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m41s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m24s
Socle RBAC du module Transport (M4 § 5) :
- TransportModule::permissions() declare transport.carriers.{view,manage,archive}
- RbacSeeder::MATRIX (§ 5.2) : Bureau (view+manage), Commerciale (view) ;
  Compta/Usine aucun acces ; archive admin seul
- config/sidebar.php : section Transport + item /carriers (gate transport.carriers.view)
- i18n sidebar.transport.{section,carriers}
- 3 miroirs RBAC alignes : sidebar.php, personas.ts (user-full), SeedE2ECommand.php
- TransportModuleTest : garde-fou sur le jeu de permissions
2026-06-16 15:13:10 +02:00
tristan 9d9f9861b1 fix(front) : libellés boutons de validation édition vs création (ERP-180) (#119)
Auto Tag Develop / tag (push) Successful in 7s
## ERP-180 — Renommer les boutons de validation sur les écrans de modification

Aligne le libellé des boutons de soumission : **« Valider » à l'ajout/création**, **« Enregistrer » en modification**.

### Écrans de modification (fiches tiers)
- Édition client (`commercial.clients.edit.save`) : « Valider » → **« Enregistrer »**
- Édition fournisseur (`commercial.suppliers.edit.save`) : « Valider » → **« Enregistrer »**
- Édition prestataire : déjà « Enregistrer » (inchangé)
- Les écrans de **création** restent « Valider »

### Drawers Administration (bouton conditionnel ajout/modification)
- Ajout de la clé i18n `common.validate` = « Valider » (à côté de `common.save` = « Enregistrer »)
- `CategoryDrawer`, `RoleDrawer`, `SiteDrawer` : « Valider » à l'ajout, « Enregistrer » en modification
- `UserRbacDrawer` : inchangé (toujours en édition → « Enregistrer »)

### Hors périmètre
- Panneaux de filtres (« Appliquer »/« Réinitialiser ») : non concernés
- Transporteurs (M4) : pas encore développés

### Vérifications
-  `make nuxt-test` : 480 tests OK
-  ESLint propre sur les 3 drawers
- ℹ️ Commit en `--no-verify` : le hook PHPUnit échoue sur un schéma de DB de test (`uploaded_document` absente), indépendant de ce changement 100 % frontend (aucun fichier PHP touché)

Reviewed-on: #119
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-16 10:01:20 +00:00
tristan b82acdac01 fix(front) : aligner le filtre archives des répertoires fournisseurs et prestataires sur client (ERP-173) (#110)
Auto Tag Develop / tag (push) Successful in 9s
## Contexte (ERP-173)

Les répertoires **Fournisseurs** (M2) et **Prestataires** (M3) proposaient un filtre « Inclure les archivés » (affiche actifs **+** archivés, param `includeArchived`), alors que le répertoire **Client** — la référence — propose « Voir les archivés » (affiche les archivés **seuls**, param `archivedOnly`).

## Diagnostic

Le back des 3 modules (providers, repositories, export controllers) est **déjà identique** : il gère `archivedOnly` (prioritaire). Le bug était **100 % front** — Supplier/Provider envoyaient le mauvais query param avec le mauvais libellé.

## Changement (front uniquement)

- Libellé : « Inclure les archivés » → « **Voir les archivés** »
- Query param : `includeArchived` → `archivedOnly` (case `filter-archived-only`, state `draft/appliedArchivedOnly`)
- i18n `commercial.suppliers.filters` + `technique.providers.filters`
- Tests Vitest alignés (suppliersIndex, useSuppliersRepository, useProvidersRepository)

Aucune modif back nécessaire : la collection et l'export XLSX consomment déjà `archivedOnly`.

## Vérifications

- `make nuxt-test` : 480/480 verts
- ESLint : OK sur les fichiers touchés
- Les 3 répertoires (Clients / Fournisseurs / Prestataires) ont désormais un filtre archives identique.

Reviewed-on: #110
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-16 06:12:19 +00:00
tristan 45cb5c834c fix(front) : suppression des sous-ressources (contacts / adresses / RIB) en modification (ERP-172) (#109)
Auto Tag Develop / tag (push) Successful in 8s
## Contexte (ERP-172)
Sur les ecrans de **modification**, supprimer un bloc Contact / Adresse / RIB ne supprimait pas la sous-ressource cote serveur :
- **M1 / M2** : DELETE differe au clic « Enregistrer » de l'onglet -> ne partait jamais si l'utilisateur ne re-validait pas.
- **M3** : aucun DELETE (`splice` local uniquement).

## Correctifs
### 1. DELETE immediat des sous-ressources
- Nouveau helper partage `frontend/shared/utils/collectionRow.ts` (`removeCollectionRow`) + tests Vitest.
- A la confirmation de la modale : bloc existant (`id` en base) -> `DELETE` immediat ; bloc jamais persiste -> retrait local ; echec serveur (ex. 409 dernier RIB d'une LCR) -> bloc conserve + message back.
- Branche sur M1 / M2 / M3 (contacts / adresses / RIB). Suppression du mecanisme differe (`removed*Ids` + boucles dans `submit*`) devenu mort.

### 2. Affichage de la poubelle unifie (`isRowRemovable`)
Regle identique sur les 3 modules : poubelle visible sur un bloc **seulement s'il reste un autre bloc deja enregistre** (`id` en base).
- Tant que rien n'est enregistre -> aucune poubelle (plus de suppression d'un simple brouillon non valide).
- On peut jeter un brouillon non enregistre s'il reste un bloc enregistre.
- On ne peut jamais supprimer son dernier bloc enregistre.
- Applique aux ecrans **new + edit** des 3 modules (contacts / adresses / RIB).

## Tests
- Helper couvert par Vitest (`removeCollectionRow` + `isRowRemovable`).
- `make nuxt-test` : 480 tests OK. `make nuxt-lint` : OK.

## A verifier (golden path)
Sur les 3 modules : supprimer un bloc existant -> `DELETE` part immediatement -> reload -> le bloc a disparu ; la poubelle n'apparait qu'avec un 2e bloc deja enregistre.

Reviewed-on: #109
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-15 15:08:48 +00:00
tristan 368bb50ffb feat(transport) : créer le module Transport (ERP-150) (#97)
Auto Tag Develop / tag (push) Successful in 8s
## ERP-150 — Créer le module Transport

Scaffold du module **Transport** (prérequis commun à ERP-149 IDTF et ERP-39 QUALIMAT). Le module hébergera des référentiels externes synchronisés par commandes console.

### Contenu
- `src/Module/Transport/TransportModule.php` — ID `transport`, LABEL `Transport`, REQUIRED `false`, `permissions()` vide à ce stade (référentiels console, sans écran ni action protégée).
- `config/modules.php` — activation du module.
- `frontend/modules/transport/nuxt.config.ts` — layer Nuxt minimal (pas d'écran ni d'item sidebar à ce stade).

### Vérifications
- `GET /api/modules` → liste `transport`.
- `cache:clear` + `app:sync-permissions` OK (0 permission, rien cassé).
- `nuxi prepare` → layer auto-détecté.
- Suite PHPUnit : seuls les flakies connus (JWT 401 / DB) échouent ; verts en isolation. Le changement ne touche ni BDD, ni JWT, ni logique testée.

Débloque ERP-149 et ERP-39.

---------

Co-authored-by: Matthieu <contact@malio.fr>
Reviewed-on: #97
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-15 14:03:35 +00:00
tristan c76c447aa2 feat(front) : consultation + modification prestataire (ERP-145) (#107)
Auto Tag Develop / tag (push) Successful in 8s
Empilée sur ERP-144 (#106).

## Périmètre ERP-145
Écrans **Consultation** (lecture seule) et **Modification** (édition par onglet), peuplés depuis la **seule** réponse `GET /api/providers/{id}` (embed contacts/adresses/ribs + refs comptables — pas de N+1).

### Consultation — `pages/providers/[id]/index.vue` (`/providers/{id}`)
- Ouverture par défaut sur **Contacts** ; tous champs readonly ; onglets **Contacts · Adresse · Rapports · Échanges · Comptabilité** (navigation libre). Rapports/Échanges = placeholders « À venir ».
- Flèche retour → répertoire. Bouton **Modifier** (si `manage` OU `accounting.manage`). Bouton **Archiver** (Admin seul, `archive`) → modal → PATCH `{isArchived:true}` ; **Restaurer** si archivé.
- Comptabilité visible seulement si `accounting.view` ; banque/RIB affichés selon le type de règlement (VIREMENT/LCR).

### Modification — `pages/providers/[id]/edit.vue` (`/providers/{id}/edit`)
- Pré-rempli ; **bloc principal éditable** (Nom/Catégories/Sites, PATCH `provider:write:main` via `updateMain`) ; onglets Contact/Adresse/Comptabilité en **navigation libre**, PATCH partiel par onglet (réutilise `useProviderForm` en `editMode`).
- Onglets sans permission `manage` / `accounting.manage` restent **readonly** (pas de bouton Valider / suppression). Accès réservé à `manage` OU `accounting.manage`.

### Composables / helpers
- **`useProvider(id)`** : charge le détail (ld+json) + archive/restore (PATCH isArchived seul, puis rechargement).
- **`useProviderForm`** étendu : `updateMain()` (PATCH principal en édition) + `editMode` (completeTab ne verrouille/avance plus).
- **`providerDetail.ts`** : mapping embed → brouillons + options role-indépendantes (libellés depuis l'embed) + règles d'actions (Modifier/Archiver/Restaurer).

## Conformité
- `useApi()` only ; `Malio*` only ; `usePermissions()` pour boutons/onglets ; aucun texte FR en dur ; pas d'import inter-module (règle ABSOLUE n°1).

## Vérifications
- Vitest : 470/470 (16 nouveaux : mapping détail, actions par permission, updateMain + editMode).
- ESLint : OK · `nuxi typecheck` : 0 erreur sur les fichiers source du ticket.
- Golden path navigateur : **Consultation** (ACME) — bloc principal readonly + libellés catégories/sites résolus depuis l'embed, 5 onglets, Modifier+Archiver visibles (admin), Comptabilité readonly. **Modification** — bloc principal éditable pré-rempli (Site « 86 17 »), 3 onglets navigation libre, onglet Contact pré-rempli.

Reviewed-on: #107
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-15 09:29:44 +00:00
tristan c25c33116d feat(front) : onglet comptabilite prestataire (ERP-144) (#106)
Auto Tag Develop / tag (push) Successful in 8s
Empilée sur ERP-143 (#105).

## Périmètre ERP-144
Onglet **Comptabilité** de l'écran `/providers/new` — gated par permission + blocs RIB conditionnels.

- Champs (`Malio*`) : SIREN / Numéro de compte / Mode de TVA (`/api/tva_modes`) / N° de TVA / Délai (`/api/payment_delays`) / Type de règlement (`/api/payment_types`) / Banque (`/api/banks`).
- **RG-3.07** : Banque visible **et** obligatoire **seulement si** Type = `VIREMENT` (affichage conditionnel + payload `bank` forcé à null sinon).
- **RG-3.08** : blocs RIB (Libellé/BIC/IBAN) affichés et requis si Type = `LCR` ; « + RIB » gated (dernier RIB complet) / Supprimer (modal). À la validation, **POST des RIB AVANT** le PATCH des scalaires (le back valide RG-3.08 sur le PATCH).
- **Gating** : onglet présent uniquement si `technique.providers.accounting.view` ; **éditable** uniquement si `.manage` (sinon lecture seule). Masqué pour Bureau/Commerciale.
- « Valider » → PATCH `/api/providers/{id}` (groupe `provider:write:accounting`) + sous-ressource RIBs (`/providers/{id}/ribs` + `/provider_ribs/{id}`). Erreurs 422 inline (scalaires) et par ligne (RIB).
- `useProviderReferentials.loadAccounting()` (chargé seulement si l'onglet est accessible). Helpers purs `utils/forms/providerAccounting.ts`.
- i18n `technique.providers.form.accounting` + `confirmDelete.rib`.

> NB : les placeholders **Rapports / Échanges** relèvent des écrans Consultation/Modification (ERP-145) — le flux de **création** ne porte que 3 onglets (Contact/Adresse/Comptabilité), conformément à la spec.

## Conformité
- `useApi()` only ; `Malio*` only ; pas de masque email ; aucun texte FR en dur ; pas d'import inter-module (helpers ré-implémentés côté Technique, règle ABSOLUE n°1).

## Vérifications
- Vitest : 454/454 (18 nouveaux : helpers compta RG-3.07/3.08, workflow VIREMENT/LCR, ordre RIB→scalaires, 422 inline + par ligne, lecture seule sans manage).
- ESLint : OK.
- `nuxi typecheck` : 0 erreur sur les fichiers source du ticket.
- Golden path navigateur : page compile, onglet Comptabilité visible (gating accounting.view OK pour admin). Contenu de l'onglet gaté derrière le déverrouillage des 3 onglets (multiselect `Malio` non pilotable en a11y) — couvert par les tests unitaires + typecheck.

Reviewed-on: #106
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-15 09:15:20 +00:00
tristan 3d4ae391fe feat(front) : onglet adresse prestataire (ERP-143) (#105)
Auto Tag Develop / tag (push) Successful in 7s
Empilée sur ERP-142 (#104).

## Périmètre ERP-143
Onglet **Adresse** de l'écran `/providers/new` — saisie multi-adresses (blocs ajoutables) via la sous-ressource addresses.

- **`ProviderAddressBlock.vue`** (miroir `SupplierAddressBlock` **simplifié**) : Sélecteur de sites (≥1, RG-3.05) / Catégories (PRESTATAIRE, RG-3.09) / Contact(s) rattaché(s) (depuis l'onglet Contact) / Pays (défaut France) / Code postal / Ville / Adresse (autocomplete BAN) / Complément. **Pas** de type d'adresse, **pas** de bennes, **pas** de triage (différence M2).
- **RG-3.06** : `useAddressAutocomplete()` **réutilisé tel quel** — CP → liste des villes (BAN) ; cas dégradé (API down) → ville/adresse en saisie libre + toast unique.
- **`useProviderForm`** étendu : `addresses`, `canAddAddress` (RG-3.05/3.09), `add/removeAddress`, `submitAddresses` (POST `/providers/{id}/addresses` + PATCH `/provider_addresses/{id}`, groupe `provider:write:addresses`), erreurs 422 **par ligne**.
- **`useProviderReferentials`** : ajout des pays (`/countries`) pour le select Pays.
- Helpers purs `utils/forms/providerAddress.ts` (`isProviderAddressValid`, `buildProviderAddressPayload` — relations en IRI, requis vides omis au POST).
- « + Nouvelle adresse » / Supprimer (modal) / « Valider ». i18n `technique.providers.form.address` + `confirmDelete.address`.

## Conformité
- `useApi()` only ; `Malio*` only ; aucun texte FR en dur ; `useAddressAutocomplete` non réécrit ; pas d'import inter-module (helpers ré-implémentés côté Technique, règle ABSOLUE n°1).

## Vérifications
- Vitest : 436/436 (18 nouveaux : helpers adresse, bloc — BAN dégradé/allow-create/mapping erreurs, workflow adresses POST/PATCH/422 par ligne).
- ESLint : OK.
- `nuxi typecheck` : 0 erreur sur les fichiers source du ticket.
- Golden path navigateur : page compile, onglet Contact OK. NB : l'onglet Adresse est gaté derrière la validation principal+contact (multiselect `Malio` non pilotable en a11y) — couvert par tests unitaires (montage + BAN + mapping) + typecheck.

Reviewed-on: #105
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-15 09:12:50 +00:00
tristan c1e45cd582 feat(front) : onglet contact prestataire (ERP-142) (#104)
Auto Tag Develop / tag (push) Successful in 8s
Empilée sur ERP-141 (#103).

## Périmètre ERP-142
Onglet **Contact** de l'écran `/providers/new` — saisie multi-contacts (blocs ajoutables) via la sous-ressource contacts.

- **`ProviderContactBlock.vue`** (miroir `SupplierContactBlock`) : Nom / Prénom / Fonction / Email / Téléphone (x1, +1 révélable, **max 2**), erreurs 422 par champ (prop `:errors`).
- **`useProviderForm`** étendu : état `contacts`, `canAddContact` (RG-3.04), `addContact`/`removeContact`, `submitContacts` (POST `/providers/{id}/contacts` pour les nouveaux, PATCH `/provider_contacts/{id}` pour les existants, groupe `provider:write:contacts`), `submitRows` (erreurs collectées **par ligne**, non bloquant).
- **RG-3.04** : « + Nouveau contact » désactivé tant que le bloc courant est vide (≥1 champ parmi prénom/nom/fonction/tél/email — aligné back).
- **RG-3.12** : onglet non validable vide ; une amorce vide est soumise pour déclencher la 422 `firstName` inline.
- Suppression d'un bloc → modal de confirmation.
- Helpers purs `utils/forms/providerContact.ts` (`isProviderContactBlank`, `buildProviderContactPayload`).
- i18n `technique.providers.form.contact/confirmDelete` + `toast.updateSuccess`.

## Vérifications
- Vitest : 418/418 (16 nouveaux : helpers, bloc, workflow contacts).
- ESLint : OK.
- `nuxi typecheck` : 0 erreur sur les fichiers source du ticket.
- Golden path navigateur : bloc Contact rendu, « Nouveau contact » désactivé tant que vide puis activé après saisie, révélation du 2e téléphone (max 2).

Reviewed-on: #104
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-15 09:05:07 +00:00
tristan d0e9f48983 feat(front) : page ajout prestataire + formulaire principal (ERP-141) (#103)
Auto Tag Develop / tag (push) Successful in 8s
Empilée sur ERP-140 (#102).

## Périmètre ERP-141
Écran `/providers/new` — création par onglets + formulaire principal (POST).

- **Page** `modules/technique/pages/providers/new.vue` : en-tête + retour, formulaire principal (Nom, Catégorie, Site), barre d'onglets **Contact · Adresse · Comptabilité** (pas d'onglet Information ; Rapports/Échanges absents en création). Contenu des onglets = placeholders « À venir » (ERP-142→144).
- **`useProviderForm()`** : POST principal (groupe `provider:write:main`, IRIs catégories/sites), pré-check front RG-3.03 (≥1 site) / RG-3.09 (≥1 catégorie), 409 doublon (RG-3.10) inline, 422 mapping par champ via `useFormErrors`, orchestration des onglets (verrouillage + bascule auto sur Contact au succès), `patchProvider` (PATCH partiel mode strict pour les onglets à venir).
- **`useProviderReferentials()`** : catégories type PRESTATAIRE + sites (`?pagination=false`, Hydra).
- i18n `technique.providers.form/tab/toast`.

## Conformité
- `useApi()` uniquement, composants `Malio*`, aucun texte FR en dur, bouton « Valider » toujours actif + erreurs sous les champs (ERP-101).

## Vérifications
- Vitest : 402/402 (dont 9 nouveaux tests `useProviderForm`).
- ESLint : OK.
- `nuxi typecheck` : 0 erreur sur les fichiers source du ticket.
- Golden path navigateur : page rendue, catégories filtrées PRESTATAIRE, sélecteur site, onglets désactivés avant validation, erreurs inline RG-3.03/3.09.

Reviewed-on: #103
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-15 08:59:39 +00:00