View | Details | Raw Unified | Return to bug 14962
Collapse All | Expand All

(-)a/t/db_dependent/Circulation/Displays.t (+198 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More tests => 3;
21
use Test::NoWarnings;
22
23
use C4::Circulation qw( AddIssue AddReturn );
24
use Koha::Database;
25
use Koha::DateUtils qw( dt_from_string );
26
27
use t::lib::TestBuilder;
28
use t::lib::Mocks;
29
30
my $schema = Koha::Database->new->schema;
31
$schema->storage->txn_begin;
32
33
my $builder = t::lib::TestBuilder->new;
34
35
t::lib::Mocks::mock_preference( 'UseDisplayModule', 1 );
36
37
subtest 'display_return_over - yes - any library' => sub {
38
    plan tests => 5;
39
40
    # Create test data
41
    my $library1 = $builder->build_object( { class => 'Koha::Libraries' } );
42
    my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
43
    my $patron =
44
        $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $library1->branchcode } } );
45
    my $item =
46
        $builder->build_sample_item( { homebranch => $library1->branchcode, holdingbranch => $library1->branchcode } );
47
48
    # Mock userenv
49
    t::lib::Mocks::mock_userenv( { branchcode => $library1->branchcode } );
50
51
    # Create a display with 'yes - any library' return_over setting
52
    my $display = $builder->build_object(
53
        {
54
            class => 'Koha::Displays',
55
            value => {
56
                display_return_over => 'yes - any library',
57
                enabled             => 1,
58
                start_date          => undef,
59
                end_date            => undef,
60
            }
61
        }
62
    );
63
64
    # Add item to display
65
    my $display_item = $builder->build_object(
66
        {
67
            class => 'Koha::DisplayItems',
68
            value => {
69
                display_id   => $display->display_id,
70
                itemnumber   => $item->itemnumber,
71
                biblionumber => $item->biblionumber,
72
            }
73
        }
74
    );
75
76
    # Verify item is in display
77
    my $active_display = $item->active_display_item;
78
    ok( defined $active_display, 'Item should have an active display item' );
79
    is( $active_display->display_id, $display->display_id, 'Display item should be linked to the correct display' );
80
81
    # Issue the item
82
    AddIssue( $patron, $item->barcode );
83
84
    # Return the item at the home library
85
    my ( $doreturn, $messages, $issue, $borrower ) = AddReturn( $item->barcode, $library1->branchcode );
86
    is( $doreturn, 1, 'Item should be returned successfully' );
87
    ok( exists $messages->{RemovedFromDisplay}, 'RemovedFromDisplay message should be present' );
88
89
    # Verify item was removed from display
90
    $active_display = $item->active_display_item;
91
    is( $active_display, undef, 'Item should no longer have an active display item after return' );
92
};
93
94
subtest 'display_return_over - yes - except at home library' => sub {
95
    plan tests => 9;
96
97
    # Create test data
98
    my $library1 = $builder->build_object( { class => 'Koha::Libraries' } );
99
    my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
100
    my $patron =
101
        $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $library1->branchcode } } );
102
103
    # Mock userenv
104
    t::lib::Mocks::mock_userenv( { branchcode => $library1->branchcode } );
105
106
    # Test 1: Return at non-home library should remove from display
107
    my $item1 =
108
        $builder->build_sample_item( { homebranch => $library1->branchcode, holdingbranch => $library1->branchcode } );
109
110
    my $display1 = $builder->build_object(
111
        {
112
            class => 'Koha::Displays',
113
            value => {
114
                display_return_over => 'yes - except at home library',
115
                enabled             => 1,
116
                start_date          => undef,
117
                end_date            => undef,
118
            }
119
        }
120
    );
121
122
    my $display_item1 = $builder->build_object(
123
        {
124
            class => 'Koha::DisplayItems',
125
            value => {
126
                display_id   => $display1->display_id,
127
                itemnumber   => $item1->itemnumber,
128
                biblionumber => $item1->biblionumber,
129
            }
130
        }
131
    );
132
133
    my $active_display = $item1->active_display_item;
134
    ok( defined $active_display, 'Item should have an active display item' );
135
136
    AddIssue( $patron, $item1->barcode );
137
    my ( $doreturn, $messages, $issue, $borrower ) = AddReturn( $item1->barcode, $library2->branchcode );
138
139
    is( $doreturn, 1, 'Item should be returned successfully at non-home library' );
140
    ok(
141
        exists $messages->{RemovedFromDisplay},
142
        'RemovedFromDisplay message should be present when returned at non-home library'
143
    );
144
145
    $active_display = $item1->active_display_item;
146
    is( $active_display, undef, 'Item should be removed from display when returned at non-home library' );
147
148
    # Test 2: Return at home library should NOT remove from display
149
    my $item2 =
150
        $builder->build_sample_item( { homebranch => $library1->branchcode, holdingbranch => $library1->branchcode } );
151
152
    my $display2 = $builder->build_object(
153
        {
154
            class => 'Koha::Displays',
155
            value => {
156
                display_return_over => 'yes - except at home library',
157
                enabled             => 1,
158
                start_date          => undef,
159
                end_date            => undef,
160
            }
161
        }
162
    );
163
164
    my $display_item2 = $builder->build_object(
165
        {
166
            class => 'Koha::DisplayItems',
167
            value => {
168
                display_id   => $display2->display_id,
169
                itemnumber   => $item2->itemnumber,
170
                biblionumber => $item2->biblionumber,
171
            }
172
        }
173
    );
174
175
    $active_display = $item2->active_display_item;
176
    ok( defined $active_display, 'Item should have an active display item before return' );
177
178
    AddIssue( $patron, $item2->barcode );
179
    ( $doreturn, $messages, $issue, $borrower ) = AddReturn( $item2->barcode, $library1->branchcode );
180
181
    is( $doreturn, 1, 'Item should be returned successfully at home library' );
182
    ok(
183
        !exists $messages->{RemovedFromDisplay},
184
        'RemovedFromDisplay message should NOT be present when returned at home library'
185
    );
186
187
    $active_display = $item2->active_display_item;
188
    ok( defined $active_display, 'Item should still have an active display item when returned at home library' );
189
    is(
190
        $active_display->display_id, $display2->display_id,
191
        'Display item should still be linked to the correct display'
192
    );
193
194
    # Clean up
195
    $display_item2->delete;
