add vacation msg retrieval and addition/deletion to self-service API, RT#20896
[freeside.git] / FS / FS / svc_Common.pm
index 7a93bc4..ef37351 100644 (file)
@@ -5,6 +5,8 @@ use vars qw( @ISA $noexport_hack $DEBUG $me
              $overlimit_missing_cust_svc_nonfatal_kludge );
 use Carp qw( cluck carp croak confess ); #specify cluck have to specify them all
 use Scalar::Util qw( blessed );
+use Lingua::EN::Inflect qw( PL_N );
+use FS::Conf;
 use FS::Record qw( qsearch qsearchs fields dbh );
 use FS::cust_main_Mixin;
 use FS::cust_svc;
@@ -13,6 +15,7 @@ use FS::queue;
 use FS::cust_main;
 use FS::inventory_item;
 use FS::inventory_class;
+use FS::NetworkMonitoringSystem;
 
 @ISA = qw( FS::cust_main_Mixin FS::Record );
 
@@ -197,12 +200,13 @@ I<depend_jobnum>.
 If I<jobnum> is set to an array reference, the jobnums of any export jobs will
 be added to the referenced array.
 
-If I<child_objects> is set to an array reference of FS::tablename objects (for
-example, FS::acct_snarf objects), they will have their svcnum field set and
-will be inserted after this record, but before any exports are run.  Each
-element of the array can also optionally be a two-element array reference
-containing the child object and the name of an alternate field to be filled in
-with the newly-inserted svcnum, for example C<[ $svc_forward, 'srcsvc' ]>
+If I<child_objects> is set to an array reference of FS::tablename objects
+(for example, FS::svc_export_machine or FS::acct_snarf objects), they
+will have their svcnum field set and will be inserted after this record,
+but before any exports are run.  Each element of the array can also
+optionally be a two-element array reference containing the child object
+and the name of an alternate field to be filled in with the newly-inserted
+svcnum, for example C<[ $svc_forward, 'srcsvc' ]>
 
 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
