Olivier Massot пре 5 месеци
родитељ
комит
ec2b2f014b

+ 18 - 11
src/Entity/Shop/ShopRequest.php

@@ -6,24 +6,20 @@ namespace App\Entity\Shop;
 
 use ApiPlatform\Metadata\ApiResource;
 use ApiPlatform\Metadata\Get;
-use ApiPlatform\Metadata\Post;
 use App\Enum\Shop\ShopRequestStatus;
 use App\Enum\Shop\ShopRequestType;
-use App\State\Processor\Shop\NewStructureArtistPremiumTrialRequestProcessor;
 use App\State\Provider\Shop\ShopRequestProvider;
-use Doctrine\ORM\Mapping as ORM;
 use Doctrine\DBAL\Types\Types;
-use DateTimeImmutable;
-use Symfony\Component\Validator\Constraints as Assert;
+use Doctrine\ORM\Mapping as ORM;
 
 /**
- * Une demande effectuée par un client via la boutique en ligne (ex: demande d'essai premium)
+ * Une demande effectuée par un client via la boutique en ligne (ex: demande d'essai premium).
  */
 #[ApiResource(operations: [
     new Get(
         uriTemplate: '/public/shop/validate/{token}',
         provider: ShopRequestProvider::class,
-    )
+    ),
 ])]
 #[ORM\Entity]
 class ShopRequest
@@ -33,7 +29,7 @@ class ShopRequest
     private string $token;
 
     #[ORM\Column(type: 'datetime_immutable')]
-    private DateTimeImmutable $submissionDate;
+    private \DateTimeImmutable $submissionDate;
 
     #[ORM\Column(length: 50, enumType: ShopRequestStatus::class)]
     private ShopRequestStatus $status;
@@ -41,12 +37,15 @@ class ShopRequest
     #[ORM\Column(length: 50, enumType: ShopRequestType::class)]
     private ShopRequestType $type;
 
+    /**
+     * @var array<string, mixed>
+     */
     #[ORM\Column(type: Types::JSON)]
     private array $data = [];
 
     public function __construct()
     {
-        $this->submissionDate = new DateTimeImmutable();
+        $this->submissionDate = new \DateTimeImmutable();
         $this->status = ShopRequestStatus::PENDING;
     }
 
@@ -62,12 +61,12 @@ class ShopRequest
         return $this;
     }
 
-    public function getSubmissionDate(): DateTimeImmutable
+    public function getSubmissionDate(): \DateTimeImmutable
     {
         return $this->submissionDate;
     }
 
-    public function setSubmissionDate(DateTimeImmutable $submissionDate): self
+    public function setSubmissionDate(\DateTimeImmutable $submissionDate): self
     {
         $this->submissionDate = $submissionDate;
 
@@ -98,11 +97,19 @@ class ShopRequest
         return $this;
     }
 
+    /**
+     * @return array<string, mixed>
+     */
     public function getData(): array
     {
         return $this->data;
     }
 
