From 4e1d7a16896787cb4e874abce8fc051a3c12a3ae Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Sat, 6 Feb 2016 03:59:31 +0000 Subject: [PATCH] Bug 15534 - Add the ability to prevent a patron from placing a hold on a record with available items MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Some libraries would like to prevent patrons from placing holds on items where there are other items available for the patron to check out. Test Plan: 1) Apply this patch 2) Browse to the circulation rules 3) Note the new option for "On shelf holds allowed" 4) Set the rule to "If all unavailable", set "item level holds" to allow 5) Find a patron/branch/itemtype applicable to this rule 6) Ensure at least one item on the record is available for the patron to check out 7) Attempt to place a hold for the item 8) Note you cannot place the hold 9) Check the available item out to another patron 10) Note you can now place a hold for the first patron Signed-off-by: Andreas Hedström Mace Works as intended! Signed-off-by: Jonathan Druart Signed-off-by: Katrin Fischer Signed-off-by: Kyle M Hall --- C4/Reserves.pm | 26 +++- .../prog/en/modules/admin/smart-rules.tt | 12 +- .../Holds/DisallowHoldIfItemsAvailable.t | 120 ++++++++++++++++++ 3 files changed, 155 insertions(+), 3 deletions(-) create mode 100755 t/db_dependent/Holds/DisallowHoldIfItemsAvailable.t diff --git a/C4/Reserves.pm b/C4/Reserves.pm index caf44eaef4..4823f5382f 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -41,6 +41,8 @@ use Koha::Database; use Koha::Hold; use Koha::Holds; use Koha::Libraries; +use Koha::Items; +use Koha::ItemTypes; use List::MoreUtils qw( firstidx any ); use Carp; @@ -1498,8 +1500,30 @@ sub IsAvailableForItemLevelRequest { $item->{withdrawn} || ($item->{damaged} && !C4::Context->preference('AllowHoldsOnDamagedItems')); + my $on_shelf_holds = _OnShelfHoldsAllowed($itype,$borrower->{categorycode},$item->{holdingbranch}); + + if ( $on_shelf_holds == 1 ) { + return 1; + } elsif ( $on_shelf_holds == 2 ) { + my @items = + Koha::Items->search( { biblionumber => $item->{biblionumber} } ); + + my $any_available = 0; + + foreach my $i (@items) { + $any_available = 1 + unless $i->itemlost + || $i->{notforloan} > 0 + || $i->withdrawn + || $i->onloan + || GetReserveStatus( $i->id ) eq "Waiting" + || ( $i->damaged + && !C4::Context->preference('AllowHoldsOnDamagedItems') ) + || Koha::ItemTypes->find( $i->effective_itemtype() )->notforloan; + } - return 1 if _OnShelfHoldsAllowed($itype,$borrower->{categorycode},$item->{holdingbranch}); + return $any_available ? 0 : 1; + } return $item->{onloan} || GetReserveStatus($item->{itemnumber}) eq "Waiting"; } diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt index 184258d3fd..40900da32e 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt @@ -248,7 +248,14 @@ for="tobranch">Clone these rules to: Edit @@ -318,7 +325,8 @@ for="tobranch">Clone these rules to: - + + diff --git a/t/db_dependent/Holds/DisallowHoldIfItemsAvailable.t b/t/db_dependent/Holds/DisallowHoldIfItemsAvailable.t new file mode 100755 index 0000000000..54a8b7f8e2 --- /dev/null +++ b/t/db_dependent/Holds/DisallowHoldIfItemsAvailable.t @@ -0,0 +1,120 @@ +#!/usr/bin/perl + +use Modern::Perl; + +use C4::Context; +use C4::Items; +use C4::Circulation; +use Koha::IssuingRule; + +use Test::More tests => 4; + +use t::lib::TestBuilder; + +BEGIN { + use FindBin; + use lib $FindBin::Bin; + use_ok('C4::Reserves'); +} + +my $schema = Koha::Database->schema; +$schema->storage->txn_begin; +my $dbh = C4::Context->dbh; + +my $builder = t::lib::TestBuilder->new; + +my $library1 = $builder->build({ + source => 'Branch', +}); + +# Now, set a userenv +C4::Context->_new_userenv('xxx'); +C4::Context->set_userenv(0,0,0,'firstname','surname', $library1->{branchcode}, 'Midway Public Library', '', '', ''); + +my $bib_title = "Test Title"; + +my $borrower1 = $builder->build({ + source => 'Borrower', + value => { + branchcode => $library1->{branchcode}, + dateexpiry => '3000-01-01', + } +}); + +my $borrower2 = $builder->build({ + source => 'Borrower', + value => { + branchcode => $library1->{branchcode}, + dateexpiry => '3000-01-01', + } +}); + +# Test hold_fulfillment_policy +my ( $itemtype ) = @{ $dbh->selectrow_arrayref("SELECT itemtype FROM itemtypes LIMIT 1") }; +my $borrowernumber1 = $borrower1->{borrowernumber}; +my $borrowernumber2 = $borrower2->{borrowernumber}; +my $library_A = $library1->{branchcode}; + +$dbh->do("INSERT INTO biblio (frameworkcode, author, title, datecreated) VALUES ('', 'Koha test', '$bib_title', '2011-02-01')"); + +my $biblionumber = $dbh->selectrow_array("SELECT biblionumber FROM biblio WHERE title = '$bib_title'") + or BAIL_OUT("Cannot find newly created biblio record"); + +$dbh->do("INSERT INTO biblioitems (biblionumber, marcxml, itemtype) VALUES ($biblionumber, '', '$itemtype')"); + +my $biblioitemnumber = + $dbh->selectrow_array("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber = $biblionumber") + or BAIL_OUT("Cannot find newly created biblioitems record"); + +$dbh->do(" + INSERT INTO items (barcode, biblionumber, biblioitemnumber, homebranch, holdingbranch, notforloan, damaged, itemlost, withdrawn, onloan, itype) + VALUES ('AllowHoldIf1', $biblionumber, $biblioitemnumber, '$library_A', '$library_A', 0, 0, 0, 0, NULL, '$itemtype') +"); + +my $itemnumber1 = + $dbh->selectrow_array("SELECT itemnumber FROM items WHERE biblionumber = $biblionumber") + or BAIL_OUT("Cannot find newly created item"); + +my $item1 = GetItem( $itemnumber1 ); + +$dbh->do(" + INSERT INTO items (barcode, biblionumber, biblioitemnumber, homebranch, holdingbranch, notforloan, damaged, itemlost, withdrawn, onloan, itype) + VALUES ('AllowHoldIf2', $biblionumber, $biblioitemnumber, '$library_A', '$library_A', 0, 0, 0, 0, NULL, '$itemtype') +"); + +my $itemnumber2 = + $dbh->selectrow_array("SELECT itemnumber FROM items WHERE biblionumber = $biblionumber ORDER BY itemnumber DESC") + or BAIL_OUT("Cannot find newly created item"); + +my $item2 = GetItem( $itemnumber2 ); + +$dbh->do("DELETE FROM issuingrules"); +my $rule = Koha::IssuingRule->new( + { + categorycode => '*', + itemtype => '*', + branchcode => '*', + maxissueqty => 99, + issuelength => 7, + lengthunit => 8, + reservesallowed => 99, + onshelfholds => 2, + } +); +$rule->store(); + +my $is = IsAvailableForItemLevelRequest( $item1, $borrower1); +is( $is, 0, "Item cannot be held, 2 items available" ); + +AddIssue( $borrower2, $item1->{barcode} ); + +$is = IsAvailableForItemLevelRequest( $item1, $borrower1); +is( $is, 0, "Item cannot be held, 1 item available" ); + +AddIssue( $borrower2, $item2->{barcode} ); + +$is = IsAvailableForItemLevelRequest( $item1, $borrower1); +is( $is, 1, "Item can be held, no items available" ); + +# Cleanup +$schema->storage->txn_rollback; -- 2.39.5