瀏覽代碼

refactor ShopService and Trial

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

+ 1 - 0
src/Service/Organization/OrganizationProfileCreator.php

@@ -10,6 +10,7 @@ use App\Enum\Organization\PrincipalTypeEnum;
 use App\Service\Network\Tree;
 use App\Service\Organization\Utils as OrganizationUtils;
 use App\Service\Security\Module;
+use App\Service\Shop\Trial;
 use App\Service\Utils\DatesUtils;
 use App\Test\Service\Organization\OrganizationProfileCreatorTest;
 

+ 0 - 37
src/Service/Organization/Trial.php

@@ -1,37 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App\Service\Organization;
-
-use App\Service\Utils\DatesUtils;
-
-/**
- * Class OrganizationProfileCreator : Service contenant les manipulations associés à la ressource OrganizationProfile.
- */
-class Trial
-{
-    public function __construct(
-        private DatesUtils $datesUtils,
-    ) {
-    }
-
-    /**
-     * Retourne le décompte sur 30 jours du dernier lancement d'essai.
-     *
-     * @return int
-     */
-    public function getTrialCountdown(?\DateTimeInterface $trialStartDate)
-    {
-        if (empty($trialStartDate)) {
-            return 0;
-        }
-
-        $daysSince = $this->datesUtils::daysSince($trialStartDate);
-        if ($daysSince > 30) {
-            return 0;
-        }
-
-        return 30 - $daysSince;
-    }
-}

+ 36 - 83
src/Service/Shop/ShopService.php

@@ -55,9 +55,8 @@ class ShopService
         private OrganizationFactory $organizationFactory,
         private SerializerInterface $serializer,
         private LoggerInterface $logger,
-        private DolibarrApiService $dolibarrApiService,
-        private DolibarrUtils $dolibarrUtils,
         private MessageBusInterface $messageBus,
+        private Trial $trial,
     ) {
         $this->phoneNumberUtil = PhoneNumberUtil::getInstance();
     }
@@ -170,61 +169,6 @@ class ShopService
         $this->entityManager->flush();
     }
 
