Difference between revisions of "WorkFlow2"

From Request Tracker Wiki
Jump to navigation Jump to search
(Stage Advancer scrip)
(Main Scrip Setup)
Line 34: Line 34:
 
== Main Scrip Setup ==
 
== Main Scrip Setup ==
  
Create a Global Scrip with the following parameters;
+
Readers Note: Condition? Action? Template? Stage? Here are my guesses;
  
 
Condition: User Defined
 
Condition: User Defined
Line 49: Line 49:
  
 
  <nowiki>#example workflow.  Whatever you do, do NOT make '|' (a pipe symbol) the first character in a stagename
 
  <nowiki>#example workflow.  Whatever you do, do NOT make '|' (a pipe symbol) the first character in a stagename
      my @newcompworkflow = (
+
        my @newcompworkflow = (
            #  stagename              stagedesc                                                    owner      queue
+
              #  stagename              stagedesc                                                    owner      queue
            ["AskUserForSoftware", "please ask the user what specialized software they would like", "person1",  "mainhelpqueue"],
+
              ["AskUserForSoftware", "please ask the user what specialized software they would like", "person1",  "mainhelpqueue"],
            ["OrderNewComputer", "please order the user's new computer", "person1", "purchases"],
+
              ["OrderNewComputer", "please order the user's new computer", "person1", "purchases"],
            ["ImageMachine","please image the user's new machine","person2", "mainhelpqueue"],
+
              ["ImageMachine","please image the user's new machine","person2", "mainhelpqueue"],
            ["blah","please blah blah blah","person2","someotherqueue"],
+
              ["blah","please blah blah blah","person2","someotherqueue"],
      );
+
        );
      my %workflows = ();
+
        my %workflows = ();
      #Set workflow name to 'New Computer'
+
        #Set workflow name to 'New Computer'
      #Make as many workflows you want like the example above and define them here.
+
        #Make as many workflows you want like the example above and define them here.
      #The name here ('New Computer') will correspond to the possible values for the customfield WorkflowName, so add them  as values there.
+
        #The name here ('New Computer') will correspond to the possible values for the customfield WorkflowName, so add them  as values there.
      $workflows{'New Computer'} = \@newcompworkflow;
+
        $workflows{'New Computer'} = \@newcompworkflow;
      my $stagename = 0;
+
        my $stagename = 0;
      my $stagedesc = 1;
+
        my $stagedesc = 1;
      my $stageowner = 2;
+
        my $stageowner = 2;
      my $stagequeue = 3;
+
        my $stagequeue = 3;
      my $wfn = 'WorkflowName';
+
        my $wfn = 'WorkflowName';
      my $wfs = 'WorkflowStage';
+
        my $wfs = 'WorkflowStage';
      my $wfsd = 'WorkflowStageDesc';
+
        my $wfsd = 'WorkflowStageDesc';
      my $wfso = 'WorkflowStageOwner';
+
        my $wfso = 'WorkflowStageOwner';
      my $wfsq = 'WorkflowStageQueue';
+
        my $wfsq = 'WorkflowStageQueue';
     
+
       
        my $QueueObj = $self-&gt;TicketObj-&gt;QueueObj;
+
        my $QueueObj = $self-&gt;TicketObj-&gt;QueueObj;
      my $wfnobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser );
+
        my $wfnobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser );
        $wfnobj-&gt;LoadByNameAndQueue( Name =&gt; $wfn, Queue =&gt; $QueueObj-&gt;id );
