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

(-)a/C4/Reserves.pm (-24 / +43 lines)
Lines 122-127 BEGIN { Link Here
122
        &AutoUnsuspendReserves
122
        &AutoUnsuspendReserves
123
123
124
        &IsAvailableForItemLevelRequest
124
        &IsAvailableForItemLevelRequest
125
        ItemsAnyAvailableForHold
125
126
126
        &AlterPriority
127
        &AlterPriority
127
        &ToggleLowestPriority
128
        &ToggleLowestPriority
Lines 1259-1288 sub IsAvailableForItemLevelRequest { Link Here
1259
    if ( $on_shelf_holds == 1 ) {
1260
    if ( $on_shelf_holds == 1 ) {
1260
        return 1;
1261
        return 1;
1261
    } elsif ( $on_shelf_holds == 2 ) {
1262
    } elsif ( $on_shelf_holds == 2 ) {
1262
        my @items =
1263
        my $any_available = ItemsAnyAvailableForHold( { biblionumber => $item->biblionumber, patron => $patron });
1263
          Koha::Items->search( { biblionumber => $item->biblionumber } );
1264
1265
        my $any_available = 0;
1266
1267
        foreach my $i (@items) {
1268
            my $reserves_control_branch = GetReservesControlBranch( $i->unblessed(), $patron->unblessed );
1269
            my $branchitemrule = C4::Circulation::GetBranchItemRule( $reserves_control_branch, $i->itype );
1270
            my $item_library = Koha::Libraries->find( {branchcode => $i->homebranch} );
1271
1272
1273
            $any_available = 1
1274
              unless $i->itemlost
1275
              || $i->notforloan > 0
1276
              || $i->withdrawn
1277
              || $i->onloan
1278
              || IsItemOnHoldAndFound( $i->id )
1279
              || ( $i->damaged
1280
                && !C4::Context->preference('AllowHoldsOnDamagedItems') )
1281
              || Koha::ItemTypes->find( $i->effective_itemtype() )->notforloan
1282
              || $branchitemrule->{holdallowed} == 1 && $patron->branchcode ne $i->homebranch
1283
              || $branchitemrule->{holdallowed} == 3 && !$item_library->validate_hold_sibling( {branchcode => $patron->branchcode} );
1284
        }
1285
1286
        return $any_available ? 0 : 1;
1264
        return $any_available ? 0 : 1;
1287
    } else { # on_shelf_holds == 0 "If any unavailable" (the description is rather cryptic and could still be improved)
1265
    } else { # on_shelf_holds == 0 "If any unavailable" (the description is rather cryptic and could still be improved)
1288
        return $item->onloan || IsItemOnHoldAndFound( $item->itemnumber );
1266
        return $item->onloan || IsItemOnHoldAndFound( $item->itemnumber );
Lines 1316-1321 sub _get_itype { Link Here
1316
    return $itype;
1294
    return $itype;
1317
}
1295
}
1318
1296
1297
=head2 ItemsAnyAvailableForHold
1298
1299
  ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron });
1300
1301
This function checks all items for specified biblionumber (num) / patron (object)
1302
and returns true (1) or false (0) depending if any of rules allows at least of
1303
one item to be available for hold including lots of parameters/logic
1304
1305
=cut
1306
1307
sub ItemsAnyAvailableForHold {
1308
    my $param = shift;
1309
1310
    my @items = Koha::Items->search( { biblionumber => $param->{biblionumber} } );
1311
1312
    my $any_available = 0;
1313
1314
    foreach my $i (@items) {
1315
        my $reserves_control_branch =
1316
            GetReservesControlBranch( $i->unblessed(), $param->{patron}->unblessed );
1317
        my $branchitemrule =
1318
            C4::Circulation::GetBranchItemRule( $reserves_control_branch, $i->itype );
1319
        my $item_library = Koha::Libraries->find( { branchcode => $i->homebranch } );
1320
1321
        $any_available = 1
1322
            unless $i->itemlost
1323
            || $i->notforloan > 0
1324
            || $i->withdrawn
1325
            || $i->onloan
1326
            || IsItemOnHoldAndFound( $i->id )
1327
            || ( $i->damaged
1328
            && ! C4::Context->preference('AllowHoldsOnDamagedItems') )
1329
            || Koha::ItemTypes->find( $i->effective_itemtype() )->notforloan
1330
            || $branchitemrule->{holdallowed} == 1 && $param->{patron}->branchcode ne $i->homebranch
1331
            || $branchitemrule->{holdallowed} == 3
1332
            && ! $item_library->validate_hold_sibling( { branchcode => $param->{patron}->branchcode } );
1333
    }
1334
1335
    return $any_available;
1336
}
1337
1319
=head2 AlterPriority
1338
=head2 AlterPriority
1320
1339
1321
  AlterPriority( $where, $reserve_id, $prev_priority, $next_priority, $first_priority, $last_priority );
1340
  AlterPriority( $where, $reserve_id, $prev_priority, $next_priority, $first_priority, $last_priority );
(-)a/t/db_dependent/Holds/DisallowHoldIfItemsAvailable.t (-5 / +58 lines)
Lines 8-14 use C4::Items; Link Here
8
use Koha::Items;
8
use Koha::Items;
9
use Koha::CirculationRules;
9
use Koha::CirculationRules;
10
10
11
use Test::More tests => 6;
11
use Test::More tests => 10;
12
12
13
use t::lib::TestBuilder;
13
use t::lib::TestBuilder;
14
use t::lib::Mocks;
14
use t::lib::Mocks;
Lines 96-111 Koha::CirculationRules->set_rules( Link Here
96
    }
96
    }
