non-billco FTP invoice spool upload, #16382
authorMark Wells <mark@freeside.biz>
Tue, 22 May 2012 07:24:30 +0000 (00:24 -0700)
committerMark Wells <mark@freeside.biz>
Tue, 22 May 2012 07:24:30 +0000 (00:24 -0700)
FS/FS/Conf.pm
FS/FS/Cron/upload.pm

index 2acbf0a..e9cdafb 100644 (file)
@@ -3087,7 +3087,14 @@ and customer address. Include units.',
     'type'        => 'checkbox',
   },
 
-  {
+    {
+    'key'         => 'cust_bill-ftp_spool',
+    'section'     => 'invoicing',
+    'description' => 'Enable FTP upload of the invoice spool during daily processing',
+    'type'        => 'checkbox',
+  },
+
+{
     'key'         => 'svc_acct-usage_suspend',
     'section'     => 'billing',
     'description' => 'Suspends the package an account belongs to when svc_acct.seconds or a bytecount is decremented to 0 or below (accounts with an empty seconds and up|down|totalbytes value are ignored).  Typically used in conjunction with prepaid packages and freeside-sqlradius-radacctd.',
index dceead6..5fe8131 100644 (file)
@@ -39,42 +39,98 @@ sub upload {
 
   warn "$me upload called\n" if $DEBUG;
 
-  my $conf = new FS::Conf;
-  my @agent = grep { $conf->config( 'billco-username', $_->agentnum, 1 ) }
-              grep { $conf->config( 'billco-password', $_->agentnum, 1 ) }
-              qsearch( 'agent', {} );
+  my @tasks;
 
   my $date =  time2str('%Y%m%d%H%M%S', $^T); # more?
 
-  @agent = grep { $_ == $opt{'a'} } @agent if $opt{'a'};
+  my $conf = new FS::Conf;
 
-  foreach my $agent ( @agent ) {
+  my @agents = $opt{'a'} ? FS::agent->by_key($opt{'a'}) : qsearch('agent', {});
+
+  if ( $conf->exists('cust_bill-ftp_spool') ) {
+    my $url = $conf->config('cust_bill-ftpdir');
+    $url = "/$url" unless $url =~ m[^/];
+    $url = 'ftp://' . $conf->config('cust_bill-ftpserver') . $url;
+
+    my $format = $conf->config('cust_bill-ftpformat');
+    my $username = $conf->config('cust_bill-ftpusername');
+    my $password = $conf->config('cust_bill-ftppassword');
+
+    my %task = (
+      'date'      => $date,
+      'l'         => $opt{'l'},
+      'm'         => $opt{'m'},
+      'v'         => $opt{'v'},
+      'username'  => $username,
+      'password'  => $password,
+      'url'       => $url,
+      'format'    => $format,
+    );
+
+    if ( $conf->exists('cust_bill-spoolagent') ) {
+      # then push each agent's spool separately
+      foreach ( @agents ) {
+        push @tasks, { %task, 'agentnum' => $_->agentnum };
+      }
+    }
+    elsif ( $opt{'a'} ) {
+      warn "Per-agent processing, but cust_bill-spoolagent is not enabled.\nSkipped invoice upload.\n";
+    }
+    else {
+      push @tasks, \%task;
+    }
+  }
 
-    my $agentnum = $agent->agentnum;
+  else { #check each agent for billco upload settings
+
+    my %task = (
+      'date'      => $date,
+      'l'         => $opt{'l'},
+      'm'         => $opt{'m'},
+      'v'         => $opt{'v'},
+    );
+
+    foreach (@agents) {
+      my $agentnum = $_->agentnum;
+
+      if ( $conf->config( 'billco-username', $agentnum, 1 ) ) {
+        my $username = $conf->config('billco-username', $agentnum, 1);
+        my $password = $conf->config('billco-password', $agentnum, 1);
+        my $clicode  = $conf->config('billco-clicode',  $agentnum, 1);
+        my $url      = $conf->config('billco-url',      $agentnum);
+        push @tasks, {
+          %task,
+          'agentnum' => $agentnum,
+          'username' => $username,
+          'password' => $password,
+          'url'      => $url,
+          'clicode'  => $clicode,
+          'format'   => 'billco',
+        };
+      }
+    } # foreach @agents
+
+  } #!if cust_bill-ftp_spool
+
+  foreach (@tasks) {
+
+    my $agentnum = $_->{agentnum};
 
     if ( $opt{'m'} ) {
 
       if ( $opt{'r'} ) {
         warn "DRY RUN: would add agent $agentnum for queued upload\n";
       } else {
-
         my $queue = new FS::queue {
-          'job'      => 'FS::Cron::upload::billco_upload',
+          'job'      => 'FS::Cron::upload::spool_upload',
         };
-        my $error = $queue->insert(
-                                    'agentnum' => $agentnum,
-                                    'date'     => $date,
-                                    'l'        => $opt{'l'} || '',
-                                    'm'        => $opt{'m'} || '',
-                                    'v'        => $opt{'v'} || '',
-                                  );
-
+        my $error = $queue->insert( %$_ );
       }
 
     } else {
 
-      eval "&billco_upload( 'agentnum' => $agentnum, 'date' => $date );";
-      warn "billco_upload failed: $@\n"
+      eval { spool_upload(%$_) };
+      warn "spool_upload failed: $@\n"
         if $@;
 
     }
@@ -83,26 +139,21 @@ sub upload {
 
 }
 
-sub billco_upload {
+sub spool_upload {
   my %opt = @_;
 
-  warn "$me billco_upload called\n" if $DEBUG;
+  warn "$me spool_upload called\n" if $DEBUG;
   my $conf = new FS::Conf;
   my $dir = '%%%FREESIDE_EXPORT%%%/export.'. $FS::UID::datasrc. '/cust_bill';
 
   my $agentnum = $opt{agentnum} or die "no agentnum provided\n";
-  my $url      = $conf->config( 'billco-url', $agentnum )
-    or die "no url for agent $agentnum\n";
+  my $url      = $opt{url} or die "no url for agent $agentnum\n";
   $url =~ s/^\s+//; $url =~ s/\s+$//;
-  my $username = $conf->config( 'billco-username', $agentnum, 1 )
-    or die "no username for agent $agentnum\n";
-  my $password = $conf->config( 'billco-password', $agentnum, 1 )
-    or die "no password for agent $agentnum\n";
-  my $clicode  = $conf->config( 'billco-clicode', $agentnum, 1 );
-    #or die "no clicode for agent $agentnum\n";
+
+  my $username = $opt{username} or die "no username for agent $agentnum\n";
+  my $password = $opt{password} or die "no password for agent $agentnum\n";
 
   die "no date provided\n" unless $opt{date};
-  my $zipfile  = "$dir/agentnum$agentnum-$opt{date}.zip";
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -119,82 +170,119 @@ sub billco_upload {
     or die "no such agent: $agentnum";
   $agent->select_for_update; #mutex 
 
-  unless ( -f "$dir/agentnum$agentnum-header.csv" ||
-           -f "$dir/agentnum$agentnum-detail.csv" )
-  {
-    warn "$me neither $dir/agentnum$agentnum-header.csv nor ".
-         "$dir/agentnum$agentnum-detail.csv found\n" if $DEBUG;
-    $dbh->commit or die $dbh->errstr if $oldAutoCommit;
-    return;
-  }
+  if ( $opt{'format'} eq 'billco' ) {
+
+    my $zipfile  = "$dir/agentnum$agentnum-$opt{date}.zip";
 
-  # 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->fetchow_arrayref->[0];
-      sleep 300;
+    unless ( -f "$dir/agentnum$agentnum-header.csv" ||
+             -f "$dir/agentnum$agentnum-detail.csv" )
+    {
+      warn "$me neither $dir/agentnum$agentnum-header.csv nor ".
+           "$dir/agentnum$agentnum-detail.csv found\n" if $DEBUG;
+      $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+      return;
     }
-  }
 
-  foreach ( qw ( header detail ) ) {
-    rename "$dir/agentnum$agentnum-$_.csv",
-           "$dir/agentnum$agentnum-$opt{date}-$_.csv";
-  }
+    # 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/agentnum$agentnum-$_.csv",
+             "$dir/agentnum$agentnum-$opt{date}-$_.csv";
+    }
+
+    my $command = "cd $dir; zip $zipfile ".
+                  "agentnum$agentnum-$opt{date}-header.csv ".
+                  "agentnum$agentnum-$opt{date}-detail.csv";
+
+    system($command) and die "$command failed\n";
 
-  my $command = "cd $dir; zip $zipfile ".
-                "agentnum$agentnum-$opt{date}-header.csv ".
-                "agentnum$agentnum-$opt{date}-detail.csv";
+    unlink "agentnum$agentnum-$opt{date}-header.csv",
+           "agentnum$agentnum-$opt{date}-detail.csv";
 
-  system($command) and die "$command failed\n";
+    if ( $url =~ /^http/i ) {
 
-  unlink "agentnum$agentnum-$opt{date}-header.csv",
-         "agentnum$agentnum-$opt{date}-detail.csv";
+      my $ua = new LWP::UserAgent;
+      my $res = $ua->request( POST( $url,
+                                    'Content_Type' => 'form-data',
+                                    'Content' => [ 'username' => $username,
+                                                   'pass'     => $password,
+                                                   'custid'   => $username,
+                                                   'clicode'  => $opt{clicode},
+                                                   'file1'    => [ $zipfile ],
+                                                 ],
+                                  )
+                            );
 
-  if ( $url =~ /^http/i ) {
+      die "upload failed: ". $res->status_line. "\n"
+        unless $res->is_success;
 
-    my $ua = new LWP::UserAgent;
-    my $res = $ua->request( POST( $url,
-                                  'Content_Type' => 'form-data',
-                                  'Content' => [ 'username' => $username,
-                                                 'pass'     => $password,
-                                                 'custid'   => $username,
-                                                 'clicode'  => $clicode,
-                                                 'file1'    => [ $zipfile ],
-                                               ],
-                                )
-                          );
+    } elsif ( $url =~ /^ftp:\/\/([\w\.]+)(\/.*)$/i ) {
 
-    die "upload failed: ". $res->status_line. "\n"
-      unless $res->is_success;
+      my($hostname, $path) = ($1, $2);
 
-  } elsif ( $url =~ /^ftp:\/\/([\w\.]+)(\/.*)$/i ) {
+      my $ftp = new Net::FTP($hostname)
+        or die "can't connect to $hostname: $@\n";
+      $ftp->login($username, $password)
+        or die "can't login to $hostname: ". $ftp->message."\n";
+      unless ( $ftp->cwd($path) ) {
+        my $msg = "can't cd $path on $hostname: ". $ftp->message. "\n";
+        ( $path eq '/' ) ? warn $msg : die $msg;
+      }
+      $ftp->binary
+        or die "can't set binary mode on $hostname\n";
+
+      $ftp->put($zipfile)
+        or die "can't put $zipfile: ". $ftp->message. "\n";
 
-    my($hostname, $path) = ($1, $2);
+      $ftp->quit;
 
-    my $ftp = new Net::FTP($hostname) #, Passive=>1 )
-      or die "can't connect to $hostname: $@\n";
-    $ftp->login($username, $password)
-      or die "can't login to $hostname: ". $ftp->message."\n";
-    unless ( $ftp->cwd($path) ) {
-      my $msg = "can't cd $path on $hostname: ". $ftp->message. "\n";
-      ( $path eq '/' ) ? warn $msg : die $msg;
+    } else {
+      die "unknown scheme in URL $url\n";
     }
-    $ftp->binary
-      or die "can't set binary mode on $hostname\n";
 
-    $ftp->put($zipfile)
-      or die "can't put $zipfile: ". $ftp->message. "\n";
+  } else { #$opt{format} ne 'billco'
 
-    $ftp->quit;
+    my $date = $opt{date};
+    my $file = $opt{agentnum} ? "agentnum$opt{agentnum}" : 'spool'; #.csv
+    unless ( -f "$dir/$file.csv" ) {
+      warn "$me $dir/$file.csv not found\n" if $DEBUG;
+      $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+      return;
+    }
+    rename "$dir/$file.csv", "$dir/$file-$date.csv";
+
+    #ftp only for now
+    if ( $url =~ m{^ftp://([\w\.]+)(/.*)$}i ) {
+
+      my ($hostname, $path) = ($1, $2);
+      my $ftp = new Net::FTP ($hostname)
+        or die "can't connect to $hostname: $@\n";
+      $ftp->login($username, $password)
+        or die "can't login to $hostname: ".$ftp->message."\n";
+      unless ( $ftp->cwd($path) ) {
+        my $msg = "can't cd $path on $hostname: ".$ftp->message."\n";
+        ( $path eq '/' ) ? warn $msg : die $msg;
+      }
+      chdir($dir);
+      $ftp->put("$file-$date.csv")
+        or die "can't put $file-$date.csv: ".$ftp->message."\n";
+      $ftp->quit;
 
-  } else {
-    die "unknown scheme in URL $url\n";
-  }
+    } else {
+      die "malformed FTP URL $url\n";
+    }
+  } #opt{format}
 
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   '';