diff --git a/module/finc/config/module.config.php b/module/finc/config/module.config.php index 80cd4926de58e8bc18b75a4794107085dcab48a4..178586187b7814c13843e7e407c1d345348c345a 100644 --- a/module/finc/config/module.config.php +++ b/module/finc/config/module.config.php @@ -17,6 +17,7 @@ $config = [ 'ils_driver' => [ 'factories' => [ 'fincils' => 'finc\ILS\Driver\Factory::getFincILS', + 'daia' => 'finc\ILS\Driver\Factory::getDAIA', 'paia' => 'finc\ILS\Driver\Factory::getPAIA', ], ], diff --git a/module/finc/src/finc/ILS/Driver/DAIA.php b/module/finc/src/finc/ILS/Driver/DAIA.php new file mode 100644 index 0000000000000000000000000000000000000000..30bf450ded0b0490c72ff382db211ba89f43ad6b --- /dev/null +++ b/module/finc/src/finc/ILS/Driver/DAIA.php @@ -0,0 +1,283 @@ +<?php +/** + * ILS Driver for VuFind to query availability information via DAIA. + * + * Based on the proof-of-concept-driver by Till Kinstler, GBV. + * Relaunch of the daia driver developed by Oliver Goldschmidt. + * + * PHP version 5 + * + * Copyright (C) Jochen Lienhard 2014. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package ILS_Drivers + * @author Jochen Lienhard <lienhard@ub.uni-freiburg.de> + * @author Oliver Goldschmidt <o.goldschmidt@tu-harburg.de> + * @author André Lahmann <lahmann@ub.uni-leipzig.de> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/vufind2:building_an_ils_driver Wiki + */ +namespace finc\ILS\Driver; + +/** + * ILS Driver for VuFind to query availability information via DAIA. + * + * @category VuFind2 + * @package ILS_Drivers + * @author Jochen Lienhard <lienhard@ub.uni-freiburg.de> + * @author Oliver Goldschmidt <o.goldschmidt@tu-harburg.de> + * @author André Lahmann <lahmann@ub.uni-leipzig.de> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/vufind2:building_an_ils_driver Wiki + */ +class DAIA extends \VuFind\ILS\Driver\DAIA +{ + + /** + * Parse an array with DAIA status information. + * + * @param string $id Record id for the DAIA array. + * @param array $daiaArray Array with raw DAIA status information. + * + * @return array Array with VuFind compatible status information. + */ + protected function parseDaiaArray($id, $daiaArray) + { + $doc_id = null; + $doc_href = null; + if (array_key_exists('id', $daiaArray)) { + $doc_id = $daiaArray['id']; + } + if (array_key_exists('href', $daiaArray)) { + // url of the document (not needed for VuFind) + $doc_href = $daiaArray['href']; + } + if (array_key_exists('message', $daiaArray)) { + // log messages for debugging + $this->logMessages($daiaArray['message'], 'document'); + } + // if one or more items exist, iterate and build result-item + if (array_key_exists('item', $daiaArray)) { + $number = 0; + foreach ($daiaArray['item'] as $item) { + $result_item = []; + $result_item['id'] = $id; + $result_item['item_id'] = $item['id']; + // custom DAIA field used in getHoldLink() + $result_item['ilslink'] + = (isset($item['href']) ? $item['href'] : $doc_href); + // count items + $number++; + $result_item['number'] = $this->getItemNumber($item, $number); + // set default value for barcode + $result_item['barcode'] = $this->getItemBarcode($item); + // set default value for reserve + $result_item['reserve'] = $this->getItemReserveStatus($item); + // get callnumber + $result_item['callnumber'] = $this->getItemCallnumber($item); + // get location + $result_item['location'] = $this->getItemLocation($item); + // get location link + $result_item['locationhref'] = $this->getItemLocationLink($item); + // get location + $result_item['storage'] = $this->getItemStorage($item); + // status and availability will be calculated in own function + $result_item = $this->getItemStatus($item) + $result_item; + // add result_item to the result array + $result[] = $result_item; + } // end iteration on item + } + + return $result; + } + + /** + * Returns an array with status information for provided item. + * + * @param array $item Array with DAIA item data + * + * @return array + */ + protected function getItemStatus($item) + { + $availability = false; + $status = ''; // status cannot be null as this will crash the translator + $duedate = null; + $availableLink = ''; + $queue = ''; + $notes = []; + if (array_key_exists('available', $item)) { + // check if item is loanable or presentation + foreach ($item['available'] as $available) { + // attribute service can be set once or not + if (isset($available['service']) + && in_array( + $available['service'], + ['loan', 'presentation', 'openaccess'] + ) + ) { + // set item available if service is loan, presentation or + // openaccess + $availability = true; + if ($available['service'] == 'loan' + && isset($available['service']['href']) + ) { + // save the link to the ils if we have a href for loan + // service + $availableLink = $available['service']['href']; + } + } + + // use limitation element for status string + if (isset($available['limitation'])) { + $notes = array_merge($notes, $this->getItemLimitation($available['limitation'])); + } + + // log messages for debugging + if (isset($available['message'])) { + $this->logMessages($available['message'], 'item->available'); + } + } + } + if (array_key_exists('unavailable', $item)) { + foreach ($item['unavailable'] as $unavailable) { + // attribute service can be set once or not + if (isset($unavailable['service']) + && in_array( + $unavailable['service'], + ['loan', 'presentation', 'openaccess'] + ) + ) { + if ($unavailable['service'] == 'loan' + && isset($unavailable['service']['href']) + ) { + //save the link to the ils if we have a href for loan service + } + + // use limitation element for status string + if (isset($unavailable['limitation'])) { + $notes = array_merge($notes, $this + ->getItemLimitation($unavailable['limitation'])); + } + } + // attribute expected is mandatory for unavailable element + if (isset($unavailable['expected'])) { + try { + $duedate = $this->dateConverter + ->convertToDisplayDate( + 'Y-m-d', $unavailable['expected'] + ); + } catch (\Exception $e) { + $this->debug('Date conversion failed: ' . $e->getMessage()); + $duedate = null; + } + } + + // attribute queue can be set + if (isset($unavailable['queue'])) { + $queue = $unavailable['queue']; + } + + // log messages for debugging + if (isset($unavailable['message'])) { + $this->logMessages($unavailable['message'], 'item->unavailable'); + } + } + } + + /*'availability' => '0', + 'status' => '', // string - needs to be computed from availability info + 'duedate' => '', // if checked_out else null + 'returnDate' => '', // false if not recently returned(?) + 'requests_placed' => '', // total number of placed holds + 'is_holdable' => false, // place holding possible?*/ + + if (!empty($availableLink)) { + $return['ilslink'] = $availableLink; + } + + $return['notes'] = $notes; + $return['status'] = $status; + $return['availability'] = $availability; + $return['duedate'] = $duedate; + $return['requests_placed'] = $queue; + + return $return; + } + + /** + * Returns the evaluated value of the provided limitation element + * + * @param array $limitations Array with DAIA limitation data + * + * @return array + */ + protected function getItemLimitation($limitations) + { + $itemLimitation = []; + foreach ($limitations as $limitation) { + // return the first limitation with content set + if (isset($limitation['content'])) { + $itemLimitation[] = $limitation['content']; + } + } + return $itemLimitation; + } + + /** + * Returns the value for "location" in VuFind getStatus/getHolding array + * + * @param array $item Array with DAIA item data + * + * @return string + */ + protected function getItemLocation($item) + { + $location = ''; + + if (isset($item['department']) + && isset($item['department']['content']) + ) { + $location .= (empty($location) + ? $item['department']['content'] + : ' - ' . $item['department']['content']); + } + + return (empty($location) ? 'Unknown' : $location); + } + + /** + * Returns the value for "location" in VuFind getStatus/getHolding array + * + * @param array $item Array with DAIA item data + * + * @return string + */ + protected function getItemStorage($item) + { + $storage = ''; + + if (isset($item['storage']) + && isset($item['storage']['content']) + ) { + $storage .= (empty($storage) + ? $item['storage']['content'] + : ' - ' . $item['storage']['content']); + } + + return (empty($storage) ? 'Unknown' : $storage); + } +} diff --git a/module/finc/src/finc/ILS/Driver/PAIA.php b/module/finc/src/finc/ILS/Driver/PAIA.php index 2cde98d7e2a29a7689d3c9027f2ca264060a3017..6d004994eabe1895f6ea1400d371795f3f8a7202 100644 --- a/module/finc/src/finc/ILS/Driver/PAIA.php +++ b/module/finc/src/finc/ILS/Driver/PAIA.php @@ -51,7 +51,7 @@ use VuFind\Exception\ILS as ILSException, * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link http://vufind.org/wiki/building_an_ils_driver Wiki */ -class PAIA extends \VuFind\ILS\Driver\DAIA implements +class PAIA extends DAIA implements HttpServiceAwareInterface, LoggerAwareInterface { use \VuFindHttp\HttpServiceAwareTrait; diff --git a/themes/finc/scss/default.scss b/themes/finc/scss/default.scss index 56772ee60a7f74d2b6ec2aeeb5aba6edfcfde3c8..0663ae5984f31a7b84cbea7e578e393c307d0754 100644 --- a/themes/finc/scss/default.scss +++ b/themes/finc/scss/default.scss @@ -45,10 +45,33 @@ } // RECORD VIEW +// TABS +// Table width +.tabs-content table { + width:100%; +} +// Holdings +// Insert line break before Vormerken buttons +#holdings-tab { + line-height: 1.75rem; + td { + vertical-align: top; + } + td span:after { + content: "\a "; + white-space: pre; + } + // remove excessive bottom margins above order buttons + ul {margin-bottom: 0} + .button { + margin-top: .5rem; + } +} // Internformat .pace-car th {min-width: 10%} -// Footer + +// FOOTER .powered-by { img { height: 1.75em; diff --git a/themes/finc/templates/RecordTab/holdingsils.phtml b/themes/finc/templates/RecordTab/holdingsils.phtml new file mode 100644 index 0000000000000000000000000000000000000000..f2356f96c319a5766ce3ba1d26d6b2dc864e778b --- /dev/null +++ b/themes/finc/templates/RecordTab/holdingsils.phtml @@ -0,0 +1,168 @@ +<!-- recordTab - HOLDINGSILS.phtml --> +<? + // Set up convenience variables: + $account = $this->auth()->getManager(); + $user = $account->isLoggedIn(); + $holdings = $this->driver->getRealTimeHoldings(); + $openUrl = $this->openUrl($this->driver, 'holdings'); + $openUrlActive = $openUrl->isActive(); + // Account for replace_other_urls setting + $urls = $this->record($this->driver)->getLinkDetails($openUrlActive); + $offlineMode = $this->ils()->getOfflineMode(); + // Set page title. + $this->headTitle($this->translate('Holdings') . ': ' . $this->driver->getBreadcrumb()); +?> + +<?=$this->context($this)->renderInContext('librarycards/selectcard.phtml', array('user' => $this->auth()->isLoggedIn())); ?> + +<? if ($offlineMode == "ils-offline"): ?> + <div data-alert class="alert-box warning" tabindex="0" aria-live="assertive" role="dialogalert"> + <h2><?=$this->transEsc('ils_offline_title')?></h2> + <p><strong><?=$this->transEsc('ils_offline_status')?></strong></p> + <p><?=$this->transEsc('ils_offline_holdings_message')?></p> + <? $supportEmail = $this->escapeHtmlAttr($this->systemEmail()); ?> + <p><a href="mailto:<?=$supportEmail?>"><?=$supportEmail?></a></p> + </div> +<? endif; ?> +<? if (($this->ils()->getHoldsMode() == 'driver' && !empty($holdings)) || $this->ils()->getTitleHoldsMode() == 'driver'): ?> + <? if ($account->loginEnabled() && $offlineMode != 'ils-offline'): ?> + <? if (!$user): ?> + <div data-alert class="alert-box info" tabindex="0" aria-live="assertive" role="dialogalert"> + <a href="<?=$this->recordLink()->getTabUrl($this->driver, 'Holdings')?>?login=true&catalogLogin=true"><?=$this->transEsc("Login")?></a> <?=$this->transEsc("hold_login")?> + </div> + <? elseif (!$user->cat_username): ?> + <div data-alert class="alert-box info" tabindex="0" aria-live="assertive" role="dialogalert"> + <?=$this->translate("hold_profile_html", array('%%url%%' => $this->recordLink()->getTabUrl($this->driver, 'Holdings') . '?catalogLogin=true'))?> + </div> + <? endif; ?> + <? endif; ?> +<? endif; ?> +<? $holdingTitleHold = $this->driver->tryMethod('getRealTimeTitleHold'); if (!empty($holdingTitleHold)): ?> + <a class="placehold modal-link button small" title="<?=$this->transEsc('request_place_text')?>" href="<?=$this->recordLink()->getRequestUrl($holdingTitleHold)?>"><i class="fa fa-flag"></i> <?=$this->transEsc('title_hold_place')?></a> +<? endif; ?> +<? if (!empty($urls) || $openUrlActive): ?> + <h3><?=$this->transEsc("Internet")?></h3> + <? if (!empty($urls)): ?> + <? foreach ($urls as $current): ?> + <a href="<?=$this->escapeHtmlAttr($this->proxyUrl($current['url']))?>"><?=$this->escapeHtml($current['desc'])?></a><br/> + <? endforeach; ?> + <? endif; ?> + <? if ($openUrlActive): ?><?=$openUrl->renderTemplate()?><? endif; ?> +<? endif; ?> +<? foreach ($holdings as $holding): ?> + <h3> + <? $locationText = $this->transEsc('location_' . $holding['location'], array(), $holding['location']); ?> + <? if (isset($holding['locationhref']) && $holding['locationhref']): ?> + <a href="<?=$holding['locationhref']?>" target="_blank"><?=$locationText?></a> + <? else: ?> + <?=$locationText?> + <? endif; ?> + </h3> +<table class="table" summary="<?=$this->transEsc('Holdings details from')?> <?=$this->transEsc($holding['location'])?>"> + <tr> + <th><?=$this->transEsc("Availability")?></th> + <th><?=$this->transEsc("Details")?></th> + </tr> + <? foreach ($holding['items'] as $row): ?> + <? $check = (isset($row['check']) && $row['check']); ?> + <? $checkStorageRetrievalRequest = (isset($row['checkStorageRetrievalRequest']) && $row['checkStorageRetrievalRequest']); ?> + <? $checkILLRequest = (isset($row['checkILLRequest']) && $row['checkILLRequest']); ?> + <? if (isset($row['barcode']) && $row['barcode'] != ""): ?> + <tr vocab="http://schema.org/" typeof="Offer"> + <td> + <? if ($row['availability']): ?> + <? /* Begin Available Items (Holds) */ ?> + <span class="label success"><?=$this->transEsc("Available")?><link property="availability" href="http://schema.org/InStock" /></span> + <? else: ?> + <? /* Begin Unavailable Items (Recalls) */ ?> + <span class="label alert"><?=$this->transEsc($row['status'])?><link property="availability" href="http://schema.org/OutOfStock" /></span> + <? endif; ?> + </td> + <td> + <? if ($row['reserve'] == "Y"): ?> + <link property="availability" href="http://schema.org/InStoreOnly" /> + <?=$this->transEsc("On Reserve - Ask at Circulation Desk")?><br /> + <? endif; ?> + <? if (isset($row['use_unknown_message']) && $row['use_unknown_message']): ?> + <span class="label secondary"><?=$this->transEsc("status_unknown_message")?></span> + <? else: ?> + <? if (isset($row['callnumber'])): ?> + <span class="callnumber"><?=$this->transEsc("Call Number")?>: <?=$row['callnumber']?></span> + <? endif; ?> + <? if (isset($row['storage']) && $row['storage'] != 'Unknown'): ?> + <span class="storage"><?=$this->transEsc("Location")?>: <?=$row['storage']?></span> + <? endif; ?> + <? if ($row['availability']): ?> + <? /* Begin Available Items (Holds) */ ?> + <? if (isset($row['notes'])): ?> + <span class="notes"><?=$this->transEsc("Notes")?>:</span> + <ul class="notes"> + <? foreach ($row['notes'] as $note): ?> + <li><?=$note?></li> + <? endforeach; ?> + </ul> + <? endif; ?> + <? if (isset($row['link']) && $row['link']): ?> + <a class="<?=$check ? 'checkRequest ' : ''?>inlineblock modal-link placehold hide-for-print" href="<?=$this->recordLink()->getRequestUrl($row['link'])?>" title="<?=$this->transEsc($check ? "Check Hold" : "Place a Hold")?>"><i class="fa fa-flag"></i> <?=$this->transEsc($check ? "Check Hold" : "Place a Hold")?></a> + <? endif; ?> + <? if (isset($row['storageRetrievalRequestLink']) && $row['storageRetrievalRequestLink']): ?> + <a class="<?=$checkStorageRetrievalRequest ? 'checkStorageRetrievalRequest ' : ''?>modal-link placeStorageRetrievalRequest" href="<?=$this->recordLink()->getRequestUrl($row['storageRetrievalRequestLink'])?>" title="<?=$this->transEsc($checkStorageRetrievalRequest ? "storage_retrieval_request_check_text" : "storage_retrieval_request_place_text")?>"><i class="fa fa-flag"></i> <?=$this->transEsc($checkStorageRetrievalRequest ? "storage_retrieval_request_check_text" : "storage_retrieval_request_place_text")?></a> + <? endif; ?> + <? if (isset($row['ILLRequestLink']) && $row['ILLRequestLink']): ?> + <a class="<?=$checkILLRequest ? 'checkILLRequest ' : ''?>inlineblock modal-link placeILLRequest" href="<?=$this->recordLink()->getRequestUrl($row['ILLRequestLink'])?>" title="<?=$this->transEsc($checkILLRequest ? "ill_request_check_text" : "ill_request_place_text")?>"><i class="fa fa-flag"></i> <?=$this->transEsc($checkILLRequest ? "ill_request_check_text" : "ill_request_place_text")?></a> + <? endif; ?> + <? else: ?> + <? /* Begin Unavailable Items (Recalls) */ ?> + <span class="label alert"><?=$this->transEsc($row['status'])?><link property="availability" href="http://schema.org/OutOfStock" /></span> + <? if (isset($row['returnDate']) && $row['returnDate']): ?>– <span class="small"><?=$this->escapeHtml($row['returnDate'])?></span><? endif; ?> + <? if (isset($row['duedate']) && $row['duedate']): ?> + – <span class="small"><?=$this->transEsc("Due")?>: <?=$this->escapeHtml($row['duedate'])?></span> + <? endif; ?> + <? if (isset($row['requests_placed']) && $row['requests_placed'] > 0): ?> + <span><?=$this->transEsc("Requests")?>: <?=$this->escapeHtml($row['requests_placed'])?></span> + <? endif; ?> + <? if (isset($row['link']) && $row['link']): ?> + <a class="<?=$check ? 'checkRequest' : ''?> modal-link inlineblock placehold hide-for-print" href="<?=$this->recordLink()->getRequestUrl($row['link'])?>"><i class="fa fa-flag"></i> <?=$this->transEsc($check ? "Check Recall" : "Recall This")?></a> + <? endif; ?> + <? endif; ?> + <? endif; ?> + <? /* Embed item structured data: library, barcode, call number */ ?> + <? if ($row['location']): ?> + <meta property="seller" content="<?=$this->escapeHtmlAttr($row['location'])?>" /> + <? endif; ?> + <? if ($row['barcode']): ?> + <meta property="serialNumber" content="<?=$this->escapeHtmlAttr($row['barcode'])?>" /> + <? endif; ?> + <? if ($row['callnumber']): ?> + <meta property="sku" content="<?=$this->escapeHtmlAttr($row['callnumber'])?>" /> + <? endif; ?> + <? /* Declare that the item is to be borrowed, not for sale */ ?> + <link property="businessFunction" href="http://purl.org/goodrelations/v1#LeaseOut" /> + <link property="itemOffered" href="#record" /> + </td> + </tr> + <? endif; ?> + <? endforeach; ?> + <? if (!empty($holding['purchase_history'])): ?> + <tr> + <th><?=$this->transEsc("Most Recent Received Issues")?>:</th> + <td> + <? foreach ($holding['purchase_history'] as $current): ?> + <?=$this->escapeHtml($current['issue'])?><br/> + <? endforeach; ?> + </td> + </tr> + <? endif; ?> +</table> +<? endforeach; ?> + +<? $history = $this->driver->getRealTimeHistory(); ?> +<? if (is_array($history) && !empty($history)): ?> +<h3><?=$this->transEsc("Most Recent Received Issues")?></h3> +<table class="table"> + <? foreach ($history as $row): ?> + <tr><td><?=$this->escapeHtml($row['issue'])?></td></tr> + <? endforeach; ?> +</table> +<? endif; ?> +<!-- recordTab - HOLDINGSILS.phtml end --> \ No newline at end of file