diff options
author | jeff <jeff> | 2010-05-22 19:57:53 +0000 |
---|---|---|
committer | jeff <jeff> | 2010-05-22 19:57:53 +0000 |
commit | 4ef5b3b917b7802a136551ad567dc9d649700f53 (patch) | |
tree | 2d55887d28f88922e5a61eeb802bb1a0fe627437 /httemplate | |
parent | 6c08340010e68fa7ca0989f4902761c8d0db941f (diff) |
improved fcc 477 report #7783
Diffstat (limited to 'httemplate')
-rwxr-xr-x | httemplate/edit/part_pkg.cgi | 11 | ||||
-rwxr-xr-x | httemplate/search/477.html | 256 | ||||
-rwxr-xr-x | httemplate/search/477partIA_detail.html | 125 | ||||
-rwxr-xr-x | httemplate/search/477partIA_summary.html | 80 | ||||
-rwxr-xr-x | httemplate/search/477partIIA.html | 113 | ||||
-rwxr-xr-x | httemplate/search/477partIIB.html | 102 | ||||
-rwxr-xr-x | httemplate/search/477partIV.html | 17 | ||||
-rwxr-xr-x | httemplate/search/477partV.html | 53 | ||||
-rwxr-xr-x | httemplate/search/477partVI.html | 130 | ||||
-rw-r--r-- | httemplate/search/elements/metasearch.html | 71 | ||||
-rw-r--r-- | httemplate/search/elements/search-html.html | 39 | ||||
-rw-r--r-- | httemplate/search/elements/search-xml.html | 88 | ||||
-rw-r--r-- | httemplate/search/elements/search.html | 10 | ||||
-rwxr-xr-x | httemplate/search/report_477.html | 171 |
14 files changed, 1065 insertions, 201 deletions
diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index 6ef8dd894..c8b7ecb58 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -48,6 +48,7 @@ 'bill_dst_pkgpart' => 'Include line item(s) from package', 'svc_dst_pkgpart' => 'Include services of package', 'report_option' => 'Report classes', + 'fcc_ds0s' => 'Voice-grade eqivalents', }, 'fields' => [ @@ -167,6 +168,16 @@ { field=>'pay_weight', type=>'text', size=>6 }, { field=>'credit_weight', type=>'text', size=>6 }, + ( $conf->exists('cust_pkg-show_fcc_voice_grade_equivalent') + ? ( + { type => 'tablebreak-tr-title', + value => 'FCC Form 477 information', + }, + { field=>'fcc_ds0s', type=>'text', size=>6 }, + ) + : () + ), + { type => 'columnend' }, diff --git a/httemplate/search/477.html b/httemplate/search/477.html index 0f1502f2a..bd7fb2d8b 100755 --- a/httemplate/search/477.html +++ b/httemplate/search/477.html @@ -1,44 +1,76 @@ -<% include( 'elements/search.html', - 'title' => 'FCC Form 477 Results', - 'html_init' => $html_init, - 'name' => 'regions', - 'query' => [ @sql_query ], - 'count_query' => $count_query, - 'order_by' => 'ORDER BY censustract', - 'avoid_quote' => 1, - 'no_csv_header' => 1, - 'header' => [ - 'County code', - 'Census tract code', - 'Upload rate', - 'Download rate', - 'Technology code', - 'Technology code other', - 'Quantity', - 'Percentage residential', - ], - 'fields' => [ - sub { my $row = shift; substr($row->censustract, 2, 3) }, - sub { my $row = shift; substr($row->censustract, 5) }, - 'upload', - 'download', - sub { 7 }, - sub { '' }, - 'quantity', - sub { my $row = shift; sprintf "%.2f", $row->residential }, - ], - 'links' => [ - [ $link, $link_suffix ], - [ $link, $link_suffix ], - [ $link, $link_suffix ], - [ $link, $link_suffix ], - [ $link, $link_suffix ], - [ $link, $link_suffix ], - [ $link, $link_suffix ], - [ $link, $link_suffix ], - ], - ) -%> +% unless ( $type eq 'xml' ) { +<% include( '/elements/header.html', 'FCC Form 477 Results') %> +%}else{ +<?xml version="1.0" encoding="ISO-8859-1"?> +<Form_477_submission xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://specialreports.fcc.gov/wcb/Form477/XMLSchema-instance/form_477_upload_Schema.xsd" > +%} +% if ( $type eq 'html' || $type eq 'html-print' ) { +<TABLE WIDTH="100%"> + <TR><TD></TD> +%}elsif ( $type eq 'xml' ) { +%} +% unless ( $type eq 'html-print' || $type eq 'xml' ) { + + <TD ALIGN="right"> + + Download full results<BR> +% $cgi->param('_type', 'xml'); + as <A HREF="<% $cgi->self_url %>">XML file</A><BR> + +% $cgi->param('_type', 'html-print'); + as <A HREF="<% $cgi->self_url %>">printable copy</A> + + </TD> +% $cgi->param('_type', $type ); +% } +% if ( $type eq 'html' || $type eq 'html-print' ) { + </TR> +</TABLE> +%}elsif ( $type eq 'xml' ) { +%} +% foreach my $part ( @parts ) { +% if ( $part{$part} ) { +% +% if ( $part eq 'V' ) { +% next unless ( $part{'IIA'} || $part{'IIB'} ); +% } +% +% if ( $part eq 'VI' ) { +% next unless $part{'IA'}; +% } +% +% my @reports = (); +% if ( $part eq 'IA' ) { +% for ( my $tech = 0; $tech < scalar(@technology_option); $tech++ ) { +% next unless $technology_option[$tech]; +% my $url = &{$url_mangler}($cgi->self_url, $part); +% if ( $type eq 'xml' ) { +<<% 'Part_IA_'. chr(65 + $tech) %>> +% } +<% include( "477part${part}_summary.html", 'tech_code' => $tech, 'url' => $url ) %> +<% include( "477part${part}_detail.html", 'tech_code' => $tech, 'url' => $url ) %> +% if ( $type eq 'xml' ) { +</<% 'Part_IA_'. chr(65 + $tech) %>> +% } +% } +% } else { +% if ( $type eq 'xml' ) { +<<% 'Part_'. uc($part) %>> +% } +% my $url = &{$url_mangler}($cgi->self_url, $part); +<% include( "477part${part}.html", 'url' => $url ) %> +% if ( $type eq 'xml' ) { +</<% 'Part_'. uc($part) %>> +% } +% } +% } +% } +% +% if ( $type eq 'html' || $type eq 'html-print' ) { +<% include( '/elements/footer.html') %> +%}elsif ( $type eq 'xml' ) { +</Form_477_submission> +%} <%init> my $curuser = $FS::CurrentUser::CurrentUser; @@ -46,137 +78,15 @@ my $curuser = $FS::CurrentUser::CurrentUser; die "access denied" unless $curuser->access_right('List packages'); -my %search_hash = (); -my @sql_query = (); - -for ( qw(agentnum magic classnum) ) { - $search_hash{$_} = $cgi->param($_) if $cgi->param($_); -} +my %part = map { $_ => 1 } grep { /^\w+$/ } $cgi->param('part'); +my $type = $cgi->param('_type') || 'html'; +my $xlsname = '477report'; +my @technology_option = &FS::Report::FCC_477::parse_technology_option($cgi); +my $url_mangler = sub { + my ($url, $part) = (shift, shift); + $url =~ s/477\./477part$part./; + $url; +}; +my @parts = qw( IA IIA IIB IV V VI ); -my @column_option = $cgi->param('column_option') - if $cgi->param('column_option'); - -my @row_option = $cgi->param('row_option') - if $cgi->param('row_option'); - -my $where = join(' OR ', map { "num = $_" } grep { /^\d+$/ } @column_option ); -my %column_option_name = $where ? - ( map { $_->name => $_->num } - qsearch({ 'table' => 'part_pkg_report_option', - 'hashref' => {}, - 'extra_sql' => "WHERE $where", - }) - ) : - ( 'all packages' => '' ); - -$where = join(' OR ', map { "num = $_" } grep { /^\d+$/ } @row_option ); -my %row_option_name = $where ? - ( map { $_->name => $_->num } - qsearch({ 'table' => 'part_pkg_report_option', - 'hashref' => {}, - 'extra_sql' => "WHERE $where", - }) - ) : - ( 'all packages' => '' ); - -@row_option = map { $row_option_name{$_} } sort keys %row_option_name; -@column_option = map { $column_option_name{$_} } sort keys %column_option_name; - -#$search_hash{row_option} = join(',', @row_option) if @row_option; -my $summary .= '<H2>Summary</H2>'. include('/elements/table.html'); -$summary .= '<TR><TH></TH>'; -foreach my $column ( sort keys %column_option_name ) { - $summary .= "<TH>$column</TH>"; -} -$summary .= "</TR>"; - -my $total_count = 0; -my $total_residential = 0; -my $rowcount = 1; -foreach my $row ( sort keys %row_option_name ) { - - $summary .= "<TR><TH>$row</TH>"; - - my $columncount = 2; - foreach my $column ( sort keys %column_option_name ) { - my @report_option = (); - push @report_option, $row_option_name{$row} - if $row_option_name{$row}; - push @report_option, $column_option_name{$column} - if $column_option_name{$column}; - my $report_option = join(',', @report_option) if @report_option; - - my $sql_query = FS::cust_pkg->search( - { %search_hash, - ($report_option ? ( 'report_option' => $report_option ) : () ), - } - ); - my $extracolumns = "$rowcount AS upload, $columncount AS download"; - my $percent = "CASE WHEN count(*) > 0 THEN 100-100*cast(count(cust_main.company) as numeric)/cast(count(*) as numeric) ELSE cast(0 as numeric) END AS residential"; - $sql_query->{select} = "count(*) AS quantity, $extracolumns, censustract, $percent"; - $sql_query->{extra_sql} =~ /^(.*)(ORDER BY pkgnum)(.*)$/s - or die "couldn't parse extra_sql"; - $sql_query->{extra_sql} = "$1 GROUP BY censustract $3"; - - my $count_sql = delete($sql_query->{'count_query'}); - $count_sql =~ s/ FROM/,count(cust_main.company) FROM/ - or die "couldn't parse count_sql"; - - my $count_sth = dbh->prepare($count_sql) - or die "Error preparing $count_sql: ". dbh->errstr; - $count_sth->execute - or die "Error executing $count_sql: ". $count_sth->errstr; - my $count_arrayref = $count_sth->fetchrow_arrayref; - my $count = $count_arrayref->[0]; - $total_count += $count; - my $residential = $count_arrayref->[1]; - $total_residential += $residential; - my $percentage = sprintf('%.2f', $count ? 100-100*$residential/$count : 0); - - $summary .= "<TD>$count<BR>$percentage% residential</TD>"; - push @sql_query, $sql_query; - $columncount++; - } - - $summary .= "</TR>"; - $rowcount++; -} - -my $total_percentage = - sprintf("%.2f", $total_count ? 100-100*$total_residential/$total_count : 0); - -my $html_init = '<H2>Totals</H2>'. include('/elements/table.html'). "<TR>"; -$html_init .= "<TH>Total Connections</TH>"; -$html_init .= "<TH>% owned loop</TH>"; -$html_init .= "<TH>% billed to end users</TH>"; -$html_init .= "<TH>% residential</TH>"; -$html_init .= "<TH>% residential > 200kbps</TH>"; -$html_init .= "</TR><TR>"; -$html_init .= "<TD>$total_count</TD>"; -$html_init .= "<TD>100.00</TD>"; -$html_init .= "<TD>100.00</TD>"; -$html_init .= "<TD>$total_percentage</TD>"; -$html_init .= "<TD>$total_percentage</TD>"; -$html_init .= "</TR></TABLE><BR>"; -$html_init .= $summary; -$html_init .= "</TABLE><BR><H2>Details</H2>"; - -my $count_query = 'SELECT count(*) FROM ( ('. - join( ') UNION (', - map { my $extra = $_->{extra_sql}; my $addl = $_->{addl_from}; - "SELECT censustract from cust_pkg $addl $extra"; - } - @sql_query - ). ') ) AS foo'; - -my $link = 'cust_pkg.cgi?'. - join(';', map{ "$_=". $search_hash{$_} } keys %search_hash). ';'; -my $link_suffix = sub { my $row = shift; - my $result = 'censustract='. $row->censustract. ';'; - $result .= 'report_option='. @row_option[$row->upload - 1] - if @row_option[$row->upload - 1]; - $result .= 'report_option='. @column_option[$row->download - 1] - if @column_option[$row->download - 1]; - $result; - }; </%init> diff --git a/httemplate/search/477partIA_detail.html b/httemplate/search/477partIA_detail.html new file mode 100755 index 000000000..546d56c7f --- /dev/null +++ b/httemplate/search/477partIA_detail.html @@ -0,0 +1,125 @@ +<% include( 'elements/search.html', + 'html_init' => $html_init, + 'name' => 'lines', + 'query' => $query, + 'count_query' => $count_query, + 'really_disable_download' => 1, + 'disable_download' => 1, + 'nohtmlheader' => 1, + 'disable_total' => 1, + 'header' => [ '', @column_option_name ], + 'xml_elements' => [ @xml_elements ], + 'fields' => [ @fields ], + ) +%> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('List packages'); + +my %opt = @_; +my %search_hash = (); + +for ( qw(agentnum magic classnum) ) { + $search_hash{$_} = $cgi->param($_) if $cgi->param($_); +} + +my @column_option = grep { /^\d+/ } $cgi->param('part1_column_option') + if $cgi->param('part1_column_option'); + +my @row_option = grep { /^\d+/ } $cgi->param('part1_row_option') + if $cgi->param('part1_row_option'); + +my @technology_option = &FS::Report::FCC_477::parse_technology_option($cgi); + +my @column_option_name = scalar(@column_option) + ? ( map { my $part_pkg_report_option = + qsearchs({ 'table' => 'part_pkg_report_option', + 'hashref' => { num => $_ }, + }); + $part_pkg_report_option ? $part_pkg_report_option->name + : 'no such report option'; + } @column_option + ) + : ( 'all packages' ); + +my $where = join(' OR ', map { "num = $_" } @row_option ); +my %row_option_name = $where ? + ( map { $_->num => $_->name } + qsearch({ 'table' => 'part_pkg_report_option', + 'hashref' => {}, + 'extra_sql' => "WHERE $where", + }) + ) : + (); + +my $tech_code = $opt{tech_code}; +my $technology = $FS::Report::FCC_477::technology[$tech_code] || 'unknown'; +my $html_init = "<H2>Part IA $technology breakdown by speeds</H2>"; +my $xml_prefix = 'PartIA_'. chr(65 + $tech_code); + +my $query = 'SELECT '. join(' UNION ALL SELECT ',@row_option); +my $count_query = 'SELECT '. scalar(@row_option); + +my $value = sub { + my ($rowref, $column) = (shift, shift); + my $row = $rowref->[0]; + + if ($column eq 'name') { + return $row_option_name{$row} || 'no such report option'; + } elsif ( $column =~ /^(\d+)$/ ) { + my @report_option = ( $row || '', + $column_option[$1 - 2] || '', + $technology_option[$tech_code] || '', + ); + + my ( $count, $residential ) = FS::cust_pkg->fcc_477_count( + { %search_hash, 'report_option' => join(',', @report_option) } + ); + + my $percentage = sprintf('%.2f', $count ? 100 * $residential / $count : 0); + my $return = $count; + $return .= "<BR>$percentage% residential" + unless $cgi->param('_type') eq 'xml'; + return $return; + } else { + return '<FONT SIZE="+1" COLOR="#ff0000">Bad call to column_value</FONT>'; + } +}; + +my @fields = ( + sub { &{$value}(shift, 'name');}, + sub { &{$value}(shift, 2);}, + sub { &{$value}(shift, 3);}, + sub { &{$value}(shift, 4);}, + sub { &{$value}(shift, 5);}, + sub { &{$value}(shift, 6);}, + sub { &{$value}(shift, 7);}, + sub { &{$value}(shift, 8);}, + sub { &{$value}(shift, 9);}, + ); +shift @fields if $cgi->param('_type') eq 'xml'; + +my $xml_element = sub { + my ($rowref, $column) = (shift, shift); + my $row = $rowref->[0]; + + $row++; + $xml_prefix. $column. $row; + +}; + +my @xml_elements = ( + sub { &{$xml_element}(shift, 'f') }, + sub { &{$xml_element}(shift, 'g') }, + sub { &{$xml_element}(shift, 'h') }, + sub { &{$xml_element}(shift, 'i') }, + sub { &{$xml_element}(shift, 'j') }, + sub { &{$xml_element}(shift, 'k') }, + sub { &{$xml_element}(shift, 'l') }, + sub { &{$xml_element}(shift, 'm') }, +); + +</%init> diff --git a/httemplate/search/477partIA_summary.html b/httemplate/search/477partIA_summary.html new file mode 100755 index 000000000..269f2caf2 --- /dev/null +++ b/httemplate/search/477partIA_summary.html @@ -0,0 +1,80 @@ +<% include( 'elements/search.html', + 'html_init' => $html_init, + 'name' => 'lines', + 'query' => 'SELECT 1', + 'count_query' => 'SELECT 1', + 'really_disable_download' => 1, + 'disable_download' => 1, + 'nohtmlheader' => 1, + 'disable_total' => 1, + 'header' => [ + 'Total Connections', + '% owned loop', + '% billed to end users', + '% residential', + '% residential > 200kbps', + ], + 'xml_elements' => [ + $xml_prefix. 'a1', + $xml_prefix. 'b1', + $xml_prefix. 'c1', + $xml_prefix. 'd1', + $xml_prefix. 'e1', + ], + 'fields' => [ + sub { $total_count }, + sub { '100.00' }, + sub { '100.00' }, + sub { $total_percentage }, + sub { $total_percentage }, + ], + ) +%> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('List packages'); + +my %opt = @_; +my %search_hash = (); + +for ( qw(agentnum magic classnum) ) { + $search_hash{$_} = $cgi->param($_) if $cgi->param($_); +} + +my @column_option = grep { /^\d+$/ } $cgi->param('part1_column_option') + if $cgi->param('part1_column_option'); + +my @row_option = grep { /^\d+$/ } $cgi->param('part1_row_option') + if $cgi->param('part1_row_option'); + +my @technology_option = &FS::Report::FCC_477::parse_technology_option($cgi); + +my $total_count = 0; +my $total_residential = 0; +my $tech_code = $opt{tech_code}; +my $technology = $FS::Report::FCC_477::technology[$tech_code] || 'unknown'; +my $html_init = "<H2>Part IA $technology totals</H2>"; +my $xml_prefix = 'PartIA_'. chr(65 + $tech_code); + +foreach my $row ( @row_option ) { + foreach my $column ( @column_option ) { + + my @report_option = ( $row || '-1', $column || '-1', $technology_option[$tech_code] ); + + my ( $count, $residential ) = FS::cust_pkg->fcc_477_count( + { %search_hash, 'report_option' => join(',', @report_option) } + ); + + $total_count += $count; + $total_residential += $residential; + } +} + +my $total_percentage = + sprintf("%.2f", $total_count ? 100*$total_residential/$total_count : 0); + + +</%init> diff --git a/httemplate/search/477partIIA.html b/httemplate/search/477partIIA.html new file mode 100755 index 000000000..64f773a21 --- /dev/null +++ b/httemplate/search/477partIIA.html @@ -0,0 +1,113 @@ +<% include( 'elements/search.html', + 'html_init' => $html_init, + 'name' => 'lines', + 'query' => $query, + 'count_query' => 'SELECT 11', + 'really_disable_download' => 1, + 'disable_download' => 1, + 'nohtmlheader' => 1, + 'disable_total' => 1, + 'header' => [ @headers ], + 'xml_elements' => [ @xml_elements ], + 'fields' => [ @fields ], + ) +%> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('List packages'); + +my $html_init = '<H2>Part IIA</H2>'; +my %search_hash = (); + +for ( qw(agentnum magic classnum) ) { + $search_hash{$_} = $cgi->param($_) if $cgi->param($_); +} + +my @row_option = grep { /^\d+$/ } $cgi->param('part2a_row_option') + if $cgi->param('part2a_row_option'); + +# fudge in two rows of LD carrier +unshift @row_option, $row_option[0]; + +# fudge in the first pair of rows +unshift @row_option, ''; +unshift @row_option, ''; + +my $query = 'SELECT '. join(' UNION SELECT ', 1..11); + +my $total_count = 0; +my $column_value = sub { + my $row = shift; + + my @report_option = ( $row_option[$row - 1] || '' ); + + my $sql_query = FS::cust_pkg->search( + { %search_hash, 'report_option' => join(',', @report_option) } + ); + + my $count_sql = delete($sql_query->{'count_query'}); + if ( $row == 2 || $row == 4 ) { + $count_sql =~ s/COUNT\(\*\) FROM/COALESCE( sum(CASE WHEN cust_main.company IS NULL OR cust_main.company = '' THEN fcc_ds0s END), 0 ) FROM/ + or die "couldn't parse count_sql"; + } else { + $count_sql =~ s/COUNT\(\*\) FROM/COALESCE( sum(fcc_ds0s), 0 ) FROM/ + or die "couldn't parse count_sql"; + } + + my $count_sth = dbh->prepare($count_sql) + or die "Error preparing $count_sql: ". dbh->errstr; + $count_sth->execute + or die "Error executing $count_sql: ". $count_sth->errstr; + my $count_arrayref = $count_sth->fetchrow_arrayref; + my $count = $count_arrayref->[0]; + + $total_count = $count if $row == 1; + $count = sprintf('%.2f', $total_count ? 100*$count/$total_count : 0) + if $row != 1; + + return "$count"; +}; + +my @headers = ( + '', + 'End user lines', + 'UNE-P replacement', + 'UNE (unswitched)', + 'UNE-P', +); + +my @xml_elements = ( + sub { my $row = shift; my $rownum = $row->[0] + 1; "PartII_${rownum}a" }, + sub { my $row = shift; my $rownum = $row->[0] + 1; "PartII_${rownum}b" }, + sub { my $row = shift; my $rownum = $row->[0] + 1; "PartII_${rownum}c" }, + sub { my $row = shift; my $rownum = $row->[0] + 1; "PartII_${rownum}d" }, +); + + +my @rows = ( + 'lines', + '% residential', + '% LD carrier', + '% residential and LD carrier', + '% own loops', + '% obtained unswitched UNE loops', + '% UNE-P', + '% UNE-P replacement', + '% FTTP', + '% coax', + '% wireless', +); + +my @fields = ( + sub { my $row = shift; $rows[$row->[0] - 1]; }, + sub { my $row = shift; &{$column_value}($row->[0]); }, + sub { 0; }, + sub { 0; }, + sub { 0; }, +); + +shift @fields if $cgi->param('_type') eq 'xml'; +</%init> diff --git a/httemplate/search/477partIIB.html b/httemplate/search/477partIIB.html new file mode 100755 index 000000000..278dfdc8b --- /dev/null +++ b/httemplate/search/477partIIB.html @@ -0,0 +1,102 @@ +<% include( 'elements/search.html', + 'html_init' => $html_init, + 'name' => 'lines', + 'query' => $query, + 'count_query' => 'SELECT 11', + 'really_disable_download' => 1, + 'disable_download' => 1, + 'nohtmlheader' => 1, + 'disable_total' => 1, + 'header' => [ @headers ], + 'xml_elements' => [ @xml_elements ], + 'fields' => [ @fields ], + ) +%> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('List packages'); + +my $html_init = '<H2>Part IIB</H2>'; +my %search_hash = (); + +for ( qw(agentnum magic classnum) ) { + $search_hash{$_} = $cgi->param($_) if $cgi->param($_); +} + +my @row_option = grep { /^\d+$/ } $cgi->param('part2b_row_option') + if $cgi->param('part2b_row_option'); + +# fudge in 2nd row +unshift @row_option, $row_option[0]; + +my $query = 'SELECT '. join(' UNION SELECT ', 1..8); + +my $total_count = 0; +my $column_value = sub { + my $row = shift; + + my @report_option = ( $row_option[$row - 1] || '' ); + + my $sql_query = FS::cust_pkg->search( + { %search_hash, 'report_option' => join(',', @report_option) } + ); + + my $count_sql = delete($sql_query->{'count_query'}); + if ( $row == 2 ) { + $count_sql =~ s/COUNT\(\*\) FROM/COALESCE( sum(CASE WHEN cust_main.company IS NULL OR cust_main.company = '' THEN fcc_ds0s END), 0 ) FROM/ + or die "couldn't parse count_sql"; + } else { + $count_sql =~ s/COUNT\(\*\) FROM/COALESCE( sum(fcc_ds0s), 0 ) FROM/ + or die "couldn't parse count_sql"; + } + + my $count_sth = dbh->prepare($count_sql) + or die "Error preparing $count_sql: ". dbh->errstr; + $count_sth->execute + or die "Error executing $count_sql: ". $count_sth->errstr; + my $count_arrayref = $count_sth->fetchrow_arrayref; + my $count = $count_arrayref->[0]; + + $total_count = $count if $row == 1; + $count = sprintf('%.2f', $total_count ? 100*$count/$total_count : 0) + if $row != 1; + + return "$count"; +}; + +my @headers = ( + '', + 'with broadband', + 'without broadband', + 'wholesale', +); + +my @xml_elements = ( + sub { my $row = shift; my $rownum = $row->[0] + 1; "PartII_${rownum}a" }, + sub { my $row = shift; my $rownum = $row->[0] + 1; "PartII_${rownum}b" }, + sub { my $row = shift; my $rownum = $row->[0] + 1; "PartII_${rownum}c" }, +); + +my @rows = ( + 'total number', + '% residential', + '% nomadic', + '% copper', + '% FTTP', + '% coax', + '% wireless', + '% other broadband', +); + +my @fields = ( + sub { my $row = shift; $rows[$row->[0] - 1]; }, + sub { 0; }, + sub { my $row = shift; &{$column_value}($row->[0]); }, + sub { 0; }, +); + +shift @fields if $cgi->param('_type') eq 'xml'; +</%init> diff --git a/httemplate/search/477partIV.html b/httemplate/search/477partIV.html new file mode 100755 index 000000000..269a925dc --- /dev/null +++ b/httemplate/search/477partIV.html @@ -0,0 +1,17 @@ +%if ( $cgi->param('_type') eq 'html' || $cgi->param('_type') eq 'html-print' ) { +<H2>Part IV</H2> +%} elsif ( $cgi->param('_type') eq 'xml' ) { +<notes> +%} +<% $cgi->param('notes') |h %> +%if ( $cgi->param('_type') eq 'xml' ) { +</notes> +%} +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('List packages'); + +</%init> diff --git a/httemplate/search/477partV.html b/httemplate/search/477partV.html new file mode 100755 index 000000000..c6ceac4db --- /dev/null +++ b/httemplate/search/477partV.html @@ -0,0 +1,53 @@ +<% include( 'elements/search.html', + 'html_init' => $html_init, + 'name' => 'zip code', + 'query' => [ @sql_query ], + 'count_query' => $count_query, + 'nohtmlheader' => 1, + 'disable_total' => 1, + 'header' => [ 'zip code' ], + 'xml_elements' => [ 'zip codes' ], + 'no_field_elements' => 1, + 'fields' => [ 'zip' ], + 'url' => $opt{url} || $cgi->self_url, + + ) +%> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('List packages'); + +my %opt = @_; +my $html_init = '<H2>Part V</H2>'; +my %search_hash = (); +my @sql_query = (); +my @count_query = (); + +for ( qw(agentnum magic classnum) ) { + $search_hash{$_} = $cgi->param($_) if $cgi->param($_); +} + +my $sql_query = FS::cust_pkg->search( { %search_hash, 'fcc_line' > 1 }); +$sql_query->{select} = 'DISTINCT zip'; +$sql_query->{extra_sql} =~ s/ORDER BY [.\w]+//; +push @sql_query, $sql_query; +push @count_query, delete($sql_query->{'count_query'}); +$count_query[0] =~ s/count\(\*\)/count(DISTINCT zip)/; +$count_query[0] =~ s/ORDER BY [.\w]+//; + +$search_hash{classnum} = $cgi->param('part2a_classnum') + if $cgi->param('part2a_classnum'); + +$sql_query = FS::cust_pkg->search( { %search_hash } ); +$sql_query->{select} = 'DISTINCT zip'; +$sql_query->{extra_sql} =~ s/ORDER BY [.\w]+//; +push @sql_query, $sql_query; +push @count_query, delete($sql_query->{'count_query'}); +$count_query[1] =~ s/count\(\*\)/count(DISTINCT zip)/; +$count_query[1] =~ s/ORDER BY [.\w]+//; +my $count_query = join(' UNION ', @count_query); + +</%init> diff --git a/httemplate/search/477partVI.html b/httemplate/search/477partVI.html new file mode 100755 index 000000000..dbd17032c --- /dev/null +++ b/httemplate/search/477partVI.html @@ -0,0 +1,130 @@ +<% include( 'elements/search.html', + 'html_init' => $html_init, + 'name' => 'regions', + 'query' => [ @sql_query ], + 'count_query' => $count_query, + 'order_by' => 'ORDER BY censustract', + 'avoid_quote' => 1, + 'no_csv_header' => 1, + 'nohtmlheader' => 1, + 'header' => [ + 'County code', + 'Census tract code', + 'Upload rate', + 'Download rate', + 'Technology code', + 'Technology code other', + 'Quantity', + 'Percentage residential', + ], + 'xml_elements' => [ + 'county_fips', + 'census_tract', + 'upload_rate_code', + 'download_rate_code', + 'technology_code', + 'technology_code_other', + 'value', + 'percentage', + ], + 'fields' => [ + sub { my $row = shift; substr($row->censustract, 2, 3) }, + sub { my $row = shift; substr($row->censustract, 5) }, + 'upload', + 'download', + 'technology_code', + sub { '' }, # doesn't really work + 'quantity', + sub { my $row = shift; sprintf "%.2f", $row->residential }, + ], + 'links' => [ + [ $link, $link_suffix ], + [ $link, $link_suffix ], + [ $link, $link_suffix ], + [ $link, $link_suffix ], + [ $link, $link_suffix ], + [ $link, $link_suffix ], + [ $link, $link_suffix ], + [ $link, $link_suffix ], + ], + 'url' => $opt{url} || $cgi->self_url, + 'xml_row_element' => 'Datarow', + ) +%> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('List packages'); + +my %opt = @_; + +my $html_init = '<H2>Part VI</H2>'; + +my %search_hash = (); +my @sql_query = (); + +for ( qw(agentnum magic classnum) ) { + $search_hash{$_} = $cgi->param($_) if $cgi->param($_); +} + +my @column_option = grep { /^\d+$/ } $cgi->param('part1_column_option') + if $cgi->param('part1_column_option'); + +my @row_option = grep { /^\d+$/ } $cgi->param('part1_row_option') + if $cgi->param('part1_row_option'); + +my @technology_option = &FS::Report::FCC_477::parse_technology_option($cgi); + +my $rowcount = 1; +foreach my $row ( @row_option ) { + my $columncount = 2; + foreach my $column ( @column_option ) { + my $tech_code = 0; + foreach my $technology ( @technology_option ) { + $tech_code++; + next unless $technology; + my @report_option = (); + push @report_option, $row if $row; + push @report_option, $column if $column; + push @report_option, $technology; + my $report_option = join(',', @report_option) if @report_option; + + my $sql_query = FS::cust_pkg->search( + { %search_hash, + ($report_option ? ( 'report_option' => $report_option ) : () ), + } + ); + my $extracolumns = "$rowcount AS upload, $columncount AS download, $tech_code as technology_code"; + my $percent = "CASE WHEN count(*) > 0 THEN 100-100*cast(count(cust_main.company) as numeric)/cast(count(*) as numeric) ELSE cast(0 as numeric) END AS residential"; + $sql_query->{select} = "count(*) AS quantity, $extracolumns, censustract, $percent"; + $sql_query->{extra_sql} =~ /^(.*)(ORDER BY pkgnum)(.*)$/s + or die "couldn't parse extra_sql"; + $sql_query->{extra_sql} = "$1 GROUP BY censustract $3"; + push @sql_query, $sql_query; + } + $columncount++; + } + $rowcount++; +} + +my $count_query = 'SELECT count(*) FROM ( ('. + join( ') UNION ALL (', + map { my $extra = $_->{extra_sql}; my $addl = $_->{addl_from}; + "SELECT censustract from cust_pkg $addl $extra"; + } + @sql_query + ). ') ) AS foo'; + +my $link = 'cust_pkg.cgi?'. + join(';', map{ "$_=". $search_hash{$_} } keys %search_hash). ';'; +my $link_suffix = sub { my $row = shift; + my $result = 'censustract='. $row->censustract. ';'; + $result .= 'report_option='. @row_option[$row->upload - 1] + if @row_option[$row->upload - 1]; + $result .= 'report_option='. @column_option[$row->download - 1] + if @column_option[$row->download - 1]; + $result; + }; +</%init> diff --git a/httemplate/search/elements/metasearch.html b/httemplate/search/elements/metasearch.html new file mode 100644 index 000000000..b9d3e3ce2 --- /dev/null +++ b/httemplate/search/elements/metasearch.html @@ -0,0 +1,71 @@ +<%doc> + +Example: + + include( 'elements/metasearch.html', + + ### + # required + ### + + 'title' => 'Page title', + + #arrayref of hashrefs suited for passing to elements/search.html + #see that documentation + 'search' => [ + { + query => { 'table' => 'tablename', + #everything else is optional... + 'hashref' => { 'f1' => 'value', + 'f2' => { 'op' => '<', + 'value' => '54', + }, + }, + 'select' => '*', + 'order_by' => 'ORDER BY something', + + }, + count_query => 'SELECT COUNT(*) FROM tablename', + }, + { + query => 'table' => 'anothertablename', + count_query => 'SELECT COUNT(*) FROM anothertablename', + }, + ], + + ### + # optional + ### + + # some HTML callbacks... + 'menubar' => '', #menubar arrayref + 'html_init' => '', #after the header/menubar and before the pager + 'html_form' => '', #after the pager, right before the results + # (only shown if there are results) + # (use this for any form-opening tag rather than + # html_init, to avoid a nested form) + 'html_foot' => '', #at the bottom + 'html_posttotal' => '', #at the bottom + # (these three can be strings or coderefs) + + ); + +</%doc> +% foreach my $search ( @{$opt{search}} ) { +<% include('search.html', + %$search, + 'type' => $type, + 'nohtmlheader' => 1, + ) +%> +% +% } +<%init> + +my(%opt) = @_; +#warn join(' / ', map { "$_ => $opt{$_}" } keys %opt ). "\n"; + +my $type = $cgi->param('_type') =~ /^(csv|\w*\.xls|select|html(-print)?)$/ + ? $1 : 'html' ; + +</%init> diff --git a/httemplate/search/elements/search-html.html b/httemplate/search/elements/search-html.html index 37178dcc2..e5e6ca954 100644 --- a/httemplate/search/elements/search-html.html +++ b/httemplate/search/elements/search-html.html @@ -32,11 +32,17 @@ % % if ( $type eq 'html-print' ) { - <% include( '/elements/header-popup.html', $opt{'title'} ) %> + <% $opt{nohtmlheader} + ? '' + : include( '/elements/header-popup.html', $opt{'title'} ) + %> % } elsif ( $type eq 'select' ) { - <% include( '/elements/header-popup.html', $opt{'title'} ) %> + <% $opt{nohtmlheader} + ? '' + : include( '/elements/header-popup.html', $opt{'title'} ) + %> <% defined($opt{'html_init'}) ? ( ref($opt{'html_init'}) ? &{$opt{'html_init'}}() @@ -54,9 +60,11 @@ % # @menubar = ( 'Main menu' => $p ); % } - <% include( '/elements/header.html', $opt{'title'}, - include( '/elements/menubar.html', @menubar ) - ) + <% $opt{nohtmlheader} + ? '' + : include( '/elements/header.html', $opt{'title'}, + include( '/elements/menubar.html', @menubar ) + ) %> <% defined($opt{'html_init'}) @@ -95,7 +103,7 @@ % $cgi->delete('maxrecords'); % $cgi->param('_dummy', 1); - ( show <SELECT NAME="maxrecords" onChange="window.location = '<% $cgi->self_url %>;maxrecords=' + this.options[this.selectedIndex].value;"> + ( show <SELECT NAME="maxrecords" onChange="window.location = '<% $self_url %>;maxrecords=' + this.options[this.selectedIndex].value;"> % foreach my $max ( map { $_ * $confmax } qw( 1 5 10 25 ) ) { <OPTION VALUE="<% $max %>" <% ( $maxrecords == $max ) ? 'SELECTED' : '' %>><% $max %></OPTION> @@ -136,13 +144,18 @@ Download full results<BR> % $cgi->param('_type', "$xlsname.xls" ); - as <A HREF="<% $cgi->self_url %>">Excel spreadsheet</A><BR> + as <A HREF="<% $self_url %>">Excel spreadsheet</A><BR> % $cgi->param('_type', 'csv'); - as <A HREF="<% $cgi->self_url %>">CSV file</A><BR> + as <A HREF="<% $self_url %>">CSV file</A><BR> + +% if ( defined($opt{xml_elements}) ) { +% $cgi->param('_type', 'xml'); + as <A HREF="<% $self_url %>">XML file</A><BR> +% } % $cgi->param('_type', 'html-print'); - as <A HREF="<% $cgi->self_url %>">printable copy</A> + as <A HREF="<% $self_url %>">printable copy</A> </TD> % $cgi->param('_type', "html" ); @@ -417,9 +430,11 @@ % } % if ( $type eq 'html-print' ) { +% unless ( $opt{nohtmlheader} ) { </BODY></HTML> +% } % } else { <% defined($opt{'html_foot'}) @@ -430,7 +445,10 @@ : '' %> - <% include( '/elements/footer.html' ) %> + <% $opt{nohtmlheader} + ? '' + : include( '/elements/footer.html' ) + %> % } @@ -447,6 +465,7 @@ my $confmax = $args{'confmax'}; my $maxrecords = $args{'maxrecords'}; my $offset = $args{'offset'}; my %opt = %{ $args{'opt'} }; +my $self_url = $opt{'url'} || $cgi->self_url; my $count_sth = dbh->prepare($opt{'count_query'}) or die "Error preparing $opt{'count_query'}: ". dbh->errstr; diff --git a/httemplate/search/elements/search-xml.html b/httemplate/search/elements/search-xml.html new file mode 100644 index 000000000..9f5e9b6c1 --- /dev/null +++ b/httemplate/search/elements/search-xml.html @@ -0,0 +1,88 @@ +% foreach my $row ( @$rows ) { +% +% if (&{$beginrow}($row)){ +<% &{$beginrow}($row) %> +% } +% +% foreach my $i ( 0 .. scalar( @{$opt{'fields'}} ) - 1 ) { +% my $field = $opt{'fields'}->[$i]; +% my $value = ''; +% if ( ref($field) eq 'CODE' ) { +% $value = &{$field}($row); +% $value = '(N/A)' #unimplemented +% if ref($value) eq 'ARRAY'; +% } else { +% $value = $row->$field(); +% } +% +<% &{$beginfield}($row, $i) %><% $value |h %><% &{$endfield}($row, $i) %> +% +% } +% +% if (&{$endrow}($row)) { +<% &{$endrow}($row) %> +% } +% +% } +<%init> + +my %args = @_; +my $header = $args{'header'}; +my $rows = $args{'rows'}; +my %opt = %{ $args{'opt'} }; + +http_header('Content-Type' => 'application/XML' ); # So saith RFC 4180 +http_header('Content-Disposition' => + 'attachment;filename="'.($opt{'name'} || PL($opt{'name_singular'}) ).'.xml"'); + +unless ( $opt{'fields'} ) { + foreach my $i ( 0 .. ( $#{ @$rows[0] } ) ) { + $opt{'fields'}->[$i] = sub { my $row = shift; $row->[$i]; }; + } +} + +my $beginrow = sub { return ''; }; +my $endrow = sub { return ''; }; +if ($opt{xml_row_element}) { + $beginrow = sub { my ($row, $index) = @_; + my $value; + if ( ref($opt{xml_row_element}) eq 'CODE' ) { + $value = &{$opt{xml_row_element}}($row); + } else { + $value = $opt{xml_row_element}; + } + return "<$value>"; + }; + $endrow = sub { my ($row, $index) = @_; + my $value; + if ( ref($opt{xml_row_element}) eq 'CODE' ) { + $value = &{$opt{xml_row_element}}($row); + } else { + $value = $opt{xml_row_element}; + } + return "</$value>"; + }; +} +my $beginfield = sub { my ($row, $index) = @_; + my $value; + if ( ref($opt{xml_elements}->[$index]) eq 'CODE' ) { + $value = &{$opt{xml_elements}->[$index]}($row); + } else { + $value = $opt{xml_elements}->[$index]; + } + return "<$value>"; + }; +my $endfield = sub { my ($row, $index) = @_; + my $value; + if ( ref($opt{xml_elements}->[$index]) eq 'CODE' ) { + $value = &{$opt{xml_elements}->[$index]}($row); + } else { + $value = $opt{xml_elements}->[$index]; + } + return "</$value>"; + }; + +$beginfield = sub { return ''; } if $opt{no_field_elements}; #hmm +$endfield = sub { return ''; } if $opt{no_field_elements}; #hmm + +</%init> diff --git a/httemplate/search/elements/search.html b/httemplate/search/elements/search.html index 636885edc..a258f1721 100644 --- a/httemplate/search/elements/search.html +++ b/httemplate/search/elements/search.html @@ -172,6 +172,10 @@ Example: % <% include('search-xls.html', header=>$header, rows=>$rows, opt=>\%opt ) %> % +% } elsif ( $type eq 'xml' ) { +% +<% include('search-xml.html', rows=>$rows, opt=>\%opt ) %> +% % } else { # regular HTML % <% include('search-html.html', @@ -195,7 +199,7 @@ my(%opt) = @_; my $curuser = $FS::CurrentUser::CurrentUser; -my $type = $cgi->param('_type') =~ /^(csv|\w*\.xls|select|html(-print)?)$/ +my $type = $cgi->param('_type') =~ /^(csv|\w*\.xls|xml|select|html(-print)?)$/ ? $1 : 'html' ; my %align = ( @@ -224,9 +228,13 @@ if($type =~ /csv|xls/) { } while ( exists($h->[$i]) ); } +# wtf? $opt{disable_download} = 0 if $opt{disable_download} && $curuser->access_right('Configuration download'); +$opt{disable_download} = 1 + if $opt{really_disable_download}; + my @link_agentnums = (); my $null_link = ''; if ( $opt{'agent_virt'} ) { diff --git a/httemplate/search/report_477.html b/httemplate/search/report_477.html index 2b5111209..bc2a95806 100755 --- a/httemplate/search/report_477.html +++ b/httemplate/search/report_477.html @@ -23,30 +23,167 @@ ) %> -% if ( scalar( qsearch( 'part_pkg_report_option', { 'disabled' => '' } ) ) ) { -% # the m2 javascript magic in edit/elements/edit.html would be better here - - <% include( '/elements/tr-select-table.html', - 'label' => 'Column report classes', - 'table' => 'part_pkg_report_option', - 'name_col' => 'name', - 'hashref' => { 'disabled' => '' }, - 'element_name' => 'column_option', - 'multiple' => 'multiple', + <SCRIPT type="text/javascript"> + function partchange(what) { + var id = 'part' + what.value; + var element = document.getElementById(id); + if (what.checked) { + element.style.display = ''; + } else { + element.style.display = 'none'; + } + } + </SCRIPT> + + <% include( '/elements/tr-checkbox.html', + 'label' => 'Enable part IA?', + 'field' => 'part', + 'value' => 'IA', + 'onchange' => 'partchange(this)', + ) + %> + + <TR id='partIA' style="display:none"><TD>Part IA</TD><TD><TABLE> + <TR><TD>Download speeds</TD><TD> + <TABLE> +% foreach my $speed ( @FS::Report::FCC_477::download ) { + <TR> + <TH><% $speed %></TH> + <TD> + <% include( '/elements/select-table.html', + 'table' => 'part_pkg_report_option', + 'name_col' => 'name', + 'hashref' => { 'disabled' => '' }, + 'element_name' => 'part1_column_option', + 'disable_empty' => 1, + ) + %> + </TD> + </TR> +% } + </TABLE></TD> + <TD>Upload speeds</TD><TD> + <TABLE> +% foreach my $speed ( @FS::Report::FCC_477::upload ) { + <TR> + <TH><% $speed %></TH> + <TD> + <% include( '/elements/select-table.html', + 'table' => 'part_pkg_report_option', + 'name_col' => 'name', + 'hashref' => { 'disabled' => '' }, + 'element_name' => 'part1_row_option', + 'disable_empty' => 1, + ) + %> + </TD> + </TR> +% } + </TABLE></TD></TR> + <TR><TD>Technologies</TD><TD> + <TABLE> +% my $i = 0; +% foreach my $tech ( @FS::Report::FCC_477::technology ) { + <TR> + <TH><% $tech %></TH> + <TD> + <% include( '/elements/select-table.html', + 'table' => 'part_pkg_report_option', + 'name_col' => 'name', + 'hashref' => { 'disabled' => '' }, + 'element_name' => "part1_technology_option_$i", + 'empty_label' => '(omit)', + ) + %> + </TD> + </TR> +% $i++ +% } + </TABLE></TD></TR> + </TABLE></TD></TR> + + <% include( '/elements/tr-checkbox.html', + 'label' => 'Enable part IIA?', + 'field' => 'part', + 'value' => 'IIA', + 'onchange' => 'partchange(this)', ) %> - <% include( '/elements/tr-select-table.html', - 'label' => 'Row report classes', - 'table' => 'part_pkg_report_option', - 'name_col' => 'name', - 'hashref' => { 'disabled' => '' }, - 'element_name' => 'row_option', - 'multiple' => 'multiple', + <TR id='partIIA' style="display:none"><TD>Part IIA</TD><TD><TABLE> +% foreach my $option ( @FS::Report::FCC_477::part2aoption ) { + <TR> + <TH><% $option %></TH> + <TD> + <% include( '/elements/select-table.html', + 'table' => 'part_pkg_report_option', + 'name_col' => 'name', + 'hashref' => { 'disabled' => '' }, + 'element_name' => 'part2a_row_option', + ) + %> + </TD> + </TR> +% } + </TABLE></TD></TR> + + <% include( '/elements/tr-checkbox.html', + 'label' => 'Enable part IIB?', + 'field' => 'part', + 'value' => 'IIB', + 'onchange' => 'partchange(this)', ) %> + <TR id='partIIB' style="display:none"><TD>Part IIB</TD><TD><TABLE> +% foreach my $option ( @FS::Report::FCC_477::part2boption ) { + <TR> + <TH><% $option %></TH> + <TD> + <% include( '/elements/select-table.html', + 'table' => 'part_pkg_report_option', + 'name_col' => 'name', + 'hashref' => { 'disabled' => '' }, + 'element_name' => 'part2b_row_option', + ) + %> + </TD> + </TR> % } + </TABLE></TD></TR> + + <% include( '/elements/tr-checkbox.html', + 'label' => 'Enable part IV?', + 'field' => 'part', + 'value' => 'IV', + 'onchange' => 'partchange(this)', + ) + %> + + <TR id='partIV' style="display:none"><TD>Part IV</TD><TD><TABLE> + <% include( '/elements/tr-textarea.html', + 'label' => 'Explanatory notes', + 'id' => 'partIV', + 'field' => 'notes', + 'rows' => 15, + 'cols' => 80, + ) + %> + </TABLE></TD></TR> + + <% include( '/elements/tr-checkbox.html', + 'label' => 'Enable part V?', + 'field' => 'part', + 'value' => 'V', + ) + %> + + <% include( '/elements/tr-checkbox.html', + 'label' => 'Enable part VI?', + 'field' => 'part', + 'value' => 'VI', + ) + %> </TABLE> |