diff --git a/VERSIONS_HOTLINE/33948 b/VERSIONS_HOTLINE/33948 new file mode 100644 index 0000000000000000000000000000000000000000..3c470515d72ee129fba857bdba46cd03e47ef480 --- /dev/null +++ b/VERSIONS_HOTLINE/33948 @@ -0,0 +1 @@ + - ticket #33948 : Koha/Pikoloco : Correction du calcul de la disponibilité des exemplaires \ No newline at end of file diff --git a/library/Class/WebService/SIGB/Koha/Exemplaire.php b/library/Class/WebService/SIGB/Koha/Exemplaire.php index d6b786db6e2ae4f0cfa400f8cbfd9fc5de31a0f2..dcac15af7a530d9e2eb7ab6d15c129f7358bc77e 100644 --- a/library/Class/WebService/SIGB/Koha/Exemplaire.php +++ b/library/Class/WebService/SIGB/Koha/Exemplaire.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_WebService_SIGB_Koha_Exemplaire extends Class_WebService_SIGB_Exemplaire { protected $_endommage = false; @@ -30,6 +30,7 @@ class Class_WebService_SIGB_Koha_Exemplaire extends Class_WebService_SIGB_Exempl public function setEndommage($flag) { $this->_endommage = (bool)$flag; $this->updateDisponibilite(); + return $this; } @@ -48,6 +49,7 @@ class Class_WebService_SIGB_Koha_Exemplaire extends Class_WebService_SIGB_Exempl public function setPerdu($flag) { $this->_perdu = (bool)$flag; $this->updateDisponibilite(); + return $this; } @@ -83,6 +85,7 @@ class Class_WebService_SIGB_Koha_Exemplaire extends Class_WebService_SIGB_Exempl public function setDateRetour($date_retour) { parent::setDateRetour($date_retour); $this->updateDisponibilite(); + return $this; } @@ -103,7 +106,7 @@ class Class_WebService_SIGB_Koha_Exemplaire extends Class_WebService_SIGB_Exempl */ public function updateDisponibilite() { if (!$this->isPiege() and ('' != $this->getDateRetour())) - $this->setDisponibiliteEnPret(); + $this->setDisponibiliteEnPret(); } diff --git a/library/Class/WebService/SIGB/Koha/GetRecordsResponseReader.php b/library/Class/WebService/SIGB/Koha/GetRecordsResponseReader.php index 19fcb6655ada9e9fe0b9e6151456c123afd9508a..34b15890816c22e008322fa20e1107a6d207f218 100644 --- a/library/Class/WebService/SIGB/Koha/GetRecordsResponseReader.php +++ b/library/Class/WebService/SIGB/Koha/GetRecordsResponseReader.php @@ -18,35 +18,36 @@ * along with BOKEH; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + class Class_WebService_SIGB_Koha_GetRecordsResponseReader { use Class_WebService_SIGB_Koha_TraitFormat; - protected $_xml_parser; - protected $_notice; - protected $inderdire_resa_doc_dispo=false; - protected $_reservations = []; - protected $_not_for_loan_status = array( - 0 => Class_WebService_SIGB_Exemplaire::DISPO_LIBRE, - 1 => "Exclu du prêt", - 2 => "En traitement", - 3 => "Consultation sur place", - 4 => "En réserve", - 5 => "En réparation", - 6 => "En reliure", - 7 => "Exclu du prêt temporairement"); - - /** - * @var Class_WebService_SIGB_Koha_Exemplaire - */ - protected $_current_exemplaire; + static protected $_default_reader; + + protected $_record, $_item, $_holds = []; + protected $_cannot_hold_available = false; + protected $_not_for_loan_status = [0 => Class_WebService_SIGB_Exemplaire::DISPO_LIBRE, + 1 => 'Exclu du prêt', + 2 => 'En traitement', + 3 => 'Consultation sur place', + 4 => 'En réserve', + 5 => 'En réparation', + 6 => 'En reliure', + 7 => 'Exclu du prêt temporairement']; public static function newInstance() { return new self(); } + /** @category testing */ + public static function setDefaultReader($reader) { + static::$_default_reader = $reader; + } + + public function setInterdireResaDocDispo($dispo) { - $this->interdire_resa_doc_dispo = $dispo; + $this->_cannot_hold_available = $dispo; return $this; } @@ -54,118 +55,190 @@ class Class_WebService_SIGB_Koha_GetRecordsResponseReader { public function setCodificationDisponibilites($codif) { foreach($codif as $status => $libelle) $this->_not_for_loan_status[$status] = $libelle; + return $this; } + public function allowAvailableDocumentReservation() { + return !$this->_cannot_hold_available; + } + + public function getNoticeFromXML($xml) { - $this->_xml_parser = Class_WebService_XMLParser::newInstance(); - $this->_notice = new Class_WebService_SIGB_Notice(0); - $this->_xml_parser - ->setElementHandler($this) - ->parse($xml); + $this->_record = new Class_WebService_SIGB_Notice(0); + if (false === ($doc = $this->_getReader()->read($xml))) + return $this->_record; + + if (!$record = $doc->record) + return $this->_record; + + if ($id = $record->biblioitemnumber) + $this->_record->setId((string)$id); - return $this->_notice; + foreach($record->reserves->reserve as $xml_hold) + $this->_handleHold($xml_hold); + + foreach($record->items->item as $xml_item) + $this->_handleItem($xml_item); + + return $this->_record; } - public function allowAvailableDocumentReservation() { - return !$this->interdire_resa_doc_dispo; + protected function _handleHold($xml_hold) { + if ($this->_hasChild('itemnumber', $xml_hold)) + $this->_holds[] = (string)$xml_hold->itemnumber; } - public function endBiblioItemNumber($data) { - if (!$this->_xml_parser->inParents('items')) - $this->_notice->setId($data); + protected function _handleItem($xml_item) { + $this->_item = new Class_WebService_SIGB_Koha_Exemplaire(null); + $this->_xml_item = $xml_item; + + $this + ->_handleItemWithdrawn() + ->_handleItemNotForLoan() + ->_handleItemNumber() + ->_handleItemDateDue() + ->_handleItemBarCode() + ->_handleItemLost() + ->_handleItemDamaged() + ; + + $this->_record->addExemplaire($this->_item); } - public function startItem($attributes) { - $this->_current_exemplaire = new Class_WebService_SIGB_Koha_Exemplaire(null); + protected function _handleItemBarCode() { + if ($this->_hasChild('barcode', $this->_xml_item)) + $this->_item->setCodeBarre((string)$this->_xml_item->barcode); + + return $this; } - public function endItem($data) { - $this->_notice->addExemplaire($this->_current_exemplaire); + protected function _handleItemDateDue() { + $date_due = ''; + if ($this->_hasChild('date_due', $this->_xml_item) + && $date_due = (string)$this->_xml_item->date_due) { + $date = $this->formatDate($date_due); + $this->_item + ->setDateRetour($date) + ->setDisponibiliteEnPret(); + } + + if ($date_due || $this->allowAvailableDocumentReservation()) + $this->_item->setReservable(true); + + return $this; } - public function endBarCode($data) { - if ($this->_xml_parser->inParents('item')) - $this->_current_exemplaire->setCodeBarre($data); + protected function _handleItemWithdrawn() { + // different koha versions compatibility + return $this + ->_handleWithdrawnNamed('withdrawn') + ->_handleWithdrawnNamed('wthdrawn'); } - public function endDate_Due($data) { - if (!$this->_xml_parser->inParents('item')) - return; + protected function _handleWithdrawnNamed($name) { + if (!$this->_hasChild($name, $this->_xml_item)) + return $this; - $date = $this->formatDate($data); - $this->_current_exemplaire->setDateRetour($date); + if ('0' != (string)$this->_xml_item->{$name}) + $this->_item + ->setRetire(true) + ->setDisponibilitePilonne(); - if (('' != $date) || ($this->allowAvailableDocumentReservation())) - $this->_current_exemplaire->setReservable(true); + return $this; } - public function endWthdrawn($data) { - if (!$this->_xml_parser->inParents('item')) - return; + protected function _handleItemLost() { + if ($this->_hasChild('itemlost', $this->_xml_item) + && '0' !== (string)$this->_xml_item->itemlost) + $this->_item + ->setPerdu(true) + ->setDisponibilitePerdu(); - if (0 != $data) { - $this->_current_exemplaire->setRetire(true); - $this->_current_exemplaire->setDisponibilitePilonne(); - } + return $this; } - public function endItemlost($data) { - if (!$this->_xml_parser->inParents('item')) - return; + protected function _handleItemDamaged() { + if ($this->_hasChild('damaged', $this->_xml_item) + && '0' !== (string)$this->_xml_item->damaged) + $this->_item->setEndommage(true); - if (0 != $data) { - $this->_current_exemplaire->setPerdu(true); - $this->_current_exemplaire->setDisponibilitePerdu(); - - } + return $this; } - public function endDamaged($data) { - if (!$this->_xml_parser->inParents('item')) - return; + protected function _handleItemNotForLoan() { + if (!$this->_hasChild('notforloan', $this->_xml_item)) + return $this; - if (0 != $data) - $this->_current_exemplaire->setEndommage(true); + $data = (string)$this->_xml_item->notforloan; + if (!array_key_exists($data, $this->_not_for_loan_status) + || $this->_item->isPiege()) + return $this; + + if (!in_array($data, ['0', '4'])) + $this->_item->notForLoan(); + + if ('' == $this->_item->getDateRetour()) + $this->_item->setDisponibilite($this->_not_for_loan_status[$data]); + + return $this; } - public function endNotForLoan($data) { - if (!$this->_xml_parser->inParents('item')) - return; + protected function _handleItemNumber() { + if (!$this->_hasChild('itemnumber', $this->_xml_item)) + return $this; - if (array_key_exists($data, $this->_not_for_loan_status) and !$this->_current_exemplaire->isPiege()) { - $this->_current_exemplaire->setDisponibilite($this->_not_for_loan_status[$data]); - if (!in_array($data, array('0', '4'))) - $this->_current_exemplaire->notForLoan(); + $data = (string)$this->_xml_item->itemnumber; + $this->_item->setId($data); + if ($this->_isHeld($data)) { + $this->_item + ->setDisponibiliteDejaReserve() + ->setReservable(true); } + + return $this; } - public function endItemNumber($data) { - if ($this->_xml_parser->inParents('reserve')) { - $this->_reservations[] = $data; - return; - } + protected function _isHeld($id) { + return in_array($id, $this->_holds); + } - if ($this->_xml_parser->inParents('item')) { - $this->_current_exemplaire->setId($data); - if (in_array($data, $this->_reservations)) { - $this->_current_exemplaire->setDisponibiliteDejaReserve(); - $this->_current_exemplaire->setReservable(true); - } - } + + protected function _getReader() { + return static::$_default_reader + ? static::$_default_reader + : new Class_WebService_SIGB_Koha_GetRecordsResponseReaderXmlReader(); + } + + + protected function _hasChild($name, $node) { + foreach($node->children() as $child) + if ($child->getName() == $name) + return true; + return false; } } -?> \ No newline at end of file + + +class Class_WebService_SIGB_Koha_GetRecordsResponseReaderXmlReader { + public function read($xml) { + libxml_use_internal_errors(true); + $document = simplexml_load_string($xml); + libxml_use_internal_errors(false); + + return $document; + } +} \ No newline at end of file diff --git a/library/Class/WebService/SIGB/Koha/Service.php b/library/Class/WebService/SIGB/Koha/Service.php index dc9a329a9d9f7b8311d20f9fb1412a349660121b..350b2a2e029d4059a423badbb42a80fcf8a1b78e 100644 --- a/library/Class/WebService/SIGB/Koha/Service.php +++ b/library/Class/WebService/SIGB/Koha/Service.php @@ -206,12 +206,17 @@ class Class_WebService_SIGB_Koha_Service extends Class_WebService_SIGB_AbstractR public function getNotice($id) { - return $this->ilsdiGetRecords($id, - Class_WebService_SIGB_Koha_GetRecordsResponseReader::newInstance() - ->setCodificationDisponibilites($this->codification_disponibilites) - ->setInterdireResaDocDispo($this->interdire_resa_doc_dispo)); + return $this->ilsdiGetRecords($id, $this->_getReader()); } + + protected function _getReader() { + return Class_WebService_SIGB_Koha_GetRecordsResponseReader::newInstance() + ->setCodificationDisponibilites($this->codification_disponibilites) + ->setInterdireResaDocDispo($this->interdire_resa_doc_dispo); + } + + public function test() { $validator = new ZendAfi_Validate_Url(); if (!$validator->isValid($this->getServerRoot())) @@ -225,19 +230,16 @@ class Class_WebService_SIGB_Koha_Service extends Class_WebService_SIGB_AbstractR $message .= $response->getStatus() . " " . $response->getMessage() . "\n\n" . $response->getBody(); return $message; - } catch (Exception $e) { + + } catch (Exception $e) { return $e->getMessage() . '\n' . $e->getTraceAsString(); } } - public function newBuySuggestForm() { return $this->providesSuggestions() ? new Class_WebService_SIGB_Koha_BuySuggestForm() : parent::newBuySuggestForm(); } - -} - -?> \ No newline at end of file +} \ No newline at end of file diff --git a/tests/library/Class/WebService/SIGB/KohaTest.php b/tests/library/Class/WebService/SIGB/KohaTest.php index ccf2bbb1cc8f4c31caa5f58d074dd2df7bf4d322..8f6ec4af38abb5ef6075dacd6c1b3966bcdac923 100644 --- a/tests/library/Class/WebService/SIGB/KohaTest.php +++ b/tests/library/Class/WebService/SIGB/KohaTest.php @@ -1025,3 +1025,27 @@ class KohaServicePatroninfoReaderWithNoLibTest extends KohaTestCase { $this->assertEmpty($this->laurent->getLibraryLabel()); } } + + +/** @see http://forge.afi-sa.fr/issues/33948 */ +class KohaServiceGetRecordPikolocoTest extends KohaTestCase { + protected $record; + + public function setUp() { + parent::setUp(); + + $this->mock_web_client + ->whenCalled('open_url') + ->with('http://cat-aficg55.biblibre.com/cgi-bin/koha/ilsdi.pl?service=GetRecords&id=7359') + ->answers(file_get_contents(__DIR__ . '/pikoloco_record_7359.txt')); + + $this->record = $this->service->getNotice(7359); + } + + + /** @test */ + public function itemShouldNotBeAvailable() { + $this->assertNotEquals('Disponible', + $this->record->exemplaireAt(0)->getDisponibilite()); + } +} \ No newline at end of file diff --git a/tests/library/Class/WebService/SIGB/pikoloco_record_7359.txt b/tests/library/Class/WebService/SIGB/pikoloco_record_7359.txt new file mode 100644 index 0000000000000000000000000000000000000000..85ac07a9603c1c1fe924d518b54250fd9fb522c8 --- /dev/null +++ b/tests/library/Class/WebService/SIGB/pikoloco_record_7359.txt @@ -0,0 +1,168 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<GetRecords> + <record> + <pages>527 p.</pages> + <cn_sort></cn_sort> + <itemtype>Texte impr</itemtype> + <issues> + <issue> + <author>Régine Deforges</author> + <itemnumber>7677</itemnumber> + <title>Alger, ville blanche</title> + <date_due>2015-09-01 23:59:00</date_due> + <auto_renew>0</auto_renew> + <barcode>RARE000336</barcode> + <cardnumber>RARE000023</cardnumber> + <issuedate>2015-08-11 16:37:00</issuedate> + <firstname>Denise</firstname> + <onsite_checkout>0</onsite_checkout> + <branchcode>RARECOURT</branchcode> + <surname>HAVETTE</surname> + <biblionumber>7359</biblionumber> + <borrowernumber>159</borrowernumber> + <timestamp>2015-08-11 16:37:04</timestamp> + </issue> + </issues> + <items> + <item> + <booksellerid>AUTRE</booksellerid> + <onloan>2015-09-01</onloan> + <cn_sort>R_DEF_A</cn_sort> + <issues>1</issues> + <barcode>RARE000336</barcode> + <holdingbranch>RARECOURT</holdingbranch> + <damaged>0</damaged> + <ccode>ROMANS</ccode> + <datelastseen>2015-08-11</datelastseen> + <itemlost>0</itemlost> + <biblioitemnumber>7359</biblioitemnumber> + <datelastborrowed>2015-08-11</datelastborrowed> + <itemnumber>7677</itemnumber> + <location>ADULTE</location> + <itype>LIV</itype> + <date_due>2015-09-01 23:59:00</date_due> + <holdingbranchname>Espace Culturel de Rarecourt</holdingbranchname> + <itemcallnumber>R DEF a</itemcallnumber> + <cardnumber>RARE000023</cardnumber> + <homebranchname>Espace Culturel de Rarecourt</homebranchname> + <itemnotes>La bicyclette bleue 8 - Saga familiale</itemnotes> + <withdrawn>0</withdrawn> + <biblionumber>7359</biblionumber> + <notforloan>0</notforloan> + <dateaccessioned>2014-12-18</dateaccessioned> + <timestamp>2015-08-11 16:37:04</timestamp> + <borrowernumber>159</borrowernumber> + <homebranch>RARECOURT</homebranch> + </item> + </items> + <publishercode>Éd. France loisirs</publishercode> + <biblioitemnumber>7359</biblioitemnumber> + <size>21 cm</size> + <volume>1959-1960</volume> + <reserves> + </reserves> + <isbn>2744151610</isbn> + <collectiontitle> La bicyclette bleue</collectiontitle> + <publicationyear>2002</publicationyear> + <marcxml><?xml version="1.0" encoding="UTF-8"?> +<record + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd" + xmlns="http://www.loc.gov/MARC21/slim"> + + <leader>00832cam a2200241 4500</leader> + <controlfield tag="001">7359</controlfield> + <datafield tag="010" ind1=" " ind2=" "> + <subfield code="a">2744151610</subfield> + <subfield code="b">rel.</subfield> + <subfield code="d">15,10 EUR</subfield> + </datafield> + <datafield tag="020" ind1=" " ind2=" "> + <subfield code="a">FR</subfield> + <subfield code="b">00227467</subfield> + </datafield> + <datafield tag="090" ind1=" " ind2=" "> + <subfield code="a">7359</subfield> + </datafield> + <datafield tag="100" ind1=" " ind2=" "> + <subfield code="a">20020809d2002 m y0frey50 ba</subfield> + </datafield> + <datafield tag="101" ind1="0" ind2=" "> + <subfield code="a">fre</subfield> + </datafield> + <datafield tag="102" ind1=" " ind2=" "> + <subfield code="a">FR</subfield> + </datafield> + <datafield tag="105" ind1=" " ind2=" "> + <subfield code="a"> z 00 a </subfield> + </datafield> + <datafield tag="106" ind1=" " ind2=" "> + <subfield code="a">r</subfield> + </datafield> + <datafield tag="200" ind1="1" ind2=" "> + <subfield code="a">Alger, ville blanche</subfield> + <subfield code="b">Texte imprimé</subfield> + <subfield code="e">1959-1960</subfield> + <subfield code="f">Régine Deforges</subfield> + </datafield> + <datafield tag="210" ind1=" " ind2=" "> + <subfield code="a">Paris</subfield> + <subfield code="c">Éd. France loisirs</subfield> + <subfield code="d">2002</subfield> + <subfield code="e">86-Ligugé</subfield> + <subfield code="e">Impr. Aubin</subfield> + </datafield> + <datafield tag="215" ind1=" " ind2=" "> + <subfield code="a">527 p.</subfield> + <subfield code="c">jaquette ill. en coul.</subfield> + <subfield code="d">21 cm</subfield> + </datafield> + <datafield tag="225" ind1="1" ind2="9"> + <subfield code="a"> La bicyclette bleue</subfield> + </datafield> + <datafield tag="300" ind1=" " ind2=" "> + <subfield code="a">En appendice, entretien avec Régine Deforges</subfield> + </datafield> + <datafield tag="461" ind1=" " ind2="0"> + <subfield code="0">34308953</subfield> + <subfield code="t"> La Bicyclette bleue</subfield> + </datafield> + <datafield tag="686" ind1=" " ind2=" "> + <subfield code="2">Cadre de classement de la Bibliographie nationale française</subfield> + </datafield> + <datafield tag="700" ind1=" " ind2=" "> + <subfield code="3">11899083</subfield> + <subfield code="a">Deforges</subfield> + <subfield code="b">Régine</subfield> + <subfield code="f">1935-2014</subfield> + <subfield code="4">070</subfield> + </datafield> + <datafield tag="801" ind1=" " ind2="0"> + <subfield code="a">FR</subfield> + <subfield code="b">FR-751131015</subfield> + <subfield code="c">20020809</subfield> + <subfield code="g">AFNOR</subfield> + <subfield code="2">intermrc</subfield> + </datafield> + <datafield tag="995" ind1=" " ind2=" "> + <subfield code="2">0</subfield> + <subfield code="3">0</subfield> + <subfield code="9">7677</subfield> + <subfield code="a">AUTRE</subfield> + <subfield code="b">RARECOURT</subfield> + <subfield code="c">RARECOURT</subfield> + <subfield code="e">ADULTE</subfield> + <subfield code="f">RARE000336</subfield> + <subfield code="h">ROMANS</subfield> + <subfield code="k">R DEF a</subfield> + <subfield code="n">2015-09-01</subfield> + <subfield code="o">0</subfield> + <subfield code="r">LIV</subfield> + <subfield code="u">La bicyclette bleue 8 - Saga familiale</subfield> + </datafield> +</record> +</marcxml> + <biblionumber>7359</biblionumber> + <timestamp>2014-12-18 16:34:57</timestamp> + </record> +</GetRecords>