From 9b802d26aa8c41eba455f31b29f2c7bbf4738341 Mon Sep 17 00:00:00 2001 From: Serge Tkachuk Date: Tue, 16 Sep 2025 14:20:52 +0200 Subject: [PATCH] added: Availability section --- config/vufind/KohaILSDI.ini | 0 config/vufind/LOTS.ini | 22 ++- languages/en.ini | 8 + languages/en.ini.lots-8.0 | 12 ++ languages/sv.ini | 8 + languages/sv.ini.lots-8.0 | 12 ++ local/config/vufind/LOTS.ini | 15 -- local/languages/en.ini | 2 - local/languages/sv.ini | 2 - module/LOTS/src/LOTS/ILS/Driver/KohaRest.php | 142 +++++++++++++++++- .../RecordDriver/DefaultRecord/core.phtml | 9 +- .../DefaultRecord/result-list.phtml | 116 ++++++++++++++ 12 files changed, 325 insertions(+), 23 deletions(-) mode change 100755 => 100644 config/vufind/KohaILSDI.ini create mode 100644 languages/en.ini.lots-8.0 create mode 100644 languages/sv.ini.lots-8.0 delete mode 100644 local/config/vufind/LOTS.ini delete mode 100644 local/languages/en.ini delete mode 100644 local/languages/sv.ini diff --git a/config/vufind/KohaILSDI.ini b/config/vufind/KohaILSDI.ini old mode 100755 new mode 100644 diff --git a/config/vufind/LOTS.ini b/config/vufind/LOTS.ini index 98b0354e0d3..eb31de6bed8 100644 --- a/config/vufind/LOTS.ini +++ b/config/vufind/LOTS.ini @@ -80,7 +80,7 @@ showReservationButton = true [Suggestions] allowAnonymous = true -; Example +; Example ; librariesToRemove="LIB1", "MAIN", "X" librariesToRemove="" ; Note: The 'author' field is always visible and not hidden @@ -123,5 +123,25 @@ showItemsInVufind = true ; SUPLER-212/Andra-eller-ta-bort-reservera-knapp-pa-exemplar hideDetailReserveEvenIfInKoha = true +; LotsLerum-160 +showAvailabilityInResults = false ; Set to false to hide the availability section +enableDebug = false ; Set to true to enable debug logging +maxBranches = 100 ; Maximum number of branches to process + [NotFinished] showBankIDOption = false + +; LotsLerum-158 +; LOTS Session timeout configuration +; Session timeout configuration +[SessionTimeout] +; Enable or disable session timeout modal +enabled = false + +; Use session CSRF EXPIRE time instead of configured timeout_minutes +; If true, will use EXPIRE from $_SESSION['__Laminas']['csrf']['EXPIRE'] +; If false, will use timeout_minutes setting +use_session_expire = true + +; Session timeout in minutes (used only when use_session_expire = false) +timeout_minutes = 60 diff --git a/languages/en.ini b/languages/en.ini index 86065b49e22..10bf06822b8 100644 --- a/languages/en.ini +++ b/languages/en.ini @@ -1329,3 +1329,11 @@ Your Tags = "Your Tags" your_match_would_be_here = "Your match would be here." Zip = "Zip" zoom = "Zoom" +; LOTS begin +session_expired = "Your session has expired. Please login again." +Branch = "Branch" +Available copies = "Available copies" +Total copies = "Total copies" +No book found = "No book found" +Select branch = "Select branch" +; LOTS end diff --git a/languages/en.ini.lots-8.0 b/languages/en.ini.lots-8.0 new file mode 100644 index 00000000000..8ddc6ca8fdb --- /dev/null +++ b/languages/en.ini.lots-8.0 @@ -0,0 +1,12 @@ +; LOTS begin +; Add the contents of this file to your language file in the folder /usr/local/vufind/local/languages or /usr/local/vufind/languages +; English (en.ini) +session_expired = "Your session has expired. Please login again." + +; LotsLerum-160 +Branch = "Branch" +Available copies = "Available copies" +Total copies = "Total copies" +No book found = "No book found" +Select branch = "Select branch" +; LOTS end diff --git a/languages/sv.ini b/languages/sv.ini index f19e52e085d..5ed455aa965 100644 --- a/languages/sv.ini +++ b/languages/sv.ini @@ -1451,3 +1451,11 @@ suggestion_top_paragraph="

