MT2116 : Addons to the CSV Export
[koha.git] / offline_circ / process_koc.pl
index d8624f5..a187722 100755 (executable)
@@ -19,7 +19,7 @@
 #
 
 use strict;
-require Exporter;
+use warnings;
 
 use CGI;
 use C4::Output;
@@ -31,6 +31,8 @@ use C4::Accounts;
 use C4::Circulation;
 use C4::Members;
 use C4::Stats;
+use C4::UploadedFile;
+use C4::BackgroundJob;
 
 use Date::Calc qw( Add_Delta_Days Date_to_Days );
 
@@ -45,53 +47,115 @@ my ($template, $loggedinuser, $cookie)
   = get_template_and_user( { template_name => "offline_circ/process_koc.tmpl",
                                query => $query,
                                type => "intranet",
-                               authnotrequired => 1,
-                               debug => 1,
+                               authnotrequired => 0,
+                                flagsrequired   => { circulate => "circulate_remaining_permissions" },
                                });
 
+
+my $fileID=$query->param('uploadedfileid');
+my $runinbackground = $query->param('runinbackground');
+my $completedJobID = $query->param('completedJobID');
+my %cookies = parse CGI::Cookie($cookie);
+my $sessionID = $cookies{'CGISESSID'}->value;
 ## 'Local' globals.
 our $dbh = C4::Context->dbh();
