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

(-)a/C4/Reserves.pm (-61 / +185 lines)
Lines 341-359 sub CanBookBeReserved{ Link Here
341
        return { status =>'alreadypossession' };
341
        return { status =>'alreadypossession' };
342
    }
342
    }
343
343
344
    my @circulation_rules;
345
344
    if ( $params->{itemtype} ) {
346
    if ( $params->{itemtype} ) {
345
347
346
        # biblio-level, item type-contrained
348
        # biblio-level, item type-contrained
347
        my $patron          = Koha::Patrons->find($borrowernumber);
349
        my $patron          = Koha::Patrons->find($borrowernumber);
348
        my $reservesallowed = Koha::CirculationRules->get_effective_rule(
350
        my $reservesallowed_rule = Koha::CirculationRules->get_effective_rule(
349
            {
351
            {
350
                itemtype     => $params->{itemtype},
352
                itemtype     => $params->{itemtype},
351
                categorycode => $patron->categorycode,
353
                categorycode => $patron->categorycode,
352
                branchcode   => $pickup_branchcode,
354
                branchcode   => $pickup_branchcode,
353
                rule_name    => 'reservesallowed',
355
                rule_name    => 'reservesallowed',
354
            }
356
            }
355
        )->rule_value;
357
        );
358
        push @circulation_rules, $reservesallowed_rule if $reservesallowed_rule;
356
359
360
        my $reservesallowed = $reservesallowed_rule ? $reservesallowed_rule->rule_value : undef;
357
        $reservesallowed = ( $reservesallowed eq '' ) ? undef : $reservesallowed;
361
        $reservesallowed = ( $reservesallowed eq '' ) ? undef : $reservesallowed;
358
362
359
        my $count = $patron->holds->search(
363
        my $count = $patron->holds->search(
Lines 368-374 sub CanBookBeReserved{ Link Here
368
            }
372
            }
369
        )->count;
373
        )->count;
370
374
371
        return { status => '' }
375
        return { status => '', circulation_rules => \@circulation_rules }
372
          if defined $reservesallowed and $reservesallowed < $count + 1;
376
          if defined $reservesallowed and $reservesallowed < $count + 1;
373
    }
377
    }
374
378
Lines 386-421 sub CanBookBeReserved{ Link Here
386
        $items = Koha::Items->search({ biblionumber => $biblionumber});
390
        $items = Koha::Items->search({ biblionumber => $biblionumber});
387
    }
391
    }
388
392
389
    my $canReserve = { status => '' };
393
    my $response = { status => '', item_responses => [] };
390
    my $patron = Koha::Patrons->find( $borrowernumber );
394
    my $patron = Koha::Patrons->find( $borrowernumber );
391
    while ( my $item = $items->next ) {
395
    while ( my $item = $items->next ) {
392
        $canReserve = CanItemBeReserved( $patron, $item, $pickup_branchcode, $params );
396
        my $itemResponse = CanItemBeReserved( $patron, $item, $pickup_branchcode, $params );
393
        return { status => 'OK' } if $canReserve->{status} eq 'OK';
397
        push @{ $response->{item_responses} }, { %$itemResponse, item => $item };
398
399
        if ($itemResponse->{status} eq 'OK') {
400
            $response->{status} = 'OK';
401
402
            return $response;
403
        }
394
    }
404
    }
395
    return $canReserve;
405
406
    return $response;
396
}
407
}
397
408
398
=head2 CanItemBeReserved
409
=head2 CanItemBeReserved
399
410
400
  $canReserve = &CanItemBeReserved($patron, $item, $branchcode, $params)
411
  $canReserve = CanItemBeReserved($patron, $item, $branchcode, $params)
