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

(-)a/C4/Reserves.pm (-59 / +27 lines)
Lines 356-364 sub CanItemBeReserved { Link Here
356
356
357
    my $dbh = C4::Context->dbh;
357
    my $dbh = C4::Context->dbh;
358
    my $ruleitemtype;    # itemtype of the matching issuing rule
358
    my $ruleitemtype;    # itemtype of the matching issuing rule
359
    my $allowedreserves  = 0; # Total number of holds allowed across all records
359
    my $allowedreserves  = 0; # Total number of holds allowed across all records, default to none
360
    my $holds_per_record = 1; # Total number of holds allowed for this one given record
361
    my $holds_per_day;        # Default to unlimited
362
360
363
    # we retrieve borrowers and items informations #
361
    # we retrieve borrowers and items informations #
364
    # item->{itype} will come for biblioitems if necessery
362
    # item->{itype} will come for biblioitems if necessery
Lines 405-420 sub CanItemBeReserved { Link Here
405
    }
403
    }
406
404
407
    # we retrieve rights
405
    # we retrieve rights
408
    if ( my $rights = GetHoldRule( $borrower->{'categorycode'}, $item->effective_itemtype, $branchcode ) ) {
406
    if (
409
        $ruleitemtype     = $rights->{itemtype};
407
        my $reservesallowed = Koha::CirculationRules->get_effective_rule({
410
        $allowedreserves  = $rights->{reservesallowed} // $allowedreserves;
408
                itemtype     => $item->effective_itemtype,
411
        $holds_per_record = $rights->{holds_per_record} // $holds_per_record;
409
                categorycode => $borrower->{categorycode},
412
        $holds_per_day    = $rights->{holds_per_day};
410
                branchcode   => $branchcode,
411
                rule_name    => 'reservesallowed',
412
        })
413
    ) {
414
        $ruleitemtype     = $reservesallowed->itemtype;
415
        $allowedreserves  = $reservesallowed->rule_value // 0; #undefined is 0, blank is unlimited
413
    }
416
    }
414
    else {
417
    else {
415
        $ruleitemtype = undef;
418
        $ruleitemtype = undef;
416
    }
419
    }
417
420
421
    my $rights = Koha::CirculationRules->get_effective_rules({
422
        categorycode => $borrower->{'categorycode'},
423
        itemtype     => $item->effective_itemtype,
424
        branchcode   => $branchcode,
425
        rules        => ['holds_per_record','holds_per_day']
426
    });
427
    my $holds_per_record = $rights->{holds_per_record} // 1;
428
    my $holds_per_day    = $rights->{holds_per_day};
429
418
    my $search_params = {
430
    my $search_params = {
419
        borrowernumber => $borrowernumber,
431
        borrowernumber => $borrowernumber,
420
        biblionumber   => $item->biblionumber,
432
        biblionumber   => $item->biblionumber,
Lines 2208-2268 sub GetMaxPatronHoldsForRecord { Link Here
2208
2220
2209
        $branchcode = $item->homebranch if ( $controlbranch eq "ItemHomeLibrary" );
2221
        $branchcode = $item->homebranch if ( $controlbranch eq "ItemHomeLibrary" );
2210
2222
2211
        my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode );
2223
        my $rule = Koha::CirculationRules->get_effective_rule({
2212
        my $holds_per_record = $rule ? $rule->{holds_per_record} : 0;
2213
        $max = $holds_per_record if $holds_per_record > $max;
2214
    }
2215
2216
    return $max;
2217
}
2218
2219
=head2 GetHoldRule
2220
2221
my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode );
2222
2223
Returns the matching hold related issuingrule fields for a given
2224
patron category, itemtype, and library.
2225
2226
=cut
2227
2228
sub GetHoldRule {
2229
    my ( $categorycode, $itemtype, $branchcode ) = @_;
2230
2231
    my $reservesallowed = Koha::CirculationRules->get_effective_rule(
2232
        {
2233
            itemtype     => $itemtype,
2234
            categorycode => $categorycode,
2224
            categorycode => $categorycode,
2235
            branchcode   => $branchcode,
2236
            rule_name    => 'reservesallowed',
2237
            order_by     => {
2238
                -desc => [ 'categorycode', 'itemtype', 'branchcode' ]
2239
            }
2240
        }
2241
    );
2242
2243
    my $rules;
2244
    if ( $reservesallowed ) {
2245
        $rules->{reservesallowed} = $reservesallowed->rule_value;
2246
        $rules->{itemtype}        = $reservesallowed->itemtype;
2247
        $rules->{categorycode}    = $reservesallowed->categorycode;
2248
        $rules->{branchcode}      = $reservesallowed->branchcode;
2249
    }
2250
2251
    my $holds_per_x_rules = Koha::CirculationRules->get_effective_rules(
2252
        {
2253
            itemtype     => $itemtype,
2225
            itemtype     => $itemtype,
2254
            categorycode => $categorycode,
2255
            branchcode   => $branchcode,
2226
            branchcode   => $branchcode,
2256
            rules        => ['holds_per_record', 'holds_per_day'],
2227
            rule_name    => 'holds_per_record'
2257
            order_by     => {
2228
        });
2258
                -desc => [ 'categorycode', 'itemtype', 'branchcode' ]
2229
        my $holds_per_record = $rule ? $rule->rule_value : 0;
2259
            }
2230
        $max = $holds_per_record if $holds_per_record > $max;
2260
        }
2231
    }
