use C4::Members qw( GetMember );
use C4::Letters;
use C4::Branch qw( GetBranchDetail );
+use C4::Dates qw( format_date_in_iso );
use List::MoreUtils qw( firstidx );
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
sub AddReserve {
my (
$branch, $borrowernumber, $biblionumber,
- $constraint, $bibitems, $priority, $notes,
+ $constraint, $bibitems, $priority, $resdate, $notes,
$title, $checkitem, $found
) = @_;
my $fee =
$bibitems );
my $dbh = C4::Context->dbh;
my $const = lc substr( $constraint, 0, 1 );
- my @datearr = localtime(time);
- my $resdate =
- ( 1900 + $datearr[5] ) . "-" . ( $datearr[4] + 1 ) . "-" . $datearr[3];
+ $resdate = format_date_in_iso( $resdate ) if ( $resdate );
+ $resdate = C4::Dates->today( 'iso' ) unless ( $resdate );
+ if ( C4::Context->preference( 'AllowHoldDateInFuture' ) ) {
+ # Make room in reserves for this before those of a later reserve date
+ $priority = _ShiftPriorityByDateAndPriority( $biblionumber, $resdate, $priority );
+ }
my $waitingdate;
# If the reserv had the waiting status, we had the value of the resdate
sub GetReservesFromBiblionumber {
my ($biblionumber) = shift or return (0, []);
+ my ($all_dates) = shift;
my $dbh = C4::Context->dbh;
# Find the desired items in the reserves
itemnumber,
reservenotes
FROM reserves
- WHERE biblionumber = ?
- ORDER BY priority";
+ WHERE biblionumber = ? ";
+ unless ( $all_dates ) {
+ $query .= "AND reservedate <= CURRENT_DATE()";
+ }
+ $query .= "ORDER BY priority";
my $sth = $dbh->prepare($query);
$sth->execute($biblionumber);
my @results;
=cut
sub GetReservesFromItemnumber {
- my ( $itemnumber ) = @_;
+ my ( $itemnumber, $all_dates ) = @_;
my $dbh = C4::Context->dbh;
my $query = "
SELECT reservedate,borrowernumber,branchcode
FROM reserves
WHERE itemnumber=?
";
+ unless ( $all_dates ) {
+ $query .= " AND reservedate <= CURRENT_DATE()";
+ }
my $sth_res = $dbh->prepare($query);
$sth_res->execute($itemnumber);
my ( $reservedate, $borrowernumber,$branchcode ) = $sth_res->fetchrow_array;
return @$data;
}
#-------------------------------------------------------------------------------------
+=item CanBookBeReserved
+
+$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};
+ }
+
+ @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;
+ }
+
+}
+
+=item CanItemBeReserved
+
+$error = &CanItemBeReserved($borrowernumber, $itemnumber)
+
+this function return 1 if an item can be issued by this borrower.
+
+=cut
+sub CanItemBeReserved{
+ my ($borrowernumber, $itemnumber) = @_;
+
+ my $dbh = C4::Context->dbh;
+ my $allowedreserves = 0;
+
+ my $controlbranch = C4::Context->preference('ReservesControlBranch');
+ my $itype = C4::Context->preference('item-level_itypes') ? "itype" : "itemtype";
+
+ # we retrieve borrowers and items informations #
+ my $item = GetItem($itemnumber);
+ my $borrower = C4::Members::GetMember('borrowernumber'=>$borrowernumber);
+
+ # we retrieve user rights on this itemtype and branchcode
+ my $sth = $dbh->prepare("SELECT categorycode, itemtype, branchcode, reservesallowed
+ FROM issuingrules
+ WHERE (categorycode in (?,'*') )
+ AND (itemtype IN (?,'*'))
+ AND (branchcode IN (?,'*'))
+ ORDER BY
+ categorycode DESC,
+ itemtype DESC,
+ branchcode DESC;"
+ );
+
+ my $querycount ="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 = ?
+ ";
+
+
+ my $itemtype = $item->{$itype};
+ my $categorycode = $borrower->{categorycode};
+ my $branchcode = "";
+ my $branchfield = "reserves.branchcode";
+
+ if( $controlbranch eq "ItemHomeLibrary" ){
+ $branchfield = "items.homebranch";
+ $branchcode = $item->{homebranch};
+ }elsif( $controlbranch eq "PatronLibrary" ){
+ $branchfield = "borrowers.branchcode";
+ $branchcode = $borrower->{branchcode};
+ }
+
+ # we retrieve rights
+ $sth->execute($categorycode, $itemtype, $branchcode);
+ if(my $rights = $sth->fetchrow_hashref()){
+ $itemtype = $rights->{itemtype};
+ $allowedreserves = $rights->{reservesallowed};
+ }else{
+ $itemtype = '*';
+ }
+
+ # we retrieve count
+
+ $querycount .= "AND $branchfield = ?";
+
+ $querycount .= " AND $itype = ?" if ($itemtype ne "*");
+ my $sthcount = $dbh->prepare($querycount);
+
+ if($itemtype eq "*"){
+ $sthcount->execute($borrowernumber, $branchcode);
+ }else{
+ $sthcount->execute($borrowernumber, $branchcode, $itemtype);
+ }
+
+ my $reservecount = "0";
+ if(my $rowcount = $sthcount->fetchrow_hashref()){
+ $reservecount = $rowcount->{count};
+ }
+
+ # we check if it's ok or not
+ if( $reservecount < $allowedreserves ){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+#--------------------------------------------------------------------------------
=item GetReserveCount
$number = &GetReserveCount($borrowernumber);
=item CheckReserves
($status, $reserve) = &CheckReserves($itemnumber);
+ ($status, $reserve) = &CheckReserves(undef, $barcode);
Find a book in the reserves.
my ( $item, $barcode ) = @_;
my $dbh = C4::Context->dbh;
my $sth;
+ my $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) {
- my $qitem = $dbh->quote($item);
- # Look up the item by itemnumber
- my $query = "
- SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan, items.notforloan AS itemnotforloan
- FROM items
- LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
- LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
- WHERE itemnumber=$qitem
- ";
- $sth = $dbh->prepare($query);
+ $sth = $dbh->prepare("$select WHERE itemnumber = ?");
+ $sth->execute($item);
}
else {
- my $qbc = $dbh->quote($barcode);
- # Look up the item by barcode
- my $query = "
- SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan, items.notforloan AS itemnotforloan
- FROM items
- LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
- LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
- WHERE items.biblioitemnumber = biblioitems.biblioitemnumber
- AND biblioitems.itemtype = itemtypes.itemtype
- AND barcode=$qbc
- ";
- $sth = $dbh->prepare($query);
-
- # FIXME - This function uses $item later on. Ought to set it here.
+ $sth = $dbh->prepare("$select WHERE barcode = ?");
+ $sth->execute($barcode);
}
- $sth->execute;
- my ( $biblio, $bibitem, $notforloan_per_itemtype, $notforloan_per_item ) = $sth->fetchrow_array;
- $sth->finish;
+ # 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.
+
# if item is not for loan it cannot be reserved either.....
- # execption to notforloan is where items.notforloan < 0 : This indicates the item is holdable.
+ # execpt where items.notforloan < 0 : This indicates the item is holdable.
return ( 0, 0 ) if ( $notforloan_per_item > 0 ) or $notforloan_per_itemtype;
- # get the reserves...
# Find this item in the reserves
- my @reserves = _Findgroupreserve( $bibitem, $biblio, $item );
- my $count = scalar @reserves;
+ my @reserves = _Findgroupreserve( $bibitem, $biblio, $itemnumber );
# $priority and $highest are used to find the most important item
# in the list returned by &_Findgroupreserve. (The lower $priority,
# the more important the item.)
# $highest is the most important item we've seen so far.
- my $priority = 10000000;
my $highest;
- if ($count) {
+ if (scalar @reserves) {
+ my $priority = 10000000;
foreach my $res (@reserves) {
- # FIXME - $item might be undefined or empty: the caller
- # might be searching by barcode.
- if ( $res->{'itemnumber'} == $item && $res->{'priority'} == 0) {
- # Found it
- return ( "Waiting", $res );
- }
- else {
- # See if this item is more important than what we've got
- # so far.
- if ( $res->{'priority'} != 0 && $res->{'priority'} < $priority )
- {
+ if ( $res->{'itemnumber'} == $itemnumber && $res->{'priority'} == 0) {
+ return ( "Waiting", $res ); # Found it
+ } else {
+ # See if this item is more important than what we've got so far
+ if ( $res->{'priority'} && $res->{'priority'} < $priority ) {
$priority = $res->{'priority'};
$highest = $res;
}
}
}
- # If we get this far, then no exact match was found. Print the
- # most important item on the list. I think this tells us who's
- # next in line to get this book.
- if ($highest) { # FIXME - $highest might be undefined
+ # If we get this far, then no exact match was found.
+ # We return the most important (i.e. next) reservation.
+ if ($highest) {
$highest->{'itemnumber'} = $item;
return ( "Reserved", $highest );
}
";
my $sth_set = $dbh->prepare($query);
$sth_set->execute( $newstatus, $itemnumber );
+
+ if ( C4::Context->preference("ReturnToShelvingCart") && $newstatus ) {
+ CartToShelf( $itemnumber );
+ }
}
=item ModReserveAffect
$sth->execute( $itemnumber, $borrowernumber,$biblionumber);
_koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf );
+ if ( C4::Context->preference("ReturnToShelvingCart") ) {
+ CartToShelf( $itemnumber );
+ }
+
return;
}
AND priority > 0
AND item_level_request = 1
AND itemnumber = ?
+ AND reservedate <= CURRENT_DATE()
/;
my $sth = $dbh->prepare($item_level_target_query);
$sth->execute($itemnumber);
AND priority > 0
AND item_level_request = 0
AND hold_fill_targets.itemnumber = ?
+ AND reservedate <= CURRENT_DATE()
/;
$sth = $dbh->prepare($title_level_target_query);
$sth->execute($itemnumber);
AND reserves.reservedate = reserveconstraints.reservedate )
OR reserves.constrainttype='a' )
AND (reserves.itemnumber IS NULL OR reserves.itemnumber = ?)
+ AND reserves.reservedate <= CURRENT_DATE()
/;
$sth = $dbh->prepare($query);
$sth->execute( $biblio, $bibitem, $itemnumber );
}
}
+=item _ShiftPriorityByDateAndPriority
+
+=over 4
+
+$new_priority = _ShiftPriorityByDateAndPriority( $biblionumber, $reservedate, $priority );
+
+=back
+
+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>.
+
+It effectively makes room for a new reserve to be inserted with a certain
+ 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.
+
+=cut
+
+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 $sth = $dbh->prepare( $query );
+ $sth->execute( $biblio, $resdate, $new_priority );
+ my ( $min_priority ) = $sth->fetchrow;
+ $sth->finish; # $sth might have more data.
+ $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";
+ my $sth_update = $dbh->prepare( $query );
+
+ $query = "SELECT * FROM reserves WHERE priority >= ?";
+ $sth = $dbh->prepare( $query );
+ $sth->execute( $new_priority );
+ while ( my $row = $sth->fetchrow_hashref ) {
+ $sth_update->execute( $updated_priority, $biblio, $row->{borrowernumber}, $row->{reservedate} );
+ $updated_priority++;
+ }
+
+ return $new_priority; # so the caller knows what priority they end up at
+}
+
=back
=head1 AUTHOR