CreateTickets Scrip based on Custom Field selection

I’m trying to automatically generate tickets on the creation of a ticket. Multiple tickets will be created, but it depends on what is chosen in a custom field on the ticket.

I’m playing around with creating a Scrip to do this:

Description: On Create Spawn Tickets
Condition: On Create
Action: Create Tickets
Template: Spawn Template

Where Spawn Template contains the data needed to generate a new ticket, for example:
===Create-Ticket: test1
Queue: Test
Subject: {Tickets{‘TOP’}->Subject} - Test Reference Ticket
Status: new
RefersTo: TOP
CustomField-134: Value A
CustomField-135: Value B
Content: This ticket tests spawning references tickets.
ENDOFCONTENT

However, I don’t believe the given scrips can accommodate a custom set of tickets based on the custom field value that is selected.

I can write a custom user defined action to trap which value is selected in the custom field, but how do I call RT::Action::CreateTickets within the scrip to generate my custom list of tickets?

Thanks in advance!

Edit: fixed format errors in template example.

According to the RT::Action::CreateTickets documentation, you can “embed snippets of Perl inside the Text::Template using {} delimiters”. This should mean that your “Spawn Template” can have embedded Perl logic to look at the state of custom fields and then determine what to create on that basis (assuming I’m understanding what you are trying to do correctly).

Hi GreenJimll,

I see now… so I could simply use the original Scrip such as:

Description: On Create Spawn Tickets
Condition: On Create
Action: Create Tickets
Template: Spawn Template

And embed some perl within it to choose which templates to actually use based on which custom field is selected in the original ticket.

Could you help me spell it out a bit? So perhaps in CustomField, I have the following values to choose from: Value A, Value B, and Value C.

Perhaps my Spawn Template contains the following templates:
===Create-Ticket: testA
Queue: Test
Subject: {Tickets{‘TOP’}->Subject} - Test Reference Ticket
Status: ‘new’
RefersTo: TOP
CustomField-134: ‘Value A’
CustomField-135: ‘Value B’
Content: This ticket tests spawning references tickets.
ENDOFCONTENT

===Create-Ticket: testB
Queue: Test
Subject: {Tickets{‘TOP’}->Subject} - Test Reference Ticket
Status: ‘new’
RefersTo: TOP
CustomField-134: ‘Value A’
CustomField-135: ‘Value B’
Content: This ticket tests spawning references tickets.
ENDOFCONTENT

===Create-Ticket: testC
Queue: Test
Subject: {Tickets{‘TOP’}->Subject} - Test Reference Ticket
Status: ‘new’
RefersTo: TOP
CustomField-134: ‘Value A’
CustomField-135: ‘Value B’
Content: This ticket tests spawning references tickets.
ENDOFCONTENT

Can you help point me in the direction as to how I would add perl to this template to select only the testA template if Value A is selected, testB if Value B is selected, etc.?

Thanks!

Also, based on the description of Text::Template within the RT::Action::CreateTickets documentation, it seems that perl is only allowed within the ===Create-Ticket: boundary. Meaning I would have to add perl to each ===Create-Ticket: boundary individually instead of say:

if (CustomField = ‘Value A’) {
===Create-Ticket: testA
… add parameters…
ENDOFCONTENT
===Create-Ticket: testX
… add parameters…
ENDOFCONTENT
} elsif (CustomField = ‘Value B’) {
===Create-Ticket: testB
… add parameters…
ENDOFCONTENT
===Create-Ticket: testY
… add parameters…
ENDOFCONTENT
}

I guess I’m just not sure how or where the conditional check would be added inside of the ===Create-Ticket: boundary.

Thanks.

I guess when it comes down to it, I’d love to just call the methods from RT::Action::CreateTickets directly in a user defined action, and feed it an existing Template instead of using the Scrip builder. That way, I can write my conditional logic in and just create the tickets with the defined templates. Obviously the code below is wrong, but the idea looks something like:

use RT::Action::CreateTickets;
use RT::Template;

my $creation = RT::Action::CreateTickets->new($RT::SystemUser);
my $template = RT::Template->new($RT::SystemUser);

if (CustomField = ‘Value A’) {
$template->LoadByName( Name => ‘Value A Template’, Queue => ‘Test’ );
$creation->Create( Template => ‘$template’ );
} elsif (CustomField = ‘Value B’) {
$template->LoadByName( Name => ‘Value B Template’, Queue => ‘Test’ );
$creation->Create( Template => ‘$template’ );
}

