Files
scripts/Perl OTRS/Kernel/Modules/AdminProcessManagement.pm
2024-10-14 00:08:40 +02:00

2123 lines
72 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::Modules::AdminProcessManagement;
## nofilter(TidyAll::Plugin::OTRS::Perl::Dumper)
use strict;
use warnings;
use Data::Dumper;
use Kernel::System::VariableCheck qw(:all);
use Kernel::Language qw(Translatable);
our $ObjectManagerDisabled = 1;
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {%Param};
bless( $Self, $Type );
return $Self;
}
sub Run {
my ( $Self, %Param ) = @_;
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
$Self->{Subaction} = $ParamObject->GetParam( Param => 'Subaction' ) || '';
my $ProcessID = $ParamObject->GetParam( Param => 'ID' ) || '';
my $EntityID = $ParamObject->GetParam( Param => 'EntityID' ) || '';
my $EntityObject = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Entity');
# get the list of updated or deleted entities
my $EntitySyncStateList = $EntityObject->EntitySyncStateList(
UserID => $Self->{UserID}
);
my $SynchronizeMessage = Translatable(
'Process Management information from database is not in sync with the system configuration, please synchronize all processes.'
);
if ( IsArrayRefWithData($EntitySyncStateList) ) {
# create a notification if system is not up to date
$Param{NotifyData} = [
{
Info => $SynchronizeMessage,
},
];
}
# get needed objects
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $ProcessObject = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Process');
my $StateObject = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Process::State');
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
# ------------------------------------------------------------ #
# ProcessImport
# ------------------------------------------------------------ #
if ( $Self->{Subaction} eq 'ProcessImport' ) {
# challenge token check for write action
$LayoutObject->ChallengeTokenCheck();
my $Content;
my $Home = $Kernel::OM->Get('Kernel::Config')->Get('Home');
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
my $ExampleProcess = $ParamObject->GetParam( Param => 'ExampleProcess' );
my $FileWithoutExtension;
if ($ExampleProcess) {
my $ExampleProcessFilename = $ParamObject->GetParam( Param => 'ExampleProcess' );
$ExampleProcessFilename =~ s{/+|\.{2,}}{}smx; # remove slashes and ..
if ( !$ExampleProcessFilename ) {
return $Kernel::OM->Get('Kernel::Output::HTML::Layout')->FatalError(
Message => Translatable('Need ExampleProcesses!'),
);
}
# extract file name without extension
$ExampleProcessFilename =~ m{(.*?)\.yml$}smx;
$FileWithoutExtension = $1;
# run _pre.pm if available
if ( -e "$Home/var/processes/examples/" . $FileWithoutExtension . "_pre.pm" ) {
my $BackendName = 'var::processes::examples::' . $FileWithoutExtension . '_pre';
my $Loaded = $MainObject->Require(
$BackendName,
);
if ($Loaded) {
my $BackendPre = $Kernel::OM->Get(
$BackendName,
);
my %Status = $BackendPre->Run();
if ( !$Status{Success} ) {
# show the error screen
return $LayoutObject->ErrorScreen(
Message => $Status{Error},
);
}
}
}
$Content = $MainObject->FileRead(
Location => "$Home/var/processes/examples/$ExampleProcessFilename",
Mode => 'utf8',
);
if ( !$Content ) {
return $Kernel::OM->Get('Kernel::Output::HTML::Layout')->FatalError(
Message =>
$LayoutObject->{LanguageObject}->Translate( 'Could not read %s!', $ExampleProcessFilename ),
);
}
$Content = ${ $Content || \'' };
}
else {
my $FormID = $ParamObject->GetParam( Param => 'FormID' ) || '';
my %UploadStuff = $ParamObject->GetUploadAll(
Param => 'FileUpload',
);
$Content = $UploadStuff{Content};
}
my $OverwriteExistingEntities = $ParamObject->GetParam( Param => 'OverwriteExistingEntities' );
# import the process YAML file
my %ProcessImport = $ProcessObject->ProcessImport(
Content => $Content,
OverwriteExistingEntities => $OverwriteExistingEntities,
UserID => $Self->{UserID},
);
if ( !$ProcessImport{Success} ) {
# show the error screen
return $LayoutObject->ErrorScreen(
Message => $ProcessImport{Message},
Comment => $ProcessImport{Comment} || '',
);
}
else {
# Run _post.pm if available.
if (
$ExampleProcess
&& -e "$Home/var/processes/examples/" . $FileWithoutExtension . "_post.pm"
)
{
my $BackendName = 'var::processes::examples::' . $FileWithoutExtension . '_post';
my $Loaded = $MainObject->Require(
$BackendName,
);
if ($Loaded) {
my $BackendPost = $Kernel::OM->Get(
$BackendName,
);
my %Status = $BackendPost->Run();
if ( !$Status{Success} ) {
# show the error screen
return $LayoutObject->ErrorScreen(
Message => $Status{Error},
);
}
}
}
# show the overview with success informations
$Param{NotifyData} = [
{
Info => $ProcessImport{Message},
},
{
Info => $SynchronizeMessage,
},
];
return $Self->_ShowOverview(
%Param,
);
}
}
# ------------------------------------------------------------ #
# ProcessExport
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ProcessExport' ) {
# check for ProcessID
my $ProcessID = $ParamObject->GetParam( Param => 'ID' ) || '';
if ( !$ProcessID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('Need ProcessID!'),
);
}
my $ProcessData = $Self->_GetProcessData(
ID => $ProcessID
);
# convert the processdata hash to string
my $ProcessDataYAML = $Kernel::OM->Get('Kernel::System::YAML')->Dump( Data => $ProcessData );
# send the result to the browser
return $LayoutObject->Attachment(
ContentType => 'text/html; charset=' . $LayoutObject->{Charset},
Content => $ProcessDataYAML,
Type => 'attachment',
Filename => 'Export_ProcessEntityID_' . $ProcessData->{Process}->{EntityID} . '.yml',
NoCache => 1,
);
}
# ------------------------------------------------------------ #
# ProcessPrint
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ProcessPrint' ) {
# we need to use Data::Dumper with custom Indent
my $Indent = $Data::Dumper::Indent;
$Data::Dumper::Indent = 1;
# check for ProcessID
my $ProcessID = $ParamObject->GetParam( Param => 'ID' ) || '';
if ( !$ProcessID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('Need ProcessID!'),
);
}
my $BooleanMapping = {
0 => Translatable('No'),
1 => Translatable('Yes'),
2 => Translatable('Yes (mandatory)'),
};
my $ProcessData = $Self->_GetProcessData(
ID => $ProcessID
);
my $Output = $LayoutObject->Header(
Value => $Param{Title},
Type => 'Small',
);
# print all activities
if ( $ProcessData->{Activities} && %{ $ProcessData->{Activities} } ) {
for my $ActivityEntityID ( sort keys %{ $ProcessData->{Activities} } ) {
$LayoutObject->Block(
Name => 'ActivityRow',
Data => {
%{ $ProcessData->{Activities}->{$ActivityEntityID} },
DialogCount =>
scalar
@{ $ProcessData->{Activities}->{$ActivityEntityID}->{ActivityDialogs} },
},
);
# list all assigned dialogs
my $AssignedDialogs = $ProcessData->{Activities}->{$ActivityEntityID}->{Config}->{ActivityDialog};
if ( $AssignedDialogs && %{$AssignedDialogs} ) {
$LayoutObject->Block(
Name => 'AssignedDialogs',
);
for my $AssignedDialog ( sort keys %{$AssignedDialogs} ) {
my $AssignedDialogEntityID = $ProcessData->{Activities}->{$ActivityEntityID}->{Config}
->{ActivityDialog}->{$AssignedDialog};
$LayoutObject->Block(
Name => 'AssignedDialogsRow',
Data => {
Name => $ProcessData->{ActivityDialogs}->{$AssignedDialogEntityID}
->{Name},
EntityID => $AssignedDialogEntityID,
},
);
}
}
}
}
else {
$LayoutObject->Block(
Name => 'ActivityRowEmpty',
);
}
# print all activity dialogs
if ( $ProcessData->{ActivityDialogs} && %{ $ProcessData->{ActivityDialogs} } ) {
for my $ActivityDialogEntityID ( sort keys %{ $ProcessData->{ActivityDialogs} } ) {
$LayoutObject->Block(
Name => 'ActivityDialogRow',
Data => {
ShownIn => join(
', ',
@{
$ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}
->{Config}->{Interface}
}
),
%{ $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID} },
},
);
for my $ElementAttribute (
qw(DescriptionShort DescriptionLong SubmitButtonText SubmitAdviceText Permission RequiredLock)
)
{
my $Value = $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}->{Config}
->{$ElementAttribute};
if ( defined $Value ) {
if ( $ElementAttribute eq 'RequiredLock' ) {
$Value = $BooleanMapping->{$Value};
}
$LayoutObject->Block(
Name => 'ElementAttribute',
Data => {
Key => $ElementAttribute,
Value => $Value,
},
);
}
}
# list all assigned fields
my $AssignedFields = $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}->{Config}
->{FieldOrder};
if ( $AssignedFields && @{$AssignedFields} ) {
$LayoutObject->Block(
Name => 'AssignedFields',
);
for my $AssignedField ( @{$AssignedFields} ) {
$LayoutObject->Block(
Name => 'AssignedFieldsRow',
Data => {
Name => $AssignedField,
},
);
my %Values = %{
$ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}
->{Config}->{Fields}->{$AssignedField}
};
if ( $Values{Config} ) {
$Values{Config} = Dumper( $Values{Config} ); ## no critic
$Values{Config} =~ s{ \s* \$VAR1 \s* =}{}xms;
$Values{Config} =~ s{\s+\{}{\{}xms;
}
for my $Key ( sort keys %Values ) {
if ( $Key eq 'Display' ) {
$Values{$Key} = $BooleanMapping->{ $Values{$Key} };
}
if ( $Values{$Key} ) {
$LayoutObject->Block(
Name => 'AssignedFieldsRowValue',
Data => {
Key => $Key,
Value => $Values{$Key},
},
);
}
}
}
}
}
}
else {
$LayoutObject->Block(
Name => 'ActivityDialogRowEmpty',
);
}
# print all transitions
if ( $ProcessData->{Transitions} && %{ $ProcessData->{Transitions} } ) {
for my $TransitionEntityID ( sort keys %{ $ProcessData->{Transitions} } ) {
# list config
my $Config = $ProcessData->{Transitions}->{$TransitionEntityID}->{Config};
$LayoutObject->Block(
Name => 'TransitionRow',
Data => {
%{ $ProcessData->{Transitions}->{$TransitionEntityID} },
ConditionLinking => $Config->{ConditionLinking},
},
);
if ( $Config && %{$Config} ) {
$LayoutObject->Block(
Name => 'Condition',
);
for my $Condition ( sort keys %{ $Config->{Condition} } ) {
$LayoutObject->Block(
Name => 'ConditionRow',
Data => {
Name => $Condition,
},
);
my %Values = %{ $Config->{Condition}->{$Condition} };
for my $Key ( sort keys %Values ) {
if ( $Values{$Key} ) {
if ( ref $Values{$Key} eq 'HASH' ) {
$LayoutObject->Block(
Name => 'ConditionRowSub',
Data => {
NameSub => $Key,
},
);
for my $SubKey ( sort keys %{ $Values{$Key} } ) {
if ( ref $Values{$Key}->{$SubKey} eq 'HASH' ) {
$LayoutObject->Block(
Name => 'ConditionRowSubSub',
Data => {
NameSubSub => $SubKey,
},
);
for my $SubSubKey (
sort keys %{ $Values{$Key}->{$SubKey} }
)
{
$LayoutObject->Block(
Name => 'ConditionRowSubSubValue',
Data => {
Key => $SubSubKey,
Value =>
$Values{$Key}->{$SubKey}->{$SubSubKey},
},
);
}
}
else {
$LayoutObject->Block(
Name => 'ConditionRowSubValue',
Data => {
Key => $SubKey,
Value => $Values{$Key}->{$SubKey},
},
);
}
}
}
else {
$LayoutObject->Block(
Name => 'ConditionRowValue',
Data => {
Key => $Key,
Value => $Values{$Key},
},
);
}
}
}
}
}
}
}
else {
$LayoutObject->Block(
Name => 'TransitionRowEmpty',
);
}
# print all transition actions
if ( $ProcessData->{TransitionActions} && %{ $ProcessData->{TransitionActions} } ) {
for my $TransitionActionEntityID ( sort keys %{ $ProcessData->{TransitionActions} } ) {
$LayoutObject->Block(
Name => 'TransitionActionRow',
Data => {
Module => $ProcessData->{TransitionActions}->{$TransitionActionEntityID}
->{Config}->{Module},
%{ $ProcessData->{TransitionActions}->{$TransitionActionEntityID} },
},
);
# list config
my $Config = $ProcessData->{TransitionActions}->{$TransitionActionEntityID}->{Config}
->{Config};
if ( $Config && %{$Config} ) {
$LayoutObject->Block(
Name => 'Config',
);
CONFIGITEM:
for my $ConfigItem ( sort keys %{$Config} ) {
next CONFIGITEM if !$ConfigItem;
$LayoutObject->Block(
Name => 'ConfigRow',
Data => {
Name => $ConfigItem,
Value => $Config->{$ConfigItem},
},
);
}
}
}
}
else {
$LayoutObject->Block(
Name => 'TransitionActionRowEmpty',
);
}
# determine skin for selection of the correct logo
# 1. use UserSkin setting from Agent preferences, if available
# 2. use HostBased skin setting, if available
# 3. use default skin from configuration
my $SkinSelectedHostBased;
my $DefaultSkinHostBased = $ConfigObject->Get('Loader::Agent::DefaultSelectedSkin::HostBased');
if ( $DefaultSkinHostBased && $ENV{HTTP_HOST} ) {
REGEXP:
for my $RegExp ( sort keys %{$DefaultSkinHostBased} ) {
# do not use empty regexp or skin directories
next REGEXP if !$RegExp;
next REGEXP if !$DefaultSkinHostBased->{$RegExp};
# check if regexp is matching
if ( $ENV{HTTP_HOST} =~ /$RegExp/i ) {
$SkinSelectedHostBased = $DefaultSkinHostBased->{$RegExp};
}
}
}
my $SkinSelected = $Self->{'UserSkin'};
# check if the skin is valid
my $SkinValid = 0;
if ($SkinSelected) {
$SkinValid = $LayoutObject->SkinValidate(
SkinType => 'Agent',
Skin => $SkinSelected,
);
}
if ( !$SkinValid ) {
$SkinSelected = $SkinSelectedHostBased
|| $ConfigObject->Get('Loader::Agent::DefaultSelectedSkin')
|| 'default';
}
my %AgentLogo;
# check if we need to display a custom logo for the selected skin
my $AgentLogoCustom = $ConfigObject->Get('AgentLogoCustom');
if (
$SkinSelected
&& $AgentLogoCustom
&& IsHashRefWithData($AgentLogoCustom)
&& $AgentLogoCustom->{$SkinSelected}
)
{
%AgentLogo = %{ $AgentLogoCustom->{$SkinSelected} };
}
# Otherwise show default header logo, if configured
elsif ( defined $ConfigObject->Get('AgentLogo') ) {
%AgentLogo = %{ $ConfigObject->Get('AgentLogo') };
}
# get logo
if ( $AgentLogo{URL} ) {
$LayoutObject->Block(
Name => 'Logo',
Data => {
LogoURL => $ConfigObject->Get('Frontend::WebPath') . $AgentLogo{URL},
},
);
}
# collect path information
my @Path;
push @Path, $ProcessData->{Process}->{Config}->{StartActivity};
ACTIVITY:
for my $Activity ( @{ $ProcessData->{Process}->{Activities} } ) {
next ACTIVITY if $Activity eq $ProcessData->{Process}->{Config}->{StartActivity};
push @Path, $Activity;
}
for my $Activity (@Path) {
for my $Transition (
sort keys %{ $ProcessData->{Process}->{Config}->{Path}->{$Activity} }
)
{
my $TransitionActionString;
if (
$ProcessData->{Process}->{Config}->{Path}->{$Activity}->{$Transition}
->{TransitionAction}
&& @{
$ProcessData->{Process}->{Config}->{Path}->{$Activity}->{$Transition}
->{TransitionAction}
}
)
{
$TransitionActionString = join(
', ',
@{
$ProcessData->{Process}->{Config}->{Path}->{$Activity}->{$Transition}
->{TransitionAction}
}
);
if ($TransitionActionString) {
$TransitionActionString = '(' . $TransitionActionString . ')';
}
}
$LayoutObject->Block(
Name => 'PathItem',
Data => {
ActivityStart => $Activity,
Transition => $Transition,
TransitionActions => $TransitionActionString,
ActivityEnd =>
$ProcessData->{Process}->{Config}->{Path}->{$Activity}->{$Transition}
->{ActivityEntityID},
},
);
}
}
$Output .= $LayoutObject->Output(
TemplateFile => "AdminProcessManagementProcessPrint",
Data => {
Name => $ProcessData->{Process}->{Name} . ' ('
. $ProcessData->{Process}->{EntityID} . ')',
State => $ProcessData->{Process}->{State} . ' ('
. $ProcessData->{Process}->{StateEntityID} . ')',
Description => $ProcessData->{Process}->{Config}->{Description},
StartActivity => $ProcessData->{Process}->{Config}->{StartActivity},
%Param,
},
);
$Output .= $LayoutObject->Footer();
# reset Indent
$Data::Dumper::Indent = $Indent;
return $Output;
}
# ------------------------------------------------------------ #
# ProcessCopy
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ProcessCopy' ) {
# challenge token check for write action
$LayoutObject->ChallengeTokenCheck();
# get Process data
my $ProcessData = $ProcessObject->ProcessGet(
ID => $ProcessID,
UserID => $Self->{UserID},
);
if ( !$ProcessData ) {
return $LayoutObject->ErrorScreen(
Message => $LayoutObject->{LanguageObject}->Translate( 'Unknown Process %s!', $ProcessID ),
);
}
# create new process name
my $ProcessName = $LayoutObject->{LanguageObject}->Translate( '%s (copy)', $ProcessData->{Name} );
# generate entity ID
my $EntityID = $EntityObject->EntityIDGenerate(
EntityType => 'Process',
UserID => $Self->{UserID},
);
# show error if can't generate a new EntityID
if ( !$EntityID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('There was an error generating a new EntityID for this Process'),
);
}
# check if Inactive state estity exists
my $StateList = $StateObject->StateList( UserID => $Self->{UserID} );
my %StateLookup = reverse %{$StateList};
my $StateEntityID = $StateLookup{'Inactive'};
# show error if StateEntityID for Inactive does not exist
if ( !$EntityID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('The StateEntityID for state Inactive does not exists'),
);
}
# otherwise save configuration and return to overview screen
my $ProcessID = $ProcessObject->ProcessAdd(
Name => $ProcessName,
EntityID => $EntityID,
StateEntityID => $StateEntityID,
Layout => $ProcessData->{Layout},
Config => $ProcessData->{Config},
UserID => $Self->{UserID},
);
# show error if can't create
if ( !$ProcessID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('There was an error creating the Process'),
);
}
# set entitty sync state
my $Success = $EntityObject->EntitySyncStateSet(
EntityType => 'Process',
EntityID => $EntityID,
SyncState => 'not_sync',
UserID => $Self->{UserID},
);
# show error if can't set
if ( !$Success ) {
return $LayoutObject->ErrorScreen(
Message => $LayoutObject->{LanguageObject}->Translate(
'There was an error setting the entity sync status for Process entity: %s', $EntityID
),
);
}
# return to overview
return $LayoutObject->Redirect( OP => "Action=$Self->{Action}" );
}
# ------------------------------------------------------------ #
# ProcessNew
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ProcessNew' ) {
return $Self->_ShowEdit(
%Param,
Action => 'New',
);
}
# ------------------------------------------------------------ #
# ProcessNewAction
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ProcessNewAction' ) {
# challenge token check for write action
$LayoutObject->ChallengeTokenCheck();
# get process data
my $ProcessData;
# get parameter from web browser
my $GetParam = $Self->_GetParams();
# set new confguration
$ProcessData->{Name} = $GetParam->{Name};
$ProcessData->{Config}->{Description} = $GetParam->{Description};
$ProcessData->{StateEntityID} = $GetParam->{StateEntityID};
# check required parameters
my %Error;
if ( !$GetParam->{Name} ) {
# add server error error class
$Error{NameServerError} = 'ServerError';
$Error{NameServerErrorMessage} = Translatable('This field is required');
}
if ( !$GetParam->{Description} ) {
# add server error error class
$Error{DescriptionServerError} = 'ServerError';
$Error{DescriptionServerErrorMessage} = Translatable('This field is required');
}
# check if state exists
my $StateList = $StateObject->StateList( UserID => $Self->{UserID} );
if ( !$StateList->{ $GetParam->{StateEntityID} } )
{
# add server error error class
$Error{StateEntityIDServerError} = 'ServerError';
}
# if there is an error return to edit screen
if ( IsHashRefWithData( \%Error ) ) {
return $Self->_ShowEdit(
%Error,
%Param,
ProcessData => $ProcessData,
Action => 'New',
);
}
# generate entity ID
my $EntityID = $EntityObject->EntityIDGenerate(
EntityType => 'Process',
UserID => $Self->{UserID},
);
# show error if can't generate a new EntityID
if ( !$EntityID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('There was an error generating a new EntityID for this Process'),
);
}
# otherwise save configuration and return to overview screen
my $ProcessID = $ProcessObject->ProcessAdd(
Name => $ProcessData->{Name},
EntityID => $EntityID,
StateEntityID => $ProcessData->{StateEntityID},
Layout => {},
Config => $ProcessData->{Config},
UserID => $Self->{UserID},
);
# show error if can't create
if ( !$ProcessID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('There was an error creating the Process'),
);
}
# set entitty sync state
my $Success = $EntityObject->EntitySyncStateSet(
EntityType => 'Process',
EntityID => $EntityID,
SyncState => 'not_sync',
UserID => $Self->{UserID},
);
# show error if can't set
if ( !$Success ) {
return $LayoutObject->ErrorScreen(
Message => $LayoutObject->{LanguageObject}->Translate(
'There was an error setting the entity sync status for Process entity: %s', $EntityID
),
);
}
# redirect to process edit screen
return $LayoutObject->Redirect(
OP =>
"Action=AdminProcessManagement;Subaction=ProcessEdit;ID=$ProcessID"
);
}
# ------------------------------------------------------------ #
# ProcessEdit
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ProcessEdit' ) {
# check for ProcessID
if ( !$ProcessID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('Need ProcessID!'),
);
}
# set screens path in session
my @ScreensPath = (
{
Action => $Self->{Action} || '',
Subaction => $Self->{Subaction} || '',
Parameters => 'ID=' . $ProcessID . ';EntityID=' . $EntityID
}
);
# convert screens patch to string (JSON)
my $JSONScreensPath = $LayoutObject->JSONEncode(
Data => \@ScreensPath,
);
$Kernel::OM->Get('Kernel::System::AuthSession')->UpdateSessionID(
SessionID => $Self->{SessionID},
Key => 'ProcessManagementScreensPath',
Value => $JSONScreensPath,
);
# get Process data
my $ProcessData = $ProcessObject->ProcessGet(
ID => $ProcessID,
UserID => $Self->{UserID},
);
# check for valid Process data
if ( !IsHashRefWithData($ProcessData) ) {
return $LayoutObject->ErrorScreen(
Message =>
$LayoutObject->{LanguageObject}->Translate( 'Could not get data for ProcessID %s', $ProcessID ),
);
}
return $Self->_ShowEdit(
%Param,
ProcessID => $ProcessID,
ProcessData => $ProcessData,
Action => 'Edit',
);
}
# ------------------------------------------------------------ #
# ProcessEditAction
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ProcessEditAction' ) {
# challenge token check for write action
$LayoutObject->ChallengeTokenCheck();
# get webserice configuration
my $ProcessData;
# get parameter from web browser
my $GetParam = $Self->_GetParams();
# set new confguration
$ProcessData->{Name} = $GetParam->{Name};
$ProcessData->{EntityID} = $GetParam->{EntityID};
$ProcessData->{ProcessLayout} = $GetParam->{ProcessLayout};
$ProcessData->{StateEntityID} = $GetParam->{StateEntityID};
$ProcessData->{Config}->{Description} = $GetParam->{Description};
$ProcessData->{Config}->{Path} = $GetParam->{Path};
$ProcessData->{Config}->{StartActivity} = $GetParam->{StartActivity};
$ProcessData->{Config}->{StartActivityDialog} = $GetParam->{StartActivityDialog};
# check required parameters
my %Error;
if ( !$GetParam->{Name} ) {
# add server error error class
$Error{NameServerError} = 'ServerError';
$Error{NameServerErrorMessage} = Translatable('This field is required');
}
if ( !$GetParam->{Description} ) {
# add server error error class
$Error{DescriptionServerError} = 'ServerError';
$Error{DescriptionServerErrorMessage} = Translatable('This field is required');
}
# check if state exists
my $StateList = $StateObject->StateList( UserID => $Self->{UserID} );
if ( !$StateList->{ $GetParam->{StateEntityID} } )
{
# add server error error class
$Error{StateEntityIDServerError} = 'ServerError';
}
# if there is an error return to edit screen
if ( IsHashRefWithData( \%Error ) ) {
return $Self->_ShowEdit(
%Error,
%Param,
ProcessData => $ProcessData,
Action => 'Edit',
);
}
# otherwise save configuration and return to overview screen
my $Success = $ProcessObject->ProcessUpdate(
ID => $ProcessID,
Name => $ProcessData->{Name},
EntityID => $ProcessData->{EntityID},
StateEntityID => $ProcessData->{StateEntityID},
Layout => $ProcessData->{ProcessLayout},
Config => $ProcessData->{Config},
UserID => $Self->{UserID},
);
# show error if can't update
if ( !$Success ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('There was an error updating the Process'),
);
}
# set entitty sync state
$Success = $EntityObject->EntitySyncStateSet(
EntityType => 'Process',
EntityID => $ProcessData->{EntityID},
SyncState => 'not_sync',
UserID => $Self->{UserID},
);
# show error if can't set
if ( !$Success ) {
return $LayoutObject->ErrorScreen(
Message => $LayoutObject->{LanguageObject}->Translate(
'There was an error setting the entity sync status for Process entity: %s',
$ProcessData->{EntityID}
),
);
}
if (
defined $ParamObject->GetParam( Param => 'ContinueAfterSave' )
&& ( $ParamObject->GetParam( Param => 'ContinueAfterSave' ) eq '1' )
)
{
# if the user would like to continue editing the process, just redirect to the edit screen
return $LayoutObject->Redirect(
OP =>
"Action=AdminProcessManagement;Subaction=ProcessEdit;ID=$ProcessID;EntityID=$ProcessData->{EntityID}"
);
}
else {
# otherwise return to overview
return $LayoutObject->Redirect( OP => "Action=$Self->{Action}" );
}
}
# ------------------------------------------------------------ #
# ProcessDeleteCheck AJAX
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ProcessDeleteCheck' ) {
# check for ProcessID
return if !$ProcessID;
my $CheckResult = $Self->_CheckProcessDelete( ID => $ProcessID );
# build JSON output
my $JSON = $LayoutObject->JSONEncode(
Data => {
%{$CheckResult},
},
);
# send JSON response
return $LayoutObject->Attachment(
ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
Content => $JSON,
Type => 'inline',
NoCache => 1,
);
}
# ------------------------------------------------------------ #
# ProcessDelete AJAX
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ProcessDelete' ) {
# challenge token check for write action
$LayoutObject->ChallengeTokenCheck();
# check for ProcessID
return if !$ProcessID;
my $CheckResult = $Self->_CheckProcessDelete( ID => $ProcessID );
my $JSON;
if ( $CheckResult->{Success} ) {
my $Success = $ProcessObject->ProcessDelete(
ID => $ProcessID,
UserID => $Self->{UserID},
);
my %DeleteResult = (
Success => $Success,
);
if ( !$Success ) {
$DeleteResult{Message}
= $LayoutObject->{LanguageObject}->Translate( 'Process: %s could not be deleted', $ProcessID );
}
else {
# set entitty sync state
my $Success = $EntityObject->EntitySyncStateSet(
EntityType => 'Process',
EntityID => $CheckResult->{ProcessData}->{EntityID},
SyncState => 'deleted',
UserID => $Self->{UserID},
);
# show error if cant set
if ( !$Success ) {
$DeleteResult{Success} = $Success;
$DeleteResult{Message} = $LayoutObject->{LanguageObject}->Translate(
'There was an error setting the entity sync status for Process entity: %s',
$CheckResult->{ProcessData}->{EntityID}
);
}
}
# build JSON output
$JSON = $LayoutObject->JSONEncode(
Data => {
%DeleteResult,
},
);
}
else {
# build JSON output
$JSON = $LayoutObject->JSONEncode(
Data => {
%{$CheckResult},
},
);
}
# send JSON response
return $LayoutObject->Attachment(
ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
Content => $JSON,
Type => 'inline',
NoCache => 1,
);
}
# ------------------------------------------------------------ #
# ProcessSync
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ProcessSync' ) {
my $Location = $ConfigObject->Get('Home') . '/Kernel/Config/Files/ZZZProcessManagement.pm';
my $ProcessDump = $ProcessObject->ProcessDump(
ResultType => 'FILE',
Location => $Location,
UserID => $Self->{UserID},
);
if ($ProcessDump) {
my $Success = $EntityObject->EntitySyncStatePurge(
UserID => $Self->{UserID},
);
if ($Success) {
return $LayoutObject->Redirect( OP => "Action=$Self->{Action}" );
}
else {
# show error if can't set state
return $LayoutObject->ErrorScreen(
Message => Translatable('There was an error setting the entity sync status.'),
);
}
}
else {
# show error if can't synch
return $LayoutObject->ErrorScreen(
Message => Translatable('There was an error synchronizing the processes.'),
);
}
}
# ------------------------------------------------------------ #
# EntityUsageCheck AJAX
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'EntityUsageCheck' ) {
my %GetParam;
for my $Param (qw(EntityType EntityID)) {
$GetParam{$Param} = $ParamObject->GetParam( Param => $Param ) || '';
}
# check needed information
return if !$GetParam{EntityType};
return if !$GetParam{EntityID};
my $EntityCheck = $Self->_CheckEntityUsage(%GetParam);
# build JSON output
my $JSON = $LayoutObject->JSONEncode(
Data => {
%{$EntityCheck},
},
);
# send JSON response
return $LayoutObject->Attachment(
ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
Content => $JSON,
Type => 'inline',
NoCache => 1,
);
}
# ------------------------------------------------------------ #
# EntityDelete AJAX
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'EntityDelete' ) {
# challenge token check for write action
$LayoutObject->ChallengeTokenCheck();
my %GetParam;
for my $Param (qw(EntityType EntityID ItemID)) {
$GetParam{$Param} = $ParamObject->GetParam( Param => $Param ) || '';
}
# check needed information
return if !$GetParam{EntityType};
return if !$GetParam{EntityID};
return if !$GetParam{ItemID};
return if $GetParam{EntityType} ne 'Activity'
&& $GetParam{EntityType} ne 'ActivityDialog'
&& $GetParam{EntityType} ne 'Transition'
&& $GetParam{EntityType} ne 'TransitionAction';
my $EntityCheck = $Self->_CheckEntityUsage(%GetParam);
my $JSON;
if ( !$EntityCheck->{Deleteable} ) {
$JSON = $LayoutObject->JSONEncode(
Data => {
Success => 0,
Message => $LayoutObject->{LanguageObject}
->Translate( 'The %s:%s is still in use', $GetParam{EntityType}, $GetParam{EntityID} ),
},
);
}
else {
# get entity
my $Method = $GetParam{EntityType} . 'Get';
my $Entity = $Kernel::OM->Get( 'Kernel::System::ProcessManagement::DB::' . $GetParam{EntityType} )->$Method(
ID => $GetParam{ItemID},
UserID => $Self->{UserID},
);
if ( $Entity->{EntityID} ne $GetParam{EntityID} ) {
$JSON = $LayoutObject->JSONEncode(
Data => {
Success => 0,
Message => $LayoutObject->{LanguageObject}->Translate(
'The %s:%s has a different EntityID',
$GetParam{EntityType}, $GetParam{ItemID}
),
},
);
}
else {
# delete entity
$Method = $GetParam{EntityType} . 'Delete';
my $Success
= $Kernel::OM->Get( 'Kernel::System::ProcessManagement::DB::' . $GetParam{EntityType} )->$Method(
ID => $GetParam{ItemID},
UserID => $Self->{UserID},
);
my $Message;
if ( !$Success ) {
$Success = 0;
$Message = $LayoutObject->{LanguageObject}
->Translate( 'Could not delete %s:%s', $GetParam{EntityType}, $GetParam{ItemID} );
}
else {
# set entitty sync state
my $Success = $EntityObject->EntitySyncStateSet(
EntityType => $GetParam{EntityType},
EntityID => $Entity->{EntityID},
SyncState => 'deleted',
UserID => $Self->{UserID},
);
# show error if cant set
if ( !$Success ) {
$Success = 0;
$Message = $LayoutObject->{LanguageObject}->Translate(
'There was an error setting the entity sync status for %s entity: %s',
$GetParam{EntityType}, $Entity->{EntityID}
);
}
}
# build JSON output
$JSON = $LayoutObject->JSONEncode(
Data => {
Success => $Success,
Message => $Message,
},
);
}
}
# send JSON response
return $LayoutObject->Attachment(
ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
Content => $JSON,
Type => 'inline',
NoCache => 1,
);
}
# ------------------------------------------------------------ #
# EntityGet AJAX
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'EntityGet' ) {
my %GetParam;
for my $Param (qw(EntityType EntityID ItemID)) {
$GetParam{$Param} = $ParamObject->GetParam( Param => $Param ) || '';
}
# check needed information
return if !$GetParam{EntityType};
return if !$GetParam{EntityID} && !$GetParam{ItemID};
return if $GetParam{EntityType} ne 'Activity'
&& $GetParam{EntityType} ne 'ActivityDialog'
&& $GetParam{EntityType} ne 'Transition'
&& $GetParam{EntityType} ne 'TransitionAction'
&& $GetParam{EntityType} ne 'Process';
# get entity
my $Method = $GetParam{EntityType} . 'Get';
my $EntityData;
if ( $GetParam{ItemID} && $GetParam{ItemID} ne '' ) {
$EntityData
= $Kernel::OM->Get( 'Kernel::System::ProcessManagement::DB::' . $GetParam{EntityType} )->$Method(
ID => $GetParam{ItemID},
UserID => $Self->{UserID},
);
}
else {
$EntityData
= $Kernel::OM->Get( 'Kernel::System::ProcessManagement::DB::' . $GetParam{EntityType} )->$Method(
EntityID => $GetParam{EntityID},
UserID => $Self->{UserID},
);
}
my $JSON;
if ( !IsHashRefWithData($EntityData) ) {
$JSON = $LayoutObject->JSONEncode(
Data => {
Success => 0,
Message => $LayoutObject->{LanguageObject}->Translate( 'Could not get %s', $GetParam{EntityType} ),
},
);
}
else {
# build JSON output
$JSON = $LayoutObject->JSONEncode(
Data => {
Success => 1,
EntityData => $EntityData,
},
);
}
# send JSON response
return $LayoutObject->Attachment(
ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
Content => $JSON,
Type => 'inline',
NoCache => 1,
);
}
# ------------------------------------------------------------ #
# UpdateSyncMessage AJAX
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'UpdateSyncMessage' ) {
# get the list of updated or deleted entities
my $EntitySyncStateList = $EntityObject->EntitySyncStateList(
UserID => $Self->{UserID}
);
# prevent errors by defining $Output as an empty string instead of undef
my $Output = '';
if ( IsArrayRefWithData($EntitySyncStateList) ) {
$Output = $LayoutObject->Notify(
Info => $SynchronizeMessage,
);
}
# send HTML response
return $LayoutObject->Attachment(
ContentType => 'text/html',
Content => $Output,
Type => 'inline',
NoCache => 1,
);
}
# ------------------------------------------------------------ #
# UpdateAccordion AJAX
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'UpdateAccordion' ) {
# ouput available process elements in the accordion
for my $Element (qw(Activity ActivityDialog Transition TransitionAction)) {
my $ElementMethod = $Element . 'ListGet';
# get a list of all elements with details
my $ElementList = $Kernel::OM->Get( 'Kernel::System::ProcessManagement::DB::' . $Element )
->$ElementMethod( UserID => $Self->{UserID} );
# check there are elements to display
if ( IsArrayRefWithData($ElementList) ) {
for my $ElementData (
sort { lc( $a->{Name} ) cmp lc( $b->{Name} ) }
@{$ElementList}
)
{
my $AvailableIn = '';
if ( $Element eq "ActivityDialog" ) {
my $ConfigAvailableIn = $ElementData->{Config}->{Interface};
if ( defined $ConfigAvailableIn ) {
my $InterfaceLength = scalar @{$ConfigAvailableIn};
if ( $InterfaceLength == 2 ) {
$AvailableIn = 'A/C';
}
elsif ( $InterfaceLength == 1 ) {
$AvailableIn = substr( $ConfigAvailableIn->[0], 0, 1 );
}
else {
$AvailableIn = 'A';
}
}
else {
$AvailableIn = 'A';
}
}
# print each element in the accordion
$LayoutObject->Block(
Name => $Element . 'Row',
Data => {
%{$ElementData},
AvailableIn => $AvailableIn, #only used for ActivityDialogs
},
);
}
}
else {
# print no data found in the accordion
$LayoutObject->Block(
Name => $Element . 'NoDataRow',
Data => {},
);
}
}
my $Output = $LayoutObject->Output(
TemplateFile => "AdminProcessManagementProcessAccordion",
Data => {},
);
# send HTML response
return $LayoutObject->Attachment(
ContentType => 'text/html',
Content => $Output,
Type => 'inline',
NoCache => 1,
);
}
# ------------------------------------------------------------ #
# UpdateScreensPath AJAX
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'UpdateScreensPath' ) {
my $Success = 1;
my $Message = '';
for my $Needed (qw(ProcessID ProcessEntityID)) {
$Param{$Needed} = $ParamObject->GetParam( Param => $Needed ) || '';
if ( !$Param{$Needed} ) {
$Success = 0;
$Message = $LayoutObject->{LanguageObject}->Translate( 'Need %s!', $Needed );
}
}
if ($Success) {
$Self->_PushSessionScreen(
ID => $Param{ProcessID},
EntityID => $Param{ProcessEntityID},
Subaction => 'ProcessEdit',
Action => 'AdminProcessManagement',
);
}
# build JSON output
my $JSON = $LayoutObject->JSONEncode(
Data => {
Success => $Success,
Message => $Message,
},
);
# send JSON response
return $LayoutObject->Attachment(
ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
Content => $JSON,
Type => 'inline',
NoCache => 1,
);
}
# ------------------------------------------------------------ #
# Overview
# ------------------------------------------------------------ #
else {
return $Self->_ShowOverview(
%Param,
);
}
}
sub _ShowOverview {
my ( $Self, %Param ) = @_;
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $Output = $LayoutObject->Header();
$Output .= $LayoutObject->NavigationBar();
# show notifications if any
if ( $Param{NotifyData} ) {
for my $Notification ( @{ $Param{NotifyData} } ) {
$Output .= $LayoutObject->Notify(
%{$Notification},
);
}
}
my @ExampleProcesses = $Kernel::OM->Get('Kernel::System::Main')->DirectoryRead(
Directory => $Kernel::OM->Get('Kernel::Config')->Get('Home') . '/var/processes/examples',
Filter => '*.yml',
);
my %ExampleProcessData;
for my $ExampleProcessFilename (@ExampleProcesses) {
my $Key = $ExampleProcessFilename;
$Key =~ s{^.*/([^/]+)$}{$1}smx;
my $Value = $Key;
$Value =~ s{^(.+).yml}{$1}smx;
$Value =~ s{_}{ }smxg;
$ExampleProcessData{$Key} = $Value;
}
my %Frontend;
$Frontend{ExampleProcessList} = $Kernel::OM->Get('Kernel::Output::HTML::Layout')->BuildSelection(
Name => 'ExampleProcess',
Data => \%ExampleProcessData,
PossibleNone => 1,
Translation => 0,
Class => 'Modernize Validate_Required',
);
$Frontend{OTRSBusinessIsInstalled} = $Kernel::OM->Get('Kernel::System::OTRSBusiness')->OTRSBusinessIsInstalled();
my $ProcessObject = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Process');
# get a process list
my $ProcessList = $ProcessObject->ProcessList( UserID => $Self->{UserID} );
if ( IsHashRefWithData($ProcessList) ) {
# Sort process list by name instead of ID (bug#12311).
my @ProcessIDs = sort { lc $ProcessList->{$a} cmp lc $ProcessList->{$b} } keys %{$ProcessList};
# get each process data
for my $ProcessID (@ProcessIDs) {
my $ProcessData = $ProcessObject->ProcessGet(
ID => $ProcessID,
UserID => $Self->{UserID},
);
# print each process in overview table
$LayoutObject->Block(
Name => 'ProcessRow',
Data => {
%{$ProcessData},
Description => $ProcessData->{Config}->{Description},
}
);
}
}
else {
# print no data found message
$LayoutObject->Block(
Name => 'ProcessNoDataRow',
Data => {},
);
}
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminProcessManagement',
Data => {
%Param,
%Frontend,
},
);
$Output .= $LayoutObject->Footer();
return $Output;
}
sub _ShowEdit {
my ( $Self, %Param ) = @_;
# get process information
my $ProcessData = $Param{ProcessData} || {};
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $StateObject = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Process::State');
if ( defined $Param{Action} && $Param{Action} eq 'Edit' ) {
# check if process is inactive and show delete action
my $State = $StateObject->StateLookup(
EntityID => $ProcessData->{StateEntityID},
UserID => $Self->{UserID},
);
if ( $State eq 'Inactive' ) {
$LayoutObject->Block(
Name => 'ProcessDeleteAction',
Data => {
%{$ProcessData},
},
);
}
# ouput available process elements in the accordion
for my $Element (qw(Activity ActivityDialog Transition TransitionAction)) {
my $ElementMethod = $Element . 'ListGet';
# get a list of all elements with details
my $ElementList = $Kernel::OM->Get( 'Kernel::System::ProcessManagement::DB::' . $Element )
->$ElementMethod( UserID => $Self->{UserID} );
# check there are elements to display
if ( IsArrayRefWithData($ElementList) ) {
for my $ElementData (
sort { lc( $a->{Name} ) cmp lc( $b->{Name} ) }
@{$ElementList}
)
{
my $AvailableIn = '';
if ( $Element eq "ActivityDialog" ) {
my $ConfigAvailableIn = $ElementData->{Config}->{Interface};
if ( defined $ConfigAvailableIn ) {
my $InterfaceLength = scalar @{$ConfigAvailableIn};
if ( $InterfaceLength == 2 ) {
$AvailableIn = 'A/C';
}
elsif ( $InterfaceLength == 1 ) {
$AvailableIn = substr( $ConfigAvailableIn->[0], 0, 1 );
}
else {
$AvailableIn = 'A';
}
}
else {
$AvailableIn = 'A';
}
}
# print each element in the accordion
$LayoutObject->Block(
Name => $Element . 'Row',
Data => {
%{$ElementData},
AvailableIn => $AvailableIn, #only used for ActivityDialogs
},
);
}
}
else {
# print no data found in the accordion
$LayoutObject->Block(
Name => $Element . 'NoDataRow',
Data => {},
);
}
}
}
# get a list of all states
my $StateList = $StateObject->StateList( UserID => $Self->{UserID} );
# get the 'inactive' state for init
my $InactiveStateID;
for my $StateID ( sort keys %{$StateList} ) {
if ( $StateList->{$StateID} =~ m{Inactive}xmsi ) {
$InactiveStateID = $StateID;
}
}
my $StateError = '';
if ( $Param{StateEntityIDServerError} ) {
$StateError = $Param{StateEntityIDServerError};
}
$Param{StateSelection} = $LayoutObject->BuildSelection(
Data => $StateList || {},
Name => 'StateEntityID',
ID => 'StateEntityID',
SelectedID => $ProcessData->{StateEntityID}
|| $InactiveStateID, # select inactive by default
Sort => 'AlphanumericKey',
Translation => 1,
Class => 'Modernize W75pc ' . $StateError,
);
my $Output = $LayoutObject->Header();
$Output .= $LayoutObject->NavigationBar();
# show notifications if any
if ( $Param{NotifyData} ) {
for my $Notification ( @{ $Param{NotifyData} } ) {
$Output .= $LayoutObject->Notify(
%{$Notification},
);
}
}
# set db dump as config settings
my $ProcessDump = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Process')->ProcessDump(
ResultType => 'HASH',
UserID => $Self->{UserID},
);
# send data to JS
$LayoutObject->AddJSData(
Key => 'ConfigProcess',
Value => {
Process => $ProcessDump->{Process},
ProcessLayout => $ProcessData->{Layout},
Activity => $ProcessDump->{Activity},
ActivityDialog => $ProcessDump->{ActivityDialog},
Transition => $ProcessDump->{Transition},
TransitionAction => $ProcessDump->{TransitionAction},
PopupPathActivity => $LayoutObject->{Baselink}
. 'Action=AdminProcessManagementActivity;Subaction=ActivityEdit;',
PopupPathPath => $LayoutObject->{Baselink} . 'Action=AdminProcessManagementPath;Subaction=PathEdit;',
}
);
$Output .= $LayoutObject->Output(
TemplateFile => "AdminProcessManagementProcess$Param{Action}",
Data => {
%Param,
%{$ProcessData},
Description => $ProcessData->{Config}->{Description} || '',
},
);
$Output .= $LayoutObject->Footer();
return $Output;
}
sub _GetParams {
my ( $Self, %Param ) = @_;
my $GetParam;
# get parameters from web browser
for my $ParamName (
qw( Name EntityID ProcessLayout Path StartActivity StartActivityDialog Description StateEntityID )
)
{
$GetParam->{$ParamName} = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam( Param => $ParamName )
|| '';
}
my $JSONObject = $Kernel::OM->Get('Kernel::System::JSON');
if ( $GetParam->{ProcessLayout} ) {
$GetParam->{ProcessLayout} = $JSONObject->Decode(
Data => $GetParam->{ProcessLayout},
);
}
if ( $GetParam->{Path} ) {
$GetParam->{Path} = $JSONObject->Decode(
Data => $GetParam->{Path},
);
}
return $GetParam;
}
sub _CheckProcessDelete {
my ( $Self, %Param ) = @_;
# get needed objects
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# get Process data
my $ProcessData = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Process')->ProcessGet(
ID => $Param{ID},
UserID => $Self->{UserID},
);
# check for valid Process data
if ( !IsHashRefWithData($ProcessData) ) {
return {
Success => 0,
Message => $LayoutObject->{LanguageObject}->Translate( 'Could not get data for ProcessID %s', $Param{ID} ),
};
}
# check that the Process is in Inactive state
my $State = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Process::State')->StateLookup(
EntityID => $ProcessData->{StateEntityID},
UserID => $Self->{UserID},
);
if ( $State ne 'Inactive' ) {
return {
Success => 0,
Message => $LayoutObject->{LanguageObject}->Translate( 'Process: %s is not Inactive', $Param{ID} ),
};
}
return {
Success => 1,
ProcessData => $ProcessData,
};
}
sub _CheckEntityUsage {
my ( $Self, %Param ) = @_;
my %Config = (
Activity => {
Parent => 'Process',
Method => 'ProcessListGet',
Array => 'Activities',
},
ActivityDialog => {
Parent => 'Activity',
Method => 'ActivityListGet',
Array => 'ActivityDialogs',
},
Transition => {
Parent => 'Process',
Method => 'ProcessListGet',
Array => 'Transitions',
},
);
my @Usage;
# transition action needs to be handled on a different way than other process parts as it does
# not depend directly on a parent part, it is nested in the process path configuration
if ( $Param{EntityType} eq 'TransitionAction' ) {
my $ProcessList = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Process')->ProcessListGet(
UserID => $Self->{UserID},
);
# search in all processes
PROCESS:
for my $Process ( @{$ProcessList} ) {
next PROCESS if !$Process->{Config}->{Path};
my $Path = $Process->{Config}->{Path};
# search on each activity on the process path
ACTIVITY:
for my $ActivityEntityID ( sort keys %{$Path} ) {
# search on each transition on the activity
TRANSITION:
for my $TransitionEntityID ( sort keys %{ $Path->{$ActivityEntityID} } ) {
next TRANSITION if !$Path->{$ActivityEntityID}->{$TransitionEntityID};
my $TransitionConfig = $Path->{$ActivityEntityID}->{$TransitionEntityID};
next TRANSITION if !$TransitionConfig->{TransitionAction};
my @TransitionActions = @{ $TransitionConfig->{TransitionAction} };
ENTITY:
for my $EntityID (@TransitionActions) {
if ( $EntityID eq $Param{EntityID} ) {
my $TransitionData
= $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Transition')->TransitionGet(
EntityID => $TransitionEntityID,
UserID => $Self->{UserID},
);
my $ActivityData
= $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Activity')->ActivityGet(
EntityID => $ActivityEntityID,
UserID => $Self->{UserID},
);
push @Usage, "$Process->{Name} -> $ActivityData->{Name} -> $TransitionData->{Name}";
last ENTITY;
}
}
}
}
}
}
else {
return if !$Config{ $Param{EntityType} };
my $Parent = $Config{ $Param{EntityType} }->{Parent};
my $Method = $Config{ $Param{EntityType} }->{Method};
my $Array = $Config{ $Param{EntityType} }->{Array};
# get a list of parents with all the details
my $List = $Kernel::OM->Get( 'Kernel::System::ProcessManagement::DB::' . $Parent )->$Method(
UserID => 1,
);
# search entity id in all parents
PARENT:
for my $ParentData ( @{$List} ) {
next PARENT if !$ParentData;
next PARENT if !$ParentData->{$Array};
ENTITY:
for my $EntityID ( @{ $ParentData->{$Array} } ) {
if ( $EntityID eq $Param{EntityID} ) {
push @Usage, $ParentData->{Name};
last ENTITY;
}
}
}
}
my $Deleteable = 0;
if ( scalar @Usage == 0 ) {
$Deleteable = 1;
}
return {
Deleteable => $Deleteable,
Usage => \@Usage,
};
}
sub _PushSessionScreen {
my ( $Self, %Param ) = @_;
# add screen to the screen path
push @{ $Self->{ScreensPath} }, {
Action => $Self->{Action} || '',
Subaction => $Param{Subaction},
ID => $Param{ID},
EntityID => $Param{EntityID},
};
# convert screens path to string (JSON)
my $JSONScreensPath = $Kernel::OM->Get('Kernel::Output::HTML::Layout')->JSONEncode(
Data => $Self->{ScreensPath},
);
# update session
$Kernel::OM->Get('Kernel::System::AuthSession')->UpdateSessionID(
SessionID => $Self->{SessionID},
Key => 'ProcessManagementScreensPath',
Value => $JSONScreensPath,
);
return 1;
}
sub _GetProcessData {
my ( $Self, %Param ) = @_;
my %ProcessData;
# get needed objects
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# get process data
my $Process = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Process')->ProcessGet(
ID => $Param{ID},
UserID => $Self->{UserID},
);
if ( !$Process ) {
return $LayoutObject->ErrorScreen(
Message => $LayoutObject->{LanguageObject}->Translate( 'Unknown Process %s!', $Param{ID} ),
);
}
$ProcessData{Process} = $Process;
# get all used activities
for my $ActivityEntityID ( @{ $Process->{Activities} } ) {
my $Activity = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Activity')->ActivityGet(
EntityID => $ActivityEntityID,
UserID => $Self->{UserID},
);
$ProcessData{Activities}->{$ActivityEntityID} = $Activity;
# get all used activity dialogs
for my $ActivityDialogEntityID ( @{ $Activity->{ActivityDialogs} } ) {
my $ActivityDialog
= $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::ActivityDialog')->ActivityDialogGet(
EntityID => $ActivityDialogEntityID,
UserID => $Self->{UserID},
);
$ProcessData{ActivityDialogs}->{$ActivityDialogEntityID} = $ActivityDialog;
}
}
# get all used transitions
for my $TransitionEntityID ( @{ $Process->{Transitions} } ) {
my $Transition = $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::Transition')->TransitionGet(
EntityID => $TransitionEntityID,
UserID => $Self->{UserID},
);
$ProcessData{Transitions}->{$TransitionEntityID} = $Transition;
}
# get all used transition actions
for my $TransitionActionEntityID ( @{ $Process->{TransitionActions} } ) {
my $TransitionAction
= $Kernel::OM->Get('Kernel::System::ProcessManagement::DB::TransitionAction')->TransitionActionGet(
EntityID => $TransitionActionEntityID,
UserID => $Self->{UserID},
);
$ProcessData{TransitionActions}->{$TransitionActionEntityID} = $TransitionAction;
}
return \%ProcessData;
}
1;