diff --git a/VERSIONS_WIP/114208 b/VERSIONS_WIP/114208
new file mode 100644
index 0000000000000000000000000000000000000000..c3d27f5141d0ca1a1529c6df7c4a95c84d72f750
--- /dev/null
+++ b/VERSIONS_WIP/114208
@@ -0,0 +1 @@
+ - ticket #114208 : Recherche : il est maintenant possible d'accéder à une notice directement en passant en paramètre son identifiant SIGB
\ No newline at end of file
diff --git a/application/modules/opac/controllers/RechercheController.php b/application/modules/opac/controllers/RechercheController.php
index 14ecda3f45331795048f30faf98db194a5e3f18e..82bb9114f85624a2bd1eb149839f566ca0024336 100644
--- a/application/modules/opac/controllers/RechercheController.php
+++ b/application/modules/opac/controllers/RechercheController.php
@@ -322,46 +322,18 @@ class RechercheController extends ZendAfi_Controller_Action {
   }
 
 
-  protected function _isViewNoticeRequestFromSIGB() {
-    return $this->_getParam('id_sigb') || $this->_getParam('id_site');
-  }
-
-
-  protected function _handleViewNoticeRequestFromSIGB() {
-    if (!$id_sigb = $this->_getParam('id_sigb'))
-      return $this->_badRequestError($this->_('Paramètre id_sigb obligatoire'));
-
-    if (!$id_site = $this->_getParam('id_site'))
-      return $this->_badRequestError($this->_('Paramètre id_site obligatoire'));
-
-    if (!$annex = Class_CodifAnnexe::findFirstBy(['id_origine' => $id_site]))
-      return $this->_recordDoesNotExistsError();
-
-    if (!$item = Class_Exemplaire::findFirstBy(['id_origine' => $id_sigb,
-                                                'id_bib' => $annex->getIdBib()]))
-      return $this->_recordDoesNotExistsError();
-
-    return $this->_redirect('/recherche/viewnotice/id/' . $item->getIdNotice());
-  }
-
-
-  protected function _badRequestError($message) {
-    throw new Zend_Controller_Action_Exception($message, 400);
-  }
-
-
-  protected function _recordDoesNotExistsError() {
-    throw new Zend_Controller_Action_Exception($this->view->_('Désolé, aucun document ne correspond aux critères transmis'),
-                                               404);
-  }
-
-
   public function viewnoticeAction() {
     if ($authority_record = $this->_authorityFromParams())
       return $this->_redirect('/opac/recherche/viewnotice/id/' . $authority_record->getId());
 
-    if ($this->_isViewNoticeRequestFromSIGB())
-      return $this->_handleViewNoticeRequestFromSIGB();
+
+    $record_request = Class_MoteurRecherche_RecordRequest::newFor($this->_getParam('id_sigb'),
+                                                                  $this->_getParam('id_site'));
+
+    if ($record_id = $record_request->recordId())
+      return $this->_redirect('/recherche/viewnotice/id/' . $record_id);
+
+    $record_request->doNotFound();
 
     $id_notice = (int)$this->_getParam('id');
     $clef_alpha = (string)$this->_getParam('clef');
diff --git a/library/Class/MoteurRecherche/RecordRequest.php b/library/Class/MoteurRecherche/RecordRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c5cfb4baa31906268576d3cdb8181bc7e4aaa68e
--- /dev/null
+++ b/library/Class/MoteurRecherche/RecordRequest.php
@@ -0,0 +1,120 @@
+<?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
+ */
+
+
+abstract class Class_MoteurRecherche_RecordRequest {
+  use Trait_Translator;
+
+  const ALL_SITES = '*';
+
+  protected
+    $_id,
+    $_id_sigb,
+    $_success_callback,
+    $_id_site;
+
+  public static function newFor($id_sigb, $id_site) {
+    if (!$id_sigb && !$id_site)
+      return new Class_MoteurRecherche_NullRecordRequest();
+
+    $t = new Class_Translator;
+    if (!$id_sigb)
+      return new Class_MoteurRecherche_MissingParamRecordRequest($t->_('Paramètre id_sigb obligatoire'));
+
+    if (!$id_site)
+      return new Class_MoteurRecherche_MissingParamRecordRequest($t->_('Paramètre id_site obligatoire'));
+
+    if (!$item = static::_findItem($id_sigb, $id_site))
+      return new Class_MoteurRecherche_UnknownRecordRequest();
+
+    return new Class_MoteurRecherche_FoundRecordRequest($item->getIdNotice());
+  }
+
+
+  protected static function _findItem($id_sigb, $id_site) {
+    if (static::ALL_SITES === $id_site)
+      return Class_Exemplaire::findFirstBy(['id_origine' => $id_sigb]);
+
+    return ($annex = Class_CodifAnnexe::findFirstBy(['id_origine' => $id_site]))
+      ? Class_Exemplaire::findFirstBy(['id_origine' => $id_sigb,
+                                       'id_bib' => $annex->getIdBib()])
+      : null;
+  }
+
+
+  protected function _badRequestError($message) {
+    throw new Zend_Controller_Action_Exception($message, 400);
+  }
+
+
+  protected function _recordDoesNotExistsError() {
+    throw new Zend_Controller_Action_Exception($this->_('Désolé, aucun document ne correspond aux critères transmis'),
+                                               404);
+  }
+
+
+  public function doNotFound() {}
+
+
+  public function recordId() {
+    return $this->_id;
+  }
+}
+
+
+
+
+class Class_MoteurRecherche_NullRecordRequest extends Class_MoteurRecherche_RecordRequest {
+}
+
+
+
+
+class Class_MoteurRecherche_MissingParamRecordRequest extends Class_MoteurRecherche_RecordRequest {
+  protected $_message;
+
+  public function __construct($message) {
+    $this->_message = $message;
+  }
+
+
+  public function doNotFound() {
+    $this->_badRequestError($this->_message);
+  }
+}
+
+
+
+
+class Class_MoteurRecherche_UnknownRecordRequest extends Class_MoteurRecherche_RecordRequest {
+  public function doNotFound() {
+    $this->_recordDoesNotExistsError();
+  }
+}
+
+
+
+
+class Class_MoteurRecherche_FoundRecordRequest extends Class_MoteurRecherche_RecordRequest {
+  public function __construct($id) {
+    $this->_id = $id;
+  }
+}
diff --git a/tests/application/modules/opac/controllers/RechercheControllerTest.php b/tests/application/modules/opac/controllers/RechercheControllerTest.php
index d491352260840890dabab772beeb4238792a092c..4fd767efbf689f8f6c8a8fbd7069c7987cfbfb35 100644
--- a/tests/application/modules/opac/controllers/RechercheControllerTest.php
+++ b/tests/application/modules/opac/controllers/RechercheControllerTest.php
@@ -692,29 +692,48 @@ class RechercheControllerViewNoticeByIdSigbTest extends RechercheControllerNotic
 
 
   /** @test */
+  public function withIdSigbAndIdSiteWildcardShouldRedirectToViewNoticeId345() {
+    $this->dispatch('/recherche/viewnotice/id_sigb/12/id_site/*');
+    $this->assertRedirectTo('/recherche/viewnotice/id/345');
+  }
+
+
+  /**
+   * @test
+   * @expectedException Zend_Controller_Action_Exception
+   */
   public function withUnknownIdSiteShouldThrow404() {
-    $this->dispatch('/recherche/viewnotice/id_sigb/12/id_site/3', false);
+    $this->dispatch('/recherche/viewnotice/id_sigb/12/id_site/3');
     $this->assertResponseCode(404);
   }
 
 
-  /** @test */
+  /**
+   * @test
+   * @expectedException Zend_Controller_Action_Exception
+   */
   public function withUnknownIdSigbShouldThrow404() {
-    $this->dispatch('/recherche/viewnotice/id_sigb/66/id_site/2', false);
+    $this->dispatch('/recherche/viewnotice/id_sigb/66/id_site/2');
     $this->assertResponseCode(404);
   }
 
 
-  /** @test */
+  /**
+   * @test
+   * @expectedException Zend_Controller_Action_Exception
+   */
   public function withNoIdSigbShouldThrow400() {
-    $this->dispatch('/recherche/viewnotice/id_site/2', false);
+    $this->dispatch('/recherche/viewnotice/id_site/2');
     $this->assertResponseCode(400);
   }
 
 
-  /** @test */
+  /**
+   * @test
+   * @expectedException Zend_Controller_Action_Exception
+   */
   public function withNoIdSiteShouldThrow400() {
-    $this->dispatch('/recherche/viewnotice/id_sigb/12', false);
+    $this->dispatch('/recherche/viewnotice/id_sigb/12');
     $this->assertResponseCode(400);
   }
 }