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

(-)a/C4/Reserves.pm (-24 / +35 lines)
Lines 353-388 sub GetReservesFromItemnumber { Link Here
353
353
354
=head2 GetReservesFromBorrowernumber
354
=head2 GetReservesFromBorrowernumber
355
355
356
    $borrowerreserv = GetReservesFromBorrowernumber($borrowernumber,$tatus);
356
    $borrowerreserv = GetReservesFromBorrowernumber($borrowernumber[,$status][,$biblionumber][,$itemnumber]);
357
358
TODO :: Descritpion
359
357
360
=cut
358
=cut
361
359
362
sub GetReservesFromBorrowernumber {
360
sub GetReservesFromBorrowernumber {
363
    my ( $borrowernumber, $status ) = @_;
361
    my ( $borrowernumber, $found, $biblionumber, $itemnumber ) = @_;
364
    my $dbh   = C4::Context->dbh;
362
365
    my $sth;
363
    my @params;
366
    if ($status) {
364
367
        $sth = $dbh->prepare("
365
    my $sql = "SELECT * FROM reserves WHERE borrowernumber = ?";
368
            SELECT *
366
    push( @params, $borrowernumber );
369
            FROM   reserves
367
370
            WHERE  borrowernumber=?
368
    if ( $biblionumber ) {
371
                AND found =?
369
        $sql .= " AND biblionumber = ? ";
372
            ORDER BY reservedate
370
        push( @params, $biblionumber );
373
        ");
371
    }
374
        $sth->execute($borrowernumber,$status);
372
375
    } else {
373
    if ( $itemnumber ) {
376
        $sth = $dbh->prepare("
374
        $sql .= " AND itemnumber = ? ";
377
            SELECT *
375
        push( @params, $itemnumber );
378
            FROM   reserves
376
    }
379
            WHERE  borrowernumber=?
377
380
            ORDER BY reservedate
378
    if ( $found ) {
381
        ");
379
        $sql .= " AND found = ? ";
382
        $sth->execute($borrowernumber);
380
        push( @params, $found );
383
    }
381
    }
382
383
    $sql .= " ORDER BY reservedate ";
384
385
    my $dbh = C4::Context->dbh;
386
    my $sth = $dbh->prepare( $sql );
387
388
    $sth->execute( @params );
389
384
    my $data = $sth->fetchall_arrayref({});
390
    my $data = $sth->fetchall_arrayref({});
385
    return @$data;
391
392
    if ( scalar @$data ) {
393
        return @$data;
394
    } else {
395
        return ();
396
    }
386
}
397
}
387
#-------------------------------------------------------------------------------------
398
#-------------------------------------------------------------------------------------
388
=head2 CanBookBeReserved
399
=head2 CanBookBeReserved
(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 427-429 INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES(' Link Here
427
INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('UseCourseReserves', '0', 'Enable the course reserves feature.', NULL, 'YesNo');
427
INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('UseCourseReserves', '0', 'Enable the course reserves feature.', NULL, 'YesNo');
428
INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHoldNotes',0,'Show hold notes on OPAC','','YesNo');
428
INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHoldNotes',0,'Show hold notes on OPAC','','YesNo');
429
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('CalculateFinesOnReturn','1','Switch to control if overdue fines are calculated on return or not', '', 'YesNo');
429
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('CalculateFinesOnReturn','1','Switch to control if overdue fines are calculated on return or not', '', 'YesNo');
430
INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('MaxHoldsPerRecord', '1', 'The maximum number of holds allowed per bibliographic record per borrower', NULL, NULL);
(-)a/installer/data/mysql/updatedatabase.pl (+7 lines)
Lines 7010-7015 CREATE TABLE IF NOT EXISTS borrower_files ( Link Here
7010
    SetVersion($DBversion);
7010
    SetVersion($DBversion);
7011
}
7011
}
7012
7012
7013
$DBversion = "3.13.00.XXX";
7014
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
7015
    $dbh->do("INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('MaxHoldsPerRecord', '1', 'The maximum number of holds allowed per bibliographic record per borrower', NULL, NULL)");
7016
    print "Upgrade to $DBversion done (Add syspref MaxHoldsPerRecord)\n";
7017
    SetVersion ($DBversion);
7018
}
7019
7013
=head1 FUNCTIONS
7020
=head1 FUNCTIONS
7014
7021
7015
=head2 TableExists($table)
7022
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (-1 / +6 lines)
Lines 411-417 Circulation: Link Here
411
            - Patrons can only have
411
            - Patrons can only have
412
            - pref: maxreserves
412
            - pref: maxreserves
413
              class: integer
413
              class: integer
414
            - holds at once.
414
            - total holds at a time.
415
        -
416
            - Patrons can only place
417
            - pref: MaxHoldsPerRecord
418
              class: integer
419
            - holds on a single record at a time.
415
        -
420
        -
416
            - pref: emailLibrarianWhenHoldIsPlaced
421
            - pref: emailLibrarianWhenHoldIsPlaced
417
              choices:
422
              choices:
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt (-2 / +2 lines)
Lines 55-61 function check() { Link Here
55
    }
55
    }
56
56
57
    if (alreadyreserved > "0"){
57
    if (alreadyreserved > "0"){
58
		msg += (_("- This patron had already placed a hold on this item") + "\n" + _("Please cancel the previous hold first") + "\n");
58
         msg += (_("This patron has already placed the maximum number of holds for this record.") + "\n\n" + _("Please cancel a previous hold first.") + "\n");
59
    }
59
    }
60
60
61
	if (msg == "") return(true);
61
	if (msg == "") return(true);
Lines 240-246 function checkMultiHold() { Link Here
240
          <li><strong>Too Many Holds: </strong> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %] </a> has too many holds.</li>
240
          <li><strong>Too Many Holds: </strong> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %] </a> has too many holds.</li>
241
        [% END %]
241
        [% END %]
242
        [% IF ( alreadyreserved ) %]
242
        [% IF ( alreadyreserved ) %]
243
          <li><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>already has a hold</strong> on this item </li>
243
          <li><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>has already placed the maximum allowed number of holds</strong> on this record</li>
244
        [% END %]
244
        [% END %]
245
        [% IF ( none_available ) %]
245
        [% IF ( none_available ) %]
246
          <li> <strong>No copies are available</strong> to be placed on hold</li>
246
          <li> <strong>No copies are available</strong> to be placed on hold</li>
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-reserve.tt (-1 / +5 lines)
Lines 316-322 Link Here
316
                            [% IF ( bibitemloo.already_patron_possession ) %]
316
                            [% IF ( bibitemloo.already_patron_possession ) %]
317
                                <div class="bibmessage">This title cannot be requested because it's already in your possession.</div>
317
                                <div class="bibmessage">This title cannot be requested because it's already in your possession.</div>
318
                            [% ELSE %]
318
                            [% ELSE %]
319
                                <div class="bibmessage">This title cannot be requested.</div>
319
                                [% IF bibitemloo.max_holds %]
320
                                    <div class="bibmessage">This title cannot be requested. You have already placed the maximum number of requests allowed for this title.</div>
321
                                [% ELSE %]
322
                                    <div class="bibmessage">This title cannot be requested.</div>
323
                                [% END %]
320
                            [% END %]
324
                            [% END %]
321
                          [% END %]
325
                          [% END %]
322
                        [% END %]
326
                        [% END %]
(-)a/opac/opac-reserve.pl (-10 / +18 lines)
Lines 37-43 use C4::Debug; Link Here
37
use Koha::DateUtils;
37
use Koha::DateUtils;
38
# use Data::Dumper;
38
# use Data::Dumper;
39
39
40
my $MAXIMUM_NUMBER_OF_RESERVES = C4::Context->preference("maxreserves");
40
my $maxreserves = C4::Context->preference("maxreserves");
41
my $max_holds_per_record = C4::Context->preference('MaxHoldsPerRecord');
41
42
42
my $query = new CGI;
43
my $query = new CGI;
43
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
44
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
Lines 171-177 foreach my $biblioNumber (@biblionumbers) { Link Here
171
#
172
#
172
if ( $query->param('place_reserve') ) {
173
if ( $query->param('place_reserve') ) {
173
    my $reserve_cnt = 0;
174
    my $reserve_cnt = 0;
174
    if ($MAXIMUM_NUMBER_OF_RESERVES) {
175
    if ($maxreserves) {
175
        $reserve_cnt = GetReservesFromBorrowernumber( $borrowernumber );
176
        $reserve_cnt = GetReservesFromBorrowernumber( $borrowernumber );
176
    }
177
    }
177
178
Lines 255-262 if ( $query->param('place_reserve') ) { Link Here
255
        }
256
        }
256
        my $notes = $query->param('notes_'.$biblioNum)||'';
257
        my $notes = $query->param('notes_'.$biblioNum)||'';
257
258
258
        if (   $MAXIMUM_NUMBER_OF_RESERVES
259
        if (   $maxreserves
259
            && $reserve_cnt >= $MAXIMUM_NUMBER_OF_RESERVES )
260
            && $reserve_cnt >= $maxreserves )
260
        {
261
        {
261
            $canreserve = 0;
262
            $canreserve = 0;
262
        }
263
        }
Lines 317-323 if ( CheckBorrowerDebarred($borrowernumber) ) { Link Here
317
318
318
my @reserves = GetReservesFromBorrowernumber( $borrowernumber );
319
my @reserves = GetReservesFromBorrowernumber( $borrowernumber );
319
$template->param( RESERVES => \@reserves );
320
$template->param( RESERVES => \@reserves );
320
if ( $MAXIMUM_NUMBER_OF_RESERVES && (scalar(@reserves) >= $MAXIMUM_NUMBER_OF_RESERVES) ) {
321
if ( $maxreserves && (scalar(@reserves) >= $maxreserves) ) {
321
    $template->param( message => 1 );
322
    $template->param( message => 1 );
322
    $noreserves = 1;
323
    $noreserves = 1;
323
    $template->param( too_many_reserves => scalar(@reserves));
324
    $template->param( too_many_reserves => scalar(@reserves));
Lines 325-336 if ( $MAXIMUM_NUMBER_OF_RESERVES && (scalar(@reserves) >= $MAXIMUM_NUMBER_OF_RES Link Here
325
foreach my $res (@reserves) {
326
foreach my $res (@reserves) {
326
    foreach my $biblionumber (@biblionumbers) {
327
    foreach my $biblionumber (@biblionumbers) {
327
        if ( $res->{'biblionumber'} == $biblionumber && $res->{'borrowernumber'} == $borrowernumber) {
328
        if ( $res->{'biblionumber'} == $biblionumber && $res->{'borrowernumber'} == $borrowernumber) {
328
#            $template->param( message => 1 );
329
            $biblioDataHash{$biblionumber}->{holds_count}++;
329
#            $noreserves = 1;
330
#            $template->param( already_reserved => 1 );
331
            $biblioDataHash{$biblionumber}->{already_reserved} = 1;
332
        }
330
        }
333
    }
331
    }
332
334
}
333
}
335
334
336
unless ($noreserves) {
335
unless ($noreserves) {
Lines 374-379 foreach my $biblioNum (@biblionumbers) { Link Here
374
    $biblioLoopIter{reservecount} = $biblioData->{reservecount};
373
    $biblioLoopIter{reservecount} = $biblioData->{reservecount};
375
    $biblioLoopIter{already_reserved} = $biblioData->{already_reserved};
374
    $biblioLoopIter{already_reserved} = $biblioData->{already_reserved};
376
    $biblioLoopIter{mandatorynotes}=0; #FIXME: For future use
375
    $biblioLoopIter{mandatorynotes}=0; #FIXME: For future use
376
    $biblioLoopIter{holds_count} = $biblioData->{holds_count};
377
377
378
    if (!$itemLevelTypes && $biblioData->{itemtype}) {
378
    if (!$itemLevelTypes && $biblioData->{itemtype}) {
379
        $biblioLoopIter{description} = $itemTypes->{$biblioData->{itemtype}}{description};
379
        $biblioLoopIter{description} = $itemTypes->{$biblioData->{itemtype}}{description};
Lines 500-510 foreach my $biblioNum (@biblionumbers) { Link Here
500
            $policy_holdallowed = 0;
500
            $policy_holdallowed = 0;
501
        }
501
        }
502
502
503
        if (IsAvailableForItemLevelRequest($itemNum) and $policy_holdallowed and CanItemBeReserved($borrowernumber,$itemNum) and ($itemLoopIter->{already_reserved} ne 1)) {
503
        if (IsAvailableForItemLevelRequest($itemNum) and $policy_holdallowed and CanItemBeReserved($borrowernumber,$itemNum) and ($itemLoopIter->{holds_count} < $max_holds_per_record )) {
504
            $itemLoopIter->{available} = 1;
504
            $itemLoopIter->{available} = 1;
505
            $numCopiesAvailable++;
505
            $numCopiesAvailable++;
506
        }
506
        }
507
507
508
        # Don't allow multiple item level holds on the same item if borrowers can place multiple holds on one bib
509
        $itemLoopIter->{available} = 0 if ( GetReservesFromBorrowernumber( $borrowernumber, undef, undef, $itemNum ) );
510
508
	# FIXME: move this to a pm
511
	# FIXME: move this to a pm
509
        my $dbh = C4::Context->dbh;
512
        my $dbh = C4::Context->dbh;
510
        my $sth2 = $dbh->prepare("SELECT * FROM reserves WHERE borrowernumber=? AND itemnumber=? AND found='W'");
513
        my $sth2 = $dbh->prepare("SELECT * FROM reserves WHERE borrowernumber=? AND itemnumber=? AND found='W'");
Lines 531-536 foreach my $biblioNum (@biblionumbers) { Link Here
531
    if ($biblioLoopIter{already_reserved}) {
534
    if ($biblioLoopIter{already_reserved}) {
532
        $biblioLoopIter{holdable} = undef;
535
        $biblioLoopIter{holdable} = undef;
533
    }
536
    }
537
    if ($biblioLoopIter{holds_count} >= $max_holds_per_record) {
538
        $biblioLoopIter{holdable} = undef;
539
        $anyholdable = undef;
540
        $biblioLoopIter{max_holds} = 1;
541
    }
534
    if(not CanBookBeReserved($borrowernumber,$biblioNum)){
542
    if(not CanBookBeReserved($borrowernumber,$biblioNum)){
535
        $biblioLoopIter{holdable} = undef;
543
        $biblioLoopIter{holdable} = undef;
536
    }
544
    }
(-)a/reserve/request.pl (-12 / +26 lines)
Lines 180-185 $template->param( messageborrower => $messageborrower ); Link Here
180
180
181
# FIXME launch another time GetMember perhaps until
181
# FIXME launch another time GetMember perhaps until
182
my $borrowerinfo = GetMember( borrowernumber => $borrowernumber_hold );
182
my $borrowerinfo = GetMember( borrowernumber => $borrowernumber_hold );
183
my $max_holds_per_record = C4::Context->preference('MaxHoldsPerRecord');
183
184
184
my @biblionumbers = ();
185
my @biblionumbers = ();
185
my $biblionumbers = $input->param('biblionumbers');
186
my $biblionumbers = $input->param('biblionumbers');
Lines 214-238 foreach my $biblionumber (@biblionumbers) { Link Here
214
    my $totalcount = $count;
215
    my $totalcount = $count;
215
    my $alreadyreserved;
216
    my $alreadyreserved;
216
217
218
    my $holds_for_this_borrower_count = 0;
217
    foreach my $res (@$reserves) {
219
    foreach my $res (@$reserves) {
218
        if ( defined $res->{found} && $res->{found} eq 'W' ) {
220
        if ( defined $res->{found} && $res->{found} eq 'W' ) {
219
            $count--;
221
            $count--;
220
        }
222
        }
221
223
222
        if ( defined $borrowerinfo && ($borrowerinfo->{borrowernumber} eq $res->{borrowernumber}) ) {
224
        if (   defined $borrowerinfo
223
            $warnings = 1;
225
            && $borrowerinfo->{borrowernumber} eq $res->{borrowernumber} )
224
            $alreadyreserved = 1;
226
        {
225
            $biblioloopiter{warn} = 1;
227
            $holds_for_this_borrower_count++;
226
            $biblioloopiter{alreadyres} = 1;
228
229
            if ( $holds_for_this_borrower_count > $max_holds_per_record ) {
230
                $warnings                   = 1;
231
                $alreadyreserved            = 1;
232
                $biblioloopiter{warn}       = 1;
233
                $biblioloopiter{alreadyres} = 1;
234
            }
227
        }
235
        }
228
    }
236
    }
229
237
230
    $template->param( alreadyreserved => $alreadyreserved,
238
    $template->param(
231
                      messages => $messages,
239
        alreadyreserved   => $alreadyreserved,
232
                      warnings => $warnings,
240
        messages          => $messages,
233
                 maxreserves=>$maxreserves,
241
        warnings          => $warnings,
234
                     alreadypossession => $alreadypossession,
242
        maxreserves       => $maxreserves,
235
					  );
243
        alreadypossession => $alreadypossession,
244
    );
236
245
237
246
238
    # FIXME think @optionloop, is maybe obsolete, or  must be switchable by a systeme preference fixed rank or not
247
    # FIXME think @optionloop, is maybe obsolete, or  must be switchable by a systeme preference fixed rank or not
Lines 449-454 foreach my $biblionumber (@biblionumbers) { Link Here
449
                $itemdata_enumchron = 1;
458
                $itemdata_enumchron = 1;
450
            }
459
            }
451
460
461
            # Don't allow multiple item level holds on the same item if borrowers can place multiple holds on one bib
462
            if ( GetReservesFromBorrowernumber( $borrowerinfo->{borrowernumber}, undef, undef, $itemnumber) ) {
463
                $item->{available} = 0;
464
                $item->{override} = 0;
465
            }
466
452
            push @{ $biblioitem->{itemloop} }, $item;
467
            push @{ $biblioitem->{itemloop} }, $item;
453
        }
468
        }
454
469
455
- 

Return to bug 7710