RT#40641: unprovisioning preserved cancelled services
authorJonathan Prykop <jonathan@freeside.biz>
Mon, 11 Apr 2016 12:08:02 +0000 (07:08 -0500)
committerJonathan Prykop <jonathan@freeside.biz>
Mon, 11 Apr 2016 12:08:02 +0000 (07:08 -0500)
17 files changed:
FS/FS/part_svc.pm
FS/FS/svc_Common.pm
httemplate/browse/part_svc.cgi
httemplate/elements/tr-cust_svc_cancel.html
httemplate/search/cust_svc.html
httemplate/search/svc_acct.cgi
httemplate/search/svc_broadband.cgi
httemplate/search/svc_circuit.cgi
httemplate/search/svc_dish.cgi
httemplate/search/svc_domain.cgi
httemplate/search/svc_external.cgi
httemplate/search/svc_fiber.html
httemplate/search/svc_forward.cgi
httemplate/search/svc_hardware.cgi
httemplate/search/svc_phone.cgi
httemplate/search/svc_www.cgi
httemplate/view/elements/svc_edit_link.html

index 612c590..621a554 100644 (file)
@@ -590,6 +590,26 @@ sub num_cust_svc {
   $sth->fetchrow_arrayref->[0];
 }
 
+=item num_cust_svc_cancelled
+
+Returns the number of associated customer services that are
+attached to cancelled packages.
+
+=cut
+
+sub num_cust_svc_cancelled {
+  my $self = shift;
+  my $sth = dbh->prepare(
+    "SELECT COUNT(*) FROM cust_svc
+     LEFT JOIN cust_pkg USING ( pkgnum )
+     WHERE svcpart = ?
+     AND cust_pkg.cancel IS NOT NULL"
+  ) or die dbh->errstr;
+  $sth->execute($self->svcpart)
+    or die $sth->errstr;
+  $sth->fetchrow_arrayref->[0];
+}
+
 =item svc_x
 
 Returns a list of associated FS::svc_* records.
index 73658f6..4fd2d0b 100644 (file)
@@ -1385,11 +1385,17 @@ Parameters:
 
 =item order_by
 
+=item cancelled - if true, only returns svcs attached to cancelled pkgs;
+if defined and false, only returns svcs not attached to cancelled packages
+
 =back
 
 =cut
 
