View | Details | Raw Unified | Return to bug 23732
Collapse All | Expand All

(-)a/C4/Reserves.pm (-60 / +184 lines)
Lines 370-388 sub CanBookBeReserved{ Link Here
370
        return { status =>'alreadypossession' };
370
        return { status =>'alreadypossession' };
371
    }
371
    }
372
372
373
    my @circulation_rules;
374
373
    if ( $params->{itemtype} ) {
375
    if ( $params->{itemtype} ) {
374
376
375
        # biblio-level, item type-contrained
377
        # biblio-level, item type-contrained
376
        my $patron          = Koha::Patrons->find($borrowernumber);
378
        my $patron          = Koha::Patrons->find($borrowernumber);
377
        my $reservesallowed = Koha::CirculationRules->get_effective_rule(
379
        my $reservesallowed_rule = Koha::CirculationRules->get_effective_rule(
378
            {
380
            {
379
                itemtype     => $params->{itemtype},
381
                itemtype     => $params->{itemtype},
380
                categorycode => $patron->categorycode,
382
                categorycode => $patron->categorycode,
381
                branchcode   => $pickup_branchcode,
383
                branchcode   => $pickup_branchcode,
382
                rule_name    => 'reservesallowed',
384
                rule_name    => 'reservesallowed',
383
            }
385
            }
384
        )->rule_value;
386
        );
387
        push @circulation_rules, $reservesallowed_rule if $reservesallowed_rule;
385
388
389
        my $reservesallowed = $reservesallowed_rule ? $reservesallowed_rule->rule_value : undef;
386
        $reservesallowed = ( $reservesallowed eq '' ) ? undef : $reservesallowed;
390
        $reservesallowed = ( $reservesallowed eq '' ) ? undef : $reservesallowed;
387
391
388
        my $count = $patron->holds->search(
392
        my $count = $patron->holds->search(
Lines 397-403 sub CanBookBeReserved{ Link Here
397
            }
401
            }
398
        )->count;
402
        )->count;
399
403
400
        return { status => '' }
404
        return { status => '', circulation_rules => \@circulation_rules }
401
          if defined $reservesallowed and $reservesallowed < $count + 1;
405
          if defined $reservesallowed and $reservesallowed < $count + 1;
402
    }
406
    }
403
407
Lines 415-450 sub CanBookBeReserved{ Link Here
415
        $items = Koha::Items->search({ biblionumber => $biblionumber});
419
        $items = Koha::Items->search({ biblionumber => $biblionumber});
416
    }
420
    }
417
421
418
    my $canReserve = { status => '' };
422
    my $response = { status => '', item_responses => [] };
419
    my $patron = Koha::Patrons->find( $borrowernumber );
423
    my $patron = Koha::Patrons->find( $borrowernumber );
420
    while ( my $item = $items->next ) {
424
    while ( my $item = $items->next ) {
421
        $canReserve = CanItemBeReserved( $patron, $item, $pickup_branchcode, $params );
425
        my $itemResponse = CanItemBeReserved( $patron, $item, $pickup_branchcode, $params );
422
        return { status => 'OK' } if $canReserve->{status} eq 'OK';
426
        push @{ $response->{item_responses} }, { %$itemResponse, item => $item };
427
428
        if ($itemResponse->{status} eq 'OK') {
429
            $response->{status} = 'OK';
430
431
            return $response;
432
        }
423
    }
433
    }
424
    return $canReserve;
434
435
    return $response;
425
}
436
}
426
437
427
=head2 CanItemBeReserved
438
=head2 CanItemBeReserved
428
439
429
  $canReserve = &CanItemBeReserved($patron, $item, $branchcode, $params)
440
  $canReserve = CanItemBeReserved($patron, $item, $branchcode, $params)
