Bug 24394: Typo when adding a new cash register
[koha-ffzg.git] / C4 / Reserves.pm
index 3c3e158..503771e 100644 (file)
@@ -21,38 +21,35 @@ package C4::Reserves;
 # along with Koha; if not, see <http://www.gnu.org/licenses>.
 
 
-use strict;
-#use warnings; FIXME - Bug 2505
-use C4::Context;
+use Modern::Perl;
+
+use C4::Accounts;
 use C4::Biblio;
-use C4::Members;
-use C4::Items;
 use C4::Circulation;
-use C4::Accounts;
-
-# for _koha_notify_reserve
-use C4::Members::Messaging;
-use C4::Members qw();
+use C4::Context;
+use C4::Items;
 use C4::Letters;
 use C4::Log;
-
+use C4::Members::Messaging;
+use C4::Members;
+use Koha::Account::Lines;
 use Koha::Biblios;
-use Koha::DateUtils;
 use Koha::Calendar;
+use Koha::CirculationRules;
 use Koha::Database;
+use Koha::DateUtils;
 use Koha::Hold;
-use Koha::Old::Hold;
 use Koha::Holds;
-use Koha::Libraries;
 use Koha::IssuingRules;
-use Koha::Items;
 use Koha::ItemTypes;
+use Koha::Items;
+use Koha::Libraries;
+use Koha::Old::Hold;
 use Koha::Patrons;
-use Koha::CirculationRules;
 
-use List::MoreUtils qw( firstidx any );
 use Carp;
 use Data::Dumper;
+use List::MoreUtils qw( firstidx any );
 
 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
 
