diff --git a/CHANGELOG.md b/CHANGELOG.md
index 87d1979c881cec9fb874d95d0627f6a05cffec7d..12db7bb8374b89f21f1ef21b8012fd15834ceb31 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,19 @@
 Journal des modifications
 =========================
 
+5.2.6
+-----
+- Déclaration des membres du comite de suivi individuel
+- Amélioration du message de blocage des modifications des structures
+- Le texte de l'engagement d'impartialité est maintenant un 'contenu' éditable dans le module unicaen/renderer
+- Ajout de l'année de thèse du doctorant (au moment de la session) dans l'export des sessions de formation et sur les émargements
+- Heurodatage des changements d'etat des sessions de formation
+- [FIX] Plus d'envoi de mail lors du classement des inscriptions si les inscriptions ne sont pas closes
+- [FIX] Ajout de l'affichage de la liste des présences à une session si celle-ci est imminente.
+- [FIX] Correction du calcul d'erreur de l'année de thèse du doctorant dans les sessions de formation.
+- [FIX] Correction du problème de téléchargement des avis en mode non connecté (par exemple pour les membres du jury)
+- [FIX] removeProp() ne fonctionnait plus dans le widget JS d'autorisation de mise en ligne : remplacé par prop().  
+
 5.2.5
 -----
 - Filtrage des propositions de soutenances par Etab, ED, UR, état.
