From 2c52e403cf1f66c5cf30c1fd2312c70fcd72b09a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?ANDRE=20s=C3=A9bastien?= <sandre@afi-sa.fr>
Date: Tue, 29 Mar 2022 17:23:29 +0200
Subject: [PATCH] dev#141440 activities add effectif total  * add fckeditor img
 in result activities  * detail-session display first contenu before
 information

---
 FEATURES/141440                               |  10 +
 VERSIONS_WIP/141440                           |   1 +
 cosmogramme/sql/patch/patch_432.php           |   6 +
 library/Class/AdminVar.php                    |   2 +-
 library/Class/SessionActivity.php             |  64 +++-
 library/Class/SessionActivityAttendees.php    | 289 +++++++++------
 library/Class/SessionActivityInscription.php  |  28 +-
 library/Class/User/SessionActivity.php        |  39 +-
 .../Controller/Plugin/Manager/Manager.php     |   1 -
 .../ZendAfi/Form/Admin/SessionActivity.php    |  27 +-
 .../Form/SessionActivityInscription.php       |   6 +-
 library/ZendAfi/View/Helper/RenderSession.php |  20 +-
 .../Library/View/Wrapper/ActivitySession.php  |  16 +-
 .../Library/View/Wrapper/Article.php          |   7 +
 ...ssionActivityInscriptionControllerTest.php |  27 +-
 tests/db/UpgradeDBTest.php                    |  28 ++
 .../AbonneControllerActivitiesTest.php        |   2 +-
 .../AbonneControllerWithQuotasTest.php        | 339 ++++++++++++++++--
 .../ActivitiesWithQueueAbonneTest.php         | 173 ++++++++-
 .../ActivitiesWithQueueAdminTest.php          |  18 +-
 ...minControllerInscriptionWithQuotasTest.php |  18 +-
 .../AdminControllerWithQuotasTest.php         | 209 +++++++++--
 .../PolygoneTemplateAbonneAgendaTest.php      | 119 ++++--
 23 files changed, 1180 insertions(+), 269 deletions(-)
 create mode 100644 FEATURES/141440
 create mode 100644 VERSIONS_WIP/141440
 create mode 100644 cosmogramme/sql/patch/patch_432.php