+
        $wfnobj-&gt;LoadByNameAndQueue( Name =&gt; $wfn, Queue =&gt; $QueueObj-&gt;id );
        unless( $wfnobj-&gt;id ) {
+
        unless( $wfnobj-&gt;id ) {
          $wfnobj-&gt;LoadByNameAndQueue( Name =&gt; $wfn, Queue =&gt; 0 );
+
          $wfnobj-&gt;LoadByNameAndQueue( Name =&gt; $wfn, Queue =&gt; 0 );
          unless( $wfnobj-&gt;id ) {
+
          unless( $wfnobj-&gt;id ) {
            $RT::Logger-&gt;warning("custom field '$wfn' isn't global or defined for queue '". $QueueObj-&gt;Name ."'");
+
            $RT::Logger-&gt;warning("custom field '$wfn' isn't global or defined for queue '". $QueueObj-&gt;Name ."'");
            return undef;
+
            return undef;
          }
+
          }
 +
        }
 +
       
 +
        my $wfsobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser );
 +
        $wfsobj-&gt;LoadByNameAndQueue( Name =&gt; $wfs, Queue =&gt; $QueueObj-&gt;id );
 +
        unless( $wfsobj-&gt;id ) {
 +
          $wfsobj-&gt;LoadByNameAndQueue( Name =&gt; $wfs, Queue =&gt; 0 );
 +
          unless( $wfsobj-&gt;id ) {
 +
            $RT::Logger-&gt;warning("custom field '$wfs' isn't global or defined for queue '". $QueueObj-&gt;Name ."'");
 +
            return undef;
 +
          }
 +
        }
 +
        my $wfsdobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser );
 +
        $wfsdobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsd, Queue =&gt; $QueueObj-&gt;id );
 +
        unless( $wfsdobj-&gt;id ) {
 +
          $wfsdobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsd, Queue =&gt; 0 );
 +
          unless( $wfsdobj-&gt;id ) {
 +
            $RT::Logger-&gt;warning("custom field '$wfsd' isn't global or defined for queue '". $QueueObj-&gt;Name ."'");
 +
            return undef;
 +
          }
 +
        }
 +
       
 +
        my $wfsoobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser );
 +
        $wfsoobj-&gt;LoadByNameAndQueue( Name =&gt; $wfso, Queue =&gt; $QueueObj-&gt;id );
 +
        unless( $wfsoobj-&gt;id ) {
 +
          $wfsoobj-&gt;LoadByNameAndQueue( Name =&gt; $wfso, Queue =&gt; 0 );
 +
          unless( $wfsoobj-&gt;id ) {
 +
            $RT::Logger-&gt;warning("custom field '$wfso' isn't global or defined for queue '". $QueueObj-&gt;Name ."'");
 +
            return undef;
 +
          }
 +
        }
 +
        my $wfsqobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser );
 +
        $wfsqobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsq, Queue =&gt; $QueueObj-&gt;id );
 +
        unless( $wfsqobj-&gt;id ) {
 +
          $wfsqobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsq, Queue =&gt; 0 );
 +
          unless( $wfsqobj-&gt;id ) {
 +
            $RT::Logger-&gt;warning("custom field '$wfsq' isn't global or defined for queue '". $QueueObj-&gt;Name ."'");
 +
            return undef;
 +
          }
 +
        }
 +
       
 +
        #See if this ticket is part of a workflow
 +
        my $wfname = $self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowName');
 +
        my @workflow;
 +
        if ($wfname ne '') {
 +
            @workflow = @{$workflows{$wfname}};
 
         }
 
         }
     
+
       
         my $wfsobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser );
+
        #If the customfield workflowname was just set, then set workflowstage to the first stage of that workflow
        $wfsobj-&gt;LoadByNameAndQueue( Name =&gt; $wfs, Queue =&gt; $QueueObj-&gt;id );
+
         if ( ( $self-&gt;TransactionObj-&gt;Type eq 'CustomField' ) &amp;&amp;
         unless( $wfsobj-&gt;id ) {
+
            ($self-&gt;TransactionObj-&gt;Field == $wfnobj-&gt;id) ) {
          $wfsobj-&gt;LoadByNameAndQueue( Name =&gt; $wfs, Queue =&gt; 0 );
+
          
          unless( $wfsobj-&gt;id ) {
+
                if ($workflows{$wfname}) {
            $RT::Logger-&gt;warning("custom field '$wfs' isn't global or defined for queue '". $QueueObj-&gt;Name ."'");
+
                    my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue(
            return undef;
+
                                                Field =&gt; $wfsobj-&gt;id,
          }
+
                                                Value =&gt; $workflow[0][$stagename],
 +
                                                RecordTransaction =&gt; 1 );
 +
                }
 +
                return undef;
 +
              #even though this did what we wanted it to, return undef because we have no email to send at this point
 
         }
 
         }
         my $wfsdobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser );
+
         #if we dont have a workflow by now, bail
      $wfsdobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsd, Queue =&gt; $QueueObj-&gt;id );