-# svc_broadband::search should eventually use this instead
+### Don't call the 'cancelled' option 'Service Status'
+### There is no such thing
+### See cautionary note in httemplate/browse/part_svc.cgi
+
 sub search {
   my ($class, $params) = @_;
 
@@ -1493,6 +1499,14 @@ sub search {
     push @where, "exportnum = $1";
   }
 
+  if ( defined($params->{'cancelled'}) ) {
+    if ($params->{'cancelled'}) {
+      push @where, "cust_pkg.cancel IS NOT NULL";
+    } else {
+      push @where, "cust_pkg.cancel IS NULL";
+    }
+  }
+
 #  # sector and tower
 #  my @where_sector = $class->tower_sector_sql($params);
 #  if ( @where_sector ) {
index 88f8d8d..dee4394 100755 (executable)
@@ -119,9 +119,13 @@ function part_export_areyousure(href) {
       <% $svcdb %></TD>
 
     <TD ROWSPAN=<% $rowspan %> CLASS="grid" BGCOLOR="<% $bgcolor %>">
-      <FONT COLOR="#00CC00"><B><% $num_active_cust_svc{$part_svc->svcpart} %></B></FONT>&nbsp;<% $num_active_cust_svc{$part_svc->svcpart} ? svc_url( 'ahref' => 1, 'm' => $m, 'action' => 'search', 'part_svc' => $part_svc, 'query' => "svcpart=". $part_svc->svcpart ) : '<A NAME="zero">' %>active</A>
-
-% if ( $num_active_cust_svc{$part_svc->svcpart} ) { 
+% my $svcurl_active = svc_url( 'ahref' => 1, 'm' => $m, 'action' => 'search', 'part_svc' => $part_svc, 'query' => "svcpart=". $part_svc->svcpart . "&cancelled=0");
+% my $svcurl_cancel = svc_url( 'ahref' => 1, 'm' => $m, 'action' => 'search', 'part_svc' => $part_svc, 'query' => "svcpart=". $part_svc->svcpart . "&cancelled=1");
+      <FONT COLOR="#00CC00"><B><% $num_cust_svc_active{$part_svc->svcpart} %></B></FONT>&nbsp;<% $num_cust_svc_active{$part_svc->svcpart} ? $svcurl_active : '' %>active<% $num_cust_svc_active{$part_svc->svcpart} ? '</A>' : '' %>
+% if ( $num_cust_svc_cancelled{$part_svc->svcpart} ) { 
+        <BR><FONT COLOR="#FF0000"><B><% $num_cust_svc_cancelled{$part_svc->svcpart} %></B></FONT>&nbsp;<% $svcurl_cancel %>cancelled</A>
+% }
+% if ( $num_cust_svc{$part_svc->svcpart} ) { 
         <BR><FONT SIZE="-1">[ <A HREF="<%$p%>edit/bulk-cust_svc.html?svcpart=<% $part_svc->svcpart %>">change</A> ]</FONT>
 % } 
 
@@ -245,11 +249,25 @@ my @part_svc =
     qsearch('part_svc', \%search );
 my $total = scalar(@part_svc);
 
-my %num_active_cust_svc = map { $_->svcpart => $_->num_cust_svc } @part_svc;
+## The Active/Cancelled distinction is a bit awkward,
+## active currently includes unattached and suspended services,
+## but we've previously referred to EVERY existing cust_svc as "Active",
+## and we don't really want to know numbers by individual package status,
+## so for now the UI will distinguish these as "Active" and "Cancelled",
+## but please let's not go so far as to introduce the idea of "Service Status"
+
+my %num_cust_svc_active;
+my %num_cust_svc_cancelled;
+my %num_cust_svc;
+foreach my $part_svc (@part_svc) {
+  $num_cust_svc{$part_svc->svcpart} = $part_svc->num_cust_svc;
+  $num_cust_svc_cancelled{$part_svc->svcpart} = $part_svc->num_cust_svc_cancelled;
+  $num_cust_svc_active{$part_svc->svcpart} = $num_cust_svc{$part_svc->svcpart} - $num_cust_svc_cancelled{$part_svc->svcpart};
+}
 
 if ( $cgi->param('orderby') eq 'active' ) {
-  @part_svc = sort { $num_active_cust_svc{$b->svcpart} <=>
-                     $num_active_cust_svc{$a->svcpart}     } @part_svc;
+  @part_svc = sort { $num_cust_svc{$b->svcpart} <=>
+                     $num_cust_svc{$a->svcpart}     } @part_svc;
 } elsif ( $cgi->param('orderby') eq 'svc' ) { 
   @part_svc = sort { lc($a->svc) cmp lc($b->svc) } @part_svc;
 }
index 44276ec..52dedd6 100644 (file)
@@ -18,7 +18,14 @@ for use in view/cust_main.
 %   }
   </B></TD>
 </TR>
-%# no action links, the service is canceled
+%# no action links except unprovision, the service is canceled
+% if ( $curuser->access_right('Unprovision customer service') && ! $opt{no_links} ) {
+<TR>
+  <TD COLSPAN="2" ALIGN="right" VALIGN="top" STYLE="padding-bottom:5px; padding-top:0px">
+    <FONT SIZE="-2">(&nbsp;<% $svc_unprovision_link %>&nbsp;)</FONT>
+  </TD>
+</TR>
+% }
 
 <%init>
 my %opt = @_;
@@ -29,4 +36,9 @@ my $part_svc = $opt{'part_svc'} || $cust_svc->part_svc;
 my $cust_pkg = $opt{'cust_pkg'} || $cust_svc->cust_pkg;
 my $svc_x = $cust_svc->svc_x;
 
+my $svc_unprovision_link = 
+  qq!<A HREF="javascript:areyousure('${p}misc/unprovision.cgi?! .
+  $cust_svc->svcnum .
+  qq!', '!.emt('Permanently unprovision and delete this service?').qq!')">!.emt('Unprovision').'</A>';
+
 </%init>
index 3b77043..7000e30 100644 (file)
@@ -1,50 +1,63 @@
 <& elements/search.html,
           'title'       => emt('Service search results'),
-             'name'        => emt('services'),
-             'query'       => $sql_query,
-             'count_query' => $count_query,
-             'redirect'    => $link,
-             'header'      => [ emt('#'),
-                                emt('Service'),
-                                # package?
-                                FS::UI::Web::cust_header(),
-                              ],
-             'fields'      => [ 'svcnum',
-                                sub { 
-                                  #$_[0]->svc. ': '. $_[0]->label;
-                                  my($label, $value, $svcdb) = $_[0]->label;
-                                   my $id = $_[0]->agent_svcid
-                                              ? $_[0]->agent_svcid.': '
-                                              : '';
-                                  "$label: $id$value";
-                                },
-                                # package?
-                                \&FS::UI::Web::cust_fields,
-                              ],
-             'links'       => [ $link,
-                                $link,
-                                # package?
-                                ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
-                                       FS::UI::Web::cust_header()
-                                 ),
-                              ],
-              'align' => 'rl'. FS::UI::Web::cust_aligns(),
-              'color' => [ 
-                           '',
-                           '',
-                           FS::UI::Web::cust_colors(),
-                         ],
-              'style' => [ 
-                           '',
-                           '',
-                           FS::UI::Web::cust_styles(),
-                         ],
+          'name'        => emt('services'),
+          'query'       => $sql_query,
+          'count_query' => $count_query,
+          'redirect'    => $link,
+          'header'      => [ emt('#'),
+                             emt('Service'),
+                             emt('Pkg. Status'),
+                             # package?
+                             FS::UI::Web::cust_header(),
+                           ],
+          'fields'      => [ 'svcnum',
+                             sub { 
+                               #$_[0]->svc. ': '. $_[0]->label;
+                               my($label, $value, $svcdb) = $_[0]->label;
+                               my $id = $_[0]->agent_svcid
+                                      ? $_[0]->agent_svcid.': '
+                                      : '';
+                               "$label: $id$value";
+                             },
+                             sub {
+                               $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_pkg;
+                               $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                             },
+                             # package?
+                             \&FS::UI::Web::cust_fields,
+                           ],
+          'links'       => [ $link,
+                             $link,
+                             '', # pkg status
+                             # package?
+                             ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
+                                 FS::UI::Web::cust_header()
+                             ),
+                           ],
+          'align'       => 'rlr'. FS::UI::Web::cust_aligns(),
+          'color'       => [ 
+                             '',
+                             '',
+                             sub {
+                               my $c = FS::cust_pkg::statuscolors;
+                               $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                             }, # pkg status
+                             FS::UI::Web::cust_colors(),
+                           ],
+          'style'       => [ 
+                             '',
+                             '',
+                             'b', # pkg status
+                             FS::UI::Web::cust_styles(),
+                           ],
 &>
 <%init>
 
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('List services');
 
