summaryrefslogtreecommitdiff
path: root/FS/bin
diff options
context:
space:
mode:
Diffstat (limited to 'FS/bin')
-rwxr-xr-xFS/bin/freeside-daily7
-rw-r--r--FS/bin/freeside-ipifony-download240
-rwxr-xr-xFS/bin/freeside-monthly4
-rw-r--r--FS/bin/freeside-queued8
4 files changed, 256 insertions, 3 deletions
diff --git a/FS/bin/freeside-daily b/FS/bin/freeside-daily
index 8e8ae4ff9..ac93aaf2f 100755
--- a/FS/bin/freeside-daily
+++ b/FS/bin/freeside-daily
@@ -4,6 +4,7 @@ use strict;
use Getopt::Std;
use FS::UID qw(adminsuidsetup);
use FS::Conf;
+use FS::Log;
&untaint_argv; #what it sounds like (eww)
use vars qw(%opt);
@@ -11,6 +12,8 @@ getopts("p:a:d:vl:sy:nmrkg:o", \%opt);
my $user = shift or die &usage;
adminsuidsetup $user;
+my $log = FS::Log->new('daily');
+$log->info('start');
#you can skip this by not having a NetworkMonitoringSystem configured
use FS::Cron::nms_report qw(nms_report);
@@ -74,6 +77,8 @@ unlink <${deldir}.CGItemp*>;
use FS::Cron::backup qw(backup);
backup();
+$log->info('finish');
+
###
# subroutines
###
@@ -138,7 +143,7 @@ the bill and collect methods of a cust_main object. See L<FS::cust_main>.
-l: debugging level
- -m: Experimental multi-process mode uses the job queue for multi-process and/or multi-machine billing.
+ -m: Multi-process mode uses the job queue for multi-process and/or multi-machine billing.
-r: Multi-process mode dry run option
diff --git a/FS/bin/freeside-ipifony-download b/FS/bin/freeside-ipifony-download
new file mode 100644
index 000000000..e893326e2
--- /dev/null
+++ b/FS/bin/freeside-ipifony-download
@@ -0,0 +1,240 @@
+#!/usr/bin/perl
+
+use strict;
+use Getopt::Std;
+use Date::Format qw(time2str);
+use File::Temp qw(tempdir);
+use Net::SFTP::Foreign;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch qsearchs);
+use FS::cust_main;
+use FS::Conf;
+use Text::CSV;
+
+my %opt;
+getopts('va:P:C:', \%opt);
+
+#$Net::SFTP::Foreign::debug = -1;
+sub HELP_MESSAGE { '
+ Usage:
+ freeside-ipifony-download
+ [ -v ]
+ [ -a archivedir ]
+ [ -P port ]
+ [ -C category ]
+ freesideuser sftpuser@hostname[:path]
+' }
+
+my @fields = (
+ 'custnum',
+ 'date_desc',
+ 'quantity',
+ 'amount',
+ 'classname',
+);
+
+my $user = shift or die &HELP_MESSAGE;
+adminsuidsetup $user;
+
+# for statistics
+my $num_charges = 0;
+my $num_errors = 0;
+my $sum_charges = 0;
+# cache classnums
+my %classnum_of;
+
+if ( $opt{a} ) {
+ die "no such directory: $opt{a}\n"
+ unless -d $opt{a};
+ die "archive directory $opt{a} is not writable by the freeside user\n"
+ unless -w $opt{a};
+}
+
+my $categorynum = '';
+if ( $opt{C} ) {
+ # find this category (don't auto-create it, it should exist already)
+ my $category = qsearchs('pkg_category', { categoryname => $opt{C} });
+ if (!defined($category)) {
+ die "Package category '$opt{C}' does not exist.\n";
+ }
+ $categorynum = $category->categorynum;
+}
+
+#my $tmpdir = File::Temp->newdir();
+my $tmpdir = tempdir( CLEANUP => 1 ); #DIR=>somewhere?
+
+my $host = shift
+ or die &HELP_MESSAGE;
+my ($sftpuser, $path);
+$host =~ s/^(.+)\@//;
+$sftpuser = $1 || $ENV{USER};
+$host =~ s/:(.*)//;
+$path = $1;
+
+my $port = 22;
+if ( $opt{P} =~ /^(\d+)$/ ) {
+ $port = $1;
+}
+
+# for now assume SFTP download as the only method
+print STDERR "Connecting to $sftpuser\@$host...\n" if $opt{v};
+
+my $sftp = Net::SFTP::Foreign->new(
+ host => $host,
+ user => $sftpuser,
+ port => $port,
+ # for now we don't support passwords. use authorized_keys.
+ timeout => 30,
+ more => ($opt{v} ? '-v' : ''),
+);
+die "failed to connect to '$sftpuser\@$host'\n(".$sftp->error.")\n"
+ if $sftp->error;
+
+$sftp->setcwd($path) if $path;
+
+my $files = $sftp->ls('.', wanted => qr/\.csv$/, names_only => 1);
+if (!@$files) {
+ print STDERR "No charge files found.\n" if $opt{v};
+ exit(-1);
+}
+FILE: foreach my $filename (@$files) {
+ print STDERR "Retrieving $filename\n" if $opt{v};
+ $sftp->get("$filename", "$tmpdir/$filename");
+ if($sftp->error) {
+ warn "failed to download $filename\n";
+ next FILE;
+ }
+
+ # make sure server archive dir exists
+ if ( !$sftp->stat('Archive') ) {
+ print STDERR "Creating $path/Archive\n" if $opt{v};
+ $sftp->mkdir('Archive');
+ if($sftp->error) {
+ # something is seriously wrong
+ die "failed to create archive directory on server:\n".$sftp->error."\n";
+ }
+ }
+ #move to server archive dir
+ $sftp->rename("$filename", "Archive/$filename");
+ if($sftp->error) {
+ warn "failed to archive $filename on server:\n".$sftp->error."\n";
+ } # process it anyway, I guess/
+
+ #copy to local archive dir
+ if ( $opt{a} ) {
+ print STDERR "Copying $tmpdir/$filename to archive dir $opt{a}\n"
+ if $opt{v};
+ copy("$tmpdir/$filename", $opt{a});
+ warn "failed to copy $tmpdir/$filename to $opt{a}: $!" if $!;
+ }
+
+ open my $fh, "<$tmpdir/$filename";
+ my $header = <$fh>;
+ if ($header !~ /^cust_id/) {
+ warn "warning: $filename has incorrect header row:\n$header\n";
+ # but try anyway
+ }
+ my $csv = Text::CSV->new; # orthodox CSV
+ my %hash;
+ while (my $line = <$fh>) {
+ $csv->parse($line) or do {
+ warn "can't parse $filename: ".$csv->error_input."\n";
+ next FILE;
+ };
+ @hash{@fields} = $csv->fields();
+ my $cust_main = FS::cust_main->by_key($hash{custnum});
+ if (!$cust_main) {
+ warn "customer #$hash{custnum} not found\n";
+ next;
+ }
+ print STDERR "Found customer #$hash{custnum}: ".$cust_main->name."\n"
+ if $opt{v};
+
+ # construct arguments for $cust_main->charge
+ my %opt = (
+ amount => $hash{amount},
+ quantity => $hash{quantity},
+ start_date => $cust_main->next_bill_date,
+ pkg => $hash{date_desc},
+ );
+ if (my $classname = $hash{classname}) {
+ if (!exists($classnum_of{$classname}) ) {
+ # then look it up
+ my $pkg_class = qsearchs('pkg_class', {
+ classname => $classname,
+ categorynum => $categorynum,
+ });
+ if (!defined($pkg_class)) {
+ # then create it
+ $pkg_class = FS::pkg_class->new({
+ classname => $classname,
+ categorynum => $categorynum,
+ });
+ my $error = $pkg_class->insert;
+ die "Error creating package class for product code '$classname':\n".
+ "$error\n"
+ if $error;
+ }
+
+ $classnum_of{$classname} = $pkg_class->classnum;
+ }
+ $opt{classnum} = $classnum_of{$classname};
+ }
+ # XXX what's the tax status of these charges?
+ print STDERR " Charging $hash{amount}\n"
+ if $opt{v};
+ my $error = $cust_main->charge(\%opt);
+ if ($error) {
+ warn "Error creating charge: $error" if $error;
+ $num_errors++;
+ } else {
+ $num_charges++;
+ $sum_charges += $hash{amount};
+ }
+ } #while $line
+ close $fh;
+} #FILE
+
+if ($opt{v}) {
+ print STDERR "
+Finished!
+ Processed files: @$files
+ Created charges: $num_charges
+ Sum of charges: \$".sprintf('%0.2f', $sum_charges)."
+ Errors: $num_errors
+";
+}
+
+=head1 NAME
+
+freeside-eftca-download - Retrieve payment batch responses from EFT Canada.
+
+=head1 SYNOPSIS
+
+ freeside-eftca-download [ -v ] [ -a archivedir ] user
+
+=head1 DESCRIPTION
+
+Command line tool to download returned payment reports from the EFT Canada
+gateway and void the returned payments. Uses the login and password from
+'batchconfig-eft_canada'.
+
+-v: Be verbose.
+
+-a directory: Archive response files in the provided directory.
+
+user: freeside username
+
+=head1 BUGS
+
+You need to manually SFTP to ftp.eftcanada.com from the freeside account
+and accept their key before running this script.
+
+=head1 SEE ALSO
+
+L<FS::pay_batch>
+
+=cut
+
+1;
+
diff --git a/FS/bin/freeside-monthly b/FS/bin/freeside-monthly
index 0d6ea14a2..69502a01d 100755
--- a/FS/bin/freeside-monthly
+++ b/FS/bin/freeside-monthly
@@ -7,7 +7,7 @@ use FS::UID qw(adminsuidsetup);
&untaint_argv; #what it sounds like (eww)
#use vars qw($opt_d $opt_v $opt_p $opt_a $opt_s $opt_y);
use vars qw(%opt);
-getopts("p:a:d:vsy:", \%opt);
+getopts("p:a:d:vsy:m", \%opt);
my $user = shift or die &usage;
adminsuidsetup $user;
@@ -72,6 +72,8 @@ the bill and collect methods of a cust_main object. See L<FS::cust_main>.
-v: enable debugging
+ -m: Experimental multi-process mode (delay upload jobs until billing jobs complete)
+
user: From the mapsecrets file - see config.html from the base documentation
custnum: if one or more customer numbers are specified, only bills those
diff --git a/FS/bin/freeside-queued b/FS/bin/freeside-queued
index 756b699d4..2fd80255e 100644
--- a/FS/bin/freeside-queued
+++ b/FS/bin/freeside-queued
@@ -11,6 +11,7 @@ use FS::Conf;
use FS::Record qw(qsearch);
use FS::queue;
use FS::queue_depend;
+use FS::Log;
# no autoloading for non-FS classes...
use Net::SSH 0.07;
@@ -45,6 +46,7 @@ while ( $@ ) {
}
}
+my $log = FS::Log->new('queue');
logfile( "%%%FREESIDE_LOG%%%/queuelog.". $FS::UID::datasrc );
warn "completing daemonization (detaching))\n" if $DEBUG;
@@ -135,6 +137,8 @@ while (1) {
foreach my $job ( @jobs ) {
+ $log->debug('locking queue job', object => $job);
+
my %hash = $job->hash;
$hash{'status'} = 'locked';
my $ljob = new FS::queue ( \%hash );
@@ -186,7 +190,7 @@ while (1) {
dbh->{'private_profile'} = {} if UNIVERSAL::can(dbh, 'sprintProfile');
#auto-use classes...
- if ( $ljob->job =~ /(FS::(part_export|cust_main|cust_pkg)::\w+)::/
+ if ( $ljob->job =~ /(FS::(part_export|cust_main|cust_pkg|Cron)::\w+)::/
|| $ljob->job =~ /(FS::\w+)::/
)
{
@@ -205,6 +209,8 @@ while (1) {
}
my $eval = "&". $ljob->job. '(@args);';
+ # don't put @args in the log, may expose passwords
+ $log->info('starting job ('.$ljob->job.')');
warn 'running "&'. $ljob->job. '('. join(', ', @args). ")\n" if $DEBUG;
eval $eval; #throw away return value? suppose so
if ( $@ ) {