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

(-)a/C4/Circulation.pm (-12 / +11 lines)
Lines 1166-1172 sub CanBookBeIssued { Link Here
1166
1166
1167
    ## check for high holds decreasing loan period
1167
    ## check for high holds decreasing loan period
1168
    if ( C4::Context->preference('decreaseLoanHighHolds') ) {
1168
    if ( C4::Context->preference('decreaseLoanHighHolds') ) {
1169
        my $check = checkHighHolds( $item_unblessed, $patron_unblessed );
1169
        my $check = checkHighHolds( $item_object, $patron );
1170
1170
1171
        if ( $check->{exceeded} ) {
1171
        if ( $check->{exceeded} ) {
1172
            if ($override_high_holds) {
1172
            if ($override_high_holds) {
Lines 1278-1286 sub CanBookBeReturned { Link Here
1278
=cut
1278
=cut
1279
1279
1280
sub checkHighHolds {
1280
sub checkHighHolds {
1281
    my ( $item, $borrower ) = @_;
1281
    my ( $item, $patron ) = @_;
1282
    my $branchcode = _GetCircControlBranch( $item, $borrower );
1282
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
1283
    my $item_object = Koha::Items->find( $item->{itemnumber} );
1284
1283
1285
    my $return_data = {
1284
    my $return_data = {
1286
        exceeded    => 0,
1285
        exceeded    => 0,
Lines 1289-1295 sub checkHighHolds { Link Here
1289
        due_date    => undef,
1288
        due_date    => undef,
1290
    };
1289
    };
1291
1290
1292
    my $holds = Koha::Holds->search( { biblionumber => $item->{'biblionumber'} } );
1291
    my $holds = Koha::Holds->search( { biblionumber => $item->biblionumber } );
1293
1292
1294
    if ( $holds->count() ) {
1293
    if ( $holds->count() ) {
1295
        $return_data->{outstanding} = $holds->count();
1294
        $return_data->{outstanding} = $holds->count();
Lines 1322-1328 sub checkHighHolds { Link Here
1322
            }
1321
            }
1323
1322
1324
            # Remove any items that are not holdable for this patron
1323
            # Remove any items that are not holdable for this patron
1325
            @items = grep { CanItemBeReserved( $borrower->{borrowernumber}, $_->itemnumber, undef, { ignore_found_holds => 1 } )->{status} eq 'OK' } @items;
1324
            @items = grep { CanItemBeReserved( $patron , $_, undef, { ignore_found_holds => 1 } )->{status} eq 'OK' } @items;
1326
1325
1327
            my $items_count = scalar @items;
1326
            my $items_count = scalar @items;
1328
1327
Lines 1337-1358 sub checkHighHolds { Link Here
1337
1336
1338
        my $issuedate = dt_from_string();
1337
        my $issuedate = dt_from_string();
1339
1338
1340
        my $itype = $item_object->effective_itemtype;
1339
        my $itype = $item->effective_itemtype;
1341
        my $daysmode = Koha::CirculationRules->get_effective_daysmode(
1340
        my $daysmode = Koha::CirculationRules->get_effective_daysmode(
1342
            {
1341
            {
1343
                categorycode => $borrower->{categorycode},
1342
                categorycode => $patron->categorycode,
1344
                itemtype     => $itype,
1343
                itemtype     => $itype,
1345
                branchcode   => $branchcode,
1344
                branchcode   => $branchcode,
1346
            }
1345
            }
1347
        );
1346
        );
1348
        my $calendar = Koha::Calendar->new( branchcode => $branchcode, days_mode => $daysmode );
1347
        my $calendar = Koha::Calendar->new( branchcode => $branchcode, days_mode => $daysmode );
1349
1348
1350
        my $orig_due = C4::Circulation::CalcDateDue( $issuedate, $itype, $branchcode, $borrower );
1349
        my $orig_due = C4::Circulation::CalcDateDue( $issuedate, $itype, $branchcode, $patron->unblessed );
1351
1350
1352
        my $rule = Koha::CirculationRules->get_effective_rule(
1351
        my $rule = Koha::CirculationRules->get_effective_rule(
1353
            {
1352
            {
1354
                categorycode => $borrower->{categorycode},
1353
                categorycode => $patron->categorycode,
1355
                itemtype     => $item_object->effective_itemtype,
1354
                itemtype     => $item->effective_itemtype,
1356
                branchcode   => $branchcode,
1355
                branchcode   => $branchcode,
1357
                rule_name    => 'decreaseloanholds',
1356
                rule_name    => 'decreaseloanholds',
1358
            }
1357
            }
Lines 2846-2852 sub CanBookBeRenewed { Link Here
2846
                next if IsItemOnHoldAndFound( $item->itemnumber );
2845
                next if IsItemOnHoldAndFound( $item->itemnumber );
2847
                while ( my $patron = $patrons->next ) {
2846
                while ( my $patron = $patrons->next ) {
2848
                    next unless IsAvailableForItemLevelRequest($item, $patron);
2847
                    next unless IsAvailableForItemLevelRequest($item, $patron);
2849
                    next unless CanItemBeReserved($patron->borrowernumber,$item->itemnumber,undef,{ignore_hold_counts=>1})->{status} eq 'OK';
2848
                    next unless CanItemBeReserved($patron,$item,undef,{ignore_hold_counts=>1})->{status} eq 'OK';
2850
                    push @reservable, $item->itemnumber;
2849
                    push @reservable, $item->itemnumber;
2851
                    if (@reservable >= @borrowernumbers) {
2850
                    if (@reservable >= @borrowernumbers) {
2852
                        $resfound = 0;
2851
                        $resfound = 0;
(-)a/C4/ILSDI/Services.pm (-1 / +1 lines)
Lines 872-878 sub HoldItem { Link Here
872
    }
872
    }
873
873
874
    # Check for item disponibility
874
    # Check for item disponibility
875
    my $canitembereserved = C4::Reserves::CanItemBeReserved( $borrowernumber, $itemnumber, $branch )->{status};
875
    my $canitembereserved = C4::Reserves::CanItemBeReserved( $patron, $item, $branch )->{status};
876
    return { code => $canitembereserved } unless $canitembereserved eq 'OK';
876
    return { code => $canitembereserved } unless $canitembereserved eq 'OK';
877
877
878
    my $resdate;
878
    my $resdate;
(-)a/C4/Reserves.pm (-21 / +27 lines)
Lines 330-345 sub CanBookBeReserved{ Link Here
330
        return { status =>'alreadypossession' };
330
        return { status =>'alreadypossession' };
331
    }
331
    }
332
332
333
    my @itemnumbers = Koha::Items->search({ biblionumber => $biblionumber})->get_column("itemnumber");
333
    my $items;
334
    #get items linked via host records
334
    #get items linked via host records
335
    my @hostitems = get_hostitemnumbers_of($biblionumber);
335
    my @hostitemnumbers = get_hostitemnumbers_of($biblionumber);
336
    if (@hostitems){
336
    if (@hostitemnumbers){
337
        push (@itemnumbers, @hostitems);
337
        $items = Koha::Items->search({
338
            -or => [
339
                biblionumber => $biblionumber,
340
                itemnumber => { -in => @hostitemnumbers }
341
            ]
342
        });
343
    } else {
344
        $items = Koha::Items->search({ biblionumber => $biblionumber});
338
    }
345
    }
339
346
340
    my $canReserve = { status => '' };
347
    my $canReserve = { status => '' };
341
    foreach my $itemnumber (@itemnumbers) {
348
    my $patron = Koha::Patrons->find( $borrowernumber );
342
        $canReserve = CanItemBeReserved( $borrowernumber, $itemnumber, $pickup_branchcode, $params );
349
    while ( my $item = $items->next ) {
350
        $canReserve = CanItemBeReserved( $patron, $item, $pickup_branchcode, $params );
343
        return { status => 'OK' } if $canReserve->{status} eq 'OK';
351
        return { status => 'OK' } if $canReserve->{status} eq 'OK';
344
    }
352
    }
345
    return $canReserve;
353
    return $canReserve;
Lines 347-353 sub CanBookBeReserved{ Link Here
347
355
348
=head2 CanItemBeReserved
356
=head2 CanItemBeReserved
349
357
350
  $canReserve = &CanItemBeReserved($borrowernumber, $itemnumber, $branchcode, $params)
358
  $canReserve = &CanItemBeReserved($patron, $item, $branchcode, $params)
351
  if ($canReserve->{status} eq 'OK') { #We can reserve this Item! }
359
  if ($canReserve->{status} eq 'OK') { #We can reserve this Item! }
352
360
353
  current params are:
361
  current params are:
Lines 372-378 sub CanBookBeReserved{ Link Here
372
=cut
380
=cut
373
381
374
sub CanItemBeReserved {
382
sub CanItemBeReserved {
375
    my ( $borrowernumber, $itemnumber, $pickup_branchcode, $params ) = @_;
383
    my ( $patron, $item, $pickup_branchcode, $params ) = @_;
376
384
377
    my $dbh = C4::Context->dbh;
385
    my $dbh = C4::Context->dbh;
378
    my $ruleitemtype;    # itemtype of the matching issuing rule
386
    my $ruleitemtype;    # itemtype of the matching issuing rule
Lines 380-388 sub CanItemBeReserved { Link Here
380
388
381
    # we retrieve borrowers and items informations #
389
    # we retrieve borrowers and items informations #
382
    # item->{itype} will come for biblioitems if necessery
390
    # item->{itype} will come for biblioitems if necessery
383
    my $item       = Koha::Items->find($itemnumber);
384
    my $biblio     = $item->biblio;
391
    my $biblio     = $item->biblio;
385
    my $patron = Koha::Patrons->find( $borrowernumber );
386
    my $borrower = $patron->unblessed;
392
    my $borrower = $patron->unblessed;
387
393
388
    # If an item is damaged and we don't allow holds on damaged items, we can stop right here
394
    # If an item is damaged and we don't allow holds on damaged items, we can stop right here
Lines 397-403 sub CanItemBeReserved { Link Here
397
403
398
    # Check that the patron doesn't have an item level hold on this item already
404
    # Check that the patron doesn't have an item level hold on this item already
399
    return { status =>'itemAlreadyOnHold' }
405
    return { status =>'itemAlreadyOnHold' }
400
      if ( !$params->{ignore_hold_counts} && Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count() );
406
      if ( !$params->{ignore_hold_counts} && Koha::Holds->search( { borrowernumber => $patron->borrowernumber, itemnumber => $item->itemnumber } )->count() );
401
407
402
    # Check that patron have not checked out this biblio (if AllowHoldsOnPatronsPossessions set)
408
    # Check that patron have not checked out this biblio (if AllowHoldsOnPatronsPossessions set)
403
    if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions')
409
    if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions')
Lines 454-460 sub CanItemBeReserved { Link Here
454
    my $holds_per_day    = $rights->{holds_per_day};
460
    my $holds_per_day    = $rights->{holds_per_day};
455
461
456
    my $search_params = {
462
    my $search_params = {
457
        borrowernumber => $borrowernumber,
463
        borrowernumber => $patron->borrowernumber,
458
        biblionumber   => $item->biblionumber,
464
        biblionumber   => $item->biblionumber,
459
    };
465
    };
460
    $search_params->{found} = undef if $params->{ignore_found_holds};
466
    $search_params->{found} = undef if $params->{ignore_found_holds};
Lines 470-476 sub CanItemBeReserved { Link Here
470
    }
476
    }
471
477
472
    my $today_holds = Koha::Holds->search({
478
    my $today_holds = Koha::Holds->search({
473
        borrowernumber => $borrowernumber,
479
        borrowernumber => $patron->borrowernumber,
474
        reservedate    => dt_from_string->date
480
        reservedate    => dt_from_string->date
475
    });
481
    });
476
482
Lines 495-504 sub CanItemBeReserved { Link Here
495
    my $sthcount = $dbh->prepare($querycount);
501
    my $sthcount = $dbh->prepare($querycount);
496
502
497
    if ( defined $ruleitemtype ) {
503
    if ( defined $ruleitemtype ) {
498
        $sthcount->execute( $borrowernumber, $branchcode, $ruleitemtype );
504
        $sthcount->execute( $patron->borrowernumber, $branchcode, $ruleitemtype );
499
    }
505
    }
500
    else {
506
    else {
501
        $sthcount->execute( $borrowernumber, $branchcode );
507
        $sthcount->execute( $patron->borrowernumber, $branchcode );
502
    }
508
    }
503
509
504
    my $reservecount = "0";
510
    my $reservecount = "0";
Lines 519-525 sub CanItemBeReserved { Link Here
519
    # Now we need to check hold limits by patron category
525
    # Now we need to check hold limits by patron category
520
    my $rule = Koha::CirculationRules->get_effective_rule(
526
    my $rule = Koha::CirculationRules->get_effective_rule(
521
        {
527
        {
522
            categorycode => $borrower->{categorycode},
528
            categorycode => $patron->categorycode,
523
            branchcode   => $branchcode,
529
            branchcode   => $branchcode,
524
            rule_name    => 'max_holds',
530
            rule_name    => 'max_holds',
525
        }
531
        }
Lines 527-533 sub CanItemBeReserved { Link Here
527
    if (!$params->{ignore_hold_counts} && $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
533
    if (!$params->{ignore_hold_counts} && $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
528
        my $total_holds_count = Koha::Holds->search(
534
        my $total_holds_count = Koha::Holds->search(
529
            {
535
            {
530
                borrowernumber => $borrower->{borrowernumber}
536
                borrowernumber => $patron->borrowernumber
531
            }
537
            }
532
        )->count();
538
        )->count();
533
539
Lines 535-541 sub CanItemBeReserved { Link Here
535
    }
541
    }
536
542
537
    my $reserves_control_branch =
543
    my $reserves_control_branch =
538
      GetReservesControlBranch( $item->unblessed(), $borrower );
544
      GetReservesControlBranch( $item->unblessed(), $patron->unblessed );
539
    my $branchitemrule =
545
    my $branchitemrule =
540
      C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->effective_itemtype );
546
      C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->effective_itemtype );
541
547
Lines 551-557 sub CanItemBeReserved { Link Here
551
557
552
    my $item_library = Koha::Libraries->find( {branchcode => $item->homebranch} );
558
    my $item_library = Koha::Libraries->find( {branchcode => $item->homebranch} );
553
    if ( $branchitemrule->{holdallowed} eq 'from_local_hold_group') {
559
    if ( $branchitemrule->{holdallowed} eq 'from_local_hold_group') {
554
        if($borrower->{branchcode} ne $item->homebranch && !$item_library->validate_hold_sibling( {branchcode => $borrower->{branchcode}} )) {
560
        if($patron->branchcode ne $item->homebranch && !$item_library->validate_hold_sibling( {branchcode => $patron->branchcode} )) {
555
            return { status => 'branchNotInHoldGroup' };
561
            return { status => 'branchNotInHoldGroup' };
556
        }
562
        }
557
    }
563
    }
Lines 561-567 sub CanItemBeReserved { Link Here
561
    if ( C4::Context->preference('IndependentBranches')
567
    if ( C4::Context->preference('IndependentBranches')
562
        and !C4::Context->preference('canreservefromotherbranches') )
568
        and !C4::Context->preference('canreservefromotherbranches') )
563
    {
569
    {
564
        if ( $item->homebranch ne $borrower->{branchcode} ) {
570
        if ( $item->homebranch ne $patron->branchcode ) {
565
            return { status => 'cannotReserveFromOtherBranches' };
571
            return { status => 'cannotReserveFromOtherBranches' };
566
        }
572
        }
567
    }
573
    }
Lines 1423-1429 sub ItemsAnyAvailableAndNotRestricted { Link Here
1423
            || Koha::ItemTypes->find( $i->effective_itemtype() )->notforloan
1429
            || Koha::ItemTypes->find( $i->effective_itemtype() )->notforloan
1424
            || $branchitemrule->{holdallowed} eq 'from_home_library' && $param->{patron}->branchcode ne $i->homebranch
1430
            || $branchitemrule->{holdallowed} eq 'from_home_library' && $param->{patron}->branchcode ne $i->homebranch
1425
            || $branchitemrule->{holdallowed} eq 'from_local_hold_group' && ! $item_library->validate_hold_sibling( { branchcode => $param->{patron}->branchcode } )
1431
            || $branchitemrule->{holdallowed} eq 'from_local_hold_group' && ! $item_library->validate_hold_sibling( { branchcode => $param->{patron}->branchcode } )
1426
            || CanItemBeReserved( $param->{patron}->borrowernumber, $i->id )->{status} ne 'OK';
1432
            || CanItemBeReserved( $param->{patron}, $i )->{status} ne 'OK';
1427
    }
1433
    }
1428
1434
1429
    return 0;
1435
    return 0;
(-)a/Koha/Club/Hold.pm (-5 / +7 lines)
Lines 53-58 Class (static) method that returns a new Koha::Club::Hold instance Link Here
53
53
54
sub add {
54
sub add {
55
    my ( $params ) = @_;
55
    my ( $params ) = @_;
56
    my $itemnumber = $params->{item_id};
56
57
57
    # check for mandatory params
58
    # check for mandatory params
58
    my @mandatory = ( 'biblio_id', 'club_id' );
59
    my @mandatory = ( 'biblio_id', 'club_id' );
Lines 87-97 sub add { Link Here
87
        my $pickup_id = $params->{pickup_library_id};
88
        my $pickup_id = $params->{pickup_library_id};
88
89
89
        my $can_place_hold;
90
        my $can_place_hold;
91
        my $patron = Koha::Patrons->find($patron_id);
92
        my $item = $itemnumber ? Koha::Items->find( $itemnumber ) : undef;
90
        if($params->{default_patron_home}) {
93
        if($params->{default_patron_home}) {
91
            my $patron = Koha::Patrons->find($patron_id);
92
            my $patron_home = $patron->branchcode;
94
            my $patron_home = $patron->branchcode;
93
            $can_place_hold = $params->{item_id}
95
            $can_place_hold = $itemnumber
94
                ? C4::Reserves::CanItemBeReserved( $patron_id, $params->{item_id}, $patron_home )
96
                ? C4::Reserves::CanItemBeReserved( $patron, $item, $patron_home )
95
                : C4::Reserves::CanBookBeReserved( $patron_id, $params->{biblio_id}, $patron_home );
97
                : C4::Reserves::CanBookBeReserved( $patron_id, $params->{biblio_id}, $patron_home );
96
            $pickup_id = $patron_home if $can_place_hold->{status} eq 'OK';
98
            $pickup_id = $patron_home if $can_place_hold->{status} eq 'OK';
97
            unless ( $can_place_hold->{status} eq 'OK' ) {
99
            unless ( $can_place_hold->{status} eq 'OK' ) {
Lines 100-107 sub add { Link Here
100
        }
102
        }
101
103
102
        unless ( defined $can_place_hold && $can_place_hold->{status} eq 'OK' ) {
104
        unless ( defined $can_place_hold && $can_place_hold->{status} eq 'OK' ) {
103
            $can_place_hold = $params->{item_id}
105
            $can_place_hold = $itemnumber
104
                ? C4::Reserves::CanItemBeReserved( $patron_id, $params->{item_id}, $pickup_id )
106
                ? C4::Reserves::CanItemBeReserved( $patron, $item, $pickup_id )
105
                : C4::Reserves::CanBookBeReserved( $patron_id, $params->{biblio_id}, $pickup_id );
107
                : C4::Reserves::CanBookBeReserved( $patron_id, $params->{biblio_id}, $pickup_id );
106
        }
108
        }
107
109
(-)a/Koha/REST/V1/Holds.pm (-1 / +1 lines)
Lines 166-172 sub add { Link Here
166
166
167
        my $can_place_hold
167
        my $can_place_hold
168
            = $item_id
168
            = $item_id
169
            ? C4::Reserves::CanItemBeReserved( $patron_id, $item_id )
169
            ? C4::Reserves::CanItemBeReserved( $patron, $item )
170
            : C4::Reserves::CanBookBeReserved( $patron_id, $biblio_id );
170
            : C4::Reserves::CanBookBeReserved( $patron_id, $biblio_id );
171
171
172
        if ( $patron->holds->count + 1 > C4::Context->preference('maxreserves') ) {
172
        if ( $patron->holds->count + 1 > C4::Context->preference('maxreserves') ) {
(-)a/opac/opac-reserve.pl (-6 / +6 lines)
Lines 237-245 if ( $query->param('place_reserve') ) { Link Here
237
            $branch = $patron->branchcode;
237
            $branch = $patron->branchcode;
238
        }
238
        }
239
239
240
        my $item = $itemNum ? Koha::Items->find( $itemNum ) : undef;
240
        # When choosing a specific item, the default pickup library should be dictated by the default hold policy
241
        # When choosing a specific item, the default pickup library should be dictated by the default hold policy
241
        if ( ! C4::Context->preference("OPACAllowUserToChooseBranch") && $itemNum ) {
242
        if ( ! C4::Context->preference("OPACAllowUserToChooseBranch") && $itemNum ) {
242
            my $item = Koha::Items->find( $itemNum );
243
            my $type = $item->effective_itemtype;
243
            my $type = $item->effective_itemtype;
244
            my $rule = GetBranchItemRule( $patron->branchcode, $type );
244
            my $rule = GetBranchItemRule( $patron->branchcode, $type );
245
245
Lines 254-261 if ( $query->param('place_reserve') ) { Link Here
254
        }
254
        }
255
255
256
#item may belong to a host biblio, if yes change biblioNum to hosts bilbionumber
256
#item may belong to a host biblio, if yes change biblioNum to hosts bilbionumber
257
        if ( $itemNum ne '' ) {
257
        if ( $itemNum ) {
258
            my $item = Koha::Items->find( $itemNum );
259
            my $hostbiblioNum = $item->biblio->biblionumber;
258
            my $hostbiblioNum = $item->biblio->biblionumber;
260
            if ( $hostbiblioNum ne $biblioNum ) {
259
            if ( $hostbiblioNum ne $biblioNum ) {
261
                $biblioNum = $hostbiblioNum;
260
                $biblioNum = $hostbiblioNum;
Lines 276-283 if ( $query->param('place_reserve') ) { Link Here
276
        my $expiration_date = $query->param("expiration_date_$biblioNum");
275
        my $expiration_date = $query->param("expiration_date_$biblioNum");
277
276
278
        my $rank = $biblioData->{rank};
277
        my $rank = $biblioData->{rank};
279
        if ( $itemNum ne '' ) {
278
        my $patron = Koha::Patrons->find( $borrowernumber );
280
            $canreserve = 1 if CanItemBeReserved( $borrowernumber, $itemNum, $branch )->{status} eq 'OK';
279
        if ( $itemNum ) {
280
            $canreserve = 1 if CanItemBeReserved( $patron, $item, $branch )->{status} eq 'OK';
281
        }
281
        }
282
        else {
282
        else {
283
            $canreserve = 1 if CanBookBeReserved( $borrowernumber, $biblioNum, $branch )->{status} eq 'OK';
283
            $canreserve = 1 if CanBookBeReserved( $borrowernumber, $biblioNum, $branch )->{status} eq 'OK';
Lines 559-565 foreach my $biblioNum (@biblionumbers) { Link Here
559
        my $policy_holdallowed = !$itemLoopIter->{already_reserved};
559
        my $policy_holdallowed = !$itemLoopIter->{already_reserved};
560
        $policy_holdallowed &&=
560
        $policy_holdallowed &&=
561
            IsAvailableForItemLevelRequest($item, $patron) &&
561
            IsAvailableForItemLevelRequest($item, $patron) &&
562
            CanItemBeReserved( $borrowernumber, $itemNum )->{status} eq 'OK';
562
            CanItemBeReserved( $patron, $item )->{status} eq 'OK';
563
563
564
        if ($policy_holdallowed) {
564
        if ($policy_holdallowed) {
565
            my $opac_hold_policy = Koha::CirculationRules->get_opacitemholds_policy( { item => $item, patron => $patron } );
565
            my $opac_hold_policy = Koha::CirculationRules->get_opacitemholds_policy( { item => $item, patron => $patron } );
(-)a/reserve/placerequest.pl (-9 / +8 lines)
Lines 49-56 my $expirationdate = $input->param('expiration_date'); Link Here
49
my $itemtype       = $input->param('itemtype') || undef;
49
my $itemtype       = $input->param('itemtype') || undef;
50
my $non_priority   = $input->param('non_priority');
50
my $non_priority   = $input->param('non_priority');
51
51
52
my $borrower = Koha::Patrons->find( $borrowernumber );
52
my $patron = Koha::Patrons->find( $borrowernumber );
53
$borrower = $borrower->unblessed if $borrower;
54
53
55
my $biblionumbers = $input->param('biblionumbers');
54
my $biblionumbers = $input->param('biblionumbers');
56
$biblionumbers ||= $biblionumber . '/';
55
$biblionumbers ||= $biblionumber . '/';
Lines 70-76 foreach my $bibnum (@biblionumbers) { Link Here
70
69
71
my $found;
70
my $found;
72
71
73
if ( $type eq 'str8' && $borrower ) {
72
if ( $type eq 'str8' && $patron ) {
74
73
75
    foreach my $biblionumber ( keys %bibinfos ) {
74
    foreach my $biblionumber ( keys %bibinfos ) {
76
        my $count = @bibitems;
75
        my $count = @bibitems;
Lines 97-109 if ( $type eq 'str8' && $borrower ) { Link Here
97
                $biblionumber = $item->biblionumber;
96
                $biblionumber = $item->biblionumber;
98
            }
97
            }
99
98
100
            my $can_item_be_reserved = CanItemBeReserved($borrower->{'borrowernumber'}, $item->itemnumber, $item_pickup_location)->{status};
99
            my $can_item_be_reserved = CanItemBeReserved($patron, $item, $item_pickup_location)->{status};
101
100
102
            if ( $can_item_be_reserved eq 'OK' || ( $can_item_be_reserved ne 'itemAlreadyOnHold' && $can_override ) ) {
101
            if ( $can_item_be_reserved eq 'OK' || ( $can_item_be_reserved ne 'itemAlreadyOnHold' && $can_override ) ) {
103
                AddReserve(
102
                AddReserve(
104
                    {
103
                    {
105
                        branchcode       => $item_pickup_location,
104
                        branchcode       => $item_pickup_location,
106
                        borrowernumber   => $borrower->{'borrowernumber'},
105
                        borrowernumber   => $patron->borrowernumber,
107
                        biblionumber     => $biblionumber,
106
                        biblionumber     => $biblionumber,
108
                        priority         => $rank[0],
107
                        priority         => $rank[0],
109
                        reservation_date => $startdate,
108
                        reservation_date => $startdate,
Lines 121-131 if ( $type eq 'str8' && $borrower ) { Link Here
121
120
122
        } elsif (@biblionumbers > 1) {
121
        } elsif (@biblionumbers > 1) {
123
            my $bibinfo = $bibinfos{$biblionumber};
122
            my $bibinfo = $bibinfos{$biblionumber};
124
            if ( $can_override || CanBookBeReserved($borrower->{'borrowernumber'}, $biblionumber)->{status} eq 'OK' ) {
123
            if ( $can_override || CanBookBeReserved($patron->borrowernumber, $biblionumber)->{status} eq 'OK' ) {
125
                AddReserve(
124
                AddReserve(
126
                    {
125
                    {
127
                        branchcode       => $bibinfo->{pickup},
126
                        branchcode       => $bibinfo->{pickup},
128
                        borrowernumber   => $borrower->{'borrowernumber'},
127
                        borrowernumber   => $patron->borrowernumber,
129
                        biblionumber     => $biblionumber,
128
                        biblionumber     => $biblionumber,
130
                        priority         => $bibinfo->{rank},
129
                        priority         => $bibinfo->{rank},
131
                        reservation_date => $startdate,
130
                        reservation_date => $startdate,
Lines 142-152 if ( $type eq 'str8' && $borrower ) { Link Here
142
        } else {
141
        } else {
143
            # place a request on 1st available
142
            # place a request on 1st available
144
            for ( my $i = 0 ; $i < $holds_to_place_count ; $i++ ) {
143
            for ( my $i = 0 ; $i < $holds_to_place_count ; $i++ ) {
145
                if ( $can_override || CanBookBeReserved($borrower->{'borrowernumber'}, $biblionumber)->{status} eq 'OK' ) {
144
                if ( $can_override || CanBookBeReserved($patron->borrowernumber, $biblionumber)->{status} eq 'OK' ) {
146
                    AddReserve(
145
                    AddReserve(
147
                        {
146
                        {
148
                            branchcode       => $branch,
147
                            branchcode       => $branch,
149
                            borrowernumber   => $borrower->{'borrowernumber'},
148
                            borrowernumber   => $patron->borrowernumber,
150
                            biblionumber     => $biblionumber,
149
                            biblionumber     => $biblionumber,
151
                            priority         => $rank[0],
150
                            priority         => $rank[0],
152
                            reservation_date => $startdate,
151
                            reservation_date => $startdate,
(-)a/reserve/request.pl (-1 / +1 lines)
Lines 565-571 foreach my $biblionumber (@biblionumbers) { Link Here
565
565
566
                $item->{'holdallowed'} = $branchitemrule->{'holdallowed'};
566
                $item->{'holdallowed'} = $branchitemrule->{'holdallowed'};
567
567
568
                my $can_item_be_reserved = CanItemBeReserved( $patron->borrowernumber, $itemnumber )->{status};
568
                my $can_item_be_reserved = CanItemBeReserved( $patron, $item_object )->{status};
569
                $item->{not_holdable} = $can_item_be_reserved unless ( $can_item_be_reserved eq 'OK' );
569
                $item->{not_holdable} = $can_item_be_reserved unless ( $can_item_be_reserved eq 'OK' );
570
570
571
                $item->{item_level_holds} = Koha::CirculationRules->get_opacitemholds_policy( { item => $item_object, patron => $patron } );
571
                $item->{item_level_holds} = Koha::CirculationRules->get_opacitemholds_policy( { item => $item_object, patron => $patron } );
(-)a/t/db_dependent/Holds.t (-100 / +101 lines)
Lines 64-77 my $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumbe Link Here
64
64
65
# Create some borrowers
65
# Create some borrowers
66
my @borrowernumbers;
66
my @borrowernumbers;
67
my @patrons;
67
foreach (1..$borrowers_count) {
68
foreach (1..$borrowers_count) {
68
    my $borrowernumber = Koha::Patron->new({
69
    my $patron = Koha::Patron->new({
69
        firstname =>  'my firstname',
70
        firstname =>  'my firstname',
70
        surname => 'my surname ' . $_,
71
        surname => 'my surname ' . $_,
71
        categorycode => $category->{categorycode},
72
        categorycode => $category->{categorycode},
72
        branchcode => $branch_1,
73
        branchcode => $branch_1,
73
    })->store->borrowernumber;
74
    })->store;
74
    push @borrowernumbers, $borrowernumber;
75
    push @patrons, $patron;
76
    push @borrowernumbers, $patron->borrowernumber;
75
}
77
}
76
78
77
# Create five item level holds
79
# Create five item level holds
Lines 233-239 is( $hold->priority, '6', "Test AlterPriority(), move to bottom" ); Link Here
233
# IndependentBranches is OFF.
235
# IndependentBranches is OFF.
234
236
235
my $foreign_biblio = $builder->build_sample_biblio({ itemtype => 'DUMMY' });
237
my $foreign_biblio = $builder->build_sample_biblio({ itemtype => 'DUMMY' });
236
my $foreign_itemnumber = $builder->build_sample_item({ library => $branch_2, biblionumber => $foreign_biblio->biblionumber })->itemnumber;
238
my $foreign_item = $builder->build_sample_item({ library => $branch_2, biblionumber => $foreign_biblio->biblionumber });
237
Koha::CirculationRules->set_rules(
239
Koha::CirculationRules->set_rules(
238
    {
240
    {
239
        categorycode => undef,
241
        categorycode => undef,
Lines 265-271 t::lib::Mocks::mock_preference('item-level_itypes', 1); Link Here
265
t::lib::Mocks::mock_preference('IndependentBranches', 0);
267
t::lib::Mocks::mock_preference('IndependentBranches', 0);
266
268
267
is(
269
is(
268
    CanItemBeReserved($borrowernumbers[0], $foreign_itemnumber)->{status}, 'OK',
270
    CanItemBeReserved($patrons[0], $foreign_item)->{status}, 'OK',
269
    '$branch_1 patron allowed to reserve $branch_2 item with IndependentBranches OFF (bug 2394)'
271
    '$branch_1 patron allowed to reserve $branch_2 item with IndependentBranches OFF (bug 2394)'
270
);
272
);
271
273
Lines 273-286 is( Link Here
273
t::lib::Mocks::mock_preference('IndependentBranches', 1);
275
t::lib::Mocks::mock_preference('IndependentBranches', 1);
274
t::lib::Mocks::mock_preference('canreservefromotherbranches', 0);
276
t::lib::Mocks::mock_preference('canreservefromotherbranches', 0);
275
ok(
277
ok(
276
    CanItemBeReserved($borrowernumbers[0], $foreign_itemnumber)->{status} eq 'cannotReserveFromOtherBranches',
278
    CanItemBeReserved($patrons[0], $foreign_item)->{status} eq 'cannotReserveFromOtherBranches',
277
    '$branch_1 patron NOT allowed to reserve $branch_2 item with IndependentBranches ON ... (bug 2394)'
279
    '$branch_1 patron NOT allowed to reserve $branch_2 item with IndependentBranches ON ... (bug 2394)'
278
);
280
);
279
281
280
# ... unless canreservefromotherbranches is ON
282
# ... unless canreservefromotherbranches is ON
281
t::lib::Mocks::mock_preference('canreservefromotherbranches', 1);
283
t::lib::Mocks::mock_preference('canreservefromotherbranches', 1);
282
ok(
284
ok(
283
    CanItemBeReserved($borrowernumbers[0], $foreign_itemnumber)->{status} eq 'OK',
285
    CanItemBeReserved($patrons[0], $foreign_item)->{status} eq 'OK',
284
    '... unless canreservefromotherbranches is ON (bug 2394)'
286
    '... unless canreservefromotherbranches is ON (bug 2394)'
285
);
287
);
286
288
Lines 325-333 ok( Link Here
325
    is( $hold3->discard_changes->priority, 1, "After ModReserve, the 3rd reserve becomes the first on the waiting list" );
327
    is( $hold3->discard_changes->priority, 1, "After ModReserve, the 3rd reserve becomes the first on the waiting list" );
326
}
328
}
327
329
328
Koha::Items->find($itemnumber)->damaged(1)->store; # FIXME The $itemnumber is a bit confusing here
330
my $damaged_item = Koha::Items->find($itemnumber)->damaged(1)->store; # FIXME The $itemnumber is a bit confusing here
329
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 1 );
331
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 1 );
330
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber)->{status}, 'OK', "Patron can reserve damaged item with AllowHoldsOnDamagedItems enabled" );
332
is( CanItemBeReserved( $patrons[0], $damaged_item)->{status}, 'OK', "Patron can reserve damaged item with AllowHoldsOnDamagedItems enabled" );
331
ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold can be trapped for damaged item with AllowHoldsOnDamagedItems enabled" );
333
ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold can be trapped for damaged item with AllowHoldsOnDamagedItems enabled" );
332
334
333
$hold = Koha::Hold->new(
335
$hold = Koha::Hold->new(
Lines 337-356 $hold = Koha::Hold->new( Link Here
337
        biblionumber   => $biblio->biblionumber,
339
        biblionumber   => $biblio->biblionumber,
338
    }
340
    }
339
)->store();
341
)->store();
340
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber )->{status},
342
is( CanItemBeReserved( $patrons[0], $damaged_item )->{status},
341
    'itemAlreadyOnHold',
343
    'itemAlreadyOnHold',
342
    "Patron cannot place a second item level hold for a given item" );
344
    "Patron cannot place a second item level hold for a given item" );
343
$hold->delete();
345
$hold->delete();
344
346
345
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 0 );
347
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 0 );
346
ok( CanItemBeReserved( $borrowernumbers[0], $itemnumber)->{status} eq 'damaged', "Patron cannot reserve damaged item with AllowHoldsOnDamagedItems disabled" );
348
ok( CanItemBeReserved( $patrons[0], $damaged_item)->{status} eq 'damaged', "Patron cannot reserve damaged item with AllowHoldsOnDamagedItems disabled" );
347
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for damaged item with AllowHoldsOnDamagedItems disabled" );
349
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for damaged item with AllowHoldsOnDamagedItems disabled" );
348
350
349
# Items that are not for loan, but holdable should not be trapped until they are available for loan
351
# Items that are not for loan, but holdable should not be trapped until they are available for loan
350
t::lib::Mocks::mock_preference( 'TrapHoldsOnOrder', 0 );
352
t::lib::Mocks::mock_preference( 'TrapHoldsOnOrder', 0 );
351
Koha::Items->find($itemnumber)->damaged(0)->notforloan(-1)->store;
353
my $nfl_item = Koha::Items->find($itemnumber)->damaged(0)->notforloan(-1)->store;
352
Koha::Holds->search({ biblionumber => $biblio->id })->delete();
354
Koha::Holds->search({ biblionumber => $biblio->id })->delete();
353
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber)->{status}, 'OK', "Patron can place hold on item that is not for loan but holdable ( notforloan < 0 )" );
355
is( CanItemBeReserved( $patrons[0], $nfl_item)->{status}, 'OK', "Patron can place hold on item that is not for loan but holdable ( notforloan < 0 )" );
354
$hold = Koha::Hold->new(
356
$hold = Koha::Hold->new(
355
    {
357
    {
356
        borrowernumber => $borrowernumbers[0],
358
        borrowernumber => $borrowernumbers[0],
Lines 370-380 ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for i Link Here
370
t::lib::Mocks::mock_preference( 'SkipHoldTrapOnNotForLoanValue', '-1|1' );
372
t::lib::Mocks::mock_preference( 'SkipHoldTrapOnNotForLoanValue', '-1|1' );
371
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for item with notforloan value matching SkipHoldTrapOnNotForLoanValue" );
373
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for item with notforloan value matching SkipHoldTrapOnNotForLoanValue" );
372
is(
374
is(
373
    CanItemBeReserved( $borrowernumbers[0], $itemnumber)->{status}, 'itemAlreadyOnHold',
375
    CanItemBeReserved( $patrons[0], $nfl_item)->{status}, 'itemAlreadyOnHold',
374
    "cannot request item that you have already reservedd"
376
    "cannot request item that you have already reservedd"
375
);
377
);
376
is(
378
is(
377
    CanItemBeReserved( $borrowernumbers[0], $item->itemnumber, undef, { ignore_hold_counts => 1 })->{status}, 'OK',
379
    CanItemBeReserved( $patrons[0], $item, undef, { ignore_hold_counts => 1 })->{status}, 'OK',
378
    "can request item if we are not checking holds counts, but only if policy allows or forbids it"
380
    "can request item if we are not checking holds counts, but only if policy allows or forbids it"
379
);
381
);
380
$hold->delete();
382
$hold->delete();
Lines 391-401 AddReserve( Link Here
391
    }
393
    }
392
);
394
);
393
is(
395
is(
394
    CanItemBeReserved( $borrowernumbers[0], $item->itemnumber)->{status}, 'noReservesAllowed',
396
    CanItemBeReserved( $patrons[0], $item)->{status}, 'noReservesAllowed',
395
    "cannot request item if policy that matches on item-level item type forbids it"
397
    "cannot request item if policy that matches on item-level item type forbids it"
396
);
398
);
397
is(
399
is(
398
    CanItemBeReserved( $borrowernumbers[0], $item->itemnumber, undef, { ignore_hold_counts => 1 })->{status}, 'noReservesAllowed',
400
    CanItemBeReserved( $patrons[0], $item, undef, { ignore_hold_counts => 1 })->{status}, 'noReservesAllowed',
399
    "cannot request item if policy that matches on item-level item type forbids it even if ignoring counts"
401
    "cannot request item if policy that matches on item-level item type forbids it even if ignoring counts"
400
);
402
);
401
403
Lines 468-501 subtest 'CanItemBeReserved' => sub { Link Here
468
        my $biblionumber_can = $builder->build_sample_biblio({ itemtype => $itemtype_can })->biblionumber;
470
        my $biblionumber_can = $builder->build_sample_biblio({ itemtype => $itemtype_can })->biblionumber;
469
        my $biblionumber_record_cannot = $builder->build_sample_biblio({ itemtype => $itemtype_cant_record })->biblionumber;
471
        my $biblionumber_record_cannot = $builder->build_sample_biblio({ itemtype => $itemtype_cant_record })->biblionumber;
470
472
471
        my $itemnumber_1_can = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_cannot })->itemnumber;
473
        my $item_1_can = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_cannot });
472
        my $itemnumber_1_cannot = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_cant, biblionumber => $biblionumber_cannot })->itemnumber;
474
        my $item_1_cannot = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_cant, biblionumber => $biblionumber_cannot });
473
        my $itemnumber_2_can = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_can })->itemnumber;
475
        my $item_2_can = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_can });
474
        my $itemnumber_2_cannot = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_cant, biblionumber => $biblionumber_can })->itemnumber;
476
        my $item_2_cannot = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_cant, biblionumber => $biblionumber_can });
475
        my $itemnumber_3_cannot = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_cant_record, biblionumber => $biblionumber_record_cannot })->itemnumber;
477
        my $item_3_cannot = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_cant_record, biblionumber => $biblionumber_record_cannot });
476
478
477
        Koha::Holds->search({borrowernumber => $borrowernumbers[0]})->delete;
479
        Koha::Holds->search({borrowernumber => $borrowernumbers[0]})->delete;
478
480
479
        t::lib::Mocks::mock_preference('item-level_itypes', 1);
481
        t::lib::Mocks::mock_preference('item-level_itypes', 1);
480
        is(
482
        is(
481
            CanItemBeReserved( $borrowernumbers[0], $itemnumber_2_cannot)->{status}, 'noReservesAllowed',
483
            CanItemBeReserved( $patrons[0], $item_2_cannot)->{status}, 'noReservesAllowed',
482
            "With item level set, rule from item must be picked (CANNOT)"
484
            "With item level set, rule from item must be picked (CANNOT)"
483
        );
485
        );
484
        is(
486
        is(
485
            CanItemBeReserved( $borrowernumbers[0], $itemnumber_1_can)->{status}, 'OK',
487
            CanItemBeReserved( $patrons[0], $item_1_can)->{status}, 'OK',
486
            "With item level set, rule from item must be picked (CAN)"
488
            "With item level set, rule from item must be picked (CAN)"
487
        );
489
        );
488
        t::lib::Mocks::mock_preference('item-level_itypes', 0);
490
        t::lib::Mocks::mock_preference('item-level_itypes', 0);
489
        is(
491
        is(
490
            CanItemBeReserved( $borrowernumbers[0], $itemnumber_1_can)->{status}, 'noReservesAllowed',
492
            CanItemBeReserved( $patrons[0], $item_1_can)->{status}, 'noReservesAllowed',
491
            "With biblio level set, rule from biblio must be picked (CANNOT)"
493
            "With biblio level set, rule from biblio must be picked (CANNOT)"
492
        );
494
        );
493
        is(
495
        is(
494
            CanItemBeReserved( $borrowernumbers[0], $itemnumber_2_cannot)->{status}, 'OK',
496
            CanItemBeReserved( $patrons[0], $item_2_cannot)->{status}, 'OK',
495
            "With biblio level set, rule from biblio must be picked (CAN)"
497
            "With biblio level set, rule from biblio must be picked (CAN)"
496
        );
498
        );
497
        is(
499
        is(
498
            CanItemBeReserved( $borrowernumbers[0], $itemnumber_3_cannot)->{status}, 'noReservesAllowed',
500
            CanItemBeReserved( $patrons[0], $item_3_cannot)->{status}, 'noReservesAllowed',
499
            "When no holds allowed and no holds per record allowed should return noReservesAllowed"
501
            "When no holds allowed and no holds per record allowed should return noReservesAllowed"
500
        );
502
        );
501
    };
503
    };
Lines 504-514 subtest 'CanItemBeReserved' => sub { Link Here
504
        plan tests => 7;
506
        plan tests => 7;
505
507
506
        my $biblionumber_1 = $builder->build_sample_biblio({ itemtype => $itemtype_can })->biblionumber;
508
        my $biblionumber_1 = $builder->build_sample_biblio({ itemtype => $itemtype_can })->biblionumber;
507
        my $itemnumber_11 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_1 })->itemnumber;
509
        my $item_11 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_1 });
508
        my $itemnumber_12 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_1 })->itemnumber;
510
        my $item_12 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_1 });
509
        my $biblionumber_2 = $builder->build_sample_biblio({ itemtype => $itemtype_can })->biblionumber;
511
        my $biblionumber_2 = $builder->build_sample_biblio({ itemtype => $itemtype_can })->biblionumber;
510
        my $itemnumber_21 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_2 })->itemnumber;
512
        my $item_21 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_2 });
511
        my $itemnumber_22 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_2 })->itemnumber;
513
        my $item_22 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_2 });
512
514
513
        Koha::Holds->search({borrowernumber => $borrowernumbers[0]})->delete;
515
        Koha::Holds->search({borrowernumber => $borrowernumbers[0]})->delete;
514
516
Lines 522-528 subtest 'CanItemBeReserved' => sub { Link Here
522
            t::lib::Mocks::mock_preference('item-level_itypes', $item_level);
524
            t::lib::Mocks::mock_preference('item-level_itypes', $item_level);
523
            is(
525
            is(
524
                # FIXME This is not really correct, but CanItemBeReserved does not check if biblio-level holds already exist
526
                # FIXME This is not really correct, but CanItemBeReserved does not check if biblio-level holds already exist
525
                CanItemBeReserved( $borrowernumbers[0], $itemnumber_11)->{status}, 'OK',
527
                CanItemBeReserved( $patrons[0], $item_11)->{status}, 'OK',
526
                "A biblio-level hold already exists - another hold can be placed on a specific item item"
528
                "A biblio-level hold already exists - another hold can be placed on a specific item item"
527
            );
529
            );
528
        }
530
        }
Lines 533-539 subtest 'CanItemBeReserved' => sub { Link Here
533
            branch => $branch_1,
535
            branch => $branch_1,
534
            borrowernumber => $borrowernumbers[0],
536
            borrowernumber => $borrowernumbers[0],
535
            biblionumber => $biblionumber_1,
537
            biblionumber => $biblionumber_1,
536
            itemnumber => $itemnumber_11,
538
            itemnumber => $item_11->itemnumber,
537
        });
539
        });
538
540
539
        $dbh->do('DELETE FROM circulation_rules');
541
        $dbh->do('DELETE FROM circulation_rules');
Lines 549-555 subtest 'CanItemBeReserved' => sub { Link Here
549
            }
551
            }
550
        );
552
        );
551
        is(
553
        is(
552
            CanItemBeReserved( $borrowernumbers[0], $itemnumber_12)->{status}, 'tooManyHoldsForThisRecord',
554
            CanItemBeReserved( $patrons[0], $item_12)->{status}, 'tooManyHoldsForThisRecord',
553
            "A item-level hold already exists and holds_per_record=1, another hold cannot be placed on this record"
555
            "A item-level hold already exists and holds_per_record=1, another hold cannot be placed on this record"
554
        );
556
        );
555
        Koha::CirculationRules->set_rules(
557
        Koha::CirculationRules->set_rules(
Lines 564-570 subtest 'CanItemBeReserved' => sub { Link Here
564
            }
566
            }
565
        );
567
        );
566
        is(
568
        is(
567
            CanItemBeReserved( $borrowernumbers[0], $itemnumber_12)->{status}, 'tooManyHoldsForThisRecord',
569
            CanItemBeReserved( $patrons[0], $item_12)->{status}, 'tooManyHoldsForThisRecord',
568
            "A item-level hold already exists and holds_per_record=1 - tooManyHoldsForThisRecord has priority over tooManyReserves"
570
            "A item-level hold already exists and holds_per_record=1 - tooManyHoldsForThisRecord has priority over tooManyReserves"
569
        );
571
        );
570
        Koha::CirculationRules->set_rules(
572
        Koha::CirculationRules->set_rules(
Lines 579-585 subtest 'CanItemBeReserved' => sub { Link Here
579
            }
581
            }
580
        );
582
        );
581
        is(
583
        is(
582
            CanItemBeReserved( $borrowernumbers[0], $itemnumber_12)->{status}, 'OK',
584
            CanItemBeReserved( $patrons[0], $item_12)->{status}, 'OK',
583
            "A item-level hold already exists but holds_per_record=2- another item-level hold can be placed on this record"
585
            "A item-level hold already exists but holds_per_record=2- another item-level hold can be placed on this record"
584
        );
586
        );
585
587
Lines 587-593 subtest 'CanItemBeReserved' => sub { Link Here
587
            branch => $branch_1,
589
            branch => $branch_1,
588
            borrowernumber => $borrowernumbers[0],
590
            borrowernumber => $borrowernumbers[0],
589
            biblionumber => $biblionumber_2,
591
            biblionumber => $biblionumber_2,
590
            itemnumber => $itemnumber_21
592
            itemnumber => $item_21->itemnumber
591
        });
593
        });
592
        Koha::CirculationRules->set_rules(
594
        Koha::CirculationRules->set_rules(
593
            {
595
            {
Lines 601-611 subtest 'CanItemBeReserved' => sub { Link Here
601
            }
603
            }
602
        );
604
        );
603
        is(
605
        is(
604
            CanItemBeReserved( $borrowernumbers[0], $itemnumber_21)->{status}, 'itemAlreadyOnHold',
606
            CanItemBeReserved( $patrons[0], $item_21)->{status}, 'itemAlreadyOnHold',
605
            "A item-level holds already exists on this item, itemAlreadyOnHold should be raised"
607
            "A item-level holds already exists on this item, itemAlreadyOnHold should be raised"
606
        );
608
        );
607
        is(
609
        is(
608
            CanItemBeReserved( $borrowernumbers[0], $itemnumber_22)->{status}, 'tooManyReserves',
610
            CanItemBeReserved( $patrons[0], $item_22)->{status}, 'tooManyReserves',
609
            "This patron has already placed reservesallowed holds, tooManyReserves should be raised"
611
            "This patron has already placed reservesallowed holds, tooManyReserves should be raised"
610
        );
612
        );
611
    };
613
    };
Lines 647-668 Koha::CirculationRules->set_rules( Link Here
647
    }
649
    }
648
);
650
);
649
$biblio = $builder->build_sample_biblio({ itemtype => 'CANNOT' });
651
$biblio = $builder->build_sample_biblio({ itemtype => 'CANNOT' });
650
$itemnumber = $builder->build_sample_item({ library => $branch_1, itype => 'CANNOT', biblionumber => $biblio->biblionumber})->itemnumber;
652
my $branch_rule_item = $builder->build_sample_item({ library => $branch_1, itype => 'CANNOT', biblionumber => $biblio->biblionumber});
651
is(CanItemBeReserved($borrowernumbers[0], $itemnumber)->{status}, 'notReservable',
653
is(CanItemBeReserved($patrons[0], $branch_rule_item)->{status}, 'notReservable',
652
    "CanItemBeReserved should return 'notReservable'");
654
    "CanItemBeReserved should return 'notReservable'");
653
655
654
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
656
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
655
$itemnumber = $builder->build_sample_item({ library => $branch_2, itype => 'CAN', biblionumber => $biblio->biblionumber})->itemnumber;
657
$branch_rule_item = $builder->build_sample_item({ library => $branch_2, itype => 'CAN', biblionumber => $biblio->biblionumber});
656
is(CanItemBeReserved($borrowernumbers[0], $itemnumber)->{status},
658
is(CanItemBeReserved($patrons[0], $branch_rule_item)->{status},
657
    'cannotReserveFromOtherBranches',
659
    'cannotReserveFromOtherBranches',
658
    "CanItemBeReserved should use PatronLibrary rule when ReservesControlBranch set to 'PatronLibrary'");
660
    "CanItemBeReserved should use PatronLibrary rule when ReservesControlBranch set to 'PatronLibrary'");
659
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'ItemHomeLibrary' );
661
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'ItemHomeLibrary' );
660
is(CanItemBeReserved($borrowernumbers[0], $itemnumber)->{status},
662
is(CanItemBeReserved($patrons[0], $branch_rule_item)->{status},
661
    'OK',
663
    'OK',
662
    "CanItemBeReserved should use item home library rule when ReservesControlBranch set to 'ItemsHomeLibrary'");
664
    "CanItemBeReserved should use item home library rule when ReservesControlBranch set to 'ItemsHomeLibrary'");
663
665
664
$itemnumber = $builder->build_sample_item({ library => $branch_1, itype => 'CAN', biblionumber => $biblio->biblionumber})->itemnumber;
666
$branch_rule_item = $builder->build_sample_item({ library => $branch_1, itype => 'CAN', biblionumber => $biblio->biblionumber});
665
is(CanItemBeReserved($borrowernumbers[0], $itemnumber)->{status}, 'OK',
667
is(CanItemBeReserved($patrons[0], $branch_rule_item)->{status}, 'OK',
666
    "CanItemBeReserved should return 'OK'");
668
    "CanItemBeReserved should return 'OK'");
667
669
668
# Bug 12632
670
# Bug 12632
Lines 675-681 $dbh->do('DELETE FROM items'); Link Here
675
$dbh->do('DELETE FROM biblio');
677
$dbh->do('DELETE FROM biblio');
676
678
677
$biblio = $builder->build_sample_biblio({ itemtype => 'ONLY1' });
679
$biblio = $builder->build_sample_biblio({ itemtype => 'ONLY1' });
678
$itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
680
my $limit_count_item = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber});
679
681
680
Koha::CirculationRules->set_rules(
682
Koha::CirculationRules->set_rules(
681
    {
683
    {
Lines 688-694 Koha::CirculationRules->set_rules( Link Here
688
        }
690
        }
689
    }
691
    }
690
);
692
);
691
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber )->{status},
693
is( CanItemBeReserved( $patrons[0], $limit_count_item )->{status},
692
    'OK', 'Patron can reserve item with hold limit of 1, no holds placed' );
694
    'OK', 'Patron can reserve item with hold limit of 1, no holds placed' );
693
695
694
my $res_id = AddReserve(
696
my $res_id = AddReserve(
Lines 700-713 my $res_id = AddReserve( Link Here
700
    }
702
    }
701
);
703
);
702
704
703
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber )->{status},
705
is( CanItemBeReserved( $patrons[0], $limit_count_item )->{status},
704
    'tooManyReserves', 'Patron cannot reserve item with hold limit of 1, 1 bib level hold placed' );
706
    'tooManyReserves', 'Patron cannot reserve item with hold limit of 1, 1 bib level hold placed' );
705
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber, undef, { ignore_hold_counts => 1 } )->{status},
707
is( CanItemBeReserved( $patrons[0], $limit_count_item, undef, { ignore_hold_counts => 1 } )->{status},
706
    'OK', 'Patron can reserve item if checking policy but not counts' );
708
    'OK', 'Patron can reserve item if checking policy but not counts' );
707
709
708
    #results should be the same for both ReservesControlBranch settings
710
    #results should be the same for both ReservesControlBranch settings
709
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'ItemHomeLibrary' );
711
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'ItemHomeLibrary' );
710
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber )->{status},
712
is( CanItemBeReserved( $patrons[0], $limit_count_item )->{status},
711
    'tooManyReserves', 'Patron cannot reserve item with hold limit of 1, 1 bib level hold placed' );
713
    'tooManyReserves', 'Patron cannot reserve item with hold limit of 1, 1 bib level hold placed' );
712
#reset for further tests
714
#reset for further tests
713
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
715
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
Lines 718-724 subtest 'Test max_holds per library/patron category' => sub { Link Here
718
    $dbh->do('DELETE FROM reserves');
720
    $dbh->do('DELETE FROM reserves');
719
721
720
    $biblio = $builder->build_sample_biblio;
722
    $biblio = $builder->build_sample_biblio;
721
    $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
723
    my $max_holds_item = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber});
722
    Koha::CirculationRules->set_rules(
724
    Koha::CirculationRules->set_rules(
723
        {
725
        {
724
            categorycode => undef,
726
            categorycode => undef,
Lines 746-752 subtest 'Test max_holds per library/patron category' => sub { Link Here
746
      Koha::Holds->search( { borrowernumber => $borrowernumbers[0] } )->count();
748
      Koha::Holds->search( { borrowernumber => $borrowernumbers[0] } )->count();
747
    is( $count, 3, 'Patron now has 3 holds' );
749
    is( $count, 3, 'Patron now has 3 holds' );
748
750
749
    my $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
751
    my $ret = CanItemBeReserved( $patrons[0], $max_holds_item );
750
    is( $ret->{status}, 'OK', 'Patron can place hold with no borrower circ rules' );
752
    is( $ret->{status}, 'OK', 'Patron can place hold with no borrower circ rules' );
751
753
752
    my $rule_all = Koha::CirculationRules->set_rule(
754
    my $rule_all = Koha::CirculationRules->set_rule(
Lines 767-785 subtest 'Test max_holds per library/patron category' => sub { Link Here
767
        }
769
        }
768
    );
770
    );
769
771
770
    $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
772
    $ret = CanItemBeReserved( $patrons[0], $max_holds_item );
771
    is( $ret->{status}, 'OK', 'Patron can place hold with branch/category rule of 5, category rule of 3' );
773
    is( $ret->{status}, 'OK', 'Patron can place hold with branch/category rule of 5, category rule of 3' );
772
774
773
    $rule_branch->delete();
775
    $rule_branch->delete();
774
776
775
    $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
777
    $ret = CanItemBeReserved( $patrons[0], $max_holds_item );
776
    is( $ret->{status}, 'tooManyReserves', 'Patron cannot place hold with only a category rule of 3' );
778
    is( $ret->{status}, 'tooManyReserves', 'Patron cannot place hold with only a category rule of 3' );
777
779
778
    $rule_all->delete();
780
    $rule_all->delete();
779
    $rule_branch->rule_value(3);
781
    $rule_branch->rule_value(3);
780
    $rule_branch->store();
782
    $rule_branch->store();
781
783
782
    $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
784
    $ret = CanItemBeReserved( $patrons[0], $max_holds_item );
783
    is( $ret->{status}, 'tooManyReserves', 'Patron cannot place hold with only a branch/category rule of 3' );
785
    is( $ret->{status}, 'tooManyReserves', 'Patron cannot place hold with only a branch/category rule of 3' );
784
786
785
    $rule_branch->rule_value(5);
787
    $rule_branch->rule_value(5);
Lines 787-793 subtest 'Test max_holds per library/patron category' => sub { Link Here
787
    $rule_branch->rule_value(5);
789
    $rule_branch->rule_value(5);
788
    $rule_branch->store();
790
    $rule_branch->store();
789
791
790
    $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
792
    $ret = CanItemBeReserved( $patrons[0], $max_holds_item );
791
    is( $ret->{status}, 'OK', 'Patron can place hold with branch/category rule of 5, category rule of 5' );
793
    is( $ret->{status}, 'OK', 'Patron can place hold with branch/category rule of 5, category rule of 5' );
792
};
794
};
793
795
Lines 795-801 subtest 'Pickup location availability tests' => sub { Link Here
795
    plan tests => 4;
797
    plan tests => 4;
796
798
797
    $biblio = $builder->build_sample_biblio({ itemtype => 'ONLY1' });
799
    $biblio = $builder->build_sample_biblio({ itemtype => 'ONLY1' });
798
    $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
800
    my $pickup_item = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber});
799
    #Add a default rule to allow some holds
801
    #Add a default rule to allow some holds
800
802
801
    Koha::CirculationRules->set_rules(
803
    Koha::CirculationRules->set_rules(
Lines 809-840 subtest 'Pickup location availability tests' => sub { Link Here
809
            }
811
            }
810
        }
812
        }
811
    );
813
    );
812
    my $item = Koha::Items->find($itemnumber);
813
    my $branch_to = $builder->build({ source => 'Branch' })->{ branchcode };
814
    my $branch_to = $builder->build({ source => 'Branch' })->{ branchcode };
814
    my $library = Koha::Libraries->find($branch_to);
815
    my $library = Koha::Libraries->find($branch_to);
815
    $library->pickup_location('1')->store;
816
    $library->pickup_location('1')->store;
816
    my $patron = $builder->build({ source => 'Borrower' })->{ borrowernumber };
817
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
817
818
818
    t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1);
