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

(-)a/reserve/request.pl (-400 / +417 lines)
Lines 196-201 $template->param( Link Here
196
    multi_hold => $multi_hold,
196
    multi_hold => $multi_hold,
197
);
197
);
198
198
199
# If we are coming from the search result and only 1 is selected
200
$biblionumber ||= $biblionumbers[0] unless $multi_hold;
201
199
# If we have the borrowernumber because we've performed an action, then we
202
# If we have the borrowernumber because we've performed an action, then we
200
# don't want to try to place another reserve.
203
# don't want to try to place another reserve.
201
if ($borrowernumber_hold && !$action) {
204
if ($borrowernumber_hold && !$action) {
Lines 291-768 $template->param( Link Here
291
    messageclub     => $messageclub
294
    messageclub     => $messageclub
292
);
295
);
293
296
294
# FIXME launch another time GetMember perhaps until (Joubu: Why?)
297
# Load the hold list if
295
my $patron = Koha::Patrons->find( $borrowernumber_hold );
298
#  - we are searching for a patron or club and found one
296
299
#  - we are not searching for anything
297
if ( $patron && $multi_hold ) {
300
if (   ( $findborrower && $borrowernumber_hold || $findclub && $club_hold )
298
    my @multi_pickup_locations =
301
    || ( !$findborrower && !$findclub ) )
299
      Koha::Biblios->search( { biblionumber => \@biblionumbers } )
302
{
300
      ->pickup_locations( { patron => $patron } )->as_list;
303
    # FIXME launch another time GetMember perhaps until (Joubu: Why?)
301
    $template->param( multi_pickup_locations => \@multi_pickup_locations );
304
    my $patron = Koha::Patrons->find( $borrowernumber_hold );
302
}
303
304
my $logged_in_patron = Koha::Patrons->find( $borrowernumber );
305
306
my $wants_check;
307
if ($patron) {
308
    $wants_check = $patron->wants_check_for_previous_checkout;
309
}
310
my $itemdata_enumchron = 0;
311
my $itemdata_ccode = 0;
312
my @biblioloop = ();
313
my $no_reserves_allowed = 0;
314
foreach my $biblionumber (@biblionumbers) {
315
    next unless $biblionumber =~ m|^\d+$|;
316
317
    my %biblioloopiter = ();
318
305
319
    my $biblio = Koha::Biblios->find( $biblionumber );
306
    if ( $patron && $multi_hold ) {
320
    unless ($biblio) {
307
        my @multi_pickup_locations =
321
        $biblioloopiter{noitems} = 1;
308
          Koha::Biblios->search( { biblionumber => \@biblionumbers } )
322
        $template->param('nobiblio' => 1);
309
          ->pickup_locations( { patron => $patron } )->as_list;
323
        last;
310
        $template->param( multi_pickup_locations => \@multi_pickup_locations );
324
    }
311
    }
325
312
326
    my $force_hold_level;
313
    my $logged_in_patron = Koha::Patrons->find( $borrowernumber );
327
    if ( $patron ) {
328
        { # CanBookBeReserved
329
            my $canReserve = CanBookBeReserved( $patron->borrowernumber, $biblionumber );
330
            if ( $canReserve->{status} eq 'OK' ) {
331
332
                #All is OK and we can continue
333
            }
334
            elsif ( $canReserve->{status} eq 'noReservesAllowed' || $canReserve->{status} eq 'notReservable' ) {
335
                $no_reserves_allowed = 1;
336
            }
337
            elsif ( $canReserve->{status} eq 'tooManyReserves' ) {
338
                $exceeded_maxreserves = 1;
339
                $template->param( maxreserves => $canReserve->{limit} );
340
            }
341
            elsif ( $canReserve->{status} eq 'tooManyHoldsForThisRecord' ) {
342
                $exceeded_holds_per_record = 1;
343
                $biblioloopiter{ $canReserve->{status} } = 1;
344
            }
345
            elsif ( $canReserve->{status} eq 'ageRestricted' ) {
346
                $template->param( $canReserve->{status} => 1 );
347
                $biblioloopiter{ $canReserve->{status} } = 1;
348
            }
349
            elsif ( $canReserve->{status} eq 'alreadypossession' ) {
350
                $template->param( $canReserve->{status} => 1);
351
                $biblioloopiter{ $canReserve->{status} } = 1;
352
            }
353
            else {
354
                $biblioloopiter{ $canReserve->{status} } = 1;
355
            }
356
        }
357
314
358
        # For multiple holds per record, if a patron has previously placed a hold,
315
    my $wants_check;
359
        # the patron can only place more holds of the same type. That is, if the
316
    if ($patron) {
360
        # patron placed a record level hold, all the holds the patron places must
317
        $wants_check = $patron->wants_check_for_previous_checkout;
361
        # be record level. If the patron placed an item level hold, all holds
362
        # the patron places must be item level
363
        my $holds = Koha::Holds->search(
364
            {
365
                borrowernumber => $patron->borrowernumber,
366
                biblionumber   => $biblionumber,
367
                found          => undef,
368
            }
369
        );
370
        $force_hold_level = $holds->forced_hold_level();
371
        $biblioloopiter{force_hold_level} = $force_hold_level;
372
        $template->param( force_hold_level => $force_hold_level );
373
374
        # For a librarian to be able to place multiple record holds for a patron for a record,
375
        # we must find out what the maximum number of holds they can place for the patron is
376
        my $max_holds_for_record = GetMaxPatronHoldsForRecord( $patron->borrowernumber, $biblionumber );
377
        my $remaining_holds_for_record = $max_holds_for_record - $holds->count();
378
        $biblioloopiter{remaining_holds_for_record} = $max_holds_for_record;
379
        $template->param( max_holds_for_record => $max_holds_for_record );
380
        $template->param( remaining_holds_for_record => $remaining_holds_for_record );
381
    }
318
    }
319
    my $itemdata_enumchron = 0;
320
    my $itemdata_ccode = 0;
321
    my @biblioloop = ();
322
    my $no_reserves_allowed = 0;
323
    foreach my $biblionumber (@biblionumbers) {
324
        next unless $biblionumber =~ m|^\d+$|;
325
326
        my %biblioloopiter = ();
327
328
        my $biblio = Koha::Biblios->find( $biblionumber );
329
        unless ($biblio) {
330
            $biblioloopiter{noitems} = 1;
331
            $template->param('nobiblio' => 1);
332
            last;
333
        }
382
334
335
        my $force_hold_level;
336
        if ( $patron ) {
337
            { # CanBookBeReserved
338
                my $canReserve = CanBookBeReserved( $patron->borrowernumber, $biblionumber );
339
                if ( $canReserve->{status} eq 'OK' ) {
383
340
384
    my $count = Koha::Holds->search( { biblionumber => $biblionumber } )->count();
341
                    #All is OK and we can continue
385
    my $totalcount = $count;
342
                }
386
343
                elsif ( $canReserve->{status} eq 'noReservesAllowed' || $canReserve->{status} eq 'notReservable' ) {
387
    # adding a fixed value for priority options
344
                    $no_reserves_allowed = 1;
388
    my $fixedRank = $count+1;
345
                }
389
346
                elsif ( $canReserve->{status} eq 'tooManyReserves' ) {
390
    my %itemnumbers_of_biblioitem;
347
                    $exceeded_maxreserves = 1;
348
                    $template->param( maxreserves => $canReserve->{limit} );
349
                }
350
                elsif ( $canReserve->{status} eq 'tooManyHoldsForThisRecord' ) {
351
                    $exceeded_holds_per_record = 1;
352
                    $biblioloopiter{ $canReserve->{status} } = 1;
353
                }
354
                elsif ( $canReserve->{status} eq 'ageRestricted' ) {
355
                    $template->param( $canReserve->{status} => 1 );
356
                    $biblioloopiter{ $canReserve->{status} } = 1;
357
                }
358
                elsif ( $canReserve->{status} eq 'alreadypossession' ) {
359
                    $template->param( $canReserve->{status} => 1);
360
                    $biblioloopiter{ $canReserve->{status} } = 1;
361
                }
362
                else {
363
                    $biblioloopiter{ $canReserve->{status} } = 1;
364
                }
365
            }
391
366
392
    my @hostitems = get_hostitemnumbers_of($biblionumber);
367
            # For multiple holds per record, if a patron has previously placed a hold,
393
    my @itemnumbers;
368
            # the patron can only place more holds of the same type. That is, if the
394
    if (@hostitems){
369
            # patron placed a record level hold, all the holds the patron places must
395
        $template->param('hostitemsflag' => 1);
370
            # be record level. If the patron placed an item level hold, all holds
396
        push(@itemnumbers, @hostitems);
371
            # the patron places must be item level
397
    }
372
            my $holds = Koha::Holds->search(
373
                {
374
                    borrowernumber => $patron->borrowernumber,
375
                    biblionumber   => $biblionumber,
376
                    found          => undef,
377
                }
378
            );
379
            $force_hold_level = $holds->forced_hold_level();
380
            $biblioloopiter{force_hold_level} = $force_hold_level;
381
            $template->param( force_hold_level => $force_hold_level );
382
383
            # For a librarian to be able to place multiple record holds for a patron for a record,
384
            # we must find out what the maximum number of holds they can place for the patron is
385
            my $max_holds_for_record = GetMaxPatronHoldsForRecord( $patron->borrowernumber, $biblionumber );
386
            my $remaining_holds_for_record = $max_holds_for_record - $holds->count();
387
            $biblioloopiter{remaining_holds_for_record} = $max_holds_for_record;
388
            $template->param( max_holds_for_record => $max_holds_for_record );
389
            $template->param( remaining_holds_for_record => $remaining_holds_for_record );
390
        }
398
391
399
    my $items = Koha::Items->search({ -or => { biblionumber => $biblionumber, itemnumber => { in => \@itemnumbers } } });
400
392
401
    unless ( $items->count ) {
393
        my $count = Koha::Holds->search( { biblionumber => $biblionumber } )->count();
402
        # FIXME Then why do we continue?
394
        my $totalcount = $count;
403
        $template->param('noitems' => 1) unless ( $multi_hold );
404
        $biblioloopiter{noitems} = 1;
405
    }
406
395
407
    ## Here we go backwards again to create hash of biblioitemnumber to itemnumbers
396
        # adding a fixed value for priority options
408
    ## this is important when we have analytic items which may be on another record
397
        my $fixedRank = $count+1;
409
    my ( $iteminfos_of );
410
    while ( my $item = $items->next ) {
411
        $item = $item->unblessed;
412
        my $biblioitemnumber = $item->{biblioitemnumber};
413
        my $itemnumber = $item->{itemnumber};
414
        push( @{ $itemnumbers_of_biblioitem{$biblioitemnumber} }, $itemnumber );
415
        $iteminfos_of->{$itemnumber} = $item;
416
    }
417
398
418
    my @biblioitemnumbers = keys %itemnumbers_of_biblioitem;
399
        my %itemnumbers_of_biblioitem;
419
420
    my $biblioiteminfos_of = {
421
        map {
422
            my $biblioitem = $_;
423
            ( $biblioitem->{biblioitemnumber} => $biblioitem )
424
          } @{ Koha::Biblioitems->search(
425
                { biblioitemnumber => { -in => \@biblioitemnumbers } },
426
                { select => ['biblionumber', 'biblioitemnumber', 'publicationyear', 'itemtype']}
427
            )->unblessed
428
          }
429
    };
430
400
431
    my @bibitemloop;
401
        my @hostitems = get_hostitemnumbers_of($biblionumber);
402
        my @itemnumbers;
403
        if (@hostitems){
404
            $template->param('hostitemsflag' => 1);
405
            push(@itemnumbers, @hostitems);
406
        }
432
407
433
    my @available_itemtypes;
408
        my $items = Koha::Items->search({ -or => { biblionumber => $biblionumber, itemnumber => { in => \@itemnumbers } } });
434
    foreach my $biblioitemnumber (@biblioitemnumbers) {
435
        my $biblioitem = $biblioiteminfos_of->{$biblioitemnumber};
436
        my $num_available = 0;
437
        my $num_override  = 0;
438
        my $hiddencount   = 0;
439
        my $num_alreadyheld = 0;
440
409
441
        $biblioitem->{force_hold_level} = $force_hold_level;
410
        unless ( $items->count ) {
411
            # FIXME Then why do we continue?
412
            $template->param('noitems' => 1) unless ( $multi_hold );
413
            $biblioloopiter{noitems} = 1;
414
        }
442
415
443
        if ( $biblioitem->{biblioitemnumber} ne $biblionumber ) {
416
        ## Here we go backwards again to create hash of biblioitemnumber to itemnumbers
444
            $biblioitem->{hostitemsflag} = 1;
417
        ## this is important when we have analytic items which may be on another record
418
        my ( $iteminfos_of );
419
        while ( my $item = $items->next ) {
420
            $item = $item->unblessed;
421
            my $biblioitemnumber = $item->{biblioitemnumber};
422
            my $itemnumber = $item->{itemnumber};
423
            push( @{ $itemnumbers_of_biblioitem{$biblioitemnumber} }, $itemnumber );
424
            $iteminfos_of->{$itemnumber} = $item;
445
        }
425
        }
446
426
447
        $biblioloopiter{description} = $biblioitem->{description};
427
        my @biblioitemnumbers = keys %itemnumbers_of_biblioitem;
448
        $biblioloopiter{itypename}   = $biblioitem->{description};
428
449
        if ( $biblioitem->{itemtype} ) {
429
        my $biblioiteminfos_of = {
430
            map {
431
                my $biblioitem = $_;
432
                ( $biblioitem->{biblioitemnumber} => $biblioitem )
433
              } @{ Koha::Biblioitems->search(
434
                    { biblioitemnumber => { -in => \@biblioitemnumbers } },
435
                    { select => ['biblionumber', 'biblioitemnumber', 'publicationyear', 'itemtype']}
436
                )->unblessed
437
              }
438
        };
439
440
        my @bibitemloop;
441
442
        my @available_itemtypes;
443
        foreach my $biblioitemnumber (@biblioitemnumbers) {
444
            my $biblioitem = $biblioiteminfos_of->{$biblioitemnumber};
445
            my $num_available = 0;
446
            my $num_override  = 0;
447
            my $hiddencount   = 0;
448
            my $num_alreadyheld = 0;
449
450
            $biblioitem->{force_hold_level} = $force_hold_level;
451
452
            if ( $biblioitem->{biblioitemnumber} ne $biblionumber ) {
453
                $biblioitem->{hostitemsflag} = 1;
454
            }
450
455
451
            $biblioitem->{description} =
456
            $biblioloopiter{description} = $biblioitem->{description};
452
              $itemtypes->{ $biblioitem->{itemtype} }{description};
457
            $biblioloopiter{itypename}   = $biblioitem->{description};
458
            if ( $biblioitem->{itemtype} ) {
453
459
454
            $biblioloopiter{imageurl} =
460
                $biblioitem->{description} =
455
              getitemtypeimagelocation( 'intranet',
461
                  $itemtypes->{ $biblioitem->{itemtype} }{description};
456
                $itemtypes->{ $biblioitem->{itemtype} }{imageurl} );
462
457
        }
463
                $biblioloopiter{imageurl} =
464
                  getitemtypeimagelocation( 'intranet',
465
                    $itemtypes->{ $biblioitem->{itemtype} }{imageurl} );
466
            }
458
467
459
        # iterating through all items first to check if any of them available
468
            # iterating through all items first to check if any of them available
460
        # to pass this value further inside down to IsAvailableForItemLevelRequest to
469
            # to pass this value further inside down to IsAvailableForItemLevelRequest to
461
        # it's complicated logic to analyse.
470
            # it's complicated logic to analyse.
462
        # (before this loop was inside that sub loop so it was O(n^2) )
471
            # (before this loop was inside that sub loop so it was O(n^2) )
463
        my $items_any_available;
472
            my $items_any_available;
464
        $items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $biblioitem->{biblionumber}, patron => $patron })
473
            $items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $biblioitem->{biblionumber}, patron => $patron })
465
            if $patron;
474
                if $patron;
466
475
467
        foreach my $itemnumber ( @{ $itemnumbers_of_biblioitem{$biblioitemnumber} } )    {
476
            foreach my $itemnumber ( @{ $itemnumbers_of_biblioitem{$biblioitemnumber} } )    {
468
            my $item = $iteminfos_of->{$itemnumber};
477
                my $item = $iteminfos_of->{$itemnumber};
469
            my $do_check;
478
                my $do_check;
470
            if ( $patron ) {
479
                if ( $patron ) {
471
                $do_check = $patron->do_check_for_previous_checkout($item) if $wants_check;
480
                    $do_check = $patron->do_check_for_previous_checkout($item) if $wants_check;
472
                if ( $do_check && $wants_check ) {
481
                    if ( $do_check && $wants_check ) {
473
                    $item->{checked_previously} = $do_check;
482
                        $item->{checked_previously} = $do_check;
474
                    if ( $multi_hold ) {
483
                        if ( $multi_hold ) {
475
                        $biblioloopiter{checked_previously} = $do_check;
484
                            $biblioloopiter{checked_previously} = $do_check;
476
                    } else {
485
                        } else {
477
                        $template->param( checked_previously => $do_check );
486
                            $template->param( checked_previously => $do_check );
487
                        }
478
                    }
488
                    }
479
                }
489
                }
480
            }
490
                $item->{force_hold_level} = $force_hold_level;
481
            $item->{force_hold_level} = $force_hold_level;
482
491
483
            unless (C4::Context->preference('item-level_itypes')) {
492
                unless (C4::Context->preference('item-level_itypes')) {
484
                $item->{itype} = $biblioitem->{itemtype};
493
                    $item->{itype} = $biblioitem->{itemtype};
485
            }
494
                }
486
495
487
            $item->{itypename} = $itemtypes->{ $item->{itype} }{description};
496
                $item->{itypename} = $itemtypes->{ $item->{itype} }{description};
488
            $item->{imageurl} = getitemtypeimagelocation( 'intranet', $itemtypes->{ $item->{itype} }{imageurl} );
497
                $item->{imageurl} = getitemtypeimagelocation( 'intranet', $itemtypes->{ $item->{itype} }{imageurl} );
489
            $item->{homebranch} = $item->{homebranch};
498
                $item->{homebranch} = $item->{homebranch};
490
499
491
            # if the holdingbranch is different than the homebranch, we show the
500
                # if the holdingbranch is different than the homebranch, we show the
492
            # holdingbranch of the document too
501
                # holdingbranch of the document too
493
            if ( $item->{homebranch} ne $item->{holdingbranch} ) {
502
                if ( $item->{homebranch} ne $item->{holdingbranch} ) {
494
                $item->{holdingbranch} = $item->{holdingbranch};
503
                    $item->{holdingbranch} = $item->{holdingbranch};
495
            }
504
                }
496
505
497
            if($item->{biblionumber} ne $biblionumber){
506
                if($item->{biblionumber} ne $biblionumber){
498
                $item->{hostitemsflag} = 1;
507
                    $item->{hostitemsflag} = 1;
499
                $item->{hosttitle} = Koha::Biblios->find( $item->{biblionumber} )->title;
508
                    $item->{hosttitle} = Koha::Biblios->find( $item->{biblionumber} )->title;
500
            }
509
                }
501
510
502
            # if the item is currently on loan, we display its return date and
511
                # if the item is currently on loan, we display its return date and
503
            # change the background color
512
                # change the background color
504
            my $issue = Koha::Checkouts->find( { itemnumber => $itemnumber } );
513
                my $issue = Koha::Checkouts->find( { itemnumber => $itemnumber } );
505
            if ( $issue ) {
514
                if ( $issue ) {
506
                $item->{date_due} = $issue->date_due;
515
                    $item->{date_due} = $issue->date_due;
507
                $item->{backgroundcolor} = 'onloan';
516
                    $item->{backgroundcolor} = 'onloan';
508
            }
517
                }
509
518
510
            # checking reserve
519
                # checking reserve
511
            my $item_object = Koha::Items->find( $itemnumber );
520
                my $item_object = Koha::Items->find( $itemnumber );
512
            my $holds = $item_object->current_holds;
521
                my $holds = $item_object->current_holds;
513
            if ( my $first_hold = $holds->next ) {
522
                if ( my $first_hold = $holds->next ) {
514
                my $p = Koha::Patrons->find( $first_hold->borrowernumber );
523
                    my $p = Koha::Patrons->find( $first_hold->borrowernumber );
515
524
516
                $item->{backgroundcolor} = 'reserved';
525
                    $item->{backgroundcolor} = 'reserved';
517
                $item->{reservedate}     = output_pref({ dt => dt_from_string( $first_hold->reservedate ), dateonly => 1 }); # FIXME Should be formatted in the template
526
                    $item->{reservedate}     = output_pref({ dt => dt_from_string( $first_hold->reservedate ), dateonly => 1 }); # FIXME Should be formatted in the template
518
                $item->{ReservedFor}     = $p;
527
                    $item->{ReservedFor}     = $p;
519
                $item->{ExpectedAtLibrary}     = $first_hold->branchcode;
528
                    $item->{ExpectedAtLibrary}     = $first_hold->branchcode;
520
                $item->{waitingdate} = $first_hold->waitingdate;
529
                    $item->{waitingdate} = $first_hold->waitingdate;
521
            }
530
                }
522
531
523
            # Management of the notforloan document
532
                # Management of the notforloan document
524
            if ( $item->{notforloan} ) {
533
                if ( $item->{notforloan} ) {
525
                $item->{backgroundcolor} = 'other';
534
                    $item->{backgroundcolor} = 'other';
526
            }
535
                }
527
536
528
            # Management of lost or long overdue items
537
                # Management of lost or long overdue items
529
            if ( $item->{itemlost} ) {
538
                if ( $item->{itemlost} ) {
530
                $item->{backgroundcolor} = 'other';
539
                    $item->{backgroundcolor} = 'other';
531
                if ($logged_in_patron->category->hidelostitems && !$showallitems) {
540
                    if ($logged_in_patron->category->hidelostitems && !$showallitems) {
532
                    $item->{hide} = 1;
541
                        $item->{hide} = 1;
533
                    $hiddencount++;
542
                        $hiddencount++;
543
                    }
534
                }
544
                }
535
            }
536
545
537
            # Check the transit status
546
                # Check the transit status
538
            my ( $transfertwhen, $transfertfrom, $transfertto ) =
547
                my ( $transfertwhen, $transfertfrom, $transfertto ) =
539
              GetTransfers($itemnumber);
548
                  GetTransfers($itemnumber);
540
549
541
            if ( defined $transfertwhen && $transfertwhen ne '' ) {
550
                if ( defined $transfertwhen && $transfertwhen ne '' ) {
542
                $item->{transfertwhen} = output_pref({ dt => dt_from_string( $transfertwhen ), dateonly => 1 });
551
                    $item->{transfertwhen} = output_pref({ dt => dt_from_string( $transfertwhen ), dateonly => 1 });
543
                $item->{transfertfrom} = $transfertfrom;
552
                    $item->{transfertfrom} = $transfertfrom;
544
                $item->{transfertto} = $transfertto;
553
                    $item->{transfertto} = $transfertto;
545
                $item->{nocancel} = 1;
554
                    $item->{nocancel} = 1;
546
            }
555
                }
547
556
548
            # If there is no loan, return and transfer, we show a checkbox.
557
                # If there is no loan, return and transfer, we show a checkbox.
549
            $item->{notforloan} ||= 0;
558
                $item->{notforloan} ||= 0;
550
559
551
            # if independent branches is on we need to check if the person can reserve
560
                # if independent branches is on we need to check if the person can reserve
552
            # for branches they arent logged in to
561
                # for branches they arent logged in to
553
            if ( C4::Context->preference("IndependentBranches") ) {
562
                if ( C4::Context->preference("IndependentBranches") ) {
554
                if (! C4::Context->preference("canreservefromotherbranches")){
563
                    if (! C4::Context->preference("canreservefromotherbranches")){
555
                    # can't reserve items so need to check if item homebranch and userenv branch match if not we can't reserve
564
                        # can't reserve items so need to check if item homebranch and userenv branch match if not we can't reserve
556
                    my $userenv = C4::Context->userenv;
565
                        my $userenv = C4::Context->userenv;
557
                    unless ( C4::Context->IsSuperLibrarian ) {
566
                        unless ( C4::Context->IsSuperLibrarian ) {
558
                        $item->{cantreserve} = 1 if ( $item->{homebranch} ne $userenv->{branch} );
567
                            $item->{cantreserve} = 1 if ( $item->{homebranch} ne $userenv->{branch} );
568
                        }
559
                    }
569
                    }
560
                }
570
                }
561
            }
562
571
563
            if ( $patron ) {
572
                if ( $patron ) {
564
                my $patron_unblessed = $patron->unblessed;
573
                    my $patron_unblessed = $patron->unblessed;
565
                my $branch = C4::Circulation::_GetCircControlBranch($item, $patron_unblessed);
574
                    my $branch = C4::Circulation::_GetCircControlBranch($item, $patron_unblessed);
566
575
567
                my $branchitemrule = GetBranchItemRule( $branch, $item->{'itype'} );
576
                    my $branchitemrule = GetBranchItemRule( $branch, $item->{'itype'} );
568
577
569
                $item->{'holdallowed'} = $branchitemrule->{'holdallowed'};
578
                    $item->{'holdallowed'} = $branchitemrule->{'holdallowed'};
570
579
571
                my $can_item_be_reserved = CanItemBeReserved( $patron->borrowernumber, $itemnumber )->{status};
580
                    my $can_item_be_reserved = CanItemBeReserved( $patron->borrowernumber, $itemnumber )->{status};
572
                $item->{not_holdable} = $can_item_be_reserved unless ( $can_item_be_reserved eq 'OK' );
581
                    $item->{not_holdable} = $can_item_be_reserved unless ( $can_item_be_reserved eq 'OK' );
573
582
574
                $item->{item_level_holds} = Koha::CirculationRules->get_opacitemholds_policy( { item => $item_object, patron => $patron } );
583
                    $item->{item_level_holds} = Koha::CirculationRules->get_opacitemholds_policy( { item => $item_object, patron => $patron } );
575
584
576
                if (
585
                    if (
577
                       !$item->{cantreserve}
586
                           !$item->{cantreserve}
578
                    && !$exceeded_maxreserves
587
                        && !$exceeded_maxreserves
579
                    && $can_item_be_reserved eq 'OK'
588
                        && $can_item_be_reserved eq 'OK'
580
                    # items_any_available defined outside of the current loop,
589
                        # items_any_available defined outside of the current loop,
581
                    # so we avoiding loop inside IsAvailableForItemLevelRequest:
590
                        # so we avoiding loop inside IsAvailableForItemLevelRequest:
582
                    && IsAvailableForItemLevelRequest($item_object, $patron, undef, $items_any_available)
591
                        && IsAvailableForItemLevelRequest($item_object, $patron, undef, $items_any_available)
583
                  )
592
                      )
584
                {
593
                    {
585
                    # Send the pickup locations count to the UI, the pickup locations will be pulled using the API
594
                        # Send the pickup locations count to the UI, the pickup locations will be pulled using the API
586
                    my @pickup_locations = $item_object->pickup_locations({ patron => $patron })->as_list;
595
                        my @pickup_locations = $item_object->pickup_locations({ patron => $patron })->as_list;
587
                    $item->{pickup_locations_count} = scalar @pickup_locations;
596
                        $item->{pickup_locations_count} = scalar @pickup_locations;
588
597
589
                    if ( @pickup_locations ) {
598
                        if ( @pickup_locations ) {
590
                        $num_available++;
599
                            $num_available++;
591
                        $item->{available} = 1;
600
                            $item->{available} = 1;
592
601
593
                        my $default_pickup_location;
602
                            my $default_pickup_location;
594
603
595
                        # Default to logged-in, if valid
604
                            # Default to logged-in, if valid
596
                        if ( C4::Context->userenv->{branch} ) {
605
                            if ( C4::Context->userenv->{branch} ) {
597
                            ($default_pickup_location) = grep { $_->branchcode eq C4::Context->userenv->{branch} } @pickup_locations;
606
                                ($default_pickup_location) = grep { $_->branchcode eq C4::Context->userenv->{branch} } @pickup_locations;
598
                        }
607
                            }
599
600
                        $item->{default_pickup_location} = $default_pickup_location;
601
                    }
602
                    else {
603
                        $item->{available} = 0;
604
                        $item->{not_holdable} = "no_valid_pickup_location";
605
                    }
606
608
607
                    push( @available_itemtypes, $item->{itype} );
608
                }
609
                elsif ( C4::Context->preference('AllowHoldPolicyOverride') ) {
610
                    # If AllowHoldPolicyOverride is set, it should override EVERY restriction, not just branch item rules
611
                    # with the exception of itemAlreadyOnHold because, you know, the item is already on hold
612
                    if ( $can_item_be_reserved ne 'itemAlreadyOnHold' ) {
613
                        # Send the pickup locations count to the UI, the pickup locations will be pulled using the API
614
                        my $pickup_locations = $item_object->pickup_locations({ patron => $patron });
615
                        $item->{pickup_locations_count} = $pickup_locations->count;
616
                        if ( $item->{pickup_locations_count} > 0 ) {
617
                            $item->{override} = 1;
618
                            $num_override++;
619
                            # pass the holding branch for use as default
620
                            my $default_pickup_location = $pickup_locations->search({ branchcode => $item->{holdingbranch} })->next;
621
                            $item->{default_pickup_location} = $default_pickup_location;
609
                            $item->{default_pickup_location} = $default_pickup_location;
622
                        }
610
                        }
623
                        else {
611
                        else {
624
                            $item->{available} = 0;
612
                            $item->{available} = 0;
625
                            $item->{not_holdable} = "no_valid_pickup_location";
613
                            $item->{not_holdable} = "no_valid_pickup_location";
626
                        }
614
                        }
627
                    } else { $num_alreadyheld++ }
628
615
629
                    push( @available_itemtypes, $item->{itype} );
616
                        push( @available_itemtypes, $item->{itype} );
630
                }
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;
631
                            }
632
                            else {
633
                                $item->{available} = 0;
634
                                $item->{not_holdable} = "no_valid_pickup_location";
635
                            }
636
                        } else { $num_alreadyheld++ }
637
638
                        push( @available_itemtypes, $item->{itype} );
639
                    }
631
640
632
                # If none of the conditions hold true, then neither override nor available is set and the item cannot be checked
641
                    # If none of the conditions hold true, then neither override nor available is set and the item cannot be checked
633
642
634
                # Show serial enumeration when needed
643
                    # Show serial enumeration when needed
635
                if ($item->{enumchron}) {
644
                    if ($item->{enumchron}) {
636
                    $itemdata_enumchron = 1;
645
                        $itemdata_enumchron = 1;
637
                }
646
                    }
638
                # Show collection when needed
647
                    # Show collection when needed
639
                if ($item->{ccode}) {
648
                    if ($item->{ccode}) {
640
                    $itemdata_ccode = 1;
649
                        $itemdata_ccode = 1;
650
                    }
641
                }
651
                }
652
653
                push @{ $biblioitem->{itemloop} }, $item;
642
            }
654
            }
643
655
644
            push @{ $biblioitem->{itemloop} }, $item;
656
            # While we can't override an alreay held item, we should be able to override the others
645
        }
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
            }
