From bc5fc3c593efa7ef7b506dd1ccc72a641d40faa5 Mon Sep 17 00:00:00 2001 From: Jake Deery Date: Tue, 2 Dec 2025 09:16:05 +0000 Subject: [PATCH] reword! test suite for bug_14962 --- t/db_dependent/Circulation/Displays.t | 198 +++++++++++ t/db_dependent/Koha/DisplayItems.t | 262 ++++++++++++++ t/db_dependent/Koha/Displays.t | 174 ++++++++++ t/db_dependent/api/v1/displayitems.t | 477 ++++++++++++++++++++++++++ t/db_dependent/api/v1/displays.t | 411 ++++++++++++++++++++++ t/db_dependent/api/v1/items.t | 83 ++++- 6 files changed, 1604 insertions(+), 1 deletion(-) create mode 100644 t/db_dependent/Circulation/Displays.t create mode 100644 t/db_dependent/Koha/DisplayItems.t create mode 100644 t/db_dependent/Koha/Displays.t create mode 100644 t/db_dependent/api/v1/displayitems.t create mode 100644 t/db_dependent/api/v1/displays.t diff --git a/t/db_dependent/Circulation/Displays.t b/t/db_dependent/Circulation/Displays.t new file mode 100644 index 00000000000..5ac09bc08b1 --- /dev/null +++ b/t/db_dependent/Circulation/Displays.t @@ -0,0 +1,198 @@ +#!/usr/bin/perl + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::More tests => 3; +use Test::NoWarnings; + +use C4::Circulation qw( AddIssue AddReturn ); +use Koha::Database; +use Koha::DateUtils qw( dt_from_string ); + +use t::lib::TestBuilder; +use t::lib::Mocks; + +my $schema = Koha::Database->new->schema; +$schema->storage->txn_begin; + +my $builder = t::lib::TestBuilder->new; + +t::lib::Mocks::mock_preference( 'UseDisplayModule', 1 ); + +subtest 'display_return_over - yes - any library' => sub { + plan tests => 5; + + # Create test data + my $library1 = $builder->build_object( { class => 'Koha::Libraries' } ); + my $library2 = $builder->build_object( { class => 'Koha::Libraries' } ); + my $patron = + $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $library1->branchcode } } ); + my $item = + $builder->build_sample_item( { homebranch => $library1->branchcode, holdingbranch => $library1->branchcode } ); + + # Mock userenv + t::lib::Mocks::mock_userenv( { branchcode => $library1->branchcode } ); + + # Create a display with 'yes - any library' return_over setting + my $display = $builder->build_object( + { + class => 'Koha::Displays', + value => { + display_return_over => 'yes - any library', + enabled => 1, + start_date => undef, + end_date => undef, + } + } + ); + + # Add item to display + my $display_item = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display->display_id, + itemnumber => $item->itemnumber, + biblionumber => $item->biblionumber, + } + } + ); + + # Verify item is in display + my $active_display = $item->active_display_item; + ok( defined $active_display, 'Item should have an active display item' ); + is( $active_display->display_id, $display->display_id, 'Display item should be linked to the correct display' ); + + # Issue the item + AddIssue( $patron, $item->barcode ); + + # Return the item at the home library + my ( $doreturn, $messages, $issue, $borrower ) = AddReturn( $item->barcode, $library1->branchcode ); + is( $doreturn, 1, 'Item should be returned successfully' ); + ok( exists $messages->{RemovedFromDisplay}, 'RemovedFromDisplay message should be present' ); + + # Verify item was removed from display + $active_display = $item->active_display_item; + is( $active_display, undef, 'Item should no longer have an active display item after return' ); +}; + +subtest 'display_return_over - yes - except at home library' => sub { + plan tests => 9; + + # Create test data + my $library1 = $builder->build_object( { class => 'Koha::Libraries' } ); + my $library2 = $builder->build_object( { class => 'Koha::Libraries' } ); + my $patron = + $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $library1->branchcode } } ); + + # Mock userenv + t::lib::Mocks::mock_userenv( { branchcode => $library1->branchcode } ); + + # Test 1: Return at non-home library should remove from display + my $item1 = + $builder->build_sample_item( { homebranch => $library1->branchcode, holdingbranch => $library1->branchcode } ); + + my $display1 = $builder->build_object( + { + class => 'Koha::Displays', + value => { + display_return_over => 'yes - except at home library', + enabled => 1, + start_date => undef, + end_date => undef, + } + } + ); + + my $display_item1 = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display1->display_id, + itemnumber => $item1->itemnumber, + biblionumber => $item1->biblionumber, + } + } + ); + + my $active_display = $item1->active_display_item; + ok( defined $active_display, 'Item should have an active display item' ); + + AddIssue( $patron, $item1->barcode ); + my ( $doreturn, $messages, $issue, $borrower ) = AddReturn( $item1->barcode, $library2->branchcode ); + + is( $doreturn, 1, 'Item should be returned successfully at non-home library' ); + ok( + exists $messages->{RemovedFromDisplay}, + 'RemovedFromDisplay message should be present when returned at non-home library' + ); + + $active_display = $item1->active_display_item; + is( $active_display, undef, 'Item should be removed from display when returned at non-home library' ); + + # Test 2: Return at home library should NOT remove from display + my $item2 = + $builder->build_sample_item( { homebranch => $library1->branchcode, holdingbranch => $library1->branchcode } ); + + my $display2 = $builder->build_object( + { + class => 'Koha::Displays', + value => { + display_return_over => 'yes - except at home library', + enabled => 1, + start_date => undef, + end_date => undef, + } + } + ); + + my $display_item2 = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display2->display_id, + itemnumber => $item2->itemnumber, + biblionumber => $item2->biblionumber, + } + } + ); + + $active_display = $item2->active_display_item; + ok( defined $active_display, 'Item should have an active display item before return' ); + + AddIssue( $patron, $item2->barcode ); + ( $doreturn, $messages, $issue, $borrower ) = AddReturn( $item2->barcode, $library1->branchcode ); + + is( $doreturn, 1, 'Item should be returned successfully at home library' ); + ok( + !exists $messages->{RemovedFromDisplay}, + 'RemovedFromDisplay message should NOT be present when returned at home library' + ); + + $active_display = $item2->active_display_item; + ok( defined $active_display, 'Item should still have an active display item when returned at home library' ); + is( + $active_display->display_id, $display2->display_id, + 'Display item should still be linked to the correct display' + ); + + # Clean up + $display_item2->delete; +}; + +$schema->storage->txn_rollback; diff --git a/t/db_dependent/Koha/DisplayItems.t b/t/db_dependent/Koha/DisplayItems.t new file mode 100644 index 00000000000..9efbf102bc3 --- /dev/null +++ b/t/db_dependent/Koha/DisplayItems.t @@ -0,0 +1,262 @@ +#!/usr/bin/perl + +# Copyright 2025 Koha Development team +# +# This file is part of Koha +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::NoWarnings; +use Test::More tests => 13; + +use DateTime; +use C4::Context; +use Koha::DisplayItem; +use Koha::DisplayItems; +use Koha::Database; + +use t::lib::TestBuilder; + +my $schema = Koha::Database->new->schema; +$schema->storage->txn_begin; + +my $builder = t::lib::TestBuilder->new; +my $nb_of_display_items = Koha::DisplayItems->search->count; + +# Create test data +my $library = $builder->build( { source => 'Branch' } ); +my $biblio = $builder->build( { source => 'Biblio' } ); +my $item1 = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } ); +my $item2 = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } ); + +my $display = $builder->build( { source => 'Display', value => { display_branch => $library->{branchcode} } } ); + +# Create display items for testing +my $new_display_item_1 = Koha::DisplayItem->new( + { + display_id => $display->{display_id}, + itemnumber => $item1->{itemnumber}, + biblionumber => $biblio->{biblionumber}, + date_added => '2024-01-01', + date_remove => '2024-12-31', + } +)->store; + +my $new_display_item_2 = Koha::DisplayItem->new( + { + display_id => $display->{display_id}, + itemnumber => $item2->{itemnumber}, + biblionumber => $biblio->{biblionumber}, + date_added => '2024-02-01', + date_remove => '2024-11-30', + } +)->store; + +# Test basic CRUD operations +like( $new_display_item_1->display_id, qr|^\d+$|, 'Adding a new display item should have set the display_id' ); +is( Koha::DisplayItems->search->count, $nb_of_display_items + 2, 'The 2 display items should have been added' ); + +my $retrieved_display_item_1 = Koha::DisplayItems->find( + { + display_id => $new_display_item_1->display_id, + itemnumber => $new_display_item_1->itemnumber + } +); +is( + $retrieved_display_item_1->biblionumber, $new_display_item_1->biblionumber, + 'Find a display item by composite key should return the correct display item' +); + +# Test Koha::DisplayItem methods +subtest 'display method' => sub { + plan tests => 2; + + my $display_obj = $new_display_item_1->display; + isa_ok( $display_obj, 'Koha::Display', 'display should return a Koha::Display object' ); + is( $display_obj->display_id, $display->{display_id}, 'display should return the correct display' ); +}; + +subtest 'item method' => sub { + plan tests => 2; + + my $item_obj = $new_display_item_1->item; + isa_ok( $item_obj, 'Koha::Item', 'item should return a Koha::Item object' ); + is( $item_obj->itemnumber, $item1->{itemnumber}, 'item should return the correct item' ); +}; + +subtest 'biblio method' => sub { + plan tests => 2; + + my $biblio_obj = $new_display_item_1->biblio; + isa_ok( $biblio_obj, 'Koha::Biblio', 'biblio should return a Koha::Biblio object' ); + is( $biblio_obj->biblionumber, $biblio->{biblionumber}, 'biblio should return the correct biblio' ); +}; + +# Test Koha::DisplayItems methods +subtest 'for_display method' => sub { + plan tests => 2; + + my $display_items = Koha::DisplayItems->for_display( $display->{display_id} ); + isa_ok( $display_items, 'Koha::DisplayItems', 'for_display should return a Koha::DisplayItems object' ); + is( $display_items->count, 2, 'for_display should return the correct number of display items' ); +}; + +subtest 'for_item method' => sub { + plan tests => 2; + + my $display_items = Koha::DisplayItems->for_item( $item1->{itemnumber} ); + isa_ok( $display_items, 'Koha::DisplayItems', 'for_item should return a Koha::DisplayItems object' ); + is( $display_items->count, 1, 'for_item should return the correct number of display items' ); +}; + +subtest 'for_biblio method' => sub { + plan tests => 2; + + my $display_items = Koha::DisplayItems->for_biblio( $biblio->{biblionumber} ); + isa_ok( $display_items, 'Koha::DisplayItems', 'for_biblio should return a Koha::DisplayItems object' ); + is( $display_items->count, 2, 'for_biblio should return the correct number of display items' ); +}; + +subtest 'due_for_removal method' => sub { + plan tests => 3; + + # Create a display item that should be removed today + my $today = DateTime->today->ymd; + my $item_to_remove = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } ); + + my $display_item_due = Koha::DisplayItem->new( + { + display_id => $display->{display_id}, + itemnumber => $item_to_remove->{itemnumber}, + biblionumber => $biblio->{biblionumber}, + date_added => '2024-01-01', + date_remove => $today, + } + )->store; + + my $due_items = Koha::DisplayItems->due_for_removal; + isa_ok( $due_items, 'Koha::DisplayItems', 'due_for_removal should return a Koha::DisplayItems object' ); + + my $found_due_item = 0; + while ( my $item = $due_items->next ) { + $found_due_item = 1 if $item->itemnumber == $item_to_remove->{itemnumber}; + } + ok( $found_due_item, 'due_for_removal should include items due for removal today' ); + + # Create a display item that should be removed in the future + my $future_date = DateTime->today->add( days => 30 )->ymd; + my $item_future = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } ); + + my $display_item_future = Koha::DisplayItem->new( + { + display_id => $display->{display_id}, + itemnumber => $item_future->{itemnumber}, + biblionumber => $biblio->{biblionumber}, + date_added => '2024-01-01', + date_remove => $future_date, + } + )->store; + + my $due_items_2 = Koha::DisplayItems->due_for_removal; + my $found_future_item = 0; + while ( my $item = $due_items_2->next ) { + $found_future_item = 1 if $item->itemnumber == $item_future->{itemnumber}; + } + ok( !$found_future_item, 'due_for_removal should not include items due for removal in the future' ); + + # Clean up the additional display items + $display_item_due->delete; + $display_item_future->delete; +}; + +subtest 'display_days automatic date_remove calculation' => sub { + plan tests => 5; + + # Create a display with display_days set to 30 + my $display_with_days = $builder->build_object( + { + class => 'Koha::Displays', + value => { display_days => 30 } + } + ); + + my $item3 = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } ); + + # Create display item without date_remove - should auto-calculate + my $display_item_auto = Koha::DisplayItem->new( + { + display_id => $display_with_days->display_id, + itemnumber => $item3->{itemnumber}, + biblionumber => $biblio->{biblionumber}, + } + )->store; + + ok( defined $display_item_auto->date_remove, 'date_remove should be set automatically' ); + + # Calculate expected date (today + 30 days) + my $dt = DateTime->now( time_zone => C4::Context->tz() ); + $dt->add( days => 30 ); + my $expected_date = $dt->ymd; + is( $display_item_auto->date_remove, $expected_date, 'date_remove should be today + display_days' ); + + # Create display item with explicit date_remove - should NOT auto-calculate + my $item4 = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } ); + my $manual_date = '2025-12-31'; + my $display_item_manual = Koha::DisplayItem->new( + { + display_id => $display_with_days->display_id, + itemnumber => $item4->{itemnumber}, + biblionumber => $biblio->{biblionumber}, + date_remove => $manual_date, + } + )->store; + + is( $display_item_manual->date_remove, $manual_date, 'Explicit date_remove should not be overridden' ); + + # Create display without display_days - date_remove should be NULL + my $display_no_days = $builder->build_object( + { + class => 'Koha::Displays', + value => { display_days => undef } + } + ); + my $item5 = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } ); + + my $display_item_no_days = Koha::DisplayItem->new( + { + display_id => $display_no_days->display_id, + itemnumber => $item5->{itemnumber}, + biblionumber => $biblio->{biblionumber}, + } + )->store; + + is( $display_item_no_days->date_remove, undef, 'date_remove should be NULL when display has no display_days' ); + + # Clean up + $display_item_auto->delete; + $display_item_manual->delete; + $display_item_no_days->delete; + $display_with_days->delete; + $display_no_days->delete; + + pass('Cleanup successful'); +}; + +# Test delete +$retrieved_display_item_1->delete; +is( Koha::DisplayItems->search->count, $nb_of_display_items + 1, 'Delete should have deleted the display item' ); + +$schema->storage->txn_rollback; diff --git a/t/db_dependent/Koha/Displays.t b/t/db_dependent/Koha/Displays.t new file mode 100644 index 00000000000..96b9fa38584 --- /dev/null +++ b/t/db_dependent/Koha/Displays.t @@ -0,0 +1,174 @@ +#!/usr/bin/perl + +# Copyright 2025 Koha Development team +# +# This file is part of Koha +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::NoWarnings; +use Test::More tests => 10; + +use DateTime; +use Koha::Display; +use Koha::Displays; +use Koha::Database; + +use t::lib::TestBuilder; + +my $schema = Koha::Database->new->schema; +$schema->storage->txn_begin; + +my $builder = t::lib::TestBuilder->new; +my $nb_of_displays = Koha::Displays->search->count; + +# Create a library for testing display_branch +my $library = $builder->build( { source => 'Branch' } ); + +# Create item types for testing +my $itemtype1 = $builder->build( { source => 'Itemtype' } ); +my $itemtype2 = $builder->build( { source => 'Itemtype' } ); + +# Get current date for testing +my $today = DateTime->today; +my $yesterday = $today->clone->subtract( days => 1 ); +my $tomorrow = $today->clone->add( days => 1 ); + +# Create displays for testing +my $new_display_1 = Koha::Display->new( + { + display_name => 'my_display_name_for_test_1', + enabled => 1, + display_return_over => 'no', + start_date => $yesterday->ymd, + end_date => $tomorrow->ymd, + display_location => 'DISPLAY_LOC_1', + display_code => 'DISPLAY_CODE_1', + display_branch => $library->{branchcode}, + display_itype => $itemtype1->{itemtype}, + } +)->store; + +my $new_display_2 = Koha::Display->new( + { + display_name => 'my_display_name_for_test_2', + enabled => 0, + display_return_over => 'yes - any library', + display_location => 'DISPLAY_LOC_2', + display_code => 'DISPLAY_CODE_2', + display_itype => $itemtype2->{itemtype}, + } +)->store; + +# Test basic CRUD operations +like( $new_display_1->display_id, qr|^\d+$|, 'Adding a new display should have set the display_id' ); +is( Koha::Displays->search->count, $nb_of_displays + 2, 'The 2 displays should have been added' ); + +my $retrieved_display_1 = Koha::Displays->find( $new_display_1->display_id ); +is( + $retrieved_display_1->display_name, $new_display_1->display_name, + 'Find a display by id should return the correct display' +); + +# Test Koha::Display methods +subtest 'display_items method' => sub { + plan tests => 2; + + my $display_items = $new_display_1->display_items; + isa_ok( $display_items, 'Koha::DisplayItems', 'display_items should return a Koha::DisplayItems object' ); + is( $display_items->count, 0, 'New display should have no display items' ); +}; + +subtest 'library method' => sub { + plan tests => 3; + + my $library_obj = $new_display_1->library; + isa_ok( $library_obj, 'Koha::Library', 'library should return a Koha::Library object' ); + is( $library_obj->branchcode, $library->{branchcode}, 'library should return the correct library' ); + + # Test display without library + is( $new_display_2->library, undef, 'display without library should return undef' ); +}; + +# Test Koha::Displays methods +subtest 'enabled method' => sub { + plan tests => 2; + + my $enabled_displays = Koha::Displays->enabled; + isa_ok( $enabled_displays, 'Koha::Displays', 'enabled should return a Koha::Displays object' ); + + my $found_enabled = 0; + while ( my $display = $enabled_displays->next ) { + $found_enabled = 1 if $display->display_id == $new_display_1->display_id; + } + ok( $found_enabled, 'enabled displays should include the enabled display' ); +}; + +subtest 'for_branch method' => sub { + plan tests => 2; + + my $branch_displays = Koha::Displays->for_branch( $library->{branchcode} ); + isa_ok( $branch_displays, 'Koha::Displays', 'for_branch should return a Koha::Displays object' ); + + my $found_branch_display = 0; + while ( my $display = $branch_displays->next ) { + $found_branch_display = 1 if $display->display_id == $new_display_1->display_id; + } + ok( $found_branch_display, 'for_branch should include displays for the specified branch' ); +}; + +subtest 'active method' => sub { + plan tests => 3; + + my $active_displays = Koha::Displays->active; + isa_ok( $active_displays, 'Koha::Displays', 'active should return a Koha::Displays object' ); + + my $found_active = 0; + while ( my $display = $active_displays->next ) { + $found_active = 1 if $display->display_id == $new_display_1->display_id; + } + ok( $found_active, 'active displays should include the active display within date range' ); + + # Create a display that's not active (dates in the past) + my $past_end = $today->clone->subtract( days => 10 ); + my $past_start = $today->clone->subtract( days => 20 ); + + my $inactive_display = Koha::Display->new( + { + display_name => 'inactive_display', + enabled => 1, + display_return_over => 'no', + start_date => $past_start->ymd, + end_date => $past_end->ymd, + } + )->store; + + my $active_displays_2 = Koha::Displays->active; + my $found_inactive = 0; + while ( my $display = $active_displays_2->next ) { + $found_inactive = 1 if $display->display_id == $inactive_display->display_id; + } + ok( !$found_inactive, 'active displays should not include displays outside date range' ); + + # Clean up the inactive display + $inactive_display->delete; +}; + +# Test delete +$retrieved_display_1->delete; +is( Koha::Displays->search->count, $nb_of_displays + 1, 'Delete should have deleted the display' ); + +$schema->storage->txn_rollback; diff --git a/t/db_dependent/api/v1/displayitems.t b/t/db_dependent/api/v1/displayitems.t new file mode 100644 index 00000000000..d775760a795 --- /dev/null +++ b/t/db_dependent/api/v1/displayitems.t @@ -0,0 +1,477 @@ +#!/usr/bin/env perl + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::NoWarnings; +use Test::More tests => 6; +use Test::Mojo; +use JSON; + +use t::lib::TestBuilder; +use t::lib::Mocks; + +use Koha::DisplayItems; +use Koha::Database; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +my $t = Test::Mojo->new('Koha::REST::V1'); +t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); + +subtest 'list() tests' => sub { + + plan tests => 20; + + $schema->storage->txn_begin; + + Koha::DisplayItems->search->delete; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + ## Authorized user tests + # No displayitems, so empty array should be returned + $t->get_ok("//$userid:$password@/api/v1/display/items")->status_is(200)->json_is( [] ); + + # Create test data + my $display = $builder->build_object( { class => 'Koha::Displays' } ); + my $biblio = $builder->build_sample_biblio(); + my $item = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } ); + + my $displayitem = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display->display_id, + itemnumber => $item->itemnumber, + biblionumber => $biblio->biblionumber + } + } + ); + + # One displayitem created, should get returned + $t->get_ok("//$userid:$password@/api/v1/display/items")->status_is(200)->json_is( [ $displayitem->to_api ] ); + + # Create another displayitem with same display + my $item2 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } ); + my $another_displayitem = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display->display_id, + itemnumber => $item2->itemnumber, + biblionumber => $biblio->biblionumber + } + } + ); + + # Create displayitem with different display + my $display2 = $builder->build_object( { class => 'Koha::Displays' } ); + my $item3 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } ); + my $displayitem_different_display = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display2->display_id, + itemnumber => $item3->itemnumber, + biblionumber => $biblio->biblionumber + } + } + ); + + # Three displayitems created, they should all be returned + $t->get_ok("//$userid:$password@/api/v1/display/items")->status_is(200)->json_is( + [ + $displayitem->to_api, + $another_displayitem->to_api, + $displayitem_different_display->to_api + ] + ); + + # Filtering works, two displayitems sharing display_id + $t->get_ok( "//$userid:$password@/api/v1/display/items?display_id=" . $display->display_id )->status_is(200) + ->json_is( + [ + $displayitem->to_api, + $another_displayitem->to_api + ] + ); + + $t->get_ok( "//$userid:$password@/api/v1/display/items?itemnumber=" . $item->itemnumber )->status_is(200) + ->json_is( [ $displayitem->to_api ] ); + + # Warn on unsupported query parameter + $t->get_ok("//$userid:$password@/api/v1/display/items?displayitem_blah=blah")->status_is(400) + ->json_is( [ { path => '/query/displayitem_blah', message => 'Malformed query string' } ] ); + + # Unauthorized access + $t->get_ok("//$unauth_userid:$password@/api/v1/display/items")->status_is(403); + + $schema->storage->txn_rollback; +}; + +subtest 'get() tests' => sub { + + plan tests => 11; + + $schema->storage->txn_begin; + + # Create test data + my $display = $builder->build_object( { class => 'Koha::Displays' } ); + my $biblio = $builder->build_sample_biblio(); + my $item = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } ); + + my $displayitem = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display->display_id, + itemnumber => $item->itemnumber, + biblionumber => $biblio->biblionumber + } + } + ); + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + $t->get_ok( + "//$userid:$password@/api/v1/display/items/" . $displayitem->display_id . "/" . $displayitem->itemnumber ) + ->status_is(200)->json_is( $displayitem->to_api ); + + $t->get_ok( "//$unauth_userid:$password@/api/v1/display/items/" + . $displayitem->display_id . "/" + . $displayitem->itemnumber )->status_is(403); + + # Create displayitem to delete + my $item_to_delete = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } ); + my $displayitem_to_delete = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display->display_id, + itemnumber => $item_to_delete->itemnumber, + biblionumber => $biblio->biblionumber + } + } + ); + my $non_existent_display_id = $displayitem_to_delete->display_id; + my $non_existent_item_id = $displayitem_to_delete->itemnumber; + $displayitem_to_delete->delete; + + $t->get_ok("//$userid:$password@/api/v1/display/items/$non_existent_display_id/$non_existent_item_id") + ->status_is(404)->json_is( '/error' => 'Display item not found' ); + + # Test with completely non-existent IDs + $t->get_ok("//$userid:$password@/api/v1/display/items/99999/99999")->status_is(404) + ->json_is( '/error' => 'Display item not found' ); + + $schema->storage->txn_rollback; +}; + +subtest 'add() tests' => sub { + + plan tests => 17; + + $schema->storage->txn_begin; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + # Create test data + my $display = $builder->build_object( { class => 'Koha::Displays' } ); + my $biblio = $builder->build_sample_biblio(); + my $item = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } ); + + my $displayitem = { + display_id => $display->display_id, + itemnumber => $item->itemnumber, + biblionumber => $biblio->biblionumber, + date_added => "2024-01-15", + date_remove => "2024-02-15" + }; + + # Unauthorized attempt to write + $t->post_ok( "//$unauth_userid:$password@/api/v1/display/items" => json => $displayitem )->status_is(403); + + # Authorized attempt to write invalid data + my $displayitem_with_invalid_field = { + blah => "DisplayItem Blah", + display_id => $display->display_id, + itemnumber => $item->itemnumber, + biblionumber => $biblio->biblionumber + }; + + $t->post_ok( "//$userid:$password@/api/v1/display/items" => json => $displayitem_with_invalid_field ) + ->status_is(400)->json_is( + "/errors" => [ + { + message => "Properties not allowed: blah.", + path => "/body" + } + ] + ); + + # Authorized attempt to write + $t->post_ok( "//$userid:$password@/api/v1/display/items" => json => $displayitem )->status_is( 201, 'REST3.2.1' ) + ->header_like( + Location => qr|^\/api\/v1\/display/items/\d+/\d+|, + 'REST3.4.1' + )->json_is( '/display_id' => $displayitem->{display_id} ) + ->json_is( '/itemnumber' => $displayitem->{itemnumber} ) + ->json_is( '/biblionumber' => $displayitem->{biblionumber} ) + ->json_is( '/date_added' => $displayitem->{date_added} ); + + # Test missing required field (display_id is required) + my $displayitem_missing_field = { + itemnumber => $item->itemnumber, + biblionumber => $biblio->biblionumber + + # Missing display_id (required field) + }; + + $t->post_ok( "//$userid:$password@/api/v1/display/items" => json => $displayitem_missing_field )->status_is(400) + ->json_has('/errors'); + + # Test successful creation with different item + my $item2 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } ); + my $displayitem2 = { + display_id => $display->display_id, + itemnumber => $item2->itemnumber, + biblionumber => $biblio->biblionumber, + date_added => "2024-01-16", + date_remove => "2024-02-16" + }; + $t->post_ok( "//$userid:$password@/api/v1/display/items" => json => $displayitem2 )->status_is(201); + + $schema->storage->txn_rollback; +}; + +subtest 'update() tests' => sub { + + plan tests => 15; + + $schema->storage->txn_begin; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + # Create test data + my $display = $builder->build_object( { class => 'Koha::Displays' } ); + my $biblio = $builder->build_sample_biblio(); + my $item = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } ); + + my $displayitem = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display->display_id, + itemnumber => $item->itemnumber, + biblionumber => $biblio->biblionumber + } + } + ); + + # Unauthorized attempt to update + $t->put_ok( "//$unauth_userid:$password@/api/v1/display/items/" + . $displayitem->display_id . "/" + . $displayitem->itemnumber => json => { date_added => '2024-01-20' } )->status_is(403); + + # Attempt partial update on a PUT (missing required field) + my $displayitem_with_missing_field = { + biblionumber => $biblio->biblionumber + + # Missing display_id and itemnumber (required fields) + }; + + $t->put_ok( "//$userid:$password@/api/v1/display/items/" + . $displayitem->display_id . "/" + . $displayitem->itemnumber => json => $displayitem_with_missing_field )->status_is(400) + ->json_has("/errors"); + + # Full object update on PUT + my $displayitem_with_updated_field = { + display_id => $display->display_id, + itemnumber => $item->itemnumber, + biblionumber => $biblio->biblionumber, + date_added => "2024-01-20", + date_remove => "2024-03-20" + }; + + $t->put_ok( "//$userid:$password@/api/v1/display/items/" + . $displayitem->display_id . "/" + . $displayitem->itemnumber => json => $displayitem_with_updated_field )->status_is(200) + ->json_is( '/date_added' => '2024-01-20' ); + + # Authorized attempt to write invalid data + my $displayitem_with_invalid_field = { + blah => "DisplayItem Blah", + display_id => $display->display_id, + itemnumber => $item->itemnumber, + biblionumber => $biblio->biblionumber + }; + + $t->put_ok( "//$userid:$password@/api/v1/display/items/" + . $displayitem->display_id . "/" + . $displayitem->itemnumber => json => $displayitem_with_invalid_field )->status_is(400)->json_is( + "/errors" => [ + { + message => "Properties not allowed: blah.", + path => "/body" + } + ] + ); + + # Test with non-existent displayitem + $t->put_ok( "//$userid:$password@/api/v1/display/items/99999/99999" => json => $displayitem_with_updated_field ) + ->status_is(404); + + # Wrong method (POST) + $t->post_ok( "//$userid:$password@/api/v1/display/items/" + . $displayitem->display_id . "/" + . $displayitem->itemnumber => json => $displayitem_with_updated_field )->status_is(404); + + $schema->storage->txn_rollback; +}; + +subtest 'delete() tests' => sub { + + plan tests => 7; + + $schema->storage->txn_begin; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + # Create test data + my $display = $builder->build_object( { class => 'Koha::Displays' } ); + my $biblio = $builder->build_sample_biblio(); + my $item = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } ); + + my $displayitem = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display->display_id, + itemnumber => $item->itemnumber, + biblionumber => $biblio->biblionumber + } + } + ); + + # Unauthorized attempt to delete + $t->delete_ok( "//$unauth_userid:$password@/api/v1/display/items/" + . $displayitem->display_id . "/" + . $displayitem->itemnumber )->status_is(403); + + $t->delete_ok( + "//$userid:$password@/api/v1/display/items/" . $displayitem->display_id . "/" . $displayitem->itemnumber ) + ->status_is( 204, 'REST3.2.4' )->content_is( '', 'REST3.3.4' ); + + $t->delete_ok( + "//$userid:$password@/api/v1/display/items/" . $displayitem->display_id . "/" . $displayitem->itemnumber ) + ->status_is(404); + + $schema->storage->txn_rollback; +}; diff --git a/t/db_dependent/api/v1/displays.t b/t/db_dependent/api/v1/displays.t new file mode 100644 index 00000000000..124a0709f77 --- /dev/null +++ b/t/db_dependent/api/v1/displays.t @@ -0,0 +1,411 @@ +#!/usr/bin/env perl + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::NoWarnings; +use Test::More tests => 7; +use Test::Mojo; +use JSON; + +use t::lib::TestBuilder; +use t::lib::Mocks; + +use Koha::Displays; +use Koha::Database; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +my $t = Test::Mojo->new('Koha::REST::V1'); +t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); + +subtest 'config() tests' => sub { + + plan tests => 5; + + $schema->storage->txn_begin; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + t::lib::Mocks::mock_preference( 'UseDisplayModule', 1 ); + + ## Authorized user tests + # No displays, so empty array should be returned + $t->get_ok("//$userid:$password@/api/v1/displays/config")->status_is(200) + ->json_is( { settings => { enabled => 1 } } ); + + # Unauthorized access + $t->get_ok("//$unauth_userid:$password@/api/v1/displays/config")->status_is(403); + + $schema->storage->txn_rollback; +}; + +subtest 'list() tests' => sub { + + plan tests => 20; + + $schema->storage->txn_begin; + + Koha::Displays->search->delete; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + ## Authorized user tests + # No displays, so empty array should be returned + $t->get_ok("//$userid:$password@/api/v1/displays")->status_is(200)->json_is( [] ); + + my $display = $builder->build_object( { class => 'Koha::Displays' } ); + + # One display created, should get returned + $t->get_ok("//$userid:$password@/api/v1/displays")->status_is(200)->json_is( [ $display->to_api ] ); + + my $another_display = + $builder->build_object( + { class => 'Koha::Displays', value => { display_branch => $display->display_branch } } ); + my $display_with_another_branch = $builder->build_object( { class => 'Koha::Displays' } ); + + # Three displays created, they should all be returned + $t->get_ok("//$userid:$password@/api/v1/displays")->status_is(200)->json_is( + [ + $display->to_api, + $another_display->to_api, + $display_with_another_branch->to_api + ] + ); + + # Filtering works, two displays sharing display_branch + $t->get_ok( "//$userid:$password@/api/v1/displays?display_branch=" . $display->display_branch )->status_is(200) + ->json_is( + [ + $display->to_api, + $another_display->to_api + ] + ); + + $t->get_ok( "//$userid:$password@/api/v1/displays?display_name=" . $display->display_name )->status_is(200) + ->json_is( [ $display->to_api ] ); + + # Warn on unsupported query parameter + $t->get_ok("//$userid:$password@/api/v1/displays?display_blah=blah")->status_is(400) + ->json_is( [ { path => '/query/display_blah', message => 'Malformed query string' } ] ); + + # Unauthorized access + $t->get_ok("//$unauth_userid:$password@/api/v1/displays")->status_is(403); + + $schema->storage->txn_rollback; +}; + +subtest 'get() tests' => sub { + + plan tests => 8; + + $schema->storage->txn_begin; + + my $display = $builder->build_object( { class => 'Koha::Displays' } ); + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + $t->get_ok( "//$userid:$password@/api/v1/displays/" . $display->display_id )->status_is(200) + ->json_is( $display->to_api ); + + $t->get_ok( "//$unauth_userid:$password@/api/v1/displays/" . $display->display_id )->status_is(403); + + my $display_to_delete = $builder->build_object( { class => 'Koha::Displays' } ); + my $non_existent_id = $display_to_delete->display_id; + $display_to_delete->delete; + + $t->get_ok("//$userid:$password@/api/v1/displays/$non_existent_id")->status_is(404) + ->json_is( '/error' => 'Display not found' ); + + $schema->storage->txn_rollback; +}; + +subtest 'add() tests' => sub { + + plan tests => 18; + + $schema->storage->txn_begin; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + my $itemtype = $builder->build_object( { class => 'Koha::ItemTypes' } ); + + my $display = { + display_name => "Test Display", + enabled => JSON::true, + display_return_over => "no", + start_date => "2024-01-01", + end_date => "2024-12-31", + display_location => "DISPLAY", + display_code => "TEST", + display_branch => "CPL", + display_itype => $itemtype->itemtype + }; + + # Unauthorized attempt to write + $t->post_ok( "//$unauth_userid:$password@/api/v1/displays" => json => $display )->status_is(403); + + # Authorized attempt to write invalid data + my $display_with_invalid_field = { + blah => "Display Blah", + display_name => "Test Display", + enabled => JSON::true, + display_return_over => "no" + }; + + $t->post_ok( "//$userid:$password@/api/v1/displays" => json => $display_with_invalid_field )->status_is(400) + ->json_is( + "/errors" => [ + { + message => "Properties not allowed: blah.", + path => "/body" + } + ] + ); + + # Authorized attempt to write + my $display_id = + $t->post_ok( "//$userid:$password@/api/v1/displays" => json => $display )->status_is( 201, 'REST3.2.1' ) + ->header_like( + Location => qr|^\/api\/v1\/displays/\d*|, + 'REST3.4.1' + )->json_is( '/display_name' => $display->{display_name} )->json_is( '/enabled' => $display->{enabled} ) + ->json_is( '/display_return_over' => $display->{display_return_over} ) + ->json_is( '/start_date' => $display->{start_date} )->tx->res->json->{display_id}; + + # Authorized attempt to create with null id + $display->{display_id} = undef; + $t->post_ok( "//$userid:$password@/api/v1/displays" => json => $display )->status_is(400)->json_has('/errors'); + + # Authorized attempt to create with existing id + $display->{display_id} = $display_id; + $t->post_ok( "//$userid:$password@/api/v1/displays" => json => $display )->status_is(400)->json_is( + "/errors" => [ + { + message => "Read-only.", + path => "/body/display_id" + } + ] + ); + + $schema->storage->txn_rollback; +}; + +subtest 'update() tests' => sub { + + plan tests => 15; + + $schema->storage->txn_begin; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + my $itemtype = $builder->build_object( { class => 'Koha::ItemTypes' } ); + + my $display_id = $builder->build_object( { class => 'Koha::Displays' } )->display_id; + + # Unauthorized attempt to update + $t->put_ok( "//$unauth_userid:$password@/api/v1/displays/$display_id" => json => + { display_name => 'New unauthorized name change' } )->status_is(403); + + # Attempt partial update on a PUT + my $display_with_missing_field = { + display_name => 'Updated Display', + enabled => JSON::false + }; + + $t->put_ok( "//$userid:$password@/api/v1/displays/$display_id" => json => $display_with_missing_field ) + ->status_is(400) + ->json_is( "/errors" => [ { message => "Missing property.", path => "/body/display_return_over" } ] ); + + # Full object update on PUT + my $display_with_updated_field = { + display_name => "Updated Display Name", + enabled => JSON::false, + display_return_over => "yes - any library", + start_date => "2024-02-01", + end_date => "2024-11-30", + display_location => "NEWDISPLAY", + display_code => "UPDATED", + display_branch => "CPL", + display_itype => $itemtype->itemtype + }; + + $t->put_ok( "//$userid:$password@/api/v1/displays/$display_id" => json => $display_with_updated_field ) + ->status_is(200)->json_is( '/display_name' => 'Updated Display Name' ); + + # Authorized attempt to write invalid data + my $display_with_invalid_field = { + blah => "Display Blah", + display_name => "Test Display", + enabled => JSON::true, + display_return_over => "no" + }; + + $t->put_ok( "//$userid:$password@/api/v1/displays/$display_id" => json => $display_with_invalid_field ) + ->status_is(400)->json_is( + "/errors" => [ + { + message => "Properties not allowed: blah.", + path => "/body" + } + ] + ); + + my $display_to_delete = $builder->build_object( { class => 'Koha::Displays' } ); + my $non_existent_id = $display_to_delete->display_id; + $display_to_delete->delete; + + $t->put_ok( "//$userid:$password@/api/v1/displays/$non_existent_id" => json => $display_with_updated_field ) + ->status_is(404); + + # Wrong method (POST) + $display_with_updated_field->{display_id} = 2; + + $t->post_ok( "//$userid:$password@/api/v1/displays/$display_id" => json => $display_with_updated_field ) + ->status_is(404); + + $schema->storage->txn_rollback; +}; + +subtest 'delete() tests' => sub { + + plan tests => 7; + + $schema->storage->txn_begin; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } # displays permission + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + my $display_id = $builder->build_object( { class => 'Koha::Displays' } )->display_id; + + # Unauthorized attempt to delete + $t->delete_ok("//$unauth_userid:$password@/api/v1/displays/$display_id")->status_is(403); + + $t->delete_ok("//$userid:$password@/api/v1/displays/$display_id")->status_is( 204, 'REST3.2.4' ) + ->content_is( '', 'REST3.3.4' ); + + $t->delete_ok("//$userid:$password@/api/v1/displays/$display_id")->status_is(404); + + $schema->storage->txn_rollback; +}; diff --git a/t/db_dependent/api/v1/items.t b/t/db_dependent/api/v1/items.t index 16975e74a28..0b7dd005fb5 100755 --- a/t/db_dependent/api/v1/items.t +++ b/t/db_dependent/api/v1/items.t @@ -19,8 +19,8 @@ use Modern::Perl; +use Test::More tests => 7; use Test::NoWarnings; -use Test::More tests => 6; use Test::MockModule; use Test::Mojo; use Test::Warn; @@ -601,3 +601,84 @@ subtest 'pickup_locations() tests' => sub { $schema->storage->txn_rollback; }; + +subtest 'effective display fields tests' => sub { + + plan tests => 12; + + $schema->storage->txn_begin; + + t::lib::Mocks::mock_preference( 'UseDisplayModule', 1 ); + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + # Create an item with specific location, collection code, homebranch, and holdingbranch + my $item = $builder->build_sample_item( + { + location => 'SHELF', + ccode => 'COLL1', + homebranch => $librarian->branchcode, + holdingbranch => $librarian->branchcode, + } + ); + + # Test without display - should return regular values + $t->get_ok( "//$userid:$password@/api/v1/items/" . $item->id )->status_is(200) + ->json_is( '/effective_location' => 'SHELF' )->json_is( '/effective_collection_code' => 'COLL1' ) + ->json_is( '/effective_home_library_id' => $librarian->branchcode ) + ->json_is( '/effective_holding_library_id' => $librarian->branchcode ); + + # Create a display with different values + my $display_library = $builder->build_object( { class => 'Koha::Libraries' } ); + my $display = $builder->build_object( + { + class => 'Koha::Displays', + value => { + display_location => 'DISPLAY', + display_code => 'DISPLAYCOLL', + display_branch => $display_library->branchcode, + display_holding_branch => $display_library->branchcode, + enabled => 1, + start_date => undef, + end_date => undef, + } + } + ); + + # Add item to display + my $display_item = $builder->build_object( + { + class => 'Koha::DisplayItems', + value => { + display_id => $display->display_id, + itemnumber => $item->itemnumber, + biblionumber => $item->biblionumber, + } + } + ); + + # Test with display - should return display values + $t->get_ok( "//$userid:$password@/api/v1/items/" . $item->id )->status_is(200) + ->json_is( '/effective_location' => 'DISPLAY' )->json_is( '/effective_collection_code' => 'DISPLAYCOLL' ) + ->json_is( '/effective_home_library_id' => $display_library->branchcode ) + ->json_is( '/effective_holding_library_id' => $display_library->branchcode ); + + $schema->storage->txn_rollback; +}; -- 2.50.1 (Apple Git-155)