suspend and unsuspend whole customer action, RT#17841
authorIvan Kohler <ivan@freeside.biz>
Mon, 4 Jun 2012 22:29:18 +0000 (15:29 -0700)
committerIvan Kohler <ivan@freeside.biz>
Mon, 4 Jun 2012 22:29:18 +0000 (15:29 -0700)
FS/FS/AccessRight.pm
FS/FS/access_right.pm
FS/FS/cust_main/Packages.pm
httemplate/misc/cust_main-suspend.cgi [new file with mode: 0755]
httemplate/misc/cust_main-unsuspend.cgi [new file with mode: 0755]
httemplate/misc/suspend_cust.html [new file with mode: 0644]
httemplate/misc/unsuspend_cust.html [new file with mode: 0644]
httemplate/view/cust_main.cgi

index bcf3f64..4aa777b 100644 (file)
@@ -111,6 +111,8 @@ tie my %rights, 'Tie::IxHash',
     'Edit customer tags',
     'Edit referring customer',
     'View customer history',
     'Edit customer tags',
     'Edit referring customer',
     'View customer history',
+    'Suspend customer',
+    'Unsuspend customer',
     'Cancel customer',
     'Complimentary customer', #aka users-allow_comp 
     'Merge customer',
     'Cancel customer',
     'Complimentary customer', #aka users-allow_comp 
     'Merge customer',
index 26a480b..52cae34 100644 (file)
@@ -3,6 +3,7 @@ package FS::access_right;
 use strict;
 use vars qw( @ISA );
 use FS::Record qw( qsearch qsearchs );
 use strict;
 use vars qw( @ISA );
 use FS::Record qw( qsearch qsearchs );
+use FS::upgrade_journal;
 
 @ISA = qw(FS::Record);
 
 
 @ISA = qw(FS::Record);
 