819
    t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1);
819
    t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype');
820
    t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype');
820
821
821
    $library->pickup_location('1')->store;
822
    $library->pickup_location('1')->store;
822
    is(CanItemBeReserved($patron, $item->itemnumber, $branch_to)->{status},
823
    is(CanItemBeReserved($patron, $pickup_item, $branch_to)->{status},
823
       'OK', 'Library is a pickup location');
824
       'OK', 'Library is a pickup location');
824
825
825
    my $limit = Koha::Item::Transfer::Limit->new({
826
    my $limit = Koha::Item::Transfer::Limit->new({
826
        fromBranch => $item->holdingbranch,
827
        fromBranch => $pickup_item->holdingbranch,
827
        toBranch => $branch_to,
828
        toBranch => $branch_to,
828
        itemtype => $item->effective_itemtype,
829
        itemtype => $pickup_item->effective_itemtype,
829
    })->store;
830
    })->store;
830
    is(CanItemBeReserved($patron, $item->itemnumber, $branch_to)->{status},
831
    is(CanItemBeReserved($patron, $pickup_item, $branch_to)->{status},
831
       'cannotBeTransferred', 'Item cannot be transferred');
832
       'cannotBeTransferred', 'Item cannot be transferred');
832
    $limit->delete;
833
    $limit->delete;