+    /**
+     * @param array<string, mixed> $data
+     *
+     * @return $this
+     */
     public function setData(array $data): self
     {
         $this->data = $data;

+ 1 - 4
src/Message/Handler/Shop/NewStructureArtistPremiumTrialHandler.php

@@ -20,14 +20,12 @@ use Symfony\Component\Messenger\Attribute\AsMessageHandler;
 readonly class NewStructureArtistPremiumTrialHandler
 {
     public function __construct(
-        private ShopService            $shopService,
-
+        private ShopService $shopService,
     ) {
     }
 
     /**
      * @param NewStructureArtistPremiumTrial $message The message to process
-     * @return void
      */
     public function __invoke(NewStructureArtistPremiumTrial $message): void
     {
@@ -35,5 +33,4 @@ readonly class NewStructureArtistPremiumTrialHandler
 
         $this->shopService->handleNewStructureArtistPremiumTrialRequest($token);
     }
-
 }

+ 0 - 1
src/Message/Message/Shop/NewStructureArtistPremiumTrial.php

@@ -34,7 +34,6 @@ class NewStructureArtistPremiumTrial
      * Sets the token that identifies the shop request.
      *
      * @param string $token The token
-     * @return void
      */
     public function setToken(string $token): void
     {

+ 30 - 41
src/Service/Dolibarr/DolibarrApiService.php

@@ -6,10 +6,8 @@ namespace App\Service\Dolibarr;
 
 use App\Entity\Organization\Organization;
 use App\Enum\Dolibarr\DolibarrDocTypeEnum;
-use App\Enum\Organization\SettingsProductEnum;
 use App\Service\Rest\ApiRequestService;
 use App\Service\Utils\DatesUtils;
-use Exception;
 use JetBrains\PhpStorm\Pure;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
@@ -59,16 +57,15 @@ class DolibarrApiService extends ApiRequestService
     }
 
     /**
-     * Get the dolibarr id of an organization
+     * Get the dolibarr id of an organization.
      *
-     * @param int $organizationId
-     * @return int|null
      * @throws \JsonException
      */
     public function getSocietyId(int $organizationId): ?int
     {
         $society = $this->getSociety($organizationId);
-        return $society ? (int)$society['id'] : null;
+
+        return $society ? (int) $society['id'] : null;
     }
 
     /**
@@ -297,22 +294,20 @@ class DolibarrApiService extends ApiRequestService
     }
 
     /**
-     * Créé un nouveau contrat Dolibarr
+     * Créé un nouveau contrat Dolibarr.
      *
-     * @param int $socId
      * @param int $productId L'id du produit dans dolibarr (@see DolibarrUtils::getProductId())
-     * @param bool $isNewClient
-     * @param int $duration Durée du contrat (en mois)
-     * @return int
-     * @throws Exception
+     * @param int $duration  Durée du contrat (en mois)
+     *
+     * @throws \Exception
      */
     public function createContract(
-        int  $socId,
-        int  $productId,
+        int $socId,
+        int $productId,
         bool $isNewClient = false,
-        int $duration = 12
+        int $duration = 12,
     ): int {
-        $route = "contracts";
+        $route = 'contracts';
         $date = DatesUtils::new();
 
         $product = $this->getJsonContent(
@@ -323,10 +318,10 @@ class DolibarrApiService extends ApiRequestService
         $originVente = $isNewClient ? 1 : 3;
 
         $body = [
-            "socid" => $socId,
-            "date_contrat" => $date->format('Y-m-d'),
-            "commercial_signature_id" => 8,
-            "commercial_suivi_id" => 8,
+            'socid' => $socId,
+            'date_contrat' => $date->format('Y-m-d'),
+            'commercial_signature_id' => 8,
+            'commercial_suivi_id' => 8,
             'statut' => 1,
             'lines' => [
                 [
@@ -334,13 +329,13 @@ class DolibarrApiService extends ApiRequestService
                     'label' => $product['label'],
                     'desc' => $product['description'],
                     'qty' => 1,
-                    'subprice' => number_format((float)$product['price'],2),
+                    'subprice' => number_format((float) $product['price'], 2),
                     'price_base_type' => $product['price_base_type'],
                     'tva_tx' => $product['tva_tx'],
-                ]
+                ],
             ],
             'array_options' => [
-                'options_ec_amount' => number_format((float)$product['price'],2),
+                'options_ec_amount' => number_format((float) $product['price'], 2),
                 'options_ec_duration_months' => $duration,
                 'options_ec_signature_date' => $date->format('Y-m-d'),
                 'options_ec_effective_date' => $date->format('Y-m-d'),
@@ -355,22 +350,21 @@ class DolibarrApiService extends ApiRequestService
                 'options_logicielfact' => 1,
                 'options_versionfact' => 2,
                 'options_2iopen_origvente' => $originVente,
-            ]
+            ],
         ];
 
-        return (int)$this->post($route, $body)->getContent();
+        return (int) $this->post($route, $body)->getContent();
     }
 
     /**
-     * Ajoute une ligne au contrat
+     * Ajoute une ligne au contrat.
      *
-     * @param int $contractId
-     * @param int $productId
      * @param int $duration Durée du contrat (en jours)
-     * @return int
-     * @throws Exception
+     *
+     * @throws \Exception
      */
-    public function createContractLine(int $contractId, int $productId, int $duration = 12): int {
+    public function createContractLine(int $contractId, int $productId, int $duration = 12): int
+    {
         $route = "contracts/$contractId/lines";
 
         $date = DatesUtils::new();
@@ -385,23 +379,18 @@ class DolibarrApiService extends ApiRequestService
             'label' => $product['label'],
             'desc' => $product['description'],
             'qty' => 1,
-            'subprice' => number_format((float)$product['price'],2),
+            'subprice' => number_format((float) $product['price'], 2),
             'price_base_type' => $product['price_base_type'],
             'tva_tx' => $product['tva_tx'],
             'date_start' => $date->format('Y-m-d'),
             'date_end' => $endDate->format('Y-m-d'),
         ];
 
-        return (int)$this->post($route, $body)->getContent();
+        return (int) $this->post($route, $body)->getContent();
     }
 
     /**
-     * Met à jour le produit possédé par la structure dans Dolibarr
-     *
-     * @param int $socId
-     * @param SettingsProductEnum $contractType Produit concerné (@see SettingsProductEnum)
-     * @param bool $isTrial
-     * @return void
+     * Met à jour le produit possédé par la structure dans Dolibarr.
      */
     public function updateSocietyProduct(int $socId, string $productName): void
     {
@@ -409,8 +398,8 @@ class DolibarrApiService extends ApiRequestService
 
         $body = [
             'array_options' => [
-                'options_2iopen_software_opentalent' => $productName
-            ]
+                'options_2iopen_software_opentalent' => $productName,
+            ],
         ];
 
         $this->put($route, $body);

+ 26 - 33
src/Service/Dolibarr/DolibarrUtils.php

@@ -1,4 +1,5 @@
 <?php
+
 declare(strict_types=1);
 
 namespace App\Service\Dolibarr;
@@ -6,7 +7,6 @@ namespace App\Service\Dolibarr;
 use App\Enum\Organization\SettingsProductEnum;
 use App\Service\Utils\DatesUtils;
 use Doctrine\DBAL\Connection;
