summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjeff <jeff>2008-07-01 05:03:42 +0000
committerjeff <jeff>2008-07-01 05:03:42 +0000
commit7905f5dfd903529a6de89875e6fae74638a89aa3 (patch)
treec0b2127274371c3eb040dd0fc3d9e58e0fa11627
parent3b268aa232236ad064c7b3f47a6a0a242e395bdf (diff)
correct internal reason searching, prevent interleaved suspend/cancel/expire/adjourn, backporting and refactoring
-rw-r--r--FS/FS/Schema.pm1
-rw-r--r--FS/FS/cust_pkg.pm334
-rw-r--r--FS/FS/cust_pkg_reason.pm1
-rw-r--r--FS/FS/part_export/shellcommands.pm4
-rw-r--r--FS/FS/part_export/sqlradius.pm2
-rwxr-xr-xhttemplate/edit/REAL_cust_pkg.cgi11
-rwxr-xr-xhttemplate/misc/process/cancel_pkg.html11
-rwxr-xr-xhttemplate/misc/unadjourn_pkg.cgi17
-rwxr-xr-xhttemplate/misc/unexpire_pkg.cgi17
-rwxr-xr-xhttemplate/search/cust_pkg.cgi9
-rwxr-xr-xhttemplate/view/cust_main/packages.html29
11 files changed, 325 insertions, 111 deletions
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 34e31d82d..90d9d5d7b 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -939,6 +939,7 @@ sub tables_hashref {
'num', 'serial', '', '', '', '',
'pkgnum', 'int', '', '', '', '',
'reasonnum','int', '', '', '', '',
+ 'action', 'char', 'NULL', 1, '', '', #should not be nullable
'otaker', 'varchar', '', 32, '', '',
'date', @date_type, '', '',
],
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index 5d449acd7..457d25786 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -342,6 +342,8 @@ sub replace {
if ($options->{'reason'} && $new->$method && $old->$method ne $new->$method) {
my $error = $new->insert_reason( 'reason' => $options->{'reason'},
'date' => $new->$method,
+ 'action' => $method,
+ 'reason_otaker' => $options{'reason_otaker'},
);
if ( $error ) {
dbh->rollback if $oldAutoCommit;
@@ -477,6 +479,8 @@ Available options are:
=item reason - can be set to a cancellation reason (see L<FS:reason>), either a reasonnum of an existing reason, or passing a hashref will create a new reason. The hashref should have the following keys: typenum - Reason type (see L<FS::reason_type>, reason - Text of the new reason.
+=item date - can be set to a unix style timestamp to specify when to cancel (expire)
+
=back
If there is an error, returns the error, otherwise returns false.
@@ -485,6 +489,7 @@ If there is an error, returns the error, otherwise returns false.
sub cancel {
my( $self, %options ) = @_;
+ my $error;
warn "cust_pkg::cancel called with options".
join(', ', map { "$_: $options{$_}" } keys %options ). "\n"
@@ -501,12 +506,23 @@ sub cancel {
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
- my $cancel_time = $options{'time'} || time;
+ my $old = $self->select_for_update;
- my $error;
+ if ( $old->get('cancel') || $self->get('cancel') ) {
+ dbh->rollback if $oldAutoCommit;
+ return ""; # no error
+ }
+
+ my $date = $options{date} if $options{date}; # expire/cancel later
+ $date = '' if ($date && $date <= time); # complain instead?
+
+ my $cancel_time = $options{'time'} || time;
if ( $options{'reason'} ) {
- $error = $self->insert_reason( 'reason' => $options{'reason'} );
+ $error = $self->insert_reason( 'reason' => $options{'reason'},
+ 'action' => $date ? 'expire' : 'cancel',
+ 'reason_otaker' => $options{'reason_otaker'},
+ );
if ( $error ) {
dbh->rollback if $oldAutoCommit;
return "Error inserting cust_pkg_reason: $error";
@@ -514,23 +530,23 @@ sub cancel {
}
my %svc;
- foreach my $cust_svc (
- #schwartz
- map { $_->[0] }
- sort { $a->[1] <=> $b->[1] }
- map { [ $_, $_->svc_x->table_info->{'cancel_weight'} ]; }
- qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } )
- ) {
+ unless ( $date ) {
+ foreach my $cust_svc (
+ #schwartz
+ map { $_->[0] }
+ sort { $a->[1] <=> $b->[1] }
+ map { [ $_, $_->svc_x->table_info->{'cancel_weight'} ]; }
+ qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } )
+ ) {
- my $error = $cust_svc->cancel;
+ my $error = $cust_svc->cancel;
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return "Error cancelling cust_svc: $error";
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Error cancelling cust_svc: $error";
+ }
}
- }
- unless ( $self->getfield('cancel') ) {
# Add a credit for remaining service
my $remaining_value = $self->calc_remain(time=>$cancel_time);
if ( $remaining_value > 0 && !$options{'no_credit'} ) {
@@ -543,20 +559,22 @@ sub cancel {
if ($error) {
$dbh->rollback if $oldAutoCommit;
return "Error crediting customer \$$remaining_value for unused time on".
- $self->part_pkg->pkg. ": $error";
- }
- }
- my %hash = $self->hash;
- $hash{'cancel'} = $cancel_time;
- my $new = new FS::cust_pkg ( \%hash );
- $error = $new->replace( $self, options => { $self->options } );
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
+ $self->part_pkg->pkg. ": $error";
+ }
}
}
+ my %hash = $self->hash;
+ $date ? ($hash{'expire'} = $date) : ($hash{'cancel'} = $cancel_time);
+ my $new = new FS::cust_pkg ( \%hash );
+ $error = $new->replace( $self, options => { $self->options } );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ return '' if $date; #no errors
my $conf = new FS::Conf;
my @invoicing_list = grep { $_ !~ /^(POST|FAX)$/ } $self->cust_main->invoicing_list;
@@ -593,7 +611,59 @@ sub cancel_if_expired {
'';
}
-=item suspend [ OPTION => VALUE ... ]
+=item unexpire
+
+Cancels any pending expiration (sets the expire field to null).
+
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub unexpire {
+ my( $self, %options ) = @_;
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $old = $self->select_for_update;
+
+ my $pkgnum = $old->pkgnum;
+ if ( $old->get('cancel') || $self->get('cancel') ) {
+ dbh->rollback if $oldAutoCommit;
+ return "Can't unexpire cancelled package $pkgnum";
+ # or at least it's pointless
+ }
+
+ unless ( $old->get('expire') && $self->get('expire') ) {
+ dbh->rollback if $oldAutoCommit;
+ return ""; # no error
+ }
+
+ my %hash = $self->hash;
+ $hash{'expire'} = '';
+ my $new = new FS::cust_pkg ( \%hash );
+ $error = $new->replace( $self, options => { $self->options } );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ ''; #no errors
+
+}
+
+=item suspend [ OPTION => VALUE ... ]
Suspends all services (see L<FS::cust_svc> and L<FS::part_svc>) in this
package, then suspends the package itself (sets the susp field to now).
@@ -604,6 +674,8 @@ Available options are:
=item reason - can be set to a cancellation reason (see L<FS:reason>), either a reasonnum of an existing reason, or passing a hashref will create a new reason. The hashref should have the following keys: typenum - Reason type (see L<FS::reason_type>, reason - Text of the new reason.
+=item date - can be set to a unix style timestamp to specify when to suspend (adjourn)
+
=back
If there is an error, returns the error, otherwise returns false.
@@ -612,6 +684,7 @@ If there is an error, returns the error, otherwise returns false.
sub suspend {
my( $self, %options ) = @_;
+ my $error;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
@@ -624,48 +697,69 @@ sub suspend {
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
- my $error;
+ my $old = $self->select_for_update;
+
+ my $pkgnum = $old->pkgnum;
+ if ( $old->get('cancel') || $self->get('cancel') ) {
+ dbh->rollback if $oldAutoCommit;
+ return "Can't suspend cancelled package $pkgnum";
+ }
+
+ if ( $old->get('susp') || $self->get('susp') ) {
+ dbh->rollback if $oldAutoCommit;
+ return ""; # no error # complain on adjourn?
+ }
+
+ my $date = $options{date} if $options{date}; # adjourn/suspend later
+ $date = '' if ($date && $date <= time); # complain instead?
+
+ if ( $date && $old->get('expire') && $old->get('expire') < $date ) {
+ dbh->rollback if $oldAutoCommit;
+ return "Package $pkgnum expires before it would be suspended.";
+ }
if ( $options{'reason'} ) {
- $error = $self->insert_reason( 'reason' => $options{'reason'} );
+ $error = $self->insert_reason( 'reason' => $options{'reason'},
+ 'action' => $date ? 'adjourn' : 'suspend',
+ 'reason_otaker' => $options{'reason_otaker'},
+ );
if ( $error ) {
dbh->rollback if $oldAutoCommit;
return "Error inserting cust_pkg_reason: $error";
}
}
- foreach my $cust_svc (
- qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } )
- ) {
- my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $cust_svc->svcpart } );
+ unless ( $date ) {
+ foreach my $cust_svc (
+ qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } )
+ ) {
+ my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $cust_svc->svcpart } );
- $part_svc->svcdb =~ /^([\w\-]+)$/ or do {
- $dbh->rollback if $oldAutoCommit;
- return "Illegal svcdb value in part_svc!";
- };
- my $svcdb = $1;
- require "FS/$svcdb.pm";
-
- my $svc = qsearchs( $svcdb, { 'svcnum' => $cust_svc->svcnum } );
- if ($svc) {
- $error = $svc->suspend;
- if ( $error ) {
+ $part_svc->svcdb =~ /^([\w\-]+)$/ or do {
$dbh->rollback if $oldAutoCommit;
- return $error;
+ return "Illegal svcdb value in part_svc!";
+ };
+ my $svcdb = $1;
+ require "FS/$svcdb.pm";
+
+ my $svc = qsearchs( $svcdb, { 'svcnum' => $cust_svc->svcnum } );
+ if ($svc) {
+ $error = $svc->suspend;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
}
}
-
}
- unless ( $self->getfield('susp') ) {
- my %hash = $self->hash;
- $hash{'susp'} = time;
- my $new = new FS::cust_pkg ( \%hash );
- $error = $new->replace( $self, options => { $self->options } );
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
+ my %hash = $self->hash;
+ $date ? ($hash{'adjourn'} = $date) : ($hash{'susp'} = time);
+ my $new = new FS::cust_pkg ( \%hash );
+ $error = $new->replace( $self, options => { $self->options } );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
}
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
@@ -707,6 +801,19 @@ sub unsuspend {
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
+ my $old = $self->select_for_update;
+
+ my $pkgnum = $old->pkgnum;
+ if ( $old->get('cancel') || $self->get('cancel') ) {
+ dbh->rollback if $oldAutoCommit;
+ return "Can't unsuspend cancelled package $pkgnum";
+ }
+
+ unless ( $old->get('susp') && $self->get('susp') ) {
+ dbh->rollback if $oldAutoCommit;
+ return ""; # no error # complain instead?
+ }
+
foreach my $cust_svc (
qsearch('cust_svc',{'pkgnum'=> $self->pkgnum } )
) {
@@ -730,30 +837,86 @@ sub unsuspend {
}
- unless ( ! $self->getfield('susp') ) {
- my %hash = $self->hash;
- my $inactive = time - $hash{'susp'};
+ my %hash = $self->hash;
+ my $inactive = time - $hash{'susp'};
- my $conf = new FS::Conf;
+ my $conf = new FS::Conf;
- $hash{'bill'} = ( $hash{'bill'} || $hash{'setup'} ) + $inactive
- if ( $opt{'adjust_next_bill'}
- || $conf->config('unsuspend-always_adjust_next_bill_date') )
- && $inactive > 0 && ( $hash{'bill'} || $hash{'setup'} );
+ $hash{'bill'} = ( $hash{'bill'} || $hash{'setup'} ) + $inactive
+ if ( $opt{'adjust_next_bill'}
+ || $conf->config('unsuspend-always_adjust_next_bill_date') )
+ && $inactive > 0 && ( $hash{'bill'} || $hash{'setup'} );
- $hash{'susp'} = '';
- $hash{'adjourn'} = '' if $hash{'adjourn'} < time;
- my $new = new FS::cust_pkg ( \%hash );
- $error = $new->replace( $self, options => { $self->options } );
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
+ $hash{'susp'} = '';
+ $hash{'adjourn'} = '' if $hash{'adjourn'} < time;
+ my $new = new FS::cust_pkg ( \%hash );
+ $error = $new->replace( $self, options => { $self->options } );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ ''; #no errors
+}
+
+=item unadjourn
+
+Cancels any pending suspension (sets the adjourn field to null).
+
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub unadjourn {
+ my( $self, %options ) = @_;
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $old = $self->select_for_update;
+
+ my $pkgnum = $old->pkgnum;
+ if ( $old->get('cancel') || $self->get('cancel') ) {
+ dbh->rollback if $oldAutoCommit;
+ return "Can't unadjourn cancelled package $pkgnum";
+ # or at least it's pointless
+ }
+
+ if ( $old->get('susp') || $self->get('susp') ) {
+ dbh->rollback if $oldAutoCommit;
+ return "Can't unadjourn suspended package $pkgnum";
+ # perhaps this is arbitrary
+ }
+
+ unless ( $old->get('adjourn') && $self->get('adjourn') ) {
+ dbh->rollback if $oldAutoCommit;
+ return ""; # no error
+ }
+
+ my %hash = $self->hash;
+ $hash{'adjourn'} = '';
+ my $new = new FS::cust_pkg ( \%hash );
+ $error = $new->replace( $self, options => { $self->options } );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
}
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
''; #no errors
+
}
=item last_bill
@@ -772,30 +935,37 @@ sub last_bill {
$cust_bill_pkg ? $cust_bill_pkg->sdate : $self->setup || 0;
}
-=item last_cust_pkg_reason
+=item last_cust_pkg_reason ACTION
-Returns the most recent FS::reason associated with the package.
+Returns the most recent ACTION FS::cust_pkg_reason associated with the package.
+Returns false if there is no reason or the package is not currenly ACTION'd
+ACTION is one of adjourn, susp, cancel, or expire.
=cut
sub last_cust_pkg_reason {
- my $self = shift;
+ my ( $self, $action ) = ( shift, shift );
+ my $date = $self->get($action);
qsearchs( {
'table' => 'cust_pkg_reason',
- 'hashref' => { 'pkgnum' => $self->pkgnum, },
- 'extra_sql'=> "AND date <= ". time,
- 'order_by' => 'ORDER BY date DESC LIMIT 1',
+ 'hashref' => { 'pkgnum' => $self->pkgnum,
+ 'action' => substr(uc($action), 0, 1),
+ 'date' => $date,
+ },
+ 'order_by' => 'ORDER BY num DESC LIMIT 1',
} );
}
-=item last_reason
+=item last_reason ACTION
-Returns the most recent FS::reason associated with the package.
+Returns the most recent ACTION FS::reason associated with the package.
+Returns false if there is no reason or the package is not currenly ACTION'd
+ACTION is one of adjourn, susp, cancel, or expire.
=cut
sub last_reason {
- my $cust_pkg_reason = shift->last_cust_pkg_reason;
+ my $cust_pkg_reason = shift->last_cust_pkg_reason(@_);
$cust_pkg_reason->reason
if $cust_pkg_reason;
}
@@ -2055,7 +2225,8 @@ sub bulk_change {
sub insert_reason {
my ($self, %options) = @_;
- my $otaker = $FS::CurrentUser::CurrentUser->username;
+ my $otaker = $options{reason_otaker} ||
+ $FS::CurrentUser::CurrentUser->username;
my $reasonnum;
if ( $options{'reason'} =~ /^(\d+)$/ ) {
@@ -2084,6 +2255,7 @@ sub insert_reason {
new FS::cust_pkg_reason({ 'pkgnum' => $self->pkgnum,
'reasonnum' => $reasonnum,
'otaker' => $otaker,
+ 'action' => substr(uc($options{'action'}),0,1),
'date' => $options{'date'}
? $options{'date'}
: time,
diff --git a/FS/FS/cust_pkg_reason.pm b/FS/FS/cust_pkg_reason.pm
index 24808f944..92cd4a1f9 100644
--- a/FS/FS/cust_pkg_reason.pm
+++ b/FS/FS/cust_pkg_reason.pm
@@ -98,6 +98,7 @@ sub check {
$self->ut_numbern('num')
|| $self->ut_number('pkgnum')
|| $self->ut_number('reasonnum')
+ || $self->ut_enum('action', [ 'A', 'C', 'E', 'S' ])
|| $self->ut_text('otaker')
|| $self->ut_numbern('date')
;
diff --git a/FS/FS/part_export/shellcommands.pm b/FS/FS/part_export/shellcommands.pm
index 29e0a5799..c55fa367e 100644
--- a/FS/FS/part_export/shellcommands.pm
+++ b/FS/FS/part_export/shellcommands.pm
@@ -255,7 +255,9 @@ sub _export_command {
@radius_groups = $svc_acct->radius_groups;
my ($reasonnum, $reasontext, $reasontypenum, $reasontypetext);
- if ( $cust_pkg && $action eq 'suspend' && (my $r = $cust_pkg->last_reason) ) {
+ if ( $cust_pkg && $action eq 'suspend' &&
+ (my $r = $cust_pkg->last_reason('susp')) )
+ {
$reasonnum = $r->reasonnum;
$reasontext = $r->reason;
$reasontypenum = $r->reason_type;
diff --git a/FS/FS/part_export/sqlradius.pm b/FS/FS/part_export/sqlradius.pm
index 3c25a99ee..88b7ed399 100644
--- a/FS/FS/part_export/sqlradius.pm
+++ b/FS/FS/part_export/sqlradius.pm
@@ -311,7 +311,7 @@ sub suspended_usergroups {
#false laziness with FS::part_export::shellcommands
#subclass part_export?
- my $r = $svc_acct->cust_svc->cust_pkg->last_reason;
+ my $r = $svc_acct->cust_svc->cust_pkg->last_reason('susp');
my %reasonmap = $self->_groups_susp_reason_map;
my $userspec = '';
if ($r) {
diff --git a/httemplate/edit/REAL_cust_pkg.cgi b/httemplate/edit/REAL_cust_pkg.cgi
index 6f7f0d7db..b2c89c32c 100755
--- a/httemplate/edit/REAL_cust_pkg.cgi
+++ b/httemplate/edit/REAL_cust_pkg.cgi
@@ -44,10 +44,10 @@
<& .row_edit, cust_pkg=>$cust_pkg, column=>'setup', label=>'Setup' &>
<& .row_edit, cust_pkg=>$cust_pkg, column=>'last_bill', label=>$last_bill_or_renewed &>
<& .row_edit, cust_pkg=>$cust_pkg, column=>'bill', label=>$next_bill_or_prepaid_until &>
- <& .row_edit, cust_pkg=>$cust_pkg, column=>'adjourn', label=>'Adjournment', note=>'(will <b>suspend</b> this package when the date is reached)' &>
+ <& .row_display, cust_pkg=>$cust_pkg, column=>'adjourn', label=>'Adjournment', note=>'(will <b>suspend</b> this package when the date is reached)' &>
<& .row_display, cust_pkg=>$cust_pkg, column=>'susp', label=>'Suspension' &>
- <& .row_edit, cust_pkg=>$cust_pkg, column=>'expire', label=>'Expiration', note=>'(will <b>cancel</b> this package when the date is reached)' &>
+ <& .row_display, cust_pkg=>$cust_pkg, column=>'expire', label=>'Expiration', note=>'(will <b>cancel</b> this package when the date is reached)' &>
<& .row_display, cust_pkg=>$cust_pkg, column=>'cancel', label=>'Cancellation' &>
<%def .row_edit>
@@ -96,11 +96,16 @@
$cust_pkg
$column
$label
+ $note => ''
</%args>
% if ( $cust_pkg->get($column) ) {
<TR>
<TD ALIGN="right"><% $label %> date</TD>
- <TD BGCOLOR="#ffffff"><% time2str($format,$cust_pkg->get($column)) %></TD>
+ <TD BGCOLOR="#ffffff"><% time2str($format,$cust_pkg->get($column)) %>
+% if ( $note ) {
+ <BR><FONT SIZE=-1><% $note %></FONT>
+% }
+ </TD>
</TR>
% }
</%def>
diff --git a/httemplate/misc/process/cancel_pkg.html b/httemplate/misc/process/cancel_pkg.html
index d265c1849..669af9c87 100755
--- a/httemplate/misc/process/cancel_pkg.html
+++ b/httemplate/misc/process/cancel_pkg.html
@@ -46,6 +46,7 @@ if ($method eq 'expire' || $method eq 'adjourn'){
$date = $cgi->param('date');
str2time($cgi->param('date')) =~ /^(\d+)$/ or die "Illegal date";
$date = $1;
+ $method = ($method eq 'expire') ? 'cancel' : 'suspend';
}
my $cust_pkg = qsearchs( 'cust_pkg', {'pkgnum'=>$pkgnum} );
@@ -61,15 +62,7 @@ if ($reasonnum == -1) {
};
}
-my $error;
-if ($method eq 'expire' || $method eq 'adjourn'){
- my %hash = $cust_pkg->hash;
- $hash{$method} = $date;
- my $new = new FS::cust_pkg \%hash;
- $error = $new->replace($cust_pkg, 'reason' => $reasonnum);
-} else {
- $error = $cust_pkg->$method( 'reason' => $reasonnum );
-}
+my $error = $cust_pkg->$method( 'reason' => $reasonnum, 'date' => $date );
if ($error) {
$cgi->param('error', $error);
diff --git a/httemplate/misc/unadjourn_pkg.cgi b/httemplate/misc/unadjourn_pkg.cgi
new file mode 100755
index 000000000..356b49cb3
--- /dev/null
+++ b/httemplate/misc/unadjourn_pkg.cgi
@@ -0,0 +1,17 @@
+%if ( $error ) {
+% errorpage($error);
+%} else {
+<% $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum')) %>
+%}
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Suspend customer package later');
+
+my ($pkgnum) = $cgi->keywords;
+my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } );
+my $error = "No package $pkgnum" unless $cust_pkg;
+
+$error ||= $cust_pkg->unadjourn;
+
+</%init>
diff --git a/httemplate/misc/unexpire_pkg.cgi b/httemplate/misc/unexpire_pkg.cgi
new file mode 100755
index 000000000..445025524
--- /dev/null
+++ b/httemplate/misc/unexpire_pkg.cgi
@@ -0,0 +1,17 @@
+%if ( $error ) {
+% errorpage($error);
+%} else {
+<% $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum')) %>
+%}
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Cancel customer package later');
+
+my ($pkgnum) = $cgi->keywords;
+my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } );
+my $error = "No package $pkgnum" unless $cust_pkg;
+
+$error ||= $cust_pkg->unexpire;
+
+</%init>
diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi
index 6c63ed412..bd4a9466f 100755
--- a/httemplate/search/cust_pkg.cgi
+++ b/httemplate/search/cust_pkg.cgi
@@ -52,11 +52,10 @@
sub { my $self = shift;
my $return = '';
- if ($self->getfield('cancel') ||
- $self->getfield('suspend')) {
- my $reason = $self->last_reason;# too inefficient?
- $return = $reason->reason if $reason;
-
+ foreach my $action ( qw ( cancel susp ) ) {
+ my $reason = $self->last_reason($action);
+ $return = $reason->reason if $reason;
+ last if $return;
}
$return;
},
diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html
index 093cbfae6..44c5d6304 100755
--- a/httemplate/view/cust_main/packages.html
+++ b/httemplate/view/cust_main/packages.html
@@ -149,15 +149,12 @@ Current packages
%
%
% if ( $cust_pkg->get('cancel') ) { #status: cancelled
-% my $cpr = $cust_pkg->last_cust_pkg_reason;
+% my $cpr = $cust_pkg->last_cust_pkg_reason('cancel');
<% pkg_status_row($cust_pkg, 'Cancelled', 'cancel', 'color'=>'FF0000', conf=>$conf ) %>
<% pkg_status_row_colspan(
- ( ( $cpr && ( $cpr->date == $cust_pkg->get('cancel') ||
- $cpr->date == $cust_pkg->expire
- )
- ) ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
+ ( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
'align' => 'right', 'color' => 'ff0000', 'size' => '-2',
)
%>
@@ -178,15 +175,12 @@ Current packages
% } else {
%
% if ( $cust_pkg->get('susp') ) { #status: suspended
-% my $cpr = $cust_pkg->last_cust_pkg_reason;
+% my $cpr = $cust_pkg->last_cust_pkg_reason('susp');
<% pkg_status_row( $cust_pkg, 'Suspended', 'susp', 'color'=>'FF9900', conf=>$conf ) %>
<% pkg_status_row_colspan(
- ( ( $cpr && ( $cpr->date == $cust_pkg->susp ||
- $cpr->date == $cust_pkg->adjourn
- )
- ) ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
+ ( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
'align' => 'right', 'color' => 'FF9900', 'size' => '-2',
)
%>
@@ -418,7 +412,18 @@ sub pkg_status_row {
sub pkg_status_row_if {
my( $cust_pkg, $title, $field, %opt ) = @_;
- $cust_pkg->get($field) ? pkg_status_row(@_) : '';
+
+ $title = '<FONT SIZE=-1>(&nbsp;'. pkg_unadjourn_link($cust_pkg). '&nbsp;)&nbsp;</FONT>'. $title
+ if ( $field eq 'adjourn' &&
+ $curuser->access_right('Suspend customer package later')
+ );
+
+ $title = '<FONT SIZE=-1>(&nbsp;'. pkg_unexpire_link($cust_pkg). '&nbsp;)&nbsp;</FONT>'. $title
+ if ( $field eq 'expire' &&
+ $curuser->access_right('Cancel customer package later')
+ );
+
+ $cust_pkg->get($field) ? pkg_status_row($cust_pkg, $title, $field, %opt) : '';
}
sub pkg_status_row_changed {
@@ -566,6 +571,8 @@ sub pkg_adjourn_link { include( '/elements/popup_link-cust_pkg.html',
sub pkg_unsuspend_link { pkg_link('misc/unsusp_pkg', 'Unsuspend', @_ ); }
sub pkg_dates_link { pkg_link('edit/REAL_cust_pkg', 'Edit&nbsp;dates', @_ ); }
+sub unadjourn_link { pkg_link('misc/unadjourn_pkg', 'Abort', @_ ); }
+sub unexpire_link { pkg_link('misc/unexpire_pkg', 'Abort', @_ ); }
sub pkg_cancel_link { include( '/elements/popup_link-cust_pkg.html',
{ 'action' => $p. 'misc/cancel_pkg.html?method=cancel',