430
  if ($canReserve->{status} eq 'OK') { #We can reserve this Item! }
441
  if ($canReserve->{status} eq 'OK') { #We can reserve this Item! }
431
442
432
  current params are:
443
Current params are:
433
  'ignore_hold_counts' - we use this routine to check if an item can fill a hold - on this case we
444
434
  should not check if there are too many holds as we only care about reservability
445
=over
435
446
436
@RETURNS { status => OK },              if the Item can be reserved.
447
=item * C<ignore_hold_counts>
437
         { status => ageRestricted },   if the Item is age restricted for this borrower.
448
438
         { status => damaged },         if the Item is damaged.
449
we use this routine to check if an item can
439
         { status => cannotReserveFromOtherBranches }, if syspref 'canreservefromotherbranches' is OK.
450
fill a hold - on this case we should not check if there are too many holds as
440
         { status => branchNotInHoldGroup }, if borrower home library is not in hold group, and holds are only allowed from hold groups.
451
we only care about reservability
441
         { status => tooManyReserves, limit => $limit }, if the borrower has exceeded their maximum reserve amount.
452
442
         { status => notReservable },   if holds on this item are not allowed
453
=back
443
         { status => libraryNotFound },   if given branchcode is not an existing library
454
444
         { status => libraryNotPickupLocation },   if given branchcode is not configured to be a pickup location
455
Returns a hashref with the following keys:
445
         { status => cannotBeTransferred }, if branch transfer limit applies on given item and branchcode
456
446
         { status => pickupNotInHoldGroup }, pickup location is not in hold group, and pickup locations are only allowed from hold groups.
457
=over
447
         { status => recall }, if the borrower has already placed a recall on this item
458
459
=item * C<status>
460
461
A string that can have the following values:
462
463
=over
464
465
=item * C<OK> if the item can be reserved
466
467
=item * C<ageRestricted> if the item is aged restricted for this borrower
468
469
=item * C<damaged> if the item is damaged
470
471
=item * C<cannotReserveFromOtherBranches> if syspref
472
'canreservefromotherbranches' is OK
473
474
=item * C<branchNotInHoldGroup> if borrower home library is not in hold group,
475
and holds are only allowed from hold groups.
476
477
=item * C<tooManyReserves> if the borrower has exceeded their maximum reserve
478
amount.
479
480
=item * C<tooManyHoldsForThisRecord> if the borrower has exceeded their maximum
481
reserve amount for this biblio record
482
483
=item * C<tooManyReservesToday> if the borrower has exceeded their maximum
484
reserve amount for today
485
486
=item * C<notReservable> if holds on this item are not allowed
487
488
=item * C<libraryNotFound> if given branchcode is not an existing library
489
490
=item * C<libraryNotPickupLocation> if given branchcode is not configured to be
491
a pickup location
492
493
=item * C<cannotBeTransferred> if branch transfer limit applies on given item
494
and branchcode
495
496
=item * C<pickupNotInHoldGroup> if pickup location is not in hold group, and
497
pickup locations are only allowed from hold groups.
498
499
=item * C<recall> if the borrower has already placed a recall on this item
500
501
=back
502
503
=item * C<limit>
504
505
Only if C<status> is equal to C<tooManyReserves>, C<tooManyHoldsForThisRecord>,
506
or C<tooManyReservesToday>.
507
508
It contains the number of reserves allowed.
509
510
=item * C<circulation_rules>
511
512
An arrayref containing all circulations rules (L<Koha::CirculationRule>) that
513
have been checked
514
515
=back
448
516
449
=cut
517
=cut
450
518
Lines 467-474 sub CanItemBeReserved { Link Here
467
    }
535
    }
468
536
469
    my $dbh = C4::Context->dbh;
537
    my $dbh = C4::Context->dbh;
470
    my $ruleitemtype;    # itemtype of the matching issuing rule
471
    my $allowedreserves  = 0; # Total number of holds allowed across all records, default to none
472
538
473
    # We check item branch if IndependentBranches is ON
539
    # We check item branch if IndependentBranches is ON
474
    # and canreservefromotherbranches is OFF
540
    # and canreservefromotherbranches is OFF
Lines 520-553 sub CanItemBeReserved { Link Here
520
        $reserves_control_branch  = $patron->branchcode;
586
        $reserves_control_branch  = $patron->branchcode;
521
    }
587
    }
522
588
523
    # we retrieve rights
589
    my @circulation_rules;
524
    if (
525
        my $reservesallowed = Koha::CirculationRules->get_effective_rule({
526
                itemtype     => $item->effective_itemtype,
527
                categorycode => $patron->categorycode,
528
                branchcode   => $reserves_control_branch,
529
                rule_name    => 'reservesallowed',
530
        })
531
    ) {
532
        $ruleitemtype     = $reservesallowed->itemtype;
533
        $allowedreserves  = $reservesallowed->rule_value // 0; #undefined is 0, blank is unlimited
534
    }
535
    else {
536
        $ruleitemtype = undef;
537
    }
538
590
539
    my $rights = Koha::CirculationRules->get_effective_rules({
591
    my $holds_per_record_rule = Koha::CirculationRules->get_effective_rule({
540
        categorycode => $patron->categorycode,
592
        categorycode => $patron->categorycode,
541
        itemtype     => $item->effective_itemtype,
593
        itemtype     => $item->effective_itemtype,
542
        branchcode   => $reserves_control_branch,
594
        branchcode   => $reserves_control_branch,
543
        rules        => ['holds_per_record','holds_per_day']
595
        rule_name    => 'holds_per_record',
544
    });
596
    });
