WorkFlow2: Difference between revisions

From Request Tracker Wiki
Jump to navigation Jump to search
Line 36: Line 36:
On User Defined Create Tickets with Template (aforementioned) (Global) 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).
On User Defined Create Tickets with Template (aforementioned) (Global) 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).


Readers Note: From the veiwpoint of a non RT guru, this step is incomprehensible. When you create a scrip, you need to set Condition, Actiion, Template and Stage parameters (RT3.6). The correct settings for these are not provided. Also, where does one paste the code? I assume that it goes in the Custom Condition box but I really hate having to assume stuff when following instructions.
Readers Note: From the veiwpoint of a non RT guru, this step is incomprehensible. What does "On User Defined Create Tickets with Template (aforementioned) (Global)" mean? Also, when you create a scrip, you need to set Condition, Actiion, Template and Stage parameters (RT3.6). The correct settings for these are not provided. Also, where does one paste the code? I assume that it goes in the Custom Condition box but I really hate having to assume stuff when following instructions.


  <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 18:40, 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 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

On User Defined Create Tickets with Template (aforementioned) (Global) 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).

Readers Note: From the veiwpoint of a non RT guru, this step is incomprehensible. What does "On User Defined Create Tickets with Template (aforementioned) (Global)" mean? Also, when you create a scrip, you need to set Condition, Actiion, Template and Stage parameters (RT3.6). The correct settings for these are not provided. Also, where does one paste the code? I assume that it goes in the Custom Condition box but I really hate having to assume stuff when following instructions.

#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';
    
     my $QueueObj = $self->TicketObj->QueueObj;
    my $wfnobj = RT::CustomField->new( $QueueObj->CurrentUser );
     $wfnobj->LoadByNameAndQueue( Name => $wfn, Queue => $QueueObj->id );
     unless( $wfnobj->id ) {
       $wfnobj->LoadByNameAndQueue( Name => $wfn, Queue => 0 );
       unless( $wfnobj->id ) {
         $RT::Logger->warning("custom field '$wfn' isn't global or defined for queue '". $QueueObj->Name ."'");
         return undef;
       }
     }
    
     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 $wfsdobj = RT::CustomField->new( $QueueObj->CurrentUser );
    $wfsdobj->LoadByNameAndQueue( Name => $wfsd, Queue => $QueueObj->id );
     unless( $wfsdobj->id ) {
       $wfsdobj->LoadByNameAndQueue( Name => $wfsd, Queue => 0 );
       unless( $wfsdobj->id ) {
         $RT::Logger->warning("custom field '$wfsd' isn't global or defined for queue '". $QueueObj->Name ."'");
         return undef;
       }
     }
    
     my $wfsoobj = RT::CustomField->new( $QueueObj->CurrentUser );
    $wfsoobj->LoadByNameAndQueue( Name => $wfso, Queue => $QueueObj->id );
     unless( $wfsoobj->id ) {
       $wfsoobj->LoadByNameAndQueue( Name => $wfso, Queue => 0 );
       unless( $wfsoobj->id ) {
         $RT::Logger->warning("custom field '$wfso' isn't global or defined for queue '". $QueueObj->Name ."'");
         return undef;
       }
     }
     my $wfsqobj = RT::CustomField->new( $QueueObj->CurrentUser );
    $wfsqobj->LoadByNameAndQueue( Name => $wfsq, Queue => $QueueObj->id );
     unless( $wfsqobj->id ) {
       $wfsqobj->LoadByNameAndQueue( Name => $wfsq, Queue => 0 );
       unless( $wfsqobj->id ) {
         $RT::Logger->warning("custom field '$wfsq' isn't global or defined for queue '". $QueueObj->Name ."'");
         return undef;
       }
     }
    
    #See if this ticket is part of a workflow
    my $wfname = $self->TicketObj->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->TransactionObj->Type eq 'CustomField' ) &&
        ($self->TransactionObj->Field == $wfnobj->id) ) {
    
            if ($workflows{$wfname}) {
                my( $st, $msg ) = $self->TicketObj->AddCustomFieldValue(
                                             Field => $wfsobj->id,
                                             Value => $workflow[0][$stagename],
                                             RecordTransaction => 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->TransactionObj->Type eq "CustomField") &&
          ($self->TransactionObj->Field == $wfsobj->id) ) {
       if (substr($self->TicketObj->FirstCustomFieldValue('WorkflowStage'), 0, 1) eq '|') {
           my $x = 0;
           for ($x=0;$x<@workflow;$x++) {
                if ($workflow[$x][$stagename] eq substr($self->TicketObj->FirstCustomFieldValue('WorkflowStage'), 1)) {
                       my( $st, $msg ) = $self->TicketObj->AddCustomFieldValue(
                                             Field => $wfsobj->id,
                                             Value => ($x == $#workflow) ? 'Completed' : $workflow[$x+1][$stagename],
                                             RecordTransaction => 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<@workflow;$x++) {
          if ($workflow[$x][$stagename] eq $self->TicketObj->FirstCustomFieldValue('WorkflowStage')) {
       my( $st, $msg ) = $self->TicketObj->AddCustomFieldValue(
                                             Field => $wfsdobj->id,
                                             Value => $workflow[$x][$stagedesc],
                                             RecordTransaction => 0 );
    
           my( $st, $msg ) = $self->TicketObj->AddCustomFieldValue(
                                             Field => $wfsoobj->id,
                                             Value => $workflow[$x][$stageowner],
                                             RecordTransaction => 0 );
           my( $st, $msg ) = $self->TicketObj->AddCustomFieldValue(
                                             Field => $wfsqobj->id,
                                             Value => $workflow[$x][$stagequeue],
                                             RecordTransaction => 0 );
    
       return 1;
           }
       }
    
    }
    return undef;
    
    

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.

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