-use Exception;
 
 /**
  * Utility class for interacting with Dolibarr ERP/CRM system.
@@ -22,44 +22,42 @@ use Exception;
  */
 class DolibarrUtils
 {
-    const ARTIST_STANDARD_CMF_PRODUCT_ID = 283;
-    const ARTIST_PREMIUM_TRIAL_PRODUCT_ID = 598;
-    const ARTIST_PREMIUM_PRODUCT_ID = 281;
-    const ARTIST_PREMIUM_CMF_PRODUCT_ID = 282;
+    public const ARTIST_STANDARD_CMF_PRODUCT_ID = 283;
+    public const ARTIST_PREMIUM_TRIAL_PRODUCT_ID = 598;
+    public const ARTIST_PREMIUM_PRODUCT_ID = 281;
+    public const ARTIST_PREMIUM_CMF_PRODUCT_ID = 282;
 
     public function __construct(
         private Connection $dolibarrConnection,
-    ) {}
+    ) {
+    }
 
     /**
      * Retourne l'id Dolibarr du produit donné, selon le produit possédé et l'appartenance
      * ou non au réseau CMF.
      *
      * @param SettingsProductEnum $contractType Produit concerné (@see SettingsProductEnum)
-     * @param bool $isTrial
-     * @param bool $isCmf
-     * @return int
      */
     public function getProductId(
         SettingsProductEnum $contractType,
         bool $isTrial = false,
-        bool $isCmf = false
+        bool $isCmf = false,
     ): int {
         if ($contractType === SettingsProductEnum::ARTIST_PREMIUM && $isTrial) {
             return self::ARTIST_PREMIUM_TRIAL_PRODUCT_ID;
-        } else if ($contractType === SettingsProductEnum::ARTIST_PREMIUM && $isCmf) {
+        } elseif ($contractType === SettingsProductEnum::ARTIST_PREMIUM && $isCmf) {
             return self::ARTIST_PREMIUM_CMF_PRODUCT_ID;
-        } else if ($contractType === SettingsProductEnum::ARTIST_PREMIUM) {
+        } elseif ($contractType === SettingsProductEnum::ARTIST_PREMIUM) {
             return self::ARTIST_PREMIUM_PRODUCT_ID;
-        } else if ($contractType === SettingsProductEnum::ARTIST && $isCmf) {
+        } elseif ($contractType === SettingsProductEnum::ARTIST && $isCmf) {
             return self::ARTIST_STANDARD_CMF_PRODUCT_ID;
         } else {
-            throw new \InvalidArgumentException("Invalid contract type");
+            throw new \InvalidArgumentException('Invalid contract type');
         }
     }
 
     /**
-     * Exécute une requête SQL sur la DB Dolibarr
+     * Exécute une requête SQL sur la DB Dolibarr.
      *
      * @throws \Doctrine\DBAL\Exception
      */
@@ -70,13 +68,14 @@ class DolibarrUtils
 
     /**
      * Remplace le ou les commerciaux actuellement affectés à la société par l'utilisateur 'api'
-     * (pas de solution trouvée via l'API)
+     * (pas de solution trouvée via l'API).
      *
-     * @param int $societyId
      * @return void
+     *
      * @throws \Doctrine\DBAL\Exception
      */
