= 1 site) sont DEJA couverts par * ClientSubResourceApiTest (ERP-57) et ne sont pas reduplique ici. Ce fichier * cible : * - RG-1.06 / RG-1.07 / RG-1.08 : exclusivite is_prospect vs * is_delivery / is_billing ; * - RG-1.11 : billing_email obligatoire ssi is_billing ; * - RG-1.29 : seules les categories de type SECTEUR / AUTRE sont autorisees sur * une adresse (DISTRIBUTEUR / COURTIER -> 422). * * Depuis ERP-76, ces regles sont portees par des Assert\Callback sur l'entite * ClientAddress (mirror applicatif des CHECK Postgres) : la combinaison invalide * est donc rejetee en 422 AVANT la base, et non plus par une violation CHECK * remontant en 500. Les CHECK BDD restent en filet de securite (non testes ici, * inatteignables tant que les validators applicatifs passent en premier). * * @internal */ final class ClientAddressTest extends AbstractCommercialApiTestCase { private const string LD = 'application/ld+json'; /** * RG-1.06 / RG-1.07 : une adresse de prospection ne peut pas etre une * adresse de livraison -> 422 (Assert\Callback, mirror du CHECK * chk_client_address_prospect_exclusive). */ public function testProspectAddressCannotBeDelivery(): void { $this->skipIfSitesModuleDisabled(); $client = $this->createAdminClient(); $seed = $this->seedClient('Prospect Delivery'); $client->request('POST', '/api/clients/'.$seed->getId().'/addresses', [ 'headers' => ['Content-Type' => self::LD], 'json' => [ 'isProspect' => true, 'isDelivery' => true, 'postalCode' => '86100', 'city' => 'Châtellerault', 'street' => '1 rue du Test', 'sites' => [$this->firstSiteIri()], ], ]); self::assertResponseStatusCodeSame(422); } /** * RG-1.06 / RG-1.08 : une adresse de prospection ne peut pas etre une * adresse de facturation -> 422. On fournit billingEmail pour que la seule * violation possible soit l'exclusivite prospect/billing. */ public function testProspectAddressCannotBeBilling(): void { $this->skipIfSitesModuleDisabled(); $client = $this->createAdminClient(); $seed = $this->seedClient('Prospect Billing'); $client->request('POST', '/api/clients/'.$seed->getId().'/addresses', [ 'headers' => ['Content-Type' => self::LD], 'json' => [ 'isProspect' => true, 'isBilling' => true, 'billingEmail' => 'facturation@test.fr', 'postalCode' => '86100', 'city' => 'Châtellerault', 'street' => '1 rue du Test', 'sites' => [$this->firstSiteIri()], ], ]); self::assertResponseStatusCodeSame(422); } /** * RG-1.11 : une adresse de facturation exige un billingEmail -> 422. */ public function testBillingAddressRequiresBillingEmail(): void { $this->skipIfSitesModuleDisabled(); $client = $this->createAdminClient(); $seed = $this->seedClient('Billing No Email'); $client->request('POST', '/api/clients/'.$seed->getId().'/addresses', [ 'headers' => ['Content-Type' => self::LD], 'json' => [ 'isBilling' => true, 'postalCode' => '86100', 'city' => 'Châtellerault', 'street' => '1 rue du Test', 'sites' => [$this->firstSiteIri()], ], ]); self::assertResponseStatusCodeSame(422); } /** * RG-1.11 (sens inverse) : une adresse NON facturable ne peut pas porter un * billingEmail -> 422. */ public function testNonBillingAddressRejectsBillingEmail(): void { $this->skipIfSitesModuleDisabled(); $client = $this->createAdminClient(); $seed = $this->seedClient('Non Billing With Email'); $client->request('POST', '/api/clients/'.$seed->getId().'/addresses', [ 'headers' => ['Content-Type' => self::LD], 'json' => [ 'isBilling' => false, 'billingEmail' => 'parasite@test.fr', 'postalCode' => '86100', 'city' => 'Châtellerault', 'street' => '1 rue du Test', 'sites' => [$this->firstSiteIri()], ], ]); self::assertResponseStatusCodeSame(422); } /** * RG-1.29 : poster une categorie de type DISTRIBUTEUR sur une adresse -> 422 * avec violation sur le champ `categories`. */ public function testAddressRejectsDistributorCategory(): void { $this->skipIfSitesModuleDisabled(); $client = $this->createAdminClient(); $seed = $this->seedClient('Address Distributor Cat'); $category = $this->createCategory('DISTRIBUTEUR'); $client->request('POST', '/api/clients/'.$seed->getId().'/addresses', [ 'headers' => ['Content-Type' => self::LD], 'json' => [ 'postalCode' => '86100', 'city' => 'Châtellerault', 'street' => '1 rue du Test', 'sites' => [$this->firstSiteIri()], 'categories' => ['/api/categories/'.$category->getId()], ], ]); self::assertResponseStatusCodeSame(422); self::assertStringContainsString( 'Type de catégorie non autorisé sur une adresse.', (string) $client->getResponse()->getContent(false), ); } /** * RG-1.29 : poster une categorie de type COURTIER sur une adresse -> 422. */ public function testAddressRejectsBrokerCategory(): void { $this->skipIfSitesModuleDisabled(); $client = $this->createAdminClient(); $seed = $this->seedClient('Address Broker Cat'); $category = $this->createCategory('COURTIER'); $client->request('POST', '/api/clients/'.$seed->getId().'/addresses', [ 'headers' => ['Content-Type' => self::LD], 'json' => [ 'postalCode' => '86100', 'city' => 'Châtellerault', 'street' => '1 rue du Test', 'sites' => [$this->firstSiteIri()], 'categories' => ['/api/categories/'.$category->getId()], ], ]); self::assertResponseStatusCodeSame(422); } /** * RG-1.29 : une categorie de type SECTEUR est autorisee sur une adresse. */ public function testAddressAcceptsSectorCategory(): void { $this->skipIfSitesModuleDisabled(); $client = $this->createAdminClient(); $seed = $this->seedClient('Address Sector Cat'); $category = $this->createCategory('SECTEUR'); $client->request('POST', '/api/clients/'.$seed->getId().'/addresses', [ 'headers' => ['Content-Type' => self::LD], 'json' => [ 'postalCode' => '86100', 'city' => 'Châtellerault', 'street' => '1 rue du Test', 'sites' => [$this->firstSiteIri()], 'categories' => ['/api/categories/'.$category->getId()], ], ]); self::assertResponseStatusCodeSame(201); } /** * RG-1.29 : une categorie de type AUTRE est autorisee sur une adresse. */ public function testAddressAcceptsOtherCategory(): void { $this->skipIfSitesModuleDisabled(); $client = $this->createAdminClient(); $seed = $this->seedClient('Address Other Cat'); $category = $this->createCategory('AUTRE'); $client->request('POST', '/api/clients/'.$seed->getId().'/addresses', [ 'headers' => ['Content-Type' => self::LD], 'json' => [ 'postalCode' => '86100', 'city' => 'Châtellerault', 'street' => '1 rue du Test', 'sites' => [$this->firstSiteIri()], 'categories' => ['/api/categories/'.$category->getId()], ], ]); self::assertResponseStatusCodeSame(201); } /** * Retourne l'IRI du premier site seede (fixtures Sites). */ private function firstSiteIri(): string { $site = $this->getEm()->getRepository(Site::class)->findOneBy([]); self::assertNotNull($site, 'Aucun site seede : impossible de tester les adresses.'); return '/api/sites/'.$site->getId(); } }