RT#37912: Service Provisioning Export for ISPConfig 3 [bug fixes]
[freeside.git] / FS / FS / cust_svc.pm
index 0465580..9d9ecdd 100644 (file)
@@ -3,7 +3,7 @@ use base qw( FS::cust_main_Mixin FS::option_Common ); #FS::Record );
 
 use strict;
 use vars qw( $DEBUG $me $ignore_quantity $conf $ticket_system );
 
 use strict;
 use vars qw( $DEBUG $me $ignore_quantity $conf $ticket_system );
-use Carp;
+use Carp qw(cluck);
 #use Scalar::Util qw( blessed );
 use List::Util qw( max );
 use FS::Conf;
 #use Scalar::Util qw( blessed );
 use List::Util qw( max );
 use FS::Conf;
@@ -16,6 +16,7 @@ use FS::domain_record;
 use FS::part_export;
 use FS::cdr;
 use FS::UI::Web;
 use FS::part_export;
 use FS::cdr;
 use FS::UI::Web;
+use FS::export_cust_svc;
 
 #most FS::svc_ classes are autoloaded in svc_x emthod
 use FS::svc_acct;  #this one is used in the cache stuff
 
 #most FS::svc_ classes are autoloaded in svc_x emthod
 use FS::svc_acct;  #this one is used in the cache stuff
@@ -32,6 +33,15 @@ FS::UID->install_callback( sub {
   $ticket_system = $conf->config('ticket_system')
 });
 
   $ticket_system = $conf->config('ticket_system')
 });
 
+our $cache_enabled = 0;
+
+sub _simplecache {
+  my( $self, $hashref ) = @_;
+  if ( $cache_enabled && $hashref->{'svc'} ) {
+    $self->{'_svcpart'} = FS::part_svc->new($hashref);
+  }
+}
+
 sub _cache {
   my $self = shift;
   my ( $hashref, $cache ) = @_;
 sub _cache {
   my $self = shift;
   my ( $hashref, $cache ) = @_;
@@ -102,6 +112,37 @@ sub table { 'cust_svc'; }
 Adds this service to the database.  If there is an error, returns the error,
 otherwise returns false.
 
 Adds this service to the database.  If there is an error, returns the error,
 otherwise returns false.
 
+=cut
+
+sub insert {
+  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;
+
+  my $error = $self->SUPER::insert;
+
+  #check if this releases a hold (see FS::pkg_svc provision_hold)
+  $error ||= $self->_check_provision_hold;
+
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error if $error
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  ''; #no error
+
+}
+
 =item delete
 
 Deletes this service from the database.  If there is an error, returns the
 =item delete
 
 Deletes this service from the database.  If there is an error, returns the
@@ -129,6 +170,17 @@ sub delete {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
+  # delete associated export_cust_svc
+  foreach my $export_cust_svc (
+    qsearch('export_cust_svc',{ 'svcnum' => $self->svcnum })
+  ) {
+    my $error = $export_cust_svc->delete;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   my $error = $self->SUPER::delete;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
   my $error = $self->SUPER::delete;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
@@ -202,7 +254,7 @@ sub suspend {
   my $svc = qsearchs( $svcdb, { 'svcnum' => $self->svcnum } )
     or return '';
 
   my $svc = qsearchs( $svcdb, { 'svcnum' => $self->svcnum } )
     or return '';
 
-  $error = $svc->suspend;
+  my $error = $svc->suspend;
   return $error if $error;
 
   if ( $opt{labels_arryref} ) {
   return $error if $error;
 
   if ( $opt{labels_arryref} ) {
@@ -428,6 +480,9 @@ sub replace {
     } # if ($svc_x->locationnum)
   } # if this is a location change
 
     } # if ($svc_x->locationnum)
   } # if this is a location change
 
+  #check if this releases a hold (see FS::pkg_svc provision_hold)
+  $error ||= $new->_check_provision_hold;
+
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error if $error
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error if $error
@@ -567,7 +622,11 @@ link_type.
 sub part_svc_link {
   my $self = shift;
   my $agentnum = $self->pkgnum ? $self->cust_pkg->cust_main->agentnum : '';
 sub part_svc_link {
   my $self = shift;
   my $agentnum = $self->pkgnum ? $self->cust_pkg->cust_main->agentnum : '';
-  FS::part_svc_link->by_agentnum($agentnum, src_svcpart=>$self->svcpart, @_);
+  FS::part_svc_link->by_agentnum($agentnum,
+    src_svcpart=>$self->svcpart,
+    disabled   => '',
+    @_
+  );
 }
 
 =item display_svcnum 
 }
 
 =item display_svcnum 
@@ -591,9 +650,9 @@ L<FS::part_svc>).
 
 sub part_svc {
   my $self = shift;
 
 sub part_svc {
   my $self = shift;
-  $self->{'_svcpart'}
-    ? $self->{'_svcpart'}
-    : qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } );
+  return $self->{_svcpart} if $self->{_svcpart};
+  cluck 'cust_svc->part_svc called' if $DEBUG;
+  qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } );
 }
 
 =item cust_pkg
 }
 
 =item cust_pkg
