Skip to content

Commit

Permalink
[VUFIND-1701] Setting to display FOLIO holdings info when no items ex…
Browse files Browse the repository at this point in the history
  • Loading branch information
dltj authored Sep 11, 2024
1 parent 9fe8b90 commit 053de2e
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 16 deletions.
6 changes: 6 additions & 0 deletions config/vufind/Folio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,12 @@ in_transit[] = "Open - Awaiting delivery"
; retrieved from FOLIO will be retained.
;vufind_sort = "enumchron"

; If set to true and there are no items attached to a FOLIO holdings record,
; VuFind will display the holdings summary, supplement, and indexes fields on the record
; holdings tab.
; Note: `hide_holdings[]` in config.ini can be used to suppress display of specific locations.
; show_holdings_no_items = true

[CourseReserves]
; If set to true, the course number will be prefixed on the course name; if false,
; only the name will be displayed:
Expand Down
1 change: 1 addition & 0 deletions languages/HoldingStatus/en.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
availability_uncertain = "Uncertain"
copies_ordered_on_date = "%%copies%% copies ordered on %%date%%"
copy_ordered_on_date = "1 copy ordered on %%date%%"
holding_no_items_availability_message = "See full record"
service_available_presentation = "In Library Use Only"
service_loan = "Loan"
service_presentation = "In Library Use"
Expand Down
70 changes: 56 additions & 14 deletions module/VuFind/src/VuFind/ILS/Driver/Folio.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
use Laminas\Http\Response;
use VuFind\Exception\ILS as ILSException;
use VuFind\I18n\Translator\TranslatorAwareInterface;
use VuFind\ILS\Logic\AvailabilityStatus;
use VuFindHttp\HttpServiceAwareInterface as HttpServiceAwareInterface;

use function array_key_exists;
Expand Down Expand Up @@ -691,6 +692,38 @@ protected function getHoldingDetailsForItem($holding): array
);
}

/**
* Support method for getHolding() -- return an array of item-level details from
* both FOLIO holdings and item records.
*
* Depending on where this method is called, $locationId will be the holdings record
* location (in the case where no items are attached to a holding) or the item record
* location (in cases where there are attached items).
*
* @param string $locationId Location identifier from FOLIO
* @param array $holdingDetails Holding details produced by getHoldingDetailsForItem()
*
* @return array
*/
protected function getItemFieldsFromLocAndHolding(
string $locationId,
array $holdingDetails,
): array {
$locationData = $this->getLocationData($locationId);
$locationName = $locationData['name'];
return [
'is_holdable' => $this->isHoldable($locationName),
'holdings_notes' => $holdingDetails['hasHoldingNotes']
? $holdingDetails['holdingNotes'] : null,
'summary' => array_unique($holdingDetails['holdingsStatements']),
'supplements' => $holdingDetails['holdingsSupplements'],
'indexes' => $holdingDetails['holdingsIndexes'],
'location' => $locationName,
'location_code' => $locationData['code'],
'folio_location_is_active' => $locationData['isActive'],
];
}

