@@ -, +, @@ tables - adds a switch to turn off and on row grouping (today's checkouts vs previous checkouts) (on by default) - adds "column settings" for relatives' checkouts tables - factorize some code that was duplicated across the two DataTables configurations (mDataProp) the relatives checkouts table contain at least 10 checkouts. in both tables (sorting, pagination, the data itself, ...) --- admin/columns_settings.yml | 60 +- installer/data/mysql/atomicupdate/bug_15219.sql | 2 + installer/data/mysql/sysprefs.sql | 1 + .../plugins/jquery.dataTables.rowGrouping.js | 10 +- .../prog/en/includes/checkouts-table-footer.inc | 2 +- .../prog/en/includes/checkouts-table.inc | 1 - .../prog/en/includes/checkouts.js.inc | 24 + .../prog/en/includes/columns_settings.inc | 2 +- .../intranet-tmpl/prog/en/includes/strings.inc | 1 + .../en/modules/admin/preferences/circulation.pref | 6 + .../prog/en/modules/circ/circulation.tt | 13 +- .../prog/en/modules/members/moremember.tt | 12 +- koha-tmpl/intranet-tmpl/prog/js/checkouts.js | 748 ++++++++++----------- svc/checkouts | 105 +-- 14 files changed, 519 insertions(+), 468 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_15219.sql create mode 100644 koha-tmpl/intranet-tmpl/prog/en/includes/checkouts.js.inc --- a/admin/columns_settings.yml +++ a/admin/columns_settings.yml @@ -209,7 +209,7 @@ modules: moremember: issues-table: - - columnname: sort_order + columnname: group_order cannot_be_toggled: 1 cannot_be_modified: 1 is_hidden: 1 @@ -218,11 +218,6 @@ modules: cannot_be_toggled: 1 cannot_be_modified: 1 is_hidden: 1 - - - columnname: due_date_unformatted - cannot_be_toggled: 1 - cannot_be_modified: 1 - is_hidden: 1 - columnname: due_date - @@ -255,6 +250,29 @@ modules: columnname: export cannot_be_toggled: 1 cannot_be_modified: 1 + relatives-issues-table: + - + columnname: due_date + - + columnname: title + - + columnname: item_type + - + columnname: location + - + columnname: checkout_on + - + columnname: checkout_from + - + columnname: callno + - + columnname: charge + - + columnname: fine + - + columnname: price + - + columnname: patron holdshistory: holdshistory-table: @@ -321,7 +339,7 @@ modules: circulation: issues-table: - - columnname: sort_order + columnname: group_order cannot_be_toggled: 1 cannot_be_modified: 1 is_hidden: 1 @@ -330,11 +348,6 @@ modules: cannot_be_toggled: 1 cannot_be_modified: 1 is_hidden: 1 - - - columnname: due_date_unformatted - cannot_be_toggled: 1 - cannot_be_modified: 1 - is_hidden: 1 - columnname: due_date - @@ -367,6 +380,29 @@ modules: columnname: export cannot_be_toggled: 1 cannot_be_modified: 1 + relatives-issues-table: + - + columnname: due_date + - + columnname: title + - + columnname: item_type + - + columnname: location + - + columnname: checkout_on + - + columnname: checkout_from + - + columnname: callno + - + columnname: charge + - + columnname: fine + - + columnname: price + - + columnname: patron returns: checkedintable: --- a/installer/data/mysql/atomicupdate/bug_15219.sql +++ a/installer/data/mysql/atomicupdate/bug_15219.sql @@ -0,0 +1,2 @@ +INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) +VALUES ('ServerSideCheckoutsTables','0',NULL,'If enabled, use the "server-side processing" feature for checkouts tables. Can improve performance when there is a big number of checkouts to display.','YesNo'); --- a/installer/data/mysql/sysprefs.sql +++ a/installer/data/mysql/sysprefs.sql @@ -488,6 +488,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('SelfCheckTimeout','120','','Define the number of seconds before the Web-based Self Checkout times out a patron','Integer'), ('SeparateHoldings','0',NULL,'Separate current branch holdings from other holdings','YesNo'), ('SeparateHoldingsBranch','homebranch','homebranch|holdingbranch','Branch used to separate holdings','Choice'), +('ServerSideCheckoutsTables','0',NULL,'If enabled, use the "server-side processing" feature for checkouts tables. Can improve performance when there is a big number of checkouts per patron.','YesNo'), ('SessionRestrictionByIP','1','Check for change in remote IP address for session security. Disable only when remote IP address changes frequently.','','YesNo'), ('SessionStorage','mysql','mysql|Pg|tmp','Use database or a temporary file for storing session data','Choice'), ('ShelfBrowserUsesCcode','1','0','Use the item collection code when finding items for the shelf browser.','YesNo'), --- a/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.dataTables.rowGrouping.js +++ a/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.dataTables.rowGrouping.js @@ -608,15 +608,15 @@ } - oTable.fnSetColumnVis(properties.iGroupingColumnIndex, !properties.bHideGroupingColumn); + oTable.fnSetColumnVis(properties.iGroupingColumnIndex, !properties.bHideGroupingColumn, false); if (properties.bCustomColumnOrdering) { - oTable.fnSetColumnVis(properties.iGroupingOrderByColumnIndex, !properties.bHideGroupingOrderByColumn); + oTable.fnSetColumnVis(properties.iGroupingOrderByColumnIndex, !properties.bHideGroupingOrderByColumn, false); } if (properties.iGroupingColumnIndex2 != -1) { - oTable.fnSetColumnVis(properties.iGroupingColumnIndex2, !properties.bHideGroupingColumn2); + oTable.fnSetColumnVis(properties.iGroupingColumnIndex2, !properties.bHideGroupingColumn2, false); } if (properties.bCustomColumnOrdering2) { - oTable.fnSetColumnVis(properties.iGroupingOrderByColumnIndex2, !properties.bHideGroupingOrderByColumn2); + oTable.fnSetColumnVis(properties.iGroupingOrderByColumnIndex2, !properties.bHideGroupingOrderByColumn2, false); } oTable.fnSettings().aoDrawCallback.push({ "fn": _fnDrawCallBackWithGrouping, @@ -687,4 +687,4 @@ }); }; -})(jQuery); +})(jQuery); --- a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table-footer.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table-footer.inc @@ -1,6 +1,6 @@ - Totals: + Totals: [% totaldue %] [% finetotal %] [% totalprice %] --- a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc @@ -13,7 +13,6 @@     Due date - Due date Title Item type Location --- a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts.js.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts.js.inc @@ -0,0 +1,24 @@ +[% USE Koha %] + + + + --- a/koha-tmpl/intranet-tmpl/prog/en/includes/columns_settings.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/columns_settings.inc @@ -40,7 +40,7 @@ function KohaTable(id_selector, dt_parameters, columns_settings, add_filters) { table.dataTable($.extend(true, {}, dataTablesDefaults, dt_parameters)); $(hidden_ids).each(function(index, value) { - table.fnSetColumnVis( value, false ); + table.fnSetColumnVis( value, false, false ); }); if ( add_filters ) { --- a/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc @@ -43,5 +43,6 @@ var SUSPEND_HOLD_ERROR_NOT_FOUND = _("Unable to suspend hold, hold not found"); var RESUME_HOLD_ERROR_NOT_FOUND = _("Unable to resume, hold not found"); var CURRENT = _(" (current) "); + var GROUP_TODAYS_CHECKOUTS = _("Group today's checkouts"); //]]> --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -52,6 +52,12 @@ Circulation: asc: earliest to latest desc: latest to earliest - due date. + - + - pref: ServerSideCheckoutsTables + choices: + yes: Enable + no: Do not enable + - server-side processing on checkouts tables. It can improve performance when there is a big number of checkouts to display. - - pref: SpecifyDueDate choices: --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -847,7 +847,6 @@ No patron matched [% message | html %] - @@ -981,24 +980,16 @@ No patron matched [% message | html %] [% INCLUDE 'timepicker.inc' %] - + [% INCLUDE 'checkouts.js.inc' %] - + [% INCLUDE 'checkouts.js.inc' %] @@ -559,22 +558,13 @@ /* Set some variable needed in circulation.js */ var interface = "[% interface %]"; var theme = "[% theme %]"; - var borrowernumber = "[% patron.borrowernumber %]"; var branchcode = "[% Branches.GetLoggedInBranchcode() %]"; var exports_enabled = "[% Koha.Preference('ExportCircHistory') %]"; - var AllowCirculate = [% (CAN_user_circulate_circulate_remaining_permissions)? 1 : 0 %] - var AllowRenewalLimitOverride = [% (CAN_user_circulate_override_renewals && Koha.Preference('AllowRenewalLimitOverride') )? 1: 0 %]; var script = "moremember"; - var relatives_borrowernumbers = new Array(); - [% FOREACH b IN relatives_borrowernumbers %] - relatives_borrowernumbers.push("[% b %]"); - [% END %] var MSG_EXPORT_SELECT_CHECKOUTS = _("You must select checkout(s) to export"); var MSG_CONFIRM_DELETE_MESSAGE = _("Are you sure you want to delete this message? This cannot be undone."); - columns_settings = [% ColumnsSettings.GetColumns( 'members', 'moremember', 'issues-table', 'json' ) %] - $(document).ready(function() { if ( $('#clubs-tab').length ) { $('#clubs-tab-link').on('click', function() { --- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js +++ a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js @@ -1,3 +1,267 @@ +(function($) { + +var ymd = $.datepicker.formatDate('yy-mm-dd', new Date()); + +function enableGrouping(datatable) { + datatable.rowGrouping({ + iGroupingColumnIndex: 1, + iGroupingOrderByColumnIndex: 0, + sGroupingColumnSortDirection: "desc" + }); +} + +function disableGrouping(datatable) { + var oSettings = datatable.fnSettings(); + for (f = 0; f < oSettings.aoDrawCallback.length; f++) { + if (oSettings.aoDrawCallback[f].sName == 'fnRowGrouping') { + oSettings.aoDrawCallback.splice(f, 1); + oSettings.aaSortingFixed = null; + datatable.fnDraw(); + break; + } + } +} + +var mRenders = { + groupOrder: function (oData, sType, oObj) { + if ( oObj.issued_today ) { + return "1"; + } else { + return "0"; + } + }, + groupName: function (oData, sType, oObj) { + if (oObj.issued_today) { + return "" + TODAYS_CHECKOUTS + ""; + } else { + return "" + PREVIOUS_CHECKOUTS + ""; + } + }, + dateDueFormatted: function (oData, sType, oObj) { + var due = oObj.date_due_formatted; + + if ( oObj.date_due_overdue ) { + due = "" + due + ""; + } + + due = "" + due + ""; + + if ( oObj.lost ) { + due += "" + oObj.lost + ""; + } + + if ( oObj.damaged ) { + due += "" + oObj.damaged + ""; + } + + return due; + }, + title: function (oData, sType, oObj) { + var title = "" + + oObj.title; + + $.each(oObj.subtitle, function( index, value ) { + title += " " + value.subfield; + }); + + if ( oObj.enumchron ) { + title += " (" + oObj.enumchron + ")"; + } + + title += ""; + + if ( oObj.author ) { + title += " " + BY.replace( "_AUTHOR_", " " + oObj.author ); + } + + if ( oObj.itemnotes ) { + var span_class = "text-muted"; + if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) { + span_class = "circ-hlt"; + } + title += " - " + oObj.itemnotes + ""; + } + + if ( oObj.itemnotes_nonpublic ) { + var span_class = "text-danger"; + if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) { + span_class = "circ-hlt"; + } + title += " - " + oObj.itemnotes_nonpublic + ""; + } + + var onsite_checkout = ''; + if ( oObj.onsite_checkout == 1 ) { + onsite_checkout += " (" + INHOUSE_USE + ")"; + } + + title += " " + + "" + + oObj.barcode + + "" + + onsite_checkout + + return title; + }, + itemtype: function (oData, sType, oObj) { + return oObj.itemtype_description; + }, + issuedate: function (oData, sType, oObj) { + return oObj.issuedate_formatted; + }, + branch: function (oData, sType, oObj) { + return oObj.branchname; + }, + charge: function (oData, sType, oObj) { + if (!oObj.charge) oObj.charge = 0; + return '' + parseFloat(oObj.charge).toFixed(2) + ''; + }, + fine: function (oData, sType, oObj) { + if (!oObj.fine) oObj.fine = 0; + return '' + parseFloat(oObj.fine).toFixed(2) + ''; + }, + price: function (oData, sType, oObj) { + if (!oObj.price) oObj.price = 0; + return parseFloat(oObj.price).toFixed(2); + }, + renew: function (oData, sType, oObj) { + var content = ""; + var span_style = ""; + var span_class = ""; + + content += ""; + content += "" + oObj.renewals_count + ""; + + if ( oObj.can_renew ) { + // Do nothing + } else if ( oObj.can_renew_error == "on_reserve" ) { + content += "" + + "" + ON_HOLD + "" + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "too_many" ) { + content += "" + + NOT_RENEWABLE + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "restriction" ) { + content += "" + + NOT_RENEWABLE_RESTRICTION + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "overdue" ) { + content += "" + + NOT_RENEWABLE_OVERDUE + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "too_soon" ) { + content += "" + + NOT_RENEWABLE_TOO_SOON.format( oObj.can_renew_date ) + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "auto_too_soon" ) { + content += "" + + NOT_RENEWABLE_AUTO_TOO_SOON + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "auto_too_late" ) { + content += "" + + NOT_RENEWABLE_AUTO_TOO_LATE + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "auto_too_much_oweing" ) { + content += "" + + NOT_RENEWABLE_AUTO_TOO_MUCH_OWEING + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "auto_account_expired" ) { + content += "" + + NOT_RENEWABLE_AUTO_ACCOUNT_EXPIRED + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "auto_renew" ) { + content += "" + + NOT_RENEWABLE_AUTO_RENEW + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "onsite_checkout" ) { + // Don't display something if it's an onsite checkout + } else { + content += "" + + oObj.can_renew_error + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } + + var can_force_renew = ( oObj.onsite_checkout == 0 ) && ( oObj.can_renew_error != "on_reserve" ); + var can_renew = ( oObj.renewals_remaining > 0 && !oObj.can_renew_error ); + if ( can_renew || can_force_renew ) { + content += "" + + "" + + ""; + + content += "(" + + RENEWALS_REMAINING.format( oObj.renewals_remaining, oObj.renewals_allowed ) + + ")"; + } + + content += ""; + + return content; + }, + checkin: function (oData, sType, oObj) { + if (oObj.can_renew_error == "on_reserve") { + return "" + ON_HOLD + ""; + } else { + return ""; + } + }, + export: function (oData, sType, oObj) { + var s = ""; + + s += ""; + return s; + }, + patron: function (oData, sType, oObj) { + return "" + + oObj.borrower.firstname + " " + oObj.borrower.surname + " (" + oObj.borrower.cardnumber + ")" + } +}; + $(document).ready(function() { $.ajaxSetup ({ cache: false }); @@ -152,8 +416,6 @@ $(document).ready(function() { return false; }); - var ymd = $.datepicker.formatDate('yy-mm-dd', new Date()); - $('#issues-table').hide(); $('#issues-table-actions').hide(); $('#issues-table-load-immediately').change(function(){ @@ -187,16 +449,24 @@ $(document).ready(function() { "sProcessing": MSG_DT_LOADING_RECORDS, }, "bAutoWidth": false, - "dom": 'B<"clearfix">rt', + "bProcessing": true, + "bServerSide": ServerSideCheckoutsTables, + "sAjaxSource": "/cgi-bin/koha/svc/checkouts", + "fnServerParams": function (aoData) { + aoData.push({ "name": "borrowernumber", "value": borrowernumber }); + }, + "bPaginate": true, + "sPaginationType": "four_button", + "dom": 'B<"clearfix"><"top pager"ilp>rt', + "aaSorting": [], "aoColumns": [ { - "mDataProp": function( oObj ) { - return oObj.sort_order; - } + "mData": "issued_today", + "mRender": mRenders.groupOrder }, { - "mDataProp": function( oObj ) { - if ( oObj.issued_today ) { + "mData": function (oObj) { + if (oObj.issued_today) { return "" + TODAYS_CHECKOUTS + ""; } else { return "" + PREVIOUS_CHECKOUTS + ""; @@ -204,251 +474,57 @@ $(document).ready(function() { } }, { - "mDataProp": "date_due", - "bVisible": false, + "mData": "date_due", + "mRender": mRenders.dateDueFormatted }, { - "iDataSort": 2, // Sort on hidden unformatted date due column - "mDataProp": function( oObj ) { - var due = oObj.date_due_formatted; - - if ( oObj.date_due_overdue ) { - due = "" + due + ""; - } - - due = "" + due + ""; - - if ( oObj.lost ) { - due += "" + oObj.lost + ""; - } - - if ( oObj.damaged ) { - due += "" + oObj.damaged + ""; - } - - var patron_note = " "; - due +="
" + patron_note; - - return due; - } + "mData": "title", + "mRender": mRenders.title }, { - "mDataProp": function ( oObj ) { - title = "" - + oObj.title; - - $.each(oObj.subtitle, function( index, value ) { - title += " " + value.subfield; - }); - - if ( oObj.enumchron ) { - title += " (" + oObj.enumchron + ")"; - } - - title += ""; - - if ( oObj.author ) { - title += " " + BY.replace( "_AUTHOR_", " " + oObj.author ); - } - - if ( oObj.itemnotes ) { - var span_class = "text-muted"; - if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) { - span_class = "circ-hlt"; - } - title += " - " + oObj.itemnotes + ""; - } - - if ( oObj.itemnotes_nonpublic ) { - var span_class = "text-danger"; - if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) { - span_class = "circ-hlt"; - } - title += " - " + oObj.itemnotes_nonpublic + ""; - } - - var onsite_checkout = ''; - if ( oObj.onsite_checkout == 1 ) { - onsite_checkout += " (" + INHOUSE_USE + ")"; - } - - title += " " - + "" - + oObj.barcode - + "" - + onsite_checkout - - return title; - }, - "sType": "anti-the" + "mData": "itemtype", + "mRender": mRenders.itemtype }, - { "mDataProp": "itemtype_description" }, - { "mDataProp": "location" }, - { "mDataProp": "homebranch" }, - { "mDataProp": "issuedate_formatted" }, - { "mDataProp": "branchname" }, - { "mDataProp": "itemcallnumber" }, + { "mData": "location" }, + { "mData": "homebranch" }, { - "mDataProp": function ( oObj ) { - if ( ! oObj.charge ) oObj.charge = 0; - return '' + parseFloat(oObj.charge).toFixed(2) + ''; - } + "mData": "issuedate", + "mRender": mRenders.issuedate }, { - "mDataProp": function ( oObj ) { - if ( ! oObj.fine ) oObj.fine = 0; - return '' + parseFloat(oObj.fine).toFixed(2) + ''; - } + "mData": "branchcode", + "mRender": mRenders.branch }, + { "mData": "itemcallnumber" }, { - "mDataProp": function ( oObj ) { - if ( ! oObj.price ) oObj.price = 0; - return '' + parseFloat(oObj.price).toFixed(2) + ''; - } + "mData": "charge", + "mRender": mRenders.charge, + "bSortable": ServerSideCheckoutsTables ? false : true + }, + { + "mData": "fine", + "mRender": mRenders.fine, + "bSortable": ServerSideCheckoutsTables ? false : true + }, + { + "mData": "replacementprice", + "mRender": mRenders.price, + "bSortable": ServerSideCheckoutsTables ? false : true }, { - "bSortable": false, "bVisible": AllowCirculate ? true : false, - "mDataProp": function ( oObj ) { - var content = ""; - var span_style = ""; - var span_class = ""; - - content += ""; - content += "" + oObj.renewals_count + ""; - - if ( oObj.can_renew ) { - // Do nothing - } else if ( oObj.can_renew_error == "on_reserve" ) { - content += "" - + "" + ON_HOLD + "" - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } else if ( oObj.can_renew_error == "too_many" ) { - content += "" - + NOT_RENEWABLE - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } else if ( oObj.can_renew_error == "restriction" ) { - content += "" - + NOT_RENEWABLE_RESTRICTION - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } else if ( oObj.can_renew_error == "overdue" ) { - content += "" - + NOT_RENEWABLE_OVERDUE - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } else if ( oObj.can_renew_error == "too_soon" ) { - content += "" - + NOT_RENEWABLE_TOO_SOON.format( oObj.can_renew_date ) - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } else if ( oObj.can_renew_error == "auto_too_soon" ) { - content += "" - + NOT_RENEWABLE_AUTO_TOO_SOON - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } else if ( oObj.can_renew_error == "auto_too_late" ) { - content += "" - + NOT_RENEWABLE_AUTO_TOO_LATE - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } else if ( oObj.can_renew_error == "auto_too_much_oweing" ) { - content += "" - + NOT_RENEWABLE_AUTO_TOO_MUCH_OWEING - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } else if ( oObj.can_renew_error == "auto_account_expired" ) { - content += "" - + NOT_RENEWABLE_AUTO_ACCOUNT_EXPIRED - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } else if ( oObj.can_renew_error == "auto_renew" ) { - content += "" - + NOT_RENEWABLE_AUTO_RENEW - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } else if ( oObj.can_renew_error == "onsite_checkout" ) { - // Don't display something if it's an onsite checkout - } else { - content += "" - + oObj.can_renew_error - + ""; - - span_style = "display: none"; - span_class = "renewals-allowed"; - } - - var can_force_renew = ( oObj.onsite_checkout == 0 ) && ( oObj.can_renew_error != "on_reserve" ); - var can_renew = ( oObj.renewals_remaining > 0 && !oObj.can_renew_error ); - if ( can_renew || can_force_renew ) { - content += "" - + "" - + ""; - - content += "(" - + RENEWALS_REMAINING.format( oObj.renewals_remaining, oObj.renewals_allowed ) - + ")"; - } - - content += ""; - - return content; - } + "mRender": mRenders.renew, + "bSortable": false }, { - "bSortable": false, "bVisible": AllowCirculate ? true : false, - "mDataProp": function ( oObj ) { - if ( oObj.can_renew_error == "on_reserve" ) { - return "" + ON_HOLD + ""; - } else { - return ""; - } - } + "mRender": mRenders.checkin, + "bSortable": false }, { "bVisible": exports_enabled == 1 ? true : false, "bSortable": false, - "mDataProp": function ( oObj ) { - var s = ""; - - s += ""; - return s; - } + "mRender": mRenders.export } ], "fnFooterCallback": function ( nRow, aaData, iStart, iEnd, aiDisplay ) { @@ -463,39 +539,30 @@ $(document).ready(function() { $("#totaldue").html(total_charge.toFixed(2)); $("#totalfine").html(total_fine.toFixed(2)); $("#totalprice").html(total_price.toFixed(2)); - }, - "bPaginate": false, - "bProcessing": true, - "bServerSide": false, - "sAjaxSource": '/cgi-bin/koha/svc/checkouts', - "fnServerData": function ( sSource, aoData, fnCallback ) { - aoData.push( { "name": "borrowernumber", "value": borrowernumber } ); - - $.getJSON( sSource, aoData, function (json) { - fnCallback(json) - } ); - }, - "fnInitComplete": function(oSettings) { - // Disable rowGrouping plugin after first use - // so any sorting on the table doesn't use it - var oSettings = issuesTable.fnSettings(); - - for (f = 0; f < oSettings.aoDrawCallback.length; f++) { - if (oSettings.aoDrawCallback[f].sName == 'fnRowGrouping') { - oSettings.aoDrawCallback.splice(f, 1); - break; - } - } - - oSettings.aaSortingFixed = null; - }, - }, columns_settings).rowGrouping( - { - iGroupingColumnIndex: 1, - iGroupingOrderByColumnIndex: 0, - sGroupingColumnSortDirection: "asc" } - ); + }, columns_settings); + + enableGrouping(issuesTable); + + var groupingSwitch = $('') + .attr('id', 'issues-table-row-grouping-switch') + .attr('checked', 'checked') + .css('vertical-align', 'middle') + .change(function() { + if ($(this).is(':checked')) { + enableGrouping(issuesTable); + } else { + disableGrouping(issuesTable); + } + }); + $('
') + .css('float', 'left') + .css('padding', '0.3em 0.5em') + .css('line-height', '1.9em') + .append(groupingSwitch) + .append(' ') + .append('') + .appendTo('#issues-table_wrapper .top.pager'); if ( $("#issues-table").length ) { $("#issues-table_processing").position({ @@ -509,129 +576,60 @@ $(document).ready(function() { var relativesIssuesTable; $("#relatives-issues-tab").click( function() { if ( ! relativesIssuesTable ) { - relativesIssuesTable = $("#relatives-issues-table").dataTable({ + relativesIssuesTable = KohaTable("#relatives-issues-table", { "bAutoWidth": false, - "sDom": "rt", - "aaSorting": [], + "sDom": 'C<"top pager"ilp>rt', + "aaSorting": [[4, "desc"]], + "bProcessing": true, + "bServerSide": ServerSideCheckoutsTables, + "sAjaxSource": "/cgi-bin/koha/svc/checkouts", + "fnServerParams": function (aoData) { + for (i in relatives_borrowernumbers) { + var borrowernumber = relatives_borrowernumbers[i]; + aoData.push({ "name": "borrowernumber", "value": borrowernumber }); + } + }, + "bPaginate": true, + "sPaginationType": "four_button", "aoColumns": [ { - "mDataProp": "date_due", - "bVisible": false, + "mData": "date_due", + "mRender": mRenders.dateDueFormatted }, { - "iDataSort": 1, // Sort on hidden unformatted date due column - "mDataProp": function( oObj ) { - var today = new Date(); - var due = new Date( oObj.date_due ); - if ( today > due ) { - return "" + oObj.date_due_formatted + ""; - } else { - return oObj.date_due_formatted; - } - } + "mData": "title", + "mRender": mRenders.title, }, + { "mData": "itemtype" }, + { "mData": "location" }, { - "mDataProp": function ( oObj ) { - title = "" - + oObj.title; - - $.each(oObj.subtitle, function( index, value ) { - title += " " + value.subfield; - }); - - if ( oObj.enumchron ) { - title += " (" + oObj.enumchron + ")"; - } - - title += ""; - - if ( oObj.author ) { - title += " " + BY.replace( "_AUTHOR_", " " + oObj.author ); - } - - if ( oObj.itemnotes ) { - var span_class = ""; - if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) { - span_class = "circ-hlt"; - } - title += " - " + oObj.itemnotes + "" - } - - if ( oObj.itemnotes_nonpublic ) { - var span_class = ""; - if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) { - span_class = "circ-hlt"; - } - title += " - " + oObj.itemnotes_nonpublic + "" - } - - var onsite_checkout = ''; - if ( oObj.onsite_checkout == 1 ) { - onsite_checkout += " (" + INHOUSE_USE + ")"; - } - - title += " " - + "" - + oObj.barcode - + "" - + onsite_checkout; - - return title; - }, - "sType": "anti-the" + "mData": "issuedate", + "mRender": mRenders.issuedate }, - { "mDataProp": "itemtype" }, - { "mDataProp": "location" }, - { "mDataProp": "issuedate_formatted" }, - { "mDataProp": "branchname" }, - { "mDataProp": "itemcallnumber" }, + { "mData": "branchname" }, + { "mData": "itemcallnumber" }, { - "mDataProp": function ( oObj ) { - if ( ! oObj.charge ) oObj.charge = 0; - return parseFloat(oObj.charge).toFixed(2); - } + "mData": "charge", + "mRender": mRenders.charge, + "bSortable": ServerSideCheckoutsTables ? false : true }, { - "mDataProp": function ( oObj ) { - if ( ! oObj.fine ) oObj.fine = 0; - return parseFloat(oObj.fine).toFixed(2); - } + "mData": "fine", + "mRender": mRenders.fine, + "bSortable": ServerSideCheckoutsTables ? false : true }, { - "mDataProp": function ( oObj ) { - if ( ! oObj.price ) oObj.price = 0; - return parseFloat(oObj.price).toFixed(2); - } + "mData": "replacementprice", + "mRender": mRenders.price, + "bSortable": ServerSideCheckoutsTables ? false : true }, { - "mDataProp": function( oObj ) { - return "" - + oObj.borrower.firstname + " " + oObj.borrower.surname + " (" + oObj.borrower.cardnumber + ")" - } - }, - ], - "bPaginate": false, - "bProcessing": true, - "bServerSide": false, - "sAjaxSource": '/cgi-bin/koha/svc/checkouts', - "fnServerData": function ( sSource, aoData, fnCallback ) { - $.each(relatives_borrowernumbers, function( index, value ) { - aoData.push( { "name": "borrowernumber", "value": value } ); - }); - - $.getJSON( sSource, aoData, function (json) { - fnCallback(json) - } ); - }, - }); + "mData": "borrowernumber", + "mRender": mRenders.patron, + "bSortable": ServerSideCheckoutsTables ? false : true + } + ] + }, relatives_columns_settings); } }); @@ -651,4 +649,6 @@ $(document).ready(function() { } } ).prop('checked', false); } - }); +}); + +})(jQuery); --- a/svc/checkouts +++ a/svc/checkouts @@ -27,6 +27,7 @@ use C4::Biblio qw(GetMarcBiblio GetFrameworkCode GetRecordValue ); use C4::Circulation qw(GetIssuingCharges CanBookBeRenewed GetRenewCount GetSoonestRenewDate); use C4::Overdues qw(GetFine); use C4::Context; +use C4::Utils::DataTables; use Koha::AuthorisedValues; use Koha::DateUtils; @@ -45,26 +46,33 @@ unless (haspermission($userid, { circulate => 'circulate_remaining_permissions' exit 0; } -my @sort_columns = qw/date_due title itype issuedate branchcode itemcallnumber/; - my @borrowernumber = $input->multi_param('borrowernumber'); -my $offset = $input->param('iDisplayStart'); -my $results_per_page = $input->param('iDisplayLength') || -1; - -my $sorting_column = $input->param('iSortCol_0') || q{}; -$sorting_column = ( $sorting_column && $sort_columns[$sorting_column] ) ? $sort_columns[$sorting_column] : 'issuedate'; - -my $sorting_direction = $input->param('sSortDir_0') || q{}; -$sorting_direction = $sorting_direction eq 'asc' ? 'asc' : 'desc'; - -$results_per_page = undef if ( $results_per_page == -1 ); - -binmode STDOUT, ":encoding(UTF-8)"; -print $input->header( -type => 'text/plain', -charset => 'UTF-8' ); +my $offset = $input->param('iDisplayStart'); +my $count = $input->param('iDisplayLength'); + +my %params = dt_get_params($input); +my $orderby = dt_build_orderby(\%params); + +my $todaysIssuesDefaultSortOrder = + C4::Context->preference('todaysIssuesDefaultSortOrder'); +my $previousIssuesDefaultSortOrder = + C4::Context->preference('previousIssuesDefaultSortOrder'); + +# Default sort when user hasn't clicked on a column header yet. +# When row grouping is enabled, DataTables ask to sort on issued_today column, +# so we need to treat this case the same as the "no sorting" case +if (!$orderby || $orderby =~ m/ORDER BY issued_today desc\s*$/) { + $orderby = qq{ + ORDER BY + issued_today DESC, + CASE WHEN issued_today = 0 THEN date_due END $previousIssuesDefaultSortOrder, + CASE WHEN issued_today != 0 THEN date_due END $todaysIssuesDefaultSortOrder + }; +} my @parameters; my $sql = ' - SELECT + SELECT SQL_CALC_FOUND_ROWS issuedate, date_due, date_due < now() as date_due_overdue, @@ -100,7 +108,7 @@ my $sql = ' location, items.enumchron, - DATEDIFF( issuedate, CURRENT_DATE() ) AS not_issued_today + DATEDIFF( issuedate, CURRENT_DATE() ) = 0 AS issued_today FROM issues LEFT JOIN items USING ( itemnumber ) LEFT JOIN biblio USING ( biblionumber ) @@ -108,27 +116,33 @@ my $sql = ' LEFT JOIN borrowers USING ( borrowernumber ) LEFT JOIN branches ON ( issues.branchcode = branches.branchcode ) LEFT JOIN branches branches2 ON ( items.homebranch = branches2.branchcode ) - WHERE borrowernumber + WHERE '; +my $borrowernumber_sql = 'borrowernumber'; if ( @borrowernumber == 1 ) { - $sql .= '= ?'; -} -else { - $sql .= ' IN (' . join( ',', ('?') x @borrowernumber ) . ') '; + $borrowernumber_sql .= ' = ?'; +} else { + $borrowernumber_sql .= ' IN (' . join( ',', ('?') x @borrowernumber ) . ') '; } +$sql .= $borrowernumber_sql; push( @parameters, @borrowernumber ); -$sql .= " ORDER BY $sorting_column $sorting_direction "; +$sql .= " $orderby"; + +if ($count && $count > 0) { + $sql .= " LIMIT ?,?"; + push @parameters, $offset, $count; +} my $dbh = C4::Context->dbh(); my $sth = $dbh->prepare($sql); $sth->execute(@parameters); +my ($iTotalDisplayRecords) = $dbh->selectrow_array('SELECT FOUND_ROWS()'); my $item_level_itypes = C4::Context->preference('item-level_itypes'); -my @checkouts_today; -my @checkouts_previous; +my @checkouts; while ( my $c = $sth->fetchrow_hashref() ) { my ($charge) = GetIssuingCharges( $c->{itemnumber}, $c->{borrowernumber} ); my $fine = GetFine( $c->{itemnumber}, $c->{borrowernumber} ); @@ -219,36 +233,25 @@ while ( my $c = $sth->fetchrow_hashref() ) { firstname => $c->{firstname}, cardnumber => $c->{cardnumber}, }, - issued_today => !$c->{not_issued_today}, + issued_today => $c->{issued_today} ? JSON::true : JSON::false, }; - if ( $c->{not_issued_today} ) { - push( @checkouts_previous, $checkout ); - } - else { - push( @checkouts_today, $checkout ); - } + push @checkouts, $checkout; } +binmode STDOUT, ":encoding(UTF-8)"; +print $input->header( -type => 'application/json', -charset => 'UTF-8' ); -@checkouts_today = sort { $a->{timestamp} cmp $b->{timestamp} } @checkouts_today; -@checkouts_today = reverse(@checkouts_today) - unless ( C4::Context->preference('todaysIssuesDefaultSortOrder') eq 'desc' ); - -@checkouts_previous = sort { $a->{date_due} cmp $b->{date_due} } @checkouts_previous; -@checkouts_previous = reverse(@checkouts_previous) - if ( C4::Context->preference('previousIssuesDefaultSortOrder') eq 'desc' ); - -my @checkouts = ( @checkouts_today, @checkouts_previous ); - -my $i = 1; -map { $_->{sort_order} = $i++ } @checkouts; - +my $sEcho = $input->param('sEcho'); +my ($iTotalRecords) = $dbh->selectrow_array( + "SELECT COUNT(*) FROM issues WHERE $borrowernumber_sql", undef, + @borrowernumber); -my $data; -$data->{'iTotalRecords'} = scalar @checkouts; -$data->{'iTotalDisplayRecords'} = scalar @checkouts; -$data->{'sEcho'} = $input->param('sEcho') || undef; -$data->{'aaData'} = \@checkouts; +my $response = { + iTotalRecords => $iTotalRecords, + iTotalDisplayRecords => $iTotalDisplayRecords, + sEcho => $sEcho, + aaData => \@checkouts, +}; -print to_json($data); +print to_json($response); --
Due date (unformatted, hidden) Due date Title Item type