X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=C4%2FReserves.pm;h=359bbad97bcd729acc38a8ab4bfb30abece7ccc9;hb=01875b565d7c04b3b00ba1986f824cae7d1fb2a9;hp=464b3f37c536147398d67e8cd51dacd5222b0596;hpb=c9ba8c899d854d4190df783f3f1aec2989d2cb10;p=koha_fer diff --git a/C4/Reserves.pm b/C4/Reserves.pm index 464b3f37c5..359bbad97b 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -2,7 +2,8 @@ package C4::Reserves; # Copyright 2000-2002 Katipo Communications # 2006 SAN Ouest Provence -# 2007 BibLibre Paul POULAIN +# 2007-2010 BibLibre Paul POULAIN +# 2011 Catalyst IT # # This file is part of Koha. # @@ -26,7 +27,6 @@ use C4::Context; use C4::Biblio; use C4::Members; use C4::Items; -use C4::Search; use C4::Circulation; use C4::Accounts; @@ -50,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 @@ -67,27 +68,25 @@ 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 BEGIN { # set the version for version checking $VERSION = 3.01; - require Exporter; + require Exporter; @ISA = qw(Exporter); @EXPORT = qw( &AddReserve @@ -100,7 +99,8 @@ BEGIN { &GetReserveCount &GetReserveFee &GetReserveInfo - + &GetReserveStatus + &GetOtherReserves &ModReserveFill @@ -109,6 +109,7 @@ BEGIN { &ModReserveStatus &ModReserveCancelAll &ModReserveMinusPriority + &MoveReserve &CheckReserves &CanBookBeReserved @@ -121,9 +122,10 @@ BEGIN { &AlterPriority &ToggleLowestPriority ); + @EXPORT_OK = qw( MergeHolds ); } -=item AddReserve +=head2 AddReserve AddReserve($branch,$borrowernumber,$biblionumber,$constraint,$bibitems,$priority,$resdate,$expdate,$notes,$title,$checkitem,$found) @@ -142,7 +144,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 ); - $expdate = format_date_in_iso( $expdate ) if ( $expdate ); + 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 ); @@ -190,7 +196,9 @@ sub AddReserve { my $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber); my $biblio = GetBiblioData($biblionumber); my $letter = C4::Letters::getletter( 'reserves', 'HOLDPLACED'); - my $admin_email_address = C4::Context->preference('KohaAdminEmailAddress'); + 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) { @@ -228,9 +236,9 @@ sub AddReserve { 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>. @@ -308,11 +316,11 @@ sub GetReservesFromBiblionumber { return ( $#results + 1, \@results ); } -=item GetReservesFromItemnumber +=head2 GetReservesFromItemnumber ( $reservedate, $borrowernumber, $branchcode ) = GetReservesFromItemnumber($itemnumber); - TODO :: Description here +TODO :: Description here =cut @@ -333,12 +341,12 @@ sub GetReservesFromItemnumber { return ( $reservedate, $borrowernumber, $branchcode ); } -=item GetReservesFromBorrowernumber +=head2 GetReservesFromBorrowernumber $borrowerreserv = GetReservesFromBorrowernumber($borrowernumber,$tatus); - - TODO :: Descritpion - + +TODO :: Descritpion + =cut sub GetReservesFromBorrowernumber { @@ -367,92 +375,33 @@ 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 IN (?, '*')"; - push @args,$borrower->{categorycode}; - - if($controlbranch eq "ItemHomeLibrary"){ - $rightsquery .= " AND branchcode = '*'"; - }elsif($controlbranch eq "PatronLibrary"){ - $rightsquery .= " AND branchcode IN (?,'*')"; - push @args, $borrower->{branchcode}; + my @items = get_itemnumbers_of($biblionumber); + #get items linked via host records + my @hostitems = get_hostitemnumbers_of($biblionumber); + if (@hostitems){ + push (@items,@hostitems); } - - 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}; - } - - @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; + + foreach my $item (@items){ + return 1 if CanItemBeReserved($borrowernumber, $item); } - + 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 @@ -539,9 +488,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. @@ -563,9 +512,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 @@ -575,7 +524,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'} ) { @@ -613,9 +562,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 @@ -716,9 +665,9 @@ sub GetReserveFee { return $fee; } -=item GetReservesToBranch +=head2 GetReservesToBranch -@transreserv = GetReservesToBranch( $frombranch ); + @transreserv = GetReservesToBranch( $frombranch ); Get reserve list for a given branch @@ -743,9 +692,9 @@ sub GetReservesToBranch { return (@transreserv); } -=item GetReservesForBranch +=head2 GetReservesForBranch -@transreserv = GetReservesForBranch($frombranch); + @transreserv = GetReservesForBranch($frombranch); =cut @@ -776,10 +725,22 @@ 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; +} - ($status, $reserve) = &CheckReserves($itemnumber); - ($status, $reserve) = &CheckReserves(undef, $barcode); +=head2 CheckReserves + + ($status, $reserve, $all_reserves) = &CheckReserves($itemnumber); + ($status, $reserve, $all_reserves) = &CheckReserves(undef, $barcode); Find a book in the reserves. @@ -807,17 +768,32 @@ sub CheckReserves { my ( $item, $barcode ) = @_; my $dbh = C4::Context->dbh; my $sth; - my $select = " - SELECT items.biblionumber, + my $select; + if (C4::Context->preference('item-level_itypes')){ + $select = " + SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan, items.notforloan AS itemnotforloan, items.itemnumber - FROM items - LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber - LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype - "; - + FROM items + LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber + LEFT JOIN itemtypes ON items.itype = itemtypes.itemtype + "; + } + else { + $select = " + SELECT items.biblionumber, + items.biblioitemnumber, + itemtypes.notforloan, + items.notforloan AS itemnotforloan, + items.itemnumber + FROM items + LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber + LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype + "; + } + if ($item) { $sth = $dbh->prepare("$select WHERE itemnumber = ?"); $sth->execute($item); @@ -829,11 +805,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 ); @@ -847,10 +823,16 @@ 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::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'}); + next if ($branchitemrule->{'holdallowed'} == 0); + next if (($branchitemrule->{'holdallowed'} == 1) && ($branch ne $borrowerinfo->{'branchcode'})); $priority = $res->{'priority'}; $highest = $res; } @@ -862,19 +844,18 @@ 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 ( '' ); } -=item CancelExpiredReserves +=head2 CancelExpiredReserves CancelExpiredReserves(); - - Cancels all reserves with an expiration date from before today. - + +Cancels all reserves with an expiration date from before today. + =cut sub CancelExpiredReserves { @@ -892,7 +873,7 @@ sub CancelExpiredReserves { } -=item CancelReserve +=head2 CancelReserve &CancelReserve($biblionumber, $itemnumber, $borrowernumber); @@ -990,17 +971,13 @@ sub CancelReserve { $sth->execute( $biblio, $borr ); # now fix the priority on the others.... - _FixPriority( $priority, $biblio ); + _FixPriority( $biblio, $borr ); } } -=item ModReserve +=head2 ModReserve -=over 4 - -ModReserve($rank, $biblio, $borrower, $branch[, $itemnumber]) - -=back + ModReserve($rank, $biblio, $borrower, $branch[, $itemnumber]) Change a hold request's priority or cancel it. @@ -1022,7 +999,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. @@ -1076,7 +1053,7 @@ sub ModReserve { } } -=item ModReserveFill +=head2 ModReserveFill &ModReserveFill($reserve); @@ -1140,13 +1117,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. @@ -1175,9 +1152,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. @@ -1187,6 +1164,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 { @@ -1210,7 +1188,8 @@ sub ModReserveAffect { $query = " UPDATE reserves SET priority = 0, - itemnumber = ? + itemnumber = ?, + found = 'T' WHERE borrowernumber = ? AND biblionumber = ? "; @@ -1238,11 +1217,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 @@ -1260,9 +1239,9 @@ sub ModReserveCancelAll { return ( $messages, $nextreservinfo ); } -=item ModReserveMinusPriority +=head2 ModReserveMinusPriority -&ModReserveMinusPriority($itemnumber,$borrowernumber,$biblionumber) + &ModReserveMinusPriority($itemnumber,$borrowernumber,$biblionumber) Reduce the values of queuded list @@ -1285,34 +1264,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); @@ -1321,13 +1319,9 @@ sub GetReserveInfo { } -=item IsAvailableForItemLevelRequest +=head2 IsAvailableForItemLevelRequest -=over 4 - -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 @@ -1393,17 +1387,19 @@ 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")); } } -=item AlterPriority -AlterPriority( $where, $borrowernumber, $biblionumber, $reservedate ); +=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 ) = @_; @@ -1432,10 +1428,12 @@ sub AlterPriority { } } -=item ToggleLowestPriority -ToggleLowestPriority( $borrowernumber, $biblionumber ); +=head2 ToggleLowestPriority + + ToggleLowestPriority( $borrowernumber, $biblionumber ); This function sets the lowestPriority field to true if is false, and false if it is true. + =cut sub ToggleLowestPriority { @@ -1457,16 +1455,16 @@ sub ToggleLowestPriority { _FixPriority( $biblionumber, $borrowernumber, '999999' ); } -=item _FixPriority +=head2 _FixPriority -&_FixPriority($biblio,$borrowernumber,$rank,$ignoreSetLowestRank); + &_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 +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 @@ -1478,13 +1476,13 @@ sub _FixPriority { } 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 ); @@ -1501,7 +1499,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); @@ -1558,7 +1556,7 @@ sub _FixPriority { } } -=item _Findgroupreserve +=head2 _Findgroupreserve @results = &_Findgroupreserve($biblioitemnumber, $biblionumber, $itemnumber); @@ -1644,6 +1642,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, @@ -1671,13 +1670,9 @@ sub _Findgroupreserve { return @results; } -=item _koha_notify_reserve - -=over 4 - -_koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ); +=head2 _koha_notify_reserve -=back + _koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ); Sends a notification to the patron that their hold has been filled (through ModReserveAffect, _not_ ModReserveFill) @@ -1688,12 +1683,23 @@ sub _koha_notify_reserve { my ($itemnumber, $borrowernumber, $biblionumber) = @_; my $dbh = C4::Context->dbh; - my $borrower = C4::Members::GetMember( $borrowernumber ); + 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 ( $borrower->{'email'} || $borrower->{'smsalertnumber'} ) { - $messagingprefs = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $borrowernumber, message_name => 'Hold Filled' } ); + 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'}; @@ -1761,25 +1767,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 @@ -1787,39 +1789,128 @@ 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 +} + +=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) { # 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); + +This shifts the holds from C<$from_biblio> to C<$to_biblio> and reorders them by the date they were placed + +=cut + +sub MergeHolds { + my ( $dbh, $to_biblio, $from_biblio ) = @_; + my $sth = $dbh->prepare( + "SELECT count(*) as reservenumber FROM reserves WHERE biblionumber = ?" + ); + $sth->execute($from_biblio); + if ( my $data = $sth->fetchrow_hashref() ) { + + # holds exist on old record, if not we don't need to do anything + $sth = $dbh->prepare( + "UPDATE reserves SET biblionumber = ? WHERE biblionumber = ?"); + $sth->execute( $to_biblio, $from_biblio ); + + # Reorder by date + # don't reorder those already waiting + + $sth = $dbh->prepare( +"SELECT * FROM reserves WHERE biblionumber = ? AND (found <> ? AND found <> ? OR found is NULL) ORDER BY reservedate ASC" + ); + my $upd_sth = $dbh->prepare( +"UPDATE reserves SET priority = ? WHERE biblionumber = ? AND borrowernumber = ? + AND reservedate = ? AND constrainttype = ? AND (itemnumber = ? or itemnumber is NULL) " + ); + $sth->execute( $to_biblio, 'W', 'T' ); + my $priority = 1; + while ( my $reserve = $sth->fetchrow_hashref() ) { + $upd_sth->execute( + $priority, $to_biblio, + $reserve->{'borrowernumber'}, $reserve->{'reservedate'}, + $reserve->{'constrainttype'}, $reserve->{'itemnumber'} + ); + $priority++; + } + } } -=back =head1 AUTHOR -Koha Developement team +Koha Development Team =cut