4b880a23c2dfa8cdf40dc349fb3b170c074ead4d
[freeside.git] / FS / FS / queue.pm
1 package FS::queue;
2
3 use strict;
4 use vars qw( @ISA @EXPORT_OK $conf );
5 use Exporter;
6 use FS::UID;
7 use FS::Conf;
8 use FS::Record qw( qsearch qsearchs dbh );
9 #use FS::queue;
10 use FS::queue_arg;
11 use FS::cust_svc;
12
13 @ISA = qw(FS::Record);
14 @EXPORT_OK = qw( joblisting );
15
16 $FS::UID::callback{'FS::queue'} = sub {
17   $conf = new FS::Conf;
18 };
19
20 =head1 NAME
21
22 FS::queue - Object methods for queue records
23
24 =head1 SYNOPSIS
25
26   use FS::queue;
27
28   $record = new FS::queue \%hash;
29   $record = new FS::queue { 'column' => 'value' };
30
31   $error = $record->insert;
32
33   $error = $new_record->replace($old_record);
34
35   $error = $record->delete;
36
37   $error = $record->check;
38
39 =head1 DESCRIPTION
40
41 An FS::queue object represents an queued job.  FS::queue inherits from
42 FS::Record.  The following fields are currently supported:
43
44 =over 4
45
46 =item jobnum - primary key
47
48 =item job - fully-qualified subroutine name
49
50 =item status - job status
51
52 =item statustext - freeform text status message
53
54 =item _date - UNIX timestamp
55
56 =item svcnum - optional link to service (see L<FS::cust_svc>)
57
58 =back
59
60 =head1 METHODS
61
62 =over 4
63
64 =item new HASHREF
65
66 Creates a new job.  To add the example to the database, see L<"insert">.
67
68 Note that this stores the hash reference, not a distinct copy of the hash it
69 points to.  You can ask the object for a copy with the I<hash> method.
70
71 =cut
72
73 # the new method can be inherited from FS::Record, if a table method is defined
74
75 sub table { 'queue'; }
76
77 =item insert [ ARGUMENT, ARGUMENT... ]
78
79 Adds this record to the database.  If there is an error, returns the error,
80 otherwise returns false.
81
82 If any arguments are supplied, a queue_arg record for each argument is also
83 created (see L<FS::queue_arg>).
84
85 =cut
86
87 #false laziness w/part_export.pm
88 sub insert {
89   my $self = shift;
90
91   local $SIG{HUP} = 'IGNORE';
92   local $SIG{INT} = 'IGNORE';
93   local $SIG{QUIT} = 'IGNORE';
94   local $SIG{TERM} = 'IGNORE';
95   local $SIG{TSTP} = 'IGNORE';
96   local $SIG{PIPE} = 'IGNORE';
97
98   my $oldAutoCommit = $FS::UID::AutoCommit;
99   local $FS::UID::AutoCommit = 0;
100   my $dbh = dbh;
101
102   my $error = $self->SUPER::insert;
103   if ( $error ) {
104     $dbh->rollback if $oldAutoCommit;
105     return $error;
106   }
107
108   foreach my $arg ( @_ ) {
109     my $queue_arg = new FS::queue_arg ( {
110       'jobnum' => $self->jobnum,
111       'arg'    => $arg,
112     } );
113     $error = $queue_arg->insert;
114     if ( $error ) {
115       $dbh->rollback if $oldAutoCommit;
116       return $error;
117     }
118   }
119
120   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
121
122   '';
123
124 }
125
126 =item delete
127
128 Delete this record from the database.  Any corresponding queue_arg records are
129 deleted as well
130
131 =cut
132
133 sub delete {
134   my $self = shift;
135
136   local $SIG{HUP} = 'IGNORE';
137   local $SIG{INT} = 'IGNORE';
138   local $SIG{QUIT} = 'IGNORE';
139   local $SIG{TERM} = 'IGNORE';
140   local $SIG{TSTP} = 'IGNORE';
141   local $SIG{PIPE} = 'IGNORE';
142
143   my $oldAutoCommit = $FS::UID::AutoCommit;
144   local $FS::UID::AutoCommit = 0;
145   my $dbh = dbh;
146
147   my @args = qsearch( 'queue_arg', { 'jobnum' => $self->jobnum } );
148
149   my $error = $self->SUPER::delete;
150   if ( $error ) {
151     $dbh->rollback if $oldAutoCommit;
152     return $error;
153   }
154
155   foreach my $arg ( @args ) {
156     $error = $arg->delete;
157     if ( $error ) {
158       $dbh->rollback if $oldAutoCommit;
159       return $error;
160     }
161   }
162
163   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
164
165   '';
166
167 }
168
169 =item replace OLD_RECORD
170
171 Replaces the OLD_RECORD with this one in the database.  If there is an error,
172 returns the error, otherwise returns false.
173
174 =cut
175
176 # the replace method can be inherited from FS::Record
177
178 =item check
179
180 Checks all fields to make sure this is a valid job.  If there is
181 an error, returns the error, otherwise returns false.  Called by the insert
182 and replace methods.
183
184 =cut
185
186 sub check {
187   my $self = shift;
188   my $error =
189     $self->ut_numbern('jobnum')
190     || $self->ut_anything('job')
191     || $self->ut_numbern('_date')
192     || $self->ut_enum('status',['', qw( new locked failed )])
193     || $self->ut_textn('statustext')
194     || $self->ut_numbern('svcnum')
195   ;
196   return $error if $error;
197
198   $error = $self->ut_foreign_keyn('svcnum', 'cust_svc', 'svcnum');
199   $self->svcnum('') if $error;
200
201   $self->status('new') unless $self->status;
202   $self->_date(time) unless $self->_date;
203
204   ''; #no error
205 }
206
207 =item args
208
209 =cut
210
211 sub args {
212   my $self = shift;
213   map $_->arg, qsearch( 'queue_arg',
214                         { 'jobnum' => $self->jobnum },
215                         '',
216                         'ORDER BY argnum'
217                       );
218 }
219
220 =item cust_svc
221
222 Returns the FS::cust_svc object associated with this job, if any.
223
224 =cut
225
226 sub cust_svc {
227   my $self = shift;
228   qsearchs('cust_svc', { 'svcnum' => $self->svcnum } );
229 }
230
231 =item joblisting HASHREF NOACTIONS
232
233 =cut
234
235 sub joblisting {
236   my($hashref, $noactions) = @_;
237
238   use Date::Format;
239   use FS::CGI;
240
241   my @queue = qsearch( 'queue', $hashref );
242   return '' unless scalar(@queue);
243
244   my $html = FS::CGI::table(). <<END;
245       <TR>
246         <TH COLSPAN=2>Job</TH>
247         <TH>Args</TH>
248         <TH>Date</TH>
249         <TH>Status</TH>
250 END
251   $html .= '<TH>Account</TH>' unless $hashref->{svcnum};
252   $html .= '</TR>';
253
254   my $dangerous = $conf->exists('queue_dangerous_controls');
255
256   my $p = FS::CGI::popurl(2);
257   foreach my $queue ( sort { 
258     $a->getfield('jobnum') <=> $b->getfield('jobnum')
259   } @queue ) {
260     my $queue_hashref = $queue->hashref;
261     my $jobnum = $queue->jobnum;
262
263     my $args;
264     if ( $dangerous || $queue->job !~ /^FS::part_export::/ || !$noactions ) {
265       $args = join(' ', $queue->args);
266     } else {
267       $args = '';
268     }
269
270     my $date = time2str( "%a %b %e %T %Y", $queue->_date );
271     my $status = $queue->status;
272     $status .= ': '. $queue->statustext if $queue->statustext;
273     if ( $dangerous
274          || ( ! $noactions && $status =~ /^failed/ || $status =~ /^locked/ ) ) {
275       $status .=
276         qq! (&nbsp;<A HREF="$p/misc/queue.cgi?jobnum=$jobnum&action=new">retry</A>&nbsp;|!.
277         qq!&nbsp;<A HREF="$p/misc/queue.cgi?jobnum=$jobnum&action=del">remove</A>&nbsp;)!;
278     }
279     my $cust_svc = $queue->cust_svc;
280
281     $html .= <<END;
282       <TR>
283         <TD>$jobnum</TD>
284         <TD>$queue_hashref->{job}</TD>
285         <TD>$args</TD>
286         <TD>$date</TD>
287         <TD>$status</TD>
288 END
289
290     unless ( $hashref->{svcnum} ) {
291       my $account;
292       if ( $cust_svc ) {
293         my $table = $cust_svc->part_svc->svcdb;
294         my $label = ( $cust_svc->label )[1];
295         $account = qq!<A HREF="../view/$table.cgi?!. $queue->svcnum.
296                    qq!">$label</A>!;
297       } else {
298         $account = '';
299       }
300       $html .= "<TD>$account</TD>";
301     }
302
303     $html .= '</TR>';
304
305 }
306
307   $html .= '</TABLE>';
308
309   $html;
310
311 }
312
313 =back
314
315 =head1 VERSION
316
317 $Id: queue.pm,v 1.10 2002-03-27 07:08:08 ivan Exp $
318
319 =head1 BUGS
320
321 =head1 SEE ALSO
322
323 L<FS::Record>, schema.html from the base documentation.
324
325 =cut
326
327 1;
328