833
834
834
    $library->pickup_location('0')->store;
835
    $library->pickup_location('0')->store;
835
    is(CanItemBeReserved($patron, $item->itemnumber, $branch_to)->{status},
836
    is(CanItemBeReserved($patron, $pickup_item, $branch_to)->{status},
836
       'libraryNotPickupLocation', 'Library is not a pickup location');
837
       'libraryNotPickupLocation', 'Library is not a pickup location');
837
    is(CanItemBeReserved($patron, $item->itemnumber, 'nonexistent')->{status},
838
    is(CanItemBeReserved($patron, $pickup_item, 'nonexistent')->{status},
838
       'libraryNotFound', 'Cannot set unknown library as pickup location');
839
       'libraryNotFound', 'Cannot set unknown library as pickup location');
839
};
840
};
840
841
Lines 852-862 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
852
853
853
    # Create 3 biblios with items
854
    # Create 3 biblios with items
854
    my $biblio_1 = $builder->build_sample_biblio({ itemtype => $itemtype->itemtype });
855
    my $biblio_1 = $builder->build_sample_biblio({ itemtype => $itemtype->itemtype });
855
    my $itemnumber_1 = $builder->build_sample_item({ library => $library->branchcode, biblionumber => $biblio_1->biblionumber})->itemnumber;
