477 report: mobile deployment info
authorMark Wells <mark@freeside.biz>
Wed, 6 Aug 2014 21:11:01 +0000 (14:11 -0700)
committerMark Wells <mark@freeside.biz>
Wed, 6 Aug 2014 21:11:01 +0000 (14:11 -0700)
13 files changed:
FS/FS/Report/FCC_477.pm
FS/FS/Schema.pm
FS/FS/deploy_zone.pm
FS/FS/deploy_zone_vertex.pm
FS/FS/part_pkg_fcc_option.pm
httemplate/browse/deploy_zone.html
httemplate/browse/part_pkg-fcc.html
httemplate/edit/deploy_zone-fixed.html
httemplate/edit/deploy_zone-mobile.html [new file with mode: 0644]
httemplate/edit/process/deploy_zone-mobile.html [new file with mode: 0644]
httemplate/elements/deploy_zone_vertex.html [new file with mode: 0644]
httemplate/misc/part_pkg_fcc_options.html
httemplate/search/report_477.html

index 86fa0a6..0f3dfb1 100644 (file)
@@ -11,7 +11,7 @@ use FS::Record qw( dbh );
 use Tie::IxHash;
 use Storable;
 
-$DEBUG = 1;
+$DEBUG = 0;
 
 =head1 NAME
 
@@ -259,9 +259,11 @@ sub active_on {
 }
 
 sub is_fixed_broadband {
-  "is_broadband::int = 1 AND technology::int IN(".join(',',
-    10, 11, 12, 20, 30, 40, 41, 42, 50, 60, 70, 90, 0
-  ).")";
+  "is_broadband::int = 1 AND technology::int IN( 10, 11, 12, 20, 30, 40, 41, 42, 50, 60, 70, 90, 0 )"
+}
+
+sub is_mobile_broadband {
+  "is_broadband::int = 1 AND technology::int IN( 80, 81, 82, 83, 84, 85, 86, 87, 88)"
 }
 
 =item report SECTION, OPTIONS