/**
* Support method for getHolding() -- given a few key details, format an item
* for inclusion in the return value.
Expand Down Expand Up @@ -718,10 +751,7 @@ protected function formatHoldingItem(
array_map([$this, 'formatNote'], $item->notes ?? [])
);
$locationId = $item->effectiveLocation->id;
$locationData = $this->getLocationData($locationId);
$locationName = $locationData['name'];
$locationCode = $locationData['code'];
$locationIsActive = $locationData['isActive'];

// concatenate enumeration fields if present
$enum = implode(
' ',
Expand All @@ -741,8 +771,9 @@ protected function formatHoldingItem(
$item->effectiveCallNumberComponents->callNumber
?? $item->itemLevelCallNumber ?? ''
);
$locAndHoldings = $this->getItemFieldsFromLocAndHolding($locationId, $holdingDetails);

return $callNumberData + [
return $callNumberData + $locAndHoldings + [
'id' => $bibId,
'item_id' => $item->id,
'holdings_id' => $holdingDetails['id'],
Expand All @@ -752,16 +783,7 @@ protected function formatHoldingItem(
'status' => $item->status->name,
'duedate' => $dueDateValue,
'availability' => $item->status->name == 'Available',
'is_holdable' => $this->isHoldable($locationName),
'holdings_notes' => $holdingDetails['hasHoldingNotes']
? $holdingDetails['holdingNotes'] : null,
'item_notes' => !empty(implode($itemNotes)) ? $itemNotes : null,
'summary' => array_unique($holdingDetails['holdingsStatements']),
'supplements' => $holdingDetails['holdingsSupplements'],
'indexes' => $holdingDetails['holdingsIndexes'],
'location' => $locationName,
'location_code' => $locationCode,
'folio_location_is_active' => $locationIsActive,
'reserve' => 'TODO',
'addLink' => true,
'bound_with_records' => $boundWithRecords,
Expand Down Expand Up @@ -834,6 +856,7 @@ public function getHolding($bibId, array $patron = null, array $options = [])
$showDueDate = $this->config['Availability']['showDueDate'] ?? true;
$showTime = $this->config['Availability']['showTime'] ?? false;
$maxNumDueDateItems = $this->config['Availability']['maxNumberItems'] ?? 5;
$showHoldingsNoItems = $this->config['Holdings']['show_holdings_no_items'] ?? false;
$dueDateItemCount = 0;

$instance = $this->getInstanceByBibId($bibId);
Expand Down Expand Up @@ -896,6 +919,25 @@ public function getHolding($bibId, array $patron = null, array $options = [])
}
$nextBatch[] = $nextItem;
}

// If there are no item records on this holding, we're going to create a fake one,
// fill it with data from the FOLIO holdings record, and make it not appear in
// the full record display using a non-visible AvailabilityStatus.
if ($number == 0 && $showHoldingsNoItems) {
$locAndHoldings = $this->getItemFieldsFromLocAndHolding($holding->effectiveLocationId, $holdingDetails);
$invisibleAvailabilityStatus = new AvailabilityStatus(
true,
'HoldingStatus::holding_no_items_availability_message'
);
$invisibleAvailabilityStatus->setVisibilityInHoldings(false);
$nextBatch[] = $locAndHoldings + [
'id' => $bibId,
'callnumber' => $holdingDetails['holdingCallNumber'],
'callnumber_prefix' => $holdingDetails['holdingCallNumberPrefix'],
'reserve' => 'N',
'availability' => $invisibleAvailabilityStatus,
];
}
$items = array_merge(
$items,
$sortNeeded
Expand Down
23 changes: 21 additions & 2 deletions module/VuFind/src/VuFind/ILS/Logic/AvailabilityStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ class AvailabilityStatus implements AvailabilityStatusInterface
*/
protected int $availability;

/**
* Item visibility in holdings tab
*
* @var bool
*/
protected bool $visibilityInHoldingsTab = true;

/**
* Constructor
*
Expand Down Expand Up @@ -93,8 +100,20 @@ public function is(int $availability): bool
*/
public function isVisibleInHoldings(): bool
{
// Can be overridden if the status should not be visible in the holdings tab,
return true;
return $this->visibilityInHoldingsTab;
}

/**
* Set visibility in holdings tab.
*
* @param bool $visibilityInHoldingsTab Visibility toggle
*
* @return AvailabilityStatus
*/
public function setVisibilityInHoldings(bool $visibilityInHoldingsTab): AvailabilityStatus
{
$this->visibilityInHoldingsTab = $visibilityInHoldingsTab;
return $this;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ public function is(int $availability): bool;
*/
public function isVisibleInHoldings(): bool;

/**
* Set visibility status.
*
* @param bool $visibilityInHoldingsTab Visibility toggle
*
* @return AvailabilityStatus
*/
public function setVisibilityInHoldings(bool $visibilityInHoldingsTab): AvailabilityStatus;

/**
* Get status description.
*
Expand Down

0 comments on commit 053de2e

Please sign in to comment.