瀏覽代碼

fix and complete unit tests, lint

Olivier Massot 5 月之前
父節點
當前提交
628a46bd57

+ 1 - 1
src/ApiResources/Shop/NewStructureArtistPremiumTrialRequest.php

@@ -115,7 +115,7 @@ class NewStructureArtistPremiumTrialRequest implements ShopRequestData
 
     /**
      * Password of the admin account of the newly created structure.
-
+     *
      * Must have at least 8 characters, including at least one uppercase letter,
      * one lowercase letter, one digit, and one special character.
      */

+ 1 - 1
src/ApiResources/Shop/ShopRequestData.php

@@ -1,9 +1,9 @@
 <?php
+
 declare(strict_types=1);
 
 namespace App\ApiResources\Shop;
 
 interface ShopRequestData
 {
-
 }

+ 1 - 1
src/Repository/Access/AccessRepository.php

@@ -73,7 +73,7 @@ class AccessRepository extends ServiceEntityRepository implements UserLoaderInte
     /**
      * Retourne l'access administrateur de cette organisation.
      */
-    public function findAdminAccess(Organization $organization): Access
+    public function findAdminAccess(Organization $organization): ?Access
     {
         return $this->findOneBy([
             'adminAccess' => 1,

+ 6 - 5
src/Service/Dolibarr/DolibarrUtils.php

@@ -59,8 +59,9 @@ class DolibarrUtils
     /**
      * Exécute une requête SQL sur la DB Dolibarr.
      *
-     * @param string $sql The SQL query to execute
-     * @param array $params The parameters to bind to the query
+     * @param string                   $sql    The SQL query to execute
+     * @param array<int|string, mixed> $params The parameters to bind to the query
+     *
      * @throws \Doctrine\DBAL\Exception
      */
     protected function executeQuery(string $sql, array $params = []): void
@@ -81,12 +82,12 @@ class DolibarrUtils
         $apiUserId = 8;
 
         $this->executeQuery(
-            "DELETE FROM llx_societe_commerciaux WHERE fk_soc = ?",
+            'DELETE FROM llx_societe_commerciaux WHERE fk_soc = ?',
             [$societyId]
         );
 
         $this->executeQuery(
-            "INSERT INTO llx_societe_commerciaux (fk_soc, fk_user) VALUES (?, ?)",
+            'INSERT INTO llx_societe_commerciaux (fk_soc, fk_user) VALUES (?, ?)',
             [$societyId, $apiUserId]
         );
     }
@@ -115,7 +116,7 @@ class DolibarrUtils
             $now,
             $apiUserId,
             $apiUserId,
-            $apiUserId
+            $apiUserId,
         ]);
     }
 

+ 2 - 2
src/Service/Organization/OrganizationFactory.php

@@ -949,7 +949,7 @@ class OrganizationFactory
      * and one special character.
      *
      * @param Organization $organization The organization whose admin account password will be set
-     * @param string $password The plain password to set
+     * @param string       $password     The plain password to set
      *
      * @throws \RuntimeException If no admin account is found or if the password doesn't meet the requirements
      */
@@ -975,6 +975,6 @@ class OrganizationFactory
         $this->entityManager->persist($person);
         $this->entityManager->flush();
 
-        $this->logger->info('Admin account password set for organization: ' . $organization->getId());
+        $this->logger->info('Admin account password set for organization: '.$organization->getId());
     }
 }

+ 6 - 3
src/Service/Shop/ShopService.php