401
  if ($canReserve->{status} eq 'OK') { #We can reserve this Item! }
412
  if ($canReserve->{status} eq 'OK') { #We can reserve this Item! }
402
413
403
  current params are:
414
Current params are:
404
  'ignore_hold_counts' - we use this routine to check if an item can fill a hold - on this case we
415
405
  should not check if there are too many holds as we only care about reservability
416
=over
406
417
407
@RETURNS { status => OK },              if the Item can be reserved.
418
=item * C<ignore_hold_counts>
408
         { status => ageRestricted },   if the Item is age restricted for this borrower.
419
409
         { status => damaged },         if the Item is damaged.
420
we use this routine to check if an item can
410
         { status => cannotReserveFromOtherBranches }, if syspref 'canreservefromotherbranches' is OK.
421
fill a hold - on this case we should not check if there are too many holds as
411
         { status => branchNotInHoldGroup }, if borrower home library is not in hold group, and holds are only allowed from hold groups.
422
we only care about reservability
412
         { status => tooManyReserves, limit => $limit }, if the borrower has exceeded their maximum reserve amount.
423
413
         { status => notReservable },   if holds on this item are not allowed
424
=back
414
         { status => libraryNotFound },   if given branchcode is not an existing library
425
415
         { status => libraryNotPickupLocation },   if given branchcode is not configured to be a pickup location
426
Returns a hashref with the following keys:
416
         { status => cannotBeTransferred }, if branch transfer limit applies on given item and branchcode
427
417
         { status => pickupNotInHoldGroup }, pickup location is not in hold group, and pickup locations are only allowed from hold groups.
428
=over
418
         { status => recall }, if the borrower has already placed a recall on this item
429
430
=item * C<status>
431
432
A string that can have the following values:
433
434
=over
435
436
=item * C<OK> if the item can be reserved
437
438
=item * C<ageRestricted> if the item is aged restricted for this borrower
439
440
=item * C<damaged> if the item is damaged
441
442
=item * C<cannotReserveFromOtherBranches> if syspref
443
'canreservefromotherbranches' is OK
444
445
=item * C<branchNotInHoldGroup> if borrower home library is not in hold group,
446
and holds are only allowed from hold groups.
447
448
=item * C<tooManyReserves> if the borrower has exceeded their maximum reserve
449
amount.
450
451
=item * C<tooManyHoldsForThisRecord> if the borrower has exceeded their maximum
452
reserve amount for this biblio record
453
454
=item * C<tooManyReservesToday> if the borrower has exceeded their maximum
455
reserve amount for today
456
457
=item * C<notReservable> if holds on this item are not allowed
458
459
=item * C<libraryNotFound> if given branchcode is not an existing library
460
461
=item * C<libraryNotPickupLocation> if given branchcode is not configured to be
462
a pickup location
463
464
=item * C<cannotBeTransferred> if branch transfer limit applies on given item
465
and branchcode
466
467
=item * C<pickupNotInHoldGroup> if pickup location is not in hold group, and
468
pickup locations are only allowed from hold groups.
469
470
=item * C<recall> if the borrower has already placed a recall on this item
471
472
=back
473
474
=item * C<limit>
475
476
Only if C<status> is equal to C<tooManyReserves>, C<tooManyHoldsForThisRecord>,
477
or C<tooManyReservesToday>.
478
479
It contains the number of reserves allowed.
480
481
=item * C<circulation_rules>
482
483
An arrayref containing all circulations rules (L<Koha::CirculationRule>) that
484
have been checked
485
486
=back
419
487
420
=cut
488
=cut
421
489
Lines 423-430 sub CanItemBeReserved { Link Here
423
    my ( $patron, $item, $pickup_branchcode, $params ) = @_;
491
    my ( $patron, $item, $pickup_branchcode, $params ) = @_;
424
492
425
    my $dbh = C4::Context->dbh;
493
    my $dbh = C4::Context->dbh;
426
    my $ruleitemtype;    # itemtype of the matching issuing rule
427
    my $allowedreserves  = 0; # Total number of holds allowed across all records, default to none
428
494
429
    # We check item branch if IndependentBranches is ON
495
    # We check item branch if IndependentBranches is ON
430
    # and canreservefromotherbranches is OFF
496
    # and canreservefromotherbranches is OFF
Lines 481-514 sub CanItemBeReserved { Link Here
481
        $reserves_control_branch  = $borrower->{branchcode};
547
        $reserves_control_branch  = $borrower->{branchcode};
482
    }
548
    }
483
549
484
    # we retrieve rights
550
    my @circulation_rules;
485
    if (
486
        my $reservesallowed = Koha::CirculationRules->get_effective_rule({
487
                itemtype     => $item->effective_itemtype,
488
                categorycode => $borrower->{categorycode},
489
                branchcode   => $reserves_control_branch,
490
                rule_name    => 'reservesallowed',
491
        })
492
    ) {
493
        $ruleitemtype     = $reservesallowed->itemtype;
494
        $allowedreserves  = $reservesallowed->rule_value // 0; #undefined is 0, blank is unlimited
495
    }
496
    else {
497
        $ruleitemtype = undef;
498
    }
499
551
500
    my $rights = Koha::CirculationRules->get_effective_rules({
552
    my $holds_per_record_rule = Koha::CirculationRules->get_effective_rule({
501
        categorycode => $borrower->{'categorycode'},
553
        categorycode => $borrower->{categorycode},
502
        itemtype     => $item->effective_itemtype,
554
        itemtype     => $item->effective_itemtype,
503
        branchcode   => $reserves_control_branch,
555
        branchcode   => $reserves_control_branch,
504
        rules        => ['holds_per_record','holds_per_day']
556
        rule_name    => 'holds_per_record',
505
    });
557
    });
506
    my $holds_per_record = $rights->{holds_per_record} // 1;
558
    push @circulation_rules, $holds_per_record_rule if $holds_per_record_rule;
507
    my $holds_per_day    = $rights->{holds_per_day};
559
560
    my $holds_per_record = $holds_per_record_rule ? $holds_per_record_rule->rule_value : 1;
508
561
509
    if (   defined $holds_per_record && $holds_per_record ne '' ){
562
    if (   defined $holds_per_record && $holds_per_record ne '' ){
510
        if ( $holds_per_record == 0 ) {
563
        if ( $holds_per_record == 0 ) {
511
            return { status => "noReservesAllowed" };
564
            return { status => "noReservesAllowed", circulation_rules => \@circulation_rules };
512
        }
565
        }
513
        if ( !$params->{ignore_hold_counts} ) {
566
        if ( !$params->{ignore_hold_counts} ) {
514
            my $search_params = {
567
            my $search_params = {
Lines 516-539 sub CanItemBeReserved { Link Here
516
                biblionumber   => $item->biblionumber,
569
                biblionumber   => $item->biblionumber,
517
            };
570
            };
518
            my $holds = Koha::Holds->search($search_params);
571
            my $holds = Koha::Holds->search($search_params);
519
            return { status => "tooManyHoldsForThisRecord", limit => $holds_per_record } if $holds->count() >= $holds_per_record;
572
573
            if ($holds->count() >= $holds_per_record) {
574
                return {
575
                    status => "tooManyHoldsForThisRecord",
576
                    limit  => $holds_per_record,
577
                    circulation_rules => \@circulation_rules,
578
                };
579
            }
520
        }
580
        }
521
    }
581
    }
522
582
583
    my $holds_per_day_rule = Koha::CirculationRules->get_effective_rule({
584
        categorycode => $borrower->{'categorycode'},
585
        itemtype     => $item->effective_itemtype,
586
        branchcode   => $reserves_control_branch,
587
        rule_name    => 'holds_per_day',
588
    });
589
    push @circulation_rules, $holds_per_day_rule if $holds_per_day_rule;
590
591
    my $holds_per_day = $holds_per_day_rule ? $holds_per_day_rule->rule_value : undef;
523
    if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne '')
592
    if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne '')
524
    {
593
    {
525
        my $today_holds = Koha::Holds->search({
594
        my $today_holds = Koha::Holds->search({
526
            borrowernumber => $patron->borrowernumber,
595
            borrowernumber => $patron->borrowernumber,
527
            reservedate    => dt_from_string->date
596
            reservedate    => dt_from_string->date
528
        });
597
        });
529
        return { status => 'tooManyReservesToday', limit => $holds_per_day } if $today_holds->count() >= $holds_per_day;
598
599
        if ($today_holds->count() >= $holds_per_day) {
600
            return {
601
                status => 'tooManyReservesToday',
602
                limit  => $holds_per_day,
603
                circulation_rules => \@circulation_rules,
604
            };
605
        }
606
    }
607
608
    my $reservesallowed_rule = Koha::CirculationRules->get_effective_rule({
609
        itemtype     => $item->effective_itemtype,
610
        categorycode => $borrower->{categorycode},
611
        branchcode   => $reserves_control_branch,
612
        rule_name    => 'reservesallowed',
613
    });
614
    push @circulation_rules, $reservesallowed_rule if $reservesallowed_rule;
615
616
    my $ruleitemtype;    # itemtype of the matching issuing rule
617
    my $allowedreserves  = 0; # Total number of holds allowed across all records, default to none
618
    if ($reservesallowed_rule) {
619
        $ruleitemtype     = $reservesallowed_rule->itemtype;
620
        $allowedreserves  = $reservesallowed_rule->rule_value // 0; #undefined is 0, blank is unlimited
530
    }
621
    }
531
622
532
    # we check if it's ok or not
623
    # we check if it's ok or not
533
    if ( defined $allowedreserves && $allowedreserves ne '' ){
624
    if ( defined $allowedreserves && $allowedreserves ne '' ){
534
        if( $allowedreserves == 0 ){
625
        if ( $allowedreserves == 0 ) {
535
            return { status => 'noReservesAllowed' };
626
            return {
627
                status            => 'noReservesAllowed',
628
                circulation_rules => \@circulation_rules,
629
            };
536
        }
630
        }
631
537
        if ( !$params->{ignore_hold_counts} ) {
632
        if ( !$params->{ignore_hold_counts} ) {
538
            # we retrieve count
633
            # we retrieve count
539
            my $querycount = q{
634
            my $querycount = q{
Lines 577-621 sub CanItemBeReserved { Link Here
577
                $reservecount = $rowcount->{count};
672
                $reservecount = $rowcount->{count};
578
            }
673
            }
579
674
580
            return { status => 'tooManyReserves', limit => $allowedreserves } if $reservecount >= $allowedreserves;
675
            if ($reservecount >= $allowedreserves) {
676
                return {
677
                    status => 'tooManyReserves',
678
                    limit  => $allowedreserves,
679
                    circulation_rules => \@circulation_rules,
680
                };
681
            }
581
        }
682
        }
582
    }
683
    }
583
684
584
    # Now we need to check hold limits by patron category
685
    # Now we need to check hold limits by patron category
585
    my $rule = Koha::CirculationRules->get_effective_rule(
686
    my $max_holds_rule = Koha::CirculationRules->get_effective_rule(
586
        {
687
        {
587
            categorycode => $patron->categorycode,
688
            categorycode => $patron->categorycode,
588
            branchcode   => $reserves_control_branch,
689
            branchcode   => $reserves_control_branch,
589
            rule_name    => 'max_holds',
690
            rule_name    => 'max_holds',
590
        }
691
        }
591
    );
692
    );
592
    if (!$params->{ignore_hold_counts} && $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
693
    push @circulation_rules, $max_holds_rule if $max_holds_rule;
694
695
    if (!$params->{ignore_hold_counts} && $max_holds_rule && defined( $max_holds_rule->rule_value ) && $max_holds_rule->rule_value ne '' ) {
593
        my $total_holds_count = Koha::Holds->search(
696
        my $total_holds_count = Koha::Holds->search(
594
            {
697
            {
595
                borrowernumber => $patron->borrowernumber
698
                borrowernumber => $patron->borrowernumber
596
            }
699
            }
597
        )->count();
700
        )->count();
598
701
599
        return { status => 'tooManyReserves', limit => $rule->rule_value} if $total_holds_count >= $rule->rule_value;
702
        if ($total_holds_count >= $max_holds_rule->rule_value) {
703
            return {
704
                status => 'tooManyReserves',
705
                limit => $max_holds_rule->rule_value,
706
                circulation_rules => \@circulation_rules,
707
            };
708
        }
600
    }
709
    }
601
710
711
    my $holdallowed_rule = Koha::CirculationRules->get_effective_rule({
712
        branchcode => $reserves_control_branch,
713
        itemtype => $item->effective_itemtype,
714
        rule_name => 'holdallowed',
715
    });
716
    push @circulation_rules, $holdallowed_rule if $holdallowed_rule;
717
602
    my $branchitemrule =
718
    my $branchitemrule =
603
      C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->effective_itemtype );
719
      C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->effective_itemtype );