-our @output; ## For storing messages to be displayed to the user
-
-$query::POST_MAX = 1024 * 10000;
-my $file = $query->param("kocfile");
-$file=~m/^.*(\\|\/)(.*)/; # strip the remote path and keep the filename 
-
-my $header_line = <$file>;
-my $file_info   = parse_header_line($header_line);
-if ($file_info->{'Version'} ne $FILE_VERSION) {
-    push( @output, { message => "Warning: This file is version '$file_info->{'Version'}', but I only know how to import version '$FILE_VERSION'. I'll try my best." } );
-}
-
-
-while ( my $line = <$file> ) {
-
-    # my ( $date, $time, $command, @arguments ) = parse_command_line( $line );
-    my $command_line = parse_command_line($line);
-
-    # map command names in the file to subroutine names
-    my %dispatch_table = (
-        issue   => \&kocIssueItem,
-        return  => \&kocReturnItem,
-        payment => \&kocMakePayment,
-    );
+our @output = (); ## For storing messages to be displayed to the user
+
+
+if ($completedJobID) {
+    my $job = C4::BackgroundJob->fetch($sessionID, $completedJobID);
+    my $results = $job->results();
+    $template->param(transactions_loaded => 1);
+    $template->param(messages => $results->{results});
+} elsif ($fileID) {
+    my $uploaded_file = C4::UploadedFile->fetch($sessionID, $fileID);
+    my $fh = $uploaded_file->fh();
+    my @input_lines = <$fh>;
+  
+    my $filename = $uploaded_file->name(); 
+    my $job = undef;
+
+    if ($runinbackground) {
+        my $job_size = scalar(@input_lines);
+        $job = C4::BackgroundJob->new($sessionID, $filename, $ENV{'SCRIPT_NAME'}, $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
+            # fork failed, so exit immediately
+            warn "fork failed while attempting to run $ENV{'SCRIPT_NAME'} as a background job";
+            exit 0;
+        }
+
+        # if we get here, we're a child that has detached
+        # itself from Apache
+
+    }     
+
+    my $header_line = shift @input_lines;
+    my $file_info   = parse_header_line($header_line);
+    if ($file_info->{'Version'} ne $FILE_VERSION) {
+      push( @output, { message => 1,
+      ERROR_file_version => 1,
+      upload_version => $file_info->{'Version'},
+      current_version => $FILE_VERSION
+      } );
+    }
+    
+    
+    my $i = 0;
+    foreach  my $line (@input_lines)  {
+    
+        $i++;
+        my $command_line = parse_command_line($line);
+        
+        # map command names in the file to subroutine names
+        my %dispatch_table = (
+            issue     => \&kocIssueItem,
+            'return'  => \&kocReturnItem,
+            payment   => \&kocMakePayment,
+        );
+
+        # call the right sub name, passing the hashref of command_line to it.
+        if ( exists $dispatch_table{ $command_line->{'command'} } ) {
+            $dispatch_table{ $command_line->{'command'} }->($command_line);
+        } else {
+            warn "unknown command: '$command_line->{command}' not processed";
+        }
+
+        if ($runinbackground) {
+            $job->progress($i);
+        }
+    }
 
-    # call the right sub name, passing the hashref of command_line to it.
-    if ( exists $dispatch_table{ $command_line->{'command'} } ) {
-        $dispatch_table{ $command_line->{'command'} }->($command_line);
+    if ($runinbackground) {
+        $job->finish({ results => \@output }) if defined($job);
     } else {
-        warn "unknown command: '$command_line->{command}' not processed";
+        $template->param(transactions_loaded => 1);
+        $template->param(messages => \@output);
     }
-
 }
 
-$template->param(
-               intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
-               intranetstylesheet => C4::Context->preference("intranetstylesheet"),
-               IntranetNav => C4::Context->preference("IntranetNav"),
-
-                messages => \@output,
-       );
 output_html_with_http_headers $query, $cookie, $template->output;
 
 =head3 parse_header_line
@@ -173,8 +237,9 @@ sub arguments_for_command {
 sub kocIssueItem {
   my $circ = shift;
 
+  $circ->{ 'barcode' } = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && C4::Context->preference('itemBarcodeInputFilter'));
   my $branchcode = C4::Context->userenv->{branch};
-  my $borrower = GetMember( $circ->{ 'cardnumber' }, 'cardnumber' );
+  my $borrower = GetMember( 'cardnumber'=>$circ->{ 'cardnumber' } );
   my $item = GetBiblioFromItemNumber( undef, $circ->{ 'barcode' } );
   my $issue = GetItemIssue( $item->{'itemnumber'} );
 
@@ -200,7 +265,16 @@ sub kocIssueItem {
         $circ->{'date'},               # issuedate
     ) unless ($DEBUG);
 
-      push( @output, { message => "Renewed $item->{ 'title' } ( $item->{ 'barcode' } ) to $borrower->{ 'firstname' } $borrower->{ 'surename' } ( $borrower->{'cardnumber'} ) : $circ->{ 'datetime' }\n" } );
+      push( @output, { renew => 1,
+    title => $item->{ 'title' },
+    biblionumber => $item->{'biblionumber'},
+    barcode => $item->{ 'barcode' },
+    firstname => $borrower->{ 'firstname' },
+    surname => $borrower->{ 'surname' },
+    borrowernumber => $borrower->{'borrowernumber'},
+    cardnumber => $borrower->{'cardnumber'},
+    datetime => $circ->{ 'datetime' }
+    } );
 
     } else {
 #warn "Item issued to a different member.";
@@ -212,7 +286,16 @@ sub kocIssueItem {
       if ( Date_to_Days( $i_y, $i_m, $i_d ) < Date_to_Days( $c_y, $c_m, $c_d ) ) { ## Current issue to a different persion is older than this issue, return and issue.
         my $date_due_object = C4::Dates->new($date_due ,'iso');
         C4::Circulation::AddIssue( $borrower, $circ->{'barcode'}, $date_due_object ) unless ( DEBUG );
-        push( @output, { message => "Issued $item->{ 'title' } ( $item->{ 'barcode' } ) to $borrower->{ 'firstname' } $borrower->{ 'surename' } ( $borrower->{'cardnumber'} ) : $circ->{ 'datetime' }\n" } );
+        push( @output, { issue => 1,
+    title => $item->{ 'title' },
+    biblionumber => $item->{'biblionumber'},
+    barcode => $item->{ 'barcode' },
+    firstname => $borrower->{ 'firstname' },
+    surname => $borrower->{ 'surname' },
+    borrowernumber => $borrower->{'borrowernumber'},
+    cardnumber => $borrower->{'cardnumber'},
+    datetime => $circ->{ 'datetime' }
+    } );
 
       } else { ## Current issue is *newer* than this issue, write a 'returned' issue, as the item is most likely in the hands of someone else now.
 #warn "Current issue to another member is newer. Doing nothing";
@@ -224,31 +307,62 @@ sub kocIssueItem {
   } else { ## Item is not checked out to anyone at the moment, go ahead and issue it
       my $date_due_object = C4::Dates->new($date_due ,'iso');
       C4::Circulation::AddIssue( $borrower, $circ->{'barcode'}, $date_due_object ) unless ( DEBUG );
-    push( @output, { message => "Issued $item->{ 'title' } ( $item->{ 'barcode' } ) to $borrower->{ 'firstname' } $borrower->{ 'surename' } ( $borrower->{'cardnumber'} ) : $circ->{ 'datetime' }\n" } );
-  }  
+    push( @output, { issue => 1,
+    title => $item->{ 'title' },
+    biblionumber => $item->{'biblionumber'},
+    barcode => $item->{ 'barcode' },
+    firstname => $borrower->{ 'firstname' },
+    surname => $borrower->{ 'surname' },
+    borrowernumber => $borrower->{'borrowernumber'},
+    cardnumber => $borrower->{'cardnumber'},
+    datetime =>$circ->{ 'datetime' }
+    } );
+        }  
 }
 
 sub kocReturnItem {
   my ( $circ ) = @_;
+  $circ->{'barcode'} = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && C4::Context->preference('itemBarcodeInputFilter'));
   my $item = GetBiblioFromItemNumber( undef, $circ->{ 'barcode' } );
   #warn( Data::Dumper->Dump( [ $circ, $item ], [ qw( circ item ) ] ) );
   my $borrowernumber = _get_borrowernumber_from_barcode( $circ->{'barcode'} );
-  unless ( $borrowernumber ) {
-      push( @output, { message => "Warning: unable to determine borrower from item ($item->{'barcode'}). Cannot mark returned\n" } );
-  }
-  C4::Circulation::MarkIssueReturned( $borrowernumber,
+  if ( $borrowernumber ) {
+  my $borrower = GetMember( 'borrowernumber' =>$borrowernumber );
+    C4::Circulation::MarkIssueReturned( $borrowernumber,
                                       $item->{'itemnumber'},
                                       undef,
                                       $circ->{'date'} );
   
-  push( @output, { message => "Returned $item->{ 'title' } ( $item->{ 'barcode' } ) From borrower number $borrowernumber : $circ->{ 'datetime' }\n" } ); 
+  push( @output, { return => 1,
+    title => $item->{ 'title' },
+    biblionumber => $item->{'biblionumber'},
+    barcode => $item->{ 'barcode' },
+    borrowernumber => $borrower->{'borrowernumber'},
+    firstname => $borrower->{'firstname'},
+    surname => $borrower->{'surname'},
+    cardnumber => $borrower->{'cardnumber'},
+    datetime => $circ->{ 'datetime' }
+    } ); 
+  } else {
+    push( @output, { ERROR_no_borrower_from_item => 1,
+    badbarcode => $circ->{'barcode'}
+    } );
+  
+  }
+
 }
 
 sub kocMakePayment {
   my ( $circ ) = @_;
-  my $borrower = GetMember( $circ->{ 'cardnumber' }, 'cardnumber' );
+  my $borrower = GetMember( 'cardnumber'=>$circ->{ 'cardnumber' } );
   recordpayment( $borrower->{'borrowernumber'}, $circ->{'amount'} );
-  push( @output, { message => "accepted payment ($circ->{'amount'}) from cardnumber ($circ->{'cardnumber'}), borrower ($borrower->{'borrowernumber'})" } );
+  push( @output, { payment => 1,
+    amount => $circ->{'amount'},
+    firstname => $borrower->{'firstname'},
+    surname => $borrower->{'surname'},
+    cardnumber => $circ->{'cardnumber'},
+    borrower => $borrower->{'borrowernumber'}
+    } );
 }
 
 =head3 _get_borrowernumber_from_barcode