@@ -290,7 +292,7 @@ sub report {
 
 sub fbd_sql {
   my $class = shift;
-  my %opt = shift;
+  my %opt = @_;
   my $date = $opt{date} || time;
   warn $date;
   my $agentnum = $opt{agentnum};
@@ -328,7 +330,7 @@ sub fbd_sql {
 
 sub fbs_sql {
   my $class = shift;
-  my %opt = shift;
+  my %opt = @_;
   my $date = $opt{date} || time;
   my $agentnum = $opt{agentnum};
 
@@ -371,7 +373,7 @@ sub fbs_sql {
 
 sub fvs_sql {
   my $class = shift;
-  my %opt = shift;
+  my %opt = @_;
   my $date = $opt{date} || time;
   my $agentnum = $opt{agentnum};
 
@@ -413,7 +415,7 @@ sub fvs_sql {
 
 sub lts_sql {
   my $class = shift;
-  my %opt = shift;
+  my %opt = @_;
   my $date = $opt{date} || time;
   my $agentnum = $opt{agentnum};
 
@@ -465,7 +467,7 @@ sub lts_sql {
 
 sub voip_sql {
   my $class = shift;
-  my %opt = shift;
+  my %opt = @_;
   my $date = $opt{date} || time;
   my $agentnum = $opt{agentnum};
 
@@ -510,7 +512,82 @@ sub voip_sql {
   GROUP BY $group_by
   ORDER BY $order_by
   ";
+}
+
+sub mbs_sql {
+  my $class = shift;
+  my %opt = @_;
+  my $date = $opt{date} || time;
+  my $agentnum = $opt{agentnum};
+
+  my @select = (
+    'state.fips',
+    'broadband_downstream',
+    'broadband_upstream',
+    'COUNT(*)',
+    'COUNT(is_consumer)',
+  );
+  my $from =
+    'cust_pkg
+      JOIN cust_location ON (cust_pkg.locationnum = cust_location.locationnum)
+      JOIN state USING (country, state)
+      JOIN cust_main ON (cust_pkg.custnum = cust_main.custnum)
+      JOIN part_pkg USING (pkgpart) '.
+      join_optionnames_int(qw(
+        is_broadband technology
+        is_consumer
+        )).
+      join_optionnames(qw(broadband_downstream broadband_upstream))
+  ;
+  my @where = (
+    active_on($date),
+    is_mobile_broadband()
+  );
+  push @where, "cust_main.agentnum = $agentnum" if $agentnum;
+  my $group_by = 'state.fips, broadband_downstream, broadband_upstream ';
+  my $order_by = $group_by;
+
+  "SELECT ".join(', ', @select) . "
+  FROM $from
+  WHERE ".join(' AND ', @where)."
+  GROUP BY $group_by
+  ORDER BY $order_by
+  ";
+}
+
+sub mvs_sql {
+  my $class = shift;
+  my %opt = @_;
+  my $date = $opt{date} || time;
+  my $agentnum = $opt{agentnum};
+
+  my @select = (
+    'state.fips',
+    'COUNT(*)',
+    'COUNT(mobile_direct)',
+  );
+  my $from =
+    'cust_pkg
+      JOIN cust_location ON (cust_pkg.locationnum = cust_location.locationnum)
+      JOIN state USING (country, state)
+      JOIN cust_main ON (cust_pkg.custnum = cust_main.custnum)
+      JOIN part_pkg USING (pkgpart) '.
+      join_optionnames_int(qw( is_mobile mobile_direct) )
+  ;
+  my @where = (
+    active_on($date),
+    'is_mobile = 1'
+  );
+  push @where, "cust_main.agentnum = $agentnum" if $agentnum;
+  my $group_by = 'state.fips';
+  my $order_by = $group_by;
 
+  "SELECT ".join(', ', @select) . "
+  FROM $from
+  WHERE ".join(' AND ', @where)."
+  GROUP BY $group_by
+  ORDER BY $order_by
+  ";
 }
 
 =item parts
index 2b6dc6d..1b82e0e 100644 (file)
@@ -6682,11 +6682,12 @@ sub tables_hashref {
         'zonetype',       'char',    '',     1,       '', '',
         'technology',     'int',     '',     '',      '', '',
         'spectrum',       'int',     'NULL', '',      '', '',
-        'servicetype',    'char',    '',     '12',    '', '',
         'adv_speed_up',   'decimal', '',     '10,3', '0', '',
         'adv_speed_down', 'decimal', '',     '10,3', '0', '',
         'cir_speed_up',   'decimal', '',     '10,3', '0', '',
         'cir_speed_down', 'decimal', '',     '10,3', '0', '',
+        'is_broadband',   'char',    'NULL', 1,       '', '',
+        'is_voice',       'char',    'NULL', 1,       '', '',
         'is_consumer',    'char',    'NULL', 1,       '', '',
         'is_business',    'char',    'NULL', 1,       '', '',
         'active_date',    @date_type,                 '', '',
@@ -6727,10 +6728,9 @@ sub tables_hashref {
         'zonenum',        'int',     '',     '',      '', '',
         'latitude',       'decimal', '',     '10,7',  '', '', 
         'longitude',      'decimal', '',     '10,7',  '', '', 
-        'sequence',       'int',     '',     '',      '', '',
       ],
       'primary_key' => 'vertexnum',
-      'unique' => [ [ 'zonenum', 'sequence' ] ],
+      'unique' => [ ],
       'index'  => [ ],
       'foreign_keys' => [
                           { columns     => [ 'zonenum' ],
index 227a022..16f59c8 100644 (file)
@@ -65,10 +65,6 @@ The FCC technology code for the type of service available.
 
 For mobile service zones, the FCC code for the RF band.
 
-=item servicetype
-
-"broadband" or "voice"
-
 =item adv_speed_up
 
 For broadband, the advertised upstream bandwidth in the zone.  If multiple
@@ -97,6 +93,14 @@ type of service is sold.
 'Y' if this service is sold to business or institutional use.  Not mutually
 exclusive with is_consumer.
 
+=item is_broadband
+
+'Y' if this service includes broadband Internet.
+
+=item is_voice
+
+'Y' if this service includes voice communication.
+
 =item active_date
 
 The date this zone became active.
@@ -180,25 +184,30 @@ sub check {
     || $self->ut_textn('description')
     || $self->ut_number('agentnum')
     || $self->ut_foreign_key('agentnum', 'agent', 'agentnum')
-    || $self->ut_alphan('dbaname')
+    || $self->ut_textn('dbaname')
     || $self->ut_enum('zonetype', [ 'B', 'P' ])
     || $self->ut_number('technology')
     || $self->ut_numbern('spectrum')
-    || $self->ut_enum('servicetype', [ 'broadband', 'voice' ])
     || $self->ut_decimaln('adv_speed_up', 3)
     || $self->ut_decimaln('adv_speed_down', 3)
     || $self->ut_decimaln('cir_speed_up', 3)
     || $self->ut_decimaln('cir_speed_down', 3)
     || $self->ut_flag('is_consumer')
     || $self->ut_flag('is_business')
+    || $self->ut_flag('is_broadband')
+    || $self->ut_flag('is_voice')
     || $self->ut_numbern('active_date')
     || $self->ut_numbern('expire_date')
   ;
   return $error if $error;
 
   foreach(qw(adv_speed_down adv_speed_up cir_speed_down cir_speed_up)) {
-    if (!$self->get($_)) {
-      $self->set($_, 0);
+    if ($self->get('is_broadband')) {
+      if (!$self->get($_)) {
+        $self->set($_, 0);
+      }
+    } else {
+      $self->set($_, '');
     }
   }
   if (!$self->get('active_date')) {
@@ -226,7 +235,35 @@ sub element_table {
   }
 }
 
-=back
+=item deploy_zone_block
+
+Returns the census block records in this zone, in order by census block
+number.  Only appropriate to block-type zones.
+
+=item deploy_zone_vertex
+
+Returns the vertex records for this zone, in order by sequence number.  Only
+appropriate to polygon-type zones.
+
+=cut
+
+sub deploy_zone_block {
+  my $self = shift;
+  qsearch({
+      table     => 'deploy_zone_block',
+      hashref   => { zonenum => $self->zonenum },
+      order_by  => ' ORDER BY censusblock',
+  });
+}
+
+sub deploy_zone_vertex {
+  my $self = shift;
+  qsearch({
+      table     => 'deploy_zone_vertex',
+      hashref   => { zonenum => $self->zonenum },
+      order_by  => ' ORDER BY vertexnum',
+  });
+}
 
 =head1 BUGS
 
index a25bfde..078b326 100644 (file)
@@ -47,10 +47,6 @@ Latitude, as a decimal; positive values are north of the Equator.
 
 Longitude, as a decimal; positive values are east of Greenwich.
 
-=item sequence
-
-The ordinal position of this vertex, starting with zero.
-
 =back
 
 =head1 METHODS
@@ -104,7 +100,6 @@ sub check {
     || $self->ut_number('zonenum')
     || $self->ut_coord('latitude')
     || $self->ut_coord('longitude')
-    || $self->ut_number('sequence')
   ;
   return $error if $error;
 
index a090b96..5c78e5f 100644 (file)
@@ -139,6 +139,23 @@ tie our %technology_labels, 'Tie::IxHash',  (
   0  => 'Other'
 );
 
+tie our %spectrum_labels, 'Tie::IxHash', (
+  90 => '700 MHz Band',
+  91 => 'Cellular Band',
+  92 => 'Specialized Mobile Radio (SMR) Band',
+  93 => 'Advanced Wireless Services (AWS) 1 Band',
+  94 => 'Broadband Personal Communications Service (PCS) Band',
+  95 => 'Wireless Communications Service (WCS) Band',
+  96 => 'Broadband Radio Service/Educational Broadband Service Band',
+  97 => 'Satellite (e.g. L-band, Big LEO, Little LEO)',
+  98 => 'Unlicensed (including broadcast television “white spaces”) Bands',
+  99 => '600 MHz',
+  100 => 'H Block',
+  101 => 'Advanced Wireless Services (AWS) 3 Band',
+  102 => 'Advanced Wireless Services (AWS) 4 Band',
+  103 => 'Other',
+);
+
 sub media_types {
   Storable::dclone(\%media_types);
 }
@@ -147,6 +164,10 @@ sub technology_labels {
   Storable::dclone(\%technology_labels);
 }
 
+sub spectrum_labels {
+  Storable::dclone(\%spectrum_labels);
+}
+
 =head1 BUGS
 
 =head1 SEE ALSO
index 489a226..ddfbde4 100644 (file)
@@ -48,9 +48,9 @@
   sort_fields     => [ 'zonenum',
                        'description',
                        'technology',
-                       'is_consumer is not null, is_business is not null',
-                       'adv_speed_down, adv_speed_up',
-                       'cir_speed_down, cir_speed_up',
+                       '(is_consumer is not null, is_business is not null)',
+                       '(adv_speed_down, adv_speed_up)',
+                       '(cir_speed_down, cir_speed_up)',
                      ],
   links           => [  '', $link_fixed, ],
   align           => 'clllllr',
   disable_maxselect => 1,
   disable_total     => 1,
 &>
+<P><FONT SIZE="+1"><B>Mobile Zones</B></FONT></P>
+<& elements/browse.html,
+  name_singular   => 'zone',
+  query           => { table      => 'deploy_zone',
+                       hashref    => { zonetype => 'P' },
+                     },
+  count_query     => "SELECT COUNT(*) FROM deploy_zone WHERE zonetype = 'P'",
+  agent_virt      => 1,
+  header          => [  '#',
+                        'Description',
+                        'Technology',
+                        'Spectrum',
+                        'Service Type',
+                        'Advertised Mbps',
+                        'Vertices', # number of vertices? not so useful
+                     ],
+  fields          => [  'zonenum',
+                        'description',
+                        sub { my $self = shift;
+                              $tech_label->{$self->technology} },
+                        sub { my $self = shift;
+                              $spec_label->{$self->spectrum} },
+                        sub { my $self = shift;
+                              join( ' / ',
+                                $self->is_voice ? 'voice' : (),
+                                $self->is_broadband ? 'broadband' : (),
+                              )
+                            },
+                        sub { my $self = shift;
+                              join( ' / ', grep $_,
+                                $self->adv_speed_down,
+                                $self->adv_speed_up
+                              )
+                            },
+                        sub { my $self = shift;
+                              FS::deploy_zone_vertex->count('zonenum = '.$self->zonenum)
+                            },
+                     ],
+  sort_fields     => [ 'zonenum',
+                       'description',
+                       'technology',
+                       'spectrum',
+                       '(is_voice is not null, is_broadband is not null)',
+                       '(adv_speed_down, adv_speed_up)',
+                     ],
+  links           => [  '', $link_mobile, ],
+  align           => 'clllllr',
+  nohtmlheader    => 1,
+  disable_maxselect => 1,
+  disable_total     => 1,
+&>
+
+<& /elements/footer.html &>
 <%init>
 my $curuser = $FS::CurrentUser::CurrentUser;
 my $acl_edit = $curuser->access_right('Edit FCC report configuration');
@@ -66,7 +119,8 @@ die "access denied"
   unless $acl_edit or $acl_edit_global;
 
 my $link_fixed = [ $p.'edit/deploy_zone-fixed.html?', 'zonenum' ];
-my $link_mobile= [ $p.'edit/deploy_zone-mobile.html', 'zonenum' ];
+my $link_mobile= [ $p.'edit/deploy_zone-mobile.html?', 'zonenum' ];
 
 my $tech_label = FS::part_pkg_fcc_option->technology_labels;
+my $spec_label = FS::part_pkg_fcc_option->spectrum_labels;
 </%init>
index 9facd10..14dfcba 100755 (executable)
@@ -30,8 +30,8 @@
 
 my $curuser = $FS::CurrentUser::CurrentUser;
 
-my $edit        = 'Edit package definitions';
-my $edit_global = 'Edit global package definitions';
+my $edit        = 'Edit FCC report configuration';
+my $edit_global = 'Edit FCC report configuration for all agents';
 my $acl_edit        = $curuser->access_right($edit);
 my $acl_edit_global = $curuser->access_right($edit_global);
 
index 8c6d54e..1a79500 100644 (file)
@@ -21,9 +21,9 @@
           type          => 'hidden',
           value         => 'B'
         },
-        { field         => 'servicetype',
+        { field         => 'is_broadband',
           type          => 'hidden',
-          value         => 'broadband'
+          value         => 'Y',
         },
         'description',
         { field         => 'active_date',
@@ -38,7 +38,7 @@
         'dbaname',
         { field         => 'technology',
           type          => 'select',
-          options       => [ keys(%$technology_labels) ],
+          options       => [ map { @$_ } values(%$media_types) ],
           labels        => $technology_labels,
         },
         { field         => 'is_consumer', type => 'checkbox', value=>'Y' },
@@ -71,6 +71,8 @@ die "access denied"
   ]);
 
 my $technology_labels = FS::part_pkg_fcc_option->technology_labels;
+my $media_types = FS::part_pkg_fcc_option->media_types;
+delete $media_types->{'Mobile Wireless'}; # cause this is the fixed zone page
 
 my $m2_error_callback = sub {
   my ($cgi, $deploy_zone) = @_;
@@ -78,6 +80,7 @@ my $m2_error_callback = sub {
     /^blocknum\d+/ and length($cgi->param($_.'_censusblock'))
   } $cgi->param;
 
+  sort { $a->censusblock <=> $b->censusblock }
   map {
     my $k = $_;
     FS::deploy_zone_block->new({
diff --git a/httemplate/edit/deploy_zone-mobile.html b/httemplate/edit/deploy_zone-mobile.html
new file mode 100644 (file)
index 0000000..8e985b1
--- /dev/null
@@ -0,0 +1,90 @@
+<& elements/edit.html,
+    'name_singular' => 'deployment zone',
+    'table'         => 'deploy_zone',
+    'post_url'      => popurl(1).'process/deploy_zone-mobile.html',
+    'labels'        => {
+        'description'     => 'Description',
+        'agentnum'        => 'Agent',
+        'dbaname'         => 'Business name (if different from agent)',
+        'technology'      => 'Technology',
+        'spectrum'        => 'Spectrum',
+        'is_broadband',   => 'Broadband Internet',
+        'adv_speed_up'    => 'Upstream',
+        'adv_speed_down'  => 'Downstream',
+        'is_voice',       => 'Voice',
+        'vertexnum'       => '',
+        'active_date'     => 'Active since',
+    },
+    'fields'        => [
+        { field         => 'zonetype',
+          type          => 'hidden',
+          value         => 'P'
+        },
+        'description',
+        { field         => 'active_date',
+          type          => 'fixed-date',
+          value         => time,
+        },
+        { field         => 'agentnum',
+          type          => 'select-agent',
+          disable_empty => 1,
+          viewall_right => 'Edit FCC report configuration for all agents',
+        },
+        'dbaname',
+        { field         => 'technology',
+          type          => 'select',
+          options       => $media_types->{'Mobile Wireless'},
+          labels        => $technology_labels,
+        },
+        { field         => 'spectrum',
+          type          => 'select',
+          options       => [ keys %$spectrum_labels ],
+          labels        => $spectrum_labels,
+        },
+        { field         => 'is_broadband', type => 'checkbox', value=>'Y' },
+        { field         => 'is_voice', type => 'checkbox', value=>'Y' },
+        { type => 'tablebreak-tr-title',
+          value => 'Advertised minimum speed (Mbps)' },
+        'adv_speed_down',
+        'adv_speed_up',
+        { type => 'tablebreak-tr-title', value => 'Footprint'},
+        { field => 'vertexnum',
+          type              => 'deploy_zone_vertex',
+          o2m_table         => 'deploy_zone_vertex',
+          m2_label          => ' ',
+          m2_error_callback => $m2_error_callback,
+        },
+    ],
+
+&>
+<%init>
+my $curuser = $FS::CurrentUser::CurrentUser;
+die "access denied"
+  unless $curuser->access_right([
+    'Edit FCC report configuration',
+    'Edit FCC report configuration for all agents',
+  ]);
+
+my $technology_labels = FS::part_pkg_fcc_option->technology_labels;
+my $spectrum_labels = FS::part_pkg_fcc_option->spectrum_labels;
+my $media_types = FS::part_pkg_fcc_option->media_types;
+
+my $m2_error_callback = sub {
+  my ($cgi, $deploy_zone) = @_;
+  my @vertexnums = sort { $a <=> $b } grep {
+    /^vertexnum\d+/ and length($cgi->param($_.'_latitude'))
+  } $cgi->param;
+
+  map {
+    my $k = $_;
+    my $s = 0;
+    FS::deploy_zone_vertex->new({
+      vertexnum   => scalar($cgi->param($k)),
+      zonenum     => $deploy_zone->zonenum,
+      latitude    => scalar($cgi->param($k.'_latitude')),
+      longitude   => scalar($cgi->param($k.'_longitude')),
+    })
+  } @vertexnums;
+};
+
+</%init>
diff --git a/httemplate/edit/process/deploy_zone-mobile.html b/httemplate/edit/process/deploy_zone-mobile.html
new file mode 100644 (file)
index 0000000..c913c5c
--- /dev/null
@@ -0,0 +1,9 @@
+<& elements/process.html, 
+    error_redirect => popurl(2).'deploy_zone-mobile.html?',
+    table       => 'deploy_zone',
+    viewall_dir => 'browse',
+    process_o2m => 
+      { 'table'  => 'deploy_zone_vertex',
+                     'fields' => [qw( latitude longitude )]
+      },
+&>
diff --git a/httemplate/elements/deploy_zone_vertex.html b/httemplate/elements/deploy_zone_vertex.html
new file mode 100644 (file)
index 0000000..b3c8b31
--- /dev/null
@@ -0,0 +1,45 @@
+% unless ( $opt{'js_only'} ) {
+
+  <INPUT TYPE="hidden" NAME="<%$name%>" ID="<%$id%>" VALUE="<% $curr_value %>">
+  Latitude&nbsp;
+  <INPUT TYPE  = "text"
+         NAME  = "<%$name%>_latitude"
+         ID    = "<%$id%>_latitude"
+         VALUE = "<% scalar($cgi->param($name.'_latitude'))
+                      || $deploy_zone_vertex->latitude
+                 %>"
+         SIZE  = 18
+         <% $onchange %>
+  >
+  &nbsp;
+  Longitude&nbsp;
+  <INPUT TYPE  = "text"
+         NAME  = "<%$name%>_longitude"
+         ID    = "<%$id%>_longitude"
+         VALUE = "<% scalar($cgi->param($name.'_longitude'))
+                      || $deploy_zone_vertex->longitude
+                 %>"
+         SIZE  = 18
+         <% $onchange %>
+  >
+% }
+<%init>
+
+my( %opt ) = @_;
+
+my $name = $opt{'element_name'} || $opt{'field'} || 'vertexnum';
+my $id = $opt{'id'} || 'vertexnum';
+
+my $curr_value = $opt{'curr_value'} || $opt{'value'};
+
+my $onchange = $opt{'onchange'};
+if ( $onchange ) {
+  $onchange =~ s/\(what\);/(this);/;
+  $onchange = 'onchange="'.$onchange.'"';
+}
+
+my $deploy_zone_vertex = $curr_value
+  ? FS::deploy_zone_vertex->by_key($curr_value)
+  : FS::deploy_zone_vertex->new;
+
+</%init>
index a5ecb12..27b45e0 100644 (file)
     <FIELDSET ID="voip">
       <LABEL FOR="voip_sessions">Number of simultaneous calls possible</LABEL>
       <INPUT NAME="voip_sessions" ID="voip_sessions">
+      <BR>
       <& .checkbox, 'voip_lastmile' &>
       <LABEL FOR="voip_lastmile">Do you also provide last-mile connectivity?</LABEL>
     </FIELDSET>
   </P>
+  <P>
+    <& .checkbox, 'is_mobile' &>
+    <LABEL FOR="is_mobile">This package provides mobile telephone service</LABEL>
+    <FIELDSET ID="mobile">
+      <LABEL FOR="mobile_direct">Do you bill the customer directly?</LABEL>
+      <& .checkbox, 'mobile_direct' &>
+    </FIELDSET>
+  </P>
   <DIV WIDTH="100%" STYLE="text-align:center">
     <INPUT TYPE="submit" VALUE="Save changes">
   </DIV>
@@ -168,7 +177,7 @@ function enable_fieldset(fieldset_id) {
   // set up all event handlers
   addEventListener(form, 'submit', save_changes);
 
-  var sections = [ 'broadband', 'phone', 'voip' ];
+  var sections = [ 'broadband', 'phone', 'voip', 'mobile' ];
   for(var i = 0; i < sections.length; i++) {
     var toggle = form.elements['is_'+sections[i]];
     addEventListener(toggle, 'change', enable_fieldset(sections[i]));
index 78ba35c..cbbd5d9 100755 (executable)
@@ -4,11 +4,13 @@
 %   $m->abort;
 % }
 <& /elements/header.html, 'FCC Form 477 Report' &>
+% if ( $curuser->access_right('Edit FCC report configuration') ) {
 <FONT SIZE="+1"><STRONG>Preparation</STRONG></FONT>
 <UL>
   <LI> <A HREF="<% $p %>browse/part_pkg-fcc.html">Configure packages</A> for FCC reporting categories.</LI>
   <LI> <A HREF="<% $p %>browse/deploy_zone.html">Enter deployment zones</A> for broadband Internet or mobile phone.</LI>
 </UL>
+% }
   
 <FORM ACTION="477.html" METHOD="GET">
 
@@ -48,8 +50,9 @@
 <& /elements/footer.html &>
 <%init>
 
+my $curuser = $FS::CurrentUser::CurrentUser;
 die "access denied"
-  unless $FS::CurrentUser::CurrentUser->access_right('List packages');
+  unless $curuser->access_right('List packages');
 
 my $conf = FS::Conf->new;