1# -- 2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/ 3# -- 4# This software comes with ABSOLUTELY NO WARRANTY. For details, see 5# the enclosed file COPYING for license information (GPL). If you 6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. 7# -- 8## nofilter(TidyAll::Plugin::OTRS::Perl::LayoutObject) 9package Kernel::System::SysConfig::ValueType::Date; 10 11use strict; 12use warnings; 13 14use Kernel::System::VariableCheck qw(:all); 15 16use parent qw(Kernel::System::SysConfig::BaseValueType); 17 18our @ObjectDependencies = ( 19 'Kernel::Config', 20 'Kernel::Language', 21 'Kernel::Output::HTML::Layout', 22 'Kernel::System::Log', 23 'Kernel::System::JSON', 24 'Kernel::System::User', 25); 26 27=head1 NAME 28 29Kernel::System::SysConfig::ValueType::Date - System configuration date value type backed. 30 31=head1 PUBLIC INTERFACE 32 33=head2 new() 34 35Create an object. Do not use it directly, instead use: 36 37 use Kernel::System::ObjectManager; 38 local $Kernel::OM = Kernel::System::ObjectManager->new(); 39 my $ValueTypeObject = $Kernel::OM->Get('Kernel::System::SysConfig::ValueType::Date'); 40 41=cut 42 43sub new { 44 my ( $Type, %Param ) = @_; 45 46 # Allocate new hash for object. 47 my $Self = {}; 48 bless( $Self, $Type ); 49 50 return $Self; 51} 52 53=head2 SettingEffectiveValueCheck() 54 55Check if provided EffectiveValue matches structure defined in XMLContentParsed. 56 57 my %Result = $ValueTypeObject->SettingEffectiveValueCheck( 58 XMLContentParsed => { # (required) 59 Value => [ 60 { 61 'Item' => [ 62 { 63 'Content' => '2016-01-01', 64 'ValueType' => 'Date', 65 }, 66 ], 67 }, 68 ], 69 }, 70 EffectiveValue => '2016-02-02', # (optional) 71 UserID => 1, # (required) 72 ); 73 74Result: 75 %Result = ( 76 EffectiveValue => '2016-02-03', # Note that EffectiveValue can be modified 77 Success => 1, 78 Error => undef, 79 ); 80 81=cut 82 83sub SettingEffectiveValueCheck { 84 my ( $Self, %Param ) = @_; 85 86 for my $Needed (qw(XMLContentParsed UserID)) { 87 if ( !$Param{$Needed} ) { 88 $Kernel::OM->Get('Kernel::System::Log')->Log( 89 Priority => 'error', 90 Message => "Need $Needed!" 91 ); 92 93 return; 94 } 95 } 96 97 my %Result = ( 98 Success => 0, 99 ); 100 101 # Data should be scalar. 102 if ( ref $Param{EffectiveValue} ) { 103 $Result{Error} = 'EffectiveValue for Date must be a scalar!'; 104 return %Result; 105 } 106 107 if ( $Param{EffectiveValue} !~ m{\d{4}-\d{2}-\d{2}} ) { 108 $Result{Error} = "EffectiveValue for Date($Param{EffectiveValue}) must be in format YYYY-MM-DD!"; 109 return %Result; 110 } 111 112 my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences( 113 UserID => $Param{UserID}, 114 ); 115 116 my $OTRSTimeZone = $Kernel::OM->Get('Kernel::Config')->Get("OTRSTimeZone"); 117 my $DateTimeObject; 118 119 if ( !$Preferences{UserTimeZone} || $Preferences{UserTimeZone} eq $OTRSTimeZone ) { 120 $DateTimeObject = $Kernel::OM->Create( 121 'Kernel::System::DateTime', 122 ObjectParams => { 123 TimeZone => $OTRSTimeZone, 124 }, 125 ); 126 127 my $SetSuccess = $DateTimeObject->Set( String => $Param{EffectiveValue} ); 128 129 if ( !$SetSuccess ) { 130 $Result{Error} = $Kernel::OM->Get('Kernel::Language')->Translate( 131 "EffectiveValue for Date($Param{EffectiveValue}) must be in format YYYY-MM-DD!", 132 ); 133 return %Result; 134 } 135 136 $Result{EffectiveValue} = $Param{EffectiveValue}; 137 } 138 else { 139 $DateTimeObject = $Kernel::OM->Create( 140 'Kernel::System::DateTime', 141 ObjectParams => { 142 TimeZone => $Preferences{UserTimeZone}, 143 }, 144 ); 145 146 my $SetSuccess = $DateTimeObject->Set( String => $Param{EffectiveValue} ); 147 148 if ( !$SetSuccess ) { 149 $Result{Error} = $Kernel::OM->Get('Kernel::Language')->Translate( 150 "EffectiveValue for Date($Param{EffectiveValue}) must be in format YYYY-MM-DD!", 151 ); 152 return %Result; 153 } 154 155 my $Success = $DateTimeObject->ToTimeZone( 156 TimeZone => $OTRSTimeZone, 157 ); 158 159 if ($Success) { 160 $Result{EffectiveValue} = $DateTimeObject->ToString(); 161 } 162 else { 163 $Result{Error} = $Kernel::OM->Get('Kernel::Language')->Translate( 164 "System was not able to calculate user Date in OTRSTimeZone!" 165 ); 166 167 $Kernel::OM->Get('Kernel::System::Log')->Log( 168 Priority => 'error', 169 Message => "System was not able to calculate user Date in OTRSTimeZone!" 170 ); 171 } 172 } 173 174 if ( !$DateTimeObject ) { 175 $Result{Error} = $Kernel::OM->Get('Kernel::Language')->Translate( 176 "EffectiveValue for Date($Param{EffectiveValue}) must be in format YYYY-MM-DD!", 177 ); 178 return %Result; 179 } 180 181 $Result{Success} = 1; 182 183 return %Result; 184} 185 186=head2 SettingRender() 187 188Extracts the effective value from a XML parsed setting. 189 190 my $SettingHTML = $ValueTypeObject->SettingRender( 191 Name => 'SettingName', 192 EffectiveValue => '2016-02-02', # (optional) 193 DefaultValue => 'Product 5', # (optional) 194 Class => 'My class' # (optional) 195 RW => 1, # (optional) Allow editing. Default 0. 196 Item => [ # (optional) XML parsed item 197 { 198 'ValueType' => 'Date', 199 'Content' => '2016-02-02', 200 'ValueRegex' => '', 201 }, 202 ], 203 IsArray => 1, # (optional) Item is part of the array 204 IsHash => 1, # (optional) Item is part of the hash 205 IDSuffix => 1, # (optional) Suffix will be added to the element ID 206 SkipEffectiveValueCheck => 1, # (optional) If enabled, system will not perform effective value check. 207 # Default: 1. 208 UserID => 1, # (required) UserID 209 ); 210 211Returns: 212 213 $SettingHTML = '<div class "Field"...</div>'; 214 215=cut 216 217sub SettingRender { 218 my ( $Self, %Param ) = @_; 219 220 for my $Needed (qw(Name UserID)) { 221 if ( !defined $Param{$Needed} ) { 222 $Kernel::OM->Get('Kernel::System::Log')->Log( 223 Priority => 'error', 224 Message => "Need $Needed", 225 ); 226 return; 227 } 228 } 229 230 $Param{Class} //= ''; 231 $Param{Class} .= ' Date'; 232 $Param{DefaultValue} //= ''; 233 234 my $IDSuffix = $Param{IDSuffix} || ''; 235 236 my $LanguageObject = $Kernel::OM->Get('Kernel::Language'); 237 238 my $EffectiveValue = $Param{EffectiveValue}; 239 if ( 240 !defined $EffectiveValue 241 && $Param{Item} 242 && $Param{Item}->[0]->{Content} 243 ) 244 { 245 $EffectiveValue = $Param{Item}->[0]->{Content}; 246 } 247 248 my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); 249 250 # Check if there is Datepicker before we add it. 251 my $HasDatepicker = $LayoutObject->{HasDatepicker}; 252 253 my $Name = $Param{Name} . $IDSuffix; 254 255 my %EffectiveValueCheck = ( 256 Success => 1, 257 ); 258 259 if ( !$Param{SkipEffectiveValueCheck} ) { 260 %EffectiveValueCheck = $Self->SettingEffectiveValueCheck( 261 EffectiveValue => $EffectiveValue, 262 XMLContentParsed => { 263 Value => [ 264 { 265 Item => $Param{Item}, 266 }, 267 ], 268 }, 269 UserID => $Param{UserID}, 270 ); 271 } 272 273 my $TimeZone = $Kernel::OM->Get('Kernel::Config')->Get("OTRSTimeZone"); 274 275 my $DateTimeObject = $Kernel::OM->Create( 276 'Kernel::System::DateTime', 277 ObjectParams => { 278 String => $EffectiveValue, 279 TimeZone => $TimeZone, 280 }, 281 ); 282 283 my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences( 284 UserID => $Param{UserID}, 285 ); 286 287 if ( $Preferences{UserTimeZone} ) { 288 my $Success = $DateTimeObject->ToTimeZone( 289 TimeZone => $Preferences{UserTimeZone}, 290 ); 291 292 $TimeZone = $Preferences{UserTimeZone}; 293 294 if ( !$Success ) { 295 $Kernel::OM->Get('Kernel::System::Log')->Log( 296 Priority => 'error', 297 Message => "System was not able to calculate DateTime in user timezone!" 298 ); 299 } 300 } 301 302 my @Date = split m{-|\s|:}, $DateTimeObject->ToString(); 303 304 my $HTML = "<div class='SettingContent'>\n"; 305 $HTML .= $LayoutObject->BuildDateSelection( 306 Prefix => $Name, 307 $Name . "Class" => $Param{Class}, 308 $Name . "Year" => $Date[0], 309 $Name . "Month" => $Date[1], 310 $Name . "Day" => $Date[2], 311 YearDiff => 10, 312 Format => 'DateInputFormat', 313 Validate => 1, 314 Disabled => $Param{RW} ? 0 : 1, 315 OverrideTimeZone => 1, 316 ); 317 318 my $TimeZoneText = $Kernel::OM->Get('Kernel::Language')->Translate("Time Zone"); 319 $HTML .= "<span class='TimeZoneText'>$TimeZoneText: $TimeZone</span>\n"; 320 321 if ( !$EffectiveValueCheck{Success} ) { 322 my $Message = $LanguageObject->Translate("Value is not correct! Please, consider updating this field."); 323 324 $HTML .= $Param{IsValid} ? "<div class='BadEffectiveValue'>\n" : "<div>\n"; 325 $HTML .= "<p>* $Message</p>\n"; 326 $HTML .= "</div>\n"; 327 } 328 329 $HTML .= "</div>\n"; 330 331 if ( !$Param{IsArray} && !$Param{IsHash} ) { 332 my $DefaultText = $LanguageObject->Translate('Default'); 333 334 $HTML .= <<"EOF"; 335 <div class=\"WidgetMessage Bottom\"> 336 $DefaultText: $Param{DefaultValue} 337 </div> 338EOF 339 } 340 341 if ( $Param{IsAjax} && $LayoutObject->{_JSOnDocumentComplete} && $Param{RW} ) { 342 for my $JS ( @{ $LayoutObject->{_JSOnDocumentComplete} } ) { 343 $HTML .= "<script>$JS</script>"; 344 } 345 } 346 347 if ( $Param{IsAjax} ) { 348 349 # Remove JS generated in BuildDateSelection() call (setting is disabled or it's already sent together with HTML). 350 # It also prevents multiple Datepicker initializations (if there are several on the page). 351 pop @{ $LayoutObject->{_JSOnDocumentComplete} }; 352 353 if ( !$HasDatepicker ) { 354 my $VacationDays = $LayoutObject->DatepickerGetVacationDays(); 355 my $TextDirection = $LanguageObject->{TextDirection} || ''; 356 357 my $JSONString = $Kernel::OM->Get('Kernel::System::JSON')->Encode( 358 Data => { 359 VacationDays => $VacationDays, 360 IsRTL => ( $TextDirection eq 'rtl' ) ? 1 : 0, 361 }, 362 ); 363 364 $HTML .= "<script> 365 Core.Config.Set('Datepicker', $JSONString); 366 </script>"; 367 368 # If there are several DateTime settings, don't run this block again. 369 $LayoutObject->{HasDatepicker} = 1; 370 } 371 } 372 373 return $HTML; 374} 375 376=head2 AddItem() 377 378Generate HTML for new array/hash item. 379 380 my $HTML = $ValueTypeObject->AddItem( 381 Name => 'SettingName', (required) Name 382 DefaultItem => { (optional) DefaultItem hash, if available 383 Content => '2017-01-01', 384 ValueType => 'Date', 385 }, 386 IDSuffix => '_Array1', (optional) IDSuffix is needed for arrays and hashes. 387 ); 388 389Returns: 390 391 $HTML = '<select class="Validate_DateMonth Date" id="SettingName_Array1Month" ...'; 392 393=cut 394 395sub AddItem { 396 my ( $Self, %Param ) = @_; 397 398 # Check needed stuff. 399 for my $Needed (qw(Name)) { 400 if ( !$Param{$Needed} ) { 401 $Kernel::OM->Get('Kernel::System::Log')->Log( 402 Priority => 'error', 403 Message => "Need $Needed!", 404 ); 405 return; 406 } 407 } 408 409 my $IDSuffix = $Param{IDSuffix} || ''; 410 my $Class = $Param{Class} || ''; 411 $Class .= ' Date Entry'; 412 413 my $Name = $Param{Name} . $IDSuffix; 414 415 my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); 416 my $TimeZone = $Kernel::OM->Get('Kernel::Config')->Get("OTRSTimeZone"); 417 418 my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences( 419 UserID => $Param{UserID}, 420 ); 421 422 my $DefaultValue; 423 if ( $Param{DefaultItem} ) { 424 my $DateTimeObject = $Kernel::OM->Create( 425 'Kernel::System::DateTime', 426 ObjectParams => { 427 String => $Param{DefaultItem}->{Content}, 428 TimeZone => $TimeZone, 429 }, 430 ); 431 432 if ( $Preferences{UserTimeZone} ) { 433 my $Success = $DateTimeObject->ToTimeZone( 434 TimeZone => $Preferences{UserTimeZone}, 435 ); 436 437 if ( !$Success ) { 438 $Kernel::OM->Get('Kernel::System::Log')->Log( 439 Priority => 'error', 440 Message => "System was not able to calculate DateTime in user timezone!" 441 ); 442 } 443 } 444 445 $DefaultValue = $DateTimeObject->ToString(); 446 } 447 448 if ( $Preferences{UserTimeZone} ) { 449 $TimeZone = $Preferences{UserTimeZone}; 450 } 451 452 my $Result; 453 454 if ($DefaultValue) { 455 my @Date = split m{-|\s|:}, $DefaultValue; 456 457 $Result = $LayoutObject->BuildDateSelection( 458 Prefix => $Name, 459 $Name . "Year" => $Date[0], 460 $Name . "Month" => $Date[1], 461 $Name . "Day" => $Date[2], 462 $Name . "Class" => $Class, 463 YearDiff => 10, 464 Format => 'DateInputFormat', 465 Validate => 1, 466 OverrideTimeZone => 1, 467 ); 468 } 469 else { 470 $Result = $LayoutObject->BuildDateSelection( 471 Prefix => $Name, 472 $Name . "Class" => $Class, 473 YearDiff => 10, 474 Format => 'DateInputFormat', 475 Validate => 1, 476 OverrideTimeZone => 1, 477 ); 478 } 479 480 my $TimeZoneText = $Kernel::OM->Get('Kernel::Language')->Translate("Time Zone"); 481 $Result .= "<span class='TimeZoneText'>$TimeZoneText: $TimeZone</span>\n"; 482 483 for my $JS ( @{ $LayoutObject->{_JSOnDocumentComplete} } ) { 484 $Result .= "<script>$JS</script>"; 485 } 486 487 return $Result; 488} 489 4901; 491 492=head1 TERMS AND CONDITIONS 493 494This software is part of the OTRS project (L<https://otrs.org/>). 495 496This software comes with ABSOLUTELY NO WARRANTY. For details, see 497the enclosed file COPYING for license information (GPL). If you 498did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>. 499 500=cut 501