604
720
605
    if ( $branchitemrule->{holdallowed} eq 'not_allowed' ) {
721
    if ( $branchitemrule->{holdallowed} eq 'not_allowed' ) {
606
        return { status => 'notReservable' };
722
        return { status => 'notReservable', circulation_rules => \@circulation_rules };
607
    }
723
    }
608
724
609
    if (   $branchitemrule->{holdallowed} eq 'from_home_library'
725
    if (   $branchitemrule->{holdallowed} eq 'from_home_library'
610
        && $borrower->{branchcode} ne $item->homebranch )
726
        && $borrower->{branchcode} ne $item->homebranch )
611
    {
727
    {
612
        return { status => 'cannotReserveFromOtherBranches' };
728
        return { status => 'cannotReserveFromOtherBranches', circulation_rules => \@circulation_rules };
613
    }
729
    }
614
730
615
    my $item_library = Koha::Libraries->find( {branchcode => $item->homebranch} );
731
    my $item_library = Koha::Libraries->find( {branchcode => $item->homebranch} );
616
    if ( $branchitemrule->{holdallowed} eq 'from_local_hold_group') {
732
    if ( $branchitemrule->{holdallowed} eq 'from_local_hold_group') {
617
        if($patron->branchcode ne $item->homebranch && !$item_library->validate_hold_sibling( {branchcode => $patron->branchcode} )) {
733
        if($patron->branchcode ne $item->homebranch && !$item_library->validate_hold_sibling( {branchcode => $patron->branchcode} )) {
618
            return { status => 'branchNotInHoldGroup' };
734
            return { status => 'branchNotInHoldGroup', circulation_rules => \@circulation_rules };
619
        }
735
        }
620
    }
736
    }
