Bug 16284: Add test
[koha-equinox.git] / t / db_dependent / Patron / Borrower_PrevCheckout.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
9 use Test::More tests => 60;
10
11 use_ok('Koha::Patron');
12
13 use t::lib::TestBuilder;
14 use t::lib::Mocks;
15
16 my $schema = Koha::Database->new->schema;
17 $schema->storage->txn_begin;
18
19 my $builder = t::lib::TestBuilder->new;
20 my $yesCatCode = $builder->build({
21     source => 'Category',
22     value => {
23         categorycode => 'yesCat',
24         checkprevcheckout => 'yes',
25     },
26 });
27
28 my $noCatCode = $builder->build({
29     source => 'Category',
30     value => {
31         categorycode => 'noCat',
32         checkprevcheckout => 'no',
33     },
34 });
35
36 my $inheritCatCode = $builder->build({
37     source => 'Category',
38     value => {
39         categorycode => 'inheritCat',
40         checkprevcheckout => 'inherit',
41     },
42 });
43
44 # Create context for some tests late on in the file.
45 my $library = $builder->build({ source => 'Branch' });
46 my $staff = $builder->build({source => 'Borrower'});
47
48 t::lib::Mocks::mock_userenv({ branchcode => $library->{branchcode} });
49
50 # wants_check_for_previous_checkout
51
52 # We expect the following result matrix:
53 #
54 # (1/0 indicates the return value of WantsCheckPrevCheckout; i.e. 1 says we
55 # should check whether the item was previously issued)
56 #
57 # | System Preference | hardyes                           | softyes                           | softno                            | hardno                            |
58 # |-------------------+-----------------------------------+-----------------------------------+-----------------------------------+-----------------------------------|
59 # | Category Setting  | yes       | no        | inherit   | yes       | no        | inherit   | yes       | no        | inherit   | yes       | no        | inherit   |
60 # |-------------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------|
61 # | 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 |
62 # |-------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
63 # | 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 |
64
65 my $mappings = [
66     {
67         syspref    => 'hardyes',
68         categories => [
69             {
70                 setting => 'yes',
71                 patrons => [
72                     {setting => 'yes',     result => 1},
73                     {setting => 'no',      result => 1},
74                     {setting => 'inherit', result => 1},
75                 ],
76             },
77             {
78                 setting => 'no',
79                 patrons => [
80                     {setting => 'yes',     result => 1},
81                     {setting => 'no',      result => 1},
82                     {setting => 'inherit', result => 1},
83                 ],
84             },
85             {
86                 setting => 'inherit',
87                 patrons => [
88                     {setting => 'yes',     result => 1},
89                     {setting => 'no',      result => 1},
90                     {setting => 'inherit', result => 1},
91                 ],
92             },
93         ],
94     },
95     {
96         syspref    => 'softyes',
97         categories => [
98             {
99                 setting => 'yes',
100                 patrons => [
101                     {setting => 'yes',     result => 1},
102                     {setting => 'no',      result => 0},
103                     {setting => 'inherit', result => 1},
104                 ],
105             },
106             {
107                 setting => 'no',
108                 patrons => [
109                     {setting => 'yes',     result => 1},
110                     {setting => 'no',      result => 0},
111                     {setting => 'inherit', result => 0},
112                 ],
113             },
114             {
115                 setting => 'inherit',
116                 patrons => [
117                     {setting => 'yes',     result => 1},
118                     {setting => 'no',      result => 0},
119                     {setting => 'inherit', result => 1},
120                 ],
121             },
122         ],
123     },
124     {
125         syspref    => 'softno',
126         categories => [
127             {
128                 setting => 'yes',
129                 patrons => [
130                     {setting => 'yes',     result => 1},
131                     {setting => 'no',      result => 0},
132                     {setting => 'inherit', result => 1},
133                 ],
134             },
135             {
136                 setting => 'no',
137                 patrons => [
138                     {setting => 'yes',     result => 1},
139                     {setting => 'no',      result => 0},
140                     {setting => 'inherit', result => 0},
141                 ],
142             },
143             {
144                 setting => 'inherit',
145                 patrons => [
146                     {setting => 'yes',     result => 1},
147                     {setting => 'no',      result => 0},
148                     {setting => 'inherit', result => 0},
149                 ],
150             },
151         ],
152     },
153     {
154         syspref    => 'hardno',
155         categories => [
156             {
157                 setting => 'yes',
158                 patrons => [
159                     {setting => 'yes',     result => 0},
160                     {setting => 'no',      result => 0},
161                     {setting => 'inherit', result => 0},
162                 ],
163             },
164             {
165                 setting => 'no',
166                 patrons => [
167                     {setting => 'yes',     result => 0},
168                     {setting => 'no',      result => 0},
169                     {setting => 'inherit', result => 0},
170                 ],
171             },
172             {
173                 setting => 'inherit',
174                 patrons => [
175                     {setting => 'yes',     result => 0},
176                     {setting => 'no',      result => 0},
177                     {setting => 'inherit', result => 0},
178                 ],
179             },
180         ],
181     },
182 ];
183
184 map {
185     my $syspref = $_->{syspref};
186     t::lib::Mocks::mock_preference('checkprevcheckout', $syspref);
187     map {
188         my $code = $_->{setting} . 'Cat';
189         map {
190             my $kpatron = $builder->build({
191                 source => 'Borrower',
192                 value  => {
193                     checkprevcheckout => $_->{setting},
194                     categorycode => $code,
195                 },
196             });
197             my $patron = Koha::Patrons->find($kpatron->{borrowernumber});
198             is(
199                 $patron->wants_check_for_previous_checkout, $_->{result},
200                 "Predicate with syspref " . $syspref . ", cat " . $code
201                     . ", patron " . $_->{setting}
202               );
203         } @{$_->{patrons}};
204     } @{$_->{categories}};
205 } @{$mappings};
206
207 # do_check_for_previous_checkout
208
209 # We want to test:
210 # - DESCRIPTION [RETURNVALUE (0/1)]
211 ## PreIssue (sanity checks)
212 # - Item, patron [0]
213 # - Diff item, same bib, same patron [0]
214 # - Diff item, diff bib, same patron [0]
215 # - Same item, diff patron [0]
216 # - Diff item, same bib, diff patron [0]
217 # - Diff item, diff bib, diff patron [0]
218 ## PostIssue
219 # - Same item, same patron [1]
220 # - Diff item, same bib, same patron [1]
221 # - Diff item, diff bib, same patron [0]
222 # - Same item, diff patron [0]
223 # - Diff item, same bib, diff patron [0]
224 # - Diff item, diff bib, diff patron [0]
225 ## PostReturn
226 # - Same item, same patron [1]
227 # - Diff item, same bib, same patron [1]
228 # - Diff item, diff bib, same patron [0]
229 # - Same item, diff patron [0]
230 # - Diff item, same bib, diff patron [0]
231 # - Diff item, diff bib, diff patron [0]
232
233 # Requirements:
234 # $patron, $different_patron, $items (same bib number), $different_item
235 my $patron = $builder->build({source => 'Borrower'});
236 my $patron_d = $builder->build({source => 'Borrower'});
237
238 my $biblio = $builder->build_sample_biblio;
239 $biblio->serial(0)->store;
240 my $item_1 = $builder->build({
241     source => 'Item',
242     value => { biblionumber => $biblio->biblionumber }
243 });
244 my $item_2 = $builder->build({
245     source => 'Item',
246     value => { biblionumber => $biblio->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->do_check_for_previous_checkout($_->{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 = Koha::Patrons->find( $patron->{borrowernumber} )->unblessed;
306 BAIL_OUT("Issue failed")
307     unless AddIssue($patron_get_mem, $item_1->{barcode});
308
309 # Then test:
310 my $cpvPmappings = [
311     {
312         msg => "Same item, same patron [1]",
313         item => $item_1,
314         patron => $patron,
315         result => 1,
316     },
317     {
318         msg => "Diff item, same bib, same patron [1]",
319         item => $item_2,
320         patron => $patron,
321         result => 1,
322     },
323     {
324         msg => "Diff item, diff bib, same patron [0]",
325         item => $item_d,
326         patron => $patron,
327         result => 0,
328     },
329     {
330         msg => "Same item, diff patron [0]",
331         item => $item_1,
332         patron => $patron_d,
333         result => 0,
334     },
335     {
336         msg => "Diff item, same bib, diff patron [0]",
337         item => $item_2,
338         patron => $patron_d,
339         result => 0,
340     },
341     {
342         msg => "Diff item, diff bib, diff patron [0]",
343         item => $item_d,
344         patron => $patron_d,
345         result => 0,
346     },
347 ];
348
349 test_it($cpvPmappings, "PostIssue");
350
351 # Return item_1 from patron:
352 BAIL_OUT("Return Failed") unless AddReturn($item_1->{barcode}, $patron->{branchcode});
353
354 # Then:
355 test_it($cpvPmappings, "PostReturn");
356
357 # Finally test C4::Circulation::CanBookBeIssued
358
359 # We have already tested ->wants_check_for_previous_checkout and
360 # ->do_check_for_previous_checkout, so all that remains to be tested is
361 # whetherthe different combinational outcomes of the above return values in
362 # CanBookBeIssued result in the approriate $needsconfirmation.
363
364 # We want to test:
365 # - DESCRIPTION [RETURNVALUE (0/1)]
366 # - patron, !wants_check_for_previous_checkout, !do_check_for_previous_checkout
367 #   [!$issuingimpossible,!$needsconfirmation->{PREVISSUE}]
368 # - patron, wants_check_for_previous_checkout, !do_check_for_previous_checkout
369 #   [!$issuingimpossible,!$needsconfirmation->{PREVISSUE}]
370 # - patron, !wants_check_for_previous_checkout, do_check_for_previous_checkout
371 #   [!$issuingimpossible,!$needsconfirmation->{PREVISSUE}]
372 # - patron, wants_check_for_previous_checkout, do_check_for_previous_checkout
373 #   [!$issuingimpossible,$needsconfirmation->{PREVISSUE}]
374
375 # Needs:
376 # - $patron
377 # - $item objects (one not issued, another prevIssued)
378 # - $checkprevcheckout pref (first hardno, then hardyes)
379
380 # Our Patron
381 my $patron_category = $builder->build({ source => 'Category', value => { category_type => 'P', enrolmentfee => 0 } });
382 my $CBBI_patron = $builder->build({source => 'Borrower', value => { categorycode => $patron_category->{categorycode} }});
383 $patron = Koha::Patrons->find( $CBBI_patron->{borrowernumber} );
384 # Our Items
385
386 my $new_item = $builder->build({
387     source => 'Item',
388     value => {
389         notforloan => 0,
390         withdrawn  => 0,
391         itemlost   => 0,
392         biblionumber => $builder->build( { source => 'Biblioitem' } )->{biblionumber},
393     },
394 });
395 my $prev_item = $builder->build({
396     source => 'Item',
397     value => {
398         notforloan => 0,
399         withdrawn  => 0,
400         itemlost   => 0,
401         biblionumber => $builder->build( { source => 'Biblioitem' } )->{biblionumber},
402     },
403 });
404 # Second is Checked Out
405 BAIL_OUT("CanBookBeIssued Issue failed")
406     unless AddIssue($patron->unblessed, $prev_item->{barcode});
407
408 # Mappings
409 my $CBBI_mappings = [
410     {
411         syspref => 'hardno',
412         item    => $new_item,
413         result  => undef,
414         msg     => "patron, !wants_check_for_previous_checkout, !do_check_for_previous_checkout"
415
416     },
417     {
418         syspref => 'hardyes',
419         item    => $new_item,
420         result  => undef,
421         msg     => "patron, wants_check_for_previous_checkout, !do_check_for_previous_checkout"
422     },
423     {
424         syspref => 'hardno',
425         item    => $prev_item,
426         result  => undef,
427         msg     => "patron, !wants_check_for_previous_checkout, do_check_for_previous_checkout"
428     },
429     {
430         syspref => 'hardyes',
431         item    => $prev_item,
432         result  => 1,
433         msg     => "patron, wants_check_for_previous_checkout, do_check_for_previous_checkout"
434     },
435 ];
436
437 # Tests
438 map {
439     t::lib::Mocks::mock_preference('checkprevcheckout', $_->{syspref});
440     my ( $issuingimpossible, $needsconfirmation ) =
441         C4::Circulation::CanBookBeIssued(
442             $patron, $_->{item}->{barcode}
443         );
444     is($needsconfirmation->{PREVISSUE}, $_->{result}, $_->{msg});
445 } @{$CBBI_mappings};
446
447 $schema->storage->txn_rollback;
448
449 subtest 'Check previous checkouts for serial' => sub {
450     plan tests => 2;
451     $schema->storage->txn_begin;
452
453     my $library = $builder->build_object({ class => 'Koha::Libraries'});
454
455     my $patron = $builder->build_object({
456             class => 'Koha::Patrons',
457             value => {
458                 branchcode => $library->branchcode
459             }
460         });
461     t::lib::Mocks::mock_userenv({ patron => $patron });
462
463     my $biblio = $builder->build_sample_biblio;
464     $biblio->serial(1)->store;
465
466     my $item1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
467     my $item2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
468
469     AddIssue($patron->unblessed, $item1->barcode);
470
471     is($patron->do_check_for_previous_checkout($item1->unblessed), 1, 'Check only one item if bibliographic record is serial');
472     is($patron->do_check_for_previous_checkout($item2->unblessed), 0, 'Check only one item if bibliographic record is serial');
473
474     $schema->storage->txn_rollback;
475 }