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();
72 ok( !$biblio->hidden_in_opac({ rules => { withdrawn => [ 2 ] } }), 'Biblio not hidden if there is no item attached' );
74 my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
75 my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
77 $item_1->withdrawn( 1 )->store->discard_changes;
78 $item_2->withdrawn( 1 )->store->discard_changes;
80 ok( !$biblio->hidden_in_opac({ rules => { withdrawn => [ 2 ] } }), 'Biblio not hidden' );
82 $item_2->withdrawn( 2 )->store->discard_changes;
83 $biblio->discard_changes; # refresh
85 ok( !$biblio->hidden_in_opac({ rules => { withdrawn => [ 2 ] } }), 'Biblio not hidden' );
87 $item_1->withdrawn( 2 )->store->discard_changes;
88 $biblio->discard_changes; # refresh
90 ok( $biblio->hidden_in_opac({ rules => { withdrawn => [ 2 ] } }), 'Biblio hidden' );
92 $schema->storage->txn_rollback;
95 subtest 'items() tests' => sub {
99 $schema->storage->txn_begin;
101 my $biblio = $builder->build_sample_biblio();
103 is( $biblio->items->count, 0, 'No items, count is 0' );
105 my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
106 my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
108 my $items = $biblio->items;
109 is( ref($items), 'Koha::Items', 'Returns a Koha::Items resultset' );
110 is( $items->count, 2, 'Two items in resultset' );
112 my @items = $biblio->items->as_list;
113 is( scalar @items, 2, 'Same result, but in list context' );
115 $schema->storage->txn_rollback;
119 subtest 'get_coins and get_openurl' => sub {
123 $schema->storage->txn_begin;
125 my $builder = t::lib::TestBuilder->new;
126 my $biblio = $builder->build_sample_biblio({
132 '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',
133 'GetCOinsBiblio returned right metadata'
136 my $record = MARC::Record->new();
137 $record->append_fields( MARC::Field->new('100','','','a' => 'Author 2'), MARC::Field->new('880','','','a' => 'Something') );
138 my ( $biblionumber ) = C4::Biblio::AddBiblio($record, '');
139 my $biblio_no_title = Koha::Biblios->find($biblionumber);
141 $biblio_no_title->get_coins,
142 'ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&rft.genre=book&rft.au=Author%202',
143 'GetCOinsBiblio returned right metadata if biblio does not have a title'
146 t::lib::Mocks::mock_preference("OpenURLResolverURL", "https://koha.example.com/");
148 $biblio->get_openurl,
149 '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',
150 'Koha::Biblio->get_openurl returned right URL'
153 t::lib::Mocks::mock_preference("OpenURLResolverURL", "https://koha.example.com/?client_id=ci1");
155 $biblio->get_openurl,
156 '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',
157 'Koha::Biblio->get_openurl returned right URL'
160 $schema->storage->txn_rollback;
163 subtest 'is_serial() tests' => sub {
167 $schema->storage->txn_begin;
169 my $biblio = $builder->build_sample_biblio();
171 $biblio->serial( 1 )->store->discard_changes;
172 ok( $biblio->is_serial, 'Bibliographic record is serial' );
174 $biblio->serial( 0 )->store->discard_changes;
175 ok( !$biblio->is_serial, 'Bibliographic record is not serial' );
177 my $record = $biblio->metadata->record;
178 $record->leader('00142nas a22 7a 4500');
179 ModBiblio($record, $biblio->biblionumber );
180 $biblio = Koha::Biblios->find($biblio->biblionumber);
182 ok( $biblio->is_serial, 'Bibliographic record is serial' );
184 $schema->storage->txn_rollback;
187 subtest 'pickup_locations' => sub {
190 $schema->storage->txn_begin;
192 Koha::CirculationRules->search->delete;
193 Koha::CirculationRules->set_rules(
195 categorycode => undef,
199 reservesallowed => 25,
204 my $root1 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1 } } );
205 my $root2 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1 } } );
206 my $root3 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1 } } );
208 my $library1 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'zzz' } } );
209 my $library2 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'AAA' } } );
210 my $library3 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 0, branchname => 'FFF' } } );
211 my $library4 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'CCC' } } );
212 my $library5 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'eee' } } );
213 my $library6 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'BBB' } } );
214 my $library7 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, branchname => 'DDD' } } );
215 my $library8 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 0, branchname => 'GGG' } } );
217 our @branchcodes = map { $_->branchcode } ($library1, $library2, $library3, $library4, $library5, $library6, $library7, $library8);
219 Koha::CirculationRules->set_rules(
221 branchcode => $library1->branchcode,
224 holdallowed => 'from_home_library',
225 hold_fulfillment_policy => 'any',
226 returnbranch => 'any'
231 Koha::CirculationRules->set_rules(
233 branchcode => $library2->branchcode,
236 holdallowed => 'from_local_hold_group',
237 hold_fulfillment_policy => 'holdgroup',
238 returnbranch => 'any'
243 Koha::CirculationRules->set_rules(
245 branchcode => $library3->branchcode,
248 holdallowed => 'from_local_hold_group',
249 hold_fulfillment_policy => 'patrongroup',
250 returnbranch => 'any'
255 Koha::CirculationRules->set_rules(
257 branchcode => $library4->branchcode,
260 holdallowed => 'from_any_library',
261 hold_fulfillment_policy => 'holdingbranch',
262 returnbranch => 'any'
267 Koha::CirculationRules->set_rules(
269 branchcode => $library5->branchcode,
272 holdallowed => 'from_any_library',
273 hold_fulfillment_policy => 'homebranch',
274 returnbranch => 'any'
279 Koha::CirculationRules->set_rules(
281 branchcode => $library6->branchcode,
284 holdallowed => 'from_home_library',
285 hold_fulfillment_policy => 'holdgroup',
286 returnbranch => 'any'
291 Koha::CirculationRules->set_rules(
293 branchcode => $library7->branchcode,
296 holdallowed => 'from_local_hold_group',
297 hold_fulfillment_policy => 'holdingbranch',
298 returnbranch => 'any'
304 Koha::CirculationRules->set_rules(
306 branchcode => $library8->branchcode,
309 holdallowed => 'from_any_library',
310 hold_fulfillment_policy => 'patrongroup',
311 returnbranch => 'any'
316 my $group1_1 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root1->id, branchcode => $library1->branchcode } } );
317 my $group1_2 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root1->id, branchcode => $library2->branchcode } } );
319 my $group2_3 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root2->id, branchcode => $library3->branchcode } } );
320 my $group2_4 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root2->id, branchcode => $library4->branchcode } } );
322 my $group3_5 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library5->branchcode } } );
323 my $group3_6 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library6->branchcode } } );
324 my $group3_7 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library7->branchcode } } );
325 my $group3_8 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root3->id, branchcode => $library8->branchcode } } );
327 my $biblio1 = $builder->build_sample_biblio({ title => '1' });
328 my $biblio2 = $builder->build_sample_biblio({ title => '2' });
330 my $item1_1 = $builder->build_sample_item({
331 biblionumber => $biblio1->biblionumber,
332 homebranch => $library1->branchcode,
333 holdingbranch => $library2->branchcode,
336 my $item1_3 = $builder->build_sample_item({
337 biblionumber => $biblio1->biblionumber,
338 homebranch => $library3->branchcode,
339 holdingbranch => $library4->branchcode,
342 my $item1_7 = $builder->build_sample_item({
343 biblionumber => $biblio1->biblionumber,
344 homebranch => $library7->branchcode,
345 holdingbranch => $library4->branchcode,
348 my $item2_2 = $builder->build_sample_item({
349 biblionumber => $biblio2->biblionumber,
350 homebranch => $library2->branchcode,
351 holdingbranch => $library1->branchcode,
354 my $item2_4 = $builder->build_sample_item({
355 biblionumber => $biblio2->biblionumber,
356 homebranch => $library4->branchcode,
357 holdingbranch => $library3->branchcode,
360 my $item2_6 = $builder->build_sample_item({
361 biblionumber => $biblio2->biblionumber,
362 homebranch => $library6->branchcode,
363 holdingbranch => $library4->branchcode,
366 my $patron1 = $builder->build_object( { class => 'Koha::Patrons', value => { firstname=>'1', branchcode => $library1->branchcode } } );
367 my $patron8 = $builder->build_object( { class => 'Koha::Patrons', value => { firstname=>'8', branchcode => $library8->branchcode } } );
370 "ItemHomeLibrary-1-1" => 6,
371 "ItemHomeLibrary-1-8" => 1,
372 "ItemHomeLibrary-2-1" => 2,
373 "ItemHomeLibrary-2-8" => 0,
374 "PatronLibrary-1-1" => 6,
375 "PatronLibrary-1-8" => 3,
376 "PatronLibrary-2-1" => 0,
377 "PatronLibrary-2-8" => 3,
381 my ( $cbranch, $biblio, $patron, $results ) = @_;
382 t::lib::Mocks::mock_preference('ReservesControlBranch', $cbranch);
385 my $pickup_location = $_;
386 grep { $pickup_location->branchcode eq $_ } @branchcodes
387 } $biblio->pickup_locations( { patron => $patron } )->as_list;
390 scalar(@pl) == $results->{ $cbranch . '-'
391 . $biblio->title . '-'
392 . $patron->firstname },
393 'ReservesControlBranch: '
400 . $results->{ $cbranch . '-'
401 . $biblio->title . '-'
402 . $patron->firstname }
408 foreach my $cbranch ('ItemHomeLibrary','PatronLibrary') {
409 foreach my $biblio ($biblio1, $biblio2) {
410 foreach my $patron ($patron1, $patron8) {
411 _doTest($cbranch, $biblio, $patron, $results);
416 my @pl_names = map { $_->branchname } $biblio1->pickup_locations( { patron => $patron1 } )->as_list;
417 my $pl_ori_str = join('|', @pl_names);
418 my $pl_sorted_str = join('|', sort { lc($a) cmp lc($b) } @pl_names);
420 $pl_ori_str eq $pl_sorted_str,
421 'Libraries must be sorted by name'
423 $schema->storage->txn_rollback;
426 subtest 'to_api() tests' => sub {
428 $schema->storage->txn_begin;
430 my $biblio = $builder->build_sample_biblio();
431 my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
433 my $biblioitem_api = $biblio->biblioitem->to_api;
434 my $biblio_api = $biblio->to_api;
436 plan tests => (scalar keys %{ $biblioitem_api }) + 1;
438 foreach my $key ( keys %{ $biblioitem_api } ) {
439 is( $biblio_api->{$key}, $biblioitem_api->{$key}, "$key is added to the biblio object" );
442 $biblio_api = $biblio->to_api({ embed => { items => {} } });
443 is_deeply( $biblio_api->{items}, [ $item->to_api ], 'Item correctly embedded' );
445 $schema->storage->txn_rollback;
448 subtest 'suggestions() tests' => sub {
452 $schema->storage->txn_begin;
454 my $biblio = $builder->build_sample_biblio();
456 is( ref($biblio->suggestions), 'Koha::Suggestions', 'Return type is correct' );
459 $biblio->suggestions->unblessed,
461 '->suggestions returns an empty Koha::Suggestions resultset'
464 my $suggestion = $builder->build_object(
466 class => 'Koha::Suggestions',
467 value => { biblionumber => $biblio->biblionumber }
471 my $suggestions = $biblio->suggestions->unblessed;
474 $biblio->suggestions->unblessed,
475 [ $suggestion->unblessed ],
476 '->suggestions returns the related Koha::Suggestion objects'
479 $schema->storage->txn_rollback;
482 subtest 'orders() and active_orders() tests' => sub {
486 $schema->storage->txn_begin;
488 my $biblio = $builder->build_sample_biblio();
490 my $orders = $biblio->orders;
491 my $active_orders = $biblio->active_orders;
493 is( ref($orders), 'Koha::Acquisition::Orders', 'Result type is correct' );
494 is( $biblio->orders->count, $biblio->active_orders->count, '->orders->count returns the count for the resultset' );
496 # Add a couple orders
498 $builder->build_object(
500 class => 'Koha::Acquisition::Orders',
502 biblionumber => $biblio->biblionumber,
503 datecancellationprinted => '2019-12-31'
509 $builder->build_object(
511 class => 'Koha::Acquisition::Orders',
513 biblionumber => $biblio->biblionumber,
514 datecancellationprinted => undef
519 $orders = $biblio->orders;
520 $active_orders = $biblio->active_orders;
522 is( ref($orders), 'Koha::Acquisition::Orders', 'Result type is correct' );
523 is( ref($active_orders), 'Koha::Acquisition::Orders', 'Result type is correct' );
524 is( $orders->count, $active_orders->count + 2, '->active_orders->count returns the rigt count' );
526 $schema->storage->txn_rollback;
529 subtest 'subscriptions() tests' => sub {
533 $schema->storage->txn_begin;
535 my $biblio = $builder->build_sample_biblio;
537 my $subscriptions = $biblio->subscriptions;
538 is( ref($subscriptions), 'Koha::Subscriptions',
539 'Koha::Biblio->subscriptions should return a Koha::Subscriptions object'
541 is( $subscriptions->count, 0, 'Koha::Biblio->subscriptions should return the correct number of subscriptions');
543 # Add two subscriptions
545 $builder->build_object(
547 class => 'Koha::Subscriptions',
548 value => { biblionumber => $biblio->biblionumber }
553 $subscriptions = $biblio->subscriptions;
554 is( ref($subscriptions), 'Koha::Subscriptions',
555 'Koha::Biblio->subscriptions should return a Koha::Subscriptions object'
557 is( $subscriptions->count, 2, 'Koha::Biblio->subscriptions should return the correct number of subscriptions');
559 $schema->storage->txn_rollback;
562 subtest 'get_marc_notes() MARC21 tests' => sub {
565 $schema->storage->txn_begin;
567 t::lib::Mocks::mock_preference( 'NotesToHide', '520' );
569 my $biblio = $builder->build_sample_biblio;
570 my $record = $biblio->metadata->record;
571 $record->append_fields(
572 MARC::Field->new( '500', '', '', a => 'Note1' ),
573 MARC::Field->new( '505', '', '', a => 'Note2', u => 'http://someserver.com' ),
574 MARC::Field->new( '520', '', '', a => 'Note3 skipped' ),
575 MARC::Field->new( '541', '0', '', a => 'Note4 skipped on opac' ),
576 MARC::Field->new( '541', '', '', a => 'Note5' ),
578 C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
579 $biblio = Koha::Biblios->find( $biblio->biblionumber);
580 my $notes = $biblio->get_marc_notes({ marcflavour => 'MARC21' });
581 is( $notes->[0]->{marcnote}, 'Note1', 'First note' );
582 is( $notes->[1]->{marcnote}, 'Note2', 'Second note' );
583 is( $notes->[2]->{marcnote}, 'http://someserver.com', 'URL separated' );
584 is( $notes->[3]->{marcnote}, 'Note4 skipped on opac',"Not shows if not opac" );
585 is( $notes->[4]->{marcnote}, 'Note5', 'Fifth note' );
586 is( @$notes, 5, 'No more notes' );
587 $notes = $biblio->get_marc_notes({ marcflavour => 'MARC21', opac => 1 });
588 is( $notes->[0]->{marcnote}, 'Note1', 'First note' );
589 is( $notes->[1]->{marcnote}, 'Note2', 'Second note' );
590 is( $notes->[2]->{marcnote}, 'http://someserver.com', 'URL separated' );
591 is( $notes->[3]->{marcnote}, 'Note5', 'Fifth note shows after fourth skipped' );
592 is( @$notes, 4, 'No more notes' );
594 $schema->storage->txn_rollback;
597 subtest 'get_marc_notes() UNIMARC tests' => sub {
600 $schema->storage->txn_begin;
602 t::lib::Mocks::mock_preference( 'NotesToHide', '310' );
604 my $biblio = $builder->build_sample_biblio;
605 my $record = $biblio->metadata->record;
606 $record->append_fields(
607 MARC::Field->new( '300', '', '', a => 'Note1' ),
608 MARC::Field->new( '300', '', '', a => 'Note2' ),
609 MARC::Field->new( '310', '', '', a => 'Note3 skipped' ),
611 C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
612 $biblio = Koha::Biblios->find( $biblio->biblionumber);
613 my $notes = $biblio->get_marc_notes({ marcflavour => 'UNIMARC' });
614 is( $notes->[0]->{marcnote}, 'Note1', 'First note' );
615 is( $notes->[1]->{marcnote}, 'Note2', 'Second note' );
616 is( @$notes, 2, 'No more notes' );
618 $schema->storage->txn_rollback;