Bug 16889: Remove C4::Items::columns and use Koha::Items->columns instead
[koha.git] / C4 / Items.pm
index a78c9c4..0e04574 100644 (file)
@@ -25,7 +25,7 @@ use Carp;
 use C4::Context;
 use C4::Koha;
 use C4::Biblio;
-use C4::Dates qw/format_date format_date_in_iso/;
+use Koha::DateUtils;
 use MARC::Record;
 use C4::ClassSource;
 use C4::Log;
@@ -35,13 +35,15 @@ 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::DateUtils qw/dt_from_string/;
-
 use Koha::Database;
 
-use vars qw($VERSION @ISA @EXPORT);
+use Koha::Items;
+use Koha::SearchEngine;
+use Koha::SearchEngine::Search;
+
+use vars qw(@ISA @EXPORT);
 
 BEGIN {
-    $VERSION = 3.07.00.049;
 
        require Exporter;
     @ISA = qw( Exporter );
@@ -251,7 +253,7 @@ sub AddItemFromMarc {
        
        my $localitemmarc=MARC::Record->new;
        $localitemmarc->append_fields($source_item_marc->field($itemtag));
-    my $item = &TransformMarcToKoha( $dbh, $localitemmarc, $frameworkcode ,'items');
+    my $item = &TransformMarcToKoha( $localitemmarc, $frameworkcode ,'items');
     my $unlinked_item_subfields = _get_unlinked_item_subfields($localitemmarc, $frameworkcode);
     return AddItem($item, $biblionumber, $dbh, $frameworkcode, $unlinked_item_subfields);
 }
@@ -383,7 +385,7 @@ sub AddItemBatchFromMarc {
         $temp_item_marc->append_fields($item_field);
     
         # add biblionumber and biblioitemnumber
-        my $item = TransformMarcToKoha( $dbh, $temp_item_marc, $frameworkcode, 'items' );
+        my $item = TransformMarcToKoha( $temp_item_marc, $frameworkcode, 'items' );
         my $unlinked_item_subfields = _get_unlinked_item_subfields($temp_item_marc, $frameworkcode);
         $item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
         $item->{'biblionumber'} = $biblionumber;
@@ -447,13 +449,14 @@ Returns item record
 
 =cut
 
-our %default_values_for_mod_from_marc;
-
 sub _build_default_values_for_mod_marc {
     my ($frameworkcode) = @_;
-    return $default_values_for_mod_from_marc{$frameworkcode}
-      if exists $default_values_for_mod_from_marc{$frameworkcode};
-    my $marc_structure = C4::Biblio::GetMarcStructure( 1, $frameworkcode );
+
+    my $cache     = Koha::Cache->get_instance();
+    my $cache_key = "default_value_for_mod_marc-$frameworkcode";
+    my $cached    = $cache->get_from_cache($cache_key);
+    return $cached if $cached;
+
     my $default_values = {
         barcode                  => undef,
         booksellerid             => undef,
@@ -473,6 +476,7 @@ sub _build_default_values_for_mod_marc {
         location                 => undef,
         permanent_location       => undef,
         materials                => undef,
+        new_status               => undef,
         notforloan               => 0,
         # paidfor => undef, # commented, see bug 12817
         price                    => undef,
@@ -484,15 +488,18 @@ sub _build_default_values_for_mod_marc {
         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{$frameworkcode}{$field} =
+        $default_values_for_mod_from_marc{$field} =
           $default_value
           if C4::Koha::IsKohaFieldLinked(
             { kohafield => $kohafield, frameworkcode => $frameworkcode } );
     }
-    return $default_values_for_mod_from_marc{$frameworkcode};
+
+    $cache->set_in_cache($cache_key, \%default_values_for_mod_from_marc);
+    return \%default_values_for_mod_from_marc;
 }
 
 sub ModItemFromMarc {
@@ -506,8 +513,8 @@ sub ModItemFromMarc {
 
     my $localitemmarc = MARC::Record->new;
     $localitemmarc->append_fields( $item_marc->field($itemtag) );
-    my $item = &TransformMarcToKoha( $dbh, $localitemmarc, $frameworkcode, 'items' );
-    my $default_values = _build_default_values_for_mod_marc();
+    my $item = &TransformMarcToKoha( $localitemmarc, $frameworkcode, 'items' );
+    my $default_values = _build_default_values_for_mod_marc($frameworkcode);
     foreach my $item_field ( keys %$default_values ) {
         $item->{$item_field} = $default_values->{$item_field}
           unless exists $item->{$item_field};
@@ -648,8 +655,8 @@ C<$itemnum> is the item number
 sub ModDateLastSeen {
     my ($itemnumber) = @_;
     
-    my $today = C4::Dates->new();    
-    ModItem({ itemlost => 0, datelastseen => $today->output("iso") }, undef, $itemnumber);
+    my $today = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
+    ModItem({ itemlost => 0, datelastseen => $today }, undef, $itemnumber);
 }
 
 =head2 DelItem
@@ -1035,7 +1042,7 @@ sub GetLostItems {
   branch       => $branch,
   offset       => $offset,
   size         => $size,
-  stautshash   => $statushash
+  statushash   => $statushash,
   interface    => $interface,
 } );
 
@@ -1101,7 +1108,7 @@ sub GetItemsForInventory {
     }
 
     if ($datelastseen) {
-        $datelastseen = format_date_in_iso($datelastseen);  
+        $datelastseen = output_pref({ str => $datelastseen, dateformat => 'iso', dateonly => 1 });
         push @where_strings, '(datelastseen < ? OR datelastseen IS NULL)';
         push @bind_params, $datelastseen;
     }
@@ -1301,6 +1308,8 @@ sub GetItemsInfo {
     my ( $biblionumber ) = @_;
     my $dbh   = C4::Context->dbh;
     # note biblioitems.* must be avoided to prevent large marc and marcxml fields from killing performance.
+    require C4::Languages;
+    my $language = C4::Languages::getlanguage();
     my $query = "
     SELECT items.*,
            biblio.*,
@@ -1326,6 +1335,7 @@ sub GetItemsInfo {
            serial.serialseq,
            serial.publisheddate,
            itemtypes.description,
+           COALESCE( localization.translation, itemtypes.description ) AS translated_description,
            itemtypes.notforloan as notforloan_per_itemtype,
            holding.branchurl,
            holding.branchname,
@@ -1344,9 +1354,15 @@ sub GetItemsInfo {
      LEFT JOIN serial USING (serialid)
      LEFT JOIN itemtypes   ON   itemtypes.itemtype         = "
      . (C4::Context->preference('item-level_itypes') ? 'items.itype' : 'biblioitems.itemtype');
+    $query .= q|
+    LEFT JOIN localization ON itemtypes.itemtype = localization.code
+        AND localization.entity = 'itemtypes'
+        AND localization.lang = ?
+    |;
+
     $query .= " WHERE items.biblionumber = ? ORDER BY home.branchname, items.enumchron, LPAD( items.copynumber, 8, '0' ), items.dateaccessioned DESC" ;
     my $sth = $dbh->prepare($query);
-    $sth->execute($biblionumber);
+    $sth->execute($language, $biblionumber);
     my $i = 0;
     my @results;
     my $serial;
@@ -1750,104 +1766,6 @@ sub GetHiddenItemnumbers {
     return @resultitems;
 }
 
-=head3 get_item_authorised_values
-
-find the types and values for all authorised values assigned to this item.
-
-parameters: itemnumber
-
-returns: a hashref malling the authorised value to the value set for this itemnumber
-
-    $authorised_values = {
-             'CCODE'      => undef,
-             'DAMAGED'    => '0',
-             'LOC'        => '3',
-             'LOST'       => '0'
-             'NOT_LOAN'   => '0',
-             'RESTRICTED' => undef,
-             'STACK'      => undef,
-             'WITHDRAWN'  => '0',
-             'branches'   => 'CPL',
-             'cn_source'  => undef,
-             'itemtypes'  => 'SER',
-           };
-
-Notes: see C4::Biblio::get_biblio_authorised_values for a similar method at the biblio level.
-
-=cut
-
-sub get_item_authorised_values {
-    my $itemnumber = shift;
-
-    # assume that these entries in the authorised_value table are item level.
-    my $query = q(SELECT distinct authorised_value, kohafield
-                    FROM marc_subfield_structure
-                    WHERE kohafield like 'item%'
-                      AND authorised_value != '' );
-
-    my $itemlevel_authorised_values = C4::Context->dbh->selectall_hashref( $query, 'authorised_value' );
-    my $iteminfo = GetItem( $itemnumber );
-    # warn( Data::Dumper->Dump( [ $itemlevel_authorised_values ], [ 'itemlevel_authorised_values' ] ) );
-    my $return;
-    foreach my $this_authorised_value ( keys %$itemlevel_authorised_values ) {
-        my $field = $itemlevel_authorised_values->{ $this_authorised_value }->{'kohafield'};
-        $field =~ s/^items\.//;
-        if ( exists $iteminfo->{ $field } ) {
-            $return->{ $this_authorised_value } = $iteminfo->{ $field };
-        }
-    }
-    # warn( Data::Dumper->Dump( [ $return ], [ 'return' ] ) );
-    return $return;
-}
-
-=head3 get_authorised_value_images
-
-find a list of icons that are appropriate for display based on the
-authorised values for a biblio.
-
-parameters: listref of authorised values, such as comes from
-get_item_authorised_values or
-from C4::Biblio::get_biblio_authorised_values
-
-returns: listref of hashrefs for each image. Each hashref looks like this:
-
-      { imageurl => '/intranet-tmpl/prog/img/itemtypeimg/npl/WEB.gif',
-        label    => '',
-        category => '',
-        value    => '', }
-
-Notes: Currently, I put on the full path to the images on the staff
-side. This should either be configurable or not done at all. Since I
-have to deal with 'intranet' or 'opac' in
-get_biblio_authorised_values, perhaps I should be passing it in.
-
-=cut
-
-sub get_authorised_value_images {
-    my $authorised_values = shift;
-
-    my @imagelist;
-
-    my $authorised_value_list = GetAuthorisedValues();
-    # warn ( Data::Dumper->Dump( [ $authorised_value_list ], [ 'authorised_value_list' ] ) );
-    foreach my $this_authorised_value ( @$authorised_value_list ) {
-        if ( exists $authorised_values->{ $this_authorised_value->{'category'} }
-             && $authorised_values->{ $this_authorised_value->{'category'} } eq $this_authorised_value->{'authorised_value'} ) {
-            # warn ( Data::Dumper->Dump( [ $this_authorised_value ], [ 'this_authorised_value' ] ) );
-            if ( defined $this_authorised_value->{'imageurl'} ) {
-                push @imagelist, { imageurl => C4::Koha::getitemtypeimagelocation( 'intranet', $this_authorised_value->{'imageurl'} ),
-                                   label    => $this_authorised_value->{'lib'},
-                                   category => $this_authorised_value->{'category'},
-                                   value    => $this_authorised_value->{'authorised_value'}, };
-            }
-        }
-    }
-
-    # warn ( Data::Dumper->Dump( [ \@imagelist ], [ 'imagelist' ] ) );
-    return \@imagelist;
-
-}
-
 =head1 LIMITED USE FUNCTIONS
 
 The following functions, while part of the public API,
@@ -2048,7 +1966,11 @@ sub _do_column_fixes_for_mod {
         (not defined $item->{'withdrawn'} or $item->{'withdrawn'} eq '')) {
         $item->{'withdrawn'} = 0;
     }
-    if (exists $item->{'location'} && !$item->{'permanent_location'}) {
+    if (exists $item->{location}
+        and $item->{location} ne 'CART'
+        and $item->{location} ne 'PROC'
+        and not $item->{permanent_location}
+    ) {
         $item->{'permanent_location'} = $item->{'location'};
     }
     if (exists $item->{'timestamp'}) {
@@ -2128,7 +2050,7 @@ C<items.withdrawn>
 
 sub _set_defaults_for_add {
     my $item = shift;
-    $item->{dateaccessioned} ||= C4::Dates->new->output('iso');
+    $item->{dateaccessioned} ||= output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
     $item->{$_} ||= 0 for (qw( notforloan damaged itemlost withdrawn));
 }
 
@@ -2162,7 +2084,7 @@ sub _koha_new_item {
             notforloan          = ?,
             damaged             = ?,
             itemlost            = ?,
-            withdrawn            = ?,
+            withdrawn           = ?,
             itemcallnumber      = ?,
             coded_location_qualifier = ?,
             restricted          = ?,
@@ -2171,7 +2093,7 @@ sub _koha_new_item {
             holdingbranch       = ?,
             paidfor             = ?,
             location            = ?,
-            permanent_location            = ?,
+            permanent_location  = ?,
             onloan              = ?,
             issues              = ?,
             renewals            = ?,
@@ -2181,14 +2103,15 @@ sub _koha_new_item {
             ccode               = ?,
             itype               = ?,
             materials           = ?,
-            uri = ?,
+            uri                 = ?,
             enumchron           = ?,
             more_subfields_xml  = ?,
             copynumber          = ?,
-            stocknumber         = ?
+            stocknumber         = ?,
+            new_status          = ?
           ";
     my $sth = $dbh->prepare($query);
-    my $today = C4::Dates->today('iso');
+    my $today = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
    $sth->execute(
             $item->{'biblionumber'},
             $item->{'biblioitemnumber'},
@@ -2229,6 +2152,7 @@ sub _koha_new_item {
             $item->{'more_subfields_xml'},
             $item->{'copynumber'},
             $item->{'stocknumber'},
+            $item->{'new_status'},
     );
 
     my $itemnumber;
@@ -2302,6 +2226,9 @@ Exported function (core API) for deleting an item record in Koha if there no cur
 
 sub DelItemCheck {
     my ( $dbh, $biblionumber, $itemnumber ) = @_;
+
+    $dbh ||= C4::Context->dbh;
+
     my $error;
 
         my $countanalytics=GetAnalyticsCount($itemnumber);
@@ -2320,7 +2247,8 @@ sub DelItemCheck {
     if ($onloan){
         $error = "book_on_loan" 
     }
-    elsif ( !C4::Context->IsSuperLibrarian()
+    elsif ( defined C4::Context->userenv
+        and !C4::Context->IsSuperLibrarian()
         and C4::Context->preference("IndependentBranches")
         and ( C4::Context->userenv->{branch} ne $item->{'homebranch'} ) )
     {
@@ -2581,12 +2509,12 @@ counts Usage of itemnumber in Analytical bibliorecords.
 
 sub GetAnalyticsCount {
     my ($itemnumber) = @_;
-    require C4::Search;
 
     ### ZOOM search here
     my $query;
     $query= "hi=".$itemnumber;
-            my ($err,$res,$result) = C4::Search::SimpleSearch($query,0,10);
+    my $searcher = Koha::SearchEngine::Search->new({index => $Koha::SearchEngine::BIBLIOS_INDEX});
+    my ($err,$res,$result) = $searcher->simple_search_compat($query,0,10);
     return ($result);
 }
 
@@ -2922,7 +2850,7 @@ sub PrepareItemrecordDisplay {
             # loop through each subfield
             my $cntsubf;
             foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
-                next if ( subfield_is_koha_internal_p($subfield) );
+                next if IsMarcStructureInternal($tagslib->{$tag}{$subfield});
                 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
                 my %subfield_data;
                 $subfield_data{tag}           = $tag;
@@ -3023,13 +2951,12 @@ sub PrepareItemrecordDisplay {
 
                         #----- itemtypes
                     } elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
-                        my $sth = $dbh->prepare( "SELECT itemtype,description FROM itemtypes ORDER BY description" );
-                        $sth->execute;
+                        my $itemtypes = GetItemTypes( style => 'array' );
                         push @authorised_values, ""
                           unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
-                        while ( my ( $itemtype, $description ) = $sth->fetchrow_array ) {
-                            push @authorised_values, $itemtype;
-                            $authorised_lib{$itemtype} = $description;
+                        for my $itemtype ( @$itemtypes ) {
+                            push @authorised_values, $itemtype->{itemtype};
+                            $authorised_lib{$itemtype->{itemtype}} = $itemtype->{translated_description};
                         }
                         #---- class_sources
                     } elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "cn_source" ) {
@@ -3119,4 +3046,80 @@ sub PrepareItemrecordDisplay {
     };
 }
 
+=head2 biblioitems_columns
+
+  my @columns = C4::Items::biblioitems_columns();
+
+Returns an array of biblioitems' table columns on success,
+and an empty array on failure.
+
+=cut
+
+sub biblioitems_columns {
+    my $rs = Koha::Database->new->schema->resultset('Biblioitem');
+    return $rs->result_source->columns;
+}
+
+sub ToggleNewStatus {
+    my ( $params ) = @_;
+    my @rules = @{ $params->{rules} };
+    my $report_only = $params->{report_only};
+
+    my $dbh = C4::Context->dbh;
+    my @errors;
+    my @item_columns = map { "items.$_" } Koha::Items->columns;
+    my @biblioitem_columns = map { "biblioitems.$_" } C4::Items::biblioitems_columns;
+    my $report;
+    for my $rule ( @rules ) {
+        my $age = $rule->{age};
+        my $conditions = $rule->{conditions};
+        my $substitutions = $rule->{substitutions};
+        my @params;
+
+        my $query = q|
+            SELECT items.biblionumber, items.itemnumber
+            FROM items
+            LEFT JOIN biblioitems ON biblioitems.biblionumber = items.biblionumber
+            WHERE 1
+        |;
+        for my $condition ( @$conditions ) {
+            if (
+                 grep {/^$condition->{field}$/} @item_columns
+              or grep {/^$condition->{field}$/} @biblioitem_columns
+            ) {
+                if ( $condition->{value} =~ /\|/ ) {
+                    my @values = split /\|/, $condition->{value};
+                    $query .= qq| AND $condition->{field} IN (|
+                        . join( ',', ('?') x scalar @values )
+                        . q|)|;
+                    push @params, @values;
+                } else {
+                    $query .= qq| AND $condition->{field} = ?|;
+                    push @params, $condition->{value};
+                }
+            }
+        }
+        if ( defined $age ) {
+            $query .= q| AND TO_DAYS(NOW()) - TO_DAYS(dateaccessioned) >= ? |;
+            push @params, $age;
+        }
+        my $sth = $dbh->prepare($query);
+        $sth->execute( @params );
+        while ( my $values = $sth->fetchrow_hashref ) {
+            my $biblionumber = $values->{biblionumber};
+            my $itemnumber = $values->{itemnumber};
+            my $item = C4::Items::GetItem( $itemnumber );
+            for my $substitution ( @$substitutions ) {
+                next unless $substitution->{field};
+                C4::Items::ModItem( {$substitution->{field} => $substitution->{value}}, $biblionumber, $itemnumber )
+                    unless $report_only;
+                push @{ $report->{$itemnumber} }, $substitution;
+            }
+        }
+    }
+
+    return $report;
+}
+
+
 1;