…etc…

The RT::Action::CreateTickets module doesn’t have a ‘Create’ method, only methods for Parsing. Clearly these methods need to be used in some manner… but I have no idea how.

Can anyone help me out or clear up any misunderstandings I might be having?

Thanks.

I got this figured out. While it may not have been the ideal solution, it works for me. Since I couldn’t make calling methods in a user-defined Action scrip from the RT::Action::CreateTickets module work, I just yanked /opt/rt4/lib/Actions/CreateTickets.pm and localized it as a different name, such as CreateTicketsByCustomField.pm.

I modified the Prepare sub to include logic determining which value was selected in an explicitly defined Custom Field object. It then finds a template with an explicitly defined name that is appended by the value of the custom field selection. If the explicitly defined name is Tasks- and the custom field value selected is ‘ValueA’, it would attempt to load a template named “Tasks-ValueA” within an explicitly defined Queue (by id). Based on the documentation of $template->LoadByName, you can leave off the Queue argument to search for the template globally. I chose not to.

It would be nice to make it more dynamic so that a parameter could be passed to use any Custom Field object, for example, but I’m not sure how to accomplish that right now.

With this code, I can create and use as many templates as I want and as long as they match the naming convention of what’s expected. The benefit is that a completely different set of tickets can be automatically created based on what value is selected in the custom field.

This was added as a new Action, then referenced in a Scrip Action. The Condition is ‘On Create’, Action is ‘Create Tickets By Custom Field’, and Template is “blank”, as that is dynamically determined by what’s selected in the custom field.

Here’s the modified & sanitized Prepare sub for anyone interested.

sub Prepare {
my $self = shift;
$RT::Logger->debug(“In Prepare”);

# load Custom Field and get it's ID
$RT::Logger->debug("Setting CFName");
my $CFname = 'Test';
my $CF = RT::CustomField->new(RT->SystemUser);
$CF->LoadByName(Name => $CFname);
my $CF_ID = $CF->Id();

# Ensure $CF was loaded with the desired and valid custom field object
$RT::Logger->debug("Checking CF object");
unless ($CF) {
    $RT::Logger->warning("No CustomField by name $CFname found. Skipping additional ticket creations.");
    return 0;
};

# Load the select value of $CF into $CFvalue
$RT::Logger->debug("loading CF value into CFvalue");
my $CFvalue = $self->TicketObj->FirstCustomFieldValue($CF_ID);

# If $CFvalue has something in it, set the $TemplateToLoad variable, otherwise quit.
$RT::Logger->debug("Checking CFvalue");
unless ( $CFvalue ) {
    $RT::Logger->warning("No value selected in $CFname. Skipping additional ticket creations.");
    return 0;
};
$RT::Logger->debug("Got CFvalue: $CFvalue");

my $TemplateToLoad;
$RT::Logger->debug("Loaded CF value: $CFvalue");


$TemplateToLoad = "Tasks-$CFvalue";

# set the template to match what was selected in $CFvalue
$RT::Logger->debug("Creating Template object");
my $template = RT::Template->new($RT::SystemUser);

# Need to use Queue ID here, not name. Omit Queue argument if searching global templates.
$RT::Logger->debug("Loading selected CF value as a Template");
my ($result, $msg) = $template->LoadByName(
    Name => $TemplateToLoad,
    Queue => 3,
);
# If the template doesn't exist, quit.
unless ($result) {
    $RT::Logger->error("Couldn't find a template named $TemplateToLoad. Skipping additional ticket creations. Error message: $msg");
    return 0;
};

my $templatename = $template->Name;
$RT::Logger->debug("Template loaded has name $templatename" );

# Replaced $self->TemplateObj with $template below.  The rest of the code is original RT code.
unless ( $template ) {
    $RT::Logger->warning("No template object handed to $self");
}

unless ( $self->TransactionObj ) {
    $RT::Logger->warning("No transaction object handed to $self");

}

unless ( $self->TicketObj ) {
    $RT::Logger->warning("No ticket object handed to $self");

}

my $active = 0;
if ( $template->Type eq 'Perl' ) {
    $active = 1;
} else {
    RT->Logger->info(sprintf(
        "Template #%d is type %s.  You most likely want to use a Perl template instead.",
        $template->id, $template->Type
    ));
}

$self->Parse(
    Content        => $template->Content,
    _ActiveContent => $active,
);
return 1;

}