@@ -, +, @@ $item_record,$borrower_record; calls OnShelfHoldsAllowed() only have meaning per item type --- C4/Auth.pm | 1 - C4/ILSDI/Services.pm | 2 +- C4/Items.pm | 2 + C4/Reserves.pm | 341 ++++++++++++-------- C4/VirtualShelves/Page.pm | 1 - admin/smart-rules.pl | 19 +- admin/systempreferences.pl | 2 - .../mysql/it-IT/necessari/system_preferences.sql | 1 - installer/data/mysql/kohastructure.sql | 3 + installer/data/mysql/sysprefs.sql | 2 - installer/data/mysql/updatedatabase.pl | 36 ++- installer/html-template-to-template-toolkit.pl | 2 +- .../en/modules/admin/preferences/circulation.pref | 6 - .../prog/en/modules/admin/preferences/opac.pref | 6 - .../prog/en/modules/admin/smart-rules.tt | 94 +++--- .../prog/en/includes/opac-detail-sidebar.inc | 8 +- .../opac-tmpl/prog/en/modules/opac-reserve.tt | 177 +++++----- .../prog/en/modules/opac-results-grouped.tt | 18 +- .../opac-tmpl/prog/en/modules/opac-results.tt | 6 +- .../opac-tmpl/prog/en/modules/opac-shelves.tt | 2 +- opac/opac-ISBDdetail.pl | 9 +- opac/opac-MARCdetail.pl | 8 +- opac/opac-detail.pl | 2 - opac/opac-reserve.pl | 43 +-- opac/opac-search.pl | 19 +- reserve/request.pl | 2 +- 26 files changed, 439 insertions(+), 373 deletions(-) --- a/C4/Auth.pm +++ a/C4/Auth.pm @@ -397,7 +397,6 @@ sub get_template_and_user { OPACAmazonCoverImages => C4::Context->preference("OPACAmazonCoverImages"), OPACFRBRizeEditions => C4::Context->preference("OPACFRBRizeEditions"), OpacHighlightedWords => C4::Context->preference("OpacHighlightedWords"), - OPACItemHolds => C4::Context->preference("OPACItemHolds"), OPACShelfBrowser => "". C4::Context->preference("OPACShelfBrowser"), OpacShowRecentComments => C4::Context->preference("OpacShowRecentComments"), OPACURLOpenInNewWindow => "" . C4::Context->preference("OPACURLOpenInNewWindow"), --- a/C4/ILSDI/Services.pm +++ a/C4/ILSDI/Services.pm @@ -485,7 +485,7 @@ sub GetServices { my $canbookbereserved = CanBookBeReserved( $borrower, $biblionumber ); if ($canbookbereserved) { push @availablefor, 'title level hold'; - my $canitembereserved = IsAvailableForItemLevelRequest($itemnumber); + my $canitembereserved = IsAvailableForItemLevelRequest($item, $borrower); if ($canitembereserved) { push @availablefor, 'item level hold'; } --- a/C4/Items.pm +++ a/C4/Items.pm @@ -164,6 +164,8 @@ sub GetItem { ($data->{'serialseq'} , $data->{'publisheddate'}) = $ssth->fetchrow_array(); } #if we don't have an items.itype, use biblioitems.itemtype. + # FIXME this should respect the itypes systempreference + # if (C4::Context->preference('item-level_itypes')) { if( ! $data->{'itype'} ) { my $sth = $dbh->prepare("SELECT itemtype FROM biblioitems WHERE biblionumber = ?"); $sth->execute($data->{'biblionumber'}); --- a/C4/Reserves.pm +++ a/C4/Reserves.pm @@ -68,13 +68,13 @@ This modules provides somes functions to deal with reservations. The complete workflow is : ==== 1st use case ==== patron request a document, 1st available : P >0, F=NULL, I=NULL - a library having it run "transfertodo", and clic on the list + 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 + patron can pick it up P =0, F=W, 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 @@ -93,7 +93,7 @@ BEGIN { @ISA = qw(Exporter); @EXPORT = qw( &AddReserve - + &GetReservesFromItemnumber &GetReservesFromBiblionumber &GetReservesFromBorrowernumber @@ -103,9 +103,9 @@ BEGIN { &GetReserveFee &GetReserveInfo &GetReserveStatus - + &GetOtherReserves - + &ModReserveFill &ModReserveAffect &ModReserve @@ -113,7 +113,7 @@ BEGIN { &ModReserveCancelAll &ModReserveMinusPriority &MoveReserve - + &CheckReserves &CanBookBeReserved &CanItemBeReserved @@ -123,7 +123,9 @@ BEGIN { &AutoUnsuspendReserves &IsAvailableForItemLevelRequest - + + &OPACItemHoldsAllowed + &AlterPriority &ToggleLowestPriority @@ -132,7 +134,7 @@ BEGIN { &SuspendAll ); @EXPORT_OK = qw( MergeHolds ); -} +} =head2 AddReserve @@ -240,7 +242,7 @@ sub AddReserve { foreach (@$bibitems) { $sth->execute($borrowernumber, $biblionumber, $resdate, $_); } - + return; # FIXME: why not have a useful return value? } @@ -302,7 +304,7 @@ sub GetReservesFromBiblionumber { push( @bibitemno, $bibitemnos ); # FIXME: inefficient: use fetchall_arrayref } my $count = scalar @bibitemno; - + # if we have two or more different specific itemtypes # reserved by same person on same day my $bdata; @@ -417,30 +419,30 @@ This function return 1 if an item can be issued by this borrower. 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); - + 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, + 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 + + my $querycount ="SELECT count(*) as count FROM reserves LEFT JOIN items USING (itemnumber) @@ -448,13 +450,13 @@ sub CanItemBeReserved{ 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}; @@ -462,34 +464,33 @@ sub CanItemBeReserved{ $branchfield = "borrowers.branchcode"; $branchcode = $borrower->{branchcode}; } - - # we retrieve rights + + # we retrieve rights $sth->execute($categorycode, $itemtype, $branchcode); if(my $rights = $sth->fetchrow_hashref()){ $itemtype = $rights->{itemtype}; - $allowedreserves = $rights->{reservesallowed}; + $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; @@ -688,8 +689,8 @@ sub GetReservesToBranch { my $dbh = C4::Context->dbh; my $sth = $dbh->prepare( "SELECT borrowernumber,reservedate,itemnumber,timestamp - FROM reserves - WHERE priority='0' + FROM reserves + WHERE priority='0' AND branchcode=?" ); $sth->execute( $frombranch ); @@ -712,7 +713,7 @@ sub GetReservesForBranch { my ($frombranch) = @_; my $dbh = C4::Context->dbh; my $query = "SELECT borrowernumber,reservedate,itemnumber,waitingdate - FROM reserves + FROM reserves WHERE priority='0' AND found='W' "; if ($frombranch){ @@ -737,11 +738,11 @@ sub GetReservesForBranch { 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; @@ -803,7 +804,7 @@ sub CheckReserves { LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype "; } - + if ($item) { $sth = $dbh->prepare("$select WHERE itemnumber = ?"); $sth->execute($item); @@ -818,7 +819,7 @@ sub CheckReserves { 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. + # execpt where items.notforloan < 0 : This indicates the item is holdable. return ( '' ) if ( $notforloan_per_item > 0 ) or $notforloan_per_itemtype; # Find this item in the reserves @@ -873,7 +874,7 @@ sub CancelExpiredReserves { # Cancel reserves that have passed their expiration date. my $dbh = C4::Context->dbh; my $sth = $dbh->prepare( " - SELECT * FROM reserves WHERE DATE(expirationdate) < DATE( CURDATE() ) + SELECT * FROM reserves WHERE DATE(expirationdate) < DATE( CURDATE() ) AND expirationdate IS NOT NULL AND found IS NULL " ); @@ -882,7 +883,7 @@ sub CancelExpiredReserves { while ( my $res = $sth->fetchrow_hashref() ) { CancelReserve( $res->{'biblionumber'}, '', $res->{'borrowernumber'} ); } - + # Cancel reserves that have been waiting too long if ( C4::Context->preference("ExpireReservesMaxPickUpDelay") ) { my $max_pickup_delay = C4::Context->preference("ReservesMaxPickUpDelay"); @@ -1038,12 +1039,12 @@ If C<$rank> is 'del', the hold request is cancelled. If C<$rank> is an integer greater than zero, the priority of the request is set to that value. Since priority != 0 means -that the item is not waiting on the hold shelf, setting the +that the item is not waiting on the hold shelf, setting the priority to a non-zero value also sets the request's found -status and waiting date to NULL. +status and waiting date to NULL. The optional C<$itemnumber> parameter is used only when -C<$rank> is a non-zero integer; if supplied, the itemnumber +C<$rank> is a non-zero integer; if supplied, the itemnumber of the hold request is set accordingly; if omitted, the itemnumber is cleared. @@ -1073,20 +1074,20 @@ sub ModReserve { $query = qq/ INSERT INTO old_reserves SELECT * - FROM reserves + FROM reserves WHERE biblionumber = ? AND borrowernumber = ? /; $sth = $dbh->prepare($query); $sth->execute( $biblio, $borrower ); $query = qq/ - DELETE FROM reserves + DELETE FROM reserves WHERE biblionumber = ? AND borrowernumber = ? /; $sth = $dbh->prepare($query); $sth->execute( $biblio, $borrower ); - + } elsif ($rank =~ /^\d+/ and $rank > 0) { my $query = " @@ -1171,7 +1172,7 @@ sub ModReserveFill { "; $sth = $dbh->prepare($query); $sth->execute( $biblionumber, $resdate, $borrowernumber ); - + # now fix the priority on the others (if the priority wasn't # already sorted!).... unless ( $priority == 0 ) { @@ -1216,7 +1217,7 @@ with the biblionumber & the borrowernumber, we can affect the itemnumber 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 +otherwise, a transfer is on the way, and the end of the transfer will take care of the waiting status =cut @@ -1297,7 +1298,7 @@ sub ModReserveCancelAll { &ModReserveMinusPriority($itemnumber,$borrowernumber,$biblionumber) -Reduce the values of queuded list +Reduce the values of queuded list =cut @@ -1308,7 +1309,7 @@ sub ModReserveMinusPriority { my $dbh = C4::Context->dbh; my $query = " UPDATE reserves - SET priority = 0 , itemnumber = ? + SET priority = 0 , itemnumber = ? WHERE borrowernumber=? AND biblionumber=? "; @@ -1330,42 +1331,42 @@ Current implementation this query should have a single result. sub GetReserveInfo { my ( $borrowernumber, $biblionumber ) = @_; my $dbh = C4::Context->dbh; - my $strsth="SELECT - reservedate, - reservenotes, + my $strsth="SELECT + reservedate, + reservenotes, reserves.borrowernumber, - reserves.biblionumber, + reserves.biblionumber, reserves.branchcode, reserves.waitingdate, - notificationdate, - reminderdate, - priority, + notificationdate, + reminderdate, + priority, found, - firstname, - surname, - phone, - email, - address, + firstname, + surname, + phone, + email, + address, address2, - cardnumber, - city, + cardnumber, + city, zipcode, - biblio.title, + biblio.title, biblio.author, - items.holdingbranch, - items.itemcallnumber, + items.holdingbranch, + items.itemcallnumber, items.itemnumber, - items.location, - barcode, + items.location, + barcode, notes - FROM reserves - LEFT JOIN items USING(itemnumber) + FROM reserves + LEFT JOIN items USING(itemnumber) LEFT JOIN borrowers USING(borrowernumber) - LEFT JOIN biblio ON (reserves.biblionumber=biblio.biblionumber) - WHERE + LEFT JOIN biblio ON (reserves.biblionumber=biblio.biblionumber) + WHERE reserves.borrowernumber=? AND reserves.biblionumber=?"; - my $sth = $dbh->prepare($strsth); + my $sth = $dbh->prepare($strsth); $sth->execute($borrowernumber,$biblionumber); my $data = $sth->fetchrow_hashref; @@ -1375,22 +1376,18 @@ sub GetReserveInfo { =head2 IsAvailableForItemLevelRequest - my $is_available = IsAvailableForItemLevelRequest($itemnumber); + my $is_available = IsAvailableForItemLevelRequest($item_record,$borrower_record); 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 +* 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. +Need to check the issuingrules onshelfholds column, +if this is set items on the shelf can be placed on hold Note that IsAvailableForItemLevelRequest() does not check if the staff operator is authorized to place @@ -1401,50 +1398,82 @@ and canreservefromotherbranches. =cut sub IsAvailableForItemLevelRequest { - my $itemnumber = shift; - - my $item = GetItem($itemnumber); + my $item = shift; + my $borrower = shift; + 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 $dbh = C4::Context->dbh; - my $notforloan_query; + my $itype; 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 = ?"; + # We cant trust GetItem to honour the syspref, so safest to do it ourselves + # When GetItem is fixed, we can remove this + $itype = $item->{itype}; } - 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; + else { + # XXX This is a bit dodgy. It relies on biblio itemtype column having different name. + # So if we already have a biblioitems join when calling this function, + # we don't need to access the database again + $itype = $item->{itemtype}; + } + unless ($itype) { + my $query = "SELECT itemtype FROM biblioitems WHERE biblioitemnumber = ? "; + my $sth = $dbh->prepare($query); + $sth->execute($item->{biblioitemnumber}); + if (my $data = $sth->fetchrow_hashref()){ + $itype = $data->{itemtype}; + } } - 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; + my $notforloan_per_itemtype + = $dbh->selectrow_array("SELECT notforloan FROM itemtypes WHERE itemtype = ?", + undef, $itype); + + return 0 if + $notforloan_per_itemtype || + $item->{itemlost} || + $item->{notforloan} > 0 || + $item->{wthdrawn} || + ($item->{damaged} && !C4::Context->preference('AllowHoldsOnDamagedItems')); - if (C4::Context->preference('AllowOnShelfHolds')) { - return $available_per_item; + if (OnShelfHoldsAllowed($itype,$borrower->{categorycode},$item->{holdingbranch})) { + return 1; } else { - return ($available_per_item and ($item->{onloan} or GetReserveStatus($itemnumber) eq "W")); + return $item->{onloan} || GetReserveStatus($item->{itemnumber}) eq "W"; } } +=head2 OnShelfHoldsAllowed + + OnShelfHoldsAllowed($itemtype,$borrowercategory,$branchcode); + +Checks issuingrules, using the borrowers categorycode, the itemtype, and branchcode to see if onshelf +holds are allowed, returns true if so. + +=cut + +sub OnShelfHoldsAllowed { + my ($itype,$borrowercategory,$branchcode) = @_; + + my $query = "SELECT onshelfholds FROM issuingrules WHERE + (issuingrules.categorycode = ? OR issuingrules.categorycode = '*') + AND + (issuingrules.itemtype = ? OR issuingrules.itemtype = '*') + AND + (issuingrules.branchcode = ? OR issuingrules.branchcode = '*') + ORDER BY + issuingrules.categorycode desc, + issuingrules.itemtype desc, + issuingrules.branchcode desc + LIMIT 1"; + my $dbh = C4::Context->dbh; + my $onshelfholds = $dbh->selectrow_array($query, undef, $borrowercategory,$itype,$branchcode); + return $onshelfholds; +} + =head2 AlterPriority AlterPriority( $where, $borrowernumber, $biblionumber, $reservedate ); @@ -1466,8 +1495,8 @@ sub AlterPriority { $sth->finish(); if ( $where eq 'up' || $where eq 'down' ) { - - my $priority = $reserve->{'priority'}; + + my $priority = $reserve->{'priority'}; $priority = $where eq 'up' ? $priority - 1 : $priority + 1; _FixPriority( $biblionumber, $borrowernumber, $priority ) @@ -1505,7 +1534,7 @@ sub ToggleLowestPriority { $borrowernumber, ); $sth->finish; - + _FixPriority( $biblionumber, $borrowernumber, '999999' ); } @@ -1612,7 +1641,7 @@ 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 +=cut sub _FixPriority { my ( $biblio, $borrowernumber, $rank, $ignoreSetLowestRank ) = @_; @@ -1691,10 +1720,10 @@ 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 ); @@ -1754,7 +1783,7 @@ sub _Findgroupreserve { push( @results, $data ); } return @results if @results; - + # check for title-level targetted match my $title_level_target_query = qq/ SELECT reserves.biblionumber AS biblionumber, @@ -1833,7 +1862,7 @@ sub _koha_notify_reserve { my $dbh = C4::Context->dbh; 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'); @@ -1843,7 +1872,7 @@ sub _koha_notify_reserve { } else { $to_address = $borrower->{$which_address}; } - + my $letter_code; my $print_mode = 0; my $messagingprefs; @@ -1888,7 +1917,7 @@ sub _koha_notify_reserve { borrowernumber => $borrowernumber, message_transport_type => 'print', } ); - + return; } @@ -1967,6 +1996,58 @@ sub _ShiftPriorityByDateAndPriority { return $new_priority; # so the caller knows what priority they wind up receiving } +=head2 OPACItemHoldsAllowed + + OPACItemHoldsAllowed($item_record,$borrower_record); + +Checks issuingrules, using the borrowers categorycode, the itemtype, and branchcode to see +if specific item holds are allowed, returns true if so. + +=cut + +sub OPACItemHoldsAllowed { + my ($item,$borrower) = @_; + + my $branchcode = $item->{homebranch} or die "No homebranch"; + my $itype; + my $dbh = C4::Context->dbh; + if (C4::Context->preference('item-level_itypes')) { + # We cant trust GetItem to honour the syspref, so safest to do it ourselves + # When GetItem is fixed, we can remove this + $itype = $item->{itype}; + } + else { + my $query = "SELECT itemtype FROM biblioitems WHERE biblioitemnumber = ? "; + my $sth = $dbh->prepare($query); + $sth->execute($item->{biblioitemnumber}); + if (my $data = $sth->fetchrow_hashref()){ + $itype = $data->{itemtype}; + } + } + + my $query = "SELECT opacitemholds,categorycode,itemtype,branchcode FROM issuingrules WHERE + (issuingrules.categorycode = ? OR issuingrules.categorycode = '*') + AND + (issuingrules.itemtype = ? OR issuingrules.itemtype = '*') + AND + (issuingrules.branchcode = ? OR issuingrules.branchcode = '*') + ORDER BY + issuingrules.categorycode desc, + issuingrules.itemtype desc, + issuingrules.branchcode desc + LIMIT 1"; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare($query); + $sth->execute($borrower->{categorycode},$itype,$branchcode); + my $data = $sth->fetchrow_hashref; + if ($data->{opacitemholds}){ + return 1; + } + else { + return 0; + } +} + =head2 MoveReserve MoveReserve( $itemnumber, $borrowernumber, $cancelreserve ) --- a/C4/VirtualShelves/Page.pm +++ a/C4/VirtualShelves/Page.pm @@ -238,7 +238,6 @@ sub shelfpage { # explicitly fetch this shelf my ($shelfnumber2,$shelfname,$owner,$category,$sorton) = GetShelf($shelfnumber); - $template->param( 'AllowOnShelfHolds' => C4::Context->preference('AllowOnShelfHolds') ); if (C4::Context->preference('TagsEnabled')) { $template->param(TagsEnabled => 1); foreach (qw(TagsShowOnList TagsInputOnList)) { --- a/admin/smart-rules.pl +++ a/admin/smart-rules.pl @@ -101,12 +101,12 @@ elsif ($op eq 'delete-branch-item') { # save the values entered elsif ($op eq 'add') { my $sth_search = $dbh->prepare('SELECT COUNT(*) AS total FROM issuingrules WHERE branchcode=? AND categorycode=? AND itemtype=?'); - my $sth_insert = $dbh->prepare('INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, reservesallowed, issuelength, lengthunit, hardduedate, hardduedatecompare, fine, finedays, firstremind, chargeperiod,rentaldiscount, overduefinescap) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'); - my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, reservesallowed=?, issuelength=?, lengthunit = ?, hardduedate=?, hardduedatecompare=?, rentaldiscount=?, overduefinescap=? WHERE branchcode=? AND categorycode=? AND itemtype=?"); + my $sth_insert = $dbh->prepare('INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, reservesallowed, issuelength, lengthunit, hardduedate, hardduedatecompare, fine, finedays, firstremind, chargeperiod,rentaldiscount, onshelfholds, opacitemholds, reservesmaxpickupdelay, overduefinescap) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'); + my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, reservesallowed=?, issuelength=?, lengthunit=?, hardduedate=?, hardduedatecompare=?, rentaldiscount=?, onshelfholds=?, opacitemholds=?, reservesmaxpickupdelay=?, overduefinescap=? WHERE branchcode=? AND categorycode=? AND itemtype=?"); my $br = $branch; # branch my $bor = $input->param('categorycode'); # borrower category - my $cat = $input->param('itemtype'); # item type + my $itemtype = $input->param('itemtype'); # item type my $fine = $input->param('fine'); my $finedays = $input->param('finedays'); my $firstremind = $input->param('firstremind'); @@ -114,6 +114,7 @@ elsif ($op eq 'add') { my $maxissueqty = $input->param('maxissueqty'); my $renewalsallowed = $input->param('renewalsallowed'); my $reservesallowed = $input->param('reservesallowed'); + my $onshelfholds = $input->param('onshelfholds') || 0; $maxissueqty =~ s/\s//g; $maxissueqty = undef if $maxissueqty !~ /^\d+/; my $issuelength = $input->param('issuelength'); @@ -122,15 +123,17 @@ elsif ($op eq 'add') { $hardduedate = format_date_in_iso($hardduedate); my $hardduedatecompare = $input->param('hardduedatecompare'); my $rentaldiscount = $input->param('rentaldiscount'); + my $reservesmaxpickupdelay = $input->param('reservesmaxpickupdelay'); + my $opacitemholds = $input->param('opacitemholds') || 0; my $overduefinescap = $input->param('overduefinescap') || undef; - $debug and warn "Adding $br, $bor, $cat, $fine, $maxissueqty"; + $debug and warn "Adding $br, $bor, $itemtype, $fine, $maxissueqty"; - $sth_search->execute($br,$bor,$cat); + $sth_search->execute($br,$bor,$itemtype); my $res = $sth_search->fetchrow_hashref(); if ($res->{total}) { - $sth_update->execute($fine, $finedays,$firstremind, $chargeperiod, $maxissueqty, $renewalsallowed,$reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount,$overduefinescap, $br,$bor,$cat); + $sth_update->execute($fine, $finedays,$firstremind, $chargeperiod, $maxissueqty, $renewalsallowed,$reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount, $onshelfholds, $opacitemholds, $reservesmaxpickupdelay, $overduefinescap, $br,$bor,$itemtype); } else { - $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed,$reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays,$firstremind,$chargeperiod,$rentaldiscount,$overduefinescap); + $sth_insert->execute($br,$bor,$itemtype,$maxissueqty,$renewalsallowed,$reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays,$firstremind,$chargeperiod,$rentaldiscount,$onshelfholds,$opacitemholds,$reservesmaxpickupdelay,$overduefinescap); } } elsif ($op eq "set-branch-defaults") { @@ -385,7 +388,7 @@ while (my $row = $sth2->fetchrow_hashref) { $row->{'humancategorycode'} ||= $row->{'categorycode'}; $row->{'default_humancategorycode'} = 1 if $row->{'humancategorycode'} eq '*'; $row->{'fine'} = sprintf('%.2f', $row->{'fine'}); - if ($row->{'hardduedate'} ne '0000-00-00') { + if ($row->{'hardduedate'} && $row->{'hardduedate'} ne '0000-00-00') { $row->{'hardduedate'} = format_date( $row->{'hardduedate'}); $row->{'hardduedatebefore'} = 1 if ($row->{'hardduedatecompare'} == -1); $row->{'hardduedateexact'} = 1 if ($row->{'hardduedatecompare'} == 0); --- a/admin/systempreferences.pl +++ a/admin/systempreferences.pl @@ -186,7 +186,6 @@ $tabsysprefs{HomeOrHoldingBranch} = "Circulation"; $tabsysprefs{HomeOrHoldingBranchReturn} = "Circulation"; $tabsysprefs{RandomizeHoldsQueueWeight} = "Circulation"; $tabsysprefs{StaticHoldsQueueWeight} = "Circulation"; -$tabsysprefs{AllowOnShelfHolds} = "Circulation"; $tabsysprefs{AllowHoldsOnDamagedItems} = "Circulation"; $tabsysprefs{UseBranchTransferLimits} = "Circulation"; $tabsysprefs{AllowHoldPolicyOverride} = "Circulation"; @@ -366,7 +365,6 @@ $tabsysprefs{suggestion} = "OPAC"; $tabsysprefs{OpacTopissue} = "OPAC"; $tabsysprefs{OpacBrowser} = "OPAC"; $tabsysprefs{OpacRenewalAllowed} = "OPAC"; -$tabsysprefs{OPACItemHolds} = "OPAC"; $tabsysprefs{OPACGroupResults} = "OPAC"; $tabsysprefs{XSLTDetailsDisplay} = "OPAC"; $tabsysprefs{XSLTResultsDisplay} = "OPAC"; --- a/installer/data/mysql/it-IT/necessari/system_preferences.sql +++ a/installer/data/mysql/it-IT/necessari/system_preferences.sql @@ -17,7 +17,6 @@ -- 51 Franklin Street' WHERE variable = ' Fifth Floor' WHERE variable = ' Boston' WHERE variable = ' MA 02110-1301 USA. UPDATE systempreferences SET value = 'cataloguing' WHERE variable = 'AcqCreateItem'; -UPDATE systempreferences SET value = '1' WHERE variable = 'AllowOnShelfHolds'; UPDATE systempreferences SET value = '1' WHERE variable = 'AllowRenewalLimitOverride'; UPDATE systempreferences SET value = 'annual' WHERE variable = 'autoBarcode'; UPDATE systempreferences SET value = 'email' WHERE variable = 'AutoEmailPrimaryAddress'; --- a/installer/data/mysql/kohastructure.sql +++ a/installer/data/mysql/kohastructure.sql @@ -999,6 +999,9 @@ CREATE TABLE `issuingrules` ( -- circulation and fine rules `reservesallowed` smallint(6) NOT NULL default "0", -- how many holds are allowed `branchcode` varchar(10) NOT NULL default '', -- the branch this rule is for (branches.branchcode) overduefinescap decimal default NULL, -- the maximum amount of an overdue fine + onshelfholds tinyint(1) NOT NULL default 0, -- allow holds for items that are on shelf + opacitemholds tinyint(1) NOT NULL default "0", -- allow opac users to place specific items on hold + reservesmaxpickupdelay smallint(6) default NULL, -- max pickup delay PRIMARY KEY (`branchcode`,`categorycode`,`itemtype`), KEY `categorycode` (`categorycode`), KEY `itemtype` (`itemtype`) --- a/installer/data/mysql/sysprefs.sql +++ a/installer/data/mysql/sysprefs.sql @@ -186,7 +186,6 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OAI-PMH:archiveID','KOHA-OAI-TEST','OAI-PMH archive identification',NULL,'Free'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OAI-PMH:MaxCount','50','OAI-PMH maximum number of records by answer to ListRecords and ListIdentifiers queries',NULL,'Integer'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OAI-PMH:ConfFile','','If empty, Koha OAI Server operates in normal mode, otherwise it operates in extended mode.',NULL,'File'); -INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OPACItemHolds','1','Allow OPAC users to place hold on specific items. If OFF, users can only request next available copy.','','YesNo'); INSERT INTO `systempreferences` (variable, value,options,type, explanation) VALUES ('AddPatronLists','categorycode','categorycode|category_type','Choice','Allow user to choose what list to pick up from when adding patrons'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ExtendedPatronAttributes','0','Use extended patron IDs and attributes',NULL,'YesNo'); @@ -219,7 +218,6 @@ INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('XSLTDetailsDisplay','','','Enable XSL stylesheet control over details page display on intranet','Free'), ('XSLTResultsDisplay','','','Enable XSL stylesheet control over results page display on intranet','Free'); INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES('AdvancedSearchTypes','itemtypes','itemtypes|ccode','Select which set of fields comprise the Type limit in the advanced search','Choice'); -INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES('AllowOnShelfHolds', '0', '', 'Allow hold requests to be placed on items that are not on loan', 'YesNo'); INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES('AllowHoldsOnDamagedItems', '1', '', 'Allow hold requests to be placed on damaged items', 'YesNo'); INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES('OpacSuppression', '0', '', 'Turn ON the OPAC Suppression feature, requires further setup, ask your system administrator for details', 'YesNo'); -- FIXME: add FrameworksLoaded, noOPACUserLogin? --- a/installer/data/mysql/updatedatabase.pl +++ a/installer/data/mysql/updatedatabase.pl @@ -2092,7 +2092,6 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) { $dbh->do("UPDATE `systempreferences` SET options='10' WHERE variable='globalDueDate'"); $dbh->do("UPDATE `systempreferences` SET type='Integer' WHERE variable='numSearchResults'"); $dbh->do("UPDATE `systempreferences` SET type='Integer' WHERE variable='OPACnumSearchResults'"); - $dbh->do("UPDATE `systempreferences` SET type='Integer' WHERE variable='ReservesMaxPickupDelay'"); $dbh->do("UPDATE `systempreferences` SET type='Integer' WHERE variable='TransfersMaxDaysWarning'"); $dbh->do("UPDATE `systempreferences` SET type='Integer' WHERE variable='StaticHoldsQueueWeight'"); $dbh->do("UPDATE `systempreferences` SET type='Integer' WHERE variable='holdCancelLength'"); @@ -5657,6 +5656,41 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) { SetVersion ($DBversion); } + + +$DBversion = '3.09.00.XXX'; +if (C4::Context->preference("Version") < TransformToNum($DBversion)) { + # First create the column + $dbh->do("ALTER TABLE issuingrules ADD onshelfholds tinyint(1) default 0"); + # Now update the column + if (C4::Context->preference("AllowOnShelfHolds")){ + # Pref is on, set allow for all rules + $dbh->do("UPDATE issuingrules SET onshelfholds=1"); + } else { + # If the preference is not set, leave off + $dbh->do("UPDATE issuingrules SET onshelfholds=0"); + } + $dbh->do("ALTER TABLE issuingrules MODIFY onshelfholds tinyint(1) default 0 NOT NULL"); + # Remove from the systempreferences table + $dbh->do("DELETE FROM systempreferences WHERE variable = 'AllowOnShelfHolds'"); + + # First create the column + $dbh->do("ALTER TABLE issuingrules ADD opacitemholds tinyint(1) DEFAULT 0"); + # Now update the column + if (C4::Context->preference("OPACItemHolds")){ + # Pref is on, set allow for all rules + $dbh->do("UPDATE issuingrules SET opacitemholds=1"); + } + # If the preference is not set, leave off + # Remove from the systempreferences table + $dbh->do("DELETE FROM systempreferences WHERE variable = 'OPACItemHolds'"); + + $dbh->do("ALTER TABLE issuingrules ADD reservesmaxpickupdelay smallint(6) DEFAULT NULL"); + + print "Upgrade to $DBversion done (Move AllowOnShelfHolds to circulation matrix; Move OPACItemHolds system preference to circulation matrix; ReservesMaxPickupDelay circulation rule)\n"; + SetVersion ($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) --- a/installer/html-template-to-template-toolkit.pl +++ a/installer/html-template-to-template-toolkit.pl @@ -32,7 +32,7 @@ my @globals = ("themelang","JacketImages","OPACAmazonCoverImages","GoogleJackets "SyndeticsEnabled", "OpacRenewalAllowed", "item_level_itypes","noItemTypeImages", "virtualshelves", "RequestOnOpac", "COinSinOPACResults", "OPACXSLTResultsDisplay", "OPACItemsResultsDisplay", "LibraryThingForLibrariesID", "opacuserlogin", "TagsEnabled", -"TagsShowOnList", "TagsInputOnList","loggedinusername","AllowOnShelfHolds","opacbookbag", +"TagsShowOnList", "TagsInputOnList","loggedinusername","opacbookbag", "OPACAmazonEnabled", "SyndeticsCoverImages","using_https"); # Arguments: --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -269,12 +269,6 @@ Circulation: no: "Don't allow" - hold requests to be placed on damaged items. - - - pref: AllowOnShelfHolds - choices: - yes: Allow - no: "Don't allow" - - hold requests to be placed on items that are not checked out. - - - pref: AllowHoldDateInFuture choices: yes: Allow --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref @@ -379,12 +379,6 @@ OPAC: # choices: # - If ON, enables subject cloud on OPAC - - - pref: OPACItemHolds - choices: - yes: Allow - no: "Don't allow" - - patrons to place holds on specific items in the OPAC. If this is disabled, users can only put a hold on the next available item. - - - pref: OpacRenewalAllowed choices: yes: Allow --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt @@ -76,57 +76,46 @@ for="tobranch">Clone these rules to: - [% ELSE %] -