666
            $template->param( hiddencount => $hiddencount);
646
667
647
        # While we can't override an alreay held item, we should be able to override the others
668
            push @bibitemloop, $biblioitem;
648
        # Unless all items are already held
649
        if ( $num_override > 0 && ($num_override + $num_alreadyheld) == scalar( @{ $biblioitem->{itemloop} } ) ) {
650
        # That is, if all items require an override
651
            $template->param( override_required => 1 );
652
        } elsif ( $num_available == 0 ) {
653
            $template->param( none_available => 1 );
654
            $biblioloopiter{warn} = 1;
655
            $biblioloopiter{none_avail} = 1;
656
        }
669
        }
657
        $template->param( hiddencount => $hiddencount);
658
659
        push @bibitemloop, $biblioitem;
660
    }
661
670
662
    @available_itemtypes = uniq( @available_itemtypes );
671
        @available_itemtypes = uniq( @available_itemtypes );
663
    $template->param( available_itemtypes => \@available_itemtypes );
672
        $template->param( available_itemtypes => \@available_itemtypes );
664
673
665
    # existingreserves building
674
        # existingreserves building
666
    my @reserveloop;
675
        my @reserveloop;
667
    my @reserves = Koha::Holds->search( { biblionumber => $biblionumber }, { order_by => 'priority' } );
