+
+
+=head1 Lifecycles
+
+=head2 Lifecycle definitions
+
+Each lifecycle is a list of possible statuses split into three logic
+sets: B<initial>, B<active> and B<inactive>. Each status in a
+lifecycle must be unique. (Statuses may not be repeated across sets.)
+Each set may have any number of statuses.
+
+For example:
+
+ default => {
+ initial => ['new'],
+ active => ['open', 'stalled'],
+ inactive => ['resolved', 'rejected', 'deleted'],
+ ...
+ },
+
+Status names can be from 1 to 64 ASCII characters. Statuses are
+localized using RT's standard internationalization and localization
+system.
+
+=over 4
+
+=item initial
+
+You can define multiple B<initial> statuses for tickets in a given
+lifecycle.
+
+RT will automatically set its B<Started> date when you change a
+ticket's status from an B<initial> state to an B<active> or
+B<inactive> status.
+
+=item active
+
+B<Active> tickets are "currently in play" - they're things that are
+being worked on and not yet complete.
+
+=item inactive
+
+B<Inactive> tickets are typically in their "final resting state".
+
+While you're free to implement a workflow that ignores that
+description, typically once a ticket enters an inactive state, it will
+never again enter an active state.
+
+RT will automatically set the B<Resolved> date when a ticket's status
+is changed from an B<Initial> or B<Active> status to an B<Inactive>
+status.
+
+B<deleted> is still a special status and protected by the
+B<DeleteTicket> right, unless you re-defined rights (read below). If
+you don't want to allow ticket deletion at any time simply don't
+include it in your lifecycle.
+
+=back
+
+Statuses in each set are ordered and listed in the UI in the defined
+order.
+
+Changes between statuses are constrained by transition rules, as
+described below.
+
+=head2 Default values
+
+In some cases a default value is used to display in UI or in API when
+value is not provided. You can configure defaults using the following
+syntax:
+
+ default => {
+ ...
+ defaults => {
+ on_create => 'new',
+ on_resolve => 'resolved',
+ ...
+ },
+ },
+
+The following defaults are used.
+
+=over 4
+
+=item on_create
+
+If you (or your code) doesn't specify a status when creating a ticket,
+RT will use the this status. See also L</Statuses available during
+ticket creation>.
+
+=item on_merge
+
+When tickets are merged, the status of the ticket that was merged
+away is forced to this value. It should be one of inactive statuses;
+'resolved' or its equivalent is most probably the best candidate.
+
+=item approved
+
+When an approval is accepted, the status of depending tickets will
+be changed to this value.
+
+=item denied
+
+When an approval is denied, the status of depending tickets will
+be changed to this value.
+
+=item reminder_on_open
+
+When a reminder is opened, the status will be changed to this value.
+
+=item reminder_on_resolve
+
+When a reminder is resolved, the status will be changed to this value.
+
+=back
+
+=head2 Transitions between statuses and UI actions
+
+A B<Transition> is a change of status from A to B. You should define
+all possible transitions in each lifecycle using the following format:
+
+ default => {
+ ...
+ transitions => {
+ '' => [qw(new open resolved)],
+ new => [qw(open resolved rejected deleted)],
+ open => [qw(stalled resolved rejected deleted)],
+ stalled => [qw(open)],
+ resolved => [qw(open)],
+ rejected => [qw(open)],
+ deleted => [qw(open)],
+ },
+ ...
+ },
+
+The order of items in the listing for each transition line affects
+the order they appear in the drop-down. If you change the config
+for 'open' state listing to:
+
+ open => [qw(stalled rejected deleted resolved)],
+
+then the 'resolved' status will appear as the last item in the drop-down.
+
+=head3 Statuses available during ticket creation
+
+By default users can create tickets with a status of new,
+open, or resolved, but cannot create tickets with a status of
+rejected, stalled, or deleted. If you want to change the statuses
+available during creation, update the transition from '' (empty
+string), like in the example above.
+
+=head3 Protecting status changes with rights
+
+A transition or group of transitions can be protected by a specific
+right. Additionally, you can name new right names, which will be added
+to the system to control that transition. For example, if you wished to
+create a lesser right than ModifyTicket for rejecting tickets, you could
+write:
+
+ default => {
+ ...
+ rights => {
+ '* -> deleted' => 'DeleteTicket',
+ '* -> rejected' => 'RejectTicket',
+ '* -> *' => 'ModifyTicket',
+ },
+ ...
+ },
+
+This would create a new C<RejectTicket> right in the system which you
+could assign to whatever groups you choose.
+
+On the left hand side you can have the following variants:
+
+ '<from> -> <to>'
+ '* -> <to>'
+ '<from> -> *'
+ '* -> *'
+
+Valid transitions are listed in order of priority. If a user attempts
+to change a ticket's status from B<new> to B<open> then the lifecycle
+is checked for presence of an exact match, then for 'any to B<open>',
+'B<new> to any' and finally 'any to any'.
+
+If you don't define any rights, or there is no match for a transition,
+RT will use the B<DeleteTicket> or B<ModifyTicket> as appropriate.
+
+=head3 Labeling and defining actions
+
+For each transition you can define an action that will be shown in the
+UI; each action annotated with a label and an update type.
+
+Each action may provide a default update type, which can be
+B<Comment>, B<Respond>, or absent. For example, you may want your
+staff to write a reply to the end user when they change status from
+B<new> to B<open>, and thus set the update to B<Respond>. Neither
+B<Comment> nor B<Respond> are mandatory, and user may leave the
+message empty, regardless of the update type.
+
+This configuration can be used to accomplish what
+$ResolveDefaultUpdateType was used for in RT 3.8.
+
+Use the following format to define labels and actions of transitions:
+
+ default => {
+ ...
+ actions => [
+ 'new -> open' => { label => 'Open it', update => 'Respond' },
+ 'new -> resolved' => { label => 'Resolve', update => 'Comment' },
+ 'new -> rejected' => { label => 'Reject', update => 'Respond' },
+ 'new -> deleted' => { label => 'Delete' },
+
+ 'open -> stalled' => { label => 'Stall', update => 'Comment' },
+ 'open -> resolved' => { label => 'Resolve', update => 'Comment' },
+ 'open -> rejected' => { label => 'Reject', update => 'Respond' },
+
+ 'stalled -> open' => { label => 'Open it' },
+ 'resolved -> open' => { label => 'Re-open', update => 'Comment' },
+ 'rejected -> open' => { label => 'Re-open', update => 'Comment' },
+ 'deleted -> open' => { label => 'Undelete' },
+ ],
+ ...
+ },
+
+In addition, you may define multiple actions for the same transition.
+Alternately, you may use '* -> x' to match more than one transition.
+For example:
+
+ default => {
+ ...
+ actions => [
+ ...
+ 'new -> rejected' => { label => 'Reject', update => 'Respond' },
+ 'new -> rejected' => { label => 'Quick Reject' },
+ ...
+ '* -> deleted' => { label => 'Delete' },
+ ...
+ ],
+ ...
+ },
+
+=head2 Moving tickets between queues with different lifecycles
+
+Unless there is an explicit mapping between statuses in two different
+lifecycles, you can not move tickets between queues with these
+lifecycles -- even if both use the exact same set of statuses.
+Such a mapping is defined as follows:
+
+ __maps__ => {
+ 'from lifecycle -> to lifecycle' => {
+ 'status in left lifecycle' => 'status in right lifecycle',
+ ...
+ },
+ ...
+ },
+
+=cut
+
+Set(%Lifecycles,
+ default => {
+ initial => [qw(new)], # loc_qw
+ active => [qw(open stalled)], # loc_qw
+ inactive => [qw(resolved rejected deleted)], # loc_qw
+
+ defaults => {
+ on_create => 'new',
+ on_merge => 'resolved',
+ approved => 'open',
+ denied => 'rejected',
+ reminder_on_open => 'open',
+ reminder_on_resolve => 'resolved',
+ },
+
+ transitions => {
+ "" => [qw(new open resolved)],
+
+ # from => [ to list ],
+ new => [qw( open stalled resolved rejected deleted)],
+ open => [qw(new stalled resolved rejected deleted)],
+ stalled => [qw(new open rejected resolved deleted)],
+ resolved => [qw(new open stalled rejected deleted)],
+ rejected => [qw(new open stalled resolved deleted)],
+ deleted => [qw(new open stalled rejected resolved )],
+ },
+ rights => {
+ '* -> deleted' => 'DeleteTicket',
+ '* -> *' => 'ModifyTicket',
+ },
+ actions => [
+ 'new -> open' => { label => 'Open It', update => 'Respond' }, # loc{label}
+ 'new -> resolved' => { label => 'Resolve', update => 'Comment' }, # loc{label}
+ 'new -> rejected' => { label => 'Reject', update => 'Respond' }, # loc{label}
+ 'new -> deleted' => { label => 'Delete', }, # loc{label}
+ 'open -> stalled' => { label => 'Stall', update => 'Comment' }, # loc{label}
+ 'open -> resolved' => { label => 'Resolve', update => 'Comment' }, # loc{label}
+ 'open -> rejected' => { label => 'Reject', update => 'Respond' }, # loc{label}
+ 'stalled -> open' => { label => 'Open It', }, # loc{label}
+ 'resolved -> open' => { label => 'Re-open', update => 'Comment' }, # loc{label}
+ 'rejected -> open' => { label => 'Re-open', update => 'Comment' }, # loc{label}
+ 'deleted -> open' => { label => 'Undelete', }, # loc{label}
+ ],
+ },
+# don't change lifecyle of the approvals, they are not capable to deal with
+# custom statuses
+ approvals => {
+ initial => [ 'new' ],
+ active => [ 'open', 'stalled' ],
+ inactive => [ 'resolved', 'rejected', 'deleted' ],
+
+ defaults => {
+ on_create => 'new',
+ on_merge => 'resolved',
+ reminder_on_open => 'open',
+ reminder_on_resolve => 'resolved',
+ },
+
+ transitions => {
+ '' => [qw(new open resolved)],
+
+ # from => [ to list ],
+ new => [qw(open stalled resolved rejected deleted)],
+ open => [qw(new stalled resolved rejected deleted)],
+ stalled => [qw(new open rejected resolved deleted)],
+ resolved => [qw(new open stalled rejected deleted)],
+ rejected => [qw(new open stalled resolved deleted)],
+ deleted => [qw(new open stalled rejected resolved)],
+ },
+ rights => {
+ '* -> deleted' => 'DeleteTicket',
+ '* -> rejected' => 'ModifyTicket',
+ '* -> *' => 'ModifyTicket',
+ },
+ actions => [
+ 'new -> open' => { label => 'Open It', update => 'Respond' }, # loc{label}
+ 'new -> resolved' => { label => 'Resolve', update => 'Comment' }, # loc{label}
+ 'new -> rejected' => { label => 'Reject', update => 'Respond' }, # loc{label}
+ 'new -> deleted' => { label => 'Delete', }, # loc{label}
+ 'open -> stalled' => { label => 'Stall', update => 'Comment' }, # loc{label}
+ 'open -> resolved' => { label => 'Resolve', update => 'Comment' }, # loc{label}
+ 'open -> rejected' => { label => 'Reject', update => 'Respond' }, # loc{label}
+ 'stalled -> open' => { label => 'Open It', }, # loc{label}
+ 'resolved -> open' => { label => 'Re-open', update => 'Comment' }, # loc{label}
+ 'rejected -> open' => { label => 'Re-open', update => 'Comment' }, # loc{label}
+ 'deleted -> open' => { label => 'Undelete', }, # loc{label}
+ ],
+ },
+);
+
+
+
+
+
+=head1 Administrative interface
+
+=over 4
+
+=item C<$ShowRTPortal>
+
+RT can show administrators a feed of recent RT releases and other
+related announcements and information from Best Practical on the top
+level Admin page. This feature helps you stay up to date on
+RT security announcements and version updates.
+
+RT provides this feature using an "iframe" on C</Admin/index.html>
+which asks the administrator's browser to show an inline page from
+Best Practical's website.
+
+If you'd rather not make this feature available to your
+administrators, set C<$ShowRTPortal> to 0.