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

(-)a/Koha/Holds.pm (+135 lines)
Lines 153-158 sub get_items_that_can_fill { Link Here
153
    );
153
    );
154
}
154
}
155
155
156
=head3 remaining_holds_total
157
158
    my $remaining_holds_total = Koha::Holds->remaining_holds_total({ patron => $patron, biblio => $biblio });
159
160
Calculates and returns the number of remaining holds a borrower is allowed to place.
161
This will be firstly based on the maxreserves system preference, the secondly the reservesallowed circulation rules
162
163
=cut
164
165
sub remaining_holds_total {
166
    my ( $self, $params ) = @_;
167
168
    unless ( $params->{patron} ) {
169
        # no patron was passed
170
        return 0;
171
    }
172
173
    my $current_holds_count = $params->{patron}->holds->count;
174
    my $holds_allowed_total = C4::Context->preference('maxreserves');
175
    if ( $holds_allowed_total and $current_holds_count >= $holds_allowed_total ) {
176
        # patron has more holds than maxreserves system preference
177
        return 0;
178
    }
179
180
    my $branchcode = C4::Context->preference('ReservesControlBranch');
181
    if ( $params->{biblio} ) {
182
        # iterate through every item attached to this biblio.
183
        # get the highest reservesallowed value out of these item types.
184
        my @items = Koha::Items->search({ biblionumber => $params->{biblio}->biblionumber });
185
        foreach my $item ( @items ) {
186
            my $reservesallowed = Koha::CirculationRules->get_effective_rule({
187
                rule_name => 'reservesallowed',
188
                categorycode => $params->{patron}->categorycode,
189
                itemtype => $item->itemtype,
190
                branchcode => $branchcode,
191
            });
192
            if ( $reservesallowed and $reservesallowed->rule_value and $reservesallowed->rule_value < $holds_allowed_total ) {
193
                # use the lowest value
194
                $holds_allowed_total = $reservesallowed->rule_value;
195
            }
196
        }
197
    } else {
198
        my $reservesallowed = Koha::CirculationRules->get_effective_rule({
199
            rule_name => 'reservesallowed',
200
            categorycode => $params->{patron}->categorycode,
201
            itemtype => undef,
202
            branchcode => $branchcode,
203
        });
204
        if ( $reservesallowed and $reservesallowed->rule_value and $reservesallowed->rule_value < $holds_allowed_total ) {
205
            # use the lowest value
206
            $holds_allowed_total = $reservesallowed->rule_value;
207
        }
208
    }
209
    my $remaining_holds_count = $holds_allowed_total - $current_holds_count;
210
    return $remaining_holds_count;
211
}
212
213
=head3 remaining_holds_record
214
215
    my $remaining_holds_record = Koha::Holds->remaining_holds_record({ patron => $patron, biblio => $biblio });
216
217
Calculates and returns the number of remaining holds a borrower is allowed to place per record.
218
This will be based on the holds_per_record circulation rules
219
220
=cut
221
222
sub remaining_holds_record {
223
    my ( $self, $params ) = @_;
224
225
    unless ( $params->{patron} or $params->{biblio} ) {
226
        # no patron or biblio was passed
227
        return 0;
228
    }
229
230
    my $current_holds_count = $self->search({ borrowernumber => $params->{patron}->borrowernumber, biblionumber => $params->{biblio}->biblionumber })->count;
231
    my $holds_allowed_per_record = 0;
232
233
    my $branchcode = C4::Context->preference('ReservesControlBranch');
234
    my @items = Koha::Items->search({ biblionumber => $params->{biblio}->biblionumber });
235
    foreach my $item ( @items ) {
236
        my $holds_per_record = Koha::CirculationRules->get_effective_rule({
237
            rule_name => 'holds_per_record',
238
            categorycode => $params->{patron}->categorycode,
239
            itemtype => $item->itemtype,
240
            branchcode => $branchcode,
241
        });
242
        if ( $holds_per_record and $holds_per_record->rule_value and $holds_per_record->rule_value < $holds_allowed_per_record ) {
243
            # use the lowest value
244
            $holds_allowed_per_record = $holds_per_record->rule_value;
245
        }
246
    }
247
248
    my $remaining_holds_count = $holds_allowed_per_record - $current_holds_count;
249
    return $remaining_holds_count;
250
}
251
252
=head3 remaining_holds_today
253
254
    my $remaining_holds_today = Koha::Holds->remaining_holds_today({ patron => $patron, biblio => $biblio });
