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

[FINNA-2662] Adjust loan history export to use paging #3076

Open
wants to merge 25 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9c2bf86
Paging for exporting transaction history until work processor is impl…
LuomaJuha Nov 4, 2024
3c602e0
Adjusted loan history to show form to download
LuomaJuha Nov 5, 2024
9a549d9
Added csrf
LuomaJuha Nov 5, 2024
0d6b1c2
QA
LuomaJuha Nov 5, 2024
4cfe9cc
Adjusted translations
LuomaJuha Nov 5, 2024
33616de
Adjustments to loan history downloading
LuomaJuha Nov 15, 2024
5573fca
Added comments to template
LuomaJuha Nov 15, 2024
2d99afd
Merge branch 'dev' into add-paging-to-history
LuomaJuha Jan 3, 2025
a19346e
Adjusted to fetch file from ajax handler
LuomaJuha Jan 13, 2025
c78eb63
Removed unused files and translations
LuomaJuha Jan 13, 2025
4497c6d
Adjusted translation, reverted change to demo driver
LuomaJuha Jan 13, 2025
81b6326
Adjusted page numbers
LuomaJuha Jan 13, 2025
42c1d18
Remove useless ilsdefaults
LuomaJuha Jan 13, 2025
00fe1dd
Adjusted comments
LuomaJuha Jan 13, 2025
7ab3039
Removed unused use
LuomaJuha Jan 13, 2025
701d067
Merge branch 'dev' into add-paging-to-history
LuomaJuha Jan 15, 2025
e473b62
Changed naming from transactions to checkouts
LuomaJuha Jan 15, 2025
39061ab
Added comments
LuomaJuha Jan 15, 2025
9ba8d20
Removed unused parameter type
LuomaJuha Jan 15, 2025
6ca8bb4
Adjusted js comments
LuomaJuha Jan 15, 2025
6931dbf
Removed test variable..
LuomaJuha Jan 16, 2025
1d742b5
Adjusted to calculate history properly
LuomaJuha Jan 16, 2025
6125ab8
Added test for GetCheckoutHistory
LuomaJuha Jan 16, 2025
c6a274c
small tuning to test
LuomaJuha Jan 16, 2025
dc5359c
Fix
LuomaJuha Jan 17, 2025
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
4 changes: 4 additions & 0 deletions local/config/finna/config.ini.sample
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,10 @@ library_cards = true
; memory problems for users with a large number of historic loans). Default = 50
;historic_loan_page_size = 50

; Limit for how many historic transactions to fetch at most from ILS
; when downloading loan history
loan_history_download_batch_limit = 1000

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tämä ei näytä vaikuttavan dropdownissa näkyvään sivumäärään.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ny pitäis taas vaikuttaa!


; Whether to display the item barcode for each loan. Default is false.
display_checked_out_item_barcode = true