545
    my $holds_per_record = $rights->{holds_per_record} // 1;
597
    push @circulation_rules, $holds_per_record_rule if $holds_per_record_rule;
546
    my $holds_per_day    = $rights->{holds_per_day};
598
599
    my $holds_per_record = $holds_per_record_rule ? $holds_per_record_rule->rule_value : 1;
547
600
548
    if (   defined $holds_per_record && $holds_per_record ne '' ){
601
    if (   defined $holds_per_record && $holds_per_record ne '' ){
549
        if ( $holds_per_record == 0 ) {
602
        if ( $holds_per_record == 0 ) {
550
            return _cache { status => "noReservesAllowed" };
603
            return _cache { status => "noReservesAllowed", circulation_rules => \@circulation_rules };
551
        }
604
        }
552
        if ( !$params->{ignore_hold_counts} ) {
605
        if ( !$params->{ignore_hold_counts} ) {
553
            my $search_params = {
606
            my $search_params = {
Lines 555-578 sub CanItemBeReserved { Link Here
555
                biblionumber   => $item->biblionumber,
608
                biblionumber   => $item->biblionumber,
556
            };
609
            };
557
            my $holds = Koha::Holds->search($search_params);
610
            my $holds = Koha::Holds->search($search_params);
558
            return _cache { status => "tooManyHoldsForThisRecord", limit => $holds_per_record } if $holds->count() >= $holds_per_record;
611
612
            if ($holds->count() >= $holds_per_record) {
613
                return _cache {
614
                    status => "tooManyHoldsForThisRecord",
615
                    limit  => $holds_per_record,
616
                    circulation_rules => \@circulation_rules,
617
                };
618
            }
559
        }
619
        }
560
    }
620
    }
561
621
622
    my $holds_per_day_rule = Koha::CirculationRules->get_effective_rule({
623
        categorycode => $patron->categorycode,
624
        itemtype     => $item->effective_itemtype,
625
        branchcode   => $reserves_control_branch,
626
        rule_name    => 'holds_per_day',
627
    });
628
    push @circulation_rules, $holds_per_day_rule if $holds_per_day_rule;
629
630
    my $holds_per_day = $holds_per_day_rule ? $holds_per_day_rule->rule_value : undef;
562
    if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne '')
631
    if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne '')
563
    {
632
    {
564
        my $today_holds = Koha::Holds->search({
633
        my $today_holds = Koha::Holds->search({
565
            borrowernumber => $patron->borrowernumber,
634
            borrowernumber => $patron->borrowernumber,
566
            reservedate    => dt_from_string->date
635
            reservedate    => dt_from_string->date
567
        });
636
        });
568
        return _cache { status => 'tooManyReservesToday', limit => $holds_per_day } if $today_holds->count() >= $holds_per_day;
637
638
        if ($today_holds->count() >= $holds_per_day) {
639
            return _cache {
640
                status => 'tooManyReservesToday',
641
                limit  => $holds_per_day,
642
                circulation_rules => \@circulation_rules,
643
            };
644
        }
645
    }
646
647
    my $reservesallowed_rule = Koha::CirculationRules->get_effective_rule({
648
        itemtype     => $item->effective_itemtype,
649
        categorycode => $patron->categorycode,
650
        branchcode   => $reserves_control_branch,
651
        rule_name    => 'reservesallowed',
652
    });
653
    push @circulation_rules, $reservesallowed_rule if $reservesallowed_rule;
654
655
    my $ruleitemtype;    # itemtype of the matching issuing rule
656
    my $allowedreserves  = 0; # Total number of holds allowed across all records, default to none
657
    if ($reservesallowed_rule) {
658
        $ruleitemtype     = $reservesallowed_rule->itemtype;
659
        $allowedreserves  = $reservesallowed_rule->rule_value // 0; #undefined is 0, blank is unlimited
569
    }
660
    }
570
661
571
    # we check if it's ok or not
662
    # we check if it's ok or not