+my %cust_pkg_cache;
+
 my $sql_query;
 
 my $orderby = 'ORDER BY cust_svc.svcnum'; #has to be ordered by something
@@ -83,6 +96,13 @@ if ( length( $cgi->param('search_svc') ) ) {
   } elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
 
     push @extra_sql, "svcpart = $1";
+    if (defined($cgi->param('cancelled'))) {
+      if ($cgi->param('cancelled')) {
+        push @extra_sql, "cust_pkg.cancel IS NOT NULL";
+      } else {
+        push @extra_sql, "cust_pkg.cancel IS NULL";
+      }
+    }
 
   } else {
     errorpage("No search term specified");
index 58764f8..ef89f01 100755 (executable)
@@ -59,6 +59,8 @@ my $curuser =  $FS::CurrentUser::CurrentUser;
 
 die "access denied" unless $curuser->access_right('List services');
 
+my %cust_pkg_cache;
+
 my $link      = [ "${p}view/svc_acct.cgi?",   'svcnum'  ];
 my $link_cust = sub {
   my $svc_acct = shift;
@@ -130,6 +132,7 @@ for (qw( towernum sectornum )) {
 my $timepermonth = '';
 
 my $orderby = 'ORDER BY svcnum';
+my $addl_from = '';
 if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
 
   $search_hash{'unlinked'} = 1
@@ -281,6 +284,9 @@ if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
 } elsif ( $cgi->param('svcpart') ) {
   $orderby = "ORDER BY uid";
   #$orderby = "ORDER BY svcnum";
+  if ( defined($cgi->param('cancelled')) ) {
+    $search_hash{'cancelled'} = $cgi->param('cancelled') ? 1 : 0;
+  }
 } else {
   $orderby = "ORDER BY uid";
 
@@ -347,6 +353,19 @@ foreach my $pkg_field ( @pkg_fields ) {
   
 }
 
+push @header, emt('Pkg. Status');
+push @fields, sub {
+  $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+  $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status;
+};
+push @links, '';
+$align .= 'r';
+push @color, sub {
+  my $c = FS::cust_pkg::statuscolors;
+  $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+};
+push @style, 'b';
+
 push @header, FS::UI::Web::cust_header($cgi->param('cust_fields'));
 push @fields, \&FS::UI::Web::cust_fields,
 push @links, map { $_ ne 'Cust. Status' ? $link_cust : '' }
@@ -357,6 +376,7 @@ push @style, FS::UI::Web::cust_styles();
 
 $search_hash{'order_by'} = $orderby;
 $search_hash{'where'} = \@extra_sql;
+$search_hash{'addl_from'} = $addl_from;
 
 my $sql_query = FS::svc_acct->search(\%search_hash);
 my $count_query = delete($sql_query->{'count_query'});
index 6bf4f08..ff2538c 100755 (executable)
@@ -10,6 +10,7 @@
                                  'Router',
                                  @tower_header,
                                  'IP Address',
+                                 emt('Pkg. Status'),
                                  FS::UI::Web::cust_header($cgi->param('cust_fields')),
                                ],
               'fields'      => [ 'svcnum',
                                  },
                                  @tower_fields,
                                  'ip_addr',
+                                 sub {
+                                   $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+                                   $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                                 },
                                  \&FS::UI::Web::cust_fields,
                                ],
               'links'       => [ $link,
                                  '', #$link_router,
                                  (map '', @tower_fields),
                                  $link,
+                                 '', # pkg status
                                  ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
                                        FS::UI::Web::cust_header($cgi->param('cust_fields'))
                                  ),
                                ],
