From: Mark Wells Date: Tue, 22 May 2012 07:24:30 +0000 (-0700) Subject: non-billco FTP invoice spool upload, #16382 X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=cf0188f03b566ba9ae95294e211ea788ac9b050c non-billco FTP invoice spool upload, #16382 --- diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 2acbf0a89..e9cdafb84 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -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.', diff --git a/FS/FS/Cron/upload.pm b/FS/FS/Cron/upload.pm index dceead6b3..5fe813148 100644 --- a/FS/FS/Cron/upload.pm +++ b/FS/FS/Cron/upload.pm @@ -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; '';