621
737
Lines 633-647 sub CanItemBeReserved { Link Here
633
        unless ($item->can_be_transferred({ to => $destination })) {
749
        unless ($item->can_be_transferred({ to => $destination })) {
634
            return { status => 'cannotBeTransferred' };
750
            return { status => 'cannotBeTransferred' };
635
        }
751
        }
752
753
        my $hold_fulfillment_policy_rule = Koha::CirculationRules->get_effective_rule({
754
            branchcode => $reserves_control_branch,
755
            itemtype => $item->effective_itemtype,
756
            rule_name => 'hold_fulfillment_policy',
757
        });
758
        push @circulation_rules, $hold_fulfillment_policy_rule if $hold_fulfillment_policy_rule;
759
636
        if ($branchitemrule->{hold_fulfillment_policy} eq 'holdgroup' && !$item_library->validate_hold_sibling( {branchcode => $pickup_branchcode} )) {
760
        if ($branchitemrule->{hold_fulfillment_policy} eq 'holdgroup' && !$item_library->validate_hold_sibling( {branchcode => $pickup_branchcode} )) {
637
            return { status => 'pickupNotInHoldGroup' };
761
            return { status => 'pickupNotInHoldGroup', circulation_rules => \@circulation_rules };
638
        }
762
        }
639
        if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $borrower->{branchcode}})->validate_hold_sibling({branchcode => $pickup_branchcode})) {
763
        if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $borrower->{branchcode}})->validate_hold_sibling({branchcode => $pickup_branchcode})) {
640
            return { status => 'pickupNotInHoldGroup' };
764
            return { status => 'pickupNotInHoldGroup', circulation_rules => \@circulation_rules };
641
        }
