Przeglądaj źródła

Merge branch 'feature/v8-3367' into develop

Olivier Massot 3 lat temu
rodzic
commit
19e2644ec5
75 zmienionych plików z 3849 dodań i 4048 usunięć
  1. 1 1
      src/ApiResources/Dolibarr/DolibarrContractLine.php
  2. 2 2
      src/DataProvider/Utils/SiretDataProvider.php
  3. 4 0
      src/Enum/Cotisation/AlertStateEnum.php
  4. 1 0
      src/Enum/Education/AdvancedEducationNotationTypeEnum.php
  5. 3 1
      src/Enum/Education/TypeCriteriaEnum.php
  6. 1 0
      src/Enum/Network/NetworkEnum.php
  7. 1 0
      src/Enum/Organization/OrganizationIdsEnum.php
  8. 8 0
      src/Enum/Organization/PrincipalTypeEnum.php
  9. 5 0
      src/Enum/Organization/SettingsProductEnum.php
  10. 2 3
      src/Service/Access/Utils.php
  11. 13 8
      src/Service/Constraint/DateTimeConstraint.php
  12. 1 1
      src/Service/Core/AddressPostalUtils.php
  13. 3 6
      src/Service/Cotisation/Utils.php
  14. 3 3
      src/Service/Dolibarr/DolibarrAccountCreator.php
  15. 1 1
      src/Service/Dolibarr/DolibarrApiService.php
  16. 38 33
      src/Service/Dolibarr/DolibarrSyncService.php
  17. 27 15
      src/Service/Education/EducationNotationUtils.php
  18. 1 1
      src/Service/Export/Encoder/PdfEncoder.php
  19. 3 3
      src/Service/Export/LicenceCmfExporter.php
  20. 19 8
      src/Service/Mobyt/MobytService.php
  21. 8 1
      src/Service/Mobyt/MobytUserStatusCreator.php
  22. 3 3
      src/Service/Network/Tree.php
  23. 8 8
      src/Service/Network/Utils.php
  24. 18 10
      src/Service/OnChange/Organization/OnParametersChange.php
  25. 4 1
      src/Service/Organization/OrganizationProfileCreator.php
  26. 23 19
      src/Service/Organization/Utils.php
  27. 3 2
      src/Service/Security/SwitchUser.php
  28. 2 2
      src/Service/Utils/ArrayUtils.php
  29. 2 3
      src/Service/Utils/GpsCoordinateUtils.php
  30. 2 2
      src/Service/Utils/Siret.php
  31. 323 79
      tests/Service/Access/AccessProfileCreatorTest.php
  32. 52 32
      tests/Service/Access/AdminAccessUtilsTest.php
  33. 78 69
      tests/Service/Access/UtilsTest.php
  34. 167 0
      tests/Service/Constraint/AbstractTimeConstraintsUtilsTest.php
  35. 82 132
      tests/Service/Constraint/DateTimeConstraintTest.php
  36. 37 19
      tests/Service/Core/ContactPointUtilsTest.php
  37. 15 10
      tests/Service/Cotisation/CotisationCreatorTest.php
  38. 225 234
      tests/Service/Cotisation/UtilsTest.php
  39. 152 82
      tests/Service/Dolibarr/DolibarrAccountCreatorTest.php
  40. 165 55
      tests/Service/Dolibarr/DolibarrApiServiceTest.php
  41. 660 287
      tests/Service/Dolibarr/DolibarrSyncServiceTest.php
  42. 0 542
      tests/Service/Dolibarr/fixtures/bills.json
  43. 0 442
      tests/Service/Dolibarr/fixtures/contacts.json
  44. 0 187
      tests/Service/Dolibarr/fixtures/contract.json
  45. 0 798
      tests/Service/Dolibarr/fixtures/thirdparties.json
  46. 0 135
      tests/Service/Dolibarr/fixtures/thirdparty.json
  47. 169 32
      tests/Service/Education/EducationNotationUtilsTest.php
  48. 35 16
      tests/Service/Export/Encoder/PdfEncoderTest.php
  49. 134 59
      tests/Service/Export/LicenceCmfExporterTest.php
  50. 46 38
      tests/Service/MailHubTest.php
  51. 76 56
      tests/Service/Mobyt/MobytServiceTest.php
  52. 26 20
      tests/Service/Mobyt/MobytUserStatusCreatorTest.php
  53. 0 14
      tests/Service/Mobyt/fixtures/user_status.json
  54. 41 36
      tests/Service/Network/TreeTest.php
  55. 203 54
      tests/Service/Network/UtilsTest.php
  56. 5 3
      tests/Service/OnChange/OnChangeDefaultTest.php
  57. 51 24
      tests/Service/OnChange/Organization/OnOrganizationChangeTest.php
  58. 217 111
      tests/Service/OnChange/Organization/OnParametersChangeTest.php
  59. 36 40
      tests/Service/OnChange/Organization/OnSubdomainChangeTest.php
  60. 140 56
      tests/Service/Organization/OrganizationProfileCreatorTest.php
  61. 130 78
      tests/Service/Organization/UtilsTest.php
  62. 34 21
      tests/Service/Rest/ApiRequestServiceTest.php
  63. 19 13
      tests/Service/Rest/Operation/BaseRestOperationTest.php
  64. 4 2
      tests/Service/Rest/Operation/CreateOperationTest.php
  65. 24 10
      tests/Service/Security/ModuleTest.php
  66. 19 22
      tests/Service/Security/SwitchUserTest.php
  67. 7 2
      tests/Service/ServiceIterator/CurrentAccessExtensionIteratorTest.php
  68. 13 4
      tests/Service/ServiceIterator/EncoderIteratorTest.php
  69. 13 4
      tests/Service/ServiceIterator/ExporterIteratorTest.php
  70. 29 7
      tests/Service/ServiceIterator/OptionalsRolesIteratorTest.php
  71. 7 2
      tests/Service/Storage/TemporaryFileStorageTest.php
  72. 48 29
      tests/Service/Typo3/Typo3ServiceTest.php
  73. 9 7
      tests/Service/Utils/ArrayUtilsTest.php
  74. 106 34
      tests/Service/Utils/GpsCoordinateUtilsTest.php
  75. 42 14
      tests/Service/Utils/SiretTest.php

+ 1 - 1
src/ApiResources/Dolibarr/DolibarrContractLine.php

@@ -108,7 +108,7 @@ class DolibarrContractLine implements ApiResourcesInterface
         return $this;
     }
 
-    public function isDateEnd(): ?\DateTimeInterface
+    public function getDateEnd(): ?\DateTimeInterface
     {
         return $this->dateEnd;
     }

+ 2 - 2
src/DataProvider/Utils/SiretDataProvider.php

@@ -28,7 +28,7 @@ final class SiretDataProvider implements ItemDataProviderInterface, RestrictedDa
     {
         $siretResponse = new Siret();
         $siretResponse->setNumber($id);
-        $siretResponse->setIsCorrect($this->siretUtils->isSiretIsCorrect($id));
+        $siretResponse->setIsCorrect($this->siretUtils->isSiretCorrect($id));
         return $siretResponse;
     }
-}
+}

+ 4 - 0
src/Enum/Cotisation/AlertStateEnum.php

@@ -7,6 +7,10 @@ use MyCLabs\Enum\Enum;
 
 /**
  * état des alertes des cotisations disponibles.
+ * @method static AFFILIATION()
+ * @method static INSURANCE()
+ * @method static INVOICE()
+ * @method static ADVERTISINGINSURANCE()
  */
 class AlertStateEnum extends Enum
 {

+ 1 - 0
src/Enum/Education/AdvancedEducationNotationTypeEnum.php

@@ -7,6 +7,7 @@ use MyCLabs\Enum\Enum;
 
 /**
  * Type possible sur lesquels les grilles péda doivent se baser
+ * @method static BY_TEACHER()
  */
 class AdvancedEducationNotationTypeEnum extends Enum
 {

+ 3 - 1
src/Enum/Education/TypeCriteriaEnum.php

@@ -8,10 +8,12 @@ use MyCLabs\Enum\Enum;
 
 /**
  * Type de critère possible pour les notations
+ * @method static WITH_NOTATION()
+ * @method static WITHOUT_NOTATION()
  */
 class TypeCriteriaEnum extends Enum
 {
     private const WITH_NOTATION   = 'WITH_NOTATION';
     private const CUSTOM_NOTATION  = 'CUSTOM_NOTATION';
     private const WITHOUT_NOTATION   = 'WITHOUT_NOTATION';
-}
+}

+ 1 - 0
src/Enum/Network/NetworkEnum.php

@@ -9,6 +9,7 @@ use MyCLabs\Enum\Enum;
  * Liste des réseaux disponibles
  * @method static CMF()
  * @method static FFEC()
+ * @method static CFBF()
  */
 class NetworkEnum extends Enum
 {

+ 1 - 0
src/Enum/Organization/OrganizationIdsEnum.php

@@ -9,6 +9,7 @@ use MyCLabs\Enum\Enum;
  * Id de structure spécifiques
  * @method static CMF()
  * @method static FFEC()
+ * @method static _2IOS()
  */
 class OrganizationIdsEnum extends Enum
 {

+ 8 - 0
src/Enum/Organization/PrincipalTypeEnum.php

@@ -7,6 +7,14 @@ use MyCLabs\Enum\Enum;
 
 /**
  * Types principaux d'une organisation
+ * @method static DELEGATION()
+ * @method static GROUPMENT()
+ * @method static LOCAL_FEDERATION()
+ * @method static DEPARTEMENTAL_FEDERATION()
+ * @method static REGIONAL_FEDERATION()
+ * @method static NATIONAL_FEDERATION()
+ * @method static ARTISTIC_EDUCATION_ONLY()
+ * @method static ARTISTIC_PRACTICE_ONLY()
  */
 class PrincipalTypeEnum extends Enum
 {

+ 5 - 0
src/Enum/Organization/SettingsProductEnum.php

@@ -8,6 +8,11 @@ use MyCLabs\Enum\Enum;
 /**
  * Type de produit disponible pour une organisation
  * @method static SCHOOL()
+ * @method static ARTIST()
+ * @method static MANAGER()
+ * @method static MANAGER_PREMIUM()
+ * @method static ARTIST_PREMIUM()
+ * @method static SCHOOL_PREMIUM()
  */
 class SettingsProductEnum extends Enum
 {

+ 2 - 3
src/Service/Access/Utils.php

@@ -17,8 +17,6 @@ use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
  */
 class Utils
 {
-    // TODO: Renommer en AccessUtils
-
     public function __construct(
         private RoleHierarchyInterface $roleHierarchy,
         private AccessRepository $accessRepository,
@@ -32,6 +30,7 @@ class Utils
      * @param Access $access
      * @return array
      * @see UtilsTest::testFilterAccesses()
+     * TODO: est-ce qu'on essaierait pas de trouver un nom plus explicite? j'ai pas trop d'idée la tout de suite cela dit
      */
     public function filterAccesses(array $accesses, Access $access): array {
         return array_filter($accesses, function($a) use($access){
@@ -48,7 +47,7 @@ class Utils
      * @see UtilsTest::testHasRoles()
      */
     public function hasRoles(Access $access, string $roleToHave): bool{
-        return in_array($roleToHave, $this->getAllRoles($access));
+        return in_array($roleToHave, $this->getAllRoles($access), true);
     }
 
     /**

+ 13 - 8
src/Service/Constraint/DateTimeConstraint.php

@@ -7,6 +7,7 @@ use App\Entity\Access\Access;
 use App\Service\Organization\Utils as OrganizationUtils;
 use App\Tests\Service\Constraint\DateTimeConstraintTest;
 use Doctrine\ORM\EntityManagerInterface;
+use JetBrains\PhpStorm\ArrayShape;
 
 /**
  * Classe DateTimeConstraint qui définie les dates de débuts et fin de périodes
@@ -45,7 +46,7 @@ class DateTimeConstraint extends AbstractTimeConstraintUtils
             $periods = $this->getPeriods($access);
             if($historical['present']) $contraints = $this->addConstraint($contraints, $this->presentConstraint($periods));
             if($historical['past']) $contraints = $this->addConstraint($contraints, $this->pastConstraint($periods));
-            if($historical['future']) $contraints = $this->addConstraint($contraints, $this->futurConstraint($periods));
+            if($historical['future']) $contraints = $this->addConstraint($contraints, $this->futureConstraint($periods));
         }
         return $this->cleanConstraints($contraints);
     }
@@ -65,18 +66,20 @@ class DateTimeConstraint extends AbstractTimeConstraintUtils
 
     /**
      * Fonction permettant de récupérer les périodes de début et de fin d'affichage
+     *
      * @param Access $access
      * @return array
      * @throws \Exception
      * @see DateTimeConstraintTest::testGetPeriodsToday()
      */
-    private function getPeriods(Access $access): array{
+    private function getPeriods(Access $access): array {
         $organization = $access->getOrganization();
         $activityYear = $access->getActivityYear();
         $currentActivityYear = $this->organizationUtils->getOrganizationCurrentActivityYear($organization);
 
         $periods = $this->organizationUtils->getActivityPeriodsSwitchYear($organization, $activityYear);
-        //Si l'année courante est l'année d'affichage choisie par l'utilisateur, alors la date de début est aujourd'hui
+
+        // Si l'année courante est l'année d'affichage choisie par l'utilisateur, alors la date de début est aujourd'hui
         if($activityYear === $currentActivityYear){
             $today = new \DateTime('now');
             $periods[OrganizationUtils::START_DATE_KEY] = $today->format('Y-m-d');
@@ -90,11 +93,13 @@ class DateTimeConstraint extends AbstractTimeConstraintUtils
      *  - la date de début est plus petite ou égale (<=) à la date de fin de période à afficher
      * ET
      *  - la date de fin est plus grande ou égale (>=) à la date de fin de période à afficher OU que la date de fin n'est pas remplie (NULL)
-     * @param $periods
+     *
+     * @param array $periods
      * @return array
+     *
      * @see DateTimeConstraintTest::testPresentConstrain()
      */
-    private function presentConstraint(array $periods): array{
+    private function presentConstraint(array $periods): array {
         return [
           self::START_KEY => [
               $periods[OrganizationUtils::END_DATE_KEY] => self::INF + self::EQUAL
@@ -107,7 +112,7 @@ class DateTimeConstraint extends AbstractTimeConstraintUtils
     }
 
     /**
-     * Une période est dans le passée si :
+     * Une période est dans le passé si :
      * - la date de fin est plus petite (<) que la date de début de période à afficher
      * @param $periods
      * @return array
@@ -122,13 +127,13 @@ class DateTimeConstraint extends AbstractTimeConstraintUtils
     }
 
     /**
-     * Une période est dans le future si :
+     * Une période est dans le futur si :
      * - la date de début est plus grande (>) que la date de fin de période à afficher
      * @param $periods
      * @return array
      * @see DateTimeConstraintTest::testFuturConstrain()
      */
-    private function futurConstraint($periods): array{
+    private function futureConstraint($periods): array{
         return [
             self::START_KEY => [
                 $periods[OrganizationUtils::END_DATE_KEY] => self::SUP

+ 1 - 1
src/Service/Core/AddressPostalUtils.php

@@ -13,7 +13,7 @@ class AddressPostalUtils
      * @param string $separator
      * @return string
      */
-    public static function getFullStreetAddress(AddressPostal $addressPostal, string $separator = "\n"): string {
+    public function getFullStreetAddress(AddressPostal $addressPostal, string $separator = "\n"): string {
         return implode($separator, array_filter([
             trim($addressPostal->getStreetAddress()),
             trim($addressPostal->getStreetAddressSecond()),

+ 3 - 6
src/Service/Cotisation/Utils.php

@@ -17,20 +17,17 @@ use App\Service\Network\Utils as NetworkUtils;
  */
 class Utils
 {
-    // TODO: Renommer en CotisationUtils
-
     const MEMBERSHIP_WAITING = 495; // Affiliation in progress
     const MEMBERSHIP_NOPAYMENT = 517; // Waiting paiement
     const SUBMIT_IN_PROGRESS = 540; // Affiliation in progress
 
-    function __construct(
+    public function __construct(
         private NetworkUtils                     $networkUtils,
         private OrganizationUtils                $organizationUtils,
         private NetworkOrganizationRepository    $networkOrganizationRepository,
         private CotisationApiResourcesRepository $cotisationApiResourcesRepository
     )
-    {
-    }
+    {}
 
     /**
      * Test si l'organisation est un dernier parent ET appartient à la CMF.
@@ -84,7 +81,7 @@ class Utils
      */
     public function isManagerAndNotLastParentAndCMF(Organization $organization): bool
     {
-        return $this->organizationUtils->isManager($organization) && !$this->isLastParentAndCMF($organization);
+        return $this->organizationUtils->isManager($organization) && !$this->networkOrganizationRepository->isLastParent($organization) && $this->networkUtils->isCMF($organization);
     }
 
 

+ 3 - 3
src/Service/Dolibarr/DolibarrAccountCreator.php

@@ -83,8 +83,8 @@ class DolibarrAccountCreator
                     ->setContractId((int)$lineData['fk_contrat'])
                     ->setServiceRef($lineData['product_ref'])
                     ->setServiceLabel($lineData['product_label'])
-                    ->setDateStart(new \DateTime(date('c', $lineData['date_start'])))
-                    ->setDateEnd(new \DateTime(date('c', $lineData['date_end'])));
+                    ->setDateStart(new \DateTime(date('c', (int)$lineData['date_start'])))
+                    ->setDateEnd(new \DateTime(date('c', (int)$lineData['date_end'])));
     }
 
     public function createDolibarrBill(array $billData): DolibarrBill {
@@ -93,7 +93,7 @@ class DolibarrAccountCreator
                     ->setRef($billData['ref'])
                     ->setTaxExcludedAmount((float)$billData['total_ht'])
                     ->setTaxIncludedAmount((float)$billData['total_ttc'])
-                    ->setDate(new \DateTime(date('c', $billData['date'])))
+                    ->setDate(new \DateTime(date('c', (int)$billData['date'])))
                     ->setPaid((bool)$billData['paye']);
     }
 }

+ 1 - 1
src/Service/Dolibarr/DolibarrApiService.php

@@ -80,7 +80,7 @@ class DolibarrApiService extends ApiRequestService
      * Get all the societies which are Opentalent client
      * @throws HttpException
      */
-    public function getAllClients(bool $withContract = false): array
+    public function getAllClients(): array
     {
         return $this->getJsonContent(
             "thirdparties",

+ 38 - 33
src/Service/Dolibarr/DolibarrSyncService.php

@@ -51,6 +51,8 @@ class DolibarrSyncService
         private AccessRepository $accessRepository,
         private FunctionTypeRepository $functionTypeRepository,
         private DolibarrApiService $dolibarrApiService,
+        private AddressPostalUtils $addressPostalUtils,
+        private ArrayUtils $arrayUtils,
         private TranslatorInterface $translator,
         private LoggerInterface $logger
     ) {}
@@ -63,10 +65,12 @@ class DolibarrSyncService
      *
      * Returns an array of DolibarrSyncOperations
      *
-     * @var callable | null $progressionCallback A callback method for indicating the current progression of the process;
-     *                                           Shall accept two integer arguments: current progression, and total.
      * @return array<BaseRestOperation>
      * @throws Exception
+     * @var callable | null $progressionCallback A callback method for indicating the current progression of the process;
+     *                                           Shall accept two integer arguments: current progression, and total.
+     *
+     * @noinspection NullPointerExceptionInspection
      */
     public function scan(?callable $progressionCallback = null): array {
         $this->logger->info("-- Scan started --");
@@ -92,11 +96,15 @@ class DolibarrSyncService
         $operations = [];
         $i = 0; $total = count($dolibarrClientsIndex);
         foreach ($dolibarrClientsIndex as $organizationId => $dolibarrSociety) {
-            $dolibarrSociety = self::sanitizeDolibarrData($dolibarrSociety);
+            $dolibarrSociety = $this->sanitizeDolibarrData($dolibarrSociety);
 
             $organization = $this->organizationRepository->find($organizationId);
             if ($organization === null) {
                 $this->logger->error("Organization " . $organizationId . " not found in the Opentalent DB");
+                $i++;
+                if ($progressionCallback !== null) {
+                    $progressionCallback($i, $total);
+                }
                 continue;
             }
 
@@ -112,7 +120,7 @@ class DolibarrSyncService
             // Sync contact data of the client
             $mainAddress = $this->getOrganizationPostalAddress($organization);
             if ($mainAddress !== null) {
-                $streetAddress = AddressPostalUtils::getFullStreetAddress($mainAddress);
+                $streetAddress = $this->addressPostalUtils->getFullStreetAddress($mainAddress);
                 if (trim($mainAddress->getAddressOwner() ?? '') !== '') {
                     $streetAddress = $mainAddress->getAddressOwner() . "\n" . $streetAddress;
                 }
@@ -145,14 +153,14 @@ class DolibarrSyncService
             $product = $organization->getSettings()->getProduct();
             if (SettingsProductEnum::isSchool($product)) {
                 $infos[] = $this->translator->trans('STUDENTS_COUNT') . " : " .
-                    self::countWithMission([FunctionEnum::STUDENT()->getValue()], $organizationMembers);
+                    $this->countWithMission([FunctionEnum::STUDENT()->getValue()], $organizationMembers);
             }
             if (SettingsProductEnum::isSchool($product) || SettingsProductEnum::isArtist($product)) {
                 $infos[] = $this->translator->trans('ADHERENTS_COUNT') . " : " .
-                    self::countWithMission([FunctionEnum::ADHERENT()->getValue()], $organizationMembers);
+                    $this->countWithMission([FunctionEnum::ADHERENT()->getValue()], $organizationMembers);
             }
             $infos[] = $this->translator->trans('ADMIN_ACCESS_COUNT') . " : " .
-                self::countWithMission($adminMissions, $organizationMembers);
+                $this->countWithMission($adminMissions, $organizationMembers);
 
             // /!\ On est forcé de passer la sub-array entière pour mettre à jour le champ modifié, sinon
             //     tous les autres champs seront passés à null...
@@ -166,7 +174,7 @@ class DolibarrSyncService
             $newSocietyData['status'] = '1';
 
             // Only update the fields that are different (it's important to let it non-recursive, the subarray have to be passed entirely)
-            $newSocietyData = ArrayUtils::getChanges(
+            $newSocietyData = $this->arrayUtils->getChanges(
                 $dolibarrSociety,
                 $newSocietyData,
                 false,
@@ -197,24 +205,18 @@ class DolibarrSyncService
                 $access = $this->accessRepository->find($accessId);
                 $person = $access?->getPerson();
 
-                if ($person === null) // this should not happen, but is expected by code inspection...
-                { throw new \Exception('Access or person not found'); }
-
                 // Keep track of the contacts seen
-                if (in_array($person->getId(), $contactsProcessed, true)) {
-                    // already updated from another mission
-                    continue;
-                }
                 $contactsProcessed[] = $person->getId();
 
-                // special: if the contact has no name, ignore it
-                if (!$person->getName() || !$person->getGivenName()) {
+                // special: if the contact hasn't a firstname and a lastname, ignore it
+                if (empty($person->getName()) || empty($person->getGivenName())) {
+                    $this->logger->error("Person " . $person->getId() . " miss a lastname and/or a firstname, ignored.");
                     continue;
                 }
 
                 // Get the matching dolibarr contact
-                $dolibarrContact = self::findDolibarrContactFor($dolibarrSocietyContacts, $person);
-                $dolibarrContact = self::sanitizeDolibarrData($dolibarrContact);
+                $dolibarrContact = $this->findDolibarrContactFor($dolibarrSocietyContacts, $person);
+                $dolibarrContact = $this->sanitizeDolibarrData($dolibarrContact);
 
                 $contact = $this->getPersonContact($person);
 
@@ -224,8 +226,8 @@ class DolibarrSyncService
                     'lastname' => trim($person->getName()),
                     'firstname' => trim($person->getGivenName()),
                     'email' => $contact?->getEmail(),
-                    'phone_pro' => $contact?->getTelphone() ? self::formatPhoneNumber($contact?->getTelphone()) : null,
-                    'phone_mobile' => $contact?->getMobilPhone() ? self::formatPhoneNumber($contact?->getMobilPhone()): null,
+                    'phone_pro' => $contact?->getTelphone() ? $this->formatPhoneNumber($contact?->getTelphone()) : null,
+                    'phone_mobile' => $contact?->getMobilPhone() ? $this->formatPhoneNumber($contact?->getMobilPhone()): null,
                     'poste' => $this->formatContactPosition($missions, $person->getGender()),
                     'statut' => '1'
                 ];
@@ -249,7 +251,7 @@ class DolibarrSyncService
                     );
                 } else {
                     // Only update the fields that are different (it's important to let it non-recursive, the subarray have to be passed entirely)
-                    $newContactData = ArrayUtils::getChanges(
+                    $newContactData = $this->arrayUtils->getChanges(
                         $dolibarrContact,
                         $newContactData,
                         false,
@@ -325,6 +327,10 @@ class DolibarrSyncService
             if ($operation->getStatus() !== $operation::STATUS_READY) {
                 // operation has already been treated
                 $this->logger->warning('Tried to execute an operation that was not marked as ready : ' . $operation);
+                $i++;
+                if ($progressionCallback !== null) {
+                    $progressionCallback($i, $total);
+                }
                 continue;
             }
 
@@ -457,7 +463,7 @@ class DolibarrSyncService
      * @param Person $person
      * @return array|null
      */
-    protected static function findDolibarrContactFor(array $dolibarrContacts, Person $person): ?array {
+    protected function findDolibarrContactFor(array $dolibarrContacts, Person $person): ?array {
         foreach ($dolibarrContacts as $contactData) {
             if (!empty($contactData["array_options"]["options_2iopen_person_id"])) {
                 $id = (int)$contactData["array_options"]["options_2iopen_person_id"];
@@ -492,14 +498,14 @@ class DolibarrSyncService
      * @param array|null $data
      * @return array|null
      */
-    protected static function sanitizeDolibarrData(?array $data): ?array {
+    protected function sanitizeDolibarrData(?array $data): ?array {
         if ($data === null) {
             return null;
         }
 
         foreach ($data as $field => $value) {
             if (is_array($value)) {
-                $data[$field] = self::sanitizeDolibarrData($value);
+                $data[$field] = $this->sanitizeDolibarrData($value);
             } else if ($value === '') {
                 $data[$field] = null;
             }
@@ -555,11 +561,10 @@ class DolibarrSyncService
             foreach ($contactPoints as $contactPoint) {
                 if ($contactPoint->getContactType() === $contactType) {
                     if ($contactPoint->getTelphone() !== null) {
-
-                        return self::formatPhoneNumber($contactPoint->getTelphone());
+                        return $this->formatPhoneNumber($contactPoint->getTelphone());
                     }
                     if ($contactPoint->getMobilPhone() !== null) {
-                        return self::formatPhoneNumber($contactPoint->getMobilPhone());
+                        return $this->formatPhoneNumber($contactPoint->getMobilPhone());
                     }
                 }
             }
@@ -616,7 +621,7 @@ class DolibarrSyncService
      * @param array $members An organization members as returned by getActiveMembersIndex: [$accessID => [$missions...]]
      * @return int
      */
-    protected static function countWithMission(array $missions, array $members): int {
+    protected function countWithMission(array $missions, array $members): int {
         return count(array_filter(
             $members,
             static function ($actualMissions) use ($missions) { return !empty(array_intersect($actualMissions, $missions)); }
@@ -694,7 +699,7 @@ class DolibarrSyncService
      * @param PhoneNumber $phoneNumber
      * @return mixed
      */
-    protected static function formatPhoneNumber(PhoneNumber $phoneNumber): string {
+    protected function formatPhoneNumber(PhoneNumber $phoneNumber): string {
         $phoneUtil = PhoneNumberUtil::getInstance();
         return str_replace(
             ' ',
@@ -728,10 +733,10 @@ class DolibarrSyncService
         }
 
         // Sanitize to get rid of the null / empty strings transformations of the API
-        $updated = self::sanitizeDolibarrData($updated);
-        $responseData = self::sanitizeDolibarrData($responseData);
+        $updated = $this->sanitizeDolibarrData($updated);
+        $responseData = $this->sanitizeDolibarrData($responseData);
 
-        $diffs = ArrayUtils::getChanges($responseData, $updated, true);
+        $diffs = $this->arrayUtils->getChanges($responseData, $updated, true);
 
         if (!empty($diffs)) {
             /** @noinspection JsonEncodingApiUsageInspection */

+ 27 - 15
src/Service/Education/EducationNotationUtils.php

@@ -8,18 +8,19 @@ use App\Enum\Education\TypeCriteriaEnum;
 use App\Test\Service\Access\EducationNotationUtilsTest;
 
 /**
- * Classe EducationNotationUtils qui contiens les fonctions relatives aux évaluations d'un enseignement
+ * Classe EducationNotationUtils qui contient les fonctions relatives aux évaluations d'un enseignement
  */
 class EducationNotationUtils
 {
     /**
-     * Fonction permettant de retrouver la note calculé par rapport à la note maximale possible définie par la structure
+     * Fonction permettant de retrouver la note calculée par rapport à la note maximale possible définie par la structure
      * @param EducationNotation $educationNotation
      * @return float|null
      * @see EducationNotationUtilsTest::testGetNotationTransformed()
      */
-    public function getNotationTransformed(EducationNotation $educationNotation)
+    public function getNotationTransformed(EducationNotation $educationNotation): ?float
     {
+        /** @noinspection NullPointerExceptionInspection */
         $noteMax = $educationNotation->getEducationStudent()->getAccess()->getOrganization()->getParameters()->getAverage();
         return $this->calculNotationByAMaxNote($educationNotation, $noteMax);
     }
@@ -30,26 +31,37 @@ class EducationNotationUtils
      * @return float|null
      * @see EducationNotationUtilsTest::testGetNotationOriginal()
      */
-    public function getNotationOriginal(EducationNotation $educationNotation)
+    public function getNotationOriginal(EducationNotation $educationNotation): ?float
     {
-        if(!$educationNotation->getCriteriaNotation()) return null;
+        if(!$educationNotation->getCriteriaNotation()) {
+            return null;
+        }
         $noteMax = $educationNotation->getCriteriaNotation()->getNoteMax();
         return $this->calculNotationByAMaxNote($educationNotation, $noteMax);
     }
 
     /**
-     * Effectue un ratio de la note sur 100 à la base pour la cacluler par rapport à la note maximale passée en paramètre.
-     * @param $educationNotation
-     * @param $noteMax
+     * Recalcule une note sur 100 par rapport à la nouvelle note maximale passée en paramètre.
+     *
+     * Les notes sont toutes enregistrées sur 100 dans la DB, cette méthode permet de recalculer la note en fonction
+     * de la note maximale de l'école.
+     *
+     * @param EducationNotation $educationNotation
+     * @param float $noteMax
      * @return float|null
      */
-    private function calculNotationByAMaxNote($educationNotation, $noteMax){
-        if(is_null($educationNotation->getNote())) return null;
-        if(!$educationNotation->getCriteriaNotation()) return null;
-        if($educationNotation->getCriteriaNotation()->getType() !== TypeCriteriaEnum::WITH_NOTATION()->getValue()) return null;
+    protected function calculNotationByAMaxNote(EducationNotation $educationNotation, float $noteMax): ?float
+    {
+        if(
+            is_null($educationNotation->getNote()) ||
+            !$educationNotation->getCriteriaNotation() ||
+            $educationNotation->getCriteriaNotation()->getType() !== TypeCriteriaEnum::WITH_NOTATION()->getValue()
+        ) {
+            return null;
+        }
 
-        $note = (float)(($educationNotation->getNote() * $noteMax) / 100);
+        $note = ($educationNotation->getNote() * $noteMax) / 100;
 
-        return round ( $note , 2 );
+        return round ( (float)$note , 2 );
     }
-}
+}

+ 1 - 1
src/Service/Export/Encoder/PdfEncoder.php

@@ -52,7 +52,7 @@ class PdfEncoder implements EncoderInterface
      */
     public function encode(string $html, array $options = []): string
     {
-        $options = array_merge($this->defaultOptions, $options);
+        $options = array_merge($this->getDefaultOptions(), $options);
 
         return $this->knpSnappy->getOutputFromHtml($html, $options);
     }

+ 3 - 3
src/Service/Export/LicenceCmfExporter.php

@@ -22,7 +22,7 @@ class LicenceCmfExporter extends BaseExporter
     /**
      * La couleur de la carte de licence change chaque année, de manière cyclique
      */
-    public const LICENCE_CMF_COLOR_START_YEAR = "2020";
+    public const LICENCE_CMF_COLOR_START_YEAR = 2020;
     public const LICENCE_CMF_COLOR = [0 => '931572', 1 => 'C2981A', 2 =>  '003882', 3 =>  '27AAE1', 4 =>  '2BB673'];
 
     public function __construct(
@@ -40,7 +40,7 @@ class LicenceCmfExporter extends BaseExporter
     {
         $organization = $this->accessRepository->find($exportRequest->getRequesterId())?->getOrganization();
         if ($organization === null) {
-            throw new \RuntimeException('Unable to dermin the organization of the curent user; abort.');
+            throw new \RuntimeException('Unable to determine the organization of the curent user; abort.');
         }
 
         $licenceCmf = new LicenceCmf();
@@ -114,7 +114,7 @@ class LicenceCmfExporter extends BaseExporter
      * @return string
      */
     protected function getLicenceColor(int $year): string {
-        if (!(self::LICENCE_CMF_COLOR_START_YEAR > $year)) {
+        if (!($year > self::LICENCE_CMF_COLOR_START_YEAR)) {
             return self::LICENCE_CMF_COLOR[0];
         }
         return self::LICENCE_CMF_COLOR[($year - self::LICENCE_CMF_COLOR_START_YEAR) % count(self::LICENCE_CMF_COLOR)];

+ 19 - 8
src/Service/Mobyt/MobytService.php

@@ -17,8 +17,9 @@ class MobytService extends ApiRequestService
     private string $userId;
     private string $sessionKey;
 
+    /** @noinspection SenselessProxyMethodInspection */
     #[Pure]
-    function __construct(
+    public function __construct(
         HttpClientInterface $mobyt_client
     )
     {
@@ -32,27 +33,37 @@ class MobytService extends ApiRequestService
      * @param string $password
      * @return void
      */
-    private function connect(string $login, string $password): void
+    protected function connect(string $login, string $password): void
     {
         $responseContent = $this->getContent('login', ['username' => $login, 'password' => $password]);
-        list($this->userId, $this->sessionKey) = explode(';', $responseContent);
+        [$this->userId, $this->sessionKey] = explode(';', $responseContent);
+    }
+
+    protected function getUserId(): string
+    {
+        return $this->userId;
+    }
+
+    protected function getSessionKey(): string
+    {
+        return $this->sessionKey;
     }
 
     /**
-     * Get a mobyt user status by its opentalent organization id
+     * Get a mobyt user status by its opentalent organization login and password
      *
-     * @param int $organizationId
      * @param string $login
      * @param string $password
      * @return array
+     * @throws \JsonException
      */
-    public function getUserStatus(int $organizationId, string $login, string $password): array {
+    public function getUserStatus(string $login, string $password): array {
         $this->connect($login, $password);
         return $this->getJsonContent(
             'status',
             ['getMoney' => 'true', 'typeAliases' => 'true'],
             [
-                'headers' => [ 'user_key' => $this->userId, 'Session_key' => $this->sessionKey ]
+                'headers' => [ 'user_key' => $this->getUserId(), 'Session_key' => $this->getSessionKey() ]
             ]
         );
     }
@@ -69,7 +80,7 @@ class MobytService extends ApiRequestService
     {
         try{
             $this->connect($login, $password);
-        }catch (NotFoundHttpException $exception){
+        }catch (NotFoundHttpException){
             return false;
         }
         return true;

+ 8 - 1
src/Service/Mobyt/MobytUserStatusCreator.php

@@ -12,6 +12,13 @@ class MobytUserStatusCreator
         private OrganizationRepository $organizationRepository,
     ) {}
 
+    /**
+     * Retrieve the status of the user from the Mobyt Api (via MobytService)
+     *
+     * @param int $organizationId
+     * @return MobytUserStatus
+     * @throws \JsonException
+     */
     public function getUserStatus(int $organizationId): MobytUserStatus {
         $userStatus = new MobytUserStatus();
         $userStatus->setOrganizationId($organizationId);
@@ -24,7 +31,7 @@ class MobytUserStatusCreator
             return $userStatus;
         }
 
-        $userStatusData = $this->mobytService->getUserStatus($organizationId, $mobytLogin, $mobytPassword);
+        $userStatusData = $this->mobytService->getUserStatus($mobytLogin, $mobytPassword);
         $userStatus->setActive(true);
         $userStatus->setMoney($userStatusData['money']);
 

+ 3 - 3
src/Service/Network/Tree.php

@@ -29,7 +29,7 @@ class Tree
 
     /**
      * Trie les organisations par rapport à leur type principal :
-     * DELEGATION, GROUPMENT,  LOCAL_FEDERATION, DEPARTEMENTAL_FEDERATION, REGIONAL_FEDERATION, NATIONAL_FEDERATION
+     * DELEGATION, GROUPMENT, LOCAL_FEDERATION, DEPARTEMENTAL_FEDERATION, REGIONAL_FEDERATION, NATIONAL_FEDERATION
      * @param array $organizations
      * @return array
      * @see TreeTest::testSortByType()
@@ -44,10 +44,10 @@ class Tree
             PrincipalTypeEnum::NATIONAL_FEDERATION()
         ];
 
-        usort($organizations, function(Organization $organization1, Organization $organization2) use($typeOrder){
+        usort($organizations, static function(Organization $organization1, Organization $organization2) use($typeOrder) {
             return array_keys($typeOrder, $organization1->getPrincipalType()) <=> array_keys($typeOrder, $organization2->getPrincipalType());
         });
 
         return $organizations;
     }
-}
+}

+ 8 - 8
src/Service/Network/Utils.php

@@ -15,7 +15,6 @@ use App\Tests\Service\Network\UtilsTest;
  */
 class Utils
 {
-    // TODO: Renommer en NetworkUtils
     /**
      * Test si l'organisation appartient au réseau de la CMF
      * @param Organization $organization
@@ -23,7 +22,7 @@ class Utils
      * @see UtilsTest::testIsCmf()
      */
     public function isCMF(Organization $organization): bool {
-        return $this->isOrganizationBelongToTheNetwork($organization, NetworkEnum::CMF());
+        return $this->doesOrganizationBelongToTheNetwork($organization, NetworkEnum::CMF());
     }
 
     /**
@@ -33,23 +32,24 @@ class Utils
      * @see UtilsTest::testIsCmfAndActiveNow()
      */
     public function isCMFAndActiveNow(Organization $organization): bool {
-        return $this->isOrganizationBelongToTheNetwork($organization, NetworkEnum::CMF(), true);
+        return $this->doesOrganizationBelongToTheNetwork($organization, NetworkEnum::CMF(), true);
     }
 
     /**
-     * Test si l'organisation appartient à un réseau
+     * Teste si l'organisation appartient à un réseau
+     *
      * @param Organization $organization
      * @param NetworkEnum $network  id du réseau
-     * @param bool $activeNow  si true, on test en plus l'activité aujourd'hui
+     * @param bool $activeNow  si true, on teste en plus l'activité aujourd'hui
      * @return boolean
      * @see UtilsTest::testIsOrganizationBelongToTheNetwork()
      */
-    public function isOrganizationBelongToTheNetwork(Organization $organization, NetworkEnum $network, ?bool $activeNow = false): bool {
+    public function doesOrganizationBelongToTheNetwork(Organization $organization, NetworkEnum $network, ?bool $activeNow = false): bool {
         $networksOrganizations = $organization->getNetworkOrganizations();
         /** @var NetworkOrganization $networksOrganization */
         foreach ($networksOrganizations as $networksOrganization) {
             if ($networksOrganization->getNetwork()->getId() === $network->getValue()) {
-                return $activeNow ? $this->doesNetworkOrganizationIsActiveNow($networksOrganization) : true;
+                return !$activeNow || $this->isNetworkOrganizationActiveNow($networksOrganization);
             }
         }
         return false;
@@ -61,7 +61,7 @@ class Utils
      * @return bool
      * @throws \Exception
      */
-    public function doesNetworkOrganizationIsActiveNow(NetworkOrganization $networksOrganization): bool{
+    public function isNetworkOrganizationActiveNow(NetworkOrganization $networksOrganization): bool{
         return DatesUtils::isIntervalIsValidNow($networksOrganization->getStartDate(), $networksOrganization->getEndDate());
     }
 }

+ 18 - 10
src/Service/OnChange/Organization/OnParametersChange.php

@@ -32,6 +32,7 @@ class OnParametersChange extends OnChangeDefault
         private MessageBusInterface $messageBus
     ){ }
 
+    /** @noinspection PhpParameterNameChangedDuringInheritanceInspection */
     public function validate($parameters, OnChangeContext $context): void
     {
         // Une structure CMF n'a pas le droit de désactiver son site typo3
@@ -45,8 +46,12 @@ class OnParametersChange extends OnChangeDefault
 
     /**
      * @param Parameters $parameters
+     * @throws \Exception
+     * @noinspection PhpParameterNameChangedDuringInheritanceInspection
      */
-    public function beforeChange($parameters, OnChangeContext $context): void{
+    public function beforeChange($parameters, OnChangeContext $context): void
+    {
+        // Le type de notation a changé
         if(
             $context->previousData() &&
             $context->previousData()->getAdvancedEducationNotationType() !== $parameters->getAdvancedEducationNotationType()
@@ -54,7 +59,7 @@ class OnParametersChange extends OnChangeDefault
             $this->onAdvancedEducationNotationTypeChange($parameters);
         }
 
-        //La date de début d'activité change
+        // La date de début d'activité change
         if(
             $context->previousData() &&
             $context->previousData()->getMusicalDate() !== $parameters->getMusicalDate()
@@ -68,9 +73,11 @@ class OnParametersChange extends OnChangeDefault
 
     /**
      * @param Parameters $parameters
+     * @noinspection PhpParameterNameChangedDuringInheritanceInspection
      */
-    public function onChange($parameters, OnChangeContext $context): void{
-        //La note maximale du suivi pédagogique change
+    public function onChange($parameters, OnChangeContext $context): void
+    {
+        // La note maximale du suivi pédagogique change
         if(
             $context->previousData() &&
             $context->previousData()->getAverage() !== $parameters->getAverage()
@@ -112,20 +119,21 @@ class OnParametersChange extends OnChangeDefault
     }
 
     /**
-     * Si le le type de grilles d'évaluation évolue, il faut "nettoyer" les curriculums/teachers associés au type précédent
+     * Si le type de grilles d'évaluation évolue, il faut "nettoyer" les curriculums/teachers associés au type précédent
+     *
      * @param Parameters $parameters
      * @see OnParametersChangeTest::testOnAdvancedEducationNotationTypeByTeachersChange()
      * @see OnParametersChangeTest::testOnAdvancedEducationNotationTypeByEducationChange()
      */
     public function onAdvancedEducationNotationTypeChange(Parameters $parameters): void {
-        foreach ($parameters->getOrganization()->getEducationNotationConfigs() as $educationNotationConfig){
+        foreach ($parameters->getOrganization()->getEducationNotationConfigs() as $educationNotationConfig) {
             /** @var EducationNotationConfig $educationNotationConfig */
-            if($parameters->getAdvancedEducationNotationType() === AdvancedEducationNotationTypeEnum::BY_TEACHER()->getValue()){
-                foreach ($educationNotationConfig->getEducationCurriculums() as $educationCurriculum){
+            if ($parameters->getAdvancedEducationNotationType() === AdvancedEducationNotationTypeEnum::BY_TEACHER()->getValue()) {
+                foreach ($educationNotationConfig->getEducationCurriculums() as $educationCurriculum) {
                     $educationCurriculum->setEducationNotationConfig(null);
                 }
-            }else{
-                foreach ($educationNotationConfig->getTeachers() as $teacher){
+            } else {
+                foreach ($educationNotationConfig->getTeachers() as $teacher) {
                     $teacher->setEducationNotationConfig(null);
                 }
             }

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

@@ -37,7 +37,10 @@ class OrganizationProfileCreator
         $organizationProfile->setParametersId($organization->getParameters()->getId());
         $organizationProfile->setLegalStatus($organization->getLegalStatus());
         $organizationProfile->setHasChildren($organization->getNetworkOrganizationChildren()->count() > 1);
-        $organizationProfile->setShowAdherentList($organization->getParameters()->getShowAdherentList() && $organization->getPrincipalType() != PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY());
+        $organizationProfile->setShowAdherentList(
+            $organization->getParameters()->getShowAdherentList() &&
+            $organization->getPrincipalType() !== PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY()->getValue()
+        );
 
         foreach ($organization->getNetworkOrganizations() as $networkOrganization){
             $organizationProfile->addNetwork($networkOrganization->getNetwork()->getName());

+ 23 - 19
src/Service/Organization/Utils.php

@@ -11,45 +11,47 @@ use App\Test\Service\Organization\UtilsTest;
 use Doctrine\Common\Collections\Criteria;
 
 /**
- * Class OrganizationUtils : service rassemblant des fonctions d'aides pour les questions se rapportant à l'organisation
- * @package App\Service\Resource
+ * Service rassemblant des fonctions d'aide pour les questions se rapportant à l'organisation
  */
 class Utils
 {
-    // TODO: Renommer en OrganizationUtils
-
-    const START_DATE_KEY = 'dateStart';
-    const END_DATE_KEY = 'dateEnd';
+    public const START_DATE_KEY = 'dateStart';
+    public const END_DATE_KEY = 'dateEnd';
 
     /**
-     * Test si l'organisation est considérée comme une structure == n'a pas un produit manager
+     * Teste si l'organisation est considérée comme une structure == n'a pas un produit manager
+     *
      * @param Organization $organization
      * @return bool
      * @see UtilsTest::testIsStructureTest()
      */
-    public function isStructure(Organization $organization): bool{
-        return $organization->getSettings()->getProduct() != SettingsProductEnum::MANAGER()
-            && $organization->getSettings()->getProduct() != SettingsProductEnum::MANAGER_PREMIUM();
+    public function isStructure(Organization $organization): bool
+    {
+        return $organization->getSettings()->getProduct() !== SettingsProductEnum::MANAGER()->getValue() &&
+               $organization->getSettings()->getProduct() !== SettingsProductEnum::MANAGER_PREMIUM()->getValue();
     }
 
     /**
-     * Test si l'organisation est considérée comme un manager == a un produit manager standard
+     * Teste si l'organisation est considérée comme un manager == a un produit manager standard
+     *
      * @param Organization $organization
      * @return bool
      * @see UtilsTest::testIsManagerTest()
      */
-    public function isManager(Organization $organization): bool{
-        return $organization->getSettings()->getProduct() == SettingsProductEnum::MANAGER();
+    public function isManager(Organization $organization): bool
+    {
+        return $organization->getSettings()->getProduct() === SettingsProductEnum::MANAGER()->getValue();
     }
 
     /**
-     * Test si l'organisation est la structure 2iOpenservice
+     * Teste si l'organisation est la structure 2iOpenservice
      * @param Organization $organization
      * @return bool
      * @see UtilsTest::testIsOrganizationIs2ios()
      */
-    public function isOrganizationIs2ios(Organization $organization): bool{
-        return $this->isOrganizationIdIs($organization, OrganizationIdsEnum::_2IOS());
+    public function is2iosOrganization(Organization $organization): bool
+    {
+        return $this->isOrganizationIdEqualTo($organization, OrganizationIdsEnum::_2IOS());
     }
 
     /**
@@ -58,8 +60,9 @@ class Utils
      * @return bool
      * @see UtilsTest::testIsOrganizationIsCMF()
      */
-    public function isOrganizationIsCMF(Organization $organization): bool{
-        return $this->isOrganizationIdIs($organization, OrganizationIdsEnum::CMF());
+    public function isOrganizationCMF(Organization $organization): bool
+    {
+        return $this->isOrganizationIdEqualTo($organization, OrganizationIdsEnum::CMF());
     }
 
     /**
@@ -68,7 +71,8 @@ class Utils
      * @param OrganizationIdsEnum $organizationIdsEnum
      * @return bool
      */
-    private function isOrganizationIdIs(Organization $organization, OrganizationIdsEnum $organizationIdsEnum){
+    protected function isOrganizationIdEqualTo(Organization $organization, OrganizationIdsEnum $organizationIdsEnum): bool
+    {
         return $organization->getId() === $organizationIdsEnum->getValue();
     }
 

+ 3 - 2
src/Service/Security/SwitchUser.php

@@ -18,7 +18,8 @@ class SwitchUser
      * @return bool
      * @see SwitchUserTest::testIsAllowedToSwitch()
      */
-    public function isAllowedToSwitch(UserInterface $user, UserInterface $user_to_switch):bool{
+    public function isAllowedToSwitch(UserInterface $user, UserInterface $user_to_switch): bool
+    {
         return $user->getChildren()->contains($user_to_switch);
     }
-}
+}

+ 2 - 2
src/Service/Utils/ArrayUtils.php

@@ -19,7 +19,7 @@ class ArrayUtils
      *                                accept two parameters (the values) and return true if the values are equals.
      * @return array
      */
-    public static function getChanges(array $initialArray, array $newArray, bool $recursive = false, ?callable $callback = null): array
+    public function getChanges(array $initialArray, array $newArray, bool $recursive = false, ?callable $callback = null): array
     {
         $changes = [];
         foreach ($newArray as $field => $value) {
@@ -27,7 +27,7 @@ class ArrayUtils
                 $changes[$field] = $value;
             }
             elseif ($recursive && is_array($initialArray[$field]) && is_array($value)) {
-                $newVal = self::getChanges($initialArray[$field], $value, $recursive, $callback);
+                $newVal = $this->getChanges($initialArray[$field], $value, $recursive, $callback);
                 if (!empty($newVal)) {
                     $changes[$field] = $newVal;
                 }

+ 2 - 3
src/Service/Utils/GpsCoordinateUtils.php

@@ -42,8 +42,7 @@ class GpsCoordinateUtils
         }catch(\Exception $e){
             throw new NotFoundHttpException('no_reverse_gps_coordinate', $e, 404);
         }
-
-        return json_decode($response, true);
+        return json_decode($response, true, 512, JSON_THROW_ON_ERROR);
     }
 
     /**
@@ -65,7 +64,7 @@ class GpsCoordinateUtils
             throw new NotFoundHttpException('no_reverse_gps_coordinate', $e, 404);
         }
 
-        return json_decode($response, true);
+        return json_decode($response, true, 512, JSON_THROW_ON_ERROR);
     }
 
     /**

+ 2 - 2
src/Service/Utils/Siret.php

@@ -31,8 +31,8 @@ class Siret
      * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
      * @see SiretTest::testIsSiretIsCorrect()
      */
-    public function isSiretIsCorrect(string $siret): bool {
+    public function isSiretCorrect(string $siret): bool {
         $response = $this->clientSiret->request('GET', $siret);
         return $response->getStatusCode() === Response::HTTP_OK;
     }
-}
+}

+ 323 - 79
tests/Service/Access/AccessProfileCreatorTest.php

@@ -4,139 +4,383 @@ namespace App\Test\Service\Access;
 use App\ApiResources\Profile\AccessProfile;
 use App\ApiResources\Profile\OrganizationProfile;
 use App\Entity\Access\Access;
-use App\Entity\Billing\AccessIntangible;
-use App\Entity\Billing\AccessPayer;
+use App\Entity\Core\File;
 use App\Entity\Organization\Organization;
 use App\Entity\Person\Person;
 use App\Repository\Access\AccessRepository;
 use App\Service\Access\AccessProfileCreator;
-use App\Service\Access\OptionalsRolesIterator;
-use App\Service\Access\Utils;
+use App\Service\Access\Utils as AccessUtils;
 use App\Service\Organization\OrganizationProfileCreator;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\Security\Core\Exception\AuthenticationException;
-use Symfony\Component\Security\Core\Role\RoleHierarchy;
 
 class AccessProfileCreatorTest extends TestCase
 {
-    private Access  $access;
-    private AccessProfileCreator $accessProfileCreator;
-    private mixed $accessRepositoryMock;
+    private MockObject | OrganizationProfileCreator $organizationProfileCreator;
+    private MockObject | AccessRepository $accessRepository;
+    private MockObject | AccessUtils $accessUtils;
+    private MockObject | AccessProfileCreator $accessProfileCreator;
+    private MockObject | AccessProfile $accessProfile;
+    private MockObject | Collection $emptyCollection;
+    private MockObject | Collection $nonEmptyCollection;
+    private MockObject | Organization $organization;
+    private MockObject | Access $access;
+    private MockObject | OrganizationProfile $organizationProfile;
 
     public function setUp():void
     {
-        $person = new Person();
-        $person
-            ->setName('Foo')
-            ->setGivenName('Bar')
-        ;
-
-        $today = new \DateTime();
-        $this->access = new Access();
-        $this->access
-            ->setAdminAccess(true)
-            ->setPerson($person)
-            ->setOrganization(new Organization())
-            ->setActivityYear($today->format('Y'))
-        ;
-
-        $organizationProfileCreatorMock = $this->getMockBuilder(OrganizationProfileCreator::class)->disableOriginalConstructor()->getMock();
-        $organizationProfileCreatorMock
-            ->method('createCompleteOrganizationProfile')
-            ->with($this->access->getOrganization())
-            ->willReturn(new OrganizationProfile());
+        $this->organizationProfileCreator = $this->getMockBuilder(OrganizationProfileCreator::class)->disableOriginalConstructor()->getMock();
+        $this->accessRepository = $this->getMockBuilder(AccessRepository::class)->disableOriginalConstructor()->getMock();
+        $this->accessUtils = $this->getMockBuilder(AccessUtils::class)->disableOriginalConstructor()->getMock();
+
+        $this->emptyCollection = $this->getMockBuilder(Collection::class)->getMock();
+        $this->emptyCollection->method('isEmpty')->willReturn(true);
 
-        $this->accessRepositoryMock = $this->getMockBuilder(AccessRepository::class)->disableOriginalConstructor()->getMock();
-        $accessUtilsMock = $this->getMockBuilder(Utils::class)->disableOriginalConstructor()->getMock();
+        $this->nonEmptyCollection = $this->getMockBuilder(Collection::class)->getMock();
+        $this->nonEmptyCollection->method('isEmpty')->willReturn(false);
 
-        $this->accessProfileCreator = new AccessProfileCreator(
-            $organizationProfileCreatorMock,
-            $this->accessRepositoryMock,
-            $accessUtilsMock
-        );
+        $this->organization = $this->getMockBuilder(Organization::class)->getMock();
+        $this->access = $this->getMockBuilder(Access::class)->getMock();
+        $this->organizationProfile = $this->getMockBuilder(OrganizationProfile::class)->getMock();
+        $this->accessProfile = $this->getMockBuilder(AccessProfile::class)->getMock();
     }
 
     /**
      * @see AccessProfileCreator::getAccessProfile()
      */
     public function testGetAccessProfileFailed(){
-        $this->accessRepositoryMock
+
+        $this->accessProfileCreator = $this
+            ->getMockBuilder(AccessProfileCreator::class)
+            ->setConstructorArgs([$this->organizationProfileCreator, $this->accessRepository, $this->accessUtils])
+            ->setMethodsExcept(['getAccessProfile'])
+            ->getMock();
+
+        $this->accessRepository
             ->method('findAllValidAccesses')
             ->with($this->access)
             ->willReturn([]);
+
         $this->expectException(AuthenticationException::class);
         $this->accessProfileCreator->getAccessProfile($this->access);
     }
 
     /**
-     * @see AccessProfileCreator::createCompleteAccessProfile()
+     * Access valide avec multicompte et famille
+     *
+     * @see AccessProfileCreator::getAccessProfile()
      */
-    public function testCreateCompleteAccessProfile(){
-        $accessProfile = $this->accessProfileCreator->createCompleteAccessProfile($this->access);
-        $this->assertInstanceOf(AccessProfile::class, $accessProfile);
+    public function testGetAccessProfile(): void
+    {
+        $accessProfileCreator = $this
+            ->getMockBuilder(AccessProfileCreator::class)
+            ->setConstructorArgs([$this->organizationProfileCreator, $this->accessRepository, $this->accessUtils])
+            ->setMethodsExcept(['getAccessProfile'])
+            ->getMock();
+
+        $otherAccess1 = $this->getMockBuilder(Access::class)->getMock();
+        $otherAccess2 = $this->getMockBuilder(Access::class)->getMock();
+
+        // Find valid accesses
+        $this->accessRepository
+            ->method('findAllValidAccesses')
+            ->with($this->access)
+            ->willReturn([$this->access, $otherAccess1, $otherAccess2]);
+
+        // create the profile
+        $accessProfileCreator
+            ->expects(self::once())
+            ->method('createCompleteAccessProfile')
+            ->with($this->access)
+            ->willReturn($this->accessProfile);
+
+        // Multi compte
+        $otherOrganization1 = $this->getMockBuilder(Organization::class)->getMock();
+        $otherOrganization2 = $this->getMockBuilder(Organization::class)->getMock();
+
+        $otherAccess1->method('getOrganization')->willReturn($otherOrganization1);
+        $otherAccess2->method('getOrganization')->willReturn($otherOrganization2);
+
+        $otherOrganizationProfile1 = $this->getMockBuilder(OrganizationProfile::class)->getMock();
+        $otherOrganizationProfile2 = $this->getMockBuilder(OrganizationProfile::class)->getMock();
+
+        $this->organizationProfileCreator
+            ->expects(self::exactly(2))
+            ->method('createLightOrganizationProfile')
+            ->willReturnMap(
+                [
+                    [$otherOrganization1, $otherOrganizationProfile1],
+                    [$otherOrganization2, $otherOrganizationProfile2],
+                ]
+            );
+
+        $this->accessUtils
+            ->expects(self::once())
+            ->method('filterAccesses')
+            ->with([$this->access, $otherAccess1, $otherAccess2], $this->access)
+            ->willReturn([$otherAccess1, $otherAccess2]);
+
+        $this->accessProfile
+            ->expects(self::exactly(2))
+            ->method('addMultiAccess')
+            ->withConsecutive(
+                [$otherOrganizationProfile1],
+                [$otherOrganizationProfile2]
+            );
+
+        // Accesses famille
+        $children1 = $this->getMockBuilder(Access::class)->getMock();
+        $children2 = $this->getMockBuilder(Access::class)->getMock();
+        $childrenProfile1 = $this->getMockBuilder(AccessProfile::class)->getMock();
+        $childrenProfile2 = $this->getMockBuilder(AccessProfile::class)->getMock();
+
+        $this->access->expects(self::once())->method('getChildren')->willReturn(new ArrayCollection([$children1, $children2]));
+
+        $accessProfileCreator
+            ->expects(self::exactly(2))
+            ->method('createLightAccessProfile')
+            ->willReturnMap([
+                [$children1, $childrenProfile1],
+                [$children2, $childrenProfile2]
+            ]);
+
+        $this->accessProfile
+            ->expects(self::exactly(2))
+            ->method('addFamilyAccess')
+            ->withConsecutive(
+                [$childrenProfile1],
+                [$childrenProfile2]
+            );
+
+        $accessProfileCreator->getAccessProfile($this->access);
     }
 
     /**
-     * @see AccessProfileCreator::createLightAccessProfile()
+     * Test d'un access en compte switch
+     *
+     * @see AccessProfileCreator::getAccessProfile()
      */
-    public function testCreateLightAccessProfile(){
-        $accessProfile = $this->accessProfileCreator->createLightAccessProfile($this->access);
-        $this->assertInstanceOf(AccessProfile::class, $accessProfile);
+    public function testGetAccessProfileSwitch(): void {
+        $accessProfileCreator = $this
+            ->getMockBuilder(AccessProfileCreator::class)
+            ->setConstructorArgs([$this->organizationProfileCreator, $this->accessRepository, $this->accessUtils])
+            ->setMethodsExcept(['getAccessProfile'])
+            ->getMock();
+
+        $this->accessRepository
+            ->method('findAllValidAccesses')
+            ->with($this->access)
+            ->willReturn([$this->access]);
+
+        $accessProfileCreator
+            ->expects(self::once())
+            ->method('createCompleteAccessProfile')
+            ->with($this->access)
+            ->willReturn($this->accessProfile);
+
+        $this->accessUtils
+            ->expects(self::once())
+            ->method('filterAccesses')
+            ->with([$this->access], $this->access)
+            ->willReturn([]);
+
+        $this->access->method('getChildren')->willReturn(new ArrayCollection([]));
+
+        $originalAccess = $this->getMockBuilder(Access::class)->getMock();
+        $originalAccessProfile = $this->getMockBuilder(AccessProfile::class)->getMock();
+
+        $accessProfileCreator
+            ->expects(self::once())
+            ->method('createLightAccessProfile')
+            ->with($originalAccess)
+            ->willReturn($originalAccessProfile);
+
+        $this->accessProfile->expects(self::once())->method('setOriginalAccess')->with($originalAccessProfile);
+
+        $accessProfileCreator->getAccessProfile($this->access, $originalAccess);
     }
 
-    public function testIsGuardian(){
-        $childrenMock = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
-        $this->access->addChild($childrenMock);
+    /**
+     * Setup mocks for the tests on createCompleteAccessProfile
+     */
+    private function setupCreateCompleteAccessProfile(): void
+    {
+        $this->accessProfileCreator = $this
+            ->getMockBuilder(AccessProfileCreator::class)
+            ->setConstructorArgs([$this->organizationProfileCreator, $this->accessRepository, $this->accessUtils])
+            ->setMethodsExcept(['createCompleteAccessProfile'])
+            ->getMock();
+
+        $this->access->expects(self::once())->method('getAdminAccess')->willReturn(true);
+        $this->access->expects(self::once())->method('getHistorical')->willReturn(['present' => true]);
+        $this->access->expects(self::once())->method('getOrganization')->willReturn($this->organization);
+
+        $this->accessUtils->expects(self::once())->method('getAllRoles')->with($this->access)->willReturn(['FOO']);
 
-        $accessProfile = $this->accessProfileCreator->createCompleteAccessProfile($this->access);
-        $this->assertTrue($accessProfile->getIsGuardian());
+        $this->organizationProfileCreator
+            ->expects(self::once())
+            ->method('createCompleteOrganizationProfile')
+            ->with($this->organization)
+            ->willReturn($this->organizationProfile);
+
+        $this->accessProfile->method('setIsAdminAccess')->willReturnSelf();
+        $this->accessProfile->method('setRoles')->willReturnSelf();
+        $this->accessProfile->method('setHistorical')->willReturnSelf();
+        $this->accessProfile->method('setOrganization')->willReturnSelf();
+        $this->accessProfile->method('setIsGuardian')->willReturnSelf();
+        $this->accessProfile->method('setIsPayor')->willReturnSelf();
+
+        $this->accessProfileCreator
+            ->expects(self::once())
+            ->method('createLightAccessProfile')
+            ->with($this->access)
+            ->willReturn($this->accessProfile);
     }
 
-    public function testIsNotGuardian(){
-        $accessProfile = $this->accessProfileCreator->createCompleteAccessProfile($this->access);
-        $this->assertFalse($accessProfile->getIsGuardian());
+    /**
+     * Default situation: the access is neither guardian nor payer or admin
+     *
+     * @see AccessProfileCreator::createCompleteAccessProfile()
+     */
+    public function testCreateCompleteAccessProfile(): void
+    {
+        $this->setupCreateCompleteAccessProfile();
+
+        $this->access->method('getChildren')->willReturn($this->emptyCollection);
+        $this->access->method('getBillingPayers')->willReturn($this->emptyCollection);
+        $this->access->method('getBillingReceivers')->willReturn($this->emptyCollection);
+        $this->access->method('getAccessIntangibles')->willReturn($this->emptyCollection);
+
+        $this->accessProfile->expects(self::once())->method('setIsAdminAccess')->with(true)->willReturnSelf();
+        $this->accessProfile->expects(self::once())->method('setRoles')->with(['FOO'])->willReturnSelf();
+        $this->accessProfile->expects(self::once())->method('setHistorical')->with(['present' => true])->willReturnSelf();
+        $this->accessProfile->expects(self::once())->method('setOrganization')->with($this->organizationProfile)->willReturnSelf();
+        $this->accessProfile->expects(self::once())->method('setIsGuardian')->with(false)->willReturnSelf();
+        $this->accessProfile->expects(self::once())->method('setIsPayor')->with(false)->willReturnSelf();
+
+        $this->accessProfileCreator->createCompleteAccessProfile($this->access);
     }
 
-    public function testIsPayorWithBillingPayer(){
-        $accessPayerMock = $this->getMockBuilder(AccessPayer::class)->disableOriginalConstructor()->getMock();
-        $this->access->addBillingPayer($accessPayerMock);
+    /**
+     * If the access has children, isGuardian shall be set to true
+     *
+     * @see AccessProfileCreator::createCompleteAccessProfile()
+     */
+    public function testCreateCompleteAccessProfileIsGuardian(): void
+    {
+        $this->setupCreateCompleteAccessProfile();
+
+        $this->access->method('getChildren')->willReturn($this->nonEmptyCollection);
+        $this->access->method('getBillingPayers')->willReturn($this->emptyCollection);
+        $this->access->method('getBillingReceivers')->willReturn($this->emptyCollection);
+        $this->access->method('getAccessIntangibles')->willReturn($this->emptyCollection);
+
+        $this->accessProfile->expects(self::once())->method('setIsGuardian')->with(true)->willReturnSelf();
 
-        $accessProfile = $this->accessProfileCreator->createCompleteAccessProfile($this->access);
-        $this->assertTrue($accessProfile->getIsPayor());
+        $this->accessProfileCreator->createCompleteAccessProfile($this->access);
     }
 
-    public function testIsPayorWithAccessIntangible(){
-        $accessIntangibleMock = $this->getMockBuilder(AccessIntangible::class)->disableOriginalConstructor()->getMock();
-        $this->access->addAccessIntangible($accessIntangibleMock);
+    /**
+     * If the access has billingPayers, isPayor shall be set to true
+     *
+     * @see AccessProfileCreator::createCompleteAccessProfile()
+     */
+    public function testCreateCompleteAccessProfileIsPayorWithBillingPayer(): void
+    {
+        $this->setupCreateCompleteAccessProfile();
+
+        $this->access->method('getChildren')->willReturn($this->emptyCollection);
+        $this->access->method('getBillingPayers')->willReturn($this->nonEmptyCollection);
+        $this->access->method('getBillingReceivers')->willReturn($this->emptyCollection);
+        $this->access->method('getAccessIntangibles')->willReturn($this->emptyCollection);
 
-        $accessProfile = $this->accessProfileCreator->createCompleteAccessProfile($this->access);
-        $this->assertTrue($accessProfile->getIsPayor());
+        $this->accessProfile->expects(self::once())->method('setIsPayor')->with(true)->willReturnSelf();
+
+        $this->accessProfileCreator->createCompleteAccessProfile($this->access);
     }
 
-    public function testIsNotPayor(){
-        $accessProfile = $this->accessProfileCreator->createCompleteAccessProfile($this->access);
-        $this->assertFalse($accessProfile->getIsPayor());
+    /**
+     * If the access has no billingPayers but has AccessIntangible, isPayor shall be set to true
+     *
+     * @see AccessProfileCreator::createCompleteAccessProfile()
+     */
+    public function testCreateCompleteAccessProfileIsPayorWithAccessIntangible(): void
+    {
+        $this->setupCreateCompleteAccessProfile();
+
+        $this->access->method('getChildren')->willReturn($this->emptyCollection);
+        $this->access->method('getBillingPayers')->willReturn($this->emptyCollection);
+        $this->access->method('getBillingReceivers')->willReturn($this->emptyCollection);
+        $this->access->method('getAccessIntangibles')->willReturn($this->nonEmptyCollection);
+
+        $this->accessProfile->expects(self::once())->method('setIsPayor')->with(true)->willReturnSelf();
+
+        $this->accessProfileCreator->createCompleteAccessProfile($this->access);
     }
 
-    public function testIsNotPayorWithAccessIntangibleBecauseChildren(){
-        $accessIntangibleMock = $this->getMockBuilder(AccessIntangible::class)->disableOriginalConstructor()->getMock();
-        $this->access->addAccessIntangible($accessIntangibleMock);
+    /**
+     * If the access has no billingPayers, has AccessIntangible but also have children, isPayor shall be set to false
+     *
+     * @see AccessProfileCreator::createCompleteAccessProfile()
+     */
+    public function testCreateCompleteAccessProfileNotPayorWithAccessIntangibleBecauseChildren(): void
+    {
+        $this->setupCreateCompleteAccessProfile();
+
+        $this->access->method('getChildren')->willReturn($this->nonEmptyCollection);
+        $this->access->method('getBillingPayers')->willReturn($this->emptyCollection);
+        $this->access->method('getBillingReceivers')->willReturn($this->emptyCollection);
+        $this->access->method('getAccessIntangibles')->willReturn($this->nonEmptyCollection);
 
-        $childrenMock = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
-        $this->access->addChild($childrenMock);
+        $this->accessProfile->expects(self::once())->method('setIsPayor')->with(false)->willReturnSelf();
 
-        $accessProfile = $this->accessProfileCreator->createCompleteAccessProfile($this->access);
-        $this->assertFalse($accessProfile->getIsPayor());
+        $this->accessProfileCreator->createCompleteAccessProfile($this->access);
     }
 
-    public function testIsNotPayorWithAccessIntangibleBecauseBillingReceivers(){
-        $accessIntangibleMock = $this->getMockBuilder(AccessIntangible::class)->disableOriginalConstructor()->getMock();
-        $this->access->addAccessIntangible($accessIntangibleMock);
+    /**
+     * @see AccessProfileCreator::createLightAccessProfile()
+     */
+    public function testCreateLightAccessProfile(): void
+    {
+        $accessProfileCreator = $this
+            ->getMockBuilder(AccessProfileCreator::class)
+            ->setConstructorArgs([$this->organizationProfileCreator, $this->accessRepository, $this->accessUtils])
+            ->setMethodsExcept(['createLightAccessProfile'])
+            ->getMock();
+
+        $image = $this->getMockBuilder(File::class)->getMock();
+        $image->expects(self::once())->method('getId')->willReturn(123);
+
+        $person = $this->getMockBuilder(Person::class)->getMock();
+        $person->expects(self::once())->method('getName')->willReturn('Foo');
+        $person->expects(self::once())->method('getGivenName')->willReturn('Bar');
+        $person->expects(self::once())->method('getGender')->willReturn('MR');
+        $person->expects(self::once())->method('getImage')->willReturn($image);
+
+        $this->access->expects(self::once())->method('getId')->willReturn(1);
+        $this->access->method('getOrganization')->willReturn($this->organization);
+        $this->access->method('getPerson')->willReturn($person);
+        $this->access->expects(self::once())->method('getActivityYear')->willReturn(2020);
+        $this->access->expects(self::once())->method('getSuperAdminAccess')->willReturn(false);
+
+        $this->organizationProfileCreator
+            ->expects(self::once())
+            ->method('createLightOrganizationProfile')
+            ->with($this->organization)
+            ->willReturn($this->organizationProfile);
 
-        $accessPayerMock = $this->getMockBuilder(AccessPayer::class)->disableOriginalConstructor()->getMock();
-        $this->access->addBillingReceiver($accessPayerMock);
+        $accessProfile = $accessProfileCreator->createLightAccessProfile($this->access);
 
-        $accessProfile = $this->accessProfileCreator->createCompleteAccessProfile($this->access);
-        $this->assertFalse($accessProfile->getIsPayor());
+        $this->assertEquals(1, $accessProfile->getId());
+        $this->assertEquals('Foo', $accessProfile->getName());
+        $this->assertEquals('Bar', $accessProfile->getGivenName());
+        $this->assertEquals('MR', $accessProfile->getGender());
+        $this->assertEquals(2020, $accessProfile->getActivityYear());
+        $this->assertEquals(123, $accessProfile->getAvatarId());
+        $this->assertEquals(false, $accessProfile->getIsSuperAdminAccess());
+        $this->assertEquals($this->organizationProfile, $accessProfile->getOrganization());
     }
 }

+ 52 - 32
tests/Service/Access/AdminAccessUtilsTest.php

@@ -8,80 +8,100 @@ use App\Entity\Core\ContactPoint;
 use App\Entity\Organization\Organization;
 use App\Entity\Person\Person;
 use App\Service\Access\AdminAccessUtils;
-use App\Service\Access\Utils;
+use App\Service\Access\Utils as AccessUtils;
 use App\Service\Core\ContactPointUtils;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 
 class AdminAccessUtilsTest extends TestCase
 {
-    private Organization $organization;
-    private AdminAccessUtils  $adminAccessUtils;
-    private ContactPointUtils $contactPointUtilsMock;
-    private Utils $accessUtilsMock;
+    private MockObject | Organization $organization;
+    private MockObject | Access $access;
+    private MockObject | ContactPointUtils $contactPointUtils;
+    private MockObject | AccessUtils $accessUtils;
 
     public function setUp():void
     {
-        $this->organization = new Organization();
-
-        $this->accessUtilsMock = $this->getMockBuilder(Utils::class)->disableOriginalConstructor()->getMock();
-        $this->contactPointUtilsMock = $this->getMockBuilder(ContactPointUtils::class)->disableOriginalConstructor()->getMock();
-
-        $this->adminAccessUtils = new AdminAccessUtils(
-            $this->accessUtilsMock,
-            $this->contactPointUtilsMock
-        );
+        $this->organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
+        $this->access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
+        $this->accessUtils = $this->getMockBuilder(AccessUtils::class)->disableOriginalConstructor()->getMock();
+        $this->contactPointUtils = $this->getMockBuilder(ContactPointUtils::class)->disableOriginalConstructor()->getMock();
     }
 
     /**
      * @see AdminAccessUtils::getAdminAccess()
      */
-    public function testGetAdminAccessWithoutAdministrator(){
-        $this->accessUtilsMock
+    public function testGetAdminAccessWithoutAdministrator(): void
+    {
+        $adminAccessUtils = $this->getMockBuilder(AdminAccessUtils::class)
+            ->setConstructorArgs([$this->accessUtils, $this->contactPointUtils])
+            ->setMethodsExcept(['getAdminAccess'])
+            ->getMock();
+
+        $this->accessUtils
             ->method('findAdminFor')
             ->with($this->organization)
             ->willReturn(null);
 
-        $this->assertNull($this->adminAccessUtils->getAdminAccess($this->organization));
+        $returned = $adminAccessUtils->getAdminAccess($this->organization);
+
+        $this->assertNull($returned);
     }
 
     /**
      * @see AdminAccessUtils::getAdminAccess()
      */
     public function testGetAdminAccessWithoutContactPoint(){
-        $administrator = new Access();
+        $adminAccessUtils = $this->getMockBuilder(AdminAccessUtils::class)
+            ->setConstructorArgs([$this->accessUtils, $this->contactPointUtils])
+            ->setMethodsExcept(['getAdminAccess'])
+            ->getMock();
 
-        $this->accessUtilsMock
+        $this->accessUtils
             ->method('findAdminFor')
             ->with($this->organization)
-            ->willReturn($administrator);
+            ->willReturn($this->access);
 
-        $this->contactPointUtilsMock
+        $this->contactPointUtils
             ->method('getPersonContactPointPrincipal')
-            ->with($administrator)
+            ->with($this->access)
             ->willReturn(null);
 
-        $this->assertNull($this->adminAccessUtils->getAdminAccess($this->organization));
+        $returned = $adminAccessUtils->getAdminAccess($this->organization);
+
+        $this->assertNull($returned);
     }
 
     /**
      * @see AdminAccessUtils::getAdminAccess()
      */
     public function testGetAdminAccess(){
-        $person = new Person();
-        $administrator = new Access();
-        $administrator->setPerson($person);
-        $contactPoint = new ContactPoint();
+        $adminAccessUtils = $this->getMockBuilder(AdminAccessUtils::class)
+            ->setConstructorArgs([$this->accessUtils, $this->contactPointUtils])
+            ->setMethodsExcept(['getAdminAccess'])
+            ->getMock();
+
+        $person = $this->getMockBuilder(Person::class)->disableOriginalConstructor()->getMock();
+        $person->method('getUsername')->willReturn('foo');
+
+        $this->access->method('getId')->willReturn(1);
+        $this->access->method('getPerson')->willReturn($person);
 
-        $this->accessUtilsMock
+        $contactPoint = $this->getMockBuilder(ContactPoint::class)->disableOriginalConstructor()->getMock();
+        $contactPoint->method('getEmail')->willReturn('foo@bar.net');
+
+        $this->accessUtils
             ->method('findAdminFor')
             ->with($this->organization)
-            ->willReturn($administrator);
+            ->willReturn($this->access);
 
-        $this->contactPointUtilsMock
+        $this->contactPointUtils
             ->method('getPersonContactPointPrincipal')
-            ->with($administrator)
+            ->with($this->access)
             ->willReturn($contactPoint);
 
-        $this->assertInstanceOf(AdminAccess::class, $this->adminAccessUtils->getAdminAccess($this->organization));
+        $returned = $adminAccessUtils->getAdminAccess($this->organization);
+
+        $this->assertInstanceOf(AdminAccess::class, $returned);
     }
 }

+ 78 - 69
tests/Service/Access/UtilsTest.php

@@ -5,114 +5,123 @@ namespace App\Test\Service\Access;
 use App\Entity\Access\Access;
 use App\Entity\Organization\Organization;
 use App\Repository\Access\AccessRepository;
-use App\Service\Access\HandleOptionalsRoles;
-use App\Service\Access\Utils;
+use App\Service\Access\Utils as AccessUtils;
 use App\Service\ServiceIterator\OptionalsRolesIterator;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\Security\Core\Role\RoleHierarchy;
 
 class UtilsTest extends TestCase
 {
-    private Utils $utils;
-    private AccessRepository $accessRepositoryMock;
+    private MockObject | RoleHierarchy $roleHierarchy;
+    private MockObject | OptionalsRolesIterator $optionalsRolesIterator;
+    private MockObject | AccessRepository $accessRepository;
 
     public function setUp():void
     {
-        $roleHierarchyMock = $this->getMockBuilder(RoleHierarchy::class)->disableOriginalConstructor()->getMock();
-        $roleHierarchyMock
-            ->method('getReachableRoleNames')
-            ->willReturn(["ROLE_A", "ROLE_B"]);
-
-
-        $optionalsRolesIteratorMock = $this->getMockBuilder(OptionalsRolesIterator::class)->disableOriginalConstructor()->getMock();
-        $optionalsRolesIteratorMock
-            ->method('getOptionalsRoles')
-            ->willReturn(["ROLE_OPT"]);
-
-        $this->accessRepositoryMock = $this->getMockBuilder(AccessRepository::class)->disableOriginalConstructor()->getMock();
-
-        $this->utils = new Utils($roleHierarchyMock,  $this->accessRepositoryMock, $optionalsRolesIteratorMock);
+        $this->roleHierarchy = $this->getMockBuilder(RoleHierarchy::class)->disableOriginalConstructor()->getMock();
+        $this->optionalsRolesIterator = $this->getMockBuilder(OptionalsRolesIterator::class)->disableOriginalConstructor()->getMock();
+        $this->accessRepository = $this->getMockBuilder(AccessRepository::class)->disableOriginalConstructor()->getMock();
     }
 
     /**
      * @see Utils::filterAccesses()
      */
-    public function testFilterAccesses(){
-        $accessMock1 = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
-        $accessMock1
-            ->method('getId')
-            ->willReturn(1);
-        $accessesMock[] = $accessMock1;
-        $accessMock2 = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
-        $accessMock2
-            ->method('getId')
-            ->willReturn(2);
-        $accessesMock[] = $accessMock2;
-        $accessMock3 = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
-        $accessMock3
-            ->method('getId')
-            ->willReturn(3);
-        $accessesMock[] = $accessMock3;
-
-        $this->assertCount(2, $this->utils->filterAccesses($accessesMock, $accessMock2));
-    }
+    public function testFilterAccesses(): void
+    {
+        $accessUtils = $this->getMockBuilder(AccessUtils::class)
+            ->setConstructorArgs([$this->roleHierarchy,  $this->accessRepository, $this->optionalsRolesIterator])
+            ->setMethodsExcept(['filterAccesses'])
+            ->getMock();
 
-    /**
-     * @see Utils::hasRoles()
-     */
-    public function testHasRoles(){
-        $accessMock1 = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
-        $accessMock1
-            ->method('getRoles')
-            ->willReturn(['ROLE_A']);
+        $access1 = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
+        $access1->method('getId')->willReturn(1);
+
+        $access2 = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
+        $access2->method('getId')->willReturn(2);
+
+        $access3 = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
+        $access3->method('getId')->willReturn(3);
+
+        $accesses = [$access1, $access2, $access3];
+
+        $result = $accessUtils->filterAccesses($accesses, $access2);
 
-        $this->assertTrue($this->utils->hasRoles($accessMock1, 'ROLE_A'));
+        $this->assertEqualsCanonicalizing(
+            [$access1->getId(), $access3->getId()],
+            array_map(static function ($access) { return $access->getId(); }, $result)
+        );
     }
 
     /**
      * @see Utils::hasRoles()
      */
-    public function testHasNotRoles(){
-        $accessMock1 = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
-        $accessMock1
-            ->method('getRoles')
-            ->willReturn(['ROLE_A']);
+    public function testHasRoles(): void
+    {
+        $accessUtils = $this->getMockBuilder(AccessUtils::class)
+            ->setConstructorArgs([$this->roleHierarchy,  $this->accessRepository, $this->optionalsRolesIterator])
+            ->setMethodsExcept(['hasRoles'])
+            ->getMock();
 
-        $this->assertFalse($this->utils->hasRoles($accessMock1, 'ROLE_X'));
-    }
+        $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
 
+        $accessUtils->method('getAllRoles')->with($access)->willReturn(['ROLE_A']);
+
+        $this->assertTrue($accessUtils->hasRoles($access, 'ROLE_A'));
+        $this->assertFalse($accessUtils->hasRoles($access, 'ROLE_B'));
+    }
 
     /**
      * @see Utils::getAllRoles()
      */
-    public function testGetAllRoles(){
-        $accessMock1 = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
-        $accessMock1
-            ->method('getRoles')
-            ->willReturn(['ROLE_A']);
+    public function testGetAllRoles(): void
+    {
+        $accessUtils = $this->getMockBuilder(AccessUtils::class)
+            ->setConstructorArgs([$this->roleHierarchy,  $this->accessRepository, $this->optionalsRolesIterator])
+            ->setMethodsExcept(['getAllRoles'])
+            ->getMock();
+
+        $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
+        $access->method('getRoles')->willReturn(['ROLE_A']);
+
+        $this->roleHierarchy->method('getReachableRoleNames')->willReturn(["ROLE_A", "ROLE_B"]);
+        $this->optionalsRolesIterator->method('getOptionalsRoles')->willReturn(["ROLE_OPT"]);
 
-        $this->assertEquals(['ROLE_A', 'ROLE_B'], $this->utils->getAllRoles($accessMock1));
+        $this->assertEquals(['ROLE_A', 'ROLE_B'], $accessUtils->getAllRoles($access));
     }
 
     /**
      * @see Utils::findAdminFor()
      */
-    public function testFindAdminFor(){
-        $this->accessRepositoryMock
-            ->method('findOneBy')
-            ->willReturn(new Access());
+    public function testFindAdminFor(): void
+    {
+        $accessUtils = $this->getMockBuilder(AccessUtils::class)
+            ->setConstructorArgs([$this->roleHierarchy,  $this->accessRepository, $this->optionalsRolesIterator])
+            ->setMethodsExcept(['findAdminFor'])
+            ->getMock();
+
+        $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
+        $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
+
+        $this->accessRepository->method('findOneBy')->with(['adminAccess' => true, 'organization' => $organization])->willReturn($access);
 
-        $this->assertNotEmpty($this->utils->findAdminFor(new Organization()));
+        $this->assertNotEmpty($accessUtils->findAdminFor($organization));
     }
 
     /**
      * @see Utils::findAdminFor()
      */
-    public function testFindAdminForNotFound(){
-        $this->accessRepositoryMock
-            ->method('findOneBy')
-            ->willReturn(null);
+    public function testFindAdminForNotFound(): void
+    {
+        $accessUtils = $this->getMockBuilder(AccessUtils::class)
+            ->setConstructorArgs([$this->roleHierarchy,  $this->accessRepository, $this->optionalsRolesIterator])
+            ->setMethodsExcept(['findAdminFor'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
+
+        $this->accessRepository->method('findOneBy')->with(['adminAccess' => true, 'organization' => $organization])->willReturn(null);
 
-        $this->assertNull($this->utils->findAdminFor(new Organization()));
+        $this->assertNull($accessUtils->findAdminFor($organization));
     }
 }

+ 167 - 0
tests/Service/Constraint/AbstractTimeConstraintsUtilsTest.php

@@ -0,0 +1,167 @@
+<?php
+
+namespace App\Tests\Service\Constraint;
+
+use App\Service\Constraint\AbstractTimeConstraintUtils;
+use App\Tests\TestToolsTrait;
+use PHPUnit\Framework\TestCase;
+
+class AbstractTimeConstraintsUtilsTest extends TestCase
+{
+    use TestToolsTrait;
+
+    /**
+     * @throws \ReflectionException
+     * @see DateTimeConstraint::hasCustomPeriods()
+     */
+    public function testHasCustomPeriods(){
+        $historical = ['dateStart' => '2020-09-01', 'dateEnd' => '2021-08-31'];
+
+        $timeConstraintUtils = $this->getMockBuilder(AbstractTimeConstraintUtils::class)
+            ->setConstructorArgs([])
+            ->setMethodsExcept(['hasCustomPeriods'])
+            ->getMock();
+
+        $this->assertTrue($this->invokeMethod($timeConstraintUtils, 'hasCustomPeriods', [$historical]));
+    }
+
+    /**
+     * @throws \ReflectionException
+     * @see DateTimeConstraint::hasCustomPeriods()
+     */
+    public function testHasNotCustomPeriods(){
+        $historical = ['dateStart' => null, 'dateEnd' => null];
+
+        $timeConstraintUtils = $this->getMockBuilder(AbstractTimeConstraintUtils::class)
+            ->setConstructorArgs([])
+            ->setMethodsExcept(['hasCustomPeriods'])
+            ->getMock();
+
+        $this->assertFalse($this->invokeMethod($timeConstraintUtils, 'hasCustomPeriods', [$historical]));
+    }
+
+    /**
+     * @see DateTimeConstraint::addConstraint()
+     */
+    public function testAddConstraint(){
+        $originalConstraint = [
+            'start' => [],
+            'end' => []
+        ];
+        $presentConstraint = [
+            'start' => [
+                '2022-08-31' => 4
+            ],
+            'end' => [
+                '2021-12-20' => 8,
+                'NULL' => 0
+            ]
+        ];
+        $pastConstraint = [
+            'end' => [
+                '2021-12-20' => 1
+            ]
+        ];
+        $constraintAfterStartExpected = [
+            'start' => [
+                '2022-08-31' => [4]
+            ],
+            'end' => [
+                '2021-12-20' => [8],
+                'NULL' => [0]
+            ]
+        ];
+        $constraintAfterEndExpected = [
+            'start' => [
+                '2022-08-31' => [4]
+            ],
+            'end' => [
+                '2021-12-20' => [8, 1],
+                'NULL' => [0]
+            ]
+        ];
+
+        $timeConstraintUtils = $this->getMockBuilder(AbstractTimeConstraintUtils::class)
+            ->setConstructorArgs([])
+            ->setMethodsExcept(['addConstraint'])
+            ->getMock();
+
+        $this->assertEquals($constraintAfterStartExpected, $this->invokeMethod($timeConstraintUtils, 'addConstraint', [$originalConstraint, $presentConstraint]));
+        $this->assertEquals($constraintAfterEndExpected, $this->invokeMethod($timeConstraintUtils, 'addConstraint', [$constraintAfterStartExpected, $pastConstraint]));
+    }
+
+    /**
+     * @see AbstractTimeConstraintUtils::cleanConstraints()
+     */
+    public function testCleanConstraints(): void
+    {
+        $originalConstraint= [
+            'start' => [
+                '2022-08-31' => [5]
+            ],
+            'end' => [
+                '2021-12-20' => [8, 1],
+                'NULL' => [0]
+            ]
+        ];
+        $constraintExpected= [
+            'start' => [
+                '2022-08-31' => [5]
+            ],
+            'end' => []
+        ];
+
+        $timeConstraintUtils = $this->getMockBuilder(AbstractTimeConstraintUtils::class)
+            ->setConstructorArgs([])
+            ->setMethodsExcept(['cleanConstraints'])
+            ->getMock();
+
+        $this->assertEquals($constraintExpected, $this->invokeMethod($timeConstraintUtils, 'cleanConstraints', [$originalConstraint]));
+    }
+
+    /**
+     * @see AbstractTimeConstraintUtils::filterConstraint()
+     */
+    public function testFilterConstraint(): void
+    {
+        $originalStartConstraint= [
+            'start' => [
+                '2021-12-20' => [8, 1],
+                '2022-01-01' => [5]
+            ]
+        ];
+        $startConstraintExpected = [
+            '2022-01-01' => [5]
+        ];
+
+        $timeConstraintUtils = $this->getMockBuilder(AbstractTimeConstraintUtils::class)
+            ->setConstructorArgs([])
+            ->setMethodsExcept(['filterConstraint'])
+            ->getMock();
+
+        $this->assertEquals(
+            $startConstraintExpected,
+            $this->invokeMethod($timeConstraintUtils, 'filterConstraint', [$originalStartConstraint, 'start'])
+        );
+    }
+
+    /**
+     * @see AbstractTimeConstraintUtils::clearNull()
+     */
+    public function testClearNull(): void
+    {
+        $originalEndConstraint= [
+            'end' => [
+                'NULL' => 0
+            ]
+        ];
+        $endConstraintExpected = [];
+
+        $timeConstraintUtils = $this->getMockBuilder(AbstractTimeConstraintUtils::class)
+            ->setConstructorArgs([])
+            ->setMethodsExcept(['clearNull'])
+            ->getMock();
+
+        $this->assertEquals($endConstraintExpected, $this->invokeMethod($timeConstraintUtils, 'clearNull', [$originalEndConstraint, 'end']));
+    }
+}

+ 82 - 132
tests/Service/Constraint/DateTimeConstraintTest.php

@@ -5,22 +5,26 @@ use App\Entity\Access\Access;
 use App\Entity\Organization\Organization;
 use App\Entity\Organization\Parameters;
 use App\Service\Constraint\DateTimeConstraint;
+use App\Service\Organization\Utils as OrganizationUtils;
 use App\Tests\TestToolsTrait;
 use Doctrine\ORM\EntityManagerInterface;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 
+
 class DateTimeConstraintTest extends TestCase
 {
    use TestToolsTrait;
 
-   private DateTimeConstraint $dateTimeConstraint;
+   private MockObject | OrganizationUtils $organizationUtils;
+   private MockObject | EntityManagerInterface $em;
+
    private array $periods;
 
    public function setUp(): void
    {
-       $em = $this->getMockBuilder(EntityManagerInterface::class)->disableOriginalConstructor()->getMock();
-       $organizationUtils = new \App\Service\Organization\Utils();
-       $this->dateTimeConstraint = new DateTimeConstraint($em, $organizationUtils);
+       $this->em = $this->getMockBuilder(EntityManagerInterface::class)->disableOriginalConstructor()->getMock();
+       $this->organizationUtils = $this->getMockBuilder(OrganizationUtils::class)->disableOriginalConstructor()->getMock();
 
        $this->periods = [
            'dateStart' => '2021-12-20',
@@ -31,8 +35,9 @@ class DateTimeConstraintTest extends TestCase
    /**
     * @see DateTimeConstraint::presentConstraint()
     */
-   public function testPresentConstrain(){
-       $constraintExpected = [
+   public function testPresentConstraint(): void
+   {
+       $expected = [
            'start' => [
                '2022-08-31' => 4
            ],
@@ -41,181 +46,126 @@ class DateTimeConstraintTest extends TestCase
                'NULL' => 0
            ]
        ];
-       $this->assertEquals($constraintExpected, $this->invokeMethod($this->dateTimeConstraint, 'presentConstraint', [$this->periods]));
+
+       $dateTimeConstraint = $this->getMockBuilder(DateTimeConstraint::class)
+           ->setConstructorArgs([$this->em, $this->organizationUtils])
+           ->setMethodsExcept(['presentConstraint'])
+           ->getMock();
+
+       $result = $this->invokeMethod($dateTimeConstraint, 'presentConstraint', [$this->periods]);
+
+       $this->assertEquals($expected, $result);
    }
 
     /**
      * @see DateTimeConstraint::pastConstraint()
      */
-    public function testPastConstrain(){
-        $constraintExpected = [
+    public function testPastConstraint(): void
+    {
+        $expected = [
             'end' => [
                 '2021-12-20' => 1
             ]
         ];
-        $this->assertEquals($constraintExpected, $this->invokeMethod($this->dateTimeConstraint, 'pastConstraint', [$this->periods]));
+
+        $dateTimeConstraint = $this->getMockBuilder(DateTimeConstraint::class)
+            ->setConstructorArgs([$this->em, $this->organizationUtils])
+            ->setMethodsExcept(['pastConstraint'])
+            ->getMock();
+
+        $result = $this->invokeMethod($dateTimeConstraint, 'pastConstraint', [$this->periods]);
+
+        $this->assertEquals($expected, $result);
     }
 
     /**
      * @see DateTimeConstraint::futurConstraint()
      */
-    public function testFuturConstrain(){
-        $constraintExpected = [
+    public function testFutureConstraint(): void
+    {
+        $expected = [
             'start' => [
                 '2022-08-31' => 5
             ]
         ];
-        $this->assertEquals($constraintExpected, $this->invokeMethod($this->dateTimeConstraint, 'futurConstraint', [$this->periods]));
-    }
-
-    /**
-     * @see DateTimeConstraint::clearNull()
-     */
-    public function testClearNull(){
-        $originalEndConstraint= [
-            'end' => [
-                'NULL' => 0
-            ]
-        ];
-        $endConstraintExpected = [];
-        $this->assertEquals($endConstraintExpected, $this->invokeMethod($this->dateTimeConstraint, 'clearNull', [$originalEndConstraint, 'end']));
-    }
 
-    /**
-     * @see DateTimeConstraint::filterConstraint()
-     */
-    public function testFilterConstraint(){
-        $originalStartConstraint= [
-            'start' => [
-                '2021-12-20' => [8, 1],
-                '2022-01-01' => [5]
-            ]
-        ];
-        $startConstraintExpected = [
-            '2022-01-01' => [5]
-        ];
-        $this->assertEquals($startConstraintExpected, $this->invokeMethod($this->dateTimeConstraint, 'filterConstraint', [$originalStartConstraint, 'start']));
-    }
+        $dateTimeConstraint = $this->getMockBuilder(DateTimeConstraint::class)
+            ->setConstructorArgs([$this->em, $this->organizationUtils])
+            ->setMethodsExcept(['futureConstraint'])
+            ->getMock();
 
-    /**
-     * @see DateTimeConstraint::cleanConstraints()
-     */
-    public function testCleanConstraints(){
-        $originalConstraint= [
-            'start' => [
-                '2022-08-31' => [5]
-            ],
-            'end' => [
-                '2021-12-20' => [8, 1],
-                'NULL' => [0]
-            ]
-        ];
-        $constraintExpected= [
-            'start' => [
-                '2022-08-31' => [5]
-            ],
-            'end' => []
-        ];
-        $this->assertEquals($constraintExpected, $this->invokeMethod($this->dateTimeConstraint, 'cleanConstraints', [$originalConstraint]));
-    }
+        $result = $this->invokeMethod($dateTimeConstraint, 'futureConstraint', [$this->periods]);
 
-    /**
-     * @see DateTimeConstraint::addConstraint()
-     */
-    public function testAddConstraint(){
-        $originalConstraint = [
-            'start' => [],
-            'end' => []
-        ];
-        $presentConstraint = [
-            'start' => [
-                '2022-08-31' => 4
-            ],
-            'end' => [
-                '2021-12-20' => 8,
-                'NULL' => 0
-            ]
-        ];
-        $pastConstraint = [
-            'end' => [
-                '2021-12-20' => 1
-            ]
-        ];
-        $constraintAfterStartExpected = [
-            'start' => [
-                '2022-08-31' => [4]
-            ],
-            'end' => [
-                '2021-12-20' => [8],
-                'NULL' => [0]
-            ]
-        ];
-        $constraintAfterEndExpected = [
-            'start' => [
-                '2022-08-31' => [4]
-            ],
-            'end' => [
-                '2021-12-20' => [8, 1],
-                'NULL' => [0]
-            ]
-        ];
-        $this->assertEquals($constraintAfterStartExpected, $this->invokeMethod($this->dateTimeConstraint, 'addConstraint', [$originalConstraint, $presentConstraint]));
-        $this->assertEquals($constraintAfterEndExpected, $this->invokeMethod($this->dateTimeConstraint, 'addConstraint', [$constraintAfterStartExpected, $pastConstraint]));
+        $this->assertEquals($expected, $result);
     }
 
     /**
+     * Si l'année courante est l'année d'affichage choisie par l'utilisateur, alors la date de début est aujourd'hui
+     *
      * @throws \ReflectionException
      * @see DateTimeConstraint::getPeriods()
      */
-    public function testGetPeriodsToday(){
+    public function testGetPeriodsToday(): void
+    {
         $today = new \DateTime('now');
 
+        $activityYear = (int)$today->format('Y');
+        if ((int)$today->format('m') < 9) {
+            $activityYear--;
+        }
+
+        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $parameters->method('getMusicalDate')->willReturn(new \DateTime('2000-09-01'));
+
         $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
-        $parameters = new Parameters();
-        $parameters->setMusicalDate(new \DateTime('2000-09-01'));
         $organization->method('getParameters')->willReturn($parameters);
 
         $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
         $access->method('getOrganization')->willReturn($organization);
+        $access->method('getActivityYear')->willReturn(2020);
+
+        $this->organizationUtils->method('getOrganizationCurrentActivityYear')->with($organization)->willReturn(2020);
+        $this->organizationUtils
+            ->method('getActivityPeriodsSwitchYear')
+            ->with($organization, 2020)
+            ->willReturn(['dateStart' => 'YEAR-09-01', 'dateEnd' => ($activityYear + 1) . '-08-31']); // dateStart will be overwritten
 
-        $activityYear = $today->format('Y');
-        if($today->format('m') < 9) $activityYear--;
+        $dateTimeConstraint = $this->getMockBuilder(DateTimeConstraint::class)
+            ->setConstructorArgs([$this->em, $this->organizationUtils])
+            ->setMethodsExcept(['getPeriods'])
+            ->getMock();
 
-        $access->method('getActivityYear')->willReturn(intval($activityYear));
+        $periodExpected = ['dateStart' => $today->format('Y-m-d'), 'dateEnd' => ($activityYear + 1) . '-08-31'];
 
-        $periodExpected = ['dateStart' => $today->format('Y-m-d'), 'dateEnd' => '2022-08-31'];
-        $this->assertEquals($periodExpected, $this->invokeMethod($this->dateTimeConstraint, 'getPeriods', [$access]));
+        $result = $this->invokeMethod($dateTimeConstraint, 'getPeriods', [$access]);
+
+        $this->assertEquals($periodExpected, $result);
     }
 
     /**
      * @throws \ReflectionException
      * @see DateTimeConstraint::getPeriods()
      */
-    public function testGetPeriodsNotToday(){
+    public function testGetPeriodsNotToday(): void
+    {
         $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
 
         $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
         $access->method('getOrganization')->willReturn($organization);
         $access->method('getActivityYear')->willReturn(2020);
-        $periodExpected = ['dateStart' => '2020-09-01', 'dateEnd' => '2021-08-31'];
-        $this->assertEquals($periodExpected, $this->invokeMethod($this->dateTimeConstraint, 'getPeriods', [$access]));
-    }
 
-    /**
-     * @throws \ReflectionException
-     * @see DateTimeConstraint::hasCustomPeriods()
-     */
-    public function testHasCustomPeriods(){
-        $historical = ['dateStart' => '2020-09-01', 'dateEnd' => '2021-08-31'];
-        $this->assertTrue($this->invokeMethod($this->dateTimeConstraint, 'hasCustomPeriods', [$historical]));
-    }
+        $this->organizationUtils->method('getOrganizationCurrentActivityYear')->with($organization)->willReturn(2022);
+        $this->organizationUtils
+            ->method('getActivityPeriodsSwitchYear')
+            ->with($organization, 2020)
+            ->willReturn(['dateStart' => '2020-09-01', 'dateEnd' => '2021-08-31']);
 
-    /**
-     * @throws \ReflectionException
-     * @see DateTimeConstraint::hasCustomPeriods()
-     */
-    public function testHasNotCustomPeriods(){
-        $historical = ['dateStart' => null, 'dateEnd' => null];
-        $this->assertFalse($this->invokeMethod($this->dateTimeConstraint, 'hasCustomPeriods', [$historical]));
+        $dateTimeConstraint = $this->getMockBuilder(DateTimeConstraint::class)
+            ->setConstructorArgs([$this->em, $this->organizationUtils])
+            ->setMethodsExcept(['getPeriods'])
+            ->getMock();
+
+        $periodExpected = ['dateStart' => '2020-09-01', 'dateEnd' => '2021-08-31'];
+        $this->assertEquals($periodExpected, $this->invokeMethod($dateTimeConstraint, 'getPeriods', [$access]));
     }
 }

+ 37 - 19
tests/Service/Core/ContactPointUtilsTest.php

@@ -9,49 +9,67 @@ use App\Enum\Core\ContactPointTypeEnum;
 use App\Repository\Core\ContactPointRepository;
 use App\Service\Access\Utils;
 use App\Service\Core\ContactPointUtils;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 
 class ContactPointUtilsTest extends TestCase
 {
-    private ContactPointUtils $contactPointUtils;
-    private ContactPointRepository $contactPointRepositoryMock;
+    private MockObject | ContactPointRepository $contactPointRepository;
 
     public function setUp():void
     {
-        $this->contactPointRepositoryMock = $this->getMockBuilder(ContactPointRepository::class)->disableOriginalConstructor()->getMock();
-
-        $this->contactPointUtils = new ContactPointUtils($this->contactPointRepositoryMock);
+        $this->contactPointRepository = $this->getMockBuilder(ContactPointRepository::class)->disableOriginalConstructor()->getMock();
     }
 
     /**
      * @see Utils::getPersonContactPointPrincipal()
      */
-    public function testGetPersonContactPointPrincipal(){
-        $person = new Person();
-        $access = new Access();
-        $access->setPerson($person);
+    public function testGetPersonContactPointPrincipal(): void
+    {
+        $person = $this->getMockBuilder(Person::class)->disableOriginalConstructor()->getMock();
+        $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
+        $access->method('getPerson')->willReturn($person);
+
+        $contactPoint = $this->getMockBuilder(ContactPoint::class)->disableOriginalConstructor()->getMock();
 
-        $this->contactPointRepositoryMock
+        $this->contactPointRepository
             ->method('getByTypeAndPerson')
             ->with(ContactPointTypeEnum::PRINCIPAL()->getValue(), $access->getPerson())
-            ->willReturn([new ContactPoint()]);
+            ->willReturn([$contactPoint]);
 
-        $this->assertInstanceOf(ContactPoint::class, $this->contactPointUtils->getPersonContactPointPrincipal($access));
+        $contactPointUtils = $this
+            ->getMockBuilder(ContactPointUtils::class)
+            ->setConstructorArgs([$this->contactPointRepository])
+            ->setMethodsExcept(['getPersonContactPointPrincipal'])
+            ->getMock();
+
+        $this->assertEquals(
+            $contactPoint,
+            $contactPointUtils->getPersonContactPointPrincipal($access)
+        );
     }
 
     /**
      * @see Utils::getPersonContactPointPrincipal()
      */
-    public function testGetPersonContactPointPrincipalNotExist(){
-        $person = new Person();
-        $access = new Access();
-        $access->setPerson($person);
+    public function testGetPersonContactPointPrincipalNotExisting(){
+        $person = $this->getMockBuilder(Person::class)->disableOriginalConstructor()->getMock();
+        $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
+        $access->method('getPerson')->willReturn($person);
 
-        $this->contactPointRepositoryMock
+        $this->contactPointRepository
             ->method('getByTypeAndPerson')
             ->with(ContactPointTypeEnum::PRINCIPAL()->getValue(), $access->getPerson())
             ->willReturn([]);
 
-        $this->assertNull($this->contactPointUtils->getPersonContactPointPrincipal($access));
+        $contactPointUtils = $this
+            ->getMockBuilder(ContactPointUtils::class)
+            ->setConstructorArgs([$this->contactPointRepository])
+            ->setMethodsExcept(['getPersonContactPointPrincipal'])
+            ->getMock();
+
+        $this->assertNull(
+            $contactPointUtils->getPersonContactPointPrincipal($access)
+        );
     }
-}
+}

+ 15 - 10
tests/Service/Cotisation/CotisationCreatorTest.php

@@ -6,32 +6,37 @@ use App\Entity\Organization\Organization;
 use App\Repository\Organization\OrganizationRepository;
 use App\Service\Cotisation\CotisationCreator;
 use App\Service\Cotisation\Utils;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 
 class CotisationCreatorTest extends TestCase
 {
-    private OrganizationRepository $organizationRepository;
-    private Utils $cotisationUtils;
-    private CotisationCreator $cotisationCreator;
+    private MockObject | OrganizationRepository $organizationRepository;
+    private MockObject | Utils $cotisationUtils;
 
     public function setUp():void
     {
         $this->organizationRepository = $this->getMockBuilder(OrganizationRepository::class)->disableOriginalConstructor()->getMock();
         $this->cotisationUtils = $this->getMockBuilder(Utils::class)->disableOriginalConstructor()->getMock();
-
-        $this->cotisationCreator = new CotisationCreator(
-            $this->organizationRepository,
-            $this->cotisationUtils
-        );
     }
 
     public function testGetCotisation() {
+        $cotisationCreator = $this->getMockBuilder(CotisationCreator::class)
+            ->setConstructorArgs([$this->organizationRepository, $this->cotisationUtils])
+            ->setMethodsExcept(['getCotisation'])
+            ->getMock();
+
         $this->cotisationUtils->expects(self::once())->method('getCurrentCotisationYear')->willReturn(2000);
+
         $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
         $this->organizationRepository->expects(self::once())->method('find')->willReturn($organization);
-        $this->cotisationUtils->expects(self::once())->method('getAlertState')->with($organization, 2000);
-        $cotisation = $this->cotisationCreator->getCotisation(1);
+
+        $this->cotisationUtils->expects(self::once())->method('getAlertState')->with($organization, 2000)->willReturn('foo');
+
+        $cotisation = $cotisationCreator->getCotisation(1);
 
         $this->assertEquals(1, $cotisation->getOrganizationId());
+        $this->assertEquals(2000, $cotisation->getCotisationYear());
+        $this->assertEquals('foo', $cotisation->getAlertState());
     }
 }

+ 225 - 234
tests/Service/Cotisation/UtilsTest.php

@@ -6,65 +6,35 @@ use App\Entity\Organization\Organization;
 use App\Enum\Cotisation\AlertStateEnum;
 use App\Repository\Cotisation\CotisationApiResourcesRepository;
 use App\Repository\Network\NetworkOrganizationRepository;
-use App\Service\Cotisation\Utils;
+use App\Service\Cotisation\Utils as CotisationUtils;
 use App\Service\Organization\Utils as OrganizationUtils;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 use \App\Service\Network\Utils as NetworkUtils;
 
 class UtilsTest extends TestCase
 {
-    const MEMBERSHIP_WAITING = 495; // Affiliation in progress
-    const MEMBERSHIP_NOPAYMENT = 517; // Waiting paiement
-    const SUBMIT_IN_PROGRESS = 540; // Affiliation in progress
+    private const MEMBERSHIP_WAITING = 495; // Affiliation in progress
+    private const MEMBERSHIP_NOPAYMENT = 517; // Waiting paiement
+    private const SUBMIT_IN_PROGRESS = 540; // Affiliation in progress
 
-    private NetworkOrganizationRepository $networkOrganizationRepositoryMock;
-    private NetworkUtils $networkUtilsMock;
-    private OrganizationUtils $organizationUtilsMock;
-
-    public function getOrganizationMock(): Organization{
-        $organizationMock = $this->getMockBuilder(Organization::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $organizationMock
-            ->method('getId')
-            ->willReturn(1);
-        return $organizationMock;
-
-    }
-
-    public function getUtilsInstance(){
-        return new Utils(
-            $this->networkUtilsMock,
-            $this->organizationUtilsMock,
-            $this->networkOrganizationRepositoryMock,
-            $this->cotisationApiResourcesRepositoryMock
-        );
-    }
+    private MockObject | NetworkOrganizationRepository $networkOrganizationRepository;
+    private MockObject | NetworkUtils $networkUtils;
+    private MockObject | OrganizationUtils $organizationUtils;
+    private MockObject | CotisationApiResourcesRepository $cotisationApiResourcesRepository;
 
     public function setUp(): void
     {
-        $this->networkOrganizationRepositoryMock =
-            $this
-                ->getMockBuilder(NetworkOrganizationRepository::class)
+        $this->networkOrganizationRepository = $this->getMockBuilder(NetworkOrganizationRepository::class)
                 ->disableOriginalConstructor()
                 ->getMock();
 
-        $this->networkUtilsMock =
-            $this
-                ->getMockBuilder(NetworkUtils::class)
-                ->disableOriginalConstructor()
-                ->getMock();
-
-        $this->organizationUtilsMock =
-            $this
-                ->getMockBuilder(OrganizationUtils::class)
-                ->getMock();
+        $this->networkUtils = $this->getMockBuilder(NetworkUtils::class)->disableOriginalConstructor()->getMock();
+        $this->organizationUtils = $this->getMockBuilder(OrganizationUtils::class)->getMock();
 
-        $this->cotisationApiResourcesRepositoryMock =
-            $this
-                ->getMockBuilder(CotisationApiResourcesRepository::class)
-                ->disableOriginalConstructor()
-                ->getMock();
+        $this->cotisationApiResourcesRepository = $this->getMockBuilder(CotisationApiResourcesRepository::class)
+            ->disableOriginalConstructor()
+            ->getMock();
     }
 
     /**
@@ -72,43 +42,38 @@ class UtilsTest extends TestCase
      */
     public function testIsLastParentAndCMF(): void
     {
-        $organizationMock = $this->getOrganizationMock();
+        $cotisationUtils = $this->getMockBuilder(CotisationUtils::class)
+            ->setConstructorArgs([$this->networkUtils, $this->organizationUtils, $this->networkOrganizationRepository, $this->cotisationApiResourcesRepository])
+            ->setMethodsExcept(['isLastParentAndCMF'])
+            ->getMock();
 
-        $this->networkOrganizationRepositoryMock
-                ->expects($this->once())
-                ->method('isLastParent')
-                ->with($organizationMock)
-                ->willReturn(true);
+        $organization1 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization2 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization3 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization4 = $this->getMockBuilder(Organization::class)->getMock();
 
-        $this->networkUtilsMock
-                ->expects($this->once())
+        $this->networkOrganizationRepository
+                ->method('isLastParent')
+                ->willReturnMap([
+                    [$organization1, true],
+                    [$organization2, true],
+                    [$organization3, false],
+                    [$organization4, false],
+                ]);
+
+        $this->networkUtils
                 ->method('isCMF')
-                ->with($organizationMock)
-                ->willReturn(true);
-
-        $utils = $this->getUtilsInstance();
-        $this->assertTrue($utils->isLastParentAndCMF($organizationMock));
-    }
-
-    /**
-     * @see Utils::isLastParentAndCMF()
-     */
-    public function testIsNotLastParentAndCMF(): void
-    {
-        $organizationMock = $this->getOrganizationMock();
-
-        $this->networkOrganizationRepositoryMock
-            ->expects($this->once())
-            ->method('isLastParent')
-            ->with($organizationMock)
-            ->willReturn(false);
-
-        $this->networkUtilsMock
-            ->expects($this->never())
-            ->method('isCMF');
-
-        $utils = $this->getUtilsInstance();
-        $this->assertFalse($utils->isLastParentAndCMF($organizationMock));
+                ->willReturnMap([
+                    [$organization1, true],
+                    [$organization2, false],
+                    [$organization3, true],
+                    [$organization4, false],
+                ]);
+
+        $this->assertTrue($cotisationUtils->isLastParentAndCMF($organization1));
+        $this->assertFalse($cotisationUtils->isLastParentAndCMF($organization2));
+        $this->assertFalse($cotisationUtils->isLastParentAndCMF($organization3));
+        $this->assertFalse($cotisationUtils->isLastParentAndCMF($organization4));
     }
 
     /**
@@ -116,43 +81,39 @@ class UtilsTest extends TestCase
      */
     public function testIsStructureAndCMF(): void
     {
-        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
-
-        $this->organizationUtilsMock
-            ->expects($this->once())
-            ->method('isStructure')
-            ->with($organizationMock)
-            ->willReturn(true);
-
-        $this->networkUtilsMock
-            ->expects($this->once())
-            ->method('isCMF')
-            ->with($organizationMock)
-            ->willReturn(true);
+        $cotisationUtils = $this->getMockBuilder(CotisationUtils::class)
+            ->setConstructorArgs([$this->networkUtils, $this->organizationUtils, $this->networkOrganizationRepository, $this->cotisationApiResourcesRepository])
+            ->setMethodsExcept(['isStructureAndCMF'])
+            ->getMock();
 
-        $utils = $this->getUtilsInstance();
-        $this->assertTrue($utils->isStructureAndCMF($organizationMock));
-    }
+        $organization1 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization2 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization3 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization4 = $this->getMockBuilder(Organization::class)->getMock();
 
-    /**
-     * @see Utils::isStructureAndCMF()
-     */
-    public function testIsNotStructureAndCMF(): void
-    {
-        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
-
-        $this->organizationUtilsMock
-            ->expects($this->once())
+        $this->organizationUtils
             ->method('isStructure')
-            ->with($organizationMock)
-            ->willReturn(false);
-
-        $this->networkUtilsMock
-            ->expects($this->never())
-            ->method('isCMF');
-
-        $utils = $this->getUtilsInstance();
-        $this->assertFalse($utils->isStructureAndCMF($organizationMock));
+            ->willReturnMap([
+                [$organization1, true],
+                [$organization2, false],
+                [$organization3, true],
+                [$organization4, false],
+            ]);
+
+        $this->networkUtils
+            ->method('isCMF')
+            ->with($organization1)
+            ->willReturnMap([
+                [$organization1, true],
+                [$organization2, false],
+                [$organization3, false],
+                [$organization4, true],
+            ]);
+
+        $this->assertTrue($cotisationUtils->isStructureAndCMF($organization1));
+        $this->assertFalse($cotisationUtils->isStructureAndCMF($organization2));
+        $this->assertFalse($cotisationUtils->isStructureAndCMF($organization3));
+        $this->assertFalse($cotisationUtils->isStructureAndCMF($organization4));
     }
 
     /**
@@ -160,43 +121,77 @@ class UtilsTest extends TestCase
      */
     public function testIsManagerAndCMF(): void
     {
-        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
+        $cotisationUtils = $this->getMockBuilder(CotisationUtils::class)
+            ->setConstructorArgs([$this->networkUtils, $this->organizationUtils, $this->networkOrganizationRepository, $this->cotisationApiResourcesRepository])
+            ->setMethodsExcept(['isManagerAndCMF'])
+            ->getMock();
 
-        $this->organizationUtilsMock
-            ->expects($this->once())
-            ->method('isManager')
-            ->with($organizationMock)
-            ->willReturn(true);
+        $organization1 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization2 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization3 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization4 = $this->getMockBuilder(Organization::class)->getMock();
 
-        $this->networkUtilsMock
-            ->expects($this->once())
+        $this->organizationUtils
+            ->method('isManager')
+            ->willReturnMap([
+                [$organization1, true],
+                [$organization2, false],
+                [$organization3, true],
+                [$organization4, false],
+            ]);
+
+        $this->networkUtils
             ->method('isCMF')
-            ->with($organizationMock)
-            ->willReturn(true);
-
-        $utils = $this->getUtilsInstance();
-        $this->assertTrue($utils->isManagerAndCMF($organizationMock));
+            ->willReturnMap([
+                [$organization1, true],
+                [$organization2, false],
+                [$organization3, false],
+                [$organization4, true],
+            ]);
+
+        $this->assertTrue($cotisationUtils->isManagerAndCMF($organization1));
+        $this->assertFalse($cotisationUtils->isManagerAndCMF($organization2));
+        $this->assertFalse($cotisationUtils->isManagerAndCMF($organization3));
+        $this->assertFalse($cotisationUtils->isManagerAndCMF($organization4));
     }
 
     /**
-     * @see Utils::isManagerAndCMF()
+     * @see Utils::isManagerAndNotLastParentAndCMF()
      */
-    public function testIsNotManagerAndCMF(): void
+    public function testIsManagerAndLastParentAndCMF(): void
     {
-        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
-
-        $this->organizationUtilsMock
-            ->expects($this->once())
-            ->method('isManager')
-            ->with($organizationMock)
-            ->willReturn(false);
+        $cotisationUtils = $this->getMockBuilder(CotisationUtils::class)
+            ->setConstructorArgs([$this->networkUtils, $this->organizationUtils, $this->networkOrganizationRepository, $this->cotisationApiResourcesRepository])
+            ->setMethodsExcept(['isManagerAndLastParentAndCMF'])
+            ->getMock();
 
-        $this->networkUtilsMock
-            ->expects($this->never())
-            ->method('isCMF');
+        $organization1 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization2 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization3 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization4 = $this->getMockBuilder(Organization::class)->getMock();
 
-        $utils = $this->getUtilsInstance();
-        $this->assertFalse($utils->isManagerAndCMF($organizationMock));
+        $this->organizationUtils
+            ->method('isManager')
+            ->willReturnMap([
+                [$organization1, true],
+                [$organization2, false],
+                [$organization3, true],
+                [$organization4, false],
+            ]);
+
+        $cotisationUtils
+            ->method('isLastParentAndCMF')
+            ->willReturnMap([
+                [$organization1, true],
+                [$organization2, false],
+                [$organization3, false],
+                [$organization4, true],
+            ]);
+
+        $this->assertTrue($cotisationUtils->isManagerAndLastParentAndCMF($organization1));
+        $this->assertFalse($cotisationUtils->isManagerAndLastParentAndCMF($organization2));
+        $this->assertFalse($cotisationUtils->isManagerAndLastParentAndCMF($organization3));
+        $this->assertFalse($cotisationUtils->isManagerAndLastParentAndCMF($organization4));
     }
 
     /**
@@ -204,100 +199,74 @@ class UtilsTest extends TestCase
      */
     public function testIsManagerAndNotLastParentAndCMF(): void
     {
-        $organizationMock = $this->getOrganizationMock();
-
-        $this->organizationUtilsMock
-            ->expects($this->once())
-            ->method('isManager')
-            ->with($organizationMock)
-            ->willReturn(true);
-
-        $this->networkOrganizationRepositoryMock
-            ->expects($this->once())
-            ->method('isLastParent')
-            ->with($organizationMock)
-            ->willReturn(false);
-
-        $this->networkUtilsMock
-            ->expects($this->never())
-            ->method('isCMF');
-
-        $utils = $this->getUtilsInstance();
-        $this->assertTrue($utils->isManagerAndNotLastParentAndCMF($organizationMock));
-    }
+        $cotisationUtils = $this->getMockBuilder(CotisationUtils::class)
+            ->setConstructorArgs([$this->networkUtils, $this->organizationUtils, $this->networkOrganizationRepository, $this->cotisationApiResourcesRepository])
+            ->setMethodsExcept(['isManagerAndNotLastParentAndCMF'])
+            ->getMock();
 
-    /**
-     * @see Utils::isManagerAndLastParentAndCMF()
-     */
-    public function testIsManagerAndLastParentAndCMF(): void
-    {
-        $organizationMock = $this->getOrganizationMock();
+        $organization1 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization2 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization3 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization4 = $this->getMockBuilder(Organization::class)->getMock();
 
-        $this->organizationUtilsMock
-            ->expects($this->once())
+        $this->organizationUtils
             ->method('isManager')
-            ->with($organizationMock)
-            ->willReturn(true);
-
-        $this->networkOrganizationRepositoryMock
-            ->expects($this->once())
+            ->willReturnMap([
+                [$organization1, true],
+                [$organization2, false],
+                [$organization3, true],
+                [$organization4, true],
+            ]);
+
+        $this->networkOrganizationRepository
             ->method('isLastParent')
-            ->with($organizationMock)
-            ->willReturn(true);
-
-        $this->networkUtilsMock
-            ->expects($this->once())
+            ->willReturnMap([
+                [$organization1, false],
+                [$organization2, false],
+                [$organization3, true],
+                [$organization4, false],
+            ]);
+
+        $this->networkUtils
             ->method('isCMF')
-            ->willReturn(true);
-
-        $utils = $this->getUtilsInstance();
-        $this->assertTrue($utils->isManagerAndLastParentAndCMF($organizationMock));
+            ->willReturnMap([
+                [$organization1, true],
+                [$organization2, true],
+                [$organization3, true],
+                [$organization4, false],
+            ]);
+
+        $this->assertTrue($cotisationUtils->isManagerAndNotLastParentAndCMF($organization1));
+        $this->assertFalse($cotisationUtils->isManagerAndNotLastParentAndCMF($organization2));
+        $this->assertFalse($cotisationUtils->isManagerAndNotLastParentAndCMF($organization3));
+        $this->assertFalse($cotisationUtils->isManagerAndNotLastParentAndCMF($organization4));
     }
 
     /**
      * @see Utils::getAlertState()
      */
-    public function testGetAlertStateAffiliation(): void
+    public function testGetAlertState(): void
     {
-        $year = 2022;
-
-        $organizationMock = $this->getOrganizationMock();
-
-        $utils = $this->getUtilsInstance();
-
-        $this->cotisationApiResourcesRepositoryMock
-            ->method('getAffiliationState')
-            ->with($organizationMock->getId(), $year)
-            ->willReturn(self::MEMBERSHIP_WAITING);
-
-        $this->assertEquals(AlertStateEnum::AFFILIATION()->getValue(), $utils->getAlertState($organizationMock, $year) );
-
-        $this->cotisationApiResourcesRepositoryMock
-            ->method('getAffiliationState')
-            ->with($organizationMock->getId(), $year)
-            ->willReturn(self::SUBMIT_IN_PROGRESS);
-
-        $this->assertEquals(AlertStateEnum::AFFILIATION()->getValue(), $utils->getAlertState($organizationMock, $year) );
+        $cotisationUtils = $this->getMockBuilder(CotisationUtils::class)
+            ->setConstructorArgs([$this->networkUtils, $this->organizationUtils, $this->networkOrganizationRepository, $this->cotisationApiResourcesRepository])
+            ->setMethodsExcept(['getAlertState'])
+            ->getMock();
 
-    }
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getId')->willReturn(1);
 
-    /**
-     * @see Utils::getAlertState()
-     */
-    public function testGetAlertStateInvoice(): void
-    {
         $year = 2022;
 
-        $organizationMock = $this->getOrganizationMock();
-
-        $utils = $this->getUtilsInstance();
-
-        $this->cotisationApiResourcesRepositoryMock
+        $this->cotisationApiResourcesRepository
             ->method('getAffiliationState')
-            ->with($organizationMock->getId(), $year)
-            ->willReturn(self::MEMBERSHIP_NOPAYMENT);
-
-        $this->assertEquals(AlertStateEnum::INVOICE()->getValue(), $utils->getAlertState($organizationMock, $year) );
+            ->with($organization->getId(), $year)
+            ->willReturnOnConsecutiveCalls(
+                self::MEMBERSHIP_WAITING, self::SUBMIT_IN_PROGRESS, self::MEMBERSHIP_NOPAYMENT
+            );
+
+        $this->assertEquals(AlertStateEnum::AFFILIATION()->getValue(), $cotisationUtils->getAlertState($organization, $year) );
+        $this->assertEquals(AlertStateEnum::AFFILIATION()->getValue(), $cotisationUtils->getAlertState($organization, $year) );
+        $this->assertEquals(AlertStateEnum::INVOICE()->getValue(), $cotisationUtils->getAlertState($organization, $year) );
     }
 
     /**
@@ -305,18 +274,27 @@ class UtilsTest extends TestCase
      */
     public function testGetAlertStateInsurance(): void
     {
+        $cotisationUtils = $this->getMockBuilder(CotisationUtils::class)
+            ->setConstructorArgs([$this->networkUtils, $this->organizationUtils, $this->networkOrganizationRepository, $this->cotisationApiResourcesRepository])
+            ->setMethodsExcept(['getAlertState'])
+            ->getMock();
+
         $year = 2022;
 
-        $organizationMock = $this->getOrganizationMock();
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getId')->willReturn(1);
 
-        $utils = $this->getUtilsInstance();
+        $this->cotisationApiResourcesRepository
+            ->method('getAffiliationState')
+            ->with($organization->getId(), $year)
+            ->willReturn(null);
 
-        $this->cotisationApiResourcesRepositoryMock
+        $this->cotisationApiResourcesRepository
             ->method('isInsuranceNotDone')
-            ->with($organizationMock->getId(), $year)
+            ->with($organization->getId(), $year)
             ->willReturn(true);
 
-        $this->assertEquals(AlertStateEnum::INSURANCE()->getValue(), $utils->getAlertState($organizationMock, $year) );
+        $this->assertEquals(AlertStateEnum::INSURANCE()->getValue(), $cotisationUtils->getAlertState($organization, $year) );
     }
 
     /**
@@ -324,18 +302,27 @@ class UtilsTest extends TestCase
      */
     public function testGetAlertStateAdvertisingInsurance(): void
     {
+        $cotisationUtils = $this->getMockBuilder(CotisationUtils::class)
+            ->setConstructorArgs([$this->networkUtils, $this->organizationUtils, $this->networkOrganizationRepository, $this->cotisationApiResourcesRepository])
+            ->setMethodsExcept(['getAlertState'])
+            ->getMock();
+
         $year = 2022;
 
-        $organizationMock = $this->getOrganizationMock();
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getId')->willReturn(1);
 
-        $utils = $this->getUtilsInstance();
+        $this->cotisationApiResourcesRepository
+            ->method('getAffiliationState')
+            ->with($organization->getId(), $year)
+            ->willReturn(null);
 
-        $this->cotisationApiResourcesRepositoryMock
+        $this->cotisationApiResourcesRepository
             ->method('isNotDGVCustomer')
-            ->with($organizationMock->getId())
+            ->with($organization->getId())
             ->willReturn(true);
 
-        $this->assertEquals(AlertStateEnum::ADVERTISINGINSURANCE()->getValue(), $utils->getAlertState($organizationMock, $year) );
+        $this->assertEquals(AlertStateEnum::ADVERTISINGINSURANCE()->getValue(), $cotisationUtils->getAlertState($organization, $year) );
     }
 
     /**
@@ -343,13 +330,17 @@ class UtilsTest extends TestCase
      */
     public function testGetCurrentCotisationYear(): void
     {
-        $utils = $this->getUtilsInstance();
+        $cotisationUtils = $this->getMockBuilder(CotisationUtils::class)
+            ->setConstructorArgs([$this->networkUtils, $this->organizationUtils, $this->networkOrganizationRepository, $this->cotisationApiResourcesRepository])
+            ->setMethodsExcept(['getCurrentCotisationYear'])
+            ->getMock();
 
         $today = new \DateTime('now');
-        if($today->format('m') <= 9)
-            $this->assertEquals($today->format('Y'), $utils->getCurrentCotisationYear());
-        else
-            $this->assertEquals(($today->format('Y') + 1), $utils->getCurrentCotisationYear());
+        $expectedYear = (int)$today->format('Y');
+        if($today->format('m') > 9) {
+            $expectedYear++;
+        }
 
+        $this->assertEquals($expectedYear, $cotisationUtils->getCurrentCotisationYear());
     }
-}
+}

+ 152 - 82
tests/Service/Dolibarr/DolibarrAccountCreatorTest.php

@@ -1,7 +1,10 @@
-<?php
+<?php /** @noinspection PhpUnhandledExceptionInspection */
 
 namespace App\Tests\Service\Dolibarr;
 
+use App\ApiResources\Dolibarr\DolibarrAccount;
+use App\ApiResources\Dolibarr\DolibarrBill;
+use App\ApiResources\Dolibarr\DolibarrContract;
 use App\Service\Dolibarr\DolibarrAccountCreator;
 use App\Service\Dolibarr\DolibarrApiService;
 use PHPUnit\Framework\TestCase;
@@ -9,110 +12,177 @@ use PHPUnit\Framework\TestCase;
 class DolibarrAccountCreatorTest extends TestCase
 {
     private DolibarrApiService $dolibarrApiService;
-    private DolibarrAccountCreator $dolibarrAccountCreator;
 
     public function setUp(): void {
         $this->dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
             ->disableOriginalConstructor()
             ->getMock();
-
-        $this->dolibarrAccountCreator = new DolibarrAccountCreator($this->dolibarrApiService);
     }
 
-    private function getJsonContentFromFixture(string $filename): array {
-        $filepath = dirname(__FILE__) . '/fixtures/' . $filename;
-        return json_decode(file_get_contents($filepath), true);
+    public function testGetDolibarrAccount(): void
+    {
+        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountCreator::class)
+            ->setConstructorArgs([$this->dolibarrApiService])
+            ->setMethodsExcept(['getDolibarrAccount'])
+            ->getMock();
+
+        $organizationId = 1;
+        $socId = 123;
+
+        // Create dolibarr account
+        $accountData = [1]; // dummy non-null data
+        $this->dolibarrApiService->expects(self::once())->method('getSociety')->with($organizationId)->willReturn($accountData);
+
+        $dolibarrAccount = $this->getMockBuilder(DolibarrAccount::class)->getMock();
+        $dolibarrAccount->method('getSocId')->willReturn($socId);
+
+        $dolibarrAccountCreator
+            ->expects(self::once())
+            ->method('createDolibarrAccount')
+            ->with($organizationId, $accountData)
+            ->willReturn($dolibarrAccount);
+
+        // Get active contract and services
+        $contractData = [1]; // dummy non-null data
+        $this->dolibarrApiService->expects(self::once())->method('getActiveContract')->with($socId)->willReturn($contractData);
+
+        $dolibarrContract = $this->getMockBuilder(DolibarrContract::class)->getMock();
+
+        $dolibarrAccountCreator
+            ->expects(self::once())
+            ->method('createDolibarrContract')
+            ->with($contractData)
+            ->willReturn($dolibarrContract);
+
+        $dolibarrAccount->expects(self::once())->method('setContract')->with($dolibarrContract);
+
+        // get bills
+        $billsData = [[10], [20]]; // dummy non-empty data
+
+        $dolibarrBill1 = $this->getMockBuilder(DolibarrBill::class)->getMock();
+        $dolibarrBill2 = $this->getMockBuilder(DolibarrBill::class)->getMock();
+
+        $this->dolibarrApiService->expects(self::once())->method('getBills')->with($socId)->willReturn($billsData);
+
+        $dolibarrAccountCreator
+            ->expects(self::exactly(2))
+            ->method('createDolibarrBill')
+            ->willReturnMap([
+                [[10], $dolibarrBill1],
+                [[20], $dolibarrBill2]
+            ]);
+
+        $dolibarrAccount->expects(self::exactly(2))->method('addBill')->withConsecutive([$dolibarrBill1], [$dolibarrBill2]);
+
+        $result = $dolibarrAccountCreator->getDolibarrAccount(1);
+
+        $this->assertEquals($dolibarrAccount, $result);
     }
 
-    public function testGetDolibarrAccount() {
-        $this->dolibarrApiService
-            ->expects($this->once())
-            ->method('getSociety')
-            ->with(1)
-            ->willReturn(
-                $this->getJsonContentFromFixture('thirdparty.json')[0]
-            );
-
-        $this->dolibarrApiService
-            ->expects($this->once())
-            ->method('getActiveContract')
-            ->with(1726)
-            ->willReturn(
-                $this->getJsonContentFromFixture('contract.json')[0]
-            );
-
-        $this->dolibarrApiService
-            ->expects($this->once())
-            ->method('getBills')
-            ->with(1726)
-            ->willReturn(
-                $this->getJsonContentFromFixture('bills.json')
-            );
-
-        $dolibarrAccount = $this->dolibarrAccountCreator->getDolibarrAccount(1);
-
-        $this->assertEquals(
-            $dolibarrAccount->getClientNumber(),
-            "001855"
-        );
-        $this->assertEquals(
-            $dolibarrAccount->getContract()->getRef(),
-            "0000037-C1_1"
-        );
-        $this->assertEquals(
-            $dolibarrAccount->getContract()->getLines()[0]->getServiceRef(),
-            "ABO_ART_PRE_CMF"
-        );
-        $this->assertEquals(
-            $dolibarrAccount->getBills()[2]->getRef(),
-            "FA2105-03135"
-        );
+    public function testCreateDolibarrAccount(): void
+    {
+        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountCreator::class)
+            ->setConstructorArgs([$this->dolibarrApiService])
+            ->setMethodsExcept(['createDolibarrAccount'])
+            ->getMock();
+
+        $organizationId = 1;
+        $accountData = ['id' => '2', 'code_client' => 'C2', 'array_options' => []];
+
+        $dolibarrAccount = $dolibarrAccountCreator->createDolibarrAccount($organizationId, $accountData);
+
+        $this->assertEquals(1, $dolibarrAccount->getOrganizationId());
+        $this->assertEquals(2, $dolibarrAccount->getSocId());
+        $this->assertEquals("C2", $dolibarrAccount->getClientNumber());
+        $this->assertEquals(null, $dolibarrAccount->getProduct());
     }
 
-    public function testCreateDolibarrAccount() {
-        $accountData = $this->getJsonContentFromFixture('thirdparty.json')[0];
+    public function testCreateDolibarrAccountWithProduct(): void
+    {
+        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountCreator::class)
+            ->setConstructorArgs([$this->dolibarrApiService])
+            ->setMethodsExcept(['createDolibarrAccount'])
+            ->getMock();
+
+        $organizationId = 1;
+        $accountData = ['id' => '2', 'code_client' => 'C2', 'array_options' => ['options_2iopen_software_used' => 1]];
+
+        $dolibarrAccount = $dolibarrAccountCreator->createDolibarrAccount($organizationId, $accountData);
 
-        $dolibarrAccount = $this->dolibarrAccountCreator->createDolibarrAccount(1, $accountData);
-        $this->assertEquals(
-            $dolibarrAccount->getClientNumber(),
-            "001855"
-        );
+        $this->assertEquals('PRODUCT_ARTIST', $dolibarrAccount->getProduct());
     }
 
-    public function testCreateDolibarrContract() {
-        $contractData = $this->getJsonContentFromFixture('contract.json')[0];
+    public function testCreateDolibarrContract(): void
+    {
+        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountCreator::class)
+            ->setConstructorArgs([$this->dolibarrApiService])
+            ->setMethodsExcept(['createDolibarrContract'])
+            ->getMock();
+
+        $contractData = [
+            'ref' => 'foo',
+            'socid' => 123,
+            'lines' => [[1], [2]]
+        ];
 
-        $dolibarrContract = $this->dolibarrAccountCreator->createDolibarrContract($contractData);
+        $dolibarrAccountCreator
+            ->expects(self::exactly(2))
+            ->method('createDolibarrContractLine')
+            ->withConsecutive([[1]], [[2]]);
 
-        $this->assertEquals(
-            $dolibarrContract->getRef(),
-            "0000037-C1_1"
-        );
-        $this->assertEquals(
-            $dolibarrContract->getLines()[0]->getServiceRef(),
-            "ABO_ART_PRE_CMF"
-        );
+        $dolibarrContract = $dolibarrAccountCreator->createDolibarrContract($contractData);
+
+        $this->assertEquals('foo', $dolibarrContract->getRef());
+        $this->assertEquals(123, $dolibarrContract->getSocId());
     }
 
     public function testCreateDolibarrContractLine() {
-        $lineData = $this->getJsonContentFromFixture('contract.json')[0]['lines'][0];
-
-        $dolibarrContractLine = $this->dolibarrAccountCreator->createDolibarrContractLine($lineData);
+        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountCreator::class)
+            ->setConstructorArgs([$this->dolibarrApiService])
+            ->setMethodsExcept(['createDolibarrContractLine'])
+            ->getMock();
 
-        $this->assertEquals(
-            $dolibarrContractLine->getServiceRef(),
-            "ABO_ART_PRE_CMF"
-        );
+        $lineData = [
+            'id'=> '1',
+            'fk_contrat' => '123',
+            'product_ref' => 'foo',
+            'product_label' => 'bar',
+            'date_start' => '1577836800',
+            'date_end' => '1609372800'
+        ];
+
+        $dolibarrContractLine = $dolibarrAccountCreator->createDolibarrContractLine($lineData);
+
+        $this->assertEquals(1, $dolibarrContractLine->getId());
+        $this->assertEquals(123, $dolibarrContractLine->getContractId());
+        $this->assertEquals('foo', $dolibarrContractLine->getServiceRef());
+        $this->assertEquals('bar', $dolibarrContractLine->getServiceLabel());
+        $this->assertEquals('2020-01-01T00:00:00+00:00', $dolibarrContractLine->getDateStart()->format('c'));
+        $this->assertEquals('2020-12-31T00:00:00+00:00', $dolibarrContractLine->getDateEnd()->format('c'));
     }
 
     public function testCreateDolibarrBill() {
-        $billData = $this->getJsonContentFromFixture('bills.json')[0];
 
-        $dolibarrBill = $this->dolibarrAccountCreator->createDolibarrBill($billData);
-        $this->assertEquals(
-            $dolibarrBill->getRef(),
-            "AV2106-02992"
-        );
-    }
+        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountCreator::class)
+            ->setConstructorArgs([$this->dolibarrApiService])
+            ->setMethodsExcept(['createDolibarrBill'])
+            ->getMock();
 
+        $billData = [
+            'id' => '1',
+            'ref' => 'foo',
+            'total_ht' => '100.0',
+            'total_ttc' => '120.0',
+            'date' => '1577836800',
+            'paye' => '0'
+        ];
+
+        $dolibarrBill = $dolibarrAccountCreator->createDolibarrBill($billData);
+
+        $this->assertEquals(1, $dolibarrBill->getId());
+        $this->assertEquals('foo', $dolibarrBill->getRef());
+        $this->assertEquals(100.0, $dolibarrBill->getTaxExcludedAmount());
+        $this->assertEquals(120.0, $dolibarrBill->getTaxIncludedAmount());
+        $this->assertEquals(false, $dolibarrBill->getPaid());
+    }
 }

+ 165 - 55
tests/Service/Dolibarr/DolibarrApiServiceTest.php

@@ -3,96 +3,206 @@
 namespace App\Tests\Service\Dolibarr;
 
 use App\Service\Dolibarr\DolibarrApiService;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
+use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
-use Symfony\Contracts\HttpClient\ResponseInterface;
 
 class DolibarrApiServiceTest extends TestCase
 {
-    private HttpClientInterface $client;
-    private DolibarrApiService $dolibarrApiService;
+    private MockObject | HttpClientInterface $client;
 
     public function setUp(): void {
         $this->client = $this->getMockBuilder(HttpClientInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
-
-        $this->dolibarrApiService = new DolibarrApiService($this->client);
-    }
-
-    private function getContentFromFixture(string $filename): string {
-        $filepath = dirname(__FILE__) . '/fixtures/' . $filename;
-        return file_get_contents($filepath);
     }
 
     /**
      * @see DolibarrApiService::getSociety()
      */
     public function testGetSociety(): void {
-        $responseContent = $this->getContentFromFixture('thirdparty.json');
-
-        $response = $this->getMockBuilder(ResponseInterface::class)
-            ->disableOriginalConstructor()
+        $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getSociety'])
             ->getMock();
-        $response->method('getContent')->willReturn($responseContent);
 
-        $this->client
-            ->expects($this->once())
-            ->method('request')
-            ->with("GET", "thirdparties?limit=1&sqlfilters=ref_int%3D1")
-            ->willReturn($response);
+        $organizationId = 123;
+
+        $dolibarrApiService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with("thirdparties", [ "limit" => "1", "sqlfilters" => "ref_int=" . $organizationId])
+            ->willReturn([['id' => 1]]); // dummy non-empty data
 
-        $data = $this->dolibarrApiService->getSociety(1);
+        $society = $dolibarrApiService->getSociety($organizationId);
 
-        $this->assertEquals(
-            $data['id'],
-            1726
-        );
+        $this->assertEquals(['id' => 1], $society);
     }
 
     /**
      * @see DolibarrApiService::getActiveContract()
      */
     public function testGetActiveContract(): void {
-        $responseContent = $this->getContentFromFixture('contract.json');
+        $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getActiveContract'])
+            ->getMock();
 
-        $response = $this->getMockBuilder(ResponseInterface::class)
-            ->disableOriginalConstructor()
+        $socId = 1;
+
+        $dolibarrApiService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with("contracts", ["limit" => "1", "sqlfilters" => "statut=1", "thirdparty_ids" => $socId])
+            ->willReturn([['id' => 1]]); // dummy non-empty data
+
+        $this->assertEquals(['id' => 1], $dolibarrApiService->getActiveContract($socId));
+    }
+
+    /**
+     * @see DolibarrApiService::getActiveContract()
+     */
+    public function testGetActiveContractMissing(): void {
+        $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getActiveContract'])
             ->getMock();
-        $response->method('getContent')->willReturn($responseContent);
-
-        $this->client
-            ->expects($this->once())
-            ->method('request')
-            ->with("GET", "contracts?limit=1&sqlfilters=statut%3D1&thirdparty_ids=1")
-            ->willReturn($response);
-
-        $this->assertEquals(
-            $this->dolibarrApiService->getActiveContract(1)['socid'],
-            43
-        );
+
+        $socId = 1;
+
+        $dolibarrApiService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with("contracts", ["limit" => "1", "sqlfilters" => "statut=1", "thirdparty_ids" => $socId])
+            ->willThrowException(new HttpException(404));
+
+        $this->assertEquals(null, $dolibarrApiService->getActiveContract($socId));
     }
 
     /**
      * @see DolibarrApiService::getBills()
      */
     public function testGetBills(): void {
-        $responseContent = $this->getContentFromFixture('bills.json');
+        $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getBills'])
+            ->getMock();
 
-        $response = $this->getMockBuilder(ResponseInterface::class)
-            ->disableOriginalConstructor()
+        $socId = 1;
+
+        $dolibarrApiService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with("invoices", ["sortfield" => "datef", "sortorder" => "DESC", "limit" => 5, "sqlfilters" => "fk_soc=" . $socId])
+            ->willReturn([['id' => 10], ['id' => 20]]);
+
+        $this->assertEquals([['id' => 10], ['id' => 20]], $dolibarrApiService->getBills($socId));
+    }
+
+    /**
+     * @see DolibarrApiService::getBills()
+     */
+    public function testGetBillsMissing(): void {
+        $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getBills'])
             ->getMock();
-        $response->method('getContent')->willReturn($responseContent);
-
-        $this->client
-            ->expects($this->once())
-            ->method('request')
-            ->with("GET", "invoices?sortfield=datef&sortorder=DESC&limit=5&sqlfilters=fk_soc%3D1")
-            ->willReturn($response);
-
-        $this->assertEquals(
-            $this->dolibarrApiService->getBills(1)[2]['socid'],
-            284
-        );
+
+        $socId = 1;
+
+        $dolibarrApiService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with("invoices", ["sortfield" => "datef", "sortorder" => "DESC", "limit" => 5, "sqlfilters" => "fk_soc=" . $socId])
+            ->willThrowException(new HttpException(404));
+
+        $this->assertEquals([], $dolibarrApiService->getBills($socId));
     }
+
+    public function testGetAllClients(): void
+    {
+        $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getAllClients'])
+            ->getMock();
+
+        $dolibarrApiService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with("thirdparties", ["limit" => "1000000", "sqlfilters" => "client=1"])
+            ->willReturn([['id' => 10], ['id' => 20]]);
+
+        $this->assertEquals([['id' => 10], ['id' => 20]], $dolibarrApiService->getAllClients());
+    }
+
+    public function testGetContacts() {
+        $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getContacts'])
+            ->getMock();
+
+        $socId = 1;
+
+        $dolibarrApiService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with("contacts", ['limit' => 1000, 'thirdparty_ids' => $socId])
+            ->willReturn([['id' => 10], ['id' => 20]]);
+
+        $this->assertEquals([['id' => 10], ['id' => 20]], $dolibarrApiService->getContacts($socId));
+    }
+
+    public function testGetContactsMissing(): void {
+        $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getContacts'])
+            ->getMock();
+
+        $socId = 1;
+
+        $dolibarrApiService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with("contacts", ['limit' => 1000, 'thirdparty_ids' => $socId])
+            ->willThrowException(new HttpException(404));
+
+        $this->assertEquals([], $dolibarrApiService->getContacts($socId));
+    }
+
+    public function testGetActiveOpentalentContacts() {
+        $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getActiveOpentalentContacts'])
+            ->getMock();
+
+        $socId = 1;
+
+        $dolibarrApiService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with("contacts?limit=1000&t.statut=1&thirdparty_ids=" . $socId . "&sqlfilters=(te.2iopen_person_id%3A%3E%3A0)")
+            ->willReturn([['id' => 10], ['id' => 20]]);
+
+        $this->assertEquals([['id' => 10], ['id' => 20]], $dolibarrApiService->getActiveOpentalentContacts($socId));
+    }
+
+    public function testGetActiveOpentalentContactsMissing(): void {
+        $dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getActiveOpentalentContacts'])
+            ->getMock();
+
+        $socId = 1;
+
+        $dolibarrApiService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with("contacts?limit=1000&t.statut=1&thirdparty_ids=" . $socId . "&sqlfilters=(te.2iopen_person_id%3A%3E%3A0)")
+            ->willThrowException(new HttpException(404));
+
+        $this->assertEquals([], $dolibarrApiService->getActiveOpentalentContacts($socId));
+    }
+
+
 }

Plik diff jest za duży
+ 660 - 287
tests/Service/Dolibarr/DolibarrSyncServiceTest.php


+ 0 - 542
tests/Service/Dolibarr/fixtures/bills.json

@@ -1,542 +0,0 @@
-[
-  {
-    "socid": "284",
-    "fk_user_author": null,
-    "fk_user_valid": null,
-    "date": 1624831200,
-    "datem": 1626091849,
-    "ref_client": null,
-    "type": "2",
-    "remise_absolue": null,
-    "remise_percent": null,
-    "total_ht": "-731.00000000",
-    "total_tva": "-146.20000000",
-    "total_localtax1": "0.00000000",
-    "total_localtax2": "0.00000000",
-    "total_ttc": "-877.20000000",
-    "revenuestamp": "0.00000000",
-    "close_code": null,
-    "close_note": null,
-    "paye": "1",
-    "module_source": null,
-    "pos_source": null,
-    "fk_fac_rec_source": null,
-    "fk_facture_source": "256",
-    "linked_objects": [],
-    "date_lim_reglement": 1624831200,
-    "cond_reglement_code": null,
-    "mode_reglement_code": "VIR",
-    "fk_bank": null,
-    "products": [],
-    "lines": [
-      {
-        "fk_facture": "310",
-        "fk_parent_line": null,
-        "label": null,
-        "desc": "<p>Logiciel de gestion et de communication pour les &eacute;tablissements d&#39;enseignement artistique comprend :</p>\r\n\r\n<ul>\r\n\t<li>3 comptes administratifs</li>\r\n\t<li>comptes utilisateurs (&eacute;l&egrave;ves, familles et professeurs)</li>\r\n\t<li>site internet complet</li>\r\n</ul>\r\n<br />\r\n<em><strong>Conditions r&eacute;serv&eacute;es aux adh&eacute;rents CMF. </strong>.En cas de non renouvellement de votre adh&eacute;sion, vous basculerez sur les conditions publiques.</em>\r\n\r\n<p>&nbsp;</p>",
-        "localtax1_type": "0",
-        "localtax2_type": "0",
-        "fk_remise_except": null,
-        "rang": "0",
-        "fk_fournprice": null,
-        "pa_ht": "731.00000000",
-        "marge_tx": -0,
-        "marque_tx": 0,
-        "special_code": "0",
-        "origin": null,
-        "origin_id": null,
-        "fk_code_ventilation": 0,
-        "date_start": 1624053600,
-        "date_end": 1655503200,
-        "ref": "ABO_SCH_PRE_200-399_CMF",
-        "product_ref": "ABO_SCH_PRE_200-399_CMF",
-        "libelle": "Abonnement Opentalent School premium Tranche  200-399 Adhérent CMF",
-        "product_label": "Abonnement Opentalent School premium Tranche  200-399 Adhérent CMF",
-        "product_desc": "<p>Logiciel de gestion et de communication pour les &eacute;tablissements d&#39;enseignement artistique comprend :</p>\r\n\r\n<ul>\r\n\t<li>3 comptes administratifs</li>\r\n\t<li>comptes utilisateurs (&eacute;l&egrave;ves, familles et professeurs)</li>\r\n\t<li>site internet complet</li>\r\n</ul>\r\n<br />\r\n<em><strong>Conditions r&eacute;serv&eacute;es aux adh&eacute;rents CMF. </strong>.En cas de non renouvellement de votre adh&eacute;sion, vous basculerez sur les conditions publiques.</em>\r\n\r\n<p>&nbsp;</p>",
-        "situation_percent": "100",
-        "fk_prev_id": null,
-        "multicurrency_subprice": "-731.00000000",
-        "multicurrency_total_ht": "-731.00000000",
-        "multicurrency_total_tva": "-146.20000000",
-        "multicurrency_total_ttc": "-877.20000000",
-        "qty": "1",
-        "subprice": "-731.00000000",
-        "product_type": "1",
-        "fk_product": "327",
-        "vat_src_code": "",
-        "tva_tx": "20.000",
-        "localtax1_tx": "0.000",
-        "localtax2_tx": "0.000",
-        "remise_percent": "0",
-        "total_ht": "-731.00000000",
-        "total_tva": "-146.20000000",
-        "total_localtax1": "0.00000000",
-        "total_localtax2": "0.00000000",
-        "total_ttc": "-877.20000000",
-        "info_bits": "0",
-        "id": "1240",
-        "rowid": "1240",
-        "fk_unit": null,
-        "import_key": null,
-        "array_options": {
-          "options_show_total_ht": null,
-          "options_show_reduc": null
-        },
-        "linkedObjectsIds": null,
-        "canvas": null,
-        "ref_ext": null,
-        "statut": null,
-        "state": null,
-        "state_id": null,
-        "state_code": null,
-        "transport_mode_id": null,
-        "last_main_doc": null,
-        "fk_account": null,
-        "lines": null,
-        "date_creation": null,
-        "date_validation": null,
-        "date_modification": null,
-        "description": "<p>Logiciel de gestion et de communication pour les &eacute;tablissements d&#39;enseignement artistique comprend :</p>\r\n\r\n<ul>\r\n\t<li>3 comptes administratifs</li>\r\n\t<li>comptes utilisateurs (&eacute;l&egrave;ves, familles et professeurs)</li>\r\n\t<li>site internet complet</li>\r\n</ul>\r\n<br />\r\n<em><strong>Conditions r&eacute;serv&eacute;es aux adh&eacute;rents CMF. </strong>.En cas de non renouvellement de votre adh&eacute;sion, vous basculerez sur les conditions publiques.</em>\r\n\r\n<p>&nbsp;</p>",
-        "fk_product_type": "1",
-        "code_ventilation": "100105976",
-        "fk_accounting_account": "100105976"
-      }
-    ],
-    "line": null,
-    "extraparams": [],
-    "specimen": null,
-    "fac_rec": null,
-    "fk_multicurrency": "0",
-    "multicurrency_code": "EUR",
-    "multicurrency_tx": "1.00000000",
-    "multicurrency_total_ht": "-731.00000000",
-    "multicurrency_total_tva": "-146.20000000",
-    "multicurrency_total_ttc": "-877.20000000",
-    "situation_cycle_ref": null,
-    "situation_counter": null,
-    "situation_final": "0",
-    "tab_previous_situation_invoice": [],
-    "tab_next_situation_invoice": [],
-    "id": "310",
-    "import_key": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopen_origvente": "2",
-      "options_logicielfact": "2",
-      "options_versionfact": "2",
-      "options_ec_beg_bill_period_date": "",
-      "options_ec_end_bill_period_date": ""
-    },
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "thirdparty": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "ref": "AV2106-02992",
-    "ref_ext": null,
-    "statut": "2",
-    "country": null,
-    "country_id": null,
-    "country_code": null,
-    "state": null,
-    "state_id": null,
-    "state_code": null,
-    "mode_reglement_id": "2",
-    "cond_reglement_id": "0",
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": "InfraSPlus_F",
-    "last_main_doc": "facture/AV2106-02992/AV2106-02992.pdf",
-    "fk_account": "1",
-    "note_public": "Annule la facture FA2105-03135 suite geste commerciale exceptionnel de 10% sur le montant de l'abonnement au logiciel Opentalent School Premium",
-    "note_private": null,
-    "fk_incoterms": "0",
-    "libelle_incoterms": null,
-    "location_incoterms": "",
-    "name": null,
-    "lastname": null,
-    "firstname": null,
-    "civility_id": null,
-    "date_creation": 1624893979,
-    "date_validation": 1624831200,
-    "date_modification": 1626091849,
-    "entity": "1",
-    "date_pointoftax": "",
-    "mode_reglement": "Virement",
-    "cond_reglement_doc": null,
-    "user_author": "5",
-    "user_valid": "5",
-    "totalpaid": null,
-    "totalcreditnotes": null,
-    "totaldeposits": null,
-    "remaintopay": "-877.20",
-    "contacts_ids": [
-      "29845"
-    ]
-  },
-  {
-    "socid": "284",
-    "fk_user_author": null,
-    "fk_user_valid": null,
-    "date": 1624831200,
-    "datem": 1625552613,
-    "ref_client": null,
-    "type": "0",
-    "remise_absolue": null,
-    "remise_percent": null,
-    "total_ht": "657.90000000",
-    "total_tva": "131.58000000",
-    "total_localtax1": "0.00000000",
-    "total_localtax2": "0.00000000",
-    "total_ttc": "789.48000000",
-    "revenuestamp": "0.00000000",
-    "close_code": null,
-    "close_note": null,
-    "paye": "1",
-    "module_source": null,
-    "pos_source": null,
-    "fk_fac_rec_source": null,
-    "fk_facture_source": null,
-    "linked_objects": [],
-    "date_lim_reglement": 1624917600,
-    "cond_reglement_code": "RECEP",
-    "mode_reglement_code": "VIR",
-    "fk_bank": null,
-    "products": [],
-    "lines": [
-      {
-        "fk_facture": "311",
-        "fk_parent_line": null,
-        "label": null,
-        "desc": "<p>Logiciel de gestion et de communication pour les &eacute;tablissements d&#39;enseignement artistique comprend :</p>\r\n\r\n<ul>\r\n\t<li>3 comptes administratifs</li>\r\n\t<li>comptes utilisateurs (&eacute;l&egrave;ves, familles et professeurs)</li>\r\n\t<li>site internet complet</li>\r\n</ul>\r\n<br />\r\n<em><strong>Conditions r&eacute;serv&eacute;es aux adh&eacute;rents CMF. </strong>.En cas de non renouvellement de votre adh&eacute;sion, vous basculerez sur les conditions publiques.</em>\r\n\r\n<p><span style=\"color:#e74c3c\"><strong>Geste commercial exceptionnel de 10 %</strong></span></p>",
-        "localtax1_type": "0",
-        "localtax2_type": "0",
-        "fk_remise_except": null,
-        "rang": "0",
-        "fk_fournprice": null,
-        "pa_ht": "731.00000000",
-        "marge_tx": -10.000000000000002,
-        "marque_tx": -11.111111111111114,
-        "special_code": "0",
-        "origin": null,
-        "origin_id": null,
-        "fk_code_ventilation": 0,
-        "date_start": 1624053600,
-        "date_end": 1655503200,
-        "ref": "ABO_SCH_PRE_200-399_CMF",
-        "product_ref": "ABO_SCH_PRE_200-399_CMF",
-        "libelle": "Abonnement Opentalent School premium Tranche  200-399 Adhérent CMF",
-        "product_label": "Abonnement Opentalent School premium Tranche  200-399 Adhérent CMF",
-        "product_desc": "<p>Logiciel de gestion et de communication pour les &eacute;tablissements d&#39;enseignement artistique comprend :</p>\r\n\r\n<ul>\r\n\t<li>3 comptes administratifs</li>\r\n\t<li>comptes utilisateurs (&eacute;l&egrave;ves, familles et professeurs)</li>\r\n\t<li>site internet complet</li>\r\n</ul>\r\n<br />\r\n<em><strong>Conditions r&eacute;serv&eacute;es aux adh&eacute;rents CMF. </strong>.En cas de non renouvellement de votre adh&eacute;sion, vous basculerez sur les conditions publiques.</em>\r\n\r\n<p>&nbsp;</p>",
-        "situation_percent": "100",
-        "fk_prev_id": null,
-        "multicurrency_subprice": "731.00000000",
-        "multicurrency_total_ht": "657.90000000",
-        "multicurrency_total_tva": "131.58000000",
-        "multicurrency_total_ttc": "789.48000000",
-        "qty": "1",
-        "subprice": "731.00000000",
-        "product_type": "1",
-        "fk_product": "327",
-        "vat_src_code": "",
-        "tva_tx": "20.000",
-        "localtax1_tx": "0.000",
-        "localtax2_tx": "0.000",
-        "remise_percent": "10",
-        "total_ht": "657.90000000",
-        "total_tva": "131.58000000",
-        "total_localtax1": "0.00000000",
-        "total_localtax2": "0.00000000",
-        "total_ttc": "789.48000000",
-        "info_bits": "0",
-        "id": "1241",
-        "rowid": "1241",
-        "fk_unit": null,
-        "import_key": null,
-        "array_options": {
-          "options_show_total_ht": null,
-          "options_show_reduc": null
-        },
-        "linkedObjectsIds": null,
-        "canvas": null,
-        "ref_ext": null,
-        "statut": null,
-        "state": null,
-        "state_id": null,
-        "state_code": null,
-        "transport_mode_id": null,
-        "last_main_doc": null,
-        "fk_account": null,
-        "lines": null,
-        "date_creation": null,
-        "date_validation": null,
-        "date_modification": null,
-        "description": "<p>Logiciel de gestion et de communication pour les &eacute;tablissements d&#39;enseignement artistique comprend :</p>\r\n\r\n<ul>\r\n\t<li>3 comptes administratifs</li>\r\n\t<li>comptes utilisateurs (&eacute;l&egrave;ves, familles et professeurs)</li>\r\n\t<li>site internet complet</li>\r\n</ul>\r\n<br />\r\n<em><strong>Conditions r&eacute;serv&eacute;es aux adh&eacute;rents CMF. </strong>.En cas de non renouvellement de votre adh&eacute;sion, vous basculerez sur les conditions publiques.</em>\r\n\r\n<p><span style=\"color:#e74c3c\"><strong>Geste commercial exceptionnel de 10 %</strong></span></p>",
-        "fk_product_type": "1",
-        "code_ventilation": "100105976",
-        "fk_accounting_account": "100105976"
-      }
-    ],
-    "line": null,
-    "extraparams": [],
-    "specimen": null,
-    "fac_rec": null,
-    "fk_multicurrency": "0",
-    "multicurrency_code": "EUR",
-    "multicurrency_tx": "1.00000000",
-    "multicurrency_total_ht": "657.90000000",
-    "multicurrency_total_tva": "131.58000000",
-    "multicurrency_total_ttc": "789.48000000",
-    "situation_cycle_ref": null,
-    "situation_counter": null,
-    "situation_final": "0",
-    "tab_previous_situation_invoice": [],
-    "tab_next_situation_invoice": [],
-    "id": "311",
-    "import_key": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopen_origvente": "2",
-      "options_logicielfact": "2",
-      "options_versionfact": "2",
-      "options_ec_beg_bill_period_date": 1624053600,
-      "options_ec_end_bill_period_date": 1655503200
-    },
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "thirdparty": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "ref": "FA2106-03183",
-    "ref_ext": null,
-    "statut": "2",
-    "country": null,
-    "country_id": null,
-    "country_code": null,
-    "state": null,
-    "state_id": null,
-    "state_code": null,
-    "mode_reglement_id": "2",
-    "cond_reglement_id": "1",
-    "transport_mode_id": null,
-    "cond_reglement": "Due upon receipt",
-    "shipping_method_id": null,
-    "modelpdf": "InfraSPlus_F",
-    "last_main_doc": "facture/FA2106-03183/FA2106-03183.pdf",
-    "fk_account": "1",
-    "note_public": null,
-    "note_private": null,
-    "fk_incoterms": "0",
-    "libelle_incoterms": null,
-    "location_incoterms": "",
-    "name": null,
-    "lastname": null,
-    "firstname": null,
-    "civility_id": null,
-    "date_creation": 1624895968,
-    "date_validation": 1624831200,
-    "date_modification": 1625552613,
-    "entity": "1",
-    "date_pointoftax": "",
-    "mode_reglement": "Virement",
-    "cond_reglement_doc": "Due upon receipt",
-    "user_author": "5",
-    "user_valid": "5",
-    "totalpaid": "789.48000000",
-    "totalcreditnotes": null,
-    "totaldeposits": null,
-    "remaintopay": "0",
-    "contacts_ids": [
-      "29845"
-    ]
-  },
-  {
-    "socid": "284",
-    "fk_user_author": null,
-    "fk_user_valid": null,
-    "date": 1621980000,
-    "datem": 1626091889,
-    "ref_client": null,
-    "type": "0",
-    "remise_absolue": null,
-    "remise_percent": null,
-    "total_ht": "731.00000000",
-    "total_tva": "146.20000000",
-    "total_localtax1": "0.00000000",
-    "total_localtax2": "0.00000000",
-    "total_ttc": "877.20000000",
-    "revenuestamp": "0.00000000",
-    "close_code": null,
-    "close_note": null,
-    "paye": "1",
-    "module_source": null,
-    "pos_source": null,
-    "fk_fac_rec_source": null,
-    "fk_facture_source": null,
-    "linked_objects": [],
-    "date_lim_reglement": 1622066400,
-    "cond_reglement_code": "RECEP",
-    "mode_reglement_code": "VIR",
-    "fk_bank": null,
-    "products": [],
-    "lines": [
-      {
-        "fk_facture": "256",
-        "fk_parent_line": null,
-        "label": null,
-        "desc": "<p>Logiciel de gestion et de communication pour les &eacute;tablissements d&#39;enseignement artistique comprend :</p>\r\n\r\n<ul>\r\n\t<li>3 comptes administratifs</li>\r\n\t<li>comptes utilisateurs (&eacute;l&egrave;ves, familles et professeurs)</li>\r\n\t<li>site internet complet</li>\r\n</ul>\r\n<br />\r\n<em><strong>Conditions r&eacute;serv&eacute;es aux adh&eacute;rents CMF. </strong>.En cas de non renouvellement de votre adh&eacute;sion, vous basculerez sur les conditions publiques.</em>\r\n\r\n<p>&nbsp;</p>",
-        "localtax1_type": "0",
-        "localtax2_type": "0",
-        "fk_remise_except": null,
-        "rang": "0",
-        "fk_fournprice": null,
-        "pa_ht": "731.00000000",
-        "marge_tx": 0,
-        "marque_tx": 0,
-        "special_code": "0",
-        "origin": null,
-        "origin_id": null,
-        "fk_code_ventilation": 0,
-        "date_start": 1624053600,
-        "date_end": 1655503200,
-        "ref": "ABO_SCH_PRE_200-399_CMF",
-        "product_ref": "ABO_SCH_PRE_200-399_CMF",
-        "libelle": "Abonnement Opentalent School premium Tranche  200-399 Adhérent CMF",
-        "product_label": "Abonnement Opentalent School premium Tranche  200-399 Adhérent CMF",
-        "product_desc": "<p>Logiciel de gestion et de communication pour les &eacute;tablissements d&#39;enseignement artistique comprend :</p>\r\n\r\n<ul>\r\n\t<li>3 comptes administratifs</li>\r\n\t<li>comptes utilisateurs (&eacute;l&egrave;ves, familles et professeurs)</li>\r\n\t<li>site internet complet</li>\r\n</ul>\r\n<br />\r\n<em><strong>Conditions r&eacute;serv&eacute;es aux adh&eacute;rents CMF. </strong>.En cas de non renouvellement de votre adh&eacute;sion, vous basculerez sur les conditions publiques.</em>\r\n\r\n<p>&nbsp;</p>",
-        "situation_percent": "100",
-        "fk_prev_id": null,
-        "multicurrency_subprice": "731.00000000",
-        "multicurrency_total_ht": "731.00000000",
-        "multicurrency_total_tva": "146.20000000",
-        "multicurrency_total_ttc": "877.20000000",
-        "qty": "1",
-        "subprice": "731.00000000",
-        "product_type": "1",
-        "fk_product": "327",
-        "vat_src_code": "",
-        "tva_tx": "20.000",
-        "localtax1_tx": "0.000",
-        "localtax2_tx": "0.000",
-        "remise_percent": "0",
-        "total_ht": "731.00000000",
-        "total_tva": "146.20000000",
-        "total_localtax1": "0.00000000",
-        "total_localtax2": "0.00000000",
-        "total_ttc": "877.20000000",
-        "info_bits": "0",
-        "id": "952",
-        "rowid": "952",
-        "fk_unit": null,
-        "import_key": null,
-        "array_options": {
-          "options_show_total_ht": null,
-          "options_show_reduc": null
-        },
-        "linkedObjectsIds": null,
-        "canvas": null,
-        "ref_ext": null,
-        "statut": null,
-        "state": null,
-        "state_id": null,
-        "state_code": null,
-        "transport_mode_id": null,
-        "last_main_doc": null,
-        "fk_account": null,
-        "lines": null,
-        "date_creation": null,
-        "date_validation": null,
-        "date_modification": null,
-        "description": "<p>Logiciel de gestion et de communication pour les &eacute;tablissements d&#39;enseignement artistique comprend :</p>\r\n\r\n<ul>\r\n\t<li>3 comptes administratifs</li>\r\n\t<li>comptes utilisateurs (&eacute;l&egrave;ves, familles et professeurs)</li>\r\n\t<li>site internet complet</li>\r\n</ul>\r\n<br />\r\n<em><strong>Conditions r&eacute;serv&eacute;es aux adh&eacute;rents CMF. </strong>.En cas de non renouvellement de votre adh&eacute;sion, vous basculerez sur les conditions publiques.</em>\r\n\r\n<p>&nbsp;</p>",
-        "fk_product_type": "1",
-        "code_ventilation": "100105976",
-        "fk_accounting_account": "100105976"
-      }
-    ],
-    "line": null,
-    "extraparams": [],
-    "specimen": null,
-    "fac_rec": null,
-    "fk_multicurrency": "0",
-    "multicurrency_code": "EUR",
-    "multicurrency_tx": "1.00000000",
-    "multicurrency_total_ht": "731.00000000",
-    "multicurrency_total_tva": "146.20000000",
-    "multicurrency_total_ttc": "877.20000000",
-    "situation_cycle_ref": null,
-    "situation_counter": null,
-    "situation_final": "0",
-    "tab_previous_situation_invoice": [],
-    "tab_next_situation_invoice": [],
-    "id": "256",
-    "import_key": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopen_origvente": "2",
-      "options_logicielfact": "2",
-      "options_versionfact": "2",
-      "options_ec_beg_bill_period_date": 1624053600,
-      "options_ec_end_bill_period_date": 1655503200
-    },
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "thirdparty": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "ref": "FA2105-03135",
-    "ref_ext": null,
-    "statut": "2",
-    "country": null,
-    "country_id": null,
-    "country_code": null,
-    "state": null,
-    "state_id": null,
-    "state_code": null,
-    "mode_reglement_id": "2",
-    "cond_reglement_id": "1",
-    "transport_mode_id": null,
-    "cond_reglement": "Due upon receipt",
-    "shipping_method_id": null,
-    "modelpdf": "InfraSPlus_F",
-    "last_main_doc": "facture/FA2105-03135/FA2105-03135.pdf",
-    "fk_account": "1",
-    "note_public": null,
-    "note_private": null,
-    "fk_incoterms": "0",
-    "libelle_incoterms": null,
-    "location_incoterms": "",
-    "name": null,
-    "lastname": null,
-    "firstname": null,
-    "civility_id": null,
-    "date_creation": 1622017153,
-    "date_validation": 1621980000,
-    "date_modification": 1626091889,
-    "entity": "1",
-    "date_pointoftax": "",
-    "mode_reglement": "Virement",
-    "cond_reglement_doc": "Due upon receipt",
-    "user_author": "5",
-    "user_valid": "5",
-    "totalpaid": null,
-    "totalcreditnotes": "877.20000000",
-    "totaldeposits": null,
-    "remaintopay": "0",
-    "contacts_ids": [
-      "29845"
-    ]
-  }
-]

+ 0 - 442
tests/Service/Dolibarr/fixtures/contacts.json

@@ -1,442 +0,0 @@
-[
-  {
-    "civility_id": null,
-    "civility_code": "MME",
-    "civility": "Madame",
-    "address": null,
-    "zip": null,
-    "town": null,
-    "state_id": null,
-    "state_code": null,
-    "state": null,
-    "poste": "Secrétaire",
-    "socid": "8",
-    "statut": "1",
-    "code": null,
-    "email": "abcd@hotmail.com",
-    "no_email": null,
-    "skype": null,
-    "photo": null,
-    "jabberid": null,
-    "phone_pro": "+33478570000",
-    "phone_perso": "",
-    "phone_mobile": "+33682980000",
-    "fax": "",
-    "priv": "0",
-    "birthday": "",
-    "default_lang": null,
-    "ref_facturation": null,
-    "ref_contrat": null,
-    "ref_commande": null,
-    "ref_propal": null,
-    "user_id": null,
-    "user_login": null,
-    "roles": null,
-    "cacheprospectstatus": [],
-    "fk_prospectlevel": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Jamais contacté",
-    "stcomm_picto": null,
-    "id": "5868",
-    "import_key": "crm",
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopen_person_id": "108939"
-    },
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "ref": "5868",
-    "ref_ext": null,
-    "country": "",
-    "country_id": "0",
-    "country_code": "",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": null,
-    "cond_reglement_id": null,
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": null,
-    "note_public": null,
-    "note_private": null,
-    "fk_incoterms": null,
-    "libelle_incoterms": null,
-    "location_incoterms": null,
-    "name": null,
-    "lastname": "DUPONT",
-    "firstname": "Valerie",
-    "date_creation": "",
-    "date_validation": null,
-    "date_modification": 1612541370,
-    "entity": "1",
-    "socname": "Société Musicale l'Abeille",
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "mail": "abcd@hotmail.com",
-    "gender": "woman"
-  },
-  {
-    "civility_id": null,
-    "civility_code": "MME",
-    "civility": "Madame",
-    "address": null,
-    "zip": null,
-    "town": null,
-    "state_id": null,
-    "state_code": null,
-    "state": null,
-    "poste": "Présidente",
-    "socid": "8",
-    "statut": "1",
-    "code": null,
-    "email": "xyz@sfr.fr",
-    "no_email": null,
-    "skype": null,
-    "photo": null,
-    "jabberid": null,
-    "phone_pro": "",
-    "phone_perso": "",
-    "phone_mobile": "+33600009399",
-    "fax": "",
-    "priv": "0",
-    "birthday": "",
-    "default_lang": null,
-    "ref_facturation": null,
-    "ref_contrat": null,
-    "ref_commande": null,
-    "ref_propal": null,
-    "user_id": null,
-    "user_login": null,
-    "roles": null,
-    "cacheprospectstatus": [],
-    "fk_prospectlevel": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Jamais contact&eacute;",
-    "stcomm_picto": null,
-    "id": "5869",
-    "import_key": "crm",
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopen_person_id": "156252"
-    },
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "ref": "5869",
-    "ref_ext": null,
-    "country": "",
-    "country_id": "0",
-    "country_code": "",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": null,
-    "cond_reglement_id": null,
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": null,
-    "note_public": null,
-    "note_private": null,
-    "fk_incoterms": null,
-    "libelle_incoterms": null,
-    "location_incoterms": null,
-    "name": null,
-    "lastname": "DURAND",
-    "firstname": "Elise",
-    "date_creation": "",
-    "date_validation": null,
-    "date_modification": 1612541370,
-    "entity": "1",
-    "socname": "Société Musicale l'Abeille",
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "mail": "xyz@sfr.fr",
-    "gender": "woman"
-  },
-  {
-    "civility_id": null,
-    "civility_code": "MME",
-    "civility": "Madame",
-    "address": null,
-    "zip": null,
-    "town": null,
-    "state_id": null,
-    "state_code": null,
-    "state": null,
-    "poste": "Trésorière",
-    "socid": "9",
-    "statut": "1",
-    "code": null,
-    "email": null,
-    "no_email": null,
-    "skype": null,
-    "photo": null,
-    "jabberid": null,
-    "phone_pro": "",
-    "phone_perso": "",
-    "phone_mobile": "",
-    "fax": "",
-    "priv": "0",
-    "birthday": "",
-    "default_lang": null,
-    "ref_facturation": null,
-    "ref_contrat": null,
-    "ref_commande": null,
-    "ref_propal": null,
-    "user_id": null,
-    "user_login": null,
-    "roles": null,
-    "cacheprospectstatus": [],
-    "fk_prospectlevel": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Jamais contact&eacute;",
-    "stcomm_picto": null,
-    "id": "5870",
-    "import_key": "crm",
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopen_person_id": "112775"
-    },
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "ref": "5870",
-    "ref_ext": null,
-    "country": "",
-    "country_id": "0",
-    "country_code": "",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": null,
-    "cond_reglement_id": null,
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": null,
-    "note_public": null,
-    "note_private": null,
-    "fk_incoterms": null,
-    "libelle_incoterms": null,
-    "location_incoterms": null,
-    "name": null,
-    "lastname": "LEGRAND",
-    "firstname": "Anaïs",
-    "date_creation": "",
-    "date_validation": null,
-    "date_modification": 1612541370,
-    "entity": "1",
-    "socname": "Ensemble à vents Opus 92",
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "mail": null,
-    "gender": "woman"
-  },
-  {
-    "civility_id": null,
-    "civility_code": "MME",
-    "civility": "Madame",
-    "address": null,
-    "zip": null,
-    "town": null,
-    "state_id": null,
-    "state_code": null,
-    "state": null,
-    "poste": "Secrétaire",
-    "socid": "9",
-    "statut": "1",
-    "code": null,
-    "email": null,
-    "no_email": null,
-    "skype": null,
-    "photo": null,
-    "jabberid": null,
-    "phone_pro": "",
-    "phone_perso": "",
-    "phone_mobile": "",
-    "fax": "",
-    "priv": "0",
-    "birthday": "",
-    "default_lang": null,
-    "ref_facturation": null,
-    "ref_contrat": null,
-    "ref_commande": null,
-    "ref_propal": null,
-    "user_id": null,
-    "user_login": null,
-    "roles": null,
-    "cacheprospectstatus": [],
-    "fk_prospectlevel": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Jamais contact&eacute;",
-    "stcomm_picto": null,
-    "id": "5871",
-    "import_key": "crm",
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopen_person_id": "302117"
-    },
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "ref": "5871",
-    "ref_ext": null,
-    "country": "",
-    "country_id": "0",
-    "country_code": "",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": null,
-    "cond_reglement_id": null,
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": null,
-    "note_public": null,
-    "note_private": null,
-    "fk_incoterms": null,
-    "libelle_incoterms": null,
-    "location_incoterms": null,
-    "name": null,
-    "lastname": "LEJEUNE",
-    "firstname": "Cassandra",
-    "date_creation": "",
-    "date_validation": null,
-    "date_modification": 1612541370,
-    "entity": "1",
-    "socname": "Ensemble à vents Opus 92",
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "mail": null,
-    "gender": "woman"
-  },
-  {
-    "civility_id": null,
-    "civility_code": "MR",
-    "civility": "Monsieur",
-    "address": null,
-    "zip": null,
-    "town": null,
-    "state_id": null,
-    "state_code": null,
-    "state": null,
-    "poste": "Président",
-    "socid": "9",
-    "statut": "1",
-    "code": null,
-    "email": "email@gmail.com",
-    "no_email": null,
-    "skype": null,
-    "photo": null,
-    "jabberid": null,
-    "phone_pro": "",
-    "phone_perso": "",
-    "phone_mobile": "",
-    "fax": "",
-    "priv": "0",
-    "birthday": "",
-    "default_lang": null,
-    "ref_facturation": null,
-    "ref_contrat": null,
-    "ref_commande": null,
-    "ref_propal": null,
-    "user_id": null,
-    "user_login": null,
-    "roles": null,
-    "cacheprospectstatus": [],
-    "fk_prospectlevel": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Jamais contact&eacute;",
-    "stcomm_picto": null,
-    "id": "5872",
-    "import_key": "crm",
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopen_person_id": null
-    },
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "ref": "5872",
-    "ref_ext": null,
-    "country": "",
-    "country_id": "0",
-    "country_code": "",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": null,
-    "cond_reglement_id": null,
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": null,
-    "note_public": null,
-    "note_private": null,
-    "fk_incoterms": null,
-    "libelle_incoterms": null,
-    "location_incoterms": null,
-    "name": null,
-    "lastname": "ZORRO",
-    "firstname": "Fabrice",
-    "date_creation": "",
-    "date_validation": null,
-    "date_modification": 1612541370,
-    "entity": "1",
-    "socname": "Ensemble à vents Opus 92",
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "mail": "email@gmail.com",
-    "gender": "man"
-  }
-]

+ 0 - 187
tests/Service/Dolibarr/fixtures/contract.json

@@ -1,187 +0,0 @@
-[
-  {
-    "ref_customer": null,
-    "ref_supplier": null,
-    "entity": "1",
-    "socid": "43",
-    "societe": null,
-    "statut": "1",
-    "product": null,
-    "fk_user_author": null,
-    "user_author_id": "1",
-    "user_creation": null,
-    "user_cloture": null,
-    "date_creation": 1280786400,
-    "date_modification": null,
-    "date_validation": null,
-    "date_contrat": 1280786400,
-    "commercial_signature_id": "5",
-    "commercial_suivi_id": "5",
-    "fk_projet": null,
-    "extraparams": [],
-    "lines": [
-      {
-        "id": "4",
-        "ref": "ABO_ART_PRE_CMF",
-        "tms": null,
-        "fk_contrat": "2",
-        "fk_product": "282",
-        "statut": "4",
-        "type": null,
-        "label": null,
-        "libelle": null,
-        "description": "<p>Logiciel de gestion et de communication en ligne pour les structures culturelles de type Chorale, Orchestre, Compagnie (cirque, danse, de rue, théâtre,etc...).\n<br/>Inclus 150 comptes internet pour les membres et un site internet personnalisable.\n<br/>Conditions réservées aux adhérents CMF. En cas de non renouvellement de votre adhésion, vous basculerez sur les conditions publiques.</p>",
-        "product_type": "1",
-        "product_ref": "ABO_ART_PRE_CMF",
-        "product_label": "Abonnement Opentalent Artist premium CMF",
-        "date_commande": null,
-        "date_start": 1280786400,
-        "date_start_real": 1280786400,
-        "date_end": 1659477600,
-        "date_end_real": "",
-        "tva_tx": "20.000",
-        "localtax1_tx": "0.000",
-        "localtax2_tx": "0.000",
-        "localtax1_type": null,
-        "localtax2_type": null,
-        "qty": "1",
-        "remise_percent": "0",
-        "remise": null,
-        "fk_remise_except": null,
-        "subprice": "63.33000000",
-        "price": "63.33",
-        "price_ht": "63.33",
-        "total_ht": "63.33000000",
-        "total_tva": "12.67000000",
-        "total_localtax1": "0.00000000",
-        "total_localtax2": "0.00000000",
-        "total_ttc": "76.00000000",
-        "fk_fournprice": null,
-        "pa_ht": "63.33000000",
-        "info_bits": "0",
-        "fk_user_author": "1",
-        "fk_user_ouverture": "1",
-        "fk_user_cloture": null,
-        "commentaire": null,
-        "rowid": null,
-        "fk_unit": null,
-        "import_key": null,
-        "array_options": {
-          "options_2iopen_vers_fact": null,
-          "options_2iopen_log_fact": null,
-          "options_ec_type_line": "8"
-        },
-        "linkedObjectsIds": null,
-        "canvas": null,
-        "origin": null,
-        "origin_id": null,
-        "ref_ext": null,
-        "state": null,
-        "state_id": null,
-        "state_code": null,
-        "barcode_type": null,
-        "barcode_type_code": null,
-        "barcode_type_label": null,
-        "barcode_type_coder": null,
-        "transport_mode_id": null,
-        "last_main_doc": null,
-        "fk_account": null,
-        "note": null,
-        "lines": null,
-        "date_creation": null,
-        "date_validation": null,
-        "date_modification": null,
-        "desc": "<p>Logiciel de gestion et de communication en ligne pour les structures culturelles de type Chorale, Orchestre, Compagnie (cirque, danse, de rue, théâtre,etc...).\n<br/>Inclus 150 comptes internet pour les membres et un site internet personnalisable.\n<br/>Conditions réservées aux adhérents CMF. En cas de non renouvellement de votre adhésion, vous basculerez sur les conditions publiques.</p>",
-        "vat_src_code": "",
-        "product_desc": "<p>Logiciel de gestion et de communication en ligne pour les structures culturelles de type Chorale, Orchestre, Compagnie (cirque, danse, de rue, th&eacute;&acirc;tre,etc...).<br />\r\nInclus 150 comptes internet pour les membres et un site internet personnalisable.<br />\r\nConditions r&eacute;serv&eacute;es aux adh&eacute;rents CMF. En cas de non renouvellement de votre adh&eacute;sion, vous basculerez sur les conditions publiques.</p>"
-      }
-    ],
-    "id": "2",
-    "import_key": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopen_origvente": "2",
-      "options_logicielfact": "1",
-      "options_versionfact": "2",
-      "options_ec_initial_amount": "63.33000000",
-      "options_ec_amount": "63.33000000",
-      "options_ec_initial_value_installation": null,
-      "options_ec_current_value_installation": "0.00000000",
-      "options_ec_signature_date": "",
-      "options_ec_effective_date": 1280786400,
-      "options_ec_duration_months": "12",
-      "options_ec_tacit_renewal": "1",
-      "options_ec_termination_period_months": "2",
-      "options_ec_des_term_date": "",
-      "options_ec_eff_term_date": "",
-      "options_ec_billing_due": "1",
-      "options_ec_billing_frequency": "4",
-      "options_ec_billing_begin_period": "1",
-      "options_ec_payment_condition": "1",
-      "options_ec_payment_mode": "2",
-      "options_ec_account": "1",
-      "options_ec_revaluation_index": "2",
-      "options_ec_enable_to_revaluation_date": 1609455600,
-      "options_ec_revaluation_date": "1",
-      "options_ec_month_for_new_revaluation_index": "11",
-      "options_ec_initial_revaluation_index_used": "1",
-      "options_ec_last_revaluation_index_used": "14",
-      "options_ec_revaluation_calculation_base": "2",
-      "options_ec_fixed_amount_not_revaluable": null,
-      "options_ec_unauthorized_deflation": "1",
-      "options_ec_amount_round_rule": null
-    },
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "thirdparty": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "ref": "0000037-C1_1",
-    "ref_ext": null,
-    "country": null,
-    "country_id": null,
-    "country_code": null,
-    "state": null,
-    "state_id": null,
-    "state_code": null,
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": null,
-    "cond_reglement_id": null,
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": null,
-    "note_public": null,
-    "note_private": null,
-    "note": null,
-    "total_ht": "63.33",
-    "total_tva": null,
-    "total_localtax1": null,
-    "total_localtax2": null,
-    "total_ttc": "76",
-    "fk_incoterms": null,
-    "libelle_incoterms": null,
-    "location_incoterms": null,
-    "name": null,
-    "lastname": null,
-    "firstname": null,
-    "mise_en_service": 1280786400,
-    "fin_validite": 1627941600,
-    "fk_soc": "43",
-    "nbofserviceswait": 0,
-    "nbofservicesopened": 1,
-    "nbofservicesexpired": 0,
-    "nbofservicesclosed": 0,
-    "nbofservices": 1,
-    "total_vat": "12.67"
-  }
-]

+ 0 - 798
tests/Service/Dolibarr/fixtures/thirdparties.json

@@ -1,798 +0,0 @@
-[
-  {
-    "entity": "1",
-    "name": "Etablissement d'Enseignement Artistique",
-    "name_alias": null,
-    "address": "\n217, rue Raoul Follereau\n",
-    "zip": "74300",
-    "town": "CLUSES",
-    "status": "1",
-    "state_id": "81",
-    "state_code": "74",
-    "state": "Haute-Savoie",
-    "phone": "+33678403010",
-    "fax": null,
-    "email": null,
-    "skype": null,
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "url": null,
-    "barcode": null,
-    "idprof1": null,
-    "idprof2": null,
-    "idprof3": null,
-    "idprof4": null,
-    "idprof5": null,
-    "idprof6": null,
-    "tva_assuj": "1",
-    "tva_intra": null,
-    "localtax1_assuj": "0",
-    "localtax1_value": null,
-    "localtax2_assuj": "0",
-    "localtax2_value": null,
-    "managers": null,
-    "capital": null,
-    "typent_id": "0",
-    "typent_code": "TE_UNKNOWN",
-    "effectif": "",
-    "effectif_id": "0",
-    "forme_juridique_code": "812",
-    "forme_juridique": null,
-    "remise_percent": "",
-    "remise_supplier_percent": "0",
-    "mode_reglement_supplier_id": null,
-    "cond_reglement_supplier_id": null,
-    "transport_mode_supplier_id": null,
-    "fk_prospectlevel": null,
-    "date_modification": 1632728888,
-    "user_modification": null,
-    "date_creation": "",
-    "user_creation": null,
-    "specimen": null,
-    "client": "2",
-    "prospect": 0,
-    "fournisseur": "0",
-    "code_client": "001855",
-    "code_fournisseur": null,
-    "code_compta": "0001855",
-    "code_compta_client": null,
-    "code_compta_fournisseur": null,
-    "note_private": null,
-    "note_public": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Never contacted",
-    "stcomm_picto": null,
-    "price_level": null,
-    "outstanding_limit": null,
-    "order_min_amount": null,
-    "supplier_order_min_amount": null,
-    "parent": null,
-    "default_lang": null,
-    "ref": "1726",
-    "ref_ext": null,
-    "import_key": "crm",
-    "webservices_url": null,
-    "webservices_key": null,
-    "logo": null,
-    "logo_small": null,
-    "logo_mini": null,
-    "logo_squarred": null,
-    "logo_squarred_small": null,
-    "logo_squarred_mini": null,
-    "accountancy_code_sell": null,
-    "accountancy_code_buy": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_sirene_status": null,
-      "options_b4d_spe_name": null,
-      "options_sirene_update_date": "",
-      "options_2iopen_domain": "7",
-      "options_2iopen_structure_type": "12",
-      "options_2iopen_nombre_eleves": null,
-      "options_2iopen_software_used": "4",
-      "options_2iopen_num_portable": null,
-      "options_2iopen_structure_type_cmf": null,
-      "options_2iopen_organization_id": "37306"
-    },
-    "fk_incoterms": null,
-    "location_incoterms": null,
-    "libelle_incoterms": null,
-    "fk_multicurrency": null,
-    "multicurrency_code": null,
-    "id": "1726",
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "statut": null,
-    "country": "France",
-    "country_id": "1",
-    "country_code": "FR",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": "2",
-    "cond_reglement_id": "1",
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": "0",
-    "lastname": null,
-    "firstname": null,
-    "civility_id": null,
-    "date_validation": null
-  },
-  {
-    "entity": "1",
-    "name": "Société Musicale l'Abeille",
-    "name_alias": null,
-    "address": "\n4 rue Jean Moulin\n\n",
-    "zip": "69310",
-    "town": "PIERRE BENITE",
-    "status": "1",
-    "state_id": "76",
-    "state_code": "69",
-    "state": "Rhône",
-    "phone": "623936009",
-    "fax": null,
-    "email": "alexis.manasser@yahoo.fr",
-    "skype": null,
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "url": "http://abeille.wifeo.com/",
-    "barcode": null,
-    "idprof1": null,
-    "idprof2": null,
-    "idprof3": null,
-    "idprof4": null,
-    "idprof5": null,
-    "idprof6": null,
-    "tva_assuj": "1",
-    "tva_intra": null,
-    "localtax1_assuj": "0",
-    "localtax1_value": null,
-    "localtax2_assuj": "0",
-    "localtax2_value": null,
-    "managers": null,
-    "capital": null,
-    "typent_id": "0",
-    "typent_code": "TE_UNKNOWN",
-    "effectif": "",
-    "effectif_id": "0",
-    "forme_juridique_code": "92",
-    "forme_juridique": "Association loi 1901 ou assimilé",
-    "remise_percent": "",
-    "remise_supplier_percent": "0",
-    "mode_reglement_supplier_id": null,
-    "cond_reglement_supplier_id": null,
-    "transport_mode_supplier_id": null,
-    "fk_prospectlevel": null,
-    "date_modification": 1632728888,
-    "user_modification": null,
-    "date_creation": "",
-    "user_creation": null,
-    "specimen": null,
-    "client": "2",
-    "prospect": 0,
-    "fournisseur": "0",
-    "code_client": "000002",
-    "code_fournisseur": null,
-    "code_compta": "0000002",
-    "code_compta_client": null,
-    "code_compta_fournisseur": null,
-    "note_private": "Autres email(s): ",
-    "note_public": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Never contacted",
-    "stcomm_picto": null,
-    "price_level": null,
-    "outstanding_limit": null,
-    "order_min_amount": null,
-    "supplier_order_min_amount": null,
-    "parent": "711",
-    "default_lang": null,
-    "ref": "8",
-    "ref_ext": "3c839cab-f46d-eddc-f2ef-543fb02978a2",
-    "import_key": "crm",
-    "webservices_url": null,
-    "webservices_key": null,
-    "logo": null,
-    "logo_small": null,
-    "logo_mini": null,
-    "logo_squarred": null,
-    "logo_squarred_small": null,
-    "logo_squarred_mini": null,
-    "accountancy_code_sell": null,
-    "accountancy_code_buy": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopeninfoopentalent": null,
-      "options_sirene_status": null,
-      "options_b4d_spe_name": null,
-      "options_sirene_update_date": "",
-      "options_2iopen_domain": "7",
-      "options_2iopen_structure_type": "21",
-      "options_2iopen_nombre_eleves": null,
-      "options_2iopen_software_opentalent": null,
-      "options_2iopen_software_used": "1",
-      "options_2iopen_num_portable": null,
-      "options_2iopen_structure_type_cmf": null,
-      "options_2iopen_organization_id": "13878"
-    },
-    "fk_incoterms": null,
-    "location_incoterms": null,
-    "libelle_incoterms": null,
-    "fk_multicurrency": null,
-    "multicurrency_code": null,
-    "id": "8",
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "statut": null,
-    "country": "France",
-    "country_id": "1",
-    "country_code": "FR",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": "2",
-    "cond_reglement_id": "1",
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": "0",
-    "lastname": null,
-    "firstname": null,
-    "civility_id": null,
-    "date_validation": null
-  },
-  {
-    "entity": "1",
-    "name": "Ensemble à vents Opus 92",
-    "name_alias": null,
-    "address": "\n96 rue de la Sous Préfecture\n\n",
-    "zip": "69400",
-    "town": "VILLEFRANCHE-SUR-SAÔNE",
-    "status": "1",
-    "state_id": "76",
-    "state_code": "69",
-    "state": "Rhône",
-    "phone": "683283834",
-    "fax": null,
-    "email": "bureau@opus92.org",
-    "skype": null,
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "url": "http://www.opus92.org",
-    "barcode": null,
-    "idprof1": null,
-    "idprof2": null,
-    "idprof3": null,
-    "idprof4": null,
-    "idprof5": null,
-    "idprof6": null,
-    "tva_assuj": "1",
-    "tva_intra": null,
-    "localtax1_assuj": "0",
-    "localtax1_value": null,
-    "localtax2_assuj": "0",
-    "localtax2_value": null,
-    "managers": null,
-    "capital": null,
-    "typent_id": "0",
-    "typent_code": "TE_UNKNOWN",
-    "effectif": "",
-    "effectif_id": "0",
-    "forme_juridique_code": "92",
-    "forme_juridique": "Association loi 1901 ou assimilé",
-    "remise_percent": "",
-    "remise_supplier_percent": "0",
-    "mode_reglement_supplier_id": null,
-    "cond_reglement_supplier_id": null,
-    "transport_mode_supplier_id": null,
-    "fk_prospectlevel": null,
-    "date_modification": 1632728888,
-    "user_modification": null,
-    "date_creation": "",
-    "user_creation": null,
-    "specimen": null,
-    "client": "2",
-    "prospect": 0,
-    "fournisseur": "0",
-    "code_client": "000003",
-    "code_fournisseur": null,
-    "code_compta": "0000003",
-    "code_compta_client": null,
-    "code_compta_fournisseur": null,
-    "note_private": "Autres email(s): contact@opus92.org",
-    "note_public": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Never contacted",
-    "stcomm_picto": null,
-    "price_level": null,
-    "outstanding_limit": null,
-    "order_min_amount": null,
-    "supplier_order_min_amount": null,
-    "parent": "711",
-    "default_lang": null,
-    "ref": "9",
-    "ref_ext": "7191614d-2d4c-8c25-17b9-543fb25fa130",
-    "import_key": "crm",
-    "webservices_url": null,
-    "webservices_key": null,
-    "logo": null,
-    "logo_small": null,
-    "logo_mini": null,
-    "logo_squarred": null,
-    "logo_squarred_small": null,
-    "logo_squarred_mini": null,
-    "accountancy_code_sell": null,
-    "accountancy_code_buy": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopeninfoopentalent": null,
-      "options_sirene_status": null,
-      "options_b4d_spe_name": null,
-      "options_sirene_update_date": "",
-      "options_2iopen_domain": "7",
-      "options_2iopen_structure_type": "19",
-      "options_2iopen_nombre_eleves": null,
-      "options_2iopen_software_opentalent": null,
-      "options_2iopen_software_used": "1",
-      "options_2iopen_num_portable": null,
-      "options_2iopen_structure_type_cmf": null,
-      "options_2iopen_organization_id": "13891"
-    },
-    "fk_incoterms": null,
-    "location_incoterms": null,
-    "libelle_incoterms": null,
-    "fk_multicurrency": null,
-    "multicurrency_code": null,
-    "id": "9",
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "statut": null,
-    "country": "France",
-    "country_id": "1",
-    "country_code": "FR",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": "2",
-    "cond_reglement_id": "1",
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": "0",
-    "lastname": null,
-    "firstname": null,
-    "civility_id": null,
-    "date_validation": null
-  },
-  {
-    "entity": "1",
-    "name": "Association Musicale de Montanay",
-    "name_alias": null,
-    "address": "\n142 rue Centrale\n\n",
-    "zip": "69250",
-    "town": "MONTANAY",
-    "status": "1",
-    "state_id": "76",
-    "state_code": "69",
-    "state": "Rhône",
-    "phone": "04 78 00 73 64",
-    "fax": null,
-    "email": "gonnet-family@wanadoo.fr",
-    "skype": null,
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "url": "https://assocmusicalemontanay.wordpress.com/",
-    "barcode": null,
-    "idprof1": null,
-    "idprof2": null,
-    "idprof3": null,
-    "idprof4": null,
-    "idprof5": null,
-    "idprof6": null,
-    "tva_assuj": "1",
-    "tva_intra": null,
-    "localtax1_assuj": "0",
-    "localtax1_value": null,
-    "localtax2_assuj": "0",
-    "localtax2_value": null,
-    "managers": null,
-    "capital": null,
-    "typent_id": "0",
-    "typent_code": "TE_UNKNOWN",
-    "effectif": "",
-    "effectif_id": "0",
-    "forme_juridique_code": "92",
-    "forme_juridique": "Association loi 1901 ou assimilé",
-    "remise_percent": "",
-    "remise_supplier_percent": "0",
-    "mode_reglement_supplier_id": null,
-    "cond_reglement_supplier_id": null,
-    "transport_mode_supplier_id": null,
-    "fk_prospectlevel": null,
-    "date_modification": 1632728888,
-    "user_modification": null,
-    "date_creation": "",
-    "user_creation": null,
-    "specimen": null,
-    "client": "2",
-    "prospect": 0,
-    "fournisseur": "0",
-    "code_client": "000004",
-    "code_fournisseur": null,
-    "code_compta": "0000004",
-    "code_compta_client": null,
-    "code_compta_fournisseur": null,
-    "note_private": "Autres email(s): franckbrosse@aol.com, direction.amm@gmail.com",
-    "note_public": null,
-    "stcomm_id": "3",
-    "statut_commercial": "Contacted",
-    "stcomm_picto": null,
-    "price_level": null,
-    "outstanding_limit": null,
-    "order_min_amount": null,
-    "supplier_order_min_amount": null,
-    "parent": "711",
-    "default_lang": null,
-    "ref": "10",
-    "ref_ext": "7f92c92b-ffea-2753-c2bd-4d3a116f7d4e",
-    "import_key": "crm",
-    "webservices_url": null,
-    "webservices_key": null,
-    "logo": null,
-    "logo_small": null,
-    "logo_mini": null,
-    "logo_squarred": null,
-    "logo_squarred_small": null,
-    "logo_squarred_mini": null,
-    "accountancy_code_sell": null,
-    "accountancy_code_buy": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopeninfoopentalent": null,
-      "options_sirene_status": null,
-      "options_b4d_spe_name": null,
-      "options_sirene_update_date": "",
-      "options_2iopen_domain": "7",
-      "options_2iopen_structure_type": "19",
-      "options_2iopen_nombre_eleves": "2",
-      "options_2iopen_software_opentalent": null,
-      "options_2iopen_software_used": "1",
-      "options_2iopen_num_portable": null,
-      "options_2iopen_structure_type_cmf": null,
-      "options_2iopen_organization_id": "13904"
-    },
-    "fk_incoterms": null,
-    "location_incoterms": null,
-    "libelle_incoterms": null,
-    "fk_multicurrency": null,
-    "multicurrency_code": null,
-    "id": "10",
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "statut": null,
-    "country": "France",
-    "country_id": "1",
-    "country_code": "FR",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": "2",
-    "cond_reglement_id": "1",
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": "0",
-    "lastname": null,
-    "firstname": null,
-    "civility_id": null,
-    "date_validation": null
-  },
-  {
-    "entity": "1",
-    "name": "Le Chant du Marmont",
-    "name_alias": null,
-    "address": "\nen Mairie\nRue des Gagères\n",
-    "zip": "01480",
-    "town": "FRANS",
-    "status": "1",
-    "state_id": "7",
-    "state_code": "01",
-    "state": "Ain",
-    "phone": "474607172",
-    "fax": null,
-    "email": "pat.mouchon@orange.fr",
-    "skype": null,
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "url": "http:/bffrans.freeheberg.com",
-    "barcode": null,
-    "idprof1": null,
-    "idprof2": null,
-    "idprof3": null,
-    "idprof4": null,
-    "idprof5": null,
-    "idprof6": null,
-    "tva_assuj": "1",
-    "tva_intra": null,
-    "localtax1_assuj": "0",
-    "localtax1_value": null,
-    "localtax2_assuj": "0",
-    "localtax2_value": null,
-    "managers": null,
-    "capital": null,
-    "typent_id": "0",
-    "typent_code": "TE_UNKNOWN",
-    "effectif": "",
-    "effectif_id": "0",
-    "forme_juridique_code": "92",
-    "forme_juridique": "Association loi 1901 ou assimilé",
-    "remise_percent": "",
-    "remise_supplier_percent": "0",
-    "mode_reglement_supplier_id": null,
-    "cond_reglement_supplier_id": null,
-    "transport_mode_supplier_id": null,
-    "fk_prospectlevel": null,
-    "date_modification": 1632728888,
-    "user_modification": null,
-    "date_creation": "",
-    "user_creation": null,
-    "specimen": null,
-    "client": "2",
-    "prospect": 0,
-    "fournisseur": "0",
-    "code_client": "000005",
-    "code_fournisseur": null,
-    "code_compta": "0000005",
-    "code_compta_client": null,
-    "code_compta_fournisseur": null,
-    "note_private": "Autres email(s): nuguet.roger@orange.fr",
-    "note_public": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Never contacted",
-    "stcomm_picto": null,
-    "price_level": null,
-    "outstanding_limit": null,
-    "order_min_amount": null,
-    "supplier_order_min_amount": null,
-    "parent": "711",
-    "default_lang": null,
-    "ref": "11",
-    "ref_ext": "5001328e-ce5e-f1b2-ae9e-543fb29aea42",
-    "import_key": "crm",
-    "webservices_url": null,
-    "webservices_key": null,
-    "logo": null,
-    "logo_small": null,
-    "logo_mini": null,
-    "logo_squarred": null,
-    "logo_squarred_small": null,
-    "logo_squarred_mini": null,
-    "accountancy_code_sell": null,
-    "accountancy_code_buy": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopeninfoopentalent": null,
-      "options_sirene_status": null,
-      "options_b4d_spe_name": null,
-      "options_sirene_update_date": "",
-      "options_2iopen_domain": "7",
-      "options_2iopen_structure_type": "19",
-      "options_2iopen_nombre_eleves": null,
-      "options_2iopen_software_opentalent": null,
-      "options_2iopen_software_used": "1",
-      "options_2iopen_num_portable": null,
-      "options_2iopen_structure_type_cmf": null,
-      "options_2iopen_organization_id": "13917"
-    },
-    "fk_incoterms": null,
-    "location_incoterms": null,
-    "libelle_incoterms": null,
-    "fk_multicurrency": null,
-    "multicurrency_code": null,
-    "id": "11",
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "statut": null,
-    "country": "France",
-    "country_id": "1",
-    "country_code": "FR",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": "2",
-    "cond_reglement_id": "1",
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": "0",
-    "lastname": null,
-    "firstname": null,
-    "civility_id": null,
-    "date_validation": null
-  },
-  {
-    "entity": "1",
-    "name": "Orchestre Symphonique de Villefranche",
-    "name_alias": null,
-    "address": "\n96 rue de la Sous Préfecture\n\n",
-    "zip": "69400",
-    "town": "VILLEFRANCHE-SUR-SAÔNE",
-    "status": "1",
-    "state_id": "76",
-    "state_code": "69",
-    "state": "Rhône",
-    "phone": "06.86.12.85.22",
-    "fax": null,
-    "email": "orchestre.osv@orange.fr",
-    "skype": null,
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "url": " ",
-    "barcode": null,
-    "idprof1": null,
-    "idprof2": null,
-    "idprof3": null,
-    "idprof4": null,
-    "idprof5": null,
-    "idprof6": null,
-    "tva_assuj": "1",
-    "tva_intra": null,
-    "localtax1_assuj": "0",
-    "localtax1_value": null,
-    "localtax2_assuj": "0",
-    "localtax2_value": null,
-    "managers": null,
-    "capital": null,
-    "typent_id": "0",
-    "typent_code": "TE_UNKNOWN",
-    "effectif": "",
-    "effectif_id": "0",
-    "forme_juridique_code": "92",
-    "forme_juridique": "Association loi 1901 ou assimilé",
-    "remise_percent": "",
-    "remise_supplier_percent": "0",
-    "mode_reglement_supplier_id": null,
-    "cond_reglement_supplier_id": null,
-    "transport_mode_supplier_id": null,
-    "fk_prospectlevel": null,
-    "date_modification": 1632728888,
-    "user_modification": null,
-    "date_creation": "",
-    "user_creation": null,
-    "specimen": null,
-    "client": "2",
-    "prospect": 0,
-    "fournisseur": "0",
-    "code_client": "000006",
-    "code_fournisseur": null,
-    "code_compta": "0000006",
-    "code_compta_client": null,
-    "code_compta_fournisseur": null,
-    "note_private": "Autres email(s): sebremont@orange.fr",
-    "note_public": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Never contacted",
-    "stcomm_picto": null,
-    "price_level": null,
-    "outstanding_limit": null,
-    "order_min_amount": null,
-    "supplier_order_min_amount": null,
-    "parent": "711",
-    "default_lang": null,
-    "ref": "12",
-    "ref_ext": "8f83c66f-384c-98c8-94e5-543fb25fb8b6",
-    "import_key": "crm",
-    "webservices_url": null,
-    "webservices_key": null,
-    "logo": null,
-    "logo_small": null,
-    "logo_mini": null,
-    "logo_squarred": null,
-    "logo_squarred_small": null,
-    "logo_squarred_mini": null,
-    "accountancy_code_sell": null,
-    "accountancy_code_buy": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_2iopeninfoopentalent": null,
-      "options_sirene_status": null,
-      "options_b4d_spe_name": null,
-      "options_sirene_update_date": "",
-      "options_2iopen_domain": "7",
-      "options_2iopen_structure_type": "21",
-      "options_2iopen_nombre_eleves": null,
-      "options_2iopen_software_opentalent": null,
-      "options_2iopen_software_used": "1",
-      "options_2iopen_num_portable": null,
-      "options_2iopen_structure_type_cmf": null,
-      "options_2iopen_organization_id": "13930"
-    },
-    "fk_incoterms": null,
-    "location_incoterms": null,
-    "libelle_incoterms": null,
-    "fk_multicurrency": null,
-    "multicurrency_code": null,
-    "id": "12",
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "statut": null,
-    "country": "France",
-    "country_id": "1",
-    "country_code": "FR",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": "2",
-    "cond_reglement_id": "1",
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": "0",
-    "lastname": null,
-    "firstname": null,
-    "civility_id": null,
-    "date_validation": null
-  }
-]

+ 0 - 135
tests/Service/Dolibarr/fixtures/thirdparty.json

@@ -1,135 +0,0 @@
-[
-  {
-    "entity": "1",
-    "name": "Etablissement d'Enseignement Artistique",
-    "name_alias": null,
-    "address": "\n217, rue Raoul Follereau\n",
-    "zip": "74300",
-    "town": "CLUSES",
-    "status": "1",
-    "state_id": "81",
-    "state_code": "74",
-    "state": "Haute-Savoie",
-    "phone": "+33678403010",
-    "fax": null,
-    "email": null,
-    "skype": null,
-    "twitter": null,
-    "facebook": null,
-    "linkedin": null,
-    "url": null,
-    "barcode": null,
-    "idprof1": null,
-    "idprof2": null,
-    "idprof3": null,
-    "idprof4": null,
-    "idprof5": null,
-    "idprof6": null,
-    "tva_assuj": "1",
-    "tva_intra": null,
-    "localtax1_assuj": "0",
-    "localtax1_value": null,
-    "localtax2_assuj": "0",
-    "localtax2_value": null,
-    "managers": null,
-    "capital": null,
-    "typent_id": "0",
-    "typent_code": "TE_UNKNOWN",
-    "effectif": "",
-    "effectif_id": "0",
-    "forme_juridique_code": "812",
-    "forme_juridique": null,
-    "remise_percent": "",
-    "remise_supplier_percent": "0",
-    "mode_reglement_supplier_id": null,
-    "cond_reglement_supplier_id": null,
-    "transport_mode_supplier_id": null,
-    "fk_prospectlevel": null,
-    "date_modification": 1632728888,
-    "user_modification": null,
-    "date_creation": "",
-    "user_creation": null,
-    "specimen": null,
-    "client": "2",
-    "prospect": 0,
-    "fournisseur": "0",
-    "code_client": "001855",
-    "code_fournisseur": null,
-    "code_compta": "0001855",
-    "code_compta_client": null,
-    "code_compta_fournisseur": null,
-    "note_private": null,
-    "note_public": null,
-    "stcomm_id": "0",
-    "statut_commercial": "Never contacted",
-    "stcomm_picto": null,
-    "price_level": null,
-    "outstanding_limit": null,
-    "order_min_amount": null,
-    "supplier_order_min_amount": null,
-    "parent": null,
-    "default_lang": null,
-    "ref": "1726",
-    "ref_ext": null,
-    "import_key": "crm",
-    "webservices_url": null,
-    "webservices_key": null,
-    "logo": null,
-    "logo_small": null,
-    "logo_mini": null,
-    "logo_squarred": null,
-    "logo_squarred_small": null,
-    "logo_squarred_mini": null,
-    "accountancy_code_sell": null,
-    "accountancy_code_buy": null,
-    "array_options": {
-      "options_rfltr_model_id": null,
-      "options_sirene_status": null,
-      "options_b4d_spe_name": null,
-      "options_sirene_update_date": "",
-      "options_2iopen_domain": "7",
-      "options_2iopen_structure_type": "12",
-      "options_2iopen_nombre_eleves": null,
-      "options_2iopen_software_opentalent": null,
-      "options_2iopen_software_used": "4",
-      "options_2iopen_num_portable": null,
-      "options_2iopen_structure_type_cmf": null,
-      "options_2iopen_organization_id": "37306",
-      "options_2iopeninfoopentalent": ""
-    },
-    "fk_incoterms": null,
-    "location_incoterms": null,
-    "libelle_incoterms": null,
-    "fk_multicurrency": null,
-    "multicurrency_code": null,
-    "id": "1726",
-    "linkedObjectsIds": null,
-    "canvas": null,
-    "fk_project": null,
-    "contact": null,
-    "contact_id": null,
-    "user": null,
-    "origin": null,
-    "origin_id": null,
-    "statut": null,
-    "country": "France",
-    "country_id": "1",
-    "country_code": "FR",
-    "barcode_type": null,
-    "barcode_type_code": null,
-    "barcode_type_label": null,
-    "barcode_type_coder": null,
-    "mode_reglement_id": "2",
-    "cond_reglement_id": "1",
-    "transport_mode_id": null,
-    "cond_reglement": null,
-    "shipping_method_id": null,
-    "modelpdf": null,
-    "last_main_doc": null,
-    "fk_account": "0",
-    "lastname": null,
-    "firstname": null,
-    "civility_id": null,
-    "date_validation": null
-  }
-]

+ 169 - 32
tests/Service/Education/EducationNotationUtilsTest.php

@@ -12,54 +12,191 @@ use App\Enum\Education\TypeCriteriaEnum;
 use App\Service\Education\EducationNotationUtils;
 use PHPUnit\Framework\TestCase;
 
+class TestableEducationNotationUtils extends EducationNotationUtils {
+    public function calculNotationByAMaxNote(EducationNotation $educationNotation, float $noteMax): ?float {
+        return parent::calculNotationByAMaxNote($educationNotation, $noteMax);
+    }
+}
+
 class EducationNotationUtilsTest extends TestCase
 {
-    private EducationNotationUtils $educationNotationUtils;
-    private EducationNotation $educationNotation;
-
-    public function setUp():void
+    /**
+     * @see EducationNotationUtils::getNotationTransformed()
+     */
+    public function testGetNotationTransformed(): void
     {
-        $this->educationNotationUtils = new EducationNotationUtils();
+        $educationNotationUtils = $this->getMockBuilder(TestableEducationNotationUtils::class)
+            ->setMethodsExcept(['getNotationTransformed'])
+            ->getMock();
+
+        $noteMax = 80;
 
-        $criteriaNotation = new CriteriaNotation();
-        $criteriaNotation->setType(TypeCriteriaEnum::WITH_NOTATION()->getValue());
-        $criteriaNotation->setNoteMax(50);
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $parameters->method('getAverage')->willReturn($noteMax);
 
-        $this->educationNotation = new EducationNotation();
-        $this->educationNotation->setCriteriaNotation($criteriaNotation);
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getParameters')->willReturn($parameters);
+
+        $access = $this->getMockBuilder(Access::class)->getMock();
+        $access->method('getOrganization')->willReturn($organization);
+
+        $educationStudent = $this->getMockBuilder(EducationStudent::class)->getMock();
+        $educationStudent->method('getAccess')->willReturn($access);
+
+        $educationNotation = $this->getMockBuilder(EducationNotation::class)->getMock();
+        $educationNotation->method('getEducationStudent')->willReturn($educationStudent);
+
+        $educationNotationUtils->expects(self::once())->method('calculNotationByAMaxNote')->with($educationNotation, $noteMax);
+
+        $educationNotationUtils->getNotationTransformed($educationNotation);
     }
 
     /**
-     * @see EducationNotationUtils::getNotationTransformed()
+     * @see EducationNotationUtils::getNotationOriginal()
      */
-    public function testGetNotationTransformed()
+    public function testGetNotationOriginal(): void
     {
-        $parameters = new Parameters();
-        $parameters->setAverage(80);
-        $organization = new Organization();
-        $organization->setParameters($parameters);
-        $access = new Access();
-        $access->setOrganization($organization);
-        $educationStudent = new EducationStudent();
-        $educationStudent->setAccess($access);
-
-        $this->educationNotation->setEducationStudent($educationStudent);
-        $this->educationNotation->setNote(100);
-        $this->assertEquals(80, $this->educationNotationUtils->getNotationTransformed($this->educationNotation));
-
-        $this->educationNotation->setNote(50);
-        $this->assertEquals(40, $this->educationNotationUtils->getNotationTransformed($this->educationNotation));
+        $educationNotationUtils = $this->getMockBuilder(TestableEducationNotationUtils::class)
+            ->setMethodsExcept(['getNotationOriginal'])
+            ->getMock();
+
+        $noteMax = 40;
+
+        $criteriaNotation = $this->getMockBuilder(CriteriaNotation::class)->getMock();
+        $criteriaNotation->method('getNoteMax')->willReturn($noteMax);
+
+        $educationNotation = $this->getMockBuilder(EducationNotation::class)->getMock();
+        $educationNotation->method('getCriteriaNotation')->willReturn($criteriaNotation);
+
+        $educationNotationUtils->expects(self::once())->method('calculNotationByAMaxNote')->with($educationNotation, $noteMax);
+
+        $educationNotationUtils->getNotationOriginal($educationNotation);
     }
 
     /**
      * @see EducationNotationUtils::getNotationOriginal()
      */
-    public function testGetNotationOriginal()
+    public function testGetNotationOriginalWithoutCriteria(): void
+    {
+        $educationNotationUtils = $this->getMockBuilder(TestableEducationNotationUtils::class)
+            ->setMethodsExcept(['getNotationOriginal'])
+            ->getMock();
+
+        $educationNotation = $this->getMockBuilder(EducationNotation::class)->getMock();
+        $educationNotation->method('getCriteriaNotation')->willReturn(null);
+
+        $educationNotationUtils->expects(self::never())->method('calculNotationByAMaxNote');
+
+        $this->assertNull($educationNotationUtils->getNotationOriginal($educationNotation));
+    }
+
+    public function testCalculNotationByAMaxNote(): void
+    {
+        $educationNotationUtils = $this->getMockBuilder(TestableEducationNotationUtils::class)
+            ->setMethodsExcept(['calculNotationByAMaxNote'])
+            ->getMock();
+
+        $note1 = 60.0;
+        $note2 = 0.0;
+        $note3 = 100.0;
+        $noteMax = 20;
+
+        $criteriaNotation = $this->getMockBuilder(CriteriaNotation::class)->getMock();
+        $criteriaNotation->method('getType')->willReturn(TypeCriteriaEnum::WITH_NOTATION()->getValue());
+
+        $educationNotation1 = $this->getMockBuilder(EducationNotation::class)->getMock();
+        $educationNotation1->method('getCriteriaNotation')->willReturn($criteriaNotation);
+        $educationNotation1->method('getNote')->willReturn($note1);
+
+        $educationNotation2 = $this->getMockBuilder(EducationNotation::class)->getMock();
+        $educationNotation2->method('getCriteriaNotation')->willReturn($criteriaNotation);
+        $educationNotation2->method('getNote')->willReturn($note2);
+
+        $educationNotation3 = $this->getMockBuilder(EducationNotation::class)->getMock();
+        $educationNotation3->method('getCriteriaNotation')->willReturn($criteriaNotation);
+        $educationNotation3->method('getNote')->willReturn($note3);
+
+        $this->assertEquals(
+            12,
+            $educationNotationUtils->calculNotationByAMaxNote($educationNotation1, $noteMax)
+        );
+
+        $this->assertEquals(
+            0,
+            $educationNotationUtils->calculNotationByAMaxNote($educationNotation2, $noteMax)
+        );
+
+        $this->assertEquals(
+            20,
+            $educationNotationUtils->calculNotationByAMaxNote($educationNotation3, $noteMax)
+        );
+    }
+
+    /**
+     * If $educationNotation has no note, it should return null
+     */
+    public function testCalculNotationByAMaxNoteWithoutNote(): void
     {
-        $this->educationNotation->setNote(100);
-        $this->assertEquals(50, $this->educationNotationUtils->getNotationOriginal($this->educationNotation));
+        $educationNotationUtils = $this->getMockBuilder(TestableEducationNotationUtils::class)
+            ->setMethodsExcept(['calculNotationByAMaxNote'])
+            ->getMock();
+
+        $note = null;
+        $noteMax = 20;
+
+        $educationNotation = $this->getMockBuilder(EducationNotation::class)->getMock();
+        $educationNotation->expects(self::atLeastOnce())->method('getNote')->willReturn($note);
+
+        $this->assertEquals(
+            null,
+            $educationNotationUtils->calculNotationByAMaxNote($educationNotation, $noteMax)
+        );
+    }
+
+    /**
+     * If $educationNotation has no criteriaNotation, it should return null
+     */
+    public function testCalculNotationByAMaxNoteWithoutCriteria(): void
+    {
+        $educationNotationUtils = $this->getMockBuilder(TestableEducationNotationUtils::class)
+            ->setMethodsExcept(['calculNotationByAMaxNote'])
+            ->getMock();
+
+        $note = 50.0;
+        $noteMax = 20;
+
+        $educationNotation = $this->getMockBuilder(EducationNotation::class)->getMock();
+        $educationNotation->expects(self::atLeastOnce())->method('getNote')->willReturn($note);
+        $educationNotation->expects(self::atLeastOnce())->method('getCriteriaNotation')->willReturn(null);
+
+        $this->assertEquals(
+            null,
+            $educationNotationUtils->calculNotationByAMaxNote($educationNotation, $noteMax)
+        );
+    }
+
+    /**
+     * If $criteriaNotation has WITHOUT_NOTATION type, this should return null
+     */
+    public function testCalculNotationByAMaxNoteWithoutNotation(): void
+    {
+        $educationNotationUtils = $this->getMockBuilder(TestableEducationNotationUtils::class)
+            ->setMethodsExcept(['calculNotationByAMaxNote'])
+            ->getMock();
+
+        $note = 60.0;
+        $noteMax = 20;
+
+        $criteriaNotation = $this->getMockBuilder(CriteriaNotation::class)->getMock();
+        $criteriaNotation->expects(self::once())->method('getType')->willReturn(TypeCriteriaEnum::WITHOUT_NOTATION()->getValue());
+
+        $educationNotation = $this->getMockBuilder(EducationNotation::class)->getMock();
+        $educationNotation->expects(self::atLeastOnce())->method('getNote')->willReturn($note);
+        $educationNotation->expects(self::atLeastOnce())->method('getCriteriaNotation')->willReturn($criteriaNotation);
 
-        $this->educationNotation->setNote(50);
-        $this->assertEquals(25, $this->educationNotationUtils->getNotationOriginal($this->educationNotation));
+        $this->assertEquals(
+            null,
+            $educationNotationUtils->calculNotationByAMaxNote($educationNotation, $noteMax)
+        );
     }
 }

+ 35 - 16
tests/Service/Export/Encoder/PdfEncoderTest.php

@@ -2,38 +2,57 @@
 
 use App\Service\Export\Encoder\PdfEncoder;
 use Knp\Snappy\Pdf;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 
 class PdfEncoderTest extends TestCase
 {
-    public function testSupport() {
-        $mocker = $this->getMockBuilder(Pdf::class);
-        $knpSnappy = $mocker->getMock();
-        $encoder = new PdfEncoder($knpSnappy);
+    private MockObject | Pdf $knpSnappy;
+
+    public function setUp(): void
+    {
+        $this->knpSnappy = $this->getMockBuilder(Pdf::class)->getMock();
+    }
+
+    public function testSupport(): void
+    {
+        $encoder = $this->getMockBuilder(PdfEncoder::class)
+            ->setConstructorArgs([$this->knpSnappy])
+            ->setMethodsExcept(['support'])
+            ->getMock();
 
         $this->assertTrue($encoder->support('pdf'));
         $this->assertFalse($encoder->support('txt'));
     }
 
-    public function testGetDefaultOptions() {
-        $mocker = $this->getMockBuilder(Pdf::class);
-        $knpSnappy = $mocker->getMock();
-        $encoder = new PdfEncoder($knpSnappy);
+    public function testGetDefaultOptions(): void
+    {
+        $encoder = $this->getMockBuilder(PdfEncoder::class)
+            ->setConstructorArgs([$this->knpSnappy])
+            ->setMethodsExcept(['getDefaultOptions'])
+            ->getMock();
 
         $this->assertIsArray($encoder->getDefaultOptions());
     }
 
-    public function testEncode() {
-        $mocker = $this->getMockBuilder(Pdf::class);
-        $knpSnappy = $mocker->getMock();
-        $knpSnappy
+    public function testEncode(): void
+    {
+        $encoder = $this->getMockBuilder(PdfEncoder::class)
+            ->setConstructorArgs([$this->knpSnappy])
+            ->setMethodsExcept(['encode'])
+            ->getMock();
+
+        $encoder->method('getDefaultOptions')->willReturn(['defaultOption' => 1]);
+
+        $this->knpSnappy
             ->expects(self::once())
             ->method('getOutputFromHtml')
-            ->with('<div>content</div>')
+            ->with('<div>content</div>', ['defaultOption' => 1, 'additionalOption' => 2])
             ->willReturn('%%encoded%%');
 
-        $encoder = new PdfEncoder($knpSnappy);
-
-        $this->assertEquals('%%encoded%%', $encoder->encode('<div>content</div>'));
+        $this->assertEquals(
+            '%%encoded%%',
+            $encoder->encode('<div>content</div>', ['additionalOption' => 2])
+        );
     }
 }

+ 134 - 59
tests/Service/Export/LicenceCmfExporterTest.php

@@ -1,4 +1,4 @@
-<?php
+<?php /** @noinspection PhpUnhandledExceptionInspection */
 
 use App\ApiResources\Export\ExportRequest;
 use App\ApiResources\Export\LicenceCmf\LicenceCmfOrganizationER;
@@ -13,37 +13,43 @@ use App\Repository\Access\AccessRepository;
 use App\Repository\Organization\OrganizationRepository;
 use App\Service\Export\Encoder\PdfEncoder;
 use App\Service\Export\LicenceCmfExporter;
+use App\Service\Export\Model\ExportModelInterface;
+use App\Service\Export\Model\LicenceCmf;
+use App\Service\Export\Model\LicenceCmfCollection;
 use App\Service\ServiceIterator\EncoderIterator;
 use App\Service\Storage\TemporaryFileStorage;
 use App\Service\Storage\UploadStorage;
+use App\Tests\TestToolsTrait;
 use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\EntityManagerInterface;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 use Twig\Environment;
 
 class LicenceCmfExporterTest extends TestCase
 {
-    private mixed $exportRequest;
-    private mixed $accessRepo;
-    private mixed $twig;
-    private mixed $encoderIterator;
-    private mixed $em;
-    private mixed $storage;
-    private mixed $organizationRepo;
-    private mixed $uploadStorage;
-    private mixed $access;
-    private mixed $organization;
-    private mixed $cmf;
-    private mixed $networkOrgs;
-    private mixed $collection;
-    private mixed $parent;
-    private mixed $logo;
-    private mixed $presidentAccess;
-    private mixed $president;
-    private mixed $cmfParameters;
-    private mixed $qrCode;
-    private LicenceCmfExporter $exporter;
-    private mixed $encoder;
+    use TestToolsTrait;
+
+    private MockObject | LicenceCmfOrganizationER $exportRequest;
+    private MockObject | AccessRepository $accessRepo;
+    private MockObject | Environment $twig;
+    private MockObject | EncoderIterator $encoderIterator;
+    private MockObject | EntityManagerInterface $em;
+    private MockObject | TemporaryFileStorage $storage;
+    private MockObject | OrganizationRepository $organizationRepo;
+    private MockObject | UploadStorage $uploadStorage;
+    private MockObject | Access $access;
+    private MockObject | Organization $organization;
+    private MockObject | Organization $cmf;
+    private MockObject | NetworkOrganization $networkOrgs;
+    private MockObject | Collection $collection;
+    private MockObject | Organization $parent;
+    private MockObject | File $logo;
+    private MockObject | Access $presidentAccess;
+    private MockObject | Person $president;
+    private MockObject | Parameters $cmfParameters;
+    private MockObject | File $qrCode;
+    private MockObject | PdfEncoder $encoder;
 
     public function setUp(): void {
         $this->exportRequest = $this->getMockBuilder(LicenceCmfOrganizationER::class)->getMock();
@@ -66,20 +72,33 @@ class LicenceCmfExporterTest extends TestCase
         $this->president = $this->getMockBuilder(Person::class)->getMock();
         $this->cmfParameters = $this->getMockBuilder(Parameters::class)->getMock();
         $this->qrCode = $this->getMockBuilder(File::class)->getMock();
+    }
 
-        $this->exporter = new LicenceCmfExporter($this->organizationRepo, $this->uploadStorage);
-        $this->exporter->setAccessRepository($this->accessRepo);
-        $this->exporter->setTwig($this->twig);
-        $this->exporter->setEncoderIterator($this->encoderIterator);
-        $this->exporter->setEntityManager($this->em);
-        $this->exporter->setStorage($this->storage);
+    private function makeExporterMock(string $methodUnderTest): LicenceCmfExporter | MockObject
+    {
+        $exporter = $this->getMockBuilder(LicenceCmfExporter::class)
+            ->setConstructorArgs([$this->organizationRepo, $this->uploadStorage])
+            ->setMethodsExcept(['setAccessRepository', 'setTwig', 'setEncoderIterator',
+                'setEntityManager', 'setEntityManager', 'setStorage', $methodUnderTest])
+            ->getMock();
+
+        $exporter->setAccessRepository($this->accessRepo);
+        $exporter->setTwig($this->twig);
+        $exporter->setEncoderIterator($this->encoderIterator);
+        $exporter->setEntityManager($this->em);
+        $exporter->setStorage($this->storage);
+
+        return $exporter;
     }
 
-    public function testSupport() {
+    public function testSupport(): void
+    {
+        $exporter = $this->makeExporterMock('support');
+
         $unsupportedExportRequest = $this->getMockBuilder(ExportRequest::class)->disableOriginalConstructor()->getMock();
 
-        $this->assertTrue($this->exporter->support($this->exportRequest));
-        $this->assertFalse($this->exporter->support($unsupportedExportRequest));
+        $this->assertTrue($exporter->support($this->exportRequest));
+        $this->assertFalse($exporter->support($unsupportedExportRequest));
     }
 
     private function prepareModelBuilding() {
@@ -115,14 +134,14 @@ class LicenceCmfExporterTest extends TestCase
         $this->organizationRepo->expects(self::once())->method('find')->with(12097)->willReturn($this->cmf);
     }
 
-    public function testBuildModel() {
+    public function testBuildModel(): void
+    {
+        $exporter = $this->makeExporterMock('buildModel');
+
         $this->prepareModelBuilding();
 
-        $reflection = new ReflectionClass('App\Service\Export\LicenceCmfExporter');
-        $this->buildModelMethod = $reflection->getMethod('buildModel');
-        $this->buildModelMethod->setAccessible(true);
+        $modelCollection = $this->invokeMethod($exporter, 'buildModel', [$this->exportRequest]);
 
-        $modelCollection = $this->buildModelMethod->invokeArgs($this->exporter, [$this->exportRequest]);
         $licence = $modelCollection->getLicences()[0];
 
         $this->assertEquals('my_network', $licence->getFederationName());
@@ -133,35 +152,91 @@ class LicenceCmfExporterTest extends TestCase
         $this->assertEquals('http:://foo.bar/1', $licence->getLogoUri());
     }
 
-    public function testExport() {
-        $this->prepareModelBuilding();
+    /**
+     * If the organization cannot be determined from the exportRequest author, an error should be thrown
+     */
+    public function testBuildModelWithoutOrganization(): void
+    {
+        $exporter = $this->makeExporterMock('buildModel');
 
-        $this->twig
-            ->expects(self::once())
-            ->method('render')
-            ->with('@templates/export/licence_cmf.html.twig')
-            ->willReturn('<div>rendered html</div>');
+        $this->exportRequest->method('getRequesterId')->willReturn(1);
+        $this->accessRepo->method('find')->with(1)->willReturn(null);
 
-        $this->encoderIterator
-            ->expects(self::once())
-            ->method('getEncoderFor')
-            ->with('pdf')
-            ->willReturn($this->encoder);
+        $this->expectException(RuntimeException::class);
 
-        $this->encoder
-            ->expects(self::once())
-            ->method('encode')
-            ->with('<div>rendered html</div>')
-            ->willReturn('%%encoded%%');
+        $this->invokeMethod($exporter, 'buildModel', [$this->exportRequest]);
+    }
 
-        $this->storage
-            ->expects(self::once())
-            ->method('write')
-            ->willReturn('/temp/abcd/licence_cmf_2020.pdf');
+    public function testGetFileBasename(): void
+    {
+        $exporter = $this->makeExporterMock('getFileBasename');
+
+        $licence = $this->getMockBuilder(LicenceCmf::class)->getMock();
+        $licence->method('getYear')->willReturn(2020);
+
+        $model = $this->getMockBuilder(LicenceCmfCollection::class)->getMock();
+        $model->method('getLicences')->willReturn([$licence]);
+
+        $result = $this->invokeMethod($exporter, 'getFileBasename', [$model]);
 
-        $file = $this->exporter->export($this->exportRequest);
+        $this->assertEquals(
+            'licence_cmf_2020.pdf',
+            $result
+        );
+    }
+
+    public function testGetFileType(): void
+    {
+        $exporter = $this->makeExporterMock('getFileType');
 
-        $this->assertMatchesRegularExpression('/licence_cmf_\d{4}.pdf/', $file->getName());
+        $this->assertEquals(
+            'LICENCE_CMF',
+            $this->invokeMethod($exporter, 'getFileType')
+        );
     }
 
+    /**
+     * Given year is before the start year, first color is used
+     */
+    public function testGetLicenceColorPastYear(): void
+    {
+        $exporter = $this->makeExporterMock('getLicenceColor');
+
+        $year = LicenceCmfExporter::LICENCE_CMF_COLOR_START_YEAR - 10;
+
+        $this->assertEquals(
+            LicenceCmfExporter::LICENCE_CMF_COLOR[0],
+            $this->invokeMethod($exporter, 'getLicenceColor', [$year])
+        );
+    }
+
+    /**
+     * Given year is within the 5 first years
+     */
+    public function testGetLicenceColorFirstYears(): void
+    {
+        $exporter = $this->makeExporterMock('getLicenceColor');
+
+        $year = LicenceCmfExporter::LICENCE_CMF_COLOR_START_YEAR + 3;
+
+        $this->assertEquals(
+            LicenceCmfExporter::LICENCE_CMF_COLOR[3],
+            $this->invokeMethod($exporter, 'getLicenceColor', [$year])
+        );
+    }
+
+    /**
+     * Given year is beyond the 5 first years
+     */
+    public function testGetLicenceColorNExtYears(): void
+    {
+        $exporter = $this->makeExporterMock('getLicenceColor');
+
+        $year = LicenceCmfExporter::LICENCE_CMF_COLOR_START_YEAR + 8;
+
+        $this->assertEquals(
+            LicenceCmfExporter::LICENCE_CMF_COLOR[3],
+            $this->invokeMethod($exporter, 'getLicenceColor', [$year])
+        );
+    }
 }

+ 46 - 38
tests/Service/MailHubTest.php

@@ -1,5 +1,9 @@
-<?php
+<?php /** @noinspection PhpUnhandledExceptionInspection */
 
+use App\Entity\Access\Access;
+use App\Entity\Core\ContactPoint;
+use App\Entity\Person\Person;
+use App\Service\Access\Utils as AccessUtils;
 use App\Service\Core\ContactPointUtils;
 use App\Service\MailHub;
 use PHPUnit\Framework\TestCase;
@@ -11,88 +15,92 @@ class MailHubTest extends TestCase
     private MailerInterface $mailer;
     private string $opentalentNoReplyEmailAddress;
     private ContactPointUtils $contactPointUtils;
-    private \App\Service\Access\Utils $accessUtils;
+    private AccessUtils $accessUtils;
 
     public function setUp(): void {
         $this->mailer = $this->getMockBuilder(MailerInterface::class)->disableOriginalConstructor()->getMock();
         $this->opentalentNoReplyEmailAddress = 'noreply@opentalent.fr';
         $this->contactPointUtils = $this->getMockBuilder(ContactPointUtils::class)->disableOriginalConstructor()->getMock();
-        $this->accessUtils = $this->getMockBuilder(\App\Service\Access\Utils::class)->disableOriginalConstructor()->getMock();
+        $this->accessUtils = $this->getMockBuilder(AccessUtils::class)->disableOriginalConstructor()->getMock();
     }
 
     public function testSendAutomaticEmailTo(): void
     {
-        $contactPoint = $this->getMockBuilder(\App\Entity\Core\ContactPoint::class)->disableOriginalConstructor()->getMock();
+        $mailerHub = $this->getMockBuilder(MailHub::class)
+            ->setConstructorArgs([$this->mailer, $this->opentalentNoReplyEmailAddress, $this->contactPointUtils, $this->accessUtils])
+            ->setMethodsExcept(['sendAutomaticEmailTo'])
+            ->getMock();
+
+        $contactPoint = $this->getMockBuilder(ContactPoint::class)->disableOriginalConstructor()->getMock();
         $contactPoint->method('getEmail')->willReturn('mail@domain.net');
 
-        $person = $this->getMockBuilder(\App\Entity\Person\Person::class)->disableOriginalConstructor()->getMock();
+        $person = $this->getMockBuilder(Person::class)->disableOriginalConstructor()->getMock();
         $person->method('getFullName')->willReturn('Don Diego de la Vega');
         $person->method('getUsername')->willReturn('zorro2000');
 
-        $access = $this->getMockBuilder(\App\Entity\Access\Access::class)->disableOriginalConstructor()->getMock();
+        $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
         $access->method('getPerson')->willReturn($person);
 
         $this->contactPointUtils->expects(self::once())->method('getPersonContactPointPrincipal')->willReturn($contactPoint);
 
-        $this->mailer->expects(self::once())
+        $this->mailer
+            ->expects(self::once())
             ->method('send')
             ->with(self::isInstanceOf(TemplatedEmail::class));
 
-        $mailerHub = new MailHub(
-            $this->mailer,
-            $this->opentalentNoReplyEmailAddress,
-            $this->contactPointUtils,
-            $this->accessUtils
-        );
-
         $mailerHub->sendAutomaticEmailTo($access, 'subject', 'a_template', []);
     }
 
     public function testSendAutomaticEmailToButNoAddress(): void
     {
-        $access = $this->getMockBuilder(\App\Entity\Access\Access::class)->disableOriginalConstructor()->getMock();
+        $mailerHub = $this->getMockBuilder(MailHub::class)
+            ->setConstructorArgs([$this->mailer, $this->opentalentNoReplyEmailAddress, $this->contactPointUtils, $this->accessUtils])
+            ->setMethodsExcept(['sendAutomaticEmailTo'])
+            ->getMock();
 
-        $this->contactPointUtils->expects(self::once())->method('getPersonContactPointPrincipal')->willReturn(null);
+        $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
 
-        $mailerHub = new MailHub(
-            $this->mailer,
-            $this->opentalentNoReplyEmailAddress,
-            $this->contactPointUtils,
-            $this->accessUtils
-        );
+        $this->contactPointUtils->expects(self::once())->method('getPersonContactPointPrincipal')->willReturn(null);
 
         $this->expectException(\RuntimeException::class);
 
         $mailerHub->sendAutomaticEmailTo($access, 'subject', 'a_template', []);
     }
 
-    public function testSendAutomaticEmailToAdmin() {
+    public function testSendAutomaticEmailToAdmin(): void
+    {
+        $mailerHub = $this->getMockBuilder(MailHub::class)
+            ->setConstructorArgs([$this->mailer, $this->opentalentNoReplyEmailAddress, $this->contactPointUtils, $this->accessUtils])
+            ->setMethodsExcept(['sendAutomaticEmailToAdmin'])
+            ->getMock();
 
         $organization = $this->getMockBuilder(\App\Entity\Organization\Organization::class)->disableOriginalConstructor()->getMock();
-        $admin = $this->getMockBuilder(\App\Entity\Access\Access::class)->disableOriginalConstructor()->getMock();
+        $admin = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
 
         $this->accessUtils->expects(self::once())->method('findAdminFor')->with($organization)->willReturn($admin);
 
-        $mailerHub = $this->getMockBuilder(MailHub::class)
-            ->onlyMethods(['sendAutomaticEmailTo'])
-            ->setConstructorArgs([$this->mailer, $this->opentalentNoReplyEmailAddress, $this->contactPointUtils, $this->accessUtils])
-            ->getMock();
-        $mailerHub->expects(self::once())->method('sendAutomaticEmailTo')->with($admin, 'subject', 'template', []);
+        $mailerHub
+            ->expects(self::once())
+            ->method('sendAutomaticEmailTo')
+            ->with($admin, 'subject', 'template', []);
 
         $mailerHub->sendAutomaticEmailToAdmin($organization, 'subject', 'template', []);
     }
 
-    public function testSendAutomaticEmailToAdminButNoAdmin() {
+    public function testSendAutomaticEmailToAdminButNoAdmin(): void
+    {
+        $mailerHub = $this->getMockBuilder(MailHub::class)
+            ->setConstructorArgs([$this->mailer, $this->opentalentNoReplyEmailAddress, $this->contactPointUtils, $this->accessUtils])
+            ->setMethodsExcept(['sendAutomaticEmailToAdmin'])
+            ->getMock();
 
         $organization = $this->getMockBuilder(\App\Entity\Organization\Organization::class)->disableOriginalConstructor()->getMock();
-        $this->accessUtils->expects(self::once())->method('findAdminFor')->with($organization)->willReturn(null);
-
-        $mailerHub = new MailHub(
-            $this->mailer,
-            $this->opentalentNoReplyEmailAddress,
-            $this->contactPointUtils,
-            $this->accessUtils
-        );
+
+        $this->accessUtils
+            ->expects(self::once())
+            ->method('findAdminFor')
+            ->with($organization)
+            ->willReturn(null);
 
         $this->expectException(\RuntimeException::class);
 

+ 76 - 56
tests/Service/Mobyt/MobytServiceTest.php

@@ -1,4 +1,4 @@
-<?php
+<?php /** @noinspection PhpUnhandledExceptionInspection */
 
 namespace App\Tests\Service\Mobyt;
 
@@ -8,101 +8,121 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
 use Symfony\Contracts\HttpClient\ResponseInterface;
 
+class TestableMobytService extends MobytService {
+    public function connect(string $login, string $password): void { parent::connect($login, $password); }
+    public function getUserId(): string { return parent::getUserId(); }
+    public function getSessionKey(): string { return parent::getSessionKey(); }
+}
+
 class MobytServiceTest extends TestCase
 {
     private HttpClientInterface $client;
-    private MobytService $mobytService;
 
     public function setUp():void
     {
         $this->client = $this->getMockBuilder(HttpClientInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
-
-        $this->mobytService = new MobytService($this->client);
-    }
-
-    private function getContentFromFixture(string $filename): string {
-        $filepath = dirname(__FILE__) . '/fixtures/' . $filename;
-        return file_get_contents($filepath);
     }
 
     /**
      * @see MobytService::getUserStatus()
      */
-    public function testGetUserStatus(): void {
+    public function testConnect(): void {
 
-        // Mock the response that will be returned by the connection request
-        $connectResponse = $this->getMockBuilder(ResponseInterface::class)
-            ->disableOriginalConstructor()
+        $mobytService = $this->getMockBuilder(TestableMobytService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['connect', 'getUserId', 'getSessionKey'])
             ->getMock();
-        $connectResponse->method('getContent')->willReturn('userId;sessionKey');
 
-        // Mock the response that will be returned by the user_status request
-        $responseContent = $this->getContentFromFixture('user_status.json');
-        $response = $this->getMockBuilder(ResponseInterface::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $response->method('getContent')->willReturn($responseContent);
+        $login = 'foo';
+        $password = 'bar';
 
-        $this->client
-            ->method('request')
-            ->withConsecutive(
-                ["GET", "login?username=user&password=pwd"],
-                ["GET", "status?getMoney=true&typeAliases=true", ['headers' => [ 'user_key' => 'userId', 'Session_key' => 'sessionKey' ]]]
+        $mobytService
+            ->expects(self::once())
+            ->method('getContent')
+            ->with(
+                'login',
+                ['username' => $login, 'password' => $password]
             )
-            ->willReturnOnConsecutiveCalls(
-                $connectResponse,
-                $response
-            );
+            ->willReturn('123;456');
+
+        $mobytService->connect($login, $password);
 
-        $data = $this->mobytService->getUserStatus(1, 'user', 'pwd');
+        $this->assertEquals(
+            '123',
+            $mobytService->getUserId()
+        );
 
         $this->assertEquals(
-            $data['money'],
-            33.0
+            '456',
+            $mobytService->getSessionKey()
         );
     }
 
     /**
-     * @see MobytService::hasCredentialsCorrect()
+     * @see MobytService::getUserStatus()
      */
-    public function testHasCredentialsCorrect(): void {
+    public function testGetUserStatus(): void {
 
-        // Mock the response that will be returned by the connection request
-        $connectResponse = $this->getMockBuilder(ResponseInterface::class)
-            ->disableOriginalConstructor()
+        $mobytService = $this->getMockBuilder(TestableMobytService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['getUserStatus'])
             ->getMock();
-        $connectResponse->method('getContent')->willReturn('userId;sessionKey');
 
-        $this->client
-            ->method('request')
-            ->with("GET", "login?username=user&password=pwd")
-            ->willReturnOnConsecutiveCalls(
-                $connectResponse
+        $login = 'foo';
+        $password = 'bar';
+
+        $mobytService->expects(self::once())->method('connect')->with($login, $password);
+
+        $mobytService->method('getUserId')->willReturn('123');
+        $mobytService->method('getSessionKey')->willReturn('456');
+
+        $mobytService
+            ->expects(self::once())
+            ->method('getJsonContent')
+            ->with(
+                'status',
+                ['getMoney' => 'true', 'typeAliases' => 'true'],
+                [
+                    'headers' => [ 'user_key' => '123', 'Session_key' => '456' ]
+                ]
             );
 
-        $this->assertTrue($this->mobytService->hasCredentialsCorrect('user', 'pwd'));
+        $mobytService->getUserStatus($login, $password);
     }
 
     /**
      * @see MobytService::hasCredentialsCorrect()
      */
-    public function testHasCredentialsUnCorrect(): void {
+    public function testHasCredentialsCorrect(): void {
+        $mobytService = $this->getMockBuilder(TestableMobytService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['hasCredentialsCorrect'])
+            ->getMock();
 
-        // Mock the response that will be returned by the connection request
-        $connectResponse = $this->getMockBuilder(ResponseInterface::class)
-            ->disableOriginalConstructor()
+        $login = 'foo';
+        $password = 'bar';
+
+        $mobytService->expects(self::once())->method('connect')->with($login, $password);
+
+        $this->assertTrue($mobytService->hasCredentialsCorrect($login, $password));
+    }
+
+    /**
+     * @see MobytService::hasCredentialsCorrect()
+     */
+    public function testHasCredentialsNotCorrect(): void {
+        $mobytService = $this->getMockBuilder(TestableMobytService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['hasCredentialsCorrect'])
             ->getMock();
-        $connectResponse->method('getContent')->willThrowException(new NotFoundHttpException());
 
-        $this->client
-            ->method('request')
-            ->with("GET", "login?username=user&password=pwd")
-            ->willReturnOnConsecutiveCalls(
-                $connectResponse
-            );
+        $login = 'foo';
+        $password = 'bar';
+
+        $mobytService->expects(self::once())->method('connect')->with($login, $password)->willThrowException(new NotFoundHttpException());
 
-        $this->assertFalse($this->mobytService->hasCredentialsCorrect('user', 'pwd'));
+        $this->assertFalse($mobytService->hasCredentialsCorrect($login, $password));
     }
 }

+ 26 - 20
tests/Service/Mobyt/MobytUserStatusCreatorTest.php

@@ -13,7 +13,6 @@ class MobytUserStatusCreatorTest extends TestCase
 {
     private MobytService $mobytService;
     private OrganizationRepository $organizationRepository;
-    private MobytUserStatusCreator $mobytUserStatusCreator;
 
     public function setUp(): void {
         $this->mobytService = $this->getMockBuilder(MobytService::class)
@@ -23,41 +22,48 @@ class MobytUserStatusCreatorTest extends TestCase
         $this->organizationRepository = $this->getMockBuilder(OrganizationRepository::class)
             ->disableOriginalConstructor()
             ->getMock();
-
-        $this->mobytUserStatusCreator = new MobytUserStatusCreator(
-            $this->mobytService,
-            $this->organizationRepository
-        );
     }
 
-    private function getJsonContentFromFixture(string $filename): array {
-        $filepath = dirname(__FILE__) . '/fixtures/' . $filename;
-        return json_decode(file_get_contents($filepath), true);
-    }
+    public function testGetUserStatus(): void
+    {
+        $mobytUserStatusCreator = $this->getMockBuilder(MobytUserStatusCreator::class)
+            ->setConstructorArgs([$this->mobytService, $this->organizationRepository])
+            ->setMethodsExcept(['getUserStatus'])
+            ->getMock();
 
-    public function testGetUserStatus() {
-        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
-        $parameters->expects($this->once())->method('getUsernameSMS')->willReturn('user');
-        $parameters->expects($this->once())->method('getPasswordSMS')->willReturn('pwd');
+        $organizationId = 123;
+        $mobytLogin = 'foo';
+        $mobytPassword = 'bar';
 
         $organization = $this->getMockBuilder(Organization::class)->getMock();
-        $organization->expects($this->once())->method('getParameters')->willReturn($parameters);
-
         $this->organizationRepository
             ->expects($this->once())
             ->method('find')
-            ->with(1)
+            ->with($organizationId)
             ->willReturn($organization);
 
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $organization->expects($this->once())->method('getParameters')->willReturn($parameters);
+
+        $parameters->expects($this->once())->method('getUsernameSMS')->willReturn($mobytLogin);
+        $parameters->expects($this->once())->method('getPasswordSMS')->willReturn($mobytPassword);
+
         $this->mobytService
             ->expects($this->once())
             ->method('getUserStatus')
-            ->with(1, 'user', 'pwd')
+            ->with($mobytLogin, $mobytPassword)
             ->willReturn(
-                $this->getJsonContentFromFixture('user_status.json')
+                [
+                    'money' => 33.0,
+                    'sms' => [
+                        ['type' => 'N', 'quantity' => '300'],
+                        ['type' => 'EE', 'quantity' => '301'],  // this type of sms should be ignored by the method
+                    ],
+                    'email' => null
+                ]
             );
 
-        $mobytUserStatus = $this->mobytUserStatusCreator->getUserStatus(1);
+        $mobytUserStatus = $mobytUserStatusCreator->getUserStatus($organizationId);
 
         $this->assertEquals(
             $mobytUserStatus->getMoney(),

+ 0 - 14
tests/Service/Mobyt/fixtures/user_status.json

@@ -1,14 +0,0 @@
-{
-  "money": 33.0,
-  "sms": [
-    {
-      "type": "N",
-      "quantity": 300
-    },
-    {
-      "type": "EE",
-      "quantity": 300
-    }
-  ],
-  "email": null
-}

+ 41 - 36
tests/Service/Network/TreeTest.php

@@ -8,17 +8,14 @@ use App\Service\Network\Tree;
 
 class TreeTest extends TestCase
 {
-    private Tree $tree;
-    private NetworkOrganizationRepository $networkOrganizationRepositoryMock;
+    private NetworkOrganizationRepository $networkOrganizationRepository;
 
     public function setUp():void
     {
-        $this->networkOrganizationRepositoryMock =
-            $this
+        $this->networkOrganizationRepository = $this
                 ->getMockBuilder(NetworkOrganizationRepository::class)
                 ->disableOriginalConstructor()
                 ->getMock();
-        $this->tree = new Tree($this->networkOrganizationRepositoryMock);
     }
 
     /**
@@ -26,25 +23,28 @@ class TreeTest extends TestCase
      */
     public function testFindAllParentsAndSortByType():void
     {
-        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
-        $organizationMock
-            ->method('getId')
-            ->willReturn(1);
-        $this->networkOrganizationRepositoryMock
-            ->expects($this->once())
+        $tree = $this->getMockBuilder(Tree::class)
+            ->setConstructorArgs([$this->networkOrganizationRepository])
+            ->setMethodsExcept(['findAllParentsAndSortByType'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $parent1 = $this->getMockBuilder(Organization::class)->getMock();
+        $parent2 = $this->getMockBuilder(Organization::class)->getMock();
+        $parents = [$parent1, $parent2];
+
+        $this->networkOrganizationRepository
+            ->expects(self::once())
             ->method('findAllParents')
-            ->with($organizationMock)
-            ->willReturn([$organizationMock]);
+            ->with($organization)
+            ->willReturn($parents);
 
-        $treeMock = $this
-            ->getMockBuilder(Tree::class)
-            ->setConstructorArgs([$this->networkOrganizationRepositoryMock])
-            ->onlyMethods(['sortByType'])
-            ->getMock();
-        $treeMock
-            ->expects($this->once())
-            ->method('sortByType');
-        $treeMock->findAllParentsAndSortByType($organizationMock);
+        $tree
+            ->expects(self::once())
+            ->method('sortByType')
+            ->with($parents);
+
+        $tree->findAllParentsAndSortByType($organization);
     }
 
     /**
@@ -52,25 +52,30 @@ class TreeTest extends TestCase
      */
     public function testSortByType():void
     {
-        $organizationMock1 = $this->getMockBuilder(Organization::class)->getMock();
-        $organizationMock1->method('getId')->willReturn(2);
-        $organizationMock1->method('getPrincipalType')->willReturn('REGIONAL_FEDERATION');
+        $tree = $this->getMockBuilder(Tree::class)
+            ->setConstructorArgs([$this->networkOrganizationRepository])
+            ->setMethodsExcept(['sortByType'])
+            ->getMock();
+
+        $organization1 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization1->method('getId')->willReturn(2);
+        $organization1->method('getPrincipalType')->willReturn('REGIONAL_FEDERATION');
 
-        $organizationMock2 = $this->getMockBuilder(Organization::class)->getMock();
-        $organizationMock2->method('getId')->willReturn(3);
-        $organizationMock2->method('getPrincipalType')->willReturn('NATIONAL_FEDERATION');
+        $organization2 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization2->method('getId')->willReturn(3);
+        $organization2->method('getPrincipalType')->willReturn('NATIONAL_FEDERATION');
 
-        $organizationMock3 = $this->getMockBuilder(Organization::class)->getMock();
-        $organizationMock3->method('getId')->willReturn(4);
-        $organizationMock3->method('getPrincipalType')->willReturn('DEPARTEMENTAL_FEDERATION');
+        $organization3 = $this->getMockBuilder(Organization::class)->getMock();
+        $organization3->method('getId')->willReturn(4);
+        $organization3->method('getPrincipalType')->willReturn('DEPARTEMENTAL_FEDERATION');
 
         $organizations = [
-            $organizationMock2,
-            $organizationMock1,
-            $organizationMock3
+            $organization2,
+            $organization1,
+            $organization3
         ];
 
-        $result = $this->tree->sortByType($organizations);
+        $result = $tree->sortByType($organizations);
 
         $this->assertIsArray($result);
         $this->assertContainsOnlyInstancesOf(Organization::class, $result);
@@ -78,4 +83,4 @@ class TreeTest extends TestCase
         $this->assertEquals(2, $result[1]->getId());
         $this->assertEquals(3, $result[2]->getId());
     }
-}
+}

+ 203 - 54
tests/Service/Network/UtilsTest.php

@@ -1,47 +1,37 @@
-<?php
+<?php /** @noinspection PhpUnhandledExceptionInspection */
+
 namespace App\Tests\Service\Network;
 
 use App\Entity\Network\Network;
 use App\Entity\Network\NetworkOrganization;
 use App\Entity\Organization\Organization;
 use App\Enum\Network\NetworkEnum;
+use DateTime;
+use Doctrine\Common\Collections\ArrayCollection;
 use PHPUnit\Framework\TestCase;
-use App\Service\Network\Utils;
+use App\Service\Network\Utils as NetworkUtils;
 
 class UtilsTest extends TestCase
 {
-    private Utils $utils;
-    private Organization $organizationCmf;
-    private Organization $organizationFfec;
-
-    public function setUp():void
-    {
-        $networkCmf = new Network();
-        $networkCmf->setId(3);
-        $networkCmf->setName('CMF');
-        $networkOrganization = new NetworkOrganization();
-        $networkOrganization->setNetwork($networkCmf);
-        $networkOrganization->setStartDate(new \DateTime('2000-09-11'));
-        $this->organizationCmf = new Organization();
-        $this->organizationCmf->addNetworkOrganization($networkOrganization);
-
-        $networkFfec = new Network();
-        $networkFfec->setId(4);
-        $networkFfec->setName('FFEC');
-        $networkOrganization = new NetworkOrganization();
-        $networkOrganization->setNetwork($networkFfec);
-        $this->organizationFfec = new Organization();
-        $this->organizationFfec->addNetworkOrganization($networkOrganization);
-
-        $this->utils = new Utils();
-    }
-
     /**
      * @see Utils::isCMF()
      */
     public function testIsCmf():void
     {
-        $result = $this->utils->isCmf($this->organizationCmf);
+        $networkUtils = $this
+            ->getMockBuilder(NetworkUtils::class)
+            ->setMethodsExcept(['isCMF'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+
+        $networkUtils
+            ->expects(self::once())
+            ->method('doesOrganizationBelongToTheNetwork')
+            ->with($organization, NetworkEnum::CMF())
+            ->willReturn(true);
+
+        $result = $networkUtils->isCmf($organization);
         $this->assertTrue($result);
     }
 
@@ -50,53 +40,212 @@ class UtilsTest extends TestCase
      */
     public function testIsNotCmf():void
     {
-        $result = $this->utils->isCmf($this->organizationFfec);
+        $networkUtils = $this
+            ->getMockBuilder(NetworkUtils::class)
+            ->setMethodsExcept(['isCMF'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $networkUtils
+            ->expects(self::once())
+            ->method('doesOrganizationBelongToTheNetwork')
+            ->with($organization, NetworkEnum::CMF())
+            ->willReturn(false);
+
+        $result = $networkUtils->isCmf($organization);
         $this->assertFalse($result);
     }
 
     /**
-     * @see Utils::isCMFAndActiveNow()
+     * @see Utils::isCMF()
      */
     public function testIsCmfAndActiveNow():void
     {
-        $result = $this->utils->isCMFAndActiveNow($this->organizationCmf);
-        $this->assertTrue($result);
+        $networkUtils = $this
+            ->getMockBuilder(NetworkUtils::class)
+            ->setMethodsExcept(['isCMFAndActiveNow'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $networkUtils
+            ->expects(self::once())
+            ->method('doesOrganizationBelongToTheNetwork')
+            ->with($organization, NetworkEnum::CMF(), true)
+            ->willReturn(false);
+
+        $result = $networkUtils->isCMFAndActiveNow($organization);
+        $this->assertFalse($result);
     }
 
     /**
-     * @see Utils::isCMFAndActiveNow()
+     * @see Utils::doesOrganizationBelongToTheNetwork()
      */
-    public function testIsCmfAndNotActiveNow():void
+    public function testDoesOrganizationBelongToTheNetwork():void
     {
-        $networkCmf = new Network();
-        $networkCmf->setId(3);
-        $networkCmf->setName('CMF');
-        $networkOrganization = new NetworkOrganization();
-        $networkOrganization->setNetwork($networkCmf);
-        $networkOrganization->setStartDate(new \DateTime('2000-09-11'));
-        $networkOrganization->setEndDate(new \DateTime('2020-09-11'));
-        $organizationCmfNotActive = new Organization();
-        $organizationCmfNotActive->addNetworkOrganization($networkOrganization);
-
-        $result = $this->utils->isCMFAndActiveNow($organizationCmfNotActive);
-        $this->assertFalse($result);
+        $networkUtils = $this
+            ->getMockBuilder(NetworkUtils::class)
+            ->setMethodsExcept(['doesOrganizationBelongToTheNetwork'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+
+        $network1 = $this->getMockBuilder(Network::class)->getMock();
+        $network1->method('getId')->willReturn(NetworkEnum::CMF()->getValue());
+
+        $networkOrganization1 = $this->getMockBuilder(NetworkOrganization::class)->getMock();
+        $networkOrganization1->method('getNetwork')->willReturn($network1);
+
+        $network2 = $this->getMockBuilder(Network::class)->getMock();
+        $network2->method('getId')->willReturn(NetworkEnum::FFEC()->getValue());
+
+        $networkOrganization2 = $this->getMockBuilder(NetworkOrganization::class)->getMock();
+        $networkOrganization2->method('getNetwork')->willReturn($network2);
+
+        $organization
+            ->expects(self::once())
+            ->method('getNetworkOrganizations')
+            ->willReturn(new ArrayCollection([$networkOrganization1, $networkOrganization2]));
+
+        $networkUtils->expects(self::never())->method('isNetworkOrganizationActiveNow');
+
+        $result = $networkUtils->doesOrganizationBelongToTheNetwork($organization, NetworkEnum::FFEC());
+
+        $this->assertTrue($result);
     }
 
     /**
-     * @see Utils::isOrganizationBelongToTheNetwork()
+     * @see Utils::doesOrganizationBelongToTheNetwork()
      */
-    public function testIsOrganizationBelongToTheNetwork():void
+    public function testDoesOrganizationBelongToTheNetworkAndActive():void
     {
-        $result = $this->utils->isOrganizationBelongToTheNetwork($this->organizationCmf, NetworkEnum::CMF());
+        $networkUtils = $this
+            ->getMockBuilder(NetworkUtils::class)
+            ->setMethodsExcept(['doesOrganizationBelongToTheNetwork'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+
+        $network1 = $this->getMockBuilder(Network::class)->getMock();
+        $network1->method('getId')->willReturn(NetworkEnum::CMF()->getValue());
+
+        $networkOrganization1 = $this->getMockBuilder(NetworkOrganization::class)->getMock();
+        $networkOrganization1->method('getNetwork')->willReturn($network1);
+
+        $network2 = $this->getMockBuilder(Network::class)->getMock();
+        $network2->method('getId')->willReturn(NetworkEnum::FFEC()->getValue());
+
+        $networkOrganization2 = $this->getMockBuilder(NetworkOrganization::class)->getMock();
+        $networkOrganization2->method('getNetwork')->willReturn($network2);
+
+        $organization
+            ->expects(self::once())
+            ->method('getNetworkOrganizations')
+            ->willReturn(new ArrayCollection([$networkOrganization1, $networkOrganization2]));
+
+        $networkUtils->expects(self::once())->method('isNetworkOrganizationActiveNow')->with($networkOrganization2)->willReturn(true);
+
+        $result = $networkUtils->doesOrganizationBelongToTheNetwork($organization, NetworkEnum::FFEC(), true);
+
         $this->assertTrue($result);
     }
 
     /**
-     * @see Utils::isOrganizationBelongToTheNetwork()
+     * @see Utils::doesOrganizationBelongToTheNetwork()
      */
-    public function testIsOrganizationNotBelongToTheNetwork():void
+    public function testDoesOrganizationBelongToTheNetworkFalse():void
     {
-        $result = $this->utils->isOrganizationBelongToTheNetwork($this->organizationCmf, NetworkEnum::FFEC());
+        $networkUtils = $this
+            ->getMockBuilder(NetworkUtils::class)
+            ->setMethodsExcept(['doesOrganizationBelongToTheNetwork'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+
+        $network1 = $this->getMockBuilder(Network::class)->getMock();
+        $network1->method('getId')->willReturn(NetworkEnum::CMF()->getValue());
+
+        $networkOrganization1 = $this->getMockBuilder(NetworkOrganization::class)->getMock();
+        $networkOrganization1->method('getNetwork')->willReturn($network1);
+
+        $network2 = $this->getMockBuilder(Network::class)->getMock();
+        $network2->method('getId')->willReturn(NetworkEnum::FFEC()->getValue());
+
+        $networkOrganization2 = $this->getMockBuilder(NetworkOrganization::class)->getMock();
+        $networkOrganization2->method('getNetwork')->willReturn($network2);
+
+        $organization
+            ->expects(self::once())
+            ->method('getNetworkOrganizations')
+            ->willReturn(new ArrayCollection([$networkOrganization1, $networkOrganization2]));
+
+        $networkUtils->expects(self::never())->method('isNetworkOrganizationActiveNow');
+
+        $result = $networkUtils->doesOrganizationBelongToTheNetwork($organization, NetworkEnum::CFBF());
+
         $this->assertFalse($result);
     }
-}
+
+    /**
+     * @see Utils::doesOrganizationBelongToTheNetwork()
+     */
+    public function testIsOrganizationActiveNow():void
+    {
+        $networkUtils = $this
+            ->getMockBuilder(NetworkUtils::class)
+            ->setMethodsExcept(['isNetworkOrganizationActiveNow'])
+            ->getMock();
+
+        $date1 = new DateTime('now');
+        $date1->modify('-1 year');
+
+        $date2 = new DateTime('now');
+        $date2->modify('+1 year');
+
+        $networkOrganization = $this->getMockBuilder(NetworkOrganization::class)->getMock();
+        $networkOrganization
+            ->expects(self::once())
+            ->method('getStartDate')
+            ->willReturn($date1);
+
+        $networkOrganization
+            ->expects(self::once())
+            ->method('getEndDate')
+            ->willReturn($date2);
+
+        $this->assertTrue(
+            $networkUtils->isNetworkOrganizationActiveNow($networkOrganization)
+        );
+    }
+
+    /**
+     * @see Utils::doesOrganizationBelongToTheNetwork()
+     */
+    public function testIsOrganizationActiveNowNotActive():void
+    {
+        $networkUtils = $this
+            ->getMockBuilder(NetworkUtils::class)
+            ->setMethodsExcept(['isNetworkOrganizationActiveNow'])
+            ->getMock();
+
+        $date1 = new DateTime('now');
+        $date1->modify('-3 year');
+
+        $date2 = new DateTime('now');
+        $date2->modify('-1 year');
+
+        $networkOrganization = $this->getMockBuilder(NetworkOrganization::class)->getMock();
+        $networkOrganization
+            ->expects(self::once())
+            ->method('getStartDate')
+            ->willReturn($date1);
+
+        $networkOrganization
+            ->expects(self::once())
+            ->method('getEndDate')
+            ->willReturn($date2);
+
+        $this->assertFalse(
+            $networkUtils->isNetworkOrganizationActiveNow($networkOrganization)
+        );
+    }
+}

+ 5 - 3
tests/Service/OnChange/OnChangeDefaultTest.php

@@ -7,11 +7,13 @@ use PHPUnit\Framework\TestCase;
 class OnChangeDefaultTest extends TestCase
 {
     /**
-     * Default OnChange service does nothing; it shouldn't change anything to the data nor raise excemptions
+     * Default OnChange service does nothing; it shouldn't change anything to the data nor raise exceptions
      */
-    public function testDoesNothing() {
+    public function testDoesNothing(): void
+    {
         $data = 1;
-        $context = new OnChangeContext([]);
+
+        $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
 
         $onChange = new OnChangeDefault();
         $onChange->validate($data, $context);

+ 51 - 24
tests/Service/OnChange/Organization/OnOrganizationChangeTest.php

@@ -11,22 +11,14 @@ use PHPUnit\Framework\TestCase;
 
 class OnOrganizationChangeTest extends TestCase
 {
-    private Organization $organization;
-    private OnOrganizationChange $onOrganizationChange;
-
-    public function setUp():void
-    {
-        $this->organization = new Organization();
-        $this->onOrganizationChange = new OnOrganizationChange();
-    }
-
     public function testBeforeChangeNoChange(): void
     {
         $onOrganizationChange =  $this
             ->getMockBuilder(OnOrganizationChange::class)
-            ->onlyMethods(['onLegalStatusChange'])
+            ->setMethodsExcept(['beforeChange'])
             ->disableOriginalConstructor()
             ->getMock();
+
         $onOrganizationChange
             ->expects(self::never())
             ->method('onLegalStatusChange')
@@ -48,9 +40,10 @@ class OnOrganizationChangeTest extends TestCase
     {
         $onOrganizationChange =  $this
             ->getMockBuilder(OnOrganizationChange::class)
-            ->onlyMethods(['onLegalStatusChange'])
+            ->setMethodsExcept(['beforeChange'])
             ->disableOriginalConstructor()
             ->getMock();
+
         $onOrganizationChange
             ->expects(self::once())
             ->method('onLegalStatusChange')
@@ -71,18 +64,52 @@ class OnOrganizationChangeTest extends TestCase
     /**
      * @see OnOrganizationChange::onLegalStatusChange()
      */
-    public function testOnLegalStatusChange(){
-        $this->organization->setLegalStatus(LegalEnum::COMMERCIAL_SOCIETY()->getValue());
-        $parameters = new Parameters();
-        $parameters->setShowAdherentList(true);
-        $billingSettings = new BillingSetting();
-        $billingSettings->setApplyVat(false);
-        $this->organization->setParameters($parameters);
-        $this->organization->setBillingSetting($billingSettings);
-
-        $this->onOrganizationChange->onLegalStatusChange($this->organization);
-
-        $this->assertFalse($this->organization->getParameters()->getShowAdherentList());
-        $this->assertTrue($this->organization->getBillingSetting()->getApplyVat());
+    public function testOnLegalStatusChangeToAsso(){
+
+        $onOrganizationChange =  $this
+            ->getMockBuilder(OnOrganizationChange::class)
+            ->setMethodsExcept(['onLegalStatusChange'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
+        $organization->method('getLegalStatus')->willReturn(LegalEnum::ASSOCIATION_LAW_1901()->getValue());
+
+        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $organization->method('getParameters')->willReturn($parameters);
+
+        $billingSettings = $this->getMockBuilder(BillingSetting::class)->disableOriginalConstructor()->getMock();
+        $organization->method('getBillingSetting')->willReturn($billingSettings);
+
+        $parameters->expects(self::never())->method('setShowAdherentList');
+        $billingSettings->expects(self::never())->method('setApplyVat');
+
+        $onOrganizationChange->onLegalStatusChange($organization);
+    }
+
+    /**
+     * @see OnOrganizationChange::onLegalStatusChange()
+     */
+    public function testOnLegalStatusChangeToSociety(){
+
+        $onOrganizationChange =  $this
+            ->getMockBuilder(OnOrganizationChange::class)
+            ->setMethodsExcept(['onLegalStatusChange'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
+        $organization->method('getLegalStatus')->willReturn(LegalEnum::COMMERCIAL_SOCIETY()->getValue());
+
+        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $organization->method('getParameters')->willReturn($parameters);
+
+        $billingSettings = $this->getMockBuilder(BillingSetting::class)->disableOriginalConstructor()->getMock();
+        $organization->method('getBillingSetting')->willReturn($billingSettings);
+
+        $parameters->expects(self::once())->method('setShowAdherentList')->with(false);
+        $billingSettings->expects(self::once())->method('setApplyVat')->with(true);
+
+        $onOrganizationChange->onLegalStatusChange($organization);
     }
 }

+ 217 - 111
tests/Service/OnChange/Organization/OnParametersChangeTest.php

@@ -1,4 +1,7 @@
-<?php
+<?php /** @noinspection DuplicatedCode */
+
+/** @noinspection PhpUnhandledExceptionInspection */
+
 namespace App\Test\Service\OnChange\Organization;
 
 use App\Entity\Access\Access;
@@ -13,99 +16,133 @@ use App\Message\Command\Typo3\Typo3DeleteCommand;
 use App\Message\Command\Typo3\Typo3UndeleteCommand;
 use App\Message\Command\Typo3\Typo3UpdateCommand;
 use App\Repository\Booking\CourseRepository;
+use App\Service\Network\Utils as NetworkUtils;
 use App\Service\OnChange\OnChangeContext;
 use App\Service\OnChange\Organization\OnParametersChange;
+use App\Service\Organization\Utils as OrganizationUtils;
 use AssertionError;
+use Doctrine\Common\Collections\ArrayCollection;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\Messenger\Envelope;
 use Symfony\Component\Messenger\MessageBusInterface;
 
 class OnParametersChangeTest extends TestCase
 {
-    private Parameters $parameters;
-    private OnParametersChange $onParametersChange;
-    private CourseRepository $courseRepositoryMock;
-    private \App\Service\Network\Utils $networkUtils;
+    private CourseRepository $courseRepository;
+    private NetworkUtils $networkUtils;
     private MessageBusInterface $messageBus;
-    private \App\Service\Organization\Utils $organizationUtils;
+    private OrganizationUtils $organizationUtils;
 
     public function setUp(): void
     {
-        $this->courseRepositoryMock = $this->getMockBuilder(CourseRepository::class)->disableOriginalConstructor()->getMock();
-        $this->networkUtils = $this->getMockBuilder(\App\Service\Network\Utils::class)->disableOriginalConstructor()->getMock();
-        $this->organizationUtils = $this->getMockBuilder(\App\Service\Organization\Utils::class)->disableOriginalConstructor()->getMock();
+        $this->courseRepository = $this->getMockBuilder(CourseRepository::class)->disableOriginalConstructor()->getMock();
+        $this->networkUtils = $this->getMockBuilder(NetworkUtils::class)->disableOriginalConstructor()->getMock();
+        $this->organizationUtils = $this->getMockBuilder(OrganizationUtils::class)->disableOriginalConstructor()->getMock();
         $this->messageBus = $this->getMockBuilder(MessageBusInterface::class)->disableOriginalConstructor()->getMock();
-        $this->parameters = new Parameters();
-        $this->onParametersChange = new OnParametersChange(
-            $this->courseRepositoryMock,
-            $this->networkUtils,
-            $this->organizationUtils,
-            $this->messageBus
-        );
     }
 
-    public function testValidate(): void
+    public function testValidateValid(): void
     {
+        $onParametersChange = $this->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['validate'])
+            ->getMock();
+
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
 
-        // 1. Is CMF and site web enabled ; 2. Is not CMF and site web disabled ; 3. Is not CMF and site web enabled
-        foreach ([[false, true], [true, false], [false, false]] as $params) {
-            $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $consecutiveParams = [
+            [false, true],  // Is CMF and site web enabled
+            [true, false],  // Is not CMF and site web disabled
+            [false, false]  // Is not CMF and site web enabled
+        ];
+
+        foreach ($consecutiveParams as $params) {
+            $organization = $this->getMockBuilder(Organization::class)->getMock();
+            $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+            $parameters->method('getOrganization')->willReturn($organization);
+
             $parameters->expects(self::once())->method('getDesactivateOpentalentSiteWeb')->willReturn($params[0]);
 
-            $this->networkUtils = $this->getMockBuilder(\App\Service\Network\Utils::class)->disableOriginalConstructor()->getMock();
-            $this->networkUtils->method('isCMFAndActiveNow')->willReturn($params[1]);
+            $this->networkUtils = $this->getMockBuilder(NetworkUtils::class)->getMock();
+            $this->networkUtils->method('isCMFAndActiveNow')->with($organization)->willReturn($params[1]);
 
-            $this->onParametersChange->validate($parameters, $context);
+            $onParametersChange->validate($parameters, $context);
         }
     }
 
     public function testValidateInvalid(): void
     {
-        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $onParametersChange = $this->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['validate'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $parameters->method('getOrganization')->willReturn($organization);
+
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
 
         // Is CMF and site web disabled
         $parameters->expects(self::once())->method('getDesactivateOpentalentSiteWeb')->willReturn(true);
-        $this->networkUtils->expects(self::once())->method('isCMFAndActiveNow')->willReturn(true);
+        $this->networkUtils->expects(self::once())->method('isCMFAndActiveNow')->with($organization)->willReturn(true);
 
         $this->expectException(\RuntimeException::class);
 
-        $this->onParametersChange->validate($parameters, $context);
+        $onParametersChange->validate($parameters, $context);
     }
 
     public function testBeforeChange(): void
     {
-        $onParametersChange =  $this
+        $onParametersChange = $this
             ->getMockBuilder(OnParametersChange::class)
-            ->onlyMethods(['onAdvancedEducationNotationTypeChange', 'onMusicalDateChange'])
-            ->disableOriginalConstructor()
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['beforeChange'])
             ->getMock();
 
-        $onParametersChange
-            ->expects(self::once())
-            ->method('onAdvancedEducationNotationTypeChange')
-            ->willReturnSelf();
-        $onParametersChange
-            ->expects(self::once())
-            ->method('onMusicalDateChange')
-            ->willReturnSelf();
+        $onParametersChange->expects(self::once())->method('onAdvancedEducationNotationTypeChange');
+
+        $onParametersChange->expects(self::once())->method('onMusicalDateChange');
 
-        $previousParameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
-        $previousParameters->method('getAdvancedEducationNotationType')->willReturn('BY_EDUCATION');
         $musicalDate = new \DateTime('2022-01-01');
+
+        $previousParameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $previousParameters->method('getAdvancedEducationNotationType')->willReturn('BY_EDUCATION');
         $previousParameters->method('getMusicalDate')->willReturn($musicalDate);
+
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
         $context->method('previousData')->willReturn($previousParameters);
 
-        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
         $parameters->method('getAdvancedEducationNotationType')->willReturn('SOMETHING_ELSE');
         $parameters->method('getMusicalDate')->willReturn(new \DateTime('2023-01-01'));
 
         // Both mocked methods should be called once here
         $onParametersChange->beforeChange($parameters, $context);
+    }
+
+    public function testBeforeChangeNoChange(): void
+    {
+        $onParametersChange = $this
+            ->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['beforeChange'])
+            ->getMock();
+
+        $onParametersChange->expects(self::never())->method('onAdvancedEducationNotationTypeChange');
+
+        $onParametersChange->expects(self::never())->method('onMusicalDateChange');
+
+        $musicalDate = new \DateTime('2022-01-01');
+
+        $previousParameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $previousParameters->method('getAdvancedEducationNotationType')->willReturn('BY_EDUCATION');
+        $previousParameters->method('getMusicalDate')->willReturn($musicalDate);
+
+        $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
+        $context->method('previousData')->willReturn($previousParameters);
 
-        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
         $parameters->method('getId')->willReturn(1);
         $parameters->method('getAdvancedEducationNotationType')->willReturn('BY_EDUCATION');
         $parameters->method('getMusicalDate')->willReturn($musicalDate);
@@ -116,35 +153,47 @@ class OnParametersChangeTest extends TestCase
 
     public function testOnChangeNoChange(): void
     {
+        $onParametersChange = $this
+            ->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['onChange'])
+            ->getMock();
+
         $this->messageBus->expects($this->never())->method('dispatch');
 
-        $previousParameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $previousParameters = $this->getMockBuilder(Parameters::class)->getMock();
         $previousParameters->method('getId')->willReturn(1);
-        $previousParameters->expects(self::once())->method('getAverage')->willReturn(20);
-        $previousParameters->expects(self::once())->method('getDesactivateOpentalentSiteWeb')->willReturn(false);
-        $previousParameters->expects(self::once())->method('getCustomDomain')->willReturn(null);
+        $previousParameters->method('getAverage')->willReturn(20);
+        $previousParameters->method('getDesactivateOpentalentSiteWeb')->willReturn(false);
+        $previousParameters->method('getCustomDomain')->willReturn(null);
 
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
         $context->method('previousData')->willReturn($previousParameters);
 
-        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
         $parameters->method('getId')->willReturn(1);
         $parameters->method('getAverage')->willReturn(20);
         $parameters->method('getDesactivateOpentalentSiteWeb')->willReturn(false);
         $parameters->method('getCustomDomain')->willReturn(null);
 
-        $this->onParametersChange->onChange($parameters, $context);
+        $onParametersChange->onChange($parameters, $context);
     }
 
     public function testOnChangeAverageChanged(): void
     {
+        $onParametersChange = $this
+            ->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['onChange'])
+            ->getMock();
+
         $this->messageBus
             ->expects(self::once())
             ->method('dispatch')
             ->with(self::isInstanceOf(AverageChange::class))
             ->willReturn(new Envelope(new AverageChange(1)));
 
-        $previousParameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $previousParameters = $this->getMockBuilder(Parameters::class)->getMock();
         $previousParameters->method('getId')->willReturn(1);
         $previousParameters->expects(self::once())->method('getAverage')->willReturn(20);
         $previousParameters->method('getDesactivateOpentalentSiteWeb')->willReturn(false);
@@ -153,24 +202,30 @@ class OnParametersChangeTest extends TestCase
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
         $context->method('previousData')->willReturn($previousParameters);
 
-        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
         $parameters->method('getId')->willReturn(1);
         $parameters->method('getDesactivateOpentalentSiteWeb')->willReturn(false);
         $parameters->method('getCustomDomain')->willReturn(null);
         $parameters->expects(self::once())->method('getAverage')->willReturn(30);
 
-        $this->onParametersChange->onChange($parameters, $context);
+        $onParametersChange->onChange($parameters, $context);
     }
 
     public function testOnChangeCustomDomainChanged(): void
     {
+        $onParametersChange = $this
+            ->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['onChange'])
+            ->getMock();
+
         $this->messageBus
             ->expects(self::once())
             ->method('dispatch')
             ->with(self::isInstanceOf(Typo3UpdateCommand::class))
             ->willReturn(new Envelope(new Typo3UpdateCommand(1)));
 
-        $previousParameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $previousParameters = $this->getMockBuilder(Parameters::class)->getMock();
         $previousParameters->method('getId')->willReturn(1);
         $previousParameters->method('getAverage')->willReturn(20);
         $previousParameters->method('getDesactivateOpentalentSiteWeb')->willReturn(false);
@@ -179,28 +234,34 @@ class OnParametersChangeTest extends TestCase
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
         $context->method('previousData')->willReturn($previousParameters);
 
-        $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
         $organization->method('getId')->willReturn(1);
 
-        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
         $parameters->method('getId')->willReturn(1);
         $parameters->method('getOrganization')->willReturn($organization);
         $parameters->method('getDesactivateOpentalentSiteWeb')->willReturn(false);
         $parameters->expects(self::once())->method('getCustomDomain')->willReturn('custom');
         $parameters->method('getAverage')->willReturn(20);
 
-        $this->onParametersChange->onChange($parameters, $context);
+        $onParametersChange->onChange($parameters, $context);
     }
 
     public function testOnChangeWebsiteDisabled(): void
     {
+        $onParametersChange = $this
+            ->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['onChange'])
+            ->getMock();
+
         $this->messageBus
             ->expects(self::once())
             ->method('dispatch')
             ->with(self::isInstanceOf(Typo3DeleteCommand::class))
             ->willReturn(new Envelope(new Typo3DeleteCommand(1)));
 
-        $previousParameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $previousParameters = $this->getMockBuilder(Parameters::class)->getMock();
         $previousParameters->method('getId')->willReturn(1);
         $previousParameters->method('getAverage')->willReturn(20);
         $previousParameters->expects(self::once())->method('getDesactivateOpentalentSiteWeb')->willReturn(false);
@@ -209,21 +270,27 @@ class OnParametersChangeTest extends TestCase
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
         $context->method('previousData')->willReturn($previousParameters);
 
-        $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
         $organization->method('getId')->willReturn(1);
 
-        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
         $parameters->method('getId')->willReturn(1);
         $parameters->method('getOrganization')->willReturn($organization);
         $parameters->method('getDesactivateOpentalentSiteWeb')->willReturn(true);
         $parameters->method('getCustomDomain')->willReturn(null);
         $parameters->method('getAverage')->willReturn(20);
 
-        $this->onParametersChange->onChange($parameters, $context);
+        $onParametersChange->onChange($parameters, $context);
     }
 
     public function testOnChangeWebsiteEnabled(): void
     {
+        $onParametersChange = $this
+            ->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['onChange'])
+            ->getMock();
+
         $this->messageBus
             ->expects(self::exactly(2))
             ->method('dispatch')
@@ -237,7 +304,7 @@ class OnParametersChangeTest extends TestCase
                 throw new AssertionError('unexpected message : ' . $message::class);
             });
 
-        $previousParameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $previousParameters = $this->getMockBuilder(Parameters::class)->getMock();
         $previousParameters->method('getId')->willReturn(1);
         $previousParameters->method('getAverage')->willReturn(20);
         $previousParameters->expects(self::once())->method('getDesactivateOpentalentSiteWeb')->willReturn(true);
@@ -246,17 +313,17 @@ class OnParametersChangeTest extends TestCase
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
         $context->method('previousData')->willReturn($previousParameters);
 
-        $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
         $organization->method('getId')->willReturn(1);
 
-        $parameters = $this->getMockBuilder(Parameters::class)->disableOriginalConstructor()->getMock();
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
         $parameters->method('getId')->willReturn(1);
         $parameters->method('getOrganization')->willReturn($organization);
         $parameters->method('getDesactivateOpentalentSiteWeb')->willReturn(false);
         $parameters->method('getCustomDomain')->willReturn(null);
         $parameters->method('getAverage')->willReturn(20);
 
-        $this->onParametersChange->onChange($parameters, $context);
+        $onParametersChange->onChange($parameters, $context);
     }
 
     /**
@@ -264,19 +331,27 @@ class OnParametersChangeTest extends TestCase
      */
     public function testOnAdvancedEducationNotationTypeByTeachersChange(): void
     {
-        $educationNotationConfig = new EducationNotationConfig();
-        $educationCurriculum = new EducationCurriculum();
-        $educationNotationConfig->addEducationCurriculum($educationCurriculum);
+        $onParametersChange = $this
+            ->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['onAdvancedEducationNotationTypeChange'])
+            ->getMock();
 
-        $organization = new Organization();
-        $organization->addEducationNotationConfig($educationNotationConfig);
+        $educationCurriculum = $this->getMockBuilder(EducationCurriculum::class)->getMock();
 
-        $this->parameters->setAdvancedEducationNotationType(AdvancedEducationNotationTypeEnum::BY_TEACHER()->getValue());
-        $this->parameters->setOrganization($organization);
+        $educationNotationConfig = $this->getMockBuilder(EducationNotationConfig::class)->getMock();
+        $educationNotationConfig->method('getEducationCurriculums')->willReturn(new ArrayCollection([$educationCurriculum]));
 
-        $this->assertCount(1, $educationNotationConfig->getEducationCurriculums());
-        $this->onParametersChange->onAdvancedEducationNotationTypeChange($this->parameters);
-        $this->assertNull($educationNotationConfig->getEducationCurriculums()->first()->getEducationNotationConfig());
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getEducationNotationConfigs')->willReturn(new ArrayCollection([$educationNotationConfig]));
+
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $parameters->method('getOrganization')->willReturn($organization);
+        $parameters->method('getAdvancedEducationNotationType')->willReturn(AdvancedEducationNotationTypeEnum::BY_TEACHER()->getValue());
+
+        $educationCurriculum->expects(self::once())->method('setEducationNotationConfig')->with(null);
+
+        $onParametersChange->onAdvancedEducationNotationTypeChange($parameters);
     }
 
     /**
@@ -284,19 +359,27 @@ class OnParametersChangeTest extends TestCase
      */
     public function testOnAdvancedEducationNotationTypeByEducationChange(): void
     {
-        $educationNotationConfig = new EducationNotationConfig();
-        $teacher = new Access();
-        $educationNotationConfig->addTeacher($teacher);
+        $onParametersChange = $this
+            ->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['onAdvancedEducationNotationTypeChange'])
+            ->getMock();
+
+        $teacher = $this->getMockBuilder(Access::class)->getMock();
+
+        $educationNotationConfig = $this->getMockBuilder(EducationNotationConfig::class)->getMock();
+        $educationNotationConfig->method('getTeachers')->willReturn(new ArrayCollection([$teacher]));
 
-        $organization = new Organization();
-        $organization->addEducationNotationConfig($educationNotationConfig);
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getEducationNotationConfigs')->willReturn(new ArrayCollection([$educationNotationConfig]));
+
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $parameters->method('getOrganization')->willReturn($organization);
+        $parameters->method('getAdvancedEducationNotationType')->willReturn(AdvancedEducationNotationTypeEnum::BY_EDUCATION()->getValue());
 
-        $this->parameters->setAdvancedEducationNotationType(AdvancedEducationNotationTypeEnum::BY_EDUCATION()->getValue());
-        $this->parameters->setOrganization($organization);
+        $teacher->expects(self::once())->method('setEducationNotationConfig')->with(null);
 
-        $this->assertCount(1, $educationNotationConfig->getTeachers());
-        $this->onParametersChange->onAdvancedEducationNotationTypeChange($this->parameters);
-        $this->assertNull($educationNotationConfig->getTeachers()->first()->getEducationNotationConfig());
+        $onParametersChange->onAdvancedEducationNotationTypeChange($parameters);
     }
 
     /**
@@ -306,28 +389,38 @@ class OnParametersChangeTest extends TestCase
      */
     public function testOnMusicalDateChangeToPast(): void
     {
-        $this->parameters->setMusicalDate(new \DateTime('2022-09-01'));
+        $onParametersChange = $this
+            ->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['onMusicalDateChange'])
+            ->getMock();
 
-        $organization = new Organization();
-        $this->parameters->setOrganization($organization);
-        $organization->setParameters($this->parameters);
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $organization->method('getParameters')->willReturn($parameters);
+        $parameters->method('getOrganization')->willReturn($organization);
 
-        $this->organizationUtils->expects(self::once())->method('getActivityYearSwitchDate')->willReturn(2022);
+        $parameters->method('getMusicalDate')->willReturn(new \DateTime('2022-09-01'));
 
-        $course = new Course();
-        $course->setStartYear(2021);
-        $course->setEndYear(2022);
-        $course->setDatetimeStart(new \DateTime('2022-09-02'));
+        $startDate = new \DateTime('2022-09-02');
 
-        $this->courseRepositoryMock
-            ->method('getCoursesToFrom')
-            ->willReturn([$course])
-        ;
+        $this->organizationUtils
+            ->expects(self::once())
+            ->method('getActivityYearSwitchDate')
+            ->with($organization, $startDate)
+            ->willReturn(2022);
+
+        $course = $this->getMockBuilder(Course::class)->getMock();
+        $course->method('getStartYear')->willReturn(2021);
+        $course->method('getEndYear')->willReturn(2022);
+        $course->method('getDatetimeStart')->willReturn($startDate);
 
-        $this->onParametersChange->onMusicalDateChange($this->parameters, new \DateTime('2022-09-05'));
+        $this->courseRepository->method('getCoursesToFrom')->willReturn([$course]);
 
-        $this->assertEquals(2022, $course->getStartYear());
-        $this->assertEquals(2023, $course->getEndYear());
+        $course->expects(self::once())->method('setStartYear')->with(2022);
+        $course->expects(self::once())->method('setEndYear')->with(2023);
+
+        $onParametersChange->onMusicalDateChange($parameters, new \DateTime('2022-09-05'));
     }
 
     /**
@@ -338,27 +431,40 @@ class OnParametersChangeTest extends TestCase
      */
     public function testOnMusicalDateChangeToFuture(): void
     {
-        $this->parameters->setMusicalDate(new \DateTime('2022-09-05'));
+        $onParametersChange = $this
+            ->getMockBuilder(OnParametersChange::class)
+            ->setConstructorArgs([$this->courseRepository, $this->networkUtils, $this->organizationUtils, $this->messageBus])
+            ->setMethodsExcept(['onMusicalDateChange'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $organization->method('getParameters')->willReturn($parameters);
+        $parameters->method('getOrganization')->willReturn($organization);
 
-        $organization = new Organization();
-        $this->parameters->setOrganization($organization);
-        $organization->setParameters($this->parameters);
+        $parameters->method('getMusicalDate')->willReturn(new \DateTime('2022-09-05'));
 
-        $this->organizationUtils->expects(self::once())->method('getActivityYearSwitchDate')->willReturn(2021);
+        $startDate = new \DateTime('2022-09-02');
+
+        $this->organizationUtils
+            ->expects(self::once())
+            ->method('getActivityYearSwitchDate')
+            ->with($organization, $startDate)
+            ->willReturn(2021);
 
-        $course = new Course();
-        $course->setStartYear(2022);
-        $course->setEndYear(2023);
-        $course->setDatetimeStart(new \DateTime('2022-09-02'));
+        $course = $this->getMockBuilder(Course::class)->getMock();
+        $course->method('getStartYear')->willReturn(2022);
+        $course->method('getEndYear')->willReturn(2023);
+        $course->method('getDatetimeStart')->willReturn($startDate);
 
-        $this->courseRepositoryMock
+        $this->courseRepository
             ->method('getCoursesToFrom')
             ->willReturn([$course])
         ;
 
-        $this->onParametersChange->onMusicalDateChange($this->parameters, new \DateTime('2022-09-01'));
+        $course->expects(self::once())->method('setStartYear')->with(2021);
+        $course->expects(self::once())->method('setEndYear')->with(2022);
 
-        $this->assertEquals(2021, $course->getStartYear());
-        $this->assertEquals(2022, $course->getEndYear());
+        $onParametersChange->onMusicalDateChange($parameters, new \DateTime('2022-09-01'));
     }
 }

+ 36 - 40
tests/Service/OnChange/Organization/OnSubdomainChangeTest.php

@@ -1,4 +1,4 @@
-<?php
+<?php /** @noinspection DuplicatedCode */
 
 namespace App\Test\Service\OnChange\Organization;
 
@@ -14,6 +14,7 @@ use App\Service\Organization\Utils as OrganizationUtils;
 use App\Service\Typo3\BindFileService;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\ORM\EntityManagerInterface;
+use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\Messenger\Envelope;
 use Symfony\Component\Messenger\MessageBusInterface;
@@ -25,7 +26,6 @@ class OnSubdomainChangeTest extends TestCase
     private MailHub $mailHub;
     private BindFileService $bindFileService;
     private MessageBusInterface $messageBus;
-    private OnSubdomainChange $onSubdomainChange;
 
     public function setUp():void
     {
@@ -34,18 +34,19 @@ class OnSubdomainChangeTest extends TestCase
         $this->mailHub = $this->getMockBuilder(MailHub::class)->disableOriginalConstructor()->getMock();
         $this->bindFileService = $this->getMockBuilder(BindFileService::class)->disableOriginalConstructor()->getMock();
         $this->messageBus = $this->getMockBuilder(MessageBusInterface::class)->disableOriginalConstructor()->getMock();
+    }
 
-        $this->onSubdomainChange = new OnSubdomainChange(
-            $this->organizationUtils,
-            $this->accessUtils,
-            $this->mailHub,
-            $this->bindFileService,
-            $this->messageBus
-        );
+    private function makeOnSubdomainChangeMock(string $methodName): MockObject | OnSubdomainChange {
+        return $this->getMockBuilder(OnSubdomainChange::class)
+            ->setConstructorArgs([$this->organizationUtils, $this->accessUtils, $this->mailHub, $this->bindFileService, $this->messageBus])
+            ->setMethodsExcept([$methodName])
+            ->getMock();
     }
 
     public function testValidateIsOk(): void
     {
+        $onSubdomainChange = $this->makeOnSubdomainChangeMock('validate');
+
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
         $context->method('isPostRequest')->willReturn(true);
 
@@ -55,22 +56,26 @@ class OnSubdomainChangeTest extends TestCase
         $subdomain = $this->getMockBuilder(Subdomain::class)->disableOriginalConstructor()->getMock();
         $subdomain->expects(self::once())->method('getOrganization')->willReturn($organization);
 
-        $this->onSubdomainChange->validate($subdomain, $context);
+        $onSubdomainChange->validate($subdomain, $context);
     }
 
     public function testValidateIsPutRequest(): void
     {
+        $onSubdomainChange = $this->makeOnSubdomainChangeMock('validate');
+
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
         $context->method('isPostRequest')->willReturn(false);
 
         $subdomain = $this->getMockBuilder(Subdomain::class)->disableOriginalConstructor()->getMock();
         $subdomain->expects(self::never())->method('getOrganization');
 
-        $this->onSubdomainChange->validate($subdomain, $context);
+        $onSubdomainChange->validate($subdomain, $context);
     }
 
     public function testValidateMaxReached(): void
     {
+        $onSubdomainChange = $this->makeOnSubdomainChangeMock('validate');
+
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
         $context->method('isPostRequest')->willReturn(true);
 
@@ -81,10 +86,13 @@ class OnSubdomainChangeTest extends TestCase
         $subdomain->expects(self::once())->method('getOrganization')->willReturn($organization);
 
         $this->expectException(\RuntimeException::class);
-        $this->onSubdomainChange->validate($subdomain, $context);
+        $onSubdomainChange->validate($subdomain, $context);
     }
 
-    public function testBeforeChangeActivated() {
+    public function testBeforeChangeActivated(): void
+    {
+        $onSubdomainChange = $this->makeOnSubdomainChangeMock('beforeChange');
+
         // Le sous-domaine qu'on vient d'activer
         $subdomain = $this->getMockBuilder(Subdomain::class)->disableOriginalConstructor()->getMock();
         $subdomain->method('isActive')->willReturn(true);
@@ -108,28 +116,26 @@ class OnSubdomainChangeTest extends TestCase
         $context->method('isPutRequest')->willReturn(true);
         $context->method('isPostRequest')->willReturn(false);
 
-        $this->onSubdomainChange->beforeChange($subdomain, $context);
+        $onSubdomainChange->beforeChange($subdomain, $context);
     }
 
     public function testOnChangeNoChange(): void
     {
-        $onChange =  $this
-            ->getMockBuilder(OnSubdomainChange::class)
-            ->onlyMethods(['sendEmailAfterSubdomainChange'])
-            ->disableOriginalConstructor()
-            ->getMock();
+        $onSubdomainChange = $this->makeOnSubdomainChangeMock('onChange');
 
         $this->bindFileService->expects(self::never())->method('registerSubdomain');
         $this->messageBus->expects(self::never())->method('dispatch');
-        $onChange->expects(self::never())->method('sendEmailAfterSubdomainChange');
+        $onSubdomainChange->expects(self::never())->method('sendEmailAfterSubdomainChange');
 
         $subdomain = $this->getMockBuilder(Subdomain::class)->disableOriginalConstructor()->getMock();
         $context = $this->getMockBuilder(OnChangeContext::class)->disableOriginalConstructor()->getMock();
 
-        $onChange->onChange($subdomain, $context);
+        $onSubdomainChange->onChange($subdomain, $context);
     }
 
     public function testOnChangeActivated(): void {
+        $onSubdomainChange = $this->makeOnSubdomainChangeMock('onChange');
+
         $this->bindFileService->expects(self::never())->method('registerSubdomain');
         $this->messageBus
             ->expects(self::once())
@@ -137,14 +143,7 @@ class OnSubdomainChangeTest extends TestCase
             ->with(self::isInstanceOf(Typo3UpdateCommand::class))
             ->willReturn(new Envelope(new Typo3UpdateCommand(1)));
 
-        $onChange = $this
-            ->getMockBuilder(OnSubdomainChange::class)
-            ->onlyMethods(['sendEmailAfterSubdomainChange'])
-            ->setConstructorArgs(
-                [$this->organizationUtils, $this->accessUtils, $this->mailHub, $this->bindFileService, $this->messageBus]
-            )
-            ->getMock();
-        $onChange->expects(self::once())->method('sendEmailAfterSubdomainChange');
+        $onSubdomainChange->expects(self::once())->method('sendEmailAfterSubdomainChange');
 
         // Le sous-domaine qu'on vient d'activer
         $subdomain = $this->getMockBuilder(Subdomain::class)->disableOriginalConstructor()->getMock();
@@ -164,10 +163,12 @@ class OnSubdomainChangeTest extends TestCase
         $context->method('isPutRequest')->willReturn(true);
         $context->method('isPostRequest')->willReturn(false);
 
-        $onChange->onChange($subdomain, $context);
+        $onSubdomainChange->onChange($subdomain, $context);
     }
 
     public function testOnChangeCreated(): void {
+        $onSubdomainChange = $this->makeOnSubdomainChangeMock('onChange');
+
         $this->bindFileService->expects(self::once())->method('registerSubdomain');
         $this->messageBus
             ->expects(self::once())
@@ -175,14 +176,7 @@ class OnSubdomainChangeTest extends TestCase
             ->with(self::isInstanceOf(Typo3UpdateCommand::class))
             ->willReturn(new Envelope(new Typo3UpdateCommand(1)));
 
-        $onChange = $this
-            ->getMockBuilder(OnSubdomainChange::class)
-            ->onlyMethods(['sendEmailAfterSubdomainChange'])
-            ->setConstructorArgs(
-                [$this->organizationUtils, $this->accessUtils, $this->mailHub, $this->bindFileService, $this->messageBus]
-            )
-            ->getMock();
-        $onChange->expects(self::once())->method('sendEmailAfterSubdomainChange');
+        $onSubdomainChange->expects(self::once())->method('sendEmailAfterSubdomainChange');
 
         // Le sous-domaine qu'on vient d'activer
         $subdomain = $this->getMockBuilder(Subdomain::class)->disableOriginalConstructor()->getMock();
@@ -198,10 +192,12 @@ class OnSubdomainChangeTest extends TestCase
         $context->method('isPutRequest')->willReturn(false);
         $context->method('isPostRequest')->willReturn(true);
 
-        $onChange->onChange($subdomain, $context);
+        $onSubdomainChange->onChange($subdomain, $context);
     }
 
     public function testSendEmailAfterSubdomainChange(): void {
+        $onSubdomainChange = $this->makeOnSubdomainChangeMock('sendEmailAfterSubdomainChange');
+
         $admin = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
 
         $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
@@ -232,6 +228,6 @@ class OnSubdomainChangeTest extends TestCase
                 ]
             );
 
-        $this->onSubdomainChange->sendEmailAfterSubdomainChange($subdomain);
+        $onSubdomainChange->sendEmailAfterSubdomainChange($subdomain);
     }
 }

+ 140 - 56
tests/Service/Organization/OrganizationProfileCreatorTest.php

@@ -1,85 +1,169 @@
-<?php
+<?php /** @noinspection DuplicatedCode */
+
 namespace App\Test\Service\Organization;
 
 use App\ApiResources\Profile\OrganizationProfile;
+use App\Entity\Network\Network;
+use App\Entity\Network\NetworkOrganization;
 use App\Entity\Organization\Organization;
 use App\Entity\Organization\Parameters;
 use App\Entity\Organization\Settings;
-use App\Entity\Organization\Subdomain;
 use App\Enum\Organization\PrincipalTypeEnum;
 use App\Service\Network\Tree;
 use App\Service\Organization\OrganizationProfileCreator;
+use App\Service\Organization\Utils as OrganizationUtils;
 use App\Service\Security\Module;
+use Doctrine\Common\Collections\ArrayCollection;
 use PHPUnit\Framework\TestCase;
 
 class OrganizationProfileCreatorTest extends TestCase
 {
-    private Organization  $organization;
-    private Module $moduleMock;
-    private Tree $treeMock;
-    private OrganizationProfileCreator $organizationProfileCreator;
+    private Module $module;
+    private Tree $tree;
+    private OrganizationUtils $organizationUtils;
 
     public function setUp():void
     {
-        $this->organization = new Organization();
-
-        $this->moduleMock = $this->getMockBuilder(Module::class)->disableOriginalConstructor()->getMock();
-        $this->moduleMock
-            ->method('getOrganizationModules')
-            ->with($this->organization)
-            ->willReturn(["MODULE_A", "MODULE_B"]);
-
-        $this->treeMock = $this->getMockBuilder(Tree::class)->disableOriginalConstructor()->getMock();
-        $parent = new Organization();
-        $parent->setName('Parent');
-        $parent->setParameters(new Parameters());
-        $this->treeMock
-            ->method('findAllParentsAndSortByType')
-            ->with($this->organization)
-            ->willReturn([$parent, $parent]);
-
-        $organizationUtils = new \App\Service\Organization\Utils();
-
-        $this->organizationProfileCreator = new OrganizationProfileCreator($this->moduleMock,$this->treeMock, $organizationUtils);
-
-        $this->organization->setPrincipalType(PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY());
-        $settings = new Settings();
-        $settings->setProduct('adminassos');
-        $parameters = new Parameters();
-        $parameters->setShowAdherentList(true);
-        $subdomain = new Subdomain();
-
-        $this->organization
-            ->setParameters($parameters)
-            ->setSettings($settings)
-            ->addSubdomain($subdomain)
-            ->setName('Foo')
-        ;
+        $this->module = $this->getMockBuilder(Module::class)->disableOriginalConstructor()->getMock();
+        $this->tree = $this->getMockBuilder(Tree::class)->disableOriginalConstructor()->getMock();
+        $this->organizationUtils = $this->getMockBuilder(OrganizationUtils::class)->disableOriginalConstructor()->getMock();
     }
 
     /**
      * @see OrganizationProfileCreator::createCompleteOrganizationProfile()
      */
-    public function testCreateCompleteOrganizationProfile(){
-        $organizationProfile = $this->organizationProfileCreator->createCompleteOrganizationProfile($this->organization);
-        $this->assertInstanceOf(OrganizationProfile::class, $organizationProfile);
-    }
+    public function testCreateCompleteOrganizationProfile(): void
+    {
+        $organizationProfileCreator = $this->getMockBuilder(OrganizationProfileCreator::class)
+            ->setConstructorArgs([$this->module, $this->tree, $this->organizationUtils])
+            ->setMethodsExcept(['createCompleteOrganizationProfile'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organizationProfile = $this->getMockBuilder(OrganizationProfile::class)->getMock();
+
+        $modules = ['1'];
+        $this->module->method('getOrganizationModules')->with($organization)->willReturn($modules);
+        $organizationProfile->expects(self::once())->method('setModules')->with($modules);
+
+        $product = "product";
+        $settings = $this->getMockBuilder(Settings::class)->getMock();
+        $settings->method('getProduct')->willReturn($product);
+        $organization->method('getSettings')->willReturn($settings);
+        $organizationProfile->expects(self::once())->method('setProduct')->with($product);
+
+        $parametersId = 101;
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $parameters->method('getId')->willReturn($parametersId);
+        $organization->method('getParameters')->willReturn($parameters);
+        $organizationProfile->expects(self::once())->method('setParametersId')->with($parametersId);
+
+        $organization->method('getLegalStatus')->willReturn('foo');
+        $organizationProfile->expects(self::once())->method('setLegalStatus')->with('foo');
+
+        $organization->method('getNetworkOrganizationChildren')->willReturn(new ArrayCollection([1, 2, 3]));
+        $organizationProfile->expects(self::once())->method('setHasChildren')->with(true);
+
+        $parameters->method('getShowAdherentList')->willReturn(true);
+        $organization->method('getPrincipalType')->willReturn(PrincipalTypeEnum::LOCAL_FEDERATION()->getValue());
+        $organizationProfile->expects(self::once())->method('setShowAdherentList')->with(true);
+
+        $network1 = $this->getMockBuilder(Network::class)->getMock();
+        $network1->method('getName')->willReturn('Net 1');
+        $networkOrganization1 = $this->getMockBuilder(NetworkOrganization::class)->getMock();
+        $networkOrganization1->method('getNetwork')->willReturn($network1);
+
+        $network2 = $this->getMockBuilder(Network::class)->getMock();
+        $network2->method('getName')->willReturn('Net 2');
+        $networkOrganization2 = $this->getMockBuilder(NetworkOrganization::class)->getMock();
+        $networkOrganization2->method('getNetwork')->willReturn($network2);
+
+        $organization->method('getNetworkOrganizations')->willReturn(new ArrayCollection([$networkOrganization1, $networkOrganization2]));
+
+        $organizationProfile->expects(self::exactly(2))->method('addNetwork')->withConsecutive(['Net 1'], ['Net 2']);
+
+        $parent1 = $this->getMockBuilder(Organization::class)->getMock();
+        $parent2 = $this->getMockBuilder(Organization::class)->getMock();
+        $this->tree->method('findAllParentsAndSortByType')->willReturn([$parent1, $parent2]);
+
+        $parentProfile1 = $this->getMockBuilder(OrganizationProfile::class)->getMock();
+        $parentProfile2 = $this->getMockBuilder(OrganizationProfile::class)->getMock();
+
+        // Called 3 times, once for the organization, two for its parents
+        $organizationProfileCreator
+            ->expects(self::exactly(3))
+            ->method('createLightOrganizationProfile')
+            ->withConsecutive([$organization], [$parent1], [$parent2])
+            ->willReturnOnConsecutiveCalls($organizationProfile, $parentProfile1, $parentProfile2);
+
+        $organizationProfile
+            ->expects(self::exactly(2))
+            ->method('addParent')
+            ->withConsecutive([$parentProfile1], [$parentProfile2]);
+
+        $this->organizationUtils->method('getOrganizationCurrentActivityYear')->with($organization)->willReturn(2022);
+        $organizationProfile->expects(self::once())->method('setCurrentYear')->with();
 
-    public function testCreateOrganizationProfileWithoutAdherentListBecauseOfPrincipalType(){
-        $organizationProfile = $this->organizationProfileCreator->createCompleteOrganizationProfile($this->organization);
-        $this->assertFalse($organizationProfile->getShowAdherentList());
+        $returned = $organizationProfileCreator->createCompleteOrganizationProfile($organization);
+
+        $this->assertSame(
+            $organizationProfile,
+            $returned
+        );
     }
 
-    public function testCreateOrganizationProfileWithoutAdherentList(){
-        $this->organization->setPrincipalType(PrincipalTypeEnum::ARTISTIC_PRACTICE_ONLY());
-        $this->organization->getParameters()->setShowAdherentList(false);
-        $organizationProfile = $this->organizationProfileCreator->createCompleteOrganizationProfile($this->organization);
-        $this->assertFalse($organizationProfile->getShowAdherentList());
+    /**
+     * If the organization principal type is ARTISTIC_EDUCATION_ONLY, then showAdherentList should be set to false
+     */
+    public function testCreateOrganizationProfileWithoutAdherentListBecauseOfPrincipalType(): void
+    {
+        $organizationProfileCreator = $this->getMockBuilder(OrganizationProfileCreator::class)
+            ->setConstructorArgs([$this->module, $this->tree, $this->organizationUtils])
+            ->setMethodsExcept(['createCompleteOrganizationProfile'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organizationProfile = $this->getMockBuilder(OrganizationProfile::class)->getMock();
+        $organizationProfileCreator->method('createLightOrganizationProfile')->with($organization)->willReturn($organizationProfile);
+
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $organization->method('getParameters')->willReturn($parameters);
+
+        $parameters->method('getShowAdherentList')->willReturn(true);
+        $organization->method('getPrincipalType')->willReturn(PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY()->getValue());
+        $organizationProfile->expects(self::once())->method('setShowAdherentList')->with(false);
+
+        $organization->method('getNetworkOrganizations')->willReturn(new ArrayCollection([]));
+        $this->tree->method('findAllParentsAndSortByType')->willReturn([]);
+
+        $organizationProfileCreator->createCompleteOrganizationProfile($organization);
+
     }
 
-    public function testCreateOrganizationProfileWithAdherentList(){
-        $this->organization->setPrincipalType(PrincipalTypeEnum::ARTISTIC_PRACTICE_ONLY());
-        $organizationProfile = $this->organizationProfileCreator->createCompleteOrganizationProfile($this->organization);
-        $this->assertTrue($organizationProfile->getShowAdherentList());
+    /**
+     * If the parameters::showAdherentList is false, then organizationProfile::showAdherentList should be set to false
+     */
+    public function testCreateOrganizationProfileWithoutAdherentList(): void
+    {
+        $organizationProfileCreator = $this->getMockBuilder(OrganizationProfileCreator::class)
+            ->setConstructorArgs([$this->module, $this->tree, $this->organizationUtils])
+            ->setMethodsExcept(['createCompleteOrganizationProfile'])
+            ->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organizationProfile = $this->getMockBuilder(OrganizationProfile::class)->getMock();
+        $organizationProfileCreator->method('createLightOrganizationProfile')->with($organization)->willReturn($organizationProfile);
+
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $organization->method('getParameters')->willReturn($parameters);
+
+        $parameters->method('getShowAdherentList')->willReturn(false);
+        $organization->method('getPrincipalType')->willReturn(PrincipalTypeEnum::LOCAL_FEDERATION()->getValue());
+        $organizationProfile->expects(self::once())->method('setShowAdherentList')->with(false);
+
+        $organization->method('getNetworkOrganizations')->willReturn(new ArrayCollection([]));
+        $this->tree->method('findAllParentsAndSortByType')->willReturn([]);
+
+        $organizationProfileCreator->createCompleteOrganizationProfile($organization);
     }
 }

+ 130 - 78
tests/Service/Organization/UtilsTest.php

@@ -1,121 +1,168 @@
-<?php
+<?php /** @noinspection PhpUnhandledExceptionInspection */
+
 namespace App\Test\Service\Organization;
 
 use App\Entity\Organization\Organization;
 use App\Entity\Organization\Parameters;
 use App\Entity\Organization\Settings;
+use App\Enum\Organization\OrganizationIdsEnum;
 use App\Enum\Organization\SettingsProductEnum;
-use App\Service\Organization\Utils;
 use App\Service\Organization\Utils as OrganizationUtils;
 use PHPUnit\Framework\TestCase;
 
-class UtilsTest extends TestCase
-{
-    private OrganizationUtils $organizationUtils;
-    private Organization $organization;
-    private Organization $federation;
-
-    public function setUp():void
-    {
-        $settings = new Settings();
-        $settings->setProduct(SettingsProductEnum::ARTIST_PREMIUM());
-        $this->organization = new Organization();
-        $this->organization->setSettings($settings);
-
-        $settings = new Settings();
-        $settings->setProduct(SettingsProductEnum::MANAGER());
-        $this->federation = new Organization();
-        $this->federation->setSettings($settings);
-
-        $this->organizationUtils = new OrganizationUtils();
+class TestableOrganizationUtils extends OrganizationUtils {
+    public function isOrganizationIdEqualTo(Organization $organization, OrganizationIdsEnum $organizationIdsEnum): bool {
+        return parent::isOrganizationIdEqualTo($organization, $organizationIdsEnum);
     }
+}
 
+class UtilsTest extends TestCase
+{
     /**
      * @see OrganizationUtils::isStructure()
      */
-    public function testIsStructureTest(){
-        $this->assertTrue($this->organizationUtils->isStructure($this->organization));
+    public function testIsStructure(): void
+    {
+        $organizationUtils = $this->getMockBuilder(TestableOrganizationUtils::class)->setMethodsExcept(['isStructure'])->getMock();
+
+        $settings = $this->getMockBuilder(Settings::class)->getMock();
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getSettings')->willReturn($settings);
+
+        // Each cal to 'isStructure' provoke 2 calls on getProduct
+        $settings->method('getProduct')->willReturnOnConsecutiveCalls(
+            SettingsProductEnum::ARTIST()->getValue(),
+            SettingsProductEnum::ARTIST()->getValue(),
+            SettingsProductEnum::ARTIST_PREMIUM()->getValue(),
+            SettingsProductEnum::ARTIST_PREMIUM()->getValue(),
+            SettingsProductEnum::SCHOOL()->getValue(),
+            SettingsProductEnum::SCHOOL()->getValue(),
+            SettingsProductEnum::SCHOOL_PREMIUM()->getValue(),
+            SettingsProductEnum::SCHOOL_PREMIUM()->getValue(),
+            SettingsProductEnum::MANAGER()->getValue(),
+            SettingsProductEnum::MANAGER()->getValue(),
+            SettingsProductEnum::MANAGER_PREMIUM()->getValue(),
+            SettingsProductEnum::MANAGER_PREMIUM()->getValue(),
+        );
+
+        $this->assertTrue($organizationUtils->isStructure($organization));
+        $this->assertTrue($organizationUtils->isStructure($organization));
+        $this->assertTrue($organizationUtils->isStructure($organization));
+        $this->assertTrue($organizationUtils->isStructure($organization));
+        $this->assertFalse($organizationUtils->isStructure($organization));
+        $this->assertFalse($organizationUtils->isStructure($organization));
     }
 
     /**
      * @see OrganizationUtils::isStructure()
      */
-    public function testIsNotStructureTest(){
-        $this->assertFalse($this->organizationUtils->isStructure($this->federation));
+    public function testIsManager(): void
+    {
+        $organizationUtils = $this->getMockBuilder(TestableOrganizationUtils::class)->setMethodsExcept(['isManager'])->getMock();
+
+        $settings = $this->getMockBuilder(Settings::class)->getMock();
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getSettings')->willReturn($settings);
+
+        $settings->method('getProduct')->willReturnOnConsecutiveCalls(
+            SettingsProductEnum::ARTIST()->getValue(),
+            SettingsProductEnum::ARTIST_PREMIUM()->getValue(),
+            SettingsProductEnum::SCHOOL()->getValue(),
+            SettingsProductEnum::SCHOOL_PREMIUM()->getValue(),
+            SettingsProductEnum::MANAGER()->getValue(),
+            SettingsProductEnum::MANAGER_PREMIUM()->getValue(),
+        );
+
+        $this->assertFalse($organizationUtils->isManager($organization));
+        $this->assertFalse($organizationUtils->isManager($organization));
+        $this->assertFalse($organizationUtils->isManager($organization));
+        $this->assertFalse($organizationUtils->isManager($organization));
+        $this->assertTrue($organizationUtils->isManager($organization));
+        $this->assertFalse($organizationUtils->isManager($organization));
     }
 
     /**
-     * @see OrganizationUtils::isManager()
+     * @see OrganizationUtils::is2iosOrganization()
      */
-    public function testIsManagerTest(){
-        $this->assertTrue($this->organizationUtils->isManager($this->federation));
-    }
+    public function testIsOrganizationIs2ios(): void
+    {
+        $organizationUtils = $this->getMockBuilder(TestableOrganizationUtils::class)->setMethodsExcept(['is2iosOrganization'])->getMock();
 
-    /**
-     * @see OrganizationUtils::isManager()
-     */
-    public function testIsNotManagerTest(){
-        $this->assertFalse($this->organizationUtils->isManager($this->organization));
-    }
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
 
-    /**
-     * @see OrganizationUtils::isOrganizationIs2ios()
-     */
-    public function testIsOrganizationIs2ios(){
-        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
-        $organizationMock
-            ->method('getId')
-            ->willReturn(32366);
-        $this->assertTrue($this->organizationUtils->isOrganizationIs2ios($organizationMock));
+        $organizationUtils->expects(self::once())->method('isOrganizationIdEqualTo')->with($organization, OrganizationIdsEnum::_2IOS());
+
+        $organizationUtils->is2iosOrganization($organization);
     }
 
     /**
-     * @see OrganizationUtils::isOrganizationIs2ios()
+     * @see OrganizationUtils::isOrganizationCMF()
      */
-    public function testIsNotOrganizationIs2ios(){
-        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
-        $organizationMock
-            ->method('getId')
-            ->willReturn(1);
-        $this->assertFalse($this->organizationUtils->isOrganizationIs2ios($organizationMock));
+    public function testIsOrganizationIsCMF(): void
+    {
+        $organizationUtils = $this->getMockBuilder(TestableOrganizationUtils::class)->setMethodsExcept(['isOrganizationCMF'])->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+
+        $organizationUtils->expects(self::once())->method('isOrganizationIdEqualTo')->with($organization, OrganizationIdsEnum::CMF());
+
+        $organizationUtils->isOrganizationCMF($organization);
     }
 
+
     /**
-     * @see OrganizationUtils::isOrganizationIsCMF()
+     * @see OrganizationUtils::is2iosOrganization()
      */
-    public function testIsOrganizationIsCMF(){
-        $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
-        $organizationMock
-            ->method('getId')
-            ->willReturn(12097);
-        $this->assertTrue($this->organizationUtils->isOrganizationIsCMF($organizationMock));
+    public function testIsOrganizationIdEqualTo(): void
+    {
+        $organizationUtils = $this->getMockBuilder(TestableOrganizationUtils::class)->setMethodsExcept(['isOrganizationIdEqualTo'])->getMock();
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getId')->willReturnOnConsecutiveCalls(123, OrganizationIdsEnum::_2IOS()->getValue());
+
+        $this->assertFalse($organizationUtils->isOrganizationIdEqualTo($organization, OrganizationIdsEnum::_2IOS()));
+        $this->assertTrue($organizationUtils->isOrganizationIdEqualTo($organization, OrganizationIdsEnum::_2IOS()));
     }
 
     /**
      * @see OrganizationUtils::getOrganizationCurrentActivityYear()
      */
-    public function testGetOrganizationCurrentActivityYear(){
-        $parameters = new Parameters();
-        $parameters->setMusicalDate(new \DateTime('2020-09-01'));
-        $this->organization->setParameters($parameters);
+    public function testGetOrganizationCurrentActivityYear(): void
+    {
+        $organizationUtils = $this->getMockBuilder(TestableOrganizationUtils::class)->setMethodsExcept(['getOrganizationCurrentActivityYear'])->getMock();
+
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $parameters->method('getMusicalDate')->willReturn(new \DateTime('2020-09-01'));
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getParameters')->willReturn($parameters);
 
         $today = new \DateTime('now');
-        if($today->format('m') < 9)
-            $this->assertEquals( ($today->format('Y') - 1), $this->organizationUtils->getOrganizationCurrentActivityYear($this->organization));
-        else
-            $this->assertEquals($today->format('Y'), $this->organizationUtils->getOrganizationCurrentActivityYear($this->organization));
+        $expected = (int)$today->format('Y');
+        if ((int)$today->format('m') < 9) {
+            --$expected;
+        }
+
+        $this->assertEquals(
+            $expected,
+            $organizationUtils->getOrganizationCurrentActivityYear($organization)
+        );
     }
 
     /**
      * @see OrganizationUtils::getActivityPeriodsSwitchYear()
      */
-    public function testGetActivityPeriodsSwitchYear(){
-        $parameters = new Parameters();
-        $parameters->setMusicalDate(new \DateTime('2020-09-05'));
-        $this->organization->setParameters($parameters);
+    public function testGetActivityPeriodsSwitchYear(): void
+    {
+        $organizationUtils = $this->getMockBuilder(TestableOrganizationUtils::class)->setMethodsExcept(['getActivityPeriodsSwitchYear'])->getMock();
+
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $parameters->method('getMusicalDate')->willReturn(new \DateTime('2020-09-05'));
 
-        $organizationUtils = new \App\Service\Organization\Utils();
-        $periods = $organizationUtils->getActivityPeriodsSwitchYear($this->organization, 2022);
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getParameters')->willReturn($parameters);
+
+        $periods = $organizationUtils->getActivityPeriodsSwitchYear($organization, 2022);
 
         $this->assertEquals('2022-09-05', $periods['dateStart']);
         $this->assertEquals('2023-09-04', $periods['dateEnd']);
@@ -124,12 +171,17 @@ class UtilsTest extends TestCase
     /**
      * @see OrganizationUtils::getActivityYearSwitchDate()
      */
-    public function testgetActivityYearSwitchDate(){
-        $parameters = new Parameters();
-        $parameters->setMusicalDate(new \DateTime('2020-09-05'));
-        $this->organization->setParameters($parameters);
+    public function testgetActivityYearSwitchDate(): void
+    {
+        $organizationUtils = $this->getMockBuilder(TestableOrganizationUtils::class)->setMethodsExcept(['getActivityYearSwitchDate'])->getMock();
+
+        $parameters = $this->getMockBuilder(Parameters::class)->getMock();
+        $parameters->method('getMusicalDate')->willReturn(new \DateTime('2020-09-05'));
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getParameters')->willReturn($parameters);
 
-        $this->assertEquals(2022, $this->organizationUtils->getActivityYearSwitchDate($this->organization, new \DateTime('2022-09-10')));
-        $this->assertEquals(2021, $this->organizationUtils->getActivityYearSwitchDate($this->organization, new \DateTime('2022-09-02')));
+        $this->assertEquals(2022, $organizationUtils->getActivityYearSwitchDate($organization, new \DateTime('2022-09-10')));
+        $this->assertEquals(2021, $organizationUtils->getActivityYearSwitchDate($organization, new \DateTime('2022-09-02')));
     }
 }

+ 34 - 21
tests/Service/Rest/ApiRequestServiceTest.php

@@ -19,10 +19,11 @@ class ApiRequestServiceTest extends TestCase
         $this->client = $this->getMockBuilder(HttpClientInterface::class)->disableOriginalConstructor()->getMock();
     }
 
-    public function testGetJsonContent() {
+    public function testGetJsonContent(): void
+    {
         $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
             ->setConstructorArgs([$this->client])
-            ->onlyMethods(['getContent'])
+            ->setMethodsExcept(['getJsonContent'])
             ->getMock();
 
         $apiRequestService->expects(self::once())
@@ -35,10 +36,11 @@ class ApiRequestServiceTest extends TestCase
         $this->assertEquals(['foo' => 'bar'], $data);
     }
 
-    public function testGetContent() {
+    public function testGetContent(): void
+    {
         $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
             ->setConstructorArgs([$this->client])
-            ->onlyMethods(['get'])
+            ->setMethodsExcept(['getContent'])
             ->getMock();
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
@@ -54,10 +56,11 @@ class ApiRequestServiceTest extends TestCase
         $this->assertEquals('{foo: bar}', $content);
     }
 
-    public function testGetContentWithError() {
+    public function testGetContentWithError(): void
+    {
         $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
             ->setConstructorArgs([$this->client])
-            ->onlyMethods(['get'])
+            ->setMethodsExcept(['getContent'])
             ->getMock();
 
         $apiRequestService->expects(self::once())
@@ -68,10 +71,11 @@ class ApiRequestServiceTest extends TestCase
         $apiRequestService->getContent('path/to/data');
     }
 
-    public function testGet() {
+    public function testGet(): void
+    {
         $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
             ->setConstructorArgs([$this->client])
-            ->onlyMethods(['request'])
+            ->setMethodsExcept(['get'])
             ->getMock();
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
@@ -86,10 +90,11 @@ class ApiRequestServiceTest extends TestCase
         $this->assertEquals($response, $actualResponse);
     }
 
-    public function testPost() {
+    public function testPost(): void
+    {
         $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
             ->setConstructorArgs([$this->client])
-            ->onlyMethods(['request'])
+            ->setMethodsExcept(['post'])
             ->getMock();
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
@@ -104,10 +109,11 @@ class ApiRequestServiceTest extends TestCase
         $this->assertEquals($response, $actualResponse);
     }
 
-    public function testPut() {
+    public function testPut(): void
+    {
         $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
             ->setConstructorArgs([$this->client])
-            ->onlyMethods(['request'])
+            ->setMethodsExcept(['put'])
             ->getMock();
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
@@ -122,10 +128,11 @@ class ApiRequestServiceTest extends TestCase
         $this->assertEquals($response, $actualResponse);
     }
 
-    public function testDelete() {
+    public function testDelete(): void
+    {
         $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
             ->setConstructorArgs([$this->client])
-            ->onlyMethods(['request'])
+            ->setMethodsExcept(['delete'])
             ->getMock();
 
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
@@ -140,24 +147,30 @@ class ApiRequestServiceTest extends TestCase
         $this->assertEquals($response, $actualResponse);
     }
 
-    public function testRequest() {
-        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+    public function testRequest(): void
+    {
+        $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['request'])
+            ->getMock();
 
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $this->client->expects(self::once())->method('request')->with('GET', 'path/to/data?param=1', [])->willReturn($response);
 
-        $apiRequestService = new ApiRequestService($this->client);
-
         $actualResponse = $apiRequestService->request('GET', 'path/to/data', ['param' => 1]);
 
         $this->assertEquals($response, $actualResponse);
     }
 
-    public function testRequestWithError() {
+    public function testRequestWithError(): void
+    {
+        $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['request'])
+            ->getMock();
 
         $this->client->expects(self::once())->method('request')->willThrowException(new TransportException('error', 500));
 
-        $apiRequestService = new ApiRequestService($this->client);
-
         $this->expectException(HttpException::class);
         $apiRequestService->request('GET', 'path/to/data');
     }

+ 19 - 13
tests/Service/Rest/Operation/BaseRestOperationTest.php

@@ -20,7 +20,8 @@ class BaseRestOperationTest extends TestCase
             ->getMock();
     }
 
-    public function testGetters() {
+    public function testGetters(): void
+    {
         $operation = new TestableBaseRestOperation(
             'a label',
             'GET',
@@ -43,11 +44,12 @@ class BaseRestOperationTest extends TestCase
     /**
      * Test execution with a valid request
      */
-    public function testExecuteValid()
+    public function testExecuteValid(): void
     {
-        $operation = new TestableBaseRestOperation(
-            'Update entity 1', 'PUT', 'entity/1', [], [], ['json' => '{"a":1}']
-        );
+        $operation = $this->getMockBuilder(TestableBaseRestOperation::class)
+            ->setConstructorArgs(['Update entity 1', 'PUT', 'entity/1', [], [], ['json' => '{"a":1}']])
+            ->setMethodsExcept(['execute', 'getStatus', 'getErrorMessage'])
+            ->getMock();
 
         $responseOk = $this->getMockBuilder(ResponseInterface::class)->getMock();
         $responseOk->method('getStatusCode')->willReturn(200);
@@ -59,6 +61,7 @@ class BaseRestOperationTest extends TestCase
             ->willReturn($responseOk);
 
         $operation->execute($this->apiRequestService);
+
         $this->assertEquals(BaseRestOperation::STATUS_DONE, $operation->getStatus());
         $this->assertEquals("", $operation->getErrorMessage());
     }
@@ -66,11 +69,12 @@ class BaseRestOperationTest extends TestCase
     /**
      * Test execution with an invalid request (api returns an error 404 for example)
      */
-    public function testExecuteInvalid()
+    public function testExecuteInvalid(): void
     {
-        $operation = new TestableBaseRestOperation(
-            'Update entity 1', 'PUT', 'entity/2'
-        );
+        $operation = $this->getMockBuilder(TestableBaseRestOperation::class)
+            ->setConstructorArgs(['Update entity 1', 'PUT', 'entity/2'])
+            ->setMethodsExcept(['execute', 'getStatus', 'getErrorMessage'])
+            ->getMock();
 
         $responseError = $this->getMockBuilder(ResponseInterface::class)->getMock();
         $responseError->method('getStatusCode')->willReturn(404);
@@ -93,10 +97,12 @@ class BaseRestOperationTest extends TestCase
     /**
      * Test execution if the request throw an HTTP exception
      */
-    public function testExecutionError() {
-        $operation = new TestableBaseRestOperation(
-            'Update entity 1', 'PUT', 'entity/3'
-        );
+    public function testExecutionError(): void
+    {
+        $operation = $this->getMockBuilder(TestableBaseRestOperation::class)
+            ->setConstructorArgs(['Update entity 1', 'PUT', 'entity/3'])
+            ->setMethodsExcept(['execute', 'getStatus', 'getErrorMessage'])
+            ->getMock();
 
         $responseException = $this->getMockBuilder(ResponseInterface::class)->getMock();
         $responseException->method('getStatusCode')->willReturn(500);

+ 4 - 2
tests/Service/Rest/Operation/CreateOperationTest.php

@@ -5,7 +5,8 @@ use PHPUnit\Framework\TestCase;
 
 class CreateOperationTest extends TestCase
 {
-    public function testGetters() {
+    public function testGetters(): void
+    {
         $operation = new CreateOperation(
             'Create a dinosaur',
             'dinosaur',
@@ -20,7 +21,8 @@ class CreateOperationTest extends TestCase
         $this->assertEquals('POST dinosaur', (string)$operation);
     }
 
-    public function testGetChangeLog() {
+    public function testGetChangeLog(): void
+    {
         $operation = new CreateOperation(
             'Create a dinosaur',
             'dinosaur',

+ 24 - 10
tests/Service/Security/ModuleTest.php

@@ -8,10 +8,11 @@ use App\Service\Utils\Reflection;
 use Doctrine\Common\Collections\ArrayCollection;
 use PHPUnit\Framework\TestCase;
 use App\Service\Security\Module;
+use App\Service\Cotisation\Utils as CotisationUtils;
 
 class ModuleTest extends TestCase
 {
-    const OPENTALENT_CONFIG = __DIR__.'/../../../config/opentalent';
+    private const OPENTALENT_CONFIG = __DIR__.'/../../../config/opentalent';
 
     private Reflection $reflectionMock;
     private Parser $parser;
@@ -22,10 +23,11 @@ class ModuleTest extends TestCase
         $this->parser = new Parser();
     }
 
-    public function testGetOrganizationModules() {
+    public function testGetOrganizationModules(): void
+    {
         $module = $this->getMockBuilder(Module::class)
-            ->onlyMethods(['getModuleBySettings', 'getModulesByConditions', 'getModulesByProductConfiguration'])
-            ->disableOriginalConstructor()
+            ->setConstructorArgs([$this->reflectionMock, $this->parser, self::OPENTALENT_CONFIG])
+            ->setMethodsExcept(['getOrganizationModules'])
             ->getMock();
 
         $module->expects(self::once())->method('getModuleBySettings')->willReturn(['Sms']);
@@ -48,7 +50,12 @@ class ModuleTest extends TestCase
     /**
      * @see Module::getModuleBySettings()
      */
-    public function testGetModuleBySettings(){
+    public function testGetModuleBySettings(): void
+    {
+        $module = $this->getMockBuilder(Module::class)
+            ->setConstructorArgs([$this->reflectionMock, $this->parser, self::OPENTALENT_CONFIG])
+            ->setMethodsExcept(['getModuleBySettings'])
+            ->getMock();
 
         $settingsMock = $this->getMockBuilder(Settings::class)->getMock();
         $settingsMock
@@ -62,7 +69,6 @@ class ModuleTest extends TestCase
             ->method('getSettings')
             ->willReturn($settingsMock);
 
-        $module = new Module($this->reflectionMock, $this->parser, self::OPENTALENT_CONFIG);
         $value = "Sms";
         // assert function to test whether 'value' is a value of array
         $this->assertContains($value, $module->getModuleBySettings($organizationMock)) ;
@@ -71,20 +77,24 @@ class ModuleTest extends TestCase
     /**
      * @see Module::getModulesByConditions()
      */
-    public function testGetModulesByConditions()
+    public function testGetModulesByConditions(): void
     {
+        $module = $this->getMockBuilder(Module::class)
+            ->setConstructorArgs([$this->reflectionMock, $this->parser, self::OPENTALENT_CONFIG])
+            ->setMethodsExcept(['getModulesByConditions'])
+            ->getMock();
+
         $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
         $this->reflectionMock
             ->method('dynamicInvokeServiceWithArgsAndMethod')
             ->withConsecutive(
-                ['App\\Service\\Cotisation\\Utils', 'isLastParentAndCMF', array($organizationMock)]
+                [CotisationUtils::class, 'isLastParentAndCMF', array($organizationMock)]
             )
             ->willReturnOnConsecutiveCalls(
                 [true]
             )
         ;
 
-        $module = new Module($this->reflectionMock, $this->parser, self::OPENTALENT_CONFIG);
         $value = "CotisationCall";
         // assert function to test whether 'value' is a value of array
         $this->assertContains($value, $module->getModulesByConditions($organizationMock)) ;
@@ -95,7 +105,11 @@ class ModuleTest extends TestCase
      */
     public function testGetModulesByProductConfiguration()
     {
-        $module = new Module($this->reflectionMock, $this->parser, self::OPENTALENT_CONFIG);
+        $module = $this->getMockBuilder(Module::class)
+            ->setConstructorArgs([$this->reflectionMock, $this->parser, self::OPENTALENT_CONFIG])
+            ->setMethodsExcept(['getModulesByProductConfiguration'])
+            ->getMock();
+
         $value = "MessagesAdvanced";
         // assert function to test whether 'value' is a value of array
         $this->assertContains($value, $module->getModulesByProductConfiguration('artist-premium')) ;

+ 19 - 22
tests/Service/Security/SwitchUserTest.php

@@ -8,41 +8,38 @@ use PHPUnit\Framework\TestCase;
 
 class SwitchUserTest extends TestCase
 {
-    public function setUp():void
-    {
-    }
-
     /**
      * @see SwitchUser::isAllowedToSwitch()
      */
-    public function testIsAllowedToSwitch(){
-        $childrenMockMock = $this->getMockBuilder(Access::class)->getMock();
+    public function testIsAllowedToSwitch(): void
+    {
+        // Cannot mock SwitchUser because of https://github.com/sebastianbergmann/phpunit/issues/3886
+        $switchUser = new SwitchUser();
 
-        $children = new ArrayCollection();
-        $children->add($childrenMockMock);
+        $children = $this->getMockBuilder(Access::class)->getMock();
 
-        $userMockMock = $this->getMockBuilder(Access::class)->getMock();
-        $userMockMock
-            ->expects($this->once())
-            ->method('getChildren')
-            ->willReturn($children);
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $user->method('getChildren')
+            ->willReturn(new ArrayCollection([$children]));
 
-        $switchUser = new SwitchUser();
-        $this->assertTrue($switchUser->isAllowedToSwitch($userMockMock, $childrenMockMock));
+        $this->assertTrue($switchUser->isAllowedToSwitch($user, $children));
     }
 
     /**
      * @see SwitchUser::isAllowedToSwitch()
      */
-    public function testIsNotAllowedToSwitch(){
-        $childrenMockMock = $this->getMockBuilder(Access::class)->getMock();
-        $userMockMock = $this->getMockBuilder(Access::class)->getMock();
-        $userMockMock
+    public function testIsNotAllowedToSwitch(): void
+    {
+        // Cannot mock SwitchUser because of https://github.com/sebastianbergmann/phpunit/issues/3886
+        $switchUser = new SwitchUser();
+
+        $children = $this->getMockBuilder(Access::class)->getMock();
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $user
             ->expects($this->once())
             ->method('getChildren')
             ->willReturn(new ArrayCollection());
 
-        $switchUser = new SwitchUser();
-        $this->assertFalse($switchUser->isAllowedToSwitch($userMockMock, $childrenMockMock));
+        $this->assertFalse($switchUser->isAllowedToSwitch($user, $children));
     }
-}
+}

+ 7 - 2
tests/Service/ServiceIterator/CurrentAccessExtensionIteratorTest.php

@@ -7,7 +7,8 @@ use PHPUnit\Framework\TestCase;
 
 class CurrentAccessExtensionIteratorTest extends TestCase
 {
-    public function testAddWhere() {
+    public function testAddWhere(): void
+    {
         $queryBuilder = $this->getMockBuilder(QueryBuilder::class)
             ->disableOriginalConstructor()
             ->getMock();
@@ -26,7 +27,11 @@ class CurrentAccessExtensionIteratorTest extends TestCase
 
         $extensions = [$ext1, $ext2, $ext3];
 
-        $iterator = new CurrentAccessExtensionIterator($extensions);
+        $iterator = $this->getMockBuilder(CurrentAccessExtensionIterator::class)
+            ->setConstructorArgs([$extensions])
+            ->setMethodsExcept(['addWhere'])
+            ->getMock();
+
         $actualExt = $iterator->addWhere($queryBuilder, 'foo');
 
         $this->assertEquals(true, $actualExt);

+ 13 - 4
tests/Service/ServiceIterator/EncoderIteratorTest.php

@@ -6,7 +6,8 @@ use PHPUnit\Framework\TestCase;
 
 class EncoderIteratorTest extends TestCase
 {
-    public function testGetEncoderFor() {
+    public function testGetEncoderFor(): void
+    {
         $mocker = $this->getMockBuilder(EncoderInterface::class);
 
         $encoder1 = $mocker->getMock();
@@ -20,13 +21,18 @@ class EncoderIteratorTest extends TestCase
 
         $encoders = [$encoder1, $encoder2, $encoder3];
 
-        $iterator = new EncoderIterator($encoders);
+        $iterator = $this->getMockBuilder(EncoderIterator::class)
+            ->setConstructorArgs([$encoders])
+            ->setMethodsExcept(['getEncoderFor'])
+            ->getMock();
+
         $actualEncoder = $iterator->getEncoderFor('pdf');
 
         $this->assertEquals($encoder2, $actualEncoder);
     }
 
-    public function testGetEncoderForError() {
+    public function testGetEncoderForError(): void
+    {
         $mocker = $this->getMockBuilder(EncoderInterface::class);
 
         $encoder1 = $mocker->getMock();
@@ -37,7 +43,10 @@ class EncoderIteratorTest extends TestCase
 
         $encoders = [$encoder1, $encoder2];
 
-        $iterator = new EncoderIterator($encoders);
+        $iterator = $this->getMockBuilder(EncoderIterator::class)
+            ->setConstructorArgs([$encoders])
+            ->setMethodsExcept(['getEncoderFor'])
+            ->getMock();
 
         $this->expectException(Exception::class);
         $iterator->getEncoderFor('gif');

+ 13 - 4
tests/Service/ServiceIterator/ExporterIteratorTest.php

@@ -9,7 +9,8 @@ use PHPUnit\Framework\TestCase;
 
 class ExporterIteratorTest extends TestCase
 {
-    public function testGetExporterFor() {
+    public function testGetExporterFor(): void
+    {
         $exportRequest = $this->getMockBuilder(ExportRequest::class)
             ->disableOriginalConstructor()
             ->getMock();
@@ -27,13 +28,18 @@ class ExporterIteratorTest extends TestCase
 
         $exporters = [$exporter1, $exporter2, $exporter3];
 
-        $iterator = new ExporterIterator($exporters);
+        $iterator = $this->getMockBuilder(ExporterIterator::class)
+            ->setConstructorArgs([$exporters])
+            ->setMethodsExcept(['getExporterFor'])
+            ->getMock();
+
         $actualExporter = $iterator->getExporterFor($exportRequest);
 
         $this->assertEquals($exporter2, $actualExporter);
     }
 
-    public function testGetExporterForError() {
+    public function testGetExporterForError(): void
+    {
         $exportRequest = $this->getMockBuilder(ExportRequest::class)
             ->disableOriginalConstructor()
             ->getMock();
@@ -48,7 +54,10 @@ class ExporterIteratorTest extends TestCase
 
         $exporters = [$exporter1, $exporter2];
 
-        $iterator = new ExporterIterator($exporters);
+        $iterator = $this->getMockBuilder(ExporterIterator::class)
+            ->setConstructorArgs([$exporters])
+            ->setMethodsExcept(['getExporterFor'])
+            ->getMock();
 
         $this->expectException(Exception::class);
         $iterator->getExporterFor($exportRequest);

+ 29 - 7
tests/Service/ServiceIterator/OptionalsRolesIteratorTest.php

@@ -7,10 +7,9 @@ use PHPUnit\Framework\TestCase;
 
 class OptionalsRolesIteratorTest extends TestCase
 {
-    public function testAddWhere() {
-        $access = $this->getMockBuilder(Access::class)
-            ->disableOriginalConstructor()
-            ->getMock();
+    public function testAddWhere(): void
+    {
+        $access = $this->getMockBuilder(Access::class)->getMock();
 
         $mocker = $this->getMockBuilder(OptionalsRolesInterface::class);
 
@@ -30,14 +29,37 @@ class OptionalsRolesIteratorTest extends TestCase
 
         $roles = [$role1, $role2, $role3, $role4];
 
-        $iterator = new OptionalsRolesIterator($roles);
+        $iterator = $this->getMockBuilder(OptionalsRolesIterator::class)
+            ->setConstructorArgs([$roles])
+            ->setMethodsExcept(['getOptionalsRoles'])
+            ->getMock();
+
         $actualRoles = $iterator->getOptionalsRoles($access);
 
         $this->assertEquals(['ROLE2', 'ROLE4'], $actualRoles);
 
-        $roles = [$role1, $role3];
 
-        $iterator = new OptionalsRolesIterator($roles);
+    }
+
+    public function testAddWhereNotFound(): void
+    {
+        $access = $this->getMockBuilder(Access::class)->getMock();
+
+        $mocker = $this->getMockBuilder(OptionalsRolesInterface::class);
+
+        $role1 = $mocker->getMock();
+        $role1->method('support')->willReturn(false);
+
+        $role2 = $mocker->getMock();
+        $role2->method('support')->willReturn(false);
+
+        $roles = [$role1, $role2];
+
+        $iterator = $this->getMockBuilder(OptionalsRolesIterator::class)
+            ->setConstructorArgs([$roles])
+            ->setMethodsExcept(['getOptionalsRoles'])
+            ->getMock();
+
         $actualRoles = $iterator->getOptionalsRoles($access);
 
         $this->assertEquals([], $actualRoles);

+ 7 - 2
tests/Service/Storage/TemporaryFileStorageTest.php

@@ -8,7 +8,8 @@ use PHPUnit\Framework\TestCase;
 
 class TemporaryFileStorageTest extends TestCase
 {
-    public function testGetStorageBaseDir() {
+    public function testGetStorageBaseDir(): void
+    {
         $fileSystemMap = $this->getMockBuilder(FilesystemMap::class)
             ->disableOriginalConstructor()
             ->getMock();
@@ -23,7 +24,11 @@ class TemporaryFileStorageTest extends TestCase
         $fileSystem->method('getAdapter')->willReturn($adapter);
         $adapter->expects($this->once())->method('write')->willReturnSelf();
 
-        $storage = new TemporaryFileStorage($fileSystemMap);
+        $storage = $this->getMockBuilder(TemporaryFileStorage::class)
+            ->setConstructorArgs([$fileSystemMap])
+            ->setMethodsExcept(['write'])
+            ->getMock();
+
         $path = $storage->write('my_file.txt', 'some content');
 
         $this->assertMatchesRegularExpression(

+ 48 - 29
tests/Service/Typo3/Typo3ServiceTest.php

@@ -1,4 +1,4 @@
-<?php
+<?php /** @noinspection PhpUnhandledExceptionInspection */
 
 namespace App\Test\Service\Typo3;
 
@@ -29,14 +29,18 @@ class Typo3ServiceTest extends TestCase
             ->with('GET', '/typo3/index.php?route=foo&param=bar')
             ->willReturn($response);
 
-        $typo3Service = new TestableTypo3Service($this->typo3Client);
+        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
+            ->setConstructorArgs([$this->typo3Client])
+            ->setMethodsExcept(['sendCommand'])
+            ->getMock();
 
         $typo3Service->sendCommand('foo', ['param' => 'bar']);
     }
 
-    public function testCreateSite() {
-        $typo3Service = $this->getMockBuilder(Typo3Service::class)
-            ->onlyMethods(['sendCommand'])
+    public function testCreateSite(): void
+    {
+        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
+            ->setMethodsExcept(['createSite'])
             ->disableOriginalConstructor()
             ->getMock();
 
@@ -49,12 +53,14 @@ class Typo3ServiceTest extends TestCase
         $typo3Service->createSite(1);
     }
 
-    public function testClearSiteCache() {
-        $typo3Service = $this->getMockBuilder(Typo3Service::class)
-            ->onlyMethods(['sendCommand'])
+    public function testClearSiteCache(): void
+    {
+        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
+            ->setMethodsExcept(['updateSite'])
             ->disableOriginalConstructor()
             ->getMock();
 
+
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
             ->method('sendCommand')->
@@ -64,12 +70,14 @@ class Typo3ServiceTest extends TestCase
         $typo3Service->updateSite(1);
     }
 
-    public function testDeleteSite() {
-        $typo3Service = $this->getMockBuilder(Typo3Service::class)
-            ->onlyMethods(['sendCommand'])
+    public function testDeleteSite(): void
+    {
+        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
+            ->setMethodsExcept(['deleteSite'])
             ->disableOriginalConstructor()
             ->getMock();
 
+
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
             ->method('sendCommand')->
@@ -79,12 +87,14 @@ class Typo3ServiceTest extends TestCase
         $typo3Service->deleteSite(1);
     }
 
-    public function testUndeleteSite() {
-        $typo3Service = $this->getMockBuilder(Typo3Service::class)
-            ->onlyMethods(['sendCommand'])
+    public function testUndeleteSite(): void
+    {
+        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
+            ->setMethodsExcept(['undeleteSite'])
             ->disableOriginalConstructor()
             ->getMock();
 
+
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
             ->method('sendCommand')->
@@ -94,12 +104,14 @@ class Typo3ServiceTest extends TestCase
         $typo3Service->undeleteSite(1);
     }
 
-    public function testSetSiteDomain() {
-        $typo3Service = $this->getMockBuilder(Typo3Service::class)
-            ->onlyMethods(['sendCommand'])
+    public function testSetSiteDomain(): void
+    {
+        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
+            ->setMethodsExcept(['setSiteDomain'])
             ->disableOriginalConstructor()
             ->getMock();
 
+
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
             ->method('sendCommand')->
@@ -109,12 +121,14 @@ class Typo3ServiceTest extends TestCase
         $typo3Service->setSiteDomain(1, 'new-domain', false);
     }
 
-    public function testSetSiteDomainWithRedirection() {
-        $typo3Service = $this->getMockBuilder(Typo3Service::class)
-            ->onlyMethods(['sendCommand'])
+    public function testSetSiteDomainWithRedirection(): void
+    {
+        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
+            ->setMethodsExcept(['setSiteDomain'])
             ->disableOriginalConstructor()
             ->getMock();
 
+
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
             ->method('sendCommand')->
@@ -124,12 +138,14 @@ class Typo3ServiceTest extends TestCase
         $typo3Service->setSiteDomain(1, 'new-domain', true);
     }
 
-    public function testResetSitePerms() {
-        $typo3Service = $this->getMockBuilder(Typo3Service::class)
-            ->onlyMethods(['sendCommand'])
+    public function testResetSitePerms(): void
+    {
+        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
+            ->setMethodsExcept(['resetSitePerms'])
             ->disableOriginalConstructor()
             ->getMock();
 
+
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
             ->method('sendCommand')->
@@ -139,12 +155,14 @@ class Typo3ServiceTest extends TestCase
         $typo3Service->resetSitePerms(1);
     }
 
-    public function testGetSiteStatus() {
-        $typo3Service = $this->getMockBuilder(Typo3Service::class)
-            ->onlyMethods(['sendCommand'])
+    public function testGetSiteStatus(): void
+    {
+        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
+            ->setMethodsExcept(['getSiteStatus'])
             ->disableOriginalConstructor()
             ->getMock();
 
+
         $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
         $typo3Service->expects(self::once())
             ->method('sendCommand')->
@@ -154,9 +172,10 @@ class Typo3ServiceTest extends TestCase
         $typo3Service->getSiteStatus(1);
     }
 
-    public function testAddRedirection() {
-        $typo3Service = $this->getMockBuilder(Typo3Service::class)
-            ->onlyMethods(['sendCommand'])
+    public function testAddRedirection(): void
+    {
+        $typo3Service = $this->getMockBuilder(TestableTypo3Service::class)
+            ->setMethodsExcept(['addRedirection'])
             ->disableOriginalConstructor()
             ->getMock();
 

+ 9 - 7
tests/Service/Utils/ArrayUtilsTest.php

@@ -9,10 +9,12 @@ class ArrayUtilsTest extends TestCase
 {
     public function testGetChanges(): void
     {
+        $arrayUtils = new ArrayUtils();
+
         // Non-recursive (default)
         $this->assertEquals(
             ['b' => -2, 'c' => ['d' => 4, 'e' => ['f' => -5]], 'g' => 7],
-            ArrayUtils::getChanges(
+            $arrayUtils->getChanges(
                 ['a' => 1, 'b' => 2, 'c' => ['d' => 4, 'e' => ['f' => 5]]],
                 ['a' => 1, 'b' => -2, 'c' => ['d' => 4, 'e' => ['f' => -5]], 'g' => 7],
             )
@@ -21,7 +23,7 @@ class ArrayUtilsTest extends TestCase
         // Recursive
         $this->assertEquals(
             ['b' => -2, 'c' => ['e' => ['f' => -5]], 'g' => 7],
-            ArrayUtils::getChanges(
+            $arrayUtils->getChanges(
                 ['a' => 1, 'b' => 2, 'c' => ['d' => 4, 'e' => ['f' => 5]]],
                 ['a' => 1, 'b' => -2, 'c' => ['d' => 4, 'e' => ['f' => -5]], 'g' => 7],
                 true
@@ -31,7 +33,7 @@ class ArrayUtilsTest extends TestCase
         // Recursive with unchanged sub array
         $this->assertEquals(
             ['b' => -2],
-            ArrayUtils::getChanges(
+            $arrayUtils->getChanges(
                 ['a' => 1, 'b' => 2, 'c' => ['d' => 4, 'e' => ['f' => 5]]],
                 ['a' => 1, 'b' => -2, 'c' => ['d' => 4, 'e' => ['f' => 5]]],
                 true
@@ -41,7 +43,7 @@ class ArrayUtilsTest extends TestCase
         // No changes
         $this->assertEquals(
             [],
-            ArrayUtils::getChanges(
+            $arrayUtils->getChanges(
                 ['a' => 1, 'b' => 2, 'c' => ['d' => 4, 'e' => ['f' => 5]]],
                 ['a' => 1, 'b' => 2, 'c' => ['d' => 4, 'e' => ['f' => 5]]],
             )
@@ -50,7 +52,7 @@ class ArrayUtilsTest extends TestCase
         // Empty arrays
         $this->assertEquals(
             [],
-            ArrayUtils::getChanges(
+            $arrayUtils->getChanges(
                 [],
                 [],
             )
@@ -59,7 +61,7 @@ class ArrayUtilsTest extends TestCase
         // First array is empty
         $this->assertEquals(
             ['a' => 1],
-            ArrayUtils::getChanges(
+            $arrayUtils->getChanges(
                 [],
                 ['a' => 1],
             )
@@ -68,7 +70,7 @@ class ArrayUtilsTest extends TestCase
         // With callback
         $this->assertEquals(
             ['a' => 2],
-            ArrayUtils::getChanges(
+            $arrayUtils->getChanges(
                 ['a' => 1, 'b' => ''],
                 ['a' => 2, 'b' => null],
                 false,

+ 106 - 34
tests/Service/Utils/GpsCoordinateUtilsTest.php

@@ -7,14 +7,19 @@ use PHPUnit\Framework\TestCase;
 use Symfony\Component\HttpClient\MockHttpClient;
 use Symfony\Component\HttpClient\Response\MockResponse;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
+use Symfony\Contracts\HttpClient\ResponseInterface;
 
 class GpsCoordinateUtilsTest extends TestCase
 {
+    private HttpClientInterface $client;
     private string $response;
     private string $responseReverse;
 
     public function setUp(): void
     {
+        $this->client = $this->getMockBuilder(HttpClientInterface::class)->disableOriginalConstructor()->getMock();
+
         $this->response = '[{"place_id":124047700,"licence":"Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright","osm_type":"way","osm_id":146744176,"boundingbox":["46.040309","46.0413942","6.584711","6.5864561"],"lat":"46.0405718","lon":"6.5857964","display_name":"Chemin des Rirets, La Frasse, Romme, Nancy-sur-Cluses, Bonneville, Haute-Savoie, Auvergne-Rhône-Alpes, France métropolitaine, 74300, France","place_rank":26,"category":"highway","type":"residential","importance":0.8099999999999999}]';
         $this->responseReverse = '{"place_id":124302276,"licence":"Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright","osm_type":"way","osm_id":146744171,"lat":"46.04082792421903","lon":"6.585562827387761","place_rank":26,"category":"highway","type":"unclassified","importance":0.09999999999999998,"addresstype":"road","name":"Chemin des Larrets","display_name":"Chemin des Larrets, La Frasse, Romme, Nancy-sur-Cluses, Bonneville, Haute-Savoie, Auvergne-Rhône-Alpes, France métropolitaine, 74300, France","address":{"road":"Chemin des Larrets","hamlet":"La Frasse","village":"Romme","municipality":"Bonneville","county":"Haute-Savoie","state":"Auvergne-Rhône-Alpes","country":"France","postcode":"74300","country_code":"fr"},"boundingbox":["46.0404896","46.040881","6.585013","6.5874704"]}';
     }
@@ -24,15 +29,26 @@ class GpsCoordinateUtilsTest extends TestCase
      */
     public function testSearchGpsCoordinates():void
     {
-        $responses = [new MockResponse($this->response, ['http_code' => 200])];
-        $client = new MockHttpClient($responses, 'https://nominatim.openstreetmap.org/');
+        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['searchGpsCoordinates'])
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->getMock();
+        $response->method('getContent')->willReturn('{"data":1}');  // dummy response data
+
+        $this->client
+            ->expects(self::once())
+            ->method('request')
+            ->with(
+                'GET',
+                'search?addressdetails=1&format=json&limit=10&street=11 chemin des rirtes&postalcode=74300&city=nancy-sur-cluses'
+            )
+            ->willReturn($response);
 
-        $gpsCoordinateUtils = new GpsCoordinateUtils($client);
         $content = $gpsCoordinateUtils->searchGpsCoordinates('11 chemin des rirtes', '74300', 'nancy-sur-cluses');
 
-        $this->assertIsArray($content);
-        $this->assertCount(1, $content);
-        $this->assertEquals("Chemin des Rirets, La Frasse, Romme, Nancy-sur-Cluses, Bonneville, Haute-Savoie, Auvergne-Rhône-Alpes, France métropolitaine, 74300, France", $content[0]['display_name']);
+        $this->assertEquals(['data' => 1], $content);
     }
 
     /**
@@ -40,10 +56,16 @@ class GpsCoordinateUtilsTest extends TestCase
      */
     public function testSearchGpsCoordinatesFailed():void
     {
-        $responses = [new MockResponse('...', ['http_code' => 404])];
-        $client = new MockHttpClient($responses, 'https://nominatim.openstreetmap.org/');
+        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['searchGpsCoordinates'])
+            ->getMock();
+
+        $this->client
+            ->expects(self::once())
+            ->method('request')
+            ->willThrowException(new \Exception());
 
-        $gpsCoordinateUtils = new GpsCoordinateUtils($client);
         $this->expectException(NotFoundHttpException::class);
         $gpsCoordinateUtils->searchGpsCoordinates('...', '74300', '...');
     }
@@ -53,15 +75,25 @@ class GpsCoordinateUtilsTest extends TestCase
      */
     public function testReverseGpsCoordinates():void
     {
-        $responses = [new MockResponse($this->responseReverse, ['http_code' => 200])];
-        $client = new MockHttpClient($responses, 'https://nominatim.openstreetmap.org/');
+        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['reverseGpsCoordinates'])
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->getMock();
+        $response->method('getContent')->willReturn('{"data":1}');  // dummy response data
+
+        $this->client
+            ->expects(self::once())
+            ->method('request')
+            ->with(
+                'GET',
+                'reverse?addressdetails=1&format=json&lat=46.040851602664&lon=6.58558355'
+            )
+            ->willReturn($response);
 
-        $gpsCoordinateUtils = new GpsCoordinateUtils($client);
         $content = $gpsCoordinateUtils->reverseGpsCoordinates(46.04085160266434, 6.585583549999978);
-
-        $this->assertIsArray($content);
-        $this->assertArrayHasKey('place_id', $content);
-        $this->assertEquals("Chemin des Larrets, La Frasse, Romme, Nancy-sur-Cluses, Bonneville, Haute-Savoie, Auvergne-Rhône-Alpes, France métropolitaine, 74300, France", $content['display_name']);
+        $this->assertEquals(['data' => 1], $content);
     }
 
     /**
@@ -69,10 +101,16 @@ class GpsCoordinateUtilsTest extends TestCase
      */
     public function testReverseGpsCoordinatesFailed():void
     {
-        $responses = [new MockResponse('...', ['http_code' => 404])];
-        $client = new MockHttpClient($responses, 'https://nominatim.openstreetmap.org/');
+        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['reverseGpsCoordinates'])
+            ->getMock();
+
+        $this->client
+            ->expects(self::once())
+            ->method('request')
+            ->willThrowException(new \Exception());
 
-        $gpsCoordinateUtils = new GpsCoordinateUtils($client);
         $this->expectException(NotFoundHttpException::class);
         $gpsCoordinateUtils->reverseGpsCoordinates(0000, 0000);
     }
@@ -82,11 +120,37 @@ class GpsCoordinateUtilsTest extends TestCase
      */
     public function testCreateGpsCoordinate():void
     {
-        $responses = [new MockResponse('...', ['http_code' => 200])];
-        $client = new MockHttpClient($responses, 'https://nominatim.openstreetmap.org/');
-
-        $gpsCoordinateUtils = new GpsCoordinateUtils($client);
-        $this->assertInstanceOf(GpsCoordinate::class, $gpsCoordinateUtils->createGpsCoordinate(json_decode($this->responseReverse, true)));
+        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['createGpsCoordinate'])
+            ->getMock();
+
+        $gpsApiResponse = [
+            'address' => ['foo'],
+            'lat' => 123.4,
+            'lon' => 456.7,
+        ];
+
+        $gpsCoordinateUtils
+            ->expects(self::once())
+            ->method('transformAddress')
+            ->with(['foo'])
+            ->willReturn(
+                [
+                    'city' => 'bar',
+                    'cp' => '12345',
+                    'streetAddress' => '1 rue lambda',
+                    'streetAddressSecond' => 'cedex 1'
+                ]
+            );
+
+        $gpsCoordinate = $gpsCoordinateUtils->createGpsCoordinate($gpsApiResponse);
+
+        $this->assertEquals(123.4, $gpsCoordinate->getLatitude());
+        $this->assertEquals(456.7, $gpsCoordinate->getLongitude());
+        $this->assertEquals('bar', $gpsCoordinate->getCity());
+        $this->assertEquals('1 rue lambda', $gpsCoordinate->getStreetAddress());
+        $this->assertEquals('cedex 1', $gpsCoordinate->getStreetAddressSecond());
     }
 
     /**
@@ -94,17 +158,25 @@ class GpsCoordinateUtilsTest extends TestCase
      */
     public function testTransformAddress():void
     {
-        $responses = [new MockResponse('...', ['http_code' => 200])];
-        $client = new MockHttpClient($responses, 'https://nominatim.openstreetmap.org/');
+        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['transformAddress'])
+            ->getMock();
+
+        $arrayAddress = [
+            'road' => 'foo',
+            'hamlet' => 'bar',
+            'town' => 'alpha',
+            'postcode' => '12345'
+        ];
+
+        $addressTransformed = $gpsCoordinateUtils->transformAddress($arrayAddress);
 
-        $gpsCoordinateUtils = new GpsCoordinateUtils($client);
-        $arrayAddress = json_decode($this->responseReverse, true);
-        $addressTransformed = $gpsCoordinateUtils->transformAddress($arrayAddress['address']);
         $this->assertEquals([
-              "streetAddress" => "Chemin des Larrets",
-              "streetAddressSecond" => "La Frasse",
-              "city" => "Romme",
-              "cp" => "74300"
+              "streetAddress" => "foo",
+              "streetAddressSecond" => "bar",
+              "city" => "alpha",
+              "cp" => "12345"
             ], $addressTransformed);
     }
-}
+}

+ 42 - 14
tests/Service/Utils/SiretTest.php

@@ -1,32 +1,60 @@
-<?php
+<?php /** @noinspection PhpUnhandledExceptionInspection */
+
 namespace App\Tests\Service\Utils;
 
 use App\Service\Utils\Siret;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\HttpClient\MockHttpClient;
 use Symfony\Component\HttpClient\Response\MockResponse;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
+use Symfony\Contracts\HttpClient\ResponseInterface;
 
 class SiretTest extends TestCase
 {
+    private HttpClientInterface $client;
+
+    public function setUp(): void
+    {
+        $this->client = $this->getMockBuilder(HttpClientInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+
     /**
-     * @see Siret::isSiretIsCorrect()
+     * @see Siret::isSiretCorrect()
      */
-    public function testIsSiretIsCorrect():void
+    public function testIsSiretCorrect():void
     {
-        $responses = [new MockResponse('...', ['http_code' => 200])];
-        $client = new MockHttpClient($responses, 'https://entreprise.data.gouv.fr/api/sirene/v3/etablissements/');
-        $siret = new Siret($client);
-        $this->assertTrue($siret->isSiretIsCorrect('50465312200052'));
+        $siret = $this->getMockBuilder(Siret::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['isSiretCorrect'])
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->getMock();
+        $response->method('getStatusCode')->willReturn(200);
+
+        $this->client->expects(self::once())->method('request')->willReturn($response);
+
+        $this->assertTrue(
+            $siret->isSiretCorrect('50465312200052')
+        );
     }
 
     /**
-     * @see Siret::isSiretIsCorrect()
+     * @see Siret::isSiretCorrect()
      */
-    public function testIsNotSiretIsCorrect():void
+    public function testIsNotSiretCorrect():void
     {
-        $responses = [new MockResponse('...', ['http_code' => 404])];
-        $client = new MockHttpClient($responses, 'https://entreprise.data.gouv.fr/api/sirene/v3/etablissements/');
-        $siret = new Siret($client);
-        $this->assertFalse($siret->isSiretIsCorrect('50465312200052'));
+        $siret = $this->getMockBuilder(Siret::class)
+            ->setConstructorArgs([$this->client])
+            ->setMethodsExcept(['isSiretCorrect'])
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->getMock();
+        $response->method('getStatusCode')->willReturn(404);
+
+        $this->client->expects(self::once())->method('request')->willReturn($response);
+
+        $this->assertFalse($siret->isSiretCorrect('50465312200052'));
     }
-}
+}

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików