diff options
| -rw-r--r-- | FS/FS/Conf.pm | 7 | ||||
| -rw-r--r-- | FS/FS/Mason.pm | 1 | ||||
| -rw-r--r-- | FS/FS/Report/FCC_477.pm | 90 | ||||
| -rw-r--r-- | FS/FS/Schema.pm | 1 | ||||
| -rw-r--r-- | FS/FS/cust_pkg.pm | 39 | ||||
| -rw-r--r-- | FS/FS/part_pkg.pm | 3 | ||||
| -rw-r--r-- | FS/MANIFEST | 1 | ||||
| -rw-r--r-- | FS/t/Report-FCC_477.t | 5 | ||||
| -rwxr-xr-x | httemplate/edit/part_pkg.cgi | 11 | ||||
| -rwxr-xr-x | httemplate/search/477.html | 257 | ||||
| -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 | 
22 files changed, 1213 insertions, 201 deletions
| diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 7f914901d..6658704cc 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2369,6 +2369,13 @@ worry that config_items is freeside-specific and icky.    },    { +    'key'         => 'cust_pkg-show_fcc_voice_grade_equivalent', +    'section'     => 'UI', +    'description' => "Show a field on package definitions for assigning a DSO equivalency number suitable for use on FCC form 477.", +    'type'        => 'checkbox', +  }, + +  {      'key'         => 'svc_acct-edit_uid',      'section'     => 'shell',      'description' => 'Allow UID editing.', diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index 155a80966..a0a5b4b34 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -121,6 +121,7 @@ if ( -e $addl_handler_use_file ) {    use FS::Msgcat qw(gettext geterror);    use FS::Misc qw( send_email send_fax states_hash counties state_label );    use FS::Misc::eps2png qw( eps2png ); +  use FS::Report::FCC_477;    use FS::Report::Table::Monthly;    use FS::TicketSystem;    use FS::Tron qw( tron_lint ); diff --git a/FS/FS/Report/FCC_477.pm b/FS/FS/Report/FCC_477.pm new file mode 100644 index 000000000..518b9f0e1 --- /dev/null +++ b/FS/FS/Report/FCC_477.pm @@ -0,0 +1,90 @@ +package FS::Report::FCC_477; + +use strict; +use vars qw( @ISA @upload @download @technology @part2aoption @part2boption ); +use FS::Report; + +@ISA = qw( FS::Report ); + +=head1 NAME + +FS::Report::FCC_477 - Routines for FCC Form 477 reports + +=head1 SYNOPSIS + +=head1 BUGS + +Documentation. + +=head1 SEE ALSO + +=cut + +@upload = qw( + <200kpbs + 200-768kpbs + 768kbps-1.5mbps + 1.5-3mpbs + 3-6mbps + 6-10mbps + 10-25mbps + 25-100mbps + >100bmps +); + +@download = qw( + 200-768kpbs + 768kbps-1.5mbps + 1.5-3mpbs + 3-6mbps + 6-10mbps + 10-25mbps + 25-100mbps + >100bmps +); + +@technology = ( +  'Asymetric xDSL', +  'Symetric xDSL', +  'Other Wireline', +  'Cable Modem', +  'Optical Carrier', +  'Satellite', +  'Terrestrial Fixed Wireless', +  'Terrestrial Mobile Wireless', +  'Electric Power Line', +  'Other Technology', +); + +@part2aoption = ( + 'LD carrier', + 'owned loops', + 'unswitched UNE loops', + 'UNE-P', + 'UNE-P replacement', + 'FTTP', + 'coax', + 'wireless', +); + +@part2boption = ( + 'nomadic', + 'copper', + 'FTTP', + 'coax', + 'wireless', + 'other broadband', +); + +sub parse_technology_option { +  my $cgi = shift; +  my @result = (); +  my $i = 0; +  for (my $i = 0; $i < scalar(@technology); $i++) { +    my $value = $cgi->param("part1_technology_option_$i"); #lame +    push @result, $value =~ /^\d+$/ ? $value : 0; +  } +  return (@result); +} + +1; diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 78f3e44a9..3cc853f20 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1298,6 +1298,7 @@ sub tables_hashref {          'pay_weight',    'real',    'NULL', '', '', '',          'credit_weight', 'real',    'NULL', '', '', '',          'agentnum',      'int',     'NULL', '', '', '',  +        'fcc_ds0s',      'int',     'NULL', '', '', '',         ],        'primary_key' => 'pkgpart', diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 89eadd599..80c8a32fb 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -2381,6 +2381,10 @@ a value suited to passing to FS::UI::Web::cust_header  specifies the user for agent virtualization +=item fcc_line + + boolean selects packages containing fcc form 477 telco lines +  =back  =cut @@ -2502,6 +2506,12 @@ sub search {    push @where,  "part_pkg.custom = 'Y'" if $params->{custom};    ### +  # parse fcc_line +  ### + +  push @where,  "part_pkg.fcc_ds0s > 0" if $params->{fcc_line}; + +  ###    # parse censustract    ### @@ -2648,6 +2658,35 @@ sub search {  } +=item fcc_477_count + +Returns a list of two package counts.  The first is a count of packages +based on the supplied criteria and the second is the count of residential +packages with those same criteria.  Criteria are specified as in the search +method. + +=cut + +sub fcc_477_count { +  my ($class, $params) = @_; + +  my $sql_query = $class->search( $params ); + +  my $count_sql = delete($sql_query->{'count_query'}); +  $count_sql =~ s/ FROM/,count(CASE WHEN cust_main.company IS NULL OR cust_main.company = '' THEN 1 END) 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; + +  return ( @$count_arrayref ); + +} + +  =item location_sql  Returns a list: the first item is an SQL fragment identifying matching  diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm index 276889d62..95bc56a13 100644 --- a/FS/FS/part_pkg.pm +++ b/FS/FS/part_pkg.pm @@ -98,6 +98,8 @@ inherits from FS::Record.  The following fields are currently supported:  =item agentnum - Optional agentnum (see L<FS::agent>) +=item fcc_ds0s - Optional DS0 equivalency number for FCC form 477 +  =back  =head1 METHODS @@ -477,6 +479,7 @@ sub check {             ? $self->ut_foreign_keyn('agentnum', 'agent', 'agentnum' )             : $self->ut_agentnum_acl('agentnum', \@null_agentnum_right)         ) +    || $self->ut_numbern('fcc_ds0s')      || $self->SUPER::check    ;    return $error if $error; diff --git a/FS/MANIFEST b/FS/MANIFEST index 5bcb8534f..e348b8bf7 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -39,6 +39,7 @@ FS/Daemon.pm  FS/Misc.pm  FS/Record.pm  FS/Report.pm +FS/Report/FCC_477.pm  FS/Report/Table.pm  FS/Report/Table/Monthly.pm  FS/SearchCache.pm diff --git a/FS/t/Report-FCC_477.t b/FS/t/Report-FCC_477.t new file mode 100644 index 000000000..b7359aa83 --- /dev/null +++ b/FS/t/Report-FCC_477.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::Report::FCC_477; +$loaded=1; +print "ok 1\n"; diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index 9ee8d4d0d..52f70c5cb 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -47,6 +47,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' => [ @@ -159,6 +160,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..06e544c0b 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,16 @@ 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); +  warn "mangling $url with $part\n"; +  $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 3d4a4b039..67f0b0d03 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" );  @@ -416,9 +429,11 @@  %     }  %     if ( $type eq 'html-print' ) { +%       unless ( $opt{nohtmlheader} ) {          </BODY></HTML> +%       }  %     } else {          <% defined($opt{'html_foot'})  @@ -429,7 +444,10 @@                : ''          %> -        <% include( '/elements/footer.html' ) %> +        <% $opt{nohtmlheader} +             ? '' +             : include( '/elements/footer.html' ) +        %>  %     } @@ -446,6 +464,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 1312cac41..b97a9b321 100644 --- a/httemplate/search/elements/search.html +++ b/httemplate/search/elements/search.html @@ -171,6 +171,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', @@ -194,7 +198,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 = ( @@ -223,9 +227,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 7b85c137c..206d49056 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> | 