@@ -183,9 +184,13 @@ sub _upgrade_data { # class method
   my @all_groups = qsearch('access_group', {});
 
   my %onetime = (
   my @all_groups = qsearch('access_group', {});
 
   my %onetime = (
-    'List customers'   => 'List all customers',
-    'List packages'    => 'Summarize packages',
-    'Post payment'     => 'Backdate payment',
+    'List customers'                      => 'List all customers',
+    'List packages'                       => 'Summarize packages',
+    'Post payment'                        => 'Backdate payment',
+    'Cancel customer package immediately' => 'Un-cancel customer package',
+    'Suspend customer package'            => 'Suspend customer',
+    'Unsuspend customer package'          => 'Unsuspend customer',
+
     'List services'    => [ 'Services: Accounts',
                             'Services: Domains',
                             'Services: Certificates',
     'List services'    => [ 'Services: Accounts',
                             'Services: Domains',
                             'Services: Certificates',
@@ -205,7 +210,6 @@ sub _upgrade_data { # class method
                             'Usage: Call Detail Records (CDRs)',
                             'Usage: Unrateable CDRs',
                           ],
                             'Usage: Call Detail Records (CDRs)',
                             'Usage: Unrateable CDRs',
                           ],
-    'Cancel customer package immediately' => 'Un-cancel customer package',
   );
 
   foreach my $old_acl ( keys %onetime ) {
   );
 
   foreach my $old_acl ( keys %onetime ) {
index 887ac49..957043a 100644 (file)
@@ -355,6 +355,7 @@ Returns all suspended packages (see L<FS::cust_pkg>) for this customer.
 
 sub suspended_pkgs {
   my $self = shift;
 
 sub suspended_pkgs {
   my $self = shift;
+  return $self->num_suspended_pkgs unless wantarray;
   grep { $_->susp } $self->ncancelled_pkgs;
 }
 
   grep { $_->susp } $self->ncancelled_pkgs;
 }
 
@@ -381,6 +382,7 @@ this customer.
 
 sub unsuspended_pkgs {
   my $self = shift;
 
 sub unsuspended_pkgs {
   my $self = shift;
+  return $self->num_unsuspended_pkgs unless wantarray;
   grep { ! $_->susp } $self->ncancelled_pkgs;
 }
 
   grep { ! $_->susp } $self->ncancelled_pkgs;
 }
 
@@ -442,6 +444,16 @@ sub num_ncancelled_pkgs {
   shift->num_pkgs("( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )");
 }
 
   shift->num_pkgs("( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )");
 }
 
+sub num_suspended_pkgs {
+  shift->num_pkgs("     ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
+                    AND cust_pkg.susp IS NOT NULL AND cust_pkg.susp != 0   ");
+}
+
+sub num_unsuspended_pkgs {
+  shift->num_pkgs("     ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
+                    AND ( cust_pkg.susp   IS NULL OR cust_pkg.susp   = 0 ) ");
+}
+
 sub num_pkgs {
   my( $self ) = shift;
   my $sql = scalar(@_) ? shift : '';
 sub num_pkgs {
   my( $self ) = shift;
   my $sql = scalar(@_) ? shift : '';
diff --git a/httemplate/misc/cust_main-suspend.cgi b/httemplate/misc/cust_main-suspend.cgi
new file mode 100755 (executable)
index 0000000..6185136
--- /dev/null
@@ -0,0 +1,75 @@
+<& /elements/header-popup.html, mt("Customer suspended") &>
+  <SCRIPT TYPE="text/javascript">
+    window.top.location.reload();
+  </SCRIPT>
+  </BODY>
+</HTML>
+<%init>
+
+#false laziness w/cust_main-cancel.cgi
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Suspend customer');
+
+my $custnum;
+my $adjourn = '';
+if ( $cgi->param('custnum') =~ /^(\d+)$/ ) {
+  $custnum = $1;
+  $adjourn = $cgi->param('adjourn');
+} else {
+  my($query) = $cgi->keywords;
+  $query =~ /^(\d+)$/ || die "Illegal custnum";
+  $custnum = $1;
+}
+
+#false laziness w/process/cancel_pkg.html
+
+#untaint reasonnum
+my $reasonnum = $cgi->param('reasonnum');
+$reasonnum =~ /^(-?\d+)$/ || die "Illegal reasonnum";
+$reasonnum = $1;
+
+if ($reasonnum == -1) {
+  $reasonnum = {
+    'typenum' => scalar( $cgi->param('newreasonnumT') ),
+    'reason'  => scalar( $cgi->param('newreasonnum' ) ),
+  };
+}
+
+#eslaf
+
+my $cust_main = qsearchs( {
+  'table'     => 'cust_main',
+  'hashref'   => { 'custnum' => $custnum },
+  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+} );
+
+my @errors;
+if($cgi->param('now_or_later')) {
+  $adjourn = parse_datetime($adjourn);
+  if($adjourn) {
+    #warn "setting adjourn dates on custnum#$custnum\n";
+    my @pkgs = $cust_main->unsuspended_pkgs;
+    @errors = grep {$_} map { $_->suspend(
+      'reason'  => $reasonnum,
+      'date'    => $adjourn,
+    ) } @pkgs;
+  }
+  else {
+    @errors = ("error parsing adjourn date: ".$cgi->param('adjourn'));
+  }
+}
+else {
+  warn "suspending $cust_main";
+  @errors = $cust_main->suspend(
+    'reason' => $reasonnum,
+  );
+}
+my $error = join(' / ', @errors) if scalar(@errors);
+
+if ( $error ) {
+  $cgi->param('error', $error);
+  print $cgi->redirect(popurl(1). "suspend_cust.html?". $cgi->query_string );
+}
+
+</%init>
diff --git a/httemplate/misc/cust_main-unsuspend.cgi b/httemplate/misc/cust_main-unsuspend.cgi
new file mode 100755 (executable)
index 0000000..eb4a2c8
--- /dev/null
@@ -0,0 +1,56 @@
+<& /elements/header-popup.html, mt("Customer unsuspended") &>
+  <SCRIPT TYPE="text/javascript">
+    window.top.location.reload();
+  </SCRIPT>
+  </BODY>
+</HTML>
+<%init>
+
+#false laziness w/cust_main-cancel.cgi
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Unsuspend customer');
+
+my $custnum;
+my $resume = '';
+if ( $cgi->param('custnum') =~ /^(\d+)$/ ) {
+  $custnum = $1;
+  $resume = $cgi->param('resume');
+} else {
+  my($query) = $cgi->keywords;
+  $query =~ /^(\d+)$/ || die "Illegal custnum";
+  $custnum = $1;
+}
+
+my $cust_main = qsearchs( {
+  'table'     => 'cust_main',
+  'hashref'   => { 'custnum' => $custnum },
+  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+} );
+
+my @errors;
+if($cgi->param('now_or_later')) {
+  $resume = parse_datetime($resume);
+  if($resume) {
+    #warn "setting resume dates on custnum#$custnum\n";
+    my @pkgs = $cust_main->suspended_pkgs;
+    @errors = grep {$_} map { $_->unsuspend(
+      'date'    => $resume,
+    ) } @pkgs;
+  }
+  else {
+    @errors = ("error parsing adjourn date: ".$cgi->param('adjourn'));
+  }
+}
+else {
+  warn "unsuspending $cust_main";
+  @errors = $cust_main->unsuspend;
+}
+my $error = join(' / ', @errors) if scalar(@errors);
+
+if ( $error ) {
+  $cgi->param('error', $error);
+  print $cgi->redirect(popurl(1). "unsuspend_cust.html?". $cgi->query_string );
+}
+
+</%init>
diff --git a/httemplate/misc/suspend_cust.html b/httemplate/misc/suspend_cust.html
new file mode 100644 (file)
index 0000000..b41f36f
--- /dev/null
@@ -0,0 +1,79 @@
+<& /elements/header-popup.html, mt('Suspend customer')  &>
+
+<& /elements/error.html &>
+
+<FORM NAME="cust_suspend_popup" ACTION="<% popurl(1) %>cust_main-suspend.cgi" METHOD=POST>
+<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>">
+
+ <P ALIGN="center"><B><% mt('Suspend this customer?') |h %></B>
+
+<TABLE BORDER="0" CELLSPACING="2"
+STYLE="margin-left:auto; margin-right:auto">
+<TR>
+  <TD ALIGN="right">
+    <INPUT TYPE="radio" NAME="now_or_later" VALUE="0" onclick="toggle(false)" CHECKED />
+  </TD>
+  <TD ALIGN="left"><% mt('Suspend now') |h %></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">
+    <INPUT TYPE="radio" NAME="now_or_later" VALUE="1" onclick="toggle(true)" />
+  </TD>
+  <TD ALIGN="left"><% mt('Suspend on date: ') |h %> 
+  <& /elements/input-date-field.html, {
+              'name'    => 'adjourn',
+              'value'   => time,
+    }  &>
+  </TD>
+</TR>
+</TABLE>
+<SCRIPT type="text/javascript">
+function toggle(val) {
+  document.getElementById("adjourn_text").disabled = !val;
+  document.getElementById("adjourn_button").style.visibility = 
+    val ? 'visible' : 'hidden';
+}
+toggle(false);
+</SCRIPT> 
+
+<TABLE BGCOLOR="#cccccc", BORDER="0" CELLSPACING="2"
+STYLE="margin-left:auto; margin-right:auto">
+<& /elements/tr-select-reason.html,
+             'field'          => 'reasonnum',
+             'reason_class'   => 'C',
+             'cgi'            => $cgi,
+             'control_button' => "document.getElementById('confirm_suspend_cust_button')",
+&>
+
+</TABLE>
+
+<BR>
+<P ALIGN="CENTER">
+<INPUT TYPE="submit" NAME="submit" ID="confirm_suspend_cust_button" VALUE="<% mt('Suspend customer') |h %>" DISABLED> 
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+<INPUT TYPE="BUTTON" VALUE="<% mt("Don't suspend") |h %>" onClick="parent.cClick();"> 
+
+</FORM>
+</BODY>
+</HTML>
+
+<%init>
+
+#false laziness w/cancel_cust.html
+
+$cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum';
+my $custnum = $1;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied" unless $curuser->access_right('Suspend customer');
+
+my $cust_main = qsearchs( {
+  'table'     => 'cust_main',
+  'hashref'   => { 'custnum' => $custnum },
+  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+} );
+die "No customer # $custnum" unless $cust_main;
+
+</%init>
+
diff --git a/httemplate/misc/unsuspend_cust.html b/httemplate/misc/unsuspend_cust.html
new file mode 100644 (file)
index 0000000..600eb26
--- /dev/null
@@ -0,0 +1,68 @@
+<& /elements/header-popup.html, mt('Unsuspend customer')  &>
+
+<& /elements/error.html &>
+
+<FORM NAME="cust_unsuspend_popup" ACTION="<% popurl(1) %>cust_main-unsuspend.cgi" METHOD=POST>
+<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>">
+
+ <P ALIGN="center"><B><% mt('Unsuspend this customer?') |h %></B>
+
+<TABLE BORDER="0" CELLSPACING="2"
+STYLE="margin-left:auto; margin-right:auto">
+<TR>
+  <TD ALIGN="right">
+    <INPUT TYPE="radio" NAME="now_or_later" VALUE="0" onclick="toggle(false)" CHECKED />
+  </TD>
+  <TD ALIGN="left"><% mt('Unsuspend now') |h %></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">
+    <INPUT TYPE="radio" NAME="now_or_later" VALUE="1" onclick="toggle(true)" />
+  </TD>
+  <TD ALIGN="left"><% mt('Unsuspend on date: ') |h %> 
+  <& /elements/input-date-field.html, {
+              'name'    => 'resume',
+              'value'   => time,
+    }  &>
+  </TD>
+</TR>
+</TABLE>
+<SCRIPT type="text/javascript">
+function toggle(val) {
+  document.getElementById("resume_text").disabled = !val;
+  document.getElementById("resume_button").style.visibility = 
+    val ? 'visible' : 'hidden';
+}
+toggle(false);
+</SCRIPT> 
+
+<BR>
+<P ALIGN="CENTER">
+<INPUT TYPE="submit" NAME="submit" ID="confirm_unsuspend_cust_button" VALUE="<% mt('Unsuspend customer') |h %>"> 
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+<INPUT TYPE="BUTTON" VALUE="<% mt("Don't unsuspend") |h %>" onClick="parent.cClick();"> 
+
+</FORM>
+</BODY>
+</HTML>
+
+<%init>
+
+#false laziness w/cancel_cust.html
+
+$cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum';
+my $custnum = $1;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied" unless $curuser->access_right('Unsuspend customer');
+
+my $cust_main = qsearchs( {
+  'table'     => 'cust_main',
+  'hashref'   => { 'custnum' => $custnum },
+  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+} );
+die "No customer # $custnum" unless $cust_main;
+
+</%init>
+
index 83f28d3..ec31919 100755 (executable)
@@ -46,10 +46,39 @@ function areyousure(href, message) {
   <A HREF="<% $p %>edit/cust_main.cgi?<% $custnum %>"><% mt('Edit this customer') |h %></A> | 
 % } 
 
   <A HREF="<% $p %>edit/cust_main.cgi?<% $custnum %>"><% mt('Edit this customer') |h %></A> | 
 % } 
 
-% if ( $curuser->access_right('Cancel customer')
-%        && $cust_main->ncancelled_pkgs
+% if ( $curuser->access_right('Suspend customer')
+%        && scalar($cust_main->unsuspended_pkgs)
+%      ) {
+  <& /elements/popup_link-cust_main.html,
+              { 'action'      => $p. 'misc/suspend_cust.html',
+                'label'       => emt('Suspend this customer'),
+                'actionlabel' => emt('Confirm Suspension'),
+                'color'       => '#ff9900',
+                'cust_main'   => $cust_main,
+                'width'       => 616, #make room for reasons
+                'height'      => 366,
+              }
+  &> | 
+% }
+
+% if ( $curuser->access_right('Unsuspend customer')
+%        && scalar($cust_main->suspended_pkgs)
 %      ) {
 %      ) {
+  <& /elements/popup_link-cust_main.html,
+              { 'action'      => $p. 'misc/unsuspend_cust.html',
+                'label'       => emt('Unsuspend this customer'),
+                'actionlabel' => emt('Confirm Unsuspension'),
+                #'color'       => '#ff9900',
+                'cust_main'   => $cust_main,
+                #'width'       => 616, #make room for reasons
+                #'height'      => 366,
+              }
+  &> | 
+% }
 
 
+% if ( $curuser->access_right('Cancel customer')
+%        && scalar($cust_main->ncancelled_pkgs)
+%      ) {
   <& /elements/popup_link-cust_main.html,
               { 'action'      => $p. 'misc/cancel_cust.html',
                 'label'       => emt('Cancel this customer'),
   <& /elements/popup_link-cust_main.html,
               { 'action'      => $p. 'misc/cancel_cust.html',
                 'label'       => emt('Cancel this customer'),
@@ -60,11 +89,9 @@ function areyousure(href, message) {
                 'height'      => 366,
               }
   &> | 
                 'height'      => 366,
               }
   &> | 
-
 % }
 
 % if ( $curuser->access_right('Merge customer') ) {
 % }
 
 % if ( $curuser->access_right('Merge customer') ) {
-
   <& /elements/popup_link-cust_main.html,
               { 'action'      => $p. 'misc/merge_cust.html',
                 'label'       => emt('Merge this customer'),
   <& /elements/popup_link-cust_main.html,
               { 'action'      => $p. 'misc/merge_cust.html',
                 'label'       => emt('Merge this customer'),
@@ -74,7 +101,6 @@ function areyousure(href, message) {
                 'height'      => 192,
               }
   &> | 
                 'height'      => 192,
               }
   &> | 
-
 % } 
 
 % if ( $conf->exists('deletecustomers')
 % } 
 
 % if ( $conf->exists('deletecustomers')