Files
Starseed/docs/specs/M1-clients/cahier-test-back-M1.md
T
matthieu 8fae987e15
Auto Tag Develop / tag (push) Successful in 6s
docs(commercial) : refonte contact — suppression du contact inline (specs M1 + M2) (#54)
Acte la décision refonte-contact dans les specs : le contact principal inline (firstName/lastName/phonePrimary/phoneSecondary/email) est retiré des entités tiers (Client, Supplier). Les contacts vivent uniquement dans ClientContact / SupplierContact (onglet Contacts). Garantie « >=1 contact nommé » préservée par RG-1.05/1.14 (M1) et RG-2.04/2.13 (M2).

- M1 (spec-back/spec-front/cahier) : modèle Client sans contact inline ; RG-1.01/1.02 supprimées ; D1 (recherche) / D2 (export) décrites ; version V1.
- M2 (spec-back/spec-front) : FICHIERS NOUVEAUX (non versionnés sur develop), introduits déjà corrigés (Supplier sans contact inline, RG-2.01/2.02 supprimées) ; version V0.2.
- docs/specs/M1-clients/refonte-contact/ : décision (README) + tickets (M1 back/front/specs, M2 specs) + prompts + amendement des tickets M2.

Lesstime : tâches #103 (M1 back), #104 (M1 front), #105 (M1 specs), #106 (M2 specs) ; tickets M2 #85-#97 amendés.
---------

Co-authored-by: Matthieu <contact@malio.fr>
Reviewed-on: #54
Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
2026-06-03 13:16:11 +00:00

8.6 KiB

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 (supprimée V1 — refonte-contact) contact inline retiré du Client ; complétude couverte par RG-1.05 / RG-1.14 (ClientContact) refonte-contact
RG-1.02 (supprimée du Client V1) téléphones inline retirés du Client (testés sur ClientContact) refonte-contact
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 → 422 (Assert\Callback + CHECK filet) ClientAddressTest::testProspectAddressCannotBeDelivery ; ::testProspectAddressCannotBeBilling ERP-60 / ERP-76
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 → 422 (Assert\Callback + CHECK filet) ClientAddressTest::testBillingAddressRequiresBillingEmail ; ::testNonBillingAddressRejectsBillingEmail ERP-60 / ERP-76
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 : ClientAddress::validateCategoryTypes (Assert\Callback) rejette une catégorie DISTRIBUTEUR/COURTIER en 422 (violation categories). Tests : ClientAddressTest::testAddressRejectsDistributorCategory / ::testAddressRejectsBrokerCategory / ::testAddressAcceptsSectorCategory / ::testAddressAcceptsOtherCategory ERP-76

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)résolu en ERP-76. La validation d'écriture refuse désormais une catégorie de type DISTRIBUTEUR/COURTIER sur une ClientAddress (→ 422, violation categories) via l'Assert\Callback ClientAddress::validateCategoryTypes. Le filtrage de lecture reste front-driven (SearchFilter). Couvert par ClientAddressTest.
  • Violations CHECK → statut HTTPrésolu en ERP-76. Les règles d'adresse RG-1.06/07/08/11 sont désormais rejetées en 422 par des Assert\Callback applicatifs (validateProspectExclusivity / validateBillingEmailPresence) qui s'exécutent AVANT la base. Les CHECK Postgres (chk_client_address_prospect_exclusive / chk_client_address_billing_email) restent en filet de sécurité. Les tests ClientAddressTest assertent maintenant le 422 explicite (et non plus ≥ 400).