# --
# 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::State;
use strict;
use warnings;
our @ObjectDependencies = (
'Kernel::Config',
'Kernel::System::Cache',
'Kernel::System::DB',
'Kernel::System::Log',
'Kernel::System::SysConfig',
'Kernel::System::Valid',
);
=head1 NAME
Kernel::System::State - state lib
=head1 DESCRIPTION
All ticket state functions.
=head1 PUBLIC INTERFACE
=head2 new()
create an object
my $StateObject = $Kernel::OM->Get('Kernel::System::State');
=cut
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {};
bless( $Self, $Type );
$Self->{CacheType} = 'State';
$Self->{CacheTTL} = 60 * 60 * 24 * 20;
return $Self;
}
=head2 StateAdd()
add new states
my $ID = $StateObject->StateAdd(
Name => 'New State',
Comment => 'some comment',
ValidID => 1,
TypeID => 1,
UserID => 123,
);
=cut
sub StateAdd {
my ( $Self, %Param ) = @_;
# check needed stuff
for (qw(Name ValidID TypeID UserID)) {
if ( !$Param{$_} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $_!"
);
return;
}
}
# get database object
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# store data
return if !$DBObject->Do(
SQL => 'INSERT INTO ticket_state (name, valid_id, type_id, comments,'
. ' create_time, create_by, change_time, change_by)'
. ' VALUES (?, ?, ?, ?, current_timestamp, ?, current_timestamp, ?)',
Bind => [
\$Param{Name}, \$Param{ValidID}, \$Param{TypeID}, \$Param{Comment},
\$Param{UserID}, \$Param{UserID},
],
);
# get new state id
return if !$DBObject->Prepare(
SQL => 'SELECT id FROM ticket_state WHERE name = ?',
Bind => [ \$Param{Name} ],
Limit => 1,
);
# fetch the result
my $ID;
while ( my @Row = $DBObject->FetchrowArray() ) {
$ID = $Row[0];
}
return if !$ID;
# delete cache
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
Type => $Self->{CacheType},
);
return $ID;
}
=head2 StateGet()
get state attributes
my %State = $StateObject->StateGet(
Name => 'New State',
);
my %State = $StateObject->StateGet(
ID => 123,
);
returns
my %State = (
Name => "new",
ID => 1,
TypeName => "new",
TypeID => 1,
ValidID => 1,
CreateTime => "2010-11-29 11:04:04",
ChangeTime => "2010-11-29 11:04:04",
Comment => "New ticket created by customer.",
);
=cut
sub StateGet {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{ID} && !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need ID or Name!"
);
return;
}
# check cache
my $CacheKey;
if ( $Param{Name} ) {
$CacheKey = 'StateGet::Name::' . $Param{Name};
}
else {
$CacheKey = 'StateGet::ID::' . $Param{ID};
}
my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
Type => $Self->{CacheType},
Key => $CacheKey,
);
return %{$Cache} if $Cache;
# get database object
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# sql
my @Bind;
my $SQL = 'SELECT ts.id, ts.name, ts.valid_id, ts.comments, ts.type_id, tst.name,'
. ' ts.change_time, ts.create_time'
. ' FROM ticket_state ts, ticket_state_type tst WHERE ts.type_id = tst.id AND ';
if ( $Param{Name} ) {
$SQL .= ' ts.name = ?';
push @Bind, \$Param{Name};
}
else {
$SQL .= ' ts.id = ?';
push @Bind, \$Param{ID};
}
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => \@Bind,
Limit => 1,
);
# fetch the result
my %Data;
while ( my @Data = $DBObject->FetchrowArray() ) {
%Data = (
ID => $Data[0],
Name => $Data[1],
Comment => $Data[3],
ValidID => $Data[2],
TypeID => $Data[4],
TypeName => $Data[5],
ChangeTime => $Data[6],
CreateTime => $Data[7],
);
}
# set cache
$Kernel::OM->Get('Kernel::System::Cache')->Set(
Type => $Self->{CacheType},
TTL => $Self->{CacheTTL},
Key => $CacheKey,
Value => \%Data,
);
# no data found...
if ( !%Data ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "State '$Param{Name}' not found!",
);
return;
}
return %Data;
}
=head2 StateUpdate()
update state attributes
$StateObject->StateUpdate(
ID => 123,
Name => 'New State',
Comment => 'some comment',
ValidID => 1,
TypeID => 1,
UserID => 123,
);
=cut
sub StateUpdate {
my ( $Self, %Param ) = @_;
# check needed stuff
for (qw(ID Name ValidID TypeID UserID)) {
if ( !$Param{$_} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $_!"
);
return;
}
}
# get database object
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# sql
return if !$DBObject->Do(
SQL => 'UPDATE ticket_state SET name = ?, comments = ?, type_id = ?, '
. ' valid_id = ?, change_time = current_timestamp, change_by = ? '
. ' WHERE id = ?',
Bind => [
\$Param{Name}, \$Param{Comment}, \$Param{TypeID}, \$Param{ValidID},
\$Param{UserID}, \$Param{ID},
],
);
# delete cache
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
Type => $Self->{CacheType},
);
return 1;
}
=head2 StateGetStatesByType()
get list of states for a type or a list of state types.
Get all states with state type open and new:
(available: new, open, closed, pending reminder, pending auto, removed, merged)
my @List = $StateObject->StateGetStatesByType(
StateType => ['open', 'new'],
Result => 'ID', # HASH|ID|Name
);
Get all state types used by config option named like
Ticket::ViewableStateType for "Viewable" state types.
my %List = $StateObject->StateGetStatesByType(
Type => 'Viewable',
Result => 'HASH', # HASH|ID|Name
);
=cut
sub StateGetStatesByType {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{Result} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need Result!'
);
return;
}
if ( !$Param{Type} && !$Param{StateType} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need Type or StateType!'
);
return;
}
# cache key
my $CacheKey = 'StateGetStatesByType::';
if ( $Param{Type} ) {
$CacheKey .= 'Type::' . $Param{Type};
}
if ( $Param{StateType} ) {
my @StateType;
if ( ref $Param{StateType} eq 'ARRAY' ) {
@StateType = @{ $Param{StateType} };
}
else {
push @StateType, $Param{StateType};
}
$CacheKey .= 'StateType::' . join ':', sort @StateType;
}
# check cache
my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
Type => $Self->{CacheType},
Key => $CacheKey,
);
if ($Cache) {
if ( $Param{Result} eq 'Name' ) {
return @{ $Cache->{Name} };
}
elsif ( $Param{Result} eq 'HASH' ) {
return %{ $Cache->{HASH} };
}
return @{ $Cache->{ID} };
}
# sql
my @StateType;
my @Name;
my @ID;
my %Data;
if ( $Param{Type} ) {
# get config object
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
if ( $ConfigObject->Get( 'Ticket::' . $Param{Type} . 'StateType' ) ) {
@StateType = @{ $ConfigObject->Get( 'Ticket::' . $Param{Type} . 'StateType' ) };
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Type 'Ticket::$Param{Type}StateType' not found in Kernel/Config.pm!",
);
die;
}
}
else {
if ( ref $Param{StateType} eq 'ARRAY' ) {
@StateType = @{ $Param{StateType} };
}
else {
push @StateType, $Param{StateType};
}
}
# get database object
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
@StateType = map { $DBObject->Quote($_) } @StateType;
my $SQL = ''
. 'SELECT ts.id, ts.name, tst.name'
. ' FROM ticket_state ts, ticket_state_type tst'
. ' WHERE tst.id = ts.type_id'
. " AND tst.name IN ('${\(join '\', \'', sort @StateType)}' )"
. " AND ts.valid_id IN ( ${\(join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet())} )";
return if !$DBObject->Prepare( SQL => $SQL );
# fetch the result
while ( my @Data = $DBObject->FetchrowArray() ) {
push @Name, $Data[1];
push @ID, $Data[0];
$Data{ $Data[0] } = $Data[1];
}
# set runtime cache
my $All = {
Name => \@Name,
ID => \@ID,
HASH => \%Data,
};
# set permanent cache
$Kernel::OM->Get('Kernel::System::Cache')->Set(
Type => $Self->{CacheType},
TTL => $Self->{CacheTTL},
Key => $CacheKey,
Value => $All,
);
if ( $Param{Result} eq 'Name' ) {
return @Name;
}
elsif ( $Param{Result} eq 'HASH' ) {
return %Data;
}
return @ID;
}
=head2 StateList()
get state list as a hash of ID, Name pairs
my %List = $StateObject->StateList(
UserID => 123,
);
my %List = $StateObject->StateList(
UserID => 123,
Valid => 1, # is default
);
my %List = $StateObject->StateList(
UserID => 123,
Valid => 0,
);
returns
my %List = (
1 => "new",
2 => "closed successful",
3 => "closed unsuccessful",
4 => "open",
5 => "removed",
6 => "pending reminder",
7 => "pending auto close+",
8 => "pending auto close-",
9 => "merged",
);
=cut
sub StateList {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'UserID!'
);
return;
}
my $Valid = 1;
if ( !$Param{Valid} && defined( $Param{Valid} ) ) {
$Valid = 0;
}
# check cache
my $CacheKey = 'StateList::' . $Valid;
my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
Type => $Self->{CacheType},
Key => $CacheKey,
);
return %{$Cache} if $Cache;
# sql
my $SQL = 'SELECT id, name FROM ticket_state';
if ($Valid) {
$SQL
.= " WHERE valid_id IN ( ${\(join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet())} )";
}
# get database object
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
return if !$DBObject->Prepare( SQL => $SQL );
# fetch the result
my %Data;
while ( my @Row = $DBObject->FetchrowArray() ) {
$Data{ $Row[0] } = $Row[1];
}
# set cache
$Kernel::OM->Get('Kernel::System::Cache')->Set(
Type => $Self->{CacheType},
TTL => $Self->{CacheTTL},
Key => $CacheKey,
Value => \%Data,
);
return %Data;
}
=head2 StateLookup()
returns the id or the name of a state
my $StateID = $StateObject->StateLookup(
State => 'closed successful',
);
my $State = $StateObject->StateLookup(
StateID => 2,
);
=cut
sub StateLookup {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{State} && !$Param{StateID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need State or StateID!'
);
return;
}
# get (already cached) state list
my %StateList = $Self->StateList(
Valid => 0,
UserID => 1,
);
my $Key;
my $Value;
my $ReturnData;
if ( $Param{StateID} ) {
$Key = 'StateID';
$Value = $Param{StateID};
$ReturnData = $StateList{ $Param{StateID} };
}
else {
$Key = 'State';
$Value = $Param{State};
my %StateListReverse = reverse %StateList;
$ReturnData = $StateListReverse{ $Param{State} };
}
# check if data exists
if ( !defined $ReturnData ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "No $Key for $Value found!",
);
return;
}
return $ReturnData;
}
=head2 StateTypeList()
get state type list as a hash of ID, Name pairs
my %ListType = $StateObject->StateTypeList(
UserID => 123,
);
returns
my %ListType = (
1 => "new",
2 => "open",
3 => "closed",
4 => "pending reminder",
5 => "pending auto",
6 => "removed",
7 => "merged",
);
=cut
sub StateTypeList {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'UserID!'
);
return;
}
# check cache
my $CacheKey = 'StateTypeList';
my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
Type => $Self->{CacheType},
Key => $CacheKey,
);
return %{$Cache} if $Cache;
# get database object
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# sql
return if !$DBObject->Prepare(
SQL => 'SELECT id, name FROM ticket_state_type',
);
# fetch the result
my %Data;
while ( my @Row = $DBObject->FetchrowArray() ) {
$Data{ $Row[0] } = $Row[1];
}
# set cache
$Kernel::OM->Get('Kernel::System::Cache')->Set(
Type => $Self->{CacheType},
TTL => $Self->{CacheTTL},
Key => $CacheKey,
Value => \%Data,
);
return %Data;
}
=head2 StateTypeLookup()
returns the id or the name of a state type
my $StateTypeID = $StateObject->StateTypeLookup(
StateType => 'pending auto',
);
or
my $StateType = $StateObject->StateTypeLookup(
StateTypeID => 1,
);
=cut
sub StateTypeLookup {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{StateType} && !$Param{StateTypeID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
StateType => 'error',
Message => 'Need StateType or StateTypeID!',
);
return;
}
# get (already cached) state type list
my %StateTypeList = $Self->StateTypeList(
UserID => 1,
);
my $Key;
my $Value;
my $ReturnData;
if ( $Param{StateTypeID} ) {
$Key = 'StateTypeID';
$Value = $Param{StateTypeID};
$ReturnData = $StateTypeList{ $Param{StateTypeID} };
}
else {
$Key = 'StateType';
$Value = $Param{StateType};
my %StateTypeListReverse = reverse %StateTypeList;
$ReturnData = $StateTypeListReverse{ $Param{StateType} };
}
# check if data exists
if ( !defined $ReturnData ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "No $Key for $Value found!",
);
return;
}
return $ReturnData;
}
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