765
        }
642
    }
766
    }
643
767
644
    return { status => 'OK' };
768
    return { status => 'OK', circulation_rules => \@circulation_rules };
645
}
769
}
646
770
647
=head2 CanReserveBeCanceledFromOpac
771
=head2 CanReserveBeCanceledFromOpac
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt (+150 lines)
Lines 205-210 Link Here
205
                </h2>
205
                </h2>
206
            [% END %]
206
            [% END %]
207
207
208
            [% IF canbookbereserved_responses %]
209
                <button type="button" class="btn btn-sm" data-toggle="modal" data-target="#holdruleschecker">[% t('Show circulation rules') | html %]</button>
210
            [% END %]
211
208
            [% UNLESS club OR patron OR patron.borrowernumber OR noitems OR nobiblio %]
212
            [% UNLESS club OR patron OR patron.borrowernumber OR noitems OR nobiblio %]
209
                [% IF ( messageborrower ) %]
213
                [% IF ( messageborrower ) %]
210
                    <div class="dialog alert">
214
                    <div class="dialog alert">
Lines 472-477 Link Here
472
                                <li><strong>No items available: </strong>One or more records have no items that can be held</li>
476
                                <li><strong>No items available: </strong>One or more records have no items that can be held</li>
473
                            [% END # /IF exceeded_maxreserves %]
477
                            [% END # /IF exceeded_maxreserves %]
474
                        [% END # /UNLESS multi_hold %]
478
                        [% END # /UNLESS multi_hold %]
479
475
                    </div>
480
                    </div>
476
                [% END # /IF ( exceeded_maxreserves || ... %]
481
                [% END # /IF ( exceeded_maxreserves || ... %]
477
482
Lines 1756-1759 Link Here
1756
    </script>
1761
    </script>
1757
[% END %]
1762
[% END %]
1758
1763
1764
<div class="modal fade" id="holdruleschecker" tabindex="-1" role="dialog" aria-labelledby="holdruleschecker-title">
1765
    <div class="modal-dialog modal-lg" role="document">
1766
        <div class="modal-content">
1767
            <div class="modal-header">
1768
                <h4 class="modal-title" id="holdruleschecker-title">[% t('Holding rules') | html %]</h4>
1769
            </div>
1770
            <div class="modal-body">
1771
                <div>
1772
                    <h4>[% t('Overall info') | html %]</h4>
1773
1774
                    <ul>
1775
                        <li>
1776
                            [% tnx('Patron has {count} hold', 'Patron has {count} holds', reserves_count, { count = '<strong>' _ reserves_count _ '</strong>' }) | $raw %]
1777
                            [% tx('and this request would raise the number to {count}.', { count = '<strong>' _ (new_reserves_count + reserves_count) _ '</strong>' }) | $raw %]
1778
                        </li>
1779
                        <li>
1780
                            [% IF reserves_count >= Koha.Preference('maxreserves') %]
1781
                                <span class="text-danger">
1782
                            [% ELSE %]
1783
                                <span>
1784
                            [% END %]
1785
                                [% tx('{preference_name} preference:', { preference_name = '<em>maxreserves</em>' }) | $raw %]
1786
                                <strong>[% Koha.Preference('maxreserves') | html %]</strong>
1787
                            </span>
1788
                        </li>
1789
                        <li>
1790
                            [% tx('{preference_name} preference:', { preference_name = '<em>ReservesControlBranch</em>' }) | $raw %]
1791
                            <strong>[% Koha.Preference('ReservesControlBranch') | html %]</strong>
1792
                        </li
1793
                    </ul>
1794
                </div>
1795
1796
                <h4>[% t('Per record info') | html %]</h4>
1797
1798
                <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
1799
                    [% FOREACH response IN canbookbereserved_responses %]
1800
                        <div class="panel panel-default">
1801
                            <div class="panel-heading" role="tab" id="heading-[% response.biblio.biblionumber | html %]">
1802
                                <h4 class="panel-title">
1803
                                    <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 %]">
1804
                                        [% response.biblio.title | html %]
1805
                                    </a>
1806
                                </h4>
1807
                            </div>
1808
                            <div id="collapse-[% response.biblio.biblionumber | html %]" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-[% response.biblio.biblionumber | html %]">
1809
                                <div class="panel-body">
1810
                                    <h5>[% t('Circulation rules checked') | html %]</h5>
1811
1812
                                    <table>
1813
                                        <thead>
1814
                                            <tr>
1815
                                                <th>[% t('Item') | html %]</th>
1816
                                                <th>[% t('Library') | html %]</th>
1817
                                                <th>[% t('Category') | html %]</th>
1818
                                                <th>[% t('Item type') | html %]</th>
1819
                                                <th>[% t('Rule name') | html %]</th>
1820
                                                <th>[% t('Rule value') | html %]</th>
1821
                                            </tr>
1822
                                        </thead>
1823
                                        <tbody>
1824
                                            [% FOREACH circulation_rule IN response.circulation_rules %]
1825
                                                <tr>
1826
                                                    <td></td>
1827
                                                    <td>
1828
                                                        [% IF circulation_rule.branchcode %]
1829
                                                            [% Branches.GetName(circulation_rule.branchcode) | html %]
1830
                                                            ([% circulation_rule.branchcode | html %])
1831
                                                        [% ELSE %]
1832
                                                            <em>[% t('All') | html %]</em>
1833
                                                        [% END %]
1834
                                                    </td>
1835
                                                    <td>
1836
                                                        [% IF circulation_rule.categorycode %]
1837
                                                            [% Categories.GetName(circulation_rule.categorycode) | html %]
1838
                                                        [% ELSE %]
1839
                                                            <em>[% t('All') | html %]</em>
1840
                                                        [% END %]
1841
                                                    </td>
1842
                                                    <td>
1843
                                                        [% IF circulation_rule.itemtype %]
1844
                                                            [% ItemTypes.GetDescription(circulation_rule.itemtype) | html %]
1845
                                                        [% ELSE %]
1846
                                                            <em>[% t('All') | html %]</em>
1847
                                                        [% END %]
1848
                                                    </td>
1849
                                                    <td>
1850
                                                        [% circulation_rule.rule_name | html %]
1851
                                                    </td>
1852
                                                    <td>
1853
                                                        [% circulation_rule.rule_value | html %]
1854
                                                    </td>
1855
                                                </tr>
1856
                                            [% END %]
1857
                                            [% FOREACH item_response IN response.item_responses %]
1858
                                                [% FOREACH circulation_rule IN item_response.circulation_rules %]
1859
                                                    <tr>
1860
                                                        <td>
1861
                                                            [% item_response.item.barcode | html %] (#[% item_response.item.itemnumber | html %])
1862
                                                        </td>
1863
                                                        <td>
1864
                                                            [% IF circulation_rule.branchcode %]
1865
                                                                [% Branches.GetName(circulation_rule.branchcode) | html %]
1866
                                                                ([% circulation_rule.branchcode | html %])
1867
                                                            [% ELSE %]
1868
                                                                <em>[% t('All') | html %]</em>
1869
                                                            [% END %]
1870
                                                        </td>
1871
                                                        <td>
1872
                                                            [% IF circulation_rule.categorycode %]
1873
                                                                [% Categories.GetName(circulation_rule.categorycode) | html %]
1874
                                                            [% ELSE %]
1875
                                                                <em>[% t('All') | html %]</em>
1876
                                                            [% END %]
1877
                                                        </td>
1878
                                                        <td>
1879
                                                            [% IF circulation_rule.itemtype %]
1880
                                                                [% ItemTypes.GetDescription(circulation_rule.itemtype) | html %]
1881
                                                            [% ELSE %]
1882
                                                                <em>[% t('All') | html %]</em>
1883
                                                            [% END %]
1884
                                                        </td>
1885
                                                        <td>
1886
                                                            [% circulation_rule.rule_name | html %]
1887
                                                        </td>
1888
                                                        <td>
1889
                                                            [% circulation_rule.rule_value | html %]
1890
                                                        </td>
1891
                                                    </tr>
1892
                                                [% END %]
1893
                                            [% END %]
1894
                                        </tbody>
1895
                                    </table>
1896
                                </div>
1897
                            </div>
1898
                        </div>
1899
                    [% END %]
1900
                </div>
1901
            </div>
1902
            <div class="modal-footer">
1903
                <button type="button" class="btn btn-default" data-dismiss="modal">[% t('Close') | html %]</button>
1904
            </div>
1905
        </div>
1906
    </div>
1907
</div> <!-- end of Modal -->
1908
1759
[% INCLUDE 'intranet-bottom.inc' %]
1909
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/reserve/request.pl (-2 / +9 lines)
Lines 181-188 if ($borrowernumber_hold && !$action) { Link Here
181
    # FIXME At this time we have a simple count of reservs, but, later, we could improve the infos "title" ...
181
    # FIXME At this time we have a simple count of reservs, but, later, we could improve the infos "title" ...
182
182
183
    my $reserves_count = $patron->holds->count;
183
    my $reserves_count = $patron->holds->count;
184
    $template->param(reserves_count => $reserves_count);
184
185
185
    my $new_reserves_count = scalar( @biblionumbers );
186
    my $new_reserves_count = scalar( @biblionumbers );
187
    $template->param(new_reserves_count   => $new_reserves_count);
186
188
187
    my $maxreserves = C4::Context->preference('maxreserves');
189
    my $maxreserves = C4::Context->preference('maxreserves');
188
    $template->param( maxreserves => $maxreserves );
190
    $template->param( maxreserves => $maxreserves );
Lines 198-205 if ($borrowernumber_hold && !$action) { Link Here
198
        $exceeded_maxreserves = 1;
200
        $exceeded_maxreserves = 1;
199
        $template->param(
201
        $template->param(
200
            new_reserves_allowed => $new_reserves_allowed,
202
            new_reserves_allowed => $new_reserves_allowed,
201
            new_reserves_count   => $new_reserves_count,
202
            reserves_count       => $reserves_count,
203
            maxreserves          => $maxreserves,
203
            maxreserves          => $maxreserves,
204
        );
204
        );
205
    }
205
    }
Lines 293-298 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
293
    my @biblioloop = ();
293
    my @biblioloop = ();
294
    my $no_reserves_allowed = 0;
294
    my $no_reserves_allowed = 0;
295
    my $num_bibs_available = 0;
295
    my $num_bibs_available = 0;
296
    my @canbookbereserved_responses;
296
    foreach my $biblionumber (@biblionumbers) {
297
    foreach my $biblionumber (@biblionumbers) {
297
        next unless $biblionumber =~ m|^\d+$|;
298
        next unless $biblionumber =~ m|^\d+$|;
298
299
Lines 311-316 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
311
        if ( $patron ) {
312
        if ( $patron ) {
312
            { # CanBookBeReserved
313
            { # CanBookBeReserved
313
                my $canReserve = CanBookBeReserved( $patron->borrowernumber, $biblionumber );
314
                my $canReserve = CanBookBeReserved( $patron->borrowernumber, $biblionumber );
315
316
                push @canbookbereserved_responses, { %$canReserve, biblio => $biblio };
317
314
                if ( $canReserve->{status} eq 'OK' ) {
318
                if ( $canReserve->{status} eq 'OK' ) {
315
319
316
                    #All is OK and we can continue
320
                    #All is OK and we can continue
Lines 694-699 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
694
698
695
    $template->param( no_bibs_available => 1 ) unless $num_bibs_available > 0;
699
    $template->param( no_bibs_available => 1 ) unless $num_bibs_available > 0;
696
700
701
    $Data::Dumper::Maxdepth = 3;
702
    use Data::Dumper; warn Dumper \@canbookbereserved_responses;
703
    $template->param( canbookbereserved_responses => \@canbookbereserved_responses );
697
    $template->param( biblioloop => \@biblioloop );
704
    $template->param( biblioloop => \@biblioloop );
698
    $template->param( no_reserves_allowed => $no_reserves_allowed );
705
    $template->param( no_reserves_allowed => $no_reserves_allowed );
699
    $template->param( exceeded_maxreserves => $exceeded_maxreserves );
706
    $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