From c92cf7173a1e3830215fbfb2d108af60d541a4ec Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Tue, 4 Feb 2014 12:42:55 -0500 Subject: [PATCH] Bug 11703 - Convert checkouts table to ajax datatable When a patron has many checked out items, circulation.pl can take a very long time to load ( on the order of minutes in some cases ). This is primarily due to the processing of the previous checkouts list. If we convert to this table to a datatable that fetches its data via ajax, we can make circulation.pl far more responsive. The same should be done with relative's checkouts as well. Test Plan: 1) Apply this patch 2) Observe that the checkouts and relatives' checkouts tables are now loaded asynchronously 3) Observe and verify the renew and return actions are now ajax based and function in a manner equivilent to how they used to. --- Koha/Schema/Result/Issue.pm | 32 ++- api/checkin.pl | 75 +++ api/checkouts.pl | 137 ++++++ api/renew.pl | 69 +++ circ/circulation.pl | 121 +----- .../intranet-tmpl/prog/en/css/staff-global.css | 2 +- koha-tmpl/intranet-tmpl/prog/en/js/checkouts.js | 267 +++++++++++ .../intranet-tmpl/prog/en/js/pages/circulation.js | 156 +++++-- .../prog/en/modules/circ/circulation.tt | 492 +++++--------------- 9 files changed, 810 insertions(+), 541 deletions(-) create mode 100755 api/checkin.pl create mode 100755 api/checkouts.pl create mode 100755 api/renew.pl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/js/checkouts.js diff --git a/Koha/Schema/Result/Issue.pm b/Koha/Schema/Result/Issue.pm index 282c802..e1838b6 100644 --- a/Koha/Schema/Result/Issue.pm +++ b/Koha/Schema/Result/Issue.pm @@ -184,10 +184,34 @@ __PACKAGE__->belongs_to( # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ZEh31EKBmURMKxDxI+H3EA __PACKAGE__->belongs_to( - "borrower", - "Koha::Schema::Result::Borrower", - { borrowernumber => "borrowernumber" }, - { join_type => "LEFT", on_delete => "CASCADE", on_update => "CASCADE" }, + "borrower", + "Koha::Schema::Result::Borrower", + { borrowernumber => "borrowernumber" }, + { join_type => "LEFT", on_delete => "CASCADE", on_update => "CASCADE" }, +); + +__PACKAGE__->belongs_to( + "item", + "Koha::Schema::Result::Item", + { itemnumber => "itemnumber" }, + { + is_deferrable => 1, + join_type => "LEFT", + on_delete => "CASCADE", + on_update => "CASCADE", + }, +); + +__PACKAGE__->belongs_to( + "branch", + "Koha::Schema::Result::Branch", + { branchcode => "branchcode" }, + { + is_deferrable => 1, + join_type => "LEFT", + on_delete => "CASCADE", + on_update => "CASCADE", + }, ); 1; diff --git a/api/checkin.pl b/api/checkin.pl new file mode 100755 index 0000000..808b5c4 --- /dev/null +++ b/api/checkin.pl @@ -0,0 +1,75 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use CGI; +use JSON qw(to_json); + +use C4::Circulation; +use C4::Items qw(GetBarcodeFromItemnumber); +use C4::Context; +use C4::Auth qw(check_cookie_auth); + +use Koha::DateUtils qw(output_pref_due); + +my $input = new CGI; + +my ( $auth_status, $sessionID ) = + check_cookie_auth( $input->cookie('CGISESSID'), + { circulate => 'circulate_remaining_permissions' } ); + +if ( $auth_status ne "ok" ) { + exit 0; +} + +binmode STDOUT, ":encoding(UTF-8)"; +print $input->header( -type => 'text/plain', -charset => 'UTF-8' ); + +my $itemnumber = $input->param('itemnumber'); +my $borrowernumber = $input->param('borrowernumber'); +my $override_limit = $input->param('override_limit'); +my $exempt_fine = $input->param('exempt_fine'); +my $branchcode = $input->param('branchcode') + || C4::Context->userenv->{'branch'}; + +my $barcode = GetBarcodeFromItemnumber($itemnumber); + +my $data; +$data->{itemnumber} = $itemnumber; +$data->{borrowernumber} = $borrowernumber; +$data->{branchcode} = $branchcode; + +if ( C4::Context->preference("InProcessingToShelvingCart") ) { + my $item = GetItem($itemnumber); + if ( $item->{'location'} eq 'PROC' ) { + $item->{'location'} = 'CART'; + ModItem( $item, $item->{'biblionumber'}, $item->{'itemnumber'} ); + } +} + +if ( C4::Context->preference("ReturnToShelvingCart") ) { + my $item = GetItem($itemnumber); + $item->{'location'} = 'CART'; + ModItem( $item, $item->{'biblionumber'}, $item->{'itemnumber'} ); +} + +( $data->{returned} ) = AddReturn( $barcode, $branchcode, $exempt_fine ); + +print to_json($data); diff --git a/api/checkouts.pl b/api/checkouts.pl new file mode 100755 index 0000000..4aebab1 --- /dev/null +++ b/api/checkouts.pl @@ -0,0 +1,137 @@ +#!/usr/bin/perl + +# This software is placed under the gnu General Public License, v2 (http://www.gnu.org/licenses/gpl.html) + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use CGI; +use JSON qw(to_json); + +use C4::Auth qw(check_cookie_auth); +use C4::Biblio qw(GetMarcBiblio GetFrameworkCode GetRecordValue ); +use C4::Charset; +use C4::Circulation qw(GetIssuingCharges CanBookBeRenewed GetRenewCount); +use C4::Context; + +use Koha::Database; +use Koha::DateUtils; + +my $input = new CGI; + +my ( $auth_status, $sessionID ) = + check_cookie_auth( $input->cookie('CGISESSID'), + { circulate => 'circulate_remaining_permissions' } ); + +if ( $auth_status ne "ok" ) { + exit 0; +} + +my $schema = Koha::Database->new()->schema(); + +my @sort_columns = qw/date_due title itype issuedate branchcode itemcallnumber/; + +my @borrowernumber = $input->param('borrowernumber'); +my $offset = $input->param('iDisplayStart'); +my $results_per_page = $input->param('iDisplayLength'); +my $sorting_column = $sort_columns[ $input->param('iSortCol_0') ] || 'issuedate'; +my $sorting_direction = $input->param('sSortDir_0') || '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 $checkouts_rs = $schema->resultset('Issue')->search( + { borrowernumber => \@borrowernumber }, + { + prefetch => { 'item' => 'biblio' }, + order_by => { "-$sorting_direction" => $sorting_column } + } +); + +my $borrower; +my @checkouts; +while ( my $c = $checkouts_rs->next() ) { + + # No point in fetching this every time if only one borrower + $borrower = $c->borrower() + if ( !$borrower || @borrowernumber > 1 ); + + my $borrowernumber = $borrower->borrowernumber(); + my $itemnumber = $c->item()->itemnumber(); + my $biblionumber = $c->item()->biblionumber(); + + my ($charge) = + GetIssuingCharges( $c->itemnumber()->itemnumber(), $borrowernumber ); + + my ( $can_renew, $can_renew_error ) = + CanBookBeRenewed( $borrowernumber, $itemnumber ); + + my ( $renewals_count, $renewals_allowed, $renewals_remaining ) = + GetRenewCount( $borrowernumber, $itemnumber ); + + push( + @checkouts, + { + DT_RowId => "$itemnumber-$borrowernumber", + title => $c->item()->biblio()->title(), + author => $c->item()->biblio()->author(), + barcode => $c->item()->barcode(), + itemtype => $c->item()->effective_itemtype(), + itemnotes => $c->item()->itemnotes(), + branchcode => $c->branchcode(), + branchname => $c->branch->branchname(), + itemcallnumber => $c->item()->itemcallnumber() || q{}, + charge => $charge, + price => $c->item->replacementprice() || q{}, + can_renew => $can_renew, + can_renew_error => $can_renew_error, + itemnumber => $itemnumber, + borrowernumber => $borrowernumber, + biblionumber => $biblionumber, + issuedate => $c->issuedate(), + date_due => $c->date_due(), + renewals_count => $renewals_count, + renewals_allowed => $renewals_allowed, + renewals_remaining => $renewals_remaining, + issuedate_formatted => + output_pref( dt_from_string( $c->issuedate() ) ), + date_due_formatted => + output_pref_due( dt_from_string( $c->date_due() ) ), + subtitle => GetRecordValue( + 'subtitle', GetMarcBiblio($biblionumber), + GetFrameworkCode($biblionumber) + ), + borrower => { + surname => $borrower->surname(), + firstname => $borrower->firstname(), + cardnumber => $borrower->cardnumber(), + } + } + ); +} + +my $data; +$data->{'iTotalRecords'} = scalar @checkouts; #FIXME +$data->{'iTotalDisplayRecords'} = scalar @checkouts; +$data->{'sEcho'} = $input->param('sEcho') || undef; +$data->{'aaData'} = \@checkouts; + +print to_json($data); diff --git a/api/renew.pl b/api/renew.pl new file mode 100755 index 0000000..42be2de --- /dev/null +++ b/api/renew.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use CGI; +use JSON qw(to_json); + +use C4::Circulation; +use C4::Context; +use C4::Auth qw(check_cookie_auth); + +use Koha::DateUtils qw(output_pref_due dt_from_string); + +my $input = new CGI; + +my ( $auth_status, $sessionID ) = + check_cookie_auth( $input->cookie('CGISESSID'), + { circulate => 'circulate_remaining_permissions' } ); + +if ( $auth_status ne "ok" ) { + exit 0; +} + +binmode STDOUT, ":encoding(UTF-8)"; +print $input->header( -type => 'text/plain', -charset => 'UTF-8' ); + +my $itemnumber = $input->param('itemnumber'); +my $borrowernumber = $input->param('borrowernumber'); +my $override_limit = $input->param('override_limit'); +my $branchcode = $input->param('branchcode') + || C4::Context->userenv->{'branch'}; +my $date_due; +if ( $input->param('date_due') ) { + $date_due = dt_from_string( $input->param('date_due') ); + $date_due->set_hour(23); + $date_due->set_minute(59); +} + +my $data; +$data->{itemnumber} = $itemnumber; +$data->{borrowernumber} = $borrowernumber; +$data->{branchcode} = $branchcode; + +( $data->{renew_okay}, $data->{error} ) = + CanBookBeRenewed( $borrowernumber, $itemnumber, $override_limit ); + +if ( $data->{renew_okay} ) { + $date_due = AddRenewal( $borrowernumber, $itemnumber, $branchcode, $date_due ); + $data->{date_due} = output_pref_due( $date_due ); +} + +print to_json($data); diff --git a/circ/circulation.pl b/circ/circulation.pl index 8af776f..e759eb7 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -42,6 +42,7 @@ use CGI::Session; use C4::Members::Attributes qw(GetBorrowerAttributes); use Koha::Borrower::Debarments qw(GetDebarments); use Koha::DateUtils; +use Koha::Database; use Date::Calc qw( Today @@ -96,14 +97,6 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user ( my $branches = GetBranches(); -my @failedrenews = $query->param('failedrenew'); # expected to be itemnumbers -our %renew_failed = (); -for (@failedrenews) { $renew_failed{$_} = 1; } - -my @failedreturns = $query->param('failedreturn'); -our %return_failed = (); -for (@failedreturns) { $return_failed{$_} = 1; } - my $findborrower = $query->param('findborrower') || q{}; $findborrower =~ s|,| |g; my $borrowernumber = $query->param('borrowernumber'); @@ -355,9 +348,8 @@ if ($barcode) { } } - # FIXME If the issue is confirmed, we launch another time GetMemberIssuesAndFines, now display the issue count after issue - my ( $od, $issue, $fines ) = GetMemberIssuesAndFines( $borrowernumber ); - $template->param( issuecount => $issue ); + my ( $od, $issue, $fines ) = GetMemberIssuesAndFines($borrowernumber); + $template->param( issuecount => $issue ); } # reload the borrower info for the sake of reseting the flags..... @@ -457,100 +449,6 @@ if ($borrowernumber) { $template->param( adultborrower => 1 ) if ( $borrower->{'category_type'} eq 'A' ); } -# make the issued books table. -my $todaysissues = ''; -my $previssues = ''; -our @todaysissues = (); -our @previousissues = (); -our @relissues = (); -our @relprevissues = (); -my $displayrelissues; - -our $totalprice = 0; - -sub build_issue_data { - my $issueslist = shift; - my $relatives = shift; - - # split in 2 arrays for today & previous - foreach my $it ( @$issueslist ) { - my $itemtypeinfo = getitemtypeinfo( (C4::Context->preference('item-level_itypes')) ? $it->{'itype'} : $it->{'itemtype'} ); - - # set itemtype per item-level_itype syspref - FIXME this is an ugly hack - $it->{'itemtype'} = ( C4::Context->preference( 'item-level_itypes' ) ) ? $it->{'itype'} : $it->{'itemtype'}; - - ($it->{'charge'}, $it->{'itemtype_charge'}) = GetIssuingCharges( - $it->{'itemnumber'}, $it->{'borrowernumber'} - ); - $it->{'charge'} = sprintf("%.2f", $it->{'charge'}); - my ($can_renew, $can_renew_error) = CanBookBeRenewed( - $it->{'borrowernumber'},$it->{'itemnumber'} - ); - $it->{"renew_error_${can_renew_error}"} = 1 if defined $can_renew_error; - my $restype = C4::Reserves::GetReserveStatus( $it->{'itemnumber'} ); - $it->{'can_renew'} = $can_renew; - $it->{'can_confirm'} = !$can_renew && !$restype; - $it->{'renew_error'} = ( $restype eq "Waiting" or $restype eq "Reserved" ) ? 1 : 0; - $it->{'checkoutdate'} = C4::Dates->new($it->{'issuedate'},'iso')->output('syspref'); - $it->{'issuingbranchname'} = GetBranchName($it->{'branchcode'}); - - $totalprice += $it->{'replacementprice'} || 0; - $it->{'itemtype'} = $itemtypeinfo->{'description'}; - $it->{'itemtype_image'} = $itemtypeinfo->{'imageurl'}; - $it->{'dd_sort'} = $it->{'date_due'}; - $it->{'dd'} = output_pref($it->{'date_due'}); - $it->{'displaydate_sort'} = $it->{'issuedate'}; - $it->{'displaydate'} = output_pref($it->{'issuedate'}); - #$it->{'od'} = ( $it->{'date_due'} lt $todaysdate ) ? 1 : 0 ; - $it->{'od'} = $it->{'overdue'}; - $it->{'subtitle'} = GetRecordValue('subtitle', GetMarcBiblio($it->{biblionumber}), GetFrameworkCode($it->{biblionumber})); - $it->{'renew_failed'} = $renew_failed{$it->{'itemnumber'}}; - $it->{'return_failed'} = $return_failed{$it->{'barcode'}}; - - if ( ( $it->{'issuedate'} && $it->{'issuedate'} gt $todaysdate ) - || ( $it->{'lastreneweddate'} && $it->{'lastreneweddate'} gt $todaysdate ) ) { - (!$relatives) ? push @todaysissues, $it : push @relissues, $it; - } else { - (!$relatives) ? push @previousissues, $it : push @relprevissues, $it; - } - ($it->{'renewcount'},$it->{'renewsallowed'},$it->{'renewsleft'}) = C4::Circulation::GetRenewCount($it->{'borrowernumber'},$it->{'itemnumber'}); #Add renewal count to item data display - } -} - -if ($borrower) { - - # Getting borrower relatives - my @relborrowernumbers = GetMemberRelatives($borrower->{'borrowernumber'}); - #push @borrowernumbers, $borrower->{'borrowernumber'}; - - # get each issue of the borrower & separate them in todayissues & previous issues - my $issueslist = GetPendingIssues($borrower->{'borrowernumber'}); - my $relissueslist = []; - if ( @relborrowernumbers ) { - $relissueslist = GetPendingIssues(@relborrowernumbers); - } - - build_issue_data($issueslist, 0); - build_issue_data($relissueslist, 1); - - $displayrelissues = scalar($relissueslist); - - if ( C4::Context->preference( "todaysIssuesDefaultSortOrder" ) eq 'asc' ) { - @todaysissues = sort { $a->{'timestamp'} cmp $b->{'timestamp'} } @todaysissues; - } - else { - @todaysissues = sort { $b->{'timestamp'} cmp $a->{'timestamp'} } @todaysissues; - } - - if ( C4::Context->preference( "previousIssuesDefaultSortOrder" ) eq 'asc' ){ - @previousissues = sort { $a->{'date_due'} cmp $b->{'date_due'} } @previousissues; - } - else { - @previousissues = sort { $b->{'date_due'} cmp $a->{'date_due'} } @previousissues; - } -} - - my @values; my %labels; my $CGIselectborrower; @@ -702,6 +600,11 @@ if (C4::Context->preference('ExtendedPatronAttributes')) { ); } +my @relatives = GetMemberRelatives( $borrower->{'borrowernumber'} ); +my $relatives_issues_count = + Koha::Database->new()->schema()->resultset('Issue') + ->count( { borrowernumber => \@relatives } ); + $template->param( lib_messages_loop => $lib_messages_loop, bor_messages_loop => $bor_messages_loop, @@ -739,13 +642,7 @@ $template->param( duedatespec => $duedatespec, message => $message, CGIselectborrower => $CGIselectborrower, - totalprice => sprintf('%.2f', $totalprice), totaldue => sprintf('%.2f', $total), - todayissues => \@todaysissues, - previssues => \@previousissues, - relissues => \@relissues, - relprevissues => \@relprevissues, - displayrelissues => $displayrelissues, inprocess => $inprocess, memberofinstution => $member_of_institution, CGIorganisations => $CGIorganisations, @@ -758,6 +655,8 @@ $template->param( SuspendHoldsIntranet => C4::Context->preference('SuspendHoldsIntranet'), AutoResumeSuspendedHolds => C4::Context->preference('AutoResumeSuspendedHolds'), RoutingSerials => C4::Context->preference('RoutingSerials'), + relatives_issues_count => $relatives_issues_count, + relatives_borrowernumbers => \@relatives, ); # save stickyduedate to session diff --git a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css index 2a04c35..fcc7319 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css +++ b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css @@ -270,7 +270,7 @@ tr.even td, tr.even.highlight td { border-right : 1px solid #BCBCBC; } -td.od { +.overdue td.od { color : #cc0000; font-weight : bold; } diff --git a/koha-tmpl/intranet-tmpl/prog/en/js/checkouts.js b/koha-tmpl/intranet-tmpl/prog/en/js/checkouts.js new file mode 100644 index 0000000..c507449 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/js/checkouts.js @@ -0,0 +1,267 @@ +$(document).ready(function() { + var ymd = $.datepicker.formatDate('yy-mm-dd', new Date()); + + $("#issues-table").dataTable({ + "sDom": "<'row-fluid'<'span6'><'span6'>r>t<'row-fluid'>t", + "aaSorting": [], + "aoColumns": [ + { + "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; + } + } + }, + { + "mDataProp": function ( oObj ) { + title = "" + + oObj.title; + + $.each(oObj.subtitle, function( index, value ) { + title += " " + value.subfield; + }); + + title += ""; + + if ( oObj.author ) { + title += " " + _("by") + " " + 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 + "" + } + + title += " " + + "" + + oObj.barcode + + ""; + + return title; + } + }, + { "mDataProp": "itemtype" }, + { "mDataProp": "issuedate" }, + { "mDataProp": "branchname" }, + { "mDataProp": "itemcallnumber" }, + { + "bSortable": false, + "mDataProp": function ( oObj ) { + return parseFloat(oObj.charge).toFixed(2); + } + }, + { + "bSortable": false, + "mDataProp": "price" }, + { + "bSortable": false, + "mDataProp": function ( oObj ) { + var content = ""; + var span_style = ""; + var span_class = ""; + + 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 { + content += "" + + oObj.can_renew_error + + ""; + + span_style = "display: none"; + span_class = "renewals-allowed"; + } + + content += "" + + "" + + ""; + + if ( oObj.renewals_remaining ) { + content += "(" + + oObj.renewals_remaining + + " " + _("of") + " " + + oObj.renewals_allowed + " " + + _("renewals remaining") + ")" + } + + + return content; + } + }, + { + "bSortable": false, + "mDataProp": function ( oObj ) { + if ( oObj.can_renew_error == "on_reserve" ) { + return "" + _("On hold") + ""; + } else { + return ""; + } + } + }, + { + "bVisible": exports_enabled ? true : false, + "bSortable": false, + "mDataProp": function ( oObj ) { + return ""; + } + } + ], + "fnFooterCallback": function ( nRow, aaData, iStart, iEnd, aiDisplay ) { + var total_charge = 0; + var total_price = 0; + for ( var i=0; i < aaData.length; i++ ) { + total_charge += aaData[i]['charge'] * 1; + total_price += aaData[i]['price'] * 1; + } + var nCells = nRow.getElementsByTagName('td'); + nCells[1].innerHTML = total_charge.toFixed(2); + nCells[2].innerHTML = total_price.toFixed(2); + }, + "bPaginate": false, + "bProcessing": true, + "bServerSide": true, + "sAjaxSource": '/cgi-bin/koha/api/checkouts.pl', + "fnServerData": function ( sSource, aoData, fnCallback ) { + aoData.push( { "name": "borrowernumber", "value": borrowernumber } ); + + $.getJSON( sSource, aoData, function (json) { + fnCallback(json) + } ); + }, + }); + + // Don't load relatives' issues table unless it is clicked on + var relativesIssuesTable; + $("#relatives-issues-tab").click( function() { + if ( ! relativesIssuesTable ) { + relativesIssuesTable = $("#relatives-issues-table").dataTable({ + "sDom": "<'row-fluid'<'span6'><'span6'>r>t<'row-fluid'>t", + "aaSorting": [], + "aoColumns": [ + { + "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; + } + } + }, + { + "mDataProp": function ( oObj ) { + title = "" + + oObj.title; + + $.each(oObj.subtitle, function( index, value ) { + title += " " + value.subfield; + }); + + title += ""; + + if ( oObj.author ) { + title += " " + _("by") + " " + 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 + "" + } + + title += " " + + "" + + oObj.barcode + + ""; + + return title; + } + }, + { "mDataProp": "itemtype" }, + { "mDataProp": "issuedate" }, + { "mDataProp": "branchname" }, + { "mDataProp": "itemcallnumber" }, + { "mDataProp": "charge" }, + { "mDataProp": "price" }, + { + "mDataProp": function( oObj ) { + return "" + + oObj.borrower.firstname + " " + oObj.borrower.surname + " (" + oObj.borrower.cardnumber + ")" + } + }, + ], + "bPaginate": false, + "bProcessing": true, + "bServerSide": true, + "sAjaxSource": '/cgi-bin/koha/api/checkouts.pl', + "fnServerData": function ( sSource, aoData, fnCallback ) { + $.each(relatives_borrowernumbers, function( index, value ) { + aoData.push( { "name": "borrowernumber", "value": value } ); + }); + + $.getJSON( sSource, aoData, function (json) { + fnCallback(json) + } ); + }, + }); + } + }); + + $("#issues-table").on("sort",function() { + $("#previous").hide(); // Don't want to see "previous checkouts" header sorted with other rows + }); + $("#relatives-issues-table").on("sort",function() { + $("#relprevious").hide(); // Don't want to see "previous checkouts" header sorted with other rows + }); + + if ( AllowRenewalLimitOverride ) { + $( '#override_limit' ).click( function () { + if ( this.checked ) { + $( '.renewals-allowed' ).show(); $( '.renewals-disabled' ).hide(); + } else { + $( '.renewals-allowed' ).hide(); $( '.renewals-disabled' ).show(); + } + } ).attr( 'checked', false ); + } + }); diff --git a/koha-tmpl/intranet-tmpl/prog/en/js/pages/circulation.js b/koha-tmpl/intranet-tmpl/prog/en/js/pages/circulation.js index fe307bf..cfffa2f 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/js/pages/circulation.js +++ b/koha-tmpl/intranet-tmpl/prog/en/js/pages/circulation.js @@ -1,57 +1,136 @@ $(document).ready(function() { - $('#patronlists').tabs(); - var allcheckboxes = $(".checkboxed"); - $("#renew_all").on("click",function(){ - allcheckboxes.checkCheckboxes(":input[name*=items]"); - allcheckboxes.unCheckCheckboxes(":input[name*=barcodes]"); - }); - $("#CheckAllitems").on("click",function(){ - allcheckboxes.checkCheckboxes(":input[name*=items]"); - allcheckboxes.unCheckCheckboxes(":input[name*=barcodes]"); return false; + // Handle the select all/none links for checkouts table columns + $("#CheckAllRenewals").on("click",function(){ + $("#UncheckAllCheckins").click(); + $(".renew:visible").attr("checked", "checked" ); + return false; }); - $("#CheckNoitems").on("click",function(){ - allcheckboxes.unCheckCheckboxes(":input[name*=items]"); return false; + $("#UncheckAllRenewals").on("click",function(){ + $(".renew:visible").removeAttr("checked"); + return false; }); - $("#CheckAllreturns").on("click",function(){ - allcheckboxes.checkCheckboxes(":input[name*=barcodes]"); - allcheckboxes.unCheckCheckboxes(":input[name*=items]"); return false; + + $("#CheckAllCheckins").on("click",function(){ + $("#UncheckAllRenewals").click(); + $(".checkin:visible").attr("checked", "checked" ); + return false; }); - $("#CheckNoreturns" ).on("click",function(){ - allcheckboxes.unCheckCheckboxes(":input[name*=barcodes]"); return false; + $("#UncheckAllCheckins").on("click",function(){ + $(".checkin:visible").removeAttr("checked"); + return false; }); - $("#CheckAllexports").on("click",function(){ - allcheckboxes.checkCheckboxes(":input[name*=biblionumbers]"); + $("#CheckAllExports").on("click",function(){ + $(".export:visible").attr("checked", "checked" ); return false; }); - $("#CheckNoexports").on("click",function(){ - allcheckboxes.unCheckCheckboxes(":input[name*=biblionumbers]"); + $("#UncheckAllExports").on("click",function(){ + $(".export:visible").removeAttr("checked"); return false; }); - $("#relrenew_all").on("click",function(){ - allcheckboxes.checkCheckboxes(":input[name*=items]"); - allcheckboxes.unCheckCheckboxes(":input[name*=barcodes]"); - }); - $("#relCheckAllitems").on("click",function(){ - allcheckboxes.checkCheckboxes(":input[name*=items]"); - allcheckboxes.unCheckCheckboxes(":input[name*=barcodes]"); return false; + // Don't allow both return and renew checkboxes to be checked + $(document).on("change", '.renew', function(){ + if ( $(this).is(":checked") ) { + $( "#checkin_" + $(this).val() ).removeAttr("checked"); + } }); - $("#relCheckNoitems").on("click",function(){ - allcheckboxes.unCheckCheckboxes(":input[name*=items]"); return false; + $(document).on("change", '.checkin', function(){ + if ( $(this).is(":checked") ) { + $( "#renew_" + $(this).val() ).removeAttr("checked"); + } }); - $("#relCheckAllreturns").on("click",function(){ - allcheckboxes.checkCheckboxes(":input[name*=barcodes]"); - allcheckboxes.unCheckCheckboxes(":input[name*=items]"); return false; + + // Handle renewals + $("#RenewCheckinChecked").on("click",function(){ + $(".checkin:checked:visible").each(function() { + itemnumber = $(this).val(); + + $(this).replaceWith(""); + + params = { + itemnumber: itemnumber, + borrowernumber: borrowernumber, + branchcode: branchcode, + exempt_fine: $("#exemptfine").is(':checked') + }; + + $.post( "/cgi-bin/koha/api/checkin.pl", params, function( data ) { + id = "#checkin_" + data.itemnumber; + + content = ""; + if ( data.returned ) { + content = _("Returned"); + } else { + content = _("Unable to return"); + } + + $(id).replaceWith( content ); + }, "json") + }); + + $(".renew:checked:visible").each(function() { + var override_limit = $("#override_limit").is(':checked') ? 1 : 0; + + var itemnumber = $(this).val(); + + $(this).replaceWith(""); + + var params = { + itemnumber: itemnumber, + borrowernumber: borrowernumber, + branchcode: branchcode, + override_limit: override_limit, + date_due: $("#newduedate").val() + }; + + $.post( "/cgi-bin/koha/api/renew.pl", params, function( data ) { + var id = "#renew_" + data.itemnumber; + + var content = ""; + if ( data.renew_okay ) { + content = _("Renewed, due: ") + data.date_due; + } else { + content = _("Renew failed: "); + if ( data.error == "no_checkout" ) { + content += _("not checked out"); + } else if ( data.error == "too_many" ) { + content += _("too many renewals"); + } else if ( data.error == "on_reserve" ) { + content += _("on reserve"); + } else if ( data.error ) { + content += data.error; + } else { + content += _("reason unknown"); + } + } + + $(id).replaceWith( content ); + }, "json") + }); + + // Prevent form submit + return false; }); - $("#relCheckNoreturns").on("click",function(){ - allcheckboxes.unCheckCheckboxes(":input[name*=barcodes]"); return false; + + $("#RenewAll").on("click",function(){ + $("#CheckAllRenewals").click(); + $("#UncheckAllCheckins").click(); + $("#RenewCheckinChecked").click(); + + // Prevent form submit + return false; }); + + $('#patronlists').tabs(); + $("#messages ul").after(""+MSG_ADD_MESSAGE+""); + $("#borrower_messages .cancel").on("click",function(){ $("#add_message_form").hide(); $("#addmessage").show(); }); + $("#addmessage").on("click",function(){ $(this).hide(); $("#add_message_form").show(); @@ -76,8 +155,9 @@ $(document).ready(function() { export_checkouts(export_format); return false; }); + // Clicking the table cell checks the checkbox inside it - $("td").on("click",function(e){ + $(document).on("click", 'td', function(e){ if(e.target.tagName.toLowerCase() == 'td'){ $(this).find("input:checkbox:visible").each( function() { $(this).click(); @@ -107,13 +187,9 @@ function export_checkouts(format) { } else if (format == 'iso2709') { $("#dont_export_item").val(1); } - document.issues.action="/cgi-bin/koha/tools/export.pl"; + document.getElementById("export_format").value = format; document.issues.submit(); - - /* Reset form action to its initial value */ - document.issues.action="/cgi-bin/koha/reserve/renewscript.pl"; - } function validate1(date) { diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt index e667bc3..ce041ed 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -13,88 +13,45 @@ [% INCLUDE 'doc-head-close.inc' %] [% INCLUDE 'calendar.inc' %] -[% IF ( UseTablesortForCirc ) %] + [% INCLUDE 'datatables-strings.inc' %] -[% END %] + [% INCLUDE 'timepicker.inc' %] + @@ -516,7 +473,7 @@ No patron matched [% message %] [% ELSE %] [% END %] - + [% IF ( SpecifyDueDate ) %]
Specify due date [% INCLUDE 'date-format.inc' %]:
@@ -528,7 +485,7 @@ No patron matched [% message %] [% ELSE %] [% END %] - +
[% END %] @@ -687,346 +644,111 @@ No patron matched [% message %]
[% IF ( issuecount ) %] -
- - - - - - - - - - - - - - - - - [% IF ( exports_enabled ) %] - - [% END %] - -[% IF ( todayissues ) %] -[% INCLUDE 'checkouts-table-footer.inc' %] - - - [% FOREACH todayissue IN todayissues %] - [% IF ( loop.odd ) %] - - [% ELSE %] - - [% END %] - [% IF ( todayissue.od ) %] - - - - [% IF ( todayissue.multiple_borrowers ) %][% END %] - - - - - [% IF ( todayissue.renew_failed ) %] - - [% ELSE %] - - [% END %] - [% IF ( todayissue.return_failed ) %] - - [% ELSE %] - [% IF ( todayissue.renew_error_on_reserve ) %] - - [% ELSE %] - - [% END %] - [% END %] - [% IF ( exports_enabled ) %] - - [% END %] - - [% END %] - [% END %] - -[% IF ( previssues ) %] - [% UNLESS ( todayissues ) %] - [% INCLUDE 'checkouts-table-footer.inc' %] - - [% END %] - [% IF ( UseTablesortForCirc ) %][% IF ( exports_enabled ) %][% END %][% ELSE %][% IF ( exports_enabled ) %][% END %] - [% FOREACH previssue IN previssues %] - [% IF ( loop.odd ) %] - - [% ELSE %] - - [% END %] - [% IF ( previssue.od ) %] - - - - [% IF ( previssue.multiple_borrowers ) %][% END %] - - - - - [% IF ( previssue.renew_failed ) %] - - [% ELSE %] - - [% END %] - [% IF ( previssue.return_failed ) %] - - [% ELSE %] - [% IF ( previssue.renew_error_on_reserve ) %] - - [% ELSE %] - + [% IF ( exports_enabled ) %] +
+ + + + + + + + + +
[% END %] [% END %] - [% IF ( exports_enabled ) %] - - [% END %] - - [% END %] -[% END %] - -
Due dateTitleItem typeChecked out onChecked out fromCall noChargePriceRenew

select all | none

Check in

select all | none

Export

select all | none

[% ELSE %][% END %] - [% todayissue.dd %] - - [% IF ( todayissue.itemlost ) %] - [% AuthorisedValues.GetByCode( 'LOST', todayissue.itemlost ) %] - [% END %] - [% IF ( todayissue.damaged ) %] - [% AuthorisedValues.GetByCode( 'DAMAGED', todayissue.damaged ) %] - [% END %] - [% todayissue.title |html %][% FOREACH subtitl IN todayissue.subtitle %] [% subtitl.subfield %][% END %][% IF ( todayissue.author ) %], by [% todayissue.author %][% END %][% IF ( todayissue.itemnotes ) %]- [% todayissue.itemnotes %][% END %] [% todayissue.barcode %][% UNLESS ( noItemTypeImages ) %] [% IF ( todayissue.itemtype_image ) %][% END %][% END %][% todayissue.itemtype %][% todayissue.checkoutdate %][% todayissue.firstname %] [% todayissue.surname %][% todayissue.issuingbranchname %][% todayissue.itemcallnumber %][% todayissue.charge %][% todayissue.replacementprice %]Renewal failed[% IF ( todayissue.renewals ) %][% todayissue.renewals %][% ELSE %]0[% END %] - [% IF ( todayissue.can_renew ) %] - - [% IF ( todayissue.od ) %] - - [% ELSE %] - - [% END %] - [% IF todayissue.renewsallowed && todayissue.renewsleft %] - ([% todayissue.renewsleft %] of [% todayissue.renewsallowed %] renewals remaining) - [% END %] - [% ELSE %] - [% IF ( todayissue.can_confirm ) %] - [% IF todayissue.renewsallowed && todayissue.renewsleft %] - ([% todayissue.renewsleft %] of [% todayissue.renewsallowed %] renewals remaining) - [% END %] - - [% END %] - [% IF ( todayissue.renew_error_on_reserve ) %] - On hold - [% END %] - [% IF ( todayissue.renew_error_too_many ) %] - Not renewable + + + + + + + + + + + + + + + + + + [% INCLUDE 'checkouts-table-footer.inc' %] +
Due dateTitleItem typeChecked out onChecked out fromCall noChargePriceRenew

select all | none

Check in

select all | none

Export

select all | none

+ + [% IF ( issuecount ) %] +
+ [% IF ( CAN_user_circulate_override_renewals ) %] + [% IF ( AllowRenewalLimitOverride ) %] + + + [% END %] [% END %] - [% IF ( todayissue.can_confirm ) %] - - [% END %] - [% END %] -
Checkin failedOn hold - - - - - - -
Previous checkouts
[% ELSE %][% END %]Previous checkouts
[% ELSE %][% END %] - [% previssue.dd %] + + + - [% IF ( previssue.itemlost ) %] - [% AuthorisedValues.GetByCode( 'LOST', previssue.itemlost ) %] - [% END %] - [% IF ( previssue.damaged ) %] - [% AuthorisedValues.GetByCode( 'DAMAGED', previssue.damaged ) %] - [% END %] - [% previssue.title |html %][% FOREACH subtitl IN previssue.subtitle %] [% subtitl.subfield %][% END %][% IF ( previssue.author ) %], by [% previssue.author %][% END %] [% IF ( previssue.itemnotes ) %]- [% previssue.itemnotes %][% END %] [% previssue.barcode %] - [% previssue.itemtype %] - [% previssue.displaydate %][% previssue.firstname %] [% previssue.surname %][% previssue.issuingbranchname %][% previssue.itemcallnumber %][% previssue.charge %][% previssue.replacementprice %]Renewal failed[% IF ( previssue.renewals ) %][% previssue.renewals %][% ELSE %]0[% END %] - [% IF ( previssue.can_renew ) %] - - [% IF ( previssue.od ) %] - - [% ELSE %] - - [% END %] - [% IF previssue.renewsallowed && previssue.renewsleft %] - ([% previssue.renewsleft %] of [% previssue.renewsallowed %] renewals remaining) - [% END %] - [% ELSE %] - [% IF ( previssue.can_confirm ) %] - [% IF previssue.renewsallowed && previssue.renewsleft %] - ([% previssue.renewsleft %] of [% previssue.renewsallowed %] renewals remaining) - [% END %] - - [% END %] - [% IF ( previssue.renew_error_on_reserve ) %] - On hold - [% END %] - [% IF ( previssue.renew_error_too_many ) %] - Not renewable - [% END %] - [% IF ( previssue.can_confirm ) %] - - [% END %] - [% END %] - Check-in failedOn hold - - - - - - -
- [% IF ( issuecount ) %] -
- [% IF ( CAN_user_circulate_override_renewals ) %] - [% IF ( AllowRenewalLimitOverride ) %] - - - [% END %] - [% END %] - - -
- [% IF ( exports_enabled ) %] -
- - - - - - - - -
- [% END %] - [% END %]
[% ELSE %] -

Patron has nothing checked out.

+

Patron has nothing checked out.

[% END %]
-[% IF ( displayrelissues ) %] -
- - - - - - - - - - - - - - -[% IF ( relissues ) %] - - [% FOREACH relissue IN relissues %] - [% IF ( loop.odd ) %] - - [% ELSE %] - - [% END %] - [% IF ( relissue.overdue ) %] - - [% IF ( relissue.itemlost ) %] - [% AuthorisedValues.GetByCode( 'LOST', relissue.itemlost ) %] - [% END %] - [% IF ( relissue.damaged ) %] - [% AuthorisedValues.GetByCode( 'DAMAGED', relissue.damaged ) %] - [% END %] - - - - - - - - - - [% END %] - [% END %] -[% IF ( relprevissues ) %] - [% IF ( UseTablesortForCirc ) %][% ELSE %][% END %] - [% FOREACH relprevissue IN relprevissues %] - [% IF ( loop.odd ) %] - - [% ELSE %] - - [% END %] - [% IF ( relprevissue.overdue ) %] - - - - - - [% IF ( relprevissue.multiple_borrowers ) %][% END %] - - - - - - [% END %] -[% END %] - +[% IF ( relatives_issues_count ) %] +
+
Due dateTitleItem typeChecked out onChecked out fromCall noChargePricePatron
[% ELSE %][% END %] - [% relissue.dd %][% relissue.title |html %][% FOREACH subtitl IN relissue.subtitle %] [% subtitl.subfield %][% END %][% IF ( relissue.author ) %], by [% relissue.author %][% END %][% IF ( relissue.itemnotes ) %]- [% relissue.itemnotes %][% END %] [% relissue.barcode %][% UNLESS ( noItemTypeImages ) %] [% IF ( relissue.itemtype_image ) %][% END %][% END %][% relissue.itemtype %][% relissue.displaydate %][% relissue.issuingbranchname %][% relissue.itemcallnumber %][% relissue.charge %][% relissue.replacementprice %][% relissue.firstname %] [% relissue.surname %] ([% relissue.cardnumber %])
Previous checkouts
Previous checkouts
[% ELSE %][% END %] - [% relprevissue.dd %] - [% relprevissue.title |html %][% FOREACH subtitl IN relprevissue.subtitle %] [% subtitl.subfield %][% END %][% IF ( relprevissue.author ) %], by [% relprevissue.author %][% END %] [% IF ( relprevissue.itemnotes ) %]- [% relprevissue.itemnotes %][% END %] [% relprevissue.barcode %][% UNLESS noItemTypeImages %][% IF relprevissue.itemtype_image %][% END %][% END %][% relprevissue.itemtype %][% relprevissue.displaydate %][% relprevissue.issuingbranchname %][% relprevissue.itemcallnumber %][% relprevissue.firstname %] [% relprevissue.surname %][% relprevissue.charge %][% relprevissue.replacementprice %][% relprevissue.firstname %] [% relprevissue.surname %] ([% relprevissue.cardnumber %])
+ + + + + + + + + + + + +
Due dateTitleItem typeChecked out onChecked out fromCall noChargePricePatron
-
-[% END %] +[% END %] [% INCLUDE borrower_debarments.inc %] -- 1.7.2.5