Skip to content

Commit

Permalink
Improvements to hold-expiration process
Browse files Browse the repository at this point in the history
This patch adds a expirationdate column to reserves and old_reserves,
to set more-firm rather than calculated-on-the-fly expirations, and creates
a cronjob to move expired holds out of the queue, and to the old_reserves
table.  The expiration date is manually enterable in several places, and
displays are updated to show the date. Several places that were using
on-the-fly calculations of the date were revised to use the table value,
and the calculation of table values was set to take advantage of the
library calendar, so that holds will not expire on a closed day.

Be sure to execute the following SQL for an upgrade to this patch:

  ALTER TABLE reserves ADD expirationdate date;
  ALTER TABLE old_reserves ADD expirationdate date;
  • Loading branch information
dlbptfs authored and J. David Bavousett committed Mar 4, 2010
1 parent 8d4b607 commit 1da1059
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 47 deletions.
50 changes: 41 additions & 9 deletions C4/Reserves.pm
Expand Up @@ -28,6 +28,8 @@ use C4::Items;
use C4::Search;
use C4::Circulation;
use C4::Accounts;
use C4::Dates;
use C4::Calendar;

# for _koha_notify_reserve
use C4::Members::Messaging;
Expand All @@ -36,6 +38,7 @@ use C4::Letters;
use C4::Branch qw( GetBranchDetail );
use C4::Dates qw( format_date_in_iso );
use List::MoreUtils qw( firstidx );
use Date::Calc qw(Today Add_Delta_Days);

use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);

