فهرست منبع

Merge branch 'release/0.1.0'

Vincent GUFFON 4 سال پیش
والد
کامیت
c3210e0c37
67فایلهای تغییر یافته به همراه3564 افزوده شده و 215 حذف شده
  1. 4 0
      .env
  2. 3 0
      composer.json
  3. 418 2
      composer.lock
  4. 174 0
      config/opentalent/enum.yaml
  5. 5 0
      config/packages/framework.yaml
  6. 1 1
      config/packages/security.yaml
  7. 1 1
      config/packages/security/billing.yaml
  8. 5 7
      config/packages/security/booking.yaml
  9. 1 1
      config/packages/security/donors.yaml
  10. 1 2
      config/packages/security/equipments.yaml
  11. 3 12
      config/packages/security/generalConfig.yaml
  12. 1 1
      config/packages/security/medals.yaml
  13. 2 4
      config/packages/security/pedagogics.yaml
  14. 2 1
      config/packages/security/users.yaml
  15. 3 2
      config/services.yaml
  16. 5 5
      config/services/apiPlatform.yaml
  17. 0 11
      config/services/dataPersisters.yaml
  18. 56 0
      src/ApiResources/Enum/Enum.php
  19. 6 6
      src/ApiResources/Profile/AccessProfile.php
  20. 21 8
      src/ApiResources/Profile/OrganizationProfile.php
  21. 54 0
      src/ApiResources/Utils/Siret.php
  22. 0 36
      src/DataPersister/Common/OpentalentDataPersister.php
  23. 5 1
      src/DataProvider/Access/AccessProfileDataProvider.php
  24. 0 37
      src/DataProvider/Common/OpentalentCollectionDataProvider.php
  25. 0 34
      src/DataProvider/Common/OpentalentItemDataProvider.php
  26. 67 0
      src/DataProvider/Enum/EnumDataProvider.php
  27. 38 0
      src/DataProvider/Utils/SiretDataProvider.php
  28. 40 6
      src/Entity/Access/Access.php
  29. 202 0
      src/Entity/Core/AddressPostal.php
  30. 285 0
      src/Entity/Core/BankAccount.php
  31. 273 0
      src/Entity/Core/ContactPoint.php
  32. 41 0
      src/Entity/Core/Country.php
  33. 2 1
      src/Entity/Network/NetworkOrganization.php
  34. 715 6
      src/Entity/Organization/Organization.php
  35. 83 0
      src/Entity/Organization/OrganizationAddressPostal.php
  36. 114 0
      src/Entity/Organization/OrganizationLicence.php
  37. 34 0
      src/Entity/Person/Person.php
  38. 30 0
      src/Enum/Core/ContactPointTypeEnum.php
  39. 16 0
      src/Enum/Organization/AddressPostalOrganizationTypeEnum.php
  40. 19 0
      src/Enum/Organization/CategoryEnum.php
  41. 16 0
      src/Enum/Organization/LegalEnum.php
  42. 39 0
      src/Enum/Organization/OpcaEnum.php
  43. 20 0
      src/Enum/Organization/SchoolCategoryEnum.php
  44. 14 0
      src/Enum/Organization/TypeEstablishmentDetailEnum.php
  45. 15 0
      src/Enum/Organization/TypeEstablishmentEnum.php
  46. 50 0
      src/Repository/Core/AddressPostalRepository.php
  47. 50 0
      src/Repository/Core/BankAccountRepository.php
  48. 50 0
      src/Repository/Core/ContactPointRepository.php
  49. 50 0
      src/Repository/Core/CountryRepository.php
  50. 50 0
      src/Repository/Organization/OrganizationAddressPostalRepository.php
  51. 50 0
      src/Repository/Organization/OrganizationLicenceRepository.php
  52. 62 0
      src/Security/Voter/BankAccountVoter.php
  53. 62 0
      src/Security/Voter/ContactPointVoter.php
  54. 2 2
      src/Security/Voter/ModuleVoter.php
  55. 57 0
      src/Serializer/OpentalentNormalizer.php
  56. 1 6
      src/Service/Network/Tree.php
  57. 12 13
      src/Service/Security/Module.php
  58. 28 0
      src/Service/Utils/Dates.php
  59. 32 0
      src/Service/Utils/Parser.php
  60. 22 5
      src/Service/Utils/Reflection.php
  61. 38 0
      src/Service/Utils/Siret.php
  62. 15 0
      symfony.lock
  63. 9 4
      tests/Service/Security/ModuleTest.php
  64. 27 0
      tests/Service/Utils/DatesTest.php
  65. 22 0
      tests/Service/Utils/ParserTest.php
  66. 32 0
      tests/Service/Utils/SiretTest.php
  67. 9 0
      tests/Service/Utils/fixtures/fixture.yaml

+ 4 - 0
.env

@@ -45,3 +45,7 @@ BLACKFIRE_CLIENT_TOKEN=8cfbeb263d044da9678dc2612531504da3790c308da7448e35724a5da
 BLACKFIRE_SERVER_ID=1171e53b-459b-41da-a292-80ff68cee8c2
 BLACKFIRE_SERVER_TOKEN=dbd1cfbea015fe83cccfc189a36ca3c16f3a1b43b94f50032a15e41e53548e8b
 ###< BlackFire configuration ###
+
+###> opentalent config folder ###
+OPENTALENT_CONFIG=/config/opentalent
+###< opentalent config folder ###

+ 3 - 0
composer.json

@@ -18,6 +18,7 @@
         "doctrine/doctrine-bundle": "^2.1",
         "doctrine/doctrine-migrations-bundle": "^3.0",
         "doctrine/orm": "^2.7",
+        "egulias/email-validator": "^3.0",
         "jbouzekri/phumbor-bundle": "^2.1",
         "lexik/jwt-authentication-bundle": "^2.8",
         "myclabs/php-enum": "^1.7",
@@ -30,6 +31,8 @@
         "symfony/expression-language": "5.2.*",
         "symfony/flex": "^1.3.1",
         "symfony/framework-bundle": "5.2.*",
+        "symfony/http-client": "5.2.*",
+        "symfony/intl": "5.2.*",
         "symfony/property-access": "5.2.*",
         "symfony/property-info": "5.2.*",
         "symfony/security-bundle": "5.2.*",

+ 418 - 2
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "78e315177bdaef6835ad89b8d33ca753",
+    "content-hash": "23f47743189511f32a5c5690792332dc",
     "packages": [
         {
             "name": "api-platform/core",
@@ -1630,6 +1630,74 @@
             ],
             "time": "2020-07-30T16:57:33+00:00"
         },
+        {
+            "name": "egulias/email-validator",
+            "version": "3.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/egulias/EmailValidator.git",
+                "reference": "e5df72f45f0ba585a278ce02607b8b542aabfec7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/e5df72f45f0ba585a278ce02607b8b542aabfec7",
+                "reference": "e5df72f45f0ba585a278ce02607b8b542aabfec7",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/lexer": "^1.2",
+                "php": ">=7.2",
+                "symfony/polyfill-intl-idn": "^1.15"
+            },
+            "require-dev": {
+                "php-coveralls/php-coveralls": "^2.2",
+                "phpunit/phpunit": "^8.5.8|^9.3.3",
+                "vimeo/psalm": "^4"
+            },
+            "suggest": {
+                "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Egulias\\EmailValidator\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Eduardo Gulias Davis"
+                }
+            ],
+            "description": "A library for validating emails against several RFCs",
+            "homepage": "https://github.com/egulias/EmailValidator",
+            "keywords": [
+                "email",
+                "emailvalidation",
+                "emailvalidator",
+                "validation",
+                "validator"
+            ],
+            "support": {
+                "issues": "https://github.com/egulias/EmailValidator/issues",
+                "source": "https://github.com/egulias/EmailValidator/tree/3.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/egulias",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-12-29T15:04:19+00:00"
+        },
         {
             "name": "fig/link-util",
             "version": "1.1.1",
@@ -4369,6 +4437,92 @@
             ],
             "time": "2021-01-27T11:19:04+00:00"
         },
+        {
+            "name": "symfony/http-client",
+            "version": "v5.2.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/http-client.git",
+                "reference": "c7d1f35a31ef153a302e3f80336170e1280b983d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/http-client/zipball/c7d1f35a31ef153a302e3f80336170e1280b983d",
+                "reference": "c7d1f35a31ef153a302e3f80336170e1280b983d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "psr/log": "^1.0",
+                "symfony/http-client-contracts": "^2.2",
+                "symfony/polyfill-php73": "^1.11",
+                "symfony/polyfill-php80": "^1.15",
+                "symfony/service-contracts": "^1.0|^2"
+            },
+            "provide": {
+                "php-http/async-client-implementation": "*",
+                "php-http/client-implementation": "*",
+                "psr/http-client-implementation": "1.0",
+                "symfony/http-client-implementation": "2.2"
+            },
+            "require-dev": {
+                "amphp/amp": "^2.5",
+                "amphp/http-client": "^4.2.1",
+                "amphp/http-tunnel": "^1.0",
+                "amphp/socket": "^1.1",
+                "guzzlehttp/promises": "^1.4",
+                "nyholm/psr7": "^1.0",
+                "php-http/httplug": "^1.0|^2.0",
+                "psr/http-client": "^1.0",
+                "symfony/dependency-injection": "^4.4|^5.0",
+                "symfony/http-kernel": "^4.4.13|^5.1.5",
+                "symfony/process": "^4.4|^5.0",
+                "symfony/stopwatch": "^4.4|^5.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\HttpClient\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/http-client/tree/v5.2.4"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-03-01T00:40:14+00:00"
+        },
         {
             "name": "symfony/http-client-contracts",
             "version": "v2.3.1",
@@ -4624,6 +4778,94 @@
             ],
             "time": "2021-01-27T14:45:46+00:00"
         },
+        {
+            "name": "symfony/intl",
+            "version": "v5.2.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/intl.git",
+                "reference": "930f17689729cc47d2ce18be21ed403bcbeeb6a9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/intl/zipball/930f17689729cc47d2ce18be21ed403bcbeeb6a9",
+                "reference": "930f17689729cc47d2ce18be21ed403bcbeeb6a9",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-intl-icu": "~1.0",
+                "symfony/polyfill-php80": "^1.15"
+            },
+            "require-dev": {
+                "symfony/filesystem": "^4.4|^5.0"
+            },
+            "suggest": {
+                "ext-intl": "to use the component with locales other than \"en\""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Intl\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ],
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@gmail.com"
+                },
+                {
+                    "name": "Eriksen Costa",
+                    "email": "eriksen.costa@infranology.com.br"
+                },
+                {
+                    "name": "Igor Wiedler",
+                    "email": "igor@wiedler.ch"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides a PHP replacement layer for the C intl extension that includes additional data from the ICU library",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "i18n",
+                "icu",
+                "internationalization",
+                "intl",
+                "l10n",
+                "localization"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/intl/tree/v5.2.3"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-01-27T10:01:46+00:00"
+        },
         {
             "name": "symfony/polyfill-intl-grapheme",
             "version": "v1.22.0",
@@ -4702,6 +4944,180 @@
             ],
             "time": "2021-01-07T16:49:33+00:00"
         },
+        {
+            "name": "symfony/polyfill-intl-icu",
+            "version": "v1.22.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-intl-icu.git",
+                "reference": "af1842919c7e7364aaaa2798b29839e3ba168588"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/af1842919c7e7364aaaa2798b29839e3ba168588",
+                "reference": "af1842919c7e7364aaaa2798b29839e3ba168588",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "suggest": {
+                "ext-intl": "For best performance and support of other locales than \"en\""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.22-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Intl\\Icu\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ],
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for intl's ICU-related data and classes",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "icu",
+                "intl",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.22.1"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-01-22T09:19:47+00:00"
+        },
+        {
+            "name": "symfony/polyfill-intl-idn",
+            "version": "v1.22.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-intl-idn.git",
+                "reference": "2d63434d922daf7da8dd863e7907e67ee3031483"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483",
+                "reference": "2d63434d922daf7da8dd863e7907e67ee3031483",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1",
+                "symfony/polyfill-intl-normalizer": "^1.10",
+                "symfony/polyfill-php72": "^1.10"
+            },
+            "suggest": {
+                "ext-intl": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.22-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Intl\\Idn\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Laurent Bassin",
+                    "email": "laurent@bassin.info"
+                },
+                {
+                    "name": "Trevor Rowbotham",
+                    "email": "trevor.rowbotham@pm.me"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "idn",
+                "intl",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-01-22T09:19:47+00:00"
+        },
         {
             "name": "symfony/polyfill-intl-normalizer",
             "version": "v1.22.0",
@@ -7297,5 +7713,5 @@
         "ext-iconv": "*"
     },
     "platform-dev": [],
-    "plugin-api-version": "1.1.0"
+    "plugin-api-version": "2.0.0"
 }

+ 174 - 0
config/opentalent/enum.yaml

