Files
scripts/Perl OTRS/Kernel/Modules/AgentITSMChangeSearch.pm
2024-10-14 00:08:40 +02:00

1753 lines
60 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::Modules::AgentITSMChangeSearch;
use strict;
use warnings;
use Kernel::Language qw(Translatable);
use Kernel::System::VariableCheck qw(:all);
our $ObjectManagerDisabled = 1;
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {%Param};
bless( $Self, $Type );
return $Self;
}
sub Run {
my ( $Self, %Param ) = @_;
# get config object
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
# get config for frontend
$Self->{Config} = $ConfigObject->Get("ITSMChange::Frontend::$Self->{Action}");
# get param object
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
# get confid data
$Self->{StartHit} = int( $ParamObject->GetParam( Param => 'StartHit' ) || 1 );
$Self->{SearchLimit} = $Self->{Config}->{SearchLimit} || 500;
$Self->{SortBy} = $ParamObject->GetParam( Param => 'SortBy' )
|| $Self->{Config}->{'SortBy::Default'}
|| 'ChangeID';
$Self->{OrderBy} = $ParamObject->GetParam( Param => 'OrderBy' )
|| $Self->{Config}->{'Order::Default'}
|| 'Down';
$Self->{Profile} = $ParamObject->GetParam( Param => 'Profile' ) || '';
$Self->{SaveProfile} = $ParamObject->GetParam( Param => 'SaveProfile' ) || '';
$Self->{TakeLastSearch} = $ParamObject->GetParam( Param => 'TakeLastSearch' ) || '';
$Self->{SelectTemplate} = $ParamObject->GetParam( Param => 'SelectTemplate' ) || '';
$Self->{EraseTemplate} = $ParamObject->GetParam( Param => 'EraseTemplate' ) || '';
# get layout object
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# check request
if ( $ParamObject->GetParam( Param => 'SearchTemplate' ) && $Self->{Profile} ) {
return $LayoutObject->Redirect(
OP =>
"Action=AgentITSMChangeSearch;Subaction=Search;TakeLastSearch=1;SaveProfile=1;Profile=$Self->{Profile}"
);
}
# get dynamic field object
my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField');
# get the dynamic fields for this screen (change dynamic fields)
$Self->{DynamicFieldChange} = $DynamicFieldObject->DynamicFieldListGet(
Valid => 1,
ObjectType => 'ITSMChange',
FieldFilter => $Self->{Config}->{DynamicField} || {},
);
# get the dynamic fields for this screen (workorder dynamic fields)
$Self->{DynamicFieldWorkOrder} = $DynamicFieldObject->DynamicFieldListGet(
Valid => 1,
ObjectType => 'ITSMWorkOrder',
FieldFilter => $Self->{Config}->{DynamicField} || {},
);
# get needed objects
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
my $SearchProfileObject = $Kernel::OM->Get('Kernel::System::SearchProfile');
# get single params
my %GetParam;
# load parameters from search profile,
# this happens when the next result page should be shown, or when the results are reordered
if ( ( $Self->{Subaction} eq 'LoadProfile' && $Self->{Profile} ) || $Self->{TakeLastSearch} ) {
%GetParam = $SearchProfileObject->SearchProfileGet(
Base => 'ITSMChangeSearch',
Name => $Self->{Profile},
UserLogin => $Self->{UserLogin},
);
}
else {
# get scalar search params
for my $ParamName (
qw(
ChangeNumber ChangeTitle Description Justification
CABCustomer
CABAgent
WorkOrderTitle WorkOrderInstruction WorkOrderReport ResultForm
RequestedTimeSearchType PlannedStartTimeSearchType PlannedEndTimeSearchType
ActualStartTimeSearchType ActualEndTimeSearchType CreateTimeSearchType
ChangeTimeSearchType
)
)
{
$GetParam{$ParamName} = $ParamObject->GetParam( Param => $ParamName );
# remove whitespace on the start and end
if ( $GetParam{$ParamName} ) {
$GetParam{$ParamName} =~ s{ \A \s+ }{}xms;
$GetParam{$ParamName} =~ s{ \s+ \z }{}xms;
}
}
# get array search params
for my $SearchParam (
qw( ChangeStateIDs
ChangeManagerIDs ChangeBuilderIDs
PriorityIDs CategoryIDs ImpactIDs
CreateBy
WorkOrderStateIDs WorkOrderTypeIDs WorkOrderAgentIDs
)
)
{
my @Array = $ParamObject->GetArray( Param => $SearchParam );
if (@Array) {
$GetParam{$SearchParam} = \@Array;
}
}
# get time related params
for my $TimeType (
qw( Requested PlannedStart PlannedEnd ActualStart ActualEnd Create Change )
)
{
# get time params fields
my @Array = $ParamObject->GetArray( Param => $TimeType . 'TimeSearchType' );
if (@Array) {
for my $Item (@Array) {
$GetParam{ $TimeType . $Item . 'Field' } = 1;
}
}
# get time params details
for my $Part (
qw(
PointFormat Point PointStart
Start StartDay StartMonth StartYear
Stop StopDay StopMonth StopYear
)
)
{
my $ParamKey = "${TimeType}Time${Part}";
my $ParamVal = $ParamObject->GetParam( Param => $ParamKey );
# remove white space on the start and end
if ($ParamVal) {
$ParamVal =~ s{ \A \s+ }{}xms;
$ParamVal =~ s{ \s+ \z }{}xms;
}
# store in %GetParam
$GetParam{$ParamKey} = $ParamVal;
}
}
# get Dynamic fields from param object
# cycle trough the activated Dynamic Fields for this screen
DYNAMICFIELD:
for my $DynamicFieldConfig (
@{ $Self->{DynamicFieldChange} },
@{ $Self->{DynamicFieldWorkOrder} }
)
{
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
# get search field preferences
my $SearchFieldPreferences = $DynamicFieldBackendObject->SearchFieldPreferences(
DynamicFieldConfig => $DynamicFieldConfig,
);
next DYNAMICFIELD if !IsArrayRefWithData($SearchFieldPreferences);
PREFERENCE:
for my $Preference ( @{$SearchFieldPreferences} ) {
# extract the dynamic field value from the web request
my $DynamicFieldValue = $DynamicFieldBackendObject->SearchFieldValueGet(
DynamicFieldConfig => $DynamicFieldConfig,
ParamObject => $ParamObject,
ReturnProfileStructure => 1,
LayoutObject => $LayoutObject,
Type => $Preference->{Type},
);
# set the complete value structure in GetParam to store it later in the search profile
if ( IsHashRefWithData($DynamicFieldValue) ) {
%GetParam = ( %GetParam, %{$DynamicFieldValue} );
}
}
}
}
# set result form env
if ( !$GetParam{ResultForm} ) {
$GetParam{ResultForm} = '';
}
# show result site or perform other actions
if ( $Self->{Subaction} eq 'Search' && !$Self->{EraseTemplate} ) {
# fill up profile name (e.g. with last-search)
if ( !$Self->{Profile} || !$Self->{SaveProfile} ) {
$Self->{Profile} = 'last-search';
}
# save search profile (under last-search or real profile name)
$Self->{SaveProfile} = 1;
# remember last search values
if ( $Self->{SaveProfile} && $Self->{Profile} ) {
# remove old profile stuff
$SearchProfileObject->SearchProfileDelete(
Base => 'ITSMChangeSearch',
Name => $Self->{Profile},
UserLogin => $Self->{UserLogin},
);
# insert new profile params
for my $Key ( sort keys %GetParam ) {
if ( $GetParam{$Key} ) {
$SearchProfileObject->SearchProfileAdd(
Base => 'ITSMChangeSearch',
Name => $Self->{Profile},
Key => $Key,
Value => $GetParam{$Key},
UserLogin => $Self->{UserLogin},
);
}
}
}
# prepare CABAgents and CABCustomers
if ( $GetParam{CABAgent} ) {
$GetParam{CABAgents} = [ $GetParam{CABAgent} ];
}
if ( $GetParam{CABCustomer} ) {
$GetParam{CABCustomers} = [ $GetParam{CABCustomer} ];
}
# get session object
my $SessionObject = $Kernel::OM->Get('Kernel::System::AuthSession');
# store last queue screen
my $URL = "Action=AgentITSMChangeSearch;Subaction=Search;Profile=$Self->{Profile};SortBy=$Self->{SortBy}"
. ";OrderBy=$Self->{OrderBy};TakeLastSearch=1;StartHit=$Self->{StartHit}";
$SessionObject->UpdateSessionID(
SessionID => $Self->{SessionID},
Key => 'LastScreenChanges',
Value => $URL,
);
$SessionObject->UpdateSessionID(
SessionID => $Self->{SessionID},
Key => 'LastChangeView',
Value => $URL,
);
# get and check the time search parameters
TIMETYPE:
for my $TimeType (
qw( Requested PlannedStart PlannedEnd ActualStart ActualEnd Create Change )
)
{
# extract the time search parameters for $TimeType into %TimeSelectionParam
my %TimeSelectionParam;
for my $Part (
qw(
SearchType
PointFormat Point PointStart
Start StartDay StartMonth StartYear
Stop StopDay StopMonth StopYear
)
)
{
$TimeSelectionParam{$Part} = $GetParam{ $TimeType . 'Time' . $Part };
}
# nothing to do, when no time search type has been selected
next TIMETYPE if !$TimeSelectionParam{SearchType};
if ( $TimeSelectionParam{SearchType} eq 'TimeSlot' ) {
my %SystemTime; # used for checking the ordering of the two times
# the earlier limit
if (
$TimeSelectionParam{StartDay}
&& $TimeSelectionParam{StartMonth}
&& $TimeSelectionParam{StartYear}
)
{
# format as timestamp
$GetParam{ $TimeType . 'TimeNewerDate' } = sprintf
'%04d-%02d-%02d 00:00:00',
$TimeSelectionParam{StartYear},
$TimeSelectionParam{StartMonth},
$TimeSelectionParam{StartDay};
}
# the later limit
if (
$TimeSelectionParam{StopDay}
&& $TimeSelectionParam{StopMonth}
&& $TimeSelectionParam{StopYear}
)
{
# format as timestamp
$GetParam{ $TimeType . 'TimeOlderDate' } = sprintf
'%04d-%02d-%02d 23:59:59',
$TimeSelectionParam{StopYear},
$TimeSelectionParam{StopMonth},
$TimeSelectionParam{StopDay};
}
}
elsif ( $TimeSelectionParam{SearchType} eq 'TimePoint' ) {
# queries relative to now
if (
$TimeSelectionParam{Point}
&& $TimeSelectionParam{PointStart}
&& $TimeSelectionParam{PointFormat}
)
{
my $CurSysDTObject = $Kernel::OM->Create('Kernel::System::DateTime');
my $SearchDTObject = $CurSysDTObject->Clone();
my $TimeUnit = ucfirst $TimeSelectionParam{PointFormat} . 's';
my $TimeValue = $TimeSelectionParam{Point};
if ( $TimeUnit eq 'Weeks' ) {
$TimeUnit = 'Days';
$TimeValue = $TimeValue * 7;
}
if ( $TimeSelectionParam{PointStart} eq 'Before' ) {
$SearchDTObject->Add(
$TimeUnit => $TimeValue,
);
$GetParam{ $TimeType . 'TimeNewerDate' } = $CurSysDTObject->ToString();
$GetParam{ $TimeType . 'TimeOlderDate' } = $SearchDTObject->ToString();
}
else {
$SearchDTObject->Subtract(
$TimeUnit => $TimeValue,
);
$GetParam{ $TimeType . 'TimeNewerDate' } = $SearchDTObject->ToString();
$GetParam{ $TimeType . 'TimeOlderDate' } = $CurSysDTObject->ToString();
}
}
}
else {
# unknown search types are simply ignored
}
}
# search for substrings by default
for my $Field (
qw(ChangeTitle WorkOrderTitle Description Justification
WorkOrderInstruction WorkOrderReport
)
)
{
if ( defined( $GetParam{$Field} ) && $GetParam{$Field} ne '' ) {
$GetParam{$Field} = "*$GetParam{$Field}*";
}
}
# dynamic fields search parameters for ticket search
my %DynamicFieldSearchParameters;
# cycle trough the activated Dynamic Fields for this screen
DYNAMICFIELD:
for my $DynamicFieldConfig (
@{ $Self->{DynamicFieldChange} },
@{ $Self->{DynamicFieldWorkOrder} }
)
{
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
# get search field preferences
my $SearchFieldPreferences = $DynamicFieldBackendObject->SearchFieldPreferences(
DynamicFieldConfig => $DynamicFieldConfig,
);
next DYNAMICFIELD if !IsArrayRefWithData($SearchFieldPreferences);
PREFERENCE:
for my $Preference ( @{$SearchFieldPreferences} ) {
# extract the dynamic field value from the profile
my $SearchParameter = $DynamicFieldBackendObject->SearchFieldParameterBuild(
DynamicFieldConfig => $DynamicFieldConfig,
Profile => \%GetParam,
LayoutObject => $LayoutObject,
Type => $Preference->{Type},
);
# set search parameter
if ( defined $SearchParameter ) {
$DynamicFieldSearchParameters{ 'DynamicField_' . $DynamicFieldConfig->{Name} }
= $SearchParameter->{Parameter};
}
}
}
# get change object
my $ChangeObject = $Kernel::OM->Get('Kernel::System::ITSMChange');
# perform change search
my $ViewableChangeIDs = $ChangeObject->ChangeSearch(
Result => 'ARRAY',
OrderBy => [ $Self->{SortBy} ],
OrderByDirection => [ $Self->{OrderBy} ],
Limit => $Self->{SearchLimit},
MirrorDB => 1,
UserID => $Self->{UserID},
%GetParam,
%DynamicFieldSearchParameters,
);
# get user object
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
# CSV output
if (
$GetParam{ResultForm} eq 'CSV'
||
$GetParam{ResultForm} eq 'Excel'
)
{
my @CSVHead;
my @CSVData;
# get all change dynamic fields that are configured for the search csv output
my %FieldFilter;
FIELD:
for my $Field ( @{ $Self->{Config}->{SearchCSVData} } ) {
if ( $Field =~ m{ \A DynamicField_ ( [a-zA-Z\d]+ ) \z }xms ) {
$FieldFilter{$1} = 1;
}
}
# get all dynamic fields for ITSMChange with the selected field filter
my $DynamicFieldsITSMChange = $DynamicFieldObject->DynamicFieldListGet(
Valid => 1,
ObjectType => 'ITSMChange',
FieldFilter => \%FieldFilter,
);
ID:
for my $ChangeID ( @{$ViewableChangeIDs} ) {
# to store data of sub-elements
my %SubElementData;
# get change data
my $Change = $ChangeObject->ChangeGet(
UserID => $Self->{UserID},
ChangeID => $ChangeID,
);
next ID if !$Change;
# to store all data
my %Info = %{$Change};
# get user data for needed user types
USERTYPE:
for my $UserType (qw(ChangeBuilder ChangeManager WorkOrderAgent)) {
# check if UserType attribute exists either in change or workorder
if ( !$Change->{ $UserType . 'ID' } && !$Info{ $UserType . 'ID' } ) {
next USERTYPE;
}
# get user data
my %User = $UserObject->GetUserData(
UserID => $Change->{ $UserType . 'ID' } || $Info{ $UserType . 'ID' },
Cached => 1,
);
# set user full name
$Info{$UserType} = $User{UserFullname};
}
# to store the linked service data
my $LinkListWithData = {};
my @WorkOrderIDs;
# store the combined linked services data from all workorders of this change
@WorkOrderIDs = @{ $Change->{WorkOrderIDs} };
# store the combined linked services data
for my $WorkOrderID (@WorkOrderIDs) {
# get linked objects of this workorder
my $LinkListWithDataWorkOrder = $Kernel::OM->Get('Kernel::System::LinkObject')->LinkListWithData(
Object => 'ITSMWorkOrder',
Key => $WorkOrderID,
State => 'Valid',
UserID => $Self->{UserID},
);
OBJECT:
for my $Object ( sort keys %{$LinkListWithDataWorkOrder} ) {
# only show linked services of workorder
next OBJECT if $Object ne 'Service';
LINKTYPE:
for my $LinkType ( sort keys %{ $LinkListWithDataWorkOrder->{$Object} } ) {
DIRECTION:
for my $Direction (
sort keys %{ $LinkListWithDataWorkOrder->{$Object}->{$LinkType} }
)
{
ID:
for my $ID (
sort keys %{
$LinkListWithDataWorkOrder->{$Object}->{$LinkType}
->{$Direction}
}
)
{
# combine the linked object data from all workorders
$LinkListWithData->{$Object}->{$LinkType}->{$Direction}->{$ID}
= $LinkListWithDataWorkOrder->{$Object}->{$LinkType}
->{$Direction}->{$ID};
}
}
}
}
}
# get unique service ids
my %UniqueServiceIDs;
my $ServicesRef = $LinkListWithData->{Service} || {};
for my $LinkType ( sort keys %{$ServicesRef} ) {
# extract link type List
my $LinkTypeList = $ServicesRef->{$LinkType};
for my $Direction ( sort keys %{$LinkTypeList} ) {
# extract direction list
my $DirectionList = $ServicesRef->{$LinkType}->{$Direction};
# collect unique service ids
for my $ServiceID ( sort keys %{$DirectionList} ) {
$UniqueServiceIDs{$ServiceID}++;
}
}
}
# get the data for each service
my @ServicesData;
SERVICEID:
for my $ServiceID ( sort keys %UniqueServiceIDs ) {
# get service data
my %ServiceData = $Kernel::OM->Get('Kernel::System::Service')->ServiceGet(
ServiceID => $ServiceID,
UserID => $Self->{UserID},
);
# store service data
push @ServicesData, \%ServiceData;
}
# sort services data by service name
@ServicesData = sort { $a->{Name} cmp $b->{Name} } @ServicesData;
# store services data
if ( scalar @ServicesData ) {
SERVICE:
for my $Service (@ServicesData) {
my $ServiceName = $Service->{NameShort};
if ( $Info{Services} ) {
$Info{Services} .= ' ' . $ServiceName;
next SERVICE;
}
$Info{Services} = $ServiceName;
}
}
# csv quote
if ( !@CSVHead ) {
@CSVHead = @{ $Self->{Config}->{SearchCSVData} };
}
my @Data;
for my $Header (@CSVHead) {
# if the column is a dynamic field
if ( $Header =~ m{ \A DynamicField_ ( [a-zA-Z\d]+ ) \z }xms ) {
my $DynamicFieldName = $1;
DYNAMICFIELD:
for my $DynamicFieldConfig ( @{$DynamicFieldsITSMChange} ) {
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
next DYNAMICFIELD if $DynamicFieldConfig->{Name} ne $DynamicFieldName;
# get print string for this dynamic field
my $Value = $DynamicFieldBackendObject->DisplayValueRender(
DynamicFieldConfig => $DynamicFieldConfig,
Value => $Info{$Header},
ValueMaxChars => 100,
LayoutObject => $LayoutObject,
);
$Info{$Header} = $Value->{Value};
last DYNAMICFIELD;
}
}
push @Data, $Info{$Header};
}
push @CSVData, \@Data;
}
# csv quote
# translate non existing header may result in a garbage file
if ( !@CSVHead ) {
@CSVHead = @{ $Self->{Config}->{SearchCSVData} };
}
# translate headers
for my $Header (@CSVHead) {
# replace ChangeNumber header with the current ChangeHook from config
if ( $Header eq 'ChangeNumber' ) {
$Header = $ConfigObject->Get('ITSMChange::Hook');
}
else {
$Header = $LayoutObject->{LanguageObject}->Translate($Header);
}
}
my $CSVObject = $Kernel::OM->Get('Kernel::System::CSV');
my $CurSysDTObject = $Kernel::OM->Create('Kernel::System::DateTime');
if ( $GetParam{ResultForm} eq 'CSV' ) {
# Assemble CSV data.
my $CSV = $CSVObject->Array2CSV(
Head => \@CSVHead,
Data => \@CSVData,
Separator => $Self->{UserCSVSeparator},
);
# Return CSV to download.
return $LayoutObject->Attachment(
Filename => sprintf(
'change_search_%s.csv',
$CurSysDTObject->Format(
Format => '%F_%H-%M',
),
),
ContentType => "text/csv; charset=" . $LayoutObject->{UserCharset},
Content => $CSV,
);
}
elsif ( $GetParam{ResultForm} eq 'Excel' ) {
# Assemble Excel data.
my $Excel = $CSVObject->Array2CSV(
Head => \@CSVHead,
Data => \@CSVData,
Format => 'Excel',
);
# Return Excel to download.
return $LayoutObject->Attachment(
Filename => sprintf(
'change_search_%s.xlsx',
$CurSysDTObject->Format(
Format => '%F_%H-%M',
),
),
ContentType => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset="
. $LayoutObject->{UserCharset},
Content => $Excel,
);
}
}
elsif ( $GetParam{ResultForm} eq 'Print' ) {
# to store all data
my %Info;
# get pdf object
my $PDFObject = $Kernel::OM->Get('Kernel::System::PDF');
# to send data to the PDF output
my @PDFData;
ID:
for my $ChangeID ( @{$ViewableChangeIDs} ) {
# get change data
my $Change = $ChangeObject->ChangeGet(
UserID => $Self->{UserID},
ChangeID => $ChangeID,
);
next ID if !$Change;
# add change data,
%Info = %{$Change};
# get user data for needed user types
USERTYPE:
for my $UserType (qw(ChangeBuilder ChangeManager WorkOrderAgent)) {
# check if UserType attribute exists either in change or workorder
if ( !$Change->{ $UserType . 'ID' } && !$Info{ $UserType . 'ID' } ) {
next USERTYPE;
}
# get user data
my %User = $UserObject->GetUserData(
UserID =>
$Change->{ $UserType . 'ID' } || $Info{ $UserType . 'ID' },
Cached => 1,
);
# set user full name
$Info{$UserType} = $User{UserFullname};
}
my $ChangeTitle = $LayoutObject->Output(
Template => '[% Data.ChangeTitle | truncate(30) | html %]',
Data => \%Info,
);
my $PlannedStart = $LayoutObject->Output(
Template => '[% Data.PlannedStartTime | Localize("TimeLong") %]',
Data => \%Info,
);
my $PlannedEnd = $LayoutObject->Output(
Template => '[% Data.PlannedEndTime | Localize("TimeLong") %]',
Data => \%Info,
);
my @PDFRow;
push @PDFRow, $Info{ChangeNumber};
push @PDFRow, $ChangeTitle;
push @PDFRow, $Info{ChangeBuilder};
push @PDFRow, $Info{WorkOrderCount};
push @PDFRow, $Info{ChangeState};
push @PDFRow, $Info{Priority};
push @PDFRow, $PlannedStart;
push @PDFRow, $PlannedEnd;
push @PDFData, \@PDFRow;
}
# PDF Output
my $Title = $LayoutObject->{LanguageObject}->Translate('Change Search');
my $PrintedBy = $LayoutObject->{LanguageObject}->Translate('printed by');
my $Page = $LayoutObject->{LanguageObject}->Translate('Page');
my $Time = $LayoutObject->{Time};
# get maximum number of pages
my $MaxPages = $ConfigObject->Get('PDF::MaxPages');
if ( !$MaxPages || $MaxPages < 1 || $MaxPages > 1000 ) {
$MaxPages = 100;
}
# create the header
my $CellData;
# output 'No ticket data found', if no content was given
if (@PDFData) {
$CellData->[0]->[0]->{Content} = $ConfigObject->Get('ITSMChange::Hook');
$CellData->[0]->[0]->{Font} = 'ProportionalBold';
$CellData->[0]->[1]->{Content} = $LayoutObject->{LanguageObject}->Translate('ChangeTitle');
$CellData->[0]->[1]->{Font} = 'ProportionalBold';
$CellData->[0]->[2]->{Content} = $LayoutObject->{LanguageObject}->Translate('ChangeBuilder');
$CellData->[0]->[2]->{Font} = 'ProportionalBold';
$CellData->[0]->[3]->{Content} = $LayoutObject->{LanguageObject}->Translate('WorkOrders');
$CellData->[0]->[3]->{Font} = 'ProportionalBold';
$CellData->[0]->[4]->{Content} = $LayoutObject->{LanguageObject}->Translate('ChangeState');
$CellData->[0]->[4]->{Font} = 'ProportionalBold';
$CellData->[0]->[5]->{Content} = $LayoutObject->{LanguageObject}->Translate('Priority');
$CellData->[0]->[5]->{Font} = 'ProportionalBold';
$CellData->[0]->[6]->{Content} = $LayoutObject->{LanguageObject}->Translate('PlannedStartTime');
$CellData->[0]->[6]->{Font} = 'ProportionalBold';
$CellData->[0]->[7]->{Content} = $LayoutObject->{LanguageObject}->Translate('PlannedEndTime');
$CellData->[0]->[7]->{Font} = 'ProportionalBold';
# create the content array
my $CounterRow = 1;
for my $Row (@PDFData) {
my $CounterColumn = 0;
for my $Content ( @{$Row} ) {
$CellData->[$CounterRow]->[$CounterColumn]->{Content} = $Content;
$CounterColumn++;
}
$CounterRow++;
}
}
else {
$CellData->[0]->[0]->{Content} = $LayoutObject->{LanguageObject}->Translate('No ticket data found.');
}
# page params
my %PageParam;
$PageParam{PageOrientation} = 'landscape';
$PageParam{MarginTop} = 30;
$PageParam{MarginRight} = 40;
$PageParam{MarginBottom} = 40;
$PageParam{MarginLeft} = 40;
$PageParam{HeaderRight} = $Title;
# table params
my %TableParam;
$TableParam{CellData} = $CellData;
$TableParam{Type} = 'Cut';
$TableParam{FontSize} = 6;
$TableParam{Border} = 0;
$TableParam{BackgroundColorEven} = '#DDDDDD';
$TableParam{Padding} = 1;
$TableParam{PaddingTop} = 3;
$TableParam{PaddingBottom} = 3;
# create new pdf document
$PDFObject->DocumentNew(
Title => $ConfigObject->Get('Product') . ': ' . $Title,
Encode => $LayoutObject->{UserCharset},
);
# start table output
$PDFObject->PageNew(
%PageParam,
FooterRight => $Page . ' 1',
);
$PDFObject->PositionSet(
Move => 'relativ',
Y => -6,
);
# output title
$PDFObject->Text(
Text => $Title,
FontSize => 13,
);
$PDFObject->PositionSet(
Move => 'relativ',
Y => -6,
);
# output "printed by"
$PDFObject->Text(
Text => $PrintedBy . ' '
. $Self->{UserFullname} . ' ('
. $Self->{UserEmail} . ') '
. $Time,
FontSize => 9,
);
$PDFObject->PositionSet(
Move => 'relativ',
Y => -14,
);
PAGE:
for my $Count ( 2 .. $MaxPages ) {
# output table (or a fragment of it)
%TableParam = $PDFObject->Table( %TableParam, );
# stop output or another page
if ( $TableParam{State} ) {
last PAGE;
}
else {
$PDFObject->PageNew(
%PageParam, FooterRight => $Page
. ' '
. $Count,
);
}
}
my $PDFString = $PDFObject->DocumentOutput();
# return the pdf document
my $CurSysDTObject = $Kernel::OM->Create('Kernel::System::DateTime');
return $LayoutObject->Attachment(
Filename => sprintf(
'change_search_%s.pdf',
$CurSysDTObject->Format(
Format => '%F_%H-%M',
),
),
ContentType => "application/pdf",
Content => $PDFString,
Type => 'inline',
);
}
else {
# start html page
my $Output = $LayoutObject->Header();
$Output .= $LayoutObject->NavigationBar();
$LayoutObject->Print( Output => \$Output );
$Output = '';
$Self->{Filter} = $ParamObject->GetParam( Param => 'Filter' ) || '';
$Self->{View} = $ParamObject->GetParam( Param => 'View' ) || '';
# show changes
my $LinkPage = 'Filter='
. $LayoutObject->Ascii2Html( Text => $Self->{Filter} )
. ';View=' . $LayoutObject->Ascii2Html( Text => $Self->{View} )
. ';SortBy=' . $LayoutObject->Ascii2Html( Text => $Self->{SortBy} )
. ';OrderBy='
. $LayoutObject->Ascii2Html( Text => $Self->{OrderBy} )
. ';Profile=' . $Self->{Profile} . ';TakeLastSearch=1;Subaction=Search'
. ';';
my $LinkSort = 'Filter='
. $LayoutObject->Ascii2Html( Text => $Self->{Filter} )
. ';View=' . $LayoutObject->Ascii2Html( Text => $Self->{View} )
. ';Profile=' . $Self->{Profile} . ';TakeLastSearch=1;Subaction=Search'
. ';';
my $LinkFilter = 'TakeLastSearch=1;Subaction=Search;Profile='
. $LayoutObject->Ascii2Html( Text => $Self->{Profile} )
. ';';
my $LinkBack = 'Subaction=LoadProfile;Profile='
. $LayoutObject->Ascii2Html( Text => $Self->{Profile} )
. ';TakeLastSearch=1;';
# find out which columns should be shown
my @ShowColumns;
if ( $Self->{Config}->{ShowColumns} ) {
# get all possible columns from config
my %PossibleColumn = %{ $Self->{Config}->{ShowColumns} };
# get the column names that should be shown
COLUMNNAME:
for my $Name ( sort keys %PossibleColumn ) {
next COLUMNNAME if !$PossibleColumn{$Name};
push @ShowColumns, $Name;
}
}
$Output .= $LayoutObject->ITSMChangeListShow(
ChangeIDs => $ViewableChangeIDs,
Total => scalar @{$ViewableChangeIDs},
View => $Self->{View},
Env => $Self,
LinkPage => $LinkPage,
LinkSort => $LinkSort,
LinkFilter => $LinkFilter,
LinkBack => $LinkBack,
Profile => $Self->{Profile},
TitleName => $LayoutObject->{LanguageObject}->Translate('Change Search Result'),
ShowColumns => \@ShowColumns,
SortBy => $LayoutObject->Ascii2Html( Text => $Self->{SortBy} ),
OrderBy => $LayoutObject->Ascii2Html( Text => $Self->{OrderBy} ),
RequestedURL => 'Action=' . $Self->{Action} . ';' . $LinkPage,
);
# build footer
$Output .= $LayoutObject->Footer();
return $Output;
}
}
elsif ( $Self->{Subaction} eq 'AJAXProfileDelete' ) {
my $Profile = $ParamObject->GetParam( Param => 'Profile' );
# remove old profile stuff
$SearchProfileObject->SearchProfileDelete(
Base => 'ITSMChangeSearch',
Name => $Profile,
UserLogin => $Self->{UserLogin},
);
my $Output = $LayoutObject->JSONEncode(
Data => 1,
);
return $LayoutObject->Attachment(
NoCache => 1,
ContentType => 'text/html',
Content => $Output,
Type => 'inline'
);
}
elsif ( $Self->{Subaction} eq 'AJAX' ) {
my $Output = $Self->_MaskForm(
%GetParam,
);
$Output .= $LayoutObject->Output(
TemplateFile => 'AgentITSMChangeSearch',
Data => \%Param,
);
return $LayoutObject->Attachment(
NoCache => 1,
ContentType => 'text/html',
Content => $Output,
Type => 'inline'
);
}
$LayoutObject->AddJSData(
Key => 'ITSMChangeManagementSearch.Open',
Value => 1,
);
# There was no 'SubAction', or there were validation errors, or an user or customer was searched
# generate search mask
my $Output = $LayoutObject->Header();
$Output .= $LayoutObject->NavigationBar();
$Output .= $LayoutObject->Output(
TemplateFile => 'AgentITSMChangeSearch',
Data => \%Param,
);
$Output .= $LayoutObject->Footer();
return $Output;
}
sub _MaskForm {
my ( $Self, %Param ) = @_;
# get param object
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
# get config object
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
my $Profile = $ParamObject->GetParam( Param => 'Profile' ) || '';
my $EmptySearch = $ParamObject->GetParam( Param => 'EmptySearch' );
if ( !$Profile ) {
$EmptySearch = 1;
}
# get search profile object
my $SearchProfileObject = $Kernel::OM->Get('Kernel::System::SearchProfile');
my %GetParam = $SearchProfileObject->SearchProfileGet(
Base => 'ITSMChangeSearch',
Name => $Profile,
UserLogin => $Self->{UserLogin},
);
# allow profile overwrite the contents of %Param
%Param = (
%Param,
%GetParam,
);
# get user object
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
# set user friendly CABAgent field
if ( $Param{CABAgent} && $Param{CABAgent} ne '' ) {
# get user data
my %UserData = $UserObject->GetUserData(
UserID => $Param{CABAgent},
);
# set user frienly CABAgent string
my $UserValue = sprintf '"%s" <%s>',
$UserData{UserFullname},
$UserData{UserEmail};
$Param{CABAgentSearch} = $UserValue;
}
# set user friendly CABCustomer field
if ( $Param{CABCustomer} && $Param{CABCustomer} ne '' ) {
# get customer data
my %CustomerSearchList = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerSearch(
Search => $Param{CABCustomer},
);
$Param{CABCustomerSearch} = $CustomerSearchList{ $Param{CABCustomer} };
}
# set attributes string
my @Attributes = (
{
Key => 'ChangeNumber',
Value => Translatable('Change Number'),
},
{
Key => 'ChangeTitle',
Value => Translatable('Change Title'),
},
{
Key => 'WorkOrderTitle',
Value => Translatable('Work Order Title'),
},
{
Key => 'CABAgent',
Value => Translatable('CAB Agent'),
},
{
Key => 'CABCustomer',
Value => Translatable('CAB Customer'),
},
{
Key => '',
Value => '-',
Disabled => 1,
},
{
Key => 'Description',
Value => Translatable('Change Description'),
},
{
Key => 'Justification',
Value => Translatable('Change Justification'),
},
{
Key => 'WorkOrderInstruction',
Value => Translatable('WorkOrder Instruction'),
},
{
Key => 'WorkOrderReport',
Value => Translatable('WorkOrder Report'),
},
);
# get dynamic field backend object
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
my $DynamicFieldSeparator = 1;
my $LastObjectType = '';
# get layout object
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# create dynamic fields search options for attribute select
# cycle trough the activated Dynamic Fields for this screen
DYNAMICFIELD:
for my $DynamicFieldConfig (
@{ $Self->{DynamicFieldChange} },
@{ $Self->{DynamicFieldWorkOrder} }
)
{
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
next DYNAMICFIELD if !$DynamicFieldConfig->{Name};
next DYNAMICFIELD if $DynamicFieldConfig->{Name} eq '';
if (
$LastObjectType eq 'ITSMChange'
&& $DynamicFieldConfig->{ObjectType} eq 'ITSMWorkOrder'
)
{
$DynamicFieldSeparator = 1;
}
# save the last object type (needed for separator between change and workorder fields)
$LastObjectType = $DynamicFieldConfig->{ObjectType};
# create a separator for dynamic fields attributes
if ($DynamicFieldSeparator) {
push @Attributes, (
{
Key => '',
Value => '-',
Disabled => 1,
},
);
$DynamicFieldSeparator = 0;
}
# get search field preferences
my $SearchFieldPreferences = $DynamicFieldBackendObject->SearchFieldPreferences(
DynamicFieldConfig => $DynamicFieldConfig,
);
next DYNAMICFIELD if !IsArrayRefWithData($SearchFieldPreferences);
# translate the dynamic field label
my $TranslatedDynamicFieldLabel = $LayoutObject->{LanguageObject}->Translate(
$DynamicFieldConfig->{Label},
);
PREFERENCE:
for my $Preference ( @{$SearchFieldPreferences} ) {
# translate the suffix
my $TranslatedSuffix = $LayoutObject->{LanguageObject}->Translate(
$Preference->{LabelSuffix},
) || '';
if ($TranslatedSuffix) {
$TranslatedSuffix = ' (' . $TranslatedSuffix . ')';
}
push @Attributes, (
{
Key => 'Search_DynamicField_'
. $DynamicFieldConfig->{Name}
. $Preference->{Type},
Value => $TranslatedDynamicFieldLabel . $TranslatedSuffix,
},
);
}
}
# create a separator if a dynamic field attribute was pushed
if ( !$DynamicFieldSeparator ) {
push @Attributes, (
{
Key => '',
Value => '-',
Disabled => 1,
},
);
}
# create HTML strings for all dynamic fields
my %DynamicFieldHTML;
# cycle trough the activated Dynamic Fields for this screen
DYNAMICFIELD:
for my $DynamicFieldConfig (
@{ $Self->{DynamicFieldChange} },
@{ $Self->{DynamicFieldWorkOrder} }
)
{
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
# get search field preferences
my $SearchFieldPreferences = $DynamicFieldBackendObject->SearchFieldPreferences(
DynamicFieldConfig => $DynamicFieldConfig,
);
next DYNAMICFIELD if !IsArrayRefWithData($SearchFieldPreferences);
# get PossibleValues
my $PossibleValues = $DynamicFieldBackendObject->PossibleValuesGet(
DynamicFieldConfig => $DynamicFieldConfig,
OverridePossibleNone => 0,
);
PREFERENCE:
for my $Preference ( @{$SearchFieldPreferences} ) {
# get field html
$DynamicFieldHTML{ $DynamicFieldConfig->{Name} . $Preference->{Type} }
= $DynamicFieldBackendObject->SearchFieldRender(
DynamicFieldConfig => $DynamicFieldConfig,
Profile => \%GetParam,
PossibleValuesFilter => $PossibleValues,
DefaultValue =>
$Self->{Config}->{Defaults}->{DynamicField}
->{ $DynamicFieldConfig->{Name} },
LayoutObject => $LayoutObject,
Type => $Preference->{Type},
);
}
}
push @Attributes, (
{
Key => 'PriorityIDs',
Value => Translatable('Change Priority'),
},
{
Key => 'ImpactIDs',
Value => Translatable('Change Impact'),
},
{
Key => 'CategoryIDs',
Value => Translatable('Change Category'),
},
{
Key => 'ChangeStateIDs',
Value => Translatable('Change State'),
},
{
Key => 'ChangeManagerIDs',
Value => Translatable('Change Manager'),
},
{
Key => 'ChangeBuilderIDs',
Value => Translatable('Change Builder'),
},
{
Key => 'CreateBy',
Value => Translatable('Created By'),
},
{
Key => 'WorkOrderStateIDs',
Value => Translatable('WorkOrder State'),
},
{
Key => 'WorkOrderTypeIDs',
Value => Translatable('WorkOrder Type'),
},
{
Key => 'WorkOrderAgentIDs',
Value => Translatable('WorkOrder Agent'),
},
{
Key => '',
Value => '-',
Disabled => 1,
},
);
# set time attributes
my @TimeTypes = (
{
Prefix => 'Requested',
Title => Translatable('Requested Date'),
},
{
Prefix => 'PlannedStart',
Title => Translatable('Planned Start Time'),
},
{
Prefix => 'PlannedEnd',
Title => Translatable('Planned End Time'),
},
{
Prefix => 'ActualStart',
Title => Translatable('Actual Start Time'),
},
{
Prefix => 'ActualEnd',
Title => Translatable('Actual End Time'),
},
{
Prefix => 'Create',
Title => Translatable('Create Time'),
},
{
Prefix => 'Change',
Title => Translatable('Change Time'),
},
);
TIMETYPE:
for my $TimeType (@TimeTypes) {
my $Prefix = $TimeType->{Prefix};
# show RequestedTime only when enabled in SysConfig
if ( $Prefix eq 'Requested' && !$Self->{Config}->{RequestedTime} ) {
next TIMETYPE;
}
my $Title = $LayoutObject->{LanguageObject}->Translate( $TimeType->{Title} );
my $BeforeAfterTranslatable = $LayoutObject->{LanguageObject}->Translate('(before/after)');
my $BetweenTranslatable = $LayoutObject->{LanguageObject}->Translate('(between)');
push @Attributes, (
{
Key => $Prefix . 'TimePointField',
Value => $Title . " $BeforeAfterTranslatable",
},
{
Key => $Prefix . 'TimeSlotField',
Value => $Title . " $BetweenTranslatable",
},
);
}
$Param{AttributesStrg} = $LayoutObject->BuildSelection(
PossibleNone => 1,
Data => \@Attributes,
Name => 'Attribute',
Multiple => 0,
Class => 'Modernize',
);
$Param{AttributesOrigStrg} = $LayoutObject->BuildSelection(
PossibleNone => 1,
Data => \@Attributes,
Name => 'AttributeOrig',
Multiple => 0,
Class => 'Modernize',
);
# Get a complete list of users
# for the selection 'ChangeBuilder', 'ChangeManager' and 'created by user'.
# It is important to also search for invalid agents, as we want to find
# these changes too.
# Out of office nice might be appended to the values.
my %Users = $UserObject->UserList(
Type => 'Long',
Valid => 0,
);
# dropdown menu for 'created by users'
$Param{'CreateBySelectionString'} = $LayoutObject->BuildSelection(
Data => \%Users,
Name => 'CreateBy',
Multiple => 1,
Size => 5,
SelectedID => $Param{CreateBy},
Class => 'Modernize',
);
# build change manager dropdown
$Param{'ChangeManagerSelectionString'} = $LayoutObject->BuildSelection(
Data => \%Users,
Name => 'ChangeManagerIDs',
Multiple => 1,
Size => 5,
SelectedID => $Param{ChangeManagerIDs},
Class => 'Modernize',
);
# build change builder dropdown
$Param{'ChangeBuilderSelectionString'} = $LayoutObject->BuildSelection(
Data => \%Users,
Name => 'ChangeBuilderIDs',
Multiple => 1,
Size => 5,
SelectedID => $Param{ChangeBuilderIDs},
Class => 'Modernize',
);
# get change object
my $ChangeObject = $Kernel::OM->Get('Kernel::System::ITSMChange');
# get possible Change Categories
my $Categories = $ChangeObject->ChangePossibleCIPGet(
Type => 'Category',
UserID => $Self->{UserID},
);
$Param{'ChangeCategorySelectionString'} = $LayoutObject->BuildSelection(
Data => $Categories,
Name => 'CategoryIDs',
Multiple => 1,
Size => 5,
SelectedID => $Param{CategoryIDs},
Class => 'Modernize',
);
# get possible Change Impacts
my $Impacts = $ChangeObject->ChangePossibleCIPGet(
Type => 'Impact',
UserID => $Self->{UserID},
);
$Param{'ChangeImpactSelectionString'} = $LayoutObject->BuildSelection(
Data => $Impacts,
Name => 'ImpactIDs',
Multiple => 1,
Size => 5,
SelectedID => $Param{ImpactIDs},
Class => 'Modernize',
);
# get possible Change Priorities
my $Priorities = $ChangeObject->ChangePossibleCIPGet(
Type => 'Priority',
UserID => $Self->{UserID},
);
$Param{'ChangePrioritySelectionString'} = $LayoutObject->BuildSelection(
Data => $Priorities,
Name => 'PriorityIDs',
Multiple => 1,
Size => 5,
SelectedID => $Param{PriorityIDs},
Class => 'Modernize',
);
# get change states
my $ChangeStates = $ChangeObject->ChangePossibleStatesGet(
UserID => $Self->{UserID},
);
$Param{'ChangeStateSelectionString'} = $LayoutObject->BuildSelection(
Data => $ChangeStates,
Name => 'ChangeStateIDs',
Multiple => 1,
Size => 5,
SelectedID => $Param{ChangeStateIDs},
Class => 'Modernize',
);
# get workorder agents
$Param{'WorkOrderAgentIDSelectionString'} = $LayoutObject->BuildSelection(
Data => \%Users,
Name => 'WorkOrderAgentIDs',
Multiple => 1,
Size => 5,
SelectedID => $Param{WorkOrderAgentIDs},
Class => 'Modernize',
);
# get work order object
my $WorkOrderObject = $Kernel::OM->Get('Kernel::System::ITSMChange::ITSMWorkOrder');
# get workorder states
my $WorkOrderStates = $WorkOrderObject->WorkOrderPossibleStatesGet(
UserID => 1,
);
$Param{'WorkOrderStateSelectionString'} = $LayoutObject->BuildSelection(
Data => $WorkOrderStates,
Name => 'WorkOrderStateIDs',
Multiple => 1,
Size => 5,
SelectedID => $Param{WorkOrderStateIDs},
Class => 'Modernize',
);
# get workorder types
my $WorkOrderTypes = $WorkOrderObject->WorkOrderTypeList(
UserID => 1,
);
$Param{'WorkOrderTypeSelectionString'} = $LayoutObject->BuildSelection(
Data => $WorkOrderTypes,
Name => 'WorkOrderTypeIDs',
Multiple => 1,
Size => 5,
SelectedID => $Param{WorkOrderTypeIDs},
Class => 'Modernize',
);
# set result output formats
$Param{ResultFormStrg} = $LayoutObject->BuildSelection(
Data => {
Normal => Translatable('Normal'),
Print => Translatable('Print'),
CSV => Translatable('CSV'),
Excel => Translatable('Excel'),
},
Name => 'ResultForm',
SelectedID => $Param{ResultForm} || 'Normal',
Class => 'Modernize',
);
my %Profiles = $SearchProfileObject->SearchProfileList(
Base => 'ITSMChangeSearch',
UserLogin => $Self->{UserLogin},
);
delete $Profiles{''};
delete $Profiles{'last-search'};
if ($EmptySearch) {
$Profiles{''} = '-';
}
else {
$Profiles{'last-search'} = '-';
}
$Param{ProfilesStrg} = $LayoutObject->BuildSelection(
Data => \%Profiles,
Name => 'Profile',
ID => 'SearchProfile',
SelectedID => $Profile,
Class => 'Modernize',
PossibleNone => 1,
);
# html search mask output
$LayoutObject->Block(
Name => 'SearchAJAX',
Data => { %Param, }, #%GetParam },
);
# number of minutes, days, weeks, months and years
my %OneToFiftyNine = map { $_ => sprintf '%2s', $_ } ( 1 .. 59 );
# time period that can be selected from the GUI
my %TimePeriod = %{ $ConfigObject->Get('ITSMWorkOrder::TimePeriod') };
TIMETYPE:
for my $TimeType (@TimeTypes) {
my $Prefix = $TimeType->{Prefix};
# show RequestedTime only when enabled in SysConfig
if ( $Prefix eq 'Requested' && !$Self->{Config}->{RequestedTime} ) {
next TIMETYPE;
}
my $Title = $LayoutObject->{LanguageObject}->Translate( $TimeType->{Title} );
my %TimeSelectionData = (
Prefix => $Prefix,
Title => $Title,
);
$TimeSelectionData{TimePoint} = $LayoutObject->BuildSelection(
Data => \%OneToFiftyNine,
Name => $Prefix . 'TimePoint',
SelectedID => $Param{ $Prefix . 'TimePoint' },
);
$TimeSelectionData{TimePointStart} = $LayoutObject->BuildSelection(
Data => {
'Last' => Translatable('last'),
'Before' => Translatable('before'),
},
Name => $Prefix . 'TimePointStart',
SelectedID => $Param{ $Prefix . 'TimePointStart' } || 'Last',
);
$TimeSelectionData{TimePointFormat} = $LayoutObject->BuildSelection(
Data => {
minute => Translatable('minute(s)'),
hour => Translatable('hour(s)'),
day => Translatable('day(s)'),
week => Translatable('week(s)'),
month => Translatable('month(s)'),
year => Translatable('year(s)'),
},
Name => $Prefix . 'TimePointFormat',
SelectedID => $Param{ $Prefix . 'TimePointFormat' },
);
$TimeSelectionData{TimeStart} = $LayoutObject->BuildDateSelection(
%Param,
%TimePeriod,
Prefix => $Prefix . 'TimeStart',
Format => 'DateInputFormat',
Validate => 1,
DiffTime => -( ( 60 * 60 * 24 ) * 30 ),
);
$TimeSelectionData{TimeStop} = $LayoutObject->BuildDateSelection(
%Param,
%TimePeriod,
Prefix => $Prefix . 'TimeStop',
Format => 'DateInputFormat',
);
# show time field
$LayoutObject->Block(
Name => 'TimeSelection',
Data => \%TimeSelectionData,
);
}
# output Dynamic fields blocks
# cycle trough the activated Dynamic Fields for this screen
DYNAMICFIELD:
for my $DynamicFieldConfig (
@{ $Self->{DynamicFieldChange} },
@{ $Self->{DynamicFieldWorkOrder} }
)
{
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
# get search field preferences
my $SearchFieldPreferences = $DynamicFieldBackendObject->SearchFieldPreferences(
DynamicFieldConfig => $DynamicFieldConfig,
);
next DYNAMICFIELD if !IsArrayRefWithData($SearchFieldPreferences);
PREFERENCE:
for my $Preference ( @{$SearchFieldPreferences} ) {
# skip fields that HTML could not be retrieved
next PREFERENCE if !IsHashRefWithData(
$DynamicFieldHTML{ $DynamicFieldConfig->{Name} . $Preference->{Type} }
);
$LayoutObject->Block(
Name => 'DynamicField',
Data => {
Label =>
$DynamicFieldHTML{ $DynamicFieldConfig->{Name} . $Preference->{Type} }
->{Label},
Field =>
$DynamicFieldHTML{ $DynamicFieldConfig->{Name} . $Preference->{Type} }
->{Field},
},
);
}
}
# show attributes
my %AlreadyShown;
ITEM:
for my $Item (@Attributes) {
my $Key = $Item->{Key};
next ITEM if !$Key;
next ITEM if !defined $Param{$Key};
next ITEM if $Param{$Key} eq '';
next ITEM if $AlreadyShown{$Key};
if ( ref $Param{$Key} eq 'ARRAY' && !@{ $Param{$Key} } ) {
next ITEM;
}
$AlreadyShown{$Key} = 1;
$LayoutObject->AddJSData(
Key => 'ITSMChangeManagementSearch.Attribute.' . $Key,
Value => 1,
);
}
# if no attribute is shown, show change number
if ( !$Profile ) {
$LayoutObject->AddJSData(
Key => 'ITSMChangeManagementSearch.Attribute.ChangeNumber',
Value => 1,
);
}
# build output
my $Output = $LayoutObject->Output(
TemplateFile => 'AgentITSMChangeSearch',
Data => \%Param,
AJAX => 1,
);
return $Output;
}
1;