use C4::Letters;
use C4::Branch qw( GetBranchDetail );
use C4::Dates qw( format_date_in_iso );
+
+use Koha::DateUtils;
+
use List::MoreUtils qw( firstidx );
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
BEGIN {
# set the version for version checking
- $VERSION = 3.01;
+ $VERSION = 3.07.00.049;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(
&GetReservesToBranch
&GetReserveCount
&GetReserveFee
- &GetReserveInfo
+ &GetReserveInfo
&GetReserveStatus
&GetOtherReserves
&CancelReserve
&CancelExpiredReserves
+ &AutoUnsuspendReserves
+
&IsAvailableForItemLevelRequest
&AlterPriority
&ToggleLowestPriority
&ReserveSlip
+ &ToggleSuspend
+ &SuspendAll
);
@EXPORT_OK = qw( MergeHolds );
}
itemnumber,
reservenotes,
expirationdate,
- lowestPriority
+ lowestPriority,
+ suspend,
+ suspend_until
FROM reserves
WHERE biblionumber = ? ";
unless ( $all_dates ) {
sub CanBookBeReserved{
my ($borrowernumber, $biblionumber) = @_;
- my @items = get_itemnumbers_of($biblionumber);
+ my $items = GetItemnumbersForBiblio($biblionumber);
#get items linked via host records
my @hostitems = get_hostitemnumbers_of($biblionumber);
if (@hostitems){
- push (@items,@hostitems);
+ push (@$items,@hostitems);
}
- foreach my $item (@items){
+ foreach my $item (@$items){
return 1 if CanItemBeReserved($borrowernumber, $item);
}
return 0;
sub CancelExpiredReserves {
+ # Cancel reserves that have passed their expiration date.
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare( "
SELECT * FROM reserves WHERE DATE(expirationdate) < DATE( CURDATE() )
AND expirationdate IS NOT NULL
+ AND found IS NULL
" );
$sth->execute();
CancelReserve( $res->{'biblionumber'}, '', $res->{'borrowernumber'} );
}
+ # Cancel reserves that have been waiting too long
+ if ( C4::Context->preference("ExpireReservesMaxPickUpDelay") ) {
+ my $max_pickup_delay = C4::Context->preference("ReservesMaxPickUpDelay");
+ my $charge = C4::Context->preference("ExpireReservesMaxPickUpDelayCharge");
+
+ my $query = "SELECT * FROM reserves WHERE TO_DAYS( NOW() ) - TO_DAYS( waitingdate ) > ? AND found = 'W' AND priority = 0";
+ $sth = $dbh->prepare( $query );
+ $sth->execute( $max_pickup_delay );
+
+ while (my $res = $sth->fetchrow_hashref ) {
+ if ( $charge ) {
+ manualinvoice($res->{'borrowernumber'}, $res->{'itemnumber'}, 'Hold waiting too long', 'F', $charge);
+ }
+
+ CancelReserve( $res->{'biblionumber'}, '', $res->{'borrowernumber'} );
+ }
+ }
+
+}
+
+=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
Cancels a reserve.
Use either C<$biblionumber> or C<$itemnumber> to specify the item to
-cancel, but not both: if both are given, C<&CancelReserve> does
-nothing.
+cancel, but not both: if both are given, C<&CancelReserve> uses
+C<$itemnumber>.
C<$borrowernumber> is the borrower number of the patron on whose
behalf the book was reserved.
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;
}
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");
+ $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);
}
}
#first : check if we have a reservation for this item .
my ($itemnumber, $newstatus) = @_;
- my $dbh = C4::Context->dbh;
- my $query = " UPDATE reserves
- SET found=?,waitingdate = now()
- WHERE itemnumber=?
- AND found IS NULL
- AND priority = 0
- ";
+ my $dbh = C4::Context->dbh;
+
+ my $query = "UPDATE reserves SET found = ?, waitingdate = NOW() WHERE itemnumber = ? AND found IS NULL AND priority = 0";
my $sth_set = $dbh->prepare($query);
$sth_set->execute( $newstatus, $itemnumber );
}
else {
# affect the reserve to Waiting as well.
- $query = "
- UPDATE reserves
- SET priority = 0,
- found = 'W',
- waitingdate=now(),
- itemnumber = ?
- WHERE borrowernumber = ?
- AND biblionumber = ?
- ";
+ $query = "
+ UPDATE reserves
+ SET priority = 0,
+ found = 'W',
+ waitingdate = NOW(),
+ itemnumber = ?
+ WHERE borrowernumber = ?
+ AND biblionumber = ?
+ ";
}
$sth = $dbh->prepare($query);
$sth->execute( $itemnumber, $borrowernumber,$biblionumber);
_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, $suspend_until ) = @_;
+
+ $suspend_until = output_pref( dt_from_string( $suspend_until ), 'iso' ) if ( $suspend_until );
+
+ my $do_until = ( $suspend_until ) ? '?' : 'NULL';
+
+ my $dbh = C4::Context->dbh;
+
+ my $sth = $dbh->prepare(
+ "UPDATE reserves SET suspend = NOT suspend,
+ suspend_until = CASE WHEN suspend = 0 THEN NULL ELSE $do_until END
+ WHERE biblionumber = ?
+ AND borrowernumber = ?
+ ");
+
+ my @params;
+ push( @params, $suspend_until ) if ( $suspend_until );
+ push( @params, $biblionumber );
+ push( @params, $borrowernumber );
+
+ $sth->execute( @params );
+ $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;
+
+ $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);
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);
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);
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 );
my $messagingprefs;
if ( $to_address || $borrower->{'smsalertnumber'} ) {
$messagingprefs = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $borrowernumber, message_name => 'Hold_Filled' } );
-
- return if ( !defined( $messagingprefs->{'letter_code'} ) );
- $letter_code = $messagingprefs->{'letter_code'};
} else {
- $letter_code = 'HOLD_PRINT';
$print_mode = 1;
}
my $admin_email_address = $branch_details->{'branchemail'} || C4::Context->preference('KohaAdminEmailAddress');
- my $letter = C4::Letters::GetPreparedLetter (
+ my %letter_params = (
module => 'reserves',
- letter_code => $letter_code,
branchcode => $reserve->{branchcode},
tables => {
'branches' => $branch_details,
'items', $reserve->{'itemnumber'},
},
substitute => { today => C4::Dates->new()->output() },
- ) or die "Could not find a letter called '$letter_code' in the 'reserves' module";
-
+ );
if ( $print_mode ) {
+ $letter_params{ 'letter_code' } = 'HOLD_PRINT';
+ my $letter = C4::Letters::GetPreparedLetter ( %letter_params ) or die "Could not find a letter called '$letter_params{'letter_code'}' in the 'reserves' module";
+
C4::Letters::EnqueueLetter( {
letter => $letter,
borrowernumber => $borrowernumber,
return;
}
- if ( grep { $_ eq 'email' } @{$messagingprefs->{transports}} ) {
- # aka, 'email' in ->{'transports'}
+ if ( $to_address && defined $messagingprefs->{transports}->{'email'} ) {
+ $letter_params{ 'letter_code' } = $messagingprefs->{transports}->{'email'};
+ my $letter = C4::Letters::GetPreparedLetter ( %letter_params ) or die "Could not find a letter called '$letter_params{'letter_code'}' in the 'reserves' module";
+
C4::Letters::EnqueueLetter(
{ letter => $letter,
borrowernumber => $borrowernumber,
);
}
- if ( grep { $_ eq 'sms' } @{$messagingprefs->{transports}} ) {
+ if ( $borrower->{'smsalertnumber'} && defined $messagingprefs->{transports}->{'sms'} ) {
+ $letter_params{ 'letter_code' } = $messagingprefs->{transports}->{'sms'};
+ my $letter = C4::Letters::GetPreparedLetter ( %letter_params ) or die "Could not find a letter called '$letter_params{'letter_code'}' in the 'reserves' module";
+
C4::Letters::EnqueueLetter(
{ letter => $letter,
borrowernumber => $borrowernumber,
}
}
-
=head2 ReserveSlip
ReserveSlip($branchcode, $borrowernumber, $biblionumber)