<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># --
# Kernel/Output/HTML/TicketOverviewPreview.pm
# Copyright (C) 2001-2014 OTRS AG, http://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

package Kernel::Output::HTML::TicketOverviewPreview;

use strict;
use warnings;

use Kernel::System::CustomerUser;
use Kernel::System::SystemAddress;
use Kernel::System::DynamicField;
use Kernel::System::DynamicField::Backend;
use Kernel::System::VariableCheck qw(:all);

sub new {
    my ( $Type, %Param ) = @_;

    # allocate new hash for object
    my $Self = \%Param;
    bless( $Self, $Type );

    # get needed objects
    for (
        qw(ConfigObject LogObject DBObject EncodeObject LayoutObject UserID UserObject GroupObject TicketObject MainObject QueueObject)
        )
    {
        $Self-&gt;{$_} = $Param{$_} || die "Got no $_!";
    }

    $Self-&gt;{CustomerUserObject} = Kernel::System::CustomerUser-&gt;new(%Param);
    $Self-&gt;{SystemAddress}      = Kernel::System::SystemAddress-&gt;new(%Param);
    $Self-&gt;{DynamicFieldObject} = Kernel::System::DynamicField-&gt;new(%Param);
    $Self-&gt;{BackendObject}      = Kernel::System::DynamicField::Backend-&gt;new(%Param);

    # get dynamic field config for frontend module
    $Self-&gt;{DynamicFieldFilter}
        = $Self-&gt;{ConfigObject}-&gt;Get("Ticket::Frontend::OverviewPreview")-&gt;{DynamicField};

    # get the dynamic fields for this screen
    $Self-&gt;{DynamicField} = $Self-&gt;{DynamicFieldObject}-&gt;DynamicFieldListGet(
        Valid       =&gt; 1,
        ObjectType  =&gt; ['Ticket'],
        FieldFilter =&gt; $Self-&gt;{DynamicFieldFilter} || {},
    );

    return $Self;
}

sub ActionRow {
    my ( $Self, %Param ) = @_;

    # check if bulk feature is enabled
    my $BulkFeature = 0;
    if ( $Param{Bulk} &amp;&amp; $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::BulkFeature') ) {
        my @Groups;
        if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::BulkFeatureGroup') ) {
            @Groups = @{ $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::BulkFeatureGroup') };
        }
        if ( !@Groups ) {
            $BulkFeature = 1;
        }
        else {
            for my $Group (@Groups) {
                next if !$Self-&gt;{LayoutObject}-&gt;{"UserIsGroup[$Group]"};
                if ( $Self-&gt;{LayoutObject}-&gt;{"UserIsGroup[$Group]"} eq 'Yes' ) {
                    $BulkFeature = 1;
                    last;
                }
            }
        }
    }

    $Self-&gt;{LayoutObject}-&gt;Block(
        Name =&gt; 'DocumentActionRow',
        Data =&gt; \%Param,
    );

    if ($BulkFeature) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'DocumentActionRowBulk',
            Data =&gt; {
                %Param,
                Name =&gt; 'Bulk',
            },
        );
    }

    # run ticket overview document item menu modules
    if (
        $Param{Config}-&gt;{OverviewMenuModules}
        &amp;&amp; ref $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::OverviewMenuModule') eq 'HASH'
        )
    {

        my %Menus = %{ $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::OverviewMenuModule') };
        MENUMODULE:
        for my $Menu ( sort keys %Menus ) {

            next MENUMODULE if !IsHashRefWithData( $Menus{$Menu} );
            next MENUMODULE if ( $Menus{$Menu}-&gt;{View} &amp;&amp; $Menus{$Menu}-&gt;{View} ne $Param{View} );

            # load module
            if ( !$Self-&gt;{MainObject}-&gt;Require( $Menus{$Menu}-&gt;{Module} ) ) {
                return $Self-&gt;{LayoutObject}-&gt;FatalError();
            }
            my $Object = $Menus{$Menu}-&gt;{Module}-&gt;new( %{$Self} );

            # run module
            my $Item = $Object-&gt;Run(
                %Param,
                Config =&gt; $Menus{$Menu},
            );
            next MENUMODULE if !IsHashRefWithData($Item);

            if ( $Item-&gt;{Block} eq 'DocumentActionRowItem' ) {

                # add session id if needed
                if ( !$Self-&gt;{LayoutObject}-&gt;{SessionIDCookie} &amp;&amp; $Item-&gt;{Link} ) {
                    $Item-&gt;{Link}
                        .= ';'
                        . $Self-&gt;{LayoutObject}-&gt;{SessionName} . '='
                        . $Self-&gt;{LayoutObject}-&gt;{SessionID};
                }

                # create id
                $Item-&gt;{ID} = $Item-&gt;{Name};
                $Item-&gt;{ID} =~ s/(\s|&amp;|;)//ig;

                my $Link = $Item-&gt;{Link};
                if ( $Item-&gt;{Target} ) {
                    $Link = '#';
                }

                my $Class = '';
                if ( $Item-&gt;{PopupType} ) {
                    $Class = 'AsPopup PopupType_' . $Item-&gt;{PopupType};
                }

                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; $Item-&gt;{Block},
                    Data =&gt; {
                        ID   =&gt; $Item-&gt;{ID},
                        Name =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( $Item-&gt;{Name} ),
                        Link =&gt; $Self-&gt;{LayoutObject}-&gt;{Baselink} . $Item-&gt;{Link},
                        Description =&gt; $Item-&gt;{Description},
                        Block       =&gt; $Item-&gt;{Block},
                        Class       =&gt; $Class,
                    },
                );
            }
            elsif ( $Item-&gt;{Block} eq 'DocumentActionRowHTML' ) {

                next MENUMODULE if !$Item-&gt;{HTML};

                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; $Item-&gt;{Block},
                    Data =&gt; $Item,
                );
            }
        }
    }

    # init for table control
    $Self-&gt;{LayoutObject}-&gt;Block(
        Name =&gt; 'DocumentReadyStart',
        Data =&gt; \%Param,
    );

    my $Output = $Self-&gt;{LayoutObject}-&gt;Output(
        TemplateFile =&gt; 'AgentTicketOverviewPreview',
        Data         =&gt; \%Param,
    );

    return $Output;
}

