diff options
Diffstat (limited to 'httemplate/view/cust_main')
-rwxr-xr-x | httemplate/view/cust_main/attachments.html | 151 | ||||
-rw-r--r-- | httemplate/view/cust_main/billing.html | 37 | ||||
-rw-r--r-- | httemplate/view/cust_main/change_history.html | 302 | ||||
-rw-r--r-- | httemplate/view/cust_main/misc.html | 19 | ||||
-rw-r--r-- | httemplate/view/cust_main/one_time_charge_link.html | 91 | ||||
-rwxr-xr-x | httemplate/view/cust_main/packages.html | 214 | ||||
-rw-r--r-- | httemplate/view/cust_main/packages/package.html | 23 | ||||
-rw-r--r-- | httemplate/view/cust_main/packages/services.html | 28 | ||||
-rw-r--r-- | httemplate/view/cust_main/packages/status.html | 86 | ||||
-rw-r--r-- | httemplate/view/cust_main/payment_history.html | 51 | ||||
-rw-r--r-- | httemplate/view/cust_main/payment_history/credit.html | 14 | ||||
-rw-r--r-- | httemplate/view/cust_main/payment_history/invoice.html | 19 | ||||
-rw-r--r-- | httemplate/view/cust_main/payment_history/payment.html | 14 | ||||
-rw-r--r-- | httemplate/view/cust_main/payment_history/statement.html | 34 | ||||
-rw-r--r-- | httemplate/view/cust_main/payment_history/voided_payment.html | 27 | ||||
-rw-r--r-- | httemplate/view/cust_main/tickets.html | 3 |
16 files changed, 917 insertions, 196 deletions
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> |