RT# 81961 Repair broken links in POD documentation
[freeside.git] / FS / FS / Cron / upload.pm
index a9094c0..691170a 100644 (file)
@@ -9,6 +9,7 @@ use FS::Record qw( qsearch qsearchs );
 use FS::Conf;
 use FS::queue;
 use FS::agent;
+use FS::Log;
 use FS::Misc qw( send_email ); #for bridgestone
 use FS::upload_target;
 use LWP::UserAgent;
@@ -33,6 +34,8 @@ $me = '[FS::Cron::upload]';
 
 sub upload {
   my %opt = @_;
+  my $log = FS::Log->new('Cron::upload');
+  $log->info('start');
 
   my $debug = 0;
   $debug = 1 if $opt{'v'};
@@ -95,6 +98,32 @@ sub upload {
     }
   } # foreach @agents
 
+  # if there's nothing to do, don't hold up the rest of the process
+  if (!@tasks) {
+    $log->info('finish (nothing to upload)');
+    return '';
+  }
+
+  # wait for any ongoing billing jobs to complete
+  if ($opt{m}) {
+    my $dbh = dbh;
+    my $sql = "SELECT count(*) FROM queue LEFT JOIN cust_main USING(custnum) ".
+    "WHERE queue.job='FS::cust_main::queued_bill' AND status != 'failed'";
+    if (@agents) {
+      $sql .= ' AND cust_main.agentnum IN('.
+        join(',', map {$_->agentnum} @agents).
+        ')';
+    }
+    my $sth = $dbh->prepare($sql) or die $dbh->errstr;
+    while (1) {
+      $sth->execute()
+        or die "Unexpected error executing statement $sql: ". $sth->errstr;
+      last if $sth->fetchrow_arrayref->[0] == 0;
+      warn "Waiting 5min for billing to complete...\n" if $DEBUG;
+      sleep 300;
+    }
+  }
+
   foreach (@tasks) {
 
     my $agentnum = $_->{agentnum};
@@ -119,11 +148,13 @@ sub upload {
     }
 
   }
