From c4329172e77e205f263afea7438bf4433ee40081 Mon Sep 17 00:00:00 2001
From: Antony Le Courtes <antony.lecourtes@unicaen.fr>
Date: Fri, 24 Mar 2023 15:57:19 +0100
Subject: [PATCH] Ajout et validation d'offre d'emploi

---
 composer.json                                 |  2 +-
 composer.lock                                 | 18 ++++----
 data/ddl/table/VALIDATION.php                 |  2 +-
 data/nomenclatures.php                        |  5 ++
 data/privileges.php                           |  6 ++-
 front/Mission/ListeOffreEmploi.vue            |  7 ++-
 front/Mission/OffreEmploi.vue                 | 46 +++++++++++++++++--
 .../src/Entity/Db/TypeValidation.php          |  1 +
 .../src/Provider/Privilege/Privileges.php     | 15 +++---
 .../src/Service/TypeValidationService.php     |  7 +++
 module/Mission/config/module.config.php       | 33 ++++++++++---
 .../src/Controller/OffreEmploiController.php  | 43 ++++++++++++++++-
 module/Mission/src/Entity/Db/OffreEmploi.php  |  2 +-
 13 files changed, 152 insertions(+), 35 deletions(-)

diff --git a/composer.json b/composer.json
index 422ec146dc..2d9406de5e 100644
--- a/composer.json
+++ b/composer.json
@@ -14,7 +14,7 @@
         "unicaen/privilege"                           : "6.0.1",
         "unicaen/utilisateur"                         : "6.0.4",
         "laminas/laminas-file"                        : "^2.8",
-        "unicaen/code"                                : "6.0.6",
+        "unicaen/code"                                : "6.0.8",
         "unicaen/import"                              : "6.0.1",
         "unicaen/tbl"                                 : "6.0.1",
         "unicaen/open-document"                       : "6.0.1",
diff --git a/composer.lock b/composer.lock
index 5f1cc5f40b..3d2e0bfc25 100644
--- a/composer.lock
+++ b/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": "72e67e488af6f39c90ea43e0a848fbf5",
+    "content-hash": "52b3f7e4ada3aa5a5562b9dd2f6b22ce",
     "packages": [
         {
             "name": "beberlei/assert",
@@ -6878,11 +6878,11 @@
         },
         {
             "name": "unicaen/app",
-            "version": "6.0.1",
+            "version": "6.0.5",
             "source": {
                 "type": "git",
                 "url": "https://git.unicaen.fr/lib/unicaen/app.git",
-                "reference": "19335523fd529823d959a3c6cc9eccf3b0dc63b8"
+                "reference": "a85de98e91ea41bf97eb0fdb9359f4942e9fe96d"
             },
             "require": {
                 "beberlei/assert": "^3.3",
@@ -6917,7 +6917,7 @@
                 "mpdf/mpdf": "^8.0",
                 "ocramius/proxy-manager": "^2.0",
                 "php": "^8.0",
-                "unicaen/console": "dev-main"
+                "unicaen/console": "^6.0"
             },
             "require-dev": {
                 "laminas/laminas-test": "^3.2",
@@ -6938,7 +6938,7 @@
                 ]
             },
             "description": "Module de base des applications unicaen",
-            "time": "2023-02-08T15:57:37+00:00"
+            "time": "2023-03-21T14:44:06+00:00"
         },
         {
             "name": "unicaen/authentification",
@@ -7036,11 +7036,11 @@
         },
         {
             "name": "unicaen/code",
-            "version": "6.0.6",
+            "version": "6.0.8",
             "source": {
                 "type": "git",
                 "url": "https://git.unicaen.fr/lib/unicaen/code.git",
-                "reference": "14803000f2db012e8fafd6d162bd265c8e98e0da"
+                "reference": "7af2b00f72a4300d4cb94e9bdd951066a334ef6c"
             },
             "require": {
                 "easybook/geshi": ">=1.0",
@@ -7057,11 +7057,11 @@
                 ]
             },
             "description": "Boite à outils pour la programmation avec la bibliothèque Unicaen",
