Bug 29288: Unit tests
[koha.git] / t / db_dependent / Koha / Biblio.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 Test::More tests => 19;
21 use Test::Warn;
22
23 use C4::Biblio qw( AddBiblio ModBiblio ModBiblioMarc );
24 use C4::Circulation qw( AddIssue AddReturn );
25
26 use Koha::Database;
27 use Koha::Caches;
28 use Koha::Acquisition::Orders;
29 use Koha::AuthorisedValueCategories;
30 use Koha::AuthorisedValues;
31 use Koha::MarcSubfieldStructures;
32 use Koha::Exceptions::Exception;
33
34 use MARC::Field;
35 use MARC::Record;
36
37 use t::lib::TestBuilder;
38 use t::lib::Mocks;
39 use Test::MockModule;
40
41 BEGIN {
42     use_ok('Koha::Biblio');
43     use_ok('Koha::Biblios');
44 }
45
46 my $schema  = Koha::Database->new->schema;
47 my $builder = t::lib::TestBuilder->new;
48
49 subtest 'metadata() tests' => sub {
50
51     plan tests => 4;
52
53     $schema->storage->txn_begin;
54
55     my $title = 'Oranges and Peaches';
56
57     my $record = MARC::Record->new();
58     my $field = MARC::Field->new('245','','','a' => $title);
59     $record->append_fields( $field );
60     my ($biblionumber) = C4::Biblio::AddBiblio($record, '');
61
62     my $biblio = Koha::Biblios->find( $biblionumber );
63     is( ref $biblio, 'Koha::Biblio', 'Found a Koha::Biblio object' );
64
65     my $metadata = $biblio->metadata;
66     is( ref $metadata, 'Koha::Biblio::Metadata', 'Method metadata() returned a Koha::Biblio::Metadata object' );
67
68     my $record2 = $metadata->record;
69     is( ref $record2, 'MARC::Record', 'Method record() returned a MARC::Record object' );
70
71     is( $record2->field('245')->subfield("a"), $title, 'Title in 245$a matches title from original record object' );
72
73     $schema->storage->txn_rollback;
74 };
75
76 subtest 'hidden_in_opac() tests' => sub {
77
78     plan tests => 6;
79
80     $schema->storage->txn_begin;
81
82     my $biblio = $builder->build_sample_biblio();
83     my $rules  = { withdrawn => [ 2 ] };
84
85     t::lib::Mocks::mock_preference( 'OpacHiddenItemsHidesRecord', 0 );
86
87     ok(
88         !$biblio->hidden_in_opac({ rules => $rules }),
89         'Biblio not hidden if there is no item attached (!OpacHiddenItemsHidesRecord)'
90     );
91
92     t::lib::Mocks::mock_preference( 'OpacHiddenItemsHidesRecord', 1 );
93
94     ok(
95         !$biblio->hidden_in_opac({ rules => $rules }),
96         'Biblio not hidden if there is no item attached (OpacHiddenItemsHidesRecord)'
97     );
98
99     my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
100     my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
101
102     $item_1->withdrawn( 1 )->store->discard_changes;
103     $item_2->withdrawn( 1 )->store->discard_changes;
104
105     ok( !$biblio->hidden_in_opac({ rules => $rules }), 'Biblio not hidden' );
106
107     $item_2->withdrawn( 2 )->store->discard_changes;
108     $biblio->discard_changes; # refresh
109
110     ok( !$biblio->hidden_in_opac({ rules => $rules }), 'Biblio not hidden' );
111
112     $item_1->withdrawn( 2 )->store->discard_changes;
113     $biblio->discard_changes; # refresh
114
115     ok( $biblio->hidden_in_opac({ rules => $rules }), 'Biblio hidden' );
116
117     t::lib::Mocks::mock_preference( 'OpacHiddenItemsHidesRecord', 0 );
118     ok(
119         !$biblio->hidden_in_opac( { rules => $rules } ),
120         'Biblio hidden (!OpacHiddenItemsHidesRecord)'
121     );
122
123
124     $schema->storage->txn_rollback;
125 };
126
127 subtest 'items() tests' => sub {
128
129     plan tests => 4;
130
131     $schema->storage->txn_begin;
132
133     my $biblio = $builder->build_sample_biblio();
134
135     is( $biblio->items->count, 0, 'No items, count is 0' );
136
137     my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
138     my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
139
140     my $items = $biblio->items;
141     is( ref($items), 'Koha::Items', 'Returns a Koha::Items resultset' );
142     is( $items->count, 2, 'Two items in resultset' );
143
144     my @items = $biblio->items->as_list;
145     is( scalar @items, 2, 'Same result, but in list context' );
146
147     $schema->storage->txn_rollback;
148
149 };
150
151 subtest 'get_coins and get_openurl' => sub {
152
153     plan tests => 4;
154
155     $schema->storage->txn_begin;
156
157     my $builder = t::lib::TestBuilder->new;
158     my $biblio = $builder->build_sample_biblio({
159             title => 'Title 1',
160             author => 'Author 1'
161         });
162     is(
163         $biblio->get_coins,
164         'ctx_ver=Z39.88-2004&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&amp;rft.genre=book&amp;rft.btitle=Title%201&amp;rft.au=Author%201',
165         'GetCOinsBiblio returned right metadata'
166     );
167
168     my $record = MARC::Record->new();
169     $record->append_fields( MARC::Field->new('100','','','a' => 'Author 2'), MARC::Field->new('880','','','a' => 'Something') );
170     my ( $biblionumber ) = C4::Biblio::AddBiblio($record, '');
171     my $biblio_no_title = Koha::Biblios->find($biblionumber);
172     is(
173         $biblio_no_title->get_coins,
174         'ctx_ver=Z39.88-2004&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&amp;rft.genre=book&amp;rft.au=Author%202',
175         'GetCOinsBiblio returned right metadata if biblio does not have a title'
176     );
177
178     t::lib::Mocks::mock_preference("OpenURLResolverURL", "https://koha.example.com/");
179     is(
180         $biblio->get_openurl,
181         'https://koha.example.com/?ctx_ver=Z39.88-2004&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&amp;rft.genre=book&amp;rft.btitle=Title%201&amp;rft.au=Author%201',
182         'Koha::Biblio->get_openurl returned right URL'
183     );
184
185     t::lib::Mocks::mock_preference("OpenURLResolverURL", "https://koha.example.com/?client_id=ci1");
186     is(
187         $biblio->get_openurl,
188         'https://koha.example.com/?client_id=ci1&amp;ctx_ver=Z39.88-2004&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&amp;rft.genre=book&amp;rft.btitle=Title%201&amp;rft.au=Author%201',
189         'Koha::Biblio->get_openurl returned right URL'
190     );
191
192     $schema->storage->txn_rollback;
193 };
194
195 subtest 'is_serial() tests' => sub {
196
197     plan tests => 3;
198
199     $schema->storage->txn_begin;
200
201     my $biblio = $builder->build_sample_biblio();
202
203     $biblio->serial( 1 )->store->discard_changes;
204     ok( $biblio->is_serial, 'Bibliographic record is serial' );
205
206     $biblio->serial( 0 )->store->discard_changes;
207     ok( !$biblio->is_serial, 'Bibliographic record is not serial' );
208
209     my $record = $biblio->metadata->record;
210     $record->leader('00142nas a22     7a 4500');
211     ModBiblio($record, $biblio->biblionumber );
212     $biblio = Koha::Biblios->find($biblio->biblionumber);
213
214     ok( $biblio->is_serial, 'Bibliographic record is serial' );
215
216     $schema->storage->txn_rollback;
217 };
218
219 subtest 'pickup_locations' => sub {
220     plan tests => 9;
221
222     $schema->storage->txn_begin;
223
224     Koha::CirculationRules->search->delete;
225     Koha::CirculationRules->set_rules(
226         {
227             categorycode => undef,
228             itemtype     => undef,
229             branchcode   => undef,
230             rules        => {
231                 reservesallowed => 25,
232             }
233         }
234     );
235
236     my $root1 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1 } } );
237     my $root2 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1 } } );
238     my $root3 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1 } } );
239
240     my $library1 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'zzz' } } );
241     my $library2 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'AAA' } } );
242     my $library3 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 0, branchname => 'FFF' } } );
243     my $library4 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'CCC' } } );
244     my $library5 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'eee' } } );
245     my $library6 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'BBB' } } );
246     my $library7 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'DDD' } } );
247     my $library8 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 0, branchname => 'GGG' } } );
248
249     our @branchcodes = map { $_->branchcode } ($library1, $library2, $library3, $library4, $library5, $library6, $library7, $library8);
250
251     Koha::CirculationRules->set_rules(
252         {
253             branchcode => $library1->branchcode,
254             itemtype   => undef,
255             rules => {
256                 holdallowed => 'from_home_library',
257                 hold_fulfillment_policy => 'any',
258                 returnbranch => 'any'
259             }
260         }
261     );
262
263     Koha::CirculationRules->set_rules(
264         {
265             branchcode => $library2->branchcode,
266             itemtype   => undef,
267             rules => {
268                 holdallowed => 'from_local_hold_group',
269                 hold_fulfillment_policy => 'holdgroup',
270                 returnbranch => 'any'
271             }
272         }
273     );
274
275     Koha::CirculationRules->set_rules(
276         {
277             branchcode => $library3->branchcode,
278             itemtype   => undef,
279             rules => {
280                 holdallowed => 'from_local_hold_group',
281                 hold_fulfillment_policy => 'patrongroup',
282                 returnbranch => 'any'
283             }
284         }
285     );
286
287     Koha::CirculationRules->set_rules(
288         {
289             branchcode => $library4->branchcode,
290             itemtype   => undef,
291             rules => {
292                 holdallowed => 'from_any_library',
293                 hold_fulfillment_policy => 'holdingbranch',
294                 returnbranch => 'any'
295             }
296         }
297     );
298
299     Koha::CirculationRules->set_rules(
300         {
301             branchcode => $library5->branchcode,
302             itemtype   => undef,
303             rules => {
304                 holdallowed => 'from_any_library',
305                 hold_fulfillment_policy => 'homebranch',
306                 returnbranch => 'any'
307             }
308         }
309     );
310
311     Koha::CirculationRules->set_rules(
312         {
313             branchcode => $library6->branchcode,
314             itemtype   => undef,
315             rules => {
316                 holdallowed => 'from_home_library',
317                 hold_fulfillment_policy => 'holdgroup',
318                 returnbranch => 'any'
319             }
320         }
321     );
322
323     Koha::CirculationRules->set_rules(
324         {
325             branchcode => $library7->branchcode,
326             itemtype   => undef,
327             rules => {
328                 holdallowed => 'from_local_hold_group',
329                 hold_fulfillment_policy => 'holdingbranch',
330                 returnbranch => 'any'
331             }
332         }
333     );
334
335
336     Koha::CirculationRules->set_rules(
337         {
338             branchcode => $library8->branchcode,
339             itemtype   => undef,
340             rules => {
341                 holdallowed => 'from_any_library',
342                 hold_fulfillment_policy => 'patrongroup',
343                 returnbranch => 'any'
344             }
345         }
346     );
347
348     my $group1_1 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root1->id, branchcode => $library1->branchcode } } );
349     my $group1_2 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root1->id, branchcode => $library2->branchcode } } );
350
351     my $group2_3 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root2->id, branchcode => $library3->branchcode } } );
352     my $group2_4 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root2->id, branchcode => $library4->branchcode } } );
353
354     my $group3_5 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library5->branchcode } } );
355     my $group3_6 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library6->branchcode } } );
356     my $group3_7 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library7->branchcode } } );
357     my $group3_8 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library8->branchcode } } );
358
359     my $biblio1  = $builder->build_sample_biblio({ title => '1' });
360     my $biblio2  = $builder->build_sample_biblio({ title => '2' });
361
362     my $item1_1  = $builder->build_sample_item({
363         biblionumber     => $biblio1->biblionumber,
364         homebranch       => $library1->branchcode,
365         holdingbranch    => $library2->branchcode,
366     })->store;
367
368     my $item1_3  = $builder->build_sample_item({
369         biblionumber     => $biblio1->biblionumber,
370         homebranch       => $library3->branchcode,
371         holdingbranch    => $library4->branchcode,
372     })->store;
373
374     my $item1_7  = $builder->build_sample_item({
375         biblionumber     => $biblio1->biblionumber,
376         homebranch       => $library7->branchcode,
377         holdingbranch    => $library4->branchcode,
378     })->store;
379
380     my $item2_2  = $builder->build_sample_item({
381         biblionumber     => $biblio2->biblionumber,
382         homebranch       => $library2->branchcode,
383         holdingbranch    => $library1->branchcode,
384     })->store;
385
386     my $item2_4  = $builder->build_sample_item({
387         biblionumber     => $biblio2->biblionumber,
388         homebranch       => $library4->branchcode,
389         holdingbranch    => $library3->branchcode,
390     })->store;
391
392     my $item2_6  = $builder->build_sample_item({
393         biblionumber     => $biblio2->biblionumber,
394         homebranch       => $library6->branchcode,
395         holdingbranch    => $library4->branchcode,
396     })->store;
397
398     my $patron1 = $builder->build_object( { class => 'Koha::Patrons', value => { firstname=>'1', branchcode => $library1->branchcode } } );
399     my $patron8 = $builder->build_object( { class => 'Koha::Patrons', value => { firstname=>'8', branchcode => $library8->branchcode } } );
400
401     my $results = {
402         "ItemHomeLibrary-1-1" => 6,
403         "ItemHomeLibrary-1-8" => 1,
404         "ItemHomeLibrary-2-1" => 2,
405         "ItemHomeLibrary-2-8" => 0,
406         "PatronLibrary-1-1" => 6,
407         "PatronLibrary-1-8" => 3,
408         "PatronLibrary-2-1" => 0,
409         "PatronLibrary-2-8" => 3,
410     };
411
412     sub _doTest {
413         my ( $cbranch, $biblio, $patron, $results ) = @_;
414         t::lib::Mocks::mock_preference('ReservesControlBranch', $cbranch);
415
416         my @pl = map {
417             my $pickup_location = $_;
418             grep { $pickup_location->branchcode eq $_ } @branchcodes
419         } $biblio->pickup_locations( { patron => $patron } )->as_list;
420
421         ok(
422             scalar(@pl) == $results->{ $cbranch . '-'
423                   . $biblio->title . '-'
424                   . $patron->firstname },
425             'ReservesControlBranch: '
426               . $cbranch
427               . ', biblio'
428               . $biblio->title
429               . ', patron'
430               . $patron->firstname
431               . ' should return '
432               . $results->{ $cbranch . '-'
433                   . $biblio->title . '-'
434                   . $patron->firstname }
435               . ' but returns '
436               . scalar(@pl)
437         );
438     }
439
440     foreach my $cbranch ('ItemHomeLibrary','PatronLibrary') {
441         foreach my $biblio ($biblio1, $biblio2) {
442             foreach my $patron ($patron1, $patron8) {
443                 _doTest($cbranch, $biblio, $patron, $results);
444             }
445         }
446     }
447
448     my @pl_names = map { $_->branchname } $biblio1->pickup_locations( { patron => $patron1 } )->as_list;
449     my $pl_ori_str = join('|', @pl_names);
450     my $pl_sorted_str = join('|', sort { lc($a) cmp lc($b) } @pl_names);
451     ok(
452         $pl_ori_str eq $pl_sorted_str,
453         'Libraries must be sorted by name'
454     );
455     $schema->storage->txn_rollback;
456 };
457
458 subtest 'to_api() tests' => sub {
459
460     $schema->storage->txn_begin;
461
462     my $biblio = $builder->build_sample_biblio();
463     my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
464
465     my $biblioitem_api = $biblio->biblioitem->to_api;
466     my $biblio_api     = $biblio->to_api;
467
468     plan tests => (scalar keys %{ $biblioitem_api }) + 1;
469
470     foreach my $key ( keys %{ $biblioitem_api } ) {
471         is( $biblio_api->{$key}, $biblioitem_api->{$key}, "$key is added to the biblio object" );
472     }
473
474     $biblio_api = $biblio->to_api({ embed => { items => {} } });
475     is_deeply( $biblio_api->{items}, [ $item->to_api ], 'Item correctly embedded' );
476
477     $schema->storage->txn_rollback;
478 };
479
480 subtest 'suggestions() tests' => sub {
481
482     plan tests => 3;
483
484     $schema->storage->txn_begin;
485
486     my $biblio     = $builder->build_sample_biblio();
487
488     is( ref($biblio->suggestions), 'Koha::Suggestions', 'Return type is correct' );
489
490     is_deeply(
491         $biblio->suggestions->unblessed,
492         [],
493         '->suggestions returns an empty Koha::Suggestions resultset'
494     );
495
496     my $suggestion = $builder->build_object(
497         {
498             class => 'Koha::Suggestions',
499             value => { biblionumber => $biblio->biblionumber }
500         }
501     );
502
503     my $suggestions = $biblio->suggestions->unblessed;
504
505     is_deeply(
506         $biblio->suggestions->unblessed,
507         [ $suggestion->unblessed ],
508         '->suggestions returns the related Koha::Suggestion objects'
509     );
510
511     $schema->storage->txn_rollback;
512 };
513
514 subtest 'get_marc_components() tests' => sub {
515
516     plan tests => 5;
517
518     $schema->storage->txn_begin;
519
520     my ($host_bibnum) = C4::Biblio::AddBiblio(host_record(), '');
521     my $host_biblio = Koha::Biblios->find($host_bibnum);
522     t::lib::Mocks::mock_preference( 'SearchEngine', 'Zebra' );
523     my $search_mod = Test::MockModule->new( 'Koha::SearchEngine::Zebra::Search' );
524     $search_mod->mock( 'simple_search_compat', \&search_component_record2 );
525
526     my $components = $host_biblio->get_marc_components;
527     is( ref($components), 'ARRAY', 'Return type is correct' );
528
529     is_deeply(
530         $components,
531         [],
532         '->get_marc_components returns an empty ARRAY'
533     );
534
535     $search_mod->unmock( 'simple_search_compat');
536     $search_mod->mock( 'simple_search_compat', \&search_component_record1 );
537     my $component_record = component_record1()->as_xml();
538
539     is_deeply(
540         $host_biblio->get_marc_components,
541         [$component_record],
542         '->get_marc_components returns the related component part record'
543     );
544     $search_mod->unmock( 'simple_search_compat');
545
546     $search_mod->mock( 'simple_search_compat',
547         sub { Koha::Exceptions::Exception->throw("error searching analytics") }
548     );
549     warning_like { $components = $host_biblio->get_marc_components }
550         qr{^Warning from simple_search_compat: 'error searching analytics'};
551
552     is_deeply(
553         $host_biblio->messages,
554         [
555             {
556                 type    => 'error',
557                 message => 'component_search',
558                 payload => "error searching analytics"
559             }
560         ]
561     );
562     $search_mod->unmock( 'simple_search_compat');
563
564     $schema->storage->txn_rollback;
565 };
566
567 subtest 'get_components_query' => sub {
568     plan tests => 3;
569
570     my $biblio = $builder->build_sample_biblio();
571     my $biblionumber = $biblio->biblionumber;
572     my $record = $biblio->metadata->record;
573
574     t::lib::Mocks::mock_preference( 'UseControlNumber', '0' );
575     is($biblio->get_components_query, "Host-item:(Some boring read)", "UseControlNumber disabled");
576
577     t::lib::Mocks::mock_preference( 'UseControlNumber', '1' );
578     my $marc_001_field = MARC::Field->new('001', $biblionumber);
579     $record->append_fields($marc_001_field);
580     C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
581     $biblio = Koha::Biblios->find( $biblio->biblionumber);
582
583     is($biblio->get_components_query, "(rcn:$biblionumber AND (bib-level:a OR bib-level:b))", "UseControlNumber enabled without MarcOrgCode");
584
585     my $marc_003_field = MARC::Field->new('003', 'OSt');
586     $record->append_fields($marc_003_field);
587     C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
588     $biblio = Koha::Biblios->find( $biblio->biblionumber);
589
590     is($biblio->get_components_query, "(((rcn:$biblionumber AND cni:OSt) OR rcn:\"OSt $biblionumber\") AND (bib-level:a OR bib-level:b))", "UseControlNumber enabled with MarcOrgCode");
591 };
592
593 subtest 'orders() and active_orders() tests' => sub {
594
595     plan tests => 5;
596
597     $schema->storage->txn_begin;
598
599     my $biblio = $builder->build_sample_biblio();
600
601     my $orders        = $biblio->orders;
602     my $active_orders = $biblio->active_orders;
603
604     is( ref($orders), 'Koha::Acquisition::Orders', 'Result type is correct' );
605     is( $biblio->orders->count, $biblio->active_orders->count, '->orders->count returns the count for the resultset' );
606
607     # Add a couple orders
608     foreach (1..2) {
609         $builder->build_object(
610             {
611                 class => 'Koha::Acquisition::Orders',
612                 value => {
613                     biblionumber => $biblio->biblionumber,
614                     datecancellationprinted => '2019-12-31'
615                 }
616             }
617         );
618     }
619
620     $builder->build_object(
621         {
622             class => 'Koha::Acquisition::Orders',
623             value => {
624                 biblionumber => $biblio->biblionumber,
625                 datecancellationprinted => undef
626             }
627         }
628     );
629
630     $orders = $biblio->orders;
631     $active_orders = $biblio->active_orders;
632
633     is( ref($orders), 'Koha::Acquisition::Orders', 'Result type is correct' );
634     is( ref($active_orders), 'Koha::Acquisition::Orders', 'Result type is correct' );
635     is( $orders->count, $active_orders->count + 2, '->active_orders->count returns the rigt count' );
636
637     $schema->storage->txn_rollback;
638 };
639
640 subtest 'subscriptions() tests' => sub {
641
642     plan tests => 4;
643
644     $schema->storage->txn_begin;
645
646     my $biblio = $builder->build_sample_biblio;
647
648     my $subscriptions = $biblio->subscriptions;
649     is( ref($subscriptions), 'Koha::Subscriptions',
650         'Koha::Biblio->subscriptions should return a Koha::Subscriptions object'
651     );
652     is( $subscriptions->count, 0, 'Koha::Biblio->subscriptions should return the correct number of subscriptions');
653
654     # Add two subscriptions
655     foreach (1..2) {
656         $builder->build_object(
657             {
658                 class => 'Koha::Subscriptions',
659                 value => { biblionumber => $biblio->biblionumber }
660             }
661         );
662     }
663
664     $subscriptions = $biblio->subscriptions;
665     is( ref($subscriptions), 'Koha::Subscriptions',
666         'Koha::Biblio->subscriptions should return a Koha::Subscriptions object'
667     );
668     is( $subscriptions->count, 2, 'Koha::Biblio->subscriptions should return the correct number of subscriptions');
669
670     $schema->storage->txn_rollback;
671 };
672
673 subtest 'get_marc_notes() MARC21 tests' => sub {
674     plan tests => 13;
675
676     $schema->storage->txn_begin;
677
678     t::lib::Mocks::mock_preference( 'NotesToHide', '520' );
679
680     my $biblio = $builder->build_sample_biblio;
681     my $record = $biblio->metadata->record;
682     $record->append_fields(
683         MARC::Field->new( '500', '', '', a => 'Note1' ),
684         MARC::Field->new( '505', '', '', a => 'Note2', u => 'http://someserver.com' ),
685         MARC::Field->new( '520', '', '', a => 'Note3 skipped' ),
686         MARC::Field->new( '541', '0', '', a => 'Note4 skipped on opac' ),
687         MARC::Field->new( '541', '', '', a => 'Note5' ),
688         MARC::Field->new( '590', '', '', a => 'CODE' ),
689     );
690
691     Koha::AuthorisedValueCategory->new({ category_name => 'TEST' })->store;
692     Koha::AuthorisedValue->new({ category => 'TEST', authorised_value => 'CODE', lib => 'Description should show', lib_opac => 'Description should show OPAC' })->store;
693     my $mss = Koha::MarcSubfieldStructures->find({tagfield => "590", tagsubfield => "a", frameworkcode => $biblio->frameworkcode });
694     $mss->update({ authorised_value => "TEST" });
695
696     my $cache = Koha::Caches->get_instance;
697     $cache->clear_from_cache("MarcStructure-0-");
698     $cache->clear_from_cache("MarcStructure-1-");
699     $cache->clear_from_cache("default_value_for_mod_marc-");
700     $cache->clear_from_cache("MarcSubfieldStructure-");
701
702     C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
703     $biblio = Koha::Biblios->find( $biblio->biblionumber);
704
705     my $notes = $biblio->get_marc_notes({ marcflavour => 'MARC21' });
706     is( $notes->[0]->{marcnote}, 'Note1', 'First note' );
707     is( $notes->[1]->{marcnote}, 'Note2', 'Second note' );
708     is( $notes->[2]->{marcnote}, 'http://someserver.com', 'URL separated' );
709     is( $notes->[3]->{marcnote}, 'Note4 skipped on opac',"Not shows if not opac" );
710     is( $notes->[4]->{marcnote}, 'Note5', 'Fifth note' );
711     is( $notes->[5]->{marcnote}, 'Description should show', 'Authorised value is correctly parsed to show description rather than code' );
712     is( @$notes, 6, 'No more notes' );
713     $notes = $biblio->get_marc_notes({ marcflavour => 'MARC21', opac => 1 });
714     is( $notes->[0]->{marcnote}, 'Note1', 'First note' );
715     is( $notes->[1]->{marcnote}, 'Note2', 'Second note' );
716     is( $notes->[2]->{marcnote}, 'http://someserver.com', 'URL separated' );
717     is( $notes->[3]->{marcnote}, 'Note5', 'Fifth note shows after fourth skipped' );
718     is( $notes->[4]->{marcnote}, 'Description should show OPAC', 'Authorised value is correctly parsed for OPAC to show description rather than code' );
719     is( @$notes, 5, 'No more notes' );
720
721     $cache->clear_from_cache("MarcStructure-0-");
722     $cache->clear_from_cache("MarcStructure-1-");
723     $cache->clear_from_cache("default_value_for_mod_marc-");
724     $cache->clear_from_cache("MarcSubfieldStructure-");
725
726     $schema->storage->txn_rollback;
727 };
728
729 subtest 'get_marc_notes() UNIMARC tests' => sub {
730     plan tests => 3;
731
732     $schema->storage->txn_begin;
733
734     t::lib::Mocks::mock_preference( 'NotesToHide', '310' );
735
736     my $biblio = $builder->build_sample_biblio;
737     my $record = $biblio->metadata->record;
738     $record->append_fields(
739         MARC::Field->new( '300', '', '', a => 'Note1' ),
740         MARC::Field->new( '300', '', '', a => 'Note2' ),
741         MARC::Field->new( '310', '', '', a => 'Note3 skipped' ),
742     );
743     C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
744     $biblio = Koha::Biblios->find( $biblio->biblionumber);
745     my $notes = $biblio->get_marc_notes({ marcflavour => 'UNIMARC' });
746     is( $notes->[0]->{marcnote}, 'Note1', 'First note' );
747     is( $notes->[1]->{marcnote}, 'Note2', 'Second note' );
748     is( @$notes, 2, 'No more notes' );
749
750     $schema->storage->txn_rollback;
751 };
752
753 subtest 'host_items() tests' => sub {
754     plan tests => 6;
755
756     $schema->storage->txn_begin;
757
758     my $biblio = $builder->build_sample_biblio( { frameworkcode => '' } );
759
760     t::lib::Mocks::mock_preference( 'EasyAnalyticalRecords', 1 );
761     my $host_items = $biblio->host_items;
762     is( ref($host_items),   'Koha::Items' );
763     is( $host_items->count, 0 );
764
765     my $item_1 =
766       $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
767     my $host_item_1 = $builder->build_sample_item;
768     my $host_item_2 = $builder->build_sample_item;
769
770     my $record = $biblio->metadata->record;
771     $record->append_fields(
772         MARC::Field->new(
773             '773', '', '',
774             9 => $host_item_1->itemnumber,
775             9 => $host_item_2->itemnumber
776         ),
777     );
778     C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
779     $biblio = $biblio->get_from_storage;
780     $host_items = $biblio->host_items;
781     is( $host_items->count, 2 );
782     is_deeply( [ $host_items->get_column('itemnumber') ],
783         [ $host_item_1->itemnumber, $host_item_2->itemnumber ] );
784
785     t::lib::Mocks::mock_preference( 'EasyAnalyticalRecords', 0 );
786     $host_items = $biblio->host_items;
787     is( ref($host_items),   'Koha::Items' );
788     is( $host_items->count, 0 );
789
790     $schema->storage->txn_rollback;
791 };
792
793 subtest 'article_requests() tests' => sub {
794
795     plan tests => 3;
796
797     $schema->storage->txn_begin;
798
799     my $item   = $builder->build_sample_item;
800     my $biblio = $item->biblio;
801
802     my $article_requests = $biblio->article_requests;
803     is( ref($article_requests), 'Koha::ArticleRequests',
804         'In scalar context, type is correct' );
805     is( $article_requests->count, 0, 'No article requests' );
806
807     foreach my $i ( 0 .. 3 ) {
808
809         my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
810
811         Koha::ArticleRequest->new(
812             {
813                 borrowernumber => $patron->id,
814                 biblionumber   => $biblio->id,
815                 itemnumber     => $item->id,
816                 title          => $biblio->title,
817             }
818         )->request;
819     }
820
821     $article_requests = $biblio->article_requests;
822     is( $article_requests->count, 4, '4 article requests' );
823
824     $schema->storage->txn_rollback;
825 };
826
827 subtest 'current_checkouts() and old_checkouts() tests' => sub {
828
829     plan tests => 4;
830
831     $schema->storage->txn_begin;
832
833     my $library = $builder->build_object({ class => 'Koha::Libraries' });
834
835     my $patron_1 = $builder->build_object({ class => 'Koha::Patrons' })->unblessed;
836     my $patron_2 = $builder->build_object({ class => 'Koha::Patrons' })->unblessed;
837
838     my $item_1 = $builder->build_sample_item;
839     my $item_2 = $builder->build_sample_item({ biblionumber => $item_1->biblionumber });
840
841     t::lib::Mocks::mock_userenv({ branchcode => $library->id });
842
843     AddIssue( $patron_1, $item_1->barcode );
844     AddIssue( $patron_1, $item_2->barcode );
845
846     AddReturn( $item_1->barcode );
847     AddIssue( $patron_2, $item_1->barcode );
848
849     my $biblio = $item_1->biblio;
850     my $current_checkouts = $biblio->current_checkouts;
851     my $old_checkouts = $biblio->old_checkouts;
852
853     is( ref($current_checkouts), 'Koha::Checkouts', 'Type is correct' );
854     is( ref($old_checkouts), 'Koha::Old::Checkouts', 'Type is correct' );
855
856     is( $current_checkouts->count, 2, 'Count is correct for current checkouts' );
857     is( $old_checkouts->count, 1, 'Count is correct for old checkouts' );
858
859     $schema->storage->txn_rollback;
860 };
861
862 sub component_record1 {
863     my $marc = MARC::Record->new;
864     $marc->append_fields(
865         MARC::Field->new( '001', '3456' ),
866         MARC::Field->new( '245', '', '', a => 'Some title 1' ),
867         MARC::Field->new( '773', '', '', w => '(FIRST)1234' ),
868     );
869     return $marc;
870 }
871 sub search_component_record1 {
872     my @results = ( component_record1()->as_xml() );
873     return ( undef, \@results, 1 );
874 }
875
876 sub search_component_record2 {
877     my @results;
878     return ( undef, \@results, 0 );
879 }
880
881 sub host_record {
882     my $marc = MARC::Record->new;
883     $marc->append_fields(
884         MARC::Field->new( '001', '1234' ),
885         MARC::Field->new( '003', 'FIRST' ),
886         MARC::Field->new( '245', '', '', a => 'Some title' ),
887     );
888     return $marc;
889 }