Bug 17600: Standardize our EXPORT_OK
[srvgit] / tools / batchMod.pl
index 83a052b..63e22fc 100755 (executable)
 
 use CGI qw ( -utf8 );
 use Modern::Perl;
-use Try::Tiny;
-
-use C4::Auth;
-use C4::Output;
-use C4::Biblio;
-use C4::Items;
-use C4::Circulation;
+use Try::Tiny qw( catch try );
+
+use C4::Auth qw( get_template_and_user );
+use C4::Output qw( output_html_with_http_headers );
+use C4::Biblio qw(
+    DelBiblio
+    GetAuthorisedValueDesc
+    GetMarcFromKohaField
+    GetMarcStructure
+    IsMarcStructureInternal
+    TransformHtmlToXml
+);
+use C4::Items qw( GetItemsInfo Item2Marc ModItemFromMarc );
+use C4::Circulation qw( LostItem IsItemIssued );
 use C4::Context;
 use C4::Koha;
 use C4::BackgroundJob;
-use C4::ClassSource;
-use C4::Debug;
-use C4::Members;
+use C4::ClassSource qw( GetClassSources GetClassSource );
 use MARC::File::XML;
-use List::MoreUtils qw/uniq/;
+use List::MoreUtils qw( uniq );
 
 use Koha::Database;
 use Koha::Exceptions::Exception;
 use Koha::AuthorisedValues;
 use Koha::Biblios;
-use Koha::DateUtils;
+use Koha::DateUtils qw( dt_from_string );
 use Koha::Items;
 use Koha::ItemTypes;
 use Koha::Patrons;
+use Koha::SearchEngine::Indexer;
 
-my $input = new CGI;
+my $input = CGI->new;
 my $dbh = C4::Context->dbh;
 my $error        = $input->param('error');
 my @itemnumbers  = $input->multi_param('itemnumber');
@@ -54,7 +60,6 @@ my $op           = $input->param('op');
 my $del          = $input->param('del');
 my $del_records  = $input->param('del_records');
 my $completedJobID = $input->param('completedJobID');
-my $runinbackground = $input->param('runinbackground');
 my $src          = $input->param('src');
 my $use_default_values = $input->param('use_default_values');
 my $exclude_from_local_holds_priority = $input->param('exclude_from_local_holds_priority');
@@ -74,7 +79,6 @@ my ($template, $loggedinuser, $cookie)
     = get_template_and_user({template_name => $template_name,
                  query => $input,
                  type => "intranet",
-                 authnotrequired => 0,
                  flagsrequired => $template_flag,
                  });
 
@@ -150,24 +154,9 @@ if ($op eq "action") {
         $template->param( "job_completed" => 1 );
     }
 
