Bug 20144: [sql_modes] Set default value for biblio.datecreated in tests
[koha.git] / t / db_dependent / Items.t
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 under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 2 of the License, or (at your option) any later
8 # version.
9 #
10 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along
15 # with Koha; if not, write to the Free Software Foundation, Inc.,
16 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 #
18
19 use Modern::Perl;
20 use Data::Dumper;
21
22 use MARC::Record;
23 use C4::Biblio;
24 use Koha::Database;
25 use Koha::DateUtils qw( dt_from_string );
26 use Koha::Library;
27
28 use t::lib::Mocks;
29 use t::lib::TestBuilder;
30
31 use Koha::MarcSubfieldStructures;
32 use Koha::Caches;
33
34 use Test::More tests => 12;
35
36 use Test::Warn;
37
38 BEGIN {
39     use_ok('C4::Items');
40     use_ok('Koha::Items');
41 }
42
43 my $schema = Koha::Database->new->schema;
44 my $location = 'My Location';
45
46 subtest 'General Add, Get and Del tests' => sub {
47
48     plan tests => 16;
49
50     $schema->storage->txn_begin;
51
52     my $builder = t::lib::TestBuilder->new;
53     my $library = $builder->build({
54         source => 'Branch',
55     });
56     my $itemtype = $builder->build({
57         source => 'Itemtype',
58     });
59
60     # Create a biblio instance for testing
61     t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
62     my ($bibnum, $bibitemnum) = get_biblio();
63
64     # Add an item.
65     my ($item_bibnum, $item_bibitemnum, $itemnumber) = AddItem({ homebranch => $library->{branchcode}, holdingbranch => $library->{branchcode}, location => $location, itype => $itemtype->{itemtype} } , $bibnum);
66     cmp_ok($item_bibnum, '==', $bibnum, "New item is linked to correct biblionumber.");
67     cmp_ok($item_bibitemnum, '==', $bibitemnum, "New item is linked to correct biblioitemnumber.");
68
69     # Get item.
70     my $getitem = GetItem($itemnumber);
71     cmp_ok($getitem->{'itemnumber'}, '==', $itemnumber, "Retrieved item has correct itemnumber.");
72     cmp_ok($getitem->{'biblioitemnumber'}, '==', $item_bibitemnum, "Retrieved item has correct biblioitemnumber.");
73     is( $getitem->{location}, $location, "The location should not have been modified" );
74     is( $getitem->{permanent_location}, $location, "The permanent_location should have been set to the location value" );
75
76     # Modify item; setting barcode.
77     ModItem({ barcode => '987654321' }, $bibnum, $itemnumber);
78     my $moditem = GetItem($itemnumber);
79     cmp_ok($moditem->{'barcode'}, '==', '987654321', 'Modified item barcode successfully to: '.$moditem->{'barcode'} . '.');
80
81     # Delete item.
82     DelItem({ biblionumber => $bibnum, itemnumber => $itemnumber });
83     my $getdeleted = GetItem($itemnumber);
84     is($getdeleted->{'itemnumber'}, undef, "Item deleted as expected.");
85
86     ($item_bibnum, $item_bibitemnum, $itemnumber) = AddItem({ homebranch => $library->{branchcode}, holdingbranch => $library->{branchcode}, location => $location, permanent_location => 'my permanent location', itype => $itemtype->{itemtype} } , $bibnum);
87     $getitem = GetItem($itemnumber);
88     is( $getitem->{location}, $location, "The location should not have been modified" );
89     is( $getitem->{permanent_location}, 'my permanent location', "The permanent_location should not have modified" );
90
91     ModItem({ location => $location }, $bibnum, $itemnumber);
92     $getitem = GetItem($itemnumber);
93     is( $getitem->{location}, $location, "The location should have been set to correct location" );
94     is( $getitem->{permanent_location}, $location, "The permanent_location should have been set to location" );
95
96     ModItem({ location => 'CART' }, $bibnum, $itemnumber);
97     $getitem = GetItem($itemnumber);
98     is( $getitem->{location}, 'CART', "The location should have been set to CART" );
99     is( $getitem->{permanent_location}, $location, "The permanent_location should not have been set to CART" );
100
101     t::lib::Mocks::mock_preference('item-level_itypes', '1');
102     $getitem = GetItem($itemnumber);
103     is( $getitem->{itype}, $itemtype->{itemtype}, "Itemtype set correctly when using item-level_itypes" );
104     t::lib::Mocks::mock_preference('item-level_itypes', '0');
105     $getitem = GetItem($itemnumber);
106     is( $getitem->{itype}, undef, "Itemtype set correctly when not using item-level_itypes" );
107
108     $schema->storage->txn_rollback;
109 };
110
111 subtest 'GetHiddenItemnumbers tests' => sub {
112
113     plan tests => 9;
114
115     # This sub is controlled by the OpacHiddenItems system preference.
116
117     $schema->storage->txn_begin;
118
119     my $builder = t::lib::TestBuilder->new;
120     my $library1 = $builder->build({
121         source => 'Branch',
122     });
123
124     my $library2 = $builder->build({
125         source => 'Branch',
126     });
127     my $itemtype = $builder->build({
128         source => 'Itemtype',
129     });
130
131     # Create a new biblio
132     t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
133     my ($biblionumber, $biblioitemnumber) = get_biblio();
134
135     # Add two items
136     my ( $item1_bibnum, $item1_bibitemnum, $item1_itemnumber ) = AddItem(
137         {
138             homebranch    => $library1->{branchcode},
139             holdingbranch => $library1->{branchcode},
140             withdrawn     => 1,
141             itype         => $itemtype->{itemtype},
142         },
143         $biblionumber
144     );
145     my ( $item2_bibnum, $item2_bibitemnum, $item2_itemnumber ) = AddItem(
146         {
147             homebranch    => $library2->{branchcode},
148             holdingbranch => $library2->{branchcode},
149             withdrawn     => 0,
150             itype         => $itemtype->{itemtype},
151         },
152         $biblionumber
153     );
154
155     my $opachiddenitems;
156     my @itemnumbers = ($item1_itemnumber,$item2_itemnumber);
157     my @hidden;
158     my @items;
159     push @items, GetItem( $item1_itemnumber );
160     push @items, GetItem( $item2_itemnumber );
161
162     # Empty OpacHiddenItems
163     t::lib::Mocks::mock_preference('OpacHiddenItems','');
164     ok( !defined( GetHiddenItemnumbers( @items ) ),
165         "Hidden items list undef if OpacHiddenItems empty");
166
167     # Blank spaces
168     t::lib::Mocks::mock_preference('OpacHiddenItems','  ');
169     ok( scalar GetHiddenItemnumbers( @items ) == 0,
170         "Hidden items list empty if OpacHiddenItems only contains blanks");
171
172     # One variable / value
173     $opachiddenitems = "
174         withdrawn: [1]";
175     t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
176     @hidden = GetHiddenItemnumbers( @items );
177     ok( scalar @hidden == 1, "Only one hidden item");
178     is( $hidden[0], $item1_itemnumber, "withdrawn=1 is hidden");
179
180     # One variable, two values
181     $opachiddenitems = "
182         withdrawn: [1,0]";
183     t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
184     @hidden = GetHiddenItemnumbers( @items );
185     ok( scalar @hidden == 2, "Two items hidden");
186     is_deeply( \@hidden, \@itemnumbers, "withdrawn=1 and withdrawn=0 hidden");
187
188     # Two variables, a value each
189     $opachiddenitems = "
190         withdrawn: [1]
191         homebranch: [$library2->{branchcode}]
192     ";
193     t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
194     @hidden = GetHiddenItemnumbers( @items );
195     ok( scalar @hidden == 2, "Two items hidden");
196     is_deeply( \@hidden, \@itemnumbers, "withdrawn=1 and homebranch library2 hidden");
197
198     # Valid OpacHiddenItems, empty list
199     @items = ();
200     @hidden = GetHiddenItemnumbers( @items );
201     ok( scalar @hidden == 0, "Empty items list, no item hidden");
202
203     $schema->storage->txn_rollback;
204 };
205
206 subtest 'GetItemsInfo tests' => sub {
207
208     plan tests => 4;
209
210     $schema->storage->txn_begin;
211
212     my $builder = t::lib::TestBuilder->new;
213     my $library1 = $builder->build({
214         source => 'Branch',
215     });
216     my $library2 = $builder->build({
217         source => 'Branch',
218     });
219     my $itemtype = $builder->build({
220         source => 'Itemtype',
221     });
222
223     # Add a biblio
224     my ($biblionumber, $biblioitemnumber) = get_biblio();
225     # Add an item
226     my ( $item_bibnum, $item_bibitemnum, $itemnumber ) = AddItem(
227         {
228             homebranch    => $library1->{branchcode},
229             holdingbranch => $library2->{branchcode},
230             itype         => $itemtype->{itemtype},
231         },
232         $biblionumber
233     );
234
235     my $library = Koha::Libraries->find( $library1->{branchcode} );
236     $library->opac_info("homebranch OPAC info");
237     $library->store;
238
239     $library = Koha::Libraries->find( $library2->{branchcode} );
240     $library->opac_info("holdingbranch OPAC info");
241     $library->store;
242
243     my @results = GetItemsInfo( $biblionumber );
244     ok( @results, 'GetItemsInfo returns results');
245     is( $results[0]->{ home_branch_opac_info }, "homebranch OPAC info",
246         'GetItemsInfo returns the correct home branch OPAC info notice' );
247     is( $results[0]->{ holding_branch_opac_info }, "holdingbranch OPAC info",
248         'GetItemsInfo returns the correct holding branch OPAC info notice' );
249     is( exists( $results[0]->{ onsite_checkout } ), 1,
250         'GetItemsInfo returns a onsite_checkout key' );
251
252     $schema->storage->txn_rollback;
253 };
254
255 subtest q{Test Koha::Database->schema()->resultset('Item')->itemtype()} => sub {
256
257     plan tests => 4;
258
259     $schema->storage->txn_begin;
260
261     my $biblio = $schema->resultset('Biblio')->create({
262         title       => "Test title",
263         datecreated => dt_from_string,
264         biblioitems => [ { itemtype => 'BIB_LEVEL' } ],
265     });
266     my $biblioitem = $biblio->biblioitems->first;
267     my $item = $schema->resultset('Item')->create({
268         biblioitemnumber => $biblioitem->biblioitemnumber,
269         biblionumber     => $biblio->biblionumber,
270         itype            => "ITEM_LEVEL",
271     });
272
273     t::lib::Mocks::mock_preference( 'item-level_itypes', 0 );
274     is( $item->effective_itemtype(), 'BIB_LEVEL', '$item->itemtype() returns biblioitem.itemtype when item-level_itypes is disabled' );
275
276     t::lib::Mocks::mock_preference( 'item-level_itypes', 1 );
277     is( $item->effective_itemtype(), 'ITEM_LEVEL', '$item->itemtype() returns items.itype when item-level_itypes is enabled' );
278
279     # If itemtype is not defined and item-level_level item types are set
280     # fallback to biblio-level itemtype (Bug 14651) and warn
281     $item->itype( undef );
282     $item->update();
283     my $effective_itemtype;
284     warning_is { $effective_itemtype = $item->effective_itemtype() }
285                 "item-level_itypes set but no itemtype set for item (".$item->itemnumber.")",
286                 '->effective_itemtype() raises a warning when falling back to bib-level';
287
288     ok( defined $effective_itemtype &&
289                 $effective_itemtype eq 'BIB_LEVEL',
290         '$item->effective_itemtype() falls back to biblioitems.itemtype when item-level_itypes is enabled but undef' );
291
292     $schema->storage->txn_rollback;
293 };
294
295 subtest 'SearchItems test' => sub {
296     plan tests => 14;
297
298     $schema->storage->txn_begin;
299     my $dbh = C4::Context->dbh;
300     my $builder = t::lib::TestBuilder->new;
301
302     my $library1 = $builder->build({
303         source => 'Branch',
304     });
305     my $library2 = $builder->build({
306         source => 'Branch',
307     });
308     my $itemtype = $builder->build({
309         source => 'Itemtype',
310     });
311
312     t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
313     my $cpl_items_before = SearchItemsByField( 'homebranch', $library1->{branchcode});
314
315     my ($biblionumber) = get_biblio();
316
317     my (undef, $initial_items_count) = SearchItems(undef, {rows => 1});
318
319     # Add two items
320     my (undef, undef, $item1_itemnumber) = AddItem({
321         homebranch => $library1->{branchcode},
322         holdingbranch => $library1->{branchcode},
323         itype => $itemtype->{itemtype},
324     }, $biblionumber);
325     my (undef, undef, $item2_itemnumber) = AddItem({
326         homebranch => $library2->{branchcode},
327         holdingbranch => $library2->{branchcode},
328         itype => $itemtype->{itemtype},
329     }, $biblionumber);
330
331     my ($items, $total_results);
332
333     ($items, $total_results) = SearchItems();
334     is($total_results, $initial_items_count + 2, "Created 2 new items");
335     is(scalar @$items, $total_results, "SearchItems() returns all items");
336
337     ($items, $total_results) = SearchItems(undef, {rows => 1});
338     is($total_results, $initial_items_count + 2);
339     is(scalar @$items, 1, "SearchItems(undef, {rows => 1}) returns only 1 item");
340
341     # Search all items where homebranch = 'CPL'
342     my $filter = {
343         field => 'homebranch',
344         query => $library1->{branchcode},
345         operator => '=',
346     };
347     ($items, $total_results) = SearchItems($filter);
348     ok($total_results > 0, "There is at least one CPL item");
349     my $all_items_are_CPL = 1;
350     foreach my $item (@$items) {
351         if ($item->{homebranch} ne $library1->{branchcode}) {
352             $all_items_are_CPL = 0;
353             last;
354         }
355     }
356     ok($all_items_are_CPL, "All items returned by SearchItems are from CPL");
357
358     # Search all items where homebranch != 'CPL'
359     $filter = {
360         field => 'homebranch',
361         query => $library1->{branchcode},
362         operator => '!=',
363     };
364     ($items, $total_results) = SearchItems($filter);
365     ok($total_results > 0, "There is at least one non-CPL item");
366     my $all_items_are_not_CPL = 1;
367     foreach my $item (@$items) {
368         if ($item->{homebranch} eq $library1->{branchcode}) {
369             $all_items_are_not_CPL = 0;
370             last;
371         }
372     }
373     ok($all_items_are_not_CPL, "All items returned by SearchItems are not from CPL");
374
375     # Search all items where biblio title (245$a) is like 'Silence in the %'
376     $filter = {
377         field => 'marc:245$a',
378         query => 'Silence in the %',
379         operator => 'like',
380     };
381     ($items, $total_results) = SearchItems($filter);
382     ok($total_results >= 2, "There is at least 2 items with a biblio title like 'Silence in the %'");
383
384     # Search all items where biblio title is 'Silence in the library'
385     # and homebranch is 'CPL'
386     $filter = {
387         conjunction => 'AND',
388         filters => [
389             {
390                 field => 'marc:245$a',
391                 query => 'Silence in the %',
392                 operator => 'like',
393             },
394             {
395                 field => 'homebranch',
396                 query => $library1->{branchcode},
397                 operator => '=',
398             },
399         ],
400     };
401     ($items, $total_results) = SearchItems($filter);
402     my $found = 0;
403     foreach my $item (@$items) {
404         if ($item->{itemnumber} == $item1_itemnumber) {
405             $found = 1;
406             last;
407         }
408     }
409     ok($found, "item1 found");
410
411     my $frameworkcode = q||;
412     my ($itemfield) = GetMarcFromKohaField('items.itemnumber', $frameworkcode);
413
414     # Create item subfield 'z' without link
415     $dbh->do('DELETE FROM marc_subfield_structure WHERE tagfield=? AND tagsubfield="z" AND frameworkcode=?', undef, $itemfield, $frameworkcode);
416     $dbh->do('INSERT INTO marc_subfield_structure (tagfield, tagsubfield, frameworkcode) VALUES (?, "z", ?)', undef, $itemfield, $frameworkcode);
417
418     # Clear cache
419     my $cache = Koha::Caches->get_instance();
420     $cache->clear_from_cache("MarcStructure-0-$frameworkcode");
421     $cache->clear_from_cache("MarcStructure-1-$frameworkcode");
422     $cache->clear_from_cache("default_value_for_mod_marc-");
423     $cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
424
425     my $item3_record = new MARC::Record;
426     $item3_record->append_fields(
427         new MARC::Field(
428             $itemfield, '', '',
429             'z' => 'foobar',
430             'y' => $itemtype->{itemtype}
431         )
432     );
433     my (undef, undef, $item3_itemnumber) = AddItemFromMarc($item3_record,
434         $biblionumber);
435
436     # Search item where item subfield z is "foobar"
437     $filter = {
438         field => 'marc:' . $itemfield . '$z',
439         query => 'foobar',
440         operator => 'like',
441     };
442     ($items, $total_results) = SearchItems($filter);
443     ok(scalar @$items == 1, 'found 1 item with $z = "foobar"');
444
445     # Link $z to items.itemnotes (and make sure there is no other subfields
446     # linked to it)
447     $dbh->do('DELETE FROM marc_subfield_structure WHERE kohafield="items.itemnotes" AND frameworkcode=?', undef, $itemfield, $frameworkcode);
448     $dbh->do('UPDATE marc_subfield_structure SET kohafield="items.itemnotes" WHERE tagfield=? AND tagsubfield="z" AND frameworkcode=?', undef, $itemfield, $frameworkcode);
449
450     # Clear cache
451     $cache->clear_from_cache("MarcStructure-0-$frameworkcode");
452     $cache->clear_from_cache("MarcStructure-1-$frameworkcode");
453     $cache->clear_from_cache("default_value_for_mod_marc-");
454     $cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
455
456     ModItemFromMarc($item3_record, $biblionumber, $item3_itemnumber);
457
458     # Make sure the link is used
459     my $item3 = GetItem($item3_itemnumber);
460     ok($item3->{itemnotes} eq 'foobar', 'itemnotes eq "foobar"');
461
462     # Do the same search again.
463     # This time it will search in items.itemnotes
464     ($items, $total_results) = SearchItems($filter);
465     ok(scalar @$items == 1, 'found 1 item with itemnotes = "foobar"');
466
467     my $cpl_items_after = SearchItemsByField( 'homebranch', $library1->{branchcode});
468     is( ( scalar( @$cpl_items_after ) - scalar ( @$cpl_items_before ) ), 1, 'SearchItemsByField should return something' );
469
470     $schema->storage->txn_rollback;
471 };
472
473 subtest 'Koha::Item(s) tests' => sub {
474
475     plan tests => 5;
476
477     $schema->storage->txn_begin();
478
479     my $builder = t::lib::TestBuilder->new;
480     my $library1 = $builder->build({
481         source => 'Branch',
482     });
483     my $library2 = $builder->build({
484         source => 'Branch',
485     });
486     my $itemtype = $builder->build({
487         source => 'Itemtype',
488     });
489
490     # Create a biblio and item for testing
491     t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
492     my ($bibnum, $bibitemnum) = get_biblio();
493     my ( $item_bibnum, $item_bibitemnum, $itemnumber ) = AddItem(
494         {
495             homebranch    => $library1->{branchcode},
496             holdingbranch => $library2->{branchcode},
497             itype         => $itemtype->{itemtype},
498         },
499         $bibnum
500     );
501
502     # Get item.
503     my $item = Koha::Items->find( $itemnumber );
504     is( ref($item), 'Koha::Item', "Got Koha::Item" );
505
506     my $homebranch = $item->home_branch();
507     is( ref($homebranch), 'Koha::Library', "Got Koha::Library from home_branch method" );
508     is( $homebranch->branchcode(), $library1->{branchcode}, "Home branch code matches homebranch" );
509
510     my $holdingbranch = $item->holding_branch();
511     is( ref($holdingbranch), 'Koha::Library', "Got Koha::Library from holding_branch method" );
512     is( $holdingbranch->branchcode(), $library2->{branchcode}, "Home branch code matches holdingbranch" );
513
514     $schema->storage->txn_rollback;
515 };
516
517 subtest 'C4::Biblio::EmbedItemsInMarcBiblio' => sub {
518     plan tests => 7;
519
520     $schema->storage->txn_begin();
521
522     my $builder = t::lib::TestBuilder->new;
523     my $library1 = $builder->build({
524         source => 'Branch',
525     });
526     my $library2 = $builder->build({
527         source => 'Branch',
528     });
529     my $itemtype = $builder->build({
530         source => 'Itemtype',
531     });
532
533     my ( $biblionumber, $biblioitemnumber ) = get_biblio();
534     my $item_infos = [
535         { homebranch => $library1->{branchcode}, holdingbranch => $library1->{branchcode} },
536         { homebranch => $library1->{branchcode}, holdingbranch => $library1->{branchcode} },
537         { homebranch => $library1->{branchcode}, holdingbranch => $library1->{branchcode} },
538         { homebranch => $library2->{branchcode}, holdingbranch => $library2->{branchcode} },
539         { homebranch => $library2->{branchcode}, holdingbranch => $library2->{branchcode} },
540         { homebranch => $library1->{branchcode}, holdingbranch => $library2->{branchcode} },
541         { homebranch => $library1->{branchcode}, holdingbranch => $library2->{branchcode} },
542         { homebranch => $library1->{branchcode}, holdingbranch => $library2->{branchcode} },
543     ];
544     my $number_of_items = scalar @$item_infos;
545     my $number_of_items_with_homebranch_is_CPL =
546       grep { $_->{homebranch} eq $library1->{branchcode} } @$item_infos;
547
548     my @itemnumbers;
549     for my $item_info (@$item_infos) {
550         my ( undef, undef, $itemnumber ) = AddItem(
551             {
552                 homebranch    => $item_info->{homebranch},
553                 holdingbranch => $item_info->{holdingbanch},
554                 itype         => $itemtype->{itemtype},
555             },
556             $biblionumber
557         );
558         push @itemnumbers, $itemnumber;
559     }
560
561     # Emptied the OpacHiddenItems pref
562     t::lib::Mocks::mock_preference( 'OpacHiddenItems', '' );
563
564     my ($itemfield) =
565       C4::Biblio::GetMarcFromKohaField( 'items.itemnumber', '' );
566     my $record = C4::Biblio::GetMarcBiblio({ biblionumber => $biblionumber });
567     warning_is { C4::Biblio::EmbedItemsInMarcBiblio() }
568     { carped => 'EmbedItemsInMarcBiblio: No MARC record passed' },
569       'Should crap is no record passed.';
570
571     C4::Biblio::EmbedItemsInMarcBiblio( $record, $biblionumber );
572     my @items = $record->field($itemfield);
573     is( scalar @items, $number_of_items, 'Should return all items' );
574
575     C4::Biblio::EmbedItemsInMarcBiblio( $record, $biblionumber,
576         [ $itemnumbers[1], $itemnumbers[3] ] );
577     @items = $record->field($itemfield);
578     is( scalar @items, 2, 'Should return all items present in the list' );
579
580     C4::Biblio::EmbedItemsInMarcBiblio( $record, $biblionumber, undef, 1 );
581     @items = $record->field($itemfield);
582     is( scalar @items, $number_of_items, 'Should return all items for opac' );
583
584     my $opachiddenitems = "
585         homebranch: ['$library1->{branchcode}']";
586     t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
587
588     C4::Biblio::EmbedItemsInMarcBiblio( $record, $biblionumber );
589     @items = $record->field($itemfield);
590     is( scalar @items,
591         $number_of_items,
592         'Even with OpacHiddenItems set, all items should have been embedded' );
593
594     C4::Biblio::EmbedItemsInMarcBiblio( $record, $biblionumber, undef, 1 );
595     @items = $record->field($itemfield);
596     is(
597         scalar @items,
598         $number_of_items - $number_of_items_with_homebranch_is_CPL,
599 'For OPAC, the pref OpacHiddenItems should have been take into account. Only items with homebranch ne CPL should have been embedded'
600     );
601
602     $opachiddenitems = "
603         homebranch: ['$library1->{branchcode}', '$library2->{branchcode}']";
604     t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
605     C4::Biblio::EmbedItemsInMarcBiblio( $record, $biblionumber, undef, 1 );
606     @items = $record->field($itemfield);
607     is(
608         scalar @items,
609         0,
610 'For OPAC, If all items are hidden, no item should have been embedded'
611     );
612
613     $schema->storage->txn_rollback;
614 };
615
616
617 subtest 'C4::Items::_build_default_values_for_mod_marc' => sub {
618     plan tests => 4;
619
620     $schema->storage->txn_begin();
621
622     my $builder = t::lib::TestBuilder->new;
623     my $framework = $builder->build({ source => 'BiblioFramework' });
624
625     # Link biblio.biblionumber and biblioitems.biblioitemnumber to avoid _koha_marc_update_bib_ids to fail with 'no biblio[item]number tag for framework"
626     Koha::MarcSubfieldStructures->search({ frameworkcode => '', tagfield => '999', tagsubfield => [ 'c', 'd' ] })->delete;
627     Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '999', tagsubfield => 'c', kohafield => 'biblio.biblionumber' })->store;
628     Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '999', tagsubfield => 'd', kohafield => 'biblioitems.biblioitemnumber' })->store;
629
630     # Same for item fields: itemnumber, barcode, itype
631     Koha::MarcSubfieldStructures->search({ frameworkcode => '', tagfield => '952', tagsubfield => [ '9', 'p', 'y' ] })->delete;
632     Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => '9', kohafield => 'items.itemnumber' })->store;
633     Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => 'p', kohafield => 'items.barcode' })->store;
634     Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => 'y', kohafield => 'items.itype' })->store;
635     Koha::Caches->get_instance->clear_from_cache( "MarcSubfieldStructure-" );
636
637     my $itemtype = $builder->build({ source => 'Itemtype' })->{itemtype};
638
639     # Create a record with a barcode
640     my ($biblionumber) = get_biblio( $framework->{frameworkcode} );
641     my $item_record = new MARC::Record;
642     my $a_barcode = 'a barcode';
643     my $barcode_field = MARC::Field->new(
644         '952', ' ', ' ',
645         p => $a_barcode,
646         y => $itemtype
647     );
648     my $itemtype_field = MARC::Field->new(
649         '952', ' ', ' ',
650         y => $itemtype
651     );
652     $item_record->append_fields( $barcode_field );
653     my (undef, undef, $item_itemnumber) = AddItemFromMarc($item_record, $biblionumber);
654
655     # Make sure everything has been set up
656     my $item = GetItem($item_itemnumber);
657     is( $item->{barcode}, $a_barcode, 'Everything has been set up correctly, the barcode is defined as expected' );
658
659     # Delete the barcode field and save the record
660     $item_record->delete_fields( $barcode_field );
661     $item_record->append_fields( $itemtype_field ); # itemtype is mandatory
662     ModItemFromMarc($item_record, $biblionumber, $item_itemnumber);
663     $item = GetItem($item_itemnumber);
664     is( $item->{barcode}, undef, 'The default value should have been set to the barcode, the field is mapped to a kohafield' );
665
666     # Re-add the barcode field and save the record
667     $item_record->append_fields( $barcode_field );
668     ModItemFromMarc($item_record, $biblionumber, $item_itemnumber);
669     $item = GetItem($item_itemnumber);
670     is( $item->{barcode}, $a_barcode, 'Everything has been set up correctly, the barcode is defined as expected' );
671
672     # Remove the mapping for barcode
673     Koha::MarcSubfieldStructures->search({ frameworkcode => '', tagfield => '952', tagsubfield => 'p' })->delete;
674
675     # And make sure the caches are cleared
676     my $cache = Koha::Caches->get_instance();
677     $cache->clear_from_cache("default_value_for_mod_marc-");
678     $cache->clear_from_cache("MarcSubfieldStructure-");
679
680     # Update the MARC field with another value
681     $item_record->delete_fields( $barcode_field );
682     my $another_barcode = 'another_barcode';
683     my $another_barcode_field = MARC::Field->new(
684         '952', ' ', ' ',
685         p => $another_barcode,
686     );
687     $item_record->append_fields( $another_barcode_field );
688     # The DB value should not have been updated
689     ModItemFromMarc($item_record, $biblionumber, $item_itemnumber);
690     $item = GetItem($item_itemnumber);
691     is ( $item->{barcode}, $a_barcode, 'items.barcode is not mapped anymore, so the DB column has not been updated' );
692
693     $cache->clear_from_cache("default_value_for_mod_marc-");
694     $cache->clear_from_cache( "MarcSubfieldStructure-" );
695     $schema->storage->txn_rollback;
696 };
697
698 subtest '_mod_item_dates' => sub {
699     plan tests => 11;
700
701     is( C4::Items::_mod_item_dates(), undef, 'Call without parameters' );
702     is( C4::Items::_mod_item_dates(1), undef, 'Call without hashref' );
703
704     my $orgitem;
705     my $item = {
706         itemcallnumber  => 'V II 149 1963',
707         barcode         => '109304',
708     };
709     $orgitem = { %$item };
710     C4::Items::_mod_item_dates($item);
711     is_deeply( $item, $orgitem, 'No dates passed to _mod_item_dates' );
712
713     # add two correct dates
714     t::lib::Mocks::mock_preference('dateformat', 'us');
715     $item->{dateaccessioned} = '01/31/2016';
716     $item->{onloan} =  $item->{dateaccessioned};
717     $orgitem = { %$item };
718     C4::Items::_mod_item_dates($item);
719     is( $item->{dateaccessioned}, '2016-01-31', 'dateaccessioned is fine' );
720     is( $item->{onloan}, '2016-01-31', 'onloan is fine too' );
721
722
723     # add some invalid dates
724     $item->{notexistingcolumndate} = '13/1/2015'; # wrong format
725     $item->{anotherdate} = 'tralala'; # even worse
726     $item->{myzerodate} = '0000-00-00'; # wrong too
727     C4::Items::_mod_item_dates($item);
728     is( $item->{notexistingcolumndate}, undef, 'Invalid date became NULL' );
729     is( $item->{anotherdate}, undef, 'Second invalid date became NULL too' );
730     is( $item->{myzerodate}, undef, '0000-00-00 became NULL too' );
731
732     # check if itemlost_on was not touched
733     $item->{itemlost_on} = '12345678';
734     $item->{withdrawn_on} = '12/31/2015 23:59:00';
735     $orgitem = { %$item };
736     C4::Items::_mod_item_dates($item);
737     is_deeply( $item, $orgitem, 'Colums with _on are not touched' );
738
739     t::lib::Mocks::mock_preference('dateformat', 'metric');
740     $item->{dateaccessioned} = '01/31/2016'; #wrong
741     $item->{yetanotherdatetime} = '20/01/2016 13:58:00'; #okay
742     C4::Items::_mod_item_dates($item);
743     is( $item->{dateaccessioned}, undef, 'dateaccessioned wrong format' );
744     is( $item->{yetanotherdatetime}, '2016-01-20 13:58:00',
745         'yetanotherdatetime is ok' );
746 };
747
748 subtest 'get_hostitemnumbers_of' => sub {
749     plan tests => 1;
750
751     my $bib = MARC::Record->new();
752     $bib->append_fields(
753         MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'),
754         MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'),
755         MARC::Field->new('773', ' ', ' ', b => 'b without 0 or 9'),
756     );
757     my ($biblionumber, $bibitemnum) = AddBiblio($bib, '');
758
759     my @itemnumbers = C4::Items::get_hostitemnumbers_of( $biblionumber );
760     is( @itemnumbers, 0, );
761 };
762
763 # Helper method to set up a Biblio.
764 sub get_biblio {
765     my ( $frameworkcode ) = @_;
766     $frameworkcode //= '';
767     my $bib = MARC::Record->new();
768     $bib->append_fields(
769         MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'),
770         MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'),
771     );
772     my ($bibnum, $bibitemnum) = AddBiblio($bib, $frameworkcode);
773     return ($bibnum, $bibitemnum);
774 }