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

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

Return to bug 29043