Skip to content

Instantly share code, notes, and snippets.

@mjlassila
Last active August 29, 2015 14:15
Show Gist options
  • Save mjlassila/98dc2bdc4d6dc0880221 to your computer and use it in GitHub Desktop.
Save mjlassila/98dc2bdc4d6dc0880221 to your computer and use it in GitHub Desktop.
Local modifications for VoyagerRestful Finna/Vufind -driver
<!-- For including in RecordDrivers/Index/holdings.tpl -->
{if $row.order_update_date}
<tr>
<td class="copyTitle">{translate text="Order information"}: </td>
<td colspan="4">
{translate text=$row.order_status|escape}
{$row.order_update_date|escape}
</td>
</tr>
{/if}
<!-- START of modified: RecordDrivers/Index/holdings.tpl -->
<div class="holdingsHeader clearfix">
{if is_array($recordFormat)}
{assign var=format value=$recordFormat.0}
{else}
{assign var=format value=$recordFormat}
{/if}
<div class="holdingsHoldingURLs">
{if (!empty($holdingURLs) || $holdingsOpenURL)}
<h5>{translate text="available_online"}</h5>
<ul class="holdingsOnline">
{if !empty($holdingURLs)}
{foreach from=$holdingURLs item=desc key=currentUrl name=loop}
<li><a href="{$currentUrl|proxify|escape}" target="_blank">{$desc|translate_prefix:'link_'|escape}</a></li>
{/foreach}
{/if}
{if $holdingsOpenURL}
{include file="Search/openurl.tpl" openUrl=$holdingsOpenURL}
{/if}
</ul>
{/if}
</div>
<div class="holdingsHeaderLinks">
{if $id|substr:0:7 == 'helmet.'}
<span class="native_link">
<a href="http://haku.helmet.fi/iii/encore/record/C|R{$id|substr:7|escape}" target="_blank">{translate text='Holdings details from'} HelMet</a><br/>
</span>
{/if}
</div>
{if $patronFunctions}
<div class="holdingsPlaceHold">
{assign var="ublink" value=false}
{foreach from=$holdings item=holding}
{if !$ublink}
{foreach from=$holding item=row}
{if !$ublink && $row.UBRequestLink}
<a class="UBRequestPlace checkUBRequest button buttonFinna" href="{$row.UBRequestLink|escape}"><span>{translate text="ub_request_check"}</span></a>
{assign var="ublink" value=true}
{/if}
{/foreach}
{/if}
{/foreach}
{if !$hideLogin && $offlineMode != "ils-offline"}
{if ($driverMode && !empty($holdings)) || $titleDriverMode}
{if $showLoginMsg || $showTitleLoginMsg}
{translate text="hold_login"} <a class="button buttonFinna" href="{$path}/MyResearch/Home?followup=true&followupModule=Record&followupAction={$id|escape}">{translate text="Login"}</a>
{/if}
{if count($catalogAccounts) > 1}
{include file="MyResearch/select-card.tpl"}
{/if}
{if $user && !$user->cat_username}
<a class="button buttonFinna" href="{$path}/MyResearch/Profile">{translate text="Add an account to place holds"}</a>
{/if}
{/if}
{/if}
{if $holdingTitleHold && $holdingTitleHold != 'block'}
<a class="button buttonFinna holdPlace" href="{$holdingTitleHold|escape}">{translate text="title_hold_place"}</a>
{/if}
{if $catalogAccounts && !$ublink && !$holdingTitleHold}
<span>{translate text="title_cant_place_hold"}</span>
{/if}
{if $holdingTitleHold == 'block'}
{translate text="hold_error_blocked"}
{/if}
</div>
{/if}
</div>
{if $driver != 'AxiellWebServices'}
<div class="holdingsContainerHeader">
{if $coreMergedRecordData.dedup_data}
<div class="menuHolder">
<select id="dedupRecordHoldingsMenu" name="deduprecordHoldingsMenu" class="dropdown jumpMenuURL">
{foreach from=$coreMergedRecordData.dedup_data key=source item=dedupData name=loop}
<option value="{$url}/Record/{$dedupData.id|escape:"url"}#holdingstab"{if $dedupData.id == $id} selected="selected"{/if}>{translate text=$source prefix='source_'}</option>
{/foreach}
</select>
</div>
{else}
<h5>{translate text=$source prefix='source_'}</h5>
{/if}
</div>
<div class="holdingsContainer clearfix driver-{$driver}">
{if !$holdings}
<h5>{translate text="No holdings information available"}</h5>
{else}
<div>
{* Display link to access rights for records from fennica, viola and vaari *}
{if $coreSource == 'fennica' || $coreSource == 'viola' || $coreSource == 'vaari'}
<p class="accessRights"><a href="
{if $coreSource == 'fennica' || $coreSource == 'viola'}{if $userLang == 'fi'}http://www.kansalliskirjasto.fi/kokoelmatjapalvelut/lainaus/kansalliskokoelmankaytosta.html{elseif $userLang == 'sv'}http://www.nationalbiblioteket.fi/tjanster/lainaus/kansalliskokoelmankaytosta.html{else}http://www.nationallibrary.fi/services/lainaus/kansalliskokoelmankaytosta.html{/if}
{elseif $coreSource == 'vaari'}http://www.varastokirjasto.fi/{if $userLang == 'fi'}kaukolainaus/varastokirjaston-palvelut-henkiloasiakkaille/{elseif $userLang == 'sv'}utlaning/service-for-privatkunder/{else}loans-and-requests/ill-services-for-private-customers/{/if}
{/if}
" target="_blank">{translate text="Record access rights"}</a></p>
{/if}
</div>
{/if}
{foreach from=$holdings item=holding key=location name=holdings}
{assign var=prevGroupId value=''}
{assign var="copyCount" value="0"}
{foreach from=$holding item=row name=items}
{assign var="itemsIteration" value=$smarty.foreach.items.iteration}
{if isset($row.mfhd_id)}
{assign var="holdingsGroupId" value=$row.mfhd_id}
{else}
{if isset($row.callnumber)}
{assign var="holdingsGroupId" value=$row.callnumber|replace:'.':'_'}
{else}
{assign var="holdingsGroupId" value=$location|replace:'.':'_'}
{/if}
{/if}
{if $prevGroupId != $holdingsGroupId}
{assign var="showCopyTitle" value=1}
{if $prevGroupId}
<tr class="avail"><td>{$availCount}</td></tr>
</table>
{/if}
{assign var=prevGroupId value=$holdingsGroupId}
<table class="holdingsContainerHolding {if $smarty.foreach.items.first && $smarty.foreach.holdings.iteration <=5}active{/if}" id="holding_{$prevGroupId}_{$itemsIteration}" cellpadding="2" cellspacing="0" border="0" class="citation" summary="{translate text='Holdings details from'} {translate text=$location}">
<tr class="holdingsContainerHeading">
<th colspan="2" class="location"><span class="arrowIndicator"></span>{$location|translate|escape}</th>
<th colspan="2" class="holdingDetails">
<span class="availability">{translate text="Available"}</span>
</th>
<th class="locationLink">
{if $locationServiceUrl}
<a class="openLocationService" href="{$locationServiceUrl}&callno={$row.callnumber|escape:'url'}">
{$row.callnumber|truncate:21:"...":true|escape}</a><a class="openLocationServiceQR" href="{$locationServiceUrl}&callno={$row.callnumber|escape:'url'}"><i class="icon-qrcode"></i></a>
{else}
{$row.callnumber|escape}
{/if}
</th>
</tr>
<tr class="mobileLocation">
<td colspan="5" class="locationLink">
{if $locationServiceUrl}
<a class="openLocationService" href="{$locationServiceUrl}&callno={$row.callnumber|escape:'url'}">
{$row.callnumber|truncate:21:"..."|escape}</a><a class="openLocationServiceQR" href="{$locationServiceUrl}&callno={$row.callnumber|escape:'url'}"><i class="icon-qrcode"></i></a>
{else}
{$row.callnumber|escape}
{/if}
</td>
</tr>
{assign var="availCount" value=0}
{if $row.summary}
<tr class="rowSummary format-{$format}">
<td class="copyTitle">{translate text="Volume Holdings"}: </td>
<td colspan="4">
{foreach from=$row.summary item=summary}
{$summary|replace:'((':'('|replace:'))':')'|escape}<br>
{/foreach}
</td>
</tr>
{/if}
{if $row.purchase_history}
<tr>
<td class="copyTitle">{translate text="Most Recent Received Issues"}: </td>
<td colspan="4">
{foreach from=$row.purchase_history item=data}
{$data.issue|escape}<br>
{/foreach}
</td>
</tr>
{/if}
{if $row.notes}
<tr>
<td class="copyTitle">{translate text="Notes"}: </td>
<td colspan="4">
{foreach from=$row.notes item=data}
{$data|escape}<br>
{/foreach}
</td>
</tr>
{/if}
{if $row.order_update_date}
<tr class="orderinfo">
<td class="copyTitle">{translate text="Order information"}: </td>
<td colspan="4">
{translate text=$row.order_status|escape}
{$row.order_update_date|escape}
</td>
</tr>
{/if}
{if $row.supplements}
<tr>
<td class="copyTitle">{translate text="Supplements"}: </td>
<td colspan="4">
{foreach from=$row.supplements item=supplement}
{$supplement|escape}<br>
{/foreach}
</td>
</tr>
{/if}
{if $row.indexes}
<tr>
<td class="copyTitle">{translate text="Indexes"}: </td>
<td colspan="4">
{foreach from=$row.indexes item=index}
{$index|escape}<br>
{/foreach}
</td>
</tr>
{/if}
{/if}
{if $row.item_id}
{if $copyCount == 12}<tr class="toggleCopyDetails"><td class="copyTitle"></td><td colspan="2"><strong><a href="#">{translate text="More Results"}</a></strong></td></tr>{/if}
<tr class="copyDetails {if $showCopyTitle}{counter start=0 assign=copyCount}first{/if} {if $copyCount >= 12}hidden{/if}">
{counter assign=copyCount}
{if $showCopyTitle}<td class="copyTitle">{translate text="Copies"}{assign var="showCopyTitle" value=0}</td>
{else}<td></td>{/if}
<td class="copyNumber">
{if $row.itemSummary}
{$row.itemSummary}
{else}
{if $row.number|trim == false}{translate text="Copy"}{/if}
{$row.number|escape}
{/if}
</td>
<td colspan="3" class="copyInfo">
{if $row.reserve == "Y"}
{translate text="On Reserve - Ask at Circulation Desk"}
{elseif $row.use_unknown_message}
<span class="unknown">{translate text="status_unknown_message"}</span>
{else}
{if $patronFunctions}
{if $row.availability}
{assign var=availCount value=$availCount+1}
{* Begin Available Items (Holds) *}
<span class="available">{translate text="Available"}</span>
{if $row.link}
<a class="holdPlace{if $row.check} checkRequest{/if}" href="{$row.link|escape}"><span>{if !$row.check}{translate text="Place a Hold"}{else}{translate text="Check Hold"}{/if}</span></a>
{/if}
{if $row.callSlipLink}
<a class="callSlipPlace{if $row.checkCallSlip} checkCallSlipRequest{/if}" href="{$row.callSlipLink|escape}"><span>{if !$row.checkCallSlip}{translate text="call_slip_place_text"}{else}{translate text="Check Call Slip Request"}{/if}</span></a>
{/if}
{else}
{* Begin Unavailable Items (Recalls) *}
{if is_null($row.availability)}
<span class="availabilityUnknown" data-status="{$row.status}">{translate text=$row.status prefix='status_'}</span>
{else}
<span class="checkedout">{translate text=$row.status prefix='status_'}</span>
{/if}
{if $row.returnDate} <span class="statusExtra"><span class="returnDate">{$row.returnDate|escape}</span></span>
{/if}
{if $row.duedate}
{* N.B. The "returnDate duedate" classes on the next line are needed for the JS below to work properly *}
<span class="statusExtra">{translate text="Due"}: <span class="returnDate duedate">{$row.duedate|escape}</span></span>
{/if}
{if $row.requests_placed > 0}
<span>{translate text="Requests"}: {$row.requests_placed|escape}</span>
{/if}
{if $row.link}
<a class="holdPlace{if $row.check} checkRequest{/if}" href="{$row.link|escape}"><span>{if !$row.check}{translate text="Recall This"}{else}{translate text="Check Recall"}{/if}</span></a>
{/if}
{/if}
{/if}
{/if}
</td>
</tr>
{/if}
{/foreach}
<tr class="avail"><td>{$availCount}</td></tr>
</table>
{/foreach}
</div>
{else}
<div class="holdingsContainerHeader">
<h5>{translate text=$source prefix='source_'}
{if $holdings}
<div class="holdRequestTotals">
<span class="requestCount">{translate text="Request queue"}: {$requestCount}</span>
<span class="holdCount">{translate text="Total number of items"}: {$holdCount}</span>
</div>
{/if}
</h5>
</div>
<div class="holdingsContainer clearfix driver-{$driver}">
{if !$holdings}
<h5>{translate text="No holdings information available"}</h5>
{else}
<div>
{* Display link to access rights for records from fennica, viola and vaari *}
{if $coreSource == 'fennica' || $coreSource == 'viola' || $coreSource == 'vaari'}
<p class="accessRights"><a href="
{if $coreSource == 'fennica' || $coreSource == 'viola'}{if $userLang == 'fi'}http://www.kansalliskirjasto.fi/kokoelmatjapalvelut/lainaus/kansalliskokoelmankaytosta.html{elseif $userLang == 'sv'}http://www.nationalbiblioteket.fi/tjanster/lainaus/kansalliskokoelmankaytosta.html{else}http://www.nationallibrary.fi/services/lainaus/kansalliskokoelmankaytosta.html{/if}
{elseif $coreSource == 'vaari'}http://www.varastokirjasto.fi/{if $userLang == 'fi'}kaukolainaus/varastokirjaston-palvelut-henkiloasiakkaille/{elseif $userLang == 'sv'}utlaning/service-for-privatkunder/{else}loans-and-requests/ill-services-for-private-customers/{/if}
{/if}
" target="_blank">{translate text="Record access rights"}</a></p>
{/if}
</div>
{/if}
{foreach from=$holdings item=location name=locations}
{if $location.0.status.text == "Available"}
{assign var="availableLoc" value="1"}
{else}
{assign var="availableLoc" value="0"}
{/if}
{assign var="status" value=$location.0.status.text}
<table class="holdingsContainerHolding {if $smarty.foreach.locations.first}active{/if}">
<tr class="holdingsContainerHeading">
<th class="location" colspan="2"><span class="arrowIndicator"></span>{$location.0.title}</th>
<th class="holdingDetails" colspan="2">
<span class="availability {if $availableLoc || $location.0.status.text=="On Reference Desk"}available{else}checkedout{/if}">
{if $availableLoc}
{translate text="axiell_available_from"} {$location.0.status.availableCount} {translate text="axiell_branches"}
{elseif $status=="Closest due"}
{translate text=$status} {$location.0.status.closestDueDate}
{else}
{translate text="status_`$status`"}
{/if}
</span>
</th>
<th class="locationLink">{$location.0.callnumber}
{if $location.0.journal && $location.0.is_holdable && $user && $user->cat_username && $location.0.reservableIdLink}
{if $holdingTitleHold != 'block'}
<a class="button buttonFinna holdPlace" href="{$location.0.reservableIdLink|escape}">{translate text="title_hold_place"}</a>
{elseif $holdingTitleHold == 'block'}
{translate text="hold_error_blocked"}
{/if}
{/if}
</th>
</tr>
{foreach from=$location.0.holdings item=holding name=holding}
<tr class="copyDetails {if $smarty.foreach.holding.first}first{/if}">
{if $smarty.foreach.holding.first}
<td class="copyTitle">{translate text="Library unit"}</td>
{else}
<td></td>
{/if}
<td class="copyNumber">{if $location.0.journal}{$holding.organisation}, {/if}{$holding.branch}, {$holding.department}{if $holding.location}, {$holding.location}{/if}</td>
<td class="copyInfo" colspan="2">
<span class="{if $holding.availability || $holding.status=="On Reference Desk"}available{else}checkedout{/if}">
{if $holding.availability}
{capture assign="avail" name="avail"}{translate text="axiell_available"}{/capture}{$avail|@ucfirst}
{else}
{translate text="status_`$holding.status`"}
{/if}
</span>
{if $holding.duedate != '' && !$holding.availability}
<span class="statusExtra">{translate text="Due Date"}: <span class="returnDate">{$holding.duedate}</span></span>
{elseif $holding.ordered > 0}
<span class="statusExtra">{translate text="status_Ordered"}: {$holding.ordered}</span>
{/if}
</td>
<td class="availableOfTotal">{translate text="Available items"}: {$holding.available} / {$holding.total}</td>
</tr>
{/foreach}
</table>
{/foreach}
</div>
{/if}
{literal}
<script type="text/javascript">
$(document).ready(function() {
// IE8 compatible Date.now()
Date.now = Date.now || function() { return +new Date; };
/* Open volume details by clicking on the heading */
$('.holdingsContainerHeading').click(function() {
$(this).closest('table').toggleClass('active');
})
/* Show more/less copy information */
$('.toggleCopyDetails a').click(function(e) {
e.preventDefault();
$(this).toggleClass('active');
var $parentTr = $(this).closest('tr'),
$copyDetails = $parentTr.siblings('.copyDetails'),
openText = '{/literal}{translate text="More Results"}{literal}',
closeText = '{/literal}{translate text="Fewer Results"}{literal}';
// Change .hidden to .visible
$copyDetails.each(function() {
if ($(this).is('.hidden')) {
$(this).removeClass('hidden').addClass('visible');
} else if ($(this).is('.visible')) {
$(this).removeClass('visible').addClass('hidden');
}
});
// Move the toggler and change its content accordingly
if ($(this).is('.active')) {
$(this).text(closeText);
$parentTr.insertAfter($copyDetails.last());
} else {
$(this).text(openText);
}
});
{/literal}{if $driver != 'AxiellWebServices'}{literal}
/* Show copy details in the heading */
$('.holdingsContainerHolding').each(function() {
var availableCount = $(this).find('.avail td').text();
var orderinfoCount = $(this).find('.orderinfo').length;
$headingAvail = $(this).find('.holdingsContainerHeading .availability');
iBlock = {'display': 'inline-block'},
msg = '{/literal}{translate text="status_No_status_information"}{literal}',
in_order = '{/literal}{translate text="status_In Process"}{literal}'
due = '{/literal}{translate text="Closest due"}{literal}';
/* If there are available copies, show the number */
if (availableCount > 0) {
$headingAvail.addClass('available');
$headingAvail.text(availableCount + ' ' + $headingAvail.text().toLowerCase()).show();
}
else { /* If no available copies, get return dates */
var prevDate, firstDate, firstDateText;
$(this).find('.copyDetails .returnDate.duedate').each(function() {
var returnDateSplit = $(this).text().split('.'); /* Split the date and build it anew */
var returnDate = new Date(returnDateSplit[2], returnDateSplit[1] - 1, returnDateSplit[0]);
if (typeof prevDate == 'undefined' || returnDate < prevDate) {
firstDate = returnDate; /* Get the closest date to today */
}
prevDate = firstDate;
})
/* If a return date exists */
if (typeof firstDate != 'undefined') {
var $dateTarget = $(this).find('.holdingDetails .returnDate');
$headingAvail.addClass('checkedout').text(due + ' ' + ' ' + firstDate.getDate() + '.' +
(firstDate.getMonth() + 1) + '.' +firstDate.getFullYear()).css(iBlock);
} else { /* Without a date, only show the checkedout message */
var uniqueStatuses = [];
var fullStatus = '';
$(this).find('.checkedout').each(function(index, elem) {
var status = $(elem).text();
if ((jQuery.inArray(status, uniqueStatuses)) == -1) {
uniqueStatuses.push(status);
fullStatus += status + ' ';
}
});
if (fullStatus !== '') {
$headingAvail.addClass('checkedout').text(fullStatus).css(iBlock);
}
if (orderinfoCount >=1) { /* If no message found, print the default one */
$headingAvail.addClass('unknown').text(in_order).css(iBlock);
}
else { /* If no message found, print the default one */
$headingAvail.addClass('unknown').text(msg).css(iBlock);
}
}
}
});
{/literal}{/if}{literal}
$('a.holdPlace,a.callSlipPlace,a.UBRequestPlace').click(function() {
var id = {/literal}'{$id}'{literal};
var href = $(this).attr('href');
var hashPos = href.indexOf('#');
if (hashPos >= 0) {
href = href.substring(0, hashPos);
}
var $dialog = getPageInLightbox(href + '&lightbox=1', $(this).text(), 'Record', '', id);
return false;
});
createDropdowns();
initDropdowns();
initJumpMenus();
});
</script>
{/literal}
<!-- END of modified: RecordDrivers/Index/holdings.tpl -->
<?php
/**
* Voyager ILS Driver modifications for displaying purchase order information
*
* @category VuFind
* @package ILS_Drivers
* @author Andrew S. Nagy <vufind-tech@lists.sourceforge.net>
* @author Demian Katz <demian.katz@villanova.edu>
* @author Matti Lassila
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link http://vufind.org/wiki/building_an_ils_driver Wiki
*/
require_once 'VoyagerRestful.php';
class VoyagerRestfulLocal extends VoyagerRestful
{
/**
* Protected support method for getHolding.
* Modified for including purchase order
* information.
*
* @param array $id A Bibliographic id
*
* @return array Keyed data for use in an sql query
* @access protected
*/
protected function getHoldingNoItemsSQL($id)
{
// Check how many line items are available
// If there are more than one, do not query
// acquisition information as most likely
// these are serials.
$sql = "SELECT COUNT(*) AS CNT FROM "
.$this->dbName.".LINE_ITEM "
."INNER JOIN ".$this->dbName.".BIB_TEXT ON ".$this->dbName.".BIB_TEXT.BIB_ID = ".$this->dbName.".LINE_ITEM.BIB_ID "
."WHERE ".$this->dbName.".BIB_TEXT.BIB_FORMAT LIKE 'am' AND ".$this->dbName.".LINE_ITEM.BIB_ID=".$id;
try {
$sqlStmt = $this->db->prepare($sql);
$sqlStmt->execute();
} catch (PDOException $e) {
return new PEAR_Error($e->getMessage());
}
$result = $sqlStmt->fetchAll();
$lineItemCount = $result[0]["CNT"];
// Only one line item available; so likely it is a book.
if ($lineItemCount == 1) {
$sqlExpressions = array("BIB_MFHD.BIB_ID", "null as ITEM_BARCODE", "null as ITEM_ID",
"MFHD_DATA.RECORD_SEGMENT", "null as ITEM_ENUM",
"'N' as ON_RESERVE", "1 as ITEM_SEQUENCE_NUMBER",
"'No information available' as status",
"NVL(LOCATION.LOCATION_DISPLAY_NAME, " .
"LOCATION.LOCATION_NAME) as location",
"null as TEMP_LOCATION",
"null as PERM_LOCATION",
"MFHD_MASTER.DISPLAY_CALL_NO as callnumber",
"MFHD_MASTER.MFHD_ID",
"null as duedate",
"LINE_ITEM.QUANTITY as quantity",
"LINE_ITEM_COPY_STATUS.STATUS_DATE as order_update_date",
"LINE_ITEM_STATUS.LINE_ITEM_STATUS_DESC",
"PURCHASE_ORDER.PO_TYPE",
$this->getItemSortSequenceSQL('LOCATION.LOCATION_ID'),
"null as ITEM_TYPE_ID",
"null as TEMP_ITEM_TYPE_ID"
);
// From
$sqlFrom = array($this->dbName.".BIB_MFHD", $this->dbName.".LOCATION",
$this->dbName.".MFHD_MASTER", $this->dbName.".MFHD_DATA",
$this->dbName.".LINE_ITEM",$this->dbName. ".PURCHASE_ORDER",
$this->dbName.".PO_STATUS",$this->dbName.".LINE_ITEM_STATUS",
$this->dbName.".LINE_ITEM_COPY_STATUS"
);
// Where
$sqlWhere = array("BIB_MFHD.BIB_ID = :id",
"LINE_ITEM.BIB_ID = :id",
"LOCATION.LOCATION_ID = MFHD_MASTER.LOCATION_ID",
"MFHD_MASTER.MFHD_ID = BIB_MFHD.MFHD_ID",
"MFHD_DATA.MFHD_ID = BIB_MFHD.MFHD_ID",
"MFHD_MASTER.SUPPRESS_IN_OPAC='N'",
"PURCHASE_ORDER.PO_ID = LINE_ITEM.PO_ID",
"LINE_ITEM.LINE_ITEM_ID=LINE_ITEM_COPY_STATUS.LINE_ITEM_ID",
"LINE_ITEM_STATUS.LINE_ITEM_STATUS = LINE_ITEM_COPY_STATUS.LINE_ITEM_STATUS",
"NOT EXISTS (SELECT MFHD_ID FROM {$this->dbName}.MFHD_ITEM WHERE MFHD_ITEM.MFHD_ID=MFHD_MASTER.MFHD_ID)"
);
// Order
$sqlOrder = array("MFHD_DATA.MFHD_ID", "MFHD_DATA.SEQNUM");
// Bind
$sqlBind = array(':id' => $id);
}
// Do not query acquisition information for serials.
else {
$sqlExpressions = array("BIB_MFHD.BIB_ID", "null as ITEM_BARCODE", "null as ITEM_ID",
"MFHD_DATA.RECORD_SEGMENT", "null as ITEM_ENUM",
"'N' as ON_RESERVE", "1 as ITEM_SEQUENCE_NUMBER",
"'No information available' as status",
"NVL(LOCATION.LOCATION_DISPLAY_NAME, " .
"LOCATION.LOCATION_NAME) as location",
" null as TEMP_LOCATION",
" null as PERM_LOCATION",
"MFHD_MASTER.DISPLAY_CALL_NO as callnumber",
"MFHD_MASTER.MFHD_ID",
" null as duedate",
$this->getItemSortSequenceSQL('LOCATION.LOCATION_ID'),
" null as ITEM_TYPE_ID",
" null as TEMP_ITEM_TYPE_ID"
);
// From
$sqlFrom = array($this->dbName.".BIB_MFHD", $this->dbName.".LOCATION",
$this->dbName.".MFHD_MASTER", $this->dbName.".MFHD_DATA"
);
// Where
$sqlWhere = array("BIB_MFHD.BIB_ID = :id",
"LOCATION.LOCATION_ID = MFHD_MASTER.LOCATION_ID",
"MFHD_MASTER.MFHD_ID = BIB_MFHD.MFHD_ID",
"MFHD_DATA.MFHD_ID = BIB_MFHD.MFHD_ID",
"MFHD_MASTER.SUPPRESS_IN_OPAC='N'",
"NOT EXISTS (SELECT MFHD_ID FROM {$this->dbName}.MFHD_ITEM WHERE MFHD_ITEM.MFHD_ID=MFHD_MASTER.MFHD_ID)"
);
// Order
$sqlOrder = array("MFHD_DATA.MFHD_ID", "MFHD_DATA.SEQNUM");
// Bind
$sqlBind = array(':id' => $id);
}
$sqlArray = array('expressions' => $sqlExpressions,
'from' => $sqlFrom,
'where' => $sqlWhere,
'order' => $sqlOrder,
'bind' => $sqlBind,
);
return $sqlArray;
}
protected function processHoldingData($data, $id, $patron = false)
{
$holding = $this->preProcessHoldingData($data, $id, $patron);
$mode = CatalogConnection::getHoldsMode();
foreach ($holding as $i => $row) {
$is_borrowable = $this->isBorrowable($row['_fullRow']['ITEM_TYPE_ID']);
$is_holdable = $this->itemHolds && $this->isHoldable($row['_fullRow']['STATUS_ARRAY']);
$isCallSlipAllowed = $this->isCallSlipAllowed($row);
// If the item cannot be borrowed or if the item is not holdable,
// set is_holdable to false
if (!$is_borrowable || !$is_holdable) {
$is_holdable = false;
}
// Only used for driver generated hold links
$addLink = false;
$addCallSlipLink = false;
$holdType = '';
$callslip = '';
// Hold Type - If we have patron data, we can use it to dermine if a
// hold link should be shown
if ($is_holdable) {
if ($patron && $mode == "driver") {
// This limit is set as the api is slow to return results
if ($i < $this->holdCheckLimit && $this->holdCheckLimit != "0") {
$holdType = $this->determineHoldType(
$patron['id'], $row['id'], $row['item_id']
);
$addLink = $holdType ? $holdType : false;
} else {
$holdType = "auto";
$addLink = "check";
}
} else {
$holdType = "auto";
}
}
if ($isCallSlipAllowed) {
if ($patron && $mode == "driver") {
if ($i < $this->callSlipCheckLimit && $this->callSlipCheckLimit != "0") {
$callslip = false;
if ($this->isCallSlipAllowed($row)) {
$callslip = $this->checkItemRequests($patron['id'], 'callslip', $row['id'], $row['item_id']);
}
} else {
$callslip = "auto";
$addCallSlipLink = "check";
}
} else {
$callslip = "auto";
}
}
$UBRequest = '';
$addUBRequestLink = false;
if ($patron && isset($this->config['UBRequests']['enabled']) && $this->config['UBRequests']['enabled']) {
$UBRequest = 'auto';
$addUBRequestLink = 'check';
}
$holding[$i] += array(
'is_holdable' => $is_holdable,
'holdtype' => $holdType,
'addLink' => $addLink,
'level' => "copy",
'callslip' => $callslip,
'addCallSlipLink' => $addCallSlipLink,
'ubrequest' => $UBRequest,
'addUBRequestLink' => $addUBRequestLink
);
unset($holding[$i]['_fullRow']);
}
return $holding;
}
/**
* Protected support method for getHolding.
*
* @param array $data Item Data
* @param string $id The record id
* @param array $patron Patron Data
*
* @return array Keyed data
* @access protected
*/
protected function preProcessHoldingData($data, $id, $patron = false)
{
$holding = array();
// Build Holdings Array
$i = 0;
$purchaseHistory = parent::getPurchaseHistory($id);
foreach ($data as $item) {
foreach ($item as $number => $row) {
// Get availability/status info based on the array of status codes:
$availability = $this->determineAvailability($row['STATUS_ARRAY']);
// If we found other statuses, we should override the display value
// appropriately:
if (count($availability['otherStatuses']) > 0) {
$row['STATUS']
= $this->pickStatus($availability['otherStatuses']);
}
// Convert Voyager Format to display format
$dueDate = false;
if (!empty($row['DUEDATE'])) {
$dueDate = $this->dateFormat->convertToDisplayDate(
"m-d-y", $row['DUEDATE']
);
if (PEAR::isError($dueDate)) {
return $dueDate;
}
}
$returnDate = false;
if (!empty($row['RETURNDATE'])) {
$returnDate = $this->dateFormat->convertToDisplayDate(
"m-d-y H:i", $row['RETURNDATE']
);
if (PEAR::isError($returnDate)) {
return $returnDate;
}
$returnTime = $this->dateFormat->convertToDisplayTime(
"m-d-y H:i", $row['RETURNDATE']
);
if (PEAR::isError($returnTime)) {
return $returnTime;
}
$returnDate .= " " . $returnTime;
}
$returnDate = (in_array("Discharged", $row['STATUS_ARRAY']))
? $returnDate : false;
$requests_placed = (isset($row['HOLDS_PLACED']) ? $row['HOLDS_PLACED'] : 0)
+ (isset($row['RECALLS_PLACED']) ? $row['RECALLS_PLACED'] : 0);
$holding[$i] = $this->processHoldingRow($row);
$purchases = array();
foreach ($purchaseHistory as $historyItem) {
if ($holding[$i]['mfhd_id'] == $historyItem['mfhd_id']) {
$purchases[] = $historyItem;
}
}
$holding[$i] += array(
'availability' => $availability['available'],
'duedate' => $dueDate,
'number' => $number,
'requests_placed' => $requests_placed,
'returnDate' => $returnDate,
'use_unknown_message' => in_array('No information available', $row['STATUS_ARRAY']),
'purchase_history' => $purchases
);
// Parse Holding Record
if ($row['RECORD_SEGMENT']) {
$marcDetails
= $this->processRecordSegment($row['RECORD_SEGMENT']);
if (!empty($marcDetails)) {
$holding[$i] += $marcDetails;
}
}
$i++;
}
}
if (!isset($this->config['Holdings']['use_sort_groups'])
|| $this->config['Holdings']['use_sort_groups']
) {
usort(
$holding,
function($a, $b) {
return $a['sort_seq'] == $b['sort_seq']
&& isset($a['item_id']) && isset($b['item_id'])
? $a['item_id'] - $b['item_id']
: $a['sort_seq'] - $b['sort_seq'];
}
);
}
return $holding;
}
/**
* Protected support method for getHolding.
*
* @param array $sqlRow SQL Row Data
*
* @return array Keyed data
* @access protected
*/
protected function processHoldingRow($sqlRow)
{
$row = array(
'id' => $sqlRow['BIB_ID'],
'mfhd_id' => $sqlRow['MFHD_ID'],
'item_id' => $sqlRow['ITEM_ID'],
'status' => $sqlRow['STATUS'],
'location' => $sqlRow['TEMP_LOCATION'] > 0
? $this->getLocationName($sqlRow['TEMP_LOCATION'])
: utf8_encode($sqlRow['LOCATION']),
'reserve' => $sqlRow['ON_RESERVE'],
'callnumber' => $sqlRow['CALLNUMBER'],
'barcode' => $sqlRow['ITEM_BARCODE'],
'sort_seq' => isset($sqlRow['SORT_SEQ'])
? $sqlRow['SORT_SEQ']
: PHP_INT_MAX
);
if (array_key_exists('ORDER_UPDATE_DATE',$sqlRow)) {
$row +=array(
'quantity' => $sqlRow['QUANTITY'],
'order_update_date' =>
$this->dateFormat->convertToDisplayDate("m-d-y",
$sqlRow['ORDER_UPDATE_DATE']),
'order_status' => $sqlRow['LINE_ITEM_STATUS_DESC'],
'order_type' => $sqlRow['PO_TYPE']);
}
$row += array('item_id' => $sqlRow['ITEM_ID'], '_fullRow' => $sqlRow);
return $row;
}
public function getHolding($id, $patron = false)
{
$possibleQueries = array();
// There are two possible queries we can use to obtain status information.
// The first (and most common) obtains information from a combination of
// items and holdings records. The second (a rare case) obtains
// information from the holdings record when no items are available.
$sqlArrayItems = $this->getHoldingItemsSQL($id);
$possibleQueries[] = $this->buildSqlFromArray($sqlArrayItems);
$sqlArrayNoItems = $this->getHoldingNoItemsSQL($id);
$possibleQueries[] = $this->buildSqlFromArray($sqlArrayNoItems);
// Loop through the possible queries and try each in turn -- the first one
// that yields results will cause us to break out of the loop.
$data = array();
foreach ($possibleQueries as $sql) {
// Execute SQL
try {
$sqlStmt = $this->db->prepare($sql['string']);
$this->debugLogSQL(__FUNCTION__, $sql['string'], $sql['bind']);
$sqlStmt->execute($sql['bind']);
} catch (PDOException $e) {
return new PEAR_Error($e->getMessage());
}
$sqlRows = array();
while ($row = $sqlStmt->fetch(PDO::FETCH_ASSOC)) {
$sqlRows[] = $row;
}
$data = array_merge($data, $this->getHoldingData($sqlRows));
}
return $this->processHoldingData($data, $id, $patron);
}
/**
* Protected support method for getHolding.
*
* @param array $recordSegment A Marc Record Segment obtained from an SQL query
*
* @return array Keyed data
* @access protected
*/
protected function processRecordSegment($recordSegment)
{
$marcDetails = array();
try {
$marc = new File_MARC(
str_replace(array("\n", "\r"), '', $recordSegment),
File_MARC::SOURCE_STRING
);
if ($record = $marc->next()) {
// Get Notes
$noteFields = array(
'506' => 'au',
'845' => 'a',
'852' => 'z'
);
foreach ($noteFields as $fieldCode => $subfieldCodes) {
if ($fields = $record->getFields($fieldCode)) {
foreach ($fields as $field) {
if ($subfields = $field->getSubfields()) {
$line = '';
foreach ($subfields as $code => $subfield) {
if (!strstr($subfieldCodes, $code)) {
continue;
}
if ($line) {
$line .= ' ';
}
$line .= $subfield->getData();
}
if ($line) {
$marcDetails['notes'][] = $line;
}
}
}
}
}
// Get Summary (may be multiple lines)
if ($fields = $record->getFields('863')) {
foreach ($fields as $field) {
if ($subfields = $field->getSubfields()) {
$line = '';
foreach ($subfields as $code => $subfield) {
if (!strstr('abiz', $code)) {
continue;
}
if ($line) {
$line .= ' ';
}
if ($code == 'i' || $code == 'z') {
$line .= '(' . $subfield->getData() . ')';
} else {
$line .= $subfield->getData();
}
}
if ($line) {
$marcDetails['summary'][] = $line;
}
}
}
}
if ($fields = $record->getFields('866')) {
foreach ($fields as $field) {
if ($subfields = $field->getSubfields()) {
$line = '';
foreach ($subfields as $code => $subfield) {
if (!strstr('az', $code)) {
continue;
}
if ($line) {
$line .= ' ';
}
$line .= $subfield->getData();
}
if ($line) {
$marcDetails['summary'][] = $line;
}
}
}
}
// Get Supplementary material (may be multiple lines)
if ($fields = $record->getFields('867')) {
foreach ($fields as $field) {
if ($subfields = $field->getSubfields()) {
$line = '';
foreach ($subfields as $code => $subfield) {
if (!strstr('az', $code)) {
continue;
}
if ($line) {
$line .= ' ';
}
if ($code == 'z') {
$line .= '(' . $subfield->getData() . ')';
} else {
$line .= $subfield->getData();
}
}
if ($line) {
$marcDetails['supplements'][] = $line;
}
}
}
}
// Get indexes (may be multiple lines)
if ($fields = $record->getFields('868')) {
foreach ($fields as $field) {
if ($subfields = $field->getSubfields()) {
$line = '';
foreach ($subfields as $code => $subfield) {
if (!strstr('az', $code)) {
continue;
}
if ($line) {
$line .= ' ';
}
if ($code == 'z') {
$line .= '(' . $subfield->getData() . ')';
} else {
$line .= $subfield->getData();
}
}
if ($line) {
$marcDetails['indexes'][] = $line;
}
}
}
}
}
} catch (Exception $e) {
trigger_error(
'Poorly Formatted MFHD Record', E_USER_NOTICE
);
}
return $marcDetails;
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment