Bug 7641: Suspend Reserves
authorKyle M Hall <kyle@bywatersolutions.com>
Thu, 1 Mar 2012 16:57:58 +0000 (11:57 -0500)
committerPaul Poulain <paul.poulain@biblibre.com>
Thu, 29 Mar 2012 12:37:49 +0000 (14:37 +0200)
Adds the ability to suspend reserves. The new system preference
AutoResumeSuspendedHolds enables the ability to set a date for
a suspended hold to automatically be resumed.

When a hold is suspended, it will continue to increase in priority
as the holds above it are fulfilled. If the first holds in line
to be filled are suspended, the first non-suspened hold in line
will be used when an item can fulfill a hold that has been placed.

http://bugs.koha-community.org/show_bug.cgi?id=7641
Signed-off-by: Nicole C. Engard <nengard@bywatersolutions.com>
Tested with the preference on and off:
1. placed several holds in the staff client
2. suspended some with a date
3. suspended some without a date
4. triggered hold message by checking in for hold with suspensions
5. the suspended hold was skipped as it should be
6. tested suspending holds in the OPAC w and w/out dates
7. ran the cron to clear suspensions with dates

All the above tests worked as expected. Signing off.

17 files changed:
C4/Reserves.pm
circ/circulation.pl
installer/data/mysql/kohastructure.sql
installer/data/mysql/sysprefs.sql
installer/data/mysql/updatedatabase.pl
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref
koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt
koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt
koha-tmpl/opac-tmpl/prog/en/modules/opac-user.tt
members/moremember.pl
misc/cronjobs/holds/auto_unsuspend_holds.pl [new file with mode: 0755]
opac/opac-modrequest-suspend.pl [new file with mode: 0755]
opac/opac-user.pl
reserve/modrequest.pl
reserve/modrequest_suspendall.pl [new file with mode: 0755]
reserve/request.pl

index 276658c..05a4870 100644 (file)
@@ -117,12 +117,16 @@ BEGIN {
         &CancelReserve
         &CancelExpiredReserves
 
+        &AutoUnsuspendReserves
+
         &IsAvailableForItemLevelRequest
         
         &AlterPriority
         &ToggleLowestPriority
 
         &ReserveSlip
+        &ToggleSuspend
+        &SuspendAll
     );
     @EXPORT_OK = qw( MergeHolds );
 }    