@@ -0,0 +1,174 @@
+opentalent:
+  #AccessAndFunction
+    function: 'App\Enum\AccessAndFunction\FunctionEnum'
+    function_activities: 'App\Enum\AccessAndFunction\ActivitiesFunctionEnum'
+    function_administratives: 'App\Enum\AccessAndFunction\AdministrativesFunctionEnum'
+    function_associatives: 'App\Enum\AccessAndFunction\AssociativesFunctionEnum'
+    function_departures_cause: 'App\Enum\AccessAndFunction\DeparturesCauseEnum'
+    function_pedagogics: 'App\Enum\AccessAndFunction\PedagogicsFunctionEnum'
+    function_other: 'App\Enum\AccessAndFunction\OtherFunctionEnum'
+    function_type: 'App\Enum\AccessAndFunction\TypeFunctionEnum'
+    license_type: 'App\Enum\AccessAndFunction\LicenseTypeEnum'
+    license_rate: 'App\Enum\AccessAndFunction\LicenseRateEnum'
+    function_role: 'App\Enum\AccessAndFunction\FunctionalRoleEnum'
+
+  #AccessSocial
+    professional_status: 'App\Enum\AccessSocial\ProfessionalStatusEnum'
+    type_of_contact: 'App\Enum\AccessSocial\TypeOfContractEnum'
+    assisted_contract: 'App\Enum\AccessSocial\AssistedContractEnum'
+    period_unit: 'App\Enum\AccessSocial\PeriodUnitEnum'
+    family_situation: 'App\Enum\AccessSocial\FamilySituationEnum'
+
+  #Core
+    address_postal_person: 'App\Enum\Core\AddressPostalPersonTypeEnum'
+    address_postal_organization: 'App\Enum\Organization\AddressPostalOrganizationTypeEnum'
+    period: 'App\Enum\Core\PeriodEnum'
+    action_status_type: 'App\Enum\Core\ActionStatusTypeEnum'
+    control_type: 'App\Enum\Core\ControlTypeEnum'
+    repair_type: 'App\Enum\Core\RepairTypeEnum'
+    contact_point_type: 'App\Enum\Core\ContactPointTypeEnum'
+    contact_point_type_person: 'App\Enum\Core\ContactPointTypePersonEnum'
+    appreciation: 'App\Enum\Core\AppreciationEnum'
+    semester: 'App\Enum\Core\SemesterEnum'
+    trimester: 'App\Enum\Core\TrimesterEnum'
+    month: 'App\Enum\Core\MonthEnum'
+    notification_type: 'App\Enum\Core\NotificationTypeEnum'
+    tips_priority_level: 'App\Enum\Core\PriorityLevelEnum'
+    tips_type_person: 'App\Enum\Core\TipsTypePersonEnum'
+    tips_network: 'App\Enum\Core\TipsNetworkEnum'
+    tips_product: 'App\Enum\Core\TipsProductEnum'
+    days_enum: 'App\Enum\Core\DaysEnum'
+    timezone: 'App\Enum\Core\TimeZoneEnum'
+    tagtextcolor: 'App\Enum\Core\TagTextColorEnum'
+    tips_legalstatus: 'App\Enum\Core\TipsLegalStatusEnum'
+
+  #Donor
+    donor_displayed_on: 'App\Enum\Donor\DonorDisplayedOnEnum'
+    donor_status: 'App\Enum\Donor\DonorStatusEnum'
+
+  #Network
+    network_leading: 'App\Enum\Network\LeadingCauseEnum'
+    network: 'App\Enum\Network\NetworkEnum'
+
+  #Organization
+    organization_category: 'App\Enum\Organization\CategoryEnum'
+    organization_financial: 'App\Enum\Organization\financialEnum'
+    organization_legal: 'App\Enum\Organization\LegalEnum'
+    organization_opca: 'App\Enum\Organization\opcaEnum'
+    organization_principal_type: 'App\Enum\Organization\principalTypeEnum'
+    organization_school_cat: 'App\Enum\Organization\schoolCategoryEnum'
+    organization_type_establishment_detail: 'App\Enum\Organization\typeEstablishmentDetailEnum'
+    organization_type_establishment: 'App\Enum\Organization\typeEstablishmentEnum'
+    organization_familly_type: 'App\Enum\Organization\FamillyTypeEnum'
+    organization_sub_familly_type: 'App\Enum\Organization\SubFamillyTypeEnum'
+    organization_bulletin_period: 'App\Enum\Organization\BulletinPeriodEnum'
+    organization_bulletin_output: 'App\Enum\Organization\BulletinOutputEnum'
+    organization_bulletin_send_to: 'App\Enum\Organization\SendToBulletinEnum'
+    organization_setting_country: 'App\Enum\Organization\CountryEnum'
+
+  #Person
+    person_gender: 'App\Enum\Person\GenderEnum'
+    person_insee: 'App\Enum\Person\InseeEnum'
+    person_medal_type: 'App\Enum\Person\MedalTypeEnum'
+    person_moral_type: 'App\Enum\Person\MoralPersonTypeEnum'
+    medal_type: 'App\Enum\Person\MedalTypeEnum'
+
+  #Place
+    place_day_of_week: 'App\Enum\Place\DayOfWeekEnum'
+    place_site_status: 'App\Enum\Place\SiteStatusEnum'
+    place_site_type: 'App\Enum\Place\SiteTypeEnum'
+
+  #Product
+    equipment_appreciation: 'App\Enum\Product\AppreciationEnum'
+    equipment_control_type: 'App\Enum\Product\ControlTypeEnum'
+    equipment_loan_type: 'App\Enum\Product\LoanTypeEnum'
+    equipment_category: 'App\Enum\Product\EquipmentCategoryEnum'
+    equipment_detail: 'App\Enum\Product\EquipmentDetailEnum'
+    equipment_family: 'App\Enum\Product\EquipmentFamillyEnum'
+    equipment_group: 'App\Enum\Product\EquipmentGroupEnum'
+    equipment_insurance: 'App\Enum\Product\EquipmentInsuranceEnum'
+    equipment_logistical_platform: 'App\Enum\Product\EquipmentLogisticalPlatformEnum'
+    equipment_status: 'App\Enum\Product\EquipmentStatusEnum'
+    equipment_tone: 'App\Enum\Product\EquipmentToneEnum'
+    equipment_used_for: 'App\Enum\Product\EquipmentUsedForEnum'
+    equipment_repair_type: 'App\Enum\Product\RepairTypeEnum'
+    equipment_band: 'App\Enum\Product\BandEnum'
+    equipment_difficulty: 'App\Enum\Product\DifficultyEnum'
+    equipment_origin: 'App\Enum\Product\OriginMusicScoreEnum'
+    equipment_outcause: 'App\Enum\Product\OutCauseEnum'
+    equipment_checking: 'App\Enum\Product\CheckingEnum'
+    intangible_amount_type: 'App\Enum\Product\IntangibleAmountTypeEnum'
+    equipment_periodicity_control: 'App\Enum\Product\PeriodicityControlEnum'
+
+  #Event
+    event_type: 'App\Enum\Booking\EventTypeEnum'
+    event_visibility: 'App\Enum\Booking\VisibilityEnum'
+    event_type_gender: 'App\Enum\Booking\EventGenderTypeEnum'
+    event_educationalproject_establishment: 'App\Enum\Booking\EducationalProjectEstablishmentEnum'
+    event_educationalproject_specialclass: 'App\Enum\Booking\EducationalProjectSpecialClassEnum'
+    event_educationalproject_educationaldevice: 'App\Enum\Booking\EducationalProjectEducationalDeviceEnum'
+    examen_convocation_status: 'App\Enum\Booking\ExamenConvocationStatusEnum'
+    examen_convocation_presence: 'App\Enum\Booking\ExamenConvocationPresenceEnum'
+    examen_timeline: 'App\Enum\Booking\ExamenTimelineTypeEnum'
+    course_timeline: 'App\Enum\Booking\CourseTimelineTypeEnum'
+    organization_holiday_timeline: 'App\Enum\Booking\OrganizationHolidayTimelineTypeEnum'
+    person_holiday_timeline: 'App\Enum\Booking\PersonHolidayTimelineTypeEnum'
+    event_timeline: 'App\Enum\Booking\EventTimelineTypeEnum'
+    educational_project_timeline: 'App\Enum\Booking\EducationalProjectTimelineTypeEnum'
+    event_participation: 'App\Enum\Booking\ParticipationStatusEnum'
+
+  #file
+    file_visibility: 'App\Enum\Core\FileVisibilityEnum'
+    file_folder: 'App\Enum\Core\FileFolderEnum'
+
+  #education
+    education: 'App\Enum\Education\EducationTypeEnum'
+    education_year: 'App\Enum\Education\YearEnum'
+    education_period: 'App\Enum\Education\PeriodEnum'
+    education_periodicity: 'App\Enum\Education\PeriodicityEnum'
+    
+  #billing
+    billing_periodicity: 'App\Enum\Billing\PeriodicityEnum'
+    billing_type_periodicity: 'App\Enum\Billing\PeriodicityTypeEnum'
+    billing_pricingline_adhesion: 'App\Enum\Billing\PricingLineAdhesionEnum'
+    billing_pricingline_productrent: 'App\Enum\Billing\PricingLineProductRentEnum'
+    billing_discount_global_tariff_family: 'App\Enum\Billing\DiscountGlobalTariffFamilyEnum'
+    billing_pricingline_invoice_line: 'App\Enum\Billing\PricingLineInvoiceLineEnum'
+    billing_payment_choice: 'App\Enum\Billing\PaymentChoiceEnum'
+    billing_bank: 'App\Enum\Billing\BankEnum'
+    billing_periodicity_payment: 'App\Enum\Billing\PeriodicityPaymentEnum'
+    billing_rent_reduction_type: 'App\Enum\Billing\ReductionTypeEnum'
+    billing_rent_year: 'App\Enum\Billing\RentYearEnum'
+    billing_family_reduction_type: 'App\Enum\Billing\FamilyReductionTypeEnum'
+    billing_payment_state: 'App\Enum\Billing\PaymentStateEnum'
+    billing_period: 'App\Enum\Billing\PeriodEnum'
+    billing_adhesion_choice: 'App\Enum\Billing\AdhesionChoiceEnum'
+    billing_order_adult_type_choice: 'App\Enum\Billing\OrderAdultTypeEnum'
+    billing_adult_condition_type_choice: 'App\Enum\Billing\AdultConditionTypeEnum'
+    billing_payment_type_choice: 'App\Enum\Billing\PaymentTypeEnum'
+    billing_type: 'App\Enum\Billing\BillingTypeEnum'
+
+  #message
+    message_status: 'App\Enum\Message\MessageStatusEnum'
+    report_message_satus: 'App\Enum\Message\ReportMessageSatusEnum'
+    message_sender: 'App\Enum\Message\SenderEnum'
+    message_sender_only_access: 'App\Enum\Message\SenderOnlyAccessEnum'
+    message_send_to: 'App\Enum\Message\SendToEnum'
+
+  #rules
+    default_rules: 'App\Enum\Rulerz\RulesEnum'
+    manager_rules: 'App\Enum\Rulerz\RulesManagerEnum'
+
+  #commission
+    commission_member_function: 'App\Enum\Person\CommissionMemberFunctionEnum'
+    commission_member_cause_output: 'App\Enum\Person\CauseOutputEnum'
+
+  #Cotisation
+    cotisation_function_enum_choices: 'App\Enum\Cotisation\CotisationFunctionEnum'
+    type_of_practices_enum: 'App\Enum\Cotisation\TypeOfPracticeEnum'
+
+  #OnlineRegistration
+    onlineregistration_registration_status: 'App\Enum\OnlineRegistration\RegistrationStatus'
+    onlineregistration_wish_registration: 'App\Enum\OnlineRegistration\WishRegistration'
+    onlineregistration_file_type: 'App\Enum\OnlineRegistration\FileTypeEnum'
+    onlineregistration_origin_education_student_wish: 'App\Enum\OnlineRegistration\EducationStudentWishOriginEnum'

+ 5 - 0
config/packages/framework.yaml

@@ -15,3 +15,8 @@ framework:
     #fragments: true
     php_errors:
         log: true
+
+    http_client:
+        scoped_clients:
+            siret_checking:
+                base_uri: 'https://entreprise.data.gouv.fr/api/sirene/v3/etablissements/'

+ 1 - 1
config/packages/security.yaml

@@ -7,7 +7,7 @@ security:
 
         BASE_ROLE_ADMINISTRATION_CORE : &BASE_ROLE_ADMINISTRATION_CORE
             - ROLE_MEMBER_CORE
-            - ROLE_ORGANIZATION_EDIT
+            - ROLE_ORGANIZATION
 
         ROLE_ADMIN:
             - ROLE_CORE-CRUD

+ 1 - 1
config/packages/security/billing.yaml

@@ -1,7 +1,7 @@
 security:
     role_hierarchy:
         ROLE_BILLINGS_ADMINISTRATION:
-          - ROLE_BILLINGS-SEIZURE_REFERENCE
+          - ROLE_BILLINGS_ADMINISTRATION_VIEW
           - ROLE_BILLINGS-ADMINISTRATION_ACTION
           - ROLE_PES-ADMINISTRATION
           - ROLE_BERGERLEVRAULT-ADMINISTRATION

+ 5 - 7
config/packages/security/booking.yaml

@@ -1,10 +1,7 @@
 security:
     role_hierarchy:
         ROLE_EVENTS:
-          - ROLE_EVENT-GENDER_VIEW
-          - ROLE_CATEGORIES_VIEW
-          - ROLE_EVENT_ACTION
-          - ROLE_EVENT_REFERENCE
+          - ROLE_EVENTS_VIEW
 
         ROLE_EVENTS_VIEW:
           - ROLE_EVENT-GENDER_VIEW
@@ -19,8 +16,8 @@ security:
           - ROLE_ACCESS_REFERENCE
 
         ROLE_COURSES:
+          - ROLE_COURSES_VIEW
           - ROLE_EDUCATIONSTUDENT_VIEW
-          - ROLE_COURSE_REFERENCE
           - ROLE_COURSE_ACTION
           - ROLE_ORGANIZATION_VIEW
 
@@ -42,6 +39,7 @@ security:
           - ROLE_EQUIPMENT_REFERENCE
 
         ROLE_EXAMENS:
+          - ROLE_EXAMENS_VIEW
           - ROLE_EXAMEN_REFERENCE
           - ROLE_PRESENCE-EXAMEN_EXPORT
 
@@ -58,7 +56,7 @@ security:
           - ROLE_EQUIPMENT_REFERENCE
 
         ROLE_EDUCATIONALPROJECTS:
-          - ROLE_EDUCATIONAL-PROJECT_REFERENCE
+          - ROLE_EDUCATIONALPROJECTS_VIEW
           - ROLE_ROADMAP_EXPORT
 
         ROLE_EDUCATIONALPROJECTS_VIEW:
@@ -71,8 +69,8 @@ security:
           - ROLE_EQUIPMENT_REFERENCE
 
         ROLE_ATTENDANCES:
+          - ROLE_ATTENDANCES_VIEW
           - ROLE_ORGANIZATION-FUNCTION_VIEW
-          - ROLE_ACCESS_REFERENCE
           - ROLE_PRESENCE-COURSE_EXPORT
 
         ROLE_ATTENDANCES_VIEW:

+ 1 - 1
config/packages/security/donors.yaml

@@ -1,7 +1,7 @@
 security:
     role_hierarchy:
         ROLE_DONORS:
-          - ROLE_DONOR_REFERENCE
+          - ROLE_DONORS_VIEW
 
         ROLE_DONORS_VIEW:
           - ROLE_DONOR_REFERENCE

+ 1 - 2
config/packages/security/equipments.yaml

@@ -1,8 +1,7 @@
 security:
     role_hierarchy:
         ROLE_EQUIPMENTS:
-          - ROLE_EQUIPMENT_REFERENCE
-          - ROLE_EQUIPMENT-LIST_VIEW
+          - ROLE_EQUIPMENTS_VIEW
 
         ROLE_EQUIPMENTS_VIEW:
           - ROLE_EQUIPMENT_REFERENCE

+ 3 - 12
config/packages/security/generalConfig.yaml

@@ -1,8 +1,9 @@
 security:
     role_hierarchy:
         ROLE_GENERAL_CONFIG:
+          - ROLE_GENERAL_CONFIG_VIEW
           - ROLE_PLACE
-          - ROLE_ORGANIZATION_EDIT
+          - ROLE_ORGANIZATION
           - ROLE_ORGANIZATION_VIEW
           - ROLE_ACTIVITY
           - ROLE_FILE
@@ -12,9 +13,6 @@ security:
           - ROLE_ORGANIZATION_VIEW
           - ROLE_ACTIVITY_VIEW
 
-        ROLE_PLACE:
-          - ROLE_PLACE_REFERENCE
-
         ROLE_PLACE_VIEW:
           - ROLE_PLACE_REFERENCE
 
@@ -22,14 +20,11 @@ security:
           - ROLE_ACCESS_REFERENCE
           - ROLE_EQUIPMENT_REFERENCE
 
-        ROLE_ORGANIZATION_EDIT:
-          - ROLE_ORGANIZATION_REFERENCE
-
         ROLE_ORGANIZATION_VIEW:
           - ROLE_ORGANIZATION_REFERENCE
 
         ROLE_NETWORK:
-          - ROLE_ORGANIZATION_VIEW
+          - ROLE_NETWORK_VIEW
 
         ROLE_NETWORK_VIEW:
           - ROLE_ORGANIZATION_VIEW
@@ -37,10 +32,6 @@ security:
         ROLE_ORGANIZATION_REFERENCE:
           - ROLE_ACCESS_REFERENCE
 
-        ROLE_ACTIVITY:
-          - ROLE_ACTIVITY-TYPE_VIEW
-          - ROLE_ACTIVITY_REFERENCE
-
         ROLE_ACTIVITY_VIEW:
           - ROLE_ACTIVITY-TYPE_VIEW
           - ROLE_ACTIVITY_REFERENCE

