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

(-)a/C4/Reserves.pm (-59 / +27 lines)
Lines 370-378 sub CanItemBeReserved { Link Here
370
370
371
    my $dbh = C4::Context->dbh;
371
    my $dbh = C4::Context->dbh;
372
    my $ruleitemtype;    # itemtype of the matching issuing rule
372
    my $ruleitemtype;    # itemtype of the matching issuing rule
373
    my $allowedreserves  = 0; # Total number of holds allowed across all records
373
    my $allowedreserves  = 0; # Total number of holds allowed across all records, default to none
374
    my $holds_per_record = 1; # Total number of holds allowed for this one given record
375
    my $holds_per_day;        # Default to unlimited
376
374
377
    # we retrieve borrowers and items informations #
375
    # we retrieve borrowers and items informations #
378
    # item->{itype} will come for biblioitems if necessery
376
    # item->{itype} will come for biblioitems if necessery
Lines 425-440 sub CanItemBeReserved { Link Here
425
    }
423
    }
426
424
427
    # we retrieve rights
425
    # we retrieve rights
428
    if ( my $rights = GetHoldRule( $borrower->{'categorycode'}, $item->effective_itemtype, $branchcode ) ) {
426
    if (
429
        $ruleitemtype     = $rights->{itemtype};
427
        my $reservesallowed = Koha::CirculationRules->get_effective_rule({
430
        $allowedreserves  = $rights->{reservesallowed} // $allowedreserves;
428
                itemtype     => $item->effective_itemtype,
431
        $holds_per_record = $rights->{holds_per_record} // $holds_per_record;
429
                categorycode => $borrower->{categorycode},
432
        $holds_per_day    = $rights->{holds_per_day};
430
                branchcode   => $branchcode,
431
                rule_name    => 'reservesallowed',
432
        })
433
    ) {
434
        $ruleitemtype     = $reservesallowed->itemtype;
435
        $allowedreserves  = $reservesallowed->rule_value // 0; #undefined is 0, blank is unlimited
433
    }
436
    }
434
    else {
437
    else {
435
        $ruleitemtype = undef;
438
        $ruleitemtype = undef;
436
    }
439
    }
437
440
441
    my $rights = Koha::CirculationRules->get_effective_rules({
442
        categorycode => $borrower->{'categorycode'},
443
        itemtype     => $item->effective_itemtype,
444
        branchcode   => $branchcode,
445
        rules        => ['holds_per_record','holds_per_day']
446
    });
447
    my $holds_per_record = $rights->{holds_per_record} // 1;
448
    my $holds_per_day    = $rights->{holds_per_day};
449
438
    my $search_params = {
450
    my $search_params = {
439
        borrowernumber => $borrowernumber,
451
        borrowernumber => $borrowernumber,
440
        biblionumber   => $item->biblionumber,
452
        biblionumber   => $item->biblionumber,
Lines 2243-2303 sub GetMaxPatronHoldsForRecord { Link Here
2243
2255
2244
        $branchcode = $item->homebranch if ( $controlbranch eq "ItemHomeLibrary" );
2256
        $branchcode = $item->homebranch if ( $controlbranch eq "ItemHomeLibrary" );
2245
2257
2246
        my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode );
2258
        my $rule = Koha::CirculationRules->get_effective_rule({
2247
        my $holds_per_record = $rule ? $rule->{holds_per_record} : 0;
2248
        $max = $holds_per_record if $holds_per_record > $max;
2249
    }
2250
2251
    return $max;
2252
}
2253
2254
=head2 GetHoldRule
2255
2256
my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode );
2257
2258
Returns the matching hold related issuingrule fields for a given
2259
patron category, itemtype, and library.
2260
2261
=cut
2262
2263
sub GetHoldRule {
2264
    my ( $categorycode, $itemtype, $branchcode ) = @_;
2265
2266
    my $reservesallowed = Koha::CirculationRules->get_effective_rule(
2267
        {
2268
            itemtype     => $itemtype,
2269
            categorycode => $categorycode,
2259
            categorycode => $categorycode,
2270
            branchcode   => $branchcode,
2271
            rule_name    => 'reservesallowed',
2272
            order_by     => {
2273
                -desc => [ 'categorycode', 'itemtype', 'branchcode' ]
2274
            }
2275
        }
2276
    );
2277
2278
    my $rules;
2279
    if ( $reservesallowed ) {
2280
        $rules->{reservesallowed} = $reservesallowed->rule_value;
2281
        $rules->{itemtype}        = $reservesallowed->itemtype;
2282
        $rules->{categorycode}    = $reservesallowed->categorycode;
2283
        $rules->{branchcode}      = $reservesallowed->branchcode;
2284
    }
2285
2286
    my $holds_per_x_rules = Koha::CirculationRules->get_effective_rules(
2287
        {
2288
            itemtype     => $itemtype,
2260
            itemtype     => $itemtype,
2289
            categorycode => $categorycode,
2290
            branchcode   => $branchcode,
2261
            branchcode   => $branchcode,
2291
            rules        => ['holds_per_record', 'holds_per_day'],
2262
            rule_name    => 'holds_per_record'
2292
            order_by     => {
2263
        });
2293
                -desc => [ 'categorycode', 'itemtype', 'branchcode' ]
2264
        my $holds_per_record = $rule ? $rule->rule_value : 0;
2294
            }
2265
        $max = $holds_per_record if $holds_per_record > $max;
2295
        }
2266
    }
