fix UI: displaying "Add" on invoice event edits
[freeside.git] / FS / FS / svc_Common.pm
1 package FS::svc_Common;
2
3 use strict;
4 use vars qw( @ISA $noexport_hack );
5 use FS::Record qw( qsearchs fields dbh );
6 use FS::cust_svc;
7 use FS::part_svc;
8 use FS::queue;
9
10 @ISA = qw( FS::Record );
11
12 =head1 NAME
13
14 FS::svc_Common - Object method for all svc_ records
15
16 =head1 SYNOPSIS
17
18 use FS::svc_Common;
19
20 @ISA = qw( FS::svc_Common );
21
22 =head1 DESCRIPTION
23
24 FS::svc_Common is intended as a base class for table-specific classes to
25 inherit from, i.e. FS::svc_acct.  FS::svc_Common inherits from FS::Record.
26
27 =head1 METHODS
28
29 =over 4
30
31 =item insert [ JOBNUM_ARRAYREF [ OBJECTS_ARRAYREF ] ]
32
33 Adds this record to the database.  If there is an error, returns the error,
34 otherwise returns false.
35
36 The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be 
37 defined.  An FS::cust_svc record will be created and inserted.
38
39 If an arrayref is passed as parameter, the B<jobnum>s of any export jobs will
40 be added to the array.
41
42 If an arrayref of FS::tablename objects (for example, FS::acct_snarf objects)
43 is passed as the optional second parameter, they will have their svcnum fields
44 set and will be inserted after this record, but before any exports are run.
45
46 =cut
47
48 sub insert {
49   my $self = shift;
50   local $FS::queue::jobnums = shift if @_;
51   my $objects = scalar(@_) ? shift : [];
52   my $error;
53
54   local $SIG{HUP} = 'IGNORE';
55   local $SIG{INT} = 'IGNORE';
56   local $SIG{QUIT} = 'IGNORE';
57   local $SIG{TERM} = 'IGNORE';
58   local $SIG{TSTP} = 'IGNORE';
59   local $SIG{PIPE} = 'IGNORE';
60
61   my $oldAutoCommit = $FS::UID::AutoCommit;
62   local $FS::UID::AutoCommit = 0;
63   my $dbh = dbh;
64
65   $error = $self->check;
66   return $error if $error;
67
68   my $svcnum = $self->svcnum;
69   my $cust_svc = $svcnum ? qsearchs('cust_svc',{'svcnum'=>$self->svcnum}) : '';
70   #unless ( $svcnum ) {
71   if ( !$svcnum or !$cust_svc ) {
72     $cust_svc = new FS::cust_svc ( {
73       #hua?# 'svcnum'  => $svcnum,
74       'svcnum'  => $self->svcnum,
75       'pkgnum'  => $self->pkgnum,
76       'svcpart' => $self->svcpart,
77     } );
78     $error = $cust_svc->insert;
79     if ( $error ) {
80       $dbh->rollback if $oldAutoCommit;
81       return $error;
82     }
83     $svcnum = $self->svcnum($cust_svc->svcnum);
84   } else {
85     #$cust_svc = qsearchs('cust_svc',{'svcnum'=>$self->svcnum});
86     unless ( $cust_svc ) {
87       $dbh->rollback if $oldAutoCommit;
88       return "no cust_svc record found for svcnum ". $self->svcnum;
89     }
90     $self->pkgnum($cust_svc->pkgnum);
91     $self->svcpart($cust_svc->svcpart);
92   }
93
94   $error = $self->SUPER::insert;
95   if ( $error ) {
96     $dbh->rollback if $oldAutoCommit;
97     return $error;
98   }
99
100   foreach my $object ( @$objects ) {
101     $object->svcnum($self->svcnum);
102     $error = $object->insert;
103     if ( $error ) {
104       $dbh->rollback if $oldAutoCommit;
105       return $error;
106     }
107   }
108
109   #new-style exports!
110   unless ( $noexport_hack ) {
111     foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
112       my $error = $part_export->export_insert($self);
113       if ( $error ) {
114         $dbh->rollback if $oldAutoCommit;
115         return "exporting to ". $part_export->exporttype.
116                " (transaction rolled back): $error";
117       }
118     }
119   }
120
121   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
122
123   '';
124 }
125
126 =item delete
127
128 Deletes this account from the database.  If there is an error, returns the
129 error, otherwise returns false.
130
131 The corresponding FS::cust_svc record will be deleted as well.
132
133 =cut
134
135 sub delete {
136   my $self = shift;
137   my $error;
138
139   local $SIG{HUP} = 'IGNORE';
140   local $SIG{INT} = 'IGNORE';
141   local $SIG{QUIT} = 'IGNORE';
142   local $SIG{TERM} = 'IGNORE';
143   local $SIG{TSTP} = 'IGNORE';
144   local $SIG{PIPE} = 'IGNORE';
145
146   my $svcnum = $self->svcnum;
147
148   my $oldAutoCommit = $FS::UID::AutoCommit;
149   local $FS::UID::AutoCommit = 0;
150   my $dbh = dbh;
151
152   $error = $self->SUPER::delete;
153   return $error if $error;
154
155   #new-style exports!
156   unless ( $noexport_hack ) {
157     foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
158       my $error = $part_export->export_delete($self);
159       if ( $error ) {
160         $dbh->rollback if $oldAutoCommit;
161         return "exporting to ". $part_export->exporttype.
162                " (transaction rolled back): $error";
163       }
164     }
165   }
166
167   return $error if $error;
168
169   my $cust_svc = $self->cust_svc;
170   $error = $cust_svc->delete;
171   return $error if $error;
172
173   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
174
175   '';
176 }
177
178 =item replace OLD_RECORD
179
180 Replaces OLD_RECORD with this one.  If there is an error, returns the error,
181 otherwise returns false.
182
183 =cut
184
185 sub replace {
186   my ($new, $old) = (shift, shift);
187
188   local $SIG{HUP} = 'IGNORE';
189   local $SIG{INT} = 'IGNORE';
190   local $SIG{QUIT} = 'IGNORE';
191   local $SIG{TERM} = 'IGNORE';
192   local $SIG{TSTP} = 'IGNORE';
193   local $SIG{PIPE} = 'IGNORE';
194
195   my $oldAutoCommit = $FS::UID::AutoCommit;
196   local $FS::UID::AutoCommit = 0;
197   my $dbh = dbh;
198
199   my $error = $new->SUPER::replace($old);
200   if ($error) {
201     $dbh->rollback if $oldAutoCommit;
202     return $error;
203   }
204
205   #new-style exports!
206   unless ( $noexport_hack ) {
207     foreach my $part_export ( $new->cust_svc->part_svc->part_export ) {
208       my $error = $part_export->export_replace($new,$old);
209       if ( $error ) {
210         $dbh->rollback if $oldAutoCommit;
211         return "error exporting to ". $part_export->exporttype.
212                " (transaction rolled back): $error";
213       }
214     }
215   }
216
217   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
218   '';
219 }
220
221
222 =item setfixed
223
224 Sets any fixed fields for this service (see L<FS::part_svc>).  If there is an
225 error, returns the error, otherwise returns the FS::part_svc object (use ref()
226 to test the return).  Usually called by the check method.
227
228 =cut
229
230 sub setfixed {
231   my $self = shift;
232   $self->setx('F');
233 }
234
235 =item setdefault
236
237 Sets all fields to their defaults (see L<FS::part_svc>), overriding their
238 current values.  If there is an error, returns the error, otherwise returns
239 the FS::part_svc object (use ref() to test the return).
240
241 =cut
242
243 sub setdefault {
244   my $self = shift;
245   $self->setx('D');
246 }
247
248 sub setx {
249   my $self = shift;
250   my $x = shift;
251
252   my $error;
253
254   $error =
255     $self->ut_numbern('svcnum')
256   ;
257   return $error if $error;
258
259   #get part_svc
260   my $svcpart;
261   if ( $self->svcnum && qsearchs('cust_svc', {'svcnum'=>$self->svcnum}) ) {
262     my $cust_svc = $self->cust_svc;
263     return "Unknown svcnum" unless $cust_svc; 
264     $svcpart = $cust_svc->svcpart;
265   } else {
266     $svcpart = $self->getfield('svcpart');
267   }
268   my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } );
269   return "Unkonwn svcpart" unless $part_svc;
270
271   #set default/fixed/whatever fields from part_svc
272   my $table = $self->table;
273   foreach my $field ( grep { $_ ne 'svcnum' } fields($table) ) {
274     my $part_svc_column = $part_svc->part_svc_column($field);
275     if ( $part_svc_column->columnflag eq $x ) {
276       $self->setfield( $field, $part_svc_column->columnvalue );
277     }
278   }
279
280  $part_svc;
281
282 }
283
284 =item cust_svc
285
286 Returns the cust_svc record associated with this svc_ record, as a FS::cust_svc
287 object (see L<FS::cust_svc>).
288
289 =cut
290
291 sub cust_svc {
292   my $self = shift;
293   qsearchs('cust_svc', { 'svcnum' => $self->svcnum } );
294 }
295
296 =item suspend
297
298 Runs export_suspend callbacks.
299
300 =cut
301
302 sub suspend {
303   my $self = shift;
304
305   local $SIG{HUP} = 'IGNORE';
306   local $SIG{INT} = 'IGNORE';
307   local $SIG{QUIT} = 'IGNORE';
308   local $SIG{TERM} = 'IGNORE';
309   local $SIG{TSTP} = 'IGNORE';
310   local $SIG{PIPE} = 'IGNORE';
311
312   my $oldAutoCommit = $FS::UID::AutoCommit;
313   local $FS::UID::AutoCommit = 0;
314   my $dbh = dbh;
315
316   #new-style exports!
317   unless ( $noexport_hack ) {
318     foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
319       my $error = $part_export->export_suspend($self);
320       if ( $error ) {
321         $dbh->rollback if $oldAutoCommit;
322         return "error exporting to ". $part_export->exporttype.
323                " (transaction rolled back): $error";
324       }
325     }
326   }
327
328   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
329   '';
330
331 }
332
333 =item unsuspend
334
335 Runs export_unsuspend callbacks.
336
337 =cut
338
339 sub unsuspend {
340   my $self = shift;
341
342   local $SIG{HUP} = 'IGNORE';
343   local $SIG{INT} = 'IGNORE';
344   local $SIG{QUIT} = 'IGNORE';
345   local $SIG{TERM} = 'IGNORE';
346   local $SIG{TSTP} = 'IGNORE';
347   local $SIG{PIPE} = 'IGNORE';
348
349   my $oldAutoCommit = $FS::UID::AutoCommit;
350   local $FS::UID::AutoCommit = 0;
351   my $dbh = dbh;
352
353   #new-style exports!
354   unless ( $noexport_hack ) {
355     foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
356       my $error = $part_export->export_unsuspend($self);
357       if ( $error ) {
358         $dbh->rollback if $oldAutoCommit;
359         return "error exporting to ". $part_export->exporttype.
360                " (transaction rolled back): $error";
361       }
362     }
363   }
364
365   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
366   '';
367
368 }
369
370 =item cancel
371
372 Stub - returns false (no error) so derived classes don't need to define these
373 methods.  Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
374
375 =cut
376
377 sub cancel { ''; }
378
379 =back
380
381 =head1 VERSION
382
383 $Id: svc_Common.pm,v 1.12.4.4 2003-11-12 12:29:55 ivan Exp $
384
385 =head1 BUGS
386
387 The setfixed method return value.
388
389 =head1 SEE ALSO
390
391 L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>, schema.html
392 from the base documentation.
393
394 =cut
395
396 1;
397