Bug 29662: (bug 27526 follow-up) Prefill all subfields if SubfieldsToUseWhenPrefill...
[srvgit] / cataloguing / additem.pl
index 14e88d1..4617cb5 100755 (executable)
@@ -25,26 +25,20 @@ use CGI qw ( -utf8 );
 use C4::Auth qw( get_template_and_user haspermission );
 use C4::Output qw( output_and_exit_if_error output_and_exit output_html_with_http_headers );
 use C4::Biblio qw(
-    GetAuthorisedValueDesc
     GetFrameworkCode
-    GetMarcBiblio
     GetMarcFromKohaField
     GetMarcStructure
     IsMarcStructureInternal
     ModBiblio
-    TransformHtmlToXml
-    TransformMarcToKoha
 );
-use C4::Items qw( AddItemFromMarc ModItemFromMarc );
 use C4::Context;
-use C4::Circulation qw( LostItem );
-use C4::Koha qw( GetAuthorisedValues );
-use C4::ClassSource qw( GetClassSources GetClassSource );
+use C4::Circulation qw( barcodedecode LostItem );
 use C4::Barcodes;
 use C4::Barcodes::ValueBuilder;
-use Koha::DateUtils qw( dt_from_string );
+use Koha::Biblios;
 use Koha::Items;
 use Koha::ItemTypes;
+use Koha::Items;
 use Koha::Libraries;
 use Koha::Patrons;
 use Koha::SearchEngine::Indexer;
@@ -52,283 +46,43 @@ use C4::Search qw( enabled_staff_search_views );
 use Storable qw( freeze thaw );
 use URI::Escape qw( uri_escape_utf8 );
 use C4::Members;
+use Koha::UI::Form::Builder::Item;
 
 use MARC::File::XML;
 use URI::Escape qw( uri_escape_utf8 );
+use Encode qw( encode_utf8 );
 use MIME::Base64 qw( decode_base64url encode_base64url );
 use List::Util qw( first );
 use List::MoreUtils qw( any uniq );
 
 our $dbh = C4::Context->dbh;
 