196
};
197
198
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Koha/DisplayItems.t (+262 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2025 Koha Development team
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Test::NoWarnings;
23
use Test::More tests => 13;
24
25
use DateTime;
26
use C4::Context;
27
use Koha::DisplayItem;
28
use Koha::DisplayItems;
29
use Koha::Database;
30
31
use t::lib::TestBuilder;
32
33
my $schema = Koha::Database->new->schema;
34
$schema->storage->txn_begin;
35
36
my $builder             = t::lib::TestBuilder->new;
37
my $nb_of_display_items = Koha::DisplayItems->search->count;
38
39
# Create test data
40
my $library = $builder->build( { source => 'Branch' } );
41
my $biblio  = $builder->build( { source => 'Biblio' } );
42
my $item1   = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } );
43
my $item2   = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } );
44
45
my $display = $builder->build( { source => 'Display', value => { display_branch => $library->{branchcode} } } );
46
47
# Create display items for testing
48
my $new_display_item_1 = Koha::DisplayItem->new(
49
    {
50
        display_id   => $display->{display_id},
51
        itemnumber   => $item1->{itemnumber},
52
        biblionumber => $biblio->{biblionumber},
53
        date_added   => '2024-01-01',
54
        date_remove  => '2024-12-31',
55
    }
56
)->store;
57
58
my $new_display_item_2 = Koha::DisplayItem->new(
59
    {
60
        display_id   => $display->{display_id},
61
        itemnumber   => $item2->{itemnumber},
62
        biblionumber => $biblio->{biblionumber},
63
        date_added   => '2024-02-01',
64
        date_remove  => '2024-11-30',
65
    }
66
)->store;
67
68
# Test basic CRUD operations
69
like( $new_display_item_1->display_id, qr|^\d+$|, 'Adding a new display item should have set the display_id' );
70
is( Koha::DisplayItems->search->count, $nb_of_display_items + 2, 'The 2 display items should have been added' );
71
72
my $retrieved_display_item_1 = Koha::DisplayItems->find(
73
    {
74
        display_id => $new_display_item_1->display_id,
75
        itemnumber => $new_display_item_1->itemnumber
76
    }
77
);
78
is(
79
    $retrieved_display_item_1->biblionumber, $new_display_item_1->biblionumber,
80
    'Find a display item by composite key should return the correct display item'
81
);
82
83
# Test Koha::DisplayItem methods
84
subtest 'display method' => sub {
85
    plan tests => 2;
86
87
    my $display_obj = $new_display_item_1->display;
88
    isa_ok( $display_obj, 'Koha::Display', 'display should return a Koha::Display object' );
89
    is( $display_obj->display_id, $display->{display_id}, 'display should return the correct display' );
90
};
91
92
subtest 'item method' => sub {
93
    plan tests => 2;
94
95
    my $item_obj = $new_display_item_1->item;
96
    isa_ok( $item_obj, 'Koha::Item', 'item should return a Koha::Item object' );
97
    is( $item_obj->itemnumber, $item1->{itemnumber}, 'item should return the correct item' );
98
};
99
100
subtest 'biblio method' => sub {
101
    plan tests => 2;
102
103
    my $biblio_obj = $new_display_item_1->biblio;
104
    isa_ok( $biblio_obj, 'Koha::Biblio', 'biblio should return a Koha::Biblio object' );
105
    is( $biblio_obj->biblionumber, $biblio->{biblionumber}, 'biblio should return the correct biblio' );
106
};
107
108
# Test Koha::DisplayItems methods
109
subtest 'for_display method' => sub {
110
    plan tests => 2;
111
112
    my $display_items = Koha::DisplayItems->for_display( $display->{display_id} );
113
    isa_ok( $display_items, 'Koha::DisplayItems', 'for_display should return a Koha::DisplayItems object' );
114
    is( $display_items->count, 2, 'for_display should return the correct number of display items' );
115
};
116
117
subtest 'for_item method' => sub {
118
    plan tests => 2;
119
120
    my $display_items = Koha::DisplayItems->for_item( $item1->{itemnumber} );
121
    isa_ok( $display_items, 'Koha::DisplayItems', 'for_item should return a Koha::DisplayItems object' );
122
    is( $display_items->count, 1, 'for_item should return the correct number of display items' );
123
};
124
125
subtest 'for_biblio method' => sub {
126
    plan tests => 2;
127
128
    my $display_items = Koha::DisplayItems->for_biblio( $biblio->{biblionumber} );
129
    isa_ok( $display_items, 'Koha::DisplayItems', 'for_biblio should return a Koha::DisplayItems object' );
130
    is( $display_items->count, 2, 'for_biblio should return the correct number of display items' );
131
};
132
133
subtest 'due_for_removal method' => sub {
134
    plan tests => 3;
135
136
    # Create a display item that should be removed today
137
    my $today          = DateTime->today->ymd;
138
    my $item_to_remove = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } );
139
140
    my $display_item_due = Koha::DisplayItem->new(
141
        {
142
            display_id   => $display->{display_id},
143
            itemnumber   => $item_to_remove->{itemnumber},
144
            biblionumber => $biblio->{biblionumber},
145
            date_added   => '2024-01-01',
146
            date_remove  => $today,
147
        }
148
    )->store;
149
150
    my $due_items = Koha::DisplayItems->due_for_removal;
151
    isa_ok( $due_items, 'Koha::DisplayItems', 'due_for_removal should return a Koha::DisplayItems object' );
152
153
    my $found_due_item = 0;
154
    while ( my $item = $due_items->next ) {
155
        $found_due_item = 1 if $item->itemnumber == $item_to_remove->{itemnumber};
156
    }
157
    ok( $found_due_item, 'due_for_removal should include items due for removal today' );
158
159
    # Create a display item that should be removed in the future
160
    my $future_date = DateTime->today->add( days => 30 )->ymd;
161
    my $item_future = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } );
162
163
    my $display_item_future = Koha::DisplayItem->new(
164
        {
165
            display_id   => $display->{display_id},
166
            itemnumber   => $item_future->{itemnumber},
167
            biblionumber => $biblio->{biblionumber},
168
            date_added   => '2024-01-01',
169
            date_remove  => $future_date,
170
        }
171
    )->store;
172
173
    my $due_items_2       = Koha::DisplayItems->due_for_removal;
174
    my $found_future_item = 0;
175
    while ( my $item = $due_items_2->next ) {
176
        $found_future_item = 1 if $item->itemnumber == $item_future->{itemnumber};
177
    }
178
    ok( !$found_future_item, 'due_for_removal should not include items due for removal in the future' );
179
180
    # Clean up the additional display items
181
    $display_item_due->delete;
182
    $display_item_future->delete;
183
};
184
185
subtest 'display_days automatic date_remove calculation' => sub {
186
    plan tests => 5;
187
188
    # Create a display with display_days set to 30
189
    my $display_with_days = $builder->build_object(
190
        {
191
            class => 'Koha::Displays',
192
            value => { display_days => 30 }
193
        }
194
    );
195
196
    my $item3 = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } );
197
198
    # Create display item without date_remove - should auto-calculate
199
    my $display_item_auto = Koha::DisplayItem->new(
200
        {
201
            display_id   => $display_with_days->display_id,
202
            itemnumber   => $item3->{itemnumber},
203
            biblionumber => $biblio->{biblionumber},
204
        }
205
    )->store;
206
207
    ok( defined $display_item_auto->date_remove, 'date_remove should be set automatically' );
208
209
    # Calculate expected date (today + 30 days)
210
    my $dt = DateTime->now( time_zone => C4::Context->tz() );
211
    $dt->add( days => 30 );
212
    my $expected_date = $dt->ymd;
213
    is( $display_item_auto->date_remove, $expected_date, 'date_remove should be today + display_days' );
