summaryrefslogtreecommitdiff
path: root/httemplate/view
diff options
context:
space:
mode:
Diffstat (limited to 'httemplate/view')
-rw-r--r--httemplate/view/attachment.html16
-rwxr-xr-xhttemplate/view/cust_bill-logo.cgi2
-rwxr-xr-xhttemplate/view/cust_bill-pdf.cgi22
-rwxr-xr-xhttemplate/view/cust_bill-ps.cgi21
-rwxr-xr-xhttemplate/view/cust_bill.cgi73
-rwxr-xr-xhttemplate/view/cust_main.cgi134
-rwxr-xr-xhttemplate/view/cust_main/attachments.html151
-rw-r--r--httemplate/view/cust_main/billing.html37
-rw-r--r--httemplate/view/cust_main/change_history.html302
-rw-r--r--httemplate/view/cust_main/misc.html19
-rw-r--r--httemplate/view/cust_main/one_time_charge_link.html91
-rwxr-xr-xhttemplate/view/cust_main/packages.html214
-rw-r--r--httemplate/view/cust_main/packages/package.html23
-rw-r--r--httemplate/view/cust_main/packages/services.html28
-rw-r--r--httemplate/view/cust_main/packages/status.html86
-rw-r--r--httemplate/view/cust_main/payment_history.html51
-rw-r--r--httemplate/view/cust_main/payment_history/credit.html14
-rw-r--r--httemplate/view/cust_main/payment_history/invoice.html19
-rw-r--r--httemplate/view/cust_main/payment_history/payment.html14
-rw-r--r--httemplate/view/cust_main/payment_history/statement.html34
-rw-r--r--httemplate/view/cust_main/payment_history/voided_payment.html27
-rw-r--r--httemplate/view/cust_main/tickets.html3
-rw-r--r--httemplate/view/cust_pay.html41
-rw-r--r--httemplate/view/cust_pay_void.html1
-rwxr-xr-xhttemplate/view/cust_statement-pdf.cgi28
-rwxr-xr-xhttemplate/view/cust_statement.html79
-rw-r--r--httemplate/view/elements/svc_Common.html63
-rw-r--r--httemplate/view/svc_Common.html12
-rwxr-xr-xhttemplate/view/svc_acct.cgi2
-rw-r--r--httemplate/view/svc_broadband.cgi59
-rwxr-xr-xhttemplate/view/svc_domain.cgi57
-rw-r--r--httemplate/view/svc_phone.cgi75
32 files changed, 1486 insertions, 312 deletions
diff --git a/httemplate/view/attachment.html b/httemplate/view/attachment.html
new file mode 100644
index 0000000..5fc0539
--- /dev/null
+++ b/httemplate/view/attachment.html
@@ -0,0 +1,16 @@
+<% $attach->body %>
+<%init>
+my ($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $attachnum = $1 or die 'Invalid attachment number';
+$FS::CurrentUser::CurrentUser->access_right('Download attachment') or die 'access denied';
+
+my $attach = qsearchs('cust_attachment', { attachnum => $attachnum }) or die "Attachment not found: $attachnum";
+die 'access denied' if $attach->disabled;
+
+$m->clear_buffer;
+$r->content_type($attach->mime_type || 'text/plain');
+$r->headers_out->add('Content-Disposition' => 'attachment;filename=' . $attach->filename);
+
+
+</%init>
diff --git a/httemplate/view/cust_bill-logo.cgi b/httemplate/view/cust_bill-logo.cgi
index 09ac9a7..ad2ff54 100755
--- a/httemplate/view/cust_bill-logo.cgi
+++ b/httemplate/view/cust_bill-logo.cgi
@@ -10,7 +10,7 @@ my $conf = new FS::Conf;
my $templatename;
my $agentnum = '';
if ( $cgi->param('invnum') ) {
- $templatename = $cgi->param('templatename');
+ $templatename = $cgi->param('template') || $cgi->param('templatename');
my $cust_bill = qsearchs('cust_bill', { 'invnum' => $cgi->param('invnum') } )
or die 'unknown invnum';
$agentnum = $cust_bill->cust_main->agentnum;
diff --git a/httemplate/view/cust_bill-pdf.cgi b/httemplate/view/cust_bill-pdf.cgi
index f09e1b7..51e47e0 100755
--- a/httemplate/view/cust_bill-pdf.cgi
+++ b/httemplate/view/cust_bill-pdf.cgi
@@ -4,11 +4,23 @@
die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('View invoices');
-#untaint invnum
+my( $invnum, $template, $notice_name );
my($query) = $cgi->keywords;
-$query =~ /^((.+)-)?(\d+)(.pdf)?$/;
-my $templatename = $2;
-my $invnum = $3;
+if ( $query =~ /^((.+)-)?(\d+)(.pdf)?$/ ) {
+ $template = $2;
+ $invnum = $3;
+ $notice_name = 'Invoice';
+} else {
+ $invnum = $cgi->param('invnum');
+ $invnum =~ s/\.pdf//i;
+ $template = $cgi->param('template');
+ $notice_name = ( $cgi->param('notice_name') || 'Invoice' );
+}
+
+my %opt = (
+ 'template' => $template,
+ 'notice_name' => $notice_name,
+);
my $cust_bill = qsearchs({
'select' => 'cust_bill.*',
@@ -19,7 +31,7 @@ my $cust_bill = qsearchs({
});
die "Invoice #$invnum not found!" unless $cust_bill;
-my $pdf = $cust_bill->print_pdf( '', $templatename);
+my $pdf = $cust_bill->print_pdf(\%opt);
http_header('Content-Type' => 'application/pdf' );
http_header('Content-Length' => length($pdf) );
diff --git a/httemplate/view/cust_bill-ps.cgi b/httemplate/view/cust_bill-ps.cgi
index 5313dbf..881491f 100755
--- a/httemplate/view/cust_bill-ps.cgi
+++ b/httemplate/view/cust_bill-ps.cgi
@@ -1,14 +1,25 @@
-<% $cust_bill->print_ps( '', $templatename) %>
+<% $cust_bill->print_ps(\%opt) %>
<%init>
die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('View invoices');
-#untaint invnum
+my( $invnum, $template, $notice_name );
my($query) = $cgi->keywords;
-$query =~ /^((.+)-)?(\d+)$/;
-my $templatename = $2;
-my $invnum = $3;
+if ( $query =~ /^((.+)-)?(\d+)(.pdf)?$/ ) {
+ $template = $2;
+ $invnum = $3;
+ $notice_name = 'Invoice';
+} else {
+ $invnum = $cgi->param('invnum');
+ $template = $cgi->param('template');
+ $notice_name = ( $cgi->param('notice_name') || 'Invoice' );
+}
+
+my %opt = (
+ 'template' => $template,
+ 'notice_name' => $notice_name,
+);
my $cust_bill = qsearchs({
'select' => 'cust_bill.*',
diff --git a/httemplate/view/cust_bill.cgi b/httemplate/view/cust_bill.cgi
index 450c74e..ce8d96a 100755
--- a/httemplate/view/cust_bill.cgi
+++ b/httemplate/view/cust_bill.cgi
@@ -2,10 +2,32 @@
"View this customer (#$display_custnum)" => "${p}view/cust_main.cgi?$custnum",
)) %>
+% if ( $conf->exists('deleteinvoices')
+% && $curuser->access_right('Delete invoices' )
+% )
+% {
+
+ <SCRIPT TYPE="text/javascript">
+ function areyousure(href, message) {
+ if (confirm(message) == true)
+ window.location.href = href;
+ }
+ </SCRIPT>
+
+ <A HREF = "javascript:areyousure(
+ '<%$p%>misc/delete-cust_bill.html?<% $invnum %>',
+ 'Are you sure you want to delete this invoice?'
+ )"
+ TITLE = "Delete this invoice from the database completely"
+ >Delete this invoice</A>
+ <BR><BR>
+
+% }
% if ( $cust_bill->owed > 0
% && scalar( grep $payby{$_}, qw(BILL CASH WEST MCRD) )
-% && $FS::CurrentUser::CurrentUser->access_right('Post payment')
+% && $curuser->access_right('Post payment')
+% && ! $conf->exists('pkg-balances')
% )
% {
% my $s = 0;
@@ -36,27 +58,25 @@
% }
+% if ( $curuser->access_right('Resend invoices') ) {
-% if ( $FS::CurrentUser::CurrentUser->access_right('Resend invoices') ) {
-
- <A HREF="<% $p %>misc/print-invoice.cgi?<% $link %>">Re-print this invoice</A>
+ <A HREF="<% $p %>misc/send-invoice.cgi?method=print;<% $link %>">Re-print this invoice</A>
% if ( grep { $_ ne 'POST' } $cust_bill->cust_main->invoicing_list ) {
- | <A HREF="<% $p %>misc/email-invoice.cgi?<% $link %>">Re-email this invoice</A>
+ | <A HREF="<% $p %>misc/send-invoice.cgi?method=email;<% $link %>">Re-email this invoice</A>
% }
% if ( $conf->exists('hylafax') && length($cust_bill->cust_main->fax) ) {
- | <A HREF="<% $p %>misc/fax-invoice.cgi?<% $link %>">Re-fax this invoice</A>
+ | <A HREF="<% $p %>misc/send-invoice.cgi?method=fax;<% $link %>">Re-fax this invoice</A>
% }
<BR><BR>
% }
-
% if ( $conf->exists('invoice_latex') ) {
- <A HREF="<% $p %>view/cust_bill-pdf.cgi?<% $link %>.pdf">View typeset invoice</A>
+ <A HREF="<% $p %>view/cust_bill-pdf.cgi?<% $link %>">View typeset invoice PDF</A>
<BR><BR>
% }
@@ -72,24 +92,35 @@
<% $br ? '<BR><BR>' : '' %>
% if ( $conf->exists('invoice_html') ) {
-
- <% join('', $cust_bill->print_html('', $templatename) ) %>
+ <% join('', $cust_bill->print_html(\%opt) ) %>
% } else {
-
- <PRE><% join('', $cust_bill->print_text('', $templatename) ) %></PRE>
+ <PRE><% join('', $cust_bill->print_text(\%opt) ) %></PRE>
% }
<% include('/elements/footer.html') %>
<%init>
+my $curuser = $FS::CurrentUser::CurrentUser;
+
die "access denied"
- unless $FS::CurrentUser::CurrentUser->access_right('View invoices');
+ unless $curuser->access_right('View invoices');
-#untaint invnum
+my( $invnum, $template, $notice_name );
my($query) = $cgi->keywords;
-$query =~ /^((.+)-)?(\d+)$/;
-my $templatename = $2;
-my $invnum = $3;
+if ( $query =~ /^((.+)-)?(\d+)$/ ) {
+ $template = $2;
+ $invnum = $3;
+ $notice_name = 'Invoice';
+} else {
+ $invnum = $cgi->param('invnum');
+ $template = $cgi->param('template');
+ $notice_name = $cgi->param('notice_name');
+}
+
+my %opt = (
+ 'template' => $template,
+ 'notice_name' => $notice_name,
+);
my $conf = new FS::Conf;
@@ -104,7 +135,7 @@ my $cust_bill = qsearchs({
'table' => 'cust_bill',
'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
'hashref' => { 'invnum' => $invnum },
- 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+ 'extra_sql' => ' AND '. $curuser->agentnums_sql,
});
die "Invoice #$invnum not found!" unless $cust_bill;
@@ -113,8 +144,8 @@ my $display_custnum = $cust_bill->cust_main->display_custnum;
#my $printed = $cust_bill->printed;
-my $link = $templatename ? "$templatename-$invnum" : $invnum;
+my $link = "invnum=$invnum";
+$link .= ';template='. uri_escape($template) if $template;
+$link .= ';notice_name='. $notice_name if $notice_name;
</%init>
-
-
diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi
index 2231d41..314207b 100755
--- a/httemplate/view/cust_main.cgi
+++ b/httemplate/view/cust_main.cgi
@@ -1,8 +1,19 @@
-<% include("/elements/header.html","Customer View: ". $cust_main->name ) %>
+<% include('/elements/header.html', {
+ 'title' => "Customer View: ". $cust_main->name,
+ 'nobr' => 1,
+ })
+%>
+<BR>
-% if ( $curuser->access_right('Edit customer') ) {
- <A HREF="<% $p %>edit/cust_main.cgi?<% $custnum %>">Edit this customer</A> |
-% }
+<% include('/elements/menubar.html',
+ { 'newstyle' => 1,
+ 'selected' => $viewname{$view},
+ 'url_base' => $cgi->url. "?custnum=$custnum;show=",
+ },
+ %views,
+ )
+%>
+<BR>
<% include('/elements/init_overlib.html') %>
@@ -13,6 +24,12 @@ function areyousure(href, message) {
}
</SCRIPT>
+% if ( $view eq 'basics' || $view eq 'jumbo' ) {
+
+% if ( $curuser->access_right('Edit customer') ) {
+ <A HREF="<% $p %>edit/cust_main.cgi?<% $custnum %>">Edit this customer</A> |
+% }
+
% if ( $curuser->access_right('Cancel customer')
% && $cust_main->ncancelled_pkgs
% ) {
@@ -23,6 +40,7 @@ function areyousure(href, message) {
'actionlabel' => 'Confirm Cancellation',
'color' => '#ff0000',
'cust_main' => $cust_main,
+ 'width' => 616, #make room for reasons
}
)
%> |
@@ -74,10 +92,12 @@ function areyousure(href, message) {
</TD>
</TR>
</TABLE>
-%
-%if ( $cust_main->comments =~ /[^\s\n\r]/ ) {
-%
+% }
+
+% if ( $view eq 'notes' || $view eq 'jumbo' ) {
+
+%if ( $cust_main->comments =~ /[^\s\n\r]/ ) {
<BR>
Comments
<% ntable("#cccccc") %><TR><TD><% ntable("#cccccc",2) %>
@@ -87,12 +107,17 @@ Comments
</TD>
</TR>
</TABLE></TABLE>
-% }
<BR><BR>
+% }
+<A NAME="notes">
% my $notecount = scalar($cust_main->notes());
% if ( ! $conf->exists('cust_main-disable_notes') || $notecount) {
-<A NAME="cust_main_note"><FONT SIZE="+2">Notes</FONT></A><BR>
+% unless ( $view eq 'notes' && $cust_main->comments !~ /[^\s\n\r]/ ) {
+ <BR>
+ <A NAME="cust_main_note"><FONT SIZE="+2">Notes</FONT></A><BR>
+% }
+
% if ( $curuser->access_right('Add customer note') &&
% ! $conf->exists('cust_main-disable_notes')
% ) {
@@ -114,25 +139,78 @@ Comments
<% include('cust_main/notes.html', 'custnum' => $cust_main->custnum ) %>
% }
+<BR>
+% if(! $conf->config('disable_cust_attachment')
+% and $curuser->access_right('Add attachment')) {
+<% include( '/elements/popup_link-cust_main.html',
+ 'label' => 'Attach file',
+ 'action' => $p.'edit/cust_main_attach.cgi',
+ 'actionlabel' => 'Upload file',
+ 'cust_main' => $cust_main,
+ 'width' => 616,
+ 'height' => 408,
+ )
+%>
+% }
+<% include('cust_main/attachments.html', 'custnum' => $cust_main->custnum ) %>
+% if($cgi->param('show_deleted')) {
+<A HREF="<% $p.'view/cust_main.cgi?custnum=' . $cust_main->custnum .
+ ($view ? ";show=$view" : '') . '#notes'
+ %>"><I>(Show active attachments)</I></A>
+% }
+% elsif($curuser->access_right('View deleted attachments')) {
+<A HREF="<% $p.'view/cust_main.cgi?custnum=' . $cust_main->custnum .
+ ($view ? ";show=$view" : '') . ';show_deleted=1#notes'
+ %>"><I>(Show deleted attachments)</I></A>
+% }
+<BR>
-% if ( $conf->config('ticket_system') ) {
+% }
- <BR><BR>
+% if ( $view eq 'jumbo' ) {
+ <BR><BR>
+ <A NAME="tickets"><FONT SIZE="+2">Tickets</FONT></A><BR>
+% }
+
+% if ( $view eq 'tickets' || $view eq 'jumbo' ) {
+
+% if ( $conf->config('ticket_system') ) {
<% include('cust_main/tickets.html', $cust_main ) %>
% }
+ <BR><BR>
+
+% }
+% if ( $view eq 'jumbo' ) { #XXX enable me && $curuser->access_right('View customer packages') {
-<BR><BR>
+ <A NAME="cust_pkg"><FONT SIZE="+2">Packages</FONT></A><BR>
+% }
+
+% if ( $view eq 'packages' || $view eq 'jumbo' ) {
% #XXX enable me# if ( $curuser->access_right('View customer packages') {
<% include('cust_main/packages.html', $cust_main ) %>
% #}
+% }
+
+% if ( $view eq 'jumbo' ) {
+ <BR><BR>
+ <A NAME="history"><FONT SIZE="+2">Payment History</FONT></A><BR>
+% }
+
+% if ( $view eq 'payment_history' || $view eq 'jumbo' ) {
+
% if ( $conf->config('payby-default') ne 'HIDE' ) {
<% include('cust_main/payment_history.html', $cust_main ) %>
% }
+% }
+
+% if ( $view eq 'change_history' ) { # || $view eq 'jumbo'
+<% include('cust_main/change_history.html', $cust_main ) %>
+% }
<% include('/elements/footer.html') %>
<%init>
@@ -144,10 +222,16 @@ die "access denied"
my $conf = new FS::Conf;
-die "No customer specified (bad URL)!" unless $cgi->keywords;
-my($query) = $cgi->keywords; # needs parens with my, ->keywords returns array
-$query =~ /^(\d+)$/;
-my $custnum = $1;
+my $custnum;
+if ( $cgi->param('custnum') =~ /^(\d+)$/ ) {
+ $custnum = $1;
+} else {
+ die "No customer specified (bad URL)!" unless $cgi->keywords;
+ my($query) = $cgi->keywords; # needs parens with my, ->keywords returns array
+ $query =~ /^(\d+)$/;
+ $custnum = $1;
+}
+
my $cust_main = qsearchs( {
'table' => 'cust_main',
'hashref' => { 'custnum' => $custnum },
@@ -155,4 +239,22 @@ my $cust_main = qsearchs( {
});
die "Customer not found!" unless $cust_main;
+#false laziness w/pref/pref.html and Conf.pm (cust_main-default_view)
+tie my %views, 'Tie::IxHash',
+ 'Basics' => 'basics',
+ 'Notes' => 'notes', #notes and files?
+;
+$views{'Tickets'} = 'tickets'
+ if $conf->config('ticket_system');
+$views{'Packages'} = 'packages';
+$views{'Payment History'} = 'payment_history'
+ unless $conf->config('payby-default' eq 'HIDE');
+$views{'Change History'} = 'change_history'
+ if $curuser->access_right('View customer history');
+$views{'Jumbo'} = 'jumbo';
+
+my %viewname = reverse %views;
+
+my $view = $cgi->param('show') || $curuser->default_customer_view;
+
</%init>
diff --git a/httemplate/view/cust_main/attachments.html b/httemplate/view/cust_main/attachments.html
new file mode 100755
index 0000000..53635fd
--- /dev/null
+++ b/httemplate/view/cust_main/attachments.html
@@ -0,0 +1,151 @@
+% if ( scalar(@attachments) ) {
+
+ <% include('/elements/init_overlib.html') %>
+
+ <% include("/elements/table-grid.html") %>
+
+ <TR>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Date</TH>
+% if ( $conf->exists('cust_main_note-display_times') ) {
+ <TH CLASS="grid" BGCOLOR="#cccccc">Time</TH>
+% }
+ <TH CLASS="grid" BGCOLOR="#cccccc">Person</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Filename</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Type</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Size</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
+ </TR>
+
+% my $bgcolor1 = '#eeeeee';
+% my $bgcolor2 = '#ffffff';
+% my $bgcolor = '';
+% if($cgi->param('show_deleted')) {
+% if ($curuser->access_right('View deleted attachments')) {
+% @attachments = grep { $_->disabled } @attachments;
+% }
+% else {
+% @attachments = ();
+% }
+% }
+% else {
+% @attachments = grep { not $_->disabled } @attachments;
+% }
+%
+% foreach my $attach (@attachments) {
+%
+% if ( $bgcolor eq $bgcolor1 ) {
+% $bgcolor = $bgcolor2;
+% } else {
+% $bgcolor = $bgcolor1;
+% }
+%
+% my $pop = popurl(3);
+% my $attachnum = $attach->attachnum;
+% my $edit = '';
+% if($attach->disabled) { # then you can undelete it or purge it.
+% if ($curuser->access_right('Undelete attachment')) {
+% my $clickjs = popup('edit/process/cust_main_attach.cgi?'.
+% "custnum=$custnum;attachnum=$attachnum;".
+% "undelete=1",
+% 'Undelete attachment');
+% $edit .= qq!&nbsp; <A HREF="javascript:void(0);" $clickjs>(undelete)</A>!;
+% }
+% if ($curuser->access_right('Purge attachment')) {
+% my $clickjs = popup('edit/process/cust_main_attach.cgi?'.
+% "custnum=$custnum;attachnum=$attachnum;".
+% "purge=1",
+% 'Purge attachment');
+% $edit .= qq!&nbsp; <A HREF="javascript:void(0);" $clickjs>(purge)</A>!;
+% }
+% }
+% else { # you can download or edit it
+% if ($curuser->access_right('Edit attachment') ) {
+% my $clickjs = popup('edit/cust_main_attach.cgi?'.
+% "custnum=$custnum;attachnum=$attachnum",
+% 'Edit attachment properties');
+% $edit .= qq!&nbsp; <A HREF="javascript:void(0);" $clickjs>(edit)</A>!;
+% }
+% if($curuser->access_right('Delete attachment') ) {
+% my $clickjs = popup('edit/process/cust_main_attach.cgi?'.
+% "custnum=$custnum;attachnum=$attachnum;".
+% "delete=1",
+% 'Delete attachment');
+% $edit .= qq!&nbsp; <A HREF="javascript:void(0);" $clickjs>(delete)</A>!;
+% }
+% if ($curuser->access_right('Download attachment') ) {
+% $edit .= qq!&nbsp; <A HREF="!.popurl(1).'attachment.html?'.$attachnum.qq!">(download)</A>!;
+% }
+% }
+
+ <TR>
+ <% note_datestr($attach,$conf,$bgcolor) %>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ &nbsp;<% $attach->otaker%>
+ </TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ &nbsp;<% $attach->filename %>
+ </TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ &nbsp;<% $attach->mime_type %>
+ </TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ &nbsp;<% size_units( $attach->size ) %>
+ </TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ <% $edit %>
+ </TD>
+ </TR>
+
+% } #end display notes
+
+</TABLE>
+
+% }
+<%init>
+
+my $conf = new FS::Conf;
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+my(%opt) = @_;
+
+my $custnum = $opt{'custnum'};
+
+my $cust_main = qsearchs('cust_main', {'custnum' => $custnum} );
+die "Customer not found!" unless $cust_main;
+
+my (@attachments) = qsearch('cust_attachment', {'custnum' => $custnum});
+
+#subroutines
+
+sub note_datestr {
+ my($note, $conf, $bgcolor) = @_ or return '';
+ my $td = qq{<TD CLASS="grid" BGCOLOR="$bgcolor" ALIGN="right">};
+ my $format = "$td%b&nbsp;%o,&nbsp;%Y</TD>";
+ $format .= "$td%l:%M%P</TD>"
+ if $conf->exists('cust_main_note-display_times');
+ ( my $strip = time2str($format, $note->_date) ) =~ s/ (\d)/$1/g;
+ $strip;
+}
+
+sub size_units {
+ my $bytes = shift;
+ return $bytes if $bytes < 1024;
+ return int($bytes / 1024)."K" if $bytes < 1048576;
+ return int($bytes / 1048576)."M";
+}
+
+sub popup {
+ my ($url, $label) = @_;
+ my $onclick =
+ include('/elements/popup_link_onclick.html',
+ 'action' => popurl(2).$url,
+ 'actionlabel' => $label,
+ 'width' => 616,
+ 'height' => 408,
+ 'frame' => 'top',
+ );
+ return qq!onclick="$onclick"!;
+}
+
+
+</%init>
diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html
index aea90e8..c8d0c47 100644
--- a/httemplate/view/cust_main/billing.html
+++ b/httemplate/view/cust_main/billing.html
@@ -159,11 +159,24 @@ Billing information
</TR>
% }
-
+% my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups');
<TR>
- <TD ALIGN="right">Tax&nbsp;exempt</TD>
+ <TD ALIGN="right">Tax&nbsp;exempt<% @exempt_groups ? ' (all taxes)' : '' %></TD>
<TD BGCOLOR="#ffffff"><% $cust_main->tax ? 'yes' : 'no' %></TD>
</TR>
+% foreach my $exempt_group ( @exempt_groups ) {
+<TR>
+ <TD ALIGN="right">Tax&nbsp;exempt (<% $exempt_group %> taxes)</TD>
+ <TD BGCOLOR="#ffffff"><% $cust_main->tax_exemption($exempt_group) ? 'yes' : 'no' %></TD>
+</TR>
+% }
+
+% if ( $conf->exists('enable_taxproducts') ) {
+<TR>
+ <TD ALIGN="right">Tax&nbsp;location</TD>
+ <TD BGCOLOR="#ffffff"><% $cust_main->geocode('cch') %></TD>
+</TR>
+% }
<TR>
<TD ALIGN="right">Postal&nbsp;invoices</TD>
<TD BGCOLOR="#ffffff">
@@ -203,6 +216,20 @@ Billing information
</TR>
% }
+% if ( $conf->exists('voip-cust_email_csv_cdr') ) {
+ <TR>
+ <TD ALIGN="right">Email&nbsp;CDRs&nbsp;as&nbsp;CSV</TD>
+ <TD BGCOLOR="#ffffff"><% $cust_main->email_csv_cdr ? 'yes' : 'no' %></TD>
+ </TR>
+% }
+
+% if ( $show_term || $cust_main->cdr_termination_percentage ) {
+ <TR>
+ <TD ALIGN="right">CDR termination settlement</TD>
+ <TD BGCOLOR="#ffffff"><% $cust_main->cdr_termination_percentage %><% $cust_main->cdr_termination_percentage =~ /\d/ ? '%' : '' %></TD>
+ </TR>
+% }
+
</TABLE></TD></TR></TABLE>
<%once>
@@ -217,4 +244,10 @@ my @invoicing_list = $cust_main->invoicing_list;
my $conf = new FS::Conf;
my $money_char = $conf->config('money_char') || '$';
+#false laziness w/edit/cust_main/billing.html
+my $term_sql = "SELECT COUNT(*) FROM cust_pkg LEFT JOIN part_pkg USING ( pkgpart ) WHERE custnum = ? AND plan = 'cdr_termination' LIMIT 1";
+my $term_sth = dbh->prepare($term_sql) or die dbh->errstr;
+$term_sth->execute($cust_main->custnum) or die $term_sth->errstr;
+my $show_term = $term_sth->fetchrow_arrayref->[0];
+
</%init>
diff --git a/httemplate/view/cust_main/change_history.html b/httemplate/view/cust_main/change_history.html
new file mode 100644
index 0000000..53a79f4
--- /dev/null
+++ b/httemplate/view/cust_main/change_history.html
@@ -0,0 +1,302 @@
+% if ( int( time - (keys %years)[0] * 31556736 ) > $start ) {
+ Show:
+% my $chy = $cgi->param('change_history-years');
+% foreach my $y (keys %years) {
+% if ( $y == $years ) {
+ <FONT SIZE="+1"><% $years{$y} %></FONT>
+% } else {
+% $cgi->param('change_history-years', $y);
+ <A HREF="<% $cgi->self_url %>"><% $years{$y} %></A>
+% }
+% last if int( time - $y * 31556736 ) < $start;
+% }
+% $cgi->param('change_history-years', $chy);
+% }
+
+<% include("/elements/table-grid.html") %>
+% my $bgcolor1 = '#eeeeee';
+% my $bgcolor2 = '#ffffff';
+% my $bgcolor = '';
+
+<TR>
+ <TH CLASS="grid" BGCOLOR="#cccccc">User</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Date</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Time</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Item</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Action</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">Description</TH>
+</TR>
+
+% foreach my $item ( sort { $a->history_date <=> $b->history_date
+% #|| table order
+% || $a->historynum <=> $b->historynum
+% }
+% @history
+% )
+% {
+%
+% my $history_other = '';
+% my $act = $item->history_action;
+% if ( $act =~ /^replace/ ) {
+% my $pkey = $item->primary_key;
+% my $date = $item->history_date;
+% $history_other = qsearchs({
+% 'table' => $item->table,
+% 'hashref' => { $pkey => $item->$pkey(),
+% 'history_action' => $replace_other{$act},
+% 'historynum' => { 'op' => $replace_dir{$act},
+% 'value' => $item->historynum
+% },
+% },
+% 'extra_sql' => "
+% AND history_date $replace_direq{$act} $date
+% AND ($date $replace_op{$act} $fuzz) $replace_direq{$act} history_date
+% ORDER BY historynum $replace_ord{$act} LIMIT 1
+% ",
+% });
+% }
+%
+% if ( $bgcolor eq $bgcolor1 ) {
+% $bgcolor = $bgcolor2;
+% } else {
+% $bgcolor = $bgcolor1;
+% }
+
+ <TR>
+ <TD ALIGN="left" CLASS="grid" BGCOLOR="<% $bgcolor %>">
+% my $otaker = $item->history_user;
+% $otaker = '<i>auto billing</i>' if $otaker eq 'fs_daily';
+% $otaker = '<i>customer self-service</i>' if $otaker eq 'fs_selfservice';
+% $otaker = '<i>job queue</i>' if $otaker eq 'fs_queue';
+ <% $otaker %>
+ </TD>
+ <TD ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
+% my $d = time2str('%b %o, %Y', $item->history_date );
+% $d =~ s/ /&nbsp;/g;
+ <% $d %>
+ </TD>
+ <TD ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
+% my $t = time2str('%r', $item->history_date );
+% $t =~ s/ /&nbsp;/g;
+ <% $t %>
+ </TD>
+ <TD ALIGN="center" CLASS="grid" BGCOLOR="<% $bgcolor %>">
+% my $label = $h_tables{$item->table};
+% $label = &{ $h_table_labelsub{$item->table} }( $item, $label )
+% if $h_table_labelsub{$item->table};
+ <% $label %>
+ </TD>
+ <TD ALIGN="left" CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ <% $action{$item->history_action} %>
+ </TD>
+ <TD ALIGN="left" CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ <% join(', ',
+ map { my $value = ( $_ =~ /(^pay(info|cvv)|^ss|_password)$/ )
+ ? 'N/A'
+ : $item->get($_);
+ $value = substr($value, 0, 77).'...' if length($value) > 80;
+ $value = encode_entities($value);
+ "<I>$_</I>:<B>$value</B>";
+ }
+ grep { $history_other
+ ? ( $item->get($_) ne $history_other->get($_) )
+ : ( $item->get($_) =~ /\S/ )
+ }
+ grep { ! /^(history|custnum$)/i }
+ $item->fields
+ )
+ %>
+ </TD>
+ </TR>
+
+% }
+
+</TABLE>
+<%once>
+
+# length-switching
+
+tie my %years, 'Tie::IxHash',
+ .5 => '6 months',
+ 1 => '1 year',
+ 2 => '2 years',
+ 5 => '5 years',
+ 39 => 'all history',
+;
+
+# labeling history rows
+
+my %action = (
+ 'insert' => 'Insert', #'Create',
+ 'replace_old' => 'Change&nbsp;from',
+ 'replace_new' => 'Change&nbsp;to',
+ 'delete' => 'Remove',
+);
+
+# finding the other replace row
+
+my %replace_other = (
+ 'replace_new' => 'replace_old',
+ 'replace_old' => 'replace_new',
+);
+my %replace_dir = (
+ 'replace_new' => '<',
+ 'replace_old' => '>',
+);
+my %replace_direq = (
+ 'replace_new' => '<=',
+ 'replace_old' => '>=',
+);
+my %replace_op = (
+ 'replace_new' => '-',
+ 'replace_old' => '+',
+);
+my %replace_ord = (
+ 'replace_new' => 'DESC',
+ 'replace_old' => 'ASC',
+);
+
+my $fuzz = 5; #seems like a lot
+
+# which tables to search and what to call them
+
+tie my %tables, 'Tie::IxHash',
+ 'cust_main' => 'Customer',
+ 'cust_main_invoice' => 'Invoice destination',
+ 'cust_pkg' => 'Package',
+ #? or just svc_* ? 'cust_svc' =>
+ 'svc_acct' => 'Account',
+ 'radius_usergroup' => 'RADIUS group',
+ 'svc_domain' => 'Domain',
+ 'svc_www' => 'Hosting',
+ 'svc_forward' => 'Mail forward',
+ 'svc_broadband' => 'Broadband',
+ 'svc_external' => 'External service',
+ 'svc_phone' => 'Phone',
+ 'phone_device' => 'Phone device',
+ #? it gets provisioned anyway 'phone_avail' => 'Phone',
+;
+
+my $svc_join = 'JOIN cust_svc USING ( svcnum ) JOIN cust_pkg USING ( pkgnum )';
+
+my %table_join = (
+ 'svc_acct' => $svc_join,
+ 'radius_usergroup' => $svc_join,
+ 'svc_domain' => $svc_join,
+ 'svc_www' => $svc_join,
+ 'svc_forward' => $svc_join,
+ 'svc_broadband' => $svc_join,
+ 'svc_external' => $svc_join,
+ 'svc_phone' => $svc_join,
+ 'phone_device' => $svc_join,
+);
+
+my %h_tables = map { ( "h_$_" => $tables{$_} ) } keys %tables;
+
+my %pkgpart = ();
+my $pkg_labelsub = sub {
+ my($item, $label) = @_;
+ $pkgpart{$item->pkgpart} ||= $item->part_pkg->pkg;
+ $label. ': <b>'. encode_entities($pkgpart{$item->pkgpart}). '</b>';
+};
+
+my $svc_labelsub = sub {
+ my($item, $label) = @_;
+ $label. ': <b>'. encode_entities($item->label($item->history_date)). '</b>';
+};
+
+my %h_table_labelsub = (
+ 'h_cust_pkg' => $pkg_labelsub,
+ 'h_svc_acct' => $svc_labelsub,
+ #'h_radius_usergroup' =>
+ 'h_svc_domain' => $svc_labelsub,
+ 'h_svc_www' => $svc_labelsub,
+ 'h_svc_forward' => $svc_labelsub,
+ 'h_svc_broadband' => $svc_labelsub,
+ 'h_svc_external' => $svc_labelsub,
+ 'h_svc_phone' => $svc_labelsub,
+ #'h_phone_device'
+);
+
+# cust_main
+# cust_main_invoice
+
+# cust_pkg
+# cust_pkg_option?
+# cust_pkg_detail
+# cust_pkg_reason? no
+
+#cust_svc
+#cust_svc_option?
+#svc_*
+# svc_acct
+# radius_usergroup
+# acct_snarf? is this even used?
+# svc_domain
+# domain_record
+# registrar
+# svc_forward
+# svc_www
+# svc_broadband
+# (virtual fields? eh... maybe when they're real)
+# svc_external
+# svc_phone
+# phone_device
+# phone_avail
+
+# future:
+
+# inventory_item (from services)
+# pkg_referral? (changed?)
+
+#random others:
+
+# cust_location?
+# cust_main-exemption?? (295.ca named tax exemptions)
+
+</%once>
+<%init>
+
+my( $cust_main ) = @_;
+
+my $conf = new FS::Conf;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access deined"
+ unless $curuser->access_right('View customer history');
+
+# find out the beginning of this customer history, if possible
+my $h_insert = qsearchs({
+ 'table' => 'h_cust_main',
+ 'hashref' => { 'custnum' => $cust_main->custnum,
+ 'history_action' => 'insert',
+ },
+ 'extra_sql' => 'ORDER BY historynum LIMIT 1',
+});
+my $start = $h_insert ? $h_insert->history_date : 0;
+
+# retreive the history
+
+my @history = ();
+
+my $years = $conf->config('change_history-years') || .5;
+if ( $cgi->param('change_history-years') =~ /^([\d\.]+)$/ ) {
+ $years = $1;
+}
+my $newer_than = int( time - $years * 31556736 ); #60*60*24*365.24
+
+local($FS::Record::nowarn_classload) = 1;
+
+foreach my $table ( keys %tables ) {
+ my @items = qsearch({
+ 'table' => "h_$table",
+ 'addl_from' => $table_join{$table},
+ 'hashref' => { 'history_date' => { op=>'>=', value=>$newer_than }, },
+ 'extra_sql' => ' AND custnum = '. $cust_main->custnum,
+ });
+ push @history, @items;
+
+}
+
+</%init>
diff --git a/httemplate/view/cust_main/misc.html b/httemplate/view/cust_main/misc.html
index 060da87..71e8d69 100644
--- a/httemplate/view/cust_main/misc.html
+++ b/httemplate/view/cust_main/misc.html
@@ -85,13 +85,24 @@
</TR>
% if ( $conf->exists('cust_main-enable_birthdate') ) {
-% my $dt = DateTime->from_epoch(epoch => $cust_main->birthdate,
-% time_zone=>'floating',
-% );
+% my $dt = $cust_main->birthdate ne ''
+% ? DateTime->from_epoch( 'epoch' => $cust_main->birthdate,
+% 'time_zone' =>'floating',
+% )
+% : '';
<TR>
<TD ALIGN="right">Date of Birth</TD>
- <TD BGCOLOR="#ffffff"><% $cust_main->birthdate ne '' ? $dt->strftime($date_format) : '' %></TD>
+ <TD BGCOLOR="#ffffff"><% $dt ? $dt->strftime($date_format) : '' %></TD>
+ </TR>
+
+% }
+
+% if ( $conf->exists('cust_main-require_censustract') ) {
+
+ <TR>
+ <TD ALIGN="right">Census tract</TD>
+ <TD BGCOLOR="#ffffff"><% $cust_main->censustract %></TD>
</TR>
% }
diff --git a/httemplate/view/cust_main/one_time_charge_link.html b/httemplate/view/cust_main/one_time_charge_link.html
new file mode 100644
index 0000000..4ce8a28
--- /dev/null
+++ b/httemplate/view/cust_main/one_time_charge_link.html
@@ -0,0 +1,91 @@
+<SCRIPT TYPE="text/javascript">
+
+function taxproductmagic(which) {
+
+ var str = '';
+ var elements = which.form.elements;
+ for (var i = 0; i<elements.length; i++) {
+
+ if (elements[i].name == 'taxproductnum'){
+ document.getElementById('taxproductnum').value = elements[i].value;
+ continue;
+ }
+ if (elements[i].name == 'taxproductnum_description'){
+ continue;
+ }
+
+ if (str.length){str += ';';}
+
+ var value = '';
+ if ( elements[i].type == 'checkbox' || elements[i].type == 'radio' ) {
+ if ( elements[i].checked == true ) {
+ value = elements[i].value;
+ //} else {
+ // value = '';
+ }
+ } else {
+ value = elements[i].value;
+ }
+ str += elements[i].name + '=' + escape(value);
+
+ }
+ document.getElementById('charge_storage').value = str;
+ cClick();
+ overlib( OLiframeContent('<% $p %>/browse/part_pkg_taxproduct.cgi?_type=select&id=taxproductnum&onclick=taxproductquickchargemagic&taxproductnum='+document.getElementById('taxproductnum').value, 1000, 400, 'tax_product_popup'), CAPTION, 'Select product', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK);
+}
+
+function taxproductquickchargemagic() {
+ var str = document.getElementById('charge_storage').value;
+ if (str.length){str += ';';}
+ str += 'magic=taxproductnum;taxproductnum=';
+ str += escape(document.getElementById('taxproductnum').value);
+ cClick();
+ overlib( OLiframeContent('<% $p %>/edit/quick-charge.html?'+str, 545, 336, 'One-time charge'), CAPTION, 'One-time charge', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK, BGCOLOR, '#333399', CGCOLOR, '#333399', CLOSETEXT, 'Close');
+
+}
+
+function taxoverridemagic(which) {
+ var str = '';
+ var elements = which.ownerDocument.QuickChargeForm.elements;
+ for (var i = 0; i<elements.length; i++) {
+ if (elements[i].name == 'tax_override'){
+ document.getElementById('tax_override').value = elements[i].value;
+ continue;
+ }
+ if (str.length){str += ';';}
+ str += elements[i].name + '=' + escape(elements[i].value);
+ }
+ document.getElementById('charge_storage').value = str;
+ cClick();
+ overlib( OLiframeContent('<% $p %>/edit/part_pkg_taxoverride.html?element_name=tax_override;onclick=taxoverridequickchargemagic;selected='+document.getElementById('tax_override').value, 1100, 600, 'tax_product_popup'), CAPTION, 'Edit product tax overrides', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK);
+}
+
+function taxoverridequickchargemagic() {
+ var str = document.getElementById('charge_storage').value;
+ if (str.length){str += ';';}
+ str += 'magic=taxoverride;tax_override=';
+ str += document.getElementById('tax_override').value;
+ cClick();
+ overlib( OLiframeContent('<% $p %>/edit/quick-charge.html?'+str, 545, 336, 'One-time charge'), CAPTION, 'One-time charge', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK, BGCOLOR, '#333399', CGCOLOR, '#333399', CLOSETEXT, 'Close');
+
+}
+
+</SCRIPT>
+
+<FORM NAME='quickcharge' STYLE="margin:0; padding:0; display:inline"><INPUT NAME="taxproductnum" ID="taxproductnum" TYPE="hidden"><INPUT NAME="tax_override" ID="tax_override" TYPE="hidden"><INPUT NAME="charge_storage" ID="charge_storage" TYPE="hidden"><INPUT NAME="taxproductnum_description" ID="taxproductnum_description" TYPE="hidden"></FORM>
+
+<% include('/elements/popup_link.html', {
+ 'action' => $p.'edit/quick-charge.html?custnum='. $cust_main->custnum,
+ 'label' => 'One-time charge',
+ 'actionlabel' => 'One-time charge',
+ 'color' => '#333399',
+ 'width' => 763,
+ 'height' => 408,
+ })
+%>
+
+<%init>
+
+my($cust_main) = @_;
+
+</%init>
diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html
index 2c25888..17a0691 100755
--- a/httemplate/view/cust_main/packages.html
+++ b/httemplate/view/cust_main/packages.html
@@ -1,94 +1,24 @@
-<A NAME="cust_pkg"><FONT SIZE="+2">Packages</FONT></A><BR>
-
-% if ( $curuser->access_right('One-time charge') ) {
-
-<SCRIPT TYPE="text/javascript">
-
-function taxproductmagic(which) {
- var str = '';
- var elements = which.form.elements;
- for (var i = 0; i<elements.length; i++) {
- if (elements[i].name == 'taxproductnum'){
- document.getElementById('taxproductnum').value = elements[i].value;
- continue;
- }
- if (elements[i].name == 'taxproductnum_description'){
- continue;
- }
- if (str.length){str += ';';}
- str += elements[i].name + '=' + escape(elements[i].value);
- }
- document.getElementById('charge_storage').value = str;
- cClick();
- overlib( OLiframeContent('<% $p %>/browse/part_pkg_taxproduct.cgi?_type=select&id=taxproductnum&onclick=taxproductquickchargemagic&taxproductnum='+document.getElementById('taxproductnum').value, 1000, 400, 'tax_product_popup'), CAPTION, 'Select product', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK);
-}
-
-function taxproductquickchargemagic() {
- var str = document.getElementById('charge_storage').value;
- if (str.length){str += ';';}
- str += 'magic=taxproductnum;taxproductnum=';
- str += escape(document.getElementById('taxproductnum').value);
- cClick();
- overlib( OLiframeContent('<% $p %>/edit/quick-charge.html?'+str, 545, 336, 'One-time charge'), CAPTION, 'One-time charge', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK, BGCOLOR, '#333399', CGCOLOR, '#333399', CLOSETEXT, 'Close');
-
-}
-
-function taxoverridemagic(which) {
- var str = '';
- var elements = which.ownerDocument.QuickChargeForm.elements;
- for (var i = 0; i<elements.length; i++) {
- if (elements[i].name == 'tax_override'){
- document.getElementById('tax_override').value = elements[i].value;
- continue;
- }
- if (str.length){str += ';';}
- str += elements[i].name + '=' + escape(elements[i].value);
- }
- document.getElementById('charge_storage').value = str;
- cClick();
- overlib( OLiframeContent('<% $p %>/edit/part_pkg_taxoverride.html?element_name=tax_override;onclick=taxoverridequickchargemagic;selected='+document.getElementById('tax_override').value, 1100, 600, 'tax_product_popup'), CAPTION, 'Edit product tax overrides', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK);
-}
-
-function taxoverridequickchargemagic() {
- var str = document.getElementById('charge_storage').value;
- if (str.length){str += ';';}
- str += 'magic=taxoverride;tax_override=';
- str += document.getElementById('tax_override').value;
- cClick();
- overlib( OLiframeContent('<% $p %>/edit/quick-charge.html?'+str, 545, 336, 'One-time charge'), CAPTION, 'One-time charge', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK, BGCOLOR, '#333399', CGCOLOR, '#333399', CLOSETEXT, 'Close');
-
-}
-
-</SCRIPT>
-<FORM NAME='quickcharge'>
- <INPUT NAME="taxproductnum" ID="taxproductnum" TYPE="hidden">
- <INPUT NAME="tax_override" ID="tax_override" TYPE="hidden">
- <INPUT NAME="charge_storage" ID="charge_storage" TYPE="hidden">
- <INPUT NAME="taxproductnum_description" ID="taxproductnum_description" TYPE="hidden">
-</FORM>
-% }
-
% my $s = 0;
% if ( $curuser->access_right('Order customer package') ) {
<% $s++ ? ' | ' : '' %>
- <% order_pkg_link($cust_main) %>
+ <% include( '/elements/popup_link-cust_main.html',
+ 'action' => $p. 'misc/order_pkg.html',
+ 'label' => 'Order&nbsp;new&nbsp;package',
+ 'actionlabel' => 'Order new package',
+ 'color' => '#333399',
+ 'cust_main' => $cust_main,
+ 'closetext' => 'Close',
+ 'width' => 763,
+ 'height' => 350,
+ )
+ %>
% }
% if ( $curuser->access_right('One-time charge')
% && $conf->config('payby-default') ne 'HIDE'
% ) {
-%
<% $s++ ? ' | ' : '' %>
- <% include('/elements/popup_link.html',
- {
- 'action' => $p. 'edit/quick-charge.html?custnum='. $cust_main->custnum,
- 'label' => 'One-time charge',
- 'actionlabel' => 'One-time charge',
- 'color' => '#333399',
- 'width' => 763,
- 'height' => 408,
- })
- %>
+ <% include('one_time_charge_link.html', $cust_main) %>
% }
% if ( $curuser->access_right('Bulk change customer packages') ) {
@@ -109,19 +39,25 @@ Current packages
% )
% )
% {
+% my $prev = $cgi->param('showcancelledpackages');
% $cgi->param('showcancelledpackages', 1);
-%
-
( <a href="<% $cgi->self_url %>">show
+% $cgi->param('showcancelledpackages', $prev);
% } else {
% $cgi->param('showcancelledpackages', 0);
-%
-
( <a href="<% $cgi->self_url %>">hide
+% $cgi->param('showcancelledpackages', 1);
% }
cancelled packages</a> )
% }
+% if ( $num_old_packages ) {
+% $cgi->param('showoldpackages', 1);
+ ( <a href="<% $cgi->self_url %>">show old packages</a> )
+% } elsif ( $cgi->param('showoldpackages') ) {
+% $cgi->param('showoldpackages', 0);
+ ( <a href="<% $cgi->self_url %>">hide old packages</a> )
+% }
% if ( @$packages ) {
<% include('/elements/table-grid.html') %>
@@ -138,6 +74,7 @@ Current packages
<TH CLASS="grid" BGCOLOR="#cccccc">Services</TH>
</TR>
+% #$FS::cust_pkg::DEBUG = 2;
% foreach my $cust_pkg (@$packages) {
%
% if ( $bgcolor eq $bgcolor1 ) {
@@ -146,25 +83,13 @@ Current packages
% $bgcolor = $bgcolor1;
% }
%
-% my $countrydefault = scalar($conf->config('countrydefault')) || 'US';
% my %iopt = (
-% 'bgcolor' => $bgcolor,
-% 'cust_pkg' => $cust_pkg,
-% 'part_pkg' => $cust_pkg->part_pkg,
-%
-% #for services.html and status.html
-% 'cust_pkg-display_times' => $conf->exists('cust_pkg-display_times'),
-%
-% #for location.html
-% 'countrydefault' => $countrydefault,
-% 'statedefault' => ( scalar($conf->config('statedefault'))
-% || ($countrydefault eq 'US' ? 'CA' : '') ),
-%
-% #for services.html
-% 'svc_external-skip_manual' => $conf->exists('svc_external-skip_manual'),
-% 'legacy_link' => $conf->exists('legacy_link'),
-%
+% 'bgcolor' => $bgcolor,
+% 'cust_pkg' => $cust_pkg,
+% 'part_pkg' => $cust_pkg->part_pkg,
+% %conf_opt,
% );
+%
<!--pkgnum: <% $cust_pkg->pkgnum %>-->
<TR>
@@ -193,6 +118,7 @@ Current packages
if ( el ) el.scrollIntoView(true);
</SCRIPT>
% }
+
<%init>
my( $cust_main ) = @_;
@@ -200,18 +126,38 @@ my $conf = new FS::Conf;
my $curuser = $FS::CurrentUser::CurrentUser;
-my $packages = get_packages($cust_main, $conf);
+my( $packages, $num_old_packages ) = get_packages($cust_main, $conf);
my $show_location = $conf->exists('cust_pkg-always_show_location')
|| ( grep $_->locationnum, @$packages ); # ? '1' : '0';
+my $countrydefault = scalar($conf->config('countrydefault')) || 'US';
+my %conf_opt = (
+ #for services.html and status.html
+ 'cust_pkg-display_times' => $conf->exists('cust_pkg-display_times'),
+
+ #for status.html
+ 'cust_pkg-show_autosuspend' => $conf->exists('cust_pkg-show_autosuspend'),
+ #for status.html pkg-balances
+ 'pkg-balances' => $conf->exists('pkg-balances'),
+ 'money_char' => ( $conf->config('money_char') || '$' ),
+
+ #for location.html
+ 'countrydefault' => $countrydefault,
+ 'statedefault' => ( scalar($conf->config('statedefault'))
+ || ($countrydefault eq 'US' ? 'CA' : '') ),
+ #for services.html
+ 'svc_external-skip_manual' => $conf->exists('svc_external-skip_manual'),
+ 'legacy_link' => $conf->exists('legacy_link'),
+ 'svc_broadband-manage_link' => $conf->config('svc_broadband-manage_link'),
+);
+
#subroutines
sub get_packages {
my $cust_main = shift or return undef;
my $conf = shift;
-
- my @packages = ();
+
my $method;
if ( $cgi->param('showcancelledpackages') eq '0' #see if it was set by me
|| ( $conf->exists('hidecancelledpackages')
@@ -223,19 +169,51 @@ sub get_packages {
$method = 'all_pkgs';
}
- [ $cust_main->$method() ];
-}
+ my $cust_pkg_fields =
+ join(', ', map { "cust_pkg.$_ AS $_" } fields('cust_pkg') );
+
+ my $part_pkg_fields =
+ join(', ', map { "part_pkg.$_ AS part_pkg_$_" } fields('part_pkg') );
+
+ my $group_by =
+ join(', ', map "cust_pkg.$_", fields('cust_pkg') ). ', '.
+ join(', ', map "part_pkg.$_", fields('part_pkg') );
+
+ my $num_svcs = '( SELECT COUNT(*) FROM cust_svc '.
+ ' WHERE cust_svc.pkgnum = cust_pkg.pkgnum ) AS num_svcs';
+
+ my @packages = $cust_main->$method( {
+ 'select' => "$cust_pkg_fields, $part_pkg_fields, $num_svcs",
+ 'addl_from' => 'LEFT JOIN part_pkg USING ( pkgpart )',
+ } );
+ my $num_old_packages = scalar(@packages);
+
+ foreach my $cust_pkg ( @packages ) {
+ my %hash = $cust_pkg->hash;
+ my %part_pkg = map { /^part_pkg_(.+)$/ or die; ( $1 => $hash{$_} ); }
+ grep { /^part_pkg_/ } keys %hash;
+ $cust_pkg->{'_pkgpart'} = new FS::part_pkg \%part_pkg;
+ }
+
+ unless ( $cgi->param('showoldpackages') ) {
+ my $years = $conf->config('cust_main-packages-years') || 2;
+ my $seconds = 31556926; #60*60*24*365.2422 is close enough
+ my $then = time - $seconds;
+
+ my %hide = ( 'cancelled' => 'cancel',
+ 'one-time charge' => 'setup',
+ );
+
+ @packages =
+ grep { !exists($hide{$_->status}) or $_->get($hide{$_->status}) > $then
+ or $_->num_svcs #don't hide packages w/services
+ }
+ @packages;
+ }
+
+ $num_old_packages -= scalar(@packages);
-sub order_pkg_link {
- include( '/elements/popup_link-cust_main.html',
- 'action' => $p. 'misc/order_pkg.html',
- 'label' => 'Order&nbsp;new&nbsp;package',
- 'actionlabel' => 'Order new package',
- 'color' => '#333399',
- 'cust_main' => shift,
- 'closetext' => 'Close',
- 'width' => 763,
- )
+ ( \@packages, $num_old_packages );
}
</%init>
diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html
index b07e1af..280a016 100644
--- a/httemplate/view/cust_main/packages/package.html
+++ b/httemplate/view/cust_main/packages/package.html
@@ -6,7 +6,7 @@
ID ="cust_pkg<% $cust_pkg->pkgnum %>"
><% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><B><% $part_pkg->pkg |h %></B></A>
-
- <% $part_pkg->comment |h %>
+ <% $part_pkg->custom_comment |h %>
</TD>
</TR>
@@ -38,7 +38,7 @@
%
% if ( $curuser->access_right('Customize customer package') ) {
% $br=1;
- (&nbsp;<%pkg_customize_link($cust_pkg,$cust_pkg->custnum)%>&nbsp;)
+ (&nbsp;<%pkg_customize_link($cust_pkg,$part_pkg)%>&nbsp;)
% }
%
<% $br ? '<BR>' : '' %>
@@ -58,18 +58,18 @@
% my $editi = $curuser->access_right('Edit customer package invoice details');
% my $editc = $curuser->access_right('Edit customer package comments');
+% my @cust_pkg_detail = $cust_pkg->cust_pkg_detail;
+% my @invoice_detail = grep { $_->detailtype eq 'I' } @cust_pkg_detail;
+% my @comments = grep { $_->detailtype eq 'C' } @cust_pkg_detail;
%
-% if ( $cust_pkg->cust_pkg_detail('I')
-% || $cust_pkg->cust_pkg_detail('C')
-% || $editi
-% || $editc ) {
+% if ( scalar(@invoice_detail) || scalar(@comments) || $editi || $editc ) {
%
% my $editlink = $p. 'edit/cust_pkg_detail?pkgnum='. $cust_pkg->pkgnum.
% ';detailtype=';
<TR>
-% if ( $cust_pkg->cust_pkg_detail('I') ) {
+% if ( @invoice_detail ) {
<TD VALIGN="top">
<% include('/elements/table-grid.html') %>
<TR>
@@ -89,7 +89,7 @@
</FONT>
</TH>
</TR>
-% foreach my $cust_pkg_detail ( $cust_pkg->cust_pkg_detail('I') ) {
+% foreach my $cust_pkg_detail ( @invoice_detail ) {
<TR>
<TD><FONT SIZE="-1">&nbsp;-&nbsp;<% $cust_pkg_detail->detail |h %></FONT></TD>
</TR>
@@ -113,7 +113,7 @@
</TD>
% }
-% if ( $cust_pkg->cust_pkg_detail('C') ) {
+% if ( @comments ) {
<TD VALIGN="top">
<% include('/elements/table-grid.html') %>
<TR>
@@ -133,7 +133,7 @@
</FONT>
</TH>
</TR>
-% foreach my $cust_pkg_detail ( $cust_pkg->cust_pkg_detail('C') ) {
+% foreach my $cust_pkg_detail ( @comments ) {
<TR>
<TD><FONT SIZE="-1">&nbsp;-&nbsp;<% $cust_pkg_detail->detail |h %></FONT></TD>
</TR>
@@ -198,9 +198,10 @@ sub pkg_dates_link { pkg_link('edit/REAL_cust_pkg', 'Edit&nbsp;dates', @_ ); }
sub pkg_customize_link {
my $cust_pkg = shift or return '';
+ my $part_pkg = shift;
my $custnum = $cust_pkg->custnum;
qq!<A HREF="${p}edit/part_pkg.cgi?!.
- "clone=". $cust_pkg->part_pkg->pkgpart. ';'.
+ "clone=". $part_pkg->pkgpart. ';'.
"pkgnum=". $cust_pkg->pkgnum.
qq!">Customize</A>!;
}
diff --git a/httemplate/view/cust_main/packages/services.html b/httemplate/view/cust_main/packages/services.html
index 1e47373..0fe7931 100644
--- a/httemplate/view/cust_main/packages/services.html
+++ b/httemplate/view/cust_main/packages/services.html
@@ -36,15 +36,29 @@
% )
% ) {
(&nbsp;<%svc_recharge_link($cust_svc)%>&nbsp;)
-% }
+% }
</FONT></TD>
- <TD ALIGN="right" VALIGN="top" STYLE="padding-bottom:5px;padding-top:0px"><FONT SIZE="-2">
+ <TD ALIGN="right" VALIGN="top" STYLE="padding-bottom:5px;padding-top:0px">
-% if ( $curuser->access_right('Unprovision customer service') ) {
- (&nbsp;<%svc_unprovision_link($cust_svc)%>&nbsp;)
-% }
- </FONT></TD>
+% my $ip_addr = $cust_svc->svc_x->ip_addr;
+
+% if ( $part_svc->svcdb eq 'svc_broadband' ) {
+ <FONT SIZE="-1" STYLE="float:left">(&nbsp;<% include('/elements/popup_link-ping.html', 'ip'=> $ip_addr ) %>&nbsp;)</FONT>
+
+% }
+
+% my $manage_link = $opt{'svc_broadband-manage_link'};
+% if ( $manage_link && $part_svc->svcdb eq 'svc_broadband' ) {
+% my $svc_manage_link = eval(qq("$manage_link"));
+ <FONT SIZE="-1" STYLE="float:left">(&nbsp;<A HREF="<% $svc_manage_link %>">Manage Device</A>&nbsp;)</FONT>
+
+% }
+
+% if ( $curuser->access_right('Unprovision customer service') ) {
+ <FONT SIZE="-2">(&nbsp;<%svc_unprovision_link($cust_svc)%>&nbsp;)</FONT>
+% }
+ </TD>
</TR>
% }
@@ -75,6 +89,8 @@ my $cust_pkg = $opt{'cust_pkg'};
my $part_pkg = $opt{'part_pkg'};
my $curuser = $FS::CurrentUser::CurrentUser;
+my $conf = new FS::Conf;
+
sub svc_provision_link {
my ($cust_pkg, $part_svc, $opt, $curuser) = @_;
( my $svc_nbsp = $part_svc->svc ) =~ s/\s+/&nbsp;/g;
diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html
index 106137b..6667a55 100644
--- a/httemplate/view/cust_main/packages/status.html
+++ b/httemplate/view/cust_main/packages/status.html
@@ -8,20 +8,21 @@
<% pkg_status_row($cust_pkg, 'Cancelled', 'cancel', 'color'=>'FF0000', %opt ) %>
- <% pkg_status_row_colspan(
+ <% pkg_status_row_colspan( $cust_pkg,
( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
- 'align' => 'right', 'color' => 'ff0000', 'size' => '-2',
+ 'align'=>'right', 'color'=>'ff0000', 'size'=>'-2', 'colspan'=>$colspan,
+ %opt
)
%>
% unless ( $cust_pkg->get('setup') ) {
- <% pkg_status_row_colspan('Never billed') %>
+ <% pkg_status_row_colspan( $cust_pkg, 'Never billed', '', 'colspan'=>$colspan, %opt, ) %>
% } 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 ) %>
@@ -34,19 +35,20 @@
<% pkg_status_row( $cust_pkg, 'Suspended', 'susp', 'color'=>'FF9900', %opt ) %>
- <% pkg_status_row_colspan(
+ <% pkg_status_row_colspan( $cust_pkg,
( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
- 'align' => 'right', 'color' => 'FF9900', 'size' => '-2',
+ 'align'=>'right', 'color'=>'FF9900', 'size'=>'-2', 'colspan'=>$colspan,
+ %opt,
)
%>
% unless ( $cust_pkg->get('setup') ) {
- <% pkg_status_row_colspan('Never billed') %>
+ <% pkg_status_row_colspan( $cust_pkg, 'Never billed', '', 'colspan'=>$colspan, %opt ) %>
% } 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 +72,15 @@
%
% unless ( $part_pkg->freq ) {
- <% pkg_status_row_colspan('Not&nbsp;yet&nbsp;billed&nbsp;(one-time&nbsp;charge)') %>
+ <% pkg_status_row_colspan( $cust_pkg, 'Not&nbsp;yet&nbsp;billed&nbsp;(one-time&nbsp;charge)', '', 'colspan'=>$colspan, %opt ) %>
+
+ <% pkg_status_row_if(
+ $cust_pkg,
+ ( $part_pkg->freq ? 'Start billing' : 'Bill on' ),
+ 'start_date',
+ %opt
+ )
+ %>
<TR>
<TD COLSPAN=<%$colspan%>>
@@ -84,7 +94,9 @@
% } else {
- <% pkg_status_row_colspan("Not&nbsp;yet&nbsp;billed&nbsp;($billed_or_prepaid&nbsp;". myfreq($part_pkg). ')' ) %>
+ <% pkg_status_row_colspan($cust_pkg, "Not&nbsp;yet&nbsp;billed&nbsp;($billed_or_prepaid&nbsp;". myfreq($part_pkg). ')', '', 'colspan'=>$colspan, %opt ) %>
+
+ <% pkg_status_row_if($cust_pkg, 'Start billing', 'start_date', %opt) %>
% }
%
@@ -92,7 +104,7 @@
%
% unless ( $part_pkg->freq ) {
- <% pkg_status_row_colspan('One-time&nbsp;charge') %>
+ <% pkg_status_row_colspan($cust_pkg, 'One-time&nbsp;charge', '', 'colspan'=>$colspan, %opt ) %>
<% pkg_status_row($cust_pkg, 'Billed', 'setup', %opt) %>
@@ -100,18 +112,20 @@
%
% if (scalar($cust_pkg->overlimit)) {
- <% pkg_status_row_colspan(
+ <% pkg_status_row_colspan( $cust_pkg,
'Overlimit',
$billed_or_prepaid. '&nbsp;'. myfreq($part_pkg),
- 'color' => 'FFD000',
+ 'color'=>'FFD000', 'colspan'=>$colspan,
+ %opt
)
%>
% } else {
- <% pkg_status_row_colspan(
+ <% pkg_status_row_colspan( $cust_pkg,
'Active',
$billed_or_prepaid. '&nbsp;'. myfreq($part_pkg),
- 'color' => '00CC00',
+ 'color'=>'00CC00', 'colspan'=>$colspan,
+ %opt
)
%>
% }
@@ -122,12 +136,12 @@
%
% }
%
-% if ( $conf->exists('cust_pkg-show_autosuspend') ) {
+% if ( $opt{'cust_pkg-show_autosuspend'} ) {
% my $autosuspend = pkg_autosuspend_time( $cust_pkg );
% $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) %>
@@ -165,13 +179,10 @@
</TABLE>
</TD>
-
<%init>
my %opt = @_;
-my $conf = new FS::Conf;
-
my $bgcolor = $opt{'bgcolor'};
my $cust_pkg = $opt{'cust_pkg'};
my $part_pkg = $opt{'part_pkg'};
@@ -216,8 +227,15 @@ sub pkg_status_row {
$html .= qq(<FONT COLOR="#$color"><B>) if length($color);
$html .= qq($title&nbsp;);
$html .= qq(</B></FONT>) if length($color);
+
+ if ( $opt{'pkg_balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge
+ $html .= ' (Balance:&nbsp;<B>'. $opt{'money_char'}.
+ $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum).
+ '</B>)';
+ }
+
$html .= qq(</TD>);
- $html .= pkg_datestr($cust_pkg, $field, %opt).'</TR>';
+ $html .= pkg_datestr($cust_pkg, $field, %opt). '</TR>';
$html;
}
@@ -240,20 +258,31 @@ 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. ' - '. $part_pkg->comment;
- $html .= pkg_status_row_colspan( $label, '', size=>'-1', align=>'right' );
+ $part_pkg->pkg_comment(nopartpkg => 1);
+ $html .= pkg_status_row_colspan( $cust_pkg, $label, '',
+ 'size' => '-1',
+ 'align' => 'right',
+ 'colspan' => $opt{'colspan'},
+ );
}
+
$html;
}
sub pkg_status_row_colspan {
- my($title, $addl, %opt) = @_;
+ my($cust_pkg, $title, $addl, %opt) = @_;
+
+ my $colspan = $opt{'colspan'};
my $align = $opt{'align'} ? 'ALIGN="'. $opt{'align'}.'"' : '';
my $color = $opt{'color'} ? 'COLOR="#'.$opt{'color'}.'"' : '';
@@ -266,6 +295,13 @@ sub pkg_status_row_colspan {
$html .= qq(</B>) if $color && !$size;
$html .= qq(</FONT>) if length($color) || $size;
$html .= ",&nbsp;$addl" if length($addl);
+
+ if ( $opt{'pkg-balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge
+ $html .= ' (Balance:&nbsp;<B>'. $opt{'money_char'}.
+ $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum).
+ '</B>)';
+ }
+
$html .= qq(</TD></TR>);
$html;
diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html
index 335ce24..2ac3f26 100644
--- a/httemplate/view/cust_main/payment_history.html
+++ b/httemplate/view/cust_main/payment_history.html
@@ -1,5 +1,3 @@
-<BR><BR><A NAME="history"><FONT SIZE="+2">Payment History</FONT></A><BR>
-
%# payment links
% my $s = 0;
@@ -129,10 +127,33 @@
%# tax exemption link
-% if ( $curuser->access_right('View customer tax exemptions') ) {
- <A HREF="<% $p %>search/cust_tax_exempt_pkg.cgi?custnum=<% $custnum %>">View tax exemptions</A>
+% my $view_exemptions = $curuser->access_right('View customer tax exemptions');
+% my $add_adjustment = ( $conf->exists('enable_tax_adjustments')
+% && $curuser->access_right('Add customer tax adjustment')
+% );
+% if ( $view_exemptions || $add_adjustment ) {
+
+% if ( $view_exemptions ) {
+ <A HREF="<% $p %>search/cust_tax_exempt_pkg.cgi?custnum=<% $custnum %>">View tax exemptions</A>
+ <% $add_adjustment ? '|' : '' %>
+% }
+
+% if ( $add_adjustment ) {
+ <% include('/elements/popup_link.html', {
+ 'action' => $p.'edit/cust_tax_adjustment.html?custnum='. $cust_main->custnum,
+ 'label' => 'Add tax adjustment',
+ 'actionlabel' => 'Add tax adjustment',
+ #'color' => '#333399',
+ #'width' => 763,
+ 'height' => 200,
+ })
+ %>
+ |
+ <A HREF="<% $p %>search/cust_tax_adjustment.html?custnum=<% $custnum %>">View tax adjustments</A>
+% }
+
<BR>
-% }
+% }
%# batched payment links
@@ -353,13 +374,14 @@ my %status = (
#get payment history
my @history = ();
-my %opt =
+my %opt = (
( map { $_ => scalar($conf->config($_)) }
qw( card_refund-days )
),
( map { $_ => $conf->exists($_) }
- qw( deletepayments deleterefunds )
- );
+ qw( deleteinvoices deletepayments deleterefunds pkg-balances )
+ )
+);
#invoices
foreach my $cust_bill ($cust_main->cust_bill) {
@@ -370,6 +392,15 @@ foreach my $cust_bill ($cust_main->cust_bill) {
};
}
+#statements
+foreach my $cust_statement ($cust_main->cust_statement) {
+ push @history, {
+ 'date' => $cust_statement->_date,
+ 'desc' => include('payment_history/statement.html', $cust_statement, %opt ),
+ #'charge' => $cust_bill->charged,
+ };
+}
+
#payments (some false laziness w/credits)
foreach my $cust_pay ($cust_main->cust_pay) {
push @history, {
@@ -384,7 +415,7 @@ foreach my $cust_pay ($cust_main->cust_pay) {
foreach my $cust_pay_void ($cust_main->cust_pay_void) {
push @history, {
'date' => $cust_pay_void->_date,
- 'desc' => include('payment_history/voided_payment.html', $cust_pay_void),
+ 'desc' => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
'void_payment' => $cust_pay_void->paid,
};
@@ -394,7 +425,7 @@ foreach my $cust_pay_void ($cust_main->cust_pay_void) {
foreach my $cust_credit ($cust_main->cust_credit) {
push @history, {
'date' => $cust_credit->_date,
- 'desc' => include('payment_history/credit.html', $cust_credit),
+ 'desc' => include('payment_history/credit.html', $cust_credit, %opt ),
'credit' => $cust_credit->amount,
};
diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html
index 2deb275..058c6f5 100644
--- a/httemplate/view/cust_main/payment_history/credit.html
+++ b/httemplate/view/cust_main/payment_history/credit.html
@@ -9,7 +9,13 @@ my $curuser = $FS::CurrentUser::CurrentUser;
my @cust_credit_bill = $cust_credit->cust_credit_bill;
my @cust_credit_refund = $cust_credit->cust_credit_refund;
-my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
+my $desc = '';
+if ( $opt{'pkg-balances'} && $cust_credit->pkgnum ) {
+ my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_credit->pkgnum } );
+ $desc .= ' for '. $cust_pkg->pkg_label_long;
+}
+
+my( $pre, $post, $apply, $ext ) = ( '', '', '', '' );
if ( scalar(@cust_credit_bill) == 0
&& scalar(@cust_credit_refund) == 0 ) {
#completely unapplied
@@ -45,15 +51,15 @@ if ( scalar(@cust_credit_bill) == 0
&& scalar(@cust_credit_refund) == 0
&& $cust_credit->credited == 0 ) {
#applied to one invoice, the usual situation
- $desc = ' '. $cust_credit_bill[0]->applied_to_invoice;
+ $desc .= ' '. $cust_credit_bill[0]->applied_to_invoice;
} elsif ( scalar(@cust_credit_bill) == 0
&& scalar(@cust_credit_refund) == 1
&& $cust_credit->credited == 0 ) {
#applied to one refund
- $desc = ' refunded on '. time2str("%D", $cust_credit_refund[0]->_date);
+ $desc .= ' refunded on '. time2str("%D", $cust_credit_refund[0]->_date);
} else {
#complicated
- $desc = '<BR>';
+ $desc .= '<BR>';
foreach my $app ( sort { $a->_date <=> $b->_date }
( @cust_credit_bill, @cust_credit_refund ) ) {
if ( $app->isa('FS::cust_credit_bill') ) {
diff --git a/httemplate/view/cust_main/payment_history/invoice.html b/httemplate/view/cust_main/payment_history/invoice.html
index 39c6739..c0d32df 100644
--- a/httemplate/view/cust_main/payment_history/invoice.html
+++ b/httemplate/view/cust_main/payment_history/invoice.html
@@ -1,9 +1,11 @@
-<% $link %><% $pre %>Invoice #<% $invnum %>
-(Balance $ <% $cust_bill->owed %>)<% $post %><% $link ? '</A>' : '' %><% $events %>
+<% $link %><% $pre %>Invoice #<% $cust_bill->display_invnum %>
+(Balance $ <% $cust_bill->owed %>)<% $post %><% $link ? '</A>' : '' %><% $delete %><% $events %>
<%init>
my( $cust_bill, %opt ) = @_;
+my $conf = new FS::Conf;
+
my $curuser = $FS::CurrentUser::CurrentUser;
my($pre, $post) = ('', '');
@@ -18,6 +20,15 @@ my $link = $curuser->access_right('View invoices')
? qq!<A HREF="${p}view/cust_bill.cgi?$invnum">!
: '';
+my $delete = '';
+if ( $opt{'deleteinvoices'} && $curuser->access_right('Delete invoices') ) {
+ $delete = qq! (<A HREF="javascript:areyousure('!.
+ qq!${p}misc/delete-cust_bill.html?$invnum',!.
+ qq!'Are you sure you want to delete this invoice?')"!.
+ qq! TITLE="Delete this invoice from the database completely"!.
+ qq!>delete</A>)!;
+}
+
my $events = '';
#1.9
if ( $cust_bill->num_cust_event
@@ -26,8 +37,8 @@ if ( $cust_bill->num_cust_event
)
) {
$events =
- qq!<BR><FONT SIZE="-1"><A HREF="${p}search/cust_event.html?invnum=!.
- $cust_bill->invnum. '">(&nbsp;View invoice events&nbsp;)</A></FONT>';
+ qq!<BR><FONT SIZE="-1"><A HREF="${p}search/cust_event.html?invnum=$invnum!.
+ '">(&nbsp;View invoice events&nbsp;)</A></FONT>';
}
#
diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html
index 2e24b17..a4a349b 100644
--- a/httemplate/view/cust_main/payment_history/payment.html
+++ b/httemplate/view/cust_main/payment_history/payment.html
@@ -32,7 +32,13 @@ $payby =~ s/^MCRD$/Manual credit card/;
$payby =~ s/^BILL$//;
my $info = $payby ? "($payby$payinfo)" : '';
-my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
+my $desc = '';
+if ( $opt{'pkg-balances'} && $cust_pay->pkgnum ) {
+ my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_pay->pkgnum } );
+ $desc .= ' for '. $cust_pkg->pkg_label_long;
+}
+
+my( $pre, $post, $apply, $ext ) = ( '', '', '', '' );
if ( scalar(@cust_bill_pay) == 0
&& scalar(@cust_pay_refund) == 0 ) {
#completely unapplied
@@ -68,15 +74,15 @@ if ( scalar(@cust_bill_pay) == 0
&& scalar(@cust_pay_refund) == 0
&& $cust_pay->unapplied == 0 ) {
#applied to one invoice, the usual situation
- $desc = ' '. $cust_bill_pay[0]->applied_to_invoice;
+ $desc .= ' '. $cust_bill_pay[0]->applied_to_invoice;
} elsif ( scalar(@cust_bill_pay) == 0
&& scalar(@cust_pay_refund) == 1
&& $cust_pay->unapplied == 0 ) {
#applied to one refund
- $desc = ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date);
+ $desc .= ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date);
} else {
#complicated
- $desc = '<BR>';
+ $desc .= '<BR>';
foreach my $app ( sort { $a->_date <=> $b->_date }
( @cust_bill_pay, @cust_pay_refund ) ) {
if ( $app->isa('FS::cust_bill_pay') ) {
diff --git a/httemplate/view/cust_main/payment_history/statement.html b/httemplate/view/cust_main/payment_history/statement.html
new file mode 100644
index 0000000..dedec9b
--- /dev/null
+++ b/httemplate/view/cust_main/payment_history/statement.html
@@ -0,0 +1,34 @@
+<% $link %><% $pre %>Statement #<% $statementnum %>
+%# (Balance $ <% $cust_statement->owed %>)
+<% $post %><% $link ? '</A>' : '' %><% $events %>
+<%init>
+
+my( $cust_statement, %opt ) = @_;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+my($pre, $post) = ('', '');
+#if ( $cust_statement->owed > 0 ) {
+# $pre = '<B><FONT SIZE="+1" COLOR="#FF0000">Open ';
+# $post = '</FONT></B>';
+#}
+
+my $statementnum = $cust_statement->statementnum;
+
+my $link = $curuser->access_right('View invoices')
+ ? qq!<A HREF="${p}view/cust_statement.html?$statementnum">!
+ : '';
+
+my $events = '';
+
+#if ( $cust_statement->num_cust_event
+# && ( $curuser->access_right('Billing event reports')
+# || $curuser->access_right('View customer billing events')
+# )
+# ) {
+# $events =
+# qq!<BR><FONT SIZE="-1"><A HREF="${p}search/cust_event.html?statementnum=!.
+# $cust_statement->statementnum. '">(&nbsp;View statement events&nbsp;)</A></FONT>';
+#}
+
+</%init>
diff --git a/httemplate/view/cust_main/payment_history/voided_payment.html b/httemplate/view/cust_main/payment_history/voided_payment.html
index 9cbc47b..6103727 100644
--- a/httemplate/view/cust_main/payment_history/voided_payment.html
+++ b/httemplate/view/cust_main/payment_history/voided_payment.html
@@ -8,15 +8,32 @@ my( $cust_pay_void, %opt ) = @_;
my $curuser = $FS::CurrentUser::CurrentUser;
my $payby = $cust_pay_void->payby;
-my $payinfo = $payby eq 'CARD'
- ? $cust_pay_void->paymask
- : $cust_pay_void->payinfo;
+
+my $payinfo;
+if ( $payby eq 'CARD' ) {
+ $payinfo = $cust_pay_void->paymask;
+} elsif ( $payby eq 'CHEK' ) {
+ my( $account, $aba ) = split('@', $cust_pay_void->paymask );
+ $payinfo = "ABA $aba, Acct #$account";
+} else {
+ $payinfo = $cust_pay_void->payinfo;
+}
$payby =~ s/^BILL$/Check #/ if $payinfo;
$payby =~ s/^CHEK$/Electronic check /;
+$payby =~ s/^PREP$/Prepaid card /;
+$payby =~ s/^CARD$/Credit card #/;
+$payby =~ s/^COMP$/Complimentary by /;
+$payby =~ s/^CASH$/Cash/;
+$payby =~ s/^WEST$/Western Union/;
+$payby =~ s/^MCRD$/Manual credit card/;
$payby =~ s/^BILL$//;
-$payby =~ s/^(CARD|COMP)$/$1 /;
-my $info = $payby ? " ($payby$payinfo)" : '';
+my $info = $payby ? "($payby$payinfo)" : '';
+
+if ( $opt{'pkg-balances'} && $cust_pay_void->pkgnum ) {
+ my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_pay_void->pkgnum } );
+ $info .= ' for '. $cust_pkg->pkg_label_long;
+}
my $unvoid = '';
if ( $cust_pay_void->closed !~ /^Y/i
diff --git a/httemplate/view/cust_main/tickets.html b/httemplate/view/cust_main/tickets.html
index b5d581d..167849c 100644
--- a/httemplate/view/cust_main/tickets.html
+++ b/httemplate/view/cust_main/tickets.html
@@ -1,6 +1,3 @@
-<A NAME="tickets"><FONT SIZE="+2">Tickets</FONT></A>
-<BR>
-
(<A HREF="<% $open_link %>">View <% $openlabel %> tickets for this customer</A>)
(<A HREF="<% $res_link %>">View resolved tickets for this customer</A>)
<BR>
diff --git a/httemplate/view/cust_pay.html b/httemplate/view/cust_pay.html
index c36d769..2f23d9e 100644
--- a/httemplate/view/cust_pay.html
+++ b/httemplate/view/cust_pay.html
@@ -1,12 +1,12 @@
% if ( $link eq 'popup' ) {
- <% include('/elements/header-popup.html', "Payment Receipt" ) %>
+ <% include('/elements/header-popup.html', "$thing Receipt" ) %>
<CENTER><A HREF="javascript:self.parent.location = '<% $pr_link %>'">Print</A></CENTER><BR>
% } elsif ( $link eq 'print' ) {
- <% include('/elements/header-popup.html', "Payment Receipt" ) %>
+ <% include('/elements/header-popup.html', "$thing Receipt" ) %>
% #it would be nice if the menubar could be hidden for print, but better to
% # have it available than not, otherwise the user winds up at a dead end
@@ -18,7 +18,7 @@
% } else {
- <% include('/elements/header.html', "Payment Receipt", menubar(
+ <% include('/elements/header.html', "$thing Receipt", menubar(
"View this customer (#$display_custnum)" => "${p}view/cust_main.cgi?$custnum",
'Print receipt' => $pr_link,
))
@@ -48,6 +48,20 @@
<TD BGCOLOR="#FFFFFF"><B><% time2str"%a&nbsp;%b&nbsp;%o,&nbsp;%Y&nbsp;%r", $cust_pay->_date %></B></TD>
</TR>
+% if ( $void ) {
+
+ <TR>
+ <TD ALIGN="right">Void Date</TD>
+ <TD BGCOLOR="#FFFFFF"><B><% time2str"%a&nbsp;%b&nbsp;%o,&nbsp;%Y&nbsp;%r", $cust_pay->void_date %></B></TD>
+ </TR>
+
+%# <TR>
+%# <TD ALIGN="right">Void reason</TD>
+%# <TD BGCOLOR="#FFFFFF"><B><% $cust_pay->reason %></B></TD>
+%# </TR>
+
+% }
+
<TR>
<TD ALIGN="right">Amount</TD>
<TD BGCOLOR="#FFFFFF"><B><% $money_char. $cust_pay->paid %></B></TD>
@@ -79,6 +93,15 @@
% }
+% if ( $conf->exists('pkg-balances') && $cust_pay->pkgnum ) {
+% my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_pay->pkgnum } );
+ <TR>
+ <TD ALIGN="right">For package</TD>
+ <TD BGCOLOR="#FFFFFF"><B><% $cust_pkg->pkg_label_long %></B></TD>
+ </TR>
+
+% }
+
</TABLE>
% if ( $link eq 'print' ) {
@@ -112,16 +135,20 @@ if ( $cgi->param('link') =~ /^(\w+)$/ ) {
$link = $1;
}
+my $void = $cgi->param('void') ? 1 : 0;
+my $thing = $void ? 'Voided Payment' : 'Payment';
+my $table = $void ? 'cust_pay_void' : 'cust_pay';
+
my $cust_pay = qsearchs({
- 'select' => 'cust_pay.*',
- 'table' => 'cust_pay',
+ 'select' => "$table.*",
+ 'table' => $table,
'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
'hashref' => { 'paynum' => $paynum },
'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
});
-die "Payment #$paynum not found!" unless $cust_pay;
+die "$thing #$paynum not found!" unless $cust_pay;
-my $pr_link = "${p}view/cust_pay.html?link=print;paynum=$paynum";
+my $pr_link = "${p}view/cust_pay.html?link=print;paynum=$paynum;void=$void";
my $custnum = $cust_pay->custnum;
my $display_custnum = $cust_pay->cust_main->display_custnum;
diff --git a/httemplate/view/cust_pay_void.html b/httemplate/view/cust_pay_void.html
new file mode 100644
index 0000000..8c22170
--- /dev/null
+++ b/httemplate/view/cust_pay_void.html
@@ -0,0 +1 @@
+<% include('cust_pay.html', @_, 'void' => 1 ) %>
diff --git a/httemplate/view/cust_statement-pdf.cgi b/httemplate/view/cust_statement-pdf.cgi
new file mode 100755
index 0000000..a1739e0
--- /dev/null
+++ b/httemplate/view/cust_statement-pdf.cgi
@@ -0,0 +1,28 @@
+<% $pdf %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('View invoices');
+
+#untaint statementnum
+my($query) = $cgi->keywords;
+$query =~ /^((.+)-)?(\d+)(.pdf)?$/;
+my $templatename = $2 || 'statement'; #XXX configure... via event?? eh..
+my $statementnum = $3;
+
+my $cust_statement = qsearchs({
+ 'select' => 'cust_statement.*',
+ 'table' => 'cust_statement',
+ 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
+ 'hashref' => { 'statementnum' => $statementnum },
+ 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+});
+die "Statement #$statementnum not found!" unless $cust_statement;
+
+my $pdf = $cust_statement->print_pdf( '', $templatename);
+
+http_header('Content-Type' => 'application/pdf' );
+http_header('Content-Length' => length($pdf) );
+http_header('Cache-control' => 'max-age=60' );
+
+</%init>
diff --git a/httemplate/view/cust_statement.html b/httemplate/view/cust_statement.html
new file mode 100755
index 0000000..3e1345e
--- /dev/null
+++ b/httemplate/view/cust_statement.html
@@ -0,0 +1,79 @@
+<% include("/elements/header.html",'Statement View', menubar(
+ "View this customer (#$display_custnum)" => "${p}view/cust_main.cgi?$custnum",
+)) %>
+
+% if ( $FS::CurrentUser::CurrentUser->access_right('Resend invoices') ) {
+
+%# <A HREF="<% $p %>misc/send-statement.cgi?method=print;<% $link %>">Re-print this statement</A>
+
+% if ( grep { $_ ne 'POST' } $cust_statement->cust_main->invoicing_list ) {
+%# |
+ <A HREF="<% $p %>misc/send-statement.cgi?method=email;<% $link %>">Re-email this statement</A>
+% }
+
+% if ( 0 ) {
+% #if ( $conf->exists('hylafax') && length($cust_statement->cust_main->fax) ) {
+ | <A HREF="<% $p %>misc/send-statement.cgi?method=fax;<% $link %>">Re-fax this statement</A>
+% }
+
+ <BR><BR>
+
+% }
+
+
+% #if ( $conf->exists('invoice_latex') ) {
+% if ( 0 ) { #broken???
+
+ <A HREF="<% $p %>view/cust_statement-pdf.cgi?<% $link %>">View typeset statement</A>
+ <BR><BR>
+% }
+
+% #if ( $cust_statement->num_cust_event ) {
+% if ( 0 ) {
+<A HREF="<%$p%>search/cust_event.html?statementnum=<% $cust_statement->statementnum %>">(&nbsp;View statement events&nbsp;)</A><BR><BR>
+% }
+
+% if ( $conf->exists('invoice_html') ) {
+
+ <% join('', $cust_statement->print_html('', $templatename) ) %>
+% } else {
+
+ <PRE><% join('', $cust_statement->print_text('', $templatename) ) %></PRE>
+% }
+
+<% include('/elements/footer.html') %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('View invoices');
+
+#untaint statement
+my($query) = $cgi->keywords;
+$query =~ /^((.+)-)?(\d+)$/;
+my $templatename = $2 || 'statement'; #XXX configure... via event?? eh..
+my $statementnum = $3;
+
+my $conf = new FS::Conf;
+
+my @payby = grep /\w/, $conf->config('payby');
+#@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH WEST COMP ))
+@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH COMP ))
+ unless @payby;
+my %payby = map { $_=>1 } @payby;
+
+my $cust_statement = qsearchs({
+ 'select' => 'cust_statement.*',
+ 'table' => 'cust_statement',
+ 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
+ 'hashref' => { 'statementnum' => $statementnum },
+ 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+});
+die "Statement #$statementnum not found!" unless $cust_statement;
+
+my $custnum = $cust_statement->custnum;
+my $display_custnum = $cust_statement->cust_main->display_custnum;
+
+my $link = "statementnum=$statementnum";
+$link .= ';template='. uri_escape($templatename) if $templatename;
+
+</%init>
diff --git a/httemplate/view/elements/svc_Common.html b/httemplate/view/elements/svc_Common.html
index a0b4e37..852640e 100644
--- a/httemplate/view/elements/svc_Common.html
+++ b/httemplate/view/elements/svc_Common.html
@@ -1,30 +1,40 @@
-% # options example...
-% #
-% # 'table' => 'svc_something'
-% #
-% # 'labels' => {
-% # 'column' => 'Label',
-% # },
-% #
-% # listref - each item is a literal column name (or method) or (notyet) coderef
-% # if not specified all columns (except for the primary key) will be viewable
-% # 'fields' => [
-% # ]
-% #
-% # # defaults to "edit/$table.cgi?", will have svcnum appended
-% # 'edit_url' =>
-%
-%
-% if ( $custnum ) {
+<%doc>
+
+#Example:
+
+ include( 'elements/svc_Common.html,
+
+ 'table' => 'svc_something'
+ 'labels' => {
+ 'column' => 'Label',
+ },
+
+ #listref - each item is a literal column name (or method) or
+ # (notyet) coderef. if not specified all columns (except for the
+ #primary key) will be viewable
+ 'fields' => [
+ ]
+
+ # defaults to "edit/$table.cgi?", will have svcnum appended
+ 'edit_url' =>
+ )
+
+</%doc>
+% if ( $custnum ) {
<% include("/elements/header.html","View $label: $value") %>
<% include( '/elements/small_custview.html', $custnum, '', 1,
"${p}view/cust_main.cgi") %>
<BR>
+
% } else {
+ <% include("/elements/header.html","View $label: $value", menubar(
+ "Cancel this (unaudited) $label" =>
+ "javascript:areyousure(\'${p}misc/cancel-unaudited.cgi?$svcnum\')"
+ )) %>
<SCRIPT>
function areyousure(href) {
@@ -33,13 +43,8 @@
}
</SCRIPT>
- <% include("/elements/header.html","View $label: $value", menubar(
- "Cancel this (unaudited) $label" =>
- "javascript:areyousure(\'${p}misc/cancel-unaudited.cgi?$svcnum\')"
- )) %>
% }
-
Service #<B><% $svcnum %></B>
% my $url = $opt{'edit_url'} || $p. 'edit/'. $opt{'table'}. '.cgi?';
| <A HREF="<%$url%><%$svcnum%>">Edit this <% $label %></A>
@@ -130,7 +135,9 @@ my $svc_x = qsearchs({
' LEFT JOIN cust_pkg USING ( pkgnum ) '.
' LEFT JOIN cust_main USING ( custnum ) ',
'hashref' => { 'svcnum' => $svcnum },
- 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+ 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql(
+ 'null_right' => 'View/link unlinked services'
+ ),
}) or die "Unknown svcnum $svcnum in ". $opt{'table'}. " table\n";
my $cust_svc = $svc_x->cust_svc;
@@ -138,6 +145,14 @@ my($label, $value, $svcdb) = $cust_svc->label;
my $part_svc = $cust_svc->part_svc;
+ #false laziness w/edit/svc_Common.html
+ #override default labels with service-definition labels if applicable
+ my $labels = $opt{labels}; #not -> here
+ foreach my $field ( keys %$labels ) {
+ my $col = $part_svc->part_svc_column($field);
+ $labels->{$field} = $col->columnlabel if $col->columnlabel !~ /^\S*$/;
+ }
+
my $pkgnum = $cust_svc->pkgnum;
my($cust_pkg, $custnum);
diff --git a/httemplate/view/svc_Common.html b/httemplate/view/svc_Common.html
index bb3a6dd..defbee9 100644
--- a/httemplate/view/svc_Common.html
+++ b/httemplate/view/svc_Common.html
@@ -1,3 +1,9 @@
+<% include('elements/svc_Common.html',
+ 'table' => $table,
+ 'edit_url' => $p."edit/svc_Common.html?svcdb=$table;svcnum=",
+ %opt,
+ )
+%>
<%init>
# false laziness w/edit/svc_Common.html
@@ -21,9 +27,3 @@ if ( UNIVERSAL::can("FS::$table", 'table_info') ) {
}
</%init>
-<% include('elements/svc_Common.html',
- 'table' => $table,
- 'edit_url' => $p."edit/svc_Common.html?svcdb=$table;svcnum=",
- %opt,
- )
-%>
diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi
index e87a8ee..6a47ec7 100755
--- a/httemplate/view/svc_acct.cgi
+++ b/httemplate/view/svc_acct.cgi
@@ -214,7 +214,7 @@ Service #<B><% $svcnum %></B>
% if ($svc_acct->finger ne '') {
<TR>
- <TD ALIGN="right">GECOS</TD>
+ <TD ALIGN="right">Real Name</TD>
<TD BGCOLOR="#ffffff"><% $svc_acct->finger %></TD>
</TR>
% }
diff --git a/httemplate/view/svc_broadband.cgi b/httemplate/view/svc_broadband.cgi
index 145d341..1463925 100644
--- a/httemplate/view/svc_broadband.cgi
+++ b/httemplate/view/svc_broadband.cgi
@@ -8,7 +8,9 @@
))
%>
-<A HREF="<%${p}%>edit/svc_broadband.cgi?<%$svcnum%>">Edit this information</A>
+<% include('/elements/init_overlib.html') %>
+
+<A HREF="<%$p%>edit/svc_broadband.cgi?<%$svcnum%>">Edit this information</A>
<BR>
<%ntable("#cccccc")%>
<TR>
@@ -22,10 +24,14 @@
<TD ALIGN="right">Description</TD>
<TD BGCOLOR="#ffffff"><%$description%></TD>
</TR>
- <TR>
- <TD ALIGN="right">Router</TD>
- <TD BGCOLOR="#ffffff"><%$routernum%>: <%$routername%></TD>
- </TR>
+
+% if ( $router ) {
+ <TR>
+ <TD ALIGN="right">Router</TD>
+ <TD BGCOLOR="#ffffff"><%$router->routernum%>: <%$router->routername%></TD>
+ </TR>
+% }
+
<TR>
<TD ALIGN="right">Download Speed</TD>
<TD BGCOLOR="#ffffff"><%$speed_down%></TD>
@@ -34,18 +40,25 @@
<TD ALIGN="right">Upload Speed</TD>
<TD BGCOLOR="#ffffff"><%$speed_up%></TD>
</TR>
- <TR>
- <TD ALIGN="right">IP Address</TD>
- <TD BGCOLOR="#ffffff"><%$ip_addr%></TD>
- </TR>
- <TR>
- <TD ALIGN="right">IP Netmask</TD>
- <TD BGCOLOR="#ffffff"><%$ip_netmask%></TD>
- </TR>
- <TR>
- <TD ALIGN="right">IP Gateway</TD>
- <TD BGCOLOR="#ffffff"><%$ip_gateway%></TD>
- </TR>
+
+% if ( $ip_addr ) {
+ <TR>
+ <TD ALIGN="right">IP Address</TD>
+ <TD BGCOLOR="#ffffff">
+ <%$ip_addr%>
+ (<% include('/elements/popup_link-ping.html', 'ip'=>$ip_addr ) %>)
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">IP Netmask</TD>
+ <TD BGCOLOR="#ffffff"><%$addr_block->NetAddr->mask%></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">IP Gateway</TD>
+ <TD BGCOLOR="#ffffff"><%$addr_block->ip_gateway%></TD>
+ </TR>
+% }
+
<TR>
<TD ALIGN="right">MAC Address</TD>
<TD BGCOLOR="#ffffff"><%$mac_addr%></TD>
@@ -173,18 +186,14 @@ if ($pkgnum) {
#eofalse
my $addr_block = $svc_broadband->addr_block;
-my $router = $addr_block->router;
+my $router = $addr_block->router if $addr_block;
-if (not $router) { die "Could not lookup router for svc_broadband (svcnum $svcnum)" };
+#if (not $router) { die "Could not lookup router for svc_broadband (svcnum $svcnum)" };
my (
- $routername,
- $routernum,
$speed_down,
$speed_up,
$ip_addr,
- $ip_gateway,
- $ip_netmask,
$mac_addr,
$latitude,
$longitude,
@@ -193,13 +202,9 @@ my (
$auth_key,
$description,
) = (
- $router->getfield('routername'),
- $router->getfield('routernum'),
$svc_broadband->getfield('speed_down'),
$svc_broadband->getfield('speed_up'),
$svc_broadband->getfield('ip_addr'),
- $addr_block->ip_gateway,
- $addr_block->NetAddr->mask,
$svc_broadband->mac_addr,
$svc_broadband->latitude,
$svc_broadband->longitude,
diff --git a/httemplate/view/svc_domain.cgi b/httemplate/view/svc_domain.cgi
index 8c1f4ce..fc099d8 100755
--- a/httemplate/view/svc_domain.cgi
+++ b/httemplate/view/svc_domain.cgi
@@ -7,9 +7,29 @@
)
)) %>
+<% include('/elements/error.html') %>
+
Service #<% $svcnum %>
<BR>Service: <B><% $part_svc->svc %></B>
<BR>Domain name: <B><% $domain %></B>
+% if ($export) {
+<BR>Status: <B><% $status %></B>
+% if ( $FS::CurrentUser::CurrentUser->access_right('Manage domain registration') ) {
+% if ( defined($ops{'register'}) ) {
+ <A HREF="<% ${p} %>edit/process/domreg.cgi?op=register&svcnum=<% $svcnum %>">Register at <% $registrar->{'name'} %></A>&nbsp;
+% }
+% if ( defined($ops{'transfer'}) ) {
+ <A HREF="<% ${p} %>edit/process/domreg.cgi?op=transfer&svcnum=<% $svcnum %>">Transfer to <% $registrar->{'name'} %></A>&nbsp;
+% }
+% if ( defined($ops{'renew'}) ) {
+ <A HREF="<% ${p} %>edit/process/domreg.cgi?op=renew&svcnum=<% $svcnum %>&period=1">Renew at <% $registrar->{'name'} %></A>&nbsp;
+% }
+% if ( defined($ops{'revoke'}) ) {
+ <A HREF="<% ${p} %>edit/process/domreg.cgi?op=revoke&svcnum=<% $svcnum %>">Revoke</A>
+% }
+% }
+% }
+
% if ( $FS::CurrentUser::CurrentUser->access_right('Edit domain catchall') ) {
<BR>Catch all email <A HREF="<% ${p} %>misc/catchall.cgi?<% $svcnum %>">(change)</A>:
% } else {
@@ -138,9 +158,9 @@ my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum});
my $pkgnum = $cust_svc->getfield('pkgnum');
my($cust_pkg, $custnum, $display_custnum);
if ($pkgnum) {
- $cust_pkg =qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+ $cust_pkg = qsearchs('cust_pkg', {'pkgnum'=>$pkgnum} );
$custnum = $cust_pkg->custnum;
- $custnum = $cust_pkg->cust_main->display_custnum;
+ $display_custnum = $cust_pkg->cust_main->display_custnum;
} else {
$cust_pkg = '';
$custnum = '';
@@ -158,4 +178,37 @@ if ($svc_domain->catchall) {
my $domain = $svc_domain->domain;
+my $status = 'Unknown';
+my %ops = ();
+
+my @exports = $part_svc->part_export();
+
+my $registrar;
+my $export;
+
+# Find the first export that does domain registration
+foreach (@exports) {
+ $export = $_ if $_->can('registrar');
+}
+# If we have a domain registration export, get the registrar object
+if ($export) {
+ $registrar = $export->registrar;
+ my $domstat = $export->get_status( $svc_domain );
+ if (defined($domstat->{'message'})) {
+ $status = $domstat->{'message'};
+ } elsif (defined($domstat->{'unregistered'})) {
+ $status = 'Not registered';
+ $ops{'register'} = "Register";
+ } elsif (defined($domstat->{'status'})) {
+ $status = $domstat->{'status'} . ' ' . $domstat->{'contact_email'} . ' ' . $domstat->{'last_update_time'};
+ } elsif (defined($domstat->{'expdate'})) {
+ $status = "Expires " . $domstat->{'expdate'};
+ $ops{'renew'} = "Renew";
+ $ops{'revoke'} = "Revoke";
+ } else {
+ $status = $domstat->{'reason'};
+ $ops{'transfer'} = "Transfer";
+ }
+}
+
</%init>
diff --git a/httemplate/view/svc_phone.cgi b/httemplate/view/svc_phone.cgi
index f604daa..09d5be4 100644
--- a/httemplate/view/svc_phone.cgi
+++ b/httemplate/view/svc_phone.cgi
@@ -22,6 +22,74 @@
my $html_foot = sub {
my $svc_phone = shift;
+ ###
+ # Devices
+ ###
+
+ my $devices = '';
+
+ my $sth = dbh->prepare("SELECT COUNT(*) FROM part_device") #WHERE disabled = '' OR disabled IS NULL;");
+ or die dbh->errstr;
+ $sth->execute or die $sth->errstr;
+ my $num_part_device = $sth->fetchrow_arrayref->[0];
+
+ my @phone_device = $svc_phone->phone_device;
+ if ( @phone_device || $num_part_device ) {
+ my $svcnum = $svc_phone->svcnum;
+ $devices .=
+ qq[Devices (<A HREF="${p}edit/phone_device.html?svcnum=$svcnum">Add device</A>)<BR>];
+ if ( @phone_device ) {
+
+ $devices .= qq!
+ <SCRIPT>
+ function areyousure(href) {
+ if (confirm("Are you sure you want to delete this device?") == true)
+ window.location.href = href;
+ }
+ </SCRIPT>
+ !;
+
+
+ $devices .=
+ include('/elements/table-grid.html').
+ '<TR>'.
+ '<TH CLASS="grid" BGCOLOR="#cccccc">Type</TH>'.
+ '<TH CLASS="grid" BGCOLOR="#cccccc">MAC Addr</TH>'.
+ '<TH CLASS="grid" BGCOLOR="#cccccc"></TH>'.
+ '</TR>';
+ my $bgcolor1 = '#eeeeee';
+ my $bgcolor2 = '#ffffff';
+ my $bgcolor = '';
+
+ foreach my $phone_device ( @phone_device ) {
+
+ if ( $bgcolor eq $bgcolor1 ) {
+ $bgcolor = $bgcolor2;
+ } else {
+ $bgcolor = $bgcolor1;
+ }
+ my $td = qq(<TD CLASS="grid" BGCOLOR="$bgcolor">);
+
+ my $devicenum = $phone_device->devicenum;
+
+ $devices .= '<TR>'.
+ $td. $phone_device->part_device->devicename. '</TD>'.
+ $td. $phone_device->mac_addr. '</TD>'.
+ "$td( ".
+ qq(<A HREF="${p}edit/phone_device.html?$devicenum">edit</A> | ).
+ qq(<A HREF="javascript:areyousure('${p}misc/delete-phone_device.html?$devicenum')">delete</A>).
+ ' )</TD>'.
+ '</TR>';
+ }
+ $devices .= '</TABLE><BR>';
+ }
+ $devices .= '<BR>';
+ }
+
+ ##
+ # CDR links
+ ##
+
tie my %what, 'Tie::IxHash',
'pending' => 'NULL',
'billed' => 'done',
@@ -43,9 +111,14 @@ my $html_foot = sub {
"View $_ CDRs</A>";
} keys(%what);
- my @ilinks = ( qq(<A HREF="${p}search/cdr.html?dst=$number">).
+ my @ilinks = ( qq(<A HREF="${p}search/cdr.html?cdrbatch=__ALL__;dst=$number">).
'View incoming CDRs</A>' );
+ ###
+ # concatenate & return
+ ###
+
+ $devices.
join(' | ', @links ). '<BR>'.
join(' | ', @ilinks). '<BR>';