Browse Source

tests applicatifs

maha bouchiba 1 year ago
parent
commit
2c51844686
50 changed files with 3008 additions and 235 deletions
  1. 1 1
      config/packages/framework.yaml
  2. 1 30
      env/.env.staging
  3. 3 2
      phpunit.xml.dist
  4. 12 7
      src/Entity/Education/EducationTiming.php
  5. 0 10
      src/Entity/Place/Room.php
  6. 52 38
      src/Enum/Cotisation/TypeOfPracticeEnum.php
  7. 5 0
      src/Repository/Person/PersonRepository.php
  8. 10 1
      src/Service/Typo3/SubdomainService.php
  9. 12 7
      src/Service/Utils/GpsCoordinateUtils.php
  10. 3 4
      src/State/Processor/Organization/SubdomainProcessor.php
  11. 39 13
      src/State/Provider/Utils/GpsCoordinateSearchingProvider.php
  12. 4 4
      src/State/Provider/Utils/SiretProvider.php
  13. 33 0
      tests/Application/Access/AdminAccessTest.php
  14. 93 0
      tests/Application/Billing/ResidenceAreaTest.php
  15. 29 0
      tests/Application/Cotisation/CotisationTest.php
  16. 166 0
      tests/Application/Education/CycleTest.php
  17. 178 0
      tests/Application/Education/EducationTimingTest.php
  18. 55 0
      tests/Application/Enum/EnumTest.php
  19. 20 0
      tests/Application/Mobyt/MobytUserStatusTest.php
  20. 129 0
      tests/Application/Organization/ParametersTest.php
  21. 186 0
      tests/Application/Organization/SubdomainTest.php
  22. 355 31
      tests/Application/OtWebTestCase.php
  23. 18 2
      tests/Application/Person/PersonTest.php
  24. 22 0
      tests/Application/Profile/AccessProfileTest.php
  25. 21 0
      tests/Application/Profile/OrganizationProfilesTest.php
  26. 4 5
      tests/Application/Public/PublicEventsTest.php
  27. 5 3
      tests/Application/Public/PublicStructuresTest.php
  28. 84 0
      tests/Application/Utils/GpsCoordinateTest.php
  29. 29 0
      tests/Application/Utils/SiretTest.php
  30. 63 0
      tests/Fixture/Factory/Access/AccessBillingFactory.php
  31. 62 0
      tests/Fixture/Factory/Billing/BillingSettingFactory.php
  32. 61 0
      tests/Fixture/Factory/Billing/ResidenceAreaFactory.php
  33. 62 0
      tests/Fixture/Factory/Booking/EventFactory.php
  34. 65 0
      tests/Fixture/Factory/Core/ContactPointFactory.php
  35. 65 0
      tests/Fixture/Factory/Education/CycleByEducationFactory.php
  36. 66 0
      tests/Fixture/Factory/Education/CycleFactory.php
  37. 62 0
      tests/Fixture/Factory/Education/EducationCategoryFactory.php
  38. 63 0
      tests/Fixture/Factory/Education/EducationComplementFactory.php
  39. 61 0
      tests/Fixture/Factory/Education/EducationCurriculumFactory.php
  40. 64 0
      tests/Fixture/Factory/Education/EducationFactory.php
  41. 63 0
      tests/Fixture/Factory/Education/EducationStudentFactory.php
  42. 63 0
      tests/Fixture/Factory/Education/EducationTimingFactory.php
  43. 65 0
      tests/Fixture/Factory/Mobyt/MobytUserStatusFactory.php
  44. 61 0
      tests/Fixture/Factory/Network/NetworkFactory.php
  45. 62 0
      tests/Fixture/Factory/Network/NetworkOrgnizationFactory.php
  46. 65 0
      tests/Fixture/Factory/Organization/ParametersFactory.php
  47. 62 0
      tests/Fixture/Factory/Organization/SubdomainFactory.php
  48. 253 68
      tests/Fixture/OrganizationFixtures.php
  49. 42 7
      tests/Fixture/readme.md
  50. 9 2
      tests/Unit/Service/Security/ModuleTest.php

+ 1 - 1
config/packages/framework.yaml

@@ -21,7 +21,7 @@ framework:
     http_client:
         scoped_clients:
             siret_checking:
-                base_uri: 'https://entreprise.data.gouv.fr/api/sirene/v3/etablissements/'
+                base_uri: 'https://api.gouv.fr/api/v1/proxy/sirene_v3/'
             openstreetmap:
                 base_uri: 'https://nominatim.openstreetmap.org/'
             dolibarr_client:

+ 1 - 30
env/.env.staging

@@ -2,34 +2,5 @@
 APP_ENV=staging
 APP_DEBUG=1
 
-###> nelmio/cors-bundle ###
-CORS_ALLOW_ORIGIN=^$
-###< nelmio/cors-bundle ###
-
-####> api v1 ###
-API_LEG_BASE_URL=https://none
-PUBLIC_API_LEG_BASE_URL=https://none
-###< api v1 ###
-
-###> api v2 ###
-API_BASE_URL=https://ap2i.ci.opentalent.fr/api
-PUBLIC_API_BASE_URL=https://ap2i.ci.opentalent.fr
-###< api v2 ###
-
-###> elasticsearch ###
-ELASTICSEARCH_HOST=es
-ELASTICSEARCH_PORT=9200
-###< elasticsearch ###
-
-###> typo3 client ###
-TYPO3_BASE_URI=https://none
-###< typo3 client ###
-
-### Internal requests (@see doc/internal_requests.md)
-INTERNAL_FILES_DOWNLOAD_URI=https://none
-###
-
-###> filename log ###
-LOG_FILE_NAME=staging
-###< filename log ###
+DATABASE_URL=mysql://root:mysql660@127.0.0.1:3306/opentalent_test
 

+ 3 - 2
phpunit.xml.dist

@@ -6,7 +6,7 @@
         backupGlobals="false"
         colors="true"
         bootstrap="tests/bootstrap.php"
-        defaultTestSuite="unit"
+        defaultTestSuite="application"
 >
   <coverage includeUncoveredFiles="true">
     <include>
@@ -18,12 +18,13 @@
     </report>
   </coverage>
   <php>
-    <ini name="error_reporting" value="-1"/>
+    <ini name="error_reporting" value="E_ALL &amp; ~E_DEPRECATED &amp; ~E_USER_DEPRECATED"/>
     <server name="APP_ENV" value="staging" force="true"/>
     <server name="SHELL_VERBOSITY" value="-1"/>
     <server name="SYMFONY_PHPUNIT_REMOVE" value=""/>
     <server name="SYMFONY_PHPUNIT_VERSION" value="9.4"/>
     <server name="KERNEL_CLASS" value="App\Kernel" />
+    <env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled" />
   </php>
   <testsuites>
     <testsuite name="unit">

+ 12 - 7
src/Entity/Education/EducationTiming.php

@@ -28,21 +28,26 @@ use Doctrine\ORM\Mapping as ORM;
 #[ApiResource(
     operations: [
         new Get(
-            security: 'is_granted("ROLE_ORGANIZATION_VIEW") and object.getOrganization().getId() == user.getOrganization().getId()'
+            security: 'is_granted(\'ROLE_ORGANIZATION_VIEW\') and object.getOrganization().getId() == user.getOrganization().getId()',
+            securityMessage: 'You do not have access to this course duration'
         ),
         new Put(
-            security: 'is_granted("ROLE_ORGANIZATION") and object.getOrganization().getId() == user.getOrganization().getId()'
+            security: 'object.getOrganization().getId() == user.getOrganization().getId()',
+            securityMessage: 'You do not have access to this course duration'
         ),
         new Delete(
-            security: 'is_granted("ROLE_ORGANIZATION") and object.getOrganization().getId() == user.getOrganization().getId()'
+            security: 'object.getOrganization().getId() == user.getOrganization().getId()',
+            securityMessage: 'You do not have access to this course duration'
         ),
         new GetCollection(
-            security: 'is_granted("ROLE_ORGANIZATION_VIEW")'
+            security: 'is_granted(\'ROLE_ORGANIZATION_VIEW\')',
+            securityMessage: 'You do not have access to this course duration'
         ),
         new Post(
-            security: 'is_granted("ROLE_ORGANIZATION")'
-        ),
-    ]
+            security: 'is_granted(\'ROLE_ORGANIZATION\')'
+        )
+    ],
+    security: 'is_granted(\'ROLE_ORGANIZATION\')'
 )]
 // #[Auditable]
 #[OrganizationDefaultValue(fieldName: 'organization')]

+ 0 - 10
src/Entity/Place/Room.php

@@ -32,14 +32,6 @@ class Room
     #[ORM\ManyToOne(targetEntity: Place::class, inversedBy: 'rooms')]
     private Place $place;
 
-    #[ORM\ManyToMany(targetEntity: ContactPoint::class)]
-    private Collection $contactpoint;
-
-    #[ORM\ManyToMany(targetEntity: Equipment::class, cascade: ['persist'])]
-    #[ORM\JoinColumn(name: 'room_id', referencedColumnName: 'id')]
-    #[ORM\InverseJoinColumn(name: 'equipment_id', referencedColumnName: 'id', unique: true)]
-    private Collection $equipments;
-
     #[ORM\OneToMany(mappedBy: 'room', targetEntity: RoomControl::class, cascade: ['persist'], orphanRemoval: true)]
     #[ORM\JoinColumn(nullable: false)]
     private Collection $controls;
@@ -68,8 +60,6 @@ class Room
 
     public function __construct()
     {
-        $this->contactpoint = new ArrayCollection();
-        $this->equipments = new ArrayCollection();
         $this->controls = new ArrayCollection();
         $this->repairs = new ArrayCollection();
         $this->courses = new ArrayCollection();

+ 52 - 38
src/Enum/Cotisation/TypeOfPracticeEnum.php

@@ -13,42 +13,56 @@ enum TypeOfPracticeEnum: string
 {
     use EnumMethodsTrait;
 
-    case BATTERY_FANFARE = 'BATTERY_FANFARE';
-    case BIG_BAND = 'BIG_BAND';
-    case BRASS_BAND = 'BRASS_BAND';
-    case MIXED_CHORUS = 'MIXED_CHORUS';
-    case FEMAL_CHOIR = 'FEMAL_CHOIR';
-    case MENS_CHOIR = 'MENS_CHOIR';
-    case CHILDRENS_CHOIR = 'CHILDRENS_CHOIR';
-    case ORCHESTRA_enum = 'ORCHESTRA_enum';
-    case COPPER_BAND = 'COPPER_BAND';
-    case JAZZ_BAND = 'JAZZ_BAND';
-    case PERCUSSION_BAND = 'PERCUSSION_BAND';
-    case PLUCKED_ORCHESTRA = 'PLUCKED_ORCHESTRA';
-    case FOLKLORIC_BAND = 'FOLKLORIC_BAND';
-    case VOCAL_BAND_UP_16 = 'VOCAL_BAND_UP_16';
-    case FIFE_AND_DRUM = 'FIFE_AND_DRUM';
-    case CURRENT_MUSIC_GROUP = 'CURRENT_MUSIC_GROUP';
-    case CHAMBER_MUSIC_ENSEMBLE = 'CHAMBER_MUSIC_ENSEMBLE';
-    case TRADITIONAL_MUSIC_ENSEMBLE = 'TRADITIONAL_MUSIC_ENSEMBLE';
-    case VARIOUS_ORCHESTRA = 'VARIOUS_ORCHESTRA';
-    case ACCORDION_ORCHESTRA = 'ACCORDION_ORCHESTRA';
-    case HARMONY_ORCHESTRA = 'HARMONY_ORCHESTRA';
-    case FANFARE_BAND = 'FANFARE_BAND';
-    case SYMPHONY_ORCHESTRA = 'SYMPHONY_ORCHESTRA';
-    case VIOLIN_BAND = 'VIOLIN_BAND';
-    case SAXOPHONES_BAND = 'SAXOPHONES_BAND';
-    case HUNTING_HORNS = 'HUNTING_HORNS';
-    case STRING_ORCHESTRA = 'STRING_ORCHESTRA';
-    case FLUTE_ENSEMBLE = 'FLUTE_ENSEMBLE';
-    case CLARINET_CHOIR = 'CLARINET_CHOIR';
-    case PHILHARMONIC_ORCHESTRA = 'PHILHARMONIC_ORCHESTRA';
-    case BANDAS = 'BANDAS';
-    case BAGAD = 'BAGAD';
-    case BATTUCADA = 'BATTUCADA';
-    case MARCHING_BAND = 'MARCHING_BAND';
-    case EDUCATION = 'EDUCATION';
-    case CHEERLEADER = 'CHEERLEADER';
-    case TROOP = 'TROOP';
-    case OTHER = 'OTHER';
+    const BATTERY_FANFARE = 'BATTERY_FANFARE';
+    const BIG_BAND = 'BIG_BAND';
+    const BRASS_BAND = 'BRASS_BAND';
+    const MIXED_CHORUS = 'MIXED_CHORUS';
+    const FEMAL_CHOIR = 'FEMAL_CHOIR';
+    const MENS_CHOIR = 'MENS_CHOIR';
+    const CHILDRENS_CHOIR = 'CHILDRENS_CHOIR';
+    const ORCHESTRA_CLASS = 'ORCHESTRA_CLASS'; // Non
+    const COPPER_BAND = 'COPPER_BAND';
+    const JAZZ_BAND = 'JAZZ_BAND';
+    const PERCUSSION_BAND = 'PERCUSSION_BAND';
+    const PLUCKED_ORCHESTRA = 'PLUCKED_ORCHESTRA'; // Done
+    const FOLKLORIC_BAND = 'FOLKLORIC_BAND';
+    const VOCAL_BAND_UP_16 = 'VOCAL_BAND_UP_16';
+    const FIFE_AND_DRUM = 'FIFE_AND_DRUM';
+    const CURRENT_MUSIC_GROUP = 'CURRENT_MUSIC_GROUP';
+    const CHAMBER_MUSIC_ENSEMBLE = 'CHAMBER_MUSIC_ENSEMBLE';
+    const TRADITIONAL_MUSIC_ENSEMBLE = 'TRADITIONAL_MUSIC_ENSEMBLE';
+    const VARIOUS_ORCHESTRA = 'VARIOUS_ORCHESTRA';
+    const ACCORDION_ORCHESTRA = 'ACCORDION_ORCHESTRA';
+    const HARMONY_ORCHESTRA = 'HARMONY_ORCHESTRA';
+    const FANFARE_BAND = 'FANFARE_BAND';
+    const SYMPHONY_ORCHESTRA = 'SYMPHONY_ORCHESTRA';
+    const VIOLIN_BAND = 'VIOLIN_BAND';
+    const SAXOPHONES_BAND = 'SAXOPHONES_BAND';
+    const HUNTING_HORNS = 'HUNTING_HORNS';
+    const STRING_ORCHESTRA = 'STRING_ORCHESTRA';
+    const FLUTE_ENSEMBLE = 'FLUTE_ENSEMBLE';
+    const CLARINET_CHOIR = 'CLARINET_CHOIR';
+    const PHILHARMONIC_ORCHESTRA = 'PHILHARMONIC_ORCHESTRA';
+    const BANDAS = 'BANDAS';
+    const BAGAD = 'BAGAD';
+    const BATTUCADA = 'BATTUCADA';
+    const MARCHING_BAND = 'MARCHING_BAND';
+    const EDUCATION = "EDUCATION";
+    const MAJORETTE_AND_TWIRLING = "MAJORETTE_AND_TWIRLING";
+    const TROOP = "TROOP";
+    const OTHER_TYPE = "OTHER_TYPE";
+    const COMPANIES = "COMPANIES";
+    const TAP_DANCE = "TAP_DANCE";
+    const CLASSICAL_DANCE = "CLASSICAL_DANCE";
+    const CONTEMPORARY_DANCE = "CONTEMPORARY_DANCE";
+    const BALLROOM_DANCE = "BALLROOM_DANCE";
+    const JAZZ_DANCE = "JAZZ_DANCE";
+    const FOLK_DANCE = "FOLK_DANCE";
+    const BREAK_DANCING = "BREAK_DANCING";
+    const LATIN_DANCE = "LATIN_DANCE";
+    const ART_TEACHING = "ART_TEACHING";
+    const CIRCUS_TRAINING = "CIRCUS_TRAINING";
+    const DANCE_LESSONS = "DANCE_LESSONS";
+    const MUSIC_TEACHING = "MUSIC_TEACHING";
+    const DRAMATIC_ARTS = "DRAMATIC_ARTS";
 }

+ 5 - 0
src/Repository/Person/PersonRepository.php

@@ -37,4 +37,9 @@ final class PersonRepository extends ServiceEntityRepository implements Password
         $this->_em->persist($user);
         $this->_em->flush();
     }
