[freeside-commits] branch master updated. 06025b02ef920d4994442477ff43be7d2d6ae89b

Mark Wells mark at 420.am
Tue Aug 27 17:01:18 PDT 2013


The branch, master has been updated
       via  06025b02ef920d4994442477ff43be7d2d6ae89b (commit)
      from  267020ff22d48bb82a02a13525f0e0844ef4d6bd (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 06025b02ef920d4994442477ff43be7d2d6ae89b
Author: Mark Wells <mark at freeside.biz>
Date:   Tue Aug 27 16:59:50 2013 -0700

    send credit card expiration alerts with billing events, #13201

diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index 065fd8c..476d490 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -779,8 +779,8 @@ sub reason_type_options {
 
   {
     'key'         => 'alert_expiration',
-    'section'     => 'notification',
-    'description' => 'Enable alerts about billing method expiration (i.e. expiring credit cards).',
+    'section'     => 'deprecated',
+    'description' => 'Enable alerts about credit card expiration.  This is obsolete and no longer works.',
     'type'        => 'checkbox',
     'per_agent'   => 1,
   },
@@ -795,7 +795,7 @@ sub reason_type_options {
   
   {
     'key'         => 'alerter_msgnum',
-    'section'     => 'notification',
+    'section'     => 'deprecated',
     'description' => 'Template to use for credit card expiration alerts.',
     %msg_template_options,
   },
diff --git a/FS/FS/Cron/alert_expiration.pm b/FS/FS/Cron/alert_expiration.pm
deleted file mode 100644
index 5961e61..0000000
--- a/FS/FS/Cron/alert_expiration.pm
+++ /dev/null
@@ -1,190 +0,0 @@
-package FS::Cron::alert_expiration;
-
-use vars qw( @ISA @EXPORT_OK);
-use Exporter;
-use FS::Record qw(qsearch qsearchs);
-use FS::Conf;
-use FS::cust_main;
-use FS::Misc;
-use Time::Local;
-use Date::Parse qw(str2time);
-
-
- at ISA = qw( Exporter );
- at 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) {
-    next if !($customer->ncancelled_pkgs); # skip inactive 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) ) {
-      # Send an expiration notice.
-      my $agentnum = $customer->agentnum;
-      my $error = '';
-
-      my $msgnum = $conf->config('alerter_msgnum', $agentnum);
-      if ( $msgnum ) { # new hotness
-        my $msg_template = qsearchs('msg_template', { msgnum => $msgnum } );
-        $customer->setfield('expdate', $expire_time);
-        $error = $msg_template->send('cust_main' => $customer,
-                                     'object'    => $customer);
-      }
-      else { #!$msgnum, the hard way
-        $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 @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!
-          $error = FS::Misc::send_email ( 
-            from    =>  $mail_sender,
-            to      =>  [ @to_addrs ],
-            subject =>  'Billing Arrangement Expiration',
-            body    =>  [ $alerter->fill_in( HASH => \%fill_in ) ],
-          );
-      } 
-      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($msgnum)
-    
-# should we die here rather than report failure as below?
-    die "can't send expiration alert: $error"
-      if $error;
-    
-    } # 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;
diff --git a/FS/FS/msg_template.pm b/FS/FS/msg_template.pm
index bef2b4b..4e1f4da 100644
--- a/FS/FS/msg_template.pm
+++ b/FS/FS/msg_template.pm
@@ -732,6 +732,64 @@ sub _upgrade_data {
         $conf->delete($subject, $agentnum) if $subject;
       }
     }
+
+    if ( $conf->exists('alert_expiration', $agentnum) ) {
+      my $msgnum = $conf->exists('alerter_msgnum', $agentnum);
+      my $template = FS::msg_template->by_key($msgnum) if $msgnum;
+      if (!$template) {
+        warn "template for alerter_msgnum $msgnum not found\n";
+        next;
+      }
+      # this is now a set of billing events
+      foreach my $days (30, 15, 5) {
+        my $event = FS::part_event->new({
+            'agentnum'    => $agentnum,
+            'event'       => "Card expiration warning - $days days",
+            'eventtable'  => 'cust_main',
+            'check_freq'  => '1d',
+            'action'      => 'notice',
+            'disabled'    => 'Y', #initialize first
+        });
+        my $error = $event->insert( 'msgnum' => $msgnum );
+        if ($error) {
+          warn "error creating expiration alert event:\n$error\n\n";
+          next;
+        }
+        # make it work like before:
+        # only send each warning once before the card expires,
+        # only warn active customers,
+        # only warn customers with CARD/DCRD,
+        # only warn customers who get email invoices
+        my %conds = (
+          'once_every'          => { 'run_delay' => '30d' },
+          'cust_paydate_within' => { 'within' => $days.'d' },
+          'cust_status'         => { 'status' => { 'active' => 1 } },
+          'payby'               => { 'payby'  => { 'CARD' => 1,
+                                                   'DCRD' => 1, }
+                                   },
+          'message_email'       => {},
+        );
+        foreach (keys %conds) {
+          my $condition = FS::part_event_condition->new({
+              'conditionname' => $_,
+              'eventpart'     => $event->eventpart,
+          });
+          $error = $condition->insert( %{ $conds{$_} });
+          if ( $error ) {
+            warn "error creating expiration alert event:\n$error\n\n";
+            next;
+          }
+        }
+        $error = $event->initialize;
+        if ( $error ) {
+          warn "expiration alert event was created, but not initialized:\n$error\n\n";
+        }
+      } # foreach $days
+      $conf->delete('alerter_msgnum', $agentnum);
+      $conf->delete('alert_expiration', $agentnum);
+
+    } # if alerter_msgnum
+
   }
   foreach my $msg_template ( qsearch('msg_template', {}) ) {
     if ( $msg_template->subject || $msg_template->body ) {
diff --git a/FS/FS/part_event/Condition/cust_paydate_within.pm b/FS/FS/part_event/Condition/cust_paydate_within.pm
index 4808e90..bfe3e84 100644
--- a/FS/FS/part_event/Condition/cust_paydate_within.pm
+++ b/FS/FS/part_event/Condition/cust_paydate_within.pm
@@ -23,7 +23,7 @@ sub eventtable_hashref {
 
 sub option_fields {
   (
-    'within'  =>  { 'label'   => 'Expiration date within',
+    'within'  =>  { 'label'   => 'Credit card will expire within',
                     'type'    => 'freq',
                   },
   );
@@ -32,14 +32,17 @@ sub option_fields {
 sub condition {
   my( $self, $cust_main, %opt ) = @_;
   my $expire_time = $cust_main->paydate_epoch or return 0;
-  $opt{'time'} >= $self->option_age_from('within', $expire_time);
+  $opt{'time'} >= $self->option_age_from('within', $expire_time) and
+  $opt{'time'} <  $expire_time;
 }
 
 sub condition_sql {
   my ($self, $table, %opt) = @_;
   my $expire_time = FS::cust_main->paydate_epoch_sql or return 'true';
-  $opt{'time'} . ' >= ' .  
-    $self->condition_sql_option_age_from('within', $expire_time);
+  ' ( '. $opt{'time'} . ' >= ' .  
+    $self->condition_sql_option_age_from('within', $expire_time) .
+    ' AND ' . $opt{'time'} . ' < ' . $expire_time . ' ) ';
+
 }
 
 1;
diff --git a/FS/bin/freeside-daily b/FS/bin/freeside-daily
index b6ee518..14d797f 100755
--- a/FS/bin/freeside-daily
+++ b/FS/bin/freeside-daily
@@ -38,10 +38,13 @@ upload(%opt);
 use FS::Cron::set_lata_have_usage qw(set_lata_have_usage);
 set_lata_have_usage(%opt);
 
-# Send alerts about upcoming credit card expiration.
-use FS::Cron::alert_expiration qw(alert_expiration);
+# we used to send alerts about upcoming credit card expiration here
 my $conf = new FS::Conf;
-alert_expiration(%opt) if($conf->exists('alert_expiration'));
+if($conf->exists('alert_expiration')) {
+  warn "WARNING: the alert_expiration option is obsolete.  If you ran 
+  freeside-upgrade, it should have configured credit card expiration alerts 
+  as billing events.\n";
+}
 
 #what to do about the below when using -m?  that is the question.
 

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Conf.pm                                     |    6 +-
 FS/FS/Cron/alert_expiration.pm                    |  190 ---------------------
 FS/FS/msg_template.pm                             |   58 +++++++
 FS/FS/part_event/Condition/cust_paydate_within.pm |   11 +-
 FS/bin/freeside-daily                             |    9 +-
 5 files changed, 74 insertions(+), 200 deletions(-)
 delete mode 100644 FS/FS/Cron/alert_expiration.pm




More information about the freeside-commits mailing list