255
256
Calculates and returns the number of remaining holds a borrower is allowed to place today.
257
This will be based on the holds_per_day circulation rules
258
259
=cut
260
261
sub remaining_holds_today {
262
    my ( $self, $params ) = @_;
263
264
    unless ( $params->{patron} or $params->{biblio} ) {
265
        # no patron or biblio was passed
266
        return 0;
267
    }
268
269
    my $current_holds_count = $self->search({ borrowernumber => $params->{patron}->borrowernumber, reservedate => dt_from_string->date })->count;
270
    my $holds_allowed_per_day = 0;
271
272
    my $branchcode = C4::Context->preference('ReservesControlBranch');
273
    my @items = Koha::Items->search({ biblionumber => $params->{biblio}->biblionumber });
274
    foreach my $item ( @items ) {
275
        my $holds_per_day = Koha::CirculationRules->get_effective_rule({
276
            rule_name => 'holds_per_day',
277
            categorycode => $params->{patron}->categorycode,
278
            itemtype => $item->itemtype,
279
            branchcode => $branchcode,
280
        });
281
        if ( $holds_per_day and $holds_per_day->rule_value and $holds_per_day->rule_value < $holds_allowed_per_day ) {
282
            # use the lowest value
283
            $holds_allowed_per_day = $holds_per_day->rule_value;
284
        }
285
    }
286
287
    my $remaining_holds_count = $holds_allowed_per_day - $current_holds_count;
288
    return $remaining_holds_count;
289
}
290
156
=head3 type
291
=head3 type
157
292
158
=cut
293
=cut
(-)a/t/db_dependent/Koha/Holds.t (-2 / +194 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 6;
22
use Test::More tests => 9;
23
use Test::Warn;
23
use Test::Warn;
24
24
25
use C4::Circulation;
25
use C4::Circulation;
Lines 500-505 subtest 'get_items_that_can_fill' => sub { Link Here
500
500
501
};
501
};
502
502
503
subtest 'remaining_holds_total' => sub {
504
    plan tests => 3;
505
506
    my $biblio = $builder->build_sample_biblio;
507
    my $itype_1 = $builder->build_object({ class => 'Koha::ItemTypes' });
508
    my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype });
509
    my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype });
510
    my $item_3 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype });
511
    my $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
512
513
    t::lib::Mocks::mock_userenv({ patron => $patron_1 });
514
    t::lib::Mocks::mock_preference('maxreserves', 4);
515
    Koha::CirculationRules->set_rules({
516
        itemtype => $itype_1->itemtype,
517
        branchcode => undef,
518
        categorycode => $patron_1->categorycode,
519
        rules => {
520
            reservesallowed => 5,
521
        },
522
    });
523
524
    my $reserve_id_1 = C4::Reserves::AddReserve(
525
        {
526
            borrowernumber => $patron_1->borrowernumber,
527
            biblionumber   => $biblio->biblionumber,
528
            priority       => 1,
529
            itemnumber     => $item_1->itemnumber,
530
        }
531
    );
532
533
    my $reserve_id_2 = C4::Reserves::AddReserve(
534
        {
535
            borrowernumber => $patron_1->borrowernumber,
536
            biblionumber   => $biblio->biblionumber,
537
            priority       => 1,
538
            itemnumber     => $item_2->itemnumber,
539
        }
540
    );
541
542
    my $reserve_id_3 = C4::Reserves::AddReserve(
543
        {
544
            borrowernumber => $patron_1->borrowernumber,
545
            biblionumber   => $biblio->biblionumber,
546
            priority       => 1,
547
            itemnumber     => $item_3->itemnumber,
548
        }
549
    );
550
551
    my $reserve_id_4 = C4::Reserves::AddReserve(
552
        {
553
            borrowernumber => $patron_1->borrowernumber,
554
            biblionumber   => $biblio->biblionumber,
555
            priority       => 1,
556
            itemnumber     => undef,
557
        }
558
    );
559
560
    my $remaining_holds_total = Koha::Holds->remaining_holds_total;
561
    is( $remaining_holds_total, 0, "No patron was passed to calculate their holds" );
562
563
    $remaining_holds_total = Koha::Holds->remaining_holds_total({ patron => $patron_1, biblio => $biblio });
564
    is( $remaining_holds_total, 0, "Patron has reached maxreserves system preference maximum holds" );
565
566
    t::lib::Mocks::mock_preference('maxreserves', 5);
567
568
    $remaining_holds_total = Koha::Holds->remaining_holds_total({ patron => $patron_1, biblio => $biblio });
569
    is( $remaining_holds_total, 1, "Patron has one more allowed hold based on reservesallowed circulation rule" );
570
};
571
572
subtest 'remaining_holds_record' => sub {
573
    plan tests => 3;
574
575
    my $biblio = $builder->build_sample_biblio;
576
    my $itype_1 = $builder->build_object({ class => 'Koha::ItemTypes' });
577
    my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype });
578
    my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype });
579
    my $item_3 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype });
