summaryrefslogtreecommitdiff
path: root/FS/FS/Cron/alert_expiration.pm
diff options
context:
space:
mode:
Diffstat (limited to 'FS/FS/Cron/alert_expiration.pm')
-rw-r--r--FS/FS/Cron/alert_expiration.pm177
1 files changed, 177 insertions, 0 deletions
diff --git a/FS/FS/Cron/alert_expiration.pm b/FS/FS/Cron/alert_expiration.pm
new file mode 100644
index 0000000..a9b9da9
--- /dev/null
+++ b/FS/FS/Cron/alert_expiration.pm
@@ -0,0 +1,177 @@
+package FS::Cron::alert_expiration;
+
+use vars qw( @ISA @EXPORT_OK);
+use Exporter;
+use FS::Record qw(qsearch);
+use FS::Conf;
+use FS::cust_main;
+use FS::Misc;
+use Time::Local;
+use Date::Parse qw(str2time);
+
+
+@ISA = qw( Exporter );
+@EXPORT_OK = qw( alert_expiration );
+
+my $warning_time = 30 * 24 * 60 * 60;
+my $urgent_time = 15 * 24 * 60 * 60;
+my $panic_time = 5 * 24 * 60 * 60;
+my $window_time = 24 * 60 * 60;
+
+sub alert_expiration {
+ my $conf = new FS::Conf;
+ my $smtpmachine = $conf->config('smtpmachine');
+
+ my %opt = @_;
+ my ($_date) = $opt{'d'} ? str2time($opt{'d'}) : $^T;
+ $_date += $opt{'y'} * 86400 if $opt{'y'};
+ my ($sec, $min, $hour, $mday, $mon, $year) = (localtime($_date)) [0..5];
+ $mon++;
+
+ my $debug = 0;
+ $debug = 1 if $opt{'v'};
+ $debug = $opt{'l'} if $opt{'l'};
+
+ $FS::cust_main::DEBUG = $debug;
+
+ # Get a list of customers.
+
+ my %limit;
+ $limit{'agentnum'} = $opt{'a'} if $opt{'a'};
+ $limit{'payby'} = $opt{'p'} if $opt{'p'};
+
+ my @customers;
+
+ if(my @custnums = @ARGV) {
+ # We're given an explicit list of custnums, so select those. Then check against
+ # -a and -p to avoid doing anything unexpected.
+ foreach (@custnums) {
+ my $customer = FS::cust_main->by_key($_);
+ if($customer and (!$opt{'a'} or $customer->agentnum == $opt{'a'})
+ and (!$opt{'p'} or $customer->payby eq $opt{'p'}) ) {
+ push @customers, $customer;
+ }
+ }
+ }
+ else { # no @ARGV
+ @customers = qsearch('cust_main', \%limit);
+ }
+ return if(!@customers);
+ foreach my $customer (@customers) {
+ my $paydate = $customer->paydate;
+ next if $paydate =~ /^\s*$/; # skip empty expiration dates
+
+ my $custnum = $customer->custnum;
+ my $first = $customer->first;
+ my $last = $customer->last;
+ my $company = $customer->company;
+ my $payby = $customer->payby;
+ my $payinfo = $customer->payinfo;
+ my $daytime = $customer->daytime;
+ my $night = $customer->night;
+
+ my ($paymonth, $payyear) = $customer->paydate_monthyear;
+ $paymonth--; # localtime() convention
+ $payday = 1; # This is enforced by FS::cust_main::check.
+ my $expire_time;
+ if($payby eq 'CARD' || $payby eq 'DCRD') {
+ # Credit cards expire at the end of the month/year.
+ if($paymonth == 11) {
+ $payyear++;
+ $paymonth = 0;
+ } else {
+ $paymonth++;
+ }
+ $expire_time = timelocal(0,0,0,$payday,$paymonth,$payyear) - 1;
+ }
+ else {
+ $expire_time = timelocal(0,0,0,$payday,$paymonth,$payyear);
+ }
+
+ if (grep { $expire_time < $_date + $_ &&
+ $expire_time > $_date + $_ - $window_time }
+ ($warning_time, $urgent_time, $panic_time) ) {
+ my $agentnum = $customer->agentnum;
+ $mail_sender = $conf->config('invoice_from', $agentnum);
+ $failure_recipient = $conf->config('invoice_from', $agentnum)
+ || 'postmaster';
+
+ my @alerter_template = $conf->config('alerter_template', $agentnum)
+ or die 'cannot load config file alerter_template';
+
+ my $alerter = new Text::Template(TYPE => 'ARRAY',
+ SOURCE => [
+ map "$_\n", @alerter_template
+ ])
+ or die "can't create Text::Template object: $Text::Template::ERROR";
+
+ $alerter->compile()
+ or die "can't compile template: $Text::Template::ERROR";
+
+ my @packages = $customer->ncancelled_pkgs;
+ if(@packages) {
+ my @invoicing_list = $customer->invoicing_list;
+ my @to_addrs = grep { $_ ne 'POST' } @invoicing_list;
+ if(@to_addrs) {
+ # Set up template fields.
+ my %fill_in;
+ $fill_in{$_} = $customer->getfield($_)
+ foreach(qw(first last company));
+ $fill_in{'expdate'} = $expire_time;
+ $fill_in{'company_name'} = $conf->config('company_name', $agentnum);
+ $fill_in{'company_address'} =
+ join("\n",$conf->config('company_address',$agentnum))."\n";
+ if($payby eq 'CARD' || $payby eq 'DCRD') {
+ $fill_in{'payby'} = "credit card (".
+ substr($customer->payinfo, 0, 2) . "xxxxxxxxxx" .
+ substr($payinfo, -4) . ")";
+ }
+ elsif($payby eq 'COMP') {
+ $fill_in{'payby'} = 'complimentary account';
+ }
+ else {
+ $fill_in{'payby'} = 'current method';
+ }
+ # Send it already!
+ my $error = FS::Misc::send_email (
+ from => $mail_sender,
+ to => [ @to_addrs ],
+ subject => 'Billing Arrangement Expiration',
+ body => [ $alerter->fill_in( HASH => \%fill_in ) ],
+ );
+ die "can't send expiration alert: $error"
+ if $error;
+ }
+ else { # if(@to_addrs)
+ push @{$agent_failure_body{$customer->agentnum}},
+ sprintf(qq{%5d %-32.32s %4s %10s %12s %12s},
+ $custnum,
+ $first . " " . $last . " " . $company,
+ $payby,
+ $paydate,
+ $daytime,
+ $night );
+ }
+ } # if(@packages)
+ } # if(expired)
+ } # foreach(@customers)
+
+ # Failure notification
+ foreach my $agentnum (keys %agent_failure_body) {
+ $mail_sender = $conf->config('invoice_from', $agentnum)
+ if($conf->exists('invoice_from', $agentnum));
+ $failure_recipient = $conf->config('invoice_from', $agentnum)
+ if($conf->exists('invoice_from', $agentnum));
+ my $error = FS::Misc::send_email (
+ from => $mail_sender,
+ to => $failure_recipient,
+ subject => 'Unnotified Billing Arrangement Expirations',
+ body => [ @{$agent_failure_body{$agentnum}} ],
+ );
+ die "can't send alerter failure email to $failure_recipient: $error"
+ if $error;
+ }
+
+}
+
+1;