Bug 6906 - show 'Borrower has previously issued...
[koha.git] / t / db_dependent / Patron / CheckPrevCheckout.t
1 #!/usr/bin/perl
2 use Modern::Perl;
3
4 use C4::Members;
5 use C4::Circulation;
6 use Koha::Database;
7 use Koha::Patrons;
8 use Koha::Patron;
9
10 use Test::More tests => 59;
11
12 use_ok('Koha::Patron');
13
14 use t::lib::TestBuilder;
15 use t::lib::Mocks;
16
17 my $schema = Koha::Database->new->schema;
18 $schema->storage->txn_begin;
19
20 my $builder = t::lib::TestBuilder->new;
21 my $yesCatCode = $builder->build({
22     source => 'Category',
23     value => {
24         categorycode => 'yesCat',
25         checkprevcheckout => 'yes',
26     },
27 });
28
29 my $noCatCode = $builder->build({
30     source => 'Category',
31     value => {
32         categorycode => 'noCat',
33         checkprevcheckout => 'no',
34     },
35 });
36
37 my $inheritCatCode = $builder->build({
38     source => 'Category',
39     value => {
40         categorycode => 'inheritCat',
41         checkprevcheckout => 'inherit',
42     },
43 });
44
45 # Create context for some tests late on in the file.
46 my $staff = $builder->build({source => 'Borrower'});
47 my @USERENV = (
48     $staff->{borrowernumber}, 'test', 'MASTERTEST', 'firstname', 'CPL',
49     'CPL', 'email@example.org'
50 );
51 C4::Context->_new_userenv('DUMMY_SESSION_ID');
52 C4::Context->set_userenv(@USERENV);
53 BAIL_OUT("No userenv") unless C4::Context->userenv;
54
55
56 # wantsCheckPrevCheckout
57
58 # We expect the following result matrix:
59 #
60 # (1/0 indicates the return value of WantsCheckPrevCheckout; i.e. 1 says we
61 # should check whether the item was previously issued)
62 #
63 # | System Preference | hardyes                           | softyes                           | softno                            | hardno                            |
64 # |-------------------+-----------------------------------+-----------------------------------+-----------------------------------+-----------------------------------|
65 # | Category Setting  | yes       | no        | inherit   | yes       | no        | inherit   | yes       | no        | inherit   | yes       | no        | inherit   |
66 # |-------------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------|
67 # | Patron Setting    | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i |
68 # |-------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
69 # | Expected Result   | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
70
71 my $mappings = [
72     {
73         syspref    => 'hardyes',
74         categories => [
75             {
76                 setting => 'yes',
77                 patrons => [
78                     {setting => 'yes',     result => 1},
79                     {setting => 'no',      result => 1},
80                     {setting => 'inherit', result => 1},
81                 ],
82             },
83             {
84                 setting => 'no',
85                 patrons => [
86                     {setting => 'yes',     result => 1},
87                     {setting => 'no',      result => 1},
88                     {setting => 'inherit', result => 1},
89                 ],
90             },
91             {
92                 setting => 'inherit',
93                 patrons => [
94                     {setting => 'yes',     result => 1},
95                     {setting => 'no',      result => 1},
96                     {setting => 'inherit', result => 1},
97                 ],
98             },
99         ],
100     },
101     {
102         syspref    => 'softyes',
103         categories => [
104             {
105                 setting => 'yes',
106                 patrons => [
107                     {setting => 'yes',     result => 1},
108                     {setting => 'no',      result => 0},
109                     {setting => 'inherit', result => 1},
110                 ],
111             },
112             {
113                 setting => 'no',
114                 patrons => [
115                     {setting => 'yes',     result => 1},
116                     {setting => 'no',      result => 0},
117                     {setting => 'inherit', result => 0},
118                 ],
119             },
120             {
121                 setting => 'inherit',
122                 patrons => [
123                     {setting => 'yes',     result => 1},
124                     {setting => 'no',      result => 0},
125                     {setting => 'inherit', result => 1},
126                 ],
127             },
128         ],
129     },
130     {
131         syspref    => 'softno',
132         categories => [
133             {
134                 setting => 'yes',
135                 patrons => [
136                     {setting => 'yes',     result => 1},
137                     {setting => 'no',      result => 0},
138                     {setting => 'inherit', result => 1},
139                 ],
140             },
141             {
142                 setting => 'no',
143                 patrons => [
144                     {setting => 'yes',     result => 1},
145                     {setting => 'no',      result => 0},
146                     {setting => 'inherit', result => 0},
147                 ],
148             },
149             {
150                 setting => 'inherit',
151                 patrons => [
152                     {setting => 'yes',     result => 1},
153                     {setting => 'no',      result => 0},
154                     {setting => 'inherit', result => 0},
155                 ],
156             },
157         ],
158     },
159     {
160         syspref    => 'hardno',
161         categories => [
162             {
163                 setting => 'yes',
164                 patrons => [
165                     {setting => 'yes',     result => 0},
166                     {setting => 'no',      result => 0},
167                     {setting => 'inherit', result => 0},
168                 ],
169             },
170             {
171                 setting => 'no',
172                 patrons => [
173                     {setting => 'yes',     result => 0},
174                     {setting => 'no',      result => 0},
175                     {setting => 'inherit', result => 0},
176                 ],
177             },
178             {
179                 setting => 'inherit',
180                 patrons => [
181                     {setting => 'yes',     result => 0},
182                     {setting => 'no',      result => 0},
183                     {setting => 'inherit', result => 0},
184                 ],
185             },
186         ],
187     },
188 ];
189
190 map {
191     my $syspref = $_->{syspref};
192     t::lib::Mocks::mock_preference('checkprevcheckout', $syspref);
193     map {
194         my $code = $_->{setting} . 'Cat';
195         map {
196             my $kpatron = $builder->build({
197                 source => 'Borrower',
198                 value  => {
199                     checkprevcheckout => $_->{setting},
200                     categorycode => $code,
201                 },
202             });
203             my $patron = Koha::Patrons->find($kpatron->{borrowernumber});
204             is(
205                 $patron->wantsCheckPrevCheckout, $_->{result},
206                 "Predicate with syspref " . $syspref . ", cat " . $code
207                     . ", patron " . $_->{setting}
208               );
209         } @{$_->{patrons}};
210     } @{$_->{categories}};
211 } @{$mappings};
212
213 # doCheckPrevCheckout
214
215 # We want to test:
216 # - DESCRIPTION [RETURNVALUE (0/1)]
217 ## PreIssue (sanity checks)
218 # - Item, patron [0]
219 # - Diff item, same bib, same patron [0]
220 # - Diff item, diff bib, same patron [0]
221 # - Same item, diff patron [0]
222 # - Diff item, same bib, diff patron [0]
223 # - Diff item, diff bib, diff patron [0]
224 ## PostIssue
225 # - Same item, same patron [1]
226 # - Diff item, same bib, same patron [1]
227 # - Diff item, diff bib, same patron [0]
228 # - Same item, diff patron [0]
229 # - Diff item, same bib, diff patron [0]
230 # - Diff item, diff bib, diff patron [0]
231 ## PostReturn
232 # - Same item, same patron [1]
233 # - Diff item, same bib, same patron [1]
234 # - Diff item, diff bib, same patron [0]
235 # - Same item, diff patron [0]
236 # - Diff item, same bib, diff patron [0]
237 # - Diff item, diff bib, diff patron [0]
238
239 # Requirements:
240 # $patron, $different_patron, $items (same bib number), $different_item
241 my $patron = $builder->build({source => 'Borrower'});
242 my $patron_d = $builder->build({source => 'Borrower'});
243 my $item_1 = $builder->build({source => 'Item'});
244 my $item_2 = $builder->build({
245     source => 'Item',
246     value => { biblionumber => $item_1->{biblionumber} },
247 });
248 my $item_d = $builder->build({source => 'Item'});
249
250 ## Testing Sub
251 sub test_it {
252     my ($mapping, $stage) = @_;
253     map {
254         my $patron = Koha::Patrons->find($_->{patron}->{borrowernumber});
255         is(
256             $patron->doCheckPrevCheckout($_->{item}),
257             $_->{result}, $stage . ": " . $_->{msg}
258         );
259     } @{$mapping};
260 };
261
262 ## Initial Mappings
263 my $cpvmappings = [
264     {
265         msg => "Item, patron [0]",
266         item => $item_1,
267         patron => $patron,
268         result => 0,
269     },
270     {
271         msg => "Diff item, same bib, same patron [0]",
272         item => $item_2,
273         patron => $patron,
274         result => 0,
275     },
276     {
277         msg => "Diff item, diff bib, same patron [0]",
278         item => $item_d,
279         patron => $patron,
280         result => 0,
281     },
282     {
283         msg => "Same item, diff patron [0]",
284         item => $item_1,
285         patron => $patron_d,
286         result => 0,
287     },
288     {
289         msg => "Diff item, same bib, diff patron [0]",
290         item => $item_2,
291         patron => $patron_d,
292         result => 0,
293     },
294     {
295         msg => "Diff item, diff bib, diff patron [0]",
296         item => $item_d,
297         patron => $patron_d,
298         result => 0,
299     },
300 ];
301
302 test_it($cpvmappings, "PreIssue");
303
304 # Issue item_1 to $patron:
305 my $patron_get_mem =
306     GetMember(%{{borrowernumber => $patron->{borrowernumber}}});
307 BAIL_OUT("Issue failed")
308     unless AddIssue($patron_get_mem, $item_1->{barcode});
309
310 # Then test:
311 my $cpvPmappings = [
312     {
313         msg => "Same item, same patron [1]",
314         item => $item_1,
315         patron => $patron,
316         result => 1,
317     },
318     {
319         msg => "Diff item, same bib, same patron [1]",
320         item => $item_2,
321         patron => $patron,
322         result => 1,
323     },
324     {
325         msg => "Diff item, diff bib, same patron [0]",
326         item => $item_d,
327         patron => $patron,
328         result => 0,
329     },
330     {
331         msg => "Same item, diff patron [0]",
332         item => $item_1,
333         patron => $patron_d,
334         result => 0,
335     },
336     {
337         msg => "Diff item, same bib, diff patron [0]",
338         item => $item_2,
339         patron => $patron_d,
340         result => 0,
341     },
342     {
343         msg => "Diff item, diff bib, diff patron [0]",
344         item => $item_d,
345         patron => $patron_d,
346         result => 0,
347     },
348 ];
349
350 test_it($cpvPmappings, "PostIssue");
351
352 # Return item_1 from patron:
353 BAIL_OUT("Return Failed") unless AddReturn($item_1->{barcode}, $patron->{branchcode});
354
355 # Then:
356 test_it($cpvPmappings, "PostReturn");
357
358 # Finally test C4::Circulation::CanBookBeIssued
359
360 # We have already tested ->wantsCheckPrevCheckout and ->doCheckPrevCheckout,
361 # so all that remains to be tested is whetherthe different combinational
362 # outcomes of the above return values in CanBookBeIssued result in the
363 # approriate $needsconfirmation.
364
365 # We want to test:
366 # - DESCRIPTION [RETURNVALUE (0/1)]
367 # - patron, !wantsCheckPrevCheckout, !doCheckPrevCheckout
368 #   [!$issuingimpossible,!$needsconfirmation->{PREVISSUE}]
369 # - patron, wantsCheckPrevCheckout, !doCheckPrevCheckout
370 #   [!$issuingimpossible,!$needsconfirmation->{PREVISSUE}]
371 # - patron, !wantsCheckPrevCheckout, doCheckPrevCheckout
372 #   [!$issuingimpossible,!$needsconfirmation->{PREVISSUE}]
373 # - patron, wantsCheckPrevCheckout, doCheckPrevCheckout
374 #   [!$issuingimpossible,$needsconfirmation->{PREVISSUE}]
375
376 # Needs:
377 # - $patron_from_GetMember
378 # - $item objects (one not issued, another prevIssued)
379 # - $checkprevcheckout pref (first hardno, then hardyes)
380
381 # Our Patron
382 my $CBBI_patron = $builder->build({source => 'Borrower'});
383 my $p_from_GetMember =
384     GetMember(%{{borrowernumber => $CBBI_patron->{borrowernumber}}});
385 # Our Items
386 my $new_item = $builder->build({
387     source => 'Item',
388     value => {
389         notforloan => 0,
390         withdrawn  => 0,
391         itemlost   => 0,
392     },
393 });
394 my $prev_item = $builder->build({
395     source => 'Item',
396     value => {
397         notforloan => 0,
398         withdrawn  => 0,
399         itemlost   => 0,
400     },
401 });
402 # Second is Checked Out
403 BAIL_OUT("CanBookBeIssued Issue failed")
404     unless AddIssue($p_from_GetMember, $prev_item->{barcode});
405
406 # Mappings
407 my $CBBI_mappings = [
408     {
409         syspref => 'hardno',
410         item    => $new_item,
411         result  => undef,
412         msg     => "patron, !wantsCheckPrevCheckout, !doCheckPrevCheckout"
413
414     },
415     {
416         syspref => 'hardyes',
417         item    => $new_item,
418         result  => undef,
419         msg     => "patron, wantsCheckPrevCheckout, !doCheckPrevCheckout"
420     },
421     {
422         syspref => 'hardno',
423         item    => $prev_item,
424         result  => undef,
425         msg     => "patron, !wantsCheckPrevCheckout, doCheckPrevCheckout"
426     },
427     {
428         syspref => 'hardyes',
429         item    => $prev_item,
430         result  => 1,
431         msg     => "patron, wantsCheckPrevCheckout, doCheckPrevCheckout"
432     },
433 ];
434
435 # Tests
436 map {
437     t::lib::Mocks::mock_preference('checkprevcheckout', $_->{syspref});
438     my ( $issuingimpossible, $needsconfirmation ) =
439         C4::Circulation::CanBookBeIssued(
440             $p_from_GetMember, $_->{item}->{barcode}
441         );
442     is($needsconfirmation->{PREVISSUE}, $_->{result}, $_->{msg});
443 } @{$CBBI_mappings};
444
445 $schema->storage->txn_rollback;
446
447 1;