@@ -244,6 +244,10 @@ class ShopService
 
     /**
      * Vérifie la validité d'une requête d'essai artist premium pour une nouvelle structure.
+     *
+     * @param array<string, mixed> $data
+     *
+     * @throws \Exception
      */
     protected function validateNewStructureArtistPremiumTrialRequest(
         array $data,
@@ -328,10 +332,9 @@ class ShopService
      */
     protected function sendConfirmationMailToRepresentative(
         NewStructureArtistPremiumTrialRequest $trialRequest,
-    ): void
-    {
+    ): void {
         // Create the admin username
-        $adminUsername = 'admin' . $trialRequest->getStructureIdentifier();
+        $adminUsername = 'admin'.$trialRequest->getStructureIdentifier();
 
         // Create the admin login URL
         $adminLoginUrl = UrlBuilder::concat($this->adminBaseUrl, ['#/login/']);

+ 5 - 5
src/Service/Utils/UrlBuilder.php

@@ -32,7 +32,7 @@ class UrlBuilder
     /**
      * Concatenate an url and a list of parameters.
      *
-     * @param list<string|int> $parameters
+     * @param array<string, mixed> $parameters
      */
     public static function concatParameters(string $url, array $parameters = []): string
     {
@@ -74,10 +74,10 @@ class UrlBuilder
     /**
      * Build an url.
      *
-     * @param string        $url           The base url
-     * @param array<string> $tails         la suite de l'url sous forme de tableau
-     * @param list<string>  $parameters    A list of parameters (can be an empty array)
-     * @param bool          $preprendHttps Should the 'https://' be prepended if missing
+     * @param string               $url           The base url
+     * @param array<string>        $tails         la suite de l'url sous forme de tableau
+     * @param array<string, mixed> $parameters    A list of parameters (can be an empty array)
+     * @param bool                 $preprendHttps Should the 'https://' be prepended if missing
      */
     public static function concat(string $url, array $tails, array $parameters = [], bool $preprendHttps = false): string
     {

+ 19 - 7
tests/Unit/Service/Dolibarr/DolibarrUtilsTest.php

@@ -18,7 +18,7 @@ class TestableDolibarrUtils extends DolibarrUtils
 {
     public function executeQueryPublic(string $sql): void
     {
-        $this->executeQuery($sql);
+        $this->executeQuery($sql, []);
     }
 }
 
@@ -114,7 +114,7 @@ class DolibarrUtilsTest extends TestCase
         $this->dolibarrConnection
             ->expects($this->once())
             ->method('executeQuery')
-            ->with($sql);
+            ->with($sql, []);
 
         $this->dolibarrUtils->executeQueryPublic($sql);
     }
@@ -131,9 +131,8 @@ class DolibarrUtilsTest extends TestCase
             ->expects($this->exactly(2))
             ->method('executeQuery')
             ->withConsecutive(
-                ["DELETE FROM llx_societe_commerciaux WHERE fk_soc = $societyId"],
-                ["INSERT INTO llx_societe_commerciaux (fk_soc, fk_user) 
-                   VALUES ($societyId, $apiUserId)"]
+                ['DELETE FROM llx_societe_commerciaux WHERE fk_soc = ?', [$societyId]],
+                ['INSERT INTO llx_societe_commerciaux (fk_soc, fk_user) VALUES (?, ?)', [$societyId, $apiUserId]]
             );
 
         $this->dolibarrUtils->updateSocietyCommercialsWithApi($societyId);
@@ -158,12 +157,25 @@ class DolibarrUtilsTest extends TestCase
         $datesMock = $this->createMock(DatesUtils::class);
         DatesUtils::setFakeDatetime('2023-01-01 12:00:00');
 
+        $sql = "INSERT INTO llx_actioncomm (fk_soc, ref, code, label, note, datep, datep2, datec, fk_user_author, fk_user_mod, fk_user_action, percent) 
+                   VALUES (?, -1, 'AC_OT_ONLINE_STORE', ?, ?, ?, ?, ?, ?, ?, ?, -1)";
+
         $this->dolibarrConnection
             ->expects($this->once())
             ->method('executeQuery')
             ->with(
-                "INSERT INTO llx_actioncomm (fk_soc, ref, code, label, note, datep, datep2, datec, fk_user_author, fk_user_mod, fk_user_action, percent) 
-                   VALUES ($societyId, -1, 'AC_OT_ONLINE_STORE', '$title', '$message', '$formattedDate', '$formattedDate', '$formattedDate', $apiUserId, $apiUserId, $apiUserId, -1)"
+                $sql,
+                [
+                    $societyId,
+                    $title,
+                    $message,
+                    $formattedDate,
+                    $formattedDate,
+                    $formattedDate,
+                    $apiUserId,
+                    $apiUserId,
+                    $apiUserId,
+                ]
             );
 
         $this->dolibarrUtils->addActionComm($societyId, $title, $message);

+ 103 - 11
tests/Unit/Service/Shop/ShopServiceTest.php

@@ -32,7 +32,7 @@ class TestableShopService extends ShopService
 {
     public PhoneNumberUtil $phoneNumberUtil;
 
-    public function controlShopRequestData(ShopRequestType $type, NewStructureArtistPremiumTrialRequest|array $data): void
+    public function controlShopRequestData(ShopRequestType $type, array $data): void
     {
         parent::controlShopRequestData($type, $data);
     }
@@ -62,16 +62,25 @@ class TestableShopService extends ShopService
         return parent::generateSubdomain($name);
     }
 
-    public function validateNewStructureArtistPremiumTrialRequest($request): void
+    public function validateNewStructureArtistPremiumTrialRequest(array $data): void
     {
-        parent::validateNewStructureArtistPremiumTrialRequest($request);
+        parent::validateNewStructureArtistPremiumTrialRequest($data);
     }
 
     public function createOrganizationCreationRequestFromTrialRequest(
         NewStructureArtistPremiumTrialRequest $trialRequest,
-        bool $forValidationOnly = false,
     ): OrganizationCreationRequest {
-        return parent::createOrganizationCreationRequestFromTrialRequest($trialRequest, $forValidationOnly);
+        return parent::createOrganizationCreationRequestFromTrialRequest($trialRequest);
+    }
+
+    public function sendMailToSalesAdministration(NewStructureArtistPremiumTrialRequest $trialRequest): void
+    {
+        parent::sendMailToSalesAdministration($trialRequest);
+    }
+
+    public function sendConfirmationMailToRepresentative(NewStructureArtistPremiumTrialRequest $trialRequest): void
+    {
+        parent::sendConfirmationMailToRepresentative($trialRequest);
     }
 }
 
@@ -83,22 +92,28 @@ class ShopServiceTest extends TestCase
     private readonly MockObject|EntityManagerInterface $entityManager;
     private readonly MockObject|Mailer $mailer;
     private string $publicBaseUrl;
+    private string $adminBaseUrl;
     private readonly MockObject|OrganizationFactory $organizationFactory;
     private readonly MockObject|SerializerInterface $serializer;
     private readonly MockObject|LoggerInterface $logger;
     private readonly MockObject|MessageBusInterface $messageBus;
     private readonly MockObject|Trial $trial;
+    private string $faqUrl;
+    private string $softwareWebsiteUrl;
 
     public function setUp(): void
     {
         $this->entityManager = $this->getMockBuilder(EntityManagerInterface::class)->disableOriginalConstructor()->getMock();
         $this->mailer = $this->getMockBuilder(Mailer::class)->disableOriginalConstructor()->getMock();
         $this->publicBaseUrl = 'https://example.com';
+        $this->adminBaseUrl = 'https://admin.example.com';
         $this->organizationFactory = $this->getMockBuilder(OrganizationFactory::class)->disableOriginalConstructor()->getMock();
         $this->serializer = $this->getMockBuilder(SerializerInterface::class)->disableOriginalConstructor()->getMock();
         $this->logger = $this->getMockBuilder(LoggerInterface::class)->disableOriginalConstructor()->getMock();
         $this->messageBus = $this->getMockBuilder(MessageBusInterface::class)->disableOriginalConstructor()->getMock();
         $this->trial = $this->getMockBuilder(Trial::class)->disableOriginalConstructor()->getMock();
+        $this->faqUrl = 'https://faq.example.com';
+        $this->softwareWebsiteUrl = 'https://software.example.com';
     }
 
     private function getShopServiceMockFor(string $methodName): TestableShopService|MockObject
@@ -110,11 +125,14 @@ class ShopServiceTest extends TestCase
                     $this->entityManager,
                     $this->mailer,
                     $this->publicBaseUrl,
+                    $this->adminBaseUrl,
                     $this->organizationFactory,
                     $this->serializer,
                     $this->logger,
                     $this->messageBus,
                     $this->trial,
+                    $this->faqUrl,
+                    $this->softwareWebsiteUrl,
                 ]
             )
             ->setMethodsExcept([$methodName])
@@ -280,14 +298,12 @@ class ShopServiceTest extends TestCase
             ->expects(self::once())
             ->method('main')
             ->with(self::callback(function ($model) use ($token, $data) {
-                var_dump($model);
-
                 return $model->getToken() === $token
                     && $model->getRepresentativeEmail() === $data['representativeEmail']
                     && $model->getRepresentativeFirstName() === $data['representativeFirstName']
                     && $model->getRepresentativeLastName() === $data['representativeLastName']
                     && $model->getStructureName() === $data['structureName']
-                    && $model->getValidationUrl() === 'https://example.com/api/public/shop/validate/'.$token;
+                    && $model->getValidationUrl() === 'https://software.example.com/shop/try/validation?token='.$token;
             }));
 
         $shopRequest->expects(self::once())
@@ -359,6 +375,15 @@ class ShopServiceTest extends TestCase
             ->method('startArtistPremiumTrialForNewStructure')
             ->with($organization, $trialRequest);
 
+        // Mock the sendMailToSalesAdministration and sendConfirmationMailToRepresentative methods
+        $shopService->expects(self::once())
+            ->method('sendMailToSalesAdministration')
+            ->with($trialRequest);
+
+        $shopService->expects(self::once())
+            ->method('sendConfirmationMailToRepresentative')
+            ->with($trialRequest);
+
         $this->logger->expects(self::once())
             ->method('info')
             ->with('Successfully processed NewStructureArtistPremiumTrial for token: '.$token);
@@ -512,7 +537,16 @@ class ShopServiceTest extends TestCase
             ->method('interruptIfOrganizationExists')
             ->with($organizationCreationRequest);
 
-        $shopService->validateNewStructureArtistPremiumTrialRequest($trialRequest);
+        // Convert the trial request to an array for validation
+        $data = [
+            'representativePhone' => '+33123456789',
+        ];
+        $this->serializer->expects(self::once())
+            ->method('deserialize')
+            ->with(json_encode($data), NewStructureArtistPremiumTrialRequest::class, 'json')
+            ->willReturn($trialRequest);
+
+        $shopService->validateNewStructureArtistPremiumTrialRequest($data);
     }
 
     /**
@@ -538,10 +572,19 @@ class ShopServiceTest extends TestCase
             ->with('invalid-phone')
             ->willReturn(false);
 
+        // Convert the trial request to an array for validation
+        $data = [
+            'representativePhone' => 'invalid-phone',
+        ];
+        $this->serializer->expects(self::once())
+            ->method('deserialize')
+            ->with(json_encode($data), NewStructureArtistPremiumTrialRequest::class, 'json')
+            ->willReturn($trialRequest);
+
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionMessage('Invalid phone number');
 
-        $shopService->validateNewStructureArtistPremiumTrialRequest($trialRequest);
+        $shopService->validateNewStructureArtistPremiumTrialRequest($data);
     }
 
     /**
@@ -569,7 +612,7 @@ class ShopServiceTest extends TestCase
         $fakeDate = '2023-05-15 10:30:00';
         DatesUtils::setFakeDatetime($fakeDate);
 
-        // Test with forValidationOnly = false (default)
+        // Create the organization creation request
         $result = $shopService->createOrganizationCreationRequestFromTrialRequest($trialRequest);
 
         // Verify that all fields are set
@@ -589,4 +632,53 @@ class ShopServiceTest extends TestCase
         $this->assertFalse($result->isClient());
         $this->assertEquals(new \DateTime($fakeDate), $result->getCreationDate());
     }
+
+    /**
+     * Test sendMailToSalesAdministration method.
+     */
+    public function testSendMailToSalesAdministration(): void
+    {
+        $shopService = $this->getShopServiceMockFor('sendMailToSalesAdministration');
+
+        $trialRequest = $this->getMockBuilder(NewStructureArtistPremiumTrialRequest::class)
+            ->getMock();
+
+        $this->mailer
+            ->expects(self::once())
+            ->method('main')
+            ->with(self::callback(function ($model) use ($trialRequest) {
+                return $model instanceof \App\Service\Mailer\Model\Shop\NewStructureArtistPremium\NotificationToSalesAdminModel
+                    && $model->getTrialRequest() === $trialRequest
+                    && $model->getSenderId() === \App\Enum\Access\AccessIdsEnum::ADMIN_2IOPENSERVICE->value;
+            }));
+
+        $shopService->sendMailToSalesAdministration($trialRequest);
+    }
+
+    /**
+     * Test sendConfirmationMailToRepresentative method.
+     */
+    public function testSendConfirmationMailToRepresentative(): void
+    {
+        $shopService = $this->getShopServiceMockFor('sendConfirmationMailToRepresentative');
+
+        $trialRequest = $this->getMockBuilder(NewStructureArtistPremiumTrialRequest::class)
+            ->getMock();
+        $trialRequest->method('getStructureIdentifier')->willReturn('test-structure');
+
+        $this->mailer
+            ->expects(self::once())
+            ->method('main')
+            ->with(self::callback(function ($model) use ($trialRequest) {
+                return $model instanceof \App\Service\Mailer\Model\Shop\NewStructureArtistPremium\ConfirmationToRepresentativeModel
+                    && $model->getTrialRequest() === $trialRequest
+                    && $model->getSenderId() === \App\Enum\Access\AccessIdsEnum::ADMIN_2IOPENSERVICE->value
+                    && $model->getAccountCreationUrl() === 'https://example.com/account/create'
+                    && $model->getFaqUrl() === 'https://faq.example.com'
+                    && $model->getAdminUsername() === 'admintest-structure'
+                    && $model->getAdminLoginUrl() === 'https://admin.example.com/#/login/';
+            }));
+
+        $shopService->sendConfirmationMailToRepresentative($trialRequest);
+    }
 }