5c9fe5e120957f90f458bcba64dc992ece91a51e
[freeside.git] / FS / FS / svc_broadband.pm
1 package FS::svc_broadband;
2
3 use strict;
4 use vars qw(@ISA $conf);
5 use FS::Record qw( qsearchs qsearch dbh );
6 use FS::svc_Common;
7 use FS::cust_svc;
8 use FS::addr_block;
9 use NetAddr::IP;
10
11 @ISA = qw( FS::svc_Common );
12
13 $FS::UID::callback{'FS::svc_broadband'} = sub { 
14   $conf = new FS::Conf;
15 };
16
17 =head1 NAME
18
19 FS::svc_broadband - Object methods for svc_broadband records
20
21 =head1 SYNOPSIS
22
23   use FS::svc_broadband;
24
25   $record = new FS::svc_broadband \%hash;
26   $record = new FS::svc_broadband { 'column' => 'value' };
27
28   $error = $record->insert;
29
30   $error = $new_record->replace($old_record);
31
32   $error = $record->delete;
33
34   $error = $record->check;
35
36   $error = $record->suspend;
37
38   $error = $record->unsuspend;
39
40   $error = $record->cancel;
41
42 =head1 DESCRIPTION
43
44 An FS::svc_broadband object represents a 'broadband' Internet connection, such
45 as a DSL, cable modem, or fixed wireless link.  These services are assumed to
46 have the following properties:
47
48 FS::svc_broadband inherits from FS::svc_Common.  The following fields are
49 currently supported:
50
51 =over 4
52
53 =item svcnum - primary key
54
55 =item blocknum - see FS::addr_block
56
57 =item
58 speed_up - maximum upload speed, in bits per second.  If set to zero, upload
59 speed will be unlimited.  Exports that do traffic shaping should handle this
60 correctly, and not blindly set the upload speed to zero and kill the customer's
61 connection.
62
63 =item
64 speed_down - maximum download speed, as above
65
66 =item ip_addr - the customer's IP address.  If the customer needs more than one
67 IP address, set this to the address of the customer's router.  As a result, the
68 customer's router will have the same address for both its internal and external
69 interfaces thus saving address space.  This has been found to work on most NAT
70 routers available.
71
72 =back
73
74 =head1 METHODS
75
76 =over 4
77
78 =item new HASHREF
79
80 Creates a new svc_broadband.  To add the record to the database, see
81 "insert".
82
83 Note that this stores the hash reference, not a distinct copy of the hash it
84 points to.  You can ask the object for a copy with the I<hash> method.
85
86 =cut
87
88 sub table { 'svc_broadband'; }
89
90 =item insert [ , OPTION => VALUE ... ]
91
92 Adds this record to the database.  If there is an error, returns the error,
93 otherwise returns false.
94
95 The additional fields pkgnum and svcpart (see FS::cust_svc) should be 
96 defined.  An FS::cust_svc record will be created and inserted.
97
98 Currently available options are: I<depend_jobnum>
99
100 If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
101 jobnums), all provisioning jobs will have a dependancy on the supplied
102 jobnum(s) (they will not run until the specific job(s) complete(s)).
103
104 =cut
105
106 # Standard FS::svc_Common::insert
107
108 =item delete
109
110 Delete this record from the database.
111
112 =cut
113
114 # Standard FS::svc_Common::delete
115
116 =item replace OLD_RECORD
117
118 Replaces the OLD_RECORD with this one in the database.  If there is an error,
119 returns the error, otherwise returns false.
120
121 =cut
122
123 # Standard FS::svc_Common::replace
124
125 =item suspend
126
127 Called by the suspend method of FS::cust_pkg (see FS::cust_pkg).
128
129 =item unsuspend
130
131 Called by the unsuspend method of FS::cust_pkg (see FS::cust_pkg).
132
133 =item cancel
134
135 Called by the cancel method of FS::cust_pkg (see FS::cust_pkg).
136
137 =item check
138
139 Checks all fields to make sure this is a valid broadband service.  If there is
140 an error, returns the error, otherwise returns false.  Called by the insert
141 and replace methods.
142
143 =cut
144
145 sub check {
146   my $self = shift;
147   my $x = $self->setfixed;
148
149   return $x unless ref($x);
150
151   my $error =
152     $self->ut_numbern('svcnum')
153     || $self->ut_foreign_key('blocknum', 'addr_block', 'blocknum')
154     || $self->ut_number('speed_up')
155     || $self->ut_number('speed_down')
156     || $self->ut_ipn('ip_addr')
157     || $self->ut_hexn('mac_addr')
158     || $self->ut_hexn('auth_key')
159     || $self->ut_floatn('latitude')
160     || $self->ut_floatn('longitude')
161     || $self->ut_floatn('altitude')
162     || $self->ut_textn('vlan_profile')
163   ;
164   return $error if $error;
165
166   if($self->speed_up < 0) { return 'speed_up must be positive'; }
167   if($self->speed_down < 0) { return 'speed_down must be positive'; }
168
169   if($self->latitude < -90 || $self->latitude > 90) {
170     return 'latitude must be between -90 and 90';
171   }
172   if($self->longitude < -180 || $self->longitude > 180) {
173     return 'longitude must be between -180 and 180';
174   }
175
176   if (not($self->ip_addr) or $self->ip_addr eq '0.0.0.0') {
177     my $next_addr = $self->addr_block->next_free_addr;
178     if ($next_addr) {
179       $self->ip_addr($next_addr->addr);
180     } else {
181       return "No free addresses in addr_block (blocknum: ".$self->blocknum.")";
182     }
183   }
184
185   # This should catch errors in the ip_addr.  If it doesn't,
186   # they'll almost certainly not map into the block anyway.
187   my $self_addr = $self->NetAddr; #netmask is /32
188   return ('Cannot parse address: ' . $self->ip_addr) unless $self_addr;
189
190   my $block_addr = $self->addr_block->NetAddr;
191   unless ($block_addr->contains($self_addr)) {
192     return 'blocknum '.$self->blocknum.' does not contain address '.$self->ip_addr;
193   }
194
195   my $router = $self->addr_block->router 
196     or return 'Cannot assign address from unallocated block:'.$self->addr_block->blocknum;
197   if(grep { $_->routernum == $router->routernum} $self->allowed_routers) {
198   } # do nothing
199   else {
200     return 'Router '.$router->routernum.' cannot provide svcpart '.$self->svcpart;
201   }
202
203   $self->SUPER::check;
204 }
205
206 =item NetAddr
207
208 Returns a NetAddr::IP object containing the IP address of this service.  The netmask 
209 is /32.
210
211 =cut
212
213 sub NetAddr {
214   my $self = shift;
215   return new NetAddr::IP ($self->ip_addr);
216 }
217
218 =item addr_block
219
220 Returns the FS::addr_block record (i.e. the address block) for this broadband service.
221
222 =cut
223
224 sub addr_block {
225   my $self = shift;
226
227   return qsearchs('addr_block', { blocknum => $self->blocknum });
228 }
229
230 =back
231
232 =item allowed_routers
233
234 Returns a list of allowed FS::router objects.
235
236 =cut
237
238 sub allowed_routers {
239   my $self = shift;
240
241   return map { $_->router } qsearch('part_svc_router', { svcpart => $self->svcpart });
242 }
243
244 =head1 BUGS
245
246 The business with sb_field has been 'fixed', in a manner of speaking.
247
248 =head1 SEE ALSO
249
250 FS::svc_Common, FS::Record, FS::addr_block,
251 FS::part_svc, schema.html from the base documentation.
252
253 =cut
254
255 1;
256