This commit was generated by cvs2svn to compensate for changes in r6252,
[freeside.git] / FS / FS / svc_Common.pm
index 907f35f..787acee 100644 (file)
@@ -1,8 +1,8 @@
 package FS::svc_Common;
 
 use strict;
 package FS::svc_Common;
 
 use strict;
-use vars qw( @ISA $noexport_hack $DEBUG );
-use Carp;
+use vars qw( @ISA $noexport_hack $DEBUG $me );
+use Carp qw( cluck carp croak ); #specify cluck have to specify them all..
 use FS::Record qw( qsearch qsearchs fields dbh );
 use FS::cust_main_Mixin;
 use FS::cust_svc;
 use FS::Record qw( qsearch qsearchs fields dbh );
 use FS::cust_main_Mixin;
 use FS::cust_svc;
@@ -14,7 +14,8 @@ use FS::inventory_class;
 
 @ISA = qw( FS::cust_main_Mixin FS::Record );
 
 
 @ISA = qw( FS::cust_main_Mixin FS::Record );
 
-$DEBUG = 1;
+$me = '[FS::svc_Common]';
+$DEBUG = 0;
 
 =head1 NAME
 
 
 =head1 NAME
 
@@ -35,6 +36,27 @@ inherit from, i.e. FS::svc_acct.  FS::svc_Common inherits from FS::Record.
 
 =over 4
 
 
 =over 4
 
+=item search_sql_field FIELD STRING
+
+Class method which returns an SQL fragment to search for STRING in FIELD.
+
+=cut
+
+sub search_sql_field {
+  my( $class, $field, $string ) = @_;
+  my $table = $class->table;
+  my $q_string = dbh->quote($string);
+  "$table.$field = $q_string";
+}
+
+#fallback for services that don't provide a search... 
+sub search_sql {
+  #my( $class, $string ) = @_;
+  '1 = 0'; #false
+}
+
+=item new
+
 =cut
 
 sub new {
 =cut
 
 sub new {
@@ -106,13 +128,26 @@ sub virtual_fields {
     my %flags = map { $_->columnname, $_->columnflag } (
         qsearch ('part_svc_column', { svcpart => $svcpart } )
       );
     my %flags = map { $_->columnname, $_->columnflag } (
         qsearch ('part_svc_column', { svcpart => $svcpart } )
       );
-    return grep { not ($flags{$_} eq 'X') } @vfields;
+    return grep { not ( defined($flags{$_}) && $flags{$_} eq 'X') } @vfields;
   } else { # Case 3
     return @vfields;
   } 
   return ();
 }
 
   } else { # Case 3
     return @vfields;
   } 
   return ();
 }
 
+=item label
+
+svc_Common provides a fallback label subroutine that just returns the svcnum.
+
+=cut
+
+sub label {
+  my $self = shift;
+  cluck "warning: ". ref($self). " not loaded or missing label method; ".
+        "using svcnum";
+  $self->svcnum;
+}
+
 =item check
 
 Checks the validity of fields in this record.
 =item check
 
 Checks the validity of fields in this record.
@@ -152,18 +187,21 @@ If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
 jobnums), all provisioning jobs will have a dependancy on the supplied
 jobnum(s) (they will not run until the specific job(s) complete(s)).
 
 jobnums), all provisioning jobs will have a dependancy on the supplied
 jobnum(s) (they will not run until the specific job(s) complete(s)).
 
