[freeside-commits] branch FREESIDE_3_BRANCH updated. f1a024ad18faf7246176f7679f0443e0377785b6

Mark Wells mark at 420.am
Wed Sep 4 13:06:13 PDT 2013


The branch, FREESIDE_3_BRANCH has been updated
       via  f1a024ad18faf7246176f7679f0443e0377785b6 (commit)
      from  81ffe1d0f3f0201c9392bb5555134d65b0ce33c6 (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 f1a024ad18faf7246176f7679f0443e0377785b6
Author: Mark Wells <mark at freeside.biz>
Date:   Wed Sep 4 12:54:57 2013 -0700

    assign entire address blocks to services for RADIUS Framed-Route option, #20742

diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index a6689c2..e5c8db3 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -2187,6 +2187,7 @@ sub tables_hashref {
         'selfservice_access', 'varchar', 'NULL',   $char_d, '', '',
         'classnum',               'int', 'NULL',        '', '', '',
         'restrict_edit_password','char', 'NULL',         1, '', '',
+        'has_router',            'char', 'NULL',         1, '', '',
 ],
       'primary_key' => 'svcpart',
       'unique' => [],
diff --git a/FS/FS/part_export/broadband_sqlradius.pm b/FS/FS/part_export/broadband_sqlradius.pm
index b5d1a80..522c637 100644
--- a/FS/FS/part_export/broadband_sqlradius.pm
+++ b/FS/FS/part_export/broadband_sqlradius.pm
@@ -6,6 +6,7 @@ use Tie::IxHash;
 use FS::Conf;
 use FS::Record qw( dbh str2time_sql ); #qsearch qsearchs );
 use FS::part_export::sqlradius qw(sqlradius_connect);
+use NEXT;
 
 FS::UID->install_callback(sub { $conf = new FS::Conf });
 
@@ -88,7 +89,9 @@ sub export_username {
 
 sub radius_reply {
   my($self, $svc_broadband) = (shift, shift);
-  my %reply;
+  # start with attributes the service wants
+  my %reply = $self->NEXT::radius_reply($svc_broadband);
+  # add export-specific stuff
   if (  length($self->option('ip_addr_as',1)) 
     and length($svc_broadband->ip_addr) ) {
     $reply{$self->option('ip_addr_as')} = $svc_broadband->ip_addr;
@@ -98,8 +101,9 @@ sub radius_reply {
 
 sub radius_check {
   my($self, $svc_broadband) = (shift, shift);
+
+  my %check = $self->SUPER::radius_check($svc_broadband);
   my $password_attrib = $conf->config('radius-password') || 'Password';
-  my %check;
   if ( $self->option('mac_as_password') ) {
     $check{$password_attrib} = $self->export_username($svc_broadband);
   }
diff --git a/FS/FS/part_export/sqlradius.pm b/FS/FS/part_export/sqlradius.pm
index 833dd9a..c8a963d 100644
--- a/FS/FS/part_export/sqlradius.pm
+++ b/FS/FS/part_export/sqlradius.pm
@@ -9,6 +9,7 @@ use FS::part_export;
 use FS::svc_acct;
 use FS::export_svc;
 use Carp qw( cluck );
+use NEXT;
 
 @ISA = qw(FS::part_export);
 @EXPORT_OK = qw( sqlradius_connect );
@@ -133,12 +134,14 @@ sub export_username { # override for other svcdb
 
 sub radius_reply { #override for other svcdb
   my($self, $svc_acct) = (shift, shift);
-  $svc_acct->radius_reply;
+  my %every = $svc_acct->EVERY::radius_reply;
+  map { @$_ } values %every;
 }
 
 sub radius_check { #override for other svcdb
   my($self, $svc_acct) = (shift, shift);
-  $svc_acct->radius_check;
+  my %every = $svc_acct->EVERY::radius_check;
+  map { @$_ } values %every;
 }
 
 sub _export_insert {
@@ -194,8 +197,8 @@ sub _export_replace {
 
   foreach my $table (qw(reply check)) {
     my $method = "radius_$table";
-    my %new = $new->$method();
-    my %old = $old->$method();
+    my %new = $self->$method($new);
+    my %old = $self->$method($old);
     if ( grep { !exists $old{$_} #new attributes
                 || $new{$_} ne $old{$_} #changed
               } keys %new
diff --git a/FS/FS/part_svc.pm b/FS/FS/part_svc.pm
index da794dd..a116819 100644
--- a/FS/FS/part_svc.pm
+++ b/FS/FS/part_svc.pm
@@ -65,6 +65,10 @@ empty for full access, "readonly" for read-only, "hidden" to hide it entirely
 right to change the password field, rather than just "Edit password".  Only
 relevant to svc_acct for now.
 
+=item has_router - Allow the service to have an L<FS::router> connected 
+through it.  Probably only relevant to svc_broadband, svc_acct, and svc_dsl
+for now.
+
 =back
 
 =head1 METHODS
@@ -394,11 +398,12 @@ sub check {
     $self->ut_numbern('svcpart')
     || $self->ut_text('svc')
     || $self->ut_alpha('svcdb')
-    || $self->ut_enum('disabled', [ '', 'Y' ] )
-    || $self->ut_enum('preserve', [ '', 'Y' ] )
+    || $self->ut_flag('disabled')
+    || $self->ut_flag('preserve')
     || $self->ut_enum('selfservice_access', [ '', 'hidden', 'readonly' ] )
     || $self->ut_foreign_keyn('classnum', 'part_svc_class', 'classnum' )
-    || $self->ut_enum('restrict_edit_password', [ '', 'Y' ] )
+    || $self->ut_flag('restrict_edit_password')
+    || $self->ut_flag('has_router')
 ;
   return $error if $error;
 
diff --git a/FS/FS/router.pm b/FS/FS/router.pm
index 6fa44b4..937dc1f 100755
--- a/FS/FS/router.pm
+++ b/FS/FS/router.pm
@@ -63,16 +63,87 @@ sub table { 'router'; }
 Adds this record to the database.  If there is an error, returns the error,
 otherwise returns false.
 
-=item delete
+If the pseudo-field 'blocknum' is set to an L<FS::addr_block> number, then 
+that address block will be assigned to this router.  Currently only one
+block can be assigned this way.
+
+=cut
+
+sub insert {
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
 
-Deletes this record from the database.  If there is an error, returns the
-error, otherwise returns false.
+  my $self = shift;
+  my $error = $self->SUPER::insert(@_);
+  return $error if $error;
+  if ( $self->blocknum ) {
+    my $block = FS::addr_block->by_key($self->blocknum);
+    if ($block) {
+      if ($block->routernum) {
+        $error = "block ".$block->cidr." is already assigned to a router";
+      } else {
+        $block->set('routernum', $self->routernum);
+        $block->set('manual_flag', 'Y');
+        $error = $block->replace;
+      }
+    } else {
+      $error = "blocknum ".$self->blocknum." not found";
+    }
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+  $dbh->commit if $oldAutoCommit;
+  return $error;
+}
 
 =item replace OLD_RECORD
 
 Replaces OLD_RECORD with this one in the database.  If there is an error,
 returns the error, otherwise returns false.
 
+=cut
+
+sub replace {
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $self = shift;
+  my $old = shift || $self->replace_old;
+  my $error = $self->SUPER::replace($old, @_);
+  return $error if $error;
+
+  if ( defined($self->blocknum) ) {
+    #warn "FS::router::replace: blocknum = ".$self->blocknum."\n";
+    # then release any blocks we're already holding
+    foreach my $block ($self->addr_block) {
+      $block->set('routernum', 0);
+      $block->set('manual_flag', '');
+      $error ||= $block->replace;
+    }
+    if ( !$error and $self->blocknum > 0 ) {
+      # and, if the new blocknum is a real blocknum, assign it
+      my $block = FS::addr_block->by_key($self->blocknum);
+      if ( $block ) {
+        $block->set('routernum', $self->routernum);
+        $block->set('manual_flag', '');
+        $error ||= $block->replace;
+      } else {
+        $error = "blocknum ".$self->blocknum." not found";
+      }
+    }
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+  $dbh->commit if $oldAutoCommit;
+  return $error;
+}
+
 =item check
 
 Checks all fields to make sure this is a valid record.  If there is an error,
@@ -89,6 +160,7 @@ sub check {
     || $self->ut_text('routername')
     || $self->ut_enum('manual_addr', [ '', 'Y' ])
     || $self->ut_agentnum_acl('agentnum', 'Broadband global configuration')
+    || $self->ut_foreign_keyn('svcnum', 'cust_svc', 'svcnum')
   ;
   return $error if $error;
 
@@ -97,28 +169,25 @@ sub check {
 
 =item delete
 
-Deletes this router if and only if no address blocks (see L<FS::addr_block>)
-are currently allocated to it.
+Deallocate all address blocks from this router and delete it.
 
 =cut
 
 sub delete {
     my $self = shift;
 
-    return 'Router has address blocks allocated to it' if $self->addr_block;
-    
-    local $SIG{HUP} = 'IGNORE';
-    local $SIG{INT} = 'IGNORE';
-    local $SIG{QUIT} = 'IGNORE';
-    local $SIG{TERM} = 'IGNORE';
-    local $SIG{TSTP} = 'IGNORE';
-    local $SIG{PIPE} = 'IGNORE';
-
     my $oldAutoCommit = $FS::UID::AutoCommit;
     local $FS::UID::AutoCommit = 0;
     my $dbh = dbh;
-    
-    my $error = $self->SUPER::delete;
+ 
+    my $error;
+    foreach my $block ($self->addr_block) {
+      $block->set('manual_flag', '');
+      $block->set('routernum', 0);
+      $error ||= $block->replace;
+    }
+
+    $error ||= $self->SUPER::delete;
     if ( $error ) {
        $dbh->rollback if $oldAutoCommit;
        return $error;
@@ -187,6 +256,19 @@ sub agent {
   qsearchs('agent', { 'agentnum' => shift->agentnum });
 }
 
+=item cust_svc
+
+Returns the cust_svc associated with this router, if any.  This should be
+the service that I<provides connectivity to the router>, not any service 
+connected I<through> the router.
+
+=cut
+
+sub cust_svc {
+  my $svcnum = shift->svcnum or return undef;
+  FS::cust_svc->by_key($svcnum);
+}
+
 =back
 
 =head1 SEE ALSO
diff --git a/FS/FS/svc_Common.pm b/FS/FS/svc_Common.pm
index 0aea455..3993d3d 100644
--- a/FS/FS/svc_Common.pm
+++ b/FS/FS/svc_Common.pm
@@ -367,6 +367,7 @@ sub delete {
 	      || $self->SUPER::delete
               || $self->export('delete', @$export_args)
 	      || $self->return_inventory
+              || $self->release_router
 	      || $self->predelete_hook
 	      || $self->cust_svc->delete
   ;
@@ -989,6 +990,24 @@ sub inventory_item {
   });
 }
 
+=item release_router 
+
+Delete any routers associated with this service.  This will release their
+address blocks, also.
+
+=cut
+
+sub release_router {
+  my $self = shift;
+  my @routers = qsearch('router', { svcnum => $self->svcnum });
+  foreach (@routers) {
+    my $error = $_->delete;
+    return "$error (removing router '".$_->routername."')" if $error;
+  }
+  '';
+}
+
+
 =item cust_svc
 
 Returns the cust_svc record associated with this svc_ record, as a FS::cust_svc
diff --git a/FS/FS/svc_IP_Mixin.pm b/FS/FS/svc_IP_Mixin.pm
index 7eda7e0..ff7c2f5 100644
--- a/FS/FS/svc_IP_Mixin.pm
+++ b/FS/FS/svc_IP_Mixin.pm
@@ -3,6 +3,7 @@ package FS::svc_IP_Mixin;
 use strict;
 use base 'FS::IP_Mixin';
 use FS::Record qw(qsearchs qsearch);
+use NEXT;
 
 =item addr_block
 
@@ -120,4 +121,93 @@ sub _is_used {
   }
 }
 
+=item attached_router
+
+Returns the L<FS::router> attached via this service (as opposed to the one
+this service is connected through), that is, a router whose "svcnum" field
+equals this service's primary key.
+
+If the 'router_routernum' pseudo-field is set, returns that router instead.
+
+=cut
+
+sub attached_router {
+  my $self = shift;
+  if ( length($self->get('router_routernum') )) {
+    return FS::router->by_key($self->router_routernum);
+  } else {
+    qsearchs('router', { 'svcnum' => $self->svcnum });
+  }
+}
+
+=item attached_block
+
+Returns the address block (L<FS::addr_block>) assigned to the attached_router,
+if there is one.
+
+If the 'router_blocknum' pseudo-field is set, returns that block instead.
+
+=cut
+
+sub attached_block {
+  my $self = shift;
+  if ( length($self->get('router_blocknum')) ) {
+    return FS::addr_block->by_key($self->router_blocknum);
+  } else {
+    my $router = $self->attached_router or return '';
+    my ($block) = $router->addr_block;
+    return $block || '';
+  }
+}
+
+=item radius_check
+
+Returns nothing.
+
+=cut
+
+sub radius_check { }
+
+=item radius_reply
+
+Returns RADIUS reply items that are relevant across all exports and 
+necessary for the IP address configuration of the service.  Currently, that
+means "Framed-Route" if there's an attached router.
+
+=cut
+
+sub radius_reply {
+  my $self = shift;
+  my %reply;
+  my ($block) = $self->attached_block;
+  if ( $block ) {
+    # block routed over dynamic IP: "192.168.100.0/29 0.0.0.0 1"
+    # or
+    # block routed over fixed IP: "192.168.100.0/29 192.168.100.1 1"
+    # (the "1" at the end is the route metric)
+    $reply{'Framed-Route'} =
+    $block->cidr . ' ' .
+    ($self->ip_addr || '0.0.0.0') . ' 1';
+  }
+  %reply;
+}
+
+sub replace_check {
+  my ($new, $old) = @_;
+  # this modifies $old, not $new, which is a slight abuse of replace_check,
+  # but there's no way to ensure that replace_old gets called...
+  #
+  # ensure that router_routernum and router_blocknum are set to their
+  # current values, so that exports remember the service's attached router 
+  # and block even after they've been replaced
+  my $router = $old->attached_router;
+  my $block = $old->attached_block;
+  $old->set('router_routernum', $router ? $router->routernum : 0);
+  $old->set('router_blocknum', $block ? $block->blocknum : 0);
+  my $err_or_ref = $new->NEXT::replace_check($old) || '';
+  # because NEXT::replace_check($old) ends up trying to AUTOLOAD replace_check
+  # which is dumb, but easily worked around
+  ref($err_or_ref) ? '' : $err_or_ref;
+}
+
 1;
diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html
index 8ed8201..d01fe72 100644
--- a/httemplate/edit/elements/edit.html
+++ b/httemplate/edit/elements/edit.html
@@ -321,7 +321,7 @@ Example:
 %   $include_common{$_} = $f->{$_} foreach grep exists($f->{$_}),
 %     qw( js_only html_only select_only layers_only cell_style ),#selectlayers,?
 %     qw( empty_label ),                                   # select-*
-%     qw( value_col compare_sub ),                         # select-table
+%     qw( value_col compare_sub order_by ),                # select-table
 %     qw( table name_col ),                           #(select,checkboxes)-table
 %     qw( target_table link_table ),                       #checkboxes-table
 %     qw( hashref agent_virt agent_null agent_null_right ),#*-table
diff --git a/httemplate/edit/elements/part_svc_column.html b/httemplate/edit/elements/part_svc_column.html
index 1c5b453..aa3c647 100644
--- a/httemplate/edit/elements/part_svc_column.html
+++ b/httemplate/edit/elements/part_svc_column.html
@@ -248,6 +248,19 @@ that field.
     </TD>
   </TR>
 % }
+% # special case: services with attached routers (false laziness...)
+% if ( $svcdb eq 'svc_acct' or $svcdb eq 'svc_broadband' or $svcdb eq 'svc_dsl' ) {
+%   push @fields, 'has_router';
+  <TR>
+    <TD COLSPAN=3 ALIGN="right">
+      <% emt('This service has an attached router') %>
+    </TD>
+    <TD>
+      <INPUT TYPE="checkbox" NAME="has_router" VALUE="Y" \
+      <% $part_svc->has_router ? 'CHECKED' : '' %>>
+    </TD>
+  </TR>
+% }
 </TABLE>
 <& /elements/progress-init.html,
   $svcdb, #form name
diff --git a/httemplate/edit/elements/svc_Common.html b/httemplate/edit/elements/svc_Common.html
index d46d1cb..321c685 100644
--- a/httemplate/edit/elements/svc_Common.html
+++ b/httemplate/edit/elements/svc_Common.html
@@ -21,6 +21,7 @@
                                       : ''; #?
                      &{ $cb }( $cgi,$svc_x, $part_svc,$cust_pkg, $fields,$opt);
                    }
+
                  },
 
                  'edit_callback' => sub {
@@ -43,6 +44,27 @@
                                       : ''; #?
                      &{ $cb }( $cgi,$svc_x, $part_svc,$cust_pkg, $fields,$opt);
                    }
+
+                   if ( $part_svc->has_router ) {
+                     my $router = qsearchs('router', {svcnum => $svc_x->svcnum});
+                     if ( $router ) {
+                       $svc_x->set("router_$_", $router->get($_))
+                         foreach ('routername', 'routernum');
+                       my ($block) = $router->addr_block; # one-to-one for now
+                       if ( $block ) {
+                         $svc_x->set('router_blocknum', $block->blocknum);
+                         # silly, but necessary...make the currently 
+                         # assigned block appear on the list
+                         my ($field) = grep {ref($_) and 
+                                             $_->{field} eq 'router_blocknum'}
+                                         @$fields;
+                         $field->{extra_sql} = 
+                           ' OR routernum = '.$router->routernum;
+                         $field->{curr_value} = $block->blocknum;
+                       }
+                     }
+                   }
+
                  },
 
                  'new_hashref_callback' => sub {
@@ -72,7 +94,6 @@
                    }
 
                    $svc_x->set_default_and_fixed;
-
                  },
 
                  'field_callback' => sub {
@@ -125,20 +146,21 @@
                  },
 
                  'html_init' => sub {
+                   my $html;
                    my $cust_main;
                    if ( $pkgnum ) {
                      my $cust_pkg = qsearchs('cust_pkg', {'pkgnum' => $pkgnum});
                      $cust_main = $cust_pkg->cust_main if $cust_pkg;
-                   }
-                   $cust_main
-                     ? include( '/elements/small_custview.html',
+                     if ( $cust_main ) {
+                        $html = include( '/elements/small_custview.html',
                                 $cust_main,
                                 '',
                                 1,
                                 popurl(2). "view/cust_main.cgi"
-                              ). '<BR>'
-                     : '';
-
+                              ). '<BR>';
+                     }
+                   }
+                   $html;
                  },
 
                  'html_table_bottom' => sub {
@@ -200,6 +222,28 @@ sub label_fixup {
     $labels->{$field} = $col->columnlabel if $col->columnlabel !~ /^\s*$/;
   }
 
+  if ( $part_svc->has_router ) {
+    # these will be set up as pseudo-fields in the new_ and edit_ callbacks
+    push @{ $opt->{'fields'} }, (
+      { field => 'router_routernum',   type => 'hidden' },
+      { field => 'router_routername',  type => 'text', size => 32 },
+      # router address block selection
+      # (one-to-one for now)
+      { field => 'router_blocknum',
+        type  => 'select-table',
+        table       => 'addr_block',
+        hashref     => { 'routernum' => '0' },
+        agent_virt  => 1,
+        agent_null  => 1,
+        name_col    => 'cidr',
+        order_by    => 'ORDER BY ip_gateway, ip_netmask',
+        empty_label => '(none)',
+        disable_empty => 0,
+      },
+    );
+    $labels->{router_routername}  = 'Attached router name';
+    $labels->{router_blocknum}    = 'Attached address block';
+  }
 }
 
 </%once>
diff --git a/httemplate/edit/process/elements/svc_Common.html b/httemplate/edit/process/elements/svc_Common.html
index 06f4c00..e1b7cbe 100644
--- a/httemplate/edit/process/elements/svc_Common.html
+++ b/httemplate/edit/process/elements/svc_Common.html
@@ -1,6 +1,7 @@
 <% include( 'process.html',
                  'edit_ext' => 'cgi',
                  'redirect' => popurl(3)."view/$table.cgi?",
+                 'args_callback' => $args_callback,
                  %opt,
            )
 %>
@@ -16,4 +17,22 @@ foreach (fields($table)) {
   }
 }
 
+my $args_callback = sub {
+  my ($cgi, $svc) = @_;
+  my $part_svc = FS::part_svc->by_key($cgi->param('svcpart'))
+    or die "svcpart required";
+  if ( $part_svc->has_router ) {
+    my $router = FS::router->new({
+      map { $_ => $cgi->param("router_$_") }
+      qw( routernum routername blocknum )
+    });
+   if (length($router->routername) == 0) {
+      #sensible default
+      $router->set('routername', $svc->label);
+    }
+    return (child_objects => [ $router ]);
+  }
+  ();
+};
+
 </%init>
diff --git a/httemplate/edit/process/svc_acct.cgi b/httemplate/edit/process/svc_acct.cgi
index d4bcd35..ca614cb 100755
--- a/httemplate/edit/process/svc_acct.cgi
+++ b/httemplate/edit/process/svc_acct.cgi
@@ -88,7 +88,7 @@ if ( ! $error ) {
 
   my $export_info = FS::part_export::export_info();
 
-  my @svc_export_machine =
+  my @child_objects =
     map FS::svc_export_machine->new({
           'svcnum'     => $svcnum,
           'exportnum'  => $_->exportnum,
@@ -97,6 +97,19 @@ if ( ! $error ) {
       grep { $_->machine eq '_SVC_MACHINE' }
         $part_svc->part_export;
 
+  if ( $part_svc->has_router ) {
+    my $router = FS::router->new({
+      map { $_ => $cgi->param("router_$_") }
+      qw( routernum routername blocknum )
+    });
+    if (length($router->routername == 0)) {
+      #sensible default
+      $router->set('routername', $new->label);
+    }
+    push @child_objects, $router;
+  }
+
+
   if ( $svcnum ) {
     foreach ( grep { $old->$_ != $new->$_ }
                    qw( seconds upbytes downbytes totalbytes )
@@ -110,9 +123,9 @@ if ( ! $error ) {
       $error ||= $new->set_usage(\%hash);  #unoverlimit and trigger radius changes
       last;                                #once is enough
     }
-    $error ||= $new->replace($old, 'child_objects'=>\@svc_export_machine);
+    $error ||= $new->replace($old, 'child_objects'=>\@child_objects);
   } else {
-    $error ||= $new->insert('child_objects'=>\@svc_export_machine);
+    $error ||= $new->insert('child_objects'=>\@child_objects);
     $svcnum = $new->svcnum;
   }
 }
diff --git a/httemplate/edit/svc_acct.cgi b/httemplate/edit/svc_acct.cgi
index 627791b..90f4823 100755
--- a/httemplate/edit/svc_acct.cgi
+++ b/httemplate/edit/svc_acct.cgi
@@ -345,6 +345,35 @@
 % } 
 
 </TR>
+
+% if ( $part_svc->has_router ) {
+<& /elements/hidden.html,
+    field => 'router_routernum',
+    curr_value => $svc_acct->router_routernum
+&>
+<& /elements/tr-input-text.html,
+    label => 'Attached router name',
+    field => 'router_routername',
+    size  => 32,
+    curr_value => $svc_acct->router_routername
+&>
+<& /elements/tr-select-table.html,
+    label         => 'Attached address block',
+    field         => 'router_blocknum',
+    table         => 'addr_block',
+    hashref       => { 'routernum' => '0' },
+    extra_sql     => ($svc_acct->router_routernum ?
+                        ' OR routernum = '.$svc_acct->router_routernum : ''),
+    agent_virt    => 1,
+    agent_null    => 1,
+    name_col      => 'cidr',
+    order_by      => 'ORDER BY ip_gateway, ip_netmask',
+    empty_label   => '(none)',
+    disable_empty => 0,
+    curr_value    => $svc_acct->router_blocknum
+&>
+% }
+
 % foreach my $field ($svc_acct->virtual_fields) { 
 % # If the flag is X, it won't even show up in $svc_acct->virtual_fields. 
 % if ( $part_svc->part_svc_column($field)->columnflag ne 'F' ) { 
@@ -527,4 +556,21 @@ if ( $export_google ) {
   } #if $error
 }
 
+if ( $part_svc->has_router ) { # duplicates the one in elements/svc_Common
+  if ( $svcnum ) {
+    my $router = qsearchs('router', {svcnum => $svc_acct->svcnum});
+    if ( $router ) {
+      $svc_acct->set("router_$_", $router->get($_))
+        foreach ('routername', 'routernum');
+      my ($block) = $router->addr_block;
+      $svc_acct->set('router_blocknum', $block->blocknum) if ( $block );
+    }
+  }
+  foreach (qw(router_routername router_routernum router_blocknum)) {
+    if ( $cgi->param($_) =~ /^(\w+)$/ ) {
+      $svc_acct->set($_, $1);
+    }
+  }
+}
+
 </%init>
diff --git a/httemplate/view/elements/svc_Common.html b/httemplate/view/elements/svc_Common.html
index 0248434..bc1cd45 100644
--- a/httemplate/view/elements/svc_Common.html
+++ b/httemplate/view/elements/svc_Common.html
@@ -214,6 +214,20 @@ if ($pkgnum) {
   $custnum = '';
 }
 
+# attached routers
+if ( my $router = qsearchs('router', { svcnum => $svc_x->svcnum }) ) {
+  push @$fields, qw(router_routername router_block);
+  $labels->{'router_routername'} = 'Attached router';
+  $labels->{'router_block'} = 'Attached address block';
+  $svc_x->set('router_routername', $router->routername);
+  my $block = qsearchs('addr_block', { routernum => $router->routernum });
+  if ( $block ) {
+    $svc_x->set('router_block', $block->cidr);
+  } else {
+    $svc_x->set('router_block', '<i>(none)</i>');
+  }
+}
+
 &{ $opt{'svc_callback'} }( $cgi, $svc_x, $part_svc, $cust_pkg, $fields, \%opt ) 
     if $opt{'svc_callback'};
 </%init>
diff --git a/httemplate/view/svc_acct/basics.html b/httemplate/view/svc_acct/basics.html
index 04e7bcf..441c20a 100644
--- a/httemplate/view/svc_acct/basics.html
+++ b/httemplate/view/svc_acct/basics.html
@@ -152,6 +152,8 @@ sub slipip {
 <& /view/elements/tr.html, label=>mt('RADIUS groups'),
     value=>join('<BR>', $svc_acct->radius_groups('long_description')) &>
 
+<& router.html, 'svc_acct' => $svc_acct &>
+
 %# Can this be abstracted further?  Maybe a library function like
 %# widget('HTML', 'view', $svc_acct) ?  It would definitely make UI 
 %# style management easier.

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

Summary of changes:
 FS/FS/Schema.pm                                  |    1 +
 FS/FS/part_export/broadband_sqlradius.pm         |    8 +-
 FS/FS/part_export/sqlradius.pm                   |   11 ++-
 FS/FS/part_svc.pm                                |   11 ++-
 FS/FS/router.pm                                  |  114 +++++++++++++++++++---
 FS/FS/svc_Common.pm                              |   19 ++++
 FS/FS/svc_IP_Mixin.pm                            |   90 +++++++++++++++++
 httemplate/edit/elements/edit.html               |    2 +-
 httemplate/edit/elements/part_svc_column.html    |   13 +++
 httemplate/edit/elements/svc_Common.html         |   58 ++++++++++--
 httemplate/edit/process/elements/svc_Common.html |   19 ++++
 httemplate/edit/process/svc_acct.cgi             |   19 +++-
 httemplate/edit/svc_acct.cgi                     |   46 +++++++++
 httemplate/view/elements/svc_Common.html         |   14 +++
 httemplate/view/svc_acct/basics.html             |    2 +
 15 files changed, 391 insertions(+), 36 deletions(-)




More information about the freeside-commits mailing list