Bug 25444: Simplify the code using a loop
[koha-ffzg.git] / C4 / Items.pm
index 36d1d92..a162ac5 100644 (file)
@@ -30,10 +30,8 @@ BEGIN {
         AddItemBatchFromMarc
         ModItemFromMarc
         Item2Marc
-        ModItem
         ModDateLastSeen
         ModItemTransfer
-        DelItem
         CheckItemPreSave
         GetItemsForInventory
         GetItemsInfo
@@ -41,8 +39,6 @@ BEGIN {
         GetHostItemsInfo
         get_hostitemnumbers_of
         GetHiddenItemnumbers
-        ItemSafeToDelete
-        DelItemCheck
         MoveItemFromBiblio
         CartToShelf
         GetAnalyticsCount
@@ -141,15 +137,27 @@ sub CartToShelf {
 =head2 AddItemFromMarc
 
   my ($biblionumber, $biblioitemnumber, $itemnumber) 
-      = AddItemFromMarc($source_item_marc, $biblionumber);
+      = AddItemFromMarc($source_item_marc, $biblionumber[, $params]);
 
 Given a MARC::Record object containing an embedded item
 record and a biblionumber, create a new item record.
 
+The final optional parameter, C<$params>, expected to contain
+'skip_modzebra_update' key, which relayed down to Koha::Item/store,
+there it prevents calling of ModZebra (and Elasticsearch update),
+which takes most of the time in batch adds/deletes: ModZebra better
+to be called later in C<additem.pl> after the whole loop.
+
+$params:
+    skip_modzebra_update => 1|0
+
 =cut
 
 sub AddItemFromMarc {
-    my ( $source_item_marc, $biblionumber ) = @_;
+    my $source_item_marc = shift;
+    my $biblionumber     = shift;
+    my $params           = @_ ? shift : {};
+
     my $dbh = C4::Context->dbh;
 
     # parse item hash from MARC
@@ -163,7 +171,9 @@ sub AddItemFromMarc {
     my $unlinked_item_subfields = _get_unlinked_item_subfields( $localitemmarc, $frameworkcode );
     $item_values->{more_subfields_xml} = _get_unlinked_subfields_xml($unlinked_item_subfields);
     $item_values->{biblionumber} = $biblionumber;
-    my $item = Koha::Item->new( $item_values )->store;
+    $item_values->{cn_source} = delete $item_values->{'items.cn_source'}; # Because of C4::Biblio::_disambiguate
+    $item_values->{cn_sort}   = delete $item_values->{'items.cn_sort'};   # Because of C4::Biblio::_disambiguate
+    my $item = Koha::Item->new( $item_values )->store({ skip_modzebra_update => $params->{skip_modzebra_update} });
     return ( $item->biblionumber, $item->biblioitemnumber, $item->itemnumber );
 }
 
@@ -241,6 +251,8 @@ sub AddItemBatchFromMarc {
         $item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
         $item->{'biblionumber'} = $biblionumber;
         $item->{'biblioitemnumber'} = $biblioitemnumber;
+        $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
 
         # check for duplicate barcode
         my %item_errors = CheckItemPreSave($item);
@@ -250,15 +262,12 @@ sub AddItemBatchFromMarc {
             next ITEMFIELD;
         }
 
-        _set_derived_columns_for_add($item);
-        my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
-        warn $error if $error;
-        push @itemnumbers, $itemnumber; # FIXME not checking error
-        $item->{'itemnumber'} = $itemnumber;
+        my $item_object = Koha::Item->new($item)->store;
+        push @itemnumbers, $item_object->itemnumber; # FIXME not checking error
 
-        logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog"); 
+        logaction("CATALOGUING", "ADD", $item_object->itemnumber, "item") if C4::Context->preference("CataloguingLog");
 
-        my $new_item_marc = _marc_from_item_hash($item, $frameworkcode, $unlinked_item_subfields);
+        my $new_item_marc = _marc_from_item_hash($item_object->unblessed, $frameworkcode, $unlinked_item_subfields);
         $item_field->replace_with($new_item_marc->field($itemtag));
     }
 
@@ -273,83 +282,6 @@ sub AddItemBatchFromMarc {
     return (\@itemnumbers, \@errors);
 }
 
-=head2 ModItemFromMarc
-
-  ModItemFromMarc($item_marc, $biblionumber, $itemnumber);
-
-This function updates an item record based on a supplied
-C<MARC::Record> object containing an embedded item field.
-This API is meant for the use of C<additem.pl>; for 
-other purposes, C<ModItem> should be used.
-
-This function uses the hash %default_values_for_mod_from_marc,
-which contains default values for item fields to
-apply when modifying an item.  This is needed because
-if an item field's value is cleared, TransformMarcToKoha
-does not include the column in the
-hash that's passed to ModItem, which without
-use of this hash makes it impossible to clear
-an item field's value.  See bug 2466.
-
-Note that only columns that can be directly
-changed from the cataloging and serials
-item editors are included in this hash.
-
-Returns item record
-
-=cut
-
-sub _build_default_values_for_mod_marc {
-    # Has no framework parameter anymore, since Default is authoritative
-    # for Koha to MARC mappings.
-
-    my $cache     = Koha::Caches->get_instance();
-    my $cache_key = "default_value_for_mod_marc-";
-    my $cached    = $cache->get_from_cache($cache_key);
-    return $cached if $cached;
-
-    my $default_values = {
-        barcode                  => undef,
-        booksellerid             => undef,
-        ccode                    => undef,
-        'items.cn_source'        => undef,
-        coded_location_qualifier => undef,
-        copynumber               => undef,
-        damaged                  => 0,
-        enumchron                => undef,
-        holdingbranch            => undef,
-        homebranch               => undef,
-        itemcallnumber           => undef,
-        itemlost                 => 0,
-        itemnotes                => undef,
-        itemnotes_nonpublic      => undef,
-        itype                    => undef,
-        location                 => undef,
-        permanent_location       => undef,
-        materials                => undef,
-        new_status               => undef,
-        notforloan               => 0,
-        price                    => undef,
-        replacementprice         => undef,
-        replacementpricedate     => undef,
-        restricted               => undef,
-        stack                    => undef,
-        stocknumber              => undef,
-        uri                      => undef,
-        withdrawn                => 0,
-    };
-    my %default_values_for_mod_from_marc;
-    while ( my ( $field, $default_value ) = each %$default_values ) {
-        my $kohafield = $field;
-        $kohafield =~ s|^([^\.]+)$|items.$1|;
-        $default_values_for_mod_from_marc{$field} = $default_value
-            if C4::Biblio::GetMarcFromKohaField( $kohafield );
-    }
-
-    $cache->set_in_cache($cache_key, \%default_values_for_mod_from_marc);
-    return \%default_values_for_mod_from_marc;
-}
-
 sub ModItemFromMarc {
     my $item_marc = shift;
     my $biblionumber = shift;
@@ -360,81 +292,18 @@ sub ModItemFromMarc {
 
     my $localitemmarc = MARC::Record->new;
     $localitemmarc->append_fields( $item_marc->field($itemtag) );
+    my $item_object = Koha::Items->find($itemnumber);
     my $item = TransformMarcToKoha( $localitemmarc, $frameworkcode, 'items' );
-    my $default_values = _build_default_values_for_mod_marc();
-    foreach my $item_field ( keys %$default_values ) {
-        $item->{$item_field} = $default_values->{$item_field}
-          unless exists $item->{$item_field};
-    }
+    $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
+    $item->{itemnumber} = $itemnumber;
+    $item->{biblionumber} = $biblionumber;
+    $item_object = $item_object->set_or_blank($item);
     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;
 
-    my $item_object = Koha::Items->find($itemnumber);
-    $item_object->more_subfields_xml(_get_unlinked_subfields_xml($unlinked_item_subfields))->store;
-
-    return $item_object->get_from_storage->unblessed;
-}
-
-=head2 ModItem
-
-ModItem(
-    { column => $newvalue },
-    $biblionumber,
-    $itemnumber,
-    {
-        [ unlinked_item_subfields => $unlinked_item_subfields, ]
-        [ log_action => 1, ]
-    }
-);
-
-Change one or more columns in an item record.
-
-The first argument is a hashref mapping from item column
-names to the new values.  The second and third arguments
-are the biblionumber and itemnumber, respectively.
-The fourth, optional parameter (additional_params) may contain the keys
-unlinked_item_subfields and log_action.
-
-C<$unlinked_item_subfields> contains an arrayref containing
-subfields present in the original MARC
-representation of the item (e.g., from the item editor) that are
-not mapped to C<items> columns directly but should instead
-be stored in C<items.more_subfields_xml> and included in 
-the biblio items tag for display and indexing.
-
-If one of the changed columns is used to calculate
-the derived value of a column such as C<items.cn_sort>, 
-this routine will perform the necessary calculation
-and set the value.
-
-If log_action is set to false, the action will not be logged.
-If log_action is true or undefined, the action will be logged.
-
-=cut
-
-sub ModItem {
-    my ( $item, $biblionumber, $itemnumber, $additional_params ) = @_;
-    my $log_action = $additional_params->{log_action} // 1;
-
-    _set_derived_columns_for_mod($item);
-    _do_column_fixes_for_mod($item);
-    # FIXME add checks
-    # duplicate barcode
-    # attempt to change itemnumber
-    # attempt to change biblionumber (if we want
-    # an API to relink an item to a different bib,
-    # it should be a separate function)
-
-    # update items table
-    _koha_modify_item($item);
-
-    # request that bib be reindexed so that searching on current
-    # item status is possible
-    ModZebra( $biblionumber, "specialUpdate", "biblioserver" );
-
-    _after_item_action_hooks({ action => 'modify', item_id => $itemnumber });
-
-    logaction( "CATALOGUING", "MODIFY", $itemnumber, "item " . Dumper($item) )
-      if $log_action && C4::Context->preference("CataloguingLog");
+    return $item_object->unblessed;
 }
 
 =head2 ModItemTransfer
@@ -489,40 +358,6 @@ sub ModDateLastSeen {
     $item->store({ log_action => 0 });
 }
 
-=head2 DelItem
-
-  DelItem({ itemnumber => $itemnumber, [ biblionumber => $biblionumber ] } );
-
-Exported function (core API) for deleting an item record in Koha.
-
-=cut
-
-sub DelItem {
-    my ( $params ) = @_;
-
-    my $itemnumber   = $params->{itemnumber};
-    my $biblionumber = $params->{biblionumber};
-
-    unless ($biblionumber) {
-        my $item = Koha::Items->find( $itemnumber );
-        $biblionumber = $item ? $item->biblio->biblionumber : undef;
-    }
-
-    # If there is no biblionumber for the given itemnumber, there is nothing to delete
-    return 0 unless $biblionumber;
-
-    # FIXME check the item has no current issues
-    my $deleted = _koha_delete_item( $itemnumber );
-
-    ModZebra( $biblionumber, "specialUpdate", "biblioserver" );
-
-    _after_item_action_hooks({ action => 'delete', item_id => $itemnumber });
-
-    #search item field code
-    logaction("CATALOGUING", "DELETE", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
-    return $deleted;
-}
-
 =head2 CheckItemPreSave
 
     my $item_ref = TransformMarcToKoha($marc, 'items');
@@ -1199,7 +1034,7 @@ sub Item2Marc {
         } keys %{ $itemrecord } 
     };
     my $framework = C4::Biblio::GetFrameworkCode( $biblionumber );
-    my $itemmarc = C4::Biblio::TransformKohaToMarc( $mungeditem ); # Bug 21774: no_split parameter removed to allow cloned subfields
+    my $itemmarc = C4::Biblio::TransformKohaToMarc( $mungeditem, { framework => $framework } );
     my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField(
         "items.itemnumber", $framework,
     );
@@ -1221,247 +1056,6 @@ the inner workings of C<C4::Items>.
 
 =cut
 
-=head2 %derived_columns
-
-This hash keeps track of item columns that
-are strictly derived from other columns in
-the item record and are not meant to be set
-independently.
-
-Each key in the hash should be the name of a
-column (as named by TransformMarcToKoha).  Each
-value should be hashref whose keys are the
-columns on which the derived column depends.  The
-hashref should also contain a 'BUILDER' key
-that is a reference to a sub that calculates
-the derived value.
-
-=cut
-
-my %derived_columns = (
-    'items.cn_sort' => {
-        'itemcallnumber' => 1,
-        'items.cn_source' => 1,
-        'BUILDER' => \&_calc_items_cn_sort,
-    }
-);
-
-=head2 _set_derived_columns_for_add 
-
-  _set_derived_column_for_add($item);
-
-Given an item hash representing a new item to be added,
-calculate any derived columns.  Currently the only
-such column is C<items.cn_sort>.
-
-=cut
-
-sub _set_derived_columns_for_add {
-    my $item = shift;
-
-    foreach my $column (keys %derived_columns) {
-        my $builder = $derived_columns{$column}->{'BUILDER'};
-        my $source_values = {};
-        foreach my $source_column (keys %{ $derived_columns{$column} }) {
-            next if $source_column eq 'BUILDER';
-            $source_values->{$source_column} = $item->{$source_column};
-        }
-        $builder->($item, $source_values);
-    }
-}
-
-=head2 _do_column_fixes_for_mod
-
-  _do_column_fixes_for_mod($item);
-
-Given an item hashref containing one or more
-columns to modify, fix up certain values.
-Specifically, set to 0 any passed value
-of C<notforloan>, C<damaged>, C<itemlost>, or
-C<withdrawn> that is either undefined or
-contains the empty string.
-
-=cut
-
-sub _do_column_fixes_for_mod {
-    my $item = shift;
-
-    if (exists $item->{'notforloan'} and
-        (not defined $item->{'notforloan'} or $item->{'notforloan'} eq '')) {
-        $item->{'notforloan'} = 0;
-    }
-    if (exists $item->{'damaged'} and
-        (not defined $item->{'damaged'} or $item->{'damaged'} eq '')) {
-        $item->{'damaged'} = 0;
-    }
-    if (exists $item->{'itemlost'} and
-        (not defined $item->{'itemlost'} or $item->{'itemlost'} eq '')) {
-        $item->{'itemlost'} = 0;
-    }
-    if (exists $item->{'withdrawn'} and
-        (not defined $item->{'withdrawn'} or $item->{'withdrawn'} eq '')) {
-        $item->{'withdrawn'} = 0;
-    }
-    if (
-        exists $item->{location}
-        and ( !defined $item->{location}
-            || ( $item->{location} ne 'CART' and $item->{location} ne 'PROC' ) )
-        and not $item->{permanent_location}
-      )
-    {
-        $item->{'permanent_location'} = $item->{'location'};
-    }
-    if (exists $item->{'timestamp'}) {
-        delete $item->{'timestamp'};
-    }
-}
-
-=head2 _get_single_item_column
-
-  _get_single_item_column($column, $itemnumber);
-
-Retrieves the value of a single column from an C<items>
-row specified by C<$itemnumber>.
-
-=cut
-
-sub _get_single_item_column {
-    my $column = shift;
-    my $itemnumber = shift;
-    
-    my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare("SELECT $column FROM items WHERE itemnumber = ?");
-    $sth->execute($itemnumber);
-    my ($value) = $sth->fetchrow();
-    return $value; 
-}
-
-=head2 _calc_items_cn_sort
-
-  _calc_items_cn_sort($item, $source_values);
-
-Helper routine to calculate C<items.cn_sort>.
-
-=cut
-
-sub _calc_items_cn_sort {
-    my $item = shift;
-    my $source_values = shift;
-
-    $item->{'items.cn_sort'} = GetClassSort($source_values->{'items.cn_source'}, $source_values->{'itemcallnumber'}, "");
-}
-
-=head2 _koha_new_item
-
-  my ($itemnumber,$error) = _koha_new_item( $item, $barcode );
-
-Perform the actual insert into the C<items> table.
-
-=cut
-
-sub _koha_new_item {
-    my ( $item, $barcode ) = @_;
-    my $dbh=C4::Context->dbh;  
-    my $error;
-    $item->{permanent_location} //= $item->{location};
-    _mod_item_dates( $item );
-    my $query =
-           "INSERT INTO items SET
-            biblionumber        = ?,
-            biblioitemnumber    = ?,
-            barcode             = ?,
-            dateaccessioned     = ?,
-            booksellerid        = ?,
-            homebranch          = ?,
-            price               = ?,
-            replacementprice    = ?,
-            replacementpricedate = ?,
-            datelastborrowed    = ?,
-            datelastseen        = ?,
-            stack               = ?,
-            notforloan          = ?,
-            damaged             = ?,
-            itemlost            = ?,
-            withdrawn           = ?,
-            itemcallnumber      = ?,
-            coded_location_qualifier = ?,
-            restricted          = ?,
-            itemnotes           = ?,
-            itemnotes_nonpublic = ?,
-            holdingbranch       = ?,
-            location            = ?,
-            permanent_location  = ?,
-            onloan              = ?,
-            issues              = ?,
-            renewals            = ?,
-            reserves            = ?,
-            cn_source           = ?,
-            cn_sort             = ?,
-            ccode               = ?,
-            itype               = ?,
-            materials           = ?,
-            uri                 = ?,
-            enumchron           = ?,
-            more_subfields_xml  = ?,
-            copynumber          = ?,
-            stocknumber         = ?,
-            new_status          = ?
-          ";
-    my $sth = $dbh->prepare($query);
-    my $today = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
-   $sth->execute(
-            $item->{'biblionumber'},
-            $item->{'biblioitemnumber'},
-            $barcode,
-            $item->{'dateaccessioned'},
-            $item->{'booksellerid'},
-            $item->{'homebranch'},
-            $item->{'price'},
-            $item->{'replacementprice'},
-            $item->{'replacementpricedate'} || $today,
-            $item->{datelastborrowed},
-            $item->{datelastseen} || $today,
-            $item->{stack},
-            $item->{'notforloan'},
-            $item->{'damaged'},
-            $item->{'itemlost'},
-            $item->{'withdrawn'},
-            $item->{'itemcallnumber'},
-            $item->{'coded_location_qualifier'},
-            $item->{'restricted'},
-            $item->{'itemnotes'},
-            $item->{'itemnotes_nonpublic'},
-            $item->{'holdingbranch'},
-            $item->{'location'},
-            $item->{'permanent_location'},
-            $item->{'onloan'},
-            $item->{'issues'},
-            $item->{'renewals'},
-            $item->{'reserves'},
-            $item->{'items.cn_source'},
-            $item->{'items.cn_sort'},
-            $item->{'ccode'},
-            $item->{'itype'},
-            $item->{'materials'},
-            $item->{'uri'},
-            $item->{'enumchron'},
-            $item->{'more_subfields_xml'},
-            $item->{'copynumber'},
-            $item->{'stocknumber'},
-            $item->{'new_status'},
-    );
-
-    my $itemnumber;
-    if ( defined $sth->errstr ) {
-        $error.="ERROR in _koha_new_item $query".$sth->errstr;
-    }
-    else {
-        $itemnumber = $dbh->{'mysql_insertid'};
-    }
-
-    return ( $itemnumber, $error );
-}
-
 =head2 MoveItemFromBiblio
 
   MoveItemFromBiblio($itenumber, $frombiblio, $tobiblio);
@@ -1512,193 +1106,6 @@ sub MoveItemFromBiblio {
     return;
 }
 
-=head2 ItemSafeToDelete
-
-   ItemSafeToDelete( $biblionumber, $itemnumber);
-
-Exported function (core API) for checking whether an item record is safe to delete.
-
-returns 1 if the item is safe to delete,
-
-"book_on_loan" if the item is checked out,
-
-"not_same_branch" if the item is blocked by independent branches,
-
-"book_reserved" if the there are holds aganst the item, or
-
-"linked_analytics" if the item has linked analytic records.
-
-=cut
-
-sub ItemSafeToDelete {
-    my ( $biblionumber, $itemnumber ) = @_;
-    my $status;
-    my $dbh = C4::Context->dbh;
-
-    my $error;
-
-    my $countanalytics = GetAnalyticsCount($itemnumber);
-
-    my $item = Koha::Items->find($itemnumber) or return;
-
-    if ($item->checkout) {
-        $status = "book_on_loan";
-    }
-    elsif ( defined C4::Context->userenv
-        and !C4::Context->IsSuperLibrarian()
-        and C4::Context->preference("IndependentBranches")
-        and ( C4::Context->userenv->{branch} ne $item->homebranch ) )
-    {
-        $status = "not_same_branch";
-    }
-    else {
-        # check it doesn't have a waiting reserve
-        my $sth = $dbh->prepare(
-            q{
-            SELECT COUNT(*) FROM reserves
-            WHERE (found = 'W' OR found = 'T')
-            AND itemnumber = ?
-        }
-        );
-        $sth->execute($itemnumber);
-        my ($reserve) = $sth->fetchrow;
-        if ($reserve) {
-            $status = "book_reserved";
-        }
-        elsif ( $countanalytics > 0 ) {
-            $status = "linked_analytics";
-        }
-        else {
-            $status = 1;
-        }
-    }
-    return $status;
-}
-
-=head2 DelItemCheck
-
-   DelItemCheck( $biblionumber, $itemnumber);
-
-Exported function (core API) for deleting an item record in Koha if there no current issue.
-
-DelItemCheck wraps ItemSafeToDelete around DelItem.
-
-=cut
-
-sub DelItemCheck {
-    my ( $biblionumber, $itemnumber ) = @_;
-    my $status = ItemSafeToDelete( $biblionumber, $itemnumber );
-
-    if ( $status == 1 ) {
-        DelItem(
-            {
-                biblionumber => $biblionumber,
-                itemnumber   => $itemnumber
-            }
-        );
-    }
-    return $status;
-}
-
-=head2 _koha_modify_item
-
-  my ($itemnumber,$error) =_koha_modify_item( $item );
-
-Perform the actual update of the C<items> row.  Note that this
-routine accepts a hashref specifying the columns to update.
-
-=cut
-
-sub _koha_modify_item {
-    my ( $item ) = @_;
-    my $dbh=C4::Context->dbh;  
-    my $error;
-
-    my $query = "UPDATE items SET ";
-    my @bind;
-    _mod_item_dates( $item );
-    for my $key ( keys %$item ) {
-        next if ( $key eq 'itemnumber' );
-        $query.="$key=?,";
-        push @bind, $item->{$key};
-    }
-    $query =~ s/,$//;
-    $query .= " WHERE itemnumber=?";
-    push @bind, $item->{'itemnumber'};
-    my $sth = $dbh->prepare($query);
-    $sth->execute(@bind);
-    if ( $sth->err ) {
-        $error.="ERROR in _koha_modify_item $query: ".$sth->errstr;
-        warn $error;
-    }
-    return ($item->{'itemnumber'},$error);
-}
-
-sub _mod_item_dates { # date formatting for date fields in item hash
-    my ( $item ) = @_;
-    return if !$item || ref($item) ne 'HASH';
-
-    my @keys = grep
-        { $_ =~ /^onloan$|^date|date$|datetime$/ }
-        keys %$item;
-    # Incl. dateaccessioned,replacementpricedate,datelastborrowed,datelastseen
-    # NOTE: We do not (yet) have items fields ending with datetime
-    # Fields with _on$ have been handled already
-
-    foreach my $key ( @keys ) {
-        next if !defined $item->{$key}; # skip undefs
-        my $dt = eval { dt_from_string( $item->{$key} ) };
-            # eval: dt_from_string will die on us if we pass illegal dates
-
-        my $newstr;
-        if( defined $dt  && ref($dt) eq 'DateTime' ) {
-            if( $key =~ /datetime/ ) {
-                $newstr = DateTime::Format::MySQL->format_datetime($dt);
-            } else {
-                $newstr = DateTime::Format::MySQL->format_date($dt);
-            }
-        }
-        $item->{$key} = $newstr; # might be undef to clear garbage
-    }
-}
-
-=head2 _koha_delete_item
-
-  _koha_delete_item( $itemnum );
-
-Internal function to delete an item record from the koha tables
-
-=cut
-
-sub _koha_delete_item {
-    my ( $itemnum ) = @_;
-
-    my $dbh = C4::Context->dbh;
-    # save the deleted item to deleteditems table
-    my $sth = $dbh->prepare("SELECT * FROM items WHERE itemnumber=?");
-    $sth->execute($itemnum);
-    my $data = $sth->fetchrow_hashref();
-
-    # There is no item to delete
-    return 0 unless $data;
-
-    my $query = "INSERT INTO deleteditems SET ";
-    my @bind  = ();
-    foreach my $key ( keys %$data ) {
-        next if ( $key eq 'timestamp' ); # timestamp will be set by db
-        $query .= "$key = ?,";
-        push( @bind, $data->{$key} );
-    }
-    $query =~ s/\,$//;
-    $sth = $dbh->prepare($query);
-    $sth->execute(@bind);
-
-    # delete from items table
-    $sth = $dbh->prepare("DELETE FROM items WHERE itemnumber=?");
-    my $deleted = $sth->execute($itemnum);
-    return ( $deleted == 1 ) ? 1 : 0;
-}
-
 =head2 _marc_from_item_hash
 
   my $item_marc = _marc_from_item_hash($item, $frameworkcode[, $unlinked_item_subfields]);
@@ -1935,9 +1342,6 @@ sub _SearchItems_build_where_fragment {
                     }
                     $column = "ExtractValue($sqlfield, '$xpath')";
                 }
-            } elsif ($field eq 'issues') {
-                # Consider NULL as 0 for issues count
-                $column = 'COALESCE(issues,0)';
             } else {
                 $column = $field;
             }
@@ -2273,8 +1677,7 @@ sub PrepareItemrecordDisplay {
                         #----- itemtypes
                     } elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
                         my $itemtypes = Koha::ItemTypes->search_with_localization;
-                        push @authorised_values, ""
-                          unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
+                        push @authorised_values, "";
                         while ( my $itemtype = $itemtypes->next ) {
                             push @authorised_values, $itemtype->itemtype;
                             $authorised_lib{$itemtype->itemtype} = $itemtype->translated_description;
@@ -2285,7 +1688,7 @@ sub PrepareItemrecordDisplay {
 
                         #---- class_sources
                     } elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "cn_source" ) {
-                        push @authorised_values, "" unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
+                        push @authorised_values, "";
 
                         my $class_sources = GetClassSources();
                         my $default_source = $defaultvalue || C4::Context->preference("DefaultClassificationSource");
@@ -2305,8 +1708,7 @@ sub PrepareItemrecordDisplay {
                             $tagslib->{$tag}->{$subfield}->{authorised_value},
                             $branch_limit ? $branch_limit : ()
                         );
-                        push @authorised_values, ""
-                          unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
+                        push @authorised_values, "";
                         while ( my ( $value, $lib ) = $authorised_values_sth->fetchrow_array ) {
                             push @authorised_values, $value;
                             $authorised_lib{$value} = $lib;