diff options
Diffstat (limited to 'httemplate')
45 files changed, 931 insertions, 327 deletions
diff --git a/httemplate/browse/access_user.html b/httemplate/browse/access_user.html index 321025b..3162e3a 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 23bc23f..3371926 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 04af73d..056c17c 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/man/FS/part_export/.cvs_is_on_crack b/httemplate/docs/man/FS/part_export/.cvs_is_on_crack deleted file mode 100644 index e69de29..0000000 --- a/httemplate/docs/man/FS/part_export/.cvs_is_on_crack +++ /dev/null diff --git a/httemplate/edit/access_user.html b/httemplate/edit/access_user.html index 73488ef..1f52b47 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 5d06f3c..1a06d94 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 3d6c486..d1d4368 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 6c6a1a9..e2501cb 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/mailinglistmember.html b/httemplate/edit/mailinglistmember.html new file mode 100644 index 0000000..2391cb6 --- /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_svc.cgi b/httemplate/edit/part_svc.cgi index 51925c0..98ed9fe 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/prepay_credit.cgi b/httemplate/edit/prepay_credit.cgi index f7a1b08..ed404b7 100644 --- a/httemplate/edit/prepay_credit.cgi +++ b/httemplate/edit/prepay_credit.cgi @@ -7,16 +7,13 @@ Generate <INPUT TYPE="text" NAME="num" VALUE="<% $cgi->param('num') || '(quantity)' |h %>" SIZE=10 MAXLENGTH=10 onFocus="if ( this.value == '(quantity)' ) { this.value = ''; }"> -prepaid cards of - -<INPUT TYPE="text" NAME="length" SIZE=3 MAXLENGTH=2 VALUE=8> <SELECT NAME="type"> % foreach (qw(alpha alphanumeric numeric)) { <OPTION<% $cgi->param('type') eq $_ ? ' SELECTED' : '' %>><% $_ %> % } </SELECT> -characters each +prepaid cards <BR>for <SELECT NAME="agentnum"><OPTION>(any agent) % foreach my $opt_agent ( qsearch('agent', { 'disabled' => '' } ) ) { diff --git a/httemplate/edit/process/mailinglistmember.html b/httemplate/edit/process/mailinglistmember.html new file mode 100644 index 0000000..f1842b8 --- /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 399991f..2b7e1da 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/prepay_credit.cgi b/httemplate/edit/process/prepay_credit.cgi index a55522b..8f2eb2b 100644 --- a/httemplate/edit/process/prepay_credit.cgi +++ b/httemplate/edit/process/prepay_credit.cgi @@ -56,7 +56,6 @@ $hashref->{totalbytes} = $cgi->param('totalbytes') * $cgi->param('totalmultiplie $error ||= FS::prepay_credit::generate( $num, scalar($cgi->param('type')), - $cgi->param('length'), $hashref ); diff --git a/httemplate/edit/process/rate_region.cgi b/httemplate/edit/process/rate_region.cgi index 882991e..8036f73 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 0000000..580f6cc --- /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/rate_detail.html b/httemplate/edit/rate_detail.html index dd8c3f6..869ace8 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 9ca3a35..f77c0db 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_acct.cgi b/httemplate/edit/svc_acct.cgi index 9c21c44..99e4b74 100755 --- a/httemplate/edit/svc_acct.cgi +++ b/httemplate/edit/svc_acct.cgi @@ -132,7 +132,7 @@ Service # <% $svcnum ? "<B>$svcnum</B>" : " (NEW)" %><BR> </TR> % } else { - <INPUT TYPE="hidden" NAME="cgp_aliases" VALUE="<% $svc_acct->cgp_aliases %>"> + <INPUT TYPE="text" NAME="cgp_aliases" VALUE="<% $svc_acct->cgp_aliases %>"> % } diff --git a/httemplate/edit/svc_domain.cgi b/httemplate/edit/svc_domain.cgi index c85dd3b..78faf12 100755 --- a/httemplate/edit/svc_domain.cgi +++ b/httemplate/edit/svc_domain.cgi @@ -63,7 +63,7 @@ Available top-level domains: <% $export->option('tlds') %> </TR> % } else { - <INPUT TYPE="hidden" NAME="cgp_aliases" VALUE="<% $svc_domain->cgp_aliases %>"> + <INPUT TYPE="text" NAME="cgp_aliases" VALUE="<% $svc_domain->cgp_aliases %>"> % } % if ( $part_svc->part_svc_column('max_accounts')->columnflag =~ /^[FA]$/ ) { diff --git a/httemplate/edit/svc_mailinglist.cgi b/httemplate/edit/svc_mailinglist.cgi new file mode 100644 index 0000000..c7c739d --- /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/elements/checkboxes-table.html b/httemplate/elements/checkboxes-table.html index a31bdb9..b6b04d1 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 22e872e..8da91ef 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/menu.html b/httemplate/elements/menu.html index d4a915e..a68a575 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 ef0d22c..23c4369 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 aa2d73b..453205c 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 af8d595..b62d6a0 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 0000000..9df91a1 --- /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/misc/cancel_pkg.html b/httemplate/misc/cancel_pkg.html index 10c0e0d..67d2847 100755 --- a/httemplate/misc/cancel_pkg.html +++ b/httemplate/misc/cancel_pkg.html @@ -58,7 +58,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 0000000..6b91de8 --- /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 9ea0d0d..0000000 --- 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 0d8417b..0000000 --- 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 87a6745..60b2aeb 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 b9e9daa..f800dbd 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 e73133c..442d83a 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 ceb7464..5116e54 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 9b0201c..2e79cd7 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/mailinglistmember.html b/httemplate/search/mailinglistmember.html new file mode 100644 index 0000000..ee395f4 --- /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 0000000..87237c7 --- /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_employee_commission.html b/httemplate/search/report_employee_commission.html new file mode 100644 index 0000000..a79630a --- /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_prepaid_income.cgi b/httemplate/search/report_prepaid_income.cgi index ce928b8..c0e2b80 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 6e02413..6eea2b0 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 833c92e..71511dc 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/svc_acct/tr.html b/httemplate/view/svc_acct/tr.html deleted file mode 100644 index e2ec7d4..0000000 --- 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 0000000..f646a41 --- /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> |