Line 0
Link Here
|
|
|
1 |
#!/usr/bin/perl |
2 |
|
3 |
# Copyright Koha-Suomi Oy 2016 |
4 |
# |
5 |
# This file is part of Koha |
6 |
# |
7 |
# Koha is free software; you can redistribute it and/or modify it |
8 |
# under the terms of the GNU General Public License as published by |
9 |
# the Free Software Foundation; either version 3 of the License, or |
10 |
# (at your option) any later version. |
11 |
# |
12 |
# Koha is distributed in the hope t1hat it will be useful, but |
13 |
# WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
# GNU General Public License for more details. |
16 |
# |
17 |
# You should have received a copy of the GNU General Public License |
18 |
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
19 |
|
20 |
use Modern::Perl; |
21 |
use Test::More tests => 14; |
22 |
use t::lib::Mocks; |
23 |
use t::lib::TestBuilder; |
24 |
require t::db_dependent::Koha::Availability::Helpers; |
25 |
|
26 |
use Koha::Database; |
27 |
use Koha::IssuingRules; |
28 |
use Koha::Items; |
29 |
use Koha::ItemTypes; |
30 |
|
31 |
use Koha::Item::Availability::Hold; |
32 |
|
33 |
my $schema = Koha::Database->new->schema; |
34 |
$schema->storage->txn_begin; |
35 |
|
36 |
my $builder = t::lib::TestBuilder->new; |
37 |
|
38 |
set_default_system_preferences(); |
39 |
set_default_circulation_rules(); |
40 |
|
41 |
subtest 'Given item is in a good state for availability' => \&t_ok_availability; |
42 |
sub t_ok_availability { |
43 |
plan tests => 3; |
44 |
|
45 |
my $patron = build_a_test_patron(); |
46 |
my $item = build_a_test_item(); |
47 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
48 |
|
49 |
ok($availability->available, 'When I request availability, then the item is available.'); |
50 |
ok(!$availability->confirm, 'Then nothing needs to be confirmed.'); |
51 |
ok(!$availability->unavailable, 'Then there are no reasons to be unavailable.'); |
52 |
} |
53 |
|
54 |
subtest 'Given item is damaged' => sub { |
55 |
plan tests => 2; |
56 |
|
57 |
subtest 'Given AllowHoldsOnDamagedItems is disabled' => \&t_damaged_item_allow_disabled; |
58 |
subtest 'Given AllowHoldsOnDamagedItems is enabled' => \&t_damaged_item_allow_enabled; |
59 |
sub t_damaged_item_allow_disabled { |
60 |
plan tests => 4; |
61 |
|
62 |
t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 0); |
63 |
|
64 |
my $patron = build_a_test_patron(); |
65 |
my $item = build_a_test_item()->set({damaged=>1})->store; |
66 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
67 |
my $expecting = 'Koha::Exceptions::Item::Damaged'; |
68 |
|
69 |
is($item->damaged, 1, 'When I look at the item, I see that it is damaged.'); |
70 |
ok(!$availability->available, 'When I request availability, then the item is not available.'); |
71 |
is($availability->unavailable, 1, 'Then there is only one unavailability reason.'); |
72 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, |
73 |
'Then there is an unavailability status indicating damaged item.'); |
74 |
}; |
75 |
sub t_damaged_item_allow_enabled { |
76 |
plan tests => 4; |
77 |
|
78 |
t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1); |
79 |
|
80 |
my $patron = build_a_test_patron(); |
81 |
my $item = build_a_test_item()->set({damaged=>1})->store; |
82 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
83 |
|
84 |
is($item->damaged, 1, 'When I look at the item, I see that it is damaged.'); |
85 |
ok($availability->available, 'When I request availability, then the item is available.'); |
86 |
ok(!$availability->unavailable, 'Then there are no statuses for unavailability.'); |
87 |
ok(!$availability->confirm, 'Then there is no reason to have availability confirmed.'); |
88 |
}; |
89 |
}; |
90 |
|
91 |
subtest 'Given item is lost' => \&t_lost; |
92 |
sub t_lost { |
93 |
plan tests => 4; |
94 |
|
95 |
my $patron = build_a_test_patron(); |
96 |
my $item = build_a_test_item()->set({itemlost=>1})->store; |
97 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
98 |
my $expecting = 'Koha::Exceptions::Item::Lost'; |
99 |
|
100 |
is($item->itemlost, 1, 'When I try to look at the item, I find out that it is lost.'); |
101 |
ok(!$availability->available, 'When I request availability, then the item is not available.'); |
102 |
is($availability->unavailable, 1, 'Then there is only one unavailability reason.'); |
103 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, |
104 |
'Then there is an unavailability status indicating lost item.'); |
105 |
}; |
106 |
|
107 |
subtest 'Given item is not for loan' => \&t_notforloan; |
108 |
sub t_notforloan { |
109 |
plan tests => 4; |
110 |
|
111 |
my $patron = build_a_test_patron(); |
112 |
my $item = build_a_test_item()->set({notforloan=>1})->store; |
113 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
114 |
my $expecting = 'Koha::Exceptions::Item::NotForLoan'; |
115 |
|
116 |
is($item->notforloan, 1, 'When I look at the item, I see that it is not for loan.'); |
117 |
ok(!$availability->available, 'When I request availability, then the item is not available.'); |
118 |
is($availability->unavailable, 1, 'Then there is only one unavailability reason.'); |
119 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, |
120 |
'Then there is an unavailability status indicating the item is not for loan.'); |
121 |
}; |
122 |
|
123 |
subtest 'Given item type is not for loan' => sub { |
124 |
|
125 |
subtest 'Given item-level_itypes is on (item-itemtype)' => \&t_itemlevel_itemtype_notforloan_item_level_itypes_on; |
126 |
subtest 'Given item-level_itypes is off (biblioitem-itemtype)' => \&t_itemlevel_itemtype_notforloan_item_level_itypes_off; |
127 |
sub t_itemlevel_itemtype_notforloan_item_level_itypes_on { |
128 |
plan tests => 5; |
129 |
|
130 |
t::lib::Mocks::mock_preference('item-level_itypes', 1); |
131 |
|
132 |
my $patron = build_a_test_patron(); |
133 |
my $item = build_a_test_item(); |
134 |
my $biblioitem = Koha::Biblioitems->find($item->biblioitemnumber); |
135 |
my $itemtype = Koha::ItemTypes->find($item->itype); |
136 |
$itemtype->set({notforloan=>1})->store; |
137 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
138 |
my $expecting = 'Koha::Exceptions::ItemType::NotForLoan'; |
139 |
|
140 |
is(Koha::ItemTypes->find($biblioitem->itemtype)->notforloan, 0, 'Biblioitem itemtype is for loan.'); |
141 |
is(Koha::ItemTypes->find($item->itype)->notforloan, 1, 'Item itemtype is not for loan.'); |
142 |
ok(!$availability->available, 'When I request availability, then the item is not available.'); |
143 |
is($availability->unavailable, 1, 'Then there is only one unavailability reason.'); |
144 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, |
145 |
"Then there is an unavailability status indicating the itemtype is not forloan."); |
146 |
}; |
147 |
sub t_itemlevel_itemtype_notforloan_item_level_itypes_off { |
148 |
plan tests => 5; |
149 |
|
150 |
t::lib::Mocks::mock_preference('item-level_itypes', 0); |
151 |
|
152 |
my $patron = build_a_test_patron(); |
153 |
my $item = build_a_test_item(); |
154 |
my $biblioitem = Koha::Biblioitems->find($item->biblioitemnumber); |
155 |
my $itemtype = Koha::ItemTypes->find($biblioitem->itemtype); |
156 |
$itemtype->set({notforloan=>1})->store; |
157 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
158 |
my $expecting = 'Koha::Exceptions::ItemType::NotForLoan'; |
159 |
|
160 |
is(Koha::ItemTypes->find($biblioitem->itemtype)->notforloan, 1, 'Biblioitem itemtype is not for loan.'); |
161 |
is(Koha::ItemTypes->find($item->itype)->notforloan, 0, 'Item itemtype is for loan.'); |
162 |
ok(!$availability->available, 'When I request availability, then the item is not available.'); |
163 |
is($availability->unavailable, 1, 'Then there is only one unavailability reason.'); |
164 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, |
165 |
"Then there is an unavailability status indicating the itemtype is not forloan."); |
166 |
}; |
167 |
}; |
168 |
|
169 |
subtest 'Given item is ordered' => \&t_ordered; |
170 |
sub t_ordered { |
171 |
plan tests => 4; |
172 |
|
173 |
my $patron = build_a_test_patron(); |
174 |
my $item = build_a_test_item()->set({notforloan=>-1})->store; |
175 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
176 |
my $expecting = 'Koha::Exceptions::Item::NotForLoan'; |
177 |
|
178 |
ok($availability->available, 'When I request availability, then the item is available.'); |
179 |
ok(!$availability->unavailable, 'Then there are no reasons for unavailability.'); |
180 |
is(ref($availability->notes->{$expecting}), $expecting, |
181 |
'Then there is an additional note indicating not for loan status.'); |
182 |
is($availability->notes->{$expecting}->code, 'Ordered', 'Not for loan code says the item is ordered.') |
183 |
}; |
184 |
|
185 |
subtest 'Given item is restricted' => \&t_restricted; |
186 |
sub t_restricted { |
187 |
plan tests => 4; |
188 |
|
189 |
my $patron = build_a_test_patron(); |
190 |
my $item = build_a_test_item()->set({restricted=>1})->store; |
191 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
192 |
my $expecting = 'Koha::Exceptions::Item::Restricted'; |
193 |
|
194 |
is($item->restricted, 1, 'When I look at the item, I see that it is restricted.'); |
195 |
ok(!$availability->available, 'When I request availability, then the item is not available.'); |
196 |
is($availability->unavailable, 1, 'Then there is only one unavailability reason.'); |
197 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, |
198 |
'Then there is an unavailability status indicating restricted item.'); |
199 |
}; |
200 |
|
201 |
subtest 'Transfer is limited' => \&t_transfer_limit; |
202 |
sub t_transfer_limit { |
203 |
plan tests => 4; |
204 |
|
205 |
t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1); |
206 |
t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype'); |
207 |
|
208 |
my $patron = build_a_test_patron(); |
209 |
my $item = build_a_test_item(); |
210 |
my $branch2 = Koha::Libraries->find($builder->build({ source => 'Branch' })->{branchcode}); |
211 |
is(C4::Circulation::CreateBranchTransferLimit( |
212 |
$branch2->branchcode, |
213 |
$item->holdingbranch, |
214 |
$item->effective_itemtype |
215 |
), 1, 'There is a branch transfer limit for itemtype from ' |
216 |
.$item->holdingbranch.' to '.$branch2->branchcode .'.'); |
217 |
my $availability = Koha::Item::Availability::Hold->new({ |
218 |
item => $item, |
219 |
patron => $patron, |
220 |
to_branch => $branch2->branchcode, |
221 |
})->in_opac; |
222 |
my $expecting = 'Koha::Exceptions::Item::CannotBeTransferred'; |
223 |
ok(!$availability->available, 'When I check availability for hold, then item' |
224 |
.' is not available'); |
225 |
is($availability->unavailable, 1, 'Then there is one reason for unavailability'); |
226 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, 'Then there' |
227 |
.' is an unavailability status indicating unability to transfer the item.'); |
228 |
}; |
229 |
|
230 |
subtest 'Given item has no barcode' => \&t_unknown_barcode; |
231 |
sub t_unknown_barcode { |
232 |
plan tests => 4; |
233 |
|
234 |
my $patron = build_a_test_patron(); |
235 |
my $item = build_a_test_item()->set({barcode=>undef})->store; |
236 |
my $expecting = 'Koha::Exceptions::Item::UnknownBarcode'; |
237 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
238 |
|
239 |
is($item->barcode, undef, 'When I look at the item, we see that it has undefined barcode.'); |
240 |
ok($availability->unavailable, 'When I request availability, then the item is not available.'); |
241 |
is($availability->unavailable, 1, 'Then there is only one unavailability reason.'); |
242 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, |
243 |
'Then there is an unavailability status indicating unknown barcode.'); |
244 |
}; |
245 |
|
246 |
subtest 'Given item is withdrawn' => \&t_withdrawn; |
247 |
sub t_withdrawn { |
248 |
plan tests => 4; |
249 |
|
250 |
my $patron = build_a_test_patron(); |
251 |
my $item = build_a_test_item()->set({restricted=>1})->store; |
252 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
253 |
my $expecting = 'Koha::Exceptions::Item::Restricted'; |
254 |
|
255 |
is($item->restricted, 1, 'When I look at the item, I see that it is restricted.'); |
256 |
ok(!$availability->available, 'When I request availability, then the item is not available.'); |
257 |
is($availability->unavailable, 1, 'Then there is only one unavailability reason.'); |
258 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, |
259 |
'Then there is an unavailability status indicating restricted item.'); |
260 |
}; |
261 |
|
262 |
subtest 'Already held' => \&t_already_held; |
263 |
sub t_already_held { |
264 |
plan tests => 8; |
265 |
|
266 |
my $patron = build_a_test_patron(); |
267 |
my $item = build_a_test_item(); |
268 |
my $reserve_id = add_item_level_hold($item, $patron, $item->homebranch); |
269 |
my $hold = Koha::Holds->find({ borrowernumber => $patron->borrowernumber }); |
270 |
Koha::IssuingRules->search->delete; |
271 |
my $rule = Koha::IssuingRule->new({ |
272 |
branchcode => $item->homebranch, |
273 |
itemtype => $item->effective_itemtype, |
274 |
categorycode => $patron->categorycode, |
275 |
holds_per_record => 9001, |
276 |
reservesallowed => 9001, |
277 |
opacitemholds => 'Y', |
278 |
})->store; |
279 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
280 |
my $expecting = 'Koha::Exceptions::Item::AlreadyHeldForThisPatron'; |
281 |
|
282 |
is($rule->reservesallowed, 9001, 'As I look at circulation rules, I can see that many reserves are allowed.'); |
283 |
ok($reserve_id, 'I have placed a hold on an item.'); |
284 |
is($hold->itemnumber, $item->itemnumber, 'The item I have hold for is the same item I will check availability for.'); |
285 |
ok(!$availability->available, 'When I request availability, then the item is not available.'); |
286 |
ok(!$availability->confirm, 'Then there is nothing to be confirmed.'); |
287 |
ok(!$availability->note, 'Then there are no additional notes.'); |
288 |
is($availability->unavailable, 1, 'Then there is only one reason for unavailability.'); |
289 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, |
290 |
'Then there is an unavailability status indicating that I have already held this.'); |
291 |
}; |
292 |
|
293 |
subtest 'Less than maxreserves' => \&t_less_than_maxreserves; |
294 |
sub t_less_than_maxreserves { |
295 |
plan tests => 5; |
296 |
|
297 |
t::lib::Mocks::mock_preference('maxreserves', 50); |
298 |
|
299 |
my $patron = build_a_test_patron(); |
300 |
my $item = build_a_test_item(); |
301 |
my $item2 = build_a_test_item(); |
302 |
my $reserve_id = add_item_level_hold($item2, $patron, $item2->homebranch); |
303 |
my $holdcount = Koha::Holds->search({ borrowernumber => $patron->borrowernumber })->count; |
304 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
305 |
|
306 |
ok(C4::Context->preference('maxreserves') > $holdcount, 'When I check my holds, I can see that I have less than maximum allowed.'); |
307 |
ok($availability->available, 'When I request availability, then the item is available.'); |
308 |
ok(!$availability->confirm, 'Then there is nothing to be confirmed.'); |
309 |
ok(!$availability->note, 'Then there are no additional notes.'); |
310 |
ok(!$availability->unavailable, 'Then there are no reasons for unavailability.'); |
311 |
}; |
312 |
|
313 |
subtest 'Equal to maxreserves' => \&t_equal_to_maxreserves; |
314 |
sub t_equal_to_maxreserves { |
315 |
plan tests => 8; |
316 |
|
317 |
t::lib::Mocks::mock_preference('maxreserves', 1); |
318 |
|
319 |
my $patron = build_a_test_patron(); |
320 |
my $item = build_a_test_item(); |
321 |
my $item2 = build_a_test_item(); |
322 |
my $reserve_id = add_item_level_hold($item2, $patron, $item2->homebranch); |
323 |
my $holdcount = Koha::Holds->search({ borrowernumber => $patron->borrowernumber })->count; |
324 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
325 |
my $expecting = 'Koha::Exceptions::Hold::MaximumHoldsReached'; |
326 |
|
327 |
ok(C4::Context->preference('maxreserves') == $holdcount, 'When I check my holds, I can see that I maximum allowed holds.'); |
328 |
ok(!$availability->available, 'When I request availability, then the item is not available.'); |
329 |
ok(!$availability->confirm, 'Then there is nothing to be confirmed.'); |
330 |
ok(!$availability->note, 'Then there are no additional notes.'); |
331 |
is($availability->unavailable, 1, 'Then there are is one reason for unavailability.'); |
332 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, 'Then there is an unavailability' |
333 |
.' status indicating maximum holds have been reached.'); |
334 |
|
335 |
my $ex = $availability->unavailabilities->{$expecting}; |
336 |
is($ex->max_holds_allowed, 1, 'Then, from the status, I can see the maximum holds allowed.'); |
337 |
is($ex->current_hold_count, 1, 'Then, from the status, I can see my current hold count.'); |
338 |
}; |
339 |
|
340 |
subtest 'More than maxreserves' => \&t_more_than_maxreserves; |
341 |
sub t_more_than_maxreserves { |
342 |
plan tests => 8; |
343 |
|
344 |
t::lib::Mocks::mock_preference('maxreserves', 1); |
345 |
|
346 |
my $patron = build_a_test_patron(); |
347 |
my $item = build_a_test_item(); |
348 |
my $item2 = build_a_test_item(); |
349 |
my $item3 = build_a_test_item(); |
350 |
my $reserve_id = add_item_level_hold($item2, $patron, $item2->homebranch); |
351 |
my $reserve_id2 = add_item_level_hold($item3, $patron, $item3->homebranch); |
352 |
my $holdcount = Koha::Holds->search({ borrowernumber => $patron->borrowernumber })->count; |
353 |
my $availability = Koha::Item::Availability::Hold->new({item => $item, patron => $patron})->in_opac; |
354 |
my $expecting = 'Koha::Exceptions::Hold::MaximumHoldsReached'; |
355 |
|
356 |
ok(C4::Context->preference('maxreserves') < $holdcount, 'When I check my holds, I can see that I have more holds than allowed. How?!'); |
357 |
ok(!$availability->available, 'When I request availability, then the item is not available.'); |
358 |
ok(!$availability->confirm, 'Then there is nothing to be confirmed.'); |
359 |
ok(!$availability->note, 'Then there are no additional notes.'); |
360 |
is($availability->unavailable, 1, 'Then there are is one reason for unavailability.'); |
361 |
is(ref($availability->unavailabilities->{$expecting}), $expecting, 'Then there is an unavailability' |
362 |
.' status indicating maximum holds have been reached.'); |
363 |
|
364 |
my $ex = $availability->unavailabilities->{$expecting}; |
365 |
is($ex->max_holds_allowed, 1, 'Then, from the status, I can see the maximum holds allowed.'); |
366 |
is($ex->current_hold_count, 2, 'Then, from the status, I can see my current hold count.'); |
367 |
}; |
368 |
|
369 |
$schema->storage->txn_rollback; |
370 |
|
371 |
1; |