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

(-)a/C4/Reserves.pm (-2 / +34 lines)
Lines 463-468 See CanItemBeReserved() for possible return values. Link Here
463
sub CanBookBeReserved{
463
sub CanBookBeReserved{
464
    my ($borrowernumber, $biblionumber) = @_;
464
    my ($borrowernumber, $biblionumber) = @_;
465
465
466
    # Check if borrower already has reserved the same biblio.
467
    my @reserves = GetReservesFromBorrowernumber($borrowernumber);
468
    foreach my $reserve (@reserves) {
469
        if ($reserve->{biblionumber} == $biblionumber) {
470
            return 'alreadyReserved';
471
        }
472
    }
473
474
    # Check if borrower has reached the maximum number of holds allowed
475
    my $maxreserves = C4::Context->preference('maxreserves');
476
    if ($maxreserves && scalar(@reserves) >= $maxreserves) {
477
        return 'tooManyReserves';
478
    }
479
466
    my $items = GetItemnumbersForBiblio($biblionumber);
480
    my $items = GetItemnumbersForBiblio($biblionumber);
467
    #get items linked via host records
481
    #get items linked via host records
468
    my @hostitems = get_hostitemnumbers_of($biblionumber);
482
    my @hostitems = get_hostitemnumbers_of($biblionumber);
Lines 475-481 sub CanBookBeReserved{ Link Here
475
        $canReserve = CanItemBeReserved( $borrowernumber, $item );
489
        $canReserve = CanItemBeReserved( $borrowernumber, $item );
476
        return 'OK' if $canReserve eq 'OK';
490
        return 'OK' if $canReserve eq 'OK';
477
    }
491
    }
478
    return $canReserve;
492
493
    return 'none_available';
479
}
494
}
480
495
481
=head2 CanItemBeReserved
496
=head2 CanItemBeReserved
Lines 489-494 sub CanBookBeReserved{ Link Here
489
         cannotReserveFromOtherBranches, if syspref 'canreservefromotherbranches' is OK.
504
         cannotReserveFromOtherBranches, if syspref 'canreservefromotherbranches' is OK.
490
         tooManyReserves, if the borrower has exceeded his maximum reserve amount.
505
         tooManyReserves, if the borrower has exceeded his maximum reserve amount.
491
         notReservable,   if holds on this item are not allowed
506
         notReservable,   if holds on this item are not allowed
507
         alreadyReserved, if the borrower has already reserved this item.
492
508
493
=cut
509
=cut
494
510
Lines 498-504 sub CanItemBeReserved{ Link Here
498
    my $dbh             = C4::Context->dbh;
514
    my $dbh             = C4::Context->dbh;
499
    my $ruleitemtype; # itemtype of the matching issuing rule
515
    my $ruleitemtype; # itemtype of the matching issuing rule
500
    my $allowedreserves = 0;
516
    my $allowedreserves = 0;
501
            
517
502
    # we retrieve borrowers and items informations #
518
    # we retrieve borrowers and items informations #
503
    # item->{itype} will come for biblioitems if necessery
519
    # item->{itype} will come for biblioitems if necessery
504
    my $item = GetItem($itemnumber);
520
    my $item = GetItem($itemnumber);
Lines 512-517 sub CanItemBeReserved{ Link Here
512
    my ($ageRestriction, $daysToAgeRestriction) = C4::Circulation::GetAgeRestriction( $biblioData->{agerestriction}, $borrower );
528
    my ($ageRestriction, $daysToAgeRestriction) = C4::Circulation::GetAgeRestriction( $biblioData->{agerestriction}, $borrower );
513
    return 'ageRestricted' if $daysToAgeRestriction && $daysToAgeRestriction > 0;
529
    return 'ageRestricted' if $daysToAgeRestriction && $daysToAgeRestriction > 0;
514
530
531
    # Check if borrower already has reserved the same item or biblio.
532
    my @reserves = GetReservesFromBorrowernumber($borrowernumber);
533
    foreach my $reserve (@reserves) {
534
        if (   $reserve->{itemnumber} == $itemnumber
535
            or $reserve->{biblionumber} == $item->{biblionumber} )
536
        {
537
            return 'alreadyReserved';
538
        }
539
    }
540
541
    # Check if borrower has reached the maximum number of holds allowed
542
    my $maxreserves = C4::Context->preference('maxreserves');
543
    if ($maxreserves && scalar(@reserves) >= $maxreserves) {
544
        return 'tooManyReserves';
545
    }
546
515
    my $controlbranch = C4::Context->preference('ReservesControlBranch');
547
    my $controlbranch = C4::Context->preference('ReservesControlBranch');
516
    my $itemtypefield = C4::Context->preference('item-level_itypes') ? "itype" : "itemtype";
548
    my $itemtypefield = C4::Context->preference('item-level_itypes') ? "itype" : "itemtype";
517
549
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt (-2 / +2 lines)
Lines 297-303 function checkMultiHold() { Link Here
297
    </form>
297
    </form>
298
  [% ELSE %]
298
  [% ELSE %]
299
299
300
[% IF ( maxreserves || alreadyreserved || none_available || alreadypossession || ageRestricted ) %]
300
[% IF ( maxreserves || alreadyReserved || none_available || alreadypossession || ageRestricted ) %]
301
    <div class="dialog alert">
301
    <div class="dialog alert">
302
302
303
    [% UNLESS ( multi_hold ) %]
303
    [% UNLESS ( multi_hold ) %]
Lines 309-315 function checkMultiHold() { Link Here
309
        [% IF ( ageRestricted ) %]
309
        [% IF ( ageRestricted ) %]
310
          <li><strong>Age restricted</strong></li>
310
          <li><strong>Age restricted</strong></li>
311
        [% END %]
311
        [% END %]
312
        [% IF ( alreadyreserved ) %]
312
        [% IF ( 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
        [% END %]
314
        [% END %]
315
        [% IF ( none_available ) %]
315
        [% IF ( none_available ) %]
(-)a/reserve/request.pl (-14 / +3 lines)
Lines 208-214 foreach my $biblionumber (@biblionumbers) { Link Here
208
    elsif ( $canReserve eq 'tooManyReserves' ) {
208
    elsif ( $canReserve eq 'tooManyReserves' ) {
209
        $maxreserves = 1;
209
        $maxreserves = 1;
210
    }
210
    }
211
    elsif ( $canReserve eq 'ageRestricted' ) {
211
    elsif ( grep { $canReserve eq $_ }
212
        (qw(ageRestricted alreadyReserved none_available)) )
213
    {
212
        $template->param( $canReserve => 1 );
214
        $template->param( $canReserve => 1 );
213
        $biblioloopiter{$canReserve} = 1;
215
        $biblioloopiter{$canReserve} = 1;
214
    }
216
    }
Lines 225-251 foreach my $biblionumber (@biblionumbers) { Link Here
225
    my $reserves = GetReservesFromBiblionumber({ biblionumber => $biblionumber, all_dates => 1 });
227
    my $reserves = GetReservesFromBiblionumber({ biblionumber => $biblionumber, all_dates => 1 });
226
    my $count = scalar( @$reserves );
228
    my $count = scalar( @$reserves );
227
    my $totalcount = $count;
229
    my $totalcount = $count;
228
    my $holds_count = 0;
229
    my $alreadyreserved = 0;
230
230
231
    foreach my $res (@$reserves) {
231
    foreach my $res (@$reserves) {
232
        if ( defined $res->{found} ) { # found can be 'W' or 'T'
232
        if ( defined $res->{found} ) { # found can be 'W' or 'T'
233
            $count--;
233
            $count--;
234
        }
234
        }
235
236
        if ( defined $borrowerinfo && defined($borrowerinfo->{borrowernumber}) && ($borrowerinfo->{borrowernumber} eq $res->{borrowernumber}) ) {
237
            $holds_count++;
238
        }
239
    }
240
241
    if ( $holds_count ) {
242
            $alreadyreserved = 1;
243
            $biblioloopiter{warn} = 1;
244
            $biblioloopiter{alreadyres} = 1;
245
    }
235
    }
246
236
247
    $template->param(
237
    $template->param(
248
        alreadyreserved => $alreadyreserved,
249
        alreadypossession => $alreadypossession,
238
        alreadypossession => $alreadypossession,
250
    );
239
    );
251
240
(-)a/t/db_dependent/Holds.t (-17 / +38 lines)
Lines 6-12 use t::lib::Mocks; Link Here
6
use C4::Context;
6
use C4::Context;
7
use C4::Branch;
7
use C4::Branch;
8
8
9
use Test::More tests => 49;
9
use Test::More tests => 52;
10
use MARC::Record;
10
use MARC::Record;
11
use C4::Biblio;
11
use C4::Biblio;
12
use C4::Items;
12
use C4::Items;
Lines 59-66 foreach (1..$borrowers_count) { Link Here
59
59
60
my $biblionumber   = $bibnum;
60
my $biblionumber   = $bibnum;
61
61
62
my @branches = GetBranchesLoop();
62
my $branches = GetBranchesLoop();
63
my $branch = $branches[0][0]{value};
63
my $branch = $branches->[0]{value};
64
64
65
# Create five item level holds
65
# Create five item level holds
66
foreach my $borrowernumber ( @borrowernumbers ) {
66
foreach my $borrowernumber ( @borrowernumbers ) {
Lines 222-228 $dbh->do( Link Here
222
);
222
);
223
223
224
# make sure some basic sysprefs are set
224
# make sure some basic sysprefs are set
225
t::lib::Mocks::mock_preference('ReservesControlBranch', 'homebranch');
225
t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
226
t::lib::Mocks::mock_preference('item-level_itypes', 1);
226
t::lib::Mocks::mock_preference('item-level_itypes', 1);
227
227
228
# if IndependentBranches is OFF, a CPL patron can reserve an MPL item
228
# if IndependentBranches is OFF, a CPL patron can reserve an MPL item
Lines 310-319 ModReserve({ reserve_id => $reserveid2, rank => 'del' }); Link Here
310
$reserve3 = GetReserve( $reserveid3 );
310
$reserve3 = GetReserve( $reserveid3 );
311
is( $reserve3->{priority}, 1, "After ModReserve, the 3rd reserve becomes the first on the waiting list" );
311
is( $reserve3->{priority}, 1, "After ModReserve, the 3rd reserve becomes the first on the waiting list" );
312
312
313
ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold can be trapped for damaged item with AllowHoldsOnDamagedItems enabled" );
314
313
ModItem({ damaged => 1 }, $item_bibnum, $itemnumber);
315
ModItem({ damaged => 1 }, $item_bibnum, $itemnumber);
316
CancelReserve({reserve_id => $reserveid3});
314
C4::Context->set_preference( 'AllowHoldsOnDamagedItems', 1 );
317
C4::Context->set_preference( 'AllowHoldsOnDamagedItems', 1 );
315
ok( CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'OK', "Patron can reserve damaged item with AllowHoldsOnDamagedItems enabled" );
318
ok( CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'OK', "Patron can reserve damaged item with AllowHoldsOnDamagedItems enabled" );
316
ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold can be trapped for damaged item with AllowHoldsOnDamagedItems enabled" );
317
C4::Context->set_preference( 'AllowHoldsOnDamagedItems', 0 );
319
C4::Context->set_preference( 'AllowHoldsOnDamagedItems', 0 );
318
ok( CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'damaged', "Patron cannot reserve damaged item with AllowHoldsOnDamagedItems disabled" );
320
ok( CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'damaged', "Patron cannot reserve damaged item with AllowHoldsOnDamagedItems disabled" );
319
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for damaged item with AllowHoldsOnDamagedItems disabled" );
321
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for damaged item with AllowHoldsOnDamagedItems disabled" );
Lines 329-351 AddReserve( Link Here
329
    '',
331
    '',
330
    1,
332
    1,
331
);
333
);
334
my ($bibnum2, $title2, $bibitemnum2) = create_helper_biblio('CANNOT');
335
my ($item_bibnum2, $item_bibitemnum2, $itemnumber2) = AddItem({ homebranch => $branch, holdingbranch => $branch, itype => 'CANNOT' } , $bibnum2);
332
ok(
336
ok(
333
    CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'tooManyReserves',
337
    CanItemBeReserved( $borrowernumbers[0], $itemnumber2) eq 'tooManyReserves',
334
    "cannot request item if policy that matches on item-level item type forbids it"
338
    "cannot request item if policy that matches on item-level item type forbids it"
335
);
339
);
336
ModItem({ itype => 'CAN' }, $item_bibnum, $itemnumber);
340
ModItem({ itype => 'CAN' }, $item_bibnum2, $itemnumber2);
337
ok(
341
ok(
338
    CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'OK',
342
    CanItemBeReserved( $borrowernumbers[0], $itemnumber2) eq 'OK',
339
    "can request item if policy that matches on item type allows it"
343
    "can request item if policy that matches on item type allows it"
340
);
344
);
341
345
342
t::lib::Mocks::mock_preference('item-level_itypes', 0);
346
t::lib::Mocks::mock_preference('item-level_itypes', 0);
343
ModItem({ itype => undef }, $item_bibnum, $itemnumber);
347
ModItem({ itype => undef }, $item_bibnum2, $itemnumber2);
344
ok(
348
ok(
345
    CanItemBeReserved( $borrowernumbers[0], $itemnumber) eq 'tooManyReserves',
349
    CanItemBeReserved( $borrowernumbers[0], $itemnumber2) eq 'tooManyReserves',
346
    "cannot request item if policy that matches on bib-level item type forbids it (bug 9532)"
350
    "cannot request item if policy that matches on bib-level item type forbids it (bug 9532)"
347
);
351
);
348
352
353
is(CanBookBeReserved($borrowernumbers[0], $bibnum), 'alreadyReserved');
354
355
C4::Context->set_preference('maxreserves', 1);
356
ok(CanBookBeReserved($borrowernumbers[0], $biblionumber) eq 'tooManyReserves');
357
358
C4::Context->set_preference('maxreserves', 0);
359
t::lib::Mocks::mock_preference('IndependentBranches', 1);
360
t::lib::Mocks::mock_preference('canreservefromotherbranches', 0);
361
ok(CanBookBeReserved($borrowernumbers[0], $foreign_bibnum) eq 'none_available');
349
362
350
# Test branch item rules
363
# Test branch item rules
351
364
Lines 427-436 sub create_helper_biblio { Link Here
427
    my $itemtype = shift;
440
    my $itemtype = shift;
428
    my $bib = MARC::Record->new();
441
    my $bib = MARC::Record->new();
429
    my $title = 'Silence in the library';
442
    my $title = 'Silence in the library';
430
    $bib->append_fields(
443
    if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
431
        MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'),
444
        $bib->append_fields(
432
        MARC::Field->new('245', ' ', ' ', a => $title),
445
            MARC::Field->new('700', ' ', '0', a => 'Moffat, Steven'),
433
        MARC::Field->new('942', ' ', ' ', c => $itemtype),
446
            MARC::Field->new('200', ' ', ' ', a => $title),
434
    );
447
            MARC::Field->new('099', ' ', ' ', t => $itemtype),
435
    return ($bibnum, $title, $bibitemnum) = AddBiblio($bib, '');
448
        );
449
    } else {
450
        $bib->append_fields(
451
            MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'),
452
            MARC::Field->new('245', ' ', ' ', a => $title),
453
            MARC::Field->new('942', ' ', ' ', c => $itemtype),
454
        );
455
    }
456
457
    return AddBiblio($bib, '');
436
}
458
}
437
- 

Return to bug 11999