@@ -264,7 +268,9 @@ sub GetReservesFromBiblionumber {
                 itemnumber,
                 reservenotes,
                 expirationdate,
-                lowestPriority
+                lowestPriority,
+                suspend,
+                suspend_until
         FROM     reserves
         WHERE biblionumber = ? ";
     unless ( $all_dates ) {
@@ -894,6 +900,24 @@ sub CancelExpiredReserves {
 
 }
 
+=head2 AutoUnsuspendReserves
+
+  AutoUnsuspendReserves();
+
+Unsuspends all suspended reserves with a suspend_until date from before today.
+
+=cut
+
+sub AutoUnsuspendReserves {
+
+    my $dbh = C4::Context->dbh;
+
+    my $query = "UPDATE reserves SET suspend = 0, suspend_until = NULL WHERE DATE( suspend_until ) < DATE( CURDATE() )";
+    my $sth = $dbh->prepare( $query );
+    $sth->execute();
+
+}
+
 =head2 CancelReserve
 
   &CancelReserve($biblionumber, $itemnumber, $borrowernumber);
@@ -1029,7 +1053,7 @@ itemnumber and supplying itemnumber.
 
 sub ModReserve {
     #subroutine to update a reserve
-    my ( $rank, $biblio, $borrower, $branch , $itemnumber) = @_;
+    my ( $rank, $biblio, $borrower, $branch , $itemnumber, $suspend_until) = @_;
      return if $rank eq "W";
      return if $rank eq "n";
     my $dbh = C4::Context->dbh;
@@ -1062,14 +1086,25 @@ sub ModReserve {
         
     }
     elsif ($rank =~ /^\d+/ and $rank > 0) {
-        my $query = qq/
-        UPDATE reserves SET priority = ? ,branchcode = ?, itemnumber = ?, found = NULL, waitingdate = NULL
+        my $query = "
+            UPDATE reserves SET priority = ? ,branchcode = ?, itemnumber = ?, found = NULL, waitingdate = NULL
             WHERE biblionumber   = ?
-             AND borrowernumber = ?
-        /;
+            AND borrowernumber = ?
+        ";
         my $sth = $dbh->prepare($query);
         $sth->execute( $rank, $branch,$itemnumber, $biblio, $borrower);
         $sth->finish;
+
+        if ( defined( $suspend_until ) ) {
+            if ( $suspend_until ) {
+                $suspend_until = C4::Dates->new( $suspend_until )->output("iso");
+                warn "SUSPEND UNTIL: $suspend_until";
+                $dbh->do("UPDATE reserves SET suspend = 1, suspend_until = ? WHERE biblionumber = ? AND borrowernumber = ?", undef, ( $suspend_until, $biblio, $borrower ) );
+            } else {
+                $dbh->do("UPDATE reserves SET suspend_until = NULL WHERE biblionumber = ? AND borrowernumber = ?", undef, ( $biblio, $borrower ) );
+            }
+        }
+
         _FixPriority( $biblio, $borrower, $rank);
     }
 }
@@ -1472,6 +1507,93 @@ sub ToggleLowestPriority {
     _FixPriority( $biblionumber, $borrowernumber, '999999' );
 }
 
+=head2 ToggleSuspend
+
+  ToggleSuspend( $borrowernumber, $biblionumber );
+
+This function sets the suspend field to true if is false, and false if it is true.
+If the reserve is currently suspended with a suspend_until date, that date will
+be cleared when it is unsuspended.
+
+=cut
+
+sub ToggleSuspend {
+    my ( $borrowernumber, $biblionumber ) = @_;
+
+    my $dbh = C4::Context->dbh;
+
+    my $sth = $dbh->prepare(
+        "UPDATE reserves SET suspend = NOT suspend,
+        suspend_until = CASE WHEN suspend = 0 THEN NULL ELSE suspend_until END
+        WHERE biblionumber = ?
+        AND borrowernumber = ?
+    ");
+    $sth->execute(
+        $biblionumber,
+        $borrowernumber,
+    );
+    $sth->finish;
+}
+
+=head2 SuspendAll
+
+  SuspendAll(
+      borrowernumber   => $borrowernumber,
+      [ biblionumber   => $biblionumber, ]
+      [ suspend_until  => $suspend_until, ]
+      [ suspend        => $suspend ]
+  );
+
+  This function accepts a set of hash keys as its parameters.
+  It requires either borrowernumber or biblionumber, or both.
+
+  suspend_until is wholly optional.
+
+=cut
+
+sub SuspendAll {
+    my %params = @_;
+
+    my $borrowernumber = $params{'borrowernumber'} || undef;
+    my $biblionumber   = $params{'biblionumber'}   || undef;
+    my $suspend_until  = $params{'suspend_until'}  || undef;
+    my $suspend        = defined( $params{'suspend'} ) ? $params{'suspend'} :  1;
+
+    warn "C4::Reserves::SuspendAll( borrowernumber => $borrowernumber, biblionumber => $biblionumber, suspend_until => $suspend_until, suspend => $suspend )";
+
+    $suspend_until = C4::Dates->new( $suspend_until )->output("iso") if ( defined( $suspend_until ) );
+
+    return unless ( $borrowernumber || $biblionumber );
+
+    my ( $query, $sth, $dbh, @query_params );
+
+    $query = "UPDATE reserves SET suspend = ? ";
+    push( @query_params, $suspend );
+    if ( !$suspend ) {
+        $query .= ", suspend_until = NULL ";
+    } elsif ( $suspend_until ) {
+        $query .= ", suspend_until = ? ";
+        push( @query_params, $suspend_until );
+    }
+    $query .= " WHERE ";
+    if ( $borrowernumber ) {
+        $query .= " borrowernumber = ? ";
+        push( @query_params, $borrowernumber );
+    }
+    $query .= " AND " if ( $borrowernumber && $biblionumber );
+    if ( $biblionumber ) {
+        $query .= " biblionumber = ? ";
+        push( @query_params, $biblionumber );
+    }
+    $query .= " AND found IS NULL ";
+
+    $dbh = C4::Context->dbh;
+    $sth = $dbh->prepare( $query );
+    $sth->execute( @query_params );
+    $sth->finish;
+}
+
+
 =head2 _FixPriority
 
   &_FixPriority($biblio,$borrowernumber,$rank,$ignoreSetLowestRank);
@@ -1616,6 +1738,7 @@ sub _Findgroupreserve {
         AND item_level_request = 1
         AND itemnumber = ?
         AND reservedate <= CURRENT_DATE()
+        AND suspend = 0
     /;
     my $sth = $dbh->prepare($item_level_target_query);
     $sth->execute($itemnumber);
@@ -1646,6 +1769,7 @@ sub _Findgroupreserve {
         AND item_level_request = 0
         AND hold_fill_targets.itemnumber = ?
         AND reservedate <= CURRENT_DATE()
+        AND suspend = 0
     /;
     $sth = $dbh->prepare($title_level_target_query);
     $sth->execute($itemnumber);
@@ -1677,6 +1801,7 @@ sub _Findgroupreserve {
           OR  reserves.constrainttype='a' )
           AND (reserves.itemnumber IS NULL OR reserves.itemnumber = ?)
           AND reserves.reservedate <= CURRENT_DATE()
+          AND suspend = 0
     /;
     $sth = $dbh->prepare($query);
     $sth->execute( $biblio, $bibitem, $itemnumber );
index 082b3d4..469209c 100755 (executable)
@@ -354,6 +354,8 @@ if ($borrowernumber) {
         $getreserv{itemcallnumber} = $getiteminfo->{'itemcallnumber'};
         $getreserv{biblionumber}   = $getiteminfo->{'biblionumber'};
         $getreserv{waitingat}      = GetBranchName( $num_res->{'branchcode'} );
+        $getreserv{suspend}        = $num_res->{'suspend'};
+        $getreserv{suspend_until}  = C4::Dates->new( $num_res->{'suspend_until'}, "iso")->output("syspref");
         #         check if we have a waiting status for reservations
         if ( $num_res->{'found'} eq 'W' ) {
             $getreserv{color}   = 'reserved';
@@ -726,4 +728,7 @@ $template->param(
     DHTMLcalendar_dateformat  => C4::Dates->DHTMLcalendar(),
     canned_bor_notes_loop     => $canned_notes,
 );
+
+$template->param( AutoResumeSuspendedHolds => C4::Context->preference('AutoResumeSuspendedHolds') );
+
 output_html_with_http_headers $query, $cookie, $template->output;
index 26689c6..fda0bac 100644 (file)
@@ -1459,6 +1459,8 @@ CREATE TABLE `old_reserves` ( -- this table holds all holds/reserves that have b
   `waitingdate` date default NULL, -- the date the item was marked as waiting for the patron at the library
   `expirationdate` DATE DEFAULT NULL, -- the date the hold expires (usually the date entered by the patron to say they don't need the hold after a certain date)
   `lowestPriority` tinyint(1) NOT NULL,
+  `suspend` BOOLEAN NOT NULL DEFAULT 0,
+  `suspend_until` DATETIME NULL DEFAULT NULL,
   KEY `old_reserves_borrowernumber` (`borrowernumber`),
   KEY `old_reserves_biblionumber` (`biblionumber`),
   KEY `old_reserves_itemnumber` (`itemnumber`),
@@ -1652,6 +1654,8 @@ CREATE TABLE `reserves` ( -- information related to holds/reserves in Koha
   `waitingdate` date default NULL, -- the date the item was marked as waiting for the patron at the library
   `expirationdate` DATE DEFAULT NULL, -- the date the hold expires (usually the date entered by the patron to say they don't need the hold after a certain date)
   `lowestPriority` tinyint(1) NOT NULL,
+  `suspend` BOOLEAN NOT NULL DEFAULT 0,
+  `suspend_until` DATETIME NULL DEFAULT NULL,
   KEY priorityfoundidx (priority,found),
   KEY `borrowernumber` (`borrowernumber`),
   KEY `biblionumber` (`biblionumber`),
index 4a12a17..e8c22ee 100644 (file)
@@ -359,3 +359,4 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('Babeltheque_url_update', '', 'Url for Babeltheque update (E.G. http://www.babeltheque.com/.../file.csv.bz2)', '', 'Free');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('SocialNetworks','1','Enable/Disable social networks links in opac detail pages','','YesNo');
 INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES('SubscriptionDuplicateDroppedInput','','','List of fields which must not be rewritten when a subscription is duplicated (Separated by pipe |)','Free');
+INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('AutoResumeSuspendedHolds',  '1', NULL ,  'Allow suspended holds to be automatically resumed by a set date.',  'YesNo');
index d29c8e4..ddc288c 100755 (executable)
@@ -5095,6 +5095,20 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
     SetVersion($DBversion);
 }
 
+$DBversion = "3.07.00.042";
+if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
+    $dbh->do("ALTER TABLE reserves ADD suspend BOOLEAN NOT NULL DEFAULT 0");
+    $dbh->do("ALTER TABLE old_reserves ADD suspend BOOLEAN NOT NULL DEFAULT 0");
+
+    $dbh->do("ALTER TABLE reserves ADD suspend_until DATETIME NULL DEFAULT NULL");
+    $dbh->do("ALTER TABLE old_reserves ADD suspend_until DATETIME NULL DEFAULT NULL");
+
+    $dbh->do("INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('AutoResumeSuspendedHolds',  '1', NULL ,  'Allow suspended holds to be automatically resumed by a set date.',  'YesNo')");
+
+    print "Upgrade to $DBversion done (Add suspend fields to reserves table, add syspref AutoResumeSuspendedHolds)\n";
+    SetVersion ($DBversion);
+}
+
 =head1 FUNCTIONS
 
 =head2 DropAllForeignKeys($table)
index 59ed564..471aa0e 100644 (file)
@@ -344,6 +344,12 @@ Circulation:
                   yes: Transfer
                   no: "Don't transfer"
             - items when cancelling all waiting holds.
+        -
+            - pref: AutoResumeSuspendedHolds
+              choices:
+                  yes: Allow
+                  no: "Don't allow"
+            - suspended holds to be automatically resumed by a set date.
     Fines Policy:
         -
             - Calculate fines based on days overdue
index eaa4a8d..57c16ee 100644 (file)
@@ -947,9 +947,10 @@ No patron matched <span class="ex">[% message %]</span>
             <th>Hold date</th>
             <th>Title</th>
             <th>Call Number</th>
-                       <th>Barcode</th>
+            <th>Barcode</th>
             <th>Priority</th>
-                       <th>Delete?</th>
+            <th>Delete?</th>
+            <th>&nbsp;</th>
         </tr></thead>
                <tbody>
         [% FOREACH reservloo IN reservloop %]
@@ -976,11 +977,65 @@ No patron matched <span class="ex">[% message %]</span>
                 <input type="hidden" name="borrowernumber" value="[% borrowernumber %]" />
                 <input type="hidden" name="reservenumber" value="[% reservloo.reservenumber %]" />
             </td>
+            <td>[% IF ( reservloo.suspend ) %]Suspended [% IF ( reservloo.suspend_until ) %] until [% reservloo.suspend_until %][% END %][% END %]</td>
             </tr>
         [% END %]</tbody>
     </table>
                <fieldset class="action"><input type="submit" class="cancel" name="submit" value="Cancel Marked Requests" /></fieldset>
     </form>
+
+    <fieldset class="action">
+        <form action="/cgi-bin/koha/reserve/modrequest_suspendall.pl" method="post">
+            <input type="hidden" name="from" value="circ" />
+            <input type="hidden" name="borrowernumber" value="[% borrowernumber %]" />
+            <input type="submit" value="Suspend All Requests" />
+
+            [% IF AutoResumeSuspendedHolds %]
+            <label for="suspend_until">until</label>
+            <input type="text" size="10" id="suspend_until" name="suspend_until"/>
+            <img src="[% themelang %]/lib/calendar/cal.gif" alt="Show Calendar"  border="0" id="CalendarSuspendUntil" style="cursor: pointer;" />
+            <span class="hint">Specify date on which to resume [% INCLUDE 'date-format.inc' %]: </span>
+
+             <script language="JavaScript" type="text/javascript">
+                        //<![CDATA[
+                   function validate1(date) {
+                         var today = new Date();
+                         if ( date < today ) {
+                             return true;
+                          } else {
+                             return false;
+                          }
+                     };
+                     function refocus(calendar) {
+                        $('#barcode').focus();
+                        calendar.hide();
+                     };
+                               //#TODO - ADD syspref (AllowPostDatedCheckouts).
+                     Calendar.setup(
+                          {
+                             inputField : "suspend_until",
+                             ifFormat : "[% DHTMLcalendar_dateformat %]",
+                             button : "CalendarSuspendUntil",
+//                           disableFunc : validate1,
+//                           dateStatusFunc : validate1,
+                             onClose : refocus
+                           }
+                        );
+                               //]]>
+             </script>
+             [% END %]
+        </form>
+    </fieldset>
+
+    <fieldset class="action">
+        <form action="/cgi-bin/koha/reserve/modrequest_suspendall.pl" method="post">
+            <input type="hidden" name="from" value="circ" />
+            <input type="hidden" name="borrowernumber" value="[% borrowernumber %]" />
+            <input type="hidden" name="suspend" value="0" />
+            <input type="submit" value="Resume All Suspended All Requests" />
+       </form>
+    </fieldset>
+
        [% ELSE %]
        <p>Patron has nothing on hold.</p>
 [% END %]
index 7a62b00..b568ec9 100644 (file)
@@ -606,6 +606,7 @@ function validate1(date) {
                        <th>Barcode</th>
                        <th>Priority</th>
                        <th>Delete?</th>
+                       <th>&nbsp;</th>
                </tr></thead>
                <tbody>[% FOREACH reservloo IN reservloop %]
                <tr class="[% reservloo.color %]">
@@ -637,12 +638,65 @@ function validate1(date) {
                 <input type="hidden" name="biblionumber" value="[% reservloo.biblionumber %]" />
                 <input type="hidden" name="borrowernumber" value="[% borrowernumber %]" />
             </td>
+            <td>[% IF ( reservloo.suspend ) %]Suspended [% IF ( reservloo.suspend_until ) %] until [% reservloo.suspend_until %][% END %][% END %]</td>
         </tr>
                [% END %]</tbody>
     </table>
 
         <fieldset class="action"><input type="submit" class="cancel" name="submit" value="Cancel Marked Requests" /></fieldset>
     </form>
+    <fieldset class="action">
+        <form action="/cgi-bin/koha/reserve/modrequest_suspendall.pl" method="post">
+            <input type="hidden" name="from" value="borrower" />
+            <input type="hidden" name="borrowernumber" value="[% borrowernumber %]" />
+            <input type="submit" value="Suspend All Requests" />
+
+            [% IF AutoResumeSuspendedHolds %]
+            <label for="suspend_until">until</label>
+            <input type="text" size="10" id="suspend_until" name="suspend_until"/>
+            <img src="[% themelang %]/lib/calendar/cal.gif" alt="Show Calendar"  border="0" id="CalendarSuspendUntil" style="cursor: pointer;" />
+            <span class="hint">Specify date on which to resume [% INCLUDE 'date-format.inc' %]: </span>
+
+             <script language="JavaScript" type="text/javascript">
+                        //<![CDATA[
+                   function validate1(date) {
+                         var today = new Date();
+                         if ( date < today ) {
+                             return true;
+                          } else {
+                             return false;
+                          }
+                     };
+                     function refocus(calendar) {
+                        $('#barcode').focus();
+                        calendar.hide();
+                     };
+                               //#TODO - ADD syspref (AllowPostDatedCheckouts).
+                     Calendar.setup(
+                          {
+                             inputField : "suspend_until",
+                             ifFormat : "[% DHTMLcalendar_dateformat %]",
+                             button : "CalendarSuspendUntil",
+//                           disableFunc : validate1,
+//                           dateStatusFunc : validate1,
+                             onClose : refocus
+                           }
+                        );
+                               //]]>
+             </script>
+            [% END %]
+        </form>
+    </fieldset>
+
+    <fieldset class="action">
+        <form action="/cgi-bin/koha/reserve/modrequest_suspendall.pl" method="post">
+            <input type="hidden" name="from" value="borrower" />
+            <input type="hidden" name="borrowernumber" value="[% borrowernumber %]" />
+            <input type="hidden" name="suspend" value="0" />
+            <input type="submit" value="Resume All Suspended All Requests" />
+       </form>
+    </fieldset>
+
     [% ELSE %]<p>Patron has nothing on hold.</p>[% END %]
        </div>
 
index a257e2e..3a5c8c3 100644 (file)
@@ -597,6 +597,7 @@ function checkMultiHold() {
             <th><img src="/intranet-tmpl/[% theme %]/img/go-bottom.png" border="0" alt="Toggle Set to Lowest Priority" /></th>
         [% END %]
        <th>&nbsp;</th>
+       <th>&nbsp;</th>
       </tr>
   [% FOREACH reserveloo IN biblioloo.reserveloop %]
   [% UNLESS ( loop.odd ) %]<tr class="highlight">[% ELSE %]<tr>[% END %]
@@ -653,7 +654,7 @@ function checkMultiHold() {
         <td>
     [% IF ( reserveloo.wait ) %]
        [% IF ( reserveloo.atdestination ) %]
-                [% IF ( reserveloo.found ) %]
+            [% IF ( reserveloo.found ) %]
                 Item waiting at <b> [% reserveloo.wbrname %]</b> <input type="hidden" name="pickup" value="[% reserveloo.wbrcode %]" />
             [% ELSE %]
                 Waiting to be pulled <input type="hidden" name="pickup" value="[% reserveloo.wbrcode %]" />
@@ -728,6 +729,44 @@ function checkMultiHold() {
                 </a>
        </td>
 
+       <td>
+       [% UNLESS ( reserveloo.wait ) %]
+            <input type="button" value="[% IF ( reserveloo.suspend ) %]Unsuspend[% ELSE %]Suspend[% END %]" onclick="window.location.href='request.pl?action=toggleSuspend&amp;borrowernumber=[% reserveloo.borrowernumber %]&amp;biblionumber=[% reserveloo.biblionumber %]&amp;date=[% reserveloo.date %]'" />
+
+            [% IF AutoResumeSuspendedHolds %]
+           <label for="suspend_until_[% reserveloo.borrowernumber %]">[% IF ( reserveloo.suspend ) %] on [% ELSE %] until [% END %]</label>
+           <input name="suspend_until" id="suspend_until_[% reserveloo.borrowernumber %]" size="10" readonly="readonly" value="[% reserveloo.suspend_until %]" />
+           <img src="[% themelang %]/lib/calendar/cal.gif" alt="Show Calendar" border="0" id="SuspendUntilDate_[% reserveloo.borrowernumber %]" style="cursor: pointer;" />
+           <script language="JavaScript" type="text/javascript">
+               //<![CDATA[
+               function validate1(date) {
+                       var today = new Date();
+                       if ( (date > today) ||
+                    ( date.getDate() == today.getDate() &&
+                      date.getMonth() == today.getMonth() &&
+                      date.getFullYear() == today.getFullYear() ) ) {
+                               return false;
+                       } else {
+                               return true;
+                       }
+               };
+               Calendar.setup(
+                       {
+                               inputField : "suspend_until_[% reserveloo.borrowernumber %]",
+                               ifFormat : "[% DHTMLcalendar_dateformat %]",
+                               button : "SuspendUntilDate_[% reserveloo.borrowernumber %]",
+                               disableFunc : validate1,
+                               dateStatusFunc : validate1
+                       }
+               );
+               //]]>
+           </script>
+           <a href='#' onclick="document.getElementById('suspend_until_[% reserveloo.borrowernumber %]').value='';">Clear Date</a>
+            [% END %]
+       [% ELSE %]
+               <input type="hidden" name="suspend_until" value="" />
+       [% END %]
+       </td>
       </tr>
 
   [% END %] <!-- existing reserveloop -->
index 19b7389..b8e98a2 100644 (file)
@@ -3,6 +3,7 @@
 [% INCLUDE 'doc-head-open.inc' %]
 [% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha Online[% END %] Catalog &rsaquo; Your library home
 [% INCLUDE 'doc-head-close.inc' %]
+[% INCLUDE 'calendar.inc' %]
 <script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.metadata.min.js"></script>
 <script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.tablesorter.min.js"></script>
 <script type="text/JavaScript">
@@ -397,6 +398,8 @@ $.tablesorter.addParser({
                             [% IF ( RESERVE.intransit ) %]
                                 Item in transit from <b> [% RESERVE.frombranch %]</b> since 
                                 [% RESERVE.datesent | $KohaDates %]
+                            [% ELSIF ( RESERVE.suspend ) %]
+                                Suspended [% IF ( RESERVE.suspend_until ) %] until [% RESERVE.suspend_until %] [% END %]
                             [% ELSE %]
                                 Pending
                             [% END %]
@@ -409,14 +412,66 @@ $.tablesorter.addParser({
                <input type="hidden" name="reservenumber" value="[% RESERVE.reservenumber %]" />
                        <input type="submit" name="submit" class="icon delete cancel" value="Cancel" onclick="return confirmDelete('Are you sure you want to cancel this hold?');" /></form>
                [% ELSE %]
-                       &nbsp;
                [% END %]
                </td>
 
+
             </tr>
             [% END %]
                        </tbody>
         </table>
+
+       <div>
+            <form action="/cgi-bin/koha/opac-modrequest-suspend.pl" method="post">
+              <input type="submit" name="submit" class="icon delete cancel" value="Suspend all holds" onclick="return confirmDelete('Are you sure you want to suspend all holds?');" />
+              <input type="hidden" name="suspend" value="1" />
+
+             [% IF AutoResumeSuspendedHolds %]
+             <label for="suspend_until"> until </label>
+              <input name="suspend_until" id="suspend_until" readonly="readonly" size="10">
+              <script language="JavaScript" type="text/javascript">
+              //<![CDATA[
+
+              var cal_img = document.createElement('img');
+              cal_img.src = "[% themelang %]/lib/calendar/cal.gif";
+              cal_img.alt = "Show Calendar";
+              cal_img.border = "0";
+              cal_img.id = "CalendarSuspendUntil";
+              cal_img.style.cursor = "pointer";
+              document.getElementById("suspend_until").parentNode.appendChild( cal_img );
+
+              function validate(date) {
+                  var today = new Date();
+                        if ( (date > today) ||
+                                ( date.getDate() == today.getDate() &&
+                                  date.getMonth() == today.getMonth() &&
+                                  date.getFullYear() == today.getFullYear() ) ) {
+                            return false;
+                        } else {
+                            return true;
+                        }
+              };
+              Calendar.setup(
+              {
+                inputField : "suspend_until",
+                ifFormat : "[% DHTMLcalendar_dateformat %]",
+                button : "CalendarSuspendUntil",
+                disableFunc : validate,
+                dateStatusFunc : validate
+              }
+              );
+              //]]>
+              </script>
+              <a href="#" style="font-size:85%;text-decoration:none;" onclick="document.getElementById('suspend_until').value='';return false;">Clear Date</a></p>
+              [% END %]
+            </form>
+       </div>
+       <div>
+            <form action="/cgi-bin/koha/opac-modrequest-suspend.pl" method="post">
+              <input type="submit" name="submit" class="icon delete cancel" value="Resume all suspended holds" onclick="return confirmDelete('Are you sure you want to resume all suspended holds?');" />
+              <input type="hidden" name="suspend" value="0" />
+            </form>
+       </div>
     </div>
     [% END %]
     </div><!-- /opac-user views -->
index a83bce9..32541c9 100755 (executable)
@@ -320,6 +320,8 @@ if ($borrowernumber) {
             $getreserv{biblionumber}  = $num_res->{'biblionumber'};    
         }
         $getreserv{waitingposition} = $num_res->{'priority'};
+        $getreserv{suspend} = $num_res->{'suspend'};
+        $getreserv{suspend_until} = C4::Dates->new( $num_res->{'suspend_until'}, "iso")->output("syspref");;
 
         push( @reservloop, \%getreserv );
     }
@@ -427,8 +429,8 @@ $template->param(
     "dateformat_" . (C4::Context->preference("dateformat") || '') => 1,
     samebranch     => $samebranch,
     quickslip            => $quickslip,
-       activeBorrowerRelationship => (C4::Context->preference('borrowerRelationship') ne ''),
-);
+    activeBorrowerRelationship => (C4::Context->preference('borrowerRelationship') ne ''),
+    AutoResumeSuspendedHolds => C4::Context->preference('AutoResumeSuspendedHolds') );
 
 output_html_with_http_headers $input, $cookie, $template->output;
 
diff --git a/misc/cronjobs/holds/auto_unsuspend_holds.pl b/misc/cronjobs/holds/auto_unsuspend_holds.pl
new file mode 100755 (executable)
index 0000000..268910b
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+
+# Copyright 2009-2010 Kyle Hall
+#
+# 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 strict;
+#use warnings; FIXME - Bug 2505
+
+BEGIN {
+    # find Koha's Perl modules
+    # test carefully before changing this
+    use FindBin;
+    eval { require "$FindBin::Bin/../kohalib.pl" };
+}
+
+# cancel all expired hold requests
+
+use C4::Reserves;
+
+AutoUnsuspendReserves();
diff --git a/opac/opac-modrequest-suspend.pl b/opac/opac-modrequest-suspend.pl
new file mode 100755 (executable)
index 0000000..ec15265
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+
+# 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 strict;
+use warnings;
+
+use CGI;
+use C4::Output;
+use C4::Reserves;
+use C4::Auth;
+my $query = new CGI;
+my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+    {
+        template_name   => "opac-account.tmpl",
+        query           => $query,
+        type            => "opac",
+        authnotrequired => 0,
+        flagsrequired   => { borrow => 1 },
+        debug           => 1,
+    }
+);
+
+my $suspend       = $query->param('suspend');
+my $suspend_until = $query->param('suspend_until') || undef;
+
+SuspendAll(
+    borrowernumber => $borrowernumber,
+    suspend        => $suspend,
+    suspend_until  => $suspend_until,
+);
+
+print $query->redirect("/cgi-bin/koha/opac-user.pl#opac-user-holds");
index b89e862..a9a6305 100755 (executable)
@@ -263,6 +263,7 @@ foreach my $res (@reserves) {
     if ($OPACDisplayRequestPriority) {
         $res->{'priority'} = '' if $res->{'priority'} eq '0';
     }
+    $res->{'suspend_until'} = C4::Dates->new( $res->{'suspend_until'}, "iso")->output("syspref") if ( $res->{'suspend_until'} );
 }
 
 # use Data::Dumper;
@@ -360,5 +361,8 @@ $template->param(
     dateformat    => C4::Context->preference("dateformat"),
 );
 
+$template->param( DHTMLcalendar_dateformat  => C4::Dates->DHTMLcalendar() );
+$template->param( AutoResumeSuspendedHolds => C4::Context->preference('AutoResumeSuspendedHolds') );
+
 output_html_with_http_headers $query, $cookie, $template->output;
 
index eecd86b..03ef064 100755 (executable)
@@ -46,6 +46,7 @@ my @biblionumber=$query->param('biblionumber');
 my @borrower=$query->param('borrowernumber');
 my @branch=$query->param('pickup');
 my @itemnumber=$query->param('itemnumber');
+my @suspend_until=$query->param('suspend_until');
 my $multi_hold = $query->param('multi_hold');
 my $biblionumbers = $query->param('biblionumbers');
 my $count=@rank;
@@ -66,7 +67,7 @@ if ($CancelBorrowerNumber) {
 else {
     for (my $i=0;$i<$count;$i++){
         undef $itemnumber[$i] unless $itemnumber[$i] ne '';
-        ModReserve($rank[$i],$biblionumber[$i],$borrower[$i],$branch[$i],$itemnumber[$i]); #from C4::Reserves
+        ModReserve($rank[$i],$biblionumber[$i],$borrower[$i],$branch[$i],$itemnumber[$i],$suspend_until[$i]); #from C4::Reserves
     }
 }
 my $from=$query->param('from');
diff --git a/reserve/modrequest_suspendall.pl b/reserve/modrequest_suspendall.pl
new file mode 100755 (executable)
index 0000000..48d5412
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+
+#script to modify reserves/requests
+#written 2/1/00 by chris@katipo.oc.nz
+#last update 27/1/2000 by chris@katipo.co.nz
+
+
+# Copyright 2000-2002 Katipo Communications
+#
+# 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 strict;
+use warnings;
+use CGI;
+use C4::Output;
+use C4::Reserves;
+use C4::Auth;
+
+my $query = new CGI;
+my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+    {
+        template_name   => "about.tmpl",
+        query           => $query,
+        type            => "intranet",
+        authnotrequired => 0,
+        flagsrequired   => { catalogue => 1 },
+        debug           => 1,
+    }
+);
+
+my $borrowernumber = $query->param('borrowernumber');
+my $suspend        = $query->param('suspend');
+my $suspend_until  = $query->param('suspend_until');
+
+SuspendAll( borrowernumber => $borrowernumber, suspend_until => $suspend_until, suspend => $suspend );
+
+my $from = $query->param('from');
+$from ||= q{};
+if ( $from eq 'borrower'){
+    print $query->redirect("/cgi-bin/koha/members/moremember.pl?borrowernumber=$borrowernumber");
+} elsif ( $from eq 'circ'){
+    print $query->redirect("/cgi-bin/koha/circ/circulation.pl?borrowernumber=$borrowernumber");
+} else {
+    print $query->redirect("/cgi-bin/koha/circ/circulation.pl?borrowernumber=$borrowernumber");
+}
index b96447f..ff01850 100755 (executable)
@@ -110,6 +110,10 @@ if ( $action eq 'move' ) {
   my $borrowernumber = $input->param('borrowernumber');
   my $biblionumber   = $input->param('biblionumber');
   ToggleLowestPriority( $borrowernumber, $biblionumber );
+} elsif ( $action eq 'toggleSuspend' ) {
+  my $borrowernumber = $input->param('borrowernumber');
+  my $biblionumber   = $input->param('biblionumber');
+  ToggleSuspend( $borrowernumber, $biblionumber );
 }
 
 if ($findborrower) {
@@ -568,7 +572,8 @@ foreach my $biblionumber (@biblionumbers) {
         $reserve{'lowestPriority'}    = $res->{'lowestPriority'};
         $reserve{'branchloop'} = GetBranchesLoop($res->{'branchcode'});
         $reserve{'optionloop'} = \@optionloop;
-
+        $reserve{'suspend'} = $res->{'suspend'};
+        $reserve{'suspend_until'} = C4::Dates->new( $res->{'suspend_until'}, "iso")->output("syspref");
         push( @reserveloop, \%reserve );
     }
 
@@ -627,5 +632,7 @@ if ( C4::Context->preference( 'AllowHoldDateInFuture' ) ) {
     $template->param( reserve_in_future => 1 );
 }
 
+$template->param( AutoResumeSuspendedHolds => C4::Context->preference('AutoResumeSuspendedHolds') );
+
 # printout the page
 output_html_with_http_headers $input, $cookie, $template->output;