1 package FS::svc_Common;
4 use vars qw( @ISA $noexport_hack $DEBUG );
5 use FS::Record qw( qsearch qsearchs fields dbh );
10 @ISA = qw( FS::Record );
17 FS::svc_Common - Object method for all svc_ records
23 @ISA = qw( FS::svc_Common );
27 FS::svc_Common is intended as a base class for table-specific classes to
28 inherit from, i.e. FS::svc_acct. FS::svc_Common inherits from FS::Record.
38 # This restricts the fields based on part_svc_column and the svcpart of
39 # the service. There are four possible cases:
40 # 1. svcpart passed as part of the svc_x hash.
41 # 2. svcpart fetched via cust_svc based on svcnum.
42 # 3. No svcnum or svcpart. In this case, return ALL the fields with
43 # dbtable eq $self->table.
44 # 4. Called via "fields('svc_acct')" or something similar. In this case
45 # there is no $self object.
49 my @vfields = $self->SUPER::virtual_fields;
51 return @vfields unless (ref $self); # Case 4
53 if ($self->svcpart) { # Case 1
54 $svcpart = $self->svcpart;
55 } elsif ( $self->svcnum
56 && qsearchs('cust_svc',{'svcnum'=>$self->svcnum} )
58 $svcpart = $self->cust_svc->svcpart;
63 if ($svcpart) { #Cases 1 and 2
64 my %flags = map { $_->columnname, $_->columnflag } (
65 qsearch ('part_svc_column', { svcpart => $svcpart } )
67 return grep { not ($flags{$_} eq 'X') } @vfields;
76 Checks the validity of fields in this record.
78 At present, this does nothing but call FS::Record::check (which, in turn,
79 does nothing but run virtual field checks).
88 =item insert [ , OPTION => VALUE ... ]
90 Adds this record to the database. If there is an error, returns the error,
91 otherwise returns false.
93 The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
94 defined. An FS::cust_svc record will be created and inserted.
96 Currently available options are: I<jobnums>, I<child_objects> and
99 If I<jobnum> is set to an array reference, the jobnums of any export jobs will
100 be added to the referenced array.
102 If I<child_objects> is set to an array reference of FS::tablename objects (for
103 example, FS::acct_snarf objects), they will have their svcnum fieldsset and
104 will be inserted after this record, but before any exports are run.
106 If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
107 jobnums), all provisioning jobs will have a dependancy on the supplied
108 jobnum(s) (they will not run until the specific job(s) complete(s)).
115 warn "FS::svc_Common::insert called with options ".
116 join(', ', map { "$_: $options{$_}" } keys %options ). "\n"
120 local $FS::queue::jobnums = \@jobnums;
121 warn "FS::svc_Common::insert: set \$FS::queue::jobnums to $FS::queue::jobnums"
123 my $objects = $options{'child_objects'} || [];
124 my $depend_jobnums = $options{'depend_jobnum'} || [];
125 $depend_jobnums = [ $depend_jobnums ] unless ref($depend_jobnums);
128 local $SIG{HUP} = 'IGNORE';
129 local $SIG{INT} = 'IGNORE';
130 local $SIG{QUIT} = 'IGNORE';
131 local $SIG{TERM} = 'IGNORE';
132 local $SIG{TSTP} = 'IGNORE';
133 local $SIG{PIPE} = 'IGNORE';
135 my $oldAutoCommit = $FS::UID::AutoCommit;
136 local $FS::UID::AutoCommit = 0;
139 $error = $self->check;
140 return $error if $error;
142 my $svcnum = $self->svcnum;
143 my $cust_svc = $svcnum ? qsearchs('cust_svc',{'svcnum'=>$self->svcnum}) : '';
144 #unless ( $svcnum ) {
145 if ( !$svcnum or !$cust_svc ) {
146 $cust_svc = new FS::cust_svc ( {
147 #hua?# 'svcnum' => $svcnum,
148 'svcnum' => $self->svcnum,
149 'pkgnum' => $self->pkgnum,
150 'svcpart' => $self->svcpart,
152 $error = $cust_svc->insert;
154 $dbh->rollback if $oldAutoCommit;
157 $svcnum = $self->svcnum($cust_svc->svcnum);
159 #$cust_svc = qsearchs('cust_svc',{'svcnum'=>$self->svcnum});
160 unless ( $cust_svc ) {
161 $dbh->rollback if $oldAutoCommit;
162 return "no cust_svc record found for svcnum ". $self->svcnum;
164 $self->pkgnum($cust_svc->pkgnum);
165 $self->svcpart($cust_svc->svcpart);
168 $error = $self->SUPER::insert;
170 $dbh->rollback if $oldAutoCommit;
174 foreach my $object ( @$objects ) {
175 $object->svcnum($self->svcnum);
176 $error = $object->insert;
178 $dbh->rollback if $oldAutoCommit;
184 unless ( $noexport_hack ) {
186 warn "FS::svc_Common::insert: \$FS::queue::jobnums is $FS::queue::jobnums"
189 foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
190 my $error = $part_export->export_insert($self);
192 $dbh->rollback if $oldAutoCommit;
193 return "exporting to ". $part_export->exporttype.
194 " (transaction rolled back): $error";
198 foreach my $depend_jobnum ( @$depend_jobnums ) {
199 warn "inserting dependancies on supplied job $depend_jobnum\n"
201 foreach my $jobnum ( @jobnums ) {
202 my $queue = qsearchs('queue', { 'jobnum' => $jobnum } );
203 warn "inserting dependancy for job $jobnum on $depend_jobnum\n"
205 my $error = $queue->depend_insert($depend_jobnum);
207 $dbh->rollback if $oldAutoCommit;
208 return "error queuing job dependancy: $error";
215 if ( exists $options{'jobnums'} ) {
216 push @{ $options{'jobnums'} }, @jobnums;
219 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
226 Deletes this account from the database. If there is an error, returns the
227 error, otherwise returns false.
229 The corresponding FS::cust_svc record will be deleted as well.
237 local $SIG{HUP} = 'IGNORE';
238 local $SIG{INT} = 'IGNORE';
239 local $SIG{QUIT} = 'IGNORE';
240 local $SIG{TERM} = 'IGNORE';
241 local $SIG{TSTP} = 'IGNORE';
242 local $SIG{PIPE} = 'IGNORE';
244 my $svcnum = $self->svcnum;
246 my $oldAutoCommit = $FS::UID::AutoCommit;
247 local $FS::UID::AutoCommit = 0;
250 $error = $self->SUPER::delete;
251 return $error if $error;
254 unless ( $noexport_hack ) {
255 foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
256 my $error = $part_export->export_delete($self);
258 $dbh->rollback if $oldAutoCommit;
259 return "exporting to ". $part_export->exporttype.
260 " (transaction rolled back): $error";
265 return $error if $error;
267 my $cust_svc = $self->cust_svc;
268 $error = $cust_svc->delete;
269 return $error if $error;
271 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
276 =item replace OLD_RECORD
278 Replaces OLD_RECORD with this one. If there is an error, returns the error,
279 otherwise returns false.
284 my ($new, $old) = (shift, shift);
286 local $SIG{HUP} = 'IGNORE';
287 local $SIG{INT} = 'IGNORE';
288 local $SIG{QUIT} = 'IGNORE';
289 local $SIG{TERM} = 'IGNORE';
290 local $SIG{TSTP} = 'IGNORE';
291 local $SIG{PIPE} = 'IGNORE';
293 my $oldAutoCommit = $FS::UID::AutoCommit;
294 local $FS::UID::AutoCommit = 0;
297 my $error = $new->SUPER::replace($old);
299 $dbh->rollback if $oldAutoCommit;
304 unless ( $noexport_hack ) {
306 #not quite false laziness, but same pattern as FS::svc_acct::replace and
307 #FS::part_export::sqlradius::_export_replace. List::Compare or something
308 #would be useful but too much of a pain in the ass to deploy
310 my @old_part_export = $old->cust_svc->part_svc->part_export;
311 my %old_exportnum = map { $_->exportnum => 1 } @old_part_export;
312 my @new_part_export =
314 ? qsearchs('part_svc', { svcpart=>$new->svcpart } )->part_export
315 : $new->cust_svc->part_svc->part_export;
316 my %new_exportnum = map { $_->exportnum => 1 } @new_part_export;
318 foreach my $delete_part_export (
319 grep { ! $new_exportnum{$_->exportnum} } @old_part_export
321 my $error = $delete_part_export->export_delete($old);
323 $dbh->rollback if $oldAutoCommit;
324 return "error deleting, export to ". $delete_part_export->exporttype.
325 " (transaction rolled back): $error";
329 foreach my $replace_part_export (
330 grep { $old_exportnum{$_->exportnum} } @new_part_export
332 my $error = $replace_part_export->export_replace($new,$old);
334 $dbh->rollback if $oldAutoCommit;
335 return "error exporting to ". $replace_part_export->exporttype.
336 " (transaction rolled back): $error";
340 foreach my $insert_part_export (
341 grep { ! $old_exportnum{$_->exportnum} } @new_part_export
343 my $error = $insert_part_export->export_insert($new);
345 $dbh->rollback if $oldAutoCommit;
346 return "error inserting export to ". $insert_part_export->exporttype.
347 " (transaction rolled back): $error";
353 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
360 Sets any fixed fields for this service (see L<FS::part_svc>). If there is an
361 error, returns the error, otherwise returns the FS::part_svc object (use ref()
362 to test the return). Usually called by the check method.
373 Sets all fields to their defaults (see L<FS::part_svc>), overriding their
374 current values. If there is an error, returns the error, otherwise returns
375 the FS::part_svc object (use ref() to test the return).
391 $self->ut_numbern('svcnum')
393 return $error if $error;
397 if ( $self->get('svcpart') ) {
398 $svcpart = $self->get('svcpart');
399 } elsif ( $self->svcnum && qsearchs('cust_svc', {'svcnum'=>$self->svcnum}) ) {
400 my $cust_svc = $self->cust_svc;
401 return "Unknown svcnum" unless $cust_svc;
402 $svcpart = $cust_svc->svcpart;
404 my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } );
405 return "Unkonwn svcpart" unless $part_svc;
407 #set default/fixed/whatever fields from part_svc
408 my $table = $self->table;
409 foreach my $field ( grep { $_ ne 'svcnum' } $self->fields ) {
410 my $part_svc_column = $part_svc->part_svc_column($field);
411 if ( $part_svc_column->columnflag eq $x ) {
412 $self->setfield( $field, $part_svc_column->columnvalue );
422 Returns the cust_svc record associated with this svc_ record, as a FS::cust_svc
423 object (see L<FS::cust_svc>).
429 qsearchs('cust_svc', { 'svcnum' => $self->svcnum } );
434 Runs export_suspend callbacks.
441 local $SIG{HUP} = 'IGNORE';
442 local $SIG{INT} = 'IGNORE';
443 local $SIG{QUIT} = 'IGNORE';
444 local $SIG{TERM} = 'IGNORE';
445 local $SIG{TSTP} = 'IGNORE';
446 local $SIG{PIPE} = 'IGNORE';
448 my $oldAutoCommit = $FS::UID::AutoCommit;
449 local $FS::UID::AutoCommit = 0;
453 unless ( $noexport_hack ) {
454 foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
455 my $error = $part_export->export_suspend($self);
457 $dbh->rollback if $oldAutoCommit;
458 return "error exporting to ". $part_export->exporttype.
459 " (transaction rolled back): $error";
464 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
471 Runs export_unsuspend callbacks.
478 local $SIG{HUP} = 'IGNORE';
479 local $SIG{INT} = 'IGNORE';
480 local $SIG{QUIT} = 'IGNORE';
481 local $SIG{TERM} = 'IGNORE';
482 local $SIG{TSTP} = 'IGNORE';
483 local $SIG{PIPE} = 'IGNORE';
485 my $oldAutoCommit = $FS::UID::AutoCommit;
486 local $FS::UID::AutoCommit = 0;
490 unless ( $noexport_hack ) {
491 foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
492 my $error = $part_export->export_unsuspend($self);
494 $dbh->rollback if $oldAutoCommit;
495 return "error exporting to ". $part_export->exporttype.
496 " (transaction rolled back): $error";
501 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
508 Stub - returns false (no error) so derived classes don't need to define these
509 methods. Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
515 =item clone_suspended
517 Constructor used by FS::part_export::_export_suspend fallback. Stub returning
518 same object for svc_ classes which don't implement a suspension fallback
519 (everything except svc_acct at the moment). Document better.
523 sub clone_suspended {
527 =item clone_kludge_unsuspend
529 Constructor used by FS::part_export::_export_unsuspend fallback. Stub returning
530 same object for svc_ classes which don't implement a suspension fallback
531 (everything except svc_acct at the moment). Document better.
535 sub clone_kludge_unsuspend {
543 The setfixed method return value.
547 L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>, schema.html
548 from the base documentation.