-              'align'       => 'rll'.('r' x @tower_fields).'r'.
+              'align'       => 'rll'.('r' x @tower_fields).'rr'.
                                 FS::UI::Web::cust_aligns(),
               'color'       => [ 
                                  '',
                                  '',
                                  (map '', @tower_fields),
                                  '',
+                                 sub {
+                                   my $c = FS::cust_pkg::statuscolors;
+                                   $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                                 }, # pkg status
                                  FS::UI::Web::cust_colors(),
                                ],
               'style'       => [ 
@@ -47,6 +57,7 @@
                                  '',
                                  (map '', @tower_fields),
                                  '',
+                                 'b',
                                  FS::UI::Web::cust_styles(),
                                ],
           
@@ -56,6 +67,8 @@
 die "access denied" unless
   $FS::CurrentUser::CurrentUser->access_right('List services');
 
+my %cust_pkg_cache;
+
 my $conf = new FS::Conf;
 
 my %search_hash;
@@ -68,6 +81,9 @@ if ( $cgi->param('magic') eq 'unlinked' ) {
   foreach (qw(pkgpart routernum towernum sectornum)) {
     $search_hash{$_} = [ $cgi->param($_) ] if $cgi->param($_);
   }
+  if ( defined($cgi->param('cancelled')) ) {
+    $search_hash{'cancelled'} = $cgi->param('cancelled') ? 1 : 0;
+  }
 }
 
 if ( $cgi->param('sortby') =~ /^(\w+)$/ ) {
index 8f05e04..2174734 100644 (file)
@@ -10,6 +10,7 @@
                      'Termination',
                      'Circuit ID',
                      'IP Address',
+                     emt('Pkg. Status'),
                      FS::UI::Web::cust_header($cgi->param('cust_fields')),
                    ],
   'fields'      => [ 'svcnum',
                      'termination',
                      'circuit_id',
                      'ip_addr',
+                     sub {
+                       $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+                       $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                     },
                      \&FS::UI::Web::cust_fields,
                    ],
   'links'       => [ $link,
                      '',
                      $link,
                      $link,
+                     '', # pkg status
                      FS::UI::Web::cust_links($cgi->param('cust_fields')),
                    ],
-  'align'       => 'rlllll'.  FS::UI::Web::cust_aligns(),
+  'align'       => 'rlllllr'.  FS::UI::Web::cust_aligns(),
   'color'       => [ 
                      ('') x 6,
+                     sub {
+                       my $c = FS::cust_pkg::statuscolors;
+                       $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                     }, # pkg status
                      FS::UI::Web::cust_colors(),
                    ],
   'style'       => [ 
                      ('') x 6,
+                     'b',
                      FS::UI::Web::cust_styles(),
                    ],
 
@@ -44,6 +55,8 @@
 die "access denied" unless
   $FS::CurrentUser::CurrentUser->access_right('List services');
 
+my %cust_pkg_cache;
+
 my $conf = new FS::Conf;
 
 my %search_hash;
@@ -56,6 +69,9 @@ if ( $cgi->param('magic') eq 'unlinked' ) {
   foreach (qw(pkgpart routernum towernum sectornum)) {
     $search_hash{$_} = [ $cgi->param($_) ] if $cgi->param($_);
   }
+  if ( defined($cgi->param('cancelled')) ) {
+    $search_hash{'cancelled'} = $cgi->param('cancelled') ? 1 : 0;
+  }
 }
 
 my $query = FS::svc_circuit->search(\%search_hash);