2261
    );
2262
    $rules->{holds_per_record} = $holds_per_x_rules->{holds_per_record};
2263
    $rules->{holds_per_day} = $holds_per_x_rules->{holds_per_day};
2264
2232
2265
    return $rules;
2233
    return $max;
2266
}
2234
}
2267
2235
2268
=head1 AUTHOR
2236
=head1 AUTHOR
(-)a/t/db_dependent/Holds.t (-1 / +70 lines)
Lines 7-13 use t::lib::TestBuilder; Link Here
7
7
8
use C4::Context;
8
use C4::Context;
9
9
10
use Test::More tests => 66;
10
use Test::More tests => 67;
11
use MARC::Record;
11
use MARC::Record;
12
12
13
use C4::Biblio;
13
use C4::Biblio;
Lines 1251-1253 subtest 'CanItemBeReserved / pickup_not_in_hold_group' => sub { Link Here
1251
1251
1252
    $schema->storage->txn_rollback;
1252
    $schema->storage->txn_rollback;
1253
};
1253
};
1254
1255
subtest 'CanItemBeReserved rule precedence tests' => sub {
1256
1257
    plan tests => 3;
1258
1259
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
1260
    $schema->storage->txn_begin;
1261
    my $library  = $builder->build_object( { class => 'Koha::Libraries', value => {
1262
        pickup_location => 1,
1263
    }});
1264
    my $item = $builder->build_sample_item({
1265
        homebranch    => $library->branchcode,
1266
        holdingbranch => $library->branchcode
1267
    });
1268
    my $item2 = $builder->build_sample_item({
1269
        homebranch    => $library->branchcode,
1270
        holdingbranch => $library->branchcode,
1271
        itype         => $item->itype
1272
    });
1273
    my $patron   = $builder->build_object({ class => 'Koha::Patrons', value => {
1274
        branchcode => $library->branchcode
1275
    }});
1276
    Koha::CirculationRules->set_rules(
1277
        {
1278
            branchcode   => undef,
1279
            categorycode => $patron->categorycode,
1280
            itemtype     => $item->itype,
1281
            rules        => {
1282
                reservesallowed  => 1,
1283
            }
1284
        }
1285
    );
1286
    is_deeply(
1287
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1288
        { status => 'OK' },
1289
        'Patron of specified category can place 1 hold on specified itemtype'
1290
    );
1291
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
1292
        biblionumber   => $item2->biblionumber,
1293
        itemnumber     => $item2->itemnumber,
1294
        found          => undef,
1295
        priority       => 1,
1296
        branchcode     => $library->branchcode,
1297
        borrowernumber => $patron->borrowernumber,
1298
    }});
1299
    is_deeply(
1300
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1301
        { status => 'tooManyReserves', limit => 1 },
1302
        'Patron of specified category can place 1 hold on specified itemtype, cannot place a second'
1303
    );
1304
    Koha::CirculationRules->set_rules(
1305
        {
1306
            branchcode   => $library->branchcode,
1307
            categorycode => undef,
1308
            itemtype     => undef,
1309
            rules        => {
1310
                reservesallowed  => 2,
1311
            }
1312
        }
1313
    );
1314
    is_deeply(
1315
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1316
        { status => 'OK' },
1317
        'Patron of specified category can place 1 hold on specified itemtype if library rule for all types and categories set to 2'
1318
    );
1319
1320
    $schema->storage->txn_rollback;