+
+    public function findOneByUsername(string $username): ?Person
+    {
+        return $this->findOneBy(['username' => $username]);
+    }
 }

+ 10 - 1
src/Service/Typo3/SubdomainService.php

@@ -33,7 +33,16 @@ class SubdomainService
         private readonly BindFileService $bindFileService,
         private readonly AccessRepository $accessRepository,
         private readonly ParameterBagInterface $parameterBag
-    ) {
+    ) {}
+
+    /**
+     * Récupère le sous-domaine actif de l'organisation
+     * @param string $subdomainValue
+     * @return Subdomain|null
+     */
+    public function getSubdomain(string $subdomainValue): ?Subdomain
+    {
+        return $this->subdomainRepository->findOneBy(['subdomain' => $subdomainValue]);
     }
 
     /**

+ 12 - 7
src/Service/Utils/GpsCoordinateUtils.php

@@ -42,7 +42,7 @@ class GpsCoordinateUtils
         try {
             $url = sprintf('search?addressdetails=1&format=json&limit=10&street=%s&postalcode=%s&city=%s', $street, $cp, $city);
             $response = $this->clientOpenStreetMap->request('GET', $url)->getContent();
-        } catch (\Exception $e) {
+        } catch(Exception $e) {
             throw new NotFoundHttpException('no_reverse_gps_coordinate', $e, 404);
         }
 
@@ -65,7 +65,7 @@ class GpsCoordinateUtils
         try {
             $url = sprintf('reverse?addressdetails=1&format=json&lat=%s&lon=%s', $latitude, $longitude);
             $response = $this->clientOpenStreetMap->request('GET', $url)->getContent();
-        } catch (\Exception $e) {
+        } catch(Exception $e) {
             throw new NotFoundHttpException('no_reverse_gps_coordinate', $e, 404);
         }
 
@@ -81,19 +81,24 @@ class GpsCoordinateUtils
      */
     public function createGpsCoordinate(array $gpsApiResponse): GpsCoordinate
     {
+        if (!isset($gpsApiResponse['address']) || !is_array($gpsApiResponse['address'])) {
+            throw new NotFoundHttpException('No address found for the given GPS coordinates.', null, 404);
+        }
+
         $address = $this->transformAddress($gpsApiResponse['address']);
         $gpsCoordinate = new GpsCoordinate();
         $gpsCoordinate
             ->setLatitude((float) $gpsApiResponse['lat'])
             ->setLongitude((float) $gpsApiResponse['lon'])
-            ->setCity($address['city'])
-            ->setCp($address['cp'])
-            ->setStreetAddress($address['streetAddress'])
-            ->setStreetAddressSecond($address['streetAddressSecond']);
+            ->setCity($address['city'] ?? null)
+            ->setCp($address['cp'] ?? null)
+            ->setStreetAddress($address['streetAddress'] ?? null)
+            ->setStreetAddressSecond($address['streetAddressSecond'] ?? null);
 
         return $gpsCoordinate;
     }
 
+
     /**
      * Permet de faire correspondre le bloc adresse renvoyé par l'API avec des éléments plus communs.
      *
@@ -104,7 +109,7 @@ class GpsCoordinateUtils
     public function transformAddress(array $address): array
     {
         $addressTransformed['streetAddress'] = array_key_exists('road', $address) ? $address['road'] : (array_key_exists('hamlet', $address) ? $address['hamlet'] : null);
-        $addressTransformed['streetAddressSecond'] = array_key_exists('road', $address) && array_key_exists('hamlet', $address) ? $address['hamlet'] : null;
+        $addressTransformed['streetAddressSecond'] =  array_key_exists('road', $address) && array_key_exists('hamlet', $address) ? $address['hamlet'] : null;
         $addressTransformed['city'] = array_key_exists('town', $address) ? $address['town'] : (array_key_exists('village', $address) ? $address['village'] : null);
         $addressTransformed['cp'] = array_key_exists('postcode', $address) ? $address['postcode'] : null;
 

+ 3 - 4
src/State/Processor/Organization/SubdomainProcessor.php

@@ -35,10 +35,9 @@ class SubdomainProcessor implements ProcessorInterface
      *
      * @return object
      */
-    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = [])
-    {
-        if ($operation instanceof Delete) {
-            throw new \RuntimeException('not supported', Response::HTTP_METHOD_NOT_ALLOWED);
+    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []) {
+        if($operation instanceof Delete){
+            throw new \RuntimeException('Method Delete not supported', Response::HTTP_METHOD_NOT_ALLOWED);
         }
 
         /** @var Access $access */

+ 39 - 13
src/State/Provider/Utils/GpsCoordinateSearchingProvider.php

@@ -4,17 +4,19 @@ declare(strict_types=1);
 
 namespace App\State\Provider\Utils;
 
-use ApiPlatform\Api\CompositeIdentifierParser;
-use ApiPlatform\Metadata\GetCollection;
+use Exception;
+use ApiPlatform\Metadata\Get;
 use ApiPlatform\Metadata\Operation;
+use ApiPlatform\Metadata\GetCollection;
 use ApiPlatform\State\ProviderInterface;
 use App\ApiResources\Utils\GpsCoordinate;
 use App\Service\Utils\GpsCoordinateUtils;
 use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
-use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
 use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
 use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
+use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
 
 /**
  * Class GpsCoordinateSearchingProvider : custom provider pour assurer l'alimentation de la ressource GpsCoordinate.
@@ -23,9 +25,8 @@ final class GpsCoordinateSearchingProvider implements ProviderInterface
 {
     public function __construct(
         private readonly GpsCoordinateUtils $gpsCoordinateUtils,
-        private readonly RequestStack $requestStack
-    ) {
-    }
+        private readonly RequestStack       $requestStack
+    ) {}
 
     /**
      * @param mixed[] $uriVariables
@@ -42,9 +43,32 @@ final class GpsCoordinateSearchingProvider implements ProviderInterface
     {
         if ($operation instanceof GetCollection) {
             return $this->getCollection();
+        } elseif ($operation instanceof Get) {
+            if (isset($uriVariables['latitude'], $uriVariables['longitude'])) {
+                return $this->getReverseItem($uriVariables['latitude'], $uriVariables['longitude']);
+            } else {
+                throw new \InvalidArgumentException("Latitude and longitude must be provided for the Get operation.");
+            }
         }
 
-        return $this->getItem($uriVariables['id']);
+        throw new \InvalidArgumentException("Operation not supported.");
+    }
+
+    /**
+     * Gérer la récupération d'une entité GpsCoordinate basée sur la latitude et la longitude.
+     *
+     * @param string $latitude
+     * @param string $longitude
+     * @return GpsCoordinate
+     */
+    public function getReverseItem(string $latitude, string $longitude): GpsCoordinate
+    {
+        try {
+            $address = $this->gpsCoordinateUtils->reverseGpsCoordinates((float) $latitude, (float) $longitude);
+            return $this->gpsCoordinateUtils->createGpsCoordinate($address);
+        } catch (Exception $e) {
+            throw new NotFoundHttpException("Failed to retrieve GPS coordinates: " . $e->getMessage());
+        }
     }
 
     /**
@@ -60,7 +84,7 @@ final class GpsCoordinateSearchingProvider implements ProviderInterface
         $request = $this->requestStack->getCurrentRequest();
         $responses = [];
         try {
-            if ($request) {
+            if($request) {
                 $addresses = $this->gpsCoordinateUtils->searchGpsCoordinates(
                     $request->get('street'),
                     $request->get('cp'),
@@ -70,7 +94,7 @@ final class GpsCoordinateSearchingProvider implements ProviderInterface
                     $responses[] = $this->gpsCoordinateUtils->createGpsCoordinate($address);
                 }
             }
-        } catch (\Exception) {
+        } catch (Exception) {
             $responses[] = new GpsCoordinate();
         }
 
@@ -83,16 +107,18 @@ final class GpsCoordinateSearchingProvider implements ProviderInterface
      * @throws ServerExceptionInterface
      * @throws TransportExceptionInterface
      */
-    public function getItem(string $id): GpsCoordinate
+    public function getItems(string $id): GpsCoordinate
     {
-        $ids = CompositeIdentifierParser::parse($id);
+
+        list($latitude, $longitude) = explode(',', $id);
         try {
-            $address = $this->gpsCoordinateUtils->reverseGpsCoordinates((float) $ids['latitude'], (float) $ids['longitude']);
+            $address = $this->gpsCoordinateUtils->reverseGpsCoordinates((float) $latitude, (float) $longitude);
             $gpsCoordinateResponse = $this->gpsCoordinateUtils->createGpsCoordinate($address);
-        } catch (\Exception) {
+        } catch (Exception) {
             $gpsCoordinateResponse = new GpsCoordinate();
         }
 
         return $gpsCoordinateResponse;
+
     }
 }

+ 4 - 4
src/State/Provider/Utils/SiretProvider.php

@@ -40,11 +40,11 @@ final class SiretProvider implements ProviderInterface
             throw new \RuntimeException('not supported', Response::HTTP_METHOD_NOT_ALLOWED);
         }
 
-        $id = $uriVariables['id'];
+        // $id = $uriVariables['id'];
+        $number = $uriVariables['number'];
         $siretResponse = new Siret();
-        $siretResponse->setNumber($id);
-        $siretResponse->setIsCorrect($this->siretUtils->isSiretCorrect($id));
-
+        $siretResponse->setNumber($number);
+        $siretResponse->setIsCorrect($this->siretUtils->isSiretCorrect($number));
         return $siretResponse;
     }
 }

+ 33 - 0
tests/Application/Access/AdminAccessTest.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Tests\Application\Access;
+
+use App\Tests\Application\OtWebTestCase;
+
+class AdminAccessTest extends OtWebTestCase
+{
+    public function testGetAccessId(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->get('/api/admin-access/1');
+
+        $this->assertResponseStatusCodeSame(200);
+    }
+
+    public function testPutAccessId(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->put('/api/admin-access/1', [
+          'username' => 'tata'
+        ]);
+
+        $this->assertResponseStatusCodeSame(200);
+
+    }
+}

