We had a request from one of our service desk folk recently, asking if there was a simple way they could take an email correspondence transaction for an existing ticket and turn it into a new ticket. This came about because some end users were asking for more than one thing at the same time, and if different teams had to deal with each request it either had to be done serially with tickets bouncing back and forth between different teams’ queues, or the service desk had to raise new tickets themselves.
So I put my hacking slippers on and in case this is useful to others, here’s what I’ve got so far. My solution is in two parts: a callback on the /Elements/ShowTransactionPage
and a new local Mason page called ``/Ticket/TransactionToTicket’.
Here’s the callback, which I’ve put into /opt/rt5/local/html/Callbacks/SplitOffTransaction/Elements/ShowTransaction/Default
on our RT5 setup:
<%ARGS>
$Transaction => undef
$Actions => undef
$Object => undef
</%ARGS>
<%INIT>
if($Transaction->IsInbound() &&
($Transaction->Type() eq 'Create' || $Transaction->Type() eq 'Correspond')
) {
push @$Actions, {
path => '/Ticket/TransactionToTicket.html?id='.$Transaction->id,
title => 'Split Off',
};
}
</%INIT>
This is pretty simple - it just looks for the sort of transactions we want (Create
or Correspond
on an RT::Ticket
type object) and then sneaks in an extra new action menu item to point to the new Mason page with the title “Split Off”.
The Mason page lives in /opt/rt5/local/html/Ticket/TransactionToTicket.html
and is a bit longer:
<& /Elements/Header,
Title => $title,
LinkRel => \%link_rel &>
<& /Elements/Tabs &>
<h1>Handling Transaction <% $Transaction->id %> in queue <% $Queue->Name() %></h1>
<%INIT>
my $title;
my %link_rel;
# Check that we have a valid transaction to play with
unless ($ARGS{'id'}) {
Abort('No transaction ID specified');
}
my $Transaction = RT::Transaction->new( $session{'CurrentUser'} );
$Transaction->Load($ARGS{'id'});
if($Transaction->ObjectType ne "RT::Ticket" ||
!($Transaction->Type() eq 'Create' || $Transaction->Type() eq 'Correspond')
) {
Abort('Transaction '.$ARGS{'id'}.' is not a valid ticket correspondance transaction');
}
# Get the old original ticket that this transaction came from, and the
# queue that ticket was in.
my $OldTicket = RT::Ticket->new( $session{'CurrentUser'} );
$OldTicket->Load($Transaction->ObjectId());
my $Queue = $OldTicket->QueueObj();
# Check that the user can create tickets in that queue.
unless ( $Queue->CurrentUserHasRight('CreateTicket') ) {
Abort('You have no permission to create tickets in this queue.', Code => HTTP::Status::HTTP_FORBIDDEN);
}
# Work out who the requestor should be. First try the From for the first
# attachment in the transaction, but if that doesn't work fall back on the
# requestor(s) of the original old ticket.
my $oldRequestors = $Transaction->Attachments->First->Addresses->{'From'};
if(!@{$oldRequestors}) {
@{$oldRequestors} = split(/,/, $OldTicket->RequestorAddresses);
}
# Make a shiny new ticket with the contents of the original transaction
my $NewTicket = RT::Ticket->new( $session{'CurrentUser'} );
my($ticketId, $newTransObj, $errorMessage) = $NewTicket->Create(
Queue => $Queue,
Requestor => $oldRequestors,
Subject => $Transaction->Subject() || "Split off from " . $OldTicket->Subject() ? $OldTicket->Subject : $OldTicket->id,
MIMEObj => $Transaction->Attachments->First->ContentAsMIME(),
Parents => $OldTicket->id,
Owner => $OldTicket->OwnerObj,
);
if(!$ticketId) {
Abort('Could not create a new ticket for transaction '.$ARGS{'id'}.
': '. $errorMessage);
}
# Redirect the user to look at the new ticket.
RT::Interface::Web::Redirect(RT->Config->Get('WebURL')."/Ticket/Display.html?id=".$NewTicket->id);
</%INIT>
Still pretty obvious hopefully - its takes the ID of the transaction we want to split off, check it looks OK, gets the original old ticket object and associated queue, checks that the current user can create tickets and if they can makes a new one with first attachment of the transaction as its MIME object. For a requestor it tries to get the From address from the transaction, but if that fails it reverts the requestor(s) of the original old ticket the transaction came from. I also try to link the old ticket as the parent of the new ticket.
Finally if the ticket has been created OK, it redirects the user to the normal RT /Ticket/Display.html
page so they can check and interact with it. Note that the page output at the top is a bit of a debugging placeholder - if all goes well the user never sees that because once the ticket is successfully created we redirect to the display page.
I hope this quick hack is of use to someone (and cue someone now telling me that there’s already an RT config option to turn this feature on in the existing code… )