RT# 31208 Docs $FS::Record::qsearch_qualify_columns
[freeside.git] / FS / FS / svc_dsl.pm
1 package FS::svc_dsl;
2 use base qw(FS::Password_Mixin
3             FS::svc_Common);
4
5 use strict;
6 use vars qw( $conf $DEBUG $me );
7 use FS::UID;
8 use FS::Record qw( qsearch qsearchs dbh );
9 use FS::svc_Common;
10 use FS::dsl_device;
11 use FS::dsl_note;
12 use FS::qual;
13
14 $DEBUG = 0;
15 $me = '[FS::svc_dsl]';
16
17 FS::UID->install_callback( sub { 
18   $conf = new FS::Conf;
19 }
20 );
21
22 =head1 NAME
23
24 FS::svc_dsl - Object methods for svc_dsl records
25
26 =head1 SYNOPSIS
27
28   use FS::svc_dsl;
29
30   $record = new FS::svc_dsl \%hash;
31   $record = new FS::svc_dsl { 'column' => 'value' };
32
33   $error = $record->insert;
34
35   $error = $new_record->replace($old_record);
36
37   $error = $record->delete;
38
39   $error = $record->check;
40   
41   $error = $record->suspend;
42
43   $error = $record->unsuspend;
44
45   $error = $record->cancel;
46
47 =head1 DESCRIPTION
48
49 An FS::svc_dsl object represents a DSL service.  FS::svc_dsl inherits from
50 FS::svc_Common.  The following fields are currently supported:
51
52 =over 4
53
54 =item svcnum - Primary key (assigned automatcially for new DSL))
55
56 =item pushed - Time DSL order pushed to vendor/telco, if applicable
57
58 =item desired_due_date - Desired Due Date
59
60 =item due_date - Due Date
61
62 =item vendor_order_id - Vendor/telco DSL order #
63
64 =item vendor_order_type
65
66 Vendor/telco DSL order type (e.g. (M)ove, (A)dd, (C)hange, (D)elete, or similar)
67
68 =item vendor_order_status
69
70 Vendor/telco DSL order status (e.g. (N)ew, (A)ssigned, (R)ejected, (M)revised,
71 (C)ompleted, (X)cancelled, or similar)
72
73 =item first - End-user first name
74
75 =item last - End-user last name
76
77 =item company - End-user company name
78
79 =item phonenum - DSL Telephone Number
80
81 =item gateway_access_number - Gateway access number, if different
82
83 =item loop_type - Loop-type - vendor/telco-specific
84
85 =item local_voice_provider - Local Voice Provider's name
86
87 =item circuitnum - Circuit #
88
89 =item vpi
90
91 =item vci
92
93 =item rate_band - Rate Band
94
95 =item isp_chg
96
97 =item isp_prev
98
99 =item staticips
100
101 =item vendor_qual_id
102
103 Ikano-specific fields, do not use otherwise
104
105 =item username - if outsourced PPPoE/RADIUS, username
106
107 =item password - if outsourced PPPoE/RADIUS, password
108
109 =item monitored - Order is monitored (auto-pull/sync), either Y or blank
110
111 =item last_pull - time of last data pull from vendor/telco
112
113
114 =back
115
116 =head1 METHODS
117
118 =over 4
119
120 =item new HASHREF
121
122 Creates a new DSL.  To add the DSL to the database, see L<"insert">.
123
124 Note that this stores the hash reference, not a distinct copy of the hash it
125 points to.  You can ask the object for a copy with the I<hash> method.
126
127 =cut
128
129 # the new method can be inherited from FS::Record, if a table method is defined
130
131 sub table_info {
132     my %dis1 = ( disable_default=>1, disable_fixed=>1, disable_inventory=>1, disable_select=>1 );
133     my %dis2 = ( disable_inventory=>1, disable_select=>1 );
134
135     {
136         'name' => 'DSL',
137         'name_plural' => 'DSLs',
138         'lcname_plural' => 'DSLs',
139         'sorts' => [ 'phonenum' ],
140         'display_weight' => 55,
141         'cancel_weight' => 75,
142         'ip_field' => 'staticips',
143         'fields' => {
144             'pushed'                => { label => 'Pushed', 
145                                          type  => 'disabled' },
146             'desired_due_date'      => { label => 'Desired Due Date', %dis2, },
147             'due_date'              => { label => 'Due Date', %dis2, },
148             'vendor_order_id'       => { label => 'Vendor Order ID', %dis2, },
149             'vendor_qual_id'        => { label => 'Vendor Qualification ID', 
150                                          type => 'disabled' },
151             'vendor_order_type'     => { label => 'Vendor Order Type',
152                                          disable_inventory => 1, },
153             'vendor_order_status'   => { label => 'Vendor Order Status',
154                                          disable_inventory => 1, },
155             'first'                 => { label => 'First Name', %dis2, },
156             'last'                  => { label => 'Last Name', %dis2, },
157             'company'               => { label => 'Company Name', %dis2, },
158             'phonenum'              => { label => 'Service Telephone Number', },
159             'gateway_access_number' => { label => 'Gateway Access Number'.
160                                                   ' (if different)', },
161             'loop_type'             => { label => 'Loop Type',
162                                          disable_inventory => 1, },
163             'local_voice_provider'  => { label => 'Local Voice Provider',
164                                          disable_inventory => 1, },
165             'circuitnum'            => { label => 'Circuit #',        },
166             'rate_band'             => { label => 'Rate Band',
167                                          disable_inventory => 1, },
168             'vpi'                   => { label => 'VPI',
169                                          disable_inventory => 1 },
170             'vci'                   => { label => 'VCI',
171                                          disable_inventory => 1 },
172             'isp_chg'               => { label => 'ISP Changing?', 
173                                          type  => 'checkbox',
174                                          %dis2, },
175             'isp_prev'              => { label => 'Current or Previous ISP',
176                                          disable_inventory => 1, },
177             'username'              => { label => 'PPPoE Username',
178                                          type  => 'text', },
179             'password'              => { label => 'PPPoE Password', %dis2 },
180             'staticips'             => { label => 'Static IPs', %dis1 },
181             'monitored'             => { label => 'Monitored', 
182                                          type => 'checkbox', %dis2 },
183             'last_pull'             => { label => 'Last Pull',
184                                          type  => 'disabled' },
185         },
186     };
187 }
188
189 sub table { 'svc_dsl'; }
190
191 sub label {
192    my $self = shift;
193    return $self->phonenum if $self->phonenum;
194    return $self->username if $self->username;
195    return $self->vendor_order_id if $self->vendor_order_id;
196    return $self->svcnum;
197 }
198
199 =item notes
200
201 Returns the set of FS::dsl_notes associated with this service
202
203 =cut 
204 sub notes {
205   my $self = shift;
206   qsearch( 'dsl_note', { 'svcnum' => $self->svcnum } );
207 }
208
209 =item insert
210
211 Adds this record to the database.  If there is an error, returns the error,
212 otherwise returns false.
213
214 =cut
215
216 sub insert {
217   my $self = shift;
218   my $dbh = dbh;
219   my $oldAutoCommit = $FS::UID::AutoCommit;
220   local $FS::UID::AutoCommit = 0;
221
222   my $error = $self->SUPER::insert(@_);
223   if ( length($self->password) ) {
224     $error ||= $self->insert_password_history;
225   }
226
227   if ( $error ) {
228     $dbh->rollback if $oldAutoCommit;
229     return $error;
230   }
231
232   $dbh->commit if $oldAutoCommit;
233   '';
234 }
235
236 =item delete
237
238 Delete this record from the database.
239
240 =cut
241
242 # the delete method can be inherited from FS::Record
243
244 =item replace OLD_RECORD
245
246 Replaces the OLD_RECORD with this one in the database.  If there is an error,
247 returns the error, otherwise returns false.
248
249 =cut
250
251 sub replace {
252   my $new = shift;
253   my $old = shift || $new->replace_old;
254   my $dbh = dbh;
255   my $oldAutoCommit = $FS::UID::AutoCommit;
256   local $FS::UID::AutoCommit = 0;
257
258   my $error = $new->SUPER::replace($old, @_);
259   if ( $old->password ne $new->password ) {
260     $error ||= $new->insert_password_history;
261   }
262
263   if ( $error ) {
264     $dbh->rollback if $oldAutoCommit;
265     return $error;
266   }
267
268   $dbh->commit if $oldAutoCommit;
269   '';
270 }
271
272 # the replace method can be inherited from FS::Record
273
274 =item check
275
276 Checks all fields to make sure this is a valid DSL.  If there is
277 an error, returns the error, otherwise returns false.  Called by the insert
278 and replace methods.
279
280 =cut
281
282 # the check method should currently be supplied - FS::Record contains some
283 # data checking routines
284
285 sub check {
286   my $self = shift;
287
288   my $error = 
289     $self->ut_numbern('svcnum')
290     || $self->ut_numbern('pushed')
291     || $self->ut_numbern('desired_due_date')
292     || $self->ut_numbern('due_date')
293     || $self->ut_textn('vendor_order_id')
294     || $self->ut_textn('vendor_qual_id')
295     || $self->ut_alphan('vendor_order_type')
296     || $self->ut_alphan('vendor_order_status')
297     || $self->ut_textn('first')
298     || $self->ut_textn('last')
299     || $self->ut_textn('company')
300     || $self->ut_numbern('phonenum')
301     || $self->ut_numbern('gateway_access_number')
302     || $self->ut_alphasn('loop_type')
303     || $self->ut_textn('local_voice_provider')
304     || $self->ut_textn('circuitnum')
305     || $self->ut_textn('rate_band')
306     || $self->ut_numbern('vpi')
307     || $self->ut_numbern('vci')
308     || $self->ut_alphan('isp_chg')
309     || $self->ut_textn('isp_prev')
310     || $self->ut_textn('username')
311     || $self->ut_textn('password')
312     || $self->ut_textn('staticips')
313     || $self->ut_enum('monitored',    [ '', 'Y' ])
314     || $self->ut_numbern('last_pull')
315   ;
316   return $error if $error;
317
318   $self->gateway_access_number('')
319     if $self->phonenum && $self->phonenum eq $self->gateway_access_number;
320
321   $self->SUPER::check;
322 }
323
324 =item gateway_access_or_phonenum
325
326 =cut
327
328 sub gateway_access_or_phonenum {
329   my $self = shift;
330   $self->gateway_access_number || $self->phonenum;
331 }
332
333 =item dsl_device
334
335 Returns the MAC addresses associated with this DSL service, as FS::dsl_device
336 objects.
337
338 =cut
339
340 sub dsl_device {
341   my $self = shift;
342   qsearch('dsl_device', { 'svcnum' => $self->svcnum });
343 }
344
345 sub predelete_hook_first {
346     my $self = shift;
347     my @exports = $self->part_svc->part_export_dsl_pull;
348     return 'More than one DSL-pulling export attached' if scalar(@exports) > 1;
349     if ( scalar(@exports) == 1 ) {
350         my $export = $exports[0];
351         return $export->dsl_pull($self);
352     }
353     '';
354 }
355
356 sub predelete_hook {
357     my $self = shift;
358     my @notes = $self->notes;
359     foreach my $note ( @notes ) {
360         my $error = $note->delete;
361         return $error if $error;
362     }
363     '';
364 }
365
366 # password_history compatibility
367
368 sub _password {
369   my $self = shift;
370   $self->get('password');
371 }
372
373 sub _password_encoding { 'plain'; }
374
375 =back
376
377 =head1 SEE ALSO
378
379 L<FS::svc_Common>, edit/part_svc.cgi from an installed web interface,
380 export.html from the base documentation, L<FS::Record>, L<FS::Conf>,
381 L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>, L<FS::queue>,
382 L<freeside-queued>, schema.html from the base documentation.
383
384 =cut
385
386 1;
387