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

(-)a/reserve/request.pl (-197 / +274 lines)
Lines 437-676 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
437
              }
437
              }
438
        };
438
        };
439
439
440
        my @bibitemloop;
440
        if ( $club_hold or $borrowernumber_hold ) {
441
441
            my @bibitemloop;
442
        my @available_itemtypes;
442
            my @available_itemtypes;
443
        foreach my $biblioitemnumber (@biblioitemnumbers) {
443
            foreach my $biblioitemnumber (@biblioitemnumbers) {
444
            my $biblioitem = $biblioiteminfos_of->{$biblioitemnumber};
444
                my $biblioitem      = $biblioiteminfos_of->{$biblioitemnumber};
445
            my $num_available = 0;
445
                my $num_available   = 0;
446
            my $num_override  = 0;
446
                my $num_override    = 0;
447
            my $hiddencount   = 0;
447
                my $hiddencount     = 0;
448
            my $num_alreadyheld = 0;
448
                my $num_alreadyheld = 0;
449
449
450
            $biblioitem->{force_hold_level} = $force_hold_level;
450
                $biblioitem->{force_hold_level} = $force_hold_level;
451
452
                if ( $biblioitem->{biblioitemnumber} ne $biblionumber ) {
453
                    $biblioitem->{hostitemsflag} = 1;
454
                }
451
455
452
            if ( $biblioitem->{biblioitemnumber} ne $biblionumber ) {
456
                $biblioloopiter{description} = $biblioitem->{description};
453
                $biblioitem->{hostitemsflag} = 1;
457
                $biblioloopiter{itypename}   = $biblioitem->{description};
454
            }
458
                if ( $biblioitem->{itemtype} ) {
455
459
456
            $biblioloopiter{description} = $biblioitem->{description};
460
                    $biblioitem->{description} =
457
            $biblioloopiter{itypename}   = $biblioitem->{description};
461
                      $itemtypes->{ $biblioitem->{itemtype} }{description};
458
            if ( $biblioitem->{itemtype} ) {
459
462
460
                $biblioitem->{description} =
463
                    $biblioloopiter{imageurl} =
461
                  $itemtypes->{ $biblioitem->{itemtype} }{description};
464
                      getitemtypeimagelocation( 'intranet',
465
                        $itemtypes->{ $biblioitem->{itemtype} }{imageurl} );
466
                }
462
467
463
                $biblioloopiter{imageurl} =
468
   # iterating through all items first to check if any of them available
464
                  getitemtypeimagelocation( 'intranet',
469
   # to pass this value further inside down to IsAvailableForItemLevelRequest to
465
                    $itemtypes->{ $biblioitem->{itemtype} }{imageurl} );
470
   # it's complicated logic to analyse.
466
            }
471
   # (before this loop was inside that sub loop so it was O(n^2) )
472
                my $items_any_available;
473
                $items_any_available = ItemsAnyAvailableAndNotRestricted(
474
                    {
475
                        biblionumber => $biblioitem->{biblionumber},
476
                        patron       => $patron
477
                    }
478
                ) if $patron;
467
479
468
            # iterating through all items first to check if any of them available
480
                foreach my $itemnumber (
469
            # to pass this value further inside down to IsAvailableForItemLevelRequest to
481
                    @{ $itemnumbers_of_biblioitem{$biblioitemnumber} } )
470
            # it's complicated logic to analyse.
482
                {
471
            # (before this loop was inside that sub loop so it was O(n^2) )
483
                    my $item = $iteminfos_of->{$itemnumber};
472
            my $items_any_available;
484
                    my $do_check;
473
            $items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $biblioitem->{biblionumber}, patron => $patron })
485
                    if ($patron) {
474
                if $patron;
486
                        $do_check =
475
487
                          $patron->do_check_for_previous_checkout($item)
476
            foreach my $itemnumber ( @{ $itemnumbers_of_biblioitem{$biblioitemnumber} } )    {
488
                          if $wants_check;
477
                my $item = $iteminfos_of->{$itemnumber};
489
                        if ( $do_check && $wants_check ) {
478
                my $do_check;
490
                            $item->{checked_previously} = $do_check;
479
                if ( $patron ) {
491
                            if ($multi_hold) {
480
                    $do_check = $patron->do_check_for_previous_checkout($item) if $wants_check;
492
                                $biblioloopiter{checked_previously} = $do_check;
481
                    if ( $do_check && $wants_check ) {
493
                            }
482
                        $item->{checked_previously} = $do_check;
494
                            else {
483
                        if ( $multi_hold ) {
495
                                $template->param(
484
                            $biblioloopiter{checked_previously} = $do_check;
496
                                    checked_previously => $do_check );
485
                        } else {
497
                            }
486
                            $template->param( checked_previously => $do_check );
487
                        }
498
                        }
488
                    }
499
                    }
489
                }
500
                    $item->{force_hold_level} = $force_hold_level;
490
                $item->{force_hold_level} = $force_hold_level;
491
492
                unless (C4::Context->preference('item-level_itypes')) {
493
                    $item->{itype} = $biblioitem->{itemtype};
494
                }
495
496
                $item->{itypename} = $itemtypes->{ $item->{itype} }{description};
497
                $item->{imageurl} = getitemtypeimagelocation( 'intranet', $itemtypes->{ $item->{itype} }{imageurl} );
498
                $item->{homebranch} = $item->{homebranch};
499
501
500
                # if the holdingbranch is different than the homebranch, we show the
502
                    unless ( C4::Context->preference('item-level_itypes') ) {
501
                # holdingbranch of the document too
503
                        $item->{itype} = $biblioitem->{itemtype};
502
                if ( $item->{homebranch} ne $item->{holdingbranch} ) {
504
                    }
503
                    $item->{holdingbranch} = $item->{holdingbranch};
504
                }
505
506
                if($item->{biblionumber} ne $biblionumber){
507
                    $item->{hostitemsflag} = 1;
508
                    $item->{hosttitle} = Koha::Biblios->find( $item->{biblionumber} )->title;
509
                }
510
505
511
                # if the item is currently on loan, we display its return date and
506
                    $item->{itypename} =
512
                # change the background color
507
                      $itemtypes->{ $item->{itype} }{description};
513
                my $issue = Koha::Checkouts->find( { itemnumber => $itemnumber } );
508
                    $item->{imageurl} = getitemtypeimagelocation( 'intranet',
514
                if ( $issue ) {
509
                        $itemtypes->{ $item->{itype} }{imageurl} );
515
                    $item->{date_due} = $issue->date_due;
510
                    $item->{homebranch} = $item->{homebranch};
516
                    $item->{backgroundcolor} = 'onloan';
517
                }
518
511
519
                # checking reserve
512
            # if the holdingbranch is different than the homebranch, we show the
520
                my $item_object = Koha::Items->find( $itemnumber );
513
            # holdingbranch of the document too
521
                my $holds = $item_object->current_holds;
514
                    if ( $item->{homebranch} ne $item->{holdingbranch} ) {
522
                if ( my $first_hold = $holds->next ) {
515
                        $item->{holdingbranch} = $item->{holdingbranch};
523
                    my $p = Koha::Patrons->find( $first_hold->borrowernumber );
516
                    }
524
525
                    $item->{backgroundcolor} = 'reserved';
526
                    $item->{reservedate}     = output_pref({ dt => dt_from_string( $first_hold->reservedate ), dateonly => 1 }); # FIXME Should be formatted in the template
527
                    $item->{ReservedFor}     = $p;
528
                    $item->{ExpectedAtLibrary}     = $first_hold->branchcode;
529
                    $item->{waitingdate} = $first_hold->waitingdate;
530
                }
531
517
532
                # Management of the notforloan document
518
                    if ( $item->{biblionumber} ne $biblionumber ) {
533
                if ( $item->{notforloan} ) {
519
                        $item->{hostitemsflag} = 1;
534
                    $item->{backgroundcolor} = 'other';
520
                        $item->{hosttitle} =
535
                }
521
                          Koha::Biblios->find( $item->{biblionumber} )->title;
522
                    }
536
523
537
                # Management of lost or long overdue items
524
              # if the item is currently on loan, we display its return date and
538
                if ( $item->{itemlost} ) {
525
              # change the background color
539
                    $item->{backgroundcolor} = 'other';
526
                    my $issue =
540
                    if ($logged_in_patron->category->hidelostitems && !$showallitems) {
527
                      Koha::Checkouts->find( { itemnumber => $itemnumber } );
541
                        $item->{hide} = 1;
528
                    if ($issue) {
542
                        $hiddencount++;
529
                        $item->{date_due}        = $issue->date_due;
530
                        $item->{backgroundcolor} = 'onloan';
543
                    }
531
                    }
544
                }
545
532
546
                # Check the transit status
533
                    # checking reserve
547
                my ( $transfertwhen, $transfertfrom, $transfertto ) =
534
                    my $item_object = Koha::Items->find($itemnumber);
548
                  GetTransfers($itemnumber);
535
                    my $holds       = $item_object->current_holds;
536
                    if ( my $first_hold = $holds->next ) {
537
                        my $p =
538
                          Koha::Patrons->find( $first_hold->borrowernumber );
539
540
                        $item->{backgroundcolor} = 'reserved';
541
                        $item->{reservedate}     = output_pref(
542
                            {
543
                                dt =>
544
                                  dt_from_string( $first_hold->reservedate ),
545
                                dateonly => 1
546
                            }
547
                        );    # FIXME Should be formatted in the template
548
                        $item->{ReservedFor}       = $p;
549
                        $item->{ExpectedAtLibrary} = $first_hold->branchcode;
550
                        $item->{waitingdate}       = $first_hold->waitingdate;
551
                    }
549
552
550
                if ( defined $transfertwhen && $transfertwhen ne '' ) {
553
                    # Management of the notforloan document
551
                    $item->{transfertwhen} = output_pref({ dt => dt_from_string( $transfertwhen ), dateonly => 1 });
554
                    if ( $item->{notforloan} ) {
552
                    $item->{transfertfrom} = $transfertfrom;
555
                        $item->{backgroundcolor} = 'other';
553
                    $item->{transfertto} = $transfertto;
556
                    }
554
                    $item->{nocancel} = 1;
555
                }
556
557
557
                # If there is no loan, return and transfer, we show a checkbox.
558
                    # Management of lost or long overdue items
558
                $item->{notforloan} ||= 0;
559
                    if ( $item->{itemlost} ) {
559
560
                        $item->{backgroundcolor} = 'other';
560
                # if independent branches is on we need to check if the person can reserve
561
                        if ( $logged_in_patron->category->hidelostitems
561
                # for branches they arent logged in to
562
                            && !$showallitems )
562
                if ( C4::Context->preference("IndependentBranches") ) {
563
                        {
563
                    if (! C4::Context->preference("canreservefromotherbranches")){
564
                            $item->{hide} = 1;
564
                        # can't reserve items so need to check if item homebranch and userenv branch match if not we can't reserve
565
                            $hiddencount++;
565
                        my $userenv = C4::Context->userenv;
566
                        unless ( C4::Context->IsSuperLibrarian ) {
567
                            $item->{cantreserve} = 1 if ( $item->{homebranch} ne $userenv->{branch} );
568
                        }
566
                        }
569
                    }
567
                    }
570
                }
571
568
572
                if ( $patron ) {
569
                    # Check the transit status
573
                    my $patron_unblessed = $patron->unblessed;
570
                    my ( $transfertwhen, $transfertfrom, $transfertto ) =
574
                    my $branch = C4::Circulation::_GetCircControlBranch($item, $patron_unblessed);
571
                      GetTransfers($itemnumber);
575
572
576
                    my $branchitemrule = GetBranchItemRule( $branch, $item->{'itype'} );
573
                    if ( defined $transfertwhen && $transfertwhen ne '' ) {
577
574
                        $item->{transfertwhen} = output_pref(
578
                    $item->{'holdallowed'} = $branchitemrule->{'holdallowed'};
575
                            {
579
576
                                dt       => dt_from_string($transfertwhen),
580
                    my $can_item_be_reserved = CanItemBeReserved( $patron->borrowernumber, $itemnumber )->{status};
577
                                dateonly => 1
581
                    $item->{not_holdable} = $can_item_be_reserved unless ( $can_item_be_reserved eq 'OK' );
582
583
                    $item->{item_level_holds} = Koha::CirculationRules->get_opacitemholds_policy( { item => $item_object, patron => $patron } );
584
585
                    if (
586
                           !$item->{cantreserve}
587
                        && !$exceeded_maxreserves
588
                        && $can_item_be_reserved eq 'OK'
589
                        # items_any_available defined outside of the current loop,
590
                        # so we avoiding loop inside IsAvailableForItemLevelRequest:
591
                        && IsAvailableForItemLevelRequest($item_object, $patron, undef, $items_any_available)
592
                      )
593
                    {
594
                        # Send the pickup locations count to the UI, the pickup locations will be pulled using the API
595
                        my @pickup_locations = $item_object->pickup_locations({ patron => $patron })->as_list;
596
                        $item->{pickup_locations_count} = scalar @pickup_locations;
597
598
                        if ( @pickup_locations ) {
599
                            $num_available++;
600
                            $item->{available} = 1;
601
602
                            my $default_pickup_location;
603
604
                            # Default to logged-in, if valid
605
                            if ( C4::Context->userenv->{branch} ) {
606
                                ($default_pickup_location) = grep { $_->branchcode eq C4::Context->userenv->{branch} } @pickup_locations;
607
                            }
578
                            }
579
                        );
580
                        $item->{transfertfrom} = $transfertfrom;
581
                        $item->{transfertto}   = $transfertto;
582
                        $item->{nocancel}      = 1;
583
                    }
608
584
609
                            $item->{default_pickup_location} = $default_pickup_location;
585
                 # If there is no loan, return and transfer, we show a checkbox.
610
                        }
586
                    $item->{notforloan} ||= 0;
611
                        else {
587
612
                            $item->{available} = 0;
588
      # if independent branches is on we need to check if the person can reserve
613
                            $item->{not_holdable} = "no_valid_pickup_location";
589
      # for branches they arent logged in to
590
                    if ( C4::Context->preference("IndependentBranches") ) {
591
                        if (
592
                            !C4::Context->preference(
593
                                "canreservefromotherbranches")
594
                          )
595
                        {
596
# can't reserve items so need to check if item homebranch and userenv branch match if not we can't reserve
597
                            my $userenv = C4::Context->userenv;
598
                            unless ( C4::Context->IsSuperLibrarian ) {
599
                                $item->{cantreserve} = 1
600
                                  if (
601
                                    $item->{homebranch} ne $userenv->{branch} );
602
                            }
614
                        }
603
                        }
615
616
                        push( @available_itemtypes, $item->{itype} );
617
                    }
604
                    }
618
                    elsif ( C4::Context->preference('AllowHoldPolicyOverride') ) {
605
619
                        # If AllowHoldPolicyOverride is set, it should override EVERY restriction, not just branch item rules
606
                    if ($patron) {
620
                        # with the exception of itemAlreadyOnHold because, you know, the item is already on hold
607
                        my $patron_unblessed = $patron->unblessed;
621
                        if ( $can_item_be_reserved ne 'itemAlreadyOnHold' ) {
608
                        my $branch =
622
                            # Send the pickup locations count to the UI, the pickup locations will be pulled using the API
609
                          C4::Circulation::_GetCircControlBranch( $item,
623
                            my $pickup_locations = $item_object->pickup_locations({ patron => $patron });
610
                            $patron_unblessed );
624
                            $item->{pickup_locations_count} = $pickup_locations->count;
611
625
                            if ( $item->{pickup_locations_count} > 0 ) {
612
                        my $branchitemrule =
626
                                $item->{override} = 1;
613
                          GetBranchItemRule( $branch, $item->{'itype'} );
627
                                $num_override++;
614
628
                                # pass the holding branch for use as default
615
                        $item->{'holdallowed'} =
629
                                my $default_pickup_location = $pickup_locations->search({ branchcode => $item->{holdingbranch} })->next;
616
                          $branchitemrule->{'holdallowed'};
630
                                $item->{default_pickup_location} = $default_pickup_location;
617
618
                        my $can_item_be_reserved =
619
                          CanItemBeReserved( $patron->borrowernumber,
620
                            $itemnumber )->{status};
621
                        $item->{not_holdable} = $can_item_be_reserved
622
                          unless ( $can_item_be_reserved eq 'OK' );
623
624
                        $item->{item_level_holds} =
625
                          Koha::CirculationRules->get_opacitemholds_policy(
626
                            { item => $item_object, patron => $patron } );
627
628
                        if (
629
                               !$item->{cantreserve}
630
                            && !$exceeded_maxreserves
631
                            && $can_item_be_reserved eq 'OK'
632
633
                    # items_any_available defined outside of the current loop,
634
                    # so we avoiding loop inside IsAvailableForItemLevelRequest:
635
                            && IsAvailableForItemLevelRequest(
636
                                $item_object, $patron,
637
                                undef,        $items_any_available
638
                            )
639
                          )
640
                        {
641
# Send the pickup locations count to the UI, the pickup locations will be pulled using the API
642
                            my @pickup_locations =
643
                              $item_object->pickup_locations(
644
                                { patron => $patron } )->as_list;
645
                            $item->{pickup_locations_count} =
646
                              scalar @pickup_locations;
647
648
                            if (@pickup_locations) {
649
                                $num_available++;
650
                                $item->{available} = 1;
651
652
                                my $default_pickup_location;
653
654
                                # Default to logged-in, if valid
655
                                if ( C4::Context->userenv->{branch} ) {
656
                                    ($default_pickup_location) = grep {
657
                                        $_->branchcode eq
658
                                          C4::Context->userenv->{branch}
659
                                    } @pickup_locations;
660
                                }
661
662
                                $item->{default_pickup_location} =
663
                                  $default_pickup_location;
631
                            }
664
                            }
632
                            else {
665
                            else {
633
                                $item->{available} = 0;
666
                                $item->{available} = 0;
634
                                $item->{not_holdable} = "no_valid_pickup_location";
667
                                $item->{not_holdable} =
668
                                  "no_valid_pickup_location";
635
                            }
669
                            }
636
                        } else { $num_alreadyheld++ }
637
670
638
                        push( @available_itemtypes, $item->{itype} );
671
                            push( @available_itemtypes, $item->{itype} );
639
                    }
672
                        }
673
                        elsif (
674
                            C4::Context->preference('AllowHoldPolicyOverride') )
675
                        {
676
# If AllowHoldPolicyOverride is set, it should override EVERY restriction, not just branch item rules
677
# with the exception of itemAlreadyOnHold because, you know, the item is already on hold
678
                            if ( $can_item_be_reserved ne 'itemAlreadyOnHold' )
679
                            {
680
# Send the pickup locations count to the UI, the pickup locations will be pulled using the API
681
                                my $pickup_locations =
682
                                  $item_object->pickup_locations(
683
                                    { patron => $patron } );
684
                                $item->{pickup_locations_count} =
685
                                  $pickup_locations->count;
686
                                if ( $item->{pickup_locations_count} > 0 ) {
687
                                    $item->{override} = 1;
688
                                    $num_override++;
689
690
                                    # pass the holding branch for use as default
691
                                    my $default_pickup_location =
692
                                      $pickup_locations->search(
693
                                        {
694
                                            branchcode => $item->{holdingbranch}
695
                                        }
696
                                    )->next;
697
                                    $item->{default_pickup_location} =
698
                                      $default_pickup_location;
699
                                }
700
                                else {
701
                                    $item->{available} = 0;
702
                                    $item->{not_holdable} =
703
                                      "no_valid_pickup_location";
704
                                }
705
                            }
706
                            else { $num_alreadyheld++ }
640
707
641
                    # If none of the conditions hold true, then neither override nor available is set and the item cannot be checked
708
                            push( @available_itemtypes, $item->{itype} );
709
                        }
642
710
643
                    # Show serial enumeration when needed
711
# If none of the conditions hold true, then neither override nor available is set and the item cannot be checked
644
                    if ($item->{enumchron}) {
712
645
                        $itemdata_enumchron = 1;
713
                        # Show serial enumeration when needed
646
                    }
714
                        if ( $item->{enumchron} ) {
647
                    # Show collection when needed
715
                            $itemdata_enumchron = 1;
648
                    if ($item->{ccode}) {
716
                        }
649
                        $itemdata_ccode = 1;
717
718
                        # Show collection when needed
719
                        if ( $item->{ccode} ) {
720
                            $itemdata_ccode = 1;
721
                        }
650
                    }
722
                    }
723
724
                    push @{ $biblioitem->{itemloop} }, $item;
651
                }
725
                }
652
726
653
                push @{ $biblioitem->{itemloop} }, $item;
727
# While we can't override an alreay held item, we should be able to override the others
654
            }
728
# Unless all items are already held
729
                if ( $num_override > 0
730
                    && ( $num_override + $num_alreadyheld ) ==
731
                    scalar( @{ $biblioitem->{itemloop} } ) )
732
                {
733
                    # That is, if all items require an override
734
                    $template->param( override_required => 1 );
735
                }
736
                elsif ( $num_available == 0 ) {
737
                    $template->param( none_available => 1 );
738
                    $biblioloopiter{warn}       = 1;
739
                    $biblioloopiter{none_avail} = 1;
740
                }
741
                $template->param( hiddencount => $hiddencount );
655
742
656
            # While we can't override an alreay held item, we should be able to override the others
743
                push @bibitemloop, $biblioitem;
657
            # Unless all items are already held
658
            if ( $num_override > 0 && ($num_override + $num_alreadyheld) == scalar( @{ $biblioitem->{itemloop} } ) ) {
659
            # That is, if all items require an override
660
                $template->param( override_required => 1 );
661
            } elsif ( $num_available == 0 ) {
662
                $template->param( none_available => 1 );
663
                $biblioloopiter{warn} = 1;
664
                $biblioloopiter{none_avail} = 1;
665
            }
744
            }
