X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=C4%2FReserves.pm;h=83738408afc2b0dbfb73c63dea021e5a2f49b0cf;hb=22804d6ff6fdc2105644f03d0edca1e4e17d4b72;hp=031ca3235894ed8cb8a6c30b817838d4e710c716;hpb=4747ea7462c04770484386538b1594c1760bc75b;p=koha.git diff --git a/C4/Reserves.pm b/C4/Reserves.pm index 031ca32358..83738408af 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -2,7 +2,7 @@ package C4::Reserves; # Copyright 2000-2002 Katipo Communications # 2006 SAN Ouest Provence -# 2007 BibLibre Paul POULAIN +# 2007-2010 BibLibre Paul POULAIN # # This file is part of Koha. # @@ -15,15 +15,16 @@ package C4::Reserves; # 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 +# 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: someday +#use warnings; FIXME - Bug 2505 use C4::Context; use C4::Biblio; +use C4::Members; use C4::Items; use C4::Search; use C4::Circulation; @@ -31,7 +32,7 @@ use C4::Accounts; # for _koha_notify_reserve use C4::Members::Messaging; -use C4::Members qw( GetMember ); +use C4::Members qw(); use C4::Letters; use C4::Branch qw( GetBranchDetail ); use C4::Dates qw( format_date_in_iso ); @@ -49,14 +50,15 @@ C4::Reserves - Koha functions for dealing with reservation. =head1 DESCRIPTION - this modules provides somes functions to deal with reservations. - +This modules provides somes functions to deal with reservations. + Reserves are stored in reserves table. The following columns contains important values : - priority >0 : then the reserve is at 1st stage, and not yet affected to any item. =0 : then the reserve is being dealed - found : NULL : means the patron requested the 1st available, and we haven't choosen the item - W(aiting) : the reserve has an itemnumber affected, and is on the way + T(ransit) : the reserve is linked to an item but is in transit to the pickup branch + W(aiting) : the reserve is linked to an item, is at the pickup branch, and is waiting on the hold shelf F(inished) : the reserve has been completed, and is done - itemnumber : empty : the reserve is still unaffected to an item filled: the reserve is attached to an item @@ -66,20 +68,18 @@ C4::Reserves - Koha functions for dealing with reservation. a library having it run "transfertodo", and clic on the list if there is no transfer to do, the reserve waiting patron can pick it up P =0, F=W, I=filled - if there is a transfer to do, write in branchtransfer P =0, F=NULL, I=filled + if there is a transfer to do, write in branchtransfer P =0, F=T, I=filled The pickup library recieve the book, it check in P =0, F=W, I=filled The patron borrow the book P =0, F=F, I=filled ==== 2nd use case ==== patron requests a document, a given item, If pickup is holding branch P =0, F=W, I=filled - If transfer needed, write in branchtransfer P =0, F=NULL, I=filled - The pickup library recieve the book, it checks it in P =0, F=W, I=filled + If transfer needed, write in branchtransfer P =0, F=T, I=filled + The pickup library receive the book, it checks it in P =0, F=W, I=filled The patron borrow the book P =0, F=F, I=filled - -=head1 FUNCTIONS -=over 2 +=head1 FUNCTIONS =cut @@ -99,7 +99,8 @@ BEGIN { &GetReserveCount &GetReserveFee &GetReserveInfo - + &GetReserveStatus + &GetOtherReserves &ModReserveFill @@ -113,21 +114,25 @@ BEGIN { &CanBookBeReserved &CanItemBeReserved &CancelReserve + &CancelExpiredReserves &IsAvailableForItemLevelRequest + + &AlterPriority + &ToggleLowestPriority ); } -=item AddReserve +=head2 AddReserve - AddReserve($branch,$borrowernumber,$biblionumber,$constraint,$bibitems,$priority,$notes,$title,$checkitem,$found) + AddReserve($branch,$borrowernumber,$biblionumber,$constraint,$bibitems,$priority,$resdate,$expdate,$notes,$title,$checkitem,$found) =cut sub AddReserve { my ( $branch, $borrowernumber, $biblionumber, - $constraint, $bibitems, $priority, $resdate, $notes, + $constraint, $bibitems, $priority, $resdate, $expdate, $notes, $title, $checkitem, $found ) = @_; my $fee = @@ -137,6 +142,11 @@ sub AddReserve { my $const = lc substr( $constraint, 0, 1 ); $resdate = format_date_in_iso( $resdate ) if ( $resdate ); $resdate = C4::Dates->today( 'iso' ) unless ( $resdate ); + if ($expdate) { + $expdate = format_date_in_iso( $expdate ); + } else { + undef $expdate; # make reserves.expirationdate default to null rather than '0000-00-00' + } if ( C4::Context->preference( 'AllowHoldDateInFuture' ) ) { # Make room in reserves for this before those of a later reserve date $priority = _ShiftPriorityByDateAndPriority( $biblionumber, $resdate, $priority ); @@ -167,18 +177,47 @@ sub AddReserve { my $query = qq/ INSERT INTO reserves (borrowernumber,biblionumber,reservedate,branchcode,constrainttype, - priority,reservenotes,itemnumber,found,waitingdate) + priority,reservenotes,itemnumber,found,waitingdate,expirationdate) VALUES (?,?,?,?,?, - ?,?,?,?,?) + ?,?,?,?,?,?) /; my $sth = $dbh->prepare($query); $sth->execute( $borrowernumber, $biblionumber, $resdate, $branch, $const, $priority, $notes, $checkitem, - $found, $waitingdate + $found, $waitingdate, $expdate ); + # 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; + } + + 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/ @@ -191,12 +230,13 @@ sub AddReserve { foreach (@$bibitems) { $sth->execute($borrowernumber, $biblionumber, $resdate, $_); } + return; # FIXME: why not have a useful return value? } -=item GetReservesFromBiblionumber +=head2 GetReservesFromBiblionumber -($count, $title_reserves) = &GetReserves($biblionumber); + ($count, $title_reserves) = &GetReserves($biblionumber); This function gets the list of reservations for one C<$biblionumber>, returning a count of the reserves and an arrayref pointing to the reserves for C<$biblionumber>. @@ -219,7 +259,9 @@ sub GetReservesFromBiblionumber { constrainttype, found, itemnumber, - reservenotes + reservenotes, + expirationdate, + lowestPriority FROM reserves WHERE biblionumber = ? "; unless ( $all_dates ) { @@ -272,11 +314,11 @@ sub GetReservesFromBiblionumber { return ( $#results + 1, \@results ); } -=item GetReservesFromItemnumber +=head2 GetReservesFromItemnumber ( $reservedate, $borrowernumber, $branchcode ) = GetReservesFromItemnumber($itemnumber); - TODO :: Description here +TODO :: Description here =cut @@ -297,12 +339,12 @@ sub GetReservesFromItemnumber { return ( $reservedate, $borrowernumber, $branchcode ); } -=item GetReservesFromBorrowernumber +=head2 GetReservesFromBorrowernumber $borrowerreserv = GetReservesFromBorrowernumber($borrowernumber,$tatus); - - TODO :: Descritpion - + +TODO :: Descritpion + =cut sub GetReservesFromBorrowernumber { @@ -331,94 +373,27 @@ sub GetReservesFromBorrowernumber { return @$data; } #------------------------------------------------------------------------------------- -=item CanBookBeReserved +=head2 CanBookBeReserved -$error = &CanBookBeReserved($borrowernumber, $biblionumber) + $error = &CanBookBeReserved($borrowernumber, $biblionumber) =cut sub CanBookBeReserved{ my ($borrowernumber, $biblionumber) = @_; - my $dbh = C4::Context->dbh; - my $biblio = GetBiblioData($biblionumber); - my $borrower = C4::Members::GetMember(borrowernumber=>$borrowernumber); - my $controlbranch = C4::Context->preference('ReservesControlBranch'); - my $itype = C4::Context->preference('item-level_itypes'); - my $reservesrights= 0; - my $reservescount = 0; - - # we retrieve the user rights - my @args; - my $rightsquery = "SELECT categorycode, itemtype, branchcode, reservesallowed - FROM issuingrules - WHERE categorycode = ?"; - push @args,$borrower->{categorycode}; - - if($controlbranch eq "ItemHomeLibrary"){ - $rightsquery .= " AND branchcode = '*'"; - }elsif($controlbranch eq "PatronLibrary"){ - $rightsquery .= " AND branchcode IN (?,'*')"; - push @args, $borrower->{branchcode}; - } - - if(not $itype){ - $rightsquery .= " AND itemtype IN (?,'*')"; - push @args, $biblio->{itemtype}; - }else{ - $rightsquery .= " AND itemtype = '*'"; - } - - $rightsquery .= " ORDER BY categorycode DESC, itemtype DESC, branchcode DESC"; - - my $sthrights = $dbh->prepare($rightsquery); - $sthrights->execute(@args); - - if(my $row = $sthrights->fetchrow_hashref()){ - $reservesrights = $row->{reservesallowed}; + my @items = GetItemsInfo($biblionumber); + foreach my $item (@items){ + return 1 if CanItemBeReserved($borrowernumber, $item->{itemnumber}); } - - @args = (); - # we count how many reserves the borrower have - my $countquery = "SELECT count(*) as count - FROM reserves - LEFT JOIN items USING (itemnumber) - LEFT JOIN biblioitems ON (reserves.biblionumber=biblioitems.biblionumber) - LEFT JOIN borrowers USING (borrowernumber) - WHERE borrowernumber = ? - "; - push @args, $borrowernumber; - - if(not $itype){ - $countquery .= "AND itemtype = ?"; - push @args, $biblio->{itemtype}; - } - - if($controlbranch eq "PatronLibrary"){ - $countquery .= " AND borrowers.branchcode = ? "; - push @args, $borrower->{branchcode}; - } - - my $sthcount = $dbh->prepare($countquery); - $sthcount->execute(@args); - - if(my $row = $sthcount->fetchrow_hashref()){ - $reservescount = $row->{count}; - } - - if($reservescount < $reservesrights){ - return 1; - }else{ - return 0; - } - + return 0; } -=item CanItemBeReserved +=head2 CanItemBeReserved -$error = &CanItemBeReserved($borrowernumber, $itemnumber) + $error = &CanItemBeReserved($borrowernumber, $itemnumber) -this function return 1 if an item can be issued by this borrower. +This function return 1 if an item can be issued by this borrower. =cut @@ -505,9 +480,9 @@ sub CanItemBeReserved{ } } #-------------------------------------------------------------------------------- -=item GetReserveCount +=head2 GetReserveCount -$number = &GetReserveCount($borrowernumber); + $number = &GetReserveCount($borrowernumber); this function returns the number of reservation for a borrower given on input arg. @@ -529,9 +504,9 @@ sub GetReserveCount { return $row->{counter}; } -=item GetOtherReserves +=head2 GetOtherReserves -($messages,$nextreservinfo)=$GetOtherReserves(itemnumber); + ($messages,$nextreservinfo)=$GetOtherReserves(itemnumber); Check queued list of this document and check if this document must be transfered @@ -579,9 +554,9 @@ sub GetOtherReserves { return ( $messages, $nextreservinfo ); } -=item GetReserveFee +=head2 GetReserveFee -$fee = GetReserveFee($borrowernumber,$biblionumber,$constraint,$biblionumber); + $fee = GetReserveFee($borrowernumber,$biblionumber,$constraint,$biblionumber); Calculate the fee for a reserve @@ -682,9 +657,9 @@ sub GetReserveFee { return $fee; } -=item GetReservesToBranch +=head2 GetReservesToBranch -@transreserv = GetReservesToBranch( $frombranch ); + @transreserv = GetReservesToBranch( $frombranch ); Get reserve list for a given branch @@ -709,9 +684,9 @@ sub GetReservesToBranch { return (@transreserv); } -=item GetReservesForBranch +=head2 GetReservesForBranch -@transreserv = GetReservesForBranch($frombranch); + @transreserv = GetReservesForBranch($frombranch); =cut @@ -742,7 +717,19 @@ sub GetReservesForBranch { return (@transreserv); } -=item CheckReserves +sub GetReserveStatus { + my ($itemnumber) = @_; + + 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; +} + +=head2 CheckReserves ($status, $reserve) = &CheckReserves($itemnumber); ($status, $reserve) = &CheckReserves(undef, $barcode); @@ -817,6 +804,12 @@ sub CheckReserves { } 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 $iteminfo=C4::Items::GetItem($itemnumber); + my $branch=C4::Circulation::_GetCircControlBranch($iteminfo,$borrowerinfo); + my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$iteminfo->{'itype'}); + next if ($branchitemrule->{'holdallowed'} == 0); + next if (($branchitemrule->{'holdallowed'} == 1) && ($branch ne $borrowerinfo->{'branchcode'})); $priority = $res->{'priority'}; $highest = $res; } @@ -835,7 +828,30 @@ sub CheckReserves { } } -=item CancelReserve +=head2 CancelExpiredReserves + + CancelExpiredReserves(); + +Cancels all reserves with an expiration date from before today. + +=cut + +sub CancelExpiredReserves { + + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare( " + SELECT * FROM reserves WHERE DATE(expirationdate) < DATE( CURDATE() ) + AND expirationdate IS NOT NULL + " ); + $sth->execute(); + + while ( my $res = $sth->fetchrow_hashref() ) { + CancelReserve( $res->{'biblionumber'}, '', $res->{'borrowernumber'} ); + } + +} + +=head2 CancelReserve &CancelReserve($biblionumber, $itemnumber, $borrowernumber); @@ -933,17 +949,13 @@ sub CancelReserve { $sth->execute( $biblio, $borr ); # now fix the priority on the others.... - _FixPriority( $priority, $biblio ); + _FixPriority( $biblio, $borr ); } } -=item ModReserve - -=over 4 +=head2 ModReserve -ModReserve($rank, $biblio, $borrower, $branch[, $itemnumber]) - -=back + ModReserve($rank, $biblio, $borrower, $branch[, $itemnumber]) Change a hold request's priority or cancel it. @@ -965,7 +977,7 @@ C<$rank> is a non-zero integer; if supplied, the itemnumber of the hold request is set accordingly; if omitted, the itemnumber is cleared. -FIXME: Note that the forgoing can have the effect of causing +B Note that the forgoing can have the effect of causing item-level hold requests to turn into title-level requests. This will be fixed once reserves has separate columns for requested itemnumber and supplying itemnumber. @@ -1019,7 +1031,7 @@ sub ModReserve { } } -=item ModReserveFill +=head2 ModReserveFill &ModReserveFill($reserve); @@ -1083,13 +1095,13 @@ sub ModReserveFill { # now fix the priority on the others (if the priority wasn't # already sorted!).... unless ( $priority == 0 ) { - _FixPriority( $priority, $biblionumber ); + _FixPriority( $biblionumber, $borrowernumber ); } } -=item ModReserveStatus +=head2 ModReserveStatus -&ModReserveStatus($itemnumber, $newstatus); + &ModReserveStatus($itemnumber, $newstatus); Update the reserve status for the active (priority=0) reserve. @@ -1118,9 +1130,9 @@ sub ModReserveStatus { } } -=item ModReserveAffect +=head2 ModReserveAffect -&ModReserveAffect($itemnumber,$borrowernumber,$diffBranchSend); + &ModReserveAffect($itemnumber,$borrowernumber,$diffBranchSend); This function affect an item and a status for a given reserve The itemnumber parameter is used to find the biblionumber. @@ -1130,6 +1142,7 @@ to the correct reserve. if $transferToDo is not set, then the status is set to "Waiting" as well. otherwise, a transfer is on the way, and the end of the transfer will take care of the waiting status + =cut sub ModReserveAffect { @@ -1153,7 +1166,8 @@ sub ModReserveAffect { $query = " UPDATE reserves SET priority = 0, - itemnumber = ? + itemnumber = ?, + found = 'T' WHERE borrowernumber = ? AND biblionumber = ? "; @@ -1181,11 +1195,11 @@ sub ModReserveAffect { return; } -=item ModReserveCancelAll +=head2 ModReserveCancelAll -($messages,$nextreservinfo) = &ModReserveCancelAll($itemnumber,$borrowernumber); + ($messages,$nextreservinfo) = &ModReserveCancelAll($itemnumber,$borrowernumber); - function to cancel reserv,check other reserves, and transfer document if it's necessary +function to cancel reserv,check other reserves, and transfer document if it's necessary =cut @@ -1203,9 +1217,9 @@ sub ModReserveCancelAll { return ( $messages, $nextreservinfo ); } -=item ModReserveMinusPriority +=head2 ModReserveMinusPriority -&ModReserveMinusPriority($itemnumber,$borrowernumber,$biblionumber) + &ModReserveMinusPriority($itemnumber,$borrowernumber,$biblionumber) Reduce the values of queuded list @@ -1228,34 +1242,53 @@ sub ModReserveMinusPriority { _FixPriority($biblionumber, $borrowernumber, '0'); } -=item GetReserveInfo +=head2 GetReserveInfo -&GetReserveInfo($borrowernumber,$biblionumber); + &GetReserveInfo($borrowernumber,$biblionumber); + +Get item and borrower details for a current hold. +Current implementation this query should have a single result. - Get item and borrower details for a current hold. - Current implementation this query should have a single result. =cut sub GetReserveInfo { my ( $borrowernumber, $biblionumber ) = @_; my $dbh = C4::Context->dbh; - my $strsth="SELECT reservedate, reservenotes, reserves.borrowernumber, - reserves.biblionumber, reserves.branchcode, - notificationdate, reminderdate, priority, found, - firstname, surname, phone, - email, address, address2, - cardnumber, city, zipcode, - biblio.title, biblio.author, - items.holdingbranch, items.itemcallnumber, items.itemnumber, - barcode, notes - FROM reserves left join items - ON items.itemnumber=reserves.itemnumber , - borrowers, biblio + my $strsth="SELECT + reservedate, + reservenotes, + reserves.borrowernumber, + reserves.biblionumber, + reserves.branchcode, + reserves.waitingdate, + notificationdate, + reminderdate, + priority, + found, + firstname, + surname, + phone, + email, + address, + address2, + cardnumber, + city, + zipcode, + biblio.title, + biblio.author, + items.holdingbranch, + items.itemcallnumber, + items.itemnumber, + items.location, + barcode, + notes + FROM reserves + LEFT JOIN items USING(itemnumber) + LEFT JOIN borrowers USING(borrowernumber) + LEFT JOIN biblio ON (reserves.biblionumber=biblio.biblionumber) WHERE - reserves.borrowernumber=? && - reserves.biblionumber=? && - reserves.borrowernumber=borrowers.borrowernumber && - reserves.biblionumber=biblio.biblionumber "; + reserves.borrowernumber=? + AND reserves.biblionumber=?"; my $sth = $dbh->prepare($strsth); $sth->execute($borrowernumber,$biblionumber); @@ -1264,13 +1297,9 @@ sub GetReserveInfo { } -=item IsAvailableForItemLevelRequest - -=over 4 +=head2 IsAvailableForItemLevelRequest -my $is_available = IsAvailableForItemLevelRequest($itemnumber); - -=back + my $is_available = IsAvailableForItemLevelRequest($itemnumber); Checks whether a given item record is available for an item-level hold request. An item is available if @@ -1336,38 +1365,102 @@ sub IsAvailableForItemLevelRequest { if (C4::Context->preference('AllowOnShelfHolds')) { return $available_per_item; } else { - return ($available_per_item and $item->{onloan}); + return ($available_per_item and ($item->{onloan} or GetReserveStatus($itemnumber) eq "W")); + } +} + +=head2 AlterPriority + + AlterPriority( $where, $borrowernumber, $biblionumber, $reservedate ); + +This function changes a reserve's priority up, down, to the top, or to the bottom. +Input: $where is 'up', 'down', 'top' or 'bottom'. Biblionumber, Date reserve was placed + +=cut + +sub AlterPriority { + my ( $where, $borrowernumber, $biblionumber ) = @_; + + my $dbh = C4::Context->dbh; + + ## Find this reserve + my $sth = $dbh->prepare('SELECT * FROM reserves WHERE biblionumber = ? AND borrowernumber = ? AND cancellationdate IS NULL'); + $sth->execute( $biblionumber, $borrowernumber ); + my $reserve = $sth->fetchrow_hashref(); + $sth->finish(); + + if ( $where eq 'up' || $where eq 'down' ) { + + my $priority = $reserve->{'priority'}; + $priority = $where eq 'up' ? $priority - 1 : $priority + 1; + _FixPriority( $biblionumber, $borrowernumber, $priority ) + + } elsif ( $where eq 'top' ) { + + _FixPriority( $biblionumber, $borrowernumber, '1' ) + + } elsif ( $where eq 'bottom' ) { + + _FixPriority( $biblionumber, $borrowernumber, '999999' ) + } } -=item _FixPriority +=head2 ToggleLowestPriority + + ToggleLowestPriority( $borrowernumber, $biblionumber ); + +This function sets the lowestPriority field to true if is false, and false if it is true. -&_FixPriority($biblio,$borrowernumber,$rank); +=cut + +sub ToggleLowestPriority { + my ( $borrowernumber, $biblionumber ) = @_; - Only used internally (so don't export it) - Changed how this functions works # - Now just gets an array of reserves in the rank order and updates them with - the array index (+1 as array starts from 0) - and if $rank is supplied will splice item from the array and splice it back in again - in new priority rank + my $dbh = C4::Context->dbh; + + my $sth = $dbh->prepare( + "UPDATE reserves SET lowestPriority = NOT lowestPriority + WHERE biblionumber = ? + AND borrowernumber = ?" + ); + $sth->execute( + $biblionumber, + $borrowernumber, + ); + $sth->finish; + + _FixPriority( $biblionumber, $borrowernumber, '999999' ); +} + +=head2 _FixPriority + + &_FixPriority($biblio,$borrowernumber,$rank,$ignoreSetLowestRank); + +Only used internally (so don't export it) +Changed how this functions works # +Now just gets an array of reserves in the rank order and updates them with +the array index (+1 as array starts from 0) +and if $rank is supplied will splice item from the array and splice it back in again +in new priority rank =cut sub _FixPriority { - my ( $biblio, $borrowernumber, $rank ) = @_; + my ( $biblio, $borrowernumber, $rank, $ignoreSetLowestRank ) = @_; my $dbh = C4::Context->dbh; if ( $rank eq "del" ) { CancelReserve( $biblio, undef, $borrowernumber ); } if ( $rank eq "W" || $rank eq "0" ) { - # make sure priority for waiting items is 0 + # make sure priority for waiting or in-transit items is 0 my $query = qq/ UPDATE reserves SET priority = 0 WHERE biblionumber = ? AND borrowernumber = ? - AND found ='W' + AND found IN ('W', 'T') /; my $sth = $dbh->prepare($query); $sth->execute( $biblio, $borrowernumber ); @@ -1384,7 +1477,7 @@ sub _FixPriority { SELECT borrowernumber, reservedate, constrainttype FROM reserves WHERE biblionumber = ? - AND ((found <> 'W') or found is NULL) + AND ((found <> 'W' AND found <> 'T') or found is NULL) ORDER BY priority ASC /; my $sth = $dbh->prepare($query); @@ -1430,9 +1523,18 @@ sub _FixPriority { ); $sth->finish; } + + $sth = $dbh->prepare( "SELECT borrowernumber FROM reserves WHERE lowestPriority = 1 ORDER BY priority" ); + $sth->execute(); + + unless ( $ignoreSetLowestRank ) { + while ( my $res = $sth->fetchrow_hashref() ) { + _FixPriority( $biblio, $res->{'borrowernumber'}, '999999', 1 ); + } + } } -=item _Findgroupreserve +=head2 _Findgroupreserve @results = &_Findgroupreserve($biblioitemnumber, $biblionumber, $itemnumber); @@ -1518,6 +1620,7 @@ sub _Findgroupreserve { SELECT reserves.biblionumber AS biblionumber, reserves.borrowernumber AS borrowernumber, reserves.reservedate AS reservedate, + reserves.waitingdate AS waitingdate, reserves.branchcode AS branchcode, reserves.cancellationdate AS cancellationdate, reserves.found AS found, @@ -1545,13 +1648,9 @@ sub _Findgroupreserve { return @results; } -=item _koha_notify_reserve - -=over 4 +=head2 _koha_notify_reserve -_koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ); - -=back + _koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ); Sends a notification to the patron that their hold has been filled (through ModReserveAffect, _not_ ModReserveFill) @@ -1562,9 +1661,30 @@ sub _koha_notify_reserve { my ($itemnumber, $borrowernumber, $biblionumber) = @_; my $dbh = C4::Context->dbh; - my $messagingprefs = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $borrowernumber, message_name => 'Hold Filled' } ); - - return if ( !defined( $messagingprefs->{'letter_code'} ) ); + 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 $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; + } my $sth = $dbh->prepare(" SELECT * @@ -1578,19 +1698,33 @@ sub _koha_notify_reserve { my $admin_email_address = $branch_details->{'branchemail'} || C4::Context->preference('KohaAdminEmailAddress'); - my $letter = getletter( 'reserves', $messagingprefs->{'letter_code'} ); + 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', $reserve->{'borrowernumber'} ); - C4::Letters::parseletter( $letter, 'biblio', $reserve->{'biblionumber'} ); - C4::Letters::parseletter( $letter, 'reserves', $reserve->{'borrowernumber'}, $reserve->{'biblionumber'} ); + C4::Letters::parseletter( $letter, 'borrowers', $borrowernumber ); + C4::Letters::parseletter( $letter, 'biblio', $biblionumber ); + C4::Letters::parseletter( $letter, 'reserves', $borrowernumber, $biblionumber ); 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 ( -1 != firstidx { $_ eq 'email' } @{$messagingprefs->{transports}} ) { + if ( $print_mode ) { + C4::Letters::EnqueueLetter( { + letter => $letter, + borrowernumber => $borrowernumber, + message_transport_type => 'print', + } ); + + return; + } + + if ( grep { $_ eq 'email' } @{$messagingprefs->{transports}} ) { # aka, 'email' in ->{'transports'} C4::Letters::EnqueueLetter( { letter => $letter, @@ -1601,7 +1735,7 @@ sub _koha_notify_reserve { ); } - if ( -1 != firstidx { $_ eq 'sms' } @{$messagingprefs->{transports}} ) { + if ( grep { $_ eq 'sms' } @{$messagingprefs->{transports}} ) { C4::Letters::EnqueueLetter( { letter => $letter, borrowernumber => $borrowernumber, @@ -1611,25 +1745,21 @@ sub _koha_notify_reserve { } } -=item _ShiftPriorityByDateAndPriority - -=over 4 +=head2 _ShiftPriorityByDateAndPriority -$new_priority = _ShiftPriorityByDateAndPriority( $biblionumber, $reservedate, $priority ); - -=back + $new_priority = _ShiftPriorityByDateAndPriority( $biblionumber, $reservedate, $priority ); This increments the priority of all reserves after the one - with either the lowest date after C<$reservedate> - or the lowest priority after C<$priority>. +with either the lowest date after C<$reservedate> +or the lowest priority after C<$priority>. It effectively makes room for a new reserve to be inserted with a certain - priority, which is returned. +priority, which is returned. This is most useful when the reservedate can be set by the user. It allows - the new reserve to be placed before other reserves that have a later - reservedate. Since priority also is set by the form in reserves/request.pl - the sub accounts for that too. +the new reserve to be placed before other reserves that have a later +reservedate. Since priority also is set by the form in reserves/request.pl +the sub accounts for that too. =cut @@ -1637,39 +1767,36 @@ sub _ShiftPriorityByDateAndPriority { my ( $biblio, $resdate, $new_priority ) = @_; my $dbh = C4::Context->dbh; - my $query = "SELECT priority FROM reserves WHERE biblionumber = ? AND ( reservedate > ? OR priority > ? ) ORDER BY priority ASC"; + my $query = "SELECT priority FROM reserves WHERE biblionumber = ? AND ( reservedate > ? OR priority > ? ) ORDER BY priority ASC LIMIT 1"; my $sth = $dbh->prepare( $query ); $sth->execute( $biblio, $resdate, $new_priority ); - my ( $min_priority ) = $sth->fetchrow; - $sth->finish; # $sth might have more data. + my $min_priority = $sth->fetchrow; + # if no such matches are found, $new_priority remains as original value $new_priority = $min_priority if ( $min_priority ); - my $updated_priority = $new_priority + 1; - $query = " - UPDATE reserves - SET priority = ? - WHERE biblionumber = ? - AND borrowernumber = ? - AND reservedate = ? - AND found IS NULL"; + # Shift the priority up by one; works in conjunction with the next SQL statement + $query = "UPDATE reserves + SET priority = priority+1 + WHERE biblionumber = ? + AND borrowernumber = ? + AND reservedate = ? + AND found IS NULL"; my $sth_update = $dbh->prepare( $query ); - $query = "SELECT * FROM reserves WHERE priority >= ?"; + # Select all reserves for the biblio with priority greater than $new_priority, and order greatest to least + $query = "SELECT borrowernumber, reservedate FROM reserves WHERE priority >= ? AND biblionumber = ? ORDER BY priority DESC"; $sth = $dbh->prepare( $query ); - $sth->execute( $new_priority ); + $sth->execute( $new_priority, $biblio ); while ( my $row = $sth->fetchrow_hashref ) { - $sth_update->execute( $updated_priority, $biblio, $row->{borrowernumber}, $row->{reservedate} ); - $updated_priority++; + $sth_update->execute( $biblio, $row->{borrowernumber}, $row->{reservedate} ); } - return $new_priority; # so the caller knows what priority they end up at + return $new_priority; # so the caller knows what priority they wind up receiving } -=back - =head1 AUTHOR -Koha Developement team +Koha Development Team =cut