Expand Down
11 changes: 7 additions & 4 deletions local/languages/finna/en-gb.ini
Original file line number Diff line number Diff line change
Expand Up @@ -599,10 +599,13 @@ list_order_saved = "Sort order saved"
list-tags-info = "Add a new keyword"
Loading = "Loading"
Loan Details = "Loan Details"
loan_history_download = "Export all"
loan_history_download_csv = "Export CSV"
loan_history_download_ods = "Export OpenOffice (ods)"
loan_history_download_xlsx = "Export Excel (xlsx)"
loan_history_download = "Download loan history"
loan_history_download_csv = "CSV"
loan_history_download_ods = "OpenOffice (ods)"
loan_history_download_xlsx = "Excel (xlsx)"
loan_history_info = "Pages downloaded at most %%total%%"
EreMaijala marked this conversation as resolved.
Show resolved Hide resolved
loan_history_pages = "Pages available to download: %%total%%"
loan_history_choose_file_format = "Choose file format"
loan_history_purge = "Purge History"
loan_history_purge_prompt_html = "Are you sure you will purge the loan history? Cleared loan history cannot be retrieved anymore."
loan_history_purge_selected = "Purge Selected"
Expand Down
11 changes: 7 additions & 4 deletions local/languages/finna/fi.ini
Original file line number Diff line number Diff line change
Expand Up @@ -589,10 +589,13 @@ list_order_saved = "Järjestys tallennettu"
list-tags-info = "Lisää uusi avainsana"
Loading = "Ladataan"
Loan Details = "Lainan tiedot"
loan_history_download = "Vie kaikki"
loan_history_download_csv = "Vie CSV"
loan_history_download_ods = "Vie OpenOffice (ods)"
loan_history_download_xlsx = "Vie Excel (xlsx)"
loan_history_download = "Lataa lainaushistoria"
loan_history_download_csv = "CSV"
loan_history_download_ods = "OpenOffice (ods)"
loan_history_download_xlsx = "Excel (xlsx)"
loan_history_info = "Sivuja ladataan korkeintaan %%total%%"
loan_history_pages = "Sivuja ladattavana: %%total%%"
loan_history_choose_file_format = "Valitse tiedostomuoto"
loan_history_purge = "Tyhjennä historia"
loan_history_purge_prompt_html = "Oletko varma, että haluat tyhjentää lainaushistoriasi? Tyhjennettyä historiaa ei saa takaisin."
loan_history_purge_selected = "Poista valitut"
Expand Down
11 changes: 7 additions & 4 deletions local/languages/finna/sv.ini
Original file line number Diff line number Diff line change
Expand Up @@ -587,10 +587,13 @@ list_order_saved = "Sortering sparad"
list-tags-info = "Lägg till nytt nyckelord"
Loading = "Laddar"
Loan Details = "Information om lånet"
loan_history_download = "Exportera alla"
loan_history_download_csv = "Exportera CSV"
loan_history_download_ods = "Exportera OpenOffice (ods)"
loan_history_download_xlsx = "Exportera Excel (xlsx)"
loan_history_download = "Ladda lånehistorik"
loan_history_download_csv = "CSV"
loan_history_download_ods = "OpenOffice (ods)"
loan_history_download_xlsx = "Excel (xlsx)"
loan_history_info = "Sidorna laddas högst %%total%%"
loan_history_pages = "Sidorna tillgängliga för nedladdning: %%total%%"
loan_history_choose_file_format = "Välja filformat"
loan_history_purge = "Rensa historiken"
loan_history_purge_prompt_html = "Är du säker på att du vill rensa din utlåningshistorik? Raderad historik kan inte återskapas."
loan_history_purge_selected = "Radera valda"
Expand Down
225 changes: 128 additions & 97 deletions module/Finna/src/Finna/Controller/MyResearchController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1347,116 +1347,147 @@ public function downloadLoanHistoryAction()
'getMyTransactionHistory',
$patron
);

