Bug 17829: Move GetMember to Koha::Patron
[koha.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 => 59;
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 my @USERENV = (
48     $staff->{borrowernumber}, 'test', 'MASTERTEST', 'firstname', $library->{branchcode},
49     $library->{branchcode}, '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 # wants_check_for_previous_checkout
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->wants_check_for_previous_checkout, $_->{result},
206                 "Predicate with syspref " . $syspref . ", cat " . $code
207                     . ", patron " . $_->{setting}
208               );
209         } @{$_->{patrons}};
210     } @{$_->{categories}};
211 } @{$mappings};
212
213 # do_check_for_previous_checkout
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->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 $CBBI_patron = $builder->build({source => 'Borrower'});
382 $patron = Koha::Patrons->find( $CBBI_patron->{borrowernumber} )->unblessed;
383 # Our Items
384 my $new_item = $builder->build({
385     source => 'Item',
386     value => {
387         notforloan => 0,
388         withdrawn  => 0,
389         itemlost   => 0,
390     },
391 });
392 my $prev_item = $builder->build({
393     source => 'Item',
394     value => {
395         notforloan => 0,
396         withdrawn  => 0,
397         itemlost   => 0,
398     },
399 });
400 # Second is Checked Out
401 BAIL_OUT("CanBookBeIssued Issue failed")
402     unless AddIssue($patron, $prev_item->{barcode});
403
404 # Mappings
405 my $CBBI_mappings = [
406     {
407         syspref => 'hardno',
408         item    => $new_item,
409         result  => undef,
410         msg     => "patron, !wants_check_for_previous_checkout, !do_check_for_previous_checkout"
411
412     },
413     {
414         syspref => 'hardyes',
415         item    => $new_item,
416         result  => undef,
417         msg     => "patron, wants_check_for_previous_checkout, !do_check_for_previous_checkout"
418     },
419     {
420         syspref => 'hardno',
421         item    => $prev_item,
422         result  => undef,
423         msg     => "patron, !wants_check_for_previous_checkout, do_check_for_previous_checkout"
424     },
425     {
426         syspref => 'hardyes',
427         item    => $prev_item,
428         result  => 1,
429         msg     => "patron, wants_check_for_previous_checkout, do_check_for_previous_checkout"
430     },
431 ];
432
433 # Tests
434 map {
435     t::lib::Mocks::mock_preference('checkprevcheckout', $_->{syspref});
436     my ( $issuingimpossible, $needsconfirmation ) =
437         C4::Circulation::CanBookBeIssued(
438             $patron, $_->{item}->{barcode}
439         );
440     is($needsconfirmation->{PREVISSUE}, $_->{result}, $_->{msg});
441 } @{$CBBI_mappings};
442
443 $schema->storage->txn_rollback;
444
445 1;