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

(-)a/C4/Circulation.pm (-1 / +1 lines)
Lines 1225-1231 sub checkHighHolds { Link Here
1225
            }
1225
            }
1226
1226
1227
            # Remove any items that are not holdable for this patron
1227
            # Remove any items that are not holdable for this patron
1228
            @items = grep { CanItemBeReserved( $borrower->{borrowernumber}, $_->itemnumber )->{status} eq 'OK' } @items;
1228
            @items = grep { CanItemBeReserved( $borrower->{borrowernumber}, $_->itemnumber, undef, { ignore_found_holds => 1 } )->{status} eq 'OK' } @items;
1229
1229
1230
            my $items_count = scalar @items;
1230
            my $items_count = scalar @items;
1231
1231
(-)a/C4/Reserves.pm (-11 / +18 lines)
Lines 301-315 sub AddReserve { Link Here
301
301
302
=head2 CanBookBeReserved
302
=head2 CanBookBeReserved
303
303
304
  $canReserve = &CanBookBeReserved($borrowernumber, $biblionumber, $branchcode)
304
  $canReserve = &CanBookBeReserved($borrowernumber, $biblionumber, $branchcode, $params)
305
  if ($canReserve eq 'OK') { #We can reserve this Item! }
305
  if ($canReserve eq 'OK') { #We can reserve this Item! }
306
306
307
  $params are passed directly through to CanItemBeReserved
308
307
See CanItemBeReserved() for possible return values.
309
See CanItemBeReserved() for possible return values.
308
310
309
=cut
311
=cut
310
312
311
sub CanBookBeReserved{
313
sub CanBookBeReserved{
312
    my ($borrowernumber, $biblionumber, $pickup_branchcode) = @_;
314
    my ($borrowernumber, $biblionumber, $pickup_branchcode, $params) = @_;
313
315
314
    my @itemnumbers = Koha::Items->search({ biblionumber => $biblionumber})->get_column("itemnumber");
316
    my @itemnumbers = Koha::Items->search({ biblionumber => $biblionumber})->get_column("itemnumber");
315
    #get items linked via host records
317
    #get items linked via host records
Lines 320-326 sub CanBookBeReserved{ Link Here
320
322
321
    my $canReserve = { status => '' };
323
    my $canReserve = { status => '' };
322
    foreach my $itemnumber (@itemnumbers) {
324
    foreach my $itemnumber (@itemnumbers) {
323
        $canReserve = CanItemBeReserved( $borrowernumber, $itemnumber, $pickup_branchcode );
325
        $canReserve = CanItemBeReserved( $borrowernumber, $itemnumber, $pickup_branchcode, $params );
324
        return { status => 'OK' } if $canReserve->{status} eq 'OK';
326
        return { status => 'OK' } if $canReserve->{status} eq 'OK';
325
    }
327
    }
326
    return $canReserve;
328
    return $canReserve;
Lines 328-336 sub CanBookBeReserved{ Link Here
328
330
329
=head2 CanItemBeReserved
331
=head2 CanItemBeReserved
330
332
331
  $canReserve = &CanItemBeReserved($borrowernumber, $itemnumber, $branchcode)
333
  $canReserve = &CanItemBeReserved($borrowernumber, $itemnumber, $branchcode, $params)
332
  if ($canReserve->{status} eq 'OK') { #We can reserve this Item! }
334
  if ($canReserve->{status} eq 'OK') { #We can reserve this Item! }
333
335
336
  current params are 'ignore_found_holds' - if true holds that have been trapped are not counted
337
  toward the patron limit, used by checkHighHolds to avoid counting the hold we will fill with the
338
  current checkout against the high holds threshold
339
334
@RETURNS { status => OK },              if the Item can be reserved.
340
@RETURNS { status => OK },              if the Item can be reserved.
335
         { status => ageRestricted },   if the Item is age restricted for this borrower.
341
         { status => ageRestricted },   if the Item is age restricted for this borrower.
336
         { status => damaged },         if the Item is damaged.
342
         { status => damaged },         if the Item is damaged.
Lines 346-352 sub CanBookBeReserved{ Link Here
346
=cut
352
=cut
347
353
348
sub CanItemBeReserved {
354
sub CanItemBeReserved {
349
    my ( $borrowernumber, $itemnumber, $pickup_branchcode ) = @_;
355
    my ( $borrowernumber, $itemnumber, $pickup_branchcode, $params ) = @_;
350
356
351
    my $dbh = C4::Context->dbh;
357
    my $dbh = C4::Context->dbh;
352
    my $ruleitemtype;    # itemtype of the matching issuing rule
358
    my $ruleitemtype;    # itemtype of the matching issuing rule
Lines 409-420 sub CanItemBeReserved { Link Here
409
        $ruleitemtype = undef;
415
        $ruleitemtype = undef;
410
    }
416
    }
411
417
412
    my $holds = Koha::Holds->search(
418
    my $search_params = {
413
        {
419
        borrowernumber => $borrowernumber,
414
            borrowernumber => $borrowernumber,
420
        biblionumber   => $item->biblionumber,
415
            biblionumber   => $item->biblionumber,
421
    };
416
        }
422
    $search_params->{found} = undef if $params->{ignore_found_holds};
417
    );
423
424
    my $holds = Koha::Holds->search($search_params);
418
    if (   defined $holds_per_record && $holds_per_record ne ''
425
    if (   defined $holds_per_record && $holds_per_record ne ''
419
        && $holds->count() >= $holds_per_record ) {
426
        && $holds->count() >= $holds_per_record ) {
420
        return { status => "tooManyHoldsForThisRecord", limit => $holds_per_record };
427
        return { status => "tooManyHoldsForThisRecord", limit => $holds_per_record };
(-)a/t/db_dependent/DecreaseLoanHighHolds.t (-4 / +22 lines)
Lines 30-36 use Koha::CirculationRules; Link Here
30
use t::lib::TestBuilder;
30
use t::lib::TestBuilder;
31
use t::lib::Mocks;
31
use t::lib::Mocks;
32
32
33
use Test::More tests => 17;
33
use Test::More tests => 19;
34
34
35
my $dbh    = C4::Context->dbh;
35
my $dbh    = C4::Context->dbh;
36
my $schema = Koha::Database->new()->schema();
36
my $schema = Koha::Database->new()->schema();
Lines 71-76 for my $i ( 1 .. 20 ) { Link Here
71
71
72
my $biblio = $builder->build_sample_biblio();
72
my $biblio = $builder->build_sample_biblio();
73
73
74
# The biblio gets 10 items
74
my @items;
75
my @items;
75
for my $i ( 1 .. 10 ) {
76
for my $i ( 1 .. 10 ) {
76
    my $item = $builder->build_sample_item(
77
    my $item = $builder->build_sample_item(
Lines 82-87 for my $i ( 1 .. 10 ) { Link Here
82
    push( @items, $item );
83
    push( @items, $item );
83
}
84
}
84
85
86
# Place 6 holds, patrons 0,1,2,3,4,5
85
for my $i ( 0 .. 5 ) {
87
for my $i ( 0 .. 5 ) {
86
    my $patron = $patrons[$i];
88
    my $patron = $patrons[$i];
87
    my $hold   = Koha::Hold->new(
89
    my $hold   = Koha::Hold->new(
Lines 93-100 for my $i ( 0 .. 5 ) { Link Here
93
    )->store();
95
    )->store();
94
}
96
}
95
97
96
my $item   = pop(@items);
98
my $item   = shift(@items);
97
my $patron = pop(@patrons);
99
my $patron = shift(@patrons);
100
my $patron_hold = Koha::Holds->find({ borrowernumber => $patron->borrowernumber, biblionumber => $item->biblionumber });
98
101
99
Koha::CirculationRules->set_rules(
102
Koha::CirculationRules->set_rules(
100
    {
103
    {
Lines 129-135 my $patron_hr = { borrowernumber => $patron->id, branchcode => $library->{branch Link Here
129
132
130
my $data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
133
my $data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
131
is( $data->{exceeded},        1,          "Static mode should exceed threshold" );
134
is( $data->{exceeded},        1,          "Static mode should exceed threshold" );
132
is( $data->{outstanding},     6,          "Should have 5 outstanding holds" );
135
is( $data->{outstanding},     6,          "Should have 6 outstanding holds" );
133
is( $data->{duration},        1,          "Should have duration of 1" );
136
is( $data->{duration},        1,          "Should have duration of 1" );
134
is( ref( $data->{due_date} ), 'DateTime', "due_date should be a DateTime object" );
137
is( ref( $data->{due_date} ), 'DateTime', "due_date should be a DateTime object" );
135
138
Lines 142-147 t::lib::Mocks::mock_preference( 'decreaseLoanHighHoldsControl', 'dynamic' ); Link Here
142
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
145
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
143
is( $data->{exceeded}, 0, "Should not exceed threshold" );
146
is( $data->{exceeded}, 0, "Should not exceed threshold" );
144
147
148
149
# Place 6 more holds - patrons 5,6,7,8,9,10
145
for my $i ( 5 .. 10 ) {
150
for my $i ( 5 .. 10 ) {
146
    my $patron = $patrons[$i];
151
    my $patron = $patrons[$i];
147
    my $hold   = Koha::Hold->new(
152
    my $hold   = Koha::Hold->new(
Lines 153-161 for my $i ( 5 .. 10 ) { Link Here
153
    )->store();
158
    )->store();
154
}
159
}
155
160
161
# 12 holds, threshold is 1 over 10 holdable items = 11
156
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
162
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
157
is( $data->{exceeded}, 1, "Should exceed threshold of 1" );
163
is( $data->{exceeded}, 1, "Should exceed threshold of 1" );
164
is( $data->{outstanding}, 12, "Should exceed threshold of 1" );
158
165
166
# 12 holds, threshold is 2 over 10 holdable items = 12 (equal is okay)
159
t::lib::Mocks::mock_preference( 'decreaseLoanHighHoldsValue', 2 );
167
t::lib::Mocks::mock_preference( 'decreaseLoanHighHoldsValue', 2 );
160
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
168
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
161
is( $data->{exceeded}, 0, "Should not exceed threshold of 2" );
169
is( $data->{exceeded}, 0, "Should not exceed threshold of 2" );
Lines 164-169 my $unholdable = pop(@items); Link Here
164
$unholdable->damaged(-1);
172
$unholdable->damaged(-1);
165
$unholdable->store();
173
$unholdable->store();
166
174
175
# 12 holds, threshold is 2 over 9 holdable items = 11
167
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
176
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
168
is( $data->{exceeded}, 1, "Should exceed threshold with one damaged item" );
177
is( $data->{exceeded}, 1, "Should exceed threshold with one damaged item" );
169
178
Lines 171-176 $unholdable->damaged(0); Link Here
171
$unholdable->itemlost(-1);
180
$unholdable->itemlost(-1);
172
$unholdable->store();
181
$unholdable->store();
173
182
183
# 12 holds, threshold is 2 over 9 holdable items = 11
174
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
184
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
175
is( $data->{exceeded}, 1, "Should exceed threshold with one lost item" );
185
is( $data->{exceeded}, 1, "Should exceed threshold with one lost item" );
176
186
Lines 178-183 $unholdable->itemlost(0); Link Here
178
$unholdable->notforloan(-1);
188
$unholdable->notforloan(-1);
179
$unholdable->store();
189
$unholdable->store();
180
190
191
# 12 holds, threshold is 2 over 9 holdable items = 11
181
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
192
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
182
is( $data->{exceeded}, 1, "Should exceed threshold with one notforloan item" );
193
is( $data->{exceeded}, 1, "Should exceed threshold with one notforloan item" );
183
194
Lines 185-192 $unholdable->notforloan(0); Link Here
185
$unholdable->withdrawn(-1);
196
$unholdable->withdrawn(-1);
186
$unholdable->store();
197
$unholdable->store();
187
198
199
# 12 holds, threshold is 2 over 9 holdable items = 11
200
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
201
is( $data->{exceeded}, 1, "Should exceed threshold with one withdrawn item" );
202
203
$patron_hold->found('F')->store;
204
# 11 holds, threshold is 2 over 9 holdable items = 11
188
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
205
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
189
is( $data->{exceeded}, 1, "Should exceed threshold with one withdrawn item" );
206
is( $data->{exceeded}, 1, "Should exceed threshold with one withdrawn item" );
207
$patron_hold->found(undef)->store;
190
208
191
t::lib::Mocks::mock_preference('CircControl', 'PatronLibrary');
209
t::lib::Mocks::mock_preference('CircControl', 'PatronLibrary');
192
210
(-)a/t/db_dependent/Reserves/MultiplePerRecord.t (-3 / +5 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 39;
22
use Test::More tests => 40;
23
use t::lib::TestBuilder;
23
use t::lib::TestBuilder;
24
use t::lib::Mocks;
24
use t::lib::Mocks;
25
25
Lines 277-283 Koha::CirculationRules->set_rules( Link Here
277
        itemtype     => undef,
277
        itemtype     => undef,
278
        branchcode   => undef,
278
        branchcode   => undef,
279
        rules        => {
279
        rules        => {
280
            reservesallowed  => 2,
280
            reservesallowed  => 3,
281
            holds_per_record => 2,
281
            holds_per_record => 2,
282
        }
282
        }
283
    }
283
    }
Lines 314-317 Koha::Holds->find($hold_id)->found("W")->store; Link Here
314
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
314
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
315
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
315
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
316
316
317
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber}, undef, { ignore_found_holds => 1 });
318
is( $can->{status}, 'OK', 'Third hold is allowed when ignoring waiting holds' );
319
317
$schema->storage->txn_rollback;
320
$schema->storage->txn_rollback;
318
- 

Return to bug 25566