3 # This file is part of Koha.
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.
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.
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>.
20 use Test::More tests => 14;
24 use Koha::Acquisition::Orders;
26 use t::lib::TestBuilder;
30 use_ok('Koha::Biblio');
31 use_ok('Koha::Biblios');
34 my $schema = Koha::Database->new->schema;
35 my $builder = t::lib::TestBuilder->new;
37 subtest 'metadata() tests' => sub {
41 $schema->storage->txn_begin;
43 my $title = 'Oranges and Peaches';
45 my $record = MARC::Record->new();
46 my $field = MARC::Field->new('245','','','a' => $title);
47 $record->append_fields( $field );
48 my ($biblionumber) = C4::Biblio::AddBiblio($record, '');
50 my $biblio = Koha::Biblios->find( $biblionumber );
51 is( ref $biblio, 'Koha::Biblio', 'Found a Koha::Biblio object' );
53 my $metadata = $biblio->metadata;
54 is( ref $metadata, 'Koha::Biblio::Metadata', 'Method metadata() returned a Koha::Biblio::Metadata object' );
56 my $record2 = $metadata->record;
57 is( ref $record2, 'MARC::Record', 'Method record() returned a MARC::Record object' );
59 is( $record2->field('245')->subfield("a"), $title, 'Title in 245$a matches title from original record object' );
61 $schema->storage->txn_rollback;
64 subtest 'hidden_in_opac() tests' => sub {
68 $schema->storage->txn_begin;
70 my $biblio = $builder->build_sample_biblio();
71 my $rules = { withdrawn => [ 2 ] };
73 t::lib::Mocks::mock_preference( 'OpacHiddenItemsHidesRecord', 0 );
76 !$biblio->hidden_in_opac({ rules => $rules }),
77 'Biblio not hidden if there is no item attached (!OpacHiddenItemsHidesRecord)'
80 t::lib::Mocks::mock_preference( 'OpacHiddenItemsHidesRecord', 1 );
83 !$biblio->hidden_in_opac({ rules => $rules }),
84 'Biblio not hidden if there is no item attached (OpacHiddenItemsHidesRecord)'
87 my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
88 my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
90 $item_1->withdrawn( 1 )->store->discard_changes;
91 $item_2->withdrawn( 1 )->store->discard_changes;
93 ok( !$biblio->hidden_in_opac({ rules => $rules }), 'Biblio not hidden' );
95 $item_2->withdrawn( 2 )->store->discard_changes;
96 $biblio->discard_changes; # refresh
98 ok( !$biblio->hidden_in_opac({ rules => $rules }), 'Biblio not hidden' );
100 $item_1->withdrawn( 2 )->store->discard_changes;
101 $biblio->discard_changes; # refresh
103 ok( $biblio->hidden_in_opac({ rules => $rules }), 'Biblio hidden' );
105 t::lib::Mocks::mock_preference( 'OpacHiddenItemsHidesRecord', 0 );
107 !$biblio->hidden_in_opac( { rules => $rules } ),
108 'Biblio hidden (!OpacHiddenItemsHidesRecord)'
112 $schema->storage->txn_rollback;
115 subtest 'items() tests' => sub {
119 $schema->storage->txn_begin;
121 my $biblio = $builder->build_sample_biblio();
123 is( $biblio->items->count, 0, 'No items, count is 0' );
125 my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
126 my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
128 my $items = $biblio->items;
129 is( ref($items), 'Koha::Items', 'Returns a Koha::Items resultset' );
130 is( $items->count, 2, 'Two items in resultset' );
132 my @items = $biblio->items->as_list;
133 is( scalar @items, 2, 'Same result, but in list context' );
135 $schema->storage->txn_rollback;
139 subtest 'get_coins and get_openurl' => sub {
143 $schema->storage->txn_begin;
145 my $builder = t::lib::TestBuilder->new;
146 my $biblio = $builder->build_sample_biblio({
152 'ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&rft.genre=book&rft.btitle=Title%201&rft.au=Author%201',
153 'GetCOinsBiblio returned right metadata'
156 my $record = MARC::Record->new();
157 $record->append_fields( MARC::Field->new('100','','','a' => 'Author 2'), MARC::Field->new('880','','','a' => 'Something') );
158 my ( $biblionumber ) = C4::Biblio::AddBiblio($record, '');
159 my $biblio_no_title = Koha::Biblios->find($biblionumber);
161 $biblio_no_title->get_coins,
162 'ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&rft.genre=book&rft.au=Author%202',
163 'GetCOinsBiblio returned right metadata if biblio does not have a title'
166 t::lib::Mocks::mock_preference("OpenURLResolverURL", "https://koha.example.com/");
168 $biblio->get_openurl,
169 'https://koha.example.com/?ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&rft.genre=book&rft.btitle=Title%201&rft.au=Author%201',
170 'Koha::Biblio->get_openurl returned right URL'
173 t::lib::Mocks::mock_preference("OpenURLResolverURL", "https://koha.example.com/?client_id=ci1");
175 $biblio->get_openurl,
176 'https://koha.example.com/?client_id=ci1&ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&rft.genre=book&rft.btitle=Title%201&rft.au=Author%201',
177 'Koha::Biblio->get_openurl returned right URL'
180 $schema->storage->txn_rollback;
183 subtest 'is_serial() tests' => sub {
187 $schema->storage->txn_begin;
189 my $biblio = $builder->build_sample_biblio();
191 $biblio->serial( 1 )->store->discard_changes;
192 ok( $biblio->is_serial, 'Bibliographic record is serial' );
194 $biblio->serial( 0 )->store->discard_changes;
195 ok( !$biblio->is_serial, 'Bibliographic record is not serial' );
197 my $record = $biblio->metadata->record;
198 $record->leader('00142nas a22 7a 4500');
199 ModBiblio($record, $biblio->biblionumber );
200 $biblio = Koha::Biblios->find($biblio->biblionumber);
202 ok( $biblio->is_serial, 'Bibliographic record is serial' );
204 $schema->storage->txn_rollback;
207 subtest 'pickup_locations' => sub {
210 $schema->storage->txn_begin;
212 Koha::CirculationRules->search->delete;
213 Koha::CirculationRules->set_rules(
215 categorycode => undef,
219 reservesallowed => 25,
224 my $root1 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1 } } );
225 my $root2 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1 } } );
226 my $root3 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1 } } );
228 my $library1 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'zzz' } } );
229 my $library2 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'AAA' } } );
230 my $library3 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 0, branchname => 'FFF' } } );
231 my $library4 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'CCC' } } );
232 my $library5 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'eee' } } );
233 my $library6 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'BBB' } } );
234 my $library7 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'DDD' } } );
235 my $library8 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 0, branchname => 'GGG' } } );
237 our @branchcodes = map { $_->branchcode } ($library1, $library2, $library3, $library4, $library5, $library6, $library7, $library8);
239 Koha::CirculationRules->set_rules(
241 branchcode => $library1->branchcode,
244 holdallowed => 'from_home_library',
245 hold_fulfillment_policy => 'any',
246 returnbranch => 'any'
251 Koha::CirculationRules->set_rules(
253 branchcode => $library2->branchcode,
256 holdallowed => 'from_local_hold_group',
257 hold_fulfillment_policy => 'holdgroup',
258 returnbranch => 'any'
263 Koha::CirculationRules->set_rules(
265 branchcode => $library3->branchcode,
268 holdallowed => 'from_local_hold_group',
269 hold_fulfillment_policy => 'patrongroup',
270 returnbranch => 'any'
275 Koha::CirculationRules->set_rules(
277 branchcode => $library4->branchcode,
280 holdallowed => 'from_any_library',
281 hold_fulfillment_policy => 'holdingbranch',
282 returnbranch => 'any'
287 Koha::CirculationRules->set_rules(
289 branchcode => $library5->branchcode,
292 holdallowed => 'from_any_library',
293 hold_fulfillment_policy => 'homebranch',
294 returnbranch => 'any'
299 Koha::CirculationRules->set_rules(
301 branchcode => $library6->branchcode,
304 holdallowed => 'from_home_library',
305 hold_fulfillment_policy => 'holdgroup',
306 returnbranch => 'any'
311 Koha::CirculationRules->set_rules(
313 branchcode => $library7->branchcode,
316 holdallowed => 'from_local_hold_group',
317 hold_fulfillment_policy => 'holdingbranch',
318 returnbranch => 'any'
324 Koha::CirculationRules->set_rules(
326 branchcode => $library8->branchcode,
329 holdallowed => 'from_any_library',
330 hold_fulfillment_policy => 'patrongroup',
331 returnbranch => 'any'
336 my $group1_1 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root1->id, branchcode => $library1->branchcode } } );
337 my $group1_2 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root1->id, branchcode => $library2->branchcode } } );
339 my $group2_3 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root2->id, branchcode => $library3->branchcode } } );
340 my $group2_4 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root2->id, branchcode => $library4->branchcode } } );
342 my $group3_5 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library5->branchcode } } );
343 my $group3_6 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library6->branchcode } } );
344 my $group3_7 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library7->branchcode } } );
345 my $group3_8 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library8->branchcode } } );
347 my $biblio1 = $builder->build_sample_biblio({ title => '1' });
348 my $biblio2 = $builder->build_sample_biblio({ title => '2' });
350 my $item1_1 = $builder->build_sample_item({
351 biblionumber => $biblio1->biblionumber,
352 homebranch => $library1->branchcode,
353 holdingbranch => $library2->branchcode,
356 my $item1_3 = $builder->build_sample_item({
357 biblionumber => $biblio1->biblionumber,
358 homebranch => $library3->branchcode,
359 holdingbranch => $library4->branchcode,
362 my $item1_7 = $builder->build_sample_item({
363 biblionumber => $biblio1->biblionumber,
364 homebranch => $library7->branchcode,
365 holdingbranch => $library4->branchcode,
368 my $item2_2 = $builder->build_sample_item({
369 biblionumber => $biblio2->biblionumber,
370 homebranch => $library2->branchcode,
371 holdingbranch => $library1->branchcode,
374 my $item2_4 = $builder->build_sample_item({
375 biblionumber => $biblio2->biblionumber,
376 homebranch => $library4->branchcode,
377 holdingbranch => $library3->branchcode,
380 my $item2_6 = $builder->build_sample_item({
381 biblionumber => $biblio2->biblionumber,
382 homebranch => $library6->branchcode,
383 holdingbranch => $library4->branchcode,
386 my $patron1 = $builder->build_object( { class => 'Koha::Patrons', value => { firstname=>'1', branchcode => $library1->branchcode } } );
387 my $patron8 = $builder->build_object( { class => 'Koha::Patrons', value => { firstname=>'8', branchcode => $library8->branchcode } } );
390 "ItemHomeLibrary-1-1" => 6,
391 "ItemHomeLibrary-1-8" => 1,
392 "ItemHomeLibrary-2-1" => 2,
393 "ItemHomeLibrary-2-8" => 0,
394 "PatronLibrary-1-1" => 6,
395 "PatronLibrary-1-8" => 3,
396 "PatronLibrary-2-1" => 0,
397 "PatronLibrary-2-8" => 3,
401 my ( $cbranch, $biblio, $patron, $results ) = @_;
402 t::lib::Mocks::mock_preference('ReservesControlBranch', $cbranch);
405 my $pickup_location = $_;
406 grep { $pickup_location->branchcode eq $_ } @branchcodes
407 } $biblio->pickup_locations( { patron => $patron } )->as_list;
410 scalar(@pl) == $results->{ $cbranch . '-'
411 . $biblio->title . '-'
412 . $patron->firstname },
413 'ReservesControlBranch: '
420 . $results->{ $cbranch . '-'
421 . $biblio->title . '-'
422 . $patron->firstname }
428 foreach my $cbranch ('ItemHomeLibrary','PatronLibrary') {
429 foreach my $biblio ($biblio1, $biblio2) {
430 foreach my $patron ($patron1, $patron8) {
431 _doTest($cbranch, $biblio, $patron, $results);
436 my @pl_names = map { $_->branchname } $biblio1->pickup_locations( { patron => $patron1 } )->as_list;
437 my $pl_ori_str = join('|', @pl_names);
438 my $pl_sorted_str = join('|', sort { lc($a) cmp lc($b) } @pl_names);
440 $pl_ori_str eq $pl_sorted_str,
441 'Libraries must be sorted by name'
443 $schema->storage->txn_rollback;
446 subtest 'to_api() tests' => sub {
448 $schema->storage->txn_begin;
450 my $biblio = $builder->build_sample_biblio();
451 my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
453 my $biblioitem_api = $biblio->biblioitem->to_api;
454 my $biblio_api = $biblio->to_api;
456 plan tests => (scalar keys %{ $biblioitem_api }) + 1;
458 foreach my $key ( keys %{ $biblioitem_api } ) {
459 is( $biblio_api->{$key}, $biblioitem_api->{$key}, "$key is added to the biblio object" );
462 $biblio_api = $biblio->to_api({ embed => { items => {} } });
463 is_deeply( $biblio_api->{items}, [ $item->to_api ], 'Item correctly embedded' );
465 $schema->storage->txn_rollback;
468 subtest 'suggestions() tests' => sub {
472 $schema->storage->txn_begin;
474 my $biblio = $builder->build_sample_biblio();
476 is( ref($biblio->suggestions), 'Koha::Suggestions', 'Return type is correct' );
479 $biblio->suggestions->unblessed,
481 '->suggestions returns an empty Koha::Suggestions resultset'
484 my $suggestion = $builder->build_object(
486 class => 'Koha::Suggestions',
487 value => { biblionumber => $biblio->biblionumber }
491 my $suggestions = $biblio->suggestions->unblessed;
494 $biblio->suggestions->unblessed,
495 [ $suggestion->unblessed ],
496 '->suggestions returns the related Koha::Suggestion objects'
499 $schema->storage->txn_rollback;
502 subtest 'orders() and active_orders() tests' => sub {
506 $schema->storage->txn_begin;
508 my $biblio = $builder->build_sample_biblio();
510 my $orders = $biblio->orders;
511 my $active_orders = $biblio->active_orders;
513 is( ref($orders), 'Koha::Acquisition::Orders', 'Result type is correct' );
514 is( $biblio->orders->count, $biblio->active_orders->count, '->orders->count returns the count for the resultset' );
516 # Add a couple orders
518 $builder->build_object(
520 class => 'Koha::Acquisition::Orders',
522 biblionumber => $biblio->biblionumber,
523 datecancellationprinted => '2019-12-31'
529 $builder->build_object(
531 class => 'Koha::Acquisition::Orders',
533 biblionumber => $biblio->biblionumber,
534 datecancellationprinted => undef
539 $orders = $biblio->orders;
540 $active_orders = $biblio->active_orders;
542 is( ref($orders), 'Koha::Acquisition::Orders', 'Result type is correct' );
543 is( ref($active_orders), 'Koha::Acquisition::Orders', 'Result type is correct' );
544 is( $orders->count, $active_orders->count + 2, '->active_orders->count returns the rigt count' );
546 $schema->storage->txn_rollback;
549 subtest 'subscriptions() tests' => sub {
553 $schema->storage->txn_begin;
555 my $biblio = $builder->build_sample_biblio;
557 my $subscriptions = $biblio->subscriptions;
558 is( ref($subscriptions), 'Koha::Subscriptions',
559 'Koha::Biblio->subscriptions should return a Koha::Subscriptions object'
561 is( $subscriptions->count, 0, 'Koha::Biblio->subscriptions should return the correct number of subscriptions');
563 # Add two subscriptions
565 $builder->build_object(
567 class => 'Koha::Subscriptions',
568 value => { biblionumber => $biblio->biblionumber }
573 $subscriptions = $biblio->subscriptions;
574 is( ref($subscriptions), 'Koha::Subscriptions',
575 'Koha::Biblio->subscriptions should return a Koha::Subscriptions object'
577 is( $subscriptions->count, 2, 'Koha::Biblio->subscriptions should return the correct number of subscriptions');
579 $schema->storage->txn_rollback;
582 subtest 'get_marc_notes() MARC21 tests' => sub {
585 $schema->storage->txn_begin;
587 t::lib::Mocks::mock_preference( 'NotesToHide', '520' );
589 my $biblio = $builder->build_sample_biblio;
590 my $record = $biblio->metadata->record;
591 $record->append_fields(
592 MARC::Field->new( '500', '', '', a => 'Note1' ),
593 MARC::Field->new( '505', '', '', a => 'Note2', u => 'http://someserver.com' ),
594 MARC::Field->new( '520', '', '', a => 'Note3 skipped' ),
595 MARC::Field->new( '541', '0', '', a => 'Note4 skipped on opac' ),
596 MARC::Field->new( '541', '', '', a => 'Note5' ),
598 C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
599 $biblio = Koha::Biblios->find( $biblio->biblionumber);
600 my $notes = $biblio->get_marc_notes({ marcflavour => 'MARC21' });
601 is( $notes->[0]->{marcnote}, 'Note1', 'First note' );
602 is( $notes->[1]->{marcnote}, 'Note2', 'Second note' );
603 is( $notes->[2]->{marcnote}, 'http://someserver.com', 'URL separated' );
604 is( $notes->[3]->{marcnote}, 'Note4 skipped on opac',"Not shows if not opac" );
605 is( $notes->[4]->{marcnote}, 'Note5', 'Fifth note' );
606 is( @$notes, 5, 'No more notes' );
607 $notes = $biblio->get_marc_notes({ marcflavour => 'MARC21', opac => 1 });
608 is( $notes->[0]->{marcnote}, 'Note1', 'First note' );
609 is( $notes->[1]->{marcnote}, 'Note2', 'Second note' );
610 is( $notes->[2]->{marcnote}, 'http://someserver.com', 'URL separated' );
611 is( $notes->[3]->{marcnote}, 'Note5', 'Fifth note shows after fourth skipped' );
612 is( @$notes, 4, 'No more notes' );
614 $schema->storage->txn_rollback;
617 subtest 'get_marc_notes() UNIMARC tests' => sub {
620 $schema->storage->txn_begin;
622 t::lib::Mocks::mock_preference( 'NotesToHide', '310' );
624 my $biblio = $builder->build_sample_biblio;
625 my $record = $biblio->metadata->record;
626 $record->append_fields(
627 MARC::Field->new( '300', '', '', a => 'Note1' ),
628 MARC::Field->new( '300', '', '', a => 'Note2' ),
629 MARC::Field->new( '310', '', '', a => 'Note3 skipped' ),
631 C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
632 $biblio = Koha::Biblios->find( $biblio->biblionumber);
633 my $notes = $biblio->get_marc_notes({ marcflavour => 'UNIMARC' });
634 is( $notes->[0]->{marcnote}, 'Note1', 'First note' );
635 is( $notes->[1]->{marcnote}, 'Note2', 'Second note' );
636 is( @$notes, 2, 'No more notes' );
638 $schema->storage->txn_rollback;