diff options
Diffstat (limited to 'httemplate/view')
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! <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! <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! <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! <A HREF="javascript:void(0);" $clickjs>(delete)</A>!; +% } +% if ($curuser->access_right('Download attachment') ) { +% $edit .= qq! <A HREF="!.popurl(1).'attachment.html?'.$attachnum.qq!">(download)</A>!; +% } +% } + + <TR> + <% note_datestr($attach,$conf,$bgcolor) %> + <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> + <% $attach->otaker%> + </TD> + <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> + <% $attach->filename %> + </TD> + <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> + <% $attach->mime_type %> + </TD> + <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> + <% 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 %o, %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 exempt</TD> + <TD ALIGN="right">Tax 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 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 location</TD> + <TD BGCOLOR="#ffffff"><% $cust_main->geocode('cch') %></TD> +</TR> +% } <TR> <TD ALIGN="right">Postal 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 CDRs as 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/ / /g; + <% $d %> + </TD> + <TD ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>"> +% my $t = time2str('%r', $item->history_date ); +% $t =~ s/ / /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 from', + 'replace_new' => 'Change 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 new 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 new 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; - ( <%pkg_customize_link($cust_pkg,$cust_pkg->custnum)%> ) + ( <%pkg_customize_link($cust_pkg,$part_pkg)%> ) % } % <% $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"> - <% $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"> - <% $cust_pkg_detail->detail |h %></FONT></TD> </TR> @@ -198,9 +198,10 @@ sub pkg_dates_link { pkg_link('edit/REAL_cust_pkg', 'Edit 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 @@ % ) % ) { ( <%svc_recharge_link($cust_svc)%> ) -% } +% } </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') ) { - ( <%svc_unprovision_link($cust_svc)%> ) -% } - </FONT></TD> +% my $ip_addr = $cust_svc->svc_x->ip_addr; + +% if ( $part_svc->svcdb eq 'svc_broadband' ) { + <FONT SIZE="-1" STYLE="float:left">( <% include('/elements/popup_link-ping.html', 'ip'=> $ip_addr ) %> )</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">( <A HREF="<% $svc_manage_link %>">Manage Device</A> )</FONT> + +% } + +% if ( $curuser->access_right('Unprovision customer service') ) { + <FONT SIZE="-2">( <%svc_unprovision_link($cust_svc)%> )</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+/ /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 yet billed (one-time charge)') %> + <% pkg_status_row_colspan( $cust_pkg, 'Not yet billed (one-time 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 yet billed ($billed_or_prepaid ". myfreq($part_pkg). ')' ) %> + <% pkg_status_row_colspan($cust_pkg, "Not yet billed ($billed_or_prepaid ". 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 charge') %> + <% pkg_status_row_colspan($cust_pkg, 'One-time 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. ' '. 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. ' '. 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 ); $html .= qq(</B></FONT>) if length($color); + + if ( $opt{'pkg_balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge + $html .= ' (Balance: <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 changed', 'change_date', %opt ); + + my $html = + pkg_status_row( $cust_pkg, 'Package 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 .= ", $addl" if length($addl); + + if ( $opt{'pkg-balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge + $html .= ' (Balance: <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. '">( View invoice events )</A></FONT>'; + qq!<BR><FONT SIZE="-1"><A HREF="${p}search/cust_event.html?invnum=$invnum!. + '">( View invoice events )</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. '">( View statement events )</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 %b %o, %Y %r", $cust_pay->_date %></B></TD> </TR> +% if ( $void ) { + + <TR> + <TD ALIGN="right">Void Date</TD> + <TD BGCOLOR="#FFFFFF"><B><% time2str"%a %b %o, %Y %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 %>">( View statement events )</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> +% } +% if ( defined($ops{'transfer'}) ) { + <A HREF="<% ${p} %>edit/process/domreg.cgi?op=transfer&svcnum=<% $svcnum %>">Transfer to <% $registrar->{'name'} %></A> +% } +% if ( defined($ops{'renew'}) ) { + <A HREF="<% ${p} %>edit/process/domreg.cgi?op=renew&svcnum=<% $svcnum %>&period=1">Renew at <% $registrar->{'name'} %></A> +% } +% 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>'; |