2296
    );
2297
    $rules->{holds_per_record} = $holds_per_x_rules->{holds_per_record};
2298
    $rules->{holds_per_day} = $holds_per_x_rules->{holds_per_day};
2299
2267
2300
    return $rules;
2268
    return $max;
2301
}
2269
}
2302
2270
2303
=head1 AUTHOR
2271
=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 => 67;
10
use Test::More tests => 68;
11
use MARC::Record;
11
use MARC::Record;
12
12
13
use C4::Biblio;
13
use C4::Biblio;
Lines 1328-1330 subtest 'non priority holds' => sub { Link Here
1328
    $schema->storage->txn_rollback;
1328
    $schema->storage->txn_rollback;
1329
1329
1330
};
1330
};
1331
1332
subtest 'CanItemBeReserved rule precedence tests' => sub {
1333
1334
    plan tests => 3;
1335
1336
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
1337
    $schema->storage->txn_begin;
1338
    my $library  = $builder->build_object( { class => 'Koha::Libraries', value => {
1339
        pickup_location => 1,
1340
    }});
1341
    my $item = $builder->build_sample_item({
1342
        homebranch    => $library->branchcode,
1343
        holdingbranch => $library->branchcode
1344
    });
1345
    my $item2 = $builder->build_sample_item({
1346
        homebranch    => $library->branchcode,
1347
        holdingbranch => $library->branchcode,
1348
        itype         => $item->itype
1349
    });
1350
    my $patron   = $builder->build_object({ class => 'Koha::Patrons', value => {
1351
        branchcode => $library->branchcode
1352
    }});
1353
    Koha::CirculationRules->set_rules(
1354
        {
1355
            branchcode   => undef,
1356
            categorycode => $patron->categorycode,
1357
            itemtype     => $item->itype,
1358
            rules        => {
1359
                reservesallowed  => 1,
1360
            }
1361
        }
1362
    );
1363
    is_deeply(
1364
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1365
        { status => 'OK' },
1366
        'Patron of specified category can place 1 hold on specified itemtype'
1367
    );
1368
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
1369
        biblionumber   => $item2->biblionumber,
1370
        itemnumber     => $item2->itemnumber,
1371
        found          => undef,
1372
        priority       => 1,
1373
        branchcode     => $library->branchcode,
1374
        borrowernumber => $patron->borrowernumber,
1375
    }});
1376
    is_deeply(
1377
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1378
        { status => 'tooManyReserves', limit => 1 },
1379
        'Patron of specified category can place 1 hold on specified itemtype, cannot place a second'
1380
    );
1381
    Koha::CirculationRules->set_rules(
1382
        {
1383
            branchcode   => $library->branchcode,
1384
            categorycode => undef,
1385
            itemtype     => undef,
1386
            rules        => {
1387
                reservesallowed  => 2,
1388
            }
1389
        }
1390
    );
1391
    is_deeply(
1392
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1393
        { status => 'OK' },
1394
        'Patron of specified category can place 1 hold on specified itemtype if library rule for all types and categories set to 2'
1395
    );
1396
1397
    $schema->storage->txn_rollback;
