2198 lines
69 KiB
Perl
2198 lines
69 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::ProcessManagement::DB::Process;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Kernel::System::ProcessManagement::DB::Entity;
|
|
use Kernel::System::ProcessManagement::DB::Activity;
|
|
use Kernel::System::ProcessManagement::DB::ActivityDialog;
|
|
use Kernel::System::ProcessManagement::DB::Process::State;
|
|
use Kernel::System::ProcessManagement::DB::Transition;
|
|
use Kernel::System::ProcessManagement::DB::TransitionAction;
|
|
|
|
use Kernel::System::VariableCheck qw(:all);
|
|
|
|
our @ObjectDependencies = (
|
|
'Kernel::Config',
|
|
'Kernel::Language',
|
|
'Kernel::System::Cache',
|
|
'Kernel::System::DB',
|
|
'Kernel::System::DynamicField',
|
|
'Kernel::System::Log',
|
|
'Kernel::System::Main',
|
|
'Kernel::System::User',
|
|
'Kernel::System::YAML',
|
|
);
|
|
|
|
=head1 NAME
|
|
|
|
Kernel::System::ProcessManagement::DB::Process
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
Process Management DB Process backend
|
|
|
|
=head1 PUBLIC INTERFACE
|
|
|
|
=head2 new()
|
|
|
|
Don't use the constructor directly, use the ObjectManager instead:
|
|
|
|
my $ProcessObject = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Process');
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my ( $Type, %Param ) = @_;
|
|
|
|
# allocate new hash for object
|
|
my $Self = {};
|
|
bless( $Self, $Type );
|
|
|
|
$Self->{EntityObject} = Kernel::System::ProcessManagement::DB::Entity->new();
|
|
$Self->{ActivityDialogObject} = Kernel::System::ProcessManagement::DB::ActivityDialog->new();
|
|
$Self->{ActivityObject} = Kernel::System::ProcessManagement::DB::Activity->new();
|
|
$Self->{StateObject} = Kernel::System::ProcessManagement::DB::Process::State->new();
|
|
$Self->{TransitionObject} = Kernel::System::ProcessManagement::DB::Transition->new();
|
|
$Self->{TransitionActionObject} = Kernel::System::ProcessManagement::DB::TransitionAction->new();
|
|
|
|
# get the cache TTL (in seconds)
|
|
$Self->{CacheTTL} = int( $Kernel::OM->Get('Kernel::Config')->Get('Process::CacheTTL') || 3600 );
|
|
|
|
# set lower if database is case sensitive
|
|
$Self->{Lower} = '';
|
|
if ( $Kernel::OM->Get('Kernel::System::DB')->GetDatabaseFunction('CaseSensitive') ) {
|
|
$Self->{Lower} = 'LOWER';
|
|
}
|
|
|
|
return $Self;
|
|
}
|
|
|
|
=head2 ProcessAdd()
|
|
|
|
add new Process
|
|
|
|
returns the id of the created process if success or undef otherwise
|
|
|
|
my $ID = $ProcessObject->ProcessAdd(
|
|
EntityID => 'P1' # mandatory, exportable unique identifier
|
|
Name => 'NameOfProcess', # mandatory
|
|
StateEntityID => 'S1',
|
|
Layout => $LayoutHashRef, # mandatory, diagram objects positions to be stored in
|
|
# YAML format
|
|
Config => $ConfigHashRef, # mandatory, process configuration to be stored in YAML
|
|
# format
|
|
UserID => 123, # mandatory
|
|
);
|
|
|
|
Returns:
|
|
|
|
$ID = 567;
|
|
|
|
=cut
|
|
|
|
sub ProcessAdd {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Key (qw(EntityID Name StateEntityID Layout Config UserID)) {
|
|
if ( !$Param{$Key} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Key!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# check if EntityID already exists
|
|
return if !$DBObject->Prepare(
|
|
SQL => "
|
|
SELECT id
|
|
FROM pm_process
|
|
WHERE $Self->{Lower}(entity_id) = $Self->{Lower}(?)",
|
|
Bind => [ \$Param{EntityID} ],
|
|
Limit => 1,
|
|
);
|
|
|
|
my $EntityExists;
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
$EntityExists = 1;
|
|
}
|
|
|
|
if ($EntityExists) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "The EntityID:$Param{EntityID} already exists for a process!"
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check config valid format (at least it must contain the description)
|
|
if ( !IsHashRefWithData( $Param{Config} ) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Config needs to be a valid Hash reference!",
|
|
);
|
|
return;
|
|
}
|
|
if ( !$Param{Config}->{Description} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need Description in Config!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get yaml object
|
|
my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML');
|
|
|
|
# dump layout and config as string
|
|
my $Layout = $YAMLObject->Dump( Data => $Param{Layout} );
|
|
my $Config = $YAMLObject->Dump( Data => $Param{Config} );
|
|
|
|
# Make sure the resulting string has the UTF-8 flag. YAML only sets it if
|
|
# part of the data already had it.
|
|
utf8::upgrade($Layout);
|
|
utf8::upgrade($Config);
|
|
|
|
# SQL
|
|
return if !$DBObject->Do(
|
|
SQL => '
|
|
INSERT INTO pm_process ( entity_id, name, state_entity_id, layout, config, create_time,
|
|
create_by, change_time, change_by )
|
|
VALUES (?, ?, ?, ?, ?, current_timestamp, ?, current_timestamp, ?)',
|
|
Bind => [
|
|
\$Param{EntityID}, \$Param{Name}, \$Param{StateEntityID}, \$Layout, \$Config,
|
|
\$Param{UserID}, \$Param{UserID},
|
|
],
|
|
);
|
|
|
|
return if !$DBObject->Prepare(
|
|
SQL => 'SELECT id FROM pm_process WHERE entity_id = ?',
|
|
Bind => [ \$Param{EntityID} ],
|
|
);
|
|
|
|
my $ID;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
$ID = $Row[0];
|
|
}
|
|
|
|
# delete cache
|
|
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
|
|
Type => 'ProcessManagement_Process',
|
|
);
|
|
|
|
return if !$ID;
|
|
|
|
return $ID;
|
|
}
|
|
|
|
=head2 ProcessDelete()
|
|
|
|
delete a Process
|
|
|
|
returns 1 if success or undef otherwise
|
|
|
|
my $Success = $ProcessObject->ProcessDelete(
|
|
ID => 123,
|
|
UserID => 123,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ProcessDelete {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Key (qw(ID UserID)) {
|
|
if ( !$Param{$Key} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Key!"
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# check if exists
|
|
my $Process = $Self->ProcessGet(
|
|
ID => $Param{ID},
|
|
UserID => 1,
|
|
);
|
|
return if !IsHashRefWithData($Process);
|
|
|
|
# delete process
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'DELETE FROM pm_process WHERE id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
);
|
|
|
|
# delete cache
|
|
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
|
|
Type => 'ProcessManagement_Process',
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 ProcessGet()
|
|
|
|
get Process attributes
|
|
|
|
my $Process = $ProcessObject->ProcessGet(
|
|
ID => 123, # ID or EntityID is needed
|
|
EntityID => 'P1',
|
|
ActivityNames => 1, # default 0, 1 || 0, if 0 returns an Activities array
|
|
# with the activity entity IDs, if 1 returns an
|
|
# Activities hash with the activity entity IDs as
|
|
# keys and Activity Names as values
|
|
TransitionNames => 1, # default 0, 1 || 0, if 0 returns an Transitions array
|
|
# with the transition entity IDs, if 1 returns an
|
|
# Transitions hash with the transition entity IDs as
|
|
# keys and Transition Names as values
|
|
TransitionActionNames => 1, # default 0, 1 || 0, if 0 returns an TransitionActions array
|
|
# with the TransitionAction entity IDs, if 1 returns an
|
|
# TransitionAction hash with the TransitionAction entity IDs as
|
|
# keys and TransitionAction Names as values
|
|
UserID => 123, # mandatory
|
|
);
|
|
|
|
Returns:
|
|
|
|
$Process = {
|
|
ID => 123,
|
|
EntityID => 'P1',
|
|
Name => 'some name',
|
|
StateEntityID => 'S1',
|
|
State => 'Active',
|
|
Layout => $LayoutHashRef,
|
|
Config => $ConfigHashRef,
|
|
Activities => ['A1','A2','A3'],
|
|
Activities => ['T1','T2','T3'],
|
|
CreateTime => '2012-07-04 15:08:00',
|
|
ChangeTime => '2012-07-04 15:08:00',
|
|
};
|
|
|
|
$Process = {
|
|
ID => 123,
|
|
EntityID => 'P1',
|
|
Name => 'some name',
|
|
StateEntityID => 'S1',
|
|
State => 'Active',
|
|
Layout => $LayoutHashRef,
|
|
Config => $ConfigHashRef,
|
|
Activities => {
|
|
'A1' => 'Activity1',
|
|
'A2' => 'Activity2',
|
|
'A3' => 'Activity3',
|
|
};
|
|
Transitions => {
|
|
'T1' => 'Transition1',
|
|
'T2' => 'Transition2',
|
|
'T3' => 'Transition3',
|
|
};
|
|
TransitionActions => {
|
|
'TA1' => 'TransitionAction1',
|
|
'TA2' => 'TransitionAction2',
|
|
'TA3' => 'TransitionAction3',
|
|
};
|
|
CreateTime => '2012-07-04 15:08:00',
|
|
ChangeTime => '2012-07-04 15:08:00',
|
|
};
|
|
|
|
=cut
|
|
|
|
sub ProcessGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ID} && !$Param{EntityID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ID or EntityID!'
|
|
);
|
|
return;
|
|
}
|
|
|
|
if ( !$Param{UserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need UserID!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
my $ActivityNames = 0;
|
|
if ( defined $Param{ActivityNames} && $Param{ActivityNames} == 1 ) {
|
|
$ActivityNames = 1;
|
|
}
|
|
my $TransitionNames = 0;
|
|
if ( defined $Param{TransitionNames} && $Param{TransitionNames} == 1 ) {
|
|
$TransitionNames = 1;
|
|
}
|
|
my $TransitionActionNames = 0;
|
|
if ( defined $Param{TransitionActionNames} && $Param{TransitionActionNames} == 1 ) {
|
|
$TransitionActionNames = 1;
|
|
}
|
|
|
|
# check cache
|
|
my $CacheKey;
|
|
if ( $Param{ID} ) {
|
|
$CacheKey = 'ProcessGet::ID::' . $Param{ID} . '::ActivityNames::'
|
|
. $ActivityNames
|
|
. '::TransitionNames::'
|
|
. $TransitionNames
|
|
. '::TransitionActionNames::'
|
|
. $TransitionActionNames;
|
|
}
|
|
else {
|
|
$CacheKey = 'ProcessGet::EntityID::' . $Param{EntityID} . '::ActivityNames::'
|
|
. $ActivityNames
|
|
. '::TransitionNames::'
|
|
. $TransitionNames
|
|
. '::TransitionActionNames::'
|
|
. $TransitionActionNames;
|
|
}
|
|
|
|
# get cache object
|
|
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
|
|
|
|
my $Cache = $CacheObject->Get(
|
|
Type => 'ProcessManagement_Process',
|
|
Key => $CacheKey,
|
|
);
|
|
return $Cache if $Cache;
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# SQL
|
|
if ( $Param{ID} ) {
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT id, entity_id, name, state_entity_id, layout, config, create_time,
|
|
change_time
|
|
FROM pm_process
|
|
WHERE id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
Limit => 1,
|
|
);
|
|
}
|
|
else {
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT id, entity_id, name, state_entity_id, layout, config, create_time,
|
|
change_time
|
|
FROM pm_process
|
|
WHERE entity_id = ?',
|
|
Bind => [ \$Param{EntityID} ],
|
|
Limit => 1,
|
|
);
|
|
}
|
|
|
|
# get yaml object
|
|
my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML');
|
|
|
|
my %Data;
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
my $Layout = $YAMLObject->Load( Data => $Data[4] );
|
|
my $Config = $YAMLObject->Load( Data => $Data[5] );
|
|
|
|
%Data = (
|
|
ID => $Data[0],
|
|
EntityID => $Data[1],
|
|
Name => $Data[2],
|
|
StateEntityID => $Data[3],
|
|
Layout => $Layout,
|
|
Config => $Config,
|
|
CreateTime => $Data[6],
|
|
ChangeTime => $Data[7],
|
|
|
|
);
|
|
}
|
|
|
|
return if !$Data{ID};
|
|
|
|
# create the ActivityList
|
|
if ($ActivityNames) {
|
|
my %Activities;
|
|
|
|
if ( IsHashRefWithData( $Data{Config}->{Path} ) ) {
|
|
|
|
my $ActivityList = $Self->{ActivityObject}->ActivityList(
|
|
UseEntities => 1,
|
|
UserID => 1,
|
|
);
|
|
|
|
for my $ActivityEntityID ( sort keys %{ $Data{Config}->{Path} } ) {
|
|
$Activities{$ActivityEntityID} = $ActivityList->{$ActivityEntityID};
|
|
}
|
|
}
|
|
$Data{Activities} = \%Activities;
|
|
}
|
|
else {
|
|
my @Activities;
|
|
|
|
if ( IsHashRefWithData( $Data{Config}->{Path} ) ) {
|
|
|
|
# get path keys (ActivityEntityIDs) and map them into an array
|
|
@Activities = map {$_} sort keys %{ $Data{Config}->{Path} };
|
|
}
|
|
$Data{Activities} = \@Activities;
|
|
}
|
|
|
|
# create the transition list
|
|
if ($TransitionNames) {
|
|
|
|
my %Transitions;
|
|
if ( IsHashRefWithData( $Data{Config}->{Path} ) ) {
|
|
|
|
my $TransitionList = $Self->{TransitionObject}->TransitionList(
|
|
UseEntities => 1,
|
|
UserID => 1,
|
|
);
|
|
|
|
for my $ActivityEntityID ( sort keys %{ $Data{Config}->{Path} } ) {
|
|
for my $TransitionEntityID (
|
|
sort keys %{ $Data{Config}->{Path}->{$ActivityEntityID} }
|
|
)
|
|
{
|
|
$Transitions{$TransitionEntityID} = $TransitionList->{$TransitionEntityID};
|
|
}
|
|
}
|
|
}
|
|
$Data{Transitions} = \%Transitions;
|
|
}
|
|
else {
|
|
my @Transitions;
|
|
|
|
if ( IsHashRefWithData( $Data{Config}->{Path} ) ) {
|
|
|
|
for my $ActivityEntityID ( sort keys %{ $Data{Config}->{Path} } ) {
|
|
|
|
for my $TransitionEntityID (
|
|
sort keys %{ $Data{Config}->{Path}->{$ActivityEntityID} }
|
|
)
|
|
{
|
|
push @Transitions, $TransitionEntityID;
|
|
}
|
|
}
|
|
}
|
|
$Data{Transitions} = \@Transitions;
|
|
}
|
|
|
|
# create the transition action list
|
|
if ($TransitionActionNames) {
|
|
|
|
my %TransitionActions;
|
|
if ( IsHashRefWithData( $Data{Config}->{Path} ) ) {
|
|
|
|
my $TransitionActionList = $Self->{TransitionActionObject}->TransitionActionList(
|
|
UseEntities => 1,
|
|
UserID => 1,
|
|
);
|
|
|
|
for my $ActivityEntityID ( sort keys %{ $Data{Config}->{Path} } ) {
|
|
|
|
my $TransitionPath = $Data{Config}->{Path}->{$ActivityEntityID};
|
|
for my $TransitionEntityID ( sort keys %{$TransitionPath} ) {
|
|
|
|
my $TransitionActionPath = $Data{Config}->{Path}->{$ActivityEntityID}->{$TransitionEntityID}
|
|
->{Action};
|
|
if ( $TransitionActionPath && @{$TransitionActionPath} ) {
|
|
for my $TransitionActionEntityID ( sort @{$TransitionActionPath} ) {
|
|
$TransitionActions{$TransitionActionEntityID}
|
|
= $TransitionActionList->{$TransitionEntityID};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$Data{TransitionActions} = \%TransitionActions;
|
|
}
|
|
else {
|
|
my @TransitionActions;
|
|
|
|
if ( IsHashRefWithData( $Data{Config}->{Path} ) ) {
|
|
|
|
for my $ActivityEntityID ( sort keys %{ $Data{Config}->{Path} } ) {
|
|
|
|
my $TransitionPath = $Data{Config}->{Path}->{$ActivityEntityID};
|
|
for my $TransitionEntityID ( sort keys %{$TransitionPath} ) {
|
|
|
|
my $TransitionActionPath = $TransitionPath->{$TransitionEntityID}->{TransitionAction};
|
|
if ( $TransitionActionPath && @{$TransitionActionPath} ) {
|
|
for my $TransitionActionEntityID ( sort @{$TransitionActionPath} ) {
|
|
push @TransitionActions, $TransitionActionEntityID;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$Data{TransitionActions} = \@TransitionActions;
|
|
}
|
|
|
|
$Data{State} = $Self->{StateObject}->StateLookup(
|
|
EntityID => $Data{StateEntityID},
|
|
UserID => 1,
|
|
);
|
|
|
|
# set cache
|
|
$CacheObject->Set(
|
|
Type => 'ProcessManagement_Process',
|
|
Key => $CacheKey,
|
|
Value => \%Data,
|
|
TTL => $Self->{CacheTTL},
|
|
);
|
|
|
|
return \%Data;
|
|
}
|
|
|
|
=head2 ProcessUpdate()
|
|
|
|
update Process attributes
|
|
|
|
returns 1 if success or undef otherwise
|
|
|
|
my $Success = $ProcessObject->ProcessUpdate(
|
|
ID => 123, # mandatory
|
|
EntityID => 'P1' # mandatory, exportable unique identifier
|
|
Name => 'NameOfProcess', # mandatory
|
|
StateentityID => 'S1',
|
|
Layout => $LayoutHashRef, # mandatory, diagram objects positions to be stored in
|
|
# YAML format
|
|
Config => $ConfigHashRef, # mandatory, process configuration to be stored in YAML
|
|
# format
|
|
UserID => 123, # mandatory
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ProcessUpdate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Key (qw(ID EntityID Name StateEntityID Layout Config UserID)) {
|
|
if ( !$Param{$Key} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Key!"
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# check if EntityID already exists
|
|
return if !$DBObject->Prepare(
|
|
SQL => "
|
|
SELECT id FROM pm_process
|
|
WHERE $Self->{Lower}(entity_id) = $Self->{Lower}(?)
|
|
AND id != ?",
|
|
Bind => [ \$Param{EntityID}, \$Param{ID} ],
|
|
LIMIT => 1,
|
|
);
|
|
|
|
my $EntityExists;
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
$EntityExists = 1;
|
|
}
|
|
|
|
if ($EntityExists) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "The EntityID:$Param{Name} already exists for a process!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check config valid format (at least it must contain the description)
|
|
if ( !IsHashRefWithData( $Param{Config} ) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Config needs to be a valid Hash reference!",
|
|
);
|
|
return;
|
|
}
|
|
if ( !$Param{Config}->{Description} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need Description in Config!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get yaml object
|
|
my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML');
|
|
|
|
# dump layout and config as string
|
|
my $Layout = $YAMLObject->Dump( Data => $Param{Layout} );
|
|
my $Config = $YAMLObject->Dump( Data => $Param{Config} );
|
|
|
|
# Make sure the resulting string has the UTF-8 flag. YAML only sets it if
|
|
# part of the data already had it.
|
|
utf8::upgrade($Layout);
|
|
utf8::upgrade($Config);
|
|
|
|
# check if need to update db
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT entity_id, name, state_entity_id, layout, config
|
|
FROM pm_process
|
|
WHERE id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
Limit => 1,
|
|
);
|
|
|
|
my $CurrentEntityID;
|
|
my $CurrentName;
|
|
my $CurrentStateEntityID;
|
|
my $CurrentLayout;
|
|
my $CurrentConfig;
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
$CurrentEntityID = $Data[0];
|
|
$CurrentName = $Data[1];
|
|
$CurrentStateEntityID = $Data[2];
|
|
$CurrentLayout = $Data[3];
|
|
$CurrentConfig = $Data[4];
|
|
}
|
|
|
|
if ($CurrentEntityID) {
|
|
|
|
return 1 if $CurrentEntityID eq $Param{EntityID}
|
|
&& $CurrentName eq $Param{Name}
|
|
&& $CurrentStateEntityID eq $Param{StateEntityID}
|
|
&& $CurrentLayout eq $Layout
|
|
&& $CurrentConfig eq $Config;
|
|
}
|
|
|
|
# SQL
|
|
return if !$DBObject->Do(
|
|
SQL => '
|
|
UPDATE pm_process
|
|
SET entity_id = ?, name = ?, state_entity_id = ?, layout = ?, config = ?,
|
|
change_time = current_timestamp, change_by = ?
|
|
WHERE id = ?',
|
|
Bind => [
|
|
\$Param{EntityID}, \$Param{Name}, \$Param{StateEntityID}, \$Layout, \$Config,
|
|
\$Param{UserID}, \$Param{ID},
|
|
],
|
|
);
|
|
|
|
# delete cache
|
|
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
|
|
Type => 'ProcessManagement_Process',
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 ProcessList()
|
|
|
|
get a Process list
|
|
|
|
my $List = $ProcessObject->ProcessList(
|
|
UseEntities => 0, # default 0, 1 || 0. if 0 the return hash keys are
|
|
# the process IDs otherwise keys are the
|
|
# process entity IDs
|
|
StateEntityIDs => ['S1','S2'], # optional, to filter processes that match listed
|
|
# state entity IDs
|
|
UserID => 1,
|
|
);
|
|
|
|
Returns:
|
|
|
|
$List = {
|
|
1 => 'NameOfProcess',
|
|
}
|
|
|
|
or
|
|
|
|
$List = {
|
|
'P1' => 'NameOfProcess',
|
|
}
|
|
|
|
=cut
|
|
|
|
sub ProcessList {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed
|
|
if ( !$Param{UserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need UserID!"
|
|
);
|
|
return;
|
|
}
|
|
|
|
my $StateEntityIDsStrg;
|
|
if ( !IsArrayRefWithData( $Param{StateEntityIDs} ) ) {
|
|
$StateEntityIDsStrg = 'ALL';
|
|
}
|
|
else {
|
|
$StateEntityIDsStrg = join ',', @{ $Param{StateEntityIDs} };
|
|
}
|
|
|
|
# check cache
|
|
my $UseEntities = 0;
|
|
if ( defined $Param{UseEntities} && $Param{UseEntities} ) {
|
|
$UseEntities = 1;
|
|
}
|
|
|
|
# get cache object
|
|
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
|
|
|
|
my $CacheKey = 'ProcessList::UseEntities::' . $UseEntities . '::StateEntityIDs::'
|
|
. $StateEntityIDsStrg;
|
|
my $Cache = $CacheObject->Get(
|
|
Type => 'ProcessManagement_Process',
|
|
Key => $CacheKey,
|
|
);
|
|
return $Cache if ref $Cache;
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
my $SQL = '
|
|
SELECT id, entity_id, name
|
|
FROM pm_process ';
|
|
if ( $StateEntityIDsStrg ne 'ALL' ) {
|
|
|
|
my $StateEntityIDsStrgDB =
|
|
join ',', map { "'" . $DBObject->Quote($_) . "'" } @{ $Param{StateEntityIDs} };
|
|
|
|
$SQL .= "WHERE state_entity_id IN ($StateEntityIDsStrgDB)";
|
|
}
|
|
|
|
return if !$DBObject->Prepare( SQL => $SQL );
|
|
|
|
my %Data;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
if ( !$UseEntities ) {
|
|
$Data{ $Row[0] } = $Row[2];
|
|
}
|
|
else {
|
|
$Data{ $Row[1] } = $Row[2];
|
|
}
|
|
}
|
|
|
|
# set cache
|
|
$CacheObject->Set(
|
|
Type => 'ProcessManagement_Process',
|
|
Key => $CacheKey,
|
|
Value => \%Data,
|
|
TTL => $Self->{CacheTTL},
|
|
);
|
|
|
|
return \%Data;
|
|
}
|
|
|
|
=head2 ProcessListGet()
|
|
|
|
get a Process list with all process details
|
|
|
|
my $List = $ProcessObject->ProcessListGet(
|
|
UserID => 1,
|
|
);
|
|
|
|
Returns:
|
|
|
|
$List = [
|
|
{
|
|
ID => 123,
|
|
EntityID => 'P1',
|
|
Name => 'some name',
|
|
StateEntityID => 'S1',
|
|
State => 'Active',
|
|
Layout => $LayoutHashRef,
|
|
Config => $ConfigHashRef,
|
|
Activities => ['A1','A2','A3'],
|
|
CreateTime => '2012-07-04 15:08:00',
|
|
ChangeTime => '2012-07-04 15:08:00',
|
|
},
|
|
{
|
|
ID => 456,
|
|
EntityID => 'P2',
|
|
Name => 'some name',
|
|
StateEntityID => 'S1',
|
|
State => 'Active',
|
|
Layout => $LayoutHashRef,
|
|
Config => $ConfigHashRef,
|
|
Activities => ['A3','A4','A5'],
|
|
CreateTime => '2012-07-04 15:10:00',
|
|
ChangeTime => '2012-07-04 15:10:00',
|
|
},
|
|
];
|
|
|
|
=cut
|
|
|
|
sub ProcessListGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{UserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need UserID!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get cache object
|
|
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
|
|
|
|
# check cache
|
|
my $CacheKey = 'ProcessListGet';
|
|
|
|
my $Cache = $CacheObject->Get(
|
|
Type => 'ProcessManagement_Process',
|
|
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, entity_id
|
|
FROM pm_process
|
|
ORDER BY id',
|
|
);
|
|
|
|
my @ProcessIDs;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
push @ProcessIDs, $Row[0];
|
|
}
|
|
|
|
my @Data;
|
|
for my $ItemID (@ProcessIDs) {
|
|
|
|
my $ProcessData = $Self->ProcessGet(
|
|
ID => $ItemID,
|
|
UserID => 1,
|
|
);
|
|
push @Data, $ProcessData;
|
|
}
|
|
|
|
# set cache
|
|
$CacheObject->Set(
|
|
Type => 'ProcessManagement_Process',
|
|
Key => $CacheKey,
|
|
Value => \@Data,
|
|
TTL => $Self->{CacheTTL},
|
|
);
|
|
|
|
return \@Data;
|
|
}
|
|
|
|
=head2 ProcessSearch()
|
|
|
|
search processes by process name
|
|
|
|
my $ProcessEntityIDs = $ProcessObject->ProcessSearch(
|
|
ProcessName => 'SomeText', # e. g. "SomeText*", "Some*ext" or ['*SomeTest1*', '*SomeTest2*']
|
|
);
|
|
|
|
Returns:
|
|
|
|
$ProcessEntityIDs = [ 'Process-e11e2e9aa83344a235279d4f6babc6ec', 'Process-f8194a25ab0ccddefeb4240c281c1f56' ];
|
|
|
|
=cut
|
|
|
|
sub ProcessSearch {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ProcessName} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ProcessName!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
my $SQL = 'SELECT DISTINCT entity_id
|
|
FROM pm_process ';
|
|
|
|
# if it's no ref, put it to array ref
|
|
if ( ref $Param{ProcessName} eq '' ) {
|
|
$Param{ProcessName} = [ $Param{ProcessName} ];
|
|
}
|
|
|
|
if ( IsArrayRefWithData( $Param{ProcessName} ) ) {
|
|
$SQL .= ' WHERE' if IsArrayRefWithData( $Param{ProcessName} );
|
|
}
|
|
|
|
my @QuotedSearch;
|
|
my $SQLOR = 0;
|
|
|
|
VALUE:
|
|
for my $Value ( @{ $Param{ProcessName} } ) {
|
|
|
|
next VALUE if !defined $Value || !length $Value;
|
|
|
|
$Value = '%' . $DBObject->Quote( $Value, 'Like' ) . '%';
|
|
$Value =~ s/\*/%/g;
|
|
$Value =~ s/%%/%/gi;
|
|
|
|
if ($SQLOR) {
|
|
$SQL .= ' OR';
|
|
}
|
|
|
|
$SQL .= ' name LIKE ? ';
|
|
|
|
push @QuotedSearch, $Value;
|
|
$SQLOR = 1;
|
|
|
|
}
|
|
|
|
if ( IsArrayRefWithData( $Param{ProcessName} ) ) {
|
|
$SQL .= $DBObject->GetDatabaseFunction('LikeEscapeString');
|
|
}
|
|
$SQL .= ' ORDER BY entity_id';
|
|
|
|
return if !$DBObject->Prepare(
|
|
SQL => $SQL,
|
|
Bind => [ \(@QuotedSearch) ]
|
|
);
|
|
|
|
my @Data;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
push @Data, $Row[0];
|
|
}
|
|
|
|
return \@Data;
|
|
}
|
|
|
|
=head2 ProcessDump()
|
|
|
|
gets a complete processes information dump from the DB including: Process State, Activities,
|
|
ActivityDialogs, Transitions and TransitionActions
|
|
|
|
my $ProcessDump = $ProcessObject->ProcessDump(
|
|
ResultType => 'SCALAR' # 'SCALAR' || 'HASH' || 'FILE'
|
|
Location => '/opt/otrs/var/myfile.txt' # mandatory for ResultType = 'FILE'
|
|
UserID => 1,
|
|
);
|
|
|
|
Returns:
|
|
|
|
$ProcessDump = '
|
|
$Self->{'Process'} = {
|
|
'P1' => {
|
|
'Name' => 'Process 1',
|
|
'CreateTime' => '2012-07-21 08:11:33',
|
|
'ChangeTime' => '2012-07-21 08:11:33',
|
|
'Path' => {
|
|
'A1' => {
|
|
'T1' => {
|
|
'Action' => [
|
|
'TA1',
|
|
],
|
|
}
|
|
},
|
|
'StartActivity' => 'A1',
|
|
'StartActivityDialog' => 'AD1',
|
|
'State' => 'S1'
|
|
},
|
|
# ...
|
|
};
|
|
|
|
$Self->{'Process::State'} = {
|
|
'S1' => 'Active',
|
|
'S2' => 'Inactive',
|
|
'S3' => 'FadeAway'
|
|
};
|
|
|
|
$Self->{'Process::Activity'} = {
|
|
'A1' => {
|
|
'Name' => 'Activity 1'
|
|
'CreateTime' => '2012-07-21 08:11:33',
|
|
'ChangeTime' => '2012-07-21 08:11:33',
|
|
'ActivityDialog' => {
|
|
'1' => 'AD1',
|
|
}
|
|
},
|
|
},
|
|
# ...
|
|
};
|
|
|
|
$Self->{'Process::ActivityDialog'} = {
|
|
'AD1' => {
|
|
'Name' => 'Activity Dialog 1',
|
|
'CreateTime' => '2012-07-21 08:11:33',
|
|
'ChangeTime' => '2012-07-21 08:11:33',
|
|
'DescriptionLong' => 'Longer description',
|
|
'DescriptionShort' => 'Short description',
|
|
'FieldOrder' => [
|
|
'StateID',
|
|
'DynamicField_Marke',
|
|
],
|
|
'Fields' => {
|
|
'StateID' => {
|
|
'DefaultValue' => '1',
|
|
'DescriptionLong' => 'Longer description',
|
|
'DescriptionShort' => 'Short description',
|
|
'Display' => '0'
|
|
},
|
|
'DynamicField_Marke' => {
|
|
'DescriptionLong' => 'Longer description',
|
|
'DescriptionShort' => 'Short description',
|
|
'Display' => '2'
|
|
},
|
|
},
|
|
#...
|
|
};
|
|
|
|
$Self->{'Process::Transition'} = {
|
|
'T1' => {
|
|
'Name' => 'Transition 1'
|
|
'ChangeTime' => '2012-07-21 08:11:33',
|
|
'CreateTime' => '2012-07-21 08:11:33',
|
|
'Condition' => {
|
|
'Type' => 'and',
|
|
'Cond1' => {
|
|
'Fields' => {
|
|
'DynamicField_Marke' => {
|
|
'Match' => 'Teststring',
|
|
'Type' => 'String',
|
|
},
|
|
},
|
|
'Type' => 'and',
|
|
},
|
|
},
|
|
},
|
|
# ...
|
|
};
|
|
|
|
$Self->{'Process::Action'} = {
|
|
'TA1' => {
|
|
'Name' => 'Queue Move',
|
|
'CreateTime' => '2012-07-21 08:11:33',
|
|
'ChangeTime' => '2012-07-21 08:11:33',
|
|
'Module' => 'Kernel::System::Process::Transition::Action::QueueMove',
|
|
'Config' => {
|
|
'NewOwner' => 'root@localhost',
|
|
'TargetQueue' => 'Raw',
|
|
},
|
|
},
|
|
# ...
|
|
};
|
|
';
|
|
|
|
my $ProcessDump = $ProcessObject->ProcessDump(
|
|
ResultType => 'HASH' # 'SCALAR' || 'HASH' || 'FILE'
|
|
Location => '/opt/otrs/var/myfile.txt' # mandatory for ResultType = 'FILE'
|
|
UserID => 1,
|
|
);
|
|
|
|
Returns:
|
|
|
|
$ProcessDump = {
|
|
Process => {
|
|
'P1' => {
|
|
'Name' => 'Process 1',
|
|
'CreateTime' => '2012-07-21 08:11:33',
|
|
'ChangeTime' => '2012-07-21 08:11:33',
|
|
'Path' => {
|
|
'A1' => {
|
|
'T1' => {
|
|
'Action' => [
|
|
'TA1',
|
|
],
|
|
}
|
|
},
|
|
'StartActivity' => 'A1',
|
|
'StartActivityDialog' => 'AD1',
|
|
'State' => 'S1'
|
|
},
|
|
# ...
|
|
};
|
|
|
|
State => {
|
|
'S1' => 'Active',
|
|
'S2' => 'Inactive',
|
|
'S3' => 'FadeAway'
|
|
};
|
|
|
|
Activity => {
|
|
'A1' => {
|
|
'Name' => 'Activity 1'
|
|
'CreateTime' => '2012-07-21 08:11:33',
|
|
'ChangeTime' => '2012-07-21 08:11:33',
|
|
'ActivityDialog' => {
|
|
'1' => 'AD1',
|
|
}
|
|
},
|
|
},
|
|
# ...
|
|
};
|
|
|
|
ActivityDialog => {
|
|
'AD1' => {
|
|
'Name' => 'Activity Dialog 1',
|
|
'CreateTime' => '2012-07-21 08:11:33',
|
|
'ChangeTime' => '2012-07-21 08:11:33',
|
|
'DescriptionLong' => 'Longer description',
|
|
'DescriptionShort' => 'Short description',
|
|
'FieldOrder' => [
|
|
'StateID',
|
|
'DynamicField_Marke',
|
|
],
|
|
'Fields' => {
|
|
'StateID' => {
|
|
'DefaultValue' => '1',
|
|
'DescriptionLong' => 'Longer description',
|
|
'DescriptionShort' => 'Short description',
|
|
'Display' => '0'
|
|
},
|
|
'DynamicField_Marke' => {
|
|
'DescriptionLong' => 'Longer description',
|
|
'DescriptionShort' => 'Short description',
|
|
'Display' => '2'
|
|
},
|
|
},
|
|
#...
|
|
};
|
|
|
|
Transition => {
|
|
'T1' => {
|
|
'Name' => 'Transition 1'
|
|
'ChangeTime' => '2012-07-21 08:11:33',
|
|
'CreateTime' => '2012-07-21 08:11:33',
|
|
'Condition' => {
|
|
'Type' => 'and',
|
|
'Cond1' => {
|
|
'Fields' => {
|
|
'DynamicField_Marke' => {
|
|
'Match' => 'Teststring',
|
|
'Type' => 'String',
|
|
},
|
|
},
|
|
'Type' => 'and',
|
|
},
|
|
},
|
|
},
|
|
# ...
|
|
};
|
|
|
|
TransitionAction => {
|
|
'TA1' => {
|
|
'Name' => 'Queue Move',
|
|
'CreateTime' => '2012-07-21 08:11:33',
|
|
'ChangeTime' => '2012-07-21 08:11:33',
|
|
'Module' => 'Kernel::System::Process::Transition::Action::QueueMove',
|
|
'Config' => {
|
|
'NewOwner' => 'root@localhost',
|
|
'TargetQueue' => 'Raw',
|
|
},
|
|
},
|
|
# ...
|
|
};
|
|
}
|
|
|
|
my $ProcessDump = $ProcessObject->ProcessDump(
|
|
ResultType => 'Location' # 'SCALAR' || 'HASH' || 'FILE'
|
|
Location => '/opt/otrs/var/myfile.txt' # mandatory for ResultType = 'FILE'
|
|
UserID => 1,
|
|
);
|
|
|
|
Returns:
|
|
$ProcessDump = '/opt/otrs/var/myfile.txt'; # or undef if can't write the file
|
|
|
|
=cut
|
|
|
|
sub ProcessDump {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{UserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need UserID!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
if ( !defined $Param{ResultType} )
|
|
{
|
|
$Param{ResultType} = 'SCALAR';
|
|
}
|
|
|
|
if ( $Param{ResultType} eq 'FILE' ) {
|
|
if ( !$Param{Location} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need Location for ResultType \'FILE\'!',
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
# get States
|
|
my %StateDump = %{ $Self->{StateObject}->StateList( UserID => 1 ) };
|
|
|
|
# get Processes
|
|
my $ProcessList = $Self->ProcessListGet( UserID => 1 );
|
|
|
|
my %ProcessDump;
|
|
|
|
PROCESS:
|
|
for my $ProcessData ( @{$ProcessList} ) {
|
|
|
|
next PROCESS if !IsHashRefWithData($ProcessData);
|
|
|
|
$ProcessDump{ $ProcessData->{EntityID} } = {
|
|
Name => $ProcessData->{Name},
|
|
CreateTime => $ProcessData->{CreateTime},
|
|
ChangeTime => $ProcessData->{ChangeTime},
|
|
StateEntityID => $ProcessData->{StateEntityID},
|
|
State => $ProcessData->{State},
|
|
StartActivity => $ProcessData->{Config}->{StartActivity} || '',
|
|
StartActivityDialog => $ProcessData->{Config}->{StartActivityDialog} || '',
|
|
Path => $ProcessData->{Config}->{Path} || {},
|
|
};
|
|
}
|
|
|
|
# get Activities
|
|
my $ActivitiesList = $Self->{ActivityObject}->ActivityListGet( UserID => 1 );
|
|
|
|
my %ActivityDump;
|
|
|
|
ACTIVITY:
|
|
for my $ActivityData ( @{$ActivitiesList} ) {
|
|
|
|
next ACTIVITY if !IsHashRefWithData($ActivityData);
|
|
|
|
$ActivityDump{ $ActivityData->{EntityID} } = {
|
|
ID => $ActivityData->{ID},
|
|
Name => $ActivityData->{Name},
|
|
CreateTime => $ActivityData->{CreateTime},
|
|
ChangeTime => $ActivityData->{ChangeTime},
|
|
ActivityDialog => $ActivityData->{Config}->{ActivityDialog} || '',
|
|
};
|
|
}
|
|
|
|
# get ActivityDialogs
|
|
my $ActivityDialogsList = $Self->{ActivityDialogObject}->ActivityDialogListGet( UserID => 1 );
|
|
|
|
my %ActivityDialogDump;
|
|
|
|
ACTIVITYDIALOG:
|
|
for my $ActivityDialogData ( @{$ActivityDialogsList} ) {
|
|
|
|
next ACTIVITY if !IsHashRefWithData($ActivityDialogData);
|
|
|
|
$ActivityDialogDump{ $ActivityDialogData->{EntityID} } = {
|
|
Name => $ActivityDialogData->{Name},
|
|
CreateTime => $ActivityDialogData->{CreateTime},
|
|
ChangeTime => $ActivityDialogData->{ChangeTime},
|
|
Interface => $ActivityDialogData->{Config}->{Interface} || '',
|
|
DescriptionShort => $ActivityDialogData->{Config}->{DescriptionShort} || '',
|
|
DescriptionLong => $ActivityDialogData->{Config}->{DescriptionLong} || '',
|
|
Fields => $ActivityDialogData->{Config}->{Fields} || {},
|
|
FieldOrder => $ActivityDialogData->{Config}->{FieldOrder} || [],
|
|
Permission => $ActivityDialogData->{Config}->{Permission} || '',
|
|
RequiredLock => $ActivityDialogData->{Config}->{RequiredLock} || '',
|
|
SubmitAdviceText => $ActivityDialogData->{Config}->{SubmitAdviceText} || '',
|
|
SubmitButtonText => $ActivityDialogData->{Config}->{SubmitButtonText} || '',
|
|
};
|
|
}
|
|
|
|
# get Transitions
|
|
my $TransitionsList = $Self->{TransitionObject}->TransitionListGet( UserID => 1 );
|
|
|
|
my %TransitionDump;
|
|
|
|
TRANSITION:
|
|
for my $TransitionData ( @{$TransitionsList} ) {
|
|
|
|
next TRANSITION if !IsHashRefWithData($TransitionData);
|
|
|
|
$TransitionDump{ $TransitionData->{EntityID} } = {
|
|
Name => $TransitionData->{Name},
|
|
CreateTime => $TransitionData->{CreateTime},
|
|
ChangeTime => $TransitionData->{ChangeTime},
|
|
Condition => $TransitionData->{Config}->{Condition} || {},
|
|
ConditionLinking => $TransitionData->{Config}->{ConditionLinking} || '',
|
|
};
|
|
}
|
|
|
|
# get TransitionActions
|
|
my $TransitionActionsList = $Self->{TransitionActionObject}->TransitionActionListGet( UserID => 1 );
|
|
|
|
my %TransitionActionDump;
|
|
|
|
TRANSITIONACTION:
|
|
for my $TransitionActionData ( @{$TransitionActionsList} ) {
|
|
|
|
next TRANSITIONACTION if !IsHashRefWithData($TransitionActionData);
|
|
|
|
$TransitionActionDump{ $TransitionActionData->{EntityID} } = {
|
|
Name => $TransitionActionData->{Name},
|
|
CreateTime => $TransitionActionData->{CreateTime},
|
|
ChangeTime => $TransitionActionData->{ChangeTime},
|
|
Module => $TransitionActionData->{Config}->{Module} || '',
|
|
Config => $TransitionActionData->{Config}->{Config} || {},
|
|
};
|
|
}
|
|
|
|
# delete cache (this will also delete the cache for display or hide AgentTicketProcess menu
|
|
# item)
|
|
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
|
|
Type => 'ProcessManagement_Process',
|
|
);
|
|
|
|
# return Hash useful for JSON
|
|
if ( $Param{ResultType} eq 'HASH' ) {
|
|
|
|
return {
|
|
'Process' => \%ProcessDump,
|
|
'State' => \%StateDump,
|
|
'Activity' => \%ActivityDump,
|
|
'ActivityDialog' => \%ActivityDialogDump,
|
|
'Transition' => \%TransitionDump,
|
|
'TransitionAction' => \%TransitionActionDump,
|
|
};
|
|
|
|
}
|
|
else {
|
|
|
|
# create output
|
|
|
|
my $Output = $Self->_ProcessItemOutput(
|
|
Key => "Process",
|
|
Value => \%ProcessDump,
|
|
);
|
|
|
|
$Output .= $Self->_ProcessItemOutput(
|
|
Key => 'Process::State',
|
|
Value => \%StateDump,
|
|
);
|
|
|
|
$Output .= $Self->_ProcessItemOutput(
|
|
Key => 'Process::Activity',
|
|
Value => \%ActivityDump,
|
|
);
|
|
|
|
$Output .= $Self->_ProcessItemOutput(
|
|
Key => 'Process::ActivityDialog',
|
|
Value => \%ActivityDialogDump,
|
|
);
|
|
|
|
$Output .= $Self->_ProcessItemOutput(
|
|
Key => 'Process::Transition',
|
|
Value => \%TransitionDump,
|
|
);
|
|
|
|
$Output .= $Self->_ProcessItemOutput(
|
|
Key => 'Process::TransitionAction',
|
|
Value => \%TransitionActionDump,
|
|
);
|
|
|
|
# return a scalar variable with all config as test
|
|
if ( $Param{ResultType} ne 'FILE' ) {
|
|
|
|
return $Output;
|
|
}
|
|
|
|
# return a file location
|
|
else {
|
|
|
|
# get user data of the current user to use for the file comment
|
|
my %User = $Kernel::OM->Get('Kernel::System::User')->GetUserData(
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
# remove home from location path to show in file comment
|
|
my $Home = $Kernel::OM->Get('Kernel::Config')->Get('Home');
|
|
my $Location = $Param{Location};
|
|
$Location =~ s{$Home\/}{}xmsg;
|
|
|
|
# build comment (therefore we need to trick out the filter)
|
|
my $FileStart = <<'EOF';
|
|
# OTRS config file (automatically generated)
|
|
# VERSION:1.1
|
|
package Kernel::Config::Files::ZZZProcessManagement;
|
|
use strict;
|
|
use warnings;
|
|
no warnings 'redefine'; ## no critic
|
|
use utf8;
|
|
sub Load {
|
|
my ($File, $Self) = @_;
|
|
EOF
|
|
|
|
my $FileEnd = <<'EOF';
|
|
return;
|
|
}
|
|
1;
|
|
EOF
|
|
|
|
$Output = $FileStart . $Output . $FileEnd;
|
|
|
|
my $FileLocation = $Kernel::OM->Get('Kernel::System::Main')->FileWrite(
|
|
Location => $Param{Location},
|
|
Content => \$Output,
|
|
Mode => 'utf8',
|
|
Type => 'Local',
|
|
);
|
|
|
|
return $FileLocation;
|
|
}
|
|
}
|
|
}
|
|
|
|
=head2 ProcessImport()
|
|
|
|
import a process YAML file/content
|
|
|
|
my %ProcessImport = $ProcessObject->ProcessImport(
|
|
Content => $YAMLContent, # mandatory, YAML format
|
|
OverwriteExistingEntities => 0, # 0 || 1
|
|
UserID => 1, # mandatory
|
|
);
|
|
|
|
Returns:
|
|
|
|
%ProcessImport = (
|
|
Message => 'The Message to show.', # error or success message
|
|
Comment => 'Any comment', # optional
|
|
Success => 1, # 1 if success or undef otherwise
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ProcessImport {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
for my $Needed (qw(Content UserID)) {
|
|
|
|
# check needed stuff
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
my $ProcessData = $Kernel::OM->Get('Kernel::System::YAML')->Load( Data => $Param{Content} );
|
|
if ( ref $ProcessData ne 'HASH' ) {
|
|
return (
|
|
Message =>
|
|
"Couldn't read process configuration file. Please make sure you file is valid.",
|
|
);
|
|
}
|
|
|
|
# collect all used fields and make sure they're present
|
|
my @UsedDynamicFields;
|
|
for my $ActivityDialog ( sort keys %{ $ProcessData->{ActivityDialogs} } ) {
|
|
for my $FieldName (
|
|
sort
|
|
keys %{ $ProcessData->{ActivityDialogs}->{$ActivityDialog}->{Config}->{Fields} }
|
|
)
|
|
{
|
|
if ( $FieldName =~ s{DynamicField_(\w+)}{$1}xms ) {
|
|
push @UsedDynamicFields, $FieldName;
|
|
}
|
|
}
|
|
}
|
|
|
|
# get dynamic field object
|
|
my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField');
|
|
|
|
# get all present dynamic fields and check if the fields used in the config are beyond them
|
|
my $DynamicFieldList = $DynamicFieldObject->DynamicFieldList(
|
|
ResultType => 'HASH',
|
|
);
|
|
my @PresentDynamicFieldNames = values %{$DynamicFieldList};
|
|
|
|
my @MissingDynamicFieldNames;
|
|
for my $UsedDynamicFieldName (@UsedDynamicFields) {
|
|
if ( !grep { $_ eq $UsedDynamicFieldName } @PresentDynamicFieldNames ) {
|
|
push @MissingDynamicFieldNames, $UsedDynamicFieldName;
|
|
}
|
|
}
|
|
|
|
if ( $#MissingDynamicFieldNames > -1 ) {
|
|
my $MissingDynamicFields = join( ', ', @MissingDynamicFieldNames );
|
|
return (
|
|
Message => "The following dynamic fields are missing: $MissingDynamicFields. "
|
|
. "Import has been stopped.",
|
|
);
|
|
}
|
|
|
|
# make sure all activities and dialogs are present
|
|
my @UsedActivityDialogs;
|
|
for my $ActivityEntityID ( @{ $ProcessData->{Process}->{Activities} } ) {
|
|
if ( ref $ProcessData->{Activities}->{$ActivityEntityID} ne 'HASH' ) {
|
|
return (
|
|
Message => "Missing data for Activity $ActivityEntityID.",
|
|
);
|
|
}
|
|
else {
|
|
for my $UsedActivityDialog (
|
|
@{ $ProcessData->{Activities}->{$ActivityEntityID}->{ActivityDialogs} }
|
|
)
|
|
{
|
|
push @UsedActivityDialogs, $UsedActivityDialog;
|
|
}
|
|
}
|
|
}
|
|
|
|
for my $ActivityDialogEntityID (@UsedActivityDialogs) {
|
|
if ( ref $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID} ne 'HASH' ) {
|
|
return (
|
|
Message => "Missing data for ActivityDialog $ActivityDialogEntityID.",
|
|
);
|
|
}
|
|
}
|
|
|
|
# make sure all transitions are present
|
|
for my $TransitionEntityID ( @{ $ProcessData->{Process}->{Transitions} } ) {
|
|
if ( ref $ProcessData->{Transitions}->{$TransitionEntityID} ne 'HASH' ) {
|
|
return (
|
|
Message => "Missing data for Transition $TransitionEntityID.",
|
|
);
|
|
}
|
|
}
|
|
|
|
# make sure all transition actions are present
|
|
for my $TransitionActionEntityID ( @{ $ProcessData->{Process}->{TransitionActions} } ) {
|
|
if ( ref $ProcessData->{TransitionActions}->{$TransitionActionEntityID} ne 'HASH' ) {
|
|
return (
|
|
Message => "Missing data for TransitionAction $TransitionActionEntityID.",
|
|
);
|
|
}
|
|
}
|
|
|
|
my %EntityMapping;
|
|
my %PartNameMap = (
|
|
Activity => 'Activities',
|
|
ActivityDialog => 'ActivityDialogs',
|
|
Transition => 'Transitions',
|
|
TransitionAction => 'TransitionActions'
|
|
);
|
|
|
|
# if OverwriteExistingEntities no new entities must be added to the DB unless the entity does
|
|
# not not exists
|
|
if ( $Param{OverwriteExistingEntities} ) {
|
|
|
|
my $EntityID = $ProcessData->{Process}->{EntityID};
|
|
my $NewEntityID = $EntityID;
|
|
|
|
# check if EntityID matched the format (it could be that a process from 3.3.x is been
|
|
# imported)
|
|
if ( $NewEntityID !~ m{\A Process - [0-9a-f]{32} \z}msx ) {
|
|
|
|
# generate new EntityIDs
|
|
$NewEntityID = $Self->{EntityObject}->EntityIDGenerate(
|
|
EntityType => 'Process',
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
|
|
$EntityMapping{Process}->{$EntityID} = $NewEntityID;
|
|
|
|
for my $PartName (qw(Activity ActivityDialog Transition TransitionAction)) {
|
|
for my $PartEntityID ( sort keys %{ $ProcessData->{ $PartNameMap{$PartName} } } ) {
|
|
|
|
$NewEntityID = $PartEntityID;
|
|
|
|
# check if EntityID matched the format (it could be that a process from 3.3.x is been
|
|
# imported)
|
|
if ( $NewEntityID !~ m{\A $PartName - [0-9a-f]{32} \z}msx ) {
|
|
|
|
# generate new EntityIDs
|
|
$NewEntityID = $Self->{EntityObject}->EntityIDGenerate(
|
|
EntityType => $PartName,
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
|
|
$EntityMapping{ $PartNameMap{$PartName} }->{$PartEntityID} = $NewEntityID;
|
|
}
|
|
|
|
# make sure that all entity mapping parts are defined as hash references
|
|
$EntityMapping{ $PartNameMap{$PartName} } //= {};
|
|
}
|
|
}
|
|
else {
|
|
|
|
my $EntityID = $ProcessData->{Process}->{EntityID};
|
|
|
|
# generate new EntityIDs
|
|
my $NewEntityID = $Self->{EntityObject}->EntityIDGenerate(
|
|
EntityType => 'Process',
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
$EntityMapping{Process}->{$EntityID} = $NewEntityID;
|
|
|
|
for my $PartName (qw(Activity ActivityDialog Transition TransitionAction)) {
|
|
for my $PartEntityID ( sort keys %{ $ProcessData->{ $PartNameMap{$PartName} } } ) {
|
|
|
|
$NewEntityID = $Self->{EntityObject}->EntityIDGenerate(
|
|
EntityType => $PartName,
|
|
UserID => $Param{UserID},
|
|
);
|
|
$EntityMapping{ $PartNameMap{$PartName} }->{$PartEntityID} = $NewEntityID;
|
|
}
|
|
|
|
# make sure that all entity mapping parts are defined as hash references
|
|
$EntityMapping{ $PartNameMap{$PartName} } //= {};
|
|
}
|
|
|
|
# set EntityIDs
|
|
my $UpdateResult = $Self->_ImportedEntitiesUpdate(
|
|
ProcessData => $ProcessData,
|
|
EntityMapping => \%EntityMapping,
|
|
);
|
|
|
|
if ( !$UpdateResult->{Success} ) {
|
|
return %{$UpdateResult};
|
|
}
|
|
|
|
# overwrite process data with the temporary entities
|
|
$ProcessData = $UpdateResult->{ProcessData};
|
|
}
|
|
|
|
# invert the entity mappings, this is needed as we need to check if the new entities exists:
|
|
# for non overwriting processes they must not exists and new records must be generated,
|
|
# for overwriting processes it might happens that one record does not exists and it needs
|
|
# to be created before it is updated
|
|
# if new entities are to be created they will be using minimal data and updated with real data
|
|
# later, this way overwriting and non overwriting processes will share the same logic
|
|
%{ $EntityMapping{Process} } = reverse %{ $EntityMapping{Process} };
|
|
%{ $EntityMapping{Activities} } = reverse %{ $EntityMapping{Activities} };
|
|
%{ $EntityMapping{ActivityDialogs} } = reverse %{ $EntityMapping{ActivityDialogs} };
|
|
%{ $EntityMapping{Transitions} } = reverse %{ $EntityMapping{Transitions} };
|
|
%{ $EntityMapping{TransitionActions} } = reverse %{ $EntityMapping{TransitionActions} };
|
|
|
|
my %AddedEntityIDs;
|
|
|
|
# get all processes
|
|
my $ProcessList = $Self->ProcessList(
|
|
UseEntities => 1,
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
# check if processes exists otherwise create them
|
|
for my $ProcessEntityID ( sort keys %{ $EntityMapping{Process} } ) {
|
|
if ( !$ProcessList->{$ProcessEntityID} ) {
|
|
|
|
# create an empty process
|
|
my $ProcessID = $Self->ProcessAdd(
|
|
EntityID => $ProcessEntityID,
|
|
Name => 'NewProcess',
|
|
StateEntityID => 'S1',
|
|
Layout => {},
|
|
Config => {
|
|
Path => {},
|
|
Description => 'NewProcess',
|
|
},
|
|
UserID => $Param{UserID},
|
|
);
|
|
if ( !$ProcessID ) {
|
|
return $Self->_ProcessImportRollBack(
|
|
AddedEntityIDs => \%AddedEntityIDs,
|
|
UserID => $Param{UserID},
|
|
Message => 'Process '
|
|
. $ProcessData->{Process}->{Name}
|
|
. ' could not be added. Stopping import!',
|
|
);
|
|
}
|
|
|
|
# remember added entity
|
|
$AddedEntityIDs{Process}->{$ProcessEntityID} = $ProcessID;
|
|
}
|
|
}
|
|
|
|
my %PartConfigMap = (
|
|
Activity => {},
|
|
ActivityDialog => {
|
|
DescriptionShort => 'NewActivityDialog',
|
|
Fields => {},
|
|
FieldOrder => [],
|
|
},
|
|
Transition => {
|
|
Condition => {},
|
|
},
|
|
TransitionAction => {
|
|
Module => 'NewTransitionAction',
|
|
Config => {},
|
|
},
|
|
);
|
|
|
|
# create missing process parts
|
|
for my $PartName (qw(Activity ActivityDialog Transition TransitionAction)) {
|
|
|
|
my $PartListFunction = $PartName . 'List';
|
|
my $PartAddFunction = $PartName . 'Add';
|
|
my $PartObject = $PartName . 'Object';
|
|
|
|
# get all part items
|
|
my $PartsList = $Self->{$PartObject}->$PartListFunction(
|
|
UseEntities => 1,
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
# check if part exists otherwise create them
|
|
for my $PartEntityID ( sort keys %{ $EntityMapping{ $PartNameMap{$PartName} } } ) {
|
|
if ( !$PartsList->{$PartEntityID} ) {
|
|
|
|
# create an empty part
|
|
my $PartID = $Self->{$PartObject}->$PartAddFunction(
|
|
EntityID => $PartEntityID,
|
|
Name => "New$PartName",
|
|
Config => $PartConfigMap{$PartName},
|
|
UserID => $Param{UserID},
|
|
);
|
|
if ( !$PartID ) {
|
|
return $Self->_ProcessImportRollBack(
|
|
AddedEntityIDs => \%AddedEntityIDs,
|
|
UserID => $Param{UserID},
|
|
Message => "$PartName "
|
|
. $ProcessData->{ $PartNameMap{$PartName} }->{$PartEntityID}->{Name}
|
|
. ' could not be added. Stopping import!',
|
|
);
|
|
}
|
|
|
|
# remember added entity
|
|
$AddedEntityIDs{ $PartNameMap{$PartName} }->{$PartEntityID} = $PartID;
|
|
}
|
|
}
|
|
}
|
|
|
|
# update all entities with real data
|
|
# update process
|
|
for my $ProcessEntityID ( sort keys %{ $EntityMapping{Process} } ) {
|
|
my $Process = $Self->ProcessGet(
|
|
EntityID => $ProcessEntityID,
|
|
UserID => $Param{UserID},
|
|
);
|
|
my $Success = $Self->ProcessUpdate(
|
|
%{ $ProcessData->{Process} },
|
|
ID => $Process->{ID},
|
|
UserID => $Param{UserID},
|
|
);
|
|
if ( !$Success ) {
|
|
return $Self->_ProcessImportRollBack(
|
|
AddedEntityIDs => \%AddedEntityIDs,
|
|
UserID => $Param{UserID},
|
|
Message => "Process: $ProcessEntityID could not be updated. "
|
|
. "Stopping import!",
|
|
);
|
|
}
|
|
}
|
|
|
|
# update all other process parts
|
|
for my $PartName (qw(Activity ActivityDialog Transition TransitionAction)) {
|
|
|
|
my $PartGetFunction = $PartName . 'Get';
|
|
my $PartUpdateFunction = $PartName . 'Update';
|
|
my $PartObject = $PartName . 'Object';
|
|
|
|
for my $PartEntityID ( sort keys %{ $EntityMapping{ $PartNameMap{$PartName} } } ) {
|
|
my $Part = $Self->{$PartObject}->$PartGetFunction(
|
|
EntityID => $PartEntityID,
|
|
UserID => $Param{UserID}
|
|
);
|
|
my $Success = $Self->{$PartObject}->$PartUpdateFunction(
|
|
%{ $ProcessData->{ $PartNameMap{$PartName} }->{$PartEntityID} },
|
|
ID => $Part->{ID},
|
|
UserID => $Param{UserID},
|
|
);
|
|
if ( !$Success ) {
|
|
return $Self->_ProcessImportRollBack(
|
|
AddedEntityIDs => \%AddedEntityIDs,
|
|
UserID => $Param{UserID},
|
|
Message => "$PartName: $PartEntityID could not be updated. "
|
|
. " Stopping import!",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (
|
|
Message => $Kernel::OM->Get('Kernel::Language')->Translate(
|
|
'The process "%s" and all of its data has been imported successfully.',
|
|
$ProcessData->{Process}->{Name}
|
|
),
|
|
Success => 1,
|
|
);
|
|
}
|
|
|
|
sub _ProcessItemOutput {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $Output = $Kernel::OM->Get('Kernel::System::Main')->Dump(
|
|
$Param{Value},
|
|
);
|
|
|
|
my $Key = "\$Self->{'$Param{Key}'}";
|
|
$Output =~ s{\A \$VAR1}{$Key}mxs;
|
|
|
|
return $Output . "\n";
|
|
}
|
|
|
|
sub _ImportedEntitiesUpdate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my %EntityMapping = %{ $Param{EntityMapping} };
|
|
|
|
# re-write process with entity mapping information
|
|
my $Process = $Param{ProcessData}->{Process};
|
|
my $NewProcess;
|
|
|
|
# set non changing root attributes
|
|
for my $Attribute (qw(Name StateEntityID)) {
|
|
$NewProcess->{$Attribute} = $Process->{$Attribute};
|
|
}
|
|
|
|
# set new process main entity
|
|
my $NewProcessEntityID = $EntityMapping{Process}->{ $Process->{EntityID} };
|
|
if ( !$NewProcessEntityID ) {
|
|
my $Message = "Could not find a entity mapping for Process: $Process->{EntityID}";
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'Error',
|
|
Message => $Message,
|
|
);
|
|
return {
|
|
Success => 0,
|
|
Message => $Message,
|
|
};
|
|
}
|
|
|
|
$NewProcess->{EntityID} = $NewProcessEntityID;
|
|
|
|
# set the process layout
|
|
$NewProcess->{Layout} = {};
|
|
for my $ActivityEntityID ( sort keys %{ $Process->{Layout} } ) {
|
|
my $NewActivityEntityID = $EntityMapping{Activities}->{$ActivityEntityID};
|
|
if ( !$NewActivityEntityID ) {
|
|
my $Message = "Could not find a entity mapping for Activity: $ActivityEntityID";
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'Error',
|
|
Message => $Message,
|
|
);
|
|
return {
|
|
Success => 0,
|
|
Message => $Message,
|
|
};
|
|
}
|
|
$NewProcess->{Layout}->{$NewActivityEntityID} = $Process->{Layout}->{$ActivityEntityID};
|
|
}
|
|
|
|
# set process config non changing attributes
|
|
$NewProcess->{Config}->{Description} = $Process->{Config}->{Description};
|
|
|
|
# set process config start activity and start activity dialog EntityID
|
|
my %AttributeMap = (
|
|
Activity => 'Activities',
|
|
ActivityDialog => 'ActivityDialogs',
|
|
);
|
|
|
|
ATTRIBUTE:
|
|
for my $Attribute (qw(Activity ActivityDialog)) {
|
|
$NewProcess->{Config}->{"Start$Attribute"} = '';
|
|
|
|
next ATTRIBUTE if !$Process->{Config}->{"Start$Attribute"};
|
|
my $NewAttributeEntityID = $EntityMapping{ $AttributeMap{$Attribute} }
|
|
->{ $Process->{Config}->{"Start$Attribute"} };
|
|
if ( !$NewAttributeEntityID ) {
|
|
my $Message = "Could not find a entity mapping for $Attribute: "
|
|
. "$Process->{Config}->{Start$Attribute}";
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'Error',
|
|
Message => $Message,
|
|
);
|
|
return {
|
|
Success => 0,
|
|
Message => $Message,
|
|
};
|
|
}
|
|
$NewProcess->{Config}->{"Start$Attribute"} = $NewAttributeEntityID;
|
|
}
|
|
|
|
# set process path
|
|
$NewProcess->{Config}->{Path} = {};
|
|
for my $ActivityEntityID ( sort keys %{ $Process->{Config}->{Path} } ) {
|
|
|
|
# set new activity EntityID in process path
|
|
my $NewActivityEntityID = $EntityMapping{Activities}->{$ActivityEntityID};
|
|
if ( !$NewActivityEntityID ) {
|
|
my $Message = "Could not find a entity mapping for Activity: $ActivityEntityID";
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'Error',
|
|
Message => $Message,
|
|
);
|
|
return {
|
|
Success => 0,
|
|
Message => $Message,
|
|
};
|
|
}
|
|
$NewProcess->{Config}->{Path}->{$NewActivityEntityID} = {};
|
|
|
|
# check if original action has configuration (e.g. last activity might be empty)
|
|
my $Activity = $Process->{Config}->{Path}->{$ActivityEntityID};
|
|
if ( IsHashRefWithData($Activity) ) {
|
|
for my $TransitionEntityID ( sort keys %{$Activity} ) {
|
|
my $Transition = $Activity->{$TransitionEntityID};
|
|
my $NewTransition;
|
|
for my $TransitionActionEntityID ( @{ $Transition->{TransitionAction} } ) {
|
|
|
|
# set new transition action EntityID from process path activity transition
|
|
my $NewTransitionActionEntityID = $EntityMapping{TransitionActions}->{$TransitionActionEntityID};
|
|
if ( !$NewTransitionActionEntityID ) {
|
|
my $Message = "Could not find a entity mapping for Transition Action: "
|
|
. "$TransitionActionEntityID";
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'Error',
|
|
Message => $Message,
|
|
);
|
|
return {
|
|
Success => 0,
|
|
Message => $Message,
|
|
};
|
|
}
|
|
push @{ $NewTransition->{TransitionAction} }, $NewTransitionActionEntityID;
|
|
}
|
|
|
|
# set new activity EntityID stored in the transition
|
|
my $NewDestinationActivityEntityID = $EntityMapping{Activities}->{ $Transition->{ActivityEntityID} };
|
|
if ( !$NewDestinationActivityEntityID ) {
|
|
my $Message = "Could not find a entity mapping for Activity: "
|
|
. "$Transition->{ActivityEntityID}";
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'Error',
|
|
Message => $Message,
|
|
);
|
|
return {
|
|
Success => 0,
|
|
Message => $Message,
|
|
};
|
|
}
|
|
$NewTransition->{ActivityEntityID} = $NewDestinationActivityEntityID;
|
|
|
|
# set new transition EntityID
|
|
my $NewTransitionEntityID = $EntityMapping{Transitions}->{$TransitionEntityID};
|
|
if ( !$NewTransitionEntityID ) {
|
|
my $Message = "Could not find a entity mapping for Transition: $TransitionEntityID";
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'Error',
|
|
Message => $Message,
|
|
);
|
|
return {
|
|
Success => 0,
|
|
Message => $Message,
|
|
};
|
|
}
|
|
|
|
# set new transition to its entity hash key
|
|
$NewProcess->{Config}->{Path}->{$NewActivityEntityID}->{$NewTransitionEntityID} = $NewTransition;
|
|
}
|
|
}
|
|
}
|
|
|
|
# re-write activities with entity mapping information
|
|
my $Activities = $Param{ProcessData}->{Activities};
|
|
my $NewActivities;
|
|
for my $ActivityEntityID ( sort keys %{$Activities} ) {
|
|
|
|
# get current old activity
|
|
my $CurrentActivity = $Activities->{$ActivityEntityID};
|
|
|
|
# set new activity EntityID
|
|
my $NewActivityEntityID = $EntityMapping{Activities}->{$ActivityEntityID};
|
|
if ( !$NewActivityEntityID ) {
|
|
my $Message = "Could not find a entity mapping for Activity: $ActivityEntityID";
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'Error',
|
|
Message => $Message,
|
|
);
|
|
return {
|
|
Success => 0,
|
|
Message => $Message,
|
|
};
|
|
}
|
|
$NewActivities->{$NewActivityEntityID}->{EntityID} = $NewActivityEntityID;
|
|
|
|
# set non changing attributes
|
|
$NewActivities->{$NewActivityEntityID}->{Name} = $CurrentActivity->{Name};
|
|
|
|
# set an empty configuration
|
|
$NewActivities->{$NewActivityEntityID}->{Config}->{ActivityDialog} = {};
|
|
|
|
# set new entities for the configured activity dialogs
|
|
my $CurrentActivityDialogs = $CurrentActivity->{Config}->{ActivityDialog};
|
|
for my $OrderKey ( sort keys %{$CurrentActivityDialogs} ) {
|
|
|
|
# get old activity dialog EntityID
|
|
my $ActivityDialogEntityID = $CurrentActivityDialogs->{$OrderKey};
|
|
|
|
# set new activity dialog EntityID
|
|
my $NewActivityDialogEntityID = $EntityMapping{ActivityDialogs}->{$ActivityDialogEntityID};
|
|
if ( !$NewActivityDialogEntityID ) {
|
|
my $Message = "Could not find a entity mapping for Activity Dialog: "
|
|
. "$ActivityDialogEntityID";
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'Error',
|
|
Message => $Message,
|
|
);
|
|
return {
|
|
Success => 0,
|
|
Message => $Message,
|
|
};
|
|
}
|
|
$NewActivities->{$NewActivityEntityID}->{Config}->{ActivityDialog}->{$OrderKey}
|
|
= $NewActivityDialogEntityID;
|
|
}
|
|
}
|
|
|
|
# re-write all other parts
|
|
my %PartNameMap = (
|
|
ActivityDialog => 'ActivityDialogs',
|
|
Transition => 'Transitions',
|
|
TransitionAction => 'TransitionActions'
|
|
);
|
|
|
|
my %NewParts;
|
|
|
|
for my $PartName (qw(ActivityDialog Transition TransitionAction)) {
|
|
my $CurrentParts = $Param{ProcessData}->{ $PartNameMap{$PartName} };
|
|
|
|
for my $CurrentEntityID ( sort keys %{$CurrentParts} ) {
|
|
|
|
# get current old process part
|
|
my $CurrentPart = $CurrentParts->{$CurrentEntityID};
|
|
|
|
# set new part EntityID
|
|
my $NewEntityID = $EntityMapping{ $PartNameMap{$PartName} }->{$CurrentEntityID};
|
|
if ( !$NewEntityID ) {
|
|
my $Message = "Could not find a entity mapping for $PartName: $CurrentEntityID";
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'Error',
|
|
Message => $Message,
|
|
);
|
|
return {
|
|
Success => 0,
|
|
Message => $Message,
|
|
};
|
|
}
|
|
|
|
$NewParts{ $PartNameMap{$PartName} }->{$NewEntityID}->{EntityID} = $NewEntityID;
|
|
|
|
# set non changing attributes
|
|
for my $Attribute (qw(Name Config)) {
|
|
$NewParts{ $PartNameMap{$PartName} }->{$NewEntityID}->{$Attribute} = $CurrentPart->{$Attribute};
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
Success => 1,
|
|
ProcessData => {
|
|
%NewParts,
|
|
Process => $NewProcess,
|
|
Activities => $NewActivities,
|
|
},
|
|
};
|
|
}
|
|
|
|
sub _ProcessImportRollBack {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my %AddedEntityIDs = %{ $Param{AddedEntityIDs} };
|
|
|
|
my $Error;
|
|
|
|
# delete added processes
|
|
for my $ProcessEntityID ( sort keys %{ $AddedEntityIDs{Process} } ) {
|
|
my $ProcessID = $AddedEntityIDs{Process}->{$ProcessEntityID};
|
|
my $Success = $Self->ProcessDelete(
|
|
ID => $ProcessID,
|
|
UserID => $Param{UserID},
|
|
);
|
|
if ( !$Success ) {
|
|
$Error = 1;
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Process: $ProcessEntityID could not be deleted",
|
|
);
|
|
}
|
|
}
|
|
|
|
my %PartNameMap = (
|
|
Activity => 'Activities',
|
|
ActivityDialog => 'ActivityDialogs',
|
|
Transition => 'Transitions',
|
|
TransitionAction => 'TransitionActions'
|
|
);
|
|
|
|
# delete added process parts
|
|
for my $Part (qw(Activity ActivityDialog Transition TransitionAction)) {
|
|
for my $PartEntityID ( sort keys %{ $AddedEntityIDs{ $PartNameMap{$Part} } } ) {
|
|
my $PartID = $AddedEntityIDs{ $PartNameMap{$Part} }->{$PartEntityID};
|
|
my $DeleteFunction = $Part . 'Delete';
|
|
my $Object = $Part . 'Object';
|
|
my $Success = $Self->{$Object}->$DeleteFunction(
|
|
ID => $PartID,
|
|
UserID => $Param{UserID},
|
|
);
|
|
if ( !$Success ) {
|
|
$Error = 1;
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "$Part: $PartEntityID could not be deleted",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
my $Comment = 'Process could not be imported. All changes have been rolled back.';
|
|
|
|
if ($Error) {
|
|
$Comment = ' There was an error rolling back the partially imported process, please'
|
|
. ' check the error log for details.';
|
|
}
|
|
|
|
return (
|
|
Success => 0,
|
|
Message => $Param{Message},
|
|
Comment => $Comment,
|
|
);
|
|
}
|
|
|
|
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
|