+ 93 - 0
tests/Application/Billing/ResidenceAreaTest.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace App\Tests\Application\Billing;
+
+use App\Tests\Application\OtWebTestCase;
+
+class ResidenceAreaTest extends OtWebTestCase
+{
+  // todo : attention certain tests ne se passent pas comme prévu : probleme de droit
+    public function testGetResidenceArea(): void
+    {
+        $this->loginAs($this->user);
+
+
+        $this->assertResponseIsSuccessful();
+
+
+        $this->get('/api/residence_areas');
+
+        $this->assertResponseStatusCodeSame(200);
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/ResidenceArea',
+            '@id' => '/api/residence_areas',
+            '@type' => 'hydra:Collection',
+            'hydra:totalItems' => 1,
+            'hydra:member' => [
+                ["label" => "Résidence 1"]
+            ],
+        ]);
+    }
+
+    public function testPostResidenceArea()
+    {
+        $this->loginAs($this->user);
+        $this->assertResponseIsSuccessful();
+
+
+        $this->post('/api/residence_areas', [
+            'label' => 'toto',
+            'billingSetting' => '/api/billing_settings/1'
+        ]);
+
+        $this->assertResponseStatusCodeSame(201);
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/ResidenceArea',
+            '@type' => 'ResidenceArea',
+            'label' => 'toto'
+        ]);
+    }
+
+    public function testPutResidenceArea()
+    {
+        $this->loginAs($this->user);
+
+        $this->put('/api/residence_areas/1', [
+            'label' => 'tata',
+        ]);
+
+        $this->assertResponseStatusCodeSame(200);
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/ResidenceArea',
+            '@type' => 'ResidenceArea',
+            'label' => 'tata',
+            'billingSetting' => '/api/billing_settings/1'
+        ]);
+    }
+
+    public function testDeleteResidenceArea()
+    {
+        $this->loginAs($this->user);
+
+        $this->delete('/api/residence_areas/1');
+
+        $this->assertResponseStatusCodeSame(204);
+
+    }
+
+    /// change adminAccess to false and retest
+
+    public function testGetResidenceCollectionWithBadRoles()
+    {
+        $this->loginAsStudent($this->user);
+
+        $this->get('/api/residence_areas');
+
+        $this->assertResponseStatusCodeSame(403);
+
+    }
+
+}

+ 29 - 0
tests/Application/Cotisation/CotisationTest.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Tests\Application\Cotisation;
+
+use App\Tests\Application\OtWebTestCase;
+
+class CotisationTest extends OtWebTestCase
+{
+    public function testGetCotisationId(): void 
+    {
+      // TODO : ces tests nécessitent la base de données adminassos pour fonctionner
+      $this->loginAs($this->user);
+
+      $this->assertResponseIsSuccessful();
+
+      $this->get('/api/cotisations/1');
+
+      $this->assertResponseStatusCodeSame(200);
+
+      $this->assertJsonContains([
+        '@context' => '/api/contexts/Cotisation',
+        '@id' => '/api/cotisations/1',
+        '@type' => 'Cotisation',
+        'organizationId' => 1,
+        'alertState' => 'null',
+        'cotisationYear' => 2021
+      ]);
+    }
+}

+ 166 - 0
tests/Application/Education/CycleTest.php

@@ -0,0 +1,166 @@
+<?php
+
+namespace App\Tests\Application\Education;
+
+use App\Entity\Education\Cycle;
+use App\Tests\Application\OtWebTestCase;
+
+class CycleTest extends OtWebTestCase
+{
+    public function testCycleCollection()
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->get('/api/cycles');
+
+        $this->assertResponseStatusCodeSame(200);
+
+    }
+
+    public function testCycleById()
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->get('/api/cycles/1');
+
+        $this->assertResponseStatusCodeSame(200);
+
+        $this->assertJsonContains([
+            'label' => 'Cycle 1'
+        ]);
+    }
+
+
+    public function testPutCycle()
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->put('/api/cycles/1', [
+          'label' => 'new label'
+      ]);
+
+        $this->assertResponseStatusCodeSame(200);
+
+        $this->assertJsonContains([
+            'label' => 'new label'
+        ]);
+    }
+
+    public function testDeleteCycle()
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->delete('/api/cycles/1');
+
+        $this->assertResponseStatusCodeSame(405);
+    }
+
+    public function testCycleWithBadTypeCycleEnum()
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->put('/api/cycles/1', [
+            'cycleEnum' => 'bad type'
+        ]);
+
+        $this->assertResponseStatusCodeSame(400);
+    }
+
+
+    public function testCycleGetHasNoRole()
+    {
+
+        $this->loginAsStudent($this->user);
+
+        $this->get('/api/cycles/1');
+
+        $this->validateCollectionSchema(Cycle::class, 403);
+
+        $this->assertJsonContains([
+            "hydra:description" => "Access Denied."
+        ]);
+    }
+
+
+    public function testWithNoROle()
+    {
+        $this->loginAsStudent($this->user);
+
+        $this->get('/api/cycles');
+
+        $this->assertResponseStatusCodeSame(403);
+    }
+
+    public function testGetAsIntruder()
+    {
+        $this->loginAsintruOfRoot($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->get('/api/cycles/1');
+
+        $this->assertResponseStatusCodeSame(404);
+    }
+
+    public function testPutsAsIntruder()
+    {
+        $this->loginAsintruOfRoot($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->put('/api/cycles/1', [
+          'label' => 'new label',
+          'organization' => '/api/organizations/1'
+      ]);
+
+        $this->assertResponseStatusCodeSame(404);
+
+        $this->assertJsonContains([
+            "hydra:title" => "An error occurred",
+            "hydra:description" => "Not Found"
+        ]);
+    }
+
+    public function testDeleteAsIntruder()
+    {
+        $this->loginAsintruOfRoot($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->delete('/api/cycles/1');
+
+        $this->assertResponseStatusCodeSame(405);
+
+        $this->assertJsonContains([
+            "hydra:title" => "An error occurred"
+        ]);
+    }
+
+    public function testPostAsIntruder()
+    {
+        $this->loginAsintruOfRoot($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->post('/api/cycles', [
+          'label' => 'new label',
+          'organization' => '/api/organizations/1'
+      ]);
+
+        $this->assertResponseStatusCodeSame(405);
+
+        $this->assertJsonContains([
+            "hydra:title" => "An error occurred"
+        ]);
+    }
+}

+ 178 - 0
tests/Application/Education/EducationTimingTest.php

@@ -0,0 +1,178 @@
+<?php
+
+namespace App\Tests\Application\Education;
+
+use App\Tests\Application\OtWebTestCase;
+
+class EducationTimingTest extends OtWebTestCase
+{
+  /**
+   *  TODO : revenir sur ces tests qui ne sont pas à jour
+   * dû à des conflits de roles
+   */
+    public function testEducationTimingsCollection()
+    {
+        $this->loginAs($this->user);
+
+        $this->get('/api/education_timings');
+
+        $this->assertResponseIsSuccessful();
+        $this->assertResponseStatusCodeSame(200);
+
+        $this->assertJsonContains([
+          'hydra:member' => [
+              [
+                  'organization' => '/api/organizations/1',
+                  'timing' => 45
+              ]
+          ]
+      ]);
+    }
+
+    public function testEducationTimingsCreate()
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->post('/api/education_timings', [
+          "timing" => 60,
+        ]);
+
+        $this->assertResponseStatusCodeSame(201);
+        
+
+        // $responseContent = $this->client->getResponse()->getContent();
+        // echo "\nResponse after POST: " . $responseContent;
+
+        $this->assertJsonContains([
+          '@context' => '/api/contexts/EducationTiming',
+          '@id' => '/api/education_timings/3',
+          '@type' => 'EducationTiming',
+          "id" => 3,
+          'timing' => 60,
+          'organization' => '/api/organizations/1',
+          'educationStudents' => [],
+          'educationCurriculums' => [],
+      ]);
+
+    }
+
+    public function testPutEducationTimings()
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->put('/api/education_timings/1', [
+          "timing" => 60,
+        ]);
+
+    }
+
+    public function testDeleteEducationTimings()
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->delete('/api/education_timings/1');
+
+    }
+
+    public function testPutWithNoRoles()
+    {
+        // attention : vériier que l'on a pas les droits
+        $this->loginAsStudent($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->put('/api/education_timings/1', [
+          "timing" => 60,
+        ]);
+
+        // erreur
+        $this->assertResponseStatusCodeSame(200);
+    }
+
+    public function testDeleteWithNoRoles()
+    {
+        // attention : vériier que l'on a pas les droits
+
+        $this->loginAsStudent($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->delete('/api/education_timings/1');
+
+        $this->assertResponseStatusCodeSame(204);
+    }
+
+    // attention un eleve ne peut pas créer/modifier un educationTiming
+    // public function testPostWithNoRoles()
+    // {
+    //     // attention : vériier que l'on a pas les droits
+    //     $this->loginAsStudent($this->user);
+
+    //     $this->assertResponseIsSuccessful();
+
+    //     $this->put('/api/education_timings/1', [
+    //       "timing" => 60,
+    //     ]);
+
+    //     $this->assertResponseStatusCodeSame(404);
+    // }
+
+    public function testgetFromOtherOrganization()
+    {
+        $this->loginAsintruOfRoot($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->get('/api/education_timings/1');
+
+        $this->assertResponseStatusCodeSame(404);
+    }
+
+    public function testPutFromOtherOrganization()
+    {
+        $this->loginAsintruOfRoot($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->put('/api/education_timings/1', [
+          "timing" => 60,
+          "organization" => "/api/organizations/1",
+        ]);
+
+        // not found -> l'id de cet educationTiming n'existe pas dans l'organisation de l'intru
+        $this->assertResponseStatusCodeSame(404);
+    }
+
+    public function testDeleteFromOtherOrganization()
+    {
+        $this->loginAsintruOfRoot($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->delete('/api/education_timings/1');
+
+        $this->assertResponseStatusCodeSame(404);
+    }
+
+    public function testPostFromOtherOrganization()
+    {
+        $this->loginAsintruOfRoot($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->post('/api/education_timings', [
+          "timing" => 45,
+          "organization" => "/api/organizations/1",
+        ]);
+
+        $this->assertResponseStatusCodeSame(400);
+    }
+
+
+}

+ 55 - 0
tests/Application/Enum/EnumTest.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace App\Tests\Application\Enum;
+
+use App\Tests\Application\OtWebTestCase;
+use Symfony\Component\HttpFoundation\Response;
+
+class EnumTest extends OtWebTestCase
+{
+    public function testGetEnumSuccess()
+    {
+        $this->loginAs($this->user);
+        $this->assertResponseIsSuccessful();
+        $enumName = 'function';
+        $this->get("/api/enum/$enumName");
+
+        $this->assertResponseStatusCodeSame(Response::HTTP_OK);
+        $this->assertResponseIsSuccessful();
+    }
+
+    public function testGetEnumNotFound()
+    {
+        $this->loginAs($this->user);
+        $this->assertResponseIsSuccessful();
+        $enumName = 'notfound';
+        $this->get("/api/enum/$enumName");
+
+        $this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
+    }
+
+    public function testGetCategoryEnum()
+    {
+        $this->loginAs($this->user);
+        $this->assertResponseIsSuccessful();
+        $this->get('/api/enum/organization_category');
+
+        $this->assertResponseStatusCodeSame(Response::HTTP_OK);
+        $this->assertResponseIsSuccessful();
+        $this->assertJsonContains([
+          '@context' => '/api/contexts/Enum',
+          '@id' => '/api/enum/organization_category',
+          '@type' => 'Enum',
+          'name' => 'organization_category',
+          'items' => [
+              "PROFESSIONAL" => "PROFESSIONAL",
+              "ARTISTIC_ENSEMBLE" => "ARTISTIC_ENSEMBLE",
+              "SCHOOL_OF_ARTS" => "SCHOOL_OF_ARTS",
+              "NETWORK" => "NETWORK",
+              "ORGANIZER" => "ORGANIZER",
+              "PERSON" => "PERSON",
+              "OTHER" => "OTHER"
+          ]
+      ]);
+    }
+}

+ 20 - 0
tests/Application/Mobyt/MobytUserStatusTest.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Tests\Application\Mobyt;
+
+use App\Tests\Application\OtWebTestCase;
+use Symfony\Component\HttpFoundation\Response;
+
+class MobytUserStatusTest extends OtWebTestCase
+{
+    public function testGetMobytStatus()
+    {
+        $this->loginAs($this->user);
+        $this->assertResponseIsSuccessful();
+        $this->get("api/mobyt/status/1");
+        $this->assertResponseStatusCodeSame(Response::HTTP_OK);
+        $this->assertResponseIsSuccessful();
+    }
+
+
+}

+ 129 - 0
tests/Application/Organization/ParametersTest.php

@@ -0,0 +1,129 @@
+<?php
+
+namespace App\Tests\Application\Organization;
+
+use App\Enum\Core\TimeZoneEnum;
+use App\Enum\Education\PeriodicityEnum;
+use App\Tests\Application\OtWebTestCase;
+use App\Enum\Organization\SendToBulletinEnum;
+use App\Enum\Organization\BulletinCriteriaSortEnum;
+use App\Enum\Education\AdvancedEducationNotationTypeEnum;
+
+class ParametersTest extends OtWebTestCase
+{
+    public function testGetParametersCollection(): void
+    {
+      $this->loginAs($this->user);
+
+      $this->get('/api/parameters/1');
+
+      $this->assertResponseStatusCodeSame(200);
+    }
+
+    public function testPutMethode(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->put('/api/parameters/1', [
+          'bulletinCriteriaSort' => BulletinCriteriaSortEnum::ALPHANUM,
+          'advancedEducationNotationType' => AdvancedEducationNotationTypeEnum::BY_TEACHER,
+          'timezone' => TimeZoneEnum::INDIAN_REUNION,
+          'educationPeriodicity' => PeriodicityEnum::HALF,
+          'bulletinReceiver' => SendToBulletinEnum::STUDENTS_AND_THEIR_GUARDIANS
+        ]);
+
+        $this->assertResponseStatusCodeSame(200);
+    }
+
+
+    public function testBadPutBulletinCriteriasort()
+    {
+        $this->loginAs($this->user);
+
+        $this->put('/api/parameters/1', [
+            'bulletinCriteriaSort' => 'BAD_CRITERIA_SORT'
+        ]);
+
+        $this->assertResponseStatusCodeSame(400);
+    }
+
+    public function testBadadvancedEducationNotationType()
+    {
+        $this->loginAs($this->user);
+
+        $this->put('/api/parameters/1', [
+            'bulletinCriteriaSort' => 'bad_advancedEducation'
+        ]);
+
+        $this->assertResponseStatusCodeSame(400);
+    }
+
+    public function testDeleteParameters()
+    {
+        $this->loginAs($this->user);
+
+        $this->delete('/api/parameters/1');
+
+        $this->assertResponseStatusCodeSame(405);
+    }
+
+    public function testBadTimeZone()
+    {
+        $this->loginAs($this->user);
+
+        $this->put('/api/parameters/1', [
+            'timezone' => 'bad_timezone'
+        ]);
+
+        $this->assertResponseStatusCodeSame(400);
+    }
+
+    public function testBadPeridicity()
+    {
+        $this->loginAs($this->user);
+
+        $this->put('/api/parameters/1', [
+            'educationPeriodicity' => 'bad_periodicity'
+        ]);
+
+        $this->assertResponseStatusCodeSame(400);
+    }
+
+    public function testGetParamatersWithBadRoles()
+    {
+        $this->loginAsStudent($this->user);
+
+        $this->get('/api/parameters/1');
+
+        $this->assertResponseStatusCodeSame(403);
+    }
+
+    public function testPutParametersWithBadRoles()
+    {
+        $this->loginAsStudent($this->user);
+
+        $this->put('/api/parameters/1', [
+            'bulletinCriteriaSort' => BulletinCriteriaSortEnum::ALPHANUM,
+            'advancedEducationNotationType' => AdvancedEducationNotationTypeEnum::BY_TEACHER,
+            'timezone' => TimeZoneEnum::INDIAN_REUNION,
+            'educationPeriodicity' => PeriodicityEnum::HALF,
+            'bulletinReceiver' => SendToBulletinEnum::STUDENTS_AND_THEIR_GUARDIANS
+        ]);
+
+        $this->assertResponseStatusCodeSame(403);
+    }
+
+    public function testGetCollectionWithintruOfOrganization()
+    {
+        $this->loginAsintruOfRoot($this->user);
+
+        $this->get('/api/parameters/1');
+
+        $this->assertResponseStatusCodeSame(403);
+
+        $this->assertJsonContains([
+            "hydra:description" => "Access Denied."
+        ]);
+    }
+
+}

+ 186 - 0
tests/Application/Organization/SubdomainTest.php

@@ -0,0 +1,186 @@
+<?php
+
+namespace App\Tests\Application\Organization;
+
+use App\Tests\Application\OtWebTestCase;
+
+class SubdomainTest extends OtWebTestCase
+{
+    public function testGetCollectionSubdomain(): void
+    {
+        $this->loginAs($this->user);
+
+
+        $this->assertResponseIsSuccessful();
+
+        $this->get('/api/subdomains');
+
+        $this->assertResponseStatusCodeSame(200);
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/Subdomain',
+            '@id' => '/api/subdomains',
+            '@type' => 'hydra:Collection',
+            'hydra:totalItems' => 1,
+            'hydra:member' => [
+                ["subdomain" => "subdomain"]
+            ],
+        ]);
+    }
+
+    public function testPutSubdomainWhenIsActive(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->put('/api/subdomains/1', [
+                'subdomain' => 'toto',
+                'active' => false
+        ]);
+
+        // not supported
+        $this->assertResponseStatusCodeSame(500);
+
+        // hydra descriion : not supported
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/Error',
+            '@type' => 'hydra:Error',
+            'hydra:title' => 'An error occurred',
+            'hydra:description' => 'not supported',
+        ]);
+
+    }
+
+    public function testSubdomainWhenIsActiveAndPutActive(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->put('/api/subdomains/1', [
+                'subdomain' => 'toto',
+                'active' => true
+        ]);
+
+        // not supported
+        $this->assertResponseStatusCodeSame(500);
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/Error',
+            '@type' => 'hydra:Error',
+            'hydra:title' => 'An error occurred',
+            'hydra:description' => 'The subdomain is already active',
+        ]);
+
+    }
+
+    public function testDeleteSubdomain(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->delete('/api/subdomains/1');
+
+        $this->assertResponseStatusCodeSame(405);
+    }
+
+    // attention : vérifier que les !ROLE_ORGANIZATION peuvent accéder à la ressource
+    public function testGetCollectionWithBadRoles()
+    {
+        $this->loginAsStudent($this->user);
+
+        $this->get('/api/subdomains');
+
+        $this->assertResponseStatusCodeSame(200);
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/Subdomain',
+            '@id' => '/api/subdomains',
+            '@type' => 'hydra:Collection',
+            'hydra:totalItems' => 1,
+            'hydra:member' => [
+                ["subdomain" => "subdomain"]
+            ],
+        ]);
+    }
+
+    public function testPutSubdomainWithBadRoles(): void
+    {
+        
+        $this->loginAsStudent($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->put('/api/subdomains/1', [
+                'subdomain' => 'toto',
+                'active' => false
+        ]);
+
+        // not supported
+        $this->assertResponseStatusCodeSame(403);
+
+        // hydra descriion : not supported
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/Error',
+            '@type' => 'hydra:Error',
+            'hydra:title' => 'An error occurred',
+        ]);
+    }
+
+    public function testDeleteMethodWithBadRoles(): void
+    {
+        $this->loginAsStudent($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->delete('/api/subdomains/1');
+
+        $this->assertResponseStatusCodeSame(405);
+
+        // error not found
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/Error',
+            '@type' => 'hydra:Error',
+            'hydra:title' => 'An error occurred',
+        ]);
+    }
+
+    public function testPostMethodWithBadRoles(): void
+    {
+        $this->loginAsStudent($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->post('/api/subdomains', [
+            'subdomain' => 'toto',
+            'active' => false
+        ]);
+
+        $this->assertResponseStatusCodeSame(403);
+    }
+
+    public function testGetCollectionFromIntruOfOrganization(): void
+    {
+        $this->loginAsintruOfRoot($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->get('/api/subdomains/1');
+
+        // pas le droit d'accéder à la ressource
+        $this->assertResponseStatusCodeSame(404);
+
+      // not found 
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/Error',
+            '@type' => 'hydra:Error',
+            'hydra:title' => 'An error occurred',
+        ]);
+
+        
+    }
+}

