Files
scripts/Perl OTRS/Kernel/Output/PDF/Ticket.pm
2024-10-14 00:08:40 +02:00

1263 lines
40 KiB
Perl

# --
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
# --
package Kernel::Output::PDF::Ticket;
use strict;
use warnings;
our @ObjectDependencies = (
'Kernel::Config',
'Kernel::Output::HTML::Layout',
'Kernel::System::LinkObject',
'Kernel::System::Log',
'Kernel::System::PDF',
'Kernel::System::JSON',
'Kernel::System::User',
'Kernel::System::CustomerUser',
'Kernel::System::Ticket',
'Kernel::System::Ticket::Article',
'Kernel::System::DynamicField',
'Kernel::System::DynamicField::Backend',
);
use Kernel::System::VariableCheck qw(IsHashRefWithData);
sub new {
my ( $Type, %Param ) = @_;
# Allocate new hash for object.
my $Self = {};
bless( $Self, $Type );
return $Self;
}
sub GeneratePDF {
my ( $Self, %Param ) = @_;
# Check needed params.
for my $Needed (qw(TicketID UserID Interface)) {
if ( !$Param{$Needed} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => "error",
Message => "Need $Needed!"
);
return;
}
}
# Get appropriate interface flag.
my %Interface;
if ( $Param{Interface} eq 'Agent' ) {
$Interface{Agent} = 1;
}
elsif ( $Param{Interface} eq 'Customer' ) {
$Interface{Customer} = 1;
$Interface{IsVisibleForCustomer} = {
IsVisibleForCustomer => 1,
};
}
# Get ticket content.
my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');
my %Ticket = $TicketObject->TicketGet(
TicketID => $Param{TicketID},
DynamicFields => 0,
UserID => $Param{UserID},
);
# Get article list.
my $ArticleObject = $Kernel::OM->Get('Kernel::System::Ticket::Article');
my @MetaArticles = $ArticleObject->ArticleList(
TicketID => $Ticket{TicketID},
UserID => $Param{UserID},
%{ $Interface{IsVisibleForCustomer} },
);
# Check if only one article should be printed in agent interface.
if ( $Param{ArticleID} ) {
@MetaArticles = grep { $_->{ArticleID} == $Param{ArticleID} } @MetaArticles;
}
# Get article content.
my @ArticleBox;
for my $MetaArticle (@MetaArticles) {
my $ArticleBackendObject = $ArticleObject->BackendForArticle( %{$MetaArticle} );
my %Article = $ArticleBackendObject->ArticleGet(
%{$MetaArticle},
DynamicFields => 0,
);
my %Attachments = $ArticleBackendObject->ArticleAttachmentIndex(
%{$MetaArticle},
ExcludePlainText => 1,
ExcludeHTMLBody => 1,
ExcludeInline => 1,
);
$Article{Atms} = \%Attachments;
push @ArticleBox, \%Article;
}
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $LinkObject = $Kernel::OM->Get('Kernel::System::LinkObject');
# Get necessary data only for agent interface.
my %TicketInfo;
my %LinkData;
if ( $Interface{Agent} ) {
# Show total accounted time if feature is active.
if ( $ConfigObject->Get('Ticket::Frontend::AccountTime') ) {
$Ticket{TicketTimeUnits} = $TicketObject->TicketAccountedTimeGet(
TicketID => $Ticket{TicketID},
);
}
# Get user data.
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
my %User = $UserObject->GetUserData(
UserID => $Param{UserID},
);
$TicketInfo{User} = \%User;
# Get owner info.
my %Owner = $UserObject->GetUserData(
User => $Ticket{Owner},
);
$TicketInfo{Owner} = \%Owner;
# Get responsible info.
if ( $ConfigObject->Get('Ticket::Responsible') && $Ticket{Responsible} ) {
my %Responsible = $UserObject->GetUserData(
User => $Ticket{Responsible},
);
$TicketInfo{Responsible} = \%Responsible;
}
# Get link ticket data.
my $LinkListWithData = $LinkObject->LinkListWithData(
Object => 'Ticket',
Key => $Param{TicketID},
State => 'Valid',
UserID => $Param{UserID},
ObjectParameters => {
Ticket => {
IgnoreLinkedTicketStateTypes => 1,
},
},
);
# Get the link data.
if ( $LinkListWithData && ref $LinkListWithData eq 'HASH' && %{$LinkListWithData} ) {
%LinkData = $LayoutObject->LinkObjectTableCreate(
LinkListWithData => $LinkListWithData,
ViewMode => 'SimpleRaw',
);
}
}
# Get customer info.
my $CustomerUserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
my %CustomerData;
if ( $Ticket{CustomerUserID} ) {
%CustomerData = $CustomerUserObject->CustomerUserDataGet(
User => $Ticket{CustomerUserID},
);
}
elsif ( $Ticket{CustomerID} ) {
%CustomerData = $CustomerUserObject->CustomerUserDataGet(
CustomerID => $Ticket{CustomerID},
);
}
# Transform time values into human readable form.
$Ticket{Age} = $LayoutObject->CustomerAge(
Age => $Ticket{Age},
Space => ' ',
);
if ( $Ticket{UntilTime} ) {
$Ticket{PendingUntil} = $LayoutObject->CustomerAge(
Age => $Ticket{UntilTime},
Space => ' ',
);
}
# Get maximum number of pages.
my %Page;
$Page{MaxPages} = $ConfigObject->Get('PDF::MaxPages');
if ( !$Page{MaxPages} || $Page{MaxPages} < 1 || $Page{MaxPages} > 1000 ) {
$Page{MaxPages} = 100;
}
my $HeaderRight = $ConfigObject->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} = $LayoutObject->{LanguageObject}->Translate('Page');
$Page{PageCount} = 1;
# Create new PDF document.
my $PDFObject = $Kernel::OM->Get('Kernel::System::PDF');
$PDFObject->DocumentNew(
Title => $ConfigObject->Get('Product') . ': ' . $Title,
Encode => $LayoutObject->{UserCharset},
);
# Create first PDF page.
$PDFObject->PageNew(
%Page,
FooterRight => $Page{PageText} . ' ' . $Page{PageCount},
);
$Page{PageCount}++;
$PDFObject->PositionSet(
Move => 'relativ',
Y => -6,
);
# Output title.
$PDFObject->Text(
Text => $Ticket{Title},
FontSize => 13,
);
$PDFObject->PositionSet(
Move => 'relativ',
Y => -6,
);
# Output "printed by".
my $PrintedBy = $LayoutObject->{LanguageObject}->Translate('printed by');
my $DateTimeString = $Kernel::OM->Create('Kernel::System::DateTime')->ToString();
my $Time = $LayoutObject->{LanguageObject}->FormatTimeString(
$DateTimeString,
'DateFormat',
);
if ( $Interface{Agent} ) {
$PrintedBy .= ' ' . $TicketInfo{User}{UserFullname} . ' ('
. $TicketInfo{User}{UserEmail} . ')'
. ', ' . $Time;
}
elsif ( $Interface{Customer} ) {
$PrintedBy .= ' ' . $CustomerData{UserFullname} . ' ('
. $CustomerData{UserEmail} . ')'
. ', ' . $Time;
}
$PDFObject->Text(
Text => $PrintedBy,
FontSize => 9,
);
$PDFObject->PositionSet(
Move => 'relativ',
Y => -14,
);
# Output ticket infos.
$Self->_PDFOutputTicketInfos(
PageData => \%Page,
TicketData => \%Ticket,
OwnerData => $TicketInfo{Owner},
ResponsibleData => $TicketInfo{Responsible},
Interface => \%Interface,
);
$PDFObject->PositionSet(
Move => 'relativ',
Y => -6,
);
# Output ticket dynamic fields.
$Self->_PDFOutputTicketDynamicFields(
PageData => \%Page,
TicketData => \%Ticket,
Interface => \%Interface,
);
$PDFObject->PositionSet(
Move => 'relativ',
Y => -6,
);
# Output linked objects.
if (%LinkData) {
# Get link type list.
my %LinkTypeList = $LinkObject->TypeList(
UserID => $Param{UserID},
);
$Self->_PDFOutputLinkedObjects(
PageData => \%Page,
LinkData => \%LinkData,
LinkTypeList => \%LinkTypeList,
);
}
# Output customer infos.
if (%CustomerData) {
$Self->_PDFOutputCustomerInfos(
PageData => \%Page,
CustomerData => \%CustomerData,
);
}
# Output articles.
$Self->_PDFOutputArticles(
PageData => \%Page,
ArticleData => \@ArticleBox,
ArticleNumber => $Param{ArticleNumber},
Interface => \%Interface,
);
# Return the PDF document.
return $PDFObject->DocumentOutput();
}
sub _PDFOutputTicketInfos {
my ( $Self, %Param ) = @_;
# Check needed stuff for both interfaces.
for my $Needed (qw(PageData TicketData Interface)) {
if ( !defined( $Param{$Needed} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!"
);
return;
}
}
# Check needed param for agent interface.
if ( $Param{Interface}{Agent} && !defined( $Param{OwnerData} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need OwnerData!"
);
return;
}
my %Ticket = %{ $Param{TicketData} };
my %Page = %{ $Param{PageData} };
# Get needed objects.
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
# Create left table.
my $TableLeft = [];
my $CustomerConfig;
if ( $Param{Interface}{Customer} ) {
$CustomerConfig = $ConfigObject->Get("Ticket::Frontend::CustomerTicketZoom");
}
# Add ticket data, respecting AttributesView configuration for customer interface.
for my $Attribute (qw(State Priority Queue Lock CustomerID)) {
if ( $Param{Interface}{Agent} || $CustomerConfig->{AttributesView}->{$Attribute} ) {
my $Row = {
Key => $LayoutObject->{LanguageObject}->Translate($Attribute),
Value => $LayoutObject->{LanguageObject}->Translate( $Ticket{$Attribute} )
|| $Ticket{$Attribute} || '-',
};
push( @{$TableLeft}, $Row );
}
}
# Add Owner data, different output between interfaces.
if ( $Param{Interface}{Agent} ) {
my $OwnerRow = {
Key => $LayoutObject->{LanguageObject}->Translate('Owner'),
Value => $Ticket{Owner} . ' (' . $Param{OwnerData}->{UserFullname} . ')',
};
push( @{$TableLeft}, $OwnerRow );
}
elsif ( $Param{Interface}{Customer} && $CustomerConfig->{AttributesView}->{Owner} ) {
my $OwnerRow = {
Key => $LayoutObject->{LanguageObject}->Translate('Owner'),
Value => $Ticket{Owner},
};
push( @{$TableLeft}, $OwnerRow );
}
# Add Responsible row, if feature is enabled.
if ( $ConfigObject->Get('Ticket::Responsible') ) {
my $Responsible = '-';
if ( $Param{Interface}{Agent} && $Ticket{Responsible} ) {
$Responsible = $Ticket{Responsible} . ' (' . $Param{ResponsibleData}->{UserFullname} . ')';
}
elsif (
$Param{Interface}{Customer}
&& $CustomerConfig->{AttributesView}->{Responsible}
&& $Ticket{Responsible}
)
{
$Responsible = $Ticket{Responsible};
}
my $Row = {
Key => $LayoutObject->{LanguageObject}->Translate('Responsible'),
Value => $Responsible,
};
push( @{$TableLeft}, $Row );
}
# Add Type row, if feature is enabled.
if (
$ConfigObject->Get('Ticket::Type')
&& ( $Param{Interface}{Agent} || $CustomerConfig->{AttributesView}->{Type} )
)
{
my $Row = {
Key => $LayoutObject->{LanguageObject}->Translate('Type'),
Value => $Ticket{Type},
};
push( @{$TableLeft}, $Row );
}
# Add Service and SLA row, if feature is enabled.
if ( $ConfigObject->Get('Ticket::Service') ) {
if ( $Param{Interface}{Agent} || $CustomerConfig->{AttributesView}->{Service} ) {
my $RowService = {
Key => $LayoutObject->{LanguageObject}->Translate('Service'),
Value => $Ticket{Service} || '-',
};
push( @{$TableLeft}, $RowService );
}
if ( $Param{Interface}{Agent} || $CustomerConfig->{AttributesView}->{SLA} ) {
my $RowSLA = {
Key => $LayoutObject->{LanguageObject}->Translate('SLA'),
Value => $Ticket{SLA} || '-',
};
push( @{$TableLeft}, $RowSLA );
}
}
# Create right table.
my $TableRight = [
{
Key => $LayoutObject->{LanguageObject}->Translate('Age'),
Value => $LayoutObject->{LanguageObject}->Translate( $Ticket{Age} ),
},
{
Key => $LayoutObject->{LanguageObject}->Translate('Created'),
Value => $LayoutObject->{LanguageObject}->FormatTimeString(
$Ticket{Created},
'DateFormat',
),
},
];
if ( $Param{Interface}{Customer} ) {
unshift(
@{$TableRight},
{
Key => $LayoutObject->{LanguageObject}->Translate('CustomerID'),
Value => $Ticket{CustomerID},
}
);
}
elsif ( $Param{Interface}{Agent} ) {
# Show created by if different then User ID 1.
if ( $Ticket{CreateBy} > 1 ) {
my $Row = {
Key => $LayoutObject->{LanguageObject}->Translate('Created by'),
Value => $Kernel::OM->Get('Kernel::System::User')->UserName( UserID => $Ticket{CreateBy} ),
};
push( @{$TableRight}, $Row );
}
# Show accounted time.
if ( $ConfigObject->Get('Ticket::Frontend::AccountTime') ) {
my $Row = {
Key => $LayoutObject->{LanguageObject}->Translate('Accounted time'),
Value => $Ticket{TicketTimeUnits},
};
push( @{$TableRight}, $Row );
}
# Only show pending until unless it is really pending.
if ( $Ticket{PendingUntil} ) {
my $Row = {
Key => $LayoutObject->{LanguageObject}->Translate('Pending till'),
Value => $Ticket{PendingUntil},
};
push( @{$TableRight}, $Row );
}
# Add first response time row.
if ( defined( $Ticket{FirstResponseTime} ) ) {
my $Row = {
Key => $LayoutObject->{LanguageObject}->Translate('First Response Time'),
Value => $LayoutObject->{LanguageObject}->FormatTimeString(
$Ticket{FirstResponseTimeDestinationDate},
'DateFormat',
'NoSeconds',
),
};
push( @{$TableRight}, $Row );
}
# Add update time row.
if ( defined( $Ticket{UpdateTime} ) ) {
my $Row = {
Key => $LayoutObject->{LanguageObject}->Translate('Update Time'),
Value => $LayoutObject->{LanguageObject}->FormatTimeString(
$Ticket{UpdateTimeDestinationDate},
'DateFormat',
'NoSeconds',
),
};
push( @{$TableRight}, $Row );
}
# Add solution time row.
if ( defined( $Ticket{SolutionTime} ) ) {
my $Row = {
Key => $LayoutObject->{LanguageObject}->Translate('Solution Time'),
Value => $LayoutObject->{LanguageObject}->FormatTimeString(
$Ticket{SolutionTimeDestinationDate},
'DateFormat',
'NoSeconds',
),
};
push( @{$TableRight}, $Row );
}
}
my $Rows = @{$TableLeft};
if ( @{$TableRight} > $Rows ) {
$Rows = @{$TableRight};
}
my %TableParam;
for my $Row ( 1 .. $Rows ) {
$Row--;
$TableParam{CellData}[$Row][0]{Content} = $TableLeft->[$Row]->{Key};
$TableParam{CellData}[$Row][0]{Font} = 'ProportionalBold';
$TableParam{CellData}[$Row][1]{Content} = $TableLeft->[$Row]->{Value};
$TableParam{CellData}[$Row][2]{Content} = ' ';
$TableParam{CellData}[$Row][2]{BackgroundColor} = '#FFFFFF';
$TableParam{CellData}[$Row][3]{Content} = $TableRight->[$Row]->{Key};
$TableParam{CellData}[$Row][3]{Font} = 'ProportionalBold';
$TableParam{CellData}[$Row][4]{Content} = $TableRight->[$Row]->{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} = '#F2F2F2';
$TableParam{Padding} = 6;
$TableParam{PaddingTop} = 3;
$TableParam{PaddingBottom} = 3;
# Output table.
my $PDFObject = $Kernel::OM->Get('Kernel::System::PDF');
PAGE:
for ( $Page{PageCount} .. $Page{MaxPages} ) {
# Output table (or a fragment of it).
%TableParam = $PDFObject->Table( %TableParam, );
# Stop output or output next page.
if ( $TableParam{State} ) {
last PAGE;
}
else {
$PDFObject->PageNew(
%Page,
FooterRight => $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} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!"
);
return;
}
}
my %Page = %{ $Param{PageData} };
my %TypeList = %{ $Param{LinkTypeList} };
my %TableParam;
my $Row = 0;
# Get needed objects.
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $PDFObject = $Kernel::OM->Get('Kernel::System::PDF');
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] }->{ $LinkData[1] . 'Name' };
$LinkTypeName = $LayoutObject->{LanguageObject}->Translate($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}->{$LinkTypeLinkDirection};
for my $Object ( sort { lc $a cmp lc $b } keys %{$ObjectList} ) {
for my $Item ( @{ $ObjectList->{$Object} } ) {
$TableParam{CellData}[$Row][0]{Content} ||= '';
$TableParam{CellData}[$Row][1]{Content} = $Item->{Title} || '';
}
continue {
$Row++;
}
}
}
$TableParam{ColumnData}[0]{Width} = 80;
$TableParam{ColumnData}[1]{Width} = 431;
$PDFObject->HLine(
Color => '#aaa',
LineWidth => 0.5,
);
# Set new position.
$PDFObject->PositionSet(
Move => 'relativ',
Y => -10,
);
# Output headline.
$PDFObject->Text(
Text => $LayoutObject->{LanguageObject}->Translate('Linked Objects'),
Height => 10,
Type => 'Cut',
Font => 'Proportional',
FontSize => 9,
Color => '#666666',
);
# Set new position.
$PDFObject->PositionSet(
Move => 'relativ',
Y => -4,
);
# Table params.
$TableParam{Type} = 'Cut';
$TableParam{Border} = 0;
$TableParam{FontSize} = 6;
$TableParam{Padding} = 1;
$TableParam{PaddingTop} = 3;
$TableParam{PaddingBottom} = 3;
# Output table.
PAGE:
for ( $Page{PageCount} .. $Page{MaxPages} ) {
# Output table (or a fragment of it).
%TableParam = $PDFObject->Table( %TableParam, );
# Stop output or output next page.
if ( $TableParam{State} ) {
last PAGE;
}
else {
$PDFObject->PageNew(
%Page,
FooterRight => $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} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!"
);
return;
}
}
my $Output = 0;
my %Ticket = %{ $Param{TicketData} };
my %Page = %{ $Param{PageData} };
my %TableParam;
my $Row = 0;
# Get dynamic field config for appropriate frontend module.
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
my $DynamicFieldFilter;
if ( $Param{Interface}{Agent} ) {
$DynamicFieldFilter = $ConfigObject->Get("Ticket::Frontend::AgentTicketPrint")->{DynamicField};
}
elsif ( $Param{Interface}{Customer} ) {
$DynamicFieldFilter = $ConfigObject->Get("Ticket::Frontend::CustomerTicketPrint")->{DynamicField};
}
# Get the dynamic fields for ticket object.
my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
Valid => 1,
ObjectType => ['Ticket'],
FieldFilter => $DynamicFieldFilter || {},
);
# Get needed objects.
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# Generate table, cycle trough the activated Dynamic Fields for ticket object.
DYNAMICFIELD:
for my $DynamicFieldConfig ( @{$DynamicField} ) {
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
if ( $Param{Interface}{Customer} ) {
# Skip dynamic field if is not designed for customer interface.
my $IsCustomerInterfaceCapable = $DynamicFieldBackendObject->HasBehavior(
DynamicFieldConfig => $DynamicFieldConfig,
Behavior => 'IsCustomerInterfaceCapable',
);
next DYNAMICFIELD if !$IsCustomerInterfaceCapable;
}
my $Value = $DynamicFieldBackendObject->ValueGet(
DynamicFieldConfig => $DynamicFieldConfig,
ObjectID => $Ticket{TicketID},
);
next DYNAMICFIELD if !$Value;
next DYNAMICFIELD if $Value eq "";
# Get print string for this dynamic field.
my $ValueStrg = $DynamicFieldBackendObject->DisplayValueRender(
DynamicFieldConfig => $DynamicFieldConfig,
Value => $Value,
HTMLOutput => 0,
LayoutObject => $LayoutObject,
);
$TableParam{CellData}[$Row][0]{Content}
= $LayoutObject->{LanguageObject}->Translate( $DynamicFieldConfig->{Label} )
. ':';
$TableParam{CellData}[$Row][0]{Font} = 'ProportionalBold';
$TableParam{CellData}[$Row][1]{Content} = $ValueStrg->{Value};
$Row++;
$Output = 1;
}
$TableParam{ColumnData}[0]{Width} = 80;
$TableParam{ColumnData}[1]{Width} = 431;
# Output ticket dynamic fields.
if ($Output) {
my $PDFObject = $Kernel::OM->Get('Kernel::System::PDF');
$PDFObject->HLine(
Color => '#aaa',
LineWidth => 0.5,
);
# Set new position.
$PDFObject->PositionSet(
Move => 'relativ',
Y => -10,
);
# Output headline.
$PDFObject->Text(
Text => $LayoutObject->{LanguageObject}->Translate('Ticket Dynamic Fields'),
Height => 10,
Type => 'Cut',
Font => 'Proportional',
FontSize => 8,
Color => '#666666',
);
# Set new position.
$PDFObject->PositionSet(
Move => 'relativ',
Y => -4,
);
# Table params.
$TableParam{Type} = 'Cut';
$TableParam{Border} = 0;
$TableParam{FontSize} = 6;
$TableParam{Padding} = 1;
$TableParam{PaddingTop} = 3;
$TableParam{PaddingBottom} = 3;
# Output table.
PAGE:
for ( $Page{PageCount} .. $Page{MaxPages} ) {
# Output table (or a fragment of it).
%TableParam = $PDFObject->Table( %TableParam, );
# Stop output or output next page.
if ( $TableParam{State} ) {
last PAGE;
}
else {
$PDFObject->PageNew(
%Page,
FooterRight => $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} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!"
);
return;
}
}
my $Output = 0;
my %CustomerData = %{ $Param{CustomerData} };
my %Page = %{ $Param{PageData} };
my %TableParam;
my $Row = 0;
my $Map = $CustomerData{Config}->{Map};
# Check if customer company support is enabled.
if ( $CustomerData{Config}->{CustomerCompanySupport} ) {
my $Map2 = $CustomerData{CompanyConfig}->{Map};
if ($Map2) {
push( @{$Map}, @{$Map2} );
}
}
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
for my $Field ( @{$Map} ) {
if ( ${$Field}[3] && $CustomerData{ ${$Field}[0] } ) {
$TableParam{CellData}[$Row][0]{Content} = $LayoutObject->{LanguageObject}->Translate( ${$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) {
my $PDFObject = $Kernel::OM->Get('Kernel::System::PDF');
# Set new position.
$PDFObject->PositionSet(
Move => 'relativ',
Y => -10,
);
$PDFObject->HLine(
Color => '#aaa',
LineWidth => 0.5,
);
# Set new position.
$PDFObject->PositionSet(
Move => 'relativ',
Y => -4,
);
# Output headline.
$PDFObject->Text(
Text => $LayoutObject->{LanguageObject}->Translate('Customer Information'),
Height => 10,
Type => 'Cut',
Font => 'Proportional',
FontSize => 8,
Color => '#666666',
);
# Set new position.
$PDFObject->PositionSet(
Move => 'relativ',
Y => -4,
);
# Table params.
$TableParam{Type} = 'Cut';
$TableParam{Border} = 0;
$TableParam{FontSize} = 6;
$TableParam{Padding} = 1;
$TableParam{PaddingTop} = 3;
$TableParam{PaddingBottom} = 3;
# Output table.
PAGE:
for ( $Page{PageCount} .. $Page{MaxPages} ) {
# Output table (or a fragment of it).
%TableParam = $PDFObject->Table( %TableParam, );
# Stop output or output next page.
if ( $TableParam{State} ) {
last PAGE;
}
else {
$PDFObject->PageNew(
%Page,
FooterRight => $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} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!"
);
return;
}
}
my %Page = %{ $Param{PageData} };
# Get needed objects.
my $PDFObject = $Kernel::OM->Get('Kernel::System::PDF');
my $ArticleObject = $Kernel::OM->Get('Kernel::System::Ticket::Article');
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
my @ArticleData = @{ $Param{ArticleData} };
my $ArticleCount = scalar @ArticleData;
# Get config settings.
my $ZoomExpandSort = $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Frontend::ZoomExpandSort');
# Resort article order.
if ( $Param{Interface}{Agent} && $ZoomExpandSort eq 'reverse' ) {
@ArticleData = reverse(@ArticleData);
}
my $ArticleCounter = 1;
for my $ArticleTmp (@ArticleData) {
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} };
my $Filesize = $LayoutObject->HumanReadableDataSize( Size => $File{FilesizeRaw} );
$Attachments .= $File{Filename} . ' (' . $Filesize . ")\n";
}
# Show total accounted time if feature is active.
if ( $Param{Interface}{Agent} && $ConfigObject->Get('Ticket::Frontend::AccountTime') ) {
$Article{'Accounted time'} = $ArticleObject->ArticleAccountedTimeGet(
ArticleID => $Article{ArticleID},
);
}
# Generate article info table.
my %TableParam1;
my $Row = 0;
$PDFObject->PositionSet(
Move => 'relativ',
Y => -6,
);
# Get article number.
my $ArticleNumber;
if ( $Param{ArticleNumber} ) {
$ArticleNumber = $Param{ArticleNumber};
}
else {
$ArticleNumber = $ZoomExpandSort eq 'reverse' ? $ArticleCount - $ArticleCounter + 1 : $ArticleCounter;
}
if ( $Param{Interface}{Customer} ) {
$ArticleNumber = $ArticleCounter;
}
# Article number tag.
$PDFObject->Text(
Text => $LayoutObject->{LanguageObject}->Translate('Article') . ' #' . $ArticleNumber,
Height => 10,
Type => 'Cut',
Font => 'Proportional',
FontSize => 8,
Color => '#666666',
);
$PDFObject->PositionSet(
Move => 'relativ',
Y => 2,
);
my %ArticleFields = $LayoutObject->ArticleFields(%Article);
# Display article fields.
ARTICLE_FIELD:
for my $ArticleFieldKey (
sort { $ArticleFields{$a}->{Prio} <=> $ArticleFields{$b}->{Prio} }
keys %ArticleFields
)
{
my %ArticleField = %{ $ArticleFields{$ArticleFieldKey} // {} };
next ARTICLE_FIELD if $Param{Interface}->{Customer} && $ArticleField{HideInCustomerInterface};
next ARTICLE_FIELD if $ArticleField{HideInTicketPrint};
next ARTICLE_FIELD if !$ArticleField{Value};
$TableParam1{CellData}[$Row][0]{Content}
= $LayoutObject->{LanguageObject}->Translate( $ArticleField{Label} ) . ':';
$TableParam1{CellData}[$Row][0]{Font} = 'ProportionalBold';
$TableParam1{CellData}[$Row][1]{Content} = $ArticleField{Value};
$Row++;
}
# Display article accounted time.
if ( $Param{Interface}{Agent} ) {
my $ArticleTime = $ArticleObject->ArticleAccountedTimeGet(
ArticleID => $Article{ArticleID},
);
if ($ArticleTime) {
$TableParam1{CellData}[$Row][0]{Content}
= $LayoutObject->{LanguageObject}->Translate('Accounted time') . ':';
$TableParam1{CellData}[$Row][0]{Font} = 'ProportionalBold';
$TableParam1{CellData}[$Row][1]{Content} = $ArticleTime;
$Row++;
}
}
$TableParam1{CellData}[$Row][0]{Content} = $LayoutObject->{LanguageObject}->Translate('Created') . ':';
$TableParam1{CellData}[$Row][0]{Font} = 'ProportionalBold';
$TableParam1{CellData}[$Row][1]{Content} = $LayoutObject->{LanguageObject}->FormatTimeString(
$Article{CreateTime},
'DateFormat',
);
$TableParam1{CellData}[$Row][1]{Content}
.= ' ' . $LayoutObject->{LanguageObject}->Translate('by');
my $SenderType = $ArticleObject->ArticleSenderTypeLookup(
SenderTypeID => $Article{SenderTypeID},
);
$TableParam1{CellData}[$Row][1]{Content}
.= ' ' . $LayoutObject->{LanguageObject}->Translate($SenderType);
$Row++;
# Get dynamic field config for appropriate frontend module.
my $DynamicFieldFilter;
if ( $Param{Interface}{Agent} ) {
$DynamicFieldFilter = $ConfigObject->Get("Ticket::Frontend::AgentTicketPrint")->{DynamicField};
}
elsif ( $Param{Interface}{Customer} ) {
$DynamicFieldFilter = $ConfigObject->Get("Ticket::Frontend::CustomerTicketPrint")->{DynamicField};
}
# Get the dynamic fields for ticket object.
my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
Valid => 1,
ObjectType => ['Article'],
FieldFilter => $DynamicFieldFilter || {},
);
# Generate table, cycle trough the activated Dynamic Fields for ticket object.
DYNAMICFIELD:
for my $DynamicFieldConfig ( @{$DynamicField} ) {
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
if ( $Param{Interface}{Customer} ) {
# Skip the dynamic field if it is not designed for customer interface.
my $IsCustomerInterfaceCapable = $DynamicFieldBackendObject->HasBehavior(
DynamicFieldConfig => $DynamicFieldConfig,
Behavior => 'IsCustomerInterfaceCapable',
);
next DYNAMICFIELD if !$IsCustomerInterfaceCapable;
}
my $Value = $DynamicFieldBackendObject->ValueGet(
DynamicFieldConfig => $DynamicFieldConfig,
ObjectID => $Article{ArticleID},
);
next DYNAMICFIELD if !$Value;
next DYNAMICFIELD if $Value eq "";
# Get print string for this dynamic field.
my $ValueStrg = $DynamicFieldBackendObject->DisplayValueRender(
DynamicFieldConfig => $DynamicFieldConfig,
Value => $Value,
HTMLOutput => 0,
LayoutObject => $LayoutObject,
);
$TableParam1{CellData}[$Row][0]{Content}
= $LayoutObject->{LanguageObject}->Translate( $DynamicFieldConfig->{Label} )
. ':';
$TableParam1{CellData}[$Row][0]{Font} = 'ProportionalBold';
$TableParam1{CellData}[$Row][1]{Content} = $ValueStrg->{Value};
$Row++;
}
if ($Attachments) {
$TableParam1{CellData}[$Row][0]{Content} = $LayoutObject->{LanguageObject}->Translate('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;
$PDFObject->PositionSet(
Move => 'relativ',
Y => -6,
);
$PDFObject->HLine(
Color => '#aaa',
LineWidth => 0.5,
);
$PDFObject->PositionSet(
Move => 'relativ',
Y => -6,
);
# Table params (article infos).
$TableParam1{Type} = 'Cut';
$TableParam1{Border} = 0;
$TableParam1{FontSize} = 6;
$TableParam1{Padding} = 1;
$TableParam1{PaddingTop} = 3;
$TableParam1{PaddingBottom} = 3;
# Output table (article infos).
PAGE:
for ( $Page{PageCount} .. $Page{MaxPages} ) {
# Output table (or a fragment of it).
%TableParam1 = $PDFObject->Table( %TableParam1, );
# Stop output or output next page.
if ( $TableParam1{State} ) {
last PAGE;
}
else {
$PDFObject->PageNew(
%Page,
FooterRight => $Page{PageText} . ' ' . $Page{PageCount},
);
$Page{PageCount}++;
}
}
my $ArticlePreview = $LayoutObject->ArticlePreview(
%Article,
ResultType => 'plain',
);
# Table params (article body).
my %TableParam2;
$TableParam2{CellData}[0][0]{Content} = $ArticlePreview || ' ';
$TableParam2{Type} = 'Cut';
$TableParam2{Border} = 0;
$TableParam2{Font} = 'Monospaced';
$TableParam2{FontSize} = 7;
$TableParam2{BackgroundColor} = '#f2f2f2';
$TableParam2{Padding} = 4;
$TableParam2{PaddingTop} = 4;
$TableParam2{PaddingBottom} = 4;
# Output table (article body).
PAGE:
for ( $Page{PageCount} .. $Page{MaxPages} ) {
# Output table (or a fragment of it).
%TableParam2 = $PDFObject->Table( %TableParam2, );
# Stop output or output next page.
if ( $TableParam2{State} ) {
last PAGE;
}
else {
$PDFObject->PageNew(
%Page,
FooterRight => $Page{PageText} . ' ' . $Page{PageCount},
);
$Page{PageCount}++;
}
}
$ArticleCounter++;
}
return 1;
}
1;