diff --git a/config/application.config.php b/config/application.config.php
index f71c30de764f438186bfb2da7c8ec839d3597bef..73f2c74b657ffd6fc130abc74ba779133edd600c 100755
--- a/config/application.config.php
+++ b/config/application.config.php
@@ -47,6 +47,7 @@ return [
         'Retraitement',
         'Soutenance',
         'Formation',
+        'ComiteSuiviIndividuel',
         'RapportActivite',
         'Notification',
         'Information',
diff --git a/doc/release-notes/v5.2.6.md b/doc/release-notes/v5.2.6.md
new file mode 100644
index 0000000000000000000000000000000000000000..6f8c871c2228cf1aa9f6ed29f61b692f928e3e02
--- /dev/null
+++ b/doc/release-notes/v5.2.6.md
@@ -0,0 +1,58 @@
+# Version 5.2.6
+
+## 1. Sur le serveur d'application
+
+- Placez-vous dans le répertoire de l'application puis lancez la commande suivante
+  pour installer la nouvelle version :
+
+```bash
+git fetch --tags && git checkout --force 5.2.6 && bash ./install.sh
+```
+
+- Selon le moteur PHP que vous avez installé, rechargez le service, exemple :
+    - php7.4-fpm         : `service php7.4-fpm reload`
+    - apache2-mod-php7.4 : `service apache2 reload`
+
+
+## 2. Dans la base de données
+
+```sql
+-- table de membre du csi
+-- /!\ referebce au même qualité que celle décrite dans le module soutenance
+
+create table csi_membre
+(
+id                    serial                  constraint csi_membre_pkey primary key,
+these_id              bigint not null         constraint membre_these_fk references these on delete cascade,
+genre                 varchar(1) not null,
+qualite               bigint not null         constraint membre_qualite_fk references soutenance_qualite on delete set null,
+etablissement         varchar(128) not null,
+role_id               varchar(64) not null,
+exterieur             varchar(3),
+email                 varchar(256),
+acteur_id             bigint                   constraint soutemembre_acteur_fk references acteur on delete cascade,
+visio                 boolean default false not null,
+nom                   varchar(256),
+prenom                varchar(256),
+histo_creation        timestamp not null,
+histo_createur_id     bigint not null          constraint membre_createur_fk references utilisateur,
+histo_modification    timestamp not null,
+histo_modificateur_id bigint not null          constraint membre_modificateur_fk references utilisateur,
+histo_destruction     timestamp,
+histo_destructeur_id  bigint                   constraint membre_destructeur_fk references utilisateur,
+);
+
+-- insertions liées à l'engagement d'impartialité comme un template
+INSERT INTO unicaen_renderer_macro (code, description, variable_name, methode_name) VALUES ('Membre#Denomination', '<p>Retourne la dénomination d''une membre</p>', 'membre', 'getDenomination');
+INSERT INTO unicaen_renderer_template (code, description, document_type, document_sujet, document_corps) VALUES ('SOUTENANCE_ENGAGEMENT_IMPARTIALITE', '<p>Texte associé à l''engagement d''impartialité</p>', 'texte', 'Engagement d''impartialité', '<p>En signant cet engagement d''impartialité, je, sous-signé <strong>VAR[Membre#Denomination]</strong>, atteste ne pas avoir de liens d''intérêt, qu''ils soient de nature professionnelle, familiale, personnelle ou patrimoniale avec le doctorant ou son directeur de thèse, ne pas avoir pris part aux travaux de la thèse et ne pas avoir de publication cosignée avec le doctorant dans les cinq dernières années et ne pas avoir participé au comité de suivi de la thèse de VAR[Doctorant#Denomination].</p><p>By signing, I certify that I have no personal or family connection with the doctoral student or his/her PhD supervisor and that I have not taken part in the work of the thesis and not co-authored  publications with the doctoral student for the last five years.<br /><br /></p>');
+
+--table pour l'heurodatage des changement d'etats des sessions
+create table formation_session_etat_heurodatage
+(
+  id serial constraint formation_session_etat_heurodatage_pk primary key,
+  session_id integer not null constraint formation_session_etat_heurodatage_session references formation_session on delete cascade,
+  etat_id varchar(1) not null constraint formation_session_etat_heurodatage_etat references formation_etat on delete cascade,
+  heurodatage timestamp not null,
+  utilisateur_id int not null constraint formation_session_etat_heurodatage_user references utilisateur on delete cascade
+);
+```
diff --git a/module/Application/src/Application/Controller/Factory/Rapport/RapportCsiControllerFactory.php b/module/Application/src/Application/Controller/Factory/Rapport/RapportCsiControllerFactory.php
index cdd87156b908be41dc7d657d0232251f51d9a9b5..563f3e1404471e644a4f5c53d98b8902f2ab5315 100644
--- a/module/Application/src/Application/Controller/Factory/Rapport/RapportCsiControllerFactory.php
+++ b/module/Application/src/Application/Controller/Factory/Rapport/RapportCsiControllerFactory.php
@@ -7,6 +7,7 @@ use Application\Entity\Db\TypeRapport;
 use Application\Entity\Db\TypeValidation;
 use Application\Form\Rapport\RapportForm;
 use Application\Form\RapportCsiForm;
+use ComiteSuiviIndividuel\Service\Membre\MembreService;
 use Fichier\Service\Fichier\FichierService;
 use Individu\Service\IndividuService;
 use Application\Service\Notification\NotifierService;
@@ -36,6 +37,8 @@ class RapportCsiControllerFactory
          * @var IndividuService       $individuService
          * @var ValidationService     $validationService
          * @var RapportForm           $rapportForm
+         *
+         * @var MembreService $membreService
          */
         $theseService = $container->get('TheseService');
         $fichierService = $container->get(FichierService::class);
@@ -49,6 +52,8 @@ class RapportCsiControllerFactory
         $typeRapport = $rapportService->findTypeRapportByCode(TypeRapport::RAPPORT_CSI);
         $typeValidation = $validationService->findTypeValidationByCode(TypeValidation::CODE_RAPPORT_CSI);
 
+        $membreService = $container->get(MembreService::class);
+
         $controller = new RapportCsiController();
         $controller->setTheseService($theseService);
         $controller->setRapportService($rapportService);
@@ -61,6 +66,7 @@ class RapportCsiControllerFactory
         $controller->setAnneesUnivs($theseAnneeUnivService);
         $controller->setTypeRapport($typeRapport);
         $controller->setTypeValidation($typeValidation);
+        $controller->setMembreService($membreService);
 
         $theseService->attach($controller->getEventManager());
 
diff --git a/module/Application/src/Application/Controller/Rapport/RapportController.php b/module/Application/src/Application/Controller/Rapport/RapportController.php
index 56eca0930c8303c4ea9ce092fc97fd8def58df0b..d87761ef2621ceb69f9875f5371f3cd4b7fa4118 100644
--- a/module/Application/src/Application/Controller/Rapport/RapportController.php
+++ b/module/Application/src/Application/Controller/Rapport/RapportController.php
@@ -12,6 +12,7 @@ use Application\EventRouterReplacerAwareTrait;
 use Application\Filter\IdifyFilter;
 use Application\Filter\IdifyFilterAwareTrait;
 use Application\Form\Rapport\RapportForm;
+use ComiteSuiviIndividuel\Service\Membre\MembreServiceAwareTrait;
 use Fichier\Service\Fichier\FichierServiceAwareTrait;
 use Fichier\Service\Fichier\FichierStorageServiceAwareTrait;
 use Individu\Service\IndividuServiceAwareTrait;
diff --git a/module/Application/src/Application/Controller/Rapport/RapportCsiController.php b/module/Application/src/Application/Controller/Rapport/RapportCsiController.php
index e3d2c744135dbd75403b0df6a61a69c1a4c051d7..117757b79e9b6dab868dd217fa496d561dc55fcc 100644
--- a/module/Application/src/Application/Controller/Rapport/RapportCsiController.php
+++ b/module/Application/src/Application/Controller/Rapport/RapportCsiController.php
@@ -3,9 +3,15 @@
 namespace Application\Controller\Rapport;
 
 use Application\Provider\Privilege\RapportPrivileges;
+use ComiteSuiviIndividuel\Service\Membre\MembreServiceAwareTrait;
+use Laminas\Http\Response;
+use Laminas\View\Model\ViewModel;
 
 class RapportCsiController extends RapportController
 {
+    use MembreServiceAwareTrait;
+
+
     protected $routeName = 'rapport-csi';
 
     protected $privilege_TELEVERSER_TOUT = RapportPrivileges::RAPPORT_CSI_TELEVERSER_TOUT;
@@ -18,4 +24,48 @@ class RapportCsiController extends RapportController
 //    protected $privilege_VALIDER_SIEN = RapportPrivileges::RAPPORT_CSI_VALIDER_SIEN;
 //    protected $privilege_DEVALIDER_TOUT = RapportPrivileges::RAPPORT_CSI_DEVALIDER_TOUT;
 //    protected $privilege_DEVALIDER_SIEN = RapportPrivileges::RAPPORT_CSI_DEVALIDER_SIEN;
+
+    /**
+     * @return Response|ViewModel
+     */
+    public function consulterAction()
+    {
+        $this->these = $this->requestedThese();
+        $this->fetchRapportsTeleverses();
+
+        $membres = $this->getMembreService()->getMembresByThese($this->these);
+
+        // gestion d'une éventuelle requête POST d'ajout d'un rapport
+        $result = $this->ajouterAction();
+        if ($result instanceof Response) {
+            return $result;
+        }
+
+        return new ViewModel([
+            'rapports' => $this->rapportsTeleverses,
+            'these' => $this->these,
+            'form' => $this->form,
+            'isTeleversementPossible' => $this->isTeleversementPossible(),
+            'membres' => $membres,
+
+            'typeValidation' => $this->typeValidation,
+            'routeName' => $this->routeName,
+            'privilege_LISTER_TOUT' => $this->privilege_LISTER_TOUT,
+            'privilege_LISTER_SIEN' => $this->privilege_LISTER_SIEN,
+            'privilege_TELEVERSER_TOUT' => $this->privilege_TELEVERSER_TOUT,
+            'privilege_TELEVERSER_SIEN' => $this->privilege_TELEVERSER_SIEN,
+            'privilege_SUPPRIMER_TOUT' => $this->privilege_SUPPRIMER_TOUT,
+            'privilege_SUPPRIMER_SIEN' => $this->privilege_SUPPRIMER_SIEN,
+            'privilege_RECHERCHER_TOUT' => $this->privilege_RECHERCHER_TOUT,
+            'privilege_RECHERCHER_SIEN' => $this->privilege_RECHERCHER_SIEN,
+            'privilege_TELECHARGER_TOUT' => $this->privilege_TELECHARGER_TOUT,
+            'privilege_TELECHARGER_SIEN' => $this->privilege_TELECHARGER_SIEN,
+            'privilege_TELECHARGER_ZIP' => $this->privilege_TELECHARGER_ZIP,
+            'privilege_VALIDER_TOUT' => $this->privilege_VALIDER_TOUT,
+            'privilege_VALIDER_SIEN' => $this->privilege_VALIDER_SIEN,
+            'privilege_DEVALIDER_TOUT' => $this->privilege_DEVALIDER_TOUT,
+            'privilege_DEVALIDER_SIEN' => $this->privilege_DEVALIDER_SIEN,
+        ]);
+    }
+
 }
diff --git a/module/Application/view/application/rapport/rapport-csi/consulter.phtml b/module/Application/view/application/rapport/rapport-csi/consulter.phtml
index f392529bd8284bc419417f945d49247e8526d970..cfada7645c682d0e440dbd7ff5e13a9473d9a75a 100644
--- a/module/Application/view/application/rapport/rapport-csi/consulter.phtml
+++ b/module/Application/view/application/rapport/rapport-csi/consulter.phtml
@@ -3,6 +3,7 @@
 namespace Application;
 
 use Application\Entity\Db\Rapport;
+use ComiteSuiviIndividuel\Entity\Db\Membre;
 use These\Entity\Db\These;
 use Application\Entity\Db\TypeValidation;
 use Application\Form\RapportCsiForm;
@@ -16,6 +17,7 @@ use Application\View\Renderer\PhpRenderer;
  * @var RapportCsiForm $form
  * @var bool $isTeleversementPossible
  * @var TypeValidation $typeValidation
+ * @var Membre[] $membres
  *
  * @see \Application\Controller\Rapport\RapportCsiController::consulterAction()
  */
@@ -34,6 +36,8 @@ $canAdd = $this->isAllowed($rapportProto, $privilege_TELEVERSER_TOUT) || $this->
 if (!$isTeleversementPossible) {
     $canAdd = false;
 }
+
+$canModifier = ($privilege_TELEVERSER_SIEN OR $privilege_TELEVERSER_TOUT);
 ?>
 
 <?php $this->headTitle($this->translate($title = "Rapports CSI"))
@@ -50,6 +54,95 @@ if (!$isTeleversementPossible) {
     Cette page est consacrée au téléversement des rapports CSI.
 </p>
 
+<div class="row">
+    <div class="col-md-11">
+
+        <h2>Membres du comité</h2>
+
+        <?php if ($membres AND !empty($membres)) : ?>
+            <table class="table table-condensed table-hover">
+                <thead>
+                    <tr>
+                        <th> Civilité </th>
+                        <th> Prénom </th>
+                        <th> Nom </th>
+                        <th> Adresse électronique </th>
+                        <th> Qualité </th>
+                        <th> Rang </th>
+                        <th> Extérieur </th>
+                        <th> Établissement </th>
+                        <th> Rôle </th>
+                        <th> En visio </th>
+                        <?php if ($canModifier) : ?>
+                            <th> Action</th>
+                        <?php endif; ?>
+                    </tr>
+                </thead>
+                <tbody>
+                    <?php foreach ($membres as $membre) : ?>
+                    <tr>
+                        <td> <?php echo ($membre->getGenre()==='F')?"Madame":"Monsieur"; ?> </td>
+                        <td> <?php echo $membre->getPrenom(); ?> </td>
+                        <td> <?php echo $membre->getNom(); ?> </td>
+                        <td> <?php echo ($membre->getEmail() !== null)?$membre->getEmail():"<strong><span class='text-danger'><span class='fas fa-exclamation-triangle'></span> AUCUN MAIL</span></strong>"; ?> </td>
+                        <td> <?php echo ($membre->getQualite())?$membre->getQualite()->getLibelle():"Non définie"; ?> </td>
+                        <td> <?php echo $membre->getRang(); ?> </td>
+                        <td>
+                            <?php if ($membre->isExterieur()): ?>
+                                <span class="icon icon-oui iconly text-success"></span>
+                            <?php else: ?>
+                                <span class="icon icon-non iconly text-danger"></span>
+                            <?php endif; ?>
+                        </td>
+                        <td>
+                            <?php echo $membre->getEtablissement(); ?> <br/>
+                        </td>
+                        <td> <?php echo $membre->getRole(); ?> </td>
+                        <td>
+                            <?php if ($membre->isVisio()): ?>
+                                <span class="icon icon-oui iconly text-success"></span>
+                                <?php $hasVisio = true; ?>
+                            <?php else: ?>
+                                <span class="icon icon-non iconly text-danger"></span>
+                            <?php endif; ?>
+                        </td>
+                        <?php if ($canModifier) : ?>
+                            <td>
+                                <a  <?php /** @see \ComiteSuiviIndividuel\Controller\MembreController::modifierAction(); */ ?>
+                                        href="<?php echo $this->url('comite-suivi-individuel/membre/modifier', ['membre' => $membre->getId()], [] ,true); ?>"
+                                        class="ajax-modal"
+                                        data-event="modification">
+                                    <span class="icon icon-edit iconly"></span>
+                                </a>
+                                <a  <?php /** @see \ComiteSuiviIndividuel\Controller\MembreController::supprimerAction(); */ ?>
+                                        href="<?php echo $this->url('comite-suivi-individuel/membre/supprimer', ['membre' => $membre->getId()], [] ,true); ?>"
+                                        class="ajax-modal"
+                                        data-event="modification">
+                                    <span class="icon icon-delete iconly"></span>
+                                </a>
+                            </td>
+                        <?php endif; ?>
+                    </tr>
+                    <?php endforeach; ?>
+                </tbody>
+            </table>
+        <?php else : ?>
+            <p>
+            Aucun membre de désigné
+            </p>
+        <?php endif; ?>
+
+        <?php if ($canModifier) : ?>
+            <a  <?php /** @see \ComiteSuiviIndividuel\Controller\MembreController::ajouterAction(); */ ?>
+                href="<?php echo $this->url('comite-suivi-individuel/membre/ajouter', ['these' => $these->getId()]); ?>"
+                class="btn btn-primary ajax-modal" data-event="modification"
+            >
+                <span class="icon icon-user-add"></span>
+                Ajouter une membre du comité
+            </a>
+        <?php endif; ?>
+    </div>
+</div>
 <div class="row">
     <div class="col-md-11">
 
@@ -146,9 +239,9 @@ if (!$isTeleversementPossible) {
 
 <script>
     $(function() {
-        var $ajouterBtn = $("#ajouterBtn");
-        var $annulerBtn = $("#annulerBtn");
-        var $ajouterForm = $("#ajouterForm");
+        let $ajouterBtn = $("#ajouterBtn");
+        let $annulerBtn = $("#annulerBtn");
+        let $ajouterForm = $("#ajouterForm");
 
         $ajouterBtn.on('click', function() {
             $ajouterForm.show();
@@ -160,5 +253,11 @@ if (!$isTeleversementPossible) {
             $ajouterBtn.show();
             return false;
         });
+
+        $("body").on("modification", function (event) {
+            event.div.modal('hide');
+            window.location.reload();
+        });
     });
+
 </script>
diff --git a/module/Application/view/application/utilisateur/init-compte.phtml b/module/Application/view/application/utilisateur/init-compte.phtml
index f9883220321f8113ab40a682b55d6ee1491b5d31..206ff810d423fc7ac2040afcc76c0920933b6cf9 100644
--- a/module/Application/view/application/utilisateur/init-compte.phtml
+++ b/module/Application/view/application/utilisateur/init-compte.phtml
@@ -42,8 +42,8 @@ $this->headTitle("Initialisation du compte utilisateur");
                 Le mot de passe doit :
                 <ul>
                     <li> être d'une longueur minimale de 8 caractères ; </li>
-                    <li> posséder des caractères en majuscule et en minuscule  ; </li>
-                    <li> posséder au moins un chiffre  ; </li>
+                    <li> posséder des caractères en majuscule et en minuscule ; </li>
+                    <li> posséder au moins un chiffre ; </li>
                     <li> posséder au moins un caractère spécial (parmi '!', '@', '#', '$', '%', '^', '&', '*', '_').</li>
                 </ul>
             </div>
@@ -70,7 +70,7 @@ $this->headTitle("Initialisation du compte utilisateur");
 
 <div class="alert alert-danger">
     <p class="lead">
-        <span class="fas fa-exclamation-triangle"></span> Aucun compte utilisateur ne correspond à ce jeton d'identification.
+        <span class="icon icon-attention"></span> Aucun compte utilisateur ne correspond à ce jeton d'identification.
     </p>
 
     <p>
diff --git a/module/ComiteSuiviIndividuel/Module.php b/module/ComiteSuiviIndividuel/Module.php
new file mode 100644
index 0000000000000000000000000000000000000000..02c853cec93205da3ac0ada85b840514a1b2e700
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/Module.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace ComiteSuiviIndividuel;
+
+use Laminas\Config\Factory as ConfigFactory;
+use Laminas\Stdlib\Glob;
+
+class Module
+{
+    public function getConfig()
+    {
+        $paths = array_merge(
+            [__DIR__ . '/config/module.config.php'],
+            Glob::glob(__DIR__ . '/config/others/{,*.}{config}.php', Glob::GLOB_BRACE)
+        );
+
+        return ConfigFactory::fromFiles($paths);
+    }
+
+    public function getAutoloaderConfig(): array
+    {
+        return array(
+            'Laminas\Loader\StandardAutoloader' => array(
+                'namespaces' => array(
+                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
+                ),
+            ),
+        );
+    }
+}
diff --git a/module/ComiteSuiviIndividuel/config/module.config.php b/module/ComiteSuiviIndividuel/config/module.config.php
new file mode 100755
index 0000000000000000000000000000000000000000..1201645cd9b4d1626eb6d332140bb56df1afcfd3
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/config/module.config.php
@@ -0,0 +1,72 @@
+<?php
+
+use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
+use Doctrine\ORM\Mapping\Driver\XmlDriver;
+use Laminas\Router\Http\Segment;
+use UnicaenAuth\Guard\PrivilegeController;
+
+return [
+    'doctrine' => [
+        'driver' => [
+            'orm_default' => [
+                'class' => MappingDriverChain::class,
+                'drivers' => [
+                    'ComiteSuiviIndividuel\Entity\Db' => 'orm_default_xml_driver',
+                ],
+            ],
+            'orm_default_xml_driver' => [
+                'class' => XmlDriver::class,
+                'cache' => 'array',
+                'paths' => [
+                    __DIR__ . '/../src/ComiteSuiviIndividuel/Entity/Db/Mapping',
+                ],
+            ],
+        ],
+    ],
+    'view_manager' => [
+        'template_path_stack' => [
+            __DIR__ . '/../view',
+        ],
+    ],
+    'bjyauthorize' => [
+//        'rule_providers'     => [
+//            PrivilegeRuleProvider::class => [
+//                'allow' => [
+//                    [],
+//                ],
+//            ],
+//        ],
+        'guards' => [
+            PrivilegeController::class => []
+        ],
+    ],
+    'router' => [
+        'routes' => [
+        ],
+    ],
+    'navigation' => [
+        'default' => [
+            'home' => [
+                'pages' => [
+                ],
+            ],
+        ],
+    ],
+    'form_elements' => [
+        'factories' => [
+        ],
+    ],
+    'hydrators' => array(
+        'factories' => array()
+    ),
+    'service_manager' => [
+        'factories' => [
+        ],
+    ],
+    'controllers' => [
+        'factories' => [
+        ],
+    ],
+    'controller_plugins' => [
+    ],
+];
diff --git a/module/ComiteSuiviIndividuel/config/others/membre.config.php b/module/ComiteSuiviIndividuel/config/others/membre.config.php
new file mode 100644
index 0000000000000000000000000000000000000000..2ca7d8f31921c39c9d8e3c530dcb425f902c1488
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/config/others/membre.config.php
@@ -0,0 +1,155 @@
+<?php
+
+namespace Soutenance;
+
+use Application\Provider\Privilege\RapportPrivileges;
+use ComiteSuiviIndividuel\Controller\MembreController;
+use ComiteSuiviIndividuel\Controller\MembreControllerFactory;
+use ComiteSuiviIndividuel\Form\Membre\MembreForm;
+use ComiteSuiviIndividuel\Form\Membre\MembreFormFactory;
+use ComiteSuiviIndividuel\Form\Membre\MembreHydrator;
+use ComiteSuiviIndividuel\Form\Membre\MembreHydratorFactory;
+use ComiteSuiviIndividuel\Service\Membre\MembreService;
+use ComiteSuiviIndividuel\Service\Membre\MembreServiceFactory;
+use Laminas\Router\Http\Literal;
+use Laminas\Router\Http\Segment;
+use UnicaenAuth\Guard\PrivilegeController;
+use UnicaenAuth\Provider\Rule\PrivilegeRuleProvider;
+
+return [
+    'bjyauthorize' => [
+        'resource_providers' => [
+            'BjyAuthorize\Provider\Resource\Config' => [
+//                'Acteur' => [],
+            ],
+        ],
+        'rule_providers' => [
+            PrivilegeRuleProvider::class => [
+//                'allow' => [
+//                    [
+//                        'privileges' => [
+//                            InterventionPrivileges::INTERVENTION_AFFICHER,
+//                            InterventionPrivileges::INTERVENTION_MODIFIER,
+//                        ],
+//                        'resources' => ['These'],
+//                        'assertion' => InterventionAssertion::class,
+//                    ],
+//                ],
+            ],
+        ],
+        'guards' => [
+            PrivilegeController::class => [
+                [
+                    'controller' => MembreController::class,
+                    'action' => [
+                        'ajouter',
+                        'modifier',
+                        'supprimer',
+                    ],
+                    'privileges' => [
+                        RapportPrivileges::RAPPORT_CSI_TELEVERSER_SIEN,
+                        RapportPrivileges::RAPPORT_CSI_TELEVERSER_TOUT,
+                    ],
+                ],
+            ],
+        ],
+    ],
+
+    'navigation' => [
+        'default' => [
+            'home' => [
+                'pages' => [
+                ],
+            ],
+        ],
+    ],
+
+    'router' => [
+        'routes' => [
+            'comite-suivi-individuel' => [
+                'type' => Literal::class,
+                'may_terminate' => false,
+                'options' => [
+                    'route' => '/comite-suivi-individuel',
+                    'defaults' => [
+                        'controller' => MembreController::class,
+                        'action' => 'ajouter',
+                    ],
+                ],
+                'child_routes' => [
+                    'membre' => [
+                        'type' => Literal::class,
+                        'may_terminate' => false,
+                        'options' => [
+                            'route' => '/membre',
+                            'defaults' => [
+                                'controller' => MembreController::class,
+                                'action' => 'ajouter',
+                            ],
+                        ],
+                        'child_routes' => [
+                            'ajouter' => [
+                                'type' => Segment::class,
+                                'may_terminate' => true,
+                                'options' => [
+                                    'route' => '/ajouter/:these',
+                                    'defaults' => [
+                                        'action' => 'ajouter',
+                                    ],
+                                ],
+                            ],
+                            'modifier' => [
+                                'type' => Segment::class,
+                                'may_terminate' => true,
+                                'options' => [
+                                    'route' => '/modifier/:membre',
+                                    'defaults' => [
+                                        'action' => 'modifier',
+                                    ],
+                                ],
+                            ],
+                            'supprimer' => [
+                                'type' => Segment::class,
+                                'may_terminate' => true,
+                                'options' => [
+                                    'route' => '/supprimer/:membre',
+                                    'defaults' => [
+                                        'action' => 'supprimer',
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ],
+    ],
+
+    'service_manager' => [
+        'factories' => [
+            MembreService::class => MembreServiceFactory::class,
+        ],
+    ],
+    'controllers' => [
+        'factories' => [
+            MembreController::class => MembreControllerFactory::class,
+        ],
+    ],
+
+    'form_elements' => [
+        'factories' => [
+            MembreForm::class => MembreFormFactory::class,
+        ],
+    ],
+
+    'hydrators' => [
+        'factories' => [
+            MembreHydrator::class => MembreHydratorFactory::class,
+        ],
+    ],
+
+    'view_helpers' => [
+        'invokables' => [
+        ],
+    ],
+];
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Controller/MembreController.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Controller/MembreController.php
new file mode 100644
index 0000000000000000000000000000000000000000..e04d84bb2ffd5923a08541ac6cd043e414b9baed
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Controller/MembreController.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Controller;
+
+use Application\Controller\AbstractController;
+use ComiteSuiviIndividuel\Entity\Db\Membre;
+use ComiteSuiviIndividuel\Form\Membre\MembreFromAwareTrait;
+use ComiteSuiviIndividuel\Service\Membre\MembreServiceAwareTrait;
+use Laminas\View\Model\ViewModel;
+
+class MembreController extends AbstractController
+{
+    use MembreServiceAwareTrait;
+    use MembreFromAwareTrait;
+
+    public function ajouterAction() : ViewModel
+    {
+        $these = $this->requestedThese();
+        $membre = new Membre();
+
+        $form = $this->getMembreForm();
+        $form->setAttribute('action', $this->url()->fromRoute('comite-suivi-individuel/membre/ajouter', ['these' => $these->getId()], [], true));
+        $form->bind($membre);
+
+        $request = $this->getRequest();
+        if ($request->isPost()) {
+            $data = $request->getPost();
+            $form->setData($data);
+            if ($form->isValid()) {
+                $membre->setThese($these);
+                $this->getMembreService()->create($membre);
+            }
+        }
+
+        $vm = new ViewModel([
+            'title' => "Ajout d'un membre de comité de suivi individuel",
+            'these' => $these,
+            'form' => $form,
+        ]);
+        $vm->setTemplate('comite-suivi-individuel/membre/modifier');
+        return $vm;
+    }
+
+    public function modifierAction() : ViewModel
+    {
+        $membre = $this->getMembreService()->getRequestedMembre($this);
+
+        $form = $this->getMembreForm();
+        $form->setAttribute('action', $this->url()->fromRoute('comite-suivi-individuel/membre/modifier', ['membre' => $membre->getId()], [], true));
+        $form->bind($membre);
+
+        $request = $this->getRequest();
+        if ($request->isPost()) {
+            $data = $request->getPost();
+            $form->setData($data);
+            if ($form->isValid()) {
+
+                $this->getMembreService()->create($membre);
+            }
+        }
+
+        $vm = new ViewModel([
+            'title' => "Modification d'un membre du comité de suivi individuel",
+            'form' => $form,
+        ]);
+        $vm->setTemplate('comite-suivi-individuel/membre/modifier');
+        return $vm;
+    }
+
+    public function supprimerAction() : ViewModel
+    {
+        $membre = $this->getMembreService()->getRequestedMembre($this);
+
+        $request = $this->getRequest();
+        if ($request->isPost()) {
+            $data = $request->getPost();
+            if ($data["reponse"] === "oui") $this->getMembreService()->delete($membre);
+            exit();
+        }
+
+        $vm = new ViewModel();
+        if ($membre !== null) {
+            $vm->setTemplate('comite-suivi-individuel/default/confirmation');
+            $vm->setVariables([
+                'title' => "Suppression du membre " . $membre->getDenomination(),
+                'text' => "La suppression est définitive êtes-vous sûr&middot;e de vouloir continuer ?",
+                'action' => $this->url()->fromRoute('comite-suivi-individuel/membre/supprimer', ["membre" => $membre->getId()], [], true),
+            ]);
+        }
+        return $vm;
+    }
+}
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Controller/MembreControllerFactory.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Controller/MembreControllerFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..fb355b2ed5741d9a276b255b520afa9c524daab5
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Controller/MembreControllerFactory.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Controller;
+
+use ComiteSuiviIndividuel\Form\Membre\MembreForm;
+use ComiteSuiviIndividuel\Service\Membre\MembreService;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\ContainerInterface;
+use Psr\Container\NotFoundExceptionInterface;
+
+class MembreControllerFactory {
+
+    /**
+     * @param ContainerInterface $container
+     * @return MembreController
+     * @throws ContainerExceptionInterface
+     * @throws NotFoundExceptionInterface
+     */
+    public function __invoke(ContainerInterface $container) : MembreController
+    {
+        /**
+         * @var MembreService $membreService
+         * @var MembreForm $membreForm
+         */
+        $membreService = $container->get(MembreService::class);
+        $membreForm = $container->get('FormElementManager')->get(MembreForm::class);
+
+        $controller = new MembreController();
+        $controller->setMembreService($membreService);
+        $controller->setMembreForm($membreForm);
+        return $controller;
+    }
+}
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Entity/Db/Mapping/ComiteSuiviIndividuel.Entity.Db.Membre.dcm.xml b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Entity/Db/Mapping/ComiteSuiviIndividuel.Entity.Db.Membre.dcm.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b1e1de572cf67941a209ccbc7a55b6d931f7c046
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Entity/Db/Mapping/ComiteSuiviIndividuel.Entity.Db.Membre.dcm.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                  xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
+    <entity name="ComiteSuiviIndividuel\Entity\Db\Membre" table="CSI_MEMBRE">
+        <id name="id" type="integer" column="ID">
+            <generator strategy="SEQUENCE"/>
+        </id>
+
+        <many-to-one field="these" target-entity="These\Entity\Db\These">
+            <join-columns>
+                <join-column name="these_id" referenced-column-name="ID"/>
+            </join-columns>
+        </many-to-one>
+
+        <field name="genre"             type="string"       length="1"          column="GENRE"          nullable="false"/>
+        <field name="prenom"            type="string"       length="256"        column="PRENOM"         nullable="false"/>
+        <field name="nom"               type="string"       length="256"        column="NOM"            nullable="false"/>
+        <field name="email"             type="string"       length="256"        column="EMAIL"          nullable="false"/>
+
+        <many-to-one field="qualite" target-entity="Soutenance\Entity\Qualite">
+            <join-columns>
+                <join-column name="QUALITE" referenced-column-name="ID"/>
+            </join-columns>
+        </many-to-one>
+
+        <field name="etablissement"     type="string"       length="128"        column="ETABLISSEMENT"  nullable="false"/>
+        <field name="exterieur"         type="string"       length="3"          column="EXTERIEUR"      nullable="false"/>
+        <field name="role"              type="string"       length="64"         column="ROLE_ID"        nullable="false"/>
+        <field name="visio"             type="boolean"                          column="VISIO"          nullable="false"/>
+
+        <many-to-one field="acteur" target-entity="These\Entity\Db\Acteur">
+            <join-columns>
+                <join-column name="ACTEUR_ID" referenced-column-name="ID"/>
+            </join-columns>
+        </many-to-one>
+
+        <!-- HISTORISATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
+        <field name="histoCreation" type="datetime" column="HISTO_CREATION" nullable="false"/>
+        <field name="histoDestruction" type="datetime" column="HISTO_DESTRUCTION" nullable="true"/>
+        <field name="histoModification" type="datetime" column="HISTO_MODIFICATION" nullable="false"/>
+        <many-to-one field="histoCreateur" target-entity="Application\Entity\Db\Utilisateur">
+            <join-columns>
+                <join-column name="HISTO_CREATEUR_ID" referenced-column-name="ID"/>
+            </join-columns>
+        </many-to-one>
+        <many-to-one field="histoModificateur" target-entity="Application\Entity\Db\Utilisateur">
+            <join-columns>
+                <join-column name="HISTO_MODIFICATEUR_ID" referenced-column-name="ID"/>
+            </join-columns>
+        </many-to-one>
+        <many-to-one field="histoDestructeur" target-entity="Application\Entity\Db\Utilisateur">
+            <join-columns>
+                <join-column name="HISTO_DESTRUCTEUR_ID" referenced-column-name="ID"/>
+            </join-columns>
+        </many-to-one>
+
+    </entity>
+</doctrine-mapping>
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Entity/Db/Membre.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Entity/Db/Membre.php
new file mode 100644
index 0000000000000000000000000000000000000000..cfd7866f6f0a50a60a3e9b5a4ce5c35b033d792e
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Entity/Db/Membre.php
@@ -0,0 +1,177 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Entity\Db;
+
+use Soutenance\Entity\Qualite;
+use These\Entity\Db\Acteur;
+use Individu\Entity\Db\Individu;
+use These\Entity\Db\These;
+use UnicaenApp\Entity\HistoriqueAwareInterface;
+use UnicaenApp\Entity\HistoriqueAwareTrait;
+use UnicaenApp\Exception\RuntimeException;
+
+class Membre implements HistoriqueAwareInterface {
+    use HistoriqueAwareTrait;
+
+    const MEMBRE_CSI        = 'Membre';
+    const RAPPORTEUR_CSI    = 'Rapporteur';
+
+    private ?int $id = -1;
+    private ?These $these = null;
+    private ?string $genre = null;
+    private ?string $prenom = null;
+    private ?string $nom = null;
+    private ?string $email = null;
+    private ?Qualite $qualite = null;
+    private ?string $etablissement = null;
+    private ?string $exterieur = null;
+    private ?string $role = null;
+    private bool $visio = false;
+    private ?Acteur $acteur = null;
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function setId(?int $id): void
+    {
+        $this->id = $id;
+    }
+
+    public function getThese(): ?These
+    {
+        return $this->these;
+    }
+
+    public function setThese(?These $these): void
+    {
+        $this->these = $these;
+    }
+
+    public function getGenre(): ?string
+    {
+        return $this->genre;
+    }
+
+    public function setGenre(?string $genre): void
+    {
+        $this->genre = $genre;
+    }
+
+    public function getPrenom(): ?string
+    {
+        return $this->prenom;
+    }
+
+    public function setPrenom(?string $prenom): void
+    {
+        $this->prenom = $prenom;
+    }
+
+    public function getNom(): ?string
+    {
+        return $this->nom;
+    }
+
+    public function setNom(?string $nom): void
+    {
+        $this->nom = $nom;
+    }
+
+    public function getEmail(): ?string
+    {
+        return $this->email;
+    }
+
+    public function setEmail(?string $email): void
+    {
+        $this->email = $email;
+    }
+
+    public function getQualite(): ?Qualite
+    {
+        return $this->qualite;
+    }
+
+    public function setQualite(?Qualite $qualite): void
+    {
+        $this->qualite = $qualite;
+    }
+
+    public function getEtablissement(): ?string
+    {
+        return $this->etablissement;
+    }
+
+    public function setEtablissement(?string $etablissement): void
+    {
+        $this->etablissement = $etablissement;
+    }
+
+    public function getExterieur(): ?string
+    {
+        return $this->exterieur;
+    }
+
+    public function setExterieur(?string $exterieur): void
+    {
+        $this->exterieur = $exterieur;
+    }
+
+    public function getRole(): ?string
+    {
+        return $this->role;
+    }
+
+    public function setRole(?string $role): void
+    {
+        $this->role = $role;
+    }
+
+    public function isVisio(): bool
+    {
+        return $this->visio;
+    }
+
+    public function setVisio(bool $visio): void
+    {
+        $this->visio = $visio;
+    }
+
+    public function getActeur(): ?Acteur
+    {
+        return $this->acteur;
+    }
+
+    public function setActeur(?Acteur $acteur): void
+    {
+        $this->acteur = $acteur;
+    }
+
+    public function getDenomination() : string
+    {
+        return $this->prenom." ".$this->getNom();
+    }
+
+    public function getRang() : ?string
+    {
+        if ($this->getQualite() === null) {
+            throw new RuntimeException("Pas de qualité associé au membre de jury [".$this->getDenomination()."].");
+        }
+        return $this->getQualite()->getRang();
+    }
+
+    public function isExterieur() : ?bool
+    {
+        if ($this->exterieur === null) return null;
+        return ($this->exterieur === "oui");
+    }
+
+    public function getIndividu() : ?Individu
+    {
+        $acteur = $this->getActeur();
+        if ($acteur === null) return null;
+        return $acteur->getIndividu();
+    }
+}
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreForm.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..4b176162be8353b756e1f606ad40df05b4dd862b
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreForm.php
@@ -0,0 +1,145 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Form\Membre;
+
+use ComiteSuiviIndividuel\Entity\Db\Membre;
+use Soutenance\Service\Qualite\QualiteServiceAwareTrait;
+use UnicaenApp\Service\EntityManagerAwareTrait;
+use Laminas\Form\Element\Email;
+use Laminas\Form\Element\Radio;
+use Laminas\Form\Element\Select;
+use Laminas\Form\Element\Submit;
+use Laminas\Form\Element\Text;
+use Laminas\Form\Element\Textarea;
+use Laminas\Form\Form;
+use Laminas\InputFilter\Factory;
+use Laminas\Validator\EmailAddress;
+
+class MembreForm extends Form {
+    use EntityManagerAwareTrait;
+    use QualiteServiceAwareTrait;
+
+    public function init()
+    {
+        $this->add([
+           'type' => Radio::class,
+           'name' => 'sexe',
+           'options' => [
+               'label' => 'Civilité : ',
+               'value_options' => [
+                   'F' => 'Madame',
+                   'H' => 'Monsieur',
+               ],
+           ],
+        ]);
+
+        $this->add(
+            (new Text('prenom'))
+                ->setLabel("Prénom du membre de comité :")
+        );
+        $this->add(
+            (new Text('nom'))
+                ->setLabel("Nom du membre de comité :")
+        );
+
+
+        $mailValidator = new EmailAddress();
+        $mailValidator->setMessages([
+           EmailAddress::INVALID_FORMAT =>  'Adresse électronique non valide !',
+        ]);
+        $this->add(
+            (new Email('email'))
+                ->setLabel("Adresse électronique :")
+                ->setValidator($mailValidator)
+        );
+
+        $this->add([
+            'name' => 'qualite',
+            'type' => Select::class,
+            'options' => [
+                'label' => 'Qualité : ',
+                'empty_option' => "Sélectionner une qualité ... ",
+                'value_options' => $this->getQualiteService()->getQualitesAsGroupOptions(),
+            ],
+            'attributes' => [
+                'id'                => 'competence',
+                'class'             => 'bootstrap-selectpicker show-tick',
+                'data-live-search'  => 'true',
+            ]
+        ]);
+
+        $this->add(
+            (new Text('etablissement'))
+                ->setLabel("Université, établissement d'enseignement ou entreprise :")
+        );
+        $this->add(
+            (new Radio('exterieur'))
+                ->setLabel("Le membre est extérieur (non membre d'un établissement de la COMUE et non membre de l'unité de recherche de la thèse) :")
+                ->setValueOptions([ 'oui' => 'Oui', 'non' => 'Non'])
+        );
+        $this->add(
+            (new Radio('visio'))
+                ->setLabel("Le membre sera présent en visioconférence :")
+                ->setValueOptions([ '1' => 'Oui', '0' => 'Non'])
+        );
+        $this->add(
+            (new Radio('role'))
+                ->setLabel("Role dans le comité :")
+                ->setValueOptions([
+                    Membre::RAPPORTEUR_CSI   => 'Rapporteur du comité',
+                    Membre::MEMBRE_CSI       => 'Membre du comité',
+                ])
+        );
+
+        $this->add((new Submit('submit'))
+            ->setValue("Enregistrer")
+            ->setAttribute('class', 'btn btn-primary')
+        );
+
+        $this->setInputFilter((new Factory())->createInputFilter([
+            'sexe' => [
+                'name' => 'sexe',
+                'required' => true,
+            ],
+            'prenom' => [
+                'name' => 'prenom',
+                'required' => true,
+            ],
+            'nom' => [
+                'name' => 'prenom',
+                'required' => true,
+            ],
+            'email' => [
+                'name' => 'email',
+                'required' => true,
+                'validator' => [
+                    'name' => EmailAddress::class,
+                    'messages' => [
+                        EmailAddress::INVALID_FORMAT => '',
+                    ],
+                ],
+            ],
+            'qualite' => [
+                'name' => 'qualite',
+                'required' => true,
+            ],
+            'etablissement' => [
+                'name' => 'etablissement',
+                'required' => true,
+            ],
+            'exterieur' => [
+                'name' => 'exterieur',
+                'required' => true,
+            ],
+            'visio' => [
+                'name' => 'visio',
+                'required' => true,
+            ],
+            'role' => [
+                'name' => 'role',
+                'required' => true,
+            ],
+        ]));
+    }
+
+}
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreFormFactory.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreFormFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..334c49c9a5f5092e88f0d537eb8f406c9eb8791f
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreFormFactory.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Form\Membre;
+
+use Doctrine\ORM\EntityManager;
+use Interop\Container\ContainerInterface;
+use Soutenance\Service\Qualite\QualiteService;
+
+
+class MembreFormFactory
+{
+    public function __invoke(ContainerInterface $container)
+    {
+        /**
+         * @var EntityManager $entityManager
+         * @var QualiteService $qualiteService
+         */
+        $entityManager = $container->get('doctrine.entitymanager.orm_default');
+        $qualiteService = $container->get(QualiteService::class);
+
+        /** @var MembreHydrator $hydrator */
+        $hydrator = $container->get('HydratorManager')->get(MembreHydrator::class);
+
+        /** @var MembreForm $form */
+        $form = new MembreForm();
+        $form->setEntityManager($entityManager);
+        $form->setQualiteService($qualiteService);
+        $form->setHydrator($hydrator);
+
+        return $form;
+    }
+}
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreFromAwareTrait.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreFromAwareTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..a543668cab318d50a431a68a1792f5464fad21d9
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreFromAwareTrait.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Form\Membre;
+
+trait MembreFromAwareTrait {
+
+    /** @var MembreForm */
+    private $membreForm;
+
+    /**
+     * @return MembreForm
+     */
+    public function getMembreForm()
+    {
+        return $this->membreForm;
+    }
+
+    /**
+     * @param MembreForm $membreForm
+     * @return MembreForm
+     */
+    public function setMembreForm($membreForm)
+    {
+        $this->membreForm = $membreForm;
+        return $this->membreForm;
+    }
+
+
+}
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreHydrator.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreHydrator.php
new file mode 100644
index 0000000000000000000000000000000000000000..1707ebd793761466a57bf068369370ed3455ffcb
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreHydrator.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Form\Membre;
+
+use ComiteSuiviIndividuel\Entity\Db\Membre;
+use Soutenance\Service\Qualite\QualiteServiceAwareTrait;
+use Laminas\Hydrator\HydratorInterface;
+
+class MembreHydrator implements HydratorInterface
+{
+    use QualiteServiceAwareTrait;
+
+    /**
+     * @param array $data
+     * @param Membre $membre
+     * @return Membre
+     */
+    public function hydrate(array $data, $membre) {
+
+        $membre->setGenre($data['sexe']);
+        $membre->setPrenom($data['prenom']);
+        $membre->setNom($data['nom']);
+        $membre->setQualite($this->getQualiteService()->getQualite($data['qualite']));
+        $membre->setEtablissement($data['etablissement']);
+        $membre->setExterieur($data['exterieur']);
+        $membre->setVisio($data['visio']);
+        $membre->setRole($data['role']);
+        $membre->setEmail($data['email']);
+        return $membre;
+    }
+
+    /**
+     * @param Membre $membre
+     * @return array
+     */
+    public function extract($membre): array {
+
+        $data = [];
+        $data['sexe']               = $membre->getGenre();
+        $data['prenom']             = $membre->getPrenom();
+        $data['nom']                = $membre->getNom();
+        $data['qualite']            = ($membre->getQualite())?$membre->getQualite()->getId():null;
+        $data['etablissement']      = $membre->getEtablissement();
+        $data['exterieur']          = $membre->getExterieur();
+        $data['visio']              = $membre->isVisio();
+        $data['role']               = $membre->getRole();
+        $data['email']              = $membre->getEmail();
+
+        return $data;
+    }
+}
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreHydratorFactory.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreHydratorFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..a45dbd97d1c2cbdf33837a16129b2828f2fea1d8
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Form/Membre/MembreHydratorFactory.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Form\Membre;
+
+use Interop\Container\ContainerInterface;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\NotFoundExceptionInterface;
+use Soutenance\Service\Qualite\QualiteService;
+
+class MembreHydratorFactory
+{
+    /**
+     * @param ContainerInterface $container
+     * @return MembreHydrator
+     * @throws ContainerExceptionInterface
+     * @throws NotFoundExceptionInterface
+     */
+    public function __invoke(ContainerInterface $container) : MembreHydrator
+    {
+        /**
+         * @var QualiteService $qualiteService
+         */
+        $qualiteService = $container->get(QualiteService::class);
+
+        $hydrator = new MembreHydrator();
+        $hydrator->setQualiteService($qualiteService);
+
+        return $hydrator;
+    }
+}
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Service/Membre/MembreService.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Service/Membre/MembreService.php
new file mode 100644
index 0000000000000000000000000000000000000000..c50988c9884e2c2dd0a31668b50f569bc0c90bd4
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Service/Membre/MembreService.php
@@ -0,0 +1,117 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Service\Membre;
+
+use ComiteSuiviIndividuel\Entity\Db\Membre;
+use Doctrine\ORM\NonUniqueResultException;
+use Doctrine\ORM\ORMException;
+use Doctrine\ORM\QueryBuilder;
+use Laminas\Mvc\Controller\AbstractActionController;
+use These\Entity\Db\These;
+use UnicaenApp\Exception\RuntimeException;
+use UnicaenApp\Service\EntityManagerAwareTrait;
+
+class MembreService {
+    use EntityManagerAwareTrait;
+
+    /** GESTION DES ENTITES *******************************************************************************************/
+
+    public function create(Membre $membre) : Membre
+    {
+        try {
+            $this->getEntityManager()->persist($membre);
+            $this->getEntityManager()->flush($membre);
+        } catch(ORMException $e) {
+            throw new RuntimeException("Un problème est survenu en base de donnée",0,$e);
+        }
+        return $membre;
+    }
+
+    public function update(Membre $membre) : Membre
+    {
+        try {
+            $this->getEntityManager()->flush($membre);
+        } catch(ORMException $e) {
+            throw new RuntimeException("Un problème est survenu en base de donnée",0,$e);
+        }
+        return $membre;
+    }
+
+    public function historise(Membre $membre) : Membre
+    {
+        $membre->historiser();
+        try {
+            $this->getEntityManager()->flush($membre);
+        } catch(ORMException $e) {
+            throw new RuntimeException("Un problème est survenu en base de donnée",0,$e);
+        }
+        return $membre;
+    }
+
+    public function restore(Membre $membre) : Membre
+    {
+        $membre->dehistoriser();
+        try {
+            $this->getEntityManager()->flush($membre);
+        } catch(ORMException $e) {
+            throw new RuntimeException("Un problème est survenu en base de donnée",0,$e);
+        }
+        return $membre;
+    }
+
+    public function delete(Membre $membre) : Membre
+    {
+        try {
+            $this->getEntityManager()->remove($membre);
+            $this->getEntityManager()->flush($membre);
+        } catch(ORMException $e) {
+            throw new RuntimeException("Un problème est survenu en base de donnée",0,$e);
+        }
+        return $membre;
+    }
+
+    /** REQUETAGE *****************************************************************************************************/
+
+    public function createQueryBuilder() : QueryBuilder
+    {
+        $qb = $this->getEntityManager()->getRepository(Membre::class)->createQueryBuilder('membre')
+            ->leftJoin('membre.acteur', 'acteur')->addSelect('acteur')
+            ->leftJoin('membre.qualite', 'qualite')->addSelect('qualite')
+            ->leftJoin('membre.these', 'these')->addSelect('these')
+        ;
+        return $qb;
+    }
+
+    public function getMembre(?int $id) : ?Membre
+    {
+        $qb = $this->createQueryBuilder()
+            ->andWhere('membre.id = :id')->setParameter('id', $id);
+        try {
+            $result = $qb->getQuery()->getOneOrNullResult();
+        } catch (NonUniqueResultException $e) {
+            throw new RuntimeException("Plusieurs Membre partagent le même id [".$id."]");
+        }
+        return $result;
+    }
+
+    public function getRequestedMembre(AbstractActionController $controller, string $param='membre') : ?Membre
+    {
+        $id = $controller->params()->fromRoute($param);
+        $result = $this->getMembre($id);
+        return $result;
+    }
+
+    /**
+     * @param These $these
+     * @return Membre[]
+     */
+    public function getMembresbyThese(These $these) : array
+    {
+        $qb = $this->createQueryBuilder()
+            ->andWhere('membre.these = :these')->setParameter('these', $these);
+        $result = $qb->getQuery()->getResult();
+        return $result;
+    }
+
+    /** FACADE ********************************************************************************************************/
+}
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Service/Membre/MembreServiceAwareTrait.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Service/Membre/MembreServiceAwareTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..54844780ade8d8d83f83f6392a0c0365848150d3
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Service/Membre/MembreServiceAwareTrait.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Service\Membre;
+
+trait MembreServiceAwareTrait {
+
+    private MembreService $membreService;
+
+    public function getMembreService(): MembreService
+    {
+        return $this->membreService;
+    }
+
+    public function setMembreService(MembreService $membreService): void
+    {
+        $this->membreService = $membreService;
+    }
+
+}
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Service/Membre/MembreServiceFactory.php b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Service/Membre/MembreServiceFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..e055ac96958a8328247c20d2b5d571824dd1006e
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/src/ComiteSuiviIndividuel/Service/Membre/MembreServiceFactory.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace ComiteSuiviIndividuel\Service\Membre;
+
+use Doctrine\ORM\EntityManager;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\ContainerInterface;
+use Psr\Container\NotFoundExceptionInterface;
+
+class MembreServiceFactory {
+
+    /**
+     * @param ContainerInterface $container
+     * @return MembreService
+     * @throws ContainerExceptionInterface
+     * @throws NotFoundExceptionInterface
+     */
+    public function __invoke(ContainerInterface $container) : MembreService
+    {
+        /**
+         * @var EntityManager $entityManager
+         */
+        $entityManager = $container->get('doctrine.entitymanager.orm_default');
+
+        $service = new MembreService();
+        $service->setEntityManager($entityManager);
+        return $service;
+    }
+
+}
\ No newline at end of file
diff --git a/module/ComiteSuiviIndividuel/view/comite-suivi-individuel/default/confirmation.phtml b/module/ComiteSuiviIndividuel/view/comite-suivi-individuel/default/confirmation.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..db3629d614e97980a4542838e56cbd74b3ecc370
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/view/comite-suivi-individuel/default/confirmation.phtml
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @var string $title
+ * @var string $text
+ * @var string $action
+ * @var bool $justificationOui
+ * @var bool $justificationNon
+ */
+
+?>
+
+<p class="lead">
+<?php echo $text; ?>
+</p>
+
+
+<table style="width: 100%;">
+    <tr><td style="width: 50%;">
+<form method="post" action="<?php echo $action; ?>">
+    <input type="hidden" name="reponse" value="oui">
+    <?php if ($justificationOui === true) : ?>
+        <label for="justification-oui"> Justification </label>
+        <textarea id="justification-oui" name="justification-oui" style="width: 95%;" placeholder="Merci de justifier"></textarea><br/>
+    <?php endif; ?>
+    <input type="submit" name="reponse" class="btn btn-success action" value="Oui, je suis sûr&middot;e">
+</form>
+        </td><td style="width: 50%;">
+<form method="post" action="<?php echo $action; ?>">
+    <input type="hidden" name="reponse" value="non">
+    <?php if ($justificationNon === true) : ?>
+        <label for="justification-non"> Justification </label>
+        <textarea id="justification-non" name="justification-non"  style="width: 95%;" placeholder="Merci de justifier"></textarea><br/>
+    <?php endif; ?>
+    <input type="submit" id="non" name="reponse" class="btn btn-danger action"  value="Non, je ne veux pas">
+</form>
+        </td></tr>
+</table>
+
+<script>
+    $(function() {
+        $("input#non").click(function(e){
+            $('div.modal').modal('hide');
+            e.preventDefault(e);
+        });
+    });
+</script>
+
diff --git a/module/ComiteSuiviIndividuel/view/comite-suivi-individuel/membre/modifier.phtml b/module/ComiteSuiviIndividuel/view/comite-suivi-individuel/membre/modifier.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..0f3da2a4c6ed93d5535463306f659819106d641a
--- /dev/null
+++ b/module/ComiteSuiviIndividuel/view/comite-suivi-individuel/membre/modifier.phtml
@@ -0,0 +1,17 @@
+<?php
+
+use ComiteSuiviIndividuel\Form\Membre\MembreForm;
+use These\Entity\Db\These;
+
+/**
+ * @see \ComiteSuiviIndividuel\Controller\MembreController::ajouterAction()
+ * @see \ComiteSuiviIndividuel\Controller\MembreController::modifierAction()
+ *
+ * @var string $title
+ * @var These $these
+ * @var MembreForm $form
+ */
+
+?>
+
+<?php echo $this->form($form); ?>
\ No newline at end of file
diff --git a/module/Formation/src/Formation/Controller/SessionController.php b/module/Formation/src/Formation/Controller/SessionController.php
index 91fe90d74f31d4a29bdcd6cbc78f68dd6939f881..5ebf7c5581a45c29fe75e96f12fffb4636463320 100644
--- a/module/Formation/src/Formation/Controller/SessionController.php
+++ b/module/Formation/src/Formation/Controller/SessionController.php
@@ -91,6 +91,7 @@ class SessionController extends AbstractController
                 /** @var Etat $enPrepration */
                 $enPrepration = $this->getEntityManager()->getRepository(Etat::class)->findOneBy(["code" => Etat::CODE_PREPARATION]);
                 $session->setEtat($enPrepration);
+                $this->sessionService->addHeurodatage($session, $enPrepration);
 
                 $this->getSessionService()->update($session);
 
@@ -209,6 +210,7 @@ class SessionController extends AbstractController
 
             if ($etat !== null) {
                 $session->setEtat($etat);
+                $this->sessionService->addHeurodatage($session, $etat);
                 $this->getSessionService()->update($session);
 
                 switch ($session->getEtat()->getCode()) {
@@ -261,13 +263,13 @@ class SessionController extends AbstractController
             if ($positionPrincipale < $session->getTailleListePrincipale()) {
                 $inscription->setListe(Inscription::LISTE_PRINCIPALE);
                 $this->getInscriptionService()->update($inscription);
-                $this->getNotificationService()->triggerInscriptionListePrincipale($inscription);
+                if ($session->isFinInscription()) $this->getNotificationService()->triggerInscriptionListePrincipale($inscription);
                 $positionPrincipale++;
             } else {
                 if ($positionComplementaire < $session->getTailleListeComplementaire()) {
                     $inscription->setListe(Inscription::LISTE_COMPLEMENTAIRE);
                     $this->getInscriptionService()->update($inscription);
-                    $this->getNotificationService()->triggerInscriptionListeComplementaire($inscription);
+                    if ($session->isFinInscription()) $this->getNotificationService()->triggerInscriptionListeComplementaire($inscription);
                     $positionComplementaire++;
                 }
                 else {
@@ -299,15 +301,16 @@ class SessionController extends AbstractController
     public function genererExportAction() : CsvModel
     {
         $session = $this->getSessionService()->getRepository()->getRequestedSession($this);
+        $annee = $session->getAnneeScolaire();
 
-        $headers = ['Liste', 'Dénomination étudiant', 'Adresse électronique', 'Établissement', 'École doctorale', 'Unité de recherche', 'Desinscription', 'Motif de desinscription'];
+        $headers = ['Liste', 'Dénomination étudiant', 'Adresse électronique', 'Année de thèse', 'Établissement', 'École doctorale', 'Unité de recherche', 'Desinscription', 'Motif de desinscription'];
 
         $inscriptions = $session->getInscriptions()->toArray();
         $records = [];
         /** @var Inscription $inscription */
         foreach ($inscriptions as $inscription) {
             $doctorant = $inscription->getDoctorant();
-            $theses = array_filter($doctorant->getTheses(), function (These $t) { return $t->getEtatThese() === These::ETAT_EN_COURS; });
+            $theses = array_filter($doctorant->getTheses(), function (These $t) { return ($t->getEtatThese() === These::ETAT_EN_COURS AND $t->estNonHistorise());});
             $etablissements = array_map(function (These $t) { return ($t->getEtablissement())?$t->getEtablissement()->getStructure()->getLibelle():"Établissement non renseigné";}, $theses);
             $ecoles = array_map(function (These $t) { return ($t->getEcoleDoctorale())?$t->getEcoleDoctorale()->getStructure()->getLibelle():"École doctorale non renseignée";}, $theses);
             $unites = array_map(function (These $t) { return ($t->getUniteRecherche())?$t->getUniteRecherche()->getStructure()->getLibelle():"Unité de recherche non renseignée";}, $theses);
@@ -315,6 +318,7 @@ class SessionController extends AbstractController
                 'Liste' => $inscription->getListe(),
                 'Dénomination étudiant' => $doctorant->getIndividu()->getNomComplet(),
                 'Adresse électronique' => $doctorant->getIndividu()->getEmail(),
+                'Année de thèse' => current($theses)->getNbInscription($annee),
                 'Établissement' => implode("/",$etablissements),
                 'École doctorale' => implode("/",$ecoles),
                 'Unité de recherche' => implode("/",$unites),
diff --git a/module/Formation/src/Formation/Entity/Db/Etat.php b/module/Formation/src/Formation/Entity/Db/Etat.php
index 9fec303c446e370b6fafc0174aa90cfe0dcdfa2b..e032569e14091a0b3ca4085a79993a9d175c465f 100644
--- a/module/Formation/src/Formation/Entity/Db/Etat.php
+++ b/module/Formation/src/Formation/Entity/Db/Etat.php
@@ -7,7 +7,6 @@ class Etat {
     const CODE_PREPARATION = 'P';
     const CODE_OUVERTE = 'O';
     const CODE_FERME = 'F';
-    const CODE_NOTIFIER = 'N';
     const CODE_CLOTURER = 'C';
     const CODE_ANNULEE = 'A';
     const CODE_IMMINENT = 'I';
diff --git a/module/Formation/src/Formation/Entity/Db/Mapping/Formation.Entity.Db.Session.dcm.xml b/module/Formation/src/Formation/Entity/Db/Mapping/Formation.Entity.Db.Session.dcm.xml
index 39de2363cf3e085535a7649dd9d5b0f3011fffcd..555f7b51f801d81af8d46811bfcb0b2eef0fdbea 100644
--- a/module/Formation/src/Formation/Entity/Db/Mapping/Formation.Entity.Db.Session.dcm.xml
+++ b/module/Formation/src/Formation/Entity/Db/Mapping/Formation.Entity.Db.Session.dcm.xml
@@ -44,6 +44,7 @@
         <one-to-many field="structuresValides" target-entity="Formation\Entity\Db\SessionStructureValide" mapped-by="session"/>
         <one-to-many field="seances" target-entity="Formation\Entity\Db\Seance" mapped-by="session"/>
         <one-to-many field="formateurs" target-entity="Formation\Entity\Db\Formateur" mapped-by="session"/>
+        <one-to-many field="heurodatages" target-entity="Formation\Entity\Db\SessionEtatHeurodatage" mapped-by="session"/>
 
         <one-to-many field="inscriptions" target-entity="Formation\Entity\Db\Inscription" mapped-by="session"/>
         <field name="tailleListePrincipale"     type="integer"                     column="TAILLE_LISTE_PRINCIPALE"      nullable="true"/>
diff --git a/module/Formation/src/Formation/Entity/Db/Mapping/Formation.Entity.Db.SessionEtatHeurodatage.dcm.xml b/module/Formation/src/Formation/Entity/Db/Mapping/Formation.Entity.Db.SessionEtatHeurodatage.dcm.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ce98b58c76051cf42d343255a99bcd636ac46329
--- /dev/null
+++ b/module/Formation/src/Formation/Entity/Db/Mapping/Formation.Entity.Db.SessionEtatHeurodatage.dcm.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
+    <entity name="Formation\Entity\Db\SessionEtatHeurodatage"
+            table="FORMATION_SESSION_ETAT_HEURODATAGE"
+    >
+        <id name="id" type="integer" column="ID">
+            <generator strategy="SEQUENCE"/>
+        </id>
+
+        <many-to-one field="session" target-entity="Formation\Entity\Db\Session">
+            <join-columns>
+                <join-column name="SESSION_ID" referenced-column-name="ID"/>
+            </join-columns>
+        </many-to-one>
+        <many-to-one field="etat" target-entity="Formation\Entity\Db\Etat">
+            <join-columns>
+                <join-column name="ETAT_ID" referenced-column-name="CODE"/>
+            </join-columns>
+        </many-to-one>
+        <field name="heurodatage" type="datetime" column="HEURODATAGE" nullable="false"/>
+        <many-to-one field="utilisateur" target-entity="Application\Entity\Db\Utilisateur">
+            <join-columns>
+                <join-column name="utilisateur_id" referenced-column-name="ID"/>
+            </join-columns>
+        </many-to-one>
+    </entity>
+</doctrine-mapping>
\ No newline at end of file
diff --git a/module/Formation/src/Formation/Entity/Db/Session.php b/module/Formation/src/Formation/Entity/Db/Session.php
index 17969db812b68c316a76dc93849f02e5dc2afa6b..5cf708272f96ebae3b653ad13179086999b5ff1f 100644
--- a/module/Formation/src/Formation/Entity/Db/Session.php
+++ b/module/Formation/src/Formation/Entity/Db/Session.php
@@ -51,6 +51,7 @@ class Session implements HistoriqueAwareInterface,
     private Collection $seances;
     private Collection $formateurs;
     private Collection $inscriptions;
+    private Collection $heurodatages;
 
     private ?int $tailleListePrincipale = null;
     private ?int $tailleListeComplementaire = null;
@@ -331,6 +332,29 @@ class Session implements HistoriqueAwareInterface,
         return 'M'.$module->getId() . 'F'.$formation->getId() . 'S'.$this->getId();
     }
 
+    public function getAnneeScolaire() : int
+    {
+        $debut = $this->getDateDebut();
+        if ($debut === null) $debut = new DateTime();
+
+        $mois = ((int) $debut->format('m'));
+        $annee =  ((int) $debut->format('Y'));
+        if ($mois > 8) $annee += 1;
+        return $annee;
+    }
+
+    /**
+     * @return SessionEtatHeurodatage[]
+     */
+    public function getHeurodatages() : array
+    {
+        $array = $this->heurodatages->toArray();
+        usort($array,
+            function (SessionEtatHeurodatage $a, SessionEtatHeurodatage $b) {
+                return $a->getHeurodatage() > $b->getHeurodatage(); });
+        return $array;
+    }
+
     /** Pour les macros ********************************************************************************/
 
     /**
diff --git a/module/Formation/src/Formation/Entity/Db/SessionEtatHeurodatage.php b/module/Formation/src/Formation/Entity/Db/SessionEtatHeurodatage.php
new file mode 100644
index 0000000000000000000000000000000000000000..926245ac0661c47595ba0552f76f1d0b0d8acc6b
--- /dev/null
+++ b/module/Formation/src/Formation/Entity/Db/SessionEtatHeurodatage.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Formation\Entity\Db;
+
+use Application\Entity\Db\Utilisateur;
+use DateTime;
+
+class SessionEtatHeurodatage
+{
+    private ?int $id = -1;
+    private ?Session $session = null;
+    private ?Etat $etat = null;
+    private ?DateTime $heurodatage = null;
+    private ?Utilisateur $utilisateur = null;
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getSession(): ?Session
+    {
+        return $this->session;
+    }
+
+    public function setSession(?Session $session): void
+    {
+        $this->session = $session;
+    }
+
+    public function getEtat(): ?Etat
+    {
+        return $this->etat;
+    }
+
+    public function setEtat(?Etat $etat): void
+    {
+        $this->etat = $etat;
+    }
+
+    public function getHeurodatage(): ?DateTime
+    {
+        return $this->heurodatage;
+    }
+
+    public function setHeurodatage(?DateTime $heurodatage): void
+    {
+        $this->heurodatage = $heurodatage;
+    }
+
+    /**
+     * @return Utilisateur|null
+     */
+    public function getUtilisateur(): ?Utilisateur
+    {
+        return $this->utilisateur;
+    }
+
+    /**
+     * @param Utilisateur|null $utilisateur
+     */
+    public function setUtilisateur(?Utilisateur $utilisateur): void
+    {
+        $this->utilisateur = $utilisateur;
+    }
+
+}
\ No newline at end of file
diff --git a/module/Formation/src/Formation/Service/Exporter/Emargement/emargement.phtml b/module/Formation/src/Formation/Service/Exporter/Emargement/emargement.phtml
index 6bc5f2e5602d06a8998aa36f4043594614e96eb3..fea331b206dc77653f4530e8a18040845f549745 100644
--- a/module/Formation/src/Formation/Service/Exporter/Emargement/emargement.phtml
+++ b/module/Formation/src/Formation/Service/Exporter/Emargement/emargement.phtml
@@ -10,6 +10,7 @@ use Formation\Entity\Db\Inscription;
 use Formation\Entity\Db\Seance;
 
 $session = $seance->getSession();
+$annee = $session->getAnneeScolaire();
 $inscriptions = $session->getListePrincipale();
 usort($inscriptions, function(Inscription $a, Inscription $b) { return $a->getDoctorant()->getIndividu()->getNomComplet() > $b->getDoctorant()->getIndividu()->getNomComplet();});
 
@@ -58,21 +59,26 @@ $formateurs = $session->getFormateurs();
     <?php foreach ($inscriptions as $inscription) : ?>
         <?php
             $theses = $inscription->getDoctorant()->getTheses();
-            $theses = array_filter($theses, function(These $t) { return $t->getEtatThese() === These::ETAT_EN_COURS;});
-            $etablissements = []; $ecoles = []; $unites = [];
-            foreach ($theses as $these) {
+            $theses = array_filter($theses, function(These $t) { return ($t->getEtatThese() === These::ETAT_EN_COURS AND $t->estNonHistorise());});
+            $etablissements = []; $ecoles = []; $unites = []; $anneets = [];
+            /** @var These $these */
+        foreach ($theses as $these) {
                 $etablissement = ($these->getEtablissement())?$these->getEtablissement()->getStructure()->getSigle():"Établissement non renseigné";
                 $etablissements[$etablissement] = $etablissement;
                 $ecole = ($these->getEcoleDoctorale())?$these->getEcoleDoctorale()->getStructure()->getSigle():"École doctorale non renseignée";
                 $ecoles[$ecole] = $ecole;
                 $unite = ($these->getUniteRecherche())?$these->getUniteRecherche()->getStructure()->getSigle():"Unité de recherche non renseignée";
                 $unites[$unite] = $unite;
+                $anneet = $these->getNbInscription($annee);
+                $anneets[$these->getId()] = $anneet;
             }
         ?>
         <tr>
             <td>
                 <strong> <?php echo $inscription->getDoctorant()->getIndividu()->getNomComplet(); ?> </strong>
                 <br/>
+                D<?php echo implode(", ",$anneets); ?>
+                -
                 <?php echo implode(", ",$etablissements); ?>
                 -
                 <?php echo implode(", ",$ecoles); ?>
diff --git a/module/Formation/src/Formation/Service/Session/SessionService.php b/module/Formation/src/Formation/Service/Session/SessionService.php
index 654f125b51853922d0293e7b13001a15e1116246..997192f1f52ef1cafff5cf2260771d9bdc497995 100644
--- a/module/Formation/src/Formation/Service/Session/SessionService.php
+++ b/module/Formation/src/Formation/Service/Session/SessionService.php
@@ -2,13 +2,18 @@
 
 namespace Formation\Service\Session;
 
+use Application\Entity\Db\Utilisateur;
+use Application\Service\UserContextServiceAwareTrait;
+use DateTime;
 use Doctrine\ORM\ORMException;
 use Doctrine\ORM\Query\Expr;
 use Doctrine\ORM\Query\Expr\Join;
+use Formation\Entity\Db\Etat;
 use Formation\Entity\Db\Formation;
 use Formation\Entity\Db\Repository\SessionRepository;
 use Formation\Entity\Db\Seance;
 use Formation\Entity\Db\Session;
+use Formation\Entity\Db\SessionEtatHeurodatage;
 use Formation\Service\Formation\FormationServiceAwareTrait;
 use UnicaenApp\Exception\RuntimeException;
 use UnicaenApp\Service\EntityManagerAwareTrait;
@@ -16,6 +21,7 @@ use UnicaenApp\Service\EntityManagerAwareTrait;
 class SessionService {
     use EntityManagerAwareTrait;
     use FormationServiceAwareTrait;
+    use UserContextServiceAwareTrait;
 
     /**
      * @return SessionRepository
@@ -166,4 +172,25 @@ class SessionService {
 
         return $sessionIds;
     }
+
+    public function addHeurodatage(Session $session, Etat $etat) : SessionEtatHeurodatage
+    {
+
+        $heurodatage = new SessionEtatHeurodatage();
+        $heurodatage->setSession($session);
+        $heurodatage->setEtat($etat);
+        $heurodatage->setHeurodatage(new DateTime());
+        $user = $this->userContextService->getIdentityDb();
+        if ($user === null) $user = $this->getEntityManager()->getRepository(Utilisateur::class)->find(1);
+        $heurodatage->setUtilisateur($user);
+
+        try {
+            $this->getEntityManager()->persist($heurodatage);
+            $this->getEntityManager()->flush($heurodatage);
+        } catch (ORMException $e) {
+            throw new RuntimeException("Une erreur s'est produite en bd.", 0, $e);
+        }
+
+        return $heurodatage;
+    }
 }
\ No newline at end of file
diff --git a/module/Formation/src/Formation/Service/Session/SessionServiceFactory.php b/module/Formation/src/Formation/Service/Session/SessionServiceFactory.php
index b24ddc312dea7d1bc4571b15df9a1fe712693ebf..f2c770e02f33b365e43f4fb4d2a64e35b198e5af 100644
--- a/module/Formation/src/Formation/Service/Session/SessionServiceFactory.php
+++ b/module/Formation/src/Formation/Service/Session/SessionServiceFactory.php
@@ -7,6 +7,7 @@ use Formation\Service\Formation\FormationService;
 use Interop\Container\ContainerInterface;
 use Psr\Container\ContainerExceptionInterface;
 use Psr\Container\NotFoundExceptionInterface;
+use UnicaenAuth\Service\UserContext;
 
 class SessionServiceFactory {
 
@@ -21,13 +22,16 @@ class SessionServiceFactory {
         /**
          * @var EntityManager $entitymanager
          * @var FormationService $formationService
+         * @var UserContext $userService
          */
         $entitymanager = $container->get('doctrine.entitymanager.orm_default');
         $formationService = $container->get(FormationService::class);
+        $userService = $container->get(UserContext::class);
 
         $service = new SessionService();
         $service->setEntityManager($entitymanager);
         $service->setFormationService($formationService);
+        $service->setUserContextService($userService);
         return $service;
     }
 }
\ No newline at end of file
diff --git a/module/Formation/src/Formation/View/Helper/EtatViewHelper.php b/module/Formation/src/Formation/View/Helper/EtatViewHelper.php
index 7f92313787ba02ff146d0214fe6fc13e7c575d4b..4792867f42b010d33df6832c2fa74d93508ad058 100644
--- a/module/Formation/src/Formation/View/Helper/EtatViewHelper.php
+++ b/module/Formation/src/Formation/View/Helper/EtatViewHelper.php
@@ -8,6 +8,7 @@ use Application\View\Renderer\PhpRenderer;
 use Formation\Entity\Db\Interfaces\HasSiteInterface;
 use Formation\Entity\Db\Interfaces\HasTypeInterface;
 use Formation\Entity\Db\Session;
+use Formation\Entity\Db\SessionEtatHeurodatage;
 use Laminas\View\Helper\AbstractHelper;
 use Laminas\View\Helper\Partial;
 use Laminas\View\Resolver\TemplatePathStack;
@@ -15,11 +16,11 @@ use Laminas\View\Resolver\TemplatePathStack;
 class EtatViewHelper extends AbstractHelper
 {
     /**
-     * @param Session|null $object
+     * @param Session|SessionEtatHeurodatage|null $object
      * @param array $options
      * @return string|Partial
      */
-    public function __invoke(?Session $object, array $options = [])
+    public function __invoke($object, array $options = [])
     {
         /** @var PhpRenderer $view */
         $view = $this->getView();
diff --git a/module/Formation/src/Formation/View/Helper/partial/inscription.phtml b/module/Formation/src/Formation/View/Helper/partial/inscription.phtml
index d8c0aea25fc728715e7dc6e6ebff8ea76ebb4651..0dd644a5856bc9e2ce8ceb06b88fc32a4b04c7fa 100644
--- a/module/Formation/src/Formation/View/Helper/partial/inscription.phtml
+++ b/module/Formation/src/Formation/View/Helper/partial/inscription.phtml
@@ -7,7 +7,6 @@
  */
 
 use These\Entity\Db\These;
-use These\Entity\Db\TheseAnneeUniv;
 use Formation\Entity\Db\Inscription;
 
 $actionListePrincipale = (!isset($options['action-liste-principale']) OR $options['action-liste-principale'] !== false);
@@ -17,13 +16,12 @@ $actionSupprimer = (!isset($options['action-supprimer']) OR $options['action-sup
 
 $doctorant = $inscription->getDoctorant();
 $session = $inscription->getSession();
+$annee = $session->getAnneeScolaire();
 //todo trouver solution pour récupèrer la bonne thèse dans le cas des thèses multiples
 
 /** @var These $these */
 $these = current($doctorant->getTheses());
 //todo faire fonction pour le calcul dans l'entité
-$annee = ((int) "2021");
-$inscriptions = array_filter($these->getAnneesUnivInscription()->toArray(), function (TheseAnneeUniv $a) use ($annee) { return $a->getAnneeUniv() <= $annee; });
 
 ?>
 
@@ -33,7 +31,7 @@ $inscriptions = array_filter($these->getAnneesUnivInscription()->toArray(), func
     echo $doctorant->getIndividu()->getNomComplet(); ?>
     <span class=" <?php if ($inscription->estHistorise()) echo "historisee"; ?> " title="<?php echo $inscription->getDescription(); ?>">
     <?php foreach ($doctorant->getTheses() as $these) {
-        if ($these->getEtatThese() === These::ETAT_EN_COURS) {
+        if ($these->getEtatThese() === These::ETAT_EN_COURS AND $these->estNonHistorise()) {
             echo "<br/>";
             echo $this->site($these->getEtablissement());
             echo " - ";
@@ -41,7 +39,7 @@ $inscriptions = array_filter($these->getAnneesUnivInscription()->toArray(), func
             echo " - ";
             echo $this->site($these->getUniteRecherche());
             echo " - ";
-            echo "D" . count($inscriptions);
+            echo "D" . $these->getNbInscription($annee);
         }
     }
     ?>
diff --git a/module/Formation/view/formation/session/afficher.phtml b/module/Formation/view/formation/session/afficher.phtml
index 4dc3c6ed648310d7df01c32ea5bdc2ce3a1efe6d..219c0b4cb00264e1a49ef90fa262a00af747c1f0 100644
--- a/module/Formation/view/formation/session/afficher.phtml
+++ b/module/Formation/view/formation/session/afficher.phtml
@@ -111,61 +111,76 @@ echo $this->messenger()->addMessagesFromFlashMessengerWithNoNamespace();
 <?php endif; ?>
 
 <h2> Informations sur la session de formation </h2>
-
-<div class="index-result">
-<dl class="row">
-    <dt class="col-md-3"> Module </dt>
-    <dd class="col-md-9">
-        <?php if ($module !== null) : ?>
-            <?php if ($canAfficherModule) : ?>
-                <a href="<?php echo $this->url('formation/module/afficher', ['module' => $module->getId()], [], true); ?>">
-                    <?php echo $module->getLibelle(); ?></a>
+<div class="row">
+    <div class="col-md-7">
+        <div class="index-result">
+    <dl class="row">
+        <dt class="col-md-3"> Module </dt>
+        <dd class="col-md-9">
+            <?php if ($module !== null) : ?>
+                <?php if ($canAfficherModule) : ?>
+                    <a href="<?php echo $this->url('formation/module/afficher', ['module' => $module->getId()], [], true); ?>">
+                        <?php echo $module->getLibelle(); ?></a>
+                <?php else : ?>
+                    <?php echo $module->getLibelle(); ?>
+                <?php endif; ?>
             <?php else : ?>
-                <?php echo $module->getLibelle(); ?>
+                <i> Aucun module associé à la formation</i>
             <?php endif; ?>
-        <?php else : ?>
-            <i> Aucun module associé à la formation</i>
-        <?php endif; ?>
-    </dd>
-    <dt class="col-md-3"> Formation </dt>
-    <dd class="col-md-9">
-        <?php if ($canAfficherFormation) : ?>
-            <a href="<?php echo $this->url('formation/formation/afficher', ['formation' => $formation->getId()], [], true); ?>">
-                <?php echo $formation->getLibelle(); ?></a>
-        <?php else : ?>
-            <?php echo $formation->getLibelle(); ?>
-        <?php endif; ?>
-    </dd>
-    <?php if ($session->getDescription() !== null) : ?>
-        <dt class="col-md-3"> Description </dt>
-        <dd class="col-md-9"> <?php echo $session->getDescription(); ?> </dd>
-    <?php endif; ?>
-    <dt class="col-md-3"> Code </dt>
-    <dd class="col-md-9"> <code><?php echo $session->getCode(); ?></code></dd>
-    <dt class="col-md-3"> État </dt>
-    <dd class="col-md-9"> <?php echo $this->etat($session); ?> </dd>
-    <dt class="col-md-3"> Site organisateur </dt>
-    <dd class="col-md-9"> <?php echo $this->site($session); ?> </dd>
-    <dt class="col-md-3"> Responsable </dt>
-    <dd class="col-md-9">
-        <?php if ($session->getResponsable()) : ?>
-            <?php echo $session->getResponsable()->getNomComplet(); ?>
-        <?php else : ?>
-            Aucun responsable
+        </dd>
+        <dt class="col-md-3"> Formation </dt>
+        <dd class="col-md-9">
+            <?php if ($canAfficherFormation) : ?>
+                <a href="<?php echo $this->url('formation/formation/afficher', ['formation' => $formation->getId()], [], true); ?>">
+                    <?php echo $formation->getLibelle(); ?></a>
+            <?php else : ?>
+                <?php echo $formation->getLibelle(); ?>
+            <?php endif; ?>
+        </dd>
+        <?php if ($session->getDescription() !== null) : ?>
+            <dt class="col-md-3"> Description </dt>
+            <dd class="col-md-9"> <?php echo $session->getDescription(); ?> </dd>
         <?php endif; ?>
-    </dd>
-    <dt class="col-md-3"> Modalité </dt>
-    <dd class="col-md-9"> <?php echo $this->modalite($session); ?> </dd>
-    <dt class="col-md-3"> Type </dt>
-    <dd class="col-md-9"> <?php echo $this->type($session); ?> </dd>
-
-    <dt class="col-md-3"> Liste principale </dt>
-    <dd class="col-md-9"> <?php echo count($listePrincipaleTrue); ?>/<?php echo $session->getTailleListePrincipale(); ?></dd>
-    <dt class="col-md-3"> Liste complémentaire </dt>
-    <dd class="col-md-9"> <?php echo count($listeComplementaireTrue); ?>/<?php echo $session->getTailleListeComplementaire(); ?></dd>
-    <dt class="col-md-3"> Nombre d'inscription </dt>
-    <dd class="col-md-9"> <?php echo count($inscrits); ?></dd>
-</dl>
+        <dt class="col-md-3"> Code </dt>
+        <dd class="col-md-9"> <code><?php echo $session->getCode(); ?></code></dd>
+        <dt class="col-md-3"> État </dt>
+        <dd class="col-md-9"> <?php echo $this->etat($session); ?> </dd>
+        <dt class="col-md-3"> Site organisateur </dt>
+        <dd class="col-md-9"> <?php echo $this->site($session); ?> </dd>
+        <dt class="col-md-3"> Responsable </dt>
+        <dd class="col-md-9">
+            <?php if ($session->getResponsable()) : ?>
+                <?php echo $session->getResponsable()->getNomComplet(); ?>
+            <?php else : ?>
+                Aucun responsable
+            <?php endif; ?>
+        </dd>
+        <dt class="col-md-3"> Modalité </dt>
+        <dd class="col-md-9"> <?php echo $this->modalite($session); ?> </dd>
+        <dt class="col-md-3"> Type </dt>
+        <dd class="col-md-9"> <?php echo $this->type($session); ?> </dd>
+
+        <dt class="col-md-3"> Liste principale </dt>
+        <dd class="col-md-9"> <?php echo count($listePrincipaleTrue); ?>/<?php echo $session->getTailleListePrincipale(); ?></dd>
+        <dt class="col-md-3"> Liste complémentaire </dt>
+        <dd class="col-md-9"> <?php echo count($listeComplementaireTrue); ?>/<?php echo $session->getTailleListeComplementaire(); ?></dd>
+        <dt class="col-md-3"> Nombre d'inscription </dt>
+        <dd class="col-md-9"> <?php echo count($inscrits); ?></dd>
+    </dl>
+    </div>
+    </div>
+    <div class="col-md-5">
+        <h3>Heurodatage</h3>
+        <?php $heurodatages = $session->getHeurodatages(); ?>
+        <?php foreach ($heurodatages as $heurodatage) : ?>
+            <?php echo $this->etat($heurodatage); ?>
+            &nbsp;
+            <?php echo $heurodatage->getHeurodatage()->format('d/m/Y à H:i'); ?>
+            par
+            <?php echo $heurodatage->getUtilisateur()->getDisplayName(); ?>
+        <br/>
+        <?php endforeach; ?>
+    </div>
 </div>
 
 <div class="row">
@@ -463,9 +478,9 @@ echo $this->messenger()->addMessagesFromFlashMessengerWithNoNamespace();
     </div>
 </div>
 
-    <h2> Présences aux scéances</h2>
+    <h2> Présences aux séances</h2>
 
-    <?php if ($session->getEtat()->getCode() !== Etat::CODE_FERME AND $session->getEtat()->getCode() !== Etat::CODE_CLOTURER) : ?>
+    <?php if ($session->getEtat()->getCode() !== Etat::CODE_IMMINENT AND $session->getEtat()->getCode() !== Etat::CODE_FERME AND $session->getEtat()->getCode() !== Etat::CODE_CLOTURER) : ?>
         <em> Les présences ne peuvent pas encore être renseignées.</em>
     <?php else : ?>
         <?php echo $this->partial('formation/presence/renseigner-presences', ['session' => $session, 'presences' => $presences, 'titre' => false], [], true); ?>
diff --git a/module/Soutenance/config/others/avis.config.php b/module/Soutenance/config/others/avis.config.php
index 253d57d990bb8b557d1beebcd051397e1052901b..ed1f3bd9407c2da560e09d2b046117782f9515a9 100644
--- a/module/Soutenance/config/others/avis.config.php
+++ b/module/Soutenance/config/others/avis.config.php
@@ -56,6 +56,13 @@ return array(
                     ],
                     'privileges' => AvisSoutenancePrivileges::AVIS_ANNULER,
                 ],
+                [
+                    'controller' => AvisController::class,
+                    'action' => [
+                        'telecharger',
+                    ],
+                    'roles' => [],
+                ],
             ],
         ],
     ],
@@ -97,6 +104,17 @@ return array(
                                     ],
                                 ],
                             ],
+                            'telecharger' => [
+                                'type' => Literal::class,
+                                'may_terminate' => true,
+                                'options' => [
+                                    'route' => '/telecharger',
+                                    'defaults' => [
+                                        'controller' => AvisController::class,
+                                        'action' => 'telecharger',
+                                    ],
+                                ],
+                            ],
                         ],
                     ],
                 ],
diff --git a/module/Soutenance/src/Soutenance/Controller/AvisController.php b/module/Soutenance/src/Soutenance/Controller/AvisController.php
index 4fada20610dc89153d83986286143af1e85e4e9d..124f7db5439752e08d2a58b0017ceada98fa9077 100644
--- a/module/Soutenance/src/Soutenance/Controller/AvisController.php
+++ b/module/Soutenance/src/Soutenance/Controller/AvisController.php
@@ -3,6 +3,9 @@
 namespace Soutenance\Controller;
 
 use Application\Controller\AbstractController;
+use Fichier\Service\Fichier\FichierServiceAwareTrait;
+use Fichier\Service\Fichier\FichierStorageServiceAwareTrait;
+use Fichier\Service\Storage\Adapter\Exception\StorageAdapterException;
 use These\Service\Acteur\ActeurServiceAwareTrait;
 use These\Service\These\TheseServiceAwareTrait;
 use Soutenance\Entity\Avis;
@@ -16,6 +19,7 @@ use Soutenance\Service\Proposition\PropositionServiceAwareTrait;
 use Soutenance\Service\Validation\ValidatationServiceAwareTrait;
 use Laminas\Http\Request;
 use Laminas\View\Model\ViewModel;
+use UnicaenApp\Exception\RuntimeException;
 
 class AvisController extends AbstractController
 {
@@ -27,6 +31,9 @@ class AvisController extends AbstractController
     use TheseServiceAwareTrait;
     use ValidatationServiceAwareTrait;
 
+    use FichierStorageServiceAwareTrait;
+    use FichierServiceAwareTrait;
+
     use AvisFormAwareTrait;
 
     public function indexAction()
@@ -133,4 +140,22 @@ class AvisController extends AbstractController
         $this->redirect()->toRoute('soutenance/index-rapporteur', ['these' => $these->getId()], [], true);
     }
 
+
+    public function telechargerAction()
+    {
+        $these = $this->requestedThese();
+        $membre = $this->getMembreService()->getRequestedMembre($this, 'rapporteur');
+        $avis = $this->getAvisService()->getAvisByMembre($membre);
+        $fichier = $avis->getFichier();
+
+        // injection préalable du contenu du fichier pour pouvoir utiliser le plugin Uploader
+        try {
+            $contenuFichier = $this->fichierStorageService->getFileContentForFichier($fichier);
+        } catch (StorageAdapterException $e) {
+            throw new RuntimeException("Impossible d'obtenir le contenu du fichier", null, $e);
+        }
+        $fichier->setContenuFichierData($contenuFichier);
+
+        $this->uploader()->download($fichier);
+    }
 }
\ No newline at end of file
diff --git a/module/Soutenance/src/Soutenance/Controller/AvisControllerFactory.php b/module/Soutenance/src/Soutenance/Controller/AvisControllerFactory.php
index e58cbf1eeb602d7dd133f3045e4f67bfe9c0455f..4c353974962fa7f54a78bde88ede595ac56051e1 100644
--- a/module/Soutenance/src/Soutenance/Controller/AvisControllerFactory.php
+++ b/module/Soutenance/src/Soutenance/Controller/AvisControllerFactory.php
@@ -2,6 +2,10 @@
 
 namespace Soutenance\Controller;
 
+use Fichier\Service\Fichier\FichierService;
+use Fichier\Service\Fichier\FichierStorageService;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\NotFoundExceptionInterface;
 use These\Service\Acteur\ActeurService;
 use These\Service\These\TheseService;
 use Interop\Container\ContainerInterface;
@@ -17,8 +21,10 @@ class AvisControllerFactory
     /**
      * @param ContainerInterface $container
      * @return AvisController
+     * @throws ContainerExceptionInterface
+     * @throws NotFoundExceptionInterface
      */
-    public function __invoke(ContainerInterface $container)
+    public function __invoke(ContainerInterface $container) : AvisController
     {
 
         /**
@@ -38,12 +44,17 @@ class AvisControllerFactory
         $theseService               = $container->get('TheseService');
         $validationService          = $container->get(ValidationService::class);
 
+        /** @var FichierService $fichierService */
+        $fichierService = $container->get(FichierService::class);
+
+        /** @var FichierStorageService $fileService */
+        $fileService = $container->get(FichierStorageService::class);
+
         /**
          * @var AvisForm $avisForm
          */
         $avisForm = $container->get('FormElementManager')->get(AvisForm::class);
 
-        /** @var AvisController $controller */
         $controller = new AvisController();
         $controller->setTheseService($theseService);
         $controller->setValidationService($validationService);
@@ -53,6 +64,9 @@ class AvisControllerFactory
         $controller->setAvisService($avisService);
         $controller->setMembreService($membreService);
 
+        $controller->setFichierService($fichierService);
+        $controller->setFichierStorageService($fileService);
+
         $controller->setAvisForm($avisForm);
 
         return $controller;
diff --git a/module/Soutenance/src/Soutenance/Controller/EngagementImpartialiteController.php b/module/Soutenance/src/Soutenance/Controller/EngagementImpartialiteController.php
index e9b233e8872348127d5786f4862264a1cc09eebc..07337efd36240652fdb062fb6d01340cae28ff76 100644
--- a/module/Soutenance/src/Soutenance/Controller/EngagementImpartialiteController.php
+++ b/module/Soutenance/src/Soutenance/Controller/EngagementImpartialiteController.php
@@ -4,6 +4,7 @@ namespace Soutenance\Controller;
 
 use Application\Controller\AbstractController;
 use Application\Entity\Db\Validation;
+use Soutenance\Provider\Template\TexteTemplates;
 use These\Service\Acteur\ActeurServiceAwareTrait;
 use Soutenance\Entity\Evenement;
 use Soutenance\Entity\Membre;
@@ -14,6 +15,7 @@ use Soutenance\Service\Notifier\NotifierSoutenanceServiceAwareTrait;
 use Soutenance\Service\Proposition\PropositionServiceAwareTrait;
 use UnicaenAuthToken\Service\TokenServiceAwareTrait;
 use Laminas\View\Model\ViewModel;
+use UnicaenRenderer\Service\Rendu\RenduServiceAwareTrait;
 
 /**
  * Class SoutenanceController
@@ -28,6 +30,7 @@ class EngagementImpartialiteController extends AbstractController
     use MembreServiceAwareTrait;
     use NotifierSoutenanceServiceAwareTrait;
     use PropositionServiceAwareTrait;
+    use RenduServiceAwareTrait;
     use TokenServiceAwareTrait;
 
     public function engagementImpartialiteAction() : ViewModel
@@ -36,6 +39,9 @@ class EngagementImpartialiteController extends AbstractController
         $proposition = $this->getPropositionService()->findOneForThese($these);
         $membre = $this->getMembreService()->getRequestedMembre($this);
 
+        $vars = [ 'membre' => $membre, 'doctorant' => $these->getDoctorant() ];
+        $texteEngagnement = $this->getRenduService()->generateRenduByTemplateCode(TexteTemplates::SOUTENANCE_ENGAGEMENT_IMPARTIALITE, $vars);
+
         /** @var Validation $validation */
         $validation = $this->getEngagementImpartialiteService()->getEngagementImpartialiteByMembre($these, $membre);
         if ($validation === null) $validation = $this->getEngagementImpartialiteService()->getRefusEngagementImpartialiteByMembre($these, $membre);
@@ -49,6 +55,8 @@ class EngagementImpartialiteController extends AbstractController
             'urlSigner' => $this->url()->fromRoute('soutenance/engagement-impartialite/signer', ['these' => $these->getId(), 'membre' => $membre->getId()], [], true),
             'urlRefuser' => $this->url()->fromRoute('soutenance/engagement-impartialite/refuser', ['these' => $these->getId(), 'membre' => $membre->getId()], [], true),
             'urlAnnuler' => $this->url()->fromRoute('soutenance/engagement-impartialite/annuler', ['these' => $these->getId(), 'membre' => $membre->getId()], [], true),
+
+            'texteEngagement' => $texteEngagnement,
         ]);
     }
 
diff --git a/module/Soutenance/src/Soutenance/Controller/EngagementImpartialiteControllerFactory.php b/module/Soutenance/src/Soutenance/Controller/EngagementImpartialiteControllerFactory.php
index a8138b8068bc59dd7f9f0a615b88340673386f8a..29952574b5945f550ffbaac1e8be006953169a35 100644
--- a/module/Soutenance/src/Soutenance/Controller/EngagementImpartialiteControllerFactory.php
+++ b/module/Soutenance/src/Soutenance/Controller/EngagementImpartialiteControllerFactory.php
@@ -2,6 +2,8 @@
 
 namespace Soutenance\Controller;
 
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\NotFoundExceptionInterface;
 use These\Service\Acteur\ActeurService;
 use Interop\Container\ContainerInterface;
 use Soutenance\Service\EngagementImpartialite\EngagementImpartialiteService;
@@ -11,14 +13,17 @@ use Soutenance\Service\Notifier\NotifierSoutenanceService;
 use Soutenance\Service\Proposition\PropositionService;
 use UnicaenAuthToken\Service\TokenService;
 use UnicaenAuthToken\Service\TokenServiceAwareTrait;
+use UnicaenRenderer\Service\Rendu\RenduService;
 
 class EngagementImpartialiteControllerFactory
 {
     /**
      * @param ContainerInterface $container
      * @return EngagementImpartialiteController
+     * @throws ContainerExceptionInterface
+     * @throws NotFoundExceptionInterface
      */
-    public function __invoke(ContainerInterface $container)
+    public function __invoke(ContainerInterface $container) : EngagementImpartialiteController
     {
         /**
          * @var ActeurService $acteurService
@@ -27,6 +32,7 @@ class EngagementImpartialiteControllerFactory
          * @var MembreService $membreService
          * @var NotifierSoutenanceService $notifierService
          * @var EngagementImpartialiteService $engagementImpartialiteService
+         * @var RenduService $renduService
          * @var TokenService $tokenService
          */
         $acteurService                  = $container->get(ActeurService::class);
@@ -35,9 +41,9 @@ class EngagementImpartialiteControllerFactory
         $membreService                  = $container->get(MembreService::class);
         $notifierService                = $container->get(NotifierSoutenanceService::class);
         $engagementImpartialiteService  = $container->get(EngagementImpartialiteService::class);
+        $renduService                   = $container->get(RenduService::class);
         $tokenService                   = $container->get(TokenService::class);
 
-        /** @var EngagementImpartialiteController $controller */
         $controller = new EngagementImpartialiteController();
         $controller->setActeurService($acteurService);
         $controller->setEvenementService($evenementService);
@@ -45,6 +51,7 @@ class EngagementImpartialiteControllerFactory
         $controller->setMembreService($membreService);
         $controller->setNotifierSoutenanceService($notifierService);
         $controller->setEngagementImpartialiteService($engagementImpartialiteService);
+        $controller->setRenduService($renduService);
         $controller->setTokenService($tokenService);
 
         return $controller;
diff --git a/module/Soutenance/src/Soutenance/Controller/PresoutenanceController.php b/module/Soutenance/src/Soutenance/Controller/PresoutenanceController.php
index 504136180e83ca7142a3c3ded119cf30ce5fe099..e514b43784523020a63fd8b7f19a8d077bb0e96c 100644
--- a/module/Soutenance/src/Soutenance/Controller/PresoutenanceController.php
+++ b/module/Soutenance/src/Soutenance/Controller/PresoutenanceController.php
@@ -593,13 +593,19 @@ class PresoutenanceController extends AbstractController
         foreach ($proposition->getAvis() as $avis) {
             if ($avis->estNonHistorise()) {
                 $denomination = $avis->getMembre()->getDenomination();
-                $lien = $this->url()->fromRoute('fichier/these/telecharger', [
-                    'these'      => $these->getId(),
-                    'fichier'    => $avis->getFichier()->getUuid(),
-                    'fichierNom' => $avis->getFichier()->getNom(),
-                ], [
-                    'force_canonical'=>true
-                ],true);
+//                $lien = $this->url()->fromRoute('fichier/these/telecharger', [
+//                    'these'      => $these->getId(),
+//                    'fichier'    => $avis->getFichier()->getUuid(),
+//                    'fichierNom' => $avis->getFichier()->getNom(),
+//                ], [
+//                    'force_canonical'=>true
+//                ],true);
+                $lien = $this->url()->fromRoute('soutenance/avis-soutenance/telecharger', [
+                    'these' => $these->getId(),
+                    'membre' => $avis->getMembre()->getId()
+                    ], [
+                        'force_canonical'=>true
+                    ], true);
                 $avisArray[$denomination] = $lien;
             }
         }
diff --git a/module/Soutenance/src/Soutenance/Entity/Membre.php b/module/Soutenance/src/Soutenance/Entity/Membre.php
index c28cb5458ef7af8a59e2feaa4f0852d427517bef..4219e32eece04879c315b5d46641e88dd2a42094 100644
--- a/module/Soutenance/src/Soutenance/Entity/Membre.php
+++ b/module/Soutenance/src/Soutenance/Entity/Membre.php
@@ -95,7 +95,7 @@ class Membre implements HistoriqueAwareInterface {
      */
     public function getDenomination()
     {
-        return $this->prenom." ".$this->getNom();
+        return (($this->getGenre()==='F')?"Mme":"M").' '.$this->prenom." ".strtoupper($this->getNom());
     }
 
     /**
diff --git a/module/Soutenance/src/Soutenance/Provider/Template/TexteTemplates.php b/module/Soutenance/src/Soutenance/Provider/Template/TexteTemplates.php
new file mode 100644
index 0000000000000000000000000000000000000000..9829774639c73f6d30aa354fc07cdb54cad7a250
--- /dev/null
+++ b/module/Soutenance/src/Soutenance/Provider/Template/TexteTemplates.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Soutenance\Provider\Template;
+
+class TexteTemplates {
+
+    const SOUTENANCE_ENGAGEMENT_IMPARTIALITE = 'SOUTENANCE_ENGAGEMENT_IMPARTIALITE';
+}
\ No newline at end of file
diff --git a/module/Soutenance/view/soutenance/engagement-impartialite/engagement-impartialite.phtml b/module/Soutenance/view/soutenance/engagement-impartialite/engagement-impartialite.phtml
index 3e860ea77fb125f5e571f025a968f7771e83aa6b..95883caf7f5a0d2b700ebac5997dd22987c95ed2 100644
--- a/module/Soutenance/view/soutenance/engagement-impartialite/engagement-impartialite.phtml
+++ b/module/Soutenance/view/soutenance/engagement-impartialite/engagement-impartialite.phtml
@@ -10,6 +10,7 @@
  * @var string $urlSigner
  * @var string $urlRefuser
  * @var string $urlAnnuler
+ * @var Rendu $texteEngagement
  */
 
 use These\Entity\Db\Acteur;
@@ -19,6 +20,7 @@ use Application\Entity\Db\Validation;
 use Soutenance\Entity\Membre;
 use Soutenance\Entity\Proposition;
 use Soutenance\Provider\Privilege\EngagementImpartialitePrivileges;
+use UnicaenRenderer\Entity\Db\Rendu;
 
 /**
  * La validation CODE_ENGAGEMENT_IMPARTIALITE fait office de signature électronique de l'engagement d'impartilité. Par
@@ -74,19 +76,9 @@ $this->headTitle("Engagement d'impartialité portant sur la thèse de ".$doctora
     </div>
 </div>
 
-<p>
-    En signant cet engagment d'impartialité, je, sous-signé <strong><?php echo $membre->getIndividu(); ?></strong>,
-    atteste ne pas avoir de liens d'intérêt, qu'ils soient de nature professionnelle, familiale, personnelle ou patrimoniale
-    avec le doctorant ou son directeur de thèse, ne pas avoir pris part aux travaux de la thèse et ne pas avoir de publication
-    cosignée avec le doctorant dans les cinq dernières années et ne pas avoir participé au comité de suivi de la thèse de
-    <?php echo $these->getDoctorant()->getIndividu(); ?>.
-</p>
-    By signing, I certify that I have no personal or family connection with the doctoral student or his/her PhD supervisor
-    and that I have not taken part in the work of the thesis and not co-authored  publications with the doctoral student for
-    the last five years.
-    <p>
+<?php echo $texteEngagement->getCorps(); ?>
+
 
-</p>
 <div class="row">
     <div class="col-md-4">
     <?php if ($validation): ?>
diff --git a/module/Structure/src/Structure/Entity/Db/Structure.php b/module/Structure/src/Structure/Entity/Db/Structure.php
index 6f0ad50e0112db82014a9887cbb0bb06ef7bae8c..445b06c106bff031ab9e00936ee929daa6e708a1 100644
--- a/module/Structure/src/Structure/Entity/Db/Structure.php
+++ b/module/Structure/src/Structure/Entity/Db/Structure.php
@@ -157,6 +157,12 @@ class Structure implements StructureInterface, HistoriqueAwareInterface, SourceA
         return count($this->getStructuresSubstituees()) > 0;
     }
 
+    public function estSubstituee() : bool
+    {
+        return $this->getStructureSubstituante() !== null;
+    }
+
+
     /**
      * @return string
      */
diff --git a/module/Structure/view/structure/ecole-doctorale/modifier.phtml b/module/Structure/view/structure/ecole-doctorale/modifier.phtml
index 9fe418fb6bc3a45f300c21f423119ca001eef965..1935bdedf4d519877e73bdb5393bbb7cdbb119fa 100644
--- a/module/Structure/view/structure/ecole-doctorale/modifier.phtml
+++ b/module/Structure/view/structure/ecole-doctorale/modifier.phtml
@@ -19,13 +19,14 @@ use Application\View\Renderer\PhpRenderer;
 /** @var EcoleDoctorale $ecole */
 $ecole = $form->getObject();
 $isNew = $ecole->getId() === null;
-$estSubstituante = $ecole->getStructure()->estStructureSubstituante();
+$estSubstituee = $ecole->getStructure()->estSubstituee();
+$estModifiable = !($ecole->getSource()->getImportable());
 $fcg = $this->formControlGroup();
 $this->headTitle("Modification de l'école doctorale ".$ecole->getStructure()->getCode());
 
-$editable = $isNew || $estSubstituante;
-//$form->get('libelle')->setAttribute('readonly', !$editable);
-//$form->get('sigle')->setAttribute('readonly', !$editable);
+$editable = $isNew || (!$estSubstituee AND $estModifiable);
+$form->get('libelle')->setAttribute('readonly', !$editable);
+$form->get('sigle')->setAttribute('readonly', !$editable);
 $form->get('code')->setAttribute('readonly', !$editable);
 ?>
 
@@ -37,6 +38,27 @@ $form->get('code')->setAttribute('readonly', !$editable);
     <?php endif ?>
 </h1>
 
+<?php if (!$editable) : ?>
+<div class="alert alert-warning">
+        <p>
+        <?php if (!$estModifiable) : ?>
+            <span class="icon icon-attention"></span>
+            <strong>La source (<?php echo $ecole->getSource()->getLibelle(); ?>) ne permet pas de modification.</strong>
+            <br/>
+        <?php endif; ?>
+        <?php if ($estSubstituee) : ?>
+            <span class="icon icon-attention"></span>
+            <strong>La structure est substituée et ne doit pas être modifiée.</strong>
+            <br/>
+        <?php endif; ?>
+        </p>
+
+    <p>
+        Par conséquent, vous ne pouvez pas modifier les champs : libellé, sigle et code.
+    </p>
+</div>
+<?php endif; ?>
+
 <?php echo $this->form()->openTag($form->prepare()->setAttribute('class', 'ecole-doctorale')) ?>
 <div class="row">
 
diff --git a/module/Structure/view/structure/etablissement/modifier.phtml b/module/Structure/view/structure/etablissement/modifier.phtml
index dc22683aa641be0bc26386b14ee4bc1d2f7e02bb..fd31f0eeeee40325262e747aeeafd334d47153e2 100644
--- a/module/Structure/view/structure/etablissement/modifier.phtml
+++ b/module/Structure/view/structure/etablissement/modifier.phtml
@@ -1,6 +1,7 @@
 <?php
 
 use Structure\Controller\EtablissementController;
+use Structure\Entity\Db\Etablissement;
 use Structure\Form\EtablissementForm;
 use Application\View\Renderer\PhpRenderer;
 
@@ -16,8 +17,43 @@ use Application\View\Renderer\PhpRenderer;
  */
 
 $fcg = $this->formControlGroup();
+
+
+/** @var Etablissement $etablissement */
+$etablissement = $form->getObject();
+$idEtablissement = $etablissement->getStructure()->getId();
+$isNew = $etablissement->getId() === null;
+$estSubstituee = $etablissement->getStructure()->estSubstituee();
+$estModifiable = !($etablissement->getSource()->getImportable());
+$fcg = $this->formControlGroup();
+
+$editable = $isNew || (!$estSubstituee AND $estModifiable);
+$form->get('libelle')->setAttribute('readonly', !$editable);
+$form->get('sigle')->setAttribute('readonly', !$editable);
+$form->get('code')->setAttribute('readonly', !$editable);
 ?>
 
+<?php if (!$editable) : ?>
+    <div class="alert alert-warning">
+        <p>
+            <?php if (!$estModifiable) : ?>
+                <span class="icon icon-attention"></span>
+                <strong>La source (<?php echo $etablissement->getSource()->getLibelle(); ?>) ne permet pas de modification.</strong>
+                <br/>
+            <?php endif; ?>
+            <?php if ($estSubstituee) : ?>
+                <span class="icon icon-attention"></span>
+                <strong>La structure est substituée et ne doit pas être modifiée.</strong>
+                <br/>
+            <?php endif; ?>
+        </p>
+
+        <p>
+            Par conséquent, vous ne pouvez pas modifier les champs : libellé, sigle et code.
+        </p>
+    </div>
+<?php endif; ?>
+
 <?php echo $this->form()->openTag($form->prepare()->setAttribute('class', 'etablissement')) ?>
 
 <div class="row">
diff --git a/module/Structure/view/structure/unite-recherche/modifier.phtml b/module/Structure/view/structure/unite-recherche/modifier.phtml
index 64fb8e5a9a9b318c67f1a25ba50c5835f18c81ee..24f480917ec7a9ff51f9b535d7c8641e3c753ddc 100644
--- a/module/Structure/view/structure/unite-recherche/modifier.phtml
+++ b/module/Structure/view/structure/unite-recherche/modifier.phtml
@@ -27,13 +27,14 @@ use Application\View\Renderer\PhpRenderer;
 $unite = $form->getObject();
 $idUniteRecherche = $unite->getStructure()->getId();
 $isNew = $unite->getId() === null;
-$estSubstituante = $unite->getStructure()->estStructureSubstituante();
+$estSubstituee = $unite->getStructure()->estSubstituee();
+$estModifiable = !($unite->getSource()->getImportable());
 $fcg = $this->formControlGroup();
 $this->headTitle("Modification de l'UR " . $unite->getStructure()->getCode());
 
-$editable = $isNew || $estSubstituante;
-//$form->get('libelle')->setAttribute('readonly', !$editable);
-//$form->get('sigle')->setAttribute('readonly', !$editable);
+$editable = $isNew || (!$estSubstituee AND $estModifiable);
+$form->get('libelle')->setAttribute('readonly', !$editable);
+$form->get('sigle')->setAttribute('readonly', !$editable);
 $form->get('code')->setAttribute('readonly', !$editable);
 ?>
 
@@ -47,6 +48,27 @@ $form->get('code')->setAttribute('readonly', !$editable);
 
 <?php echo $this->messenger()->addMessagesFromFlashMessengerWithNoNamespace(); ?>
 
+<?php if (!$editable) : ?>
+    <div class="alert alert-warning">
+        <p>
+            <?php if (!$estModifiable) : ?>
+                <span class="icon icon-attention"></span>
+                <strong>La source (<?php echo $unite->getSource()->getLibelle(); ?>) ne permet pas de modification.</strong>
+                <br/>
+            <?php endif; ?>
+            <?php if ($estSubstituee) : ?>
+                <span class="icon icon-attention"></span>
+                <strong>La structure est substituée et ne doit pas être modifiée.</strong>
+                <br/>
+            <?php endif; ?>
+        </p>
+
+        <p>
+            Par conséquent, vous ne pouvez pas modifier les champs : libellé, sigle et code.
+        </p>
+    </div>
+<?php endif; ?>
+
 <!-- BLOC DES INFORMATIONS GENERALES ---------------------------------------------------------------------------------->
 
 <h2> Informations générales </h2>
diff --git a/module/These/src/These/Entity/Db/These.php b/module/These/src/These/Entity/Db/These.php
index aaba8cc15995baaf47e7f2f113428aa0f72472d0..cc09bc92242a809e43a798f726f5f2a4611d968d 100644
--- a/module/These/src/These/Entity/Db/These.php
+++ b/module/These/src/These/Entity/Db/These.php
@@ -1851,4 +1851,17 @@ class These implements HistoriqueAwareInterface, ResourceInterface
         return null;
     }
 
+    public static function getAnneeScolaireCourante() : int {
+        $mois = ((int) (new DateTime())->format('m'));
+        $annee = ((int) (new DateTime())->format('Y'));
+        if ($mois > 8) $annee += 1;
+        return $annee;
+    }
+
+    public function getNbInscription(?int $annee = null) : int
+    {
+        if ($annee === null) $annee = These::getAnneeScolaireCourante();
+        $inscriptions = array_filter($this->getAnneesUnivInscription()->toArray(), function (TheseAnneeUniv $a) use ($annee) { return ($a->estNonHistorise() AND $a->getAnneeUniv() <= $annee); });
+        return count($inscriptions);
+    }
 }
diff --git a/module/These/view/these/these/depot.phtml b/module/These/view/these/these/depot.phtml
index d85f1384967eaed13be565c8f02eb8c0f4d40940..2654573ce31cfa9728f461618904062c58f614da 100644
--- a/module/These/view/these/these/depot.phtml
+++ b/module/These/view/these/these/depot.phtml
@@ -20,7 +20,7 @@ $maxFileCountThese = 1;
 $maxFileCountAutres = 50;
 
 $divId = $versionCorrigee ? 'div-depot-corrige' : 'div-depot-initial';
-$h1 = $versionCorrigee ? "Dépôt version corrigée" : "Dépôt de la thèse";
+$h1 = $versionCorrigee ? "Téléversement version corrigée" : "Téléversement de la thèse";
 ?>
 
 <?php $this->headTitle("Dépôt thèse")->prepend($these->getDoctorant()->getIndividu()->getNomUsuel()) ?>
diff --git a/public/js/app.js b/public/js/app.js
index d6af73fd5a1db44dedbc4c362336365bedd4e9f4..0d100ecd0312fc60793bfc15b635e508b863d896 100755
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -211,8 +211,8 @@ $.widget("unicaen.widgetDroitAuteurThese", {
                 this.getAnnexesDiv().refresh({}, function () {
                     $(this).show();
                 });
-                this.getTheseDiv().show(effect, {direction: "left"}).find(':input').removeProp('disabled');
-                this.getAnnexesDiv().show(effect, {direction: "left"}).find(':input').removeProp('disabled');
+                this.getTheseDiv().show(effect, {direction: "left"}).find(':input').prop('disabled', false);
+                this.getAnnexesDiv().show(effect, {direction: "left"}).find(':input').prop('disabled', false);
                 break;
             default:
                 this.getDivFichiersExpurges().hide();
@@ -270,22 +270,22 @@ $.widget("unicaen.widgetAutorisationMiseEnLigne", {
             case "2": // oui immédiatement
                 this.getInputDivEmbargoDuree().hide(effect, {direction: "left"}).find(':input').prop('disabled', 'disabled');
                 this.getInputDivMotif().hide(effect, {direction: "up"}).find(':input').prop('disabled', 'disabled');
-                this.getInputDivAuteur().show(effect, {direction: "up"}).find(':input').removeProp('disabled');
+                this.getInputDivAuteur().show(effect, {direction: "up"}).find(':input').prop('disabled', false);
                 this.getExplicOuiImmediat().show();
                 this.getExplicOuiEmbargo().hide();
                 this.getExplicNon().hide();
                 break;
             case "1": // oui avec embargo
-                this.getInputDivEmbargoDuree().show(effect, {direction: "left"}).find(':input').removeProp('disabled');
-                this.getInputDivMotif().show(effect, {direction: "up"}).find(':input').removeProp('disabled');
-                this.getInputDivAuteur().show(effect, {direction: "up"}).find(':input').removeProp('disabled');
+                this.getInputDivEmbargoDuree().show(effect, {direction: "left"}).find(':input').prop('disabled', false);
+                this.getInputDivMotif().show(effect, {direction: "up"}).find(':input').prop('disabled', false);
+                this.getInputDivAuteur().show(effect, {direction: "up"}).find(':input').prop('disabled', false);
                 this.getExplicOuiImmediat().hide();
                 this.getExplicOuiEmbargo().show();
                 this.getExplicNon().hide();
                 break;
             case "0": // non
                 this.getInputDivEmbargoDuree().hide(effect, {direction: "left"}).find(':input').prop('disabled', 'disabled');
-                this.getInputDivMotif().show(effect, {direction: "up"}).find(':input').removeProp('disabled');
+                this.getInputDivMotif().show(effect, {direction: "up"}).find(':input').prop('disabled', false);
                 this.getInputDivAuteur().hide(effect, {direction: "up"}).find(':input').prop('disabled', 'disabled');
                 this.getExplicOuiImmediat().hide();
                 this.getExplicOuiEmbargo().hide();
@@ -349,7 +349,7 @@ $.widget("unicaen.widgetConfidentialiteThese", {
         effect = effect ? "slide" : null;
         switch (value) {
             case "1":
-                this.getDivDateFin().show(effect, {direction: "left"}).find(':input').removeProp('disabled');
+                this.getDivDateFin().show(effect, {direction: "left"}).find(':input').prop('disabled', false);
                 this.getExplicConfidentialiteOui().show(effect, {direction: "left"});
                 this.getExplicConfidentialiteNon().hide(effect, {direction: "left"});
                 break;
diff --git a/script_mv_.sql b/script_mv_.sql
new file mode 100644
index 0000000000000000000000000000000000000000..c44d7a0a9142bc9ccff13b3a2ab975e097366af6
--- /dev/null
+++ b/script_mv_.sql
@@ -0,0 +1,592 @@
+alter table these alter column lib_etab_cotut type varchar(100) using lib_etab_cotut::varchar(100);
+
+drop view v_diff_these;
+drop materialized view mv_indicateur_1;
+drop materialized view mv_indicateur_2;
+drop materialized view mv_indicateur_3;
+drop materialized view mv_indicateur_4;
+drop materialized view mv_indicateur_5;
+drop materialized view mv_indicateur_6;
+drop materialized view mv_indicateur_81;
+
+-----
+
+create materialized view mv_indicateur_1 as
+SELECT these.id,
+       these.etablissement_id,
+       these.doctorant_id,
+       these.ecole_doct_id,
+       these.unite_rech_id,
+       these.besoin_expurge,
+       these.cod_unit_rech,
+       these.correc_autorisee,
+       these.date_autoris_soutenance,
+       these.date_fin_confid,
+       these.date_prem_insc,
+       these.date_prev_soutenance,
+       these.date_soutenance,
+       these.etat_these,
+       these.lib_disc,
+       these.lib_etab_cotut,
+       these.lib_pays_cotut,
+       these.lib_unit_rech,
+       these.resultat,
+       these.soutenance_autoris,
+       these.tem_avenant_cotut,
+       these.titre,
+       these.source_code,
+       these.source_id,
+       these.histo_createur_id,
+       these.histo_creation,
+       these.histo_modificateur_id,
+       these.histo_modification,
+       these.histo_destructeur_id,
+       these.histo_destruction
+FROM these these;
+
+
+create materialized view mv_indicateur_2 as
+SELECT t.id,
+       t.etablissement_id,
+       t.doctorant_id,
+       t.ecole_doct_id,
+       t.unite_rech_id,
+       t.besoin_expurge,
+       t.cod_unit_rech,
+       t.correc_autorisee,
+       t.date_autoris_soutenance,
+       t.date_fin_confid,
+       t.date_prem_insc,
+       t.date_prev_soutenance,
+       t.date_soutenance,
+       t.etat_these,
+       t.lib_disc,
+       t.lib_etab_cotut,
+       t.lib_pays_cotut,
+       t.lib_unit_rech,
+       t.resultat,
+       t.soutenance_autoris,
+       t.tem_avenant_cotut,
+       t.titre,
+       t.source_code,
+       t.source_id,
+       t.histo_createur_id,
+       t.histo_creation,
+       t.histo_modificateur_id,
+       t.histo_modification,
+       t.histo_destructeur_id,
+       t.histo_destruction,
+       t.correc_autorisee_forcee,
+       t.date_abandon,
+       t.date_transfert,
+       t.correc_effectuee
+FROM these t
+         LEFT JOIN validation v ON t.id = v.these_id
+         LEFT JOIN type_validation n ON v.type_validation_id = n.id
+WHERE t.date_soutenance > ('now'::text::timestamp without time zone - '2 mons'::interval)
+  AND t.etat_these::text = 'E'::text
+  AND n.code::text = 'PAGE_DE_COUVERTURE'::text
+  AND v.id IS NULL;
+
+
+
+create materialized view mv_indicateur_3 as
+SELECT t.id,
+       t.etablissement_id,
+       t.doctorant_id,
+       t.ecole_doct_id,
+       t.unite_rech_id,
+       t.besoin_expurge,
+       t.cod_unit_rech,
+       t.correc_autorisee,
+       t.date_autoris_soutenance,
+       t.date_fin_confid,
+       t.date_prem_insc,
+       t.date_prev_soutenance,
+       t.date_soutenance,
+       t.etat_these,
+       t.lib_disc,
+       t.lib_etab_cotut,
+       t.lib_pays_cotut,
+       t.lib_unit_rech,
+       t.resultat,
+       t.soutenance_autoris,
+       t.tem_avenant_cotut,
+       t.titre,
+       t.source_code,
+       t.source_id,
+       t.histo_createur_id,
+       t.histo_creation,
+       t.histo_modificateur_id,
+       t.histo_modification,
+       t.histo_destructeur_id,
+       t.histo_destruction,
+       t.correc_autorisee_forcee,
+       t.date_abandon,
+       t.date_transfert,
+       t.correc_effectuee
+FROM these t
+         LEFT JOIN fichier_these f ON t.id = f.these_id
+         LEFT JOIN fichier fi ON fi.id = f.fichier_id
+         LEFT JOIN nature_fichier n ON fi.nature_id = n.id
+WHERE t.date_soutenance > ('now'::text::timestamp without time zone - '1 mon'::interval)
+  AND t.etat_these::text = 'E'::text
+  AND n.code::text = 'THESE_PDF'::text
+  AND f.id IS NULL;
+
+create materialized view mv_indicateur_4 as
+SELECT t.id,
+       t.etablissement_id,
+       t.doctorant_id,
+       t.ecole_doct_id,
+       t.unite_rech_id,
+       t.besoin_expurge,
+       t.cod_unit_rech,
+       t.correc_autorisee,
+       t.date_autoris_soutenance,
+       t.date_fin_confid,
+       t.date_prem_insc,
+       t.date_prev_soutenance,
+       t.date_soutenance,
+       t.etat_these,
+       t.lib_disc,
+       t.lib_etab_cotut,
+       t.lib_pays_cotut,
+       t.lib_unit_rech,
+       t.resultat,
+       t.soutenance_autoris,
+       t.tem_avenant_cotut,
+       t.titre,
+       t.source_code,
+       t.source_id,
+       t.histo_createur_id,
+       t.histo_creation,
+       t.histo_modificateur_id,
+       t.histo_modification,
+       t.histo_destructeur_id,
+       t.histo_destruction,
+       t.correc_autorisee_forcee,
+       t.date_abandon,
+       t.date_transfert,
+       t.correc_effectuee
+FROM these t
+WHERE t.etat_these::text = 'E'::text
+  AND t.date_soutenance < 'now'::text::timestamp without time zone;
+
+
+create materialized view mv_indicateur_5 as
+SELECT t.id,
+       t.etablissement_id,
+       t.doctorant_id,
+       t.ecole_doct_id,
+       t.unite_rech_id,
+       t.besoin_expurge,
+       t.cod_unit_rech,
+       t.correc_autorisee,
+       t.date_autoris_soutenance,
+       t.date_fin_confid,
+       t.date_prem_insc,
+       t.date_prev_soutenance,
+       t.date_soutenance,
+       t.etat_these,
+       t.lib_disc,
+       t.lib_etab_cotut,
+       t.lib_pays_cotut,
+       t.lib_unit_rech,
+       t.resultat,
+       t.soutenance_autoris,
+       t.tem_avenant_cotut,
+       t.titre,
+       t.source_code,
+       t.source_id,
+       t.histo_createur_id,
+       t.histo_creation,
+       t.histo_modificateur_id,
+       t.histo_modification,
+       t.histo_destructeur_id,
+       t.histo_destruction,
+       t.correc_autorisee_forcee,
+       t.date_abandon,
+       t.date_transfert,
+       t.correc_effectuee
+FROM these t
+WHERE t.etat_these::text = 'E'::text
+  AND t.date_soutenance > 'now'::text::timestamp without time zone;
+
+create materialized view mv_indicateur_6 as
+SELECT t.id,
+       t.etablissement_id,
+       t.doctorant_id,
+       t.ecole_doct_id,
+       t.unite_rech_id,
+       t.besoin_expurge,
+       t.cod_unit_rech,
+       t.correc_autorisee,
+       t.date_autoris_soutenance,
+       t.date_fin_confid,
+       t.date_prem_insc,
+       t.date_prev_soutenance,
+       t.date_soutenance,
+       t.etat_these,
+       t.lib_disc,
+       t.lib_etab_cotut,
+       t.lib_pays_cotut,
+       t.lib_unit_rech,
+       t.resultat,
+       t.soutenance_autoris,
+       t.tem_avenant_cotut,
+       t.titre,
+       t.source_code,
+       t.source_id,
+       t.histo_createur_id,
+       t.histo_creation,
+       t.histo_modificateur_id,
+       t.histo_modification,
+       t.histo_destructeur_id,
+       t.histo_destruction,
+       t.correc_autorisee_forcee,
+       t.date_abandon,
+       t.date_transfert,
+       t.correc_effectuee
+FROM these t
+WHERE t.etat_these::text = 'E'::text
+  AND t.date_prem_insc < ('now'::text::timestamp without time zone - '6 years'::interval);
+
+create materialized view mv_indicateur_81 as
+SELECT t.id,
+       t.etablissement_id,
+       t.doctorant_id,
+       t.ecole_doct_id,
+       t.unite_rech_id,
+       t.besoin_expurge,
+       t.cod_unit_rech,
+       t.correc_autorisee,
+       t.date_autoris_soutenance,
+       t.date_fin_confid,
+       t.date_prem_insc,
+       t.date_prev_soutenance,
+       t.date_soutenance,
+       t.etat_these,
+       t.lib_disc,
+       t.lib_etab_cotut,
+       t.lib_pays_cotut,
+       t.lib_unit_rech,
+       t.resultat,
+       t.soutenance_autoris,
+       t.tem_avenant_cotut,
+       t.titre,
+       t.source_code,
+       t.source_id,
+       t.histo_createur_id,
+       t.histo_creation,
+       t.histo_modificateur_id,
+       t.histo_modification,
+       t.histo_destructeur_id,
+       t.histo_destruction,
+       t.correc_autorisee_forcee,
+       t.date_abandon,
+       t.date_transfert,
+       t.correc_effectuee
+FROM these t
+WHERE t.date_prem_insc <= ('now'::text::timestamp without time zone - '5 years'::interval)
+  AND t.etat_these::text = 'E'::text
+  AND (t.id IN (SELECT these_annee_univ.these_id
+                FROM these_annee_univ
+                         JOIN these t_1 ON these_annee_univ.these_id = t_1.id
+                WHERE t_1.etat_these::text = 'E'::text
+                GROUP BY these_annee_univ.these_id
+                HAVING max(these_annee_univ.annee_univ)::double precision <=
+                       date_part('year'::text, 'now'::text::timestamp without time zone - '1 year'::interval)));
+
+create view v_diff_these
+            (source_code, source_id, operation, u_source_id, u_etablissement_id, u_doctorant_id, u_ecole_doct_id,
+             u_unite_rech_id, u_titre, u_etat_these, u_resultat, u_code_sise_disc, u_lib_disc, u_date_prem_insc,
+             u_date_prev_soutenance, u_date_soutenance, u_date_fin_confid, u_lib_etab_cotut, u_lib_pays_cotut,
+             u_correc_autorisee, u_correc_effectuee, u_soutenance_autoris, u_date_autoris_soutenance,
+             u_tem_avenant_cotut, u_date_abandon, u_date_transfert, s_source_id, s_etablissement_id, s_doctorant_id,
+             s_ecole_doct_id, s_unite_rech_id, s_titre, s_etat_these, s_resultat, s_code_sise_disc, s_lib_disc,
+             s_date_prem_insc, s_date_prev_soutenance, s_date_soutenance, s_date_fin_confid, s_lib_etab_cotut,
+             s_lib_pays_cotut, s_correc_autorisee, s_correc_effectuee, s_soutenance_autoris, s_date_autoris_soutenance,
+             s_tem_avenant_cotut, s_date_abandon, s_date_transfert, d_source_id, d_etablissement_id, d_doctorant_id,
+             d_ecole_doct_id, d_unite_rech_id, d_titre, d_etat_these, d_resultat, d_code_sise_disc, d_lib_disc,
+             d_date_prem_insc, d_date_prev_soutenance, d_date_soutenance, d_date_fin_confid, d_lib_etab_cotut,
+             d_lib_pays_cotut, d_correc_autorisee, d_correc_effectuee, d_soutenance_autoris, d_date_autoris_soutenance,
+             d_tem_avenant_cotut, d_date_abandon, d_date_transfert)
+as
+WITH diff AS (
+    SELECT COALESCE(s.source_code, d.source_code) AS source_code,
+           COALESCE(s.source_id, d.source_id)     AS source_id,
+           CASE
+               WHEN s.source_code IS NOT NULL AND d.source_code IS NULL THEN 'insert'::text
+               WHEN s.source_code IS NOT NULL AND d.source_code IS NOT NULL AND
+                    (d.histo_destruction IS NULL OR d.histo_destruction > 'now'::text::timestamp(0) without time zone)
+                   THEN 'update'::text
+               WHEN s.source_code IS NOT NULL AND d.source_code IS NOT NULL AND d.histo_destruction IS NOT NULL AND
+                    d.histo_destruction <= 'now'::text::timestamp(0) without time zone THEN 'undelete'::text
+               WHEN s.source_code IS NULL AND d.source_code IS NOT NULL AND
+                    (d.histo_destruction IS NULL OR d.histo_destruction > 'now'::text::timestamp(0) without time zone)
+                   THEN 'delete'::text
+               ELSE NULL::text
+               END                                AS operation,
+           CASE
+               WHEN d.source_id <> s.source_id OR d.source_id IS NULL AND s.source_id IS NOT NULL OR
+                    d.source_id IS NOT NULL AND s.source_id IS NULL THEN 1
+               ELSE 0
+               END                                AS u_source_id,
+           CASE
+               WHEN d.etablissement_id <> s.etablissement_id OR
+                    d.etablissement_id IS NULL AND s.etablissement_id IS NOT NULL OR
+                    d.etablissement_id IS NOT NULL AND s.etablissement_id IS NULL THEN 1
+               ELSE 0
+               END                                AS u_etablissement_id,
+           CASE
+               WHEN d.doctorant_id <> s.doctorant_id OR d.doctorant_id IS NULL AND s.doctorant_id IS NOT NULL OR
+                    d.doctorant_id IS NOT NULL AND s.doctorant_id IS NULL THEN 1
+               ELSE 0
+               END                                AS u_doctorant_id,
+           CASE
+               WHEN d.ecole_doct_id <> s.ecole_doct_id OR d.ecole_doct_id IS NULL AND s.ecole_doct_id IS NOT NULL OR
+                    d.ecole_doct_id IS NOT NULL AND s.ecole_doct_id IS NULL THEN 1
+               ELSE 0
+               END                                AS u_ecole_doct_id,
+           CASE
+               WHEN d.unite_rech_id <> s.unite_rech_id OR d.unite_rech_id IS NULL AND s.unite_rech_id IS NOT NULL OR
+                    d.unite_rech_id IS NOT NULL AND s.unite_rech_id IS NULL THEN 1
+               ELSE 0
+               END                                AS u_unite_rech_id,
+           CASE
+               WHEN d.titre::text <> s.titre::text OR d.titre IS NULL AND s.titre IS NOT NULL OR
+                    d.titre IS NOT NULL AND s.titre IS NULL THEN 1
+               ELSE 0
+               END                                AS u_titre,
+           CASE
+               WHEN d.etat_these::text <> s.etat_these::text OR d.etat_these IS NULL AND s.etat_these IS NOT NULL OR
+                    d.etat_these IS NOT NULL AND s.etat_these IS NULL THEN 1
+               ELSE 0
+               END                                AS u_etat_these,
+           CASE
+               WHEN d.resultat::numeric <> s.resultat OR d.resultat IS NULL AND s.resultat IS NOT NULL OR
+                    d.resultat IS NOT NULL AND s.resultat IS NULL THEN 1
+               ELSE 0
+               END                                AS u_resultat,
+           CASE
+               WHEN d.code_sise_disc::text <> s.code_sise_disc::text OR
+                    d.code_sise_disc IS NULL AND s.code_sise_disc IS NOT NULL OR
+                    d.code_sise_disc IS NOT NULL AND s.code_sise_disc IS NULL THEN 1
+               ELSE 0
+               END                                AS u_code_sise_disc,
+           CASE
+               WHEN d.lib_disc::text <> s.lib_disc::text OR d.lib_disc IS NULL AND s.lib_disc IS NOT NULL OR
+                    d.lib_disc IS NOT NULL AND s.lib_disc IS NULL THEN 1
+               ELSE 0
+               END                                AS u_lib_disc,
+           CASE
+               WHEN d.date_prem_insc <> s.date_prem_insc OR d.date_prem_insc IS NULL AND s.date_prem_insc IS NOT NULL OR
+                    d.date_prem_insc IS NOT NULL AND s.date_prem_insc IS NULL THEN 1
+               ELSE 0
+               END                                AS u_date_prem_insc,
+           CASE
+               WHEN d.date_prev_soutenance <> s.date_prev_soutenance OR
+                    d.date_prev_soutenance IS NULL AND s.date_prev_soutenance IS NOT NULL OR
+                    d.date_prev_soutenance IS NOT NULL AND s.date_prev_soutenance IS NULL THEN 1
+               ELSE 0
+               END                                AS u_date_prev_soutenance,
+           CASE
+               WHEN d.date_soutenance <> s.date_soutenance OR
+                    d.date_soutenance IS NULL AND s.date_soutenance IS NOT NULL OR
+                    d.date_soutenance IS NOT NULL AND s.date_soutenance IS NULL THEN 1
+               ELSE 0
+               END                                AS u_date_soutenance,
+           CASE
+               WHEN d.date_fin_confid <> s.date_fin_confid OR
+                    d.date_fin_confid IS NULL AND s.date_fin_confid IS NOT NULL OR
+                    d.date_fin_confid IS NOT NULL AND s.date_fin_confid IS NULL THEN 1
+               ELSE 0
+               END                                AS u_date_fin_confid,
+           CASE
+               WHEN d.lib_etab_cotut::text <> s.lib_etab_cotut::text OR
+                    d.lib_etab_cotut IS NULL AND s.lib_etab_cotut IS NOT NULL OR
+                    d.lib_etab_cotut IS NOT NULL AND s.lib_etab_cotut IS NULL THEN 1
+               ELSE 0
+               END                                AS u_lib_etab_cotut,
+           CASE
+               WHEN d.lib_pays_cotut::text <> s.lib_pays_cotut::text OR
+                    d.lib_pays_cotut IS NULL AND s.lib_pays_cotut IS NOT NULL OR
+                    d.lib_pays_cotut IS NOT NULL AND s.lib_pays_cotut IS NULL THEN 1
+               ELSE 0
+               END                                AS u_lib_pays_cotut,
+           CASE
+               WHEN d.correc_autorisee::text <> s.correc_autorisee::text OR
+                    d.correc_autorisee IS NULL AND s.correc_autorisee IS NOT NULL OR
+                    d.correc_autorisee IS NOT NULL AND s.correc_autorisee IS NULL THEN 1
+               ELSE 0
+               END                                AS u_correc_autorisee,
+           CASE
+               WHEN d.correc_effectuee::text <> s.correc_effectuee::text OR
+                    d.correc_effectuee IS NULL AND s.correc_effectuee IS NOT NULL OR
+                    d.correc_effectuee IS NOT NULL AND s.correc_effectuee IS NULL THEN 1
+               ELSE 0
+               END                                AS u_correc_effectuee,
+           CASE
+               WHEN d.soutenance_autoris::text <> s.soutenance_autoris::text OR
+                    d.soutenance_autoris IS NULL AND s.soutenance_autoris IS NOT NULL OR
+                    d.soutenance_autoris IS NOT NULL AND s.soutenance_autoris IS NULL THEN 1
+               ELSE 0
+               END                                AS u_soutenance_autoris,
+           CASE
+               WHEN d.date_autoris_soutenance <> s.date_autoris_soutenance OR
+                    d.date_autoris_soutenance IS NULL AND s.date_autoris_soutenance IS NOT NULL OR
+                    d.date_autoris_soutenance IS NOT NULL AND s.date_autoris_soutenance IS NULL THEN 1
+               ELSE 0
+               END                                AS u_date_autoris_soutenance,
+           CASE
+               WHEN d.tem_avenant_cotut::text <> s.tem_avenant_cotut::text OR
+                    d.tem_avenant_cotut IS NULL AND s.tem_avenant_cotut IS NOT NULL OR
+                    d.tem_avenant_cotut IS NOT NULL AND s.tem_avenant_cotut IS NULL THEN 1
+               ELSE 0
+               END                                AS u_tem_avenant_cotut,
+           CASE
+               WHEN d.date_abandon <> s.date_abandon OR d.date_abandon IS NULL AND s.date_abandon IS NOT NULL OR
+                    d.date_abandon IS NOT NULL AND s.date_abandon IS NULL THEN 1
+               ELSE 0
+               END                                AS u_date_abandon,
+           CASE
+               WHEN d.date_transfert <> s.date_transfert OR d.date_transfert IS NULL AND s.date_transfert IS NOT NULL OR
+                    d.date_transfert IS NOT NULL AND s.date_transfert IS NULL THEN 1
+               ELSE 0
+               END                                AS u_date_transfert,
+           s.source_id                            AS s_source_id,
+           s.etablissement_id                     AS s_etablissement_id,
+           s.doctorant_id                         AS s_doctorant_id,
+           s.ecole_doct_id                        AS s_ecole_doct_id,
+           s.unite_rech_id                        AS s_unite_rech_id,
+           s.titre                                AS s_titre,
+           s.etat_these                           AS s_etat_these,
+           s.resultat                             AS s_resultat,
+           s.code_sise_disc                       AS s_code_sise_disc,
+           s.lib_disc                             AS s_lib_disc,
+           s.date_prem_insc                       AS s_date_prem_insc,
+           s.date_prev_soutenance                 AS s_date_prev_soutenance,
+           s.date_soutenance                      AS s_date_soutenance,
+           s.date_fin_confid                      AS s_date_fin_confid,
+           s.lib_etab_cotut                       AS s_lib_etab_cotut,
+           s.lib_pays_cotut                       AS s_lib_pays_cotut,
+           s.correc_autorisee                     AS s_correc_autorisee,
+           s.correc_effectuee                     AS s_correc_effectuee,
+           s.soutenance_autoris                   AS s_soutenance_autoris,
+           s.date_autoris_soutenance              AS s_date_autoris_soutenance,
+           s.tem_avenant_cotut                    AS s_tem_avenant_cotut,
+           s.date_abandon                         AS s_date_abandon,
+           s.date_transfert                       AS s_date_transfert,
+           d.source_id                            AS d_source_id,
+           d.etablissement_id                     AS d_etablissement_id,
+           d.doctorant_id                         AS d_doctorant_id,
+           d.ecole_doct_id                        AS d_ecole_doct_id,
+           d.unite_rech_id                        AS d_unite_rech_id,
+           d.titre                                AS d_titre,
+           d.etat_these                           AS d_etat_these,
+           d.resultat                             AS d_resultat,
+           d.code_sise_disc                       AS d_code_sise_disc,
+           d.lib_disc                             AS d_lib_disc,
+           d.date_prem_insc                       AS d_date_prem_insc,
+           d.date_prev_soutenance                 AS d_date_prev_soutenance,
+           d.date_soutenance                      AS d_date_soutenance,
+           d.date_fin_confid                      AS d_date_fin_confid,
+           d.lib_etab_cotut                       AS d_lib_etab_cotut,
+           d.lib_pays_cotut                       AS d_lib_pays_cotut,
+           d.correc_autorisee                     AS d_correc_autorisee,
+           d.correc_effectuee                     AS d_correc_effectuee,
+           d.soutenance_autoris                   AS d_soutenance_autoris,
+           d.date_autoris_soutenance              AS d_date_autoris_soutenance,
+           d.tem_avenant_cotut                    AS d_tem_avenant_cotut,
+           d.date_abandon                         AS d_date_abandon,
+           d.date_transfert                       AS d_date_transfert
+    FROM these d
+             JOIN source src ON src.id = d.source_id AND src.importable = true
+             FULL JOIN src_these s ON s.source_id = d.source_id AND s.source_code::text = d.source_code::text
+)
+SELECT diff.source_code,
+       diff.source_id,
+       diff.operation,
+       diff.u_source_id,
+       diff.u_etablissement_id,
+       diff.u_doctorant_id,
+       diff.u_ecole_doct_id,
+       diff.u_unite_rech_id,
+       diff.u_titre,
+       diff.u_etat_these,
+       diff.u_resultat,
+       diff.u_code_sise_disc,
+       diff.u_lib_disc,
+       diff.u_date_prem_insc,
+       diff.u_date_prev_soutenance,
+       diff.u_date_soutenance,
+       diff.u_date_fin_confid,
+       diff.u_lib_etab_cotut,
+       diff.u_lib_pays_cotut,
+       diff.u_correc_autorisee,
+       diff.u_correc_effectuee,
+       diff.u_soutenance_autoris,
+       diff.u_date_autoris_soutenance,
+       diff.u_tem_avenant_cotut,
+       diff.u_date_abandon,
+       diff.u_date_transfert,
+       diff.s_source_id,
+       diff.s_etablissement_id,
+       diff.s_doctorant_id,
+       diff.s_ecole_doct_id,
+       diff.s_unite_rech_id,
+       diff.s_titre,
+       diff.s_etat_these,
+       diff.s_resultat,
+       diff.s_code_sise_disc,
+       diff.s_lib_disc,
+       diff.s_date_prem_insc,
+       diff.s_date_prev_soutenance,
+       diff.s_date_soutenance,
+       diff.s_date_fin_confid,
+       diff.s_lib_etab_cotut,
+       diff.s_lib_pays_cotut,
+       diff.s_correc_autorisee,
+       diff.s_correc_effectuee,
+       diff.s_soutenance_autoris,
+       diff.s_date_autoris_soutenance,
+       diff.s_tem_avenant_cotut,
+       diff.s_date_abandon,
+       diff.s_date_transfert,
+       diff.d_source_id,
+       diff.d_etablissement_id,
+       diff.d_doctorant_id,
+       diff.d_ecole_doct_id,
+       diff.d_unite_rech_id,
+       diff.d_titre,
+       diff.d_etat_these,
+       diff.d_resultat,
+       diff.d_code_sise_disc,
+       diff.d_lib_disc,
+       diff.d_date_prem_insc,
+       diff.d_date_prev_soutenance,
+       diff.d_date_soutenance,
+       diff.d_date_fin_confid,
+       diff.d_lib_etab_cotut,
+       diff.d_lib_pays_cotut,
+       diff.d_correc_autorisee,
+       diff.d_correc_effectuee,
+       diff.d_soutenance_autoris,
+       diff.d_date_autoris_soutenance,
+       diff.d_tem_avenant_cotut,
+       diff.d_date_abandon,
+       diff.d_date_transfert
+FROM diff
+WHERE diff.operation IS NOT NULL
+  AND (diff.operation = 'undelete'::text OR 0 < (diff.u_source_id + diff.u_etablissement_id + diff.u_doctorant_id +
+                                                 diff.u_ecole_doct_id + diff.u_unite_rech_id + diff.u_titre +
+                                                 diff.u_etat_these + diff.u_resultat + diff.u_code_sise_disc +
+                                                 diff.u_lib_disc + diff.u_date_prem_insc + diff.u_date_prev_soutenance +
+                                                 diff.u_date_soutenance + diff.u_date_fin_confid +
+                                                 diff.u_lib_etab_cotut + diff.u_lib_pays_cotut +
+                                                 diff.u_correc_autorisee + diff.u_correc_effectuee +
+                                                 diff.u_soutenance_autoris + diff.u_date_autoris_soutenance +
+                                                 diff.u_tem_avenant_cotut + diff.u_date_abandon +
+                                                 diff.u_date_transfert));
+