-    public function updateSocietyCommercialsWithApi(int $societyId) {
+    public function updateSocietyCommercialsWithApi(int $societyId)
+    {
         $apiUserId = 8;
 
         $this->executeQuery(
@@ -91,13 +90,9 @@ class DolibarrUtils
 
     /**
      * Enregistre une entrée dans le journal des actions commercial de la société Dolibarr
-     * (pas de solution trouvée via l'API)
+     * (pas de solution trouvée via l'API).
      *
-     * @param int $societyId
-     * @param string $title
-     * @param string $message
-     * @return void
-     * @throws Exception
+     * @throws \Exception
      */
     public function addActionComm(int $societyId, string $title, string $message): void
     {
@@ -112,21 +107,19 @@ class DolibarrUtils
     }
 
     /**
-     * Retourne le nom du produit dans Dolibarr
+     * Retourne le nom du produit dans Dolibarr.
      *
      * @param SettingsProductEnum $contractType Produit concerné (@see SettingsProductEnum)
-     * @param bool $isTrial
-     * @return string|null
      */
     public function getDolibarrProductName(SettingsProductEnum $contractType, bool $isTrial = false): ?string
     {
         return match ($contractType) {
-            SettingsProductEnum::ARTIST => "Opentalent Artist",
-            SettingsProductEnum::ARTIST_PREMIUM => $isTrial ? "Opentalent Artist Premium (Essai)" : "Opentalent Artist Premium",
-            SettingsProductEnum::SCHOOL => "Opentalent School",
-            SettingsProductEnum::SCHOOL_PREMIUM => $isTrial ? "Opentalent School Premium (Essai)" : "Opentalent School Premium",
-            SettingsProductEnum::MANAGER => "Opentalent Manager",
-            SettingsProductEnum::MANAGER_PREMIUM => "Opentalent Manager Premium",
+            SettingsProductEnum::ARTIST => 'Opentalent Artist',
+            SettingsProductEnum::ARTIST_PREMIUM => $isTrial ? 'Opentalent Artist Premium (Essai)' : 'Opentalent Artist Premium',
+            SettingsProductEnum::SCHOOL => 'Opentalent School',
+            SettingsProductEnum::SCHOOL_PREMIUM => $isTrial ? 'Opentalent School Premium (Essai)' : 'Opentalent School Premium',
+            SettingsProductEnum::MANAGER => 'Opentalent Manager',
+            SettingsProductEnum::MANAGER_PREMIUM => 'Opentalent Manager Premium',
             default => null,
         };
     }

+ 1 - 0
src/Service/Mailer/Builder/AbstractBuilder.php

@@ -65,6 +65,7 @@ class AbstractBuilder implements AbstractBuilderInterface
     public function render(string $template, array $context): string
     {
         $templatePath = sprintf('@templates/emails/%s.html.twig', $template);
+
         return $this->twig->render($templatePath, $context);
     }
 

+ 38 - 47
src/Service/Shop/ShopService.php

@@ -14,13 +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\Repository\Organization\OrganizationRepository;
-use App\Service\ApiLegacy\ApiLegacyRequestService;
 use App\Service\Dolibarr\DolibarrApiService;
 use App\Service\Dolibarr\DolibarrUtils;
 use App\Service\Mailer\Mailer;
 use App\Service\Mailer\Model\NewStructureArtistPremiumTrialRequestValidationModel;
-use App\Service\Mailer\Model\SubdomainChangeModel;
 use App\Service\Organization\OrganizationFactory;
 use App\Service\Utils\DatesUtils;
 use App\Service\Utils\UrlBuilder;
@@ -28,11 +25,8 @@ use Doctrine\DBAL\Exception;
 use Doctrine\ORM\EntityManagerInterface;
 use Doctrine\ORM\Exception\ORMException;
 use Doctrine\ORM\OptimisticLockException;
-use JsonException;
 use libphonenumber\PhoneNumberUtil;
 use Psr\Log\LoggerInterface;
-use RuntimeException;
-use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
 use Symfony\Component\Messenger\Exception\ExceptionInterface;
 use Symfony\Component\Messenger\MessageBusInterface;
@@ -56,14 +50,14 @@ class ShopService
 
     public function __construct(
         private EntityManagerInterface $entityManager,
-        private Mailer                 $mailer,
-        private string                 $publicBaseUrl,
-        private OrganizationFactory    $organizationFactory,
-        private SerializerInterface    $serializer,
-        private LoggerInterface        $logger,
-        private DolibarrApiService     $dolibarrApiService,
-        private DolibarrUtils          $dolibarrUtils,
-        private MessageBusInterface    $messageBus,
+        private Mailer $mailer,
+        private string $publicBaseUrl,
+        private OrganizationFactory $organizationFactory,
+        private SerializerInterface $serializer,
+        private LoggerInterface $logger,
+        private DolibarrApiService $dolibarrApiService,
+        private DolibarrUtils $dolibarrUtils,
+        private MessageBusInterface $messageBus,
     ) {
         $this->phoneNumberUtil = PhoneNumberUtil::getInstance();
     }
@@ -72,9 +66,8 @@ class ShopService
      * A new shop request has been submitted.
      * Register the request, and send the validation link by email.
      *
-     * @param ShopRequestType $type
      * @param array<string, mixed> $data
-     * @return ShopRequest
+     *
      * @throws TransportExceptionInterface
      */
     public function registerNewShopRequest(ShopRequestType $type, array $data): ShopRequest
@@ -91,24 +84,24 @@ class ShopService
      * For NEW_STRUCTURE_ARTIST_PREMIUM_TRIAL, check if the organization already exists.
      * For other types, throw an error.
      *
-     * @param ShopRequestType $type
      * @param array<string, mixed> $data
      */
-    protected function controlShopRequestData(ShopRequestType $type, array $data): void
+    protected function controlShopRequestData(ShopRequestType $type, NewStructureArtistPremiumTrialRequest|array $data): void
     {
+        // @phpstan-ignore-next-line identical.alwaysTrue
         if ($type === ShopRequestType::NEW_STRUCTURE_ARTIST_PREMIUM_TRIAL) {
             /** @var NewStructureArtistPremiumTrialRequest $request */
             $request = $data;
             $this->validateNewStructureArtistPremiumTrialRequest($request);
         } else {
-            throw new RuntimeException('request type not supported');
+            throw new \RuntimeException('request type not supported');
         }
     }
 
     /**
      * Validate the request and dispatch the appropriate job based on the request type.
      *
-     * @throws RuntimeException|ExceptionInterface
+     * @throws \RuntimeException|ExceptionInterface
      */
     public function processShopRequest(ShopRequest $shopRequest): void
     {
@@ -120,7 +113,7 @@ class ShopService
                 );
                 break;
             default:
-                throw new RuntimeException('request type not supported');
+                throw new \RuntimeException('request type not supported');
         }
 
         $shopRequest->setStatus(ShopRequestStatus::VALIDATED);
@@ -130,9 +123,8 @@ class ShopService
 
     /**
      * Create and persist a new ShopRequest entity.
-     * @param ShopRequestType $type
+     *
      * @param array<string, mixed> $data
-     * @return ShopRequest
      */
     protected function createRequest(ShopRequestType $type, array $data): ShopRequest
     {
@@ -163,13 +155,13 @@ class ShopService
 
         $model = new NewStructureArtistPremiumTrialRequestValidationModel();
         $model
-            ->setSenderId(AccessIdsEnum::ADMIN_2IOPENSERVICE->value)
             ->setToken($shopRequest->getToken())
             ->setRepresentativeEmail($data['representativeEmail'] ?? '')
             ->setRepresentativeFirstName($data['representativeFirstName'] ?? '')
             ->setRepresentativeLastName($data['representativeLastName'] ?? '')
             ->setStructureName($data['structureName'] ?? '')
-            ->setValidationUrl($validationUrl);
+            ->setValidationUrl($validationUrl)
+            ->setSenderId(AccessIdsEnum::ADMIN_2IOPENSERVICE->value);
 
         $this->mailer->main($model);
 
@@ -181,17 +173,17 @@ class ShopService
     /**
      * 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
+     * @param Organization                          $organization The organization to start the trial for
+     * @param NewStructureArtistPremiumTrialRequest $request      The trial request data
      *
      * @throws Exception
-     * @throws JsonException
+     * @throws \JsonException
      */
     protected function startArtistPremiumTrial(Organization $organization, NewStructureArtistPremiumTrialRequest $request): void
     {
         // Update settings
         $settings = $organization->getSettings();
-        $settings->setProductBeforeTrial( $organization->getSettings()->getProduct());
+        $settings->setProductBeforeTrial($organization->getSettings()->getProduct());
         $settings->setTrialActive(true);
         $settings->setLastTrialStartDate(DatesUtils::new());
         $settings->setProduct(SettingsProductEnum::ARTIST_PREMIUM);
@@ -220,7 +212,7 @@ class ShopService
 
         // 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",
+            'Action réalisé par : %s %s.<br>Fonction : %s<br>Mail:%s<br>Tel:%s',
             $request->getRepresentativeFirstName(),
             $request->getRepresentativeLastName(),
             $request->getRepresentativeFunction(),
@@ -237,9 +229,9 @@ class ShopService
      * Handles the processing of a new structure artist premium trial request.
      *
      * @param string $token The token identifying the shop request
-     * @return void
+     *
      * @throws Exception
-     * @throws JsonException
+     * @throws \JsonException
      * @throws ORMException
      * @throws OptimisticLockException
      */
@@ -249,7 +241,8 @@ class ShopService
         $shopRequest = $this->entityManager->find(ShopRequest::class, $token);
 
         if (!$shopRequest) {
-            $this->logger->error('Cannot find ShopRequest with token: ' . $token);
+            $this->logger->error('Cannot find ShopRequest with token: '.$token);
+
             return;
         }
 
@@ -266,13 +259,14 @@ class ShopService
         // Start the artist premium trial
         $this->startArtistPremiumTrial($organization, $trialRequest);
 
-        $this->logger->info('Successfully processed NewStructureArtistPremiumTrial for token: ' . $token);
+        $this->logger->info('Successfully processed NewStructureArtistPremiumTrial for token: '.$token);
     }
 
     /**
      * Creates a new organization based on a trial request.
      *
      * @param NewStructureArtistPremiumTrialRequest $trialRequest The trial request containing organization data
+     *
      * @return Organization The created organization
      */
     protected function createOrganization(NewStructureArtistPremiumTrialRequest $trialRequest): Organization
@@ -309,6 +303,7 @@ class ShopService
      * Generate a subdomain from a structure name.
      *
      * @param string $name The structure name to generate a subdomain from
+     *
      * @return string The generated subdomain
      */
     protected function generateSubdomain(string $name): string
@@ -346,27 +341,23 @@ class ShopService
     }
 
     /**
-     * Vérifie la validité d'une requête d'essai artist premium pour une nouvelle structure
-     *
-     * @param NewStructureArtistPremiumTrialRequest $request
-     * @return void
+     * Vérifie la validité d'une requête d'essai artist premium pour une nouvelle structure.
      */
     protected function validateNewStructureArtistPremiumTrialRequest(
-        NewStructureArtistPremiumTrialRequest $request
-    ): void
-    {
+        NewStructureArtistPremiumTrialRequest $request,
+    ): void {
         // Validate phone number
         if (!$this->phoneNumberUtil->isPossibleNumber($request->getRepresentativePhone())) {
-            throw new RuntimeException('Invalid phone number');
+            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->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);
     }

+ 8 - 5
src/State/Processor/Shop/NewStructureArtistPremiumTrialRequestProcessor.php

@@ -10,6 +10,7 @@ use ApiPlatform\State\ProcessorInterface;
 use App\Enum\Shop\ShopRequestType;
 use App\Service\Shop\ShopService;
 use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
 use Symfony\Component\Serializer\SerializerInterface;
 
 /**
@@ -33,12 +34,14 @@ class NewStructureArtistPremiumTrialRequestProcessor implements ProcessorInterfa
      * 2. Serializes the request data to JSON
      * 3. Delegates to the ShopService to register the new shop request
      *
-     * @param mixed $data The request data (NewStructureArtistPremiumTrialRequest object)
-     * @param Operation $operation The API Platform operation
-     * @param array $uriVariables The URI variables
-     * @param array $context The context
+     * @param mixed     $data         The request data (NewStructureArtistPremiumTrialRequest object)
+     * @param Operation $operation    The API Platform operation
+     * @param mixed[]   $uriVariables The URI variables
+     * @param mixed[]   $context      The context
+     *
      * @return mixed The processed data
-     * @throws \RuntimeException If the operation is not a POST
+     *
+     * @throws TransportExceptionInterface
      */
     public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
     {

+ 1 - 2
src/State/Provider/Shop/ShopRequestProvider.php

@@ -11,8 +11,8 @@ use App\Enum\Shop\ShopRequestStatus;
 use App\Service\Shop\ShopService;
 use Doctrine\ORM\EntityManagerInterface;
 use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 /**
  * Provider for NewStructureTrialRequest validation.
@@ -64,5 +64,4 @@ final class ShopRequestProvider implements ProviderInterface
         // TODO: redirect to a confirmation page
         return new Response('Request validated successfully', Response::HTTP_OK);
     }
-
 }

+ 23 - 22
tests/Unit/Service/Dolibarr/DolibarrApiServiceTest.php

@@ -726,7 +726,7 @@ class DolibarrApiServiceTest extends TestCase
             'content-type' => 'application/pdf',
             'filesize' => 10660,
             'content' => 'base64encodedcontent',
-            'encoding' => 'base64'
+            'encoding' => 'base64',
         ];
 
         $dolibarrApiService
@@ -808,6 +808,7 @@ class DolibarrApiServiceTest extends TestCase
 
         $dolibarrApiService->switchSocietyToProspect(123);
     }
+
     /**
      * @see DolibarrApiService::createContract()
      */
@@ -844,10 +845,10 @@ class DolibarrApiServiceTest extends TestCase
 
         // Expected contract data
         $expectedBody = [
-            "socid" => $socId,
-            "date_contrat" => $date->format('Y-m-d'),
-            "commercial_signature_id" => 8,
-            "commercial_suivi_id" => 8,
+            'socid' => $socId,
+            'date_contrat' => $date->format('Y-m-d'),
+            'commercial_signature_id' => 8,
+            'commercial_suivi_id' => 8,
             'statut' => 1,
             'lines' => [
                 [
@@ -855,13 +856,13 @@ class DolibarrApiServiceTest extends TestCase
                     'label' => $productData['label'],
                     'desc' => $productData['description'],
                     'qty' => 1,
-                    'subprice' => number_format((float)$productData['price'], 2),
+                    'subprice' => number_format((float) $productData['price'], 2),
                     'price_base_type' => $productData['price_base_type'],
                     'tva_tx' => $productData['tva_tx'],
-                ]
+                ],
             ],
             'array_options' => [
-                'options_ec_amount' => number_format((float)$productData['price'], 2),
+                'options_ec_amount' => number_format((float) $productData['price'], 2),
                 'options_ec_duration_months' => $duration,
                 'options_ec_signature_date' => $date->format('Y-m-d'),
                 'options_ec_effective_date' => $date->format('Y-m-d'),
@@ -876,7 +877,7 @@ class DolibarrApiServiceTest extends TestCase
                 'options_logicielfact' => 1,
                 'options_versionfact' => 2,
                 'options_2iopen_origvente' => 3, // Evolution (3) for existing client
-            ]
+            ],
         ];
 
         $response = $this->getMockBuilder(ResponseInterface::class)->getMock();
@@ -929,10 +930,10 @@ class DolibarrApiServiceTest extends TestCase
 
         // Expected contract data with originVente = 1 for new client
         $expectedBody = [
-            "socid" => $socId,
-            "date_contrat" => $date->format('Y-m-d'),
-            "commercial_signature_id" => 8,
-            "commercial_suivi_id" => 8,
+            'socid' => $socId,
+            'date_contrat' => $date->format('Y-m-d'),
+            'commercial_signature_id' => 8,
+            'commercial_suivi_id' => 8,
             'statut' => 1,
             'lines' => [
                 [
@@ -940,13 +941,13 @@ class DolibarrApiServiceTest extends TestCase
                     'label' => $productData['label'],
                     'desc' => $productData['description'],
                     'qty' => 1,
-                    'subprice' => number_format((float)$productData['price'], 2),
+                    'subprice' => number_format((float) $productData['price'], 2),
                     'price_base_type' => $productData['price_base_type'],
                     'tva_tx' => $productData['tva_tx'],
-                ]
+                ],
             ],
             'array_options' => [
-                'options_ec_amount' => number_format((float)$productData['price'], 2),
+                'options_ec_amount' => number_format((float) $productData['price'], 2),
                 'options_ec_duration_months' => $duration,
                 'options_ec_signature_date' => $date->format('Y-m-d'),
                 'options_ec_effective_date' => $date->format('Y-m-d'),
@@ -961,7 +962,7 @@ class DolibarrApiServiceTest extends TestCase
                 'options_logicielfact' => 1,
                 'options_versionfact' => 2,
                 'options_2iopen_origvente' => 1, // New client (1)
-            ]
+            ],
         ];
 
         $response = $this->getMockBuilder(ResponseInterface::class)->getMock();