666
            $template->param( hiddencount => $hiddencount);
667
745
668
            push @bibitemloop, $biblioitem;
746
            @available_itemtypes = uniq(@available_itemtypes);
747
            $template->param(
748
                bibitemloop         => \@bibitemloop,
749
                available_itemtypes => \@available_itemtypes
750
            );
669
        }
751
        }
670
752
671
        @available_itemtypes = uniq( @available_itemtypes );
672
        $template->param( available_itemtypes => \@available_itemtypes );
673
674
        # existingreserves building
753
        # existingreserves building
675
        my @reserveloop;
754
        my @reserveloop;
676
        my @reserves = Koha::Holds->search( { biblionumber => $biblionumber }, { order_by => 'priority' } );
755
        my @reserves = Koha::Holds->search( { biblionumber => $biblionumber }, { order_by => 'priority' } );
Lines 736-742 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
736
815
737
        # display infos
816
        # display infos
738
        $template->param(
817
        $template->param(
739
                         bibitemloop       => \@bibitemloop,
740
                         itemdata_enumchron => $itemdata_enumchron,
818
                         itemdata_enumchron => $itemdata_enumchron,
741
                         itemdata_ccode    => $itemdata_ccode,
819
                         itemdata_ccode    => $itemdata_ccode,
742
                         date              => $date,
820
                         date              => $date,
743
- 

Return to bug 29043