+ 1 - 1
config/packages/security/medals.yaml

@@ -1,7 +1,7 @@
 security:
     role_hierarchy:
         ROLE_MEDALS:
-          - ROLE_MEDAL_REFERENCE
+          - ROLE_MEDALS_VIEW
 
         ROLE_MEDALS_VIEW:
           - ROLE_MEDAL_REFERENCE

+ 2 - 4
config/packages/security/pedagogics.yaml

@@ -3,16 +3,14 @@ security:
         ROLE_PEDAGOGICS_ADMINISTRATION:
           - ROLE_EDUCATION-NOTATION
           - ROLE_PEDAGOGICS_ACTION
-          - ROLE_EDUCATION_REFERENCE
+          - ROLE_PEDAGOGICS_ADMINISTRATION_VIEW
 
         ROLE_PEDAGOGICS_ADMINISTRATION_VIEW:
           - ROLE_EDUCATION-STUDENT_VIEW
           - ROLE_EDUCATION_REFERENCE
 
         ROLE_PEDAGOGICS_SEIZURE:
-          - ROLE_ACCESS_VIEW
-          - ROLE_EDUCATION-STUDENT_VIEW
-          - ROLE_CRITERIA-NOTATION_REFERENCE
+          - ROLE_PEDAGOGICS_SEIZURE_VIEW
           - ROLE_EDUCATION-NOTATION
           - ROLE_PEDAGOGICS-SEIZURE_ACTION
 

+ 2 - 1
config/packages/security/users.yaml

@@ -1,6 +1,7 @@
 security:
     role_hierarchy:
         ROLE_USERS:
+          - ROLE_USERS_VIEW
           - ROLE_FILE
           - ROLE_FUNCTION-TYPE_VIEW
           - ROLE_USERS_REFERENCE
@@ -24,7 +25,7 @@ security:
           - ROLE_ROOM_REFERENCE
 
         ROLE_COMMISSIONS:
-          - ROLE_ACCESS_REFERENCE
+          - ROLE_COMMISSIONS_VIEW
 
         ROLE_COMMISSIONS_VIEW:
           - ROLE_ACCESS_REFERENCE

+ 3 - 2
config/services.yaml

@@ -1,6 +1,5 @@
 # This file is the entry point to configure your own services.
 # Files in the packages/ subdirectory configure your dependencies.
