3a9c7e82d8e3f52c6726ff76d2ef6a0577e921a4
[freeside.git] / FS / FS / TicketSystem / RT_External.pm
1 package FS::TicketSystem::RT_External;
2
3 use strict;
4 use vars qw( $DEBUG $me $conf $dbh $default_queueid $external_url
5              $priority_reverse
6              $priority_field $priority_field_queue $field
7            );
8 use URI::Escape;
9 use FS::UID qw(dbh);
10 use FS::Record qw(qsearchs);
11 use FS::cust_main;
12
13 $me = '[FS::TicketSystem::RT_External]';
14 $DEBUG = 0;
15
16 FS::UID->install_callback( sub { 
17   $conf = new FS::Conf;
18   $default_queueid = $conf->config('ticket_system-default_queueid');
19   $priority_reverse = $conf->exists('ticket_system-priority_reverse');
20   $priority_field =
21     $conf->config('ticket_system-custom_priority_field');
22   if ( $priority_field ) {
23     $priority_field_queue =
24       $conf->config('ticket_system-custom_priority_field_queue');
25
26     $field = $priority_field_queue
27                   ? $priority_field_queue. '.%7B'. $priority_field. '%7D'
28                   : $priority_field;
29   } else {
30     $priority_field_queue = '';
31     $field = '';
32   }
33
34   $external_url = '';
35   $dbh = dbh;
36   if ($conf->config('ticket_system') eq 'RT_External') {
37     my ($datasrc, $user, $pass) = $conf->config('ticket_system-rt_external_datasrc');
38     $dbh = DBI->connect($datasrc, $user, $pass, { 'ChopBlanks' => 1 })
39       or die "RT_External DBI->connect error: $DBI::errstr\n";
40
41     $external_url = $conf->config('ticket_system-rt_external_url');
42   }
43
44   #kludge... should *use* the id... but good enough for now
45   if ( $priority_field_queue =~ /^(\d+)$/ ) {
46     my $id = $1;
47     my $sql = 'SELECT Name FROM Queues WHERE Id = ?';
48     my $sth = $dbh->prepare($sql) or die $dbh->errstr. " preparing $sql";
49     $sth->execute($id)            or die $sth->errstr. " executing $sql";
50
51     $priority_field_queue = $sth->fetchrow_arrayref->[0];
52
53   }
54
55 } );
56
57 sub num_customer_tickets {
58   my( $self, $custnum, $priority ) = @_;
59
60   my( $from_sql, @param) = $self->_from_customer( $custnum, $priority );
61
62   my $sql = "SELECT COUNT(*) $from_sql";
63   warn "$me $sql (@param)" if $DEBUG;
64   my $sth = $dbh->prepare($sql) or die $dbh->errstr. " preparing $sql";
65   $sth->execute(@param)         or die $sth->errstr. " executing $sql";
66
67   $sth->fetchrow_arrayref->[0];
68
69 }
70
71 sub customer_tickets {
72   my( $self, $custnum, $limit, $priority ) = @_;
73   $limit ||= 0;
74
75   my( $from_sql, @param) = $self->_from_customer( $custnum, $priority );
76   my $sql = "
77     SELECT Tickets.*,
78            Queues.Name AS Queue,
79            Users.Name  AS Owner,
80            position(Tickets.Status in 'newopenstalledresolvedrejecteddeleted')
81              AS svalue
82            ". ( length($priority) ? ", ObjectCustomFieldValues.Content" : '' )."
83       $from_sql
84       ORDER BY svalue,
85                Priority ". ( $priority_reverse ? 'ASC' : 'DESC' ). ",
86                id DESC
87       LIMIT $limit
88   ";
89   warn "$me $sql (@param)" if $DEBUG;
90   my $sth = $dbh->prepare($sql) or die $dbh->errstr. "preparing $sql";
91   $sth->execute(@param)         or die $sth->errstr. "executing $sql";
92
93   #munge column names???  #httemplate/view/cust_main/tickets.html has column
94   #names that might not make sense now...
95   $sth->fetchall_arrayref({});
96
97 }
98
99 sub _from_customer {
100   my( $self, $custnum, $priority ) = @_;
101
102   my @param = ();
103   my $join = '';
104   my $where = '';
105   if ( defined($priority) ) {
106
107     my $queue_sql = " ObjectCustomFields.ObjectId = ( SELECT id FROM Queues
108                                                        WHERE Queues.Name = ? )
109                       OR ( ? = '' AND ObjectCustomFields.ObjectId = 0 )";
110
111     my $customfield_sql =
112       "customfield = ( 
113         SELECT CustomFields.Id FROM CustomFields
114                   JOIN ObjectCustomFields
115                     ON ( CustomFields.id = ObjectCustomFields.CustomField )
116          WHERE LookupType = 'RT::Queue-RT::Ticket'
117            AND Name = ?
118            AND ( $queue_sql )
119        )";
120
121     push @param, $priority_field,
122                  $priority_field_queue,
123                  $priority_field_queue;
124
125     if ( length($priority) ) {
126       #$where = "    
127       #  and ? = ( select content from TicketCustomFieldValues
128       #             where ticket = tickets.id
129       #               and customfield = ( select id from customfields
130       #                                    where name = ?
131       #                                      and ( $queue_sql )
132       #                                 )
133       #          )
134       #";
135       unshift @param, $priority;
136
137       $join = "JOIN ObjectCustomFieldValues
138                  ON ( Tickets.id = ObjectCustomFieldValues.ObjectId )";
139       
140       $where = " AND Content = ?
141                  AND ObjectCustomFieldValues.Disabled != 1
142                  AND ObjectType = 'RT::Ticket'
143                  AND $customfield_sql";
144
145     } else {
146
147       $where =
148                "AND 0 = ( SELECT COUNT(*) FROM ObjectCustomFieldValues
149                            WHERE ObjectId    = Tickets.id
150                              AND ObjectType  = 'RT::Ticket'
151                              AND $customfield_sql
152                         )
153                ";
154     }
155
156   }
157
158   my $sql = "
159                     FROM Tickets
160                     JOIN Queues ON ( Tickets.Queue = Queues.id       )
161                     JOIN Links  ON ( Tickets.id    = Links.LocalBase )
162                     JOIN Users  ON ( Tickets.Owner = Users.id        )
163                     $join 
164        WHERE ( ". join(' OR ', map "Status = '$_'", $self->statuses ). " )
165          AND Target = 'freeside://freeside/cust_main/$custnum'
166          $where
167   ";
168
169   ( $sql, @param );
170
171 }
172
173 sub statuses {
174   #my $self = shift;
175   my @statuses = grep { ! /^\s*$/ } $conf->config('cust_main-ticket_statuses');
176   @statuses = (qw( new open stalled )) unless scalar(@statuses);
177   @statuses;
178 }
179
180 sub href_customer_tickets {
181   my( $self, $custnum ) = ( shift, shift );
182   my( $priority, @statuses);
183   if ( ref($_[0]) ) {
184     my $opt = shift;
185     $priority = $opt->{'priority'};
186     @statuses = $opt->{'statuses'} ? @{$opt->{'statuses'}} : $self->statuses;
187   } else {
188     $priority = shift;
189     @statuses = $self->statuses;
190   }
191
192   #my $href = $self->baseurl;
193
194   #i snarfed this from an RT bookmarked search, then unescaped (some of) it with
195   #perl -npe 's/%([0-9A-F]{2})/pack('C', hex($1))/eg;'
196
197   #$href .= 
198   my $href = 
199     "Search/Results.html?Order=ASC&".
200     "Query= MemberOf = 'freeside://freeside/cust_main/$custnum' ".
201     #" AND ( Status = 'open'  OR Status = 'new'  OR Status = 'stalled' )"
202     " AND ( ". join(' OR ', map "Status = '$_'", @statuses ). " ) "
203   ;
204
205   if ( defined($priority) && $field && $priority_field_queue ) {
206     $href .= " AND Queue = '$priority_field_queue' ";
207   }
208   if ( defined($priority) && $field ) {
209     $href .= " AND 'CF.$field' ";
210     if ( $priority ) {
211       $href .= "= '$priority' ";
212     } else {
213       $href .= "IS 'NULL' "; #this is "RTQL", not SQL
214     }
215   }
216
217   #$href = 
218   uri_escape($href);
219   #eventually should unescape all of it...
220
221   $href .= '&Rows=100'.
222            '&OrderBy=id&Page=1'.
223            '&Format=%27%20%20%20%3Cb%3E%3Ca%20href%3D%22'.
224            $self->baseurl.
225            'Ticket%2FDisplay.html%3Fid%3D__id__%22%3E__id__%3C%2Fa%3E%3C%2Fb%3E%2FTITLE%3A%23%27%2C%20%0A%27%3Cb%3E%3Ca%20href%3D%22'.
226            $self->baseurl.
227            'Ticket%2FDisplay.html%3Fid%3D__id__%22%3E__Subject__%3C%2Fa%3E%3C%2Fb%3E%2FTITLE%3ASubject%27%2C%20%0A%27__Status__%27%2C%20';
228
229   if ( defined($priority) && $field ) {
230     $href .= '%0A%27__CustomField.'. $field. '__%2FTITLE%3ASeverity%27%2C%20';
231   }
232
233   $href .= '%0A%27__QueueName__%27%2C%20%0A%27__OwnerName__%27%2C%20%0A%27__Priority__%27%2C%20%0A%27__NEWLINE__%27%2C%20%0A%27%27%2C%20%0A%27%3Csmall%3E__Requestors__%3C%2Fsmall%3E%27%2C%20%0A%27%3Csmall%3E__CreatedRelative__%3C%2Fsmall%3E%27%2C';
234
235   if ( defined($priority) && $field ) {
236     $href .=   '%20%0A%27__-__%27%2C';
237   }
238
239   $href .= '%20%0A%27%3Csmall%3E__ToldRelative__%3C%2Fsmall%3E%27%2C%20%0A%27%3Csmall%3E__LastUpdatedRelative__%3C%2Fsmall%3E%27%2C%20%0A%27%3Csmall%3E__TimeLeft__%3C%2Fsmall%3E%27';
240
241   #$href =
242   #uri_escape($href);
243
244   $self->baseurl. $href;
245
246 }
247
248 sub href_new_ticket {
249   my( $self, $custnum_or_cust_main, $requestors ) = @_;
250
251   my( $custnum, $cust_main );
252   if ( ref($custnum_or_cust_main) ) {
253     $cust_main = $custnum_or_cust_main;
254     $custnum = $cust_main->custnum;
255   } else {
256     $custnum = $custnum_or_cust_main;
257     $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
258   }
259   my $queueid = $cust_main->agent->ticketing_queueid || $default_queueid;
260
261   $self->baseurl.
262   'Ticket/Create.html?'.
263     "Queue=$queueid".
264     "&new-MemberOf=freeside://freeside/cust_main/$custnum".
265     ( $requestors ? '&Requestors='. uri_escape($requestors) : '' )
266     ;
267 }
268
269 sub href_ticket {
270   my($self, $ticketnum) = @_;
271   $self->baseurl. 'Ticket/Display.html?id='.$ticketnum;
272 }
273
274 sub queues {
275   my($self) = @_;
276
277   my $sql = "SELECT id, Name FROM Queues WHERE Disabled = 0";
278   my $sth = $dbh->prepare($sql) or die $dbh->errstr. " preparing $sql";
279   $sth->execute()               or die $sth->errstr. " executing $sql";
280
281   map { $_->[0] => $_->[1] } @{ $sth->fetchall_arrayref([]) };
282
283 }
284
285 sub queue {
286   my($self, $queueid) = @_;
287
288   return '' unless $queueid;
289
290   my $sql = "SELECT Name FROM Queues WHERE id = ?";
291   my $sth = $dbh->prepare($sql) or die $dbh->errstr. " preparing $sql";
292   $sth->execute($queueid)       or die $sth->errstr. " executing $sql";
293
294   my $rows = $sth->fetchrow_arrayref;
295   $rows ? $rows->[0] : '';
296
297 }
298
299 sub baseurl {
300   #my $self = shift;
301   $external_url. '/';
302 }
303
304 sub _retrieve_single_value {
305   my( $self, $sql ) = @_;
306
307   warn "$me $sql" if $DEBUG;
308   my $sth = $dbh->prepare($sql) or die $dbh->errstr. "preparing $sql";
309   $sth->execute                 or die $sth->errstr. "executing $sql";
310
311   my $arrayref = $sth->fetchrow_arrayref;
312   $arrayref ? $arrayref->[0] : $arrayref;
313 }
314
315 sub transaction_creator {
316   my( $self, $transaction_id ) = @_;
317
318   my $sql = "SELECT Name FROM Transactions JOIN Users ON ".
319             "Transactions.Creator=Users.id WHERE Transactions.id = ".
320             $transaction_id;
321
322   $self->_retrieve_single_value($sql);
323 }
324
325 sub transaction_ticketid {
326   my( $self, $transaction_id ) = @_;
327
328   my $sql = "SELECT ObjectId FROM Transactions WHERE Transactions.id = ".
329             $transaction_id;
330   
331   $self->_retrieve_single_value($sql);
332 }
333
334 sub transaction_subject {
335   my( $self, $transaction_id ) = @_;
336
337   my $sql = "SELECT Subject FROM Transactions JOIN Tickets ON ObjectId=".
338             "Tickets.id WHERE Transactions.id = ".  $transaction_id;
339   
340   $self->_retrieve_single_value($sql);
341 }
342
343 sub transaction_status {
344   my( $self, $transaction_id ) = @_;
345
346   my $sql = "SELECT Status FROM Transactions JOIN Tickets ON ObjectId=".
347             "Tickets.id WHERE Transactions.id = ".  $transaction_id;
348   
349   $self->_retrieve_single_value($sql);
350 }
351
352 1;
353