summaryrefslogtreecommitdiff
path: root/FS
diff options
context:
space:
mode:
Diffstat (limited to 'FS')
-rw-r--r--FS/FS/AccessRight.pm1
-rw-r--r--FS/FS/Mason.pm4
-rw-r--r--FS/FS/Schema.pm74
-rw-r--r--FS/FS/UI/Web.pm19
-rwxr-xr-xFS/FS/addr_block.pm18
-rw-r--r--FS/FS/circuit_provider.pm101
-rw-r--r--FS/FS/circuit_termination.pm98
-rw-r--r--FS/FS/circuit_type.pm98
-rwxr-xr-xFS/FS/router.pm7
-rw-r--r--FS/FS/svc_circuit.pm230
-rw-r--r--FS/FS/svc_phone.pm35
-rw-r--r--FS/MANIFEST8
-rw-r--r--FS/t/circuit_provider.t5
-rw-r--r--FS/t/circuit_termination.t5
-rw-r--r--FS/t/circuit_type.t5
-rw-r--r--FS/t/svc_circuit.t5
16 files changed, 710 insertions, 3 deletions
diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm
index bad831a94..92cede6a5 100644
--- a/FS/FS/AccessRight.pm
+++ b/FS/FS/AccessRight.pm
@@ -310,6 +310,7 @@ tie my %rights, 'Tie::IxHash',
'Services: Mailing lists',
'Services: Alarm services',
'Services: Video',
+ 'Services: Circuits',
'Services: External services',
'Usage: RADIUS sessions',
'Usage: Call Detail Records (CDRs)',
diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm
index 900da1005..d3e45dfee 100644
--- a/FS/FS/Mason.pm
+++ b/FS/FS/Mason.pm
@@ -392,6 +392,10 @@ if ( -e $addl_handler_use_file ) {
use FS::deploy_zone_vertex;
use FS::TaxEngine;
use FS::tax_status;
+ use FS::circuit_type;
+ use FS::circuit_provider;
+ use FS::circuit_termination;
+ use FS::svc_circuit;
# Sammath Naur
if ( $FS::Mason::addl_handler_use ) {
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 715a603f8..91dfc5d97 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -5653,6 +5653,7 @@ sub tables_hashref {
'max_simultaneous', 'int', 'NULL', '', '', '',
'e911_class', 'char', 'NULL', 1, '', '',
'e911_type', 'char', 'NULL', 1, '', '',
+ 'circuit_svcnum', 'int', 'NULL', '', '', '',
],
'primary_key' => 'svcnum',
'unique' => [ [ 'sms_carrierid', 'sms_account'] ],
@@ -5678,6 +5679,10 @@ sub tables_hashref {
table => 'cdr_carrier',
references => [ 'carrierid' ],
},
+ { columns => [ 'circuit_svcnum' ],
+ table => 'svc_circuit',
+ references => [ 'svcnum' ],
+ },
],
},
@@ -6527,6 +6532,75 @@ sub tables_hashref {
],
},
+ 'circuit_type' => {
+ 'columns' => [
+ 'typenum', 'serial', '', '', '', '',
+ 'typename', 'varchar', '', $char_d, '', '',
+ 'disabled', 'char', 'NULL', 1, '', '',
+ # speed? number of voice lines? anything else?
+ ],
+ 'primary_key' => 'typenum',
+ 'unique' => [ [ 'typename' ] ],
+ 'index' => [],
+ },
+
+ 'circuit_provider' => {
+ 'columns' => [
+ 'providernum', 'serial', '', '', '', '',
+ 'provider', 'varchar', '', $char_d, '', '',
+ 'disabled', 'char', 'NULL', 1, '', '',
+ ],
+ 'primary_key' => 'providernum',
+ 'unique' => [ [ 'provider' ], ],
+ 'index' => [],
+ },
+
+ 'circuit_termination' => {
+ 'columns' => [
+ 'termnum', 'serial', '', '', '', '',
+ 'termination','varchar', '', $char_d, '', '',
+ 'disabled', 'char', 'NULL', 1, '', '',
+ ],
+ 'primary_key' => 'termnum',
+ 'unique' => [ [ 'termination' ] ],
+ 'index' => [],
+ },
+
+ 'svc_circuit' => {
+ 'columns' => [
+ 'svcnum', 'int', '', '', '', '',
+ 'typenum', 'int', '', '', '', '',
+ 'providernum', 'int', '', '', '', '',
+ 'termnum', 'int', '', '', '', '',
+ 'circuit_id', 'varchar', '', 64, '', '',
+ 'desired_due_date', 'int', 'NULL', '', '', '',
+ 'due_date', 'int', 'NULL', '', '', '',
+ 'vendor_order_id', 'varchar', 'NULL', $char_d, '', '',
+ 'vendor_qual_id', 'varchar', 'NULL', $char_d, '', '',
+ 'vendor_order_type', 'varchar', 'NULL', $char_d, '', '',
+ 'vendor_order_status', 'varchar', 'NULL', $char_d, '', '',
+ 'endpoint_ip_addr', 'varchar', 'NULL', 40, '', '',
+ 'endpoint_mac_addr', 'varchar', 'NULL', 12, '', '',
+ ],
+ 'primary_key' => 'svcnum',
+ 'unique' => [],
+ 'index' => [ [ 'providernum' ], [ 'typenum' ] ],
+ 'foreign_keys' => [
+ { columns => [ 'svcnum' ],
+ table => 'cust_svc',
+ },
+ { columns => [ 'typenum' ],
+ table => 'circuit_type',
+ },
+ { columns => [ 'providernum' ],
+ table => 'circuit_provider',
+ },
+ { columns => [ 'termnum' ],
+ table => 'circuit_termination',
+ },
+ ],
+ },
+
'vend_main' => {
'columns' => [
'vendnum', 'serial', '', '', '', '',
diff --git a/FS/FS/UI/Web.pm b/FS/FS/UI/Web.pm
index 99c35609e..e13869265 100644
--- a/FS/FS/UI/Web.pm
+++ b/FS/FS/UI/Web.pm
@@ -113,16 +113,16 @@ sub svc_url {
if $DEBUG;
if ( $opt{m}->interp->comp_exists("/$opt{action}/$svcdb.cgi") ) {
$url = "$svcdb.cgi?";
+ } elsif ( $opt{m}->interp->comp_exists("/$opt{action}/$svcdb.html") ) {
+ $url = "$svcdb.html?";
} else {
-
my $generic = $opt{action} eq 'search' ? 'cust_svc' : 'svc_Common';
$url = "$generic.html?svcdb=$svcdb;";
$url .= 'svcnum=' if $query =~ /^\d+(;|$)/ or $query eq '';
}
- import FS::CGI 'rooturl'; #WTF! why is this necessary
- my $return = rooturl(). "$opt{action}/$url$query";
+ my $return = FS::CGI::rooturl(). "$opt{action}/$url$query";
$return = qq!<A HREF="$return">! if $opt{ahref};
@@ -574,6 +574,19 @@ sub cust_aligns {
}
}
+=item cust_links
+
+Returns an array of links to view/cust_main.cgi, for use with cust_fields.
+
+=cut
+
+sub cust_links {
+ my $link = [ FS::CGI::rooturl().'view/cust_main.cgi?', 'custnum' ];
+
+ return map { $_ eq 'cust_status_label' ? '' : $link }
+ @cust_fields;
+}
+
=item is_mobile
Utility function to determine if the client is a mobile browser.
diff --git a/FS/FS/addr_block.pm b/FS/FS/addr_block.pm
index 3e62a688b..ba0f61db1 100755
--- a/FS/FS/addr_block.pm
+++ b/FS/FS/addr_block.pm
@@ -388,6 +388,24 @@ sub label {
($router ? $router->routername : '(unallocated)'). ':'. $self->NetAddr;
}
+=item router
+
+Returns the router assigned to this block.
+
+=cut
+
+# necessary, because this can't be foreign keyed
+
+sub router {
+ my $self = shift;
+ my $routernum = $self->routernum;
+ if ( $routernum ) {
+ return FS::router->by_key($routernum);
+ } else {
+ return;
+ }
+}
+
=back
=head1 BUGS
diff --git a/FS/FS/circuit_provider.pm b/FS/FS/circuit_provider.pm
new file mode 100644
index 000000000..6cb784117
--- /dev/null
+++ b/FS/FS/circuit_provider.pm
@@ -0,0 +1,101 @@
+package FS::circuit_provider;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::circuit_provider - Object methods for circuit_provider records
+
+=head1 SYNOPSIS
+
+ use FS::circuit_provider;
+
+ $record = new FS::circuit_provider \%hash;
+ $record = new FS::circuit_provider { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::circuit_provider object represents a telecom carrier that provides
+physical circuits (L<FS::svc_circuit>). FS::circuit_provider inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item providernum - primary key
+
+=item provider - provider name
+
+=item disabled - disabled
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record. To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'circuit_provider'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=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.
+
+=item check
+
+Checks all fields to make sure this is a valid example. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('providernum')
+ || $self->ut_text('provider')
+ || $self->ut_flag('disabled')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/FS/circuit_termination.pm b/FS/FS/circuit_termination.pm
new file mode 100644
index 000000000..3f0afc1f9
--- /dev/null
+++ b/FS/FS/circuit_termination.pm
@@ -0,0 +1,98 @@
+package FS::circuit_termination;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::circuit_termination - Object methods for circuit_termination records
+
+=head1 SYNOPSIS
+
+ use FS::circuit_termination;
+
+ $record = new FS::circuit_termination \%hash;
+ $record = new FS::circuit_termination { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::circuit_termination object represents a central office circuit
+interface type. FS::circuit_termination inherits from FS::Record. The
+following fields are currently supported:
+
+=over 4
+
+=item termnum - primary key
+
+=item termination - description of the termination type
+
+=item disabled - 'Y' if this is disabled
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example to the database, see L<"insert">.
+
+=cut
+
+sub table { 'circuit_termination'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=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.
+
+=item check
+
+Checks all fields to make sure this is a valid example. 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('termnum')
+ || $self->ut_text('termination')
+ || $self->ut_flag('disabled')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/FS/circuit_type.pm b/FS/FS/circuit_type.pm
new file mode 100644
index 000000000..3b3653693
--- /dev/null
+++ b/FS/FS/circuit_type.pm
@@ -0,0 +1,98 @@
+package FS::circuit_type;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::circuit_type - Object methods for circuit_type records
+
+=head1 SYNOPSIS
+
+ use FS::circuit_type;
+
+ $record = new FS::circuit_type \%hash;
+ $record = new FS::circuit_type { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::circuit_type object represents a circuit type (such as "DS1" or "OC3").
+FS::circuit_type inherits from FS::Record. The following fields are currently
+supported:
+
+=over 4
+
+=item typenum - primary key
+
+=item typename - name of the circuit type
+
+=item disabled - 'Y' if this is disabled
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example to the database, see L<"insert">.
+
+=cut
+
+sub table { 'circuit_type'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=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.
+
+=item check
+
+Checks all fields to make sure this is a valid example. 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('typenum')
+ || $self->ut_text('typename')
+ || $self->ut_flag('disabled')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/FS/router.pm b/FS/FS/router.pm
index 4011bb097..c0c93dd32 100755
--- a/FS/FS/router.pm
+++ b/FS/FS/router.pm
@@ -200,6 +200,13 @@ sub delete {
Returns a list of FS::addr_block objects (address blocks) associated
with this object.
+=cut
+
+sub addr_block {
+ my $self = shift;
+ qsearch('addr_block', { routernum => $self->routernum });
+}
+
=item auto_addr_block
Returns a list of address blocks on which auto-assignment of IP addresses
diff --git a/FS/FS/svc_circuit.pm b/FS/FS/svc_circuit.pm
new file mode 100644
index 000000000..f705c68f4
--- /dev/null
+++ b/FS/FS/svc_circuit.pm
@@ -0,0 +1,230 @@
+package FS::svc_circuit;
+
+use strict;
+use base qw(
+ FS::svc_IP_Mixin
+ FS::MAC_Mixin
+ FS::svc_Common
+);
+use FS::Record qw( qsearch qsearchs );
+use FS::circuit_provider;
+use FS::circuit_type;
+use FS::circuit_termination;
+
+=head1 NAME
+
+FS::svc_circuit - Object methods for svc_circuit records
+
+=head1 SYNOPSIS
+
+ use FS::svc_circuit;
+
+ $record = new FS::svc_circuit \%hash;
+ $record = new FS::svc_circuit { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::svc_circuit object represents a telecom circuit service (other than
+an analog phone line, which is svc_phone, or a DSL Internet connection,
+which is svc_dsl). FS::svc_circuit inherits from FS::svc_IP_Mixin,
+FS::MAC_Mixin, and FS::svc_Common. The following fields are currently
+supported:
+
+=over 4
+
+=item svcnum - primary key; see also L<FS::cust_svc>
+
+=item typenum - circuit type (such as DS1, DS1-PRI, DS3, OC3, etc.); foreign
+key to L<FS::circuit_type>.
+
+=item providernum - circuit provider (telco); foreign key to
+L<FS::circuit_provider>.
+
+=item termnum - circuit termination type; foreign key to
+L<FS::circuit_termination>
+
+=item circuit_id - circuit ID string defined by the provider
+
+=item desired_due_date - the requested date for completion of the circuit
+order
+
+=item due_date - the provider's committed date for completion of the circuit
+order
+
+=item vendor_order_id - the provider's order number
+
+=item vendor_qual_id - the qualification number, if a qualification was
+performed
+
+=item vendor_order_type -
+
+=item vendor_order_status - the order status: ACCEPTED, PENDING, COMPLETED,
+etc.
+
+=item endpoint_ip_addr - the IP address of the endpoint equipment, if any.
+This will be validated as an IP address but not assigned from managed address
+space or checked for uniqueness.
+
+=item endpoint_mac_addr - the MAC address of the endpoint.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new circuit service. To add the record to the database, see
+L<"insert">.
+
+=cut
+
+sub table { 'svc_circuit'; }
+
+sub table_info {
+ my %dis = ( disable_default => 1, disable_fixed => 1,
+ disabled_inventory => 1, disable_select => 1 );
+
+ tie my %fields, 'Tie::IxHash', (
+ 'svcnum' => 'Service',
+ 'providernum' => {
+ label => 'Provider',
+ type => 'select',
+ select_table => 'circuit_provider',
+ select_key => 'providernum',
+ select_label => 'provider',
+ disable_inventory => 1,
+ },
+ 'typenum' => {
+ label => 'Circuit type',
+ type => 'select',
+ select_table => 'circuit_type',
+ select_key => 'typenum',
+ select_label => 'typename',
+ disable_inventory => 1,
+ },
+ 'termnum' => {
+ label => 'Termination type',
+ type => 'select',
+ select_table => 'circuit_termination',
+ select_key => 'termnum',
+ select_label => 'termination',
+ disable_inventory => 1,
+ },
+ 'circuit_id' => { label => 'Circuit ID', %dis },
+ 'desired_due_date' => { label => 'Desired due date',
+ %dis
+ },
+ 'due_date' => { label => 'Due date',
+ %dis
+ },
+ 'vendor_order_id' => { label => 'Vendor order ID', %dis },
+ 'vendor_qual_id' => { label => 'Vendor qualification ID', %dis },
+ 'vendor_order_type' => {
+ label => 'Vendor order type',
+ disable_inventory => 1
+ }, # should be a select?
+ 'vendor_order_status' => {
+ label => 'Vendor order status',
+ disable_inventory => 1
+ }, # should also be a select?
+ 'endpoint_ip_addr' => {
+ label => 'Endpoint IP address',
+ },
+ 'endpoint_mac_addr' => {
+ label => 'Endpoint MAC address',
+ type => 'input-mac_addr',
+ disable_inventory => 1,
+ },
+ );
+ return {
+ 'name' => 'Circuit',
+ 'name_plural' => 'Circuits',
+ 'longname_plural' => 'Voice and data circuit services',
+ 'display_weight' => 72,
+ 'cancel_weight' => 85, # after svc_phone
+ 'fields' => \%fields,
+ };
+}
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=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.
+
+=item check
+
+Checks all fields to make sure this is a valid 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 $mac_addr = uc($self->get('endpoint_mac_addr'));
+ $mac_addr =~ s/[\W_]//g;
+ $self->set('endpoint_mac_addr', $mac_addr);
+
+ my $error =
+ $self->ut_numbern('svcnum')
+ || $self->ut_number('typenum')
+ || $self->ut_number('providernum')
+ || $self->ut_text('circuit_id')
+ || $self->ut_numbern('desired_due_date')
+ || $self->ut_numbern('due_date')
+ || $self->ut_textn('vendor_order_id')
+ || $self->ut_textn('vendor_qual_id')
+ || $self->ut_textn('vendor_order_type')
+ || $self->ut_textn('vendor_order_status')
+ || $self->ut_ipn('endpoint_ip_addr')
+ || $self->ut_textn('endpoint_mac_addr')
+ ;
+
+ # no canonical values yet for vendor_order_status or _type
+
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=item label
+
+Returns the circuit ID.
+
+=cut
+
+sub label {
+ my $self = shift;
+ $self->get('circuit_id');
+}
+
+=back
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/FS/svc_phone.pm b/FS/FS/svc_phone.pm
index 4ca8d82fa..bd35cbac4 100644
--- a/FS/FS/svc_phone.pm
+++ b/FS/FS/svc_phone.pm
@@ -189,6 +189,14 @@ sub table_info {
select_label => 'domain',
disable_inventory => 1,
},
+ 'circuit_svcnum' => { label => 'Circuit',
+ type => 'select',
+ select_table => 'svc_domain',
+ select_key => 'svcnum',
+ select_label => 'circuit_label',
+ disable_inventory => 1,
+ },
+
'sms_carrierid' => { label => 'SMS Carrier',
type => 'select',
select_table => 'cdr_carrier',
@@ -711,6 +719,8 @@ sub radius_groups {
=item sms_cdr_carrier
+Returns the L<FS::cdr_carrier> assigned as the SMS carrier for this phone.
+
=cut
sub sms_cdr_carrier {
@@ -721,6 +731,8 @@ sub sms_cdr_carrier {
=item sms_carriername
+Returns the name of the SMS carrier, or an empty string if there isn't one.
+
=cut
sub sms_carriername {
@@ -729,6 +741,29 @@ sub sms_carriername {
$cdr_carrier->carriername;
}
+=item svc_circuit
+
+Returns the L<FS::svc_circuit> assigned as the trunk for this phone line.
+
+=item circuit_label
+
+Returns the label of the circuit (the part_svc label followed by the
+circuit ID), or an empty string if there isn't one.
+
+=cut
+
+sub svc_circuit {
+ my $self = shift;
+ my $svcnum = $self->get('circuit_svcnum') or return '';
+ return FS::svc_circuit->by_key($svcnum);
+}
+
+sub circuit_label {
+ my $self = shift;
+ my $svc_circuit = $self->svc_circuit or return '';
+ return join(' ', $svc_circuit->part_svc->svc, $svc_circuit->circuit_id);
+}
+
=item phone_device
Returns any FS::phone_device records associated with this service.
diff --git a/FS/MANIFEST b/FS/MANIFEST
index 79a7dc523..105447c6b 100644
--- a/FS/MANIFEST
+++ b/FS/MANIFEST
@@ -821,3 +821,11 @@ FS/deploy_zone_vertex.pm
t/deploy_zone_vertex.t
FS/tax_status.pm
t/tax_status.t
+FS/circuit_type.pm
+t/circuit_type.t
+FS/circuit_provider.pm
+t/circuit_provider.t
+FS/circuit_termination.pm
+t/circuit_termination.t
+FS/svc_circuit.pm
+t/svc_circuit.t
diff --git a/FS/t/circuit_provider.t b/FS/t/circuit_provider.t
new file mode 100644
index 000000000..753a156d5
--- /dev/null
+++ b/FS/t/circuit_provider.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::circuit_provider;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/circuit_termination.t b/FS/t/circuit_termination.t
new file mode 100644
index 000000000..6f5127195
--- /dev/null
+++ b/FS/t/circuit_termination.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::circuit_termination;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/circuit_type.t b/FS/t/circuit_type.t
new file mode 100644
index 000000000..dbb6e0ac5
--- /dev/null
+++ b/FS/t/circuit_type.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::circuit_type;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_circuit.t b/FS/t/svc_circuit.t
new file mode 100644
index 000000000..7fefcc04b
--- /dev/null
+++ b/FS/t/svc_circuit.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_circuit;
+$loaded=1;
+print "ok 1\n";