-
 imports:
     - { resource: services/* }
 
@@ -13,6 +12,8 @@ services:
     _defaults:
         autowire: true      # Automatically injects dependencies in your services.
         autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
+        bind:
+            $opentalentConfig: '%kernel.project_dir%%env(OPENTALENT_CONFIG)%'
 
     # makes classes in src/ available to be used as services
     # this creates a service per class whose id is the fully-qualified class name
@@ -25,4 +26,4 @@ services:
             - '../src/Tests/'
             - '../src/Controller/'
             - '../src/DataProvider/'
-            - '../src/DataPersister/'
+            - '../src/Serializer/'

+ 5 - 5
config/services/dataProviders.yaml → config/services/apiPlatform.yaml

@@ -3,12 +3,12 @@ services:
   _defaults:
     autowire: true      # Automatically injects dependencies in your services.
     autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
+    public: false
+    bind:
+      $opentalentConfig: '%kernel.project_dir%%env(OPENTALENT_CONFIG)%'
 
   App\DataProvider\:
     resource: '../../src/DataProvider/'
 
-  App\DataProvider\Common\OpentalentItemDataProvider:
-    decorates: 'api_platform.doctrine.orm.default.item_data_provider'
-
-  App\DataProvider\Common\OpentalentCollectionDataProvider:
-    decorates: 'api_platform.doctrine.orm.default.collection_data_provider'
+  App\Serializer\OpentalentNormalizer:
+    decorates: 'api_platform.jsonld.normalizer.item'

+ 0 - 11
config/services/dataPersisters.yaml

@@ -1,11 +0,0 @@
-services:
-  # default configuration for services in *this* file
-  _defaults:
-    autowire: true      # Automatically injects dependencies in your services.
-    autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
-
-  App\DataPersister\:
-    resource: '../../src/DataPersister/'
-
-  App\DataPersister\Common\OpentalentDataPersister:
-    decorates: 'api_platform.doctrine.orm.data_persister'

+ 56 - 0
src/ApiResources/Enum/Enum.php

@@ -0,0 +1,56 @@
+<?php
+declare(strict_types=1);
+
+namespace App\ApiResources\Enum;
+
+use ApiPlatform\Core\Annotation\ApiProperty;
+use ApiPlatform\Core\Annotation\ApiResource;
+
+/**
+ * Classe resource qui contient les champs disponibles lors d'un appel à enum.
+ *
+ * @ApiResource(
+ *     collectionOperations={},
+ *     itemOperations={
+ *          "get"={
+ *             "method"="GET",
+ *             "path"="/enum/{name}"
+ *          }
+ *     }
+ * )
+ */
+class Enum
+{
+    /**
+     * @ApiProperty(identifier=true)
+     */
+    private $name;
+    private $items = [];
+
+    public function __construct()
+    {
+    }
+    public function getName(): ?string
+    {
+        return $this->name;
+    }
+
+    public function setName(?string $name): self
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+
+
+    public function setItems(array $items): self
+    {
+        $this->items = $items;
+        return $this;
+    }
+
+    public function getItems(): ?array
+    {
+        return $this->items;
+    }
+}

+ 6 - 6
src/ApiResources/Profile/AccessProfile.php

@@ -24,12 +24,12 @@ class AccessProfile
     /**
      * @ApiProperty(identifier=true)
      */
-    public int $id;
-    private bool $isAdminAccess;
-    private string $name;
-    private string $givenName;
-    private array $roles = [];
-    private OrganizationProfile $organization;
+    public $id;
+    private $isAdminAccess;
+    private $name;
+    private $givenName;
+    private $roles = [];
+    private $organization;
 
     public function __construct()
     {

+ 21 - 8
src/ApiResources/Profile/OrganizationProfile.php

@@ -14,14 +14,15 @@ class OrganizationProfile
     /**
      * @ApiProperty(identifier=true)
      */
-    public int $id;
-    private string $name;
-    private string $product;
-    private string $subDomain;
-    private string $website;
-    private array $modules = [];
-    private bool $hasChildren = false;
-    private array $parents = [];
+    public $id;
+    private $name;
+    private $product;
+    private $subDomain;
+    private $networks = [];
+    private $website;
+    private $modules = [];
+    private $hasChildren = false;
+    private $parents = [];
 
     public function __construct()
     {
@@ -63,6 +64,18 @@ class OrganizationProfile
         return $this;
     }
 
+    public function getNetworks(): array
+    {
+        return $this->networks;
+    }
+
+    public function addNetwork(?string $network): self
+    {
+        $this->networks[] = $network;
+
+        return $this;
+    }
+
     public function getSubDomain(): ?string
     {
         return $this->subDomain;

+ 54 - 0
src/ApiResources/Utils/Siret.php

@@ -0,0 +1,54 @@
+<?php
+declare(strict_types=1);
+
+namespace App\ApiResources\Utils;
+
+use ApiPlatform\Core\Annotation\ApiProperty;
+use ApiPlatform\Core\Annotation\ApiResource;
+
+/**
+ * Classe resource qui contient les champs de vérification d'un siret
+ *
+ * @ApiResource(
+ *     collectionOperations={},
+ *     itemOperations={
+ *          "get"={
+ *             "method"="GET",
+ *             "path"="/siret-checking/{number}"
+ *          }
+ *     }
+ * )
+ */
+class Siret
+{
+    /**
+     * @ApiProperty(identifier=true)
+     */
+    private $number;
+    private $isCorrect;
+
+    public function __construct()
+    {
+    }
+    public function getNumber(): ?string
+    {
+        return $this->number;
+    }
+
+    public function setNumber(?string $number): self
+    {
+        $this->number = $number;
+        return $this;
+    }
+
+    public function setIsCorrect(bool $isCorrect): self
+    {
+        $this->isCorrect = $isCorrect;
+        return $this;
+    }
+
+    public function getIsCorrect(): ?bool
+    {
+        return $this->isCorrect;
+    }
+}

+ 0 - 36
src/DataPersister/Common/OpentalentDataPersister.php

@@ -1,36 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace App\DataPersister\Common;
-
-use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
-
-/**
- * Class OpentalentDataPersister : Décoration du dataPersister par défaut d'API Platform
- * @package App\DataPersister\Common
- */
-final class OpentalentDataPersister implements ContextAwareDataPersisterInterface
-{
-    private ContextAwareDataPersisterInterface $decorated;
-
-    public function __construct(ContextAwareDataPersisterInterface $decorated)
-    {
-        $this->decorated = $decorated;
-    }
-
-    public function supports($data, array $context = []): bool
-    {
-        return $this->decorated->supports($data, $context);
-    }
-
-    public function persist($data, array $context = [])
-    {
-        $result = $this->decorated->persist($data, $context);
-        return $result;
-    }
-
-    public function remove($data, array $context = [])
-    {
-        return $this->decorated->remove($data, $context);
-    }
-}

+ 5 - 1
src/DataProvider/Access/AccessProfileDataProvider.php

@@ -9,7 +9,6 @@ use App\ApiResources\Profile\AccessProfile;
 use App\ApiResources\Profile\OrganizationProfile;
 use App\Entity\Access\Access;
 use App\Entity\Organization\Organization;
-use App\Repository\Organization\OrganizationRepository;
 use App\Service\Network\Tree;
 use App\Service\Security\Module;
 use Symfony\Component\Security\Core\Role\Role;
@@ -80,6 +79,7 @@ final class AccessProfileDataProvider implements ItemDataProviderInterface, Rest
      */
     public function setOrganizationProfileFromOrganization(Organization $organization): OrganizationProfile{
         $organizationProfile = new OrganizationProfile();
+        $organizationProfile->setId($organization->getId());
         $organizationProfile->setName($organization->getName());
         $organizationProfile->setModules($this->module->getOrganizationModules($organization));
         $organizationProfile->setProduct($organization->getSettings()->getProduct());
@@ -87,6 +87,10 @@ final class AccessProfileDataProvider implements ItemDataProviderInterface, Rest
         $organizationProfile->setSubDomain($organization->getParameters()->getSubDomain());
         $organizationProfile->setWebsite($organization->getParameters()->getWebsite());
 
+        foreach ($organization->getNetworkOrganizations() as $networkOrganization){
+            $organizationProfile->addNetwork($networkOrganization->getNetwork()->getName());
+        }
+
         /** @var Organization $parent */
         foreach ($this->tree->findAllParentsAndSortByType($organization) as $parent){
             $parentProfile = new OrganizationProfile();

+ 0 - 37
src/DataProvider/Common/OpentalentCollectionDataProvider.php

@@ -1,37 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace App\DataProvider\Common;
-
-use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
-use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
-
-/**
- * Class OpentalentCollectionDataProvider : : Décoration du dataProvider Collection par défaut d'API Platform
- * @package App\DataProvider\Common
- */
-final class OpentalentCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface
-{
-    private ContextAwareCollectionDataProviderInterface $decorated;
-
-    public function __construct(
-        ContextAwareCollectionDataProviderInterface $decorated
-    )
-    {
-        $this->decorated = $decorated;
-    }
-
-    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
-    {
-
-        return $this->decorated->supports($resourceClass, $operationName, $context);
-    }
-
-    /**
-     * @inheritDoc
-     */
-    public function getCollection(string $resourceClass, string $operationName = null, array $context = [])
-    {
-        return $this->decorated->getCollection($resourceClass, $operationName, $context);
-    }
-}

+ 0 - 34
src/DataProvider/Common/OpentalentItemDataProvider.php

@@ -1,34 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace App\DataProvider\Common;
-
-use ApiPlatform\Core\DataProvider\DenormalizedIdentifiersAwareItemDataProviderInterface;
-use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
-
-/**
- * Class OpentalentItemDataProvider : : Décoration du dataProvider item par défaut d'API Platform
- * @package App\DataProvider\Common
- */
-final class OpentalentItemDataProvider implements DenormalizedIdentifiersAwareItemDataProviderInterface, RestrictedDataProviderInterface
-{
-    private DenormalizedIdentifiersAwareItemDataProviderInterface $decorated;
-
-    public function __construct(DenormalizedIdentifiersAwareItemDataProviderInterface $decorated)
-    {
-        $this->decorated = $decorated;
-    }
-
-    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
-    {
-        return $this->decorated->supports($resourceClass, $operationName, $context);
-    }
-
-    /**
-     * @inheritDoc
-     */
-    public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
-    {
-        return $this->decorated->getItem($resourceClass, $id, $operationName, $context);
-    }
-}

+ 67 - 0
src/DataProvider/Enum/EnumDataProvider.php

@@ -0,0 +1,67 @@
+<?php
+declare(strict_types=1);
+
+namespace App\DataProvider\Enum;
+
+use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
+use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
+use App\ApiResources\Enum\Enum;
+use App\Service\Utils\Parser;
+use App\Service\Utils\Reflection;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+
+/**
+ * Class EnumDataProvider : custom provider pour assurer l'alimentation des enums
+ * @package App\DataProvider\Access
+ */
+final class EnumDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
+{
+    private Parser $parser;
+    private Reflection $reflection;
+    private string $opentalentConfig;
+
+    public function __construct(
+        Parser $parser,
+        string $opentalentConfig,
+        Reflection $reflection
+    )
+    {
+        $this->parser = $parser;
+        $this->opentalentConfig = $opentalentConfig;
+        $this->reflection = $reflection;
+    }
+
+    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
+    {
+        return Enum::class === $resourceClass;
+    }
+
+    public function getItem(string $resourceClass, $name, string $operationName = null, array $context = []): ?Enum
+    {
+        $enums = $this->parser->yamlParser($this->opentalentConfig, 'enum.yaml');
+        $enumClass = $enums['opentalent'][$name];
+
+        if(!$enumClass)
+            throw new NotFoundHttpException(sprintf('Enum %s does\'nt exist', $name));
+
+        $items = [];
+        try{
+            $items = $this->reflection->dynamicInvokeClassWithArgsAndMethod(
+                $enumClass,
+                'toArrayCustom'
+            );
+        }catch (\Exception $exception){
+            try{
+                $items = $this->reflection->dynamicInvokeClassWithArgsAndMethod(
+                    $enumClass,
+                    'toArray'
+                );
+            }catch (\Exception $exception){}
+        }
+
+        $enumResponse = new Enum();
+        $enumResponse->setName($name);
+        $enumResponse->setItems($items);
+        return $enumResponse;
+    }
+}

+ 38 - 0
src/DataProvider/Utils/SiretDataProvider.php

@@ -0,0 +1,38 @@
+<?php
+declare(strict_types=1);
+
+namespace App\DataProvider\Utils;
+
+use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
+use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
+use App\ApiResources\Utils\Siret;
+use App\Service\Utils\Siret as SiretUtils;
+
+/**
+ * Class SiretDataProvider : custom provider pour assurer l'alimentation des utils Siret
+ * @package App\DataProvider\Access
+ */
+final class SiretDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
+{
+    private SiretUtils $siretUtils;
+
+    public function __construct(
+        SiretUtils $siretUtils
+    )
+    {
+        $this->siretUtils = $siretUtils;
+    }
+
+    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
+    {
+        return Siret::class === $resourceClass;
+    }
+
+    public function getItem(string $resourceClass, $number, string $operationName = null, array $context = []): ?Siret
+    {
+        $siretResponse = new Siret();
+        $siretResponse->setNumber($number);
+        $siretResponse->setIsCorrect($this->siretUtils->isSiretIsCorrect($number));
+        return $siretResponse;
+    }
+}

+ 40 - 6
src/Entity/Access/Access.php

@@ -6,6 +6,7 @@ namespace App\Entity\Access;
 use ApiPlatform\Core\Annotation\ApiResource;
 use ApiPlatform\Core\Annotation\ApiSubresource;
 use App\Entity\Organization\Organization;
+use App\Entity\Organization\OrganizationLicence;
 use App\Repository\Access\AccessRepository;
 use App\Entity\Person\Person;
 use App\Entity\Person\PersonActivity;
@@ -18,12 +19,12 @@ use Symfony\Component\Security\Core\User\UserInterface;
  * Fais le lien entre une Person et une Organization
  * @ApiResource(
  *     collectionOperations={
- *         "get"={"security"="is_granted('ROLE_USER')"},
+ *         "get"={"security"="is_granted('ROLE_USERS_VIEW')"},
  *         "post"
  *     },
  *     itemOperations={
- *         "get"={"security"="is_granted('ROLE_USER') or object.getId() == user.getId()"},
- *         "put"={"security"="is_granted('ROLE_USER')"},
+ *         "get"={"security"="(is_granted('ROLE_USERS_VIEW') and object.getOrganization().getId() == user.getOrganization().getId()) or (object.getId() == user.getId())"},
+ *         "put"={"security"="is_granted('ROLE_USERS')"},
  *         "delete"
  *     }
  * )
@@ -67,9 +68,15 @@ class Access implements UserInterface
      */
     private $personActivity;
 
+    /**
+     * @ORM\OneToMany(targetEntity=OrganizationLicence::class, mappedBy="licensee", orphanRemoval=true)
+     */
+    private $organizationLicences;
+
     public function __construct()
     {
         $this->personActivity = new ArrayCollection();
+        $this->organizationLicences = new ArrayCollection();
     }
 
     public function getId(): ?int
@@ -149,9 +156,6 @@ class Access implements UserInterface
     public function getRoles()
     {
         $roles = $this->roles;
-        // guarantee every user at least has ROLE_USER
-        $roles[] = 'ROLE_USER';
-
         return array_unique($roles);
     }
 
@@ -186,4 +190,34 @@ class Access implements UserInterface
     {
         // TODO: Implement eraseCredentials() method.
     }
+
+    /**
+     * @return Collection|OrganizationLicence[]
+     */
+    public function getOrganizationLicences(): Collection
+    {
+        return $this->organizationLicences;
+    }
+
+    public function addOrganizationLicence(OrganizationLicence $organizationLicence): self
+    {
+        if (!$this->organizationLicences->contains($organizationLicence)) {
+            $this->organizationLicences[] = $organizationLicence;
+            $organizationLicence->setLicensee($this);
+        }
+
+        return $this;
+    }
+
+    public function removeOrganizationLicence(OrganizationLicence $organizationLicence): self
+    {
+        if ($this->organizationLicences->removeElement($organizationLicence)) {
+            // set the owning side to null (unless already changed)
+            if ($organizationLicence->getLicensee() === $this) {
+                $organizationLicence->setLicensee(null);
+            }
+        }
+
+        return $this;
+    }
 }

+ 202 - 0
src/Entity/Core/AddressPostal.php

@@ -0,0 +1,202 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Entity\Core;
+
+use ApiPlatform\Core\Annotation\ApiResource;
+use App\Entity\Organization\OrganizationAddressPostal;
+use App\Repository\Core\AddressPostalRepository;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity(repositoryClass=AddressPostalRepository::class)
+ */
+class AddressPostal
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\ManyToOne(targetEntity=Country::class)
+     */
+    private $addressCountry;
+
+    /**
+     * @ORM\Column(type="string", length=100, nullable=true)
+     */
+    private $addressCity;
+
+    /**
+     * @ORM\Column(type="string", length=100, nullable=true)
+     */
+    private $addressOwner;
+
+    /**
+     * @ORM\Column(type="string", length=20, nullable=true)
+     */
+    private $postalCode;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $streetAddress;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $streetAddressSecond;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $streetAddressThird;
+
+    /**
+     * @ORM\Column(type="float", nullable=true)
+     */
+    private $latitude;
+
+    /**
+     * @ORM\Column(type="float", nullable=true)
+     */
+    private $longitude;
+
+    /**
+     * @ORM\OneToOne(targetEntity=OrganizationAddressPostal::class, mappedBy="addressPostal", cascade={"persist", "remove"})
+     */
+    private $organizationAddressPostal;
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getAddressCountry(): ?Country
+    {
+        return $this->addressCountry;
+    }
+
+    public function setAddressCountry(?Country $addressCountry): self
+    {
+        $this->addressCountry = $addressCountry;
+
+        return $this;
+    }
+
+    public function getAddressCity(): ?string
+    {
+        return $this->addressCity;
+    }
+
+    public function setAddressCity(?string $addressCity): self
+    {
+        $this->addressCity = $addressCity;
+
+        return $this;
+    }
+
+    public function getAddressOwner(): ?string
+    {
+        return $this->addressOwner;
+    }
+
+    public function setAddressOwner(?string $addressOwner): self
+    {
+        $this->addressOwner = $addressOwner;
+
+        return $this;
+    }
+
+    public function getPostalCode(): ?string
+    {
+        return $this->postalCode;
+    }
+
+    public function setPostalCode(?string $postalCode): self
+    {
+        $this->postalCode = $postalCode;
+
+        return $this;
+    }
+
+    public function getStreetAddress(): ?string
+    {
+        return $this->streetAddress;
+    }
+
+    public function setStreetAddress(?string $streetAddress): self
+    {
+        $this->streetAddress = $streetAddress;
+
+        return $this;
+    }
+
+    public function getStreetAddressSecond(): ?string
+    {
+        return $this->streetAddressSecond;
+    }
+
+    public function setStreetAddressSecond(?string $streetAddressSecond): self
+    {
+        $this->streetAddressSecond = $streetAddressSecond;
+
+        return $this;
+    }
+
+    public function getStreetAddressThird(): ?string
+    {
+        return $this->streetAddressThird;
+    }
+
+    public function setStreetAddressThird(?string $streetAddressThird): self
+    {
+        $this->streetAddressThird = $streetAddressThird;
+
+        return $this;
+    }
+
+    public function getLatitude(): ?float
+    {
+        return $this->latitude;
+    }
+
+    public function setLatitude(?float $latitude): self
+    {
+        $this->latitude = $latitude;
+
+        return $this;
+    }
+
+    public function getLongitude(): ?float
+    {
+        return $this->longitude;
+    }
+
+    public function setLongitude(?float $longitude): self
+    {
+        $this->longitude = $longitude;
+
+        return $this;
+    }
+
+    public function getOrganizationAddressPostal(): ?OrganizationAddressPostal
+    {
+        return $this->organizationAddressPostal;
+    }
+
+    public function setOrganizationAddressPostal(OrganizationAddressPostal $organizationAddressPostal): self
+    {
+        // set the owning side of the relation if necessary
+        if ($organizationAddressPostal->getAddressPostal() !== $this) {
+            $organizationAddressPostal->setAddressPostal($this);
+        }
+
+        $this->organizationAddressPostal = $organizationAddressPostal;
+
+        return $this;
+    }
+}

+ 285 - 0
src/Entity/Core/BankAccount.php

@@ -0,0 +1,285 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Entity\Core;
+
+use ApiPlatform\Core\Annotation\ApiResource;
+use App\Entity\Organization\Organization;
+use App\Repository\Core\BankAccountRepository;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
+use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Validator\Constraints as Assert;
+
+/**
+ * Données bancaire d'une Person ou d'une Organization
+ *
+ * @ApiResource(
+ *     itemOperations={
+ *           "get"={"security"="is_granted('BANK_ACCOUNT_READ', object)"},
+ *           "put"={"security"="is_granted('BANK_ACCOUNT_EDIT', object)"},
+ *     }
+ * )
+ * @ORM\Entity(repositoryClass=BankAccountRepository::class)
+ */
+class BankAccount
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $bankName;
+
+    /**
+     * @ORM\Column(type="string", length=11, nullable=true)
+     * @Assert\Bic(
+     *    message="invalid_bic"
+     * )
+     */
+    private $bic;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $bicInvalid;
+
+    /**
+     * @ORM\Column(type="string", length=34, nullable=true)
+     * @Assert\Iban(
+     *    message="invalid_iban"
+     * )
+     */
+    private $iban;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $ibanInvalid;
+
+    /**
+     * @ORM\Column(type="boolean", options={"default" : false})
+     */
+    private $holderIdDifferent = false;
+
+    /**
+     * 0 => jamais facturé, 1 => facturé 1 fois, 2 => facturé plusieurs fois
+     * @ORM\Column(type="integer", options={"default" : 0})
+     */
+    private $countInvoiced;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $holder;
+
+    /**
+     * @ORM\Column(type="boolean", options={"default" : false})
+     * @Assert\NotNull
+     */
+    private $principal = false;
+
+    /**
+     * @ORM\Column(type="text", nullable=true)
+     */
+    private $debitAddress;
+
+    /**
+     * @ORM\Column(type="string", length=35, nullable=true, unique=true)
+     */
+    private $rum;
+
+    /**
+     * @ORM\Column(type="date", nullable=true)
+     */
+    private $signatureDateSamplingMandate;
+
+    /**
+     * @ORM\ManyToMany(targetEntity=Organization::class, inversedBy="bankAccounts")
+     * @ORM\JoinTable(name="organization_bankaccount")
+     */
+    private $organization;
+
+    public function __construct()
+    {
+        $this->organization = new ArrayCollection();
+    }
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getBankName(): ?string
+    {
+        return $this->bankName;
+    }
+
+    public function setBankName(?string $bankName): self
+    {
+        $this->bankName = $bankName;
+
+        return $this;
+    }
+
+    public function getBic(): ?string
+    {
+        return $this->bic;
+    }
+
+    public function setBic(?string $bic): self
+    {
+        $this->bic = $bic;
+
+        return $this;
+    }
+
+    public function getBicInvalid(): ?string
+    {
+        return $this->bicInvalid;
+    }
+
+    public function setBicInvalid(?string $bicInvalid): self
+    {
+        $this->bicInvalid = $bicInvalid;
+
+        return $this;
+    }
+
+    public function getIban(): ?string
+    {
+        return $this->iban;
+    }
+
+    public function setIban(?string $iban): self
+    {
+        $this->iban = $iban;
+
+        return $this;
+    }
+
+    public function getIbanInvalid(): ?string
+    {
+        return $this->ibanInvalid;
+    }
+
+    public function setIbanInvalid(?string $ibanInvalid): self
+    {
+        $this->ibanInvalid = $ibanInvalid;
+
+        return $this;
+    }
+
+    public function getHolderIdDifferent(): ?bool
+    {
+        return $this->holderIdDifferent;
+    }
+
+    public function setHolderIdDifferent(bool $holderIdDifferent): self
+    {
+        $this->holderIdDifferent = $holderIdDifferent;
+
+        return $this;
+    }
+
+    public function getCountInvoiced(): ?int
+    {
+        return $this->countInvoiced;
+    }
+
+    public function setCountInvoiced(int $countInvoiced): self
+    {
+        $this->countInvoiced = $countInvoiced;
+
+        return $this;
+    }
+
+    public function getHolder(): ?string
+    {
+        return $this->holder;
+    }
+
+    public function setHolder(?string $holder): self
+    {
+        $this->holder = $holder;
+
+        return $this;
+    }
+
+    public function getPrincipal(): ?bool
+    {
+        return $this->principal;
+    }
+
+    public function setPrincipal(bool $principal): self
+    {
+        $this->principal = $principal;
+
+        return $this;
+    }
+
+    public function getDebitAddress(): ?string
+    {
+        return $this->debitAddress;
+    }
+
+    public function setDebitAddress(?string $debitAddress): self
+    {
+        $this->debitAddress = $debitAddress;
+
+        return $this;
+    }
+
+    /**
+     * @return Collection|Organization[]
+     */
+    public function getOrganization(): Collection
+    {
+        return $this->organization;
+    }
+
+    public function addOrganization(Organization $organization): self
+    {
+        if (!$this->organization->contains($organization)) {
+            $this->organization[] = $organization;
+        }
+
+        return $this;
+    }
+
+    public function removeOrganization(Organization $organization): self
+    {
+        $this->organization->removeElement($organization);
+
+        return $this;
+    }
+
+    public function getRum(): ?string
+    {
+        return $this->rum;
+    }
+
+    public function setRum(?string $rum): self
+    {
+        $this->rum = $rum;
+
+        return $this;
+    }
+
+    public function getSignatureDateSamplingMandate(): ?\DateTimeInterface
+    {
+        return $this->signatureDateSamplingMandate;
+    }
+
+    public function setSignatureDateSamplingMandate(?\DateTimeInterface $signatureDateSamplingMandate): self
+    {
+        $this->signatureDateSamplingMandate = $signatureDateSamplingMandate;
+
+        return $this;
+    }
+}

+ 273 - 0
src/Entity/Core/ContactPoint.php

@@ -0,0 +1,273 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Entity\Core;
+
+use ApiPlatform\Core\Annotation\ApiResource;
+use App\Entity\Organization\Organization;
+use App\Entity\Person\Person;
+use libphonenumber\PhoneNumber;
+use App\Repository\Core\ContactPointRepository;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
+use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Validator\Constraints as Assert;
+
+/**
+ * Données de contact d'une Person ou d'une Organization ou d'un lieu
+ * @ApiResource(
+ *     itemOperations={
+ *           "get"={"security"="is_granted('CONTACT_POINT_READ', object)"},
+ *           "put"={"security"="is_granted('CONTACT_POINT_EDIT', object)"},
+ *     }
+ * )
+ * @ORM\Entity(repositoryClass=ContactPointRepository::class)
+ */
+class ContactPoint
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(type="string", length=255)
+     * @Assert\Choice(callback={"\App\Enum\Core\ContactPointTypeEnum", "toArray"}, message="invalid-choice")
+     */
+    private $contactType;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     * @Assert\Email(mode="strict", message="invalid-email-format")
+     * @Assert\Regex(pattern="/^[a-zA-Z0-9._%-]{1,64}@[a-zA-Z0-9.-]{2,249}\.[a-zA-Z]{2,6}$/", message="email-error")
+     */
+    private $email;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $emailInvalid;
+
+    /**
+     * @ORM\Column(type="phone_number", nullable=true)
+     */
+    private $faxNumber;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $faxNumberInvalid;
+
+    /**
+     * @ORM\Column(type="phone_number", nullable=true)
+     */
+    private $telphone;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $telphoneInvalid;
+
+    /**
+     * @ORM\Column(type="phone_number", nullable=true)
+     */
+    private $mobilPhone;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $mobilPhoneInvalid;
+
+    /**
+     * @ORM\ManyToMany(targetEntity=Organization::class, inversedBy="contactPoints")
+     * @ORM\JoinTable(name="organization_contactpoint")
+     */
+    private $organization;
+
+    /**
+     * @ORM\ManyToMany(targetEntity=Person::class, inversedBy="contactPoints")
+     * @ORM\JoinTable(name="person_contactpoint")
+     */
+    private $person;
+
+    public function __construct()
+    {
+        $this->organization = new ArrayCollection();
+        $this->person = new ArrayCollection();
+    }
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getContactType(): ?string
+    {
+        return $this->contactType;
+    }
+
+    public function setContactType(string $contactType): self
+    {
+        $this->contactType = $contactType;
+
+        return $this;
+    }
+
+    public function getEmail(): ?string
+    {
+        return $this->email;
+    }
+
+    public function setEmail(?string $email): self
+    {
+        $this->email = $email;
+
+        if(!is_null($this->email && !is_null($this->getEmailInvalid())))
+            $this->setEmailInvalid(null);
+
+        return $this;
+    }
+
+    public function getEmailInvalid(): ?string
+    {
+        return $this->emailInvalid;
+    }
+
+    public function setEmailInvalid(?string $emailInvalid): self
+    {
+        $this->emailInvalid = $emailInvalid;
+
+        return $this;
+    }
+
+    public function getFaxNumber(): ?PhoneNumber
+    {
+        return $this->faxNumber;
+    }
+
+    public function setFaxNumber(?PhoneNumber $faxNumber): self
+    {
+        $this->faxNumber = $faxNumber;
+
+        if(!is_null($this->faxNumber && !is_null($this->getFaxNumberInvalid())))
+            $this->setFaxNumberInvalid(null);
+
+        return $this;
+    }
+
+    public function getFaxNumberInvalid(): ?string
+    {
+        return $this->faxNumberInvalid;
+    }
+
+    public function setFaxNumberInvalid(?string $faxNumberInvalid): self
+    {
+        $this->faxNumberInvalid = $faxNumberInvalid;
+
+        return $this;
+    }
+
+    public function getTelphone(): ?PhoneNumber
+    {
+        return $this->telphone;
+    }
+
+    public function setTelphone(?PhoneNumber $telphone): self
+    {
+        $this->telphone = $telphone;
+
+        if(!is_null($this->telphone && !is_null($this->getTelphoneInvalid())))
+            $this->setTelphoneInvalid(null);
+
+        return $this;
+    }
+
+    public function getTelphoneInvalid(): ?string
+    {
+        return $this->telphoneInvalid;
+    }
+
+    public function setTelphoneInvalid(?string $telphoneInvalid): self
+    {
+        $this->telphoneInvalid = $telphoneInvalid;
+
+        return $this;
+    }
+
+    public function getMobilPhone(): ?PhoneNumber
+    {
+        return $this->mobilPhone;
+    }
+
+    public function setMobilPhone(?PhoneNumber $mobilPhone): self
+    {
+        $this->mobilPhone = $mobilPhone;
+
+        if(!is_null($this->mobilPhone && !is_null($this->getMobilPhoneInvalid())))
+            $this->setMobilPhoneInvalid(null);
+
+        return $this;
+    }
+
+    public function getMobilPhoneInvalid(): ?string
+    {
+        return $this->mobilPhoneInvalid;
+    }
+
+    public function setMobilPhoneInvalid(?string $mobilPhoneInvalid): self
+    {
+        $this->mobilPhoneInvalid = $mobilPhoneInvalid;
+
+        return $this;
+    }
+
+    /**
+     * @return Collection|Organization[]
+     */
+    public function getOrganization(): Collection
+    {
+        return $this->organization;
+    }
+
+    public function addOrganization(Organization $organization): self
+    {
+        if (!$this->organization->contains($organization)) {
+            $this->organization[] = $organization;
+        }
+
+        return $this;
+    }
+
+    public function removeOrganization(Organization $organization): self
+    {
+        $this->organization->removeElement($organization);
+
+        return $this;
+    }
+
+    /**
+     * @return Collection|Person[]
+     */
+    public function getPerson(): Collection
+    {
+        return $this->person;
+    }
+
+    public function addPerson(Person $person): self
+    {
+        if (!$this->person->contains($person)) {
+            $this->person[] = $person;
+        }
+
+        return $this;
+    }
+
+    public function removePerson(Person $person): self
+    {
+        $this->person->removeElement($person);
+
+        return $this;
+    }
+}

+ 41 - 0
src/Entity/Core/Country.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Entity\Core;
+
+use App\Repository\Core\CountryRepository;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity(repositoryClass=CountryRepository::class)
+ */
+class Country
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(type="string", length=255)
+     */
+    private $name;
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getName(): ?string
+    {
+        return $this->name;
+    }
+
+    public function setName(string $name): self
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+}

