diff --git a/VERSIONS_HOTLINE/30672 b/VERSIONS_HOTLINE/30672
new file mode 100644
index 0000000000000000000000000000000000000000..a8148e7e83fe525cc3cf5791ef7600a24dd7011b
--- /dev/null
+++ b/VERSIONS_HOTLINE/30672
@@ -0,0 +1 @@
+ - ticket #30672 : CVS : Possibilité de paramétrer un libellé de regroupement des abonnés
\ No newline at end of file
diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php
index 07d8641570a40cc7b3135a705dfae5bc29642933..1958c02f977eeb85e72131bc170db5bbe84f421d 100644
--- a/library/Class/AdminVar.php
+++ b/library/Class/AdminVar.php
@@ -199,6 +199,7 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
 
                    'CVS_BMKEY' => Class_AdminVar_Meta::newDefault($this->_('Paramétrage CVS'))->bePrivate(),
                    'CVS_BMID' => Class_AdminVar_Meta::newDefault($this->_('Paramétrage CVS'))->bePrivate(),
+                   'CVS_BMLABEL' => Class_AdminVar_Meta::newDefault($this->_('Libellé de regroupement des abonnés'))->bePrivate(),
                    'CVS_SOURCENAME' => Class_AdminVar_Meta::newDefault($this->_('Paramétrage CVS'))->bePrivate(),
                    'CVS_SOURCEID' => Class_AdminVar_Meta::newDefault($this->_('Paramétrage CVS'))->bePrivate(),
                    'CVS_SOURCEKEY' => Class_AdminVar_Meta::newDefault($this->_('Paramétrage CVS'))->bePrivate(),