-    /**
-     * Start an artist premium trial for an organization.
-     *
-     * @param Organization                          $organization The organization to start the trial for
-     * @param NewStructureArtistPremiumTrialRequest $request      The trial request data
-     *
-     * @throws Exception
-     * @throws \JsonException
-     */
-    protected function startArtistPremiumTrial(Organization $organization, NewStructureArtistPremiumTrialRequest $request): void
-    {
-        // Update settings
-        $settings = $organization->getSettings();
-        $settings->setProductBeforeTrial($organization->getSettings()->getProduct());
-        $settings->setTrialActive(true);
-        $settings->setLastTrialStartDate(DatesUtils::new());
-        $settings->setProduct(SettingsProductEnum::ARTIST_PREMIUM);
-        $this->entityManager->persist($settings);
-        $this->entityManager->flush();
-
-        $dolibarrSocietyId = $this->dolibarrApiService->getSocietyId($organization->getId());
-
-        // Create contract in dolibarr
-        $dolibarrProductId = $this->dolibarrUtils->getProductId(
-            SettingsProductEnum::ARTIST_PREMIUM, true
-        );
-
-        $contractId = $this->dolibarrApiService->createContract(
-            $dolibarrSocietyId, $dolibarrProductId, true, 1
-        );
-
-        $this->dolibarrApiService->createContractLine($contractId, $dolibarrProductId, 1);
-
-        // Maj le représentant commercial dans dolibarr
-        $this->dolibarrUtils->updateSocietyCommercialsWithApi($dolibarrSocietyId);
-
-        // Met à jour le produit dans Dolibarr
-        $productName = $this->dolibarrUtils->getDolibarrProductName(SettingsProductEnum::ARTIST_PREMIUM, true);
-        $this->dolibarrApiService->updateSocietyProduct($dolibarrSocietyId, $productName);
-
-        // Ajoute une entrée aux actions commerciales dolibarr
-        $message = sprintf(
-            'Action réalisé par : %s %s.<br>Fonction : %s<br>Mail:%s<br>Tel:%s',
-            $request->getRepresentativeFirstName(),
-            $request->getRepresentativeLastName(),
-            $request->getRepresentativeFunction(),
-            $request->getRepresentativeEmail(),
-            $request->getRepresentativePhone()
-        );
-
-        $this->dolibarrUtils->addActionComm(
-            $dolibarrSocietyId, 'Ouverture de la période d\'essai', $message
-        );
-    }
-
     /**
      * Handles the processing of a new structure artist premium trial request.
      *
@@ -257,7 +201,7 @@ class ShopService
         $organization = $this->createOrganization($trialRequest);
 
         // Start the artist premium trial
-        $this->startArtistPremiumTrial($organization, $trialRequest);
+        $this->trial->startArtistPremiumTrial($organization, $trialRequest);
 
         $this->logger->info('Successfully processed NewStructureArtistPremiumTrial for token: '.$token);
     }
@@ -272,6 +216,38 @@ class ShopService
     protected function createOrganization(NewStructureArtistPremiumTrialRequest $trialRequest): Organization
     {
         // Generate an OrganizationCreationRequest object
+        $organizationCreationRequest = $this->createOrganizationCreationRequestFromTrialRequest($trialRequest);
+
+        // Create the organization
+        return $this->organizationFactory->create($organizationCreationRequest);
+    }
+
+    /**
+     * Vérifie la validité d'une requête d'essai artist premium pour une nouvelle structure.
+     */
+    protected function validateNewStructureArtistPremiumTrialRequest(
+        NewStructureArtistPremiumTrialRequest $request,
+    ): void {
+        // Validate phone number
+        if (!$this->phoneNumberUtil->isPossibleNumber($request->getRepresentativePhone())) {
+            throw new \RuntimeException('Invalid phone number');
+        }
+
+        // Check if organization already exists
+        $organizationCreationRequest = $this->createOrganizationCreationRequestFromTrialRequest($request, true);
+        $this->organizationFactory->interruptIfOrganizationExists($organizationCreationRequest);
+    }
+
+    /**
+     * Creates an OrganizationCreationRequest from a NewStructureArtistPremiumTrialRequest.
+     *
+     * @param NewStructureArtistPremiumTrialRequest $trialRequest The trial request containing organization data
+     *
+     * @return OrganizationCreationRequest The created organization creation request
+     */
+    protected function createOrganizationCreationRequestFromTrialRequest(
+        NewStructureArtistPremiumTrialRequest $trialRequest,
+    ): OrganizationCreationRequest {
         $organizationCreationRequest = new OrganizationCreationRequest();
         $organizationCreationRequest->setName($trialRequest->getStructureName());
         $organizationCreationRequest->setStreetAddress1($trialRequest->getAddress());
@@ -293,10 +269,9 @@ class ShopService
         $organizationCreationRequest->setProduct(SettingsProductEnum::FREEMIUM);
         $organizationCreationRequest->setCreateWebsite(false);
         $organizationCreationRequest->setClient(false);
-        $organizationCreationRequest->setCreationDate(new \DateTime());
+        $organizationCreationRequest->setCreationDate(DatesUtils::new());
 
-        // Create the organization
-        return $this->organizationFactory->create($organizationCreationRequest);
+        return $organizationCreationRequest;
     }
 
     /**
@@ -339,26 +314,4 @@ class ShopService
 
         return $subdomain;
     }
-
-    /**
-     * Vérifie la validité d'une requête d'essai artist premium pour une nouvelle structure.
-     */
-    protected function validateNewStructureArtistPremiumTrialRequest(
-        NewStructureArtistPremiumTrialRequest $request,
-    ): void {
-        // Validate phone number
-        if (!$this->phoneNumberUtil->isPossibleNumber($request->getRepresentativePhone())) {
-            throw new \RuntimeException('Invalid phone number');
-        }
-
-        // Check if organization already exists
-        $organizationCreationRequest = new OrganizationCreationRequest();
-        $organizationCreationRequest->setName($request->getStructureName());
-        $organizationCreationRequest->setCity($request->getCity());
-        $organizationCreationRequest->setPostalCode($request->getPostalCode());
-        $organizationCreationRequest->setStreetAddress1($request->getAddress());
-        $organizationCreationRequest->setStreetAddress2($request->getAddressComplement());
-        $organizationCreationRequest->setStreetAddress3('');
-        $this->organizationFactory->interruptIfOrganizationExists($organizationCreationRequest);
-    }
 }

+ 101 - 0
src/Service/Shop/Trial.php

