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

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

Return to bug 11999