index 1f8cbc3..1e73308 100755 (executable)
@@ -7,31 +7,42 @@
                  'header'      => [ '#',
                                     'Service',
                                     'Account #',
+                                    emt('Pkg. Status'),
                                     FS::UI::Web::cust_header(),
                                   ],
                  'fields'      => [ 'svcnum',
                                     'svc',
                                     'acctnum',
+                                    sub {
+                                      $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+                                      $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                                    },
                                     \&FS::UI::Web::cust_fields,
                                   ],
                  'links'       => [ $link,
                                     $link,
                                     $link,
+                                    '', # pkg status
                                     ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
                                           FS::UI::Web::cust_header()
                                     ),
                                   ],
-                 'align' => 'rll'. FS::UI::Web::cust_aligns(),
+                 'align' => 'rllr'. FS::UI::Web::cust_aligns(),
                  'color' => [ 
                               '',
                               '',
                               '',
+                              sub {
+                                my $c = FS::cust_pkg::statuscolors;
+                                $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                              }, # pkg status
                               FS::UI::Web::cust_colors(),
                             ],
                  'style' => [ 
                               '',
                               '',
                               '',
+                              'b',
                               FS::UI::Web::cust_styles(),
                             ],
              
@@ -41,6 +52,8 @@
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('List services');
 
+my %cust_pkg_cache;
+
 #my $conf = new FS::Conf;
 
 my $orderby = 'ORDER BY svcnum';
@@ -56,6 +69,13 @@ if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
   }
 } elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
   push @extra_sql, "svcpart = $1";
+  if (defined($cgi->param('cancelled'))) {
+    if ($cgi->param('cancelled')) {
+      push @extra_sql, "cust_pkg.cancel IS NOT NULL";
+    } else {
+      push @extra_sql, "cust_pkg.cancel IS NULL";
+    }
+  }
 }
 
 my $addl_from = ' LEFT JOIN cust_svc  USING ( svcnum  ) '.
index 56cfa30..c8fca9f 100755 (executable)
@@ -7,31 +7,42 @@
                  'header'            => [ '#',
                                           'Service',
                                           'Domain',
+                                          emt('Pkg. Status'),
                                           FS::UI::Web::cust_header(),
                                         ],
                  'fields'            => [ 'svcnum',
                                           'svc',
                                           'domain',
+                                          sub {
+                                            $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+                                            $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                                          },
                                           \&FS::UI::Web::cust_fields,
                                         ],
                  'links'             => [ $link,
                                           $link,
                                           $link,
+                                          '', # pkg status
                                           ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
                                                 FS::UI::Web::cust_header()
                                           ),
                                         ],
-                 'align' => 'rll'. FS::UI::Web::cust_aligns(),
+                 'align' => 'rllr'. FS::UI::Web::cust_aligns(),
                  'color' => [ 
                               '',
                               '',
                               '',
+                              sub {
+                                my $c = FS::cust_pkg::statuscolors;
+                                $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                              }, # pkg status
                               FS::UI::Web::cust_colors(),
                             ],
                  'style' => [ 
                               '',
                               '',
                               '',
+                              'b',
                               FS::UI::Web::cust_styles(),
                             ],
               
@@ -41,6 +52,8 @@
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('List services');
 
+my %cust_pkg_cache;
+
 my $conf = new FS::Conf;
 
 my $orderby = 'ORDER BY svcnum';
@@ -58,6 +71,13 @@ if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
 
 } elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
   push @extra_sql, "svcpart = $1";
+  if (defined($cgi->param('cancelled'))) {
+    if ($cgi->param('cancelled')) {
+      push @extra_sql, "cust_pkg.cancel IS NOT NULL";
+    } else {
+      push @extra_sql, "cust_pkg.cancel IS NULL";
+    }
+  }
 } else {
   $cgi->param('domain') =~ /^([\w\-\.]+)$/; 
   $svc_domain{'domain'} = $1;
index b282939..5f90561 100755 (executable)
@@ -8,29 +8,39 @@
                                           'Service',
                                           ( FS::Msgcat::_gettext('svc_external-id') || 'External ID' ),
                                           ( FS::Msgcat::_gettext('svc_external-title') || 'Title' ),
+                                          emt('Pkg. Status'),
                                           FS::UI::Web::cust_header(),
                                         ],
                  'fields'            => [ 'svcnum',
                                           'svc',
                                           'id',
                                           'title',
+                                          sub {
+                                            $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+                                            $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                                          },
                                           \&FS::UI::Web::cust_fields,
                                         ],
                  'links'             => [ $link,
                                           $link,
                                           $link,
                                           $link,
+                                          '', # pkg status
                                           ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
                                                 FS::UI::Web::cust_header()
                                           ),
                                         ],