@@ -1018,7 +1019,7 @@ class DolibarrApiServiceTest extends TestCase
             'label' => $productData['label'],
             'desc' => $productData['description'],
             'qty' => 1,
-            'subprice' => number_format((float)$productData['price'], 2),
+            'subprice' => number_format((float) $productData['price'], 2),
             'price_base_type' => $productData['price_base_type'],
             'tva_tx' => $productData['tva_tx'],
             'date_start' => $date->format('Y-m-d'),
@@ -1054,8 +1055,8 @@ class DolibarrApiServiceTest extends TestCase
 
         $expectedBody = [
             'array_options' => [
-                'options_2iopen_software_opentalent' => $productName
-            ]
+                'options_2iopen_software_opentalent' => $productName,
+            ],
         ];
 
         $response = $this->getMockBuilder(ResponseInterface::class)->getMock();
@@ -1139,8 +1140,8 @@ class DolibarrApiServiceTest extends TestCase
 
         $expectedBody = [
             'array_options' => [
-                'options_2iopen_software_opentalent' => $productName
-            ]
+                'options_2iopen_software_opentalent' => $productName,
+            ],
         ];
 
         // Mock put method to throw an exception

+ 14 - 13
tests/Unit/Service/Dolibarr/DolibarrUtilsTest.php