@@ -1171,9 +1230,10 @@ sub smart_search_param {
   my @or = 
       map { my $table = $_;
             my $search_sql = "FS::$table"->search_sql($string);
   my @or = 
       map { my $table = $_;
             my $search_sql = "FS::$table"->search_sql($string);
+            my $addl_from = "FS::$table"->search_sql_addl_from();
 
             "SELECT $table.svcnum AS svcnum, '$table' AS svcdb ".
 
             "SELECT $table.svcnum AS svcnum, '$table' AS svcdb ".
-            "FROM $table WHERE $search_sql";
+            "FROM $table $addl_from WHERE $search_sql";
           }
       FS::part_svc->svc_tables;
 
           }
       FS::part_svc->svc_tables;
 
@@ -1206,6 +1266,35 @@ sub smart_search_param {
   );
 }
 
   );
 }
 
+# If the associated cust_pkg is 'on hold'
+# and the associated pkg_svc has the provision_hold flag
+# and there are no more available_part_svcs on the cust_pkg similarly flagged,
+# then removes hold from pkg
+# returns $error or '' on success,
+# does not indicate if pkg status was changed
+sub _check_provision_hold {
+  my $self = shift;
+
+  # check status of cust_pkg
+  my $cust_pkg = $self->cust_pkg;
+  return '' unless $cust_pkg && $cust_pkg->status eq 'on hold';
+
+  # check flag on this svc
+  # small false laziness with $self->pkg_svc
+  # to avoid looking up cust_pkg twice
+  my $pkg_svc  = qsearchs( 'pkg_svc', {
+    'svcpart' => $self->svcpart,
+    'pkgpart' => $cust_pkg->pkgpart,
+  });
+  return '' unless $pkg_svc->provision_hold;
+
+  # check for any others available with that flag
+  return '' if $cust_pkg->available_part_svc( 'provision_hold' => 1 );
+
+  # conditions met, remove hold
+  return $cust_pkg->unsuspend;
+}
+
 sub _upgrade_data {
   my $class = shift;
 
 sub _upgrade_data {
   my $class = shift;
 
@@ -1236,13 +1325,19 @@ sub _upgrade_data {
     my $svcdb = $cust_svc->part_svc->svcdb;
     $h_search{'hashref'}{'svcnum'} = $svcnum;
     $h_search{'table'} = "h_$svcdb";
     my $svcdb = $cust_svc->part_svc->svcdb;
     $h_search{'hashref'}{'svcnum'} = $svcnum;
     $h_search{'table'} = "h_$svcdb";
-    my $h_svc_x = qsearchs(\%h_search)
-      or next;
-    my $class = "FS::$svcdb";
-    my $new_svc_x = $class->new({ $h_svc_x->hash });
-    my $error = $new_svc_x->insert;
-    warn "error repairing svcnum $svcnum ($svcdb) from history:\n$error\n"
-      if $error;
+    my $h_svc_x = qsearchs(\%h_search);
+    if ( $h_svc_x ) {
+      my $class = "FS::$svcdb";
+      my $new_svc_x = $class->new({ $h_svc_x->hash });
+      my $error = $new_svc_x->insert;
+      warn "error repairing svcnum $svcnum ($svcdb) from history:\n$error\n"
+        if $error;
+    } else {
+      # can't be fixed, so remove the dangling cust_svc to avoid breaking
+      # stuff
+      my $error = $cust_svc->delete;
+      warn "error cleaning up missing svcnum $svcnum ($svcdb):\n$error\n";
+    }
   }
 
   '';
   }
 
   '';