-                 'align' => 'rlrr'.
+                 'align' => 'rlrrr'.
                             FS::UI::Web::cust_aligns(),
                  'color' => [ 
                               '',
                               '',
                               '',
                               '',
+                              sub {
+                                my $c = FS::cust_pkg::statuscolors;
+                                $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                              }, # pkg status
                               FS::UI::Web::cust_colors(),
                             ],
                  'style' => [ 
@@ -38,6 +48,7 @@
                               '',
                               '',
                               '',
+                              'b',
                               FS::UI::Web::cust_styles(),
                             ],
           
@@ -47,6 +58,8 @@
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('List services');
 
+my %cust_pkg_cache;
+
 my $conf = new FS::Conf;
 
 my %svc_external;
@@ -69,6 +82,13 @@ if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
 } elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
 
   push @extra_sql, "svcpart = $1";
+  if (defined($cgi->param('cancelled'))) {
+    if ($cgi->param('cancelled')) {
+      push @extra_sql, "cust_pkg.cancel IS NOT NULL";
+    } else {
+      push @extra_sql, "cust_pkg.cancel IS NULL";
+    }
+  }
 
 } elsif ( $cgi->param('title') =~ /^(.*)$/ ) {
 
index 0cb735c..3960a16 100644 (file)
@@ -10,6 +10,7 @@
                      'ONT',
                      'Model',
                      'Serial',
+                     emt('Pkg. Status'),
                      FS::UI::Web::cust_header($cgi->param('cust_fields')),
                    ],
   'fields'      => [ 'svcnum',
                      'ont_id',
                      'ont_description',
                      'ont_serial',
+                     sub {
+                       $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+                       $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                     },
                      \&FS::UI::Web::cust_fields,
                    ],
   'links'       => [ $link,
                      $link,
                      $link,
                      $link,
+                     '', # pkg status
                      FS::UI::Web::cust_links($cgi->param('cust_fields')),
                    ],
-  'align'       => 'rlllll'.  FS::UI::Web::cust_aligns(),
+  'align'       => 'rlllllr'.  FS::UI::Web::cust_aligns(),
   'color'       => [ 
                      ('') x 6,
+                     sub {
+                       my $c = FS::cust_pkg::statuscolors;
+                       $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                     }, # pkg status
                      FS::UI::Web::cust_colors(),
                    ],
   'style'       => [ 
                      ('') x 6,
+                     'b',
                      FS::UI::Web::cust_styles(),
                    ],
 
@@ -48,6 +59,8 @@ die "access denied" unless
                                                 'List services'
                                               ]);
 
+my %cust_pkg_cache;
+
 my $conf = new FS::Conf;
 
 my %search_hash;
@@ -58,6 +71,9 @@ if ( $cgi->param('magic') eq 'unlinked' ) {
                ont_typenum oltnum shelf olt_port card vlan )) {
     $search_hash{$_} = $cgi->param($_) if defined($cgi->param($_));
   }
+  if ( defined($cgi->param('cancelled')) ) {
+    $search_hash{'cancelled'} = $cgi->param('cancelled') ? 1 : 0;
+  }
 }
 
 my $query = FS::svc_fiber->search(\%search_hash);
index 6a23bb3..ca2c288 100755 (executable)
@@ -8,28 +8,38 @@
                                           'Service',
                                           'Mail to',
                                           'Forwards to',
+                                          emt('Pkg. Status'),
                                           FS::UI::Web::cust_header(),
                                         ],
                  'fields'            => [ 'svcnum',
                                           'svc',
                                           $format_src,
                                           $format_dst,
+                                          sub {
+                                            $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+                                            $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                                          },
                                           \&FS::UI::Web::cust_fields,
                                         ],
                  'links'             => [ $link,
                                           $link,
                                           $link_src,
                                           $link_dst,
+                                          '', # pkg status
                                           ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
                                                 FS::UI::Web::cust_header()
                                           ),
                                         ],
