Bug 26704: (follow-up) Rebase for bug 29785
[koha.git] / t / db_dependent / Koha / Item.t
1 #!/usr/bin/perl
2
3 # Copyright 2019 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 use utf8;
22
23 use Test::More tests => 14;
24 use Test::Exception;
25
26 use C4::Biblio qw( GetMarcSubfieldStructure );
27 use C4::Circulation qw( AddIssue AddReturn );
28
29 use Koha::Caches;
30 use Koha::Items;
31 use Koha::Database;
32 use Koha::DateUtils qw( dt_from_string );
33 use Koha::Old::Items;
34
35 use List::MoreUtils qw(all);
36
37 use t::lib::TestBuilder;
38 use t::lib::Mocks;
39
40 my $schema  = Koha::Database->new->schema;
41 my $builder = t::lib::TestBuilder->new;
42
43 subtest 'tracked_links relationship' => sub {
44     plan tests => 3;
45
46     my $biblio = $builder->build_sample_biblio();
47     my $item   = $builder->build_sample_item({
48         biblionumber => $biblio->biblionumber,
49     });
50     my $tracked_links = $item->tracked_links;
51     is( ref($tracked_links), 'Koha::TrackedLinks', 'tracked_links returns a Koha::TrackedLinks object set' );
52     is($item->tracked_links->count, 0, "Empty Koha::TrackedLinks set returned if no tracked_links");
53     my $link1 = $builder->build({ source => 'Linktracker', value => { itemnumber => $item->itemnumber }});
54     my $link2 = $builder->build({ source => 'Linktracker', value => { itemnumber => $item->itemnumber }});
55
56     is($item->tracked_links()->count,2,"Two tracked links found");
57 };
58
59 subtest 'hidden_in_opac() tests' => sub {
60
61     plan tests => 4;
62
63     $schema->storage->txn_begin;
64
65     my $item  = $builder->build_sample_item({ itemlost => 2 });
66     my $rules = {};
67
68     # disable hidelostitems as it interteres with OpachiddenItems for the calculation
69     t::lib::Mocks::mock_preference( 'hidelostitems', 0 );
70
71     ok( !$item->hidden_in_opac, 'No rules passed, shouldn\'t hide' );
72     ok( !$item->hidden_in_opac({ rules => $rules }), 'Empty rules passed, shouldn\'t hide' );
73
74     # enable hidelostitems to verify correct behaviour
75     t::lib::Mocks::mock_preference( 'hidelostitems', 1 );
76     ok( $item->hidden_in_opac, 'Even with no rules, item should hide because of hidelostitems syspref' );
77
78     # disable hidelostitems
79     t::lib::Mocks::mock_preference( 'hidelostitems', 0 );
80     my $withdrawn = $item->withdrawn + 1; # make sure this attribute doesn't match
81
82     $rules = { withdrawn => [$withdrawn], itype => [ $item->itype ] };
83
84     ok( $item->hidden_in_opac({ rules => $rules }), 'Rule matching itype passed, should hide' );
85
86
87
88     $schema->storage->txn_rollback;
89 };
90
91 subtest 'has_pending_hold() tests' => sub {
92
93     plan tests => 2;
94
95     $schema->storage->txn_begin;
96
97     my $dbh = C4::Context->dbh;
98     my $item  = $builder->build_sample_item({ itemlost => 0 });
99     my $itemnumber = $item->itemnumber;
100
101     $dbh->do("INSERT INTO tmp_holdsqueue (surname,borrowernumber,itemnumber) VALUES ('Clamp',42,$itemnumber)");
102     ok( $item->has_pending_hold, "Yes, we have a pending hold");
103     $dbh->do("DELETE FROM tmp_holdsqueue WHERE itemnumber=$itemnumber");
104     ok( !$item->has_pending_hold, "We don't have a pending hold if nothing in the tmp_holdsqueue");
105
106     $schema->storage->txn_rollback;
107 };
108
109 subtest "as_marc_field() tests" => sub {
110
111     my $mss = C4::Biblio::GetMarcSubfieldStructure( '' );
112     my ( $itemtag, $itemtagsubfield) = C4::Biblio::GetMarcFromKohaField( "items.itemnumber" );
113
114     my @schema_columns = $schema->resultset('Item')->result_source->columns;
115     my @mapped_columns = grep { exists $mss->{'items.'.$_} } @schema_columns;
116
117     plan tests => 2 * (scalar @mapped_columns + 1) + 3;
118
119     $schema->storage->txn_begin;
120
121     my $item = $builder->build_sample_item;
122     # Make sure it has at least one undefined attribute
123     $item->set({ replacementprice => undef })->store->discard_changes;
124
125     # Tests with the mss parameter
126     my $marc_field = $item->as_marc_field({ mss => $mss });
127
128     is(
129         $marc_field->tag,
130         $itemtag,
131         'Generated field set the right tag number'
132     );
133
134     foreach my $column ( @mapped_columns ) {
135         my $tagsubfield = $mss->{ 'items.' . $column }[0]->{tagsubfield};
136         is( $marc_field->subfield($tagsubfield),
137             $item->$column, "Value is mapped correctly for column $column" );
138     }
139
140     # Tests without the mss parameter
141     $marc_field = $item->as_marc_field();
142
143     is(
144         $marc_field->tag,
145         $itemtag,
146         'Generated field set the right tag number'
147     );
148
149     foreach my $column (@mapped_columns) {
150         my $tagsubfield = $mss->{ 'items.' . $column }[0]->{tagsubfield};
151         is( $marc_field->subfield($tagsubfield),
152             $item->$column, "Value is mapped correctly for column $column" );
153     }
154
155     my $unmapped_subfield = Koha::MarcSubfieldStructure->new(
156         {
157             frameworkcode => '',
158             tagfield      => $itemtag,
159             tagsubfield   => 'X',
160         }
161     )->store;
162
163     my @unlinked_subfields;
164     push @unlinked_subfields, X => 'Something weird';
165     $item->more_subfields_xml( C4::Items::_get_unlinked_subfields_xml( \@unlinked_subfields ) )->store;
166
167     Koha::Caches->get_instance->clear_from_cache( "MarcStructure-1-" );
168     Koha::MarcSubfieldStructures->search(
169         { frameworkcode => '', tagfield => $itemtag } )
170       ->update( { display_order => \['FLOOR( 1 + RAND( ) * 10 )'] } );
171
172     $marc_field = $item->as_marc_field;
173
174     my $tagslib = C4::Biblio::GetMarcStructure(1, '');
175     my @subfields = $marc_field->subfields;
176     my $result = all { defined $_->[1] } @subfields;
177     ok( $result, 'There are no undef subfields' );
178     my @ordered_subfields = sort {
179             $tagslib->{$itemtag}->{ $a->[0] }->{display_order}
180         <=> $tagslib->{$itemtag}->{ $b->[0] }->{display_order}
181     } @subfields;
182     is_deeply(\@subfields, \@ordered_subfields);
183
184     is( scalar $marc_field->subfield('X'), 'Something weird', 'more_subfield_xml is considered' );
185
186     $schema->storage->txn_rollback;
187     Koha::Caches->get_instance->clear_from_cache( "MarcStructure-1-" );
188 };
189
190 subtest 'pickup_locations' => sub {
191     plan tests => 66;
192
193     $schema->storage->txn_begin;
194
195     my $dbh = C4::Context->dbh;
196
197     my $root1 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1, branchcode => undef } } );
198     my $root2 = $builder->build_object( { class => 'Koha::Library::Groups', value => { ft_local_hold_group => 1, branchcode => undef } } );
199     my $library1 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, } } );
200     my $library2 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, } } );
201     my $library3 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 0, } } );
202     my $library4 = $builder->build_object( { class => 'Koha::Libraries', value => { pickup_location => 1, } } );
203     my $group1_1 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root1->id, branchcode => $library1->branchcode } } );
204     my $group1_2 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root1->id, branchcode => $library2->branchcode } } );
205
206     my $group2_1 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root2->id, branchcode => $library3->branchcode } } );
207     my $group2_2 = $builder->build_object( { class => 'Koha::Library::Groups', value => { parent_id => $root2->id, branchcode => $library4->branchcode } } );
208
209     our @branchcodes = (
210         $library1->branchcode, $library2->branchcode,
211         $library3->branchcode, $library4->branchcode
212     );
213
214     my $item1 = $builder->build_sample_item(
215         {
216             homebranch    => $library1->branchcode,
217             holdingbranch => $library2->branchcode,
218             copynumber    => 1,
219             ccode         => 'Gollum'
220         }
221     )->store;
222
223     my $item3 = $builder->build_sample_item(
224         {
225             homebranch    => $library3->branchcode,
226             holdingbranch => $library4->branchcode,
227             copynumber    => 3,
228             itype         => $item1->itype,
229         }
230     )->store;
231
232     Koha::CirculationRules->set_rules(
233         {
234             categorycode => undef,
235             itemtype     => $item1->itype,
236             branchcode   => undef,
237             rules        => {
238                 reservesallowed => 25,
239             }
240         }
241     );
242
243
244     my $patron1 = $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $library1->branchcode, firstname => '1' } } );
245     my $patron4 = $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $library4->branchcode, firstname => '4' } } );
246
247     my $results = {
248         "1-1-from_home_library-any"               => 3,
249         "1-1-from_home_library-holdgroup"         => 2,
250         "1-1-from_home_library-patrongroup"       => 2,
251         "1-1-from_home_library-homebranch"        => 1,
252         "1-1-from_home_library-holdingbranch"     => 1,
253         "1-1-from_any_library-any"                => 3,
254         "1-1-from_any_library-holdgroup"          => 2,
255         "1-1-from_any_library-patrongroup"        => 2,
256         "1-1-from_any_library-homebranch"         => 1,
257         "1-1-from_any_library-holdingbranch"      => 1,
258         "1-1-from_local_hold_group-any"           => 3,
259         "1-1-from_local_hold_group-holdgroup"     => 2,
260         "1-1-from_local_hold_group-patrongroup"   => 2,
261         "1-1-from_local_hold_group-homebranch"    => 1,
262         "1-1-from_local_hold_group-holdingbranch" => 1,
263         "1-4-from_home_library-any"               => 0,
264         "1-4-from_home_library-holdgroup"         => 0,
265         "1-4-from_home_library-patrongroup"       => 0,
266         "1-4-from_home_library-homebranch"        => 0,
267         "1-4-from_home_library-holdingbranch"     => 0,
268         "1-4-from_any_library-any"                => 3,
269         "1-4-from_any_library-holdgroup"          => 2,
270         "1-4-from_any_library-patrongroup"        => 1,
271         "1-4-from_any_library-homebranch"         => 1,
272         "1-4-from_any_library-holdingbranch"      => 1,
273         "1-4-from_local_hold_group-any"           => 0,
274         "1-4-from_local_hold_group-holdgroup"     => 0,
275         "1-4-from_local_hold_group-patrongroup"   => 0,
276         "1-4-from_local_hold_group-homebranch"    => 0,
277         "1-4-from_local_hold_group-holdingbranch" => 0,
278         "3-1-from_home_library-any"               => 0,
279         "3-1-from_home_library-holdgroup"         => 0,
280         "3-1-from_home_library-patrongroup"       => 0,
281         "3-1-from_home_library-homebranch"        => 0,
282         "3-1-from_home_library-holdingbranch"     => 0,
283         "3-1-from_any_library-any"                => 3,
284         "3-1-from_any_library-holdgroup"          => 1,
285         "3-1-from_any_library-patrongroup"        => 2,
286         "3-1-from_any_library-homebranch"         => 0,
287         "3-1-from_any_library-holdingbranch"      => 1,
288         "3-1-from_local_hold_group-any"           => 0,
289         "3-1-from_local_hold_group-holdgroup"     => 0,
290         "3-1-from_local_hold_group-patrongroup"   => 0,
291         "3-1-from_local_hold_group-homebranch"    => 0,
292         "3-1-from_local_hold_group-holdingbranch" => 0,
293         "3-4-from_home_library-any"               => 0,
294         "3-4-from_home_library-holdgroup"         => 0,
295         "3-4-from_home_library-patrongroup"       => 0,
296         "3-4-from_home_library-homebranch"        => 0,
297         "3-4-from_home_library-holdingbranch"     => 0,
298         "3-4-from_any_library-any"                => 3,
299         "3-4-from_any_library-holdgroup"          => 1,
300         "3-4-from_any_library-patrongroup"        => 1,
301         "3-4-from_any_library-homebranch"         => 0,
302         "3-4-from_any_library-holdingbranch"      => 1,
303         "3-4-from_local_hold_group-any"           => 3,
304         "3-4-from_local_hold_group-holdgroup"     => 1,
305         "3-4-from_local_hold_group-patrongroup"   => 1,
306         "3-4-from_local_hold_group-homebranch"    => 0,
307         "3-4-from_local_hold_group-holdingbranch" => 1
308     };
309
310     sub _doTest {
311         my ( $item, $patron, $ha, $hfp, $results ) = @_;
312
313         Koha::CirculationRules->set_rules(
314             {
315                 branchcode => undef,
316                 itemtype   => undef,
317                 rules => {
318                     holdallowed => $ha,
319                     hold_fulfillment_policy => $hfp,
320                     returnbranch => 'any'
321                 }
322             }
323         );
324         my $ha_value =
325           $ha eq 'from_local_hold_group' ? 'holdgroup'
326           : (
327             $ha eq 'from_any_library' ? 'any'
328             : 'homebranch'
329           );
330
331         my @pl = map {
332             my $pickup_location = $_;
333             grep { $pickup_location->branchcode eq $_ } @branchcodes
334         } $item->pickup_locations( { patron => $patron } )->as_list;
335
336         ok(
337             scalar(@pl) eq $results->{
338                     $item->copynumber . '-'
339                   . $patron->firstname . '-'
340                   . $ha . '-'
341                   . $hfp
342             },
343             'item'
344               . $item->copynumber
345               . ', patron'
346               . $patron->firstname
347               . ', holdallowed: '
348               . $ha_value
349               . ', hold_fulfillment_policy: '
350               . $hfp
351               . ' should return '
352               . $results->{
353                     $item->copynumber . '-'
354                   . $patron->firstname . '-'
355                   . $ha . '-'
356                   . $hfp
357               }
358               . ' and returns '
359               . scalar(@pl)
360         );
361
362     }
363
364
365     foreach my $item ($item1, $item3) {
366         foreach my $patron ($patron1, $patron4) {
367             #holdallowed 1: homebranch, 2: any, 3: holdgroup
368             foreach my $ha ('from_home_library', 'from_any_library', 'from_local_hold_group') {
369                 foreach my $hfp ('any', 'holdgroup', 'patrongroup', 'homebranch', 'holdingbranch') {
370                     _doTest($item, $patron, $ha, $hfp, $results);
371                 }
372             }
373         }
374     }
375
376     # Now test that branchtransferlimits will further filter the pickup locations
377
378     my $item_no_ccode = $builder->build_sample_item(
379         {
380             homebranch    => $library1->branchcode,
381             holdingbranch => $library2->branchcode,
382             itype         => $item1->itype,
383         }
384     )->store;
385
386     t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1);
387     t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype');
388     Koha::CirculationRules->set_rules(
389         {
390             branchcode => undef,
391             itemtype   => $item1->itype,
392             rules      => {
393                 holdallowed             => 'from_home_library',
394                 hold_fulfillment_policy => 1,
395                 returnbranch            => 'any'
396             }
397         }
398     );
399     $builder->build_object(
400         {
401             class => 'Koha::Item::Transfer::Limits',
402             value => {
403                 toBranch   => $library1->branchcode,
404                 fromBranch => $library2->branchcode,
405                 itemtype   => $item1->itype,
406                 ccode      => undef,
407             }
408         }
409     );
410
411     my @pickup_locations = map {
412         my $pickup_location = $_;
413         grep { $pickup_location->branchcode eq $_ } @branchcodes
414     } $item1->pickup_locations( { patron => $patron1 } )->as_list;
415
416     is( scalar @pickup_locations, 3 - 1, "With a transfer limits we get back the libraries that are pickup locations minus 1 limited library");
417
418     $builder->build_object(
419         {
420             class => 'Koha::Item::Transfer::Limits',
421             value => {
422                 toBranch   => $library4->branchcode,
423                 fromBranch => $library2->branchcode,
424                 itemtype   => $item1->itype,
425                 ccode      => undef,
426             }
427         }
428     );
429
430     @pickup_locations = map {
431         my $pickup_location = $_;
432         grep { $pickup_location->branchcode eq $_ } @branchcodes
433     } $item1->pickup_locations( { patron => $patron1 } )->as_list;
434
435     is( scalar @pickup_locations, 3 - 2, "With 2 transfer limits we get back the libraries that are pickup locations minus 2 limited libraries");
436
437     t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'ccode');
438     @pickup_locations = map {
439         my $pickup_location = $_;
440         grep { $pickup_location->branchcode eq $_ } @branchcodes
441     } $item1->pickup_locations( { patron => $patron1 } )->as_list;
442     is( scalar @pickup_locations, 3, "With no transfer limits of type ccode we get back the libraries that are pickup locations");
443
444     @pickup_locations = map {
445         my $pickup_location = $_;
446         grep { $pickup_location->branchcode eq $_ } @branchcodes
447     } $item_no_ccode->pickup_locations( { patron => $patron1 } )->as_list;
448     is( scalar @pickup_locations, 3, "With no transfer limits of type ccode and an item with no ccode we get back the libraries that are pickup locations");
449
450     $builder->build_object(
451         {
452             class => 'Koha::Item::Transfer::Limits',
453             value => {
454                 toBranch   => $library2->branchcode,
455                 fromBranch => $library2->branchcode,
456                 itemtype   => undef,
457                 ccode      => $item1->ccode,
458             }
459         }
460     );
461
462     @pickup_locations = map {
463         my $pickup_location = $_;
464         grep { $pickup_location->branchcode eq $_ } @branchcodes
465     } $item1->pickup_locations( { patron => $patron1 } )->as_list;
466     is( scalar @pickup_locations, 3 - 1, "With a transfer limits we get back the libraries that are pickup locations minus 1 limited library");
467
468     $builder->build_object(
469         {
470             class => 'Koha::Item::Transfer::Limits',
471             value => {
472                 toBranch   => $library4->branchcode,
473                 fromBranch => $library2->branchcode,
474                 itemtype   => undef,
475                 ccode      => $item1->ccode,
476             }
477         }
478     );
479
480     @pickup_locations = map {
481         my $pickup_location = $_;
482         grep { $pickup_location->branchcode eq $_ } @branchcodes
483     } $item1->pickup_locations( { patron => $patron1 } )->as_list;
484     is( scalar @pickup_locations, 3 - 2, "With 2 transfer limits we get back the libraries that are pickup locations minus 2 limited libraries");
485
486     t::lib::Mocks::mock_preference('UseBranchTransferLimits', 0);
487
488     $schema->storage->txn_rollback;
489 };
490
491 subtest 'request_transfer' => sub {
492     plan tests => 13;
493     $schema->storage->txn_begin;
494
495     my $library1 = $builder->build_object( { class => 'Koha::Libraries' } );
496     my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
497     my $item     = $builder->build_sample_item(
498         {
499             homebranch    => $library1->branchcode,
500             holdingbranch => $library2->branchcode,
501         }
502     );
503
504     # Mandatory fields tests
505     throws_ok { $item->request_transfer( { to => $library1 } ) }
506     'Koha::Exceptions::MissingParameter',
507       'Exception thrown if `reason` parameter is missing';
508
509     throws_ok { $item->request_transfer( { reason => 'Manual' } ) }
510     'Koha::Exceptions::MissingParameter',
511       'Exception thrown if `to` parameter is missing';
512
513     # Successful request
514     my $transfer = $item->request_transfer({ to => $library1, reason => 'Manual' });
515     is( ref($transfer), 'Koha::Item::Transfer',
516         'Koha::Item->request_transfer should return a Koha::Item::Transfer object'
517     );
518     my $original_transfer = $transfer->get_from_storage;
519
520     # Transfer already in progress
521     throws_ok { $item->request_transfer( { to => $library2, reason => 'Manual' } ) }
522     'Koha::Exceptions::Item::Transfer::InQueue',
523       'Exception thrown if transfer is already in progress';
524
525     my $exception = $@;
526     is( ref( $exception->transfer ),
527         'Koha::Item::Transfer',
528         'The exception contains the found Koha::Item::Transfer' );
529
530     # Queue transfer
531     my $queued_transfer = $item->request_transfer(
532         { to => $library2, reason => 'Manual', enqueue => 1 } );
533     is( ref($queued_transfer), 'Koha::Item::Transfer',
534         'Koha::Item->request_transfer allowed when enqueue is set' );
535     my $transfers = $item->get_transfers;
536     is($transfers->count, 2, "There are now 2 live transfers in the queue");
537     $transfer = $transfer->get_from_storage;
538     is_deeply($transfer->unblessed, $original_transfer->unblessed, "Original transfer unchanged");
539     $queued_transfer->datearrived(dt_from_string)->store();
540
541     # Replace transfer
542     my $replaced_transfer = $item->request_transfer(
543         { to => $library2, reason => 'Manual', replace => 1 } );
544     is( ref($replaced_transfer), 'Koha::Item::Transfer',
545         'Koha::Item->request_transfer allowed when replace is set' );
546     $original_transfer->discard_changes;
547     ok($original_transfer->datecancelled, "Original transfer cancelled");
548     $transfers = $item->get_transfers;
549     is($transfers->count, 1, "There is only 1 live transfer in the queue");
550     $replaced_transfer->datearrived(dt_from_string)->store();
551
552     # BranchTransferLimits
553     t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1);
554     t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype');
555     my $limit = Koha::Item::Transfer::Limit->new({
556         fromBranch => $library2->branchcode,
557         toBranch => $library1->branchcode,
558         itemtype => $item->effective_itemtype,
559     })->store;
560
561     throws_ok { $item->request_transfer( { to => $library1, reason => 'Manual' } ) }
562     'Koha::Exceptions::Item::Transfer::Limit',
563       'Exception thrown if transfer is prevented by limits';
564
565     my $forced_transfer = $item->request_transfer( { to => $library1, reason => 'Manual', ignore_limits => 1 } );
566     is( ref($forced_transfer), 'Koha::Item::Transfer',
567         'Koha::Item->request_transfer allowed when ignore_limits is set'
568     );
569
570     $schema->storage->txn_rollback;
571 };
572
573 subtest 'deletion' => sub {
574     plan tests => 13;
575
576     $schema->storage->txn_begin;
577
578     my $biblio = $builder->build_sample_biblio();
579
580     my $item = $builder->build_sample_item(
581         {
582             biblionumber => $biblio->biblionumber,
583         }
584     );
585
586     is( ref( $item->move_to_deleted ), 'Koha::Schema::Result::Deleteditem', 'Koha::Item->move_to_deleted should return the Deleted item' )
587       ;    # FIXME This should be Koha::Deleted::Item
588     is( Koha::Old::Items->search({itemnumber => $item->itemnumber})->count, 1, '->move_to_deleted must have moved the item to deleteditem' );
589     $item = $builder->build_sample_item(
590         {
591             biblionumber => $biblio->biblionumber,
592         }
593     );
594     $item->delete;
595     is( Koha::Old::Items->search({itemnumber => $item->itemnumber})->count, 0, '->move_to_deleted must not have moved the item to deleteditem' );
596
597
598     my $library   = $builder->build_object({ class => 'Koha::Libraries' });
599     my $library_2 = $builder->build_object({ class => 'Koha::Libraries' });
600     t::lib::Mocks::mock_userenv({ branchcode => $library->branchcode });
601
602     my $patron = $builder->build_object({class => 'Koha::Patrons'});
603     $item = $builder->build_sample_item({ library => $library->branchcode });
604
605     # book_on_loan
606     C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
607
608     is(
609         @{$item->safe_to_delete->messages}[0]->message,
610         'book_on_loan',
611         'Koha::Item->safe_to_delete reports item on loan',
612     );
613
614     is(
615         @{$item->safe_to_delete->messages}[0]->message,
616         'book_on_loan',
617         'item that is on loan cannot be deleted',
618     );
619
620     ok(
621         ! $item->safe_to_delete,
622         'Koha::Item->safe_to_delete shows item NOT safe to delete'
623     );
624
625     AddReturn( $item->barcode, $library->branchcode );
626
627     # book_reserved is tested in t/db_dependent/Reserves.t
628
629     # not_same_branch
630     t::lib::Mocks::mock_preference('IndependentBranches', 1);
631     my $item_2 = $builder->build_sample_item({ library => $library_2->branchcode });
632
633     is(
634         @{$item_2->safe_to_delete->messages}[0]->message,
635         'not_same_branch',
636         'Koha::Item->safe_to_delete reports IndependentBranches restriction',
637     );
638
639     is(
640         @{$item_2->safe_to_delete->messages}[0]->message,
641         'not_same_branch',
642         'IndependentBranches prevents deletion at another branch',
643     );
644
645     # linked_analytics
646
647     { # codeblock to limit scope of $module->mock
648
649         my $module = Test::MockModule->new('C4::Items');
650         $module->mock( GetAnalyticsCount => sub { return 1 } );
651
652         $item->discard_changes;
653         is(
654             @{$item->safe_to_delete->messages}[0]->message,
655             'linked_analytics',
656             'Koha::Item->safe_to_delete reports linked analytics',
657         );
658
659         is(
660             @{$item->safe_to_delete->messages}[0]->message,
661             'linked_analytics',
662             'Linked analytics prevents deletion of item',
663         );
664
665     }
666
667     { # last_item_for_hold
668         C4::Reserves::AddReserve({ branchcode => $patron->branchcode, borrowernumber => $patron->borrowernumber, biblionumber => $item->biblionumber });
669         is(
670             @{$item->safe_to_delete->messages}[0]->message,
671             'last_item_for_hold',
672             'Item cannot be deleted if a biblio-level is placed on the biblio and there is only 1 item attached to the biblio'
673         );
674         # With another item attached to the biblio, the item can be deleted
675         $builder->build_sample_item({ biblionumber => $item->biblionumber });
676     }
677
678     ok(
679         $item->safe_to_delete,
680         'Koha::Item->safe_to_delete shows item safe to delete'
681     );
682
683     $item->safe_delete,
684
685     my $test_item = Koha::Items->find( $item->itemnumber );
686
687     is( $test_item, undef,
688         "Koha::Item->safe_delete should delete item if safe_to_delete returns true"
689     );
690
691     $schema->storage->txn_rollback;
692 };
693
694 subtest 'renewal_branchcode' => sub {
695     plan tests => 13;
696
697     $schema->storage->txn_begin;
698
699     my $item = $builder->build_sample_item();
700     my $branch = $builder->build_object({ class => 'Koha::Libraries' });
701     my $checkout = $builder->build_object({
702         class => 'Koha::Checkouts',
703         value => {
704             itemnumber => $item->itemnumber,
705         }
706     });
707
708
709     C4::Context->interface( 'intranet' );
710     t::lib::Mocks::mock_userenv({ branchcode => $branch->branchcode });
711
712     is( $item->renewal_branchcode, $branch->branchcode, "If interface not opac, we get the branch from context");
713     is( $item->renewal_branchcode({ branch => "PANDA"}), $branch->branchcode, "If interface not opac, we get the branch from context even if we pass one in");
714     C4::Context->set_userenv(51, 'userid4tests', undef, 'firstname', 'surname', undef, undef, 0, undef, undef, undef ); #mock userenv doesn't let us set null branch
715     is( $item->renewal_branchcode({ branch => "PANDA"}), "PANDA", "If interface not opac, we get the branch we pass one in if context not set");
716
717     C4::Context->interface( 'opac' );
718
719     t::lib::Mocks::mock_preference('OpacRenewalBranch', undef);
720     is( $item->renewal_branchcode, 'OPACRenew', "If interface opac and OpacRenewalBranch undef, we get OPACRenew");
721     is( $item->renewal_branchcode({branch=>'COW'}), 'OPACRenew', "If interface opac and OpacRenewalBranch undef, we get OPACRenew even if branch passed");
722
723     t::lib::Mocks::mock_preference('OpacRenewalBranch', 'none');
724     is( $item->renewal_branchcode, '', "If interface opac and OpacRenewalBranch is none, we get blank string");
725     is( $item->renewal_branchcode({branch=>'COW'}), '', "If interface opac and OpacRenewalBranch is none, we get blank string even if branch passed");
726
727     t::lib::Mocks::mock_preference('OpacRenewalBranch', 'checkoutbranch');
728     is( $item->renewal_branchcode, $checkout->branchcode, "If interface opac and OpacRenewalBranch set to checkoutbranch, we get branch of checkout");
729     is( $item->renewal_branchcode({branch=>'MONKEY'}), $checkout->branchcode, "If interface opac and OpacRenewalBranch set to checkoutbranch, we get branch of checkout even if branch passed");
730
731     t::lib::Mocks::mock_preference('OpacRenewalBranch','patronhomebranch');
732     is( $item->renewal_branchcode, $checkout->patron->branchcode, "If interface opac and OpacRenewalBranch set to patronbranch, we get branch of patron");
733     is( $item->renewal_branchcode({branch=>'TURKEY'}), $checkout->patron->branchcode, "If interface opac and OpacRenewalBranch set to patronbranch, we get branch of patron even if branch passed");
734
735     t::lib::Mocks::mock_preference('OpacRenewalBranch','itemhomebranch');
736     is( $item->renewal_branchcode, $item->homebranch, "If interface opac and OpacRenewalBranch set to itemhomebranch, we get homebranch of item");
737     is( $item->renewal_branchcode({branch=>'MANATEE'}), $item->homebranch, "If interface opac and OpacRenewalBranch set to itemhomebranch, we get homebranch of item even if branch passed");
738
739     $schema->storage->txn_rollback;
740 };
741
742 subtest 'Tests for itemtype' => sub {
743     plan tests => 2;
744     $schema->storage->txn_begin;
745
746     my $biblio = $builder->build_sample_biblio;
747     my $itemtype = $builder->build_object({ class => 'Koha::ItemTypes' });
748     my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber, itype => $itemtype->itemtype });
749
750     t::lib::Mocks::mock_preference('item-level_itypes', 1);
751     is( $item->itemtype->itemtype, $item->itype, 'Pref enabled' );
752     t::lib::Mocks::mock_preference('item-level_itypes', 0);
753     is( $item->itemtype->itemtype, $biblio->biblioitem->itemtype, 'Pref disabled' );
754
755     $schema->storage->txn_rollback;
756 };
757
758 subtest 'get_transfers' => sub {
759     plan tests => 16;
760     $schema->storage->txn_begin;
761
762     my $item = $builder->build_sample_item();
763
764     my $transfers = $item->get_transfers();
765     is(ref($transfers), 'Koha::Item::Transfers', 'Koha::Item->get_transfer should return a Koha::Item::Transfers object' );
766     is($transfers->count, 0, 'When no transfers exist, the Koha::Item:Transfers object should be empty');
767
768     my $library_to = $builder->build_object( { class => 'Koha::Libraries' } );
769
770     my $transfer_1 = $builder->build_object(
771         {
772             class => 'Koha::Item::Transfers',
773             value => {
774                 itemnumber    => $item->itemnumber,
775                 frombranch    => $item->holdingbranch,
776                 tobranch      => $library_to->branchcode,
777                 reason        => 'Manual',
778                 datesent      => undef,
779                 datearrived   => undef,
780                 datecancelled => undef,
781                 daterequested => \'NOW()'
782             }
783         }
784     );
785
786     $transfers = $item->get_transfers();
787     is($transfers->count, 1, 'When one transfer has been requested, the Koha::Item:Transfers object should contain one result');
788
789     my $transfer_2 = $builder->build_object(
790         {
791             class => 'Koha::Item::Transfers',
792             value => {
793                 itemnumber    => $item->itemnumber,
794                 frombranch    => $item->holdingbranch,
795                 tobranch      => $library_to->branchcode,
796                 reason        => 'Manual',
797                 datesent      => undef,
798                 datearrived   => undef,
799                 datecancelled => undef,
800                 daterequested => \'NOW()'
801             }
802         }
803     );
804
805     my $transfer_3 = $builder->build_object(
806         {
807             class => 'Koha::Item::Transfers',
808             value => {
809                 itemnumber    => $item->itemnumber,
810                 frombranch    => $item->holdingbranch,
811                 tobranch      => $library_to->branchcode,
812                 reason        => 'Manual',
813                 datesent      => undef,
814                 datearrived   => undef,
815                 datecancelled => undef,
816                 daterequested => \'NOW()'
817             }
818         }
819     );
820
821     $transfers = $item->get_transfers();
822     is($transfers->count, 3, 'When there are multiple open transfer requests, the Koha::Item::Transfers object contains them all');
823     my $result_1 = $transfers->next;
824     my $result_2 = $transfers->next;
825     my $result_3 = $transfers->next;
826     is( $result_1->branchtransfer_id, $transfer_1->branchtransfer_id, 'Koha::Item->get_transfers returns the oldest transfer request first');
827     is( $result_2->branchtransfer_id, $transfer_2->branchtransfer_id, 'Koha::Item->get_transfers returns the newer transfer request second');
828     is( $result_3->branchtransfer_id, $transfer_3->branchtransfer_id, 'Koha::Item->get_transfers returns the newest transfer request last');
829
830     $transfer_2->datesent(\'NOW()')->store;
831     $transfers = $item->get_transfers();
832     is($transfers->count, 3, 'When one transfer is set to in_transit, the Koha::Item::Transfers object still contains them all');
833     $result_1 = $transfers->next;
834     $result_2 = $transfers->next;
835     $result_3 = $transfers->next;
836     is( $result_1->branchtransfer_id, $transfer_2->branchtransfer_id, 'Koha::Item->get_transfers returns the active transfer request first');
837     is( $result_2->branchtransfer_id, $transfer_1->branchtransfer_id, 'Koha::Item->get_transfers returns the other transfers oldest to newest');
838     is( $result_3->branchtransfer_id, $transfer_3->branchtransfer_id, 'Koha::Item->get_transfers returns the other transfers oldest to newest');
839
840     $transfer_2->datearrived(\'NOW()')->store;
841     $transfers = $item->get_transfers();
842     is($transfers->count, 2, 'Once a transfer is received, it no longer appears in the list from ->get_transfers()');
843     $result_1 = $transfers->next;
844     $result_2 = $transfers->next;
845     is( $result_1->branchtransfer_id, $transfer_1->branchtransfer_id, 'Koha::Item->get_transfers returns the other transfers oldest to newest');
846     is( $result_2->branchtransfer_id, $transfer_3->branchtransfer_id, 'Koha::Item->get_transfers returns the other transfers oldest to newest');
847
848     $transfer_1->datecancelled(\'NOW()')->store;
849     $transfers = $item->get_transfers();
850     is($transfers->count, 1, 'Once a transfer is cancelled, it no longer appears in the list from ->get_transfers()');
851     $result_1 = $transfers->next;
852     is( $result_1->branchtransfer_id, $transfer_3->branchtransfer_id, 'Koha::Item->get_transfers returns the only transfer that remains');
853
854     $schema->storage->txn_rollback;
855 };
856
857 subtest 'Tests for relationship between item and item_orders via aqorders_item' => sub {
858     plan tests => 3;
859
860     $schema->storage->txn_begin;
861
862     my $biblio = $builder->build_sample_biblio();
863     my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
864
865     my $orders = $item->orders;
866     is ($orders->count, 0, 'No order on this item yet');
867
868     my $order_note = 'Order for ' . $item->itemnumber;
869
870     my $aq_order1 = $builder->build_object({
871         class => 'Koha::Acquisition::Orders',
872         value  => {
873             biblionumber => $biblio->biblionumber,
874             order_internalnote => $order_note,
875         },
876     });
877     my $aq_order2 = $builder->build_object({
878         class => 'Koha::Acquisition::Orders',
879         value  => {
880             biblionumber => $biblio->biblionumber,
881         },
882     });
883     my $aq_order_item1 = $builder->build({
884         source => 'AqordersItem',
885         value  => {
886             ordernumber => $aq_order1->ordernumber,
887             itemnumber => $item->itemnumber,
888         },
889     });
890
891     $orders = $item->orders;
892     is ($orders->count, 1, 'One order found by item with the relationship');
893     is ($orders->next->order_internalnote, $order_note, 'Correct order found by item with the relationship');
894 };
895
896 subtest 'move_to_biblio() tests' => sub {
897     plan tests => 16;
898
899     $schema->storage->txn_begin;
900
901     my $dbh = C4::Context->dbh;
902
903     my $source_biblio = $builder->build_sample_biblio();
904     my $target_biblio = $builder->build_sample_biblio();
905
906     my $source_biblionumber = $source_biblio->biblionumber;
907     my $target_biblionumber = $target_biblio->biblionumber;
908
909     my $item1 = $builder->build_sample_item({ biblionumber => $source_biblionumber });
910     my $item2 = $builder->build_sample_item({ biblionumber => $source_biblionumber });
911     my $item3 = $builder->build_sample_item({ biblionumber => $source_biblionumber });
912
913     my $itemnumber1 = $item1->itemnumber;
914     my $itemnumber2 = $item2->itemnumber;
915
916     my $library = $builder->build_object({ class => 'Koha::Libraries' });
917
918     my $patron = $builder->build_object({
919         class => 'Koha::Patrons',
920         value => { branchcode => $library->branchcode }
921     });
922     my $borrowernumber = $patron->borrowernumber;
923
924     my $aq_budget = $builder->build({
925         source => 'Aqbudget',
926         value  => {
927             budget_notes => 'test',
928         },
929     });
930
931     my $aq_order1 = $builder->build_object({
932         class => 'Koha::Acquisition::Orders',
933         value  => {
934             biblionumber => $source_biblionumber,
935             budget_id => $aq_budget->{budget_id},
936         },
937     });
938     my $aq_order_item1 = $builder->build({
939         source => 'AqordersItem',
940         value  => {
941             ordernumber => $aq_order1->ordernumber,
942             itemnumber => $itemnumber1,
943         },
944     });
945     my $aq_order2 = $builder->build_object({
946         class => 'Koha::Acquisition::Orders',
947         value  => {
948             biblionumber => $source_biblionumber,
949             budget_id => $aq_budget->{budget_id},
950         },
951     });
952     my $aq_order_item2 = $builder->build({
953         source => 'AqordersItem',
954         value  => {
955             ordernumber => $aq_order2->ordernumber,
956             itemnumber => $itemnumber2,
957         },
958     });
959
960     my $bib_level_hold = $builder->build_object({
961         class => 'Koha::Holds',
962         value  => {
963             biblionumber => $source_biblionumber,
964             itemnumber => undef,
965         },
966     });
967     my $item_level_hold1 = $builder->build_object({
968         class => 'Koha::Holds',
969         value  => {
970             biblionumber => $source_biblionumber,
971             itemnumber => $itemnumber1,
972         },
973     });
974     my $item_level_hold2 = $builder->build_object({
975         class => 'Koha::Holds',
976         value  => {
977             biblionumber => $source_biblionumber,
978             itemnumber => $itemnumber2,
979         }
980     });
981
982     my $tmp_holdsqueue1 = $builder->build({
983         source => 'TmpHoldsqueue',
984         value  => {
985             borrowernumber => $borrowernumber,
986             biblionumber   => $source_biblionumber,
987             itemnumber     => $itemnumber1,
988         }
989     });
990     my $tmp_holdsqueue2 = $builder->build({
991         source => 'TmpHoldsqueue',
992         value  => {
993             borrowernumber => $borrowernumber,
994             biblionumber   => $source_biblionumber,
995             itemnumber     => $itemnumber2,
996         }
997     });
998     my $hold_fill_target1 = $builder->build({
999         source => 'HoldFillTarget',
1000         value  => {
1001             borrowernumber     => $borrowernumber,
1002             biblionumber       => $source_biblionumber,
1003             itemnumber         => $itemnumber1,
1004         }
1005     });
1006     my $hold_fill_target2 = $builder->build({
1007         source => 'HoldFillTarget',
1008         value  => {
1009             borrowernumber     => $borrowernumber,
1010             biblionumber       => $source_biblionumber,
1011             itemnumber         => $itemnumber2,
1012         }
1013     });
1014     my $linktracker1 = $builder->build({
1015         source => 'Linktracker',
1016         value  => {
1017             borrowernumber     => $borrowernumber,
1018             biblionumber       => $source_biblionumber,
1019             itemnumber         => $itemnumber1,
1020         }
1021     });
1022     my $linktracker2 = $builder->build({
1023         source => 'Linktracker',
1024         value  => {
1025             borrowernumber     => $borrowernumber,
1026             biblionumber       => $source_biblionumber,
1027             itemnumber         => $itemnumber2,
1028         }
1029     });
1030
1031     my $to_biblionumber_after_move = $item1->move_to_biblio($target_biblio);
1032     is($to_biblionumber_after_move, $target_biblionumber, 'move_to_biblio returns the target biblionumber if success');
1033
1034     $to_biblionumber_after_move = $item1->move_to_biblio($target_biblio);
1035     is($to_biblionumber_after_move, undef, 'move_to_biblio returns undef if the move has failed. If called twice, the item is not attached to the first biblio anymore');
1036
1037     my $get_item1 = Koha::Items->find( $item1->itemnumber );
1038     is($get_item1->biblionumber, $target_biblionumber, 'item1 is moved');
1039     my $get_item2 = Koha::Items->find( $item2->itemnumber );
1040     is($get_item2->biblionumber, $source_biblionumber, 'item2 is not moved');
1041     my $get_item3 = Koha::Items->find( $item3->itemnumber );
1042     is($get_item3->biblionumber, $source_biblionumber, 'item3 is not moved');
1043
1044     $aq_order1->discard_changes;
1045     $aq_order2->discard_changes;
1046     is($aq_order1->biblionumber, $target_biblionumber, 'move_to_biblio moves aq_orders for item 1');
1047     is($aq_order2->biblionumber, $source_biblionumber, 'move_to_biblio does not move aq_orders for item 2');
1048
1049     $bib_level_hold->discard_changes;
1050     $item_level_hold1->discard_changes;
1051     $item_level_hold2->discard_changes;
1052     is($bib_level_hold->biblionumber,   $source_biblionumber, 'move_to_biblio does not move the biblio-level hold');
1053     is($item_level_hold1->biblionumber, $target_biblionumber, 'move_to_biblio moves the item-level hold placed on item 1');
1054     is($item_level_hold2->biblionumber, $source_biblionumber, 'move_to_biblio does not move the item-level hold placed on item 2');
1055
1056     my $get_tmp_holdsqueue1 = $schema->resultset('TmpHoldsqueue')->search({ itemnumber => $tmp_holdsqueue1->{itemnumber} })->single;
1057     my $get_tmp_holdsqueue2 = $schema->resultset('TmpHoldsqueue')->search({ itemnumber => $tmp_holdsqueue2->{itemnumber} })->single;
1058     is($get_tmp_holdsqueue1->biblionumber->biblionumber, $target_biblionumber, 'move_to_biblio moves tmp_holdsqueue for item 1');
1059     is($get_tmp_holdsqueue2->biblionumber->biblionumber, $source_biblionumber, 'move_to_biblio does not move tmp_holdsqueue for item 2');
1060
1061     my $get_hold_fill_target1 = $schema->resultset('HoldFillTarget')->search({ itemnumber => $hold_fill_target1->{itemnumber} })->single;
1062     my $get_hold_fill_target2 = $schema->resultset('HoldFillTarget')->search({ itemnumber => $hold_fill_target2->{itemnumber} })->single;
1063     # Why does ->biblionumber return a Biblio object???
1064     is($get_hold_fill_target1->biblionumber->biblionumber, $target_biblionumber, 'move_to_biblio moves hold_fill_targets for item 1');
1065     is($get_hold_fill_target2->biblionumber->biblionumber, $source_biblionumber, 'move_to_biblio does not move hold_fill_targets for item 2');
1066
1067     my $get_linktracker1 = $schema->resultset('Linktracker')->search({ itemnumber => $linktracker1->{itemnumber} })->single;
1068     my $get_linktracker2 = $schema->resultset('Linktracker')->search({ itemnumber => $linktracker2->{itemnumber} })->single;
1069     is($get_linktracker1->biblionumber->biblionumber, $target_biblionumber, 'move_to_biblio moves linktracker for item 1');
1070     is($get_linktracker2->biblionumber->biblionumber, $source_biblionumber, 'move_to_biblio does not move linktracker for item 2');
1071
1072     $schema->storage->txn_rollback;
1073 };
1074
1075 subtest 'columns_to_str' => sub {
1076     plan tests => 4;
1077
1078     $schema->storage->txn_begin;
1079
1080     my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField( "items.itemnumber" );
1081
1082     my $cache = Koha::Caches->get_instance();
1083     $cache->clear_from_cache("MarcStructure-0-");
1084     $cache->clear_from_cache("MarcStructure-1-");
1085     $cache->clear_from_cache("default_value_for_mod_marc-");
1086     $cache->clear_from_cache("MarcSubfieldStructure-");
1087
1088     # Creating subfields 'é', 'è' that are not linked with a kohafield
1089     Koha::MarcSubfieldStructures->search(
1090         {
1091             frameworkcode => '',
1092             tagfield => $itemtag,
1093             tagsubfield => ['é', 'è'],
1094         }
1095     )->delete;    # In case it exist already
1096
1097     # é is not linked with a AV
1098     # è is linked with AV branches
1099     Koha::MarcSubfieldStructure->new(
1100         {
1101             frameworkcode => '',
1102             tagfield      => $itemtag,
1103             tagsubfield   => 'é',
1104             kohafield     => undef,
1105             repeatable    => 1,
1106             defaultvalue  => 'ééé',
1107             tab           => 10,
1108         }
1109     )->store;
1110     Koha::MarcSubfieldStructure->new(
1111         {
1112             frameworkcode    => '',
1113             tagfield         => $itemtag,
1114             tagsubfield      => 'è',
1115             kohafield        => undef,
1116             repeatable       => 1,
1117             defaultvalue     => 'èèè',
1118             tab              => 10,
1119             authorised_value => 'branches',
1120         }
1121     )->store;
1122
1123     my $biblio = $builder->build_sample_biblio({ frameworkcode => '' });
1124     my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
1125     my $lost_av = $builder->build_object({ class => 'Koha::AuthorisedValues', value => { category => 'LOST', authorised_value => '42' }});
1126     my $dateaccessioned = '2020-12-15';
1127     my $library = Koha::Libraries->search->next;
1128     my $branchcode = $library->branchcode;
1129
1130     my $some_marc_xml = qq{<?xml version="1.0" encoding="UTF-8"?>
1131 <collection
1132   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1133   xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd"
1134   xmlns="http://www.loc.gov/MARC21/slim">
1135
1136 <record>
1137   <leader>         a              </leader>
1138   <datafield tag="999" ind1=" " ind2=" ">
1139     <subfield code="é">value é</subfield>
1140     <subfield code="è">$branchcode</subfield>
1141   </datafield>
1142 </record>
1143
1144 </collection>};
1145
1146     $item->update(
1147         {
1148             itemlost           => $lost_av->authorised_value,
1149             dateaccessioned    => $dateaccessioned,
1150             more_subfields_xml => $some_marc_xml,
1151         }
1152     );
1153
1154     $item = $item->get_from_storage;
1155
1156     my $s = $item->columns_to_str;
1157     is( $s->{itemlost}, $lost_av->lib, 'Attributes linked with AV replaced with description' );
1158     is( $s->{dateaccessioned}, '2020-12-15', 'Date attributes iso formatted');
1159     is( $s->{'é'}, 'value é', 'subfield ok with more than a-Z');
1160     is( $s->{'è'}, $library->branchname );
1161
1162     $cache->clear_from_cache("MarcStructure-0-");
1163     $cache->clear_from_cache("MarcStructure-1-");
1164     $cache->clear_from_cache("default_value_for_mod_marc-");
1165     $cache->clear_from_cache("MarcSubfieldStructure-");
1166
1167     $schema->storage->txn_rollback;
1168
1169 };
1170
1171 subtest 'store() tests' => sub {
1172
1173     plan tests => 1;
1174
1175     subtest '_set_found_trigger() tests' => sub {
1176
1177         plan tests => 6;
1178
1179         $schema->storage->txn_begin;
1180
1181         my $patron = $builder->build_object({ class => 'Koha::Patrons' });
1182         my $item   = $builder->build_sample_item({ itemlost => 1, itemlost_on => dt_from_string() });
1183
1184         # Add a lost item debit
1185         my $debit = $patron->account->add_debit(
1186             {
1187                 amount    => 10,
1188                 type      => 'LOST',
1189                 item_id   => $item->id,
1190                 interface => 'intranet',
1191             }
1192         );
1193
1194         my $lostreturn_policy = 'charge';
1195
1196         my $mocked_circ_rules = Test::MockModule->new('Koha::CirculationRules');
1197         $mocked_circ_rules->mock( 'get_lostreturn_policy', sub { return $lostreturn_policy; } );
1198
1199         # simulate it was found
1200         $item->set( { itemlost => 0 } )->store;
1201
1202         my $messages = $item->object_messages;
1203
1204         my $message_1 = $messages->[0];
1205
1206         is( $message_1->type,    'info',          'type is correct' );
1207         is( $message_1->message, 'lost_refunded', 'message is correct' );
1208
1209         # Find the refund credit
1210         my $credit = $debit->credits->next;
1211
1212         is_deeply(
1213             $message_1->payload,
1214             { credit_id => $credit->id },
1215             'type is correct'
1216         );
1217
1218         my $message_2 = $messages->[1];
1219
1220         is( $message_2->type,    'info',        'type is correct' );
1221         is( $message_2->message, 'lost_charge', 'message is correct' );
1222         is( $message_2->payload, undef,         'no payload' );
1223
1224         $schema->storage->txn_rollback;
1225     };
1226 };