<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># --
# Kernel/Modules/AgentTicketPrint.pm - print layout for agent interface
# 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::Modules::AgentTicketPrint;

use strict;
use warnings;

use Kernel::System::CustomerUser;
use Kernel::System::LinkObject;
use Kernel::System::PDF;
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 );

    # check needed objects
    for my $Needed (
        qw(ParamObject DBObject TicketObject LayoutObject LogObject QueueObject ConfigObject UserObject MainObject)
        )
    {
        if ( !$Self-&gt;{$Needed} ) {
            $Self-&gt;{LayoutObject}-&gt;FatalError( Message =&gt; "Got no $Needed!" );
        }
    }

    # get config settings
    $Self-&gt;{ZoomExpandSort} = $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::ZoomExpandSort');

    $Self-&gt;{CustomerUserObject} = Kernel::System::CustomerUser-&gt;new(%Param);
    $Self-&gt;{LinkObject}         = Kernel::System::LinkObject-&gt;new(%Param);
    $Self-&gt;{PDFObject}          = Kernel::System::PDF-&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::AgentTicketPrint")-&gt;{DynamicField};

    return $Self;
}

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

    my $Output;
    my $QueueID = $Self-&gt;{TicketObject}-&gt;TicketQueueID( TicketID =&gt; $Self-&gt;{TicketID} );
    my $ArticleID = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'ArticleID' );

    # check needed stuff
    if ( !$Self-&gt;{TicketID} || !$QueueID ) {
        return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'Need TicketID!' );
    }

    # check permissions
    my $Access = $Self-&gt;{TicketObject}-&gt;TicketPermission(
        Type     =&gt; 'ro',
        TicketID =&gt; $Self-&gt;{TicketID},
        UserID   =&gt; $Self-&gt;{UserID}
    );

    return $Self-&gt;{LayoutObject}-&gt;NoPermission( WithHeader =&gt; 'yes' ) if !$Access;

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

    # check if ACL restrictions exist
    if ( IsHashRefWithData( \%AclAction ) ) {

        # show error screen if ACL prohibits this action
        if ( defined $AclAction{ $Self-&gt;{Action} } &amp;&amp; $AclAction{ $Self-&gt;{Action} } eq '0' ) {
            return $Self-&gt;{LayoutObject}-&gt;NoPermission( WithHeader =&gt; 'yes' );
        }
    }

    # get linked objects
    my $LinkListWithData = $Self-&gt;{LinkObject}-&gt;LinkListWithData(
        Object =&gt; 'Ticket',
        Key    =&gt; $Self-&gt;{TicketID},
        State  =&gt; 'Valid',
        UserID =&gt; $Self-&gt;{UserID},
    );

    # get link type list
    my %LinkTypeList = $Self-&gt;{LinkObject}-&gt;TypeList(
        UserID =&gt; $Self-&gt;{UserID},
    );

    # get the link data
    my %LinkData;
    if ( $LinkListWithData &amp;&amp; ref $LinkListWithData eq 'HASH' &amp;&amp; %{$LinkListWithData} ) {
        %LinkData = $Self-&gt;{LayoutObject}-&gt;LinkObjectTableCreate(
            LinkListWithData =&gt; $LinkListWithData,
            ViewMode         =&gt; 'SimpleRaw',
        );
    }

    # get content
    my %Ticket = $Self-&gt;{TicketObject}-&gt;TicketGet(
        TicketID =&gt; $Self-&gt;{TicketID},
        UserID   =&gt; $Self-&gt;{UserID},
    );
    my @ArticleBox = $Self-&gt;{TicketObject}-&gt;ArticleContentIndex(
        TicketID                   =&gt; $Self-&gt;{TicketID},
        StripPlainBodyAsAttachment =&gt; 1,
        UserID                     =&gt; $Self-&gt;{UserID},
        DynamicFields              =&gt; 0,
    );

    # check if only one article need printed
    if ($ArticleID) {

        ARTICLE:
        for my $Article (@ArticleBox) {
            if ( $Article-&gt;{ArticleID} == $ArticleID ) {
                @ArticleBox = ($Article);
                last ARTICLE;
            }
        }
    }

    # resort article order
    if ( $Self-&gt;{ZoomExpandSort} eq 'reverse' ) {
        @ArticleBox = reverse(@ArticleBox);
    }

    # show total accounted time if feature is active:
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::AccountTime') ) {
        $Ticket{TicketTimeUnits} = $Self-&gt;{TicketObject}-&gt;TicketAccountedTimeGet(
            TicketID =&gt; $Ticket{TicketID},
        );
    }

    # user info
    my %UserInfo = $Self-&gt;{UserObject}-&gt;GetUserData(
        User =&gt; $Ticket{Owner},
    );

    # responsible info
    my %ResponsibleInfo;
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Responsible') &amp;&amp; $Ticket{Responsible} ) {
        %ResponsibleInfo = $Self-&gt;{UserObject}-&gt;GetUserData(
            User =&gt; $Ticket{Responsible},
        );
    }

    # customer info
    my %CustomerData;
    if ( $Ticket{CustomerUserID} ) {
        %CustomerData = $Self-&gt;{CustomerUserObject}-&gt;CustomerUserDataGet(
            User =&gt; $Ticket{CustomerUserID},
        );
    }

    # do some html quoting
    $Ticket{Age} = $Self-&gt;{LayoutObject}-&gt;CustomerAge(
        Age   =&gt; $Ticket{Age},
        Space =&gt; ' ',
    );

    if ( $Ticket{UntilTime} ) {
        $Ticket{PendingUntil} = $Self-&gt;{LayoutObject}-&gt;CustomerAge(
            Age   =&gt; $Ticket{UntilTime},
            Space =&gt; ' ',
        );
    }

    # generate pdf output
    if ( $Self-&gt;{PDFObject} ) {
        my $PrintedBy = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('printed by');
        my $Time = $Self-&gt;{LayoutObject}-&gt;Output( Template =&gt; '$Env{"Time"}' );
        my %Page;

        # get maximum number of pages
        $Page{MaxPages} = $Self-&gt;{ConfigObject}-&gt;Get('PDF::MaxPages');
        if ( !$Page{MaxPages} || $Page{MaxPages} &lt; 1 || $Page{MaxPages} &gt; 1000 ) {
            $Page{MaxPages} = 100;
        }
        my $HeaderRight  = $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Hook') . $Ticket{TicketNumber};
        my $HeadlineLeft = $HeaderRight;
        my $Title        = $HeaderRight;
        if ( $Ticket{Title} ) {
            $HeadlineLeft = $Ticket{Title};
            $Title .= ' / ' . $Ticket{Title};
        }

        $Page{MarginTop}    = 30;
        $Page{MarginRight}  = 40;
        $Page{MarginBottom} = 40;
        $Page{MarginLeft}   = 40;
        $Page{HeaderRight}  = $HeaderRight;
        $Page{FooterLeft}   = '';
        $Page{PageText}     = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Page');
        $Page{PageCount}    = 1;

        # create new pdf document
        $Self-&gt;{PDFObject}-&gt;DocumentNew(
            Title  =&gt; $Self-&gt;{ConfigObject}-&gt;Get('Product') . ': ' . $Title,
            Encode =&gt; $Self-&gt;{LayoutObject}-&gt;{UserCharset},
        );

        # create first pdf page
        $Self-&gt;{PDFObject}-&gt;PageNew(
            %Page, FooterRight =&gt; $Page{PageText} . ' ' . $Page{PageCount},
        );
        $Page{PageCount}++;

        $Self-&gt;{PDFObject}-&gt;PositionSet(
            Move =&gt; 'relativ',
            Y    =&gt; -6,
        );

        # output title
        $Self-&gt;{PDFObject}-&gt;Text(
            Text     =&gt; $Ticket{Title},
            FontSize =&gt; 13,
        );

        $Self-&gt;{PDFObject}-&gt;PositionSet(
            Move =&gt; 'relativ',
            Y    =&gt; -6,
        );

        # output "printed by"
        $Self-&gt;{PDFObject}-&gt;Text(
            Text =&gt; $PrintedBy . ' '
                . $Self-&gt;{UserFirstname} . ' '
                . $Self-&gt;{UserLastname} . ' ('
                . $Self-&gt;{UserEmail} . ')'
                . ', ' . $Time,
            FontSize =&gt; 9,
        );

        $Self-&gt;{PDFObject}-&gt;PositionSet(
            Move =&gt; 'relativ',
            Y    =&gt; -14,
        );

        # output ticket infos
        $Self-&gt;_PDFOutputTicketInfos(
            PageData        =&gt; \%Page,
            TicketData      =&gt; \%Ticket,
            UserData        =&gt; \%UserInfo,
            ResponsibleData =&gt; \%ResponsibleInfo,
        );

        # output ticket dynamic fields
        $Self-&gt;_PDFOutputTicketDynamicFields(
            PageData   =&gt; \%Page,
            TicketData =&gt; \%Ticket,
        );

        # output linked objects
        if (%LinkData) {
            $Self-&gt;_PDFOutputLinkedObjects(
                PageData     =&gt; \%Page,
                LinkData     =&gt; \%LinkData,
                LinkTypeList =&gt; \%LinkTypeList,
            );
        }

        # output customer infos
        if (%CustomerData) {
            $Self-&gt;_PDFOutputCustomerInfos(
                PageData     =&gt; \%Page,
                CustomerData =&gt; \%CustomerData,
            );
        }

        # output articles
        $Self-&gt;_PDFOutputArticles(
            PageData    =&gt; \%Page,
            ArticleData =&gt; \@ArticleBox,
        );

        # return the pdf document
        my $Filename = 'Ticket_' . $Ticket{TicketNumber};
        my ( $s, $m, $h, $D, $M, $Y ) = $Self-&gt;{TimeObject}-&gt;SystemTime2Date(
            SystemTime =&gt; $Self-&gt;{TimeObject}-&gt;SystemTime(),
        );
        $M = sprintf( "%02d", $M );
        $D = sprintf( "%02d", $D );
        $h = sprintf( "%02d", $h );
        $m = sprintf( "%02d", $m );
        my $PDFString = $Self-&gt;{PDFObject}-&gt;DocumentOutput();
        return $Self-&gt;{LayoutObject}-&gt;Attachment(
            Filename    =&gt; $Filename . "_" . "$Y-$M-$D" . "_" . "$h-$m.pdf",
            ContentType =&gt; "application/pdf",
            Content     =&gt; $PDFString,
            Type        =&gt; 'attachment',
        );
    }

    # generate html output
    else {

        # output header
        $Output .= $Self-&gt;{LayoutObject}-&gt;PrintHeader( Value =&gt; $Ticket{TicketNumber} );

        if (%LinkData) {

            # output link data
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'Link',
            );

            for my $LinkTypeLinkDirection ( sort { lc $a cmp lc $b } keys %LinkData ) {

                # investigate link type name
                my @LinkData = split q{::}, $LinkTypeLinkDirection;

                # output link type data
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'LinkType',
                    Data =&gt; {
                        LinkTypeName =&gt; $LinkTypeList{ $LinkData[0] }-&gt;{ $LinkData[1] . 'Name' },
                    },
                );

                # extract object list
                my $ObjectList = $LinkData{$LinkTypeLinkDirection};

                for my $Object ( sort { lc $a cmp lc $b } keys %{$ObjectList} ) {

                    for my $Item ( @{ $ObjectList-&gt;{$Object} } ) {

                        # output link type data
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; 'LinkTypeRow',
                            Data =&gt; {
                                LinkStrg =&gt; $Item-&gt;{Title},
                            },
                        );
                    }
                }
            }
        }

        # output customer infos
        if (%CustomerData) {
            $Param{CustomerTable} = $Self-&gt;{LayoutObject}-&gt;AgentCustomerViewTable(
                Data =&gt; \%CustomerData,
                Max  =&gt; 100,
            );
        }

        # show ticket
        $Output .= $Self-&gt;_HTMLMask(
            TicketID        =&gt; $Self-&gt;{TicketID},
            QueueID         =&gt; $QueueID,
            ArticleBox      =&gt; \@ArticleBox,
            ResponsibleData =&gt; \%ResponsibleInfo,
            %Param,
            %UserInfo,
            %Ticket,
        );

        # add footer
        $Output .= $Self-&gt;{LayoutObject}-&gt;PrintFooter();

        # return output
        return $Output;
    }
}

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

    # check needed stuff
    for my $Needed (qw(PageData TicketData UserData)) {
        if ( !defined( $Param{$Needed} ) ) {
            $Self-&gt;{LogObject}-&gt;Log( Priority =&gt; 'error', Message =&gt; "Need $Needed!" );
            return;
        }
    }
    my %Ticket   = %{ $Param{TicketData} };
    my %UserInfo = %{ $Param{UserData} };
    my %Page     = %{ $Param{PageData} };

    # create left table
    my $TableLeft = [
        {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('State'),
            Value =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( $Ticket{State} ),
        },
        {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Priority'),
            Value =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( $Ticket{Priority} ),
        },
        {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Queue'),
            Value =&gt; $Ticket{Queue},
        },
        {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Lock'),
            Value =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( $Ticket{Lock} ),
        },
        {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('CustomerID'),
            Value =&gt; $Ticket{CustomerID},
        },
        {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Owner'),
            Value =&gt; $Ticket{Owner} . ' ('
                . $UserInfo{UserFirstname} . ' '
                . $UserInfo{UserLastname} . ')',
        },
    ];

    # add responsible row, if feature is enabled
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Responsible') ) {
        my $Responsible = '-';
        if ( $Ticket{Responsible} ) {
            $Responsible
                = $Ticket{Responsible} . ' ('
                . $Param{ResponsibleData}-&gt;{UserFirstname} . ' '
                . $Param{ResponsibleData}-&gt;{UserLastname} . ')';
        }
        my $Row = {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Responsible'),
            Value =&gt; $Responsible,
        };
        push( @{$TableLeft}, $Row );
    }

    # add type row, if feature is enabled
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Type') ) {
        my $Row = {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Type'),
            Value =&gt; $Ticket{Type},
        };
        push( @{$TableLeft}, $Row );
    }

    # add service and sla row, if feature is enabled
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Service') ) {
        my $RowService = {
            Key =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Service'),
            Value =&gt; $Ticket{Service} || '-',
        };
        push( @{$TableLeft}, $RowService );
        my $RowSLA = {
            Key =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('SLA'),
            Value =&gt; $Ticket{SLA} || '-',
        };
        push( @{$TableLeft}, $RowSLA );
    }

    # create right table
    my $TableRight = [
        {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Age'),
            Value =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( $Ticket{Age} ),
        },
        {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Created'),
            Value =&gt; $Self-&gt;{LayoutObject}-&gt;Output(
                Template =&gt; '$TimeLong{"$Data{"Created"}"}',
                Data     =&gt; \%Ticket,
            ),
        },
    ];

    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::AccountTime') ) {
        my $Row = {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Accounted time'),
            Value =&gt; $Ticket{TicketTimeUnits},
        };
        push( @{$TableRight}, $Row );
    }

    # only show pending until unless it is really pending
    if ( $Ticket{PendingUntil} ) {
        my $Row = {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Pending till'),
            Value =&gt; $Ticket{PendingUntil},
        };
        push( @{$TableRight}, $Row );
    }

    # add first response time row
    if ( defined( $Ticket{FirstResponseTime} ) ) {
        my $Row = {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('First Response Time'),
            Value =&gt; $Self-&gt;{LayoutObject}-&gt;Output(
                Template =&gt; '$TimeShort{"$QData{"FirstResponseTimeDestinationDate"}"}',
                Data     =&gt; \%Ticket,
            ),
        };
        push( @{$TableRight}, $Row );
    }

    # add update time row
    if ( defined( $Ticket{UpdateTime} ) ) {
        my $Row = {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Update Time'),
            Value =&gt; $Self-&gt;{LayoutObject}-&gt;Output(
                Template =&gt; '$TimeShort{"$QData{"UpdateTimeDestinationDate"}"}',
                Data     =&gt; \%Ticket,
            ),
        };
        push( @{$TableRight}, $Row );
    }

    # add solution time row
    if ( defined( $Ticket{SolutionTime} ) ) {
        my $Row = {
            Key   =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Solution Time'),
            Value =&gt; $Self-&gt;{LayoutObject}-&gt;Output(
                Template =&gt; '$TimeShort{"$QData{"SolutionTimeDestinationDate"}"}',
                Data     =&gt; \%Ticket,
            ),
        };
        push( @{$TableRight}, $Row );
    }

    my $Rows = @{$TableLeft};
    if ( @{$TableRight} &gt; $Rows ) {
        $Rows = @{$TableRight};
    }

    my %TableParam;
    for my $Row ( 1 .. $Rows ) {
        $Row--;
        $TableParam{CellData}[$Row][0]{Content}         = $TableLeft-&gt;[$Row]-&gt;{Key};
        $TableParam{CellData}[$Row][0]{Font}            = 'ProportionalBold';
        $TableParam{CellData}[$Row][1]{Content}         = $TableLeft-&gt;[$Row]-&gt;{Value};
        $TableParam{CellData}[$Row][2]{Content}         = ' ';
        $TableParam{CellData}[$Row][2]{BackgroundColor} = '#FFFFFF';
        $TableParam{CellData}[$Row][3]{Content}         = $TableRight-&gt;[$Row]-&gt;{Key};
        $TableParam{CellData}[$Row][3]{Font}            = 'ProportionalBold';
        $TableParam{CellData}[$Row][4]{Content}         = $TableRight-&gt;[$Row]-&gt;{Value};
    }

    $TableParam{ColumnData}[0]{Width} = 70;
    $TableParam{ColumnData}[1]{Width} = 156.5;
    $TableParam{ColumnData}[2]{Width} = 1;
    $TableParam{ColumnData}[3]{Width} = 70;
    $TableParam{ColumnData}[4]{Width} = 156.5;

    $TableParam{Type}                = 'Cut';
    $TableParam{Border}              = 0;
    $TableParam{FontSize}            = 7;
    $TableParam{BackgroundColorEven} = '#DDDDDD';
    $TableParam{Padding}             = 6;
    $TableParam{PaddingTop}          = 3;
    $TableParam{PaddingBottom}       = 3;

    # output table
    for ( $Page{PageCount} .. $Page{MaxPages} ) {

        # output table (or a fragment of it)
        %TableParam = $Self-&gt;{PDFObject}-&gt;Table( %TableParam, );

        # stop output or output next page
        if ( $TableParam{State} ) {
            last;
        }
        else {
            $Self-&gt;{PDFObject}-&gt;PageNew(
                %Page, FooterRight =&gt; $Page{PageText} . ' ' . $Page{PageCount},
            );
            $Page{PageCount}++;
        }
    }
    return 1;
}

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

    # check needed stuff
    for my $Needed (qw(PageData LinkData LinkTypeList)) {
        if ( !defined( $Param{$Needed} ) ) {
            $Self-&gt;{LogObject}-&gt;Log( Priority =&gt; 'error', Message =&gt; "Need $Needed!" );
            return;
        }
    }

    my %Page     = %{ $Param{PageData} };
    my %TypeList = %{ $Param{LinkTypeList} };
    my %TableParam;
    my $Row = 0;

    for my $LinkTypeLinkDirection ( sort { lc $a cmp lc $b } keys %{ $Param{LinkData} } ) {

        # investigate link type name
        my @LinkData = split q{::}, $LinkTypeLinkDirection;
        my $LinkTypeName = $TypeList{ $LinkData[0] }-&gt;{ $LinkData[1] . 'Name' };
        $LinkTypeName = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get($LinkTypeName);

        # define headline
        $TableParam{CellData}[$Row][0]{Content} = $LinkTypeName . ':';
        $TableParam{CellData}[$Row][0]{Font}    = 'ProportionalBold';
        $TableParam{CellData}[$Row][1]{Content} = '';

        # extract object list
        my $ObjectList = $Param{LinkData}-&gt;{$LinkTypeLinkDirection};

        for my $Object ( sort { lc $a cmp lc $b } keys %{$ObjectList} ) {

            for my $Item ( @{ $ObjectList-&gt;{$Object} } ) {

                $TableParam{CellData}[$Row][0]{Content} ||= '';
                $TableParam{CellData}[$Row][1]{Content} = $Item-&gt;{Title} || '';
            }
            continue {
                $Row++;
            }
        }
    }

    $TableParam{ColumnData}[0]{Width} = 80;
    $TableParam{ColumnData}[1]{Width} = 431;

    # set new position
    $Self-&gt;{PDFObject}-&gt;PositionSet(
        Move =&gt; 'relativ',
        Y    =&gt; -15,
    );

    # output headline
    $Self-&gt;{PDFObject}-&gt;Text(
        Text     =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Linked Objects'),
        Height   =&gt; 7,
        Type     =&gt; 'Cut',
        Font     =&gt; 'ProportionalBoldItalic',
        FontSize =&gt; 7,
        Color    =&gt; '#666666',
    );

    # set new position
    $Self-&gt;{PDFObject}-&gt;PositionSet(
        Move =&gt; 'relativ',
        Y    =&gt; -4,
    );

    # table params
    $TableParam{Type}            = 'Cut';
    $TableParam{Border}          = 0;
    $TableParam{FontSize}        = 6;
    $TableParam{BackgroundColor} = '#DDDDDD';
    $TableParam{Padding}         = 1;
    $TableParam{PaddingTop}      = 3;
    $TableParam{PaddingBottom}   = 3;

    # output table
    for ( $Page{PageCount} .. $Page{MaxPages} ) {

        # output table (or a fragment of it)
        %TableParam = $Self-&gt;{PDFObject}-&gt;Table( %TableParam, );

        # stop output or output next page
        if ( $TableParam{State} ) {
            last;
        }
        else {
            $Self-&gt;{PDFObject}-&gt;PageNew(
                %Page, FooterRight =&gt; $Page{PageText} . ' ' . $Page{PageCount},
            );
            $Page{PageCount}++;
        }
    }

    return 1;
}

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

    # check needed stuff
    for my $Needed (qw(PageData TicketData)) {
        if ( !defined( $Param{$Needed} ) ) {
            $Self-&gt;{LogObject}-&gt;Log( Priority =&gt; 'error', Message =&gt; "Need $Needed!" );
            return;
        }
    }
    my $Output = 0;
    my %Ticket = %{ $Param{TicketData} };
    my %Page   = %{ $Param{PageData} };

    my %TableParam;
    my $Row = 0;

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

    # generate table
    # cycle trough the activated Dynamic Fields for ticket object
    DYNAMICFIELD:
    for my $DynamicFieldConfig ( @{$DynamicField} ) {
        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);

        my $Value = $Self-&gt;{BackendObject}-&gt;ValueGet(
            DynamicFieldConfig =&gt; $DynamicFieldConfig,
            ObjectID           =&gt; $Ticket{TicketID},
        );

        next DYNAMICFIELD if !$Value;
        next DYNAMICFIELD if $Value eq "";

        # get print string for this dynamic field
        my $ValueStrg = $Self-&gt;{BackendObject}-&gt;DisplayValueRender(
            DynamicFieldConfig =&gt; $DynamicFieldConfig,
            Value              =&gt; $Value,
            HTMLOutput         =&gt; 0,
            LayoutObject       =&gt; $Self-&gt;{LayoutObject},
        );

        $TableParam{CellData}[$Row][0]{Content}
            = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( $DynamicFieldConfig-&gt;{Label} ) . ':';
        $TableParam{CellData}[$Row][0]{Font}    = 'ProportionalBold';
        $TableParam{CellData}[$Row][1]{Content} = $ValueStrg-&gt;{Value};

        $Row++;
        $Output = 1;
    }

    $TableParam{ColumnData}[0]{Width} = 80;
    $TableParam{ColumnData}[1]{Width} = 431;

    # output ticket dynamic fields
    if ($Output) {

        # set new position
        $Self-&gt;{PDFObject}-&gt;PositionSet(
            Move =&gt; 'relativ',
            Y    =&gt; -15,
        );

        # output headline
        $Self-&gt;{PDFObject}-&gt;Text(
            Text     =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Ticket Dynamic Fields'),
            Height   =&gt; 7,
            Type     =&gt; 'Cut',
            Font     =&gt; 'ProportionalBoldItalic',
            FontSize =&gt; 7,
            Color    =&gt; '#666666',
        );

        # set new position
        $Self-&gt;{PDFObject}-&gt;PositionSet(
            Move =&gt; 'relativ',
            Y    =&gt; -4,
        );

        # table params
        $TableParam{Type}            = 'Cut';
        $TableParam{Border}          = 0;
        $TableParam{FontSize}        = 6;
        $TableParam{BackgroundColor} = '#DDDDDD';
        $TableParam{Padding}         = 1;
        $TableParam{PaddingTop}      = 3;
        $TableParam{PaddingBottom}   = 3;

        # output table
        for ( $Page{PageCount} .. $Page{MaxPages} ) {

            # output table (or a fragment of it)
            %TableParam = $Self-&gt;{PDFObject}-&gt;Table( %TableParam, );

            # stop output or output next page
            if ( $TableParam{State} ) {
                last;
            }
            else {
                $Self-&gt;{PDFObject}-&gt;PageNew(
                    %Page, FooterRight =&gt; $Page{PageText} . ' ' . $Page{PageCount},
                );
                $Page{PageCount}++;
            }
        }
    }
    return 1;
}

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

    # check needed stuff
    for my $Needed (qw(PageData CustomerData)) {
        if ( !defined( $Param{$Needed} ) ) {
            $Self-&gt;{LogObject}-&gt;Log( Priority =&gt; 'error', Message =&gt; "Need $Needed!" );
            return;
        }
    }
    my $Output       = 0;
    my %CustomerData = %{ $Param{CustomerData} };
    my %Page         = %{ $Param{PageData} };
    my %TableParam;
    my $Row = 0;
    my $Map = $CustomerData{Config}-&gt;{Map};

    # check if customer company support is enabled
    if ( $CustomerData{Config}-&gt;{CustomerCompanySupport} ) {
        my $Map2 = $CustomerData{CompanyConfig}-&gt;{Map};
        if ($Map2) {
            push( @{$Map}, @{$Map2} );
        }
    }
    for my $Field ( @{$Map} ) {
        if ( ${$Field}[3] &amp;&amp; $CustomerData{ ${$Field}[0] } ) {
            $TableParam{CellData}[$Row][0]{Content}
                = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( ${$Field}[1] ) . ':';
            $TableParam{CellData}[$Row][0]{Font}    = 'ProportionalBold';
            $TableParam{CellData}[$Row][1]{Content} = $CustomerData{ ${$Field}[0] };

            $Row++;
            $Output = 1;
        }
    }
    $TableParam{ColumnData}[0]{Width} = 80;
    $TableParam{ColumnData}[1]{Width} = 431;

    if ($Output) {

        # set new position
        $Self-&gt;{PDFObject}-&gt;PositionSet(
            Move =&gt; 'relativ',
            Y    =&gt; -15,
        );

        # output headline
        $Self-&gt;{PDFObject}-&gt;Text(
            Text     =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Customer Information'),
            Height   =&gt; 7,
            Type     =&gt; 'Cut',
            Font     =&gt; 'ProportionalBoldItalic',
            FontSize =&gt; 7,
            Color    =&gt; '#666666',
        );

        # set new position
        $Self-&gt;{PDFObject}-&gt;PositionSet(
            Move =&gt; 'relativ',
            Y    =&gt; -4,
        );

        # table params
        $TableParam{Type}            = 'Cut';
        $TableParam{Border}          = 0;
        $TableParam{FontSize}        = 6;
        $TableParam{BackgroundColor} = '#DDDDDD';
        $TableParam{Padding}         = 1;
        $TableParam{PaddingTop}      = 3;
        $TableParam{PaddingBottom}   = 3;

        # output table
        for ( $Page{PageCount} .. $Page{MaxPages} ) {

            # output table (or a fragment of it)
            %TableParam = $Self-&gt;{PDFObject}-&gt;Table( %TableParam, );

            # stop output or output next page
            if ( $TableParam{State} ) {
                last;
            }
            else {
                $Self-&gt;{PDFObject}-&gt;PageNew(
                    %Page, FooterRight =&gt; $Page{PageText} . ' ' . $Page{PageCount},
                );
                $Page{PageCount}++;
            }
        }
    }
    return 1;
}

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

    # check needed stuff
    for my $Needed (qw(PageData ArticleData)) {
        if ( !defined( $Param{$Needed} ) ) {
            $Self-&gt;{LogObject}-&gt;Log( Priority =&gt; 'error', Message =&gt; "Need $Needed!" );
            return;
        }
    }
    my %Page = %{ $Param{PageData} };

    my $ArticleCounter = 1;
    for my $ArticleTmp ( @{ $Param{ArticleData} } ) {
        if ( $ArticleCounter == 1 ) {
            $Self-&gt;{PDFObject}-&gt;PositionSet(
                Move =&gt; 'relativ',
                Y    =&gt; -15,
            );

            # output headline
            $Self-&gt;{PDFObject}-&gt;Text(
                Text     =&gt; $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Articles'),
                Height   =&gt; 7,
                Type     =&gt; 'Cut',
                Font     =&gt; 'ProportionalBoldItalic',
                FontSize =&gt; 7,
                Color    =&gt; '#666666',
            );
            $Self-&gt;{PDFObject}-&gt;PositionSet(
                Move =&gt; 'relativ',
                Y    =&gt; 2,
            );
        }

        my %Article = %{$ArticleTmp};

        # get attachment string
        my %AtmIndex = ();
        if ( $Article{Atms} ) {
            %AtmIndex = %{ $Article{Atms} };
        }
        my $Attachments;
        for my $FileID ( sort keys %AtmIndex ) {
            my %File = %{ $AtmIndex{$FileID} };
            $Attachments .= $File{Filename} . ' (' . $File{Filesize} . ")\n";
        }

        # show total accounted time if feature is active:
        if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::AccountTime') ) {
            $Article{'Accounted time'} = $Self-&gt;{TicketObject}-&gt;ArticleAccountedTimeGet(
                ArticleID =&gt; $Article{ArticleID},
            );
        }

        # generate article info table
        my %TableParam1;
        my $Row = 0;

        $Self-&gt;{PDFObject}-&gt;PositionSet(
            Move =&gt; 'relativ',
            Y    =&gt; -6,
        );

        # article number tag
        $Self-&gt;{PDFObject}-&gt;Text(
            Text     =&gt; '    # ' . $ArticleCounter,
            Height   =&gt; 7,
            Type     =&gt; 'Cut',
            Font     =&gt; 'ProportionalBoldItalic',
            FontSize =&gt; 7,
            Color    =&gt; '#666666',
        );

        $Self-&gt;{PDFObject}-&gt;PositionSet(
            Move =&gt; 'relativ',
            Y    =&gt; 2,
        );

        for my $Parameter ( 'From', 'To', 'Cc', 'Accounted time', 'Subject', ) {
            if ( $Article{$Parameter} ) {
                $TableParam1{CellData}[$Row][0]{Content}
                    = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get($Parameter) . ':';
                $TableParam1{CellData}[$Row][0]{Font}    = 'ProportionalBold';
                $TableParam1{CellData}[$Row][1]{Content} = $Article{$Parameter};
                $Row++;
            }
        }
        $TableParam1{CellData}[$Row][0]{Content}
            = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Created') . ':';
        $TableParam1{CellData}[$Row][0]{Font}    = 'ProportionalBold';
        $TableParam1{CellData}[$Row][1]{Content} = $Self-&gt;{LayoutObject}-&gt;Output(
            Template =&gt; '$TimeLong{"$Data{"Created"}"}',
            Data     =&gt; \%Article,
        );
        $TableParam1{CellData}[$Row][1]{Content}
            .= ' ' . $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('by');
        $TableParam1{CellData}[$Row][1]{Content}
            .= ' ' . $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( $Article{SenderType} );
        $Row++;

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

        # generate table
        # cycle trough the activated Dynamic Fields for ticket object
        DYNAMICFIELD:
        for my $DynamicFieldConfig ( @{$DynamicField} ) {
            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);

            my $Value = $Self-&gt;{BackendObject}-&gt;ValueGet(
                DynamicFieldConfig =&gt; $DynamicFieldConfig,
                ObjectID           =&gt; $Article{ArticleID},
            );

            next DYNAMICFIELD if !$Value;
            next DYNAMICFIELD if $Value eq "";

            # get print string for this dynamic field
            my $ValueStrg = $Self-&gt;{BackendObject}-&gt;DisplayValueRender(
                DynamicFieldConfig =&gt; $DynamicFieldConfig,
                Value              =&gt; $Value,
                HTMLOutput         =&gt; 0,
                LayoutObject       =&gt; $Self-&gt;{LayoutObject},
            );
            $TableParam1{CellData}[$Row][0]{Content}
                = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( $DynamicFieldConfig-&gt;{Label} )
                . ':';
            $TableParam1{CellData}[$Row][0]{Font}    = 'ProportionalBold';
            $TableParam1{CellData}[$Row][1]{Content} = $ValueStrg-&gt;{Value};
            $Row++;
        }

        $TableParam1{CellData}[$Row][0]{Content}
            = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Type') . ':';
        $TableParam1{CellData}[$Row][0]{Font} = 'ProportionalBold';
        $TableParam1{CellData}[$Row][1]{Content}
            = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get( $Article{ArticleType} );
        $Row++;

        if ($Attachments) {
            $TableParam1{CellData}[$Row][0]{Content}
                = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get('Attachment') . ':';
            $TableParam1{CellData}[$Row][0]{Font} = 'ProportionalBold';
            chomp($Attachments);
            $TableParam1{CellData}[$Row][1]{Content} = $Attachments;
        }
        $TableParam1{ColumnData}[0]{Width} = 80;
        $TableParam1{ColumnData}[1]{Width} = 431;

        $Self-&gt;{PDFObject}-&gt;PositionSet(
            Move =&gt; 'relativ',
            Y    =&gt; -6,
        );

        # table params (article infos)
        $TableParam1{Type}            = 'Cut';
        $TableParam1{Border}          = 0;
        $TableParam1{FontSize}        = 6;
        $TableParam1{BackgroundColor} = '#DDDDDD';
        $TableParam1{Padding}         = 1;
        $TableParam1{PaddingTop}      = 3;
        $TableParam1{PaddingBottom}   = 3;

        # output table (article infos)
        for ( $Page{PageCount} .. $Page{MaxPages} ) {

            # output table (or a fragment of it)
            %TableParam1 = $Self-&gt;{PDFObject}-&gt;Table( %TableParam1, );

            # stop output or output next page
            if ( $TableParam1{State} ) {
                last;
            }
            else {
                $Self-&gt;{PDFObject}-&gt;PageNew(
                    %Page, FooterRight =&gt; $Page{PageText} . ' ' . $Page{PageCount},
                );
                $Page{PageCount}++;
            }
        }

        # table params (article body)
        my %TableParam2;
        $TableParam2{CellData}[0][0]{Content} = $Article{Body} || ' ';
        $TableParam2{Type}                    = 'Cut';
        $TableParam2{Border}                  = 0;
        $TableParam2{Font}                    = 'Monospaced';
        $TableParam2{FontSize}                = 7;
        $TableParam2{BackgroundColor}         = '#DDDDDD';
        $TableParam2{Padding}                 = 4;
        $TableParam2{PaddingTop}              = 8;
        $TableParam2{PaddingBottom}           = 8;

        # output table (article body)
        for ( $Page{PageCount} .. $Page{MaxPages} ) {

            # output table (or a fragment of it)
            %TableParam2 = $Self-&gt;{PDFObject}-&gt;Table( %TableParam2, );

            # stop output or output next page
            if ( $TableParam2{State} ) {
                last;
            }
            else {
                $Self-&gt;{PDFObject}-&gt;PageNew(
                    %Page, FooterRight =&gt; $Page{PageText} . ' ' . $Page{PageCount},
                );
                $Page{PageCount}++;
            }
        }
        $ArticleCounter++;
    }
    return 1;
}

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

    # output responsible, if feature is enabled
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Responsible') ) {
        my $Responsible = '-';
        if ( $Param{Responsible} ) {
            $Responsible
                = $Param{Responsible} . ' ('
                . $Param{ResponsibleData}-&gt;{UserFirstname} . ' '
                . $Param{ResponsibleData}-&gt;{UserLastname} . ')';
        }
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Responsible',
            Data =&gt; { ResponsibleString =&gt; $Responsible, },
        );
    }

    # output type, if feature is enabled
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Type') ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'TicketType',
            Data =&gt; { %Param, },
        );
    }

    # output service and sla, if feature is enabled
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Service') ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'TicketService',
            Data =&gt; {
                Service =&gt; $Param{Service} || '-',
                SLA     =&gt; $Param{SLA}     || '-',
            },
        );
    }

    # output accounted time
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::Frontend::AccountTime') ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'AccountedTime',
            Data =&gt; {%Param},
        );
    }

    # output pending date
    if ( $Param{PendingUntil} ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'PendingUntil',
            Data =&gt; {%Param},
        );
    }

    # output first response time
    if ( defined( $Param{FirstResponseTime} ) ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'FirstResponseTime',
            Data =&gt; {%Param},
        );
    }

    # output update time
    if ( defined( $Param{UpdateTime} ) ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'UpdateTime',
            Data =&gt; {%Param},
        );
    }

    # output solution time
    if ( defined( $Param{SolutionTime} ) ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'SolutionTime',
            Data =&gt; {%Param},
        );
    }

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

    # cycle trough the activated Dynamic Fields for ticket object
    DYNAMICFIELD:
    for my $DynamicFieldConfig ( @{$DynamicField} ) {
        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);

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

        next DYNAMICFIELD if !$Value;
        next DYNAMICFIELD if $Value eq "";

        # get print string for this dynamic field
        my $ValueStrg = $Self-&gt;{BackendObject}-&gt;DisplayValueRender(
            DynamicFieldConfig =&gt; $DynamicFieldConfig,
            Value              =&gt; $Value,
            HTMLOutput         =&gt; 1,
            ValueMaxChars      =&gt; 20,
            LayoutObject       =&gt; $Self-&gt;{LayoutObject},
        );

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

        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'TicketDynamicField',
            Data =&gt; {
                Label =&gt; $Label,
                Value =&gt; $ValueStrg-&gt;{Value},
                Title =&gt; $ValueStrg-&gt;{Title},
            },
        );

        # example of dynamic fields order customization
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'TicketDynamicField_' . $DynamicFieldConfig-&gt;{Name},
            Data =&gt; {
                Label =&gt; $Label,
                Value =&gt; $ValueStrg-&gt;{Value},
                Title =&gt; $ValueStrg-&gt;{Title},
            },
        );
    }

    # build article stuff
    my $SelectedArticleID = $Param{ArticleID} || '';
    my @ArticleBox = @{ $Param{ArticleBox} };

    # get last customer article
    for my $ArticleTmp (@ArticleBox) {
        my %Article = %{$ArticleTmp};

        # get attachment string
        my %AtmIndex = ();
        if ( $Article{Atms} ) {
            %AtmIndex = %{ $Article{Atms} };
        }
        $Param{'Article::ATM'} = '';
        for my $FileID ( sort keys %AtmIndex ) {
            my %File = %{ $AtmIndex{$FileID} };
            $File{Filename} = $Self-&gt;{LayoutObject}-&gt;Ascii2Html( Text =&gt; $File{Filename} );
            $Param{'Article::ATM'}
                .= '&lt;a href="$Env{"Baselink"}Action=AgentTicketAttachment;'
                . "ArticleID=$Article{ArticleID};FileID=$FileID\" target=\"attachment\" "
                . "title=\"\$Text{\"Download\"}: $File{Filename}\"&gt;"
                . "$File{Filename}&lt;/a&gt; $File{Filesize}&lt;br/&gt;";
        }

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

            # html quoting
            $Article{Body} = $Self-&gt;{LayoutObject}-&gt;Ascii2Html(
                NewLine =&gt; $Self-&gt;{ConfigObject}-&gt;Get('DefaultViewNewLine'),
                Text    =&gt; $Article{Body},
                VMax    =&gt; $Self-&gt;{ConfigObject}-&gt;Get('DefaultViewLines') || 5000,
            );

            # do charset check
            my $CharsetText = $Self-&gt;{LayoutObject}-&gt;CheckCharset(
                %Param, %Article, Action =&gt; 'AgentTicketZoom'
            );
            if ($CharsetText) {
                $Param{'Article::TextNote'} = $CharsetText;
            }
        }
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Article',
            Data =&gt; { %Param, %Article },
        );

        # do some strips &amp;&amp; quoting
        for my $Parameter (qw(From To Cc Subject)) {
            if ( $Article{$Parameter} ) {
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'Row',
                    Data =&gt; {
                        Key   =&gt; $Parameter,
                        Value =&gt; $Article{$Parameter},
                    },
                );
            }
        }

        # show accounted article time
        if ( $Self-&gt;{ConfigObject}-&gt;Get('Ticket::ZoomTimeDisplay') ) {
            my $ArticleTime = $Self-&gt;{TicketObject}-&gt;ArticleAccountedTimeGet(
                ArticleID =&gt; $Article{ArticleID},
            );
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; "Row",
                Data =&gt; {
                    Key   =&gt; 'Time',
                    Value =&gt; $ArticleTime,
                },
            );
        }

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

        # cycle trough the activated Dynamic Fields for ticket object
        DYNAMICFIELD:
        for my $DynamicFieldConfig ( @{$DynamicField} ) {
            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);

            my $Value = $Self-&gt;{BackendObject}-&gt;ValueGet(
                DynamicFieldConfig =&gt; $DynamicFieldConfig,
                ObjectID           =&gt; $Article{ArticleID},
            );

            next DYNAMICFIELD if !$Value;
            next DYNAMICFIELD if $Value eq "";

            # get print string for this dynamic field
            my $ValueStrg = $Self-&gt;{BackendObject}-&gt;DisplayValueRender(
                DynamicFieldConfig =&gt; $DynamicFieldConfig,
                Value              =&gt; $Value,
                HTMLOutput         =&gt; 1,
                ValueMaxChars      =&gt; 20,
                LayoutObject       =&gt; $Self-&gt;{LayoutObject},
            );

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

            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'ArticleDynamicField',
                Data =&gt; {
                    Label =&gt; $Label,
                    Value =&gt; $ValueStrg-&gt;{Value},
                    Title =&gt; $ValueStrg-&gt;{Title},
                },
            );

            # example of dynamic fields order customization
            #            $Self-&gt;{LayoutObject}-&gt;Block(
            #                Name =&gt; 'ArticleDynamicField_' . $DynamicFieldConfig-&gt;{Name},
            #                Data =&gt; {
            #                    Label =&gt; $Label,
            #                    Value =&gt; $ValueStrg-&gt;{Value},
            #                    Title =&gt; $ValueStrg-&gt;{Title},
            #                },
            #            );
        }
    }

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

1;
</pre></body></html>