-                 'align' => 'rlll'. FS::UI::Web::cust_aligns(),
+                 'align' => 'rlllr'. FS::UI::Web::cust_aligns(),
                  'color' => [ 
                               '',
                               '',
                               '',
                               '',
+                              sub {
+                                my $c = FS::cust_pkg::statuscolors;
+                                $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                              }, # pkg status
                               FS::UI::Web::cust_colors(),
                             ],
                  'style' => [ 
@@ -37,6 +47,7 @@
                               '',
                               '',
                               '',
+                              'b',
                               FS::UI::Web::cust_styles(),
                             ],
              
@@ -46,6 +57,8 @@
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('List services');
 
+my %cust_pkg_cache;
+
 my $conf = new FS::Conf;
 
 my $orderby = 'ORDER BY svcnum';
@@ -62,6 +75,13 @@ if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
 
 } elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
   push @extra_sql, "svcpart = $1";
+  if (defined($cgi->param('cancelled'))) {
+    if ($cgi->param('cancelled')) {
+      push @extra_sql, "cust_pkg.cancel IS NOT NULL";
+    } else {
+      push @extra_sql, "cust_pkg.cancel IS NULL";
+    }
+  }
 }
 
 my $addl_from = ' LEFT JOIN cust_svc  USING ( svcnum  ) '.
index 93fc2c3..78f413e 100644 (file)
@@ -12,6 +12,7 @@
                                      'Hardware addr.',
                                      'IP addr.',
                                      'Smartcard',
+                                     emt('Pkg. Status'),
                                      FS::UI::Web::cust_header(),
                                    ],
             'fields'            => [ 'svcnum',
                                      'display_hw_addr',
                                      'ip_addr',
                                      'smartcard',
+                                     sub {
+                                       $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+                                       $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                                     },
                                      \&FS::UI::Web::cust_fields,
                                    ],
             'links'             => [ ($link_svc) x 8,
+                                     '', # pkg status
                                      ( map { $_ ne 'Cust. Status' ? 
                                                 $link_cust : '' }
                                        FS::UI::Web::cust_header() )
                                    ],
-            'align'             => 'rlllllll' . FS::UI::Web::cust_aligns(),
+            'align'             => 'rlllllllr' . FS::UI::Web::cust_aligns(),
             'color'             => [ ('') x 8,
-                                      FS::UI::Web::cust_colors() ],
+                                     sub {
+                                       my $c = FS::cust_pkg::statuscolors;
+                                       $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                                     }, # pkg status
+                                     FS::UI::Web::cust_colors() ],
             'style'             => [ $svc_cancel_style, ('') x 7,
-                                      FS::UI::Web::cust_styles() ],
+                                     'b',
+                                     FS::UI::Web::cust_styles() ],
 &>
 <%init>
 
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('List services');
 
+my %cust_pkg_cache;
+
 my $addl_from = '
  LEFT JOIN cust_svc  USING ( svcnum  )
  LEFT JOIN part_svc  USING ( svcpart )
@@ -93,6 +106,13 @@ if ( $cgi->param('typenum') =~ /^(\d+)$/ ) {
 
 if ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
   push @extra_sql, "cust_svc.svcpart = $1";
+  if (defined($cgi->param('cancelled'))) {
+    if ($cgi->param('cancelled')) {
+      push @extra_sql, "cust_pkg.cancel IS NOT NULL";
+    } else {
+      push @extra_sql, "cust_pkg.cancel IS NULL";
+    }
+  }
 }
 
 my ($orderby) = $cgi->param('orderby') =~ /^(\w+( ASC| DESC)?)$/i;
index f3a0564..29e7456 100644 (file)
@@ -9,6 +9,7 @@
                                           'Country code',
                                           'Phone number',
                                           @header,
+                                          emt('Pkg. Status'),
                                           FS::UI::Web::cust_header($cgi->param('cust_fields')),
                                         ],
                  'fields'            => [ 'svcnum',
                                           'countrycode',
                                           'phonenum',
                                           @fields,
+                                          sub {
+                                            $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+                                            $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                                          },
                                           \&FS::UI::Web::cust_fields,
                                         ],
                  'links'             => [ $link,
                                           $link,
                                           $link,
                                           ( map '', @header ),
+                                          '', # pkg status
                                           ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
                                                 FS::UI::Web::cust_header($cgi->param('cust_fields'))
                                           ),
                                         ],
                  'align' => 'rlrr'.
                             join('', map 'r', @header).