856
    my $item_1 = $builder->build_sample_item({ library => $library->branchcode, biblionumber => $biblio_1->biblionumber});
856
    my $biblio_2 = $builder->build_sample_biblio({ itemtype => $itemtype->itemtype });
857
    my $biblio_2 = $builder->build_sample_biblio({ itemtype => $itemtype->itemtype });
857
    my $itemnumber_2 = $builder->build_sample_item({ library => $library->branchcode, biblionumber => $biblio_2->biblionumber})->itemnumber;
858
    my $item_2 = $builder->build_sample_item({ library => $library->branchcode, biblionumber => $biblio_2->biblionumber});
858
    my $biblio_3 = $builder->build_sample_biblio({ itemtype => $itemtype->itemtype });
859
    my $biblio_3 = $builder->build_sample_biblio({ itemtype => $itemtype->itemtype });
859
    my $itemnumber_3 = $builder->build_sample_item({ library => $library->branchcode, biblionumber => $biblio_3->biblionumber})->itemnumber;
860
    my $item_3 = $builder->build_sample_item({ library => $library->branchcode, biblionumber => $biblio_3->biblionumber});
860
861
861
    Koha::CirculationRules->set_rules(
862
    Koha::CirculationRules->set_rules(
862
        {
863
        {
Lines 872-878 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
872
    );
873
    );
873
874
874
    is_deeply(
875
    is_deeply(
875
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_1 ),
876
        CanItemBeReserved( $patron, $item_1 ),
876
        { status => 'OK' },
877
        { status => 'OK' },
877
        'Patron can reserve item with hold limit of 1, no holds placed'
878
        'Patron can reserve item with hold limit of 1, no holds placed'
878
    );
879
    );
Lines 887-893 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
887
    );
