# -- # Copyright (C) 2001-2016 OTRS AG, http://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (AGPL). If you # did not receive this file, see http://www.gnu.org/licenses/agpl.txt. # -- package Kernel::Modules::CustomerTicketProcess; ## nofilter(TidyAll::Plugin::OTRS::Perl::DBObject) use strict; use warnings; 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; # global config hash for id dissolution $Self->{NameToID} = { Title => 'Title', State => 'StateID', StateID => 'StateID', Lock => 'LockID', LockID => 'LockID', Priority => 'PriorityID', PriorityID => 'PriorityID', Queue => 'QueueID', QueueID => 'QueueID', Customer => 'CustomerID', CustomerID => 'CustomerID', CustomerNo => 'CustomerID', CustomerUserID => 'CustomerUserID', Type => 'TypeID', TypeID => 'TypeID', SLA => 'SLAID', SLAID => 'SLAID', Service => 'ServiceID', ServiceID => 'ServiceID', Article => 'Article', }; return $Self; } sub Run { my ( $Self, %Param ) = @_; # get param object my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); my $TicketID = $ParamObject->GetParam( Param => 'TicketID' ); my $ActivityDialogEntityID = $ParamObject->GetParam( Param => 'ActivityDialogEntityID' ); my $ActivityDialogHashRef; # get needed objects my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket'); my $ActivityDialogObject = $Kernel::OM->Get('Kernel::System::ProcessManagement::ActivityDialog'); # some fields should be skipped for the customer interface my $SkipFields = [ 'Owner', 'Responsible', 'Lock', 'PendingTime', 'CustomerID' ]; if ($TicketID) { # include extra fields should be skipped for my $Item (qw(Service SLA Queue)) { push @{$SkipFields}, $Item; } # check if there is a configured required permission # for the ActivityDialog (if there is one) my $ActivityDialogPermission = 'rw'; if ($ActivityDialogEntityID) { $ActivityDialogHashRef = $ActivityDialogObject->ActivityDialogGet( ActivityDialogEntityID => $ActivityDialogEntityID, Interface => 'CustomerInterface', ); if ( !IsHashRefWithData($ActivityDialogHashRef) ) { return $LayoutObject->CustomerErrorScreen( Message => $LayoutObject->{LanguageObject} ->Translate( 'Couldn\'t get ActivityDialogEntityID "%s"!', $ActivityDialogEntityID ), Comment => Translatable('Please contact the admin.'), ); } if ( $ActivityDialogHashRef->{Permission} ) { $ActivityDialogPermission = $ActivityDialogHashRef->{Permission}; } } # check permissions my $Access = $TicketObject->TicketCustomerPermission( Type => $ActivityDialogPermission, TicketID => $Self->{TicketID}, UserID => $Self->{UserID} ); # error screen, don't show ticket if ( !$Access ) { return $LayoutObject->CustomerNoPermission( Message => $LayoutObject->{LanguageObject}->Translate( 'You need %s permissions!', $ActivityDialogPermission ), WithHeader => 'yes', ); } # get ACL restrictions my %PossibleActions = ( 1 => $Self->{Action} ); my $ACL = $TicketObject->TicketAcl( Data => \%PossibleActions, Action => $Self->{Action}, TicketID => $Self->{TicketID}, ReturnType => 'Action', ReturnSubType => '-', CustomerUserID => $Self->{UserID}, ); my %AclAction = $TicketObject->TicketAclActionData(); # check if ACL restrictions exist if ( $ACL || IsHashRefWithData( \%AclAction ) ) { my %AclActionLookup = reverse %AclAction; # show error screen if ACL prohibits this action if ( !$AclActionLookup{ $Self->{Action} } ) { return $LayoutObject->CustomerNoPermission( WithHeader => 'yes' ); } } if ( IsHashRefWithData($ActivityDialogHashRef) ) { my $PossibleActivityDialogs = { 1 => $ActivityDialogEntityID }; # get ACL restrictions my $ACL = $TicketObject->TicketAcl( Data => $PossibleActivityDialogs, ActivityDialogEntityID => $ActivityDialogEntityID, TicketID => $TicketID, ReturnType => 'ActivityDialog', ReturnSubType => '-', CustomerUserID => $Self->{UserID}, ); if ($ACL) { %{$PossibleActivityDialogs} = $TicketObject->TicketAclData(); } # check if ACL resctictions exist if ( !IsHashRefWithData($PossibleActivityDialogs) ) { return $LayoutObject->CustomerNoPermission( WithHeader => 'yes' ); } } } # list only Active processes by default my @ProcessStates = ('Active'); # set IsMainWindow and IsAjaxRequest for proper error responses, screen display and process list $Self->{IsMainWindow} = $ParamObject->GetParam( Param => 'IsMainWindow' ) || ''; $Self->{IsAjaxRequest} = $ParamObject->GetParam( Param => 'IsAjaxRequest' ) || ''; # fetch also FadeAway processes to continue working with existing tickets, but not to start new # ones if ( !$Self->{IsMainWindow} && $Self->{Subaction} ) { push @ProcessStates, 'FadeAway' } # get process object my $ProcessObject = $Kernel::OM->Get('Kernel::System::ProcessManagement::Process'); # get the list of processes that customer can start my $ProcessList = $ProcessObject->ProcessList( ProcessState => \@ProcessStates, Interface => ['CustomerInterface'], ); # also get the list of processes initiated by agents, as an activity dialog might be configured # for the customer interface my $FollowupProcessList = $ProcessObject->ProcessList( ProcessState => \@ProcessStates, Interface => [ 'AgentInterface', 'CustomerInterface' ], ); my $ProcessEntityID = $ParamObject->GetParam( Param => 'ProcessEntityID' ); if ( !IsHashRefWithData($ProcessList) && !IsHashRefWithData($FollowupProcessList) ) { return $LayoutObject->CustomerErrorScreen( Message => Translatable('No Process configured!'), Comment => Translatable('Please contact the admin.'), ); } # prepare process list for ACLs, use only entities instead of names, convert from # P1 => Name to P1 => P1. As ACLs should work only against entities my %ProcessListACL = map { $_ => $_ } sort keys %{$ProcessList}; # validate the ProcessList with stored ACLs my $ACL = $TicketObject->TicketAcl( ReturnType => 'Process', ReturnSubType => '-', Data => \%ProcessListACL, CustomerUserID => $Self->{UserID}, ); if ( IsHashRefWithData($ProcessList) && $ACL ) { # get ACL results my %ACLData = $TicketObject->TicketAclData(); # recover process names my %ReducedProcessList = map { $_ => $ProcessList->{$_} } sort keys %ACLData; # replace original process list with the reduced one $ProcessList = \%ReducedProcessList; } # if we have no subaction display the process list to start a new one if ( !$Self->{Subaction} ) { # to display the process list is mandatory to have processes that customer can start if ( !IsHashRefWithData($ProcessList) ) { return $LayoutObject->CustomerErrorScreen( Message => Translatable('No Process configured!'), Comment => Translatable('Please contact the admin.'), ); } # get process id (if any, a process should be pre-selected) $Param{ProcessID} = $ParamObject->GetParam( Param => 'ID' ); if ( $Param{ProcessID} ) { $Param{PreSelectProcess} = 1; } return $Self->_DisplayProcessList( %Param, ProcessList => $ProcessList, ProcessEntityID => $ProcessEntityID ); } # check if the selected process from the list is valid, prevent tamper with process selection # list (not existing, invalid an fade away processes must not be able to start a new process # ticket) elsif ( $Self->{Subaction} eq 'DisplayActivityDialogAJAX' && !$ProcessList->{$ProcessEntityID} && $Self->{IsMainWindow} ) { # translate the error message (as it will be injected in the HTML) my $ErrorMessage = $LayoutObject->{LanguageObject}->Translate("The selected process is invalid!"); # return a predefined HTML sctructure as the AJAX call is expecting and HTML response return $LayoutObject->Attachment( ContentType => 'text/html; charset=' . $LayoutObject->{Charset}, Content => '
', Type => 'inline', NoCache => 1, ); } # if invalid process is detected on a ActivityDilog popup screen show an error message elsif ( $Self->{Subaction} eq 'DisplayActivityDialog' && !$FollowupProcessList->{$ProcessEntityID} && !$Self->{IsMainWindow} ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Process %s is invalid!', $ProcessEntityID ), Comment => Translatable('Please contact the admin.'), ); } # Get the necessary parameters # collects a mixture of present values bottom to top: # SysConfig DefaultValues, ActivityDialog DefaultValues, TicketValues, SubmittedValues # including ActivityDialogEntityID and ProcessEntityID # is used for: # - Parameter checking before storing # - will be used for ACL checking later on my $GetParam = $Self->_GetParam( ProcessEntityID => $ProcessEntityID, ); # get form id $Self->{FormID} = $ParamObject->GetParam( Param => 'FormID' ); # create form id if ( !$Self->{FormID} ) { $Self->{FormID} = $Kernel::OM->Get('Kernel::System::Web::UploadCache')->FormIDCreate(); } if ( $Self->{Subaction} eq 'StoreActivityDialog' && $ProcessEntityID ) { $LayoutObject->ChallengeTokenCheck( Type => 'Customer' ); return $Self->_StoreActivityDialog( %Param, ProcessName => $ProcessList->{$ProcessEntityID}, ProcessEntityID => $ProcessEntityID, GetParam => $GetParam, ); } if ( $Self->{Subaction} eq 'DisplayActivityDialog' && $ProcessEntityID ) { return $Self->_OutputActivityDialog( %Param, ProcessEntityID => $ProcessEntityID, GetParam => $GetParam, ); } if ( $Self->{Subaction} eq 'DisplayActivityDialogAJAX' && $ProcessEntityID ) { my $ActivityDialogHTML = $Self->_OutputActivityDialog( %Param, ProcessEntityID => $ProcessEntityID, GetParam => $GetParam, ); return $LayoutObject->Attachment( ContentType => 'text/html; charset=' . $LayoutObject->{Charset}, Content => $ActivityDialogHTML, Type => 'inline', NoCache => 1, ); } elsif ( $Self->{Subaction} eq 'AJAXUpdate' ) { return $Self->_RenderAjax( %Param, ProcessEntityID => $ProcessEntityID, GetParam => $GetParam, ); } return $LayoutObject->CustomerErrorScreen( Message => Translatable('Subaction is invalid!'), Comment => Translatable('Please contact the admin.'), ); } sub _RenderAjax { # FatalError is safe because a JSON structure is expecting, then it will result into a # communications error my ( $Self, %Param ) = @_; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(ProcessEntityID)) { if ( !$Param{$Needed} ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderAjax' ), ); } } my $ActivityDialogEntityID = $Param{GetParam}{ActivityDialogEntityID}; if ( !$ActivityDialogEntityID ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', 'ActivityDialogEntityID', '_RenderAjax' ), ); } my $ActivityDialog = $Kernel::OM->Get('Kernel::System::ProcessManagement::ActivityDialog')->ActivityDialogGet( ActivityDialogEntityID => $ActivityDialogEntityID, Interface => 'CustomerInterface', ); if ( !IsHashRefWithData($ActivityDialog) ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'No ActivityDialog configured for %s in _RenderAjax!', $ActivityDialogEntityID ), ); } # get list type my $TreeView = 0; if ( $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Frontend::ListType') eq 'tree' ) { $TreeView = 1; } my %FieldsProcessed; my @JSONCollector; my $Services; # All submitted DynamicFields # get dynamic field values form http request my %DynamicFieldValues; # get backend object my $BackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend'); my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet( Valid => 1, ObjectType => 'Ticket', ); # reduce the dynamic fields to only the ones that are desinged for customer interface my @CustomerDynamicFields; DYNAMICFIELD: for my $DynamicFieldConfig ( @{$DynamicField} ) { next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig); my $IsCustomerInterfaceCapable = $BackendObject->HasBehavior( DynamicFieldConfig => $DynamicFieldConfig, Behavior => 'IsCustomerInterfaceCapable', ); next DYNAMICFIELD if !$IsCustomerInterfaceCapable; push @CustomerDynamicFields, $DynamicFieldConfig; } $DynamicField = \@CustomerDynamicFields; # get param object my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); # cycle trough the activated Dynamic Fields for this screen DYNAMICFIELD: for my $DynamicFieldConfig ( @{$DynamicField} ) { next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig); # extract the dynamic field value form the web request $DynamicFieldValues{ $DynamicFieldConfig->{Name} } = $BackendObject->EditFieldValueGet( DynamicFieldConfig => $DynamicFieldConfig, ParamObject => $ParamObject, LayoutObject => $LayoutObject, ); } # convert dynamic field values into a structure for ACLs my %DynamicFieldCheckParam; DYNAMICFIELD: for my $DynamicField ( sort keys %DynamicFieldValues ) { next DYNAMICFIELD if !$DynamicField; next DYNAMICFIELD if !$DynamicFieldValues{$DynamicField}; $DynamicFieldCheckParam{ 'DynamicField_' . $DynamicField } = $DynamicFieldValues{$DynamicField}; } $Param{GetParam}->{DynamicField} = \%DynamicFieldCheckParam; # some fields should be skipped for the customer interface my $SkipFields = [ 'Owner', 'Responsible', 'Lock', 'PendingTime', 'CustomerID' ]; # Get the activity dialog's Submit Param's or Config Params DIALOGFIELD: for my $CurrentField ( @{ $ActivityDialog->{FieldOrder} } ) { # some fields should be skipped for the customer interface next DIALOGFIELD if ( grep { $_ eq $CurrentField } @{$SkipFields} ); # Skip if we're working on a field that was already done with or without ID if ( $Self->{NameToID}{$CurrentField} && $FieldsProcessed{ $Self->{NameToID}{$CurrentField} } ) { next DIALOGFIELD; } if ( $CurrentField =~ m{^DynamicField_(.*)}xms ) { my $DynamicFieldName = $1; my $DynamicFieldConfig = ( grep { $_->{Name} eq $DynamicFieldName } @{$DynamicField} )[0]; next DIALOGFIELD if !IsHashRefWithData($DynamicFieldConfig); my $IsACLReducible = $BackendObject->HasBehavior( DynamicFieldConfig => $DynamicFieldConfig, Behavior => 'IsACLReducible', ); next DIALOGFIELD if !$IsACLReducible; my $PossibleValues = $BackendObject->PossibleValuesGet( DynamicFieldConfig => $DynamicFieldConfig, ); # convert possible values key => value to key => key for ACLs using a Hash slice my %AclData = %{$PossibleValues}; @AclData{ keys %AclData } = keys %AclData; # get ticket object my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket'); # set possible values filter from ACLs my $ACL = $TicketObject->TicketAcl( %{ $Param{GetParam} }, ReturnType => 'Ticket', ReturnSubType => 'DynamicField_' . $DynamicFieldConfig->{Name}, Data => \%AclData, CustomerUserID => $Self->{UserID}, ); if ($ACL) { my %Filter = $TicketObject->TicketAclData(); # convert Filer key => key back to key => value using map %{$PossibleValues} = map { $_ => $PossibleValues->{$_} } keys %Filter; } my $DataValues = $BackendObject->BuildSelectionDataGet( DynamicFieldConfig => $DynamicFieldConfig, PossibleValues => $PossibleValues, Value => $Param{GetParam}{ 'DynamicField_' . $DynamicFieldConfig->{Name} }, ) || $PossibleValues; # add dynamic field to the JSONCollector push( @JSONCollector, { Name => 'DynamicField_' . $DynamicFieldConfig->{Name}, Data => $DataValues, SelectedID => $DynamicFieldValues{ $DynamicFieldConfig->{Name} }, Translation => $DynamicFieldConfig->{Config}->{TranslatableValues} || 0, Max => 100, } ); } elsif ( $Self->{NameToID}{$CurrentField} eq 'QueueID' ) { next DIALOGFIELD if $FieldsProcessed{ $Self->{NameToID}{$CurrentField} }; my $Data = $Self->_GetQueues( %{ $Param{GetParam} }, ); # add Queue to the JSONCollector push( @JSONCollector, { Name => $Self->{NameToID}{$CurrentField}, Data => $Data, SelectedID => $Param{GetParam}{ $Self->{NameToID}{$CurrentField} }, PossibleNone => 1, Translation => 0, TreeView => $TreeView, Max => 100, }, ); $FieldsProcessed{ $Self->{NameToID}{$CurrentField} } = 1; } elsif ( $Self->{NameToID}{$CurrentField} eq 'StateID' ) { next DIALOGFIELD if $FieldsProcessed{ $Self->{NameToID}{$CurrentField} }; my $Data = $Self->_GetStates( %{ $Param{GetParam} }, ); # add State to the JSONCollector push( @JSONCollector, { Name => 'StateID', Data => $Data, SelectedID => $Param{GetParam}{ $Self->{NameToID}{$CurrentField} }, Translation => 1, Max => 100, }, ); $FieldsProcessed{ $Self->{NameToID}{$CurrentField} } = 1; } elsif ( $Self->{NameToID}{$CurrentField} eq 'PriorityID' ) { next DIALOGFIELD if $FieldsProcessed{ $Self->{NameToID}{$CurrentField} }; my $Data = $Self->_GetPriorities( %{ $Param{GetParam} }, ); # add Priority to the JSONCollector push( @JSONCollector, { Name => $Self->{NameToID}{$CurrentField}, Data => $Data, SelectedID => $Param{GetParam}{ $Self->{NameToID}{$CurrentField} }, Translation => 1, Max => 100, }, ); $FieldsProcessed{ $Self->{NameToID}{$CurrentField} } = 1; } elsif ( $Self->{NameToID}{$CurrentField} eq 'ServiceID' ) { next DIALOGFIELD if $FieldsProcessed{ $Self->{NameToID}{$CurrentField} }; my $Data = $Self->_GetServices( %{ $Param{GetParam} }, ); $Services = $Data; # add Service to the JSONCollector (Use ServiceID from web request) push( @JSONCollector, { Name => $Self->{NameToID}{$CurrentField}, Data => $Data, SelectedID => $ParamObject->GetParam( Param => 'ServiceID' ) || '', PossibleNone => 1, Translation => 0, TreeView => $TreeView, Max => 100, }, ); $FieldsProcessed{ $Self->{NameToID}{$CurrentField} } = 1; } elsif ( $Self->{NameToID}{$CurrentField} eq 'SLAID' ) { next DIALOGFIELD if $FieldsProcessed{ $Self->{NameToID}{$CurrentField} }; # if SLA is render before service (by it order in the fields) it needs to create # the service list if ( !IsHashRefWithData($Services) ) { $Services = $Self->_GetServices( %{ $Param{GetParam} }, ); } my $Data = $Self->_GetSLAs( %{ $Param{GetParam} }, Services => $Services, ServiceID => $ParamObject->GetParam( Param => 'ServiceID' ) || '', ); # add SLA to the JSONCollector (Use SelectedID from web request) push( @JSONCollector, { Name => $Self->{NameToID}{$CurrentField}, Data => $Data, SelectedID => $ParamObject->GetParam( Param => 'SLAID' ) || '', PossibleNone => 1, Translation => 0, Max => 100, }, ); $FieldsProcessed{ $Self->{NameToID}{$CurrentField} } = 1; } } my $JSON = $LayoutObject->BuildSelectionJSON( [@JSONCollector] ); return $LayoutObject->Attachment( ContentType => 'application/json; charset=' . $LayoutObject->{Charset}, Content => $JSON, Type => 'inline', NoCache => 1, ); } =item _GetParam() returns the current data state of the submitted information This contains the following data for the different callers: Initial call with selected Process: ProcessEntityID ActivityDialogEntityID DefaultValues for the configured Fields in that ActivityDialog DefaultValues for the 4 required Fields Queue State Lock Priority First Store call submitting an Activity Dialog: ProcessEntityID ActivityDialogEntityID SubmittedValues for the current ActivityDialog ActivityDialog DefaultValues for invisible fields of that ActivityDialog DefaultValues for the 4 required Fields Queue State Lock Priority if not configured in the ActivityDialog ActivityDialog fillout request on existing Ticket: ProcessEntityID ActivityDialogEntityID TicketValues ActivityDialog store request or AjaxUpdate request on existing Tickets: ProcessEntityID ActivityDialogEntityID TicketValues for all not-Submitted Values Submitted Values my $GetParam = _GetParam( ProcessEntityID => $ProcessEntityID, ); =cut sub _GetParam { my ( $Self, %Param ) = @_; #my $IsAJAXUpdate = $Param{AJAX} || ''; # get needed objects my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); for my $Needed (qw(ProcessEntityID)) { if ( !$Param{$Needed} ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_GetParam' ), ); } } my %GetParam; my %Ticket; my $ProcessEntityID = $Param{ProcessEntityID}; my $TicketID = $ParamObject->GetParam( Param => 'TicketID' ); my $ActivityDialogEntityID = $ParamObject->GetParam( Param => 'ActivityDialogEntityID', ); my $ActivityEntityID; my %ValuesGotten; my $Value; # If we got no ActivityDialogEntityID and no TicketID # we have to get the Processes' Startpoint if ( !$ActivityDialogEntityID && !$TicketID ) { my $ActivityActivityDialog = $Kernel::OM->Get('Kernel::System::ProcessManagement::Process')->ProcessStartpointGet( ProcessEntityID => $ProcessEntityID, ); if ( !$ActivityActivityDialog->{ActivityDialog} || !$ActivityActivityDialog->{Activity} ) { my $Message = $LayoutObject->{LanguageObject}->Translate( 'Got no Start ActivityEntityID or Start ActivityDialogEntityID for Process: %s in _GetParam!', $ProcessEntityID ); # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Message, ); } $LayoutObject->CustomerFatalError( Message => $Message, ); } $ActivityDialogEntityID = $ActivityActivityDialog->{ActivityDialog}; $ActivityEntityID = $ActivityActivityDialog->{Activity}; } my $ActivityDialog = $Kernel::OM->Get('Kernel::System::ProcessManagement::ActivityDialog')->ActivityDialogGet( ActivityDialogEntityID => $ActivityDialogEntityID, Interface => 'CustomerInterface', ); if ( !IsHashRefWithData($ActivityDialog) ) { return $LayoutObject->CustomerErrorScreen( Message => $LayoutObject->{LanguageObject} ->Translate( 'Couldn\'t get ActivityDialogEntityID "%s"!', $ActivityDialogEntityID ), Comment => Translatable('Please contact the admin.'), ); } # get config object my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); # if there is a ticket then is not an AJAX request if ($TicketID) { %Ticket = $Kernel::OM->Get('Kernel::System::Ticket')->TicketGet( TicketID => $TicketID, UserID => $ConfigObject->Get('CustomerPanelUserID'), DynamicFields => 1, ); %GetParam = %Ticket; if ( !IsHashRefWithData( \%GetParam ) ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Couldn\'t get Ticket for TicketID: %s in _GetParam!', $TicketID ), ); } $ActivityEntityID = $Ticket{ 'DynamicField_' . $ConfigObject->Get("Process::DynamicFieldProcessManagementActivityID") }; if ( !$ActivityEntityID ) { $LayoutObject->CustomerFatalError( Message => Translatable('Couldn\'t determine ActivityEntityID. DynamicField or Config isn\'t set properly!'), ); } } $GetParam{ActivityDialogEntityID} = $ActivityDialogEntityID; $GetParam{ActivityEntityID} = $ActivityEntityID; $GetParam{ProcessEntityID} = $ProcessEntityID; # some fields should be skipped for the customer interface my $SkipFields = [ 'Owner', 'Responsible', 'Lock', 'PendingTime', 'CustomerID' ]; my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet( Valid => 1, ObjectType => 'Ticket', ); # get backend object my $BackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend'); # reduce the dynamic fields to only the ones that are desinged for customer interface my @CustomerDynamicFields; DYNAMICFIELD: for my $DynamicFieldConfig ( @{$DynamicField} ) { next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig); my $IsCustomerInterfaceCapable = $BackendObject->HasBehavior( DynamicFieldConfig => $DynamicFieldConfig, Behavior => 'IsCustomerInterfaceCapable', ); next DYNAMICFIELD if !$IsCustomerInterfaceCapable; push @CustomerDynamicFields, $DynamicFieldConfig; } $DynamicField = \@CustomerDynamicFields; # Get the activitydialogs's Submit Param's or Config Params DIALOGFIELD: for my $CurrentField ( @{ $ActivityDialog->{FieldOrder} } ) { # some fields should be skipped for the customer interface next DIALOGFIELD if ( grep { $_ eq $CurrentField } @{$SkipFields} ); # Skip if we're working on a field that was already done with or without ID if ( $Self->{NameToID}{$CurrentField} && $ValuesGotten{ $Self->{NameToID}{$CurrentField} } ) { next DIALOGFIELD; } if ( $CurrentField =~ m{^DynamicField_(.*)}xms ) { my $DynamicFieldName = $1; # Get the Config of the current DynamicField (the first element of the grep result array) my $DynamicFieldConfig = ( grep { $_->{Name} eq $DynamicFieldName } @{$DynamicField} )[0]; if ( !IsHashRefWithData($DynamicFieldConfig) ) { my $Message = "DynamicFieldConfig missing for field: $Param{FieldName}, or is not a Ticket Dynamic Field!"; # log error but does not stop the execution as it could be an old Article # DynamicField, see bug#11666 $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => $Message, ); next DIALOGFIELD; } # Get DynamicField Values $Value = $BackendObject->EditFieldValueGet( DynamicFieldConfig => $DynamicFieldConfig, ParamObject => $ParamObject, LayoutObject => $LayoutObject, ); # If we got a submitted param, take it and next out if ( defined $Value && ( $Value eq '' || IsStringWithData($Value) || IsArrayRefWithData($Value) || IsHashRefWithData($Value) ) ) { $GetParam{$CurrentField} = $Value; next DIALOGFIELD; } # If we didn't have a Param Value try the ticket Value # next out if it was successful if ( defined $Ticket{$CurrentField} && ( $Ticket{$CurrentField} eq '' || IsStringWithData( $Ticket{$CurrentField} ) || IsArrayRefWithData( $Ticket{$CurrentField} ) || IsHashRefWithData( $Ticket{$CurrentField} ) ) ) { $GetParam{$CurrentField} = $Ticket{$CurrentField}; next DIALOGFIELD; } # If we had neighter submitted nor ticket param get the ActivityDialog's default Value # next out if it was successful $Value = $ActivityDialog->{Fields}{$CurrentField}{DefaultValue}; if ($Value) { $GetParam{$CurrentField} = $Value; next DIALOGFIELD; } # If we had no submitted, ticket or ActivityDialog default value # use the DynamicField's default value and next out $Value = $DynamicFieldConfig->{Config}{DefaultValue}; if ($Value) { $GetParam{$CurrentField} = $Value; next DIALOGFIELD; } # if all that failed then the field should not have a defined value otherwise # if a value (even empty) is sent, fields like Date or DateTime will mark the field as # used with the field display value, this could lead to unwanted field sets, # see bug#9159 next DIALOGFIELD; } # get article fields if ( $CurrentField eq 'Article' ) { $GetParam{Subject} = $ParamObject->GetParam( Param => 'Subject' ); $GetParam{Body} = $ParamObject->GetParam( Param => 'Body' ); @{ $GetParam{InformUserID} } = $ParamObject->GetArray( Param => 'InformUserID', ); $ValuesGotten{Article} = 1 if ( $GetParam{Subject} && $GetParam{Body} ); } if ( $CurrentField eq 'CustomerID' ) { $GetParam{Customer} = $ParamObject->GetParam( Param => 'SelectedCustomerUser', ) || ''; $GetParam{CustomerUserID} = $ParamObject->GetParam( Param => 'SelectedCustomerUser', ) || ''; } # Non DynamicFields # 1. try to get the required param my $Value = $ParamObject->GetParam( Param => $Self->{NameToID}{$CurrentField} ); if ($Value) { # if we have an ID field make sure the value without ID won't be in the # %GetParam Hash any more if ( $Self->{NameToID}{$CurrentField} =~ m{(.*)ID$}xms ) { $GetParam{$1} = undef; } $GetParam{ $Self->{NameToID}{$CurrentField} } = $Value; $ValuesGotten{ $Self->{NameToID}{$CurrentField} } = 1; next DIALOGFIELD; } # If we got ticket params, the GetParam Hash was already filled before the loop # and we can next out if ( $GetParam{ $Self->{NameToID}{$CurrentField} } ) { $ValuesGotten{ $Self->{NameToID}{$CurrentField} } = 1; next DIALOGFIELD; } # if no Submitted nore Ticket Param get ActivityDialog Config's Param if ( $CurrentField ne 'CustomerID' ) { $Value = $ActivityDialog->{Fields}{$CurrentField}{DefaultValue}; } if ($Value) { $ValuesGotten{ $Self->{NameToID}{$CurrentField} } = 1; $GetParam{$CurrentField} = $Value; next DIALOGFIELD; } } REQUIREDFIELDLOOP: for my $CurrentField (qw(Queue State Lock Priority)) { $Value = undef; if ( !$ValuesGotten{ $Self->{NameToID}{$CurrentField} } ) { $Value = $ConfigObject->Get("Process::Default$CurrentField"); if ( !$Value ) { my $Message = $LayoutObject->{LanguageObject} ->Translate( 'Process::Default%s Config Value missing!', $CurrentField ); # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Message, ); } $LayoutObject->CustomerFatalError( Message => $Message, ); } $GetParam{$CurrentField} = $Value; $ValuesGotten{ $Self->{NameToID}{$CurrentField} } = 1; } } # get also the IDs for the Required files (if they are not present) if ( $GetParam{Queue} && !$GetParam{QueueID} ) { $GetParam{QueueID} = $Kernel::OM->Get('Kernel::System::Queue')->QueueLookup( Queue => $GetParam{Queue} ); } if ( $GetParam{State} && !$GetParam{StateID} ) { $GetParam{StateID} = $Kernel::OM->Get('Kernel::System::State')->StateLookup( State => $GetParam{State} ); } if ( $GetParam{Lock} && !$GetParam{LockID} ) { $GetParam{LockID} = $Kernel::OM->Get('Kernel::System::Lock')->LockLookup( Lock => $GetParam{Lock} ); } if ( $GetParam{Priority} && !$GetParam{PriorityID} ) { $GetParam{PriorityID} = $Kernel::OM->Get('Kernel::System::Priority')->PriorityLookup( Priority => $GetParam{Priority}, ); } # and finally we'll have the special parameters: $GetParam{ResponsibleAll} = $ParamObject->GetParam( Param => 'ResponsibleAll' ); $GetParam{OwnerAll} = $ParamObject->GetParam( Param => 'OwnerAll' ); return \%GetParam; } sub _OutputActivityDialog { my ( $Self, %Param ) = @_; my $TicketID = $Param{GetParam}{TicketID}; my $ActivityDialogEntityID = $Param{GetParam}{ActivityDialogEntityID}; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); # Check needed parameters: # ProcessEntityID only # TicketID ActivityDialogEntityID if ( !$Param{ProcessEntityID} || ( !$TicketID && !$ActivityDialogEntityID ) ) { my $Message = Translatable('Got no ProcessEntityID or TicketID and ActivityDialogEntityID!'); # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Message, ); } $LayoutObject->CustomerFatalError( Message => $Message, ); } my $ActivityActivityDialog; my %Ticket; my %Error = (); my %ErrorMessage = (); # If we had Errors, we got an Errorhash %Error = %{ $Param{Error} } if ( IsHashRefWithData( $Param{Error} ) ); %ErrorMessage = %{ $Param{ErrorMessage} } if ( IsHashRefWithData( $Param{ErrorMessage} ) ); # get process object my $ProcessObject = $Kernel::OM->Get('Kernel::System::ProcessManagement::Process'); my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); if ( !$TicketID ) { $ActivityActivityDialog = $ProcessObject->ProcessStartpointGet( ProcessEntityID => $Param{ProcessEntityID}, ); if ( !IsHashRefWithData($ActivityActivityDialog) ) { my $Message = $LayoutObject->{LanguageObject}->Translate( 'Can\'t get StartActivityDialog and StartActivityDialog for the ProcessEntityID "%s"!', $Param{ProcessEntityID} ); # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Message, ); } $LayoutObject->CustomerFatalError( Message => $Message, ); } } else { # no AJAX update in this part %Ticket = $Kernel::OM->Get('Kernel::System::Ticket')->TicketGet( TicketID => $TicketID, UserID => $ConfigObject->Get('CustomerPanelUserID'), DynamicFields => 1, ); if ( !IsHashRefWithData( \%Ticket ) ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Can\'t get Ticket "%s"!', $Param{TicketID} ), ); } my $DynamicFieldProcessID = 'DynamicField_' . $ConfigObject->Get('Process::DynamicFieldProcessManagementProcessID'); my $DynamicFieldActivityID = 'DynamicField_' . $ConfigObject->Get('Process::DynamicFieldProcessManagementActivityID'); if ( !$Ticket{$DynamicFieldProcessID} || !$Ticket{$DynamicFieldActivityID} ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Can\'t get ProcessEntityID or ActivityEntityID for Ticket "%s"!', $Param{TicketID} ), ); } $ActivityActivityDialog = { Activity => $Ticket{$DynamicFieldActivityID}, ActivityDialog => $ActivityDialogEntityID, }; } my $Activity = $Kernel::OM->Get('Kernel::System::ProcessManagement::Activity')->ActivityGet( Interface => 'CustomerInterface', ActivityEntityID => $ActivityActivityDialog->{Activity} ); if ( !$Activity ) { my $Message = $LayoutObject->{LanguageObject}->Translate( 'Can\'t get Activity configuration for ActivityEntityID "%s"!', $ActivityActivityDialog->{Activity} ); # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Message, ); } $LayoutObject->CustomerFatalError( Message => $Message, ); } my $ActivityDialog = $Kernel::OM->Get('Kernel::System::ProcessManagement::ActivityDialog')->ActivityDialogGet( ActivityDialogEntityID => $ActivityActivityDialog->{ActivityDialog}, Interface => 'CustomerInterface', ); if ( !IsHashRefWithData($ActivityDialog) ) { my $Message = $LayoutObject->{LanguageObject}->Translate( 'Can\'t get ActivityDialog configuration for ActivityDialogEntityID "%s"!', $ActivityActivityDialog->{ActivityDialog} ); # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Message, ); } $LayoutObject->CustomerFatalError( Message => $Message, ); } # grep out Overwrites if defined on the Activity my @OverwriteActivityDialogNumber = grep { ref $Activity->{ActivityDialog}{$_} eq 'HASH' && $Activity->{ActivityDialog}{$_}{ActivityDialogEntityID} && $Activity->{ActivityDialog}{$_}{ActivityDialogEntityID} eq $ActivityActivityDialog->{ActivityDialog} && IsHashRefWithData( $Activity->{ActivityDialog}{$_}{Overwrite} ) } keys %{ $Activity->{ActivityDialog} }; # let the Overwrites Overwrite the ActivityDialog's Hashvalues if ( $OverwriteActivityDialogNumber[0] ) { %{$ActivityDialog} = ( %{$ActivityDialog}, %{ $Activity->{ActivityDialog}{ $OverwriteActivityDialogNumber[0] }{Overwrite} } ); } # Add PageHeader, Navbar, Formheader (Process/ActivityDialogHeader) my $Output; my $MainBoxClass; if ( !$Self->{IsMainWindow} ) { $Output = $LayoutObject->CustomerHeader( Type => 'Small', Value => $Ticket{Number}, ); # display given notify messages if this is not an ajax request if ( IsArrayRefWithData( $Param{Notify} ) ) { for my $NotifyString ( @{ $Param{Notify} } ) { $Output .= $LayoutObject->Notify( Data => $NotifyString, ); } } $LayoutObject->Block( Name => 'Header', Data => { Name => $LayoutObject->{LanguageObject}->Translate( $ActivityDialog->{Name} ) || '', } ); } elsif ( $Self->{IsMainWindow} && IsHashRefWithData( \%Error ) ) { # add rich text editor if ( $LayoutObject->{BrowserRichText} ) { # use height/width defined for this screen $Param{RichTextHeight} = $Self->{Config}->{RichTextHeight} || 0; $Param{RichTextWidth} = $Self->{Config}->{RichTextWidth} || 0; $LayoutObject->Block( Name => 'RichText', Data => \%Param, ); } # display complete header and nav bar in ajax dialogs when there is a server error $Output = $LayoutObject->CustomerHeader(); $Output .= $LayoutObject->CustomerNavigationBar(); # display original header texts (the process list maybe is not necessary) $Output .= $LayoutObject->Output( TemplateFile => 'CustomerTicketProcess', Data => {}, ); # set the MainBox class to add correct borders to the screen $MainBoxClass = 'MainBox'; } # display process iformation if ( $Self->{IsMainWindow} ) { # get process data my $Process = $ProcessObject->ProcessGet( ProcessEntityID => $Param{ProcessEntityID}, ); # output main process information $LayoutObject->Block( Name => 'ProcessInfoSidebar', Data => { Process => $Process->{Name} || '', Activity => $Activity->{Name} || '', ActivityDialog => $ActivityDialog->{Name} || '', }, ); # output activity dilalog short description (if any) if ( defined $ActivityDialog->{DescriptionShort} && $ActivityDialog->{DescriptionShort} ne '' ) { $LayoutObject->Block( Name => 'ProcessInfoSidebarActivityDialogDesc', Data => { ActivityDialogDescription => $ActivityDialog->{DescriptionShort} || '', }, ); } } # show descriptions if ( $ActivityDialog->{DescriptionShort} ) { $LayoutObject->Block( Name => 'DescriptionShort', Data => { DescriptionShort => $LayoutObject->{LanguageObject}->Translate( $ActivityDialog->{DescriptionShort}, ), }, ); } if ( $ActivityDialog->{DescriptionLong} ) { $LayoutObject->Block( Name => 'DescriptionLong', Data => { DescriptionLong => $LayoutObject->{LanguageObject}->Translate( $ActivityDialog->{DescriptionLong}, ), }, ); } # show close & cancel link if neccessary if ( !$Self->{IsMainWindow} ) { if ( $Param{RenderLocked} ) { $LayoutObject->Block( Name => 'PropertiesLock', Data => { %Param, TicketID => $TicketID, }, ); } else { $LayoutObject->Block( Name => 'CancelLink', ); } } $Output .= $LayoutObject->Output( TemplateFile => 'ProcessManagement/CustomerActivityDialogHeader', Data => { FormName => 'ActivityDialogDialog' . $ActivityActivityDialog->{ActivityDialog}, FormID => $Self->{FormID}, Subaction => 'StoreActivityDialog', TicketID => $Ticket{TicketID} || '', ActivityDialogEntityID => $ActivityActivityDialog->{ActivityDialog}, ProcessEntityID => $Param{ProcessEntityID} || $Ticket{ 'DynamicField_' . $ConfigObject->Get( 'Process::DynamicFieldProcessManagementProcessID' ) }, IsMainWindow => $Self->{IsMainWindow}, MainBoxClass => $MainBoxClass || '', }, ); my %RenderedFields = (); # get the list of fields where the AJAX loader icon should appear on AJAX updates triggered # by ActivityDialog fields my $AJAXUpdatableFields = $Self->_GetAJAXUpdatableFields( ActivityDialogFields => $ActivityDialog->{Fields}, ); # some fields should be skipped for the customer interface my $SkipFields = [ 'Owner', 'Responsible', 'Lock', 'PendingTime', 'CustomerID' ]; # Loop through ActivityDialogFields and render their output DIALOGFIELD: for my $CurrentField ( @{ $ActivityDialog->{FieldOrder} } ) { # some fields should be skipped for the customer interface next DIALOGFIELD if ( grep { $_ eq $CurrentField } @{$SkipFields} ); if ( !IsHashRefWithData( $ActivityDialog->{Fields}{$CurrentField} ) ) { my $Message = $LayoutObject->{LanguageObject}->Translate( 'Can\'t get data for Field "%s" of ActivityDialog "%s"!', $CurrentField, $ActivityActivityDialog->{ActivityDialog} ); # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Message, ); } $LayoutObject->CustomerFatalError( Message => $Message, ); } my %FieldData = %{ $ActivityDialog->{Fields}{$CurrentField} }; # We render just visible ActivityDialogFields next DIALOGFIELD if !$FieldData{Display}; # render DynamicFields if ( $CurrentField =~ m{^DynamicField_(.*)}xms ) { my $DynamicFieldName = $1; my $Response = $Self->_RenderDynamicField( ActivityDialogField => $ActivityDialog->{Fields}{$CurrentField}, FieldName => $DynamicFieldName, DescriptionShort => $ActivityDialog->{Fields}{$CurrentField}{DescriptionShort}, DescriptionLong => $ActivityDialog->{Fields}{$CurrentField}{DescriptionLong}, Ticket => \%Ticket || {}, Error => \%Error || {}, ErrorMessage => \%ErrorMessage || {}, FormID => $Self->{FormID}, GetParam => $Param{GetParam}, AJAXUpdatableFields => $AJAXUpdatableFields, ); if ( !$Response->{Success} ) { # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Response->{Message}, ); } $LayoutObject->CustomerFatalError( Message => $Response->{Message}, ); } $Output .= $Response->{HTML}; $RenderedFields{$CurrentField} = 1; } # render State elsif ( $Self->{NameToID}->{$CurrentField} eq 'StateID' ) { # We don't render Fields twice, # if there was already a Config without ID, skip this field # next DIALOGFIELD if $RenderedFields{ $Self->{NameToID}->{$CurrentField} }; my $Response = $Self->_RenderState( ActivityDialogField => $ActivityDialog->{Fields}{$CurrentField}, FieldName => $CurrentField, DescriptionShort => $ActivityDialog->{Fields}{$CurrentField}{DescriptionShort}, DescriptionLong => $ActivityDialog->{Fields}{$CurrentField}{DescriptionLong}, Ticket => \%Ticket || {}, Error => \%Error || {}, FormID => $Self->{FormID}, GetParam => $Param{GetParam}, AJAXUpdatableFields => $AJAXUpdatableFields, ); if ( !$Response->{Success} ) { # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Response->{Message}, ); } $LayoutObject->CustomerFatalError( Message => $Response->{Message}, ); } $Output .= $Response->{HTML}; $RenderedFields{ $Self->{NameToID}->{$CurrentField} } = 1; } # render Queue elsif ( $Self->{NameToID}->{$CurrentField} eq 'QueueID' ) { next DIALOGFIELD if $RenderedFields{ $Self->{NameToID}->{$CurrentField} }; my $Response = $Self->_RenderQueue( ActivityDialogField => $ActivityDialog->{Fields}{$CurrentField}, FieldName => $CurrentField, DescriptionShort => $ActivityDialog->{Fields}{$CurrentField}{DescriptionShort}, DescriptionLong => $ActivityDialog->{Fields}{$CurrentField}{DescriptionLong}, Ticket => \%Ticket || {}, Error => \%Error || {}, FormID => $Self->{FormID}, GetParam => $Param{GetParam}, AJAXUpdatableFields => $AJAXUpdatableFields, ); if ( !$Response->{Success} ) { # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Response->{Message}, ); } $LayoutObject->CustomerFatalError( Message => $Response->{Message}, ); } $Output .= $Response->{HTML}; $RenderedFields{ $Self->{NameToID}->{$CurrentField} } = 1; } # render Priority elsif ( $Self->{NameToID}->{$CurrentField} eq 'PriorityID' ) { next DIALOGFIELD if $RenderedFields{ $Self->{NameToID}->{$CurrentField} }; my $Response = $Self->_RenderPriority( ActivityDialogField => $ActivityDialog->{Fields}{$CurrentField}, FieldName => $CurrentField, DescriptionShort => $ActivityDialog->{Fields}{$CurrentField}{DescriptionShort}, DescriptionLong => $ActivityDialog->{Fields}{$CurrentField}{DescriptionLong}, Ticket => \%Ticket || {}, Error => \%Error || {}, FormID => $Self->{FormID}, GetParam => $Param{GetParam}, AJAXUpdatableFields => $AJAXUpdatableFields, ); if ( !$Response->{Success} ) { # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Response->{Message}, ); } $LayoutObject->CustomerFatalError( Message => $Response->{Message}, ); } $Output .= $Response->{HTML}; $RenderedFields{ $Self->{NameToID}->{$CurrentField} } = 1; } # render Service elsif ( $Self->{NameToID}->{$CurrentField} eq 'ServiceID' ) { next DIALOGFIELD if $RenderedFields{ $Self->{NameToID}->{$CurrentField} }; my $Response = $Self->_RenderService( ActivityDialogField => $ActivityDialog->{Fields}{$CurrentField}, FieldName => $CurrentField, DescriptionShort => $ActivityDialog->{Fields}{$CurrentField}{DescriptionShort}, DescriptionLong => $ActivityDialog->{Fields}{$CurrentField}{DescriptionLong}, Ticket => \%Ticket || {}, Error => \%Error || {}, FormID => $Self->{FormID}, GetParam => $Param{GetParam}, AJAXUpdatableFields => $AJAXUpdatableFields, ); if ( !$Response->{Success} ) { # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Response->{Message}, ); } $LayoutObject->CustomerFatalError( Message => $Response->{Message}, ); } $Output .= $Response->{HTML}; $RenderedFields{$CurrentField} = 1; } # render SLA elsif ( $Self->{NameToID}->{$CurrentField} eq 'SLAID' ) { next DIALOGFIELD if $RenderedFields{ $Self->{NameToID}->{$CurrentField} }; my $Response = $Self->_RenderSLA( ActivityDialogField => $ActivityDialog->{Fields}{$CurrentField}, FieldName => $CurrentField, DescriptionShort => $ActivityDialog->{Fields}{$CurrentField}{DescriptionShort}, DescriptionLong => $ActivityDialog->{Fields}{$CurrentField}{DescriptionLong}, Ticket => \%Ticket || {}, Error => \%Error || {}, FormID => $Self->{FormID}, GetParam => $Param{GetParam}, AJAXUpdatableFields => $AJAXUpdatableFields, ); if ( !$Response->{Success} ) { # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Response->{Message}, ); } $LayoutObject->CustomerFatalError( Message => $Response->{Message}, ); } $Output .= $Response->{HTML}; $RenderedFields{ $Self->{NameToID}->{$CurrentField} } = 1; } # render Title elsif ( $Self->{NameToID}->{$CurrentField} eq 'Title' ) { next DIALOGFIELD if $RenderedFields{ $Self->{NameToID}->{$CurrentField} }; my $Response = $Self->_RenderTitle( ActivityDialogField => $ActivityDialog->{Fields}{$CurrentField}, FieldName => $CurrentField, DescriptionShort => $ActivityDialog->{Fields}{$CurrentField}{DescriptionShort}, DescriptionLong => $ActivityDialog->{Fields}{$CurrentField}{DescriptionLong}, Ticket => \%Ticket || {}, Error => \%Error || {}, FormID => $Self->{FormID}, GetParam => $Param{GetParam}, ); if ( !$Response->{Success} ) { # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Response->{Message}, ); } $LayoutObject->CustomerFatalError( Message => $Response->{Message}, ); } $Output .= $Response->{HTML}; $RenderedFields{$CurrentField} = 1; } # render Article elsif ( $Self->{NameToID}->{$CurrentField} eq 'Article' ) { next DIALOGFIELD if $RenderedFields{ $Self->{NameToID}->{$CurrentField} }; my $Response = $Self->_RenderArticle( ActivityDialogField => $ActivityDialog->{Fields}{$CurrentField}, FieldName => $CurrentField, DescriptionShort => $ActivityDialog->{Fields}{$CurrentField}{DescriptionShort}, DescriptionLong => $ActivityDialog->{Fields}{$CurrentField}{DescriptionLong}, Ticket => \%Ticket || {}, Error => \%Error || {}, FormID => $Self->{FormID}, GetParam => $Param{GetParam}, InformAgents => $ActivityDialog->{Fields}->{Article}->{Config}->{InformAgents}, ); if ( !$Response->{Success} ) { # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Response->{Message}, ); } $LayoutObject->CustomerFatalError( Message => $Response->{Message}, ); } $Output .= $Response->{HTML}; $RenderedFields{$CurrentField} = 1; } # render Type elsif ( $Self->{NameToID}->{$CurrentField} eq 'TypeID' ) { # We don't render Fields twice, # if there was already a Config without ID, skip this field next DIALOGFIELD if $RenderedFields{ $Self->{NameToID}->{$CurrentField} }; my $Response = $Self->_RenderType( ActivityDialogField => $ActivityDialog->{Fields}{$CurrentField}, FieldName => $CurrentField, DescriptionShort => $ActivityDialog->{Fields}{$CurrentField}{DescriptionShort}, DescriptionLong => $ActivityDialog->{Fields}{$CurrentField}{DescriptionLong}, Ticket => \%Ticket || {}, Error => \%Error || {}, FormID => $Self->{FormID}, GetParam => $Param{GetParam}, AJAXUpdatableFields => $AJAXUpdatableFields, ); if ( !$Response->{Success} ) { # does not show header and footer again if ( $Self->{IsMainWindow} ) { return $LayoutObject->CustomerError( Message => $Response->{Message}, ); } $LayoutObject->CustomerFatalError( Message => $Response->{Message}, ); } $Output .= $Response->{HTML}; $RenderedFields{ $Self->{NameToID}->{$CurrentField} } = 1; } } my $FooterCSSClass = 'Footer'; if ( $Self->{IsAjaxRequest} ) { # Due to the initial loading of # the first ActivityDialog after Process selection # we have to bind the AjaxUpdate Function on # the selects, so we get the complete JSOnDocumentComplete code # and deliver it in the FooterJS block. # This Javascript Part is executed in # CustomerTicketProcess.tt $LayoutObject->Block( Name => 'FooterJS', Data => {}, ); $FooterCSSClass = 'Centered'; } # set submit button data my $ButtonText = 'Submit'; my $ButtonTitle = 'Save'; my $ButtonID = 'Submit' . $ActivityActivityDialog->{ActivityDialog}; if ( $ActivityDialog->{SubmitButtonText} ) { $ButtonText = $ActivityDialog->{SubmitButtonText}; $ButtonTitle = $ActivityDialog->{SubmitButtonText}; } $LayoutObject->Block( Name => 'Footer', Data => { FooterCSSClass => $FooterCSSClass, ButtonText => $ButtonText, ButtonTitle => $ButtonTitle, ButtonID => $ButtonID }, ); if ( $ActivityDialog->{SubmitAdviceText} ) { $LayoutObject->Block( Name => 'SubmitAdviceText', Data => { AdviceText => $ActivityDialog->{SubmitAdviceText}, }, ); } # reload parent window if ( $Param{ParentReload} ) { $LayoutObject->Block( Name => 'ParentReload', ); } # Add the FormFooter $Output .= $LayoutObject->Output( TemplateFile => 'ProcessManagement/CustomerActivityDialogFooter', Data => {}, ); # display regular footer only in non-ajax case if ( !$Self->{IsAjaxRequest} ) { $Output .= $LayoutObject->CustomerFooter( Type => $Self->{IsMainWindow} ? '' : 'Small' ); } return $Output; } sub _RenderDynamicField { my ( $Self, %Param ) = @_; # get layout objects my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(FormID FieldName)) { if ( !$Param{$Needed} ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderDynamicField' ), }; } } # get backend object my $BackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend'); my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet( Valid => 1, ObjectType => 'Ticket', ); # reduce the dynamic fields to only the ones that are desinged for customer interface my @CustomerDynamicFields; DYNAMICFIELD: for my $DynamicFieldConfig ( @{$DynamicField} ) { next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig); my $IsCustomerInterfaceCapable = $BackendObject->HasBehavior( DynamicFieldConfig => $DynamicFieldConfig, Behavior => 'IsCustomerInterfaceCapable', ); next DYNAMICFIELD if !$IsCustomerInterfaceCapable; push @CustomerDynamicFields, $DynamicFieldConfig; } $DynamicField = \@CustomerDynamicFields; my $DynamicFieldConfig = ( grep { $_->{Name} eq $Param{FieldName} } @{$DynamicField} )[0]; if ( !IsHashRefWithData($DynamicFieldConfig) ) { my $Message = "DynamicFieldConfig missing for field: $Param{FieldName}, or is not a Ticket Dynamic Field!"; # log error but does not stop the execution as it could be an old Article # DynamicField, see bug#11666 $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => $Message, ); return { Success => 1, HTML => '', }; } my $PossibleValuesFilter; my $IsACLReducible = $BackendObject->HasBehavior( DynamicFieldConfig => $DynamicFieldConfig, Behavior => 'IsACLReducible', ); if ($IsACLReducible) { # get PossibleValues my $PossibleValues = $BackendObject->PossibleValuesGet( DynamicFieldConfig => $DynamicFieldConfig, ); # All Ticket DynamicFields # used for ACL checking my %DynamicFieldCheckParam = map { $_ => $Param{GetParam}{$_} } grep {m{^DynamicField_}xms} ( keys %{ $Param{GetParam} } ); # check if field has PossibleValues property in its configuration if ( IsHashRefWithData($PossibleValues) ) { # convert possible values key => value to key => key for ACLs using a Hash slice my %AclData = %{$PossibleValues}; @AclData{ keys %AclData } = keys %AclData; # set possible values filter from ACLs my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket'); my $ACL = $TicketObject->TicketAcl( %{ $Param{GetParam} }, DynamicField => \%DynamicFieldCheckParam, Action => $Self->{Action}, ReturnType => 'Ticket', ReturnSubType => 'DynamicField_' . $DynamicFieldConfig->{Name}, Data => \%AclData, CustomerUserID => $Self->{UserID}, ); if ($ACL) { my %Filter = $TicketObject->TicketAclData(); # convert Filer key => key back to key => value using map %{$PossibleValuesFilter} = map { $_ => $PossibleValues->{$_} } keys %Filter; } } } my $ServerError; my $ErrorMessage; if ( IsHashRefWithData( $Param{Error} ) ) { if ( defined $Param{Error}->{ $Param{FieldName} } && $Param{Error}->{ $Param{FieldName} } ne '' ) { $ServerError = 1; if ( defined $Param{ErrorMessage}->{ $Param{FieldName} } && $Param{ErrorMessage}->{ $Param{FieldName} } ne '' ) { $ErrorMessage = $Param{ErrorMessage}->{ $Param{FieldName} }; } } } my $DynamicFieldHTML = $BackendObject->EditFieldRender( DynamicFieldConfig => $DynamicFieldConfig, PossibleValuesFilter => $PossibleValuesFilter, Value => $Param{GetParam}{ 'DynamicField_' . $Param{FieldName} }, LayoutObject => $LayoutObject, ParamObject => $Kernel::OM->Get('Kernel::System::Web::Request'), AJAXUpdate => 1, Mandatory => $Param{ActivityDialogField}->{Display} == 2, UpdatableFields => $Param{AJAXUpdatableFields}, ServerError => $ServerError, ErrorMessage => $ErrorMessage, ); my %Data = ( Name => $DynamicFieldConfig->{Name}, Label => $DynamicFieldHTML->{Label}, Content => $DynamicFieldHTML->{Field}, ); $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:DynamicField', Data => \%Data, ); if ( $Param{DescriptionShort} ) { $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:DynamicField:DescriptionShort', Data => { DescriptionShort => $Param{DescriptionShort}, }, ); } if ( $Param{DescriptionLong} ) { $LayoutObject->Block( Name => 'rw:DynamicField:DescriptionLong', Data => { DescriptionLong => $Param{DescriptionLong}, }, ); } return { Success => 1, HTML => $LayoutObject->Output( TemplateFile => 'ProcessManagement/DynamicField' ), }; } sub _RenderTitle { my ( $Self, %Param ) = @_; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(FormID)) { if ( !$Param{$Needed} ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderTitle' ), }; } } if ( !IsHashRefWithData( $Param{ActivityDialogField} ) ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', 'ActivityDialogField', '_RenderTitle' ), }; } my %Data = ( Label => $LayoutObject->{LanguageObject}->Translate("Title"), FieldID => 'Title', FormID => $Param{FormID}, Value => $Param{GetParam}{Title}, Name => 'Title', MandatoryClass => '', ValidateRequired => '', ); # If field is required put in the necessary variables for # ValidateRequired class input field, Mandatory class for the label if ( $Param{ActivityDialogField}->{Display} && $Param{ActivityDialogField}->{Display} == 2 ) { $Data{ValidateRequired} = 'Validate_Required'; $Data{MandatoryClass} = 'Mandatory'; } # output server errors if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{'Title'} ) { $Data{ServerError} = 'ServerError'; } $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Title', Data => \%Data, ); # set mandatory label marker if ( $Data{MandatoryClass} && $Data{MandatoryClass} ne '' ) { $LayoutObject->Block( Name => 'LabelSpan', Data => {}, ); } if ( $Param{DescriptionShort} ) { $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Title:DescriptionShort', Data => { DescriptionShort => $Param{DescriptionShort}, }, ); } if ( $Param{DescriptionLong} ) { $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Title:DescriptionLong', Data => { DescriptionLong => $Param{DescriptionLong}, }, ); } return { Success => 1, HTML => $LayoutObject->Output( TemplateFile => 'ProcessManagement/Title' ), }; } sub _RenderArticle { my ( $Self, %Param ) = @_; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(FormID Ticket)) { if ( !$Param{$Needed} ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderArticle' ), }; } } if ( !IsHashRefWithData( $Param{ActivityDialogField} ) ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', 'ActivityDialogField', '_RenderArticle' ), }; } my %Data = ( Name => 'Article', MandatoryClass => '', ValidateRequired => '', Subject => $Param{GetParam}{Subject}, Body => $Param{GetParam}{Body}, LabelSubject => $Param{ActivityDialogField}->{Config}->{LabelSubject} || $LayoutObject->{LanguageObject}->Translate("Subject"), LabelBody => $Param{ActivityDialogField}->{Config}->{LabelBody} || $LayoutObject->{LanguageObject}->Translate("Text"), ); # If field is required put in the necessary variables for # ValidateRequired class input field, Mandatory class for the label if ( $Param{ActivityDialogField}->{Display} && $Param{ActivityDialogField}->{Display} == 2 ) { $Data{ValidateRequired} = 'Validate_Required'; $Data{MandatoryClass} = 'Mandatory'; } # output server errors if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{'ArticleSubject'} ) { $Data{SubjectServerError} = 'ServerError'; } if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{'ArticleBody'} ) { $Data{BodyServerError} = 'ServerError'; } $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Article', Data => \%Data, ); # set mandatory label marker if ( $Data{MandatoryClass} && $Data{MandatoryClass} ne '' ) { $LayoutObject->Block( Name => 'LabelSpanSubject', Data => {}, ); $LayoutObject->Block( Name => 'LabelSpanBody', Data => {}, ); } # add rich text editor if ( $LayoutObject->{BrowserRichText} ) { # use height/width defined for this screen $Param{RichTextHeight} = $Self->{Config}->{RichTextHeight} || 0; $Param{RichTextWidth} = $Self->{Config}->{RichTextWidth} || 0; $LayoutObject->Block( Name => 'RichText', Data => \%Param, ); } if ( $Param{DescriptionShort} ) { $LayoutObject->Block( Name => 'rw:Article:DescriptionShort', Data => { DescriptionShort => $Param{DescriptionShort}, }, ); } if ( $Param{DescriptionLong} ) { $LayoutObject->Block( Name => 'rw:Article:DescriptionLong', Data => { DescriptionLong => $Param{DescriptionLong}, }, ); } if ( $Param{InformAgents} ) { my %ShownUsers; my %AllGroupsMembers = $Kernel::OM->Get('Kernel::System::User')->UserList( Type => 'Long', Valid => 1, ); my $GID = $Kernel::OM->Get('Kernel::System::Queue')->GetQueueGroupID( QueueID => $Param{Ticket}->{QueueID} ); my %MemberList = $Kernel::OM->Get('Kernel::System::Group')->GroupMemberList( GroupID => $GID, Type => 'note', Result => 'HASH', Cached => 1, ); for my $UserID ( sort keys %MemberList ) { $ShownUsers{$UserID} = $AllGroupsMembers{$UserID}; } $Param{OptionStrg} = $LayoutObject->BuildSelection( Data => \%ShownUsers, SelectedID => '', Name => 'InformUserID', Multiple => 1, Size => 3, Class => 'Modernize', ); $LayoutObject->Block( Name => 'rw:Article:InformAgent', Data => \%Param, ); } # get all attachments meta data my @Attachments = $Kernel::OM->Get('Kernel::System::Web::UploadCache')->FormIDGetAllFilesMeta( FormID => $Self->{FormID}, ); # show attachments ATTACHMENT: for my $Attachment (@Attachments) { if ( $Attachment->{ContentID} && $LayoutObject->{BrowserRichText} && ( $Attachment->{ContentType} =~ /image/i ) && ( $Attachment->{Disposition} eq 'inline' ) ) { next ATTACHMENT; } $LayoutObject->Block( Name => 'Attachment', Data => $Attachment, ); } return { Success => 1, HTML => $LayoutObject->Output( TemplateFile => 'ProcessManagement/Article' ), }; } sub _RenderCustomer { my ( $Self, %Param ) = @_; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(FormID)) { if ( !$Param{$Needed} ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderResponsible' ), }; } } if ( !IsHashRefWithData( $Param{ActivityDialogField} ) ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', 'ActivityDialogField', '_RenderCustomer' ), }; } my $AutoCompleteConfig = $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Frontend::CustomerSearchAutoComplete'); my %CustomerUserData = (); my $SubmittedCustomerUserID = $Param{GetParam}{CustomerUserID}; my %Data = ( LabelCustomerUser => $LayoutObject->{LanguageObject}->Translate("Customer user"), LabelCustomerID => $LayoutObject->{LanguageObject}->Translate("CustomerID"), FormID => $Param{FormID}, MandatoryClass => '', ValidateRequired => '', ); # If field is required put in the necessary variables for # ValidateRequired class input field, Mandatory class for the label if ( $Param{ActivityDialogField}->{Display} && $Param{ActivityDialogField}->{Display} == 2 ) { $Data{ValidateRequired} = 'Validate_Required'; $Data{MandatoryClass} = 'Mandatory'; } # output server errors if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{CustomerUserID} ) { $Data{CustomerUserIDServerError} = 'ServerError'; } if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{CustomerID} ) { $Data{CustomerIDServerError} = 'ServerError'; } # set some customer search autocomplete properties $LayoutObject->Block( Name => 'CustomerSearchAutoComplete', Data => { minQueryLength => $AutoCompleteConfig->{MinQueryLength} || 2, queryDelay => $AutoCompleteConfig->{QueryDelay} || 100, maxResultsDisplayed => $AutoCompleteConfig->{MaxResultsDisplayed} || 20, ActiveAutoComplete => $AutoCompleteConfig->{Active}, }, ); if ( ( IsHashRefWithData( $Param{Ticket} ) && $Param{Ticket}->{CustomerUserID} ) || $SubmittedCustomerUserID ) { %CustomerUserData = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerUserDataGet( User => $SubmittedCustomerUserID || $Param{Ticket}{CustomerUserID}, ); } # show customer field as "FirstName Lastname" if ( IsHashRefWithData( \%CustomerUserData ) ) { $Data{CustomerUserID} = "\"$CustomerUserData{UserFirstname} " . "$CustomerUserData{UserLastname}\" <$CustomerUserData{UserEmail}>"; $Data{CustomerID} = $CustomerUserData{UserCustomerID} || ''; $Data{SelectedCustomerUser} = $CustomerUserData{UserID} || ''; } # set fields that will get an AJAX loader icon when this field changes my $JSON = $LayoutObject->JSONEncode( Data => $Param{AJAXUpdatableFields}, NoQuotes => 0, ); $Data{FieldsToUpdate} = $JSON; $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Customer', Data => \%Data, ); # set mandatory label marker if ( $Data{MandatoryClass} && $Data{MandatoryClass} ne '' ) { $LayoutObject->Block( Name => 'LabelSpanCustomerUser', Data => {}, ); $LayoutObject->Block( Name => 'LabelSpanCustomerID', Data => {}, ); } if ( $Param{DescriptionShort} ) { $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Customer:DescriptionShort', Data => { DescriptionShort => $Param{DescriptionShort}, }, ); } if ( $Param{DescriptionLong} ) { $LayoutObject->Block( Name => 'rw:Customer:DescriptionLong', Data => { DescriptionLong => $Param{DescriptionLong}, }, ); } return { Success => 1, HTML => $LayoutObject->Output( TemplateFile => 'ProcessManagement/Customer' ), }; } sub _RenderSLA { my ( $Self, %Param ) = @_; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(FormID)) { if ( !$Param{$Needed} ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderSLA' ), }; } } if ( !IsHashRefWithData( $Param{ActivityDialogField} ) ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', 'ActivityDialogField', '_RenderSLA' ), }; } my $Services = $Self->_GetServices( %{ $Param{GetParam} }, ); my $SLAs = $Self->_GetSLAs( %{ $Param{GetParam} }, Services => $Services, ); my %Data = ( Label => $LayoutObject->{LanguageObject}->Translate("SLA"), FieldID => 'SLAID', FormID => $Param{FormID}, MandatoryClass => '', ValidateRequired => '', ); # If field is required put in the necessary variables for # ValidateRequired class input field, Mandatory class for the label if ( $Param{ActivityDialogField}->{Display} && $Param{ActivityDialogField}->{Display} == 2 ) { $Data{ValidateRequired} = 'Validate_Required'; $Data{MandatoryClass} = 'Mandatory'; } my $SelectedValue; # get SLA object my $SLAObject = $Kernel::OM->Get('Kernel::System::SLA'); my $SLAIDParam = $Param{GetParam}{SLAID}; if ($SLAIDParam) { $SelectedValue = $SLAObject->SLALookup( SLAID => $SLAIDParam ); } if ( $Param{FieldName} eq 'SLA' ) { if ( !$SelectedValue ) { # Fetch DefaultValue from Config if ( defined $Param{ActivityDialogField}->{DefaultValue} && $Param{ActivityDialogField}->{DefaultValue} ne '' ) { $SelectedValue = $SLAObject->SLALookup( SLA => $Param{ActivityDialogField}->{DefaultValue}, ); } if ($SelectedValue) { $SelectedValue = $Param{ActivityDialogField}->{DefaultValue}; } } } else { if ( !$SelectedValue ) { if ( defined $Param{ActivityDialogField}->{DefaultValue} && $Param{ActivityDialogField}->{DefaultValue} ne '' ) { $SelectedValue = $SLAObject->SLALookup( SLA => $Param{ActivityDialogField}->{DefaultValue}, ); } } } # Get TicketValue if ( IsHashRefWithData( $Param{Ticket} ) && !$SelectedValue ) { $SelectedValue = $Param{Ticket}->{SLA}; } # set server errors my $ServerError = ''; if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{'SLAID'} ) { $ServerError = 'ServerError'; } # build SLA string $Data{Content} = $LayoutObject->BuildSelection( Data => $SLAs, Name => 'SLAID', SelectedValue => $SelectedValue, PossibleNone => 1, Sort => 'AlphanumericValue', Translation => 0, Class => "Modernize $ServerError", Max => 200, ); # set fields that will get an AJAX loader icon when this field changes $Data{FieldsToUpdate} = $Self->_GetFieldsToUpdateStrg( TriggerField => 'SLAID', AJAXUpdatableFields => $Param{AJAXUpdatableFields}, ); $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:SLA', Data => \%Data, ); # set mandatory label marker if ( $Data{MandatoryClass} && $Data{MandatoryClass} ne '' ) { $LayoutObject->Block( Name => 'LabelSpan', Data => {}, ); } if ( $Param{DescriptionShort} ) { $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:SLA:DescriptionShort', Data => { DescriptionShort => $Param{DescriptionShort}, }, ); } if ( $Param{DescriptionLong} ) { $LayoutObject->Block( Name => 'rw:SLA:DescriptionLong', Data => { DescriptionLong => $Param{DescriptionLong}, }, ); } return { Success => 1, HTML => $LayoutObject->Output( TemplateFile => 'ProcessManagement/SLA' ), }; } sub _RenderService { my ( $Self, %Param ) = @_; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(FormID)) { if ( !$Param{$Needed} ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderService' ), }; } } if ( !IsHashRefWithData( $Param{ActivityDialogField} ) ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', 'ActivityDialogField', '_RenderService' ), }; } my $Services = $Self->_GetServices( %{ $Param{GetParam} }, ); my %Data = ( Label => $LayoutObject->{LanguageObject}->Translate("Service"), FieldID => 'ServiceID', FormID => $Param{FormID}, MandatoryClass => '', ValidateRequired => '', ); # If field is required put in the necessary variables for # ValidateRequired class input field, Mandatory class for the label if ( $Param{ActivityDialogField}->{Display} && $Param{ActivityDialogField}->{Display} == 2 ) { $Data{ValidateRequired} = 'Validate_Required'; $Data{MandatoryClass} = 'Mandatory'; } my $SelectedValue; # get service object my $ServiceObject = $Kernel::OM->Get('Kernel::System::Service'); my $ServiceIDParam = $Param{GetParam}{ServiceID}; if ($ServiceIDParam) { $SelectedValue = $ServiceObject->ServiceLookup( ServiceID => $ServiceIDParam, ); } if ( $Param{FieldName} eq 'Service' ) { if ( !$SelectedValue ) { # Fetch DefaultValue from Config if ( defined $Param{ActivityDialogField}->{DefaultValue} && $Param{ActivityDialogField}->{DefaultValue} ne '' ) { $SelectedValue = $ServiceObject->ServiceLookup( Name => $Param{ActivityDialogField}->{DefaultValue}, ); } if ($SelectedValue) { $SelectedValue = $Param{ActivityDialogField}->{DefaultValue}; } } } else { if ( !$SelectedValue ) { if ( defined $Param{ActivityDialogField}->{DefaultValue} && $Param{ActivityDialogField}->{DefaultValue} ne '' ) { $SelectedValue = $ServiceObject->ServiceLookup( Service => $Param{ActivityDialogField}->{DefaultValue}, ); } } } # Get TicketValue if ( IsHashRefWithData( $Param{Ticket} ) && !$SelectedValue ) { $SelectedValue = $Param{Ticket}->{Service}; } # set server errors my $ServerError = ''; if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{'ServiceID'} ) { $ServerError = 'ServerError'; } # get list type my $TreeView = 0; if ( $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Frontend::ListType') eq 'tree' ) { $TreeView = 1; } # build Service string $Data{Content} = $LayoutObject->BuildSelection( Data => $Services, Name => 'ServiceID', Class => "Modernize $ServerError", SelectedValue => $SelectedValue, PossibleNone => 1, TreeView => $TreeView, Sort => 'TreeView', Translation => 0, Max => 200, ); # set fields that will get an AJAX loader icon when this field changes $Data{FieldsToUpdate} = $Self->_GetFieldsToUpdateStrg( TriggerField => 'ServiceID', AJAXUpdatableFields => $Param{AJAXUpdatableFields}, ); $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Service', Data => \%Data, ); # set mandatory label marker if ( $Data{MandatoryClass} && $Data{MandatoryClass} ne '' ) { $LayoutObject->Block( Name => 'LabelSpan', Data => {}, ); } if ( $Param{DescriptionShort} ) { $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Service:DescriptionShort', Data => { DescriptionShort => $Param{DescriptionShort}, }, ); } if ( $Param{DescriptionLong} ) { $LayoutObject->Block( Name => 'rw:Service:DescriptionLong', Data => { DescriptionLong => $Param{DescriptionLong}, }, ); } return { Success => 1, HTML => $LayoutObject->Output( TemplateFile => 'ProcessManagement/Service' ), }; } sub _RenderPriority { my ( $Self, %Param ) = @_; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(FormID)) { if ( !$Param{$Needed} ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderPriority' ), }; } } if ( !IsHashRefWithData( $Param{ActivityDialogField} ) ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', 'ActivityDialogField', '_RenderPriority' ), }; } my $Priorities = $Self->_GetPriorities( %{ $Param{GetParam} }, ); my %Data = ( Label => $LayoutObject->{LanguageObject}->Translate("Priority"), FieldID => 'PriorityID', FormID => $Param{FormID}, MandatoryClass => '', ValidateRequired => '', ); # If field is required put in the necessary variables for # ValidateRequired class input field, Mandatory class for the label if ( $Param{ActivityDialogField}->{Display} && $Param{ActivityDialogField}->{Display} == 2 ) { $Data{ValidateRequired} = 'Validate_Required'; $Data{MandatoryClass} = 'Mandatory'; } my $SelectedValue; # get priority object my $PriorityObject = $Kernel::OM->Get('Kernel::System::Priority'); my $PriorityIDParam = $Param{GetParam}{PriorityID}; if ($PriorityIDParam) { $SelectedValue = $PriorityObject->PriorityLookup( PriorityID => $PriorityIDParam, ); } if ( $Param{FieldName} eq 'Priority' ) { if ( !$SelectedValue ) { # Fetch DefaultValue from Config $SelectedValue = $PriorityObject->PriorityLookup( Priority => $Param{ActivityDialogField}->{DefaultValue} || '', ); if ($SelectedValue) { $SelectedValue = $Param{ActivityDialogField}->{DefaultValue}; } } } else { if ( !$SelectedValue ) { $SelectedValue = $PriorityObject->PriorityLookup( PriorityID => $Param{ActivityDialogField}->{DefaultValue} || '', ); } } # Get TicketValue if ( IsHashRefWithData( $Param{Ticket} ) && !$SelectedValue ) { $SelectedValue = $Param{Ticket}->{Priority}; } # set server errors my $ServerError = ''; if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{'PriorityID'} ) { $ServerError = 'ServerError'; } # build next Priorities string $Data{Content} = $LayoutObject->BuildSelection( Data => $Priorities, Name => 'PriorityID', Translation => 1, SelectedValue => $SelectedValue, Class => "Modernize $ServerError", ); # set fields that will get an AJAX loader icon when this field changes $Data{FieldsToUpdate} = $Self->_GetFieldsToUpdateStrg( TriggerField => 'PriorityID', AJAXUpdatableFields => $Param{AJAXUpdatableFields}, ); $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Priority', Data => \%Data, ); # set mandatory label marker if ( $Data{MandatoryClass} && $Data{MandatoryClass} ne '' ) { $LayoutObject->Block( Name => 'LabelSpan', Data => {}, ); } if ( $Param{DescriptionShort} ) { $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Priority:DescriptionShort', Data => { DescriptionShort => $Param{DescriptionShort}, }, ); } if ( $Param{DescriptionLong} ) { $LayoutObject->Block( Name => 'rw:Priority:DescriptionLong', Data => { DescriptionLong => $Param{DescriptionLong}, }, ); } return { Success => 1, HTML => $LayoutObject->Output( TemplateFile => 'ProcessManagement/Priority' ), }; } sub _RenderQueue { my ( $Self, %Param ) = @_; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(FormID)) { if ( !$Param{$Needed} ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderQueue' ), }; } } if ( !IsHashRefWithData( $Param{ActivityDialogField} ) ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', 'ActivityDialogField', '_RenderQueue' ), }; } my $Queues = $Self->_GetQueues( %{ $Param{GetParam} }, ); my %Data = ( Label => $LayoutObject->{LanguageObject}->Translate("To queue"), FieldID => 'QueueID', FormID => $Param{FormID}, MandatoryClass => '', ValidateRequired => '', ); # If field is required put in the necessary variables for # ValidateRequired class input field, Mandatory class for the label if ( $Param{ActivityDialogField}->{Display} && $Param{ActivityDialogField}->{Display} == 2 ) { $Data{ValidateRequired} = 'Validate_Required'; $Data{MandatoryClass} = 'Mandatory'; } my $SelectedValue; # get queue object my $QueueObject = $Kernel::OM->Get('Kernel::System::Queue'); # if we got QueueID as Param from the GUI my $QueueIDParam = $Param{GetParam}{QueueID}; if ($QueueIDParam) { $SelectedValue = $QueueObject->QueueLookup( QueueID => $QueueIDParam, ); } if ( $Param{FieldName} eq 'Queue' ) { if ( !$SelectedValue ) { # Fetch DefaultValue from Config $SelectedValue = $QueueObject->QueueLookup( Queue => $Param{ActivityDialogField}->{DefaultValue} || '', ); if ($SelectedValue) { $SelectedValue = $Param{ActivityDialogField}->{DefaultValue}; } } } else { if ( !$SelectedValue ) { $SelectedValue = $QueueObject->QueueLookup( QueueID => $Param{ActivityDialogField}->{DefaultValue} || '', ); } } # Get TicketValue if ( IsHashRefWithData( $Param{Ticket} ) && !$SelectedValue ) { $SelectedValue = $Param{Ticket}->{Queue}; } # set server errors my $ServerError = ''; if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{'QueueID'} ) { $ServerError = 'ServerError'; } # get list type my $TreeView = 0; if ( $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Frontend::ListType') eq 'tree' ) { $TreeView = 1; } # build next queues string $Data{Content} = $LayoutObject->BuildSelection( Data => $Queues, Name => 'QueueID', Translation => 1, SelectedValue => $SelectedValue, Class => "Modernize $ServerError", TreeView => $TreeView, Sort => 'TreeView', PossibleNone => 1, ); $Data{FieldsToUpdate} = $Self->_GetFieldsToUpdateStrg( TriggerField => 'QueueID', AJAXUpdatableFields => $Param{AJAXUpdatableFields}, ); $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Queue', Data => \%Data, ); # set mandatory label marker if ( $Data{MandatoryClass} && $Data{MandatoryClass} ne '' ) { $LayoutObject->Block( Name => 'LabelSpan', Data => {}, ); } if ( $Param{DescriptionShort} ) { $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Queue:DescriptionShort', Data => { DescriptionShort => $Param{DescriptionShort}, }, ); } if ( $Param{DescriptionLong} ) { $LayoutObject->Block( Name => 'rw:Queue:DescriptionLong', Data => { DescriptionLong => $Param{DescriptionLong}, }, ); } return { Success => 1, HTML => $LayoutObject->Output( TemplateFile => 'ProcessManagement/Queue' ), }; } sub _RenderState { my ( $Self, %Param ) = @_; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(FormID)) { if ( !$Param{$Needed} ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderState' ), }; } } if ( !IsHashRefWithData( $Param{ActivityDialogField} ) ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', 'ActivityDialogField', '_RenderState' ), }; } my $States = $Self->_GetStates( %{ $Param{Ticket} } ); my %Data = ( Label => $LayoutObject->{LanguageObject}->Translate("Next ticket state"), FieldID => 'StateID', FormID => $Param{FormID}, MandatoryClass => '', ValidateRequired => '', ); # If field is required put in the necessary variables for # ValidateRequired class input field, Mandatory class for the label if ( $Param{ActivityDialogField}->{Display} && $Param{ActivityDialogField}->{Display} == 2 ) { $Data{ValidateRequired} = 'Validate_Required'; $Data{MandatoryClass} = 'Mandatory'; } my $SelectedValue; # get state object my $StateObject = $Kernel::OM->Get('Kernel::System::State'); my $StateIDParam = $Param{GetParam}{StateID}; if ($StateIDParam) { $SelectedValue = $StateObject->StateLookup( StateID => $StateIDParam ); } if ( $Param{FieldName} eq 'State' ) { if ( !$SelectedValue ) { # Fetch DefaultValue from Config $SelectedValue = $StateObject->StateLookup( State => $Param{ActivityDialogField}->{DefaultValue} || '', ); if ($SelectedValue) { $SelectedValue = $Param{ActivityDialogField}->{DefaultValue}; } } } else { if ( !$SelectedValue ) { $SelectedValue = $StateObject->StateLookup( StateID => $Param{ActivityDialogField}->{DefaultValue} || '', ); } } # Get TicketValue if ( IsHashRefWithData( $Param{Ticket} ) && !$SelectedValue ) { $SelectedValue = $Param{Ticket}->{State}; } # set server errors my $ServerError = ''; if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{'StateID'} ) { $ServerError = 'ServerError'; } # build next states string $Data{Content} = $LayoutObject->BuildSelection( Data => $States, Name => 'StateID', Translation => 1, SelectedValue => $SelectedValue, Class => "Modernize $ServerError", ); # set fields that will get an AJAX loader icon when this field changes $Data{FieldsToUpdate} = $Self->_GetFieldsToUpdateStrg( TriggerField => 'StateID', AJAXUpdatableFields => $Param{AJAXUpdatableFields}, ); $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:State', Data => \%Data, ); # set mandatory label marker if ( $Data{MandatoryClass} && $Data{MandatoryClass} ne '' ) { $LayoutObject->Block( Name => 'LabelSpan', Data => {}, ); } if ( $Param{DescriptionShort} ) { $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:State:DescriptionShort', Data => { DescriptionShort => $Param{DescriptionShort}, }, ); } if ( $Param{DescriptionLong} ) { $LayoutObject->Block( Name => 'rw:State:DescriptionLong', Data => { DescriptionLong => $Param{DescriptionLong}, }, ); } return { Success => 1, HTML => $LayoutObject->Output( TemplateFile => 'ProcessManagement/State' ), }; } sub _RenderType { my ( $Self, %Param ) = @_; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(FormID)) { if ( !$Param{$Needed} ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', $Needed, '_RenderType' ), }; } } if ( !IsHashRefWithData( $Param{ActivityDialogField} ) ) { return { Success => 0, Message => $LayoutObject->{LanguageObject} ->Translate( 'Parameter %s is missing in %s.', 'ActivityDialogField', '_RenderType' ), }; } my $Types = $Self->_GetTypes( %{ $Param{GetParam} }, ); my %Data = ( Label => $LayoutObject->{LanguageObject}->Translate("Type"), FieldID => 'TypeID', FormID => $Param{FormID}, MandatoryClass => '', ValidateRequired => '', ); # If field is required put in the necessary variables for # ValidateRequired class input field, Mandatory class for the label if ( $Param{ActivityDialogField}->{Display} && $Param{ActivityDialogField}->{Display} == 2 ) { $Data{ValidateRequired} = 'Validate_Required'; $Data{MandatoryClass} = 'Mandatory'; } my $SelectedValue; # get type object my $TypeObject = $Kernel::OM->Get('Kernel::System::Type'); my $TypeIDParam = $Param{GetParam}{TypeID}; if ($TypeIDParam) { $SelectedValue = $TypeObject->TypeLookup( TypeID => $TypeIDParam, ); } if ( $Param{FieldName} eq 'Type' ) { if ( !$SelectedValue ) { # Fetch DefaultValue from Config if ( defined $Param{ActivityDialogField}->{DefaultValue} && $Param{ActivityDialogField}->{DefaultValue} ne '' ) { $SelectedValue = $TypeObject->TypeLookup( Type => $Param{ActivityDialogField}->{DefaultValue}, ); } if ($SelectedValue) { $SelectedValue = $Param{ActivityDialogField}->{DefaultValue}; } } } else { if ( !$SelectedValue ) { if ( defined $Param{ActivityDialogField}->{DefaultValue} && $Param{ActivityDialogField}->{DefaultValue} ne '' ) { $SelectedValue = $TypeObject->TypeLookup( Type => $Param{ActivityDialogField}->{DefaultValue}, ); } } } # Get TicketValue if ( IsHashRefWithData( $Param{Ticket} ) && !$SelectedValue ) { $SelectedValue = $Param{Ticket}->{Type}; } # set server errors my $ServerError = ''; if ( IsHashRefWithData( $Param{Error} ) && $Param{Error}->{'TypeID'} ) { $ServerError = 'ServerError'; } # build Service string $Data{Content} = $LayoutObject->BuildSelection( Data => $Types, Name => 'TypeID', Class => "Modernize $ServerError", SelectedValue => $SelectedValue, PossibleNone => 1, Sort => 'AlphanumericValue', Translation => 0, Max => 200, ); # set fields that will get an AJAX loader icon when this field changes $Data{FieldsToUpdate} = $Self->_GetFieldsToUpdateStrg( TriggerField => 'TypeID', AJAXUpdatableFields => $Param{AJAXUpdatableFields}, ); $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Type', Data => \%Data, ); # set mandatory label marker if ( $Data{MandatoryClass} && $Data{MandatoryClass} ne '' ) { $LayoutObject->Block( Name => 'LabelSpan', Data => {}, ); } if ( $Param{DescriptionShort} ) { $LayoutObject->Block( Name => $Param{ActivityDialogField}->{LayoutBlock} || 'rw:Type:DescriptionShort', Data => { DescriptionShort => $Param{DescriptionShort}, }, ); } if ( $Param{DescriptionLong} ) { $LayoutObject->Block( Name => 'rw:Type:DescriptionLong', Data => { DescriptionLong => $Param{DescriptionLong}, }, ); } return { Success => 1, HTML => $LayoutObject->Output( TemplateFile => 'ProcessManagement/Type' ), }; } sub _StoreActivityDialog { my ( $Self, %Param ) = @_; my $TicketID = $Param{GetParam}{TicketID}; my $ProcessStartpoint; my %Ticket; my $ProcessEntityID; my $ActivityEntityID; my %Error; my %ErrorMessage; my %TicketParam; # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); my $ActivityDialogEntityID = $Param{GetParam}{ActivityDialogEntityID}; if ( !$ActivityDialogEntityID ) { $LayoutObject->CustomerFatalError( Message => Translatable('ActivityDialogEntityID missing!'), ); } my $ActivityDialog = $Kernel::OM->Get('Kernel::System::ProcessManagement::ActivityDialog')->ActivityDialogGet( ActivityDialogEntityID => $ActivityDialogEntityID, Interface => 'CustomerInterface', ); if ( !IsHashRefWithData($ActivityDialog) ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Couldn\'t get Config for ActivityDialogEntityID "%s"!', $ActivityDialogEntityID ), ); } # If is an action about attachments my $IsUpload = 0; # get param object my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); # attachment delete my @AttachmentIDs = map { my ($ID) = $_ =~ m{ \A AttachmentDelete (\d+) \z }xms; $ID ? $ID : (); } $ParamObject->GetParamNames(); # get upload chache object my $UploadCacheObject = $Kernel::OM->Get('Kernel::System::Web::UploadCache'); COUNT: for my $Count ( reverse sort @AttachmentIDs ) { my $Delete = $ParamObject->GetParam( Param => "AttachmentDelete$Count" ); next COUNT if !$Delete; %Error = (); $Error{AttachmentDelete} = 1; $UploadCacheObject->FormIDRemoveFile( FormID => $Self->{FormID}, FileID => $Count, ); $IsUpload = 1; } # attachment upload if ( $ParamObject->GetParam( Param => 'AttachmentUpload' ) ) { $IsUpload = 1; %Error = (); $Error{AttachmentUpload} = 1; my %UploadStuff = $ParamObject->GetUploadAll( Param => 'FileUpload', ); $UploadCacheObject->FormIDAddFile( FormID => $Self->{FormID}, Disposition => 'attachment', %UploadStuff, ); } # get backend object my $BackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend'); # some fields should be skipped for the customer interface my $SkipFields = [ 'Owner', 'Responsible', 'Lock', 'PendingTime', 'CustomerID' ]; my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet( Valid => 1, ObjectType => 'Ticket', ); # reduce the dynamic fields to only the ones that are desinged for customer interface my @CustomerDynamicFields; DYNAMICFIELD: for my $DynamicFieldConfig ( @{$DynamicField} ) { next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig); my $IsCustomerInterfaceCapable = $BackendObject->HasBehavior( DynamicFieldConfig => $DynamicFieldConfig, Behavior => 'IsCustomerInterfaceCapable', ); next DYNAMICFIELD if !$IsCustomerInterfaceCapable; push @CustomerDynamicFields, $DynamicFieldConfig; } $DynamicField = \@CustomerDynamicFields; if ( !$IsUpload ) { # check each Field of an Activity Dialog and fill the error hash if something goes horribly wrong my %CheckedFields; DIALOGFIELD: for my $CurrentField ( @{ $ActivityDialog->{FieldOrder} } ) { # some fields should be skipped for the customer interface next DIALOGFIELD if ( grep { $_ eq $CurrentField } @{$SkipFields} ); if ( $CurrentField =~ m{^DynamicField_(.*)}xms ) { my $DynamicFieldName = $1; # Get the Config of the current DynamicField (the first element of the grep result array) my $DynamicFieldConfig = ( grep { $_->{Name} eq $DynamicFieldName } @{$DynamicField} )[0]; if ( !IsHashRefWithData($DynamicFieldConfig) ) { my $Message = "DynamicFieldConfig missing for field: $Param{FieldName}, or is not a Ticket Dynamic Field!"; # log error but does not stop the execution as it could be an old Article # DynamicField, see bug#11666 $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => $Message, ); next DIALOGFIELD; } # Will be extended lateron for ACL Checking: my $PossibleValuesFilter; # if we have an invisible field, use config's default value if ( $ActivityDialog->{Fields}{$CurrentField}{Display} == 0 ) { $TicketParam{$CurrentField} = $ActivityDialog->{Fields}{$CurrentField}{DefaultValue} || ''; } # only validate visible fields else { # Check DynamicField Values my $ValidationResult = $BackendObject->EditFieldValueValidate( DynamicFieldConfig => $DynamicFieldConfig, PossibleValuesFilter => $PossibleValuesFilter, ParamObject => $ParamObject, Mandatory => $ActivityDialog->{Fields}{$CurrentField}{Display} == 2, ); if ( !IsHashRefWithData($ValidationResult) ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Could not perform validation on field %s!', $DynamicFieldConfig->{Label} ), ); } if ( $ValidationResult->{ServerError} ) { $Error{ $DynamicFieldConfig->{Name} } = 1; $ErrorMessage{ $DynamicFieldConfig->{Name} } = $ValidationResult->{ErrorMessage} || ''; } $TicketParam{$CurrentField} = $BackendObject->EditFieldValueGet( DynamicFieldConfig => $DynamicFieldConfig, ParamObject => $ParamObject, LayoutObject => $LayoutObject, ); } # In case of DynamicFields there is no NameToID translation # so just take the DynamicField name $CheckedFields{$CurrentField} = 1; } elsif ( $Self->{NameToID}->{$CurrentField} eq 'CustomerID' || $Self->{NameToID}->{$CurrentField} eq 'CustomerUserID' ) { next DIALOGFIELD if $CheckedFields{ $Self->{NameToID}{'CustomerID'} }; my $CustomerID = $Param{GetParam}{CustomerID} || $Self->{UserCustomerID}; if ( !$CustomerID ) { $Error{'CustomerID'} = 1; } $TicketParam{CustomerID} = $CustomerID; # Unfortunately TicketCreate needs 'CustomerUser' as param instead of 'CustomerUserID' my $CustomerUserID = $ParamObject->GetParam( Param => 'SelectedCustomerUser' ) || $Self->{UserID}; if ( !$CustomerUserID ) { $CustomerUserID = $ParamObject->GetParam( Param => 'SelectedUserID' ); } if ( !$CustomerUserID ) { $Error{'CustomerUserID'} = 1; } else { $TicketParam{CustomerUser} = $CustomerUserID; } $CheckedFields{ $Self->{NameToID}{'CustomerID'} } = 1; $CheckedFields{ $Self->{NameToID}{'CustomerUserID'} } = 1; } else { # skip if we've already checked ID or Name next DIALOGFIELD if $CheckedFields{ $Self->{NameToID}->{$CurrentField} }; my $Result = $Self->_CheckField( Field => $Self->{NameToID}->{$CurrentField}, %{ $ActivityDialog->{Fields}{$CurrentField} }, ); if ( !$Result && $ActivityDialog->{Fields}{$CurrentField}->{Display} == 2 ) { # special case for Article (Subject & Body) if ( $CurrentField eq 'Article' ) { for my $ArticlePart (qw(Subject Body)) { if ( !$Param{GetParam}->{$ArticlePart} ) { # set error for each part (if any) $Error{ 'Article' . $ArticlePart } = 1; } } } # all other fields else { $Error{ $Self->{NameToID}->{$CurrentField} } = 1; } } elsif ($Result) { $TicketParam{ $Self->{NameToID}->{$CurrentField} } = $Result; } $CheckedFields{ $Self->{NameToID}->{$CurrentField} } = 1; } } } # get needed objects my $ProcessObject = $Kernel::OM->Get('Kernel::System::ProcessManagement::Process'); my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket'); my $NewTicketID; if ( !$TicketID ) { $ProcessEntityID = $Param{GetParam}{ProcessEntityID}; if ( !$ProcessEntityID ) { return $LayoutObject->CustomerFatalError( Message => Translatable('Missing ProcessEntityID, check your ActivityDialogHeader.tt!'), ); } $ProcessStartpoint = $ProcessObject->ProcessStartpointGet( ProcessEntityID => $Param{ProcessEntityID}, ); if ( !$ProcessStartpoint || !IsHashRefWithData($ProcessStartpoint) || !$ProcessStartpoint->{Activity} || !$ProcessStartpoint->{ActivityDialog} ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'No StartActivityDialog or StartActivityDialog for Process "%s" configured!', $Param{ProcessEntityID} ), ); } $ActivityEntityID = $ProcessStartpoint->{Activity}; NEEDEDLOOP: for my $Needed (qw(Queue State Lock Priority)) { if ( !$TicketParam{ $Self->{NameToID}->{$Needed} } ) { # if a required field has no value call _CheckField as filed is hidden # (No Display param = Display => 0) and no DefaultValue, to use global default as # fallback. One reason for this to happen is that ActivityDialog DefaultValue tried # to set before, was not valid. my $Result = $Self->_CheckField( Field => $Self->{NameToID}->{$Needed}, ); if ( !$Result ) { $Error{ $Self->{NameToID}->{$Needed} } = ' ServerError'; } elsif ($Result) { $TicketParam{ $Self->{NameToID}->{$Needed} } = $Result; } } } # If we had no Errors, we can create the Ticket and Set ActivityEntityID as well as # ProcessEntityID if ( !IsHashRefWithData( \%Error ) ) { $TicketParam{UserID} = $Self->{UserID}; $TicketParam{CustomerID} = $Self->{UserCustomerID}; $TicketParam{CustomerUser} = $Self->{UserLogin}; $TicketParam{OwnerID} = $ConfigObject->Get('CustomerPanelUserID'); $TicketParam{UserID} = $ConfigObject->Get('CustomerPanelUserID'); if ( !$TicketParam{OwnerID} ) { $TicketParam{OwnerID} = $Param{GetParam}{OwnerID} || 1; } # if StartActivityDialog does not provide a ticket title set a default value if ( !$TicketParam{Title} ) { # get the current server Timestamp my $CurrentTimeStamp = $Kernel::OM->Get('Kernel::System::Time')->CurrentTimestamp(); $TicketParam{Title} = "$Param{ProcessName} - $CurrentTimeStamp"; # use article subject from the web request if any if ( IsStringWithData( $Param{GetParam}->{Subject} ) ) { $TicketParam{Title} = $Param{GetParam}->{Subject}; } } # create a new ticket $TicketID = $TicketObject->TicketCreate(%TicketParam); if ( !$TicketID ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Couldn\'t create ticket for Process with ProcessEntityID "%s"!', $Param{ProcessEntityID} ), ); } my $Success = $ProcessObject->ProcessTicketProcessSet( ProcessEntityID => $Param{ProcessEntityID}, TicketID => $TicketID, UserID => $ConfigObject->Get('CustomerPanelUserID'), ); if ( !$Success ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Couldn\'t set ProcessEntityID "%s" on TicketID "%s"!', $Param{ProcessEntityID}, $TicketID ), ); } $Success = undef; $Success = $ProcessObject->ProcessTicketActivitySet( ProcessEntityID => $Param{ProcessEntityID}, ActivityEntityID => $ProcessStartpoint->{Activity}, TicketID => $TicketID, UserID => $ConfigObject->Get('CustomerPanelUserID'), ); if ( !$Success ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Couldn\'t set ActivityEntityID "%s" on TicketID "%s"!', $Param{ProcessEntityID}, $TicketID ), Comment => Translatable('Please contact the admin.'), ); } %Ticket = $TicketObject->TicketGet( TicketID => $TicketID, UserID => $ConfigObject->Get('CustomerPanelUserID'), DynamicFields => 1, ); if ( !IsHashRefWithData( \%Ticket ) ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Could not store ActivityDialog, invalid TicketID: %s!', $TicketID ), Comment => Translatable('Please contact the admin.'), ); } for my $DynamicFieldConfig ( # 2. remove "DynamicField_" from string map { my $Field = $_; $Field =~ s{^DynamicField_(.*)}{$1}xms; # 3. grep from the DynamicFieldConfigs the resulting DynamicFields without # "DynamicField_" grep { $_->{Name} eq $Field } @{$DynamicField} } # 1. grep all DynamicFields grep {m{^DynamicField_(.*)}xms} @{ $ActivityDialog->{FieldOrder} } ) { # and now it's easy, just store the dynamic Field Values ;) $BackendObject->ValueSet( DynamicFieldConfig => $DynamicFieldConfig, ObjectID => $TicketID, Value => $TicketParam{ 'DynamicField_' . $DynamicFieldConfig->{Name} }, UserID => $ConfigObject->Get('CustomerPanelUserID'), ); } # remember new created TicketID $NewTicketID = $TicketID; } } # If we had a TicketID, get the Ticket else { # Get Ticket to check TicketID was valid %Ticket = $TicketObject->TicketGet( TicketID => $TicketID, UserID => $ConfigObject->Get('CustomerPanelUserID'), DynamicFields => 1, ); if ( !IsHashRefWithData( \%Ticket ) ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Could not store ActivityDialog, invalid TicketID: %s!', $TicketID ), ); } $ActivityEntityID = $Ticket{ 'DynamicField_' . $ConfigObject->Get('Process::DynamicFieldProcessManagementActivityID') }; if ( !$ActivityEntityID ) { return $LayoutObject->CustomerErrorScreen( Message => $LayoutObject->{LanguageObject} ->Translate( 'Missing ActivityEntityID in Ticket %s!', $Ticket{TicketID} ), Comment => Translatable('Please contact the admin.'), ); } $ProcessEntityID = $Ticket{ 'DynamicField_' . $ConfigObject->Get('Process::DynamicFieldProcessManagementProcessID') }; if ( !$ProcessEntityID ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Missing ProcessEntityID in Ticket %s!', $Ticket{TicketID} ), ); } } # if we got errors go back to displaying the ActivityDialog if ( IsHashRefWithData( \%Error ) ) { return $Self->_OutputActivityDialog( ProcessEntityID => $ProcessEntityID, TicketID => $TicketID || undef, ActivityDialogEntityID => $ActivityDialogEntityID, Error => \%Error, ErrorMessage => \%ErrorMessage, GetParam => $Param{GetParam}, ); } # Check if we deal with a Ticket Update my $UpdateTicketID = $Param{GetParam}{TicketID}; # We save only once, no matter if one or more configs are set for the same param my %StoredFields; # Save loop for storing Ticket Values that were not required on the initial TicketCreate DIALOGFIELD: for my $CurrentField ( @{ $ActivityDialog->{FieldOrder} } ) { # some fields should be skipped for the customer interface next DIALOGFIELD if ( grep { $_ eq $CurrentField } @{$SkipFields} ); if ( !IsHashRefWithData( $ActivityDialog->{Fields}{$CurrentField} ) ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Can\'t get data for Field "%s" of ActivityDialog "%s"!', $CurrentField, $ActivityDialogEntityID ), ); } if ( $CurrentField =~ m{^DynamicField_(.*)}xms ) { my $DynamicFieldName = $1; my $DynamicFieldConfig = ( grep { $_->{Name} eq $DynamicFieldName } @{$DynamicField} )[0]; if ( !IsHashRefWithData($DynamicFieldConfig) ) { my $Message = "DynamicFieldConfig missing for field: $Param{FieldName}, or is not a Ticket Dynamic Field!"; # log error but does not stop the execution as it could be an old Article # DynamicField, see bug#11666 $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => $Message, ); next DIALOGFIELD; } my $Success = $BackendObject->ValueSet( DynamicFieldConfig => $DynamicFieldConfig, ObjectID => $TicketID, Value => $TicketParam{$CurrentField}, UserID => $ConfigObject->Get('CustomerPanelUserID'), ); if ( !$Success ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Could not set DynamicField value for %s of Ticket with ID "%s" in ActivityDialog "%s"!', $CurrentField, $TicketID, $ActivityDialogEntityID ), ); } } elsif ( $CurrentField eq 'Article' && ( $UpdateTicketID || $NewTicketID ) ) { my $TicketID = $UpdateTicketID || $NewTicketID; if ( $Param{GetParam}{Subject} && $Param{GetParam}{Body} ) { # add note my $ArticleID = ''; my $MimeType = 'text/plain'; if ( $LayoutObject->{BrowserRichText} ) { $MimeType = 'text/html'; # verify html document $Param{GetParam}{Body} = $LayoutObject->RichTextDocumentComplete( String => $Param{GetParam}{Body}, ); } my $From = "$Self->{UserFirstname} $Self->{UserLastname} <$Self->{UserEmail}>"; $ArticleID = $TicketObject->ArticleCreate( TicketID => $TicketID, SenderType => 'customer', From => $From, MimeType => $MimeType, Charset => $LayoutObject->{UserCharset}, UserID => $ConfigObject->Get('CustomerPanelUserID'), HistoryType => 'AddNote', HistoryComment => '%%Note', Body => $Param{GetParam}{Body}, Subject => $Param{GetParam}{Subject}, ArticleType => $ActivityDialog->{Fields}->{Article}->{Config}->{ArticleType}, ForceNotificationToUserID => $ActivityDialog->{Fields}->{Article}->{Config}->{InformAgents} ? $Param{GetParam}{InformUserID} : [], ); if ( !$ArticleID ) { return $LayoutObject->CustomerErrorScreen(); } # get pre loaded attachment my @Attachments = $UploadCacheObject->FormIDGetAllFilesData( FormID => $Self->{FormID}, ); # get submit attachment my %UploadStuff = $ParamObject->GetUploadAll( Param => 'FileUpload', ); if (%UploadStuff) { push @Attachments, \%UploadStuff; } # write attachments ATTACHMENT: for my $Attachment (@Attachments) { # skip, deleted not used inline images my $ContentID = $Attachment->{ContentID}; if ( $ContentID && ( $Attachment->{ContentType} =~ /image/i ) && ( $Attachment->{Disposition} eq 'inline' ) ) { my $ContentIDHTMLQuote = $LayoutObject->Ascii2Html( Text => $ContentID, ); # workaround for link encode of rich text editor, see bug#5053 my $ContentIDLinkEncode = $LayoutObject->LinkEncode($ContentID); $Param{GetParam}{Body} =~ s/(ContentID=)$ContentIDLinkEncode/$1$ContentID/g; # ignore attachment if not linked in body if ( $Param{GetParam}{Body} !~ /(\Q$ContentIDHTMLQuote\E|\Q$ContentID\E)/i ) { next ATTACHMENT; } } # write existing file to backend $TicketObject->ArticleWriteAttachment( %{$Attachment}, ArticleID => $ArticleID, UserID => $ConfigObject->Get('CustomerPanelUserID'), ); } # remove pre submited attachments $UploadCacheObject->FormIDRemove( FormID => $Self->{FormID} ); } } # If we have to Update a ticket, update the transmitted values elsif ($UpdateTicketID) { my $Success; if ( $Self->{NameToID}{$CurrentField} eq 'Title' ) { # if there is no title, nothig is needed to be done if ( !defined $TicketParam{'Title'} || ( defined $TicketParam{'Title'} && $TicketParam{'Title'} eq '' ) ) { $Success = 1; } # otherwise set the ticket title else { $Success = $TicketObject->TicketTitleUpdate( Title => $TicketParam{'Title'}, TicketID => $TicketID, UserID => $ConfigObject->Get('CustomerPanelUserID'), ); } } elsif ( ( $Self->{NameToID}{$CurrentField} eq 'CustomerID' || $Self->{NameToID}{$CurrentField} eq 'CustomerUserID' ) ) { next DIALOGFIELD if $StoredFields{ $Self->{NameToID}{$CurrentField} }; if ( $ActivityDialog->{Fields}{$CurrentField}{Display} == 1 ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Wrong ActivityDialog Field config: %s can\'t be Display => 1 / Show field (Please change its configuration to be Display => 0 / Do not show field or Display => 2 / Show field as mandatory)!', $CurrentField ), ); } # skip TicketCustomerSet() if there is no change in the customer if ( $Ticket{CustomerID} eq $TicketParam{CustomerID} && $Ticket{CustomerUserID} eq $TicketParam{CustomerUser} ) { # In this case we don't want to call any additional stores # on Customer, CustomerNo, CustomerID or CustomerUserID # so make sure both fields are set to "Stored" ;) $StoredFields{ $Self->{NameToID}{'CustomerID'} } = 1; $StoredFields{ $Self->{NameToID}{'CustomerUserID'} } = 1; next DIALOGFIELD; } $Success = $TicketObject->TicketCustomerSet( No => $TicketParam{CustomerID}, # here too: unfortunately TicketCreate takes Param 'CustomerUser' # instead of CustomerUserID, so our TicketParam hash # has the CustomerUser Key instead of 'CustomerUserID' User => $TicketParam{CustomerUser}, TicketID => $TicketID, UserID => $ConfigObject->Get('CustomerPanelUserID'), ); # In this case we don't want to call any additional stores # on Customer, CustomerNo, CustomerID or CustomerUserID # so make sure both fields are set to "Stored" ;) $StoredFields{ $Self->{NameToID}{'CustomerID'} } = 1; $StoredFields{ $Self->{NameToID}{'CustomerUserID'} } = 1; } else { next DIALOGFIELD if $StoredFields{ $Self->{NameToID}{$CurrentField} }; my $TicketFieldSetSub = $CurrentField; $TicketFieldSetSub =~ s{ID$}{}xms; $TicketFieldSetSub = 'Ticket' . $TicketFieldSetSub . 'Set'; if ( $TicketObject->can($TicketFieldSetSub) ) { my $UpdateFieldName; $UpdateFieldName = $Self->{NameToID}{$CurrentField}; # to store if the field needs to be updated my $FieldUpdate; # only Service and SLA fields accepts empty values if the hash key is not # defined set it to empty so the Ticket*Set function call will get the empty # value if ( ( $UpdateFieldName eq 'ServiceID' || $UpdateFieldName eq 'SLAID' ) && !defined $TicketParam{ $Self->{NameToID}{$CurrentField} } ) { $TicketParam{ $Self->{NameToID}{$CurrentField} } = ''; $FieldUpdate = 1; } # update Service an SLA fields if they have a defined value (even empty) elsif ( $UpdateFieldName eq 'ServiceID' || $UpdateFieldName eq 'SLAID' ) { $FieldUpdate = 1; } # update any other field that its value is defiend and not emoty elsif ( $UpdateFieldName ne 'ServiceID' && $UpdateFieldName ne 'SLAID' && defined $TicketParam{ $Self->{NameToID}{$CurrentField} } && $TicketParam{ $Self->{NameToID}{$CurrentField} } ne '' ) { $FieldUpdate = 1; } $Success = 1; # check if field needs to be updated if ($FieldUpdate) { $Success = $TicketObject->$TicketFieldSetSub( $UpdateFieldName => $TicketParam{ $Self->{NameToID}{$CurrentField} }, TicketID => $TicketID, UserID => $ConfigObject->Get('CustomerPanelUserID'), ); } } } if ( !$Success ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Could not set %s for Ticket with ID "%s" in ActivityDialog "%s"!', $CurrentField, $TicketID, $ActivityDialogEntityID ), ); } } } # Transitions will be handled by ticket event module (TicketProcessTransitions.pm). # if we were updating a ticket, close the popup and return to zoom # else (new ticket) just go to zoom to show the new ticket if ($UpdateTicketID) { # load new URL in parent window and close popup return $LayoutObject->PopupClose( URL => "Action=CustomerTicketZoom;TicketID=$UpdateTicketID", ); } return $LayoutObject->Redirect( OP => "Action=CustomerTicketZoom;TicketID=$TicketID", ); } sub _DisplayProcessList { my ( $Self, %Param ) = @_; # If we have a ProcessEntityID $Param{Errors}->{ProcessEntityIDInvalid} = ' ServerError' if ( $Param{ProcessEntityID} && !$Param{ProcessList}->{ $Param{ProcessEntityID} } ); # get layout object my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); $Param{ProcessList} = $LayoutObject->BuildSelection( Class => 'Modernize Validate_Required' . ( $Param{Errors}->{ProcessEntityIDInvalid} || ' ' ), Data => $Param{ProcessList}, Name => 'ProcessEntityID', SelectedID => $Param{ProcessEntityID}, PossibleNone => 1, Sort => 'AlphanumericValue', Translation => 0, AutoComplete => 'off', ); # add rich text editor if ( $LayoutObject->{BrowserRichText} ) { # use height/width defined for this screen $Param{RichTextHeight} = $Self->{Config}->{RichTextHeight} || 0; $Param{RichTextWidth} = $Self->{Config}->{RichTextWidth} || 0; $LayoutObject->Block( Name => 'RichText', Data => \%Param, ); } if ( $Param{PreSelectProcess} && $Param{ProcessID} ) { $LayoutObject->Block( Name => 'PreSelectProcess', Data => { ProcessID => $Param{ProcessID}, }, ); } $LayoutObject->Block( Name => 'ProcessList', Data => { %Param, FormID => $Self->{FormID}, }, ); my $Output = $LayoutObject->CustomerHeader(); $Output .= $LayoutObject->CustomerNavigationBar(); $Output .= $LayoutObject->Output( TemplateFile => 'CustomerTicketProcess', Data => { %Param, }, ); # workaround when activity dialog is loaded by AJAX as first activity dialog, if there is # a date field like Pending Time or Dynamic Fields Date/Time or Date, there is no way to set # this options in the footer again $LayoutObject->{HasDatepicker} = 1; $Output .= $LayoutObject->CustomerFooter(); return $Output; } =item _CheckField() checks all the possible ticket fields and returns the ID (if possible) value of the field, if valid and checks are successfull if Display param is set to 0 or not given, it uses ActivityDialog field default value for all fields or global default value as fallback only for certain fields if Display param is set to 1 or 2 it uses the value from the web request my $PriorityID = $CustomerTicketProcessObject->_CheckField( Field => 'PriorityID', Display => 1, # optional, 0 or 1 or 2 DefaultValue => '3 normal', # ActivityDialog field default value (it uses global # default value as fall back for mandatory fields # (Queue, Sate, Lock and Priority) ); Returns: $PriorityID = 1; # if PriorityID is set to 1 in the web request my $PriorityID = $CustomerTicketProcessObject->_CheckField( Field => 'PriorityID', Display => 0, DefaultValue => '3 normal', ); Returns: $PriorityID = 3; # since ActivityDialog default value is '3 normal' and # field is hidden =cut sub _CheckField { my ( $Self, %Param ) = @_; # check needed stuff for my $Needed (qw(Field)) { if ( !$Param{$Needed} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $Needed!" ); return; } } # remove the ID and check if the given field is required for creating a ticket my $FieldWithoutID = $Param{Field}; $FieldWithoutID =~ s{ID$}{}xms; my $TicketRequiredField = scalar grep { $_ eq $FieldWithoutID } qw(Queue State Lock Priority); my $Value; # get needed objects my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); # if no Display (or Display == 0) is commited if ( !$Param{Display} ) { # Check if a DefaultValue is given if ( $Param{DefaultValue} ) { # check if the given field param is valid $Value = $Self->_LookupValue( Field => $FieldWithoutID, Value => $Param{DefaultValue}, ); } # if we got a required ticket field, check if we got a valid DefaultValue in the SysConfig if ( !$Value && $TicketRequiredField ) { $Value = $Kernel::OM->Get('Kernel::Config')->Get("Process::Default$FieldWithoutID"); if ( !$Value ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Default Config for Process::Default%s missing!', $FieldWithoutID ), ); } else { # check if the given field param is valid $Value = $Self->_LookupValue( Field => $FieldWithoutID, Value => $Value, ); if ( !$Value ) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject} ->Translate( 'Default Config for Process::Default%s invalid!', $FieldWithoutID ), ); } } } } elsif ( $Param{Display} == 1 ) { # Display == 1 is logicaliy not possible for a ticket required field if ($TicketRequiredField) { $LayoutObject->CustomerFatalError( Message => $LayoutObject->{LanguageObject}->Translate( 'Wrong ActivityDialog Field config: %s can\'t be Display => 1 / Show field (Please change its configuration to be Display => 0 / Do not show field or Display => 2 / Show field as mandatory)!', $Param{Field} ), ); } # check if the given field param is valid if ( $Param{Field} eq 'Article' ) { # in case of article fields we need to fake a value $Value = 1; } else { $Value = $Self->_LookupValue( Field => $Param{Field}, Value => $ParamObject->GetParam( Param => $Param{Field} ) || '', ); } } elsif ( $Param{Display} == 2 ) { # check if the given field param is valid if ( $Param{Field} eq 'Article' ) { my ( $Body, $Subject ) = ( $ParamObject->GetParam( Param => 'Body' ), $ParamObject->GetParam( Param => 'Subject' ) ); $Value = 0; if ( $Body && $Subject ) { $Value = 1; } } else { $Value = $Self->_LookupValue( Field => $Param{Field}, Value => $ParamObject->GetParam( Param => $Param{Field} ) || '', ); } } return $Value; } =item _LookupValue() returns the ID (if possible) of nearly all ticket fields and/or checks if its valid. Can handle IDs or Strings. Currently working with: State, Queue, Lock, Priority (possible more). my $PriorityID = $CustomerTicketProcessObject->_LookupValue( PriorityID => 1, ); $PriorityID = 1; my $StateID = $CustomerTicketProcessObject->_LookupValue( State => 'open', ); $StateID = 3; my $PriorityID = $CustomerTicketProcessObject->_LookupValue( Priority => 'unknownpriority1234', ); $PriorityID = undef; =cut sub _LookupValue { my ( $Self, %Param ) = @_; # get log object my $LogObject = $Kernel::OM->Get('Kernel::System::Log'); # check needed stuff for my $Needed (qw(Field Value)) { if ( !defined $Param{$Needed} ) { $LogObject->Log( Priority => 'error', Message => "Need $Needed!" ); return; } } if ( !$Param{Field} ) { $LogObject->Log( Priority => 'error', Message => "Field should not be empty!" ); return; } # if there is no value, there is nothing to do return if !$Param{Value}; # remove the ID for function name purpose my $FieldWithoutID = $Param{Field}; $FieldWithoutID =~ s{ID$}{}xms; my $LookupFieldName; my $ObjectName; my $FunctionName; # service and SLA lookup needs Name as parameter (While ServiceID an SLAID uses standard) if ( scalar grep { $Param{Field} eq $_ } qw( Service SLA ) ) { $LookupFieldName = 'Name'; $ObjectName = $FieldWithoutID; $FunctionName = $FieldWithoutID . 'Lookup'; } # other fields can use standard parameter names as Priority or PriorityID else { $LookupFieldName = $Param{Field}; $ObjectName = $FieldWithoutID; $FunctionName = $FieldWithoutID . 'Lookup'; } my $Value; my $FieldObject; if ( $Kernel::OM->Get('Kernel::System::Main')->Require( 'Kernel::System::' . $ObjectName, Silent => 1 ) ) { $FieldObject = $Kernel::OM->Get( 'Kernel::System::' . $ObjectName ); } # check if the backend module has the needed *Lookup sub if ( $FieldObject && $FieldObject->can($FunctionName) ) { # call the *Lookup sub and get the value $Value = $FieldObject->$FunctionName( $LookupFieldName => $Param{Value}, ); } # if we didn't have an object and the value has no ref a string e.g. Title and so on # return true elsif ( $Param{Field} eq $FieldWithoutID && !ref $Param{Value} ) { return $Param{Value}; } else { $LogObject->Log( Priority => 'error', Message => "Error while checking with " . $FieldWithoutID . "Object!" ); return; } return if ( !$Value ); # return the given ID value if the *Lookup result was a string if ( $Param{Field} ne $FieldWithoutID ) { return $Param{Value}; } # return the *Lookup string return value return $Value; } sub _GetSLAs { my ( $Self, %Param ) = @_; # if no CustomerUserID is present, consider the logged in customer if ( !$Param{CustomerUserID} ) { $Param{CustomerUserID} = $Self->{UserID}; } # get sla my %SLA; if ( $Param{ServiceID} && $Param{Services} && %{ $Param{Services} } ) { if ( $Param{Services}->{ $Param{ServiceID} } ) { %SLA = $Kernel::OM->Get('Kernel::System::Ticket')->TicketSLAList( %Param, Action => $Self->{Action}, ); } } return \%SLA; } sub _GetServices { my ( $Self, %Param ) = @_; # get service my %Service; # check needed return \%Service if !$Param{QueueID} && !$Param{TicketID}; # get options for default services for unknown customers my $DefaultServiceUnknownCustomer = $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Service::Default::UnknownCustomer'); # if no CustomerUserID is present, consider the logged in customer if ( !$Param{CustomerUserID} ) { $Param{CustomerUserID} = $Self->{UserID}; } # check if still no CustomerUserID is selected # if $DefaultServiceUnknownCustomer = 0 leave CustomerUserID empty, it will not get any services # if $DefaultServiceUnknownCustomer = 1 set CustomerUserID to get default services if ( !$Param{CustomerUserID} && $DefaultServiceUnknownCustomer ) { $Param{CustomerUserID} = ''; } # get service list if ( $Param{CustomerUserID} ) { %Service = $Kernel::OM->Get('Kernel::System::Ticket')->TicketServiceList( %Param, Action => $Self->{Action}, ); } return \%Service; } sub _GetPriorities { my ( $Self, %Param ) = @_; my %Priorities; # Initially we have just the default Queue Parameter # so make sure to get the ID in that case my $QueueID; if ( !$Param{QueueID} && $Param{Queue} ) { $QueueID = $Kernel::OM->Get('Kernel::System::Queue')->QueueLookup( Queue => $Param{Queue} ); } if ( $Param{QueueID} || $QueueID || $Param{TicketID} ) { %Priorities = $Kernel::OM->Get('Kernel::System::Ticket')->TicketPriorityList( %Param, Action => $Self->{Action}, CustomerUserID => $Self->{UserID}, ); } return \%Priorities; } sub _GetQueues { my ( $Self, %Param ) = @_; # get config object my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); # check own selection my %NewQueues; if ( $ConfigObject->Get('Ticket::Frontend::NewQueueOwnSelection') ) { %NewQueues = %{ $ConfigObject->Get('Ticket::Frontend::NewQueueOwnSelection') }; } else { # SelectionType Queue or SystemAddress? my %Queues; if ( $ConfigObject->Get('Ticket::Frontend::NewQueueSelectionType') eq 'Queue' ) { %Queues = $Kernel::OM->Get('Kernel::System::Ticket')->MoveList( %Param, Type => 'create', Action => $Self->{Action}, QueueID => $Self->{QueueID}, CustomerUserID => $Self->{UserID}, ); } else { %Queues = $Kernel::OM->Get('Kernel::System::DB')->GetTableData( Table => 'system_address', What => 'queue_id, id', Valid => 1, Clamp => 1, ); } # get create permission queues my %UserGroups = $Kernel::OM->Get('Kernel::System::CustomerGroup')->GroupMemberList( UserID => $ConfigObject->Get('CustomerPanelUserID'), Type => 'create', Result => 'HASH', ); # build selection string QUEUEID: for my $QueueID ( sort keys %Queues ) { my %QueueData = $Kernel::OM->Get('Kernel::System::Queue')->QueueGet( ID => $QueueID ); # permission check, can we create new tickets in queue next QUEUEID if !$UserGroups{ $QueueData{GroupID} }; my $String = $ConfigObject->Get('Ticket::Frontend::NewQueueSelectionString') || ' <> - Queue: '; $String =~ s//$QueueData{Name}/g; $String =~ s//$QueueData{Comment}/g; if ( $ConfigObject->Get('Ticket::Frontend::NewQueueSelectionType') ne 'Queue' ) { my %SystemAddressData = $Self->{SystemAddress}->SystemAddressGet( ID => $Queues{$QueueID}, ); $String =~ s//$SystemAddressData{Realname}/g; $String =~ s//$SystemAddressData{Name}/g; } $NewQueues{$QueueID} = $String; } } return \%NewQueues; } sub _GetStates { my ( $Self, %Param ) = @_; my %States = $Kernel::OM->Get('Kernel::System::Ticket')->TicketStateList( %Param, # Set default values for new process ticket QueueID => $Param{QueueID} || 1, TicketID => $Param{TicketID} || '', # remove type, since if Ticket::Type is active in sysconfig, the Type parameter will # be sent and the TicketStateList will send the parameter as State Type Type => undef, Action => $Self->{Action}, CustomerUserID => $Self->{UserID}, ); return \%States; } sub _GetTypes { my ( $Self, %Param ) = @_; # get type my %Type; if ( $Param{QueueID} || $Param{TicketID} ) { %Type = $Kernel::OM->Get('Kernel::System::Ticket')->TicketTypeList( %Param, Action => $Self->{Action}, CustomerUserID => $Self->{UserID}, ); } return \%Type; } sub _GetAJAXUpdatableFields { my ( $Self, %Param ) = @_; my %DefaultUpdatableFields = ( PriorityID => 1, QueueID => 1, ResponsibleID => 1, ServiceID => 1, SLAID => 1, StateID => 1, OwnerID => 1, LockID => 1, ); # get backend object my $BackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend'); my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet( Valid => 1, ObjectType => 'Ticket', ); # reduce the dynamic fields to only the ones that are desinged for customer interface my @CustomerDynamicFields; DYNAMICFIELD: for my $DynamicFieldConfig ( @{$DynamicField} ) { next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig); my $IsCustomerInterfaceCapable = $BackendObject->HasBehavior( DynamicFieldConfig => $DynamicFieldConfig, Behavior => 'IsCustomerInterfaceCapable', ); next DYNAMICFIELD if !$IsCustomerInterfaceCapable; push @CustomerDynamicFields, $DynamicFieldConfig; } $DynamicField = \@CustomerDynamicFields; # create a DynamicFieldLookupTable my %DynamicFieldLookup = map { 'DynamicField_' . $_->{Name} => $_ } @{$DynamicField}; my @UpdatableFields; FIELD: for my $Field ( sort keys %{ $Param{ActivityDialogFields} } ) { my $FieldData = $Param{ActivityDialogFields}->{$Field}; # skip hidden fields next FIELD if !$FieldData->{Display}; # for Dynamic Fields check if is AJAXUpdatable if ( $Field =~ m{^DynamicField_(.*)}xms ) { my $DynamicFieldConfig = $DynamicFieldLookup{$Field}; # skip any field with wrong config next FIELD if !IsHashRefWithData($DynamicFieldConfig); # skip field if is not IsACLReducible (updatable) my $IsACLReducible = $BackendObject->HasBehavior( DynamicFieldConfig => $DynamicFieldConfig, Behavior => 'IsACLReducible', ); next FIELD if !$IsACLReducible; push @UpdatableFields, $Field; } # for all others use %DefaultUpdatableFields table else { # standarize the field name (e.g. use StateID for State field) my $FieldName = $Self->{NameToID}->{$Field}; # skip if field name could not be converted (this means that field is unknown) next FIELD if !$FieldName; # skip if the field is not updatable via ajax next FIELD if !$DefaultUpdatableFields{$FieldName}; push @UpdatableFields, $FieldName; } } return \@UpdatableFields; } sub _GetFieldsToUpdateStrg { my ( $Self, %Param ) = @_; my $FieldsToUpdate = ''; if ( IsArrayRefWithData( $Param{AJAXUpdatableFields} ) ) { my $FirstItem = 1; FIELD: for my $Field ( @{ $Param{AJAXUpdatableFields} } ) { next FIELD if $Field eq $Param{TriggerField}; if ($FirstItem) { $FirstItem = 0; } else { $FieldsToUpdate .= ', '; } $FieldsToUpdate .= "'" . $Field . "'"; } } return $FieldsToUpdate; } 1;