sub SortOrderBar {
    my ( $Self, %Param ) = @_;
    return '';
}

sub Run {
    my ( $Self, %Param ) = @_;

    # check needed stuff
    for (qw(TicketIDs PageShown StartHit)) {
        if ( !$Param{$_} ) {
            $Self-&gt;{LogObject}-&gt;Log( Priority =&gt; 'error', Message =&gt; "Need $_!" );
            return;
        }
    }

    # check if bulk feature is enabled
    my $BulkFeature = 0;
    if ( $Param{Bulk} &amp;&amp; $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::BulkFeature') ) {
        my @Groups;
        if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::BulkFeatureGroup') ) {
            @Groups = @{ $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::BulkFeatureGroup') };
        }
        if ( !@Groups ) {
            $BulkFeature = 1;
        }
        else {
            for my $Group (@Groups) {
                next if !$Self-&gt;{LayoutObject}-&gt;{"UserIsGroup[$Group]"};
                if ( $Self-&gt;{LayoutObject}-&gt;{"UserIsGroup[$Group]"} eq 'Yes' ) {
                    $BulkFeature = 1;
                    last;
                }
            }
        }
    }

    $Self-&gt;{LayoutObject}-&gt;Block(
        Name =&gt; 'DocumentHeader',
        Data =&gt; \%Param,
    );

    my $OutputMeta = $Self-&gt;{LayoutObject}-&gt;Output(
        TemplateFile =&gt; 'AgentTicketOverviewPreview',
        Data         =&gt; \%Param,
    );
    my $OutputRaw = '';
    if ( !$Param{Output} ) {
        $Self-&gt;{LayoutObject}-&gt;Print( Output =&gt; \$OutputMeta );
    }
    else {
        $OutputRaw .= $OutputMeta;
    }
    my $Output        = '';
    my $Counter       = 0;
    my $CounterOnSite = 0;
    my @TicketIDsShown;

    # check if there are tickets to show
    if ( scalar @{ $Param{TicketIDs} } ) {

        for my $TicketID ( @{ $Param{TicketIDs} } ) {
            $Counter++;
            if (
                $Counter &gt;= $Param{StartHit}
                &amp;&amp; $Counter &lt; ( $Param{PageShown} + $Param{StartHit} )
                )
            {
                push @TicketIDsShown, $TicketID;
                my $Output = $Self-&gt;_Show(
                    TicketID =&gt; $TicketID,
                    Counter  =&gt; $CounterOnSite,
                    Bulk     =&gt; $BulkFeature,
                    Config   =&gt; $Param{Config},
                    Output   =&gt; $Param{Output} || '',
                );
                $CounterOnSite++;
                if ( !$Param{Output} ) {
                    $Self-&gt;{LayoutObject}-&gt;Print( Output =&gt; $Output );
                }
                else {
                    $OutputRaw .= ${$Output};
                }
            }
        }
    }
    else {
        $Self-&gt;{LayoutObject}-&gt;Block( Name =&gt; 'NoTicketFound' );
    }

    if ($BulkFeature) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'DocumentFooter',
            Data =&gt; \%Param,
        );
        for my $TicketID (@TicketIDsShown) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'DocumentFooterBulkItem',
                Data =&gt; \%Param,
            );
        }
        my $OutputMeta = $Self-&gt;{LayoutObject}-&gt;Output(
            TemplateFile =&gt; 'AgentTicketOverviewPreview',
            Data         =&gt; \%Param,
        );
        if ( !$Param{Output} ) {
            $Self-&gt;{LayoutObject}-&gt;Print( Output =&gt; \$OutputMeta );
        }
        else {
            $OutputRaw .= $OutputMeta;
        }
    }
    return $OutputRaw;
}