@@ -1,4 +1,5 @@
 <?php
+
 declare(strict_types=1);
 
 namespace App\Tests\Unit\Service\Dolibarr;
@@ -11,7 +12,7 @@ use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 
 /**
- * Class to expose protected methods for testing
+ * Class to expose protected methods for testing.
  */
 class TestableDolibarrUtils extends DolibarrUtils
 {
@@ -94,7 +95,7 @@ class DolibarrUtilsTest extends TestCase
     public function testGetProductIdWithInvalidContractType(): void
     {
         $this->expectException(\InvalidArgumentException::class);
-        $this->expectExceptionMessage("Invalid contract type");
+        $this->expectExceptionMessage('Invalid contract type');
 
         $this->dolibarrUtils->getProductId(
             SettingsProductEnum::SCHOOL,
@@ -108,7 +109,7 @@ class DolibarrUtilsTest extends TestCase
      */
     public function testExecuteQuery(): void
     {
-        $sql = "DELETE FROM llx_societe_commerciaux WHERE fk_soc = 123";
+        $sql = 'DELETE FROM llx_societe_commerciaux WHERE fk_soc = 123';
 
         $this->dolibarrConnection
             ->expects($this->once())
@@ -144,8 +145,8 @@ class DolibarrUtilsTest extends TestCase
     public function testAddActionComm(): void
     {
         $societyId = 123;
-        $title = "Test Title";
-        $message = "Test Message";
+        $title = 'Test Title';
+        $message = 'Test Message';
         $apiUserId = 8;
 
         // Mock DatesUtils to return a fixed date
@@ -174,7 +175,7 @@ class DolibarrUtilsTest extends TestCase
     public function testGetDolibarrProductNameForArtist(): void
     {
         $result = $this->dolibarrUtils->getDolibarrProductName(SettingsProductEnum::ARTIST);
-        $this->assertEquals("Opentalent Artist", $result);
+        $this->assertEquals('Opentalent Artist', $result);
     }
 
     /**
@@ -183,7 +184,7 @@ class DolibarrUtilsTest extends TestCase
     public function testGetDolibarrProductNameForArtistPremiumTrial(): void
     {
         $result = $this->dolibarrUtils->getDolibarrProductName(SettingsProductEnum::ARTIST_PREMIUM, true);
-        $this->assertEquals("Opentalent Artist Premium (Essai)", $result);
+        $this->assertEquals('Opentalent Artist Premium (Essai)', $result);
     }
 
     /**
@@ -192,7 +193,7 @@ class DolibarrUtilsTest extends TestCase
     public function testGetDolibarrProductNameForArtistPremium(): void
     {
         $result = $this->dolibarrUtils->getDolibarrProductName(SettingsProductEnum::ARTIST_PREMIUM);
-        $this->assertEquals("Opentalent Artist Premium", $result);
+        $this->assertEquals('Opentalent Artist Premium', $result);
     }
 
     /**
@@ -201,7 +202,7 @@ class DolibarrUtilsTest extends TestCase
     public function testGetDolibarrProductNameForSchool(): void
     {
         $result = $this->dolibarrUtils->getDolibarrProductName(SettingsProductEnum::SCHOOL);
-        $this->assertEquals("Opentalent School", $result);
+        $this->assertEquals('Opentalent School', $result);
     }
 
     /**
@@ -210,7 +211,7 @@ class DolibarrUtilsTest extends TestCase
     public function testGetDolibarrProductNameForSchoolPremiumTrial(): void
     {
         $result = $this->dolibarrUtils->getDolibarrProductName(SettingsProductEnum::SCHOOL_PREMIUM, true);
-        $this->assertEquals("Opentalent School Premium (Essai)", $result);
+        $this->assertEquals('Opentalent School Premium (Essai)', $result);
     }
 
     /**
@@ -219,7 +220,7 @@ class DolibarrUtilsTest extends TestCase
     public function testGetDolibarrProductNameForSchoolPremium(): void
     {
         $result = $this->dolibarrUtils->getDolibarrProductName(SettingsProductEnum::SCHOOL_PREMIUM);
-        $this->assertEquals("Opentalent School Premium", $result);
+        $this->assertEquals('Opentalent School Premium', $result);
     }
 
     /**
@@ -228,7 +229,7 @@ class DolibarrUtilsTest extends TestCase
     public function testGetDolibarrProductNameForManager(): void
     {
         $result = $this->dolibarrUtils->getDolibarrProductName(SettingsProductEnum::MANAGER);
-        $this->assertEquals("Opentalent Manager", $result);
+        $this->assertEquals('Opentalent Manager', $result);
     }
 
     /**
@@ -237,6 +238,6 @@ class DolibarrUtilsTest extends TestCase
     public function testGetDolibarrProductNameForManagerPremium(): void
     {
         $result = $this->dolibarrUtils->getDolibarrProductName(SettingsProductEnum::MANAGER_PREMIUM);
-        $this->assertEquals("Opentalent Manager Premium", $result);
+        $this->assertEquals('Opentalent Manager Premium', $result);
     }
 }

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

@@ -9,7 +9,8 @@ use App\Service\Utils\DatesUtils;
 use PHPUnit\Framework\TestCase;
 
 /**
- * Unit tests for Trial class
+ * Unit tests for Trial class.
+ *
  * @see Trial
  */
 class TrialTest extends TestCase

+ 18 - 18
tests/Unit/Service/Shop/ShopServiceTest.php

@@ -74,9 +74,8 @@ class TestableShopService extends ShopService
     }
 }
 
-
 /**
- * Unit tests for ShopService
+ * Unit tests for ShopService.
  */
 class ShopServiceTest extends TestCase
 {
@@ -132,7 +131,7 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test registerNewShopRequest method
+     * Test registerNewShopRequest method.
      */
     public function testRegisterNewShopRequest(): void
     {
@@ -167,7 +166,7 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test controlShopRequestData method for NEW_STRUCTURE_ARTIST_PREMIUM_TRIAL type
+     * Test controlShopRequestData method for NEW_STRUCTURE_ARTIST_PREMIUM_TRIAL type.
      */
     public function testControlShopRequestDataForNewStructureArtistPremiumTrial(): void
     {
@@ -189,7 +188,7 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test processShopRequest method for NEW_STRUCTURE_ARTIST_PREMIUM_TRIAL type
+     * Test processShopRequest method for NEW_STRUCTURE_ARTIST_PREMIUM_TRIAL type.
      */
     public function testProcessShopRequest(): void
     {
@@ -224,13 +223,13 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test createRequest method
+     * Test createRequest method.
      */
     public function testCreateRequest(): void
     {
         $shopService = $this->getShopServiceMockFor('createRequest');
 
-        $uuidRx = "/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i";
+        $uuidRx = '/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i';
 
         $type = ShopRequestType::NEW_STRUCTURE_ARTIST_PREMIUM_TRIAL;
         $data = [
@@ -261,7 +260,7 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test sendRequestValidationLink method
+     * Test sendRequestValidationLink method.
      */
     public function testSendRequestValidationLink(): void
     {
@@ -284,12 +283,13 @@ class ShopServiceTest extends TestCase
             ->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://example.com/api/public/shop/validate/'.$token;
             }));
 
         $shopRequest->expects(self::once())
@@ -307,7 +307,7 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test startArtistPremiumTrial method
+     * Test startArtistPremiumTrial method.
      */
     public function testStartArtistPremiumTrial(): void
     {
@@ -407,7 +407,7 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test handleNewStructureArtistPremiumTrialRequest method
+     * Test handleNewStructureArtistPremiumTrialRequest method.
      */
     public function testHandleNewStructureArtistPremiumTrialRequest(): void
     {
@@ -431,7 +431,7 @@ class ShopServiceTest extends TestCase
             ->with(ShopRequest::class, $token)
             ->willReturn($shopRequest);
 
-        $trialRequest = $this->getMockBuilder(\App\ApiResources\Shop\NewStructureArtistPremiumTrialRequest::class)
+        $trialRequest = $this->getMockBuilder(NewStructureArtistPremiumTrialRequest::class)
             ->getMock();
 
         $this->serializer
@@ -455,13 +455,13 @@ class ShopServiceTest extends TestCase
 
         $this->logger->expects(self::once())
             ->method('info')
-            ->with('Successfully processed NewStructureArtistPremiumTrial for token: ' . $token);
+            ->with('Successfully processed NewStructureArtistPremiumTrial for token: '.$token);
 
         $shopService->handleNewStructureArtistPremiumTrialRequest($token);
     }
 
     /**
-     * Test handleNewStructureArtistPremiumTrialRequest method with non-existent token
+     * Test handleNewStructureArtistPremiumTrialRequest method with non-existent token.
      */
     public function testHandleNewStructureArtistPremiumTrialRequestWithNonExistentToken(): void
     {
@@ -480,7 +480,7 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test createOrganization method
+     * Test createOrganization method.
      */
     public function testCreateOrganization(): void
     {
@@ -537,7 +537,7 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test generateSubdomain method
+     * Test generateSubdomain method.
      */
     public function testGenerateSubdomain(): void
     {
@@ -564,7 +564,7 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test validateNewStructureArtistPremiumTrialRequest method with valid data
+     * Test validateNewStructureArtistPremiumTrialRequest method with valid data.
      */
     public function testValidateNewStructureArtistPremiumTrialRequest(): void
     {
@@ -604,7 +604,7 @@ class ShopServiceTest extends TestCase
     }
 
     /**
-     * Test validateNewStructureArtistPremiumTrialRequest method with invalid phone number
+     * Test validateNewStructureArtistPremiumTrialRequest method with invalid phone number.
      */
     public function testValidateNewStructureArtistPremiumTrialRequestWithInvalidPhoneNumber(): void
     {