1398
1399
};
(-)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 89-95 my $item3 = $builder->build_sample_item( Link Here
89
89
90
Koha::CirculationRules->delete();
90
Koha::CirculationRules->delete();
91
91
92
# Test GetMaxPatronHoldsForRecord and GetHoldRule
92
# Test GetMaxPatronHoldsForRecord
93
Koha::CirculationRules->set_rules(
93
Koha::CirculationRules->set_rules(
94
    {
94
    {
95
        categorycode => undef,
95
        categorycode => undef,
Lines 106-121 t::lib::Mocks::mock_preference('item-level_itypes', 1); # Assuming the item type Link Here
106
106
107
my $max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
107
my $max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
108
is( $max, 1, 'GetMaxPatronHoldsForRecord returns max of 1' );
108
is( $max, 1, 'GetMaxPatronHoldsForRecord returns max of 1' );
109
my $rule = C4::Reserves::GetHoldRule(
110
    $category->{categorycode},
111
    $itemtype1->{itemtype},
112
    $library->{branchcode}
113
);
114
is( $rule->{categorycode},     undef, 'Got rule with universal categorycode' );
115
is( $rule->{itemtype},         undef, 'Got rule with universal itemtype' );
116
is( $rule->{branchcode},       undef, 'Got rule with universal branchcode' );
117
is( $rule->{reservesallowed},  1,   'Got reservesallowed of 1' );
118
is( $rule->{holds_per_record}, 1,   'Got holds_per_record of 1' );
119
109
120
Koha::CirculationRules->set_rules(
110
Koha::CirculationRules->set_rules(
121
    {
111
    {
Lines 131-146 Koha::CirculationRules->set_rules( Link Here
131
121
132
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
122
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
133
is( $max, 2, 'GetMaxPatronHoldsForRecord returns max of 2' );
123
is( $max, 2, 'GetMaxPatronHoldsForRecord returns max of 2' );
134
$rule = C4::Reserves::GetHoldRule(
135
    $category->{categorycode},
136
    $itemtype1->{itemtype},
137
    $library->{branchcode}
138
);
139
is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
140
is( $rule->{itemtype},         undef,                       'Got rule with universal itemtype' );
141
is( $rule->{branchcode},       undef,                       'Got rule with universal branchcode' );
142
is( $rule->{reservesallowed},  2,                         'Got reservesallowed of 2' );
143
is( $rule->{holds_per_record}, 2,                         'Got holds_per_record of 2' );
144
124
145
Koha::CirculationRules->set_rules(
125
Koha::CirculationRules->set_rules(
146
    {
126
    {
Lines 156-171 Koha::CirculationRules->set_rules( Link Here
156
136
157
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
137
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
158
is( $max, 3, 'GetMaxPatronHoldsForRecord returns max of 3' );
138
is( $max, 3, 'GetMaxPatronHoldsForRecord returns max of 3' );
159
$rule = C4::Reserves::GetHoldRule(
160
    $category->{categorycode},
161
    $itemtype1->{itemtype},
162
    $library->{branchcode}
163
);
164
is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
165
is( $rule->{itemtype},         $itemtype1->{itemtype},    'Got rule with universal itemtype' );
166
is( $rule->{branchcode},       undef,                       'Got rule with universal branchcode' );
167
is( $rule->{reservesallowed},  3,                         'Got reservesallowed of 3' );
168
is( $rule->{holds_per_record}, 3,                         'Got holds_per_record of 3' );
169
139
170
Koha::CirculationRules->set_rules(
140
Koha::CirculationRules->set_rules(
171
    {
141
    {
Lines 181-196 Koha::CirculationRules->set_rules( Link Here
181
151
182
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
152
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
183
is( $max, 4, 'GetMaxPatronHoldsForRecord returns max of 4' );
153
is( $max, 4, 'GetMaxPatronHoldsForRecord returns max of 4' );
184
$rule = C4::Reserves::GetHoldRule(
185
    $category->{categorycode},
186
    $itemtype2->{itemtype},
187
    $library->{branchcode}
188
);
189
is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
190
is( $rule->{itemtype},         $itemtype2->{itemtype},    'Got rule with universal itemtype' );
191
is( $rule->{branchcode},       undef,                       'Got rule with universal branchcode' );
192
is( $rule->{reservesallowed},  4,                         'Got reservesallowed of 4' );
193
is( $rule->{holds_per_record}, 4,                         'Got holds_per_record of 4' );
194
154
195
Koha::CirculationRules->set_rules(
155
Koha::CirculationRules->set_rules(
196
    {
156
    {
Lines 205-221 Koha::CirculationRules->set_rules( Link Here
205
);
165
);
206
166
207
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
167
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
208
is( $max, 5, 'GetMaxPatronHoldsForRecord returns max of 1' );
168
is( $max, 5, 'GetMaxPatronHoldsForRecord returns max of 5' );
209
$rule = C4::Reserves::GetHoldRule(
169
210
    $category->{categorycode},
170
Koha::CirculationRules->set_rules(
211
    $itemtype2->{itemtype},
171
    {
212
    $library->{branchcode}
172
        categorycode => undef,
173
        itemtype     => undef,
174
        branchcode   => $library->{branchcode},
175
        rules        => {
176
            reservesallowed  => 9,
177
            holds_per_record => 9,
178
        }
179
    }
213
);
180
);
214
is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
181
215
is( $rule->{itemtype},         $itemtype2->{itemtype},    'Got rule with universal itemtype' );
182
$max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->biblionumber );
216
is( $rule->{branchcode},       $library->{branchcode},    'Got rule with specific branchcode' );
183
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' );
217
is( $rule->{reservesallowed},  5,                         'Got reservesallowed of 5' );
218
is( $rule->{holds_per_record}, 5,                         'Got holds_per_record of 5' );
219
184
220
Koha::CirculationRules->delete();
185
Koha::CirculationRules->delete();
221
186
222
- 

Return to bug 26634