888
    );
888
889
889
    is_deeply(
890
    is_deeply(
890
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_1 ),
891
        CanItemBeReserved( $patron, $item_1 ),
891
        { status => 'tooManyReserves', limit => 1 },
892
        { status => 'tooManyReserves', limit => 1 },
892
        'Patron cannot reserve item with hold limit of 1, 1 bib level hold placed'
893
        'Patron cannot reserve item with hold limit of 1, 1 bib level hold placed'
893
    );
894
    );
Lines 905-911 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
905
    );
906
    );
906
907
907
    is_deeply(
908
    is_deeply(
908
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
909
        CanItemBeReserved( $patron, $item_2 ),
909
        { status => 'OK' },
910
        { status => 'OK' },
910
        'Patron can reserve item with 2 reserves daily cap'
911
        'Patron can reserve item with 2 reserves daily cap'
911
    );
912
    );
Lines 920-926 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
920
        }
921
        }
921
    );
922
    );
922
    is_deeply(
923
    is_deeply(
923
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
924
        CanItemBeReserved( $patron, $item_2 ),
924
        { status => 'tooManyReservesToday', limit => 2 },
925
        { status => 'tooManyReservesToday', limit => 2 },
925
        'Patron cannot a third item with 2 reserves daily cap'
926
        'Patron cannot a third item with 2 reserves daily cap'
926
    );
927
    );