97
);
97
);
98
98
99
my $is = IsAvailableForItemLevelRequest( $item1, $patron1);
99
my $is;
100
101
$is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 });
102
is( $is, 1, "Items availability: both of 2 items are available" );
103
104
$is = IsAvailableForItemLevelRequest( $item1, $patron1);
100
is( $is, 0, "Item cannot be held, 2 items available" );
105
is( $is, 0, "Item cannot be held, 2 items available" );
101
106
102
my $issue1 = AddIssue( $patron2->unblessed, $item1->barcode );
107
my $issue1 = AddIssue( $patron2->unblessed, $item1->barcode );
103
108
109
$is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 });
110
is( $is, 1, "Items availability: one item is available" );
111
104
$is = IsAvailableForItemLevelRequest( $item1, $patron1);
112
$is = IsAvailableForItemLevelRequest( $item1, $patron1);
105
is( $is, 0, "Item cannot be held, 1 item available" );
113
is( $is, 0, "Item cannot be held, 1 item available" );
106
114
107
AddIssue( $patron2->unblessed, $item2->barcode );
115
AddIssue( $patron2->unblessed, $item2->barcode );
108
116
117
$is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 });
118
is( $is, 0, "Items availability: none of items are available" );
119
109
$is = IsAvailableForItemLevelRequest( $item1, $patron1);
120
$is = IsAvailableForItemLevelRequest( $item1, $patron1);
110
is( $is, 1, "Item can be held, no items available" );
121
is( $is, 1, "Item can be held, no items available" );
111
122
Lines 119-125 AddReturn( $item1->barcode ); Link Here
119
        my $hold_allowed_from_any_libraries = 2;
130
        my $hold_allowed_from_any_libraries = 2;