572
    if ( defined $allowedreserves && $allowedreserves ne '' ){
663
    if ( defined $allowedreserves && $allowedreserves ne '' ){
573
        if( $allowedreserves == 0 ){
664
        if ( $allowedreserves == 0 ) {
574
            return _cache { status => 'noReservesAllowed' };
665
            return _cache {
666
                status            => 'noReservesAllowed',
667
                circulation_rules => \@circulation_rules,
668
            };
575
        }
669
        }
670
576
        if ( !$params->{ignore_hold_counts} ) {
671
        if ( !$params->{ignore_hold_counts} ) {
577
            # we retrieve count
672
            # we retrieve count
578
            my $querycount = q{
673
            my $querycount = q{
Lines 616-660 sub CanItemBeReserved { Link Here
616
                $reservecount = $rowcount->{count};
711
                $reservecount = $rowcount->{count};
617
            }
712
            }
618
713
619
            return _cache { status => 'tooManyReserves', limit => $allowedreserves } if $reservecount >= $allowedreserves;
714
            if ($reservecount >= $allowedreserves) {
715
                return _cache {
716
                    status => 'tooManyReserves',
717
                    limit  => $allowedreserves,
718
                    circulation_rules => \@circulation_rules,
719
                };
720
            }
620
        }
721
        }
621
    }
722
    }
622
723
623
    # Now we need to check hold limits by patron category
724
    # Now we need to check hold limits by patron category
624
    my $rule = Koha::CirculationRules->get_effective_rule(
725
    my $max_holds_rule = Koha::CirculationRules->get_effective_rule(
625
        {
726
        {
626
            categorycode => $patron->categorycode,
727
            categorycode => $patron->categorycode,
627
            branchcode   => $reserves_control_branch,
728
            branchcode   => $reserves_control_branch,
628
            rule_name    => 'max_holds',
729
            rule_name    => 'max_holds',
629
        }
730
        }
630
    );
731
    );
631
    if (!$params->{ignore_hold_counts} && $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
732
    push @circulation_rules, $max_holds_rule if $max_holds_rule;
733
734
    if (!$params->{ignore_hold_counts} && $max_holds_rule && defined( $max_holds_rule->rule_value ) && $max_holds_rule->rule_value ne '' ) {
632
        my $total_holds_count = Koha::Holds->search(
735
        my $total_holds_count = Koha::Holds->search(
633
            {
736
            {
634
                borrowernumber => $patron->borrowernumber
737
                borrowernumber => $patron->borrowernumber
635
            }
738
            }
636
        )->count();
739
        )->count();
637
740
638
        return _cache { status => 'tooManyReserves', limit => $rule->rule_value} if $total_holds_count >= $rule->rule_value;
741
        if ($total_holds_count >= $max_holds_rule->rule_value) {
742
            return _cache {
743
                status => 'tooManyReserves',
744
                limit => $max_holds_rule->rule_value,
745
                circulation_rules => \@circulation_rules,
746
            };
747
        }
639
    }
748
    }
640
749
750
    my $holdallowed_rule = Koha::CirculationRules->get_effective_rule({
751
        branchcode => $reserves_control_branch,
752
        itemtype => $item->effective_itemtype,
753
        rule_name => 'holdallowed',
754
    });
755
    push @circulation_rules, $holdallowed_rule if $holdallowed_rule;
756
641
    my $branchitemrule =
757
    my $branchitemrule =
642
      C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->effective_itemtype );
758
      C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->effective_itemtype );
643
759
644
    if ( $branchitemrule->{holdallowed} eq 'not_allowed' ) {
760
    if ( $branchitemrule->{holdallowed} eq 'not_allowed' ) {
645
        return _cache { status => 'notReservable' };
761
        return _cache { status => 'notReservable', circulation_rules => \@circulation_rules };
646
    }
762
    }
647
763
648
    if (   $branchitemrule->{holdallowed} eq 'from_home_library'
764
    if (   $branchitemrule->{holdallowed} eq 'from_home_library'
649
        && $patron->branchcode ne $item->homebranch )
765
        && $patron->branchcode ne $item->homebranch )
650
    {
766
    {
651
        return _cache { status => 'cannotReserveFromOtherBranches' };
767
        return _cache { status => 'cannotReserveFromOtherBranches', circulation_rules => \@circulation_rules };
652
    }
768
    }
653
769
654
    my $item_library = Koha::Libraries->find( {branchcode => $item->homebranch} );
770
    my $item_library = Koha::Libraries->find( {branchcode => $item->homebranch} );
655
    if ( $branchitemrule->{holdallowed} eq 'from_local_hold_group') {
771
    if ( $branchitemrule->{holdallowed} eq 'from_local_hold_group') {
656
        if($patron->branchcode ne $item->homebranch && !$item_library->validate_hold_sibling( {branchcode => $patron->branchcode} )) {
772
        if($patron->branchcode ne $item->homebranch && !$item_library->validate_hold_sibling( {branchcode => $patron->branchcode} )) {
657
            return _cache { status => 'branchNotInHoldGroup' };
773
            return _cache { status => 'branchNotInHoldGroup', circulation_rules => \@circulation_rules };
658
        }
774
        }
659
    }
775
    }
