+ _FixPriority($biblionumber, $borrowernumber, '0');
+}
+
+=item GetReserveInfo
+
+&GetReserveInfo($borrowernumber,$biblionumber);
+
+ 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,
+ 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=?
+ AND reserves.biblionumber=?";
+ my $sth = $dbh->prepare($strsth);
+ $sth->execute($borrowernumber,$biblionumber);
+
+ my $data = $sth->fetchrow_hashref;
+ return $data;
+
+}
+
+=item IsAvailableForItemLevelRequest
+
+=over 4
+
+my $is_available = IsAvailableForItemLevelRequest($itemnumber);
+
+=back
+
+Checks whether a given item record is available for an
+item-level hold request. An item is available if
+
+* it is not lost AND
+* it is not damaged AND
+* it is not withdrawn AND
+* does not have a not for loan value > 0
+
+Whether or not the item is currently on loan is
+also checked - if the AllowOnShelfHolds system preference
+is ON, an item can be requested even if it is currently
+on loan to somebody else. If the system preference
+is OFF, an item that is currently checked out cannot
+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
+and canreservefromotherbranches.
+
+=cut
+
+sub IsAvailableForItemLevelRequest {
+ my $itemnumber = shift;
+
+ my $item = GetItem($itemnumber);
+
+ # 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 $dbh = C4::Context->dbh;
+ my $notforloan_query;
+ if (C4::Context->preference('item-level_itypes')) {
+ $notforloan_query = "SELECT itemtypes.notforloan
+ FROM items
+ JOIN itemtypes ON (itemtypes.itemtype = items.itype)
+ WHERE itemnumber = ?";
+ } else {
+ $notforloan_query = "SELECT itemtypes.notforloan
+ FROM items
+ JOIN biblioitems USING (biblioitemnumber)
+ JOIN itemtypes USING (itemtype)
+ WHERE itemnumber = ?";
+ }
+ my $sth = $dbh->prepare($notforloan_query);
+ $sth->execute($itemnumber);
+ my $notforloan_per_itemtype = 0;
+ if (my ($notforloan) = $sth->fetchrow_array) {
+ $notforloan_per_itemtype = 1 if $notforloan;
+ }
+
+ my $available_per_item = 1;
+ $available_per_item = 0 if $item->{itemlost} or
+ ( $item->{notforloan} > 0 ) or
+ ($item->{damaged} and not C4::Context->preference('AllowHoldsOnDamagedItems')) or
+ $item->{wthdrawn} or
+ $notforloan_per_itemtype;
+
+
+ if (C4::Context->preference('AllowOnShelfHolds')) {
+ return $available_per_item;
+ } else {
+ return ($available_per_item and ($item->{onloan} or GetReserveStatus($itemnumber) eq "W"));
+ }
+}
+
+=item 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 ToggleLowestPriority
+ToggleLowestPriority( $borrowernumber, $biblionumber );
+
+This function sets the lowestPriority field to true if is false, and false if it is true.
+=cut
+
+sub ToggleLowestPriority {
+ my ( $borrowernumber, $biblionumber ) = @_;
+
+ 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' );