if (false === $functionConfig) {
$this->flashMessenger()->addErrorMessage('ils_action_unavailable');
return $this->redirect()->toRoute('checkouts-history');
}
$fileFormat = $this->params()->fromQuery('format', '');
if (!in_array($fileFormat, ['ods', 'csv', 'xlsx'])) {
throw new \Exception('Invalid parameters.');

$allowedFileFormats = ['csv', 'ods', 'xlsx'];
$historyResult = $this->forwardTo('checkouts', 'history');
if (!isset($historyResult->transactions)) {
return $historyResult;
}
$batchLimit = $this->getConfig()->Catalog->loan_history_download_batch_limit ?? 1000;
$pagesTotal = $historyResult->paginator ? $historyResult->paginator->count() : 1;
$pagesDownloadCounter = 1;
// Calculate how many times required to fetch from ILS to achieve the $batchLimit
if ($pagesTotal > 1) {
$pagesDownloadCounter = ceil($batchLimit / $historyResult->paginator->getItemCountPerPage());
}
if (!$this->formWasSubmitted('submitLoanHistoryRequest')) {
$view = $this->createViewModel([
'fileFormats' => $allowedFileFormats,
'params' => $historyResult->params,
'pagesTotal' => $pagesTotal,
'pagesDownloadCounter' => $pagesDownloadCounter,
]);
$view->setTemplate('checkouts/downloadhistory.phtml');
return $view;
}
$request = $this->getRequest();
if (!$request->isPost()) {
throw new \Exception('Invalid method.');
}

$recordLoader = $this->serviceLocator->get(\VuFind\Record\Loader::class);
$page = 1;
try {
$tmp = fopen('php://temp/maxmemory:' . (5 * 1024 * 1024), 'r+');
$header = [
$this->translate('Title'),
$this->translate('Format'),
$this->translate('Author'),
$this->translate('Publication Year'),
$this->translate('Institution'),
$this->translate('Borrowing Location'),
$this->translate('Checkout Date'),
$this->translate('Return Date'),
$this->translate('Due Date'),
];
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray($header);
if ('xlsx' === $fileFormat) {
Cell::setValueBinder(new AdvancedValueBinder());
}
do {
// Try to use large page size, but take ILS limits into account
$pageOptions = $this->getPaginationHelper()
->getOptions($page, null, 1000, $functionConfig);
$result = $catalog
->getMyTransactionHistory($patron, $pageOptions['ilsParams']);
// Do CSRF check
$csrf = $this->serviceLocator->get(\VuFind\Validator\CsrfInterface::class);
if (!$csrf->isValid($request->getPost('csrf'))) {
throw new \VuFind\Exception\BadRequest('error_inconsistent_parameters');
}
$fileFormat = $request->getPost('history_file_format', '');
if (!in_array($fileFormat, $allowedFileFormats)) {
throw new \Exception('Invalid format.');
}

if (isset($result['success']) && !$result['success']) {
$this->flashMessenger()->addErrorMessage($result['status']);
return $this->redirect()->toRoute('checkouts-history');
}
$startPage = (int)$request->getPost('startPage', 1);
$lastPage = min($startPage + $pagesDownloadCounter, $pagesTotal);

$ids = [];
foreach ($result['transactions'] as $current) {
$id = $current['id'] ?? '';
$source = $current['source'] ?? DEFAULT_SEARCH_BACKEND;
$ids[] = compact('id', 'source');
}
$records = $recordLoader->loadBatch($ids, true);
foreach ($result['transactions'] as $i => $current) {
$driver = $records[$i];
$format = $driver->getFormats();
$format = end($format);
$author = $driver->tryMethod('getNonPresenterAuthors');

$loan = [];
$loan[] = $current['title'] ?? $driver->getTitle() ?? '';
$loan[] = $this->translate($format);
$loan[] = $author[0]['name'] ?? '';
$loan[] = $current['publication_year'] ?? '';
$loan[] = empty($current['institution_name'])
? ''
: $this->translateWithPrefix('location_', $current['institution_name']);
$loan[] = empty($current['borrowingLocation'])
? ''
: $this->translateWithPrefix('location_', $current['borrowingLocation']);
$loan[] = $current['checkoutDate'] ?? '';
$loan[] = $current['returnDate'] ?? '';
$loan[] = $current['dueDate'] ?? '';

$nextRow = $worksheet->getHighestRow() + 1;
$worksheet->fromArray($loan, null, 'A' . (string)$nextRow);
}
$recordLoader = $this->serviceLocator->get(\VuFind\Record\Loader::class);
$tmp = fopen('php://temp/maxmemory:' . (5 * 1024 * 1024), 'r+');

$pageEnd = $pageOptions['ilsPaging']
? ceil($result['count'] / $pageOptions['limit'])
: 1;
$page++;
} while ($page <= $pageEnd);
if ('xlsx' === $fileFormat) {
$worksheet->getStyle('G2:I' . $worksheet->getHighestRow())
->getNumberFormat()
->setFormatCode('dd.mm.yyyy');
foreach (['G', 'H', 'I'] as $col) {
$worksheet->getColumnDimension($col)->setAutoSize(true);
}
$transactions = [];
for ($i = $startPage; $i <= $lastPage; $i++) {
$result = $catalog->getMyTransactionHistory($patron, $historyResult->params);
if (isset($result['success']) && !$result['success']) {
$this->flashMessenger()->addErrorMessage($result['status']);
return $this->redirect()->toRoute('checkouts-history');
}
$response = $this->getResponse();
$response->getHeaders()
->addHeaderLine(
'Content-Type',
$this->exportFormats[$fileFormat]['mediaType']
);
$writer = new $this->exportFormats[$fileFormat]['writer']($spreadsheet);
$writer->save($tmp);

$response->getHeaders()
->addHeaderLine(
'Content-Disposition',
'attachment; filename="finna-loan-history.' . $fileFormat . '"'
);

rewind($tmp);
// Break if no transactions found
if (empty($result['transactions'])) {
break;
}
$transactions = array_merge($transactions, $result['transactions']);
}
$ids = [];
foreach ($transactions as $current) {
$id = $current['id'] ?? '';
$source = $current['source'] ?? DEFAULT_SEARCH_BACKEND;
$ids[] = compact('id', 'source');
}
$records = $recordLoader->loadBatch($ids, true);

$header = [
$this->translate('Title'),
$this->translate('Format'),
$this->translate('Author'),
$this->translate('Publication Year'),
$this->translate('Institution'),
$this->translate('Borrowing Location'),
$this->translate('Checkout Date'),
$this->translate('Return Date'),
$this->translate('Due Date'),
];

$response->setContent(stream_get_contents($tmp));
} catch (\Exception $e) {
$this->flashMessenger()->addErrorMessage('An error has occurred');
return $this->redirect()->toRoute('checkouts-history');
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray($header);

if ('xlsx' === $fileFormat) {
Cell::setValueBinder(new AdvancedValueBinder());
}

foreach ($transactions as $i => $current) {
$driver = $records[$i];
$format = $driver->getFormats();
$format = end($format);
$author = $driver->tryMethod('getNonPresenterAuthors');

$loan = [];
$loan[] = $current['title'] ?? $driver->getTitle() ?? '';
$loan[] = $this->translate($format);
$loan[] = $author[0]['name'] ?? '';
$loan[] = $current['publication_year'] ?? '';
$loan[] = empty($current['institution_name'])
? ''
: $this->translateWithPrefix('location_', $current['institution_name']);
$loan[] = empty($current['borrowingLocation'])
? ''
: $this->translateWithPrefix('location_', $current['borrowingLocation']);
$loan[] = $current['checkoutDate'] ?? '';
$loan[] = $current['returnDate'] ?? '';
$loan[] = $current['dueDate'] ?? '';

$nextRow = $worksheet->getHighestRow() + 1;
$worksheet->fromArray($loan, null, 'A' . (string)$nextRow);
}
if ('xlsx' === $fileFormat) {
$worksheet->getStyle('G2:I' . $worksheet->getHighestRow())
->getNumberFormat()
->setFormatCode('dd.mm.yyyy');
foreach (['G', 'H', 'I'] as $col) {
$worksheet->getColumnDimension($col)->setAutoSize(true);
}
}
$response = $this->getResponse();
$response->getHeaders()
->addHeaderLine(
'Content-Type',
$this->exportFormats[$fileFormat]['mediaType']
);
$writer = new $this->exportFormats[$fileFormat]['writer']($spreadsheet);
$writer->save($tmp);
$fileName = implode('-', ['finna-loan-history-pages', $startPage, $lastPage]);
$fileName .= ".$fileFormat";
$response->getHeaders()
->addHeaderLine(
'Content-Disposition',
'attachment; filename="' . $fileName . '"'
);

rewind($tmp);

$response->setContent(stream_get_contents($tmp));
return $response;
}

Expand Down
34 changes: 34 additions & 0 deletions themes/finna2/templates/checkouts/downloadhistory.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!-- START of: finna - myresearch/downloadhistory.phtml -->
<?php
// Set up page title:
$this->headTitle($this->translate('loan_history_download'));

// Set up breadcrumbs:
$this->layout()->breadcrumbs = '<li><a href="' . $this->url('myresearch-home') . '">' . $this->transEsc('Your Account') . '</a></li> <li class="active">' . $this->transEsc('Loan History') . '</li>';
?>
<?=$this->context($this)->renderInContext('myresearch/menu.phtml', ['active' => 'historicLoans']); ?>

<div class="<?=$this->layoutClass('mainbody-myresearch')?>">
<h2><?=$this->transEsc('loan_history_download')?></h2>
<form name="download-loan-history-form" action="<?=$this->url('myresearch-downloadloanhistory')?>" method="POST" enctype="multipart/form-data">
<input type="hidden" name="csrf" value="<?=$this->escapeHtmlAttr($this->auth()->getManager()->getCsrfHash())?>">
<div class="alert alert-info">
<span><?=$this->transEsc('loan_history_info', ['%%total%%' => $this->pagesDownloadCounter])?></span>
</div>
<span><?=$this->transEsc('loan_history_pages', ['%%total%%' => $this->pagesTotal])?></span>
<div class="form-group">
<label class="control-label" for="history_start_index"><?=$this->transEsc('Start Page');?>:</label>
<input class="form-control" id="history_start_index" name="startPage" type="number" value="1" min="1" max="<?=$this->escapeHtmlAttr($this->pagesTotal)?>">
</div>
<div class="form-group">
<label class="control-label" for="history_file_new"><?=$this->transEsc('loan_history_choose_file_format')?>:</label>
<select class="form-control" name="history_file_format" id="history_file_new">
<?php foreach ($this->fileFormats as $format): ?>
<option value="<?=$this->escapeHtmlAttr($format)?>"><?=$this->transEscWithPrefix('loan_history_download_', $format);?></option>
<?php endforeach; ?>
</select>
</div>
<button data-lightbox-ignore class="btn btn-primary" type="submit" name="submitLoanHistoryRequest" value="<?=$this->transEscAttr('Submit')?>"><?=$this->transEsc('Submit');?></button>
</form>
</div>
<!-- END of: finna - myresearch/downloadhistory.phtml -->
19 changes: 4 additions & 15 deletions themes/finna2/templates/checkouts/history.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,10 @@
</div>
<?php if (!empty($this->transactions)): ?>
<div class="btn-group">
<div class="dropdown loan-history-download">
<button class="btn btn-primary btn-finna-toolbar dropdown-toggle download" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<?=$this->transEsc('loan_history_download')?> <span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-<?php if ($purgeSelectedAllowed): ?>right<?php else: ?>left<?php endif;?> download">
<li>
<a data-lightbox href="<?=$this->url('myresearch-savehistoricloans') ?>"><?=$this->transEsc('loan_history_save')?></a>
</li>
<?php foreach (['csv', 'ods', 'xlsx'] as $format): ?>
<li>
<a href="<?=$this->url('myresearch-downloadloanhistory', [], ['query' => ['format' => $format]])?>"><?=$this->transEsc('loan_history_download_' . $format)?></a>
</li>
<?php endforeach; ?>
</ul>
</div>
<a data-lightbox class="btn btn-primary btn-finna-toolbar" role="button" href="<?=$this->url('myresearch-savehistoricloans') ?>"><?=$this->transEsc('loan_history_save')?></a>
</div>
<div class="btn-group">
<a class="btn btn-primary btn-finna-toolbar" role="button" href="<?=$this->url('myresearch-downloadloanhistory')?>"><?=$this->transEsc('loan_history_download')?></a>
</div>
<?php endif; ?>
</div>
Expand Down