+  $log->info('finish');
 
 }
 
 sub spool_upload {
   my %opt = @_;
+  my $log = FS::Log->new('spool_upload');
 
   warn "$me spool_upload called\n" if $DEBUG;
   my $conf = new FS::Conf;
@@ -143,6 +174,8 @@ sub spool_upload {
   my $dbh = dbh;
 
   my $agentnum = $opt{agentnum};
+  $log->debug('start', agentnum => $agentnum);
+
   my $agent;
   if ( $agentnum ) {
     $agent = qsearchs( 'agent', { agentnum => $agentnum } )
@@ -160,6 +193,8 @@ sub spool_upload {
     {
       warn "$me neither $dir/$file-header.csv nor ".
            "$dir/$file-detail.csv found\n" if $DEBUG > 1;
+      $log->debug("finish (neither $file-header.csv nor ".
+           "$file-detail.csv found)");
       $dbh->commit or die $dbh->errstr if $oldAutoCommit;
       return;
     }
@@ -170,19 +205,6 @@ sub spool_upload {
     my $username = $opt{username} or die "no username for agent $agentnum\n";
     my $password = $opt{password} or die "no password for agent $agentnum\n";
 
-    # a better way?
-    if ($opt{m}) {
-      my $sql = "SELECT count(*) FROM queue LEFT JOIN cust_main USING(custnum) ".
-        "WHERE queue.job='FS::cust_main::queued_bill' AND cust_main.agentnum = ?";
-      my $sth = $dbh->prepare($sql) or die $dbh->errstr;
-      while (1) {
-        $sth->execute( $agentnum )
-          or die "Unexpected error executing statement $sql: ". $sth->errstr;
-        last if $sth->fetchrow_arrayref->[0];
-        sleep 300;
-      }
-    }
-
     foreach ( qw ( header detail ) ) {
       rename "$dir/$file-$_.csv",
              "$dir/$file-$date-$_.csv";
@@ -252,6 +274,7 @@ sub spool_upload {
 
     unless ( -f "$dir/$file.csv" ) {
       warn "$me $dir/$file.csv not found\n" if $DEBUG > 1;
+      $log->debug("finish ($dir/$file.csv not found)");
       $dbh->commit or die $dbh->errstr if $oldAutoCommit;
       return;
     }
@@ -318,16 +341,24 @@ sub spool_upload {
       system($command) and die "$command failed\n";
 
       my $error = $upload_target->put($zipfile);
-      die $error if $error;
-
-      send_report('bridgestone-confirm_template',
-        {
-          agentnum=> $agentnum,
-          zipfile => $zipfile,
-          prefix  => $prefix,
-          seq     => $seq,
-          rows    => $rows,
+      if ( $error ) {
+        foreach ( qw ( header detail ) ) {
+          rename "$dir/$file-$date-$_.csv",
+                 "$dir/$file-$_.csv";
+          die $error;
         }
+      }
+
+      send_email(
+        prepare_report('bridgestone-confirm_template',
+          {
+            agentnum=> $agentnum,
+            zipfile => $zipfile,
+            prefix  => $prefix,
+            seq     => $seq,
+            rows    => $rows,
+          }
+        )
       );
 
       $seq++;
@@ -370,43 +401,80 @@ sub spool_upload {
       close $reg;
       close $big;
 
+      # zip up all three files for transport
       my $zipfile = "$basename" . '.zip';
       my $command = "cd $dir; zip $zipfile $regfile $bigfile";
       system($command) and die "'$command' failed\n";
-      $upload_target->put("$dir/$zipfile");
 
+      # upload them, unless we're using email, in which case 
+      # the zip file will ride along with the report.  yes, this 
+      # kind of defeats the purpose of the upload_target interface,
+      # but at least we have a place to store the configuration.
+      my $error = '';
+      if ( $upload_target->protocol ne 'email' ) {
+        $error = $upload_target->put("$dir/$zipfile");
+      }
+
+      # create the report
       for (values %sum) {
         $_ = sprintf('%.2f', $_);
       }
 
-      send_report('ics-confirm_template',
+      my %report = prepare_report('ics-confirm_template',
         {
           agentnum  => $agentnum,
           count     => \%count,
           sum       => \%sum,
+          error     => $error,
         }
       );
+      if ( $upload_target->protocol eq 'email' ) {
+        $report{'to'} =
+          join('@', $upload_target->username, $upload_target->hostname);
+        $report{'subject'} = $upload_target->subject;
+        $report{'mimeparts'} = [
+          { Path        => "$dir/$zipfile",
+            Type        => 'application/zip',
+            Encoding    => 'base64',
+            Filename    => $zipfile,
+            Disposition => 'attachment',
+          }
+        ];
+      }
+      $error = send_email(%report);
+
+      if ( $error ) {
+        # put the original spool file back
+        rename "$dir/$file-$date.csv", "$dir/$file.csv";
+        die $error;
+      }
  
-      } else { # not bridgestone or ics
+    } else { # not bridgestone or ics
 
       # this is the usual case
 
       my $error = $upload_target->put("$file-$date.csv");
-      die $error if $error;
+      if ( $error ) {
+        rename "$dir/$file-$date.csv", "$dir/$file.csv";
+        die $error;
+      }
 
     }
 
   } #opt{handling}
 
+  $log->debug('finish', agentnum => $agentnum);
+
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   '';
 
 }
 
-=item send_report CONFIG PARAMS
+=item prepare_report CONFIG PARAMS
 
 Retrieves the config value named CONFIG, parses it as a Text::Template,
-extracts "to" and "subject" headers, and sends it by email.
+extracts "to" and "subject" headers, and returns a hash that can be passed
+to L<FS::Misc/send_email>.
 
 PARAMS is a hashref to be passed to C<fill_in>.  It must contain 
 'agentnum' to look up the per-agent config.
@@ -414,7 +482,8 @@ PARAMS is a hashref to be passed to C<fill_in>.  It must contain
 =cut
 
 # we used it twice, so it's now a subroutine
-sub send_report {
+
+sub prepare_report {
 
   my ($config, $params) = @_;
   my $agentnum = $params->{agentnum};
@@ -437,9 +506,9 @@ sub send_report {
   $head =~ /^to:\s*(.*)$/im;
   my $to = $1;
 
-  send_email(
+  (
     to      => $to,
-    from    => $conf->config('invoice_from', $agentnum),
+    from    => $conf->invoice_from_full($agentnum),
     subject => $subject,
     body    => $body,
   );