-            "time": "2023-03-21T10:49:29+00:00"
+            "time": "2023-03-22T16:21:31+00:00"
         },
         {
             "name": "unicaen/console",
-            "version": "dev-main",
+            "version": "6.0.0",
             "source": {
                 "type": "git",
                 "url": "https://git.unicaen.fr/lib/unicaen/console.git",
diff --git a/data/ddl/table/VALIDATION.php b/data/ddl/table/VALIDATION.php
index cd95398779..a7890c1864 100644
--- a/data/ddl/table/VALIDATION.php
+++ b/data/ddl/table/VALIDATION.php
@@ -100,7 +100,7 @@ return [
             'length'      => 0,
             'scale'       => '0',
             'precision'   => NULL,
-            'nullable'    => FALSE,
+            'nullable'    => TRUE,
             'default'     => NULL,
             'position'    => 3,
             'commentaire' => NULL,
diff --git a/data/nomenclatures.php b/data/nomenclatures.php
index a61b5fbad7..9e83885b4a 100644
--- a/data/nomenclatures.php
+++ b/data/nomenclatures.php
@@ -882,6 +882,11 @@ return [
             "CODE"    => "MISSION_REALISE",
             "LIBELLE" => "Validation d'heures de mission réalisées",
         ],
+        [
+            'ID'      => 10,
+            "CODE"    => "OFFRE_EMPLOI",
+            "LIBELLE" => "Validation d'une offre d'emploi par la DRH",
+        ],
     ],
 
     'TYPE_VOLUME_HORAIRE' => [
diff --git a/data/privileges.php b/data/privileges.php
index 5d203368cb..458502f65b 100644
--- a/data/privileges.php
+++ b/data/privileges.php
@@ -163,7 +163,11 @@ return [
             'edition-type'               => 'Edition des types de mission',
             'suppression-type'           => 'Suppression des types de mission',
             'offre-emploi-visualisation' => 'Visualisation des offres d\'emploi',
-            'offre-emploi-suppresion'    => 'Suppresion des offres d\'emploi',
+            'offre-emploi-suppression'   => 'Suppresion des offres d\'emploi',
+            'offre-emploi-ajouter'       => 'Ajouter des offres d\'emploi',
+            'offre-emploi-modifier'      => 'Modifier des offres d\'emploi',
+            'offre-emploi-valider'       => 'Valider des offres d\'emploi',
+
 
         ],
     ],
diff --git a/front/Mission/ListeOffreEmploi.vue b/front/Mission/ListeOffreEmploi.vue
index e60ebfb1ee..2543fd2caf 100644
--- a/front/Mission/ListeOffreEmploi.vue
+++ b/front/Mission/ListeOffreEmploi.vue
@@ -5,7 +5,7 @@
             <offreEmploi @supprimer="supprimer" @refresh="refresh" :key="offre.id" :offre="offre"></offreEmploi>
         </div>
     </div>
-    <!-- <a v-if="canEditTaux" class="btn btn-primary" :href="ajoutUrl" @click.prevent="ajout">Ajout d'un nouveau taux</a>-->
+    <a class="btn btn-primary" :href="ajoutUrl" @click.prevent="ajout">Ajouter une nouvelle offre</a>
 </template>
 
 <script>
@@ -16,15 +16,20 @@ export default {
     components: {
         offreEmploi
     },
+    props: {
+        canAddOffreEmploi: {type: Boolean, required: true},
+    },
     data()
     {
         return {
             offres: [],
+            ajoutUrl: Util.url('offre-emploi/saisir'),
         };
     },
     mounted()
     {
         this.reload();
+        console.log(this.offres);
     },
     methods: {
         ajout(event)
diff --git a/front/Mission/OffreEmploi.vue b/front/Mission/OffreEmploi.vue
index fe53b1e231..e4205cc9dc 100644
--- a/front/Mission/OffreEmploi.vue
+++ b/front/Mission/OffreEmploi.vue
@@ -3,18 +3,40 @@
         <div class="card h-100">
             <div class="card-header">
                 <h4> {{ offre.titre }}</h4>
-                <span class="badge bg-success">En cours</span>&nbsp;
-                <span class="badge bg-info">{{ offre.nombreHeures }} heure(s)</span>&nbsp;
-                <span class="badge bg-info">{{ offre.nombrePostes }} poste(s)</span>&nbsp;
+                <span v-if="offre.validation" class="badge rounded-pill bg-success">Valider le <u-date
+                    :value="offre.validation.histoCreation"/> par {{ offre.validation.histoCreateur.displayName }}&nbsp;</span>
+                <span v-if="!offre.validation" class="badge rounded-pill bg-warning">En attente de validation par la DRH</span>&nbsp;
+                <span class="badge rounded-pill bg-info">{{ offre.nombreHeures }} heure(s)</span>&nbsp;
+                <span class="badge rounded-pill bg-info">{{ offre.nombrePostes }} poste(s)</span>
+
             </div>
 
             <div class="card-body">
+                <p class="bg-light" style="padding:5px;">
+                    <b>Crée le : </b>
+                    <u-date :value="offre.histoCreation"/>
+                    par {{ offre.histoCreateur.displayName }}<br/>
+                    <b>Période à pourvoir : </b>du
+                    <u-date :value="offre.dateDebut"/>
+                    au
+                    <u-date :value="offre.dateFin"/>
+                    <br/>
+                    <b>Demandé par la composante :</b> {{ offre.structure.libelle }}
 
+                </p>
                 {{ offre.description }}
 
             </div>
             <div class="card-footer">
                 <div class="d-grid gap-2 d-md-flex justify-content-md-end">
+                    <a v-if="offre.validation"
+                       :href="devaliderUrl"
+                       class="btn btn-danger"
+                       @click.prevent="devalider">Devalider</a>
+                    <a v-if="!offre.validation"
+                       :href="validerUrl"
+                       class="btn btn-success"
+                       @click.prevent="valider">Valider</a>
                     <a :href="saisirUrl"
                        class="btn btn-primary"
                        @click.prevent="saisir">Modifier</a>
@@ -39,12 +61,14 @@ export default {
     },
     data()
     {
+        console.log(this.offre.histoCreation);
         return {
 
             saisirUrl: Util.url('offre-emploi/saisir/:offre', {offre: this.offre.id}),
             supprimerUrl: Util.url("offre-emploi/supprimer/:offre", {offre: this.offre.id}),
-            validerUrl: Util.url('mission/valider/:mission', {offre: this.offre.id}),
-            devaliderUrl: Util.url('mission/devalider/:mission', {offre: this.offre.id}),
+            validerUrl: Util.url('offre-emploi/valider/:offre', {offre: this.offre.id}),
+            devaliderUrl: Util.url('offre-emploi/devalider/:offre', {offre: this.offre.id}),
+
         };
     },
     methods: {
@@ -70,6 +94,18 @@ export default {
                 this.$emit('supprimer', this.offre);
             });
         },
+        valider(event)
+        {
+            popConfirm(event.currentTarget, (response) => {
+                this.$emit('refresh', response.data);
+            });
+        },
+        devalider(event)
+        {
+            popConfirm(event.currentTarget, (response) => {
+                this.$emit('refresh', response.data);
+            });
+        },
 
     },
 
diff --git a/module/Application/src/Entity/Db/TypeValidation.php b/module/Application/src/Entity/Db/TypeValidation.php
index 68f8483103..c3192e1ff4 100755
--- a/module/Application/src/Entity/Db/TypeValidation.php
+++ b/module/Application/src/Entity/Db/TypeValidation.php
@@ -17,6 +17,7 @@ class TypeValidation
     const CODE_CLOTURE_REALISE = 'CLOTURE_REALISE';
     const CODE_MISSION         = 'MISSION';
     const CODE_MISSION_REALISE = 'MISSION_REALISE';
+    const CODE_OFFRE_EMPLOI    = 'OFFRE_EMPLOI';
 
     /**
      * @var string
diff --git a/module/Application/src/Provider/Privilege/Privileges.php b/module/Application/src/Provider/Privilege/Privileges.php
index 5c3ef4d538..7bc1dc4dfa 100755
--- a/module/Application/src/Provider/Privilege/Privileges.php
+++ b/module/Application/src/Provider/Privilege/Privileges.php
@@ -2,8 +2,6 @@
 
 namespace Application\Provider\Privilege;
 
-use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
-
 /**
  * Description of Privileges
  *
@@ -13,10 +11,6 @@ use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
  */
 class Privileges extends \UnicaenPrivilege\Provider\Privilege\Privileges {
 
-    const DROIT_ROLE_VISUALISATION          = 'droit-role-visualisation';
-    const DROIT_ROLE_EDITION                = 'droit-role-edition';
-    const DROIT_PRIVILEGE_VISUALISATION     = 'droit-privilege-visualisation';
-    const DROIT_PRIVILEGE_EDITION           = 'droit-privilege-edition';
     const AGREMENT_CONSEIL_ACADEMIQUE_EDITION                  = 'agrement-conseil-academique-edition';
     const AGREMENT_CONSEIL_ACADEMIQUE_SUPPRESSION              = 'agrement-conseil-academique-suppression';
     const AGREMENT_CONSEIL_ACADEMIQUE_VISUALISATION            = 'agrement-conseil-academique-visualisation';
@@ -105,6 +99,10 @@ class Privileges extends \UnicaenPrivilege\Provider\Privilege\Privileges {
     const DOSSIER_VISUALISATION                                = 'dossier-visualisation';
     const DROIT_AFFECTATION_EDITION                            = 'droit-affectation-edition';
     const DROIT_AFFECTATION_VISUALISATION                      = 'droit-affectation-visualisation';
+    const DROIT_PRIVILEGE_EDITION                              = 'droit-privilege-edition';
+    const DROIT_PRIVILEGE_VISUALISATION                        = 'droit-privilege-visualisation';
+    const DROIT_ROLE_EDITION                                   = 'droit-role-edition';
+    const DROIT_ROLE_VISUALISATION                             = 'droit-role-visualisation';
     const ENSEIGNEMENT_DEVALIDATION                            = 'enseignement-devalidation';
     const ENSEIGNEMENT_EDITION_MASSE                           = 'enseignement-edition-masse';
     const ENSEIGNEMENT_EXPORT_CSV                              = 'enseignement-export-csv';
@@ -172,8 +170,11 @@ class Privileges extends \UnicaenPrivilege\Provider\Privilege\Privileges {
     const MISSION_EDITION                                      = 'mission-edition';
     const MISSION_EDITION_REALISE                              = 'mission-edition-realise';
     const MISSION_EDITION_TYPE                                 = 'mission-edition-type';
-    const MISSION_OFFRE_EMPLOI_VISUALISATION                   = 'mission-offre-emploi-visualisation';
+    const MISSION_OFFRE_EMPLOI_AJOUTER                         = 'mission-offre-emploi-ajouter';
+    const MISSION_OFFRE_EMPLOI_MODIFIER                        = 'mission-offre-emploi-modifier';
     const MISSION_OFFRE_EMPLOI_SUPPRESSION                     = 'mission-offre-emploi-suppression';
+    const MISSION_OFFRE_EMPLOI_VALIDER                         = 'mission-offre-emploi-valider';
+    const MISSION_OFFRE_EMPLOI_VISUALISATION                   = 'mission-offre-emploi-visualisation';
     const MISSION_SUPPRESSION_TYPE                             = 'mission-suppression-type';
     const MISSION_VALIDATION                                   = 'mission-validation';
     const MISSION_VALIDATION_REALISE                           = 'mission-validation-realise';
diff --git a/module/Application/src/Service/TypeValidationService.php b/module/Application/src/Service/TypeValidationService.php
index decfdcaaa4..925d8ab4ef 100755
--- a/module/Application/src/Service/TypeValidationService.php
+++ b/module/Application/src/Service/TypeValidationService.php
@@ -60,6 +60,13 @@ class TypeValidationService extends AbstractEntityService
 
 
 
+    public function getOffreEmploi(): TypeValidation
+    {
+        return $this->getByCode(TypeValidation::CODE_OFFRE_EMPLOI);
+    }
+
+
+
     public function getMissionRealise(): TypeValidation
     {
         return $this->getByCode(TypeValidation::CODE_MISSION_REALISE);
diff --git a/module/Mission/config/module.config.php b/module/Mission/config/module.config.php
index 323bead8b3..d1f36b0950 100644
--- a/module/Mission/config/module.config.php
+++ b/module/Mission/config/module.config.php
@@ -18,23 +18,23 @@ use Mission\Service\OffreEmploiServiceFactory;
 
 return [
     'routes' => [
-        'intervenant'   => [
+        'intervenant'  => [
             'child_routes' => [
-                'missions'       => [
+                'missions'              => [
                     'route'      => '/:intervenant/missions',
                     'controller' => MissionController::class,
                     'action'     => 'index',
                     'privileges' => Privileges::MISSION_VISUALISATION,
                     //'assertion'  => Assertion\MissionAssertion::class,
                 ],
-                'missions-suivi' => [
+                'missions-suivi'        => [
                     'route'      => '/:intervenant/missions-suivi',
                     'controller' => MissionController::class,
                     'action'     => 'suivi',
                     'privileges' => Privileges::MISSION_EDITION_REALISE,
                     //'assertion'  => Assertion\MissionAssertion::class,
                 ],
-                'missions-suivi-data' => [
+                'missions-suivi-data'   => [
                     'route'      => '/:intervenant/missions-suivi-data',
                     'controller' => MissionController::class,
                     'action'     => 'suivi-data',
@@ -50,7 +50,7 @@ return [
                 ],
             ],
         ],
-        'mission'       => [
+        'mission'      => [
             'route'         => '/mission',
             'may_terminate' => false,
             'child_routes'  => [
@@ -156,6 +156,18 @@ return [
                     'action'     => 'supprimer',
                     'privileges' => Privileges::MISSION_OFFRE_EMPLOI_VISUALISATION,
                 ],
+                'valider'   => [
+                    'route'      => '/valider/:offreEmploi',
+                    'controller' => OffreEmploiController::class,
+                    'action'     => 'valider',
+                    'privileges' => Privileges::MISSION_OFFRE_EMPLOI_VALIDER,
+                ],
+                'devalider' => [
+                    'route'      => '/devalider/:offreEmploi',
+                    'controller' => OffreEmploiController::class,
+                    'action'     => 'devalider',
+                    'privileges' => Privileges::MISSION_OFFRE_EMPLOI_VALIDER,
+                ],
             ],
 
         ],
@@ -278,6 +290,13 @@ return [
                 Privileges::MISSION_OFFRE_EMPLOI_SUPPRESSION,
             ],
         ],
+        [
+            'controller' => OffreEmploiController::class,
+            'action'     => ['valider', 'devalider'],
+            'privileges' => [
+                Privileges::MISSION_OFFRE_EMPLOI_VALIDER,
+            ],
+        ],
     ],
 
     'controllers' => [
@@ -294,9 +313,9 @@ return [
     ],
 
     'forms' => [
-        Form\MissionForm::class => Form\MissionFormFactory::class,
+        Form\MissionForm::class      => Form\MissionFormFactory::class,
         Form\MissionSuiviForm::class => Form\MissionSuiviFormFactory::class,
-        Form\OffreEmploiForm::class => Form\OffreEmploiFormFactory::class,
+        Form\OffreEmploiForm::class  => Form\OffreEmploiFormFactory::class,
     ],
 
     'view_helpers' => [
diff --git a/module/Mission/src/Controller/OffreEmploiController.php b/module/Mission/src/Controller/OffreEmploiController.php
index a86332f6db..6ecafa823b 100755
--- a/module/Mission/src/Controller/OffreEmploiController.php
+++ b/module/Mission/src/Controller/OffreEmploiController.php
@@ -31,6 +31,7 @@ class OffreEmploiController extends AbstractController
 {
     use OffreEmploiServiceAwareTrait;
     use OffreEmploiFormAwareTrait;
+    use ValidationServiceAwareTrait;
 
 
     public function indexAction()
@@ -94,12 +95,51 @@ class OffreEmploiController extends AbstractController
 
 
 
+    public function validerAction()
+    {
+        /** @var OffreEmploi $offre */
+        $offre = $this->getEvent()->getParam('offreEmploi');
+
+        if ($offre->isValide()) {
+            $this->flashMessenger()->addInfoMessage('L\'offre est déjà validé');
+        } else {
+            $this->getServiceValidation()->validerOffreEmploi($offre);
+            $this->getServiceOffreEmploi()->save($offre);
+            $this->flashMessenger()->addSuccessMessage("Offre d'emploi validée");
+        }
+
+        return $this->getAction($offre);
+    }
+
+
+
+    public function devaliderAction()
+    {
+        /** @var OffreEmploi $offre */
+        $offre      = $this->getEvent()->getParam('offreEmploi');
+        $validation = $offre->getValidation();
+        if ($validation) {
+            $offre->setAutoValidation(false);
+            $offre->setValidation(null);
+            $this->getServiceOffreEmploi()->save($offre);
+            $this->getServiceValidation()->delete($validation);
+            $this->flashMessenger()->addSuccessMessage("Offre d'emploi dévalidée");
+        } else {
+            $this->flashMessenger()->addInfoMessage("L'offre d'emploi n'était pas validée");
+        }
+
+        return $this->getAction($offre);
+    }
+
+
+
     /**
      * Retourne les données pour une mission
      *
      * @return JsonModel
      */
-    public function getAction(?OffreEmploi $offreEmploi = null)
+    public
+    function getAction(?OffreEmploi $offreEmploi = null)
     {
         if (!$offreEmploi) {
             /** @var OffreEmploi $offreEmploi */
@@ -112,5 +152,4 @@ class OffreEmploiController extends AbstractController
 
         return $this->axios()->send($this->axios()::extract($query)[0]);
     }
-
 }
\ No newline at end of file
diff --git a/module/Mission/src/Entity/Db/OffreEmploi.php b/module/Mission/src/Entity/Db/OffreEmploi.php
index 695d263c8d..3aa46a7325 100755
--- a/module/Mission/src/Entity/Db/OffreEmploi.php
+++ b/module/Mission/src/Entity/Db/OffreEmploi.php
@@ -265,7 +265,7 @@ class OffreEmploi implements HistoriqueAwareInterface, ResourceInterface, AxiosE
      *
      * @return OffreEmploi
      */
-    public function setValidation(Validation $validation): OffreEmploi
+    public function setValidation(?Validation $validation): OffreEmploi
     {
         $this->validation = $validation;
 
-- 
GitLab