+                            'r'.
                             FS::UI::Web::cust_aligns(),
                  'color' => [ 
                               '',
                               '',
                               '',
                               ( map '', @header ),
+                              sub {
+                                my $c = FS::cust_pkg::statuscolors;
+                                $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                              }, # pkg status
                               FS::UI::Web::cust_colors(),
                             ],
                  'style' => [ 
@@ -44,6 +55,7 @@
                               '',
                               '',
                               ( map '', @header ),
+                              'b',
                               FS::UI::Web::cust_styles(),
                             ],
               
@@ -53,6 +65,8 @@
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('List services');
 
+my %cust_pkg_cache;
+
 my $conf = new FS::Conf;
 
 my @select = ();
@@ -132,6 +146,9 @@ if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
 
 } elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
   $search_hash{'svcpart'} = [ $1 ];
+  if ( defined($cgi->param('cancelled')) ) {
+    $search_hash{'cancelled'} = $cgi->param('cancelled') ? 1 : 0;
+  }
 } else {
   $cgi->param('phonenum') =~ /^([\d\- ]+)$/; 
   my $phonenum = $1;
index 7410262..4f6611f 100755 (executable)
@@ -8,6 +8,7 @@
                                     'Service',
                                     'Zone',
                                     'User',
+                                    emt('Pkg. Status'),
                                     FS::UI::Web::cust_header(),
                                   ],
                  'fields'      => [ 'svcnum',
                                             ? $svc_acct->email
                                             : '';
                                         },
+                                    sub {
+                                      $cust_pkg_cache{$_[0]->svcnum} ||= $_[0]->cust_svc->cust_pkg;
+                                      $cust_pkg_cache{$_[0]->svcnum}->ucfirst_status
+                                    },
                                     \&FS::UI::Web::cust_fields,
                                   ],
                  'links'       => [ $link,
                                     $link,
                                     '',
                                     $ulink,
+                                    '', # pkg status
                                     ( map { $_ ne 'Cust. Status' ? $link_cust : '' }
                                           FS::UI::Web::cust_header()
                                     ),
                                   ],
-                 'align' => 'rlll'. FS::UI::Web::cust_aligns(),
+                 'align' => 'rlllr'. FS::UI::Web::cust_aligns(),
                  'color' => [ 
                               '',
                               '',
                               '',
                               '',
+                              sub {
+                                my $c = FS::cust_pkg::statuscolors;
+                                $c->{$cust_pkg_cache{$_[0]->svcnum}->status };
+                              }, # pkg status
                               FS::UI::Web::cust_colors(),
                             ],
                  'style' => [ 
@@ -43,6 +53,7 @@
                               '',
                               '',
                               '',
+                              'b',
                               FS::UI::Web::cust_styles(),
                             ],
              
@@ -52,6 +63,8 @@
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('List services');
 
+my %cust_pkg_cache;
+
 #my $conf = new FS::Conf;
 
 my $orderby = 'ORDER BY svcnum';
@@ -68,6 +81,13 @@ if ( $cgi->param('magic') =~ /^(all|unlinked)$/ ) {
 
 } elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
   push @extra_sql, "svcpart = $1";
+  if (defined($cgi->param('cancelled'))) {
+    if ($cgi->param('cancelled')) {
+      push @extra_sql, "cust_pkg.cancel IS NOT NULL";
+    } else {
+      push @extra_sql, "cust_pkg.cancel IS NULL";
+    }
+  }
 }
 
 my $addl_from = ' LEFT JOIN cust_svc  USING ( svcnum  ) '.
index 3ff2f58..2de5ecf 100644 (file)
@@ -1,18 +1,18 @@
-% if ( $cancel_date ) {
-<I><% mt("Canceled [_1]", time2str('%b %o %Y', $cancel_date) ) |h %></I>
-% } else {
 <SCRIPT>
 function areyousure_delete() {
   if (confirm(<% mt('Permanently delete this service?') |js_string %>) == true)
     window.location.href = '<% $cancel_url %>';
 }
 </SCRIPT>
+% if ( $cancel_date ) {
+| <I><% mt("Canceled [_1]", time2str('%b %o %Y', $cancel_date) ) |h %></I>
+% } else {
 %   if ( $curuser->access_right('Provision customer service') ) {
 | <A HREF="<% $edit_url %>"><% mt("Edit this [_1]", $label) |h %></A>
 %   }
-%   if ( $curuser->access_right('Unprovision customer service') ) {
+% }
+% if ( $curuser->access_right('Unprovision customer service') ) {
 | <A HREF="javascript:areyousure_delete()"><% mt('Unprovision this Service') |h %></A>
-%   }
 % }
 <& /elements/manage_device_link.html, 
        'svc' => $svc_x,