@@ -0,0 +1,101 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Service\Shop;
+
+use App\ApiResources\Shop\NewStructureArtistPremiumTrialRequest;
+use App\Entity\Organization\Organization;
+use App\Enum\Organization\SettingsProductEnum;
+use App\Service\Dolibarr\DolibarrApiService;
+use App\Service\Dolibarr\DolibarrUtils;
+use App\Service\Utils\DatesUtils;
+use Doctrine\ORM\EntityManagerInterface;
+
+/**
+ * Class Trial : Service contenant les manipulations associés aux périodes d'essai.
+ */
+class Trial
+{
+    public function __construct(
+        private DatesUtils $datesUtils,
+        private EntityManagerInterface $entityManager,
+        private DolibarrApiService $dolibarrApiService,
+        private DolibarrUtils $dolibarrUtils,
+    ) {
+    }
+
+    /**
+     * Retourne le décompte sur 30 jours du dernier lancement d'essai.
+     *
+     * @return int
+     */
+    public function getTrialCountdown(?\DateTimeInterface $trialStartDate)
+    {
+        if (empty($trialStartDate)) {
+            return 0;
+        }
+
+        $daysSince = $this->datesUtils::daysSince($trialStartDate);
+        if ($daysSince > 30) {
+            return 0;
+        }
+
+        return 30 - $daysSince;
+    }
+
+    /**
+     * Start an artist premium trial for an organization.
+     *
+     * @param Organization                          $organization The organization to start the trial for
+     * @param NewStructureArtistPremiumTrialRequest $request      The trial request data
+     *
+     * @throws \Doctrine\DBAL\Exception
+     * @throws \JsonException
+     */
+    public function startArtistPremiumTrial(Organization $organization, NewStructureArtistPremiumTrialRequest $request): void
+    {
+        // Update settings
+        $settings = $organization->getSettings();
+        $settings->setProductBeforeTrial($organization->getSettings()->getProduct());
+        $settings->setTrialActive(true);
+        $settings->setLastTrialStartDate(DatesUtils::new());
+        $settings->setProduct(SettingsProductEnum::ARTIST_PREMIUM);
+        $this->entityManager->persist($settings);
+        $this->entityManager->flush();
+
+        $dolibarrSocietyId = $this->dolibarrApiService->getSocietyId($organization->getId());
+
+        // Create contract in dolibarr
+        $dolibarrProductId = $this->dolibarrUtils->getProductId(
+            SettingsProductEnum::ARTIST_PREMIUM, true
+        );
+
+        $contractId = $this->dolibarrApiService->createContract(
+            $dolibarrSocietyId, $dolibarrProductId, true, 1
+        );
+
+        $this->dolibarrApiService->createContractLine($contractId, $dolibarrProductId, 1);
+
+        // Maj le représentant commercial dans dolibarr
+        $this->dolibarrUtils->updateSocietyCommercialsWithApi($dolibarrSocietyId);
+
+        // Met à jour le produit dans Dolibarr
+        $productName = $this->dolibarrUtils->getDolibarrProductName(SettingsProductEnum::ARTIST_PREMIUM, true);
+        $this->dolibarrApiService->updateSocietyProduct($dolibarrSocietyId, $productName);
+
+        // Ajoute une entrée aux actions commerciales dolibarr
+        $message = sprintf(
+            'Action réalisé par : %s %s.<br>Fonction : %s<br>Mail:%s<br>Tel:%s',
+            $request->getRepresentativeFirstName(),
+            $request->getRepresentativeLastName(),
+            $request->getRepresentativeFunction(),
+            $request->getRepresentativeEmail(),
+            $request->getRepresentativePhone()
+        );
+
+        $this->dolibarrUtils->addActionComm(
+            $dolibarrSocietyId, 'Ouverture de la période d\'essai', $message
+        );
+    }
+}

+ 1 - 1
tests/Unit/Service/Organization/OrganizationProfileCreatorTest.php

@@ -13,9 +13,9 @@ use App\Enum\Organization\PrincipalTypeEnum;
 use App\Enum\Organization\SettingsProductEnum;
 use App\Service\Network\Tree;
 use App\Service\Organization\OrganizationProfileCreator;
-use App\Service\Organization\Trial;
 use App\Service\Organization\Utils as OrganizationUtils;
 use App\Service\Security\Module;
+use App\Service\Shop\Trial;
 use Doctrine\Common\Collections\ArrayCollection;
 use PHPUnit\Framework\TestCase;
 

+ 117 - 2
tests/Unit/Service/Organization/TrialTest.php

@@ -4,8 +4,15 @@ declare(strict_types=1);
 
 namespace App\Tests\Unit\Service\Organization;
 
-use App\Service\Organization\Trial;
+use App\ApiResources\Shop\NewStructureArtistPremiumTrialRequest;
+use App\Entity\Organization\Organization;
+use App\Entity\Organization\Settings;
+use App\Enum\Organization\SettingsProductEnum;
+use App\Service\Dolibarr\DolibarrApiService;
+use App\Service\Dolibarr\DolibarrUtils;
+use App\Service\Shop\Trial;
 use App\Service\Utils\DatesUtils;
