I was able to patch the system to send close notifications to agents who have the ticket’s queue selected as one of their custom queues, but to do this requires modifications in a couple of places.

 

First, in the defaults.pm file, I added the ‘CloseNotify’ option to the following code at the end of the mail management options:

 

$Self->{PreferencesView} = {

        'Mail Management' => [

            'NewTicketNotify', 'FollowUpNotify', 'LockTimeoutNotify', 'MoveNotify', 'CloseNotify',

        ],

        Frontend => [

            'Language', 'Theme', 'QueueViewShownTickets', 'QueueView', 'RefreshTime', 'CreateNextMask',

        ],

        'Other Options' => [

            'Password', 'CustomQueue', 'SpellDict', 'FreeText', 'Comment',

        ],

    };

 

Later in this same file you will need to define this option as such:

 

$Self->{PreferencesGroups}->{CloseNotify} = {

                        Colum => 'Mail Management',

                        Label => 'Close Notification',

                        Desc => 'Send me a notification if a ticket in my custom queues is closed.',

                        Type => 'Generic',

                        Data => $Self->Get('YesNoOptions'),

                        PrefKey => 'UserSendCloseNotification',

                        Activ => 1,

            };

 

In the AAAPreferences.dtl file, you should add the following code so that the new option is displayed on the preferences page:

 

$Text{"Close notification"}

$Text{"Send me a notification if a ticket in my custom queues is closed."}

 

Finally, in the AgentClose.pm file, I added this code to the run subroutine:

 

foreach($Self->{QueueObject}->GetAllUserIDsByQueueID(QueueID => $QueueID)) {

                                    my %UserData = $Self->{UserObject}->GetUserData(UserID => $_);

                                    if ($UserData{UserSendCloseNotification}) {

                                                $Self->{TicketObject}->SendNotification (

                                                            Type => 'Close',

                                                            UserData => \%UserData,

                                                            CustomerMessageParams => { Queue => $Self->{QueueObject}->QueueLookup(QueueID => $QueueID) },

                                                            TicketID => $Self->{TicketID},

                                                            UserID => $Self->{UserID},

                                                );         

                                    }

                        }

 

The entire run subroutine as it exists on my system is shown below so you can see where I inserted this:

 