Lines 931-937 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
931
    $hold->reservedate($yesterday)->store;
932
    $hold->reservedate($yesterday)->store;
932
933
933
    is_deeply(
934
    is_deeply(
934
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
935
        CanItemBeReserved( $patron, $item_2 ),
935
        { status => 'OK' },
936
        { status => 'OK' },
936
        'Patron can reserve item with 2 bib level hold placed on different days, 2 reserves daily cap'
937
        'Patron can reserve item with 2 bib level hold placed on different days, 2 reserves daily cap'
937
    );
938
    );
Lines 952-958 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
952
    # Delete existing holds
953
    # Delete existing holds
953
    Koha::Holds->search->delete;
954
    Koha::Holds->search->delete;
954
    is_deeply(
955
    is_deeply(
955
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
956
        CanItemBeReserved( $patron, $item_2 ),
956
        { status => 'tooManyReservesToday', limit => 0 },
957
        { status => 'tooManyReservesToday', limit => 0 },
957
        'Patron cannot reserve if holds_per_day is 0 (i.e. 0 is 0)'
958
        'Patron cannot reserve if holds_per_day is 0 (i.e. 0 is 0)'
958
    );
959
    );
Lines 970-976 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
970
971
971
    Koha::Holds->search->delete;
972
    Koha::Holds->search->delete;