Fyll i formuläret för att lämna ett inköpsförs Give suggestions=Inköpsförslag Patron ID=Låntagarnummer ils_availability_detail="
Tillgängliga exemplar: %d/%d +; LOTS begin +session_expired = "Din session har gått ut. Vänligen logga in igen." +Branch = "Filial" +Available copies = "Tillgängliga exemplar" +Total copies = "Totalt antal exemplar" +No book found = "Inga exemplar" +Select branch = "Välj filial" +; LOTS end \ No newline at end of file diff --git a/languages/sv.ini.lots-8.0 b/languages/sv.ini.lots-8.0 new file mode 100644 index 00000000000..ec2ff36b992 --- /dev/null +++ b/languages/sv.ini.lots-8.0 @@ -0,0 +1,12 @@ +; LOTS begin +; Add the contents of this file to your language file in the folder /usr/local/vufind/local/languages or /usr/local/vufind/languages +; Swedish (sv.ini) +session_expired = "Din session har gått ut. Vänligen logga in igen." + +; LotsLerum-160 +Branch = "Filial" +Available copies = "Tillgängliga exemplar" +Total copies = "Totalt antal exemplar" +No book found = "Inga exemplar" +Select branch = "Välj filial" +; LOTS end \ No newline at end of file diff --git a/local/config/vufind/LOTS.ini b/local/config/vufind/LOTS.ini deleted file mode 100644 index b75656ea562..00000000000 --- a/local/config/vufind/LOTS.ini +++ /dev/null @@ -1,15 +0,0 @@ -; LotsLerum-158 -; this code should be added to the end of your current LOTS.ini -; LOTS Session timeout configuration -; Session timeout configuration -[SessionTimeout] -; Enable or disable session timeout modal -enabled = true - -; Use session CSRF EXPIRE time instead of configured timeout_minutes -; If true, will use EXPIRE from $_SESSION['__Laminas']['csrf']['EXPIRE'] -; If false, will use timeout_minutes setting -use_session_expire = true - -; Session timeout in minutes (used only when use_session_expire = false) -timeout_minutes = 60 diff --git a/local/languages/en.ini b/local/languages/en.ini deleted file mode 100644 index ce3f803b0d6..00000000000 --- a/local/languages/en.ini +++ /dev/null @@ -1,2 +0,0 @@ -; English (en.ini) -session_expired = "Your session has expired. Please login again." diff --git a/local/languages/sv.ini b/local/languages/sv.ini deleted file mode 100644 index e36493f3f47..00000000000 --- a/local/languages/sv.ini +++ /dev/null @@ -1,2 +0,0 @@ -; Swedish (sv.ini) -session_expired = "Din session har gått ut. Vänligen logga in igen." diff --git a/module/LOTS/src/LOTS/ILS/Driver/KohaRest.php b/module/LOTS/src/LOTS/ILS/Driver/KohaRest.php index 4e88c8261a6..d024bdd09e6 100644 --- a/module/LOTS/src/LOTS/ILS/Driver/KohaRest.php +++ b/module/LOTS/src/LOTS/ILS/Driver/KohaRest.php @@ -544,5 +544,145 @@ protected function getTransactions($patron, $params, $checkedIn) 'count' => $result['headers']['X-Total-Count'] ?? count($transactions), $arrayKey => $transactions ]; - } + } + + /** + * Helper method to check if debug logging is enabled + * + * @return bool True if debug logging is enabled, false otherwise + */ + protected function isDebugEnabled() + { + return isset($this->lotsConfig->Record->enableDebug) + && $this->lotsConfig->Record->enableDebug == true; + } + + /** + * Conditional debug logging method + * + * @param string $message Debug message to log + */ + protected function debugLog($message) + { + if ($this->isDebugEnabled()) { + $this->debug($message); + } + } + + /** + * Get a list of available branches from Koha (excluding hidden ones). + * + * @return array List of branches with 'id' and 'name' + */ + public function getAvailableBranches() + { + // Cache the result to avoid multiple API calls + if ($this->availableBranches === null) { + $this->availableBranches = []; + + $this->debugLog('Calling getAvailableBranches'); + + try { + // Fetch all branches in one request by setting high _per_page to handle pagination + $response = $this->makeRequest([ + 'path' => ['v1', 'libraries'], + 'query' => ['_per_page' => 100] // Assuming <100 branches; adjust if more + ]); + $this->debugLog('Response from /v1/libraries: ' . var_export($response, true)); + } catch (\Exception $e) { + $this->debugLog('Exception in getAvailableBranches: ' . $e->getMessage()); + return $this->availableBranches; + } + + if ($response && isset($response['data'])) { + foreach ($response['data'] as $branch) { + if (!isset($branch['hidden']) || $branch['hidden'] != 1) { + $this->availableBranches[] = [ + 'id' => $branch['library_id'] ?? $branch['id'] ?? null, + 'name' => $branch['name'] ?? $branch['branchname'] ?? 'Unnamed Branch', + ]; + } + } + } else { + $this->debugLog('No branches data found in response'); + } + + $this->debugLog('Returning branches: ' . var_export($this->availableBranches, true)); + } + + return $this->availableBranches; + } + + /** + * Get availability information for a specific branch or all branches if no branch is specified. + * + * @param string|null $branchId The branch ID to check, or null for all branches + * @param string|null $biblionumber The biblionumber to check availability for + * @return array Array with 'available' and 'total' counts per branch + */ + public function getAvailability($branchId = null, $biblionumber = null) + { + $availability = []; + + $this->debugLog('Calling getAvailability for branch: ' . ($branchId ?? 'all')); + if (!$biblionumber) { + $biblionumber = $this->getBiblionumber(); + if (!$biblionumber) { + $this->debugLog('No biblionumber available, skipping availability check'); + return []; + } + } + + try { + $response = $this->makeRequest( + [ + 'path' => ['v1', 'contrib', 'kohasuomi', 'availability', 'biblios', $biblionumber, 'search'], + ] + ); + $this->debugLog('Response from /v1/contrib/kohasuomi/availability/biblios/' . $biblionumber . '/search: ' . var_export($response, true)); + } catch (\Exception $e) { + $this->debugLog('Exception in getAvailability: ' . $e->getMessage()); + return []; + } + + if ($response && isset($response['data']['item_availabilities'])) { + foreach ($response['data']['item_availabilities'] as $item) { + $holdingLibraryId = $item['holding_library_id']; + if (!isset($availability[$holdingLibraryId])) { + $availability[$holdingLibraryId] = [ + 'available' => 0, + 'total' => 0, + ]; + } + $availability[$holdingLibraryId]['total']++; + if ($item['availability']['available']) { + $availability[$holdingLibraryId]['available']++; + } + } + } else { + $this->debugLog('No items data found in response'); + } + + // If a specific branch is requested, return only that branch's data + if ($branchId && isset($availability[$branchId])) { + return $availability[$branchId]; + } + + $this->debugLog('Returning availability: ' . var_export($availability, true)); + return $availability; + } + + /** + * Get the biblionumber for the current record. + * + * @return string|null Biblionumber or null if not available + */ + protected function getBiblionumber() + { + if (isset($this->driver) && method_exists($this->driver, 'getUniqueID')) { + return $this->driver->getUniqueID(); + } + return null; + } + } diff --git a/themes/lots/templates/RecordDriver/DefaultRecord/core.phtml b/themes/lots/templates/RecordDriver/DefaultRecord/core.phtml index a33d31d14b8..e9d281d65af 100644 --- a/themes/lots/templates/RecordDriver/DefaultRecord/core.phtml +++ b/themes/lots/templates/RecordDriver/DefaultRecord/core.phtml @@ -19,15 +19,20 @@ if (!isset($showSummaryLink)) { // showCorefields[2] = "Language" // showCorefields[3] = "Published" // showCorefields[3] = "Subjects" + $showAllCorefields = $config->Record->showAllCorefields; $showCorefields = $config->Record->showCorefields; -$showCorefields = $showCorefields->toArray(); +if ($showCorefields instanceof Laminas\Config\Config) { + $showCorefields = $showCorefields->toArray(); +} if (!isset($showCorefields)) { $showCorefields = ['nope']; } $showCorefieldPrefixes = $config->Record->showCorefieldPrefixes; -$showCorefieldPrefixes = $showCorefieldPrefixes->toArray(); +if ($showCorefieldPrefixes instanceof Laminas\Config\Config) { + $showCorefieldPrefixes = $showCorefieldPrefixes->toArray(); +} if (!isset($showCorefieldPrefixes)) { $showCorefieldPrefixes = ['nope']; } diff --git a/themes/lots/templates/RecordDriver/DefaultRecord/result-list.phtml b/themes/lots/templates/RecordDriver/DefaultRecord/result-list.phtml index 5e65bc33e98..888bc65784c 100644 --- a/themes/lots/templates/RecordDriver/DefaultRecord/result-list.phtml +++ b/themes/lots/templates/RecordDriver/DefaultRecord/result-list.phtml @@ -160,6 +160,122 @@

record($this->driver)->getPreviews()?>
+ + + +config()->get('LOTS'); +$lots_show_availability_in_results = $config->Record->showAvailabilityInResults ?? false; // Toggle availability display +$lots_enable_debug = $config->Record->enableDebug ?? false; // Toggle debug logging +$max_branches = $config->Record->maxBranches ?? 100; // Maximum number of branches to process + +// Get base URL using VuFind's serverUrl method or config, fallback to relative path +$base_url = method_exists($this, 'serverUrl') ? $this->serverUrl() : ($config->Site->url ?? ''); +$base_url = rtrim($base_url, '/'); // Ensure no trailing slash + +if ($lots_show_availability_in_results == 1): + // Get and validate the record's unique ID + $biblionumber = $this->driver->getUniqueID(); + if (!preg_match('/^[a-zA-Z0-9]+$/', $biblionumber)) { + if ($lots_enable_debug) { + error_log('LOTS Debug: Invalid biblionumber: ' . $biblionumber); + } + $biblionumber = ''; // Prevent invalid ID from being used + } + + // Only proceed if we have a valid biblionumber + if ($biblionumber): + // Get the catalog instance + $catalog = $this->ils(); + + // Fetch availability data for all branches (cached) + $availabilityData = $catalog->getAvailability(null, $biblionumber); + + // Fetch all available branches (cached call) + static $allBranches = null; + if ($allBranches === null) { + $allBranches = []; + $branchData = $catalog->getAvailableBranches(); + foreach ($branchData as $branch) { + $allBranches[$branch['id']] = $branch['name']; + } + } + + // Build valid branches array with proper names + $validBranches = []; + $branchCount = 0; + if (is_array($availabilityData)) { + foreach ($availabilityData as $branchId => $data) { + // Stop processing if max_branches limit is reached + if ($branchCount >= $max_branches) { + if ($lots_enable_debug) { + error_log('LOTS Debug: Max branches limit (' . $max_branches . ') reached. Stopping processing.'); + } + break; + } + + // Validate branch ID format + if (!preg_match('/^[a-zA-Z0-9]+$/', $branchId)) { + if ($lots_enable_debug) { + error_log('LOTS Debug: Invalid branch ID: ' . $branchId); + } + continue; + } + + // Only include branches with items + if ($data['total'] > 0) { + $branchName = isset($allBranches[$branchId]) ? $allBranches[$branchId] : 'Unnamed Branch'; + $validBranches[$branchId] = [ + 'name' => $branchName, + 'available' => $data['available'], + 'total' => $data['total'] + ]; + $branchCount++; + } + } + } + + // Render availability section + if (!empty($validBranches)): + // Calculate total availability across all branches + $totalAvailable = array_sum(array_column($validBranches, 'available')); + $totalCopies = array_sum(array_column($validBranches, 'total')); +?> +
+
+ + +
+ +
+ transEsc('Available copies')?>: + transEsc('Total copies')?>: + +
+
+ +
+
transEsc('No book found')?>
+
+ transEsc('Available copies')?>: 0 + transEsc('Total copies')?>: 0 + +
+
+ + + + + +