[freeside-commits] branch master updated. eb9d1063e1203231ee0c6922ea5638370f7b5ece

Mark Wells mark at 420.am
Mon Feb 27 10:32:54 PST 2012


The branch, master has been updated
       via  eb9d1063e1203231ee0c6922ea5638370f7b5ece (commit)
      from  caba365bbebc7e73ad0c25f9a3a9c75a48ed6140 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit eb9d1063e1203231ee0c6922ea5638370f7b5ece
Author: Mark Wells <mark at freeside.biz>
Date:   Mon Feb 27 10:31:47 2012 -0800

    allow svc_broadband to link directly to a router, #14698

diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 483c5e0..b2dddca 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -2484,6 +2484,7 @@ sub tables_hashref {
         'routername', 'varchar', '', $char_d, '', '', 
         'svcnum', 'int', 'NULL', '', '', '', 
         'agentnum',   'int', 'NULL', '', '', '', 
+        'auto_addr', 'char', 'NULL', 1, '', '',
       ],
       'primary_key' => 'routernum',
       'unique'      => [],
@@ -2519,6 +2520,7 @@ sub tables_hashref {
       'columns' => [
         'svcnum',                  'int',     '',      '', '', '', 
         'description',         'varchar', 'NULL', $char_d, '', '', 
+        'routernum',               'int', 'NULL',      '', '', '',
         'blocknum',                'int', 'NULL',      '', '', '', 
         'sectornum',               'int', 'NULL',      '', '', '',
         'speed_up',                'int', 'NULL',      '', '', '', 
diff --git a/FS/FS/Upgrade.pm b/FS/FS/Upgrade.pm
index d00bb5c..8f66c66 100644
--- a/FS/FS/Upgrade.pm
+++ b/FS/FS/Upgrade.pm
@@ -264,7 +264,10 @@ sub upgrade_data {
     'part_export'      => [],
 
     #insert default tower_sector if not present
-    'tower',
+    'tower' => [],
+
+    #routernum/blocknum
+    'svc_broadband' => [],
   ;
 
   \%hash;
diff --git a/FS/FS/addr_block.pm b/FS/FS/addr_block.pm
index be42cb5..e00f587 100755
--- a/FS/FS/addr_block.pm
+++ b/FS/FS/addr_block.pm
@@ -8,6 +8,7 @@ use FS::svc_broadband;
 use FS::Conf;
 use NetAddr::IP;
 use Carp qw( carp );
+use List::Util qw( first );
 
 @ISA = qw( FS::Record );
 
@@ -222,37 +223,43 @@ sub cidr {
   $self->NetAddr->cidr;
 }
 
-=item next_free_addr
+=item free_addrs
 
 Returns a NetAddr::IP object corresponding to the first unassigned address 
 in the block (other than the network, broadcast, or gateway address).  If 
-there are no free addresses, returns false.  There are never free addresses
+there are no free addresses, returns nothing.  There are never free addresses
 when manual_flag is true.
 
+=item next_free_addr
+
+Returns a NetAddr::IP object for the first unassigned address in the block,
+or '' if there are none.
+
 =cut
 
-sub next_free_addr {
+sub free_addrs {
   my $self = shift;
 
-  return '' if $self->manual_flag;
+  return if $self->manual_flag;
 
   my $conf = new FS::Conf;
   my @excludeaddr = $conf->config('exclude_ip_addr');
   
-my @used =
-( (map { $_->NetAddr->addr }
-    ($self,
-     qsearch('svc_broadband', { blocknum => $self->blocknum }))
-  ), @excludeaddr
-);
-
-  my @free = $self->NetAddr->hostenum;
-  while (my $ip = shift @free) {
-    if (not grep {$_ eq $ip->addr;} @used) { return $ip; };
-  }
+  my %used = map { $_ => 1 }
+  (
+    (map { $_->NetAddr->addr }
+      ($self,
+       qsearch('svc_broadband', { blocknum => $self->blocknum }))
+    ), @excludeaddr
+  );
 
-  '';
+  grep { !$used{$_->addr} } $self->NetAddr->hostenum;
+
+}
 
+sub next_free_addr {
+  my $self = shift;
+  ($self->free_addrs, '')[0]
 }
 
 =item allocate -- deprecated
diff --git a/FS/FS/part_export/router.pm b/FS/FS/part_export/router.pm
index 42aa51c..6a1d676 100644
--- a/FS/FS/part_export/router.pm
+++ b/FS/FS/part_export/router.pm
@@ -302,13 +302,13 @@ sub _queue {
 }
 
 sub _get_router {
-  my ($self, $svc_broadband, %args) = (shift, shift, shift, @_);
+  my ($self, $svc_broadband, %args) = (shift, shift, @_);
 
   my $router;
   if ($args{'routernum'}) {
     $router = qsearchs('router', { routernum => $args{'routernum'}});
   } else {
-    $router = $svc_broadband->addr_block->router;
+    $router = $svc_broadband->router;
   }
 
   return($router);
diff --git a/FS/FS/router.pm b/FS/FS/router.pm
index f66f2ce..99373e5 100755
--- a/FS/FS/router.pm
+++ b/FS/FS/router.pm
@@ -40,6 +40,9 @@ fields are currently supported:
 
 =item svcnum - svcnum of the owning FS::svc_broadband, if appropriate
 
+=item auto_addr - flag to automatically assign IP addresses to services
+linked to this router ('Y' or null).
+
 =back
 
 =head1 METHODS
@@ -83,6 +86,7 @@ sub check {
   my $error =
     $self->ut_numbern('routernum')
     || $self->ut_text('routername')
+    || $self->ut_enum('auto_addr', [ '', 'Y' ])
     || $self->ut_agentnum_acl('agentnum', 'Broadband global configuration')
   ;
   return $error if $error;
@@ -128,6 +132,11 @@ sub delete {
 Returns a list of FS::addr_block objects (address blocks) associated
 with this object.
 
+=item auto_addr_block
+
+Returns a list of address blocks on which auto-assignment of IP addresses
+is enabled.
+
 =cut
 
 sub addr_block {
@@ -135,6 +144,13 @@ sub addr_block {
   return qsearch('addr_block', { routernum => $self->routernum });
 }
 
+sub auto_addr_block {
+  my $self = shift;
+  return () if !$self->auto_addr;
+  return qsearch('addr_block', { routernum => $self->routernum,
+                                 manual_flag => '' });
+}
+
 =item part_svc_router
 
 Returns a list of FS::part_svc_router objects associated with this 
diff --git a/FS/FS/svc_broadband.pm b/FS/FS/svc_broadband.pm
index f5aa2fe..ac463bc 100755
--- a/FS/FS/svc_broadband.pm
+++ b/FS/FS/svc_broadband.pm
@@ -101,15 +101,15 @@ sub table_info {
       'description' => 'Descriptive label for this particular device',
       'speed_down'  => 'Maximum download speed for this service in Kbps.  0 denotes unlimited.',
       'speed_up'    => 'Maximum upload speed for this service in Kbps.  0 denotes unlimited.',
-      'ip_addr'     => 'IP address.  Leave blank for automatic assignment.',
-      'sectornum'   => 'Tower sector',
-      'blocknum'    => { 'label' => 'Address block',
-                         'type'  => 'select',
-                         'select_table' => 'addr_block',
-                         'select_key'   => 'blocknum',
-                         'select_label' => 'cidr',
-                         'disable_inventory' => 1,
-                       },
+      #'ip_addr'     => 'IP address.  Leave blank for automatic assignment.',
+      #'blocknum'    => 
+      #{ 'label' => 'Address block',
+      #                   'type'  => 'select',
+      #                   'select_table' => 'addr_block',
+      #                    'select_key'   => 'blocknum',
+      #                   'select_label' => 'cidr',
+      #                   'disable_inventory' => 1,
+      #                 },
      'plan_id' => 'Service Plan Id',
      'performance_profile' => 'Peformance Profile',
      'authkey'      => 'Authentication key',
@@ -118,6 +118,8 @@ sub table_info {
      'longitude'    => 'Longitude',
      'altitude'     => 'Altitude',
      'vlan_profile' => 'VLAN profile',
+     'sectornum'    => 'Tower/sector',
+     'routernum'    => 'Router/block',
      'usergroup'    => { 
                          label => 'RADIUS groups',
                          type  => 'select-radius_group.html',
@@ -209,13 +211,20 @@ sub search {
 
   #routernum, can be arrayref
   for my $routernum ( $params->{'routernum'} ) {
-    push @from, 'LEFT JOIN addr_block USING ( blocknum )';
+    # this no longer uses addr_block
     if ( ref $routernum and grep { $_ } @$routernum ) {
-      my $where = join(',', map { /^(\d+)$/ ? $1 : () } @$routernum );
-      push @where, "addr_block.routernum IN ($where)" if $where;
+      my $in = join(',', map { /^(\d+)$/ ? $1 : () } @$routernum );
+      my @orwhere;
+      push @orwhere, "svc_broadband.routernum IN ($in)" if $in;
+      push @orwhere, "svc_broadband.routernum IS NULL" 
+        if grep /^none$/, @$routernum;
+      push @where, '( '.join(' OR ', @orwhere).' )';
     }
     elsif ( $routernum =~ /^(\d+)$/ ) {
-      push @where, "addr_block.routernum = $1";
+      push @where, "svc_broadband.routernum = $1";
+    }
+    elsif ( $routernum eq 'none' ) {
+      push @where, "svc_broadband.routernum IS NULL";
     }
   }
 
@@ -327,8 +336,6 @@ Delete this record from the database.
 Replaces the OLD_RECORD with this one in the database.  If there is an error,
 returns the error, otherwise returns false.
 
-=cut
-
 # Standard FS::svc_Common::replace
 
 =item suspend
@@ -365,6 +372,7 @@ sub check {
   my $error =
     $self->ut_numbern('svcnum')
     || $self->ut_numbern('blocknum')
+    || $self->ut_foreign_keyn('routernum', 'router', 'routernum')
     || $self->ut_foreign_keyn('sectornum', 'tower_sector', 'sectornum')
     || $self->ut_textn('description')
     || $self->ut_numbern('speed_up')
@@ -380,8 +388,8 @@ sub check {
   ;
   return $error if $error;
 
-  if($self->speed_up < 0) { return 'speed_up must be positive'; }
-  if($self->speed_down < 0) { return 'speed_down must be positive'; }
+  if(($self->speed_up || 0) < 0) { return 'speed_up must be positive'; }
+  if(($self->speed_down || 0) < 0) { return 'speed_down must be positive'; }
 
   my $cust_svc = $self->svcnum
                  ? qsearchs('cust_svc', { 'svcnum' => $self->svcnum } )
@@ -393,18 +401,27 @@ sub check {
     $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $self->pkgnum } );
     return "Invalid pkgnum" unless $cust_pkg;
   }
-    
-  if ($self->blocknum) {
-    $error = $self->ut_foreign_key('blocknum', 'addr_block', 'blocknum');
-    return $error if $error;
-  }
+  my $agentnum = $cust_pkg->cust_main->agentnum if $cust_pkg;
+
+  if ($self->routernum) {
+    return "Router ".$self->routernum." does not provide this service"
+      unless qsearchs('part_svc_router', { 
+        svcpart => $self->cust_svc->svcpart,
+        routernum => $self->routernum
+    });
+  
+    my $router = $self->router;
+    return "Router ".$self->routernum." does not serve this customer"
+      if $router->agentnum and $router->agentnum != $agentnum;
 
-  if ($cust_pkg && $self->blocknum) {
-    my $addr_agentnum = $self->addr_block->agentnum;
-    if ($addr_agentnum && $addr_agentnum != $cust_pkg->cust_main->agentnum) {
-      return "Address block does not service this customer";
+    if ( $router->auto_addr ) {
+      my $error = $self->assign_ip_addr;
+      return $error if $error;
     }
-  }
+    else {
+      $self->blocknum('');
+    }
+  } # if $self->routernum
 
   if ( $cust_pkg && ! $self->latitude && ! $self->longitude ) {
     my $l = $cust_pkg->cust_location_or_main;
@@ -423,55 +440,60 @@ sub check {
   $self->SUPER::check;
 }
 
-sub _check_ip_addr {
-  my $self = shift;
+=item assign_ip_addr
 
-  if (not($self->ip_addr) or $self->ip_addr eq '0.0.0.0') {
+Assign an address block matching the selected router, and the selected block
+if there is one.
 
-    return '' if $conf->exists('svc_broadband-allow_null_ip_addr'); #&& !$self->blocknum
+=cut
 
-    return "Must supply either address or block"
-      unless $self->blocknum;
-    my $next_addr = $self->addr_block->next_free_addr;
-    if ($next_addr) {
-      $self->ip_addr($next_addr->addr);
-    } else {
-      return "No free addresses in addr_block (blocknum: ".$self->blocknum.")";
-    }
+sub assign_ip_addr {
+  my $self = shift;
+  my @blocks;
+  my $ip_addr;
 
+  if ( $self->blocknum and $self->addr_block->routernum == $self->routernum ) {
+    # simple case: user chose a block, find an address in that block
+    # (this overrides an existing IP address if it's not in the block)
+    @blocks = ($self->addr_block);
+  }
+  elsif ( $self->routernum ) {
+    @blocks = $self->router->auto_addr_block;
+  }
+  else { 
+    return '';
   }
 
-  if (not($self->blocknum)) {
-    return "Must supply either address or block"
-      unless ($self->ip_addr and $self->ip_addr ne '0.0.0.0');
-    my @block = grep { $_->NetAddr->contains($self->NetAddr) }
-                 map { $_->addr_block }
-                 $self->allowed_routers;
-    if (scalar(@block)) {
-      $self->blocknum($block[0]->blocknum);
-    }else{
-      return "Address not with available block.";
+  foreach my $block ( @blocks ) {
+    if ( $self->ip_addr and $block->NetAddr->contains($self->NetAddr) ) {
+      # don't change anything
+      return '';
     }
+    $ip_addr = $block->next_free_addr;
+    last if $ip_addr;
   }
-
-  # This should catch errors in the ip_addr.  If it doesn't,
-  # they'll almost certainly not map into the block anyway.
-  my $self_addr = $self->NetAddr; #netmask is /32
-  return ('Cannot parse address: ' . $self->ip_addr) unless $self_addr;
-
-  my $block_addr = $self->addr_block->NetAddr;
-  unless ($block_addr->contains($self_addr)) {
-    return 'blocknum '.$self->blocknum.' does not contain address '.$self->ip_addr;
+  if ( $ip_addr ) {
+    $self->set(ip_addr => $ip_addr->addr);
+    return '';
   }
-
-  my $router = $self->addr_block->router 
-    or return 'Cannot assign address from unallocated block:'.$self->addr_block->blocknum;
-  if(grep { $_->routernum == $router->routernum} $self->allowed_routers) {
-  } # do nothing
   else {
-    return 'Router '.$router->routernum.' cannot provide svcpart '.$self->svcpart;
+    return 'No IP address available on this router';
   }
+}
 
+sub _check_ip_addr {
+  my $self = shift;
+
+  if (not($self->ip_addr) or $self->ip_addr eq '0.0.0.0') {
+    return '' if $conf->exists('svc_broadband-allow_null_ip_addr'); 
+    return 'IP address required';
+  }
+#  if (my $dup = qsearchs('svc_broadband', {
+#        ip_addr => $self->ip_addr,
+#        svcnum  => {op=>'!=', value => $self->svcnum}
+#      }) ) {
+#    return 'IP address conflicts with svcnum '.$dup->svcnum;
+#  }
   '';
 }
 
@@ -510,6 +532,17 @@ sub addr_block {
   qsearchs('addr_block', { blocknum => $self->blocknum });
 }
 
+=item router
+
+Returns the FS::router record for this service.
+
+=cut
+
+sub router {
+  my $self = shift;
+  qsearchs('router', { routernum => $self->routernum });
+}
+
 =back
 
 =item allowed_routers
@@ -520,7 +553,34 @@ Returns a list of allowed FS::router objects.
 
 sub allowed_routers {
   my $self = shift;
-  map { $_->router } qsearch('part_svc_router', { svcpart => $self->svcpart });
+  map { $_->router } qsearch('part_svc_router', 
+    { svcpart => $self->cust_svc->svcpart });
+}
+
+
+#class method
+sub _upgrade_data {
+  my $class = shift;
+
+  # set routernum to addr_block.routernum
+  foreach my $self (qsearch('svc_broadband', {
+      blocknum => {op => '!=', value => ''},
+      routernum => ''
+    })) {
+    my $addr_block = $self->addr_block;
+    if ( my $routernum = $addr_block->routernum ) {
+      $self->set(routernum => $routernum);
+      my $error = $self->replace;
+      die "error assigning routernum $routernum to service ".$self->svcnum.
+          ":\n$error\n"
+        if $error;
+    }
+    else {
+      warn "svcnum ".$self->svcnum.
+        ": no routernum in address block ".$addr_block->cidr.", skipped\n";
+    }
+  }
+  '';
 }
 
 =head1 BUGS
@@ -530,6 +590,8 @@ The business with sb_field has been 'fixed', in a manner of speaking.
 allowed_routers isn't agent virtualized because part_svc isn't agent
 virtualized
 
+Having both routernum and blocknum as foreign keys is somewhat dubious.
+
 =head1 SEE ALSO
 
 FS::svc_Common, FS::Record, FS::addr_block,
diff --git a/httemplate/browse/router.cgi b/httemplate/browse/router.cgi
index 069ca9b..21047d7 100644
--- a/httemplate/browse/router.cgi
+++ b/httemplate/browse/router.cgi
@@ -9,6 +9,7 @@
                 'count_query'     => "SELECT count(*) from router $count_sql",
                 'header'          => [ 'Router name',
                                        'Address block(s)',
+                                       'IP addressing',
                                        'Action',
                                      ],
                 'fields'          => [ 'routername',
@@ -16,10 +17,12 @@
                                                                shift->addr_block
                                                  );
                                            },
+                                       sub { shift->auto_addr ? 'Automatic' : 'Manual' },
                                        sub { 'Delete' },
                                      ],
                 'links'           => [ [ "${p2}edit/router.cgi?", 'routernum' ],
                                        '',
+                                       '',
                                        [ "${p}misc/delete-router.html?", 'routernum' ],
                                      ],
                 'agent_virt'      => 1,
@@ -52,4 +55,5 @@ my $count_sql = $extra_sql.  ( $extra_sql =~ /WHERE/ ? ' AND' : 'WHERE' ).
     'null_right' => 'Broadband global configuration',
   );
 
+
 </%init>
diff --git a/httemplate/edit/router.cgi b/httemplate/edit/router.cgi
index 70eaa45..6672d5d 100755
--- a/httemplate/edit/router.cgi
+++ b/httemplate/edit/router.cgi
@@ -6,11 +6,14 @@
      'labels'      => { 'routernum'  => 'Router',
                         'routername' => 'Name',
                         'svc_part'   => 'Service',
+                        'agentnum'   => 'Agent',
+                        'auto_addr'  => 'Assign IP addresses automatically',
                       },
      'fields'      => [
                         { 'field'=>'routername', 'type'=>'text', 'size'=>32 },
                         { 'field'=>'agentnum',   'type'=>'select-agent' },
                         { 'field'=>'svcnum',     'type'=>'hidden' },
+                        { 'field'=>'auto_addr','type'=>'checkbox','value'=>'Y'},
                       ],
      'error_callback' => $callback,
      'edit_callback'  => $callback,
diff --git a/httemplate/edit/svc_broadband.cgi b/httemplate/edit/svc_broadband.cgi
index ff57ac0..8fccb1f 100644
--- a/httemplate/edit/svc_broadband.cgi
+++ b/httemplate/edit/svc_broadband.cgi
@@ -100,10 +100,9 @@ END
 ;
 
 my @fields = (
-  qw( description ip_addr speed_down speed_up ),
+  qw( description speed_down speed_up ),
   { field=>'sectornum', type=>'select-tower_sector', },
-  qw( blocknum ),
-  { field=>'block_label', type=>'fixed' },
+  { field=>'routernum', type=>'select-router_block_ip', },
   qw( mac_addr latitude longitude altitude vlan_profile 
       performance_profile authkey plan_id ),
 );
diff --git a/httemplate/elements/select-tiered.html b/httemplate/elements/select-tiered.html
index 35f9e5a..99b2852 100644
--- a/httemplate/elements/select-tiered.html
+++ b/httemplate/elements/select-tiered.html
@@ -35,6 +35,7 @@ contain the following:
   isn't fully tested.
 - after: an HTML string to be inserted after the select element, before 
   the next one.  By default there's nothing between them.
+- onchange: an additional javascript function to be called on change.
 
 For convenience, "curr_value" and "field" can be passed as part of the 
 main argument list, and will be applied to the last tier.
@@ -43,8 +44,13 @@ main argument list, and will be applied to the last tier.
 % $i = 0;
 % foreach my $tier (@$tiers) {
 %   my $onchange;
-%   $onchange="onchange='${pre}select_change(this, $i)'"
+%   $onchange="${pre}select_change(this, $i)"
 %     if $i < scalar(@$tiers) - 1;
+%
+%   $onchange .= ';'.$tier->{onchange}."(this, $i);"
+%     if $tier->{onchange};
+%
+%   $onchange = "onchange='$onchange'" if $onchange;
 <SELECT 
   NAME="<% $tier->{field} %>"
   ID="<% $pre."select_".$i %>"
@@ -54,7 +60,8 @@ main argument list, and will be applied to the last tier.
 %   if ( $i == 0 ) {
 %     my $options = $tiers_by_key->[0]->{''};
 %     foreach ( sort keys %$options ) {
-  <OPTION VALUE="<%$_ |h%>"><% $options->{$_} |h%></OPTION>
+  <OPTION VALUE="<%$_ |h%>" <% $curr_values->[$i] eq $_ ? 'SELECTED' : ''%>>
+  <% $options->{$_} |h%></OPTION>
 %     }
 %   }
 %   $i++;
@@ -178,7 +185,6 @@ while($i >= 1) {
   foreach my $key ( %{ $tier->{by_key} } ) {
     my $options = $tier->{by_key}->{$key};
     if ( exists( $options->{$curr_value} ) ) {
-      warn "tier $i curr_value ($curr_value) found under key $key\n";
       $tiers->[$i-1]->{curr_value} = $key;
       last;
     }
diff --git a/httemplate/elements/tr-select-router_block_ip.html b/httemplate/elements/tr-select-router_block_ip.html
new file mode 100644
index 0000000..e6b7bfe
--- /dev/null
+++ b/httemplate/elements/tr-select-router_block_ip.html
@@ -0,0 +1,94 @@
+<script type="text/javascript">
+var auto_addr_routernum = <% encode_json(\%auto_addr_routernum) %>;
+function hide_if_auto_addr(obj, i) {
+  var routernum = obj.value;
+  var select_blocknum = document.getElementsByName('blocknum')[0];
+  var label_auto_addr = document.getElementById('label_auto_addr');
+  var input_ip_addr = document.getElementById('input_ip_addr');
+  var auto = ( auto_addr_routernum[routernum] == 'Y' );
+  select_blocknum.style.display = auto ? '' : 'none';
+  label_auto_addr.style.display = auto ? '' : 'none';
+  input_ip_addr.style.display = !auto ? '' : 'none';
+}
+</script>
+<& /elements/tr-td-label.html, label => ($opt{'label'} || 'Router') &>
+<td>
+  <& /elements/select-tiered.html, prefix => 'router_', tiers => [
+  {
+    field     => 'routernum',
+    records   => \@routers,
+    name_col  => 'routername',
+    value_col => 'routernum',
+    onchange  => 'hide_if_auto_addr',
+    curr_value=> $opt{'routernum'},
+  },
+  {
+    field     => 'blocknum',
+    table     => 'addr_block',
+    hashref   => (exists($fixed{'blocknum'}) ? 
+                    { blocknum => $fixed{'blocknum'} } : {}
+                 ),
+    name_col  => 'cidr',
+    link_col  => 'routernum',
+    empty_label => '(any)',
+    curr_value  => $opt{'blocknum'},
+  },
+]
+&>
+</td></tr>
+<& /elements/tr-td-label.html, label => 'IP address' &>
+<td>
+% if ( $fixed{'ip_addr'} ) {
+  <input type="hidden" id="input_ip_addr" name="ip_addr" 
+    value="<% $opt{'ip_addr'} |h%>"><% $opt{'ip_addr'} || '' %>
+% }
+% else {
+  <input type="text" id="input_ip_addr" name="ip_addr" 
+    style="display:none" value="<% $opt{'ip_addr'} |h%>">
+% }
+  <span id="label_auto_addr"><% $opt{'ip_addr'} || '' %> 
+  <i>(automatic)</i></span>
+</td> </tr>
+<script type="text/javascript">
+hide_if_auto_addr(document.getElementsByName('routernum')[0],0);
+</script>
+<%init>
+my %opt = @_;
+my @routers;
+
+my $svc_x = $opt{'object'};
+if ( $svc_x ) {
+  $opt{$_} = $svc_x->$_
+    foreach qw(routernum blocknum ip_addr svcpart);
+}
+
+warn Dumper(\%opt);
+
+my $svcpart = $opt{'svcpart'} || '';
+my %fixed; #  which fields are fixed
+$svcpart =~ /^\d*$/ or die "invalid svcpart '$svcpart'";
+if ( $svcpart ) {
+  my $part_svc = FS::part_svc->by_key($svcpart);
+  # Traditionally, columnflag 'F' on IP address means that it MUST 
+  # be auto-assigned (or, if null IP addresses are allowed, that 
+  # it must be null).
+  foreach (qw(routernum blocknum ip_addr)) {
+    my $psc = $part_svc->part_svc_column($_);
+    if ( $psc and $psc->columnflag eq 'F' ) {
+      $fixed{$_} = $psc->columnvalue;
+    }
+  }
+  if ( $fixed{'routernum'} ) {
+    @routers = (FS::router->by_key($fixed{'routernum'}))
+  }
+  else {
+    @routers = map { $_->router } 
+      qsearch('part_svc_router', { svcpart => $svcpart });
+  }
+}
+else {
+  @routers = qsearch('router', {});
+}
+
+my %auto_addr_routernum = map { $_->routernum, $_->auto_addr } @routers;
+</%init>
diff --git a/httemplate/search/report_svc_broadband.html b/httemplate/search/report_svc_broadband.html
index ee4dfce..37f21b7 100755
--- a/httemplate/search/report_svc_broadband.html
+++ b/httemplate/search/report_svc_broadband.html
@@ -26,6 +26,10 @@
                     'multiple'      => 'multiple',
               )
     %>
+    <tr>
+      <td></td>
+      <td><input type="checkbox" name="routernum" value="none" checked> Include services with no router</td>
+    </tr>
 
     <% include( '/elements/tr-selectmultiple-part_pkg.html',
                 %pkg_search,
diff --git a/httemplate/search/svc_broadband.cgi b/httemplate/search/svc_broadband.cgi
index 605b829..ee62e90 100755
--- a/httemplate/search/svc_broadband.cgi
+++ b/httemplate/search/svc_broadband.cgi
@@ -15,8 +15,8 @@
               'fields'      => [ 'svcnum',
                                  'svc',
                                  sub {
-                                   my $blocknum = shift->blocknum or return '';
-                                   $routerbyblock{$blocknum}->routername;
+                                   my $router = shift->router; 
+                                   $router ? $router->routername : '';
                                  },
                                  @tower_fields,
                                  'ip_addr',
diff --git a/httemplate/view/svc_broadband.cgi b/httemplate/view/svc_broadband.cgi
index 2e93d42..05ae632 100644
--- a/httemplate/view/svc_broadband.cgi
+++ b/httemplate/view/svc_broadband.cgi
@@ -27,7 +27,7 @@ $labels{'coordinates'} = 'Latitude/Longitude';
 
 my @fields = (
   'description',
-  { field => 'router', value => \&router },
+  { field => 'routernum', value => \&router },
   'speed_down',
   'speed_up',
   { field => 'ip_addr', value => \&ip_addr },
@@ -48,9 +48,10 @@ push @fields,
 
 sub router {
   my $svc = shift;
-  my $addr_block = $svc->addr_block or return '';
-  my $router = $addr_block->router or return '';
-  $router->routernum . ': ' . $router->routername;
+  my $router = $svc->router or return '';
+  my $block = $svc->addr_block;
+  $block = '; '.$block->cidr if $block;
+  $router->routernum . ': ' . $router->routername . $block
 }
 
 sub ip_addr {

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Schema.pm                                    |    2 +
 FS/FS/Upgrade.pm                                   |    5 +-
 FS/FS/addr_block.pm                                |   39 +++--
 FS/FS/part_export/router.pm                        |    4 +-
 FS/FS/router.pm                                    |   16 ++
 FS/FS/svc_broadband.pm                             |  192 +++++++++++++-------
 httemplate/browse/router.cgi                       |    4 +
 httemplate/edit/router.cgi                         |    3 +
 httemplate/edit/svc_broadband.cgi                  |    5 +-
 httemplate/elements/select-tiered.html             |   12 +-
 httemplate/elements/tr-select-router_block_ip.html |   94 ++++++++++
 httemplate/search/report_svc_broadband.html        |    4 +
 httemplate/search/svc_broadband.cgi                |    4 +-
 httemplate/view/svc_broadband.cgi                  |    9 +-
 14 files changed, 297 insertions(+), 96 deletions(-)
 create mode 100644 httemplate/elements/tr-select-router_block_ip.html




More information about the freeside-commits mailing list