+ 355 - 31
tests/Application/OtWebTestCase.php

@@ -2,21 +2,42 @@
 
 namespace App\Tests\Application;
 
-use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
-use ApiPlatform\Symfony\Bundle\Test\Client;
+use DateTime;
+use Zenstruck\Foundry\Proxy;
 use App\Entity\Access\Access;
+use App\Enum\Core\TimeZoneEnum;
+use App\Enum\Education\CycleEnum;
+use App\Enum\Booking\VisibilityEnum;
 use App\Enum\Organization\LegalEnum;
+use App\Enum\Core\ContactPointTypeEnum;
+use App\Enum\Education\PeriodicityEnum;
+use Doctrine\ORM\EntityManagerInterface;
+use ApiPlatform\Symfony\Bundle\Test\Client;
 use App\Enum\Organization\PrincipalTypeEnum;
+use App\Enum\Organization\BulletinOutputEnum;
+use App\Enum\Organization\BulletinPeriodEnum;
+use App\Enum\Organization\SendToBulletinEnum;
+use Symfony\Component\HttpFoundation\Request;
 use App\Enum\Organization\SettingsProductEnum;
+use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
+use Doctrine\Common\DataFixtures\Purger\ORMPurger;
 use App\Tests\Fixture\Factory\Access\AccessFactory;
-use App\Tests\Fixture\Factory\Organization\OrganizationFactory;
-use App\Tests\Fixture\Factory\Organization\SettingsFactory;
+use App\Tests\Fixture\Factory\Booking\EventFactory;
+use App\Tests\Fixture\Factory\Network\NetworkFactory;
 use App\Tests\Fixture\Factory\Person\PersonFactory;
-use Doctrine\Common\DataFixtures\Purger\ORMPurger;
-use Doctrine\ORM\EntityManagerInterface;
-use Symfony\Component\HttpFoundation\Request;
 use Symfony\Contracts\HttpClient\ResponseInterface;
-use Zenstruck\Foundry\Proxy;
+use App\Tests\Fixture\Factory\Education\CycleFactory;
+use App\Tests\Fixture\Factory\Core\ContactPointFactory;
+use App\Enum\Education\AdvancedEducationNotationTypeEnum;
+use App\Tests\Fixture\Factory\Billing\ResidenceAreaFactory;
+use App\Tests\Fixture\Factory\Mobyt\MobytUserStatusFactory;
+use App\Tests\Fixture\Factory\Organization\SettingsFactory;
+use App\Tests\Fixture\Factory\Billing\BillingSettingFactory;
+use App\Tests\Fixture\Factory\Organization\SubdomainFactory;
+use App\Tests\Fixture\Factory\Organization\ParametersFactory;
+use App\Tests\Fixture\Factory\Education\EducationTimingFactory;
+use App\Tests\Fixture\Factory\Network\NetworkOrganizationFactory;
+use App\Tests\Fixture\Factory\Organization\OrganizationFactory;
 
 /**
  * Base class for applicative tests.
@@ -35,6 +56,7 @@ abstract class OtWebTestCase extends ApiTestCase
      */
     public function setup(): void
     {
+
         // Boot le kernel symfony et récupère l'entity manager
         // @see https://symfony.com/doc/current/testing.html#retrieving-services-in-the-test
         self::bootKernel();
@@ -52,13 +74,14 @@ abstract class OtWebTestCase extends ApiTestCase
         $this->client = static::createClient();
     }
 