+If I<export_args> is set to an array reference, the referenced list will be
+passed to export commands.
+
 =cut
 
 sub insert {
   my $self = shift;
   my %options = @_;
 =cut
 
 sub insert {
   my $self = shift;
   my %options = @_;
-  warn "FS::svc_Common::insert called with options ".
-     join(', ', map { "$_: $options{$_}" } keys %options ). "\n"
-  if $DEBUG;
+  warn "[$me] insert called with options ".
+       join(', ', map { "$_: $options{$_}" } keys %options ). "\n"
+    if $DEBUG;
 
   my @jobnums = ();
   local $FS::queue::jobnums = \@jobnums;
 
   my @jobnums = ();
   local $FS::queue::jobnums = \@jobnums;
-  warn "FS::svc_Common::insert: set \$FS::queue::jobnums to $FS::queue::jobnums"
+  warn "[$me] insert: set \$FS::queue::jobnums to $FS::queue::jobnums\n"
     if $DEBUG;
   my $objects = $options{'child_objects'} || [];
   my $depend_jobnums = $options{'depend_jobnum'} || [];
     if $DEBUG;
   my $objects = $options{'child_objects'} || [];
   my $depend_jobnums = $options{'depend_jobnum'} || [];
@@ -241,11 +279,13 @@ sub insert {
   #new-style exports!
   unless ( $noexport_hack ) {
 
   #new-style exports!
   unless ( $noexport_hack ) {
 
-    warn "FS::svc_Common::insert: \$FS::queue::jobnums is $FS::queue::jobnums"
+    warn "[$me] insert: \$FS::queue::jobnums is $FS::queue::jobnums\n"
       if $DEBUG;
 
       if $DEBUG;
 
+    my $export_args = $options{'export_args'} || [];
+
     foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
     foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
-      my $error = $part_export->export_insert($self);
+      my $error = $part_export->export_insert($self, @$export_args);
       if ( $error ) {
         $dbh->rollback if $oldAutoCommit;
         return "exporting to ". $part_export->exporttype.
       if ( $error ) {
         $dbh->rollback if $oldAutoCommit;
         return "exporting to ". $part_export->exporttype.
@@ -254,11 +294,11 @@ sub insert {
     }
 
     foreach my $depend_jobnum ( @$depend_jobnums ) {
     }
 
     foreach my $depend_jobnum ( @$depend_jobnums ) {
-      warn "inserting dependancies on supplied job $depend_jobnum\n"
+      warn "[$me] inserting dependancies on supplied job $depend_jobnum\n"
         if $DEBUG;
       foreach my $jobnum ( @jobnums ) {
         my $queue = qsearchs('queue', { 'jobnum' => $jobnum } );
         if $DEBUG;
       foreach my $jobnum ( @jobnums ) {
         my $queue = qsearchs('queue', { 'jobnum' => $jobnum } );
-        warn "inserting dependancy for job $jobnum on $depend_jobnum\n"
+        warn "[$me] inserting dependancy for job $jobnum on $depend_jobnum\n"
           if $DEBUG;
         my $error = $queue->depend_insert($depend_jobnum);
         if ( $error ) {
           if $DEBUG;
         my $error = $queue->depend_insert($depend_jobnum);
         if ( $error ) {
@@ -279,7 +319,7 @@ sub insert {
   '';
 }
 
   '';
 }
 
-=item delete
+=item delete [ , OPTION => VALUE ... ]
 
 Deletes this account from the database.  If there is an error, returns the
 error, otherwise returns false.
 
 Deletes this account from the database.  If there is an error, returns the
 error, otherwise returns false.
@@ -290,7 +330,8 @@ The corresponding FS::cust_svc record will be deleted as well.
 
 sub delete {
   my $self = shift;
 
 sub delete {
   my $self = shift;
-  my $error;
+  my %options = @_;
+  my $export_args = $options{'export_args'} || [];
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -299,35 +340,15 @@ sub delete {
   local $SIG{TSTP} = 'IGNORE';
   local $SIG{PIPE} = 'IGNORE';
 
   local $SIG{TSTP} = 'IGNORE';
   local $SIG{PIPE} = 'IGNORE';
 
-  my $svcnum = $self->svcnum;
-
   my $oldAutoCommit = $FS::UID::AutoCommit;
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
   my $oldAutoCommit = $FS::UID::AutoCommit;
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  $error = $self->SUPER::delete;
-  return $error if $error;
-
-  #new-style exports!
-  unless ( $noexport_hack ) {
-    foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
-      $error = $part_export->export_delete($self);
-      if ( $error ) {
-        $dbh->rollback if $oldAutoCommit;
-        return "exporting to ". $part_export->exporttype.
-               " (transaction rolled back): $error";
-      }
-    }
-  }
-
-  $error = $self->return_inventory;
-  if ( $error ) {
-    $dbh->rollback if $oldAutoCommit;
-    return "error returning inventory: $error";
-  }
-
-  my $cust_svc = $self->cust_svc;
-  $error = $cust_svc->delete;
+  my $error =    $self->SUPER::delete
+              || $self->export('delete', @$export_args)
+             || $self->return_inventory
+             || $self->cust_svc->delete
+  ;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
@@ -347,6 +368,7 @@ otherwise returns false.
 
 sub replace {
   my ($new, $old) = (shift, shift);
 
 sub replace {
   my ($new, $old) = (shift, shift);
+  my %options = @_;
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -359,6 +381,9 @@ sub replace {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
+  # We absolutely have to have an old vs. new record to make this work.
+  $old = $new->replace_old unless defined($old);
+
   my $error = $new->set_auto_inventory;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
   my $error = $new->set_auto_inventory;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
@@ -374,6 +399,8 @@ sub replace {
   #new-style exports!
   unless ( $noexport_hack ) {
 
   #new-style exports!
   unless ( $noexport_hack ) {
 
+    my $export_args = $options{'export_args'} || [];
+
     #not quite false laziness, but same pattern as FS::svc_acct::replace and
     #FS::part_export::sqlradius::_export_replace.  List::Compare or something
     #would be useful but too much of a pain in the ass to deploy
     #not quite false laziness, but same pattern as FS::svc_acct::replace and
     #FS::part_export::sqlradius::_export_replace.  List::Compare or something
     #would be useful but too much of a pain in the ass to deploy
@@ -389,7 +416,7 @@ sub replace {
     foreach my $delete_part_export (
       grep { ! $new_exportnum{$_->exportnum} } @old_part_export
     ) {
     foreach my $delete_part_export (
       grep { ! $new_exportnum{$_->exportnum} } @old_part_export
     ) {
-      my $error = $delete_part_export->export_delete($old);
+      my $error = $delete_part_export->export_delete($old, @$export_args);
       if ( $error ) {
         $dbh->rollback if $oldAutoCommit;
         return "error deleting, export to ". $delete_part_export->exporttype.
       if ( $error ) {
         $dbh->rollback if $oldAutoCommit;
         return "error deleting, export to ". $delete_part_export->exporttype.
@@ -400,7 +427,8 @@ sub replace {
     foreach my $replace_part_export (
       grep { $old_exportnum{$_->exportnum} } @new_part_export
     ) {
     foreach my $replace_part_export (
       grep { $old_exportnum{$_->exportnum} } @new_part_export
     ) {
-      my $error = $replace_part_export->export_replace($new,$old);
+      my $error =
+        $replace_part_export->export_replace( $new, $old, @$export_args);
       if ( $error ) {
         $dbh->rollback if $oldAutoCommit;
         return "error exporting to ". $replace_part_export->exporttype.
       if ( $error ) {
         $dbh->rollback if $oldAutoCommit;
         return "error exporting to ". $replace_part_export->exporttype.
@@ -411,7 +439,7 @@ sub replace {
     foreach my $insert_part_export (
       grep { ! $old_exportnum{$_->exportnum} } @new_part_export
     ) {
     foreach my $insert_part_export (
       grep { ! $old_exportnum{$_->exportnum} } @new_part_export
     ) {
-      my $error = $insert_part_export->export_insert($new);
+      my $error = $insert_part_export->export_insert($new, @$export_args );
       if ( $error ) {
         $dbh->rollback if $oldAutoCommit;
         return "error inserting export to ". $insert_part_export->exporttype.
       if ( $error ) {
         $dbh->rollback if $oldAutoCommit;
         return "error inserting export to ". $insert_part_export->exporttype.
@@ -425,7 +453,6 @@ sub replace {
   '';
 }
 
   '';
 }
 
-
 =item setfixed
 
 Sets any fixed fields for this service (see L<FS::part_svc>).  If there is an
 =item setfixed
 
 Sets any fixed fields for this service (see L<FS::part_svc>).  If there is an
@@ -663,33 +690,9 @@ Runs export_suspend callbacks.
 
 sub suspend {
   my $self = shift;
 
 sub suspend {
   my $self = shift;
-
-  local $SIG{HUP} = 'IGNORE';
-  local $SIG{INT} = 'IGNORE';
-  local $SIG{QUIT} = 'IGNORE';
-  local $SIG{TERM} = 'IGNORE';
-  local $SIG{TSTP} = 'IGNORE';
-  local $SIG{PIPE} = 'IGNORE';
-
-  my $oldAutoCommit = $FS::UID::AutoCommit;
-  local $FS::UID::AutoCommit = 0;
-  my $dbh = dbh;
-
-  #new-style exports!
-  unless ( $noexport_hack ) {
-    foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
-      my $error = $part_export->export_suspend($self);
-      if ( $error ) {
-        $dbh->rollback if $oldAutoCommit;
-        return "error exporting to ". $part_export->exporttype.
-               " (transaction rolled back): $error";
-      }
-    }
-  }
-
-  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
-  '';
-
+  my %options = @_;
+  my $export_args = $options{'export_args'} || [];
+  $self->export('suspend', @$export_args);
 }
 
 =item unsuspend
 }
 
 =item unsuspend
@@ -700,6 +703,21 @@ Runs export_unsuspend callbacks.
 
 sub unsuspend {
   my $self = shift;
 
 sub unsuspend {
   my $self = shift;
+  my %options = @_;
+  my $export_args = $options{'export_args'} || [];
+  $self->export('unsuspend', @$export_args);
+}
+
+=item export HOOK [ EXPORT_ARGS ]
+
+Runs the provided export hook (i.e. "suspend", "unsuspend") for this service.
+
+=cut
+
+sub export {
+  my( $self, $method ) = ( shift, shift );
+
+  $method = "export_$method" unless $method =~ /^export_/;
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -715,10 +733,11 @@ sub unsuspend {
   #new-style exports!
   unless ( $noexport_hack ) {
     foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
   #new-style exports!
   unless ( $noexport_hack ) {
     foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
-      my $error = $part_export->export_unsuspend($self);
+      next unless $part_export->can($method);
+      my $error = $part_export->$method($self, @_);
       if ( $error ) {
         $dbh->rollback if $oldAutoCommit;
       if ( $error ) {
         $dbh->rollback if $oldAutoCommit;
-        return "error exporting to ". $part_export->exporttype.
+        return "error exporting $method event to ". $part_export->exporttype.
                " (transaction rolled back): $error";
       }
     }
                " (transaction rolled back): $error";
       }
     }
@@ -729,11 +748,26 @@ sub unsuspend {
 
 }
 
 
 }
 
+=item overlimit
+
+Sets or retrieves overlimit date.
+
+=cut
+
+sub overlimit {
+  my $self = shift;
+  $self->cust_svc->overlimit(@_);
+}
+
 =item cancel
 
 =item cancel
 
-Stub - returns false (no error) so derived classes don't need to define these
+Stub - returns false (no error) so derived classes don't need to define this
 methods.  Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
 
 methods.  Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
 
+This method is called *before* the deletion step which actually deletes the
+services.  This method should therefore only be used for "pre-deletion"
+cancellation steps, if necessary.
+
 =cut
 
 sub cancel { ''; }
 =cut
 
 sub cancel { ''; }
@@ -768,6 +802,8 @@ sub clone_kludge_unsuspend {
 
 The setfixed method return value.
 
 
 The setfixed method return value.
 
+B<export> method isn't used by insert and replace methods yet.
+
 =head1 SEE ALSO
 
 L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>, schema.html
 =head1 SEE ALSO
 
 L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>, schema.html