summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wells <mark@freeside.biz>2013-09-04 12:53:30 -0700
committerMark Wells <mark@freeside.biz>2013-09-04 12:53:38 -0700
commit00de593a7e5b5b50aeec62c0ddb90db7bcd62f55 (patch)
treea600ff4184a41d22362c6b8cdfef7e1e47688b7d
parent36ad5e538cb56de33c779e34baf9abdf63c4312e (diff)
assign entire address blocks to services for RADIUS Framed-Route option, #20742
-rw-r--r--FS/FS/Schema.pm1
-rw-r--r--FS/FS/part_export/broadband_sqlradius.pm8
-rw-r--r--FS/FS/part_export/sqlradius.pm11
-rw-r--r--FS/FS/part_svc.pm11
-rwxr-xr-xFS/FS/router.pm114
-rw-r--r--FS/FS/svc_Common.pm19
-rw-r--r--FS/FS/svc_IP_Mixin.pm90
-rw-r--r--httemplate/edit/elements/edit.html2
-rw-r--r--httemplate/edit/elements/part_svc_column.html13
-rw-r--r--httemplate/edit/elements/svc_Common.html58
-rw-r--r--httemplate/edit/process/elements/svc_Common.html19
-rwxr-xr-xhttemplate/edit/process/svc_acct.cgi19
-rwxr-xr-xhttemplate/edit/svc_acct.cgi46
-rw-r--r--httemplate/view/elements/svc_Common.html14
-rw-r--r--httemplate/view/svc_acct/basics.html2
15 files changed, 391 insertions, 36 deletions
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.