1321
1322
};
(-)a/t/db_dependent/Reserves/MultiplePerRecord.t (-53 / +17 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 40;
22
use Test::More tests => 16;
23
use t::lib::TestBuilder;
23
use t::lib::TestBuilder;
24
use t::lib::Mocks;
24
use t::lib::Mocks;
25
25
Lines 117-123 my $item3 = $builder->build( Link Here
117
117
118
Koha::CirculationRules->delete();
118
Koha::CirculationRules->delete();
119
119
120
# Test GetMaxPatronHoldsForRecord and GetHoldRule
120
# Test GetMaxPatronHoldsForRecord
121
Koha::CirculationRules->set_rules(
121
Koha::CirculationRules->set_rules(
122
    {
122
    {
123
        categorycode => undef,
123
        categorycode => undef,
Lines 134-149 t::lib::Mocks::mock_preference('item-level_itypes', 1); # Assuming the item type Link Here
134
134
135
my $max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
135
my $max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
136
is( $max, 1, 'GetMaxPatronHoldsForRecord returns max of 1' );
136
is( $max, 1, 'GetMaxPatronHoldsForRecord returns max of 1' );
137
my $rule = C4::Reserves::GetHoldRule(
138
    $category->{categorycode},
139
    $itemtype1->{itemtype},
140
    $library->{branchcode}
141
);
142
is( $rule->{categorycode},     undef, 'Got rule with universal categorycode' );
143
is( $rule->{itemtype},         undef, 'Got rule with universal itemtype' );
144
is( $rule->{branchcode},       undef, 'Got rule with universal branchcode' );
145
is( $rule->{reservesallowed},  1,   'Got reservesallowed of 1' );
146
is( $rule->{holds_per_record}, 1,   'Got holds_per_record of 1' );
147
137
148
Koha::CirculationRules->set_rules(
138
Koha::CirculationRules->set_rules(
149
    {
139
    {
Lines 159-174 Koha::CirculationRules->set_rules( Link Here
159
149
160
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
150
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
161
is( $max, 2, 'GetMaxPatronHoldsForRecord returns max of 2' );
151
is( $max, 2, 'GetMaxPatronHoldsForRecord returns max of 2' );
162
$rule = C4::Reserves::GetHoldRule(
163
    $category->{categorycode},
164
    $itemtype1->{itemtype},
165
    $library->{branchcode}
166
);
167
is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
168
is( $rule->{itemtype},         undef,                       'Got rule with universal itemtype' );
169
is( $rule->{branchcode},       undef,                       'Got rule with universal branchcode' );
170
is( $rule->{reservesallowed},  2,                         'Got reservesallowed of 2' );
171
is( $rule->{holds_per_record}, 2,                         'Got holds_per_record of 2' );
172
152
173
Koha::CirculationRules->set_rules(
153
Koha::CirculationRules->set_rules(
174
    {
154
    {
Lines 184-199 Koha::CirculationRules->set_rules( Link Here
184
164
185
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
165
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
186
is( $max, 3, 'GetMaxPatronHoldsForRecord returns max of 3' );
166
is( $max, 3, 'GetMaxPatronHoldsForRecord returns max of 3' );
187
$rule = C4::Reserves::GetHoldRule(
188
    $category->{categorycode},
189
    $itemtype1->{itemtype},
190
    $library->{branchcode}
191
);
192
is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
193
is( $rule->{itemtype},         $itemtype1->{itemtype},    'Got rule with universal itemtype' );
194
is( $rule->{branchcode},       undef,                       'Got rule with universal branchcode' );
195
is( $rule->{reservesallowed},  3,                         'Got reservesallowed of 3' );
196
is( $rule->{holds_per_record}, 3,                         'Got holds_per_record of 3' );
197
167
198
Koha::CirculationRules->set_rules(
168
Koha::CirculationRules->set_rules(
199
    {
169
    {
Lines 209-224 Koha::CirculationRules->set_rules( Link Here
209
179
210
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
180
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
211
is( $max, 4, 'GetMaxPatronHoldsForRecord returns max of 4' );
181
is( $max, 4, 'GetMaxPatronHoldsForRecord returns max of 4' );
212
$rule = C4::Reserves::GetHoldRule(
213
    $category->{categorycode},
214
    $itemtype2->{itemtype},
215
    $library->{branchcode}
216
);
217
is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
218
is( $rule->{itemtype},         $itemtype2->{itemtype},    'Got rule with universal itemtype' );
219
is( $rule->{branchcode},       undef,                       'Got rule with universal branchcode' );
220
is( $rule->{reservesallowed},  4,                         'Got reservesallowed of 4' );
221
is( $rule->{holds_per_record}, 4,                         'Got holds_per_record of 4' );
222
182
223
Koha::CirculationRules->set_rules(
183
Koha::CirculationRules->set_rules(
224
    {
184
    {
Lines 233-249 Koha::CirculationRules->set_rules( Link Here
233
);
193
);
234
194
235
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
195
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
236
is( $max, 5, 'GetMaxPatronHoldsForRecord returns max of 1' );
196
is( $max, 5, 'GetMaxPatronHoldsForRecord returns max of 5' );
237
$rule = C4::Reserves::GetHoldRule(
197
238
    $category->{categorycode},
198
Koha::CirculationRules->set_rules(
239
    $itemtype2->{itemtype},
199
    {
240
    $library->{branchcode}
200
        categorycode => undef,
201
        itemtype     => undef,
202
        branchcode   => $library->{branchcode},
203
        rules        => {
204
            reservesallowed  => 9,
205
            holds_per_record => 9,
206
        }
207
    }
241
);
208
);
242
is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
209
243
is( $rule->{itemtype},         $itemtype2->{itemtype},    'Got rule with universal itemtype' );
210
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
244
is( $rule->{branchcode},       $library->{branchcode},    'Got rule with specific branchcode' );
211
is( $max, 9, 'GetMaxPatronHoldsForRecord returns max of 9 because Library specific all itemtypes all categories rule comes before All libraries specific type and specific category' );
245
is( $rule->{reservesallowed},  5,                         'Got reservesallowed of 5' );
246
is( $rule->{holds_per_record}, 5,                         'Got holds_per_record of 5' );
247
212
248
Koha::CirculationRules->delete();
213
Koha::CirculationRules->delete();
249
214
250
- 

Return to bug 26634