+ 2 - 1
src/Entity/Network/NetworkOrganization.php

@@ -3,13 +3,14 @@ declare(strict_types=1);
 
 namespace App\Entity\Network;
 
+use ApiPlatform\Core\Annotation\ApiResource;
 use App\Entity\Organization\Organization;
 use App\Repository\Network\NetworkOrganizationRepository;
 use Doctrine\ORM\Mapping as ORM;
 
 /**
  * Fait le lien entre une Organization et un Network
- *
+ * @ApiResource()
  * @ORM\Entity(repositoryClass=NetworkOrganizationRepository::class)
  */
 class NetworkOrganization

+ 715 - 6
src/Entity/Organization/Organization.php

@@ -4,23 +4,23 @@ declare(strict_types=1);
 namespace App\Entity\Organization;
 
 use ApiPlatform\Core\Annotation\ApiResource;
+use ApiPlatform\Core\Annotation\ApiSubresource;
+use App\Entity\Core\BankAccount;
+use App\Entity\Core\ContactPoint;
 use App\Entity\Network\NetworkOrganization;
 use App\Repository\Organization\OrganizationRepository;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Validator\Constraints as Assert;
 
 /**
  * Structure, organisation
  *
  * @ApiResource(
- *     collectionOperations={
- *         "get"={"security"="is_granted('ROLE_ORGANIZATION')"},
- *         "post"={"security"="is_granted('ROLE_ORGANIZATION_CREATE')"}
- *     },
  *     itemOperations={
- *         "get"={"security"="is_granted('ROLE_ORGANIZATION_EDIT') and object.getId() == user.organization.getId()"},
- *         "put"={"security"="is_granted('ROLE_ORGANIZATION_EDIT')"}
+ *         "get"={"security"="(is_granted('ROLE_ORGANIZATION_VIEW') or is_granted('ROLE_ORGANIZATION')) and object.getId() == user.organization.getId() "},
+ *         "put"={"security"="is_granted('ROLE_ORGANIZATION') and object.getId() == user.organization.getId() "}
  *     }
  * )
  * @ORM\Entity(repositoryClass=OrganizationRepository::class)
@@ -46,11 +46,13 @@ class Organization
 
     /**
      * @ORM\Column(type="string", length=255, nullable=true)
+     * @Assert\Choice(callback={"\App\Enum\Organization\LegalEnum", "toArray"})
      */
     private $legalStatus;
 
     /**
      * @ORM\Column(type="string", length=255, nullable=true)
+     * @Assert\Choice(callback={"\App\Enum\Organization\PrincipalTypeEnum", "toArray"})
      */
     private $principalType;
 
@@ -75,10 +77,207 @@ class Organization
      */
     private $parameters;
 
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $description;
+
+    /**
+     * @ORM\Column(type="date", nullable=true)
+     */
+    private $creationDate;
+
+    /**
+     * @ORM\Column(type="date", nullable=true)
+     */
+    private $declarationDate;
+
+    /**
+     * @ORM\Column(type="string", length=14, nullable=true)
+     */
+    private $siretNumber;
+
+    /**
+     * @ORM\Column(type="string", length=10, nullable=true)
+     */
+    private $waldecNumber;
+
+    /**
+     * @ORM\Column(type="string", length=5, nullable=true)
+     */
+    private $apeNumber;
+
+    /**
+     * @ORM\Column(type="string", length=50, nullable=true)
+     */
+    private $tvaNumber;
+
+    /**
+     * @ORM\Column(type="string", length=40, nullable=true)
+     */
+    private $otherType;
+
+    /**
+     * @ORM\Column(type="string", length=80, nullable=true)
+     */
+    private $acronym;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $facebook;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $twitter;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $instagram;
+
+    /**
+     * @ORM\Column(type="string", length=35, nullable=true)
+     */
+    private $collectiveAgreement;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     * @Assert\Choice(callback={"\App\Enum\Organization\OpcaEnum", "toArray"})
+     */
+    private $opca;
+
+    /**
+     * @ORM\Column(type="string", length=35, nullable=true)
+     */
+    private $icomNumber;
+
+    /**
+     * @ORM\Column(type="string", length=35, nullable=true)
+     */
+    private $urssafNumber;
+
+    /**
+     * @ORM\Column(type="string", length=20, nullable=true)
+     */
+    private $youngApproval;
+
+    /**
+     * @ORM\Column(type="string", length=20, nullable=true)
+     */
+    private $trainingApproval;
+
+    /**
+     * @ORM\Column(type="string", length=50, nullable=true)
+     */
+    private $otherApproval;
+
+    /**
+     * @ORM\Column(type="string", length=35, nullable=true)
+     */
+    private $prefectureName;
+
+    /**
+     * @ORM\Column(type="string", length=20, nullable=true)
+     */
+    private $prefectureNumber;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     * @Assert\Choice(callback={"\App\Enum\Organization\CategoryEnum", "toArray"})
+     */
+    private $category;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     * @Assert\Choice(callback={"\App\Enum\Organization\SchoolCategoryEnum", "toArray"})
+     */
+    private $schoolCategory;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     * @Assert\Choice(callback={"\App\Enum\Organization\TypeEstablishmentEnum", "toArray"})
+     */
+    private $typeEstablishment;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     * @Assert\Choice(callback={"\App\Enum\Organization\TypeEstablishmentDetailEnum", "toArray"})
+     */
+    private $typeEstablishmentDetail;
+
+    /**
+     * @ORM\Column(type="float", nullable=true)
+     */
+    private $budget;
+
+    /**
+     * @ORM\Column(type="boolean", nullable=true)
+     */
+    private $isPedagogicIsPrincipalActivity;
+
+    /**
+     * @ORM\Column(type="float", nullable=true)
+     */
+    private $pedagogicBudget;
+
+    /**
+     * @ORM\Column(type="boolean", nullable=true)
+     */
+    private $isPerformanceContractor;
+
+    /**
+     * @ORM\Column(type="string", length=20, nullable=true)
+     */
+    private $ffecApproval;
+
+    /**
+     * @ORM\Column(type="boolean")
+     */
+    private $portailVisibility;
+
+    /**
+     * @ORM\Column(type="integer", nullable=true)
+     */
+    private $cmsId;
+
+    /**
+     * @ORM\Column(type="text", nullable=true)
+     */
+    private $otherPractice;
+
+    /**
+     * @ORM\ManyToMany(targetEntity=ContactPoint::class, mappedBy="organization")
+     * @ApiSubresource()
+     */
+    private $contactPoints;
+
+    /**
+     * @ORM\ManyToMany(targetEntity=BankAccount::class, mappedBy="organization")
+     * @ApiSubresource()
+     */
+    private $bankAccounts;
+
+    /**
+     * @ORM\OneToMany(targetEntity=OrganizationAddressPostal::class, mappedBy="organization", orphanRemoval=true)
+     * @ApiSubresource()
+     */
+    private $organizationAddressPostals;
+
+    /**
+     * @ORM\OneToMany(targetEntity=OrganizationLicence::class, mappedBy="organization", orphanRemoval=true)
+     */
+    private $organizationLicences;
+
     public function __construct()
     {
         $this->networkOrganizations = new ArrayCollection();
         $this->networkOrganizationChildren = new ArrayCollection();
+        $this->contactPoints = new ArrayCollection();
+        $this->bankAccounts = new ArrayCollection();
+        $this->organizationAddressPostals = new ArrayCollection();
+        $this->organizationLicences = new ArrayCollection();
     }
 
     public function getId(): ?int
@@ -222,4 +421,514 @@ class Organization
 
         return $this;
     }
