import rt 3.8.7
[freeside.git] / rt / lib / RT / Scrips_Overlay.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2
3 # COPYRIGHT:
4
5 # This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC
6 #                                          <jesse@bestpractical.com>
7
8 # (Except where explicitly superseded by other copyright notices)
9
10
11 # LICENSE:
12
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
16 # from www.gnu.org.
17
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 # General Public License for more details.
22
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28
29
30 # CONTRIBUTION SUBMISSION POLICY:
31
32 # (The following paragraph is not intended to limit the rights granted
33 # to you to modify and distribute this software under the terms of
34 # the GNU General Public License and is only of importance to you if
35 # you choose to contribute your changes and enhancements to the
36 # community by submitting them to Best Practical Solutions, LLC.)
37
38 # By intentionally submitting any modifications, corrections or
39 # derivatives to this work, or any other work intended for use with
40 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 # you are the copyright holder for those contributions and you grant
42 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
43 # royalty-free, perpetual, license to use, copy, create derivative
44 # works based on those contributions, and sublicense and distribute
45 # those contributions and any derivatives thereof.
46
47 # END BPS TAGGED BLOCK }}}
48
49 =head1 NAME
50
51   RT::Scrips - a collection of RT Scrip objects
52
53 =head1 SYNOPSIS
54
55   use RT::Scrips;
56
57 =head1 DESCRIPTION
58
59
60 =head1 METHODS
61
62
63
64 =cut
65
66
67 package RT::Scrips;
68
69 use strict;
70 no warnings qw(redefine);
71
72 # {{{ sub LimitToQueue 
73
74 =head2 LimitToQueue
75
76 Takes a queue id (numerical) as its only argument. Makes sure that 
77 Scopes it pulls out apply to this queue (or another that you've selected with
78 another call to this method
79
80 =cut
81
82 sub LimitToQueue  {
83    my $self = shift;
84   my $queue = shift;
85  
86   $self->Limit (ENTRYAGGREGATOR => 'OR',
87                 FIELD => 'Queue',
88                 VALUE => "$queue")
89       if defined $queue;
90   
91 }
92 # }}}
93
94 # {{{ sub LimitToGlobal
95
96 =head2 LimitToGlobal
97
98 Makes sure that 
99 Scopes it pulls out apply to all queues (or another that you've selected with
100 another call to this method or LimitToQueue
101
102 =cut
103
104
105 sub LimitToGlobal  {
106    my $self = shift;
107  
108   $self->Limit (ENTRYAGGREGATOR => 'OR',
109                 FIELD => 'Queue',
110                 VALUE => 0);
111   
112 }
113 # }}}
114
115 # {{{ sub NewItem 
116 sub NewItem  {
117   my $self = shift;
118   
119   return(new RT::Scrip($self->CurrentUser));
120 }
121 # }}}
122
123 # {{{ sub Next 
124
125 =head2 Next
126
127 Returns the next scrip that this user can see.
128
129 =cut
130   
131 sub Next {
132     my $self = shift;
133     
134     
135     my $Scrip = $self->SUPER::Next();
136     if ((defined($Scrip)) and (ref($Scrip))) {
137
138         if ($Scrip->CurrentUserHasRight('ShowScrips')) {
139             return($Scrip);
140         }
141         
142         #If the user doesn't have the right to show this scrip
143         else {  
144             return($self->Next());
145         }
146     }
147     #if there never was any scrip
148     else {
149         return(undef);
150     }   
151     
152 }
153 # }}}
154
155 =head2 Apply
156
157 Run through the relevant scrips.  Scrips will run in order based on 
158 description.  (Most common use case is to prepend a number to the description,
159 forcing the scrips to run in ascending alphanumerical order.)
160
161 =cut
162
163 sub Apply {
164     my $self = shift;
165
166     my %args = ( TicketObj      => undef,
167                  Ticket         => undef,
168                  Transaction    => undef,
169                  TransactionObj => undef,
170                  Stage          => undef,
171                  Type           => undef,
172                  @_ );
173
174     $self->Prepare(%args);
175     $self->Commit();
176
177 }
178
179 =head2 Commit
180
181 Commit all of this object's prepared scrips
182
183 =cut
184
185 sub Commit {
186     my $self = shift;
187
188     
189     foreach my $scrip (@{$self->Prepared}) {
190         $RT::Logger->debug(
191             "Committing scrip #". $scrip->id
192             ." on txn #". $self->{'TransactionObj'}->id
193             ." of ticket #". $self->{'TicketObj'}->id
194         );
195
196         $scrip->Commit( TicketObj      => $self->{'TicketObj'},
197                         TransactionObj => $self->{'TransactionObj'} );
198     }
199 }
200
201
202 =head2 Prepare
203
204 Only prepare the scrips, returning an array of the scrips we're interested in
205 in order of preparation, not execution
206
207 =cut
208
209 sub Prepare { 
210     my $self = shift;
211     my %args = ( TicketObj      => undef,
212                  Ticket         => undef,
213                  Transaction    => undef,
214                  TransactionObj => undef,
215                  Stage          => undef,
216                  Type           => undef,
217                  @_ );
218
219     #We're really going to need a non-acled ticket for the scrips to work
220     $self->_SetupSourceObjects( TicketObj      => $args{'TicketObj'},
221                                 Ticket         => $args{'Ticket'},
222                                 TransactionObj => $args{'TransactionObj'},
223                                 Transaction    => $args{'Transaction'} );
224
225
226     $self->_FindScrips( Stage => $args{'Stage'}, Type => $args{'Type'} );
227
228
229     #Iterate through each script and check it's applicability.
230     while ( my $scrip = $self->Next() ) {
231
232         next
233           unless ( $scrip->IsApplicable(
234                                      TicketObj      => $self->{'TicketObj'},
235                                      TransactionObj => $self->{'TransactionObj'}
236                    ) );
237
238         #If it's applicable, prepare and commit it
239         next
240           unless ( $scrip->Prepare( TicketObj      => $self->{'TicketObj'},
241                                     TransactionObj => $self->{'TransactionObj'}
242                    ) );
243         push @{$self->{'prepared_scrips'}}, $scrip;
244
245     }
246
247     return (@{$self->Prepared});
248
249 };
250
251 =head2 Prepared
252
253 Returns an arrayref of the scrips this object has prepared
254
255
256 =cut
257
258 sub Prepared {
259     my $self = shift;
260     return ($self->{'prepared_scrips'} || []);
261 }
262
263
264 # {{{ sup _SetupSourceObjects
265
266 =head2  _SetupSourceObjects { TicketObj , Ticket, Transaction, TransactionObj }
267
268 Setup a ticket and transaction for this Scrip collection to work with as it runs through the 
269 relevant scrips.  (Also to figure out which scrips apply)
270
271 Returns: nothing
272
273 =cut
274
275
276 sub _SetupSourceObjects {
277
278     my $self = shift;
279     my %args = ( 
280             TicketObj => undef,
281             Ticket => undef,
282             Transaction => undef,
283             TransactionObj => undef,
284             @_ );
285
286     if ( ( $self->{'TicketObj'} = $args{'TicketObj'} ) ) {
287         $self->{'TicketObj'}->CurrentUser( $self->CurrentUser );
288     }
289     else {
290         $self->{'TicketObj'} = RT::Ticket->new( $self->CurrentUser );
291         $self->{'TicketObj'}->Load( $args{'Ticket'} )
292           || $RT::Logger->err("$self couldn't load ticket $args{'Ticket'}");
293     }
294
295     if ( ( $self->{'TransactionObj'} = $args{'TransactionObj'} ) ) {
296         $self->{'TransactionObj'}->CurrentUser( $self->CurrentUser );
297     }
298     else {
299         $self->{'TransactionObj'} = RT::Transaction->new( $self->CurrentUser );
300         $self->{'TransactionObj'}->Load( $args{'Transaction'} )
301           || $RT::Logger->err( "$self couldn't load transaction $args{'Transaction'}");
302     }
303
304
305 # }}}
306
307 # {{{ sub _FindScrips;
308
309 =head2 _FindScrips
310
311 Find only the apropriate scrips for whatever we're doing now.  Order them 
312 by their description.  (Most common use case is to prepend a number to the
313 description, forcing the scrips to display and run in ascending alphanumerical 
314 order.)
315
316 =cut
317
318 sub _FindScrips {
319     my $self = shift;
320     my %args = (
321                  Stage => undef,
322                  Type => undef,
323                  @_ );
324
325
326     $self->LimitToQueue( $self->{'TicketObj'}->QueueObj->Id )
327       ;    #Limit it to  $Ticket->QueueObj->Id
328     $self->LimitToGlobal();
329       # or to "global"
330
331     $self->Limit( FIELD => "Stage", VALUE => $args{'Stage'} );
332
333     my $ConditionsAlias = $self->NewAlias('ScripConditions');
334
335     $self->Join(
336         ALIAS1 => 'main',
337         FIELD1 => 'ScripCondition',
338         ALIAS2 => $ConditionsAlias,
339         FIELD2 => 'id'
340     );
341
342     #We only want things where the scrip applies to this sort of transaction
343     # TransactionBatch stage can define list of transaction
344     foreach( split /\s*,\s*/, ($args{'Type'} || '') ) {
345         $self->Limit(
346             ALIAS           => $ConditionsAlias,
347             FIELD           => 'ApplicableTransTypes',
348             OPERATOR        => 'LIKE',
349             VALUE           => $_,
350             ENTRYAGGREGATOR => 'OR',
351         )
352     }
353
354     # Or where the scrip applies to any transaction
355     $self->Limit(
356         ALIAS           => $ConditionsAlias,
357         FIELD           => 'ApplicableTransTypes',
358         OPERATOR        => 'LIKE',
359         VALUE           => "Any",
360         ENTRYAGGREGATOR => 'OR',
361     );
362
363     # Promise some kind of ordering
364     $self->OrderBy( FIELD => 'Description' );
365
366     # we call Count below, but later we always do search
367     # so just do search and get count from results
368     $self->_DoSearch if $self->{'must_redo_search'};
369
370     $RT::Logger->debug(
371         "Found ". $self->Count ." scrips for $args{'Stage'} stage"
372         ." with applicable type(s) $args{'Type'}"
373     );
374 }
375
376 # }}}
377
378 1;
379