diff --git a/VERSIONS_HOTLINE/109494 b/VERSIONS_HOTLINE/109494
new file mode 100644
index 0000000000000000000000000000000000000000..2e5133c8f5e1cd3ff5a98404b9161c486b0c0222
--- /dev/null
+++ b/VERSIONS_HOTLINE/109494
@@ -0,0 +1 @@
+ - ticket #109494 : PNB Dilicom : Correction de la mise à jour erronée des compteur de prêts lorsque la commande a été annulée
\ No newline at end of file
diff --git a/library/Class/Album/Item.php b/library/Class/Album/Item.php
index 4d3c4680ad18bdd094ce2e5638745e3a628b1bf6..a8df06267be322a0f1d28d303e3903ddea480224 100644
--- a/library/Class/Album/Item.php
+++ b/library/Class/Album/Item.php
@@ -112,6 +112,11 @@ class Class_Album_Item extends Storm_Model_Abstract {
   }
 
 
+  public function getLoanMaxNumberOfUsers() {
+    return $this->getUsageConstraints()->getLoanMaxNumberOfUsers();
+  }
+
+
   public function setLoanMaxNumberOfUsers($max) {
     $this->getUsageConstraints()->setLoanMaxNumberOfUsers($max);
     return $this;
diff --git a/library/Class/WebService/BibNumerique/Dilicom/Hub.php b/library/Class/WebService/BibNumerique/Dilicom/Hub.php
index 2ee69d428033f04ddbe1a162276b42d4836f9d00..f0fccdcf8e4a4ed84abdc250df08fe8532ec5c96 100644
--- a/library/Class/WebService/BibNumerique/Dilicom/Hub.php
+++ b/library/Class/WebService/BibNumerique/Dilicom/Hub.php
@@ -479,14 +479,20 @@ class Class_WebService_BibNumerique_Dilicom_Hub extends Class_WebService_Abstrac
 
   protected function _updateItemStatus($item) {
     $content = $this->getLoanStatus($item);
+    if (!isset($content->loanResponseLine[0]))
+      return $this;
 
-    if (isset($content->loanResponseLine[0])) {
-      $simultaneous_users_remaining = $content->loanResponseLine[0]->nus1;
+    $status = $content->loanResponseLine[0];
+    if (!isset($status->nus1) || !isset($status->nta))
+      return $this;
 
-      $item->setLoanCount(max(0, $item->getUsageConstraints()->getLoanMaxNumberOfUsers() - $simultaneous_users_remaining));
-      $item->setQuantity($item->getUsageConstraints()->getLoanQuantity() - $content->loanResponseLine[0]->nta);
-      $item->save();
-    }
+    $simultaneous_users_remaining = $status->nus1;
+    $loans_remaining = $status->nta;
+
+    $item->setLoanCount(max(0, $item->getLoanMaxNumberOfUsers() - $simultaneous_users_remaining));
+    $item->setQuantity($item->getLoanQuantity() - $loans_remaining);
+
+    $item->save();
 
     return $this;
   }
diff --git a/tests/fixtures/DilicomFixtures.php b/tests/fixtures/DilicomFixtures.php
index 3e41a4ccbee309ea48a580327168fa4aac03e55e..ace18c53364d3d5f9b6651183fc2f71a29dffc5d 100644
--- a/tests/fixtures/DilicomFixtures.php
+++ b/tests/fixtures/DilicomFixtures.php
@@ -165,6 +165,16 @@ class DilicomFixtures {
   }
 
 
+  public static function getLoanStatusCancelledResponse($orderLineId) {
+    return '{
+      "date":"2020-09-10T15:51:53Z",
+      "loanResponseLine":[{"orderLineId":"' . $orderLineId . '",
+                           "returnStatus":"CANCELLED"}],
+      "returnStatus":"WARNING",
+      "returnMessage":["All order lines are returned with error"]}';
+  }
+
+
   public static function getEndedLoansResponse($lines=[]) {
     return '{
   "requestId":"aw01v2_000000041_201502261519",
@@ -176,6 +186,28 @@ class DilicomFixtures {
 
 
   public function albumTotemThora() {
+    $constraints = [$this->fixture('Class_Album_UsageConstraint',
+                                   ['id' => 1,
+                                    'album_id' => 3,
+                                    'usage_type' => Class_Album_UsageConstraint::LOAN_CONSTRAINT,
+                                    Class_Album_UsageConstraint::MAX_NB_OF_USERS => 50,
+                                    Class_Album_Usageconstraint::QUANTITY => 50]),
+
+                    $this->fixture('Class_Album_UsageConstraint',
+                                   ['id' => 2,
+                                    'album_id' => 3,
+                                    'usage_type' => Class_Album_UsageConstraint::AVAILABILITY_CONSTRAINT,
+                                    Class_Album_UsageConstraint::DURATION => '10000',
+                                    Class_Album_UsageConstraint::ORDER_DATE => '2015-04-01 00:00:00',
+                                    'order_line_id' => 'x321'])];
+
+    $item = $this->fixture('Class_Album_Item',
+                           ['id' => 1,
+                            'album_id' => 3,
+                            'loan_count' => 2,
+                            'quantity' => 4,
+                            'usage_constraints' => $constraints]);
+
     return $this->fixture('Class_Album',
                           ['id' => 3,
                            'titre' => 'Totem et Thora',
@@ -183,25 +215,7 @@ class DilicomFixtures {
                            'external_uri' => 'http://www.edenlivres.fr/p/23416',
                            'url_origine' => 'https://url_dilicom.org/ressource/id/1',
                            'type_doc_id' => Class_TypeDoc::DILICOM,
-                           'items' => [$this->fixture('Class_Album_Item',
-                                                      ['id' => 1,
-                                                       'album_id' => 3,
-                                                       'loan_count' => 2,
-                                                       'quantity' => 4,
-                                                       'usage_constraints' => [$this->fixture('Class_Album_UsageConstraint',
-                                                                                              ['id' => 1,
-                                                                                               'album_id' => 3,
-                                                                                               'usage_type' => Class_Album_UsageConstraint::LOAN_CONSTRAINT,
-                                                                                               Class_Album_UsageConstraint::MAX_NB_OF_USERS => 50,
-                                                                                               Class_Album_Usageconstraint::QUANTITY => 50]),
-
-                                                                               $this->fixture('Class_Album_UsageConstraint',
-                                                                                              ['id' => 2,
-                                                                                               'album_id' => 3,
-                                                                                               'usage_type' => Class_Album_UsageConstraint::AVAILABILITY_CONSTRAINT,
-                                                                                               Class_Album_UsageConstraint::DURATION => '10000',
-                                                                                               Class_Album_UsageConstraint::ORDER_DATE => '2015-04-01 00:00:00',
-                                                                                               'order_line_id' => 'x321'])]])]])
+                           'items' => [$item]])
                 ->addAuthor('Raphaël Draï');
   }
 }
