Bug 20772: (follow-up) Add unit test
[srvgit] / t / db_dependent / Illrequests.t
1 #!/usr/bin/perl
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20 use File::Basename qw/basename/;
21 use Koha::Database;
22 use Koha::Illrequestattributes;
23 use Koha::Illrequest::Config;
24 use Koha::Patrons;
25 use t::lib::Mocks;
26 use t::lib::TestBuilder;
27 use Test::MockObject;
28 use Test::MockModule;
29 use Test::Exception;
30
31 use Test::More tests => 11;
32
33 my $schema = Koha::Database->new->schema;
34 my $builder = t::lib::TestBuilder->new;
35 use_ok('Koha::Illrequest');
36 use_ok('Koha::Illrequests');
37
38 subtest 'Basic object tests' => sub {
39
40     plan tests => 22;
41
42     $schema->storage->txn_begin;
43
44     Koha::Illrequests->search->delete;
45     my $illrq = $builder->build({ source => 'Illrequest' });
46     my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id});
47
48     isa_ok($illrq_obj, 'Koha::Illrequest',
49            "Correctly create and load an illrequest object.");
50     isa_ok($illrq_obj->_config, 'Koha::Illrequest::Config',
51            "Created a config object as part of Illrequest creation.");
52
53     is($illrq_obj->illrequest_id, $illrq->{illrequest_id},
54        "Illrequest_id getter works.");
55     is($illrq_obj->borrowernumber, $illrq->{borrowernumber},
56        "Borrowernumber getter works.");
57     is($illrq_obj->biblio_id, $illrq->{biblio_id},
58        "Biblio_Id getter works.");
59     is($illrq_obj->branchcode, $illrq->{branchcode},
60        "Branchcode getter works.");
61     is($illrq_obj->status, $illrq->{status},
62        "Status getter works.");
63     is($illrq_obj->placed, $illrq->{placed},
64        "Placed getter works.");
65     is($illrq_obj->replied, $illrq->{replied},
66        "Replied getter works.");
67     is($illrq_obj->updated, $illrq->{updated},
68        "Updated getter works.");
69     is($illrq_obj->completed, $illrq->{completed},
70        "Completed getter works.");
71     is($illrq_obj->medium, $illrq->{medium},
72        "Medium getter works.");
73     is($illrq_obj->accessurl, $illrq->{accessurl},
74        "Accessurl getter works.");
75     is($illrq_obj->cost, $illrq->{cost},
76        "Cost getter works.");
77     is($illrq_obj->price_paid, $illrq->{price_paid},
78        "Price_paid getter works.");
79     is($illrq_obj->notesopac, $illrq->{notesopac},
80        "Notesopac getter works.");
81     is($illrq_obj->notesstaff, $illrq->{notesstaff},
82        "Notesstaff getter works.");
83     is($illrq_obj->orderid, $illrq->{orderid},
84        "Orderid getter works.");
85     is($illrq_obj->backend, $illrq->{backend},
86        "Backend getter works.");
87
88     isnt($illrq_obj->status, 'COMP',
89          "ILL is not currently marked complete.");
90     $illrq_obj->mark_completed;
91     is($illrq_obj->status, 'COMP',
92        "ILL is now marked complete.");
93
94     $illrq_obj->delete;
95
96     is(Koha::Illrequests->search->count, 0,
97        "No illrequest found after delete.");
98
99     $schema->storage->txn_rollback;
100 };
101
102 subtest 'Working with related objects' => sub {
103
104     plan tests => 5;
105
106     $schema->storage->txn_begin;
107
108     Koha::Illrequests->search->delete;
109
110     my $patron = $builder->build({ source => 'Borrower' });
111     my $illrq = $builder->build({
112         source => 'Illrequest',
113         value => { borrowernumber => $patron->{borrowernumber} }
114     });
115     my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id});
116
117     isa_ok($illrq_obj->patron, 'Koha::Patron',
118            "OK accessing related patron.");
119
120     $builder->build({
121         source => 'Illrequestattribute',
122         value  => { illrequest_id => $illrq_obj->illrequest_id, type => 'X' }
123     });
124     $builder->build({
125         source => 'Illrequestattribute',
126         value  => { illrequest_id => $illrq_obj->illrequest_id, type => 'Y' }
127     });
128     $builder->build({
129         source => 'Illrequestattribute',
130         value  => { illrequest_id => $illrq_obj->illrequest_id, type => 'Z' }
131     });
132
133     is($illrq_obj->illrequestattributes->count, Koha::Illrequestattributes->search->count,
134        "Fetching expected number of Illrequestattributes for our request.");
135
136     my $illrq1 = $builder->build({ source => 'Illrequest' });
137     $builder->build({
138         source => 'Illrequestattribute',
139         value  => { illrequest_id => $illrq1->{illrequest_id}, type => 'X' }
140     });
141
142     is($illrq_obj->illrequestattributes->count + 1, Koha::Illrequestattributes->search->count,
143        "Fetching expected number of Illrequestattributes for our request.");
144
145     $illrq_obj->delete;
146     is(Koha::Illrequestattributes->search->count, 1,
147        "Correct number of illrequestattributes after delete.");
148
149     isa_ok(Koha::Patrons->find($patron->{borrowernumber}), 'Koha::Patron',
150            "Borrower was not deleted after illrq delete.");
151
152     $schema->storage->txn_rollback;
153 };
154
155 subtest 'Status Graph tests' => sub {
156
157     plan tests => 4;
158
159     $schema->storage->txn_begin;
160
161     my $illrq = $builder->build({source => 'Illrequest'});
162     my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id});
163
164     # _core_status_graph tests: it's just a constant, so here we just make
165     # sure it returns a hashref.
166     is(ref $illrq_obj->_core_status_graph, "HASH",
167        "_core_status_graph returns a hash.");
168
169     # _status_graph_union: let's try different merge operations.
170     # Identity operation
171     is_deeply(
172         $illrq_obj->_status_graph_union($illrq_obj->_core_status_graph, {}),
173         $illrq_obj->_core_status_graph,
174         "core_status_graph + null = core_status_graph"
175     );
176
177     # Simple addition
178     is_deeply(
179         $illrq_obj->_status_graph_union({}, $illrq_obj->_core_status_graph),
180         $illrq_obj->_core_status_graph,
181         "null + core_status_graph = core_status_graph"
182     );
183
184     # Correct merge behaviour
185     is_deeply(
186         $illrq_obj->_status_graph_union({
187             REQ => {
188                 prev_actions   => [ ],
189                 id             => 'REQ',
190                 next_actions   => [ ],
191             },
192         }, {
193             QER => {
194                 prev_actions   => [ 'REQ' ],
195                 id             => 'QER',
196                 next_actions   => [ 'REQ' ],
197             },
198         }),
199         {
200             REQ => {
201                 prev_actions   => [ 'QER' ],
202                 id             => 'REQ',
203                 next_actions   => [ 'QER' ],
204             },
205             QER => {
206                 prev_actions   => [ 'REQ' ],
207                 id             => 'QER',
208                 next_actions   => [ 'REQ' ],
209             },
210         },
211         "REQ atom + linking QER = cyclical status graph"
212     );
213
214     $schema->storage->txn_rollback;
215 };
216
217 subtest 'Backend testing (mocks)' => sub {
218
219     plan tests => 13;
220
221     $schema->storage->txn_begin;
222
223     # testing load_backend & available_backends requires that we have at least
224     # the Dummy plugin installed.  load_backend & available_backends don't
225     # currently have tests as a result.
226
227     t::lib::Mocks->mock_config('interlibrary_loans', { backend_dir => 'a_dir' }  );
228     my $backend = Test::MockObject->new;
229     $backend->set_isa('Koha::Illbackends::Mock');
230     $backend->set_always('name', 'Mock');
231
232     my $patron = $builder->build({ source => 'Borrower' });
233     my $illrq = $builder->build_object({
234         class => 'Koha::Illrequests',
235         value => { borrowernumber => $patron->{borrowernumber} }
236     });
237
238     $illrq->_backend($backend);
239
240     isa_ok($illrq->_backend, 'Koha::Illbackends::Mock',
241            "OK accessing mocked backend.");
242
243     # _backend_capability tests:
244     # We need to test whether this optional feature of a mocked backend
245     # behaves as expected.
246     # 3 scenarios: feature not implemented, feature implemented, but requested
247     # capability is not provided by backend, & feature is implemented &
248     # capability exists.  This method can be used to implement custom backend
249     # functionality, such as unmediated in the BLDSS backend (also see
250     # bugzilla 18837).
251     $backend->set_always('capabilities', undef);
252     is($illrq->_backend_capability('Test'), 0,
253        "0 returned on Mock not implementing capabilities.");
254
255     $backend->set_always('capabilities', 0);
256     is($illrq->_backend_capability('Test'), 0,
257        "0 returned on Mock not implementing Test capability.");
258
259     $backend->set_always('capabilities', sub { return 'bar'; } );
260     is($illrq->_backend_capability('Test'), 'bar',
261        "'bar' returned on Mock implementing Test capability.");
262
263     # metadata test: we need to be sure that we return the arbitrary values
264     # from the backend.
265     $backend->mock(
266         'metadata',
267         sub {
268             my ( $self, $rq ) = @_;
269             return {
270                 ID => $rq->illrequest_id,
271                 Title => $rq->patron->borrowernumber
272             }
273         }
274     );
275
276     is_deeply(
277         $illrq->metadata,
278         {
279             ID => $illrq->illrequest_id,
280             Title => $illrq->patron->borrowernumber
281         },
282         "Test metadata."
283     );
284
285     # capabilities:
286
287     # No backend graph extension
288     $backend->set_always('status_graph', {});
289     is_deeply($illrq->capabilities('COMP'),
290               {
291                   prev_actions   => [ 'REQ' ],
292                   id             => 'COMP',
293                   name           => 'Completed',
294                   ui_method_name => 'Mark completed',
295                   method         => 'mark_completed',
296                   next_actions   => [ ],
297                   ui_method_icon => 'fa-check',
298               },
299               "Dummy status graph for COMP.");
300     is($illrq->capabilities('UNKNOWN'), undef,
301        "Dummy status graph for UNKNOWN.");
302     is_deeply($illrq->capabilities(),
303               $illrq->_core_status_graph,
304               "Dummy full status graph.");
305     # Simple backend graph extension
306     $backend->set_always('status_graph',
307                          {
308                              QER => {
309                                  prev_actions   => [ 'REQ' ],
310                                  id             => 'QER',
311                                  next_actions   => [ 'REQ' ],
312                              },
313                          });
314     is_deeply($illrq->capabilities('QER'),
315               {
316                   prev_actions   => [ 'REQ' ],
317                   id             => 'QER',
318                   next_actions   => [ 'REQ' ],
319               },
320               "Simple status graph for QER.");
321     is($illrq->capabilities('UNKNOWN'), undef,
322        "Simple status graph for UNKNOWN.");
323     is_deeply($illrq->capabilities(),
324               $illrq->_status_graph_union(
325                   $illrq->_core_status_graph,
326                   {
327                       QER => {
328                           prev_actions   => [ 'REQ' ],
329                           id             => 'QER',
330                           next_actions   => [ 'REQ' ],
331                       },
332                   }
333               ),
334               "Simple full status graph.");
335
336     # custom_capability:
337
338     # No backend graph extension
339     $backend->set_always('status_graph', {});
340     is($illrq->custom_capability('unknown', {}), 0,
341        "Unknown candidate.");
342
343     # Simple backend graph extension
344     $backend->set_always('status_graph',
345                          {
346                              ID => {
347                                  prev_actions   => [ 'REQ' ],
348                                  id             => 'ID',
349                                  method         => 'identity',
350                                  next_actions   => [ 'REQ' ],
351                              },
352                          });
353     $backend->mock('identity',
354                    sub { my ( $self, $params ) = @_; return $params->{other}; });
355     is($illrq->custom_capability('identity', { test => 1, method => 'blah' })->{test}, 1,
356        "Resolve identity custom_capability");
357
358     $schema->storage->txn_rollback;
359 };
360
361
362 subtest 'Backend core methods' => sub {
363
364     plan tests => 17;
365
366     $schema->storage->txn_begin;
367
368     # Build infrastructure
369     my $backend = Test::MockObject->new;
370     $backend->set_isa('Koha::Illbackends::Mock');
371     $backend->set_always('name', 'Mock');
372
373     my $config = Test::MockObject->new;
374     $config->set_always('backend_dir', "/tmp");
375     $config->set_always('getLimitRules',
376                         { default => { count => 0, method => 'active' } });
377
378     my $illrq = $builder->build_object({
379         class => 'Koha::Illrequests',
380         value => { backend => undef }
381     });
382     $illrq->_config($config);
383
384     # Test error conditions (no backend)
385     throws_ok { $illrq->load_backend; }
386         'Koha::Exceptions::Ill::InvalidBackendId',
387         'Exception raised correctly';
388
389     throws_ok { $illrq->load_backend(''); }
390         'Koha::Exceptions::Ill::InvalidBackendId',
391         'Exception raised correctly';
392
393     # Now load the mocked backend
394     $illrq->_backend($backend);
395
396     # expandTemplate:
397     is_deeply($illrq->expandTemplate({ test => 1, method => "bar" }),
398               {
399                   test => 1,
400                   method => "bar",
401                   template => "/tmp/Mock/intra-includes/bar.inc",
402                   opac_template => "/tmp/Mock/opac-includes/bar.inc",
403               },
404               "ExpandTemplate");
405
406     # backend_create
407     # we are testing simple cases.
408     $backend->set_series('create',
409                          { stage => 'bar', method => 'create' },
410                          { stage => 'commit', method => 'create' },
411                          { stage => 'commit', method => 'create' });
412     # Test non-commit
413     is_deeply($illrq->backend_create({test => 1}),
414               {
415                   stage => 'bar', method => 'create',
416                   template => "/tmp/Mock/intra-includes/create.inc",
417                   opac_template => "/tmp/Mock/opac-includes/create.inc",
418               },
419               "Backend create: arbitrary stage.");
420     # Test commit
421     is_deeply($illrq->backend_create({test => 1}),
422               {
423                   stage => 'commit', method => 'create', permitted => 0,
424                   template => "/tmp/Mock/intra-includes/create.inc",
425                   opac_template => "/tmp/Mock/opac-includes/create.inc",
426               },
427               "Backend create: arbitrary stage, not permitted.");
428     is($illrq->status, "QUEUED", "Backend create: queued if restricted.");
429     $config->set_always('getLimitRules', {});
430     $illrq->status('NEW');
431     is_deeply($illrq->backend_create({test => 1}),
432               {
433                   stage => 'commit', method => 'create', permitted => 1,
434                   template => "/tmp/Mock/intra-includes/create.inc",
435                   opac_template => "/tmp/Mock/opac-includes/create.inc",
436               },
437               "Backend create: arbitrary stage, permitted.");
438     is($illrq->status, "NEW", "Backend create: not-queued.");
439
440     # backend_renew
441     $backend->set_series('renew', { stage => 'bar', method => 'renew' });
442     is_deeply($illrq->backend_renew({test => 1}),
443               {
444                   stage => 'bar', method => 'renew',
445                   template => "/tmp/Mock/intra-includes/renew.inc",
446                   opac_template => "/tmp/Mock/opac-includes/renew.inc",
447               },
448               "Backend renew: arbitrary stage.");
449
450     # backend_cancel
451     $backend->set_series('cancel', { stage => 'bar', method => 'cancel' });
452     is_deeply($illrq->backend_cancel({test => 1}),
453               {
454                   stage => 'bar', method => 'cancel',
455                   template => "/tmp/Mock/intra-includes/cancel.inc",
456                   opac_template => "/tmp/Mock/opac-includes/cancel.inc",
457               },
458               "Backend cancel: arbitrary stage.");
459
460     # backend_update_status
461     $backend->set_series('update_status', { stage => 'bar', method => 'update_status' });
462     is_deeply($illrq->backend_update_status({test => 1}),
463               {
464                   stage => 'bar', method => 'update_status',
465                   template => "/tmp/Mock/intra-includes/update_status.inc",
466                   opac_template => "/tmp/Mock/opac-includes/update_status.inc",
467               },
468               "Backend update_status: arbitrary stage.");
469
470     # backend_confirm
471     $backend->set_series('confirm', { stage => 'bar', method => 'confirm' });
472     is_deeply($illrq->backend_confirm({test => 1}),
473               {
474                   stage => 'bar', method => 'confirm',
475                   template => "/tmp/Mock/intra-includes/confirm.inc",
476                   opac_template => "/tmp/Mock/opac-includes/confirm.inc",
477               },
478               "Backend confirm: arbitrary stage.");
479
480     $config->set_always('partner_code', "ILLTSTLIB");
481     $backend->set_always('metadata', { Test => "Foobar" });
482     my $illbrn = $builder->build({
483         source => 'Branch',
484         value => { branchemail => "", branchreplyto => "" }
485     });
486     my $partner1 = $builder->build({
487         source => 'Borrower',
488         value => { categorycode => "ILLTSTLIB" },
489     });
490     my $partner2 = $builder->build({
491         source => 'Borrower',
492         value => { categorycode => "ILLTSTLIB" },
493     });
494     my $gen_conf = $illrq->generic_confirm({
495         current_branchcode => $illbrn->{branchcode}
496     });
497     isnt(index($gen_conf->{value}->{draft}->{body}, $backend->metadata->{Test}), -1,
498          "Generic confirm: draft contains metadata."
499     );
500     is($gen_conf->{value}->{partners}->next->borrowernumber, $partner1->{borrowernumber},
501        "Generic cofnirm: partner 1 is correct."
502     );
503     is($gen_conf->{value}->{partners}->next->borrowernumber, $partner2->{borrowernumber},
504        "Generic confirm: partner 2 is correct."
505     );
506
507     dies_ok { $illrq->generic_confirm({
508         current_branchcode => $illbrn->{branchcode},
509         stage => 'draft'
510     }) }
511         "Generic confirm: missing to dies OK.";
512
513     dies_ok { $illrq->generic_confirm({
514         current_branchcode => $illbrn->{branchcode},
515         partners => $partner1->{email},
516         stage => 'draft'
517     }) }
518         "Generic confirm: missing from dies OK.";
519
520     $schema->storage->txn_rollback;
521 };
522
523
524 subtest 'Helpers' => sub {
525
526     plan tests => 9;
527
528     $schema->storage->txn_begin;
529
530     # Build infrastructure
531     my $backend = Test::MockObject->new;
532     $backend->set_isa('Koha::Illbackends::Mock');
533     $backend->set_always('name', 'Mock');
534
535     my $config = Test::MockObject->new;
536     $config->set_always('backend_dir', "/tmp");
537
538     my $patron = $builder->build({
539         source => 'Borrower',
540         value => { categorycode => "A" }
541     });
542     my $illrq = $builder->build({
543         source => 'Illrequest',
544         value => { branchcode => "CPL", borrowernumber => $patron->{borrowernumber} }
545     });
546     my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id});
547     $illrq_obj->_config($config);
548     $illrq_obj->_backend($backend);
549
550     # getPrefix
551     $config->set_series('getPrefixes',
552                         { CPL => "TEST", TSL => "BAR", default => "DEFAULT" },
553                         { A => "ATEST", C => "CBAR", default => "DEFAULT" });
554     is($illrq_obj->getPrefix({ brw_cat => "C", branch => "CPL" }), "CBAR",
555        "getPrefix: brw_cat");
556     $config->set_series('getPrefixes',
557                         { CPL => "TEST", TSL => "BAR", default => "DEFAULT" },
558                         { A => "ATEST", C => "CBAR", default => "DEFAULT" });
559     is($illrq_obj->getPrefix({ brw_cat => "UNKNOWN", branch => "CPL" }), "TEST",
560        "getPrefix: branch");
561     $config->set_series('getPrefixes',
562                         { CPL => "TEST", TSL => "BAR", default => "DEFAULT" },
563                         { A => "ATEST", C => "CBAR", default => "DEFAULT" });
564     is($illrq_obj->getPrefix({ brw_cat => "UNKNOWN", branch => "UNKNOWN" }), "DEFAULT",
565        "getPrefix: default");
566     $config->set_always('getPrefixes', {});
567     is($illrq_obj->getPrefix({ brw_cat => "UNKNOWN", branch => "UNKNOWN" }), "",
568        "getPrefix: the empty prefix");
569
570     # id_prefix
571     $config->set_series('getPrefixes',
572                         { CPL => "TEST", TSL => "BAR", default => "DEFAULT" },
573                         { A => "ATEST", C => "CBAR", default => "DEFAULT" });
574     is($illrq_obj->id_prefix, "ATEST-", "id_prefix: brw_cat");
575     $config->set_series('getPrefixes',
576                         { CPL => "TEST", TSL => "BAR", default => "DEFAULT" },
577                         { AB => "ATEST", CD => "CBAR", default => "DEFAULT" });
578     is($illrq_obj->id_prefix, "TEST-", "id_prefix: branch");
579     $config->set_series('getPrefixes',
580                         { CPLT => "TEST", TSLT => "BAR", default => "DEFAULT" },
581                         { AB => "ATEST", CD => "CBAR", default => "DEFAULT" });
582     is($illrq_obj->id_prefix, "DEFAULT-", "id_prefix: default");
583
584     # requires_moderation
585     $illrq_obj->status('NEW')->store;
586     is($illrq_obj->requires_moderation, undef, "requires_moderation: No.");
587     $illrq_obj->status('CANCREQ')->store;
588     is($illrq_obj->requires_moderation, 'CANCREQ', "requires_moderation: Yes.");
589
590     $schema->storage->txn_rollback;
591 };
592
593
594 subtest 'Censorship' => sub {
595
596     plan tests => 2;
597
598     $schema->storage->txn_begin;
599
600     # Build infrastructure
601     my $backend = Test::MockObject->new;
602     $backend->set_isa('Koha::Illbackends::Mock');
603     $backend->set_always('name', 'Mock');
604
605     my $config = Test::MockObject->new;
606     $config->set_always('backend_dir', "/tmp");
607
608     my $illrq = $builder->build({source => 'Illrequest'});
609     my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id});
610     $illrq_obj->_config($config);
611     $illrq_obj->_backend($backend);
612
613     $config->set_always('censorship', { censor_notes_staff => 1, censor_reply_date => 0 });
614
615     my $censor_out = $illrq_obj->_censor({ foo => 'bar', baz => 564 });
616     is_deeply($censor_out, { foo => 'bar', baz => 564, display_reply_date => 1 },
617               "_censor: not OPAC, reply_date = 1");
618
619     $censor_out = $illrq_obj->_censor({ foo => 'bar', baz => 564, opac => 1 });
620     is_deeply($censor_out, {
621         foo => 'bar', baz => 564, censor_notes_staff => 1,
622         display_reply_date => 1, opac => 1
623     }, "_censor: notes_staff = 0, reply_date = 0");
624
625     $schema->storage->txn_rollback;
626 };
627
628 subtest 'Checking Limits' => sub {
629
630     plan tests => 30;
631
632     $schema->storage->txn_begin;
633
634     # Build infrastructure
635     my $backend = Test::MockObject->new;
636     $backend->set_isa('Koha::Illbackends::Mock');
637     $backend->set_always('name', 'Mock');
638
639     my $config = Test::MockObject->new;
640     $config->set_always('backend_dir', "/tmp");
641
642     my $illrq = $builder->build({source => 'Illrequest'});
643     my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id});
644     $illrq_obj->_config($config);
645     $illrq_obj->_backend($backend);
646
647     # getLimits
648     $config->set_series('getLimitRules',
649                         { CPL => { count => 1, method => 'test' } },
650                         { default => { count => 0, method => 'active' } });
651     is_deeply($illrq_obj->getLimits({ type => 'branch', value => "CPL" }),
652               { count => 1, method => 'test' },
653               "getLimits: by value.");
654     is_deeply($illrq_obj->getLimits({ type => 'branch' }),
655               { count => 0, method => 'active' },
656               "getLimits: by default.");
657     is_deeply($illrq_obj->getLimits({ type => 'branch', value => "CPL" }),
658               { count => -1, method => 'active' },
659               "getLimits: by hard-coded.");
660
661     #_limit_counter
662     is($illrq_obj->_limit_counter('annual', { branchcode => $illrq_obj->branchcode }),
663        1, "_limit_counter: Initial branch annual count.");
664     is($illrq_obj->_limit_counter('active', { branchcode => $illrq_obj->branchcode }),
665        1, "_limit_counter: Initial branch active count.");
666     is($illrq_obj->_limit_counter('annual', { borrowernumber => $illrq_obj->borrowernumber }),
667        1, "_limit_counter: Initial patron annual count.");
668     is($illrq_obj->_limit_counter('active', { borrowernumber => $illrq_obj->borrowernumber }),
669        1, "_limit_counter: Initial patron active count.");
670     $builder->build({
671         source => 'Illrequest',
672         value => {
673             branchcode => $illrq_obj->branchcode,
674             borrowernumber => $illrq_obj->borrowernumber,
675         }
676     });
677     is($illrq_obj->_limit_counter('annual', { branchcode => $illrq_obj->branchcode }),
678        2, "_limit_counter: Add a qualifying request for branch annual count.");
679     is($illrq_obj->_limit_counter('active', { branchcode => $illrq_obj->branchcode }),
680        2, "_limit_counter: Add a qualifying request for branch active count.");
681     is($illrq_obj->_limit_counter('annual', { borrowernumber => $illrq_obj->borrowernumber }),
682        2, "_limit_counter: Add a qualifying request for patron annual count.");
683     is($illrq_obj->_limit_counter('active', { borrowernumber => $illrq_obj->borrowernumber }),
684        2, "_limit_counter: Add a qualifying request for patron active count.");
685     $builder->build({
686         source => 'Illrequest',
687         value => {
688             branchcode => $illrq_obj->branchcode,
689             borrowernumber => $illrq_obj->borrowernumber,
690             placed => "2005-05-31",
691         }
692     });
693     is($illrq_obj->_limit_counter('annual', { branchcode => $illrq_obj->branchcode }),
694        2, "_limit_counter: Add an out-of-date branch request.");
695     is($illrq_obj->_limit_counter('active', { branchcode => $illrq_obj->branchcode }),
696        3, "_limit_counter: Add a qualifying request for branch active count.");
697     is($illrq_obj->_limit_counter('annual', { borrowernumber => $illrq_obj->borrowernumber }),
698        2, "_limit_counter: Add an out-of-date patron request.");
699     is($illrq_obj->_limit_counter('active', { borrowernumber => $illrq_obj->borrowernumber }),
700        3, "_limit_counter: Add a qualifying request for patron active count.");
701     $builder->build({
702         source => 'Illrequest',
703         value => {
704             branchcode => $illrq_obj->branchcode,
705             borrowernumber => $illrq_obj->borrowernumber,
706             status => "COMP",
707         }
708     });
709     is($illrq_obj->_limit_counter('annual', { branchcode => $illrq_obj->branchcode }),
710        3, "_limit_counter: Add a qualifying request for branch annual count.");
711     is($illrq_obj->_limit_counter('active', { branchcode => $illrq_obj->branchcode }),
712        3, "_limit_counter: Add a completed request for branch active count.");
713     is($illrq_obj->_limit_counter('annual', { borrowernumber => $illrq_obj->borrowernumber }),
714        3, "_limit_counter: Add a qualifying request for patron annual count.");
715     is($illrq_obj->_limit_counter('active', { borrowernumber => $illrq_obj->borrowernumber }),
716        3, "_limit_counter: Add a completed request for patron active count.");
717
718     # check_limits:
719
720     # We've tested _limit_counter, so all we need to test here is whether the
721     # current counts of 3 for each work as they should against different
722     # configuration declarations.
723
724     # No limits
725     $config->set_always('getLimitRules', undef);
726     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
727                                  librarycode => $illrq_obj->branchcode}),
728        1, "check_limits: no configuration => no limits.");
729
730     # Branch tests
731     $config->set_always('getLimitRules',
732                         { $illrq_obj->branchcode => { count => 1, method => 'active' } });
733     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
734                                  librarycode => $illrq_obj->branchcode}),
735        0, "check_limits: branch active limit exceeded.");
736     $config->set_always('getLimitRules',
737                         { $illrq_obj->branchcode => { count => 1, method => 'annual' } });
738     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
739                                  librarycode => $illrq_obj->branchcode}),
740        0, "check_limits: branch annual limit exceeded.");
741     $config->set_always('getLimitRules',
742                         { $illrq_obj->branchcode => { count => 4, method => 'active' } });
743     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
744                                  librarycode => $illrq_obj->branchcode}),
745        1, "check_limits: branch active limit OK.");
746     $config->set_always('getLimitRules',
747                         { $illrq_obj->branchcode => { count => 4, method => 'annual' } });
748     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
749                                  librarycode => $illrq_obj->branchcode}),
750        1, "check_limits: branch annual limit OK.");
751
752     # Patron tests
753     $config->set_always('getLimitRules',
754                         { $illrq_obj->patron->categorycode => { count => 1, method => 'active' } });
755     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
756                                  librarycode => $illrq_obj->branchcode}),
757        0, "check_limits: patron category active limit exceeded.");
758     $config->set_always('getLimitRules',
759                         { $illrq_obj->patron->categorycode => { count => 1, method => 'annual' } });
760     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
761                                  librarycode => $illrq_obj->branchcode}),
762        0, "check_limits: patron category annual limit exceeded.");
763     $config->set_always('getLimitRules',
764                         { $illrq_obj->patron->categorycode => { count => 4, method => 'active' } });
765     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
766                                  librarycode => $illrq_obj->branchcode}),
767        1, "check_limits: patron category active limit OK.");
768     $config->set_always('getLimitRules',
769                         { $illrq_obj->patron->categorycode => { count => 4, method => 'annual' } });
770     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
771                                  librarycode => $illrq_obj->branchcode}),
772        1, "check_limits: patron category annual limit OK.");
773
774     # One rule cancels the other
775     $config->set_series('getLimitRules',
776                         # Branch rules allow request
777                         { $illrq_obj->branchcode => { count => 4, method => 'active' } },
778                         # Patron rule forbids it
779                         { $illrq_obj->patron->categorycode => { count => 1, method => 'annual' } });
780     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
781                                  librarycode => $illrq_obj->branchcode}),
782        0, "check_limits: patron category veto overrides branch OK.");
783     $config->set_series('getLimitRules',
784                         # Branch rules allow request
785                         { $illrq_obj->branchcode => { count => 1, method => 'active' } },
786                         # Patron rule forbids it
787                         { $illrq_obj->patron->categorycode => { count => 4, method => 'annual' } });
788     is($illrq_obj->check_limits({patron => $illrq_obj->patron,
789                                  librarycode => $illrq_obj->branchcode}),
790        0, "check_limits: branch veto overrides patron category OK.");
791
792     $schema->storage->txn_rollback;
793 };
794
795 subtest 'TO_JSON() tests' => sub {
796
797     plan tests => 10;
798
799     my $illreqmodule = Test::MockModule->new('Koha::Illrequest');
800
801     # Mock ->capabilities
802     $illreqmodule->mock( 'capabilities', sub { return 'capable'; } );
803
804     # Mock ->metadata
805     $illreqmodule->mock( 'metadata', sub { return 'metawhat?'; } );
806
807     $schema->storage->txn_begin;
808
809     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
810     my $patron  = $builder->build_object( { class => 'Koha::Patrons' } );
811     my $illreq  = $builder->build_object(
812         {
813             class => 'Koha::Illrequests',
814             value => {
815                 branchcode     => $library->branchcode,
816                 borrowernumber => $patron->borrowernumber
817             }
818         }
819     );
820     my $illreq_json = $illreq->TO_JSON;
821     is( $illreq_json->{patron},
822         undef, '%embed not passed, no \'patron\' attribute' );
823     is( $illreq_json->{metadata},
824         undef, '%embed not passed, no \'metadata\' attribute' );
825     is( $illreq_json->{capabilities},
826         undef, '%embed not passed, no \'capabilities\' attribute' );
827     is( $illreq_json->{library},
828         undef, '%embed not passed, no \'library\' attribute' );
829
830     $illreq_json = $illreq->TO_JSON(
831         { patron => 1, metadata => 1, capabilities => 1, library => 1 } );
832     is( $illreq_json->{patron}->{firstname},
833         $patron->firstname,
834         '%embed passed, \'patron\' attribute correct (firstname)' );
835     is( $illreq_json->{patron}->{surname},
836         $patron->surname,
837         '%embed passed, \'patron\' attribute correct (surname)' );
838     is( $illreq_json->{patron}->{cardnumber},
839         $patron->cardnumber,
840         '%embed passed, \'patron\' attribute correct (cardnumber)' );
841     is( $illreq_json->{metadata},
842         'metawhat?', '%embed passed, \'metadata\' attribute correct' );
843     is( $illreq_json->{capabilities},
844         'capable', '%embed passed, \'capabilities\' attribute correct' );
845     is( $illreq_json->{library}->{branchcode},
846         $library->branchcode, '%embed not passed, no \'library\' attribute' );
847
848     $schema->storage->txn_rollback;
849 };