/**
  * Returns a summary of the holdings information for a single id. Used to display
  * within the search results and at the top of a full record display to ensure
  * the holding information makes sense to all users.
  *
  * @param string $id the id of the bid to load holdings for
  * @param boolean $forSearch whether or not the summary will be shown in search results
  * @return array an associative array with a summary of the holdings.
  */
 public function getStatusSummary($id, $forSearch = false)
 {
     global $configArray;
     $holdings = MillenniumStatusLoader::getStatus($id);
     $summaryInformation = array();
     $summaryInformation['recordId'] = $id;
     $summaryInformation['shortId'] = substr($id, 1);
     $summaryInformation['isDownloadable'] = false;
     //Default value, reset later if needed.
     if ($configArray['Catalog']['offline']) {
         $summaryInformation['offline'] = true;
         $summaryInformation['status'] = 'The circulation system is offline, status not available.';
         $summaryInformation['holdable'] = true;
         $summaryInformation['class'] = "unavailable";
         $summaryInformation['showPlaceHold'] = true;
         return $summaryInformation;
     }
     global $library;
     /** Location $locationSingleton */
     global $locationSingleton;
     $location = $locationSingleton->getActiveLocation();
     $canShowHoldButton = true;
     if ($library) {
         if ($forSearch) {
             $canShowHoldButton = $library->showHoldButtonInSearchResults != 0;
         } else {
             $canShowHoldButton = $library->showHoldButton != 0;
         }
     }
     if ($location) {
         if ($forSearch) {
             if ($library) {
                 $canShowHoldButton = $library->showHoldButtonInSearchResults != 0;
             } else {
                 $canShowHoldButton = $location->showHoldButton != 0;
             }
         } else {
             $canShowHoldButton = $location->showHoldButton != 0;
         }
     }
     $physicalLocation = $locationSingleton->getPhysicalLocation();
     //Check to see if we are getting issue summaries or actual holdings
     if (count($holdings) > 0) {
         $lastHolding = end($holdings);
         if (isset($lastHolding['type']) && ($lastHolding['type'] == 'issueSummary' || $lastHolding['type'] == 'issue')) {
             $issueSummaries = $holdings;
             $holdings = array();
             foreach ($issueSummaries as $issueSummary) {
                 if (isset($issueSummary['holdings'])) {
                     $holdings = array_merge($holdings, $issueSummary['holdings']);
                 } else {
                     //Create a fake holding for subscriptions so something
                     //will be displayed in the holdings summary.
                     $holdings[$issueSummary['location']] = array('availability' => '1', 'location' => $issueSummary['location'], 'libraryDisplayName' => $issueSummary['location'], 'callnumber' => isset($issueSummary['cALL']) ? $issueSummary['cALL'] : '', 'showPlaceHold' => $canShowHoldButton);
                     $summaryInformation['status'] = 'Available';
                     $summaryInformation['statusfull'] = 'Available';
                     $summaryInformation['class'] = 'available';
                 }
             }
         }
     }
     //Valid statuses are:
     //It's here
     //  - at the physical location and not checked out
     //  - also show the call number for the location
     //  - do not show place hold button
     //It's at *location*
     //  - at the user's home branch or preferred location and not checked out
     //  - also show the call number for the location
     //  - show place hold button
     //Available by Request
     //  - not at the user's home branch or preferred location, but at least one copy is not checked out
     //  - do not show the call number
     //  - show place hold button
     //Checked Out
     //  - all copies are checked out
     //  - show the call number for the local library if any
     //  - show place hold button
     //Downloadable
     //  - there is at least one download link for the record.
     $numAvailableCopies = 0;
     $numHoldableCopies = 0;
     $numCopies = 0;
     $numCopiesOnOrder = 0;
     $availableLocations = array();
     $additionalAvailableLocations = array();
     $unavailableStatus = null;
     $holdQueueLength = 0;
     //The status of all items.  Will be set to an actual status if all are the same
     //or null if the item statuses are inconsistent
     $allItemStatus = '';
     $firstCallNumber = null;
     $firstLocation = null;
     foreach ($holdings as $holdingKey => $holding) {
         if (is_null($allItemStatus)) {
             //Do nothing, the status is not distinct
         } else {
             if ($allItemStatus == '' && isset($holding['statusfull'])) {
                 $allItemStatus = $holding['statusfull'];
             } elseif (isset($holding['statusfull']) && $allItemStatus != $holding['statusfull']) {
                 $allItemStatus = null;
             }
         }
         if (isset($holding['holdQueueLength'])) {
             $holdQueueLength = $holding['holdQueueLength'];
         }
         if (isset($holding['availability']) && $holding['availability'] == 1) {
             $numAvailableCopies++;
             $addToAvailableLocation = false;
             $addToAdditionalAvailableLocation = false;
             //Check to see if the location should be listed in the list of locations that the title is available at.
             //Can only be in this system if there is a system active.
             if (sizeof($availableLocations) < 3 && !in_array($holding['libraryDisplayName'], $availableLocations)) {
                 if (isset($library)) {
                     //Check to see if the location is within this library system. It is if the key is less than or equal to 5
                     if (substr($holdingKey, 0, 1) <= 5) {
                         $addToAvailableLocation = true;
                     }
                 } else {
                     $addToAvailableLocation = true;
                 }
             }
             //Check to see if the location is listed in the count of additional locations (can be any system).
             if (!$addToAvailableLocation && !in_array($holding['libraryDisplayName'], $availableLocations) && !in_array($holding['libraryDisplayName'], $additionalAvailableLocations)) {
                 $addToAdditionalAvailableLocation = true;
             }
             if ($addToAvailableLocation) {
                 $availableLocations[] = $holding['libraryDisplayName'];
             } elseif ($addToAdditionalAvailableLocation) {
                 $additionalAvailableLocations[] = $holding['libraryDisplayName'];
             }
         } else {
             if ($unavailableStatus == null && isset($holding['status'])) {
                 $unavailableStatus = $holding['status'];
             }
         }
         if (isset($holding['holdable']) && $holding['holdable'] == 1) {
             $numHoldableCopies++;
         }
         $numCopies++;
         //Check to see if the holding has a download link and if so, set that info.
         if (isset($holding['link'])) {
             foreach ($holding['link'] as $link) {
                 if ($link['isDownload']) {
                     $summaryInformation['status'] = "Available for Download";
                     $summaryInformation['class'] = 'here';
                     $summaryInformation['isDownloadable'] = true;
                     $summaryInformation['downloadLink'] = $link['link'];
                     $summaryInformation['downloadText'] = $link['linkText'];
                 }
             }
         }
         //Only show a call number if the book is at the user's home library, one of their preferred libraries, or in the library they are in.
         $showItsHere = $library == null ? true : $library->showItsHere == 1;
         if (in_array(substr($holdingKey, 0, 1), array('1', '2', '3', '4', '5')) && !isset($summaryInformation['callnumber'])) {
             //Try to get an available non reserver call number
             if ($holding['availability'] == 1 && $holding['holdable'] == 1) {
                 //echo("Including call number " . $holding['callnumber'] . " because is  holdable");
                 $summaryInformation['callnumber'] = $holding['callnumber'];
             } else {
                 if (is_null($firstCallNumber)) {
                     //echo("Skipping call number " . $holding['callnumber'] . " because it is holdable");
                     $firstCallNumber = $holding['callnumber'];
                 } else {
                     if (is_null($firstLocation)) {
                         //echo("Skipping call number " . $holding['callnumber'] . " because it is holdable");
                         $firstLocation = $holding['location'];
                     }
                 }
             }
         }
         if ($showItsHere && substr($holdingKey, 0, 1) == '1' && $holding['availability'] == 1) {
             //The item is available within the physical library.  Patron should go get it off the shelf
             $summaryInformation['status'] = "It's here";
             $summaryInformation['showPlaceHold'] = $canShowHoldButton;
             $summaryInformation['class'] = 'here';
             $summaryInformation['location'] = $holding['location'];
         } elseif ($showItsHere && !isset($summaryInformation['status']) && substr($holdingKey, 0, 1) >= 2 && substr($holdingKey, 0, 1) <= 4 && $holding['availability'] == 1) {
             if (!isset($summaryInformation['class']) || $summaryInformation['class'] != 'here') {
                 //The item is at one of the patron's preferred branches.
                 $summaryInformation['status'] = "It's at " . $holding['location'];
                 $summaryInformation['showPlaceHold'] = $canShowHoldButton;
                 $summaryInformation['class'] = 'nearby';
                 $summaryInformation['location'] = $holding['location'];
             }
         } elseif (!isset($summaryInformation['status']) && (!$showItsHere && substr($holdingKey, 0, 1) <= 5 || substr($holdingKey, 0, 1) == 5 || !isset($library)) && (isset($holding['availability']) && $holding['availability'] == 1)) {
             if (!isset($summaryInformation['class']) || $summaryInformation['class'] != 'here' && ($summaryInformation['class'] = 'nearby')) {
                 //The item is at a location either in the same system or another system.
                 $summaryInformation['status'] = "Available At";
                 $summaryInformation['showPlaceHold'] = $canShowHoldButton;
                 if ($physicalLocation != null) {
                     $summaryInformation['class'] = 'availableOther';
                 } else {
                     $summaryInformation['class'] = 'available';
                 }
             }
         } elseif (!isset($summaryInformation['status']) && substr($holdingKey, 0, 1) == 6 && (isset($holding['availability']) && $holding['availability'] == 1)) {
             //The item is at a location either in the same system or another system.
             $summaryInformation['status'] = "Marmot";
             $summaryInformation['showPlaceHold'] = $canShowHoldButton;
             $summaryInformation['class'] = 'available';
         } elseif (substr($holdingKey, 0, 1) == 7) {
             $numCopiesOnOrder++;
             $numCopies--;
             //Don't increment number of copies for titles we don't have yet.
         }
     }
     //If all items are checked out the status will still be blank
     $summaryInformation['availableCopies'] = $numAvailableCopies;
     $summaryInformation['holdableCopies'] = $numHoldableCopies;
     if ($numHoldableCopies == 0) {
         $summaryInformation['showPlaceHold'] = false;
     }
     $summaryInformation['numCopiesOnOrder'] = $numCopiesOnOrder;
     //Do some basic sanity checking to make sure that we show the total copies
     //With at least as many copies as the number of copies on order.
     if ($numCopies < $numCopiesOnOrder) {
         $summaryInformation['numCopies'] = $numCopiesOnOrder;
     } else {
         $summaryInformation['numCopies'] = $numCopies;
     }
     $summaryInformation['copies'] = "{$numAvailableCopies} of {$numCopies} are on shelf";
     if ($numCopiesOnOrder > 0) {
         $summaryInformation['copies'] .= ", {$numCopiesOnOrder} on order";
     }
     $summaryInformation['holdQueueLength'] = $holdQueueLength;
     if ($unavailableStatus != 'ONLINE') {
         $summaryInformation['unavailableStatus'] = $unavailableStatus;
     }
     if (isset($summaryInformation['status']) && $summaryInformation['status'] != "It's here") {
         //Replace all spaces in the name of a location with no break spaces
         foreach ($availableLocations as $key => $location) {
             $availableLocations[$key] = str_replace(' ', ' ', $location);
         }
         $summaryInformation['availableAt'] = join(', ', $availableLocations);
         if ($summaryInformation['status'] == 'Marmot') {
             $summaryInformation['numAvailableOther'] = count($additionalAvailableLocations) + count($availableLocations);
         } else {
             $summaryInformation['numAvailableOther'] = count($additionalAvailableLocations);
         }
     }
     //If Status is still not set, apply some logic based on number of copies
     if (!isset($summaryInformation['status'])) {
         if ($numCopies == 0) {
             if ($numCopiesOnOrder > 0) {
                 //No copies are currently available, but we do have some that are on order.
                 //show the status as on order and make it available.
                 $summaryInformation['status'] = "On Order";
                 $summaryInformation['class'] = 'available';
                 $summaryInformation['showPlaceHold'] = $canShowHoldButton;
             } else {
                 //Deal with weird cases where there are no items by saying it is unavailable
                 $summaryInformation['status'] = "Unavailable";
                 $summaryInformation['showPlaceHold'] = false;
                 $summaryInformation['class'] = 'unavailable';
             }
         } else {
             if ($numHoldableCopies == 0 && $canShowHoldButton) {
                 $summaryInformation['status'] = "Not Available For Checkout";
                 $summaryInformation['showPlaceHold'] = false;
                 $summaryInformation['class'] = 'reserve';
             } else {
                 $summaryInformation['status'] = "Checked Out";
                 $summaryInformation['showPlaceHold'] = $canShowHoldButton;
                 $summaryInformation['class'] = 'checkedOut';
             }
         }
     }
     //Reset status if the status for all items is consistent.
     //That way it will jive with the actual full record display.
     if ($allItemStatus != null && $allItemStatus != '') {
         //Only override this for statuses that don't have special meaning
         if ($summaryInformation['status'] != 'Marmot' && $summaryInformation['status'] != 'Available At' && $summaryInformation['class'] != 'here' && $summaryInformation['class'] != 'nearby') {
             $summaryInformation['status'] = $allItemStatus;
         }
     }
     if ($allItemStatus == 'In Library Use Only') {
         $summaryInformation['inLibraryUseOnly'] = true;
     } else {
         $summaryInformation['inLibraryUseOnly'] = false;
     }
     if ($summaryInformation['availableCopies'] == 0 && $summaryInformation['isDownloadable'] == true) {
         $summaryInformation['showAvailabilityLine'] = false;
     } else {
         $summaryInformation['showAvailabilityLine'] = true;
     }
     //Clear unavailable status if it matches the status
     if (isset($summaryInformation['unavailableStatus']) && strcasecmp(trim($summaryInformation['unavailableStatus']), trim($summaryInformation['status'])) == 0) {
         $summaryInformation['unavailableStatus'] = '';
     }
     //Reset call number as needed
     if (!is_null($firstCallNumber) && !isset($summaryInformation['callnumber'])) {
         $summaryInformation['callnumber'] = $firstCallNumber;
     }
     //Reset location as needed
     if (!is_null($firstLocation) && !isset($summaryInformation['location'])) {
         $summaryInformation['location'] = $firstLocation;
     }
     //Set Status text for the summary
     if ($summaryInformation['status'] == 'Available At') {
         if ($summaryInformation['numCopies'] == 0) {
             $summaryInformation['statusText'] = "No Copies Found";
         } else {
             if (strlen($summaryInformation['availableAt']) > 0) {
                 $summaryInformation['statusText'] = "Available now" . ($summaryInformation['inLibraryUseOnly'] ? "for in library use" : "") . " at " . $summaryInformation['availableAt'] . ($summaryInformation['numAvailableOther'] > 0 ? ", and {$summaryInformation['numAvailableOther']} other location" . ($summaryInformation['numAvailableOther'] > 1 ? "s" : "") : "");
             } else {
                 $summaryInformation['statusText'] = "Available now" . ($summaryInformation['inLibraryUseOnly'] ? "for in library use" : "");
             }
         }
     } else {
         if ($summaryInformation['status'] == 'Marmot') {
             $summaryInformation['class'] = "nearby";
             $totalLocations = intval($summaryInformation['numAvailableOther']) + intval($summaryInformation['availableAt']);
             $summaryInformation['statusText'] = "Available now at " . $totalLocations . " Marmot " . ($totalLocations == 1 ? "Library" : "Libraries");
         } else {
             $summaryInformation['statusText'] = translate($summaryInformation['status']);
         }
     }
     return $summaryInformation;
 }