\ No newline at end of file
diff --git a/tests/scenarios/PnbDilicom/PnbDilicomTest.php b/tests/scenarios/PnbDilicom/PnbDilicomTest.php
index 20a9a6d1d2b51a847fb9130670544c865ef106e0..4f46447088ce73cc5dc3f9ea564b1eb4e2aecf02 100644
--- a/tests/scenarios/PnbDilicom/PnbDilicomTest.php
+++ b/tests/scenarios/PnbDilicom/PnbDilicomTest.php
@@ -1612,538 +1612,13 @@ class PnbDilicomViewHelperNoticeLoggedTest extends PnbDilicomViewHelperNoticeTes
 
 
 
-abstract class PnbDilicomViewHelperRenderAlbumTestCase extends ViewHelperTestCase {
-
-  protected $_storm_default_to_volatile = true,
-    $_helper,
-    $_html;
-
-  public function setUp() {
-    parent::setUp();
-
-    $view = new ZendAfi_Controller_Action_Helper_View();
-    $this->_helper = new ZendAfi_View_Helper_RenderAlbum();
-    $this->_helper->setView($view);
-
-    $this->book = (new DilicomFixtures())->albumTotemThora();
-    RessourcesNumeriquesFixtures::activateDilicom();
-
-    $this->_http = $this->mock();
-    Class_WebService_BibNumerique_Dilicom_Hub::setDefaultHttpClient($this->_http);
-
-    $this->_time_source = new TimeSourceForTest('2014-05-02 14:14:14');
-    Class_WebService_BibNumerique_Dilicom_Hub::setTimeSource($this->_time_source);
-    Class_Album_UsageConstraint::setTimeSource($this->_time_source);
-    Class_Hold_Pnb::setTimeSource($this->_time_source);
-
-    $this->_http
-      ->whenCalled('setAuth')
-      ->answers(null)
-
-      ->whenCalled('open_url')
-      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(5, 24));
-
-  }
-
-
-  public function tearDown() {
-    ZendAfi_Auth::getInstance()->clearIdentity();
-    Class_WebService_BibNumerique_Dilicom_Hub::setTimeSource(null);
-    Class_Album_UsageConstraint::setTimeSource(null);
-    Class_Hold_Pnb::setTimeSource(null);
-    parent::tearDown();
-  }
-}
-
-
-
-
-class PnbDilicomViewHelperRenderAlbumPNBNotLoggedTest extends PnbDilicomViewHelperRenderAlbumTestCase {
-
-  public function setUp() {
-    parent::setUp();
-    ZendAfi_Auth::getInstance()->clearIdentity();
-    $this->_html = $this->_helper->renderAlbum($this->book);
-  }
-
-
-  /** @test */
-  public function htmlShouldNotContainsLinkToConsultBook() {
-    $this->assertXPathContentContains($this->_html,
-                                      '//a[contains(@href, "/bib-numerique/consult-book-ajax/id/3")]',
-                                      'Consulter le livre en ligne');
-  }
-}
-
-
-
-
-class PnbDilicomViewHelperRenderAlbumPNBLoggedButNotAuthorizeTest
-  extends PnbDilicomViewHelperRenderAlbumTestCase {
-
-  public function setUp() {
-    parent::setUp();
-    $this->logged_user = $this->fixture('Class_Users',
-                                        ['id' => 6,
-                                         'nom'=>'Pito',
-                                         'login'=>'Chat',
-                                         'password'=>'123456',
-                                         'id_site' => 1,
-                                         'idabon' => '12345']);
-
-    $this->logged_user->setUserGroups([]);
-    ZendAfi_Auth::getInstance()->logUser($this->logged_user);
-    $this->_html = $this->_helper->renderAlbum($this->book);
-  }
-
-
-  /** @test */
-  public function htmlShouldNotContainsLinkToConsultBook() {
-    $this->assertXPathContentContains($this->_html,
-                                      '//p',utf8_encode("Vous n'avez pas le droit d'accéder à la consultation en ligne."));
-  }
-}
-
-
-
-
-class PnbDilicomViewHelperRenderAlbumPNBTest extends PnbDilicomViewHelperRenderAlbumTestCase {
-
-  public function setUp() {
-    parent::setUp();
-
-    $this->fixture('Class_Bib', ['id' => 1,
-                                 'libelle' => 'Annecy',
-                                 'gln' => '333']);
-
-    $this->logged_user = $this->fixture('Class_Users',
-                                        ['id' => 6,
-                                         'nom'=>'Pito',
-                                         'login'=>'Chat',
-                                         'password'=>'123456',
-                                         'id_site' => 1,
-                                         'idabon' => '12345',
-                                         'user_groups' => [$this->fixture('Class_UserGroup',
-                                                                          ['id' => '20',
-                                                                           'libelle' => 'Multimedia',
-                                                                           'rights' => [Class_UserGroup::RIGHT_ACCES_PNB_DILICOM]])]]);
-
-    $this->logged_user->beAbonneSIGB()->assertSave();
-    ZendAfi_Auth::getInstance()->logUser($this->logged_user);
-
-    $this->fixture('Class_Loan_Pnb', ['id' => 1,
-                                      'record_origin_id' => 'Dilicom-88817216',
-                                      'user_id' => '6']);
-
-    Class_AdminVar::set('DILICOM_PNB_ENABLE_HOLDS', '1');
-    $this->_html = $this->_helper->renderAlbum($this->book);
-  }
-
-
-  public function tearDown() {
-    unset($_SERVER['HTTPS']);
-    parent::tearDown();
-  }
-
-
-  /** @test */
-  public function htmlShouldContainsIFrameOnEdenBook() {
-    $this->assertXPath($this->_html,
-                       '//iframe[@src="http://www.edenlivres.fr/p/23416"][@width="100%"][@height="600px"]',
-                       $this->_html);
-  }
-
-
-  /** @test */
-  public function htmlShouldContainsLinkToConsultBook() {
-    $this->assertXPathContentContains($this->_html,
-                                      '//a[contains(@href, "/bib-numerique/consult-book-ajax/id/3")]',
-                                      'Consulter le livre en ligne');
-  }
-
-
-  /** @test */
-  public function htmlShouldContainsLinkToLoanBook() {
-    $this->assertXPathContentContains($this->_html,
-                                      '//a[contains(@href, "/bib-numerique/loan-book-ajax/id/3")]',
-                                      'Emprunter le livre au format EPUB');
-  }
-
-
-  /** @test */
-  public function htmlShouldNotContainsHoldBookLink() {
-    $this->assertNotXPath($this->_html,
-                          '//a[contains(@href, "/hold-book")]');
-  }
-
-
-  /** @test */
-  public function htmlShouldNotContainsReservationImpossible() {
-    $this->assertNotXPathContentContains($this->_html,
-                                         '//span',
-                                         utf8_encode('Réservation impossible'),
-                                         $this->_html);
-  }
-
-
-  /** @test */
-  public function bibWithoutGlnShouldReturnErrorMessage() {
-    Class_Bib::find(1)->setGln('')->assertSave();
-    $this->_html = $this->_helper->renderAlbum($this->book);
-    $this->assertXPathContentContains($this->_html,
-                                      '//p', utf8_encode('Annecy n\'a pas accès à la consultation en ligne'));
-  }
-
-
-  /** @test */
-  public function userWithoutBibShouldReturnErrorMessage() {
-    $this->logged_user->setBib(null)->save();
-    $this->_html = $this->_helper->renderAlbum($this->book);
-    $this->assertXPathContentContains($this->_html,
-                                      '//p', utf8_encode('Vous devez être inscrit dans une bibliothèque pour accéder à la consultation en ligne'));
-
-  }
-
-  /** @test */
-  public function withHttpsPreviewSrcShouldBeHttps() {
-    $_SERVER['HTTPS'] = 'on';
-
-    $this->_html = $this->_helper->renderAlbum($this->book);
-    $this->assertXPath($this->_html,
-                       '//iframe[@src="https://www.edenlivres.fr/p/23416"][@width="100%"][@height="600px"]',
-                       $this->_html);
-  }
-}
-
-
-
-
-class PnbDilicomViewHelperRenderAlbumPNBLoggedButBlockedTest
-  extends PnbDilicomViewHelperRenderAlbumTestCase {
-
-  public function setUp() {
-    parent::setUp();
-
-    $this->fixture('Class_Bib', ['id' => 1,
-                                 'libelle' => 'Annecy',
-                                 'gln' => '333']);
-
-    $group = $this->fixture('Class_UserGroup',
-                            ['id' => '20',
-                             'libelle' => 'Dilicom',
-                             'group_type' => Class_UserGroup::TYPE_DYNAMIC,
-                             'filters'   => json_encode([
-                                                         'search_role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
-                                                         'search_valid_subscription' => 1]),
-
-                             'rights' => [Class_UserGroup::RIGHT_ACCES_PNB_DILICOM]]);
-
-    $this->logged_user = $this
-      ->fixture('Class_Users',
-                ['id' => 6,
-                 'nom'=>'Pito',
-                 'login'=>'Chat',
-                 'password'=>'123456',
-                 'id_site' => 1,
-                 'int_bib' => $this->fixture('Class_IntBib',
-                                             ['id' => 1,
-                                              'comm_sigb' => Class_IntBib::COM_ORPHEE,
-                                              'comm_params' => ['url_serveur' => 'tests/fixtures/orphee.wsdl',
-                                                                'allow_hold_available_items' => true]]),
-                 'idabon' => '12345',
-                ]);
-
-    Class_WebService_SIGB_Orphee::setService($this->mock()
-                                             ->whenCalled('isConnected')->answers(true)
-                                             ->whenCalled('getEmprunteur')
-                                             ->answers(Class_WebService_SIGB_Emprunteur::nullInstance()->beBlocked())
-    );
-
-    $this->logged_user->beAbonneSIGB()->assertSave();
-    ZendAfi_Auth::getInstance()->logUser($this->logged_user);
-
-    $this->fixture('Class_Loan_Pnb', ['id' => 1,
-                                      'record_origin_id' => 'Dilicom-88817216',
-                                      'user_id' => '6']);
-
-
-    $this->_html = $this->_helper->renderAlbum($this->book);
-  }
-
-
-  public function tearDown() {
-    unset($_SERVER['HTTPS']);
-    Class_WebService_SIGB_Orphee::setService(null);
-
-    parent::tearDown();
-  }
-
-
-  /** @test */
-  public function htmlShouldContainsIFrameOnEdenBook() {
-    $this->assertXPath($this->_html,
-                       '//iframe[@src="http://www.edenlivres.fr/p/23416"][@width="100%"][@height="600px"]',
-                       $this->_html);
-  }
-
-
-  /** @test */
-  public function htmlShouldContainsNotAuthorizedMessage() {
-    $this->assertXPathContentContains($this->_html, '//div', 'Vous n\'avez pas le droit');
-  }
-}
-
-
-
-
-class PnbDilicomViewHelperRenderAlbumPNBGetLoanStatusTest extends PnbDilicomViewHelperRenderAlbumTestCase {
-
-  public function setUp() {
-    parent::setUp();
-    $this->fixture('Class_Bib', ['id' => 1,
-                                 'libelle' => 'Annecy',
-                                 'gln' => '333']);
-
-    $group =$this->fixture('Class_UserGroup',
-                           ['id' => '20',
-                            'libelle' => 'Multimedia',
-                            'rights' => [Class_UserGroup::RIGHT_ACCES_PNB_DILICOM]]);
-
-    $this->logged_user = $this->fixture('Class_Users',
-                                        ['id' => 6,
-                                         'nom'=>'Pito',
-                                         'login'=>'Chat',
-                                         'password'=>'123456',
-                                         'id_site' => 1,
-                                         'idabon' => '12345',
-                                         'user_groups' => [$group]]);
-
-    $this->logged_user->beAbonneSIGB()->assertSave();
-    ZendAfi_Auth::getInstance()->logUser($this->logged_user);
-
-
-    $this->other_user = $this->fixture('Class_Users',
-                                        ['id' => 7,
-                                         'nom'=>'Boum',
-                                         'login'=>'Baia',
-                                         'password'=>'9876',
-                                         'id_site' => 1,
-                                         'idabon' => '9876',
-                                         'user_groups' => [$group]]);
-
-    $this->other_user->beAbonneSIGB()->assertSave();
-  }
-
-
-  /** @test */
-  public function htmlShouldContainsRessourceNotAvailable() {
-    Class_Album_UsageConstraint::find(2)->setOrderDate('1900-05-02 14:14:14')->assertSave();
-    $this->_html = $this->_helper->renderAlbum($this->book);
-
-    $this->assertXPathContentContains($this->_html,
-                                      '//div//span[@class="error"]',
-                                      'La ressource n\'est plus disponible.');
-  }
-
-
-  /** @test */
-  public function htmlShouldContainsQuotaEmpty() {
-    $this->_http
-      ->whenCalled('open_url')
-      ->answers('');
-
-    Class_AdminVar::set('DILICOM_PNB_MAX_LOAN_PER_USER', 3);
-
-    foreach(range(1, 3) as $step)
-      $this->fixture('Class_Loan_Pnb',
-                     ['id' => $step,
-                      'user_id' => $this->logged_user->getId(),
-                      'record_origin_id' => $step,
-                      'expected_return_date' => '2022-06-01']);
-
-    $this->_html = $this->_helper->renderAlbum($this->book);
-
-    $this->assertXPathContentContains($this->_html,
-                                      '//div//span[@class="error"]',
-                                      'Emprunt impossible. Vous avez atteint votre quota de 3 emprunts');
-  }
-
-
-  /** @test */
-  public function withLoanCountTreeAndLoanCountLimitReachedHtmlShouldContainsNextAvailableLoanDate() {
-    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(5)->assertSave();
-    $this->_http
-      ->whenCalled('open_url')
-      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(2, 24));
-    // ^ so current loan count = (5 max users - 2 loans available) = 3
-
-    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT', 1);
-    $this->fixture('Class_Loan_Pnb',
-                   ['id' => 1,
-                    'user_id' => $this->other_user->getId(),
-                    'record_origin_id' => 'Dilicom-88817216',
-                    'order_line_id' => 'x321',
-                    'expected_return_date' => '2022-06-01 20:10:00']);
-
-    $this->assertXPathContentContains($this->_helper->renderAlbum($this->book),
-                                      '//div//span[@class="error"]',
-                                      utf8_encode('Emprunt impossible. Le nombre d\'emprunts simultanés pour ce document est atteint. Le prochain emprunt sera possible le mercredi 01 juin à 20h10'));
-  }
-
-
-  /** @test */
-  public function withLoanCountOneAndOneActiveHoldsShouldContainsDocumentAlreadyHeld() {
-    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(5)->assertSave();
-    $this->_http
-      ->whenCalled('open_url')
-      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(3, 24));
-    // ^ current loan count = (5 max users - 3 loans available) = 2
-
-    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT', 3);
-
-    $this->fixture('Class_Hold_Pnb',
-                   ['id' => 1,
-                    'user_id' => 876,
-                    'record_origin_id' => $this->book->getIdOrigine(),
-                    'hold_date' => '2014-04-25 14:14:14']);
-
-    $this->assertXPathContentContains($this->_helper->renderAlbum($this->book),
-                                      '//div//span[@class="error"]',
-                                      utf8_encode('Emprunt impossible. Ce document est déjà réservé'));
-  }
-
-
-  /** @test */
-  public function withLoanCountOneAndOneActiveHoldForCurrentUserShouldContainsLoanButton() {
-    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(5)->assertSave();
-    $this->_http
-      ->whenCalled('open_url')
-      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(3, 24));
-    // ^ current loan count = (5 max users - 3 loans available) = 2
-
-    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT', 3);
-
-    $this->fixture('Class_Hold_Pnb',
-                   ['id' => 1,
-                    'user_id' => Class_Users::getIdentity()->getId(),
-                    'record_origin_id' => $this->book->getIdOrigine(),
-                    'hold_date' => '2014-04-25 14:14:14']);
-
-    $this->assertXPathContentContains($this->_helper->renderAlbum($this->book),
-                                      '//div//a',
-                                      utf8_encode('Emprunter le livre au format EPUB'));
-  }
-
-
-
-  /** @test */
-  public function withLoanCountOneAndOneExpiredHoldsShouldContainsLoanButton() {
-    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(5)->assertSave();
-    $this->_http
-      ->whenCalled('open_url')
-      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(3, 24));
-    // ^ current loan count = (5 max users - 3 loans available) = 2
-
-    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT', 3);
-
-    $this->fixture('Class_Hold_Pnb',
-                   ['id' => 1,
-                    'user_id' => 876,
-                    'record_origin_id' => $this->book->getIdOrigine(),
-                    'hold_date' => '2014-04-25 14:14:14',
-                    'expiration_date' => '2014-04-26 14:14:14']);
-
-    $this->assertXPathContentContains($this->_helper->renderAlbum($this->book),
-                                      '//div//a',
-                                      utf8_encode('Emprunter le livre au format EPUB'));
-  }
-
-
-  /** @test */
-  public function withoutLoanAndThreeActiveHoldsAndAllocatedHolderShouldContainsLoanButton() {
-    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(1)->assertSave();
-    $this->_http
-      ->whenCalled('open_url')
-      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(1, 1));
-
-    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT', 3);
-
-    $this->fixture('Class_Hold_Pnb',
-                   ['id' => 1,
-                    'user_id' => Class_Users::getIdentity()->getId(),
-                    'record_origin_id' => $this->book->getIdOrigine(),
-                    'hold_date' => '2014-04-25 14:14:14',
-                    'expiration_date' => '2014-05-05 23:59:59']);
-
-    $this->fixture('Class_Hold_Pnb',
-                   ['id' => 2,
-                    'user_id' => Class_Users::getIdentity()->getId() + 1,
-                    'record_origin_id' => $this->book->getIdOrigine(),
-                    'hold_date' => '2014-04-25 14:15:14']);
-
-    $this->fixture('Class_Hold_Pnb',
-                   ['id' => 3,
-                    'user_id' => Class_Users::getIdentity()->getId() + 2,
-                    'record_origin_id' => $this->book->getIdOrigine(),
-                    'hold_date' => '2014-04-25 14:16:14']);
-
-    $this->assertXPathContentContains($this->_helper->renderAlbum($this->book),
-                                      '//div//a',
-                                      utf8_encode('Emprunter le livre au format EPUB'));
-  }
-
-
-  /** @test */
-  public function withSimultaneousLoanLimitReachedButCurrentlyLoanedByCurrentUserHtmlShouldContainsButtonToLoadAgain() {
-    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(0)->assertSave();
-    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT',0);
-    $this->fixture('Class_Loan_Pnb',
-                   ['id' => 1,
-                    'user_id' => $this->logged_user->getId(),
-                    'record_origin_id' => 'Dilicom-88817216',
-                    'order_line_id' => 'x321',
-                    'expected_return_date' => '2025-06-01 20:10:00',
-                   'loan_link' => 'https://pnb-dilicom.centprod.com/v3//link/xxx.do']);
-
-    $this->_html = $this->_helper->renderAlbum($this->book);
-
-    $this->assertXPath($this->_html,
-                       '//a[contains(@href, "/bib-numerique/loan-book-ajax/id/3")]',
-                       $this->_html);
-  }
-
-
-  /** @test */
-  public function onUnknownReturnDateHtmlShouldNotContainsNextAvailableLoanDate() {
-    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(0)->assertSave();
-    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT',0);
-    $this->fixture('Class_Loan_Pnb',
-                   ['id' => 1,
-                    'user_id' => $this->logged_user->getId(),
-                    'record_origin_id' => 1,
-                    'order_line_id' => '???',
-                    'expected_return_date' => '2022-06-01 20:10:00']);
-
-    $this->_html = $this->_helper->renderAlbum($this->book);
-
-    $this->assertNotXPathContentContains($this->_html,
-                                         '//div//span[@class="error"]',
-                                         utf8_encode('Le prochain emprunt sera possible'));
-  }
-}
-
-
-
-
 class PnbDilicomBibNumeriqueControllerBlockedUserTest extends AbstractControllerTestCase {
-
   protected
     $_http,
     $_book,
     $_time_source,
     $_storm_default_to_volatile = true;
 
-
   public function setUp() {
     parent::setUp();
 
@@ -4736,5 +4211,4 @@ class PnbDilicomBatchProcessHoldsWithThreeLoansAndOnlyTwoHoldsAllocableTest exte
     $this->assertEquals('ridley@localhost.localdomain.com',
                         $this->_sent_mails[0]->getFrom());
   }
-
 }
