diff options
Diffstat (limited to 'httemplate')
59 files changed, 1385 insertions, 455 deletions
diff --git a/httemplate/browse/access_user.html b/httemplate/browse/access_user.html index 321025b69..3162e3a6c 100644 --- a/httemplate/browse/access_user.html +++ b/httemplate/browse/access_user.html @@ -49,13 +49,29 @@ my $groups_sub = sub { }; +my $cust_sub = sub { + my $access_user = shift; + $access_user->user_custnum ? $access_user->user_cust_main->name : ''; +}; +my $cust_link = [ $p.'view/cust_main.cgi?custnum=', 'user_custnum' ]; + my $count_query = 'SELECT COUNT(*) FROM access_user'; my $link = [ $p.'edit/access_user.html?', 'usernum' ]; -my @header = ( '#', 'Username', 'Full name', 'Groups' ); -my @fields = ( 'usernum', 'username', 'name', $groups_sub ); -my $align = 'rlll'; -my @links = ( $link, $link, $link, '' ); +my @header = ( '#', 'Username', 'Full name', 'Groups', 'Customer' ); +my @fields = ( 'usernum', 'username', 'name', $groups_sub, $cust_sub, ); +my $align = 'rllll'; +my @links = ( $link, $link, $link, '', $cust_link ); + +#if ( FS::Conf->new->config('ticket_system') ) { +# push @header, 'Ticketing'; +# push @fields, sub { +# my $access_user = shift; +# +# }; +# $align .= 'l'; +# push @links, ''; +#} </%init> diff --git a/httemplate/browse/rate_detail.html b/httemplate/browse/rate_detail.html index 23bc23ff8..3371926b4 100644 --- a/httemplate/browse/rate_detail.html +++ b/httemplate/browse/rate_detail.html @@ -15,6 +15,7 @@ 'Region', 'Prefix(es)', 'Included<BR>minutes', + 'Connection<BR>charge', 'Charge per<BR>minute', 'Granularity', 'Usage class', @@ -22,12 +23,9 @@ 'fields' => [ 'regionname', sub { shift->dest_region->prefixes_short }, - sub { shift->min_included. - ' <FONT SIZE="-1">(edit)</FONT>'; - }, - sub { $money_char. shift->min_charge. - ' <FONT SIZE="-1">(edit)</FONT>'; - }, + sub { shift->min_included. $edit_hint }, + $conn_charge_sub, + sub { $money_char. shift->min_charge. $edit_hint }, sub { $granularity{ shift->sec_granularity } }, 'classname', ], @@ -39,6 +37,7 @@ <%once> tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities(); +tie my %conn_secs, 'Tie::IxHash', FS::rate_detail::conn_secs(); my $conf = new FS::Conf; my $money_char = $conf->config('money_char') || '$'; @@ -59,6 +58,15 @@ my $edit_onclick = sub { #default# 'color' => '#333399', ); }; +my $edit_hint = ' <FONT SIZE="-1">(edit)</FONT>'; + +my $conn_charge_sub = sub { + my $rate_detail = shift; + #return '' unless $rate_detail->conn_charge > 0 || $rate_detail->conn_sec; + $money_char. $rate_detail->conn_charge. + ($rate_detail->conn_sec ? ' for '.$conn_secs{$rate_detail->conn_sec} : ''). + $edit_hint; +}; </%once> <%init> diff --git a/httemplate/docs/about.html b/httemplate/docs/about.html index 04af73db8..056c17c3e 100644 --- a/httemplate/docs/about.html +++ b/httemplate/docs/about.html @@ -8,7 +8,7 @@ </CENTER> <CENTER> -<FONT SIZE="-1">© 2009 Freeside Internet Services, Inc.<BR> +<FONT SIZE="-1">© 2010 Freeside Internet Services, Inc.<BR> All rights reserved.<BR> Licensed under the terms of the<BR> GNU <b>Affero</b> General Public License.<BR> @@ -29,7 +29,7 @@ GNU <b>Affero</b> General Public License.<BR> <BR> <CENTER> -<FONT SIZE="-3">"I need a miracle every day." -J.P. Barlow</FONT> +<FONT SIZE="-3">"Put your gold money where your love is, baby" -R. Hunter</FONT> </CENTER> <SCRIPT TYPE="text/javascript"> diff --git a/httemplate/docs/credits.html b/httemplate/docs/credits.html index d927722e0..10b9e70a4 100644 --- a/httemplate/docs/credits.html +++ b/httemplate/docs/credits.html @@ -36,12 +36,13 @@ Peter Bowen<BR> Jeremy Davis<BR> Jeff Finucane<BR> Jason Hall<BR> -Kristian Hoffman<BR> Ivan Kohler<BR> Richard Siddall<BR> +Mark Wells<BR> <BR> <H3>Core Emeritus</H3> +Kristian Hoffman<BR> Brian McCane<BR> Matt Simerson<BR> <BR> @@ -90,7 +91,6 @@ Audrey Tang<BR> Jason Thomas<BR> Jesse Vincent<BR> Johan Vromans<BR> -Mark Wells<BR> Peter Wemm<BR> Mark Williamson<BR> Tim Yardley<BR> diff --git a/httemplate/docs/man/FS/part_export/.cvs_is_on_crack b/httemplate/docs/man/FS/part_export/.cvs_is_on_crack deleted file mode 100644 index e69de29bb..000000000 --- a/httemplate/docs/man/FS/part_export/.cvs_is_on_crack +++ /dev/null diff --git a/httemplate/edit/REAL_cust_pkg.cgi b/httemplate/edit/REAL_cust_pkg.cgi index 18d4415c6..29c8ca63f 100755 --- a/httemplate/edit/REAL_cust_pkg.cgi +++ b/httemplate/edit/REAL_cust_pkg.cgi @@ -128,16 +128,19 @@ </FORM> <% include('/elements/footer.html') %> +<%shared> +my $conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; + +my $format = $date_format. ' %T %z (%Z)'; + +</%shared> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Edit customer package dates'); -my $conf = new FS::Conf; -my $date_format = $conf->config('date_format') || '%m/%d/%Y'; - -my $format = $date_format. ' %T %z (%Z)'; my $error = ''; my( $pkgnum, $cust_pkg ); diff --git a/httemplate/edit/access_user.html b/httemplate/edit/access_user.html index 73488ef9a..1f52b4789 100644 --- a/httemplate/edit/access_user.html +++ b/httemplate/edit/access_user.html @@ -7,16 +7,18 @@ { field=>'_password2', type=>'password' }, 'last', 'first', + { field=>'user_custnum', type=>'search-cust_main', }, { field=>'disabled', type=>'checkbox', value=>'Y' }, ], 'labels' => { - 'usernum' => 'User number', - 'username' => 'Username', - '_password' => 'Password', - '_password2'=> 'Re-enter Password', - 'last' => 'Last name', - 'first' => 'First name', - 'disabled' => 'Disable employee', + 'usernum' => 'User number', + 'username' => 'Username', + '_password' => 'Password', + '_password2 '=> 'Re-enter Password', + 'last' => 'Last name', + 'first' => 'First name', + 'user_custnum' => 'Customer (optional)', + 'disabled' => 'Disable employee', }, 'edit_callback' => sub { my( $c, $o ) = @_; $o->set('_password', ''); diff --git a/httemplate/edit/cust_main/bottomfixup.js b/httemplate/edit/cust_main/bottomfixup.js index 5d06f3c04..1a06d9497 100644 --- a/httemplate/edit/cust_main/bottomfixup.js +++ b/httemplate/edit/cust_main/bottomfixup.js @@ -225,7 +225,6 @@ function post_standardization() { } else { - cf.elements['geocode'].value = ''; post_geocode(); } diff --git a/httemplate/edit/cust_main/top_misc.html b/httemplate/edit/cust_main/top_misc.html index 3d6c4862d..d1d436851 100644 --- a/httemplate/edit/cust_main/top_misc.html +++ b/httemplate/edit/cust_main/top_misc.html @@ -78,7 +78,7 @@ 'name' => 'signupdate', 'value' => $cust_main->signupdate, 'label' => 'Signup date', - 'format' => $conf->config('date_format') || "%m/%d/%Y", + 'format' => ( $conf->config('date_format') || "%m/%d/%Y" ), }) %> % } diff --git a/httemplate/edit/cust_main_note.cgi b/httemplate/edit/cust_main_note.cgi index 6c6a1a9a0..e2501cb54 100755 --- a/httemplate/edit/cust_main_note.cgi +++ b/httemplate/edit/cust_main_note.cgi @@ -6,11 +6,11 @@ <INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> <INPUT TYPE="hidden" NAME="notenum" VALUE="<% $notenum %>"> - -<BR><BR> -<TEXTAREA NAME="comment" ROWS="12" COLS="60"> -<% $comment %> -</TEXTAREA> +<% include('/elements/htmlarea.html', 'field' => 'comment', + 'curr_value' => $comment) %> +% #<TEXTAREA NAME="comment" ROWS="12" COLS="60"> +% # <% $comment %> +% #</TEXTAREA> <BR><BR> <INPUT TYPE="submit" VALUE="<% $notenum ? "Apply Changes" : "Add Note" %>"> @@ -33,6 +33,8 @@ if ( $cgi->param('error') ) { $comment = $note->comments; } +$comment =~ s/\r//g; # remove weird line breaks to protect FCKeditor + $cgi->param('custnum') =~ /^(\d+)$/ or die "illeagl custnum"; my $custnum = $1; diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index 8c88852ae..1a1023cbd 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -40,7 +40,7 @@ Example: 'disabled' => 0, 'onchange' => 'javascript_function', - 'include_opt_callback' => sub { #my $ = @_; + 'include_opt_callback' => sub { my $object = @_; ( 'option' => 'value', ); }, @@ -296,11 +296,15 @@ Example: % % if ( $type eq 'tablebreak-tr-title' ) { % $include_common{'table_id'} = 'TableNumber'. $tablenum++; +% } +% if ( $type eq 'tablebreak-tr-title' || $type eq 'title' ) { % $include_common{'colspan'} = $f->{colspan} if $f->{colspan}; % } % % if ( $f->{include_opt_callback} ) { -% %include_common = ( %include_common, &{ $f->{include_opt_callback} } ); +% %include_common = ( %include_common, +% &{ $f->{include_opt_callback} }( $object ) +% ); % } % % my $layer_prefix_on = ''; diff --git a/httemplate/edit/elements/svc_Common.html b/httemplate/edit/elements/svc_Common.html index 2e98a1b25..36950b2c9 100644 --- a/httemplate/edit/elements/svc_Common.html +++ b/httemplate/edit/elements/svc_Common.html @@ -34,12 +34,14 @@ 'new_hashref_callback' => sub { #my( $cgi, $svc_x ) = @_; - { svcpart => $svcpart }; + { pkgnum => $pkgnum, + svcpart => $svcpart, + }; }, 'new_callback' => sub { - my( $cgi, $svc_x, $fields, $opt ) = @_;; + my( $cgi, $svc_x, $fields, $opt ) = @_; $part_svc = qsearchs( 'part_svc', { svcpart=>$svcpart }); die "No part_svc entry!" unless $part_svc; @@ -48,6 +50,13 @@ #$svcnum=''; + if ( my $cb = $opt{'svc_new_callback'} ) { + my $cust_pkg = $pkgnum + ? qsearchs('cust_pkg', {pkgnum=>$pkgnum}) + : ''; #? + &{ $cb }( $cgi,$svc_x, $part_svc,$cust_pkg, $fields,$opt); + } + $svc_x->set_default_and_fixed; }, @@ -92,6 +101,11 @@ }; } + if ( $f->{'field'} eq 'custnum' && $pkgnum ) { + my $cust_pkg = qsearchs('cust_pkg', {'pkgnum' => $pkgnum}); + $object->set('custnum', $cust_pkg->custnum); + } + }, 'html_init' => sub { @@ -141,11 +155,13 @@ sub label_fixup { my( $part_svc, $opt ) = @_; + $opt->{'name'} ||= $part_svc->svc; + my $svcdb = $part_svc->svcdb; require "FS/$svcdb.pm"; if ( UNIVERSAL::can("FS::$svcdb", 'table_info') ) { - $opt->{'name'} ||= "FS::$svcdb"->table_info->{'name'}; + #$opt->{'name'} ||= "FS::$svcdb"->table_info->{'name'}; my $fields = "FS::$svcdb"->table_info->{'fields'}; $opt->{'fields'} ||= [ grep { $_ ne 'svcnum' } keys %$fields ]; @@ -165,7 +181,7 @@ sub label_fixup { my $labels = $opt->{labels}; # with -> here foreach my $field ( keys %{ $opt->{labels} } ) { my $col = $part_svc->part_svc_column($field); - $labels->{$field} = $col->columnlabel if $col->columnlabel !~ /^\S*$/; + $labels->{$field} = $col->columnlabel if $col->columnlabel !~ /^\s*$/; } } diff --git a/httemplate/edit/mailinglistmember.html b/httemplate/edit/mailinglistmember.html new file mode 100644 index 000000000..2391cb697 --- /dev/null +++ b/httemplate/edit/mailinglistmember.html @@ -0,0 +1,25 @@ +<% include( 'elements/edit.html', + 'name_singular' => 'member', + 'table' => 'mailinglistmember', + 'popup' => 1, + 'fields' => [ + { field=>'listnum', type=>'hidden', }, + { field=>'svcnum', type=>'hidden', }, #not yet + { field=>'contactemailnum', type=>'hidden', }, #not yet + { field=>'email', type=>'text', }, + ], + 'labels' => { 'membernum' => 'Member', + 'email' => 'Email address', + }, + 'new_callback' => $new_callback, + ) +%> +<%init> + +my $new_callback = sub { + #my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; + my( $cgi, $object ) = @_; + $object->listnum( $cgi->param('listnum') ); +}; + +</%init> diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index a02545f84..f9818c4f9 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -162,15 +162,17 @@ { type => 'columnend' }, - { 'type' => $census ? 'tablebreak-tr-title' - : 'hidden', + { 'type' => $report_option ? 'tablebreak-tr-title' + : 'hidden', 'value' => 'Optional report classes', 'field' => 'census_title', }, { 'field' => 'report_option', - 'type' => $census ? 'select-table' : 'hidden', + 'type' => $report_option ? 'select-table' + : 'hidden', 'table' => 'part_pkg_report_option', 'name_col' => 'name', + 'hashref' => { 'disabled' => '' }, 'multiple' => 1, }, @@ -256,7 +258,7 @@ my $sth = dbh->prepare("SELECT COUNT(*) FROM part_pkg_report_option". " WHERE disabled IS NULL OR disabled = '' ") or die dbh->errstr; $sth->execute or die $sth->errstr; -my $census = $sth->fetchrow_arrayref->[0]; +my $report_option = $sth->fetchrow_arrayref->[0]; #XXX # - tr-part_pkg_freq: month_increments_only (from price plans) @@ -409,7 +411,6 @@ my $m2_error_callback_maker = sub { my $link_type = shift; #yay closures return sub { my( $cgi, $object ) = @_; - my $num; map { if ( /^${link_type}_dst_pkgpart(\d+)$/ && diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index 51925c0c5..98ed9fec1 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -15,7 +15,8 @@ Disable new orders <INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<% $hashref-> Service definitions are the templates for items you offer to your customers. <UL><LI>svc_acct - Accounts - anything with a username (Mailboxes, PPP accounts, shell accounts, RADIUS entries for broadband, etc.) <LI>svc_domain - Domains - <LI>svc_forward - mail forwarding + <LI>svc_forward - Mail forwarding + <LI>svc_mailinglist - Mailing list <LI>svc_www - Virtual domain website <LI>svc_broadband - Broadband/High-speed Internet service (always-on) <LI>svc_phone - Customer phone numbers diff --git a/httemplate/edit/process/REAL_cust_pkg.cgi b/httemplate/edit/process/REAL_cust_pkg.cgi index 22aab44e8..b5796ebf5 100755 --- a/httemplate/edit/process/REAL_cust_pkg.cgi +++ b/httemplate/edit/process/REAL_cust_pkg.cgi @@ -39,14 +39,15 @@ push @errors, '_setup_areyousure' && ! $cgi->param('setup_areyousure'); # and it wasn't confirmed push @errors, '_start' - if $hash{'start_date'} && $old->start_date # if a start date was added - && $hash{'setup'}; # but there's a setup date + if $hash{'start_date'} && !$old->start_date # if a start date was added + && $hash{'setup'}; # but there's a setup date my $new; my $error; if ( @errors ) { $error = join(',', @errors); } else { + warn join(',',%hash); $new = new FS::cust_pkg \%hash; $error = $new->replace($old); } diff --git a/httemplate/edit/process/mailinglistmember.html b/httemplate/edit/process/mailinglistmember.html new file mode 100644 index 000000000..f1842b8ef --- /dev/null +++ b/httemplate/edit/process/mailinglistmember.html @@ -0,0 +1,6 @@ +<% include( 'elements/process.html', + 'table' => 'mailinglistmember', + 'popup_reload' => 'Member added', + ) +%> +%#XXX ACL diff --git a/httemplate/edit/process/part_device.html b/httemplate/edit/process/part_device.html index 399991fc8..2b7e1da49 100644 --- a/httemplate/edit/process/part_device.html +++ b/httemplate/edit/process/part_device.html @@ -1,10 +1,6 @@ <% include( 'elements/process.html', 'table' => 'part_device', 'viewall_dir' => 'browse', - 'process_m2m' => { - 'link_table' => 'export_device', - 'target_table' => 'part_export', - }, ) %> <%init> diff --git a/httemplate/edit/process/rate_region.cgi b/httemplate/edit/process/rate_region.cgi index 882991e9d..8036f7388 100755 --- a/httemplate/edit/process/rate_region.cgi +++ b/httemplate/edit/process/rate_region.cgi @@ -39,7 +39,7 @@ my @dest_detail = map { new FS::rate_detail { 'ratenum' => $ratenum, map { $_ => $cgi->param("$_$ratenum") } - qw( min_included min_charge sec_granularity classnum ) + qw( min_included conn_charge conn_sec min_charge sec_granularity classnum ) }; } qsearch('rate', {} ); diff --git a/httemplate/edit/process/svc_mailinglist.html b/httemplate/edit/process/svc_mailinglist.html new file mode 100644 index 000000000..580f6ccbd --- /dev/null +++ b/httemplate/edit/process/svc_mailinglist.html @@ -0,0 +1,11 @@ +<% include( 'elements/svc_Common.html', + 'table' => 'svc_mailinglist', + 'fields' => [ fields('svc_mailinglist'), 'listname' ], + ) +%> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? + +</%init> diff --git a/httemplate/edit/process/svc_phone.html b/httemplate/edit/process/svc_phone.html index 27a703cdf..e02ec5ccc 100644 --- a/httemplate/edit/process/svc_phone.html +++ b/httemplate/edit/process/svc_phone.html @@ -1,5 +1,6 @@ <% include( 'elements/svc_Common.html', 'table' => 'svc_phone', + 'args_callback' => $args_callback, ) %> <%init> @@ -7,4 +8,22 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? +my $args_callback = sub { + my( $cgi, $object ) = @_; + + my %opt = (); + if ( $cgi->param('locationnum') == -1 ) { + my $cust_location = new FS::cust_location { + map { $_ => scalar($cgi->param($_)) } + qw( custnum address1 address2 city county state zip country ) + }; + $opt{'cust_location'} = $cust_location; + } + + %opt; + +}; + + + </%init> diff --git a/httemplate/edit/rate_detail.html b/httemplate/edit/rate_detail.html index dd8c3f6b3..869ace8d4 100644 --- a/httemplate/edit/rate_detail.html +++ b/httemplate/edit/rate_detail.html @@ -6,6 +6,8 @@ 'dest_regionname' => 'Region', 'dest_prefixes_short' => 'Prefix(es)', 'min_included' => 'Included minutes/calls', + 'conn_charge' => 'Connection charge', + 'conn_sec' => 'For', 'min_charge' => 'Charge per minute/call', 'sec_granularity' => 'Granularity', 'classnum' => 'Usage class', @@ -17,6 +19,13 @@ { field=>'dest_regionname', type=>'fixed', }, { field=>'dest_prefixes_short', type=>'fixed', }, { field=>'min_included', type=>'text', size=>5 }, + { field=>'conn_charge', type=>'money', size=>4 }, + { field =>'conn_sec', + type =>'select', + options => [ keys %conn_secs ], + labels => \%conn_secs, + disable_empty => 1, + }, { field=>'min_charge', type=>'money', size=>4 }, { field =>'sec_granularity', type =>'select', @@ -38,9 +47,9 @@ <%once> tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities(); +tie my %conn_secs, 'Tie::IxHash', FS::rate_detail::conn_secs(); </%once> - <%init> my $conf = new FS::Conf; diff --git a/httemplate/edit/rate_region.cgi b/httemplate/edit/rate_region.cgi index 9ca3a3569..f77c0dbe7 100644 --- a/httemplate/edit/rate_region.cgi +++ b/httemplate/edit/rate_region.cgi @@ -52,6 +52,12 @@ <FONT SIZE=-1>Included<BR>minutes/calls</FONT> </TH> <TH CLASS="grid" BGCOLOR="#cccccc"> + <FONT SIZE=-1>Connection<BR>charge</FONT> + </TH> + <TH CLASS="grid" BGCOLOR="#cccccc"> + <FONT SIZE=-1>Connection<BR>charge for</FONT> + </TH> + <TH CLASS="grid" BGCOLOR="#cccccc"> <FONT SIZE=-1>Charge per<BR>minute/call</FONT> </TH> <TH CLASS="grid" BGCOLOR="#cccccc"> @@ -88,7 +94,20 @@ </TD> <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> - $<INPUT TYPE="text" SIZE=6 NAME="min_charge<%$n%>" VALUE="<% $cgi->param("min_charge$n") || $rate_detail->min_charge |h %>"> + <%$money_char%><INPUT TYPE="text" SIZE=9 NAME="conn_charge<%$n%>" VALUE="<% $cgi->param("conn_charge$n") || $rate_detail->conn_charge |h %>"> + </TD> + + <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> + <SELECT NAME="conn_sec<%$n%>"> +% foreach my $conn_sec ( keys %conn_secs ) { +% my $curr_value = $cgi->param("conn_sec$n") || $rate_detail->conn_sec; +% my $selected = ($conn_sec==$curr_value) ? ' SELECTED' : ''; + <OPTION VALUE="<% $conn_sec %>" <%$selected%>><% $conn_secs{$conn_sec} %></OPTION> +% } + </TD> + + <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> + <%$money_char%><INPUT TYPE="text" SIZE=6 NAME="min_charge<%$n%>" VALUE="<% $cgi->param("min_charge$n") || $rate_detail->min_charge |h %>"> </TD> <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> @@ -125,12 +144,19 @@ </FORM> <% include('/elements/footer.html') %> +<%once> + +tie my %conn_secs, 'Tie::IxHash', FS::rate_detail::conn_secs(); +</%once> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); +my $conf = new FS::Conf; +my $money_char = $conf->config('money_char') || '$'; + my $rate_region; if ( $cgi->param('error') ) { $rate_region = new FS::rate_region ( { diff --git a/httemplate/edit/svc_broadband.cgi b/httemplate/edit/svc_broadband.cgi index 8a108f891..b11fec7a7 100644 --- a/httemplate/edit/svc_broadband.cgi +++ b/httemplate/edit/svc_broadband.cgi @@ -63,12 +63,12 @@ my $callback = sub { if $fieldref->{field} eq 'blocknum'; $fieldref->{value} = $object->addr_block->label - if $fieldref->{field} eq 'block_label'; + if $fieldref->{field} eq 'block_label' && $object->addr_block; } else { if ($fieldref->{field} eq 'block_label') { - if ($fixedblock) { + if ($fixedblock && $object->addr_block) { $object->blocknum($fixedblock); $fieldref->{value} = $object->addr_block->label; }else{ @@ -93,7 +93,8 @@ my $callback = sub { && $FS::CurrentUser::CurrentUser->agentnum($_->agentnum) } map { $_->addr_block } $object->allowed_routers; - my @options = map { $_->blocknum } @addr_block; + my @options = map { $_->blocknum } + sort { $a->label cmp $b->label } @addr_block; my %option_labels = map { ( $_->blocknum => $_->label ) } @addr_block; $fieldref->{type} = 'select'; $fieldref->{options} = \@options; diff --git a/httemplate/edit/svc_mailinglist.cgi b/httemplate/edit/svc_mailinglist.cgi new file mode 100644 index 000000000..c7c739daa --- /dev/null +++ b/httemplate/edit/svc_mailinglist.cgi @@ -0,0 +1,25 @@ +<% include( 'elements/svc_Common.html', + 'table' => 'svc_mailinglist', + 'fields' => \@fields, + ) +%> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? + +my @fields = ( + 'username', + { field=>'domsvc', type=>'select-svc-domain', + #label => 'List address domain', + }, + { field=>'listnum', type=>'hidden', }, + { field=>'listname', type=>'text', }, + { field=>'reply_to', type=>'checkbox', value=>'Y' }, + { field=>'remove_from', type=>'checkbox', value=>'Y' }, + { field=>'reject_auto', type=>'checkbox', value=>'Y' }, + { field=>'remove_to_and_cc', type=>'checkbox', value=>'Y' }, + +); + +</%init> diff --git a/httemplate/edit/svc_phone.cgi b/httemplate/edit/svc_phone.cgi index 3c7b75249..b77d96233 100644 --- a/httemplate/edit/svc_phone.cgi +++ b/httemplate/edit/svc_phone.cgi @@ -1,8 +1,8 @@ <% include( 'elements/svc_Common.html', - 'name' => 'Phone number', 'table' => 'svc_phone', 'fields' => \@fields, 'labels' => { + 'svcnum' => 'Service', 'countrycode' => 'Country code', 'phonenum' => 'Phone number', 'domsvc' => 'Domain', @@ -10,7 +10,12 @@ 'pin' => 'Voicemail PIN', 'phone_name' => 'Name', 'pbxsvc' => 'PBX', + 'locationnum' => 'E911 location', }, + 'svc_new_callback' => sub { + my( $cgi, $svc_x, $part_svc, $cust_pkg, $fields, $opt ) = @_; + $svc_x->locationnum($cust_pkg->locationnum) if $cust_pkg; + }, ) %> <%init> @@ -39,7 +44,34 @@ push @fields, { field => 'pbxsvc', }, 'sip_password', 'pin', - 'phone_name', + { field => 'phone_name', + type => 'text', + maxlength => $conf->config('svc_phone-phone_name-max_length'), + }, + + { value => 'E911 Information', + type => 'tablebreak-tr-title', + colspan => 7, + }, + { field => 'locationnum', + type => 'select-cust_location', + label => 'E911 location', + include_opt_callback => sub { + my $svc_phone = shift; + my $pkgnum = $svc_phone->get('pkgnum') + || $cgi->param('pkgnum') + || $svc_phone->cust_svc->pkgnum; #hua? + #cross agent location exposure? sheesh + my $cust_pkg = qsearchs('cust_pkg', {'pkgnum' => $pkgnum}); + my $cust_main = $cust_pkg ? $cust_pkg->cust_main : ''; + ( 'no_bold' => 1, + 'cust_pkg' => $cust_pkg, + 'cust_main' => $cust_main, + ); + }, + }, + { field => 'custnum', type=> 'hidden' }, #for new cust_locations ; + </%init> diff --git a/httemplate/elements/checkboxes-table.html b/httemplate/elements/checkboxes-table.html index a31bdb919..b6b04d111 100644 --- a/httemplate/elements/checkboxes-table.html +++ b/httemplate/elements/checkboxes-table.html @@ -46,7 +46,7 @@ % % my $hashref = $opt{'hashref'} || {}; % -% my $extra_sql = $opt{'extra_sql'} || ''; +% my $extra_sql = ''; % % if ( $opt{'agent_virt'} ) { % $extra_sql .= ' AND' . $FS::CurrentUser::CurrentUser->agentnums_sql( diff --git a/httemplate/elements/header.html b/httemplate/elements/header.html index 22e872eca..8da91ef49 100644 --- a/httemplate/elements/header.html +++ b/httemplate/elements/header.html @@ -24,7 +24,7 @@ Example: <HTML> <HEAD> <TITLE> - <% $title %> + <% $title |h %> </TITLE> <META HTTP-Equiv="Cache-Control" Content="no-cache"> <META HTTP-Equiv="Pragma" Content="no-cache"> @@ -293,7 +293,7 @@ input.fstext { <TD BGCOLOR="#e8e8e8" HEIGHT="100%" VALIGN="top"> <!-- WIDTH="100%"> --> <FONT SIZE=6> - <% $title %> + <% $title |h %> </FONT> % unless ( $nobr ) { diff --git a/httemplate/elements/location.html b/httemplate/elements/location.html index 07aaa69f0..0ec6c04e0 100644 --- a/httemplate/elements/location.html +++ b/httemplate/elements/location.html @@ -18,7 +18,7 @@ Example: </%doc> <TR> - <TH ALIGN="right"><%$r%><% $opt{'address1_label'} || 'Address' %></TH> + <<%$th%> ALIGN="right"><%$r%><% $opt{'address1_label'} || 'Address' %></<%$th%>> <TD COLSPAN=7> <INPUT TYPE = "text" NAME = "<%$pre%>address1" @@ -48,7 +48,7 @@ Example: </TR> <TR> - <TH ALIGN="right"><%$r%>City</TH> + <<%$th%> ALIGN="right"><%$r%>City</<%$th%>> <TD WIDTH="1"> <INPUT TYPE = "text" NAME = "<%$pre%>city" @@ -59,13 +59,13 @@ Example: <% $style %> > </TD> - <TH ALIGN="right" ID="<%$pre%>countylabel" <%$county_style%>><%$r%>County</TH> + <<%$th%> ALIGN="right" ID="<%$pre%>countylabel" <%$county_style%>><%$r%>County</<%$th%>> <TD><% include('/elements/select-county.html', %select_hash ) %></TD> - <TH ALIGN="right" WIDTH="1"><%$r%>State</TH> + <<%$th%> ALIGN="right" WIDTH="1"><%$r%>State</<%$th%>> <TD WIDTH="1"> <% include('/elements/select-state.html', %select_hash ) %> </TD> - <TH><%$r%>Zip</TH> + <<%$th%>><%$r%>Zip</<%$th%>> <TD> <INPUT TYPE = "text" NAME = "<%$pre%>zip" @@ -80,7 +80,7 @@ Example: </TR> <TR> - <TH ALIGN="right"><%$r%>Country</TH> + <<%$th%> ALIGN="right"><%$r%>Country</<%$th%>> <TD COLSPAN=6><% include('/elements/select-country.html', %select_hash ) %></TD> </TR> @@ -88,7 +88,7 @@ Example: <INPUT TYPE="hidden" NAME="geocode" VALUE="<% $opt{geocode} %>"> % } else { % if ( $pre eq 'ship_' && $conf->exists('cust_main-require_censustract') ) { - <TR><TH ALIGN="right">Census tract<BR>(automatic)</TH> + <TR><<%$th%> ALIGN="right">Census tract<BR>(automatic)</<%$th%>> <TD> <INPUT TYPE="text" NAME="censustract" VALUE="<% $opt{censustract} %>"> </TD> @@ -123,7 +123,7 @@ $object->set($pre.'state', $statedefault ) || $object->get($pre.'country') ne $countrydefault; my @style = (); -push @style, 'background-color: #dddddd"' if $disabled; +push @style, 'background-color: #dddddd' if $disabled; my @address2_label_style = (); push @address2_label_style, 'visibility:hidden' @@ -161,4 +161,6 @@ my %select_hash = ( 'style' => \@style, ); +my $th = $opt{'no_bold'} ? 'TD' : 'TH'; + </%init> diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index d4a915e15..a68a5754d 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -235,6 +235,7 @@ if($curuser->access_right('Financial reports')) { 'Sales, Credits and Receipts' => [ $fsurl.'graph/report_money_time.html', 'Sales, credits and receipts summary graph' ], 'Sales Report' => [ $fsurl.'graph/report_cust_bill_pkg.html', 'Sales report and graph (by agent, package class and/or date range)' ], 'Rated Call Sales Report' => [ $fsurl.'graph/report_cust_bill_pkg_detail.html', 'Sales report and graph (by agent, package class, usage class and/or date range)' ], + 'Employee Commission Report' => [ $fsurl.'search/report_employee_commission.html', '' ], 'Credit Report' => [ $fsurl.'search/report_cust_credit.html', 'Credit report (by employee and/or date range)' ], 'Refund Report' => [ $fsurl.'search/report_cust_refund.html', 'Refund report (by type and/or date range)' ], ); @@ -320,7 +321,7 @@ $tools_menu{'Job Queue'} = [ $fsurl.'search/queue.html', 'View pending job queu if $curuser->access_right('Job queue'); $tools_menu{'Ticketing'} = [ \%tools_ticketing, 'Ticketing tools' ] if $conf->config('ticket_system'); -$tools_menu{'Time Queue'} = [ $fsurl.'search/timeworked.html', 'View pending support time' ] +$tools_menu{'Time Queue'} = [ $fsurl.'search/report_timeworked.html', 'View pending support time' ] if $curuser->access_right('Time queue'); $tools_menu{'Attachments'} = [ $fsurl.'browse/cust_attachment.html', 'View customer attachments' ] if !$conf->config('disable_cust_attachment') and $curuser->access_right('View attachments') and $curuser->access_right('Browse attachments'); diff --git a/httemplate/elements/search-cust_main.html b/httemplate/elements/search-cust_main.html index ef0d22ced..23c4369e8 100644 --- a/httemplate/elements/search-cust_main.html +++ b/httemplate/elements/search-cust_main.html @@ -3,36 +3,37 @@ Example: include( '/elements/search-cust_main.html, - 'field_name' => 'custnum', + 'field' => 'custnum', + #slightly deprecated old synonym for field#'field_name'=>'custnum', 'find_button' => 1, #add a "find" button to the field 'curr_value' => 54, #current value 'value => 32, #deprecated synonym for curr_value ); </%doc> -<INPUT TYPE="hidden" NAME="<% $opt{'field_name'} %>" VALUE="<% $value %>"> +<INPUT TYPE="hidden" NAME="<% $field %>" VALUE="<% $value %>"> <!-- some false laziness w/ misc/batch-cust_pay.html, though not as bad as i'd thought at first... --> <INPUT TYPE = "text" - NAME = "<% $opt{'field_name'} %>_search" - ID = "<% $opt{'field_name'} %>_search" + NAME = "<% $field %>_search" + ID = "<% $field %>_search" SIZE = "32" VALUE="<% $cust_main ? $cust_main->name : '(cust #, name or company)' %>" - onFocus="clearhint_<% $opt{'field_name'} %>_search(this);" - onClick="clearhint_<% $opt{'field_name'} %>_search(this);" - onChange="smart_<% $opt{'field_name'} %>_search(this);" + onFocus="clearhint_<% $field %>_search(this);" + onClick="clearhint_<% $field %>_search(this);" + onChange="smart_<% $field %>_search(this);" > % if ( $opt{'find_button'} ) { <INPUT TYPE = "button" VALUE = 'Find', - NAME = "<% $opt{'field_name'} %>_findbutton" - onClick = "smart_<% $opt{'field_name'} %>_search(this.form.<% $opt{'field_name'} %>_search);" + NAME = "<% $field %>_findbutton" + onClick = "smart_<% $field %>_search(this.form.<% $field %>_search);" > % } -<SELECT NAME="<% $opt{'field_name'} %>_select" ID="<% $opt{'field_name'} %>_select" STYLE="color:#ff0000; display:none" onChange="select_<% $opt{'field_name'} %>(this);"> +<SELECT NAME="<% $field %>_select" ID="<% $field %>_select" STYLE="color:#ff0000; display:none" onChange="select_<% $field %>(this);"> </SELECT> <% include('/elements/xmlhttp.html', @@ -43,7 +44,7 @@ Example: <SCRIPT TYPE="text/javascript"> - function clearhint_<% $opt{'field_name'} %>_search (what) { + function clearhint_<% $field %>_search (what) { what.style.color = '#000000'; @@ -55,7 +56,7 @@ Example: } - function smart_<% $opt{'field_name'} %>_search(what) { + function smart_<% $field %>_search(what) { var customer = what.value; @@ -73,11 +74,11 @@ Example: what.style.color= '#000000'; what.style.backgroundColor = '#dddddd'; - var customer_select = document.getElementById('<% $opt{'field_name'} %>_select'); + var customer_select = document.getElementById('<% $field %>_select'); //alert("search for customer " + customer); - function <% $opt{'field_name'} %>_search_update(customers) { + function <% $field %>_search_update(customers) { //alert('customers returned: ' + customers); @@ -88,7 +89,7 @@ Example: if ( customerArray.length == 0 ) { - what.form.<% $opt{'field_name'} %>.value = ''; + what.form.<% $field %>.value = ''; what.value = 'Customer not found: ' + what.value; what.style.color = '#ff0000'; @@ -100,7 +101,7 @@ Example: //alert('one customer found: ' + customerArray[0]); - what.form.<% $opt{'field_name'} %>.value = customerArray[0][0]; + what.form.<% $field %>.value = customerArray[0][0]; what.value = customerArray[0][1]; what.style.display = ''; @@ -129,17 +130,17 @@ Example: } - smart_search( customer, <% $opt{'field_name'} %>_search_update ); + smart_search( customer, <% $field %>_search_update ); } - function select_<% $opt{'field_name'} %> (what) { + function select_<% $field %> (what) { var custnum = what.options[what.selectedIndex].value; var customer = what.options[what.selectedIndex].text; - var customer_obj = document.getElementById('<% $opt{'field_name'} %>_search'); + var customer_obj = document.getElementById('<% $field %>_search'); if ( custnum == '' ) { //what.style.color = '#ff0000'; @@ -154,7 +155,7 @@ Example: } else { - what.form.<% $opt{'field_name'} %>.value = custnum; + what.form.<% $field %>.value = custnum; customer_obj.value = customer; customer_obj.style.color = '#000000'; @@ -177,7 +178,8 @@ Example: <%init> my( %opt ) = @_; -$opt{'field_name'} ||= 'custnum'; + +my $field = $opt{'field'} || $opt{'field_name'} || 'custnum'; my $value = $opt{'curr_value'} || $opt{'value'}; diff --git a/httemplate/elements/select-areacode.html b/httemplate/elements/select-areacode.html index aa2d73b65..453205c02 100644 --- a/httemplate/elements/select-areacode.html +++ b/httemplate/elements/select-areacode.html @@ -12,7 +12,7 @@ what.options[length] = optionName; } - function <% $opt{'prefix'} %>state_changed(what, callback) { + function <% $opt{'state_prefix'} %>state_changed(what, callback) { what.form.<% $opt{'prefix'} %>areacode.disabled = 'disabled'; what.form.<% $opt{'prefix'} %>areacode.style.display = 'none'; @@ -24,7 +24,7 @@ what.form.<% $opt{'prefix'} %>exchange.disabled = 'disabled'; what.form.<% $opt{'prefix'} %>phonenum.disabled = 'disabled'; - state = what.options[what.selectedIndex].value; + var state = what.options[what.selectedIndex].value; function <% $opt{'prefix'} %>update_areacodes(areacodes) { @@ -86,6 +86,7 @@ my %opt = @_; -$opt{disabled} = 'disabled' unless exists $opt{disabled}; +$opt{disabled} = 'disabled' unless exists $opt{disabled}; +$opt{state_prefix} = $opt{prefix} unless exists $opt{state_prefix}; </%init> diff --git a/httemplate/elements/select-did.html b/httemplate/elements/select-did.html index af8d59513..b62d6a089 100644 --- a/httemplate/elements/select-did.html +++ b/httemplate/elements/select-did.html @@ -3,7 +3,7 @@ Example: include('/elements/select-did.html', - 'field' => 'phonenum', + #can't actuall change from phonenum yet# 'field' => 'phonenum', 'svcpart' => 5, #OR @@ -18,6 +18,7 @@ Example: <TR> <TD> <% include('/elements/select-state.html', + 'prefix' => 'phonenum_', #$field.'_', 'country' => $country, 'disable_empty' => 0, 'empty_label' => 'Select state', @@ -26,8 +27,9 @@ Example: </TD> <TD> <% include('/elements/select-areacode.html', - 'svcpart' => $svcpart, - 'empty' => 'Select area code', + 'state_prefix' => 'phonenum_', #$field.'_', + 'svcpart' => $svcpart, + 'empty' => 'Select area code', ) %> </TD> @@ -84,4 +86,6 @@ if ( scalar(@exports) > 1 ) { my $use_selector = scalar(@exports) ? 1 : 0; +#my $field = $opt{'field'} || 'phonenum'; + </%init> diff --git a/httemplate/elements/tr-search-cust_main.html b/httemplate/elements/tr-search-cust_main.html new file mode 100644 index 000000000..9df91a18f --- /dev/null +++ b/httemplate/elements/tr-search-cust_main.html @@ -0,0 +1,15 @@ +<% include('tr-td-label.html', @_ ) %> + + <TD <% $colspan %> <% $cell_style %> ID="<% $opt{input_id} || $opt{id}.'_input0' %>"><% include('search-cust_main.html', @_ ) %></TD> + +</TR> + +<%init> + +my %opt = @_; + +my $cell_style = $opt{'cell_style'} ? 'STYLE="'. $opt{'cell_style'}. '"' : ''; + +my $colspan = $opt{'colspan'} ? 'COLSPAN="'.$opt{'colspan'}.'"' : ''; + +</%init> diff --git a/httemplate/elements/tr-select-cust_location.html b/httemplate/elements/tr-select-cust_location.html index da16dfe1c..bc3915441 100644 --- a/httemplate/elements/tr-select-cust_location.html +++ b/httemplate/elements/tr-select-cust_location.html @@ -118,7 +118,7 @@ Example: </SCRIPT> <TR> - <TH ALIGN="right">Service location</TH> + <<%$th%> ALIGN="right"><% $opt{'label'} || 'Service location' %></<%$th%>> <TD COLSPAN=7> <SELECT NAME="locationnum" onChange="locationnum_changed(this);"> <OPTION VALUE="">(default service address) @@ -139,6 +139,7 @@ Example: #'onchange' ? probably not 'disabled' => ( $locationnum == -1 ? '' : 'DISABLED' ), 'no_asterisks' => 1, + 'no_bold' => $opt{'no_bold'}, ) %> @@ -156,6 +157,7 @@ my $statedefault = $conf->config('statedefault') my %opt = @_; my $cgi = $opt{'cgi'}; +my $cust_pkg = $opt{'cust_pkg'}; my $cust_main = $opt{'cust_main'}; my $prefix = length($cust_main->ship_last) ? 'ship_' : ''; @@ -170,9 +172,15 @@ if ( $locationnum && $locationnum != -1 ) { $cust_location = new FS::cust_location; if ( $locationnum == -1 ) { $cust_location->$_( $cgi->param($_) ) foreach @location_fields; + } elsif ( $cust_pkg && $cust_pkg->locationnum ) { + my $pkg_location = $cust_pkg->cust_location; + $cust_location->$_( $pkg_location->$_ ) foreach @location_fields; + $opt{'empty_label'} ||= 'package address: '.$pkg_location->line; } else { $cust_location->$_( $cust_main->get($prefix.$_) ) foreach @location_fields; } } +my $th = $opt{'no_bold'} ? 'TD' : 'TH'; + </%init> diff --git a/httemplate/misc/delay_susp_pkg.html b/httemplate/misc/delay_susp_pkg.html index 5d6a2bd09..8adc40d55 100755 --- a/httemplate/misc/delay_susp_pkg.html +++ b/httemplate/misc/delay_susp_pkg.html @@ -42,7 +42,7 @@ <%init> -my %conf = new FS::Conf; +my $conf = new FS::Conf; my $date_format = $conf->config('date_format') || '%m/%d/%Y'; my $date = time2str($date_format, time); diff --git a/httemplate/misc/delete-mailinglistmember.html b/httemplate/misc/delete-mailinglistmember.html new file mode 100644 index 000000000..6b91de807 --- /dev/null +++ b/httemplate/misc/delete-mailinglistmember.html @@ -0,0 +1,20 @@ +% if ( $error ) { +% errorpage($error); +% } else { +<% $cgi->redirect($p."search/mailinglistmember.html?listnum=$listnum") %> +% } +<%init> + +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal devicenum"; +my $membernum = $1; + +my $mailinglistmember = + qsearchs('mailinglistmember', { 'membernum' => $membernum } ) + or die "unknown membernum $membernum"; + +my $listnum = $mailinglistmember->listnum; + +my $error = $mailinglistmember->delete; + +</%init> diff --git a/httemplate/misc/phone_device_config.html b/httemplate/misc/phone_device_config.html deleted file mode 100644 index 9ea0d0d1c..000000000 --- a/httemplate/misc/phone_device_config.html +++ /dev/null @@ -1,57 +0,0 @@ -%if ($config) { -<% $config %> -%}else{ -<% include("/elements/errorpage.html", "No configuration data produced.") %> -%} -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('View customer services'); - -my $exportnum; -if ( $cgi->param('exportnum') ) { - $cgi->param('exportnum') =~ /^(\d+)$/ or die "unparsable exportnum"; - $exportnum = $1; -} - -die "no export provided" - unless $exportnum; - -my $svcnum; -if ( $cgi->param('svcnum') ) { - $cgi->param('svcnum') =~ /^(\d+)$/ or die "unparsable svcnum"; - $svcnum = $1; -} - -my $devicenum; -if ( $cgi->param('devicenum') ) { - $cgi->param('devicenum') =~ /^(\d+)$/ or die "unparsable devicenum"; - $devicenum = $1; -} - -die "no device or service provided" - unless $svcnum || $devicenum; - -my $part_export = qsearchs('part_export', { 'exportnum' => $exportnum }) - or die "Unknown exportnum $exportnum\n"; - -my $phone_device; -my $svc_phone; -if ($devicenum) { - $phone_device = qsearchs('phone_device', { 'devicenum' => $devicenum }) - or die "Unknown device $devicenum\n"; - $svc_phone = $phone_device->svc_phone; -} else { - $svc_phone = qsearchs('svc_phone', { 'svcnum' => $svcnum }) - or die "Unknown svc_phone $svcnum\n"; -} - -my $config = $part_export->export_device_config($svc_phone, $phone_device); - -if ($config) { - http_header('Content-Type' => 'application/octet-stream'); - http_header('Content-Disposition' => 'attachment;filename="config"'); - http_header('Content-Length' => length($config)); -} - -</%init> diff --git a/httemplate/misc/process/bulk_pkg_increment_bill.cgi b/httemplate/misc/process/bulk_pkg_increment_bill.cgi deleted file mode 100755 index 0d8417b26..000000000 --- a/httemplate/misc/process/bulk_pkg_increment_bill.cgi +++ /dev/null @@ -1,76 +0,0 @@ -%if ($error) { -% $cgi->param('error', $error); -<% $cgi->redirect(popurl(2). 'bulk_pkg_increment_bill.cgi?'. $cgi->query_string ) %> -%} else { -<% header('Packages Adjusted') %> - <SCRIPT TYPE="text/javascript"> - window.top.location.reload(); - </SCRIPT> - </BODY></HTML> -% } -<%init> - -local $FS::UID::AutoCommit = 0; -my $dbh = dbh; -my $error; - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages') - and $FS::CurrentUser::CurrentUser->access_right('Edit customer package dates'); - -my $days = $cgi->param('days') or die "missing parameter: days"; -$days > 0 or $error = "Number of days must be > 0"; - -my %search_hash = (); - -$search_hash{'query'} = $cgi->param('query'); - -for my $param (qw(agentnum magic status classnum pkgpart)) { - $search_hash{$param} = $cgi->param($param) - if $cgi->param($param); -} - -### -# parse dates -### - -#false laziness w/report_cust_pkg.html -# and, now, w/bulk_change_pkg.cgi -my %disable = ( - 'all' => {}, - 'one-time charge' => { 'last_bill'=>1, 'bill'=>1, 'adjourn'=>1, 'susp'=>1, 'expire'=>1, 'cancel'=>1, }, - 'active' => { 'susp'=>1, 'cancel'=>1 }, - 'suspended' => { 'cancel' => 1 }, - 'cancelled' => {}, - '' => {}, -); - -foreach my $field (qw( setup last_bill bill adjourn susp expire cancel )) { - - my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi, $field); - - next if $beginning == 0 && $ending == 4294967295 - or $disable{$cgi->param('status')}->{$field}; - - $search_hash{$field} = [ $beginning, $ending ]; - -} - -if(!$error) { - foreach my $cust_pkg (qsearch(FS::cust_pkg->search(\%search_hash))) { - next if ! $cust_pkg->bill; - my $new_cust_pkg = FS::cust_pkg->new({ $cust_pkg->hash }); - $new_cust_pkg->bill($new_cust_pkg->bill + $days*86400); - $error = $new_cust_pkg->replace($cust_pkg); - - if($error) { - $cgi->param("error",substr($error, 0, 512)); - $dbh->rollback; - return; - } - } - - $dbh->commit; -} - -</%init> diff --git a/httemplate/misc/process/copy-rate_detail.html b/httemplate/misc/process/copy-rate_detail.html index 87a674566..60b2aebee 100644 --- a/httemplate/misc/process/copy-rate_detail.html +++ b/httemplate/misc/process/copy-rate_detail.html @@ -47,7 +47,7 @@ foreach my $countrycode ( @countrycodes ) { || new FS::rate_detail \%hash; $dst_rate_detail->$_( $src_rate_detail->get($_) ) - foreach qw( min_included min_charge sec_granularity classnum ); + foreach qw( min_included conn_charge conn_sec min_charge sec_granularity classnum ); my $method = $dst_rate_detail->ratedetailnum ? 'replace' : 'insert'; diff --git a/httemplate/misc/process/tax-import.cgi b/httemplate/misc/process/tax-import.cgi index b9e9daad5..f800dbd5b 100644 --- a/httemplate/misc/process/tax-import.cgi +++ b/httemplate/misc/process/tax-import.cgi @@ -4,6 +4,6 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Import'); -my $server = new FS::UI::Web::JSRPC 'FS::tax_rate::process_batch_import', $cgi; +my $server = new FS::UI::Web::JSRPC 'FS::tax_rate::process_batch_import', $cgi; </%init> diff --git a/httemplate/misc/rate_edit_excel.html b/httemplate/misc/rate_edit_excel.html index e73133c05..442d83aca 100644 --- a/httemplate/misc/rate_edit_excel.html +++ b/httemplate/misc/rate_edit_excel.html @@ -1,5 +1,9 @@ <% include('/elements/header.html', 'Edit rates with Excel' ) %> +% if ( $have_conn ) { + <FONT COLOR="#FF0000">WARNING: This functionality does not yet preserve connection charges.</FONT><BR><BR> +% } + <% include( '/elements/form-file_upload.html', 'name' => 'RateImportForm', 'action' => 'process/rate_edit_excel.html', @@ -58,4 +62,9 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); +my $sth = dbh->prepare('SELECT COUNT(*) FROM rate_detail WHERE conn_charge > 0 OR conn_sec > 0 LIMIT 1') + or die dbh->errstr; +$sth->execute or die $sth->errstr; +my $have_conn = $sth->fetchrow_arrayref->[0]; + </%init> diff --git a/httemplate/misc/tax-import.cgi b/httemplate/misc/tax-import.cgi index ceb74645c..5116e5404 100644 --- a/httemplate/misc/tax-import.cgi +++ b/httemplate/misc/tax-import.cgi @@ -7,7 +7,7 @@ Import a CSV file set containing tax rate records. 'name' => 'TaxRateUpload', 'action' => 'process/tax-import.cgi', 'num_files' => 6, - 'fields' => [ 'format', 'reload' ], + 'fields' => [ 'format', ], 'message' => 'Tax rates imported', ) %> @@ -18,28 +18,21 @@ Import a CSV file set containing tax rate records. <TH ALIGN="right">Format</TH> <TD> <SELECT NAME="format"> - <!-- <OPTION VALUE="cch-update" SELECTED>CCH update (CSV) --> - <OPTION VALUE="cch">CCH import (CSV) - <!-- <OPTION VALUE="cch-fixed-update">CCH update (fixed length) --> - <OPTION VALUE="cch-fixed">CCH import (fixed length) + <OPTION VALUE="cch-update" SELECTED>CCH update (CSV) + <OPTION VALUE="cch">CCH initial import (CSV) + <OPTION VALUE="cch-fixed-update">CCH update (fixed length) + <OPTION VALUE="cch-fixed">CCH initial import (fixed length) </SELECT> </TD> </TR> - <TR> - <TH ALIGN="right">Replace existing data from this vendor</TH> - <TD> - <INPUT NAME="reload" TYPE="checkbox" VALUE="1" CHECKED> - </TD> - </TR> - <% include( '/elements/file-upload.html', - 'field' => [ 'geocodefile', + 'field' => [ 'geofile', 'codefile', 'plus4file', 'zipfile', - 'txmatrixfile', - 'detailfile', + 'txmatrix', + 'detail', ], 'label' => [ 'geocode filename', 'code filename', diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index 9b0201c29..2e79cd75d 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -3,15 +3,24 @@ 'name' => 'line items', 'query' => $query, 'count_query' => $count_query, - 'count_addl' => [ $money_char. '%.2f total', ], + 'count_addl' => [ $money_char. '%.2f total', + $unearned ? ( $money_char. '%.2f unearned revenue' ) : (), + ], 'header' => [ '#', 'Description', - 'Setup charge', + ( $unearned + ? 'Unearned' + : 'Setup charge' + ), ( $use_usage eq 'usage' ? 'Usage charge' : 'Recurring charge' ), + ( $unearned + ? ( 'Charge start', 'Charge end' ) + : () + ), 'Invoice', 'Date', FS::UI::Web::cust_header(), @@ -24,7 +33,22 @@ }, #strikethrough or "N/A ($amount)" or something these when # they're not applicable to pkg_tax search - sub { sprintf($money_char.'%.2f', shift->setup ) }, + sub { my $cust_bill_pkg = shift; + if ( $unearned ) { + my $period = + $cust_bill_pkg->edate - $cust_bill_pkg->sdate; + my $elapsed = $unearned - $cust_bill_pkg->sdate; + $elapsed = 0 if $elapsed < 0; + + my $remaining = 1 - $elapsed/$period; + + sprintf($money_char. '%.2f', + $remaining * $cust_bill_pkg->recur ); + + } else { + sprintf($money_char.'%.2f', $cust_bill_pkg->setup ); + } + }, sub { my $row = shift; my $value = 0; if ( $use_usage eq 'recurring' ) { @@ -36,6 +60,12 @@ } sprintf($money_char.'%.2f', $value ); }, + ( $unearned + ? ( sub { time2str('%b %d %Y', shift->sdate ) }, + sub { time2str('%b %d %Y', shift->edate ) }, + ) + : () + ), 'invnum', sub { time2str('%b %d %Y', shift->_date ) }, \&FS::UI::Web::cust_fields, @@ -45,6 +75,7 @@ '', '', '', + ( $unearned ? ( '', '' ) : () ), $ilink, $ilink, ( map { $_ ne 'Cust. Status' ? $clink : '' } @@ -52,12 +83,16 @@ ), ], #'align' => 'rlrrrc'.FS::UI::Web::cust_aligns(), - 'align' => 'lrrrc'.FS::UI::Web::cust_aligns(), + 'align' => 'lrr'. + ( $unearned ? 'cc' : '' ). + 'rc'. + FS::UI::Web::cust_aligns(), 'color' => [ #'', '', '', '', + ( $unearned ? ( '', '' ) : () ), '', '', FS::UI::Web::cust_colors(), @@ -67,6 +102,7 @@ '', '', '', + ( $unearned ? ( '', '' ) : () ), '', '', FS::UI::Web::cust_styles(), @@ -80,6 +116,8 @@ die "access denied" my $conf = new FS::Conf; +my $unearned = ''; + #here is the agent virtualization my $agentnums_sql = $FS::CurrentUser::CurrentUser->agentnums_sql( 'table' => 'cust_main' ); @@ -282,6 +320,19 @@ if ( $cgi->param('out') ) { keys %ph ); +} elsif ( $cgi->param('unearned_now') =~ /^(\d+)$/ ) { + + $unearned = $1; + + push @where, "cust_bill_pkg.sdate < $unearned", + "cust_bill_pkg.edate > $unearned", + "cust_bill_pkg.recur != 0", + "part_pkg.freq != '0'", + "part_pkg.freq != '1'", + "part_pkg.freq NOT LIKE '%h'", + "part_pkg.freq NOT LIKE '%d'", + "part_pkg.freq NOT LIKE '%w'"; + } if ( $cgi->param('itemdesc') ) { @@ -399,10 +450,31 @@ if ( $cgi->param('pkg_tax') ) { $count_query .= "SUM(setup + recur - usage)"; } elsif ( $use_usage eq 'usage' ) { $count_query .= "SUM(usage)"; + } elsif ( $unearned ) { + $count_query .= "SUM(cust_bill_pkg.recur)"; } else { $count_query .= "SUM(cust_bill_pkg.setup + cust_bill_pkg.recur)"; } + if ( $unearned ) { + + #false laziness w/report_prepaid_income.cgi + + my $float = 'REAL'; #'DOUBLE PRECISION'; + + my $period = "CAST(cust_bill_pkg.edate - cust_bill_pkg.sdate AS $float)"; + my $elapsed = "(CASE WHEN cust_bill_pkg.sdate > $unearned + THEN 0 + ELSE ($unearned - cust_bill_pkg.sdate) + END)"; + #my $elapsed = "CAST($unearned - cust_bill_pkg.sdate AS $float)"; + + my $remaining = "(1 - $elapsed/$period)"; + + $count_query .= ", SUM($remaining * cust_bill_pkg.recur)"; + + } + } my $where = ' WHERE '. join(' AND ', @where); @@ -458,11 +530,13 @@ if ($use_usage) { } warn "count_query is $count_query\n"; -my @select = ( - 'cust_bill_pkg.*', - 'cust_bill._date', - ); -push @select, 'part_pkg.pkg' unless $cgi->param('istax'); +my @select = ( 'cust_bill_pkg.*', + 'cust_bill._date', ); + +push @select, 'part_pkg.pkg', + 'part_pkg.freq', + unless $cgi->param('istax'); + push @select, 'cust_main.custnum', FS::UI::Web::cust_sql_fields(); diff --git a/httemplate/search/cust_main-zip.html b/httemplate/search/cust_main-zip.html index 56df924bc..e87b21474 100644 --- a/httemplate/search/cust_main-zip.html +++ b/httemplate/search/cust_main-zip.html @@ -32,6 +32,17 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { $agentnum = $1; push @where, "cust_main.agentnum = $agentnum"; } + +# select svcdb + +if ( $cgi->param('svcdb') =~ /^(\w+)$/ ) { + my $svcdb = $1; + push @where, "EXISTS( SELECT 1 FROM $svcdb LEFT JOIN cust_svc USING ( svcnum ) + LEFT JOIN cust_pkg USING ( pkgnum ) + WHERE cust_pkg.custnum = cust_main.custnum + )"; +} + my $where = scalar(@where) ? 'WHERE '. join(' AND ', @where) : ''; # bill zip vs ship zip diff --git a/httemplate/search/elements/cust_pay_or_refund.html b/httemplate/search/elements/cust_pay_or_refund.html index b1296d1b0..4f83d0ab6 100755 --- a/httemplate/search/elements/cust_pay_or_refund.html +++ b/httemplate/search/elements/cust_pay_or_refund.html @@ -29,6 +29,15 @@ Examples: 'redirect_empty' => $redirect_empty, ) + include( 'elements/cust_pay_or_refund.html', + 'table' => 'h_cust_pay', + 'amount_field' => 'paid', + 'name_singular' => 'payment', + 'name_verb' => 'paid', + 'pre_header' => [ 'Transaction', 'By' ], + 'pre_fields' => [ 'history_action', 'history_user' ], + ) + </%doc> <% include( 'search.html', 'title' => $title, @@ -37,46 +46,12 @@ Examples: 'count_query' => $count_query, 'count_addl' => [ '$%.2f total '.$opt{name_verb}, ], 'redirect_empty' => $opt{'redirect_empty'}, - 'header' => [ "\u$name_singular", - 'Amount', - 'Date', - @header, - FS::UI::Web::cust_header(), - ], - 'fields' => [ - 'payby_payinfo_pretty', - sub { sprintf('$%.2f', shift->$amount_field() ) }, - sub { time2str('%b %d %Y', shift->_date ) }, - @fields, - \&FS::UI::Web::cust_fields, - ], - #'align' => 'lrrrll', - 'align' => 'rrr'. - join('', map 'c', @fields ). - FS::UI::Web::cust_aligns(), - 'links' => [ - $link, - $link, - $link, - ( map '', @fields ), - ( map { $_ ne 'Cust. Status' ? $cust_link : '' } - FS::UI::Web::cust_header() - ), - ], - 'color' => [ - '', - '', - '', - ( map '', @fields ), - FS::UI::Web::cust_colors(), - ], - 'style' => [ - '', - '', - '', - ( map '', @fields ), - FS::UI::Web::cust_styles(), - ], + 'header' => \@header, + 'fields' => \@fields, + 'align' => $align, + 'links' => \@links, + 'color' => \@color, + 'style' => \@style, ) %> <%init> @@ -88,16 +63,69 @@ my $curuser = $FS::CurrentUser::CurrentUser; die "access denied" unless $curuser->access_right('Financial reports'); -my $thing = $opt{'thing'}; +my $table = $opt{'table'} || 'cust_'.$opt{'thing'}; + my $amount_field = $opt{'amount_field'}; my $name_singular = $opt{'name_singular'}; my $title = "\u$name_singular Search Results"; +my $link = ''; +if ( ( $curuser->access_right('View invoices') #XXX for now + || $curuser->access_right('View customer payments') + ) + && ! $opt{'disable_link'} + ) +{ + + my $key; + my $q = ''; + if ( $table eq 'cust_pay_void' ) { + $key = 'paynum'; + $q .= 'void=1;'; + } elsif ( $table eq /^cust_(\w+)$/ ) { + $key = $1.'num'; + } + + if ( $key ) { + $q .= "$key="; + $link = [ "${p}view/$table.html?$q", $key ] + } +} + +my $cust_link = sub { + my $cust_thing = shift; + $cust_thing->cust_main_custnum + ? [ "${p}view/cust_main.cgi?", 'custnum' ] + : ''; +}; + my @header = (); my @fields = (); +my $align = ''; +my @links = (); +if ( $opt{'pre_header'} ) { + push @header, @{ $opt{'pre_header'} }; + $align .= 'c' x scalar(@{ $opt{'pre_header'} }); + push @links, map '', @{ $opt{'pre_header'} }; + push @fields, @{ $opt{'pre_fields'} }; +} + +push @header, "\u$name_singular", + 'Amount', + 'Date', +; +$align .= 'rrr'; +push @links, '', '', ''; +push @fields, 'payby_payinfo_pretty', + sub { sprintf('$%.2f', shift->$amount_field() ) }, + sub { time2str('%b %d %Y', shift->_date ) }, +; + unless ( $opt{'disable_by'} ) { push @header, 'By'; + $align .= 'c'; + push @links, ''; push @fields, sub { my $o = shift->otaker; $o = 'auto billing' if $o eq 'fs_daily'; $o = 'customer self-service' if $o eq 'fs_selfservice'; @@ -105,6 +133,14 @@ unless ( $opt{'disable_by'} ) { }; } +push @header, FS::UI::Web::cust_header(); +$align .= FS::UI::Web::cust_aligns(); +push @links, map { $_ ne 'Cust. Status' ? $cust_link : '' } + FS::UI::Web::cust_header(); +my @color = ( ( map '', @fields ), FS::UI::Web::cust_colors() ); +my @style = ( ( map '', @fields ), FS::UI::Web::cust_styles() ); +push @fields, \&FS::UI::Web::cust_fields; + push @header, @{ $opt{'addl_header'} } if $opt{'addl_header'}; push @fields, @{ $opt{'addl_fields'} } @@ -132,7 +168,7 @@ if ( $cgi->param('magic') ) { $cgi->param('payby') =~ /^(CARD|CHEK|BILL|PREP|CASH|WEST|MCRD)(-(VisaMC|Amex|Discover|Maestro))?$/ or die "illegal payby ". $cgi->param('payby'); - push @search, "cust_$thing.payby = '$1'"; + push @search, "$table.payby = '$1'"; if ( $3 ) { my $cardtype = $3; @@ -141,53 +177,53 @@ if ( $cgi->param('magic') ) { if ( $cardtype eq 'VisaMC' ) { #avoid posix regexes for portability $search = - " ( ( substring(cust_$thing.payinfo from 1 for 1) = '4' ". - " AND substring(cust_$thing.payinfo from 1 for 4) != '4936' ". - " AND substring(cust_$thing.payinfo from 1 for 6) ". + " ( ( substring($table.payinfo from 1 for 1) = '4' ". + " AND substring($table.payinfo from 1 for 4) != '4936' ". + " AND substring($table.payinfo from 1 for 6) ". " NOT SIMILAR TO '49030[2-9]' ". - " AND substring(cust_$thing.payinfo from 1 for 6) ". + " AND substring($table.payinfo from 1 for 6) ". " NOT SIMILAR TO '49033[5-9]' ". - " AND substring(cust_$thing.payinfo from 1 for 6) ". + " AND substring($table.payinfo from 1 for 6) ". " NOT SIMILAR TO '49110[1-2]' ". - " AND substring(cust_$thing.payinfo from 1 for 6) ". + " AND substring($table.payinfo from 1 for 6) ". " NOT SIMILAR TO '49117[4-9]' ". - " AND substring(cust_$thing.payinfo from 1 for 6) ". + " AND substring($table.payinfo from 1 for 6) ". " NOT SIMILAR TO '49118[1-2]' ". " )". - " OR substring(cust_$thing.payinfo from 1 for 2) = '51' ". - " OR substring(cust_$thing.payinfo from 1 for 2) = '52' ". - " OR substring(cust_$thing.payinfo from 1 for 2) = '53' ". - " OR substring(cust_$thing.payinfo from 1 for 2) = '54' ". - " OR substring(cust_$thing.payinfo from 1 for 2) = '54' ". - " OR substring(cust_$thing.payinfo from 1 for 2) = '55' ". - " OR substring(cust_$thing.payinfo from 1 for 2) = '36' ". #Diner's int'l processed as Visa/MC inside US + " OR substring($table.payinfo from 1 for 2) = '51' ". + " OR substring($table.payinfo from 1 for 2) = '52' ". + " OR substring($table.payinfo from 1 for 2) = '53' ". + " OR substring($table.payinfo from 1 for 2) = '54' ". + " OR substring($table.payinfo from 1 for 2) = '54' ". + " OR substring($table.payinfo from 1 for 2) = '55' ". + " OR substring($table.payinfo from 1 for 2) = '36' ". #Diner's int'l processed as Visa/MC inside US " ) "; } elsif ( $cardtype eq 'Amex' ) { $search = - " ( substring(cust_$thing.payinfo from 1 for 2 ) = '34' ". - " OR substring(cust_$thing.payinfo from 1 for 2 ) = '37' ". + " ( substring($table.payinfo from 1 for 2 ) = '34' ". + " OR substring($table.payinfo from 1 for 2 ) = '37' ". " ) "; } elsif ( $cardtype eq 'Discover' ) { $search = - " ( substring(cust_$thing.payinfo from 1 for 4 ) = '6011' ". - " OR substring(cust_$thing.payinfo from 1 for 2 ) = '65' ". - " OR substring(cust_$thing.payinfo from 1 for 3 ) = '622' ". #China Union Pay processed as Discover outside CN + " ( substring($table.payinfo from 1 for 4 ) = '6011' ". + " OR substring($table.payinfo from 1 for 2 ) = '65' ". + " OR substring($table.payinfo from 1 for 3 ) = '622' ". #China Union Pay processed as Discover outside CN " ) "; } elsif ( $cardtype eq 'Maestro' ) { $search = - " ( substring(cust_$thing.payinfo from 1 for 2 ) = '63' ". - " OR substring(cust_$thing.payinfo from 1 for 2 ) = '67' ". - " OR substring(cust_$thing.payinfo from 1 for 6 ) = '564182' ". - " OR substring(cust_$thing.payinfo from 1 for 4 ) = '4936' ". - " OR substring(cust_$thing.payinfo from 1 for 6 ) ". + " ( substring($table.payinfo from 1 for 2 ) = '63' ". + " OR substring($table.payinfo from 1 for 2 ) = '67' ". + " OR substring($table.payinfo from 1 for 6 ) = '564182' ". + " OR substring($table.payinfo from 1 for 4 ) = '4936' ". + " OR substring($table.payinfo from 1 for 6 ) ". " SIMILAR TO '49030[2-9]' ". - " OR substring(cust_$thing.payinfo from 1 for 6 ) ". + " OR substring($table.payinfo from 1 for 6 ) ". " SIMILAR TO '49033[5-9]' ". - " OR substring(cust_$thing.payinfo from 1 for 6 ) ". + " OR substring($table.payinfo from 1 for 6 ) ". " SIMILAR TO '49110[1-2]' ". - " OR substring(cust_$thing.payinfo from 1 for 6 ) ". + " OR substring($table.payinfo from 1 for 6 ) ". " SIMILAR TO '49117[4-9]' ". - " OR substring(cust_$thing.payinfo from 1 for 6 ) ". + " OR substring($table.payinfo from 1 for 6 ) ". " SIMILAR TO '49118[1-2]' ". " ) "; } else { @@ -195,10 +231,10 @@ if ( $cgi->param('magic') ) { } my $masksearch = $search; - $masksearch =~ s/cust_$thing\.payinfo/cust_$thing.paymask/gi; + $masksearch =~ s/$table\.payinfo/$table.paymask/gi; push @search, - "( $search OR ( cust_$thing.paymask IS NOT NULL AND $masksearch ) )"; + "( $search OR ( $table.paymask IS NOT NULL AND $masksearch ) )"; } } @@ -206,11 +242,11 @@ if ( $cgi->param('magic') ) { if ( $cgi->param('payinfo') ) { $cgi->param('payinfo') =~ /^\s*(\d+)\s*$/ or die "illegal payinfo ". $cgi->param('payinfo'); - push @search, "cust_$thing.payinfo = '$1'"; + push @search, "$table.payinfo = '$1'"; } if ( $cgi->param('otaker') =~ /^(\w+)$/ ) { - push @search, "cust_$thing.otaker = '$1'"; + push @search, "$table.otaker = '$1'"; } #for cust_pay_pending... statusNOT=done @@ -222,7 +258,7 @@ if ( $cgi->param('magic') ) { push @search, "_date >= $beginning ", "_date <= $ending"; - if ( $thing eq 'pay_void' ) { + if ( $table eq 'cust_pay_void' ) { my($v_beginning, $v_ending) = FS::UI::Web::parse_beginning_ending($cgi, 'void'); push @search, "void_date >= $v_beginning ", @@ -246,19 +282,34 @@ if ( $cgi->param('magic') ) { die "unknown search magic: ". $cgi->param('magic'); } + #for the history search + if ( $cgi->param('history_action') =~ /^([\w,]+)$/ ) { + my @history_action = split(/,/, $1); + push @search, 'history_action IN ('. + join(',', map "'$_'", @history_action ). ')'; + } + + if ( $cgi->param('history_date_beginning') + || $cgi->param('history_date_ending') ) { + my($h_beginning, $h_ending) = + FS::UI::Web::parse_beginning_ending($cgi, 'history_date'); + push @search, "history_date >= $h_beginning ", + "history_date <= $h_ending"; + } + #here is the agent virtualization push @search, $curuser->agentnums_sql; my $search = ' WHERE '. join(' AND ', @search); $count_query = "SELECT COUNT(*), SUM($amount_field) ". - "FROM cust_$thing LEFT JOIN cust_main USING ( custnum )". + "FROM $table LEFT JOIN cust_main USING ( custnum )". $search; $sql_query = { - 'table' => "cust_$thing", + 'table' => $table, 'select' => join(', ', - "cust_$thing.*", + "$table.*", 'cust_main.custnum as cust_main_custnum', FS::UI::Web::cust_sql_fields(), ), @@ -277,12 +328,12 @@ if ( $cgi->param('magic') ) { $cgi->param('payby') =~ /^(\w+)$/ or die "illegal payby"; my $payby = $1; - $count_query = "SELECT COUNT(*), SUM($amount_field) FROM cust_$thing". + $count_query = "SELECT COUNT(*), SUM($amount_field) FROM $table". " WHERE payinfo = '$payinfo' AND payby = '$payby'". " AND ". $curuser->agentnums_sql; $sql_query = { - 'table' => "cust_$thing", + 'table' => $table, 'hashref' => { 'payinfo' => $payinfo, 'payby' => $payby }, 'extra_sql' => $curuser->agentnums_sql. @@ -291,23 +342,4 @@ if ( $cgi->param('magic') ) { } -my $link = ''; -if ( ( $curuser->access_right('View invoices') #XXX for now - || $curuser->access_right('View customer payments') - ) - && ! $opt{'disable_link'} - ) -{ - my $key = $thing eq 'pay_void' ? 'paynum' : $thing.'num'; - my $q = ( $thing eq 'pay_void' ? 'void=1;' : '' ). "$key="; - $link = [ "${p}view/cust_$thing.html?$q", $key ] -} - -my $cust_link = sub { - my $cust_thing = shift; - $cust_thing->cust_main_custnum - ? [ "${p}view/cust_main.cgi?", 'custnum' ] - : ''; -}; - </%init> diff --git a/httemplate/search/h_cust_pay.html b/httemplate/search/h_cust_pay.html new file mode 100755 index 000000000..99330fadd --- /dev/null +++ b/httemplate/search/h_cust_pay.html @@ -0,0 +1,9 @@ +<% include( 'elements/cust_pay_or_refund.html', + 'table' => 'h_cust_pay', + 'amount_field' => 'paid', + 'name_singular' => 'payment', + 'name_verb' => 'paid', + 'pre_header' => [ 'Transaction', 'By' ], + 'pre_fields' => [ 'history_action', 'history_user' ], + ) +%> diff --git a/httemplate/search/mailinglistmember.html b/httemplate/search/mailinglistmember.html new file mode 100644 index 000000000..ee395f416 --- /dev/null +++ b/httemplate/search/mailinglistmember.html @@ -0,0 +1,57 @@ +<% include('elements/search.html', + 'title' => $title, + 'name_singular' => 'member', + 'query' => $query, + 'count_query' => $count_query, + 'header' => [ 'Email address' ], + 'fields' => [ $email_sub, ], #just this one for now + 'html_init' => $html_init, + ) +%> +<%init> + +#XXX ACL: +#make sure the mailing list is attached to a customer service i can see/view + +$cgi->param('listnum') =~ /^(\d+)$/ or die 'illegal listnum'; +my $listnum = $1; + +my $mailinglist = qsearchs('mailinglist', { 'listnum' => $listnum }) + or die "unknown listnum $listnum"; +my $title = $mailinglist->listname. ' mailing list'; + +my $svc_mailinglist = $mailinglist->svc_mailinglist; + +my $query = { + 'table' => 'mailinglistmember', + 'hashref' => { 'listnum' => $listnum }, +}; + +my $count_query = "SELECT COUNT(*) FROM mailinglistmember WHERE listnum = $listnum"; + +my $email_sub = sub { + my $member = shift; + my $r = $member->email; #just this one for now + my $a = qq[<A HREF="javascript:areyousure('$r', ]. $member->membernum. ')">'; + $r .= " (${a}remove</A>)"; + $r; +}; + +my $html_init = ''; +if ( $svc_mailinglist ) { + my $svcnum = $svc_mailinglist->svcnum; + my $label = encode_entities($svc_mailinglist->label); + $html_init .= qq[<A HREF="${p}/view/svc_mailinglist.cgi?$svcnum">View customer mailing list: $label</A><BR><BR>]; +} + +$html_init .= <<"END"; +<SCRIPT TYPE="text/javascript"> + function areyousure(email,membernum) { + if ( confirm('Are you sure you want to remove ' + email + ' from this mailing list?') ) + window.location.href="${p}misc/delete-mailinglistmember.html?" + membernum; + + } +</SCRIPT> +END + +</%init> diff --git a/httemplate/search/part_pkg.html b/httemplate/search/part_pkg.html new file mode 100644 index 000000000..87237c7cf --- /dev/null +++ b/httemplate/search/part_pkg.html @@ -0,0 +1,213 @@ +<% include( 'elements/search.html', + 'title' => $title, + 'name' => $name, + 'header' => \@header, + 'query' => { 'select' => $select, + 'table' => 'part_pkg', + 'addl_from' => $addl_from, + 'hashref' => {}, + 'extra_sql' => $extra_sql, + 'order_by' => "ORDER BY $order_by", + }, + 'count_query' => $count_query, + 'fields' => \@fields, + 'links' => \@links, + 'align' => $align, + ) +%> +<%init> + +#this is about reports about packages definitions (starting w/commission ones) +# while browse/part_pkg.cgi is config->package definitions + +my $curuser = $FS::CurrentUser::CurrentUser; +die "access denied" + unless $curuser->access_right('Financial reports'); + +my $conf = new FS::Conf; +my $money_char = $conf->config('money_char') || '$'; + +my $title = 'Package definition report'; +my $name = 'package definition'; + +my $select = ''; +my $addl_from = ''; +my @where = (); +my @order_by = (); +my @header = (); +my @fields = (); +my @links = (); +my $align = ''; + +if (1) { #commission reports + + if (1) { #employee commission reports + + $select = 'DISTINCT usernum, username, part_pkg.*'; + + $addl_from .= ' CROSS JOIN access_user '; + + if ( $cgi->param('otaker') =~ /^(\w+)$/ ) { + + #XXX in this context, agent virt for employees, not package defs + my $access_user = qsearchs('access_user', { 'username' => $1 }) + or die "unknown usernum"; + + $title = $access_user->name; + + } else { + + push @header, 'Employee'; + push @fields, sub { shift->get('username'); }; #access_user->name + push @links, ''; #link to employee edit w/ACL? + $align .= 'c'; + + push @order_by, 'otaker'; + + $title = 'Employee'; + + } + + } elsif (0) { #agent commission reports + + if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { + + #agent virt + my $agent = qsearchs('agent', { 'agentnum' => $1 }) + or die "unknown agentnum"; + + $title = $agent->agent; + + push @header, 'Agent'; + push @fields, sub { 'XXXagent' }; + push @links, ''; #link to agent edit w/ACL? + $align .= 'c'; + + push @order_by, 'agentnum'; #join to agent? we're mostly interested in grouping rather than order + + } else { + $title = 'Agent'; + } + + } + + $title .= ' commission report'; + $name = "commissionable $name"; + + +} + +push @header, 'Package definition'; +push @fields, 'pkg_comment'; +push @links, ''; #link to pkg definition edit w/ACL? +$align .= 'l'; + +if (1) { #commission reports + + my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi); + + my $match = ''; + if (1) { #employee commission reports + $match = 'cust_pkg.otaker = access_user.username'; + } elsif (0) { #agent commission reports + $match = 'cust_main.agentnum = agent.agentnum'; + } + + my $from_cust_bill_pkg_where = "FROM cust_bill_pkg + LEFT JOIN ( cust_bill ) USING ( invnum ) + LEFT JOIN ( cust_pkg ) USING ( pkgnum ) + WHERE cust_bill_pkg.pkgnum > 0 + AND cust_bill._date >= $beginning + AND cust_bill._date <= $ending "; + my $and = " AND $match + AND cust_pkg.pkgpart = part_pkg.pkgpart"; + + push @where, "EXISTS( SELECT 1 $from_cust_bill_pkg_where $and )"; + + push @header, '#'; # of sales'; + push @links, ''; #link to detail report + $align .= 'r'; + push @fields, 'num_cust_pkg'; + $select .= ", ( SELECT COUNT(DISTINCT pkgnum) + $from_cust_bill_pkg_where $and ) + AS num_cust_pkg"; +# push @fields, sub { +# my $part_pkg = shift; +# my $sql = +# #"SELECT COUNT( SELECT DISTINCT pkgnum $from_cust_bill_pkg_where )"; +# "SELECT COUNT(DISTINCT pkgnum) $from_cust_bill_pkg_where"; +# my $sth = dbh->prepare($sql) or die dbh->errstr; +# $sth->execute or die $sth->errstr; +# $sth->fetchrow_arrayref->[0]; +# }; + + push @header, 'Sales'; + push @links, ''; #link to detail report + $align .= 'r'; +# push @fields, sub { $money_char. sprintf('%.2f', shift->get('pkg_sales')); }; +# $select .= +# ", SUM( SELECT setup+recur $from_cust_bill_pkg_where ) AS pkg_sales"; + push @fields, sub { + my $part_pkg = shift; + my $sql = "SELECT SUM(cust_bill_pkg.setup+cust_bill_pkg.recur) $from_cust_bill_pkg_where AND pkgpart = ? AND "; + my @arg = ($part_pkg->pkgpart); + if (1) { #employee commission reports + $sql .= 'otaker = ?'; + push @arg, $part_pkg->get('username'); + } elsif (0) { #agent commission reports + $match = 'cust_main.agentnum = agent.agentnum'; + } + my $sth = dbh->prepare($sql) or die dbh->errstr; + $sth->execute(@arg) or die $sth->errstr; + $money_char. sprintf('%.2f', $sth->fetchrow_arrayref->[0] ); + }; + + push @header, 'Commission'; + push @links, ''; #link to detail report + $align .= 'r'; + #push @fields, sub { $money_char. sprintf('%.2f', shift->get('pkg_commission')); }; + push @fields, sub { + my $part_pkg = shift; + my $sql = "SELECT SUM(amount) FROM cust_credit + LEFT JOIN cust_event USING ( eventnum ) + LEFT JOIN part_event USING ( eventpart ) + LEFT JOIN cust_pkg ON ( cust_event.tablenum = cust_pkg.pkgnum ) + WHERE eventnum IS NOT NULL + AND action IN ( 'pkg_employee_credit', + 'pkg_employee_credit_pkg' + ) + AND cust_credit._date >= $beginning + AND cust_credit._date <= $ending + AND pkgpart = ? + AND cust_credit.custnum = ? + "; + my @arg = ($part_pkg->pkgpart); + if (1) { #employee commission reports + + #XXX in this context, agent virt for employees, not package defs + my $access_user = qsearchs('access_user', { 'username' => $part_pkg->get('username') }) + or die "unknown usernum"; + + return 0 unless $access_user->user_custnum; + push @arg, $access_user->user_custnum; + + } elsif (0) { #agent commission reports + push @arg, 'XXXagent_custnum'; #$agent->agent_custnum + } + my $sth = dbh->prepare($sql) or die dbh->errstr; + $sth->execute(@arg) or die $sth->errstr; + $money_char. sprintf('%.2f', $sth->fetchrow_arrayref->[0] ); + + }; + +} + +push @order_by, 'pkgpart'; #pkg? + +$select ||= 'part_pkg.*'; +my $extra_sql = scalar(@where) ? 'WHERE ' . join(' AND ', @where) : ''; +my $order_by = join(', ', @order_by); + +my $count_query = "SELECT COUNT(*) FROM part_pkg $addl_from $extra_sql"; + +</%init> diff --git a/httemplate/search/report_cust_main-zip.html b/httemplate/search/report_cust_main-zip.html index aa802f302..00cb9ed2c 100644 --- a/httemplate/search/report_cust_main-zip.html +++ b/httemplate/search/report_cust_main-zip.html @@ -20,7 +20,7 @@ </TR> <TR> - <TD ALIGN="right">Show customers with status:</TD> + <TD ALIGN="right">Show customers with status</TD> <TD> <SELECT NAME="status"> <OPTION VALUE="">all @@ -33,6 +33,23 @@ </TD> </TR> + <TR> + <TD ALIGN="right">Limit to customers with provisioned service</TD> + <TD> + <SELECT NAME="svcdb"> + <OPTION VALUE="">(no) + <OPTION VALUE="svc_acct">Account (svc_acct) + <OPTION VALUE="svc_broadband">Broadband service (svc_broadband) + <OPTION VALUE="svc_domain">Domain (svc_domain) + <OPTION VALUE="svc_external">External service (svc_external) + <OPTION VALUE="svc_forward">Mail forward (svc_foward) + <OPTION VALUE="svc_pbx">PBX (svc_pbx) + <OPTION VALUE="svc_phone">Phone number (svc_phone) + <OPTION VALUE="svc_www">Hosting (svc_www) + </SELECT> + </TD> + </TR> + <% include( '/elements/tr-select-agent.html', 'curr_value' => scalar( $cgi->param('agentnum') ), 'label' => 'For agent: ', diff --git a/httemplate/search/report_employee_commission.html b/httemplate/search/report_employee_commission.html new file mode 100644 index 000000000..a79630a76 --- /dev/null +++ b/httemplate/search/report_employee_commission.html @@ -0,0 +1,34 @@ +<% include('/elements/header.html', 'Employee commission report' ) %> + +<FORM ACTION="part_pkg.html"> + +<TABLE BGCOLOR="#cccccc" CELLSPACING=0> + +%# +%# <% include( '/elements/tr-select-agent.html', +%# 'curr_value' => scalar( $cgi->param('agentnum') ), +%# 'disable_empty' => 0, +%# ) +%# %> +%# + +%#2.1 +<% include( '/elements/tr-select-user.html' ) %> + +%#1.9 +%# <%include( '/elements/tr-select-otaker.html' ) %> + +<% include( '/elements/tr-input-beginning_ending.html', ) %> + +</TABLE> + +<BR> +<INPUT TYPE="submit" VALUE="Get Report"> + +<% include('/elements/footer.html') %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +</%init> diff --git a/httemplate/search/report_h_cust_pay.html b/httemplate/search/report_h_cust_pay.html new file mode 100644 index 000000000..4e47b3831 --- /dev/null +++ b/httemplate/search/report_h_cust_pay.html @@ -0,0 +1,124 @@ +<% include('/elements/header.html', 'Payment transaction history' ) %> + +<FORM ACTION="h_cust_pay.html" METHOD="GET"> +<INPUT TYPE="hidden" NAME="magic" VALUE="_date"> + +<TABLE BGCOLOR="#cccccc" CELLSPACING=0> + + <TR> + <TH BGCOLOR="#e8e8e8" COLSPAN=2 ALIGN="left"> + <FONT SIZE="+1">Search options</FONT> + </TH> + </TR> + +%#history stuff + <TR> + <TD ALIGN="right">Search transactions for: </TD> + <TD> + <SELECT NAME="history_action"> + <OPTION VALUE="insert,replace_old,replace_new,delete">(all changes) + <OPTION VALUE="delete">Insertions + <OPTION VALUE="replace_old,replace_new">Replacements + <OPTION VALUE="delete">Deletions + </SELECT> + </TD> + </TR> + + <TR> + <TD ALIGN="right" VALIGN="center">Transaction date: </TD> + <TD> + <TABLE> + <% include( '/elements/tr-input-beginning_ending.html', + prefix => 'history_date', + layout => 'horiz', + ) + %> + </TABLE> + </TD> + </TR> +%#eo history stuff + + <TR> + <TD ALIGN="right">Payments of type: </TD> + <TD> + <SELECT NAME="payby" onChange="payby_changed(this)"> + <OPTION VALUE="">all</OPTION> + <OPTION VALUE="CARD">credit card (all)</OPTION> + <OPTION VALUE="CARD-VisaMC">credit card (Visa/MasterCard)</OPTION> + <OPTION VALUE="CARD-Amex">credit card (American Express)</OPTION> + <OPTION VALUE="CARD-Discover">credit card (Discover)</OPTION> + <OPTION VALUE="CARD-Maestro">credit card (Maestro/Switch/Solo)</OPTION> + <OPTION VALUE="CHEK">electronic check / ACH</OPTION> + <OPTION VALUE="BILL">check</OPTION> + <OPTION VALUE="PREP">prepaid card</OPTION> + <OPTION VALUE="CASH">cash</OPTION> + <OPTION VALUE="WEST">Western Union</OPTION> + <OPTION VALUE="MCRD">manual credit card</OPTION> + </SELECT> + </TD> + </TR> + + <SCRIPT TYPE="text/javascript"> + + function payby_changed(what) { + if ( what.options[what.selectedIndex].value == 'BILL' ) { + document.getElementById('checkno_caption').style.color = '#000000'; + what.form.payinfo.disabled = false; + what.form.payinfo.style.backgroundColor = '#ffffff'; + } else { + document.getElementById('checkno_caption').style.color = '#bbbbbb'; + what.form.payinfo.disabled = true; + what.form.payinfo.style.backgroundColor = '#dddddd'; + } + } + + </SCRIPT> + + <TR> + <TD ALIGN="right"><FONT ID="checkno_caption" COLOR="#bbbbbb">Check #: </FONT></TD> + <TD> + <INPUT TYPE="text" NAME="payinfo" DISABLED STYLE="background-color: #dddddd"> + </TD> + </TR> + + <% include( '/elements/tr-select-agent.html', + 'curr_value' => scalar($cgi->param('agentnum')), + 'label' => 'for agent: ', + 'disable_empty' => 0, + ) + %> + + <% include( '/elements/tr-select-otaker.html' ) %> + + <TR> + <TD ALIGN="right" VALIGN="center">Payment</TD> + <TD> + <TABLE> + <% include( '/elements/tr-input-beginning_ending.html', + layout => 'horiz', + ) + %> + </TABLE> + </TD> + </TR> + + <% include( '/elements/tr-input-lessthan_greaterthan.html', + 'label' => 'Amount', + 'field' => 'paid', + ) + %> + +</TABLE> + +<BR> +<INPUT TYPE="submit" VALUE="Get Report"> + +</FORM> + +<% include('/elements/footer.html') %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +</%init> diff --git a/httemplate/search/report_prepaid_income.cgi b/httemplate/search/report_prepaid_income.cgi index ce928b81c..c0e2b807e 100644 --- a/httemplate/search/report_prepaid_income.cgi +++ b/httemplate/search/report_prepaid_income.cgi @@ -1,36 +1,86 @@ <% include("/elements/header.html", 'Prepaid Income (Unearned Revenue) Report') %> -<% table() %> - <TR> - <TH>Actual Unearned Revenue</TH> - <TH>Legacy Unearned Revenue</TH> - </TR> +<% include( '/elements/table-grid.html' ) %> + <TR> - <TD ALIGN="right">$<% $total %> - <TD ALIGN="right"> - <% $now == $time ? "\$$total_legacy" : '<i>N/A</i>'%> - </TD> +% if ( scalar(@agentnums) > 1 ) { + <TH CLASS="grid" BGCOLOR="#cccccc">Agent</TH> +% } + <TH CLASS="grid" BGCOLOR="#cccccc"><% $actual_label %>Unearned Revenue</TH> +% if ( $legacy ) { + <TH CLASS="grid" BGCOLOR="#cccccc">Legacy Unearned Revenue</TH> +% } </TR> +% my $bgcolor1 = '#eeeeee'; +% my $bgcolor2 = '#ffffff'; +% my $bgcolor; +% +% push @agentnums, 0 unless scalar(@agentnums) < 2; +% foreach my $agentnum (@agentnums) { +% +% if ( $bgcolor eq $bgcolor1 ) { +% $bgcolor = $bgcolor2; +% } else { +% $bgcolor = $bgcolor1; +% } +% +% my $alink = $agentnum ? "$link;agentnum=$agentnum" : $link; +% +% my $agent_name = 'Total'; +% if ( $agentnum ) { +% my $agent = qsearchs('agent', { 'agentnum' => $agentnum }) +% or die "unknown agentnum $agentnum"; +% $agent_name = $agent->agent; +% } + + <TR> + +% if ( scalar(@agentnums) > 1 ) { + <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $agent_name |h %></TD> +% } + + <TD ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>"><A HREF="<% $alink %>"><% $money_char %><% $total{$agentnum} %></A></TD> + +% if ( $legacy ) { + <TD ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>"> + <% $now == $time ? $money_char.$total_legacy{$agentnum} : '<i>N/A</i>'%> + </TD> +% } + + </TR> + +% } + </TABLE> + <BR> -Actual unearned revenue is the amount of unearned revenue Freeside has -actually invoiced for packages with longer-than monthly terms. -<BR><BR> -Legacy unearned revenue is the amount of unearned revenue represented by -customer packages. This number may be larger than actual unearned -revenue if you have imported longer-than monthly customer packages from -a previous billing system. -</BODY> -</HTML> +<% $actual_label %><% $actual_label ? 'u' : 'U' %>nearned revenue +is the amount of unearned revenue +<% $actual_label ? 'Freeside has actually' : '' %> +invoiced for packages with longer-than monthly terms. + +% if ( $legacy ) { + <BR><BR> + Legacy unearned revenue is the amount of unearned revenue represented by + customer packages. This number may be larger than actual unearned + revenue if you have imported longer-than monthly customer packages from + a previous billing system. +% } + +<% include('/elements/footer.html') %> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); -#doesn't yet deal with daily/weekly packages +my $conf = new FS::Conf; +my $money_char = $conf->config('money_char') || '$'; + +my $legacy = $conf->exists('enable_legacy_prepaid_income'); +my $actual_label = $legacy ? 'Actual ' : ''; -#needs to be re-written in sql for efficiency +#doesn't yet deal with daily/weekly packages my $time = time; @@ -38,74 +88,148 @@ my $now = $cgi->param('date') && str2time($cgi->param('date')) || $time; $now =~ /^(\d+)$/ or die "unparsable date?"; $now = $1; -my @where = (); +my $link = "cust_bill_pkg.cgi?nottax=1;unearned_now=$now"; -if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { - my $agentnum = $1; - push @where, "agentnum = $agentnum"; -} - -#here is the agent virtualization -push @where, $FS::CurrentUser::CurrentUser->agentnums_sql; - -my $where = join(' AND ', @where); -$where = "AND $where" if $where; - -my( $total, $total_legacy ) = ( 0, 0 ); - -my @cust_bill_pkg = - grep { $_->cust_pkg && $_->cust_pkg->part_pkg->freq !~ /^([01]|\d+[dw])$/ } - qsearch({ - 'select' => 'cust_bill_pkg.*', - 'table' => 'cust_bill_pkg', - 'addl_from' => ' LEFT JOIN cust_bill USING ( invnum ) '. - ' LEFT JOIN cust_main USING ( custnum ) ', - 'hashref' => { - 'recur' => { op=>'!=', value=>0 }, - 'edate' => { op=>'>', value=>$now }, - }, - 'extra_sql' => $where, - }); - -my @cust_pkg = - grep { $_->part_pkg->recur != 0 - && $_->part_pkg->freq !~ /^([01]|\d+[dw])$/ - } - qsearch({ - 'select' => 'cust_pkg.*', - 'table' => 'cust_pkg', - 'addl_from' => ' LEFT JOIN cust_main USING ( custnum ) ', - 'hashref' => { 'bill' => { op=>'>', value=>$now } }, - 'extra_sql' => $where, - }); - -foreach my $cust_bill_pkg ( @cust_bill_pkg) { - my $period = $cust_bill_pkg->edate - $cust_bill_pkg->sdate; - - my $elapsed = $now - $cust_bill_pkg->sdate; - $elapsed = 0 if $elapsed < 0; - - my $remaining = 1 - $elapsed/$period; - - my $unearned = $remaining * $cust_bill_pkg->recur; - $total += $unearned; +my $curuser = $FS::CurrentUser::CurrentUser; +my $agentnum = ''; +my @agentnums = (); +$agentnum ? ($agentnum) : $curuser->agentnums; +if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { + @agentnums = ($1); + #XXX#push @where, "agentnum = $agentnum"; + #XXX#$link .= ";agentnum=$agentnum"; +} else { + @agentnums = $curuser->agentnums; } -foreach my $cust_pkg ( @cust_pkg ) { - my $period = $cust_pkg->bill - $cust_pkg->last_bill; - - my $elapsed = $now - $cust_pkg->last_bill; - $elapsed = 0 if $elapsed < 0; - - my $remaining = 1 - $elapsed/$period; +my @where = (); - my $unearned = $remaining * $cust_pkg->part_pkg->recur; #!! only works for flat/legacy - $total_legacy += $unearned; +#here is the agent virtualization +push @where, $curuser->agentnums_sql( 'table'=>'cust_main' ); + +#well, because cust_bill_pkg.cgi has it and without it the numbers don't match.. +push @where , " payby != 'COMP' " + unless $cgi->param('include_comp_cust'); + +my %total = (); +my %total_legacy = (); +foreach my $agentnum (@agentnums) { + + my $where = join(' AND ', @where, "cust_main.agentnum = $agentnum"); + $where = "AND $where" if $where; + + my( $total, $total_legacy ) = ( 0, 0 ); + + # my @cust_bill_pkg = + # grep { $_->cust_pkg && $_->cust_pkg->part_pkg->freq !~ /^([01]|\d+[hdw])$/ } + # qsearch({ + # 'select' => 'cust_bill_pkg.*', + # 'table' => 'cust_bill_pkg', + # 'addl_from' => ' LEFT JOIN cust_bill USING ( invnum ) '. + # ' LEFT JOIN cust_main USING ( custnum ) ', + # 'hashref' => { + # 'recur' => { op=>'!=', value=>0 }, + # 'sdate' => { op=>'<', value=>$now }, + # 'edate' => { op=>'>', value=>$now }, + # }, + # 'extra_sql' => $where, + # }); + # + # foreach my $cust_bill_pkg ( @cust_bill_pkg) { + # my $period = $cust_bill_pkg->edate - $cust_bill_pkg->sdate; + # + # my $elapsed = $now - $cust_bill_pkg->sdate; + # $elapsed = 0 if $elapsed < 0; + # + # my $remaining = 1 - $elapsed/$period; + # + # my $unearned = $remaining * $cust_bill_pkg->recur; + # $total += $unearned; + # + # } + + #re-written in sql: + + #false laziness w/cust_bill_pkg.cgi + + my $float = 'REAL'; #'DOUBLE PRECISION'; + + my $period = "CAST(cust_bill_pkg.edate - cust_bill_pkg.sdate AS $float)"; + my $elapsed = "(CASE WHEN cust_bill_pkg.sdate > $now + THEN 0 + ELSE ($now - cust_bill_pkg.sdate) + END)"; + #my $elapsed = "CAST($unearned - cust_bill_pkg.sdate AS $float)"; + + my $remaining = "(1 - $elapsed/$period)"; + + my $select = "SUM($remaining * cust_bill_pkg.recur)"; + + #[...] + + my $sql = "SELECT $select FROM cust_bill_pkg + LEFT JOIN cust_pkg USING ( pkgnum ) + LEFT JOIN part_pkg USING ( pkgpart ) + LEFT JOIN cust_main USING ( custnum ) + WHERE pkgpart > 0 + AND sdate < $now + AND edate > $now + AND cust_bill_pkg.recur != 0 + AND part_pkg.freq != '0' + AND part_pkg.freq != '1' + AND part_pkg.freq NOT LIKE '%h' + AND part_pkg.freq NOT LIKE '%d' + AND part_pkg.freq NOT LIKE '%w' + $where + "; + + my $sth = dbh->prepare($sql) or die dbh->errstr; + $sth->execute or die $sth->errstr; + my $total = $sth->fetchrow_arrayref->[0]; + + $total = sprintf('%.2f', $total); + $total{$agentnum} = $total; + $total{0} += $total; + + if ( $legacy ) { + + #not yet rewritten in sql, but now not enabled by default + + my @cust_pkg = + grep { $_->part_pkg->recur != 0 + && $_->part_pkg->freq !~ /^([01]|\d+[dw])$/ + } + qsearch({ + 'select' => 'cust_pkg.*', + 'table' => 'cust_pkg', + 'addl_from' => ' LEFT JOIN cust_main USING ( custnum ) ', + 'hashref' => { 'bill' => { op=>'>', value=>$now } }, + 'extra_sql' => $where, + }); + + foreach my $cust_pkg ( @cust_pkg ) { + my $period = $cust_pkg->bill - $cust_pkg->last_bill; + + my $elapsed = $now - $cust_pkg->last_bill; + $elapsed = 0 if $elapsed < 0; + + my $remaining = 1 - $elapsed/$period; + + my $unearned = $remaining * $cust_pkg->part_pkg->recur; #!! only works for flat/legacy + $total_legacy += $unearned; + + } + + $total_legacy = sprintf('%.2f', $total_legacy); + $total_legacy{$agentnum} = $total_legacy; + $total_legacy{0} += $total_legacy; + + } } -$total = sprintf('%.2f', $total); -$total_legacy = sprintf('%.2f', $total_legacy); - +$total{0} = sprintf('%.2f', $total{0}); +$total_legacy{0} = sprintf('%.2f', $total_legacy{0}); + </%init> diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index 6e024132b..6eea2b09e 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -1,5 +1,5 @@ <% include('/elements/header.html', { - 'title' => "Customer View: ". $cust_main->name, + 'title' => "Customer: ". $cust_main->name, 'nobr' => 1, }) %> @@ -128,7 +128,7 @@ Comments 'actionlabel' => 'Enter customer note', 'cust_main' => $cust_main, 'width' => 616, - 'height' => 408, + 'height' => 538, #575 ) %> diff --git a/httemplate/view/cust_main/notes.html b/httemplate/view/cust_main/notes.html index 833c92e67..71511dc93 100755 --- a/httemplate/view/cust_main/notes.html +++ b/httemplate/view/cust_main/notes.html @@ -11,6 +11,9 @@ % } <TH CLASS="grid" BGCOLOR="#cccccc">Person</TH> <TH CLASS="grid" BGCOLOR="#cccccc">Note</TH> +% if ($curuser->access_right('Edit customer note') ) { + <TH CLASS="grid" BGCOLOR="#cccccc"> </TH> +% } </TR> % my $bgcolor1 = '#eeeeee'; @@ -34,7 +37,7 @@ % ";notenum=$notenum", % 'actionlabel' => 'Edit customer note', % 'width' => 616, -% 'height' => 408, +% 'height' => 538, #575 % 'frame' => 'top', % ); % my $clickjs = qq!onclick="$onclick"!; @@ -50,8 +53,11 @@ <% $note->otaker%> </TD> <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> - <%$note->comments%><% $edit %> + <%$note->comments%> </TD> +% if($edit) { + <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $edit %></TD> +% } </TR> % } #end display notes diff --git a/httemplate/view/cust_main/tickets.html b/httemplate/view/cust_main/tickets.html index 167849c76..e1f9a131e 100644 --- a/httemplate/view/cust_main/tickets.html +++ b/httemplate/view/cust_main/tickets.html @@ -1,7 +1,24 @@ +<FORM METHOD="GET" ACTION="<% $new_base %>" NAME="CreateTicketForm"> +<INPUT TYPE="submit" VALUE="Create new ticket"> +in queue +<SELECT NAME="Queue"> +% my %queues = FS::TicketSystem->queues(); +% foreach my $queueid ( keys %queues ) { +% #should consider whether the user has ACL to create ticket in each queue + <OPTION VALUE="<% $queueid %>" + <% $queueid == $new_param{'Queue'} ? 'SELECTED' : '' %> + ><% $queues{$queueid} |h %> +% } +</SELECT> +% foreach my $param ( grep { $_ ne 'Queue' } keys %new_param ) { + <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $new_param{$param} |h %>"> +% } +</FORM> +<BR> + (<A HREF="<% $open_link %>">View <% $openlabel %> tickets for this customer</A>) (<A HREF="<% $res_link %>">View resolved tickets for this customer</A>) -<BR> -(<A HREF="<% $new_link %>">Create new ticket for this customer</A>) +<BR><BR> <% include("/elements/table-grid.html") %> % my $bgcolor1 = '#eeeeee'; @@ -73,6 +90,10 @@ my $res_link = FS::TicketSystem->href_customer_tickets( { 'statuses' => [ 'resolved' ] } ); +my( $new_base, %new_param ) = FS::TicketSystem->href_params_new_ticket( + $cust_main, + join(', ', $cust_main->invoicing_list_emailonly ) ); + my $new_link = FS::TicketSystem->href_new_ticket( $cust_main, join(', ', $cust_main->invoicing_list_emailonly ) diff --git a/httemplate/view/svc_acct/tr.html b/httemplate/view/svc_acct/tr.html deleted file mode 100644 index e2ec7d42f..000000000 --- a/httemplate/view/svc_acct/tr.html +++ /dev/null @@ -1,9 +0,0 @@ -<TR> - <TD ALIGN="right"><% $opt{'label'} %></TD> - <TD BGCOLOR="#ffffff"><% $opt{'value'} %></TD> -</TR> -<%init> - -my %opt = @_; - -</%init> diff --git a/httemplate/view/svc_mailinglist.cgi b/httemplate/view/svc_mailinglist.cgi new file mode 100644 index 000000000..f646a417d --- /dev/null +++ b/httemplate/view/svc_mailinglist.cgi @@ -0,0 +1,71 @@ +<% include('elements/svc_Common.html', + 'table' => 'svc_mailinglist', + %opt, + ) +%> +<%init> + +my %opt = (); + +my $info = FS::svc_mailinglist->table_info; + +$opt{'name'} = $info->{'name'}; + +my $fields = $info->{'fields'}; +my %labels = map { $_ => ( ref($fields->{$_}) + ? $fields->{$_}{'label'} + : $fields->{$_} + ); + } + keys %$fields; + +#$opt{'fields'} = [ keys %$fields ]; +$opt{'fields'} = [ + 'username', + 'domain', + 'listname', + 'reply_to', + 'remove_from', + 'reject_auto', + 'remove_to_and_cc', +]; + +$opt{'labels'} = \%labels; + +$opt{'html_foot'} = sub { + my $svc_mailinglist = shift; + my $listnum = $svc_mailinglist->listnum; + + my $sql = 'SELECT COUNT(*) FROM mailinglistmember WHERE listnum = ?'; + my $sth = dbh->prepare($sql) or die dbh->errstr; + $sth->execute($listnum) or die $sth->errstr; + my $num = $sth->fetchrow_arrayref->[0]; + + my $add_url = $p."edit/mailinglistmember.html?listnum=$listnum"; + + my $add_link = include('/elements/init_overlib.html'). + include('/elements/popup_link.html', + 'action' => $add_url, + 'label' => 'add', + 'actionlabel' => 'Add list member', + 'width' => 392, + 'height' => 192, + ); + + ntable('#cccccc').'<TR><TD>'.ntable('#cccccc',2). qq[ + <TR> + <TD>List members</TD> + <TD BGCOLOR="#ffffff"> + $num members + ( <A HREF="${p}search/mailinglistmember.html?listnum=$listnum">view</A> + | $add_link ) + </TD> + </TR> + </TABLE></TD></TR></TABLE> + + <BR><BR> + ]. include('svc_export_settings.html', $svc_mailinglist); + +}; + +</%init> diff --git a/httemplate/view/svc_phone.cgi b/httemplate/view/svc_phone.cgi index 76ee7397d..75591c747 100644 --- a/httemplate/view/svc_phone.cgi +++ b/httemplate/view/svc_phone.cgi @@ -16,6 +16,7 @@ <%init> my $conf = new FS::Conf; +my $countrydefault = $conf->config('countrydefault') || 'US'; my @fields = qw( countrycode phonenum ); push @fields, 'domain' if $conf->exists('svc_phone-domain'); @@ -25,6 +26,25 @@ my $html_foot = sub { my $svc_phone = shift; ### + # E911 Info + ### + + my $e911 = + 'E911 Information'. + &ntable("#cccccc"). '<TR><TD>'. ntable("#cccccc",2). + '<TR><TD>Location</TD>'. + '<TD BGCOLOR="#FFFFFF">'. + $svc_phone->location_label( 'join_string' => '<BR>', + 'double_space' => ' ', + 'escape_function' => \&encode_entities, + 'countrydefault' => $countrydefault, + ). + '</TD></TR>'. + '</TABLE></TD></TR></TABLE>'. + '<BR>' + ; + + ### # Devices ### @@ -123,6 +143,7 @@ my $html_foot = sub { # concatenate & return ### + $e911. $devices. join(' | ', @links ). '<BR>'. join(' | ', @ilinks). '<BR>'; |