Example #2
0
 /**
  * Returns a summary of the holdings information for a single id. Used to display
  * within the search results and at the top of a full record display to ensure
  * the holding information makes sense to all users.
  *
  * @param string $id the id of the bid to load holdings for
  * @param boolean $forSearch whether or not the summary will be shown in search results
  * @return array an associative array with a summary of the holdings.
  */
 public function getStatusSummary($id, $forSearch = false)
 {
     //Load circulation status information so we can use it later on to
     //determine what is holdable and what is not.
     self::loadCircStatusInfo();
     self::loadLoanRules();
     require_once ROOT_DIR . '/Drivers/marmot_inc/MillenniumStatusLoader.php';
     $millenniumStatusLoader = new MillenniumStatusLoader($this);
     return $millenniumStatusLoader->getStatusSummary($id, $forSearch);
 }
 /**
  * In Sierra, all status information is up to date within the MARC record
  * due to the export so we don't need to screen scrape!
  *
  * Format of return array is:
  * key = {section#}{location}-### where ### is the holding iteration
  *
  * value = array (
  *  id = The id of the bib
  *  number = The position of the holding within the original list of holdings
  *  section = A description of the section
  *  sectionId = a numeric id of the section for sorting
  *  type = holding
  *  status
  *  statusfull
  *  reserve
  *  holdQueueLength
  *  duedate
  *  location
  *  locationLink
  *  callnumber
  *  link = array
  *  linkText
  *  isDownload
  * )
  *
  * Includes both physical titles as well as titles on order
  *
  * @param string            $id     the id of the record
  * @return array A list of holdings for the record
  */
 public function getStatus($id)
 {
     $recordDriver = RecordDriverFactory::initRecordDriverById('ils:' . $id);
     $format = $recordDriver->getFormat();
     if ($format[0] == 'Journal') {
         return parent::getStatus($id);
     }
     if (array_key_exists($id, SierraStatusLoader::$loadedStatus)) {
         return SierraStatusLoader::$loadedStatus[$id];
     }
     //Load local information
     global $library;
     global $locationSingleton;
     /** @var $locationSingleton Location */
     global $user;
     $physicalLocation = $locationSingleton->getPhysicalLocation();
     if ($physicalLocation != null) {
         $physicalBranch = $physicalLocation->holdingBranchLabel;
     } else {
         $physicalBranch = '';
     }
     $homeBranch = '';
     $homeBranchId = 0;
     $nearbyBranch1 = '';
     $nearbyBranch1Id = 0;
     $nearbyBranch2 = '';
     $nearbyBranch2Id = 0;
     //Set location information based on the user login.  This will override information based
     if (isset($user) && $user != false) {
         $homeBranchId = $user->homeLocationId;
         $nearbyBranch1Id = $user->myLocation1Id;
         $nearbyBranch2Id = $user->myLocation2Id;
     } else {
         //Check to see if the cookie for home location is set.
         if (isset($_COOKIE['home_location']) && is_numeric($_COOKIE['home_location'])) {
             $cookieLocation = new Location();
             $locationId = $_COOKIE['home_location'];
             $cookieLocation->whereAdd("locationId = '{$locationId}'");
             $cookieLocation->find();
             if ($cookieLocation->N == 1) {
                 $cookieLocation->fetch();
                 $homeBranchId = $cookieLocation->locationId;
                 $nearbyBranch1Id = $cookieLocation->nearbyLocation1;
                 $nearbyBranch2Id = $cookieLocation->nearbyLocation2;
             }
         }
     }
     //Load the holding label for the user's home location.
     $userLocation = new Location();
     $userLocation->whereAdd("locationId = '{$homeBranchId}'");
     $userLocation->find();
     if ($userLocation->N == 1) {
         $userLocation->fetch();
         $homeBranch = $userLocation->holdingBranchLabel;
     }
     //Load nearby branch 1
     $nearbyLocation1 = new Location();
     $nearbyLocation1->whereAdd("locationId = '{$nearbyBranch1Id}'");
     $nearbyLocation1->find();
     if ($nearbyLocation1->N == 1) {
         $nearbyLocation1->fetch();
         $nearbyBranch1 = $nearbyLocation1->holdingBranchLabel;
     }
     //Load nearby branch 2
     $nearbyLocation2 = new Location();
     $nearbyLocation2->whereAdd();
     $nearbyLocation2->whereAdd("locationId = '{$nearbyBranch2Id}'");
     $nearbyLocation2->find();
     if ($nearbyLocation2->N == 1) {
         $nearbyLocation2->fetch();
         $nearbyBranch2 = $nearbyLocation2->holdingBranchLabel;
     }
     //Get a list of the display names for all locations based on holding label.
     $locationLabels = array();
     $location = new Location();
     $location->find();
     $libraryLocationLabels = array();
     $locationCodes = array();
     $suppressedLocationCodes = array();
     while ($location->fetch()) {
         if (strlen($location->holdingBranchLabel) > 0 && $location->holdingBranchLabel != '???') {
             if ($library && $library->libraryId == $location->libraryId) {
                 $cleanLabel = str_replace('/', '\\/', $location->holdingBranchLabel);
                 $libraryLocationLabels[] = str_replace('.', '\\.', $cleanLabel);
             }
             $locationLabels[$location->holdingBranchLabel] = $location->displayName;
             $locationCodes[$location->code] = $location->holdingBranchLabel;
             if ($location->suppressHoldings == 1) {
                 $suppressedLocationCodes[$location->code] = $location->code;
             }
         }
     }
     if (count($libraryLocationLabels) > 0) {
         $libraryLocationLabels = '/^(' . join('|', $libraryLocationLabels) . ').*/i';
     } else {
         $libraryLocationLabels = '';
     }
     //In Sierra, we can just load data from the MARC Record/Index
     $items = $recordDriver->getItemsFast();
     $holdQueueLength = $recordDriver->getNumHolds();
     $itemStatus = array();
     $i = 0;
     foreach ($items as $item) {
         //Determine what section this holding is in
         $sectionId = 1;
         $location = $item['shelfLocation'];
         if (strlen($physicalBranch) > 0 && stripos($location, $physicalBranch) !== false) {
             //If the user is in a branch, those holdings come first.
             $section = 'In this library';
             $sectionId = 1;
         } else {
             if (strlen($homeBranch) > 0 && stripos($location, $homeBranch) !== false) {
                 //Next come the user's home branch if the user is logged in or has the home_branch cookie set.
                 $section = 'Your library';
                 $sectionId = 2;
             } else {
                 if (strlen($nearbyBranch1) > 0 && stripos($location, $nearbyBranch1) !== false) {
                     //Next come nearby locations for the user
                     $section = 'Nearby Libraries';
                     $sectionId = 3;
                 } else {
                     if (strlen($nearbyBranch2) > 0 && stripos($location, $nearbyBranch2) !== false) {
                         //Next come nearby locations for the user
                         $section = 'Nearby Libraries';
                         $sectionId = 4;
                     } else {
                         if (strlen($libraryLocationLabels) > 0 && preg_match($libraryLocationLabels, $location)) {
                             //Next come any locations within the same system we are in.
                             $section = $library->displayName;
                             $sectionId = 5;
                         } else {
                             //Finally, all other holdings are shown sorted alphabetically.
                             $section = 'Other Locations';
                             $sectionId = 6;
                         }
                     }
                 }
             }
         }
         $holding = array('location' => $item['shelfLocation'], 'reserve' => stripos($item['shelfLocation'], 'reserve') !== false ? 'Y' : 'N', 'callnumber' => $item['callnumber'], 'status' => $item['status'], 'duedate' => $item['dueDate'], 'lastCheckinDate' => $item['lastCheckinDate'], 'statusfull' => $this->translateStatusCode($item['status'], $item['dueDate']), 'id' => $id, 'number' => $i++, 'holdQueueLength' => $holdQueueLength, 'type' => 'holding', 'availability' => $item['availability'], 'holdable' => $item['holdable'] ? 1 : 0, 'libraryDisplayName' => $item['shelfLocation'], 'locationCode' => $item['location'], 'iType' => $item['iType'], 'section' => $section, 'sectionId' => $sectionId);
         $paddedNumber = str_pad($i, 3, '0', STR_PAD_LEFT);
         $holdingKey = $sectionId . $holding['location'] . $paddedNumber;
         $itemStatus[$holdingKey] = $holding;
     }
     ksort($itemStatus);
     SierraStatusLoader::$loadedStatus[$id] = $itemStatus;
     return $itemStatus;
 }