Files
2024-10-14 00:08:40 +02:00

1236 lines
39 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::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";
<div id="$DivID" class="TooltipErrorMessage">
<p>
$FieldRequiredMessage
</p>
</div>
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";
<div id="$DivID" class="TooltipErrorMessage">
<p>
$ErrorMessage
</p>
</div>
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";
<input type="hidden" id="$FieldName" name="$FieldName" value="1"/>
EOF
if ( $Param{ConfirmationCheckboxes} ) {
$HTMLString = <<"EOF";
<input type="checkbox" id="$FieldName" name="$FieldName" value="1" $FieldChecked/>
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 = ' <br/>';
# 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<https://otrs.org/>).
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<https://www.gnu.org/licenses/gpl-3.0.txt>.
=cut