@@ -241,6 +245,7 @@ sub insert {
 
   my $svcnum = $self->svcnum;
   my $cust_svc = $svcnum ? qsearchs('cust_svc',{'svcnum'=>$self->svcnum}) : '';
+  my $inserted_cust_svc = 0;
   #unless ( $svcnum ) {
   if ( !$svcnum or !$cust_svc ) {
     $cust_svc = new FS::cust_svc ( {
@@ -254,6 +259,7 @@ sub insert {
       $dbh->rollback if $oldAutoCommit;
       return $error;
     }
+    $inserted_cust_svc  = 1;
     $svcnum = $self->svcnum($cust_svc->svcnum);
   } else {
     #$cust_svc = qsearchs('cust_svc',{'svcnum'=>$self->svcnum});
@@ -272,6 +278,10 @@ sub insert {
               || $self->preinsert_hook
               || $self->SUPER::insert;
   if ( $error ) {
+    if ( $inserted_cust_svc ) {
+      my $derror = $cust_svc->delete;
+      die $derror if $derror;
+    }
     $dbh->rollback if $oldAutoCommit;
     return $error;
   }
@@ -326,6 +336,12 @@ sub insert {
 
   }
 
+  my $nms_ip_error = $self->nms_ip_insert;
+  if ( $nms_ip_error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return "error queuing IP insert: $nms_ip_error";
+  }
+
   if ( exists $options{'jobnums'} ) {
     push @{ $options{'jobnums'} }, @jobnums;
   }
@@ -424,7 +440,16 @@ sub expire {
 Replaces OLD_RECORD with this one.  If there is an error, returns the error,
 otherwise returns false.
 
-Currently available options are: I<export_args> and I<depend_jobnum>.
+Currently available options are: I<child_objects>, I<export_args> and
+I<depend_jobnum>.
+
+If I<child_objects> is set to an array reference of FS::tablename objects
+(for example, FS::svc_export_machine or FS::acct_snarf objects), they
+will have their svcnum field set and will be inserted or replaced after
+this record, but before any exports are run.  Each element of the array
+can also optionally be a two-element array reference containing the
+child object and the name of an alternate field to be filled in with
+the newly-inserted svcnum, for example C<[ $svc_forward, 'srcsvc' ]>
 
 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
@@ -447,6 +472,8 @@ sub replace {
       ? shift
       : { @_ };
 
+  my $objects = $options->{'child_objects'} || [];
+
   my @jobnums = ();
   local $FS::queue::jobnums = \@jobnums;
   warn "[$me] replace: set \$FS::queue::jobnums to $FS::queue::jobnums\n"
@@ -496,6 +523,34 @@ sub replace {
     return $error;
   }
 
+  foreach my $object ( @$objects ) {
+    my($field, $obj);
+    if ( ref($object) eq 'ARRAY' ) {
+      ($obj, $field) = @$object;
+    } else {
+      $obj = $object;
+      $field = 'svcnum';
+    }
+    $obj->$field($new->svcnum);
+
+    my $oldobj = qsearchs( $obj->table, {
+                             $field => $new->svcnum,
+                             map { $_ => $obj->$_ } $obj->_svc_child_partfields,
+                         });
+
+    if ( $oldobj ) {
+      my $pkey = $oldobj->primary_key;
+      $obj->$pkey($oldobj->$pkey);
+      $obj->replace($oldobj);
+    } else {
+      $error = $obj->insert;
+    }
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   #new-style exports!
   unless ( $noexport_hack ) {
 
@@ -836,8 +891,7 @@ sub set_auto_inventory {
         qsearchs('inventory_class', { 'classnum' => $classnum } );
       return "Can't find inventory_class.classnum $classnum"
         unless $inventory_class;
-      return "Out of ". $inventory_class->classname. "s\n"; #Lingua:: BS
-                                                            #for pluralizing
+      return "Out of ". PL_N($inventory_class->classname);
     }
 
     next if $columnflag eq 'M' && $inventory_item->svcnum == $self->svcnum;
@@ -845,31 +899,38 @@ sub set_auto_inventory {
     $self->setfield( $field, $inventory_item->item );
       #if $columnflag eq 'A' && $self->$field() eq '';
 
-    $inventory_item->svcnum( $self->svcnum );
-    my $ierror = $inventory_item->replace();
-    if ( $ierror ) {
-      $dbh->rollback if $oldAutoCommit;
-      return "Error provisioning inventory: $ierror";
-    }
-
     if ( $old && $old->$field() && $old->$field() ne $self->$field() ) {
       my $old_inv = qsearchs({
-        'table'   => 'inventory_item',
-        'hashref' => { 'classnum' => $classnum,
-                       'svcnum'   => $old->svcnum,
-                       'item'     => $old->$field(),
-                     },
+        'table'     => 'inventory_item',
+        'hashref'   => { 'classnum' => $classnum,
+                         'svcnum'   => $old->svcnum,
+                       },
+        'extra_sql' => ' AND '.
+          '( ( svc_field IS NOT NULL AND svc_field = '.$dbh->quote($field).' )'.
+          '  OR ( svc_field IS NULL AND item = '. dbh->quote($old->$field).' )'.
+          ')',
       });
       if ( $old_inv ) {
         $old_inv->svcnum('');
+        $old_inv->svc_field('');
         my $oerror = $old_inv->replace;
         if ( $oerror ) {
           $dbh->rollback if $oldAutoCommit;
           return "Error unprovisioning inventory: $oerror";
         }
+      } else {
+        warn "old inventory_item not found for $field ". $self->$field;
       }
     }
 
+    $inventory_item->svcnum( $self->svcnum );
+    $inventory_item->svc_field( $field );
+    my $ierror = $inventory_item->replace();
+    if ( $ierror ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "Error provisioning inventory: $ierror";
+    }
+
   }
 
  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
@@ -898,6 +959,7 @@ sub return_inventory {
 
   foreach my $inventory_item ( $self->inventory_item ) {
     $inventory_item->svcnum('');
+    $inventory_item->svc_field('');
     my $error = $inventory_item->replace();
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
@@ -988,9 +1050,8 @@ sub export_getsettings {
   my %defaults = ();
   my $error = $self->export('getsettings', \%settings, \%defaults);
   if ( $error ) {
-    #XXX bubble this up better
     warn "error running export_getsetings: $error";
-    return ( {}, {} );
+    return ( { 'error' => $error }, {} );
   }
   ( \%settings, \%defaults );
 }
@@ -1008,13 +1069,35 @@ sub export_getstatus {
   my %hash = ();
   my $error = $self->export('getstatus', \$html, \%hash);
   if ( $error ) {
-    #XXX bubble this up better
     warn "error running export_getstatus: $error";
-    return ( '', {} );
+    return ( '', { 'error' => $error } );
   }
   ( $html, \%hash );
 }
 
+=item export_setstatus
+
+Runs export_setstatus callbacks.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub export_setstatus { shift->_export_setstatus_X('setstatus', @_) }
+sub export_setstatus_listadd { shift->_export_setstatus_X('setstatus_listadd', @_) }
+sub export_setstatus_listdel { shift->_export_setstatus_X('setstatus_listdel', @_) }
+sub export_setstatus_vacationadd { shift->_export_setstatus_X('setstatus_vacationadd', @_) }
+sub export_setstatus_vacationdel { shift->_export_setstatus_X('setstatus_vacationdel', @_) }
+
+sub _export_setstatus_X {
+  my( $self, $method, @args ) = @_;
+  my $error = $self->export($method, @args);
+  if ( $error ) {
+    warn "error running export_$method: $error";
+    return $error;
+  }
+  '';
+}
+
 =item export HOOK [ EXPORT_ARGS ]
 
 Runs the provided export hook (i.e. "suspend", "unsuspend") for this service.
@@ -1170,6 +1253,35 @@ sub getstatus_html {
 
 }
 
+=item nms_ip_insert
+
+=cut
+
+sub nms_ip_insert {
+  my $self = shift;
+  my $conf = new FS::Conf;
+  return '' unless grep { $self->table eq $_ }
+                     $conf->config('nms-auto_add-svc_ips');
+  my $ip_field = $self->table_info->{'ip_field'};
+
+  my $queue = FS::queue->new( {
+                'job'    => 'FS::NetworkMonitoringSystem::queued_add_router',
+                'svcnum' => $self->svcnum,
+  } );
+  $queue->insert( 'FS::NetworkMonitoringSystem',
+                  $self->$ip_field(),
+                  $conf->config('nms-auto_add-community')
+                );
+}
+
+=item nms_delip
+
+=cut
+
+sub nms_ip_delete {
+#XXX not yet implemented
+}
+
 =back
 
 =head1 BUGS