Bug 29684: Fix warn about js/locale_data.js (paycollect.pl)
[koha-ffzg.git] / C4 / Items.pm
index 55bae13..502ccb6 100644 (file)
@@ -20,12 +20,12 @@ package C4::Items;
 
 use Modern::Perl;
 
-use vars qw(@ISA @EXPORT);
+our (@ISA, @EXPORT_OK);
 BEGIN {
     require Exporter;
     @ISA = qw(Exporter);
 
-    @EXPORT = qw(
+    @EXPORT_OK = qw(
         AddItemFromMarc
         AddItemBatchFromMarc
         ModItemFromMarc
@@ -39,31 +39,29 @@ BEGIN {
         GetHostItemsInfo
         get_hostitemnumbers_of
         GetHiddenItemnumbers
-        MoveItemFromBiblio
+        GetMarcItem
         CartToShelf
         GetAnalyticsCount
         SearchItems
         PrepareItemrecordDisplay
+        ToggleNewStatus
     );
 }
 
-use Carp;
-use Try::Tiny;
+use Carp qw( croak );
 use C4::Context;
 use C4::Koha;
-use C4::Biblio;
-use Koha::DateUtils;
+use C4::Biblio qw( GetMarcStructure TransformMarcToKoha );
+use Koha::DateUtils qw( dt_from_string output_pref );
 use MARC::Record;
-use C4::ClassSource;
-use C4::Log;
-use List::MoreUtils qw(any);
-use YAML qw(Load);
+use C4::ClassSource qw( GetClassSort GetClassSources GetClassSource );
+use C4::Log qw( logaction );
+use List::MoreUtils qw( any );
 use DateTime::Format::MySQL;
-use Data::Dumper; # used as part of logging item record changes, not just for
                   # debugging; so please don't remove this
 
 use Koha::AuthorisedValues;
-use Koha::DateUtils qw(dt_from_string);
+use Koha::DateUtils qw( dt_from_string output_pref );
 use Koha::Database;
 
 use Koha::Biblioitems;
@@ -276,9 +274,6 @@ sub AddItemBatchFromMarc {
         $record->delete_field($item_field);
     }
 
-    # update the MARC biblio
- #   $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode );
-
     return (\@itemnumbers, \@errors);
 }
 
@@ -308,6 +303,9 @@ sub ModItemFromMarc {
     my $item_object = Koha::Items->find($itemnumber);
     my $item = TransformMarcToKoha( $localitemmarc, $frameworkcode, 'items' );
 
+    my ( $perm_loc_tag, $perm_loc_subfield ) = C4::Biblio::GetMarcFromKohaField( "items.permanent_location" );
+    my $has_permanent_location = defined $perm_loc_tag && defined $item_marc->subfield( $perm_loc_tag, $perm_loc_subfield );
+
     # Retrieving the values for the fields that are not linked
     my @mapped_fields = Koha::MarcSubfieldStructures->search(
         {
@@ -321,10 +319,17 @@ sub ModItemFromMarc {
     }
 
     $item->{cn_source} = delete $item->{'items.cn_source'}; # Because of C4::Biblio::_disambiguate
-    $item->{cn_sort}   = delete $item->{'items.cn_sort'};   # Because of C4::Biblio::_disambiguate
+    delete $item->{'items.cn_sort'};   # Because of C4::Biblio::_disambiguate
     $item->{itemnumber} = $itemnumber;
     $item->{biblionumber} = $biblionumber;
+
+    my $existing_cn_sort = $item_object->cn_sort; # set_or_blank will reset cn_sort to undef as we are not passing it
+                                                  # We rely on Koha::Item->store to modify it if itemcallnumber or cn_source is modified
     $item_object = $item_object->set_or_blank($item);
+    $item_object->cn_sort($existing_cn_sort); # Resetting to the existing value
+
+    $item_object->make_column_dirty('permanent_location') if $has_permanent_location;
+
     my $unlinked_item_subfields = _get_unlinked_item_subfields( $localitemmarc, $frameworkcode );
     $item_object->more_subfields_xml(_get_unlinked_subfields_xml($unlinked_item_subfields));
     $item_object->store({ skip_record_index => $params->{skip_record_index} });
@@ -348,20 +353,30 @@ sub ModItemTransfer {
     my $dbh = C4::Context->dbh;
     my $item = Koha::Items->find( $itemnumber );
 
-    # Remove the 'shelving cart' location status if it is being used.
-    CartToShelf( $itemnumber ) if $item->location && $item->location eq 'CART' && ( !$item->permanent_location || $item->permanent_location ne 'CART' );
-
-    $dbh->do("UPDATE branchtransfers SET datearrived = NOW(), comments = ? WHERE itemnumber = ? AND datearrived IS NULL", undef, "Canceled, new transfer from $frombranch to $tobranch created", $itemnumber);
+    # NOTE: This retains the existing hard coded behaviour by ignoring transfer limits
+    # and always replacing any existing transfers. (In theory, calls to ModItemTransfer
+    # will have been preceded by a check of branch transfer limits)
+    my $to_library = Koha::Libraries->find($tobranch);
+    my $transfer = $item->request_transfer(
+        {
+            to            => $to_library,
+            reason        => $trigger,
+            ignore_limits => 1,
+            replace       => 1
+        }
+    );
 
-    #new entry in branchtransfers....
-    my $sth = $dbh->prepare(
-        "INSERT INTO branchtransfers (itemnumber, frombranch, datesent, tobranch, reason)
-        VALUES (?, ?, NOW(), ?, ?)");
-    $sth->execute($itemnumber, $frombranch, $tobranch, $trigger);
+    # Immediately set the item to in transit if it is checked in
+    if ( !$item->checkout ) {
+        $item->holdingbranch($frombranch)->store(
+            {
+                log_action        => 0,
+                skip_record_index => $params->{skip_record_index}
+            }
+        );
+        $transfer->transit;
+    }
 
-    # FIXME we are fetching the item twice in the 2 next statements!
-    Koha::Items->find($itemnumber)->holdingbranch($frombranch)->store({ log_action => 0, skip_record_index => $params->{skip_record_index} });
-    ModDateLastSeen($itemnumber, undef, { skip_record_index => $params->{skip_record_index} });
     return;
 }
 
@@ -480,7 +495,6 @@ lists of authorized values for certain item fields.
   minlocation  => $minlocation,
   maxlocation  => $maxlocation,
   location     => $location,
-  itemtype     => $itemtype,
   ignoreissued => $ignoreissued,
   datelastseen => $datelastseen,
   branchcode   => $branchcode,
@@ -488,6 +502,7 @@ lists of authorized values for certain item fields.
   offset       => $offset,
   size         => $size,
   statushash   => $statushash,
+  itemtypes    => \@itemsarray,
 } );
 
 Retrieve a list of title/authors/barcode/callnumber, for biblio inventory.
@@ -520,6 +535,7 @@ sub GetItemsForInventory {
     my $size         = $parameters->{'size'}         // '';
     my $statushash   = $parameters->{'statushash'}   // '';
     my $ignore_waiting_holds = $parameters->{'ignore_waiting_holds'} // '';
+    my $itemtypes    = $parameters->{'itemtypes'}    || [];
 
     my $dbh = C4::Context->dbh;
     my ( @bind_params, @where_strings );
@@ -579,7 +595,6 @@ sub GetItemsForInventory {
         push @where_strings, 'biblioitems.itemtype = ?';
         push @bind_params, $itemtype;
     }
-
     if ( $ignoreissued) {
         $query .= "LEFT JOIN issues ON items.itemnumber = issues.itemnumber ";
         push @where_strings, 'issues.date_due IS NULL';
@@ -590,6 +605,11 @@ sub GetItemsForInventory {
         push( @where_strings, q{(reserves.found != 'W' OR reserves.found IS NULL)} );
     }
 
+    if ( @$itemtypes ) {
+        my $itemtypes_str = join ', ', @$itemtypes;
+        push @where_strings, "( biblioitems.itemtype IN (" . $itemtypes_str . ") OR items.itype IN (" . $itemtypes_str . ") )";
+    }
+
     if ( @where_strings ) {
         $query .= 'WHERE ';
         $query .= join ' AND ', @where_strings;
@@ -616,7 +636,7 @@ sub GetItemsForInventory {
             '+select' => [ 'marc_subfield_structures.kohafield', 'marc_subfield_structures.frameworkcode', 'me.authorised_value', 'me.lib' ],
             '+as'     => [ 'kohafield',                          'frameworkcode',                          'authorised_value',    'lib' ],
         }
-    );
+    )->as_list;
 
     my $avmapping = { map { $_->get_column('kohafield') . ',' . $_->get_column('frameworkcode') . ',' . $_->get_column('authorised_value') => $_->get_column('lib') } @avs };
 
@@ -787,7 +807,7 @@ sub GetItemsInfo {
     }
 
     return $serial
-        ? sort { ($b->{'publisheddate'} || $b->{'enumchron'}) cmp ($a->{'publisheddate'} || $a->{'enumchron'}) } @results
+        ? sort { ($b->{'publisheddate'} || $b->{'enumchron'} || "") cmp ($a->{'publisheddate'} || $a->{'enumchron'} || "") } @results
         : @results;
 }
 
@@ -831,7 +851,7 @@ Item's itemcallnumber
 Item's call number normalized for sorting
 
 =back
-  
+
 =cut
 
 sub GetItemsLocationInfo {
@@ -874,8 +894,7 @@ sub GetHostItemsInfo {
     }
 
     my @fields;
-    if( C4::Context->preference('marcflavour') eq 'MARC21' ||
-      C4::Context->preference('marcflavour') eq 'NORMARC') {
+    if( C4::Context->preference('marcflavour') eq 'MARC21' ) {
         @fields = $record->field('773');
     } elsif( C4::Context->preference('marcflavour') eq 'UNIMARC') {
         @fields = $record->field('461');
@@ -920,7 +939,7 @@ sub get_hostitemnumbers_of {
     my ( @returnhostitemnumbers, $tag, $biblio_s, $item_s );
 
     my $marcflavor = C4::Context->preference('marcflavour');
-    if ( $marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC' ) {
+    if ( $marcflavor eq 'MARC21' ) {
         $tag      = '773';
         $biblio_s = '0';
         $item_s   = '9';
@@ -970,17 +989,11 @@ sub GetHiddenItemnumbers {
     }
     my @resultitems;
 
-    my $yaml = C4::Context->preference('OpacHiddenItems');
-    return () if (! $yaml =~ /\S/ );
-    $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt
-    my $hidingrules;
-    eval {
-        $hidingrules = YAML::Load($yaml);
-    };
-    if ($@) {
-        warn "Unable to parse OpacHiddenItems syspref : $@";
-        return ();
-    }
+    my $hidingrules = C4::Context->yaml_preference('OpacHiddenItems');
+
+    return
+        unless $hidingrules;
+
     my $dbh = C4::Context->dbh;
 
     # For each item
@@ -1086,57 +1099,6 @@ the inner workings of C<C4::Items>.
 
 =cut
 
-=head2 MoveItemFromBiblio
-
-  MoveItemFromBiblio($itenumber, $frombiblio, $tobiblio);
-
-Moves an item from a biblio to another
-
-Returns undef if the move failed or the biblionumber of the destination record otherwise
-
-=cut
-
-sub MoveItemFromBiblio {
-    my ($itemnumber, $frombiblio, $tobiblio) = @_;
-    my $dbh = C4::Context->dbh;
-    my ( $tobiblioitem ) = $dbh->selectrow_array(q|
-        SELECT biblioitemnumber
-        FROM biblioitems
-        WHERE biblionumber = ?
-    |, undef, $tobiblio );
-    my $return = $dbh->do(q|
-        UPDATE items
-        SET biblioitemnumber = ?,
-            biblionumber = ?
-        WHERE itemnumber = ?
-            AND biblionumber = ?
-    |, undef, $tobiblioitem, $tobiblio, $itemnumber, $frombiblio );
-    if ($return == 1) {
-        my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
-        $indexer->index_records( $tobiblio, "specialUpdate", "biblioserver" );
-        $indexer->index_records( $frombiblio, "specialUpdate", "biblioserver" );
-           # Checking if the item we want to move is in an order 
-        require C4::Acquisition;
-        my $order = C4::Acquisition::GetOrderFromItemnumber($itemnumber);
-           if ($order) {
-                   # Replacing the biblionumber within the order if necessary
-                   $order->{'biblionumber'} = $tobiblio;
-               C4::Acquisition::ModOrder($order);
-           }
-
-        # Update reserves, hold_fill_targets, tmp_holdsqueue and linktracker tables
-        for my $table_name ( qw( reserves hold_fill_targets tmp_holdsqueue linktracker ) ) {
-            $dbh->do( qq|
-                UPDATE $table_name
-                SET biblionumber = ?
-                WHERE itemnumber = ?
-            |, undef, $tobiblio, $itemnumber );
-        }
-        return $tobiblio;
-       }
-    return;
-}
-
 =head2 _marc_from_item_hash
 
   my $item_marc = _marc_from_item_hash($item, $frameworkcode[, $unlinked_item_subfields]);
@@ -1333,6 +1295,7 @@ sub _SearchItems_build_where_fragment {
         push @columns, Koha::Database->new()->schema()->resultset('Biblio')->result_source->columns;
         push @columns, Koha::Database->new()->schema()->resultset('Biblioitem')->result_source->columns;
         my @operators = qw(= != > < >= <= like);
+        push @operators, 'not like';
         my $field = $filter->{field} // q{};
         if ( (0 < grep { $_ eq $field } @columns) or (substr($field, 0, 5) eq 'marc:') ) {
             my $op = $filter->{operator};
@@ -1379,7 +1342,7 @@ sub _SearchItems_build_where_fragment {
             }
 
             if ( defined $ifnull ) {
-                $column = "IFNULL($column, ?)";
+                $column = "COALESCE($column, ?)";
             }
 
             if (ref $query eq 'ARRAY') {
@@ -1424,7 +1387,7 @@ A filter has the following keys:
 
 =item * query: the value to search in this column
 
-=item * operator: comparison operator. Can be one of = != > < >= <= like
+=item * operator: comparison operator. Can be one of = != > < >= <= like 'not like'
 
 =back
 
@@ -1562,10 +1525,12 @@ sub _find_value {
 
 =head2 PrepareItemrecordDisplay
 
-  PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber,$frameworkcode);
+  PrepareItemrecordDisplay($bibnum,$itemumber,$defaultvalues,$frameworkcode);
 
 Returns a hash with all the fields for Display a given item data in a template
 
+$defaultvalues should either contain a hashref of values for the new item, or be undefined.
+
 The $frameworkcode returns the item for the given frameworkcode, ONLY if bibnum is not provided
 
 =cut
@@ -1583,6 +1548,12 @@ sub PrepareItemrecordDisplay {
     # its contents. See also GetMarcStructure.
     my $tagslib = GetMarcStructure( 1, $frameworkcode, { unsafe => 1 } );
 
+    # Pick the default location from NewItemsDefaultLocation
+    if ( C4::Context->preference('NewItemsDefaultLocation') ) {
+        $defaultvalues //= {};
+        $defaultvalues->{location} //= C4::Context->preference('NewItemsDefaultLocation');
+    }
+
     # return nothing if we don't have found an existing framework.
     return q{} unless $tagslib;
     my $itemrecord;
@@ -1609,29 +1580,32 @@ sub PrepareItemrecordDisplay {
 
             # loop through each subfield
             my $cntsubf;
-            foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
-                next if IsMarcStructureInternal($tagslib->{$tag}{$subfield});
-                next unless ( $tagslib->{$tag}->{$subfield}->{'tab'} );
-                next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
+            foreach my $subfield (
+                sort { $a->{display_order} <=> $b->{display_order} || $a->{subfield} cmp $b->{subfield} }
+                grep { ref($_) && %$_ } # Not a subfield (values for "important", "lib", "mandatory", etc.) or empty
+                values %{ $tagslib->{$tag} } )
+            {
+                next unless ( $subfield->{'tab'} );
+                next if ( $subfield->{'tab'} ne "10" );
                 my %subfield_data;
                 $subfield_data{tag}           = $tag;
-                $subfield_data{subfield}      = $subfield;
+                $subfield_data{subfield}      = $subfield->{subfield};
                 $subfield_data{countsubfield} = $cntsubf++;
-                $subfield_data{kohafield}     = $tagslib->{$tag}->{$subfield}->{'kohafield'};
-                $subfield_data{id}            = "tag_".$tag."_subfield_".$subfield."_".int(rand(1000000));
+                $subfield_data{kohafield}     = $subfield->{kohafield};
+                $subfield_data{id}            = "tag_".$tag."_subfield_".$subfield->{subfield}."_".int(rand(1000000));
 
                 #        $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
-                $subfield_data{marc_lib}   = $tagslib->{$tag}->{$subfield}->{lib};
-                $subfield_data{mandatory}  = $tagslib->{$tag}->{$subfield}->{mandatory};
-                $subfield_data{repeatable} = $tagslib->{$tag}->{$subfield}->{repeatable};
+                $subfield_data{marc_lib}   = $subfield->{lib};
+                $subfield_data{mandatory}  = $subfield->{mandatory};
+                $subfield_data{repeatable} = $subfield->{repeatable};
                 $subfield_data{hidden}     = "display:none"
-                  if ( ( $tagslib->{$tag}->{$subfield}->{hidden} > 4 )
-                    || ( $tagslib->{$tag}->{$subfield}->{hidden} < -4 ) );
+                  if ( ( $subfield->{hidden} > 4 )
+                    || ( $subfield->{hidden} < -4 ) );
                 my ( $x, $defaultvalue );
                 if ($itemrecord) {
-                    ( $x, $defaultvalue ) = _find_value( $tag, $subfield, $itemrecord );
+                    ( $x, $defaultvalue ) = _find_value( $tag, $subfield->{subfield}, $itemrecord );
                 }
-                $defaultvalue = $tagslib->{$tag}->{$subfield}->{defaultvalue} unless $defaultvalue;
+                $defaultvalue = $subfield->{defaultvalue} unless $defaultvalue;
                 if ( !defined $defaultvalue ) {
                     $defaultvalue = q||;
                 } else {
@@ -1655,23 +1629,24 @@ sub PrepareItemrecordDisplay {
                     $defaultvalue =~ s/<<USER>>/$username/g;
                 }
 
-                my $maxlength = $tagslib->{$tag}->{$subfield}->{maxlength};
+                my $maxlength = $subfield->{maxlength};
 
                 # search for itemcallnumber if applicable
-                if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.itemcallnumber'
+                if ( $subfield->{kohafield} eq 'items.itemcallnumber'
                     && C4::Context->preference('itemcallnumber') && $itemrecord) {
                     foreach my $itemcn_pref (split(/,/,C4::Context->preference('itemcallnumber'))){
                         my $CNtag      = substr( $itemcn_pref, 0, 3 );
                         next unless my $field = $itemrecord->field($CNtag);
                         my $CNsubfields = substr( $itemcn_pref, 3 );
+                        $CNsubfields = undef if $CNsubfields eq '';
                         $defaultvalue = $field->as_string( $CNsubfields, ' ');
                         last if $defaultvalue;
                     }
                 }
-                if (   $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.itemcallnumber'
+                if (   $subfield->{kohafield} eq 'items.itemcallnumber'
                     && $defaultvalues
                     && $defaultvalues->{'callnumber'} ) {
-                    if( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield) ){
+                    if( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield->{subfield}) ){
                         # if the item record exists, only use default value if the item has no callnumber
                         $defaultvalue = $defaultvalues->{callnumber};
                     } elsif ( !$itemrecord and $defaultvalues ) {
@@ -1679,18 +1654,18 @@ sub PrepareItemrecordDisplay {
                         $defaultvalue = $defaultvalues->{callnumber};
                     }
                 }
-                if (   ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.holdingbranch' || $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.homebranch' )
+                if (   ( $subfield->{kohafield} eq 'items.holdingbranch' || $subfield->{kohafield} eq 'items.homebranch' )
                     && $defaultvalues
                     && $defaultvalues->{'branchcode'} ) {
                     if ( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield) ) {
                         $defaultvalue = $defaultvalues->{branchcode};
                     }
                 }
-                if (   ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.location' )
+                if (   ( $subfield->{kohafield} eq 'items.location' )
                     && $defaultvalues
                     && $defaultvalues->{'location'} ) {
 
-                    if ( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield) ) {
+                    if ( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield->{subfield}) ) {
                         # if the item record exists, only use default value if the item has no locationr
                         $defaultvalue = $defaultvalues->{location};
                     } elsif ( !$itemrecord and $defaultvalues ) {
@@ -1698,19 +1673,19 @@ sub PrepareItemrecordDisplay {
                         $defaultvalue = $defaultvalues->{location};
                     }
                 }
-                if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
+                if ( $subfield->{authorised_value} ) {
                     my @authorised_values;
                     my %authorised_lib;
 
                     # builds list, depending on authorised value...
                     #---- branch
-                    if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
+                    if ( $subfield->{'authorised_value'} eq "branches" ) {
                         if (   ( C4::Context->preference("IndependentBranches") )
                             && !C4::Context->IsSuperLibrarian() ) {
                             my $sth = $dbh->prepare( "SELECT branchcode,branchname FROM branches WHERE branchcode = ? ORDER BY branchname" );
                             $sth->execute( C4::Context->userenv->{branch} );
                             push @authorised_values, ""
-                              unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
+                              unless ( $subfield->{mandatory} );
                             while ( my ( $branchcode, $branchname ) = $sth->fetchrow_array ) {
                                 push @authorised_values, $branchcode;
                                 $authorised_lib{$branchcode} = $branchname;
@@ -1719,7 +1694,7 @@ sub PrepareItemrecordDisplay {
                             my $sth = $dbh->prepare( "SELECT branchcode,branchname FROM branches ORDER BY branchname" );
                             $sth->execute;
                             push @authorised_values, ""
-                              unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
+                              unless ( $subfield->{mandatory} );
                             while ( my ( $branchcode, $branchname ) = $sth->fetchrow_array ) {
                                 push @authorised_values, $branchcode;
                                 $authorised_lib{$branchcode} = $branchname;
@@ -1732,7 +1707,7 @@ sub PrepareItemrecordDisplay {
                         }
 
                         #----- itemtypes
-                    } elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
+                    } elsif ( $subfield->{authorised_value} eq "itemtypes" ) {
                         my $itemtypes = Koha::ItemTypes->search_with_localization;
                         push @authorised_values, "";
                         while ( my $itemtype = $itemtypes->next ) {
@@ -1744,7 +1719,7 @@ sub PrepareItemrecordDisplay {
                         }
 
                         #---- class_sources
-                    } elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "cn_source" ) {
+                    } elsif ( $subfield->{authorised_value} eq "cn_source" ) {
                         push @authorised_values, "";
 
                         my $class_sources = GetClassSources();
@@ -1762,7 +1737,7 @@ sub PrepareItemrecordDisplay {
                         #---- "true" authorised value
                     } else {
                         $authorised_values_sth->execute(
-                            $tagslib->{$tag}->{$subfield}->{authorised_value},
+                            $subfield->{authorised_value},
                             $branch_limit ? $branch_limit : ()
                         );
                         push @authorised_values, "";
@@ -1777,17 +1752,17 @@ sub PrepareItemrecordDisplay {
                         default => $defaultvalue // q{},
                         labels  => \%authorised_lib,
                     };
-                } elsif ( $tagslib->{$tag}->{$subfield}->{value_builder} ) {
+                } elsif ( $subfield->{value_builder} ) {
                 # it is a plugin
                     require Koha::FrameworkPlugin;
                     my $plugin = Koha::FrameworkPlugin->new({
-                        name => $tagslib->{$tag}->{$subfield}->{value_builder},
+                        name => $subfield->{value_builder},
                         item_style => 1,
                     });
-                    my $pars = { dbh => $dbh, record => undef, tagslib =>$tagslib, id => $subfield_data{id}, tabloop => undef };
+                    my $pars = { dbh => $dbh, record => undef, tagslib =>$tagslib, id => $subfield_data{id} };
                     $plugin->build( $pars );
                     if ( $itemrecord and my $field = $itemrecord->field($tag) ) {
-                        $defaultvalue = $field->subfield($subfield) || q{};
+                        $defaultvalue = $field->subfield($subfield->{subfield}) || q{};
                     }
                     if( !$plugin->errstr ) {
                         #TODO Move html to template; see report 12176/13397
@@ -1803,12 +1778,12 @@ sub PrepareItemrecordDisplay {
                 elsif ( $tag eq '' ) {       # it's an hidden field
                     $subfield_data{marc_value} = qq(<input type="hidden" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="50" maxlength="$maxlength" value="$defaultvalue" />);
                 }
-                elsif ( $tagslib->{$tag}->{$subfield}->{'hidden'} ) {   # FIXME: shouldn't input type be "hidden" ?
+                elsif ( $subfield->{'hidden'} ) {   # FIXME: shouldn't input type be "hidden" ?
                     $subfield_data{marc_value} = qq(<input type="text" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="50" maxlength="$maxlength" value="$defaultvalue" />);
                 }
                 elsif ( length($defaultvalue) > 100
                             or (C4::Context->preference("marcflavour") eq "UNIMARC" and
-                                  300 <= $tag && $tag < 400 && $subfield eq 'a' )
+                                  300 <= $tag && $tag < 400 && $subfield->{subfield} eq 'a' )
                             or (C4::Context->preference("marcflavour") eq "MARC21"  and
                                   500 <= $tag && $tag < 600                     )
                           ) {