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

(-)a/C4/Circulation.pm (-25 / +69 lines)
Lines 50-55 use Koha::DateUtils; Link Here
50
use Koha::Calendar;
50
use Koha::Calendar;
51
use Koha::Borrower::Debarments;
51
use Koha::Borrower::Debarments;
52
use Koha::Database;
52
use Koha::Database;
53
use Koha::Holds;
53
use Carp;
54
use Carp;
54
use List::MoreUtils qw( uniq );
55
use List::MoreUtils qw( uniq );
55
use Date::Calc qw(
56
use Date::Calc qw(
Lines 1009-1024 sub CanBookBeIssued { Link Here
1009
    }
1010
    }
1010
1011
1011
    ## check for high holds decreasing loan period
1012
    ## check for high holds decreasing loan period
1012
    my $decrease_loan = C4::Context->preference('decreaseLoanHighHolds');
1013
    if ( C4::Context->preference('decreaseLoanHighHolds') ) {
1013
    if ( $decrease_loan && $decrease_loan == 1 ) {
1014
        my $check = checkHighHolds( $item, $borrower );
1014
        my ( $reserved, $num, $duration, $returndate ) =
1015
          checkHighHolds( $item, $borrower );
1016
1015
1017
        if ( $num >= C4::Context->preference('decreaseLoanHighHoldsValue') ) {
1016
        if ( $check->{exceeded} ) {
1018
            $needsconfirmation{HIGHHOLDS} = {
1017
            $needsconfirmation{HIGHHOLDS} = {
1019
                num_holds  => $num,
1018
                num_holds  => $check->{outstanding},
1020
                duration   => $duration,
1019
                duration   => $check->{duration},
1021
                returndate => output_pref($returndate),
1020
                returndate => output_pref( $check->{due_date} ),
1022
            };
1021
            };
1023
        }
1022
        }
1024
    }
1023
    }
Lines 1113-1125 sub checkHighHolds { Link Here
1113
    my ( $item, $borrower ) = @_;
1112
    my ( $item, $borrower ) = @_;
1114
    my $biblio = GetBiblioFromItemNumber( $item->{itemnumber} );
1113
    my $biblio = GetBiblioFromItemNumber( $item->{itemnumber} );
1115
    my $branch = _GetCircControlBranch( $item, $borrower );
1114
    my $branch = _GetCircControlBranch( $item, $borrower );
1116
    my $dbh    = C4::Context->dbh;
1115
1117
    my $sth    = $dbh->prepare(
1116
    my $return_data = {
1118
'select count(borrowernumber) as num_holds from reserves where biblionumber=?'
1117
        exceeded    => 0,
1119
    );
1118
        outstanding => 0,
1120
    $sth->execute( $item->{'biblionumber'} );
1119
        duration    => 0,
1121
    my ($holds) = $sth->fetchrow_array;
1120
        due_date    => undef,
1122
    if ($holds) {
1121
    };
1122
1123
    my $holds = Koha::Holds->search( { biblionumber => $item->{'biblionumber'} } );
1124
1125
    if ( $holds->count() ) {
1126
        $return_data->{outstanding} = $holds->count();
1127
1128
        my $decreaseLoanHighHoldsControl        = C4::Context->preference('decreaseLoanHighHoldsControl');
1129
        my $decreaseLoanHighHoldsValue          = C4::Context->preference('decreaseLoanHighHoldsValue');
1130
        my $decreaseLoanHighHoldsIgnoreStatuses = C4::Context->preference('decreaseLoanHighHoldsIgnoreStatuses');
1131
1132
        my @decreaseLoanHighHoldsIgnoreStatuses = split( /,/, $decreaseLoanHighHoldsIgnoreStatuses );
1133
1134
        if ( $decreaseLoanHighHoldsControl eq 'static' ) {
1135
1136
            # static means just more than a given number of holds on the record
1137
1138
            # If the number of holds is less than the threshold, we can stop here
1139
            if ( $holds->count() < $decreaseLoanHighHoldsValue ) {
1140
                return $return_data;
1141
            }
1142
        }
1143
        elsif ( $decreaseLoanHighHoldsControl eq 'dynamic' ) {
1144
1145
            # dynamic means X more than the number of holdable items on the record
1146
1147
            # let's get the items
1148
            my @items = $holds->next()->biblio()->items();
1149
1150
            # Remove any items with status defined to be ignored even if the would not make item unholdable
1151
            foreach my $status (@decreaseLoanHighHoldsIgnoreStatuses) {
1152
                @items = grep { !$_->$status } @items;
1153
            }
1154
1155
            # Remove any items that are not holdable for this patron
1156
            @items = grep { CanItemBeReserved( $borrower->{borrowernumber}, $_->itemnumber ) ne 'OK' } @items;
1157
1158
            my $items_count = scalar @items;
1159
1160
            # If the number of holds is less than the count of items we have
1161
            # plus the number of holds allowed above that count, we can stop here
1162
            if ( $holds->count() < $items_count + $decreaseLoanHighHoldsValue ) {
1163
                return $return_data;
1164
            }
1165
        }
1166
1123
        my $issuedate = DateTime->now( time_zone => C4::Context->tz() );
1167
        my $issuedate = DateTime->now( time_zone => C4::Context->tz() );
1124
1168
1125
        my $calendar = Koha::Calendar->new( branchcode => $branch );
1169
        my $calendar = Koha::Calendar->new( branchcode => $branch );
Lines 1128-1148 sub checkHighHolds { Link Here
1128
          ( C4::Context->preference('item-level_itypes') )
1172
          ( C4::Context->preference('item-level_itypes') )
1129
          ? $biblio->{'itype'}
1173
          ? $biblio->{'itype'}
1130
          : $biblio->{'itemtype'};
1174
          : $biblio->{'itemtype'};
1131
        my $orig_due =
1132
          C4::Circulation::CalcDateDue( $issuedate, $itype, $branch,
1133
            $borrower );
1134
1175
1135
        my $reduced_datedue =
1176
        my $orig_due = C4::Circulation::CalcDateDue( $issuedate, $itype, $branch, $borrower );
1136
          $calendar->addDate( $issuedate,
1177
1137
            C4::Context->preference('decreaseLoanHighHoldsDuration') );
1178
        my $decreaseLoanHighHoldsDuration = C4::Context->preference('decreaseLoanHighHoldsDuration');
1179
1180
        my $reduced_datedue = $calendar->addDate( $issuedate, $decreaseLoanHighHoldsDuration );
1138
1181
1139
        if ( DateTime->compare( $reduced_datedue, $orig_due ) == -1 ) {
1182
        if ( DateTime->compare( $reduced_datedue, $orig_due ) == -1 ) {
1140
            return ( 1, $holds,
1183
            $return_data->{exceeded} = 1;
1141
                C4::Context->preference('decreaseLoanHighHoldsDuration'),
1184
            $return_data->{duration} = $decreaseLoanHighHoldsDuration;
1142
                $reduced_datedue );
1185
            $return_data->{due_date} = $reduced_datedue;
1143
        }
1186
        }
1144
    }
1187
    }
1145
    return ( 0, 0, 0, undef );
1188
1189
    return $return_data;
1146
}
1190
}
1147
1191
1148
=head2 AddIssue
1192
=head2 AddIssue
(-)a/Koha/Biblio.pm (+15 lines)
Lines 35-40 Koha::Biblio - Koha Biblio Object class Link Here
35
35
36
=cut
36
=cut
37
37
38
=head3 items
39
40
Returns the related Koha::Items object for this biblio in scalar context,
41
or list of Koha::Item objects in list context.
42
43
=cut
44
45
sub items {
46
    my ($self) = @_;
47
48
    $self->{_items} ||= Koha::Items->search( { biblionumber => $self->biblionumber() } );
49
50
    return wantarray ? $self->{_items}->as_list : $self->{_items};
51
}
52
38
=head3 type
53
=head3 type
39
54
40
=cut
55
=cut
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (-1 / +12 lines)
Lines 556-562 Circulation: Link Here
556
            - days for items with more than
556
            - days for items with more than
557
            - pref: decreaseLoanHighHoldsValue
557
            - pref: decreaseLoanHighHoldsValue
558
              class: integer
558
              class: integer
559
            - holds.
559
            - holds
560
            - pref: decreaseLoanHighHoldsControl
561
              choices:
562
                  static: "on the record"
563
                  dynamic: "over the number of holdable items on the record"
564
            - . Ignore items with the following statuses when counting items
565
            - pref: decreaseLoanHighHoldsIgnoreStatuses
566
              multiple:
567
                damaged: Damaged
568
                itemlost: Lost
569
                withdrawn: Withdrawn
570
                notforloan: Not for loan
560
        -
571
        -
561
            - pref: AllowHoldsOnPatronsPossessions
572
            - pref: AllowHoldsOnPatronsPossessions
562
              choices:
573
              choices:
(-)a/t/db_dependent/DecreaseLoanHighHolds.t (-1 / +151 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use DateTime;
21
22
use C4::Circulation;
23
use Koha::Database;
24
use Koha::Borrower;
25
use Koha::Biblio;
26
use Koha::Item;
27
use Koha::Holds;
28
use Koha::Hold;
29
30
use Test::More tests => 12;
31
32
my $dbh    = C4::Context->dbh;
33
my $schema = Koha::Database->new()->schema();
34
35
# Start transaction
36
$dbh->{RaiseError} = 1;
37
$schema->storage->txn_begin();
38
39
$dbh->do('DELETE FROM issues');
40
$dbh->do('DELETE FROM issuingrules');
41
$dbh->do('DELETE FROM borrowers');
42
$dbh->do('DELETE FROM items');
43
44
# Set userenv
45
C4::Context->_new_userenv('xxx');
46
C4::Context->set_userenv( 0, 0, 0, 'firstname', 'surname', 'MPL', 'Midway Public Library', '', '', '' );
47
is( C4::Context->userenv->{branch}, 'MPL', 'userenv set' );
48
49
my @patrons;
50
for my $i ( 1 .. 20 ) {
51
    my $patron = Koha::Borrower->new(
52
        { cardnumber => $i, firstname => 'Kyle', surname => 'Hall', categorycode => 'S', branchcode => 'MPL' } )
53
      ->store();
54
    push( @patrons, $patron );
55
}
56
57
my $biblio = Koha::Biblio->new()->store();
58
my $biblioitem =
59
  $schema->resultset('Biblioitem')->new( { biblionumber => $biblio->biblionumber } )->insert();
60
61
my @items;
62
for my $i ( 1 .. 10 ) {
63
    my $item = Koha::Item->new( { biblionumber => $biblio->id(), biblioitemnumber => $biblioitem->id(), } )->store();
64
    push( @items, $item );
65
}
66
67
for my $i ( 0 .. 4 ) {
68
    my $patron = $patrons[$i];
69
    my $hold   = Koha::Hold->new(
70
        {
71
            borrowernumber => $patron->id,
72
            biblionumber   => $biblio->id,
73
            branchcode     => 'MPL',
74
        }
75
    )->store();
76
}
77
78
$schema->resultset('Issuingrule')
79
  ->new( { branchcode => '*', categorycode => '*', itemtype => '*', issuelength => '14', lengthunit => 'days' } )
80
  ->insert();
81
82
my $item   = pop(@items);
83
my $patron = pop(@patrons);
84
85
C4::Context->set_preference( 'decreaseLoanHighHolds',               1 );
86
C4::Context->set_preference( 'decreaseLoanHighHoldsDuration',       1 );
87
C4::Context->set_preference( 'decreaseLoanHighHoldsValue',          1 );
88
C4::Context->set_preference( 'decreaseLoanHighHoldsControl',        'static' );
89
C4::Context->set_preference( 'decreaseLoanHighHoldsIgnoreStatuses', 'damaged,itemlost,notforloan,withdrawn' );
90
91
my $item_hr = { itemnumber => $item->id, biblionumber => $biblio->id, homebranch => 'MPL', holdingbranch => 'MPL' };
92
my $patron_hr = { borrower => $patron->id, branchcode => 'MPL' };
93
94
my $data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
95
is( $data->{exceeded},        1,          "Should exceed threshold" );
96
is( $data->{outstanding},     5,          "Should have 5 outstanding holds" );
97
is( $data->{duration},        1,          "Should have duration of 1" );
98
is( ref( $data->{due_date} ), 'DateTime', "due_date should be a DateTime object" );
99
100
C4::Context->set_preference( 'decreaseLoanHighHoldsControl', 'dynamic' );
101
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
102
is( $data->{exceeded}, 0, "Should not exceed threshold" );
103
104
for my $i ( 5 .. 10 ) {
105
    my $patron = $patrons[$i];
106
    my $hold   = Koha::Hold->new(
107
        {
108
            borrowernumber => $patron->id,
109
            biblionumber   => $biblio->id,
110
            branchcode     => 'MPL',
111
        }
112
    )->store();
113
}
114
115
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
116
is( $data->{exceeded}, 1, "Should exceed threshold" );
117
118
C4::Context->set_preference( 'decreaseLoanHighHoldsValue', 2 );
119
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
120
is( $data->{exceeded}, 0, "Should not exceed threshold" );
121
122
my $unholdable = pop(@items);
123
$unholdable->damaged(-1);
124
$unholdable->store();
125
126
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
127
is( $data->{exceeded}, 1, "Should exceed threshold" );
128
129
$unholdable->damaged(0);
130
$unholdable->itemlost(-1);
131
$unholdable->store();
132
133
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
134
is( $data->{exceeded}, 1, "Should exceed threshold" );
135
136
$unholdable->itemlost(0);
137
$unholdable->notforloan(-1);
138
$unholdable->store();
139
140
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
141
is( $data->{exceeded}, 1, "Should exceed threshold" );
142
143
$unholdable->notforloan(0);
144
$unholdable->withdrawn(-1);
145
$unholdable->store();
146
147
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
148
is( $data->{exceeded}, 1, "Should exceed threshold" );
149
150
$schema->storage->txn_rollback();
151
1;

Return to bug 14694