-    /**
-     * Delete all DB records before populating fixtures.
-     *
-     * @return void
-     *
-     * @throws \Doctrine\DBAL\Exception
-     */
+    public function loadSchema()
+    {
+        $command = 'bin/console --env=staging doctrine:schema:update --force';
+        $output = shell_exec($command);
+        echo $output;
+    }
+
+
     private function purgeDb()
     {
         if (!preg_match('/.*test.*/', $this->em->getConnection()->getDatabase())) {
@@ -69,9 +92,32 @@ abstract class OtWebTestCase extends ApiTestCase
         $purger = new ORMPurger($this->em);
         $purger->setPurgeMode(ORMPurger::PURGE_MODE_DELETE);
         $purger->purge();
+
+        $this->resetAutoIncrement();
+
         $this->em->getConnection()->exec('SET FOREIGN_KEY_CHECKS = 1;');
     }
 
+    private function resetAutoIncrement()
+    {
+        $connection = $this->em->getConnection();
+        $schemaManager = $connection->getSchemaManager();
+
+        foreach ($schemaManager->listTableNames() as $tableName) {
+            $connection->executeStatement("ALTER TABLE $tableName AUTO_INCREMENT = 1;");
+        }
+    }
+
+    private function resetAutoIncrement()
+    {
+        $connection = $this->em->getConnection();
+        $schemaManager = $connection->getSchemaManager();
+
+        foreach ($schemaManager->listTableNames() as $tableName) {
+            $connection->executeStatement("ALTER TABLE $tableName AUTO_INCREMENT = 1;");
+        }
+    }
+
     /**
      * Create and persist the fixtures (do not flush).
      *
@@ -81,27 +127,238 @@ abstract class OtWebTestCase extends ApiTestCase
     {
         $person = PersonFactory::createOne(
             [
-                'username' => 'username',
-                'password' => 'password',
-            ]
+            'username' => 'username',
+            'password' => 'password'
+          ]
         );
 
+        $personOfOtherOrganization = PersonFactory::createOne(
+            [
+            'username' => 'intruOfRoot',
+            'password' => 'password'
+          ]
+        );
+
+        $contactPoint = ContactPointFactory::createOne([
+          'contactType' => ContactPointTypeEnum::PRINCIPAL
+        ]);
+
+        $parameters = ParametersFactory::createOne([
+          'educationPeriodicity' => PeriodicityEnum::MONTHLY,
+          'financialDate' => new DateTime(),
+          'musicalDate' => new DateTime(),
+          'startCourseDate' => new DateTime(),
+          'endCourseDate' => new DateTime(),
+          'average' => 20,
+          'editCriteriaNotationByAdminOnly' => true,
+          'smsSenderName' => 'MySender',
+          'logoDonorsMove' => false,
+          'subDomain' => 'subdomain',
+          'website' => 'https://www.example.com',
+          'otherWebsite' => 'https://www.otherwebsite.com',
+          'customDomain' => 'https://www.customdomain.com',
+          'desactivateOpentalentSiteWeb' => false,
+          'bulletinPeriod' => BulletinPeriodEnum::YEAR,
+          'bulletinWithTeacher' => false,
+          'bulletinPrintAddress' => false,
+          'bulletinSignatureDirector' => true,
+          'bulletinDisplayLevelAcquired' => true,
+          'bulletinShowEducationWithoutEvaluation' => false,
+          'bulletinViewTestResults' => false,
+          'bulletinShowAbsences' => false,
+          'bulletinShowAverages' => true,
+          'bulletinOutput' => BulletinOutputEnum::SEND_BY_EMAIL,
+          'bulletinEditWithoutEvaluation' => true,
+          'bulletinReceiver' => SendToBulletinEnum::STUDENTS_AND_THEIR_GUARDIANS,
+          'usernameSMS' => '2iosinterne',
+          'passwordSMS' => '2iosot74',
+          'showAdherentList' => true,
+          'studentsAreAdherents' => false,
+          'timezone' => TimeZoneEnum::EUROPE_PARIS,
+          'advancedEducationNotationType' => AdvancedEducationNotationTypeEnum::BY_EDUCATION,
+          'sendAttendanceEmail' => true,
+          'sendAttendanceSms' => true,
+          'generateAttendanceReport' => true,
+          'consultPedagogicResult' => true,
+          'consultTeacherListing' => true,
+          'periodValidation' => true,
+
+        ]);
+        
+        $parameters2 = ParametersFactory::createOne([
+          'educationPeriodicity' => PeriodicityEnum::MONTHLY,
+          'financialDate' => new DateTime(),
+          'musicalDate' => new DateTime(),
+          'startCourseDate' => new DateTime(),
+          'endCourseDate' => new DateTime(),
+          'average' => 20,
+          'editCriteriaNotationByAdminOnly' => true,
+          'smsSenderName' => 'toto',
+          'logoDonorsMove' => false,
+          'subDomain' => 'subdomain',
+          'website' => 'https://www.toto.com',
+          'otherWebsite' => 'https://www.toto.com',
+          'customDomain' => 'https://www.toto.com',
+          'desactivateOpentalentSiteWeb' => false,
+          'bulletinPeriod' => BulletinPeriodEnum::YEAR,
+          'bulletinWithTeacher' => false,
+          'bulletinPrintAddress' => false,
+          'bulletinSignatureDirector' => true,
+          'bulletinDisplayLevelAcquired' => true,
+          'bulletinShowEducationWithoutEvaluation' => false,
+          'bulletinViewTestResults' => false,
+          'bulletinShowAbsences' => false,
+          'bulletinShowAverages' => true,
+          'bulletinOutput' => BulletinOutputEnum::SEND_BY_EMAIL,
+          'bulletinEditWithoutEvaluation' => true,
+          'bulletinReceiver' => SendToBulletinEnum::STUDENTS_AND_THEIR_GUARDIANS,
+          'usernameSMS' => 'toto',
+          'passwordSMS' => 'toto',
+          'showAdherentList' => true,
+          'studentsAreAdherents' => false,
+          'timezone' => TimeZoneEnum::EUROPE_PARIS,
+          'advancedEducationNotationType' => AdvancedEducationNotationTypeEnum::BY_EDUCATION,
+          'sendAttendanceEmail' => true,
+          'sendAttendanceSms' => true,
+          'generateAttendanceReport' => true,
+          'consultPedagogicResult' => true,
+          'consultTeacherListing' => true,
+          'periodValidation' => true,
+
+        ]);
+
+
         $organization = OrganizationFactory::createOne([
-            'legalStatus' => LegalEnum::ASSOCIATION_LAW_1901()->getValue(),
-            'principalType' => PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY()->getValue(),
-            'name' => 'My Organization',
+          'legalStatus' => LegalEnum::ASSOCIATION_LAW_1901,
+          'principalType' => PrincipalTypeEnum::NATIONAL_FEDERATION,
+          'name' => 'Root',
+          'parameters' => $parameters,
+          'siretNumber' => '34919841600035',
+          'identifier' => 'FR042100000050',
+        ]);
+
+        $network1 = NetworkFactory::createOne([
+          'name' => 'Network 1',
+          'logo' => 'logo',
+          'url' => 'https://www.network1.com',
+        ]);
+
+        $network2 = NetworkFactory::createOne([
+          'name' => 'Network 2',
+          'logo' => 'logo',
+          'url' => 'https://www.network2.com',
+        ]);
+        
+
+        $cmfNetwork = NetworkFactory::createOne([
+          'name' => 'CMF',
+          'logo' => 'logo',
+          'url' => 'https://www.cmf.com',
+        ]);
+
+        $networkOrganization = NetworkOrganizationFactory::createOne([
+          'network' => $cmfNetwork,
+          'organization' => $organization,
+          'startDate' => new DateTime('2001-01-01'),
+          'endDate' => new DateTime('2031-12-31'),
+          'leadingCause' => 'leadingCause'
+        ]);
+
+
+        $billingSetting = BillingSettingFactory::createOne([
+          'organization' => $organization,
+        ]);
+
+        $residenceArea = ResidenceAreaFactory::createOne([
+          'label' => 'Résidence 1',
+          'billingSetting' => $billingSetting,
+        ]);
+
+        $organization2 = OrganizationFactory::createOne([
+          'legalStatus' => LegalEnum::ASSOCIATION_LAW_1901,
+          'principalType' => PrincipalTypeEnum::NATIONAL_FEDERATION,
+          'name' => 'Other Organization',
+          'parameters' => $parameters2,
+        ]);
+
+        $settings2 = SettingsFactory::createOne([
+          'product' => SettingsProductEnum::SCHOOL_PREMIUM,
+          'organization' => $organization2,
+          'modules' => ['BillingAdministration']
+        ]);
+        $mobyteUserStatus = MobytUserStatusFactory::createOne([
+          'organizationId' => $organization->getId(),
+          'active' => true,
+          'amount' => 100,
+          'money' => 100
         ]);
 
-        SettingsFactory::createOne([
-            'product' => SettingsProductEnum::ARTIST(),
-            'organization' => $organization,
+        $cycle = CycleFactory::createOne([
+          'organization' => $organization,
+          'label' => 'Cycle 1',
+          'cycleEnum' => CycleEnum::CYCLE_1
+        ]);
+
+        $settings = SettingsFactory::createOne([
+          'product' => SettingsProductEnum::SCHOOL_PREMIUM,
+          'organization' => $organization,
+          'modules' => [
+            'Sms' => true,
+            // 'BillingAdministration' => true,
+            ]
+        ]);
+
+        $educationTimings = EducationTimingFactory::createOne([
+          'organization' => $organization,
+          'timing' => 45
+        ]);
+
+        $educationTimings2 = EducationTimingFactory::createOne([
+          'organization' => $organization2,
+          'timing' => 60
+        ]);
+
+        $subdomain = SubdomainFactory::createOne([
+          'organization' => $organization,
+          'subdomain' => 'subdomain',
+          'active' => true
+        ]);
+
+        $event = EventFactory::createOne([
+          'organization' => $organization,
+          'name' => 'My event',
+          'datetimeStart' => new \DateTime(),
+          'datetimeEnd' => new \DateTime(),
+          'visibility' => VisibilityEnum::PUBLIC_VISIBILITY
         ]);
 
         $this->user = AccessFactory::createOne([
-            'person' => $person,
-            'organization' => $organization,
-            'roles' => ['ROLE_USERS_VIEW'],
+          'person' => $person,
+          'organization' => $organization,
+          'roles' => ["ROLE_ADMIN","ROLE_ADMIN_CORE","ROLE_SUPER_ADMIN", "ROLE_ORGANIZATION_VIEW","ROLE_ORGANIZATION" ],
+          'adminAccess' => true,
+          'activityYear' => 2021
+        ]);
+
+        $student = PersonFactory::createOne([
+          'username' => 'student',
+          'password' => 'password'
+        ]);
+
+        $accessWithNoRole = AccessFactory::createOne([
+          'person' => $student,
+          'organization' => $organization,
+          'roles' => ["ROLE_STUDENT"],
+          'adminAccess' => false
+        ]);
+
+        $acccesFromOtherOrganization = AccessFactory::createOne([
+          'person' => $personOfOtherOrganization,
+          'organization' => $organization2,
+          'roles' => ["ROLE_ADMIN","ROLE_ADMIN_CORE","ROLE_SUPER_ADMIN", "ROLE_ORGANIZATION_VIEW","ROLE_ORGANIZATION" ],
+          'adminAccess' => true,
         ]);
+
     }
 
     /**
@@ -110,7 +367,7 @@ abstract class OtWebTestCase extends ApiTestCase
      * @param array<mixed> $data
      * @param array<mixed> $headers
      */
-    protected function request(string $method, string $route, ?array $data = null, array $headers = []): ResponseInterface
+    protected function request(string $method, string $route, array | null $data = null, array $headers = []): ResponseInterface
     {
         if ($this->user) {
             $headers = array_merge(
@@ -201,14 +458,50 @@ abstract class OtWebTestCase extends ApiTestCase
      * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
      * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
      */
-    protected function loginAs(Proxy|Access $access): void
+    public function loginAs()
     {
-        $person = $access->getPerson();
+        $access = $this->em->getRepository(Access::class)->find(1);
+        $person =  $access->getPerson();
 
         $response = $this->post(
             '/login_check',
             ['username' => $person->getUsername(), 'password' => $person->getPassword()]
         );
+
+        $content = $response->getContent();
+
+        $decodedContent = json_decode($content);
+
+        // Vérifier que le token est présent
+        if (!isset($decodedContent->token)) {
+            throw new \Exception("Token not found in response");
+        }
+
+        $this->securityToken = $decodedContent->token;
+        $this->user = $access;
+    }
+
+    /**
+     * Login as the given Access user
+     *
+     * @param Proxy|Access $access
+     * @return void
+     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
+     */
+    public function loginAsStudent()
+    {
+        // on récupère l'access qui a l'id 641003 dans l'entity manager
+        $access = $this->em->getRepository(Access::class)->find(2);
+        $person =  $access->getPerson();
+
+        $response = $this->post(
+            '/login_check',
+            ['username' => $person->getUsername(), 'password' => $person->getPassword()]
+        );
+
         $content = $response->getContent();
 
         $this->securityToken = json_decode($content)->token;
@@ -216,7 +509,38 @@ abstract class OtWebTestCase extends ApiTestCase
     }
 
     /**
-     * Assert that the response has the expected status code and is well formated.
+     * Login as the given Access user
+     *
+     * @param Proxy|Access $access
+     * @return void
+     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
+     */
+    public function loginAsintruOfRoot()
+    {
+        $access = $this->em->getRepository(Access::class)->find(3);
+        $person =  $access->getPerson();
+
+        $response = $this->post(
+            '/login_check',
+            ['username' => $person->getUsername(), 'password' => $person->getPassword()]
+        );
+
+        $content = $response->getContent();
+
+        $this->securityToken = json_decode($content)->token;
+        $this->user = $access;
+    }
+
+
+    /**
+     * Assert that the response has the expected status code and is well formated
+     *
+     * @param string $resourceClass
+     * @param int $expectedStatus
+     * @return void
      */
     protected function validateCollectionSchema(string $resourceClass, int $expectedStatus = 200): void
     {

+ 18 - 2
tests/Application/Person/PersonTest.php

@@ -2,12 +2,13 @@
 
 namespace App\Tests\Application\Person;
 
-use App\Entity\Person\Person;
+use AppBundle\Entity\Person\Person;
 use App\Tests\Application\OtWebTestCase;
 
 class PersonTest extends OtWebTestCase
 {
-    public function testPersonGet(): void
+
+    public function testPersonGetCollection(): void
     {
         $this->loginAs($this->user);
 
@@ -78,4 +79,19 @@ class PersonTest extends OtWebTestCase
         // Expects : 405 Method Not Allowed
         $this->assertResponseStatusCodeSame(405);
     }
+
+    public function testPersonGetHasNoRole(): void
+    {
+        $this->loginAsStudent($this->user);
+
+        $this->get('/api/people/' . $this->user->getPerson()->getId());
+
+        $this->validateCollectionSchema(Person::class, 404);
+
+        $this->assertJsonContains([
+            "hydra:description" => "This route does not aim to be called."
+        ]);
+    }
+
+
 }

+ 22 - 0
tests/Application/Profile/AccessProfileTest.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Tests\Application\Profile;
+
+use App\Tests\Application\OtWebTestCase;
+
+class AccessProfileTest extends OtWebTestCase
+{
+    public function testGetAccessId(): void 
+    {
+      $this->loginAs($this->user);
+
+      $this->assertResponseIsSuccessful();
+
+      $this->client->request('GET', '/api/my_profile/1', [], [], ['HTTP_AUTHORIZATION' => 'Bearer ' . $this->securityToken]);
+      dd($this->client->getResponse()->getContent());
+      // echo "\n";
+      // var_dump($this->securityToken);
+      // $this->assertResponseIsSuccessful();
+    }
+
+}

+ 21 - 0
tests/Application/Profile/OrganizationProfilesTest.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App\Tests\Application\Profile;
+
+use App\Tests\Application\OtWebTestCase;
+
+class OrganizationProfilesTest extends OtWebTestCase
+{
+    public function testGetAccessId(): void 
+    {
+      $this->loginAs($this->user);
+
+
+      $this->assertResponseIsSuccessful();
+
+      $this->get('/api/organization_profiles/1');
+
+      $this->assertResponseStatusCodeSame(200);
+    }
+
+}

+ 4 - 5
tests/Application/Public/PublicEventsTest.php

@@ -1,18 +1,17 @@
 <?php
 
 namespace App\Tests\Application\Public;
-
-use App\Entity\Public\PublicEvent;
 use App\Tests\Application\OtWebTestCase;
 
+
 class PublicEventsTest extends OtWebTestCase
 {
     public function testEvents(): void
     {
-        $this->get('/api/public/events');
-
-        $this->validateCollectionSchema(PublicEvent::class);
+        $this->loadSchema();
 
+        $response = static::createClient()->request('GET', '/api/public/events');
+        $this->assertResponseIsSuccessful();
         $this->assertJsonContains([
             '@context' => '/api/contexts/PublicEvent',
             '@id' => '/api/public/events',

+ 5 - 3
tests/Application/Public/PublicStructuresTest.php

@@ -9,6 +9,8 @@ class PublicStructuresTest extends OtWebTestCase
 {
     public function testGetIndex(): void
     {
+        $this->loadSchema();
+
         $crawler = $this->get('api/public/federation_structures');
 
         $this->validateCollectionSchema(FederationStructure::class);
@@ -17,10 +19,10 @@ class PublicStructuresTest extends OtWebTestCase
             '@context' => '/api/contexts/FederationStructure',
             '@id' => '/api/public/federation_structures',
             '@type' => 'hydra:Collection',
-            'hydra:totalItems' => 2,
+            'hydra:totalItems' => 1,
             'hydra:member' => [
-                ['name' => 'Fede 1'],
-                ['name' => 'Organization 2'],
+                ["name" => "Root2"],
+                ["name" => "Other Organization"],
             ],
         ]);
     }

+ 84 - 0
tests/Application/Utils/GpsCoordinateTest.php

@@ -0,0 +1,84 @@
+<?php
+
+namespace App\Tests\Application\Utils;
+
+use App\Tests\Application\OtWebTestCase;
+
+class GpsCoordinateTest extends OtWebTestCase
+{
+    public function testGetGpsCoordinateReverse(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->get('/api/gps-coordinate-reverse/48.8566/2.3522');
+
+        $this->assertResponseStatusCodeSame(200);
+
+        $this->assertJsonContains([
+          '@context' => '/api/contexts/GpsCoordinate',
+          '@id' => '/api/gps-coordinate-reverse/48.8564263/2.3525275780116',
+          '@type' => 'GpsCoordinate',
+          'latitude' => 48.856426299999995,
+          'longitude' => 2.3525275780116073,
+          'streetAddress' => "Place de l'Hôtel de Ville",
+          'streetAddressSecond' => null,
+          'streetAddressThird' => null,
+          'cp' => "75004",
+          'city' => null,
+          'country' => null
+        ]);
+    }
+
+    public function testGetGpsCoordinateSearching()
+    {
+        $this->loginAs($this->user);
+
+        $this->assertResponseIsSuccessful();
+
+        $this->get('/api/gps-coordinate-searching');
+
+        $this->assertResponseStatusCodeSame(200);
+
+
+        $this->assertJsonContains([
+          '@context' => '/api/contexts/GpsCoordinate',
+          '@id' => '/api/gps-coordinate-searching',
+          '@type' => 'hydra:Collection',
+          'hydra:totalItems' => 1,
+          'hydra:member' => [
+            [
+              '@id' => '/api/gps-coordinate-reverse/0/0',
+              '@type' => 'GpsCoordinate',
+              'latitude' => 0,
+              'longitude' => 0,
+              'streetAddress' => null,
+              'streetAddressSecond' => null,
+              'streetAddressThird' => null,
+              'cp' => null,
+              'city' => null,
+              'country' => null
+            ]
+          ]
+        ]);
+    }
+
+    public function testGetGpsCoordinateReverseWithInvalidCoordinates(): void
+    {
+        $this->loginAs($this->user);
+
+        $this->get('/api/gps-coordinate-reverse/12345.6789/98765.4321');
+
+        $this->assertResponseStatusCodeSame(404); 
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/Error',
+            '@type' => 'hydra:Error',
+            'hydra:title' => 'An error occurred',
+            'hydra:description' => 'Failed to retrieve GPS coordinates: No address found for the given GPS coordinates.', 
+        ]);
+    }
+
+
+}

+ 29 - 0
tests/Application/Utils/SiretTest.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Tests\Application\Utils;
+
+use App\Tests\Application\OtWebTestCase;
+
+class SiretTest extends OtWebTestCase
+{
+  // Attention, ces tests ne sont pas fonctionnels 
+    public function testGetAccessId(): void 
+    {
+      $this->loginAs($this->user);
+
+
+      $this->assertResponseIsSuccessful();
+
+      $this->get('/api/siret-checking/34919841600035');
+
+      $this->assertResponseStatusCodeSame(200);
+
+      $this->assertJsonContains([
+        '@context' => 'api/contexts/Siret',
+        '@id' => '/api/siret-checking/34919841600035',
+        '@type' => 'Siret',
+        'number' => '34919841600035',
+        'isCorrect' => true,
+      ]);
+    }
+}

+ 63 - 0
tests/Fixture/Factory/Access/AccessBillingFactory.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Access;
+
+use App\Entity\Access\Access;
+use App\Entity\Billing\AccessBilling;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<AccessBilling>
+ *
+ * @phpstan-method        AccessBilling|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static AccessBilling|Proxy createOne(array $attributes = [])
+ * @phpstan-method static AccessBilling|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static AccessBilling|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static AccessBilling|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static AccessBilling|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static AccessBilling|Proxy random(array $attributes = [])
+ * @phpstan-method static AccessBilling|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static AccessBillingRepository|RepositoryProxy repository()
+ * @phpstan-method static AccessBilling[]|Proxy[] all()
+ * @phpstan-method static AccessBilling[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static AccessBilling[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static AccessBilling[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static AccessBilling[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static AccessBilling[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class AccessBillingFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return AccessBilling::class;
+    }
+}

+ 62 - 0
tests/Fixture/Factory/Billing/BillingSettingFactory.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Billing;
+
+use App\Entity\Billing\BillingSetting;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<BillingSetting>
+ *
+ * @phpstan-method        BillingSetting|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static BillingSetting|Proxy createOne(array $attributes = [])
+ * @phpstan-method static BillingSetting|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static BillingSetting|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static BillingSetting|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static BillingSetting|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static BillingSetting|Proxy random(array $attributes = [])
+ * @phpstan-method static BillingSetting|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static BillingSettingRepository|RepositoryProxy repository()
+ * @phpstan-method static BillingSetting[]|Proxy[] all()
+ * @phpstan-method static BillingSetting[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static BillingSetting[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static BillingSetting[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static BillingSetting[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static BillingSetting[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class BillingSettingFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return BillingSetting::class;
+    }
+}

+ 61 - 0
tests/Fixture/Factory/Billing/ResidenceAreaFactory.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Billing;
+
+use Zenstruck\Foundry\ModelFactory;
+use App\Entity\Billing\ResidenceArea;
+
+/**
+ * @extends ModelFactory<ResidenceArea>
+ *
+ * @phpstan-method        ResidenceArea|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static ResidenceArea|Proxy createOne(array $attributes = [])
+ * @phpstan-method static ResidenceArea|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static ResidenceArea|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static ResidenceArea|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static ResidenceArea|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static ResidenceArea|Proxy random(array $attributes = [])
+ * @phpstan-method static ResidenceArea|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static ResidenceAreaRepository|RepositoryProxy repository()
+ * @phpstan-method static ResidenceArea[]|Proxy[] all()
+ * @phpstan-method static ResidenceArea[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static ResidenceArea[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static ResidenceArea[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static ResidenceArea[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static ResidenceArea[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class ResidenceAreaFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return ResidenceArea::class;
+    }
+}

+ 62 - 0
tests/Fixture/Factory/Booking/EventFactory.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Booking;
+
+use App\Entity\Booking\Event;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<Event>
+ *
+ * @phpstan-method        Event|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static Event|Proxy createOne(array $attributes = [])
+ * @phpstan-method static Event|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static Event|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static Event|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static Event|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static Event|Proxy random(array $attributes = [])
+ * @phpstan-method static Event|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static EventRepository|RepositoryProxy repository()
+ * @phpstan-method static Event[]|Proxy[] all()
+ * @phpstan-method static Event[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static Event[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static Event[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static Event[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static Event[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class EventFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return Event::class;
+    }
+}

+ 65 - 0
tests/Fixture/Factory/Core/ContactPointFactory.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Core;
+
+use Zenstruck\Foundry\Proxy;
+use App\Entity\Access\Access;
+use App\Entity\Core\ContactPoint;
+use Zenstruck\Foundry\ModelFactory;
+use App\Entity\Billing\AccessBilling;
+use App\Entity\Billing\BillingSetting;
+
+/**
+ * @extends ModelFactory<ContactPoint>
+ *
+ * @phpstan-method        ContactPoint|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static ContactPoint|Proxy createOne(array $attributes = [])
+ * @phpstan-method static ContactPoint|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static ContactPoint|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static ContactPoint|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static ContactPoint|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static ContactPoint|Proxy random(array $attributes = [])
+ * @phpstan-method static ContactPoint|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static ContactPointRepository|RepositoryProxy repository()
+ * @phpstan-method static ContactPoint[]|Proxy[] all()
+ * @phpstan-method static ContactPoint[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static ContactPoint[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static ContactPoint[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static ContactPoint[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static ContactPoint[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class ContactPointFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return ContactPoint::class;
+    }
+}

+ 65 - 0
tests/Fixture/Factory/Education/CycleByEducationFactory.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Education;
+
+use App\Entity\Access\Access;
+use App\Entity\Billing\AccessBilling;
+use App\Entity\Billing\BillingSetting;
+use App\Entity\Education\CycleByEducation;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<CycleByEducation>
+ *
+ * @phpstan-method        CycleByEducation|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static CycleByEducation|Proxy createOne(array $attributes = [])
+ * @phpstan-method static CycleByEducation|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static CycleByEducation|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static CycleByEducation|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static CycleByEducation|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static CycleByEducation|Proxy random(array $attributes = [])
+ * @phpstan-method static CycleByEducation|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static CycleByEducationRepository|RepositoryProxy repository()
+ * @phpstan-method static CycleByEducation[]|Proxy[] all()
+ * @phpstan-method static CycleByEducation[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static CycleByEducation[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static CycleByEducation[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static CycleByEducation[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static CycleByEducation[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class CycleByEducationFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return CycleByEducation::class;
+    }
+}

+ 66 - 0
tests/Fixture/Factory/Education/CycleFactory.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Education;
+
+use Zenstruck\Foundry\Proxy;
+use App\Entity\Access\Access;
+use App\Entity\Education\Cycle;
+use Zenstruck\Foundry\ModelFactory;
+use App\Entity\Billing\AccessBilling;
+use App\Entity\Billing\BillingSetting;
+use App\Entity\Education\CycleByEducation;
+
+/**
+ * @extends ModelFactory<Cycle>
+ *
+ * @phpstan-method        Cycle|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static Cycle|Proxy createOne(array $attributes = [])
+ * @phpstan-method static Cycle|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static Cycle|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static Cycle|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static Cycle|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static Cycle|Proxy random(array $attributes = [])
+ * @phpstan-method static Cycle|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static CycleRepository|RepositoryProxy repository()
+ * @phpstan-method static Cycle[]|Proxy[] all()
+ * @phpstan-method static Cycle[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static Cycle[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static Cycle[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static Cycle[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static Cycle[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class CycleFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return Cycle::class;
+    }
+}

+ 62 - 0
tests/Fixture/Factory/Education/EducationCategoryFactory.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Education;
+
+use App\Entity\Education\EducationCategory;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<EducationCategory>
+ *
+ * @phpstan-method        EducationCategory|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static EducationCategory|Proxy createOne(array $attributes = [])
+ * @phpstan-method static EducationCategory|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static EducationCategory|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static EducationCategory|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static EducationCategory|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static EducationCategory|Proxy random(array $attributes = [])
+ * @phpstan-method static EducationCategory|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static EducationCategoryRepository|RepositoryProxy repository()
+ * @phpstan-method static EducationCategory[]|Proxy[] all()
+ * @phpstan-method static EducationCategory[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static EducationCategory[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static EducationCategory[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static EducationCategory[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static EducationCategory[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class EducationCategoryFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return EducationCategory::class;
+    }
+}

+ 63 - 0
tests/Fixture/Factory/Education/EducationComplementFactory.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Education;
+
+use App\Entity\Education\EducationCategory;
+use App\Entity\Education\EducationComplement;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<EducationComplement>
+ *
+ * @phpstan-method        EducationComplement|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static EducationComplement|Proxy createOne(array $attributes = [])
+ * @phpstan-method static EducationComplement|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static EducationComplement|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static EducationComplement|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static EducationComplement|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static EducationComplement|Proxy random(array $attributes = [])
+ * @phpstan-method static EducationComplement|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static EducationComplementRepository|RepositoryProxy repository()
+ * @phpstan-method static EducationComplement[]|Proxy[] all()
+ * @phpstan-method static EducationComplement[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static EducationComplement[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static EducationComplement[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static EducationComplement[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static EducationComplement[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class EducationComplementFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return EducationComplement::class;
+    }
+}

+ 61 - 0
tests/Fixture/Factory/Education/EducationCurriculumFactory.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Education;
+
+use App\Entity\Education\EducationCurriculum;
+use Zenstruck\Foundry\ModelFactory;
+
+/**
+ * @extends ModelFactory<EducationCurriculum>
+ *
+ * @phpstan-method        EducationCurriculum|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static EducationCurriculum|Proxy createOne(array $attributes = [])
+ * @phpstan-method static EducationCurriculum|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static EducationCurriculum|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static EducationCurriculum|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static EducationCurriculum|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static EducationCurriculum|Proxy random(array $attributes = [])
+ * @phpstan-method static EducationCurriculum|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static EducationCurriculumRepository|RepositoryProxy repository()
+ * @phpstan-method static EducationCurriculum[]|Proxy[] all()
+ * @phpstan-method static EducationCurriculum[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static EducationCurriculum[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static EducationCurriculum[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static EducationCurriculum[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static EducationCurriculum[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class EducationCurriculumFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return EducationCurriculum::class;
+    }
+}

+ 64 - 0
tests/Fixture/Factory/Education/EducationFactory.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Education;
+
+use App\Entity\Education\Education;
+use App\Entity\Education\EducationCategory;
+use App\Entity\Education\EducationComplement;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<Education>
+ *
+ * @phpstan-method        Education|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static Education|Proxy createOne(array $attributes = [])
+ * @phpstan-method static Education|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static Education|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static Education|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static Education|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static Education|Proxy random(array $attributes = [])
+ * @phpstan-method static Education|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static EducationRepository|RepositoryProxy repository()
+ * @phpstan-method static Education[]|Proxy[] all()
+ * @phpstan-method static Education[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static Education[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static Education[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static Education[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static Education[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class EducationFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return Education::class;
+    }
+}

+ 63 - 0
tests/Fixture/Factory/Education/EducationStudentFactory.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Education;
+
+
+use App\Entity\Education\EducationStudent;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<EducationStudent>
+ *
+ * @phpstan-method        EducationStudent|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static EducationStudent|Proxy createOne(array $attributes = [])
+ * @phpstan-method static EducationStudent|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static EducationStudent|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static EducationStudent|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static EducationStudent|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static EducationStudent|Proxy random(array $attributes = [])
+ * @phpstan-method static EducationStudent|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static EducationStudentRepository|RepositoryProxy repository()
+ * @phpstan-method static EducationStudent[]|Proxy[] all()
+ * @phpstan-method static EducationStudent[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static EducationStudent[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static EducationStudent[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static EducationStudent[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static EducationStudent[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class EducationStudentFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return EducationStudent::class;
+    }
+}

+ 63 - 0
tests/Fixture/Factory/Education/EducationTimingFactory.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Education;
+
+use Zenstruck\Foundry\Proxy;
+use App\Entity\Education\Education;
+use Zenstruck\Foundry\ModelFactory;
+use App\Entity\Education\EducationTiming;
+
+/**
+ * @extends ModelFactory<EducationTiming>
+ *
+ * @phpstan-method        EducationTiming|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static EducationTiming|Proxy createOne(array $attributes = [])
+ * @phpstan-method static EducationTiming|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static EducationTiming|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static EducationTiming|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static EducationTiming|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static EducationTiming|Proxy random(array $attributes = [])
+ * @phpstan-method static EducationTiming|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static EducationTimingRepository|RepositoryProxy repository()
+ * @phpstan-method static EducationTiming[]|Proxy[] all()
+ * @phpstan-method static EducationTiming[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static EducationTiming[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static EducationTiming[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static EducationTiming[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static EducationTiming[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class EducationTimingFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return EducationTiming::class;
+    }
+}

+ 65 - 0
tests/Fixture/Factory/Mobyt/MobytUserStatusFactory.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Mobyt;
+
+use App\ApiResources\Mobyt\MobytUserStatus;
+use App\Entity\Organization\Organization;
+use App\Tests\Fixture\Factory\Person\PersonRepository;
+use Zenstruck\Foundry\RepositoryProxy;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<MobytUserStatus>
+ *
+ * @phpstan-method        MobytUserStatus|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static MobytUserStatus|Proxy createOne(array $attributes = [])
+ * @phpstan-method static MobytUserStatus|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static MobytUserStatus|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static MobytUserStatus|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static MobytUserStatus|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static MobytUserStatus|Proxy random(array $attributes = [])
+ * @phpstan-method static MobytUserStatus|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static MobytUserStatusRepository|RepositoryProxy repository()
+ * @phpstan-method static MobytUserStatus[]|Proxy[] all()
+ * @phpstan-method static MobytUserStatus[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static MobytUserStatus[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static MobytUserStatus[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static MobytUserStatus[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static MobytUserStatus[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class MobytUserStatusFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return MobytUserStatus::class;
+    }
+}

+ 61 - 0
tests/Fixture/Factory/Network/NetworkFactory.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Network;
+
+use App\Entity\Network\Network;
+use Zenstruck\Foundry\ModelFactory;
+
+/**
+ * @extends ModelFactory<Network>
+ *
+ * @phpstan-method        Network|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static Network|Proxy createOne(array $attributes = [])
+ * @phpstan-method static Network|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static Network|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static Network|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static Network|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static Network|Proxy random(array $attributes = [])
+ * @phpstan-method static Network|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static NetworkRepository|RepositoryProxy repository()
+ * @phpstan-method static Network[]|Proxy[] all()
+ * @phpstan-method static Network[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static Network[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static Network[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static Network[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static Network[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class NetworkFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return Network::class;
+    }
+}

+ 62 - 0
tests/Fixture/Factory/Network/NetworkOrgnizationFactory.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Network;
+
+use App\Entity\Network\Network;
+use Zenstruck\Foundry\ModelFactory;
+use App\Entity\Network\NetworkOrganization;
+
+/**
+ * @extends ModelFactory<Network>
+ *
+ * @phpstan-method        NetworkOrganization|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static NetworkOrganization|Proxy createOne(array $attributes = [])
+ * @phpstan-method static NetworkOrganization|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static NetworkOrganization|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static NetworkOrganization|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static NetworkOrganization|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static NetworkOrganization|Proxy random(array $attributes = [])
+ * @phpstan-method static NetworkOrganization|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static NetworkOrganizationRepository|RepositoryProxy repository()
+ * @phpstan-method static NetworkOrganization[]|Proxy[] all()
+ * @phpstan-method static NetworkOrganization[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static NetworkOrganization[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static NetworkOrganization[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static NetworkOrganization[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static NetworkOrganization[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class NetworkOrganizationFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return NetworkOrganization::class;
+    }
+}

+ 65 - 0
tests/Fixture/Factory/Organization/ParametersFactory.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Organization;
+
+use App\Entity\Organization\Parameters;
+use App\Entity\Organization\Settings;
+use App\Tests\Fixture\Factory\Person\PersonRepository;
+use Zenstruck\Foundry\RepositoryProxy;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<Parameters>
+ *
+ * @phpstan-method        Parameters|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static Parameters|Proxy createOne(array $attributes = [])
+ * @phpstan-method static Parameters|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static Parameters|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static Parameters|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static Parameters|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static Parameters|Proxy random(array $attributes = [])
+ * @phpstan-method static Parameters|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static ParametersRepository|RepositoryProxy repository()
+ * @phpstan-method static Parameters[]|Proxy[] all()
+ * @phpstan-method static Parameters[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static Parameters[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static Parameters[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static Parameters[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static Parameters[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class ParametersFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return Parameters::class;
+    }
+}

+ 62 - 0
tests/Fixture/Factory/Organization/SubdomainFactory.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Organization;
+
+use App\Entity\Education\EducationCategory;
+use App\Entity\Organization\Subdomain;
+use Zenstruck\Foundry\ModelFactory;
+
+/**
+ * @extends ModelFactory<EducationCategory>
+ *
+ * @phpstan-method        Subdomain|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static Subdomain|Proxy createOne(array $attributes = [])
+ * @phpstan-method static Subdomain|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static Subdomain|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static Subdomain|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static Subdomain|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static Subdomain|Proxy random(array $attributes = [])
+ * @phpstan-method static Subdomain|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static SubdomainRepository|RepositoryProxy repository()
+ * @phpstan-method static Subdomain[]|Proxy[] all()
+ * @phpstan-method static Subdomain[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static Subdomain[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static Subdomain[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static Subdomain[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static Subdomain[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class SubdomainFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return Subdomain::class;
+    }
+}

+ 253 - 68
tests/Fixture/OrganizationFixtures.php

@@ -2,92 +2,252 @@
 
 namespace App\Tests\Fixture;
 
+use DateTime;
+use App\Service\Utils\Uuid;
+use App\Entity\Access\Access;
 use App\Entity\Booking\Event;
-use App\Entity\Core\ContactPoint;
+use App\Entity\Person\Person;
+use Doctrine\DBAL\Connection;
+use App\Entity\Education\Cycle;
 use App\Entity\Network\Network;
-use App\Entity\Network\NetworkOrganization;
-use App\Entity\Organization\Organization;
-use App\Entity\Organization\Parameters;
+use App\Enum\Core\TimeZoneEnum;
+use App\Entity\Core\ContactPoint;
+use App\Enum\Education\CycleEnum;
+use App\Entity\Education\Education;
 use App\Enum\Booking\VisibilityEnum;
-use App\Enum\Core\ContactPointTypeEnum;
 use App\Enum\Organization\LegalEnum;
-use App\Enum\Organization\PrincipalTypeEnum;
-use App\Service\Utils\Uuid;
-use Doctrine\Bundle\FixturesBundle\Fixture;
+use App\Entity\Billing\AccessBilling;
+use App\Entity\Billing\ResidenceArea;
+use App\Entity\Organization\Settings;
+use App\Entity\Billing\BillingSetting;
+use App\Entity\Organization\Subdomain;
+use App\Entity\Organization\Parameters;
+use App\Enum\Core\ContactPointTypeEnum;
+use App\Enum\Education\PeriodicityEnum;
 use Doctrine\Persistence\ObjectManager;
+use Doctrine\ORM\EntityManagerInterface;
+use App\Entity\Education\EducationTiming;
+use App\Entity\Organization\Organization;
+use App\Entity\Education\CycleByEducation;
+use App\Entity\Education\EducationCategory;
+use Doctrine\Bundle\FixturesBundle\Fixture;
+use App\Enum\Organization\PrincipalTypeEnum;
+use App\Entity\Education\EducationComplement;
+use App\Entity\Education\EducationCurriculum;
+use App\Entity\Education\EducationStudent;
+use App\Enum\Organization\BulletinOutputEnum;
+use App\Enum\Organization\BulletinPeriodEnum;
+use App\Enum\Organization\SendToBulletinEnum;
+use App\Enum\Organization\SettingsProductEnum;
+use Doctrine\Common\DataFixtures\Purger\ORMPurger;
+use App\Enum\Education\AdvancedEducationNotationTypeEnum;
+use App\Enum\Organization\BulletinCriteriaSortEnum;
+use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
 
-class OrganizationFixtures extends Fixture
+class OrganizationFixtures extends Fixture  
 {
+    protected EntityManagerInterface $em;
+    private Connection $connection;
+
+    public function __construct(EntityManagerInterface $em, Connection $connection)
+    {
+        $this->em = $em;
+        $this->connection = $connection;
+    }
+
+    public static function getGroups(): array
+    {
+        return ['poc'];
+    }
+
+    public function purgeDb(): void
+    {
+        // Exécutez la requête SQL brute pour effectuer un TRUNCATE FORCE
+        $tableName = $this->em->getClassMetadata(Organization::class)->getTableName();
+        $truncateSql = "TRUNCATE TABLE $tableName";
+        $this->connection->executeQuery($truncateSql);
+
+        $accessTable = $this->em->getClassMetadata(Access::class)->getTableName();
+        $truncateSql = "TRUNCATE TABLE $accessTable";
+        $this->connection->executeQuery($truncateSql);
+    }
+
+
     public function load(ObjectManager $em): void
     {
+
+        // Purge DB before populating new fixtures
+        // $this->purgeDb();
+        // create an organization with a network, legal status accesses, Param , name, id and settings
         $network = new Network();
         $network->setName('NET');
         $em->persist($network);
 
-        // Create the root organization (opentalent)
-        $parameters0 = new Parameters();
-        $em->persist($parameters0);
-
         $contactPoint0 = new ContactPoint();
-        $contactPoint0->setContactType(ContactPointTypeEnum::PRINCIPAL()->getValue());
+        $contactPoint0->setContactType(ContactPointTypeEnum::PRINCIPAL);
         $em->persist($contactPoint0);
 
+        // Create the root organization (opentalent)
         $root = new Organization();
         $root->setName('Root');
-        $root->setLegalStatus(LegalEnum::COMMERCIAL_SOCIETY()->getValue());
-        $root->setPrincipalType(PrincipalTypeEnum::NATIONAL_FEDERATION()->getValue());
-        $root->setParameters($parameters0);
+        $root->setLegalStatus(LegalEnum::ASSOCIATION_LAW_1901);
+        $root->setPrincipalType(PrincipalTypeEnum::NATIONAL_FEDERATION);
         $root->addContactPoint($contactPoint0);
-        $em->persist($root);
 
-        $networkOrganisation0 = new NetworkOrganization();
-        $networkOrganisation0->setOrganization($root);
-        $networkOrganisation0->setNetwork($network);
-        $em->persist($networkOrganisation0);
-
-        // Create a federation organization
-        $parameters1 = new Parameters();
-        $em->persist($parameters1);
-
-        $contactPoint1 = new ContactPoint();
-        $contactPoint1->setContactType(ContactPointTypeEnum::PRINCIPAL()->getValue());
-        $em->persist($contactPoint1);
-
-        $fede = new Organization();
-        $fede->setName('Fede 1');
-        $fede->setLegalStatus(LegalEnum::ASSOCIATION_LAW_1901()->getValue());
-        $fede->setPrincipalType(PrincipalTypeEnum::NATIONAL_FEDERATION()->getValue());
-        $fede->setParameters($parameters1);
-        $fede->addContactPoint($contactPoint1);
-        $em->persist($fede);
-
-        $networkOrganisation1 = new NetworkOrganization();
-        $networkOrganisation1->setOrganization($fede);
-        $networkOrganisation1->setNetwork($network);
-        $networkOrganisation1->setParent($root);
-        $em->persist($networkOrganisation1);
-
-        // Create a simple organization
-        $parameters2 = new Parameters();
-        $em->persist($parameters2);
-
-        $contactPoint2 = new ContactPoint();
-        $contactPoint2->setContactType(ContactPointTypeEnum::PRINCIPAL()->getValue());
-        $em->persist($contactPoint2);
-
-        $organization = new Organization();
-        $organization->setName('Organization 2');
-        $organization->setLegalStatus(LegalEnum::ASSOCIATION_LAW_1901()->getValue());
-        $organization->setPrincipalType(PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY()->getValue());
-        $organization->setParameters($parameters2);
-        $organization->addContactPoint($contactPoint2);
-        $em->persist($organization);
-
-        $networkOrganisation2 = new NetworkOrganization();
-        $networkOrganisation2->setOrganization($organization);
-        $networkOrganisation2->setNetwork($network);
-        $networkOrganisation2->setParent($fede);
-        $em->persist($networkOrganisation2);
+        // subdomain fixtures
+        $subdomain = new Subdomain();
+        $subdomain->setOrganization($root);
+        $subdomain->setSubdomain('subdomain');
+        $subdomain->setActive(true);
+
+        $parameters = new Parameters();
+        $parameters->setFinancialDate(new DateTime());
+        $parameters->setMusicalDate(new DateTime());
+        $parameters->setStartCourseDate(new DateTime());
+        $parameters->setEndCourseDate(new DateTime());
+        $parameters->setAverage(20);
+        $parameters->setEditCriteriaNotationByAdminOnly(true);
+        $parameters->setSmsSenderName('MySender');
+        $parameters->setLogoDonorsMove(false);
+        $parameters->setSubDomain('subdomain');
+        $parameters->setWebsite('https://www.example.com');
+        $parameters->setOtherWebsite('https://www.otherwebsite.com');
+        $parameters->setCustomDomain('https://www.customdomain.com');
+        $parameters->setDesactivateOpentalentSiteWeb(false);
+        $parameters->setBulletinPeriod(BulletinPeriodEnum::YEAR);
+        $parameters->setBulletinWithTeacher(false);
+        $parameters->setBulletinPrintAddress(false);
+        $parameters->setBulletinSignatureDirector(true);
+        $parameters->setBulletinDisplayLevelAcquired(true);
+        $parameters->setBulletinShowEducationWithoutEvaluation(false);
+        $parameters->setBulletinViewTestResults(false);
+        $parameters->setBulletinShowAbsences(false);
+        $parameters->setBulletinShowAverages(true);
+        $parameters->setBulletinOutput(BulletinOutputEnum::SEND_BY_EMAIL);
+        $parameters->setBulletinEditWithoutEvaluation(true);
+        $parameters->setBulletinReceiver(SendToBulletinEnum::STUDENTS_AND_THEIR_GUARDIANS);
+        $parameters->setBulletinCriteriaSort(BulletinCriteriaSortEnum::ALPHANUM);
+        $parameters->setUsernameSMS('username');
+        $parameters->setPasswordSMS('password');
+        $parameters->setShowAdherentList(true);
+        $parameters->setStudentsAreAdherents(false);
+        $parameters->setTimezone(TimeZoneEnum::EUROPE_PARIS);
+        $parameters->setEducationPeriodicity(PeriodicityEnum::MONTHLY);
+        $parameters->setAdvancedEducationNotationType(AdvancedEducationNotationTypeEnum::BY_EDUCATION);
+        $parameters->setSendAttendanceEmail(false);
+        $parameters->setSendAttendanceSms(false);
+        $parameters->setGenerateAttendanceReport(true);
+        $parameters->setConsultPedagogicResult(true);
+        $parameters->setConsultTeacherListing(true);
+        $parameters->setPeriodValidation(true);
+        $parameters->setNotifyAdministrationAbsence(false);
+        $root->setParameters($parameters);
+
+        // settings fixtures
+        $settings = new Settings();
+        $settings->setProduct(SettingsProductEnum::SCHOOL);
+        $settings->setModules(['BillingAdministration']);
+        $root->setSettings($settings);
+
+        //create acesses with orga
+        $access = new Access();
+        $access->setOrganization($root);
+        $access->setRoles(["ROLE_ADMIN","ROLE_ADMIN_CORE","ROLE_SUPER_ADMIN"]);
+
+        $teacherAccess = new Access();
+        $teacherAccess->setOrganization($root);
+        $teacherAccess->setRoles(["ROLE_TEACHER"]);
+
+        // create a person :
+        $person = new Person();
+        $person->addAccess($access);
+        $person->setUsername('username');
+        $person->setPassword('password');
+
+        // create BillingSetting with an organization
+        $billingSetting = new BillingSetting();
+        $billingSetting->setOrganization($root);
+        $em->persist($billingSetting);
+
+        // résidence area
+        $residenceArea = new ResidenceArea();
+        $residenceArea->setLabel('label');
+        $residenceArea->setBillingSetting($billingSetting);
+
+        //create an AccessBilling with an access
+        $accessBilling = new AccessBilling();
+        $accessBilling->setAccess($access);
+        $accessBilling->setResidenceArea($residenceArea);
+
+        // Création de quelques cycles
+        $cycle1 = new Cycle();
+        $cycle1->setOrganization($root);
+        $cycle1->setLabel('Cycle 1');
+        $cycle1->setCycleEnum(CycleEnum::CYCLE_1);
+
+        $cycle2 = new Cycle();
+        $cycle2->setOrganization($root);
+        $cycle2->setLabel('Cycle 2');
+        $cycle2->setCycleEnum(CycleEnum::CYCLE_2);
+
+        // Création de l'entité EducationCategory
+        $educationCategory = new EducationCategory();
+        $educationCategory->setOrganization($root);
+
+        // Création de l'entité EducationComplement
+        $educationComplement = new EducationComplement();
+
+        // Création d'une Education
+        $education = new Education();
+        $education->setEducationCategory($educationCategory);
+        $education->setEducationComplement($educationComplement);
+
+        // Création d'un CycleByEducation
+        $cycleByEducation = new CycleByEducation();
+        $cycleByEducation->setCycle($cycle1);
+        $cycleByEducation->setEducation($education);
+
+        // Ajout de cycleByEducation à cycle et education
+        $cycle1->addCycleByEducation($cycleByEducation);
+        $education->addCycleByEducation($cycleByEducation);
+
+        $educationCurriculum = new EducationCurriculum();
+        $educationTimings= new EducationTiming();
+        $educationTimings->setTiming(45);
+        $educationTimings->setOrganization($root);
+        $educationStudent = new EducationStudent();
+        $educationTimings->addEducationStudent($educationStudent);
+        $educationTimings->addEducationCurriculum($educationCurriculum);
+        $educationCurriculum->setCycle($cycle1);
+
+
+
+        // // education complément
+        // $educationComplement = new EducationComplement();
+        // $education = (new Education());
+        // $educationCategory = new EducationCategory();
+        // $educationCategory->setOrganization($root);
+        // // $educationCurriculum = new EducationCurriculum();
+
+        // // $education->setEducationComplement($educationComplement);
+        // // $educationCategory->setOrganization($root);
+        // // $educationCategory->addEducation($education);
+        // $education->setEducationCategory($educationCategory);
+        // $education->setEducationComplement($educationComplement);
+        // $cycleByEducation = new CycleByEducation();
+
+        // // Cycle
+        // $cycle = new Cycle();
+        // $cycle->setOrganization($root);
+        // $cycle->setCycleEnum(CycleEnum::INITIATION_CYCLE);
+        // $cycle->setIsSystem(false);
+        // $cycle->setLabel('toto');
+        // $cycle->setOrder(1);
+
+        // // $cycleByEducation->setEducation();
+        // $cycle->addCycleByEducation($cycleByEducation);
+        // $cycle->setIsSystem(false);
+        // $em->persist($cycle);
 
         // Booking
         $now = new \DateTime('now');
@@ -95,14 +255,39 @@ class OrganizationFixtures extends Fixture
         $end = $now->add(new \DateInterval('P1M1D'));
 
         $event = new Event();
-        $event->setOrganization($organization);
+        $event->setOrganization($root);
         $event->setName('My Event');
         $event->setDatetimeStart($start);
         $event->setDatetimeEnd($end);
-        $event->setVisibility(VisibilityEnum::PUBLIC_VISIBILITY());
+        $event->setVisibility(VisibilityEnum::PUBLIC_VISIBILITY);
         $event->setUuid(Uuid::uuid());
+
+        $em->persist($cycle1);
+        $em->persist($cycle2);
+        $em->persist($educationCategory);
+        $em->persist($educationComplement);
+        $em->persist($education);
+        $em->persist($cycleByEducation);
+
+        // $em->persist($educationComplement);
+        // $em->persist($educationCurriculum);
+        // $em->persist($educationCategory);
+        // $em->persist($education);
+        // $em->persist($cycleByEducation);
+
+        $em->persist($root);
         $em->persist($event);
+        $em->persist($person);
+        $em->persist($access);
+        $em->persist($accessBilling);
+        $em->persist($billingSetting);
+        $em->persist($residenceArea);
+        $em->persist($subdomain);
+        $em->persist($parameters);
 
         $em->flush();
+
+        // A circular reference has been detected when serializing the object of
+        // class \u0022App\\Entity\\Education\\CycleByEducation\u0022
     }
 }

+ 42 - 7
tests/Fixture/readme.md

@@ -1,16 +1,51 @@
 # Générer la DB de test et charger les fixtures
 
-Pour regénérer le SQL de création de la DB de test :
+## Regénérer le SQL de création de la DB de test
 
-    mysqldump --user=root --password=mysql660 --host=localhost --port=3306 --default-character-set=utf8 --single-transaction=TRUE --no-data --skip-triggers "opentalent" --column-statistics=0 > opentalent_test.sql
+Pour regénérer le SQL de la base de données de test, suivez ces étapes :
 
-    mysql --user=root --password=mysql660 --host=127.0.0.1 --port=3306 -D opentalent_test < opentalent_test.sql
+1. Connectez-vous à MySQL dans le docker mariaDb :
 
-Il peut être nécessaire de regénérer les vues :
+   ```bash
+   mysql --user=root --password=mysql660 --host=127.0.0.1 --port=3306
+   DROP DATABASE IF EXISTS opentalent_test; EXIT;
 
-    bin/console --env=staging doctrine:schema:update
+   mysqldump --user=root --password=mysql660 --host=localhost --port=3306 --default-character-set=utf8 --single-transaction=TRUE --no-data --skip-triggers "opentalent" | sed 's/ AUTO_INCREMENT=[0-9]*//g' > opentalent_test.sql
 
+   mysql --user=root --password=mysql660 --host=127.0.0.1 --port=3306
+   CREATE DATABASE opentalent_test;
+   EXIT;
 
-Pour recharger les fixtures :
+   mysql --user=root --password=mysql660 --host=127.0.0.1 --port=3306 -D opentalent_test < opentalent_test.sql
 
-    bin/console --env=staging doctrine:fixtures:load
+   ```
+
+2. Dans le docker ap2i :
+   Regénérer les vues et jouer les fixtures
+
+   ```bash
+   bin/console --env=staging doctrine:schema:update
+   bin/console --env=staging d:f:l
+   ```
+
+3. Pour lancer les tests :
+
+   ```bash
+   php bin/phpunit
+   ```
+
+   ou mettre le path relatif :
+
+   ```bash
+   php bin/phpunit tests/Application/PublicEventsTest.php
+   ```
+
+   php bin/phpunit tests/Application/Person/PersonTest.php
+   php bin/phpunit tests/Application/Profile/AccessProfileTest.php
+   php bin/phpunit tests/Application/Utils/GpsCoordinateTest.php
+   php bin/phpunit tests/Application/Enum/EnumTest.php
+   php bin/phpunit tests/Application/Mobyt/MobytUserStatusTest.php
+   php bin/phpunit tests/Application/Organization/ParametersTest.php
+
+// option sms : settings -> id 3600 
+// cotisation -> network Organization -> cmf

+ 9 - 2
tests/Unit/Service/Security/ModuleTest.php

@@ -4,15 +4,19 @@ namespace App\Tests\Unit\Service\Security;
 
 use App\Entity\Organization\Organization;
 use App\Entity\Organization\Settings;
-use App\Enum\Organization\SettingsProductEnum;
 use App\Service\Cotisation\Utils as CotisationUtils;
 use App\Service\Security\Module;
 use App\Service\Utils\Reflection;
 use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
-use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
+class TestableModule extends Module
+{
+    public function getModuleByConditionsConfig(): array
+    {
+        return parent::getModuleByConditionsConfig();
+    }
 class TestableModule extends Module
 {
     public function getModuleByConditionsConfig(): array
@@ -26,6 +30,7 @@ class ModuleTest extends TestCase
     private MockObject|Reflection $reflection;
     private MockObject|ParameterBagInterface $parameterBag;
 
+    public function setUp(): void
     public function setUp(): void
     {
         $this->reflection = $this->getMockBuilder(Reflection::class)->disableOriginalConstructor()->getMock();
@@ -150,6 +155,7 @@ class ModuleTest extends TestCase
         $this->assertEquals(['foo'], $module->getModulesByProductConfiguration(SettingsProductEnum::ARTIST));
     }
 
+
     /**
      * @see Module::getModulesByProductConfiguration()
      */
@@ -170,6 +176,7 @@ class ModuleTest extends TestCase
         );
     }
 
+
     /**
      * @see Module::getModulesByProductConfiguration()
      */