580
    my $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
581
582
    t::lib::Mocks::mock_userenv({ patron => $patron_1 });
583
    t::lib::Mocks::mock_preference('maxreserves', 10);
584
    Koha::CirculationRules->set_rules({
585
        itemtype => $itype_1->itemtype,
586
        branchcode => undef,
587
        categorycode => $patron_1->categorycode,
588
        rules => {
589
            holds_per_record => 3,
590
        },
591
    });
592
593
    my $reserve_id_1 = C4::Reserves::AddReserve(
594
        {
595
            borrowernumber => $patron_1->borrowernumber,
596
            biblionumber   => $biblio->biblionumber,
597
            priority       => 1,
598
            itemnumber     => $item_1->itemnumber,
599
        }
600
    );
601
602
    my $reserve_id_2 = C4::Reserves::AddReserve(
603
        {
604
            borrowernumber => $patron_1->borrowernumber,
605
            biblionumber   => $biblio->biblionumber,
606
            priority       => 1,
607
            itemnumber     => $item_2->itemnumber,
608
        }
609
    );
610
611
    my $reserve_id_3 = C4::Reserves::AddReserve(
612
        {
613
            borrowernumber => $patron_1->borrowernumber,
614
            biblionumber   => $biblio->biblionumber,
615
            priority       => 1,
616
            itemnumber     => $item_3->itemnumber,
617
        }
618
    );
619
620
    my $remaining_holds_record = Koha::Holds->remaining_holds_record;
621
    is( $remaining_holds_record, 0, "No patron or biblio passed" );
622
623
    $remaining_holds_record = Koha::Holds->remaining_holds_record({ patron => $patron_1, biblio => $biblio });
624
    is( $remaining_holds_record, 0, "Patron has reached holds_per_record circulation rule maximum holds" );
625
626
    Koha::Holds->find( $reserve_id_3 )->delete;
627
628
    $remaining_holds_record = Koha::Holds->remaining_holds_record({ patron => $patron_1, biblio => $biblio });
629
    is( $remaining_holds_record, 1, "Patron has one more allowed hold on this record based on reservesallowed circulation rule" );
630
};
631
632
subtest 'remaining_holds_today' => sub {
633
    plan tests => 3;
634
635
    my $biblio = $builder->build_sample_biblio;
636
    my $itype_1 = $builder->build_object({ class => 'Koha::ItemTypes' });
637
    my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype });
638
    my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype });
639
    my $item_3 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype });
640
    my $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
641
642
    t::lib::Mocks::mock_userenv({ patron => $patron_1 });
643
    t::lib::Mocks::mock_preference('maxreserves', 10);
644
    Koha::CirculationRules->set_rules({
645
        itemtype => $itype_1->itemtype,
646
        branchcode => undef,
647
        categorycode => $patron_1->categorycode,
648
        rules => {
649
            holds_per_day => 5,
650
        },
651
    });
652
653
    my $reserve_id_1 = C4::Reserves::AddReserve(
654
        {
655
            borrowernumber => $patron_1->borrowernumber,
656
            biblionumber   => $biblio->biblionumber,
657
            priority       => 1,
658
            itemnumber     => $item_1->itemnumber,
659
        }
660
    );
661
662
    my $reserve_id_2 = C4::Reserves::AddReserve(
663
        {
664
            borrowernumber => $patron_1->borrowernumber,
665
            biblionumber   => $biblio->biblionumber,
666
            priority       => 1,
667
            itemnumber     => $item_2->itemnumber,
668
        }
669
    );
670
671
    my $reserve_id_3 = C4::Reserves::AddReserve(
672
        {
673
            borrowernumber => $patron_1->borrowernumber,
674
            biblionumber   => $biblio->biblionumber,
675
            priority       => 1,
676
            itemnumber     => $item_3->itemnumber,
677
        }
678
    );
679
680
    my $reserve_id_4 = C4::Reserves::AddReserve(
681
        {
682
            borrowernumber => $patron_1->borrowernumber,
683
            biblionumber   => $biblio->biblionumber,
684
            priority       => 1,
685
            itemnumber     => undef,
686
        }
687
    );
688
689
    my $remaining_holds_total = Koha::Holds->remaining_holds_today;
690
    is( $remaining_holds_total, 0, "No patron was passed to calculate their holds" );
691
692
    $remaining_holds_total = Koha::Holds->remaining_holds_today({ patron => $patron_1, biblio => $biblio });
693
    is( $remaining_holds_total, 1, "Patron has one more allowed hold based on holds_per_day circulation rule" );
694
};
695
503
$schema->storage->txn_rollback;
696
$schema->storage->txn_rollback;
504
697
505
1;
698
1;
506
- 

Return to bug 15565