1# --
2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
3# --
4# This software comes with ABSOLUTELY NO WARRANTY. For details, see
5# the enclosed file COPYING for license information (GPL). If you
6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
7# --
8
9package Kernel::Modules::AdminGenericAgent;
10
11use strict;
12use warnings;
13
14use Kernel::System::VariableCheck qw(:all);
15use Kernel::Language qw(Translatable);
16
17our $ObjectManagerDisabled = 1;
18
19sub new {
20    my ( $Type, %Param ) = @_;
21
22    # allocate new hash for object
23    my $Self = {%Param};
24    bless( $Self, $Type );
25
26    # get the dynamic fields for ticket object
27    $Self->{DynamicField} = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
28        Valid      => 1,
29        ObjectType => ['Ticket'],
30    );
31
32    return $Self;
33}
34
35sub Run {
36    my ( $Self, %Param ) = @_;
37
38    # get layout object
39    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
40
41    # secure mode message (don't allow this action till secure mode is enabled)
42    if ( !$Kernel::OM->Get('Kernel::Config')->Get('SecureMode') ) {
43        return $LayoutObject->SecureMode();
44    }
45
46    # get param object
47    my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
48
49    # get config data
50    $Self->{Profile}    = $ParamObject->GetParam( Param => 'Profile' )    || '';
51    $Self->{OldProfile} = $ParamObject->GetParam( Param => 'OldProfile' ) || '';
52    $Self->{Subaction}  = $ParamObject->GetParam( Param => 'Subaction' )  || '';
53
54    # get needed objects
55    my $CheckItemObject    = $Kernel::OM->Get('Kernel::System::CheckItem');
56    my $GenericAgentObject = $Kernel::OM->Get('Kernel::System::GenericAgent');
57
58    # ---------------------------------------------------------- #
59    # run a generic agent job -> "run now"
60    # ---------------------------------------------------------- #
61    if ( $Self->{Subaction} eq 'RunNow' ) {
62
63        # challenge token check for write action
64        $LayoutObject->ChallengeTokenCheck();
65
66        my $Run = $GenericAgentObject->JobRun(
67            Job    => $Self->{Profile},
68            UserID => 1,
69        );
70
71        # redirect
72        if ($Run) {
73            return $LayoutObject->Redirect(
74                OP => "Action=$Self->{Action}",
75            );
76        }
77
78        # redirect
79        return $LayoutObject->ErrorScreen();
80    }
81
82    if ( $Self->{Subaction} eq 'Run' ) {
83
84        return $Self->_MaskRun();
85    }
86
87    # --------------------------------------------------------------- #
88    # save generic agent job and show a view of all affected tickets
89    # --------------------------------------------------------------- #
90    # show result site
91    if ( $Self->{Subaction} eq 'UpdateAction' ) {
92
93        # challenge token check for write action
94        $LayoutObject->ChallengeTokenCheck();
95
96        my ( %GetParam, %Errors );
97
98        # challenge token check for write action
99        $LayoutObject->ChallengeTokenCheck();
100
101        # get single params
102        for my $Parameter (
103            qw(TicketNumber Title MIMEBase_From MIMEBase_To MIMEBase_Cc MIMEBase_Subject MIMEBase_Body CustomerID
104            CustomerUserLogin Agent SearchInArchive
105            NewTitle
106            NewCustomerID NewPendingTime NewPendingTimeType NewCustomerUserLogin
107            NewStateID NewQueueID NewPriorityID NewOwnerID NewResponsibleID
108            NewTypeID NewServiceID NewSLAID
109            NewNoteFrom NewNoteSubject NewNoteBody NewNoteIsVisibleForCustomer NewNoteTimeUnits NewModule
110            NewParamKey1 NewParamKey2 NewParamKey3 NewParamKey4
111            NewParamValue1 NewParamValue2 NewParamValue3 NewParamValue4
112            NewParamKey5 NewParamKey6 NewParamKey7 NewParamKey8
113            NewParamValue5 NewParamValue6 NewParamValue7 NewParamValue8
114            NewLockID NewDelete NewCMD NewSendNoNotification NewArchiveFlag
115            ScheduleLastRun Valid
116            )
117            )
118        {
119            $GetParam{$Parameter} = $ParamObject->GetParam( Param => $Parameter );
120
121            # remove leading and trailing blank spaces
122            if ( $GetParam{$Parameter} ) {
123                $CheckItemObject->StringClean(
124                    StringRef => \$GetParam{$Parameter},
125                );
126            }
127        }
128
129        for my $Type (
130            qw(Time ChangeTime CloseTime LastChangeTime LastCloseTime TimePending EscalationTime EscalationResponseTime EscalationUpdateTime EscalationSolutionTime)
131            )
132        {
133            my $Key = $Type . 'SearchType';
134            $GetParam{$Key} = $ParamObject->GetParam( Param => $Key );
135        }
136        for my $Type (
137            qw(
138            TicketCreate           TicketChange
139            TicketClose            TicketLastChange
140            TicketLastClose
141            TicketPending
142            TicketEscalation       TicketEscalationResponse
143            TicketEscalationUpdate TicketEscalationSolution
144            )
145            )
146        {
147            for my $Attribute (
148                qw(
149                TimePoint TimePointFormat TimePointStart
150                TimeStart TimeStartDay TimeStartMonth TimeStopMonth
151                TimeStop TimeStopDay TimeStopYear TimeStartYear
152                )
153                )
154            {
155                my $Key = $Type . $Attribute;
156                $GetParam{$Key} = $ParamObject->GetParam( Param => $Key );
157            }
158
159            # validate data
160            for my $Attribute (
161                qw(TimeStartDay TimeStartMonth TimeStopMonth TimeStopDay)
162                )
163            {
164                my $Key = $Type . $Attribute;
165
166                if ( $GetParam{$Key} ) {
167                    $GetParam{$Key} = sprintf( '%02d', $GetParam{$Key} );
168                }
169            }
170        }
171
172        # get dynamic fields to set from web request
173        # to store dynamic fields profile data
174        my %DynamicFieldValues;
175
176        # get dynamic field backend object
177        my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
178
179        # cycle trough the activated Dynamic Fields for this screen
180        DYNAMICFIELD:
181        for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
182            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
183
184            # extract the dynamic field value from the web request
185            my $DynamicFieldValue = $DynamicFieldBackendObject->EditFieldValueGet(
186                DynamicFieldConfig      => $DynamicFieldConfig,
187                ParamObject             => $ParamObject,
188                LayoutObject            => $LayoutObject,
189                ReturnTemplateStructure => 1,
190            );
191
192            # set the complete value structure in GetParam to store it later in the Generic Agent Job
193            if ( IsHashRefWithData($DynamicFieldValue) ) {
194                %DynamicFieldValues = ( %DynamicFieldValues, %{$DynamicFieldValue} );
195            }
196        }
197
198        # get array params
199        for my $Parameter (
200            qw(LockIDs StateIDs StateTypeIDs QueueIDs PriorityIDs OwnerIDs ResponsibleIDs
201            TypeIDs ServiceIDs SLAIDs
202            ScheduleDays ScheduleMinutes ScheduleHours
203            EventValues
204            )
205            )
206        {
207
208            # get search array params (get submitted params)
209            if ( $ParamObject->GetArray( Param => $Parameter ) ) {
210                @{ $GetParam{$Parameter} } = $ParamObject->GetArray( Param => $Parameter );
211            }
212        }
213
214        # get Dynamic fields for search from web request
215        # cycle trough the activated Dynamic Fields for this screen
216        DYNAMICFIELD:
217        for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
218            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
219
220            # get search field preferences
221            my $SearchFieldPreferences = $DynamicFieldBackendObject->SearchFieldPreferences(
222                DynamicFieldConfig => $DynamicFieldConfig,
223            );
224
225            next DYNAMICFIELD if !IsArrayRefWithData($SearchFieldPreferences);
226
227            PREFERENCE:
228            for my $Preference ( @{$SearchFieldPreferences} ) {
229
230                # extract the dynamic field value from the web request
231                my $DynamicFieldValue = $DynamicFieldBackendObject->SearchFieldValueGet(
232                    DynamicFieldConfig     => $DynamicFieldConfig,
233                    ParamObject            => $ParamObject,
234                    ReturnProfileStructure => 1,
235                    LayoutObject           => $LayoutObject,
236                    Type                   => $Preference->{Type},
237                );
238
239                # set the complete value structure in %DynamicFieldValues to store it later in the
240                # Generic Agent Job
241                if ( IsHashRefWithData($DynamicFieldValue) ) {
242                    %DynamicFieldValues = ( %DynamicFieldValues, %{$DynamicFieldValue} );
243                }
244            }
245        }
246
247        # check needed data
248        if ( !$Self->{Profile} ) {
249            $Errors{ProfileInvalid} = 'ServerError';
250        }
251
252        # Check length of fields from Add Note section.
253        if ( length $GetParam{NewNoteFrom} > 200 ) {
254            $Errors{NewNoteFromServerError} = 'ServerError';
255        }
256        if ( length $GetParam{NewNoteSubject} > 200 ) {
257            $Errors{NewNoteSubjectServerError} = 'ServerError';
258        }
259        if ( length $GetParam{NewNoteBody} > 200 ) {
260            $Errors{NewNoteBodyServerError} = 'ServerError';
261        }
262
263        # Check if ticket selection contains stop words
264        my %StopWordsServerErrors = $Self->_StopWordsServerErrorsGet(
265            MIMEBase_From    => $GetParam{MIMEBase_From},
266            MIMEBase_To      => $GetParam{MIMEBase_To},
267            MIMEBase_Cc      => $GetParam{MIMEBase_Cc},
268            MIMEBase_Subject => $GetParam{MIMEBase_Subject},
269            MIMEBase_Body    => $GetParam{MIMEBase_Body},
270        );
271        %Errors = ( %Errors, %StopWordsServerErrors );
272
273        # if no errors occurred
274        if ( !%Errors ) {
275
276            if ( $Self->{OldProfile} ) {
277
278                # remove/clean up old profile stuff
279                $GenericAgentObject->JobDelete(
280                    Name   => $Self->{OldProfile},
281                    UserID => $Self->{UserID},
282                );
283            }
284
285            # insert new profile params
286            my $JobAddResult = $GenericAgentObject->JobAdd(
287                Name => $Self->{Profile},
288                Data => {
289                    %GetParam,
290                    %DynamicFieldValues,
291                },
292                UserID => $Self->{UserID},
293            );
294
295            if ($JobAddResult) {
296
297                # if the user would like to continue editing the generic agent job, just redirect to the edit screen
298                if (
299                    defined $ParamObject->GetParam( Param => 'ContinueAfterSave' )
300                    && ( $ParamObject->GetParam( Param => 'ContinueAfterSave' ) eq '1' )
301                    )
302                {
303                    my $Profile = $Self->{Profile} || '';
304                    return $LayoutObject->Redirect( OP => "Action=$Self->{Action};Subaction=Update;Profile=$Profile" );
305                }
306                else {
307
308                    # otherwise return to overview
309                    return $LayoutObject->Redirect( OP => "Action=$Self->{Action}" );
310                }
311
312            }
313            else {
314                $Errors{ProfileInvalid}    = 'ServerError';
315                $Errors{ProfileInvalidMsg} = 'AddError';
316            }
317        }
318
319        # something went wrong
320        my $JobDataReference;
321        $JobDataReference = $Self->_MaskUpdate(
322            %Param,
323            %GetParam,
324            %DynamicFieldValues,
325            %Errors,
326            StopWordsAlreadyChecked => 1,
327        );
328
329        # generate search mask
330        my $Output = $LayoutObject->Header(
331            Title => Translatable('Edit'),
332        );
333        $Output .= $LayoutObject->NavigationBar();
334        $Output .= $LayoutObject->Output(
335            TemplateFile => 'AdminGenericAgent',
336            Data         => $JobDataReference,
337        );
338        $Output .= $LayoutObject->Footer();
339        return $Output;
340    }
341
342    # ---------------------------------------------------------- #
343    # edit generic agent job
344    # ---------------------------------------------------------- #
345    if ( $Self->{Subaction} eq 'Update' ) {
346        my $JobDataReference;
347        $JobDataReference = $Self->_MaskUpdate(%Param);
348
349        # generate search mask
350        my $Output = $LayoutObject->Header(
351            Title => Translatable('Edit'),
352        );
353
354        $Output .= $LayoutObject->NavigationBar();
355        $Output .= $LayoutObject->Output(
356            TemplateFile => 'AdminGenericAgent',
357            Data         => $JobDataReference,
358        );
359        $Output .= $LayoutObject->Footer();
360        return $Output;
361    }
362
363    # ---------------------------------------------------------- #
364    # Update dynamic fields for generic agent job by AJAX
365    # ---------------------------------------------------------- #
366    if ( $Self->{Subaction} eq 'AddDynamicField' ) {
367        my $DynamicFieldID = $ParamObject->GetParam( Param => 'DynamicFieldID' );
368        my $Type           = $ParamObject->GetParam( Param => 'Type' ) || '';
369        my $SelectedValue  = $ParamObject->GetParam( Param => 'SelectedValue' );
370        my $Widget         = $ParamObject->GetParam( Param => 'Widget' );
371
372        my $DynamicFieldConfig = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldGet(
373            ID => $DynamicFieldID,
374        );
375
376        my %JobData;
377        if ( $Self->{Profile} ) {
378            %JobData = $Kernel::OM->Get('Kernel::System::GenericAgent')->JobGet(
379                Name => $Self->{Profile},
380            );
381        }
382        $JobData{Profile}   = $Self->{Profile};
383        $JobData{Subaction} = $Self->{Subaction};
384
385        my $DynamicFieldHTML;
386        my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
387
388        # Get field HTML.
389        if ( $Widget eq 'Select' ) {
390            $DynamicFieldHTML = $DynamicFieldBackendObject->SearchFieldRender(
391                DynamicFieldConfig     => $DynamicFieldConfig,
392                Profile                => \%JobData,
393                LayoutObject           => $LayoutObject,
394                ConfirmationCheckboxes => 1,
395                Type                   => $Type,
396            );
397        }
398        elsif ( $Widget eq 'Update' ) {
399            my $PossibleValuesFilter;
400
401            my $IsACLReducible = $DynamicFieldBackendObject->HasBehavior(
402                DynamicFieldConfig => $DynamicFieldConfig,
403                Behavior           => 'IsACLReducible',
404            );
405
406            if ($IsACLReducible) {
407
408                # Get PossibleValues.
409                my $PossibleValues = $DynamicFieldBackendObject->PossibleValuesGet(
410                    DynamicFieldConfig => $DynamicFieldConfig,
411                );
412
413                # Check if field has PossibleValues property in its configuration.
414                if ( IsHashRefWithData($PossibleValues) ) {
415
416                    # Convert possible values key => value to key => key for ACLs using a Hash slice.
417                    my %AclData = %{$PossibleValues};
418                    @AclData{ keys %AclData } = keys %AclData;
419
420                    my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');
421
422                    # Set possible values filter from ACLs.
423                    my $ACL = $TicketObject->TicketAcl(
424                        Action        => $Self->{Action},
425                        Type          => 'DynamicField_' . $DynamicFieldConfig->{Name},
426                        ReturnType    => 'Ticket',
427                        ReturnSubType => 'DynamicField_' . $DynamicFieldConfig->{Name},
428                        Data          => \%AclData,
429                        UserID        => $Self->{UserID},
430                    );
431                    if ($ACL) {
432                        my %Filter = $TicketObject->TicketAclData();
433
434                        # Convert Filer key => key back to key => value using map.
435                        %{$PossibleValuesFilter} = map { $_ => $PossibleValues->{$_} }
436                            keys %Filter;
437                    }
438                }
439            }
440            $DynamicFieldHTML = $DynamicFieldBackendObject->EditFieldRender(
441                DynamicFieldConfig   => $DynamicFieldConfig,
442                PossibleValuesFilter => $PossibleValuesFilter,
443                LayoutObject         => $LayoutObject,
444                ParamObject          => $ParamObject,
445                UseDefaultValue      => 0,
446                OverridePossibleNone => 1,
447                ConfirmationNeeded   => 1,
448                NoIgnoreField        => 1,
449                Template             => \%JobData,
450                MaxLength            => 200,
451            );
452        }
453
454        $DynamicFieldHTML->{ID} = $SelectedValue;
455
456        my $Output = $LayoutObject->JSONEncode(
457            Data => $DynamicFieldHTML,
458        );
459
460        # Send JSON response.
461        return $LayoutObject->Attachment(
462            ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
463            Content     => $Output,
464            Type        => 'inline',
465            NoCache     => 1,
466        );
467    }
468
469    # ---------------------------------------------------------- #
470    # delete an generic agent job
471    # ---------------------------------------------------------- #
472    if ( $Self->{Subaction} eq 'Delete' && $Self->{Profile} ) {
473
474        # challenge token check for write action
475        $LayoutObject->ChallengeTokenCheck();
476
477        if ( $Self->{Profile} ) {
478            $GenericAgentObject->JobDelete(
479                Name   => $Self->{Profile},
480                UserID => $Self->{UserID},
481            );
482        }
483    }
484
485    # ---------------------------------------------------------- #
486    # overview of all generic agent jobs
487    # ---------------------------------------------------------- #
488    $LayoutObject->Block(
489        Name => 'ActionList',
490    );
491    $LayoutObject->Block(
492        Name => 'ActionAdd',
493    );
494    $LayoutObject->Block(
495        Name => 'Filter',
496    );
497    $LayoutObject->Block(
498        Name => 'Overview',
499    );
500
501    my %Jobs = $GenericAgentObject->JobList();
502
503    # if there are any data, it is shown
504    if (%Jobs) {
505        my $Counter = 1;
506        for my $JobKey ( sort keys %Jobs ) {
507            my %JobData = $GenericAgentObject->JobGet( Name => $JobKey );
508
509            # css setting and text for valid or invalid jobs
510            $JobData{ShownValid} = $JobData{Valid} ? 'valid' : 'invalid';
511
512            # separate each search result line by using several css
513            $LayoutObject->Block(
514                Name => 'Row',
515                Data => {%JobData},
516            );
517        }
518    }
519
520    # otherwise a no data found message is displayed
521    else {
522        $LayoutObject->Block(
523            Name => 'NoDataFoundMsg',
524            Data => {},
525        );
526    }
527
528    # generate search mask
529    my $Output = $LayoutObject->Header();
530    $Output .= $LayoutObject->NavigationBar();
531    $Output .= $LayoutObject->Output(
532        TemplateFile => 'AdminGenericAgent',
533        Data         => \%Param,
534    );
535    $Output .= $LayoutObject->Footer();
536    return $Output;
537}
538
539sub _MaskUpdate {
540    my ( $Self, %Param ) = @_;
541
542    my %JobData;
543
544    if ( $Self->{Profile} ) {
545
546        # get db job data
547        %JobData = $Kernel::OM->Get('Kernel::System::GenericAgent')->JobGet(
548            Name => $Self->{Profile},
549        );
550    }
551    $JobData{Profile}   = $Self->{Profile};
552    $JobData{Subaction} = $Self->{Subaction};
553
554    # get config object
555    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
556
557    # get list type
558    my $TreeView = 0;
559    if ( $ConfigObject->Get('Ticket::Frontend::ListType') eq 'tree' ) {
560        $TreeView = 1;
561    }
562
563    my %ShownUsers = $Kernel::OM->Get('Kernel::System::User')->UserList(
564        Type  => 'Long',
565        Valid => 1,
566    );
567
568    # get layout object
569    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
570
571    $JobData{OwnerStrg} = $LayoutObject->BuildSelection(
572        Data        => \%ShownUsers,
573        Name        => 'OwnerIDs',
574        Multiple    => 1,
575        Size        => 5,
576        Translation => 0,
577        SelectedID  => $JobData{OwnerIDs},
578        Class       => 'Modernize',
579    );
580    $JobData{NewOwnerStrg} = $LayoutObject->BuildSelection(
581        Data        => \%ShownUsers,
582        Name        => 'NewOwnerID',
583        Size        => 5,
584        Multiple    => 0,
585        Translation => 0,
586        SelectedID  => $JobData{NewOwnerID},
587        Class       => 'Modernize',
588    );
589    my %Hours;
590    for my $Number ( 0 .. 23 ) {
591        $Hours{$Number} = sprintf( "%02d", $Number );
592    }
593    $JobData{ScheduleHoursList} = $LayoutObject->BuildSelection(
594        Data        => \%Hours,
595        Name        => 'ScheduleHours',
596        Size        => 6,
597        Multiple    => 1,
598        Translation => 0,
599        SelectedID  => $JobData{ScheduleHours},
600        Class       => 'Modernize',
601    );
602    my %Minutes;
603    for my $Number ( 0 .. 59 ) {
604        $Minutes{$Number} = sprintf( "%02d", $Number );
605    }
606    $JobData{ScheduleMinutesList} = $LayoutObject->BuildSelection(
607        Data        => \%Minutes,
608        Name        => 'ScheduleMinutes',
609        Size        => 6,
610        Multiple    => 1,
611        Translation => 0,
612        SelectedID  => $JobData{ScheduleMinutes},
613        Class       => 'Modernize',
614    );
615    $JobData{ScheduleDaysList} = $LayoutObject->BuildSelection(
616        Data => {
617            1 => Translatable('Mon'),
618            2 => Translatable('Tue'),
619            3 => Translatable('Wed'),
620            4 => Translatable('Thu'),
621            5 => Translatable('Fri'),
622            6 => Translatable('Sat'),
623            0 => Translatable('Sun'),
624        },
625        Sort       => 'NumericKey',
626        Name       => 'ScheduleDays',
627        Size       => 7,
628        Multiple   => 1,
629        SelectedID => $JobData{ScheduleDays},
630        Class      => 'Modernize',
631    );
632
633    # get state object
634    my $StateObject = $Kernel::OM->Get('Kernel::System::State');
635
636    $JobData{StatesStrg} = $LayoutObject->BuildSelection(
637        Data => {
638            $StateObject->StateList(
639                UserID => 1,
640                Action => $Self->{Action},
641            ),
642        },
643        Name       => 'StateIDs',
644        Multiple   => 1,
645        Size       => 5,
646        SelectedID => $JobData{StateIDs},
647        Class      => 'Modernize',
648    );
649    $JobData{NewStatesStrg} = $LayoutObject->BuildSelection(
650        Data => {
651            $StateObject->StateList(
652                UserID => 1,
653                Action => $Self->{Action},
654            ),
655        },
656        Name       => 'NewStateID',
657        Size       => 5,
658        Multiple   => 0,
659        SelectedID => $JobData{NewStateID},
660        Class      => 'Modernize',
661    );
662    $JobData{NewPendingTimeTypeStrg} = $LayoutObject->BuildSelection(
663        Data => [
664            {
665                Key   => 60,
666                Value => Translatable('minute(s)'),
667            },
668            {
669                Key   => 3600,
670                Value => Translatable('hour(s)'),
671            },
672            {
673                Key   => 86400,
674                Value => Translatable('day(s)'),
675            },
676            {
677                Key   => 2592000,
678                Value => Translatable('month(s)'),
679            },
680            {
681                Key   => 31536000,
682                Value => Translatable('year(s)'),
683            },
684
685        ],
686        Name        => 'NewPendingTimeType',
687        Size        => 1,
688        Multiple    => 0,
689        SelectedID  => $JobData{NewPendingTimeType},
690        Translation => 1,
691        Title       => $LayoutObject->{LanguageObject}->Translate('Time unit'),
692        Class       => 'Modernize',
693    );
694
695    # get queue object
696    my $QueueObject = $Kernel::OM->Get('Kernel::System::Queue');
697
698    $JobData{QueuesStrg} = $LayoutObject->AgentQueueListOption(
699        Data               => { $QueueObject->GetAllQueues(), },
700        Size               => 5,
701        Multiple           => 1,
702        Name               => 'QueueIDs',
703        SelectedIDRefArray => $JobData{QueueIDs},
704        TreeView           => $TreeView,
705        OnChangeSubmit     => 0,
706        Class              => 'Modernize',
707    );
708    $JobData{NewQueuesStrg} = $LayoutObject->AgentQueueListOption(
709        Data           => { $QueueObject->GetAllQueues(), },
710        Size           => 5,
711        Multiple       => 0,
712        Name           => 'NewQueueID',
713        SelectedID     => $JobData{NewQueueID},
714        TreeView       => $TreeView,
715        OnChangeSubmit => 0,
716        Class          => 'Modernize',
717    );
718
719    # get priority object
720    my $PriorityObject = $Kernel::OM->Get('Kernel::System::Priority');
721
722    $JobData{PrioritiesStrg} = $LayoutObject->BuildSelection(
723        Data => {
724            $PriorityObject->PriorityList(
725                UserID => 1,
726                Action => $Self->{Action},
727            ),
728        },
729        Name       => 'PriorityIDs',
730        Size       => 5,
731        Multiple   => 1,
732        SelectedID => $JobData{PriorityIDs},
733        Class      => 'Modernize',
734    );
735    $JobData{NewPrioritiesStrg} = $LayoutObject->BuildSelection(
736        Data => {
737            $PriorityObject->PriorityList(
738                UserID => 1,
739                Action => $Self->{Action},
740            ),
741        },
742        Name       => 'NewPriorityID',
743        Size       => 5,
744        Multiple   => 0,
745        SelectedID => $JobData{NewPriorityID},
746        Class      => 'Modernize',
747    );
748
749    # get time option
750    my %Map = (
751        TicketCreate             => 'Time',
752        TicketChange             => 'ChangeTime',
753        TicketClose              => 'CloseTime',
754        TicketLastChange         => 'LastChangeTime',
755        TicketLastClose          => 'LastCloseTime',
756        TicketPending            => 'TimePending',
757        TicketEscalation         => 'EscalationTime',
758        TicketEscalationResponse => 'EscalationResponseTime',
759        TicketEscalationUpdate   => 'EscalationUpdateTime',
760        TicketEscalationSolution => 'EscalationSolutionTime',
761    );
762    for my $Type (
763        qw(
764        TicketCreate           TicketClose
765        TicketChange           TicketLastChange
766        TicketLastClose
767        TicketPending
768        TicketEscalation       TicketEscalationResponse
769        TicketEscalationUpdate TicketEscalationSolution
770        )
771        )
772    {
773        my $SearchType = $Map{$Type} . 'SearchType';
774        if ( !$JobData{$SearchType} ) {
775            $JobData{ $SearchType . '::None' } = 'checked="checked"';
776        }
777        elsif ( $JobData{$SearchType} eq 'TimePoint' ) {
778            $JobData{ $SearchType . '::TimePoint' } = 'checked="checked"';
779        }
780        elsif ( $JobData{$SearchType} eq 'TimeSlot' ) {
781            $JobData{ $SearchType . '::TimeSlot' } = 'checked="checked"';
782        }
783
784        my %Counter;
785        for my $Number ( 1 .. 60 ) {
786            $Counter{$Number} = sprintf( "%02d", $Number );
787        }
788
789        # time
790        $JobData{ $Type . 'TimePoint' } = $LayoutObject->BuildSelection(
791            Data        => \%Counter,
792            Name        => $Type . 'TimePoint',
793            SelectedID  => $JobData{ $Type . 'TimePoint' },
794            Translation => 0,
795        );
796        $JobData{ $Type . 'TimePointStart' } = $LayoutObject->BuildSelection(
797            Data => {
798                Last   => Translatable('within the last ...'),
799                Next   => Translatable('within the next ...'),
800                Before => Translatable('more than ... ago'),
801            },
802            Name       => $Type . 'TimePointStart',
803            SelectedID => $JobData{ $Type . 'TimePointStart' } || 'Last',
804        );
805        $JobData{ $Type . 'TimePointFormat' } = $LayoutObject->BuildSelection(
806            Data => {
807                minute => Translatable('minute(s)'),
808                hour   => Translatable('hour(s)'),
809                day    => Translatable('day(s)'),
810                week   => Translatable('week(s)'),
811                month  => Translatable('month(s)'),
812                year   => Translatable('year(s)'),
813            },
814            Name       => $Type . 'TimePointFormat',
815            SelectedID => $JobData{ $Type . 'TimePointFormat' },
816        );
817        $JobData{ $Type . 'TimeStart' } = $LayoutObject->BuildDateSelection(
818            %JobData,
819            Prefix   => $Type . 'TimeStart',
820            Format   => 'DateInputFormat',
821            DiffTime => -( 60 * 60 * 24 ) * 30,
822            Validate => 1,
823        );
824        $JobData{ $Type . 'TimeStop' } = $LayoutObject->BuildDateSelection(
825            %JobData,
826            Prefix   => $Type . 'TimeStop',
827            Format   => 'DateInputFormat',
828            Validate => 1,
829        );
830    }
831
832    $JobData{DeleteOption} = $LayoutObject->BuildSelection(
833        Data       => $ConfigObject->Get('YesNoOptions'),
834        Name       => 'NewDelete',
835        SelectedID => $JobData{NewDelete} || 0,
836        Class      => 'Modernize',
837    );
838    $JobData{ValidOption} = $LayoutObject->BuildSelection(
839        Data       => $ConfigObject->Get('YesNoOptions'),
840        Name       => 'Valid',
841        SelectedID => defined( $JobData{Valid} ) ? $JobData{Valid} : 1,
842        Class      => 'Modernize',
843    );
844
845    # get lock object
846    my $LockObject = $Kernel::OM->Get('Kernel::System::Lock');
847
848    $JobData{LockOption} = $LayoutObject->BuildSelection(
849        Data => {
850            $LockObject->LockList(
851                UserID => 1,
852                Action => $Self->{Action},
853            ),
854        },
855        Name       => 'LockIDs',
856        Multiple   => 1,
857        Size       => 3,
858        SelectedID => $JobData{LockIDs},
859        Class      => 'Modernize',
860    );
861    $JobData{NewLockOption} = $LayoutObject->BuildSelection(
862        Data => {
863            $LockObject->LockList(
864                UserID => 1,
865                Action => $Self->{Action},
866            ),
867        },
868        Name       => 'NewLockID',
869        Size       => 3,
870        Multiple   => 0,
871        SelectedID => $JobData{NewLockID},
872        Class      => 'Modernize',
873    );
874
875    # Show server errors if ticket selection contains stop words
876    my %StopWordsServerErrors;
877    if ( !$Param{StopWordsAlreadyChecked} ) {
878        %StopWordsServerErrors = $Self->_StopWordsServerErrorsGet(
879            MIMEBase_From    => $JobData{MIMEBase_From},
880            MIMEBase_To      => $JobData{MIMEBase_To},
881            MIMEBase_Cc      => $JobData{MIMEBase_Cc},
882            MIMEBase_Subject => $JobData{MIMEBase_Subject},
883            MIMEBase_Body    => $JobData{MIMEBase_Body},
884        );
885    }
886
887    # REMARK: we changed the wording "Send no notifications" to
888    # "Send agent/customer notifications on changes" in frontend.
889    # But the backend code is still the same (compatibility).
890    # Because of this case we changed 1=>'Yes' to 1=>'No'
891    $JobData{SendNoNotificationOption} = $LayoutObject->BuildSelection(
892        Data => {
893            '1' => Translatable('No'),
894            '0' => Translatable('Yes'),
895        },
896        Name       => 'NewSendNoNotification',
897        SelectedID => $JobData{NewSendNoNotification} || 0,
898        Class      => 'Modernize',
899    );
900
901    $JobData{AllowCustomScriptExecution} = $ConfigObject->Get('Ticket::GenericAgentAllowCustomScriptExecution') || 0;
902    $JobData{AllowCustomModuleExecution} = $ConfigObject->Get('Ticket::GenericAgentAllowCustomModuleExecution') || 0;
903
904    $LayoutObject->Block(
905        Name => 'ActionList',
906    );
907    $LayoutObject->Block(
908        Name => 'ActionOverview',
909    );
910    $LayoutObject->Block(
911        Name => 'Edit',
912        Data => {
913            %JobData,
914            %Param,
915            %StopWordsServerErrors,
916        },
917    );
918
919    # check for profile errors
920    if ( defined $Param{ProfileInvalid} ) {
921        $Param{ProfileInvalidMsg} //= '';
922        $LayoutObject->Block(
923            Name => 'ProfileInvalidMsg' . $Param{ProfileInvalidMsg},
924        );
925    }
926
927    # check if the schedule options are selected
928    if (
929        !defined $JobData{ScheduleDays}->[0]
930        || !defined $JobData{ScheduleHours}->[0]
931        || !defined $JobData{ScheduleMinutes}->[0]
932        )
933    {
934        $LayoutObject->Block(
935            Name => 'JobScheduleWarning',
936        );
937    }
938
939    # build type string
940    if ( $ConfigObject->Get('Ticket::Type') ) {
941        my %Type = $Kernel::OM->Get('Kernel::System::Type')->TypeList(
942            UserID => $Self->{UserID},
943        );
944        $JobData{TypesStrg} = $LayoutObject->BuildSelection(
945            Data        => \%Type,
946            Name        => 'TypeIDs',
947            SelectedID  => $JobData{TypeIDs},
948            Sort        => 'AlphanumericValue',
949            Size        => 3,
950            Multiple    => 1,
951            Translation => 0,
952            Class       => 'Modernize',
953        );
954        $LayoutObject->Block(
955            Name => 'TicketType',
956            Data => \%JobData,
957        );
958        $JobData{NewTypesStrg} = $LayoutObject->BuildSelection(
959            Data        => \%Type,
960            Name        => 'NewTypeID',
961            SelectedID  => $JobData{NewTypeID},
962            Sort        => 'AlphanumericValue',
963            Size        => 3,
964            Multiple    => 0,
965            Translation => 0,
966            Class       => 'Modernize',
967        );
968        $LayoutObject->Block(
969            Name => 'NewTicketType',
970            Data => \%JobData,
971        );
972    }
973
974    # build service string
975    if ( $ConfigObject->Get('Ticket::Service') ) {
976
977        # get list type
978        my %Service = $Kernel::OM->Get('Kernel::System::Service')->ServiceList(
979            Valid        => 1,
980            KeepChildren => $ConfigObject->Get('Ticket::Service::KeepChildren') // 0,
981            UserID       => $Self->{UserID},
982        );
983        my %NewService = %Service;
984        $JobData{ServicesStrg} = $LayoutObject->BuildSelection(
985            Data        => \%Service,
986            Name        => 'ServiceIDs',
987            SelectedID  => $JobData{ServiceIDs},
988            Size        => 5,
989            Multiple    => 1,
990            TreeView    => $TreeView,
991            Translation => 0,
992            Max         => 200,
993            Class       => 'Modernize',
994        );
995        $JobData{NewServicesStrg} = $LayoutObject->BuildSelection(
996            Data        => \%NewService,
997            Name        => 'NewServiceID',
998            SelectedID  => $JobData{NewServiceID},
999            Size        => 5,
1000            Multiple    => 0,
1001            TreeView    => $TreeView,
1002            Translation => 0,
1003            Max         => 200,
1004            Class       => 'Modernize',
1005        );
1006        my %SLA = $Kernel::OM->Get('Kernel::System::SLA')->SLAList(
1007            UserID => $Self->{UserID},
1008        );
1009        $JobData{SLAsStrg} = $LayoutObject->BuildSelection(
1010            Data        => \%SLA,
1011            Name        => 'SLAIDs',
1012            SelectedID  => $JobData{SLAIDs},
1013            Sort        => 'AlphanumericValue',
1014            Size        => 5,
1015            Multiple    => 1,
1016            Translation => 0,
1017            Max         => 200,
1018            Class       => 'Modernize',
1019        );
1020        $JobData{NewSLAsStrg} = $LayoutObject->BuildSelection(
1021            Data        => \%SLA,
1022            Name        => 'NewSLAID',
1023            SelectedID  => $JobData{NewSLAID},
1024            Sort        => 'AlphanumericValue',
1025            Size        => 5,
1026            Multiple    => 0,
1027            Translation => 0,
1028            Max         => 200,
1029            Class       => 'Modernize',
1030        );
1031        $LayoutObject->Block(
1032            Name => 'TicketService',
1033            Data => {%JobData},
1034        );
1035        $LayoutObject->Block(
1036            Name => 'NewTicketService',
1037            Data => {%JobData},
1038        );
1039    }
1040
1041    # ticket responsible string
1042    if ( $ConfigObject->Get('Ticket::Responsible') ) {
1043        $JobData{ResponsibleStrg} = $LayoutObject->BuildSelection(
1044            Data        => \%ShownUsers,
1045            Name        => 'ResponsibleIDs',
1046            Size        => 5,
1047            Multiple    => 1,
1048            Translation => 0,
1049            SelectedID  => $JobData{ResponsibleIDs},
1050            Class       => 'Modernize',
1051        );
1052        $JobData{NewResponsibleStrg} = $LayoutObject->BuildSelection(
1053            Data        => \%ShownUsers,
1054            Name        => 'NewResponsibleID',
1055            Size        => 5,
1056            Multiple    => 0,
1057            Translation => 0,
1058            SelectedID  => $JobData{NewResponsibleID},
1059            Class       => 'Modernize',
1060        );
1061        $LayoutObject->Block(
1062            Name => 'TicketResponsible',
1063            Data => {%JobData},
1064        );
1065        $LayoutObject->Block(
1066            Name => 'NewTicketResponsible',
1067            Data => {%JobData},
1068        );
1069    }
1070
1071    # prepare archive
1072    if ( $ConfigObject->Get('Ticket::ArchiveSystem') ) {
1073
1074        $JobData{'SearchInArchiveStrg'} = $LayoutObject->BuildSelection(
1075            Data => {
1076                ArchivedTickets    => Translatable('Archived tickets'),
1077                NotArchivedTickets => Translatable('Unarchived tickets'),
1078                AllTickets         => Translatable('All tickets'),
1079            },
1080            Name       => 'SearchInArchive',
1081            SelectedID => $JobData{SearchInArchive} || 'AllTickets',
1082            Class      => 'Modernize',
1083        );
1084
1085        $LayoutObject->Block(
1086            Name => 'SearchInArchive',
1087            Data => {%JobData},
1088        );
1089
1090        $JobData{'NewArchiveFlagStrg'} = $LayoutObject->BuildSelection(
1091            Data => {
1092                'y' => Translatable('archive tickets'),
1093                'n' => Translatable('restore tickets from archive'),
1094            },
1095            Name         => 'NewArchiveFlag',
1096            PossibleNone => 1,
1097            SelectedID   => $JobData{NewArchiveFlag} || '',
1098            Class        => 'Modernize',
1099        );
1100
1101        $LayoutObject->Block(
1102            Name => 'NewArchiveFlag',
1103            Data => {%JobData},
1104        );
1105    }
1106
1107    # create dynamic field HTML for set with historical data options
1108    my $PrintDynamicFieldsSearchHeader = 1;
1109
1110    # get dynamic field backend object
1111    my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
1112
1113    my @AddDynamicFields;
1114    my %DynamicFieldsJS;
1115
1116    # cycle through the activated Dynamic Fields for this screen
1117    DYNAMICFIELD:
1118    for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
1119        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
1120
1121        # get search field preferences
1122        my $SearchFieldPreferences = $DynamicFieldBackendObject->SearchFieldPreferences(
1123            DynamicFieldConfig => $DynamicFieldConfig,
1124        );
1125
1126        next DYNAMICFIELD if !IsArrayRefWithData($SearchFieldPreferences);
1127
1128        # Translate dynamic field label.
1129        my $TranslatedDynamicFieldLabel = $LayoutObject->{LanguageObject}->Translate(
1130            $DynamicFieldConfig->{Label},
1131        );
1132
1133        PREFERENCE:
1134        for my $Preference ( @{$SearchFieldPreferences} ) {
1135
1136            # Translate the suffix.
1137            my $TranslatedSuffix = $LayoutObject->{LanguageObject}->Translate(
1138                $Preference->{LabelSuffix},
1139            ) || '';
1140
1141            if ($TranslatedSuffix) {
1142                $TranslatedSuffix = ' (' . $TranslatedSuffix . ')';
1143            }
1144
1145            my $Key  = 'Search_DynamicField_' . $DynamicFieldConfig->{Name} . $Preference->{Type};
1146            my $Text = $TranslatedDynamicFieldLabel . $TranslatedSuffix;
1147
1148            # Save all dynamic fields for JS.
1149            $DynamicFieldsJS{$Key} = {
1150                ID   => $DynamicFieldConfig->{ID},
1151                Type => $Preference->{Type},
1152                Text => $Text,
1153            };
1154
1155            # Decide if dynamic field go to add fields dropdown or selected fields area.
1156            if ( defined $JobData{$Key} ) {
1157
1158                # Get field HTML.
1159                my $DynamicFieldHTML = $DynamicFieldBackendObject->SearchFieldRender(
1160                    DynamicFieldConfig => $DynamicFieldConfig,
1161                    Profile            => \%JobData,
1162                    DefaultValue =>
1163                        $Self->{Config}->{Defaults}->{DynamicField}->{ $DynamicFieldConfig->{Name} },
1164                    LayoutObject           => $LayoutObject,
1165                    ConfirmationCheckboxes => 1,
1166                    Type                   => $Preference->{Type},
1167                );
1168
1169                next PREFERENCE if !IsHashRefWithData($DynamicFieldHTML);
1170
1171                $LayoutObject->Block(
1172                    Name => 'SelectedDynamicFields',
1173                    Data => {
1174                        Label => $DynamicFieldHTML->{Label},
1175                        Field => $DynamicFieldHTML->{Field},
1176                        ID    => $Key,
1177                    },
1178                );
1179            }
1180            else {
1181                push @AddDynamicFields, {
1182                    Key   => $Key,
1183                    Value => $Text,
1184                };
1185            }
1186        }
1187    }
1188
1189    my $DynamicFieldsStrg = $LayoutObject->BuildSelection(
1190        PossibleNone => 1,
1191        Data         => \@AddDynamicFields,
1192        Name         => 'AddDynamicFields',
1193        Multiple     => 0,
1194        Class        => 'Modernize',
1195    );
1196    $LayoutObject->Block(
1197        Name => 'AddDynamicFields',
1198        Data => {
1199            DynamicFieldsStrg => $DynamicFieldsStrg,
1200        },
1201    );
1202
1203    # create dynamic field HTML for set with historical data options
1204    my $PrintDynamicFieldsEditHeader = 1;
1205
1206    # get param object
1207    my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
1208
1209    my @AddNewDynamicFields;
1210
1211    # cycle trough the activated Dynamic Fields for this screen
1212    DYNAMICFIELD:
1213    for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
1214        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
1215
1216        # Check if field is Attachment type ( from OTRSDynamicFieldAttachment )
1217        #   this field is not updatable by Generic Agent
1218        my $IsAttachement = $DynamicFieldBackendObject->HasBehavior(
1219            DynamicFieldConfig => $DynamicFieldConfig,
1220            Behavior           => 'IsAttachement',
1221        );
1222        next DYNAMICFIELD if $IsAttachement;
1223
1224        my $PossibleValuesFilter;
1225
1226        my $IsACLReducible = $DynamicFieldBackendObject->HasBehavior(
1227            DynamicFieldConfig => $DynamicFieldConfig,
1228            Behavior           => 'IsACLReducible',
1229        );
1230
1231        if ($IsACLReducible) {
1232
1233            # get PossibleValues
1234            my $PossibleValues = $DynamicFieldBackendObject->PossibleValuesGet(
1235                DynamicFieldConfig => $DynamicFieldConfig,
1236            );
1237
1238            # check if field has PossibleValues property in its configuration
1239            if ( IsHashRefWithData($PossibleValues) ) {
1240
1241                # convert possible values key => value to key => key for ACLs using a Hash slice
1242                my %AclData = %{$PossibleValues};
1243                @AclData{ keys %AclData } = keys %AclData;
1244
1245                # get ticket object
1246                my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');
1247
1248                # set possible values filter from ACLs
1249                my $ACL = $TicketObject->TicketAcl(
1250                    Action        => $Self->{Action},
1251                    Type          => 'DynamicField_' . $DynamicFieldConfig->{Name},
1252                    ReturnType    => 'Ticket',
1253                    ReturnSubType => 'DynamicField_' . $DynamicFieldConfig->{Name},
1254                    Data          => \%AclData,
1255                    UserID        => $Self->{UserID},
1256                );
1257                if ($ACL) {
1258                    my %Filter = $TicketObject->TicketAclData();
1259
1260                    # convert Filer key => key back to key => value using map
1261                    %{$PossibleValuesFilter} = map { $_ => $PossibleValues->{$_} }
1262                        keys %Filter;
1263                }
1264            }
1265        }
1266
1267        my $Key  = 'DynamicField_' . $DynamicFieldConfig->{Name};
1268        my $Used = 0;
1269        if ( defined $JobData{ $Key . 'Used' } ) {
1270            $Key .= 'Used';
1271            $Used = 1;
1272        }
1273
1274        # Save all new dynamic fields for JS.
1275        $DynamicFieldsJS{$Key} = {
1276            ID   => $DynamicFieldConfig->{ID},
1277            Text => $DynamicFieldConfig->{Name},
1278        };
1279
1280        # Decide if dynamic field go to add fields dropdown or selected fields area.
1281        #
1282        # First statement part - if we have a defined value.
1283        #
1284        # Second statement part - if we have empty value which can be valid if
1285        # current dynamic field has empty value in its configuration (PossibleNone).
1286        #
1287        # Third statement part - it is for Date, DateTime and similar fields which has
1288        # a checkbox "flag" for including its value to GA config. It must return
1289        # false if checkbox is unchecked (in DB value is 0, not empty string or undef),
1290        # otherwise must be true (for other dynamic fields or checked checkbox).
1291        if (
1292            defined $JobData{$Key}
1293            && (
1294                $DynamicFieldConfig->{Config}->{PossibleNone}
1295                || $JobData{$Key} ne ''
1296            )
1297            && ( !$Used || $JobData{$Key} )
1298            )
1299        {
1300
1301            # Get field HTML.
1302            my $DynamicFieldHTML = $DynamicFieldBackendObject->EditFieldRender(
1303                DynamicFieldConfig   => $DynamicFieldConfig,
1304                PossibleValuesFilter => $PossibleValuesFilter,
1305                LayoutObject         => $LayoutObject,
1306                ParamObject          => $ParamObject,
1307                UseDefaultValue      => 0,
1308                OverridePossibleNone => 1,
1309                ConfirmationNeeded   => 1,
1310                NoIgnoreField        => 1,
1311                Template             => \%JobData,
1312                MaxLength            => 200,
1313            );
1314
1315            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldHTML);
1316
1317            $LayoutObject->Block(
1318                Name => 'SelectedNewDynamicFields',
1319                Data => {
1320                    Label => $DynamicFieldHTML->{Label},
1321                    Field => $DynamicFieldHTML->{Field},
1322                    ID    => $Key,
1323                },
1324            );
1325        }
1326        else {
1327            push @AddNewDynamicFields, {
1328                Key   => $Key,
1329                Value => $DynamicFieldConfig->{Name},
1330            };
1331        }
1332    }
1333
1334    my $NewDynamicFieldsStrg = $LayoutObject->BuildSelection(
1335        PossibleNone => 1,
1336        Data         => \@AddNewDynamicFields,
1337        Name         => 'AddNewDynamicFields',
1338        Multiple     => 0,
1339        Class        => 'Modernize',
1340    );
1341    $LayoutObject->Block(
1342        Name => 'AddNewDynamicFields',
1343        Data => {
1344            NewDynamicFieldsStrg => $NewDynamicFieldsStrg,
1345        },
1346    );
1347    $LayoutObject->AddJSData(
1348        Key   => 'DynamicFieldsJS',
1349        Value => \%DynamicFieldsJS,
1350    );
1351
1352    # get event object
1353    my $EventObject = $Kernel::OM->Get('Kernel::System::Event');
1354
1355    # get registered event triggers from the config
1356    my %RegisteredEvents = $EventObject->EventList(
1357        ObjectTypes => [ 'Ticket', 'Article' ],
1358    );
1359
1360    # create the event triggers table
1361    for my $Event ( @{ $JobData{EventValues} || [] } ) {
1362
1363        # set the event type ( event object like Article or Ticket)
1364        my $EventType;
1365        EVENTTYPE:
1366        for my $Type ( sort keys %RegisteredEvents ) {
1367            if ( grep { $_ eq $Event } @{ $RegisteredEvents{$Type} } ) {
1368                $EventType = $Type;
1369                last EVENTTYPE;
1370            }
1371        }
1372
1373        # paint each event row in event triggers table
1374        $LayoutObject->Block(
1375            Name => 'EventRow',
1376            Data => {
1377                Event     => $Event,
1378                EventType => $EventType || '-',
1379            },
1380        );
1381    }
1382
1383    my @EventTypeList;
1384    my $SelectedEventType = $ParamObject->GetParam( Param => 'EventType' ) || 'Ticket';
1385
1386    # create event trigger selectors (one for each type)
1387    TYPE:
1388    for my $Type ( sort keys %RegisteredEvents ) {
1389
1390        # refresh event list for each event type
1391
1392        # paint each selector
1393        my $EventStrg = $LayoutObject->BuildSelection(
1394            PossibleNone => 0,
1395            Data         => $RegisteredEvents{$Type} || [],
1396            Name         => $Type . 'Event',
1397            Sort         => 'AlphanumericValue',
1398            PossibleNone => 0,
1399            Class        => 'Modernize EventList GenericInterfaceSpacing',
1400            Title        => $LayoutObject->{LanguageObject}->Translate('Event'),
1401        );
1402
1403        $LayoutObject->Block(
1404            Name => 'EventAdd',
1405            Data => {
1406                EventStrg => $EventStrg,
1407            },
1408        );
1409
1410        push @EventTypeList, $Type;
1411    }
1412
1413    # create event type selector
1414    my $EventTypeStrg = $LayoutObject->BuildSelection(
1415        Data          => \@EventTypeList,
1416        Name          => 'EventType',
1417        Sort          => 'AlphanumericValue',
1418        SelectedValue => $SelectedEventType,
1419        PossibleNone  => 0,
1420        Class         => 'Modernize',
1421        Title         => $LayoutObject->{LanguageObject}->Translate('Type'),
1422    );
1423    $LayoutObject->Block(
1424        Name => 'EventTypeStrg',
1425        Data => {
1426            EventTypeStrg => $EventTypeStrg,
1427        },
1428    );
1429
1430    return \%JobData;
1431}
1432
1433sub _MaskRun {
1434    my ( $Self, %Param ) = @_;
1435
1436    # get layout object
1437    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
1438
1439    my %JobData;
1440
1441    if ( $Self->{Profile} ) {
1442        %JobData = $Kernel::OM->Get('Kernel::System::GenericAgent')->JobGet( Name => $Self->{Profile} );
1443        if ( exists $JobData{SearchInArchive} && $JobData{SearchInArchive} eq 'ArchivedTickets' ) {
1444            $JobData{ArchiveFlags} = ['y'];
1445        }
1446        if ( exists $JobData{SearchInArchive} && $JobData{SearchInArchive} eq 'AllTickets' ) {
1447            $JobData{ArchiveFlags} = [ 'y', 'n' ];
1448        }
1449    }
1450    else {
1451        $LayoutObject->FatalError(
1452            Message => Translatable('Need Profile!'),
1453        );
1454    }
1455    $JobData{Profile} = $Self->{Profile};
1456    $Param{Subaction} = $Self->{Subaction};
1457    $Param{Profile}   = $Self->{Profile};
1458
1459    # dynamic fields search parameters for ticket search
1460    my %DynamicFieldSearchParameters;
1461
1462    # get dynamic field backend object
1463    my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
1464
1465    # cycle trough the activated Dynamic Fields for this screen
1466    DYNAMICFIELD:
1467    for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
1468        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
1469
1470        # get search field preferences
1471        my $SearchFieldPreferences = $DynamicFieldBackendObject->SearchFieldPreferences(
1472            DynamicFieldConfig => $DynamicFieldConfig,
1473        );
1474
1475        next DYNAMICFIELD if !IsArrayRefWithData($SearchFieldPreferences);
1476
1477        PREFERENCE:
1478        for my $Preference ( @{$SearchFieldPreferences} ) {
1479
1480            if (
1481                !$JobData{
1482                    'Search_DynamicField_'
1483                        . $DynamicFieldConfig->{Name}
1484                        . $Preference->{Type}
1485                }
1486                )
1487            {
1488                next PREFERENCE;
1489            }
1490
1491            # extract the dynamic field value from the profile
1492            my $SearchParameter = $DynamicFieldBackendObject->SearchFieldParameterBuild(
1493                DynamicFieldConfig => $DynamicFieldConfig,
1494                Profile            => \%JobData,
1495                LayoutObject       => $LayoutObject,
1496                Type               => $Preference->{Type},
1497            );
1498
1499            # set search parameter
1500            if ( defined $SearchParameter ) {
1501                $DynamicFieldSearchParameters{ 'DynamicField_' . $DynamicFieldConfig->{Name} }
1502                    = $SearchParameter->{Parameter};
1503            }
1504        }
1505    }
1506
1507    # remove residual dynamic field data from job definition
1508    # they are passed through dedicated variable anyway
1509    PARAM_NAME:
1510    for my $ParamName ( sort keys %JobData ) {
1511        next PARAM_NAME if !( $ParamName =~ /^DynamicField_/ );
1512        delete $JobData{$ParamName};
1513    }
1514
1515    # get needed objects
1516    my $TicketObject  = $Kernel::OM->Get('Kernel::System::Ticket');
1517    my $ArticleObject = $Kernel::OM->Get('Kernel::System::Ticket::Article');
1518    my $ConfigObject  = $Kernel::OM->Get('Kernel::Config');
1519
1520    # perform ticket search
1521    my $GenericAgentTicketSearch = $ConfigObject->Get("Ticket::GenericAgentTicketSearch") || {};
1522    my $Counter                  = $TicketObject->TicketSearch(
1523        Result          => 'COUNT',
1524        SortBy          => 'Age',
1525        OrderBy         => 'Down',
1526        UserID          => 1,
1527        Limit           => 60_000,
1528        ConditionInline => $GenericAgentTicketSearch->{ExtendedSearchCondition},
1529        %JobData,
1530        %DynamicFieldSearchParameters,
1531    ) || 0;
1532
1533    my @TicketIDs = $TicketObject->TicketSearch(
1534        Result          => 'ARRAY',
1535        SortBy          => 'Age',
1536        OrderBy         => 'Down',
1537        UserID          => 1,
1538        Limit           => 30,
1539        ConditionInline => $GenericAgentTicketSearch->{ExtendedSearchCondition},
1540        %JobData,
1541        %DynamicFieldSearchParameters,
1542    );
1543
1544    $LayoutObject->Block(
1545        Name => 'ActionList',
1546    );
1547    $LayoutObject->Block(
1548        Name => 'ActionOverview',
1549    );
1550    $LayoutObject->Block(
1551        Name => 'Result',
1552        Data => {
1553            %Param,
1554            Name        => $Self->{Profile},
1555            AffectedIDs => $Counter,
1556        },
1557    );
1558
1559    my $RunLimit = $ConfigObject->Get('Ticket::GenericAgentRunLimit');
1560    if ( $Counter > $RunLimit ) {
1561        $LayoutObject->Block(
1562            Name => 'RunLimit',
1563            Data => {
1564                Counter  => $Counter,
1565                RunLimit => $RunLimit,
1566            },
1567        );
1568    }
1569
1570    if (@TicketIDs) {
1571        $LayoutObject->Block(
1572            Name => 'ResultBlock',
1573        );
1574        for my $TicketID (@TicketIDs) {
1575
1576            # Get ticket data.
1577            my %Ticket = $TicketObject->TicketGet(
1578                TicketID      => $TicketID,
1579                DynamicFields => 0,
1580            );
1581
1582            # Get article data.
1583            my @Articles = $ArticleObject->ArticleList(
1584                TicketID  => $TicketID,
1585                OnlyFirst => 1,
1586            );
1587            my %Article;
1588            for my $Article (@Articles) {
1589                %Article = $ArticleObject->BackendForArticle( %{$Article} )->ArticleGet( %{$Article} );
1590            }
1591
1592            my %Data = ( %Ticket, %Article );
1593
1594            # Set missing information for tickets without articles.
1595            if ( !%Article ) {
1596                $Data{Subject} = $Data{Title};
1597            }
1598
1599            $Data{Age} = $LayoutObject->CustomerAge(
1600                Age   => $Data{Age},
1601                Space => ' ',
1602            );
1603            $Data{css} = "PriorityID-$Data{PriorityID}";
1604
1605            # user info
1606            my %UserInfo = $Kernel::OM->Get('Kernel::System::User')->GetUserData(
1607                User => $Data{Owner},
1608            );
1609            $Data{UserLastname}  = $UserInfo{UserLastname};
1610            $Data{UserFirstname} = $UserInfo{UserFirstname};
1611            $Data{UserFullname}  = $UserInfo{UserFullname};
1612            $LayoutObject->Block(
1613                Name => 'Ticket',
1614                Data => \%Data,
1615            );
1616        }
1617
1618        if ( $JobData{NewDelete} ) {
1619            $LayoutObject->Block(
1620                Name => 'DeleteWarning',
1621            );
1622        }
1623    }
1624
1625    # HTML search mask output
1626    my $Output = $LayoutObject->Header(
1627        Title => Translatable('Affected Tickets'),
1628    );
1629    $Output .= $LayoutObject->NavigationBar();
1630    $Output .= $LayoutObject->Output(
1631        TemplateFile => 'AdminGenericAgent',
1632        Data         => \%Param,
1633    );
1634
1635    # build footer
1636    $Output .= $LayoutObject->Footer();
1637    return $Output;
1638}
1639
1640sub _StopWordsServerErrorsGet {
1641    my ( $Self, %Param ) = @_;
1642
1643    if ( !%Param ) {
1644        $Kernel::OM->Get('Kernel::Output::HTML::Layout')->FatalError(
1645            Message => Translatable('Got no values to check.'),
1646        );
1647    }
1648
1649    my $ArticleObject = $Kernel::OM->Get('Kernel::System::Ticket::Article');
1650
1651    my %StopWordsServerErrors;
1652    if ( !$ArticleObject->SearchStringStopWordsUsageWarningActive() ) {
1653        return %StopWordsServerErrors;
1654    }
1655
1656    my %SearchStrings;
1657
1658    FIELD:
1659    for my $Field ( sort keys %Param ) {
1660        next FIELD if !defined $Param{$Field};
1661        next FIELD if !length $Param{$Field};
1662
1663        $SearchStrings{$Field} = $Param{$Field};
1664    }
1665
1666    if (%SearchStrings) {
1667
1668        my $StopWords = $ArticleObject->SearchStringStopWordsFind(
1669            SearchStrings => \%SearchStrings,
1670        );
1671
1672        FIELD:
1673        for my $Field ( sort keys %{$StopWords} ) {
1674            next FIELD if !defined $StopWords->{$Field};
1675            next FIELD if ref $StopWords->{$Field} ne 'ARRAY';
1676            next FIELD if !@{ $StopWords->{$Field} };
1677
1678            $StopWordsServerErrors{ $Field . 'Invalid' } = 'ServerError';
1679            $StopWordsServerErrors{ $Field . 'InvalidTooltip' }
1680                = $Kernel::OM->Get('Kernel::Output::HTML::Layout')->{LanguageObject}
1681                ->Translate('Please remove the following words because they cannot be used for the ticket selection:')
1682                . ' '
1683                . join( ',', sort @{ $StopWords->{$Field} } );
1684        }
1685    }
1686
1687    return %StopWordsServerErrors;
1688}
1689
16901;
1691