From 9a1fcad3cb69e791a972f0bd7dee68afaf4be31d Mon Sep 17 00:00:00 2001 From: Matthieu Date: Thu, 4 Jun 2026 11:35:26 +0200 Subject: [PATCH] test(commercial) : verrouille POST adresses/RIB sur client peuple (ERP-110) --- .../Api/ClientSubResourceApiTest.php | 77 ++++++++++++++++++- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/tests/Module/Commercial/Api/ClientSubResourceApiTest.php b/tests/Module/Commercial/Api/ClientSubResourceApiTest.php index 059661f..321ac10 100644 --- a/tests/Module/Commercial/Api/ClientSubResourceApiTest.php +++ b/tests/Module/Commercial/Api/ClientSubResourceApiTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Tests\Module\Commercial\Api; use App\Module\Commercial\Domain\Entity\Client as ClientEntity; +use App\Module\Commercial\Domain\Entity\ClientAddress; use App\Module\Commercial\Domain\Entity\ClientContact; use App\Module\Commercial\Domain\Entity\ClientRib; use App\Module\Commercial\Domain\Entity\PaymentType; @@ -246,6 +247,35 @@ final class ClientSubResourceApiTest extends AbstractCommercialApiTestCase self::assertResponseStatusCodeSame(422); } + /** + * Regression ERP-110 : POST d'une adresse sur un client qui en a DEJA >= 2 ne + * doit pas exploser en 500 (NonUniqueResult sur la resolution du parent). Le + * POST porte un site + une categorie (RG-1.10 / RG-1.29) pour etre valide. + */ + public function testPostAddressOnClientWithTwoExistingAddressesReturns201(): void + { + $this->skipIfSitesModuleDisabled(); + $client = $this->createAdminClient(); + $seed = $this->seedClient('Addr Multi'); + $siteIri = $this->firstSiteIri(); + $category = $this->createCategory('SECTEUR'); + $this->seedAddress($seed, 'Bordeaux'); + $this->seedAddress($seed, 'Lyon'); + + $client->request('POST', '/api/clients/'.$seed->getId().'/addresses', [ + 'headers' => ['Content-Type' => self::LD, 'Accept' => self::LD], + 'json' => [ + 'postalCode' => '75001', + 'city' => 'Paris', + 'street' => '2 rue Neuve', + 'sites' => [$siteIri], + 'categories' => ['/api/categories/'.$category->getId()], + ], + ]); + + self::assertResponseStatusCodeSame(201); + } + // === RIBs === public function testPostRibByAdminReturns201(): void @@ -284,6 +314,26 @@ final class ClientSubResourceApiTest extends AbstractCommercialApiTestCase self::assertResponseStatusCodeSame(422); } + /** + * Regression ERP-110 : POST d'un RIB sur un client qui en a DEJA >= 2 ne doit + * pas exploser en 500 (NonUniqueResult sur la resolution du parent). L'admin + * porte commercial.clients.accounting.manage requis par le POST. + */ + public function testPostRibOnClientWithTwoExistingRibsReturns201(): void + { + $client = $this->createAdminClient(); + $seed = $this->seedClient('Rib Multi'); + $this->seedRib($seed, 'Compte 1'); + $this->seedRib($seed, 'Compte 2'); + + $client->request('POST', '/api/clients/'.$seed->getId().'/ribs', [ + 'headers' => ['Content-Type' => self::LD, 'Accept' => self::LD], + 'json' => ['label' => 'Compte 3', 'bic' => self::VALID_BIC, 'iban' => self::VALID_IBAN], + ]); + + self::assertResponseStatusCodeSame(201); + } + public function testDeleteRibNonLcrReturns204(): void { $client = $this->createAdminClient(); @@ -351,13 +401,34 @@ final class ClientSubResourceApiTest extends AbstractCommercialApiTestCase } /** - * Seede un ClientRib valide rattache a un client (sans passer par l'API). + * Seede une adresse minimale valide en base (sans passer par l'API) : seules + * les colonnes NOT NULL sont posees (CP / ville / rue). Les M2M sites / + * categories restent vides — non contraints en base, suffisant pour peupler + * un client de plusieurs adresses. */ - private function seedRib(ClientEntity $client): ClientRib + private function seedAddress(ClientEntity $client, string $city): ClientAddress + { + $em = $this->getEm(); + $address = new ClientAddress(); + $address->setClient($client); + $address->setPostalCode('33000'); + $address->setCity($city); + $address->setStreet('1 rue du Test'); + $em->persist($address); + $em->flush(); + + return $address; + } + + /** + * Seede un ClientRib valide rattache a un client (sans passer par l'API). Le + * libelle est parametrable pour seeder plusieurs RIB distincts. + */ + private function seedRib(ClientEntity $client, string $label = 'Seed RIB'): ClientRib { $em = $this->getEm(); $rib = new ClientRib(); - $rib->setLabel('Seed RIB'); + $rib->setLabel($label); $rib->setBic(self::VALID_BIC); $rib->setIban(self::VALID_IBAN); $rib->setClient($client);