676
        my @reserves = Koha::Holds->search( { biblionumber => $biblionumber }, { order_by => 'priority' } );
668
    foreach my $res (
677
        foreach my $res (
669
        sort {
678
            sort {
670
            my $a_found = $a->found() || '';
679
                my $a_found = $a->found() || '';
671
            my $b_found = $a->found() || '';
680
                my $b_found = $a->found() || '';
672
            $a_found cmp $b_found;
681
                $a_found cmp $b_found;
673
        } @reserves
682
            } @reserves
674
      )
683
          )
675
    {
684
        {
676
        my %reserve;
685
            my %reserve;
677
        if ( $res->is_found() ) {
686
            if ( $res->is_found() ) {
678
            $reserve{'holdingbranch'} = $res->item()->holdingbranch();
687
                $reserve{'holdingbranch'} = $res->item()->holdingbranch();
679
            $reserve{'biblionumber'}  = $res->item()->biblionumber();
688
                $reserve{'biblionumber'}  = $res->item()->biblionumber();
680
            $reserve{'barcodenumber'} = $res->item()->barcode();
689
                $reserve{'barcodenumber'} = $res->item()->barcode();
681
            $reserve{'wbrcode'}       = $res->branchcode();
690
                $reserve{'wbrcode'}       = $res->branchcode();
682
            $reserve{'itemnumber'}    = $res->itemnumber();
691
                $reserve{'itemnumber'}    = $res->itemnumber();
683
            $reserve{'wbrname'}       = $res->branch()->branchname();
692
                $reserve{'wbrname'}       = $res->branch()->branchname();
684
            $reserve{'atdestination'} = $res->is_at_destination();
693
                $reserve{'atdestination'} = $res->is_at_destination();
685
            $reserve{'desk_name'}     = ( $res->desk() ) ? $res->desk()->desk_name() : '' ;
694
                $reserve{'desk_name'}     = ( $res->desk() ) ? $res->desk()->desk_name() : '' ;
686
            $reserve{'found'}     = $res->is_found();
695
                $reserve{'found'}     = $res->is_found();
687
            $reserve{'inprocessing'} = $res->is_in_processing();
696
                $reserve{'inprocessing'} = $res->is_in_processing();
688
            $reserve{'intransit'} = $res->is_in_transit();
697
                $reserve{'intransit'} = $res->is_in_transit();
689
        }
690
        elsif ( $res->priority() > 0 ) {
691
            if ( my $item = $res->item() )  {
692
                $reserve{'itemnumber'}      = $item->id();
693
                $reserve{'barcodenumber'}   = $item->barcode();
694
                $reserve{'item_level_hold'} = 1;
695
            }
698
            }
699
            elsif ( $res->priority() > 0 ) {
700
                if ( my $item = $res->item() )  {
701
                    $reserve{'itemnumber'}      = $item->id();
702
                    $reserve{'barcodenumber'}   = $item->barcode();
703
                    $reserve{'item_level_hold'} = 1;
704
                }
705
            }
706
707
            $reserve{'expirationdate'} = $res->expirationdate;
708
            $reserve{'date'}           = $res->reservedate;
709
            $reserve{'borrowernumber'} = $res->borrowernumber();
710
            $reserve{'biblionumber'}   = $res->biblionumber();
711
            $reserve{'patron'}         = $res->borrower;
712
            $reserve{'notes'}          = $res->reservenotes();
713
            $reserve{'waiting_date'}   = $res->waitingdate();
714
            $reserve{'ccode'}          = $res->item() ? $res->item()->ccode() : undef;
715
            $reserve{'barcode'}        = $res->item() ? $res->item()->barcode() : undef;
716
            $reserve{'priority'}       = $res->priority();
717
            $reserve{'lowestPriority'} = $res->lowestPriority();
718
            $reserve{'suspend'}        = $res->suspend();
719
            $reserve{'suspend_until'}  = $res->suspend_until();
720
            $reserve{'reserve_id'}     = $res->reserve_id();
721
            $reserve{itemtype}         = $res->itemtype();
722
            $reserve{branchcode}       = $res->branchcode();
723
            $reserve{non_priority}     = $res->non_priority();
724
            $reserve{object}           = $res;
725
726
            push( @reserveloop, \%reserve );
696
        }
727
        }
697
728
698
        $reserve{'expirationdate'} = $res->expirationdate;
729
        # get the time for the form name...
699
        $reserve{'date'}           = $res->reservedate;
730
        my $time = time();
700
        $reserve{'borrowernumber'} = $res->borrowernumber();
701
        $reserve{'biblionumber'}   = $res->biblionumber();
702
        $reserve{'patron'}         = $res->borrower;
703
        $reserve{'notes'}          = $res->reservenotes();
704
        $reserve{'waiting_date'}   = $res->waitingdate();
705
        $reserve{'ccode'}          = $res->item() ? $res->item()->ccode() : undef;
706
        $reserve{'barcode'}        = $res->item() ? $res->item()->barcode() : undef;
707
        $reserve{'priority'}       = $res->priority();
708
        $reserve{'lowestPriority'} = $res->lowestPriority();
709
        $reserve{'suspend'}        = $res->suspend();
710
        $reserve{'suspend_until'}  = $res->suspend_until();
711
        $reserve{'reserve_id'}     = $res->reserve_id();
712
        $reserve{itemtype}         = $res->itemtype();
713
        $reserve{branchcode}       = $res->branchcode();
714
        $reserve{non_priority}     = $res->non_priority();
715
        $reserve{object}           = $res;
716
717
        push( @reserveloop, \%reserve );
718
    }