660
776
Lines 672-686 sub CanItemBeReserved { Link Here
672
        unless ($item->can_be_transferred({ to => $destination })) {
788
        unless ($item->can_be_transferred({ to => $destination })) {
673
            return _cache { status => 'cannotBeTransferred' };
789
            return _cache { status => 'cannotBeTransferred' };
674
        }
790
        }
791
792
        my $hold_fulfillment_policy_rule = Koha::CirculationRules->get_effective_rule({
793
            branchcode => $reserves_control_branch,
794
            itemtype => $item->effective_itemtype,
795
            rule_name => 'hold_fulfillment_policy',
796
        });
797
        push @circulation_rules, $hold_fulfillment_policy_rule if $hold_fulfillment_policy_rule;
798
675
        if ($branchitemrule->{hold_fulfillment_policy} eq 'holdgroup' && !$item_library->validate_hold_sibling( {branchcode => $pickup_branchcode} )) {
799
        if ($branchitemrule->{hold_fulfillment_policy} eq 'holdgroup' && !$item_library->validate_hold_sibling( {branchcode => $pickup_branchcode} )) {
676
            return _cache { status => 'pickupNotInHoldGroup' };
800
            return _cache { status => 'pickupNotInHoldGroup', circulation_rules => \@circulation_rules };
677
        }
801
        }
678
        if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $patron->branchcode})->validate_hold_sibling({branchcode => $pickup_branchcode})) {
802
        if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $patron->branchcode})->validate_hold_sibling({branchcode => $pickup_branchcode})) {
679
            return _cache { status => 'pickupNotInHoldGroup' };
803
            return _cache { status => 'pickupNotInHoldGroup', circulation_rules => \@circulation_rules };
680
        }
804
        }
681
    }
805
    }
682
806
683
    return _cache { status => 'OK' };
807
    return _cache { status => 'OK', circulation_rules => \@circulation_rules };
684
}
808
}
685
809
686
=head2 ChargeReserveFee
810
=head2 ChargeReserveFee
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt (+150 lines)
Lines 241-246 Link Here
241
                </h2>
241
                </h2>
242
            [% END %]
242
            [% END %]
243
243
244
            [% IF canbookbereserved_responses %]
245
                <button type="button" class="btn btn-sm" data-toggle="modal" data-target="#holdruleschecker">[% t('Show circulation rules') | html %]</button>
246
            [% END %]
247
244
            [% UNLESS club OR patron OR patron.borrowernumber OR noitems OR nobiblio %]
248
            [% UNLESS club OR patron OR patron.borrowernumber OR noitems OR nobiblio %]
245
                [% IF ( messageborrower ) %]
249
                [% IF ( messageborrower ) %]
246
                    <div class="alert alert-warning">
250
                    <div class="alert alert-warning">
Lines 512-517 Link Here
512
                                <li><strong>No items available: </strong>One or more records have no items that can be held</li>
516
                                <li><strong>No items available: </strong>One or more records have no items that can be held</li>