+
+    public function getDescription(): ?string
+    {
+        return $this->description;
+    }
+
+    public function setDescription(?string $description): self
+    {
+        $this->description = $description;
+
+        return $this;
+    }
+
+    public function getCreationDate(): ?\DateTimeInterface
+    {
+        return $this->creationDate;
+    }
+
+    public function setCreationDate(?\DateTimeInterface $creationDate): self
+    {
+        $this->creationDate = $creationDate;
+
+        return $this;
+    }
+
+    public function getDeclarationDate(): ?\DateTimeInterface
+    {
+        return $this->declarationDate;
+    }
+
+    public function setDeclarationDate(?\DateTimeInterface $declarationDate): self
+    {
+        $this->declarationDate = $declarationDate;
+
+        return $this;
+    }
+
+    public function getSiretNumber(): ?string
+    {
+        return $this->siretNumber;
+    }
+
+    public function setSiretNumber(?string $siretNumber): self
+    {
+        $this->siretNumber = $siretNumber;
+
+        return $this;
+    }
+
+    public function getWaldecNumber(): ?string
+    {
+        return $this->waldecNumber;
+    }
+
+    public function setWaldecNumber(?string $waldecNumber): self
+    {
+        $this->waldecNumber = $waldecNumber;
+
+        return $this;
+    }
+
+    public function getApeNumber(): ?string
+    {
+        return $this->apeNumber;
+    }
+
+    public function setApeNumber(?string $apeNumber): self
+    {
+        $this->apeNumber = $apeNumber;
+
+        return $this;
+    }
+
+    public function getTvaNumber(): ?string
+    {
+        return $this->tvaNumber;
+    }
+
+    public function setTvaNumber(?string $tvaNumber): self
+    {
+        $this->tvaNumber = $tvaNumber;
+
+        return $this;
+    }
+
+    public function getOtherType(): ?string
+    {
+        return $this->otherType;
+    }
+
+    public function setOtherType(?string $otherType): self
+    {
+        $this->otherType = $otherType;
+
+        return $this;
+    }
+
+    public function getAcronym(): ?string
+    {
+        return $this->acronym;
+    }
+
+    public function setAcronym(?string $acronym): self
+    {
+        $this->acronym = $acronym;
+
+        return $this;
+    }
+
+    public function getFacebook(): ?string
+    {
+        return $this->facebook;
+    }
+
+    public function setFacebook(?string $facebook): self
+    {
+        $this->facebook = $facebook;
+
+        return $this;
+    }
+
+    public function getTwitter(): ?string
+    {
+        return $this->twitter;
+    }
+
+    public function setTwitter(?string $twitter): self
+    {
+        $this->twitter = $twitter;
+
+        return $this;
+    }
+
+    public function getInstagram(): ?string
+    {
+        return $this->instagram;
+    }
+
+    public function setInstagram(?string $instagram): self
+    {
+        $this->instagram = $instagram;
+
+        return $this;
+    }
+
+    public function getCollectiveAgreement(): ?string
+    {
+        return $this->collectiveAgreement;
+    }
+
+    public function setCollectiveAgreement(?string $collectiveAgreement): self
+    {
+        $this->collectiveAgreement = $collectiveAgreement;
+
+        return $this;
+    }
+
+    public function getOpca(): ?string
+    {
+        return $this->opca;
+    }
+
+    public function setOpca(?string $opca): self
+    {
+        $this->opca = $opca;
+
+        return $this;
+    }
+
+    public function getIcomNumber(): ?string
+    {
+        return $this->icomNumber;
+    }
+
+    public function setIcomNumber(?string $icomNumber): self
+    {
+        $this->icomNumber = $icomNumber;
+
+        return $this;
+    }
+
+    public function getUrssafNumber(): ?string
+    {
+        return $this->urssafNumber;
+    }
+
+    public function setUrssafNumber(?string $urssafNumber): self
+    {
+        $this->urssafNumber = $urssafNumber;
+
+        return $this;
+    }
+
+    public function getYoungApproval(): ?string
+    {
+        return $this->youngApproval;
+    }
+
+    public function setYoungApproval(?string $youngApproval): self
+    {
+        $this->youngApproval = $youngApproval;
+
+        return $this;
+    }
+
+    public function getTrainingApproval(): ?string
+    {
+        return $this->trainingApproval;
+    }
+
+    public function setTrainingApproval(?string $trainingApproval): self
+    {
+        $this->trainingApproval = $trainingApproval;
+
+        return $this;
+    }
+
+    public function getOtherApproval(): ?string
+    {
+        return $this->otherApproval;
+    }
+
+    public function setOtherApproval(?string $otherApproval): self
+    {
+        $this->otherApproval = $otherApproval;
+
+        return $this;
+    }
+
+    public function getPrefectureName(): ?string
+    {
+        return $this->prefectureName;
+    }
+
+    public function setPrefectureName(?string $prefectureName): self
+    {
+        $this->prefectureName = $prefectureName;
+
+        return $this;
+    }
+
+    public function getPrefectureNumber(): ?string
+    {
+        return $this->prefectureNumber;
+    }
+
+    public function setPrefectureNumber(?string $prefectureNumber): self
+    {
+        $this->prefectureNumber = $prefectureNumber;
+
+        return $this;
+    }
+
+    public function getCategory(): ?string
+    {
+        return $this->category;
+    }
+
+    public function setCategory(?string $category): self
+    {
+        $this->category = $category;
+
+        return $this;
+    }
+
+    public function getSchoolCategory(): ?string
+    {
+        return $this->schoolCategory;
+    }
+
+    public function setSchoolCategory(?string $schoolCategory): self
+    {
+        $this->schoolCategory = $schoolCategory;
+
+        return $this;
+    }
+
+    public function getTypeEstablishment(): ?string
+    {
+        return $this->typeEstablishment;
+    }
+
+    public function setTypeEstablishment(?string $typeEstablishment): self
+    {
+        $this->typeEstablishment = $typeEstablishment;
+
+        return $this;
+    }
+
+    public function getTypeEstablishmentDetail(): ?string
+    {
+        return $this->typeEstablishmentDetail;
+    }
+
+    public function setTypeEstablishmentDetail(?string $typeEstablishmentDetail): self
+    {
+        $this->typeEstablishmentDetail = $typeEstablishmentDetail;
+
+        return $this;
+    }
+
+    public function getBudget(): ?float
+    {
+        return $this->budget;
+    }
+
+    public function setBudget(?float $budget): self
+    {
+        $this->budget = $budget;
+
+        return $this;
+    }
+
+    public function getIsPedagogicIsPrincipalActivity(): ?bool
+    {
+        return $this->isPedagogicIsPrincipalActivity;
+    }
+
+    public function setIsPedagogicIsPrincipalActivity(?bool $isPedagogicIsPrincipalActivity): self
+    {
+        $this->isPedagogicIsPrincipalActivity = $isPedagogicIsPrincipalActivity;
+
+        return $this;
+    }
+
+    public function getPedagogicBudget(): ?float
+    {
+        return $this->pedagogicBudget;
+    }
+
+    public function setPedagogicBudget(?float $pedagogicBudget): self
+    {
+        $this->pedagogicBudget = $pedagogicBudget;
+
+        return $this;
+    }
+
+    public function getIsPerformanceContractor(): ?bool
+    {
+        return $this->isPerformanceContractor;
+    }
+
+    public function setIsPerformanceContractor(?bool $isPerformanceContractor): self
+    {
+        $this->isPerformanceContractor = $isPerformanceContractor;
+
+        return $this;
+    }
+
+    public function getFfecApproval(): ?string
+    {
+        return $this->ffecApproval;
+    }
+
+    public function setFfecApproval(?string $ffecApproval): self
+    {
+        $this->ffecApproval = $ffecApproval;
+
+        return $this;
+    }
+
+    public function getPortailVisibility(): ?bool
+    {
+        return $this->portailVisibility;
+    }
+
+    public function setPortailVisibility(bool $portailVisibility): self
+    {
+        $this->portailVisibility = $portailVisibility;
+
+        return $this;
+    }
+
+    public function getCmsId(): ?int
+    {
+        return $this->cmsId;
+    }
+
+    public function setCmsId(?int $cmsId): self
+    {
+        $this->cmsId = $cmsId;
+
+        return $this;
+    }
+
+    public function getOtherPractice(): ?string
+    {
+        return $this->otherPractice;
+    }
+
+    public function setOtherPractice(?string $otherPractice): self
+    {
+        $this->otherPractice = $otherPractice;
+
+        return $this;
+    }
+
+    /**
+     * @return Collection|ContactPoint[]
+     */
+    public function getContactPoints(): Collection
+    {
+        return $this->contactPoints;
+    }
+
+    public function addContactPoint(ContactPoint $contactPoint): self
+    {
+        if (!$this->contactPoints->contains($contactPoint)) {
+            $this->contactPoints[] = $contactPoint;
+            $contactPoint->addOrganization($this);
+        }
+
+        return $this;
+    }
+
+    public function removeContactPoint(ContactPoint $contactPoint): self
+    {
+        if ($this->contactPoints->removeElement($contactPoint)) {
+            $contactPoint->removeOrganization($this);
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return Collection|BankAccount[]
+     */
+    public function getBankAccounts(): Collection
+    {
+        return $this->bankAccounts;
+    }
+
+    public function addBankAccount(BankAccount $bankAccount): self
+    {
+        if (!$this->bankAccounts->contains($bankAccount)) {
+            $this->bankAccounts[] = $bankAccount;
+            $bankAccount->addOrganization($this);
+        }
+
+        return $this;
+    }
+
+    public function removeBankAccount(BankAccount $bankAccount): self
+    {
+        if ($this->bankAccounts->removeElement($bankAccount)) {
+            $bankAccount->removeOrganization($this);
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return Collection|OrganizationAddressPostal[]
+     */
+    public function getOrganizationAddressPostals(): Collection
+    {
+        return $this->organizationAddressPostals;
+    }
+
+    public function addOrganizationAddressPostal(OrganizationAddressPostal $organizationAddressPostal): self
+    {
+        if (!$this->organizationAddressPostals->contains($organizationAddressPostal)) {
+            $this->organizationAddressPostals[] = $organizationAddressPostal;
+            $organizationAddressPostal->setOrganization($this);
+        }
+
+        return $this;
+    }
+
+    public function removeOrganizationAddressPostal(OrganizationAddressPostal $organizationAddressPostal): self
+    {
+        if ($this->organizationAddressPostals->removeElement($organizationAddressPostal)) {
+            // set the owning side to null (unless already changed)
+            if ($organizationAddressPostal->getOrganization() === $this) {
+                $organizationAddressPostal->setOrganization(null);
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return Collection|OrganizationLicence[]
+     */
+    public function getOrganizationLicences(): Collection
+    {
+        return $this->organizationLicences;
+    }
+
+    public function addOrganizationLicence(OrganizationLicence $organizationLicence): self
+    {
+        if (!$this->organizationLicences->contains($organizationLicence)) {
+            $this->organizationLicences[] = $organizationLicence;
+            $organizationLicence->setOrganization($this);
+        }
+
+        return $this;
+    }
+
+    public function removeOrganizationLicence(OrganizationLicence $organizationLicence): self
+    {
+        if ($this->organizationLicences->removeElement($organizationLicence)) {
+            // set the owning side to null (unless already changed)
+            if ($organizationLicence->getOrganization() === $this) {
+                $organizationLicence->setOrganization(null);
+            }
+        }
+
+        return $this;
+    }
 }

+ 83 - 0
src/Entity/Organization/OrganizationAddressPostal.php

@@ -0,0 +1,83 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Entity\Organization;
+
+use ApiPlatform\Core\Annotation\ApiResource;
+use App\Entity\Core\AddressPostal;
+use App\Repository\Organization\OrganizationAddressPostalRepository;
+use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Validator\Constraints as Assert;
+
+/**
+ * @ApiResource()
+ * @ORM\Entity(repositoryClass=OrganizationAddressPostalRepository::class)
+ */
+class OrganizationAddressPostal
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\ManyToOne(targetEntity=Organization::class, inversedBy="organizationAddressPostals")
+     * @ORM\JoinColumn(nullable=false)
+     */
+    private $organization;
+
+    /**
+     * @ORM\OneToOne(targetEntity=AddressPostal::class, inversedBy="organizationAddressPostal", cascade={"persist", "remove"})
+     * @ORM\JoinColumn(nullable=false)
+     */
+    private $addressPostal;
+
+    /**
+     * @ORM\Column(type="string", length=255)
+     * @Assert\Choice(callback={"AppBundle\Enum\Core\AddressPostalTypeEnum", "toArray"})
+     */
+    private $type;
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getOrganization(): ?Organization
+    {
+        return $this->organization;
+    }
+
+    public function setOrganization(?Organization $organization): self
+    {
+        $this->organization = $organization;
+
+        return $this;
+    }
+
+    public function getAddressPostal(): ?AddressPostal
+    {
+        return $this->addressPostal;
+    }
+
+    public function setAddressPostal(AddressPostal $addressPostal): self
+    {
+        $this->addressPostal = $addressPostal;
+
+        return $this;
+    }
+
+    public function getType(): ?string
+    {
+        return $this->type;
+    }
+
+    public function setType(string $type): self
+    {
+        $this->type = $type;
+
+        return $this;
+    }
+}

+ 114 - 0
src/Entity/Organization/OrganizationLicence.php

@@ -0,0 +1,114 @@
+<?php
+
+namespace App\Entity\Organization;
+
+use ApiPlatform\Core\Annotation\ApiResource;
+use App\Entity\Access\Access;
+use App\Repository\Organization\OrganizationLicenceRepository;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ApiResource()
+ * @ORM\Entity(repositoryClass=OrganizationLicenceRepository::class)
+ */
+class OrganizationLicence
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\ManyToOne(targetEntity=Organization::class, inversedBy="organizationLicences")
+     * @ORM\JoinColumn(nullable=false)
+     */
+    private $organization;
+
+    /**
+     * @ORM\ManyToOne(targetEntity=Access::class, inversedBy="organizationLicences")
+     * @ORM\JoinColumn(nullable=false)
+     */
+    private $licensee;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $licenceNumber;
+
+    /**
+     * @ORM\Column(type="string", length=255, nullable=true)
+     */
+    private $categorie;
+
+    /**
+     * @ORM\Column(type="date", nullable=true)
+     */
+    private $validityDate;
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getOrganization(): ?Organization
+    {
+        return $this->organization;
+    }
+
+    public function setOrganization(?Organization $organization): self
+    {
+        $this->organization = $organization;
+
+        return $this;
+    }
+
+    public function getLicensee(): ?Access
+    {
+        return $this->licensee;
+    }
+
+    public function setLicensee(?Access $licensee): self
+    {
+        $this->licensee = $licensee;
+
+        return $this;
+    }
+
+    public function getLicenceNumber(): ?string
+    {
+        return $this->licenceNumber;
+    }
+
+    public function setLicenceNumber(?string $licenceNumber): self
+    {
+        $this->licenceNumber = $licenceNumber;
+
+        return $this;
+    }
+
+    public function getCategorie(): ?string
+    {
+        return $this->categorie;
+    }
+
+    public function setCategorie(?string $categorie): self
+    {
+        $this->categorie = $categorie;
+
+        return $this;
+    }
+
+    public function getValidityDate(): ?\DateTimeInterface
+    {
+        return $this->validityDate;
+    }
+
+    public function setValidityDate(?\DateTimeInterface $validityDate): self
+    {
+        $this->validityDate = $validityDate;
+
+        return $this;
+    }
+}

+ 34 - 0
src/Entity/Person/Person.php

@@ -3,6 +3,7 @@ declare(strict_types=1);
 
 namespace App\Entity\Person;
 
+use App\Entity\Core\ContactPoint;
 use App\Repository\Person\PersonRepository;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\Common\Collections\Collection;
@@ -49,9 +50,15 @@ class Person implements UserInterface
      */
     private $givenName;
 
+    /**
+     * @ORM\ManyToMany(targetEntity=ContactPoint::class, mappedBy="person")
+     */
+    private $contactPoints;
+
 
     public function __construct()
     {
+        $this->contactPoints = new ArrayCollection();
     }
 
     public function getId(): ?int
@@ -150,4 +157,31 @@ class Person implements UserInterface
 
         return $this;
     }
+
+    /**
+     * @return Collection|ContactPoint[]
+     */
+    public function getContactPoints(): Collection
+    {
+        return $this->contactPoints;
+    }
+
+    public function addContactPoint(ContactPoint $contactPoint): self
+    {
+        if (!$this->contactPoints->contains($contactPoint)) {
+            $this->contactPoints[] = $contactPoint;
+            $contactPoint->addPerson($this);
+        }
+
+        return $this;
+    }
+
+    public function removeContactPoint(ContactPoint $contactPoint): self
+    {
+        if ($this->contactPoints->removeElement($contactPoint)) {
+            $contactPoint->removePerson($this);
+        }
+
+        return $this;
+    }
 }

+ 30 - 0
src/Enum/Core/ContactPointTypeEnum.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Enum\Core;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Type de point de contact
+ *
+ */
+class ContactPointTypeEnum extends Enum
+{
+    private const PRINCIPAL = 'PRINCIPAL';
+    private const BILL = 'BILL';
+    private const OTHER = 'OTHER';
+    private const CONTACT = 'CONTACT';
+
+    /**
+     * @param bool $type
+     * @return array
+     */
+    public static function toArrayCustom($type = false)
+    {
+        if($type == 'person'){
+            return ['PRINCIPAL'=>self::PRINCIPAL,'OTHER'=>self::OTHER];
+        }else{
+            return parent::toArray();
+        }
+    }
+}

+ 16 - 0
src/Enum/Organization/AddressPostalOrganizationTypeEnum.php

@@ -0,0 +1,16 @@
+<?php
+namespace App\Enum\ORganization;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Type d'adresse postale
+ */
+class AddressPostalOrganizationTypeEnum extends Enum
+{
+    private const ADDRESS_PRACTICE = 'ADDRESS_PRACTICE';
+    private const ADDRESS_HEAD_OFFICE = 'ADDRESS_HEAD_OFFICE';
+    private const ADDRESS_CONTACT = 'ADDRESS_CONTACT';
+    private const ADDRESS_BILL = 'ADDRESS_BILL';
+    private const ADDRESS_OTHER = 'ADDRESS_OTHER';
+}

+ 19 - 0
src/Enum/Organization/CategoryEnum.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Enum\Organization;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Catégorie de la structure
+ */
+class CategoryEnum extends Enum
+{
+    private const PROFESSIONAL = 'PROFESSIONAL';
+    private const ARTISTIC_ENSEMBLE = 'ARTISTIC_ENSEMBLE';
+    private const SCHOOL_OF_ARTS = 'SCHOOL_OF_ARTS';
+    private const NETWORK = 'NETWORK';
+    private const ORGANIZER = 'ORGANIZER';
+    private const PERSON = 'PERSON';
+    private const OTHER = 'OTHER';
+}

+ 16 - 0
src/Enum/Organization/LegalEnum.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Enum\Organization;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Statut légal
+ */
+class LegalEnum extends Enum
+{
+    private const LOCAL_AUTHORITY = 'LOCAL_AUTHORITY';
+    private const ASSOCIATION_LAW_1901 = 'ASSOCIATION_LAW_1901';
+    private const COMMERCIAL_SOCIETY = 'COMMERCIAL_SOCIETY';
+
+}

+ 39 - 0
src/Enum/Organization/OpcaEnum.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace App\Enum\Organization;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Liste des OPCA
+ */
+class OpcaEnum extends Enum
+{
+    private const ACTALIANS = 'ACTALIANS';
+    private const AFDAS = 'AFDAS';
+    private const AGEFOS = 'AGEFOS';
+    private const ANFA = 'ANFA';
+    private const ANFH = 'ANFH';
+    private const APCMA = 'APCMA';
+    private const CONSTRUCTYS = 'CONSTRUCTYS';
+    private const FONGECIF = 'FONGECIF';
+    private const FAFIEC = 'FAFIEC';
+    private const FAFIH = 'FAFIH';
+    private const FAFSEA = 'FAFSEA';
+    private const FAF_TT = 'FAF_TT';
+    private const FIF_PL = 'FIF_PL';
+    private const FORCO = 'FORCO';
+    private const INTERGROS = 'INTERGROS';
+    private const OPCA3 = 'OPCA3_PLUS';
+    private const OPCA_DEFI = 'OPCA_DEFI';
+    private const OPCA_BAIA = 'OPCA_BAIA';
+    private const OPCA_TRANSPORTS = 'OPCA_TRANSPORTS';
+    private const OPCAIM = 'OPCAIM';
+    private const OPCALIA = 'OPCALIA';
+    private const OPCALIM = 'OPCALIM';
+    private const UNIFAF = 'UNIFAF';
+    private const UNIFORMATION = 'UNIFORMATION';
+    private const VIVEA = 'VIVEA';
+    private const AGEFOS_PME = 'AGEFOS_PME';
+    private const CNFPT = 'CNFPT';
+}

+ 20 - 0
src/Enum/Organization/SchoolCategoryEnum.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Enum\Organization;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Catégorie de l'école
+ */
+class SchoolCategoryEnum extends Enum
+{
+    private const CESMD = 'CESMD';
+    private const CNSMD = 'CNSMD';
+    private const CRC = 'CRC';
+    private const CRI = 'CRI';
+    private const CRD = 'CRD';
+    private const CRR = 'CRR';
+    private const EENC = 'EENC';
+    private const EMP = 'EMP';
+}

+ 14 - 0
src/Enum/Organization/TypeEstablishmentDetailEnum.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Enum\Organization;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Détails du type de l'établissement
+ */
+class TypeEstablishmentDetailEnum extends Enum
+{
+    private const MAIN_BUILDING = 'MAIN_BUILDING';
+    private const SECONDARY_SCHOOL = 'SECONDARY_SCHOOL';
+}

+ 15 - 0
src/Enum/Organization/TypeEstablishmentEnum.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace App\Enum\Organization;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Type d'établissement
+ *
+ */
+class TypeEstablishmentEnum extends Enum
+{
+    private const UNIQUE = 'UNIQUE';
+    private const MULTIPLE = 'MULTIPLE';
+}

+ 50 - 0
src/Repository/Core/AddressPostalRepository.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Repository\Core;
+
+use App\Entity\Core\AddressPostal;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method AddressPostal|null find($id, $lockMode = null, $lockVersion = null)
+ * @method AddressPostal|null findOneBy(array $criteria, array $orderBy = null)
+ * @method AddressPostal[]    findAll()
+ * @method AddressPostal[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class AddressPostalRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, AddressPostal::class);
+    }
+
+    // /**
+    //  * @return AddressPostal[] Returns an array of AddressPostal objects
+    //  */
+    /*
+    public function findByExampleField($value)
+    {
+        return $this->createQueryBuilder('a')
+            ->andWhere('a.exampleField = :val')
+            ->setParameter('val', $value)
+            ->orderBy('a.id', 'ASC')
+            ->setMaxResults(10)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+    */
+
+    /*
+    public function findOneBySomeField($value): ?AddressPostal
+    {
+        return $this->createQueryBuilder('a')
+            ->andWhere('a.exampleField = :val')
+            ->setParameter('val', $value)
+            ->getQuery()
+            ->getOneOrNullResult()
+        ;
+    }
+    */
+}