+
         if (!@workflow) {
         unless( $wfsdobj-&gt;id ) {
+
          return undef;
          $wfsdobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsd, Queue =&gt; 0 );
 
          unless( $wfsdobj-&gt;id ) {
 
            $RT::Logger-&gt;warning("custom field '$wfsd' isn't global or defined for queue '". $QueueObj-&gt;Name ."'");
 
            return undef;
 
          }
 
 
         }
 
         }
     
+
        #if the workflowstage is prefixed by a '|', advance to the next workflow stage in the sequence, or 'completed' if  it's done
         my $wfsoobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser );
+
        #because completion generates no notice, i'd recommend having the last item in your workflow be a notification of the responsible party
      $wfsoobj-&gt;LoadByNameAndQueue( Name =&gt; $wfso, Queue =&gt; $QueueObj-&gt;id );
+
       
        unless( $wfsoobj-&gt;id ) {
+
         if ( ($self-&gt;TransactionObj-&gt;Type eq "CustomField") &amp;&amp;
          $wfsoobj-&gt;LoadByNameAndQueue( Name =&gt; $wfso, Queue =&gt; 0 );
+
              ($self-&gt;TransactionObj-&gt;Field == $wfsobj-&gt;id) ) {
          unless( $wfsoobj-&gt;id ) {
+
          if (substr($self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowStage'), 0, 1) eq '|') {
            $RT::Logger-&gt;warning("custom field '$wfso' isn't global or defined for queue '". $QueueObj-&gt;Name ."'");
+
              my $x = 0;
            return undef;
+
              for ($x=0;$x&lt;@workflow;$x++) {
          }
+
                    if ($workflow[$x][$stagename] eq substr($self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowStage'), 1)) {
        }
+
                          my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue(
        my $wfsqobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser );
+
                                                Field =&gt; $wfsobj-&gt;id,
      $wfsqobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsq, Queue =&gt; $QueueObj-&gt;id );
+
                                                Value =&gt; ($x == $#workflow) ? 'Completed' : $workflow[$x+1][$stagename],
         unless( $wfsqobj-&gt;id ) {
+
                                                RecordTransaction =&gt; 1 );
          $wfsqobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsq, Queue =&gt; 0 );
+
                    }
          unless( $wfsqobj-&gt;id ) {
+
              }
            $RT::Logger-&gt;warning("custom field '$wfsq' isn't global or defined for queue '". $QueueObj-&gt;Name ."'");
+
              return undef;
            return undef;
+
          }
          }
+
          #If the workflowstage was just set, update the corresponding description, owner, and queue, and send off the new ticket
 +
          my $x = 0;
 +
          for ($x =0;$x&lt;@workflow;$x++) {
 +
              if ($workflow[$x][$stagename] eq $self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowStage')) {
 +
          my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue(
 +
                                                Field =&gt; $wfsdobj-&gt;id,
 +
                                                Value =&gt; $workflow[$x][$stagedesc],
 +
                                                RecordTransaction =&gt; 0 );
 +
          
 +
              my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue(
 +
                                                Field =&gt; $wfsoobj-&gt;id,
 +
                                                Value =&gt; $workflow[$x][$stageowner],
 +
                                                RecordTransaction =&gt; 0 );
 +
              my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue(
 +
                                                Field =&gt; $wfsqobj-&gt;id,
 +
                                                Value =&gt; $workflow[$x][$stagequeue],
 +
                                                RecordTransaction =&gt; 0 );
 +
       
 +
          return 1;
 +
              }
 +
          }
 +
       
 
         }
 
         }
     
+
        return undef;
      #See if this ticket is part of a workflow
+
       
      my $wfname = $self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowName');
