Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FOLIO: Support delivery fulfillment preference for requests #3930

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions config/vufind/Folio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ extraHoldFields = requiredByDate:pickUpLocation
; requested item's effective location. Only applicable to item-level requests.
;limitPickupLocations = itemEffectiveLocation

; When the extra hold field requestGroup is used, the request group Delivery is offered
; whenever the FOLIO user's Request Preferences have delivery enabled. This setting
; overrides every user's FOLIO seetting if it's necessary to globally disable delivery
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
; for backwards compatibility.
;allowDelivery = false

; When the extra hold fields pickupLocation and requestGroup are used, and requestGroup
; is Delivery, the request form's list of "pickup locations" is actually a list of
; address types matching the addresses defined for the current user. In that context,
; this setting optionally further limits which FOLIO address types are offered.
;limitDeliveryAddressTypes[] = "Campus"

; By default, a "Hold" type request is placed when an item is unavailable and a Page
; when an item is available. This setting overrides the default behavior for
; unavailable items and for all title-level requests. Legal values: "Page", "Hold" or
Expand Down
124 changes: 122 additions & 2 deletions module/VuFind/src/VuFind/ILS/Driver/Folio.php
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,7 @@ public function patronLogin($username, $password)
'firstname' => $profile->personal->firstName ?? null,
'lastname' => $profile->personal->lastName ?? null,
'email' => $profile->personal->email ?? null,
'addressTypeIds' => array_map(fn ($address) => $address->addressTypeId, $profile->personal->addresses),
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
];
}