-sub generate_subfield_form {
-        my ($tag, $subfieldtag, $value, $tagslib,$subfieldlib, $branches, $biblionumber, $temp, $subfields, $i, $restrictededition, $item) = @_;
-  
-        my $frameworkcode = &GetFrameworkCode($biblionumber);
-
-        $item //= {};
-
-        my %subfield_data;
-        my $dbh = C4::Context->dbh;
-        
-        my $index_subfield = int(rand(1000000)); 
-        if ($subfieldtag eq '@'){
-            $subfield_data{id} = "tag_".$tag."_subfield_00_".$index_subfield;
-        } else {
-            $subfield_data{id} = "tag_".$tag."_subfield_".$subfieldtag."_".$index_subfield;
-        }
-        
-        $subfield_data{tag}        = $tag;
-        $subfield_data{subfield}   = $subfieldtag;
-        $subfield_data{marc_lib}   ="<span id=\"error$i\" title=\"".$subfieldlib->{lib}."\">".$subfieldlib->{lib}."</span>";
-        $subfield_data{mandatory}  = $subfieldlib->{mandatory};
-        $subfield_data{important}  = $subfieldlib->{important};
-        $subfield_data{repeatable} = $subfieldlib->{repeatable};
-        $subfield_data{maxlength}  = $subfieldlib->{maxlength};
-        $subfield_data{display_order} = $subfieldlib->{display_order};
-        $subfield_data{kohafield}  = $subfieldlib->{kohafield} || 'items.more_subfields_xml';
-        
-        if ( ! defined( $value ) || $value eq '')  {
-            $value = $subfieldlib->{defaultvalue};
-            if ( $value ) {
-                # get today date & replace <<YYYY>>, <<YY>>, <<MM>>, <<DD>> if provided in the default value
-                my $today_dt = dt_from_string;
-                my $year = $today_dt->strftime('%Y');
-                my $shortyear = $today_dt->strftime('%y');
-                my $month = $today_dt->strftime('%m');
-                my $day = $today_dt->strftime('%d');
-                $value =~ s/<<YYYY>>/$year/g;
-                $value =~ s/<<YY>>/$shortyear/g;
-                $value =~ s/<<MM>>/$month/g;
-                $value =~ s/<<DD>>/$day/g;
-                # And <<USER>> with surname (?)
-                my $username=(C4::Context->userenv?C4::Context->userenv->{'surname'}:"superlibrarian");
-                $value=~s/<<USER>>/$username/g;
-            }
-        }
-
-        $subfield_data{visibility} = "display:none;" if (($subfieldlib->{hidden} > 4) || ($subfieldlib->{hidden} <= -4));
+sub add_item_to_item_group {
+    my ( $biblionumber, $itemnumber, $item_group, $item_group_description ) = @_;
 
-        my $pref_itemcallnumber = C4::Context->preference('itemcallnumber');
-        if (!$value && $subfieldlib->{kohafield} eq 'items.itemcallnumber' && $pref_itemcallnumber) {
-            foreach my $pref_itemcallnumber_part (split(/,/, $pref_itemcallnumber)){
-                my $CNtag       = substr( $pref_itemcallnumber_part, 0, 3 ); # 3-digit tag number
-                my $CNsubfields = substr( $pref_itemcallnumber_part, 3 ); # Any and all subfields
-                $CNsubfields = undef if $CNsubfields eq '';
-                my $temp2 = $temp->field($CNtag);
+    return unless $item_group;
 
-                next unless $temp2;
-                $value = $temp2->as_string( $CNsubfields, ' ' );
-                last if $value;
+    my $item_group_id;
+    if ( $item_group eq 'create' ) {
+        my $item_group = Koha::Biblio::ItemGroup->new(
+            {
+                biblionumber => $biblionumber,
+                description  => $item_group_description,
             }
-        }
+        )->store();
 
-        my $default_location = C4::Context->preference('NewItemsDefaultLocation');
-        if ( !$value && $subfieldlib->{kohafield} eq 'items.location' && $default_location ) {
-            $value = $default_location;
-        }
-
-        if ($frameworkcode eq 'FA' && $subfieldlib->{kohafield} eq 'items.barcode' && !$value){
-           my $input = CGI->new;
-           $value = $input->param('barcode');
-       }
-
-        if ( $subfieldlib->{authorised_value} ) {
-            my @authorised_values;
-            my %authorised_lib;
-            # builds list, depending on authorised value...
-            if ( $subfieldlib->{authorised_value} eq "LOST" ) {
-                my $ClaimReturnedLostValue = C4::Context->preference('ClaimReturnedLostValue');
-                my $item_is_return_claim = $ClaimReturnedLostValue && exists $item->{itemlost} && $ClaimReturnedLostValue eq $item->{itemlost};
-                $subfield_data{IS_RETURN_CLAIM} = $item_is_return_claim;
-
-                $subfield_data{IS_LOST_AV} = 1;
-
-                push @authorised_values, qq{};
-                my $av = GetAuthorisedValues( $subfieldlib->{authorised_value} );
-                for my $r ( @$av ) {
-                    push @authorised_values, $r->{authorised_value};
-                    $authorised_lib{$r->{authorised_value}} = $r->{lib};
-                }
-            }
-            elsif ( $subfieldlib->{authorised_value} eq "branches" ) {
-                foreach my $thisbranch (@$branches) {
-                    push @authorised_values, $thisbranch->{branchcode};
-                    $authorised_lib{$thisbranch->{branchcode}} = $thisbranch->{branchname};
-                    $value = $thisbranch->{branchcode} if $thisbranch->{selected} && !$value;
-                }
-            }
-            elsif ( $subfieldlib->{authorised_value} eq "itemtypes" ) {
-                  push @authorised_values, "";
-                  my $branch_limit = C4::Context->userenv && C4::Context->userenv->{"branch"};
-                  my $itemtypes;
-                  if($branch_limit) {
-                      $itemtypes = Koha::ItemTypes->search_with_localization({branchcode => $branch_limit});
-                  } else {
-                      $itemtypes = Koha::ItemTypes->search_with_localization;
-                  }
-                  while ( my $itemtype = $itemtypes->next ) {
-                      push @authorised_values, $itemtype->itemtype;
-                      $authorised_lib{$itemtype->itemtype} = $itemtype->translated_description;
-                  }
-
-                  unless ( $value ) {
-                      my $itype_sth = $dbh->prepare("SELECT itemtype FROM biblioitems WHERE biblionumber = ?");
-                      $itype_sth->execute( $biblionumber );
-                      ( $value ) = $itype_sth->fetchrow_array;
-                  }
-          
-                  #---- class_sources
-            }
-            elsif ( $subfieldlib->{authorised_value} eq "cn_source" ) {
-                  push @authorised_values, "";
-                    
-                  my $class_sources = GetClassSources();
-                  my $default_source = C4::Context->preference("DefaultClassificationSource");
-                  
-                  foreach my $class_source (sort keys %$class_sources) {
-                      next unless $class_sources->{$class_source}->{'used'} or
-                                  ($value and $class_source eq $value)      or
-                                  ($class_source eq $default_source);
-                      push @authorised_values, $class_source;
-                      $authorised_lib{$class_source} = $class_sources->{$class_source}->{'description'};
-                  }
-                         $value = $default_source unless ($value);
-        
-                  #---- "true" authorised value
-            }
-            else {
-                  push @authorised_values, qq{};
-                  my $av = GetAuthorisedValues( $subfieldlib->{authorised_value} );
-                  for my $r ( @$av ) {
-                      push @authorised_values, $r->{authorised_value};
-                      $authorised_lib{$r->{authorised_value}} = $r->{lib};
-                  }
-            }
+        $item_group_id = $item_group->id;
+    }
+    else {
+        $item_group_id = $item_group;
+    }
 
-            if ( $subfieldlib->{hidden} > 4 or $subfieldlib->{hidden} <= -4 ) {
-                $subfield_data{marc_value} = {
-                    type        => 'hidden',
-                    id          => $subfield_data{id},
-                    maxlength   => $subfield_data{maxlength},
-                    value       => $value,
-                    ( ( grep { $_ eq $subfieldlib->{authorised_value}} ( qw(branches itemtypes cn_source) ) ) ? () : ( category => $subfieldlib->{authorised_value}) ),
-                };
-            }
-            else {
-                $subfield_data{marc_value} = {
-                    type     => 'select',
-                    id       => "tag_".$tag."_subfield_".$subfieldtag."_".$index_subfield,
-                    values   => \@authorised_values,
-                    labels   => \%authorised_lib,
-                    default  => $value,
-                    ( ( grep { $_ eq $subfieldlib->{authorised_value}} ( qw(branches itemtypes cn_source) ) ) ? () : ( category => $subfieldlib->{authorised_value}) ),
-                };
-            }
-        }
-            # it's a thesaurus / authority field
-        elsif ( $subfieldlib->{authtypecode} ) {
-                $subfield_data{marc_value} = {
-                    type         => 'text_auth',
-                    id           => $subfield_data{id},
-                    maxlength    => $subfield_data{maxlength},
-                    value        => $value,
-                    authtypecode => $subfieldlib->{authtypecode},
-                };
-        }
-            # it's a plugin field
-        elsif ( $subfieldlib->{value_builder} ) { # plugin
-            require Koha::FrameworkPlugin;
-            my $plugin = Koha::FrameworkPlugin->new({
-                name => $subfieldlib->{'value_builder'},
-                item_style => 1,
-            });
-            my $pars=  { dbh => $dbh, record => $temp, tagslib =>$tagslib,
-                id => $subfield_data{id}, tabloop => $subfields };
-            $plugin->build( $pars );
-            if( !$plugin->errstr ) {
-                my $class= 'buttonDot'. ( $plugin->noclick? ' disabled': '' );
-                $subfield_data{marc_value} = {
-                    type        => 'text_plugin',
-                    id          => $subfield_data{id},
-                    maxlength   => $subfield_data{maxlength},
-                    value       => $value,
-                    class       => $class,
-                    nopopup     => $plugin->noclick,
-                    javascript  => $plugin->javascript,
-                };
-            } else {
-                warn $plugin->errstr;
-                $subfield_data{marc_value} = {
-                    type        => 'text',
-                    id          => $subfield_data{id},
-                    maxlength   => $subfield_data{maxlength},
-                    value       => $value,
-                }; # supply default input form
-            }
-        }
-        elsif ( $tag eq '' ) {       # it's an hidden field
-            $subfield_data{marc_value} = {
-                type        => 'hidden',
-                id          => $subfield_data{id},
-                maxlength   => $subfield_data{maxlength},
-                value       => $value,
-            };
-        }
-        elsif ( $subfieldlib->{'hidden'} ) {   # FIXME: shouldn't input type be "hidden" ?
-            $subfield_data{marc_value} = {
-                type        => 'text',
-                id          => $subfield_data{id},
-                maxlength   => $subfield_data{maxlength},
-                value       => $value,
-            };
-        }
-        elsif (
-                (
-                    $value and length($value) > 100
-                )
-                or (
-                    C4::Context->preference("marcflavour") eq "UNIMARC"
-                    and 300 <= $tag && $tag < 400 && $subfieldtag eq 'a'
-                )
-                or (
-                    C4::Context->preference("marcflavour") eq "MARC21"
-                    and 500 <= $tag && $tag < 600
-                )
-              ) {
-            # oversize field (textarea)
-            $subfield_data{marc_value} = {
-                type        => 'textarea',
-                id          => $subfield_data{id},
-                value       => $value,
-            };
-        } else {
-            # it's a standard field
-            $subfield_data{marc_value} = {
-                type        => 'text',
-                id          => $subfield_data{id},
-                maxlength   => $subfield_data{maxlength},
-                value       => $value,
-            };
+    my $item_group_item = Koha::Biblio::ItemGroup::Item->new(
+        {
+            itemnumber => $itemnumber,
+            item_group_id  => $item_group_id,
         }
-
-        # Getting list of subfields to keep when restricted editing is enabled
-        my $subfieldsToAllowForRestrictedEditing = C4::Context->preference('SubfieldsToAllowForRestrictedEditing');
-        my $allowAllSubfields = (
-            not defined $subfieldsToAllowForRestrictedEditing
-              or $subfieldsToAllowForRestrictedEditing eq q||
-        ) ? 1 : 0;
-        my @subfieldsToAllow = split(/ /, $subfieldsToAllowForRestrictedEditing);
-
-        # If we're on restricted editing, and our field is not in the list of subfields to allow,
-        # then it is read-only
-        $subfield_data{marc_value}->{readonly} = (
-            not $allowAllSubfields
-            and $restrictededition
-            and !grep { $tag . '$' . $subfieldtag  eq $_ } @subfieldsToAllow
-        ) ? 1: 0;
-
-        return \%subfield_data;
+    )->store();
 }
 
 sub get_item_from_cookie {
@@ -352,7 +106,6 @@ sub get_item_from_cookie {
 }
 
 my $input        = CGI->new;
-my $error        = $input->param('error');
 
 my $biblionumber;
 my $itemnumber;
@@ -377,6 +130,8 @@ my $fa_barcode            = $input->param('barcode');
 my $fa_branch             = $input->param('branch');
 my $fa_stickyduedate      = $input->param('stickyduedate');
 my $fa_duedatespec        = $input->param('duedatespec');
+my $volume                = $input->param('volume');
+my $volume_description    = $input->param('volume_description');
 
 our $frameworkcode = &GetFrameworkCode($biblionumber);
 
@@ -407,12 +162,11 @@ $restrictededition = 0 if ($restrictededition != 0 &&  C4::Context->IsSuperLibra
 $restrictededition = 0 if ($restrictededition != 0 && $frameworkcode eq 'FA' && haspermission($uid, {'editcatalogue' => 'fast_cataloging'}));
 
 our $tagslib = &GetMarcStructure(1,$frameworkcode);
-my $record = GetMarcBiblio({ biblionumber => $biblionumber });
+my $record = $biblio->metadata->record;
 
 output_and_exit_if_error( $input, $cookie, $template,
     { module => 'cataloguing', record => $record } );
 
-my $oldrecord = TransformMarcToKoha($record);
 my $current_item;
 my $nextop="additem";
 my @errors; # store errors found while checking data BEFORE saving item.
@@ -450,23 +204,34 @@ if ($op eq "additem") {
             }
             $item->more_subfields_xml(undef);
         } else {
-            my @v = $input->multi_param("items.".$c);
+            my @v = grep { $_ ne "" }
+                uniq $input->multi_param( "items." . $c );
+
             next unless @v;
-            $item->$c(join ' | ', uniq @v);
+
+            if ( $c eq 'permanent_location' ) { # See 27837
+                $item->make_column_dirty('permanent_location');
+            }
+
+            $item->$c(join ' | ', @v);
         }
     }
 
     # if autoBarcode is set to 'incremental', calculate barcode...
-    if ( not $item->barcode && C4::Context->preference('autoBarcode') eq 'incremental' ) {
+    if ( ! defined $item->barcode && C4::Context->preference('autoBarcode') eq 'incremental' ) {
         my ( $barcode ) = C4::Barcodes::ValueBuilder::incremental::get_barcode;
         $item->barcode($barcode);
     }
 
+    $item->barcode(barcodedecode($item->barcode));
+
     # If we have to add or add & duplicate, we add the item
-    if ( $add_submit || $prefillitem) {
+    if ( $add_submit || $add_duplicate_submit || $prefillitem) {
 
         # check for item barcode # being unique
-        if ( Koha::Items->search({ barcode => $item->barcode })->count ) {
+        if ( defined $item->barcode
+            && Koha::Items->search( { barcode => $item->barcode } )->count )
+        {
             # if barcode exists, don't create, but report The problem.
             push @errors, "barcode_not_unique";
 
@@ -474,6 +239,7 @@ if ($op eq "additem") {
         }
         else {
             $item->store->discard_changes;
+            add_item_to_item_group( $item->biblionumber, $item->biblioitemnumber, $volume, $volume_description );
 
             # This is a bit tricky : if there is a cookie for the last created item and
             # we just added an item, the cookie value is not correct yet (it will be updated
@@ -488,7 +254,8 @@ if ($op eq "additem") {
                     # We encode_base64url the whole freezed structure so we're sure we won't have any encoding problems
                     -value   => encode_base64url( freeze( { %{$item->unblessed}, itemnumber => undef } ) ),
                     -HttpOnly => 1,
-                    -expires => ''
+                    -expires => '',
+                    -sameSite => 'Lax'
                 );
 
                 $cookie = [ $cookie, $last_created_item_cookie ];
@@ -583,6 +350,7 @@ if ($op eq "additem") {
                         { skip_record_index => 1 } );
                     $current_item->discard_changes; # Cannot chain discard_changes
                     $current_item = $current_item->unblessed;
+                    add_item_to_item_group( $item->biblionumber, $item->biblioitemnumber, $volume, $volume_description );
 
 # We count the item only if it was really added
 # That way, all items are added, even if there was some already existing barcodes
@@ -628,14 +396,14 @@ if ($op eq "additem") {
 } elsif ($op eq "dupeitem") {
 #-------------------------------------------------------------------------------
 # retrieve item if exist => then, it's a modif
-    my $item = Koha::Items->find($itemnumber);
+    $current_item = Koha::Items->find($itemnumber)->unblessed;
     # FIXME Handle non existent item
     if (C4::Context->preference('autoBarcode') eq 'incremental') {
         my ( $barcode ) = C4::Barcodes::ValueBuilder::incremental::get_barcode;
-        $item->barcode($barcode);
+        $current_item->{barcode} = $barcode;
     }
     else {
-        $item->barcode(undef); # Don't save it!
+        $current_item->{barcode} = undef; # Don't save it!
     }
 
     $nextop = "additem";
@@ -644,21 +412,22 @@ if ($op eq "additem") {
 #-------------------------------------------------------------------------------
     # check that there is no issue on this item before deletion.
     my $item = Koha::Items->find($itemnumber);
-    $error = $item->safe_delete;
-    if(ref($error) eq 'Koha::Item'){
+    my $deleted = $item->safe_delete;
+    if ( $deleted ) {
         print $input->redirect("additem.pl?biblionumber=$biblionumber&frameworkcode=$frameworkcode&searchid=$searchid");
-    }else{
-        push @errors,$error;
-        $nextop="additem";
+        exit;
+    }
+    else {
+        push @errors, @{ $deleted->messages }[0]->message;
+        $nextop = "additem";
     }
 #-------------------------------------------------------------------------------
 } elsif ($op eq "delallitems") {
 #-------------------------------------------------------------------------------
     my $items = Koha::Items->search({ biblionumber => $biblionumber });
     while ( my $item = $items->next ) {
-        $error = $item->safe_delete({ skip_record_index => 1 });
-        next if ref $error eq 'Koha::Item'; # Deleted item is returned if deletion successful
-        push @errors,$error;
+        my $deleted = $item->safe_delete({ skip_record_index => 1 });
+        push @errors, @{$deleted->messages}[0]->message unless $deleted;
     }
     my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
     $indexer->index_records( $biblionumber, "specialUpdate", "biblioserver" );
@@ -687,12 +456,13 @@ if ($op eq "additem") {
     # FIXME Handle non existent item
     my $olditemlost = $item->itemlost;
     my @columns = Koha::Items->columns;
+    my $new_values = $item->unblessed;
     for my $c ( @columns ) {
         if ( $c eq 'more_subfields_xml' ) {
             my @more_subfields_xml = $input->multi_param("items.more_subfields_xml");
             my @unlinked_item_subfields;
             for my $subfield ( uniq @more_subfields_xml ) {
-                my @v = $input->multi_param('items.more_subfields_xml_' . $subfield);
+                my @v = $input->multi_param('items.more_subfields_xml_' . encode_utf8($subfield));
                 push @unlinked_item_subfields, $subfield, $_ for @v;
             }
             if ( @unlinked_item_subfields ) {
@@ -701,19 +471,38 @@ if ($op eq "additem") {
                 # used in the framework
                 $marc->append_fields(MARC::Field->new('999', ' ', ' ', @unlinked_item_subfields));
                 $marc->encoding("UTF-8");
-                $item->more_subfields_xml($marc->as_xml("USMARC"));
+                $new_values->{more_subfields_xml} = $marc->as_xml("USMARC");
                 next;
             }
             $item->more_subfields_xml(undef);
         } else {
-            my @v = $input->multi_param("items.".$c);
+            my @v = map { ( defined $_ && $_ eq '' ) ? undef : $_ } $input->multi_param( "items." . $c );
             next unless @v;
-            $item->$c(join ' | ', uniq @v);
+
+            if ( $c eq 'permanent_location' ) { # See 27837
+                $item->make_column_dirty('permanent_location');
+            }
+
+            if ( scalar(@v) == 1 && not defined $v[0] ) {
+                delete $new_values->{$c};
+            } else {
+                $new_values->{$c} = join ' | ', @v;
+            }
         }
     }
+    $item = $item->set_or_blank($new_values);
 
     # check that the barcode don't exist already
-    if ( Koha::Items->search({ barcode => $item->barcode, itemnumber => { '!=' => $item->itemnumber } })->count ) {
+    if (
+        defined $item->barcode
+        && Koha::Items->search(
+            {
+                barcode    => $item->barcode,
+                itemnumber => { '!=' => $item->itemnumber }
+            }
+        )->count
+      )
+    {
         # FIXME We shouldn't need that, ->store would explode as there is a unique constraint on items.barcode
         push @errors,"barcode_not_unique";
         $current_item = $item->unblessed; # Restore edit form for the same item
@@ -729,7 +518,7 @@ if ($op eq "additem") {
 } elsif ($op eq "delinkitem"){
 
     my $analyticfield = '773';
-       if ($marcflavour  eq 'MARC21' || $marcflavour eq 'NORMARC'){
+    if ($marcflavour  eq 'MARC21'){
         $analyticfield = '773';
     } elsif ($marcflavour eq 'UNIMARC') {
         $analyticfield = '461';
@@ -767,7 +556,7 @@ my @witness_attributes = uniq map {
     map { defined $item->{$_} && $item->{$_} ne "" ? $_ : () } keys %$item
 } @items;
 
-our ( $itemtagfield, $itemtagsubfield ) = &GetMarcFromKohaField("items.itemnumber");
+our ( $itemtagfield, $itemtagsubfield ) = GetMarcFromKohaField("items.itemnumber");
 
 my $subfieldcode_attribute_mappings;
 for my $subfield_code ( keys %{ $tagslib->{$itemtagfield} } ) {
@@ -795,107 +584,80 @@ my @header_value_loop = map {
     }
 } sort keys %$subfieldcode_attribute_mappings;
 
-# now, build the item form for entering a new item
-my $branch = $input->param('branch') || C4::Context->userenv->{branch};
-my $libraries = Koha::Libraries->search({}, { order_by => ['branchname'] })->unblessed;# build once ahead of time, instead of multiple times later.
-for my $library ( @$libraries ) {
-    $library->{selected} = 1 if $library->{branchcode} eq $branch
-}
-
-
 # Using last created item if it exists
 if (   $prefillitem
     && $op ne "additem"
-    && $op ne "edititem" )
+    && $op ne "edititem"
+    && $op ne "dupeitem" )
 {
     my $item_from_cookie = get_item_from_cookie($input);
     $current_item = $item_from_cookie if $item_from_cookie;
 }
 
-my @subfields_to_prefill = split ' ', C4::Context->preference('SubfieldsToUseWhenPrefill');
-
 if ( $current_item->{more_subfields_xml} ) {
+    # FIXME Use Maybe MARC::Record::new_from_xml if encoding issues on subfield (??)
     $current_item->{marc_more_subfields_xml} = MARC::Record->new_from_xml($current_item->{more_subfields_xml}, 'UTF-8');
 }
 
-# We generate form, and fill with values if defined
-my $temp = GetMarcBiblio({ biblionumber => $biblionumber });
-my $i = 0;
-my @subfields;
-foreach my $tag ( keys %{$tagslib} ) {
-    foreach my $subtag ( keys %{ $tagslib->{$tag} } ) {
-
-        my $subfield = $tagslib->{$tag}{$subtag};
-
-        next if IsMarcStructureInternal( $subfield );
-        next if ( $subfield->{tab} ne "10" );
-
-        my @values = ();
-
-        my $subfield_data;
-
-        # If we are not adding a new item
-        # OR
-        # If the subfield must be prefilled with last catalogued item
-        if (
-            $nextop ne 'additem'
-            || (
-                !$prefillitem
-                || ( $prefillitem && grep { $_ eq $subtag }
-                    @subfields_to_prefill )
-            )
-          )
-        {
-            my $kohafield = $subfield->{kohafield};
-            if ($kohafield) {
-
-                # This is a mapped field
-                ( my $attribute = $kohafield ) =~ s|^items\.||;
-                push @values, $subfield->{repeatable}
-                    ? split '\s\|\s', $current_item->{$attribute}
-                    : $current_item->{$attribute}
-                  if defined $current_item->{$attribute};
-            } else {
-                # Not mapped, picked the values from more_subfields_xml's MARC
-                my $marc_more = $current_item->{marc_more_subfields_xml};
-                if ( $marc_more ) {
-                    for my $f ( $marc_more->fields($tag) ) {
-                        push @values, $f->subfield($subtag);
-                    }
-                }
-            }
-        }
+my $branchcode = $input->param('branch') || C4::Context->userenv->{branch};
 
-        @values = ('') unless @values;
-
-        for my $value (@values) {
-            my $subfield_data = generate_subfield_form(
-                $tag,                        $subtag,
-                $value,                      $tagslib,
-                $subfield,                   $libraries,
-                $biblionumber,               $temp,
-                \@subfields,                 $i,
-                $restrictededition,          $current_item,
-            );
-            push @subfields, $subfield_data;
-            $i++;
-        }
+# If we are not adding a new item
+# OR
+# If the subfield must be prefilled with last catalogued item
+my @subfields_to_prefill;
+if ( $nextop eq 'additem' && $op ne 'dupeitem' && $prefillitem ) {
+    @subfields_to_prefill = split(' ', C4::Context->preference('SubfieldsToUseWhenPrefill'));
+}
+
+# Getting list of subfields to keep when restricted editing is enabled
+my @subfields_to_allow = $restrictededition ? split ' ', C4::Context->preference('SubfieldsToAllowForRestrictedEditing') : ();
+
+my $subfields =
+  Koha::UI::Form::Builder::Item->new(
+    { biblionumber => $biblionumber, item => $current_item } )->edit_form(
+    {
+        branchcode           => $branchcode,
+        restricted_editition => $restrictededition,
+        (
+            @subfields_to_allow
+            ? ( subfields_to_allow => \@subfields_to_allow )
+            : ()
+        ),
+        (
+            @subfields_to_prefill
+            ? ( subfields_to_prefill => \@subfields_to_prefill )
+            : ()
+        ),
+        prefill_with_default_values => 1,
+        branch_limit => C4::Context->userenv->{"branch"},
+        (
+            $op eq 'dupeitem'
+            ? ( ignore_invisible_subfields => 1 )
+            : ()
+        ),
     }
+);
+
+if (   $frameworkcode eq 'FA' ) {
+    my ( $barcode_field ) = grep {$_->{kohafield} eq 'items.barcode'} @$subfields;
+    $barcode_field->{marc_value}->{value} ||= $input->param('barcode');
+}
+
+if( my $default_location = C4::Context->preference('NewItemsDefaultLocation') ) {
+    my ( $location_field ) = grep {$_->{kohafield} eq 'items.location'} @$subfields;
+    $location_field->{marc_value}->{value} ||= $default_location;
 }
-@subfields = sort { $a->{display_order} <=> $b->{display_order} || $a->{subfield} cmp $b->{subfield} } @subfields;
 
+my @ig = Koha::Biblio::ItemGroups->search({ biblio_id => $biblionumber })->as_list();
 # what's the next op ? it's what we are not in : an add if we're editing, otherwise, and edit.
 $template->param(
-    biblionumber => $biblionumber,
-    title        => $oldrecord->{title},
-    author       => $oldrecord->{author},
+    biblio       => $biblio,
     items        => \@items,
+    item_groups      => \@ig,
     item_header_loop => \@header_value_loop,
-    subfields    => \@subfields,
+    subfields        => $subfields,
     itemnumber       => $itemnumber,
     barcode          => $current_item->{barcode},
-    itemtagfield     => $itemtagfield,
-    itemtagsubfield  => $itemtagsubfield,
     op      => $nextop,
     popup => scalar $input->param('popup') ? 1: 0,
     C4::Search::enabled_staff_search_views,