RT#17599: display cancelled services from history [display unprovisionable services...
[freeside.git] / FS / FS / cust_pkg.pm
index e3fb155..4ad9639 100644 (file)
@@ -1133,14 +1133,12 @@ sub cancel_if_expired {
 
 For cancelled cust_pkg, returns a list of new, uninserted FS::svc_X records 
 for services that would be inserted by L</uncancel>.  Returned objects also
-include the field '_uncancel_svcnum' that contains the original svcnum.
+include the field _h_svc_x, which contains the service history object.
+
 Set pkgnum before inserting.
 
 Accepts the following options:
 
-summarize_size - if true, returns empty list if number of potential services is 
-equal to or greater than this
-
 only_svcnum - arrayref of svcnum, only returns objects for these svcnum 
 (and only if they would otherwise be returned by this)
 
@@ -1158,19 +1156,20 @@ sub uncancel_svc_x {
   my($end, $start) = ( $self->get('cancel'), $self->get('cancel') - $fuzz );
   my @h_cust_svc = $self->h_cust_svc( $end, $start );
 
-  return () if $opt{'summarize_size'} and @h_cust_svc >= $opt{'summarize_size'};
-
   my @svc_x;
   foreach my $h_cust_svc (@h_cust_svc) {
     next if $opt{'only_svcnum'} && !(grep { $_ == $h_cust_svc->svcnum } @{$opt{'only_svcnum'}});
+    # filter out services that still exist on this package (ie preserved svcs)
+    # but keep services that have since been provisioned on another package (for informational purposes)
+    next if qsearchs('cust_svc',{ 'svcnum' => $h_cust_svc->svcnum, 'pkgnum' => $self->pkgnum });
     my $h_svc_x = $h_cust_svc->h_svc_x( $end, $start );
-    #next unless $h_svc_x; #should this happen?
+    next unless $h_svc_x; # this probably doesn't happen, but just in case
     (my $table = $h_svc_x->table) =~ s/^h_//;
     require "FS/$table.pm";
     my $class = "FS::$table";
     my $svc_x = $class->new( {
       'svcpart' => $h_cust_svc->svcpart,
-      '_uncancel_svcnum' => $h_cust_svc->svcnum,
+      '_h_svc_x' => $h_svc_x,
       map { $_ => $h_svc_x->get($_) } fields($table)
     } );
 
@@ -1211,18 +1210,22 @@ svc
 
 uncancel_svcnum
 
-label
+label - from history table if not currently calculable, undefined if it can't be loaded
 
 reprovisionable - 1 if test reprovision succeeded, otherwise 0
 
+num_cust_svc - number of svcs for this svcpart, only if summarizing (see below)
+
 Cannot be run from within a transaction.  Performs inserts
 to test the results, and then rolls back the transaction.
 Does not perform exports, so does not catch if export would fail.
 
 Also accepts the following options:
 
-summarize_size - if true, returns empty list if number of potential services is 
-equal to or greater than this
+no_test_reprovision - skip the test inserts (reprovisionable field will not exist)
+
+summarize_size - if true, returns a single summary record for svcparts with at
+least this many svcs, will have key num_cust_svc but not uncancel_svcnum, label or reprovisionable
 
 =cut
 
@@ -1235,23 +1238,45 @@ sub uncancel_svc_summary {
   local $FS::svc_Common::noexport_hack = 1; # very important not to run exports!!!
   local $FS::UID::AutoCommit = 0;
 
+  # sort by svcpart, to check summarize_size
+  my $uncancel_svc_x = {};
+  foreach my $svc_x (sort { $a->{'svcpart'} <=> $b->{'svcpart'} } $self->uncancel_svc_x) {
+    $uncancel_svc_x->{$svc_x->svcpart} = [] unless $uncancel_svc_x->{$svc_x->svcpart};
+    push @{$uncancel_svc_x->{$svc_x->svcpart}}, $svc_x;
+  }
+
   my @out;
-  foreach my $svc_x ($self->uncancel_svc_x(%opt)) {
-    $svc_x->pkgnum($self->pkgnum); # provisioning services on a canceled package, will be rolled back
-    my $part_svc = $svc_x->part_svc;
-    my $out = {
-      'svcpart' => $part_svc->svcpart,
-      'svc'     => $part_svc->svc,
-      'uncancel_svcnum' => $svc_x->get('_uncancel_svcnum'),
-    };
-    if ($svc_x->insert) { # if error inserting
-      $out->{'label'} = "(cannot re-provision)";
-      $out->{'reprovisionable'} = 0;
+  foreach my $svcpart (keys %$uncancel_svc_x) {
+    my @svcpart_svc_x = @{$uncancel_svc_x->{$svcpart}};
+    if ($opt{'summarize_size'} && (@svcpart_svc_x >= $opt{'summarize_size'})) {
+      my $svc_x = $svcpart_svc_x[0]; #grab first one for access to $part_svc
+      my $part_svc = $svc_x->part_svc;
+      push @out, {
+        'svcpart'      => $part_svc->svcpart,
+        'svc'          => $part_svc->svc,
+        'num_cust_svc' => scalar(@svcpart_svc_x),
+      };
     } else {
-      $out->{'label'} = $svc_x->label;
-      $out->{'reprovisionable'} = 1;
+      foreach my $svc_x (@svcpart_svc_x) {
+        my $part_svc = $svc_x->part_svc;
+        my $out = {
+          'svcpart' => $part_svc->svcpart,
+          'svc'     => $part_svc->svc,
+          'uncancel_svcnum' => $svc_x->get('_h_svc_x')->svcnum,
+        };
+        $svc_x->pkgnum($self->pkgnum); # provisioning services on a canceled package, will be rolled back
+        if ($opt{'no_test_reprovision'} or $svc_x->insert) {
+          # avoid possibly fatal errors from missing linked records
+          eval { $out->{'label'} = $svc_x->label };
+          eval { $out->{'label'} = $svc_x->get('_h_svc_x')->label } unless defined($out->{'label'});
+          $out->{'reprovisionable'} = 0 unless $opt{'no_test_reprovision'};
+        } else {
+          $out->{'label'} = $svc_x->label;
+          $out->{'reprovisionable'} = 1;
+        }
+        push @out, $out;
+      }
     }
-    push @out, $out;
   }
 
   dbh->rollback;