diff --git a/tests/scenarios/PnbDilicom/PnbDilicomViewHelperTest.php b/tests/scenarios/PnbDilicom/PnbDilicomViewHelperTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c4ab89022664589f8dbaae23a95059bc23d07f47
--- /dev/null
+++ b/tests/scenarios/PnbDilicom/PnbDilicomViewHelperTest.php
@@ -0,0 +1,577 @@
+<?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
+ */
+
+require_once 'tests/fixtures/DilicomFixtures.php';
+
+abstract class PnbDilicomViewHelperRenderAlbumTestCase extends ViewHelperTestCase {
+
+  protected $_storm_default_to_volatile = true,
+    $_helper,
+    $_html;
+
+  public function setUp() {
+    parent::setUp();
+
+    $view = new ZendAfi_Controller_Action_Helper_View();
+    $this->_helper = new ZendAfi_View_Helper_RenderAlbum();
+    $this->_helper->setView($view);
+
+    $this->book = (new DilicomFixtures())->albumTotemThora();
+    RessourcesNumeriquesFixtures::activateDilicom();
+
+    $this->_http = $this->mock();
+    Class_WebService_BibNumerique_Dilicom_Hub::setDefaultHttpClient($this->_http);
+
+    $this->_time_source = new TimeSourceForTest('2014-05-02 14:14:14');
+    Class_WebService_BibNumerique_Dilicom_Hub::setTimeSource($this->_time_source);
+    Class_Album_UsageConstraint::setTimeSource($this->_time_source);
+    Class_Hold_Pnb::setTimeSource($this->_time_source);
+
+    $this->_http
+      ->whenCalled('setAuth')
+      ->answers(null)
+
+      ->whenCalled('open_url')
+      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(5, 24));
+
+  }
+
+
+  public function tearDown() {
+    ZendAfi_Auth::getInstance()->clearIdentity();
+    Class_WebService_BibNumerique_Dilicom_Hub::setTimeSource(null);
+    Class_Album_UsageConstraint::setTimeSource(null);
+    Class_Hold_Pnb::setTimeSource(null);
+    parent::tearDown();
+  }
+}
+
+
+
+
+class PnbDilicomViewHelperRenderAlbumNotLoggedTest
+  extends PnbDilicomViewHelperRenderAlbumTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    ZendAfi_Auth::getInstance()->clearIdentity();
+    $this->_html = $this->_helper->renderAlbum($this->book);
+  }
+
+
+  /** @test */
+  public function htmlShouldNotContainsLinkToConsultBook() {
+    $this->assertXPathContentContains($this->_html,
+                                      '//a[contains(@href, "/bib-numerique/consult-book-ajax/id/3")]',
+                                      'Consulter le livre en ligne');
+  }
+}
+
+
+
+
+class PnbDilicomViewHelperRenderAlbumLoggedButNotAuthorizeTest
+  extends PnbDilicomViewHelperRenderAlbumTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    $this->logged_user = $this->fixture('Class_Users',
+                                        ['id' => 6,
+                                         'nom'=>'Pito',
+                                         'login'=>'Chat',
+                                         'password'=>'123456',
+                                         'id_site' => 1,
+                                         'idabon' => '12345']);
+
+    $this->logged_user->setUserGroups([]);
+    ZendAfi_Auth::getInstance()->logUser($this->logged_user);
+    $this->_html = $this->_helper->renderAlbum($this->book);
+  }
+
+
+  /** @test */
+  public function htmlShouldNotContainsLinkToConsultBook() {
+    $this->assertXPathContentContains($this->_html,
+                                      '//p',utf8_encode("Vous n'avez pas le droit d'accéder à la consultation en ligne."));
+  }
+}
+
+
+
+
+class PnbDilicomViewHelperRenderAlbumLoggedAndAuthorizedTest
+  extends PnbDilicomViewHelperRenderAlbumTestCase {
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture('Class_Bib', ['id' => 1,
+                                 'libelle' => 'Annecy',
+                                 'gln' => '333']);
+
+    $this->logged_user = $this->fixture('Class_Users',
+                                        ['id' => 6,
+                                         'nom'=>'Pito',
+                                         'login'=>'Chat',
+                                         'password'=>'123456',
+                                         'id_site' => 1,
+                                         'idabon' => '12345',
+                                         'user_groups' => [$this->fixture('Class_UserGroup',
+                                                                          ['id' => '20',
+                                                                           'libelle' => 'Multimedia',
+                                                                           'rights' => [Class_UserGroup::RIGHT_ACCES_PNB_DILICOM]])]]);
+
+    $this->logged_user->beAbonneSIGB()->assertSave();
+    ZendAfi_Auth::getInstance()->logUser($this->logged_user);
+
+    $this->fixture('Class_Loan_Pnb', ['id' => 1,
+                                      'record_origin_id' => 'Dilicom-88817216',
+                                      'user_id' => '6']);
+
+    Class_AdminVar::set('DILICOM_PNB_ENABLE_HOLDS', '1');
+    $this->_html = $this->_helper->renderAlbum($this->book);
+  }
+
+
+  public function tearDown() {
+    unset($_SERVER['HTTPS']);
+    parent::tearDown();
+  }
+
+
+  /** @test */
+  public function htmlShouldContainsIFrameOnEdenBook() {
+    $this->assertXPath($this->_html,
+                       '//iframe[@src="http://www.edenlivres.fr/p/23416"][@width="100%"][@height="600px"]',
+                       $this->_html);
+  }
+
+
+  /** @test */
+  public function htmlShouldContainsLinkToConsultBook() {
+    $this->assertXPathContentContains($this->_html,
+                                      '//a[contains(@href, "/bib-numerique/consult-book-ajax/id/3")]',
+                                      'Consulter le livre en ligne');
+  }
+
+
+  /** @test */
+  public function htmlShouldContainsLinkToLoanBook() {
+    $this->assertXPathContentContains($this->_html,
+                                      '//a[contains(@href, "/bib-numerique/loan-book-ajax/id/3")]',
+                                      'Emprunter le livre au format EPUB');
+  }
+
+
+  /** @test */
+  public function htmlShouldNotContainsHoldBookLink() {
+    $this->assertNotXPath($this->_html,
+                          '//a[contains(@href, "/hold-book")]');
+  }
+
+
+  /** @test */
+  public function htmlShouldNotContainsReservationImpossible() {
+    $this->assertNotXPathContentContains($this->_html,
+                                         '//span',
+                                         utf8_encode('Réservation impossible'),
+                                         $this->_html);
+  }
+
+
+  /** @test */
+  public function bibWithoutGlnShouldReturnErrorMessage() {
+    Class_Bib::find(1)->setGln('')->assertSave();
+    $this->_html = $this->_helper->renderAlbum($this->book);
+    $this->assertXPathContentContains($this->_html,
+                                      '//p', utf8_encode('Annecy n\'a pas accès à la consultation en ligne'));
+  }
+
+
+  /** @test */
+  public function userWithoutBibShouldReturnErrorMessage() {
+    $this->logged_user->setBib(null)->save();
+    $this->_html = $this->_helper->renderAlbum($this->book);
+    $this->assertXPathContentContains($this->_html,
+                                      '//p', utf8_encode('Vous devez être inscrit dans une bibliothèque pour accéder à la consultation en ligne'));
+
+  }
+
+  /** @test */
+  public function withHttpsPreviewSrcShouldBeHttps() {
+    $_SERVER['HTTPS'] = 'on';
+
+    $this->_html = $this->_helper->renderAlbum($this->book);
+    $this->assertXPath($this->_html,
+                       '//iframe[@src="https://www.edenlivres.fr/p/23416"][@width="100%"][@height="600px"]',
+                       $this->_html);
+  }
+}
+
+
+
+
+class PnbDilicomViewHelperRenderAlbumLoggedButBlockedTest
+  extends PnbDilicomViewHelperRenderAlbumTestCase {
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture('Class_Bib', ['id' => 1,
+                                 'libelle' => 'Annecy',
+                                 'gln' => '333']);
+
+    $group = $this->fixture('Class_UserGroup',
+                            ['id' => '20',
+                             'libelle' => 'Dilicom',
+                             'group_type' => Class_UserGroup::TYPE_DYNAMIC,
+                             'filters'   => json_encode([
+                                                         'search_role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                                                         'search_valid_subscription' => 1]),
+
+                             'rights' => [Class_UserGroup::RIGHT_ACCES_PNB_DILICOM]]);
+
+    $this->logged_user = $this
+      ->fixture('Class_Users',
+                ['id' => 6,
+                 'nom'=>'Pito',
+                 'login'=>'Chat',
+                 'password'=>'123456',
+                 'id_site' => 1,
+                 'int_bib' => $this->fixture('Class_IntBib',
+                                             ['id' => 1,
+                                              'comm_sigb' => Class_IntBib::COM_ORPHEE,
+                                              'comm_params' => ['url_serveur' => 'tests/fixtures/orphee.wsdl',
+                                                                'allow_hold_available_items' => true]]),
+                 'idabon' => '12345',
+                ]);
+
+    Class_WebService_SIGB_Orphee::setService($this->mock()
+                                             ->whenCalled('isConnected')->answers(true)
+                                             ->whenCalled('getEmprunteur')
+                                             ->answers(Class_WebService_SIGB_Emprunteur::nullInstance()->beBlocked())
+    );
+
+    $this->logged_user->beAbonneSIGB()->assertSave();
+    ZendAfi_Auth::getInstance()->logUser($this->logged_user);
+
+    $this->fixture('Class_Loan_Pnb', ['id' => 1,
+                                      'record_origin_id' => 'Dilicom-88817216',
+                                      'user_id' => '6']);
+
+
+    $this->_html = $this->_helper->renderAlbum($this->book);
+  }
+
+
+  public function tearDown() {
+    unset($_SERVER['HTTPS']);
+    Class_WebService_SIGB_Orphee::setService(null);
+
+    parent::tearDown();
+  }
+
+
+  /** @test */
+  public function htmlShouldContainsIFrameOnEdenBook() {
+    $this->assertXPath($this->_html,
+                       '//iframe[@src="http://www.edenlivres.fr/p/23416"][@width="100%"][@height="600px"]',
+                       $this->_html);
+  }
+
+
+  /** @test */
+  public function htmlShouldContainsNotAuthorizedMessage() {
+    $this->assertXPathContentContains($this->_html, '//div', 'Vous n\'avez pas le droit');
+  }
+}
+
+
+
+
+class PnbDilicomViewHelperRenderAlbumGetLoanStatusTest
+  extends PnbDilicomViewHelperRenderAlbumTestCase {
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture('Class_Bib', ['id' => 1,
+                                 'libelle' => 'Annecy',
+                                 'gln' => '333']);
+
+    $group =$this->fixture('Class_UserGroup',
+                           ['id' => '20',
+                            'libelle' => 'Multimedia',
+                            'rights' => [Class_UserGroup::RIGHT_ACCES_PNB_DILICOM]]);
+
+    $this->logged_user = $this->fixture('Class_Users',
+                                        ['id' => 6,
+                                         'nom'=>'Pito',
+                                         'login'=>'Chat',
+                                         'password'=>'123456',
+                                         'id_site' => 1,
+                                         'idabon' => '12345',
+                                         'user_groups' => [$group]]);
+
+    $this->logged_user->beAbonneSIGB()->assertSave();
+    ZendAfi_Auth::getInstance()->logUser($this->logged_user);
+
+
+    $this->other_user = $this->fixture('Class_Users',
+                                        ['id' => 7,
+                                         'nom'=>'Boum',
+                                         'login'=>'Baia',
+                                         'password'=>'9876',
+                                         'id_site' => 1,
+                                         'idabon' => '9876',
+                                         'user_groups' => [$group]]);
+
+    $this->other_user->beAbonneSIGB()->assertSave();
+  }
+
+
+  /** @test */
+  public function htmlShouldContainsRessourceNotAvailable() {
+    Class_Album_UsageConstraint::find(2)->setOrderDate('1900-05-02 14:14:14')->assertSave();
+    $this->_html = $this->_helper->renderAlbum($this->book);
+
+    $this->assertXPathContentContains($this->_html,
+                                      '//div//span[@class="error"]',
+                                      'La ressource n\'est plus disponible.');
+  }
+
+
+  /** @test */
+  public function htmlShouldContainsQuotaEmpty() {
+    $this->_http
+      ->whenCalled('open_url')
+      ->answers('');
+
+    Class_AdminVar::set('DILICOM_PNB_MAX_LOAN_PER_USER', 3);
+
+    foreach(range(1, 3) as $step)
+      $this->fixture('Class_Loan_Pnb',
+                     ['id' => $step,
+                      'user_id' => $this->logged_user->getId(),
+                      'record_origin_id' => $step,
+                      'expected_return_date' => '2022-06-01']);
+
+    $this->_html = $this->_helper->renderAlbum($this->book);
+
+    $this->assertXPathContentContains($this->_html,
+                                      '//div//span[@class="error"]',
+                                      'Emprunt impossible. Vous avez atteint votre quota de 3 emprunts');
+  }
+
+
+  /** @test */
+  public function withLoanCountTreeAndLoanCountLimitReachedHtmlShouldContainsNextAvailableLoanDate() {
+    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(5)->assertSave();
+    $this->_http
+      ->whenCalled('open_url')
+      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(2, 24));
+    // ^ so current loan count = (5 max users - 2 loans available) = 3
+
+    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT', 1);
+    $this->fixture('Class_Loan_Pnb',
+                   ['id' => 1,
+                    'user_id' => $this->other_user->getId(),
+                    'record_origin_id' => 'Dilicom-88817216',
+                    'order_line_id' => 'x321',
+                    'expected_return_date' => '2022-06-01 20:10:00']);
+
+    $this->assertXPathContentContains($this->_helper->renderAlbum($this->book),
+                                      '//div//span[@class="error"]',
+                                      utf8_encode('Emprunt impossible. Le nombre d\'emprunts simultanés pour ce document est atteint. Le prochain emprunt sera possible le mercredi 01 juin à 20h10'));
+  }
+
+
+  /** @test */
+  public function withLoanCountOneAndOneActiveHoldsShouldContainsDocumentAlreadyHeld() {
+    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(5)->assertSave();
+    $this->_http
+      ->whenCalled('open_url')
+      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(3, 24));
+    // ^ current loan count = (5 max users - 3 loans available) = 2
+
+    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT', 3);
+
+    $this->fixture('Class_Hold_Pnb',
+                   ['id' => 1,
+                    'user_id' => 876,
+                    'record_origin_id' => $this->book->getIdOrigine(),
+                    'hold_date' => '2014-04-25 14:14:14']);
+
+    $this->assertXPathContentContains($this->_helper->renderAlbum($this->book),
+                                      '//div//span[@class="error"]',
+                                      utf8_encode('Emprunt impossible. Ce document est déjà réservé'));
+  }
+
+
+  /** @test */
+  public function withLoanCountOneAndOneActiveHoldForCurrentUserShouldContainsLoanButton() {
+    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(5)->assertSave();
+    $this->_http
+      ->whenCalled('open_url')
+      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(3, 24));
+    // ^ current loan count = (5 max users - 3 loans available) = 2
+
+    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT', 3);
+
+    $this->fixture('Class_Hold_Pnb',
+                   ['id' => 1,
+                    'user_id' => Class_Users::getIdentity()->getId(),
+                    'record_origin_id' => $this->book->getIdOrigine(),
+                    'hold_date' => '2014-04-25 14:14:14']);
+
+    $this->assertXPathContentContains($this->_helper->renderAlbum($this->book),
+                                      '//div//a',
+                                      utf8_encode('Emprunter le livre au format EPUB'));
+  }
+
+
+
+  /** @test */
+  public function withLoanCountOneAndOneExpiredHoldsShouldContainsLoanButton() {
+    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(5)->assertSave();
+    $this->_http
+      ->whenCalled('open_url')
+      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(3, 24));
+    // ^ current loan count = (5 max users - 3 loans available) = 2
+
+    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT', 3);
+
+    $this->fixture('Class_Hold_Pnb',
+                   ['id' => 1,
+                    'user_id' => 876,
+                    'record_origin_id' => $this->book->getIdOrigine(),
+                    'hold_date' => '2014-04-25 14:14:14',
+                    'expiration_date' => '2014-04-26 14:14:14']);
+
+    $this->assertXPathContentContains($this->_helper->renderAlbum($this->book),
+                                      '//div//a',
+                                      utf8_encode('Emprunter le livre au format EPUB'));
+  }
+
+
+  /** @test */
+  public function withoutLoanAndThreeActiveHoldsAndAllocatedHolderShouldContainsLoanButton() {
+    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(1)->assertSave();
+    $this->_http
+      ->whenCalled('open_url')
+      ->answers(DilicomFixtures::getLoanStatusResponseAvailableUsersAndQuantityLeft(1, 1));
+
+    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT', 3);
+
+    $this->fixture('Class_Hold_Pnb',
+                   ['id' => 1,
+                    'user_id' => Class_Users::getIdentity()->getId(),
+                    'record_origin_id' => $this->book->getIdOrigine(),
+                    'hold_date' => '2014-04-25 14:14:14',
+                    'expiration_date' => '2014-05-05 23:59:59']);
+
+    $this->fixture('Class_Hold_Pnb',
+                   ['id' => 2,
+                    'user_id' => Class_Users::getIdentity()->getId() + 1,
+                    'record_origin_id' => $this->book->getIdOrigine(),
+                    'hold_date' => '2014-04-25 14:15:14']);
+
+    $this->fixture('Class_Hold_Pnb',
+                   ['id' => 3,
+                    'user_id' => Class_Users::getIdentity()->getId() + 2,
+                    'record_origin_id' => $this->book->getIdOrigine(),
+                    'hold_date' => '2014-04-25 14:16:14']);
+
+    $this->assertXPathContentContains($this->_helper->renderAlbum($this->book),
+                                      '//div//a',
+                                      utf8_encode('Emprunter le livre au format EPUB'));
+  }
+
+
+  /** @test */
+  public function withSimultaneousLoanLimitReachedButCurrentlyLoanedByCurrentUserHtmlShouldContainsButtonToLoadAgain() {
+    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(0)->assertSave();
+    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT',0);
+    $this->fixture('Class_Loan_Pnb',
+                   ['id' => 1,
+                    'user_id' => $this->logged_user->getId(),
+                    'record_origin_id' => 'Dilicom-88817216',
+                    'order_line_id' => 'x321',
+                    'expected_return_date' => '2025-06-01 20:10:00',
+                   'loan_link' => 'https://pnb-dilicom.centprod.com/v3//link/xxx.do']);
+
+    $this->_html = $this->_helper->renderAlbum($this->book);
+
+    $this->assertXPath($this->_html,
+                       '//a[contains(@href, "/bib-numerique/loan-book-ajax/id/3")]',
+                       $this->_html);
+  }
+
+
+  /** @test */
+  public function onUnknownReturnDateHtmlShouldNotContainsNextAvailableLoanDate() {
+    Class_Album_UsageConstraint::find(1)->setMaxNumberOfUsers(0)->assertSave();
+    Class_AdminVar::set('DILICOM_PNB_LOAN_COUNT_LIMIT',0);
+    $this->fixture('Class_Loan_Pnb',
+                   ['id' => 1,
+                    'user_id' => $this->logged_user->getId(),
+                    'record_origin_id' => 1,
+                    'order_line_id' => '???',
+                    'expected_return_date' => '2022-06-01 20:10:00']);
+
+    $this->_html = $this->_helper->renderAlbum($this->book);
+
+    $this->assertNotXPathContentContains($this->_html,
+                                         '//div//span[@class="error"]',
+                                         utf8_encode('Le prochain emprunt sera possible'));
+  }
+
+
+  /**
+   * @test
+   * @see http://forge.afi-sa.fr/issues/109494
+   */
+  public function withLoanStatusCancelledQuantityShouldNotBeUpdated() {
+    $item = Class_Album_Item::find(1);
+    $item
+      ->setLoanCount(0)
+      ->setQuantity(0)
+      ->assertSave();
+
+    $this->_http
+      ->whenCalled('open_url')
+      ->answers(DilicomFixtures::getLoanStatusCancelledResponse('x321'));
+
+    $this->_helper->renderAlbum($this->book);
+
+    $this->assertEquals(0, $item->getQuantity());
+    return $item;
+  }
+
+
+  /**
+   * @test
+   * @depends withLoanStatusCancelledQuantityShouldNotBeUpdated
+   */
+  public function withLoanStatusCancelledLoanCountShouldNotBeUpdated($item) {
+    $this->assertEquals(0, $item->getLoanCount());
+  }
+}