Expand Down Expand Up @@ -985,15 +988,44 @@ sub ModReserveAffect {
}
else {
# affect the reserve to Waiting as well.
$query = "
UPDATE reserves
SET priority = 0,
found = 'W',
waitingdate=now(),
itemnumber = ?
WHERE borrowernumber = ?
AND biblionumber = ?
";
my $holdperiod = C4::Context->preference('ReservesMaxPickUpDelay');
if ((!defined($holdperiod)) || ($holdperiod eq '') || ($holdperiod == 0)) {
$query = "
UPDATE reserves
SET priority = 0,
found = 'W',
waitingdate=now(),
itemnumber = ?
WHERE borrowernumber = ?
AND biblionumber = ?
";
}
else {
my ($holdexpyear,$holdexpmonth,$holdexpday) = Today();
my $holdstartdate = C4::Dates->new(sprintf "%02d/%02d/%04d",$holdexpmonth,$holdexpday,$holdexpyear, 'us');

# Grab branch for calendar purposes
$sth = $dbh->prepare("SELECT branchcode FROM reserves WHERE borrowernumber=? AND biblionumber=?");
$sth->execute($borrowernumber,$biblionumber);
my ($branch) = $sth->fetchrow;

# Check to see if hold expiration date falls on a closed library day.
# Note the useDaysMode syspref will need to be set to Calendar for
# the code to advance to the next non-closed day.
my $calendar = C4::Calendar->new( branchcode => $branch);
my $holdexpdate = $calendar->addDate($holdstartdate, $holdperiod);
my $sqlexpdate = $holdexpdate->output('iso');
$query = "
UPDATE reserves
SET priority = 0,
found = 'W',
waitingdate=now(),
itemnumber = ?,
expirationdate='$sqlexpdate'
WHERE borrowernumber = ?
AND biblionumber = ?
";
}
}
$sth = $dbh->prepare($query);
$sth->execute( $itemnumber, $borrowernumber,$biblionumber);
Expand Down
21 changes: 11 additions & 10 deletions circ/circulation.pl
Expand Up @@ -365,16 +365,17 @@
$getreserv{waitingat} = GetBranchName( $num_res->{'branchcode'} );
# check if we have a waiting status for reservations
if ( $num_res->{'found'} eq 'W' ) {
$getreserv{color} = 'reserved';
$getreserv{waiting} = 1;
# genarate information displaying only waiting reserves
$getWaitingReserveInfo{title} = $getiteminfo->{'title'};
$getWaitingReserveInfo{biblionumber} = $getiteminfo->{'biblionumber'};
$getWaitingReserveInfo{itemtype} = $itemtypeinfo->{'description'};
$getWaitingReserveInfo{author} = $getiteminfo->{'author'};
$getWaitingReserveInfo{reservedate} = format_date( $num_res->{'reservedate'} );
$getWaitingReserveInfo{waitingat} = GetBranchName( $num_res->{'branchcode'} );
$getWaitingReserveInfo{waitinghere} = 1 if $num_res->{'branchcode'} eq $branch;
$getreserv{color} = 'reserved';
$getreserv{waiting} = 1;
$getreserv{holdexpdate} = format_date( $num_res->{'expirationdate'} );
# generate information displaying only waiting reserves
$getWaitingReserveInfo{title} = $getiteminfo->{'title'};
$getWaitingReserveInfo{biblionumber} = $getiteminfo->{'biblionumber'};
$getWaitingReserveInfo{itemtype} = $itemtypeinfo->{'description'};
$getWaitingReserveInfo{author} = $getiteminfo->{'author'};
$getWaitingReserveInfo{reservedate} = format_date( $num_res->{'reservedate'} );
$getWaitingReserveInfo{waitingat} = GetBranchName( $num_res->{'branchcode'} );
$getWaitingReserveInfo{waitinghere} = 1 if $num_res->{'branchcode'} eq $branch;
}
# check transfers with the itemnumber foud in th reservation loop
if ($transfertwhen) {
Expand Down
2 changes: 2 additions & 0 deletions installer/data/mysql/kohastructure.sql
Expand Up @@ -1521,6 +1521,7 @@ CREATE TABLE `old_reserves` (
`timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`itemnumber` int(11) default NULL,
`waitingdate` date default NULL,
`expirationdate` date default NULL,
KEY `old_reserves_borrowernumber` (`borrowernumber`),
KEY `old_reserves_biblionumber` (`biblionumber`),
KEY `old_reserves_itemnumber` (`itemnumber`),
Expand Down Expand Up @@ -1693,6 +1694,7 @@ CREATE TABLE `reserves` (
`timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`itemnumber` int(11) default NULL,
`waitingdate` date default NULL,
`expirationdate` date default NULL,
KEY `borrowernumber` (`borrowernumber`),
KEY `biblionumber` (`biblionumber`),
KEY `itemnumber` (`itemnumber`),
Expand Down
9 changes: 6 additions & 3 deletions koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tmpl
Expand Up @@ -797,7 +797,8 @@ No patron matched <span class="ex"><!-- TMPL_VAR name="message" --></span>
<input type="hidden" name="from" value="circ" />
<table id="holdst">
<thead><tr>
<th>Hold date</th>
<th>Hold Date</th>
<th>Hold Expiration Date</th>
<th>Title</th>
<th>Call Number</th>
<th>Barcode</th>
Expand All @@ -807,8 +808,10 @@ No patron matched <span class="ex"><!-- TMPL_VAR name="message" --></span>
<tbody>
<!-- TMPL_LOOP NAME="reservloop" -->
<tr class="<!-- TMPL_VAR NAME="color" -->">
<td><!-- TMPL_VAR NAME="reservedate" --></td>
<td><a href="/cgi-bin/koha/reserve/request.pl?biblionumber=<!-- TMPL_VAR NAME="biblionumber" -->"><strong><!-- TMPL_VAR NAME="title" escape="html" --></strong></a><!-- TMPL_IF NAME="author" -->, by <!-- TMPL_VAR NAME="author" --><!-- /TMPL_IF --></td>
<td align=center><!-- TMPL_VAR NAME="reservedate" --></td>
<td align=center><!-- TMPL_VAR NAME="holdexpdate" --></td>
<td><a href="/cgi-bin/koha/reserve/request.pl?biblionumber=<!-- TMPL_VAR NAME="biblionumber" -->"><!-- TMPL_VAR NAME="title" escape="html" --></a><!-- TMPL_IF NAME="author" -->, by <!-- TMPL_VAR NAME="author" --><!-- /TMPL_IF --></td>
<td><!-- TMPL_VAR NAME="itemtype" --></td>
<td><!-- TMPL_VAR NAME="itemcallnumber" --></td>
<td><em><!-- TMPL_IF name="barcodereserv" -->Item <!-- TMPL_VAR NAME="barcodereserv" -->
<!-- /TMPL_IF --><!-- TMPL_IF name="waiting" --> <strong>waiting at <!-- TMPL_VAR NAME="waitingat" --></strong>
Expand Down
42 changes: 21 additions & 21 deletions koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tmpl
Expand Up @@ -515,7 +515,8 @@ if (nodename =="barcodes[]"){
<input type="hidden" name="from" value="borrower" />
<table id="holdst">
<thead><tr>
<th>Hold date</th>
<th>Hold Date</th>
<th>Hold Expiration Date</th>
<th>Title</th>
<th>Call Number</th>
<th>Barcode</th>
Expand All @@ -524,26 +525,25 @@ if (nodename =="barcodes[]"){
</tr></thead>
<tbody><!-- TMPL_LOOP NAME="reservloop" -->
<tr class="<!-- TMPL_VAR NAME="color" -->">
<td><!-- TMPL_VAR NAME="reservedate" --></td>
<td>
<a href="/cgi-bin/koha/reserve/request.pl?biblionumber=<!-- TMPL_VAR NAME="biblionumber" -->"><!-- TMPL_VAR NAME="title" escape="html" --></a><!-- TMPL_IF NAME="author" -->, by <!-- TMPL_VAR NAME="author" --><!-- /TMPL_IF -->
</td>
<td><!-- TMPL_VAR NAME="itemcallnumber" --></td>
<td><!-- TMPL_IF name="waiting" -->
<em>Item is <strong>waiting</strong></em>
<!-- /TMPL_IF -->
<!-- TMPL_IF name="transfered" -->
<em>Item <strong>in transit</strong> from
<!-- TMPL_VAR NAME="frombranch" --> since <!-- TMPL_VAR NAME="datesent" --> </em>
<!-- /TMPL_IF -->

<!-- TMPL_IF name="nottransfered" -->
<em>Item hasn't been transfered yet from <!-- TMPL_VAR NAME="nottransferedby" --></em>
<!-- /TMPL_IF -->
<!-- TMPL_IF name="barcodereserv" -->
<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=<!-- TMPL_VAR NAME="biblionumber" -->"><!-- TMPL_VAR NAME="barcodereserv" --></a>
<!-- /TMPL_IF -->
</td>
<td><!-- TMPL_VAR NAME="reservedate" --></td>
<td align=center><!-- TMPL_VAR NAME="holdexpdate" --></td>
<td><a href="/cgi-bin/koha/reserve/request.pl?biblionumber=<!-- TMPL_VAR NAME="biblionumber" -->"><!-- TMPL_VAR NAME="title" escape="html" --></a><!-- TMPL_IF NAME="author" -->, by <!-- TMPL_VAR NAME="author" --><!-- /TMPL_IF --></td>
<td><!-- TMPL_VAR NAME="itemtype" --></td>
<td><!-- TMPL_VAR NAME="itemcallnumber" --></td>
<td><!-- TMPL_IF name="waiting" -->
<em>Item is <strong>waiting</strong></em>
<!-- /TMPL_IF -->
<!-- TMPL_IF name="transfered" -->
<em>Item <strong>in transit</strong> from
<!-- TMPL_VAR NAME="frombranch" --> since <!-- TMPL_VAR NAME="datesent" --> </em>
<!-- /TMPL_IF -->
<!-- TMPL_IF name="nottransfered" -->
<em>Item hasn't been transfered yet from <!-- TMPL_VAR NAME="nottransferedby" --></em>
<!-- /TMPL_IF -->
<!-- TMPL_IF name="barcodereserv" -->
<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=<!-- TMPL_VAR NAME="biblionumber" -->"><!-- TMPL_VAR NAME="barcodereserv" --></a>
<!-- /TMPL_IF -->
</td>
<td><!-- TMPL_IF NAME="waitingposition" --><strong><!-- TMPL_VAR NAME="waitingposition" --></strong><!-- /TMPL_IF --></td>
<td><select name="rank-request">
<option value="n">No</option>
Expand Down
4 changes: 3 additions & 1 deletion koha-tmpl/opac-tmpl/prog/en/modules/opac-user.tmpl
Expand Up @@ -322,6 +322,7 @@ $.tablesorter.addParser({
<thead><tr>
<th>Title</th>
<th>Placed On</th>
<th>Expires On</th>
<th>Pick Up Location</th>
<!-- TMPL_IF NAME="showpriority" -->
<th>Priority</th>
Expand All @@ -347,7 +348,8 @@ $.tablesorter.addParser({
<td><a href="/cgi-bin/koha/opac-detail.pl?biblionumber=<!-- TMPL_VAR NAME="biblionumber" -->"><!-- TMPL_VAR NAME="reserves_title" --></a>
<!-- TMPL_VAR NAME="author" -->
</td>
<td><!-- TMPL_VAR NAME="reservedate" --></td>
<td align=center><!-- TMPL_VAR NAME="reservedate" --></td>
<td align=center><!-- TMPL_VAR NAME="holdexpdate" --></td>
<td><!-- TMPL_VAR NAME="branch" --></td>
<!-- TMPL_IF NAME="showpriority" -->
<td><!-- TMPL_VAR NAME="priority" --> </td>
Expand Down
12 changes: 9 additions & 3 deletions members/moremember.pl
Expand Up @@ -39,7 +39,7 @@ =head1 moremember.pl
use C4::Members;
use C4::Members::Attributes;
use C4::Members::AttributeTypes;
use C4::Dates;
use C4::Dates qw/format_date/;
use C4::Reserves;
use C4::Circulation;
use C4::Koha;
Expand Down Expand Up @@ -302,9 +302,15 @@ BEGIN
$getreserv{$_} = 0;
}
$getreserv{reservedate} = C4::Dates->new($num_res->{'reservedate'},'iso')->output('syspref');
foreach (qw(biblionumber title author itemcallnumber )) {
$getreserv{$_} = $getiteminfo->{$_};
if ($num_res->{'found'} eq 'W') {
$getreserv{holdexpdate} = format_date($num_res->{'expirationdate'});
}
else {
$getreserv{holdexpdate} = '';
}
foreach (qw(biblionumber title author itemcallnumber )) {
$getreserv{$_} = $getiteminfo->{$_};
}
$getreserv{barcodereserv} = $getiteminfo->{'barcode'};
$getreserv{itemtype} = $itemtypeinfo->{'description'};

Expand Down
82 changes: 82 additions & 0 deletions misc/cronjobs/holds/expireholds.pl
@@ -0,0 +1,82 @@
#!/usr/bin/perl
# run nightly -- remove holds that are later than waitingdate +
# ReservesMaxPickUpDelay from the reserves table.
#
# 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., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA

=head1 NAME
expireholds.pl - cron script to remove expired holds from the reserves table
=head1 SYNOPSIS
./expireholds.pl
or, in crontab:
0 1 * * * $KOHA_CRON_DIR/holds/expireholds.pl
=head1 DESCRIPTION
This script simply removes holds in the reserves table that have expired.
Previously, the ReservesMaxPickUpDelay syspref was being used to display
that holds had expired, but they were not being deleted from the reserves
table. This script corrects that problem.
=cut

use strict;
BEGIN {
# find Koha's Perl modules
# test carefully before changing this
use FindBin;
eval { require "$FindBin::Bin/../kohalib.pl" };
}

use C4::Context;
use C4::Dates;
my $today = C4::Dates->new();
my $today_iso = $today->output('iso');

my $dbh = C4::Context->dbh;
my $query = "SELECT * FROM reserves
WHERE expirationdate < ?";
my $sth = $dbh->prepare($query);
$sth->execute($today_iso);
while (my $expref = $sth->fetchrow_hashref) {
my $insert_fields = '';
my $value_fields = '';
foreach my $column ('borrowernumber','reservedate','biblionumber','constrainttype','branchcode','notificationdate','reminderdate','cancellationdate','reservenotes','priority','found','itemnumber','waitingdate','expirationdate') {
if (defined($expref->{$column})) {
if (length($insert_fields)) {
$insert_fields .= ",$column";
$value_fields .= ",\'$expref->{$column}\'";
}
else {
$insert_fields .= "$column";
$value_fields .= "\'$expref->{$column}\'";
}
}
}
my $inssql = "INSERT INTO old_reserves ($insert_fields)
VALUES ($value_fields)";
my $sth2 = $dbh->prepare($inssql);
$sth2->execute();
my $delsql = "DELETE FROM reserves
WHERE reservenumber = ?";
$sth2 = $dbh->prepare($delsql);
$sth2->execute($expref->{reservenumber});
}
$dbh->disconnect();
6 changes: 6 additions & 0 deletions opac/opac-user.pl
Expand Up @@ -184,6 +184,12 @@ BEGIN
my @reserves = GetReservesFromBorrowernumber( $borrowernumber );
foreach my $res (@reserves) {
$res->{'reservedate'} = format_date( $res->{'reservedate'} );
if ($res->{'found'} eq 'W') {
$res->{'holdexpdate'} = format_date( $res->{'expirationdate'} );
}
else {
$res->{'holdexpdate'} = '';
}
my $publictype = $res->{'publictype'};
$res->{$publictype} = 1;
$res->{'waiting'} = 1 if $res->{'found'} eq 'W';
Expand Down

0 comments on commit 1da1059

Please sign in to comment.