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

(-)a/C4/Reserves.pm (-2 / +34 lines)
Lines 417-422 See CanItemBeReserved() for possible return values. Link Here
417
sub CanBookBeReserved{
417
sub CanBookBeReserved{
418
    my ($borrowernumber, $biblionumber) = @_;
418
    my ($borrowernumber, $biblionumber) = @_;
419
419
420
    # Check if borrower already has reserved the same biblio.
421
    my @reserves = GetReservesFromBorrowernumber($borrowernumber);
422
    foreach my $reserve (@reserves) {
423
        if ($reserve->{biblionumber} == $biblionumber) {
424
            return 'alreadyReserved';
425
        }
426
    }
427
428
    # Check if borrower has reached the maximum number of holds allowed
429
    my $maxreserves = C4::Context->preference('maxreserves');
430
    if ($maxreserves && scalar(@reserves) >= $maxreserves) {
431
        return 'tooManyReserves';
432
    }
433
420
    my $items = GetItemnumbersForBiblio($biblionumber);
434
    my $items = GetItemnumbersForBiblio($biblionumber);
421
    #get items linked via host records
435
    #get items linked via host records
422
    my @hostitems = get_hostitemnumbers_of($biblionumber);
436
    my @hostitems = get_hostitemnumbers_of($biblionumber);
Lines 429-435 sub CanBookBeReserved{ Link Here
429
        $canReserve = CanItemBeReserved( $borrowernumber, $item );
443
        $canReserve = CanItemBeReserved( $borrowernumber, $item );
430
        return 'OK' if $canReserve eq 'OK';
444
        return 'OK' if $canReserve eq 'OK';
431
    }
445
    }
432
    return $canReserve;
446
447
    return 'none_available';
433
}
448
}
434
449
435
=head2 CanItemBeReserved
450
=head2 CanItemBeReserved
Lines 443-448 sub CanBookBeReserved{ Link Here
443
         cannotReserveFromOtherBranches, if syspref 'canreservefromotherbranches' is OK.
458
         cannotReserveFromOtherBranches, if syspref 'canreservefromotherbranches' is OK.
444
         tooManyReserves, if the borrower has exceeded his maximum reserve amount.
459
         tooManyReserves, if the borrower has exceeded his maximum reserve amount.
445
         notReservable,   if holds on this item are not allowed
460
         notReservable,   if holds on this item are not allowed
461
         alreadyReserved, if the borrower has already reserved this item.
446
462
447
=cut
463
=cut
448
464
Lines 452-458 sub CanItemBeReserved{ Link Here
452
    my $dbh             = C4::Context->dbh;
468
    my $dbh             = C4::Context->dbh;
453
    my $ruleitemtype; # itemtype of the matching issuing rule
469
    my $ruleitemtype; # itemtype of the matching issuing rule
454
    my $allowedreserves = 0;
470
    my $allowedreserves = 0;
455
            
471
456
    # we retrieve borrowers and items informations #
472
    # we retrieve borrowers and items informations #
457
    # item->{itype} will come for biblioitems if necessery
473
    # item->{itype} will come for biblioitems if necessery
458
    my $item = GetItem($itemnumber);
474
    my $item = GetItem($itemnumber);
Lines 466-471 sub CanItemBeReserved{ Link Here
466
    my ($ageRestriction, $daysToAgeRestriction) = C4::Circulation::GetAgeRestriction( $biblioData->{agerestriction}, $borrower );
482
    my ($ageRestriction, $daysToAgeRestriction) = C4::Circulation::GetAgeRestriction( $biblioData->{agerestriction}, $borrower );
467
    return 'ageRestricted' if $daysToAgeRestriction && $daysToAgeRestriction > 0;
483
    return 'ageRestricted' if $daysToAgeRestriction && $daysToAgeRestriction > 0;
468
484
485
    # Check if borrower already has reserved the same item or biblio.
486
    my @reserves = GetReservesFromBorrowernumber($borrowernumber);
487
    foreach my $reserve (@reserves) {
488
        if (   $reserve->{itemnumber} == $itemnumber
489
            or $reserve->{biblionumber} == $item->{biblionumber} )
490
        {
491
            return 'alreadyReserved';
492
        }
493
    }
494
495
    # Check if borrower has reached the maximum number of holds allowed
496
    my $maxreserves = C4::Context->preference('maxreserves');
497
    if ($maxreserves && scalar(@reserves) >= $maxreserves) {
498
        return 'tooManyReserves';
499
    }
500
469
    my $controlbranch = C4::Context->preference('ReservesControlBranch');
501
    my $controlbranch = C4::Context->preference('ReservesControlBranch');
470
502
471
    # we retrieve user rights on this itemtype and branchcode
503
    # we retrieve user rights on this itemtype and branchcode
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt (-2 / +2 lines)
Lines 299-305 function checkMultiHold() { Link Here
299
    </form>
299
    </form>
300
  [% ELSIF NOT noitems %]
300
  [% ELSIF NOT noitems %]
301
301
302
[% IF ( exceeded_maxreserves || alreadyreserved || none_available || alreadypossession || ageRestricted ) %]
302
[% IF ( exceeded_maxreserves || alreadyReserved || none_available || alreadypossession || ageRestricted ) %]
303
    <div class="dialog alert">
303
    <div class="dialog alert">
304
304
305
    [% UNLESS ( multi_hold ) %]
305
    [% UNLESS ( multi_hold ) %]
Lines 309-315 function checkMultiHold() { Link Here
309
          <li><strong>Too many holds: </strong> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %] </a> can only place a maximum of [% maxreserves %] total holds.</li>
309
          <li><strong>Too many holds: </strong> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %] </a> can only place a maximum of [% maxreserves %] total holds.</li>
310
        [% ELSIF ( alreadypossession ) %]
310
        [% ELSIF ( alreadypossession ) %]
311
          <li> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>is already in possession</strong> of one item</li>
311
          <li> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>is already in possession</strong> of one item</li>
312
        [% ELSIF ( alreadyreserved ) %]
312
        [% ELSIF ( alreadyReserved ) %]
313
          <li><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>already has a hold</strong> on this item </li>
313
          <li><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>already has a hold</strong> on this item </li>
314
        [% ELSIF ( ageRestricted ) %]
314
        [% ELSIF ( ageRestricted ) %]
315
          <li><strong>Age restricted</strong></li>
315
          <li><strong>Age restricted</strong></li>
(-)a/reserve/request.pl (-14 / +3 lines)
Lines 226-232 foreach my $biblionumber (@biblionumbers) { Link Here
226
    elsif ( $canReserve eq 'tooManyReserves' ) {
226
    elsif ( $canReserve eq 'tooManyReserves' ) {
227
        $exceeded_maxreserves = 1;
227
        $exceeded_maxreserves = 1;
228
    }
228
    }
229
    elsif ( $canReserve eq 'ageRestricted' ) {
229
    elsif ( grep { $canReserve eq $_ }
230
        (qw(ageRestricted alreadyReserved none_available)) )
231
    {
230
        $template->param( $canReserve => 1 );
232
        $template->param( $canReserve => 1 );
231
        $biblioloopiter{$canReserve} = 1;
233
        $biblioloopiter{$canReserve} = 1;
232
    }
234
    }
Lines 243-269 foreach my $biblionumber (@biblionumbers) { Link Here
243
    my $reserves = GetReservesFromBiblionumber({ biblionumber => $biblionumber, all_dates => 1 });
245
    my $reserves = GetReservesFromBiblionumber({ biblionumber => $biblionumber, all_dates => 1 });
244
    my $count = scalar( @$reserves );
246
    my $count = scalar( @$reserves );
245
    my $totalcount = $count;
247
    my $totalcount = $count;
246
    my $holds_count = 0;
247
    my $alreadyreserved = 0;
248
248
249
    foreach my $res (@$reserves) {
249
    foreach my $res (@$reserves) {
250
        if ( defined $res->{found} ) { # found can be 'W' or 'T'
250
        if ( defined $res->{found} ) { # found can be 'W' or 'T'
251
            $count--;
251
            $count--;
252
        }
252
        }
253
254
        if ( defined $borrowerinfo && defined($borrowerinfo->{borrowernumber}) && ($borrowerinfo->{borrowernumber} eq $res->{borrowernumber}) ) {
255
            $holds_count++;
256
        }
257
    }
258
259
    if ( $holds_count ) {
260
            $alreadyreserved = 1;
261
            $biblioloopiter{warn} = 1;
262
            $biblioloopiter{alreadyres} = 1;
263
    }
253
    }
264
254
265
    $template->param(
255
    $template->param(
266
        alreadyreserved => $alreadyreserved,
267
        alreadypossession => $alreadypossession,
256
        alreadypossession => $alreadypossession,
268
    );
257
    );
269
258
(-)a/t/db_dependent/Holds.t (-14 / +35 lines)
Lines 8-14 use t::lib::TestBuilder; Link Here
8
use C4::Context;
8
use C4::Context;
9
use C4::Branch;
9
use C4::Branch;
10
10
11
use Test::More tests => 60;
11
use Test::More tests => 63;
12
use MARC::Record;
12
use MARC::Record;
13
use C4::Biblio;
13
use C4::Biblio;
14
use C4::Items;
14
use C4::Items;
Lines 333-342 ModReserve({ reserve_id => $reserveid2, rank => 'del' }); Link Here
333
$reserve3 = GetReserve( $reserveid3 );
333
$reserve3 = GetReserve( $reserveid3 );
334
is( $reserve3->{priority}, 1, "After ModReserve, the 3rd reserve becomes the first on the waiting list" );
334
is( $reserve3->{priority}, 1, "After ModReserve, the 3rd reserve becomes the first on the waiting list" );
335
335
336
ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold can be trapped for damaged item with AllowHoldsOnDamagedItems enabled" );
337
336
ModItem({ damaged => 1 }, $item_bibnum, $itemnumber);
338
ModItem({ damaged => 1 }, $item_bibnum, $itemnumber);
339
CancelReserve({reserve_id => $reserveid3});
337
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 1 );
340
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 1 );
338
ok( CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'OK', "Patron can reserve damaged item with AllowHoldsOnDamagedItems enabled" );
341
ok( CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'OK', "Patron can reserve damaged item with AllowHoldsOnDamagedItems enabled" );
339
ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold can be trapped for damaged item with AllowHoldsOnDamagedItems enabled" );
340
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 0 );
342
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 0 );
341
ok( CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'damaged', "Patron cannot reserve damaged item with AllowHoldsOnDamagedItems disabled" );
343
ok( CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'damaged', "Patron cannot reserve damaged item with AllowHoldsOnDamagedItems disabled" );
342
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for damaged item with AllowHoldsOnDamagedItems disabled" );
344
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for damaged item with AllowHoldsOnDamagedItems disabled" );
Lines 351-373 AddReserve( Link Here
351
    '',
353
    '',
352
    1,
354
    1,
353
);
355
);
356
my ($bibnum2, $title2, $bibitemnum2) = create_helper_biblio('CANNOT');
357
my ($item_bibnum2, $item_bibitemnum2, $itemnumber2) = AddItem({ homebranch => $branch_1, holdingbranch => $branch_1, itype => 'CANNOT' } , $bibnum2);
354
ok(
358
ok(
355
    CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'tooManyReserves',
359
    CanItemBeReserved( $borrowernumbers[0], $itemnumber2) eq 'tooManyReserves',
356
    "cannot request item if policy that matches on item-level item type forbids it"
360
    "cannot request item if policy that matches on item-level item type forbids it"
357
);
361
);
358
ModItem({ itype => 'CAN' }, $item_bibnum, $itemnumber);
362
ModItem({ itype => 'CAN' }, $item_bibnum2, $itemnumber2);
359
ok(
363
ok(
360
    CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'OK',
364
    CanItemBeReserved( $borrowernumbers[0], $itemnumber2) eq 'OK',
361
    "can request item if policy that matches on item type allows it"
365
    "can request item if policy that matches on item type allows it"
362
);
366
);
363
367
364
t::lib::Mocks::mock_preference('item-level_itypes', 0);
368
t::lib::Mocks::mock_preference('item-level_itypes', 0);
365
ModItem({ itype => undef }, $item_bibnum, $itemnumber);
369
ModItem({ itype => undef }, $item_bibnum2, $itemnumber2);
366
ok(
370
ok(
367
    CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'tooManyReserves',
371
    CanItemBeReserved( $borrowernumbers[0], $itemnumber2) eq 'tooManyReserves',
368
    "cannot request item if policy that matches on bib-level item type forbids it (bug 9532)"
372
    "cannot request item if policy that matches on bib-level item type forbids it (bug 9532)"
369
);
373
);
370
374
375
is(CanBookBeReserved($borrowernumbers[0], $bibnum), 'alreadyReserved');
376
377
C4::Context->set_preference('maxreserves', 1);
378
ok(CanBookBeReserved($borrowernumbers[0], $biblionumber) eq 'tooManyReserves');
379
380
C4::Context->set_preference('maxreserves', 0);
381
t::lib::Mocks::mock_preference('IndependentBranches', 1);
382
t::lib::Mocks::mock_preference('canreservefromotherbranches', 0);
383
ok(CanBookBeReserved($borrowernumbers[0], $foreign_bibnum) eq 'none_available');
371
384
372
# Test branch item rules
385
# Test branch item rules
373
386
Lines 477-486 sub create_helper_biblio { Link Here
477
    my $itemtype = shift;
490
    my $itemtype = shift;
478
    my $bib = MARC::Record->new();
491
    my $bib = MARC::Record->new();
479
    my $title = 'Silence in the library';
492
    my $title = 'Silence in the library';
480
    $bib->append_fields(
493
    if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
481
        MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'),
494
        $bib->append_fields(
482
        MARC::Field->new('245', ' ', ' ', a => $title),
495
            MARC::Field->new('700', ' ', '0', a => 'Moffat, Steven'),
483
        MARC::Field->new('942', ' ', ' ', c => $itemtype),
496
            MARC::Field->new('200', ' ', ' ', a => $title),
484
    );
497
            MARC::Field->new('099', ' ', ' ', t => $itemtype),
485
    return ($bibnum, $title, $bibitemnum) = AddBiblio($bib, '');
498
        );
499
    } else {
500
        $bib->append_fields(
501
            MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'),
502
            MARC::Field->new('245', ' ', ' ', a => $title),
503
            MARC::Field->new('942', ' ', ' ', c => $itemtype),
504
        );
505
    }
506
507
    return AddBiblio($bib, '');
486
}
508
}
487
- 

Return to bug 11999