import rt 3.6.4
[freeside.git] / rt / lib / RT / Scrips_Overlay.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2
3 # COPYRIGHT:
4 #  
5 # This software is Copyright (c) 1996-2007 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/copyleft/gpl.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 =head1 NAME
49
50   RT::Scrips - a collection of RT Scrip objects
51
52 =head1 SYNOPSIS
53
54   use RT::Scrips;
55
56 =head1 DESCRIPTION
57
58
59 =head1 METHODS
60
61
62 =begin testing
63
64 ok (require RT::Scrips);
65
66 =end testing
67
68 =cut
69
70
71 package RT::Scrips;
72
73 use strict;
74 no warnings qw(redefine);
75
76 # {{{ sub LimitToQueue 
77
78 =head2 LimitToQueue
79
80 Takes a queue id (numerical) as its only argument. Makes sure that 
81 Scopes it pulls out apply to this queue (or another that you've selected with
82 another call to this method
83
84 =cut
85
86 sub LimitToQueue  {
87    my $self = shift;
88   my $queue = shift;
89  
90   $self->Limit (ENTRYAGGREGATOR => 'OR',
91                 FIELD => 'Queue',
92                 VALUE => "$queue")
93       if defined $queue;
94   
95 }
96 # }}}
97
98 # {{{ sub LimitToGlobal
99
100 =head2 LimitToGlobal
101
102 Makes sure that 
103 Scopes it pulls out apply to all queues (or another that you've selected with
104 another call to this method or LimitToQueue
105
106 =cut
107
108
109 sub LimitToGlobal  {
110    my $self = shift;
111  
112   $self->Limit (ENTRYAGGREGATOR => 'OR',
113                 FIELD => 'Queue',
114                 VALUE => 0);
115   
116 }
117 # }}}
118
119 # {{{ sub NewItem 
120 sub NewItem  {
121   my $self = shift;
122   
123   return(new RT::Scrip($self->CurrentUser));
124 }
125 # }}}
126
127 # {{{ sub Next 
128
129 =head2 Next
130
131 Returns the next scrip that this user can see.
132
133 =cut
134   
135 sub Next {
136     my $self = shift;
137     
138     
139     my $Scrip = $self->SUPER::Next();
140     if ((defined($Scrip)) and (ref($Scrip))) {
141
142         if ($Scrip->CurrentUserHasRight('ShowScrips')) {
143             return($Scrip);
144         }
145         
146         #If the user doesn't have the right to show this scrip
147         else {  
148             return($self->Next());
149         }
150     }
151     #if there never was any scrip
152     else {
153         return(undef);
154     }   
155     
156 }
157 # }}}
158
159 =head2 Apply
160
161 Run through the relevant scrips.  Scrips will run in order based on 
162 description.  (Most common use case is to prepend a number to the description,
163 forcing the scrips to run in ascending alphanumerical order.)
164
165 =cut
166
167 sub Apply {
168     my $self = shift;
169
170     my %args = ( TicketObj      => undef,
171                  Ticket         => undef,
172                  Transaction    => undef,
173                  TransactionObj => undef,
174                  Stage          => undef,
175                  Type           => undef,
176                  @_ );
177
178     $self->Prepare(%args);
179     $self->Commit();
180
181 }
182
183 =head2 Commit
184
185 Commit all of this object's prepared scrips
186
187 =cut
188
189 sub Commit {
190     my $self = shift;
191
192     
193     foreach my $scrip (@{$self->Prepared}) {
194
195         $scrip->Commit( TicketObj      => $self->{'TicketObj'},
196                         TransactionObj => $self->{'TransactionObj'} );
197     }
198 }
199
200
201 =head2 Prepare
202
203 Only prepare the scrips, returning an array of the scrips we're interested in
204 in order of preparation, not execution
205
206 =cut
207
208 sub Prepare { 
209     my $self = shift;
210     my %args = ( TicketObj      => undef,
211                  Ticket         => undef,
212                  Transaction    => undef,
213                  TransactionObj => undef,
214                  Stage          => undef,
215                  Type           => undef,
216                  @_ );
217
218     #We're really going to need a non-acled ticket for the scrips to work
219     $self->_SetupSourceObjects( TicketObj      => $args{'TicketObj'},
220                                 Ticket         => $args{'Ticket'},
221                                 TransactionObj => $args{'TransactionObj'},
222                                 Transaction    => $args{'Transaction'} );
223
224
225     $self->_FindScrips( Stage => $args{'Stage'}, Type => $args{'Type'} );
226
227
228     #Iterate through each script and check it's applicability.
229     while ( my $scrip = $self->Next() ) {
230
231         next
232           unless ( $scrip->IsApplicable(
233                                      TicketObj      => $self->{'TicketObj'},
234                                      TransactionObj => $self->{'TransactionObj'}
235                    ) );
236
237         #If it's applicable, prepare and commit it
238         next
239           unless ( $scrip->Prepare( TicketObj      => $self->{'TicketObj'},
240                                     TransactionObj => $self->{'TransactionObj'}
241                    ) );
242         push @{$self->{'prepared_scrips'}}, $scrip;
243
244     }
245
246     return (@{$self->Prepared});
247
248 };
249
250 =head2 Prepared
251
252 Returns an arrayref of the scrips this object has prepared
253
254
255 =cut
256
257 sub Prepared {
258     my $self = shift;
259     return ($self->{'prepared_scrips'} || []);
260 }
261
262
263 # {{{ sup _SetupSourceObjects
264
265 =head2  _SetupSourceObjects { TicketObj , Ticket, Transaction, TransactionObj }
266
267 Setup a ticket and transaction for this Scrip collection to work with as it runs through the 
268 relevant scrips.  (Also to figure out which scrips apply)
269
270 Returns: nothing
271
272 =cut
273
274
275 sub _SetupSourceObjects {
276
277     my $self = shift;
278     my %args = ( 
279             TicketObj => undef,
280             Ticket => undef,
281             Transaction => undef,
282             TransactionObj => undef,
283             @_ );
284
285     if ( ( $self->{'TicketObj'} = $args{'TicketObj'} ) ) {
286         $self->{'TicketObj'}->CurrentUser( $self->CurrentUser );
287     }
288     else {
289         $self->{'TicketObj'} = RT::Ticket->new( $self->CurrentUser );
290         $self->{'TicketObj'}->Load( $args{'Ticket'} )
291           || $RT::Logger->err("$self couldn't load ticket $args{'Ticket'}\n");
292     }
293
294     if ( ( $self->{'TransactionObj'} = $args{'TransactionObj'} ) ) {
295         $self->{'TransactionObj'}->CurrentUser( $self->CurrentUser );
296     }
297     else {
298         $self->{'TransactionObj'} = RT::Transaction->new( $self->CurrentUser );
299         $self->{'TransactionObj'}->Load( $args{'Transaction'} )
300           || $RT::Logger->err( "$self couldn't load transaction $args{'Transaction'}\n");
301     }
302
303
304 # }}}
305
306 # {{{ sub _FindScrips;
307
308 =head2 _FindScrips
309
310 Find only the apropriate scrips for whatever we're doing now.  Order them 
311 by their description.  (Most common use case is to prepend a number to the
312 description, forcing the scrips to display and run in ascending alphanumerical 
313 order.)
314
315 =cut
316
317 sub _FindScrips {
318     my $self = shift;
319     my %args = (
320                  Stage => undef,
321                  Type => undef,
322                  @_ );
323
324
325     $self->LimitToQueue( $self->{'TicketObj'}->QueueObj->Id )
326       ;    #Limit it to  $Ticket->QueueObj->Id
327     $self->LimitToGlobal();
328       # or to "global"
329
330     $self->Limit( FIELD => "Stage", VALUE => $args{'Stage'} );
331
332     my $ConditionsAlias = $self->NewAlias('ScripConditions');
333
334     $self->Join(
335         ALIAS1 => 'main',
336         FIELD1 => 'ScripCondition',
337         ALIAS2 => $ConditionsAlias,
338         FIELD2 => 'id'
339     );
340
341     #We only want things where the scrip applies to this sort of transaction
342     # TransactionBatch stage can define list of transaction
343     foreach( split /\s*,\s*/, ($args{'Type'} || '') ) {
344         $self->Limit(
345             ALIAS           => $ConditionsAlias,
346             FIELD           => 'ApplicableTransTypes',
347             OPERATOR        => 'LIKE',
348             VALUE           => $_,
349             ENTRYAGGREGATOR => 'OR',
350         )
351     }
352
353     # Or where the scrip applies to any transaction
354     $self->Limit(
355         ALIAS           => $ConditionsAlias,
356         FIELD           => 'ApplicableTransTypes',
357         OPERATOR        => 'LIKE',
358         VALUE           => "Any",
359         ENTRYAGGREGATOR => 'OR',
360     );
361
362     # Promise some kind of ordering
363     $self->OrderBy( FIELD => 'description' );
364
365     $RT::Logger->debug("Found ".$self->Count. " scrips");
366 }
367
368 # }}}
369
370 1;
371