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;