[freeside-commits] branch master updated. 00de593a7e5b5b50aeec62c0ddb90db7bcd62f55

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


The branch, master has been updated
       via  00de593a7e5b5b50aeec62c0ddb90db7bcd62f55 (commit)
      from  36ad5e538cb56de33c779e34baf9abdf63c4312e (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 00de593a7e5b5b50aeec62c0ddb90db7bcd62f55
Author: Mark Wells <mark at freeside.biz>
Date:   Wed Sep 4 12:53:30 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 340b678..87a14aa 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -2282,6 +2282,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 ed677d7..3270f04 100644
--- a/httemplate/edit/elements/edit.html
+++ b/httemplate/edit/elements/edit.html
@@ -322,7 +322,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 574fb51..2c694a8 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' ) { 
@@ -525,4 +554,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