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

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

Return to bug 24185