'Unsuspend customer package',
'Cancel customer package immediately',
'Cancel customer package later',
+ 'Delay suspension events',
'Add on-the-fly cancel reason', #NEW
'Add on-the-fly suspend reason', #NEW
'Edit customer package invoice details', #NEW
'stateid_state', 'varchar', 'NULL', $char_d, '', '',
'birthdate' ,@date_type, '', '',
'signupdate',@date_type, '', '',
+ 'dundate', @date_type, '', '',
'company', 'varchar', 'NULL', $char_d, '', '',
'address1', 'varchar', '', $char_d, '', '',
'address2', 'varchar', 'NULL', $char_d, '', '',
=item spool_cdr - Enable individual CDR spooling, empty or `Y'
+=item dundate - a suggestion to events (see L<FS::part_bill_event">) to delay until this unix timestamp
+
=item squelch_cdr - Discourage individual CDR printing, empty or `Y'
=back
# 3: insert
##
- foreach my $cust_event ( @cust_event ) {
+ unless( $opt{testonly} ) {
+ foreach my $cust_event ( @cust_event ) {
- my $error = $cust_event->insert();
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
+ my $error = $cust_event->insert();
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
}
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
use Carp qw(cluck confess);
use FS::Record qw( dbh qsearch qsearchs );
use FS::Conf;
+use FS::cust_main;
+use FS::cust_bill;
@ISA = qw( FS::Record );
@EXPORT_OK = qw( due_events );
sort { $a->seconds <=> $b->seconds
|| $a->weight <=> $b->weight
|| $a->eventpart <=> $b->eventpart }
+ grep { ref($record) ne 'FS::cust_bill' || $_->eventcode !~ /honor_dundate/
+ || $event_time > $record->cust_main->dundate
+ }
grep { $_->seconds <= ( $interval )
&& ! qsearch( 'cust_bill_event', {
'invnum' => $record->get($record->dbdef_table->primary_key),
--- /dev/null
+package FS::part_event::Condition::dundate;
+
+use strict;
+
+use base qw( FS::part_event::Condition );
+
+sub description {
+ "Skip until customer dun date is reached";
+}
+
+sub condition {
+ my($self, $object, %opt) = @_;
+
+ my $cust_main = $self->cust_main($object);
+
+ $cust_main->dundate <= $opt{time};
+
+}
+
+#sub condition_sql {
+# my( $self, $table ) = @_;
+#
+# 'true';
+#}
+
+1;
% '</SELECT>';
%}
%
+%sub honor_dundate {
+% my $label = shift;
+% my $plandata = shift;
+% '<TABLE>'.
+% '<TR><TD ALIGN="right">Allow delay until dun date? </TD>'.
+% qq(<TD><INPUT TYPE="checkbox" NAME="$label" VALUE="$label => 1," ).
+% ( $plandata->{$label} eq "$label => 1," ? 'CHECKED' : '' ).
+% '>'.
+% '</TD></TR>'.
+% '</TABLE>'
+%}
+%
%my $conf = new FS::Conf;
%my $money_char = $conf->config('money_char') || '$';
%
% },
% 'suspend' => {
% 'name' => 'Suspend',
-% 'code' => '$cust_main->suspend(reason => %%%sreason%%%);',
+% 'code' => '$cust_main->suspend(reason => %%%sreason%%%, %%%honor_dundate%%% );',
+% 'html' => sub { &honor_dundate('honor_dundate', @_) },
% 'weight' => 10,
% 'reason' => 'S',
% },
% 'suspend-if-balance' => {
% 'name' => 'Suspend if balance (this invoice and previous) over',
-% 'code' => '$cust_bill->cust_suspend_if_balance_over( %%%balanceover%%%, reason => %%%sreason%%%, );',
-% 'html' => " $money_char ". '<INPUT TYPE="text" SIZE="7" NAME="balanceover" VALUE="%%%balanceover%%%">',
+% 'code' => '$cust_bill->cust_suspend_if_balance_over( %%%balanceover%%%, reason => %%%sreason%%%, %%%balance_honor_dundate%%% );',
+% 'html' => sub { " $money_char ". '<INPUT TYPE="text" SIZE="7" NAME="balanceover" VALUE="%%%balanceover%%%"> '. &honor_dundate('balance_honor_dundate', @_) },
% 'weight' => 10,
% 'reason' => 'S',
% },
% 'suspend-if-pkgpart' => {
% 'name' => 'Suspend packages',
-% 'code' => '$cust_main->suspend_if_pkgpart({pkgparts => [%%%if_pkgpart%%%,], reason => %%%sreason%%%,});',
-% 'html' => sub { &select_pkgpart('if_pkgpart', @_) },
+% 'code' => '$cust_main->suspend_if_pkgpart({pkgparts => [%%%if_pkgpart%%%,], reason => %%%sreason%%%, %%%if_pkgpart_honor_dundate%%% });',
+% 'html' => sub { &select_pkgpart('if_pkgpart', @_). &honor_dundate('if_pkgpart_honor_dundate', @_) },
% 'weight' => 10,
% 'reason' => 'S',
% },
% 'suspend-unless-pkgpart' => {
% 'name' => 'Suspend packages except',
-% 'code' => '$cust_main->suspend_unless_pkgpart({unless_pkgpart => [%%%unless_pkgpart%%%], reason => %%%sreason%%%,});',
-% 'html' => sub { &select_pkgpart('unless_pkgpart', @_) },
+% 'code' => '$cust_main->suspend_unless_pkgpart({unless_pkgpart => [%%%unless_pkgpart%%%], reason => %%%sreason%%%, %%%unless_pkgpart_honor_dundate%%% });',
+% 'html' => sub { &select_pkgpart('unless_pkgpart', @_). &honor_dundate('unless_pkgpart_honor_dundate' => @_) },
% 'weight' => 10,
% 'reason' => 'S',
% },
--- /dev/null
+%# if ( $link eq 'popup' ) {
+ <% include('/elements/header-popup.html', $title ) %>
+%# } else {
+%# <% include("/elements/header.html", $title, '') %>
+%# }
+
+<LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT>
+
+<% include('/elements/error.html') %>
+
+<FORM NAME="ds_popup" ACTION="<% popurl(1) %>process/delay_susp_pkg.html" METHOD=POST>
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>">
+
+<BR><BR>
+<% "Delay automatic suspension of $pkgnum: " .$part_pkg->pkg. ' - ' .$part_pkg->comment %>
+<% ntable("#cccccc", 2) %>
+
+<TR>
+ <TD>Delay until</TD>
+ <TD><INPUT TYPE="text" NAME="date" ID="dun_date" VALUE="<% $date |h %>">
+ <IMG SRC="<% $p %>images/calendar.png" ID="dun_button" STYLE="cursor:pointer" TITLE="Select date">
+ <BR><I>m/d/y</I>
+ </TD>
+</TR>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "dun_date",
+ ifFormat: "%m/%d/%Y",
+ button: "dun_button",
+ align: "BR"
+ });
+</SCRIPT>
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" NAME="submit" VALUE="<% $submit %>">
+
+</FORM>
+</BODY>
+</HTML>
+
+<%init>
+
+my $date = time2str("%m/%d/%Y", time);
+
+my($pkgnum);
+if ( $cgi->param('error') ) {
+ $pkgnum = $cgi->param('pkgnum');
+ $date = $cgi->param('date');
+} elsif ( $cgi->param('pkgnum') =~ /^(\d+)$/ ) {
+ $pkgnum = $1;
+} else {
+ die "illegal query ". $cgi->keywords;
+}
+
+my $submit = 'Delay Suspension';
+my $right = 'Delay suspension events';
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+die "access denied" unless $curuser->access_right($right);
+
+my $title = 'Delay Suspension of Package';
+
+my $cust_pkg = qsearchs('cust_pkg', {'pkgnum' => $pkgnum})
+ or die "Unknown pkgnum: $pkgnum";
+
+my $part_pkg = $cust_pkg->part_pkg;
+
+</%init>
--- /dev/null
+<% header("Package suspension delayed") %>
+ <SCRIPT TYPE="text/javascript">
+ window.top.location.reload();
+ </SCRIPT>
+ </BODY>
+</HTML>
+<%once>
+
+my $right = 'Delay suspension events';
+
+</%once>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right($right);
+
+my ($pkgnum, $date, $cust_pkg, $cust_main, $error);
+
+#untaint pkgnum
+$cgi->param('pkgnum') =~ /^(\d+)$/ or die "Illegal pkgnum";
+$pkgnum = $1;
+
+#untaint date
+str2time($cgi->param('date')) =~ /^(\d+)$/ or die "Illegal date";
+my $date = $1;
+
+$cust_pkg = qsearchs( 'cust_pkg', {'pkgnum'=>$pkgnum} );
+if ($cust_pkg) {
+ $cust_main = $cust_pkg->cust_main;
+ $cust_main->dundate( $date );
+ $error = $cust_main->replace;
+} else {
+ $error = "Invalid pkgnum";
+}
+
+if ($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "cancel_pkg.html?". $cgi->query_string );
+}
+
+</%init>
% }
%
% }
+% my $autosuspend = pkg_autosuspend_time( $cust_pkg );
+% $cust_pkg->set('autosuspend', $autosuspend) if $autosuspend;
<% pkg_status_row_changed( $cust_pkg, conf=>$conf ) %>
<% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', conf=>$conf, curuser=>$curuser ) %>
<% pkg_status_row_if( $cust_pkg, $next_bill_or_prepaid_until, 'bill', conf=>$conf, curuser=>$curuser ) %>
+ <% pkg_status_row_if($cust_pkg, 'Will automatically suspend by', 'autosuspend', conf=>$conf) %>
<% pkg_status_row_if( $cust_pkg, 'Will suspend on', 'adjourn', conf=>$conf, curuser=>$curuser ) %>
<% pkg_status_row_if( $cust_pkg, 'Expires', 'expire', conf=>$conf, curuser=>$curuser ) %>
% if ( $curuser->access_right('Suspend customer package later') ) {
( <% pkg_adjourn_link($cust_pkg) %> )
% }
+% if ( $curuser->access_right('Delay suspension events') ) {
+ ( <% pkg_delay_link($cust_pkg) %> )
+% }
% if ( $curuser->access_right('Cancel customer package immediately') ) {
( <% pkg_cancel_link($cust_pkg) %> )
% }
)
}
+sub pkg_delay_link { include( '/elements/popup_link-cust_pkg.html',
+ { 'action' => $p. 'misc/delay_susp_pkg.html',
+ 'label' => 'Delay suspend',
+ 'actionlabel' => 'Delay suspend for',
+ 'cust_pkg' => shift,
+ }
+ )
+ }
+
sub pkg_unsuspend_link { pkg_link('misc/unsusp_pkg', 'Unsuspend', @_ ); }
sub pkg_dates_link { pkg_link('edit/REAL_cust_pkg', 'Edit dates', @_ ); }
-sub pkg_unadjourn_link { pkg_link('misc/unadjourn_pkg', 'Abort', @_ ); }
-sub pkg_unexpire_link { pkg_link('misc/unexpire_pkg', 'Abort', @_ ); }
+sub pkg_unadjourn_link { pkg_link('misc/unadjourn_pkg', 'Abort', @_ ); }
+sub pkg_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',
qq!">Customize</A>!;
}
+sub pkg_autosuspend_time {
+ my $cust_pkg = shift or return '';
+ my $days = 7;
+ my $time = time;
+ my $pending_suspend = 0;
+ while ( $days > 0 &&
+ scalar(
+ grep { $_->part_event->action eq 'suspend' }
+ @{$cust_pkg->cust_main->due_cust_event( time => $time + 86400*$days,
+ testonly => 1,
+ ) }
+ )
+ )
+ {
+ $pending_suspend = 1;
+ $days--;
+ }
+
+ $pending_suspend ? time + ($days + 1) * 86400 : '';
+
+}
</%init>