Bug 29016: Convert log viewer to ajax datatable
The script viewlog.pl it's very slow because it retrieves all action logs at the same time. It should use KohaTables with pagination/number max of returning entries like other Koha tables (API + AJAX wrapper). Test Plan: 1) Apply this patch 2) Rebuild swagger file 3) Restart all the things! 4) Browse to /cgi-bin/koha/tools/viewlog.pl 5) Test functionality, functionality should be no different! * Limit by librarian * Limit by modules * Limit by actions * Object search string * Info search string * Limit by interface * Limit by from date * Limit by to date * Limit by from and to date * Test "Compare" checkboxes ( only two should be selectable at once ) * Test column sorting * Test sharable link * Test output to a file * Test columns show/hide Signed-off-by: David Nind <david@davidnind.com> Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk> Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
4edc85cf29
commit
c861e2dafe
|
|
@ -5,6 +5,7 @@
|
|||
[% USE Branches %]
|
||||
[% USE KohaDates %]
|
||||
[% USE TablesSettings %]
|
||||
[% USE To %]
|
||||
[% PROCESS 'i18n.inc' %]
|
||||
[% SET footerjs = 1 %]
|
||||
[% INCLUDE 'doc-head-open.inc' %]
|
||||
|
|
@ -272,207 +273,28 @@
|
|||
</fieldset>
|
||||
</form>
|
||||
[% IF ( do_it ) %]
|
||||
[% IF ( total ) %]
|
||||
<h3>Log entries</h3>
|
||||
<div id="toolbar" class="btn-toolbar sticky">
|
||||
<a href="#" id="select_none" class="btn btn-link disabled"><i class="fa fa-times"></i> Check none</a>
|
||||
<button class="btn btn-link disabled compare_link"><i class="fa fa-columns"></i> Compare selected</button>
|
||||
</div>
|
||||
<div class="page-section">
|
||||
<table id="logst">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Librarian</th>
|
||||
<th>Module</th>
|
||||
<th>Action</th>
|
||||
<th>Object</th>
|
||||
<th>Info</th>
|
||||
<th>Interface</th>
|
||||
<th>Diff</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
[% FOREACH loopro IN looprow %]
|
||||
<tr>
|
||||
<td data-order="[% loopro.timestamp | html %]">[% loopro.timestamp | $KohaDates with_hours=1 %]</td>
|
||||
<td>
|
||||
[% IF loopro.librarian %]
|
||||
<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% loopro.librarian.borrowernumber | uri %]" title="display detail for this librarian.">
|
||||
[% IF ( loopro.librarian.firstname ) || ( loopro.librarian.surname ) %][% loopro.librarian.firstname | html %] [% loopro.librarian.surname | html %] ([% loopro.librarian.borrowernumber | html %])[% ELSE %][% loopro.librarian.borrowernumber | html %][% END %]</a
|
||||
>
|
||||
[% ELSE %]
|
||||
[% loopro.user | html %]
|
||||
[% END %]
|
||||
</td>
|
||||
<td>[% PROCESS translate_log_module module=loopro.module %]</td>
|
||||
<td>[% PROCESS translate_log_action action=loopro.action %]</td>
|
||||
<td>
|
||||
[% IF ( loopro.module == 'MEMBERS' ) || ( loopro.module == 'CIRCULATION' ) || ( loopro.module == 'FINES' ) || ( loopro.module == 'APIKEYS' ) %]
|
||||
[% IF loopro.patron %]
|
||||
[% IF ( loopro.module == 'APIKEYS' ) %]
|
||||
<a href="/cgi-bin/koha/members/apikeys.pl?patron_id=[% loopro.object | uri %]" title="View API keys for this patron">
|
||||
API keys for [% loopro.patron.firstname | html %] [% loopro.patron.surname | html %] ([% loopro.object | html %])
|
||||
</a>
|
||||
[% ELSE %]
|
||||
<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% loopro.object | uri %]" title="Display member details.">
|
||||
[% IF ( loopro.object ) %][% IF ( loopro.patron.firstname ) || ( loopro.patron.surname ) %]
|
||||
[% loopro.patron.firstname | html %]
|
||||
[% loopro.patron.surname | html %]
|
||||
([% loopro.object | html %])
|
||||
[% ELSE %]
|
||||
<span>Member</span> [% loopro.object | html %]
|
||||
[% END %][% END %]
|
||||
</a>
|
||||
[% END %]
|
||||
[% ELSE %]
|
||||
[% IF ( loopro.module == 'APIKEYS' ) %]
|
||||
API keys for patron [% loopro.object | html %]
|
||||
[% ELSE %]
|
||||
[% loopro.object | html %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
[% ELSIF ( loopro.module == 'CATALOGUING' ) %]
|
||||
[% IF ( loopro.info.substr(0, 4) == 'item' ) %]
|
||||
<a
|
||||
href="/cgi-bin/koha/catalogue/moredetail.pl?item=[% loopro.object | uri %]&biblionumber=[% loopro.biblionumber | uri %]&bi=[% loopro.biblioitemnumber | uri %]#item[% loopro.object | uri %]"
|
||||
>Item [% loopro.object | html %]</a
|
||||
>
|
||||
from
|
||||
<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% loopro.biblionumber | uri %]" title="Display detail for this bibliographic record"
|
||||
>Bibliographic record [% loopro.biblionumber | html %]</a
|
||||
>
|
||||
[% ELSIF ( loopro.info.substr(0, 6) == 'biblio' ) %]
|
||||
<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% loopro.object | uri %]" title="Display detail for this bibliographic record">Bibliographic record [% loopro.object | html %]</a>
|
||||
[% ELSE %]
|
||||
[% loopro.object | html %]
|
||||
[% END %]
|
||||
[% ELSIF ( loopro.module == 'SERIAL' ) %]
|
||||
<a href="/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=[% loopro.object | uri %]">Subscription [% loopro.object | html %] </a>
|
||||
[% ELSIF ( loopro.module == 'AUTHORITIES' ) %]
|
||||
<a href="/cgi-bin/koha/authorities/detail.pl?authid=[% loopro.object | uri %]" title="Display detail for this authority">Authority [% loopro.object | html %]</a>
|
||||
[% ELSIF ( loopro.module == 'NOTICES' ) %]
|
||||
[% IF ( loopro.notice ) %]
|
||||
<a
|
||||
href="/cgi-bin/koha/tools/letter.pl?op=add_form&branchcode=[% loopro.notice.branchcode | uri %]&module=[% loopro.notice.module | uri %]&code=[% loopro.notice.code | uri %]#lang_[% loopro.notice.lang | uri %]"
|
||||
>Notice [% loopro.notice.title | html %] ([% loopro.notice.code | html %])</a
|
||||
>
|
||||
[% ELSE %]
|
||||
[% loopro.object | html %]
|
||||
[% END %]
|
||||
[% ELSIF ( loopro.module == 'RECALLS' ) %]
|
||||
[% IF loopro.recall.item_level %]
|
||||
Item-level recall on
|
||||
<a href="/cgi-bin/koha/catalogue/moredetail.pl?item=[% loopro.recall.item_id | uri %]&biblionumber=[% loopro.recall.biblio_id | uri %]&bi=[% loopro.recall.item.biblioitemnumber | uri %]"
|
||||
>item</a
|
||||
>
|
||||
[% ELSE %]
|
||||
Bibliographic record-level recall on <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% loopro.recall.biblio_id | uri %]">biblio</a>
|
||||
[% END %]
|
||||
[% ELSIF ( loopro.module == 'ACQUISITIONS' && loopro.action == 'ACQUISITION ORDER' && loopro.object ) %]
|
||||
[% IF ( CAN_user_acquisition_order_manage ) %]
|
||||
Basket <a href="/cgi-bin/koha/acqui/basket.pl?basketno=[% loopro.object | uri %]">[% loopro.object | html %]</a>
|
||||
[% ELSE %]
|
||||
Basket [% loopro.object | html %]
|
||||
[% END %]
|
||||
[% ELSIF ( loopro.module == "SUGGESTION" ) %]
|
||||
<a href="/cgi-bin/koha/suggestion/suggestion.pl?suggestionid=[% loopro.object | uri %]&op=show">[% loopro.object | html %]</a>
|
||||
[% ELSE %]
|
||||
[% loopro.object | html %]
|
||||
[% END %]
|
||||
</td>
|
||||
<td>
|
||||
[% IF ( loopro.module == 'CIRCULATION' && loopro.object_found ) %]
|
||||
<a
|
||||
href="/cgi-bin/koha/catalogue/moredetail.pl?itemnumber=[% loopro.info | uri %]&biblionumber=[% loopro.biblionumber | uri %]&bi=[% loopro.biblioitemnumber | uri %]#item[% loopro.info | uri %]"
|
||||
title="Display detail for this item"
|
||||
>Item [% loopro.barcode | html %]</a
|
||||
>
|
||||
[% ELSIF ( loopro.module == 'CIRCULATION' && loopro.json_found ) %]
|
||||
<div class="loginfo" id="loginfo[% loopro.action_id | html %]">
|
||||
<div>
|
||||
<a
|
||||
href="/cgi-bin/koha/catalogue/moredetail.pl?itemnumber=[% loopro.json.itemnumber | uri %]&biblionumber=[% loopro.json.biblionumber | uri %]&bi=[% loopro.json.biblioitemnumber | uri %]#item[% loopro.json.itemnumber | uri %]"
|
||||
title="Display detail for this item"
|
||||
>Item [% loopro.json.barcode | html %] [% loopro.json.branchcode | html %]</a
|
||||
>
|
||||
</div>
|
||||
[% FOREACH force IN loopro.json.forced %]
|
||||
<div class="forced"> [% PROCESS translate_log_override override=force %] </div>
|
||||
[% END %]
|
||||
[% FOREACH confirmation IN loopro.json.confirmations %]
|
||||
<div class="confirmed"> [% PROCESS translate_log_override override=confirmation %] </div>
|
||||
[% END %]
|
||||
</div>
|
||||
[% ELSIF ( loopro.module == 'HOLDS' && loopro.json_found ) %]
|
||||
<div class="loginfo" id="loginfo[% loopro.action_id | html %]">
|
||||
<div>
|
||||
<a href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% loopro.json.biblionumber | uri %]" title="Display holds for this record"
|
||||
>Hold [% loopro.json.hold | html %] on biblio [% loopro.json.biblionumber | html %]</a
|
||||
>
|
||||
[% IF loopro.json.itemnumber %]
|
||||
-
|
||||
<a
|
||||
href="/cgi-bin/koha/catalogue/moredetail.pl?itemnumber=[% loopro.json.itemnumber | uri %]&biblionumber=[% loopro.json.biblionumber | uri %]#item[% loopro.json.itemnumber | uri %]"
|
||||
title="Display detail for this item"
|
||||
>Item [% loopro.json.itemnumber | html %]</a
|
||||
>
|
||||
[% END %]
|
||||
</div>
|
||||
[% FOREACH force IN loopro.json.forced %]
|
||||
<div class="forced"> [% PROCESS translate_log_override override=force %] </div>
|
||||
[% END %]
|
||||
[% FOREACH confirmation IN loopro.json.confirmations %]
|
||||
<div class="confirmed"> [% PROCESS translate_log_override override=confirmation %] </div>
|
||||
[% END %]
|
||||
</div>
|
||||
[% ELSIF loopro.module == "SYSTEMPREFERENCE" || loopro.module == "REPORTS" || loopro.module == "NEWS" %]
|
||||
<div class="loginfo" id="loginfo[% loopro.action_id | html %]">[% loopro.info | trim | html %]</div>
|
||||
<div class="compare_info" id="compare_info[% loopro.action_id | html %]">
|
||||
<!-- prettier-ignore-start -->
|
||||
<label>
|
||||
[% SET split_info = loopro.info.split(' \| ') %]
|
||||
<input type="checkbox" name="diff" id="action_id[% loopro.action_id | html %]" data-actionid="[% loopro.action_id | html %]" data-filter="[% FOREACH info IN split_info %][% IF loop.first %][% info | html %][% END %][% END %]" class="compare" /> Compare</label>
|
||||
<!-- prettier-ignore-end -->
|
||||
</div>
|
||||
[% ELSIF loopro.module == "NOTICES" %]
|
||||
<div class="loginfo" id="loginfo[% loopro.action_id | html %]">[% loopro.info | trim | html %]</div>
|
||||
<div class="compare_info" id="compare_info[% loopro.action_id | html %]">
|
||||
<label
|
||||
><input
|
||||
type="checkbox"
|
||||
name="diff"
|
||||
id="action_id[% loopro.action_id | html %]"
|
||||
data-actionid="[% loopro.action_id | html %]"
|
||||
data-filter="[% IF loopro.notice %][% loopro.notice.title | html %][% ELSE %][% loopro.object | html %][% END %]"
|
||||
class="compare"
|
||||
/>
|
||||
Compare</label
|
||||
>
|
||||
</div>
|
||||
[% ELSE %]
|
||||
<div class="loginfo" id="loginfo[% loopro.action_id | html %]"> [% loopro.info | html %] </div>
|
||||
[% END %]
|
||||
</td>
|
||||
<td>[% PROCESS translate_log_interface log_interface=loopro.interface %]</td>
|
||||
<td class="diff-col">[% loopro.diff | html %]</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- /.page-section -->
|
||||
[% ELSE %]
|
||||
<div class="alert alert-warning">
|
||||
[% IF ( CATALOGUING ) %]
|
||||
No log found for <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% object | url %]">Bibliographic record [% object | html %]</a>.
|
||||
[% ELSIF ( MEMBERS ) %]
|
||||
No log found for <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% object | url %]">[% INCLUDE 'patron-title.inc' %]</a>.
|
||||
[% ELSE %]
|
||||
No log found.
|
||||
[% END %]
|
||||
</div>
|
||||
[% END %]
|
||||
<h3>Log entries</h3>
|
||||
<div id="toolbar" class="btn-toolbar sticky">
|
||||
<a href="#" id="select_none" class="btn btn-link disabled"><i class="fa fa-times"></i> Check none</a>
|
||||
<button class="btn btn-link disabled compare_link"><i class="fa fa-columns"></i> Compare selected</button>
|
||||
</div>
|
||||
<div class="page-section">
|
||||
<table id="logst">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Librarian</th>
|
||||
<th>Module</th>
|
||||
<th>Action</th>
|
||||
<th>Object</th>
|
||||
<th>Info</th>
|
||||
<th>Interface</th>
|
||||
<th>Diff</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<!-- /.page-section -->
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
|
|
@ -519,6 +341,20 @@
|
|||
<script nonce="[% Koha.CSPNonce | $raw %]" data-tt-allowed="true">
|
||||
var table_settings = [% TablesSettings.GetTableSettings('tools', 'logviewer', 'logst', 'json') | $raw %];
|
||||
var CAN_user_parameters_manage_sysprefs = "[% CAN_user_parameters_manage_sysprefs | html %]";
|
||||
var CAN_user_acquisition_order_manage = "[% CAN_user_acquisition_order_manage | html %]";
|
||||
var do_it = [% do_it || 0 | html %];
|
||||
[% IF ( do_it ) %]
|
||||
var search_params = {
|
||||
user: "[% user | html %]",
|
||||
modules: [% To.json(modules || []) | $raw %],
|
||||
actions: [% To.json(actions || []) | $raw %],
|
||||
interfaces: [% To.json(interfaces || []) | $raw %],
|
||||
object: "[% object | html %]",
|
||||
info: "[% info | html %]",
|
||||
datefrom: "[% datefrom | html %]",
|
||||
dateto: "[% dateto | html %]",
|
||||
};
|
||||
[% END %]
|
||||
</script>
|
||||
[% Asset.js("js/viewlog.js") | $raw %]
|
||||
[% END %]
|
||||
|
|
|
|||
|
|
@ -150,58 +150,355 @@ function untickAll(section) {
|
|||
}
|
||||
|
||||
function limitCheckboxes() {
|
||||
var checkboxes = $(".compare");
|
||||
var limit = 2;
|
||||
var compare_link =
|
||||
'<a href="#" class="btn btn-link compare_link"><i class="fa fa-columns"></i> ' +
|
||||
__("View comparison") +
|
||||
"</a>";
|
||||
checkboxes.each(function () {
|
||||
$(this).on("change", function () {
|
||||
var checked = [];
|
||||
checkboxes.each(function () {
|
||||
if ($(this).prop("checked")) {
|
||||
checked.push($(this).data("actionid"));
|
||||
}
|
||||
});
|
||||
if (checked.length > 0) {
|
||||
$("#select_none").removeClass("disabled");
|
||||
} else {
|
||||
$("#select_none").addClass("disabled");
|
||||
$("#logst").DataTable().search("").draw();
|
||||
}
|
||||
if (checked.length == 1) {
|
||||
$("#logst").DataTable().search($(this).data("filter")).draw();
|
||||
humanMsg.displayAlert(
|
||||
__("Showing results for %s").format($(this).data("filter"))
|
||||
);
|
||||
}
|
||||
if (checked.length == 2) {
|
||||
$("#compare_info" + checked[0]).prepend(compare_link);
|
||||
$("#compare_info" + checked[1]).prepend(compare_link);
|
||||
$("button.compare_link").removeClass("disabled");
|
||||
} else if (checked.length > limit) {
|
||||
humanMsg.displayAlert(
|
||||
__("You can select maximum of two checkboxes")
|
||||
);
|
||||
$(this).prop("checked", false);
|
||||
} else if (checked.length < limit) {
|
||||
$("a.compare_link").remove();
|
||||
$("button.compare_link").addClass("disabled");
|
||||
$(document).on("change", ".compare", function () {
|
||||
var checked = [];
|
||||
$(".compare").each(function () {
|
||||
if ($(this).prop("checked")) {
|
||||
checked.push($(this).data("actionid"));
|
||||
}
|
||||
});
|
||||
if (checked.length > 0) {
|
||||
$("#select_none").removeClass("disabled");
|
||||
} else {
|
||||
$("#select_none").addClass("disabled");
|
||||
}
|
||||
if (checked.length == 2) {
|
||||
$("a.compare_link").remove();
|
||||
$("#compare_info" + checked[0]).prepend(compare_link);
|
||||
$("#compare_info" + checked[1]).prepend(compare_link);
|
||||
$("button.compare_link").removeClass("disabled");
|
||||
} else if (checked.length > limit) {
|
||||
humanMsg.displayAlert(
|
||||
__("You can select maximum of two checkboxes")
|
||||
);
|
||||
$(this).prop("checked", false);
|
||||
} else if (checked.length < limit) {
|
||||
$("a.compare_link").remove();
|
||||
$("button.compare_link").addClass("disabled");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var module_labels = {
|
||||
APIKEYS: __("API keys"),
|
||||
AUTH: __("Authentication"),
|
||||
CATALOGUING: __("Cataloging"),
|
||||
AUTHORITIES: __("Authorities"),
|
||||
MEMBERS: __("Patrons"),
|
||||
ACQUISITIONS: __("Acquisitions"),
|
||||
SERIAL: __("Serials"),
|
||||
HOLDS: __("Holds"),
|
||||
ILL: __("Interlibrary loans"),
|
||||
CIRCULATION: __("Circulation"),
|
||||
CLAIMS: __("Claims"),
|
||||
FINES: __("Fines"),
|
||||
SYSTEMPREFERENCE: __("System preferences"),
|
||||
CRONJOBS: __("Cron jobs"),
|
||||
REPORTS: __("Reports"),
|
||||
SEARCHENGINE: __("Search engine"),
|
||||
NOTICES: __("Notices"),
|
||||
NEWS: __("Additional content"),
|
||||
RECALLS: __("Recalls"),
|
||||
SUGGESTION: __("Suggestions"),
|
||||
TRANSFERS: __("Transfers"),
|
||||
};
|
||||
|
||||
var action_labels = {
|
||||
ACTIVATE: __("Activate"),
|
||||
ADD: __("Add"),
|
||||
DELETE: __("Delete"),
|
||||
MODIFY: __("Modify"),
|
||||
REVOKE: __("Revoke"),
|
||||
ISSUE: __("Checkout"),
|
||||
RETURN: __("Return"),
|
||||
CREATE: __("Create"),
|
||||
CANCEL: __("Cancel"),
|
||||
FILL: __("Fill"),
|
||||
RESUME: __("Resume"),
|
||||
SUSPEND: __("Suspend"),
|
||||
RENEW: __("Renew"),
|
||||
RENEWAL: __("Renew"),
|
||||
"CHANGE PASS": __("Change password"),
|
||||
"RESET PASS": __("Reset password"),
|
||||
ADDCIRCMESSAGE: __("Add circulation message"),
|
||||
MODCIRCMESSAGE: __("Modify circulation message"),
|
||||
DELCIRCMESSAGE: __("Delete circulation message"),
|
||||
STATUS_CHANGE: __("Change ILL request status"),
|
||||
PATRON_NOTICE: __("ILL notice sent to patron"),
|
||||
ADD_BASKET: __("Create an acquisitions basket"),
|
||||
MODIFY_BASKET: __("Modify an acquisitions basket"),
|
||||
MODIFY_BASKET_HEADER: __("Modify an acquisitions basket header"),
|
||||
MODIFY_BASKET_USERS: __("Modify an acquisitions basket's users"),
|
||||
CLOSE_BASKET: __("Close an acquisitions basket"),
|
||||
APPROVE_BASKET: __("Approve an acquisitions basket"),
|
||||
REOPEN_BASKET: __("Reopen an acquisitions basket"),
|
||||
CANCEL_ORDER: __("Cancel an order"),
|
||||
CREATE_ORDER: __("Create an order"),
|
||||
MODIFY_ORDER: __("Modify an order"),
|
||||
CREATE_INVOICE_ADJUSTMENT: __("Create an invoice adjustment"),
|
||||
UPDATE_INVOICE_ADJUSTMENT: __("Modify an invoice adjustment"),
|
||||
DELETE_INVOICE_ADJUSTMENT: __("Delete an invoice adjustment"),
|
||||
RECEIVE_ORDER: __("Receive an order"),
|
||||
MODIFY_BUDGET: __("Modify a budget"),
|
||||
CREATE_FUND: __("Create a fund"),
|
||||
MODIFY_FUND: __("Modify a fund"),
|
||||
DELETE_FUND: __("Delete a fund"),
|
||||
CREATE_RESTRICTION: __("Create restriction"),
|
||||
MODIFY_RESTRICTION: __("Modify restriction"),
|
||||
DELETE_RESTRICTION: __("Delete restriction"),
|
||||
Run: __("Run"),
|
||||
End: __("End"),
|
||||
PATRON_MERGE: __("Merge"),
|
||||
EDIT_MAPPINGS: __("Edit mappings"),
|
||||
RESET_MAPPINGS: __("Reset mappings"),
|
||||
"SERIAL CLAIM": __("Serial claim"),
|
||||
"ACQUISITION CLAIM": __("Acquisition claim"),
|
||||
"ACQUISITION ORDER": __("Acquisition order"),
|
||||
OVERDUE: __("Overdue"),
|
||||
EXPIRE: __("Expire"),
|
||||
MODIFY_CARDNUMBER: __("Modify cardnumber"),
|
||||
"RESET 2FA": __("Reset 2FA"),
|
||||
};
|
||||
|
||||
var interface_labels = {
|
||||
INTRANET: __("Staff interface"),
|
||||
OPAC: __("OPAC"),
|
||||
SIP: __("SIP"),
|
||||
COMMANDLINE: __("Command-line"),
|
||||
API: __("REST API"),
|
||||
CRON: __("Cron job"),
|
||||
UPGRADE: __("Upgrade"),
|
||||
};
|
||||
|
||||
function escapeHtml(str) {
|
||||
if (str == null) return "";
|
||||
return $("<span>").text(String(str)).html();
|
||||
}
|
||||
|
||||
function renderObject(data, type, row) {
|
||||
var mod = row.module;
|
||||
var obj = row.object;
|
||||
if (obj == null) return "";
|
||||
|
||||
if (
|
||||
mod == "MEMBERS" ||
|
||||
mod == "CIRCULATION" ||
|
||||
mod == "FINES" ||
|
||||
mod == "APIKEYS"
|
||||
) {
|
||||
if (mod == "APIKEYS") {
|
||||
return (
|
||||
'<a href="/cgi-bin/koha/members/apikeys.pl?patron_id=' +
|
||||
encodeURIComponent(obj) +
|
||||
'">' +
|
||||
__("API keys for patron %s").format(escapeHtml(obj)) +
|
||||
"</a>"
|
||||
);
|
||||
}
|
||||
return (
|
||||
'<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=' +
|
||||
encodeURIComponent(obj) +
|
||||
'">' +
|
||||
escapeHtml(obj) +
|
||||
"</a>"
|
||||
);
|
||||
}
|
||||
|
||||
if (mod == "CATALOGUING") {
|
||||
var info = row.info || "";
|
||||
if (info.substr(0, 6) == "biblio") {
|
||||
return (
|
||||
'<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' +
|
||||
encodeURIComponent(obj) +
|
||||
'">Bibliographic record ' +
|
||||
escapeHtml(obj) +
|
||||
"</a>"
|
||||
);
|
||||
}
|
||||
return escapeHtml(obj);
|
||||
}
|
||||
|
||||
if (mod == "SERIAL") {
|
||||
return (
|
||||
'<a href="/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=' +
|
||||
encodeURIComponent(obj) +
|
||||
'">Subscription ' +
|
||||
escapeHtml(obj) +
|
||||
"</a>"
|
||||
);
|
||||
}
|
||||
|
||||
if (mod == "AUTHORITIES") {
|
||||
return (
|
||||
'<a href="/cgi-bin/koha/authorities/detail.pl?authid=' +
|
||||
encodeURIComponent(obj) +
|
||||
'">Authority ' +
|
||||
escapeHtml(obj) +
|
||||
"</a>"
|
||||
);
|
||||
}
|
||||
|
||||
if (mod == "NOTICES") {
|
||||
return escapeHtml(obj);
|
||||
}
|
||||
|
||||
if (mod == "ACQUISITIONS" && row.action == "ACQUISITION ORDER" && obj) {
|
||||
if (CAN_user_acquisition_order_manage) {
|
||||
return (
|
||||
'Basket <a href="/cgi-bin/koha/acqui/basket.pl?basketno=' +
|
||||
encodeURIComponent(obj) +
|
||||
'">' +
|
||||
escapeHtml(obj) +
|
||||
"</a>"
|
||||
);
|
||||
}
|
||||
return "Basket " + escapeHtml(obj);
|
||||
}
|
||||
|
||||
if (mod == "SUGGESTION") {
|
||||
return (
|
||||
'<a href="/cgi-bin/koha/suggestion/suggestion.pl?suggestionid=' +
|
||||
encodeURIComponent(obj) +
|
||||
'&op=show">' +
|
||||
escapeHtml(obj) +
|
||||
"</a>"
|
||||
);
|
||||
}
|
||||
|
||||
return escapeHtml(obj);
|
||||
}
|
||||
|
||||
function renderInfo(data, type, row) {
|
||||
var mod = row.module;
|
||||
var info = row.info;
|
||||
var action_id = row.action_id;
|
||||
|
||||
if (info == null) return "";
|
||||
|
||||
if (mod == "SYSTEMPREFERENCE" || mod == "REPORTS" || mod == "NEWS") {
|
||||
var split_info = info.split(" | ");
|
||||
var filter_value = escapeHtml(split_info[0]);
|
||||
return (
|
||||
'<div class="loginfo" id="loginfo' +
|
||||
escapeHtml(action_id) +
|
||||
'">' +
|
||||
escapeHtml(info) +
|
||||
"</div>" +
|
||||
'<div class="compare_info" id="compare_info' +
|
||||
escapeHtml(action_id) +
|
||||
'"><label><input type="checkbox" name="diff" id="action_id' +
|
||||
escapeHtml(action_id) +
|
||||
'" data-actionid="' +
|
||||
escapeHtml(action_id) +
|
||||
'" data-filter="' +
|
||||
filter_value +
|
||||
'" class="compare" /> Compare</label></div>'
|
||||
);
|
||||
}
|
||||
|
||||
if (mod == "NOTICES") {
|
||||
return (
|
||||
'<div class="loginfo" id="loginfo' +
|
||||
escapeHtml(action_id) +
|
||||
'">' +
|
||||
escapeHtml(info) +
|
||||
"</div>" +
|
||||
'<div class="compare_info" id="compare_info' +
|
||||
escapeHtml(action_id) +
|
||||
'"><label><input type="checkbox" name="diff" id="action_id' +
|
||||
escapeHtml(action_id) +
|
||||
'" data-actionid="' +
|
||||
escapeHtml(action_id) +
|
||||
'" data-filter="' +
|
||||
escapeHtml(row.object || "") +
|
||||
'" class="compare" /> Compare</label></div>'
|
||||
);
|
||||
}
|
||||
|
||||
var rendered = renderRecordInfo(info);
|
||||
var body = rendered !== null ? rendered : escapeHtml(info);
|
||||
return (
|
||||
'<div class="loginfo" id="loginfo' +
|
||||
escapeHtml(action_id) +
|
||||
'">' +
|
||||
body +
|
||||
"</div>"
|
||||
);
|
||||
}
|
||||
|
||||
function buildApiFilters(params) {
|
||||
var filters = {};
|
||||
|
||||
if (params.user) {
|
||||
filters.user = params.user;
|
||||
}
|
||||
|
||||
if (params.object) {
|
||||
filters.object = params.object;
|
||||
}
|
||||
|
||||
if (params.info) {
|
||||
filters.info = { like: "%" + params.info + "%" };
|
||||
}
|
||||
|
||||
if (params.modules && params.modules.length > 0) {
|
||||
var non_empty = params.modules.filter(function (m) {
|
||||
return m !== "";
|
||||
});
|
||||
if (non_empty.length > 0) {
|
||||
filters.module = non_empty;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.actions && params.actions.length > 0) {
|
||||
var non_empty_actions = params.actions.filter(function (a) {
|
||||
return a !== "";
|
||||
});
|
||||
if (non_empty_actions.length > 0) {
|
||||
// Circulation uses RENEWAL, but Patrons uses RENEW
|
||||
if (non_empty_actions.indexOf("RENEW") !== -1) {
|
||||
non_empty_actions.push("RENEWAL");
|
||||
}
|
||||
filters.action = non_empty_actions;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.interfaces && params.interfaces.length > 0) {
|
||||
var non_empty_ifaces = params.interfaces.filter(function (i) {
|
||||
return i !== "";
|
||||
});
|
||||
if (non_empty_ifaces.length > 0) {
|
||||
filters.interface = non_empty_ifaces;
|
||||
}
|
||||
}
|
||||
|
||||
// Flatpickr always submits dates in YYYY-MM-DD format (dateFormat: "Y-m-d")
|
||||
if (params.datefrom && params.dateto) {
|
||||
filters.timestamp = {
|
||||
">=": params.datefrom + "T00:00:00Z",
|
||||
"<=": params.dateto + "T23:59:59Z",
|
||||
};
|
||||
} else if (params.datefrom) {
|
||||
filters.timestamp = {
|
||||
">=": params.datefrom + "T00:00:00Z",
|
||||
};
|
||||
} else if (params.dateto) {
|
||||
filters.timestamp = {
|
||||
"<=": params.dateto + "T23:59:59Z",
|
||||
};
|
||||
}
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
limitCheckboxes();
|
||||
|
||||
if ($(".compare_info").length == 0) {
|
||||
/* Remove toolbar if there are no system preference
|
||||
entries to compare */
|
||||
$("#toolbar").remove();
|
||||
}
|
||||
|
||||
if ($('input[type="checkbox"][name="modules"]:checked').length == 0) {
|
||||
tickAll("modules");
|
||||
}
|
||||
|
|
@ -259,14 +556,110 @@ $(document).ready(function () {
|
|||
}
|
||||
});
|
||||
|
||||
var logst = $("#logst").kohaTable(
|
||||
{
|
||||
autoWidth: false,
|
||||
order: [[0, "desc"]],
|
||||
pagingType: "full",
|
||||
},
|
||||
table_settings
|
||||
);
|
||||
if (do_it && typeof search_params !== "undefined") {
|
||||
var api_filters = buildApiFilters(search_params);
|
||||
|
||||
$("#logst").kohaTable(
|
||||
{
|
||||
ajax: {
|
||||
url: "/api/v1/action_logs",
|
||||
},
|
||||
order: [[0, "desc"]],
|
||||
pagingType: "full",
|
||||
autoWidth: false,
|
||||
columns: [
|
||||
{
|
||||
data: "timestamp",
|
||||
title: __("Date"),
|
||||
searchable: true,
|
||||
orderable: true,
|
||||
render: function (data, type, row) {
|
||||
if (type == "sort" || type == "type") {
|
||||
return data;
|
||||
}
|
||||
return $datetime(data);
|
||||
},
|
||||
},
|
||||
{
|
||||
data: "user",
|
||||
title: __("Librarian"),
|
||||
searchable: true,
|
||||
orderable: true,
|
||||
render: function (data, type, row) {
|
||||
if (data) {
|
||||
return (
|
||||
'<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=' +
|
||||
encodeURIComponent(data) +
|
||||
'">' +
|
||||
escapeHtml(data) +
|
||||
"</a>"
|
||||
);
|
||||
}
|
||||
return escapeHtml(data);
|
||||
},
|
||||
},
|
||||
{
|
||||
data: "module",
|
||||
title: __("Module"),
|
||||
searchable: true,
|
||||
orderable: true,
|
||||
render: function (data, type, row) {
|
||||
return module_labels[data] || escapeHtml(data);
|
||||
},
|
||||
},
|
||||
{
|
||||
data: "action",
|
||||
title: __("Action"),
|
||||
searchable: true,
|
||||
orderable: true,
|
||||
render: function (data, type, row) {
|
||||
return action_labels[data] || escapeHtml(data);
|
||||
},
|
||||
},
|
||||
{
|
||||
data: "object",
|
||||
title: __("Object"),
|
||||
searchable: true,
|
||||
orderable: true,
|
||||
render: renderObject,
|
||||
},
|
||||
{
|
||||
data: "info",
|
||||
title: __("Info"),
|
||||
searchable: true,
|
||||
orderable: false,
|
||||
render: renderInfo,
|
||||
},
|
||||
{
|
||||
data: "interface",
|
||||
title: __("Interface"),
|
||||
searchable: true,
|
||||
orderable: true,
|
||||
render: function (data, type, row) {
|
||||
if (!data) return "";
|
||||
return (
|
||||
interface_labels[data.toUpperCase()] ||
|
||||
escapeHtml(data)
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
data: "diff",
|
||||
title: __("Diff"),
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
render: function (data, type, row) {
|
||||
if (!data) return "";
|
||||
return renderStructDiff(data);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
table_settings,
|
||||
0,
|
||||
api_filters
|
||||
);
|
||||
}
|
||||
|
||||
$("body").on("click", ".compare_link", function (e) {
|
||||
e.preventDefault();
|
||||
|
|
@ -291,20 +684,6 @@ $(document).ready(function () {
|
|||
$(".compare:checked").prop("checked", false).change();
|
||||
});
|
||||
|
||||
$("td.diff-col").each(function () {
|
||||
var raw = $(this).text().trim();
|
||||
if (raw) {
|
||||
$(this).html(renderStructDiff(raw));
|
||||
}
|
||||
});
|
||||
|
||||
$("div.loginfo").each(function () {
|
||||
var raw = $(this).text().trim();
|
||||
var rendered = renderRecordInfo(raw);
|
||||
if (rendered) {
|
||||
$(this).html(rendered);
|
||||
}
|
||||
});
|
||||
patron_autocomplete($("#user"), {
|
||||
"on-select-callback": function (event, ui) {
|
||||
$("#user").val(ui.item.patron_id);
|
||||
|
|
|
|||
266
tools/viewlog.pl
266
tools/viewlog.pl
|
|
@ -89,171 +89,11 @@ $template->param(
|
|||
);
|
||||
|
||||
if ($do_it) {
|
||||
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
|
||||
my %search_params;
|
||||
|
||||
if ( $datefrom and $dateto ) {
|
||||
my $dateto_endday = dt_from_string($dateto);
|
||||
$dateto_endday->set( # We set last second of day to see all log from that day
|
||||
hour => 23,
|
||||
minute => 59,
|
||||
second => 59
|
||||
);
|
||||
$search_params{'timestamp'} = {
|
||||
-between => [
|
||||
$dtf->format_datetime( dt_from_string($datefrom) ),
|
||||
$dtf->format_datetime($dateto_endday),
|
||||
]
|
||||
};
|
||||
} elsif ($datefrom) {
|
||||
$search_params{'timestamp'} = { '>=' => $dtf->format_datetime( dt_from_string($datefrom) ) };
|
||||
} elsif ($dateto) {
|
||||
my $dateto_endday = dt_from_string($dateto);
|
||||
$dateto_endday->set( # We set last second of day to see all log from that day
|
||||
hour => 23,
|
||||
minute => 59,
|
||||
second => 59
|
||||
);
|
||||
$search_params{'timestamp'} = { '<=' => $dtf->format_datetime($dateto_endday) };
|
||||
}
|
||||
|
||||
# Circulation uses RENEWAL, but Patrons uses RENEW, this helps to find both
|
||||
if ( grep { $_ eq 'RENEW' } @actions ) {
|
||||
push @actions, 'RENEWAL';
|
||||
}
|
||||
|
||||
$search_params{user} = $user if $user;
|
||||
$search_params{module} = { -in => [@modules] } if ( defined $modules[0] and $modules[0] ne '' );
|
||||
$search_params{action} = { -in => [@actions] } if ( defined $actions[0] && $actions[0] ne '' );
|
||||
$search_params{interface} = { -in => [@interfaces] } if ( defined $interfaces[0] && $interfaces[0] ne '' );
|
||||
|
||||
if ( @modules == 1 && $object_type eq 'biblio' ) {
|
||||
|
||||
# Handle 'Modification log' from cataloguing
|
||||
my $biblio = Koha::Biblios->find($object);
|
||||
my @itemnumbers = $biblio->items->get_column('itemnumber');
|
||||
$search_params{'-or'} = [
|
||||
{ -and => { object => $object, info => { -like => 'biblio%' } } },
|
||||
{ -and => { object => \@itemnumbers, info => { -like => 'item%' } } },
|
||||
];
|
||||
$template->param( biblio => $biblio );
|
||||
} else {
|
||||
$search_params{info} = { -like => '%' . $info . '%' } if $info;
|
||||
$search_params{object} = $object if $object;
|
||||
}
|
||||
|
||||
my @logs = Koha::ActionLogs->search( \%search_params )->as_list;
|
||||
|
||||
my @data;
|
||||
foreach my $log (@logs) {
|
||||
my $result = $log->unblessed;
|
||||
|
||||
# Init additional columns for CSV export
|
||||
$result->{'biblionumber'} = q{};
|
||||
$result->{'biblioitemnumber'} = q{};
|
||||
$result->{'barcode'} = q{};
|
||||
|
||||
if ( defined $log->info && substr( $log->info, 0, 4 ) eq 'item' ) {
|
||||
|
||||
# get item information so we can create a working link
|
||||
my $itemnumber = $log->object;
|
||||
my $item = Koha::Items->find($itemnumber);
|
||||
if ($item) {
|
||||
$result->{'object_found'} = 1;
|
||||
$result->{'biblionumber'} = $item->biblionumber;
|
||||
$result->{'biblioitemnumber'} = $item->biblionumber;
|
||||
$result->{'barcode'} = $item->barcode;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $log->module eq "CIRCULATION" ) {
|
||||
my $info = $log->info;
|
||||
my $decoded;
|
||||
my $is_json = eval {
|
||||
$decoded = decode_json($info);
|
||||
1;
|
||||
};
|
||||
|
||||
if ( $is_json && ref($decoded) ) {
|
||||
$result->{'json_found'} = 1;
|
||||
my $item = Koha::Items->find( $decoded->{itemnumber} );
|
||||
if ($item) {
|
||||
$decoded->{biblionumber} = $item->biblionumber;
|
||||
$decoded->{biblioitemnumber} = $item->biblionumber;
|
||||
$decoded->{barcode} = $item->barcode;
|
||||
}
|
||||
$result->{'json'} = $decoded;
|
||||
} else {
|
||||
my $item = Koha::Items->find($info);
|
||||
if ($item) {
|
||||
$result->{'object_found'} = 1;
|
||||
$result->{'biblionumber'} = $item->biblionumber;
|
||||
$result->{'biblioitemnumber'} = $item->biblionumber;
|
||||
$result->{'barcode'} = $item->barcode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#always add firstname and surname for librarian/user
|
||||
if ( $log->user ) {
|
||||
my $patron = Koha::Patrons->find( $log->user );
|
||||
if ( $patron && $output eq 'screen' ) {
|
||||
$result->{librarian} = $patron;
|
||||
}
|
||||
}
|
||||
|
||||
#add firstname and surname for borrower, when using the CIRCULATION, MEMBERS, FINES, APIKEYS
|
||||
if ( $log->module eq "CIRCULATION"
|
||||
|| $log->module eq "MEMBERS"
|
||||
|| $log->module eq "FINES"
|
||||
|| $log->module eq "APIKEYS" )
|
||||
{
|
||||
if ( $log->object ) {
|
||||
my $patron = Koha::Patrons->find( $log->object );
|
||||
if ( $patron && $output eq 'screen' ) {
|
||||
$result->{patron} = $patron;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $log->module eq 'NOTICES' ) {
|
||||
if ( $log->object ) {
|
||||
my $notice = Koha::Notice::Templates->find( { id => $log->object } );
|
||||
if ( $notice && $output eq 'screen' ) {
|
||||
$result->{notice} = $notice->unblessed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# get recall information
|
||||
if ( $log->module eq "RECALLS" ) {
|
||||
if ( $log->object ) {
|
||||
my $recall = Koha::Recalls->find( $log->object );
|
||||
if ( $recall && $output eq 'screen' ) {
|
||||
$result->{recall} = $recall;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( $result->{module} eq 'MEMBERS' ) {
|
||||
my $json_engine = JSON->new->utf8->canonical(1)->pretty(1);
|
||||
if ( $result->{info} && $result->{info} =~ /^[{\[]/ ) {
|
||||
my $perl_info = $json_engine->decode( $result->{info} );
|
||||
$result->{info} = $json_engine->encode($perl_info);
|
||||
}
|
||||
if ( $result->{diff} && $result->{diff} =~ /^[{\[]/ ) {
|
||||
my $perl_diff = $json_engine->decode( $result->{diff} );
|
||||
$result->{diff} = $json_engine->encode($perl_diff);
|
||||
}
|
||||
}
|
||||
push @data, $result;
|
||||
}
|
||||
if ( $output eq "screen" ) {
|
||||
|
||||
# Printing results to screen
|
||||
# Screen output: pass search params to template, DataTable loads via REST API
|
||||
$template->param(
|
||||
logview => 1,
|
||||
total => scalar @data,
|
||||
looprow => \@data,
|
||||
do_it => 1,
|
||||
datefrom => $datefrom,
|
||||
dateto => $dateto,
|
||||
|
|
@ -272,6 +112,110 @@ if ($do_it) {
|
|||
output_html_with_http_headers $input, $cookie, $template->output;
|
||||
} else {
|
||||
|
||||
# CSV export: fetch and enrich data server-side
|
||||
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
|
||||
my %search_params;
|
||||
|
||||
if ( $datefrom and $dateto ) {
|
||||
my $dateto_endday = dt_from_string($dateto);
|
||||
$dateto_endday->set( # We set last second of day to see all log from that day
|
||||
hour => 23,
|
||||
minute => 59,
|
||||
second => 59
|
||||
);
|
||||
$search_params{'timestamp'} = {
|
||||
-between => [
|
||||
$dtf->format_datetime( dt_from_string($datefrom) ),
|
||||
$dtf->format_datetime($dateto_endday),
|
||||
]
|
||||
};
|
||||
} elsif ($datefrom) {
|
||||
$search_params{'timestamp'} = { '>=' => $dtf->format_datetime( dt_from_string($datefrom) ) };
|
||||
} elsif ($dateto) {
|
||||
my $dateto_endday = dt_from_string($dateto);
|
||||
$dateto_endday->set( # We set last second of day to see all log from that day
|
||||
hour => 23,
|
||||
minute => 59,
|
||||
second => 59
|
||||
);
|
||||
$search_params{'timestamp'} = { '<=' => $dtf->format_datetime($dateto_endday) };
|
||||
}
|
||||
|
||||
# Circulation uses RENEWAL, but Patrons uses RENEW, this helps to find both
|
||||
if ( grep { $_ eq 'RENEW' } @actions ) {
|
||||
push @actions, 'RENEWAL';
|
||||
}
|
||||
|
||||
$search_params{user} = $user if $user;
|
||||
$search_params{module} = { -in => [@modules] } if ( defined $modules[0] and $modules[0] ne '' );
|
||||
$search_params{action} = { -in => [@actions] } if ( defined $actions[0] && $actions[0] ne '' );
|
||||
$search_params{interface} = { -in => [@interfaces] } if ( defined $interfaces[0] && $interfaces[0] ne '' );
|
||||
|
||||
if ( @modules == 1 && $object_type eq 'biblio' ) {
|
||||
|
||||
# Handle 'Modification log' from cataloguing
|
||||
my $biblio = Koha::Biblios->find($object);
|
||||
my @itemnumbers = $biblio->items->get_column('itemnumber');
|
||||
$search_params{'-or'} = [
|
||||
{ -and => { object => $object, info => { -like => 'biblio%' } } },
|
||||
{ -and => { object => \@itemnumbers, info => { -like => 'item%' } } },
|
||||
];
|
||||
} else {
|
||||
$search_params{info} = { -like => '%' . $info . '%' } if $info;
|
||||
$search_params{object} = $object if $object;
|
||||
}
|
||||
|
||||
my @logs = Koha::ActionLogs->search( \%search_params )->as_list;
|
||||
|
||||
my @data;
|
||||
foreach my $log (@logs) {
|
||||
my $result = $log->unblessed;
|
||||
|
||||
# Init additional columns for CSV export
|
||||
$result->{'biblionumber'} = q{};
|
||||
$result->{'biblioitemnumber'} = q{};
|
||||
$result->{'barcode'} = q{};
|
||||
|
||||
if ( defined $log->info && substr( $log->info, 0, 4 ) eq 'item' ) {
|
||||
|
||||
# get item information so we can create a working link
|
||||
my $itemnumber = $log->object;
|
||||
my $item = Koha::Items->find($itemnumber);
|
||||
if ($item) {
|
||||
$result->{'biblionumber'} = $item->biblionumber;
|
||||
$result->{'biblioitemnumber'} = $item->biblionumber;
|
||||
$result->{'barcode'} = $item->barcode;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $log->module eq "CIRCULATION" ) {
|
||||
my $info = $log->info;
|
||||
my $decoded;
|
||||
my $is_json = eval {
|
||||
$decoded = decode_json($info);
|
||||
1;
|
||||
};
|
||||
|
||||
if ( $is_json && ref($decoded) ) {
|
||||
my $item = Koha::Items->find( $decoded->{itemnumber} );
|
||||
if ($item) {
|
||||
$decoded->{biblionumber} = $item->biblionumber;
|
||||
$decoded->{biblioitemnumber} = $item->biblionumber;
|
||||
$decoded->{barcode} = $item->barcode;
|
||||
}
|
||||
} else {
|
||||
my $item = Koha::Items->find($info);
|
||||
if ($item) {
|
||||
$result->{'biblionumber'} = $item->biblionumber;
|
||||
$result->{'biblioitemnumber'} = $item->biblionumber;
|
||||
$result->{'barcode'} = $item->barcode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
push @data, $result;
|
||||
}
|
||||
|
||||
# Printing to a csv file
|
||||
my $content = q{};
|
||||
if (@data) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue