summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/Cron/bill.pm193
-rw-r--r--FS/FS/Schema.pm5
-rw-r--r--FS/FS/cust_main.pm51
-rw-r--r--FS/FS/cust_pkg.pm5
-rwxr-xr-xhttemplate/edit/REAL_cust_pkg.cgi1
-rwxr-xr-xhttemplate/edit/process/REAL_cust_pkg.cgi1
-rw-r--r--httemplate/edit/process/quick-charge.cgi4
-rw-r--r--httemplate/edit/quick-charge.html38
-rw-r--r--httemplate/view/cust_main/packages/status.html43
9 files changed, 237 insertions, 104 deletions
diff --git a/FS/FS/Cron/bill.pm b/FS/FS/Cron/bill.pm
index 29f5f36c9..61b47355a 100644
--- a/FS/FS/Cron/bill.pm
+++ b/FS/FS/Cron/bill.pm
@@ -13,10 +13,16 @@ use FS::part_event;
use FS::part_event_condition;
@ISA = qw( Exporter );
-@EXPORT_OK = qw ( bill );
+@EXPORT_OK = qw ( bill bill_where );
-sub bill {
+#freeside-daily %opt:
+# -s: re-charge setup fees
+# -v: enable debugging
+# -l: debugging level
+# -m: Experimental multi-process mode uses the job queue for multi-process and/or multi-machine billing.
+# -r: Multi-process mode dry run option
+sub bill {
my %opt = @_;
my $check_freq = $opt{'check_freq'} || '1d';
@@ -24,91 +30,24 @@ sub bill {
my $debug = 0;
$debug = 1 if $opt{'v'};
$debug = $opt{'l'} if $opt{'l'};
-
$FS::cust_main::DEBUG = $debug;
#$FS::cust_event::DEBUG = $opt{'l'} if $opt{'l'};
- my @search = ();
-
- push @search, "( cust_main.archived != 'Y' OR archived IS NULL )"; #disable?
-
- push @search, "cust_main.payby = '". $opt{'p'}. "'"
- if $opt{'p'};
- push @search, "cust_main.agentnum = ". $opt{'a'}
- if $opt{'a'};
-
- if ( @ARGV ) {
- push @search, "( ".
- join(' OR ', map "cust_main.custnum = $_", @ARGV ).
- " )";
- }
-
- ###
- # generate where_pkg/where_event search clause
- ###
-
#we're at now now (and later).
- my($time)= $opt{'d'} ? str2time($opt{'d'}) : $^T;
- $time += $opt{'y'} * 86400 if $opt{'y'};
-
- my $invoice_time = $opt{'n'} ? $^T : $time;
+ $opt{'time'} = $opt{'d'} ? str2time($opt{'d'}) : $^T;
+ $opt{'time'} += $opt{'y'} * 86400 if $opt{'y'};
- # select * from cust_main where
- my $where_pkg = <<"END";
- 0 < ( select count(*) from cust_pkg
- where cust_main.custnum = cust_pkg.custnum
- and ( cancel is null or cancel = 0 )
- and ( setup is null or setup = 0
- or bill is null or bill <= $time
- or ( expire is not null and expire <= $^T )
- or ( adjourn is not null and adjourn <= $^T )
- )
- )
-END
-
- my $where_event = join(' OR ', map {
- my $eventtable = $_;
-
- my $join = FS::part_event_condition->join_conditions_sql( $eventtable );
- my $where = FS::part_event_condition->where_conditions_sql( $eventtable,
- 'time'=>$time,
- );
-
- my $are_part_event =
- "0 < ( SELECT COUNT(*) FROM part_event $join
- WHERE check_freq = '$check_freq'
- AND eventtable = '$eventtable'
- AND ( disabled = '' OR disabled IS NULL )
- AND $where
- )
- ";
-
- if ( $eventtable eq 'cust_main' ) {
- $are_part_event;
- } else {
- "0 < ( SELECT COUNT(*) FROM $eventtable
- WHERE cust_main.custnum = $eventtable.custnum
- AND $are_part_event
- )
- ";
- }
-
- } FS::part_event->eventtables);
-
- push @search, "( $where_pkg OR $where_event )";
+ $opt{'invoice_time'} = $opt{'n'} ? $^T : $opt{'time'};
###
# get a list of custnums
###
- warn "searching for customers:\n". join("\n", @search). "\n"
- if $opt{'v'} || $opt{'l'};
-
my $cursor_dbh = dbh->clone;
$cursor_dbh->do(
"DECLARE cron_bill_cursor CURSOR FOR ".
- " SELECT custnum FROM cust_main WHERE ". join(' AND ', @search)
+ " SELECT custnum FROM cust_main WHERE ". bill_where( %opt )
) or die $cursor_dbh->errstr;
while ( 1 ) {
@@ -129,8 +68,8 @@ END
foreach my $custnum ( @custnums ) {
my %args = (
- 'time' => $time,
- 'invoice_time' => $invoice_time,
+ 'time' => $opt{'time'},
+ 'invoice_time' => $opt{'invoice_time'},
'actual_time' => $^T, #when freeside-bill was started
#(not, when using -m, freeside-queued)
'check_freq' => $check_freq,
@@ -175,4 +114,108 @@ END
}
+# freeside-daily %opt:
+# -d: Pretend it's 'date'. Date is in any format Date::Parse is happy with,
+# but be careful.
+#
+# -y: In addition to -d, which specifies an absolute date, the -y switch
+# specifies an offset, in days. For example, "-y 15" would increment the
+# "pretend date" 15 days from whatever was specified by the -d switch
+# (or now, if no -d switch was given).
+#
+# -n: When used with "-d" and/or "-y", specifies that invoices should be dated
+# with today's date, irregardless of the pretend date used to pre-generate
+# the invoices.
+#
+# -p: Only process customers with the specified payby (I<CARD>, I<DCRD>, I<CHEK>, I<DCHK>, I<BILL>, I<COMP>, I<LECB>)
+#
+# -a: Only process customers with the specified agentnum
+#
+# -v: enable debugging
+#
+# -l: debugging level
+
+sub bill_where {
+ my( %opt ) = @_;
+
+ my $time = $opt{'time'};
+ my $invoice_time = $opt{'invoice_time'};
+
+ my $check_freq = $opt{'check_freq'} || '1d';
+
+ my @search = ();
+
+ push @search, "( cust_main.archived != 'Y' OR archived IS NULL )"; #disable?
+
+ push @search, "cust_main.payby = '". $opt{'p'}. "'"
+ if $opt{'p'};
+ push @search, "cust_main.agentnum = ". $opt{'a'}
+ if $opt{'a'};
+
+ if ( @ARGV ) {
+ push @search, "( ".
+ join(' OR ', map "cust_main.custnum = $_", @ARGV ).
+ " )";
+ }
+
+ ###
+ # generate where_pkg/where_event search clause
+ ###
+
+ # select * from cust_main where
+ my $where_pkg = <<"END";
+ EXISTS(
+ SELECT 1 FROM cust_pkg
+ WHERE cust_main.custnum = cust_pkg.custnum
+ AND ( cancel IS NULL OR cancel = 0 )
+ AND ( ( ( setup IS NULL OR setup = 0 )
+ AND ( start_date IS NULL OR start_date = 0
+ OR ( start_date IS NOT NULL AND start_date <= $^T )
+ )
+ )
+ OR bill IS NULL OR bill <= $time
+ OR ( expire IS NOT NULL AND expire <= $^T )
+ OR ( adjourn IS NOT NULL AND adjourn <= $^T )
+ )
+ )
+END
+
+ my $where_event = join(' OR ', map {
+ my $eventtable = $_;
+
+ my $join = FS::part_event_condition->join_conditions_sql( $eventtable );
+ my $where = FS::part_event_condition->where_conditions_sql( $eventtable,
+ 'time'=>$time,
+ );
+
+ my $are_part_event =
+ "EXISTS ( SELECT 1 FROM part_event $join
+ WHERE check_freq = '$check_freq'
+ AND eventtable = '$eventtable'
+ AND ( disabled = '' OR disabled IS NULL )
+ AND $where
+ )
+ ";
+
+ if ( $eventtable eq 'cust_main' ) {
+ $are_part_event;
+ } else {
+ "EXISTS ( SELECT 1 FROM $eventtable
+ WHERE cust_main.custnum = $eventtable.custnum
+ AND $are_part_event
+ )
+ ";
+ }
+
+ } FS::part_event->eventtables);
+
+ push @search, "( $where_pkg OR $where_event )";
+
+ warn "searching for customers:\n". join("\n", @search). "\n"
+ if $opt{'v'} || $opt{'l'};
+
+ join(' AND ', @search);
+
+}
+
1;
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 4351f2876..3c203b9d1 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -1085,6 +1085,7 @@ sub tables_hashref {
'pkgpart', 'int', '', '', '', '',
'locationnum', 'int', 'NULL', '', '', '',
'otaker', 'varchar', '', 32, '', '',
+ 'start_date', @date_type, '', '',
'setup', @date_type, '', '',
'bill', @date_type, '', '',
'last_bill', @date_type, '', '',
@@ -1102,8 +1103,8 @@ sub tables_hashref {
'primary_key' => 'pkgnum',
'unique' => [],
'index' => [ ['custnum'], ['pkgpart'], [ 'locationnum' ],
- ['setup'], ['last_bill'], ['bill'], ['susp'], ['adjourn'],
- ['expire'], ['cancel'],
+ [ 'start_date' ], ['setup'], ['last_bill'], ['bill'],
+ ['susp'], ['adjourn'], ['expire'], ['cancel'],
['change_date'],
],
},
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index e5f289ca3..5768bebf9 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -9,6 +9,7 @@ use Safe;
use Carp;
use Exporter;
use Scalar::Util qw( blessed );
+use List::Util qw( min );
use Time::Local qw(timelocal);
use Data::Dumper;
use Tie::IxHash;
@@ -2056,6 +2057,18 @@ sub unsuspended_pkgs {
grep { ! $_->susp } $self->ncancelled_pkgs;
}
+=item next_bill_date
+
+Returns the next date this customer will be billed, as a UNIX timestamp, or
+undef if no active package has a next bill date.
+
+=cut
+
+sub next_bill_date {
+ my $self = shift;
+ min( map $_->get('bill'), grep $_->get('bill'), $self->unsuspended_pkgs );
+}
+
=item num_cancelled_pkgs
Returns the number of cancelled packages (see L<FS::cust_pkg>) for this
@@ -2760,14 +2773,19 @@ sub _make_lines {
my $setup = 0;
my $unitsetup = 0;
- if ( ! $cust_pkg->setup &&
- (
- ( $conf->exists('disable_setup_suspended_pkgs') &&
- ! $cust_pkg->getfield('susp')
- ) || ! $conf->exists('disable_setup_suspended_pkgs')
- )
- || $options{'resetup'}
- ) {
+ if ( $options{'resetup'}
+ || ( ! $cust_pkg->setup
+ && ( ! $cust_pkg->start_date
+ || $cust_pkg->start_date <= $time
+ )
+ && ( ! $conf->exists('disable_setup_suspended_pkgs')
+ || ( $conf->exists('disable_setup_suspended_pkgs') &&
+ ! $cust_pkg->getfield('susp')
+ )
+ )
+ )
+ )
+ {
warn " bill setup\n" if $DEBUG > 1;
$lineitems++;
@@ -2783,6 +2801,9 @@ sub _make_lines {
#do need it, but it won't get written to the db
#|| $cust_pkg->pkgpart != $real_pkgpart;
+ $cust_pkg->setfield('start_date', '')
+ if $cust_pkg->start_date;
+
}
###
@@ -6727,12 +6748,14 @@ the error, otherwise returns false.
sub charge {
my $self = shift;
- my ( $amount, $quantity, $pkg, $comment, $classnum, $additional );
+ my ( $amount, $quantity, $start_date, $classnum );
+ my ( $pkg, $comment, $additional );
my ( $setuptax, $taxclass ); #internal taxes
my ( $taxproduct, $override ); #vendor (CCH) taxes
if ( ref( $_[0] ) ) {
$amount = $_[0]->{amount};
$quantity = exists($_[0]->{quantity}) ? $_[0]->{quantity} : 1;
+ $start_date = exists($_[0]->{start_date}) ? $_[0]->{start_date} : '';
$pkg = exists($_[0]->{pkg}) ? $_[0]->{pkg} : 'One-time charge';
$comment = exists($_[0]->{comment}) ? $_[0]->{comment}
: '$'. sprintf("%.2f",$amount);
@@ -6742,9 +6765,10 @@ sub charge {
$additional = $_[0]->{additional};
$taxproduct = $_[0]->{taxproductnum};
$override = { '' => $_[0]->{tax_override} };
- }else{
+ } else {
$amount = shift;
$quantity = 1;
+ $start_date = '';
$pkg = @_ ? shift : 'One-time charge';
$comment = @_ ? shift : '$'. sprintf("%.2f",$amount);
$setuptax = '';
@@ -6802,9 +6826,10 @@ sub charge {
}
my $cust_pkg = new FS::cust_pkg ( {
- 'custnum' => $self->custnum,
- 'pkgpart' => $pkgpart,
- 'quantity' => $quantity,
+ 'custnum' => $self->custnum,
+ 'pkgpart' => $pkgpart,
+ 'quantity' => $quantity,
+ 'start_date' => $start_date,
} );
$error = $cust_pkg->insert;
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index 881e005de..d2f0690eb 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -122,6 +122,10 @@ Billing item definition (see L<FS::part_pkg>)
Optional link to package location (see L<FS::location>)
+=item start_date
+
+date
+
=item setup
date
@@ -479,6 +483,7 @@ sub check {
|| $self->ut_foreign_key('custnum', 'cust_main', 'custnum')
|| $self->ut_numbern('pkgpart')
|| $self->ut_foreign_keyn('locationnum', 'cust_location', 'locationnum')
+ || $self->ut_numbern('start_date')
|| $self->ut_numbern('setup')
|| $self->ut_numbern('bill')
|| $self->ut_numbern('susp')
diff --git a/httemplate/edit/REAL_cust_pkg.cgi b/httemplate/edit/REAL_cust_pkg.cgi
index a707aca8d..5752c8dd8 100755
--- a/httemplate/edit/REAL_cust_pkg.cgi
+++ b/httemplate/edit/REAL_cust_pkg.cgi
@@ -46,6 +46,7 @@
<TD BGCOLOR="#ffffff"><% $cust_pkg->otaker %></TD>
</TR>
+ <& .row_edit, cust_pkg=>$cust_pkg, column=>'start_date', label=>'Start' &>
<& .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 &>
diff --git a/httemplate/edit/process/REAL_cust_pkg.cgi b/httemplate/edit/process/REAL_cust_pkg.cgi
index c99ddc288..d4ba976c4 100755
--- a/httemplate/edit/process/REAL_cust_pkg.cgi
+++ b/httemplate/edit/process/REAL_cust_pkg.cgi
@@ -19,6 +19,7 @@ die "access denied"
my $pkgnum = $cgi->param('pkgnum') or die;
my $old = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
my %hash = $old->hash;
+$hash{'start_date'} = $cgi->param('start_date') ? str2time($cgi->param('start_date')) : '';
$hash{'setup'} = $cgi->param('setup') ? str2time($cgi->param('setup')) : '';
$hash{'bill'} = $cgi->param('bill') ? str2time($cgi->param('bill')) : '';
$hash{'last_bill'} =
diff --git a/httemplate/edit/process/quick-charge.cgi b/httemplate/edit/process/quick-charge.cgi
index 470cd4b5b..8f0e42471 100644
--- a/httemplate/edit/process/quick-charge.cgi
+++ b/httemplate/edit/process/quick-charge.cgi
@@ -55,6 +55,10 @@ unless ( $error ) {
$error ||= $cust_main->charge( {
'amount' => $amount,
'quantity' => $quantity,
+ 'start_date' => ( scalar($cgi->param('start_date'))
+ ? str2time($cgi->param('start_date'))
+ : ''
+ ),
'pkg' => scalar($cgi->param('pkg')),
'setuptax' => scalar($cgi->param('setuptax')),
'taxclass' => scalar($cgi->param('taxclass')),
diff --git a/httemplate/edit/quick-charge.html b/httemplate/edit/quick-charge.html
index 8aca34a0d..ad26bff66 100644
--- a/httemplate/edit/quick-charge.html
+++ b/httemplate/edit/quick-charge.html
@@ -3,6 +3,11 @@
)
%>
+<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') %>
<SCRIPT TYPE="text/javascript">
@@ -79,6 +84,33 @@ function validate_quick_charge () {
<% include('/elements/tr-select-pkg_class.html', 'curr_value' => $cgi->param('classnum') ) %>
+<TR>
+ <TD ALIGN="right">Charge date </TD>
+ <TD>
+ <INPUT TYPE = "text"
+ NAME = "start_date"
+ SIZE = 32
+ ID = "start_date_text"
+ VALUE = "<% $start_date %>"
+ >
+ <IMG SRC = "../images/calendar.png"
+ ID = "start_date_button"
+ STYLE = "cursor: pointer"
+ TITLE = "Select date"
+ >
+ <FONT SIZE=-1>(leave blank to charge immediately)</FONT>
+ </TD>
+</TR>
+
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "start_date_text",
+ ifFormat: "%m/%d/%Y",
+ button: "start_date_button",
+ align: "BR"
+ });
+</SCRIPT>
+
<TR>
<TD ALIGN="right">Tax exempt </TD>
@@ -179,6 +211,12 @@ my $conf = new FS::Conf;
$cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum';
my $custnum = $1;
+my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ); #XXX agent-virt
+
+my $format = "%m/%d/%Y %T %z (%Z)"; #false laziness w/REAL_cust_pkg.cgi?
+my $start_date = $cust_main->next_bill_date;
+warn "*** $start_date";
+$start_date = $start_date ? time2str($format, $start_date) : '';
my $amount = '';
if ( $cgi->param('amount') =~ /^\s*\$?\s*(\d+(\.\d{1,2})?)\s*$/ ) {
diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html
index 141ed156d..6daff5031 100644
--- a/httemplate/view/cust_main/packages/status.html
+++ b/httemplate/view/cust_main/packages/status.html
@@ -10,18 +10,18 @@
<% pkg_status_row_colspan(
( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
- 'align' => 'right', 'color' => 'ff0000', 'size' => '-2',
+ 'align'=>'right', 'color'=>'ff0000', 'size'=>'-2', 'colspan'=>$colspan,
)
%>
% unless ( $cust_pkg->get('setup') ) {
- <% pkg_status_row_colspan('Never billed') %>
+ <% pkg_status_row_colspan('Never billed', '', 'colspan'=>$colspan, ) %>
% } else {
<% pkg_status_row( $cust_pkg, 'Setup', 'setup', %opt ) %>
- <% pkg_status_row_changed( $cust_pkg, %opt ) %>
+ <% pkg_status_row_changed( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
<% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
<% pkg_status_row_if( $cust_pkg, 'Suspended', 'susp', %opt, curuser=>$curuser ) %>
@@ -36,17 +36,17 @@
<% pkg_status_row_colspan(
( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
- 'align' => 'right', 'color' => 'FF9900', 'size' => '-2',
+ 'align'=>'right', 'color'=>'FF9900', 'size'=>'-2', 'colspan'=>$colspan,
)
%>
% unless ( $cust_pkg->get('setup') ) {
- <% pkg_status_row_colspan('Never billed') %>
+ <% pkg_status_row_colspan('Never billed', '', 'colspan'=>$colspan ) %>
% } else {
<% pkg_status_row($cust_pkg, 'Setup', 'setup', %opt ) %>
% }
- <% pkg_status_row_changed( $cust_pkg, %opt ) %>
+ <% pkg_status_row_changed( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
<% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
% # pkg_status_row($cust_pkg, 'Next bill', 'bill', %opt)
<% pkg_status_row_if( $cust_pkg, 'Expires', 'expire', %opt, curuser=>$curuser ) %>
@@ -70,7 +70,9 @@
%
% unless ( $part_pkg->freq ) {
- <% pkg_status_row_colspan('Not&nbsp;yet&nbsp;billed&nbsp;(one-time&nbsp;charge)') %>
+ <% pkg_status_row_colspan('Not&nbsp;yet&nbsp;billed&nbsp;(one-time&nbsp;charge)', '', 'colspan'=>$colspan, ) %>
+
+ <% pkg_status_row_if($cust_pkg, 'Start billing', 'start_date', %opt) %>
<TR>
<TD COLSPAN=<%$colspan%>>
@@ -84,7 +86,9 @@
% } else {
- <% pkg_status_row_colspan("Not&nbsp;yet&nbsp;billed&nbsp;($billed_or_prepaid&nbsp;". myfreq($part_pkg). ')' ) %>
+ <% pkg_status_row_colspan("Not&nbsp;yet&nbsp;billed&nbsp;($billed_or_prepaid&nbsp;". myfreq($part_pkg). ')', '', 'colspan'=>$colspan ) %>
+
+ <% pkg_status_row_if($cust_pkg, 'Start billing', 'start_date', %opt) %>
% }
%
@@ -92,7 +96,7 @@
%
% unless ( $part_pkg->freq ) {
- <% pkg_status_row_colspan('One-time&nbsp;charge') %>
+ <% pkg_status_row_colspan('One-time&nbsp;charge', '', 'colspan'=>$colspan, ) %>
<% pkg_status_row($cust_pkg, 'Billed', 'setup', %opt) %>
@@ -103,7 +107,7 @@
<% pkg_status_row_colspan(
'Overlimit',
$billed_or_prepaid. '&nbsp;'. myfreq($part_pkg),
- 'color' => 'FFD000',
+ 'color'=>'FFD000', 'colspan'=>$colspan,
)
%>
@@ -111,7 +115,7 @@
<% pkg_status_row_colspan(
'Active',
$billed_or_prepaid. '&nbsp;'. myfreq($part_pkg),
- 'color' => '00CC00',
+ 'color'=>'00CC00', 'colspan'=>$colspan,
)
%>
% }
@@ -127,7 +131,7 @@
% $cust_pkg->set('autosuspend', $autosuspend) if $autosuspend;
% }
- <% pkg_status_row_changed( $cust_pkg, %opt ) %>
+ <% pkg_status_row_changed( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
<% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
<% pkg_status_row_if( $cust_pkg, $next_bill_or_prepaid_until, 'bill', %opt, curuser=>$curuser ) %>
<% pkg_status_row_if($cust_pkg, 'Will automatically suspend by', 'autosuspend', %opt) %>
@@ -238,21 +242,32 @@ sub pkg_status_row_if {
sub pkg_status_row_changed {
my( $cust_pkg, %opt ) = @_;
+
return '' unless $cust_pkg->change_date;
- my $html = pkg_status_row( $cust_pkg, 'Package&nbsp;changed', 'change_date', %opt );
+
+ my $html =
+ pkg_status_row( $cust_pkg, 'Package&nbsp;changed', 'change_date', %opt );
+
my $old = $cust_pkg->old_cust_pkg;
if ( $old ) {
my $part_pkg = $old->part_pkg;
my $label = 'Changed from '. $cust_pkg->change_pkgnum. ': '.
$part_pkg->pkg_comment(nopartpkg => 1);
- $html .= pkg_status_row_colspan( $label, '', size=>'-1', align=>'right' );
+ $html .= pkg_status_row_colspan( $label, '',
+ 'size' => '-1',
+ 'align' => 'right',
+ 'colspan' => $opt{'colspan'},
+ );
}
+
$html;
}
sub pkg_status_row_colspan {
my($title, $addl, %opt) = @_;
+ my $colspan = $opt{'colspan'};
+
my $align = $opt{'align'} ? 'ALIGN="'. $opt{'align'}.'"' : '';
my $color = $opt{'color'} ? 'COLOR="#'.$opt{'color'}.'"' : '';
my $size = $opt{'size'} ? 'SIZE="'. $opt{'size'}. '"' : '';