120
131
121
        subtest 'Item is available at a different library' => sub {
132
        subtest 'Item is available at a different library' => sub {
122
            plan tests => 7;
133
            plan tests => 13;
123
134
124
            $item1->set({homebranch => $library_B, holdingbranch => $library_B })->store;
135
            $item1->set({homebranch => $library_B, holdingbranch => $library_B })->store;
125
            #Scenario is:
136
            #Scenario is:
Lines 132-151 AddReturn( $item1->barcode ); Link Here
132
                set_holdallowed_rule( $hold_allowed_from_home_library );
143
                set_holdallowed_rule( $hold_allowed_from_home_library );
133
144
134
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
145
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
146
147
                $is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 0 items, library B 1 item
148
                is( $is, 0, "Items availability: hold allowed from home + ReservesControlBranch=ItemHomeLibrary + one item is available at different library" );
149
135
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
150
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
136
                is( $is, 1, "Hold allowed from home library + ReservesControlBranch=ItemHomeLibrary, One item is available at different library, not holdable = none available => the hold is allowed at item level" );
151
                is( $is, 1, "Hold allowed from home library + ReservesControlBranch=ItemHomeLibrary, One item is available at different library, not holdable = none available => the hold is allowed at item level" );
137
                $is = IsAvailableForItemLevelRequest( $item1, $patron2);
152
                $is = IsAvailableForItemLevelRequest( $item1, $patron2);
138
                is( $is, 1, "Hold allowed from home library + ReservesControlBranch=ItemHomeLibrary, One item is available at home library, holdable = one available => the hold is not allowed at item level" );
153
                is( $is, 1, "Hold allowed from home library + ReservesControlBranch=ItemHomeLibrary, One item is available at home library, holdable = one available => the hold is not allowed at item level" );
139
                set_holdallowed_rule( $hold_allowed_from_any_libraries, $library_B );
154
                set_holdallowed_rule( $hold_allowed_from_any_libraries, $library_B );
140
                #Adding a rule for the item's home library affects the availability for a borrower from another library because ReservesControlBranch is set to ItemHomeLibrary
155
                #Adding a rule for the item's home library affects the availability for a borrower from another library because ReservesControlBranch is set to ItemHomeLibrary
156
157
                $is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 0 items, library B 1 item
158
                is( $is, 1, "Items availability: hold allowed from any library for library B + ReservesControlBranch=ItemHomeLibrary + one item is available at different library" );
159
141
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
160
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
142
                is( $is, 0, "Hold allowed from home library + ReservesControlBranch=ItemHomeLibrary, One item is available at different library, holdable = one available => the hold is not allowed at item level" );
161
                is( $is, 0, "Hold allowed from home library + ReservesControlBranch=ItemHomeLibrary, One item is available at different library, holdable = one available => the hold is not allowed at item level" );
143
162
144
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
163
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
164
165
                $is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 0 items, library B 1 item
166
                is( $is, 0, "Items availability: hold allowed from any library for library B + ReservesControlBranch=PatronLibrary + one item is available at different library" );
167
145
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
168
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
146
                is( $is, 1, "Hold allowed from home library + ReservesControlBranch=PatronLibrary, One item is available at different library, not holdable = none available => the hold is allowed at item level" );
169
                is( $is, 1, "Hold allowed from home library + ReservesControlBranch=PatronLibrary, One item is available at different library, not holdable = none available => the hold is allowed at item level" );
147
                #Adding a rule for the patron's home library affects the availability for an item from another library because ReservesControlBranch is set to PatronLibrary
170
                #Adding a rule for the patron's home library affects the availability for an item from another library because ReservesControlBranch is set to PatronLibrary
148
                set_holdallowed_rule( $hold_allowed_from_any_libraries, $library_A );
171
                set_holdallowed_rule( $hold_allowed_from_any_libraries, $library_A );
172
173
                $is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 0 items, library B 1 item
174
                is( $is, 1, "Items availability: hold allowed from any library for library A + ReservesControlBranch=PatronLibrary + one item is available at different library" );
175
149
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
176
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
150
                is( $is, 0, "Hold allowed from home library + ReservesControlBranch=PatronLibrary, One item is available at different library, holdable = one available => the hold is not allowed at item level" );
177
                is( $is, 0, "Hold allowed from home library + ReservesControlBranch=PatronLibrary, One item is available at different library, holdable = one available => the hold is not allowed at item level" );
151
            }
178
            }
Lines 154-170 AddReturn( $item1->barcode ); Link Here
154
                set_holdallowed_rule( $hold_allowed_from_any_libraries );
181
                set_holdallowed_rule( $hold_allowed_from_any_libraries );
155
182
156
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
183
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
184
185
                $is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 0 items, library B 1 item
186
                is( $is, 1, "Items availability: hold allowed from any library + ReservesControlBranch=ItemHomeLibrary + one item is available at different library" );
187
157
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
188
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
158
                is( $is, 0, "Hold allowed from any library + ReservesControlBranch=ItemHomeLibrary, One item is available at the diff library, holdable = 1 available => the hold is not allowed at item level" );
189
                is( $is, 0, "Hold allowed from any library + ReservesControlBranch=ItemHomeLibrary, One item is available at the diff library, holdable = 1 available => the hold is not allowed at item level" );
159
190
160
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
191
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
192
193
                $is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 0 items, library B 1 item
194
                is( $is, 1, "Items availability: hold allowed from any library + ReservesControlBranch=PatronLibrary + one item is available at different library" );
195
161
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
196
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
162
                is( $is, 0, "Hold allowed from any library + ReservesControlBranch=PatronLibrary, One item is available at the diff library, holdable = 1 available => the hold is not allowed at item level" );
