start of svc_acct events, #13202
authormark <mark>
Mon, 29 Aug 2011 20:50:33 +0000 (20:50 +0000)
committermark <mark>
Mon, 29 Aug 2011 20:50:33 +0000 (20:50 +0000)
FS/FS/Cron/bill.pm
FS/FS/cust_event.pm
FS/FS/cust_main.pm
FS/FS/cust_main/Billing.pm
FS/FS/part_event/Action.pm
FS/FS/part_event/Condition.pm
httemplate/search/cust_event.html

index 88fe69b..b318809 100644 (file)
@@ -156,6 +156,15 @@ sub bill {
 #
 #  -l: debugging level
 
+=item bill_where
+
+Internal function.  Returns a WHERE clause to select the set of customers who 
+have actionable packages (no setup date, or bill date in the past, or expire 
+or adjourn dates in the past) or events (does a complete where_conditions_sql 
+scan).
+
+=cut
+
 sub bill_where {
   my( %opt ) = @_;
 
@@ -209,12 +218,15 @@ END
   my $where_event = join(' OR ', map {
     my $eventtable = $_;
 
+    # joins and where clauses to test event conditions
     my $join  = FS::part_event_condition->join_conditions_sql(  $eventtable );
     my $where = FS::part_event_condition->where_conditions_sql( $eventtable,
                                                                 'time'=>$time,
                                                               );
     $where = $where ? "AND $where" : '';
 
+    # test to return all applicable part_events (defined on this eventtable,
+    # not disabled, check_freq correct, and all event conditions true)
     my $are_part_event = 
       "EXISTS ( SELECT 1 FROM part_event $join
                   WHERE check_freq = '$check_freq'
@@ -227,8 +239,11 @@ END
     if ( $eventtable eq 'cust_main' ) { 
       $are_part_event;
     } else {
-      "EXISTS ( SELECT 1 FROM $eventtable
-                  WHERE cust_main.custnum = $eventtable.custnum
+      my $cust_join = FS::part_event->eventtables_cust_join->{$eventtable}
+                      || '';
+      my $custnum = FS::part_event->eventtables_custnum->{$eventtable};
+      "EXISTS ( SELECT 1 FROM $eventtable $cust_join
+                  WHERE cust_main.custnum = $custnum
                     AND $are_part_event
               )
       ";
index 1407f43..30dea6e 100644 (file)
@@ -10,6 +10,7 @@ use FS::part_event;
 use FS::cust_main;
 use FS::cust_pkg;
 use FS::cust_bill;
+use FS::svc_acct;
 
 $DEBUG = 0;
 $me = '[FS::cust_event]';
@@ -138,7 +139,7 @@ sub check {
                               $dbdef_eventtable->primary_key
                             )
     || $self->ut_number('_date')
-    || $self->ut_enum('status', [qw( new locked done failed )])
+    || $self->ut_enum('status', [qw( new locked done failed initial)])
     || $self->ut_anything('statustext')
   ;
   return $error if $error;
@@ -190,6 +191,11 @@ sub test_conditions {
   my $object = $self->cust_X;
   my @conditions = $part_event->part_event_condition;
   $opt{'cust_event'} = $self;
+  $opt{'time'} = $self->_date
+      or die "test_conditions called without cust_event._date\n";
+    # this MUST be set, or all hell breaks loose in event conditions.
+    # it MUST be in the same time as in the cust_event object, or
+    # future time-dependent events will trigger incorrectly.
 
   #no unsatisfied conditions
   #! grep ! $_->condition( $object, %opt ), @conditions;
@@ -212,6 +218,8 @@ Runs the event action.
 
 sub do_event {
   my $self = shift;
+  my %opt = @_; # currently only 'time'
+  my $time = $opt{'time'} || time;
 
   my $part_event = $self->part_event;
 
@@ -242,7 +250,7 @@ sub do_event {
   }
 
   #replace or add myself
-  $self->_date(time);
+  $self->_date($time);
   $self->status($status);
   $self->statustext($statustext);
 
@@ -291,7 +299,7 @@ sub retriable {
   $self->replace($old);
 }
 
-=item join_cust_sql
+=item join_sql
 
 =cut
 
@@ -302,9 +310,13 @@ sub join_sql {
        JOIN part_event USING ( eventpart )
   LEFT JOIN cust_bill ON ( eventtable = 'cust_bill' AND tablenum = invnum  )
   LEFT JOIN cust_pkg  ON ( eventtable = 'cust_pkg'  AND tablenum = pkgnum  )
+
+  LEFT JOIN cust_svc  ON ( eventtable = 'svc_acct'  AND tablenum = svcnum  )
+  LEFT JOIN cust_pkg AS cust_pkg_for_svc ON ( cust_svc.pkgnum = cust_pkg_for_svc.pkgnum )
   LEFT JOIN cust_main ON (    ( eventtable = 'cust_main' AND tablenum = cust_main.custnum )
                            OR ( eventtable = 'cust_bill' AND cust_bill.custnum = cust_main.custnum )
                            OR ( eventtable = 'cust_pkg'  AND cust_pkg.custnum  = cust_main.custnum )
+                           OR ( eventtable = 'svc_acct'  AND cust_pkg_for_svc.custnum  = cust_main.custnum )
                          )
   ";
 
@@ -325,6 +337,8 @@ specified in HASHREF.  Valid parameters are
 
 =item pkgnum
 
+=item svcnum
+
 =item failed
 
 =item beginning
@@ -387,6 +401,11 @@ sub search_sql_where {
                   "tablenum = '$1'";
   }
 
+  if ( $param->{'svcnum'} =~ /^(\d+)$/ ) {
+    push @search, "part_event.eventtable = 'svc_acct'",
+                  "tablenum = '$1'";
+  }
+
   my $where = 'WHERE '. join(' AND ', @search );
 
   join(' AND ', @search );
index 7832eca..3cf0dbf 100644 (file)
@@ -3581,6 +3581,56 @@ sub cust_statement {
       qsearch($opt);
 }
 
+=item svc_x SVCDB [ OPTION => VALUE | EXTRA_QSEARCH_PARAMS_HASHREF ]
+
+Returns all services of type SVCDB (such as 'svc_acct') for this customer.  
+
+Optionally, a list or hashref of additional arguments to the qsearch call can 
+be passed following the SVCDB.
+
+=cut
+
+sub svc_x {
+  my $self = shift;
+  my $svcdb = shift;
+  if ( ! $svcdb =~ /^svc_\w+$/ ) {
+    warn "$me svc_x requires a svcdb";
+    return;
+  }
+  my $opt = ref($_[0]) ? shift : { @_ };
+
+  $opt->{'table'} = $svcdb;
+  $opt->{'addl_from'} = 
+    'LEFT JOIN cust_svc USING (svcnum) LEFT JOIN cust_pkg USING (pkgnum) '.
+    ($opt->{'addl_from'} || '');
+
+  my $custnum = $self->custnum;
+  $custnum =~ /^\d+$/ or die "bad custnum '$custnum'";
+  my $where = "cust_pkg.custnum = $custnum";
+
+  my $extra_sql = $opt->{'extra_sql'} || '';
+  if ( keys %{ $opt->{'hashref'} } ) {
+    $extra_sql = " AND $where $extra_sql";
+  }
+  else {
+    if ( $opt->{'extra_sql'} =~ /^\s*where\s(.*)/si ) {
+      $extra_sql = "WHERE $where AND $1";
+    }
+    else {
+      $extra_sql = "WHERE $where $extra_sql";
+    }
+  }
+  $opt->{'extra_sql'} = $extra_sql;
+
+  qsearch($opt);
+}
+
+# required for use as an eventtable; 
+sub svc_acct {
+  my $self = shift;
+  $self->svc_x('svc_acct', @_);
+}
+
 =item cust_credit
 
 Returns all the credits (see L<FS::cust_credit>) for this customer.
index 0b42109..80bf9cc 100644 (file)
@@ -1447,8 +1447,12 @@ sub retry_realtime {
   my $mine = 
   '( '
    . join ( ' OR ' , map { 
+    my $cust_join = FS::part_event->eventtables_cust_join->{$_} || '';
+    my $custnum = FS::part_event->eventtables_custnum->{$_};
     "( part_event.eventtable = " . dbh->quote($_) 
-    . " AND tablenum IN( SELECT " . dbdef->table($_)->primary_key . " from $_ where custnum = " . dbh->quote( $self->custnum ) . "))" ;
+    . " AND tablenum IN( SELECT " . dbdef->table($_)->primary_key 
+    . " from $_ $cust_join"
+    . " where $custnum = " . dbh->quote( $self->custnum ) . "))" ;
    } FS::part_event->eventtables)
    . ') ';
 
@@ -1608,7 +1612,7 @@ sub do_cust_event {
     #XXX lock event
     
     #re-eval event conditions (a previous event could have changed things)
-    unless ( $cust_event->test_conditions( 'time' => $time ) ) {
+    unless ( $cust_event->test_conditions ) {
       #don't leave stray "new/locked" records around
       my $error = $cust_event->delete;
       return $error if $error;
@@ -1732,45 +1736,45 @@ sub due_cust_event {
 
       @objects = @{ $opt{'objects'} };
 
-    } else {
+    } elsif ( $eventtable eq 'cust_main' ) {
 
-      #my @objects = $self->$eventtable(); # sub cust_main { @{ [ $self ] }; }
-      if ( $eventtable eq 'cust_main' ) {
-        @objects = ( $self );
-      } else {
+      @objects = ( $self );
 
-        my $cm_join =
-          "LEFT JOIN cust_main USING ( custnum )";
-
-        #some false laziness w/Cron::bill bill_where
-
-        my $join  = FS::part_event_condition->join_conditions_sql( $eventtable);
-        my $where = FS::part_event_condition->where_conditions_sql($eventtable,
-                                                           'time'=>$opt{'time'},
-                                                                  );
-        $where = $where ? "AND $where" : '';
-
-        my $are_part_event = 
-          "EXISTS ( SELECT 1 FROM part_event $join
-                      WHERE check_freq = '$check_freq'
-                        AND eventtable = '$eventtable'
-                        AND ( disabled = '' OR disabled IS NULL )
-                        $where
-                  )
-          ";
-        #eofalse
-
-        @objects = $self->$eventtable(
-                     'addl_from' => $cm_join,
-                     'extra_sql' => " AND $are_part_event",
-                   );
-      }
+    } else {
 
-    }
+      my $cm_join = " LEFT JOIN cust_main USING ( custnum )";
+      # linkage not needed here because FS::cust_main->$eventtable will 
+      # already supply it
+
+      #some false laziness w/Cron::bill bill_where
+
+      my $join  = FS::part_event_condition->join_conditions_sql( $eventtable);
+      my $where = FS::part_event_condition->where_conditions_sql($eventtable,
+        'time'=>$opt{'time'},
+      );
+      $where = $where ? "AND $where" : '';
+
+      my $are_part_event = 
+      "EXISTS ( SELECT 1 FROM part_event $join
+        WHERE check_freq = '$check_freq'
+        AND eventtable = '$eventtable'
+        AND ( disabled = '' OR disabled IS NULL )
+        $where
+        )
+      ";
+      #eofalse
+
+      @objects = $self->$eventtable(
+        'addl_from' => $cm_join,
+        'extra_sql' => " AND $are_part_event",
+      );
+    } # if ( !$opt{objects} and $eventtable ne 'cust_main' )
 
     my @e_cust_event = ();
 
-    my $cross = "CROSS JOIN $eventtable";
+    my $linkage = FS::part_event->eventtables_cust_join->{$eventtable} || '';
+
+    my $cross = "CROSS JOIN $eventtable $linkage";
     $cross .= ' LEFT JOIN cust_main USING ( custnum )'
       unless $eventtable eq 'cust_main';
 
@@ -1818,7 +1822,9 @@ sub due_cust_event {
              " possible events found for $eventtable ". $object->$pkey(). "\n";
       }
 
-      push @e_cust_event, map { $_->new_cust_event($object) } @part_event;
+      push @e_cust_event, map { 
+        $_->new_cust_event($object, 'time' => $opt{'time'}) 
+      } @part_event;
 
     }
 
@@ -1852,8 +1858,7 @@ sub due_cust_event {
   
   my %unsat = ();
 
-  @cust_event = grep $_->test_conditions( 'time'          => $opt{'time'},
-                                          'stats_hashref' => \%unsat ),
+  @cust_event = grep $_->test_conditions( 'stats_hashref' => \%unsat ),
                      @cust_event;
 
   warn "  ". scalar(@cust_event). " cust events left satisfying conditions\n"
index 45219a3..094cf7d 100644 (file)
@@ -51,6 +51,7 @@ sub eventtable_hashref {
       'cust_bill'      => 1,
       'cust_pkg'       => 1,
       'cust_pay_batch' => 1,
+      'svc_acct'       => 1,
     };
 }
 
index b624407..5c581b4 100644 (file)
@@ -54,6 +54,7 @@ sub eventtable_hashref {
       'cust_pkg'       => 1,
       'cust_pay_batch' => 1,
       'cust_statement' => 1,
+      'svc_acct'       => 1,
     };
 }
 
index 503f252..deb34b9 100644 (file)
@@ -191,6 +191,7 @@ my $sql_query = {
   'extra_sql' => $where,
   'order_by'  => 'ORDER BY _date ASC',
   'addl_from' => $join,
+  'debug' => 2,
 };
 
 my $count_sql = "SELECT COUNT(*) FROM cust_event $join $where";