Bug 14310 - Suspend and resume indvidual holds from patron holds table
authorKyle M Hall <kyle@bywatersolutions.com>
Fri, 16 Oct 2015 14:44:11 +0000 (10:44 -0400)
committerBrendan A Gallagher <brendan@bywatersolutions.com>
Wed, 27 Jan 2016 06:20:17 +0000 (06:20 +0000)
This enhancment adds the ability to suspend and resume individual holds
from the holds table on circulation.pl and moremember.pl.

The interface is inspired/cribbed from the same feature already
available in the opac.

Test Plan:
1) Apply this patch
2) Find a patron with holds
3) Suspend a hold with no resume date
4) Resume the suspended hold
5) Suspend a hold with a resume date
6) Resume the suspended hold

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Cathi Wiggins <CWIGGINS@ci.arcadia.ca.us>
Signed-off-by: Megan Wianecki <mwianecki@mplmain.mtpl.org>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Brendan A Gallagher <brendan@bywatersolutions.com>
Koha/Hold.pm
koha-tmpl/intranet-tmpl/prog/en/js/holds.js
koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt
svc/hold/resume [new file with mode: 0644]
svc/hold/suspend [new file with mode: 0644]

index 871f3e1..707622d 100644 (file)
@@ -41,6 +41,47 @@ Koha::Hold - Koha Hold object class
 
 =cut
 
+=head3 suspend_hold
+
+my $hold = $hold->suspend_hold( $suspend_until_dt );
+
+=cut
+
+sub suspend_hold {
+    my ( $self, $dt ) = @_;
+
+    if ( $self->is_waiting ) {    # We can't suspend waiting holds
+        carp "Unable to suspend waiting hold!";
+        return $self;
+    }
+
+    $dt ||= undef;
+
+    $self->suspend(1);
+    $self->suspend_until( $dt );
+
+    $self->store();
+
+    return $self;
+}
+
+=head3 resume
+
+my $hold = $hold->resume();
+
+=cut
+
+sub resume {
+    my ( $self ) = @_;
+
+    $self->suspend(0);
+    $self->suspend_until( undef );
+
+    $self->store();
+
+    return $self;
+}
+
 =head3 waiting_expires_on
 
 Returns a DateTime for the date a waiting holds expires on.