197
                is( $is, 0, "Hold allowed from any library + ReservesControlBranch=PatronLibrary, One item is available at the diff library, holdable = 1 available => the hold is not allowed at item level" );
163
            }
198
            }
164
        };
199
        };
165
200
166
        subtest 'Item is available at the same library' => sub {
201
        subtest 'Item is available at the same library' => sub {
167
            plan tests => 4;
202
            plan tests => 8;
168
203
169
            $item1->set({homebranch => $library_A, holdingbranch => $library_A })->store;
204
            $item1->set({homebranch => $library_A, holdingbranch => $library_A })->store;
170
            #Scenario is:
205
            #Scenario is:
Lines 179-188 AddReturn( $item1->barcode ); Link Here
179
                set_holdallowed_rule( $hold_allowed_from_home_library );
214
                set_holdallowed_rule( $hold_allowed_from_home_library );
180
215
181
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
216
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
217
218
                $is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 1 item
219
                is( $is, 1, "Items availability: hold allowed from home library + ReservesControlBranch=ItemHomeLibrary + one item is available at home library" );
220
182
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
221
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
183
                is( $is, 0, "Hold allowed from home library + ReservesControlBranch=ItemHomeLibrary, One item is available at the same library, holdable = 1 available  => the hold is not allowed at item level" );
222
                is( $is, 0, "Hold allowed from home library + ReservesControlBranch=ItemHomeLibrary, One item is available at the same library, holdable = 1 available  => the hold is not allowed at item level" );
184
223
185
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
224
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
225
226
                $is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 1 item
227
                is( $is, 1, "Items availability: hold allowed from home library + ReservesControlBranch=PatronLibrary + one item is available at home library" );
228
186
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
229
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
187
                is( $is, 0, "Hold allowed from home library + ReservesControlBranch=PatronLibrary, One item is available at the same library, holdable = 1 available  => the hold is not allowed at item level" );
230
                is( $is, 0, "Hold allowed from home library + ReservesControlBranch=PatronLibrary, One item is available at the same library, holdable = 1 available  => the hold is not allowed at item level" );
188
            }
231
            }
Lines 191-200 AddReturn( $item1->barcode ); Link Here
191
                set_holdallowed_rule( $hold_allowed_from_any_libraries );
234
                set_holdallowed_rule( $hold_allowed_from_any_libraries );
192
235
193
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
236
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
237
238
                $is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 1 item
239
                is( $is, 1, "Items availability: hold allowed from any library + ReservesControlBranch=ItemHomeLibrary + one item is available at home library" );
240
194
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
241
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
195
                is( $is, 0, "Hold allowed from any library + ReservesControlBranch=ItemHomeLibrary, One item is available at the same library, holdable = 1 available => the hold is not allowed at item level" );
242
                is( $is, 0, "Hold allowed from any library + ReservesControlBranch=ItemHomeLibrary, One item is available at the same library, holdable = 1 available => the hold is not allowed at item level" );
196
243
197
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
244
                t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
245
246
                $is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 1 item
247
                is( $is, 1, "Items availability: hold allowed from any library + ReservesControlBranch=PatronLibrary + one item is available at home library" );
248
198
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
249
                $is = IsAvailableForItemLevelRequest( $item1, $patron1);
199
                is( $is, 0, "Hold allowed from any library + ReservesControlBranch=PatronLibrary, One item is available at the same library, holdable = 1 available  => the hold is not allowed at item level" );
250
                is( $is, 0, "Hold allowed from any library + ReservesControlBranch=PatronLibrary, One item is available at the same library, holdable = 1 available  => the hold is not allowed at item level" );
200
            }
251
            }
Lines 228-233 Koha::CirculationRules->set_rules( Link Here
228
    }
279
    }
229
);
280
);
230
281
282
$is = ItemsAnyAvailableForHold( { biblionumber => $biblionumber, patron => $patron1 }); # patron1 in library A, library A 1 item
283
is( $is, 1, "Items availability: 1 item is available, 1 item held in T" );
284
231
$is = IsAvailableForItemLevelRequest( $item3, $patron1);
285
$is = IsAvailableForItemLevelRequest( $item3, $patron1);
232
is( $is, 1, "Item can be held, items in transit are not available" );
286
is( $is, 1, "Item can be held, items in transit are not available" );
233
287
234
- 

Return to bug 24185