214
215
    # Create display item with explicit date_remove - should NOT auto-calculate
216
    my $item4       = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } );
217
    my $manual_date = '2025-12-31';
218
    my $display_item_manual = Koha::DisplayItem->new(
219
        {
220
            display_id   => $display_with_days->display_id,
221
            itemnumber   => $item4->{itemnumber},
222
            biblionumber => $biblio->{biblionumber},
223
            date_remove  => $manual_date,
224
        }
225
    )->store;
226
227
    is( $display_item_manual->date_remove, $manual_date, 'Explicit date_remove should not be overridden' );
228
229
    # Create display without display_days - date_remove should be NULL
230
    my $display_no_days = $builder->build_object(
231
        {
232
            class => 'Koha::Displays',
233
            value => { display_days => undef }
234
        }
235
    );
236
    my $item5 = $builder->build( { source => 'Item', value => { biblionumber => $biblio->{biblionumber} } } );
237
238
    my $display_item_no_days = Koha::DisplayItem->new(
239
        {
240
            display_id   => $display_no_days->display_id,
241
            itemnumber   => $item5->{itemnumber},
242
            biblionumber => $biblio->{biblionumber},
243
        }
244
    )->store;
245
246
    is( $display_item_no_days->date_remove, undef, 'date_remove should be NULL when display has no display_days' );
247
248
    # Clean up
249
    $display_item_auto->delete;
250
    $display_item_manual->delete;
251
    $display_item_no_days->delete;
252
    $display_with_days->delete;
253
    $display_no_days->delete;
254
255
    pass('Cleanup successful');