sub _Show {
    my ( $Self, %Param ) = @_;

    # check needed stuff
    if ( !$Param{TicketID} ) {
        $Self-&gt;{LogObject}-&gt;Log( Priority =&gt; 'error', Message =&gt; 'Need TicketID!' );
        return;
    }

    # check if bulk feature is enabled
    if ( $Param{Bulk} ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Bulk',
            Data =&gt; \%Param,
        );
    }

    # collect params for ArticleGet
    my %ArticleGetParams = (
        TicketID      =&gt; $Param{TicketID},
        UserID        =&gt; $Self-&gt;{UserID},
        DynamicFields =&gt; 0,
        Order         =&gt; 'DESC',
        Limit =&gt; $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::Overview::PreviewArticleLimit') || 5,
    );

    # check if certain article sender types should be excluded from preview
    my $PreviewArticleSenderTypes
        = $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::Overview::PreviewArticleSenderTypes');
    my @ActiveArticleSenderTypes;
    if ( ref $PreviewArticleSenderTypes eq 'HASH' ) {
        @ActiveArticleSenderTypes
            = grep { $PreviewArticleSenderTypes-&gt;{$_} == 1 } keys %{$PreviewArticleSenderTypes};
    }

    # if a list of active article sender types has been determined, add them to params hash
    if (@ActiveArticleSenderTypes) {
        $ArticleGetParams{ArticleSenderType} = \@ActiveArticleSenderTypes;
    }

    # get last 5 articles
    my @ArticleBody = $Self-&gt;{TicketObject}-&gt;ArticleGet(
        %ArticleGetParams,
    );
    my %Article = %{ $ArticleBody[0] || {} };
    my $ArticleCount = scalar @ArticleBody;

    my %Ticket = $Self-&gt;{TicketObject}-&gt;TicketGet(
        TicketID      =&gt; $Param{TicketID},
        DynamicFields =&gt; 0,
    );

    # Fallback for tickets without articles: get at least basic ticket data
    if ( !%Article ) {
        %Article = %Ticket;
        if ( !$Article{Title} ) {
            $Article{Title} = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get(
                'This ticket has no title or subject'
            );
        }
        $Article{Subject} = $Article{Title};
    }

    # user info
    my %UserInfo = $Self-&gt;{UserObject}-&gt;GetUserData(
        UserID =&gt; $Article{OwnerID},
    );
    %Article = ( %UserInfo, %Article );

    # create human age
    $Article{Age} = $Self-&gt;{LayoutObject}-&gt;CustomerAge( Age =&gt; $Article{Age}, Space =&gt; ' ' );

    # fetch all std. templates ...
    my %StandardTemplates = $Self-&gt;{QueueObject}-&gt;QueueStandardTemplateMemberList(
        QueueID       =&gt; $Article{QueueID},
        TemplateTypes =&gt; 1,
    );

    $Param{StandardResponsesStrg} = $Self-&gt;{LayoutObject}-&gt;BuildSelection(
        Name =&gt; 'ResponseID',
        Data =&gt; $StandardTemplates{Answer} || {},
    );

    # customer info
    if ( $Param{Config}-&gt;{CustomerInfo} ) {
        if ( $Article{CustomerUserID} ) {
            $Article{CustomerName} = $Self-&gt;{CustomerUserObject}-&gt;CustomerName(
                UserLogin =&gt; $Article{CustomerUserID},
            );
        }
    }

    # get acl actions
    $Self-&gt;{TicketObject}-&gt;TicketAcl(
        Data          =&gt; '-',
        Action        =&gt; $Self-&gt;{Action},
        TicketID      =&gt; $Article{TicketID},
        ReturnType    =&gt; 'Action',
        ReturnSubType =&gt; '-',
        UserID        =&gt; $Self-&gt;{UserID},
    );
    my %AclAction = $Self-&gt;{TicketObject}-&gt;TicketAclActionData();

    # run ticket pre menu modules
    my @ActionItems;
    if ( ref $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::PreMenuModule') eq 'HASH' ) {
        my %Menus = %{ $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::PreMenuModule') };
        for my $Menu ( sort keys %Menus ) {

            # load module
            if ( !$Self-&gt;{MainObject}-&gt;Require( $Menus{$Menu}-&gt;{Module} ) ) {
                return $Self-&gt;{LayoutObject}-&gt;FatalError();
            }
            my $Object = $Menus{$Menu}-&gt;{Module}-&gt;new( %{$Self}, TicketID =&gt; $Param{TicketID}, );

            # run module
            my $Item = $Object-&gt;Run(
                %Param,
                Ticket =&gt; \%Article,
                ACL    =&gt; \%AclAction,
                Config =&gt; $Menus{$Menu},
            );

            next if !$Item;
            next if ref $Item ne 'HASH';
            for my $Key (qw(Name Link Description)) {
                next if !$Item-&gt;{$Key};
                $Item-&gt;{$Key} = $Self-&gt;{LayoutObject}-&gt;Output(
                    Template =&gt; $Item-&gt;{$Key},
                    Data     =&gt; \%Article,
                );
            }

            # add session id if needed
            if ( !$Self-&gt;{LayoutObject}-&gt;{SessionIDCookie} &amp;&amp; $Item-&gt;{Link} ) {
                $Item-&gt;{Link}
                    .= ';'
                    . $Self-&gt;{LayoutObject}-&gt;{SessionName} . '='
                    . $Self-&gt;{LayoutObject}-&gt;{SessionID};
            }

            # create id
            $Item-&gt;{ID} = $Item-&gt;{Name};
            $Item-&gt;{ID} =~ s/(\s|&amp;|;)//ig;

            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; $Item-&gt;{Block} || 'DocumentMenuItem',
                Data =&gt; $Item,
            );
            my $Output = $Self-&gt;{LayoutObject}-&gt;Output(
                TemplateFile =&gt; 'AgentTicketOverviewPreview',
                Data         =&gt; $Item,
            );
            $Output =~ s/\n+//g;
            $Output =~ s/\s+/ /g;
            $Output =~ s/&lt;\!--.+?--&gt;//g;

            push @ActionItems, {
                HTML        =&gt; $Output,
                ID          =&gt; $Item-&gt;{ID},
                Name        =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( $Item-&gt;{Name} ),
                Link        =&gt; $Self-&gt;{LayoutObject}-&gt;{Baselink} . $Item-&gt;{Link},
                Target      =&gt; $Item-&gt;{Target},
                PopupType   =&gt; $Item-&gt;{PopupType},
                Description =&gt; $Item-&gt;{Description},
                Block       =&gt; $Item-&gt;{Block} || 'DocumentMenuItem',

            };
        }
    }

    my $AdditionalClasses = $Param{Config}-&gt;{TicketActionsPerTicket} ? 'ShowInlineActions' : '';

    $Self-&gt;{LayoutObject}-&gt;Block(
        Name =&gt; 'DocumentContent',
        Data =&gt; {
            %Param,
            %Article,
            Class             =&gt; 'ArticleCount' . $ArticleCount,
            AdditionalClasses =&gt; $AdditionalClasses,
            Created           =&gt; $Ticket{Created},              # use value from ticket, not article
        },
    );

    # if "Actions per Ticket" (Inline Action Row) is active
    if ( $Param{Config}-&gt;{TicketActionsPerTicket} ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'InlineActionRow',
            Data =&gt; \%Param,
        );

        # Add list entries for every action
        for my $Item (@ActionItems) {
            my $Link = $Item-&gt;{Link};
            if ( $Item-&gt;{Target} ) {
                $Link = '#';
            }

            my $Class = '';
            if ( $Item-&gt;{PopupType} ) {
                $Class = 'AsPopup PopupType_' . $Item-&gt;{PopupType};
            }

            if ( $Item-&gt;{Block} eq 'DocumentMenuItem' ) {
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'InlineActionRowItem',
                    Data =&gt; {
                        TicketID    =&gt; $Param{TicketID},
                        QueueID     =&gt; $Article{QueueID},
                        ID          =&gt; $Item-&gt;{ID},
                        Name        =&gt; $Item-&gt;{Name},
                        Description =&gt; $Item-&gt;{Description},
                        Class       =&gt; $Class,
                        Link        =&gt; $Link,
                    },
                );
            }
            else {
                my $TicketID   = $Param{TicketID};
                my $SelectHTML = $Item-&gt;{HTML};
                $SelectHTML =~ s/id="DestQueueID"/id="DestQueueID$TicketID"/xmig;
                $SelectHTML =~ s/for="DestQueueID"/for="DestQueueID$TicketID"/xmig;
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'InlineActionRowItemHTML',
                    Data =&gt; {
                        HTML =&gt; $SelectHTML,
                    },
                );
            }
        }
    }

    # check if bulk feature is enabled
    if ( $Param{Bulk} ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Bulk',
            Data =&gt; \%Param,
        );
    }

    # show ticket flags
    my @TicketMetaItems = $Self-&gt;{LayoutObject}-&gt;TicketMetaItems(
        Ticket =&gt; \%Article,
    );
    for my $Item (@TicketMetaItems) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Meta',
            Data =&gt; $Item,
        );
        if ($Item) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'MetaIcon',
                Data =&gt; $Item,
            );
        }
    }

    # run article modules
    if ( $Article{ArticleID} ) {
        if ( ref $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::ArticlePreViewModule') eq 'HASH' ) {
            my %Jobs = %{ $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::ArticlePreViewModule') };
            for my $Job ( sort keys %Jobs ) {

                # load module
                if ( !$Self-&gt;{MainObject}-&gt;Require( $Jobs{$Job}-&gt;{Module} ) ) {
                    return $Self-&gt;{LayoutObject}-&gt;FatalError();
                }
                my $Object = $Jobs{$Job}-&gt;{Module}-&gt;new(
                    %{$Self},
                    ArticleID =&gt; $Article{ArticleID},
                    UserID    =&gt; $Self-&gt;{UserID},
                    Debug     =&gt; $Self-&gt;{Debug},
                );

                # run module
                my @Data = $Object-&gt;Check( Article =&gt; \%Article, %Param, Config =&gt; $Jobs{$Job} );

                for my $DataRef (@Data) {
                    if ( $DataRef-&gt;{Successful} ) {
                        $DataRef-&gt;{Result} = 'Error';
                    }
                    else {
                        $DataRef-&gt;{Result} = 'Success';
                    }

                    $Self-&gt;{LayoutObject}-&gt;Block(
                        Name =&gt; 'ArticleOption',
                        Data =&gt; $DataRef,
                    );
                }

                # filter option
                $Object-&gt;Filter( Article =&gt; \%Article, %Param, Config =&gt; $Jobs{$Job} );
            }
        }
    }

    # create output
    $Self-&gt;{LayoutObject}-&gt;Block(
        Name =&gt; 'AgentAnswer',
        Data =&gt; { %Param, %Article, %AclAction },
    );
    if (
        $Self-&gt;{ConfigObject}-&gt;Get('Frontend::Module')-&gt;{AgentTicketCompose}
        &amp;&amp; ( !defined $AclAction{AgentTicketCompose} || $AclAction{AgentTicketCompose} )
        )
    {
        my $Access = 1;
        my $Config = $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::AgentTicketCompose');
        if ( $Config-&gt;{Permission} ) {
            my $Ok = $Self-&gt;{TicketObject}-&gt;Permission(
                Type     =&gt; $Config-&gt;{Permission},
                TicketID =&gt; $Param{TicketID},
                UserID   =&gt; $Self-&gt;{UserID},
                LogNo    =&gt; 1,
            );
            if ( !$Ok ) {
                $Access = 0;
            }
            if ($Access) {
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'AgentAnswerCompose',
                    Data =&gt; { %Param, %Article, %AclAction },
                );
            }
        }
    }
    if (
        $Self-&gt;{ConfigObject}-&gt;Get('Frontend::Module')-&gt;{AgentTicketPhoneOutbound}
        &amp;&amp; (
            !defined $AclAction{AgentTicketPhoneOutbound}
            || $AclAction{AgentTicketPhoneOutbound}
        )
        )
    {
        my $Access = 1;
        my $Config = $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::AgentTicketPhoneOutbound');
        if ( $Config-&gt;{Permission} ) {
            my $OK = $Self-&gt;{TicketObject}-&gt;Permission(
                Type     =&gt; $Config-&gt;{Permission},
                TicketID =&gt; $Param{TicketID},
                UserID   =&gt; $Self-&gt;{UserID},
                LogNo    =&gt; 1,
            );
            if ( !$OK ) {
                $Access = 0;
            }
        }
        if ($Access) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'AgentAnswerPhoneOutbound',
                Data =&gt; { %Param, %Article, %AclAction },
            );
        }
    }

    # ticket type
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Type') ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Type',
            Data =&gt; { %Param, %Article },
        );
    }

    # ticket service
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Service') &amp;&amp; $Article{Service} ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Service',
            Data =&gt; { %Param, %Article },
        );
        if ( $Article{SLA} ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'SLA',
                Data =&gt; { %Param, %Article },
            );
        }
    }

    # CustomerID and CustomerName
    if ( defined $Article{CustomerID} ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'CustomerID',
            Data =&gt; { %Param, %Article },
        );

        # test access to frontend module
        my $Access = $Self-&gt;{LayoutObject}-&gt;Permission(
            Action =&gt; 'AgentTicketCustomer',
            Type   =&gt; 'rw',
        );
        if ($Access) {

            # test access to ticket
            my $Config = $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::AgentTicketCustomer');
            if ( $Config-&gt;{Permission} ) {
                my $OK = $Self-&gt;{TicketObject}-&gt;Permission(
                    Type     =&gt; $Config-&gt;{Permission},
                    TicketID =&gt; $Param{TicketID},
                    UserID   =&gt; $Self-&gt;{UserID},
                    LogNo    =&gt; 1,
                );
                if ( !$OK ) {
                    $Access = 0;
                }
            }
        }

        # define proper DTL block based on permissions
        my $CustomerIDBlock = $Access ? 'CustomerIDRW' : 'CustomerIDRO';

        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; $CustomerIDBlock,
            Data =&gt; { %Param, %Article },
        );

        if ( defined $Article{CustomerName} ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'CustomerName',
                Data =&gt; { %Param, %Article },
            );
        }
    }

    # show first response time if needed
    if ( defined $Article{FirstResponseTime} ) {
        $Article{FirstResponseTimeHuman} = $Self-&gt;{LayoutObject}-&gt;CustomerAgeInHours(
            Age   =&gt; $Article{FirstResponseTime},
            Space =&gt; ' ',
        );
        $Article{FirstResponseTimeWorkingTime} = $Self-&gt;{LayoutObject}-&gt;CustomerAgeInHours(
            Age   =&gt; $Article{FirstResponseTimeWorkingTime},
            Space =&gt; ' ',
        );
        if ( 60 * 60 * 1 &gt; $Article{FirstResponseTime} ) {
            $Article{FirstResponseTimeClass} = 'Warning'
        }
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'FirstResponseTime',
            Data =&gt; { %Param, %Article },
        );
    }

    # show update time if needed
    if ( defined $Article{UpdateTime} ) {
        $Article{UpdateTimeHuman} = $Self-&gt;{LayoutObject}-&gt;CustomerAgeInHours(
            Age   =&gt; $Article{UpdateTime},
            Space =&gt; ' ',
        );
        $Article{UpdateTimeWorkingTime} = $Self-&gt;{LayoutObject}-&gt;CustomerAgeInHours(
            Age   =&gt; $Article{UpdateTimeWorkingTime},
            Space =&gt; ' ',
        );
        if ( 60 * 60 * 1 &gt; $Article{UpdateTime} ) {
            $Article{UpdateTimeClass} = 'Warning'
        }
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'UpdateTime',
            Data =&gt; { %Param, %Article },
        );
    }

    # show solution time if needed
    if ( defined $Article{SolutionTime} ) {
        $Article{SolutionTimeHuman} = $Self-&gt;{LayoutObject}-&gt;CustomerAgeInHours(
            Age   =&gt; $Article{SolutionTime},
            Space =&gt; ' ',
        );
        $Article{SolutionTimeWorkingTime} = $Self-&gt;{LayoutObject}-&gt;CustomerAgeInHours(
            Age   =&gt; $Article{SolutionTimeWorkingTime},
            Space =&gt; ' ',
        );
        if ( 60 * 60 * 1 &gt; $Article{SolutionTime} ) {
            $Article{SolutionTimeClass} = 'Warning'
        }
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'SolutionTime',
            Data =&gt; { %Param, %Article },
        );
    }

    # Dynamic fields
    my $Counter = 0;
    my $Class   = 'Middle';

    # cycle trough the activated Dynamic Fields for this screen
    DYNAMICFIELD:
    for my $DynamicFieldConfig ( @{ $Self-&gt;{DynamicField} } ) {
        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);

        $Counter++;

        # get field value
        my $Value = $Self-&gt;{BackendObject}-&gt;ValueGet(
            DynamicFieldConfig =&gt; $DynamicFieldConfig,
            ObjectID           =&gt; $Param{TicketID},
        );

        next DYNAMICFIELD if ( !defined $Value );

        my $ValueStrg = $Self-&gt;{BackendObject}-&gt;DisplayValueRender(
            DynamicFieldConfig =&gt; $DynamicFieldConfig,
            Value              =&gt; $Value,
            ValueMaxChars      =&gt; 20,
            LayoutObject       =&gt; $Self-&gt;{LayoutObject},
        );

        my $Label = $DynamicFieldConfig-&gt;{Label};

        # create a new row if counter is starting
        if ( $Counter == 1 ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'DynamicFieldTableRow',
                Data =&gt; {
                    Class =&gt; $Class,
                },
            );
        }

        # display separation row just once
        $Class = '';

        # outout dynamic field label
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'DynamicFieldTableRowRecord',
            Data =&gt; {
                Label =&gt; $Label,
            },
        );

        if ( $ValueStrg-&gt;{Link} ) {

            # outout dynamic field value link
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'DynamicFieldTableRowRecordLink',
                Data =&gt; {
                    Value                       =&gt; $ValueStrg-&gt;{Value},
                    Title                       =&gt; $ValueStrg-&gt;{Title},
                    Link                        =&gt; $ValueStrg-&gt;{Link},
                    $DynamicFieldConfig-&gt;{Name} =&gt; $ValueStrg-&gt;{Title},
                },
            );
        }
        else {

            # outout dynamic field value plain
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'DynamicFieldTableRowRecordPlain',
                Data =&gt; {
                    Value =&gt; $ValueStrg-&gt;{Value},
                    Title =&gt; $ValueStrg-&gt;{Title},
                },
            );
        }

        # only 2 dynamic fields by row are allowed, reset couter if needed
        if ( $Counter == 2 ) {
            $Counter = 0;
        }

        # example of dynamic fields order customization
        # outout dynamic field label
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'DynamicField_' . $DynamicFieldConfig-&gt;{Name} . '_TableRowRecord',
            Data =&gt; {
                Label =&gt; $Label,
            },
        );

        if ( $ValueStrg-&gt;{Link} ) {

            # outout dynamic field value link
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'DynamicField_' . $DynamicFieldConfig-&gt;{Name} . '_TableRowRecordLink',
                Data =&gt; {
                    Value                       =&gt; $ValueStrg-&gt;{Value},
                    Title                       =&gt; $ValueStrg-&gt;{Title},
                    Link                        =&gt; $ValueStrg-&gt;{Link},
                    $DynamicFieldConfig-&gt;{Name} =&gt; $ValueStrg-&gt;{Title},
                },
            );
        }
        else {

            # outout dynamic field value plain
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'DynamicField_' . $DynamicFieldConfig-&gt;{Name} . '_TableRowRecordPlain',
                Data =&gt; {
                    Value =&gt; $ValueStrg-&gt;{Value},
                    Title =&gt; $ValueStrg-&gt;{Title},
                },
            );
        }
    }

    # fill the rest of the Dynamic Fields row with empty cells, this will look better
    if ( $Counter &gt; 0 &amp;&amp; $Counter &lt; 2 ) {

        for ( $Counter + 1 ... 2 ) {

            # outout dynamic field label
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'DynamicFieldTableRowRecord',
                Data =&gt; {
                    Label =&gt; '',
                },
            );

            # outout dynamic field value plain
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'DynamicFieldTableRowRecordPlain',
                Data =&gt; {
                    Value =&gt; '',
                    Title =&gt; '',
                },
            );
        }
    }

    if (@ArticleBody) {

        # check if a certain article type should be displayed as expanded
        my $PreviewArticleTypeExpanded
            = $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::Overview::PreviewArticleTypeExpanded')
            || '';

        # if a certain article type should be shown as expanded, set the
        # last article of this type as active
        if ($PreviewArticleTypeExpanded) {

            my $ClassCount = 0;
            for my $ArticleItem (@ArticleBody) {
                next if !$ArticleItem;

                # check if current article type should be shown as expanded
                if ( $ArticleItem-&gt;{ArticleType} eq $PreviewArticleTypeExpanded ) {
                    $ArticleItem-&gt;{Class} = 'Active';
                    last;
                }

                # otherwise display the last article in the list as expanded (default)
                elsif ( $ClassCount == $#ArticleBody ) {
                    $ArticleBody[0]-&gt;{Class} = 'Active';
                }
                $ClassCount++;
            }
        }

        # otherwise display the last article in the list as expanded (default)
        else {
            $ArticleBody[0]-&gt;{Class} = 'Active';
        }

        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'ArticlesPreviewArea',
            Data =&gt; { %Param, %Article, %AclAction },
        );
    }

    # show inline article
    for my $ArticleItem ( reverse @ArticleBody ) {

        # check if just a only html email
        my $MimeTypeText = $Self-&gt;{LayoutObject}-&gt;CheckMimeType(
            %{$ArticleItem},
            Action =&gt; 'AgentTicketZoom',
        );
        if ($MimeTypeText) {
            $ArticleItem-&gt;{BodyNote} = $MimeTypeText;
            $ArticleItem-&gt;{Body}     = '';
        }
        else {

            # html quoting
            $ArticleItem-&gt;{Body} = $Self-&gt;{LayoutObject}-&gt;Ascii2Html(
                NewLine =&gt; $Param{Config}-&gt;{DefaultViewNewLine}  || 90,
                Text    =&gt; $ArticleItem-&gt;{Body},
                VMax    =&gt; $Param{Config}-&gt;{DefaultPreViewLines} || 25,
                LinkFeature     =&gt; 1,
                HTMLResultMode  =&gt; 1,
                StripEmptyLines =&gt; $Param{Config}-&gt;{StripEmptyLines},
            );

            # do charset check
            my $CharsetText = $Self-&gt;{LayoutObject}-&gt;CheckCharset(
                %{$ArticleItem},
                Action =&gt; 'AgentTicketZoom',
            );
            if ($CharsetText) {
                $ArticleItem-&gt;{BodyNote} = $CharsetText;
            }
        }

        $ArticleItem-&gt;{Subject} = $Self-&gt;{TicketObject}-&gt;TicketSubjectClean(
            TicketNumber =&gt; $ArticleItem-&gt;{TicketNumber},
            Subject =&gt; $ArticleItem-&gt;{Subject} || '',
        );

        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'ArticlePreview',
            Data =&gt; {
                %{$ArticleItem},
                Class =&gt; $ArticleItem-&gt;{Class},
            },
        );

        # show actions
        if ( $ArticleItem-&gt;{ArticleType} !~ /^(note|email-noti)/i ) {

            # check if compose link should be shown
            if (
                $Self-&gt;{ConfigObject}-&gt;Get('Frontend::Module')-&gt;{AgentTicketCompose}
                &amp;&amp; (
                    !defined $AclAction{AgentTicketCompose}
                    || $AclAction{AgentTicketCompose}
                )
                )
            {
                my $Access = 1;
                my $Config = $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::AgentTicketCompose');
                if ( $Config-&gt;{Permission} ) {
                    my $Ok = $Self-&gt;{TicketObject}-&gt;Permission(
                        Type     =&gt; $Config-&gt;{Permission},
                        TicketID =&gt; $Article{TicketID},
                        UserID   =&gt; $Self-&gt;{UserID},
                        LogNo    =&gt; 1,
                    );
                    if ( !$Ok ) {
                        $Access = 0;
                    }
                }
                if ( $Config-&gt;{RequiredLock} ) {
                    my $Locked = $Self-&gt;{TicketObject}-&gt;LockIsTicketLocked(
                        TicketID =&gt; $Article{TicketID},
                    );
                    if ($Locked) {
                        my $AccessOk = $Self-&gt;{TicketObject}-&gt;OwnerCheck(
                            TicketID =&gt; $Article{TicketID},
                            OwnerID  =&gt; $Self-&gt;{UserID},
                        );
                        if ( !$AccessOk ) {
                            $Access = 0;
                        }
                    }
                }
                if ( $Access &amp;&amp; !$Param{Output} ) {
                    $Self-&gt;{LayoutObject}-&gt;Block(
                        Name =&gt; 'ArticlePreviewActionRow',
                        Data =&gt; {
                            %{$ArticleItem}, %AclAction,
                        },
                    );

                    # fetch all std. responses
                    my %StandardTemplates = $Self-&gt;{QueueObject}-&gt;QueueStandardTemplateMemberList(
                        QueueID       =&gt; $Article{QueueID},
                        TemplateTypes =&gt; 1,
                    );

                    my %StandardResponses;
                    if ( IsHashRefWithData( $StandardTemplates{Answer} ) ) {
                        %StandardResponses = %{ $StandardTemplates{Answer} };
                    }

                    # get StandardResponsesStrg
                    $StandardResponses{0}
                        = '- ' . $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Reply') . ' -';

                    # build html string
                    my $StandardResponsesStrg = $Self-&gt;{LayoutObject}-&gt;BuildSelection(
                        Name =&gt; 'ResponseID',
                        ID   =&gt; 'ResponseID' . $ArticleItem-&gt;{ArticleID},
                        Data =&gt; \%StandardResponses,
                    );

                    $Self-&gt;{LayoutObject}-&gt;Block(
                        Name =&gt; 'ArticlePreviewActionRowItem',
                        Data =&gt; {
                            %{$ArticleItem},
                            StandardResponsesStrg =&gt; $StandardResponsesStrg,
                            Name                  =&gt; 'Reply',
                            Class                 =&gt; 'AsPopup',
                            Action                =&gt; 'AgentTicketCompose',
                            FormID                =&gt; 'Reply' . $ArticleItem-&gt;{ArticleID},
                        },
                    );

                    # check if reply all is needed
                    my $Recipients = '';
                    for my $Key (qw(From To Cc)) {
                        next if !$ArticleItem-&gt;{$Key};
                        if ($Recipients) {
                            $Recipients .= ', ';
                        }
                        $Recipients .= $ArticleItem-&gt;{$Key};
                    }
                    my $RecipientCount = 0;
                    if ($Recipients) {
                        my $EmailParser = Kernel::System::EmailParser-&gt;new(
                            %{$Self},
                            Mode =&gt; 'Standalone',
                        );
                        my @Addresses = $EmailParser-&gt;SplitAddressLine( Line =&gt; $Recipients );
                        for my $Address (@Addresses) {
                            my $Email = $EmailParser-&gt;GetEmailAddress( Email =&gt; $Address );
                            next if !$Email;
                            my $IsLocal = $Self-&gt;{SystemAddress}-&gt;SystemAddressIsLocalAddress(
                                Address =&gt; $Email,
                            );
                            next if $IsLocal;
                            $RecipientCount++;
                        }
                    }
                    if ( $RecipientCount &gt; 1 ) {

                        # get StandardResponsesStrg
                        $StandardResponses{0}
                            = '- '
                            . $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Reply All') . ' -';
                        $StandardResponsesStrg = $Self-&gt;{LayoutObject}-&gt;BuildSelection(
                            Name =&gt; 'ResponseID',
                            ID   =&gt; 'ResponseIDAll' . $ArticleItem-&gt;{ArticleID},
                            Data =&gt; \%StandardResponses,
                        );

                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; 'ArticlePreviewActionRowItem',
                            Data =&gt; {
                                %{$ArticleItem},
                                StandardResponsesStrg =&gt; $StandardResponsesStrg,
                                Name                  =&gt; 'Reply All',
                                Class                 =&gt; 'AsPopup',
                                Action                =&gt; 'AgentTicketCompose',
                                FormID                =&gt; 'ReplyAll' . $ArticleItem-&gt;{ArticleID},
                                ReplyAll              =&gt; 1,
                            },
                        );
                    }
                }
            }
        }
    }

    # add action items as js
    if ( @ActionItems &amp;&amp; !$Param{Config}-&gt;{TicketActionsPerTicket} ) {
        my $JSON = $Self-&gt;{LayoutObject}-&gt;JSONEncode(
            Data =&gt; \@ActionItems,
        );

        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'DocumentReadyActionRowAdd',
            Data =&gt; {
                TicketID =&gt; $Param{TicketID},
                Data     =&gt; $JSON,
            },
        );
    }

    # create &amp; return output
    my $Output = $Self-&gt;{LayoutObject}-&gt;Output(
        TemplateFile =&gt; 'AgentTicketOverviewPreview',
        Data         =&gt; {
            %Param,
            %Article,
            %AclAction,
        },
    );
    return \$Output;
}
1;
</pre></body></html>