972
    is_deeply(
973
    is_deeply(
973
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
974
        CanItemBeReserved( $patron, $item_2 ),
974
        { status => 'OK' },
975
        { status => 'OK' },
975
        'Patron can reserve if holds_per_day is undef (i.e. undef is unlimited daily cap)'
976
        'Patron can reserve if holds_per_day is undef (i.e. undef is unlimited daily cap)'
976
    );
977
    );
Lines 992-998 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
992
    );
993
    );
993
994
994
    is_deeply(
995
    is_deeply(
995
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_3 ),
996
        CanItemBeReserved( $patron, $item_3 ),
996
        { status => 'OK' },
997
        { status => 'OK' },
997
        'Patron can reserve if holds_per_day is undef (i.e. undef is unlimited daily cap)'
998
        'Patron can reserve if holds_per_day is undef (i.e. undef is unlimited daily cap)'
998
    );
999
    );
Lines 1005-1018 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
1005
        }
1006
        }
1006
    );
1007
    );
1007
    is_deeply(
1008
    is_deeply(
1008
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_3 ),
1009
        CanItemBeReserved( $patron, $item_3 ),
1009
        { status => 'tooManyReserves', limit => 3 },
1010
        { status => 'tooManyReserves', limit => 3 },
1010
        'Unlimited daily holds, but reached reservesallowed'
1011
        'Unlimited daily holds, but reached reservesallowed'
1011
    );
1012
    );
1012
    #results should be the same for both ReservesControlBranch settings
1013
    #results should be the same for both ReservesControlBranch settings
1013
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
1014
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
1014
    is_deeply(
1015
    is_deeply(
1015
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_3 ),
1016
        CanItemBeReserved( $patron, $item_3 ),
1016
        { status => 'tooManyReserves', limit => 3 },
1017
        { status => 'tooManyReserves', limit => 3 },
1017
        'Unlimited daily holds, but reached reservesallowed'
1018
        'Unlimited daily holds, but reached reservesallowed'
1018
    );
1019
    );
Lines 1079-1085 subtest 'CanItemBeReserved / branch_not_in_hold_group' => sub { Link Here
1079
1080
1080
    # Test 1: Patron 3 can place hold
1081
    # Test 1: Patron 3 can place hold
1081
    is_deeply(
1082
    is_deeply(
1082
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2 ),
1083
        CanItemBeReserved( $patron3, $item_2 ),
1083
        { status => 'OK' },
1084
        { status => 'OK' },
1084
        'Patron can place hold if no circ_rules where defined'
1085
        'Patron can place hold if no circ_rules where defined'
1085
    );
1086
    );
Lines 1099-1112 subtest 'CanItemBeReserved / branch_not_in_hold_group' => sub { Link Here
1099
1100
1100
    # Test 2: Patron 1 can place hold
1101
    # Test 2: Patron 1 can place hold
1101
    is_deeply(
1102
    is_deeply(
1102
        CanItemBeReserved( $patron1->borrowernumber, $itemnumber_2 ),
1103
        CanItemBeReserved( $patron1, $item_2 ),
1103
        { status => 'OK' },
1104
        { status => 'OK' },
1104
        'Patron can place hold because patron\'s home library is part of hold group'
1105
        'Patron can place hold because patron\'s home library is part of hold group'
1105
    );
1106
    );
1106
1107
1107
    # Test 3: Patron 3 cannot place hold
1108
    # Test 3: Patron 3 cannot place hold
1108
    is_deeply(
1109
    is_deeply(
1109
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2 ),
1110
        CanItemBeReserved( $patron3, $item_2 ),
1110
        { status => 'branchNotInHoldGroup' },
1111
        { status => 'branchNotInHoldGroup' },
1111
        'Patron cannot place hold because patron\'s home library is not part of hold group'
1112
        'Patron cannot place hold because patron\'s home library is not part of hold group'
1112
    );
1113
    );
Lines 1126-1132 subtest 'CanItemBeReserved / branch_not_in_hold_group' => sub { Link Here
1126
1127
1127
    # Test 4: Patron 3 can place hold
1128
    # Test 4: Patron 3 can place hold
1128
    is_deeply(
1129
    is_deeply(
1129
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2 ),
1130
        CanItemBeReserved( $patron3, $item_2 ),
1130
        { status => 'OK' },
1131
        { status => 'OK' },
1131
        'Patron can place hold if holdallowed is set to "any" for library 2'
1132
        'Patron can place hold if holdallowed is set to "any" for library 2'
1132
    );
1133
    );
Lines 1146-1152 subtest 'CanItemBeReserved / branch_not_in_hold_group' => sub { Link Here
1146
1147
1147
    # Test 5: Patron 3 cannot place hold
1148
    # Test 5: Patron 3 cannot place hold
1148
    is_deeply(
1149
    is_deeply(
1149
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2 ),
1150
        CanItemBeReserved( $patron3, $item_2 ),
1150
        { status => 'branchNotInHoldGroup' },
1151
        { status => 'branchNotInHoldGroup' },
1151
        'Patron cannot place hold if holdallowed is set to "hold group" for library 2'
1152
        'Patron cannot place hold if holdallowed is set to "hold group" for library 2'
1152
    );
1153
    );
Lines 1166-1172 subtest 'CanItemBeReserved / branch_not_in_hold_group' => sub { Link Here
1166
1167
1167
    # Test 6: Patron 3 can place hold
1168
    # Test 6: Patron 3 can place hold
1168
    is_deeply(
1169
    is_deeply(
1169
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2 ),
1170
        CanItemBeReserved( $patron3, $item_2 ),
1170
        { status => 'OK' },
1171
        { status => 'OK' },
1171
        'Patron can place hold if holdallowed is set to "any" for itemtype 2'
1172
        'Patron can place hold if holdallowed is set to "any" for itemtype 2'
1172
    );
1173
    );
Lines 1186-1192 subtest 'CanItemBeReserved / branch_not_in_hold_group' => sub { Link Here
1186
1187
1187
    # Test 7: Patron 3 cannot place hold
1188
    # Test 7: Patron 3 cannot place hold
1188
    is_deeply(
1189
    is_deeply(
1189
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2 ),
1190
        CanItemBeReserved( $patron3, $item_2 ),
1190
        { status => 'branchNotInHoldGroup' },
1191
        { status => 'branchNotInHoldGroup' },
1191
        'Patron cannot place hold if holdallowed is set to "hold group" for itemtype 2'
1192
        'Patron cannot place hold if holdallowed is set to "hold group" for itemtype 2'
1192
    );
1193
    );
Lines 1206-1212 subtest 'CanItemBeReserved / branch_not_in_hold_group' => sub { Link Here
1206
1207
1207
    # Test 8: Patron 3 can place hold
1208
    # Test 8: Patron 3 can place hold
1208
    is_deeply(
1209
    is_deeply(
1209
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2 ),
1210
        CanItemBeReserved( $patron3, $item_2 ),
1210
        { status => 'OK' },
1211
        { status => 'OK' },
1211
        'Patron can place hold if holdallowed is set to "any" for itemtype 2 and library 2'
1212
        'Patron can place hold if holdallowed is set to "any" for itemtype 2 and library 2'
1212
    );
1213
    );