diff --git a/library/Class/CVSLink.php b/library/Class/CVSLink.php
index 92672d1e43b50d1870daee84b95939aa23893c4b..70931de54ebb03c5477b0afa0c12960eacf64afb 100644
--- a/library/Class/CVSLink.php
+++ b/library/Class/CVSLink.php
@@ -16,7 +16,7 @@
  *
  * 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 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
 class Class_CVSLink extends Class_WebService_Abstract {
@@ -26,6 +26,7 @@ class Class_CVSLink extends Class_WebService_Abstract {
 
   protected $_user;
   protected $loginTest;
+
   public static function forUser($user) {
     return new self($user);
   }
@@ -35,9 +36,9 @@ class Class_CVSLink extends Class_WebService_Abstract {
     $this->_user = $user;
   }
 
+
   public static function staticLink() {
-    return Class_Url::assemble(['controller' => 'modules',
-                                'action' => 'cvs']);
+    return Class_Url::assemble(['controller' => 'modules', 'action' => 'cvs']);
   }
 
 
@@ -45,15 +46,15 @@ class Class_CVSLink extends Class_WebService_Abstract {
     return 'http://stream.cvs-mediatheques.com/api/partners.php';
   }
 
+
   public function setConfig() {
     $this->bmkey = Class_AdminVar::get('CVS_BMKEY');
     $this->bmid = Class_AdminVar::get('CVS_BMID');
-    $this->sourceName=Class_AdminVar::get('CVS_SOURCENAME');
-    $this->sourceId=Class_AdminVar::get('CVS_SOURCEID');
-    $this->sourceKey=Class_AdminVar::get('CVS_SOURCEKEY');
-    $this->sourcePassword=Class_AdminVar::get('CVS_SOURCEPASSWORD');
-    $this->loginTest=Class_AdminVar::get('CVS_LOGINTEST');
-    
+    $this->sourceName = Class_AdminVar::get('CVS_SOURCENAME');
+    $this->sourceId = Class_AdminVar::get('CVS_SOURCEID');
+    $this->sourceKey = Class_AdminVar::get('CVS_SOURCEKEY');
+    $this->sourcePassword = Class_AdminVar::get('CVS_SOURCEPASSWORD');
+    $this->loginTest = Class_AdminVar::get('CVS_LOGINTEST');
   }
 
 
@@ -63,7 +64,7 @@ class Class_CVSLink extends Class_WebService_Abstract {
   }
 
 
-  public function searchNotices($query,$page=1,$nb_par_page=5) {
+  public function searchNotices($query, $page=1, $nb_par_page=5) {
     $this->setConfig();
     return $this->getCvsSearchNotices($query,$page,$nb_par_page);
   }
@@ -71,51 +72,28 @@ class Class_CVSLink extends Class_WebService_Abstract {
 
   public function formatXML($xml) {
     $dom = new DOMDocument;
-    $dom->preserveWhiteSpace = FALSE;
+    $dom->preserveWhiteSpace = false;
     $dom->loadXML($xml);
-    $dom->formatOutput = TRUE;
+    $dom->formatOutput = true;
     return $dom->saveXml();
   }
 
-  
-  function callCVS($action,$body=array(),&$infos){
-    $user = $this->_user ? $this->_user : new Class_Users();
-
-    $user_infos = array_filter([
-      'login' => $user->getLogin(),
-      'nom' => $user->getNom(),
-      'prenom' => $user->getPrenom(),
-      'pseudo' => $user->getPseudo(),
-      'password' => $user->getPassword(),
-      'email' => $user->getMail(),
-      'dnaiss' => (($naissance = $user->getNaissance()) 
-                   ? implode('-', array_reverse(explode('/', $naissance))) 
-                   : ''),
-      'datout' => (($finabo = $user->getDateFin()) 
-                   ? implode('-', array_reverse(explode('/', $finabo))) 
-                   : ''),
-      'bibliotheque' => $user->getLibelleBib()]);
-
-    $xml_user_infos = '';
-    foreach($user_infos as $key => $value) {
-      $xml_user_infos .= "<$key>$value</$key>";
-    }
-
 
+  public function callCVS($action, $body = [], &$infos){
+    $user = $this->_user ? $this->_user : new Class_Users();
     $time = $this->getCurrentTime();
-    if ($this->loginTest && strlen($this->loginTest)>0)
-      $loginCVS = $this->loginTest ;
-    else 
-      $loginCVS = $user->getIdabon() ? $user->getIdabon() : $user->getLogin();    
+
+    $xml_user_infos = $this->_getUserInfos($user);
+    $loginCVS = $this->_getLogin($user);
 
     $key = md5($loginCVS
-               .$this->bmid
-               .$this->bmkey
-               .$this->sourceName
-               .$this->sourceId
-               .$this->sourceKey
-               .$this->sourcePassword
-               .$time.static::CVS_SOURCEXPIRATIONTIME);
+               . $this->bmid
+               . $this->bmkey
+               . $this->sourceName
+               . $this->sourceId
+               . $this->sourceKey
+               . $this->sourcePassword
+               . $time . static::CVS_SOURCEXPIRATIONTIME);
 
     // construction du XML
     $xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
@@ -144,8 +122,8 @@ class Class_CVSLink extends Class_WebService_Abstract {
         <nombre_par_page><![CDATA[".$body['nombre_par_page']."]]></nombre_par_page>
       ";
     }
-    $xml .= "$xml_user_infos</body></albums>";
 
+    $xml .= "$xml_user_infos</body></albums>";
     $xml = base64_encode($this->formatXML($xml));
     $xml = strtr($xml,'+/','-_');
 
@@ -159,43 +137,74 @@ class Class_CVSLink extends Class_WebService_Abstract {
 
     $this->parser->parseXML($ret);
     return $this->parser;
- 
   }
 
+
+  protected function _getUserInfos($user) {
+    $user_infos = ['login' => $user->getLogin(),
+                   'nom' => $user->getNom(),
+                   'prenom' => $user->getPrenom(),
+                   'pseudo' => $user->getPseudo(),
+                   'password' => $user->getPassword(),
+                   'email' => $user->getMail(),
+                   'dnaiss' => (($naissance = $user->getNaissance())
+                                ? implode('-', array_reverse(explode('/', $naissance)))
+                                : ''),
+                   'datout' => (($finabo = $user->getDateFin())
+                                ? implode('-', array_reverse(explode('/', $finabo)))
+                                : ''),
+                   'bibliotheque' => (($label = Class_AdminVar::get('CVS_BMLABEL'))
+                                      ? $label : $user->getLibelleBib())];
+    $user_infos = array_filter($user_infos);
+
+    $xml_user_infos = '';
+    foreach($user_infos as $k => $v)
+      $xml_user_infos .= '<' . $k . '>' . $v . '</' . $k . '>';
+
+    return $xml_user_infos;
+  }
+
+
+  protected function _getLogin($user) {
+    if ($this->loginTest && strlen($this->loginTest) > 0)
+      return $this->loginTest;
+
+    return $user->getIdabon()
+      ? $user->getIdabon() : $user->getLogin();
+  }
+
+
   // retourne le lien chrono-dégradable vers un espace souhaité ($lnk)
-  function getCvsLnk($lnk){
-    $url='';
-    $this->parser = $this->callCVS('acces_site', ['querystring' => $lnk, 'affichage' => 'complet'], $infos);
-    if($this->parser->isSuccess()) {
-      $url = $this->parser->getUrl();
-    } else {
-      $this->setMessage("Merci de contacter la médiathèque pour obtenir un accès.");
-    }
-    return $url;
+  public function getCvsLnk($lnk) {
+    $this->parser = $this->callCVS('acces_site',
+                                   ['querystring' => $lnk,
+                                    'affichage' => 'complet'],
+                                   $infos);
+
+    if ($this->parser->isSuccess())
+      return $this->parser->getUrl();
+
+    $this->setMessage("Merci de contacter la médiathèque pour obtenir un accès.");
+    return '';
   }
 
 
-  function getCvsSearchNotices($query,$page,$nb_par_page){
-    $notices=[];
-    $this->parser = $this->callCVS('search_document', 
+  public function getCvsSearchNotices($query, $page, $nb_par_page){
+    $this->parser = $this->callCVS('search_document',
                                    ['q' => $query,
                                     'espace'=> '',
-                                    'classement' => 
-                                    'consultes', 
-                                    'page' => $page, 
-                                    'nombre_par_page' => $nb_par_page], 
+                                    'classement' =>
+                                    'consultes',
+                                    'page' => $page,
+                                    'nombre_par_page' => $nb_par_page],
                                    $infos);
 
-    if ($this->parser->isSuccess())
-      $notices=$this->parser->getNotices();
-
-    return $notices;
+    return $this->parser->isSuccess()
+      ? $this->parser->getNotices() : [];
   }
 
 
-  function getTotalNotices(){
+  public function getTotalNotices() {
     return $this->parser->getTotalNotices();
   }
-}
-
-?>
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/tests/library/Class/CVSLinkTest.php b/tests/library/Class/CVSLinkTest.php
index 01bced29dd3489266cfb9e50aa97a3205e01ea93..ae0d45b05b34319da6995c341d35258f8817c459 100644
--- a/tests/library/Class/CVSLinkTest.php
+++ b/tests/library/Class/CVSLinkTest.php
@@ -16,21 +16,22 @@
  *
  * 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 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
-abstract class CVSLinkTestCase extends Storm_Test_ModelTestCase {
-  protected   $_http_client;
-  protected $_jerry;
+abstract class CVSLinkTestCase extends ModelTestCase {
+  protected $_storm_default_to_volatile = true;
+  protected $_http_client, $_jerry;
+
   public function setUp() {
     parent::setUp();
-    $this->_http_client = Storm_Test_ObjectWrapper::mock();
+    $this->_http_client = $this->mock();
 
     Class_CVSLink::setTimeSource((new TimeSourceForTest)->setTime(1369640315));
-
     Class_CVSLink::setDefaultHttpClient($this->_http_client);
     Class_Xml::setDefaultHttpClient($this->_http_client);
     RessourcesNumeriquesFixtures::activateCVS();
+
     $this->_jerry = Class_Users::getLoader()
       ->newInstanceWithId(4)
       ->setIdabon(34)
@@ -45,13 +46,14 @@ abstract class CVSLinkTestCase extends Storm_Test_ModelTestCase {
       ->setBib(Class_Bib::newInstanceWithId(34, ['libelle' => 'Annecy']));
 
     $this->_cvs = Class_CVSLink::forUser($this->_jerry);
-
   }
 }
 
 
+
 class CVSLinkSearchTest extends CVSLinkTestCase {
   protected $notices;
+
   public function setUp() {
     parent::setUp();
 
@@ -61,8 +63,8 @@ class CVSLinkSearchTest extends CVSLinkTestCase {
              ['xml' => strtr(base64_encode($this->_expectedXML()), '+/','-_')])
       ->answers($this->_returnedXML())
       ->beStrict();
-    $this->notices=$this->_cvs->searchNotices('ecole',1,5);
 
+    $this->notices = $this->_cvs->searchNotices('ecole', 1, 5);
   }
 
 
@@ -94,6 +96,7 @@ class CVSLinkSearchTest extends CVSLinkTestCase {
                <bibliotheque>Annecy</bibliotheque>
              </body>
            </albums>";
+
     return $this->_cvs->formatXML($xml);
   }
 
@@ -103,27 +106,23 @@ class CVSLinkSearchTest extends CVSLinkTestCase {
     return $xml;
   }
 
+
   /** @test */
   public function searchEcoleShouldReturnTitleForFirstNoticeEtreEtAvoir() {
-    
     $this->assertEquals('Etre et avoir',
                         $this->notices[0]->getTitrePrincipal());
   }
 
 
   /** @test */
-
   public function searchEcoleShouldReturnSecondNoticeYear2013() {
-    
     $this->assertEquals('2013',
                         $this->notices[1]->getAnnee());
   }
 
 
   /** @test */
-
   public function searchEcoleShouldReturnThirdResume() {
-    
     $this->assertEquals('Pascal Paul nous présente un
 témoignage sur les retours d’utilisation des outils nomades au niveau de
 l’école primaire, l’adaptation du matériel aux pratiques pédagogiques.',
@@ -133,28 +132,92 @@ l’école primaire, l’adaptation du matériel aux pratiques pédagogiques.',
 
   /** @test */
   public function searchEcoleFirstNoticeShouldReturnExternalUrl() {
-    
     $this->assertEquals('album&docid=230240',
                         $this->notices[1]->getExternalUri());
   }
-
 }
 
-class CVSLinkWithAbonTest extends CVSLinkTestCase {
-  
 
+
+class CVSLinkWithAbonTest extends CVSLinkTestCase {
   public function setUp() {
     parent::setUp();
 
+    $this->_http_client
+      ->whenCalled('postData')
+      ->with('http://stream.cvs-mediatheques.com/api/partners.php',
+             ['xml' => strtr(base64_encode($this->_expectedXML()), '+/','-_')])
+      ->answers($this->_returnedXML())
+      ->beStrict();
+  }
 
-    $this->_http_client = Storm_Test_ObjectWrapper::mock();
 
-    Class_CVSLink::setTimeSource((new TimeSourceForTest)->setTime(1369640315));
+  protected function _expectedXML() {
+    $xml="<?xml version=\"1.0\" encoding=\"utf-8\"?>
+          <albums>
+           <header>
+             <bmid>22223</bmid>
+             <sourceid>22225</sourceid>
+             <key>d0a1b72e8e6d7af27d400e2009c1a873</key>
+             <time>1369640315</time>
+             <adhid>34</adhid>
+             <action>acces_site</action>
+           </header>
+           <body>
+             <querystring><![CDATA[]]></querystring>
+             <affichage>complet</affichage>
+             <login>34</login>
+             <nom>Khan</nom>
+             <prenom>Jerry</prenom>
+             <pseudo>JKhan</pseudo>
+             <password>secret</password>
+             <email>feu@essence.fr</email>
+             <dnaiss>1977-06-27</dnaiss>
+             <datout>2023-09-02</datout>
+             <bibliotheque>Annecy</bibliotheque>
+           </body>
+         </albums>";
+    return $this->_cvs->formatXML($xml);
+  }
 
-    Class_CVSLink::setDefaultHttpClient($this->_http_client);
-    Class_Xml::setDefaultHttpClient($this->_http_client);
+
+  protected function _returnedXML() {
+    return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+           <response>
+             <success>1</success>
+             <key>e1205ecb51fcb573303e2a67962e0a1e</key>
+             <time>1369639886</time>
+             <action>acces_site</action>
+             <data>
+               <url>http://montauban.cvs-mediatheques.com/?ln=musique&amp;con=01255712bd8d68e9e08fe3ff1dadc57a&amp;if=0</url>
+             </data>
+           </response>";
+  }
 
 
+  /** @test */
+  public function urlForJerryShouldBeCVSSSO() {
+    $this->assertEquals('http://stream.cvs-mediatheques.com/api/partners.php',
+                        $this->_cvs->baseUrl());
+  }
+
+
+  /** @test */
+  public function cvsUrlShouldExtractUrlFromResponse() {
+    $this->assertEquals('http://montauban.cvs-mediatheques.com/?ln=musique&con=01255712bd8d68e9e08fe3ff1dadc57a&if=0',
+                        $this->_cvs->url());
+  }
+}
+
+
+
+/** @see http://forge.afi-sa.fr/issues/30672 */
+class CVSLinkWithAbonAndLibraryLabelTest extends CVSLinkTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    Class_AdminVar::set('CVS_BMLABEL', 'Chinon-Vienne-Loire');
+
     $this->_http_client
       ->whenCalled('postData')
       ->with('http://stream.cvs-mediatheques.com/api/partners.php',
@@ -186,7 +249,7 @@ class CVSLinkWithAbonTest extends CVSLinkTestCase {
              <email>feu@essence.fr</email>
              <dnaiss>1977-06-27</dnaiss>
              <datout>2023-09-02</datout>
-             <bibliotheque>Annecy</bibliotheque>
+             <bibliotheque>Chinon-Vienne-Loire</bibliotheque>
            </body>
          </albums>";
     return $this->_cvs->formatXML($xml);
@@ -216,8 +279,7 @@ class CVSLinkWithAbonTest extends CVSLinkTestCase {
 
   /** @test */
   public function cvsUrlShouldExtractUrlFromResponse() {
-    $this->assertEquals('http://montauban.cvs-mediatheques.com/?ln=musique&con=01255712bd8d68e9e08fe3ff1dadc57a&if=0', 
+    $this->assertEquals('http://montauban.cvs-mediatheques.com/?ln=musique&con=01255712bd8d68e9e08fe3ff1dadc57a&if=0',
                         $this->_cvs->url());
   }
-}
-?>
\ No newline at end of file
+}
\ No newline at end of file