+
        </nowiki>
      my @workflow;
 
      if ($wfname ne '') {
 
            @workflow = @{$workflows{$wfname}};
 
      }
 
     
 
      #If the customfield workflowname was just set, then set workflowstage to the first stage of that workflow
 
      if ( ( $self-&gt;TransactionObj-&gt;Type eq 'CustomField' ) &amp;&amp;
 
          ($self-&gt;TransactionObj-&gt;Field == $wfnobj-&gt;id) ) {
 
     
 
              if ($workflows{$wfname}) {
 
                  my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue(
 
                                                Field =&gt; $wfsobj-&gt;id,
 
                                                Value =&gt; $workflow[0][$stagename],
 
                                                RecordTransaction =&gt; 1 );
 
              }
 
                return undef;
 
              #even though this did what we wanted it to, return undef because we have no email to send at this point
 
      }
 
      #if we dont have a workflow by now, bail
 
      if (!@workflow) {
 
          return undef;
 
      }
 
      #if the workflowstage is prefixed by a '|', advance to the next workflow stage in the sequence, or 'completed' if  it's done
 
      #because completion generates no notice, i'd recommend having the last item in your workflow be a notification of the responsible party
 
     
 
      if ( ($self-&gt;TransactionObj-&gt;Type eq "CustomField") &amp;&amp;
 
            ($self-&gt;TransactionObj-&gt;Field == $wfsobj-&gt;id) ) {
 
          if (substr($self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowStage'), 0, 1) eq '|') {
 
              my $x = 0;
 
              for ($x=0;$x&lt;@workflow;$x++) {
 
                  if ($workflow[$x][$stagename] eq substr($self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowStage'), 1)) {
 
                          my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue(
 
                                                Field =&gt; $wfsobj-&gt;id,
 
                                                Value =&gt; ($x == $#workflow) ? 'Completed' : $workflow[$x+1][$stagename],
 
                                                RecordTransaction =&gt; 1 );
 
                  }
 
              }
 
              return undef;
 
          }
 
          #If the workflowstage was just set, update the corresponding description, owner, and queue, and send off the new ticket
 
          my $x = 0;
 
          for ($x =0;$x&lt;@workflow;$x++) {
 
            if ($workflow[$x][$stagename] eq $self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowStage')) {
 
          my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue(
 
                                                Field =&gt; $wfsdobj-&gt;id,
 
                                                Value =&gt; $workflow[$x][$stagedesc],
 
                                                RecordTransaction =&gt; 0 );
 
     
 
              my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue(
 
                                                Field =&gt; $wfsoobj-&gt;id,
 
                                                Value =&gt; $workflow[$x][$stageowner],
 
                                                RecordTransaction =&gt; 0 );
 
              my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue(
 
                                                Field =&gt; $wfsqobj-&gt;id,
 
                                                Value =&gt; $workflow[$x][$stagequeue],
 
                                                RecordTransaction =&gt; 0 );
 
     
 
          return 1;
 
              }
 
          }
 
     
 
      }
 
      return undef;
 
     
 
      </nowiki>
 
  
 
I apologize for the terrible formatting, if someone has a perl formatter handy feel free to have at it ;)
 
I apologize for the terrible formatting, if someone has a perl formatter handy feel free to have at it ;)

Revision as of 19:16, 13 July 2011

Another kind of workflow for RT

This method draws heavily on the other workflow plugin and from many contributions here in general, so I definitely don't claim ownership of all the code/methods (thx guys :)) In the original workflow plugin, customfields were defined for each task and initiated manually, with (potentially) all the tasks running concurrently (as subtickets). In this model, one master ticket initiates a child ticket for the first task, when the first child is resolved the second child ticket is initiated etc. In addition, this method allows a name, description, queue, and owner for each subticket (stage) of the process. Also, this reduces the number of scrips+templates+customfields to a constant number, regardless of how many workflows you have.

Custom Field Setup

Add 5 (ticket) custom fields and activate them globally using the following names:

WorkflowName

WorkflowStage

WorkflowStageDesc

WorkflowStageOwner

WorkflowstageQueue

All of these should be "enter a value" fields with the exception of WorkflowName, which should be a "select one value" field.

Template Setup

Add a single global template called "WorkflowTemplate" that consists of the following:

===Create-Ticket: {$Tickets{'TOP'}->FirstCustomFieldValue('WorkflowName');}::{$Tickets{'TOP'}->FirstCustomFieldValue('WorkflowStage');} Subject: Workflow::{$Tickets{'TOP'}->Subject;} Parents: TOP Queue: {$Tickets{'TOP'}->FirstCustomFieldValue('WorkflowStageQueue');} Owner: {$Tickets{'TOP'}->FirstCustomFieldValue('WorkflowStageOwner');} Content: {$Tickets{'TOP'}->FirstCustomFieldValue('WorkflowStageDesc');} ENDOFCONTENT

Main Scrip Setup

Readers Note: Condition? Action? Template? Stage? Here are my guesses;

Condition: User Defined

Action: Create Tickets

Template: WorkflowTemplate

Stage: TransactionCreate

Beware, this scrip is pretty ugly. Basically, it's a ticket creation scrip that performs a lot more than condition checking in the condition section (i didnt wanna mess around with making a new ticket from a template in the scrip, and this was easy).

Paste the code below into the "Custom Condition" text box

#example workflow. Whatever you do, do NOT make '|' (a pipe symbol) the first character in a stagename my @newcompworkflow = ( # stagename stagedesc owner queue ["AskUserForSoftware", "please ask the user what specialized software they would like", "person1", "mainhelpqueue"], ["OrderNewComputer", "please order the user's new computer", "person1", "purchases"], ["ImageMachine","please image the user's new machine","person2", "mainhelpqueue"], ["blah","please blah blah blah","person2","someotherqueue"], ); my %workflows = (); #Set workflow name to 'New Computer' #Make as many workflows you want like the example above and define them here. #The name here ('New Computer') will correspond to the possible values for the customfield WorkflowName, so add them as values there. $workflows{'New Computer'} = \@newcompworkflow; my $stagename = 0; my $stagedesc = 1; my $stageowner = 2; my $stagequeue = 3; my $wfn = 'WorkflowName'; my $wfs = 'WorkflowStage'; my $wfsd = 'WorkflowStageDesc'; my $wfso = 'WorkflowStageOwner'; my $wfsq = 'WorkflowStageQueue'; <code><pre> my $QueueObj = $self-&gt;TicketObj-&gt;QueueObj; my $wfnobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser ); $wfnobj-&gt;LoadByNameAndQueue( Name =&gt; $wfn, Queue =&gt; $QueueObj-&gt;id ); unless( $wfnobj-&gt;id ) { $wfnobj-&gt;LoadByNameAndQueue( Name =&gt; $wfn, Queue =&gt; 0 ); unless( $wfnobj-&gt;id ) { $RT::Logger-&gt;warning("custom field '$wfn' isn't global or defined for queue '". $QueueObj-&gt;Name ."'"); return undef; } } my $wfsobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser ); $wfsobj-&gt;LoadByNameAndQueue( Name =&gt; $wfs, Queue =&gt; $QueueObj-&gt;id ); unless( $wfsobj-&gt;id ) { $wfsobj-&gt;LoadByNameAndQueue( Name =&gt; $wfs, Queue =&gt; 0 ); unless( $wfsobj-&gt;id ) { $RT::Logger-&gt;warning("custom field '$wfs' isn't global or defined for queue '". $QueueObj-&gt;Name ."'"); return undef; } } my $wfsdobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser ); $wfsdobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsd, Queue =&gt; $QueueObj-&gt;id ); unless( $wfsdobj-&gt;id ) { $wfsdobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsd, Queue =&gt; 0 ); unless( $wfsdobj-&gt;id ) { $RT::Logger-&gt;warning("custom field '$wfsd' isn't global or defined for queue '". $QueueObj-&gt;Name ."'"); return undef; } } my $wfsoobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser ); $wfsoobj-&gt;LoadByNameAndQueue( Name =&gt; $wfso, Queue =&gt; $QueueObj-&gt;id ); unless( $wfsoobj-&gt;id ) { $wfsoobj-&gt;LoadByNameAndQueue( Name =&gt; $wfso, Queue =&gt; 0 ); unless( $wfsoobj-&gt;id ) { $RT::Logger-&gt;warning("custom field '$wfso' isn't global or defined for queue '". $QueueObj-&gt;Name ."'"); return undef; } } my $wfsqobj = RT::CustomField-&gt;new( $QueueObj-&gt;CurrentUser ); $wfsqobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsq, Queue =&gt; $QueueObj-&gt;id ); unless( $wfsqobj-&gt;id ) { $wfsqobj-&gt;LoadByNameAndQueue( Name =&gt; $wfsq, Queue =&gt; 0 ); unless( $wfsqobj-&gt;id ) { $RT::Logger-&gt;warning("custom field '$wfsq' isn't global or defined for queue '". $QueueObj-&gt;Name ."'"); return undef; } } #See if this ticket is part of a workflow my $wfname = $self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowName'); my @workflow; if ($wfname ne '') { @workflow = @{$workflows{$wfname}}; } #If the customfield workflowname was just set, then set workflowstage to the first stage of that workflow if ( ( $self-&gt;TransactionObj-&gt;Type eq 'CustomField' ) &amp;&amp; ($self-&gt;TransactionObj-&gt;Field == $wfnobj-&gt;id) ) { if ($workflows{$wfname}) { my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue( Field =&gt; $wfsobj-&gt;id, Value =&gt; $workflow[0][$stagename], RecordTransaction =&gt; 1 ); } return undef; #even though this did what we wanted it to, return undef because we have no email to send at this point } #if we dont have a workflow by now, bail if (!@workflow) { return undef; } #if the workflowstage is prefixed by a '|', advance to the next workflow stage in the sequence, or 'completed' if it's done #because completion generates no notice, i'd recommend having the last item in your workflow be a notification of the responsible party if ( ($self-&gt;TransactionObj-&gt;Type eq "CustomField") &amp;&amp; ($self-&gt;TransactionObj-&gt;Field == $wfsobj-&gt;id) ) { if (substr($self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowStage'), 0, 1) eq '|') { my $x = 0; for ($x=0;$x&lt;@workflow;$x++) { if ($workflow[$x][$stagename] eq substr($self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowStage'), 1)) { my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue( Field =&gt; $wfsobj-&gt;id, Value =&gt; ($x == $#workflow) ? 'Completed' : $workflow[$x+1][$stagename], RecordTransaction =&gt; 1 ); } } return undef; } #If the workflowstage was just set, update the corresponding description, owner, and queue, and send off the new ticket my $x = 0; for ($x =0;$x&lt;@workflow;$x++) { if ($workflow[$x][$stagename] eq $self-&gt;TicketObj-&gt;FirstCustomFieldValue('WorkflowStage')) { my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue( Field =&gt; $wfsdobj-&gt;id, Value =&gt; $workflow[$x][$stagedesc], RecordTransaction =&gt; 0 ); my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue( Field =&gt; $wfsoobj-&gt;id, Value =&gt; $workflow[$x][$stageowner], RecordTransaction =&gt; 0 ); my( $st, $msg ) = $self-&gt;TicketObj-&gt;AddCustomFieldValue( Field =&gt; $wfsqobj-&gt;id, Value =&gt; $workflow[$x][$stagequeue], RecordTransaction =&gt; 0 ); return 1; } } } return undef; </nowiki> </pre></code> I apologize for the terrible formatting, if someone has a perl formatter handy feel free to have at it ;) == Stage Advancer scrip == The second scrip (also global) is responsible for changing the workflowstage from "stagename" to "|stagename" on the resolution of a child ticket. This is all that is necessary for the main scrip to notice that it is time to advance to the next stage. Readers Note: <sigh> Condition? Action? Template? Stage? <nowiki>my $MemberOf = $self->TicketObj->MemberOf; my $l = $MemberOf->Next; my $parentObj = $l->TargetObj; my $QueueObj = $parentObj->QueueObj; my $wfs = 'WorkflowStage'; my $wfsobj = RT::CustomField->new( $QueueObj->CurrentUser ); $wfsobj->LoadByNameAndQueue( Name => $wfs, Queue => $QueueObj->id ); unless( $wfsobj->id ) { $wfsobj->LoadByNameAndQueue( Name => $wfs, Queue => 0 ); unless( $wfsobj->id ) { $RT::Logger->warning("custom field '$wfs' isn't global or defined for queue '". $QueueObj->Name ."'"); return undef; } } my $curval = $parentObj->FirstCustomFieldValue('WorkflowStage'); if ($curval ne '') { my( $st, $msg ) = $parentObj->AddCustomFieldValue( Field => $wfsobj->id, Value => '|' . $curval, RecordTransaction => 1 ); return 1; } return undef;

Kicking it off

I don't know how to make it work on create because the object doesnt exist yet, but if you create a ticket and then update the workflowname, the scrip will automatically initiate the first stage and create the first child ticket. As explained in the code comments, I'd recommend having the last phase of a workflow be creating a ticket to notify the responsible party that the sequence is complete, because currently nothing happens after the last step.

Hope this helps someone