summaryrefslogtreecommitdiff
path: root/FS
diff options
context:
space:
mode:
authorkhoff <khoff>2002-09-09 23:05:30 +0000
committerkhoff <khoff>2002-09-09 23:05:30 +0000
commit44398c83f25bf4e43838df9f39331c29fdeff19d (patch)
tree963837373a3b621ee2140adad0eb0b44e12c75e6 /FS
parent91292eadb6254740a9b72e5dc95f575593f6a35d (diff)
svc_broadband merge
Diffstat (limited to 'FS')
-rw-r--r--FS/FS/ac.pm148
-rwxr-xr-xFS/FS/ac_block.pm148
-rwxr-xr-xFS/FS/ac_field.pm138
-rwxr-xr-xFS/FS/ac_type.pm128
-rw-r--r--FS/FS/cust_svc.pm4
-rwxr-xr-xFS/FS/part_ac_field.pm102
-rw-r--r--FS/FS/part_export.pm3
-rwxr-xr-xFS/FS/svc_broadband.pm295
8 files changed, 965 insertions, 1 deletions
diff --git a/FS/FS/ac.pm b/FS/FS/ac.pm
new file mode 100644
index 0000000..5a2b360
--- /dev/null
+++ b/FS/FS/ac.pm
@@ -0,0 +1,148 @@
+package FS::ac;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs qsearch );
+use FS::ac_type;
+use FS::ac_block;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::ac - Object methods for ac records
+
+=head1 SYNOPSIS
+
+ use FS::ac;
+
+ $record = new FS::ac \%hash;
+ $record = new FS::ac { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::ac record describes a broadband Access Concentrator, such as a DSLAM
+or a wireless access point. FS::ac inherits from FS::Record. The following
+fields are currently supported:
+
+narf
+
+=over 4
+
+=item acnum - primary key
+
+=item actypenum - AC type, see L<FS::ac_type>
+
+=item acname - descriptive name for the AC
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new record. To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'ac'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('acnum')
+ || $self->ut_number('actypenum')
+ || $self->ut_text('acname');
+ return $error if $error;
+
+ return "Unknown actypenum"
+ unless $self->ac_type;
+ '';
+}
+
+=item ac_type
+
+Returns the L<FS::ac_type> object corresponding to this object.
+
+=cut
+
+sub ac_type {
+ my $self = shift;
+ return qsearchs('ac_type', { actypenum => $self->actypenum });
+}
+
+=item ac_block
+
+Returns a list of L<FS::ac_block> objects (address blocks) associated
+with this object.
+
+=cut
+
+sub ac_block {
+ my $self = shift;
+ return qsearch('ac_block', { acnum => $self->acnum });
+}
+
+=item ac_field
+
+Returns a hash of L<FS::ac_field> objects assigned to this object.
+
+=cut
+
+sub ac_field {
+ my $self = shift;
+
+ return qsearch('ac_field', { acnum => $self->acnum });
+}
+
+=back
+
+=head1 VERSION
+
+$Id:
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::svc_broadband>, L<FS::ac>, L<FS::ac_block>, L<FS::ac_field>, schema.html
+from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/ac_block.pm b/FS/FS/ac_block.pm
new file mode 100755
index 0000000..09de6a4
--- /dev/null
+++ b/FS/FS/ac_block.pm
@@ -0,0 +1,148 @@
+package FS::ac_block;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs qsearch );
+use FS::ac_type;
+use FS::ac;
+use FS::svc_broadband;
+use NetAddr::IP;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::ac - Object methods for ac records
+
+=head1 SYNOPSIS
+
+ use FS::ac_block;
+
+ $record = new FS::ac_block \%hash;
+ $record = new FS::ac_block { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::ac_block record describes an address block assigned for broadband
+access. FS::ac_block inherits from FS::Record. The following fields are
+currently supported:
+
+=over 4
+
+=item acnum - the access concentrator (see L<FS::ac_type>) to which this
+block is assigned.
+
+=item ip_gateway - the gateway address used by customers within this block.
+This functions as the primary key.
+
+=item ip_netmask - the netmask of the block, expressed as an integer.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new record. To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'ac_block'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_number('acnum')
+ || $self->ut_ip('ip_gateway')
+ || $self->ut_number('ip_netmask')
+ ;
+ return $error if $error;
+
+ return "Unknown acnum"
+ unless $self->ac;
+
+ my $self_addr = new NetAddr::IP ($self->ip_gateway, $self->ip_netmask);
+ return "Cannot parse address: ". $self->ip_gateway . '/' . $self->ip_netmask
+ unless $self_addr;
+
+ my @block = grep {
+ my $block_addr = new NetAddr::IP ($_->ip_gateway, $_->ip_netmask);
+ if($block_addr->contains($self_addr)
+ or $self_addr->contains($block_addr)) { $_; };
+ } qsearch( 'ac_block', {});
+
+ foreach(@block) {
+ return "Block intersects existing block ".$_->ip_gateway."/".$_->ip_netmask;
+ }
+
+ '';
+}
+
+
+=item ac
+
+Returns the L<FS::ac> object corresponding to this object.
+
+=cut
+
+sub ac {
+ my $self = shift;
+ return qsearchs('ac', { acnum => $self->acnum });
+}
+
+=item svc_broadband
+
+Returns a list of L<FS::svc_broadband> objects associated
+with this object.
+
+=cut
+
+#sub svc_broadband {
+# my $self = shift;
+# my @svc = qsearch('svc_broadband', { actypenum => $self->ac->ac_type->actypenum });
+# return grep {
+# my $svc_addr = new NetAddr::IP($_->ip_addr, $_->ip_netmask);
+# $self_addr->contains($svc_addr);
+# } @svc;
+#}
+
+=back
+
+=cut
+
+1;
+
diff --git a/FS/FS/ac_field.pm b/FS/FS/ac_field.pm
new file mode 100755
index 0000000..f601119
--- /dev/null
+++ b/FS/FS/ac_field.pm
@@ -0,0 +1,138 @@
+package FS::ac_field;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs );
+use FS::part_ac_field;
+use FS::ac;
+
+use UNIVERSAL qw( can );
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::ac_field - Object methods for ac_field records
+
+=head1 SYNOPSIS
+
+ use FS::ac_field;
+
+ $record = new FS::ac_field \%hash;
+ $record = new FS::ac_field { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+L<FS::ac_field> contains values of fields defined by L<FS::part_ac_field>
+for an L<FS::ac>. Values must be of the data type defined by ut_type in
+L<FS::part_ac_field>.
+Supported fields as follows:
+
+=over 4
+
+=item acfieldpart - Type of ac_field as defined by L<FS::part_ac_field>
+
+=item acnum - The L<FS::ac> to which this value belongs.
+
+=item value - The contents of the field.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new record. To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'ac_field'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ return "acnum must be defined" unless $self->acnum;
+ return "acfieldpart must be defined" unless $self->acfieldpart;
+
+ my $ut_func = $self->can("ut_" . $self->part_ac_field->ut_type);
+ my $error = $self->$ut_func('value');
+
+ return $error if $error;
+
+ ''; #no error
+}
+
+=item part_ac_field
+
+Returns a reference to the L<FS:part_ac_field> that defines this L<FS::ac_field>
+
+=cut
+
+sub part_ac_field {
+ my $self = shift;
+
+ return qsearchs('part_ac_field', { acfieldpart => $self->acfieldpart });
+}
+
+=item ac
+
+Returns a reference to the L<FS::ac> to which this L<FS::ac_field> belongs.
+
+=cut
+
+sub ac {
+ my $self = shift;
+
+ return qsearchs('ac', { acnum => $self->acnum });
+}
+
+=back
+
+=head1 VERSION
+
+$Id:
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::svc_broadband>, L<FS::ac>, L<FS::ac_block>, L<FS::ac_field>, schema.html
+from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/ac_type.pm b/FS/FS/ac_type.pm
new file mode 100755
index 0000000..e83c5c5
--- /dev/null
+++ b/FS/FS/ac_type.pm
@@ -0,0 +1,128 @@
+package FS::ac_type;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs );
+use FS::ac;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::ac_type - Object methods for ac_type records
+
+=head1 SYNOPSIS
+
+ use FS::ac_type;
+
+ $record = new FS::ac_type \%hash;
+ $record = new FS::ac_type { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+L<FS::ac_type> refers to a type of access concentrator. L<FS::svc_broadband>
+records refer to a specific L<FS::ac_type> limiting the choice of access
+concentrator to one of the chosen type. This should be set as a fixed
+default in part_svc to prevent provisioning the wrong type of service for
+a given package or service type. Supported fields as follows:
+
+=over 4
+
+=item actypenum - Primary key. see L<FS::ac>
+
+=item actypename - Text identifier for access concentrator type.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new record. To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'ac_type'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ # What do we check?
+
+ ''; #no error
+}
+
+=item ac
+
+Returns a list of all L<FS::ac> records of this type.
+
+=cut
+
+sub ac {
+ my $self = shift;
+
+ return qsearch('ac', { actypenum => $self->actypenum });
+}
+
+=item part_ac_field
+
+Returns a list of all L<FS::part_ac_field> records of this type.
+
+=cut
+
+sub part_ac_field {
+ my $self = shift;
+
+ return qsearch('part_ac_field', { actypenum => $self->actypenum });
+}
+
+=back
+
+=head1 VERSION
+
+$Id:
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::svc_broadband>, L<FS::ac>, L<FS::ac_block>, L<FS::ac_field>, schema.html
+from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm
index c7cc4b3..d54fb2d 100644
--- a/FS/FS/cust_svc.pm
+++ b/FS/FS/cust_svc.pm
@@ -295,6 +295,8 @@ sub label {
} elsif ( $svcdb eq 'svc_www' ) {
my $domain = qsearchs( 'domain_record', { 'recnum' => $svc_x->recnum } );
$tag = $domain->reczone;
+ } elsif ( $svcdb eq 'svc_broadband' ) {
+ $tag = $svc_x->ip_addr . '/' . $svc_x->ip_netmask;
} else {
cluck "warning: asked for label of unsupported svcdb; using svcnum";
$tag = $svc_x->getfield('svcnum');
@@ -344,7 +346,7 @@ sub seconds_since {
=head1 VERSION
-$Id: cust_svc.pm,v 1.15 2002-05-22 12:17:06 ivan Exp $
+$Id: cust_svc.pm,v 1.16 2002-09-09 23:01:35 khoff Exp $
=head1 BUGS
diff --git a/FS/FS/part_ac_field.pm b/FS/FS/part_ac_field.pm
new file mode 100755
index 0000000..dcb4452
--- /dev/null
+++ b/FS/FS/part_ac_field.pm
@@ -0,0 +1,102 @@
+package FS::part_ac_field;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs );
+use FS::ac_field;
+use FS::ac;
+
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::part_ac_field - Object methods for part_ac_field records
+
+=head1 SYNOPSIS
+
+ use FS::part_ac_field;
+
+ $record = new FS::part_ac_field \%hash;
+ $record = new FS::part_ac_field { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+
+=over 4
+
+=item blank
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new record. To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'part_ac_field'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+ my $error = '';
+
+ $self->name =~ /^([a-z0-9_\-\.]{1,15})$/i
+ or return "Invalid field name for part_ac_field";
+
+ ''; #no error
+}
+
+
+=back
+
+=head1 VERSION
+
+$Id:
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::svc_broadband>, L<FS::ac>, L<FS::ac_block>, L<FS::ac_field>, schema.html
+from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm
index bc6a4d7..69cd805 100644
--- a/FS/FS/part_export.pm
+++ b/FS/FS/part_export.pm
@@ -839,6 +839,9 @@ tie my %sqlmail_options, 'Tie::IxHash',
},
+ 'svc_broadband' => {
+ },
+
);
=back
diff --git a/FS/FS/svc_broadband.pm b/FS/FS/svc_broadband.pm
new file mode 100755
index 0000000..ab92fb3
--- /dev/null
+++ b/FS/FS/svc_broadband.pm
@@ -0,0 +1,295 @@
+package FS::svc_broadband;
+
+use strict;
+use vars qw(@ISA $conf);
+#use FS::Record qw( qsearch qsearchs );
+use FS::Record qw( qsearchs qsearch dbh );
+use FS::svc_Common;
+use FS::cust_svc;
+use NetAddr::IP;
+
+@ISA = qw( FS::svc_Common );
+
+$FS::UID::callback{'FS::svc_broadband'} = sub {
+ $conf = new FS::Conf;
+};
+
+=head1 NAME
+
+FS::svc_broadband - Object methods for svc_broadband records
+
+=head1 SYNOPSIS
+
+ use FS::svc_broadband;
+
+ $record = new FS::svc_broadband \%hash;
+ $record = new FS::svc_broadband { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->suspend;
+
+ $error = $record->unsuspend;
+
+ $error = $record->cancel;
+
+=head1 DESCRIPTION
+
+An FS::svc_broadband object represents a 'broadband' Internet connection, such
+as a DSL, cable modem, or fixed wireless link. These services are assumed to
+have the following properties:
+
+=over 2
+
+=item
+The network consists of one or more 'Access Concentrators' (ACs), such as
+DSLAMs or wireless access points. (See L<FS::ac>.)
+
+=item
+Each AC provides connectivity to one or more contiguous blocks of IP addresses,
+each described by a gateway address and a netmask. (See L<FS::ac_block>.)
+
+=item
+Each connection has one or more static IP addresses within one of these blocks.
+
+=item
+The details of configuring routers and other devices are to be handled by a
+site-specific L<FS::part_export> subclass.
+
+=back
+
+FS::svc_broadband inherits from FS::svc_Common. The following fields are
+currently supported:
+
+=over 4
+
+=item svcnum - primary key
+
+=item
+actypenum - access concentrator type; see L<FS::ac_type>. This is included here
+so that a part_svc can specifically be a 'wireless' or 'DSL' service by
+designating actypenum as a fixed field. It does create a redundant functional
+dependency between this table and ac_type, in that the matching ac_type could
+be found by looking up the IP address in ac_block and then finding the block's
+AC, but part_svc can't do that, and we don't feel like hacking it so that it
+can.
+
+=item
+speed_up - maximum upload speed, in bits per second. If set to zero, upload
+speed will be unlimited. Exports that do traffic shaping should handle this
+correctly, and not blindly set the upload speed to zero and kill the customer's
+connection.
+
+=item
+speed_down - maximum download speed, as above
+
+=item
+ip_addr - the customer's IP address. If the customer needs more than one IP
+address, set this to the address of the customer's router. As a result, the
+customer's router will have the same address for both it's internal and external
+interfaces thus saving address space. This has been found to work on most NAT
+routers available.
+
+=item
+ip_netmask - the customer's netmask, as a single integer in the range 0-32.
+(E.g. '24', not '255.255.255.0'. We assume that address blocks are contiguous.)
+This should be 32 unless the customer has multiple IP addresses.
+
+=item
+mac_addr - the MAC address of the customer's router or other device directly
+connected to the network, if needed. Some systems (e.g. DHCP, MAC address-based
+access control) may need this. If not, you may leave it blank.
+
+=item
+location - a human-readable description of the location of the connected site,
+such as its address. This should not be used for billing or contact purposes;
+that information is stored in L<FS::cust_main>.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new svc_broadband. To add the record to the database, see
+L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'svc_broadband'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
+defined. An FS::cust_svc record will be created and inserted.
+
+=cut
+
+# sub insert {}
+# Standard FS::svc_Common::insert
+# (any necessary Deep Magic is handled by exports)
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# Standard FS::svc_Common::delete
+
+=item replace OLD_RECORD
+
+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
+# Notice a pattern here?
+
+=item suspend
+
+Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item unsuspend
+
+Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item cancel
+
+Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item check
+
+Checks all fields to make sure this is a valid broadband service. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+ my $x = $self->setfixed;
+
+ return $x unless ref($x);
+
+ my $error =
+ $self->ut_numbern('svcnum')
+ || $self->ut_foreign_key('actypenum', 'ac_type', 'actypenum')
+ || $self->ut_number('speed_up')
+ || $self->ut_number('speed_down')
+ || $self->ut_ip('ip_addr')
+ || $self->ut_numbern('ip_netmask')
+ || $self->ut_textn('mac_addr')
+ || $self->ut_textn('location')
+ ;
+ 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'; }
+
+ # This should catch errors in the ip_addr and ip_netmask. If it doesn't,
+ # they'll almost certainly not map into a valid block anyway.
+ my $self_addr = new NetAddr::IP ($self->ip_addr, $self->ip_netmask);
+ return 'Cannot parse address: ' . $self->ip_addr . '/' . $self->ip_netmask unless $self_addr;
+
+ my @block = grep {
+ my $block_addr = new NetAddr::IP ($_->ip_gateway, $_->ip_netmask);
+ if ($block_addr->contains($self_addr)) { $_ };
+ } qsearch( 'ac_block', { acnum => $self->acnum });
+
+ if(scalar @block == 0) {
+ return 'Block not found for address '.$self->ip_addr.' in actype '.$self->actypenum;
+ } elsif(scalar @block > 1) {
+ return 'ERROR: Intersecting blocks found for address '.$self->ip_addr.' :'.
+ join ', ', map {$_->ip_addr . '/' . $_->ip_netmask} @block;
+ }
+ # OK, we've found a valid block. We don't actually _do_ anything with it, though; we
+ # just take comfort in the knowledge that it exists.
+
+ # A simple qsearchs won't work here. Since we can assign blocks to customers,
+ # we have to make sure the new address doesn't fall within someone else's
+ # block. Ugh.
+
+ my @conflicts = grep {
+ my $cust_addr = new NetAddr::IP($_->ip_addr, $_->ip_netmask);
+ if (($cust_addr->contains($self_addr)) and
+ ($_->svcnum ne $self->svcnum)) { $_; };
+ } qsearch('svc_broadband', {});
+
+ if (scalar @conflicts > 0) {
+ return 'Address in use by existing service';
+ }
+
+ # Are we trying to use a network, broadcast, or the AC's address?
+ foreach (qsearch('ac_block', { acnum => $self->acnum })) {
+ my $block_addr = new NetAddr::IP($_->ip_gateway, $_->ip_netmask);
+ if ($block_addr->network->addr eq $self_addr->addr) {
+ return 'Address is network address for block '. $block_addr->network;
+ }
+ if ($block_addr->broadcast->addr eq $self_addr->addr) {
+ return 'Address is broadcast address for block '. $block_addr->network;
+ }
+ if ($block_addr->addr eq $self_addr->addr) {
+ return 'Address belongs to the access concentrator: '. $block_addr->addr;
+ }
+ }
+
+ ''; #no error
+}
+
+=item ac_block
+
+Returns the FS::ac_block record (i.e. the address block) for this broadband service.
+
+=cut
+
+sub ac_block {
+ my $self = shift;
+ my $self_addr = new NetAddr::IP ($self->ip_addr, $self->ip_netmask);
+
+ foreach my $block (qsearch( 'ac_block', {} )) {
+ my $block_addr = new NetAddr::IP ($block->ip_addr, $block->ip_netmask);
+ if($block_addr->contains($self_addr)) { return $block; }
+ }
+ return '';
+}
+
+=item ac_type
+
+Returns the FS::ac_type record for this broadband service.
+
+=cut
+
+sub ac_type {
+ my $self = shift;
+ return qsearchs('ac_type', { actypenum => $self->actypenum });
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::svc_Common>, L<FS::Record>, L<FS::ac_type>, L<FS::ac_block>,
+L<FS::part_svc>, schema.html from the base documentation.
+
+=cut
+
+1;
+