# --
# 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::System::DynamicField::Driver::BaseDateTime;
use strict;
use warnings;
use Kernel::System::VariableCheck qw(:all);
use Kernel::Language qw(Translatable);
use parent qw(Kernel::System::DynamicField::Driver::Base);
our @ObjectDependencies = (
'Kernel::System::DateTime',
'Kernel::System::DB',
'Kernel::System::DynamicFieldValue',
'Kernel::System::Log',
);
=head1 NAME
Kernel::System::DynamicField::Driver::BaseDateTime - sub module of
Kernel::System::DynamicField::Driver::Date and
Kernel::System::DynamicField::Driver::DateTime
=head1 DESCRIPTION
Date common functions.
=head1 PUBLIC INTERFACE
=cut
sub ValueGet {
my ( $Self, %Param ) = @_;
my $DFValue = $Kernel::OM->Get('Kernel::System::DynamicFieldValue')->ValueGet(
FieldID => $Param{DynamicFieldConfig}->{ID},
ObjectID => $Param{ObjectID},
);
return if !$DFValue;
return if !IsArrayRefWithData($DFValue);
return if !IsHashRefWithData( $DFValue->[0] );
return $DFValue->[0]->{ValueDateTime};
}
sub ValueSet {
my ( $Self, %Param ) = @_;
my $Success = $Kernel::OM->Get('Kernel::System::DynamicFieldValue')->ValueSet(
FieldID => $Param{DynamicFieldConfig}->{ID},
ObjectID => $Param{ObjectID},
Value => [
{
ValueDateTime => $Param{Value},
},
],
UserID => $Param{UserID},
);
return $Success;
}
sub ValueValidate {
my ( $Self, %Param ) = @_;
my $Prefix = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name};
my $DateRestriction = $Param{DynamicFieldConfig}->{Config}->{DateRestriction};
my $Success = $Kernel::OM->Get('Kernel::System::DynamicFieldValue')->ValueValidate(
Value => {
ValueDateTime => $Param{Value},
},
UserID => $Param{UserID}
);
if ($DateRestriction) {
# get time object
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
my $SystemTime = $DateTimeObject->ToEpoch();
my $ValueSystemTime = $DateTimeObject->Set(
String => $Param{Value},
);
$ValueSystemTime = $ValueSystemTime ? $DateTimeObject->ToEpoch() : undef;
if ( $DateRestriction eq 'DisableFutureDates' && $ValueSystemTime > $SystemTime ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message =>
"The value for the Data field ($Param{DynamicFieldConfig}->{Name}) is in the future! The date needs to be in the past!",
);
return;
}
elsif ( $DateRestriction eq 'DisablePastDates' && $ValueSystemTime < $SystemTime ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message =>
"The value for the Date field ($Param{DynamicFieldConfig}->{Name}) is in the past! The date needs to be in the future!",
);
return;
}
}
return $Success;
}
sub SearchSQLGet {
my ( $Self, %Param ) = @_;
my %Operators = (
Equals => '=',
GreaterThan => '>',
GreaterThanEquals => '>=',
SmallerThan => '<',
SmallerThanEquals => '<=',
);
if ( $Param{Operator} eq 'Empty' ) {
if ( $Param{SearchTerm} ) {
return " $Param{TableAlias}.value_date IS NULL ";
}
else {
return " $Param{TableAlias}.value_date IS NOT NULL ";
}
}
elsif ( !$Operators{ $Param{Operator} } ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
'Priority' => 'error',
'Message' => "Unsupported Operator $Param{Operator}",
);
return;
}
my $SQL = " $Param{TableAlias}.value_date $Operators{ $Param{Operator} } '";
$SQL .= $Kernel::OM->Get('Kernel::System::DB')->Quote( $Param{SearchTerm} ) . "' ";
return $SQL;
}
sub SearchSQLOrderFieldGet {
my ( $Self, %Param ) = @_;
return "$Param{TableAlias}.value_date";
}
sub EditFieldRender {
my ( $Self, %Param ) = @_;
# take config from field config
my $FieldConfig = $Param{DynamicFieldConfig}->{Config};
my $FieldName = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name};
my $FieldLabel = $Param{DynamicFieldConfig}->{Label};
my $Value;
# set the field value or default
if ( $Param{UseDefaultValue} ) {
$Value = $FieldConfig->{DefaultValue} || '';
}
if ( defined $Param{Value} ) {
$Value = $Param{Value};
}
if ($Value) {
my ( $Year, $Month, $Day, $Hour, $Minute, $Second ) = $Value =~
m{ \A ( \d{4} ) - ( \d{2} ) - ( \d{2} ) \s ( \d{2} ) : ( \d{2} ) : ( \d{2} ) \z }xms;
# If a value is sent this value must be active, then the Used part needs to be set to 1
# otherwise user can easily forget to mark the checkbox and this could lead into data
# lost (Bug#8258).
$FieldConfig->{ $FieldName . 'Used' } = 1;
$FieldConfig->{ $FieldName . 'Year' } = $Year;
$FieldConfig->{ $FieldName . 'Month' } = $Month;
$FieldConfig->{ $FieldName . 'Day' } = $Day;
$FieldConfig->{ $FieldName . 'Hour' } = $Hour;
$FieldConfig->{ $FieldName . 'Minute' } = $Minute;
}
# extract the dynamic field value from the web request
# TransformDates is always needed from EditFieldRender Bug#8452
my $FieldValues = $Self->EditFieldValueGet(
TransformDates => 1,
ReturnValueStructure => 1,
%Param,
);
# set values from ParamObject if present
if ( defined $FieldValues && IsHashRefWithData($FieldValues) ) {
for my $Type (qw(Used Year Month Day Hour Minute)) {
$FieldConfig->{ $FieldName . $Type } = $FieldValues->{ $FieldName . $Type };
}
}
# check and set class if necessary
# Bug#9358: Class 'DateSelection' is needed for CustomerInterface
my $FieldClass = 'DynamicFieldText DateSelection';
if ( defined $Param{Class} && $Param{Class} ne '' ) {
$FieldClass .= ' ' . $Param{Class};
}
# set field as mandatory
if ( $Param{Mandatory} ) {
$FieldClass .= ' Validate_Required';
}
# set error css class
if ( $Param{ServerError} ) {
$FieldClass .= ' ServerError';
}
# to set the predefined based on a time difference
my $DiffTime = $FieldConfig->{DefaultValue};
if ( !defined $DiffTime || $DiffTime !~ m/^ \s* -? \d+ \s* $/smx ) {
$DiffTime = 0;
}
# to set the years range
my %YearsPeriodRange;
if ( defined $FieldConfig->{YearsPeriod} && $FieldConfig->{YearsPeriod} eq '1' ) {
%YearsPeriodRange = (
YearPeriodPast => $FieldConfig->{YearsInPast} || 0,
YearPeriodFuture => $FieldConfig->{YearsInFuture} || 0,
);
}
# date restrictions
if ( $FieldConfig->{DateRestriction} ) {
if ( $FieldConfig->{DateRestriction} eq 'DisablePastDates' ) {
$FieldConfig->{ValidateDateInFuture} = 1;
}
elsif ( $FieldConfig->{DateRestriction} eq 'DisableFutureDates' ) {
$FieldConfig->{ValidateDateNotInFuture} = 1;
}
}
my $HTMLString = $Param{LayoutObject}->BuildDateSelection(
%Param,
Prefix => $FieldName,
Format => 'DateInputFormatLong',
$FieldName . 'Class' => $FieldClass,
DiffTime => $DiffTime,
$FieldName . Required => $Param{Mandatory} || 0,
$FieldName . Optional => 1,
Validate => 1,
%{$FieldConfig},
%YearsPeriodRange,
);
if ( $Param{Mandatory} ) {
my $DivID = $FieldName . 'UsedError';
my $FieldRequiredMessage = $Param{LayoutObject}->{LanguageObject}->Translate("This field is required.");
# for client side validation
$HTMLString .= <<"EOF";
$FieldRequiredMessage
EOF
}
if ( $Param{ServerError} ) {
my $ErrorMessage = $Param{ErrorMessage} || 'This field is required.';
$ErrorMessage = $Param{LayoutObject}->{LanguageObject}->Translate($ErrorMessage);
my $DivID = $FieldName . 'UsedServerError';
# for server side validation
$HTMLString .= <<"EOF";
$ErrorMessage
EOF
}
# call EditLabelRender on the common Driver
my $LabelString = $Self->EditLabelRender(
%Param,
Mandatory => $Param{Mandatory} || '0',
FieldName => $FieldName . 'Used',
);
my $Data = {
Field => $HTMLString,
Label => $LabelString,
};
return $Data;
}
sub EditFieldValueGet {
my ( $Self, %Param ) = @_;
# set the Prefix as the dynamic field name
my $Prefix = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name};
my %DynamicFieldValues;
# check if there is a Template and retrieve the dynamic field value from there
if ( IsHashRefWithData( $Param{Template} ) && defined $Param{Template}->{ $Prefix . 'Used' } ) {
for my $Type (qw(Used Year Month Day Hour Minute)) {
$DynamicFieldValues{ $Prefix . $Type } = $Param{Template}->{ $Prefix . $Type } || 0;
}
}
# otherwise get dynamic field value from the web request
elsif (
defined $Param{ParamObject}
&& ref $Param{ParamObject} eq 'Kernel::System::Web::Request'
)
{
for my $Type (qw(Used Year Month Day Hour Minute)) {
$DynamicFieldValues{ $Prefix . $Type } = $Param{ParamObject}->GetParam(
Param => $Prefix . $Type,
) || 0;
}
}
# return if the field is empty (e.g. initial screen)
return if !$DynamicFieldValues{ $Prefix . 'Used' }
&& !$DynamicFieldValues{ $Prefix . 'Year' }
&& !$DynamicFieldValues{ $Prefix . 'Month' }
&& !$DynamicFieldValues{ $Prefix . 'Day' }
&& !$DynamicFieldValues{ $Prefix . 'Hour' }
&& !$DynamicFieldValues{ $Prefix . 'Minute' };
# check if need and can transform dates
# transform the dates early for ReturnValueStructure or ManualTimeStamp Bug#8452
if ( $Param{TransformDates} && $Param{LayoutObject} ) {
# transform time stamp based on user time zone
%DynamicFieldValues = $Param{LayoutObject}->TransformDateSelection(
%DynamicFieldValues,
Prefix => $Prefix,
);
}
# check if return value structure is needed
if ( defined $Param{ReturnValueStructure} && $Param{ReturnValueStructure} eq '1' ) {
return \%DynamicFieldValues;
}
# check if return template structure is needed
if ( defined $Param{ReturnTemplateStructure} && $Param{ReturnTemplateStructure} eq '1' ) {
return \%DynamicFieldValues;
}
# add seconds as 0 to the DynamicFieldValues hash
$DynamicFieldValues{ 'DynamicField_' . $Param{DynamicFieldConfig}->{Name} . 'Second' } = 0;
my $ManualTimeStamp = '';
if ( $DynamicFieldValues{ $Prefix . 'Used' } ) {
# add a leading zero for date parts that could be less than ten to generate a correct
# time stamp
for my $Type (qw(Month Day Hour Minute Second)) {
$DynamicFieldValues{ $Prefix . $Type } = sprintf "%02d",
$DynamicFieldValues{ $Prefix . $Type };
}
my $Year = $DynamicFieldValues{ $Prefix . 'Year' } || '0000';
my $Month = $DynamicFieldValues{ $Prefix . 'Month' } || '00';
my $Day = $DynamicFieldValues{ $Prefix . 'Day' } || '00';
my $Hour = $DynamicFieldValues{ $Prefix . 'Hour' } || '00';
my $Minute = $DynamicFieldValues{ $Prefix . 'Minute' } || '00';
my $Second = $DynamicFieldValues{ $Prefix . 'Second' } || '00';
$ManualTimeStamp =
$Year . '-' . $Month . '-' . $Day . ' '
. $Hour . ':' . $Minute . ':' . $Second;
}
return $ManualTimeStamp;
}
sub EditFieldValueValidate {
my ( $Self, %Param ) = @_;
# get the field value from the http request
my $Value = $Self->EditFieldValueGet(
DynamicFieldConfig => $Param{DynamicFieldConfig},
ParamObject => $Param{ParamObject},
ReturnValueStructure => 1,
);
# on normal basis Used field could be empty but if there was no value from EditFieldValueGet()
# it must be an error
if ( !defined $Value ) {
return {
ServerError => 1,
ErrorMessage => 'Invalid Date!'
};
}
my $ServerError;
my $ErrorMessage;
# set the date time prefix as field name
my $Prefix = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name};
# date restriction
my $DateRestriction = $Param{DynamicFieldConfig}->{Config}->{DateRestriction};
# perform necessary validations
if ( $Param{Mandatory} && !$Value->{ $Prefix . 'Used' } ) {
$ServerError = 1;
}
if ( $Value->{ $Prefix . 'Used' } && $DateRestriction ) {
my $Year = $Value->{ $Prefix . 'Year' } || '0000';
my $Month = $Value->{ $Prefix . 'Month' } || '00';
my $Day = $Value->{ $Prefix . 'Day' } || '00';
my $Hour = $Value->{ $Prefix . 'Hour' } || '00';
my $Minute = $Value->{ $Prefix . 'Minute' } || '00';
my $Second = $Value->{ $Prefix . 'Second' } || '00';
my $ManualTimeStamp =
$Year . '-' . $Month . '-' . $Day . ' '
. $Hour . ':' . $Minute . ':' . $Second;
# get time object
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
my $SystemTime = $DateTimeObject->ToEpoch();
my $ValueSystemTime = $DateTimeObject->Set(
String => $ManualTimeStamp,
);
$ValueSystemTime = $ValueSystemTime ? $DateTimeObject->ToEpoch() : undef;
if ( $DateRestriction eq 'DisableFutureDates' && $ValueSystemTime > $SystemTime ) {
$ServerError = 1;
$ErrorMessage = "Invalid date (need a past date)!";
}
elsif ( $DateRestriction eq 'DisablePastDates' && $ValueSystemTime < $SystemTime ) {
$ServerError = 1;
$ErrorMessage = "Invalid date (need a future date)!";
}
}
# create resulting structure
my $Result = {
ServerError => $ServerError,
ErrorMessage => $ErrorMessage,
};
return $Result;
}
sub DisplayValueRender {
my ( $Self, %Param ) = @_;
my $Value = '';
# convert date to localized string
if ( defined $Param{Value} ) {
$Value = $Param{LayoutObject}->{LanguageObject}->FormatTimeString(
$Param{Value},
'DateFormat',
'NoSeconds',
);
}
# in this Driver there is no need for HTMLOutput
# Title is always equal to Value
my $Title = $Value;
# set field link form config
my $Link = $Param{DynamicFieldConfig}->{Config}->{Link} || '';
my $LinkPreview = $Param{DynamicFieldConfig}->{Config}->{LinkPreview} || '';
my $Data = {
Value => $Value,
Title => $Title,
Link => $Link,
LinkPreview => $LinkPreview,
};
return $Data;
}
sub SearchFieldRender {
my ( $Self, %Param ) = @_;
# take config from field config
my $FieldConfig = $Param{DynamicFieldConfig}->{Config};
my $FieldName = 'Search_DynamicField_' . $Param{DynamicFieldConfig}->{Name};
# set the default type
$Param{Type} ||= 'TimeSlot';
# add type to FieldName
$FieldName .= $Param{Type};
my $FieldLabel = $Param{DynamicFieldConfig}->{Label};
my $Value;
my %DefaultValue;
if ( defined $Param{DefaultValue} ) {
my @Items = split /;/, $Param{DefaultValue};
# format example of the key name for TimePoint:
#
# Search_DynamicField_DateTest1TimePointFormat=week;Search_DynamicField_DateTest1TimePointStart=Before;Search_DynamicField_DateTest1TimePointValue=7;
# format example of the key name for TimeSlot:
#
# Search_DynamicField_DateTest1TimeSlotStartYear=1974;Search_DynamicField_DateTest1TimeSlotStartMonth=01;Search_DynamicField_DateTest1TimeSlotStartDay=26;
# Search_DynamicField_DateTest1TimeSlotStartHour=00;Search_DynamicField_DateTest1TimeSlotStartMinute=00;Search_DynamicField_DateTest1TimeSlotStartSecond=00;
# Search_DynamicField_DateTest1TimeSlotStopYear=2013;Search_DynamicField_DateTest1TimeSlotStopMonth=01;Search_DynamicField_DateTest1TimeSlotStopDay=26;
# Search_DynamicField_DateTest1TimeSlotStopHour=23;Search_DynamicField_DateTest1TimeSlotStopMinute=59;Search_DynamicField_DateTest1TimeSlotStopSecond=59;
my $KeyName = 'Search_DynamicField_' . $Param{DynamicFieldConfig}->{Name} . $Param{Type};
ITEM:
for my $Item (@Items) {
my ( $Key, $Value ) = split /=/, $Item;
# only handle keys that match the current type
next ITEM if $Key !~ m{ $Param{Type} }xms;
if ( $Param{Type} eq 'TimePoint' ) {
if ( $Key eq $KeyName . 'Format' ) {
$DefaultValue{Format}->{$Key} = $Value;
}
elsif ( $Key eq $KeyName . 'Start' ) {
$DefaultValue{Start}->{$Key} = $Value;
}
elsif ( $Key eq $KeyName . 'Value' ) {
$DefaultValue{Value}->{$Key} = $Value;
}
next ITEM;
}
if ( $Key =~ m{Start} ) {
$DefaultValue{ValueStart}->{$Key} = $Value;
}
elsif ( $Key =~ m{Stop} ) {
$DefaultValue{ValueStop}->{$Key} = $Value;
}
}
}
# set the field value
if (%DefaultValue) {
$Value = \%DefaultValue;
}
# get the field value, this function is always called after the profile is loaded
my $FieldValues = $Self->SearchFieldValueGet(
%Param,
);
if (
defined $FieldValues
&& $Param{Type} eq 'TimeSlot'
&& defined $FieldValues->{ValueStart}
&& defined $FieldValues->{ValueStop}
)
{
$Value = $FieldValues;
}
elsif (
defined $FieldValues
&& $Param{Type} eq 'TimePoint'
&& defined $FieldValues->{Format}
&& defined $FieldValues->{Start}
&& defined $FieldValues->{Value}
)
{
$Value = $FieldValues;
}
# check and set class if necessary
my $FieldClass = 'DynamicFieldDateTime';
# set as checked if necessary
my $FieldChecked = ( defined $Value->{$FieldName} && $Value->{$FieldName} == 1 ? 'checked="checked"' : '' );
my $HTMLString = <<"EOF";
EOF
if ( $Param{ConfirmationCheckboxes} ) {
$HTMLString = <<"EOF";
EOF
}
# build HTML for TimePoint
if ( $Param{Type} eq 'TimePoint' ) {
$HTMLString .= $Param{LayoutObject}->BuildSelection(
Data => {
'Before' => Translatable('more than ... ago'),
'Last' => Translatable('within the last ...'),
'Next' => Translatable('within the next ...'),
'After' => Translatable('in more than ...'),
},
Sort => 'IndividualKey',
SortIndividual => [ 'Before', 'Last', 'Next', 'After' ],
Name => $FieldName . 'Start',
SelectedID => $Value->{Start}->{ $FieldName . 'Start' } || 'Last',
);
$HTMLString .= ' ' . $Param{LayoutObject}->BuildSelection(
Data => [ 1 .. 59 ],
Name => $FieldName . 'Value',
SelectedID => $Value->{Value}->{ $FieldName . 'Value' } || 1,
);
$HTMLString .= ' ' . $Param{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 => $FieldName . 'Format',
SelectedID => $Value->{Format}->{ $FieldName . 'Format' } || 'day',
);
my $AdditionalText;
if ( $Param{UseLabelHints} ) {
$AdditionalText = Translatable('before/after');
}
# call EditLabelRender on the common backend
my $LabelString = $Self->EditLabelRender(
%Param,
FieldName => $FieldName,
AdditionalText => $AdditionalText,
);
my $Data = {
Field => $HTMLString,
Label => $LabelString,
};
return $Data;
}
# to set the years range
my %YearsPeriodRange;
if ( defined $FieldConfig->{YearsPeriod} && $FieldConfig->{YearsPeriod} eq '1' ) {
%YearsPeriodRange = (
YearPeriodPast => $FieldConfig->{YearsInPast} || 0,
YearPeriodFuture => $FieldConfig->{YearsInFuture} || 0,
);
}
# build HTML for start value set
$HTMLString .= $Param{LayoutObject}->BuildDateSelection(
%Param,
Prefix => $FieldName . 'Start',
Format => 'DateInputFormatLong',
$FieldName . 'Class' => $FieldClass,
DiffTime => -( ( 60 * 60 * 24 ) * 30 ),
Validate => 1,
%{ $Value->{ValueStart} },
%YearsPeriodRange,
OverrideTimeZone => 1,
);
# to put a line break between the two search dates
my $LineBreak = ' ';
# in screens where the confirmation checkboxes is set, there is no need to render the filed in
# two lines (e.g. AdminGenericAgentn CustomerTicketSearch)
if ( $Param{ConfirmationCheckboxes} ) {
$LineBreak = '';
}
$HTMLString .= ' ' . $Param{LayoutObject}->{LanguageObject}->Translate("and") . "$LineBreak\n";
# build HTML for stop value set
$HTMLString .= $Param{LayoutObject}->BuildDateSelection(
%Param,
Prefix => $FieldName . 'Stop',
Format => 'DateInputFormatLong',
$FieldName . 'Class' => $FieldClass,
DiffTime => +( ( 60 * 60 * 24 ) * 30 ),
Validate => 1,
%{ $Value->{ValueStop} },
%YearsPeriodRange,
OverrideTimeZone => 1,
);
my $AdditionalText;
if ( $Param{UseLabelHints} ) {
$AdditionalText = Translatable('between');
}
# call EditLabelRender on the common Driver
my $LabelString = $Self->EditLabelRender(
%Param,
FieldName => $FieldName,
AdditionalText => $AdditionalText,
);
my $Data = {
Field => $HTMLString,
Label => $LabelString,
};
return $Data;
}
sub SearchFieldValueGet {
my ( $Self, %Param ) = @_;
# set the Prefix as the dynamic field name
my $Prefix = 'Search_DynamicField_' . $Param{DynamicFieldConfig}->{Name};
# set the default type
$Param{Type} ||= 'TimeSlot';
# add type to prefix
$Prefix .= $Param{Type};
if ( $Param{Type} eq 'TimePoint' ) {
# get dynamic field value
my %DynamicFieldValues;
for my $Type (qw(Start Value Format)) {
# get dynamic field value form param object
if ( defined $Param{ParamObject} ) {
# return if value was not checked (useful in customer interface)
return if !$Param{ParamObject}->GetParam( Param => $Prefix );
$DynamicFieldValues{ $Prefix . $Type } = $Param{ParamObject}->GetParam(
Param => $Prefix . $Type,
);
}
# otherwise get the value from the profile
elsif ( defined $Param{Profile} ) {
# return if value was not checked (useful in customer interface)
return if !$Param{Profile}->{$Prefix};
$DynamicFieldValues{ $Prefix . $Type } = $Param{Profile}->{ $Prefix . $Type };
}
else {
return;
}
}
# return if the field is empty (e.g. initial screen)
return if !$DynamicFieldValues{ $Prefix . 'Start' }
&& !$DynamicFieldValues{ $Prefix . 'Value' }
&& !$DynamicFieldValues{ $Prefix . 'Format' };
$DynamicFieldValues{$Prefix} = 1;
# check if return value structure is needed
if ( defined $Param{ReturnProfileStructure} && $Param{ReturnProfileStructure} eq '1' ) {
return \%DynamicFieldValues;
}
return {
Format => {
$Prefix . 'Format' => $DynamicFieldValues{ $Prefix . 'Format' } || 'Last',
},
Start => {
$Prefix . 'Start' => $DynamicFieldValues{ $Prefix . 'Start' } || 'day',
},
Value => {
$Prefix . 'Value' => $DynamicFieldValues{ $Prefix . 'Value' } || 1,
},
$Prefix => 1,
};
}
# get dynamic field value
my %DynamicFieldValues;
for my $Type (qw(Start Stop)) {
for my $Part (qw(Year Month Day Hour Minute)) {
# get dynamic field value from param object
if ( defined $Param{ParamObject} ) {
# return if value was not checked (useful in customer interface)
return if !$Param{ParamObject}->GetParam( Param => $Prefix );
$DynamicFieldValues{ $Prefix . $Type . $Part } = $Param{ParamObject}->GetParam(
Param => $Prefix . $Type . $Part,
);
}
# otherwise get the value from the profile
elsif ( defined $Param{Profile} ) {
# return if value was not checked (useful in customer interface)
return if !$Param{Profile}->{$Prefix};
$DynamicFieldValues{ $Prefix . $Type . $Part } = $Param{Profile}->{ $Prefix . $Type . $Part };
}
else {
return;
}
}
}
# return if the field is empty (e.g. initial screen)
return if !$DynamicFieldValues{ $Prefix . 'StartYear' }
&& !$DynamicFieldValues{ $Prefix . 'StartMonth' }
&& !$DynamicFieldValues{ $Prefix . 'StartDay' }
&& !$DynamicFieldValues{ $Prefix . 'StopYear' }
&& !$DynamicFieldValues{ $Prefix . 'StopMonth' }
&& !$DynamicFieldValues{ $Prefix . 'StopDay' };
$DynamicFieldValues{ $Prefix . 'StartSecond' } = '00';
$DynamicFieldValues{ $Prefix . 'StopSecond' } = '59';
$DynamicFieldValues{$Prefix} = 1;
# check if return value structure is needed
if ( defined $Param{ReturnProfileStructure} && $Param{ReturnProfileStructure} eq '1' ) {
return \%DynamicFieldValues;
}
# add a leading zero for date parts that could be less than ten to generate a correct
# time stamp
for my $Type (qw(Start Stop)) {
for my $Part (qw(Month Day Hour Minute Second)) {
$DynamicFieldValues{ $Prefix . $Type . $Part } = sprintf "%02d",
$DynamicFieldValues{ $Prefix . $Type . $Part };
}
}
my $ValueStart = {
$Prefix . 'StartYear' => $DynamicFieldValues{ $Prefix . 'StartYear' } || '0000',
$Prefix . 'StartMonth' => $DynamicFieldValues{ $Prefix . 'StartMonth' } || '00',
$Prefix . 'StartDay' => $DynamicFieldValues{ $Prefix . 'StartDay' } || '00',
$Prefix . 'StartHour' => $DynamicFieldValues{ $Prefix . 'StartHour' } || '00',
$Prefix . 'StartMinute' => $DynamicFieldValues{ $Prefix . 'StartMinute' } || '00',
$Prefix . 'StartSecond' => $DynamicFieldValues{ $Prefix . 'StartSecond' } || '00',
};
my $ValueStop = {
$Prefix . 'StopYear' => $DynamicFieldValues{ $Prefix . 'StopYear' } || '0000',
$Prefix . 'StopMonth' => $DynamicFieldValues{ $Prefix . 'StopMonth' } || '00',
$Prefix . 'StopDay' => $DynamicFieldValues{ $Prefix . 'StopDay' } || '00',
$Prefix . 'StopHour' => $DynamicFieldValues{ $Prefix . 'StopHour' } || '00',
$Prefix . 'StopMinute' => $DynamicFieldValues{ $Prefix . 'StopMinute' } || '00',
$Prefix . 'StopSecond' => $DynamicFieldValues{ $Prefix . 'StopSecond' } || '00',
};
return {
$Prefix => 1,
ValueStart => $ValueStart,
ValueStop => $ValueStop,
};
}
sub SearchFieldPreferences {
my ( $Self, %Param ) = @_;
my @Preferences = (
{
Type => 'TimePoint',
LabelSuffix => 'before/after',
},
{
Type => 'TimeSlot',
LabelSuffix => 'between',
},
);
return \@Preferences;
}
sub SearchFieldParameterBuild {
my ( $Self, %Param ) = @_;
# set the default type
$Param{Type} ||= 'TimeSlot';
# get field value
my $Value = $Self->SearchFieldValueGet(%Param);
my $DisplayValue;
if ( defined $Value && !$Value ) {
$DisplayValue = '';
}
# do not search if value was not checked (useful for customer interface)
if ( !$Value ) {
return {
Parameter => {
Equals => $Value,
},
Display => $DisplayValue,
};
}
# search for a wild card in the value
if ( $Value && IsHashRefWithData($Value) ) {
my $Prefix = 'Search_DynamicField_' . $Param{DynamicFieldConfig}->{Name};
$Prefix .= $Param{Type};
if (
$Param{Type} eq 'TimePoint'
&& $Value->{Start}->{ $Prefix . 'Start' }
&& $Value->{Format}->{ $Prefix . 'Format' }
&& $Value->{Value}->{ $Prefix . 'Value' }
&& $Value->{$Prefix}
)
{
# to store the search parameters
my %Parameter;
# store in local variables for easier handling
my $Format = $Value->{Format}->{ $Prefix . 'Format' };
my $Start = $Value->{Start}->{ $Prefix . 'Start' };
my $Value = $Value->{Value}->{ $Prefix . 'Value' };
my $DiffTimeMinutes = 0;
if ( $Format eq 'minute' ) {
$DiffTimeMinutes = $Value;
}
elsif ( $Format eq 'hour' ) {
$DiffTimeMinutes = $Value * 60;
}
elsif ( $Format eq 'day' ) {
$DiffTimeMinutes = $Value * 60 * 24;
}
elsif ( $Format eq 'week' ) {
$DiffTimeMinutes = $Value * 60 * 24 * 7;
}
elsif ( $Format eq 'month' ) {
$DiffTimeMinutes = $Value * 60 * 24 * 30;
}
elsif ( $Format eq 'year' ) {
$DiffTimeMinutes = $Value * 60 * 24 * 365;
}
# get time object
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
# get the current time in epoch seconds and as time-stamp
my $Now = $DateTimeObject->ToEpoch();
my $NowTimeStamp = $DateTimeObject->ToString();
# calculate difference time seconds
my $DiffTimeSeconds = $DiffTimeMinutes * 60;
my $DisplayValue = '';
# define to search before or after that time stamp
if ( $Start eq 'Before' ) {
# we must subtract the difference because it is in the past
my $DateTimeObjectBefore = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
Epoch => $Now - $DiffTimeSeconds,
}
);
# only search dates in the past (before the time stamp)
$Parameter{SmallerThanEquals} = $DateTimeObjectBefore->ToString();
# set the display value
$DisplayValue = '<= ' . $DateTimeObjectBefore->ToString();
}
elsif ( $Start eq 'Last' ) {
# we must subtract the differences because it is in the past
my $DateTimeObjectLast = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
Epoch => $Now - $DiffTimeSeconds,
}
);
# search dates in the past (after the time stamp and up to now)
$Parameter{GreaterThanEquals} = $DateTimeObjectLast->ToString();
$Parameter{SmallerThanEquals} = $NowTimeStamp;
# set the display value
$DisplayValue = $DateTimeObjectLast->ToString() . ' - ' . $NowTimeStamp;
}
elsif ( $Start eq 'Next' ) {
# we must add the difference because it is in the future
my $DateTimeObjectNext = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
Epoch => $Now + $DiffTimeSeconds,
}
);
# search dates in the future (after now and up to the time stamp)
$Parameter{GreaterThanEquals} = $NowTimeStamp;
$Parameter{SmallerThanEquals} = $DateTimeObjectNext->ToString();
# set the display value
$DisplayValue = $NowTimeStamp . ' - ' . $DateTimeObjectNext->ToString();
}
elsif ( $Start eq 'After' ) {
# we must add the difference because it is in the future
my $DateTimeObjectAfter = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
Epoch => $Now + $DiffTimeSeconds,
}
);
# only search dates in the future (after the time stamp)
$Parameter{GreaterThanEquals} = $DateTimeObjectAfter->ToString();
# set the display value
$DisplayValue = '>= ' . $DateTimeObjectAfter->ToString();
}
# return search parameter structure
return {
Parameter => \%Parameter,
Display => $DisplayValue,
};
}
my $ValueStart = $Value->{ValueStart}->{ $Prefix . 'StartYear' } . '-'
. $Value->{ValueStart}->{ $Prefix . 'StartMonth' } . '-'
. $Value->{ValueStart}->{ $Prefix . 'StartDay' } . ' '
. $Value->{ValueStart}->{ $Prefix . 'StartHour' } . ':'
. $Value->{ValueStart}->{ $Prefix . 'StartMinute' } . ':'
. $Value->{ValueStart}->{ $Prefix . 'StartSecond' };
my $ValueStop = $Value->{ValueStop}->{ $Prefix . 'StopYear' } . '-'
. $Value->{ValueStop}->{ $Prefix . 'StopMonth' } . '-'
. $Value->{ValueStop}->{ $Prefix . 'StopDay' } . ' '
. $Value->{ValueStop}->{ $Prefix . 'StopHour' } . ':'
. $Value->{ValueStop}->{ $Prefix . 'StopMinute' } . ':'
. $Value->{ValueStop}->{ $Prefix . 'StopSecond' };
# return search parameter structure
return {
Parameter => {
GreaterThanEquals => $ValueStart,
SmallerThanEquals => $ValueStop,
},
Display => $ValueStart . ' - ' . $ValueStop,
};
}
return;
}
sub StatsFieldParameterBuild {
my ( $Self, %Param ) = @_;
return {
Name => $Param{DynamicFieldConfig}->{Label},
Element => 'DynamicField_' . $Param{DynamicFieldConfig}->{Name},
TimePeriodFormat => 'DateInputFormatLong',
Block => 'Time',
};
}
sub StatsSearchFieldParameterBuild {
my ( $Self, %Param ) = @_;
my $Value = $Param{Value};
# set operator
my $Operator = $Param{Operator};
return {} if !$Operator;
return {
$Operator => $Value,
};
}
sub ReadableValueRender {
my ( $Self, %Param ) = @_;
my $Value = defined $Param{Value} ? $Param{Value} : '';
# only keep date and time without seconds or milliseconds
$Value =~ s{\A (\d{4} - \d{2} - \d{2} [ ] \d{2} : \d{2} ) }{$1}xms;
# Title is always equal to Value
my $Title = $Value;
my $Data = {
Value => $Value,
Title => $Title,
};
return $Data;
}
sub TemplateValueTypeGet {
my ( $Self, %Param ) = @_;
my $FieldName = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name};
# set the field types
my $EditValueType = 'SCALAR';
my $SearchValueType = 'SCALAR';
# return the correct structure
if ( $Param{FieldType} eq 'Edit' ) {
return {
$FieldName => $EditValueType,
};
}
elsif ( $Param{FieldType} eq 'Search' ) {
return {
'Search_' . $FieldName => $SearchValueType,
};
}
else {
return {
$FieldName => $EditValueType,
'Search_' . $FieldName => $SearchValueType,
};
}
}
sub RandomValueSet {
my ( $Self, %Param ) = @_;
my $YearValue = int( rand(40) ) + 1_990;
my $MonthValue = int( rand(9) ) + 1;
my $DayValue = int( rand(10) ) + 10;
my $HourValue = int( rand(12) ) + 10;
my $MinuteValue = int( rand(30) ) + 10;
my $SecondValue = int( rand(30) ) + 10;
my $Value = $YearValue . '-0' . $MonthValue . '-' . $DayValue . ' '
. $HourValue . ':' . $MinuteValue . ':' . $SecondValue;
my $Success = $Self->ValueSet(
%Param,
Value => $Value,
);
if ( !$Success ) {
return {
Success => 0,
};
}
return {
Success => 1,
Value => $Value,
};
}
sub ObjectMatch {
my ( $Self, %Param ) = @_;
my $FieldName = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name};
# not supported
return 0;
}
sub HistoricalValuesGet {
my ( $Self, %Param ) = @_;
# get historical values from database
my $HistoricalValues = $Kernel::OM->Get('Kernel::System::DynamicFieldValue')->HistoricalValueGet(
FieldID => $Param{DynamicFieldConfig}->{ID},
ValueType => 'DateTime',
);
# return the historical values from database
return $HistoricalValues;
}
sub ValueLookup {
my ( $Self, %Param ) = @_;
my $Value = defined $Param{Key} ? $Param{Key} : '';
# check if a translation is possible
if ( defined $Param{LanguageObject} ) {
# translate value
$Value = $Param{LanguageObject}->FormatTimeString(
$Value,
'DateFormat',
'NoSeconds',
);
}
return $Value;
}
1;
=head1 TERMS AND CONDITIONS
This software is part of the OTRS project (L).
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 L.
=cut