256
};
257
258
# Test delete
259
$retrieved_display_item_1->delete;
260
is( Koha::DisplayItems->search->count, $nb_of_display_items + 1, 'Delete should have deleted the display item' );
261
262
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Koha/Displays.t (+174 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2025 Koha Development team
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Test::NoWarnings;
23
use Test::More tests => 10;
24
25
use DateTime;
26
use Koha::Display;
27
use Koha::Displays;
28
use Koha::Database;
29
30
use t::lib::TestBuilder;
31
32
my $schema = Koha::Database->new->schema;
33
$schema->storage->txn_begin;
34
35
my $builder        = t::lib::TestBuilder->new;
36
my $nb_of_displays = Koha::Displays->search->count;
37
38
# Create a library for testing display_branch
39
my $library = $builder->build( { source => 'Branch' } );
40
41
# Create item types for testing
42
my $itemtype1 = $builder->build( { source => 'Itemtype' } );
43
my $itemtype2 = $builder->build( { source => 'Itemtype' } );
44
45
# Get current date for testing
46
my $today     = DateTime->today;
47
my $yesterday = $today->clone->subtract( days => 1 );
48
my $tomorrow  = $today->clone->add( days => 1 );
49
50
# Create displays for testing
51
my $new_display_1 = Koha::Display->new(
52
    {
53
        display_name        => 'my_display_name_for_test_1',
54
        enabled             => 1,
55
        display_return_over => 'no',
56
        start_date          => $yesterday->ymd,
57
        end_date            => $tomorrow->ymd,
58
        display_location    => 'DISPLAY_LOC_1',
59
        display_code        => 'DISPLAY_CODE_1',
60
        display_branch      => $library->{branchcode},
61
        display_itype       => $itemtype1->{itemtype},
62
    }
63
)->store;
64
65
my $new_display_2 = Koha::Display->new(
66
    {
67
        display_name        => 'my_display_name_for_test_2',
68
        enabled             => 0,
69
        display_return_over => 'yes - any library',
70
        display_location    => 'DISPLAY_LOC_2',
71
        display_code        => 'DISPLAY_CODE_2',
72
        display_itype       => $itemtype2->{itemtype},
73
    }
74
)->store;
75
76
# Test basic CRUD operations
77
like( $new_display_1->display_id, qr|^\d+$|, 'Adding a new display should have set the display_id' );
78
is( Koha::Displays->search->count, $nb_of_displays + 2, 'The 2 displays should have been added' );
79
80
my $retrieved_display_1 = Koha::Displays->find( $new_display_1->display_id );
81
is(
82
    $retrieved_display_1->display_name, $new_display_1->display_name,
83
    'Find a display by id should return the correct display'
84
);
85
86
# Test Koha::Display methods
87
subtest 'display_items method' => sub {
88
    plan tests => 2;
89
90
    my $display_items = $new_display_1->display_items;
91
    isa_ok( $display_items, 'Koha::DisplayItems', 'display_items should return a Koha::DisplayItems object' );
92
    is( $display_items->count, 0, 'New display should have no display items' );
93
};
94
95
subtest 'library method' => sub {
96
    plan tests => 3;
97
98
    my $library_obj = $new_display_1->library;
99
    isa_ok( $library_obj, 'Koha::Library', 'library should return a Koha::Library object' );
100
    is( $library_obj->branchcode, $library->{branchcode}, 'library should return the correct library' );
101
102
    # Test display without library
103
    is( $new_display_2->library, undef, 'display without library should return undef' );
104
};
105
106
# Test Koha::Displays methods
107
subtest 'enabled method' => sub {
108
    plan tests => 2;
109
110
    my $enabled_displays = Koha::Displays->enabled;
111
    isa_ok( $enabled_displays, 'Koha::Displays', 'enabled should return a Koha::Displays object' );
112
113
    my $found_enabled = 0;
114
    while ( my $display = $enabled_displays->next ) {
115
        $found_enabled = 1 if $display->display_id == $new_display_1->display_id;
116
    }
117
    ok( $found_enabled, 'enabled displays should include the enabled display' );
118
};
119
120
subtest 'for_branch method' => sub {
121
    plan tests => 2;
122
123
    my $branch_displays = Koha::Displays->for_branch( $library->{branchcode} );
124
    isa_ok( $branch_displays, 'Koha::Displays', 'for_branch should return a Koha::Displays object' );
125
126
    my $found_branch_display = 0;
127
    while ( my $display = $branch_displays->next ) {
128
        $found_branch_display = 1 if $display->display_id == $new_display_1->display_id;
129
    }
130
    ok( $found_branch_display, 'for_branch should include displays for the specified branch' );
131
};
132
133
subtest 'active method' => sub {
134
    plan tests => 3;
135
136
    my $active_displays = Koha::Displays->active;
137
    isa_ok( $active_displays, 'Koha::Displays', 'active should return a Koha::Displays object' );
138
139
    my $found_active = 0;
140
    while ( my $display = $active_displays->next ) {
141
        $found_active = 1 if $display->display_id == $new_display_1->display_id;
142
    }
143
    ok( $found_active, 'active displays should include the active display within date range' );
144
145
    # Create a display that's not active (dates in the past)
146
    my $past_end   = $today->clone->subtract( days => 10 );
147
    my $past_start = $today->clone->subtract( days => 20 );
148
149
    my $inactive_display = Koha::Display->new(
150
        {
151
            display_name        => 'inactive_display',
152
            enabled             => 1,
153
            display_return_over => 'no',
154
            start_date          => $past_start->ymd,
155
            end_date            => $past_end->ymd,
156
        }
157
    )->store;
158
159
    my $active_displays_2 = Koha::Displays->active;
160
    my $found_inactive    = 0;
161
    while ( my $display = $active_displays_2->next ) {
162
        $found_inactive = 1 if $display->display_id == $inactive_display->display_id;
163
    }
164
    ok( !$found_inactive, 'active displays should not include displays outside date range' );
165
166
    # Clean up the inactive display
167
    $inactive_display->delete;
168
};
169
170
# Test delete
171
$retrieved_display_1->delete;
172
is( Koha::Displays->search->count, $nb_of_displays + 1, 'Delete should have deleted the display' );
173
174
$schema->storage->txn_rollback;
(-)a/t/db_dependent/api/v1/displayitems.t (+477 lines)
Line 0 Link Here
1
#!/usr/bin/env perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::NoWarnings;
21
use Test::More tests => 6;
22
use Test::Mojo;
23
use JSON;
24
25
use t::lib::TestBuilder;
26
use t::lib::Mocks;
27
28
use Koha::DisplayItems;
29
use Koha::Database;
30
31
my $schema  = Koha::Database->new->schema;
32
my $builder = t::lib::TestBuilder->new;
33
34
my $t = Test::Mojo->new('Koha::REST::V1');
35
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
36
37
subtest 'list() tests' => sub {
38
39
    plan tests => 20;
40
41
    $schema->storage->txn_begin;
42
43
    Koha::DisplayItems->search->delete;
44
45
    my $librarian = $builder->build_object(
46
        {
47
            class => 'Koha::Patrons',
48
            value => { flags => 1 }     # displays permission
49
        }
50
    );
51
    my $password = 'thePassword123';
52
    $librarian->set_password( { password => $password, skip_validation => 1 } );
53
    my $userid = $librarian->userid;
54
55
    my $patron = $builder->build_object(
56
        {
57
            class => 'Koha::Patrons',
58
            value => { flags => 0 }
59
        }
60
    );
61
62
    $patron->set_password( { password => $password, skip_validation => 1 } );
63
    my $unauth_userid = $patron->userid;
64
65
    ## Authorized user tests
66
    # No displayitems, so empty array should be returned
67
    $t->get_ok("//$userid:$password@/api/v1/display/items")->status_is(200)->json_is( [] );
68
69
    # Create test data
70
    my $display = $builder->build_object( { class => 'Koha::Displays' } );
71
    my $biblio  = $builder->build_sample_biblio();
72
    my $item    = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
73
74
    my $displayitem = $builder->build_object(
75
        {
76
            class => 'Koha::DisplayItems',
77
            value => {
78
                display_id   => $display->display_id,
79
                itemnumber   => $item->itemnumber,
80
                biblionumber => $biblio->biblionumber
81
            }
82
        }
83
    );
84
85
    # One displayitem created, should get returned
86
    $t->get_ok("//$userid:$password@/api/v1/display/items")->status_is(200)->json_is( [ $displayitem->to_api ] );
87
88
    # Create another displayitem with same display
89
    my $item2               = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
90
    my $another_displayitem = $builder->build_object(
91
        {
92
            class => 'Koha::DisplayItems',
93
            value => {
94
                display_id   => $display->display_id,
95
                itemnumber   => $item2->itemnumber,
96
                biblionumber => $biblio->biblionumber
97
            }
98
        }
99
    );
100
101
    # Create displayitem with different display
102
    my $display2                      = $builder->build_object( { class => 'Koha::Displays' } );
103
    my $item3                         = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
104
    my $displayitem_different_display = $builder->build_object(
105
        {
106
            class => 'Koha::DisplayItems',
107
            value => {
108
                display_id   => $display2->display_id,
109
                itemnumber   => $item3->itemnumber,
110
                biblionumber => $biblio->biblionumber
111
            }
112
        }
113
    );
114
115
    # Three displayitems created, they should all be returned
116
    $t->get_ok("//$userid:$password@/api/v1/display/items")->status_is(200)->json_is(
117
        [
118
            $displayitem->to_api,
119
            $another_displayitem->to_api,
120
            $displayitem_different_display->to_api
121
        ]
122
    );
123
124
    # Filtering works, two displayitems sharing display_id
125
    $t->get_ok( "//$userid:$password@/api/v1/display/items?display_id=" . $display->display_id )->status_is(200)
126
        ->json_is(
127
        [
128
            $displayitem->to_api,
129
            $another_displayitem->to_api
130
        ]
131
        );
132
133
    $t->get_ok( "//$userid:$password@/api/v1/display/items?itemnumber=" . $item->itemnumber )->status_is(200)
134
        ->json_is( [ $displayitem->to_api ] );
135
136
    # Warn on unsupported query parameter
137
    $t->get_ok("//$userid:$password@/api/v1/display/items?displayitem_blah=blah")->status_is(400)
138
        ->json_is( [ { path => '/query/displayitem_blah', message => 'Malformed query string' } ] );
139
140
    # Unauthorized access
141
    $t->get_ok("//$unauth_userid:$password@/api/v1/display/items")->status_is(403);
142
143
    $schema->storage->txn_rollback;
144
};
145
146
subtest 'get() tests' => sub {
147
148
    plan tests => 11;
149
150
    $schema->storage->txn_begin;
151
152
    # Create test data
153
    my $display = $builder->build_object( { class => 'Koha::Displays' } );
154
    my $biblio  = $builder->build_sample_biblio();
155
    my $item    = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
156
157
    my $displayitem = $builder->build_object(
158
        {
159
            class => 'Koha::DisplayItems',
160
            value => {
161
                display_id   => $display->display_id,
162
                itemnumber   => $item->itemnumber,
163
                biblionumber => $biblio->biblionumber
164
            }
165
        }
166
    );
167
168
    my $librarian = $builder->build_object(
169
        {
170
            class => 'Koha::Patrons',
171
            value => { flags => 1 }     # displays permission
172
        }
173
    );
174
    my $password = 'thePassword123';
175
    $librarian->set_password( { password => $password, skip_validation => 1 } );
176
    my $userid = $librarian->userid;
177
178
    my $patron = $builder->build_object(
179
        {
180
            class => 'Koha::Patrons',
181
            value => { flags => 0 }
182
        }
183
    );
184
185
    $patron->set_password( { password => $password, skip_validation => 1 } );
186
    my $unauth_userid = $patron->userid;
187
188
    $t->get_ok(
189
        "//$userid:$password@/api/v1/display/items/" . $displayitem->display_id . "/" . $displayitem->itemnumber )
190
        ->status_is(200)->json_is( $displayitem->to_api );
191
192
    $t->get_ok( "//$unauth_userid:$password@/api/v1/display/items/"
193
            . $displayitem->display_id . "/"
194
            . $displayitem->itemnumber )->status_is(403);
195
196
    # Create displayitem to delete
197
    my $item_to_delete        = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
198
    my $displayitem_to_delete = $builder->build_object(
199
        {
200
            class => 'Koha::DisplayItems',
201
            value => {
202
                display_id   => $display->display_id,
203
                itemnumber   => $item_to_delete->itemnumber,
204
                biblionumber => $biblio->biblionumber
205
            }
206
        }
207
    );
208
    my $non_existent_display_id = $displayitem_to_delete->display_id;
209
    my $non_existent_item_id    = $displayitem_to_delete->itemnumber;
210
    $displayitem_to_delete->delete;
211
212
    $t->get_ok("//$userid:$password@/api/v1/display/items/$non_existent_display_id/$non_existent_item_id")
213
        ->status_is(404)->json_is( '/error' => 'Display item not found' );
214
215
    # Test with completely non-existent IDs
216
    $t->get_ok("//$userid:$password@/api/v1/display/items/99999/99999")->status_is(404)
217
        ->json_is( '/error' => 'Display item not found' );
218
219
    $schema->storage->txn_rollback;
220
};
221
222
subtest 'add() tests' => sub {
223
224
    plan tests => 17;
225
226
    $schema->storage->txn_begin;
227
228
    my $librarian = $builder->build_object(
229
        {
230
            class => 'Koha::Patrons',
231
            value => { flags => 1 }     # displays permission
232
        }
233
    );
234
    my $password = 'thePassword123';
235
    $librarian->set_password( { password => $password, skip_validation => 1 } );
236
    my $userid = $librarian->userid;
237
238
    my $patron = $builder->build_object(
239
        {
240
            class => 'Koha::Patrons',
241
            value => { flags => 0 }
242
        }
243
    );
244
245
    $patron->set_password( { password => $password, skip_validation => 1 } );
246
    my $unauth_userid = $patron->userid;
247
248
    # Create test data
249
    my $display = $builder->build_object( { class => 'Koha::Displays' } );
250
    my $biblio  = $builder->build_sample_biblio();
251
    my $item    = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
252
253
    my $displayitem = {
254
        display_id   => $display->display_id,
255
        itemnumber   => $item->itemnumber,
256
        biblionumber => $biblio->biblionumber,
257
        date_added   => "2024-01-15",
258
        date_remove  => "2024-02-15"
259
    };
260
261
    # Unauthorized attempt to write
262
    $t->post_ok( "//$unauth_userid:$password@/api/v1/display/items" => json => $displayitem )->status_is(403);
263
264
    # Authorized attempt to write invalid data
265
    my $displayitem_with_invalid_field = {
266
        blah         => "DisplayItem Blah",
267
        display_id   => $display->display_id,
268
        itemnumber   => $item->itemnumber,
269
        biblionumber => $biblio->biblionumber
270
    };
271
272
    $t->post_ok( "//$userid:$password@/api/v1/display/items" => json => $displayitem_with_invalid_field )
273
        ->status_is(400)->json_is(
274
        "/errors" => [
275
            {
276
                message => "Properties not allowed: blah.",
277
                path    => "/body"
278
            }
279
        ]
280
        );
281
282
    # Authorized attempt to write
283
    $t->post_ok( "//$userid:$password@/api/v1/display/items" => json => $displayitem )->status_is( 201, 'REST3.2.1' )
284
        ->header_like(
285
        Location => qr|^\/api\/v1\/display/items/\d+/\d+|,
286
        'REST3.4.1'
287
    )->json_is( '/display_id' => $displayitem->{display_id} )
288
        ->json_is( '/itemnumber'   => $displayitem->{itemnumber} )
289
        ->json_is( '/biblionumber' => $displayitem->{biblionumber} )
290
        ->json_is( '/date_added'   => $displayitem->{date_added} );
291
292
    # Test missing required field (display_id is required)
293
    my $displayitem_missing_field = {
294
        itemnumber   => $item->itemnumber,
295
        biblionumber => $biblio->biblionumber
296
297
            # Missing display_id (required field)
298
    };
299
300
    $t->post_ok( "//$userid:$password@/api/v1/display/items" => json => $displayitem_missing_field )->status_is(400)
301
        ->json_has('/errors');
302
303
    # Test successful creation with different item
304
    my $item2        = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
305
    my $displayitem2 = {
306
        display_id   => $display->display_id,
307
        itemnumber   => $item2->itemnumber,
308
        biblionumber => $biblio->biblionumber,
309
        date_added   => "2024-01-16",
310
        date_remove  => "2024-02-16"
311
    };
312
    $t->post_ok( "//$userid:$password@/api/v1/display/items" => json => $displayitem2 )->status_is(201);
313
314
    $schema->storage->txn_rollback;
315
};
316
317
subtest 'update() tests' => sub {
318
319
    plan tests => 15;
320
321
    $schema->storage->txn_begin;
322
323
    my $librarian = $builder->build_object(
324
        {
325
            class => 'Koha::Patrons',
326
            value => { flags => 1 }     # displays permission
327
        }
328
    );
329
    my $password = 'thePassword123';
330
    $librarian->set_password( { password => $password, skip_validation => 1 } );
331
    my $userid = $librarian->userid;
332
333
    my $patron = $builder->build_object(
334
        {
335
            class => 'Koha::Patrons',
336
            value => { flags => 0 }
337
        }
338
    );
339
340
    $patron->set_password( { password => $password, skip_validation => 1 } );
341
    my $unauth_userid = $patron->userid;
342
343
    # Create test data
344
    my $display = $builder->build_object( { class => 'Koha::Displays' } );
345
    my $biblio  = $builder->build_sample_biblio();
346
    my $item    = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
347
348
    my $displayitem = $builder->build_object(
349
        {
350
            class => 'Koha::DisplayItems',
351
            value => {
352
                display_id   => $display->display_id,
353
                itemnumber   => $item->itemnumber,
354
                biblionumber => $biblio->biblionumber
355
            }
356
        }
357
    );
358
359
    # Unauthorized attempt to update
360
    $t->put_ok( "//$unauth_userid:$password@/api/v1/display/items/"
361
            . $displayitem->display_id . "/"
362
            . $displayitem->itemnumber => json => { date_added => '2024-01-20' } )->status_is(403);
363
364
    # Attempt partial update on a PUT (missing required field)
365
    my $displayitem_with_missing_field = {
366
        biblionumber => $biblio->biblionumber
367
368
            # Missing display_id and itemnumber (required fields)
369
    };
370
371
    $t->put_ok( "//$userid:$password@/api/v1/display/items/"
372
            . $displayitem->display_id . "/"
373
            . $displayitem->itemnumber => json => $displayitem_with_missing_field )->status_is(400)
374
        ->json_has("/errors");
375
376
    # Full object update on PUT
377
    my $displayitem_with_updated_field = {
378
        display_id   => $display->display_id,
379
        itemnumber   => $item->itemnumber,
380
        biblionumber => $biblio->biblionumber,
381
        date_added   => "2024-01-20",
382
        date_remove  => "2024-03-20"
383
    };
384
385
    $t->put_ok( "//$userid:$password@/api/v1/display/items/"
386
            . $displayitem->display_id . "/"
387
            . $displayitem->itemnumber => json => $displayitem_with_updated_field )->status_is(200)
388
        ->json_is( '/date_added' => '2024-01-20' );
389
390
    # Authorized attempt to write invalid data
391
    my $displayitem_with_invalid_field = {
392
        blah         => "DisplayItem Blah",
393
        display_id   => $display->display_id,
394
        itemnumber   => $item->itemnumber,
395
        biblionumber => $biblio->biblionumber
396
    };
397
398
    $t->put_ok( "//$userid:$password@/api/v1/display/items/"
399
            . $displayitem->display_id . "/"
400
            . $displayitem->itemnumber => json => $displayitem_with_invalid_field )->status_is(400)->json_is(
401
        "/errors" => [
402
            {
403
                message => "Properties not allowed: blah.",
404
                path    => "/body"
405
            }
406
        ]
407
            );
408
409
    # Test with non-existent displayitem
410
    $t->put_ok( "//$userid:$password@/api/v1/display/items/99999/99999" => json => $displayitem_with_updated_field )
411
        ->status_is(404);
412
413
    # Wrong method (POST)
414
    $t->post_ok( "//$userid:$password@/api/v1/display/items/"
415
            . $displayitem->display_id . "/"
416
            . $displayitem->itemnumber => json => $displayitem_with_updated_field )->status_is(404);
417
418
    $schema->storage->txn_rollback;
419
};
420
421
subtest 'delete() tests' => sub {
422
423
    plan tests => 7;
424
425
    $schema->storage->txn_begin;
426
427
    my $librarian = $builder->build_object(
428
        {
429
            class => 'Koha::Patrons',
430
            value => { flags => 1 }     # displays permission
431
        }
432
    );
433
    my $password = 'thePassword123';
434
    $librarian->set_password( { password => $password, skip_validation => 1 } );
435
    my $userid = $librarian->userid;
436
437
    my $patron = $builder->build_object(
438
        {
439
            class => 'Koha::Patrons',
440
            value => { flags => 0 }
441
        }
442
    );
443
444
    $patron->set_password( { password => $password, skip_validation => 1 } );
445
    my $unauth_userid = $patron->userid;
446
447
    # Create test data
448
    my $display = $builder->build_object( { class => 'Koha::Displays' } );
449
    my $biblio  = $builder->build_sample_biblio();
450
    my $item    = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
451
452
    my $displayitem = $builder->build_object(
453
        {
454
            class => 'Koha::DisplayItems',
455
            value => {
456
                display_id   => $display->display_id,
457
                itemnumber   => $item->itemnumber,
458
                biblionumber => $biblio->biblionumber
459
            }
460
        }
461
    );
462
463
    # Unauthorized attempt to delete
464
    $t->delete_ok( "//$unauth_userid:$password@/api/v1/display/items/"
465
            . $displayitem->display_id . "/"
466
            . $displayitem->itemnumber )->status_is(403);
467
468
    $t->delete_ok(
469
        "//$userid:$password@/api/v1/display/items/" . $displayitem->display_id . "/" . $displayitem->itemnumber )
470
        ->status_is( 204, 'REST3.2.4' )->content_is( '', 'REST3.3.4' );
471
472
    $t->delete_ok(
473
        "//$userid:$password@/api/v1/display/items/" . $displayitem->display_id . "/" . $displayitem->itemnumber )
474
        ->status_is(404);
475
476
    $schema->storage->txn_rollback;
477
};
(-)a/t/db_dependent/api/v1/displays.t (+411 lines)
Line 0 Link Here
1
#!/usr/bin/env perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::NoWarnings;
21
use Test::More tests => 7;
22
use Test::Mojo;
23
use JSON;
24
25
use t::lib::TestBuilder;
26
use t::lib::Mocks;
27
28
use Koha::Displays;
29
use Koha::Database;
30
31
my $schema  = Koha::Database->new->schema;
32
my $builder = t::lib::TestBuilder->new;
33
34
my $t = Test::Mojo->new('Koha::REST::V1');
35
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
36
37
subtest 'config() tests' => sub {
38
39
    plan tests => 5;
40
41
    $schema->storage->txn_begin;
42
43
    my $librarian = $builder->build_object(
44
        {
45
            class => 'Koha::Patrons',
46
            value => { flags => 1 }     # displays permission
47
        }
48
    );
49
    my $password = 'thePassword123';
50
    $librarian->set_password( { password => $password, skip_validation => 1 } );
51
    my $userid = $librarian->userid;
52
53
    my $patron = $builder->build_object(
54
        {
55
            class => 'Koha::Patrons',
56
            value => { flags => 0 }
57
        }
58
    );
59
60
    $patron->set_password( { password => $password, skip_validation => 1 } );
61
    my $unauth_userid = $patron->userid;
62
63
    t::lib::Mocks::mock_preference( 'UseDisplayModule', 1 );
64
65
    ## Authorized user tests
66
    # No displays, so empty array should be returned
67
    $t->get_ok("//$userid:$password@/api/v1/displays/config")->status_is(200)
68
        ->json_is( { settings => { enabled => 1 } } );
69
70
    # Unauthorized access
71
    $t->get_ok("//$unauth_userid:$password@/api/v1/displays/config")->status_is(403);
72
73
    $schema->storage->txn_rollback;
74
};
75
76
subtest 'list() tests' => sub {
77
78
    plan tests => 20;
79
80
    $schema->storage->txn_begin;
81
82
    Koha::Displays->search->delete;
83
84
    my $librarian = $builder->build_object(
85
        {
86
            class => 'Koha::Patrons',
87
            value => { flags => 1 }     # displays permission
88
        }
89
    );
90
    my $password = 'thePassword123';
91
    $librarian->set_password( { password => $password, skip_validation => 1 } );
92
    my $userid = $librarian->userid;
93
94
    my $patron = $builder->build_object(
95
        {
96
            class => 'Koha::Patrons',
97
            value => { flags => 0 }
98
        }
99
    );
100
101
    $patron->set_password( { password => $password, skip_validation => 1 } );
102
    my $unauth_userid = $patron->userid;
103
104
    ## Authorized user tests
105
    # No displays, so empty array should be returned
106
    $t->get_ok("//$userid:$password@/api/v1/displays")->status_is(200)->json_is( [] );
107
108
    my $display = $builder->build_object( { class => 'Koha::Displays' } );
109
110
    # One display created, should get returned
111
    $t->get_ok("//$userid:$password@/api/v1/displays")->status_is(200)->json_is( [ $display->to_api ] );
112
113
    my $another_display =
114
        $builder->build_object(
115
        { class => 'Koha::Displays', value => { display_branch => $display->display_branch } } );
116
    my $display_with_another_branch = $builder->build_object( { class => 'Koha::Displays' } );
117
118
    # Three displays created, they should all be returned
119
    $t->get_ok("//$userid:$password@/api/v1/displays")->status_is(200)->json_is(
120
        [
121
            $display->to_api,
122
            $another_display->to_api,
123
            $display_with_another_branch->to_api
124
        ]
125
    );
126
127
    # Filtering works, two displays sharing display_branch
128
    $t->get_ok( "//$userid:$password@/api/v1/displays?display_branch=" . $display->display_branch )->status_is(200)
129
        ->json_is(
130
        [
131
            $display->to_api,
132
            $another_display->to_api
133
        ]
134
        );
135
136
    $t->get_ok( "//$userid:$password@/api/v1/displays?display_name=" . $display->display_name )->status_is(200)
137
        ->json_is( [ $display->to_api ] );
138
139
    # Warn on unsupported query parameter
140
    $t->get_ok("//$userid:$password@/api/v1/displays?display_blah=blah")->status_is(400)
141
        ->json_is( [ { path => '/query/display_blah', message => 'Malformed query string' } ] );
142
143
    # Unauthorized access
144
    $t->get_ok("//$unauth_userid:$password@/api/v1/displays")->status_is(403);
145
146
    $schema->storage->txn_rollback;
147
};
148
149
subtest 'get() tests' => sub {
150
151
    plan tests => 8;
152
153
    $schema->storage->txn_begin;
154
155
    my $display   = $builder->build_object( { class => 'Koha::Displays' } );
156
    my $librarian = $builder->build_object(
157
        {
158
            class => 'Koha::Patrons',
159
            value => { flags => 1 }     # displays permission
160
        }
161
    );
162
    my $password = 'thePassword123';
163
    $librarian->set_password( { password => $password, skip_validation => 1 } );
164
    my $userid = $librarian->userid;
165
166
    my $patron = $builder->build_object(
167
        {
168
            class => 'Koha::Patrons',
169
            value => { flags => 0 }
170
        }
171
    );
172
173
    $patron->set_password( { password => $password, skip_validation => 1 } );
174
    my $unauth_userid = $patron->userid;
175
176
    $t->get_ok( "//$userid:$password@/api/v1/displays/" . $display->display_id )->status_is(200)
177
        ->json_is( $display->to_api );
178
179
    $t->get_ok( "//$unauth_userid:$password@/api/v1/displays/" . $display->display_id )->status_is(403);
180
181
    my $display_to_delete = $builder->build_object( { class => 'Koha::Displays' } );
182
    my $non_existent_id   = $display_to_delete->display_id;
183
    $display_to_delete->delete;
184
185
    $t->get_ok("//$userid:$password@/api/v1/displays/$non_existent_id")->status_is(404)
186
        ->json_is( '/error' => 'Display not found' );
187
188
    $schema->storage->txn_rollback;
189
};
190
191
subtest 'add() tests' => sub {
192
193
    plan tests => 18;
194
195
    $schema->storage->txn_begin;
196
197
    my $librarian = $builder->build_object(
198
        {
199
            class => 'Koha::Patrons',
200
            value => { flags => 1 }     # displays permission
201
        }
202
    );
203
    my $password = 'thePassword123';
204
    $librarian->set_password( { password => $password, skip_validation => 1 } );
205
    my $userid = $librarian->userid;
206
207
    my $patron = $builder->build_object(
208
        {
209
            class => 'Koha::Patrons',
210
            value => { flags => 0 }
211
        }
212
    );
213
214
    $patron->set_password( { password => $password, skip_validation => 1 } );
215
    my $unauth_userid = $patron->userid;
216
217
    my $itemtype = $builder->build_object( { class => 'Koha::ItemTypes' } );
218
219
    my $display = {
220
        display_name        => "Test Display",
221
        enabled             => JSON::true,
222
        display_return_over => "no",
223
        start_date          => "2024-01-01",
224
        end_date            => "2024-12-31",
225
        display_location    => "DISPLAY",
226
        display_code        => "TEST",
227
        display_branch      => "CPL",
228
        display_itype       => $itemtype->itemtype
229
    };
230
231
    # Unauthorized attempt to write
232
    $t->post_ok( "//$unauth_userid:$password@/api/v1/displays" => json => $display )->status_is(403);
233
234
    # Authorized attempt to write invalid data
235
    my $display_with_invalid_field = {
236
        blah                => "Display Blah",
237
        display_name        => "Test Display",
238
        enabled             => JSON::true,
239
        display_return_over => "no"
240
    };
241
242
    $t->post_ok( "//$userid:$password@/api/v1/displays" => json => $display_with_invalid_field )->status_is(400)
243
        ->json_is(
244
        "/errors" => [
245
            {
246
                message => "Properties not allowed: blah.",
247
                path    => "/body"
248
            }
249
        ]
250
        );
251
252
    # Authorized attempt to write
253
    my $display_id =
254
        $t->post_ok( "//$userid:$password@/api/v1/displays" => json => $display )->status_is( 201, 'REST3.2.1' )
255
        ->header_like(
256
        Location => qr|^\/api\/v1\/displays/\d*|,
257
        'REST3.4.1'
258
    )->json_is( '/display_name' => $display->{display_name} )->json_is( '/enabled' => $display->{enabled} )
259
        ->json_is( '/display_return_over' => $display->{display_return_over} )
260
        ->json_is( '/start_date'          => $display->{start_date} )->tx->res->json->{display_id};
261
262
    # Authorized attempt to create with null id
263
    $display->{display_id} = undef;
264
    $t->post_ok( "//$userid:$password@/api/v1/displays" => json => $display )->status_is(400)->json_has('/errors');
265
266
    # Authorized attempt to create with existing id
267
    $display->{display_id} = $display_id;
268
    $t->post_ok( "//$userid:$password@/api/v1/displays" => json => $display )->status_is(400)->json_is(
269
        "/errors" => [
270
            {
271
                message => "Read-only.",
272
                path    => "/body/display_id"
273
            }
274
        ]
275
    );
276
277
    $schema->storage->txn_rollback;
278
};
279
280
subtest 'update() tests' => sub {
281
282
    plan tests => 15;
283
284
    $schema->storage->txn_begin;
285
286
    my $librarian = $builder->build_object(
287
        {
288
            class => 'Koha::Patrons',
289
            value => { flags => 1 }     # displays permission
290
        }
291
    );
292
    my $password = 'thePassword123';
293
    $librarian->set_password( { password => $password, skip_validation => 1 } );
294
    my $userid = $librarian->userid;
295
296
    my $patron = $builder->build_object(
297
        {
298
            class => 'Koha::Patrons',
299
            value => { flags => 0 }
300
        }
301
    );
302
303
    $patron->set_password( { password => $password, skip_validation => 1 } );
304
    my $unauth_userid = $patron->userid;
305
306
    my $itemtype = $builder->build_object( { class => 'Koha::ItemTypes' } );
307
308
    my $display_id = $builder->build_object( { class => 'Koha::Displays' } )->display_id;
309
310
    # Unauthorized attempt to update
311
    $t->put_ok( "//$unauth_userid:$password@/api/v1/displays/$display_id" => json =>
312
            { display_name => 'New unauthorized name change' } )->status_is(403);
313
314
    # Attempt partial update on a PUT
315
    my $display_with_missing_field = {
316
        display_name => 'Updated Display',
317
        enabled      => JSON::false
318
    };
319
320
    $t->put_ok( "//$userid:$password@/api/v1/displays/$display_id" => json => $display_with_missing_field )
321
        ->status_is(400)
322
        ->json_is( "/errors" => [ { message => "Missing property.", path => "/body/display_return_over" } ] );
323
324
    # Full object update on PUT
325
    my $display_with_updated_field = {
326
        display_name        => "Updated Display Name",
327
        enabled             => JSON::false,
328
        display_return_over => "yes - any library",
329
        start_date          => "2024-02-01",
330
        end_date            => "2024-11-30",
331
        display_location    => "NEWDISPLAY",
332
        display_code        => "UPDATED",
333
        display_branch      => "CPL",
334
        display_itype       => $itemtype->itemtype
335
    };
336
337
    $t->put_ok( "//$userid:$password@/api/v1/displays/$display_id" => json => $display_with_updated_field )
338
        ->status_is(200)->json_is( '/display_name' => 'Updated Display Name' );
339
340
    # Authorized attempt to write invalid data
341
    my $display_with_invalid_field = {
342
        blah                => "Display Blah",
343
        display_name        => "Test Display",
344
        enabled             => JSON::true,
345
        display_return_over => "no"
346
    };
347
348
    $t->put_ok( "//$userid:$password@/api/v1/displays/$display_id" => json => $display_with_invalid_field )
349
        ->status_is(400)->json_is(
350
        "/errors" => [
351
            {
352
                message => "Properties not allowed: blah.",
353
                path    => "/body"
354
            }
355
        ]
356
        );
357
358
    my $display_to_delete = $builder->build_object( { class => 'Koha::Displays' } );
359
    my $non_existent_id   = $display_to_delete->display_id;
360
    $display_to_delete->delete;
361
362
    $t->put_ok( "//$userid:$password@/api/v1/displays/$non_existent_id" => json => $display_with_updated_field )
363
        ->status_is(404);
364
365
    # Wrong method (POST)
366
    $display_with_updated_field->{display_id} = 2;
367
368
    $t->post_ok( "//$userid:$password@/api/v1/displays/$display_id" => json => $display_with_updated_field )
369
        ->status_is(404);
370
371
    $schema->storage->txn_rollback;
372
};
373
374
subtest 'delete() tests' => sub {
375
376
    plan tests => 7;
377
378
    $schema->storage->txn_begin;
379
380
    my $librarian = $builder->build_object(
381
        {
382
            class => 'Koha::Patrons',
383
            value => { flags => 1 }     # displays permission
384
        }
385
    );
386
    my $password = 'thePassword123';
387
    $librarian->set_password( { password => $password, skip_validation => 1 } );
388
    my $userid = $librarian->userid;
389
390
    my $patron = $builder->build_object(
391
        {
392
            class => 'Koha::Patrons',
393
            value => { flags => 0 }
394
        }
395
    );
396
397
    $patron->set_password( { password => $password, skip_validation => 1 } );
398
    my $unauth_userid = $patron->userid;
399
400
    my $display_id = $builder->build_object( { class => 'Koha::Displays' } )->display_id;
401
402
    # Unauthorized attempt to delete
403
    $t->delete_ok("//$unauth_userid:$password@/api/v1/displays/$display_id")->status_is(403);
404
405
    $t->delete_ok("//$userid:$password@/api/v1/displays/$display_id")->status_is( 204, 'REST3.2.4' )
406
        ->content_is( '', 'REST3.3.4' );
407
408
    $t->delete_ok("//$userid:$password@/api/v1/displays/$display_id")->status_is(404);
409
410
    $schema->storage->txn_rollback;
411
};
(-)a/t/db_dependent/api/v1/items.t (-2 / +82 lines)
Lines 19-26 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 7;
22
use Test::NoWarnings;
23
use Test::NoWarnings;
23
use Test::More tests => 6;
24
use Test::MockModule;
24
use Test::MockModule;
25
use Test::Mojo;
25
use Test::Mojo;
26
use Test::Warn;
26
use Test::Warn;
Lines 601-603 subtest 'pickup_locations() tests' => sub { Link Here
601
601
602
    $schema->storage->txn_rollback;
602
    $schema->storage->txn_rollback;
603
};
603
};
604
- 
604
605
subtest 'effective display fields tests' => sub {
606
607
    plan tests => 12;
608
609
    $schema->storage->txn_begin;
610
611
    t::lib::Mocks::mock_preference( 'UseDisplayModule', 1 );
612
613
    my $librarian = $builder->build_object(
614
        {
615
            class => 'Koha::Patrons',
616
            value => { flags => 1 }
617
        }
618
    );
619
    my $password = 'thePassword123';
620
    $librarian->set_password( { password => $password, skip_validation => 1 } );
621
    my $userid = $librarian->userid;
622
623
    my $patron = $builder->build_object(
624
        {
625
            class => 'Koha::Patrons',
626
            value => { flags => 0 }
627
        }
628
    );
629
    $patron->set_password( { password => $password, skip_validation => 1 } );
630
    my $unauth_userid = $patron->userid;
631
632
    # Create an item with specific location, collection code, homebranch, and holdingbranch
633
    my $item = $builder->build_sample_item(
634
        {
635
            location      => 'SHELF',
636
            ccode         => 'COLL1',
637
            homebranch    => $librarian->branchcode,
638
            holdingbranch => $librarian->branchcode,
639
        }
640
    );
641
642
    # Test without display - should return regular values
643
    $t->get_ok( "//$userid:$password@/api/v1/items/" . $item->id )->status_is(200)
644
        ->json_is( '/effective_location'           => 'SHELF' )->json_is( '/effective_collection_code' => 'COLL1' )
645
        ->json_is( '/effective_home_library_id'    => $librarian->branchcode )
646
        ->json_is( '/effective_holding_library_id' => $librarian->branchcode );
647
648
    # Create a display with different values
649
    my $display_library = $builder->build_object( { class => 'Koha::Libraries' } );
650
    my $display         = $builder->build_object(
651
        {
652
            class => 'Koha::Displays',
653
            value => {
654
                display_location       => 'DISPLAY',
655
                display_code           => 'DISPLAYCOLL',
656
                display_branch         => $display_library->branchcode,
657
                display_holding_branch => $display_library->branchcode,
658
                enabled                => 1,
659
                start_date             => undef,
660
                end_date               => undef,
661
            }
662
        }
663
    );
664
665
    # Add item to display
666
    my $display_item = $builder->build_object(
667
        {
668
            class => 'Koha::DisplayItems',
669
            value => {
670
                display_id   => $display->display_id,
671
                itemnumber   => $item->itemnumber,
672
                biblionumber => $item->biblionumber,
673
            }
674
        }
675
    );
676
677
    # Test with display - should return display values
678
    $t->get_ok( "//$userid:$password@/api/v1/items/" . $item->id )->status_is(200)
679
        ->json_is( '/effective_location'        => 'DISPLAY' )->json_is( '/effective_collection_code' => 'DISPLAYCOLL' )
680
        ->json_is( '/effective_home_library_id' => $display_library->branchcode )
681
        ->json_is( '/effective_holding_library_id' => $display_library->branchcode );
682
683
    $schema->storage->txn_rollback;
684
};

Return to bug 14962