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 ) {
305 foreach my $part_export ( $new->cust_svc->part_svc->part_export ) {
306 my $error = $part_export->export_replace($new,$old);
308 $dbh->rollback if $oldAutoCommit;
309 return "error exporting to ". $part_export->exporttype.
310 " (transaction rolled back): $error";
315 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
322 Sets any fixed fields for this service (see L<FS::part_svc>). If there is an
323 error, returns the error, otherwise returns the FS::part_svc object (use ref()
324 to test the return). Usually called by the check method.
335 Sets all fields to their defaults (see L<FS::part_svc>), overriding their
336 current values. If there is an error, returns the error, otherwise returns
337 the FS::part_svc object (use ref() to test the return).
353 $self->ut_numbern('svcnum')
355 return $error if $error;
359 if ( $self->svcnum && qsearchs('cust_svc', {'svcnum'=>$self->svcnum}) ) {
360 my $cust_svc = $self->cust_svc;
361 return "Unknown svcnum" unless $cust_svc;
362 $svcpart = $cust_svc->svcpart;
364 $svcpart = $self->getfield('svcpart');
366 my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } );
367 return "Unkonwn svcpart" unless $part_svc;
369 #set default/fixed/whatever fields from part_svc
370 my $table = $self->table;
371 foreach my $field ( grep { $_ ne 'svcnum' } $self->fields ) {
372 my $part_svc_column = $part_svc->part_svc_column($field);
373 if ( $part_svc_column->columnflag eq $x ) {
374 $self->setfield( $field, $part_svc_column->columnvalue );
384 Returns the cust_svc record associated with this svc_ record, as a FS::cust_svc
385 object (see L<FS::cust_svc>).
391 qsearchs('cust_svc', { 'svcnum' => $self->svcnum } );
396 Runs export_suspend callbacks.
403 local $SIG{HUP} = 'IGNORE';
404 local $SIG{INT} = 'IGNORE';
405 local $SIG{QUIT} = 'IGNORE';
406 local $SIG{TERM} = 'IGNORE';
407 local $SIG{TSTP} = 'IGNORE';
408 local $SIG{PIPE} = 'IGNORE';
410 my $oldAutoCommit = $FS::UID::AutoCommit;
411 local $FS::UID::AutoCommit = 0;
415 unless ( $noexport_hack ) {
416 foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
417 my $error = $part_export->export_suspend($self);
419 $dbh->rollback if $oldAutoCommit;
420 return "error exporting to ". $part_export->exporttype.
421 " (transaction rolled back): $error";
426 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
433 Runs export_unsuspend callbacks.
440 local $SIG{HUP} = 'IGNORE';
441 local $SIG{INT} = 'IGNORE';
442 local $SIG{QUIT} = 'IGNORE';
443 local $SIG{TERM} = 'IGNORE';
444 local $SIG{TSTP} = 'IGNORE';
445 local $SIG{PIPE} = 'IGNORE';
447 my $oldAutoCommit = $FS::UID::AutoCommit;
448 local $FS::UID::AutoCommit = 0;
452 unless ( $noexport_hack ) {
453 foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
454 my $error = $part_export->export_unsuspend($self);
456 $dbh->rollback if $oldAutoCommit;
457 return "error exporting to ". $part_export->exporttype.
458 " (transaction rolled back): $error";
463 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
470 Stub - returns false (no error) so derived classes don't need to define these
471 methods. Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
477 =item clone_suspended
479 Constructor used by FS::part_export::_export_suspend fallback. Stub returning
480 same object for svc_ classes which don't implement a suspension fallback
481 (everything except svc_acct at the moment). Document better.
485 sub clone_suspended {
489 =item clone_kludge_unsuspend
491 Constructor used by FS::part_export::_export_unsuspend fallback. Stub returning
492 same object for svc_ classes which don't implement a suspension fallback
493 (everything except svc_acct at the moment). Document better.
497 sub clone_kludge_unsuspend {
505 The setfixed method return value.
509 L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>, schema.html
510 from the base documentation.