719
731
720
    # get the time for the form name...
732
        $template->param(
721
    my $time = time();
733
                         time        => $time,
734
                         fixedRank   => $fixedRank,
735
                        );
722
736
723
    $template->param(
737
        # display infos
724
                     time        => $time,
738
        $template->param(
725
                     fixedRank   => $fixedRank,
739
                         bibitemloop       => \@bibitemloop,
726
                    );
740
                         itemdata_enumchron => $itemdata_enumchron,
741
                         itemdata_ccode    => $itemdata_ccode,
742
                         date              => $date,
743
                         biblionumber      => $biblionumber,
744
                         findborrower      => $findborrower,
745
                         biblio            => $biblio,
746
                         holdsview         => 1,
747
                         C4::Search::enabled_staff_search_views,
748
                        );
749
750
        $biblioloopiter{biblionumber} = $biblionumber;
751
        $biblioloopiter{title} = $biblio->title;
752
        $biblioloopiter{rank} = $fixedRank;
753
        $biblioloopiter{reserveloop} = \@reserveloop;
754
755
        if (@reserveloop) {
756
            $template->param( reserveloop => \@reserveloop );
757
        }
727
758
728
    # display infos
759
        if ( $patron ) {
729
    $template->param(
760
            # Add the valid pickup locations
730
                     bibitemloop       => \@bibitemloop,
761
            my @pickup_locations = $biblio->pickup_locations({ patron => $patron })->as_list;
731
                     itemdata_enumchron => $itemdata_enumchron,
762
            $biblioloopiter{pickup_locations} = \@pickup_locations;
732
                     itemdata_ccode    => $itemdata_ccode,
763
            $biblioloopiter{pickup_locations_codes} = [ map { $_->branchcode } @pickup_locations ];
733
                     date              => $date,
764
        }
734
                     biblionumber      => $biblionumber,
735
                     findborrower      => $findborrower,
736
                     biblio            => $biblio,
737
                     holdsview         => 1,
738
                     C4::Search::enabled_staff_search_views,
739
                    );