+ 50 - 0
src/Repository/Core/BankAccountRepository.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Repository\Core;
+
+use App\Entity\Core\BankAccount;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method BankAccount|null find($id, $lockMode = null, $lockVersion = null)
+ * @method BankAccount|null findOneBy(array $criteria, array $orderBy = null)
+ * @method BankAccount[]    findAll()
+ * @method BankAccount[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class BankAccountRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, BankAccount::class);
+    }
+
+    // /**
+    //  * @return BankAccount[] Returns an array of BankAccount objects
+    //  */
+    /*
+    public function findByExampleField($value)
+    {
+        return $this->createQueryBuilder('b')
+            ->andWhere('b.exampleField = :val')
+            ->setParameter('val', $value)
+            ->orderBy('b.id', 'ASC')
+            ->setMaxResults(10)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+    */
+
+    /*
+    public function findOneBySomeField($value): ?BankAccount
+    {
+        return $this->createQueryBuilder('b')
+            ->andWhere('b.exampleField = :val')
+            ->setParameter('val', $value)
+            ->getQuery()
+            ->getOneOrNullResult()
+        ;
+    }
+    */
+}

+ 50 - 0
src/Repository/Core/ContactPointRepository.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Repository\Core;
+
+use App\Entity\Core\ContactPoint;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method ContactPoint|null find($id, $lockMode = null, $lockVersion = null)
+ * @method ContactPoint|null findOneBy(array $criteria, array $orderBy = null)
+ * @method ContactPoint[]    findAll()
+ * @method ContactPoint[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class ContactPointRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, ContactPoint::class);
+    }
+
+    // /**
+    //  * @return ContactPoint[] Returns an array of ContactPoint objects
+    //  */
+    /*
+    public function findByExampleField($value)
+    {
+        return $this->createQueryBuilder('c')
+            ->andWhere('c.exampleField = :val')
+            ->setParameter('val', $value)
+            ->orderBy('c.id', 'ASC')
+            ->setMaxResults(10)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+    */
+
+    /*
+    public function findOneBySomeField($value): ?ContactPoint
+    {
+        return $this->createQueryBuilder('c')
+            ->andWhere('c.exampleField = :val')
+            ->setParameter('val', $value)
+            ->getQuery()
+            ->getOneOrNullResult()
+        ;
+    }
+    */
+}

+ 50 - 0
src/Repository/Core/CountryRepository.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Repository\Core;
+
+use App\Entity\Core\Country;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method Country|null find($id, $lockMode = null, $lockVersion = null)
+ * @method Country|null findOneBy(array $criteria, array $orderBy = null)
+ * @method Country[]    findAll()
+ * @method Country[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class CountryRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, Country::class);
+    }
+
+    // /**
+    //  * @return Country[] Returns an array of Country objects
+    //  */
+    /*
+    public function findByExampleField($value)
+    {
+        return $this->createQueryBuilder('c')
+            ->andWhere('c.exampleField = :val')
+            ->setParameter('val', $value)
+            ->orderBy('c.id', 'ASC')
+            ->setMaxResults(10)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+    */
+
+    /*
+    public function findOneBySomeField($value): ?Country
+    {
+        return $this->createQueryBuilder('c')
+            ->andWhere('c.exampleField = :val')
+            ->setParameter('val', $value)
+            ->getQuery()
+            ->getOneOrNullResult()
+        ;
+    }
+    */
+}

+ 50 - 0
src/Repository/Organization/OrganizationAddressPostalRepository.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Repository\Organization;
+
+use App\Entity\Organization\OrganizationAddressPostal;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method OrganizationAddressPostal|null find($id, $lockMode = null, $lockVersion = null)
+ * @method OrganizationAddressPostal|null findOneBy(array $criteria, array $orderBy = null)
+ * @method OrganizationAddressPostal[]    findAll()
+ * @method OrganizationAddressPostal[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class OrganizationAddressPostalRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, OrganizationAddressPostal::class);
+    }
+
+    // /**
+    //  * @return OrganizationAddressPostal[] Returns an array of OrganizationAddressPostal objects
+    //  */
+    /*
+    public function findByExampleField($value)
+    {
+        return $this->createQueryBuilder('o')
+            ->andWhere('o.exampleField = :val')
+            ->setParameter('val', $value)
+            ->orderBy('o.id', 'ASC')
+            ->setMaxResults(10)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+    */
+
+    /*
+    public function findOneBySomeField($value): ?OrganizationAddressPostal
+    {
+        return $this->createQueryBuilder('o')
+            ->andWhere('o.exampleField = :val')
+            ->setParameter('val', $value)
+            ->getQuery()
+            ->getOneOrNullResult()
+        ;
+    }
+    */
+}

+ 50 - 0
src/Repository/Organization/OrganizationLicenceRepository.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Repository\Organization;
+
+use App\Entity\Organization\OrganizationLicence;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method OrganizationLicence|null find($id, $lockMode = null, $lockVersion = null)
+ * @method OrganizationLicence|null findOneBy(array $criteria, array $orderBy = null)
+ * @method OrganizationLicence[]    findAll()
+ * @method OrganizationLicence[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class OrganizationLicenceRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, OrganizationLicence::class);
+    }
+
+    // /**
+    //  * @return OrganizationLicence[] Returns an array of OrganizationLicence objects
+    //  */
+    /*
+    public function findByExampleField($value)
+    {
+        return $this->createQueryBuilder('o')
+            ->andWhere('o.exampleField = :val')
+            ->setParameter('val', $value)
+            ->orderBy('o.id', 'ASC')
+            ->setMaxResults(10)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+    */
+
+    /*
+    public function findOneBySomeField($value): ?OrganizationLicence
+    {
+        return $this->createQueryBuilder('o')
+            ->andWhere('o.exampleField = :val')
+            ->setParameter('val', $value)
+            ->getQuery()
+            ->getOneOrNullResult()
+        ;
+    }
+    */
+}

+ 62 - 0
src/Security/Voter/BankAccountVoter.php

@@ -0,0 +1,62 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Security\Voter;
+
+use App\Entity\Access\Access;
+use App\Entity\Core\BankAccount;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authorization\Voter\Voter;
+use Symfony\Component\Security\Core\Security;
+use Symfony\Component\Security\Core\User\UserInterface;
+
+class BankAccountVoter extends Voter
+{
+    private Security $security;
+
+    public function __construct(Security $security)
+    {
+        $this->security = $security;
+    }
+
+    protected function supports($attribute, $subject): bool
+    {
+        return in_array($attribute, ['BANK_ACCOUNT_READ', 'BANK_ACCOUNT_EDIT'])
+            && $subject instanceof BankAccount;
+    }
+
+    /**
+     * @param string $attribute
+     * @param mixed $subject
+     * @param TokenInterface $token
+     * @return bool
+     */
+    protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
+    {
+        /** @var Access $user */
+        $user = $token->getUser();
+        // if the user is anonymous, do not grant access
+        if (!$user instanceof UserInterface) {
+            return false;
+        }
+
+        switch ($attribute) {
+            case 'BANK_ACCOUNT_READ':
+                if($subject->getOrganization()->count() === 1){
+                    return $this->security->isGranted('ROLE_ORGANIZATION_VIEW')
+                        && $subject->getOrganization()->current()->getId() === $user->getOrganization()->getId();
+                }
+                break;
+            case 'BANK_ACCOUNT_EDIT':
+                if($subject->getOrganization()->count() === 1){
+                    return $this->security->isGranted('ROLE_ORGANIZATION')
+                        && $subject->getOrganization()->current()->getId() === $user->getOrganization()->getId();
+                }
+                break;
+        }
+
+        return false;
+    }
+
+
+}

+ 62 - 0
src/Security/Voter/ContactPointVoter.php

@@ -0,0 +1,62 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Security\Voter;
+
+use App\Entity\Access\Access;
+use App\Entity\Core\ContactPoint;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authorization\Voter\Voter;
+use Symfony\Component\Security\Core\Security;
+use Symfony\Component\Security\Core\User\UserInterface;
+
+class ContactPointVoter extends Voter
+{
+    private Security $security;
+
+    public function __construct(Security $security)
+    {
+        $this->security = $security;
+    }
+
+    protected function supports($attribute, $subject): bool
+    {
+        return in_array($attribute, ['CONTACT_POINT_READ', 'CONTACT_POINT_EDIT'])
+            && $subject instanceof ContactPoint;
+    }
+
+    /**
+     * @param string $attribute
+     * @param mixed $subject
+     * @param TokenInterface $token
+     * @return bool
+     */
+    protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
+    {
+        /** @var Access $user */
+        $user = $token->getUser();
+        // if the user is anonymous, do not grant access
+        if (!$user instanceof UserInterface) {
+            return false;
+        }
+
+        switch ($attribute) {
+            case 'CONTACT_POINT_READ':
+                if($subject->getOrganization()->count() === 1){
+                    return $this->security->isGranted('ROLE_ORGANIZATION_VIEW')
+                        && $subject->getOrganization()->current()->getId() === $user->getOrganization()->getId();
+                }
+                break;
+            case 'CONTACT_POINT_EDIT':
+                if($subject->getOrganization()->count() === 1){
+                    return $this->security->isGranted('ROLE_ORGANIZATION')
+                        && $subject->getOrganization()->current()->getId() === $user->getOrganization()->getId();
+                }
+                break;
+        }
+
+        return false;
+    }
+
+
+}

+ 2 - 2
src/Security/ModuleVoter.php → src/Security/Voter/ModuleVoter.php

@@ -1,7 +1,7 @@
 <?php
 declare(strict_types=1);
 
-namespace App\Security;
+namespace App\Security\Voter;
 
 use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
 use App\Entity\Access\Access;
@@ -33,7 +33,7 @@ class ModuleVoter extends Voter
     /**
      * @inheritDoc
      */
-    protected function supports(string $attribute, $subject)
+    protected function supports(string $attribute, $subject): bool
     {
         if (!in_array($attribute, [self::HAVING_MODULE])) {
             return false;

+ 57 - 0
src/Serializer/OpentalentNormalizer.php

@@ -0,0 +1,57 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Serializer;
+
+use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+use Symfony\Component\Serializer\SerializerAwareInterface;
+use Symfony\Component\Serializer\SerializerInterface;
+
+/**
+ * Class OpentalentNormalizer : class décoratrice du serializer de base.
+ * @package App\Serializer
+ */
+final class OpentalentNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
+{
+    private NormalizerInterface $decorated;
+
+    public function __construct(
+        NormalizerInterface $decorated
+    )
+    {
+        if (!$decorated instanceof DenormalizerInterface) {
+            throw new \InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class));
+        }
+
+        $this->decorated = $decorated;
+    }
+
+    public function supportsNormalization($data, $format = null)
+    {
+        return $this->decorated->supportsNormalization($data, $format);
+    }
+
+    public function normalize($object, $format = null, array $context = [])
+    {
+        $data = $this->decorated->normalize($object, $format, $context);
+        return $data;
+    }
+
+    public function supportsDenormalization($data, $type, $format = null)
+    {
+        return $this->decorated->supportsDenormalization($data, $type, $format);
+    }
+
+    public function denormalize($data, $class, $format = null, array $context = [])
+    {
+        return $this->decorated->denormalize($data, $class, $format, $context);
+    }
+
+    public function setSerializer(SerializerInterface $serializer)
+    {
+        if($this->decorated instanceof SerializerAwareInterface) {
+            $this->decorated->setSerializer($serializer);
+        }
+    }
+}

