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 9package Kernel::System::State; 10 11use strict; 12use warnings; 13 14our @ObjectDependencies = ( 15 'Kernel::Config', 16 'Kernel::System::Cache', 17 'Kernel::System::DB', 18 'Kernel::System::Log', 19 'Kernel::System::SysConfig', 20 'Kernel::System::Valid', 21); 22 23=head1 NAME 24 25Kernel::System::State - state lib 26 27=head1 DESCRIPTION 28 29All ticket state functions. 30 31=head1 PUBLIC INTERFACE 32 33=head2 new() 34 35create an object 36 37 my $StateObject = $Kernel::OM->Get('Kernel::System::State'); 38 39=cut 40 41sub new { 42 my ( $Type, %Param ) = @_; 43 44 # allocate new hash for object 45 my $Self = {}; 46 bless( $Self, $Type ); 47 48 $Self->{CacheType} = 'State'; 49 $Self->{CacheTTL} = 60 * 60 * 24 * 20; 50 51 return $Self; 52} 53 54=head2 StateAdd() 55 56add new states 57 58 my $ID = $StateObject->StateAdd( 59 Name => 'New State', 60 Comment => 'some comment', 61 ValidID => 1, 62 TypeID => 1, 63 UserID => 123, 64 ); 65 66=cut 67 68sub StateAdd { 69 my ( $Self, %Param ) = @_; 70 71 # check needed stuff 72 for (qw(Name ValidID TypeID UserID)) { 73 if ( !$Param{$_} ) { 74 $Kernel::OM->Get('Kernel::System::Log')->Log( 75 Priority => 'error', 76 Message => "Need $_!" 77 ); 78 return; 79 } 80 } 81 82 # get database object 83 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 84 85 # store data 86 return if !$DBObject->Do( 87 SQL => 'INSERT INTO ticket_state (name, valid_id, type_id, comments,' 88 . ' create_time, create_by, change_time, change_by)' 89 . ' VALUES (?, ?, ?, ?, current_timestamp, ?, current_timestamp, ?)', 90 Bind => [ 91 \$Param{Name}, \$Param{ValidID}, \$Param{TypeID}, \$Param{Comment}, 92 \$Param{UserID}, \$Param{UserID}, 93 ], 94 ); 95 96 # get new state id 97 return if !$DBObject->Prepare( 98 SQL => 'SELECT id FROM ticket_state WHERE name = ?', 99 Bind => [ \$Param{Name} ], 100 Limit => 1, 101 ); 102 103 # fetch the result 104 my $ID; 105 while ( my @Row = $DBObject->FetchrowArray() ) { 106 $ID = $Row[0]; 107 } 108 109 return if !$ID; 110 111 # delete cache 112 $Kernel::OM->Get('Kernel::System::Cache')->CleanUp( 113 Type => $Self->{CacheType}, 114 ); 115 116 return $ID; 117} 118 119=head2 StateGet() 120 121get state attributes 122 123 my %State = $StateObject->StateGet( 124 Name => 'New State', 125 ); 126 127 my %State = $StateObject->StateGet( 128 ID => 123, 129 ); 130 131returns 132 133 my %State = ( 134 Name => "new", 135 ID => 1, 136 TypeName => "new", 137 TypeID => 1, 138 ValidID => 1, 139 CreateTime => "2010-11-29 11:04:04", 140 ChangeTime => "2010-11-29 11:04:04", 141 Comment => "New ticket created by customer.", 142 ); 143 144=cut 145 146sub StateGet { 147 my ( $Self, %Param ) = @_; 148 149 # check needed stuff 150 if ( !$Param{ID} && !$Param{Name} ) { 151 $Kernel::OM->Get('Kernel::System::Log')->Log( 152 Priority => 'error', 153 Message => "Need ID or Name!" 154 ); 155 return; 156 } 157 158 # check cache 159 my $CacheKey; 160 if ( $Param{Name} ) { 161 $CacheKey = 'StateGet::Name::' . $Param{Name}; 162 } 163 else { 164 $CacheKey = 'StateGet::ID::' . $Param{ID}; 165 } 166 my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get( 167 Type => $Self->{CacheType}, 168 Key => $CacheKey, 169 ); 170 return %{$Cache} if $Cache; 171 172 # get database object 173 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 174 175 # sql 176 my @Bind; 177 my $SQL = 'SELECT ts.id, ts.name, ts.valid_id, ts.comments, ts.type_id, tst.name,' 178 . ' ts.change_time, ts.create_time' 179 . ' FROM ticket_state ts, ticket_state_type tst WHERE ts.type_id = tst.id AND '; 180 if ( $Param{Name} ) { 181 $SQL .= ' ts.name = ?'; 182 push @Bind, \$Param{Name}; 183 } 184 else { 185 $SQL .= ' ts.id = ?'; 186 push @Bind, \$Param{ID}; 187 } 188 189 return if !$DBObject->Prepare( 190 SQL => $SQL, 191 Bind => \@Bind, 192 Limit => 1, 193 ); 194 195 # fetch the result 196 my %Data; 197 while ( my @Data = $DBObject->FetchrowArray() ) { 198 %Data = ( 199 ID => $Data[0], 200 Name => $Data[1], 201 Comment => $Data[3], 202 ValidID => $Data[2], 203 TypeID => $Data[4], 204 TypeName => $Data[5], 205 ChangeTime => $Data[6], 206 CreateTime => $Data[7], 207 ); 208 } 209 210 # set cache 211 $Kernel::OM->Get('Kernel::System::Cache')->Set( 212 Type => $Self->{CacheType}, 213 TTL => $Self->{CacheTTL}, 214 Key => $CacheKey, 215 Value => \%Data, 216 ); 217 218 # no data found... 219 if ( !%Data ) { 220 my $Error = $Param{Name} ? "State '$Param{Name}'" : "StateID '$Param{ID}'"; 221 $Kernel::OM->Get('Kernel::System::Log')->Log( 222 Priority => 'error', 223 Message => $Error . " not found!", 224 ); 225 return; 226 } 227 228 return %Data; 229} 230 231=head2 StateUpdate() 232 233update state attributes 234 235 $StateObject->StateUpdate( 236 ID => 123, 237 Name => 'New State', 238 Comment => 'some comment', 239 ValidID => 1, 240 TypeID => 1, 241 UserID => 123, 242 ); 243 244=cut 245 246sub StateUpdate { 247 my ( $Self, %Param ) = @_; 248 249 # check needed stuff 250 for (qw(ID Name ValidID TypeID UserID)) { 251 if ( !$Param{$_} ) { 252 $Kernel::OM->Get('Kernel::System::Log')->Log( 253 Priority => 'error', 254 Message => "Need $_!" 255 ); 256 return; 257 } 258 } 259 260 # get database object 261 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 262 263 # sql 264 return if !$DBObject->Do( 265 SQL => 'UPDATE ticket_state SET name = ?, comments = ?, type_id = ?, ' 266 . ' valid_id = ?, change_time = current_timestamp, change_by = ? ' 267 . ' WHERE id = ?', 268 Bind => [ 269 \$Param{Name}, \$Param{Comment}, \$Param{TypeID}, \$Param{ValidID}, 270 \$Param{UserID}, \$Param{ID}, 271 ], 272 ); 273 274 # delete cache 275 $Kernel::OM->Get('Kernel::System::Cache')->CleanUp( 276 Type => $Self->{CacheType}, 277 ); 278 279 return 1; 280} 281 282=head2 StateGetStatesByType() 283 284get list of states for a type or a list of state types. 285 286Get all states with state type open and new: 287(available: new, open, closed, pending reminder, pending auto, removed, merged) 288 289 my @List = $StateObject->StateGetStatesByType( 290 StateType => ['open', 'new'], 291 Result => 'ID', # HASH|ID|Name 292 ); 293 294Get all state types used by config option named like 295Ticket::ViewableStateType for "Viewable" state types. 296 297 my %List = $StateObject->StateGetStatesByType( 298 Type => 'Viewable', 299 Result => 'HASH', # HASH|ID|Name 300 ); 301 302=cut 303 304sub StateGetStatesByType { 305 my ( $Self, %Param ) = @_; 306 307 # check needed stuff 308 if ( !$Param{Result} ) { 309 $Kernel::OM->Get('Kernel::System::Log')->Log( 310 Priority => 'error', 311 Message => 'Need Result!' 312 ); 313 return; 314 } 315 316 if ( !$Param{Type} && !$Param{StateType} ) { 317 $Kernel::OM->Get('Kernel::System::Log')->Log( 318 Priority => 'error', 319 Message => 'Need Type or StateType!' 320 ); 321 return; 322 } 323 324 # cache key 325 my $CacheKey = 'StateGetStatesByType::'; 326 if ( $Param{Type} ) { 327 $CacheKey .= 'Type::' . $Param{Type}; 328 } 329 if ( $Param{StateType} ) { 330 331 my @StateType; 332 if ( ref $Param{StateType} eq 'ARRAY' ) { 333 @StateType = @{ $Param{StateType} }; 334 } 335 else { 336 push @StateType, $Param{StateType}; 337 } 338 $CacheKey .= 'StateType::' . join ':', sort @StateType; 339 } 340 341 # check cache 342 my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get( 343 Type => $Self->{CacheType}, 344 Key => $CacheKey, 345 ); 346 if ($Cache) { 347 if ( $Param{Result} eq 'Name' ) { 348 return @{ $Cache->{Name} }; 349 } 350 elsif ( $Param{Result} eq 'HASH' ) { 351 return %{ $Cache->{HASH} }; 352 } 353 return @{ $Cache->{ID} }; 354 } 355 356 # sql 357 my @StateType; 358 my @Name; 359 my @ID; 360 my %Data; 361 if ( $Param{Type} ) { 362 363 # get config object 364 my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); 365 366 if ( $ConfigObject->Get( 'Ticket::' . $Param{Type} . 'StateType' ) ) { 367 @StateType = @{ $ConfigObject->Get( 'Ticket::' . $Param{Type} . 'StateType' ) }; 368 } 369 else { 370 $Kernel::OM->Get('Kernel::System::Log')->Log( 371 Priority => 'error', 372 Message => "Type 'Ticket::$Param{Type}StateType' not found in Kernel/Config.pm!", 373 ); 374 die; 375 } 376 } 377 else { 378 if ( ref $Param{StateType} eq 'ARRAY' ) { 379 @StateType = @{ $Param{StateType} }; 380 } 381 else { 382 push @StateType, $Param{StateType}; 383 } 384 } 385 386 # get database object 387 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 388 389 @StateType = map { $DBObject->Quote($_) } @StateType; 390 391 my $SQL = '' 392 . 'SELECT ts.id, ts.name, tst.name' 393 . ' FROM ticket_state ts, ticket_state_type tst' 394 . ' WHERE tst.id = ts.type_id' 395 . " AND tst.name IN ('${\(join '\', \'', sort @StateType)}' )" 396 . " AND ts.valid_id IN ( ${\(join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet())} )"; 397 398 return if !$DBObject->Prepare( SQL => $SQL ); 399 400 # fetch the result 401 while ( my @Data = $DBObject->FetchrowArray() ) { 402 push @Name, $Data[1]; 403 push @ID, $Data[0]; 404 $Data{ $Data[0] } = $Data[1]; 405 } 406 407 # set runtime cache 408 my $All = { 409 Name => \@Name, 410 ID => \@ID, 411 HASH => \%Data, 412 }; 413 414 # set permanent cache 415 $Kernel::OM->Get('Kernel::System::Cache')->Set( 416 Type => $Self->{CacheType}, 417 TTL => $Self->{CacheTTL}, 418 Key => $CacheKey, 419 Value => $All, 420 ); 421 422 if ( $Param{Result} eq 'Name' ) { 423 return @Name; 424 } 425 elsif ( $Param{Result} eq 'HASH' ) { 426 return %Data; 427 } 428 429 return @ID; 430} 431 432=head2 StateList() 433 434get state list as a hash of ID, Name pairs 435 436 my %List = $StateObject->StateList( 437 UserID => 123, 438 ); 439 440 my %List = $StateObject->StateList( 441 UserID => 123, 442 Valid => 1, # is default 443 ); 444 445 my %List = $StateObject->StateList( 446 UserID => 123, 447 Valid => 0, 448 ); 449 450returns 451 452 my %List = ( 453 1 => "new", 454 2 => "closed successful", 455 3 => "closed unsuccessful", 456 4 => "open", 457 5 => "removed", 458 6 => "pending reminder", 459 7 => "pending auto close+", 460 8 => "pending auto close-", 461 9 => "merged", 462 ); 463 464=cut 465 466sub StateList { 467 my ( $Self, %Param ) = @_; 468 469 # check needed stuff 470 if ( !$Param{UserID} ) { 471 $Kernel::OM->Get('Kernel::System::Log')->Log( 472 Priority => 'error', 473 Message => 'UserID!' 474 ); 475 return; 476 } 477 478 my $Valid = 1; 479 if ( !$Param{Valid} && defined( $Param{Valid} ) ) { 480 $Valid = 0; 481 } 482 483 # check cache 484 my $CacheKey = 'StateList::' . $Valid; 485 my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get( 486 Type => $Self->{CacheType}, 487 Key => $CacheKey, 488 ); 489 return %{$Cache} if $Cache; 490 491 # sql 492 my $SQL = 'SELECT id, name FROM ticket_state'; 493 if ($Valid) { 494 $SQL 495 .= " WHERE valid_id IN ( ${\(join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet())} )"; 496 } 497 498 # get database object 499 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 500 501 return if !$DBObject->Prepare( SQL => $SQL ); 502 503 # fetch the result 504 my %Data; 505 while ( my @Row = $DBObject->FetchrowArray() ) { 506 $Data{ $Row[0] } = $Row[1]; 507 } 508 509 # set cache 510 $Kernel::OM->Get('Kernel::System::Cache')->Set( 511 Type => $Self->{CacheType}, 512 TTL => $Self->{CacheTTL}, 513 Key => $CacheKey, 514 Value => \%Data, 515 ); 516 517 return %Data; 518} 519 520=head2 StateLookup() 521 522returns the id or the name of a state 523 524 my $StateID = $StateObject->StateLookup( 525 State => 'closed successful', 526 ); 527 528 my $State = $StateObject->StateLookup( 529 StateID => 2, 530 ); 531 532=cut 533 534sub StateLookup { 535 my ( $Self, %Param ) = @_; 536 537 # check needed stuff 538 if ( !$Param{State} && !$Param{StateID} ) { 539 $Kernel::OM->Get('Kernel::System::Log')->Log( 540 Priority => 'error', 541 Message => 'Need State or StateID!' 542 ); 543 return; 544 } 545 546 # get (already cached) state list 547 my %StateList = $Self->StateList( 548 Valid => 0, 549 UserID => 1, 550 ); 551 552 my $Key; 553 my $Value; 554 my $ReturnData; 555 if ( $Param{StateID} ) { 556 $Key = 'StateID'; 557 $Value = $Param{StateID}; 558 $ReturnData = $StateList{ $Param{StateID} }; 559 } 560 else { 561 $Key = 'State'; 562 $Value = $Param{State}; 563 my %StateListReverse = reverse %StateList; 564 $ReturnData = $StateListReverse{ $Param{State} }; 565 } 566 567 # check if data exists 568 if ( !defined $ReturnData ) { 569 $Kernel::OM->Get('Kernel::System::Log')->Log( 570 Priority => 'error', 571 Message => "No $Key for $Value found!", 572 ); 573 return; 574 } 575 576 return $ReturnData; 577} 578 579=head2 StateTypeList() 580 581get state type list as a hash of ID, Name pairs 582 583 my %ListType = $StateObject->StateTypeList( 584 UserID => 123, 585 ); 586 587returns 588 589 my %ListType = ( 590 1 => "new", 591 2 => "open", 592 3 => "closed", 593 4 => "pending reminder", 594 5 => "pending auto", 595 6 => "removed", 596 7 => "merged", 597 ); 598 599=cut 600 601sub StateTypeList { 602 my ( $Self, %Param ) = @_; 603 604 # check needed stuff 605 if ( !$Param{UserID} ) { 606 $Kernel::OM->Get('Kernel::System::Log')->Log( 607 Priority => 'error', 608 Message => 'UserID!' 609 ); 610 return; 611 } 612 613 # check cache 614 my $CacheKey = 'StateTypeList'; 615 my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get( 616 Type => $Self->{CacheType}, 617 Key => $CacheKey, 618 ); 619 return %{$Cache} if $Cache; 620 621 # get database object 622 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 623 624 # sql 625 return if !$DBObject->Prepare( 626 SQL => 'SELECT id, name FROM ticket_state_type', 627 ); 628 629 # fetch the result 630 my %Data; 631 while ( my @Row = $DBObject->FetchrowArray() ) { 632 $Data{ $Row[0] } = $Row[1]; 633 } 634 635 # set cache 636 $Kernel::OM->Get('Kernel::System::Cache')->Set( 637 Type => $Self->{CacheType}, 638 TTL => $Self->{CacheTTL}, 639 Key => $CacheKey, 640 Value => \%Data, 641 ); 642 643 return %Data; 644} 645 646=head2 StateTypeLookup() 647 648returns the id or the name of a state type 649 650 my $StateTypeID = $StateObject->StateTypeLookup( 651 StateType => 'pending auto', 652 ); 653 654or 655 656 my $StateType = $StateObject->StateTypeLookup( 657 StateTypeID => 1, 658 ); 659 660=cut 661 662sub StateTypeLookup { 663 my ( $Self, %Param ) = @_; 664 665 # check needed stuff 666 if ( !$Param{StateType} && !$Param{StateTypeID} ) { 667 $Kernel::OM->Get('Kernel::System::Log')->Log( 668 StateType => 'error', 669 Message => 'Need StateType or StateTypeID!', 670 ); 671 return; 672 } 673 674 # get (already cached) state type list 675 my %StateTypeList = $Self->StateTypeList( 676 UserID => 1, 677 ); 678 679 my $Key; 680 my $Value; 681 my $ReturnData; 682 if ( $Param{StateTypeID} ) { 683 $Key = 'StateTypeID'; 684 $Value = $Param{StateTypeID}; 685 $ReturnData = $StateTypeList{ $Param{StateTypeID} }; 686 } 687 else { 688 $Key = 'StateType'; 689 $Value = $Param{StateType}; 690 my %StateTypeListReverse = reverse %StateTypeList; 691 $ReturnData = $StateTypeListReverse{ $Param{StateType} }; 692 } 693 694 # check if data exists 695 if ( !defined $ReturnData ) { 696 $Kernel::OM->Get('Kernel::System::Log')->Log( 697 Priority => 'error', 698 Message => "No $Key for $Value found!", 699 ); 700 return; 701 } 702 703 return $ReturnData; 704} 705 7061; 707 708=head1 TERMS AND CONDITIONS 709 710This software is part of the OTRS project (L<https://otrs.org/>). 711 712This software comes with ABSOLUTELY NO WARRANTY. For details, see 713the enclosed file COPYING for license information (GPL). If you 714did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>. 715 716=cut 717