740
741
    $biblioloopiter{biblionumber} = $biblionumber;
742
    $biblioloopiter{title} = $biblio->title;
743
    $biblioloopiter{rank} = $fixedRank;
744
    $biblioloopiter{reserveloop} = \@reserveloop;
745
746
    if (@reserveloop) {
747
        $template->param( reserveloop => \@reserveloop );
748
    }
749
765
750
    if ( $patron ) {
766
        push @biblioloop, \%biblioloopiter;
751
        # Add the valid pickup locations
752
        my @pickup_locations = $biblio->pickup_locations({ patron => $patron })->as_list;
753
        $biblioloopiter{pickup_locations} = \@pickup_locations;
754
        $biblioloopiter{pickup_locations_codes} = [ map { $_->branchcode } @pickup_locations ];
755
    }
767
    }
756
768
757
    push @biblioloop, \%biblioloopiter;
769
    $template->param( biblioloop => \@biblioloop );
770
    $template->param( no_reserves_allowed => $no_reserves_allowed );
771
    $template->param( exceeded_maxreserves => $exceeded_maxreserves );
772
    $template->param( exceeded_holds_per_record => $exceeded_holds_per_record );
773
    $template->param( subscriptionsnumber => CountSubscriptionFromBiblionumber($biblionumber));
774
} elsif ( ! $multi_hold ) {
775
    my $biblio = Koha::Biblios->find( $biblionumber );
776
    $template->param( biblio => $biblio );
758
}
777
}
759
778
760
$template->param( biblioloop => \@biblioloop );
779
if ( $multi_hold ) {
761
$template->param( no_reserves_allowed => $no_reserves_allowed );
780
    $template->param( biblionumbers => join('/', @biblionumbers) );
762
$template->param( biblionumbers => join('/', @biblionumbers) );
781
} else {
763
$template->param( exceeded_maxreserves => $exceeded_maxreserves );
782
    $template->param( biblionumber => $biblionumber || $biblionumbers[0] );
764
$template->param( exceeded_holds_per_record => $exceeded_holds_per_record );
783
}
765
$template->param( subscriptionsnumber => CountSubscriptionFromBiblionumber($biblionumber));
766
784
767
# pass the userenv branch if no pickup location selected
785
# pass the userenv branch if no pickup location selected
768
$template->param( pickup => $pickup || C4::Context->userenv->{branch} );
786
$template->param( pickup => $pickup || C4::Context->userenv->{branch} );
769
- 

Return to bug 29043