+use Doctrine\ORM\EntityManagerInterface;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -17,11 +24,22 @@ class TrialTest extends TestCase
 {
     private DatesUtils $datesUtils;
     private Trial $trial;
+    private EntityManagerInterface $entityManager;
+    private DolibarrApiService $dolibarrApiService;
+    private DolibarrUtils $dolibarrUtils;
 
     public function setUp(): void
     {
         $this->datesUtils = new DatesUtils();
-        $this->trial = new Trial($this->datesUtils);
+        $this->entityManager = $this->createMock(EntityManagerInterface::class);
+        $this->dolibarrApiService = $this->createMock(DolibarrApiService::class);
+        $this->dolibarrUtils = $this->createMock(DolibarrUtils::class);
+        $this->trial = new Trial(
+            $this->datesUtils,
+            $this->entityManager,
+            $this->dolibarrApiService,
+            $this->dolibarrUtils
+        );
     }
 
     public function tearDown(): void
@@ -89,4 +107,101 @@ class TrialTest extends TestCase
         // Should return 0 days remaining since the trial has expired
         $this->assertEquals(0, $result);
     }
+
+    /**
+     * Test startArtistPremiumTrial method.
+     *
+     * @see Trial::startArtistPremiumTrial()
+     */
+    public function testStartArtistPremiumTrial(): void
+    {
+        DatesUtils::setFakeDatetime('2025-01-01 12:00:00');
+
+        $organization = $this->createMock(Organization::class);
+
+        $settings = $this->createMock(Settings::class);
+        $settings->method('getProduct')->willReturn(SettingsProductEnum::FREEMIUM);
+
+        $organization->method('getSettings')->willReturn($settings);
+        $organization->method('getId')->willReturn(123);
+
+        $request = $this->createMock(NewStructureArtistPremiumTrialRequest::class);
+        $request->method('getRepresentativeFirstName')->willReturn('John');
+        $request->method('getRepresentativeLastName')->willReturn('Doe');
+        $request->method('getRepresentativeFunction')->willReturn('Manager');
+        $request->method('getRepresentativeEmail')->willReturn('test@example.com');
+        $request->method('getRepresentativePhone')->willReturn('+33123456789');
+
+        $settings
+            ->expects(self::once())
+            ->method('setProductBeforeTrial')
+            ->with(SettingsProductEnum::FREEMIUM);
+
+        $settings
+            ->expects(self::once())
+            ->method('setTrialActive')
+            ->with(true);
+
+        $settings
+            ->expects(self::once())
+            ->method('setLastTrialStartDate')
+            ->with(self::callback(function ($dateTime) {
+                return $dateTime instanceof \DateTime && $dateTime->format('Y-m-d H:i:s') === '2025-01-01 12:00:00';
+            }));
+
+        $settings->expects(self::once())
+            ->method('setProduct')
+            ->with(SettingsProductEnum::ARTIST_PREMIUM);
+
+        $this->entityManager->expects(self::once())
+            ->method('persist')
+            ->with($settings);
+
+        $this->entityManager->expects(self::once())
+            ->method('flush');
+
+        $this->dolibarrApiService->expects(self::once())
+            ->method('getSocietyId')
+            ->with(123)
+            ->willReturn(456);
+
+        $this->dolibarrUtils->expects(self::once())
+            ->method('getProductId')
+            ->with(SettingsProductEnum::ARTIST_PREMIUM, true)
+            ->willReturn(789);
+
+        $this->dolibarrApiService->expects(self::once())
+            ->method('createContract')
+            ->with(456, 789, true, 1)
+            ->willReturn(101112);
+
+        $this->dolibarrApiService->expects(self::once())
+            ->method('createContractLine')
+            ->with(101112, 789, 1);
+
+        $this->dolibarrUtils->expects(self::once())
+            ->method('updateSocietyCommercialsWithApi')
+            ->with(456);
+
+        $this->dolibarrUtils->expects(self::once())
+            ->method('getDolibarrProductName')
+            ->with(SettingsProductEnum::ARTIST_PREMIUM, true)
+            ->willReturn('Artist Premium (essai)');
+
+        $this->dolibarrApiService->expects(self::once())
+            ->method('updateSocietyProduct')
+            ->with(456, 'Artist Premium (essai)');
+
+        $this->dolibarrUtils->expects(self::once())
+            ->method('addActionComm')
+            ->with(456, "Ouverture de la période d'essai", self::callback(function ($message) {
+                return strpos($message, 'John') !== false
+                    && strpos($message, 'Doe') !== false
+                    && strpos($message, 'Manager') !== false
+                    && strpos($message, 'test@example.com') !== false
+                    && strpos($message, '+33123456789') !== false;
+            }));
+
+        $this->trial->startArtistPremiumTrial($organization, $request);
+    }
 }

