Bugzilla – Attachment 187297 Details for
Bug 27834
CircControl syspref is used wrong in TooMany function C4::Circulation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 27834: Use new CircControlCheckoutLimitScope system preference
Bug-27834-Use-new-CircControlCheckoutLimitScope-sy.patch (text/plain), 27.14 KB, created by
Martin Renvoize (ashimema)
on 2025-10-02 15:03:20 UTC
(
hide
)
Description:
Bug 27834: Use new CircControlCheckoutLimitScope system preference
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2025-10-02 15:03:20 UTC
Size:
27.14 KB
patch
obsolete
>From cfbe93c08bfd33a8c79a85db6abcd0de8fd7f869 Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@openfifth.co.uk> >Date: Fri, 29 Aug 2025 13:55:40 +0100 >Subject: [PATCH] Bug 27834: Use new CircControlCheckoutLimitScope system > preference >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >This patch updates the TooMany function to use the new >CircControlCheckoutLimitScope system preference, providing explicit >control over how checkout limits (maxissueqty and patron_maxissueqty) >are calculated, independent of the CircControl preference. > >Previously, the TooMany function conflated two separate concerns: >1. CircControl - which circulation rules to apply >2. Checkout counting scope - which checkouts count toward limits > >This caused the checkout counting behavior to change based on CircControl, >even when libraries wanted consistent limit enforcement regardless of >which circulation rules applied. > >The new CircControlCheckoutLimitScope preference offers three options: > >* 'all' (default) - Count all patron checkouts across all libraries >* 'item' - Count only checkouts of items from the same library as the > item being checked out (follows HomeOrHoldingBranch preference) >* 'checkout' - Count only checkouts made at the same library as the > current checkout > >Implementation note: When scope is 'item', the system counts checkouts >of items from the same library as the item being checked out (using the >item's homebranch or holdingbranch). This applies regardless of whether >the matching circulation rule is branch-specific or general (branch=*), >ensuring consistent behavior across all rule types. > >This gives libraries explicit, flexible control over checkout limit scope >while maintaining CircControl's intended purpose of rule selection. > >Test plan: >1. Apply patches and update database: > perl installer/data/mysql/updatedatabase.pl > >2. Verify new preference exists: > Administration > System preferences > Circulation > Search for "CircControlCheckoutLimitScope" > Default value should be 'all' > >3. Set up test environment: > - Create two branches (Branch1, Branch2) > - Create a patron category and item type > - Create a patron in Branch1 > - Create items from both branches > - Set circulation rules for both branches: > * Branch1: maxissueqty = 1 for itemtype/category > * Branch2: maxissueqty = 1 for itemtype/category > >4. Test scope = 'checkout': > a. Set CircControlCheckoutLimitScope = 'checkout' > b. Log in as staff from Branch1 > c. Check out item from Branch1 to patron â succeeds > d. Try to check out another item from Branch1 â blocked (limit: 1) > e. Log in as staff from Branch2 > f. Check out item from Branch2 to same patron â succeeds > g. Expected: Checkouts at different libraries don't count together > >5. Test scope = 'all': > a. Set CircControlCheckoutLimitScope = 'all' > b. Return all items > c. Log in as staff from Branch1 > d. Check out item from Branch1 to patron â succeeds > e. Log in as staff from Branch2 > f. Try to check out item from Branch2 to same patron â blocked > g. Expected: All patron checkouts count toward limit regardless of location > >6. Test scope = 'item': > a. Set CircControlCheckoutLimitScope = 'item' > b. Set HomeOrHoldingBranch = 'homebranch' > c. Return all items > d. Check out item from Branch1 to patron â succeeds > e. Try to check out another item from Branch1 â blocked (limit: 1) > f. Check out item from Branch2 to same patron â succeeds > g. Expected: Only items from same home library count together > h. Note: When checking out an item, only checkouts of items from > the same library as that item count toward the limit > >7. Test scope applies to all rule types: > a. With scope='item', test with a general rule (branch=*) > b. Check out items from different branches > c. Expected: Scope still applies - only items from the same branch > as the item being checked out are counted > >8. Test independence from CircControl: > a. Test each scope with CircControl = 'PickupLibrary' > b. Test each scope with CircControl = 'ItemHomeLibrary' > c. Test each scope with CircControl = 'PatronLibrary' > d. Expected: CircControlCheckoutLimitScope behavior is consistent > regardless of CircControl setting > >9. Run tests: > prove t/db_dependent/Circulation/TooMany.t > >10. Test with patron_maxissueqty: > - Set up patron-level limits instead of item-type limits > - Verify all three scopes work correctly > - Test with both rule types active > >11. Verify existing functionality: > - Test on-site checkouts still work > - Test item type hierarchies still work > - Test unlimited ("") limits still work > - prove t/db_dependent/Circulation/ > >Sponsored-by: University of the Arts London >--- > C4/Circulation.pm | 51 ++- > .../admin/preferences/circulation.pref | 8 + > t/db_dependent/Circulation/TooMany.t | 362 +++++++++++++++++- > 3 files changed, 397 insertions(+), 24 deletions(-) > >diff --git a/C4/Circulation.pm b/C4/Circulation.pm >index 5aa42a4d25f..471da9c851c 100644 >--- a/C4/Circulation.pm >+++ b/C4/Circulation.pm >@@ -482,17 +482,23 @@ sub TooMany { > if ( defined($maxissueqty_rule) and $maxissueqty_rule->rule_value ne "" ) { > > my $checkouts; >- if ( $maxissueqty_rule->branchcode ) { >- if ( C4::Context->preference('CircControl') eq 'PickupLibrary' ) { >- $checkouts = $patron->checkouts->search( { 'me.branchcode' => $maxissueqty_rule->branchcode } ); >- } elsif ( C4::Context->preference('CircControl') eq 'PatronLibrary' ) { >- $checkouts = $patron->checkouts; # if branch is the patron's home branch, then count all loans by patron >- } else { >- my $branch_type = C4::Context->preference('HomeOrHoldingBranch') || 'homebranch'; >- $checkouts = $patron->checkouts->search( { "item.$branch_type" => $maxissueqty_rule->branchcode } ); >- } >+ my $checkout_limit_scope = C4::Context->preference('CircControlCheckoutLimitScope') || 'all'; >+ if ( $checkout_limit_scope eq 'checkout' >+ and ( C4::Context->userenv and C4::Context->userenv->{'branch'} ) ) >+ { >+ >+ # Count only checkouts made at this pickup library >+ my $pickup_branch = C4::Context->userenv->{'branch'}; >+ $checkouts = $patron->checkouts->search( { 'me.branchcode' => $pickup_branch } ); >+ } elsif ( $checkout_limit_scope eq 'item' ) { >+ >+ # Count only checkouts of items from this items library (follows HomeOrHoldingBranch) >+ my $branch_type = C4::Context->preference('HomeOrHoldingBranch') || 'homebranch'; >+ $checkouts = $patron->checkouts->search( { "item.$branch_type" => $item->$branch_type } ); > } else { >- $checkouts = $patron->checkouts; # if rule is not branch specific then count all loans by patron >+ >+ # Default 'all': count all patron checkouts across all libraries >+ $checkouts = $patron->checkouts; # if rule is not branch specific then count all loans by patron > } > $checkouts = $checkouts->search( undef, { prefetch => 'item' } ); > >@@ -590,17 +596,24 @@ sub TooMany { > and $branch_borrower_circ_rule->{patron_maxissueqty} ne '' ) > { > my $checkouts; >- if ( C4::Context->preference('CircControl') eq 'PickupLibrary' ) { >- $checkouts = $patron->checkouts->search( { 'me.branchcode' => $branch } ); >- } elsif ( C4::Context->preference('CircControl') eq 'PatronLibrary' ) { >- $checkouts = $patron->checkouts; # if branch is the patron's home branch, then count all loans by patron >- } else { >+ my $checkout_limit_scope = C4::Context->preference('CircControlCheckoutLimitScope') || 'all'; >+ if ( $checkout_limit_scope eq 'checkout' >+ and ( C4::Context->userenv and C4::Context->userenv->{'branch'} ) ) >+ { >+ # Count only checkouts made at this pickup library >+ my $pickup_branch = C4::Context->userenv->{'branch'}; >+ $checkouts = $patron->checkouts->search( { 'me.branchcode' => $pickup_branch } ); >+ } elsif ( $checkout_limit_scope eq 'item' ) { >+ >+ # Count only checkouts of items from this library (follows HomeOrHoldingBranch) > my $branch_type = C4::Context->preference('HomeOrHoldingBranch') || 'homebranch'; >- $checkouts = $patron->checkouts->search( >- { "item.$branch_type" => $branch }, >- { prefetch => 'item' } >- ); >+ $checkouts = $patron->checkouts->search( { "item.$branch_type" => $item->$branch_type } ); >+ } else { >+ >+ # Default 'all': count all patron checkouts across all libraries >+ $checkouts = $patron->checkouts; > } >+ $checkouts = $checkouts->search( undef, { prefetch => 'item' } ); > > my $checkout_count = $checkouts->count; > my $onsite_checkout_count = $checkouts->search( { onsite_checkout => 1 } )->count; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref >index 82070552d6c..580e5a8a7d5 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref >@@ -312,6 +312,14 @@ Circulation: > homebranch: the item's home library (homebranch) > holdingbranch: the item's holding library (holdingbranch) > - . >+ - >+ - Calculate total issues for maxIssue limits using >+ - pref: CircControlCheckoutLimitScope >+ type: choice >+ choices: >+ all: all patron checkouts across all libraries. >+ item: only checkouts of items from the same library as the item being checked out (follows HomeOrHoldingBranch preference). >+ checkout: only checkouts made at the same library as the current checkout. > - > - Allow items to be checked in > - pref: AllowReturnToBranch >diff --git a/t/db_dependent/Circulation/TooMany.t b/t/db_dependent/Circulation/TooMany.t >index e2105c921f2..5b5a2f95038 100755 >--- a/t/db_dependent/Circulation/TooMany.t >+++ b/t/db_dependent/Circulation/TooMany.t >@@ -16,7 +16,7 @@ > > use Modern::Perl; > use Test::NoWarnings; >-use Test::More tests => 12; >+use Test::More tests => 15; > use C4::Context; > > use C4::Members; >@@ -562,7 +562,8 @@ subtest '1 BranchBorrowerCircRule exist: 1 CO allowed, 1 OSCO allowed' => sub { > subtest 'General vs specific rules limit quantity correctly' => sub { > plan tests => 18; > >- t::lib::Mocks::mock_preference( 'CircControl', 'ItemHomeLibrary' ); >+ t::lib::Mocks::mock_preference( 'CircControl', 'ItemHomeLibrary' ); >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'item' ); > my $branch = $builder->build( { source => 'Branch', } ); > my $category = $builder->build( { source => 'Category', } ); > my $itemtype = $builder->build( >@@ -695,7 +696,8 @@ subtest 'General vs specific rules limit quantity correctly' => sub { > ); > > # If circcontrol is PatronLibrary we count all the patron's loan, regardless of branch >- t::lib::Mocks::mock_preference( 'CircControl', 'PatronLibrary' ); >+ t::lib::Mocks::mock_preference( 'CircControl', 'PatronLibrary' ); >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'all' ); > $data = C4::Circulation::TooMany( $patron, $branch_item ); > $rule = delete $data->{circulation_rule}; > is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' ); >@@ -708,7 +710,8 @@ subtest 'General vs specific rules limit quantity correctly' => sub { > }, > 'We are allowed one from the branch specifically, but have one' > ); >- t::lib::Mocks::mock_preference( 'CircControl', 'ItemHomeLibrary' ); >+ t::lib::Mocks::mock_preference( 'CircControl', 'ItemHomeLibrary' ); >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'item' ); > > $issue = C4::Circulation::AddIssue( $patron, $branch_item->barcode, dt_from_string() ); > >@@ -735,6 +738,8 @@ subtest 'General vs specific rules limit quantity correctly' => sub { > ); > > # Now we make another from a different branch >+ # Switch to 'all' scope to test general rules counting all checkouts >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'all' ); > my $item_2 = $builder->build_sample_item( > { > itype => $itemtype->{itemtype}, >@@ -794,7 +799,9 @@ subtest 'General vs specific rules limit quantity correctly' => sub { > 'We are only allowed one for general rule, and have two total (no rule for specific branch)' > ); > >- # Set a branch specific rule for new branch >+ # Set a branch specific rule for new branch and use 'checkout' scope >+ # With PickupLibrary CircControl, we want to count checkouts made at this branch >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'checkout' ); > Koha::CirculationRules->set_rules( > { > branchcode => $branch2->{branchcode}, >@@ -1225,6 +1232,351 @@ subtest 'HomeOrHoldingBranch is used' => sub { > teardown(); > }; > >+subtest 'CircControlCheckoutLimitScope system preference controls checkout counting' => sub { >+ plan tests => 12; >+ >+ t::lib::Mocks::mock_preference( 'item-level_itypes', 1 ); >+ >+ my $branch1 = $builder->build( { source => 'Branch' } ); >+ my $branch2 = $builder->build( { source => 'Branch' } ); >+ my $category = $builder->build( { source => 'Category' } ); >+ my $itemtype = $builder->build( { source => 'Itemtype', value => { notforloan => 0 } } ); >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { >+ categorycode => $category->{categorycode}, >+ branchcode => $branch1->{branchcode}, >+ } >+ } >+ ); >+ >+ # Create items from different branches >+ my $item_branch1 = $builder->build_sample_item( >+ { >+ homebranch => $branch1->{branchcode}, >+ holdingbranch => $branch1->{branchcode}, >+ itype => $itemtype->{itemtype} >+ } >+ ); >+ >+ my $item_branch2 = $builder->build_sample_item( >+ { >+ homebranch => $branch2->{branchcode}, >+ holdingbranch => $branch2->{branchcode}, >+ itype => $itemtype->{itemtype} >+ } >+ ); >+ >+ # Set circulation rules for both branches >+ Koha::CirculationRules->set_rules( >+ { >+ branchcode => $branch1->{branchcode}, >+ categorycode => $category->{categorycode}, >+ itemtype => $itemtype->{itemtype}, >+ rules => { >+ maxissueqty => 1, >+ } >+ } >+ ); >+ >+ Koha::CirculationRules->set_rules( >+ { >+ branchcode => $branch2->{branchcode}, >+ categorycode => $category->{categorycode}, >+ itemtype => $itemtype->{itemtype}, >+ rules => { >+ maxissueqty => 1, >+ } >+ } >+ ); >+ >+ # Issue an item from branch1 >+ t::lib::Mocks::mock_userenv( { branchcode => $branch1->{branchcode} } ); >+ my $issue = C4::Circulation::AddIssue( $patron, $item_branch1->barcode, dt_from_string() ); >+ ok( $issue, 'Item from branch1 issued successfully' ); >+ >+ # Test with CircControlCheckoutLimitScope = 'checkout' >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'checkout' ); >+ >+ # From branch1 - should count checkout made at branch1 >+ my $data = C4::Circulation::TooMany( $patron, $item_branch1 ); >+ ok( $data, 'TooMany should return limit exceeded when checking from same pickup library' ); >+ is( $data->{count}, 1, 'Should count checkout made at this pickup library' ); >+ is( $data->{reason}, 'TOO_MANY_CHECKOUTS', 'Correct reason returned' ); >+ >+ # From branch2 - should not count checkout made at branch1 >+ t::lib::Mocks::mock_userenv( { branchcode => $branch2->{branchcode} } ); >+ $data = C4::Circulation::TooMany( $patron, $item_branch2 ); >+ ok( !$data, 'TooMany should allow checkout when no checkouts from this pickup library' ); >+ >+ # Test with CircControlCheckoutLimitScope = 'all' >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'all' ); >+ >+ # Should count all patron checkouts regardless of pickup library >+ $data = C4::Circulation::TooMany( $patron, $item_branch2 ); >+ ok( $data, 'TooMany should return limit exceeded when counting all checkouts' ); >+ is( $data->{count}, 1, 'Should count all patron checkouts regardless of branch' ); >+ >+ # Test with CircControlCheckoutLimitScope = 'all' from branch1 >+ t::lib::Mocks::mock_userenv( { branchcode => $branch1->{branchcode} } ); >+ $data = C4::Circulation::TooMany( $patron, $item_branch2 ); >+ ok( $data, 'TooMany should return limit exceeded' ); >+ is( $data->{count}, 1, 'Should count all patron checkouts' ); >+ >+ # Test with CircControlCheckoutLimitScope = 'item' >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'item' ); >+ >+ # Item from branch2 - should not count checkout of item from branch1 >+ $data = C4::Circulation::TooMany( $patron, $item_branch2 ); >+ ok( !$data, 'TooMany should allow checkout when no items from this home library checked out' ); >+ >+ # Item from branch1 - should count checkout of item from branch1 >+ my $item_branch1_2 = $builder->build_sample_item( >+ { >+ homebranch => $branch1->{branchcode}, >+ holdingbranch => $branch1->{branchcode}, >+ itype => $itemtype->{itemtype} >+ } >+ ); >+ >+ $data = C4::Circulation::TooMany( $patron, $item_branch1_2 ); >+ ok( $data, 'TooMany should return limit exceeded when item from same home library already checked out' ); >+ is( $data->{count}, 1, 'Should count checkout of item from same home library' ); >+ >+ teardown(); >+}; >+ >+subtest 'CircControlCheckoutLimitScope with HomeOrHoldingBranch preference' => sub { >+ plan tests => 8; >+ >+ t::lib::Mocks::mock_preference( 'item-level_itypes', 1 ); >+ t::lib::Mocks::mock_preference( 'CircControl', 'ItemHomeLibrary' ); >+ >+ my $branch1 = $builder->build( { source => 'Branch' } ); >+ my $branch2 = $builder->build( { source => 'Branch' } ); >+ my $category = $builder->build( { source => 'Category' } ); >+ my $itemtype = $builder->build( { source => 'Itemtype', value => { notforloan => 0 } } ); >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { >+ categorycode => $category->{categorycode}, >+ branchcode => $branch1->{branchcode}, >+ } >+ } >+ ); >+ >+ # Create an item with different home and holding branches >+ my $item_home1_holding2 = $builder->build_sample_item( >+ { >+ homebranch => $branch1->{branchcode}, >+ holdingbranch => $branch2->{branchcode}, >+ itype => $itemtype->{itemtype} >+ } >+ ); >+ >+ my $item_home2_holding1 = $builder->build_sample_item( >+ { >+ homebranch => $branch2->{branchcode}, >+ holdingbranch => $branch1->{branchcode}, >+ itype => $itemtype->{itemtype} >+ } >+ ); >+ >+ # Set circulation rules for both branches >+ Koha::CirculationRules->set_rules( >+ { >+ branchcode => $branch1->{branchcode}, >+ categorycode => $category->{categorycode}, >+ itemtype => $itemtype->{itemtype}, >+ rules => { >+ maxissueqty => 1, >+ } >+ } >+ ); >+ >+ Koha::CirculationRules->set_rules( >+ { >+ branchcode => $branch2->{branchcode}, >+ categorycode => $category->{categorycode}, >+ itemtype => $itemtype->{itemtype}, >+ rules => { >+ maxissueqty => 1, >+ } >+ } >+ ); >+ >+ # Test with scope='item' and HomeOrHoldingBranch='homebranch' >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'item' ); >+ t::lib::Mocks::mock_preference( 'HomeOrHoldingBranch', 'homebranch' ); >+ t::lib::Mocks::mock_userenv( { branchcode => $branch1->{branchcode} } ); >+ >+ # Check out item with homebranch=branch1 >+ my $issue = C4::Circulation::AddIssue( $patron, $item_home1_holding2->barcode, dt_from_string() ); >+ ok( $issue, 'Item with homebranch=branch1 issued successfully' ); >+ >+ # Reload item to get updated holdingbranch (AddIssue may change it) >+ $item_home1_holding2->discard_changes; >+ >+ # Try to check out another item with homebranch=branch1 >+ my $item_home1_2 = $builder->build_sample_item( >+ { >+ homebranch => $branch1->{branchcode}, >+ holdingbranch => $branch1->{branchcode}, >+ itype => $itemtype->{itemtype} >+ } >+ ); >+ >+ my $data = C4::Circulation::TooMany( $patron, $item_home1_2 ); >+ ok( $data, 'TooMany should block checkout of another item from same homebranch' ); >+ is( $data->{count}, 1, 'Should count 1 checkout with same homebranch' ); >+ >+ # Try to check out item with different homebranch (branch2) >+ $data = C4::Circulation::TooMany( $patron, $item_home2_holding1 ); >+ ok( !$data, 'TooMany should allow checkout of item from different homebranch' ); >+ >+ # Now test with HomeOrHoldingBranch='holdingbranch' >+ t::lib::Mocks::mock_preference( 'HomeOrHoldingBranch', 'holdingbranch' ); >+ >+ # After checkout, the item's holdingbranch may have been updated to the checkout library >+ # Get the current holdingbranch from the checked-out item >+ my $checked_out_holdingbranch = $item_home1_holding2->holdingbranch; >+ >+ # Try to check out another item with the same holdingbranch >+ my $item_holding_same = $builder->build_sample_item( >+ { >+ homebranch => $branch2->{branchcode}, >+ holdingbranch => $checked_out_holdingbranch, >+ itype => $itemtype->{itemtype} >+ } >+ ); >+ >+ $data = C4::Circulation::TooMany( $patron, $item_holding_same ); >+ ok( $data, 'TooMany should block checkout of another item from same holdingbranch' ); >+ is( $data->{count}, 1, 'Should count 1 checkout with same holdingbranch' ); >+ >+ # Try to check out item with different holdingbranch >+ my $different_holdingbranch = >+ $checked_out_holdingbranch eq $branch1->{branchcode} ? $branch2->{branchcode} : $branch1->{branchcode}; >+ my $item_holding_different = $builder->build_sample_item( >+ { >+ homebranch => $branch1->{branchcode}, >+ holdingbranch => $different_holdingbranch, >+ itype => $itemtype->{itemtype} >+ } >+ ); >+ >+ $data = C4::Circulation::TooMany( $patron, $item_holding_different ); >+ ok( !$data, 'TooMany should allow checkout of item from different holdingbranch' ); >+ >+ # Verify that we're actually using holdingbranch not homebranch >+ # item_home1_2 has homebranch=branch1, verify its holdingbranch determines the result >+ $data = C4::Circulation::TooMany( $patron, $item_home1_2 ); >+ if ( $item_home1_2->holdingbranch eq $checked_out_holdingbranch ) { >+ ok( $data, 'Item with same holdingbranch should be blocked' ); >+ } else { >+ ok( !$data, 'Item with different holdingbranch should be allowed' ); >+ } >+ >+ teardown(); >+}; >+ >+subtest 'CircControlCheckoutLimitScope with patron_maxissueqty' => sub { >+ plan tests => 9; >+ >+ t::lib::Mocks::mock_preference( 'item-level_itypes', 1 ); >+ >+ my $branch1 = $builder->build( { source => 'Branch' } ); >+ my $branch2 = $builder->build( { source => 'Branch' } ); >+ my $category = $builder->build( { source => 'Category' } ); >+ my $itemtype = $builder->build( { source => 'Itemtype', value => { notforloan => 0 } } ); >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { >+ categorycode => $category->{categorycode}, >+ branchcode => $branch1->{branchcode}, >+ } >+ } >+ ); >+ >+ # Create items from different branches >+ my $item_branch1 = $builder->build_sample_item( >+ { >+ homebranch => $branch1->{branchcode}, >+ holdingbranch => $branch1->{branchcode}, >+ itype => $itemtype->{itemtype} >+ } >+ ); >+ >+ my $item_branch2 = $builder->build_sample_item( >+ { >+ homebranch => $branch2->{branchcode}, >+ holdingbranch => $branch2->{branchcode}, >+ itype => $itemtype->{itemtype} >+ } >+ ); >+ >+ # Set patron_maxissueqty rules for both branches >+ Koha::CirculationRules->set_rules( >+ { >+ branchcode => $branch1->{branchcode}, >+ categorycode => $category->{categorycode}, >+ rules => { >+ patron_maxissueqty => 1, >+ } >+ } >+ ); >+ >+ Koha::CirculationRules->set_rules( >+ { >+ branchcode => $branch2->{branchcode}, >+ categorycode => $category->{categorycode}, >+ rules => { >+ patron_maxissueqty => 1, >+ } >+ } >+ ); >+ >+ # Issue an item from branch1 >+ t::lib::Mocks::mock_userenv( { branchcode => $branch1->{branchcode} } ); >+ my $issue = C4::Circulation::AddIssue( $patron, $item_branch1->barcode, dt_from_string() ); >+ ok( $issue, 'Item from branch1 issued successfully' ); >+ >+ # Test with scope='all' - should count all checkouts >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'all' ); >+ my $data = C4::Circulation::TooMany( $patron, $item_branch1 ); >+ ok( $data, 'patron_maxissueqty with scope=all should count all checkouts' ); >+ is( $data->{count}, 1, 'Should count 1 checkout total' ); >+ >+ # Test with scope='item' - should count items from same branch >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'item' ); >+ $data = C4::Circulation::TooMany( $patron, $item_branch1 ); >+ ok( $data, 'patron_maxissueqty with scope=item should count items from same branch' ); >+ is( $data->{count}, 1, 'Should count 1 checkout from branch1' ); >+ >+ # Item from different branch should be allowed with scope='item' >+ $data = C4::Circulation::TooMany( $patron, $item_branch2 ); >+ ok( !$data, 'patron_maxissueqty with scope=item should allow item from different branch' ); >+ >+ # Test with scope='checkout' - should count checkouts made at same location >+ t::lib::Mocks::mock_preference( 'CircControlCheckoutLimitScope', 'checkout' ); >+ $data = C4::Circulation::TooMany( $patron, $item_branch1 ); >+ ok( $data, 'patron_maxissueqty with scope=checkout should count checkouts made here' ); >+ is( $data->{count}, 1, 'Should count 1 checkout made at branch1' ); >+ >+ # From different branch should be allowed with scope='checkout' >+ t::lib::Mocks::mock_userenv( { branchcode => $branch2->{branchcode} } ); >+ $data = C4::Circulation::TooMany( $patron, $item_branch2 ); >+ ok( !$data, 'patron_maxissueqty with scope=checkout should allow checkout from different branch' ); >+ >+ teardown(); >+}; >+ > $schema->storage->txn_rollback; > > sub teardown { >-- >2.51.0
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 27834
:
186652
|
186653
|
187296
| 187297