X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=C4%2FReserves.pm;h=5ff12e44ec5cec671362cf3988b9366f22e3195b;hb=27a1017e44eb0ef67d8fe028a8e74b1a4c1e48eb;hp=f12c23f00947f790211afef75feb85c38c866b05;hpb=823b807ac9e20706bdd3931962e126affc72cbeb;p=koha_fer diff --git a/C4/Reserves.pm b/C4/Reserves.pm index f12c23f009..5ff12e44ec 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -36,6 +36,9 @@ use C4::Members qw(); 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); @@ -85,7 +88,7 @@ This modules provides somes functions to deal with reservations. BEGIN { # set the version for version checking - $VERSION = 3.01; + $VERSION = 3.07.00.049; require Exporter; @ISA = qw(Exporter); @EXPORT = qw( @@ -98,7 +101,7 @@ BEGIN { &GetReservesToBranch &GetReserveCount &GetReserveFee - &GetReserveInfo + &GetReserveInfo &GetReserveStatus &GetOtherReserves @@ -109,6 +112,7 @@ BEGIN { &ModReserveStatus &ModReserveCancelAll &ModReserveMinusPriority + &MoveReserve &CheckReserves &CanBookBeReserved @@ -116,10 +120,16 @@ BEGIN { &CancelReserve &CancelExpiredReserves + &AutoUnsuspendReserves + &IsAvailableForItemLevelRequest &AlterPriority &ToggleLowestPriority + + &ReserveSlip + &ToggleSuspend + &SuspendAll ); @EXPORT_OK = qw( MergeHolds ); } @@ -193,32 +203,31 @@ sub AddReserve { # Send e-mail to librarian if syspref is active if(C4::Context->preference("emailLibrarianWhenHoldIsPlaced")){ my $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber); - my $biblio = GetBiblioData($biblionumber); - my $letter = C4::Letters::getletter( 'reserves', 'HOLDPLACED'); - my $branchcode = $borrower->{branchcode}; - my $branch_details = C4::Branch::GetBranchDetail($branchcode); - my $admin_email_address =$branch_details->{'branchemail'} || C4::Context->preference('KohaAdminEmailAddress'); - - my %keys = (%$borrower, %$biblio); - foreach my $key (keys %keys) { - my $replacefield = "<<$key>>"; - $letter->{content} =~ s/$replacefield/$keys{$key}/g; - $letter->{title} =~ s/$replacefield/$keys{$key}/g; + my $branch_details = C4::Branch::GetBranchDetail($borrower->{branchcode}); + if ( my $letter = C4::Letters::GetPreparedLetter ( + module => 'reserves', + letter_code => 'HOLDPLACED', + branchcode => $branch, + tables => { + 'branches' => $branch_details, + 'borrowers' => $borrower, + 'biblio' => $biblionumber, + }, + ) ) { + + my $admin_email_address =$branch_details->{'branchemail'} || C4::Context->preference('KohaAdminEmailAddress'); + + C4::Letters::EnqueueLetter( + { letter => $letter, + borrowernumber => $borrowernumber, + message_transport_type => 'email', + from_address => $admin_email_address, + to_address => $admin_email_address, + } + ); } - - C4::Letters::EnqueueLetter( - { letter => $letter, - borrowernumber => $borrowernumber, - message_transport_type => 'email', - from_address => $admin_email_address, - to_address => $admin_email_address, - } - ); - - } - #} ($const eq "o" || $const eq "e") or return; # FIXME: why not have a useful return value? $query = qq/ @@ -262,7 +271,9 @@ sub GetReservesFromBiblionumber { itemnumber, reservenotes, expirationdate, - lowestPriority + lowestPriority, + suspend, + suspend_until FROM reserves WHERE biblionumber = ? "; unless ( $all_dates ) { @@ -383,14 +394,14 @@ sub GetReservesFromBorrowernumber { 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; @@ -523,7 +534,7 @@ sub GetOtherReserves { my ($itemnumber) = @_; my $messages; my $nextreservinfo; - my ( $restype, $checkreserves ) = CheckReserves($itemnumber); + my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber); if ($checkreserves) { my $iteminfo = GetItem($itemnumber); if ( $iteminfo->{'holdingbranch'} ne $checkreserves->{'branchcode'} ) { @@ -724,22 +735,46 @@ sub GetReservesForBranch { return (@transreserv); } +=head2 GetReserveStatus + + $reservestatus = GetReserveStatus($itemnumber, $biblionumber); + +Take an itemnumber or a biblionumber and return the status of the reserve places on it. +If several reserves exist, the reserve with the lower priority is given. + +=cut + sub GetReserveStatus { - my ($itemnumber) = @_; - + my ($itemnumber, $biblionumber) = @_; + my $dbh = C4::Context->dbh; - - my $itemstatus = $dbh->prepare("SELECT found FROM reserves WHERE itemnumber = ?"); - - $itemstatus->execute($itemnumber); - my ($found) = $itemstatus->fetchrow_array; - return $found; + + my ($sth, $found, $priority); + if ( $itemnumber ) { + $sth = $dbh->prepare("SELECT found, priority FROM reserves WHERE itemnumber = ? order by priority LIMIT 1"); + $sth->execute($itemnumber); + ($found, $priority) = $sth->fetchrow_array; + } + + if ( $biblionumber and not defined $found and not defined $priority ) { + $sth = $dbh->prepare("SELECT found, priority FROM reserves WHERE biblionumber = ? order by priority LIMIT 1"); + $sth->execute($biblionumber); + ($found, $priority) = $sth->fetchrow_array; + } + + if(defined $found) { + return 'Waiting' if $found eq 'W' and $priority == 0; + return 'Finished' if $found eq 'F'; + return 'Reserved' if $priority > 0; + } + return ''; + #empty string here will remove need for checking undef, or less log lines } =head2 CheckReserves - ($status, $reserve) = &CheckReserves($itemnumber); - ($status, $reserve) = &CheckReserves(undef, $barcode); + ($status, $reserve, $all_reserves) = &CheckReserves($itemnumber); + ($status, $reserve, $all_reserves) = &CheckReserves(undef, $barcode); Find a book in the reserves. @@ -804,11 +839,11 @@ sub CheckReserves { # note: we get the itemnumber because we might have started w/ just the barcode. Now we know for sure we have it. my ( $biblio, $bibitem, $notforloan_per_itemtype, $notforloan_per_item, $itemnumber ) = $sth->fetchrow_array; - return ( 0, 0 ) unless $itemnumber; # bail if we got nothing. + return ( '' ) unless $itemnumber; # bail if we got nothing. # if item is not for loan it cannot be reserved either..... # execpt where items.notforloan < 0 : This indicates the item is holdable. - return ( 0, 0 ) if ( $notforloan_per_item > 0 ) or $notforloan_per_itemtype; + return ( '' ) if ( $notforloan_per_item > 0 ) or $notforloan_per_itemtype; # Find this item in the reserves my @reserves = _Findgroupreserve( $bibitem, $biblio, $itemnumber ); @@ -822,11 +857,11 @@ sub CheckReserves { my $priority = 10000000; foreach my $res (@reserves) { if ( $res->{'itemnumber'} == $itemnumber && $res->{'priority'} == 0) { - return ( "Waiting", $res ); # Found it + return ( "Waiting", $res, \@reserves ); # Found it } else { # See if this item is more important than what we've got so far if ( $res->{'priority'} && $res->{'priority'} < $priority ) { - my $borrowerinfo=C4::Members::GetMemberDetails($res->{'borrowernumber'}); + my $borrowerinfo=C4::Members::GetMember(borrowernumber => $res->{'borrowernumber'}); my $iteminfo=C4::Items::GetItem($itemnumber); my $branch=C4::Circulation::_GetCircControlBranch($iteminfo,$borrowerinfo); my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$iteminfo->{'itype'}); @@ -843,11 +878,10 @@ sub CheckReserves { # We return the most important (i.e. next) reservation. if ($highest) { $highest->{'itemnumber'} = $item; - return ( "Reserved", $highest ); - } - else { - return ( 0, 0 ); + return ( "Reserved", $highest, \@reserves ); } + + return ( '' ); } =head2 CancelExpiredReserves @@ -860,10 +894,12 @@ Cancels all reserves with an expiration date from before today. 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(); @@ -871,6 +907,42 @@ sub CancelExpiredReserves { 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 @@ -880,8 +952,8 @@ sub CancelExpiredReserves { 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. @@ -1008,7 +1080,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; @@ -1041,14 +1113,24 @@ 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"); + $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); } } @@ -1137,13 +1219,9 @@ sub ModReserveStatus { #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 ); @@ -1196,15 +1274,15 @@ 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 = ? - "; + $query = " + UPDATE reserves + SET priority = 0, + found = 'W', + waitingdate = NOW(), + itemnumber = ? + WHERE borrowernumber = ? + AND biblionumber = ? + "; } $sth = $dbh->prepare($query); $sth->execute( $itemnumber, $borrowernumber,$biblionumber); @@ -1341,7 +1419,7 @@ be the target of an item-level hold request. Note that IsAvailableForItemLevelRequest() does not check if the staff operator is authorized to place a request on the item - in particular, -this routine does not check IndependantBranches +this routine does not check IndependentBranches and canreservefromotherbranches. =cut @@ -1387,7 +1465,7 @@ sub IsAvailableForItemLevelRequest { if (C4::Context->preference('AllowOnShelfHolds')) { return $available_per_item; } else { - return ($available_per_item and ($item->{onloan} or GetReserveStatus($itemnumber) eq "W")); + return ($available_per_item and ($item->{onloan} or GetReserveStatus($itemnumber) eq "Waiting")); } } @@ -1455,6 +1533,98 @@ 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, $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); @@ -1599,6 +1769,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); @@ -1629,6 +1800,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); @@ -1660,6 +1832,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 ); @@ -1686,25 +1859,14 @@ sub _koha_notify_reserve { my $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber); # Try to get the borrower's email address - my $to_address; - my $which_address = C4::Context->preference('AutoEmailPrimaryAddress'); - # If the system preference is set to 'first valid' (value == OFF), look up email address - if ($which_address eq 'OFF') { - $to_address = C4::Members::GetFirstValidEmailAddress( $borrowernumber ); - } else { - $to_address = $borrower->{$which_address}; - } + my $to_address = C4::Members::GetNoticeEmailAddress($borrowernumber); my $letter_code; my $print_mode = 0; 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; } @@ -1720,23 +1882,24 @@ sub _koha_notify_reserve { my $admin_email_address = $branch_details->{'branchemail'} || C4::Context->preference('KohaAdminEmailAddress'); - my $letter = getletter( 'reserves', $letter_code ); - die "Could not find a letter called '$letter_code' in the 'reserves' module" unless( $letter ); - - C4::Letters::parseletter( $letter, 'branches', $reserve->{'branchcode'} ); - C4::Letters::parseletter( $letter, 'borrowers', $borrowernumber ); - C4::Letters::parseletter( $letter, 'biblio', $biblionumber ); - C4::Letters::parseletter( $letter, 'reserves', $borrowernumber, $biblionumber ); + my %letter_params = ( + module => 'reserves', + branchcode => $reserve->{branchcode}, + tables => { + 'branches' => $branch_details, + 'borrowers' => $borrower, + 'biblio' => $biblionumber, + 'reserves' => $reserve, + 'items', $reserve->{'itemnumber'}, + }, + substitute => { today => C4::Dates->new()->output() }, + ); - if ( $reserve->{'itemnumber'} ) { - C4::Letters::parseletter( $letter, 'items', $reserve->{'itemnumber'} ); - } - my $today = C4::Dates->new()->output(); - $letter->{'title'} =~ s/<>/$today/g; - $letter->{'content'} =~ s/<>/$today/g; - $letter->{'content'} =~ s/<<[a-z0-9_]+\.[a-z0-9]+>>//g; #remove any stragglers 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, @@ -1746,8 +1909,10 @@ sub _koha_notify_reserve { 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, @@ -1757,7 +1922,10 @@ sub _koha_notify_reserve { ); } - 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, @@ -1816,6 +1984,56 @@ sub _ShiftPriorityByDateAndPriority { return $new_priority; # so the caller knows what priority they wind up receiving } +=head2 MoveReserve + + MoveReserve( $itemnumber, $borrowernumber, $cancelreserve ) + +Use when checking out an item to handle reserves +If $cancelreserve boolean is set to true, it will remove existing reserve + +=cut + +sub MoveReserve { + my ( $itemnumber, $borrowernumber, $cancelreserve ) = @_; + + my ( $restype, $res, $all_reserves ) = CheckReserves( $itemnumber ); + return unless $res; + + my $biblionumber = $res->{biblionumber}; + my $biblioitemnumber = $res->{biblioitemnumber}; + + if ($res->{borrowernumber} == $borrowernumber) { + ModReserveFill($res); + } + else { + # warn "Reserved"; + # The item is reserved by someone else. + # Find this item in the reserves + + my $borr_res; + foreach (@$all_reserves) { + $_->{'borrowernumber'} == $borrowernumber or next; + $_->{'biblionumber'} == $biblionumber or next; + + $borr_res = $_; + last; + } + + if ( $borr_res ) { + # The item is reserved by the current patron + ModReserveFill($borr_res); + } + + if ( $cancelreserve eq 'revert' ) { ## Revert waiting reserve to priority 1 + RevertWaitingStatus({ itemnumber => $itemnumber }); + } + elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item + CancelReserve(0, $res->{'itemnumber'}, $res->{'borrowernumber'}); + CancelReserve($res->{'biblionumber'}, 0, $res->{'borrowernumber'}); + } + } +} + =head2 MergeHolds MergeHolds($dbh,$to_biblio, $from_biblio); @@ -1860,6 +2078,95 @@ sub MergeHolds { } } +=head2 RevertWaitingStatus + + $success = RevertWaitingStatus({ itemnumber => $itemnumber }); + + Reverts a 'waiting' hold back to a regular hold with a priority of 1. + + Caveat: Any waiting hold fixed with RevertWaitingStatus will be an + item level hold, even if it was only a bibliolevel hold to + begin with. This is because we can no longer know if a hold + was item-level or bib-level after a hold has been set to + waiting status. + +=cut + +sub RevertWaitingStatus { + my ( $params ) = @_; + my $itemnumber = $params->{'itemnumber'}; + + return unless ( $itemnumber ); + + my $dbh = C4::Context->dbh; + + ## Get the waiting reserve we want to revert + my $query = " + SELECT * FROM reserves + WHERE itemnumber = ? + AND found IS NOT NULL + "; + my $sth = $dbh->prepare( $query ); + $sth->execute( $itemnumber ); + my $reserve = $sth->fetchrow_hashref(); + + ## Increment the priority of all other non-waiting + ## reserves for this bib record + $query = " + UPDATE reserves + SET + priority = priority + 1 + WHERE + biblionumber = ? + AND + priority > 0 + "; + $sth = $dbh->prepare( $query ); + $sth->execute( $reserve->{'biblionumber'} ); + + ## Fix up the currently waiting reserve + $query = " + UPDATE reserves + SET + priority = 1, + found = NULL, + waitingdate = NULL + WHERE + reserve_id = ? + "; + $sth = $dbh->prepare( $query ); + return $sth->execute( $reserve->{'reserve_id'} ); +} + +=head2 ReserveSlip + + ReserveSlip($branchcode, $borrowernumber, $biblionumber) + + Returns letter hash ( see C4::Letters::GetPreparedLetter ) or undef + +=cut + +sub ReserveSlip { + my ($branch, $borrowernumber, $biblionumber) = @_; + +# return unless ( C4::Context->boolean_preference('printreserveslips') ); + + my $reserve = GetReserveInfo($borrowernumber,$biblionumber ) + or return; + + return C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => 'RESERVESLIP', + branchcode => $branch, + tables => { + 'reserves' => $reserve, + 'branches' => $reserve->{branchcode}, + 'borrowers' => $reserve->{borrowernumber}, + 'biblio' => $reserve->{biblionumber}, + 'items' => $reserve->{itemnumber}, + }, + ); +} =head1 AUTHOR