+ 93 - 166
tests/Unit/Service/Shop/ShopServiceTest.php

@@ -4,9 +4,9 @@ declare(strict_types=1);
 
 namespace App\Tests\Unit\Service\Shop;
 
+use App\ApiResources\Organization\OrganizationCreationRequest;
 use App\ApiResources\Shop\NewStructureArtistPremiumTrialRequest;
 use App\Entity\Organization\Organization;
-use App\Entity\Organization\Settings;
 use App\Entity\Shop\ShopRequest;
 use App\Enum\Organization\LegalEnum;
 use App\Enum\Organization\PrincipalTypeEnum;
@@ -14,11 +14,10 @@ use App\Enum\Organization\SettingsProductEnum;
 use App\Enum\Shop\ShopRequestStatus;
 use App\Enum\Shop\ShopRequestType;
 use App\Message\Message\Shop\NewStructureArtistPremiumTrial;
-use App\Service\Dolibarr\DolibarrApiService;
-use App\Service\Dolibarr\DolibarrUtils;
 use App\Service\Mailer\Mailer;
 use App\Service\Organization\OrganizationFactory;
 use App\Service\Shop\ShopService;
+use App\Service\Shop\Trial;
 use App\Service\Utils\DatesUtils;
 use Doctrine\ORM\EntityManagerInterface;
 use libphonenumber\PhoneNumberUtil;
@@ -33,7 +32,7 @@ class TestableShopService extends ShopService
 {
     public PhoneNumberUtil $phoneNumberUtil;
 
-    public function controlShopRequestData(ShopRequestType $type, array $data): void
+    public function controlShopRequestData(ShopRequestType $type, NewStructureArtistPremiumTrialRequest|array $data): void
     {
         parent::controlShopRequestData($type, $data);
     }
@@ -48,10 +47,6 @@ class TestableShopService extends ShopService
         parent::sendRequestValidationLink($shopRequest);
     }
 
