@@ -, +, @@ system by patron category in the "Checkout limit by patron category". ( Should we rename this section? ) number of holds that patron has. Lets make that number 'X'. --- C4/Reserves.pm | 28 ++++++++ admin/smart-rules.pl | 48 ++++++++++++-- .../prog/en/modules/admin/smart-rules.tt | 9 +++ t/db_dependent/Holds.t | 76 +++++++++++++++++++++- 4 files changed, 156 insertions(+), 5 deletions(-) --- a/C4/Reserves.pm +++ a/C4/Reserves.pm @@ -48,6 +48,7 @@ use Koha::IssuingRules; use Koha::Items; use Koha::ItemTypes; use Koha::Patrons; +use Koha::CirculationRules; use List::MoreUtils qw( firstidx any ); use Carp; @@ -398,6 +399,33 @@ sub CanItemBeReserved { return 'tooManyReserves'; } + # Now we need to check hold limits by patron category + my $rule = Koha::CirculationRules->find( + { + categorycode => $borrower->{categorycode}, + branchcode => $borrower->{branchcode}, + itemtype => undef, + rule_name => 'max_holds', + } + ); + $rule ||= Koha::CirculationRules->find( + { + categorycode => $borrower->{categorycode}, + branchcode => undef,, + itemtype => undef, + rule_name => 'max_holds', + } + ); + if ( $rule ) { + my $total_holds_count = Koha::Holds->search( + { + borrowernumber => $borrower->{borrowernumber} + } + )->count(); + + return 'tooManyReserves' if $total_holds_count >= $rule->rule_value; + } + my $circ_control_branch = C4::Circulation::_GetCircControlBranch( $item->unblessed(), $borrower ); my $branchitemrule = --- a/admin/smart-rules.pl +++ a/admin/smart-rules.pl @@ -32,6 +32,7 @@ use Koha::Logger; use Koha::RefundLostItemFeeRule; use Koha::RefundLostItemFeeRules; use Koha::Libraries; +use Koha::CirculationRules; use Koha::Patron::Categories; my $input = CGI->new; @@ -93,6 +94,15 @@ elsif ($op eq 'delete-branch-cat') { AND categorycode = ?"); $sth_delete->execute($branch, $categorycode); } + Koha::CirculationRules->set_rule( + { + branchcode => $branch, + categorycode => $categorycode, + itemtype => undef, + rule_name => 'max_holds', + rule_value => undef, + } + ); } elsif ($op eq 'delete-branch-item') { my $itemtype = $input->param('itemtype'); @@ -277,10 +287,20 @@ elsif ($op eq "add-branch-cat") { $sth_search->execute(); my $res = $sth_search->fetchrow_hashref(); if ($res->{total}) { - $sth_update->execute($maxissueqty, $maxonsiteissueqty); + $sth_update->execute( $maxissueqty, $maxonsiteissueqty ); } else { - $sth_insert->execute($maxissueqty, $maxonsiteissueqty); + $sth_insert->execute( $maxissueqty, $maxonsiteissueqty ); } + + Koha::CirculationRules->set_rule( + { + branchcode => undef, + categorycode => undef, + itemtype => undef, + rule_name => 'max_holds', + rule_value => $max_holds, + } + ); } else { my $sth_search = $dbh->prepare("SELECT count(*) AS total FROM default_borrower_circ_rules @@ -299,10 +319,20 @@ elsif ($op eq "add-branch-cat") { $sth_search->execute($categorycode); my $res = $sth_search->fetchrow_hashref(); if ($res->{total}) { - $sth_update->execute($maxissueqty, $maxonsiteissueqty, $categorycode); + $sth_update->execute( $maxissueqty, $maxonsiteissueqty, $categorycode ); } else { - $sth_insert->execute($categorycode, $maxissueqty, $maxonsiteissueqty); + $sth_insert->execute( $categorycode, $maxissueqty, $maxonsiteissueqty ); } + + Koha::CirculationRules->set_rule( + { + branchcode => undef, + categorycode => $categorycode, + itemtype => undef, + rule_name => 'max_holds', + rule_value => $max_holds, + } + ); } } elsif ($categorycode eq "*") { my $sth_search = $dbh->prepare("SELECT count(*) AS total @@ -351,6 +381,16 @@ elsif ($op eq "add-branch-cat") { } else { $sth_insert->execute($branch, $categorycode, $maxissueqty, $maxonsiteissueqty); } + + Koha::CirculationRules->set_rule( + { + branchcode => $branch, + categorycode => $categorycode, + itemtype => undef, + rule_name => 'max_holds', + rule_value => $max_holds, + } + ); } } elsif ($op eq "add-branch-item") { --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt @@ -1,4 +1,5 @@ [% USE Branches %] +[% USE CirculationRules %] [% SET footerjs = 1 %] [% INCLUDE 'doc-head-open.inc' %] Koha › Administration › Circulation and fine rules @@ -490,6 +491,14 @@ [% branch_cat_rule_loo.maxonsiteissueqty %] [% END %] + + [% SET rule_value = CirculationRules.Get( branch_cat_rule_loo.branchcode, branch_cat_rule_loo.categorycode, branch_cat_rule_loo.itemtype, 'max_holds' ) %] + [% IF rule_value %] + [% rule_value %] + [% ELSE %] + Unlimited + [% END %] + Delete --- a/t/db_dependent/Holds.t +++ a/t/db_dependent/Holds.t @@ -7,7 +7,7 @@ use t::lib::TestBuilder; use C4::Context; -use Test::More tests => 55; +use Test::More tests => 56; use MARC::Record; use C4::Biblio; use C4::Items; @@ -18,6 +18,7 @@ use Koha::DateUtils qw( dt_from_string output_pref ); use Koha::Biblios; use Koha::Holds; use Koha::Patrons; +use Koha::CirculationRules; BEGIN { use FindBin; @@ -411,6 +412,79 @@ my $res_id = AddReserve( $branch_1, $borrowernumbers[0], $bibnum, '', 1, ); is( CanItemBeReserved( $borrowernumbers[0], $itemnumber ), 'tooManyReserves', 'Patron cannot reserve item with hold limit of 1, 1 bib level hold placed' ); +subtest 'Test max_holds per library/patron category' => sub { + plan tests => 6; + + $dbh->do('DELETE FROM reserves'); + $dbh->do('DELETE FROM issuingrules'); + $dbh->do('DELETE FROM circulation_rules'); + + ( $bibnum, $title, $bibitemnum ) = create_helper_biblio('TEST'); + ( $item_bibnum, $item_bibitemnum, $itemnumber ) = + AddItem( { homebranch => $branch_1, holdingbranch => $branch_1 }, + $bibnum ); + $dbh->do( + q{ + INSERT INTO issuingrules (categorycode, branchcode, itemtype, reservesallowed, holds_per_record) + VALUES (?, ?, ?, ?, ?) + }, + {}, + '*', '*', 'TEST', 99, 99 + ); + AddReserve( $branch_1, $borrowernumbers[0], $bibnum, '', 1, ); + AddReserve( $branch_1, $borrowernumbers[0], $bibnum, '', 1, ); + AddReserve( $branch_1, $borrowernumbers[0], $bibnum, '', 1, ); + + my $count = + Koha::Holds->search( { borrowernumber => $borrowernumbers[0] } )->count(); + is( $count, 3, 'Patron now has 3 holds' ); + + my $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber ); + is( $ret, 'OK', 'Patron can place hold with no borrower circ rules' ); + + my $rule_all = Koha::CirculationRules->set_rule( + { + categorycode => $category->{categorycode}, + branchcode => undef, + itemtype => undef, + rule_name => 'max_holds', + rule_value => 3, + } + ); + + my $rule_branch = Koha::CirculationRules->set_rule( + { + branchcode => $branch_1, + categorycode => $category->{categorycode}, + itemtype => undef, + rule_name => 'max_holds', + rule_value => 5, + } + ); + + $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber ); + is( $ret, 'OK', 'Patron can place hold with branch/category rule of 5, category rule of 3' ); + + $rule_branch->delete(); + + $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber ); + is( $ret, 'tooManyReserves', 'Patron cannot place hold with only a category rule of 3' ); + + $rule_all->delete(); + $rule_branch->rule_value(3); + $rule_branch->store(); + + $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber ); + is( $ret, 'tooManyReserves', 'Patron cannot place hold with only a branch/category rule of 3' ); + + $rule_branch->rule_value(5); + $rule_branch->update(); + $rule_branch->rule_value(5); + $rule_branch->store(); + + $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber ); + is( $ret, 'OK', 'Patron can place hold with branch/category rule of 5, category rule of 5' ); +}; # Helper method to set up a Biblio. sub create_helper_biblio { --