diff options
Diffstat (limited to 'httemplate')
110 files changed, 3347 insertions, 1151 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/part_pkg_taxclass.html b/httemplate/browse/part_pkg_taxclass.html index 04e0e23d6..fb70ee417 100644 --- a/httemplate/browse/part_pkg_taxclass.html +++ b/httemplate/browse/part_pkg_taxclass.html @@ -6,7 +6,7 @@ ], 'query' => { 'table' => 'part_pkg_taxclass', }, 'count_query' => 'SELECT COUNT(*) FROM part_pkg_taxclass', - 'header' => [ '#', 'Device type' ], + 'header' => [ '#', 'Tax class' ], 'fields' => [ 'taxclassnum', 'taxclass', ], 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/config/config-view.cgi b/httemplate/config/config-view.cgi index 13286cf21..08f6c1020 100644 --- a/httemplate/config/config-view.cgi +++ b/httemplate/config/config-view.cgi @@ -43,7 +43,10 @@ Click on a configuration value to change it. <TABLE BGCOLOR="#cccccc" BORDER=1 CELLSPACING=0 CELLPADDING=0 BORDERCOLOR="#999999"> <tr> <th colspan="2" bgcolor="#dcdcdc"> - <% ucfirst($section || 'unclassified') %> configuration options + <% ucfirst($section || 'unclassified') %> +% if ( $curuser->option('show_confitem_counts') ) { + (<% scalar( @{ $section_items{$section} } ) %> items) +% } </th> </tr> % foreach my $i (@{ $section_items{$section} }) { @@ -319,8 +322,9 @@ my %namecol = ( </%once> <%init> -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" unless $curuser->access_right('Configuration'); my $page_agent = ''; my $title; @@ -345,7 +349,7 @@ my @config_items = grep { $page_agent ? $_->per_agent : 1 } my @deleteable = qw( invoice_latexreturnaddress invoice_htmlreturnaddress ); my %deleteable = map { $_ => 1 } @deleteable; -my @sections = qw(required billing username password UI session shell BIND ); +my @sections = qw(required billing invoicing UI self-service username password session shell BIND ); push @sections, '', 'deprecated'; my %section_items = (); 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 c31213805..29c8ca63f 100755 --- a/httemplate/edit/REAL_cust_pkg.cgi +++ b/httemplate/edit/REAL_cust_pkg.cgi @@ -94,7 +94,7 @@ <SCRIPT TYPE="text/javascript"> Calendar.setup({ inputField: "<% $column %>_text", - ifFormat: "%m/%d/%Y", + ifFormat: "<% $date_format %>", button: "<% $column %>_button", align: "BR" }); @@ -128,21 +128,20 @@ </FORM> <% include('/elements/footer.html') %> +<%shared> -<%once> +my $conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; -#my $format = "%c %z (%Z)"; -my $format = "%m/%d/%Y %T %z (%Z)"; +my $format = $date_format. ' %T %z (%Z)'; -#false laziness w/view/cust_main/packages.html -#my( $billed_or_prepaid, - -</%once> +</%shared> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Edit customer package dates'); + 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_credit.cgi b/httemplate/edit/cust_credit.cgi index febf281f9..dc80847de 100755 --- a/httemplate/edit/cust_credit.cgi +++ b/httemplate/edit/cust_credit.cgi @@ -14,7 +14,7 @@ <TR> <TD ALIGN="right">Date</TD> - <TD BGCOLOR="#ffffff"><% time2str("%D",$_date) %></TD> + <TD BGCOLOR="#ffffff"><% time2str($date_format, $_date) %></TD> </TR> <TR> @@ -64,12 +64,10 @@ </FORM> </BODY> </HTML> -<%once> +<%init> my $conf = new FS::Conf; - -</%once> -<%init> +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Post credit'); diff --git a/httemplate/edit/cust_main/top_misc.html b/httemplate/edit/cust_main/top_misc.html index 041050664..d1d436851 100644 --- a/httemplate/edit/cust_main/top_misc.html +++ b/httemplate/edit/cust_main/top_misc.html @@ -43,6 +43,7 @@ %if ( $cust_main->referral_custnum % and $referring_cust_main = % qsearchs('cust_main', { custnum => $cust_main->referral_custnum } ) +% and ! $curuser->access_right('Edit referring customer') %) { <TR> @@ -52,8 +53,8 @@ </TD> </TR> <INPUT TYPE="hidden" NAME="referral_custnum" VALUE="<% $cust_main->referral_custnum %>"> -% } elsif ( ! $conf->exists('disable_customer_referrals') ) { +% } elsif ( ! $conf->exists('disable_customer_referrals') ) { <TR> <TD ALIGN="right">Referring customer</TD> @@ -61,13 +62,13 @@ <!-- <INPUT TYPE="text" NAME="referral_custnum" VALUE=""> --> <% include('/elements/search-cust_main.html', 'field_name' => 'referral_custnum', + 'curr_value' => $cust_main->referral_custnum, ) %> </TD> </TR> -% } else { - +% } else { <INPUT TYPE="hidden" NAME="referral_custnum" VALUE=""> % } @@ -77,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" ), }) %> % } @@ -92,6 +93,8 @@ my $custnum = $opt{'custnum'}; my $conf = new FS::Conf; +my $curuser = $FS::CurrentUser::CurrentUser; + my $r = qq!<font color="#ff0000">*</font> !; </%init> 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/cust_pay.cgi b/httemplate/edit/cust_pay.cgi index 07e51989e..a6b73b13a 100755 --- a/httemplate/edit/cust_pay.cgi +++ b/httemplate/edit/cust_pay.cgi @@ -26,7 +26,7 @@ Payment <TR> <TD ALIGN="right">Date</TD> <TD COLSPAN=2> - <INPUT TYPE="text" NAME="_date" ID="_date_text" VALUE="<% time2str("%m/%d/%Y %r",$_date) %>"> + <INPUT TYPE="text" NAME="_date" ID="_date_text" VALUE="<% time2str($date_format.' %r',$_date) %>"> <IMG SRC="../images/calendar.png" ID="_date_button" STYLE="cursor: pointer" TITLE="Select date"> </TD> </TR> @@ -34,7 +34,7 @@ Payment <SCRIPT TYPE="text/javascript"> Calendar.setup({ inputField: "_date_text", - ifFormat: "%m/%d/%Y", + ifFormat: "<% $date_format %>", button: "_date_button", align: "BR" }); @@ -100,7 +100,8 @@ Payment my $conf = new FS::Conf; -my $money_char = $conf->config('money_char') || '$'; +my $money_char = $conf->config('money_char') || '$'; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Post payment'); diff --git a/httemplate/edit/cust_refund.cgi b/httemplate/edit/cust_refund.cgi index 94c0993d7..59417b4c4 100755 --- a/httemplate/edit/cust_refund.cgi +++ b/httemplate/edit/cust_refund.cgi @@ -41,14 +41,14 @@ </TR> <TR> - <TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff"><% time2str("%D",$cust_pay->_date) %></TD> + <TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff"><% time2str($date_format, $cust_pay->_date) %></TD> </TR> <TR> <TD ALIGN="right">Method</TD><TD BGCOLOR="#ffffff"><% $payby %> # <% $paymask %></TD> </TR> -% unless ( $paydate ) { # possibly other reasons: i.e. card has since expired +% unless ( $paydate || $cust_pay->payby ne 'CARD' ) { # possibly other reasons: i.e. card has since expired <TR> <TD ALIGN="right">Expiration</TD><TD BGCOLOR="#ffffff"> <% include( '/elements/select-month_year.html', @@ -93,7 +93,7 @@ <TR> <TD ALIGN="right">Date</TD> - <TD BGCOLOR="#ffffff"><% time2str("%D",$_date) %></TD> + <TD BGCOLOR="#ffffff"><% time2str($date_format, $_date) %></TD> </TR> <TR> @@ -134,6 +134,8 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Refund payment'); my $conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; + my $custnum = $cgi->param('custnum'); my $refund = $cgi->param('refund'); my $payby = $cgi->param('payby'); diff --git a/httemplate/edit/elements/ApplicationCommon.html b/httemplate/edit/elements/ApplicationCommon.html index a485d37de..1fc8a09a9 100644 --- a/httemplate/edit/elements/ApplicationCommon.html +++ b/httemplate/edit/elements/ApplicationCommon.html @@ -52,7 +52,7 @@ Examples: <TR> <TD ALIGN="right">Date: </TD> - <TD><B><% time2str("%D", $src->_date) %></B></TD> + <TD><B><% time2str($date_format, $src->_date) %></B></TD> </TR> <TR> @@ -107,7 +107,7 @@ Apply to: <OPTION VALUE="">Select <% $dst_thing %> % foreach my $dst ( @dst ) { - <OPTION<% $dst->$dst_pkey eq $dst_pkeyvalue ? ' SELECTED' : '' %> VALUE="<% $dst->$dst_pkey %>">#<% $dst->$dst_pkey %> - <% time2str("%D", $dst->_date) %> - $<% $dst->$dst_unapplied %> + <OPTION<% $dst->$dst_pkey eq $dst_pkeyvalue ? ' SELECTED' : '' %> VALUE="<% $dst->$dst_pkey %>">#<% $dst->$dst_pkey %> - <% time2str($date_format, $dst->_date) %> - $<% $dst->$dst_unapplied %> % } </SELECT> @@ -133,7 +133,8 @@ Apply to: my %opt = @_; my $conf = new FS::Conf; -my $money_char = $conf->config('money_char') || '$'; +my $money_char = $conf->config('money_char') || '$'; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; my $src_thing = ucfirst($opt{'src_thing'}); my $src_table = $opt{'src_table'}; diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index fd73e031e..1a1023cbd 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -40,8 +40,10 @@ Example: 'disabled' => 0, 'onchange' => 'javascript_function', - #m2 stuff only tested w/selectlayers so far - #might work w/select too, dunno others + 'include_opt_callback' => sub { my $object = @_; + ( 'option' => 'value', ); + }, + 'm2name_table' => 'table_name', 'm2name_namecol' => 'name_column', #OR# @@ -276,9 +278,13 @@ Example: % $include_common{$_} = $f->{$_} % foreach grep exists($f->{$_}), qw( empty_label ); % +% #select-table +% $include_common{$_} = $f->{$_} +% foreach grep exists($f->{$_}), qw( value_col extra_sql ); +% % #select-table, checkboxes-table % $include_common{$_} = $f->{$_} -% foreach grep exists($f->{$_}), qw( table name_col ); +% foreach grep exists($f->{$_}), qw( table name_col ); % % #checkboxes-table % $include_common{$_} = $f->{$_} @@ -290,9 +296,17 @@ 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} }( $object ) +% ); +% } +% % my $layer_prefix_on = ''; % % my $include_sub = sub { diff --git a/httemplate/edit/elements/svc_Common.html b/httemplate/edit/elements/svc_Common.html index ef04bd04a..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,12 +50,20 @@ #$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; }, 'field_callback' => sub { my ($cgi, $object, $f) = @_; + my $columndef = $part_svc->part_svc_column($f->{'field'}); my $flag = $columndef->columnflag; if ( $flag eq 'F' ) { @@ -61,7 +71,41 @@ ? 'fixed' : 'hidden'; $f->{'value'} = $columndef->columnvalue; + } elsif ( $flag eq 'A' ) { + $f->{'type'} = 'hidden'; + } elsif ( $flag eq 'M' ) { + $f->{'empty_label'} = 'Select inventory item'; + $f->{'type'} = 'select-table'; + $f->{'table'} = 'inventory_item'; + $f->{'name_col'} = 'item'; + $f->{'value_col'} = 'item'; + $f->{'hashref'} = { + 'classnum'=>$columndef->columnvalue, + #'svcnum' => '', + }; + $f->{'extra_sql'} = 'AND ( svcnum IS NULL '; + $f->{'extra_sql'} .= ' OR svcnum = '. $object->svcnum + if $object->svcnum; + $f->{'extra_sql'} .= ' ) '; + $f->{'disable_empty'} = $object->svcnum ? 1 : 0, + } + + if ( $f->{'type'} eq 'select-svc_pbx' + || $f->{'type'} eq 'select-svc-domain' + ) + { + $f->{'include_opt_callback'} = + sub { ( 'pkgnum' => $pkgnum, + 'svcpart' => $svcpart, + ); + }; + } + + if ( $f->{'field'} eq 'custnum' && $pkgnum ) { + my $cust_pkg = qsearchs('cust_pkg', {'pkgnum' => $pkgnum}); + $object->set('custnum', $cust_pkg->custnum); } + }, 'html_init' => sub { @@ -111,12 +155,33 @@ 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'}; + + my $fields = "FS::$svcdb"->table_info->{'fields'}; + $opt->{'fields'} ||= [ grep { $_ ne 'svcnum' } keys %$fields ]; + + $opt->{labels} ||= { + map { $_ => ( ref($fields->{$_}) + ? $fields->{$_}{'label'} + : $fields->{$_} + ); + } + keys %$fields + }; + } + #false laziness w/view/svc_Common.html #override default labels with service-definition labels if applicable my $labels = $opt->{labels}; # with -> here - foreach my $field ( keys %$labels ) { + 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_device.html b/httemplate/edit/part_device.html index 4f2fe93b4..146070fd9 100644 --- a/httemplate/edit/part_device.html +++ b/httemplate/edit/part_device.html @@ -6,6 +6,7 @@ 'devicename' => 'Device name', }, 'viewall_dir' => 'browse', + 'html_bottom' => $html_bottom_sub, ) %> <%init> @@ -13,4 +14,32 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); +my $extra_sql = + join( ' OR ', map { "exporttype = '$_'" } + keys %{FS::part_export::export_info('part_device')} + ); +$extra_sql = $extra_sql ? " WHERE ( $extra_sql ) " : " WHERE 0 = 1 "; + +my $html_bottom_sub = sub { + my $part_device = shift; + + '<BR>'. + '<FONT SIZE="+1">Exports</FONT><BR>'. + + '<TABLE BGCOLOR="#cccccc" WIDTH=100%>'. + '<TR><TD>'. + include( '/elements/checkboxes-table.html', + 'source_obj' => $part_device, + 'link_table' => 'export_device', + 'target_table' => 'part_export', + 'extra_sql' => $extra_sql, + 'name_callback' => sub { my $o = shift; + $o->exporttype. ' to '. $o->machine; + }, + ). + '</TD></TR></TABLE>'; + +}; + </%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 79703435c..98ed9fec1 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -15,10 +15,12 @@ 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 + <LI>svc_pbx - Customer PBXs <LI>svc_external - Externally-tracked service <!-- <LI>svc_charge - One-time charges (Partially unimplemented) <LI>svc_wo - Work orders (Partially unimplemented) @@ -64,10 +66,9 @@ that field. % 'condition' => % sub { !ref($_[0]) || $_[0]->{disable_select} }, % }, -%# need to template-ize httemplate/edit/svc_* first -%# 'M' => { 'desc' => 'Manual selection from inventory', -%# 'condition' => $inv_sub, -%# }, +% 'M' => { 'desc' => 'Manual selection from inventory', +% 'condition' => $inv_sub, +% }, % 'A' => { 'desc' => 'Automatically fill in from inventory', % 'condition' => $inv_sub, % }, @@ -184,6 +185,9 @@ that field. % % foreach my $f ( keys %flag ) { % +% # need to template-ize more httemplate/edit/svc_* first +% next if $f eq 'M' and $layer !~ /^svc_(broadband|external|phone)$/; +% % #here is where the SUB from above is called, to skip some choices % next if $flag{$f}->{condition} % && &{ $flag{$f}->{condition} }( $def, $layer, $field ); @@ -265,6 +269,14 @@ that field. % 'empty_label' => 'Select inventory class', % ); % +% } elsif ( $def->{type} eq 'checkbox' ) { +% +% $html .= include('/elements/checkbox.html', +% 'field' => $layer.'__'.$field, +% 'curr_value' => $value, +% 'value' => 'Y', +% ); +% % } elsif ( $def->{type} eq 'select' ) { % % $html .= qq!<SELECT NAME="${layer}__${field}" $disabled!; @@ -288,6 +300,15 @@ that field. % } #endif % $html .= '</SELECT>'; % +% } elsif ( $def->{type} eq 'select-svc_pbx.html' ) { +% +% $html .= include('/elements/select-svc_pbx.html', +% 'curr_value' => $value, +% 'element_name' => "${layer}__${field}", +% 'element_etc' => $disabled, +% 'multiple' => ($flag eq 'S'), +% ); +% % } elsif ( $def->{type} eq 'radius_usergroup_selector' ) { % % #XXX disable the RADIUS usergroup selector? ugh it sure does need @@ -296,6 +317,14 @@ that field. % $html .= FS::svc_acct::radius_usergroup_selector( % [ split(',', $value) ], "${layer}__${field}" ); % +% } elsif ( $def->{type} eq 'communigate_pro-accessmodes' ) { +% +% $html .= include('/elements/communigate_pro-accessmodes.html', +% 'element_name_prefix' => "${layer}__${field}_", +% 'curr_value' => $value, +% #doesn't work#'element_etc' => $disabled, +% ); +% % } elsif ( $def->{type} eq 'disabled' ) { % % $html .= @@ -303,7 +332,7 @@ that field. % % } else { % -% $html .= '<font color="#ff0000">unknown type'. $def->{type}; +% $html .= '<font color="#ff0000">unknown type '. $def->{type}; % % } % 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/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_acct.cgi b/httemplate/edit/process/svc_acct.cgi index 515d89e91..0d2c007f1 100755 --- a/httemplate/edit/process/svc_acct.cgi +++ b/httemplate/edit/process/svc_acct.cgi @@ -11,7 +11,6 @@ die "access denied" $cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; my $svcnum = $1; -my $error; my $old; if ( $svcnum ) { @@ -32,6 +31,18 @@ foreach (map { $_,$_."_threshold" } qw( upbytes downbytes totalbytes )) { $cgi->param($_, FS::UI::bytecount::parse_bytecount($cgi->param($_)) ); } +#unmunge cgp_accessmodes (falze laziness-ish w/part_svc.pm::process &svc_domain) +unless ( $cgi->param('cgp_accessmodes') ) { + $cgi->param('cgp_accessmodes', + join(' ', + sort map { /^cgp_accessmodes_([\w\/]+)$/ or die "no way"; $1; } + grep $cgi->param($_), + grep /^cgp_accessmodes_([\w\/]+)$/, + $cgi->param() + ) + ); +} + my %hash = $svcnum ? $old->hash : (); map { $hash{$_} = scalar($cgi->param($_)); @@ -40,27 +51,31 @@ map { } (fields('svc_acct'), qw ( pkgnum svcpart usergroup )); my $new = new FS::svc_acct ( \%hash ); +my $error = ''; + $new->_password($old->_password) if $old; -if( $cgi->param('clear_password') eq '*HIDDEN*' - or $cgi->param('clear_password') =~ /^\(.* encrypted\)$/ ) { +if ( $cgi->param('clear_password') eq '*HIDDEN*' + || $cgi->param('clear_password') =~ /^\(.* encrypted\)$/ ) { die "fatal: no previous account to recall hidden password from!" unless $old; -} -else { +} else { $error = $new->set_password($cgi->param('clear_password')); } if ( $svcnum ) { - foreach (grep { $old->$_ != $new->$_ } qw( seconds upbytes downbytes totalbytes )) { + foreach ( grep { $old->$_ != $new->$_ } + qw( seconds upbytes downbytes totalbytes ) + ) + { my %hash = map { $_ => $new->$_ } grep { $new->$_ } qw( seconds upbytes downbytes totalbytes ); - $error = $new->set_usage(\%hash); #unoverlimit and trigger radius changes - last; #once is enough + $error ||= $new->set_usage(\%hash); #unoverlimit and trigger radius changes + last; #once is enough } $error ||= $new->replace($old); } else { - $error = $new->insert; + $error ||= $new->insert; $svcnum = $new->svcnum; } diff --git a/httemplate/edit/process/svc_domain.cgi b/httemplate/edit/process/svc_domain.cgi index 59b518097..381339bc8 100755 --- a/httemplate/edit/process/svc_domain.cgi +++ b/httemplate/edit/process/svc_domain.cgi @@ -15,6 +15,30 @@ $FS::svc_domain::whois_hack = 1; $cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; my $svcnum = $1; +#unmunge cgp_accessmodes (falze laziness-ish w/part_svc.pm::process & svc_acct) +unless ( $cgi->param('cgp_accessmodes') ) { + $cgi->param('cgp_accessmodes', + join(' ', + sort map { /^cgp_accessmodes_([\w\/]+)$/ or die "no way"; $1; } + grep $cgi->param($_), + grep /^cgp_accessmodes_([\w\/]+)$/, + $cgi->param() + ) + ); +} + +#unmunge acct_def_cgp_accessmodes (falze laziness-ahoy) +unless ( $cgi->param('acct_def_cgp_accessmodes') ) { + $cgi->param('acct_def_cgp_accessmodes', + join(' ', + sort map { /^acct_def_cgp_accessmodes_([\w\/]+)$/ or die "no way"; $1; } + grep $cgi->param($_), + grep /^acct_def_cgp_accessmodes_([\w\/]+)$/, + $cgi->param() + ) + ); +} + my $new = new FS::svc_domain ( { map { $_, scalar($cgi->param($_)); @@ -24,10 +48,10 @@ my $new = new FS::svc_domain ( { my $error = ''; if ($cgi->param('svcnum')) { - $error="Can't modify a domain!"; + $error = $new->replace(); } else { - $error=$new->insert; - $svcnum=$new->svcnum; + $error = $new->insert; + $svcnum = $new->svcnum; } </%init> diff --git a/httemplate/edit/process/svc_external.html b/httemplate/edit/process/svc_external.html new file mode 100644 index 000000000..3515afc4b --- /dev/null +++ b/httemplate/edit/process/svc_external.html @@ -0,0 +1,10 @@ +<% include( 'elements/svc_Common.html', + 'table' => 'svc_external', + ) +%> +<%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_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/quick-charge.html b/httemplate/edit/quick-charge.html index c96fa6c81..64ad3a289 100644 --- a/httemplate/edit/quick-charge.html +++ b/httemplate/edit/quick-charge.html @@ -147,7 +147,7 @@ function bill_now_changed (what) { <SCRIPT TYPE="text/javascript"> Calendar.setup({ inputField: "start_date_text", - ifFormat: "%m/%d/%Y", + ifFormat: "<% $date_format %>", button: "start_date_button", align: "BR" }); @@ -250,6 +250,7 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('One-time charge'); my $conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; $cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum'; my $custnum = $1; 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_Common.html b/httemplate/edit/svc_Common.html index 6666d9720..3da72d2e8 100644 --- a/httemplate/edit/svc_Common.html +++ b/httemplate/edit/svc_Common.html @@ -1,7 +1,7 @@ <% include('elements/svc_Common.html', 'table' => $table, 'post_url' => popurl(1). "process/svc_Common.html", - %opt, + %opt, ) %> <%init> diff --git a/httemplate/edit/svc_acct.cgi b/httemplate/edit/svc_acct.cgi index afbd002c1..99e4b74a4 100755 --- a/httemplate/edit/svc_acct.cgi +++ b/httemplate/edit/svc_acct.cgi @@ -54,7 +54,7 @@ Service # <% $svcnum ? "<B>$svcnum</B>" : " (NEW)" %><BR> %}else{ <INPUT TYPE="hidden" NAME="clear_password" VALUE="<% $password %>"> %} -<INPUT TYPE="hidden" NAME="_password_encoding" VALUE="<% $password_encoding %>"> +<INPUT TYPE="hidden" NAME="_password_encoding" VALUE="<% $svc_acct->_password_encoding %>"> % %my $sec_phrase = $svc_acct->sec_phrase; %if ( $conf->exists('security_phrase') @@ -122,7 +122,27 @@ Service # <% $svcnum ? "<B>$svcnum</B>" : " (NEW)" %><BR> </TD> </TR> % } -% + + +% if ( $communigate ) { + + <TR> + <TD ALIGN="right">Aliases</TD> + <TD><INPUT TYPE="text" NAME="cgp_aliases" VALUE="<% $svc_acct->cgp_aliases %>"></TD> + </TR> + +% } else { + <INPUT TYPE="text" NAME="cgp_aliases" VALUE="<% $svc_acct->cgp_aliases %>"> +% } + + +<% include('/elements/tr-select-svc_pbx.html', + 'curr_value' => $svc_acct->pbxsvc, + 'part_svc' => $part_svc, + 'cust_pkg' => $cust_pkg, + ) +%> + %#pop %my $popnum = $svc_acct->popnum || 0; %if ( $part_svc->part_svc_column('popnum')->columnflag eq 'F' ) { @@ -234,31 +254,119 @@ Service # <% $svcnum ? "<B>$svcnum</B>" : " (NEW)" %><BR> </TD> </TR> % } -% if ( $part_svc->part_svc_column('quota')->columnflag eq 'F' ) { +% if ( $communigate +% && $part_svc->part_svc_column('cgp_type')->columnflag ne 'F' ) +% { + + <TR> + <TD ALIGN="right">Mailbox type</TD> + <TD> + <SELECT NAME="cgp_type"> +% foreach my $option (qw( MultiMailbox TextMailbox MailDirMailbox +% AGrade BGrade CGrade )) { + <OPTION VALUE="<% $option %>" + <% $option eq $svc_acct->cgp_type() ? 'SELECTED' : '' %> + ><% $option %> +% } + </SELECT> + </TD> + </TR> + +% } else { + <INPUT TYPE="hidden" NAME="cgp_type" VALUE="<% $svc_acct->cgp_type() %>"> +% } + + +% #false laziness w/svc_domain +% if ( $communigate +% && $part_svc->part_svc_column('cgp_accessmodes')->columnflag ne 'F' ) +% { + + <TR> + <TD ALIGN="right">Enabled services</TD> + <TD> + <% include( '/elements/communigate_pro-accessmodes.html', + 'curr_value' => $svc_acct->cgp_accessmodes, + ) + %> + </TD> + </TR> + +% } else { + <INPUT TYPE="hidden" NAME="cgp_accessmodes" VALUE="<% $svc_acct->cgp_accessmodes() |h %>"> +% } + + +% if ( $part_svc->part_svc_column('quota')->columnflag eq 'F' ) { <INPUT TYPE="hidden" NAME="quota" VALUE="<% $svc_acct->quota %>"> -% } else { +% } else { +% my $quota_label = $communigate ? 'Mail storage limit' : 'Quota'; + <TR> + <TD ALIGN="right"><% $quota_label %></TD> + <TD><INPUT TYPE="text" NAME="quota" VALUE="<% $svc_acct->quota %>"></TD> + </TR> +% } + +% tie my %cgp_label, 'Tie::IxHash', +% 'file_quota' => 'File storage limit', +% 'file_maxnum' => 'Number of files limit', +% 'file_maxsize' => 'File size limit', +% ; +% +% foreach my $key (keys %cgp_label) { +% +% if ( !$communigate || $part_svc->part_svc_column($key)->columnflag eq 'F' ){ + <INPUT TYPE="hidden" NAME="<%$key%>" VALUE="<% $svc_acct->$key() |h %>"> +% } else { + + <TR> + <TD ALIGN="right"><% $cgp_label{$key} %></TD> + <TD><INPUT TYPE="text" NAME="<% $key %>" VALUE="<% $svc_acct->$key() |h %>"></TD> + </TR> + +% } +% } +% if ( $communigate ) { +%# false laziness w/svc_domain acct_def <TR> - <TD ALIGN="right">Quota:</TD> - <TD><INPUT TYPE="text" NAME="quota" VALUE="<% $svc_acct->quota %>"></TD> + <TD ALIGN="right">Message delete method</TD> + <TD> + <SELECT NAME="cgp_deletemode"> +% for ( 'Move To Trash', 'Immediately', 'Mark' ) { + <OPTION VALUE="<% $_ %>" + <% $_ eq $svc_acct->cgp_deletemode ? 'SELECTED' : '' %> + ><% $_ %> +% } + </SELECT> + </TD> + </TR> + + <TR> + <TD ALIGN="right">On logout remove trash</TD> + <TD><INPUT TYPE="text" NAME="cgp_emptytrash" VALUE="<% $svc_acct->cgp_emptytrash %>"></TD> </TR> -% } -% if ( $part_svc->part_svc_column('slipip')->columnflag =~ /^[FA]$/ ) { +% } else { - <INPUT TYPE="hidden" NAME="slipip" VALUE="<% $svc_acct->slipip %>"> -% } else { + <INPUT TYPE="hidden" NAME="cgp_deletemode" VALUE="<% $svc_acct->cgp_deletemode %>"> + <INPUT TYPE="hidden" NAME="cgp_emptytrash" VALUE="<% $svc_acct->cgp_emptytrash %>"> + +% } +% if ( $part_svc->part_svc_column('slipip')->columnflag =~ /^[FA]$/ ) { + <INPUT TYPE="hidden" NAME="slipip" VALUE="<% $svc_acct->slipip %>"> +% } else { <TR> <TD ALIGN="right">IP</TD> <TD><INPUT TYPE="text" NAME="slipip" VALUE="<% $svc_acct->slipip %>"></TD> </TR> % } -% + % my %label = ( seconds => 'Time', % upbytes => 'Upload bytes', % downbytes => 'Download bytes', @@ -392,6 +500,9 @@ if ( $cgi->param('error') ) { } +my $communigate = scalar($part_svc->part_export('communigate_pro')); + # || scalar($part_svc->part_export('communigate_pro_singledomain')); + my( $cust_pkg, $cust_main ) = ( '', '' ); if ( $pkgnum ) { $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $pkgnum } ); @@ -440,22 +551,17 @@ my $svc = $part_svc->getfield('svc'); my $otaker = getotaker; my $username = $svc_acct->username; -my $password; -my $password_encryption = $svc_acct->_password_encryption; -my $password_encoding = $svc_acct->_password_encoding; - -if($svcnum) { - if($password = $svc_acct->get_cleartext_password) { - if (! $conf->exists('showpasswords')) { - $password = '*HIDDEN*'; - } - } - elsif($svc_acct->_password and $password_encryption ne 'plain') { + +my $password = ''; +if ( $cgi->param('error') ) { + $password = $cgi->param('clear_password'); +} elsif ( $svcnum ) { + my $password_encryption = $svc_acct->_password_encryption; + if ( $password = $svc_acct->get_cleartext_password ) { + $password = '*HIDDEN*' unless $conf->exists('showpasswords'); + } elsif( $svc_acct->_password and $password_encryption ne 'plain' ) { $password = "(".uc($password_encryption)." encrypted)"; } - else { - $password = ''; - } } my $ulen = 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_domain.cgi b/httemplate/edit/svc_domain.cgi index 10079ce98..78faf12b2 100755 --- a/httemplate/edit/svc_domain.cgi +++ b/httemplate/edit/svc_domain.cgi @@ -8,10 +8,18 @@ <INPUT TYPE="hidden" NAME="svcpart" VALUE="<% $svcpart %>"> <% ntable("#cccccc",2) %> + <TR> -<P>Domain <INPUT TYPE="text" NAME="domain" VALUE="<% $domain %>" SIZE=28 MAXLENGTH=63> -<BR> + <TD ALIGN="right">Domain</TD> + <TD> +% if ( !$svcnum || $conf->exists('svc_domain-edit_domain') ) { + <INPUT TYPE="text" NAME="domain" VALUE="<% $domain %>" SIZE=28 MAXLENGTH=63> +% } else { + <B><% $domain %></B> +% } + % if ($export) { +<BR> Available top-level domains: <% $export->option('tlds') %> </TR> @@ -27,11 +35,161 @@ Available top-level domains: <% $export->option('tlds') %> </TR> % } - -<TR> -<P><INPUT TYPE="submit" VALUE="Submit"> + </TD> </TR> + +% if ( $communigate ) { + <TR> + <TD ALIGN="right">Administrator domain</TD> + <TD> + <% include('/elements/select-domain.html', + 'element_name' => 'parent_svcnum', + 'curr_value' => $svc_domain->parent_svcnum, + 'empty_label' => '(none)', + ) + %> + </TD> + </TR> +% } else { + <INPUT TYPE="hidden" NAME="parent_svcnum" VALUE="<% $svc_domain->parent_svcnum %>"> +% } + +% if ( $communigate +% && $part_svc->part_svc_column('max_accounts')->columnflag !~ /^[FA]$/ ) { + + <TR> + <TD ALIGN="right">Aliases</TD> + <TD><INPUT TYPE="text" NAME="cgp_aliases" VALUE="<% $svc_domain->cgp_aliases %>"></TD> + </TR> + +% } else { + <INPUT TYPE="text" NAME="cgp_aliases" VALUE="<% $svc_domain->cgp_aliases %>"> +% } + +% if ( $part_svc->part_svc_column('max_accounts')->columnflag =~ /^[FA]$/ ) { + <INPUT TYPE="hidden" NAME="max_accounts" VALUE="<% $svc_domain->max_accounts %>"> +% } else { + <TR> + <TD ALIGN="right">Maximum number of accounts</TD> + <TD> + <INPUT TYPE="text" NAME="max_accounts" SIZE=5 MAXLENGTH=6 VALUE="<% $svc_domain->max_accounts %>"> + </TD> + </TR> +% } + +% if ( $communigate +% && $part_svc->part_svc_column('cgp_accessmodes')->columnflag ne 'F' ) +% { + + <TR> + <TD ALIGN="right">Enabled services</TD> + <TD> + <% include( '/elements/communigate_pro-accessmodes.html', + 'curr_value' => $svc_domain->cgp_accessmodes, + ) + %> + </TD> + </TR> + +% } else { + <INPUT TYPE="hidden" NAME="cgp_accessmodes" VALUE="<% $svc_domain->cgp_accessmodes() |h %>"> +% } + </TABLE> +<BR> + +% if ( $communigate ) { + +Account defaults +<% ntable("#cccccc",2) %> + + <% include('/elements/tr-checkbox.html', + 'label' =>'Password modification', + 'field' => 'acct_def_password_selfchange', + 'curr_value' => $svc_domain->acct_def_password_selfchange, + 'value' => 'Y', + ) + %> + <% include('/elements/tr-checkbox.html', + 'label' =>'Password recovery', + 'field' => 'acct_def_password_recover', + 'curr_value' => $svc_domain->acct_def_password_recover, + 'value' => 'Y', + ) + %> + + <TR> + <TD ALIGN="right">Enabled services + </TD> + <TD><% include('/elements/communigate_pro-accessmodes.html', + 'element_name_prefix' => 'acct_def_cgp_accessmodes_', + 'curr_value' => $svc_domain->acct_def_cgp_accessmodes, + ) + %> + </TD> + </TR> + + <% include('/elements/tr-input-text.html', + 'label' => 'Mail storage limit', + 'field' => 'acct_def_quota', + 'curr_value' => $svc_domain->acct_def_quota, + ) + %> + <% include('/elements/tr-input-text.html', + 'label' => 'File storage limit', + 'field' => 'acct_def_file_quota', + 'curr_value' => $svc_domain->acct_def_file_quota, + ) + %> + <% include('/elements/tr-input-text.html', + 'label' => 'Files limit', + 'field' => 'acct_def_file_maxnum', + 'curr_value' => $svc_domain->acct_def_file_maxnum, + ) + %> + <% include('/elements/tr-input-text.html', + 'label' => 'File size limit', + 'field' => 'acct_def_file_maxsize', + 'curr_value' => $svc_domain->acct_def_file_maxsize, + ) + %> + +%# false laziness w/svc_acct acct_def + <TR> + <TD ALIGN="right">Message delete method</TD> + <TD> + <SELECT NAME="acct_def_cgp_deletemode"> +% for ( 'Move To Trash', 'Immediately', 'Mark' ) { + <OPTION VALUE="<% $_ %>" + <% $_ eq $svc_domain->acct_def_cgp_deletemode ? 'SELECTED' : '' %> + ><% $_ %> +% } + </SELECT> + </TD> + </TR> + + <% include('/elements/tr-input-text.html', + 'label' => 'On logout remove trash', + 'curr_value' => $svc_domain->acct_def_cgp_emptytrash, + ) + %> + +</TABLE> +<BR> + +% } else { + +% foreach my $f (qw( password_selfchange password_recover cgp_accessmodes +% quota file_quota file_maxnum file_maxsize +% cgp_deletemode cgp_emptytrash +% )) { + <INPUT TYPE="hidden" NAME="acct_def_<%$f%>" VALUE="<% $svc_domain->get("acct_def_$f") %>"> +% } + +% } + +<INPUT TYPE="submit" VALUE="Submit"> + </FORM> <% include('/elements/footer.html') %> @@ -41,6 +199,8 @@ Available top-level domains: <% $export->option('tlds') %> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? +my $conf = new FS::Conf; + my($svcnum, $pkgnum, $svcpart, $kludge_action, $part_svc, $svc_domain); if ( $cgi->param('error') ) { @@ -94,19 +254,14 @@ my $action = $svcnum ? 'Edit' : 'Add'; my $svc = $part_svc->getfield('svc'); -my @exports = $part_svc->part_export(); - -my $registrar; -my $export; +my $communigate = scalar($part_svc->part_export('communigate_pro')); + # || scalar($part_svc->part_export('communigate_pro_singledomain')); # Find the first export that does domain registration -foreach (@exports) { - $export = $_ if $_->can('registrar'); -} +my @exports = grep $_->can('registrar'), $part_svc->part_export; +my $export = $exports[0]; # If we have a domain registration export, get the registrar object -if ($export) { - $registrar = $export->registrar; -} +my $registrar = $export ? $export->registrar : ''; my $otaker = getotaker; diff --git a/httemplate/edit/svc_external.cgi b/httemplate/edit/svc_external.cgi index 0df842b21..54aa11f42 100644 --- a/httemplate/edit/svc_external.cgi +++ b/httemplate/edit/svc_external.cgi @@ -1,102 +1 @@ -<% include('/elements/header.html', "External service $action") %> - -<% include('/elements/error.html') %> - -<FORM ACTION="<%$p1%>process/svc_external.cgi" METHOD=POST> - -<INPUT TYPE="hidden" NAME="svcnum" VALUE="<% $svcnum %>"> -Service #<B><% $svcnum ? $svcnum : "(NEW)" %></B> -<BR><BR> - -<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> - -<INPUT TYPE="hidden" NAME="svcpart" VALUE="<% $svcpart %>"> - -% my $id = $svc_external->id; -% my $title = $svc_external->title; -% -<% &ntable("#cccccc",2) %> - <TR> - <TD ALIGN="right">External ID</TD> - <TD><INPUT TYPE="text" NAME="id" VALUE="<% $id %>"></TD> - </TR> - <TR> - <TD ALIGN="right">Title</TD> - <TD><INPUT TYPE="text" NAME="title" VALUE="<% $title %>"></TD> - </TR> - -% foreach my $field ($svc_external->virtual_fields) { -% if ( $part_svc->part_svc_column($field)->columnflag ne 'F' ) { -% # If the flag is X, it won't even show up in $svc_acct->virtual_fields. - <% $svc_external->pvf($field)->widget( 'HTML', - 'edit', - $svc_external->getfield($field) - ) - %> -% } -% } - -</TABLE> -<BR> - -<INPUT TYPE="submit" VALUE="Submit"> -</FORM> - -<% include('/elements/footer.html') %> - -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? - -my( $svcnum, $pkgnum, $svcpart, $part_svc, $svc_external ); -if ( $cgi->param('error') ) { - - $svc_external = new FS::svc_external ( { - map { $_, scalar($cgi->param($_)) } fields('svc_external') - } ); - $svcnum = $svc_external->svcnum; - $pkgnum = $cgi->param('pkgnum'); - $svcpart = $cgi->param('svcpart'); - $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); - die "No part_svc entry!" unless $part_svc; - -} elsif ( $cgi->param('pkgnum') && $cgi->param('svcpart') ) { #adding - - $cgi->param('pkgnum') =~ /^(\d+)$/ or die 'unparsable pkgnum'; - $pkgnum = $1; - $cgi->param('svcpart') =~ /^(\d+)$/ or die 'unparsable svcpart'; - $svcpart = $1; - - $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); - die "No part_svc entry!" unless $part_svc; - - $svc_external = new FS::svc_external { svcpart => $svcpart }; - - $svcnum=''; - - $svc_external->set_default_and_fixed; - -} else { #adding - - my($query) = $cgi->keywords; - $query =~ /^(\d+)$/ or die "unparsable svcnum"; - $svcnum=$1; - $svc_external=qsearchs('svc_external',{'svcnum'=>$svcnum}) - or die "Unknown (svc_external) svcnum!"; - - my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum}) - or die "Unknown (cust_svc) svcnum!"; - - $pkgnum=$cust_svc->pkgnum; - $svcpart=$cust_svc->svcpart; - - $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); - die "No part_svc entry!" unless $part_svc; - -} -my $action = $svc_external->svcnum ? 'Edit' : 'Add'; - -my $p1 = popurl(1); - -</%init> +<% include( 'elements/svc_Common.html', 'table'=>'svc_external' ) %> diff --git a/httemplate/edit/svc_forward.cgi b/httemplate/edit/svc_forward.cgi index 96a00a5aa..73f6465b9 100755 --- a/httemplate/edit/svc_forward.cgi +++ b/httemplate/edit/svc_forward.cgi @@ -32,24 +32,35 @@ function dstchanged(what) { </SCRIPT> <% ntable("#cccccc",2) %> -<TR><TD ALIGN="right">Email to</TD> -<TD><SELECT NAME="srcsvc" SIZE=1 onChange="srcchanged(this)"> -% foreach $_ (keys %email) { - - <OPTION<% $_ eq $srcsvc ? " SELECTED" : "" %> VALUE="<% $_ %>"><% $email{$_} %></OPTION> -% } -% if ( $svc_forward->dbdef_table->column('src') ) { - - <OPTION <% $src ? 'SELECTED' : '' %> VALUE="0">(other email address)</OPTION> -% } -</SELECT> -% if ( $svc_forward->dbdef_table->column('src') ) { - -<INPUT TYPE="text" NAME="src" VALUE="<% $src %>" <% ( $src || !scalar(%email) ) ? '' : 'DISABLED STYLE="background-color: lightgrey"' %>> -% } - -</TD></TR> +<TR> + <TD ALIGN="right">Email to</TD> + <TD> +% if ( $conf->exists('svc_forward-no_srcsvc') ) { + <INPUT NAME="srcsrc" TYPE="hidden" VALUE="0"> +% } else { + <SELECT NAME="srcsvc" SIZE=1 onChange="srcchanged(this)"> +% foreach $_ (keys %email) { + <OPTION VALUE="<% $_ %>" + <% $_ eq $srcsvc ? 'SELECTED' : '' %> + ><% $email{$_} %></OPTION> +% } + <OPTION VALUE="0" <% $src ? 'SELECTED' : '' %> + >(other email address)</OPTION> + </SELECT> +% } + +% my $src_disabled = $src +% || $conf->exists('svc_forward-no_srcsvc') +% || !scalar(%email); + <INPUT NAME = "src" + TYPE = "text" + VALUE = "<% $src %>" + <% $src_disabled ? '' : 'DISABLED STYLE="background-color: lightgrey"' %> + > + + </TD> +</TR> <TR><TD ALIGN="right">Forwards to</TD> <TD><SELECT NAME="dstsvc" SIZE=1 onChange="dstchanged(this)"> 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 d7629ab6f..b77d96233 100644 --- a/httemplate/edit/svc_phone.cgi +++ b/httemplate/edit/svc_phone.cgi @@ -1,22 +1,21 @@ <% include( 'elements/svc_Common.html', - 'name' => 'Phone number', 'table' => 'svc_phone', - 'fields' => [ 'countrycode', - { field => 'phonenum', - type => 'select-did', - label => 'Phone number', - }, - 'sip_password', - 'pin', - 'phone_name', - ], + 'fields' => \@fields, 'labels' => { + 'svcnum' => 'Service', 'countrycode' => 'Country code', 'phonenum' => 'Phone number', + 'domsvc' => 'Domain', 'sip_password' => 'SIP password', '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> @@ -24,4 +23,55 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? +my $conf = new FS::Conf; + +my @fields = ( 'countrycode', + { field => 'phonenum', + type => 'select-did', + label => 'Phone number', + }, + ); + +push @fields, { field => 'domsvc', + type => 'select-svc-domain', + label => 'Domain', + } + if $conf->exists('svc_phone-domain'); + +push @fields, { field => 'pbxsvc', + type => 'select-svc_pbx', + label => 'PBX', + }, + 'sip_password', + 'pin', + { 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/communigate_pro-accessmodes.html b/httemplate/elements/communigate_pro-accessmodes.html new file mode 100644 index 000000000..6ce9ca587 --- /dev/null +++ b/httemplate/elements/communigate_pro-accessmodes.html @@ -0,0 +1,30 @@ +<% include( 'checkboxes.html', + 'element_name_prefix' => 'cgp_accessmodes_', + 'names_list' => \@names, + 'checked_callback' => $callback, + %opt, + ) +%> +<%once> + +my @names = (qw( + Mail Relay Signal Mobile TLS POP IMAP MAPI + AirSync SIP XMPP WebMail XIMSS FTP ACAP PWD + LDAP RADIUS S/MIME WebCAL WebSite PBX HTTP +)); + +</%once> +<%init> + +my %opt = @_; +my $curr_value = $opt{'curr_value'}; + +$curr_value = { map { $_=>1 } split(/\s+/, $curr_value) } + unless ref($curr_value); + +my $callback = sub { + my( $cgi, $name ) = @_; + $curr_value->{$name}; +}; + +</%init> 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/overlibmws.js b/httemplate/elements/overlibmws.js index df2bd1db7..6a446ab00 100644 --- a/httemplate/elements/overlibmws.js +++ b/httemplate/elements/overlibmws.js @@ -1,7 +1,7 @@ /*
Do not remove or change this notice.
- overlibmws.js core module - Copyright Foteos Macrides 2002-2008. All rights reserved.
- Initial: August 18, 2002 - Last Revised: March 22, 2008
+ overlibmws.js core module - Copyright Foteos Macrides 2002-2010. All rights reserved.
+ Initial: August 18, 2002 - Last Revised: January 5, 2010
This module is subject to the same terms of usage as for Erik Bosrup's overLIB,
though only a minority of the code and API now correspond with Erik's version.
See the overlibmws Change History and Command Reference via:
@@ -132,11 +132,12 @@ OLkon=(OLua.indexOf('konqueror')>=0)?1:0, OLkht=(OLsaf||OLkon)?1:0,
OLopr=(OLua.indexOf('opera')>=0)?1:0,
OLop7=(OLopr&&document.createTextNode)?1:0;
+OLop95=(OLop7&&document.getElementsByClassName)?1:0;
if(OLopr){OLns4=OLns6=OLgek=0;OLie4=(OLop7)?1:0;}
var OLieM=((OLie4&&OLmac)&&!(OLkht||OLopr))?1:0,
-OLie5=0,OLie55=0;OLie7=0;if(OLie4&&!OLop7){
+OLie5=0,OLie55=0,OLie7=0;OLie8=0;if(OLie4&&!OLop7){
if((OLv=OLua.match(/msie (\d\.\d+)\.*/i))&&(OLv=parseFloat(OLv[1]))>=5.0){
-OLie5=1;OLns6=0;if(OLv>=5.5)OLie55=1;if(OLv>=7.0)OLie7=1;}if(OLns6)OLie4=0;}
+OLie5=1;OLns6=0;if(OLv>=5.5)OLie55=1;if(OLv>=7.0)OLie7=1;if(OLv>=8.0)OLie8=1;}if(OLns6)OLie4=0;}
if(OLns4)window.onresize=function(){location.reload();};var OLchkMh=1,OLdw;
if(OLns4||OLie4||OLns6){OLmh();if(window.addEventListener)window.addEventListener("unload",
OLulCl,false);}else{overlib=nd=cClick=OLpageDefaults=no_overlib;}
@@ -147,25 +148,25 @@ function OLulCl(){if(over)cClick();window.removeEventListener("unload",OLulCl,fa */
// Loads defaults then args into runtime variables.
function overlib(){
-if(!(OLloaded&&OLgateOK))return;if((OLexclusivePI)&&OLisExclusive(arguments))return true;if(OLchkMh)OLmh();
-if(OLndt&&!OLtimerid)OLndt=0;if(over)cClick();if(parent!=self){if(parent.OLo2Ref){parent.OLeval(parent.OLo2Ref);
-parent.OLo2Ref="";}if(parent.OLifRef){parent.OLeval(parent.OLifRef);parent.OLifRef="";}}if(OLo2Ref){eval(OLo2Ref);
-OLo2Ref="";}if(OLifRef){eval(OLifRef);OLifRef="";}OLload(OLp1or2);OLload(OLp1);OLfnRef="";OLifX=0;OLifY=0;OLhover=0;
-OLsetRunTimeVar();OLparseTokens('o3_',arguments);if(!(over=OLmkLyr()))return false;if(o3_decode)OLdecode();if(OLprintPI)
-OLchkPrint();if(OLbubblePI)OLchkForBubbleEffect();if(OLdebugPI)OLsetDebugCanShow();if(OLshadowPI)OLinitShadow();
-if(OLiframePI)OLinitIfs();if(OLfilterPI)OLinitFilterLyr();if(OLexclusivePI&&o3_exclusive&&o3_exclusivestatus!="")
-o3_status=o3_exclusivestatus;else if(o3_autostatus==2&&o3_cap!="")o3_status=o3_cap;else if(o3_autostatus==1&&o3_text!="")
-o3_status=o3_text;if(!o3_delay){return OLmain();}else{OLdelayid=setTimeout("OLmain()",o3_delay);if(o3_status!=""){
-self.status=o3_status;return true;}else if(!(OLop7&&event&&event.type=='mouseover'))return false;}
+if(!(OLloaded&&OLgateOK))return;if((OLexclusivePI)&&OLisExclusive(arguments))return true;if(OLchkMh)OLmh();if(OLndt&&
+!OLtimerid)OLndt=0;if(over){if(OLfilterPI)o3_filter=0;cClick();}if(parent!=self){if(parent.OLo2Ref){parent.OLeval(
+parent.OLo2Ref);parent.OLo2Ref="";}if(parent.OLifRef){parent.OLeval(parent.OLifRef);parent.OLifRef="";}}if(OLo2Ref){
+eval(OLo2Ref);OLo2Ref="";}if(OLifRef){eval(OLifRef);OLifRef="";}OLload(OLp1or2);OLload(OLp1);OLfnRef="";OLifX=0;OLifY=0;
+OLhover=0;if(OLcrossframePI&&parent!=self)OLchkFRAME(arguments);OLsetRunTimeVar();OLparseTokens('o3_',arguments);if(!(
+over=OLmkLyr()))return false;over.onmouseover=over.onmouseout=null;if(o3_decode)OLdecode();if(OLprintPI)OLchkPrint();
+if(OLbubblePI)OLchkForBubbleEffect();if(OLdebugPI)OLsetDebugCanShow();if(OLshadowPI)OLinitShadow();if(OLiframePI)OLinitIfs();
+if(OLfilterPI)OLinitFilterLyr();if(OLexclusivePI&&o3_exclusive&&o3_exclusivestatus!="")o3_status=o3_exclusivestatus;else
+if(o3_autostatus==2&&o3_cap!="")o3_status=o3_cap;else if(o3_autostatus==1&&o3_text!="")o3_status=o3_text;if(!o3_delay){
+return OLmain();}else{OLdelayid=setTimeout("OLmain()",o3_delay);if(o3_status!=""){self.status=o3_status;return true;}else
+if(!(OLop7&&event&&event.type=='mouseover'))return false;}
}
function OLeval(s){eval(s);}
// Clears popups if appropriate
function nd(time){
-if(OLloaded&&OLgateOK){if(!((OLexclusivePI)&&OLisExclusive())){if(time&&over&&!o3_delay){
-if(OLtimerid>0)clearTimeout(OLtimerid);OLtimerid=(OLhover&&o3_frame==self&&!OLcursorOff())?0:
-setTimeout("cClick()",(o3_timeout=OLndt=time));}else{if(!OLshowingsticky){OLallowmove=0;
-if(over)OLhideObject(over);}}}}return false;
+if(OLloaded&&OLgateOK){if(!((OLexclusivePI)&&OLisExclusive())){if(time&&over&&!o3_delay){if(OLtimerid>0)
+clearTimeout(OLtimerid);OLtimerid=(OLhover&&!OLcursorOff())?0:setTimeout("cClick()",(o3_timeout=OLndt=time));
+}else{if(!OLshowingsticky){OLallowmove=0;if(over)OLhideObject(over);}}}}return false;
}
// Close function for stickies
@@ -189,11 +190,12 @@ function no_overlib(){return false;} OVERLIB MAIN FUNCTION SET
*/
function OLmain(){
-o3_delay=0;if(parent!=self&&o3_frame==parent&&parent.OLscrollPI&&parent.over)parent.OLclearScroll();if(o3_frame==self){
-if(o3_noclose)OLoptMOUSEOFF(0);else if(o3_mouseoff)OLoptMOUSEOFF(1);}if(o3_sticky){OLshowingsticky=1;if(OLfnRef&&
-parent!=self&&o3_frame==parent&&parent.overlib){parent.OLifRef=OLfnRef+'cClick()';}}OLdoLyr();OLallowmove=0;if(o3_timeout>0){
-if(OLtimerid>0)clearTimeout(OLtimerid);OLtimerid=setTimeout("cClick()",o3_timeout);}OLchkRef();OLdisp(o3_status);
-if(OLdraggablePI)OLcheckDrag();if(o3_status!="")return true;else if(!(OLop7&&event&&event.type=='mouseover'))return false;
+o3_delay=0;if(parent!=self&&o3_frame==parent&&parent.OLscrollPI&&parent.over)parent.OLclearScroll();if(o3_noclose)
+OLoptMOUSEOFF(0);else if(o3_mouseoff)OLoptMOUSEOFF(1);if(o3_sticky){OLshowingsticky=1;if(OLfnRef&&parent!=self&&
+o3_frame==parent&&parent.overlib)parent.OLifRef=(OLfilterPI?OLfnRef+'o3_filter=0;':'')+OLfnRef+'cClick();';}OLdoLyr();
+OLallowmove=0;if(o3_timeout>0){if(OLtimerid>0)clearTimeout(OLtimerid);OLtimerid=setTimeout("cClick()",o3_timeout);}
+OLchkRef();OLdisp(o3_status);if(OLdraggablePI)OLcheckDrag();if(o3_status!="")return true;else if(!(OLop7&&event&&
+event.type=='mouseover'))return false;
}
function OLchkRef(){
if(o3_ref){OLrefXY=OLgetRefXY(o3_ref);if(OLrefXY[0]==null&&OLcrossframePI)OLchkIfRef();
@@ -211,11 +213,10 @@ OLcontentSimple(o3_text):(o3_sticky)?OLcontentCaption(o3_text,o3_cap,o3_close):O // Makes Layer
function OLmkLyr(id,f,z){
-id=(id||'overDiv');f=(f||o3_frame);z=(z||1000);var fd=f.document,d=OLgetRefById(id,fd);
-if(!d){if(OLns4)d=fd.layers[id]=new Layer(1024,f);else if(OLie4&&!OLop7){
-fd.body.insertAdjacentHTML('AfterBegin','<div id="'+id+'"></div>');d=fd.all[id];}else{d=fd.createElement('div');
-if(d){d.id=id;fd.body.appendChild(d);}}if(!d)return null;if(OLns4)d.zIndex=z;else{var o=d.style;o.position='absolute';
-o.visibility='hidden';o.zIndex=z;}}return d;
+id=(id||'overDiv');f=(f||o3_frame);z=(z||1000);var fd=f.document,d=OLgetRefById(id,fd);if(!d){if(OLns4)d=fd.layers[id]=
+new Layer(1024,f);else if(OLie4&&!OLop7){fd.body.insertAdjacentHTML('AfterBegin','<div id="'+id+'"></div>');d=fd.all[id];}
+else{d=fd.createElement('div');if(d){d.id=id;fd.body.appendChild(d);}}if(!d)return null;if(OLns4)d.zIndex=z;else{var o=
+d.style;o.position='absolute';o.visibility='hidden';o.zIndex=z;}}return d;
}
// Creates and writes layer content
@@ -225,9 +226,9 @@ if(o3_fgbackground!='')o3_fgbackground=' background="'+o3_fgbackground+'"'; if(o3_bgbackground!='')o3_bgbackground=' background="'+o3_bgbackground+'"';
if(o3_cgbackground!='')o3_cgbackground=' background="'+o3_cgbackground+'"';
if(o3_fgcolor!='')o3_fgcolor=' bgcolor="'+o3_fgcolor+'"';if(o3_bgcolor!='')o3_bgcolor=' bgcolor="'+o3_bgcolor+'"';
-if(o3_cgcolor!='')o3_cgcolor=' bgcolor="'+o3_cgcolor+'"';if(o3_height>0)o3_height=' height="'+o3_height+'"';
-else o3_height='';}if(!OLns4)OLrepositionTo(over,(OLns6?20:0),0);var lyrHtml=OLdoLGF();
-if(o3_wrap&&!o3_fullhtml){OLlayerWrite(lyrHtml);o3_width=(OLns4?over.clip.width:over.offsetWidth);if(OLie4){
+if(o3_cgcolor!='')o3_cgcolor=' bgcolor="'+o3_cgcolor+'"';if(o3_height>0)o3_height=(OLns4)?' height="'+o3_height+'"':
+' style="height:'+o3_height+'px;"';else o3_height='';}if(!OLns4)OLrepositionTo(over,(OLns6?20:0),0);var lyrHtml=OLdoLGF();
+if(o3_wrap&&!o3_fullhtml){OLlayerWrite(lyrHtml);o3_width=(OLns4?over.clip.width:over.offsetWidth);if(OLie4&&!OLop95){
var w=OLfd().clientWidth;if(o3_width>=w){if(OLop7){if(OLovertwoPI&&over==over2){var z=over2.style.zIndex;
o3_frame.document.body.removeChild(over);over2=OLmkLyr('overDiv2',o3_frame,z);over=over2;}else{
o3_frame.document.body.removeChild(over);over=OLmkLyr();}}o3_width=w-20;}}
@@ -294,7 +295,7 @@ return ((o3_base>0&&!o3_wrap)?('<table width="100%" border="0" cellpadding="0" c +o3_bgclass+'"':'')+'><tr><td height="'+o3_base+'"></td></tr></table>'):'')+'</td></tr></table>';
}
function OLwd(a){return(o3_wrap?'':' width="'+(!a?'100%':(a==1?o3_width:(o3_width-o3_padxl-o3_padxr)))+'"');}
-function OLhL(s){return(s?' style="width:100%;"':'width:100%;');}
+function OLhL(s){if(!OLie5)return '';return(s?' style="overflow:auto;"':'overflow:auto;');}
// Loads image into the div.
function OLsetBackground(i){
@@ -308,18 +309,18 @@ else{if(OLns4)over.background.src=i;else{if(OLns6)over.style.width=o3_width+'px' // Displays layer
function OLdisp(s){
if(OLmodalPI&&!o3_modalscroll)OLchkModal();if(!OLallowmove){if(OLshadowPI)OLdispShadow();if(OLiframePI)OLdispIfs();
-OLplaceLayer();if(OLmodalPI&&o3_modalscroll)OLchkModal();if(OLndt)OLshowObject(over);
-else OLshowid=setTimeout("OLshowObject(over)",1);OLallowmove=(o3_sticky||o3_nofollow)?0:1;}OLndt=0;if(s!="")self.status=s;
+OLplaceLayer();if(OLmodalPI&&o3_modalscroll)OLchkModal();if(OLndt)OLshowObject(over);else OLshowid=
+setTimeout("OLshowObject(over)",1);OLallowmove=(o3_sticky||o3_nofollow)?0:1;}OLndt=0;if(s!="")self.status=s;
}
// Decides placement of layer.
function OLplaceLayer(){
var snp,X,Y,pgLeft,pgTop,pWd=o3_width,pHt,iWd=100,iHt=100,SB=0,LM=0,CX=0,TM=0,BM=0,CY=0,o=OLfd(),
nsb=(OLgek>=20010505&&!o3_frame.scrollbars.visible)?1:0;
-if(!OLkht&&o&&o.clientWidth)iWd=o.clientWidth;
+if(!OLkht&&!OLop95&&o&&o.clientWidth)iWd=o.clientWidth;
else if(o3_frame.innerWidth){SB=Math.ceil(1.4*(o3_frame.outerWidth-o3_frame.innerWidth));
if(SB>20)SB=20;iWd=o3_frame.innerWidth;}
-pgLeft=(OLie4)?o.scrollLeft:o3_frame.pageXOffset;
+pgLeft=(OLie4&&!OLop95)?o.scrollLeft:o3_frame.pageXOffset;
if(OLie55&&OLfilterPI&&o3_filter&&o3_filtershadow)SB=CX=5;else
if((OLshadowPI)&&bkdrop&&o3_shadow&&o3_shadowx){SB+=((o3_shadowx>0)?o3_shadowx:0);
LM=((o3_shadowx<0)?Math.abs(o3_shadowx):0);CX=Math.abs(o3_shadowx);}
@@ -345,8 +346,8 @@ snp=X % o3_snapx; if(o3_hpos==LEFT){X=X-(o3_snapx+snp);}else{X=X+(o3_snapx-snp);}}X+=OLifX;}
if(!o3_nojustx&&X+pWd>pgLeft+iWd-SB)
X=iWd+pgLeft-pWd-SB;if(!o3_nojustx&&X-LM<pgLeft)X=pgLeft+LM;
-pgTop=OLie4?o.scrollTop:o3_frame.pageYOffset;
-if(!OLkht&&!nsb&&o&&o.clientHeight)iHt=o.clientHeight;
+pgTop=OLie4&&!OLop95?o.scrollTop:o3_frame.pageYOffset;
+if(!OLkht&&!OLop95&&!nsb&&o&&o.clientHeight)iHt=o.clientHeight;
else if(o3_frame.innerHeight)iHt=o3_frame.innerHeight;
if(OLbubblePI&&o3_bubble)pHt=OLbubbleHt;else pHt=OLns4?over.clip.height:over.offsetHeight;
if((OLshadowPI)&&bkdrop&&o3_shadow&&o3_shadowy){TM=(o3_shadowy<0)?Math.abs(o3_shadowy):0;
@@ -424,16 +425,15 @@ of=(p=='UR')?[W-pW,0]:(p=='LL')?[W,-pH]:(p=='LR')?[W-pW,-pH]:[W,0];}else if(c==' // Gets x or y location of object
function OLpageLoc(o,t){
var l=0,s=o;while(o.offsetParent&&o.offsetParent.tagName.toLowerCase()!='html'){l+=o['offset'+t];o=o.offsetParent;}
-l+=o['offset'+t];while(s=s.parentNode){if((s['scroll'+t]>0)&&s.tagName.toLowerCase()=='div')l-=s['scroll'+t];}return l;
+l+=o['offset'+t];if(!OLop7)while(s=s.parentNode){if((s['scroll'+t]>0)&&s.tagName.toLowerCase()=='div')l-=s['scroll'+t];}
+return l;
}
// Moves layer
function OLmouseMove(e){
-var e=(e||event);OLcC=(OLovertwoPI&&over2&&over==over2?cClick2:cClick);OLx=(e.pageX||e.clientX+OLfd().scrollLeft);
-OLy=(e.pageY||e.clientY+OLfd().scrollTop);if((OLallowmove&&over)&&(o3_frame==self||over==OLgetRefById()||(OLovertwoPI&&
-over2==over&&over==OLgetRefById('overDiv2')))){OLplaceLayer();if(OLhidePI)OLhideUtil(0,1,1,0,0,0);}if(OLhover&&over&&
-o3_frame==self&&OLcursorOff())if(o3_offdelay<1)OLcC();else{if(OLtimerid>0)clearTimeout(OLtimerid);
-OLtimerid=setTimeout("OLcC()",o3_offdelay);}
+var e=(e||event);OLx=(e.pageX||e.clientX+OLfd().scrollLeft);OLy=(e.pageY||e.clientY+OLfd().scrollTop);if((OLallowmove&&
+over)&&(o3_frame==self||over==OLgetRefById()||(OLovertwoPI&&over2==over&&over==OLgetRefById('overDiv2')))){OLplaceLayer();
+if(OLhidePI)OLhideUtil(0,1,1,0,0,0);}
}
// Capture mouse and chain other scripts.
@@ -451,8 +451,8 @@ function OLparseTokens(pf,ar){ var i,v,md= -1,par=(pf!='ol_'),p=OLpar,q=OLparQuo,t=OLtoggle;OLudf=(par&&!ar.length?1:0);
for(i=0;i<ar.length;i++){if(md<0){if(typeof ar[i]=='number'){OLudf=(par?1:0);i--;}
else{switch(pf){case 'ol_':ol_text=ar[i];break;default:o3_text=ar[i];}}md=0;}else{
-if(ar[i]==INARRAY){OLudf=0;eval(pf+'text=ol_texts['+ar[++i]+']');continue;}
-if(ar[i]==CAPARRAY){eval(pf+'cap=ol_caps['+ar[++i]+']');continue;}
+if(ar[i]==INARRAY){OLudf=0;eval(pf+'text=ol_texts['+ar[(++i)]+']');continue;}
+if(ar[i]==CAPARRAY){eval(pf+'cap=ol_caps['+ar[(++i)]+']');continue;}
if(ar[i]==CAPTION){q(ar[++i],pf+'cap');continue;}
if(Math.abs(ar[i])==STICKY){t(ar[i],pf+'sticky');continue;}
if(Math.abs(ar[i])==NOFOLLOW){t(ar[i],pf+'nofollow');continue;}
@@ -577,8 +577,8 @@ if(OLshowid>0){clearTimeout(OLshowid);OLshowid=0;}if(OLtimerid>0)clearTimeout(OL if(OLdelayid>0)clearTimeout(OLdelayid);OLtimerid=0;OLdelayid=0;self.status="";o3_label=ol_label;
if(o3_frame!=self)o=OLgetRefById();if(o){if(o.onmouseover)o.onmouseover=null;if(OLscrollPI&&o==over)OLclearScroll();
if(OLdraggablePI)OLclearDrag();if(OLfilterPI)OLcleanupFilter(o);if(OLshadowPI)OLhideShadow();var os=(OLns4)?o:o.style;
-if(((OLfilterPI)&&!OLchkFadeOut(os))||!OLfilterPI){os.visibility="hidden";if(!OLie55||!OLfilterPI||!o3_filter||
-o3_fadeout<0)o.innerHTML='';}if(OLhidePI&&o==over)OLhideUtil(0,0,1);if(OLiframePI)OLhideIfs(o);}
+if(((OLfilterPI)&&!OLchkFadeOut(os))||!OLfilterPI){os.visibility="hidden";if(!OLie55||(typeof ggOnChange=='undefined'&&
+(!OLfilterPI||!o3_filter||o3_fadeout<0)))o.innerHTML='';}if(OLhidePI&&o==over)OLhideUtil(0,0,1);if(OLiframePI)OLhideIfs(o);}
}
// Moves layer
@@ -588,8 +588,9 @@ o=(OLns4)?o:o.style;o.left=(OLns4?xL:xL+'px');o.top=(OLns4?yL:yL+'px'); // Handle NOCLOSE-MOUSEOFF
function OLoptMOUSEOFF(c){
-if(!c)o3_close="";
-over.onmouseover=function(){OLhover=1;if(OLtimerid>0){clearTimeout(OLtimerid);OLtimerid=0;}}
+if(!c)o3_close="";over.onmouseover=function(){OLhover=1;if(OLtimerid>0){clearTimeout(OLtimerid);OLtimerid=0;}}
+over.onmouseout=function(){if(OLhover){OLcC=(OLovertwoPI&&over2&&over==over2?cClick2:cClick);if(OLtimerid>0)
+clearTimeout(OLtimerid);OLtimerid=setTimeout("OLcC()",(o3_offdelay<1)?1:o3_offdelay);}}
}
function OLcursorOff(){
var o=(OLns4?over:over.style),pHt=OLns4?over.clip.height:over.offsetHeight,left=parseInt(o.left),top=parseInt(o.top),
@@ -608,7 +609,7 @@ if(OLcmdLine.length){for(var k=0;k<OLcmdLine.length;k++){var j=OLcmdLine[k](pf,i }
function OLregCmds(c){
if(typeof c!='string')return;var pM=c.split(',');pMtr=pMtr.concat(pM);
-for(var i=0;i<pM.length;i++)eval(pM[i].toUpperCase()+'='+pmCnt++);
+for(var i=0;i<pM.length;i++)eval(pM[i].toUpperCase()+'='+(pmCnt++));
}
function OLregRunTimeFunc(f){
if(typeof f=='object')OLrunTime=OLrunTime.concat(f);else OLrunTime[OLrunTime.length++]=f;
diff --git a/httemplate/elements/overlibmws_crossframe.js b/httemplate/elements/overlibmws_crossframe.js index dd6422313..e1bbf413d 100644 --- a/httemplate/elements/overlibmws_crossframe.js +++ b/httemplate/elements/overlibmws_crossframe.js @@ -1,7 +1,7 @@ /*
- overlibmws_crossframe.js plug-in module - Copyright Foteos Macrides 2003-2008. All rights reserved.
+ overlibmws_crossframe.js plug-in module - Copyright Foteos Macrides 2003-2010. All rights reserved.
For support of FRAME.
- Initial: August 3, 2003 - Last Revised: January 16, 2008
+ Initial: August 3, 2003 - Last Revised: October 25, 2008
See the Change History and Command Reference for overlibmws via:
http://www.macridesweb.com/oltest/
@@ -32,8 +32,8 @@ function OLoptFRAME(frm){ o3_frame=OLmkLyr('overDiv',frm)?frm:self;if(o3_frame!=self){var l,tFrm=OLgetFrameRef(top.frames,o3_frame),
sFrm=OLgetFrameRef(top.frames,ol_frame);if(sFrm.length==tFrm.length) {l=tFrm.lastIndexOf('[');if(l){
while(sFrm.substring(0,l)!=tFrm.substring(0,l))l=tFrm.lastIndexOf('[',l-1);tFrm=tFrm.substr(l);sFrm=sFrm.substr(l);}}
-var i,k,cnt=0,p='',str=tFrm;while((k=str.lastIndexOf('['))!= -1){cnt++;str=str.substring(0,k);}
-for(i=0;i<cnt;i++)p=p+'parent.';OLfnRef=p+'frames'+sFrm+'.';var n=window.name,o;
+var i,k,cnt=0,p='',str=tFrm;while((k=str.lastIndexOf('['))!= -1){cnt++;str=str.substring(0,k);}if(!sFrm&&o3_frame==parent)
+sFrm=OLgetFrameRef(parent,self);else for(i=0;i<cnt;i++)p=p+'parent.';OLfnRef=p+'frames'+sFrm+'.';var n=window.name,o;
if((n&&parent!=self&&o3_frame==parent)&&(o=OLgetRef(n,parent.document))){if(OLie4&&!OLop7){
OLx=event.clientX+OLfd().scrollLeft;OLy=event.clientY+OLfd().scrollTop;}
OLifX=OLpageLoc(o,'Left')-(OLie4&&!OLop7?OLfd().scrollLeft:self.pageXOffset);
@@ -47,6 +47,11 @@ OLrefXY[0]+=(OLpageLoc(o,'Left')-(OLie4&&!OLop7?OLfd(self).scrollLeft:self.pageX OLrefXY[1]+=(OLpageLoc(o,'Top')-(OLie4&&!OLop7?OLfd(self).scrollTop:self.pageYOffset));}}
}
+function OLchkFRAME(args){
+var OLfrmVal=self;for(var i=0;i<args.length;i++){if(typeof args[i]=='number'&&args[i]==FRAME){OLfrmVal=args[i+1];break;}}
+if(OLfrmVal!=self&&OLfrmVal.over&&OLfrmVal.cClick)OLfrmVal.cClick();
+}
+
OLregCmdLineFunc(OLparseCrossframe);
OLcrossframePI=1;
diff --git a/httemplate/elements/overlibmws_draggable.js b/httemplate/elements/overlibmws_draggable.js index 1bf0ecfd1..d2b5eb1ad 100644 --- a/httemplate/elements/overlibmws_draggable.js +++ b/httemplate/elements/overlibmws_draggable.js @@ -1,5 +1,5 @@ /*
- overlibmws_draggable.js plug-in module - Copyright Foteos Macrides 2002-2008. All rights reserved.
+ overlibmws_draggable.js plug-in module - Copyright Foteos Macrides 2002-2010. All rights reserved.
For support of the DRAGGABLE feature.
Initial: August 24, 2002 - Last Revised: January 26, 2008
See the Change History and Command Reference for overlibmws via:
diff --git a/httemplate/elements/overlibmws_iframe.js b/httemplate/elements/overlibmws_iframe.js index 4c937d3d7..a06bdc515 100644 --- a/httemplate/elements/overlibmws_iframe.js +++ b/httemplate/elements/overlibmws_iframe.js @@ -1,5 +1,5 @@ /*
- overlibmws_iframe.js plug-in module - Copyright Foteos Macrides 2003-2008. All rights reserved.
+ overlibmws_iframe.js plug-in module - Copyright Foteos Macrides 2003-2010. All rights reserved.
Masks system controls to prevent obscuring of popops for IE v5.5 or higher.
Initial: October 19, 2003 - Last Revised: January 26, 2008
See the Change History and Command Reference for overlibmws via:
diff --git a/httemplate/elements/phonenumber.html b/httemplate/elements/phonenumber.html index 60414a644..854f5846d 100644 --- a/httemplate/elements/phonenumber.html +++ b/httemplate/elements/phonenumber.html @@ -4,22 +4,64 @@ <% $number %> -% if ( $opt{'callable'} && $curuser->option('vonage-username') ) { - - <% include('/elements/popup_link.html', - 'action' => - 'https://secure.click2callu.com/tpcc/makecall'. - '?username='. uri_escape($curuser->option('vonage-username')). - '&password='. uri_escape($curuser->option('vonage-password')). - "&fromnumber=$vonage_number". - "&tonumber=$snumber", - 'width' => 240, - 'height' => 64, - 'actionlabel' => 'Initiating call', - 'label' => qq!<IMG SRC="${fsurl}images/red_telephone_mimooh_01.png" BORDER=0 ALT="Call this number">!, - ) - %> +% if ( $opt{'callable'} ) { +% +% if ( $curuser->option('vonage-username') ) { +% +% (my $vonage_number = $curuser->option('vonage-fromnumber')) =~ s/\D//g; +% $vonage_number =~ /^1/ or $vonage_number = "1$vonage_number"; + + <% include('/elements/popup_link.html', + 'action' => + 'https://secure.click2callu.com/tpcc/makecall'. + '?username='. uri_escape($curuser->option('vonage-username')). + '&password='. uri_escape($curuser->option('vonage-password')). + "&fromnumber=$vonage_number". + "&tonumber=$snumber", + 'width' => 240, + 'height' => 64, + 'actionlabel' => 'Initiating call', + 'label' => "<$img>", + ) + %> + +% } elsif ( $curuser->option('snom-ip') ) { +% +% my $host = $curuser->option('snom-ip'); +% if ( $curuser->option('snom-username') ) { +% my $userpass = uri_escape($curuser->option('snom-username')); +% $userpass .= ':'. uri_escape($curuser->option('snom-password')) +% if $curuser->option('snom-password'); +% $host = $userpass.'@'.$host; +% } +% +% $snumber = "1$snumber" unless $snumber =~ /~1/; #NANPA-centric + +%# <% include('/elements/popup_link.html', +%# 'action' => "http://$host/command.htm?number=$snumber", +%# %link_common, +%# ) +%# %> + + <A HREF="javascript:snom_call(<%$snumber%>)"><<% $img %>></A> + <SCRIPT TYPE="text/javascript"> + function snom_call(number) { + + var url = '<% "http://$host/command.htm?number=" %>'; + url = url + number; + + var xmlhttp = new XMLHttpRequest(); + xmlhttp.open('GET', url, true); + xmlhttp.send(null); + + } + + </SCRIPT> + + +% } +% % } % % } else { @@ -34,7 +76,6 @@ my( $number, %opt ) = @_; my $curuser = $FS::CurrentUser::CurrentUser; -( my $vonage_number = $curuser->option('vonage-fromnumber') ) =~ s/\D//g; -$vonage_number =~ /^1/ or $vonage_number = "1$vonage_number"; +my $img = qq(IMG SRC="${fsurl}images/red_telephone_mimooh_01.png" BORDER=0 ALT="Call this number"); </%init> diff --git a/httemplate/elements/search-cust_main.html b/httemplate/elements/search-cust_main.html index dbcc2ed0b..23c4369e8 100644 --- a/httemplate/elements/search-cust_main.html +++ b/httemplate/elements/search-cust_main.html @@ -1,26 +1,39 @@ -<INPUT TYPE="hidden" NAME="<% $opt{'field_name'} %>" VALUE="<% $value %>"> +<%doc> + +Example: + + include( '/elements/search-cust_main.html, + '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="<% $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', @@ -31,7 +44,7 @@ <SCRIPT TYPE="text/javascript"> - function clearhint_<% $opt{'field_name'} %>_search (what) { + function clearhint_<% $field %>_search (what) { what.style.color = '#000000'; @@ -43,7 +56,7 @@ } - function smart_<% $opt{'field_name'} %>_search(what) { + function smart_<% $field %>_search(what) { var customer = what.value; @@ -61,11 +74,11 @@ 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); @@ -76,7 +89,7 @@ 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'; @@ -88,7 +101,7 @@ //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 = ''; @@ -117,17 +130,17 @@ } - 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'; @@ -142,7 +155,7 @@ } else { - what.form.<% $opt{'field_name'} %>.value = custnum; + what.form.<% $field %>.value = custnum; customer_obj.value = customer; customer_obj.style.color = '#000000'; @@ -165,7 +178,8 @@ <%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/select-svc-domain.html b/httemplate/elements/select-svc-domain.html new file mode 100644 index 000000000..4c04466db --- /dev/null +++ b/httemplate/elements/select-svc-domain.html @@ -0,0 +1,50 @@ +<SELECT NAME="domsvc" SIZE=1> +% foreach my $svcnum ( +% sort { $svc_domain{$a} cmp $svc_domain{$b} } +% keys %svc_domain +% ) { + + <OPTION VALUE="<% $svcnum %>" + <% ($svcnum == $domsvc) ? ' SELECTED' : '' %> + ><% $svc_domain{$svcnum} %> + +% } + +</SELECT> +<%init> + +my %opt = @_; + +my %svc_domain = (); +my $domsvc; + +my $domsvc = $opt{'curr_value'}; +my $part_svc = $opt{'part_svc'} + || qsearchs('part_svc', { 'svcpart' => $opt{'svcpart'} }); + +#optional +my $cust_pkg = $opt{'cust_pkg'}; +$cust_pkg ||= qsearchs('cust_pkg', { 'pkgnum' => $opt{'pkgnum'} }) + if $opt{'pkgnum'}; + +my $pkgnum = $cust_pkg ? $cust_pkg->pkgnum : ''; + +my %svc_domain = (); + +if ( $domsvc ) { + my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $domsvc } ); + if ( $svc_domain ) { + $svc_domain{$svc_domain->svcnum} = $svc_domain; + } else { + warn "unknown svc_domain.svcnum for svc_acct.domsvc: $domsvc"; + } +} + +%svc_domain = ( + %svc_domain, + FS::svc_Domain_Mixin->domain_select_hash( 'svcpart' => $part_svc->svcpart, + 'pkgnum' => $pkgnum, + ) +); + +</%init> diff --git a/httemplate/elements/select-svc_pbx.html b/httemplate/elements/select-svc_pbx.html new file mode 100644 index 000000000..19bce96ca --- /dev/null +++ b/httemplate/elements/select-svc_pbx.html @@ -0,0 +1,57 @@ +<SELECT <% $opt{'multiple'} ? 'MULTIPLE' : 'SIZE=1' %> + NAME = "<% $opt{'element_name'} || $opt{'field'} || 'pbxsvc' %>" + <% $opt{'element_etc'} %> +> + +% unless ( $opt{'multiple'} || $opt{'disable_empty'} ) { + <OPTION VALUE=""><% $opt{'empty_label'} || '' %> +% } + +% foreach my $svcnum ( +% sort { $svc_pbx{$a} cmp $svc_pbx{$b} } +% keys %svc_pbx +% ) { +% my $svc_pbx = $svc_pbx{$svcnum}; +% my $selected = ($svcnum == $pbxsvc) ? ' SELECTED' : ''; + + <OPTION VALUE="<% $svcnum %>" <% $selected %>><% $svc_pbx{$svcnum} %> + +% } + +</SELECT> +<%init> + +# false laziness w/select-svc_acct-domain.html + +my %opt = @_; + +my $pbxsvc = $opt{'curr_value'}; +my $part_svc = $opt{'part_svc'} + || qsearchs('part_svc', { 'svcpart' => $opt{'svcpart'} }); +my $svcpart = $part_svc ? $part_svc->svcpart : ''; + +#optional +my $cust_pkg = $opt{'cust_pkg'}; +$cust_pkg ||= qsearchs('cust_pkg', { 'pkgnum' => $opt{'pkgnum'} }) + if $opt{'pkgnum'}; + +my $pkgnum = $cust_pkg ? $cust_pkg->pkgnum : ''; + +my %svc_pbx = (); + +if ( $pbxsvc ) { + my $svc_pbx = qsearchs('svc_pbx', { 'svcnum' => $pbxsvc } ); + if ( $svc_pbx ) { + $svc_pbx{$svc_pbx->svcnum} = $svc_pbx; + } else { + warn "unknown svc_pbx.svcnum for svc_acct.pbxsvc: $pbxsvc"; + } +} + +%svc_pbx = ( + %svc_pbx, + FS::svc_Common->pbx_select_hash( 'svcpart' => $svcpart, + 'pkgnum' => $pkgnum, + ) +); +</%init> diff --git a/httemplate/elements/select-table.html b/httemplate/elements/select-table.html index 10a8b2741..c280c3631 100644 --- a/httemplate/elements/select-table.html +++ b/httemplate/elements/select-table.html @@ -29,6 +29,9 @@ Example: #or 'records' => \@records, #instead of search params + #instead of the primary key... only for special cases + 'value_col' => 'columnname', + #basic params controlling the resulting <SELECT> 'pre_options' => [ 'value' => 'option' ], #before normal options 'empty_label' => '', #better specify it though, the default might change @@ -86,7 +89,7 @@ Example: % { % my $recvalue = $record->$key(); <OPTION VALUE="<% $recvalue %>" - <% ref($value) && $value->{$recvalue} || $value == $recvalue + <% ref($value) && $value->{$recvalue} || $value && $value eq $recvalue # not == because of value_col ? ' SELECTED' : '' %> ><% $opt{'label_showkey'} ? "$recvalue: " : '' %> @@ -118,7 +121,7 @@ if ( $opt{'onchange'} ) { my $dbdef_table = dbdef->table($opt{'table'}) or die "can't find dbdef for ". $opt{'table'}. " table\n"; -my $key = $dbdef_table->primary_key; #? $opt{'primary_key'} || +my $key = $opt{'value_col'} || $dbdef_table->primary_key; my $name_col = $opt{'name_col'}; diff --git a/httemplate/elements/tr-input-beginning_ending.html b/httemplate/elements/tr-input-beginning_ending.html index 8a1dd62a9..2aa597479 100644 --- a/httemplate/elements/tr-input-beginning_ending.html +++ b/httemplate/elements/tr-input-beginning_ending.html @@ -11,7 +11,7 @@ <SCRIPT TYPE="text/javascript"> Calendar.setup({ inputField: "<% $opt{prefix} %>beginning_text", - ifFormat: "%m/%d/%Y<% $time_format %>", + ifFormat: "<% $date_format. $time_format %>", button: "<% $opt{prefix} %>beginning_button", align: "BR" <% $input_time %> @@ -30,7 +30,7 @@ <SCRIPT TYPE="text/javascript"> Calendar.setup({ inputField: "<% $opt{prefix} %>ending_text", - ifFormat: "%m/%d/%Y<% $time_format %>", + ifFormat: "<% $date_format. $time_format %>", button: "<% $opt{prefix} %>ending_button", align: "BR" <% $input_time %> @@ -54,6 +54,10 @@ my $previous_request_count = ''; my %opt = @_; +my $conf = new FS::Conf; + +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; + $opt{prefix} = '' unless defined $opt{prefix}; $opt{prefix} .= '_' if $opt{prefix}; diff --git a/httemplate/elements/tr-input-date-field.html b/httemplate/elements/tr-input-date-field.html index 2a731e1e8..ff4996faf 100644 --- a/httemplate/elements/tr-input-date-field.html +++ b/httemplate/elements/tr-input-date-field.html @@ -21,8 +21,8 @@ }); </SCRIPT> - <%init> + my($name, $value, $label, $format, $usedatetime); if ( ref($_[0]) ) { my $opt = shift; @@ -35,7 +35,10 @@ if ( ref($_[0]) ) { ($name, $value, $label, $format, $usedatetime) = @_; } -$format = "%m/%d/%Y" unless $format; +my $conf = new FS::Conf; + +$format ||= $conf->config('date_format') || '%m/%d/%Y'; + $label = $name unless $label; if ( $value =~ /\S/ ) { 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/elements/tr-select-svc-domain.html b/httemplate/elements/tr-select-svc-domain.html new file mode 100644 index 000000000..437bc5896 --- /dev/null +++ b/httemplate/elements/tr-select-svc-domain.html @@ -0,0 +1,34 @@ +%if ( $columnflag eq 'F' ) { + <INPUT TYPE="hidden" NAME="domsvc" VALUE="<% $domsvc %>"> +% } else { + + <TR> + <TD ALIGN="right"><% $opt{'label'} || 'Domain' %></TD> + <TD> + <% include('/elements/select-svc-domain.html', + 'curr_value' => $domsvc, + 'part_svc' => $part_svc, + 'cust_pkg' => $cust_pkg, + ) + %> + </TD> + </TR> +% } +<%init> + +my %opt = @_; + +my $domsvc = $opt{'curr_value'}; + +#required +my $part_svc = $opt{'part_svc'} + || qsearchs('part_svc', { 'svcpart' => $opt{'svcpart'} }); + +my $columnflag = $part_svc->part_svc_column('domsvc')->columnflag; + +#optional +my $cust_pkg = $opt{'cust_pkg'}; +$cust_pkg ||= qsearchs('cust_pkg', { 'pkgnum' => $opt{'pkgnum'} }) + if $opt{'pkgnum'}; + +</%init> diff --git a/httemplate/elements/tr-select-svc_pbx.html b/httemplate/elements/tr-select-svc_pbx.html new file mode 100644 index 000000000..b02bd65c3 --- /dev/null +++ b/httemplate/elements/tr-select-svc_pbx.html @@ -0,0 +1,60 @@ +%if ( $columnflag eq 'F' || !keys(%svc_pbx) ) { + <INPUT TYPE="hidden" NAME="<% $opt{'element_name'} || $opt{'field'} || 'pbxsvc' %>" VALUE="<% $pbxsvc %>"> +% } else { + + <TR> + <TD ALIGN="right"><% $opt{'label'} || 'PBX' %></TD> + <TD> + <% include('/elements/select-svc_pbx.html', + 'curr_value' => $pbxsvc, + 'part_svc' => $part_svc, + 'cust_pkg' => $cust_pkg, + ) + %> + </TD> + </TR> +% } +<%init> + +# false laziness w/tr-select-svc_acct-domain.html + +my %opt = @_; + +my $pbxsvc = $opt{'curr_value'}; + +#required +my $part_svc = $opt{'part_svc'} + || qsearchs('part_svc', { 'svcpart' => $opt{'svcpart'} }); +my $svcpart = + $part_svc ? $part_svc->svcpart : ''; +my $columnflag = + $part_svc ? $part_svc->part_svc_column('pbxsvc')->columnflag : ''; + +#optional +my $cust_pkg = $opt{'cust_pkg'}; +$cust_pkg ||= qsearchs('cust_pkg', { 'pkgnum' => $opt{'pkgnum'} }) + if $opt{'pkgnum'}; + +# false laziness w/select-svc_pbx.html + +my $pkgnum = $cust_pkg ? $cust_pkg->pkgnum : ''; + +my %svc_pbx = (); + +if ( $pbxsvc ) { + my $svc_pbx = qsearchs('svc_pbx', { 'svcnum' => $pbxsvc } ); + if ( $svc_pbx ) { + $svc_pbx{$svc_pbx->svcnum} = $svc_pbx; + } else { + warn "unknown svc_pbx.svcnum for svc_acct.pbxsvc: $pbxsvc"; + } +} + +%svc_pbx = ( + %svc_pbx, + FS::svc_Common->pbx_select_hash( 'svcpart' => $svcpart, + 'pkgnum' => $pkgnum, + ) +); + +</%init> diff --git a/httemplate/misc/bulk_pkg_increment_bill.cgi b/httemplate/misc/bulk_pkg_increment_bill.cgi new file mode 100755 index 000000000..d594b558a --- /dev/null +++ b/httemplate/misc/bulk_pkg_increment_bill.cgi @@ -0,0 +1,50 @@ +<% include('/elements/header-popup.html', "Increment Next Bill Date") %> + +% if ( $cgi->param('error') ) { + <FONT SIZE="+1" COLOR="#ff0000">Error: <% $cgi->param('error') %></FONT> + <BR><BR> +% } + +<FORM ACTION="<% $p %>misc/process/bulk_pkg_increment_bill.cgi" METHOD=POST> + +%# some false laziness w/search/cust_pkg.cgi + +<INPUT TYPE="hidden" NAME="query" VALUE="<% $cgi->keywords |h %>"> +% for my $param (qw(agentnum custnum magic status classnum custom censustract)) { +<INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) |h %>"> +% } +% +% foreach my $pkgpart ($cgi->param('pkgpart')) { +<INPUT TYPE="hidden" NAME="pkgpart" VALUE="<% $pkgpart |h %>"> +% } +% +% foreach my $field (qw( setup last_bill bill adjourn susp expire cancel )) { +% + <INPUT TYPE="hidden" NAME="<% $field %>begin" VALUE="<% $cgi->param("${field}.begin") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>beginning" VALUE="<% $cgi->param("${field}beginning") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>end" VALUE="<% $cgi->param("${field}.end") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>ending" VALUE="<% $cgi->param("${field}.ending") |h %>"> +% } + +<% ntable('#cccccc') %> + + <TR> + <TD>Days to increment: </TD> + <TD><INPUT type="text" name="days"></TD> + </TR> + +</TABLE> + +<BR> +<INPUT TYPE="submit" VALUE="Increment next bill date"> + +</FORM> +</BODY> +</HTML> + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + +</%init> diff --git a/httemplate/misc/cancel_pkg.html b/httemplate/misc/cancel_pkg.html index 607ce13c4..67d2847cc 100755 --- a/httemplate/misc/cancel_pkg.html +++ b/httemplate/misc/cancel_pkg.html @@ -31,7 +31,7 @@ <SCRIPT TYPE="text/javascript"> Calendar.setup({ inputField: "expire_date", - ifFormat: "%m/%d/%Y", + ifFormat: "<% $date_format %>", button: "expire_button", align: "BR" }); @@ -58,7 +58,10 @@ <%init> -my $date = time2str("%m/%d/%Y", time); +my %conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; + +my $date = time2str($date_format, time); my($pkgnum, $reasonnum); if ( $cgi->param('error') ) { diff --git a/httemplate/misc/delay_susp_pkg.html b/httemplate/misc/delay_susp_pkg.html index d4a6da18f..8adc40d55 100755 --- a/httemplate/misc/delay_susp_pkg.html +++ b/httemplate/misc/delay_susp_pkg.html @@ -25,7 +25,7 @@ <SCRIPT TYPE="text/javascript"> Calendar.setup({ inputField: "dun_date", - ifFormat: "%m/%d/%Y", + ifFormat: "<% $date_format %>", button: "dun_button", align: "BR" }); @@ -42,7 +42,10 @@ <%init> -my $date = time2str("%m/%d/%Y", time); +my $conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; + +my $date = time2str($date_format, time); my($pkgnum); if ( $cgi->param('error') ) { 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/order_pkg.html b/httemplate/misc/order_pkg.html index a7571ca58..85573e6b4 100644 --- a/httemplate/misc/order_pkg.html +++ b/httemplate/misc/order_pkg.html @@ -54,7 +54,7 @@ <SCRIPT TYPE="text/javascript"> Calendar.setup({ inputField: "start_date_text", - ifFormat: "%m/%d/%Y", + ifFormat: "<% $date_format %>", button: "start_date_button", align: "BR" }); @@ -90,6 +90,7 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Order customer package'); my $conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; $cgi->param('custnum') =~ /^(\d+)$/ or die "no custnum"; my $custnum = $1; 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/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/pref/pref-process.html b/httemplate/pref/pref-process.html index 378164e7b..708583df5 100644 --- a/httemplate/pref/pref-process.html +++ b/httemplate/pref/pref-process.html @@ -45,8 +45,10 @@ unless ( $error ) { # if ($access_user) { #XXX autogen my @paramlist = qw( menu_position default_customer_view email_address + snom-ip snom-username snom-password vonage-fromnumber vonage-username vonage-password - show_pkgnum show_db_profile save_db_profile + show_pkgnum show_confitem_counts export_getsettings + show_db_profile save_db_profile height width availHeight availWidth colorDepth ); diff --git a/httemplate/pref/pref.html b/httemplate/pref/pref.html index 562ef2980..7ded18377 100644 --- a/httemplate/pref/pref.html +++ b/httemplate/pref/pref.html @@ -80,6 +80,14 @@ Development <TD><INPUT TYPE="checkbox" NAME="show_pkgnum" VALUE="1" <% $curuser->option('show_pkgnum') ? 'CHECKED' : '' %>></TD> </TR> <TR> + <TH>Show config item counts: </TH> + <TD><INPUT TYPE="checkbox" NAME="show_confitem_counts" VALUE="1" <% $curuser->option('show_confitem_counts') ? 'CHECKED' : '' %>></TD> + </TR> + <TR> + <TH>Show export data on service view (when available): </TH> + <TD><INPUT TYPE="checkbox" NAME="export_getsettings" VALUE="1" <% $curuser->option('export_getsettings') ? 'CHECKED' : '' %>></TD> + </TR> + <TR> <TH>Show database profiling (when available): </TH> <TD><INPUT TYPE="checkbox" NAME="show_db_profile" VALUE="1" <% $curuser->option('show_db_profile') ? 'CHECKED' : '' %>></TD> </TR> @@ -91,6 +99,28 @@ Development </TABLE> <BR> +SNOM integration +<% ntable("#cccccc",2) %> + + <TR> + <TH ALIGN="right">SNOM IP address</TH> + <TD><INPUT TYPE="text" NAME="snom-ip" VALUE="<% $curuser->option('snom-ip') %>"></TD> + </TR> + + <TR> + <TH ALIGN="right">SNOM HTTP username (if necessary)</TH> + <TD><INPUT TYPE="text" NAME="snom-username" VALUE="<% $curuser->option('snom-username') %>"></TD> + </TR> + + <TR> + <TH ALIGN="right">SNOM HTTP password (if necessary)</TH> + <TD><INPUT TYPE="password" NAME="snom-password" VALUE="<% $curuser->option('snom-password') %>"></TD> + </TR> + +</TABLE> +<BR> + +OR<BR><BR> Vonage integration (see <a href="https://secure.click2callu.com/">Click2Call</a>) <% ntable("#cccccc",2) %> diff --git a/httemplate/search/cust_bill.html b/httemplate/search/cust_bill.html index c1f5517af..8d72357dc 100755 --- a/httemplate/search/cust_bill.html +++ b/httemplate/search/cust_bill.html @@ -22,7 +22,7 @@ sub { time2str('%b %d %Y', shift->_date ) }, \&FS::UI::Web::cust_fields, ], - 'align' => 'rrrr'.FS::UI::Web::cust_aligns(), + 'align' => 'rrrrl'.FS::UI::Web::cust_aligns(), 'links' => [ $link, $link, diff --git a/httemplate/search/cust_bill_pay.html b/httemplate/search/cust_bill_pay.html index 3c390e706..4272d8669 100644 --- a/httemplate/search/cust_bill_pay.html +++ b/httemplate/search/cust_bill_pay.html @@ -5,34 +5,34 @@ 'count_query' => $count_query, 'count_addl' => [ '$%.2f total paid (net)', ], 'header' => [ 'Net applied', - 'to Invoice', + 'Invoice', + 'Invoice amount', + 'Invoice date', 'Payment', + 'Payment amount', + 'Payment date', 'By', FS::UI::Web::cust_header(), ], 'fields' => [ - sub { $money_char. sprintf('%.2f', shift->amount ) }, - sub { my $cbp = shift; - '#'.$cbp->invnum. ' '. - time2str('%b %d %Y', $cbp->cust_bill_date ). - " ($money_char". - sprintf('%.2f', $cbp->cust_bill_amount). - ")" - }, - sub { my $cbp = shift; - $cbp->cust_pay->payby_payinfo_pretty. ' '. - time2str('%b %d %Y', $cbp->_date ). - " ($money_char". - sprintf('%.2f', $cbp->cust_pay_paid ). - ")" - }, - sub { shift->cust_pay->otaker }, + sub { $money_char.sprintf('%.2f', shift->amount ) }, + 'invnum', + sub { $money_char.sprintf('%.2f', shift->cust_bill_charged)}, + sub { time2str('%b %d %Y', shift->cust_bill_date ) }, + sub { shift->cust_pay->payby_payinfo_pretty }, + sub { $money_char.sprintf('%.2f', shift->cust_pay_paid)}, + sub { time2str('%b %d %Y', shift->cust_pay_date ) }, + sub { shift->cust_pay_otaker }, \&FS::UI::Web::cust_fields, ], - 'align' => 'rrrl'.FS::UI::Web::cust_aligns(), + 'align' => 'rrrrlrrl'.FS::UI::Web::cust_aligns(), 'links' => [ '', $cust_bill_link, + $cust_bill_link, + $cust_bill_link, + $cust_pay_link, + $cust_pay_link, $cust_pay_link, '', ( map { $_ ne 'Cust. Status' ? $cust_link : '' } @@ -44,6 +44,10 @@ '', '', '', + '', + '', + '', + '', FS::UI::Web::cust_colors(), ], 'style' => [ @@ -51,6 +55,10 @@ '', '', '', + '', + '', + '', + '', FS::UI::Web::cust_styles(), ], ) @@ -93,9 +101,11 @@ my $sql_query = { 'table' => 'cust_bill_pay', 'select' => join(', ', 'cust_bill_pay.*', - 'cust_pay.paid AS cust_pay_paid', 'cust_bill._date AS cust_bill_date', - #'cust_bill.charged AS cust_bill_charged', + 'cust_bill.charged AS cust_bill_charged', + 'cust_pay.paid AS cust_pay_paid', + 'cust_pay._date AS cust_pay_date', + 'cust_pay.otaker AS cust_pay_otaker', 'cust_pay.custnum AS custnum', 'cust_main.custnum AS cust_main_custnum', FS::UI::Web::cust_sql_fields(), 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/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi index ee4c82d8e..83cd206cb 100755 --- a/httemplate/search/cust_pkg.cgi +++ b/httemplate/search/cust_pkg.cgi @@ -143,7 +143,6 @@ ), '', ], - 'extra_choices_callback'=> $extra_choices, ) %> <%init> @@ -253,22 +252,32 @@ sub time_or_blank { }; } -my $html_init = include('/elements/init_overlib.html'); - -my $extra_choices = sub { +my $html_init = sub { my $query = shift; - - return '' unless - $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); - - '<BR><BR>'. - include( '/elements/popup_link.html', - 'label' => 'Change these packages', - 'action' => "${p}misc/bulk_change_pkg.cgi?$query", - 'actionlabel' => 'Change Packages', - 'width' => 763, - 'height' => 336, - ); + my $text = ''; + my $curuser = $FS::CurrentUser::CurrentUser; + + if ( $curuser->access_right('Bulk change customer packages') ) { + $text .= include('/elements/init_overlib.html'). + include( '/elements/popup_link.html', + 'label' => 'Change these packages', + 'action' => "${p}misc/bulk_change_pkg.cgi?$query", + 'actionlabel' => 'Change Packages', + 'width' => 569, + 'height' => 210, + ). '<BR>'; + + if ( $curuser->access_right('Edit customer package dates') ) { + $text .= include( '/elements/popup_link.html', + 'label' => 'Increment next bill date', + 'action' => "${p}misc/bulk_pkg_increment_bill.cgi?$query", + 'actionlabel' => 'Increment Bill Date', + 'width' => 569, + 'height' => 210, + ). '<BR>'; + } + } + return $text; }; </%init> 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/elements/search-html.html b/httemplate/search/elements/search-html.html index c0bb721f7..6b915a617 100644 --- a/httemplate/search/elements/search-html.html +++ b/httemplate/search/elements/search-html.html @@ -144,11 +144,6 @@ % $cgi->param('_type', 'html-print'); as <A HREF="<% $cgi->self_url %>">printable copy</A> - <% $opt{'extra_choices_callback'} - ? &{$opt{'extra_choices_callback'}}($cgi->query_string) - : '' - %> - </TD> % $cgi->param('_type', "html" ); % } 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/inventory_item.html b/httemplate/search/inventory_item.html index cd37e267b..ba449ecd7 100644 --- a/httemplate/search/inventory_item.html +++ b/httemplate/search/inventory_item.html @@ -9,6 +9,7 @@ 'hashref' => { 'classnum' => $classnum }, 'select' => join(', ', 'inventory_item.*', + 'part_svc.svcdb', 'cust_main.custnum', FS::UI::Web::cust_sql_fields(), ), @@ -103,7 +104,16 @@ my $count_query = my $link = sub { my $inventory_item = shift; if ( $inventory_item->svcnum ) { - [ "${p}view/svc_acct.cgi?", 'svcnum' ]; + + #[ "${p}view/svc_acct.cgi?", 'svcnum' ]; + my $url = svc_url( + 'm' => $m, + 'action' => 'view', + #'svcdb' => $inventory_item->cust_svc->part_svc->svcdb, + 'svcdb' => $inventory_item->svcdb, #we have it from the joined search + 'query' => '', + ); + [ $url, 'svcnum' ]; } else { ''; } 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/search/report_prepaid_income.html b/httemplate/search/report_prepaid_income.html index d707bd81b..04801beee 100644 --- a/httemplate/search/report_prepaid_income.html +++ b/httemplate/search/report_prepaid_income.html @@ -44,7 +44,7 @@ <SCRIPT TYPE="text/javascript"> Calendar.setup({ inputField: "date_text", - ifFormat: "%m/%d/%Y", + ifFormat: "<% $date_format %>", button: "date_button", align: "BR" }); @@ -58,4 +58,7 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); +my $conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; + </%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/payment_history.html b/httemplate/view/cust_main/payment_history.html index 56a2c4dde..0dc4c41d5 100644 --- a/httemplate/view/cust_main/payment_history.html +++ b/httemplate/view/cust_main/payment_history.html @@ -205,11 +205,11 @@ <TR ID="balance_forward_row"> <TD CLASS="grid" BGCOLOR="#dddddd"> - <% time2str("%D",$date) %> + <% time2str($date_format, $date) %> </TD> <TD CLASS="grid" BGCOLOR="#dddddd"> - <I>Starting balance on <% time2str("%D",$date) %></I> + <I>Starting balance on <% time2str($date_format, $date) %></I> (<A HREF="javascript:void(0);" onClick="show_history();">show prior history</A>) </TD> @@ -297,7 +297,7 @@ <A NAME="<% $target %>"> % } - <% time2str("%D",$item->{'date'}) %> + <% time2str($date_format, $item->{'date'}) %> % if ( $target && $target{$target} == 1 ) { </A> @@ -355,6 +355,7 @@ my( $cust_main ) = @_; my $custnum = $cust_main->custnum; my $conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; my $curuser = $FS::CurrentUser::CurrentUser; @@ -376,7 +377,7 @@ my @history = (); my %opt = ( ( map { $_ => scalar($conf->config($_)) } - qw( card_refund-days ) + qw( card_refund-days date_format ) ), ( map { $_ => $conf->exists($_) } qw( deleteinvoices deletepayments deleterefunds pkg-balances ) diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html index 058c6f536..fa5838e4e 100644 --- a/httemplate/view/cust_main/payment_history/credit.html +++ b/httemplate/view/cust_main/payment_history/credit.html @@ -4,6 +4,8 @@ by <% $cust_credit->otaker %><% "$reason$desc$apply$delete$unapply" %> my( $cust_credit, %opt ) = @_; +my $date_format = $opt{'date_format'} || '%m/%d/%Y'; + my $curuser = $FS::CurrentUser::CurrentUser; my @cust_credit_bill = $cust_credit->cust_credit_bill; @@ -56,7 +58,7 @@ if ( scalar(@cust_credit_bill) == 0 && scalar(@cust_credit_refund) == 1 && $cust_credit->credited == 0 ) { #applied to one refund - $desc .= ' refunded on '. time2str("%D", $cust_credit_refund[0]->_date); + $desc .= ' refunded on '. time2str($date_format, $cust_credit_refund[0]->_date); } else { #complicated $desc .= '<BR>'; @@ -67,11 +69,11 @@ if ( scalar(@cust_credit_bill) == 0 '$'. $app->amount. ' '. $app->applied_to_invoice. '<BR>'; - #' on '. time2str("%D", $app->_date). + #' on '. time2str($date_format, $app->_date). } elsif ( $app->isa('FS::cust_credit_refund') ) { $desc .= ' '. '$'. $app->amount. - ' refunded on '. time2str("%D", $app->_date). + ' refunded on '. time2str($date_format, $app->_date). '<BR>'; } else { die "$app is not a FS::cust_credit_bill or a FS::cust_credit_refund"; diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html index a4a349bb8..53fc0dad3 100644 --- a/httemplate/view/cust_main/payment_history/payment.html +++ b/httemplate/view/cust_main/payment_history/payment.html @@ -4,6 +4,8 @@ my( $cust_pay, %opt ) = @_; +my $date_format = $opt{'date_format'} || '%m/%d/%Y'; + my $curuser = $FS::CurrentUser::CurrentUser; my $payby = $cust_pay->payby; @@ -79,7 +81,7 @@ if ( scalar(@cust_bill_pay) == 0 && scalar(@cust_pay_refund) == 1 && $cust_pay->unapplied == 0 ) { #applied to one refund - $desc .= ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date); + $desc .= ' refunded on '. time2str($date_format, $cust_pay_refund[0]->_date); } else { #complicated $desc .= '<BR>'; @@ -90,11 +92,11 @@ if ( scalar(@cust_bill_pay) == 0 '$'. $app->amount. ' '. $app->applied_to_invoice. '<BR>'; - #' on '. time2str("%D", $cust_bill_pay->_date). + #' on '. time2str($date_format, $cust_bill_pay->_date). } elsif ( $app->isa('FS::cust_pay_refund') ) { $desc .= ' '. '$'. $app->amount. - ' refunded on '. time2str("%D", $app->_date). + ' refunded on '. time2str($date_format, $app->_date). '<BR>'; } else { die "$app is not a FS::cust_bill_pay or FS::cust_pay_refund"; diff --git a/httemplate/view/cust_main/payment_history/voided_payment.html b/httemplate/view/cust_main/payment_history/voided_payment.html index 610372721..be68ff091 100644 --- a/httemplate/view/cust_main/payment_history/voided_payment.html +++ b/httemplate/view/cust_main/payment_history/voided_payment.html @@ -1,10 +1,12 @@ <DEL>Payment <% $info %></DEL> -<I>voided <% time2str("%D", $cust_pay_void->void_date) %> +<I>voided <% time2str($date_format, $cust_pay_void->void_date) %> by <% $cust_pay_void->otaker %></I><% $unvoid %> <%init> my( $cust_pay_void, %opt ) = @_; +my $date_format = $opt{'date_format'} || '%m/%d/%Y'; + my $curuser = $FS::CurrentUser::CurrentUser; my $payby = $cust_pay_void->payby; 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/cust_svc.cgi b/httemplate/view/cust_svc.cgi new file mode 100644 index 000000000..8ccfce3ff --- /dev/null +++ b/httemplate/view/cust_svc.cgi @@ -0,0 +1,23 @@ +<% $cgi->redirect(popurl(1)."$svcdb.cgi?". $svcnum ) %> +<%init> + +#needed here? we're just redirecting. i guess it could reveal the svcdb of a +#svcnum... oooooo scary. not. +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('View customer services'); + +#some false laziness w/svc_*.cgi + +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/; +my $svcnum = $1; +my $cust_svc = qsearchs( 'cust_svc', { 'svcnum' => $svcnum } ); +die "Unknown svcnum" unless $cust_svc; + +my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } ); +die "Unknown svcpart" unless $part_svc; + +my $svcdb = $part_svc->svcdb; + +</%init> + diff --git a/httemplate/view/elements/svc_export_settings.html b/httemplate/view/elements/svc_export_settings.html new file mode 100644 index 000000000..c5f2555bd --- /dev/null +++ b/httemplate/view/elements/svc_export_settings.html @@ -0,0 +1,34 @@ +% if ( $FS::CurrentUser::CurrentUser->option('export_getsettings') ) { + +% my ( $settings, $defaults ) = $svc_x->export_getsettings; +% if ( keys %$settings ) { + +%# a way to label this "Communigate pro settings".. just a config maybe... eh, +%# its just for devel + External settings + <% ntable('#cccccc',2) %> + +% foreach my $key ( sort {$defaults->{$a} <=> $defaults->{$b} or $a cmp $b} +% keys %$settings +% ) +% { + <TR> + <TD ALIGN="right"><% $key |h %></TD> + <TD BGCOLOR="<% $defaults->{$key} ? '#eeeeee' : '#ffffff' %>"> + <% $defaults->{$key} ? '<I>' : '<B>' %> + <% $settings->{$key} |h %> + <% $defaults->{$key} ? '</I>' : '</B>' %> + </TD> + </TR> +% } + + </TABLE> + <BR> + +% } +% } +<%init> + +my $svc_x = shift; + +</%init> diff --git a/httemplate/view/elements/tr.html b/httemplate/view/elements/tr.html new file mode 100644 index 000000000..e2ec7d42f --- /dev/null +++ b/httemplate/view/elements/tr.html @@ -0,0 +1,9 @@ +<TR> + <TD ALIGN="right"><% $opt{'label'} %></TD> + <TD BGCOLOR="#ffffff"><% $opt{'value'} %></TD> +</TR> +<%init> + +my %opt = @_; + +</%init> diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index 44a2aa611..9135e67e9 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -14,328 +14,63 @@ } </SCRIPT> - <% include("/elements/header.html",'Account View', menubar( + <% include("/elements/header.html",'View account', menubar( "Cancel this (unaudited) account" => "javascript:areyousure(\'${p}misc/cancel-unaudited.cgi?$svcnum\')", )) %> % } -% if ( $part_svc->part_export_usage ) { -% -% my $last_bill; -% my %plandata; -% if ( $cust_pkg ) { -% #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really -% #belong in plan data -% %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } -% split("\n", $cust_pkg->part_pkg->plandata ); -% -% $last_bill = $cust_pkg->last_bill; -% } else { -% $last_bill = 0; -% %plandata = (); -% } -% -% my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time ); -% my $hour = int($seconds/3600); -% my $min = int( ($seconds%3600) / 60 ); -% my $sec = $seconds%60; -% -% my $input = $svc_acct->attribute_since_sqlradacct( -% $last_bill, time, 'AcctInputOctets' -% ) / 1048576; -% my $output = $svc_acct->attribute_since_sqlradacct( -% $last_bill, time, 'AcctOutputOctets' -% ) / 1048576; -% -% +<% include( 'svc_acct/radius_usage.html', + 'svc_acct' => $svc_acct, + 'part_svc' => $part_svc, + 'cust_pkg' => $cust_pkg, + %gopt, + ) +%> - - RADIUS session information<BR> - <% ntable('#cccccc',2) %> - <TR><TD BGCOLOR="#ffffff"> -% if ( $seconds ) { - - Online <B><% $hour %></B>h <B><% $min %></B>m <B><% $sec %></B>s -% } else { - - Has not logged on -% } -% if ( $cust_pkg ) { - - since last bill (<% time2str('%a %b %o %Y', $last_bill) %>) -% if ( length($plandata{recur_included_hours}) ) { - - - <% $plandata{recur_included_hours} %> total hours in plan -% } - - <BR> -% } else { - - (no billing cycle available for unaudited account)<BR> -% } - - - Upload: <B><% sprintf("%.3f", $input) %></B> megabytes<BR> - Download: <B><% sprintf("%.3f", $output) %></B> megabytes<BR> - Last Login: <B><% $svc_acct->last_login_text %></B><BR> -% my $href = qq!<A HREF="${p}search/sqlradius.cgi?svcnum=$svcnum!; - - View session detail: - <% $href %>;begin=<% $last_bill %>">this billing cycle</A> - | <% $href %>;begin=<% time-15552000 %>">past six months</A> - | <% $href %>">all sessions</A> - - </TD></TR></TABLE><BR> -% } - -% my @part_svc = (); -% if ($FS::CurrentUser::CurrentUser->access_right('Change customer service')) { - - <SCRIPT TYPE="text/javascript"> - function enable_change () { - if ( document.OneTrueForm.svcpart.selectedIndex > 1 ) { - document.OneTrueForm.submit.disabled = false; - } else { - document.OneTrueForm.submit.disabled = true; - } - } - </SCRIPT> - - <FORM NAME="OneTrueForm" ACTION="<%$p%>edit/process/cust_svc.cgi"> - <INPUT TYPE="hidden" NAME="svcnum" VALUE="<% $svcnum %>"> - <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> - -% #print qq!<BR><A HREF="../misc/sendconfig.cgi?$svcnum">Send account information</A>!; -% -% if ( $pkgnum ) { -% @part_svc = grep { $_->svcdb eq 'svc_acct' -% && $_->svcpart != $part_svc->svcpart } -% $cust_pkg->available_part_svc; -% } else { -% @part_svc = qsearch('part_svc', { -% svcdb => 'svc_acct', -% disabled => '', -% svcpart => { op=>'!=', value=>$part_svc->svcpart }, -% } ); -% } -% -% } +<% include( 'svc_acct/change_svc_form.html', + 'part_svc' => \@part_svc, + 'svcnum' => $svcnum, + 'pkgnum' => $pkgnum, + %gopt, + ) +%> Service #<B><% $svcnum %></B> | <A HREF="<%$p%>edit/svc_acct.cgi?<%$svcnum%>">Edit this service</A> -% if ( @part_svc ) { - -| <SELECT NAME="svcpart" onChange="enable_change()"> - <OPTION VALUE="">Change service</OPTION> - <OPTION VALUE="">--------------</OPTION> -% foreach my $opt_part_svc ( @part_svc ) { - - <OPTION VALUE="<% $opt_part_svc->svcpart %>"><% $opt_part_svc->svc %></OPTION> -% } - - </SELECT> - <INPUT NAME="submit" TYPE="submit" VALUE="Change" disabled> - -% } - - -<% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %> - -<TR> - <TD ALIGN="right">Service</TD> - <TD BGCOLOR="#ffffff"><% $part_svc->svc %></TD> -</TR> -<TR> - <TD ALIGN="right">Username</TD> - <TD BGCOLOR="#ffffff"><% $svc_acct->username %></TD> -</TR> -<TR> - <TD ALIGN="right">Domain</TD> - <TD BGCOLOR="#ffffff"><% $domain %></TD> -</TR> - -<TR> - <TD ALIGN="right">Password</TD> - <TD BGCOLOR="#ffffff"> -% my $password = $svc_acct->get_cleartext_password; -% if ( $password =~ /^\*\w+\* (.*)$/ ) { -% $password = $1; -% +<% include( 'svc_acct/change_svc.html', + 'part_svc' => \@part_svc, + %gopt, + ) +%> - <I>(login disabled)</I> -% } -% if ( !$password and -% $svc_acct->_password_encryption ne 'plain' and -% $svc_acct->_password ) { - <I>(<% uc($svc_acct->_password_encryption) %> encrypted)</I> -% } -% elsif ( $conf->exists('showpasswords') ) { - - <PRE><% encode_entities($password) %></PRE> -% } else { - - <I>(hidden)</I> -% } - - - </TD> -</TR> -% $password = ''; -% if ( $conf->exists('security_phrase') ) { -% my $sec_phrase = $svc_acct->sec_phrase; -% - - <TR> - <TD ALIGN="right">Security phrase</TD> - <TD BGCOLOR="#ffffff"><% $svc_acct->sec_phrase %></TD> - </TR> -% } -% if ( $svc_acct->popnum ) { -% my $svc_acct_pop = qsearchs('svc_acct_pop',{'popnum'=>$svc_acct->popnum}); -% +<% include( 'svc_acct/basics.html', + 'svc_acct' => $svc_acct, + 'part_svc' => $part_svc, + %gopt, + ) +%> - <TR> - <TD ALIGN="right">Access number</TD> - <TD BGCOLOR="#ffffff"><% $svc_acct_pop->text %></TD> - </TR> -% } -% if ($svc_acct->uid ne '') { - - <TR> - <TD ALIGN="right">UID</TD> - <TD BGCOLOR="#ffffff"><% $svc_acct->uid %></TD> - </TR> -% } -% if ($svc_acct->gid ne '') { - - <TR> - <TD ALIGN="right">GID</TD> - <TD BGCOLOR="#ffffff"><% $svc_acct->gid %></TD> - </TR> -% } -% if ($svc_acct->finger ne '') { - - <TR> - <TD ALIGN="right">Real Name</TD> - <TD BGCOLOR="#ffffff"><% $svc_acct->finger %></TD> - </TR> -% } -% if ($svc_acct->dir ne '') { - - <TR> - <TD ALIGN="right">Home directory</TD> - <TD BGCOLOR="#ffffff"><% $svc_acct->dir %></TD> - </TR> -% } -% if ($svc_acct->shell ne '') { - - <TR> - <TD ALIGN="right">Shell</TD> - <TD BGCOLOR="#ffffff"><% $svc_acct->shell %></TD> - </TR> -% } -% if ($svc_acct->quota ne '') { - - <TR> - <TD ALIGN="right">Quota</TD> - <TD BGCOLOR="#ffffff"><% $svc_acct->quota %></TD> - </TR> -% } -% if ($svc_acct->slipip) { - - <TR> - <TD ALIGN="right">IP address</TD> - <TD BGCOLOR="#ffffff"> - <% ( $svc_acct->slipip eq "0.0.0.0" || $svc_acct->slipip eq '0e0' ) - ? "<I>(Dynamic)</I>" - : $svc_acct->slipip - %> - </TD> - </TR> -% } -% my %ulabel = ( seconds => 'Time', -% upbytes => 'Upload bytes', -% downbytes => 'Download bytes', -% totalbytes => 'Total bytes', -% ); -% foreach my $uf ( keys %ulabel ) { -% my $tf = $uf . "_threshold"; -% if ( $svc_acct->$uf ne '' ) { -% my $v = $uf eq 'seconds' -% #? (($svc_acct->$uf < 0 ? '-' : ''). duration_exact($svc_acct->$uf) ) -% ? ($svc_acct->$uf < 0 ? '-' : ''). -% int(abs($svc_acct->$uf)/3600). "hr ". -% sprintf("%02d",(abs($svc_acct->$uf)%3600)/60). "min" -% : FS::UI::bytecount::display_bytecount($svc_acct->$uf); - <TR> - <TD ALIGN="right"><% $ulabel{$uf} %> remaining</TD> - <TD BGCOLOR="#ffffff"><% $v %></TD> - </TR> - -% } -% } -% foreach my $attribute ( grep /^radius_/, $svc_acct->fields ) { -% $attribute =~ /^radius_(.*)$/; -% my $pattribute = $FS::raddb::attrib{$1}; -% - - <TR> - <TD ALIGN="right">Radius (reply) <% $pattribute %></TD> - <TD BGCOLOR="#ffffff"><% $svc_acct->getfield($attribute) %></TD> - </TR> -% } -% foreach my $attribute ( grep /^rc_/, $svc_acct->fields ) { -% $attribute =~ /^rc_(.*)$/; -% my $pattribute = $FS::raddb::attrib{$1}; -% - - <TR> - <TD ALIGN="right">Radius (check) <% $pattribute %></TD> - <TD BGCOLOR="#ffffff"><% $svc_acct->getfield($attribute) %></TD> - </TR> -% } - - -<TR> - <TD ALIGN="right">RADIUS groups</TD> - <TD BGCOLOR="#ffffff"><% join('<BR>', $svc_acct->radius_groups) %></TD> -</TR> -% -%# Can this be abstracted further? Maybe a library function like -%# widget('HTML', 'view', $svc_acct) ? It would definitely make UI -%# style management easier. -% -% foreach (sort { $a cmp $b } $svc_acct->virtual_fields) { - - <% $svc_acct->pvf($_)->widget('HTML', 'view', $svc_acct->getfield($_)) %> -% } - - -</TABLE></TD></TR></TABLE> </FORM> +<BR> + +<% include( 'svc_acct/hosting.html', + %gopt, + ) +%> + +%#remove this? does anybody even use it? it was a misunderstood customer +%#request IIRC? +% my $conf = new FS::Conf; +% if ( $conf->exists('svc_acct-notes') ) { +% warn 'WARNING: svc_acct-notes deprecated\n'; +<% join("<BR>", $conf->config('svc_acct-notes') ) %> <BR><BR> - -% if ( @svc_www ) { - Hosting - <% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %> -% foreach my $svc_www (@svc_www) { -% my($label, $value) = $svc_www->cust_svc->label; -% my $link = $p. 'view/svc_www.cgi?'. $svc_www->svcnum; - <TR> - <TD BGCOLOR="#ffffff"> - <A HREF="<% $link %>"><% "$label: $value" %></A> - </TD> - </TR> -% } - </TABLE></TD></TR></TABLE> - <BR><BR> % } -<% join("<BR>", $conf->config('svc_acct-notes') ) %> -<BR><BR> +<% include('elements/svc_export_settings.html', $svc_acct) %> <% joblisting({'svcnum'=>$svcnum}, 1) %> @@ -345,8 +80,6 @@ Service #<B><% $svcnum %></B> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('View customer services'); -my $conf = new FS::Conf; - my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '. ' LEFT JOIN cust_pkg USING ( pkgnum ) '. ' LEFT JOIN cust_main USING ( custnum ) '; @@ -382,25 +115,27 @@ my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } ); die "Unknown svcpart" unless $part_svc; my $svc = $part_svc->svc; -die 'Empty domsvc for svc_acct.svcnum '. $svc_acct->svcnum - unless $svc_acct->domsvc; -my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $svc_acct->domsvc } ); -die 'Unknown domain (domsvc '. $svc_acct->domsvc. - ' for svc_acct.svcnum '. $svc_acct->svcnum. ')' - unless $svc_domain; -my $domain = $svc_domain->domain; +my @part_svc = (); +if ($FS::CurrentUser::CurrentUser->access_right('Change customer service')) { + + if ( $pkgnum ) { + @part_svc = grep { $_->svcdb eq 'svc_acct' + && $_->svcpart != $part_svc->svcpart } + $cust_pkg->available_part_svc; + } else { + @part_svc = qsearch('part_svc', { + svcdb => 'svc_acct', + disabled => '', + svcpart => { op=>'!=', value=>$part_svc->svcpart }, + } ); + } -my @svc_www = qsearch({ - 'select' => 'svc_www.*', - 'table' => 'svc_www', - 'addl_from' => $addl_from, - 'hashref' => { 'usersvc' => $svcnum }, - #XXX shit outta luck if you somehow got them linked across agents - # maybe we should show but not link to them? kinda makes sense... - # (maybe a specific ACL for this situation???) - 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql( - 'null_right' => 'View/link unlinked services' - ), -}); +} + +my $communigate = scalar($part_svc->part_export('communigate_pro')); + # || scalar($part_svc->part_export('communigate_pro_singledomain')); + +my %gopt = ( 'communigate' => $communigate, + ); </%init> diff --git a/httemplate/view/svc_acct/basics.html b/httemplate/view/svc_acct/basics.html new file mode 100644 index 000000000..92b9ad7fe --- /dev/null +++ b/httemplate/view/svc_acct/basics.html @@ -0,0 +1,158 @@ +<% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %> + +<% include('/view/elements/tr.html', label=>'Service', value=>$part_svc->svc) %> +<% include('/view/elements/tr.html', label=>'Username', value=>$svc_acct->username) %> +<% include('/view/elements/tr.html', label=>'Domain', value=>$domain) %> + +% if ( $opt{'communigate'} ) { + <% include('/view/elements/tr.html', label=>'Aliases', value=>$svc_acct->cgp_aliases) %> +%} + +% if ( $svc_acct->pbxsvc ) { + <% include('/view/elements/tr.html', label=>'PBX', value=>$svc_acct->pbx_title) %> +%} + +% my $show_pw = ''; +% my $password = $svc_acct->get_cleartext_password; +% if ( $password =~ /^\*\w+\* (.*)$/ ) { +% $password = $1; +% $show_pw .= '<I>(login disabled)</I> '; +% } +% if ( ! $password +% && $svc_acct->_password_encryption ne 'plain' +% && $svc_acct->_password +% ) +% { +% $show_pw .= '<I>('. uc($svc_acct->_password_encryption). ' encrypted)</I>'; +% } elsif ( $conf->exists('showpasswords') ) { +% $show_pw .= '<PRE>'. encode_entities($password). '</PRE>'; +% } else { +% $show_pw .= '<I>(hidden)</I>'; +% } +% $password = ''; +<% include('/view/elements/tr.html', label=>'Password', value=>$show_pw) %> + + +% if ( $conf->exists('security_phrase') ) { + <%include('/view/elements/tr.html', label=>'Security phrase', value=>$svc_acct->sec_phrase)%> +% } + +% if ( $svc_acct->popnum ) { +% my $svc_acct_pop = qsearchs('svc_acct_pop',{'popnum'=>$svc_acct->popnum}); + <% include('/view/elements/tr.html', label=>'Access number', value=>$svc_acct_pop->text) %> +% } + +% if ($svc_acct->uid ne '') { + <% include('/view/elements/tr.html', label=>'UID', value=>$svc_acct->uid) %> +% } + +% if ($svc_acct->gid ne '') { + <% include('/view/elements/tr.html', label=>'GID', value=>$svc_acct->gid) %> +% } + +% if ($svc_acct->finger ne '') { + <% include('/view/elements/tr.html', label=>'Real Name', value=>$svc_acct->finger) %> +% } + +% if ($svc_acct->dir ne '') { + <% include('/view/elements/tr.html', label=>'Home directory', value=>$svc_acct->dir) %> +% } + +% if ($svc_acct->shell ne '') { + <% include('/view/elements/tr.html', label=>'Shell', value=>$svc_acct->shell) %> +% } + +% if ($svc_acct->quota ne '' && ! $opt{'communigate'} ) { + + <% include('/view/elements/tr.html', label=>'Quota', value=>$svc_acct->quota) %> + +% } elsif ( $opt{'communigate'} ) { + + <% include('/view/elements/tr.html', label=>'Mailbox type', value=>$svc_acct->cgp_type) %> + + <% include('/view/elements/tr.html', label=>'Enabled services', + value=>$svc_acct->cgp_accessmodes ) %> + + <% include('/view/elements/tr.html', label=>'Mail storage limit', + value=>$svc_acct->quota ) %> + + <% include('/view/elements/tr.html', label=>'File storage limit', + value=>$svc_acct->file_quota ) %> + + <% include('/view/elements/tr.html', label=>'Number of files limit', + value=>$svc_acct->file_maxnum ) %> + + <% include('/view/elements/tr.html', label=>'File size limit', + value=>$svc_acct->file_maxsize ) %> + + <% include('/view/elements/tr.html', label=>'Message delete method', + value=>$svc_acct->cgp_deletemode ) %> + + <% include('/view/elements/tr.html', label=>'On logout remove trash', + value=>$svc_acct->cgp_emptytrash ) %> + + +% } + +% if ($svc_acct->slipip) { + <% include('/view/elements/tr.html', + label=>'IP address', + value=> ( $svc_acct->slipip eq "0.0.0.0" || $svc_acct->slipip eq '0e0' ) + ? "<I>(Dynamic)</I>" + : $svc_acct->slipip + ) + %> +% } + +<% include('usage.html', + 'svc_acct' => $svc_acct, + ) +%> + +% foreach my $attribute ( grep /^radius_/, $svc_acct->fields ) { +% $attribute =~ /^radius_(.*)$/; +% my $pattribute = $FS::raddb::attrib{$1}; + <% include('/view/elements/tr.html', label=>"Radius (reply) $pattribute", + value=>$svc_acct->getfield($attribute) + ) + %> +% } + +% foreach my $attribute ( grep /^rc_/, $svc_acct->fields ) { +% $attribute =~ /^rc_(.*)$/; +% my $pattribute = $FS::raddb::attrib{$1}; + <% include('/view/elements/tr.html', label=>"Radius (check) $pattribute", + value=>$svc_acct->getfield($attribute) + ) + %> +% } + +<% include('/view/elements/tr.html', label=>'RADIUS groups', + value=>join('<BR>', $svc_acct->radius_groups) ) %> + +%# Can this be abstracted further? Maybe a library function like +%# widget('HTML', 'view', $svc_acct) ? It would definitely make UI +%# style management easier. +% foreach (sort { $a cmp $b } $svc_acct->virtual_fields) { + <% $svc_acct->pvf($_)->widget('HTML', 'view', $svc_acct->getfield($_)) %> +% } + +</TABLE></TD></TR></TABLE> +<%init> + +my %opt = @_; + +my $conf = new FS::Conf; + +my $svc_acct = $opt{'svc_acct'}; +my $part_svc = $opt{'part_svc'}; + +die 'Empty domsvc for svc_acct.svcnum '. $svc_acct->svcnum + unless $svc_acct->domsvc; +my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $svc_acct->domsvc } ); +die 'Unknown domain (domsvc '. $svc_acct->domsvc. + ' for svc_acct.svcnum '. $svc_acct->svcnum. ')' + unless $svc_domain; +my $domain = $svc_domain->domain; + +</%init> diff --git a/httemplate/view/svc_acct/change_svc.html b/httemplate/view/svc_acct/change_svc.html new file mode 100644 index 000000000..33d44a713 --- /dev/null +++ b/httemplate/view/svc_acct/change_svc.html @@ -0,0 +1,21 @@ +% if ( @part_svc || $opt{'showall'} ) { + +| <SELECT NAME="svcpart" onChange="enable_change()"> + <OPTION VALUE="">Change service</OPTION> + <OPTION VALUE="">--------------</OPTION> +% foreach my $opt_part_svc ( @part_svc ) { + + <OPTION VALUE="<% $opt_part_svc->svcpart %>"><% $opt_part_svc->svc %></OPTION> +% } + + </SELECT> + <INPUT NAME="submit" TYPE="submit" VALUE="Change" disabled> + +% } + +<%init> + +my %opt = @_; +my @part_svc = @{ $opt{'part_svc'} }; + +</%init> diff --git a/httemplate/view/svc_acct/change_svc_form.html b/httemplate/view/svc_acct/change_svc_form.html new file mode 100644 index 000000000..4f10922ba --- /dev/null +++ b/httemplate/view/svc_acct/change_svc_form.html @@ -0,0 +1,23 @@ +% if ( @part_svc || $opt{'showall'} ) { + <SCRIPT TYPE="text/javascript"> + function enable_change () { + if ( document.OneTrueForm.svcpart.selectedIndex > 1 ) { + document.OneTrueForm.submit.disabled = false; + } else { + document.OneTrueForm.submit.disabled = true; + } + } + </SCRIPT> + + <FORM NAME="OneTrueForm" ACTION="<%$p%>edit/process/cust_svc.cgi"> + <INPUT TYPE="hidden" NAME="svcnum" VALUE="<% $svcnum %>"> + <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> +% } +<%init> + +my %opt = @_; +my @part_svc = @{ $opt{'part_svc'} }; +my $svcnum = $opt{'svcnum'}; +my $pkgnum = $opt{'pkgnum'}; + +</%init> diff --git a/httemplate/view/svc_acct/hosting.html b/httemplate/view/svc_acct/hosting.html new file mode 100644 index 000000000..1d83603b7 --- /dev/null +++ b/httemplate/view/svc_acct/hosting.html @@ -0,0 +1,38 @@ +% if ( @svc_www || $opt{'showall'} ) { + Hosting + <% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %> +% foreach my $svc_www (@svc_www) { +% my($label, $value) = $svc_www->cust_svc->label; +% my $link = $p. 'view/svc_www.cgi?'. $svc_www->svcnum; + <TR> + <TD BGCOLOR="#ffffff"> + <A HREF="<% $link %>"><% "$label: $value" %></A> + </TD> + </TR> +% } + </TABLE></TD></TR></TABLE> + <BR><BR> +% } +<%init> + +my %opt = @_; + +#false laziness w/view_svc_acct.cgi and a zillion other places +my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '. + ' LEFT JOIN cust_pkg USING ( pkgnum ) '. + ' LEFT JOIN cust_main USING ( custnum ) '; + +my @svc_www = qsearch({ + 'select' => 'svc_www.*', + 'table' => 'svc_www', + 'addl_from' => $addl_from, + 'hashref' => { 'usersvc' => $opt{'svcnum'} }, + #XXX shit outta luck if you somehow got them linked across agents + # maybe we should show but not link to them? kinda makes sense... + # (maybe a specific ACL for this situation???) + 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql( + 'null_right' => 'View/link unlinked services' + ), +}); + +</%init> diff --git a/httemplate/view/svc_acct/radius_usage.html b/httemplate/view/svc_acct/radius_usage.html new file mode 100644 index 000000000..e2253a34a --- /dev/null +++ b/httemplate/view/svc_acct/radius_usage.html @@ -0,0 +1,77 @@ +% if ( $part_svc->part_export_usage ) { +% +% my $last_bill; +% my %plandata; +% if ( $cust_pkg ) { +% #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really +% #belong in plan data +% %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } +% split("\n", $cust_pkg->part_pkg->plandata ); +% +% $last_bill = $cust_pkg->last_bill; +% } else { +% $last_bill = 0; +% %plandata = (); +% } +% +% my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time ); +% my $hour = int($seconds/3600); +% my $min = int( ($seconds%3600) / 60 ); +% my $sec = $seconds%60; +% +% my $input = $svc_acct->attribute_since_sqlradacct( +% $last_bill, time, 'AcctInputOctets' +% ) / 1048576; +% my $output = $svc_acct->attribute_since_sqlradacct( +% $last_bill, time, 'AcctOutputOctets' +% ) / 1048576; +% +% + + + RADIUS session information<BR> + <% ntable('#cccccc',2) %> + <TR><TD BGCOLOR="#ffffff"> +% if ( $seconds ) { + + Online <B><% $hour %></B>h <B><% $min %></B>m <B><% $sec %></B>s +% } else { + + Has not logged on +% } +% if ( $cust_pkg ) { + + since last bill (<% time2str('%a %b %o %Y', $last_bill) %>) +% if ( length($plandata{recur_included_hours}) ) { + + - <% $plandata{recur_included_hours} %> total hours in plan +% } + + <BR> +% } else { + + (no billing cycle available for unaudited account)<BR> +% } + + + Upload: <B><% sprintf("%.3f", $input) %></B> megabytes<BR> + Download: <B><% sprintf("%.3f", $output) %></B> megabytes<BR> + Last Login: <B><% $svc_acct->last_login_text %></B><BR> +% my $href = qq!<A HREF="${p}search/sqlradius.cgi?svcnum=!. $svc_acct->svcnum; + + View session detail: + <% $href %>;begin=<% $last_bill %>">this billing cycle</A> + | <% $href %>;begin=<% time-15552000 %>">past six months</A> + | <% $href %>">all sessions</A> + + </TD></TR></TABLE><BR> +% } +<%init> + +my %opt = @_; + +my $svc_acct = $opt{'svc_acct'}; +my $part_svc = $opt{'part_svc'}; +my $cust_pkg = $opt{'cust_pkg'}; + +</%init> diff --git a/httemplate/view/svc_acct/usage.html b/httemplate/view/svc_acct/usage.html new file mode 100644 index 000000000..9758d8332 --- /dev/null +++ b/httemplate/view/svc_acct/usage.html @@ -0,0 +1,27 @@ +% my %ulabel = ( seconds => 'Time', +% upbytes => 'Upload bytes', +% downbytes => 'Download bytes', +% totalbytes => 'Total bytes', +% ); +% foreach my $uf ( keys %ulabel ) { +% my $tf = $uf . "_threshold"; +% if ( $svc_acct->$uf ne '' ) { +% my $v = $uf eq 'seconds' +% #? (($svc_acct->$uf < 0 ? '-' : ''). duration_exact($svc_acct->$uf) ) +% ? ($svc_acct->$uf < 0 ? '-' : ''). +% int(abs($svc_acct->$uf)/3600). "hr ". +% sprintf("%02d",(abs($svc_acct->$uf)%3600)/60). "min" +% : FS::UI::bytecount::display_bytecount($svc_acct->$uf); + <TR> + <TD ALIGN="right"><% $ulabel{$uf} %> remaining</TD> + <TD BGCOLOR="#ffffff"><% $v %></TD> + </TR> + +% } +% } +<%init> + +my %opt = @_; +my $svc_acct = $opt{'svc_acct'}; + +</%init> diff --git a/httemplate/view/svc_domain.cgi b/httemplate/view/svc_domain.cgi index a9fc775ee..3938a3406 100755 --- a/httemplate/view/svc_domain.cgi +++ b/httemplate/view/svc_domain.cgi @@ -1,136 +1,40 @@ -<% include("/elements/header.html",'Domain View', menubar( - ( ( $pkgnum || $custnum ) - ? ( "View this customer (#$display_custnum)" => "${p}view/cust_main.cgi?$custnum", - ) - : ( "Delete this (unaudited) domain" => - "javascript:areyousure('${p}misc/cancel-unaudited.cgi?$svcnum', 'Delete $domain and all records?' )" ) - ) -)) %> +% if ( $custnum ) { -<% include('/elements/error.html') %> - -Service #<% $svcnum %> -<BR>Service: <B><% $part_svc->svc %></B> -<BR>Domain name: <B><% $domain %></B> -% if ($export) { -<BR>Status: <B><% $status %></B> -% if ( $FS::CurrentUser::CurrentUser->access_right('Manage domain registration') ) { -% if ( defined($ops{'register'}) ) { - <A HREF="<% ${p} %>edit/process/domreg.cgi?op=register&svcnum=<% $svcnum %>">Register at <% $registrar->{'name'} %></A> -% } -% if ( defined($ops{'transfer'}) ) { - <A HREF="<% ${p} %>edit/process/domreg.cgi?op=transfer&svcnum=<% $svcnum %>">Transfer to <% $registrar->{'name'} %></A> -% } -% if ( defined($ops{'renew'}) ) { - <A HREF="<% ${p} %>edit/process/domreg.cgi?op=renew&svcnum=<% $svcnum %>&period=1">Renew at <% $registrar->{'name'} %></A> -% } -% if ( defined($ops{'revoke'}) ) { - <A HREF="<% ${p} %>edit/process/domreg.cgi?op=revoke&svcnum=<% $svcnum %>">Revoke</A> -% } -% } -% } +%# <% include("/elements/header.html","View $svcdomain") %> + <% include("/elements/header.html","View domain") %> + <% include( '/elements/small_custview.html', $custnum, '', 1, + "${p}view/cust_main.cgi") %> + <BR> -% if ( $FS::CurrentUser::CurrentUser->access_right('Edit domain catchall') ) { - <BR>Catch all email <A HREF="<% ${p} %>misc/catchall.cgi?<% $svcnum %>">(change)</A>: % } else { - <BR>Catch all email: -% } -<% $email ? "<B>$email</B>" : "<I>(none)<I>" %> -<BR><BR><A HREF="<% ${p} %>misc/whois.cgi?custnum=<%$custnum%>;svcnum=<%$svcnum%>;domain=<%$domain%>">View whois information.</A> -<BR><BR> -<SCRIPT> - function areyousure(href, message) { - if ( confirm(message) == true ) - window.location.href = href; - } - function slave_areyousure() { - return confirm("Remove all records and slave from " + document.SlaveForm.recdata.value + "?"); - } -</SCRIPT> - -% my @records; if ( @records = $svc_domain->domain_record ) { - - <% include('/elements/table-grid.html') %> - -% my $bgcolor1 = '#eeeeee'; -% my $bgcolor2 = '#ffffff'; -% my $bgcolor = $bgcolor2; - - <tr> - <th CLASS="grid" BGCOLOR="#cccccc">Zone</th> - <th CLASS="grid" BGCOLOR="#cccccc">Type</th> - <th CLASS="grid" BGCOLOR="#cccccc">Data</th> - </tr> - -% foreach my $domain_record ( @records ) { -% my $type = $domain_record->rectype eq '_mstr' -% ? "(slave)" -% : $domain_record->recaf. ' '. $domain_record->rectype; - - - <tr> - <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $domain_record->reczone %></td> - <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $type %></td> - <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $domain_record->recdata %> - -% unless ( $domain_record->rectype eq 'SOA' -% || ! $FS::CurrentUser::CurrentUser->access_right('Edit domain nameservice') -% ) { -% ( my $recdata = $domain_record->recdata ) =~ s/"/\\'\\'/g; - (<A HREF="javascript:areyousure('<%$p%>misc/delete-domain_record.cgi?<%$domain_record->recnum%>', 'Delete \'<% $domain_record->reczone %> <% $type %> <% $recdata %>\' ?' )">delete</A>) -% } - </td> - </tr> - - -% if ( $bgcolor eq $bgcolor1 ) { -% $bgcolor = $bgcolor2; -% } else { -% $bgcolor = $bgcolor1; -% } - -% } - - </table> -% } - -% if ( $FS::CurrentUser::CurrentUser->access_right('Edit domain nameservice') ) { - <BR> - <FORM METHOD="POST" ACTION="<%$p%>edit/process/domain_record.cgi"> - <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>"> - <INPUT TYPE="text" NAME="reczone"> - <INPUT TYPE="hidden" NAME="recaf" VALUE="IN"> IN - <SELECT NAME="rectype"> -% foreach (qw( A NS CNAME MX PTR TXT) ) { - <OPTION VALUE="<%$_%>"><%$_%></OPTION> -% } - </SELECT> - <INPUT TYPE="text" NAME="recdata"> - <INPUT TYPE="submit" VALUE="Add record"> - </FORM> - - <BR><BR> - or - <BR><BR> - - <FORM NAME="SlaveForm" METHOD="POST" ACTION="<%$p%>edit/process/domain_record.cgi"> - <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>"> -% if ( @records ) { - Delete all records and -% } - Slave from nameserver IP - <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>"> - <INPUT TYPE="hidden" NAME="reczone" VALUE="@"> - <INPUT TYPE="hidden" NAME="recaf" VALUE="IN"> - <INPUT TYPE="hidden" NAME="rectype" VALUE="_mstr"> - <INPUT TYPE="text" NAME="recdata"> - <INPUT TYPE="submit" VALUE="Slave domain" onClick="return slave_areyousure()"> - </FORM> + <% include("/elements/header.html",'View domain', menubar( + "Cancel this (unaudited) domain" => + "javascript:areyousure('${p}misc/cancel-unaudited.cgi?$svcnum', 'Delete $domain and all records?')", + )) + %> % } -<BR><BR> +<% include('/elements/error.html') %> + +<% include('svc_domain/basics.html', $svc_domain, + 'part_svc' => $part_svc, + 'custnum' => $custnum, + ) +%> +<BR> + +<% include('svc_domain/acct_defaults.html', $svc_domain, + 'part_svc' => $part_svc, + ) +%> +<BR> + +<% include('svc_domain/dns.html', $svc_domain ) %> +<BR> + +<% include('elements/svc_export_settings.html', $svc_domain) %> <% joblisting({'svcnum'=>$svcnum}, 1) %> @@ -140,6 +44,8 @@ Service #<% $svcnum %> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('View customer services'); +my $conf = new FS::Conf; + my($query) = $cgi->keywords; $query =~ /^(\d+)$/; my $svcnum = $1; @@ -171,46 +77,6 @@ if ($pkgnum) { my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } ); die "Unknown svcpart" unless $part_svc; -my $email = ''; -if ($svc_domain->catchall) { - my $svc_acct = qsearchs('svc_acct',{'svcnum'=> $svc_domain->catchall } ); - die "Unknown svcpart" unless $svc_acct; - $email = $svc_acct->email; -} - my $domain = $svc_domain->domain; -my $status = 'Unknown'; -my %ops = (); - -my @exports = $part_svc->part_export(); - -my $registrar; -my $export; - -# Find the first export that does domain registration -foreach (@exports) { - $export = $_ if $_->can('registrar'); -} -# If we have a domain registration export, get the registrar object -if ($export) { - $registrar = $export->registrar; - my $domstat = $export->get_status( $svc_domain ); - if (defined($domstat->{'message'})) { - $status = $domstat->{'message'}; - } elsif (defined($domstat->{'unregistered'})) { - $status = 'Not registered'; - $ops{'register'} = "Register"; - } elsif (defined($domstat->{'status'})) { - $status = $domstat->{'status'} . ' ' . $domstat->{'contact_email'} . ' ' . $domstat->{'last_update_time'}; - } elsif (defined($domstat->{'expdate'})) { - $status = "Expires " . $domstat->{'expdate'}; - $ops{'renew'} = "Renew"; - $ops{'revoke'} = "Revoke"; - } else { - $status = $domstat->{'reason'}; - $ops{'transfer'} = "Transfer"; - } -} - </%init> diff --git a/httemplate/view/svc_domain/acct_defaults.html b/httemplate/view/svc_domain/acct_defaults.html new file mode 100644 index 000000000..0c072bff5 --- /dev/null +++ b/httemplate/view/svc_domain/acct_defaults.html @@ -0,0 +1,71 @@ +% if ( $communigate ) { + + Account defaults + <% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %> + + <% include('/view/elements/tr.html', + label=>'Password modification', + value=>$svc_domain->acct_def_password_selfchange ? 'YES' : 'NO', + ) + %> + <% include('/view/elements/tr.html', + label=>'Password recovery', + value=>$svc_domain->acct_def_password_recover ? 'YES' : 'NO', + ) + %> + + <% include('/view/elements/tr.html', + label=>'Enabled services', + value=>$svc_domain->acct_def_cgp_accessmodes, + ) + %> + + <% include('/view/elements/tr.html', + label=>'Mail storage limit', + value=>$svc_domain->acct_def_quota, + ) + %> + + <% include('/view/elements/tr.html', + label=>'File storage limit', + value=>$svc_domain->acct_def_file_quota, + ) + %> + + <% include('/view/elements/tr.html', + label=>'Files limt', + value=>$svc_domain->acct_def_file_maxnum, + ) + %> + + <% include('/view/elements/tr.html', + label=>'File size limit', + value=>$svc_domain->acct_def_file_maxsize, + ) + %> + + <% include('/view/elements/tr.html', + label=>'Message delete method', + value=>$svc_domain->acct_def_cgp_deletemode, + ) + %> + + <% include('/view/elements/tr.html', + label=>'On logout remove trash', + value=>$svc_domain->acct_def_cgp_emptytrash, + ) + %> + + </TABLE></TD></TR></TABLE> + +% } +<%init> + +my($svc_domain, %opt) = @_; + +my $part_svc = $opt{'part_svc'}; + +my $communigate = scalar($part_svc->part_export('communigate_pro')); + # || scalar($part_svc->part_export('communigate_pro_singledomain')); + +</%init> diff --git a/httemplate/view/svc_domain/basics.html b/httemplate/view/svc_domain/basics.html new file mode 100644 index 000000000..db4fac150 --- /dev/null +++ b/httemplate/view/svc_domain/basics.html @@ -0,0 +1,134 @@ +Service #<B><% $svcnum %></B> +% #if ( $conf->exists('svc_domain-edit_domain') ) { + | <A HREF="<%$p%>edit/svc_domain.cgi?<%$svcnum%>">Edit this domain</A> +% #} + +<% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %> + +<TR> + <TD ALIGN="right">Service</TD> + <TD BGCOLOR="#ffffff"><% $part_svc->svc %></TD> +</TR> + +<TR> + <TD ALIGN="right">Domain</TD> + <TD BGCOLOR="#ffffff"> + <B><% $domain %></B> + <A HREF="<% ${p} %>misc/whois.cgi?custnum=<%$custnum%>;svcnum=<%$svcnum%>;domain=<%$domain%>">(view whois information)</A> + </TD> +</TR> + +% if ($export) { + <TR> + <TD ALIGN="right">Registration status</TD> + <TD BGCOLOR="#ffffff"><B><% $status %></B> + +% if ( $FS::CurrentUser::CurrentUser->access_right('Manage domain registration') ) { +% if ( defined($ops{'register'}) ) { + <A HREF="<% ${p} %>edit/process/domreg.cgi?op=register&svcnum=<% $svcnum %>">Register at <% $registrar->{'name'} %></A> +% } +% if ( defined($ops{'transfer'}) ) { + <A HREF="<% ${p} %>edit/process/domreg.cgi?op=transfer&svcnum=<% $svcnum %>">Transfer to <% $registrar->{'name'} %></A> +% } +% if ( defined($ops{'renew'}) ) { + <A HREF="<% ${p} %>edit/process/domreg.cgi?op=renew&svcnum=<% $svcnum %>&period=1">Renew at <% $registrar->{'name'} %></A> +% } +% if ( defined($ops{'revoke'}) ) { + <A HREF="<% ${p} %>edit/process/domreg.cgi?op=revoke&svcnum=<% $svcnum %>">Revoke</A> +% } +% } + + </TD> + </TR> +% } + +% if ( $communigate ) { + + <TR> + <TD ALIGN="right">Administrator domain</TD> + <TD BGCOLOR="#ffffff"> +% if ( $svc_domain->parent_svcnum ) { +% #XXX agent-virt aware the link + <A HREF="svc_domain.cgi?<% $svc_domain->parent_svcnum %>"><% $svc_domain->parent_svc_x->domain %></A> +% } else { + <I>(none)</I> +% } + </TD> + </TR> + + <TR> + <TD ALIGN="right">Aliases</TD> + <TD BGCOLOR="#ffffff"><% $svc_domain->cgp_aliases %></TD> + </TR> + +% } + +% if ( $communigate && $svc_domain->max_accounts ) { + <TR> + <TD ALIGN="right">Maximum number of Accounts</TD> + <TD BGCOLOR="#ffffff"><% $svc_domain->max_accounts %></TD> + </TR> +% } + +<TR> + <TD ALIGN="right">Catch all email</TD> + <TD BGCOLOR="#ffffff"><% $email ? "<B>$email</B>" : '<I>(none)</I>' %> +% if ( $FS::CurrentUser::CurrentUser->access_right('Edit domain catchall') ) { + <A HREF="<% ${p} %>misc/catchall.cgi?<% $svcnum %>">(change)</A> +% } + </TD> +</TR> + +<TR> + <TD ALIGN="right">Enabled services</TD> + <TD BGCOLOR="#ffffff"><% $svc_domain->cgp_accessmodes %></TD> +</TR> + +</TABLE></TD></TR></TABLE> + +<%init> + +my($svc_domain, %opt) = @_; +my $svcnum = $svc_domain->svcnum; +my $domain = $svc_domain->domain; +my $custnum = $opt{'custnum'}; +my $part_svc = $opt{'part_svc'}; + +my $communigate = scalar($part_svc->part_export('communigate_pro')); + # || scalar($part_svc->part_export('communigate_pro_singledomain')); + +my $email = ''; +if ($svc_domain->catchall) { + my $svc_acct = qsearchs('svc_acct',{'svcnum'=> $svc_domain->catchall } ); + die "Unknown svcpart" unless $svc_acct; + $email = $svc_acct->email; +} + +# Find the first export that does domain registration +my @exports = grep $_->can('registrar'), $part_svc->part_export; +my $export = $exports[0]; +# If we have a domain registration export, get the registrar object +my $registrar; +my $status = 'Unknown'; +my %ops = (); +if ($export) { + $registrar = $export->registrar; + my $domstat = $export->get_status( $svc_domain ); + if (defined($domstat->{'message'})) { + $status = $domstat->{'message'}; + } elsif (defined($domstat->{'unregistered'})) { + $status = 'Not registered'; + $ops{'register'} = "Register"; + } elsif (defined($domstat->{'status'})) { + $status = $domstat->{'status'} . ' ' . $domstat->{'contact_email'} . ' ' . $domstat->{'last_update_time'}; + } elsif (defined($domstat->{'expdate'})) { + $status = "Expires " . $domstat->{'expdate'}; + $ops{'renew'} = "Renew"; + $ops{'revoke'} = "Revoke"; + } else { + $status = $domstat->{'reason'}; + $ops{'transfer'} = "Transfer"; + } +} + +</%init> diff --git a/httemplate/view/svc_domain/dns.html b/httemplate/view/svc_domain/dns.html new file mode 100644 index 000000000..f6f8c71c7 --- /dev/null +++ b/httemplate/view/svc_domain/dns.html @@ -0,0 +1,94 @@ +<SCRIPT> + function areyousure(href, message) { + if ( confirm(message) == true ) + window.location.href = href; + } + function slave_areyousure() { + return confirm("Remove all records and slave from " + document.SlaveForm.recdata.value + "?"); + } +</SCRIPT> + +DNS records +% my @records; if ( @records = $svc_domain->domain_record ) { + + <% include('/elements/table-grid.html') %> + +% my $bgcolor1 = '#eeeeee'; +% my $bgcolor2 = '#ffffff'; +% my $bgcolor = $bgcolor2; + + <tr> + <th CLASS="grid" BGCOLOR="#cccccc">Zone</th> + <th CLASS="grid" BGCOLOR="#cccccc">Type</th> + <th CLASS="grid" BGCOLOR="#cccccc">Data</th> + </tr> + +% foreach my $domain_record ( @records ) { +% my $type = $domain_record->rectype eq '_mstr' +% ? "(slave)" +% : $domain_record->recaf. ' '. $domain_record->rectype; + + + <tr> + <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $domain_record->reczone %></td> + <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $type %></td> + <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $domain_record->recdata %> + +% unless ( $domain_record->rectype eq 'SOA' +% || ! $FS::CurrentUser::CurrentUser->access_right('Edit domain nameservice') +% ) { +% ( my $recdata = $domain_record->recdata ) =~ s/"/\\'\\'/g; + (<A HREF="javascript:areyousure('<%$p%>misc/delete-domain_record.cgi?<%$domain_record->recnum%>', 'Delete \'<% $domain_record->reczone %> <% $type %> <% $recdata %>\' ?' )">delete</A>) +% } + </td> + </tr> + + +% if ( $bgcolor eq $bgcolor1 ) { +% $bgcolor = $bgcolor2; +% } else { +% $bgcolor = $bgcolor1; +% } + +% } + + </table> +% } + +% if ( $FS::CurrentUser::CurrentUser->access_right('Edit domain nameservice') ) { + <FORM METHOD="POST" ACTION="<%$p%>edit/process/domain_record.cgi"> + <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>"> + <INPUT TYPE="text" NAME="reczone"> + <INPUT TYPE="hidden" NAME="recaf" VALUE="IN"> IN + <SELECT NAME="rectype"> +% foreach (qw( A NS CNAME MX PTR TXT) ) { + <OPTION VALUE="<%$_%>"><%$_%></OPTION> +% } + </SELECT> + <INPUT TYPE="text" NAME="recdata"> + <INPUT TYPE="submit" VALUE="Add record"> + </FORM> + + <FORM NAME="SlaveForm" METHOD="POST" ACTION="<%$p%>edit/process/domain_record.cgi"> + <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>"> +% if ( @records ) { + Delete all records and +% } + Or slave from nameserver IP + <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>"> + <INPUT TYPE="hidden" NAME="reczone" VALUE="@"> + <INPUT TYPE="hidden" NAME="recaf" VALUE="IN"> + <INPUT TYPE="hidden" NAME="rectype" VALUE="_mstr"> + <INPUT TYPE="text" NAME="recdata"> + <INPUT TYPE="submit" VALUE="Slave domain" onClick="return slave_areyousure()"> + </FORM> + +% } + +<%init> + +my($svc_domain, %opt) = @_; +my $svcnum = $svc_domain->svcnum; + +</%init> + diff --git a/httemplate/view/svc_forward.cgi b/httemplate/view/svc_forward.cgi index 0847a5e65..43d8a4e8b 100755 --- a/httemplate/view/svc_forward.cgi +++ b/httemplate/view/svc_forward.cgi @@ -1,12 +1,26 @@ -<% include('/elements/header.html', 'Mail Forward View', menubar( - ( ( $pkgnum || $custnum ) - ? ( "View this customer (#$display_custnum)" => "${p}view/cust_main.cgi?$custnum", - ) - : ( "Cancel this (unaudited) mail forward" => - "${p}misc/cancel-unaudited.cgi?$svcnum" ) - ) -)) -%> +% if ( $custnum ) { + + <% include("/elements/header.html","View mail forward") %> + <% include( '/elements/small_custview.html', $custnum, '', 1, + "${p}view/cust_main.cgi") %> + <BR> + +% } else { + + <% include("/elements/header.html",'View mail forward', menubar( + "Cancel this (unaudited) mail forward" => + "javascript:areyousure('${p}misc/cancel-unaudited.cgi?$svcnum')", + )) + %> + + <SCRIPT> + function areyousure(href) { + if (confirm("Permanently delete this mail forward?") == true) + window.location.href = href; + } + </SCRIPT> + +% } <A HREF="<% $p %>edit/svc_forward.cgi?<% $svcnum %>">Edit this information</A> 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 c5fce62d9..75591c747 100644 --- a/httemplate/view/svc_phone.cgi +++ b/httemplate/view/svc_phone.cgi @@ -1,15 +1,11 @@ <% include('elements/svc_Common.html', 'table' => 'svc_phone', - 'fields' => [qw( - countrycode - phonenum - sip_password - pin - phone_name - )], + 'fields' => \@fields, 'labels' => { 'countrycode' => 'Country code', 'phonenum' => 'Phone number', + 'domain' => 'Domain', + 'pbx_title' => 'PBX', 'sip_password' => 'SIP password', 'pin' => 'PIN', 'phone_name' => 'Name', @@ -19,10 +15,36 @@ %> <%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'); +push @fields, qw( pbx_title sip_password pin phone_name ); + 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 ### @@ -56,6 +78,7 @@ my $html_foot = sub { '<TH CLASS="grid" BGCOLOR="#cccccc">Type</TH>'. '<TH CLASS="grid" BGCOLOR="#cccccc">MAC Addr</TH>'. '<TH CLASS="grid" BGCOLOR="#cccccc"></TH>'. + '<TH CLASS="grid" BGCOLOR="#cccccc"></TH>'. '</TR>'; my $bgcolor1 = '#eeeeee'; my $bgcolor2 = '#ffffff'; @@ -71,10 +94,12 @@ my $html_foot = sub { my $td = qq(<TD CLASS="grid" BGCOLOR="$bgcolor">); my $devicenum = $phone_device->devicenum; + my $export_links = join( '<BR>', @{ $phone_device->export_links } ); $devices .= '<TR>'. $td. $phone_device->part_device->devicename. '</TD>'. $td. $phone_device->mac_addr. '</TD>'. + $td. $export_links. '</TD>'. "$td( ". qq(<A HREF="${p}edit/phone_device.html?$devicenum">edit</A> | ). qq(<A HREF="javascript:areyousure('${p}misc/delete-phone_device.html?$devicenum')">delete</A>). @@ -118,6 +143,7 @@ my $html_foot = sub { # concatenate & return ### + $e911. $devices. join(' | ', @links ). '<BR>'. join(' | ', @ilinks). '<BR>'; |