-    public function startArtistPremiumTrial(Organization $organization, NewStructureArtistPremiumTrialRequest $request): void
-    {
-        parent::startArtistPremiumTrial($organization, $request);
-    }
 
     public function handleNewStructureArtistPremiumTrialRequest(string $token): void
     {
@@ -72,6 +67,13 @@ class TestableShopService extends ShopService
     {
         parent::validateNewStructureArtistPremiumTrialRequest($request);
     }
+
+    public function createOrganizationCreationRequestFromTrialRequest(
+        NewStructureArtistPremiumTrialRequest $trialRequest,
+        bool $forValidationOnly = false
+    ): \App\ApiResources\Organization\OrganizationCreationRequest {
+        return parent::createOrganizationCreationRequestFromTrialRequest($trialRequest, $forValidationOnly);
+    }
 }
 
 /**
@@ -85,9 +87,8 @@ class ShopServiceTest extends TestCase
     private readonly MockObject|OrganizationFactory $organizationFactory;
     private readonly MockObject|SerializerInterface $serializer;
     private readonly MockObject|LoggerInterface $logger;
-    private readonly MockObject|DolibarrApiService $dolibarrApiService;
-    private readonly MockObject|DolibarrUtils $dolibarrUtils;
     private readonly MockObject|MessageBusInterface $messageBus;
+    private readonly MockObject|Trial $trial;
 
     public function setUp(): void
     {
@@ -97,9 +98,8 @@ class ShopServiceTest extends TestCase
         $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->dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)->disableOriginalConstructor()->getMock();
-        $this->dolibarrUtils = $this->getMockBuilder(DolibarrUtils::class)->disableOriginalConstructor()->getMock();
         $this->messageBus = $this->getMockBuilder(MessageBusInterface::class)->disableOriginalConstructor()->getMock();
+        $this->trial = $this->getMockBuilder(Trial::class)->disableOriginalConstructor()->getMock();
     }
 
     private function getShopServiceMockFor(string $methodName): TestableShopService|MockObject
@@ -114,9 +114,8 @@ class ShopServiceTest extends TestCase
                     $this->organizationFactory,
                     $this->serializer,
                     $this->logger,
-                    $this->dolibarrApiService,
-                    $this->dolibarrUtils,
                     $this->messageBus,
+                    $this->trial,
                 ]
             )
             ->setMethodsExcept([$methodName])
@@ -306,105 +305,6 @@ class ShopServiceTest extends TestCase
         $shopService->sendRequestValidationLink($shopRequest);
     }
 
-    /**
-     * Test startArtistPremiumTrial method.
-     */
-    public function testStartArtistPremiumTrial(): void
-    {
-        $shopService = $this->getShopServiceMockFor('startArtistPremiumTrial');
-
-        DatesUtils::setFakeDatetime('2025-01-01 12:00:00');
-
-        $organization = $this->getMockBuilder(Organization::class)->getMock();
-
-        $settings = $this->getMockBuilder(Settings::class)->getMock();
-        $settings->method('getProduct')->willReturn(SettingsProductEnum::FREEMIUM);
-
-        $organization->method('getSettings')->willReturn($settings);
-        $organization->method('getId')->willReturn(123);
-
-        $request = $this->getMockBuilder(NewStructureArtistPremiumTrialRequest::class)->getMock();
-        $request->method('getRepresentativeFirstName')->willReturn('John');
-        $request->method('getRepresentativeLastName')->willReturn('Doe');
-        $request->method('getRepresentativeFunction')->willReturn('Manager');
-        $request->method('getRepresentativeEmail')->willReturn('test@example.com');
-        $request->method('getRepresentativePhone')->willReturn('+33123456789');
-
-        $settings
-            ->expects(self::once())
-            ->method('setProductBeforeTrial')
-            ->with(SettingsProductEnum::FREEMIUM);
-
-        $settings
-            ->expects(self::once())
-            ->method('setTrialActive')
-            ->with(true);
-
-        $settings
-            ->expects(self::once())
-            ->method('setLastTrialStartDate')
-            ->with(self::callback(function ($dateTime) {
-                return $dateTime instanceof \DateTime && $dateTime->format('Y-m-d H:i:s') === '2025-01-01 12:00:00';
-            }));
-
-        $settings->expects(self::once())
-            ->method('setProduct')
-            ->with(SettingsProductEnum::ARTIST_PREMIUM);
-
-        $this->entityManager->expects(self::once())
-            ->method('persist')
-            ->with($settings);
-
-        $this->entityManager->expects(self::once())
-            ->method('flush');
-
-        $this->dolibarrApiService->expects(self::once())
-            ->method('getSocietyId')
-            ->with(123)
-            ->willReturn(456);
-
-        $this->dolibarrUtils->expects(self::once())
-            ->method('getProductId')
-            ->with(SettingsProductEnum::ARTIST_PREMIUM, true)
-            ->willReturn(789);
-
-        $this->dolibarrApiService->expects(self::once())
-            ->method('createContract')
-            ->with(456, 789, true, 1)
-            ->willReturn(101112);
-
-        $this->dolibarrApiService->expects(self::once())
-            ->method('createContractLine')
-            ->with(101112, 789, 1);
-
-        $this->dolibarrUtils->expects(self::once())
-            ->method('updateSocietyCommercialsWithApi')
-            ->with(456);
-
-        $this->dolibarrUtils->expects(self::once())
-            ->method('getDolibarrProductName')
-            ->with(SettingsProductEnum::ARTIST_PREMIUM, true)
-            ->willReturn('Artist Premium (essai)');
-
-        $this->dolibarrApiService->expects(self::once())
-            ->method('updateSocietyProduct')
-            ->with(456, 'Artist Premium (essai)');
-
-        $this->dolibarrUtils->expects(self::once())
-            ->method('addActionComm')
-            ->with(456, "Ouverture de la période d'essai", self::callback(function ($message) {
-                return strpos($message, 'John') !== false
-                    && strpos($message, 'Doe') !== false
-                    && strpos($message, 'Manager') !== false
-                    && strpos($message, 'test@example.com') !== false
-                    && strpos($message, '+33123456789') !== false;
-            }));
-
-        $shopService->startArtistPremiumTrial($organization, $request);
-
-        // Clear the fake date time after the test
-        DatesUtils::clearFakeDatetime();
-    }
 
     /**
      * Test handleNewStructureArtistPremiumTrialRequest method.
@@ -448,7 +348,7 @@ class ShopServiceTest extends TestCase
             ->with($trialRequest)
             ->willReturn($organization);
 
-        $shopService
+        $this->trial
             ->expects(self::once())
             ->method('startArtistPremiumTrial')
             ->with($organization, $trialRequest);
@@ -490,45 +390,21 @@ class ShopServiceTest extends TestCase
             ->getMockBuilder(NewStructureArtistPremiumTrialRequest::class)
             ->getMock();
 
-        $trialRequest->method('getStructureName')->willReturn('Test Structure');
-        $trialRequest->method('getAddress')->willReturn('123 Main St');
-        $trialRequest->method('getAddressComplement')->willReturn('Suite 456');
-        $trialRequest->method('getPostalCode')->willReturn('75000');
-        $trialRequest->method('getCity')->willReturn('Paris');
-        $trialRequest->method('getStructureEmail')->willReturn('structure@example.com');
-        $trialRequest->method('getStructureType')->willReturn(PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY);
-        $trialRequest->method('getLegalStatus')->willReturn(LegalEnum::ASSOCIATION_LAW_1901);
-        $trialRequest->method('getSiren')->willReturn('123456789');
-        $trialRequest->method('getRepresentativePhone')->willReturn('+33123456789');
-
-        $shopService
-            ->expects(self::once())
-            ->method('generateSubdomain')
-            ->with('Test Structure')
-            ->willReturn('test-structure');
+        $organizationCreationRequest = $this
+            ->getMockBuilder(OrganizationCreationRequest::class)
+            ->getMock();
 
         $organization = $this->getMockBuilder(Organization::class)->getMock();
 
-        // Mock the organizationFactory.create method to return the mock Organization
+        $shopService->expects(self::once())
+            ->method('createOrganizationCreationRequestFromTrialRequest')
+            ->with($trialRequest)
+            ->willReturn($organizationCreationRequest);
+
         $this->organizationFactory
             ->expects(self::once())
             ->method('create')
-            ->with(self::callback(function ($organizationCreationRequest) {
-                return $organizationCreationRequest->getName() === 'Test Structure'
-                    && $organizationCreationRequest->getStreetAddress1() === '123 Main St'
-                    && $organizationCreationRequest->getStreetAddress2() === 'Suite 456'
-                    && $organizationCreationRequest->getPostalCode() === '75000'
-                    && $organizationCreationRequest->getCity() === 'Paris'
-                    && $organizationCreationRequest->getEmail() === 'structure@example.com'
-                    && $organizationCreationRequest->getPrincipalType() === PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY
-                    && $organizationCreationRequest->getLegalStatus() === LegalEnum::ASSOCIATION_LAW_1901
-                    && $organizationCreationRequest->getSiretNumber() === '123456789'
-                    && $organizationCreationRequest->getPhoneNumber() === '+33123456789'
-                    && $organizationCreationRequest->getSubdomain() === 'test-structure'
-                    && $organizationCreationRequest->getProduct()->value === SettingsProductEnum::FREEMIUM->value
-                    && $organizationCreationRequest->getCreateWebsite() === false
-                    && $organizationCreationRequest->isClient() === false;
-            }))
+            ->with($organizationCreationRequest)
             ->willReturn($organization);
 
         $result = $shopService->createOrganization($trialRequest);
@@ -576,13 +452,19 @@ class ShopServiceTest extends TestCase
             ->getMock();
         $shopService->phoneNumberUtil = $phoneNumberUtil;
 
-        $request = new NewStructureArtistPremiumTrialRequest();
-        $request->setStructureName('Test Structure');
-        $request->setCity('Test City');
-        $request->setPostalCode('12345');
-        $request->setAddress('Test Address');
-        $request->setAddressComplement('Test Address Complement');
-        $request->setRepresentativePhone('+33123456789');
+        $trialRequest = $this
+            ->getMockBuilder(NewStructureArtistPremiumTrialRequest::class)
+            ->getMock();
+        $trialRequest->method('getRepresentativePhone')->willReturn('+33123456789');
+
+        $organizationCreationRequest = $this
+            ->getMockBuilder(OrganizationCreationRequest::class)
+            ->getMock();
+
+        $shopService->expects(self::once())
+            ->method('createOrganizationCreationRequestFromTrialRequest')
+            ->with($trialRequest)
+            ->willReturn($organizationCreationRequest);
 
         $phoneNumberUtil->expects(self::once())
             ->method('isPossibleNumber')
@@ -591,16 +473,9 @@ class ShopServiceTest extends TestCase
 
         $this->organizationFactory->expects(self::once())
             ->method('interruptIfOrganizationExists')
-            ->with(self::callback(function ($organizationCreationRequest) {
-                return $organizationCreationRequest->getName() === 'Test Structure'
-                    && $organizationCreationRequest->getCity() === 'Test City'
-                    && $organizationCreationRequest->getPostalCode() === '12345'
-                    && $organizationCreationRequest->getStreetAddress1() === 'Test Address'
-                    && $organizationCreationRequest->getStreetAddress2() === 'Test Address Complement'
-                    && $organizationCreationRequest->getStreetAddress3() === '';
-            }));
+            ->with($organizationCreationRequest);
 
-        $shopService->validateNewStructureArtistPremiumTrialRequest($request);
+        $shopService->validateNewStructureArtistPremiumTrialRequest($trialRequest);
     }
 
     /**
@@ -615,8 +490,10 @@ class ShopServiceTest extends TestCase
             ->getMock();
         $shopService->phoneNumberUtil = $phoneNumberUtil;
 
-        $request = new NewStructureArtistPremiumTrialRequest();
-        $request->setRepresentativePhone('invalid-phone');
+        $trialRequest = $this
+            ->getMockBuilder(NewStructureArtistPremiumTrialRequest::class)
+            ->getMock();
+        $trialRequest->method('getRepresentativePhone')->willReturn('invalid-phone');
 
         // Mock the phoneNumberUtil to return false for isPossibleNumber
         $phoneNumberUtil->expects(self::once())
@@ -627,6 +504,56 @@ class ShopServiceTest extends TestCase
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionMessage('Invalid phone number');
 
-        $shopService->validateNewStructureArtistPremiumTrialRequest($request);
+        $shopService->validateNewStructureArtistPremiumTrialRequest($trialRequest);
+    }
+
+    /**
+     * Test createOrganizationCreationRequestFromTrialRequest method with forValidationOnly=false.
+     */
+    public function testCreateOrganizationCreationRequestFromTrialRequestComplete(): void
+    {
+        $shopService = $this->getShopServiceMockFor('createOrganizationCreationRequestFromTrialRequest');
+
+        $trialRequest = $this->getMockBuilder(NewStructureArtistPremiumTrialRequest::class)
+            ->getMock();
+        $trialRequest->method('getStructureName')->willReturn('Test Structure');
+        $trialRequest->method('getCity')->willReturn('Test City');
+        $trialRequest->method('getPostalCode')->willReturn('12345');
+        $trialRequest->method('getAddress')->willReturn('Test Address');
+        $trialRequest->method('getAddressComplement')->willReturn('Test Address Complement');
+        $trialRequest->method('getRepresentativePhone')->willReturn('+33123456789');
+        $trialRequest->method('getStructureEmail')->willReturn('structure@example.com');
+        $trialRequest->method('getStructureType')->willReturn(PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY);
+        $trialRequest->method('getLegalStatus')->willReturn(LegalEnum::ASSOCIATION_LAW_1901);
+        $trialRequest->method('getSiren')->willReturn('123456789');
+
+        $shopService->expects(self::once())
+            ->method('generateSubdomain')
+            ->with('Test Structure')
+            ->willReturn('test-structure');
+
+        // Set a fake date for testing
+        $fakeDate = '2023-05-15 10:30:00';
+        DatesUtils::setFakeDatetime($fakeDate);
+
+        // Test with forValidationOnly = false (default)
+        $result = $shopService->createOrganizationCreationRequestFromTrialRequest($trialRequest);
+
+        // Verify that all fields are set
+        $this->assertEquals('Test Structure', $result->getName());
+        $this->assertEquals('Test City', $result->getCity());
+        $this->assertEquals('12345', $result->getPostalCode());
+        $this->assertEquals('Test Address', $result->getStreetAddress1());
+        $this->assertEquals('Test Address Complement', $result->getStreetAddress2());
+        $this->assertEquals('structure@example.com', $result->getEmail());
+        $this->assertEquals(PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY, $result->getPrincipalType());
+        $this->assertEquals(LegalEnum::ASSOCIATION_LAW_1901, $result->getLegalStatus());
+        $this->assertEquals('123456789', $result->getSiretNumber());
+        $this->assertEquals('+33123456789', $result->getPhoneNumber());
+        $this->assertEquals('test-structure', $result->getSubdomain());
+        $this->assertEquals(SettingsProductEnum::FREEMIUM, $result->getProduct());
+        $this->assertFalse($result->getCreateWebsite());
+        $this->assertFalse($result->isClient());
+        $this->assertEquals(new \DateTime($fakeDate), $result->getCreationDate());
     }
 }