test(commercial) : cover RG-1.01..1.29 except role-gated (M1)
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# Cahier de test back — M1 Répertoire clients (ticket ERP-60 / #478)
|
||||
|
||||
Mapping **toutes les RG (§ 7) → test(s) PHPUnit**, à jour après ERP-60.
|
||||
|
||||
Légende source : `ERP-55` `ERP-56` `ERP-57` `ERP-58` = tests écrits par les wagons
|
||||
précédents ; **`ERP-60`** = tests ajoutés par ce ticket (stratégie « combler les
|
||||
trous, zéro duplication »).
|
||||
|
||||
## Stratégie
|
||||
|
||||
ERP-60 n'écrit QUE les tests des RG non déjà couvertes par la stack, et mappe ici
|
||||
l'intégralité des RG (existantes + nouvelles + déléguées). Les tests dépendants
|
||||
des **rôles métier** (matrice RBAC bureau/compta/commerciale/usine + RG-1.04
|
||||
fonctionnel) sont **délégués à ERP-74 (#493)** : ces rôles n'existent qu'après le
|
||||
merge de la stack.
|
||||
|
||||
## Mapping RG → test
|
||||
|
||||
| RG | Intitulé | Test(s) | Source |
|
||||
|----|----------|---------|--------|
|
||||
| RG-1.01 | Prénom OU nom obligatoire → 422 | `ClientApiTest::testPostWithoutFirstOrLastNameReturns422` ; `ClientProcessorTest` (unit) | ERP-55 |
|
||||
| RG-1.02 | phoneSecondary persisté ; max 2 téléphones | `ClientFormulaireMainTest::testPostPersistsSecondaryPhoneNormalized` ; `::testThirdPhoneFieldIsIgnored` | **ERP-60** |
|
||||
| RG-1.03 | distributor/broker exclusifs + type catégorie | `ClientApiTest::testPostWithDistributorAndBrokerReturns422` ; `::testPostDistributorReferencingNonDistributorReturns422` ; `::testPostValidDistributorReturns201` ; `ClientProcessorTest` (unit) | ERP-55 |
|
||||
| RG-1.04 | Onglet Information obligatoire pour rôle Commerciale | `ClientProcessorTest::testCommercialeIncompleteInformationIsUnprocessable` ; `::testNonCommercialeSkipsInformationCompleteness` (unit, dormant). **Test fonctionnel + durcissement → ERP-74** | ERP-55 / **ERP-74** |
|
||||
| RG-1.05 | Contact : prénom OU nom → 422 (CHECK) | `ClientSubResourceApiTest::testPostContactWithoutNameReturns422` | ERP-57 |
|
||||
| RG-1.06/07/08 | Adresse prospect exclusive de livraison/facturation (CHECK) | `ClientAddressTest::testProspectAddressCannotBeDelivery` ; `::testProspectAddressCannotBeBilling` | **ERP-60** |
|
||||
| RG-1.09 | Code postal `^[0-9]{4,5}$` → 422 | `ClientSubResourceApiTest::testPostAddressWithInvalidPostalCodeReturns422` | ERP-57 |
|
||||
| RG-1.10 | ≥ 1 site sur adresse → 422 | `ClientSubResourceApiTest::testPostAddressWithoutSiteReturns422` | ERP-57 |
|
||||
| RG-1.11 | billingEmail obligatoire ssi isBilling (CHECK) | `ClientAddressTest::testBillingAddressRequiresBillingEmail` ; `::testNonBillingAddressRejectsBillingEmail` | **ERP-60** |
|
||||
| RG-1.12 | Virement → banque obligatoire → 422 | `ClientProcessorTest::testVirementWithoutBankIsUnprocessable` ; `::testVirementWithBankPasses` (unit) | ERP-55 |
|
||||
| RG-1.13 | LCR → ≥ 1 RIB ; DELETE dernier RIB en LCR → 409 | `ClientProcessorTest::testLcrWithoutRibIsUnprocessable` / `::testLcrWithRibPasses` (unit) ; `ClientSubResourceApiTest::testDeleteLastRibUnderLcrReturns409` / `::testDeleteRibNonLcrReturns204` | ERP-55 / ERP-57 |
|
||||
| RG-1.14 | ≥ 1 bloc Contact pour finaliser l'onglet | **Front-driven (pas de state machine back).** Back voisin : `ClientSubResourceApiTest::testDeleteLastContactReturns409` | ERP-57 |
|
||||
| RG-1.15 | ~~Unicité SIREN~~ supprimée (Q4) — SIREN partageable | `ClientUniquenessTest::testDuplicateSirenIsAllowed` ; `ClientMigrationTest::testNoSirenOrEmailUniqueIndex` | **ERP-60** |
|
||||
| RG-1.16 | companyName unique (case-insensitive) parmi actifs → 409 | `ClientApiTest::testPostDuplicateCompanyNameReturns409` ; `ClientMigrationTest::testCompanyNameActivePartialIndexExistsExactlyOnce` | ERP-55 / **ERP-60** |
|
||||
| RG-1.17 | ~~Unicité email~~ supprimée (Q4) — email partageable | `ClientUniquenessTest::testDuplicateEmailIsAllowed` ; `ClientMigrationTest::testNoSirenOrEmailUniqueIndex` | **ERP-60** |
|
||||
| RG-1.18 | companyName upper-cased serveur | `ClientApiTest::testPostNormalizesTextFields` ; `ClientFieldNormalizerTest::testCompanyNameIsUppercased` (unit) | ERP-55 |
|
||||
| RG-1.19 | firstName/lastName capitalize serveur | `ClientApiTest::testPostNormalizesTextFields` ; `ClientFieldNormalizerTest::testPersonNameIsTitleCased` (unit) ; `ClientSubResourceApiTest::testPostContactNormalizesFields` | ERP-55 / ERP-57 |
|
||||
| RG-1.20 | Téléphones chiffres-seuls serveur | `ClientApiTest::testPostNormalizesTextFields` ; `ClientFieldNormalizerTest::testPhoneKeepsOnlyDigits` (unit) ; `ClientFormulaireMainTest::testPostPersistsSecondaryPhoneNormalized` (secondary) | ERP-55 / **ERP-60** |
|
||||
| RG-1.21 | email lowercase serveur | `ClientApiTest::testPostNormalizesTextFields` ; `ClientFieldNormalizerTest::testEmailIsLowercased` (unit) ; `ClientSubResourceApiTest::testPostContactNormalizesFields` / `::testPostAddressNormalizesBillingEmail` | ERP-55 / ERP-57 |
|
||||
| RG-1.22 | Archive : permission `archive` + archivedAt + aucun autre champ | `ClientApiTest::testPatchArchiveSetsArchivedAtThenRestore` ; `::testPatchArchiveWithOtherFieldReturns422` ; `ClientProcessorTest` (unit, gating archive) | ERP-55 |
|
||||
| RG-1.23 | Restauration : archivedAt=null ; **409 si conflit d'unicité** | `ClientApiTest::testPatchArchiveSetsArchivedAtThenRestore` (cas nominal) ; **`ClientArchiveTest::testRestoreConflictReturns409`** (409 restauration, gap P1) | ERP-55 / **ERP-60** |
|
||||
| RG-1.24 | Liste exclut les archivés par défaut | `ClientApiTest::testListSortedByCompanyNameAscAndExcludesArchived` | ERP-55 |
|
||||
| RG-1.25 | `?includeArchived=true` inclut les archivés | `ClientApiTest::testListIncludeArchivedReturnsArchived` | ERP-55 |
|
||||
| RG-1.26 | Tri par défaut companyName ASC | `ClientApiTest::testListSortedByCompanyNameAscAndExcludesArchived` | ERP-55 |
|
||||
| RG-1.27 | Timestampable/Blamable : created* figés, updated* mis à jour | `ClientAuditTest::testCreatedFrozenAndUpdatedByReflectsModifier` | **ERP-60** |
|
||||
| RG-1.28 | PATCH multi-groupes sans permission → 403 strict (tout le payload) | `ClientProcessorTest::testStrictMixWithAccountingFieldIsForbidden` / `::testAccountingFieldWithoutPermissionIsForbidden` (unit) ; **`ClientPatchStrictTest::testMixedGroupsPatchWithoutAccountingPermissionIsForbidden`** (fonctionnel) | ERP-55 / **ERP-60** |
|
||||
| RG-1.29 | Catégorie d'adresse limitée aux types SECTEUR/AUTRE | **Filtrage LECTURE = front-driven** (SearchFilter `GET /api/categories?categoryType.code[]=…`). **Validation ÉCRITURE (POST/PATPH catégorie DISTRIBUTEUR/COURTIER → 422) NON IMPLÉMENTÉE côté back au M1** (absente du `ClientAddressProcessor` et de la liste § 8.1). → voir « Gaps & suivi » | — (gap) |
|
||||
|
||||
## Couvertures transverses
|
||||
|
||||
| Sujet | Test(s) | Source |
|
||||
|-------|---------|--------|
|
||||
| Audit iban/bic présents dans le diff (pas d'`#[AuditIgnore]`) | `ClientAuditTest::testRibCreateAuditIncludesIbanAndBic` | **ERP-60** |
|
||||
| Sécurité générique : 401 anonyme + 403 sans `commercial.clients.view` | `ClientSecurityTest` (collection + détail) ; `ClientExportControllerTest::testForbiddenWithoutClientsViewPermission` / `::testUnauthorizedWhenAnonymous` | **ERP-60** / ERP-58 |
|
||||
| Migration : index partiel unique présent (1 seul), pas de siren/email unique | `ClientMigrationTest` | **ERP-60** |
|
||||
| Référentiels comptables read-only (405 écriture, 401/403) | `ReferentialApiTest` | ERP-56 |
|
||||
| Export XLSX (colonnes accounting selon permission, 401/403) | `ClientExportControllerTest` | ERP-58 |
|
||||
|
||||
## Délégué à ERP-74 (#493) — NE PAS faire dans ERP-60
|
||||
|
||||
- **Matrice RBAC différenciée** par rôle métier (Bureau / Compta / Commerciale /
|
||||
Usine) : 200/403 par verbe et par onglet selon le rôle.
|
||||
- **RG-1.04 fonctionnel** : PATCH onglet Information par une Commerciale avec
|
||||
champs incomplets → 422 ; même PATCH par Admin → 200 (+ durcissement code/spec).
|
||||
- Raison : ces rôles métier ne sont seedés qu'après le merge de la stack M1.
|
||||
|
||||
## Gaps & suivi
|
||||
|
||||
- **RG-1.29 (validation écriture)** : refuser une catégorie de type
|
||||
`DISTRIBUTEUR`/`COURTIER` sur une `ClientAddress` (→ 422, violation
|
||||
`categories`) n'est pas implémenté au M1. La spec § 8.1 ne le liste pas comme
|
||||
cas de test back ; le filtrage de lecture est front-driven. **Suggestion** :
|
||||
ouvrir un follow-up (durcissement `ClientAddressProcessor`) ou l'intégrer à
|
||||
ERP-74. Aucune invention de feature dans ERP-60 (ticket test-only).
|
||||
- **Violations CHECK → statut HTTP** : les CHECK d'adresse (RG-1.06/07/08/11)
|
||||
sont aujourd'hui rejetées par la base (statut ≥ 400) mais sans mapping fin
|
||||
vers 422 (pas d'`exception_to_status` ni de listener DBAL→HTTP). Les tests
|
||||
ERP-60 assertent donc le **rejet** (≥ 400). Un mapping explicite vers 422
|
||||
serait une amélioration UX d'API (follow-up possible).
|
||||
Reference in New Issue
Block a user