diff --git a/FEATURES/102749 b/FEATURES/102749
new file mode 100644
index 0000000000000000000000000000000000000000..d5abe75de0e40518638e719eb2f3945eb7be6c59
--- /dev/null
+++ b/FEATURES/102749
@@ -0,0 +1,10 @@
+        '102749' =>
+            ['Label' => $this->_('Amélioration des groupes dynamiques'),
+             'Desc' => $this->_('Vous pouvez désormais utiliser tous les critères disponibles dans la liste des utiliseurs en tant que filtre des groupes dynamiques'),
+             'Image' => '',
+             'Video' => 'https://youtube.com/watch?v=B81l7kU-lqE',
+             'Category' => $this->_('Administration'),
+             'Right' => function($feature_description, $user) {return true;},
+             'Wiki' => 'http://wiki.bokeh-library-portal.org/index.php?title=Gestion_des_groupes',
+             'Test' => '',
+             'Date' => '2020-01-23'],
\ No newline at end of file
diff --git a/VERSIONS_WIP/102749 b/VERSIONS_WIP/102749
new file mode 100644
index 0000000000000000000000000000000000000000..08c413c2f2b8661d586fe758ddb6b51930830592
--- /dev/null
+++ b/VERSIONS_WIP/102749
@@ -0,0 +1 @@
+ - ticket #102749 : Administration des groupes : Les groupes dynamiques utilisent désormais les même critères que la recherche d'utilisateurs
\ No newline at end of file
diff --git a/cosmogramme/sql/patch/patch_383.php b/cosmogramme/sql/patch/patch_383.php
new file mode 100644
index 0000000000000000000000000000000000000000..78b27b5612a9fe6dca4179584ec3b6c85b120d42
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_383.php
@@ -0,0 +1,9 @@
+<?php
+$adapter = Zend_Db_Table_Abstract::getDefaultAdapter();
+try {
+  $adapter->query("alter table user_groups add column `filters` longtext not null default ''" );
+} catch (Exception $e) {}
+
+try {
+  $adapter->query("update user_groups set filters=concat('{\"search_role_level\":\"', role_level, '\", \"search_id_site\":\"', if(id_bib, id_bib, 'all'), '\"}') where group_type=1 and filters=''");
+} catch (Exception $e) {}
diff --git a/library/Class/RendezVous/SearchCriteria/Location.php b/library/Class/RendezVous/SearchCriteria/Location.php
index 80e0629a05a08bd4d5fda9aad6175c0b0003ae4a..50036b0aef53f417b19650bb41bba940d62b200f 100644
--- a/library/Class/RendezVous/SearchCriteria/Location.php
+++ b/library/Class/RendezVous/SearchCriteria/Location.php
@@ -23,13 +23,13 @@
 class Class_RendezVous_SearchCriteria_Location extends Class_SearchCriteria_Abstract {
   protected
     $_name = 'location_id',
-    $_value = self::DEFAULT_VALUE;
+    $_value = Class_SearchCriteria_Abstract::ALL_VALUES;
 
   const NONE = "none";
 
   public function buildElement() {
     $options = ['label' => $this->_('Lieu'),
-                'multiOptions' => [static::DEFAULT_VALUE => $this->_('Tous'),
+                'multiOptions' => [static::ALL_VALUES => $this->_('Tous'),
                                    static::NONE => $this->_('Indéterminé')]
                 + Class_Lieu::getAllLibelles()
     ];
diff --git a/library/Class/SearchCriteria.php b/library/Class/SearchCriteria.php
index b2e537b1480e078dad760f271446b5b26d6482d9..0d05d86ac92a41cb3636044d73f4b61802dca83d 100644
--- a/library/Class/SearchCriteria.php
+++ b/library/Class/SearchCriteria.php
@@ -30,6 +30,11 @@ abstract class Class_SearchCriteria {
     $_search_params,
     $_has_no_result = false;
 
+  public static function isCriteriaName($name) {
+    return Class_SearchCriteria_Abstract::isCriteriaName($name);
+  }
+
+
   public function __construct($params) {
   }
 
@@ -49,6 +54,27 @@ abstract class Class_SearchCriteria {
   }
 
 
+  public function replaceCriteria($class_name, $new) {
+    $this->_criteria = array_map(function ($criteria) use ($class_name, $new)
+                                 {
+                                   return  (get_class($criteria) == $class_name)
+                                   ? $new
+                                   : $criteria;
+                                 }, $this->_criteria);
+    return $this;
+  }
+
+
+  public function fetchAll($fields) {
+    $this->_buildSearchParams();
+
+    if ($this->_has_no_result)
+      return [];
+
+    return call_user_func([$this->_model_class, 'fetchAllBy'], $fields, $this->_search_params);
+  }
+
+
   public function findPage($page=1, $page_size=20) {
     $this->_buildSearchParams();
 
@@ -93,6 +119,11 @@ abstract class Class_SearchCriteria {
       ->setAttrib('style', 'position: relative')
       ->setMethod('get');
 
+    return $this->addFormElementsTo($form, 'search_group', $this->_('Recherche'));
+  }
+
+
+  public function addFormElementsTo($form, $fieldset_name, $fieldset_legend) {
     $names = (new Storm_Collection($this->_criteria))
       ->select(function($c) { return $c->getElement(); })
       ->eachDo(function($c) use ($form) { $form->addElement($c->getElement()); })
@@ -102,9 +133,7 @@ abstract class Class_SearchCriteria {
     if (!$names)
       return $form;
 
-    $form->addDisplayGroup($names,
-                           'search_group',
-                           ['legend' => $this->_('Recherche')]);
+    $form->addDisplayGroup($names, $fieldset_name, ['legend' => $fieldset_legend]);
 
     return $form;
   }
@@ -160,6 +189,17 @@ abstract class Class_SearchCriteria {
   }
 
 
+  public function modelMatch($model) {
+    return (new Storm_Collection($this->_criteria))
+      ->detect(function($each) use($model)
+               {
+                 return !$each->modelMatch($model);
+               })
+      ? false
+      : true;
+  }
+
+
   protected function _addCustomCriteriaFor($class_name, $params) {
     $model = Class_CustomField_Model::getModel($class_name);
     foreach($model->getFields() as $field)
diff --git a/library/Class/SearchCriteria/Abstract.php b/library/Class/SearchCriteria/Abstract.php
index 3b4411d78d9372263fa8b540c2ad230515d39c8c..deeae1093fc998a91115f63517551948dd6b8c86 100644
--- a/library/Class/SearchCriteria/Abstract.php
+++ b/library/Class/SearchCriteria/Abstract.php
@@ -23,7 +23,7 @@
 abstract class Class_SearchCriteria_Abstract {
   use Trait_Translator;
 
-  const DEFAULT_VALUE = 'all';
+  const ALL_VALUES = 'all';
   const NAME_PREFIX = 'search_';
 
   protected
@@ -32,6 +32,11 @@ abstract class Class_SearchCriteria_Abstract {
     $_element;
 
 
+  public static function isCriteriaName($name) {
+    return preg_match('/^' . static::NAME_PREFIX . '.+/', $name);
+  }
+
+
   public function __construct($params) {
     if (isset($params[$this->getName()]))
       $this->_value = $params[$this->getName()];
@@ -61,7 +66,7 @@ abstract class Class_SearchCriteria_Abstract {
 
 
   public function acceptSearchVisitor($visitor) {
-    if ($this->_value == static::DEFAULT_VALUE)
+    if ($this->_isAllValues())
       return;
 
     $visitor->addParam($this->_name, $this->_value);
@@ -70,4 +75,16 @@ abstract class Class_SearchCriteria_Abstract {
 
   public function describeOn($view) {
   }
+
+
+  public function modelMatch($model) {
+    return $this->_isAllValues()
+      ? true
+      : $model->callGetterByAttributeName($this->_name) == $this->_value;
+  }
+
+
+  protected function _isAllValues() {
+    return static::ALL_VALUES == $this->_value;
+  }
 }
\ No newline at end of file
diff --git a/library/Class/SearchCriteria/DateRange.php b/library/Class/SearchCriteria/DateRange.php
index 8c04e412830b7d58fae9dcd198199b096cf151cd..8142c03541493c9db44f49d34a6b4786262b1e43 100644
--- a/library/Class/SearchCriteria/DateRange.php
+++ b/library/Class/SearchCriteria/DateRange.php
@@ -76,6 +76,32 @@ class Class_SearchCriteria_DateRange extends Class_SearchCriteria_Abstract {
   }
 
 
+  public function modelMatch($model) {
+    if ($this->_isAllValues())
+      return true;
+
+    if ((!$value = $model->callGetterByAttributeName($this->_name))
+        || !(new ZendAfi_Validate_DateFormat())->isValid($value))
+      return false;
+
+    $time = strtotime(substr($value, 0, 10));
+    if ($this->_value_start
+        && strtotime($this->_sqlFormat($this->_value_start)) > $time)
+      return false;
+
+    if ($this->_value_end
+        && strtotime($this->_sqlFormat($this->_value_end)) < $time)
+      return false;
+
+    return true;
+  }
+
+
+  protected function _isAllValues() {
+    return !($this->_value_start || $this->_value_end);
+  }
+
+
   protected function _filterDate($value) {
     if (null === $value)
       return;
diff --git a/library/Class/SearchCriteria/Order.php b/library/Class/SearchCriteria/Order.php
index 060aff98f526b2b3b1f844094564d136849d70aa..c6e125f8be05373c450f059d7740c0c097597d02 100644
--- a/library/Class/SearchCriteria/Order.php
+++ b/library/Class/SearchCriteria/Order.php
@@ -39,4 +39,9 @@ class Class_SearchCriteria_Order extends Class_SearchCriteria_Abstract {
                        false !== strpos($this->_value, ',')
                        ? explode(',', $this->_value) : $this->_value);
   }
+
+
+  public function modelMatch($model) {
+    return true;
+  }
 }
diff --git a/library/Class/SearchCriteria/Select.php b/library/Class/SearchCriteria/Select.php
index ffe75e67368ad1114adc09c31661eab721bcf5ad..d0805503b5d1a36a14b75be5310baf6aa4ba8531 100644
--- a/library/Class/SearchCriteria/Select.php
+++ b/library/Class/SearchCriteria/Select.php
@@ -21,7 +21,7 @@
 
 
 class Class_SearchCriteria_Select extends Class_SearchCriteria_Abstract {
-  protected $_value = Class_SearchCriteria_Abstract::DEFAULT_VALUE;
+  protected $_value = Class_SearchCriteria_Abstract::ALL_VALUES;
 
   public function buildElement() {
     return new Zend_Form_Element_Select($this->getName(), ['value' => $this->_value]);
@@ -29,7 +29,7 @@ class Class_SearchCriteria_Select extends Class_SearchCriteria_Abstract {
 
 
   public function describeOn($view) {
-    return ($this->_element && static::DEFAULT_VALUE != $this->_value)
+    return ($this->_element && !$this->_isAllValues())
       ? $this->_element->getLabel() . ' : ' . $this->_element->getMultiOption($this->_value)
       : '';
   }
diff --git a/library/Class/SearchCriteria/SelectYesNo.php b/library/Class/SearchCriteria/SelectYesNo.php
new file mode 100644
index 0000000000000000000000000000000000000000..21ea90a5fb7a4d8d9e77fdd012adb06e58a01100
--- /dev/null
+++ b/library/Class/SearchCriteria/SelectYesNo.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+class Class_SearchCriteria_SelectYesNo extends Class_SearchCriteria_Select {
+  const
+    YES = 'yes',
+    NO = 'no';
+
+  protected $_linked_model;
+
+  public function buildElement() {
+    return parent::buildElement()
+      ->setMultiOptions([static::YES => $this->_('Oui'),
+                         static::NO => $this->_('Non'),
+                         static::ALL_VALUES => $this->_('Indifférent')]);
+  }
+
+
+  public function acceptSearchVisitor($visitor) {
+    if ($this->_isAllValues())
+      return;
+
+    if (!$ids = call_user_func([$this->_linked_model, 'findAllUserIds']))
+      return $this->_reactToNoLinkedData($visitor);
+
+    $ids = implode(',', $ids);
+    $operator = (static::NO == $this->_value) ? 'not in' : 'in';
+    $visitor->addWhereParam('id_user ' . $operator . ' (' . $ids .  ')');
+  }
+
+
+  protected function _reactToNoLinkedData($visitor) {
+    static::YES == $this->_value
+      ? $visitor->hasNoResult()
+      : null;
+  }
+
+
+  public function modelMatch($model) {
+    if ($this->_isAllValues())
+      return true;
+
+    $number = call_user_func([$this->_linked_model, 'countBy'], ['id_user' => $model->getId()]);
+    return (static::NO == $this->_value && $number == 0)
+      || (static::YES == $this->_value && $number > 0);
+  }
+}
diff --git a/library/Class/User/SearchCriteria.php b/library/Class/User/SearchCriteria.php
index 8162b9b8f2609903673572cab2899b91e3d3096b..5caadb10a04c49b45a4c96646ac87d2e14b1f484 100644
--- a/library/Class/User/SearchCriteria.php
+++ b/library/Class/User/SearchCriteria.php
@@ -25,11 +25,14 @@ class Class_User_SearchCriteria extends Class_SearchCriteria {
 
   public function __construct($params) {
     $this->_criteria = [new Class_User_SearchCriteriaLibrary($params),
-                        new Class_User_SearchCriteriaRoleLevel($params),
+                        new Class_User_SearchCriteria_RoleLevel($params),
                         new Class_User_SearchCriteriaValidSubscription($params),
+                        new Class_User_SearchCriteria_EndSubscriptionDate($params),
                         new Class_User_SearchCriteria_DateFin($params),
                         new Class_User_SearchCriteria_InLastSigbExport($params),
                         new Class_User_SearchCriteria_DateMaj($params),
+                        // disabled until real birth date on database
+//                        new Class_User_SearchCriteria_Age($params),
                         new Class_User_SearchCriteria_NumberOfReviews($params),
                         new Class_User_SearchCriteria_NumberOfBaskets($params),
                         new Class_User_SearchCriteriaSearchFor($params),
@@ -39,6 +42,7 @@ class Class_User_SearchCriteria extends Class_SearchCriteria {
 
 
 
+
 class Class_User_SearchCriteriaLibrary extends Class_SearchCriteria_Select {
   protected $_name = 'id_site';
 
@@ -51,45 +55,6 @@ class Class_User_SearchCriteriaLibrary extends Class_SearchCriteria_Select {
 
 
 
-class Class_User_SearchCriteriaRoleLevel extends Class_SearchCriteria_Select {
-  protected $_name = 'role_level';
-
-
-  public function buildElement() {
-    $this->_headScript();
-
-    if ((!Class_Users::getIdentity()->isAdmin())
-        && static::DEFAULT_VALUE == $this->_value)
-      $this->_value = ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB;
-
-    return parent::buildElement()
-      ->setLabel($this->_('Niveau d\'accès'))
-      ->setMultiOptions(['all' => $this->_('Tous')]
-                        + ZendAfi_Acl_AdminControllerRoles::getRolesLabelsWithOutSuperAdmin());
-  }
-
-
-  public function isAbonneSigb() {
-    return ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB == $this->_value;
-  }
-
-
-  protected function _headScript() {
-    $toggles = array_map(function($other)
-                         {
-                           return sprintf('formSelectToggleVisibilityForElement("#%s", $("#%s").closest("tr"), ["2"]);',
-                                          $this->getName(),
-                                          static::NAME_PREFIX . $other);
-                         },
-                         ['valid_subscription',
-                          'statut',
-                          'date_fin_start']);
-
-    Class_ScriptLoader::getInstance()->addJQueryReady(implode($toggles));
-  }
-}
-
-
 
 class Class_User_SearchCriteriaValidSubscription extends Class_SearchCriteria_Abstract {
   protected
@@ -101,7 +66,7 @@ class Class_User_SearchCriteriaValidSubscription extends Class_SearchCriteria_Ab
     parent::__construct($params);
 
     $this->_should_filter = $this->_value
-      && (new Class_User_SearchCriteriaRoleLevel($params))->isAbonneSigb();
+      && (new Class_User_SearchCriteria_RoleLevel($params))->isAbonneSigb();
   }
 
 
@@ -112,6 +77,11 @@ class Class_User_SearchCriteriaValidSubscription extends Class_SearchCriteria_Ab
   }
 
 
+  public function getAttributeName() {
+    return 'date_fin' ;
+  }
+
+
   public function acceptSearchVisitor($visitor) {
     if (!$this->_should_filter)
       return;
@@ -120,6 +90,13 @@ class Class_User_SearchCriteriaValidSubscription extends Class_SearchCriteria_Ab
   }
 
 
+  public function modelMatch($user) {
+    return $user->isAbonne()
+      ? $user->isAbonnementValid()
+      : true;
+  }
+
+
   public function describeOn($view) {
     return (0 != $this->_value)
       ? $this->_element->getLabel()
@@ -129,10 +106,12 @@ class Class_User_SearchCriteriaValidSubscription extends Class_SearchCriteria_Ab
 
 
 
+
 class Class_User_SearchCriteriaSearchFor extends Class_SearchCriteria_Abstract{
   protected
     $_name = 'search_for',
-    $_value = '';
+    $_value = '',
+    $_columns = ['login', 'nom', 'prenom', 'pseudo', 'mail', 'idabon'];
 
   public function buildElement() {
     return new Zend_Form_Element_Text($this->getName(),
@@ -142,35 +121,43 @@ class Class_User_SearchCriteriaSearchFor extends Class_SearchCriteria_Abstract{
 
 
   public function acceptSearchVisitor($visitor) {
-    $search_value = str_replace(["\000",
-                                 "\n",
-                                 "\r",
-                                 "\"",
-                                 "\'",
-                                 "'",
-                                 "\032"], '', $this->_value);
-
-    if (!$search_value)
+    if (!$search_value = $this->_sanitize($this->_value))
       return;
 
-    $columns = array_fill_keys(['login',
-                                'nom',
-                                'prenom',
-                                'pseudo',
-                                'mail',
-                                'idabon'],
-                               $search_value);
-
-    foreach($columns as $column => $value)
-      $table_or[] = sprintf('%s LIKE "%%%s%%"', $column, $value);
+    foreach(array_fill_keys($this->_columns, $search_value) as $column => $value)
+      $table_or[] = $column . ' LIKE "%' . $value . '%"';
 
     $visitor->addWhereParam(implode(' OR ', $table_or));
   }
 
 
+  public function modelMatch($user) {
+    if (!$search_value = $this->_sanitize($this->_value))
+      return true;
+
+    return null !== (new Storm_Collection($this->_columns))
+      ->detect(function($each) use($user, $search_value)
+               {
+                 return false !== strpos($user->callGetterByAttributeName($each),
+                                         $search_value);
+               });
+  }
+
+
   public function describeOn($view) {
     return ($this->_value)
       ? ($this->_element->getLabel() . ' : ' . $this->_value)
       : '';
   }
+
+
+  protected function _sanitize($value) {
+    return str_replace(["\000",
+                        "\n",
+                        "\r",
+                        "\"",
+                        "\'",
+                        "'",
+                        "\032"], '', $value);
+  }
 }
\ No newline at end of file
diff --git a/library/Class/User/SearchCriteria/Age.php b/library/Class/User/SearchCriteria/Age.php
new file mode 100644
index 0000000000000000000000000000000000000000..d83a2b80adaf9151775c43787ded41b253b764a6
--- /dev/null
+++ b/library/Class/User/SearchCriteria/Age.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+class Class_User_SearchCriteria_Age extends Class_SearchCriteria_Abstract {
+  use Trait_TimeSource;
+  protected
+    $_name = 'age',
+    $_start_name,
+    $_end_name,
+    $_from = '',
+    $_to = '';
+
+
+  public function __construct($params) {
+    $this->_start_name = $this->getName() . '_debut';
+    $this->_end_name = $this->getName() . '_fin';
+
+    parent::__construct($params);
+
+    $this->_from = isset($params[$this->_start_name])
+      ? $params[$this->_start_name]
+      : '';
+    $this->_to = isset($params[$this->_end_name])
+      ? $params[$this->_end_name]
+      : '';
+    $this->_element->loadDefault($params);
+  }
+
+
+  public function buildElement() {
+    return new ZendAfi_Form_Element_Range($this->getName(),
+                                          ['label' => $this->_('Age à partir de '),
+                                           'separator' => $this->_(' jusqu\'à '),
+                                           'from_suffix' => '_debut',
+                                           'to_suffix' => '_fin']);
+  }
+
+
+  public function acceptSearchVisitor($visitor) {
+    if ($this->_isAllValues())
+      return;
+
+    if ($this->_hasFrom()) {
+      $date = $this->substractYearsToCurrentDate((int)$this->_from);
+      $visitor->addWhereParam('naissance <=\'' . $date.'\'');
+    }
+
+    if ($this->_hasTo()) {
+      $date = $this->substractYearsToCurrentDate((int)$this->_to);
+      $visitor->addWhereParam('naissance >=\'' . $date.'\'');
+    }
+  }
+
+
+  public function modelMatch($user) {
+    if ($this->_isAllValues())
+      return true;
+
+    if (!$user->getNaissance())
+      return false;
+
+    if ($this->_hasFrom()
+        && ($date = $this->substractYearsToCurrentDate((int)$this->_from))
+        && $user->getNaissance() < $date) {
+      return false;
+    }
+
+    if (!$this->_hasTo())
+      return true;
+
+    $date = $this->substractYearsToCurrentDate((int)$this->_to);
+    return $user->getNaissance() <= $date;
+  }
+
+
+  protected function _isAllValues() {
+    return !($this->_hasFrom() || $this->_hasTo());
+  }
+
+
+  protected function _hasFrom() {
+    return '' !== $this->_from;
+  }
+
+
+  protected function _hasTo() {
+    return '' !== $this->_to;
+  }
+}
diff --git a/library/Class/User/SearchCriteria/DateFin.php b/library/Class/User/SearchCriteria/DateFin.php
index 635acaec28020f09a202aa19c535447f596808c5..12438d1e81cbcb4363d4f6ab510d16891dda9fce 100644
--- a/library/Class/User/SearchCriteria/DateFin.php
+++ b/library/Class/User/SearchCriteria/DateFin.php
@@ -26,6 +26,6 @@ class Class_User_SearchCriteria_DateFin extends Class_SearchCriteria_DateRange {
 
 
   public function buildElement() {
-    return parent::buildElement()->setLabel($this->_('Date de fin d\'abonnement'));
+    return parent::buildElement()->setLabel($this->_('Abonnement échu'));
   }
 }
diff --git a/library/Class/User/SearchCriteria/DateMaj.php b/library/Class/User/SearchCriteria/DateMaj.php
index c1f2437256c2abbe8bdc83788ae0a1bab51ffd85..31e68236eb4e3573f563d789edeb20985a61304d 100644
--- a/library/Class/User/SearchCriteria/DateMaj.php
+++ b/library/Class/User/SearchCriteria/DateMaj.php
@@ -28,4 +28,12 @@ class Class_User_SearchCriteria_DateMaj extends Class_SearchCriteria_DateRange {
   public function buildElement() {
     return parent::buildElement()->setLabel($this->_('Mis à jour'));
   }
+
+
+  public function modelMatch($model) {
+    if (!$model->isNew())
+      return parent::modelMatch($model);
+
+    return !($this->_value_start || $this->_value_end);
+  }
 }
diff --git a/library/Class/User/SearchCriteria/EndSubscriptionDate.php b/library/Class/User/SearchCriteria/EndSubscriptionDate.php
new file mode 100644
index 0000000000000000000000000000000000000000..3e6147a1beac629c1d5f63bcd2d414d9bc67cc18
--- /dev/null
+++ b/library/Class/User/SearchCriteria/EndSubscriptionDate.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Copyright (c) 2012-2019, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+class Class_User_SearchCriteria_EndSubscriptionDate extends Class_SearchCriteria_Abstract {
+  use Trait_TimeSource;
+
+  protected
+    $_name = 'end_subscription_days',
+    $_value = '',
+    $_should_filter = false;
+
+  public function __construct($params) {
+    parent::__construct($params);
+
+    $this->_should_filter = $this->_value
+      && (new Class_User_SearchCriteria_RoleLevel($params))->isAbonneSigb();
+  }
+
+
+  public function buildElement() {
+    return new Zend_Form_Element_Text($this->getName(),
+                                      ['label' => $this->_('Abonnement échu d\'ici (jours)'),
+                                       'value' => $this->_value]);
+  }
+
+
+  public function modelMatch($user) {
+    if (!$this->_should_filter)
+        return true;
+
+    return $user->getDateFin()
+      ? $user->getDateFin() <= $this->addDaysToCurrentDate($this->_value)
+      : true;
+  }
+
+
+  public function acceptSearchVisitor($visitor) {
+    if (!$this->_should_filter)
+      return;
+
+    $visitor->addWhereParam('date_fin!=\'\' and date_fin <=\'' . $this->addDaysToCurrentDate($this->_value).'\'');
+  }
+}
diff --git a/library/Class/User/SearchCriteria/InLastSigbExport.php b/library/Class/User/SearchCriteria/InLastSigbExport.php
index 1333e051524fa6da2df92c35b15a51e793597b91..b89517091697636409c5114f1d9e01158f3ccf89 100644
--- a/library/Class/User/SearchCriteria/InLastSigbExport.php
+++ b/library/Class/User/SearchCriteria/InLastSigbExport.php
@@ -26,7 +26,7 @@ class Class_User_SearchCriteria_InLastSigbExport extends Class_SearchCriteria_Se
   public function buildElement() {
     return parent::buildElement()
       ->setLabel($this->_('Présent dans le dernier export SIGB'))
-      ->setMultiOptions([static::DEFAULT_VALUE => $this->_('Indifférent'),
+      ->setMultiOptions([static::ALL_VALUES => $this->_('Indifférent'),
                          '0' => $this->_('Oui'),
                          '1' => $this->_('Non')]);
   }
diff --git a/library/Class/User/SearchCriteria/NumberOfBaskets.php b/library/Class/User/SearchCriteria/NumberOfBaskets.php
index 76997334343bf24853a0623c0fd6686598d8c26c..bbdbe457da9cd0696919cee49a08b19219f4ab66 100644
--- a/library/Class/User/SearchCriteria/NumberOfBaskets.php
+++ b/library/Class/User/SearchCriteria/NumberOfBaskets.php
@@ -19,27 +19,12 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
-class Class_User_SearchCriteria_NumberOfBaskets extends Class_SearchCriteria_Select {
-  protected $_name = 'basket';
+class Class_User_SearchCriteria_NumberOfBaskets extends Class_SearchCriteria_SelectYesNo {
+  protected
+    $_name = 'basket',
+    $_linked_model = Class_PanierNotice::class;
 
   public function buildElement() {
-    return parent::buildElement()
-      ->setLabel($this->_('A créé des paniers'))
-      ->setMultiOptions(['yes' => $this->_('Oui'),
-                         'no' => $this->_('Non'),
-                         'all' => $this->_('Indifférent')])
-      ;
-  }
-
-
-  public function acceptSearchVisitor($visitor) {
-    if (static::DEFAULT_VALUE == $this->_value)
-      return;
-
-    $ids = Class_PanierNotice::findAllUserIds();
-    $ids = implode(',', $ids);
-
-    $operator = ('no' == $this->_value) ? 'not in' : 'in';
-    $visitor->addWhereParam('id_user ' . $operator . ' (' . $ids .  ')');
+    return parent::buildElement()->setLabel($this->_('A créé des paniers'));
   }
 }
diff --git a/library/Class/User/SearchCriteria/NumberOfReviews.php b/library/Class/User/SearchCriteria/NumberOfReviews.php
index 5f069d055e62274321a3213e77de111ff14598d6..5e2d2e4dab0f62f24725c407ac03146d5b5157a2 100644
--- a/library/Class/User/SearchCriteria/NumberOfReviews.php
+++ b/library/Class/User/SearchCriteria/NumberOfReviews.php
@@ -19,27 +19,12 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
-class Class_User_SearchCriteria_NumberOfReviews extends Class_SearchCriteria_Select {
-  protected $_name = 'review';
+class Class_User_SearchCriteria_NumberOfReviews extends Class_SearchCriteria_SelectYesNo {
+  protected
+    $_name = 'review',
+    $_linked_model = Class_AvisNotice::class;
 
   public function buildElement() {
-    return parent::buildElement()
-      ->setLabel($this->_('A rédigé des avis'))
-      ->setMultiOptions(['yes' => $this->_('Oui'),
-                         'no' => $this->_('Non'),
-                         'all' => $this->_('Indifférent')])
-      ;
-  }
-
-
-  public function acceptSearchVisitor($visitor) {
-    if (static::DEFAULT_VALUE == $this->_value)
-      return;
-
-    $ids = Class_AvisNotice::findAllUserIds();
-    $ids = implode(',', $ids);
-
-    $operator = ('no' == $this->_value) ? 'not in' : 'in';
-    $visitor->addWhereParam('id_user ' . $operator . ' (' . $ids .  ')');
+    return parent::buildElement()->setLabel($this->_('A rédigé des avis')) ;
   }
 }
diff --git a/library/Class/User/SearchCriteria/RequiredRoleLevel.php b/library/Class/User/SearchCriteria/RequiredRoleLevel.php
new file mode 100644
index 0000000000000000000000000000000000000000..b3b01761c146c9d4c2b43ce431461d3ed106880b
--- /dev/null
+++ b/library/Class/User/SearchCriteria/RequiredRoleLevel.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright (c) 2012-2020, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+class Class_User_SearchCriteria_RequiredRoleLevel extends Class_User_SearchCriteria_RoleLevel {
+
+  public function buildElement() {
+    return ($element = parent::buildElement())
+      ? $element->setMultiOptions(ZendAfi_Acl_AdminControllerRoles::getRolesLabelsWithOutSuperAdmin())
+      : null;
+  }
+}
diff --git a/library/Class/User/SearchCriteria/RoleLevel.php b/library/Class/User/SearchCriteria/RoleLevel.php
new file mode 100644
index 0000000000000000000000000000000000000000..8b012e06b7167115a0a1348339f057cb90ebf9eb
--- /dev/null
+++ b/library/Class/User/SearchCriteria/RoleLevel.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Copyright (c) 2012-2020, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_User_SearchCriteria_RoleLevel extends Class_SearchCriteria_Select {
+  protected $_name = 'role_level';
+
+
+  public function buildElement() {
+    $this->_headScript();
+
+    if (!Class_Users::getIdentity())
+      return;
+
+    if ((!Class_Users::getIdentity()->isAdmin())
+        && $this->_isAllValues())
+      $this->_value = ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB;
+
+    return parent::buildElement()
+      ->setLabel($this->_('Niveau d\'accès'))
+      ->setMultiOptions([static::ALL_VALUES => $this->_('Tous')]
+                        + ZendAfi_Acl_AdminControllerRoles::getRolesLabelsWithOutSuperAdmin());
+  }
+
+
+  public function isAbonneSigb() {
+    return ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB == $this->_value;
+  }
+
+
+  protected function _headScript() {
+    $toggles = array_map(function($other)
+                         {
+                           return sprintf('formSelectToggleVisibilityForElement("#%s", $("#%s").closest("tr"), ["2"]);',
+                                          $this->getName(),
+                                          static::NAME_PREFIX . $other);
+                         },
+                         ['valid_subscription',
+                          'end_subscription_days',
+                          'statut',
+                          'date_fin_start']);
+
+    Class_ScriptLoader::getInstance()->addJQueryReady(implode($toggles));
+  }
+}
diff --git a/library/Class/UserGroup.php b/library/Class/UserGroup.php
index 91924194844d5569ef5b17d29d03813e43be82c6..5c2ede4bb4552dc79082c8244f644dd87918d580 100644
--- a/library/Class/UserGroup.php
+++ b/library/Class/UserGroup.php
@@ -40,8 +40,10 @@ class UserGroupLoader extends Storm_Model_Loader {
       ? $this->_getManualUserIdsOf($group)
       : $this->_getDynamicUserIdsOf($group);
 
-    return array_map(function($item) { return $item['id']; },
-                     $result);
+    return $result
+      ? array_map(function($item) { return $item['id']; },
+                  $result)
+      : [];
   }
 
 
@@ -52,12 +54,8 @@ class UserGroupLoader extends Storm_Model_Loader {
 
 
   protected function _getDynamicUserIdsOf($group) {
-    $params = ['role_level = ' . $group->getRoleLevel()];
-    if ($library = $group->getLibrary())
-      $params[] = 'id_site = ' . $library->getId();
-
-    return Zend_Registry::get('sql')
-      ->fetchAll('select id_user as id from bib_admin_users where ' . implode(' and ', $params));
+    $criteria = $group->getCriteria();
+    return $criteria->fetchAll(['id_user as id']);
   }
 
 
@@ -96,6 +94,11 @@ class UserGroupLoader extends Storm_Model_Loader {
   public function findAllDedicatedTo($model_class) {
     return Class_UserGroup::findAllBy(['model_class' => $model_class]);
   }
+
+
+  public function findAllDynamics() {
+    return Class_UserGroup::findAllBy(['group_type' => Class_UserGroup::TYPE_DYNAMIC]);
+  }
 }
 
 
@@ -136,8 +139,7 @@ class Class_UserGroup extends Storm_Model_Abstract {
 
   protected $_belongs_to = ['categorie' => ['model' => 'Class_UserGroupCategorie',
                                             'referenced_in' => 'id_cat'],
-                            'library' => ['model' => 'Class_Bib',
-                                          'referenced_in' => 'id_bib']];
+  ];
 
   // Les droits sont utilisés comme puissance de 2 (ce sont des masques) pour l'attribut rights_token
   const RIGHT_SUIVRE_ACTIVITY = 0;
@@ -184,10 +186,9 @@ class Class_UserGroup extends Storm_Model_Abstract {
 
   protected $_default_attribute_values = ['rights_token' => 0,
                                           'group_type' => 0,
-                                          'id_bib' => 0,
-                                          'role_level' => 0,
                                           'model_class' => null,
-                                          'model_id' => null];
+                                          'model_id' => null,
+                                          'filters' => ''];
 
 
   public static function getRightDefinitionList() {
@@ -281,8 +282,9 @@ class Class_UserGroup extends Storm_Model_Abstract {
    * @return int
    */
   public function numberOfUsers() {
-    return $this->isManual() ?
-      parent::_numberOf('users') : $this->numberOfDynamicUsers();
+    return $this->isManual()
+      ? parent::_numberOf('users')
+      : $this->numberOfDynamicUsers();
   }
 
 
@@ -293,26 +295,16 @@ class Class_UserGroup extends Storm_Model_Abstract {
     if ($this->isManual())
       return in_array($user->getId(), $this->getUsersIdsOptimized());
 
-    if ($user->getRoleLevel() != $this->getRoleLevel())
-      return false;
-
-    return ($library = $this->getLibrary())
-      ? ($this->getLibrary() == $user->getLibrary())
-      : true;
+    return ($criteria = $this->getCriteria())
+      ? $criteria->modelMatch($user)
+      : false;
   }
 
 
   public function numberOfDynamicUsers() {
-    return $this->isDynamic() ?
-      Class_Users::countBy($this->_getDynamicParams()) : 0;
-  }
-
-
-  protected function _getDynamicParams() {
-    $params = ['role_level' => $this->getRoleLevel()];
-    if ($library = $this->getLibrary())
-      $params['id_site'] = $library->getId();
-    return $params;
+    return $this->isDynamic()
+      ? $this->getCriteria()->count()
+      : 0;
   }
 
 
@@ -540,12 +532,9 @@ class Class_UserGroup extends Storm_Model_Abstract {
 
 
   public function getDynamicUsersPage($page, $items_by_page) {
-    if (!$this->isDynamic())
-      return [];
-
-    $params = $this->_getDynamicParams();
-    $params['limitPage'] = [$page, $items_by_page];
-    return Class_Users::findAllBy($params);
+    return $this->isDynamic()
+      ? $this->getCriteria()->findPage($page, $items_by_page)
+      : [];
   }
 
 
@@ -648,4 +637,19 @@ class Class_UserGroup extends Storm_Model_Abstract {
   public function addUserOptimized($user) {
     $this->getLoader()->addUserByIdTo($user->getId(), $this);
   }
+
+
+  public function getFiltersAsArray() {
+    if (!$this->isDynamic())
+      return [];
+
+    return ($filters = json_decode($this->getFilters(), true))
+      ? $filters
+      : [];
+  }
+
+
+  public function getCriteria() {
+    return (new Class_UserGroup_Filter($this->getFiltersAsArray()));
+  }
 }
\ No newline at end of file
diff --git a/library/Class/UserGroup/Filter.php b/library/Class/UserGroup/Filter.php
new file mode 100644
index 0000000000000000000000000000000000000000..4d645db904b67972e2e166eaa69dca89d0ccdf7c
--- /dev/null
+++ b/library/Class/UserGroup/Filter.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright (c) 2012-2019, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_UserGroup_Filter extends Class_User_SearchCriteria {
+  public function __construct($params) {
+    parent::__construct($params);
+    $this->replaceCriteria(Class_User_SearchCriteria_RoleLevel::class,
+                           new Class_User_SearchCriteria_RequiredRoleLevel($params));
+  }
+}
diff --git a/library/Class/Users.php b/library/Class/Users.php
index e0a9c8337ad3eaeeed32766cf824ba40839ee2b4..705a8e3410c196f1d6f2226086797546d537a7ba 100644
--- a/library/Class/Users.php
+++ b/library/Class/Users.php
@@ -826,15 +826,9 @@ class Class_Users extends Storm_Model_Abstract {
   }
 
 
-  /** @return array */
   public function getDynamicUserGroups() {
-    $params = ['role_level' => $this->getRoleLevel(),
-               'group_type' => Class_UserGroup::TYPE_DYNAMIC];
-
-    if ($library = $this->getBib())
-      $params['id_bib'] = [0, $library->getId()];
-
-    return Class_UserGroup::findAllBy($params);
+    return array_filter(Class_UserGroup::findAllDynamics(),
+                        function($group) { return $group->hasUser($this); });
   }
 
 
@@ -1088,7 +1082,6 @@ class Class_Users extends Storm_Model_Abstract {
     $this->check($this->hasRightDirigerActivity() or (count($this->getSessionInterventions()) === 0),
                  $this->_('Vous n\'avez pas les droits suffisants pour diriger une activité'));
 
-
     $this->checkAttribute('mail',($this->getMail() || !$this->getIsContactMail()),
                           $this->_('Vous devez fournir une adresse mail valide'));
 
diff --git a/library/Trait/TimeSource.php b/library/Trait/TimeSource.php
index 5c2570cd49d675f4aa33c490a3c17f89d12d3c0a..973d3e39e273569a1a925604f561f7f1bc9b00fd 100644
--- a/library/Trait/TimeSource.php
+++ b/library/Trait/TimeSource.php
@@ -47,6 +47,15 @@ trait Trait_TimeSource {
     return date('Y-m-d H:i:s',self::getTimeSource()->time());
   }
 
+  public static function substractYearsToCurrentDate($days) {
+    return date('Y-m-d',strtotime('-'.(string)$days.' year', self::getTimeSource()->time()));
+  }
+
+
+  public static function addDaysToCurrentDate($days) {
+    $now = date('Y-m-d',strtotime((string)$days.' day', self::getTimeSource()->time()));
+    return $now;
+  }
 
   /** @return Class_TimeSource */
   public static function getTimeSource() {
diff --git a/library/ZendAfi/Controller/Plugin/Manager/Manager.php b/library/ZendAfi/Controller/Plugin/Manager/Manager.php
index 6373fdc36091d1dba4e533054fd26b5d38fc9d7e..d63bcabd39bedd1bd2f54819a08e61287a181e2b 100644
--- a/library/ZendAfi/Controller/Plugin/Manager/Manager.php
+++ b/library/ZendAfi/Controller/Plugin/Manager/Manager.php
@@ -72,9 +72,9 @@ class ZendAfi_Controller_Plugin_Manager_Manager extends ZendAfi_Controller_Plugi
                                 {
                                   return $this->_getDefaultModel($models);
                                 })
-            ->visitProcessMultiCheckbox(function($form, $clean)
+            ->visitProcessMultiCheckbox(function($form, $post, $clean)
                                         {
-                                          return $this->processMulticheckboxFromPost($form, $clean);
+                                          return $this->processMulticheckboxFromPost($form, $post, $clean);
                                         })
             ->visitCustomValues(function()
                                 {
@@ -296,8 +296,8 @@ class ZendAfi_Controller_Plugin_Manager_Manager extends ZendAfi_Controller_Plugi
     if (!$this->_request->isPost())
       return false;
 
-    $post = $this->processMulticheckboxFromPost($form);
-    $model->updateAttributes($post);
+    $attributes = $this->_convertFormPostToAttributes($form, $this->_getPost());
+    $model->updateAttributes($attributes);
 
     if ((!$form->isValidModelAndArray($model, $this->_getPost())))
       return false;
@@ -328,12 +328,17 @@ class ZendAfi_Controller_Plugin_Manager_Manager extends ZendAfi_Controller_Plugi
   }
 
 
-  protected function processMulticheckboxFromPost($form, $clean = false) {
+  protected function _convertFormPostToAttributes($form, $post) {
+    return $this->processMulticheckboxFromPost($form, $post);
+  }
+
+
+  protected function processMulticheckboxFromPost($form, $post, $clean = false) {
     $defaults = [];
     foreach ($form->getMulticheckboxNames() as $checkbox_name)
       $defaults[$checkbox_name] = [];
 
-    $post = array_merge($defaults, $this->_getPost());
+    $post = array_merge($defaults, $post);
 
     if ($clean)
       $post = $form->deleteUnchanged($post);
diff --git a/library/ZendAfi/Controller/Plugin/Manager/UserGroup.php b/library/ZendAfi/Controller/Plugin/Manager/UserGroup.php
index 44695df96856785a35c12534f639331c0a8364a5..7a3042e91a377dbdd8d59f0577c86bf57ea27a60 100644
--- a/library/ZendAfi/Controller/Plugin/Manager/UserGroup.php
+++ b/library/ZendAfi/Controller/Plugin/Manager/UserGroup.php
@@ -21,6 +21,34 @@
 
 
 class ZendAfi_Controller_Plugin_Manager_UserGroup extends ZendAfi_Controller_Plugin_Manager_Manager {
+
+  protected function _getForm($model) {
+    $form = parent::_getForm($model);
+
+    return ($search_criteria = $model->getCriteria())
+      ? $search_criteria->addFormElementsTo($form, 'dynamic_filter', $this->_('Filtre'))
+      : $form;
+  }
+
+
+  protected function _convertFormPostToAttributes($form, $post) {
+    $post = parent::_convertFormPostToAttributes($form, $post);
+    $filters = [];
+    $post_filters = array_filter($post,
+                                 ['Class_UserGroup_Filter', 'isCriteriaName'],
+                                 ARRAY_FILTER_USE_KEY);
+    foreach($post_filters as $key => $value) {
+      $filters[$key] = $value;
+      unset($post[$key]);
+    }
+
+    if ($filters)
+      $post['filters'] = json_encode($filters);
+
+    return $post;
+  }
+
+
   public function editmembersAction() {
     if (!$group = Class_UserGroup::find((int)$this->_getParam('id'))) {
       $this->_redirect('admin/usergroup');
diff --git a/library/ZendAfi/Controller/Plugin/MultiSelection/Abstract.php b/library/ZendAfi/Controller/Plugin/MultiSelection/Abstract.php
index c4d55fcea62fc13e8ab0b24851261e90282f97e1..f9bc12403253e6832a0f20673843108de9a0c5f3 100644
--- a/library/ZendAfi/Controller/Plugin/MultiSelection/Abstract.php
+++ b/library/ZendAfi/Controller/Plugin/MultiSelection/Abstract.php
@@ -113,7 +113,8 @@ abstract class ZendAfi_Controller_Plugin_MultiSelection_Abstract extends ZendAfi
     if (!$this->_request->isPost())
       return;
 
-    if ((!$post = $this->processMulticheckboxFromPost($form, true)) && !($custom_values = $this->getCustomValues()))
+    if ((!$post = $this->processMulticheckboxFromPost($form, $this->_getPost(), true))
+        && !($custom_values = $this->getCustomValues()))
       return $this->_helper->notify($this->_('Les données transmises sont vide. Les modifications n\'ont pas été prises en compte.'));
 
     do {
@@ -228,8 +229,8 @@ abstract class ZendAfi_Controller_Plugin_MultiSelection_Abstract extends ZendAfi
   }
 
 
-  protected function processMulticheckboxFromPost($form, $clean = false) {
-    return call_user_func_array($this->_process_multi_checkbox, [$form, $clean]);
+  protected function processMulticheckboxFromPost($form, $post, $clean = false) {
+    return call_user_func_array($this->_process_multi_checkbox, [$form, $post, $clean]);
   }
 
 
diff --git a/library/ZendAfi/Form/Admin/UserGroup.php b/library/ZendAfi/Form/Admin/UserGroup.php
index fb021dcd130f232454843aa8d68566fda6566192..f482cb4e94d2567c63d75b6432b06de9ed73a255 100644
--- a/library/ZendAfi/Form/Admin/UserGroup.php
+++ b/library/ZendAfi/Form/Admin/UserGroup.php
@@ -33,7 +33,6 @@ class ZendAfi_Form_Admin_UserGroup extends ZendAfi_Form {
       ->setAttrib('id', 'usergroupform')
       ->addRequiredTextNamed('libelle')
       ->setLabel('Libellé');
-
     $this
       ->addElement('select', 'id_cat',
                    ['label' =>  $this->_('Catégorie'),
@@ -44,28 +43,12 @@ class ZendAfi_Form_Admin_UserGroup extends ZendAfi_Form {
                     'multiOptions' => [Class_UserGroup::TYPE_MANUAL =>  $this->_(Class_UserGroup::TYPE_MANUAL_TEXT),
                                        Class_UserGroup::TYPE_DYNAMIC => $this->_(Class_UserGroup::TYPE_DYNAMIC_TEXT),
                                        Class_UserGroup::TYPE_MULTIMEDIA => $this->_(Class_UserGroup::TYPE_MULTIMEDIA_TEXT)]] )
-      ->addElement('select',
-                   'role_level',
-                   ['label' => $this->_('Rôle'),
-                    'multiOptions' => ZendAfi_Acl_AdminControllerRoles::getListeRolesWithoutSuperAdmin()] )
-
-      ->addElement('comboLibraries', 'id_bib',
-                   ['label' => $this->_('Bibliothèque')])
-
       ->addDisplayGroup(['libelle', 'id_cat', 'group_type'],
                         'usergroup',
-                        ['legend' => $this->_('Groupe')])
-
-      ->addDisplayGroup(['role_level', 'id_bib'],
-                        'dynamic_filter',
-                        ['legend' => $this->_('Filtre')]);
-
-    $this->displayGroupFiltreVisibleOnlyOnDynamicGroup();
+                        ['legend' => $this->_('Groupe')]);
 
     if (($user = Class_Users::getIdentity())
         && $user->isAdmin()) {
-      $this->displayRightsGroupVisibleOnlyOnDynamicAndManuelGroup();
-
       $this
         ->addElement('multiCheckbox',
                      ZendAfi_Form_Admin_UserGroup::RIGHTS_PERMISSIONS,
@@ -109,18 +92,6 @@ class ZendAfi_Form_Admin_UserGroup extends ZendAfi_Form {
   }
 
 
-  public function displayGroupFiltreVisibleOnlyOnDynamicGroup() {
-    Class_ScriptLoader::getInstance()
-      ->addJqueryReady('formSelectToggleVisibilityForElement("input[name=\'group_type\']", "#fieldset-dynamic_filter", ["1"]);');
-  }
-
-
-  public function displayRightsGroupVisibleOnlyOnDynamicAndManuelGroup() {
-    Class_ScriptLoader::getInstance()
-      ->addJqueryReady('formSelectToggleVisibilityForElement("input[name=\'group_type\']", "#fieldset-rights_group", ["0","1"]);');
-  }
-
-
   protected function getRightsPermissionsOptions() {
     $rights_permissions = [];
 
diff --git a/library/ZendAfi/View/Helper/Admin/SearchUsers.php b/library/ZendAfi/View/Helper/Admin/SearchUsers.php
index 015e79889637bcb60c8baa61394d7a9613b69aaf..8958980357ffb767affbe30c9303038f8ed267c3 100644
--- a/library/ZendAfi/View/Helper/Admin/SearchUsers.php
+++ b/library/ZendAfi/View/Helper/Admin/SearchUsers.php
@@ -47,7 +47,7 @@ class ZendAfi_View_Helper_Admin_SearchUsers
                                                        'controller' => 'users',
                                                        'action' => 'mass-delete'],
                                                       null, true)
-                                     . '?' . http_build_query($this->_context->getParams()))
+                                     . '?' . http_build_query(array_filter($this->_context->getParams())))
                             ->setImage($this->view->tagImg(Class_Admin_Skin::current()
                                                            ->getIconUrl('buttons',
                                                                         'delete'),
diff --git a/library/digital_resources/Lekiosk/tests/LekioskTest.php b/library/digital_resources/Lekiosk/tests/LekioskTest.php
index a57fb2970e5aa8a284c764bf313cf86c95059492..e229b170e32c69524ef281a029ff3adccc7cb94b 100644
--- a/library/digital_resources/Lekiosk/tests/LekioskTest.php
+++ b/library/digital_resources/Lekiosk/tests/LekioskTest.php
@@ -461,8 +461,8 @@ class LekioskAdminUserGroupControllerRessourcesNumeriquesTest extends Admin_Abst
                     'group_type' => Class_UserGroup::TYPE_DYNAMIC,
                     'users' => [],
                     'rights' => [],
-                    'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
-                    'id_bib' => 9]);
+                    'filters' => json_encode(['search_role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
+                                              'search_id_site' => 9])]);
   }
 
 
diff --git a/library/digital_resources/Skilleos/tests/SkilleosTest.php b/library/digital_resources/Skilleos/tests/SkilleosTest.php
index 36de985143b4d8635158c0818c41873a32a36694..61f9e4f7c52d04407234c3b227bb3d22447a477d 100644
--- a/library/digital_resources/Skilleos/tests/SkilleosTest.php
+++ b/library/digital_resources/Skilleos/tests/SkilleosTest.php
@@ -367,8 +367,8 @@ class SkilleosAdminUserGroupControllerRessourcesNumeriquesTest extends Admin_Abs
                     'group_type' => Class_UserGroup::TYPE_DYNAMIC,
                     'users' => [],
                     'rights' => [],
-                    'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
-                    'id_bib' => 9]);
+                    'filters' => json_encode(['search_role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
+                                              'search_id_site' => 9])]);
   }
 
 
diff --git a/library/storm b/library/storm
index e999f53a9da4da9331fdb78f62a597afbffd453a..8df83e250971ac58a84f47350cc2acc5b2610341 160000
--- a/library/storm
+++ b/library/storm
@@ -1 +1 @@
-Subproject commit e999f53a9da4da9331fdb78f62a597afbffd453a
+Subproject commit 8df83e250971ac58a84f47350cc2acc5b2610341
diff --git a/scripts/user_anonymize.php b/scripts/user_anonymize.php
new file mode 100644
index 0000000000000000000000000000000000000000..c5a33e1c22af2b0c81b013ad2ee66a1a8f71edbc
--- /dev/null
+++ b/scripts/user_anonymize.php
@@ -0,0 +1,67 @@
+<?php
+require './console.php';
+
+class Anonymize{
+  protected $_current;
+
+  public function one($user) {
+    if ($user->isSuperAdmin())
+      return $this;
+
+    $this->_current = $user;
+
+    return $this->_changeToPapotituIfPresent(['login', 'pseudo', 'nom', 'prenom'])
+                ->_clearString(['naissance', 'telephone', 'mobile', 'adresse'])
+                ->_mail();
+  }
+
+  protected function _mail() {
+    if ($this->_current->hasMail())
+      $this->_current->setMail($this->_current->getLogin() . '@nowhere.com');
+
+    return $this;
+  }
+
+  protected function _changeToPapotituIfPresent($attributes) {
+    foreach($attributes as $attribute)
+      $this->_changeOneToPapotituIfPresent($attribute);
+
+    return $this;
+  }
+
+  protected function _changeOneToPapotituIfPresent($attribute) {
+    if (!$this->_current->callGetterByAttributeName($attribute))
+      return $this;
+
+    $vowels = ['a', 'e', 'i', 'o', 'u'];
+    $consonants = array_diff(range('a', 'w'), $vowels);
+    $value = '';
+    foreach(range(0, rand(6, 12) - 1) as $index) {
+      $possibles = (0 == $index % 2) ? $consonants : $vowels;
+      $value .= $possibles[array_rand($possibles)];
+    }
+
+    $this->_current->callSetterByAttributeName($attribute, $value);
+
+    return $this;
+  }
+
+
+  protected function _clearString($attributes) {
+    foreach($attributes as $attribute)
+      $this->_current->callSetterByAttributeName($attribute, '');
+
+    return $this;
+  }
+}
+
+
+$a = new Anonymize();
+
+foreach(Class_Users::findAll() as $user) {
+  $a->one($user);
+  $user->save();
+  echo '.';
+}
+
+echo "\n";
\ No newline at end of file
diff --git a/tests/application/modules/AbstractControllerTestCase.php b/tests/application/modules/AbstractControllerTestCase.php
index 655a26cfdeb4d952d155d54b838dec6f90602154..a030c14e620062d712a7b27199b15d7cb535ff9f 100644
--- a/tests/application/modules/AbstractControllerTestCase.php
+++ b/tests/application/modules/AbstractControllerTestCase.php
@@ -94,7 +94,8 @@ abstract class AbstractControllerTestCase extends Zend_Test_PHPUnit_ControllerTe
       ->newInstanceWithId(666)
       ->setLogin($account->username)
       ->setRoleLevel($account->ROLE_LEVEL)
-      ->setIdSite($account->ID_SITE);
+      ->setIdSite($account->ID_SITE)
+      ->setDateMaj('');
 
     ZendAfi_Auth::getInstance()->getStorage()->write($account);
   }
diff --git a/tests/application/modules/admin/controllers/AdminAvisModerationControllerTest.php b/tests/application/modules/admin/controllers/AdminAvisModerationControllerTest.php
index 1751f5bce64de6444296ee4ddbd734e23d7502b5..3cd7b0db70cd1b2c7467356bad334340211ce5c7 100644
--- a/tests/application/modules/admin/controllers/AdminAvisModerationControllerTest.php
+++ b/tests/application/modules/admin/controllers/AdminAvisModerationControllerTest.php
@@ -41,15 +41,17 @@ abstract class AdminAvisModerationControllerTestCase extends AbstractControllerT
                                                  'password' => 'test',
                                                  'pseudo' => 'Erik',
                                                  'id_site' => 1,
+                                                 'date_maj' => '',
                                                  'idabon' => '000x000']);
 
     $this->marcus = $this->fixture('Class_Users', ['id' => 5,
-                                                 'role_level' => 2,
-                                                 'login' => 'mc',
-                                                 'password' => 'test',
-                                                 'pseudo' => 'Marcus',
-                                                 'id_site' => 1,
-                                                 'idabon' => '000x0E0']);
+                                                   'role_level' => 2,
+                                                   'login' => 'mc',
+                                                   'password' => 'test',
+                                                   'pseudo' => 'Marcus',
+                                                   'id_site' => 1,
+                                                   'date_maj' => '',
+                                                   'idabon' => '000x0E0']);
 
 
     $this->club_cinq = $this->fixture('Class_Notice', ['id' => 18,
@@ -362,6 +364,7 @@ abstract class AdminAvisModerationControllerCmsWithAvisTestCase extends Admin_Ab
                                               'pseudo' => 'Pat',
                                               'mail' => 'pat@afi.fr',
                                               'password' => 'pass',
+                                              'date_maj' => '',
                                               'login' => 'login'])]);
 
   }
diff --git a/tests/application/modules/admin/controllers/AdminIndexControllerTest.php b/tests/application/modules/admin/controllers/AdminIndexControllerTest.php
index 23a09001d62c1aee5155d067e86873f255bd1454..d1c068457a6005cca23e856ccd309b42d81f1cdb 100644
--- a/tests/application/modules/admin/controllers/AdminIndexControllerTest.php
+++ b/tests/application/modules/admin/controllers/AdminIndexControllerTest.php
@@ -778,6 +778,7 @@ class AdminIndexControllerDisplayModifierNomDomaineTest extends AbstractControll
     $user = $this->fixture('Class_Users', ['id' => 8,
                                            'login' => 'joe',
                                            'password' => 'foo',
+                                           'date_maj' => '',
                                            'role_level' => ZendAfi_Acl_AdminControllerRoles::ADMIN_PORTAIL]);
 
     ZendAfi_Auth::getInstance()->logUser($user);
@@ -792,6 +793,7 @@ class AdminIndexControllerDisplayModifierNomDomaineTest extends AbstractControll
     $user = $this->fixture('Class_Users', ['id' => 8,
                                            'login' => 'joe',
                                            'password' => 'foo',
+                                           'date_maj' => '',
                                            'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL]);
 
     ZendAfi_Auth::getInstance()->logUser($user);
diff --git a/tests/application/modules/admin/controllers/CatalogueControllerTest.php b/tests/application/modules/admin/controllers/CatalogueControllerTest.php
index 644439700b41ceee010bbb218c396aecf95a8367..00fe75688314cc555033a89b1cf9a52f0586f9f3 100644
--- a/tests/application/modules/admin/controllers/CatalogueControllerTest.php
+++ b/tests/application/modules/admin/controllers/CatalogueControllerTest.php
@@ -47,10 +47,10 @@ abstract class AdminCatalogueControllerTestCase extends AbstractControllerTestCa
 
     $panier_jeunesse_dupont = Class_PanierNotice::newInstanceWithId(3,
                                                                     ['libelle' => 'selection jeunesse',
-                                                                     'user' => Class_Users::newInstanceWithId(45, ['nom' => 'Dupont']),
+                                                                     'user' => Class_Users::newInstanceWithId(45, ['nom' => 'Dupont','date_maj' => '']),
                                                                      'catalogues' => []]);
 
-    $duchamp = Class_Users::newInstanceWithId(98, ['nom' => 'Duchamp']);
+    $duchamp = Class_Users::newInstanceWithId(98, ['nom' => 'Duchamp', 'date_maj' => '']);
     $panier_adulte_duchamp = Class_PanierNotice::newInstanceWithId(8,
                                                                    ['libelle' => 'selection adulte',
                                                                     'user' => $duchamp,
@@ -87,7 +87,8 @@ abstract class AdminCatalogueControllerTestCase extends AbstractControllerTestCa
 
     $this->user_referent=Class_Users::newInstanceWithId(2,['login' => 'referent',
                                                            'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL,
-                                                           'pseudo' => 'referent']);
+                                                           'pseudo' => 'referent',
+                                                           'date_maj' => '']);
     $histoire = Class_Catalogue::newInstanceWithId(100,
                                                    [ 'libelle' => 'Histoire',
                                                     'sous_domaines' => [
@@ -1480,6 +1481,7 @@ class CatalogueControllerDomaintePaniersJsonActionTest extends AbstractControlle
     $this->fixture('Class_Users',
                    ['id' => 22,
                     'login' => 'Marie-Laure',
+                    'date_maj' => '',
                     'password' => 'only1Password'])->addPanier(Class_PanierNotice::find(22))
          ->setRoleLevel(ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL)
          ->save();
diff --git a/tests/application/modules/admin/controllers/FileManagerControllerTest.php b/tests/application/modules/admin/controllers/FileManagerControllerTest.php
index a846da1b3a5daa2838f1075d6581b1cc1df86257..2a1c8aa394261edbbf01a44a6f5b659e4c950432 100644
--- a/tests/application/modules/admin/controllers/FileManagerControllerTest.php
+++ b/tests/application/modules/admin/controllers/FileManagerControllerTest.php
@@ -1839,7 +1839,8 @@ class FileManagerControllerRightsTest extends Admin_AbstractControllerTestCase {
     $admin = $this->fixture('Class_Users',
                             ['id' => 3,
                              'login' => 'admin',
-                             'password' => 'admin']);
+                             'password' => 'admin',
+                             'date_maj' => '']);
     $admin->beAdminPortail();
     ZendAfi_Auth::getInstance()->logUser($admin);
     $this->dispatch('/admin/file-manager/index', true);
@@ -1892,7 +1893,9 @@ class FileManagerControllerAsModoBibTest extends Admin_AbstractControllerTestCas
                                                          'login' => 'modo bib',
                                                          'password' => 'modo bib',
                                                          'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
-                                                         'id_site' => 2]));
+                                                         'id_site' => 2,
+                                                         'date_maj' => ''
+                                                        ]));
 
     $this->dispatch('/admin/file-manager', true);
   }
diff --git a/tests/application/modules/admin/controllers/ProfilControllerTest.php b/tests/application/modules/admin/controllers/ProfilControllerTest.php
index 6cce7b14255b235bb6f95f188976967979d1fbb9..6871a7d0dc97be5877548dfd39cefc19068bad1b 100644
--- a/tests/application/modules/admin/controllers/ProfilControllerTest.php
+++ b/tests/application/modules/admin/controllers/ProfilControllerTest.php
@@ -1565,6 +1565,7 @@ class Admin_ProfilControllerIndexWithLibraryAdminConnectedTest extends Admin_Abs
                                 ['id' => 54,
                                  'login' => 'admin bib',
                                  'password' => 'popup',
+                                 'date_maj' => '',
                                  'id_site' => 4]);
     $admin_bib->beAdminBib();
     ZendAfi_Auth::getInstance()->logUser($admin_bib);
diff --git a/tests/application/modules/admin/controllers/ReferentPortailControllerTest.php b/tests/application/modules/admin/controllers/ReferentPortailControllerTest.php
index 5ec0a387fd4591960d1366587b264c688726da94..06b2e2496d819777b5933753ae1b870672e2b7fc 100644
--- a/tests/application/modules/admin/controllers/ReferentPortailControllerTest.php
+++ b/tests/application/modules/admin/controllers/ReferentPortailControllerTest.php
@@ -39,7 +39,8 @@ abstract class ReferentPortailControllerTestCase extends AbstractControllerTestC
     $user_referent=Class_Users::getLoader()->newInstanceWithId(777)
                                            ->setLogin('referent')
                                            ->setRoleLevel(ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL)
-                                           ->setPseudo('referent');
+                                           ->setPseudo('referent')
+                                           ->setDateMaj('');
 
     $this->addUserToRightsReferent($user_referent);
 
diff --git a/tests/application/modules/admin/controllers/UserGroupControllerTest.php b/tests/application/modules/admin/controllers/UserGroupControllerTest.php
index e5cc9214cd925752ce2a1630cd7b833385655055..9e6d444d4549cc582a5ec080dd05640fb16e1f21 100644
--- a/tests/application/modules/admin/controllers/UserGroupControllerTest.php
+++ b/tests/application/modules/admin/controllers/UserGroupControllerTest.php
@@ -77,6 +77,8 @@ abstract class Admin_UserGroupControllerTestCase extends Admin_AbstractControlle
                                                 'group_type' => Class_UserGroup::TYPE_DYNAMIC,
                                                 'users' => [],
                                                 'rights' => [],
+                                                'filters' => json_encode(['search_role_level' => '3',
+                                                                          'search_id_site' => '9']),
                                                 'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
                                                 'id_bib' => 9]);
 
@@ -613,31 +615,37 @@ class Admin_UserGroupControllerEditGroupModerateursBibTest extends Admin_UserGro
 
   /** @test */
   public function roleLevelSelectShouldHaveRoleModoBibSelected() {
-    $this->assertXPath('//select[@name="role_level"]/option[@value="3"][@label="rédacteur bibliothèque"][@selected="selected"]');
+    $this->assertXPath('//select[@name="search_role_level"]/option[@value="3"][@label="Rédacteur bibliothèque"][@selected="selected"]');
+  }
+
+
+  /** @test */
+  public function roleLevelSelectShouldNotHaveAllOptions() {
+    $this->assertNotXPath('//select[@name="search_role_level"]/option[@value="all"]');
   }
 
 
   /** @test */
   public function roleLevelSelectShouldHaveOnlyOneSelected() {
-    $this->assertXPathCount('//select[@name="role_level"]/option[@selected="selected"]', 1);
+    $this->assertXPathCount('//select[@name="search_role_level"]/option[@selected="selected"]', 1);
 
   }
 
   /** @test */
   public function roleLevelSelectShouldNotDisplaySysAdmRole() {
-    $this->assertNotXPath('//select[@name="role_level"]/option[@value="7"]');
+    $this->assertNotXPath('//select[@name="search_role_level"]/option[@value="7"]');
   }
 
 
   /** @test */
   public function librarySelectShouldBePresent() {
-    $this->assertXPath('//select[@name="id_bib"]');
+    $this->assertXPath('//select[@name="search_id_site"]');
   }
 
 
   /** @test */
   public function librarySelectShouldHaveAnnecySelected() {
-    $this->assertXPath('//select[@name="id_bib"]//option[@value="9"][@selected="selected"]');
+    $this->assertXPath('//select[@name="search_id_site"]//option[@value="9"][@selected="selected"]');
   }
 }
 
@@ -693,7 +701,8 @@ class Admin_UserGroupControllerEditMembersGroupStagiairesTest extends Admin_User
 
 
 
-class Admin_UserGroupControllerAddMemberSupermanGroupStagiairesTest extends Admin_UserGroupControllerTestCase {
+class Admin_UserGroupControllerAddMemberSupermanGroupStagiairesTest
+  extends Admin_UserGroupControllerTestCase {
   public function setUp() {
     parent::setUp();
 
@@ -702,7 +711,8 @@ class Admin_UserGroupControllerAddMemberSupermanGroupStagiairesTest extends Admi
                     'login' => 'Superman',
                     'password' => 'crypto',
                     'nom' => 'Clark',
-                    'prenom' => 'Kent']);
+                    'prenom' => 'Kent',
+                    'date_maj' => '']);
 
     $this->postDispatch('/admin/usergroup/editmembers/id/3',
                         ['users' => [56]]);
@@ -765,6 +775,26 @@ class Admin_UserGroupControllerDeleteMemberSpidermanFromGroupStagiairesFromNewsl
 
 
 
+class Admin_UserGroupControllerEditModeratorPostDataTest extends Admin_UserGroupControllerTestCase {
+  protected $_group;
+  public function setUp() {
+    parent::setUp();
+    $this->postDispatch('admin/usergroup/edit/id/6',
+                        ['search_role_level' => '2',
+                         'rights_permissions' => ['right-' . Class_UserGroup::RIGHT_SUIVRE_ACTIVITY,
+                                                  'right-' . Class_UserGroup::RIGHT_DIRIGER_ACTIVITY]]);
+    $this->_group = Class_UserGroup::find(6);
+  }
+
+  /** @test */
+  public function moderatorGroupShouldContainsFilters() {
+    $this->assertEquals(2 , $this->_group->getFiltersAsArray()['search_role_level']);
+  }
+}
+
+
+
+
 class Admin_UserGroupControllerEditStagiairesPostDataTest extends Admin_UserGroupControllerTestCase {
   protected $_group;
   public function setUp() {
@@ -1324,7 +1354,11 @@ class Admin_UserGroupControllerCatEditCategorieAssociationPostTest extends Admin
 
 
 
-class Admin_UserGroupControllerEditMembersWithPaginationTest extends Admin_AbstractControllerTestCase {
+class Admin_UserGroupControllerEditMembersWithPaginationTest
+  extends Admin_AbstractControllerTestCase {
+
+  protected $_storm_default_to_volatile = true;
+
   public function setup() {
     parent::setup();
     $user_group = $this->fixture('Class_UserGroup',
@@ -1333,24 +1367,33 @@ class Admin_UserGroupControllerEditMembersWithPaginationTest extends Admin_Abstr
                                   'rights' => [Class_UserGroup::RIGHT_SUIVRE_ACTIVITY]]);
 
     $members = [];
-    for ($i=1; $i<30; $i++) {
-      $user = $this->fixture('Class_Users',
-                             ['id' => $i,
-                              'nom' => $i,
-                              'login' => 'tot'.$i,
-                              'password' => '123',
-                              'user_groups' => [$user_group]]);
-
+    foreach (range(1, 29) as $id) {
+      $user = $this->_buildUser($id);
       $members[] = $this->fixture('Class_UserGroupMembership',
-                                  ['id' => $i, 'user' => $user]);
-
+                                  ['id' => $id, 'user' => $user]);
     }
+
     $user_group->setUsers($members);
     $user_group->save();
 
+    // add some users not in group
+    foreach(range(30, 33) as $id)
+      $this->_buildUser($id);
+
     $this->dispatch('admin/usergroup/editmembers/id/1',true);
   }
 
+
+  protected function _buildUser($id, $groups=[]) {
+    return $this->fixture('Class_Users',
+                          ['id' => $id,
+                           'nom' => $id,
+                           'login' => 'tot' . $id,
+                           'password' => '123',
+                           'user_groups' => $groups]);
+  }
+
+
   /** @test */
   public function paginationToolsShouldBeDisplay() {
     $this->assertXPath('//div[@class="paginationControl"]', $this->_response->getBody());
@@ -1359,38 +1402,51 @@ class Admin_UserGroupControllerEditMembersWithPaginationTest extends Admin_Abstr
 
   /** @test */
   public function nb29UsersShouldBeDisplay() {
-    $this->assertXPathContentContains('//div','29 utilisateurs', $this->_response->getBody());
+    $this->assertXPathContentContains('//div', '29 utilisateurs', $this->_response->getBody());
   }
-
 }
 
 
 
-class Admin_UserGroupControllerEditMembersWithPaginationAsAutomaticUserGroupTest extends Admin_AbstractControllerTestCase {
+
+class Admin_UserGroupControllerEditMembersWithPaginationAsAutomaticUserGroupTest
+  extends Admin_AbstractControllerTestCase {
+
+  protected $_storm_default_to_volatile = true;
+
   public function setup() {
     parent::setup();
-    $user_group = $this->fixture('Class_UserGroup',
-                                 ['id' => 1,
-                                  'libelle' => "Group",
-                                  'group_type' => Class_UserGroup::TYPE_DYNAMIC,
-                                  'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB]);
-
-    $members=[];
-    for ($i=1; $i<30; $i++) {
-      $user = $this->fixture('Class_Users',
-                             ['id' => $i,
-                              'id_sigb'=> $i,
-                              'idabon'=> $i,
-                              'nom' => $i,
-                              'login' => 'tot'.$i,
-                              'password' => '113',
-                              'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
-                              'id_site' => 1]);
-    }
+
+    foreach(range(1, 29) as $id)
+      $this->_makeUser($id, ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB);
+
+    // add some more users not in group
+    foreach(range(30, 33) as $id)
+      $this->_makeUser($id, ZendAfi_Acl_AdminControllerRoles::INVITE);
+
+    $this->fixture('Class_UserGroup',
+                   ['id' => 1,
+                    'libelle' => "Group",
+                    'group_type' => Class_UserGroup::TYPE_DYNAMIC,
+                    'filters' => json_encode(['search_role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB])]);
 
     $this->dispatch('admin/usergroup/editmembers/id/1',true);
   }
 
+
+  protected function _makeUser($id, $role) {
+      $this->fixture('Class_Users',
+                     ['id' => $id,
+                      'id_sigb'=> $id,
+                      'idabon'=> $id,
+                      'nom' => $id,
+                      'login' => 'tot'.$id,
+                      'password' => '113',
+                      'role_level' => $role,
+                      'id_site' => 1]);
+  }
+
+
   /** @test */
   public function paginationToolsShouldBeDisplay() {
     $this->assertXPath('//div[@class="paginationControl"]', $this->_response->getBody());
diff --git a/tests/application/modules/admin/controllers/UsersControllerTest.php b/tests/application/modules/admin/controllers/UsersControllerTest.php
index 62f095bc27a25c36433077c6c3bdd13e615bada7..5707b4fc1ff62e4ec6f3a8c8064b8c6aec0adc79 100644
--- a/tests/application/modules/admin/controllers/UsersControllerTest.php
+++ b/tests/application/modules/admin/controllers/UsersControllerTest.php
@@ -96,6 +96,9 @@ abstract class UsersControllerWithMarcusTestCase extends AbstractControllerTestC
 class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase {
   public function setUp() {
     parent::setUp();
+    $time_source = new TimeSourceForTest('2012-02-01 14:00:00');
+    Class_User_SearchCriteria_Age::setTimeSource($time_source);
+
 
     Zend_Registry::set('sql', $this->mock()
                        ->whenCalled('fetchAll')
@@ -155,7 +158,7 @@ class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase {
          ->answers(55)
          ->beStrict();
 
-    $this->dispatch('/admin/users?search_id_site=all&search_role_level=2&search_valid_subscription=1&search_review=1&search_search_for=\"\'fra"n\'cis"', true);
+    $this->dispatch('/admin/users?search_id_site=all&search_role_level=2&search_age_debut=10&search_age_fin=99&search_valid_subscription=1&search_review=1&search_search_for=\"\'fra"n\'cis"', true);
   }
 
 
@@ -256,7 +259,7 @@ class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase {
   /** @test */
   public function massDeleteButtonWithCurrentQueryParamsShouldBePresent() {
     $this->assertXPathContentContains('//button[contains(@onclick, "admin/users/mass-delete?search_id_site=all&search_role_level=2&search_valid_subscription=1&search_statut=all&search_review=1")]',
-                                      'Supprimer ces utilisateurs');
+                                      'Supprimer ces utilisateurs', $this->_response->getBody());
   }
 }
 
@@ -780,20 +783,22 @@ class UsersControllerReferentIndexTest extends UsersControllerWithMarcusTestCase
 
     $this->fixture('Class_Users', ['id' => 345,
                                    'login' => 'roger',
+                                   'date_maj' => '',
                                    'password' => 'roger']);
     $this->fixture('Class_Users', ['id' => 346,
                                    'login' => 'norbert',
+                                   'date_maj' => '',
                                    'password' => 'norbert']);
 
     $user = $this->fixture('Class_Users',
                            ['id' => 2,
                             'login' => 'referent',
                             'password' => 'referent',
+                            'date_maj' => '',
                             'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL]);
 
     $this->addUserToRightsReferent($user);
 
-    ZendAfi_Auth::getInstance()->logUser($user);
     $this->dispatch('/admin/users/index/order/prenom+desc', true);
   }
 
@@ -2018,7 +2023,7 @@ class UsersControllerMassDeleteTest extends UsersControllerMassDeleteTestCase {
 
   /** @test */
   public function pageShouldContainsSubscriptionEndDateDescription() {
-    $this->assertXPathContentContains('//li', 'Date de fin d\'abonnement : jusqu\'au 28/05/2018');
+    $this->assertXPathContentContains('//li', 'Abonnement échu : jusqu\'au 28/05/2018');
   }
 
 
diff --git a/tests/application/modules/opac/controllers/AbonneControllerSuggestionAchatTest.php b/tests/application/modules/opac/controllers/AbonneControllerSuggestionAchatTest.php
index 34b756d2f28151c00a7d57fa3620a369031d0feb..1f395afc28c10a12c5dd44717e2f48aa78bc12f8 100644
--- a/tests/application/modules/opac/controllers/AbonneControllerSuggestionAchatTest.php
+++ b/tests/application/modules/opac/controllers/AbonneControllerSuggestionAchatTest.php
@@ -186,6 +186,7 @@ class AbonneControllerSuggestionAchatAddFormMultipleBibsAndKohaNotRestfulTest ex
                                            'login' => 'test',
                                            'password' => 'test',
                                            'id_site' => 12,
+                                           'date_maj' => '',
                                            'int_bib' => $sigb_plage,
                                            ]);
 
diff --git a/tests/application/modules/opac/controllers/CmsControllerTest.php b/tests/application/modules/opac/controllers/CmsControllerTest.php
index fce3a71035cc8fca3c15263c42cc8970222a085e..561338d021b335ff02322ad710e4172153f21a13 100644
--- a/tests/application/modules/opac/controllers/CmsControllerTest.php
+++ b/tests/application/modules/opac/controllers/CmsControllerTest.php
@@ -804,7 +804,8 @@ abstract class CmsControllerWithFeteDeLaFriteTestCase extends AbstractController
                                                 'auteur' => $this->fixture('Class_Users' , ['id'=> 98,
                                                                                             'pseudo' => 'Mimi',
                                                                                             'password' => 'toto',
-                                                                                            'login' => 'mimi']),
+                                                                                            'login' => 'mimi',
+                                                                                            'date_maj' => '']),
                                                 'date_avis' => '2012-02-05',
                                                 'note'=>4,
                                                 'entete' => "Hmmm",
@@ -819,6 +820,7 @@ abstract class CmsControllerWithFeteDeLaFriteTestCase extends AbstractController
                                      'auteur' => $this->fixture('Class_Users' ,
                                                                 ['id'=> 123,
                                                                  'pseudo' => 'Florence',
+                                                                 'date_maj' => '',
                                                                  'password' => 'toto',
                                                                  'login' => 'florence']),
                                      'date_avis' => '2012-02-05',
diff --git a/tests/application/modules/opac/controllers/FormulaireContactTest.php b/tests/application/modules/opac/controllers/FormulaireContactTest.php
index 67b95e15509be2629370f9db2dd0db1a02b9f895..d5ad4a5fd82121a468b2e75c7dd1e66104238cf7 100644
--- a/tests/application/modules/opac/controllers/FormulaireContactTest.php
+++ b/tests/application/modules/opac/controllers/FormulaireContactTest.php
@@ -467,6 +467,7 @@ class FormulaireContactActionWithBibSelectorSettingUncheckedTest
                             'prenom' => 'Joe',
                             'mail' => 'joe-joeram@afi-sa.fr',
                             'ville' => 'Annecy',
+                            'date_maj' => '',
                             'code_postal' => '74000',
                             'adresse' => 'n°1']);
 
diff --git a/tests/application/modules/opac/controllers/IndexControllerTest.php b/tests/application/modules/opac/controllers/IndexControllerTest.php
index 83bbd165f548da1c73de7117218a535495a3a3b1..7177e4a0a45c49316a4f4a984c12818e17871d3d 100644
--- a/tests/application/modules/opac/controllers/IndexControllerTest.php
+++ b/tests/application/modules/opac/controllers/IndexControllerTest.php
@@ -236,6 +236,7 @@ class IndexControllerWithLoggedUserTest extends AbstractControllerTestCase {
     ZendAfi_Auth::getInstance()->logUser($this->fixture('Class_Users',
                                                         ['id' => 1,
                                                          'login' => 'tom',
+                                                         'date_maj' => '',
                                                          'password' => 'ok']));
     $this->dispatch('index/index', true);
   }
@@ -736,7 +737,8 @@ class IndexControllerHeartBeatTest extends Admin_AbstractControllerTestCase {
                                                          'password' => 'year',
                                                          'id_site' => 1,
                                                          'idabon' => 789465,
-                                                         'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB]));
+                                                         'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                                                         'date_maj' => '']));
     $this->dispatch('/opac/index/index', true);
     $this->assertNotXPathContentContains('//script', '/admin/index/heartbeat');
   }
diff --git a/tests/application/modules/opac/controllers/PanierControllerTest.php b/tests/application/modules/opac/controllers/PanierControllerTest.php
index 7fcd93c9ff76fdfdf046371886cc1918a6c9c534..4ba46a1ee0d8c52e5c46ab53e56e5188372f144f 100644
--- a/tests/application/modules/opac/controllers/PanierControllerTest.php
+++ b/tests/application/modules/opac/controllers/PanierControllerTest.php
@@ -1182,7 +1182,8 @@ class PanierControllerEditActionAsAbonneTest extends AbstractControllerTestCase
     $roger = Class_Users::newInstanceWithId(23, ['pseudo' => 'RogerL',
                                                  'nom' => 'plou',
                                                  'login' => 'man',
-                                                 'password' => '123']);
+                                                 'password' => '123',
+                                                 'date_maj' => '']);
     $roger->beAbonneSIGB();
     $roger->save();
 
diff --git a/tests/application/modules/opac/controllers/TogetherJSTest.php b/tests/application/modules/opac/controllers/TogetherJSTest.php
index 2cd2097a29461aabd2147f9cd4e4af6244854830..9f51fcf0ac13d784efe04b231bb675fa04390290 100644
--- a/tests/application/modules/opac/controllers/TogetherJSTest.php
+++ b/tests/application/modules/opac/controllers/TogetherJSTest.php
@@ -25,7 +25,8 @@ abstract class TogetherJSTestCase extends AbstractControllerTestCase {
       ->logUser( $this->fixture('Class_Users',
                                 ['id' => 1,
                                  'login' => 'admin',
-                                 'password' => 'pass'])
+                                 'password' => 'pass',
+                                 'date_maj' => ''])
                  ->beAdminPortail());
   }
 }
diff --git a/tests/application/modules/push/controllers/MultimediaControllerTest.php b/tests/application/modules/push/controllers/MultimediaControllerTest.php
index 36384892c1b1bb0aebff0f89a89ef85a7ea1fa1f..142b5abaa6357b48a93bd041a4bd0ce11f9bc2a7 100644
--- a/tests/application/modules/push/controllers/MultimediaControllerTest.php
+++ b/tests/application/modules/push/controllers/MultimediaControllerTest.php
@@ -804,7 +804,8 @@ class AbonneMultimediaControllerMultimediaUsersFixtures {
       ->setNaissance('1978-02-17')
       ->setDateFin('2030-01-01')
       ->setDateDebut('2022-01-01')
-      ->setEmail('loas@mail.fr');
+      ->setEmail('loas@mail.fr')
+      ->setDateMaj('');;
   }
 
 
@@ -820,7 +821,8 @@ class AbonneMultimediaControllerMultimediaUsersFixtures {
       ->setNaissance('1980-02-17')
       ->setDateFin('2030-01-01')
       ->setDateDebut('2029-01-01')
-      ->setEmail('loas@mail.fr');
+      ->setEmail('loas@mail.fr')
+      ->setDateMaj('');
   }
 
   public static function getInviteAfim() {
@@ -833,6 +835,7 @@ class AbonneMultimediaControllerMultimediaUsersFixtures {
       ->setRoleLevel(0)
       ->setIdabon('invite')
       ->setNaissance('1983-02-17')
-      ->setDateFin('2030-01-01');
+      ->setDateFin('2030-01-01')
+      ->setDateMaj('');
   }
 }
\ No newline at end of file
diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php
index 32711c9daa76351258cf79d8343d181de9409455..b53c4b98d101bd67b7d2dade1be1835bdf39c855 100644
--- a/tests/db/UpgradeDBTest.php
+++ b/tests/db/UpgradeDBTest.php
@@ -3008,3 +3008,42 @@ class UpgradeDB_382_Test extends UpgradeDBTestCase {
     $this->assertFieldType('external_agenda', 'delete_orphan_events', 'tinyint(1)');
   }
 }
+
+
+
+
+class UpgradeDB_383_Test extends UpgradeDBTestCase {
+  protected static $_dynamic_group_id;
+
+  public function prepare() {
+    $this
+      ->silentQuery('ALTER TABLE user_groups DROP COLUMN filters')
+      ->silentQuery('insert into user_groups (group_type, libelle, role_level, id_bib)
+                       values(1, "filters test", 2, 7)');
+
+    static::$_dynamic_group_id = $this->query('select id from user_groups order by id desc limit 1')
+                                      ->fetch()['id'];
+  }
+
+
+  public function tearDown() {
+    $this->silentQuery('delete from user_groups where id=' . static::$_dynamic_group_id);
+    parent::tearDown();
+  }
+
+
+  /** @test */
+  public function tableUserGroupsShouldHaveColumnFiltersText() {
+    $this->assertFieldType('user_groups', 'filters', 'longtext');
+  }
+
+
+  /** @test */
+  public function dynamicGroupFiltersShouldHaveBeenMigrated() {
+    $filters = $this->query('select filters from user_groups where id=' . static::$_dynamic_group_id)
+                    ->fetch()['filters'];
+
+    $this->assertEquals('{"search_role_level":"2", "search_id_site":"7"}',
+                        $filters);
+  }
+}
diff --git a/tests/fixtures/NewsletterFixtures.php b/tests/fixtures/NewsletterFixtures.php
index 6a3d74c43debb46bbcf03e3cee80ba8b81fef030..2e4aabc8e17aaf6ce3cc481b4db7f319b69b14ab 100644
--- a/tests/fixtures/NewsletterFixtures.php
+++ b/tests/fixtures/NewsletterFixtures.php
@@ -65,8 +65,8 @@ class NewsletterFixtures {
                                         ['id' => 15,
                                          'libelle' => 'My Other Group',
                                          'group_type' => Class_UserGroup::TYPE_DYNAMIC,
-                                         'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
-                                         'id_bib' => 1]);
+                                         'filters' => json_encode(['search_role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                                                                   'search_id_site' => 1])]);
 
 
     $controller->fixture('Class_Newsletter',
diff --git a/tests/library/Class/AvisNoticeTest.php b/tests/library/Class/AvisNoticeTest.php
index 88885ed87c752ec1100de1c96ceea45f8fb9f1c9..9fd444e4be74e284c6fa07fc5342510b5debe058 100644
--- a/tests/library/Class/AvisNoticeTest.php
+++ b/tests/library/Class/AvisNoticeTest.php
@@ -357,7 +357,8 @@ class NoticeTestHasManyAvisTest extends ModelTestCase {
     $this->millenium = $this->fixture('Class_Notice', ['id' => 34,
                                                        'clef_oeuvre' => 'MILLENIUM--LARSSON']);
 
-    $this->steve = Class_Users::newInstanceWithId(5, ['prenom' => 'Steve']);
+    $this->steve = Class_Users::newInstanceWithId(5, ['prenom' => 'Steve',
+                                                      'date_maj' => '']);
     $this->avis_millenium_steve = $this->fixture('Class_AvisNotice', ['id' => 12,
                                                                       'user' => $this->steve,
                                                                       'entete' => 'ça fait peur',
@@ -365,7 +366,7 @@ class NoticeTestHasManyAvisTest extends ModelTestCase {
                                                                       'clef_oeuvre' => 'MILLENIUM--LARSSON',
                                                                       'note' => 2]);
 
-    $this->bryan = $this->fixture('Class_Users' , ['id' =>6, 'login' => 'bryan', 'password' => 'toto', 'prenom' => 'Bryan']);
+    $this->bryan = $this->fixture('Class_Users' , ['id' =>6, 'login' => 'bryan', 'password' => 'toto', 'prenom' => 'Bryan', 'date_maj' => '']);
     $this->avis_millenium_lost_bryan = $this->fixture('Class_AvisNotice', ['id' =>15,
                                                                            'user' => $this->bryan,
                                                                            'entete' => 'perdu',
diff --git a/tests/library/Class/DynamicUserGroupTest.php b/tests/library/Class/DynamicUserGroupTest.php
index 97a9b32bc0bbff231ef1c1b521f8e8706f2c2efb..34968292163fc2851f78364b2bf9e299cee75414 100644
--- a/tests/library/Class/DynamicUserGroupTest.php
+++ b/tests/library/Class/DynamicUserGroupTest.php
@@ -23,7 +23,6 @@
 abstract class DynamicUserGroupTestCase extends ModelTestCase {
   public function setUp() {
     parent::setUp();
-    Storm_Model_Loader::defaultToVolatile();
 
     $this->_annecy = $this->fixture('Class_Bib',
                                     ['id' => 5, 'libelle' => 'Annecy']);
@@ -43,12 +42,6 @@ abstract class DynamicUserGroupTestCase extends ModelTestCase {
                                      'login' => 'X',
                                      'password' => 'X']);
   }
-
-
-  public function tearDown() {
-    Storm_Model_Loader::defaultToDb();
-    parent::tearDown();
-  }
 }
 
 
@@ -73,8 +66,8 @@ class DynamicUserGroupAbonneSIGBTest extends DynamicUserGroupTestCase {
 
     $this->_abonnes = $this->fixture('Class_UserGroup',
                                      ['id' => 3,
-                                      'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB]);
-    $this->_abonnes->beDynamic()->save();
+                                      'group_type' => Class_UserGroup::TYPE_DYNAMIC,
+                                      'filters' => json_encode(['search_role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB])]);
   }
 
 
@@ -86,14 +79,15 @@ class DynamicUserGroupAbonneSIGBTest extends DynamicUserGroupTestCase {
 
   /** @test */
   public function usersShouldContainsBaptisteAndXavier() {
-    $this->assertEquals([$this->_baptiste, $this->_xavier],
-                        $this->_abonnes->getUsers());
+    $this->assertContains($this->_baptiste, $this->_abonnes->getUsers());
+    $this->assertContains($this->_xavier, $this->_abonnes->getUsers());
   }
 
 
   /** @test */
   public function baptisteGroupsShouldBeOnlyAbonneSIGB() {
-    $this->assertEquals([$this->_abonnes], $this->_baptiste->getUserGroups());
+    $this->assertEquals([$this->_abonnes],
+                        $this->_baptiste->getUserGroups());
   }
 
 
@@ -119,8 +113,9 @@ class DynamicUserGroupModoBibTest extends DynamicUserGroupTestCase {
       ->fixture('Class_UserGroup',
                 ['id' => 3,
                  'libelle' => 'Rédacteurs marseillais',
-                 'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
-                 'library' => $this->_marseille]);
+                 'filters' => json_encode([
+                                           'search_role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
+                                           'search_id_site' => $this->_marseille->getId()])]);
     $this->_marseillais->beDynamic()->assertSave();
 
     $this->_xavier->setBib($this->_marseille)
@@ -131,36 +126,162 @@ class DynamicUserGroupModoBibTest extends DynamicUserGroupTestCase {
       ->fixture('Class_UserGroup',
                 ['id' => 12,
                  'libelle' => 'Rédacteurs annéciens',
-                 'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
-                 'library' => $this->_annecy]);
+                 'filters' => json_encode([
+                                           'search_role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
+                                           'search_id_site' => $this->_annecy->getId()])]);
+
     $this->_anneciens->beDynamic()->assertSave();
 
     $this->_baptiste->setBib($this->_annecy)
                     ->beModoBib()
                     ->assertSave();
+
+    Class_User_ILSSubscription::setTimeSource(new TimeSourceForTest('2020-01-15 15:00'));
+    $this->_gontran = $this->fixture('Class_Users',
+                                     ['id' => 22,
+                                      'login' => 'gontran',
+                                      'password' => 'password',
+                                      'id_site' => 1,
+                                      'idabon' => '111',
+                                      'statut' => 1,
+                                      'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                                      'date_fin' => '2050-01-01'
+                                     ]);
+
+    $this->_shella = $this->fixture('Class_Users',
+                                     ['id' => 28,
+                                      'login' => 'shella',
+                                      'password' => 'password',
+                                      'id_site' => 1,
+                                      'naissance' => '2015-01-01',
+                                      'idabon' => '11102',
+                                      'statut' => 1,
+                                      'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                                      'date_fin' => '2020-01-20'
+                                     ]);
+
+    $this->_subscribers = $this
+      ->fixture('Class_UserGroup',
+                ['id' => 13,
+                 'libelle' => 'Abonnés',
+                 'group_type' => Class_UserGroup::TYPE_DYNAMIC,
+                 'filters' => json_encode(['search_valid_subscription' => 1
+                                           ])]);
+
+    $this->_late_subscribers = $this
+      ->fixture('Class_UserGroup',
+                ['id' => 14,
+                 'libelle' => 'Abonnés tardifs',
+                 'group_type' => Class_UserGroup::TYPE_DYNAMIC,
+                 'filters' => json_encode([
+                                           'search_date_fin_start' => '01/01/2020',
+                                           'search_date_fin_end' => '01/01/2051'
+                                           ])]);
+
+    $this->_non_exported = $this
+      ->fixture('Class_UserGroup',
+                ['id' => 15,
+                 'libelle' => 'Abonnés tardifs',
+                 'group_type' => Class_UserGroup::TYPE_DYNAMIC,
+                 'filters' => json_encode([
+                                           'search_statut' => 1
+                                           ])]);
+    $this->fixture('Class_AvisNotice',
+                   ['id' => 34,
+                    'id_user' => $this->_xavier->getId(),
+                    'entete' => 'a mon avis']);
+
+    $this->_reviewers = $this
+      ->fixture('Class_UserGroup',
+                ['id' => 16,
+                 'libelle' => 'Critiques',
+                 'group_type' => Class_UserGroup::TYPE_DYNAMIC,
+                 'filters' => json_encode([
+                                           'search_review'=> 'yes'
+                                           ])]);
+
+    $this->_basketers = $this
+      ->fixture('Class_UserGroup',
+                ['id' => 17,
+                 'libelle' => 'Createurs de paniers',
+                 'group_type' => Class_UserGroup::TYPE_DYNAMIC,
+                 'filters' => json_encode([
+                                           'search_basket'=> 'yes'
+                                           ])]);
+
+    $this->fixture('Class_PanierNotice',
+                   ['id' => 12,
+                    'id_user' => $this->_baptiste->getId()]
+                   );
+
+    $this->_searchers = $this
+      ->fixture('Class_UserGroup',
+                ['id' => 18,
+                 'libelle' => 'Chercheurs',
+                 'group_type' => Class_UserGroup::TYPE_DYNAMIC,
+                 'filters' => json_encode([
+                                           'search_search_for'=> 'gontran'
+                                           ])]);
+
+    $this->_subscription_ended = $this
+      ->fixture('Class_UserGroup',
+                ['id' => 19,
+                 'libelle' => 'En fin d\'abonnement',
+                 'group_type' => Class_UserGroup::TYPE_DYNAMIC,
+                 'filters' => json_encode([
+                                           'search_role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                                           'search_end_subscription_days'=> 10
+                                           ])]);
   }
 
 
-  /** @test */
-  public function marseillaisShouldHaveOneUser() {
-    $this->assertEquals([$this->_xavier], $this->_marseillais->getUsers());
+  public function userGroupMap() {
+    return [
+            ['_xavier', '_marseillais'],
+            ['_baptiste', '_anneciens'],
+            ['_gontran', '_subscribers'],
+            ['_gontran', '_late_subscribers'],
+            ['_gontran', '_non_exported'],
+            ['_xavier', '_reviewers'],
+            ['_baptiste', '_basketers'],
+            ['_gontran', '_searchers'],
+            ['_shella', '_subscription_ended'],
+    ];
   }
 
 
-  /** @test */
-  public function xavierShouldHaveMarseillaisGroup() {
-    $this->assertContains($this->_marseillais, $this->_xavier->getUserGroups());
+  /**
+   * @test
+   * @dataProvider userGroupMap
+   */
+  public function groupShouldHaveUser($user, $group) {
+    $this->assertContains($this->$user, $this->{$group}->getUsers());
   }
 
 
-  /** @test */
-  public function anneciensShouldHaveOneUser() {
-    $this->assertEquals([$this->_baptiste], $this->_anneciens->getUsers());
+  /**
+   * @test
+   * @dataProvider userGroupMap
+   */
+  public function userShouldHaveGroup($user, $group) {
+    $this->assertContains($this->$group, $this->{$user}->getUserGroups());
   }
 
 
-  /** @test */
-  public function baptisteShouldHaveAnneciensGroup() {
-    $this->assertContains($this->_anneciens, $this->_baptiste->getUserGroups());
+  public function userGroupNotMatchMap() {
+    return [
+            ['_baptiste', '_marseillais'],
+            ['_xavier', '_anneciens'],
+            ['_gontran', '_subscription_ended'],
+    ];
+  }
+
+
+  /**
+   * @test
+   * @dataProvider userGroupNotMatchMap
+   */
+  public function userShouldNotHaveGroup($user, $group) {
+    $this->assertNotContains($this->$group, $this->{$user}->getUserGroups());
   }
 }
\ No newline at end of file
diff --git a/tests/library/Class/PanierNoticeTest.php b/tests/library/Class/PanierNoticeTest.php
index b762462b936177c141170b1fd4e2d37cd454b0ab..01e273e103a90fc28c4437910885016a0311ab9f 100644
--- a/tests/library/Class/PanierNoticeTest.php
+++ b/tests/library/Class/PanierNoticeTest.php
@@ -347,12 +347,15 @@ class PanierNoticeWithWrongUserIdTest extends AbstractControllerTestCase {
     $this->fixture('Class_Users', ['id'=>78,
                                    'idabon' => 888,
                                    'login' => 'tom',
-                                   'password' => 'toto']);
+                                   'password' => 'toto',
+                                   'date_maj' => ''
+                                   ]);
 
     $this->fixture('Class_Users', ['id'=>11,
                                    'idabon' => 111,
                                    'login' => 'jerry',
-                                   'password' => 'toto']);
+                                   'password' => 'toto',
+                                   'date_maj' => '']);
 
     $this->fixture('Class_PanierNotice',
                    ['id' =>4,
diff --git a/tests/library/Class/Systeme/PergameServiceTest.php b/tests/library/Class/Systeme/PergameServiceTest.php
index fcb174660a7091ce0279ef54bb71d76b5da2fddf..3c8b5b2c8df197fe0020c7af8e107318f4e943b1 100644
--- a/tests/library/Class/Systeme/PergameServiceTest.php
+++ b/tests/library/Class/Systeme/PergameServiceTest.php
@@ -155,7 +155,7 @@ class PergameServiceReserverExemplaireValidationsTest extends ModelTestCase {
       [null, 'Vous devez être connecté'],
       [Class_Users::newInstance(), 'Vous devez être connecté'],
       [$this->fixture('Class_Users',
-        ['id' => 23, 'password' => 'pass', 'login' => 'login']), 'en tant qu\'abonné']
+                      ['id' => 23, 'password' => 'pass', 'login' => 'login', 'date_maj' => '']), 'en tant qu\'abonné']
     ];
   }
 
diff --git a/tests/library/Trait/UserGroupFixtures.php b/tests/library/Trait/UserGroupFixtures.php
index 0d86dcb06056ec77c5efccddfc837ef0723e45d6..5f6b32caa49de6067fe29a560f148c4a78075e1b 100644
--- a/tests/library/Trait/UserGroupFixtures.php
+++ b/tests/library/Trait/UserGroupFixtures.php
@@ -24,44 +24,23 @@ trait Trait_UserGroupFixtures {
   protected $_referent_membership;
 
   public function addUserToRightsReferent($user) {
-    $this->_referent = Class_UserGroup::newInstanceWithId(28)
-      ->setLibelle('Referent')
-      ->setRights([
-                    Class_UserGroup::RIGHT_USER_DOMAINES_SUPPRESSION_LIMIT,
-                    Class_UserGroup::RIGHT_USER_FILE_ACCESS,
-                    Class_UserGroup::RIGHT_USER_SITOTHEQUE,
-                    Class_UserGroup::RIGHT_USER_MODO,
-                    Class_UserGroup::RIGHT_USER_INSCRIPTIONS,
-                    Class_UserGroup::RIGHT_USER_BIB_NUM,
-                    Class_UserGroup::RIGHT_USER_OPDS_READ,
-                    Class_UserGroup::RIGHT_USER_NOTICES_LIEES,
-                    Class_UserGroup::RIGHT_USER_SIGB_USER_READ
-                    ]);
-
-  Storm_Test_ObjectWrapper::onLoaderOfModel('Class_UserGroup')
-    ->whenCalled('findAll')
-    ->answers([
-                $this->_referent
-                ])
-
-    ->whenCalled('findAllBy')
-    ->answers([
-                $this->_referent
-                ]);
-
-    Storm_Test_ObjectWrapper::onLoaderOfModel('Class_UserGroupMembership')
-      ->whenCalled('findAllBy')
-      ->with(array('role' => 'user_group',
-                   'model' => $this->_referent))
-      ->answers([
-                  $this->_referent_membership = Class_UserGroupMembership::getLoader()
-                  ->newInstanceWithId(223)
-                  ->setUserId($user->getId())
-                  ->setUserGroupId(2222)]);
-
-    Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Users')
-      ->whenCalled('getIdentity')
-      ->answers($user);
-
+    $this->_referent = $this->fixture('Class_UserGroup',
+                                      ['id' => 28,
+                                       'libelle' => 'Referent',
+                                       'rights' => [
+                                                    Class_UserGroup::RIGHT_USER_DOMAINES_SUPPRESSION_LIMIT,
+                                                    Class_UserGroup::RIGHT_USER_FILE_ACCESS,
+                                                    Class_UserGroup::RIGHT_USER_SITOTHEQUE,
+                                                    Class_UserGroup::RIGHT_USER_MODO,
+                                                    Class_UserGroup::RIGHT_USER_INSCRIPTIONS,
+                                                    Class_UserGroup::RIGHT_USER_BIB_NUM,
+                                                    Class_UserGroup::RIGHT_USER_OPDS_READ,
+                                                    Class_UserGroup::RIGHT_USER_NOTICES_LIEES,
+                                                    Class_UserGroup::RIGHT_USER_SIGB_USER_READ
+                                       ]
+                                       ]
+    );
+    $user->addUserGroup($this->_referent);
+    ZendAfi_Auth::getInstance()->logUser($user);
   }
 }
\ No newline at end of file
diff --git a/tests/library/ZendAfi/View/Helper/Abonne/ReservationsTableTest.php b/tests/library/ZendAfi/View/Helper/Abonne/ReservationsTableTest.php
index 32a05c9eed8fccfab85765b7fa2f8f8bbc82c3c2..3c3a202028a53493142bc3ffe49323763f058f85 100644
--- a/tests/library/ZendAfi/View/Helper/Abonne/ReservationsTableTest.php
+++ b/tests/library/ZendAfi/View/Helper/Abonne/ReservationsTableTest.php
@@ -77,7 +77,8 @@ class ReservationsTableTest extends ViewHelperTestCase {
                             'idabon' => '888',
                             'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
                             'id_site' => 654,
-                            'id_int_bib' => 654])
+                            'id_int_bib' => 654,
+                            'date_maj' => ''])
                  ->setFicheSigb(['fiche' => $emprunteur]);
     ZendAfi_Auth::getInstance()->logUser($user);
 
diff --git a/tests/library/ZendAfi/View/Helper/Accueil/MenuVerticalTest.php b/tests/library/ZendAfi/View/Helper/Accueil/MenuVerticalTest.php
index 26fccd120848b3c7563c30f2acf0b41dd7590dfd..98d061b68ed36f2733011535f1865b7b9325950b 100644
--- a/tests/library/ZendAfi/View/Helper/Accueil/MenuVerticalTest.php
+++ b/tests/library/ZendAfi/View/Helper/Accueil/MenuVerticalTest.php
@@ -477,7 +477,8 @@ class MenuVerticalWithBoiteNewsTest extends MenuVerticalTestCase {
                                                         ['id' => 3,
                                                          'login' => 'admin',
                                                          'password' => 'admin',
-                                                         'role_level' => ZendAfi_Acl_AdminControllerRoles::ADMIN_PORTAIL
+                                                         'role_level' => ZendAfi_Acl_AdminControllerRoles::ADMIN_PORTAIL,
+                                                         'date_maj' => ''
                                                         ]));
 
     Class_Profil::getCurrentProfil()->setCfgMenus(
diff --git a/tests/library/ZendAfi/View/Helper/Admin/FonctionsAdminTest.php b/tests/library/ZendAfi/View/Helper/Admin/FonctionsAdminTest.php
index 57040b6dc8e89e91766602ef024c5e0d549fed72..6cd3dd6e3e600225fc22927283451e108106a3d0 100644
--- a/tests/library/ZendAfi/View/Helper/Admin/FonctionsAdminTest.php
+++ b/tests/library/ZendAfi/View/Helper/Admin/FonctionsAdminTest.php
@@ -43,7 +43,8 @@ class FonctionsAdminHelperTest extends ViewHelperTestCase {
                                ['id' => 89,
                                 'login' => 'test89',
                                 'password' => 'password',
-                                'role_level' => ZendAfi_Acl_AdminControllerRoles::SUPER_ADMIN]));
+                                'role_level' => ZendAfi_Acl_AdminControllerRoles::SUPER_ADMIN,
+                                'date_maj' => '']));
     $this->_content = $this->helper->fonctionsAdmin(0, false, null, [function() {return 'test';}]);
     $this->assertContains('test', $this->_content);
   }
@@ -57,7 +58,8 @@ class FonctionsAdminHelperTest extends ViewHelperTestCase {
                                 'login' => 'test89',
                                 'password' => 'password',
                                 'id_site' => 1,
-                                'role_level' => ZendAfi_Acl_AdminControllerRoles::ADMIN_BIB]));
+                                'role_level' => ZendAfi_Acl_AdminControllerRoles::ADMIN_BIB,
+                                'date_maj' => '']));
 
     $this->_content = $this->helper->fonctionsAdmin();
     $this->assertEquals('', $this->_content);
diff --git a/tests/library/ZendAfi/View/Helper/CkEditorTest.php b/tests/library/ZendAfi/View/Helper/CkEditorTest.php
index 63743b00aed6602b135bf0e6c040a77a0094c114..0bb0092ba6de00f221ef7bdd06e3c593a4a342e0 100644
--- a/tests/library/ZendAfi/View/Helper/CkEditorTest.php
+++ b/tests/library/ZendAfi/View/Helper/CkEditorTest.php
@@ -110,6 +110,7 @@ class CkEditorAdminViewHelperTest extends ViewHelperTestCase {
                                                       'mail' => 'admin@afi-sa.fr',
                                                       'password' => 'toto',
                                                       'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
+                                                      'date_maj' => '',
                                                       'user_groups' => [Class_UserGroup::find(22)]]);
 
     ZendAfi_Auth::getInstance()->logUser($this->_admin_bib);
@@ -151,6 +152,7 @@ class CkeditorWithShowFileBrowserTest extends ViewHelperTestCase {
                                                       'bib' => $annecy,
                                                       'role' => 'admin_bib',
                                                       'mail' => 'admin@afi-sa.fr',
+                                                      'date_maj' => '',
                                                       'password' => 'toto',
                                                       'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB,
                                                       'user_groups' => [Class_UserGroup::find(22)]]);
diff --git a/tests/library/ZendAfi/View/Helper/TreeViewTest.php b/tests/library/ZendAfi/View/Helper/TreeViewTest.php
index ec362e5179fac74a90affcfa63a35067ec457411..cf01511180dc4aa6ed6d234b0fb95242d56e374b 100644
--- a/tests/library/ZendAfi/View/Helper/TreeViewTest.php
+++ b/tests/library/ZendAfi/View/Helper/TreeViewTest.php
@@ -36,6 +36,7 @@ abstract class TreeViewTestCase extends ViewHelperTestCase {
                                ['id' => 56,
                                 'login' => 'admin',
                                 'password' => 'ief1',
+                                'date_maj' => '',
                                 'role_level' => ZendAfi_Acl_AdminControllerRoles::ADMIN_PORTAIL]));
 
     $view = new ZendAfi_Controller_Action_Helper_View();
diff --git a/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php b/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php
index 0a5cb41260f102ff88de9083c21ad83713301a37..6fa7a69a8432c56e4f6641e08b91ce65117d07ef 100644
--- a/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php
+++ b/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php
@@ -165,7 +165,8 @@ abstract class ViewHelperTestCase extends ModelTestCase {
 
     Class_Users::getLoader()
       ->newInstanceWithId(666)
-      ->setRoleLevel($role);
+      ->setRoleLevel($role)
+      ->setDateMaj('');
 
     Class_Bib::getLoader()
       ->newInstanceWithId(1)
diff --git a/tests/scenarios/bookmarks/LibrariesTest.php b/tests/scenarios/bookmarks/LibrariesTest.php
index 545d874fb9db67cdeef80091ed9bb4b7c981f586..5aee4d316565eced21aea51fabf4ce437fbf94c8 100644
--- a/tests/scenarios/bookmarks/LibrariesTest.php
+++ b/tests/scenarios/bookmarks/LibrariesTest.php
@@ -202,7 +202,8 @@ abstract class Bookmarks_LibrariesItemsTableWithAnnexTestCase extends AbstractCo
                             'password' => 'A nude monkey ... ?',
                             'id_site' => '654321',
                             'idabon' => '456789',
-                            'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB]);
+                            'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                            'date_maj' => '' ]);
 
     $user->setBookmarkedLibraries([654321, 789]);