@@ -175,9 +172,25 @@ sub AddReserve {
     # if we have an item selectionned, and the pickup branch is the same as the holdingbranch
     # of the document, we force the value $priority and $found .
     if ( $checkitem and not C4::Context->preference('ReservesNeedReturns') ) {
-        $priority = 0;
         my $item = Koha::Items->find( $checkitem ); # FIXME Prevent bad calls
-        if ( $item->holdingbranch eq $branch ) {
+
+        if (
+            # If item is already checked out, it cannot be set waiting
+            !$item->onloan
+
+            # The item can't be waiting if it needs a transfer
+            && $item->holdingbranch eq $branch
+
+            # Similarly, if in transit it can't be waiting
+            && !$item->get_transfer
+
+            # If we can't hold damaged items, and it is damaged, it can't be waiting
+            && ( $item->damaged && C4::Context->preference('AllowHoldsOnDamagedItems') || !$item->damaged )
+
+            # Lastly, if this already has holds, we shouldn't make it waiting for the new hold
+            && !$item->current_holds->count )
+        {
+            $priority = 0;
             $found = 'W';
         }
     }
@@ -191,7 +204,7 @@ sub AddReserve {
     my $waitingdate;
 
     # If the reserv had the waiting status, we had the value of the resdate
-    if ( $found eq 'W' ) {
+    if ( $found && $found eq 'W' ) {
         $waitingdate = $resdate;
     }
 
@@ -212,9 +225,10 @@ sub AddReserve {
             waitingdate    => $waitingdate,
             expirationdate => $expdate,
             itemtype       => $itemtype,
+            item_level_hold => $checkitem ? 1 : 0,
         }
     )->store();
-    $hold->set_waiting() if $found eq 'W';
+    $hold->set_waiting() if $found && $found eq 'W';
 
     logaction( 'HOLDS', 'CREATE', $hold->id, Dumper($hold->unblessed) )
         if C4::Context->preference('HoldsLog');
@@ -283,7 +297,7 @@ sub CanBookBeReserved{
         push (@itemnumbers, @hostitems);
     }
 
-    my $canReserve;
+    my $canReserve = { status => '' };
     foreach my $itemnumber (@itemnumbers) {
         $canReserve = CanItemBeReserved( $borrowernumber, $itemnumber, $pickup_branchcode );
         return { status => 'OK' } if $canReserve->{status} eq 'OK';
@@ -300,10 +314,13 @@ sub CanBookBeReserved{
          { status => ageRestricted },   if the Item is age restricted for this borrower.
          { status => damaged },         if the Item is damaged.
          { status => cannotReserveFromOtherBranches }, if syspref 'canreservefromotherbranches' is OK.
+         { status => branchNotInHoldGroup }, if borrower home library is not in hold group, and holds are only allowed from hold groups.
          { status => tooManyReserves, limit => $limit }, if the borrower has exceeded their maximum reserve amount.
          { status => notReservable },   if holds on this item are not allowed
          { status => libraryNotFound },   if given branchcode is not an existing library
          { status => libraryNotPickupLocation },   if given branchcode is not configured to be a pickup location
+         { status => cannotBeTransferred }, if branch transfer limit applies on given item and branchcode
+         { status => pickupNotInHoldGroup }, pickup location is not in hold group, and pickup locations are only allowed from hold groups.
 
 =cut
 
@@ -314,18 +331,18 @@ sub CanItemBeReserved {
     my $ruleitemtype;    # itemtype of the matching issuing rule
     my $allowedreserves  = 0; # Total number of holds allowed across all records
     my $holds_per_record = 1; # Total number of holds allowed for this one given record
-    my $holds_per_day    = 0; # Total number of holds allowed per day for the given patron
+    my $holds_per_day;        # Default to unlimited
 
     # we retrieve borrowers and items informations #
     # item->{itype} will come for biblioitems if necessery
-    my $item       = C4::Items::GetItem($itemnumber);
-    my $biblio     = Koha::Biblios->find( $item->{biblionumber} );
+    my $item       = Koha::Items->find($itemnumber);
+    my $biblio     = $item->biblio;
     my $patron = Koha::Patrons->find( $borrowernumber );
     my $borrower = $patron->unblessed;
 
     # If an item is damaged and we don't allow holds on damaged items, we can stop right here
     return { status =>'damaged' }
-      if ( $item->{damaged}
+      if ( $item->damaged
         && !C4::Context->preference('AllowHoldsOnDamagedItems') );
 
     # Check for the age restriction
@@ -353,7 +370,7 @@ sub CanItemBeReserved {
 
     if ( $controlbranch eq "ItemHomeLibrary" ) {
         $branchfield = "items.homebranch";
-        $branchcode  = $item->{homebranch};
+        $branchcode  = $item->homebranch;
     }
     elsif ( $controlbranch eq "PatronLibrary" ) {
         $branchfield = "borrowers.branchcode";
@@ -361,7 +378,7 @@ sub CanItemBeReserved {
     }
 
     # we retrieve rights
-    if ( my $rights = GetHoldRule( $borrower->{'categorycode'}, $item->{'itype'}, $branchcode ) ) {
+    if ( my $rights = GetHoldRule( $borrower->{'categorycode'}, $item->effective_itemtype, $branchcode ) ) {
         $ruleitemtype     = $rights->{itemtype};
         $allowedreserves  = $rights->{reservesallowed};
         $holds_per_record = $rights->{holds_per_record};
@@ -371,7 +388,6 @@ sub CanItemBeReserved {
         $ruleitemtype = '*';
     }
 
-    $item = Koha::Items->find( $itemnumber );
     my $holds = Koha::Holds->search(
         {
             borrowernumber => $borrowernumber,
@@ -397,7 +413,7 @@ sub CanItemBeReserved {
 
     # we retrieve count
 
-    $querycount .= "AND $branchfield = ?";
+    $querycount .= "AND ( $branchfield = ? OR $branchfield IS NULL )";
 
     # If using item-level itypes, fall back to the record
     # level itemtype if the hold has no associated item
@@ -444,10 +460,10 @@ sub CanItemBeReserved {
         return { status => 'tooManyReserves', limit => $rule->rule_value} if $total_holds_count >= $rule->rule_value;
     }
 
-    my $circ_control_branch =
-      C4::Circulation::_GetCircControlBranch( $item->unblessed(), $borrower );
+    my $reserves_control_branch =
+      GetReservesControlBranch( $item->unblessed(), $borrower );
     my $branchitemrule =
-      C4::Circulation::GetBranchItemRule( $circ_control_branch, $item->itype );
+      C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->itype ); # FIXME Should not be item->effective_itemtype?
 
     if ( $branchitemrule->{holdallowed} == 0 ) {
         return { status => 'notReservable' };
@@ -459,13 +475,19 @@ sub CanItemBeReserved {
         return { status => 'cannotReserveFromOtherBranches' };
     }
 
+    my $item_library = Koha::Libraries->find( {branchcode => $item->homebranch} );
+    if ( $branchitemrule->{holdallowed} == 3) {
+        if($borrower->{branchcode} ne $item->homebranch && !$item_library->validate_hold_sibling( {branchcode => $borrower->{branchcode}} )) {
+            return { status => 'branchNotInHoldGroup' };
+        }
+    }
+
     # If reservecount is ok, we check item branch if IndependentBranches is ON
     # and canreservefromotherbranches is OFF
     if ( C4::Context->preference('IndependentBranches')
         and !C4::Context->preference('canreservefromotherbranches') )
     {
-        my $itembranch = $item->homebranch;
-        if ( $itembranch ne $borrower->{branchcode} ) {
+        if ( $item->homebranch ne $borrower->{branchcode} ) {
             return { status => 'cannotReserveFromOtherBranches' };
         }
     }
@@ -474,12 +496,22 @@ sub CanItemBeReserved {
         my $destination = Koha::Libraries->find({
             branchcode => $pickup_branchcode,
         });
+
         unless ($destination) {
             return { status => 'libraryNotFound' };
         }
         unless ($destination->pickup_location) {
             return { status => 'libraryNotPickupLocation' };
         }
+        unless ($item->can_be_transferred({ to => $destination })) {
+            return { status => 'cannotBeTransferred' };
+        }
+        unless ($branchitemrule->{hold_fulfillment_policy} ne 'holdgroup' || $item_library->validate_hold_sibling( {branchcode => $pickup_branchcode} )) {
+            return { status => 'pickupNotInHoldGroup' };
+        }
+        unless ($branchitemrule->{hold_fulfillment_policy} ne 'patrongroup' || Koha::Libraries->find({branchcode => $borrower->{branchcode}})->validate_hold_sibling({branchcode => $pickup_branchcode})) {
+            return { status => 'pickupNotInHoldGroup' };
+        }
     }
 
     return { status => 'OK' };
@@ -522,8 +554,8 @@ sub GetOtherReserves {
     my $nextreservinfo;
     my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber);
     if ($checkreserves) {
-        my $iteminfo = GetItem($itemnumber);
-        if ( $iteminfo->{'holdingbranch'} ne $checkreserves->{'branchcode'} ) {
+        my $item = Koha::Items->find($itemnumber);
+        if ( $item->holdingbranch ne $checkreserves->{'branchcode'} ) {
             $messages->{'transfert'} = $checkreserves->{'branchcode'};
             #minus priorities of others reservs
             ModReserveMinusPriority(
@@ -534,7 +566,7 @@ sub GetOtherReserves {
             #launch the subroutine dotransfer
             C4::Items::ModItemTransfer(
                 $itemnumber,
-                $iteminfo->{'holdingbranch'},
+                $item->holdingbranch,
                 $checkreserves->{'branchcode'}
               ),
               ;
@@ -566,13 +598,20 @@ sub GetOtherReserves {
 
 sub ChargeReserveFee {
     my ( $borrowernumber, $fee, $title ) = @_;
-    return if !$fee || $fee==0; # the last test is needed to include 0.00
-    my $accquery = qq{
-INSERT INTO accountlines ( borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding ) VALUES (?, ?, NOW(), ?, ?, 'Res', ?)
-    };
-    my $dbh = C4::Context->dbh;
-    my $nextacctno = &getnextacctno( $borrowernumber );
-    $dbh->do( $accquery, undef, ( $borrowernumber, $nextacctno, $fee, "Reserve Charge - $title", $fee ) );
+    return if !$fee || $fee == 0;    # the last test is needed to include 0.00
+    Koha::Account->new( { patron_id => $borrowernumber } )->add_debit(
+        {
+            amount       => $fee,
+            description  => $title,
+            note         => undef,
+            user_id      => C4::Context->userenv ? C4::Context->userenv->{'number'} : undef,
+            library_id   => C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef,
+            interface    => C4::Context->interface,
+            invoice_type => undef,
+            type         => 'RESERVE',
+            item_id      => undef
+        }
+    );
 }
 
 =head2 GetReserveFee
@@ -654,9 +693,9 @@ sub GetReserveStatus {
 
 =head2 CheckReserves
 
-  ($status, $reserve, $all_reserves) = &CheckReserves($itemnumber);
-  ($status, $reserve, $all_reserves) = &CheckReserves(undef, $barcode);
-  ($status, $reserve, $all_reserves) = &CheckReserves($itemnumber,undef,$lookahead);
+  ($status, $matched_reserve, $possible_reserves) = &CheckReserves($itemnumber);
+  ($status, $matched_reserve, $possible_reserves) = &CheckReserves(undef, $barcode);
+  ($status, $matched_reserve, $possible_reserves) = &CheckReserves($itemnumber,undef,$lookahead);
 
 Find a book in the reserves.
 
@@ -727,11 +766,9 @@ 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, $damaged, $item_homebranch, $item_holdingbranch ) = $sth->fetchrow_array;
-
     return if ( $damaged && !C4::Context->preference('AllowHoldsOnDamagedItems') );
 
     return unless $itemnumber; # bail if we got nothing.
-
     # if item is not for loan it cannot be reserved either.....
     # except where items.notforloan < 0 :  This indicates the item is holdable.
     return if  ( $notforloan_per_item > 0 ) or $notforloan_per_itemtype;
@@ -759,15 +796,15 @@ sub CheckReserves {
                 }
             } else {
                 my $patron;
-                my $iteminfo;
+                my $item;
                 my $local_hold_match;
 
                 if ($LocalHoldsPriority) {
                     $patron = Koha::Patrons->find( $res->{borrowernumber} );
-                    $iteminfo = C4::Items::GetItem($itemnumber);
+                    $item = Koha::Items->find($itemnumber);
 
                     my $local_holds_priority_item_branchcode =
-                      $iteminfo->{$LocalHoldsPriorityItemControl};
+                      $item->$LocalHoldsPriorityItemControl;
                     my $local_holds_priority_patron_branchcode =
                       ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
                       ? $res->{branchcode}
@@ -781,14 +818,20 @@ sub CheckReserves {
 
                 # See if this item is more important than what we've got so far
                 if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
-                    $iteminfo ||= C4::Items::GetItem($itemnumber);
-                    next if $res->{itemtype} && $res->{itemtype} ne _get_itype( $iteminfo );
+                    $item ||= Koha::Items->find($itemnumber);
+                    next if $res->{itemtype} && $res->{itemtype} ne $item->effective_itemtype;
                     $patron ||= Koha::Patrons->find( $res->{borrowernumber} );
-                    my $branch = GetReservesControlBranch( $iteminfo, $patron->unblessed );
-                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$iteminfo->{'itype'});
+                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
+                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
                     next if ($branchitemrule->{'holdallowed'} == 0);
                     next if (($branchitemrule->{'holdallowed'} == 1) && ($branch ne $patron->branchcode));
-                    next if ( ($branchitemrule->{hold_fulfillment_policy} ne 'any') && ($res->{branchcode} ne $iteminfo->{ $branchitemrule->{hold_fulfillment_policy} }) );
+                    my $library = Koha::Libraries->find({branchcode=>$item->homebranch});
+                    next if (($branchitemrule->{'holdallowed'} == 3) && (!$library->validate_hold_sibling({branchcode => $patron->branchcode}) ));
+                    my $hold_fulfillment_policy = $branchitemrule->{hold_fulfillment_policy};
+                    next if ( ($hold_fulfillment_policy eq 'holdgroup') && (!$library->validate_hold_sibling({branchcode => $res->{branchcode}})) );
+                    next if ( ($hold_fulfillment_policy eq 'homebranch') && ($res->{branchcode} ne $item->$hold_fulfillment_policy) );
+                    next if ( ($hold_fulfillment_policy eq 'holdingbranch') && ($res->{branchcode} ne $item->$hold_fulfillment_policy) );
+                    next unless $item->can_be_transferred( { to => scalar Koha::Libraries->find( $res->{branchcode} ) } );
                     $priority = $res->{'priority'};
                     $highest  = $res;
                     last if $local_hold_match;
@@ -822,7 +865,7 @@ sub CancelExpiredReserves {
 
     my $dtf = Koha::Database->new->schema->storage->datetime_parser;
     my $params = { expirationdate => { '<', $dtf->format_date($today) } };
-    $params->{found} = undef unless $expireWaiting;
+    $params->{found} = [ { '!=', 'W' }, undef ]  unless $expireWaiting;
 
     # FIXME To move to Koha::Holds->search_expired (?)
     my $holds = Koha::Holds->search( $params );
@@ -853,7 +896,7 @@ sub AutoUnsuspendReserves {
 
     my @holds = Koha::Holds->search( { suspend_until => { '<=' => $today->ymd() } } );
 
-    map { $_->suspend(0)->suspend_until(undef)->store() } @holds;
+    map { $_->resume() } @holds;
 }
 
 =head2 ModReserve
@@ -925,15 +968,21 @@ sub ModReserve {
         logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
             if C4::Context->preference('HoldsLog');
 
-        $hold->set(
-            {
-                priority    => $rank,
-                branchcode  => $branchcode,
-                itemnumber  => $itemnumber,
-                found       => undef,
-                waitingdate => undef
-            }
-        )->store();
+        my $properties = {
+            priority    => $rank,
+            branchcode  => $branchcode,
+            itemnumber  => $itemnumber,
+            found       => undef,
+            waitingdate => undef
+        };
+        if (exists $params->{reservedate}) {
+            $properties->{reservedate} = $params->{reservedate} || undef;
+        }
+        if (exists $params->{expirationdate}) {
+            $properties->{expirationdate} = $params->{expirationdate} || undef;
+        }
+
+        $hold->set($properties)->store();
 
         if ( defined( $suspend_until ) ) {
             if ( $suspend_until ) {
@@ -967,7 +1016,6 @@ sub ModReserveFill {
     my $reserve_id = $res->{'reserve_id'};
 
     my $hold = Koha::Holds->find($reserve_id);
-
     # get the priority on this record....
     my $priority = $hold->priority;
 
@@ -1018,7 +1066,10 @@ sub ModReserveStatus {
     my $sth_set = $dbh->prepare($query);
     $sth_set->execute( $newstatus, $itemnumber );
 
-    if ( C4::Context->preference("ReturnToShelvingCart") && $newstatus ) {
+    my $item = Koha::Items->find($itemnumber);
+    if ( $item->location && $item->location eq 'CART'
+        && ( !$item->permanent_location || $item->permanent_location ne 'CART' )
+        && $newstatus ) {
       CartToShelf( $itemnumber );
     }
 }
@@ -1070,9 +1121,10 @@ sub ModReserveAffect {
       if ( !$transferToDo && !$already_on_shelf );
 
     _FixPriority( { biblionumber => $biblionumber } );
-
-    if ( C4::Context->preference("ReturnToShelvingCart") ) {
-        CartToShelf($itemnumber);
+    my $item = Koha::Items->find($itemnumber);
+    if ( $item->location && $item->location eq 'CART'
+        && ( !$item->permanent_location || $item->permanent_location ne 'CART' ) ) {
+      CartToShelf( $itemnumber );
     }
 
     return;
@@ -1128,7 +1180,7 @@ sub ModReserveMinusPriority {
 
 =head2 IsAvailableForItemLevelRequest
 
-  my $is_available = IsAvailableForItemLevelRequest($item_record,$borrower_record);
+  my $is_available = IsAvailableForItemLevelRequest( $item_record, $borrower_record, $pickup_branchcode );
 
 Checks whether a given item record is available for an
 item-level hold request.  An item is available if
@@ -1151,42 +1203,51 @@ and canreservefromotherbranches.
 =cut
 
 sub IsAvailableForItemLevelRequest {
-    my $item = shift;
-    my $borrower = shift;
+    my ( $item, $patron, $pickup_branchcode ) = @_;
 
     my $dbh = C4::Context->dbh;
     # must check the notforloan setting of the itemtype
     # FIXME - a lot of places in the code do this
     #         or something similar - need to be
     #         consolidated
-    my $patron = Koha::Patrons->find( $borrower->{borrowernumber} );
-    my $item_object = Koha::Items->find( $item->{itemnumber } );
-    my $itemtype = $item_object->effective_itemtype;
-    my $notforloan_per_itemtype
-      = $dbh->selectrow_array("SELECT notforloan FROM itemtypes WHERE itemtype = ?",
-                              undef, $itemtype);
+    my $itemtype = $item->effective_itemtype;
+    my $notforloan_per_itemtype = Koha::ItemTypes->find($itemtype)->notforloan;
 
     return 0 if
         $notforloan_per_itemtype ||
-        $item->{itemlost}        ||
-        $item->{notforloan} > 0  ||
-        $item->{withdrawn}        ||
-        ($item->{damaged} && !C4::Context->preference('AllowHoldsOnDamagedItems'));
+        $item->itemlost        ||
+        $item->notforloan > 0  ||
+        $item->withdrawn        ||
+        ($item->damaged && !C4::Context->preference('AllowHoldsOnDamagedItems'));
 
-    my $on_shelf_holds = Koha::IssuingRules->get_onshelfholds_policy( { item => $item_object, patron => $patron } );
+    my $on_shelf_holds = Koha::IssuingRules->get_onshelfholds_policy( { item => $item, patron => $patron } );
+
+    if ($pickup_branchcode) {
+        my $destination = Koha::Libraries->find($pickup_branchcode);
+        return 0 unless $destination;
+        return 0 unless $destination->pickup_location;
+        return 0 unless $item->can_be_transferred( { to => $destination } );
+        my $reserves_control_branch =
+            GetReservesControlBranch( $item->unblessed(), $patron->unblessed() );
+        my $branchitemrule =
+            C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->itype );
+        my $home_library = Koka::Libraries->find( {branchcode => $item->homebranch} );
+        return 0 unless $branchitemrule->{hold_fulfillment_policy} ne 'holdgroup' || $home_library->validate_hold_sibling( {branchcode => $pickup_branchcode} );
+    }
 
     if ( $on_shelf_holds == 1 ) {
         return 1;
     } elsif ( $on_shelf_holds == 2 ) {
         my @items =
-          Koha::Items->search( { biblionumber => $item->{biblionumber} } );
+          Koha::Items->search( { biblionumber => $item->biblionumber } );
 
         my $any_available = 0;
 
         foreach my $i (@items) {
+            my $reserves_control_branch = GetReservesControlBranch( $i->unblessed(), $patron->unblessed );
+            my $branchitemrule = C4::Circulation::GetBranchItemRule( $reserves_control_branch, $i->itype );
+            my $item_library = Koha::Libraries->find( {branchcode => $i->homebranch} );
 
-            my $circ_control_branch = C4::Circulation::_GetCircControlBranch( $i->unblessed(), $borrower );
-            my $branchitemrule = C4::Circulation::GetBranchItemRule( $circ_control_branch, $i->itype );
 
             $any_available = 1
               unless $i->itemlost
@@ -1197,12 +1258,13 @@ sub IsAvailableForItemLevelRequest {
               || ( $i->damaged
                 && !C4::Context->preference('AllowHoldsOnDamagedItems') )
               || Koha::ItemTypes->find( $i->effective_itemtype() )->notforloan
-              || $branchitemrule->{holdallowed} == 1 && $borrower->{branchcode} ne $i->homebranch;
+              || $branchitemrule->{holdallowed} == 1 && $patron->branchcode ne $i->homebranch
+              || $branchitemrule->{holdallowed} == 3 && !$item_library->validate_hold_sibling( {branchcode => $patron->branchcode} );
         }
 
         return $any_available ? 0 : 1;
     } else { # on_shelf_holds == 0 "If any unavailable" (the description is rather cryptic and could still be improved)
-        return $item->{onloan} || IsItemOnHoldAndFound( $item->{itemnumber} );
+        return $item->onloan || IsItemOnHoldAndFound( $item->itemnumber );
     }
 }
 
@@ -1413,7 +1475,7 @@ sub _FixPriority {
     if ( $rank eq "del" ) { # FIXME will crash if called without $hold
         $hold->cancel;
     }
-    elsif ( $rank eq "W" || $rank eq "0" ) {
+    elsif ( $reserve_id && ( $rank eq "W" || $rank eq "0" ) ) {
 
         # make sure priority for waiting or in-transit items is 0
         my $query = "
@@ -1441,11 +1503,12 @@ sub _FixPriority {
         push( @priority,     $line );
     }
 
+    # FIXME This whole sub must be rewritten, especially to highlight what is done when reserve_id is not given
     # To find the matching index
     my $i;
     my $key = -1;    # to allow for 0 to be a valid result
     for ( $i = 0 ; $i < @priority ; $i++ ) {
-        if ( $reserve_id == $priority[$i]->{'reserve_id'} ) {
+        if ( $reserve_id && $reserve_id == $priority[$i]->{'reserve_id'} ) {
             $key = $i;    # save the index
             last;
         }
@@ -1500,6 +1563,13 @@ C<@results> is an array of references-to-hash whose keys are mostly
 fields from the reserves table of the Koha database, plus
 C<biblioitemnumber>.
 
+This routine with either return:
+1 - Item specific holds from the holds queue
+2 - Title level holds from the holds queue
+3 - All holds for this biblionumber
+
+All return values will respect any borrowernumbers passed as arrayref in $ignore_borrowers
+
 =cut
 
 sub _Findgroupreserve {
@@ -1768,7 +1838,7 @@ sub MoveReserve {
     my ( $itemnumber, $borrowernumber, $cancelreserve ) = @_;
 
     my $lookahead = C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
-    my ( $restype, $res, $all_reserves ) = CheckReserves( $itemnumber, undef, $lookahead );
+    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
     return unless $res;
 
     my $biblionumber     =  $res->{biblionumber};
@@ -1781,18 +1851,16 @@ sub MoveReserve {
         # 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;
-        }
+        my $borr_res  = Koha::Holds->search({
+            borrowernumber => $borrowernumber,
+            biblionumber   => $biblionumber,
+        },{
+            order_by       => 'priority'
+        })->next();
 
         if ( $borr_res ) {
             # The item is reserved by the current patron
-            ModReserveFill($borr_res);
+            ModReserveFill($borr_res->unblessed);
         }
 
         if ( $cancelreserve eq 'revert' ) { ## Revert waiting reserve to priority 1
@@ -1881,6 +1949,8 @@ sub RevertWaitingStatus {
     $sth->execute( $itemnumber );
     my $reserve = $sth->fetchrow_hashref();
 
+    my $hold = Koha::Holds->find( $reserve->{reserve_id} ); # TODO Remove the next raw SQL statements and use this instead
+
     ## Increment the priority of all other non-waiting
     ## reserves for this bib record
     $query = "
@@ -1907,6 +1977,11 @@ sub RevertWaitingStatus {
     ";
     $sth = $dbh->prepare( $query );
     $sth->execute( $reserve->{'reserve_id'} );
+
+    unless ( $hold->item_level_hold ) {
+        $hold->itemnumber(undef)->store;
+    }
+
     _FixPriority( { biblionumber => $reserve->{biblionumber} } );
 }