513
                            [% END # /IF exceeded_maxreserves %]
517
                            [% END # /IF exceeded_maxreserves %]
514
                        [% END # /UNLESS multi_hold %]
518
                        [% END # /UNLESS multi_hold %]
519
515
                    </div>
520
                    </div>
516
                [% END # /IF ( exceeded_maxreserves || ... %]
521
                [% END # /IF ( exceeded_maxreserves || ... %]
517
522
Lines 2012-2015 Link Here
2012
    </script>
2017
    </script>
2013
[% END %]
2018
[% END %]
2014
2019
2020
<div class="modal fade" id="holdruleschecker" tabindex="-1" role="dialog" aria-labelledby="holdruleschecker-title">
2021
    <div class="modal-dialog modal-lg" role="document">
2022
        <div class="modal-content">
2023
            <div class="modal-header">
2024
                <h4 class="modal-title" id="holdruleschecker-title">[% t('Holding rules') | html %]</h4>
2025
            </div>
2026
            <div class="modal-body">
2027
                <div>
2028
                    <h4>[% t('Overall info') | html %]</h4>
2029
2030
                    <ul>
2031
                        <li>
2032
                            [% tnx('Patron has {count} hold', 'Patron has {count} holds', reserves_count, { count = '<strong>' _ reserves_count _ '</strong>' }) | $raw %]
2033
                            [% tx('and this request would raise the number to {count}.', { count = '<strong>' _ (new_reserves_count + reserves_count) _ '</strong>' }) | $raw %]
2034
                        </li>
2035
                        <li>
2036
                            [% IF reserves_count >= Koha.Preference('maxreserves') %]
2037
                                <span class="text-danger">
2038
                            [% ELSE %]
2039
                                <span>
2040
                            [% END %]
2041
                                [% tx('{preference_name} preference:', { preference_name = '<em>maxreserves</em>' }) | $raw %]
2042
                                <strong>[% Koha.Preference('maxreserves') | html %]</strong>
2043
                            </span>
2044
                        </li>
2045
                        <li>
2046
                            [% tx('{preference_name} preference:', { preference_name = '<em>ReservesControlBranch</em>' }) | $raw %]
2047
                            <strong>[% Koha.Preference('ReservesControlBranch') | html %]</strong>
2048
                        </li
2049
                    </ul>
2050
                </div>
2051
2052
                <h4>[% t('Per record info') | html %]</h4>
2053
2054
                <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
2055
                    [% FOREACH response IN canbookbereserved_responses %]
2056
                        <div class="panel panel-default">
2057
                            <div class="panel-heading" role="tab" id="heading-[% response.biblio.biblionumber | html %]">
2058
                                <h4 class="panel-title">
2059
                                    <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse-[% response.biblio.biblionumber | html %]" aria-expanded="true" aria-controls="collapse-[% response.biblio.biblionumber | html %]">
2060
                                        [% response.biblio.title | html %]
2061
                                    </a>
2062
                                </h4>
2063
                            </div>
2064
                            <div id="collapse-[% response.biblio.biblionumber | html %]" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-[% response.biblio.biblionumber | html %]">
2065
                                <div class="panel-body">
2066
                                    <h5>[% t('Circulation rules checked') | html %]</h5>
2067
2068
                                    <table>
2069
                                        <thead>
2070
                                            <tr>
2071
                                                <th>[% t('Item') | html %]</th>
2072
                                                <th>[% t('Library') | html %]</th>
2073
                                                <th>[% t('Category') | html %]</th>
2074
                                                <th>[% t('Item type') | html %]</th>
2075
                                                <th>[% t('Rule name') | html %]</th>
2076
                                                <th>[% t('Rule value') | html %]</th>
2077
                                            </tr>
2078
                                        </thead>
2079
                                        <tbody>
2080
                                            [% FOREACH circulation_rule IN response.circulation_rules %]
2081
                                                <tr>
2082
                                                    <td></td>
2083
                                                    <td>
2084
                                                        [% IF circulation_rule.branchcode %]
2085
                                                            [% Branches.GetName(circulation_rule.branchcode) | html %]
2086
                                                            ([% circulation_rule.branchcode | html %])
2087
                                                        [% ELSE %]
2088
                                                            <em>[% t('All') | html %]</em>
2089
                                                        [% END %]
2090
                                                    </td>
2091
                                                    <td>
2092
                                                        [% IF circulation_rule.categorycode %]
2093
                                                            [% Categories.GetName(circulation_rule.categorycode) | html %]
2094
                                                        [% ELSE %]
2095
                                                            <em>[% t('All') | html %]</em>
2096
                                                        [% END %]
2097
                                                    </td>
2098
                                                    <td>
2099
                                                        [% IF circulation_rule.itemtype %]
2100
                                                            [% ItemTypes.GetDescription(circulation_rule.itemtype) | html %]
2101
                                                        [% ELSE %]
2102
                                                            <em>[% t('All') | html %]</em>
2103
                                                        [% END %]
2104
                                                    </td>
2105
                                                    <td>
2106
                                                        [% circulation_rule.rule_name | html %]
2107
                                                    </td>
2108
                                                    <td>
2109
                                                        [% circulation_rule.rule_value | html %]
2110
                                                    </td>
2111
                                                </tr>
2112
                                            [% END %]
2113
                                            [% FOREACH item_response IN response.item_responses %]
2114
                                                [% FOREACH circulation_rule IN item_response.circulation_rules %]
2115
                                                    <tr>
2116
                                                        <td>
2117
                                                            [% item_response.item.barcode | html %] (#[% item_response.item.itemnumber | html %])
2118
                                                        </td>
2119
                                                        <td>
2120
                                                            [% IF circulation_rule.branchcode %]
2121
                                                                [% Branches.GetName(circulation_rule.branchcode) | html %]
2122
                                                                ([% circulation_rule.branchcode | html %])
2123
                                                            [% ELSE %]
2124
                                                                <em>[% t('All') | html %]</em>
2125
                                                            [% END %]
2126
                                                        </td>
2127
                                                        <td>
2128
                                                            [% IF circulation_rule.categorycode %]
2129
                                                                [% Categories.GetName(circulation_rule.categorycode) | html %]
2130
                                                            [% ELSE %]
2131
                                                                <em>[% t('All') | html %]</em>
2132
                                                            [% END %]
2133
                                                        </td>
2134
                                                        <td>
2135
                                                            [% IF circulation_rule.itemtype %]
2136
                                                                [% ItemTypes.GetDescription(circulation_rule.itemtype) | html %]
2137
                                                            [% ELSE %]
2138
                                                                <em>[% t('All') | html %]</em>
2139
                                                            [% END %]
2140
                                                        </td>
2141
                                                        <td>
2142
                                                            [% circulation_rule.rule_name | html %]
2143
                                                        </td>
2144
                                                        <td>
2145
                                                            [% circulation_rule.rule_value | html %]
2146
                                                        </td>
2147
                                                    </tr>
2148
                                                [% END %]
2149
                                            [% END %]
2150
                                        </tbody>
2151
                                    </table>
2152
                                </div>
2153
                            </div>
2154
                        </div>
2155
                    [% END %]
2156
                </div>
2157
            </div>
2158
            <div class="modal-footer">
2159
                <button type="button" class="btn btn-default" data-dismiss="modal">[% t('Close') | html %]</button>
2160
            </div>
2161
        </div>
2162
    </div>
2163
</div> <!-- end of Modal -->
2164
2015
[% INCLUDE 'intranet-bottom.inc' %]
2165
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/reserve/request.pl (-2 / +9 lines)
Lines 186-193 if ($borrowernumber_hold && !$op) { Link Here
186
    # FIXME At this time we have a simple count of reservs, but, later, we could improve the infos "title" ...
186
    # FIXME At this time we have a simple count of reservs, but, later, we could improve the infos "title" ...
187
187
188
    my $reserves_count = $patron->holds->count;
188
    my $reserves_count = $patron->holds->count;
189
    $template->param(reserves_count => $reserves_count);
189
190
190
    my $new_reserves_count = scalar( @biblionumbers );
191
    my $new_reserves_count = scalar( @biblionumbers );
192
    $template->param(new_reserves_count   => $new_reserves_count);
191
193
192
    my $maxreserves = C4::Context->preference('maxreserves');
194
    my $maxreserves = C4::Context->preference('maxreserves');
193
    $template->param( maxreserves => $maxreserves );
195
    $template->param( maxreserves => $maxreserves );
Lines 203-210 if ($borrowernumber_hold && !$op) { Link Here
203
        $exceeded_maxreserves = 1;
205
        $exceeded_maxreserves = 1;
204
        $template->param(
206
        $template->param(
205
            new_reserves_allowed => $new_reserves_allowed,
207
            new_reserves_allowed => $new_reserves_allowed,
206
            new_reserves_count   => $new_reserves_count,
207
            reserves_count       => $reserves_count,
208
            maxreserves          => $maxreserves,
208
            maxreserves          => $maxreserves,
209
        );
209
        );
210
    }
210
    }
Lines 298-303 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
298
    my @biblioloop = ();
298
    my @biblioloop = ();
299
    my $no_reserves_allowed = 0;
299
    my $no_reserves_allowed = 0;
300
    my $num_bibs_available = 0;
300
    my $num_bibs_available = 0;
301
    my @canbookbereserved_responses;
301
    foreach my $biblionumber (@biblionumbers) {
302
    foreach my $biblionumber (@biblionumbers) {
302
        next unless $biblionumber =~ m|^\d+$|;
303
        next unless $biblionumber =~ m|^\d+$|;
303
304
Lines 316-321 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
316
        if ( $patron ) {
317
        if ( $patron ) {
317
            { # CanBookBeReserved
318
            { # CanBookBeReserved
318
                my $canReserve = CanBookBeReserved( $patron->borrowernumber, $biblionumber );
319
                my $canReserve = CanBookBeReserved( $patron->borrowernumber, $biblionumber );
320
321
                push @canbookbereserved_responses, { %$canReserve, biblio => $biblio };
322
319
                if ( $canReserve->{status} eq 'OK' ) {
323
                if ( $canReserve->{status} eq 'OK' ) {
320
324
321
                    #All is OK and we can continue
325
                    #All is OK and we can continue
Lines 710-715 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
710
714
711
    $template->param( no_bibs_available => 1 ) unless $num_bibs_available > 0;
715
    $template->param( no_bibs_available => 1 ) unless $num_bibs_available > 0;
712
716
717
    $Data::Dumper::Maxdepth = 3;
718
    use Data::Dumper; warn Dumper \@canbookbereserved_responses;
719
    $template->param( canbookbereserved_responses => \@canbookbereserved_responses );
713
    $template->param( biblioloop => \@biblioloop );
720
    $template->param( biblioloop => \@biblioloop );
714
    $template->param( no_reserves_allowed => $no_reserves_allowed );
721
    $template->param( no_reserves_allowed => $no_reserves_allowed );
715
    $template->param( exceeded_maxreserves => $exceeded_maxreserves );
722
    $template->param( exceeded_maxreserves => $exceeded_maxreserves );
(-)a/t/db_dependent/Reserves/HoldRulesChecker.t (-1 / +110 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# Copyright 2019 Biblibre
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Test::More tests => 13;
23
use t::lib::TestBuilder;
24
25
use C4::Reserves qw( CanBookBeReserved );
26
27
my $schema = Koha::Database->new->schema;
28
$schema->storage->txn_begin;
29
30
my $builder = t::lib::TestBuilder->new();
31
32
my $library = $builder->build_object({ class => 'Koha::Libraries' });
33
my $category = $builder->build_object({ class => 'Koha::Patron::Categories' });
34
my $patron = $builder->build_object(
35
    {
36
        class => 'Koha::Patrons',
37
        value  => {
38
            categorycode => $category->categorycode,
39
            branchcode   => $library->branchcode,
40
        },
41
    }
42
);
43
44
my $itemtype = $builder->build_object({ class => 'Koha::ItemTypes' });
45
46
my $biblio = $builder->build_sample_biblio(
47
    {
48
        title => 'Title 1',
49
    }
50
);
51
my $item = $builder->build_sample_item(
52
    {
53
        biblionumber => $biblio->biblionumber,
54
        library      => $library->branchcode,
55
        itype        => $itemtype->itemtype,
56
        damaged      => 0,
57
    }
58
);
59
60
my $rules_rs = Koha::Database->new()->schema()->resultset('CirculationRule');
61
$rules_rs->delete();
62
63
my $default_reservesallowed_rule = $rules_rs->create(
64
    {
65
        categorycode     => undef,
66
        itemtype         => undef,
67
        branchcode       => undef,
68
        rule_name => 'reservesallowed',
69
        rule_value => 10,
70
    }
71
);
72
73
my $reservesallowed_rule = $rules_rs->create(
74
    {
75
        categorycode     => $patron->categorycode,
76
        itemtype         => undef,
77
        branchcode       => $library->branchcode,
78
        rule_name => 'reservesallowed',
79
        rule_value => 0,
80
    }
81
);
82
83
my $can = CanBookBeReserved($patron->borrowernumber, $biblio->biblionumber);
84
is($can->{status}, '');
85
is(scalar @{ $can->{circulation_rules} }, 0);
86
is(scalar @{ $can->{item_responses} }, 1);
87
is($can->{item_responses}->[0]->{status}, 'noReservesAllowed');
88
is(scalar @{ $can->{item_responses}->[0]->{circulation_rules} }, 1);
89
is($can->{item_responses}->[0]->{circulation_rules}->[0]->id, $reservesallowed_rule->id);
90
91
my $holds_per_record_rule = $rules_rs->create(
92
    {
93
        categorycode     => $patron->categorycode,
94
        itemtype         => undef,
95
        branchcode       => $library->branchcode,
96
        rule_name => 'holds_per_record',
97
        rule_value => 1,
98
    }
99
);
100
101
$can = CanBookBeReserved($patron->borrowernumber, $biblio->biblionumber);
102
is($can->{status}, '');
103
is(scalar @{ $can->{circulation_rules} }, 0);
104
is(scalar @{ $can->{item_responses} }, 1);
105
is($can->{item_responses}->[0]->{status}, 'noReservesAllowed');
106
is(scalar @{ $can->{item_responses}->[0]->{circulation_rules} }, 2);
107
is($can->{item_responses}->[0]->{circulation_rules}->[0]->id, $holds_per_record_rule->id);
108
is($can->{item_responses}->[0]->{circulation_rules}->[1]->id, $reservesallowed_rule->id);
109
110
$schema->storage->txn_rollback;

Return to bug 23732