How to use a callback to prevent ticket merging

Hi there, I am trying to write a callback that would prevent tickets from being merged if:

  • The customer defined in a custom field does not match both tickets.
  • Either ticket does not have a set customer yet.

I am OK with figuring out the logic of whether to merge, but I’m struggling to figure out how to prevent form submission on the ModifyLinks.html form.

I know that with the Ticket/Update.html/BeforeUpdate callback I can use $$skip_update to prevent ticket updates, but I can’t find any equivalent.

What I tried:

I tried using the approach used here to call the BeforeUpdate callback from ModifyLinks.html/Default: html/Callbacks/RT-Extension-MandatoryOnTransition/Ticket/ModifyAll.html/Default - metacpan.org

Using this, the BeforeUpdate callback does execute, but setting skip_update does nothing.

Example code for ModifyLinks:

root@rt4:/opt/rt4/local/html/Callbacks/RT68263-TicketMergeCheck/Ticket# cat ModifyLinks.html/Default 
<& /Callbacks/RT68263-TicketMergeCheck/Ticket/Update.html/BeforeUpdate, %ARGS &>
root@rt4:/opt/rt4/local/html/Callbacks/RT68263-TicketMergeCheck/Ticket# 

And then BeforeUpdate:

root@rt4:/opt/rt4/local/html/Callbacks/RT68263-TicketMergeCheck/Ticket# cat Update.html/BeforeUpdate 
<%ARGS>
$skip_update => undef
$results => undef
</%ARGS>
<%init>
    my $ticket = $ARGS{'TicketObj'};
    my $callback = "BeforeUpdateTicketMergeCheck#".$ticket->id.": ";
    RT::Logger->info($callback."Starting callback.");
    #This should contain fields being posted.
    my $ARGSRef = $ARGS{'ARGSRef'};

    # Check if the ticket is being submitted.
    my $submitTicket = $$ARGSRef{"SubmitTicket"};
    if ($submitTicket ne 'Save Changes')
    {
        RT::Logger->info($callback . "This is not a ticket update. Exiting callback.");
        return;
    }
    else
    {
        RT::Logger->info($callback."Attempting ModifyLinks ticket update...");
        #Example Merge into input in ARGSRef: 68264-MergeInto => 123
        my $mergeInto = $$ARGSRef{$ticket->id.'-MergeInto'};
        RT::Logger->info($callback."The value of MergeInto field is: ".$mergeInto);
        if ($mergeInto ne '')
        {
            RT::Logger->info($callback."Prevent submit!");
            $$skip_update = 1;
        }
        RT::Logger->info($callback."ARGSRef: " . $ARGSRef);
        # print all the keys and values
        for (sort keys %$ARGSRef) {
            RT::Logger->info($callback."ARGSRef: " . "$_ => $ARGSRef->{$_}"  );
        }
    }
</%init>

For now I have hacked my ModfyLinks.html code to include a custom callback with skip_update logic similar to ModifyAll.html.

This seems to be working but it would be great to have an “officially supported” and “portable” solution. Worst case, maybe it would be great to merge such a callback into the codebase. We are on RT 4.4.3 but I can see even 5.x doesn’t have any additional callbacks that seem like they would solve this issue.

In ModifyLinks.html I changed this:

$Ticket->Atomic(sub{
    $m->callback( TicketObj => $Ticket, ARGSRef => \%ARGS, Results => \@results );
    push @results, ProcessTicketLinks( TicketObj => $Ticket, ARGSRef => \%ARGS );
    push @results, ProcessObjectCustomFieldUpdates( TicketObj => $Ticket, ARGSRef => \%ARGS );
});

To become this:

# Adding custom callback with skip_update
# RT68263
my $skip_update = 0;
$m->callback( CallbackName => 'BeforeUpdate', TicketObj => $Ticket, ARGSRef => \%ARGS, skip_update => \$skip_update, results => \@results );

unless ($skip_update) {
    $Ticket->Atomic(sub{
        $m->callback( TicketObj => $Ticket, ARGSRef => \%ARGS, Results => \@results );
        push @results, ProcessTicketLinks( TicketObj => $Ticket, ARGSRef => \%ARGS );
        push @results, ProcessObjectCustomFieldUpdates( TicketObj => $Ticket, ARGSRef => \%ARGS );
    });
}

And added a new callback in Ticket/ModifyLinks.html/BeforeUpdate with $$skip_update = 1.

1 Like