3 # This file is part of Koha.
5 # Koha is free software; you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 3 of the License, or (at your option) any later
10 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License along
15 # with Koha; if not, see <http://www.gnu.org/licenses>.
18 use Test::More tests => 11;
24 use C4::Circulation qw( TooMany AddIssue );
27 use Koha::DateUtils qw( dt_from_string );
29 use Koha::CirculationRules;
31 use t::lib::TestBuilder;
34 my $schema = Koha::Database->new->schema;
35 $schema->storage->txn_begin;
37 our $dbh = C4::Context->dbh;
39 $dbh->do(q|DELETE FROM issues|);
40 $dbh->do(q|DELETE FROM items|);
41 $dbh->do(q|DELETE FROM borrowers|);
42 #$dbh->do(q|DELETE FROM branches|);
43 $dbh->do(q|DELETE FROM categories|);
44 $dbh->do(q|DELETE FROM accountlines|);
45 $dbh->do(q|DELETE FROM itemtypes WHERE parent_type IS NOT NULL|);
46 $dbh->do(q|DELETE FROM itemtypes|);
47 Koha::CirculationRules->search()->delete();
49 my $builder = t::lib::TestBuilder->new();
50 t::lib::Mocks::mock_preference('item-level_itypes', 1); # Assuming the item type is defined at item level
52 my $branch = $builder->build({
56 my $branch2 = $builder->build({
60 my $category = $builder->build({
64 my $patron = $builder->build_object({
65 class => 'Koha::Patrons',
67 categorycode => $category->{categorycode},
68 branchcode => $branch->{branchcode},
72 my $biblio = $builder->build_sample_biblio({ branchcode => $branch->{branchcode} });
73 my $item = $builder->build_sample_item({
74 biblionumber => $biblio->biblionumber,
75 homebranch => $branch->{branchcode},
76 holdingbranch => $branch->{branchcode},
79 t::lib::Mocks::mock_userenv( { patron => $patron });
81 # TooMany return ($current_loan_count, $max_loans_allowed) or undef
83 # OSCO: On-site checkout
85 subtest 'no rules exist' => sub {
88 C4::Circulation::TooMany( $patron, $item ),
89 { reason => 'NO_RULE_DEFINED', max_allowed => 0 },
90 'CO should not be allowed, in any cases'
93 C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } ),
94 { reason => 'NO_RULE_DEFINED', max_allowed => 0 },
95 'OSCO should not be allowed, in any cases'
99 subtest '1 Issuingrule exist 0 0: no issue allowed' => sub {
101 Koha::CirculationRules->set_rules(
103 branchcode => $branch->{branchcode},
104 categorycode => $category->{categorycode},
108 maxonsiteissueqty => 0,
112 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 0);
114 my $data = C4::Circulation::TooMany( $patron, $item );
115 my $rule = delete $data->{circulation_rule};
116 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
120 reason => 'TOO_MANY_CHECKOUTS',
124 'CO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
126 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } ),
127 $rule = delete $data->{circulation_rule};
128 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
132 reason => 'TOO_MANY_ONSITE_CHECKOUTS',
136 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
139 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 1);
140 $data = C4::Circulation::TooMany( $patron, $item );
141 $rule = delete $data->{circulation_rule};
142 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
146 reason => 'TOO_MANY_CHECKOUTS',
150 'CO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
152 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } ),
153 $rule = delete $data->{circulation_rule};
154 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
158 reason => 'TOO_MANY_ONSITE_CHECKOUTS',
162 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
168 subtest '1 Issuingrule exist with onsiteissueqty=unlimited' => sub {
171 Koha::CirculationRules->set_rules(
173 branchcode => $branch->{branchcode},
174 categorycode => $category->{categorycode},
178 maxonsiteissueqty => undef,
183 my $issue = C4::Circulation::AddIssue( $patron, $item->barcode, dt_from_string() );
184 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 0);
185 my $data = C4::Circulation::TooMany( $patron, $item );
186 my $rule = delete $data->{circulation_rule};
187 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
191 reason => 'TOO_MANY_CHECKOUTS',
195 'CO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
197 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } );
198 $rule = delete $data->{circulation_rule};
199 is( ref $rule, '', 'No circulation rule was returned' );
203 'OSCO should be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
206 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 1);
207 $data = C4::Circulation::TooMany( $patron, $item );
208 $rule = delete $data->{circulation_rule};
209 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
213 reason => 'TOO_MANY_CHECKOUTS',
217 'CO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
219 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } );
220 $rule = delete $data->{circulation_rule};
221 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
225 reason => 'TOO_MANY_CHECKOUTS',
229 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
236 subtest '1 Issuingrule exist 1 1: issue is allowed' => sub {
238 Koha::CirculationRules->set_rules(
240 branchcode => $branch->{branchcode},
241 categorycode => $category->{categorycode},
245 maxonsiteissueqty => 1,
249 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 0);
251 C4::Circulation::TooMany( $patron, $item ),
253 'CO should be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
256 C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } ),
258 'OSCO should be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
261 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 1);
263 C4::Circulation::TooMany( $patron, $item ),
265 'CO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
268 C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } ),
270 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
276 subtest '1 Issuingrule exist: 1 CO allowed, 1 OSCO allowed. Do a CO' => sub {
278 Koha::CirculationRules->set_rules(
280 branchcode => $branch->{branchcode},
281 categorycode => $category->{categorycode},
285 maxonsiteissueqty => 1,
290 my $issue = C4::Circulation::AddIssue( $patron, $item->barcode, dt_from_string() );
291 like( $issue->issue_id, qr|^\d+$|, 'The issue should have been inserted' );
293 t::lib::Mocks::mock_preference( 'ConsiderOnSiteCheckoutsAsNormalCheckouts', 0 );
294 my $data = C4::Circulation::TooMany( $patron, $item );
295 my $rule = delete $data->{circulation_rule};
296 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
300 reason => 'TOO_MANY_CHECKOUTS',
304 'CO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
306 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } );
307 $rule = delete $data->{circulation_rule};
308 is( ref $rule, '', 'No circulation rule was returned' );
312 'OSCO should be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
315 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 1);
316 $data = C4::Circulation::TooMany( $patron, $item );
317 $rule = delete $data->{circulation_rule};
318 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
322 reason => 'TOO_MANY_CHECKOUTS',
326 'CO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
328 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } );
329 $rule = delete $data->{circulation_rule};
330 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
334 reason => 'TOO_MANY_CHECKOUTS',
338 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
344 subtest '1 Issuingrule exist: 1 CO allowed, 1 OSCO allowed, Do a OSCO' => sub {
346 Koha::CirculationRules->set_rules(
348 branchcode => $branch->{branchcode},
349 categorycode => $category->{categorycode},
353 maxonsiteissueqty => 1,
358 my $issue = C4::Circulation::AddIssue( $patron, $item->barcode, dt_from_string(), undef, undef, undef, { onsite_checkout => 1 } );
359 like( $issue->issue_id, qr|^\d+$|, 'The issue should have been inserted' );
361 t::lib::Mocks::mock_preference( 'ConsiderOnSiteCheckoutsAsNormalCheckouts', 0 );
363 C4::Circulation::TooMany( $patron, $item ),
365 'CO should be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
367 my $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } );
368 my $rule = delete $data->{circulation_rule};
369 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
373 reason => 'TOO_MANY_ONSITE_CHECKOUTS',
377 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
380 t::lib::Mocks::mock_preference( 'ConsiderOnSiteCheckoutsAsNormalCheckouts', 1 );
381 $data = C4::Circulation::TooMany( $patron, $item );
382 $rule = delete $data->{circulation_rule};
383 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
387 reason => 'TOO_MANY_CHECKOUTS',
391 'CO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
393 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } );
394 $rule = delete $data->{circulation_rule};
395 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
399 reason => 'TOO_MANY_ONSITE_CHECKOUTS',
403 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
409 subtest '1 BranchBorrowerCircRule exist: 1 CO allowed, 1 OSCO allowed' => sub {
410 # Note: the same test coul be done for
411 # DefaultBorrowerCircRule, DefaultBranchCircRule, DefaultBranchItemRule ans DefaultCircRule.pm
414 Koha::CirculationRules->set_rules(
416 branchcode => $branch->{branchcode},
417 categorycode => $category->{categorycode},
421 maxonsiteissueqty => 1,
426 my $issue = C4::Circulation::AddIssue( $patron, $item->barcode, dt_from_string(), undef, undef, undef );
427 like( $issue->issue_id, qr|^\d+$|, 'The issue should have been inserted' );
429 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 0);
430 my $data = C4::Circulation::TooMany( $patron, $item );
431 my $rule = delete $data->{circulation_rule};
432 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
436 reason => 'TOO_MANY_CHECKOUTS',
440 'CO should be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
442 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } ),
443 $rule = delete $data->{circulation_rule};
444 is( ref $rule, '', 'No circulation rule was returned' );
448 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
451 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 1);
452 $data = C4::Circulation::TooMany( $patron, $item );
453 $rule = delete $data->{circulation_rule};
454 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
458 reason => 'TOO_MANY_CHECKOUTS',
462 'CO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
464 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } ),
465 $rule = delete $data->{circulation_rule};
466 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
470 reason => 'TOO_MANY_CHECKOUTS',
474 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
478 Koha::CirculationRules->set_rules(
480 branchcode => $branch->{branchcode},
481 categorycode => $category->{categorycode},
485 maxonsiteissueqty => 1,
490 $issue = C4::Circulation::AddIssue( $patron, $item->barcode, dt_from_string(), undef, undef, undef, { onsite_checkout => 1 } );
491 like( $issue->issue_id, qr|^\d+$|, 'The issue should have been inserted' );
493 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 0);
494 $data = C4::Circulation::TooMany( $patron, $item );
495 $rule = delete $data->{circulation_rule};
496 is( ref $rule, '', 'No circulation rule was returned' );
500 'CO should be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
502 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } ),
503 $rule = delete $data->{circulation_rule};
504 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
508 reason => 'TOO_MANY_ONSITE_CHECKOUTS',
512 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 0'
515 t::lib::Mocks::mock_preference('ConsiderOnSiteCheckoutsAsNormalCheckouts', 1);
516 $data = C4::Circulation::TooMany( $patron, $item );
517 $rule = delete $data->{circulation_rule};
518 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
522 reason => 'TOO_MANY_CHECKOUTS',
526 'CO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
528 $data = C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } ),
529 $rule = delete $data->{circulation_rule};
530 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
534 reason => 'TOO_MANY_ONSITE_CHECKOUTS',
538 'OSCO should not be allowed if ConsiderOnSiteCheckoutsAsNormalCheckouts == 1'
544 subtest 'General vs specific rules limit quantity correctly' => sub {
547 t::lib::Mocks::mock_preference('CircControl', 'ItemHomeLibrary');
548 my $branch = $builder->build({source => 'Branch',});
549 my $category = $builder->build({source => 'Category',});
550 my $itemtype = $builder->build({
551 source => 'Itemtype',
554 rentalcharge_daily => 0,
555 rentalcharge_hourly => 0,
559 my $patron = $builder->build_object({
560 class => 'Koha::Patrons',
562 categorycode => $category->{categorycode},
563 branchcode => $branch->{branchcode},
567 # Set up an issuing rule
568 Koha::CirculationRules->set_rules(
571 itemtype => $itemtype->{itemtype},
575 firstremind => 1, # 1 day of grace
576 finedays => 2, # 2 days of fine per day of overdue
577 lengthunit => 'days',
582 # Set default maximum issue quantity limits for branch
583 Koha::CirculationRules->set_rules(
585 branchcode => $branch->{branchcode},
588 patron_maxissueqty => 1,
589 patron_maxonsiteissueqty => 1,
594 # Set an All->All for an itemtype
595 Koha::CirculationRules->set_rules(
599 itemtype => $itemtype->{itemtype},
602 maxonsiteissueqty => 1,
608 my $issue_item = $builder->build_sample_item({
609 itype => $itemtype->{itemtype}
611 my $branch_item = $builder->build_sample_item({
612 itype => $itemtype->{itemtype},
613 homebranch => $branch->{branchcode},
614 holdingbranch => $branch->{branchcode}
618 t::lib::Mocks::mock_userenv({ branchcode => $branch->{branchcode} });
619 my $issue = C4::Circulation::AddIssue( $patron, $issue_item->barcode, dt_from_string() );
620 # We checkout one item
621 my $data = C4::Circulation::TooMany( $patron, $branch_item );
622 my $rule = delete $data->{circulation_rule};
623 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
627 reason => 'TOO_MANY_CHECKOUTS',
631 'We are only allowed one, and we have one (itemtype on item)'
634 # Check itemtype on biblio level
635 t::lib::Mocks::mock_preference('item-level_itypes', 0);
636 $issue_item->biblio->biblioitem->itemtype($itemtype->{itemtype})->store;
637 $branch_item->biblio->biblioitem->itemtype($itemtype->{itemtype})->store;
638 # We checkout one item
639 $data = C4::Circulation::TooMany( $patron, $branch_item );
640 $rule = delete $data->{circulation_rule};
641 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
645 reason => 'TOO_MANY_CHECKOUTS',
649 'We are only allowed one, and we have one (itemtype on biblioitem)'
651 t::lib::Mocks::mock_preference('item-level_itypes', 1);
653 # Set a branch specific rule
654 Koha::CirculationRules->set_rules(
656 branchcode => $branch->{branchcode},
657 categorycode => $category->{categorycode},
658 itemtype => $itemtype->{itemtype},
661 maxonsiteissueqty => 1,
666 t::lib::Mocks::mock_preference('HomeOrHoldingBranch', 'homebranch');
669 C4::Circulation::TooMany( $patron, $branch_item ),
671 'We are allowed one from the branch specifically now'
674 # If circcontrol is PatronLibrary we count all the patron's loan, regardless of branch
675 t::lib::Mocks::mock_preference('CircControl', 'PatronLibrary');
676 $data = C4::Circulation::TooMany( $patron, $branch_item );
677 $rule = delete $data->{circulation_rule};
678 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
682 reason => 'TOO_MANY_CHECKOUTS',
686 'We are allowed one from the branch specifically, but have one'
688 t::lib::Mocks::mock_preference('CircControl', 'ItemHomeLibrary');
690 $issue = C4::Circulation::AddIssue( $patron, $branch_item->barcode, dt_from_string() );
693 my $branch_item_2 = $builder->build_sample_item({
694 itype => $itemtype->{itemtype},
695 homebranch => $branch->{branchcode},
696 holdingbranch => $branch->{branchcode}
698 $data = C4::Circulation::TooMany( $patron, $branch_item_2 );
699 $rule = delete $data->{circulation_rule};
700 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
704 reason => 'TOO_MANY_CHECKOUTS',
708 'We are only allowed one from that branch, and have one'
711 # Now we make anothe from a different branch
712 my $item_2 = $builder->build_sample_item({
713 itype => $itemtype->{itemtype},
715 $data = C4::Circulation::TooMany( $patron, $item_2 );
716 $rule = delete $data->{circulation_rule};
717 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
721 reason => 'TOO_MANY_CHECKOUTS',
725 'We are only allowed one for general rule, and have two'
727 t::lib::Mocks::mock_preference('CircControl', 'PatronLibrary');
728 $data = C4::Circulation::TooMany( $patron, $item_2 );
729 $rule = delete $data->{circulation_rule};
730 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
734 reason => 'TOO_MANY_CHECKOUTS',
738 'We are only allowed one for general rule, and have two'
741 t::lib::Mocks::mock_preference('CircControl', 'PickupLibrary');
742 $data = C4::Circulation::TooMany( $patron, $item_2 );
743 $rule = delete $data->{circulation_rule};
744 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
748 reason => 'TOO_MANY_CHECKOUTS',
752 'We are only allowed one for general rule, and have checked out two at this branch'
755 t::lib::Mocks::mock_userenv({ branchcode => $branch2->{branchcode} });
756 $data = C4::Circulation::TooMany( $patron, $item_2 );
757 $rule = delete $data->{circulation_rule};
758 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
762 reason => 'TOO_MANY_CHECKOUTS',
766 'We are only allowed one for general rule, and have two total (no rule for specific branch)'
768 # Set a branch specific rule for new branch
769 Koha::CirculationRules->set_rules(
771 branchcode => $branch2->{branchcode},
772 categorycode => $category->{categorycode},
773 itemtype => $itemtype->{itemtype},
776 maxonsiteissueqty => 1,
782 C4::Circulation::TooMany( $patron, $branch_item ),
784 'We are allowed one from the branch specifically now'
788 subtest 'empty string means unlimited' => sub {
791 Koha::CirculationRules->set_rules(
798 maxonsiteissueqty => '',
803 C4::Circulation::TooMany( $patron, $item ),
805 'maxissueqty="" should mean unlimited'
809 C4::Circulation::TooMany( $patron, $item, { onsite_checkout => 1 } ),
811 'maxonsiteissueqty="" should mean unlimited'
815 subtest 'itemtype group tests' => sub {
818 t::lib::Mocks::mock_preference( 'CircControl', 'ItemHomeLibrary' );
819 Koha::CirculationRules->set_rules(
826 maxonsiteissueqty => '',
828 firstremind => 1, # 1 day of grace
829 finedays => 2, # 2 days of fine per day of overdue
830 lengthunit => 'days',
835 my $parent_itype = $builder->build(
837 source => 'Itemtype',
839 parent_type => undef,
840 rentalcharge => undef,
841 rentalcharge_daily => undef,
842 rentalcharge_hourly => undef,
847 my $child_itype_1 = $builder->build(
849 source => 'Itemtype',
851 parent_type => $parent_itype->{itemtype},
853 rentalcharge_daily => 0,
854 rentalcharge_hourly => 0,
859 my $child_itype_2 = $builder->build(
861 source => 'Itemtype',
863 parent_type => $parent_itype->{itemtype},
865 rentalcharge_daily => 0,
866 rentalcharge_hourly => 0,
872 my $branch = $builder->build( { source => 'Branch', } );
873 my $category = $builder->build( { source => 'Category', } );
874 my $patron = $builder->build_object(
876 class => 'Koha::Patrons',
878 categorycode => $category->{categorycode},
879 branchcode => $branch->{branchcode},
883 my $item = $builder->build_sample_item(
885 homebranch => $branch->{branchcode},
886 holdingbranch => $branch->{branchcode},
887 itype => $child_itype_1->{itemtype}
890 my $checkout_item = $builder->build_sample_item(
892 homebranch => $branch->{branchcode},
893 holdingbranch => $branch->{branchcode},
894 itype => $parent_itype->{itemtype}
898 my $all_iq_rule = $builder->build_object(
900 class => 'Koha::CirculationRules',
902 branchcode => $branch->{branchcode},
903 categorycode => $category->{categorycode},
905 rule_name => 'maxissueqty',
910 is( C4::Circulation::TooMany( $patron, $item ),
911 undef, 'Checkout allowed, using all rule of 1' );
914 my $issue = C4::Circulation::AddIssue( $patron, $checkout_item->barcode, dt_from_string() );
915 like( $issue->issue_id, qr|^\d+$|, 'The issue should have been inserted' );
917 #Patron has 1 checkout of parent itemtype {{{{ child itype1
919 my $parent_iq_rule = $builder->build_object(
921 class => 'Koha::CirculationRules',
923 branchcode => $branch->{branchcode},
924 categorycode => $category->{categorycode},
925 itemtype => $parent_itype->{itemtype},
926 rule_name => 'maxissueqty',
933 C4::Circulation::TooMany( $patron, $item ),
934 undef, 'Checkout allowed, using parent type rule of 2'
937 $all_iq_rule->rule_value(5)->store;
938 $parent_iq_rule->rule_value(1)->store;
940 my $data = C4::Circulation::TooMany( $patron, $item );
941 my $rule = delete $data->{circulation_rule};
942 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
946 reason => 'TOO_MANY_CHECKOUTS',
950 'Checkout not allowed, using parent type rule of 1'
953 $parent_iq_rule->rule_value(2)->store;
956 C4::Circulation::TooMany( $patron, $item ),
957 undef, 'Checkout allowed, using specific type of 1 and only parent type checked out'
960 $checkout_item->itype( $child_itype_1->{itemtype} )->store;
962 my $child1_iq_rule = $builder->build_object(
964 class => 'Koha::CirculationRules',
966 branchcode => $branch->{branchcode},
967 categorycode => $category->{categorycode},
968 itemtype => $child_itype_1->{itemtype},
969 rule_name => 'maxissueqty',
975 $data = C4::Circulation::TooMany( $patron, $item );
976 $rule = delete $data->{circulation_rule};
977 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
981 reason => 'TOO_MANY_CHECKOUTS',
985 'Checkout not allowed, using specific type rule of 1'
988 my $item_1 = $builder->build_sample_item(
990 homebranch => $branch->{branchcode},
991 holdingbranch => $branch->{branchcode},
992 itype => $child_itype_2->{itemtype}
996 my $child2_iq_rule = $builder->build(
998 source => 'CirculationRule',
1000 branchcode => $branch->{branchcode},
1001 categorycode => $category->{categorycode},
1002 itemtype => $child_itype_2->{itemtype},
1003 rule_name => 'maxissueqty',
1009 is( C4::Circulation::TooMany( $patron, $item_1 ),
1010 undef, 'Checkout allowed' );
1014 C4::Circulation::AddIssue( $patron, $item_1->barcode, dt_from_string() );
1015 like( $issue->issue_id, qr|^\d+$|, 'the issue should have been inserted' );
1017 #patron has 1 checkout of childitype1 and 1 checkout of childitype2
1019 $data = C4::Circulation::TooMany( $patron, $item );
1020 $rule = delete $data->{circulation_rule};
1021 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
1025 reason => 'TOO_MANY_CHECKOUTS',
1029 'Checkout not allowed, using parent type rule of 2, checkout of sibling itemtype counted'
1032 my $parent_item = $builder->build_sample_item(
1034 homebranch => $branch->{branchcode},
1035 holdingbranch => $branch->{branchcode},
1036 itype => $parent_itype->{itemtype}
1040 $data = C4::Circulation::TooMany( $patron, $parent_item );
1041 $rule = delete $data->{circulation_rule};
1042 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
1046 reason => 'TOO_MANY_CHECKOUTS',
1050 'Checkout not allowed, using parent type rule of 2, checkout of child itemtypes counted'
1053 #increase parent type to greater than specific
1054 # my $circ_rule_object =
1055 # Koha::CirculationRules->find( $parent_iq_rule->{id} );
1056 # $circ_rule_object->rule_value(4)->store();
1057 $parent_iq_rule->rule_value(4)->store();
1060 is( C4::Circulation::TooMany( $patron, $item_1 ),
1061 undef, 'Checkout allowed, using specific type rule of 3' );
1063 my $item_2 = $builder->build_sample_item(
1065 homebranch => $branch->{branchcode},
1066 holdingbranch => $branch->{branchcode},
1067 itype => $child_itype_2->{itemtype}
1073 C4::Circulation::AddIssue( $patron, $item_2->barcode, dt_from_string(),
1074 undef, undef, undef );
1075 like( $issue->issue_id, qr|^\d+$|, 'the issue should have been inserted' );
1077 #patron has 1 checkout of childitype1 and 2 of childitype2
1080 C4::Circulation::TooMany( $patron, $item_2 ),
1082 'Checkout allowed, using specific type rule of 3, checkout of sibling itemtype not counted'
1085 $child1_iq_rule->rule_value(2)->store(); #Allow 2 checkouts for child type 1
1087 my $item_3 = $builder->build_sample_item(
1089 homebranch => $branch->{branchcode},
1090 holdingbranch => $branch->{branchcode},
1091 itype => $child_itype_1->{itemtype}
1094 my $item_4 = $builder->build_sample_item(
1096 homebranch => $branch->{branchcode},
1097 holdingbranch => $branch->{branchcode},
1098 itype => $child_itype_2->{itemtype}
1104 C4::Circulation::AddIssue( $patron, $item_4->barcode, dt_from_string(),
1105 undef, undef, undef );
1106 like( $issue->issue_id, qr|^\d+$|, 'the issue should have been inserted' );
1108 #patron has 1 checkout of childitype 1 and 3 of childitype2
1110 $data = C4::Circulation::TooMany( $patron, $item_3 );
1111 $rule = delete $data->{circulation_rule};
1112 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
1116 reason => 'TOO_MANY_CHECKOUTS',
1120 'Checkout not allowed, using specific type rule of 2, checkout of sibling itemtype not counted, but parent rule (4) prevents another'
1126 subtest 'HomeOrHoldingBranch is used' => sub {
1129 t::lib::Mocks::mock_preference( 'CircControl', 'ItemHomeLibrary' );
1131 my $item_1 = $builder->build_sample_item(
1133 homebranch => $branch->{branchcode},
1134 holdingbranch => $branch2->{branchcode},
1138 Koha::CirculationRules->set_rules(
1140 branchcode => $branch->{branchcode},
1141 categorycode => undef,
1149 Koha::CirculationRules->set_rules(
1151 branchcode => $branch2->{branchcode},
1152 categorycode => undef,
1160 t::lib::Mocks::mock_userenv({ branchcode => $branch2->{branchcode} });
1161 my $issue = C4::Circulation::AddIssue( $patron, $item_1->barcode, dt_from_string() );
1163 t::lib::Mocks::mock_preference('HomeOrHoldingBranch', 'homebranch');
1165 my $data = C4::Circulation::TooMany( $patron, $item_1 );
1166 my $rule = delete $data->{circulation_rule};
1167 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
1171 reason => 'TOO_MANY_CHECKOUTS',
1175 'We are allowed zero issues from the homebranch specifically'
1178 t::lib::Mocks::mock_preference('HomeOrHoldingBranch', 'holdingbranch');
1180 $data = C4::Circulation::TooMany( $patron, $item_1 );
1181 $rule = delete $data->{circulation_rule};
1182 is( ref $rule, 'Koha::CirculationRule', 'Circulation rule was returned' );
1186 reason => 'TOO_MANY_CHECKOUTS',
1190 'We are allowed one issue from the holdingbranch specifically'
1196 $schema->storage->txn_rollback;
1199 $dbh->do(q|DELETE FROM issues|);
1200 $dbh->do(q|DELETE FROM circulation_rules|);