diff options
-rw-r--r-- | FS/FS/AccessRight.pm | 2 | ||||
-rw-r--r-- | FS/FS/access_right.pm | 12 | ||||
-rw-r--r-- | FS/FS/cust_main/Packages.pm | 12 | ||||
-rwxr-xr-x | httemplate/misc/cust_main-suspend.cgi | 75 | ||||
-rwxr-xr-x | httemplate/misc/cust_main-unsuspend.cgi | 56 | ||||
-rw-r--r-- | httemplate/misc/suspend_cust.html | 79 | ||||
-rw-r--r-- | httemplate/misc/unsuspend_cust.html | 68 | ||||
-rwxr-xr-x | httemplate/view/cust_main.cgi | 36 |
8 files changed, 331 insertions, 9 deletions
diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index bcf3f64..4aa777b 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -111,6 +111,8 @@ tie my %rights, 'Tie::IxHash', 'Edit customer tags', 'Edit referring customer', 'View customer history', + 'Suspend customer', + 'Unsuspend customer', 'Cancel customer', 'Complimentary customer', #aka users-allow_comp 'Merge customer', diff --git a/FS/FS/access_right.pm b/FS/FS/access_right.pm index 26a480b..52cae34 100644 --- a/FS/FS/access_right.pm +++ b/FS/FS/access_right.pm @@ -3,6 +3,7 @@ package FS::access_right; use strict; use vars qw( @ISA ); use FS::Record qw( qsearch qsearchs ); +use FS::upgrade_journal; @ISA = qw(FS::Record); @@ -183,9 +184,13 @@ sub _upgrade_data { # class method 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', @@ -205,7 +210,6 @@ sub _upgrade_data { # class method 'Usage: Call Detail Records (CDRs)', 'Usage: Unrateable CDRs', ], - 'Cancel customer package immediately' => 'Un-cancel customer package', ); foreach my $old_acl ( keys %onetime ) { diff --git a/FS/FS/cust_main/Packages.pm b/FS/FS/cust_main/Packages.pm index 887ac49..957043a 100644 --- a/FS/FS/cust_main/Packages.pm +++ b/FS/FS/cust_main/Packages.pm @@ -355,6 +355,7 @@ Returns all suspended packages (see L<FS::cust_pkg>) for this customer. sub suspended_pkgs { my $self = shift; + return $self->num_suspended_pkgs unless wantarray; grep { $_->susp } $self->ncancelled_pkgs; } @@ -381,6 +382,7 @@ this customer. sub unsuspended_pkgs { my $self = shift; + return $self->num_unsuspended_pkgs unless wantarray; 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 )"); } +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 : ''; diff --git a/httemplate/misc/cust_main-suspend.cgi b/httemplate/misc/cust_main-suspend.cgi new file mode 100755 index 0000000..6185136 --- /dev/null +++ b/httemplate/misc/cust_main-suspend.cgi @@ -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 index 0000000..eb4a2c8 --- /dev/null +++ b/httemplate/misc/cust_main-unsuspend.cgi @@ -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 index 0000000..b41f36f --- /dev/null +++ b/httemplate/misc/suspend_cust.html @@ -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> + +<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 index 0000000..600eb26 --- /dev/null +++ b/httemplate/misc/unsuspend_cust.html @@ -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 %>"> + +<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> + diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index 83f28d3..ec31919 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -46,10 +46,39 @@ function areyousure(href, message) { <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'), @@ -60,11 +89,9 @@ function areyousure(href, message) { 'height' => 366, } &> | - % } % if ( $curuser->access_right('Merge 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, } &> | - % } % if ( $conf->exists('deletecustomers') |