-       # Setting the job as done
-       my $job = C4::BackgroundJob->fetch($sessionID, $completedJobID);
-
-       # Calling the template
-        add_saved_job_results_to_template($template, $completedJobID, $items_display_hashref);
-
     } else {
     # While the job is getting done
 
-       # Job size is the number of items we have to process
-       my $job_size = scalar(@itemnumbers);
-       my $job = undef;
-
-       # If we asked for background processing
-       if ($runinbackground) {
-           $job = put_in_background($job_size);
-       }
-
        #initializing values for updates
     my (  $itemtagfield,   $itemtagsubfield) = &GetMarcFromKohaField( "items.itemnumber" );
        if ($values_to_modify){
@@ -186,22 +175,15 @@ if ($op eq "action") {
            }
         }
 
-        my $yesno = Koha::AuthorisedValues->search({category => 'YES_NO'});
-        my $ynhash = {};
-
-        while(my $yn = $yesno->next) {
-            $ynhash->{'av'.$yn->authorised_value} = $yn->lib;
-        }
-
+        my $upd_biblionumbers;
+        my $del_biblionumbers;
         try {
             my $schema = Koha::Database->new->schema;
             $schema->txn_do(
                 sub {
                     # For each item
                     my $i = 1;
-                    my $extra_headers = {};
                     foreach my $itemnumber (@itemnumbers) {
-                        $job->progress($i) if $runinbackground;
                         my $item = Koha::Items->find($itemnumber);
                         next
                           unless $item
@@ -211,6 +193,7 @@ if ($op eq "action") {
                             my $return = $item->safe_delete;
                             if ( ref( $return ) ) {
                                 $deleted_items++;
+                                push @$upd_biblionumbers, $itemdata->{'biblionumber'};
                             }
                             else {
                                 $not_deleted_items++;
@@ -228,9 +211,10 @@ if ($op eq "action") {
                             if ($del_records) {
                                 my $itemscount = Koha::Biblios->find( $itemdata->{'biblionumber'} )->items->count;
                                 if ( $itemscount == 0 ) {
-                                    my $error = DelBiblio( $itemdata->{'biblionumber'} );
+                                    my $error = DelBiblio( $itemdata->{'biblionumber'}, { skip_record_index => 1 } );
                                     unless ($error) {
                                         $deleted_records++;
+                                        push @$del_biblionumbers, $itemdata->{'biblionumber'};
                                         if ( $src eq 'CATALOGUING' ) {
                                             # We are coming catalogue/detail.pl, there were items from a single bib record
                                             $template->param( biblio_deleted => 1 );
@@ -246,8 +230,6 @@ if ($op eq "action") {
                                 $item->exclude_from_local_holds_priority($exclude_from_local_holds_priority)->store;
                                 $modified_holds_priority = 1;
                             }
-                                $extra_headers->{exclude_from_local_holds_priority} = {name => 'Exclude from local holds priority', items => {}} unless defined $extra_headers->{exclude_from_local_holds_priority};
-                                $extra_headers->{exclude_from_local_holds_priority}->{items}->{$item->itemnumber} = $ynhash->{'av'.$item->exclude_from_local_holds_priority};
                             }
                             my $modified = 0;
                             if ( $values_to_modify || $values_to_blank ) {
@@ -299,28 +281,25 @@ if ($op eq "action") {
                                             my $item = ModItemFromMarc(
                                                 $localmarcitem,
                                                 $itemdata->{biblionumber},
-                                                $itemnumber
+                                                $itemnumber,
+                                                { skip_record_index => 1 },
                                             )
                                           )
                                         {
-                                            LostItem( $itemnumber, 'batchmod' )
-                                              if $item->{itemlost}
+                                            LostItem(
+                                                $itemnumber,
+                                                'batchmod',
+                                                undef,
+                                                { skip_record_index => 1 }
+                                            ) if $item->{itemlost}
                                               and not $itemdata->{itemlost};
                                         }
                                     };
+                                    push @$upd_biblionumbers, $itemdata->{'biblionumber'};
                                 }
                             }
-                            if ($runinbackground) {
-                                $modified_items++ if $modified || $modified_holds_priority;
-                                $modified_fields += $modified + $modified_holds_priority;
-                                $job->set(
-                                    {
-                                        modified_items  => $modified_items,
-                                        modified_fields => $modified_fields,
-                                        extra_headers => $extra_headers,
-                                    }
-                                );
-                            }
+                            $modified_items++ if $modified || $modified_holds_priority;
+                            $modified_fields += $modified + $modified_holds_priority;
                         }
                         $i++;
                     }
@@ -337,8 +316,24 @@ if ($op eq "action") {
             }
             die "Something terrible has happened!"
                 if ($_ =~ /Rollback failed/); # Rollback failed
-        }
+        };
+        $upd_biblionumbers = [ uniq @$upd_biblionumbers ]; # Only update each bib once
+
+        # Don't send specialUpdate for records we are going to delete
+        my %del_bib_hash = map{ $_ => undef } @$del_biblionumbers;
+        @$upd_biblionumbers = grep( ! exists( $del_bib_hash{$_} ), @$upd_biblionumbers );
+
+        my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
+        $indexer->index_records( $upd_biblionumbers, 'specialUpdate', "biblioserver", undef ) if @$upd_biblionumbers;
+        $indexer->index_records( $del_biblionumbers, 'recordDelete', "biblioserver", undef ) if @$del_biblionumbers;
     }
+
+    # Calling the template
+    $template->param(
+        modified_items => $modified_items,
+        modified_fields => $modified_fields,
+    );
+
 }
 #
 #-------------------------------------------------------------------------------
@@ -396,7 +391,7 @@ if ($op eq "show"){
     my $max_display_items = $del
         ? C4::Context->preference("MaxItemsToDisplayForBatchDel")
         : C4::Context->preference("MaxItemsToDisplayForBatchMod");
-    $template->param("too_many_items_process" => scalar(@itemnumbers)) if !$del && scalar(@itemnumbers) >= C4::Context->preference("MaxItemsToProcessForBatchMod");
+    $template->param("too_many_items_process" => scalar(@itemnumbers)) if !$del && scalar(@itemnumbers) > C4::Context->preference("MaxItemsToProcessForBatchMod");
     if (scalar(@itemnumbers) <= ( $max_display_items // 1000 ) ) {
         $items_display_hashref=BuildItemsData(@itemnumbers);
     } else {
@@ -431,9 +426,8 @@ foreach my $tag (sort keys %{$tagslib}) {
         next if IsMarcStructureInternal( $tagslib->{$tag}{$subfield} );
         next if (not $allowAllSubfields and $restrictededition && !grep { $tag . '$' . $subfield eq $_ } @subfieldsToAllow );
        next if ($tagslib->{$tag}->{$subfield}->{'tab'} ne "10");
-        # barcode and stocknumber are not meant to be batch-modified
-       next if $tagslib->{$tag}->{$subfield}->{'kohafield'} eq 'items.barcode';
-       next if $tagslib->{$tag}->{$subfield}->{'kohafield'} eq 'items.stocknumber';
+        # barcode is not meant to be batch-modified
+        next if $tagslib->{$tag}->{$subfield}->{'kohafield'} eq 'items.barcode';
        my %subfield_data;
  
        my $index_subfield = int(rand(1000000)); 
@@ -505,7 +499,13 @@ foreach my $tag (sort keys %{$tagslib}) {
       else {
           push @authorised_values, ""; # unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
 
-          my @avs = Koha::AuthorisedValues->search({ category => $tagslib->{$tag}->{$subfield}->{authorised_value}, branchcode => $branch_limit },{order_by=>'lib'});
+          my @avs = Koha::AuthorisedValues->search_with_library_limits(
+              {
+                  category   => $tagslib->{$tag}->{$subfield}->{authorised_value}
+              },
+              { order_by => 'lib' },
+              $branch_limit
+          );
           for my $av ( @avs ) {
               push @authorised_values, $av->authorised_value;
               $authorised_lib{$av->authorised_value} = $av->lib;
@@ -716,13 +716,21 @@ sub BuildItemsData{
       $row_data{holds}        = $row->{holds};
       $row_data{item_holds}   = $row->{item_holds};
       $row_data{item}         = $row->{item};
+      $row_data{safe_to_delete} = $row->{item}->safe_to_delete;
       my $is_on_loan = C4::Circulation::IsItemIssued( $row->{itemnumber} );
       $row_data{onloan} = $is_on_loan ? 1 : 0;
                        push(@item_value_loop,\%row_data);
                }
                my @header_loop=map { { header_value=> $witness{$_}} } @witnesscodessorted;
 
-       return { item_loop        => \@item_value_loop, item_header_loop => \@header_loop };
+    my @cannot_be_deleted = map {
+        $_->{safe_to_delete} == 1 ? () : $_->{item}->barcode
+    } @item_value_loop;
+    return {
+        item_loop        => \@item_value_loop,
+        cannot_be_deleted => \@cannot_be_deleted,
+        item_header_loop => \@header_loop
+    };
 }
 
 #BE WARN : it is not the general case 
@@ -771,75 +779,3 @@ sub find_value {
     }
     return($indicator,$result);
 }
-
-# ----------------------------
-# Background functions
-
-
-sub add_results_to_template {
-    my $template = shift;
-    my $results = shift;
-    $template->param(map { $_ => $results->{$_} } keys %{ $results });
-}
-
-sub add_saved_job_results_to_template {
-    my $template = shift;
-    my $completedJobID = shift;
-    my $items_display_hashref= shift;
-    my $job = C4::BackgroundJob->fetch($sessionID, $completedJobID);
-    my $results = $job->results();
-    add_results_to_template($template, $results);
-
-    my $fields = $job->get("modified_fields");
-    my $items = $job->get("modified_items");
-    my $extra_headers = $job->get("extra_headers");
-
-    foreach my $header (keys %{$extra_headers}) {
-        push @{$items_display_hashref->{item_header_loop}}, {header_value => $extra_headers->{$header}->{name}};
-        foreach my $row (@{$items_display_hashref->{item_loop}}) {
-            push @{$row->{item_value}}, {field => $extra_headers->{$header}->{items}->{$row->{itemnumber}}};
-        }
-    }
-
-    $template->param(
-        modified_items => $items,
-        modified_fields => $fields,
-    );
-}
-
-sub put_in_background {
-    my $job_size = shift;
-
-    my $job = C4::BackgroundJob->new($sessionID, "test", '/cgi-bin/koha/tools/batchMod.pl', $job_size);
-    my $jobID = $job->id();
-
-    # fork off
-    if (my $pid = fork) {
-        # parent
-        # return job ID as JSON
-
-        # prevent parent exiting from
-        # destroying the kid's database handle
-        # FIXME: according to DBI doc, this may not work for Oracle
-        $dbh->{InactiveDestroy}  = 1;
-
-        my $reply = CGI->new("");
-        print $reply->header(-type => 'text/html');
-        print '{"jobID":"' . $jobID . '"}';
-        exit 0;
-    } elsif (defined $pid) {
-        # child
-        # close STDOUT to signal to Apache that
-        # we're now running in the background
-        close STDOUT;
-        close STDERR;
-    } else {
-        # fork failed, so exit immediately
-        warn "fork failed while attempting to run tools/batchMod.pl as a background job";
-        exit 0;
-    }
-    return $job;
-}
-
-
-