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>.
23 use Test::More tests => 15;
29 use t::lib::TestBuilder;
31 use Mojo::JSON qw(encode_json);
34 use C4::Circulation qw( AddIssue AddReturn );
38 use Koha::DateUtils qw (dt_from_string);
40 use Koha::Old::Checkouts;
42 use Mojo::JSON qw(encode_json);
44 my $schema = Koha::Database->new->schema;
45 my $builder = t::lib::TestBuilder->new;
47 t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
49 my $t = Test::Mojo->new('Koha::REST::V1');
51 subtest 'get() tests' => sub {
55 $schema->storage->txn_begin;
57 my $patron = $builder->build_object(
59 class => 'Koha::Patrons',
60 value => { flags => 0 }
63 my $password = 'thePassword123';
64 $patron->set_password( { password => $password, skip_validation => 1 } );
65 $patron->discard_changes;
66 my $userid = $patron->userid;
68 my $biblio = $builder->build_sample_biblio({
69 title => 'The unbearable lightness of being',
70 author => 'Milan Kundera'
72 $t->get_ok("//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber)
75 $patron->flags(4)->store;
77 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber
78 => { Accept => 'application/weird+format' } )
81 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber
82 => { Accept => 'application/json' } )
84 ->json_is( '/title', 'The unbearable lightness of being' )
85 ->json_is( '/author', 'Milan Kundera' );
87 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber
88 => { Accept => 'application/marcxml+xml' } )
91 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber
92 => { Accept => 'application/marc-in-json' } )
95 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber
96 => { Accept => 'application/marc' } )
99 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber
100 => { Accept => 'text/plain' } )
102 ->content_is($biblio->metadata->record->as_formatted);
105 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber
106 => { Accept => 'application/marc' } )
108 ->json_is( '/error', 'Object not found.' );
110 subtest 'marc-in-json encoding tests' => sub {
114 my $title_with_diacritics = "L'insoutenable légèreté de l'être";
116 my $biblio = $builder->build_sample_biblio(
118 title => $title_with_diacritics,
119 author => "Milan Kundera"
123 my $result = $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber
124 => { Accept => 'application/marc-in-json' } )
125 ->status_is(200)->tx->res->body;
127 my $encoded_title = Encode::encode( "UTF-8", $title_with_diacritics );
129 like( $result, qr/\Q$encoded_title/, "The title is not double encoded" );
132 subtest 'marcxml encoding tests' => sub {
135 my $marcflavour = C4::Context->preference('marcflavour');
136 t::lib::Mocks::mock_preference('marcflavour', 'UNIMARC');
139 my $title_with_diacritics = "L'insoutenable légèreté de l'être";
141 my $biblio = $builder->build_sample_biblio(
143 title => $title_with_diacritics,
144 author => "Milan Kundera"
148 my $record = $biblio->metadata->record;
149 $record->leader(' nam 3 4500');
150 $biblio->metadata->metadata($record->as_xml_record('UNIMARC'));
151 $biblio->metadata->store;
153 my $result = $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber
154 => { Accept => 'application/marcxml+xml' } )
155 ->status_is(200)->tx->res->body;
157 my $encoded_title = Encode::encode( "UTF-8", $title_with_diacritics );
159 like( $result, qr/\Q$encoded_title/, "The title is not double encoded" );
160 t::lib::Mocks::mock_preference('marcflavour', $marcflavour);
163 $schema->storage->txn_rollback;
166 subtest 'get_items() tests' => sub {
170 $schema->storage->txn_begin;
172 my $patron = $builder->build_object(
174 class => 'Koha::Patrons',
175 value => { flags => 0 }
178 my $password = 'thePassword123';
179 $patron->set_password( { password => $password, skip_validation => 1 } );
180 $patron->discard_changes;
181 my $userid = $patron->userid;
183 my $biblio = $builder->build_sample_biblio();
184 $t->get_ok("//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/items")
187 $patron->flags(4)->store;
189 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/items")
191 ->json_is( '' => [], 'No items on the biblio' );
193 my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
194 my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
196 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/items")
198 ->json_is( '' => [ $item_1->to_api, $item_2->to_api ], 'The items are returned' );
201 "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/items" => { "x-koha-embed" => "+strings" } )
203 ->json_has( '/0/_strings/home_library_id/str' => $item_1->holding_branch->branchname, '_strings are embedded' );
205 $schema->storage->txn_rollback;
208 subtest 'delete() tests' => sub {
212 $schema->storage->txn_begin;
214 my $patron = $builder->build_object(
216 class => 'Koha::Patrons',
217 value => { flags => 0 } # no permissions
220 my $password = 'thePassword123';
221 $patron->set_password( { password => $password, skip_validation => 1 } );
222 my $userid = $patron->userid;
224 my $item = $builder->build_sample_item();
225 my $biblio_id = $item->biblionumber;
227 $t->delete_ok("//$userid:$password@/api/v1/biblios/$biblio_id")
228 ->status_is(403, 'Not enough permissions makes it return the right code');
233 source => 'UserPermission',
235 borrowernumber => $patron->borrowernumber,
237 code => 'edit_catalogue'
243 # Bibs with items cannot be deleted
244 $t->delete_ok("//$userid:$password@/api/v1/biblios/$biblio_id")
249 # Bibs with no items can be deleted
250 $t->delete_ok("//$userid:$password@/api/v1/biblios/$biblio_id")
251 ->status_is(204, 'SWAGGER3.2.4')
252 ->content_is('', 'SWAGGER3.3.4');
254 $t->delete_ok("//$userid:$password@/api/v1/biblios/$biblio_id")
257 $schema->storage->txn_rollback;
260 subtest 'get_public() tests' => sub {
264 $schema->storage->txn_begin;
266 my $category = $builder->build_object({ class => 'Koha::Patron::Categories' });
267 my $patron = $builder->build_object(
269 class => 'Koha::Patrons',
271 flags => undef, # opac user
272 categorycode => $category->categorycode
276 my $password = 'thePassword123';
277 $patron->set_password( { password => $password, skip_validation => 1 } );
278 $patron->discard_changes;
279 my $userid = $patron->userid;
281 my $biblio = $builder->build_sample_biblio({
282 title => 'The unbearable lightness of being',
283 author => 'Milan Kundera'
286 # Make sure author in shown in the OPAC
287 my $subfields = Koha::MarcSubfieldStructures->search({ tagfield => '100' });
288 while ( my $subfield = $subfields->next ) {
289 $subfield->set({ hidden => -1 })->store;
291 Koha::Caches->get_instance()->flush_all;
293 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber
294 => { Accept => 'application/weird+format' } )
297 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber
298 => { Accept => 'text/plain' } )
300 ->content_like( qr{100\s+_aMilan Kundera} )
301 ->content_like( qr{245\s+_aThe unbearable lightness of being} );
303 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber
304 => { Accept => 'application/marcxml+xml' } )
307 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber
308 => { Accept => 'application/marc-in-json' } )
311 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber
312 => { Accept => 'application/marc' } )
315 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber
316 => { Accept => 'text/plain' } )
318 ->content_is($biblio->metadata->record->as_formatted);
320 subtest 'anonymous access' => sub {
323 $t->get_ok( "/api/v1/public/biblios/" . $biblio->biblionumber
324 => { Accept => 'application/marcxml+xml' } )
327 $t->get_ok( "/api/v1/public/biblios/" . $biblio->biblionumber
328 => { Accept => 'application/marc-in-json' } )
331 $t->get_ok( "/api/v1/public/biblios/" . $biblio->biblionumber
332 => { Accept => 'application/marc' } )
335 $t->get_ok( "/api/v1/public/biblios/" . $biblio->biblionumber
336 => { Accept => 'text/plain' } )
338 ->content_is($biblio->metadata->record->as_formatted);
341 subtest 'marc-in-json encoding tests' => sub {
345 my $title_with_diacritics = "L'insoutenable légèreté de l'être";
347 my $biblio = $builder->build_sample_biblio(
349 title => $title_with_diacritics,
350 author => "Milan Kundera"
354 my $result = $t->get_ok( "/api/v1/public/biblios/" . $biblio->biblionumber
355 => { Accept => 'application/marc-in-json' } )
356 ->status_is(200)->tx->res->body;
358 my $encoded_title = Encode::encode( "UTF-8", $title_with_diacritics );
360 like( $result, qr/\Q$encoded_title/, "The title is not double encoded" );
363 # Hide author in OPAC
364 $subfields = Koha::MarcSubfieldStructures->search({ tagfield => '100' });
365 while ( my $subfield = $subfields->next ) {
366 $subfield->set({ hidden => 1 })->store;
369 Koha::Caches->get_instance()->flush_all;
371 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber
372 => { Accept => 'text/plain' } )
374 ->content_unlike( qr{100\s+_aMilan Kundera} )
375 ->content_like( qr{245\s+_aThe unbearable lightness of being} );
377 subtest 'hidden_in_opac tests' => sub {
381 my $biblio_hidden_in_opac = 1;
383 my $biblio_class = Test::MockModule->new('Koha::Biblio');
384 # force biblio hidden in OPAC
385 $biblio_class->mock( 'hidden_in_opac', sub { return $biblio_hidden_in_opac; } );
387 $t->get_ok( "/api/v1/public/biblios/" . $biblio->biblionumber
388 => { Accept => 'text/plain' } )
389 ->status_is(404, 'hidden_in_opac + anonymous => hidden');
391 my $category_override_hidden_items = 0;
392 my $category_class = Test::MockModule->new('Koha::Patron::Category');
393 $category_class->mock( 'override_hidden_items', sub { return $category_override_hidden_items; } );
394 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber
395 => { Accept => 'text/plain' } )
396 ->status_is(404, "hidden_in_opac + patron whose category doesn't override => hidden");
398 # Make the category override
399 $category_override_hidden_items = 1;
400 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber
401 => { Accept => 'text/plain' } )
402 ->status_is(200, "hidden_in_opac + patron whose category that overrides => displayed");
404 t::lib::Mocks::mock_preference('OpacHiddenItems');
408 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber
409 => { Accept => 'application/marc' } )
411 ->json_is( '/error', 'Object not found.' );
413 $schema->storage->txn_rollback;
416 subtest 'pickup_locations() tests' => sub {
420 $schema->storage->txn_begin;
422 t::lib::Mocks::mock_preference( 'AllowHoldPolicyOverride', 0 );
424 # Small trick to ease testing
425 Koha::Libraries->search->update({ pickup_location => 0 });
427 my $library_1 = $builder->build_object({ class => 'Koha::Libraries', value => { marcorgcode => 'A', pickup_location => 1 } });
428 my $library_2 = $builder->build_object({ class => 'Koha::Libraries', value => { marcorgcode => 'B', pickup_location => 1 } });
429 my $library_3 = $builder->build_object({ class => 'Koha::Libraries', value => { marcorgcode => 'C', pickup_location => 1 } });
431 my $library_1_api = $library_1->to_api();
432 my $library_2_api = $library_2->to_api();
433 my $library_3_api = $library_3->to_api();
435 $library_1_api->{needs_override} = Mojo::JSON->false;
436 $library_2_api->{needs_override} = Mojo::JSON->false;
437 $library_3_api->{needs_override} = Mojo::JSON->true;
439 my $patron = $builder->build_object(
441 class => 'Koha::Patrons',
442 value => { userid => 'tomasito', flags => 0 }
445 my $password = 'thePassword123';
446 $patron->set_password( { password => $password, skip_validation => 1 } );
447 my $userid = $patron->userid;
450 source => 'UserPermission',
452 borrowernumber => $patron->borrowernumber,
454 code => 'place_holds',
459 my $biblio_class = Test::MockModule->new('Koha::Biblio');
463 my ( $self, $params ) = @_;
464 my $mock_patron = $params->{patron};
465 is( $mock_patron->borrowernumber,
466 $patron->borrowernumber, 'Patron passed correctly' );
467 return Koha::Libraries->search(
471 $library_1->branchcode,
472 $library_2->branchcode
476 { # we make sure no surprises in the order of the result
477 order_by => { '-asc' => 'marcorgcode' }
483 my $biblio = $builder->build_sample_biblio;
485 $t->get_ok( "//$userid:$password@/api/v1/biblios/"
487 . "/pickup_locations?patron_id=" . $patron->id )
488 ->json_is( [ $library_1_api, $library_2_api ] );
491 $t->get_ok( "//$userid:$password@/api/v1/biblios/"
493 . '/pickup_locations?'
494 . 'patron_id=' . $patron->id . '&q={"marc_org_code": { "-like": "A%" }}' )
495 ->json_is( [ $library_1_api ] );
497 t::lib::Mocks::mock_preference( 'AllowHoldPolicyOverride', 1 );
499 my $library_4 = $builder->build_object({ class => 'Koha::Libraries', value => { pickup_location => 0, marcorgcode => 'X' } });
500 my $library_5 = $builder->build_object({ class => 'Koha::Libraries', value => { pickup_location => 1, marcorgcode => 'Y' } });
502 my $library_5_api = $library_5->to_api();
503 $library_5_api->{needs_override} = Mojo::JSON->true;
505 $t->get_ok( "//$userid:$password@/api/v1/biblios/"
507 . "/pickup_locations?"
508 . "patron_id=" . $patron->id . "&_order_by=marc_org_code" )
509 ->json_is( [ $library_1_api, $library_2_api, $library_3_api, $library_5_api ] );
511 subtest 'Pagination and AllowHoldPolicyOverride tests' => sub {
515 t::lib::Mocks::mock_preference( 'AllowHoldPolicyOverride', 1 );
517 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->id . "/pickup_locations?" . "patron_id=" . $patron->id . "&_order_by=marc_org_code" . "&_per_page=1" )
518 ->json_is( [$library_1_api] )
519 ->header_is( 'X-Total-Count', '4', '4 is the count for libraries with pickup_location=1' )
520 ->header_is( 'X-Base-Total-Count', '4', '4 is the count for libraries with pickup_location=1' )
521 ->header_unlike( 'Link', qr|rel="prev"| )
522 ->header_like( 'Link', qr#(_per_page=1.*\&_page=2.*|_page=2.*\&_per_page=1.*)>\; rel="next"# )
523 ->header_like( 'Link', qr#(_per_page=1.*\&_page=1.*|_page=1.*\&_per_page=1).*>\; rel="first"# )
524 ->header_like( 'Link', qr#(_per_page=1.*\&_page=4.*|_page=4.*\&_per_page=1).*>\; rel="last"# );
526 $t->get_ok( "//$userid:$password@/api/v1/biblios/"
528 . "/pickup_locations?"
531 . "&_order_by=marc_org_code"
532 . "&_per_page=1&_page=3" ) # force the needs_override=1 check
533 ->json_is( [$library_3_api] )
534 ->header_is( 'X-Total-Count', '4', '4 is the count for libraries with pickup_location=1' )
535 ->header_is( 'X-Base-Total-Count', '4', '4 is the count for libraries with pickup_location=1' )
536 ->header_like( 'Link', qr#(_per_page=1.*\&_page=2.*|_page=2.*\&_per_page=1.*)>\; rel="prev"# )
537 ->header_like( 'Link', qr#(_per_page=1.*\&_page=4.*|_page=4.*\&_per_page=1.*)>\; rel="next"# )
538 ->header_like( 'Link', qr#(_per_page=1.*\&_page=1.*|_page=1.*\&_per_page=1).*>\; rel="first"# )
539 ->header_like( 'Link', qr#(_per_page=1.*\&_page=4.*|_page=4.*\&_per_page=1).*>\; rel="last"# );
541 t::lib::Mocks::mock_preference( 'AllowHoldPolicyOverride', 0 );
543 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->id . "/pickup_locations?" . "patron_id=" . $patron->id . "&_order_by=marc_org_code" . "&_per_page=1" )
544 ->json_is( [$library_1_api] )
545 ->header_is( 'X-Total-Count', '2' )
546 ->header_is( 'X-Base-Total-Count', '2' )
547 ->header_unlike( 'Link', qr|rel="prev"| )
548 ->header_like( 'Link', qr#(_per_page=1.*\&_page=2.*|_page=2.*\&_per_page=1.*)>\; rel="next"# )
549 ->header_like( 'Link', qr#(_per_page=1.*\&_page=1.*|_page=1.*\&_per_page=1).*>\; rel="first"# )
550 ->header_like( 'Link', qr#(_per_page=1.*\&_page=2.*|_page=2.*\&_per_page=1).*>\; rel="last"# );
553 my $deleted_patron = $builder->build_object({ class => 'Koha::Patrons' });
554 my $deleted_patron_id = $deleted_patron->id;
555 $deleted_patron->delete;
557 $t->get_ok( "//$userid:$password@/api/v1/biblios/"
559 . "/pickup_locations?"
560 . "patron_id=" . $deleted_patron_id )
562 ->json_is( '/error' => 'Patron not found' );
566 $t->get_ok( "//$userid:$password@/api/v1/biblios/"
568 . "/pickup_locations?"
569 . "patron_id=" . $patron->id )
571 ->json_is( '/error' => 'Biblio not found' );
573 $schema->storage->txn_rollback;
576 subtest 'get_items_public() tests' => sub {
580 $schema->storage->txn_begin;
582 my $override_hidden_items = 0;
584 my $mocked_category = Test::MockModule->new('Koha::Patron::Category');
585 $mocked_category->mock(
586 'override_hidden_items',
588 return $override_hidden_items;
594 my $mocked_context = Test::MockModule->new('C4::Context');
595 $mocked_context->mock(
602 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
603 my $password = 'thePassword123';
604 $patron->set_password( { password => $password, skip_validation => 1 } );
605 $patron->discard_changes;
606 my $userid = $patron->userid;
608 my $biblio = $builder->build_sample_biblio();
611 "//$userid:$password@/api/v1/public/biblios/" . $biblio->id . "/items" )
612 ->status_is(200)->json_is( '' => [], 'No items on the biblio' );
614 my $item_1 = $builder->build_sample_item( { biblionumber => $biblio->id } );
615 my $item_2 = $builder->build_sample_item(
616 { biblionumber => $biblio->id, withdrawn => 1 } );
618 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/"
619 . $biblio->biblionumber
620 . "/items" )->status_is(200)->json_is(
622 $item_1->to_api( { public => 1 } ),
623 $item_2->to_api( { public => 1 } )
625 'The items are returned'
628 $rules = { withdrawn => ['1'] };
630 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/"
631 . $biblio->biblionumber
632 . "/items" )->status_is(200)->json_is(
633 '' => [ $item_1->to_api( { public => 1 } ) ],
634 'The items are returned, hidden one is not returned'
637 $t->get_ok( "/api/v1/public/biblios/"
638 . $biblio->biblionumber
639 . "/items" )->status_is(200)->json_is(
640 '' => [ $item_1->to_api( { public => 1 } ) ],
641 'Anonymous user, items are returned, hidden one is not returned'
645 $override_hidden_items = 1;
647 $t->get_ok( "//$userid:$password@/api/v1/public/biblios/"
648 . $biblio->biblionumber
649 . "/items" )->status_is(200)->json_is(
651 $item_1->to_api( { public => 1 } ),
652 $item_2->to_api( { public => 1 } )
654 'The items are returned, the patron category has an override'
657 $schema->storage->txn_rollback;
660 subtest 'get_bookings() tests' => sub {
664 $schema->storage->txn_begin;
666 my $librarian = $builder->build_object(
668 class => 'Koha::Patrons',
669 value => { flags => 0 } # no additional permissions
674 source => 'UserPermission',
676 borrowernumber => $librarian->borrowernumber,
678 code => 'manage_bookings',
682 my $password = 'thePassword123';
683 $librarian->set_password( { password => $password, skip_validation => 1 } );
684 my $userid = $librarian->userid;
686 my $patron = $builder->build_object(
688 class => 'Koha::Patrons',
689 value => { flags => 0 }
692 $patron->set_password( { password => $password, skip_validation => 1 } );
693 my $unauth_userid = $patron->userid;
695 my $biblio = $builder->build_sample_biblio();
696 my $item1 = $builder->build_sample_item( { bookable => 1, biblionumber => $biblio->id } );
697 my $item2 = $builder->build_sample_item( { bookable => 1, biblionumber => $biblio->id } );
699 $t->get_ok( "//$unauth_userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/bookings" )->status_is(403);
701 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/bookings" )->status_is(200)
702 ->json_is( '' => [], 'No bookings on the biblio' );
705 my $start_0 = dt_from_string->subtract( days => 2 )->truncate( to => 'day' );
706 my $end_0 = dt_from_string->add( days => 4 )->truncate( to => 'day' );
707 my $booking_0 = $builder->build_object(
709 class => 'Koha::Bookings',
711 biblio_id => $biblio->id,
712 item_id => $item1->id,
713 start_date => $start_0,
719 my $ret = $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/bookings" )->status_is(200)
722 is_deeply( $ret, [ $booking_0->to_api ] );
724 $schema->storage->txn_rollback;
727 subtest 'get_checkouts() tests' => sub {
731 $schema->storage->txn_begin;
733 my $patron = $builder->build_object(
735 class => 'Koha::Patrons',
736 value => { flags => 0 }
739 my $password = 'thePassword123';
740 $patron->set_password( { password => $password, skip_validation => 1 } );
741 $patron->discard_changes;
742 my $userid = $patron->userid;
744 my $biblio = $builder->build_sample_biblio();
745 $t->get_ok("//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/checkouts")
750 source => 'UserPermission',
752 borrowernumber => $patron->borrowernumber,
754 code => 'circulate_remaining_permissions',
759 $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/checkouts" )
760 ->status_is( 200, 'circulate_remaining_permissions allows checkouts access' )
761 ->json_is( '' => [], 'No checkouts on the biblio' );
763 my $bookings_librarian = $builder->build_object(
765 class => 'Koha::Patrons',
766 value => { flags => 0 } # no additional permissions
771 source => 'UserPermission',
773 borrowernumber => $bookings_librarian->borrowernumber,
775 code => 'manage_bookings',
779 $bookings_librarian->set_password( { password => $password, skip_validation => 1 } );
780 my $bookings_userid = $bookings_librarian->userid;
782 $t->get_ok( "//$bookings_userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/checkouts" )
783 ->status_is( 200, 'manage_bookings allows checkouts access' )
784 ->json_is( '' => [], 'No checkouts on the biblio' );
786 my $item_1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
787 my $item_2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
789 AddIssue( $patron, $item_1->barcode );
790 AddIssue( $patron, $item_2->barcode );
792 my $ret = $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/checkouts")
796 my $checkout_1 = Koha::Checkouts->find({ itemnumber => $item_1->id });
797 my $checkout_2 = Koha::Checkouts->find({ itemnumber => $item_2->id });
799 is_deeply( $ret, [ $checkout_1->to_api, $checkout_2->to_api ] );
801 AddReturn( $item_1->barcode );
803 $ret = $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/checkouts")
807 is_deeply( $ret, [ $checkout_2->to_api ] );
809 $ret = $t->get_ok( "//$userid:$password@/api/v1/biblios/" . $biblio->biblionumber . "/checkouts?checked_in=1")
813 my $old_checkout_1 = Koha::Old::Checkouts->find( $checkout_1->id );
815 is_deeply( $ret, [ $old_checkout_1->to_api ] );
817 $schema->storage->txn_rollback;
820 subtest 'set_rating() tests' => sub {
824 $schema->storage->txn_begin;
826 my $patron = $builder->build_object(
828 class => 'Koha::Patrons',
829 value => { flags => 0 }
832 my $password = 'thePassword123';
833 $patron->set_password( { password => $password, skip_validation => 1 } );
834 $patron->discard_changes;
835 my $userid = $patron->userid;
837 my $biblio = $builder->build_sample_biblio();
838 $t->post_ok("/api/v1/public/biblios/" . $biblio->biblionumber . "/ratings" => json => { rating => 3 })
841 $t->post_ok("//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber . "/ratings" => json => { rating => 3 })
843 ->json_is( '/rating', '3' )
844 ->json_is( '/average', '3' )
845 ->json_is( '/count', '1' );
847 $t->post_ok("//$userid:$password@/api/v1/public/biblios/" . $biblio->biblionumber . "/ratings" => json => { rating => undef })
849 ->json_is( '/rating', undef )
850 ->json_is( '/average', '0' )
851 ->json_is( '/count', '0' );
853 $schema->storage->txn_rollback;
858 subtest 'post() tests' => sub {
862 $schema->storage->txn_begin;
864 my $patron = $builder->build_object(
866 class => 'Koha::Patrons',
867 value => { flags => 0 } # no permissions
870 my $password = 'thePassword123';
871 $patron->set_password( { password => $password, skip_validation => 1 } );
872 my $userid = $patron->userid;
874 my $frameworkcode = 'BKS';
875 my $marcxml = q|<?xml version="1.0" encoding="UTF-8"?>
877 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
878 xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd"
879 xmlns="http://www.loc.gov/MARC21/slim">
881 <leader>01102pam a2200289 a 7500</leader>
882 <controlfield tag="001">2504398</controlfield>
883 <controlfield tag="005">20200421093816.0</controlfield>
884 <controlfield tag="008">920610s1993 caub s001 0 eng </controlfield>
885 <datafield tag="010" ind1=" " ind2=" ">
886 <subfield code="a"> 92021731 </subfield>
888 <datafield tag="020" ind1=" " ind2=" ">
889 <subfield code="a">05200784381 (Test marcxml)</subfield>
891 <datafield tag="020" ind1=" " ind2=" ">
892 <subfield code="a">05200784461 (Test marcxml)</subfield>
894 <datafield tag="040" ind1=" " ind2=" ">
895 <subfield code="a">DLC</subfield>
896 <subfield code="c">DLC</subfield>
897 <subfield code="d">DLC</subfield>
899 <datafield tag="041" ind1="0" ind2=" ">
900 <subfield code="a">enggrc</subfield>
902 <datafield tag="050" ind1="0" ind2="0">
903 <subfield code="a">PA522</subfield>
904 <subfield code="b">.M38 1993</subfield>
906 <datafield tag="082" ind1="0" ind2="0">
907 <subfield code="a">480</subfield>
908 <subfield code="2">20</subfield>
910 <datafield tag="100" ind1="1" ind2=" ">
911 <subfield code="a">Mastronarde, Donald J.</subfield>
912 <subfield code="9">389</subfield>
914 <datafield tag="245" ind1="1" ind2="0">
915 <subfield code="a">Introduction to Attic Greek (Using marcxml) /</subfield>
916 <subfield code="c">Donald J. Mastronarde.</subfield>
918 <datafield tag="260" ind1=" " ind2=" ">
919 <subfield code="a">Berkeley :</subfield>
920 <subfield code="b">University of California Press,</subfield>
921 <subfield code="c">c1993.</subfield>
923 <datafield tag="300" ind1=" " ind2=" ">
924 <subfield code="a">ix, 425 p. :</subfield>
925 <subfield code="b">maps ;</subfield>
926 <subfield code="c">26 cm.</subfield>
928 <datafield tag="500" ind1=" " ind2=" ">
929 <subfield code="a">Includes index.</subfield>
931 <datafield tag="650" ind1=" " ind2="0">
932 <subfield code="a">Attic Greek dialect</subfield>
933 <subfield code="9">7</subfield>
935 <datafield tag="856" ind1="4" ind2="2">
936 <subfield code="3">Contributor biographical information</subfield>
937 <subfield code="u">http://www.loc.gov/catdir/bios/ucal051/92021731.html</subfield>
939 <datafield tag="856" ind1="4" ind2="2">
940 <subfield code="3">Publisher description</subfield>
941 <subfield code="u">http://www.loc.gov/catdir/description/ucal041/92021731.html</subfield>
943 <datafield tag="906" ind1=" " ind2=" ">
944 <subfield code="a">7</subfield>
945 <subfield code="b">cbc</subfield>
946 <subfield code="c">orignew</subfield>
947 <subfield code="d">1</subfield>
948 <subfield code="e">ocip</subfield>
949 <subfield code="f">19</subfield>
950 <subfield code="g">y-gencatlg</subfield>
952 <datafield tag="942" ind1=" " ind2=" ">
953 <subfield code="2">ddc</subfield>
954 <subfield code="c">BK</subfield>
956 <datafield tag="955" ind1=" " ind2=" ">
957 <subfield code="a">pc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93</subfield>
959 <datafield tag="999" ind1=" " ind2=" ">
960 <subfield code="c">3</subfield>
961 <subfield code="d">3</subfield>
971 "005": "20200421093816.0"
974 "008": "920610s1993 caub s001 0 eng "
991 "a": "05200784382 (Test mij)"
1002 "a": "05200784462 (Test mij)"
1070 "a": "Mastronarde, Donald J."
1084 "a": "Introduction to Attic Greek (Using mij) /"
1087 "c": "Donald J. Mastronarde."
1100 "b": "University of California Press,"
1131 "a": "Includes index."
1142 "a": "Attic Greek dialect"
1156 "3": "Contributor biographical information"
1159 "u": "http://www.loc.gov/catdir/bios/ucal051/92021731.html"
1171 "3": "Publisher description"
1174 "u": "http://www.loc.gov/catdir/description/ucal041/92021731.html"
1227 "a": "pc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93"
1249 "leader": "01102pam a2200289 a 8500"
1251 my $marc = q|01102pam a2200289 a 9500001000800000005001700008008004100025010001700066020002800083020003500111040001800146041001100164050002100175082001200196100003200208245005800240260005600298300003300354500002000387650002700407856009500434856008700529906004500616942001200661955013000673999000900803
\1e2504398
\1e20200421093816.0
\1e920610s1993 caub s001 0 eng
\1e \1fa 92021731
\1e \1fa05200784383 (Test usmarc)
\1e \1fa05200784463 (Test usmarc)
\1e \1faDLC
\1fcDLC
\1fdDLC
\1e0
\1faenggrc
\1e00
\1faPA522
\1fb.M38 1993
\1e00
\1fa480
\1f220
\1e1
\1faMastronarde, Donald J.
\1f9389
\1e10
\1faIntroduction to Attic Greek (Using usmarc) /
\1fcDonald J. Mastronarde.
\1e \1faBerkeley :
\1fbUniversity of California Press,
\1fcc1993.
\1e \1faix, 425 p. :
\1fbmaps ;
\1fc26 cm.
\1e \1faIncludes index.
\1e 0
\1faAttic Greek dialect
\1f97
\1e42
\1f3Contributor biographical information
\1fuhttp://www.loc.gov/catdir/bios/ucal051/92021731.html
\1e42
\1f3Publisher description
\1fuhttp://www.loc.gov/catdir/description/ucal041/92021731.html
\1e \1fa7
\1fbcbc
\1fcorignew
\1fd1
\1feocip
\1ff19
\1fgy-gencatlg
\1e \1f2ddc
\1fcBK
\1e \1fapc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93
\1e \1fc3
\1fd3
\1e\1d|;
1253 $t->post_ok("//$userid:$password@/api/v1/biblios")
1254 ->status_is(403, 'Not enough permissions makes it return the right code');
1259 source => 'UserPermission',
1261 borrowernumber => $patron->borrowernumber,
1263 code => 'edit_catalogue'
1268 $t->post_ok("//$userid:$password@/api/v1/biblios" => {'Content-Type' => 'application/marcxml+xml', 'x-framework-id' => $frameworkcode, "x-record-schema" => 'INVALID'})
1269 ->status_is(400, 'Invalid header x-record-schema');
1271 $t->post_ok("//$userid:$password@/api/v1/biblios" => {'Content-Type' => 'application/marcxml+xml', 'x-framework-id' => $frameworkcode} => $marcxml)
1275 $t->post_ok("//$userid:$password@/api/v1/biblios" => {'Content-Type' => 'application/marc-in-json', 'x-framework-id' => $frameworkcode, 'x-confirm-not-duplicate' => 1} => $mij)
1279 $t->post_ok("//$userid:$password@/api/v1/biblios" => {'Content-Type' => 'application/marc', 'x-framework-id' => $frameworkcode} => $marc)
1283 $schema->storage->txn_rollback;
1286 subtest 'put() tests' => sub {
1290 $schema->storage->txn_begin;
1292 my $patron = $builder->build_object(
1294 class => 'Koha::Patrons',
1295 value => { flags => 0 } # no permissions
1298 my $password = 'thePassword123';
1299 $patron->set_password( { password => $password, skip_validation => 1 } );
1300 my $userid = $patron->userid;
1302 my $frameworkcode = 'BKS';
1303 my $biblio = $builder->build_sample_biblio({frameworkcode => $frameworkcode});
1305 my $biblionumber = $biblio->biblionumber;
1307 my $marcxml = q|<?xml version="1.0" encoding="UTF-8"?>
1309 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1310 xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd"
1311 xmlns="http://www.loc.gov/MARC21/slim">
1313 <leader>01102pam a2200289 a 6500</leader>
1314 <controlfield tag="001">2504398</controlfield>
1315 <controlfield tag="005">20200421093816.0</controlfield>
1316 <controlfield tag="008">920610s1993 caub s001 0 eng </controlfield>
1317 <datafield tag="010" ind1=" " ind2=" ">
1318 <subfield code="a"> 92021731 </subfield>
1320 <datafield tag="020" ind1=" " ind2=" ">
1321 <subfield code="a">05200784384 (Test json)</subfield>
1323 <datafield tag="020" ind1=" " ind2=" ">
1324 <subfield code="a">05200784464 (Test json)</subfield>
1326 <datafield tag="040" ind1=" " ind2=" ">
1327 <subfield code="a">DLC</subfield>
1328 <subfield code="c">DLC</subfield>
1329 <subfield code="d">DLC</subfield>
1331 <datafield tag="041" ind1="0" ind2=" ">
1332 <subfield code="a">enggrc</subfield>
1334 <datafield tag="050" ind1="0" ind2="0">
1335 <subfield code="a">PA522</subfield>
1336 <subfield code="b">.M38 1993</subfield>
1338 <datafield tag="082" ind1="0" ind2="0">
1339 <subfield code="a">480</subfield>
1340 <subfield code="2">20</subfield>
1342 <datafield tag="100" ind1="1" ind2=" ">
1343 <subfield code="a">Mastronarde, Donald J.</subfield>
1344 <subfield code="9">389</subfield>
1346 <datafield tag="245" ind1="1" ind2="0">
1347 <subfield code="a">Introduction to Attic Greek (Using marcxml) /</subfield>
1348 <subfield code="c">Donald J. Mastronarde.</subfield>
1350 <datafield tag="260" ind1=" " ind2=" ">
1351 <subfield code="a">Berkeley :</subfield>
1352 <subfield code="b">University of California Press,</subfield>
1353 <subfield code="c">c1993.</subfield>
1355 <datafield tag="300" ind1=" " ind2=" ">
1356 <subfield code="a">ix, 425 p. :</subfield>
1357 <subfield code="b">maps ;</subfield>
1358 <subfield code="c">26 cm.</subfield>
1360 <datafield tag="500" ind1=" " ind2=" ">
1361 <subfield code="a">Includes index.</subfield>
1363 <datafield tag="650" ind1=" " ind2="0">
1364 <subfield code="a">Attic Greek dialect</subfield>
1365 <subfield code="9">7</subfield>
1367 <datafield tag="856" ind1="4" ind2="2">
1368 <subfield code="3">Contributor biographical information</subfield>
1369 <subfield code="u">http://www.loc.gov/catdir/bios/ucal051/92021731.html</subfield>
1371 <datafield tag="856" ind1="4" ind2="2">
1372 <subfield code="3">Publisher description</subfield>
1373 <subfield code="u">http://www.loc.gov/catdir/description/ucal041/92021731.html</subfield>
1375 <datafield tag="906" ind1=" " ind2=" ">
1376 <subfield code="a">7</subfield>
1377 <subfield code="b">cbc</subfield>
1378 <subfield code="c">orignew</subfield>
1379 <subfield code="d">1</subfield>
1380 <subfield code="e">ocip</subfield>
1381 <subfield code="f">19</subfield>
1382 <subfield code="g">y-gencatlg</subfield>
1384 <datafield tag="942" ind1=" " ind2=" ">
1385 <subfield code="2">ddc</subfield>
1386 <subfield code="c">BK</subfield>
1388 <datafield tag="955" ind1=" " ind2=" ">
1389 <subfield code="a">pc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93</subfield>
1391 <datafield tag="999" ind1=" " ind2=" ">
1392 <subfield code="c">3</subfield>
1393 <subfield code="d">3</subfield>
1403 "005": "20200421093816.0"
1406 "008": "920610s1993 caub s001 0 eng "
1423 "a": "05200784382 (Test mij)"
1434 "a": "05200784462 (Test mij)"
1502 "a": "Mastronarde, Donald J."
1516 "a": "Introduction to Attic Greek (Using mij) /"
1519 "c": "Donald J. Mastronarde."
1532 "b": "University of California Press,"
1563 "a": "Includes index."
1574 "a": "Attic Greek dialect"
1588 "3": "Contributor biographical information"
1591 "u": "http://www.loc.gov/catdir/bios/ucal051/92021731.html"
1603 "3": "Publisher description"
1606 "u": "http://www.loc.gov/catdir/description/ucal041/92021731.html"
1659 "a": "pc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93"
1681 "leader": "01102pam a2200289 a 8500"
1683 my $marc = q|01116pam a2200289 a 4500001000800000005001700008008004100025010001700066020002800083020002800111040001800139041001100157050002100168082001200189100003200201245007500233260005600308300003300364500002000397650002700417856009500444856008700539906004500626942001200671955013000683999001300813
\1e2504398
\1e20221223213433.0
\1e920610s1993 caub s001 0 eng
\1e \1fa 92021731
\1e \1fa05200784384 (Test json)
\1e \1fa05200784464 (Test json)
\1e \1faDLC
\1fcDLC
\1fdDLC
\1e0
\1faenggrc
\1e00
\1faPA522
\1fb.M38 1993
\1e00
\1fa480
\1f220
\1e1
\1faMastronarde, Donald J.
\1f9389
\1e10
\1faIntroduction to Attic Greek (Using usmarc) /
\1fcDonald J. Mastronarde.
\1e \1faBerkeley :
\1fbUniversity of California Press,
\1fcc1993.
\1e \1faix, 425 p. :
\1fbmaps ;
\1fc26 cm.
\1e \1faIncludes index.
\1e 0
\1faAttic Greek dialect
\1f97
\1e42
\1f3Contributor biographical information
\1fuhttp://www.loc.gov/catdir/bios/ucal051/92021731.html
\1e42
\1f3Publisher description
\1fuhttp://www.loc.gov/catdir/description/ucal041/92021731.html
\1e \1fa7
\1fbcbc
\1fcorignew
\1fd1
\1feocip
\1ff19
\1fgy-gencatlg
\1e \1f2ddc
\1fcBK
\1e \1fapc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93
\1e \1fc715
\1fd715
\1e\1d|;
1685 $t->put_ok("//$userid:$password@/api/v1/biblios/$biblionumber")
1686 ->status_is(403, 'Not enough permissions makes it return the right code');
1691 source => 'UserPermission',
1693 borrowernumber => $patron->borrowernumber,
1695 code => 'edit_catalogue'
1700 $t->put_ok("//$userid:$password@/api/v1/biblios/$biblionumber" => {'Content-Type' => 'application/marcxml+xml', 'x-framework-id' => $frameworkcode} => $marcxml)
1704 $biblio = Koha::Biblios->find($biblionumber);
1706 is($biblio->title, 'Introduction to Attic Greek (Using marcxml) /');
1708 $t->put_ok("//$userid:$password@/api/v1/biblios/$biblionumber" => {'Content-Type' => 'application/marc-in-json', 'x-framework-id' => $frameworkcode} => $mij)
1712 $biblio = Koha::Biblios->find($biblionumber);
1714 is($biblio->title, 'Introduction to Attic Greek (Using mij) /');
1716 $t->put_ok("//$userid:$password@/api/v1/biblios/$biblionumber" => {'Content-Type' => 'application/marc', 'x-framework-id' => $frameworkcode} => $marc)
1720 $biblio = Koha::Biblios->find($biblionumber);
1722 is($biblio->title, 'Introduction to Attic Greek (Using usmarc) /');
1724 $schema->storage->txn_rollback;
1727 subtest 'list() tests' => sub {
1731 $schema->storage->txn_begin;
1733 my $patron = $builder->build_object(
1735 class => 'Koha::Patrons',
1736 value => { flags => 0 }
1739 my $password = 'thePassword123';
1740 $patron->set_password( { password => $password, skip_validation => 1 } );
1741 $patron->discard_changes;
1742 my $userid = $patron->userid;
1744 t::lib::Mocks::mock_preference('marcflavour', 'UNIMARC');
1746 my $title_with_diacritics = "L'insoutenable légèreté de l'être";
1747 my $biblio = $builder->build_sample_biblio(
1749 title => $title_with_diacritics,
1750 author => "Milan Kundera"
1754 my $record = $biblio->metadata->record;
1755 $record->leader(' nam 3 4500');
1756 $biblio->metadata->metadata($record->as_xml_record('UNIMARC'))->store;
1758 my $biblio_id_1 = $biblio->id;
1760 t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
1761 my $biblio_id_2 = $builder->build_sample_biblio->id;
1763 my $query = encode_json( [ { biblio_id => $biblio_id_1 }, { biblio_id => $biblio_id_2 } ] );
1765 $t->get_ok("//$userid:$password@/api/v1/biblios?q=$query")->status_is(403);
1767 $patron->flags(4)->store;
1769 $t->get_ok( "//$userid:$password@/api/v1/biblios?q=$query" => { Accept => 'application/weird+format' } )
1772 $t->get_ok( "//$userid:$password@/api/v1/biblios?q=$query" => { Accept => 'application/json' } )->status_is(200);
1774 my $result = $t->get_ok( "//$userid:$password@/api/v1/biblios?q=$query" => { Accept => 'application/marcxml+xml' } )
1775 ->status_is(200)->tx->res->body;
1777 my $encoded_title = Encode::encode( "UTF-8", $title_with_diacritics );
1778 like( $result, qr/\Q$encoded_title/, "The title is not double encoded" );
1780 $t->get_ok( "//$userid:$password@/api/v1/biblios?q=$query" => { Accept => 'application/marc-in-json' } )
1783 $t->get_ok( "//$userid:$password@/api/v1/biblios?q=$query" => { Accept => 'application/marc' } )->status_is(200);
1785 $t->get_ok( "//$userid:$password@/api/v1/biblios?q=$query" => { Accept => 'text/plain' } )->status_is(200);
1787 # DELETE any biblio with ISBN = TOMAS
1788 Koha::Biblios->search({ 'biblioitem.isbn' => 'TOMAS' }, { join => [ 'biblioitem' ] })
1792 my $isbn_query = encode_json({ isbn => 'TOMAS' });
1793 $biblio->biblioitem->set({ isbn => 'TOMAS' })->store;
1794 $t->get_ok( "//$userid:$password@/api/v1/biblios?q=$isbn_query" =>
1795 { Accept => 'text/plain' } )
1798 $schema->storage->txn_rollback;
1801 subtest 'add_item() tests' => sub {
1804 $schema->storage->txn_begin;
1806 my $patron = $builder->build_object(
1808 class => 'Koha::Patrons',
1809 value => { flags => 0 }
1812 my $password = 'thePassword123';
1813 $patron->set_password( { password => $password, skip_validation => 1 } );
1814 my $userid = $patron->userid;
1816 my $biblio = $builder->build_sample_biblio();
1817 my $biblio_id = $biblio->biblionumber;
1819 my $barcode = 'mybarcode';
1820 my $matching_items = Koha::Items->search({ barcode => $barcode });
1822 while (my $item = $matching_items->next) {
1826 $t->post_ok("//$userid:$password@/api/v1/biblios/$biblio_id/items" => json => { external_id => $barcode })
1827 ->status_is(403, 'Not enough permissions to create an item');
1832 source => 'UserPermission',
1834 borrowernumber => $patron->borrowernumber,
1836 code => 'edit_catalogue'
1841 $t->post_ok("//$userid:$password@/api/v1/biblios/$biblio_id/items" => json => {
1842 external_id => $barcode,
1844 ->status_is(201, 'Item created')
1845 ->json_is('/biblio_id', $biblio_id);
1847 my $item = $builder->build_sample_item();
1849 $t->post_ok("//$userid:$password@/api/v1/biblios/$biblio_id/items" => json => {
1850 external_id => $item->barcode,
1852 ->status_is(409, 'Duplicate barcode');
1854 $schema->storage->txn_rollback;
1857 subtest 'update_item() tests' => sub {
1860 $schema->storage->txn_begin;
1862 my $patron = $builder->build_object(
1864 class => 'Koha::Patrons',
1865 value => { flags => 0 }
1868 my $password = 'thePassword123';
1869 $patron->set_password( { password => $password, skip_validation => 1 } );
1870 my $userid = $patron->userid;
1872 my $item = $builder->build_sample_item({ replacementprice => 5 });
1873 my $biblio_id = $item->biblionumber;
1874 my $item_id = $item->itemnumber;
1876 my $biblio = Koha::Biblios->find($item->biblionumber);
1878 my $matching_items = Koha::Items->search({ barcode => $item->barcode });
1880 while (my $mbcitem = $matching_items->next) {
1881 $mbcitem->delete if $mbcitem->biblionumber != $item->biblionumber;
1884 $t->put_ok("//$userid:$password@/api/v1/biblios/$biblio_id/items/$item_id" => json => { external_id => 'something' })
1885 ->status_is(403, 'Not enough permissions to update an item');
1890 source => 'UserPermission',
1892 borrowernumber => $patron->borrowernumber,
1894 code => 'edit_catalogue'
1899 my $other_item = $builder->build_sample_item();
1901 $t->put_ok("//$userid:$password@/api/v1/biblios/$biblio_id/items/$item_id" => json => {
1902 external_id => $other_item->barcode,
1904 ->status_is(409, 'Barcode not unique');
1906 $t->put_ok("//$userid:$password@/api/v1/biblios/$biblio_id/items/$item_id" => json => {
1907 replacement_price => 30,
1909 ->status_is(200, 'Item updated')
1910 ->json_is('/replacement_price', 30);
1912 $schema->storage->txn_rollback;
1915 subtest 'merge() tests' => sub {
1917 $schema->storage->txn_begin;
1925 "005": "20200421093816.0"
1928 "008": "920610s1993 caub s001 0 eng "
1945 "a": "05200784462 (Test mij)"
1999 "a": "Mastronarde, Donald J."
2013 "a": "Introduction to Attic Greek (Using mij) /"
2016 "c": "Donald J. Mastronarde."
2029 "b": "University of California Press,"
2060 "a": "Attic Greek dialect"
2088 "a": "pc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93"
2110 "leader": "01102pam a2200289 a 8500"
2113 my $patron = $builder->build_object(
2115 class => 'Koha::Patrons',
2116 value => { flags => 0 }
2119 my $password = 'thePassword123';
2120 $patron->set_password( { password => $password, skip_validation => 1 } );
2121 my $userid = $patron->userid;
2123 my $title_1 = 'Title number 1';
2124 my $title_2 = 'Title number 2';
2125 my $biblio1 = $builder->build_sample_biblio( { title => $title_1 } );
2126 my $biblio2 = $builder->build_sample_biblio( { title => $title_2 } );
2127 my $biblio_id1 = $biblio1->biblionumber;
2128 my $biblio_id2 = $biblio2->biblionumber;
2129 my $json_input1 = '{ "biblio_id_to_merge": "' . $biblio_id2 . '" }';
2131 $t->post_ok( "//$userid:$password@/api/v1/biblios/$biblio_id1/merge" =>
2132 { 'Content-Type' => 'application/json', 'Accept' => 'application/marc-in-json' } => $json_input1 )
2133 ->status_is( 403, 'Not enough permissions to merge two bib records' );
2136 $patron->flags(516)->store;
2139 "//$userid:$password@/api/v1/biblios/$biblio_id1/merge" => { 'Content-Type' => 'application/weird+format' } =>
2140 $json_input1 )->status_is( 400, 'Not correct headers' );
2143 $t->post_ok( "//$userid:$password@/api/v1/biblios/$biblio_id1/merge" =>
2144 { 'Content-Type' => 'application/json', 'Accept' => 'application/marc-in-json' } => $json_input1 )
2145 ->status_is(200)->tx->res->body;
2146 like( $result, qr/$title_1/, "Merged record has the correct title" );
2147 unlike( $result, qr/$title_2/, "Merged record doesn't have the wrong title" );
2149 my $biblio3 = $builder->build_sample_biblio( { title => 'Title number 3' } );
2150 my $biblio_id3 = $biblio3->biblionumber;
2151 my $json_input2 = '{ "biblio_id_to_merge": "' . $biblio_id3 . '",
2152 "rules": "override_ext",
2153 "datarecord": ' . $mij_rec . ' }';
2155 $t->post_ok( "//$userid:$password@/api/v1/biblios/$biblio_id1/merge" =>
2156 { 'Content-Type' => 'application/json', 'Accept' => 'application/marc-in-json' } => $json_input2 )
2157 ->status_is(200)->tx->res->body;
2158 like( $result, qr/Using mij/, "Update with Marc-in-json record" );
2159 unlike( $result, qr/$title_1/, "Change all record with dat in the 'datarecord' field" );
2161 $schema->storage->txn_rollback;