index 077b3b6..bf7ea44 100644 (file)
@@ -8,11 +8,12 @@ $(document).ready(function() {
     if ( $("#holds-tab").parent().hasClass('ui-state-active') ) { load_holds_table() }
 
     function load_holds_table() {
+        var holds = new Array();
         if ( ! holdsTable ) {
             holdsTable = $("#holds-table").dataTable({
                 "bAutoWidth": false,
                 "sDom": "rt",
-                "aoColumns": [
+                "columns": [
                     {
                         "mDataProp": "reservedate_formatted"
                     },
@@ -119,21 +120,53 @@ $(document).ready(function() {
                                  + "<input type='hidden' name='borrowernumber' value='" + borrowernumber + "'>"
                                  + "<input type='hidden' name='reserve_id' value='" + oObj.reserve_id + "'>";
                         }
+                    },
+                    {
+                        "bSortable": false,
+                        "mDataProp": function( oObj ) {
+                            holds[oObj.reserve_id] = oObj; //Store holds for later use
+
+                            if ( oObj.found ) {
+                                return "";
+                            } else if ( oObj.suspend == 1 ) {
+                                return "<a class='hold-resume btn btn-link' id='resume" + oObj.reserve_id + "' style='display: inline; white-space: nowrap;'>"
+                                     + "<i class='icon-play'></i> " + _("Resume") + "</a>";
+                            } else {
+                                return "<a class='hold-suspend btn btn-link' id='suspend" + oObj.reserve_id + "' style='display: inline; white-space: nowrap;'>"
+                                     + "<i class='icon-pause'></i> " + _("Suspend") + "</a>";
+                            }
+                        }
                     }
                 ],
                 "bPaginate": false,
                 "bProcessing": true,
                 "bServerSide": false,
-                "sAjaxSource": '/cgi-bin/koha/svc/holds',
-                "fnServerData": function ( sSource, aoData, fnCallback ) {
-                    aoData.push( { "name": "borrowernumber", "value": borrowernumber } );
-
-                    $.getJSON( sSource, aoData, function (json) {
-                        fnCallback(json)
-                    } );
+                "ajax": {
+                    "url": '/cgi-bin/koha/svc/holds',
+                    "data": function ( d ) {
+                        d.borrowernumber = borrowernumber;
+                    }
                 },
             });
 
+            $('#holds-table').on( 'draw.dt', function () {
+                $(".hold-suspend").on( "click", function() {
+                    var id = $(this).attr("id").replace("suspend", "");
+                    var hold = holds[id];
+                    $("#suspend-modal-title").html( hold.title );
+                    $("#suspend-modal-reserve_id").val( hold.reserve_id );
+                    $('#suspend-modal').modal('show');
+                });
+
+                $(".hold-resume").on( "click", function() {
+                    var id = $(this).attr("id").replace("resume", "");
+                    var hold = holds[id];
+                    $.post('/cgi-bin/koha/svc/hold/resume', { "reserve_id": hold.reserve_id }, function( data ){
+                      holdsTable.api().ajax.reload();
+                    });
+                });
+            });
+
             if ( $("#holds-table").length ) {
                 $("#holds-table_processing").position({
                     of: $( "#holds-table" ),
@@ -142,4 +175,42 @@ $(document).ready(function() {
             }
         }
     }
+
+    $("body").append("\
+        <div id='suspend-modal' class='modal hide fade' tabindex='-1' role='dialog' aria-hidden='true'>\
+            <form id='suspend-modal-form' class='form-inline'>\
+                <div class='modal-header'>\
+                    <button type='button' class='closebtn' data-dismiss='modal' aria-hidden='true'>×</button>\
+                    <h3 id='suspend-modal-label'>" + _("Suspend hold on") + " <i><span id='suspend-modal-title'></span></i></h3>\
+                </div>\
+\
+                <div class='modal-body'>\
+                    <input type='hidden' id='suspend-modal-reserve_id' name='reserve_id' />\
+\
+                    <label for='suspend-modal-until'>Suspend until:</label>\
+                    <input name='suspend_until' id='suspend-modal-until' class='suspend-until' size='10' />\
+\
+                    <p/><a class='btn btn-link' id='suspend-modal-clear-date' >" + _("Clear date to suspend indefinitely") + "</a></p>\
+\
+                </div>\
+\
+                <div class='modal-footer'>\
+                    <button id='suspend-modal-submit' class='btn btn-primary' type='submit' name='submit'>" + _("Suspend") + "</button>\
+                    <a href='#' data-dismiss='modal' aria-hidden='true' class='cancel'>" + _("Cancel") + "</a>\
+                </div>\
+            </form>\
+        </div>\
+    ");
+
+    $("#suspend-modal-until").datepicker({ minDate: 1 }); // Require that "until date" be in the future
+    $("#suspend-modal-clear-date").on( "click", function() { $("#suspend-modal-until").val(""); } );
+
+    $("#suspend-modal-submit").on( "click", function( e ) {
+        e.preventDefault();
+        $.post('/cgi-bin/koha/svc/hold/suspend', $('#suspend-modal-form').serialize(), function( data ){
+          $('#suspend-modal').modal('hide');
+          holdsTable.api().ajax.reload();
+        });
+    });
+
 });
index 78152d1..3c16501 100644 (file)
@@ -937,6 +937,7 @@ No patron matched <span class="ex">[% message %]</span>
                     <th>Expiration</th>
                     <th>Priority</th>
                     <th>Delete?</th>
+                    <th>Suspend?</th>
                 </tr>
             </thead>
         </table>
index a44fb3c..30cda46 100644 (file)
@@ -495,6 +495,7 @@ function validate1(date) {
                     <th>Expiration</th>
                     <th>Priority</th>
                     <th>Delete?</th>
+                    <th>Suspend?</th>
                 </tr>
             </thead>
         </table>
diff --git a/svc/hold/resume b/svc/hold/resume
new file mode 100644 (file)
index 0000000..03cd017
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+
+# Copyright 2015 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::Context;
+use C4::Auth qw(check_cookie_auth);
+use Koha::DateUtils qw(dt_from_string);
+use Koha::Holds;
+
+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 $reserve_id = $input->param('reserve_id');
+
+my $hold = Koha::Holds->find( $reserve_id );
+$hold->resume();
+
+print to_json( { success => !$hold->suspend() } );
diff --git a/svc/hold/suspend b/svc/hold/suspend
new file mode 100644 (file)
index 0000000..880e41a
--- /dev/null
@@ -0,0 +1,51 @@
+#!/usr/bin/perl
+
+# Copyright 2015 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::Context;
+use C4::Auth qw(check_cookie_auth);
+use Koha::DateUtils qw(dt_from_string);
+use Koha::Holds;
+
+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 $reserve_id = $input->param('reserve_id');
+
+my $suspend_until = $input->param('suspend_until') || undef;
+$suspend_until = dt_from_string( $suspend_until ) if $suspend_until;
+
+my $hold = Koha::Holds->find( $reserve_id );
+$hold->suspend_hold( $suspend_until );
+
+print to_json( { success => $hold->suspend() } );