1 =head1 Ticket Lifecycles
3 By default, RT comes with ticket statuses that work for many types
4 of workflows: new, open, stalled, resolved, rejected, and deleted.
5 But there can be any number of workflows where these status values
6 don't completely fit. RT allows you to add new custom status values and
7 define their behavior with a feature called Lifecycles.
9 =head1 Adding a New Status
11 Because Statuses are controlled via lifecycles, you must manipulate the entire
12 lifecycle configuration to add a status. In earlier versions of RT new statuses
13 could be added by adding a new element to an array in RT's config file. But
14 because lifecyles are built around statuses, the entire lifecycle configuration
15 must be modified even if you only need new statuses.
17 =head2 Copy Lifecycle Config
19 First, copy the C<%Lifecycles> hash from C<RT_Config.pm> and paste it into
22 =head2 Add Status Value
24 Add the status to the set where your new status belongs. This example adds
25 C<approved> to the active statuses:
27 active => [ 'open', 'approved', 'stalled' ],
29 =head2 Update Transitions
31 Now the transitions section must be updated so that the new status can
32 transition to the existing statuses and also so the existing statuses can
33 transition to the new status.
35 new => [qw( open approved stalled resolved rejected deleted)],
36 open => [qw(new approved stalled resolved rejected deleted)],
37 approved => [qw(new open stalled resolved rejected deleted)],
38 stalled => [qw(new open approved rejected resolved deleted)],
39 resolved => [qw(new open approved stalled rejected deleted)],
40 rejected => [qw(new open approved stalled resolved deleted)],
41 deleted => [qw(new open approved stalled rejected resolved )],
43 =head1 Order Processing Example
45 This guide demonstrates lifecycles using an order fulfillment
46 system as a real-world example. You can find full lifecycles
47 documentation in L<RT_Config/Lifecycles>.
49 As with all RT custom configuration, if you are customizing the RT
50 lifecycle, make your changes in your C<RT_SiteConfig.pm> file, not
51 directly in C<RT_Config.pm>. If you are adding a new lifecycle, you can
54 Set(%Lifecycles, my_new_lifecycle => { ... } );
56 The detailed configuration options are discussed below. Once you add it
57 and restart the server, the new lifecycle will be available on the
58 queue configuration page.
60 To show how you might use custom lifecycles, we're going to configure
61 an RT lifecycle to process orders of some sort. In our order example,
62 each ticket in the queue is considered a separate order and the orders
63 have the following statuses:
69 The order just came in untouched, pending purchase validation
73 The order is being looked at for transaction processing
77 The order is out for delivery
81 The order was successfully delivered to its destination
85 The order was delivered but subsequently refunded
89 There was an error in the process validation and the order was denied purchase
93 In this particular example, the only status an order can start with is
94 'pending.' When a process coordinator chooses to take this order, it
95 goes into processing. The order can then either be delivered or denied
96 processing. Once denied, the lifecycle for that order ends. If it is
97 delivered, the order can still be refunded.
99 The following sections walk through each part of the configuration.
100 You can find the full configuration at the end in case you want to
101 see the exact syntax or use it to experiment with.
103 =head2 Defining Status Values
105 Every queue has a lifecycle assigned to it. Without changing any
106 configuration, you are given two lifecycles to choose from: "default"
107 and "approvals." The approvals lifecycle is used by the internal
108 approvals queue, and should not be changed or used by other queues. Do
109 not modify the approvals lifecycle unless you fully understand how RT
112 =for html <img alt="Lifecycle choices" src="../images/lifecycle-choices.png">
114 =for :text [Lifecycle choices F<docs/images/lifecycle-choices.png>]
116 =for :man [Lifecycle choices F<docs/images/lifecycle-choices.png>]
118 In RT 4.0, the C<@ActiveStatus> and C<@InactiveStatus> configurations
119 which were previously available are gone. The logic defined by those
120 options is now a subset of RT's lifecycle features, as described here.
122 A ticket naturally has three states: initial (I<new>), active (I<open> and
123 I<stalled>), and inactive (I<resolved>, I<rejected>, and I<deleted>). These
124 default settings look like this in the C<RT_Config.pm> file:
127 initial => [ 'new' ],
128 active => [ 'open', 'stalled' ],
129 inactive => [ 'resolved', 'rejected', 'deleted' ],
131 The initial state is the default starting place for new tickets, although
132 you can create tickets with other statuses. Initial is generally used
133 to acknowledge that a request has been made, but not yet acted on. RT
134 sets the Started date on a ticket when it is moved out of the initial state.
136 Active tickets are currently being worked on, inactive tickets have reached
137 some final state. By default, inactive tickets don't show up in search
138 results. The AutoOpen action sets a ticket's status to the first active
139 status. You can find more details in L<RT_Config/"Lifecycle definitions">.
141 Now we want to set up some statuses appropriate for order fulfillment,
142 so we create a new top-level key called C<orders> and add our new status
145 Set( %Lifecycles, orders => {
146 initial => [ 'pending' ],
147 active => [ 'processing', 'delivery' ],
148 inactive => [ 'delivered', 'returned', 'declined', 'deleted' ],
152 We still use the initial, active and inactive categories, but we are
153 able to define status values that are appropriate for the workflow
154 we want to create. This should make the system more intuitive for users.
158 The typical lifecycle follows the path initial -> active -> inactive.
159 Obviously the path of a ticket can get more complicated than this, which
160 is where transitions come into play.
162 Transitions manage the flow of a ticket from status to status. This
163 section of the configuration has keys, which are the current status,
164 and values that define which other statuses the ticket can transition
165 to. Here are the transitions we define for our order process.
167 Set( %Lifecycles, orders => {
170 '' => [qw(pending processing declined)],
171 pending => [qw(processing declined deleted)],
172 processing => [qw(pending declined delivery delivered deleted)],
173 delivery => [qw(pending delivered returned deleted)],
174 delivered => [qw(pending returned deleted)],
175 returned => [qw(pending delivery deleted)],
176 deleted => [qw(pending processing delivered delivery returned)],
181 If a ticket is in the delivered status, it doesn't make sense for it to
182 transition to processing or declined since the customer already has the
183 order. However, it can transition to returned since they could send it back.
184 The configuration above defines this for RT.
186 The C<''> entry defines the valid statuses when a ticket is created.
188 Deleted is a special status in RT that allows you to remove a ticket from
189 active use. You may need to do this if a ticket is created by mistake, or
190 a duplicate is created. Once deleted, a ticket will never show up in search
191 results. As you can see, the system will allow you to
192 transition to deleted from any status.
194 =head2 Rights and Access Control
196 Your workflow may have several people working on tickets at different
197 steps, and for some you may want to make sure only certain users
198 can perform certain actions. For example, the company may have a rule
199 that only the quality assurance team is allowed to approve (or decline)
200 an order for delivery.
202 You can apply labels to transitions and assign rights to them to allow
203 you to apply this sort of access control. This is done with a rights
206 Set( %Lifecycles, orders => {
209 '* -> declined' => 'DeclineOrder',
210 '* -> delivery' => 'ApproveOrder',
215 This configuration tells RT to require the right DeclineOrder for a
216 transition from any status (C<*>) to C<declined>. The ApproveOrder
217 right is similar, but for C<delivery>. These rights take the place of
218 the standard ModifyTicket right, not in addition to it, so keep that
219 in mind when creating and assigning new rights.
221 Once these rights are configured and loaded (by restarting the web
222 server), they can be assigned in the web UI to groups, queues, and users.
223 The rights show up on the rights pages in a Status tab alongside the
224 standard RT rights tabs.
226 =for html <img alt="Lifecycle group rights" src="../images/global-lifecycle-group-rights.png">
228 =for :text [Lifecycle group rights F<docs/images/global-lifecycle-group-rights.png>]
230 =for :man [Lifecycle group rights F<docs/images/global-lifecycle-group-rights.png>]
232 After a status transition right is granted, users with the right will see
233 the status in the drop-down, and possibly any related actions (see
236 =head2 Default Status
238 There are interfaces to RT from which it isn't possible to define a status,
239 like sending an email to create a ticket, but tickets
240 require a status. To handle these cases, you can set
241 default status values for RT to use when the user doesn't explicitly set
244 Looking at the defaults section in the standard RT configuration,
245 you can see the events for which you can define a default status.
246 For example, 'on_create' => 'new' automatically gives newly created tickets
247 a C<new> status when the requestor doesn't supply a status. We can do the same
250 Set( %Lifecycles, orders => {
252 on_create => 'pending',
257 Only a small number of defaults are needed because in practice there are
258 relatively few cases where a ticket will find itself without a status or
259 in an ambiguous state.
263 To customize how transitions are presented in RT, lifecycles have an
264 C<actions> section where you can customize how an action (e.g. changing
265 status from new -> open) looks and functions. You can customize the action's
266 label, which is how it appears to users, and the type of update, either comment
267 or reply. As an example, in the default RT configuration the action
268 "new -> open" has the default label "Open it" and an update value of C<Respond>.
270 Using the lifecycles configuration, you can change the label to anything you
271 like. You can set the update option to C<Comment> or C<Respond>, which tells RT
272 to process the action as a comment (not sent to requestors) or a reply (sent
275 This part of the lifecycles configuration replaces the previous
276 C<$ResolveDefaultUpdateType> configuration value. To mimic that option, set
277 the update type to C<Comment> for all transitions to C<resolved>.
279 Here is an example of a change we might make for our order process:
281 Set( %Lifecycles, orders => {
284 'pending -> processing' => {
285 label => 'Open For Processing',
288 'pending -> declined' => {
297 Alternatively, supplying no update type results in a "quick"
298 action that changes the status immediately without going through the
299 ticket update page. RT's default "Delete" action is a "quick" action,
302 # from the RT "default" lifecycle
303 'new -> deleted' => {
307 If the transition has an associated right, it must be granted for a user to
308 see the action. For example, if we give a group the DeclineOrder right as
309 shown in the earlier example, members of that group will see a Decline option
310 in their Actions menu if a ticket has a pending status. The
311 L</"Full Configuration"> at the end shows other action entries that
312 make the Decline option available in more cases.
314 =for html <img alt="Action menu decline" src="../images/action-decline.png">
316 =for :text [Action menu decline F<docs/images/action-decline.png>]
318 =for :man [Action menu decline F<docs/images/action-decline.png>]
320 =head2 Mapping Between Queues
322 As we've demonstrated, each queue can have its own custom lifecycle, but
323 in RT you sometimes want to move a ticket from one queue to another.
324 A ticket will have a status in a given queue, but that status may not
325 exist in another queue you want to move the ticket to, or it may exist
326 but mean something different. To allow tickets to move between queues with
327 different lifecycles, RT needs to know how to set the status appropriately.
329 The lifecycle configuration has a C<__maps__> entry to allow you to
330 specify the mappings you want between different queues. Sometimes statuses
331 between queues don't or can't match perfectly, but if you need to move
332 tickets between those queues, it's important that you provide a complete
333 mapping, defining the most sensible mapping you can.
335 If you don't provide a mapping, users will see an error when they try to
336 move a ticket between queues with different lifecycles but no mapping.
338 Set( %Lifecycles, orders => {
341 'default -> orders' => {
343 'open' => 'processing',
346 'orders -> default' => {
348 'processing' => 'open',
356 In the example above, we first define mappings between the default queue and
357 our new orders queue. The second block defines the reverse for tickets that
358 might be moved from the orders queue to a queue that uses the default lifecycle.
360 =head2 Full Configuration
362 Here is the full configuration if you want to add it to your RT instance
367 # 'orders' shows up as a lifecycle choice when you create a new
368 # queue or modify an existing one
370 # All the appropriate order statuses
371 initial => [ 'pending' ],
372 active => [ 'processing', 'delivery' ],
373 inactive => [ 'delivered', 'returned', 'declined' ],
375 # Default order statuses for certain actions
377 on_create => 'pending',
380 # Status change restrictions
382 '' => [qw(pending processing declined)],
383 pending => [qw(processing declined deleted)],
384 processing => [qw(pending declined delivery delivered deleted)],
385 delivery => [qw(pending delivered returned deleted)],
386 delivered => [qw(pending returned deleted)],
387 returned => [qw(pending delivery deleted)],
388 deleted => [qw(pending processing delivered delivery returned)],
391 # Rights for different actions
394 # These rights are in the default lifecycle
395 '* -> deleted' => 'DeleteTicket',
396 '* -> *' => 'ModifyTicket',
398 # Maybe we want to create rights to keep QA rigid
399 '* -> declined' => 'DeclineOrder',
400 '* -> delivery' => 'ApproveOrder',
403 # Actions for the web UI
405 'pending -> processing' => {
406 label => 'Open For Processing',
409 'pending -> delivered' => {
410 label => 'Mark as being delivered',
413 'pending -> declined' => {
417 'pending -> deleted' => {
420 'processing -> declined' => {
424 'processing -> delivery' => {
425 label => 'Out for delivery',
428 'delivery -> delivered' => {
429 label => 'Mark as delivered',
432 'delivery -> returned' => {
433 label => 'Returned to Manufacturer',
436 'delivered -> returned' => {
437 label => 'Returned to Manufacturer',
440 'returned -> delivery' => {
441 label => 'Re-deliver Order',
444 'deleted -> pending' => {
451 # Status mapping different different lifecycles
453 'default -> orders' => {
455 'open' => 'processing',
456 'stalled' => 'processing',
457 'resolved' => 'delivered',
458 'rejected' => 'declined',
459 'deleted' => 'deleted',
461 'orders -> default' => {
463 'processing' => 'open',
464 'delivered' => 'resolved',
465 'returned' => 'open', # closest matching we have in 'default'
466 'declined' => 'rejected',
467 'deleted' => 'deleted',
472 Here is an example history of a ticket following this lifecycle:
474 =for html <img alt="Lifecycle history" src="../images/order-history-example.png">
476 =for :text [Lifecycle history F<docs/images/order-history-example.png>]
478 =for :man [Lifecycle history F<docs/images/order-history-example.png>]