]> git.uio.no Git - usit-rt.git/blame - docs/customizing/lifecycles.pod
Upgrade to 4.2.2
[usit-rt.git] / docs / customizing / lifecycles.pod
CommitLineData
45030404
MKG
1=head1 Ticket Lifecycles
2
3By default, RT comes with ticket statuses that work for many types
4of workflows: new, open, stalled, resolved, rejected, and deleted.
5But there can be any number of workflows where these status values
6don't completely fit. RT allows you to add new custom status values and
7define their behavior with a feature called Lifecycles.
8
9This guide demonstrates lifecycles using an order fulfillment
10system as a real-world example. You can find full lifecycles
11documentation in L<RT_Config/Lifecycles>.
12
13As with all RT custom configuration, if you are customizing the RT
14lifecycle, make your changes in your C<RT_SiteConfig.pm> file, not
15directly in C<RT_Config.pm>. If you are adding a new lifecycle, you can
16add a new entry with:
17
18 Set(%Lifecycles, my_new_lifecycle => { ... } );
19
20The detailed configuration options are discussed below. Once you add it
21and restart the server, the new lifecycle will be available on the
22queue configuration page.
23
24If you want to modify the default lifecycle, you can copy it from
25C<RT_Config.pm>, paste it into C<RT_SiteConfig.pm> and make your
26changes.
27
28=head1 Order Processing Example
29
30To show how you might use custom lifecycles, we're going to configure
31an RT lifecycle to process orders of some sort. In our order example,
32each ticket in the queue is considered a separate order and the orders
33have the following statuses:
34
35=over
36
37=item pending
38
39The order just came in untouched, pending purchase validation
40
41=item processing
42
43The order is being looked at for transaction processing
44
45=item delivery
46
47The order is out for delivery
48
49=item delivered
50
51The order was successfully delivered to its destination
52
53=item refunded
54
55The order was delivered but subsequently refunded
56
57=item declined
58
59There was an error in the process validation and the order was denied purchase
60
61=back
62
63In this particular example, the only status an order can start with is
64'pending.' When a process coordinator chooses to take this order, it
65goes into processing. The order can then either be delivered or denied
66processing. Once denied, the lifecycle for that order ends. If it is
67delivered, the order can still be refunded.
68
69The following sections walk through each part of the configuration.
70You can find the full configuration at the end in case you want to
71see the exact syntax or use it to experiment with.
72
73=head2 Defining Status Values
74
75Every queue has a lifecycle assigned to it. Without changing any
76configuration, you are given two lifecycles to choose from: "default"
77and "approvals." The approvals lifecycle is used by the internal
78approvals queue, and should not be changed or used by other queues. Do
79not modify the approvals lifecycle unless you fully understand how RT
80approvals work.
81
82=for html <img alt="Lifecycle choices" src="../images/lifecycle-choices.png">
83
84=for :text [Lifecycle choices F<docs/images/lifecycle-choices.png>]
85
86=for :man [Lifecycle choices F<docs/images/lifecycle-choices.png>]
87
88In RT 4.0, the C<@ActiveStatus> and C<@InactiveStatus> configurations
89which were previously available are gone. The logic defined by those
90options is now a subset of RT's lifecycle features, as described here.
91
92A ticket naturally has three states: initial (I<new>), active (I<open> and
93I<stalled>), and inactive (I<resolved>, I<rejected>, and I<deleted>). These
94default settings look like this in the C<RT_Config.pm> file:
95
96 default => {
97 initial => [ 'new' ],
98 active => [ 'open', 'stalled' ],
99 inactive => [ 'resolved', 'rejected', 'deleted' ],
100
101The initial state is the default starting place for new tickets, although
102you can create tickets with other statuses. Initial is generally used
103to acknowledge that a request has been made, but not yet acted on. RT
104sets the Started date on a ticket when it is moved out of the initial state.
105
106Active tickets are currently being worked on, inactive tickets have reached
107some final state. By default, inactive tickets don't show up in search
108results. The AutoOpen action sets a ticket's status to the first active
109status. You can find more details in L<RT_Config/"Lifecycle definitions">.
110
111Now we want to set up some statuses appropriate for order fulfillment,
112so we create a new top-level key called C<orders> and add our new status
113values.
114
115 Set( %Lifecycles, orders => {
116 initial => [ 'pending' ],
117 active => [ 'processing', 'delivery' ],
118 inactive => [ 'delivered', 'returned', 'declined', 'deleted' ],
119 # ...,
120 });
121
122We still use the initial, active and inactive categories, but we are
123able to define status values that are appropriate for the workflow
124we want to create. This should make the system more intuitive for users.
125
126=head2 Transitions
127
128The typical lifecycle follows the path initial -> active -> inactive.
129Obviously the path of a ticket can get more complicated than this, which
130is where transitions come into play.
131
132Transitions manage the flow of a ticket from status to status. This
133section of the configuration has keys, which are the current status,
134and values that define which other statuses the ticket can transition
135to. Here are the transitions we define for our order process.
136
137 Set( %Lifecycles, orders => {
138 # ...,
139 transitions => {
140 '' => [qw(pending processing declined)],
141 pending => [qw(processing declined deleted)],
142 processing => [qw(pending declined delivery delivered deleted)],
143 delivery => [qw(pending delivered returned deleted)],
144 delivered => [qw(pending returned deleted)],
145 returned => [qw(pending delivery deleted)],
146 deleted => [qw(pending processing delivered delivery returned)],
147 },
148 # ...,
149 });
150
151If a ticket is in the delivered status, it doesn't make sense for it to
152transition to processing or declined since the customer already has the
153order. However, it can transition to returned since they could send it back.
154The configuration above defines this for RT.
155
156The C<''> entry defines the valid statuses when a ticket is created.
157
158Deleted is a special status in RT that allows you to remove a ticket from
159active use. You may need to do this if a ticket is created by mistake, or
160a duplicate is created. Once deleted, a ticket will never show up in search
161results. As you can see, the system will allow you to
162transition to deleted from any status.
163
164=head2 Rights and Access Control
165
166Your workflow may have several people working on tickets at different
167steps, and for some you may want to make sure only certain users
168can perform certain actions. For example, the company may have a rule
169that only the quality assurance team is allowed to approve (or decline)
170an order for delivery.
171
172You can apply labels to transitions and assign rights to them to allow
173you to apply this sort of access control. This is done with a rights
174entry:
175
176 Set( %Lifecycles, orders => {
177 # ...,
178 rights => {
179 '* -> declined' => 'DeclineOrder',
180 '* -> delivery' => 'ApproveOrder',
181 },
182 # ...,
183 });
184
185This configuration tells RT to require the right DeclineOrder for a
186transition from any status (C<*>) to C<declined>. The ApproveOrder
187right is similar, but for C<delivery>. These rights take the place of
188the standard ModifyTicket right, not in addition to it, so keep that
189in mind when creating and assigning new rights.
190
191Once these rights are configured and loaded (by restarting the web
192server), they can be assigned in the web UI to groups, queues, and users.
193The rights show up on the rights pages in a Status tab alongside the
194standard RT rights tabs.
195
196=for html <img alt="Lifecycle group rights" src="../images/global-lifecycle-group-rights.png">
197
198=for :text [Lifecycle group rights F<docs/images/global-lifecycle-group-rights.png>]
199
200=for :man [Lifecycle group rights F<docs/images/global-lifecycle-group-rights.png>]
201
202After a status transition right is granted, users with the right will see
203the status in the drop-down, and possibly any related actions (see
204L</Actions>).
205
206=head2 Default Status
207
208There are interfaces to RT from which it isn't possible to define a status,
209like sending an email to create a ticket, but tickets
210require a status. To handle these cases, you can set
211default status values for RT to use when the user doesn't explicitly set
212a value.
213
214Looking at the defaults section in the standard RT configuration,
215you can see the events for which you can define a default status.
216For example, 'on_create' => 'new' automatically gives newly created tickets
217a C<new> status when the requestor doesn't supply a status. We can do the same
218for our process.
219
220 Set( %Lifecycles, orders => {
221 defaults => {
222 on_create => 'pending',
223 },
224 # ...,
225 });
226
227Only a small number of defaults are needed because in practice there are
228relatively few cases where a ticket will find itself without a status or
229in an ambiguous state.
230
231=head2 Actions
232
233To customize how transitions are presented in RT, lifecycles have an
234C<actions> section where you can customize how an action (e.g. changing
235status from new -> open) looks and functions. You can customize the action's
236label, which is how it appears to users, and the type of update, either comment
237or reply. As an example, in the default RT configuration the action
238"new -> open" has the default label "Open it" and an update value of C<Respond>.
239
240Using the lifecycles configuration, you can change the label to anything you
241like. You can set the update option to C<Comment> or C<Respond>, which tells RT
242to process the action as a comment (not sent to requestors) or a reply (sent
243to requestors).
244
245This part of the lifecycles configuration replaces the previous
246C<$ResolveDefaultUpdateType> configuration value. To mimic that option, set
247the update type to C<Comment> for all transitions to C<resolved>.
248
249Here is an example of a change we might make for our order process:
250
251 Set( %Lifecycles, orders => {
252 # ...,
253 actions => [
254 'pending -> processing' => {
255 label => 'Open For Processing',
256 update => 'Comment',
257 },
258 'pending -> declined' => {
259 label => 'Decline',
260 update => 'Respond',
261 },
262 # ...
263 ],
264 # ...
265 });
266
267Alternatively, supplying no update type results in a "quick"
268action that changes the status immediately without going through the
269ticket update page. RT's default "Delete" action is a "quick" action,
270for example:
271
272 # from the RT "default" lifecycle
273 'new -> deleted' => {
274 label => 'Delete',
275 },
276
277If the transition has an associated right, it must be granted for a user to
278see the action. For example, if we give a group the DeclineOrder right as
279shown in the earlier example, members of that group will see a Decline option
280in their Actions menu if a ticket has a pending status. The
281L</"Full Configuration"> at the end shows other action entries that
282make the Decline option available in more cases.
283
284=for html <img alt="Action menu decline" src="../images/action-decline.png">
285
286=for :text [Action menu decline F<docs/images/action-decline.png>]
287
288=for :man [Action menu decline F<docs/images/action-decline.png>]
289
290=head2 Mapping Between Queues
291
292As we've demonstrated, each queue can have its own custom lifecycle, but
293in RT you sometimes want to move a ticket from one queue to another.
294A ticket will have a status in a given queue, but that status may not
295exist in another queue you want to move the ticket to, or it may exist
296but mean something different. To allow tickets to move between queues with
297different lifecycles, RT needs to know how to set the status appropriately.
298
299The lifecycle configuration has a C<__maps__> entry to allow you to
300specify the mappings you want between different queues. Sometimes statuses
301between queues don't or can't match perfectly, but if you need to move
302tickets between those queues, it's important that you provide a complete
303mapping, defining the most sensible mapping you can.
304
305If you don't provide a mapping, users will see an error when they try to
306move a ticket between queues with different lifecycles but no mapping.
307
320f0092
MKG
308 Set( %Lifecycles,
309 orders => {
310 # ...
311 },
45030404
MKG
312 __maps__ => {
313 'default -> orders' => {
314 'new' => 'pending',
315 'open' => 'processing',
316 # ...,
317 },
318 'orders -> default' => {
319 'pending' => 'new',
320 'processing' => 'open',
321 # ...,
322 },
323 # ...,
324 },
325 # ...,
326 });
327
328In the example above, we first define mappings between the default queue and
329our new orders queue. The second block defines the reverse for tickets that
330might be moved from the orders queue to a queue that uses the default lifecycle.
331
332=head2 Full Configuration
333
334Here is the full configuration if you want to add it to your RT instance
335to experiment.
336
337 Set(%Lifecycles,
338
339 # 'orders' shows up as a lifecycle choice when you create a new
340 # queue or modify an existing one
341 orders => {
342 # All the appropriate order statuses
343 initial => [ 'pending' ],
344 active => [ 'processing', 'delivery' ],
320f0092 345 inactive => [ 'delivered', 'returned', 'declined', 'deleted' ],
45030404
MKG
346
347 # Default order statuses for certain actions
348 defaults => {
349 on_create => 'pending',
350 },
351
352 # Status change restrictions
353 transitions => {
354 '' => [qw(pending processing declined)],
355 pending => [qw(processing declined deleted)],
356 processing => [qw(pending declined delivery delivered deleted)],
357 delivery => [qw(pending delivered returned deleted)],
358 delivered => [qw(pending returned deleted)],
359 returned => [qw(pending delivery deleted)],
360 deleted => [qw(pending processing delivered delivery returned)],
361 },
362
363 # Rights for different actions
364 rights => {
365
366 # These rights are in the default lifecycle
367 '* -> deleted' => 'DeleteTicket',
368 '* -> *' => 'ModifyTicket',
369
370 # Maybe we want to create rights to keep QA rigid
371 '* -> declined' => 'DeclineOrder',
372 '* -> delivery' => 'ApproveOrder',
373 },
374
375 # Actions for the web UI
376 actions => [
377 'pending -> processing' => {
378 label => 'Open For Processing',
379 update => 'Comment',
380 },
45030404
MKG
381 'pending -> declined' => {
382 label => 'Decline',
383 update => 'Respond',
384 },
385 'pending -> deleted' => {
386 label => 'Delete',
387 },
388 'processing -> declined' => {
389 label => 'Decline',
390 update => 'Respond',
391 },
392 'processing -> delivery' => {
393 label => 'Out for delivery',
394 update => 'Comment',
395 },
396 'delivery -> delivered' => {
397 label => 'Mark as delivered',
398 update => 'Comment',
399 },
400 'delivery -> returned' => {
401 label => 'Returned to Manufacturer',
402 update => 'Respond',
403 },
404 'delivered -> returned' => {
405 label => 'Returned to Manufacturer',
406 update => 'Respond',
407 },
408 'returned -> delivery' => {
409 label => 'Re-deliver Order',
410 update => 'Respond',
411 },
412 'deleted -> pending' => {
413 label => 'Undelete',
414 update => 'Respond',
415 },
416 ],
417 },
418
419 # Status mapping different different lifecycles
420 __maps__ => {
421 'default -> orders' => {
422 'new' => 'pending',
423 'open' => 'processing',
424 'stalled' => 'processing',
425 'resolved' => 'delivered',
426 'rejected' => 'declined',
427 'deleted' => 'deleted',
428 },
429 'orders -> default' => {
430 'pending' => 'new',
431 'processing' => 'open',
432 'delivered' => 'resolved',
433 'returned' => 'open', # closest matching we have in 'default'
434 'declined' => 'rejected',
435 'deleted' => 'deleted',
436 },
437 },
438 );
439
440Here is an example history of a ticket following this lifecycle:
441
442=for html <img alt="Lifecycle history" src="../images/order-history-example.png">
443
444=for :text [Lifecycle history F<docs/images/order-history-example.png>]
445
446=for :man [Lifecycle history F<docs/images/order-history-example.png>]