diff --git a/FEATURES/141440 b/FEATURES/141440
new file mode 100644
index 00000000000..9e143c59797
--- /dev/null
+++ b/FEATURES/141440
@@ -0,0 +1,10 @@
+        '141440' =>
+            ['Label' => $this->_('Ajout d'une jauge permettant de gérer plus finement la limite du nombre de participants'),
+             'Desc' => $this->_('La jauge maximum et minimum total offre une possibilité de s\'abstreindre des jauges adulte et enfant, pour gérer la limite maximum de participants de la session'),
+             'Image' => '',
+             'Video' => '',
+             'Category' => $this->_('Activités'),
+             'Right' => function($feature_description, $user) {return true;},
+             'Wiki' => 'https://wiki.bokeh-library-portal.org/index.php?title=Gestion_des_activit%C3%A9s#Cr.C3.A9er_une_session',
+             'Test' => '',
+             'Date' => '2022-03-29'],
\ No newline at end of file
diff --git a/VERSIONS_WIP/141440 b/VERSIONS_WIP/141440
new file mode 100644
index 00000000000..74e75707bc2
--- /dev/null
+++ b/VERSIONS_WIP/141440
@@ -0,0 +1 @@
+ - fonctionnalité #141440 : Ajout d'une jauge permettant de gérer plus finement la limite du nombre de participants
\ No newline at end of file
diff --git a/cosmogramme/sql/patch/patch_432.php b/cosmogramme/sql/patch/patch_432.php
new file mode 100644
index 00000000000..475658ba781
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_432.php
@@ -0,0 +1,6 @@
+<?php
+$adapter = Zend_Db_Table_Abstract::getDefaultAdapter();
+
+try {
+  $adapter->query('alter table session_activity add column effectif_total_min int(11) unsigned not null default 0, add column effectif_total_max int(11) unsigned not null default 0');
+} catch(Exception $e) {}
diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php
index cb3222d7000..4227b9ed1c9 100644
--- a/library/Class/AdminVar.php
+++ b/library/Class/AdminVar.php
@@ -589,7 +589,7 @@ Pour vous désabonner de la lettre d\'information, merci de cliquer sur le lien
 
 
   protected function _getActivityVars() {
-    return ['ACTIVITY' => Class_AdminVar_Meta::newOnOff($this->_('Activer ou désactiver le module d\'activité')),
+    return ['ACTIVITY' => Class_AdminVar_Meta::newOnOff($this->_('Activer ou désactiver le module d\'activité'))->bePrivate(),
             'ACTIVITY_SESSION_QUOTAS' => Class_AdminVar_Meta::newOnOff($this->_('Activer ou désactiver la gestion des quotas pour les activités')),
             'ACTIVITY_NOTIFICATION_DELAY' => Class_AdminVar_Meta::newDefault($this->_('Délai d\'envoi des rappels pour les activités (en jours)'), ['value' => '0']),
             'ACTIVITY_NOTIFICATION_SUBJECT' => Class_AdminVar_Meta::newDefault($this->_('Sujet de l\'email de rappel pour les activités'), ['value'=> 'Rappel : {session.libelle_activity}']),
diff --git a/library/Class/SessionActivity.php b/library/Class/SessionActivity.php
index a4565470d1b..692cc5046c2 100644
--- a/library/Class/SessionActivity.php
+++ b/library/Class/SessionActivity.php
@@ -136,6 +136,8 @@ class Class_SessionActivity extends Storm_Model_Abstract {
                                           'effectif_max' => 10,
                                           'effectif_child_min' => 0,
                                           'effectif_child_max' => 0,
+                                          'effectif_total_min' => 0,
+                                          'effectif_total_max' => 0,
                                           'age_child_max' => 0,
                                           'age_child_min' => 0,
                                           'all_day' => 1,
@@ -415,18 +417,6 @@ class Class_SessionActivity extends Storm_Model_Abstract {
     if (!Class_AdminVar::isActivitySessionQuotasEnabled())
       return;
 
-    $this->checkAttribute("effectif_max",
-                          $this->getEffectifInscriptionMax() <= $this->getEffectifMax(),
-                          $this->_("L'effectif maximum doit être supérieur ou égal à l'effectif maximum par inscription"));
-
-    $this->checkAttribute("effectif_child_max",
-                          $this->getEffectifChildMin() <= $this->getEffectifChildMax(),
-                          $this->_("L'effectif enfants maximum doit être supérieur ou égal à l'effectif enfants minimum"));
-
-    $this->checkAttribute("effectif_child_max",
-                          $this->getEffectifInscriptionChildMax() <= $this->getEffectifChildMax(),
-                          $this->_("L'effectif enfants maximum doit être supérieur ou égal à l'effectif enfants maximum par inscription"));
-
     $this->checkAttribute('age_child_max',
                           $this->getEffectifChildMax() <= 0 || $this->getAgeChildMax() > 0,
                           $this->_("L'âge maximum pour les enfants doit être renseigné"));
@@ -435,6 +425,15 @@ class Class_SessionActivity extends Storm_Model_Abstract {
                           $this->getAgeChildMin() <= $this->getAgeChildMax(),
                           $this->_("L'âge minimum doit être inférieur à l'âge maximum pour les enfants"));
 
+    $this->checkAttribute("effectif_inscription_max",
+                          $this->getEffectifInscriptionMax() > 0
+                          || $this->getEffectifInscriptionChildMax() > 0,
+                          $this->_("Au moins un maximum par inscription doit être renseigné"));
+    $this->checkAttribute("effectif_inscription_child_max",
+                          $this->getEffectifInscriptionMax() > 0
+                          || $this->getEffectifInscriptionChildMax() > 0,
+                          $this->_("Au moins un maximum par inscription doit être renseigné"));
+
     $this->checkAttribute("effectif_inscription_max",
                           $this->getEffectifMax() <= 0 || $this->getEffectifInscriptionMax() > 0,
                           $this->_("Adultes maximum par inscription doit être renseigné"));
@@ -443,6 +442,42 @@ class Class_SessionActivity extends Storm_Model_Abstract {
                           $this->getEffectifChildMax() <= 0
                           || $this->getEffectifInscriptionChildMax() > 0,
                           $this->_("Enfants maximum par inscription doit être renseigné"));
+
+    if ($this->getEffectifTotalMax() > 0)
+      return $this->_checkEffectifTotal();
+
+    $this->checkAttribute("effectif_max",
+                          $this->getEffectifInscriptionMax() <= $this->getEffectifMax(),
+                          $this->_("L'effectif maximum doit être supérieur ou égal à l'effectif maximum par inscription"));
+
+    $this->checkAttribute("effectif_child_max",
+                          $this->getEffectifChildMin() <= $this->getEffectifChildMax(),
+                          $this->_("L'effectif enfants maximum doit être supérieur ou égal à l'effectif enfants minimum"));
+
+    $this->checkAttribute("effectif_child_max",
+                          $this->getEffectifInscriptionChildMax() <= $this->getEffectifChildMax(),
+                          $this->_("L'effectif enfants maximum doit être supérieur ou égal à l'effectif enfants maximum par inscription"));
+  }
+
+
+  protected function _checkEffectifTotal() : self {
+    $this->checkAttribute('effectif_total_max',
+                          $this->getEffectifInscriptionMax() <= $this->getEffectifTotalMax(),
+                          $this->_("L'effectif total maximum doit être supérieur ou égal à l'effectif maximum par inscription"));
+
+    $this->checkAttribute('effectif_total_max',
+                          $this->getEffectifTotalMin() <= $this->getEffectifTotalMax(),
+                          $this->_("L'effectif total maximum doit être supérieur ou égal à l'effectif total minimum"));
+
+    $this->checkAttribute('effectif_total_max',
+                          $this->getEffectifTotalMax() >= $this->getEffectifChildMax(),
+                          $this->_("Le nombre d'enfants maximum ne peut dépasser l'effectif maximum total"));
+
+    $this->checkAttribute('effectif_total_max',
+                          $this->getEffectifTotalMax() >= $this->getEffectifMax(),
+                          $this->_("Le nombre d'adultes maximum ne peut dépasser l'effectif maximum total"));
+
+    return $this;
   }
 
 
@@ -462,6 +497,11 @@ class Class_SessionActivity extends Storm_Model_Abstract {
   }
 
 
+  public function getNextTotalFor(?Class_SessionActivityInscription $registration = null) : int {
+    return $this->_getAttendees()->getNextTotalFor($registration);
+  }
+
+
   public function getNextAdultsMax() {
     return $this->_getAttendees()->getNextAdultsMax() ;
   }
diff --git a/library/Class/SessionActivityAttendees.php b/library/Class/SessionActivityAttendees.php
index 2c1ccecc645..3e9e496cf7a 100644
--- a/library/Class/SessionActivityAttendees.php
+++ b/library/Class/SessionActivityAttendees.php
@@ -27,192 +27,280 @@ class Class_SessionActivityAttendees {
     $_session_with_quotas,
     $_is_max_registration_limited = true;
 
-  public static function newFor($session) {
+  public static function newFor(Class_SessionActivity $session) {
     return $session->isQueueAttendees()
       ? new Class_SessionActivityAttendeesWithQueue($session)
       : new Class_SessionActivityAttendees($session);
   }
 
 
-  public function __construct($session) {
+  public function __construct(Class_SessionActivity $session) {
     $this->_session_activity = $session;
     $this->_session_with_quotas = Class_AdminVar::isActivitySessionQuotasEnabled();
   }
 
 
-  public function isFull() {
+  public function isFull() : bool {
+    if (($total = $this->getEffectifTotalMax()) > 0)
+      return $total <= $this->count();
+
     return $this->isFullAdults() && $this->isFullChildren();
   }
 
 
-  public function isFullAdults() {
-    return 0 == $this->getEffectifMax()
-      || $this->getEffectifMax() <= $this->numberOfAdults();
+  public function isFullAdults() : bool {
+    return 0 == $this->getEffectifMaxOrTotal()
+      || $this->getEffectifMaxOrTotal() <= $this->numberOfAdults();
   }
 
 
-  public function isFullChildren() {
-    return !$this->_session_with_quotas
-      || 0 == $this->getEffectifChildMax()
-      || $this->getEffectifChildMax() <= $this->numberOfChildren();
+  public function isFullChildren() : bool {
+    if (!$this->_session_with_quotas)
+      return true;
+
+    return 0 == $this->getEffectifChildMaxOrTotal()
+      || $this->getEffectifChildMaxOrTotal() <= $this->numberOfChildren();
   }
 
 
-  public function getMin() {
-    return (int)$this->getEffectifMin() + (int)$this->getEffectifChildMin();
+  public function getMin() : int {
+    if (($total = $this->getEffectifTotalMin()) > 0)
+      return $total;
+
+    return $this->getEffectifMin() + $this->getEffectifChildMin();
   }
 
 
-  public function getMax() {
-    return (int)$this->getEffectifMax() + (int)$this->getEffectifChildMax();
+  public function getMax() : int {
+    if (($total = $this->getEffectifTotalMax()) > 0)
+      return $total;
+
+    return $this->getEffectifMaxOrTotal() + $this->getEffectifChildMaxOrTotal();
   }
 
 
-  public function count() {
+  public function count() : int {
     return $this->numberOfAdults() + $this->numberOfChildren();
   }
 
 
-  public function countInQueue() {
+  public function countInQueue() : int {
     return 0;
   }
 
 
-  public function getEffectifMax() {
-    return $this->_session_activity->getEffectifMax();
+  public function getEffectifMax() : int {
+    return (int) $this->_session_activity->getEffectifMax();
   }
 
 
-  public function getEffectifMin() {
-    return $this->_session_activity->getEffectifMin();
+  public function getEffectifMaxOrTotal() : int {
+    return ($max = $this->getEffectifMax()) > 0
+      ? $max
+      : $this->getEffectifTotalMax();
   }
 
 
-  public function getEffectifChildMax() {
-    return $this->_session_with_quotas ? $this->_session_activity->getEffectifChildMax() : 0;
+  public function getEffectifMin() : int {
+    return ($min = (int) $this->_session_activity->getEffectifMin()) > 0
+      ? $min
+      : $this->getEffectifTotalMin();
   }
 
 
-  public function getEffectifChildMin() {
-    return $this->_session_with_quotas ? $this->_session_activity->getEffectifChildMin() : 0;
+  public function getEffectifChildMax() : int {
+    if (!$this->_session_with_quotas)
+      return 0;
+
+    return (int) $this->_session_activity->getEffectifChildMax();
   }
 
 
-  public function numberOfAdults() {
+  public function getEffectifChildMaxOrTotal() : int {
+    if (!$this->_session_with_quotas)
+      return 0;
+
+    return ($max = $this->getEffectifChildMax()) > 0
+      ? $max
+      : $this->getEffectifTotalMax();
+  }
+
+
+  public function getEffectifChildMin() : int {
+    if (!$this->_session_with_quotas)
+      return 0;
+
+    return ($min = (int) $this->_session_activity->getEffectifChildMin()) > 0
+      ? $min
+      : $this->getEffectifTotalMin();
+  }
+
+
+  public function getEffectifTotalMin() : int {
+    return $this->_session_with_quotas
+      ? (int) $this->_session_activity->getEffectifTotalMin()
+      : 0;
+  }
+
+
+  public function getEffectifTotalMax() : int {
+    return $this->_session_with_quotas
+      ? (int) $this->_session_activity->getEffectifTotalMax()
+      : 0;
+  }
+
+
+  public function getEffectifInscriptionMax() : int {
+    return $this->_session_with_quotas
+      ? (int) $this->_session_activity->getEffectifInscriptionMax()
+      : 0;
+  }
+
+
+  public function getEffectifInscriptionChildMax() : int {
+    return $this->_session_with_quotas
+      ? (int) $this->_session_activity->getEffectifInscriptionChildMax()
+      : 0;
+  }
+
+
+  public function numberOfAdults() : int {
     return $this->_countInscriptions('adults');
   }
 
 
-  public function numberOfChildren() {
-    return $this->_session_with_quotas ? $this->_countInscriptions('children') : 0;
+  public function numberOfChildren() : int {
+    return $this->_session_with_quotas
+      ? $this->_countInscriptions('children')
+      : 0;
   }
 
 
-  public function numberOfAdultsQueue() {
+  public function numberOfAdultsQueue() : int {
     return 0;
   }
 
 
-  public function numberOfChildrenQueue() {
+  public function numberOfChildrenQueue() : int {
     return 0;
   }
 
 
-  public function isFullForQueue($inscription) {
+  public function isFullForQueue(Class_SessionActivityInscription $inscription) : bool {
     return false;
   }
 
 
-  public function bypassMaxRegistration() {
+  public function bypassMaxRegistration() : self {
     $this->_is_max_registration_limited = false;
     return $this;
   }
 
 
-  public function getNextAdultsMax() {
-    return $this->_getMin($this->_session_activity
-                          ->getEffectifInscriptionMax(), $this->_remainingAdults());
+  public function getNextTotalFor($registration = null) : int {
+    if ($this->_session_activity->isQueueAttendees()
+        || $this->getEffectifTotalMax() <= 0
+        || !$registration)
+      return -1;
+
+    $remain_total = $this->getEffectifTotalMax() - $this->count();
+    if ($remain_total >= ($this->_remainingAdults() + $this->_remainingChildren()))
+      return -1;
+
+    return ($remain_total < ($registration->getAdults() + $registration->getChildren()))
+      ? $remain_total
+      : -1;
+  }
+
+
+  public function getNextAdultsMax() : int {
+    return $this->_getMin($this->getEffectifInscriptionMax(), $this->_remainingAdults());
   }
 
 
-  public function getNextAdultsMaxQueue() {
+  public function getNextAdultsMaxQueue() : int {
     return 0;
   }
 
 
-  public function getNextAdultsMaxFor($registration) {
-    return $this->_getMin($this->_session_activity
-                          ->getEffectifInscriptionMax(),
+  public function getNextAdultsMaxFor(Class_SessionActivityInscription $registration) : int {
+    return $this->_getMin($this->getEffectifInscriptionMax(),
                           ($this->_remainingAdults() + $registration->getAdults()));
   }
 
 
-  public function getNextChildrenMax() {
+  public function getNextChildrenMax() : int {
     return $this->_session_with_quotas
-      ? $this->_getMin($this->_session_activity
-                       ->getEffectifInscriptionChildMax(), $this->_remainingChildren())
+      ? $this->_getMin($this->getEffectifInscriptionChildMax(), $this->_remainingChildren())
       : 0;
   }
 
 
-  public function getNextChildrenMaxQueue() {
+  public function getNextChildrenMaxQueue() : int {
     return 0;
   }
 
 
-  public function getNextChildrenMaxFor($registration) {
+  public function getNextChildrenMaxFor(Class_SessionActivityInscription $registration) : int {
     return $this->_session_with_quotas
-        ? $this->_getMin($this->_session_activity
-                         ->getEffectifInscriptionChildMax(),
-                         $this->_remainingChildren() + $registration->getChildren())
-        : 0;
+      ? $this->_getMin($this->getEffectifInscriptionChildMax(),
+                       ($this->_remainingChildren() + $registration->getChildren()))
+      : 0;
   }
 
 
-  public function withQueuedInscriptionDo($callback) {
+  public function withQueuedInscriptionDo($callback) : self {
     return $this;
   }
 
 
   public function acceptVisitor($view) {
     if (!$this->_session_with_quotas) {
-      $view->visitLegacy($this->numberOfAdults(), $this->getEffectifMin(), $this->getEffectifMax());
+      $view->visitLegacy($this->numberOfAdults(), $this->getEffectifMin(), $this->getEffectifMaxOrTotal());
       return;
     }
 
-    if ($nb_max_adults = $this->getEffectifMax())
+    if ($nb_max_adults = $this->getEffectifMaxOrTotal())
       $view->visitAdults($this->numberOfAdults(),
                          $this->getEffectifMin(),
                          $nb_max_adults);
 
-    if ($nb_max_children = $this->getEffectifChildMax())
+    if ($nb_max_children = $this->getEffectifChildMaxOrTotal())
       $view->visitChildren($this->numberOfChildren(),
                            $this->getEffectifChildMin(),
                            $nb_max_children);
   }
 
 
-  protected function _remainingAdults() {
-    return $this->getEffectifMax() - $this->numberOfAdults();
+  protected function _remainingAdults() : int {
+    if ($this->getEffectifTotalMax() > 0)
+      return min(($this->getEffectifTotalMax() - $this->count()),
+                 ($this->getEffectifMaxOrTotal() - $this->numberOfAdults()));
+
+    return $this->getEffectifMaxOrTotal() - $this->numberOfAdults();
   }
 
 
-  protected function _remainingChildren() {
+  protected function _remainingChildren() : int {
     if (!$this->_session_with_quotas)
       return 0;
 
-    return $this->getEffectifChildMax() - $this->numberOfChildren();
+    if ($this->getEffectifTotalMax() > 0)
+      return min(($this->getEffectifTotalMax() - $this->count()),
+                 ($this->getEffectifChildMaxOrTotal() - $this->numberOfChildren()));
+
+    return $this->getEffectifChildMaxOrTotal() - $this->numberOfChildren();
   }
 
 
-  protected function _getMin($effectif_max, $remaining) {
+  protected function _getMin(int $effectif_max, int $remaining) : int {
     return $this->_is_max_registration_limited
       ? min($effectif_max, $remaining)
       : $remaining;
   }
 
 
-  protected function _countInscriptions($attribut, $with_queue=false) {
+  protected function _countInscriptions(string $attribut, bool $with_queue=false) : int {
     return $this->_registrations()
                 ->injectInto(0,
                              function($next_value, $inscription) use($attribut, $with_queue)
@@ -225,7 +313,7 @@ class Class_SessionActivityAttendees {
   }
 
 
-  protected function _registrations() {
+  protected function _registrations() : Storm_Model_Collection {
     return new Storm_Model_Collection($this->_session_activity->getSessionActivityInscriptions());
   }
 }
@@ -235,32 +323,39 @@ class Class_SessionActivityAttendees {
 
 class Class_SessionActivityAttendeesWithQueue extends Class_SessionActivityAttendees {
 
-  public function isFullAdults() {
-    return 0 == $this->getEffectifMax();
+  public function isFull() : bool {
+    return $this->isFullAdults() && $this->isFullChildren();
+  }
+
+
+  public function isFullAdults() : bool {
+    return 0 == $this->getEffectifMaxOrTotal();
   }
 
 
-  public function isFullChildren() {
-    return !$this->_session_with_quotas || 0 == $this->getEffectifChildMax();
+  public function isFullChildren() : bool {
+    return !$this->_session_with_quotas || 0 == $this->getEffectifChildMaxOrTotal();
   }
 
 
-  public function countInQueue() {
+  public function countInQueue() : int {
     return $this->numberOfAdultsQueue() + $this->numberOfChildrenQueue();
   }
 
 
-  public function numberOfAdultsQueue() {
+  public function numberOfAdultsQueue() : int {
     return $this->_countInscriptions('adults', true);
   }
 
 
-  public function numberOfChildrenQueue() {
-    return $this->_session_with_quotas ? $this->_countInscriptions('children', true) : 0;
+  public function numberOfChildrenQueue() : int {
+    return $this->_session_with_quotas
+      ? $this->_countInscriptions('children', true)
+      : 0;
   }
 
 
-  public function isFullForQueue($inscription) {
+  public function isFullForQueue(Class_SessionActivityInscription $inscription) : bool {
     $total_adults_remaining = $this->_remainingAdultsForQueue() - $inscription->getAdults();
     $total_children_remaining = $this->_session_with_quotas
       ? $this->_remainingChildrenForQueue() - $inscription->getChildren()
@@ -270,72 +365,66 @@ class Class_SessionActivityAttendeesWithQueue extends Class_SessionActivityAtten
   }
 
 
-  public function getNextAdultsMax() {
+  public function getNextAdultsMax() : int {
     return $this->_is_max_registration_limited
-      ? $this->_session_activity->getEffectifInscriptionMax()
-      : $this->getEffectifMax();
+      ? $this->getEffectifInscriptionMax()
+      : $this->getEffectifMaxOrTotal();
   }
 
 
-  public function getNextAdultsMaxQueue() {
-    return $this->_getMin($this->_session_activity->getEffectifInscriptionMax(),
+  public function getNextAdultsMaxQueue() : int {
+    return $this->_getMin($this->getEffectifInscriptionMax(),
                           $this->_remainingAdultsForQueue());
   }
 
 
-  public function getNextAdultsMaxFor($registration) {
+  public function getNextAdultsMaxFor(Class_SessionActivityInscription $registration) : int {
     return $registration->isQueue()
       ? $this->getNextAdultsMax()
-      : $this->_getMin($this->_session_activity->getEffectifInscriptionMax(),
+      : $this->_getMin($this->getEffectifInscriptionMax(),
                        ($this->_remainingAdultsForQueue() + $registration->getAdults()));
   }
 
 
-  public function getNextChildrenMax() {
+  public function getNextChildrenMax() : int {
     if (!$this->_session_with_quotas)
       return 0;
 
     return $this->_is_max_registration_limited
-      ? $this->_session_activity->getEffectifInscriptionChildMax()
-      : $this->getEffectifChildMax();
+      ? $this->getEffectifInscriptionChildMax()
+      : $this->getEffectifChildMaxOrTotal();
   }
 
 
-  public function getNextChildrenMaxQueue() {
+  public function getNextChildrenMaxQueue() : int {
     return $this->_session_with_quotas
-      ? $this->_getMin($this->_session_activity->getEffectifInscriptionChildMax(),
+      ? $this->_getMin($this->getEffectifInscriptionChildMax(),
                        $this->_remainingChildrenForQueue())
       : 0;
   }
 
 
-  public function getNextChildrenMaxFor($registration) {
+  public function getNextChildrenMaxFor(Class_SessionActivityInscription $registration) : int {
     if (!$this->_session_with_quotas)
       return 0;
 
     return $registration->isQueue()
       ? $this->getNextChildrenMax()
-      : $this->_getMin($this->_session_activity
-                       ->getEffectifInscriptionChildMax(),
+      : $this->_getMin($this->getEffectifInscriptionChildMax(),
                        ($this->_remainingChildrenForQueue() + $registration->getChildren()));
   }
 
 
-  public function withQueuedInscriptionDo($callback) {
+  public function withQueuedInscriptionDo($callback) : self {
     $collection = new Storm_Model_Collection($this->_session_activity
                                              ->getSessionActivityInscriptions());
 
     $collection = $collection
-      ->select(function($inscription)
-               {
-                 return $inscription->isQueue();
-               });
+      ->select(fn($inscription) => $inscription->isQueue());
 
     $collection
-      ->uasort(function($inscription_1, $inscription_2)
-               {
-                 return strcmp($inscription_1->getCreatedAt(), $inscription_2->getCreatedAt());
-               });
+      ->uasort(fn($inscription_1, $inscription_2) => strcmp($inscription_1->getCreatedAt(),
+                                                            $inscription_2->getCreatedAt()));
 
     $collection->eachDo($callback);
 
@@ -351,25 +440,25 @@ class Class_SessionActivityAttendeesWithQueue extends Class_SessionActivityAtten
   }
 
 
-  protected function _remainingAdults() {
-    return $this->_session_activity->getEffectifInscriptionMax();
+  protected function _remainingAdults() : int {
+    return $this->getEffectifInscriptionMax();
   }
 
 
-  protected function _remainingAdultsForQueue() {
-    return $this->getEffectifMax() - $this->numberOfAdults();
+  protected function _remainingAdultsForQueue() : int {
+    return $this->getEffectifMaxOrTotal() - $this->numberOfAdults();
   }
 
 
-  protected function _remainingChildren() {
+  protected function _remainingChildren() : int {
     if (!$this->_session_with_quotas)
       return 0;
 
-    return $this->_session_activity->getEffectifInscriptionChildMax();
+    return $this->getEffectifInscriptionChildMax();
   }
 
 
-  protected function _remainingChildrenForQueue() {
-    return $this->getEffectifChildMax() - $this->numberOfChildren();
+  protected function _remainingChildrenForQueue() : int {
+    return $this->getEffectifChildMaxOrTotal() - $this->numberOfChildren();
   }
-}
\ No newline at end of file
+}
diff --git a/library/Class/SessionActivityInscription.php b/library/Class/SessionActivityInscription.php
index a4af03a79d8..0cd2dadbb96 100644
--- a/library/Class/SessionActivityInscription.php
+++ b/library/Class/SessionActivityInscription.php
@@ -96,10 +96,34 @@ class Class_SessionActivityInscription extends Storm_Model_Abstract {
                        0 < $this->getAdults() || 0 < $this->getChildren(),
                        $this->_('Au moins un adulte ou un enfant doit s\'inscrire'));
 
+    if ($this->_checkAttributeTotal())
+      return;
+
     $this
       ->_checkRemaining('adults', 'next_adults_max', [$this, '_adultsRemainingError'])
-      ->_checkRemaining('children', 'next_children_max', [$this, '_childrenRemainingError'])
-      ;
+      ->_checkRemaining('children', 'next_children_max', [$this, '_childrenRemainingError']);
+  }
+
+
+  protected function _checkAttributeTotal() : bool {
+    $remaining = $this->isNew()
+      ? $this->getSessionActivity()->getNextTotalFor($this)
+      : $this->_getUserSessionAttribute('next_total_for');
+
+    if ($remaining < 0)
+      return false;
+
+    $plural = $this->_plural($remaining,
+                             'aucune restante',
+                             '1 restante',
+                             '%d restantes',
+                             $remaining);
+    $error_message = $this->_('Le nombre de participants au total est supérieur au nombre de places total disponibles (%s)',
+                              $plural);
+    $this->checkAttribute('adults', false, $error_message);
+    $this->checkAttribute('children', false, $error_message);
+
+    return true;
   }
 
 
diff --git a/library/Class/User/SessionActivity.php b/library/Class/User/SessionActivity.php
index 34fdb7f2b0c..81e8039c6f3 100644
--- a/library/Class/User/SessionActivity.php
+++ b/library/Class/User/SessionActivity.php
@@ -58,37 +58,52 @@ class Class_User_SessionActivity {
   }
 
 
-  public function isFullAdults() {
+  public function isFullAdults() : bool {
     return $this->_session_activity->isFullAdults();
   }
 
 
-  public function isFullChildren() {
+  public function isFullChildren() : bool {
     return $this->_session_activity->isFullChildren();
   }
 
 
-  public function getNextAdultsMax() {
+  public function getEffectifInscriptionMax() : int {
+    return $this->_session_activity->getEffectifInscriptionMax();
+  }
+
+
+  public function getEffectifInscriptionChildMax() : int {
+    return $this->_session_activity->getEffectifInscriptionChildMax();
+  }
+
+
+  public function getNextTotalFor() : int {
+    return $this->_session_activity->getNextTotalFor($this->_inscription);
+  }
+
+
+  public function getNextAdultsMax() : int {
     return $this->_session_activity->getNextAdultsMaxFor($this->_inscription);
   }
 
 
-  public function getNextChildrenMax() {
+  public function getNextChildrenMax() : int {
     return $this->_session_activity->getNextChildrenMaxFor($this->_inscription);
   }
 
 
-  public function getAgeChildMax() {
+  public function getAgeChildMax() : int {
     return $this->_session_activity->getAgeChildMax();
   }
 
 
-  public function getAgeChildMin() {
+  public function getAgeChildMin() : int {
     return $this->_session_activity->getAgeChildMin();
   }
 
 
-  public function isQueueAttendees() {
+  public function isQueueAttendees() : bool {
     return $this->_session_activity->isQueueAttendees();
   }
 }
@@ -97,12 +112,18 @@ class Class_User_SessionActivity {
 
 
 class Class_User_SessionActivityNull extends Class_User_SessionActivity {
-  public function getNextAdultsMax() {
+
+  public function getNextAdultsMax() : int {
     return 0;
   }
 
 
-  public function getNextChildrenMax() {
+  public function getNextChildrenMax() : int {
     return 0;
   }
+
+
+  public function getNextTotalFor() : int {
+    return -1;
+  }
 }
diff --git a/library/ZendAfi/Controller/Plugin/Manager/Manager.php b/library/ZendAfi/Controller/Plugin/Manager/Manager.php
index ed2ae909c0e..63a7a6571e2 100644
--- a/library/ZendAfi/Controller/Plugin/Manager/Manager.php
+++ b/library/ZendAfi/Controller/Plugin/Manager/Manager.php
@@ -308,7 +308,6 @@ class ZendAfi_Controller_Plugin_Manager_Manager
 
   protected function _setupFormAndSave($model) {
     $form = $this->_getForm($model);
-
     $this->_view->form = $form;
     if (!$this->_request->isPost())
       return false;
diff --git a/library/ZendAfi/Form/Admin/SessionActivity.php b/library/ZendAfi/Form/Admin/SessionActivity.php
index 223e25eae1c..c5862f00240 100644
--- a/library/ZendAfi/Form/Admin/SessionActivity.php
+++ b/library/ZendAfi/Form/Admin/SessionActivity.php
@@ -166,18 +166,20 @@ class ZendAfi_Form_Admin_SessionActivity extends ZendAfi_Form {
     $this
       ->_addNumber('effectif_min', $this->_('Adultes minimum'))
       ->_addNumber('effectif_max', $this->_('Adultes maximum'))
-      ->_addNumber('effectif_inscription_max',  $this->_('Adultes maximum par inscription'))
+      ->_addNumber('effectif_inscription_max',
+                   $this->_('Adultes maximum par inscription'), true)
       ->_addNumber('effectif_child_min', $this->_('Enfants minimum'))
       ->_addNumber('effectif_child_max', $this->_('Enfants maximum'))
-      ->_addNumber('effectif_inscription_child_max', $this->_('Enfants maximum par inscription'))
+      ->_addNumber('effectif_inscription_child_max',
+                   $this->_('Enfants maximum par inscription'), true)
       ->_addNumber('age_child_min', $this->_('Âge minimum des enfants'))
-      ->_addNumber('age_child_max', $this->_('Âge maximum des enfants'));
+      ->_addNumber('age_child_max', $this->_('Âge maximum des enfants'), true)
+      ->_addNumber('effectif_total_min', $this->_('Total minimum de participants'))
+      ->_addNumber('effectif_total_max', $this->_('Total maximum de participants'));
 
     return array_filter($elements,
-                        function($item)
-                        {
-                          return !in_array($item, ['effectif_min', 'effectif_max']);
-                        });
+                        fn($item) => !in_array($item, ['effectif_min',
+                                                       'effectif_max']));
   }
 
 
@@ -190,19 +192,22 @@ class ZendAfi_Form_Admin_SessionActivity extends ZendAfi_Form {
                                 'effectif_child_max',
                                 'effectif_inscription_child_max',
                                 'age_child_min',
-                                'age_child_max'],
+                                'age_child_max',
+                                'effectif_total_min',
+                                'effectif_total_max'],
                                'quotas',
                                ['legend' => $this->_('Effectif')])
       : $this;
   }
 
 
-  protected function _addNumber($name, $label) {
+  protected function _addNumber($name, $label, $required = false) {
     return $this->addElement('number', $name,
                              ['label' => $label,
                               'value' => 0,
                               'min' => 0,
-                              'required' => true,
-                              'allowEmpty' => false]);
+                              'required' => $required,
+                              'allowEmpty' => false
+                             ]);
   }
 }
diff --git a/library/ZendAfi/Form/SessionActivityInscription.php b/library/ZendAfi/Form/SessionActivityInscription.php
index 760bc68acfb..b5fe6b2f739 100644
--- a/library/ZendAfi/Form/SessionActivityInscription.php
+++ b/library/ZendAfi/Form/SessionActivityInscription.php
@@ -59,7 +59,8 @@ class ZendAfi_Form_SessionActivityInscription extends ZendAfi_Form {
     $element_adult = $this->getElement('adults');
     $element_adult->setAttrib('max', $session_user->getNextAdultsMax());
 
-    if ($session_user->isFullAdults()) {
+    if ($session_user->isFullAdults()
+        || $session_user->getEffectifInscriptionMax() <= 0) {
       $element_adult
         ->setLabel($this->_getMessages()->noMoreAdultRoom())
         ->setAttrib('disabled', 'disabled');
@@ -80,7 +81,8 @@ class ZendAfi_Form_SessionActivityInscription extends ZendAfi_Form {
     $element_children = $this->getElement('children');
     $element_children->setAttrib('max', $session_user->getNextChildrenMax());
 
-    if ($session_user->isFullChildren()) {
+    if ($session_user->isFullChildren()
+        || $session_user->getEffectifInscriptionChildMax() <= 0) {
       $element_children
         ->setLabel($this->_getMessages()->noMoreChildRoom())
         ->setAttrib('disabled', 'disabled');
diff --git a/library/ZendAfi/View/Helper/RenderSession.php b/library/ZendAfi/View/Helper/RenderSession.php
index a6e4398d3a9..c93ff9736fc 100644
--- a/library/ZendAfi/View/Helper/RenderSession.php
+++ b/library/ZendAfi/View/Helper/RenderSession.php
@@ -113,22 +113,25 @@ class Render_Session_Dl extends Render_Session {
 
 
   protected function definitionListFor($session) {
-    $html = $this->_getDisplayTitleValue($this->_('Informations'),
-                                         $this->_getInformations($session));
+    $html = $this->_getDisplayTitleValue($this->_('Contenu'),
+                                         $session->getContenu());
 
-    $html .= $this->_getDisplayTitleValue($this->_('Lieu'),
-                                          $this->view->renderLieu($session->getLieu(),
-                                                                  ['size' => '300x300']));
+    $html .= $this->_getDisplayTitleValue($this->_('Informations'),
+                                          $this->_getInformations($session));
+
+    $html .= $this
+      ->_getDisplayTitleValue($this->_('Lieu'),
+                              $this->view->renderLieu($session->getLieu(),
+                                                      ['size' => '300x300']));
 
     $html .= $this->_getLimiteInscription($session);
 
     $html .= $this->_getDisplayTitleValue($this->_('Date de début'),
                                           $session->getDateDebutTexte());
 
-    if ($session->hasDateFin()) {
+    if ($session->hasDateFin())
       $html .= $this->_getDisplayTitleValue($this->_('Date de fin'),
                                             $session->getDateFinTexte());
-    }
 
     $html .= $this->_getDisplayTitleValue($this->_('Horaires'),
                                           $session->getHoraires());
@@ -148,9 +151,6 @@ class Render_Session_Dl extends Render_Session {
     $html .= $this->_getDisplayTitleValue($this->_('Intervenants'),
                                           $this->_getIntervenantsFor($session));
 
-    $html .= $this->_getDisplayTitleValue($this->_('Contenu'),
-                                          $session->getContenu());
-
     $html .= $this->displayCustomFields($session);
 
     return $this->view->tag('dl', $html , ['class' => 'session_activity']);
diff --git a/library/templates/Intonation/Library/View/Wrapper/ActivitySession.php b/library/templates/Intonation/Library/View/Wrapper/ActivitySession.php
index c5f23e1bd45..b46190b6ee1 100644
--- a/library/templates/Intonation/Library/View/Wrapper/ActivitySession.php
+++ b/library/templates/Intonation/Library/View/Wrapper/ActivitySession.php
@@ -165,15 +165,18 @@ class Intonation_Library_View_Wrapper_ActivitySession
   public function getEmbedMedia() {
     if ($this->_embed_media)
       return $this->_embed_media;
-    return $this->_embed_media = $this->_withArticleWrapperDo(function($wrapper) { return $wrapper->getEmbedMedia();});
+
+    return $this->_embed_media = $this
+      ->_withArticleWrapperDo(fn($wrapper) => $wrapper->getEmbedMedia());
   }
 
 
   public function getHtmlPicture() {
-    if ($embed_media = $this->getEmbedMedia())
+    if ($this->getEmbedMedia())
       return '';
 
-    return ($html = $this->_withArticleWrapperDo(function($wrapper) { return $wrapper->getHtmlPicture();}))
+    return ($html = $this
+            ->_withArticleWrapperDo(fn($wrapper) => $wrapper->getFirstTagPicture()))
       ? $html
       : $this->_view->mapForLieu($this->_model->getLieu());
   }
@@ -186,10 +189,13 @@ class Intonation_Library_View_Wrapper_ActivitySession
     if ($media = $this->_mediaInSession($callback))
       return $media;
 
-    If ( ! $activity = $this->_model->getActivity())
+    if ( ! $activity = $this->_model->getActivity())
       return '';
 
-    If ( ! $description = $activity->getDescription())
+    $description = $activity->getDescription();
+    if (!$description)
+      $description = $this->_model->getContenu();
+    if (!$description)
       return '';
 
     $article = Class_Article::newInstance(['contenu' => $description]);
diff --git a/library/templates/Intonation/Library/View/Wrapper/Article.php b/library/templates/Intonation/Library/View/Wrapper/Article.php
index e2a68ea2310..8ded26ec6ad 100644
--- a/library/templates/Intonation/Library/View/Wrapper/Article.php
+++ b/library/templates/Intonation/Library/View/Wrapper/Article.php
@@ -269,6 +269,13 @@ class Intonation_Library_View_Wrapper_Article extends Intonation_Library_View_Wr
   }
 
 
+  public function getFirstTagPicture() : string {
+    return ($image = $this->_model->getFirstImageURL())
+      ? $this->_view->tagImg($image)
+      : $this->getHtmlPicture();
+  }
+
+
   public function getOsmData() {
     if (!$location = $this->_model->getLieu())
       return null;
diff --git a/tests/application/modules/admin/controllers/SessionActivityInscriptionControllerTest.php b/tests/application/modules/admin/controllers/SessionActivityInscriptionControllerTest.php
index 1b7870d3da7..9a06f069dc5 100644
--- a/tests/application/modules/admin/controllers/SessionActivityInscriptionControllerTest.php
+++ b/tests/application/modules/admin/controllers/SessionActivityInscriptionControllerTest.php
@@ -38,17 +38,17 @@ abstract class Admin_SessionActivityInscriptionControllerTestCase
   public function setUp() {
     parent::setUp();
 
-    $this->_group_profs = $this->fixture('Class_UserGroup',
+    $this->_group_profs = $this->fixture(Class_UserGroup::class,
                                          ['id' => 344,
                                           'libelle' => 'Profs',
                                           'rights' => [Class_UserGroup::RIGHT_DIRIGER_ACTIVITY]]);
 
-    $this->_groupe_stagiaires = $this->fixture('Class_UserGroup',
+    $this->_groupe_stagiaires = $this->fixture(Class_UserGroup::class,
                                                ['id' => 12,
                                                 'libelle' => 'Stagiaires',
                                                 'rights' => [Class_UserGroup::RIGHT_SUIVRE_ACTIVITY]]);
 
-    $this->_prof_laurent = $this->fixture('Class_users',
+    $this->_prof_laurent = $this->fixture(Class_users::class,
                                           ['id' => 34,
                                            'nom' => 'Laffont',
                                            'prenom' => 'Laurent',
@@ -56,7 +56,7 @@ abstract class Admin_SessionActivityInscriptionControllerTestCase
                                            'password' => 'pwd',
                                            'user_groups' => [$this->_group_profs]]);
 
-    $this->_amandine = $this->fixture('Class_Users',
+    $this->_amandine = $this->fixture(Class_Users::class,
                                       ['id' => 10,
                                        'nom' => 'Pistache',
                                        'prenom' => 'Amandine',
@@ -65,7 +65,7 @@ abstract class Admin_SessionActivityInscriptionControllerTestCase
                                        'mail' => 'pist@che.io',
                                        'user_groups' => [$this->_groupe_stagiaires]]);
 
-    $this->_patrick = $this->fixture('Class_Users',
+    $this->_patrick = $this->fixture(Class_Users::class,
                                      ['id' => 5,
                                       'id_site' => 12,
                                       'login' => 'Pat',
@@ -75,16 +75,16 @@ abstract class Admin_SessionActivityInscriptionControllerTestCase
                                       'mail' => 'user@server.org',
                                       'user_groups' => [$this->_groupe_stagiaires]]);
 
-    $this->_salle_reunion = $this->fixture('Class_Lieu',
+    $this->_salle_reunion = $this->fixture(Class_Lieu::class,
                                            ['id' => 12,
                                             'libelle' => 'Salle reunion AFI']);
 
-    $this->_learn_java = $this->fixture('Class_Activity',
+    $this->_learn_java = $this->fixture(Class_Activity::class,
                                         ['id' => 3,
                                          'libelle' => 'Learn Java',
                                          'description' => 'Here you will learn some old and boring stuff']);
 
-    $inscription = $this->fixture('Class_SessionActivityInscription',
+    $inscription = $this->fixture(Class_SessionActivityInscription::class,
                                   ['id' => 165,
                                    'stagiaire_id' => 5,
                                    'session_activity_id' => 32,
@@ -92,7 +92,7 @@ abstract class Admin_SessionActivityInscriptionControllerTestCase
                                    'children' => 2,
                                   ]);
 
-    $this->fixture('Class_SessionActivity',
+    $this->fixture(Class_SessionActivity::class,
                    ['id' => 32,
                     'activity' => $this->_learn_java,
                     'date_debut' => '2012-03-27',
@@ -101,6 +101,8 @@ abstract class Admin_SessionActivityInscriptionControllerTestCase
                     'effectif_max' => 25,
                     'effectif_child_min' => 1,
                     'effectif_child_max' => 5,
+                    'effectif_total_min' => 0,
+                    'effectif_total_max' => 0,
                     'age_child_max' => 5,
                     'effectif_inscription_max' => 2,
                     'effectif_inscription_child_max' => 2,
@@ -256,7 +258,10 @@ class Admin_SessionActivityInscriptionControllerSubscribeValidationTest
 
   /** @test */
   public function subscribeFullSessionShouldRedirectWithError() {
-    Class_SessionActivity::find(32)->setEffectifMax(1);
+    Class_SessionActivity::find(32)
+      ->setEffectifMin(1)
+      ->setEffectifMax(1)
+      ->assertSave();
     $this->dispatch('/admin/session-activity-inscription/subscribe/id/32/stagiaire_id/10');
     $this->assertFlashMessengerContentContains('Inscription impossible, plus de place disponible.');
     $this->assertRedirect();
@@ -295,4 +300,4 @@ class Admin_SessionActivityInscriptionControllerUnsubscribePatSessionMarsJavaTes
   public function removableShouldBeNotified() {
     $this->assertFlashMessengerContentContains('Le participant a bien été désinscrit');
   }
-}
\ No newline at end of file
+}
diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php
index 5cd1eec4cb3..9870818b37a 100644
--- a/tests/db/UpgradeDBTest.php
+++ b/tests/db/UpgradeDBTest.php
@@ -4585,3 +4585,31 @@ class UpgradeDB_431_Test extends UpgradeDBTestCase {
     parent::tearDown();
   }
 }
+
+
+
+
+class UpgradeDB_432_Test extends UpgradeDBTestCase {
+
+  protected $_columns = ['effectif_total_min',
+                         'effectif_total_max'];
+
+  public function prepare() {
+    $this->dropFieldsFrom('session_activity', $this->_columns);
+  }
+
+
+  public function columns() {
+    return array_map(fn($column) => [$column],
+                     $this->_columns);
+  }
+
+
+  /**
+   * @test
+   * @dataProvider columns
+   */
+  public function sessionActivityShouldContainsColumn($column) {
+    $this->assertFieldType('session_activity', $column, 'int(11) unsigned');
+  }
+}
diff --git a/tests/scenarios/Activities/AbonneControllerActivitiesTest.php b/tests/scenarios/Activities/AbonneControllerActivitiesTest.php
index 18e286b665d..1b9070cd63f 100644
--- a/tests/scenarios/Activities/AbonneControllerActivitiesTest.php
+++ b/tests/scenarios/Activities/AbonneControllerActivitiesTest.php
@@ -1376,7 +1376,7 @@ class AbonneControllerActivitiesSessionJuilletPythonDetailRetourFicheTest extend
 
   /** @test */
   public function pageShouldContainsAButtontoGoBackToFicheAbonne() {
-    $this->assertXPathContentContains('//a[contains(@href, "abonne/fiche")]', 'Retour', $this->_response->getBody());
+    $this->assertXPathContentContains('//a[contains(@href, "abonne/fiche")]', 'Retour');
   }
 
 }
diff --git a/tests/scenarios/Activities/AbonneControllerWithQuotasTest.php b/tests/scenarios/Activities/AbonneControllerWithQuotasTest.php
index 017f3e75d21..2d194763510 100644
--- a/tests/scenarios/Activities/AbonneControllerWithQuotasTest.php
+++ b/tests/scenarios/Activities/AbonneControllerWithQuotasTest.php
@@ -57,7 +57,7 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
     $this->_mail_transport = new MockMailTransport();
     Zend_Mail::setDefaultTransport($this->_mail_transport);
 
-    $this->_amadou = $this->fixture('Class_Users',
+    $this->_amadou = $this->fixture(Class_Users::class,
                                     ['id' => 435,
                                      'nom' => 'Dou',
                                      'prenom' => 'Ama',
@@ -70,22 +70,24 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
                                      'idabon' => 435]);
     $this->_amadou
       ->beAbonneSIGB()
-      ->setUserGroups([$this->fixture('Class_UserGroup',['id' => 23])->addRightSuivreActivity()])
+      ->setUserGroups([$this->fixture(Class_UserGroup::class,
+                                      ['id' => 23])
+                       ->addRightSuivreActivity()])
       ->assertSave();
 
     ZendAfi_Auth::getInstance()->logUser($this->_amadou);
 
-    $this->_gallice_cafe = $this->fixture('Class_Lieu',
+    $this->_gallice_cafe = $this->fixture(Class_Lieu::class,
                                           ['id' => 98,
                                            'libelle' => 'Galice']);
 
 
-    $this->_bib_romains = $this->fixture('Class_Lieu',
+    $this->_bib_romains = $this->fixture(Class_Lieu::class,
                                          ['id' => '99',
                                           'libelle' => 'Bibliothèque des romains']);
 
 
-    $this->_bonlieu = $this->fixture('Class_Lieu',
+    $this->_bonlieu = $this->fixture(Class_Lieu::class,
                                      ['id' => 100,
                                       'libelle' => 'Bonlieu',
                                       'adresse' => "1, rue Jean-Jaures\nBP 294",
@@ -95,12 +97,12 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
                                       'longitude' => '6.128715']);
 
     $this->_learn_smalltalk = $this
-      ->fixture('Class_Activity',
+      ->fixture(Class_Activity::class,
                 ['id' => 1,
                  'libelle' => 'Learn Smalltalk']);
 
     $this->_session_smalltalk_janvier = $this
-      ->fixture('Class_SessionActivity',
+      ->fixture(Class_SessionActivity::class,
                 ['id' => 11,
                  'activity' => $this->_learn_smalltalk,
                  'effectif_min' => 1,
@@ -113,7 +115,7 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
                  'stagiaires' => []]);
 
     $this->_session_smalltalk_juillet = $this
-      ->fixture('Class_SessionActivity',
+      ->fixture(Class_SessionActivity::class,
                 ['id' => 12,
                  'activity' => $this->_learn_smalltalk,
                  'effectif_min' => 1,
@@ -131,13 +133,13 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
       ->assertSave();
 
 
-    $this->_learn_java = $this->fixture('Class_Activity',
+    $this->_learn_java = $this->fixture(Class_Activity::class,
                                         ['id' => 3,
                                          'libelle' => 'Learn Java',
                                          'description' => 'whaaat ?']);
 
 
-    $this->_session_java_fevrier = $this->fixture('Class_SessionActivity',
+    $this->_session_java_fevrier = $this->fixture(Class_SessionActivity::class,
                                                   ['id' => 31,
                                                    'activity' => $this->_learn_java,
                                                    'effectif_min' => 2,
@@ -149,7 +151,7 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
                                                    'stagiaires' => [],
                                                    'date_limite_fin' => '2015-01-20']);
 
-    $this->_session_java_fevrier->setArticle($this->fixture('Class_Article',
+    $this->_session_java_fevrier->setArticle($this->fixture(Class_Article::class,
                                                             ['id' => 10,
                                                              'titre' => 'Java est mort, vive python !',
                                                              'contenu' => 'Java has been'])
@@ -159,7 +161,7 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
                                 ->save();
 
 
-    $this->_session_java_mars = $this->fixture('Class_SessionActivity',
+    $this->_session_java_mars = $this->fixture(Class_SessionActivity::class,
                                                ['id' => 32,
                                                 'activity' => $this->_learn_java,
                                                 'effectif_min' => 2,
@@ -170,7 +172,7 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
                                                 'stagiaires' => [],
                                                 'date_limite_fin' => '2015-03-01']);
 
-    $this->_session_java_septembre = $this->fixture('Class_SessionActivity',
+    $this->_session_java_septembre = $this->fixture(Class_SessionActivity::class,
                                                     ['id' => 30,
                                                      'activity' => $this->_learn_java,
                                                      'effectif_min' => 2,
@@ -190,12 +192,12 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
       ->assertSave();
 
 
-    $this->_learn_python = $this->fixture('Class_Activity',
+    $this->_learn_python = $this->fixture(Class_Activity::class,
                                           ['id' => 12,
                                            'libelle' => 'Learn Python']);
 
     $this->_session_python_juillet = $this
-      ->fixture('Class_SessionActivity',
+      ->fixture(Class_SessionActivity::class,
                 ['id' => 121,
                  'activity' => $this->_learn_python,
                  'date_debut' => '2014-07-10',
@@ -214,14 +216,14 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
                  'horaires' => '8h-12h, 14h-18h',
                  'lieu' => $this->_bib_romains,
                  'stagiaires' => [$this->_amadou],
-                 'intervenants' => [$this->fixture('Class_Users',
+                 'intervenants' => [$this->fixture(Class_Users::class,
                                                    ['id' =>76,
                                                     'login' => 'jpp',
                                                     'password' => 'pwd',
                                                     'nom' => 'Pirant',
                                                     'prenom' => 'Jean-Paul',
                                                     'mail' => 'jp@bokeh.fr']),
-                                    $this->fixture('Class_users',
+                                    $this->fixture(Class_users::class,
                                                    ['id' => 77,
                                                     'login' => 'cc',
                                                     'password' => 'pwd',
@@ -235,7 +237,7 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
       ->assertSave();
 
     $inscription_amadou_python = $this
-      ->fixture('Class_SessionActivityInscription',
+      ->fixture(Class_SessionActivityInscription::class,
                 ['id' => 1,
                  'stagiaire' => $this->_amadou,
                  'session_activity' => $this->_session_python_juillet,
@@ -245,12 +247,12 @@ abstract class AbonneControllerWithQuotasTestCase extends AbstractControllerTest
     $this->_amadou->setSessionActivityInscriptions([$inscription_amadou_python]);
 
 
-    $this->fixture('Class_CustomField_Meta',
+    $this->fixture(Class_CustomField_Meta::class,
                    ['id' => 1,
                     'label' => 'Noms et prénoms',
                     'field_type' => Class_CustomField_Meta::TEXT_AREA]);
 
-    $this->fixture('Class_CustomField',
+    $this->fixture(Class_CustomField::class,
                    ['id' => 1,
                     'meta_id' => 1,
                     'priority' => 1,
@@ -294,19 +296,14 @@ class Activities_AbonneControllerWithQuotasRegisteredActionTest
 abstract class AbonneControllerWithQuotasEditSessionTest
   extends AbonneControllerWithQuotasTestCase {
 
-  protected $_inscription,
+  protected
+    $_inscription,
     $_other_inscription;
 
   public function setUp() {
     parent::setUp();
-    Class_AdminVar::set('ACTIVITY_SESSION_QUOTAS', 1);
-    $this->_session_python_juillet
-      ->resetAttendees()
-      ->setEffectifMax(5)
-      ->setEffectifChildMax(15)
-      ->setEffectifInscriptionMax(3)
-      ->setEffectifInscriptionChildMax(12);
 
+    $this->_sessionActivity();
     $this->_other_inscription = $this->_register(1, 1);
     $this->_inscription = $this->_register(1, 1);
     $this->_inscription->setStagiaire($this->_amadou)
@@ -314,6 +311,17 @@ abstract class AbonneControllerWithQuotasEditSessionTest
   }
 
 
+  protected function _sessionActivity() {
+    $this->_session_python_juillet
+      ->resetAttendees()
+      ->setEffectifMax(5)
+      ->setEffectifChildMax(15)
+      ->setEffectifInscriptionMax(3)
+      ->setEffectifInscriptionChildMax(12)
+      ->assertSave();
+  }
+
+
   protected function _register($adults, $children) {
     $inscription = Class_SessionActivityInscription::newInstance(['session_activity_id' => 121,
                                                                   'adults' => $adults,
@@ -434,6 +442,86 @@ class Activities_AbonneControllerWithQuotasBadUserTest
 
 
 
+class Activities_AbonneControllerWithQuotasEditSessionActionWithOnlyTotalTest
+  extends AbonneControllerWithQuotasEditSessionTest {
+
+  public function setUp() {
+    parent::setUp();
+    $this->dispatch('/abonne/edit-session/id/' . $this->_inscription->getId());
+  }
+
+
+  protected function _sessionActivity() {
+    $this->_session_python_juillet
+      ->resetAttendees()
+      ->setEffectifMin(0)
+      ->setEffectifChildMin(0)
+      ->setEffectifMax(0)
+      ->setEffectifChildMax(0)
+      ->setEffectifInscriptionMax(6)
+      ->setEffectifInscriptionChildMax(6)
+      ->setEffectifTotalMin(1)
+      ->setEffectifTotalMax(6)
+      ->assertSave();
+
+    Class_SessionActivityInscription::find(1)->delete();
+  }
+
+
+  /** @test */
+  public function inputAdultsShouldHaveValueOneAndMaxTwo() {
+    $this->assertXPath('//input[@name="adults"][@value="1"][@max="3"]');
+  }
+
+
+  /** @test */
+  public function inputChildrenShouldHaveValueOneAndMaxTwo() {
+    $this->assertXPath('//input[@name="children"][@value="1"][@max="3"]');
+  }
+}
+
+
+
+
+class Activities_AbonneControllerWithQuotasEditSessionActionWithTotalAndMaxTest
+  extends AbonneControllerWithQuotasEditSessionTest {
+
+  public function setUp() {
+    parent::setUp();
+    $this->dispatch('/abonne/edit-session/id/' . $this->_inscription->getId());
+  }
+
+
+  protected function _sessionActivity() {
+    $this->_session_python_juillet
+      ->resetAttendees()
+      ->setEffectifMin(0)
+      ->setEffectifChildMin(0)
+      ->setEffectifMax(3)
+      ->setEffectifChildMax(5)
+      ->setEffectifInscriptionMax(3)
+      ->setEffectifInscriptionChildMax(4)
+      ->setEffectifTotalMin(1)
+      ->setEffectifTotalMax(10)
+      ->assertSave();
+  }
+
+
+  /** @test */
+  public function inputAdultsShouldHaveValueOneAndMaxTwo() {
+    $this->assertXPath('//input[@name="adults"][@value="1"][@max="2"]');
+  }
+
+
+  /** @test */
+  public function inputChildrenShouldHaveValueOneAndMaxFor() {
+    $this->assertXPath('//input[@name="children"][@value="1"][@max="4"]');
+  }
+}
+
+
+
+
 class Activities_AbonneControllerWithQuotasRegisterSessionTest
   extends AbonneControllerWithQuotasTestCase {
 
@@ -526,6 +614,49 @@ class Activities_AbonneControllerWithQuotasOpenSessionSubscriptionWithoutRigthsT
 
 
 
+class Activities_AbonneControllerWithQuotasWithTotalEffectifTest
+  extends AbonneControllerWithQuotasTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    Class_SessionActivity::find(31)->setEffectifMax(0)
+                                   ->setEffectifMin(0)
+                                   ->setEffectifChildMax(0)
+                                   ->setEffectifChildMin(0)
+                                   ->setEffectifTotalMin(2)
+                                   ->setEffectifTotalMax(7)
+                                   ->setEffectifInscriptionChildMax(2)
+                                   ->assertSave();
+  }
+
+
+  /** @test */
+  public function sessionShouldBeDisplayed() {
+    $this->dispatch('/opac/abonne/activities');
+    $this->assertXPath('//td[text()="10 février 2015"]');
+  }
+
+
+  /** @test */
+  public function subscribeSessionShouldBeOK() {
+    $this->postDispatch('/opac/abonne/inscrire-session/id/31',
+                        ['adults' => 1, 'children' => 1]);
+    $this->assertRedirectTo('/activities');
+  }
+
+
+  /** @test */
+  public function subscribeWithTooManyChildrenShouldDisplayError() {
+    $this->postDispatch('/opac/abonne/inscrire-session/id/31',
+                        ['adults' => 5, 'children' => 5]);
+
+    $this->assertXPathContentContains('//ul[@class="errors"]//li', 'Le nombre de participants au total est supérieur au nombre de places total disponibles (7 restantes)');
+  }
+}
+
+
+
+
 abstract class AbonneControllerWithQuotasRegisterSessionPostTestCase
   extends AbonneControllerWithQuotasTestCase {
 
@@ -687,12 +818,81 @@ class Activities_AbonneControllerWithQuotasRegisterSessionMaxQuotasErrosPostTest
 
 
 
+class Activities_AbonneControllerWithQuotasRegisterSessionMaxQuotasErrosWithOnlyTotalPostTest
+  extends AbonneControllerWithQuotasRegisterSessionPostTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    $this->_session_java_fevrier
+      ->setEffectifInscriptionMax(2)
+      ->setEffectifInscriptionChildMax(3)
+      ->setEffectifTotalMin(1)
+      ->setEffectifTotalMax(10)
+      ->setEffectifMin(0)
+      ->setEffectifMax(0)
+      ->setEffectifChildMin(0)
+      ->setEffectifChildMax(0)
+      ->setAgeChildMax(12);
+
+    $this->_postAdultsAndChildren(4, 5);
+  }
+
+
+  /** @test */
+  public function shouldDisplayTooManyAdults() {
+    $this->assertXPathContentContains('//ul[@class="errors"]', 'Le nombre d\'adultes est supérieur au nombre de places adultes disponibles (2 restantes)');
+  }
+
+
+  /** @test */
+  public function shouldDisplayTooManyChildren() {
+    $this->assertXPathContentContains('//ul[@class="errors"]', 'Le nombre d\'enfants est supérieur au nombre de places enfants disponibles (3 restantes)');
+  }
+}
+
+
+
+
+class Activities_AbonneControllerWithQuotasRegisterSessionMaxQuotasErrosWithTotalAndMaxPostTest
+  extends AbonneControllerWithQuotasRegisterSessionPostTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    $this->_session_java_fevrier
+      ->setEffectifInscriptionMax(3)
+      ->setEffectifInscriptionChildMax(4)
+      ->setEffectifTotalMin(1)
+      ->setEffectifTotalMax(10)
+      ->setEffectifMin(0)
+      ->setEffectifMax(3)
+      ->setEffectifChildMin(0)
+      ->setEffectifChildMax(4)
+      ->setAgeChildMax(12);
+
+    $this->_postAdultsAndChildren(4, 5);
+  }
+
+
+  /** @test */
+  public function shouldDisplayTooManyAdults() {
+    $this->assertXPathContentContains('//ul[@class="errors"]', 'Le nombre d\'adultes est supérieur au nombre de places adultes disponibles (3 restantes)',$this->_response->getBody());
+  }
+
+
+  /** @test */
+  public function shouldDisplayTooManyChildren() {
+    $this->assertXPathContentContains('//ul[@class="errors"]', 'Le nombre d\'enfants est supérieur au nombre de places enfants disponibles (4 restantes)');
+  }
+}
+
+
+
+
 class Activities_AbonneControllerWithQuotasRegisterSessionChildAgeMaxPostTest
   extends AbonneControllerWithQuotasRegisterSessionPostTestCase {
 
   /** @test */
   public function nombreEnfantsShouldContainAgeMax() {
-    Class_AdminVar::set('ACTIVITY_SESSION_QUOTAS', 1);
     $this->_session_java_mars
       ->setEffectifInscriptionMax(5)
       ->setEffectifInscriptionChildMax(10)
@@ -710,6 +910,56 @@ class Activities_AbonneControllerWithQuotasRegisterSessionChildAgeMaxPostTest
 
 
 
+class Activities_AbonneControllerWithQuotasRegisterSessionTotalWithoutInscriptionTest
+  extends AbonneControllerWithQuotasRegisterSessionPostTestCase {
+
+  /** @test */
+  public function nombreEnfantsShouldBeDisabled() {
+    $this->_session_java_mars
+      ->setEffectifInscriptionMax(5)
+      ->setEffectifInscriptionChildMax(0)
+      ->setEffectifMax(0)
+      ->setEffectifChildMax(0)
+      ->setEffectifMin(0)
+      ->setEffectifChildMin(0)
+      ->setEffectifTotalMin(0)
+      ->setEffectifTotalMax(10)
+      ->setAgeChildMax(0)
+      ->setAgeChildMin(0)
+      ->resetAttendees()
+      ->assertSave();
+    $this->dispatch('/abonne/inscrire-session/id/32');
+
+    $this->assertNotXPath('//input[@name="adults"][@disabled="disabled"]');
+    $this->assertXPath('//table//td//input[@name="children"][@disabled="disabled"]');
+  }
+
+
+  /** @test */
+  public function nombreAdultesShouldBeDisabled() {
+    $this->_session_java_mars
+      ->setEffectifInscriptionMax(0)
+      ->setEffectifInscriptionChildMax(5)
+      ->setEffectifMax(0)
+      ->setEffectifChildMax(0)
+      ->setEffectifMin(0)
+      ->setEffectifChildMin(0)
+      ->setEffectifTotalMin(0)
+      ->setEffectifTotalMax(10)
+      ->setAgeChildMax(0)
+      ->setAgeChildMin(0)
+      ->resetAttendees()
+      ->assertSave();
+    $this->dispatch('/abonne/inscrire-session/id/32');
+
+    $this->assertNotXPath('//input[@name="children"][@disabled="disabled"]');
+    $this->assertXPath('//table//td//input[@name="adults"][@disabled="disabled"]');
+  }
+}
+
+
+
+
 class Activities_AbonneControllerWithQuotasRegisterSessionWithNoMoreRoomAllErrorsPostTest
   extends AbonneControllerWithQuotasRegisterSessionPostTestCase {
 
@@ -836,6 +1086,37 @@ class Activities_AbonneControllerWithQuotasRegisterSessionWithNoMoreChildrenPost
 
 
 
+class Activities_AbonneControllerWithQuotasRegisterSessionWithOnlyOneAdultOrChildrenPostTest
+  extends AbonneControllerWithQuotasRegisterSessionPostTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    $this->_session_java_fevrier
+      ->setEffectifInscriptionMax(2)
+      ->setEffectifInscriptionChildMax(3)
+      ->setEffectifMin(0)
+      ->setEffectifMax(0)
+      ->setEffectifChildMin(0)
+      ->setEffectifChildMax(0)
+      ->setEffectifTotalMin(1)
+      ->setEffectifTotalMax(3)
+      ->setAgeChildMax(12)
+      ->assertSave();
+
+    $this->_alreadyRegisteredAdultsAndChildren(1, 1)
+         ->_postAdultsAndChildren(1, 1);
+  }
+
+
+  /** @test */
+  public function pageShouldContainsTooManySubsribersError() {
+    $this->assertXPathContentContains('//ul[@class="errors"]', 'Le nombre de participants au total est supérieur au nombre de places total disponibles (1 restante)');
+  }
+}
+
+
+
+
 class Activities_AbonneControllerWithQuotasNotFullWithQueuePostTest
   extends AbonneControllerWithQuotasTestCase {
 
diff --git a/tests/scenarios/Activities/ActivitiesWithQueueAbonneTest.php b/tests/scenarios/Activities/ActivitiesWithQueueAbonneTest.php
index 7550de9084e..5d262e1b2d9 100644
--- a/tests/scenarios/Activities/ActivitiesWithQueueAbonneTest.php
+++ b/tests/scenarios/Activities/ActivitiesWithQueueAbonneTest.php
@@ -1,4 +1,4 @@
-<?php
+*<?php
 /**
  * Copyright (c) 2012-2021, Agence Française Informatique (AFI). All rights reserved.
  *
@@ -40,12 +40,12 @@ abstract class ActivitiesWithQueueAbonneTestCase extends AbstractControllerTestC
     $this->fixture('Class_Lieu',
                    ['id' => 12,
                     'libelle' => 'Salle reunion AFI']);
-    $groupe = $this->fixture('Class_UserGroup',
+    $groupe = $this->fixture(Class_UserGroup::class,
                              ['id' => 12,
                               'libelle' => 'Stagiaires',
                               'rights' => [Class_UserGroup::RIGHT_SUIVRE_ACTIVITY]]);
 
-    $this->_chichiro = $this->fixture('Class_Users',
+    $this->_chichiro = $this->fixture(Class_Users::class,
                                       ['id' => 435,
                                        'prenom' => 'Chichi',
                                        'nom' => 'Ro',
@@ -57,7 +57,7 @@ abstract class ActivitiesWithQueueAbonneTestCase extends AbstractControllerTestC
 
     ZendAfi_Auth::getInstance()->logUser($this->_chichiro);
 
-    $this->fixture('Class_Users',
+    $this->fixture(Class_Users::class,
                    ['id' => 5,
                     'id_site' => 12,
                     'login' => 'Mononoke',
@@ -66,7 +66,7 @@ abstract class ActivitiesWithQueueAbonneTestCase extends AbstractControllerTestC
                     'nom' => 'Noke',
                     'mail' => 'Mono@noke.org',
                     'user_groups' => [$groupe]]);
-    $this->fixture('Class_Users',
+    $this->fixture(Class_Users::class,
                    ['id' => 123,
                     'id_site' => 12,
                     'login' => 'Totoro',
@@ -75,12 +75,12 @@ abstract class ActivitiesWithQueueAbonneTestCase extends AbstractControllerTestC
                     'nom' => 'Ro',
                     'mail' => 'Toto@ro.org',
                     'user_groups' => [$groupe]]);
-    $this->fixture('Class_Activity',
+    $this->fixture(Class_Activity::class,
                    ['id' => 3,
                     'libelle' => 'Learn Java',
                     'description' => 'Here you will learn some old and boring stuff']);
 
-    $this->fixture('Class_SessionActivity',
+    $this->fixture(Class_SessionActivity::class,
                    ['id' => 35,
                     'activity_id' => 3,
                     'date_debut' => '2021-05-27',
@@ -100,14 +100,14 @@ abstract class ActivitiesWithQueueAbonneTestCase extends AbstractControllerTestC
                     'queue_attendees' => true
                    ]);
 
-    $inscription_mononoke = $this->fixture('Class_SessionActivityInscription',
+    $inscription_mononoke = $this->fixture(Class_SessionActivityInscription::class,
                                            ['id' => 234,
                                             'stagiaire_id' => 5,
                                             'session_activity_id' => 35,
                                             'children' => 5,
                                             'adults' => 5,
                                            ]);
-    $inscription_totoro = $this->fixture('Class_SessionActivityInscription',
+    $inscription_totoro = $this->fixture(Class_SessionActivityInscription::class,
                                          ['id' => 567,
                                           'stagiaire_id' => 123,
                                           'session_activity_id' => 35,
@@ -196,6 +196,46 @@ class ActivitiesWithQueueAbonneWithQuotasFullWithQueueSubscribeTest
 
 
 
+class ActivitiesWithQueueAbonneWithQuotasWithMaxTotalFullWithQueueSubscribeTest
+  extends ActivitiesWithQueueAbonneTestCase {
+
+  public function setUp() {
+    parent::setUp();
+
+    Class_SessionActivity::find(35)
+      ->setEffectifMax(0)
+      ->setEffectifMin(0)
+      ->setEffectifChildMax(0)
+      ->setEffectifChildMin(0)
+      ->setEffectifTotalMax(15)
+      ->setEffectifTotalMin(1)
+      ->assertSave();
+
+    $this->dispatch('/opac/abonne/inscrire-session/id/35');
+  }
+
+
+  /** @test */
+  public function inscrireShouldNotRedirectToActivities() {
+    $this->assertNotRedirectTo('/activities');
+  }
+
+
+  /** @test */
+  public function inputAdultsShouldHaveMaxFive() {
+    $this->assertXPath('//input[@name="adults"][@max="5"]');
+  }
+
+
+  /** @test */
+  public function inputChildrenShouldHaveMaxFive() {
+    $this->assertXPath('//input[@name="children"][@max="5"]');
+  }
+}
+
+
+
+
 class ActivitiesWithQueueAbonneWithQuotasFullWithQueuePostTest
   extends ActivitiesWithQueueAbonneTestCase {
 
@@ -462,6 +502,35 @@ class ActivitiesWithQueueAbonneWithQuotasWithQueueSubscribeTest
     $this->dispatch('/abonne/inscrire-session/id/35');
     $this->assertXPathContentContains('//label[@for="adults"]', 'Nombres d\'adultes: 5 places restantes');
   }
+
+
+  /** @test */
+  public function withTotalMaxPageShouldContainsNombresAdultes3PlacesRestantes() {
+    Class_SessionActivity::find(35)
+      ->setEffectifMax(13)
+      ->setEffectifChildMin(0)
+      ->setEffectifChildMax(0)
+      ->setEffectifTotalMin(1)
+      ->setEffectifTotalMax(18)
+      ->assertSave();
+    $this->dispatch('/abonne/inscrire-session/id/35');
+    $this->assertXPathContentContains('//label[@for="adults"]', 'Nombres d\'adultes: 3 places restantes');
+  }
+
+
+  /** @test */
+  public function withTotalMaxPageShouldContainsNombresAdultes5PlacesRestantes() {
+    Class_SessionActivity::find(35)
+      ->setEffectifMin(0)
+      ->setEffectifMax(0)
+      ->setEffectifChildMin(0)
+      ->setEffectifChildMax(0)
+      ->setEffectifTotalMin(1)
+      ->setEffectifTotalMax(18)
+      ->assertSave();
+    $this->dispatch('/abonne/inscrire-session/id/35');
+    $this->assertXPathContentContains('//label[@for="adults"]', 'Nombres d\'adultes: 5 places restantes');
+  }
 }
 
 
@@ -569,4 +638,88 @@ class ActivitiesWithQueueAbonneWithQuotasFullNotInQueueEditTest
     $this->assertEquals(3, Class_SessionActivityInscription::find(234)->getChildren());
     $this->assertFalse(Class_SessionActivityInscription::find(234)->isQueue());
   }
-}
\ No newline at end of file
+}
+
+
+
+
+class ActivitiesWithQueueAbonneWithQuotasWithTotalFullNotInQueueEditTest
+  extends ActivitiesWithQueueAbonneTestCase {
+
+  protected $_inscription;
+
+  public function setUp() {
+    parent::setUp();
+
+    Class_SessionActivityInscription::find(234)
+      ->setAdults(3)
+      ->setChildren(3)
+      ->assertSave();
+
+    Class_SessionActivity::find(35)
+      ->setEffectifMin(0)
+      ->setEffectifMax(0)
+      ->setEffectifInscriptionChildMax(3)
+      ->setEffectifChildMin(0)
+      ->setEffectifChildMax(0)
+      ->setEffectifTotalMin(1)
+      ->setEffectifTotalMax(12)
+      ->assertSave();
+
+    $this->_inscription = $this->fixture(Class_SessionActivityInscription::class,
+                                         ['id' => 159,
+                                          'stagiaire_id' => 435,
+                                          'session_activity_id' => 35,
+                                          'adults' => 1,
+                                          'queue' => true,
+                                          'created_at' => '2021-04-01 14:00:00'
+                                         ]);
+
+    ZendAfi_Auth::getInstance()->logUser(Class_Users::find(5));
+
+    Class_SessionActivity::find(35)
+      ->addSessionActivityInscription($this->_inscription)
+      ->assertSave();
+  }
+
+
+  /** @test */
+  public function pageShouldContainsAdultsMax4() {
+    $this->dispatch('/abonne/edit-session/id/234');
+    $this->assertXPath('//input[@name="adults"][@max="5"]');
+  }
+
+
+  /** @test */
+  public function inscriptionShouldHaveAdults5AndNotInQueue() {
+    $this->postDispatch('/abonne/edit-session/id/234', ['adults' => 5]);
+    Class_SessionActivityInscription::clearCache();
+    $this->assertEquals(5, Class_SessionActivityInscription::find(234)->getAdults());
+    $this->assertFalse(Class_SessionActivityInscription::find(234)->isQueue());
+  }
+
+
+  /** @test */
+  public function onPostLessAdultsShouldReloadQueue() {
+    $this->postDispatch('/abonne/edit-session/id/234', ['adults' => 2]);
+    Class_SessionActivityInscription::clearCache();
+    $this->assertEquals(2, Class_SessionActivityInscription::find(234)->getAdults());
+    $this->assertFalse(Class_SessionActivityInscription::find(159)->isQueue());
+  }
+
+
+  /** @test */
+  public function pageShouldContainsChildrenMax3() {
+    $this->dispatch('/abonne/edit-session/id/234');
+    $this->assertXPath('//input[@name="children"][@max="3"]');
+  }
+
+
+  /** @test */
+  public function inscriptionShouldHaveChildren3AndNotInQueue() {
+    $this->postDispatch('/abonne/edit-session/id/234', ['children' => 5]);
+    Class_SessionActivityInscription::clearCache();
+    $this->assertEquals(3, Class_SessionActivityInscription::find(234)->getChildren());
+    $this->assertFalse(Class_SessionActivityInscription::find(234)->isQueue());
+  }
+}
diff --git a/tests/scenarios/Activities/ActivitiesWithQueueAdminTest.php b/tests/scenarios/Activities/ActivitiesWithQueueAdminTest.php
index f96f667c0b5..145891ec5d3 100644
--- a/tests/scenarios/Activities/ActivitiesWithQueueAdminTest.php
+++ b/tests/scenarios/Activities/ActivitiesWithQueueAdminTest.php
@@ -38,15 +38,15 @@ abstract class ActivitiesWithQueueAdminWithQuotasTestCase
     Class_AdminVar::set('ACTIVITY', '1');
     Class_AdminVar::set('ACTIVITY_SESSION_QUOTAS', '1');
 
-    $this->fixture('Class_Lieu',
+    $this->fixture(Class_Lieu::class,
                    ['id' => 12,
                     'libelle' => 'Salle reunion AFI']);
-    $groupe = $this->fixture('Class_UserGroup',
+    $groupe = $this->fixture(Class_UserGroup::class,
                              ['id' => 12,
                               'libelle' => 'Stagiaires',
                               'rights' => [Class_UserGroup::RIGHT_SUIVRE_ACTIVITY]]);
 
-    $this->fixture('Class_Users',
+    $this->fixture(Class_Users::class,
                    ['id' => 5,
                     'id_site' => 12,
                     'login' => 'Mononoke',
@@ -55,7 +55,7 @@ abstract class ActivitiesWithQueueAdminWithQuotasTestCase
                     'nom' => 'Noke',
                     'mail' => 'mono@noke.org',
                     'user_groups' => [$groupe]]);
-    $this->fixture('Class_Users',
+    $this->fixture(Class_Users::class,
                    ['id' => 123,
                     'id_site' => 12,
                     'login' => 'Totoro',
@@ -65,12 +65,12 @@ abstract class ActivitiesWithQueueAdminWithQuotasTestCase
                     'mail' => 'toto@ro.org',
                     'user_groups' => [$groupe]]);
 
-    $this->fixture('Class_Activity',
+    $this->fixture(Class_Activity::class,
                    ['id' => 3,
                     'libelle' => 'Learn Java',
                     'description' => 'Here you will learn some old and boring stuff']);
 
-    $this->fixture('Class_SessionActivity',
+    $this->fixture(Class_SessionActivity::class,
                    ['id' => 35,
                     'activity_id' => 3,
                     'date_debut' => '2021-05-27',
@@ -91,14 +91,14 @@ abstract class ActivitiesWithQueueAdminWithQuotasTestCase
                     'queue_attendees' => true
                    ]);
 
-    $inscription_mononoke = $this->fixture('Class_SessionActivityInscription',
+    $inscription_mononoke = $this->fixture(Class_SessionActivityInscription::class,
                                            ['id' => 234,
                                             'stagiaire_id' => 5,
                                             'session_activity_id' => 35,
                                             'children' => 5,
                                             'adults' => 5,
                                            ]);
-    $inscription_totoro = $this->fixture('Class_SessionActivityInscription',
+    $inscription_totoro = $this->fixture(Class_SessionActivityInscription::class,
                                          ['id' => 567,
                                           'stagiaire_id' => 123,
                                           'session_activity_id' => 35,
@@ -376,6 +376,8 @@ class ActivitiesWithQueueAdminEditQuotasOnSessionTest
                          'effectif_max' => 17,
                          'effectif_child_min' => 1,
                          'effectif_child_max' => 5,
+                         'effectif_total_min' => 0,
+                         'effectif_total_max' => 0,
                          'age_child_min' => 5,
                          'age_child_max' => 12,
                          'effectif_inscription_max' => 1,
diff --git a/tests/scenarios/Activities/AdminControllerInscriptionWithQuotasTest.php b/tests/scenarios/Activities/AdminControllerInscriptionWithQuotasTest.php
index d5188b538d3..26d1a35efba 100644
--- a/tests/scenarios/Activities/AdminControllerInscriptionWithQuotasTest.php
+++ b/tests/scenarios/Activities/AdminControllerInscriptionWithQuotasTest.php
@@ -39,17 +39,17 @@ abstract class AdminControllerInscriptionWithQuotasTestCase
 
     Class_AdminVar::set('ACTIVITY_SESSION_QUOTAS', 1);
 
-    $this->_group_profs = $this->fixture('Class_UserGroup',
+    $this->_group_profs = $this->fixture(Class_UserGroup::class,
                                          ['id' => 344,
                                           'libelle' => 'Profs',
                                           'rights' => [Class_UserGroup::RIGHT_DIRIGER_ACTIVITY]]);
 
-    $this->_groupe_stagiaires = $this->fixture('Class_UserGroup',
+    $this->_groupe_stagiaires = $this->fixture(Class_UserGroup::class,
                                                ['id' => 12,
                                                 'libelle' => 'Stagiaires',
                                                 'rights' => [Class_UserGroup::RIGHT_SUIVRE_ACTIVITY]]);
 
-    $this->_prof_laurent = $this->fixture('Class_users',
+    $this->_prof_laurent = $this->fixture(Class_users::class,
                                           ['id' => 34,
                                            'nom' => 'Laffont',
                                            'prenom' => 'Laurent',
@@ -57,7 +57,7 @@ abstract class AdminControllerInscriptionWithQuotasTestCase
                                            'password' => 'pwd',
                                            'user_groups' => [$this->_group_profs]]);
 
-    $this->_amandine = $this->fixture('Class_Users',
+    $this->_amandine = $this->fixture(Class_Users::class,
                                       ['id' => 10,
                                        'nom' => 'Pistache',
                                        'prenom' => 'Amandine',
@@ -66,7 +66,7 @@ abstract class AdminControllerInscriptionWithQuotasTestCase
                                        'mail' => 'pist@che.io',
                                        'user_groups' => [$this->_groupe_stagiaires]]);
 
-    $this->_patrick = $this->fixture('Class_Users',
+    $this->_patrick = $this->fixture(Class_Users::class,
                                      ['id' => 5,
                                       'id_site' => 12,
                                       'login' => 'Pat',
@@ -76,16 +76,16 @@ abstract class AdminControllerInscriptionWithQuotasTestCase
                                       'mail' => 'user@server.org',
                                       'user_groups' => [$this->_groupe_stagiaires]]);
 
-    $this->_salle_reunion = $this->fixture('Class_Lieu',
+    $this->_salle_reunion = $this->fixture(Class_Lieu::class,
                                            ['id' => 12,
                                             'libelle' => 'Salle reunion AFI']);
 
-    $this->_learn_java = $this->fixture('Class_Activity',
+    $this->_learn_java = $this->fixture(Class_Activity::class,
                                         ['id' => 3,
                                          'libelle' => 'Learn Java',
                                          'description' => 'Here you will learn some old and boring stuff']);
 
-    $this->fixture('Class_SessionActivity',
+    $this->fixture(Class_SessionActivity::class,
                    ['id' => 32,
                     'activity' => $this->_learn_java,
                     'date_debut' => '2012-03-27',
@@ -105,7 +105,7 @@ abstract class AdminControllerInscriptionWithQuotasTestCase
                     'intervenants' => [$this->_prof_laurent],
                    ]);
 
-    $inscription = $this->fixture('Class_SessionActivityInscription',
+    $inscription = $this->fixture(Class_SessionActivityInscription::class,
                                   ['id' => 165,
                                    'stagiaire_id' => 5,
                                    'session_activity_id' => 32,
diff --git a/tests/scenarios/Activities/AdminControllerWithQuotasTest.php b/tests/scenarios/Activities/AdminControllerWithQuotasTest.php
index 6768d23abe6..63d7465901d 100644
--- a/tests/scenarios/Activities/AdminControllerWithQuotasTest.php
+++ b/tests/scenarios/Activities/AdminControllerWithQuotasTest.php
@@ -36,24 +36,24 @@ abstract class AdminControllerWithQuotasTestCase extends Admin_AbstractControlle
   public function setUp() {
     parent::setUp();
 
-    $this->_legacy_registration = $this->fixture('Class_SessionActivityInscription',
+    $this->_legacy_registration = $this->fixture(Class_SessionActivityInscription::class,
                                           ['id' => 38839,
                                            'session_activity_id' => 32,
                                            'stagiaire_id' => 999838]);
 
     Class_AdminVar::set('ACTIVITY_SESSION_QUOTAS', '1');
 
-    $this->_group_profs = $this->fixture('Class_UserGroup',
+    $this->_group_profs = $this->fixture(Class_UserGroup::class,
                                          ['id' => 344,
                                           'libelle' => 'Profs',
                                           'rights' => [Class_UserGroup::RIGHT_DIRIGER_ACTIVITY]]);
 
-    $this->_groupe_stagiaires = $this->fixture('Class_UserGroup',
+    $this->_groupe_stagiaires = $this->fixture(Class_UserGroup::class,
                                                ['id' => 12,
                                                 'libelle' => 'Stagiaires',
                                                 'rights' => [Class_UserGroup::RIGHT_SUIVRE_ACTIVITY]]);
 
-    $this->_prof_laurent = $this->fixture('Class_users',
+    $this->_prof_laurent = $this->fixture(Class_users::class,
                                           ['id' => 34,
                                            'nom' => 'Laffont',
                                            'prenom' => 'Laurent',
@@ -61,7 +61,7 @@ abstract class AdminControllerWithQuotasTestCase extends Admin_AbstractControlle
                                            'password' => 'pwd',
                                            'user_groups' => [$this->_group_profs]]);
 
-    $this->_amandine = $this->fixture('Class_Users',
+    $this->_amandine = $this->fixture(Class_Users::class,
                                       ['id' => 10,
                                        'nom' => 'Pistache',
                                        'prenom' => 'Amandine',
@@ -70,7 +70,7 @@ abstract class AdminControllerWithQuotasTestCase extends Admin_AbstractControlle
                                        'mail' => 'pist@che.io',
                                        'user_groups' => [$this->_groupe_stagiaires]]);
 
-    $this->_patrick = $this->fixture('Class_Users',
+    $this->_patrick = $this->fixture(Class_Users::class,
                                      ['id' => 5,
                                       'id_site' => 12,
                                       'login' => 'Pat',
@@ -80,16 +80,16 @@ abstract class AdminControllerWithQuotasTestCase extends Admin_AbstractControlle
                                       'mail' => 'user@server.org',
                                       'user_groups' => [$this->_groupe_stagiaires]]);
 
-    $this->_salle_reunion = $this->fixture('Class_Lieu',
+    $this->_salle_reunion = $this->fixture(Class_Lieu::class,
                                            ['id' => 12,
                                             'libelle' => 'Salle reunion AFI']);
 
-    $this->_learn_java = $this->fixture('Class_Activity',
+    $this->_learn_java = $this->fixture(Class_Activity::class,
                                         ['id' => 3,
                                          'libelle' => 'Learn Java',
                                          'description' => 'Here you will learn some old and boring stuff']);
 
-    $this->fixture('Class_SessionActivity',
+    $this->fixture(Class_SessionActivity::class,
                    ['id' => 32,
                     'activity' => $this->_learn_java,
                     'date_debut' => '2012-03-27',
@@ -109,7 +109,7 @@ abstract class AdminControllerWithQuotasTestCase extends Admin_AbstractControlle
                     'intervenants' => [$this->_prof_laurent],
                    ]);
 
-    $inscription = $this->fixture('Class_SessionActivityInscription',
+    $inscription = $this->fixture(Class_SessionActivityInscription::class,
                                   ['id' => 165,
                                    'stagiaire_id' => 5,
                                    'session_activity_id' => 32,
@@ -183,6 +183,44 @@ class Activities_AdminControllerWithQuotasInscriptionTest extends AdminControlle
 
 
 
+class Activities_AdminControllerWithQuotasInscriptionAndTotalParticipantsTest
+  extends AdminControllerWithQuotasTestCase {
+
+  /** @test */
+  public function withoutAdultsAndChildrenRangePageShouldContainsTotalCounters() {
+    Class_SessionActivity::find(32)
+      ->setEffectifTotalMin(1)
+      ->setEffectifTotalMax(25)
+      ->setEffectifMin(0)
+      ->setEffectifMax(0)
+      ->setEffectifChildMin(0)
+      ->setEffectifChildMax(0)
+      ->assertSave();
+    $this->dispatch('/admin/session-activity/inscriptions/id/32/search_session_activity_subscription_status/all');
+    $this->assertXPathContentContains('//a[contains(@href, "/session-activity/inscriptions/id/32")]',
+                                      'Adultes: 1 / 1-25, Enfants: 2 / 1-25');
+  }
+
+
+  /** @test */
+  public function withAdultsAndChildrenRangePageShouldContainsAdultsAndChildrenCounters() {
+    Class_SessionActivity::find(32)
+      ->setEffectifTotalMin(1)
+      ->setEffectifTotalMax(25)
+      ->setEffectifMin(2)
+      ->setEffectifMax(25)
+      ->setEffectifChildMin(5)
+      ->setEffectifChildMax(15)
+      ->assertSave();
+    $this->dispatch('/admin/session-activity/inscriptions/id/32/search_session_activity_subscription_status/all');
+    $this->assertXPathContentContains('//a[contains(@href, "/session-activity/inscriptions/id/32")]',
+                                      'Adultes: 1 / 2-25, Enfants: 2 / 5-15');
+  }
+}
+
+
+
+
 class Activities_AdminControllerWithQuotasInscriptionLegacyTest
   extends AdminControllerWithQuotasTestCase {
 
@@ -209,7 +247,6 @@ class Activities_AdminControllerWithQuotasInscriptionLegacyTest
 class Activities_AdminControllerWithQuotasInputFieldsTest
   extends AdminControllerWithQuotasTestCase {
 
-
   public function setUp() {
     parent::setUp();
     $this->dispatch('/admin/session-activity/edit/id/32');
@@ -217,14 +254,16 @@ class Activities_AdminControllerWithQuotasInputFieldsTest
 
 
   public function quotasElements() {
-    return [['effectif_min'],
-            ['effectif_child_min'],
-            ['effectif_max'],
-            ['effectif_child_max'],
-            ['effectif_inscription_max'],
-            ['effectif_inscription_child_max'],
-            ['age_child_max'],
-            ['age_child_min']];
+    return [['effectif_total_min', false],
+            ['effectif_total_max', false],
+            ['effectif_min', false],
+            ['effectif_child_min', false],
+            ['effectif_max', false],
+            ['effectif_child_max', false],
+            ['effectif_inscription_max', true],
+            ['effectif_inscription_child_max', true],
+            ['age_child_max', true],
+            ['age_child_min', false]];
   }
 
 
@@ -232,9 +271,10 @@ class Activities_AdminControllerWithQuotasInputFieldsTest
    * @test
    * @dataProvider quotasElements
    */
-  public function formShouldContainsQuotasElement($element) {
+  public function formShouldContainsQuotasElement(string $element, bool $required) {
     $this->assertXPath('//fieldset[@id="fieldset-quotas"]//input[@name="'
-                       . $element . '"][@required="required"][@type="number"][@min="0"]');
+                       . $element . '"]' . ($required ? '[@required="required"]' : '')
+                       . '[@type="number"][@min="0"]');
   }
 }
 
@@ -284,6 +324,8 @@ class Activities_AdminControllerWithQuotasInscriptionInvalidPostTest
                              'age_child_max' => 'chaine',
                              'effectif_min' => 'chaine',
                              'effectif_max' => 'chaine',
+                             'effectif_total_min' => 'chaine',
+                             'effectif_total_max' => 'chaine',
                              'effectif_inscription_max' => 'chaine',
                              'effectif_inscription_child_max' => 'chaine'];
 
@@ -374,6 +416,129 @@ class Activities_AdminControllerWithQuotasInscriptionInvalidPostTest
     $this->assertXPathContentContains('//ul[@class="errors"]//li',
                                       "Enfants maximum par inscription doit être renseigné");
   }
+
+
+  /** @test */
+  public function withEffectifMinGreaterThanEffectifMaxShouldReturnError() {
+    $this->postDispatch('/admin/session-activity/edit/id/32',
+                        ['effectif_max' => 10,
+                         'effectif_total_min' => 20,
+                         'effectif_total_max' => 10 ]);
+    $this->assertXPathContentContains('//ul[@class="errors"]//li',
+                                      "L'effectif total maximum doit être supérieur ou égal à l'effectif total minimum");
+  }
+
+
+  /** @test */
+  public function withEffectifInscriptionMaxLesserThanEffectifTotalMaxShouldReturnError() {
+    $this->postDispatch('/admin/session-activity/edit/id/32',
+                        ['effectif_max' => 10,
+                         'effectif_total_min' => 10,
+                         'effectif_total_max' => 20,
+                         'effectif_inscription_max' => 30,
+                        ]);
+    $this->assertXPathContentContains('//ul[@class="errors"]//li',
+                                      "L'effectif total maximum doit être supérieur ou égal à l'effectif maximum par inscription");
+  }
+
+
+  /** @test */
+  public function withNumberOfAttendeesGreaterThanEffectifTotalShouldReturnError() {
+    $this->postDispatch('/admin/session-activity/edit/id/32',
+                        ['effectif_total_min' => 1,
+                         'effectif_total_max' => 1,
+                         'effectif_inscription_max' => 1,
+                         'effectif_child_min' => 0,
+                         'effectif_child_max' => 0,
+                         'effectif_min' => 0,
+                         'effectif_max' => 0,
+                        ]);
+    $this->assertXPathContentContains('//ul[@class="errors"]//li',
+                                      "Le nombre d'inscrit.e.s ne peut dépasser l'effectif maximum");
+  }
+
+
+  /** @test */
+  public function withNumberOfChildMaxGreaterThanEffectifTotalMaxShouldReturnError() {
+    $this->postDispatch('/admin/session-activity/edit/id/32',
+                        ['effectif_total_min' => 1,
+                         'effectif_total_max' => 5,
+                         'effectif_inscription_max' => 1,
+                         'effectif_child_min' => 0,
+                         'effectif_child_max' => 6,
+                         'effectif_min' => 0,
+                         'effectif_max' => 0,
+                        ]);
+    $this->assertXPathContentContains('//ul[@class="errors"]//li',
+                                      "Le nombre d'enfants maximum ne peut dépasser l'effectif maximum total");
+  }
+
+
+  /** @test */
+  public function withNumberOfAdultMaxGreaterThanEffectifTotalMaxShouldReturnError() {
+    $this->postDispatch('/admin/session-activity/edit/id/32',
+                        ['effectif_total_min' => 1,
+                         'effectif_total_max' => 5,
+                         'effectif_inscription_max' => 1,
+                         'effectif_child_min' => 0,
+                         'effectif_child_max' => 0,
+                         'effectif_min' => 0,
+                         'effectif_max' => 6,
+                        ]);
+    $this->assertXPathContentContains('//ul[@class="errors"]//li',
+                                      "Le nombre d'adultes maximum ne peut dépasser l'effectif maximum total");
+  }
+
+
+  /** @test */
+  public function inscriptionMaxAdultOrChildrenShouldBeMandatory() {
+    $this->postDispatch('/admin/session-activity/edit/id/32',
+                        ['effectif_total_min' => 1,
+                         'effectif_total_max' => 5,
+                         'effectif_inscription_max' => 0,
+                         'effectif_inscription_child_max' => 0,
+                         'effectif_child_min' => 0,
+                         'effectif_child_max' => 0,
+                         'effectif_min' => 0,
+                         'effectif_max' => 0,
+                        ]);
+    $this->assertXPathContentContains('//ul[@class="errors"]//li',
+                                      "Au moins un maximum par inscription doit être renseigné");
+  }
+}
+
+
+
+
+class Activities_AdminControllerWithQuotasInscriptionWithTotalPostTest
+  extends AdminControllerWithQuotasTestCase {
+
+  protected $_post_values = ['effectif_min' => 0,
+                             'effectif_max' => 0,
+                             'effectif_child_min' => 0,
+                             'effectif_child_max' => 0,
+                             'effectif_total_min' => 1,
+                             'effectif_total_max' => 10];
+
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->postDispatch('/admin/session-activity/edit/id/32',
+                        $this->_post_values);
+  }
+
+
+  /** @test */
+  public function sessionActivityEffectifTotalMinShouldBeOne() {
+    $this->assertEquals(1, Class_SessionActivity::find(32)->getEffectifTotalMin());
+  }
+
+
+  /** @test */
+  public function sessionActivityEffectifTotalMaxShouldBeTen() {
+    $this->assertEquals(10, Class_SessionActivity::find(32)->getEffectifTotalMax());
+  }
 }
 
 
@@ -450,4 +615,4 @@ class Activities_AdminControllerWithQuotasInscriptionAndAgeChildMinExportTest
   public function exportShouldContainsAgeMinAndMaxChildren() {
     $this->assertContains('Enfants (âge compris entre 3 et 5)', $this->_response->getBody());
   }
-}
\ No newline at end of file
+}
diff --git a/tests/scenarios/Templates/PolygoneTemplateAbonneAgendaTest.php b/tests/scenarios/Templates/PolygoneTemplateAbonneAgendaTest.php
index fb83a564e6c..a9328b10b77 100644
--- a/tests/scenarios/Templates/PolygoneTemplateAbonneAgendaTest.php
+++ b/tests/scenarios/Templates/PolygoneTemplateAbonneAgendaTest.php
@@ -20,7 +20,9 @@
  */
 
 
-abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTestCase {
+abstract class PolygoneTemplateAbonneAgendaTestCase
+  extends AbstractControllerTestCase {
+
   protected
     $_storm_default_to_volatile = true,
     $_amadou,
@@ -58,20 +60,20 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
     $this->_mail_transport = new MockMailTransport();
     Zend_Mail::setDefaultTransport($this->_mail_transport);
 
-    $this->_amadou = $this->fixture('Class_Users',
+    $this->_amadou = $this->fixture(Class_Users::class,
                                     ['id' => 435,
                                      'nom' => 'Dou',
                                      'prenom' => 'Ama',
                                      'login' => 'Amadou',
                                      'password' => 'pwd',
                                      'mail' => 'amadou@afi-sa.fr',
-                                     'bib' => $this->fixture('Class_Bib',
+                                     'bib' => $this->fixture(Class_Bib::class,
                                                              ['id' => 1,
                                                               'libelle' => 'annecy']),
                                      'idabon' => 435]);
     $this->_amadou
       ->beAbonneSIGB()
-      ->setUserGroups([($this->fixture('Class_UserGroup',
+      ->setUserGroups([($this->fixture(Class_UserGroup::class,
                                        ['id' => 23,
                                         'libelle' => 'Mon super groupe !',
                                         'model_class'=> 'Class_RendezVous'])
@@ -80,17 +82,15 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
 
     ZendAfi_Auth::getInstance()->logUser($this->_amadou);
 
-    $this->_gallice_cafe = $this->fixture('Class_Lieu',
+    $this->_gallice_cafe = $this->fixture(Class_Lieu::class,
                                           ['id' => 98,
                                            'libelle' => 'Galice']);
 
-
-    $this->_bib_romains = $this->fixture('Class_Lieu',
+    $this->_bib_romains = $this->fixture(Class_Lieu::class,
                                          ['id' => '99',
                                           'libelle' => 'Bibliothèque des romains']);
 
-
-    $this->_bonlieu = $this->fixture('Class_Lieu',
+    $this->_bonlieu = $this->fixture(Class_Lieu::class,
                                      ['id' => 100,
                                       'libelle' => 'Bonlieu',
                                       'adresse' => "1, rue Jean-Jaures\nBP 294",
@@ -100,12 +100,12 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
                                       'longitude' => '6.128715']);
 
     $this->_learn_smalltalk = $this
-      ->fixture('Class_Activity',
+      ->fixture(Class_Activity::class,
                 ['id' => 1,
                  'libelle' => 'Learn Smalltalk']);
 
     $this->_session_smalltalk_janvier = $this
-      ->fixture('Class_SessionActivity',
+      ->fixture(Class_SessionActivity::class,
                 ['id' => 11,
                  'activity' => $this->_learn_smalltalk,
                  'effectif_min' => 1,
@@ -117,7 +117,7 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
                  'stagiaires' => []]);
 
     $this->_session_smalltalk_juillet = $this
-      ->fixture('Class_SessionActivity',
+      ->fixture(Class_SessionActivity::class,
                 ['id' => 12,
                  'activity' => $this->_learn_smalltalk,
                  'effectif_min' => 1,
@@ -134,13 +134,13 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
       ->assertSave();
 
 
-    $this->_learn_java = $this->fixture('Class_Activity',
+    $this->_learn_java = $this->fixture(Class_Activity::class,
                                         ['id' => 3,
                                          'libelle' => 'Learn Java',
                                          'description' => 'whaaat ? Une superbe formation ! <img src="https://masuperimage.afi-sa.org">']);
 
 
-    $this->_session_java_fevrier = $this->fixture('Class_SessionActivity',
+    $this->_session_java_fevrier = $this->fixture(Class_SessionActivity::class,
                                                   ['id' => 31,
                                                    'activity' => $this->_learn_java,
                                                    'contenu' => 'Introduction a la syntaxe <iframe allowfullscreen="true" allowscriptaccess="always" frameborder="0" height="349" scrolling="no" src="//www.lasupersyntax.afi-sa.fr" width="425"></iframe>',
@@ -152,7 +152,7 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
                                                    'stagiaires' => [],
                                                    'date_limite_fin' => '2021-01-20']);
 
-    $this->_session_java_mars = $this->fixture('Class_SessionActivity',
+    $this->_session_java_mars = $this->fixture(Class_SessionActivity::class,
                                                ['id' => 32,
                                                 'activity' => $this->_learn_java,
                                                 'effectif_min' => 2,
@@ -171,7 +171,7 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
       ->getSessionActivityInscriptions()[0]->setAdults(1)
                                            ->setChildren(1);
 
-    $this->_session_java_septembre = $this->fixture('Class_SessionActivity',
+    $this->_session_java_septembre = $this->fixture(Class_SessionActivity::class,
                                                     ['id' => 30,
                                                      'activity' => $this->_learn_java,
                                                      'effectif_min' => 2,
@@ -189,13 +189,13 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
       ->assertSave();
 
 
-    $this->_learn_python = $this->fixture('Class_Activity',
+    $this->_learn_python = $this->fixture(Class_Activity::class,
                                           ['id' => 12,
                                            'description' => 'Yeah ! <iframe src="https://masuperiframe.afi-sa.org">',
                                            'libelle' => 'Learn Python']);
 
     $this->_session_python_juillet = $this
-      ->fixture('Class_SessionActivity',
+      ->fixture(Class_SessionActivity::class,
                 ['id' => 121,
                  'activity' => $this->_learn_python,
                  'date_debut' => '2020-07-10',
@@ -214,7 +214,7 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
                  'horaires' => '8h-12h, 14h-18h',
                  'lieu' => $this->_bib_romains,
                  'stagiaires' => [$this->_amadou],
-                 'intervenants' => [$this->fixture('Class_Users',
+                 'intervenants' => [$this->fixture(Class_Users::class,
                                                    ['id' =>76,
                                                     'login' => 'jpp',
                                                     'password' => 'pwd',
@@ -234,7 +234,7 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
       ->setSessions([$this->_session_python_juillet])
       ->assertSave();
 
-    $inscription_amadou_python = $this->fixture('Class_SessionActivityInscription',
+    $inscription_amadou_python = $this->fixture(Class_SessionActivityInscription::class,
                                                 ['id' => 1,
                                                  'stagiaire' => $this->_amadou,
                                                  'session_activity' => $this->_session_python_juillet,
@@ -245,10 +245,10 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
 
     Class_AdminVar::set('ENABLE_RENDEZ_VOUS', 1);
 
-    $rdv = $this->fixture('Class_RendezVous',
+    $rdv = $this->fixture(Class_RendezVous::class,
                           ['id' => 4,
                            'agenda' => Class_UserGroup::find(23),
-                           'location' => $this->fixture('Class_Lieu',
+                           'location' => $this->fixture(Class_Lieu::class,
                                                         ['id' => 8,
                                                          'libelle' => 'Bellevue']),
                            'date' => '2019-03-19',
@@ -268,7 +268,8 @@ abstract class PolygoneTemplateAbonneAgendaTestCase extends AbstractControllerTe
 
 
 
-class PolygoneTemplateAbonneAgendaListTest extends PolygoneTemplateAbonneAgendaTestCase {
+class PolygoneTemplateAbonneAgendaListTest
+  extends PolygoneTemplateAbonneAgendaTestCase {
 
   public function setUp() {
     parent::setUp();
@@ -351,6 +352,55 @@ class PolygoneTemplateAbonneAgendaListTest extends PolygoneTemplateAbonneAgendaT
 
 
 
+class PolygoneTemplateAbonneAgendaListWithoutOsmMapTest
+  extends PolygoneTemplateAbonneAgendaTestCase {
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->_gallice_cafe
+      ->setUrl('/userfiles/images/galice.png')
+      ->setAdresse('1, rue Jean-Jaures\nBP 294')
+      ->setCodePostal(74007)
+      ->setVille('Annecy')
+      ->setLatitude(25)
+      ->setLongitude(30)
+      ->assertSave();
+
+    Class_SessionActivity::find(11)
+      ->setContenu('<p><strong>Atelier parents/enfants</strong><img alt="" height="752" src="/userfiles/image/calimero.jpg" style="border-width: 9px; border-style: solid; float: right;" width="531" /><br />
+Vous vous sentez d&#39;humeur cr&eacute;ative ?<br />
+Venez cr&eacute;er une affiche &agrave; l&#39;aide de mat&eacute;riaux recycl&eacute;s ou de r&eacute;cup&#39; !<br />
+<img alt="" height="752" src="/userfiles/image/totoro.jpg" style="border-width: 9px; border-style: solid; float: right;" width="531" />
+En bin&ocirc;me adulte/enfant, c&#39;est encore plus marrant :-)</p>
+<p>Avec l&#39;association Artyard.</p>')
+    ->assertSave();
+
+    $this->dispatch('/opac/abonne/agenda');
+  }
+
+
+  /** @test */
+  public function pageShouldContainsLieuGaliceMapOsm() {
+    $this->assertXPath('//img[contains(@class, "osm_static_map")][@alt="Galice"]');
+  }
+
+
+  /** @test */
+  public function pageShouldContainsImgCalimero() {
+    $this->assertXPath('//img[contains(@src, "/userfiles/image/calimero.jpg")]');
+  }
+
+
+  /** @test */
+  public function pageShouldNotContainsImgTotoro() {
+    $this->assertNotXPath('//img[contains(@src, "/userfiles/image/totoro.jpg")]');
+  }
+}
+
+
+
+
 class PolygoneTemplateAbonneAgendaListWithQuotasTest extends PolygoneTemplateAbonneAgendaTestCase {
   public function setUp() {
     parent::setUp();
@@ -468,10 +518,19 @@ class PolygoneTemplateAbonneAgendaListWithSmallTalkVisibleTest
 
 
 
-class PolygoneTemplateAbonneAgendaDetailSessionTest extends PolygoneTemplateAbonneAgendaTestCase {
+class PolygoneTemplateAbonneAgendaDetailSessionTest
+  extends PolygoneTemplateAbonneAgendaTestCase {
 
   public function setUp() {
     parent::setUp();
+    Class_SessionActivity::find(31)
+      ->setContenu('<p><strong>Atelier parents/enfants</strong><img alt="" height="752" src="/userfiles/image/calimero.jpg" style="border-width: 9px; border-style: solid; float: right;" width="531" /><br />
+Vous vous sentez d&#39;humeur cr&eacute;ative ?<br />
+Venez cr&eacute;er une affiche &agrave; l&#39;aide de mat&eacute;riaux recycl&eacute;s ou de r&eacute;cup&#39; !<br />
+En bin&ocirc;me adulte/enfant, c&#39;est encore plus marrant :-)</p>
+<p>Avec l&#39;association Artyard.</p>')
+    ->assertSave();
+
     $this->dispatch('/opac/abonne/detail-session/id/31');
   }
 
@@ -491,7 +550,7 @@ class PolygoneTemplateAbonneAgendaDetailSessionTest extends PolygoneTemplateAbon
 
   /** @test */
   public function ddShouldContainsAdresse74007Annecy() {
-    $this->assertXPathContentContains('//dd', '74007 Annecy');
+    $this->assertXPathContentContains('//dd[3]//div[@class="lieu"]', '74007 Annecy');
   }
 
 
@@ -499,6 +558,12 @@ class PolygoneTemplateAbonneAgendaDetailSessionTest extends PolygoneTemplateAbon
   public function ddShouldContainsStaticMap() {
     $this->assertXPath('//dd//img[@src="https://smap.afi-sa.net/staticmap.php?center=45.902179%2C6.128715&markers=45.902179%2C6.128715&zoom=15&size=300x300"]');
   }
+
+
+  /** @test */
+  public function contenuShouldBeFirstDisplay() {
+    $this->assertXPathContentContains('//dd[1]/p', 'Atelier parents/enfants');
+  }
 }
 
 
@@ -579,7 +644,9 @@ class PolygoneTemplateAbonneAgendaDetailSessionWithQuotasTest
 
   public function setUp() {
     parent::setUp();
-    Class_SessionActivity::find(32)->resetAttendees();
+    Class_SessionActivity::find(32)
+      ->resetAttendees();
+
     Class_AdminVar::set('ACTIVITY_SESSION_QUOTAS', '1');
     $this->dispatch('/opac/abonne/detail-session/id/32');
   }
-- 
GitLab