sub Run {

    my $Self = shift;

    my %Param = @_;

    my $Output;

   

    # check needed stuff

    if (!$Self->{TicketID}) {

        # error page

        $Output .= $Self->{LayoutObject}->Header(Title => 'Error');

        $Output .= $Self->{LayoutObject}->Error(

            Message => "Can't close Ticket, no TicketID is given!",

            Comment => 'Please contact the admin.',

        );

        $Output .= $Self->{LayoutObject}->Footer();

        return $Output;

    }

    # check permissions

    if (!$Self->{TicketObject}->Permission(

        Type => 'close',

        TicketID => $Self->{TicketID},

        UserID => $Self->{UserID})) {

        # error screen, don't show ticket

        return $Self->{LayoutObject}->NoPermission(WithHeader => 'yes');

    }

   

    my $Tn = $Self->{TicketObject}->GetTNOfId(ID => $Self->{TicketID});

    my $QueueID = $Self->{TicketObject}->GetQueueIDOfTicketID(TicketID => $Self->{TicketID});

 

    if ($Self->{Subaction} eq '' || !$Self->{Subaction}) {

        # get next states

        my %NextStates = $Self->{StateObject}->StateGetStatesByType(

            Type => 'DefaultCloseNext',

            Result => 'HASH',

        );

        # get possible notes

        my %DefaultNoteTypes = %{$Self->{ConfigObject}->Get('DefaultNoteTypes')};

        my %NoteTypes = $Self->{DBObject}->GetTableData(

            Table => 'article_type',

            Valid => 1,

            What => 'id, name'

        );

        foreach (keys %NoteTypes) {

            if (!$DefaultNoteTypes{$NoteTypes{$_}}) {

                delete $NoteTypes{$_};

            }

        }

        # move queues

        my $SelectedMoveQueue = $Self->{TicketObject}->GetQueueIDOfTicketID(

            TicketID => $Self->{TicketID},

        );

        my %MoveQueues = $Self->{QueueObject}->GetAllQueues(

            UserID => $Self->{UserID},

            Type => 'move',

        );

        # --

        # html header

        # --

        $Output .= $Self->{LayoutObject}->Header(Area => 'Agent', Title => 'Close');

        # --

        # get lock state

        # --

        if (!$Self->{TicketObject}->IsTicketLocked(TicketID => $Self->{TicketID})) {

            $Self->{TicketObject}->SetLock(

                TicketID => $Self->{TicketID},

                Lock => 'lock',

                UserID => $Self->{UserID}

            );

            if ($Self->{TicketObject}->SetOwner(

                TicketID => $Self->{TicketID},

                UserID => $Self->{UserID},

                NewUserID => $Self->{UserID},

            )) {

                # show lock state

                $Output .= $Self->{LayoutObject}->TicketLocked(TicketID => $Self->{TicketID});

            }

        }

        else {

            my ($OwnerID, $OwnerLogin) = $Self->{TicketObject}->CheckOwner(

                TicketID => $Self->{TicketID},

            );

            if ($OwnerID != $Self->{UserID}) {

                $Output .= $Self->{LayoutObject}->Warning(

                    Message => "Sorry, the current owner is $OwnerLogin!",

                    Comment => 'Please change the owner first.',

                );

                $Output .= $Self->{LayoutObject}->Footer();

                return $Output;

            }

        }

        # --

        # print form ...

        # --

 

#Added by Chris Peterson, 10.04.2004

#

#Code to generate close notifications for all agents

#that have subscribed to the custom queue in which the

#ticket is located

 

                        foreach($Self->{QueueObject}->GetAllUserIDsByQueueID(QueueID => $QueueID)) {

                                    my %UserData = $Self->{UserObject}->GetUserData(UserID => $_);

                                    if ($UserData{UserSendCloseNotification}) {

                                                $Self->{TicketObject}->SendNotification (

                                                            Type => 'Close',

                                                            UserData => \%UserData,

                                                            CustomerMessageParams => { Queue => $Self->{QueueObject}->QueueLookup(QueueID => $QueueID) },

                                                            TicketID => $Self->{TicketID},

                                                            UserID => $Self->{UserID},

                                                );         

                                    }

                        }

 

#End of 10.04.2004 addition

 

                        $Output .= $Self->_Mask(

            TicketID => $Self->{TicketID},

            TicketNumber => $Tn,

            QueueID => $QueueID,

            NextStatesStrg => \%NextStates,

            NoteTypesStrg => \%NoteTypes,

            MoveQueues => \%MoveQueues,

            SelectedMoveQueue => $SelectedMoveQueue,

        );

        $Output .= $Self->{LayoutObject}->Footer();

        return $Output;

    }

    elsif ($Self->{Subaction} eq 'Store') {

        # store action

        my $StateID = $Self->{ParamObject}->GetParam(Param => 'CloseStateID');

        my $NoteID = $Self->{ParamObject}->GetParam(Param => 'CloseNoteID');

        my $Subject = $Self->{ParamObject}->GetParam(Param => 'Subject') || '';

        my $Text = $Self->{ParamObject}->GetParam(Param => 'Text') ||

            $Self->{ParamObject}->GetParam(Param => 'Body');

        my $TimeUnits = $Self->{ParamObject}->GetParam(Param => 'TimeUnits') || 0;

        my $DestQueueID = $Self->{ParamObject}->GetParam(Param => 'DestQueueID') || '';

        if (my $ArticleID = $Self->{TicketObject}->CreateArticle(

            TicketID => $Self->{TicketID},

            ArticleTypeID => $NoteID,

            SenderType => 'agent',

            >From => "$Self->{UserFirstname} $Self->{UserLastname} <$Self->{UserEmail}>",

            Subject => $Subject,

            Body => $Text,

            ContentType => "text/plain; charset=$Self->{LayoutObject}->{'UserCharset'}",

            UserID => $Self->{UserID},

            HistoryType => 'AddNote',

            HistoryComment => 'Close Note added.',

        )) {

          # time accounting

          if ($TimeUnits) {

            $Self->{TicketObject}->AccountTime(

              TicketID => $Self->{TicketID},

              ArticleID => $ArticleID,

              TimeUnit => $TimeUnits,

              UserID => $Self->{UserID},

            );

          }

          # set state

          $Self->{TicketObject}->SetState(

            UserID => $Self->{UserID},

            TicketID => $Self->{TicketID},

            ArticleID => $ArticleID,

            StateID => $StateID,

          );

          # set queue

          if ($DestQueueID) {

            $Self->{TicketObject}->MoveByTicketID(

              TicketID => => $Self->{TicketID},

              UserID => $Self->{UserID},

              QueueID => $DestQueueID,

            );

          }

          # set lock

          $Self->{TicketObject}->SetLock(

            UserID => $Self->{UserID},

            TicketID => $Self->{TicketID},

            Lock => 'unlock'

          );

          # redirect

          my %StateData = $Self->{TicketObject}->{StateObject}->StateGet(

              ID => $StateID,

          );

          if ($StateData{TypeName} =~ /^close/i) {

              return $Self->{LayoutObject}->Redirect(OP => $Self->{LastScreenQueue});

          }

          else {

              return $Self->{LayoutObject}->Redirect(OP => $Self->{LastScreen});

          }

        }

        else {

          # error screen

          $Output .= $Self->{LayoutObject}->Header();

          $Output .= $Self->{LayoutObject}->Error(

            Comment => 'Please contact your admin'

          );

          $Output .= $Self->{LayoutObject}->Footer();

          return $Output;

        }

    }

    else {

        # error screen

        $Output .= $Self->{LayoutObject}->Header();

        $Output .= $Self->{LayoutObject}->Error(

            Message => 'Wrong Subaction!!',

            Comment => 'Please contact your admin'

        );

        $Output .= $Self->{LayoutObject}->Footer();

       

                        return $Output;

    }

}

 

These are all the modifications that you should need to make to the code.  You will need to add a new notification to the notifications table – you should enter Agent::Close in the notification_type field.

 

 

The downside of modifying the code this way, as I discovered after making these changes is that the close notification is sent when the agent accesses the close ticket page, not when they actually close the ticket.  Therefore, if they go to this page and do not actually close the ticket, a false notification will be sent.  Perhaps someone else could suggest a cleaner way to implement this.  I’m on a tight schedule though, and this was a sufficient fix for my company, so I don’t have time to go back and review this code.  Hope this helps.

 

Christopher J. Peterson

Compulit, Inc

(616)285-9590

cpeterso@compulit.com