Expand Down Expand Up @@ -1411,6 +1412,22 @@ public function renewMyItems($renewDetails)
*/
public function getPickupLocations($patron, $holdInfo = null)
{
if ('Delivery' == ($holdInfo['requestGroupId'] ?? null)) {
$addressTypes = $this->getAddressTypes();
$limitDeliveryAddressTypes = $this->config['Holds']['limitDeliveryAddressTypes'] ?? [];
$deliveryPickupLocations = [];
foreach ($patron['addressTypeIds'] as $addressTypeId) {
$addressType = $addressTypes[$addressTypeId];
if (empty($limitDeliveryAddressTypes) || in_array($addressType, $limitDeliveryAddressTypes)) {
$deliveryPickupLocations[] = [
'locationID' => $addressTypeId,
'locationDisplay' => $addressType,
];
}
}
return $deliveryPickupLocations;
}

$limitedServicePoints = null;
if (
str_contains($this->config['Holds']['limitPickupLocations'] ?? '', 'itemEffectiveLocation')
Expand Down Expand Up @@ -1444,6 +1461,104 @@ public function getPickupLocations($patron, $holdInfo = null)
return $locations;
}

/**
* Get Default Pick Up Location
*
* Returns the default pick up location set in HorizonXMLAPI.ini
*
* @param array $patron Patron information returned by the patronLogin
* method.
* @param array $holdDetails Optional array, only passed in when getting a list
* in the context of placing a hold; contains most of the same values passed to
* placeHold, minus the patron data. May be used to limit the pickup options
* or may be ignored.
*
* @return false|string The default pickup location for the patron or false
* if the user has to choose.
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function getDefaultPickUpLocation($patron = false, $holdDetails = null)
{
if ('Delivery' == ($holdDetails['requestGroupId'] ?? null)) {
$deliveryPickupLocations = $this->getPickupLocations($patron, $holdDetails);
if (count($deliveryPickupLocations) == 1) {
return $deliveryPickupLocations[0]['locationDisplay'];
}
}
return false;
}

/**
* Get request groups
*
* @param int $bibId BIB ID
* @param array $patron Patron information returned by the patronLogin
* method.
* @param array $holdDetails Optional array, only passed in when getting a list
* in the context of placing a hold; contains most of the same values passed to
* placeHold, minus the patron data. May be used to limit the request group
* options or may be ignored.
*
* @return array False if request groups not in use or an array of
* associative arrays with id and name keys
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function getRequestGroups(
$bibId = null,
$patron = null,
$holdDetails = null
) {
// circulation-storage.request-preferences.collection.get
$response = $this->makeRequest(
'GET',
'/request-preference-storage/request-preference?query=userId==' . $patron['id']
);
$requestPreferencesResponse = json_decode($response->getBody());
$requestPreferences = $requestPreferencesResponse->requestPreferences[0];
$allowHoldShelf = $requestPreferences->holdShelf;
$allowDelivery = $requestPreferences->delivery && ($this->config['Holds']['allowDelivery'] ?? true);
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
if ($allowHoldShelf && $allowDelivery) {
return [
[
'id' => 'Hold Shelf',
'name' => 'Hold Shelf',
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
],
[
'id' => 'Delivery',
'name' => 'Delivery',
],
];
}
return false;
}

/**
* Get list of address types from FOLIO. Cache as needed.
*
* @return array An array mapping an address type id to its name.
*/
protected function getAddressTypes()
{
$cacheKey = 'addressTypes';
$addressTypes = $this->getCachedData($cacheKey);
if (null == $addressTypes) {
$addressTypes = [];
// addresstypes.collection.get
foreach (
$this->getPagedResults(
'addressTypes',
'/addresstypes'
) as $addressType
) {
$addressTypes[$addressType->id] = $addressType->addressType;
}
$this->putCachedData($cacheKey, $addressTypes);
}
return $addressTypes;
}

/**
* This method queries the ILS for a patron's current holds
*
Expand Down Expand Up @@ -1692,13 +1807,18 @@ public function placeHold($holdDetails)
// Account for an API spelling change introduced in mod-circulation v24:
$fulfillmentKey = $this->getModuleMajorVersion('mod-circulation') >= 24
? 'fulfillmentPreference' : 'fulfilmentPreference';
$fulfillmentValue = $holdDetails['requestGroupId'] ?? 'Hold Shelf';
$requestBody = $baseParams + [
'requesterId' => $holdDetails['patron']['id'],
'requestDate' => date('c'),
$fulfillmentKey => 'Hold Shelf',
$fulfillmentKey => $fulfillmentValue,
'requestExpirationDate' => $requiredBy,
'pickupServicePointId' => $holdDetails['pickUpLocation'],
];
if ('Hold Shelf' == $fulfillmentValue) {
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
$requestBody['pickupServicePointId'] = $holdDetails['pickUpLocation'];
} elseif ('Delivery' == $fulfillmentValue) {
$requestBody['deliveryAddressTypeId'] = $holdDetails['pickUpLocation'];
}
if (!empty($holdDetails['proxiedUser'])) {
$requestBody['requesterId'] = $holdDetails['proxiedUser'];
$requestBody['proxyUserId'] = $holdDetails['patron']['id'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
"expectedParams": {
"query": "username == foo"
},
"body": "{ \"users\": [ { \"id\": \"fake-id\", \"personal\": { \"firstName\": \"first\", \"lastName\": \"last\", \"email\": \"[email protected]\" } } ] }"
"body": "{ \"users\": [ { \"id\": \"fake-id\", \"personal\": { \"firstName\": \"first\", \"lastName\": \"last\", \"email\": \"[email protected]\", \"addresses\": [] } } ] }"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
"expectedParams": {
"query": "username == foo"
},
"body": "{ \"users\": [ { \"id\": \"fake-id\", \"personal\": { \"firstName\": \"first\", \"lastName\": \"last\", \"email\": \"[email protected]\" } } ] }"
"body": "{ \"users\": [ { \"id\": \"fake-id\", \"personal\": { \"firstName\": \"first\", \"lastName\": \"last\", \"email\": \"[email protected]\", \"addresses\": [] } } ] }"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ public function testSuccessfulPatronLoginWithOkapi(): void
'firstname' => 'first',
'lastname' => 'last',
'email' => '[email protected]',
'addressTypeIds' => [],
];
$this->assertEquals($expected, $result);
}
Expand Down Expand Up @@ -361,6 +362,7 @@ public function testSuccessfulPatronLoginWithOkapiLegacyAuth(): void
'firstname' => 'first',
'lastname' => 'last',
'email' => '[email protected]',
'addressTypeIds' => [],
];
$this->assertEquals($expected, $result);
}
Expand Down
Loading