Lines 1226-1232 subtest 'CanItemBeReserved / branch_not_in_hold_group' => sub { Link Here
1226
1227
1227
    # Test 9: Patron 3 cannot place hold
1228
    # Test 9: Patron 3 cannot place hold
1228
    is_deeply(
1229
    is_deeply(
1229
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2 ),
1230
        CanItemBeReserved( $patron3, $item_2 ),
1230
        { status => 'branchNotInHoldGroup' },
1231
        { status => 'branchNotInHoldGroup' },
1231
        'Patron cannot place hold if holdallowed is set to "hold group" for itemtype 2 and library 2'
1232
        'Patron cannot place hold if holdallowed is set to "hold group" for itemtype 2 and library 2'
1232
    );
1233
    );
Lines 1293-1299 subtest 'CanItemBeReserved / pickup_not_in_hold_group' => sub { Link Here
1293
1294
1294
    # Test 1: Patron 3 can place hold
1295
    # Test 1: Patron 3 can place hold
1295
    is_deeply(
1296
    is_deeply(
1296
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2, $library3->branchcode ),
1297
        CanItemBeReserved( $patron3, $item_2, $library3->branchcode ),
1297
        { status => 'OK' },
1298
        { status => 'OK' },
1298
        'Patron can place hold if no circ_rules where defined'
1299
        'Patron can place hold if no circ_rules where defined'
1299
    );
1300
    );
Lines 1313-1326 subtest 'CanItemBeReserved / pickup_not_in_hold_group' => sub { Link Here
1313
1314
1314
    # Test 2: Patron 1 can place hold
1315
    # Test 2: Patron 1 can place hold
1315
    is_deeply(
1316
    is_deeply(
1316
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2, $library1->branchcode ),
1317
        CanItemBeReserved( $patron3, $item_2, $library1->branchcode ),
1317
        { status => 'OK' },
1318
        { status => 'OK' },
1318
        'Patron can place hold because pickup location is part of hold group'
1319
        'Patron can place hold because pickup location is part of hold group'
1319
    );
1320
    );
1320
1321
1321
    # Test 3: Patron 3 cannot place hold
1322
    # Test 3: Patron 3 cannot place hold
1322
    is_deeply(
1323
    is_deeply(
1323
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2, $library3->branchcode ),
1324
        CanItemBeReserved( $patron3, $item_2, $library3->branchcode ),
1324
        { status => 'pickupNotInHoldGroup' },
1325
        { status => 'pickupNotInHoldGroup' },
1325
        'Patron cannot place hold because pickup location is not part of hold group'
1326
        'Patron cannot place hold because pickup location is not part of hold group'
1326
    );
1327
    );
Lines 1340-1346 subtest 'CanItemBeReserved / pickup_not_in_hold_group' => sub { Link Here
1340
1341
1341
    # Test 4: Patron 3 can place hold
1342
    # Test 4: Patron 3 can place hold
1342
    is_deeply(
1343
    is_deeply(
1343
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2, $library3->branchcode ),
1344
        CanItemBeReserved( $patron3, $item_2, $library3->branchcode ),
1344
        { status => 'OK' },
1345
        { status => 'OK' },
1345
        'Patron can place hold if default_branch_circ_rules is set to "any" for library 2'
1346
        'Patron can place hold if default_branch_circ_rules is set to "any" for library 2'
1346
    );
1347
    );
Lines 1360-1366 subtest 'CanItemBeReserved / pickup_not_in_hold_group' => sub { Link Here
1360
1361
1361
    # Test 5: Patron 3 cannot place hold
1362
    # Test 5: Patron 3 cannot place hold
1362
    is_deeply(
1363
    is_deeply(
1363
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2, $library3->branchcode ),
1364
        CanItemBeReserved( $patron3, $item_2, $library3->branchcode ),
1364
        { status => 'pickupNotInHoldGroup' },
1365
        { status => 'pickupNotInHoldGroup' },
1365
        'Patron cannot place hold if hold_fulfillment_policy is set to "hold group" for library 2'
1366
        'Patron cannot place hold if hold_fulfillment_policy is set to "hold group" for library 2'
1366
    );
1367
    );
Lines 1380-1386 subtest 'CanItemBeReserved / pickup_not_in_hold_group' => sub { Link Here
1380
1381
1381
    # Test 6: Patron 3 can place hold
1382
    # Test 6: Patron 3 can place hold
1382
    is_deeply(
1383
    is_deeply(
1383
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2, $library3->branchcode ),
1384
        CanItemBeReserved( $patron3, $item_2, $library3->branchcode ),
1384
        { status => 'OK' },
1385
        { status => 'OK' },
1385
        'Patron can place hold if hold_fulfillment_policy is set to "any" for itemtype 2'
1386
        'Patron can place hold if hold_fulfillment_policy is set to "any" for itemtype 2'
1386
    );
1387
    );
Lines 1400-1406 subtest 'CanItemBeReserved / pickup_not_in_hold_group' => sub { Link Here
1400
1401
1401
    # Test 7: Patron 3 cannot place hold
1402
    # Test 7: Patron 3 cannot place hold
1402
    is_deeply(
1403
    is_deeply(
1403
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2, $library3->branchcode ),
1404
        CanItemBeReserved( $patron3, $item_2, $library3->branchcode ),
1404
        { status => 'pickupNotInHoldGroup' },
1405
        { status => 'pickupNotInHoldGroup' },
1405
        'Patron cannot place hold if hold_fulfillment_policy is set to "hold group" for itemtype 2'
1406
        'Patron cannot place hold if hold_fulfillment_policy is set to "hold group" for itemtype 2'
1406
    );
1407
    );
Lines 1420-1426 subtest 'CanItemBeReserved / pickup_not_in_hold_group' => sub { Link Here
1420
1421
1421
    # Test 8: Patron 3 can place hold
1422
    # Test 8: Patron 3 can place hold
1422
    is_deeply(
1423
    is_deeply(
1423
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2, $library3->branchcode ),
1424
        CanItemBeReserved( $patron3, $item_2, $library3->branchcode ),
1424
        { status => 'OK' },
1425
        { status => 'OK' },
1425
        'Patron can place hold if hold_fulfillment_policy is set to "any" for itemtype 2 and library 2'
1426
        'Patron can place hold if hold_fulfillment_policy is set to "any" for itemtype 2 and library 2'
1426
    );
1427
    );
Lines 1440-1446 subtest 'CanItemBeReserved / pickup_not_in_hold_group' => sub { Link Here
1440
1441
1441
    # Test 9: Patron 3 cannot place hold
1442
    # Test 9: Patron 3 cannot place hold
1442
    is_deeply(
1443
    is_deeply(
1443
        CanItemBeReserved( $patron3->borrowernumber, $itemnumber_2, $library3->branchcode ),
1444
        CanItemBeReserved( $patron3, $item_2, $library3->branchcode ),
1444
        { status => 'pickupNotInHoldGroup' },
1445
        { status => 'pickupNotInHoldGroup' },
1445
        'Patron cannot place hold if hold_fulfillment_policy is set to "hold group" for itemtype 2 and library 2'
1446
        'Patron cannot place hold if hold_fulfillment_policy is set to "hold group" for itemtype 2 and library 2'
1446
    );
1447
    );
Lines 1574-1580 subtest 'CanItemBeReserved rule precedence tests' => sub { Link Here
1574
        }
1575
        }
1575
    );
1576
    );
1576
    is_deeply(
1577
    is_deeply(
1577
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1578
        CanItemBeReserved( $patron, $item, $library->branchcode ),
1578
        { status => 'OK' },
1579
        { status => 'OK' },
1579
        'Patron of specified category can place 1 hold on specified itemtype'
1580
        'Patron of specified category can place 1 hold on specified itemtype'
1580
    );
1581
    );
Lines 1587-1593 subtest 'CanItemBeReserved rule precedence tests' => sub { Link Here
1587
        borrowernumber => $patron->borrowernumber,
1588
        borrowernumber => $patron->borrowernumber,
1588
    }});
1589
    }});
1589
    is_deeply(
1590
    is_deeply(
1590
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1591
        CanItemBeReserved( $patron, $item, $library->branchcode ),
1591
        { status => 'tooManyReserves', limit => 1 },
1592
        { status => 'tooManyReserves', limit => 1 },
1592
        'Patron of specified category can place 1 hold on specified itemtype, cannot place a second'
1593
        'Patron of specified category can place 1 hold on specified itemtype, cannot place a second'
1593
    );
1594
    );
Lines 1602-1608 subtest 'CanItemBeReserved rule precedence tests' => sub { Link Here
1602
        }
1603
        }
1603
    );
1604
    );
1604
    is_deeply(
1605
    is_deeply(
1605
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1606
        CanItemBeReserved( $patron, $item, $library->branchcode ),
1606
        { status => 'OK' },
1607
        { status => 'OK' },
1607
        'Patron of specified category can place 1 hold on specified itemtype if library rule for all types and categories set to 2'
1608
        'Patron of specified category can place 1 hold on specified itemtype if library rule for all types and categories set to 2'
1608
    );
1609
    );
(-)a/t/db_dependent/Reserves.t (-5 / +2 lines)
Lines 1239-1246 subtest 'AllowHoldOnPatronPossession test' => sub { Link Here
1239
       'alreadypossession',
1239
       'alreadypossession',
1240
       'Patron cannot place hold on a book loaned to itself');
1240
       'Patron cannot place hold on a book loaned to itself');
1241
1241
1242
    is(C4::Reserves::CanItemBeReserved($patron->borrowernumber,
1242
    is(C4::Reserves::CanItemBeReserved( $patron, $item )->{status},
1243
                                       $item->itemnumber)->{status},
1244
       'alreadypossession',
1243
       'alreadypossession',
1245
       'Patron cannot place hold on an item loaned to itself');
1244
       'Patron cannot place hold on an item loaned to itself');
1246
1245
Lines 1251-1258 subtest 'AllowHoldOnPatronPossession test' => sub { Link Here
1251
       'OK',
1250
       'OK',
1252
       'Patron can place hold on a book loaned to itself');
1251
       'Patron can place hold on a book loaned to itself');
1253
1252
1254
    is(C4::Reserves::CanItemBeReserved($patron->borrowernumber,
1253
    is(C4::Reserves::CanItemBeReserved( $patron, $item )->{status},
1255
                                       $item->itemnumber)->{status},
1256
       'OK',
1254
       'OK',
1257
       'Patron can place hold on an item loaned to itself');
1255
       'Patron can place hold on an item loaned to itself');
1258
};
1256
};
1259
- 

Return to bug 29562