RT#17599: display cancelled services from history [display unprovisionable services...
authorJonathan Prykop <jonathan@freeside.biz>
Fri, 1 Jul 2016 04:21:17 +0000 (23:21 -0500)
committerJonathan Prykop <jonathan@freeside.biz>
Fri, 1 Jul 2016 04:21:17 +0000 (23:21 -0500)
FS/FS/cust_pkg.pm
httemplate/misc/cancel_pkg.html
httemplate/view/cust_main/packages/services.html
httemplate/view/cust_main/packages/status.html

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;
index c802897..d3ca996 100755 (executable)
 %     foreach my $uncancel_svc (@uncancel_svcs) {
 %       my $uncancel_curr_value = $uncancel_svc->{'uncancel_svcnum'};
 %       my $uncancel_disabled = '';
+%       my $uncancel_postfix = '';
 %       if ($cgi->param('error')) {
-%         $uncancel_curr_value = '' unless grep { $_ == $uncancel_svc->{'_uncancel_svcnum'} } $cgi->param('only_svcnum');
+%         $uncancel_curr_value = '' unless grep { $_ == $uncancel_svc->{'uncancel_svcnum'} } $cgi->param('only_svcnum');
 %       }
 %       unless ($uncancel_svc->{'reprovisionable'}) {
 %         $uncancel_curr_value = '';
 %         $uncancel_disabled = 1;
+%         $uncancel_postfix = '<I>(' . emt('Cannot be reprovisioned') . ')</I>';
 %       }
   <& /elements/tr-checkbox.html,
        'label'  => $uncancel_svc->{'svc'} . ': ' . $uncancel_svc->{'label'},
@@ -73,7 +75,8 @@
        'value'  => $uncancel_svc->{'uncancel_svcnum'},
        'curr_value' => $uncancel_curr_value,
        'disabled'   => $uncancel_disabled,
-       'cell_style' => 'font-weight: normal;'
+       'cell_style' => 'font-weight: normal',
+       'postfix' => $uncancel_postfix,
   &>
 %     }
 %   }
index 352f5ea..a23a4c2 100644 (file)
@@ -110,13 +110,16 @@ function clearhint_search_cust_svc(obj, str) {
 % } #foreach part_svc
 
 % if ($cust_pkg->get('cancel')) {
-%   foreach my $svc (sort { $a->{'svcpart'} <=> $b->{'svcpart'} } 
-%                      $cust_pkg->uncancel_svc_summary('summarize_size' => $opt{'cust_pkg-large_pkg_size'})
+%   foreach my $svc (
+%     $cust_pkg->uncancel_svc_summary('summarize_size' => $opt{'cust_pkg-large_pkg_size'}, 'no_test_reprovision' => 1)
 %   ) {
-%     next unless $svc->{'reprovisionable'};
       <TR>
         <TD ALIGN="right" VALIGN="top"><% $svc->{'svc'} |h %></TD>
-        <TD STYLE="padding-bottom:0px; font-style: italic"><% $svc->{'label'} |h %></TD>
+        <TD STYLE="padding-bottom:0px; font-style: italic">
+        <% $svc->{'num_cust_svc'} 
+           ? $svc->{'num_cust_svc'} . ' ' . emt('services in history') 
+           : (defined($svc->{'label'}) ? $svc->{'label'} : emt('(cannot load svc label)')) |h %>
+        </TD>
       </TR>
 %   }
 % }
index 001c128..97011c3 100644 (file)
@@ -715,6 +715,8 @@ sub pkg_uncancel_link {
              'actionlabel' => emt('Un-cancel'),
              #'color'       =>  #?
              'cust_pkg'    => shift,
+             'width'       => 960,
+             'height'      => 740,
          )
 }