+ 1 - 6
src/Service/Network/Tree.php

@@ -49,12 +49,7 @@ class Tree
         ];
 
         usort($organizations, function(Organization $organization1, Organization $organization2) use($typeOrder){
-            $orderOrganization1 = array_keys($typeOrder, $organization1->getPrincipalType());
-            $orderOrganization2 = array_keys($typeOrder, $organization2->getPrincipalType());
-            if ($orderOrganization1 == $orderOrganization2) {
-                return 0;
-            }
-            return ($orderOrganization1 < $orderOrganization2) ? -1 : 1;
+            return array_keys($typeOrder, $organization1->getPrincipalType()) <=> array_keys($typeOrder, $organization2->getPrincipalType());
         });
 
         return $organizations;

+ 12 - 13
src/Service/Security/Module.php

@@ -4,12 +4,12 @@ declare(strict_types=1);
 namespace App\Service\Security;
 
 use App\Entity\Organization\Organization;
+use App\Service\Utils\Parser;
 use App\Service\Utils\Reflection;
 use App\Test\Service\Security\ModuleTest;
 use Doctrine\Common\Cache\ApcuCache;
 use Symfony\Component\Config\FileLocator;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
-use Symfony\Component\Yaml\Yaml;
 
 /**
  * Class Module : classe gérant la récupération de l'ensemble des modules possédées par une organisation
@@ -17,15 +17,18 @@ use Symfony\Component\Yaml\Yaml;
  */
 class Module
 {
-    const OPENTALENT_CONFIG = __DIR__.'/../../../config/opentalent';
-
     private array $moduleConfig;
     private array $moduleByConditionsConfig;
     private Reflection $reflection;
+    private Parser $parser;
+    private string $opentalentConfig;
 
-    public function __construct(Reflection $reflection)
+    public function __construct(Reflection $reflection, Parser $parser,  string $opentalentConfig)
     {
         $this->reflection = $reflection;
+        $this->parser = $parser;
+        $this->opentalentConfig = $opentalentConfig;
+
         $this->moduleConfig = $this->getModuleConfig();
         $this->moduleByConditionsConfig = $this->getModuleByConditionsConfig();
     }
@@ -87,7 +90,7 @@ class Module
         $modules = $this->moduleByConditionsConfig['opentalent']['modulesbyconditions'];
         foreach ($modules as $moduleName => $module) {
             try{
-                $response = $this->reflection->dynamicInvokeWithArgsServiceMethod(
+                $response = $this->reflection->dynamicInvokeServiceWithArgsAndMethod(
                     $module["conditions"]["service"]["name"],
                     $module["conditions"]["service"]["function"],
                     array($organization)
@@ -126,23 +129,19 @@ class Module
     /**
      * Parse et retourne le contenu du fichier products.yaml
      * @return array
+     * @throws \Exception
      */
     private function getModuleConfig(): array{
-        $configDirectories = [self::OPENTALENT_CONFIG];
-        $fileLocator = new FileLocator($configDirectories);
-        $yamlConfig = $fileLocator->locate('products.yaml', null, false)[0];
-        return Yaml::parseFile($yamlConfig);
+        return $this->parser->yamlParser($this->opentalentConfig, 'products.yaml');
     }
 
     /**
      * Parse et retourne le contenu du fichier modulesbyconditions.yaml
      * @return array
+     * @throws \Exception
      */
     private function getModuleByConditionsConfig(): array{
-        $configDirectories = [self::OPENTALENT_CONFIG];
-        $fileLocator = new FileLocator($configDirectories);
-        $yamlConfig = $fileLocator->locate('modulesbyconditions.yaml', null, false)[0];
-        return Yaml::parseFile($yamlConfig);
+        return $this->parser->yamlParser($this->opentalentConfig, 'modulesbyconditions.yaml');
     }
 
     /**

+ 28 - 0
src/Service/Utils/Dates.php

@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\Utils;
+
+/**
+ * Class Dates : méthodes d'aide pour la gestion de dates.
+ * @package App\Service\Utils
+ */
+class Dates
+{
+    public function __construct()
+    {
+    }
+
+    /**
+     * Vérifie si la date du jour est comprise dans l'inerval passé en paramètres
+     * @param \DateTime $dateStart
+     * @param \DateTime $dateEnd
+     * @return bool
+     * @throws \Exception
+     * @see DatesTest::testIsIntervalIsValidNow()
+     */
+    public function isIntervalIsValidNow(\DateTime $dateStart, \DateTime $dateEnd = null): bool {
+        $now = new \DateTime('now');
+        return $dateStart <= $now && (is_null($dateEnd) || $dateEnd >= $now);
+    }
+}

+ 32 - 0
src/Service/Utils/Parser.php

@@ -0,0 +1,32 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\Utils;
+
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\Yaml\Yaml;
+
+/**
+ * Class Parser : méthodes d'aide pour la gestion de parsing de fichier.
+ * @package App\Service\Utils
+ */
+class Parser
+{
+    public function __construct()
+    {
+    }
+
+    /**
+     * Parse le fichier yaml passé en paramètre et renvoie un tableau PHP
+     * @param string $directory
+     * @param string $yamlFile
+     * @return array
+     * @see ParserTest::testYamlParser()
+     */
+    public function yamlParser(string $directory, string $yamlFile): array{
+        $configDirectories = [$directory];
+        $fileLocator = new FileLocator($configDirectories);
+        $yamlConfig = $fileLocator->locate($yamlFile, null, false)[0];
+        return Yaml::parseFile($yamlConfig);
+    }
+}

+ 22 - 5
src/Service/Utils/Reflection.php

@@ -4,6 +4,7 @@ declare(strict_types=1);
 namespace App\Service\Utils;
 
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
 
 /**
  * Class Reflection : Gestion des réflection de class
@@ -19,17 +20,33 @@ class Reflection
     }
 
     /**
-     * Appel une fonction avec ses paramètres d'une classe
+     * Appel une fonction avec ses paramètres depuis le nom d'un service
      * @param string $serviceName
      * @param string $method
      * @param array $parameters
      * @return mixed
      * @throws \ReflectionException
      */
-    public function dynamicInvokeWithArgsServiceMethod(string $serviceName, string $method, array $parameters = []) {
-        $function = $this->container->get($serviceName);
-        $reflection = new \ReflectionClass(get_class($function));
+    public function dynamicInvokeServiceWithArgsAndMethod(string $serviceName, string $method, array $parameters = []) {
+        $class = $this->container->get($serviceName);
+        return $this->dynamicInvokeClassWithArgsAndMethod(get_class($class),  $method,  $parameters = []);
+    }
+
+    /**
+     * Appel une fonction avec ses paramètres  depuis le nom d'une classe
+     * @param string $serviceName
+     * @param string $method
+     * @param array $parameters
+     * @return mixed
+     * @throws \ReflectionException
+     */
+    public function dynamicInvokeClassWithArgsAndMethod(string $className, string $method, array $parameters = []) {
+        $reflection = new \ReflectionClass($className);
         $method = $reflection->getMethod($method);
-        return $method->invokeArgs($function, $parameters);
+        if($method->isStatic()){
+            return $method->invoke(null, $parameters);
+        }else{
+            return $method->invoke($reflection, $parameters);
+        }
     }
 }

+ 38 - 0
src/Service/Utils/Siret.php

@@ -0,0 +1,38 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\Utils;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
+
+/**
+ * Class Siret : méthodes d'aide pour la gestion de numéro de Siret.
+ * @package App\Service\Utils
+ */
+class Siret
+{
+    private HttpClientInterface $clientSiret;
+
+    public function __construct(
+        HttpClientInterface $siret_checking
+    )
+    {
+        $this->clientSiret = $siret_checking;
+    }
+
+    /**
+     * Vérifie si le numéro de Siret passé en paramètre est valide
+     * @param string $siret
+     * @return bool
+     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
+     * @see DatesTest::testIsIntervalIsValidNow()
+     */
+    public function isSiretIsCorrect(string $siret): bool {
+        $response = $this->clientSiret->request('GET', $siret);
+        return $response->getStatusCode() === Response::HTTP_OK;
+    }
+}

+ 15 - 0
symfony.lock

@@ -101,6 +101,9 @@
     "doctrine/sql-formatter": {
         "version": "1.1.1"
     },
+    "egulias/email-validator": {
+        "version": "3.0.0"
+    },
     "fig/link-util": {
         "version": "1.1.1"
     },
@@ -286,6 +289,9 @@
             "src/Kernel.php"
         ]
     },
+    "symfony/http-client": {
+        "version": "v5.2.4"
+    },
     "symfony/http-client-contracts": {
         "version": "v2.3.1"
     },
@@ -295,6 +301,9 @@
     "symfony/http-kernel": {
         "version": "v5.1.7"
     },
+    "symfony/intl": {
+        "version": "v5.2.3"
+    },
     "symfony/maker-bundle": {
         "version": "1.0",
         "recipe": {
@@ -325,6 +334,12 @@
     "symfony/polyfill-intl-grapheme": {
         "version": "v1.18.1"
     },
+    "symfony/polyfill-intl-icu": {
+        "version": "v1.22.1"
+    },
+    "symfony/polyfill-intl-idn": {
+        "version": "v1.22.1"
+    },
     "symfony/polyfill-intl-normalizer": {
         "version": "v1.18.1"
     },

+ 9 - 4
tests/Service/Security/ModuleTest.php

@@ -3,17 +3,22 @@ namespace App\Test\Service\Security;
 
 use App\Entity\Organization\Organization;
 use App\Entity\Organization\Settings;
+use App\Service\Utils\Parser;
 use App\Service\Utils\Reflection;
 use PHPUnit\Framework\TestCase;
 use App\Service\Security\Module;
 
 class ModuleTest extends TestCase
 {
+    const OPENTALENT_CONFIG = __DIR__.'/../../../config/opentalent';
+
     private Reflection $reflectionMock;
+    private Parser $parser;
 
     public function setUp():void
     {
         $this->reflectionMock = $this->getMockBuilder(Reflection::class)->disableOriginalConstructor()->getMock();
+        $this->parser= new Parser();
     }
 
     /**
@@ -33,7 +38,7 @@ class ModuleTest extends TestCase
             ->method('getSettings')
             ->willReturn($settingsMock);
 
-        $module = new Module($this->reflectionMock);
+        $module = new Module($this->reflectionMock, $this->parser, self::OPENTALENT_CONFIG);
         $value = "Sms";
         // assert function to test whether 'value' is a value of array
         $this->assertContains($value, $module->getModuleBySettings($organizationMock)) ;
@@ -46,12 +51,12 @@ class ModuleTest extends TestCase
     {
         $organizationMock = $this->getMockBuilder(Organization::class)->getMock();
         $this->reflectionMock
-            ->method('dynamicInvokeWithArgsServiceMethod')
+            ->method('dynamicInvokeServiceWithArgsAndMethod')
             ->with('opentalent.network.utils', 'isCMF', array($organizationMock))
             ->willReturn(true);
 
 
-        $module = new Module($this->reflectionMock);
+        $module = new Module($this->reflectionMock, $this->parser, self::OPENTALENT_CONFIG);
         $value = "Network";
         // assert function to test whether 'value' is a value of array
         $this->assertContains($value, $module->getModulesByConditions($organizationMock)) ;
@@ -62,7 +67,7 @@ class ModuleTest extends TestCase
      */
     public function testGetModulesByProductConfiguration()
     {
-        $module = new Module($this->reflectionMock);
+        $module = new Module($this->reflectionMock, $this->parser, self::OPENTALENT_CONFIG);
         $value = "MessagesAdvanced";
         // assert function to test whether 'value' is a value of array
         $this->assertContains($value, $module->getModulesByProductConfiguration('artist-premium')) ;

+ 27 - 0
tests/Service/Utils/DatesTest.php

@@ -0,0 +1,27 @@
+<?php
+namespace App\Tests\Service\Utils;
+
+use App\Service\Utils\Dates;
+use PHPUnit\Framework\TestCase;
+
+class DatesTest extends TestCase
+{
+    /**
+     * @see Dates::isIntervalIsValidNow()
+     */
+    public function testIsIntervalIsValidNow():void
+    {
+        $dates = new Dates();
+        $this->assertTrue($dates->isIntervalIsValidNow(new \DateTime('2020-01-02'), new \DateTime('2025-01-02')));
+        $this->assertTrue($dates->isIntervalIsValidNow(new \DateTime('2020-01-02'), null));
+    }
+
+    /**
+     * @see Dates::isIntervalIsValidNow()
+     */
+    public function testIsIntervalIsNotValidNow():void
+    {
+        $dates = new Dates();
+        $this->assertFalse($dates->isIntervalIsValidNow(new \DateTime('2019-01-02'), new \DateTime('2020-01-02')));
+    }
+}

+ 22 - 0
tests/Service/Utils/ParserTest.php

@@ -0,0 +1,22 @@
+<?php
+namespace App\Tests\Service\Utils;
+
+use App\Service\Utils\Parser;
+use PHPUnit\Framework\TestCase;
+
+class ParserTest extends TestCase
+{
+    const FIXTURES = __DIR__.'/fixtures';
+
+    /**
+     * @see Parser::yamlParser()
+     */
+    public function testYamlParser():void
+    {
+        $parser = new Parser();
+        $parsingArray = $parser->yamlParser(self::FIXTURES, 'fixture.yaml');
+        $this->assertIsArray($parsingArray);
+        $this->assertIsArray($parsingArray['opentalent']);
+        $this->assertEquals('ROLE_COTISATION', $parsingArray['opentalent']['modulesbyconditions']['CotisationCall']['roles'][0]);
+    }
+}

+ 32 - 0
tests/Service/Utils/SiretTest.php

@@ -0,0 +1,32 @@
+<?php
+namespace App\Tests\Service\Utils;
+
+use App\Service\Utils\Siret;
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\HttpClient\MockHttpClient;
+use Symfony\Component\HttpClient\Response\MockResponse;
+
+class SiretTest extends TestCase
+{
+    /**
+     * @see Siret::isSiretIsCorrect()
+     */
+    public function testIsSiretIsCorrect():void
+    {
+        $responses = [new MockResponse('...', ['http_code' => 200])];
+        $client = new MockHttpClient($responses, 'https://entreprise.data.gouv.fr/api/sirene/v3/etablissements/');
+        $siret = new Siret($client);
+        $this->assertTrue($siret->isSiretIsCorrect('50465312200052'));
+    }
+
+    /**
+     * @see Siret::isSiretIsCorrect()
+     */
+    public function testIsNotSiretIsCorrect():void
+    {
+        $responses = [new MockResponse('...', ['http_code' => 404])];
+        $client = new MockHttpClient($responses, 'https://entreprise.data.gouv.fr/api/sirene/v3/etablissements/');
+        $siret = new Siret($client);
+        $this->assertFalse($siret->isSiretIsCorrect('50465312200052'));
+    }
+}

+ 9 - 0
tests/Service/Utils/fixtures/fixture.yaml

@@ -0,0 +1,9 @@
+opentalent:
+    modulesbyconditions:
+        CotisationCall:
+            roles:
+                - ROLE_COTISATION
+            conditions:
+                service:
+                    name: opentalent.cotisation.utils
+                    function: isLastParentAndCMF