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::System::GenericAgent;
10
11use strict;
12use warnings;
13
14use Time::HiRes qw(usleep);
15
16use Kernel::System::VariableCheck qw(:all);
17
18our @ObjectDependencies = (
19    'Kernel::Config',
20    'Kernel::System::Cache',
21    'Kernel::System::DateTime',
22    'Kernel::System::DB',
23    'Kernel::System::DynamicField',
24    'Kernel::System::DynamicField::Backend',
25    'Kernel::System::Log',
26    'Kernel::System::Main',
27    'Kernel::System::Queue',
28    'Kernel::System::State',
29    'Kernel::System::Ticket',
30    'Kernel::System::Ticket::Article',
31    'Kernel::System::TemplateGenerator',
32    'Kernel::System::CustomerUser',
33);
34
35=head1 NAME
36
37Kernel::System::GenericAgent - to manage the generic agent jobs
38
39=head1 DESCRIPTION
40
41All functions to manage the generic agent and the generic agent jobs.
42
43=head1 PUBLIC INTERFACE
44
45=head2 new()
46
47Don't use the constructor directly, use the ObjectManager instead:
48
49    my $GenericAgentObject = $Kernel::OM->Get('Kernel::System::GenericAgent');
50
51=cut
52
53sub new {
54    my ( $Type, %Param ) = @_;
55
56    # allocate new hash for object
57    my $Self = {};
58    bless( $Self, $Type );
59
60    # get dynamic field objects
61    my $DynamicFieldObject        = $Kernel::OM->Get('Kernel::System::DynamicField');
62    my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
63
64    # get the dynamic fields for ticket object
65    $Self->{DynamicField} = $DynamicFieldObject->DynamicFieldListGet(
66        Valid      => 1,
67        ObjectType => ['Ticket'],
68    );
69
70    # debug
71    $Self->{Debug} = $Param{Debug} || 0;
72
73    # notice on STDOUT
74    $Self->{NoticeSTDOUT} = $Param{NoticeSTDOUT} || 0;
75
76    my %Map = (
77        TicketNumber            => 'SCALAR',
78        Title                   => 'SCALAR',
79        MIMEBase_From           => 'SCALAR',
80        MIMEBase_To             => 'SCALAR',
81        MIMEBase_Cc             => 'SCALAR',
82        MIMEBase_Subject        => 'SCALAR',
83        MIMEBase_Body           => 'SCALAR',
84        TimeUnit                => 'SCALAR',
85        CustomerID              => 'SCALAR',
86        CustomerUserLogin       => 'SCALAR',
87        Agent                   => 'SCALAR',
88        StateIDs                => 'ARRAY',
89        StateTypeIDs            => 'ARRAY',
90        QueueIDs                => 'ARRAY',
91        PriorityIDs             => 'ARRAY',
92        OwnerIDs                => 'ARRAY',
93        LockIDs                 => 'ARRAY',
94        TypeIDs                 => 'ARRAY',
95        ResponsibleIDs          => 'ARRAY',
96        ServiceIDs              => 'ARRAY',
97        SLAIDs                  => 'ARRAY',
98        NewTitle                => 'SCALAR',
99        NewCustomerID           => 'SCALAR',
100        NewCustomerUserLogin    => 'SCALAR',
101        NewStateID              => 'SCALAR',
102        NewQueueID              => 'SCALAR',
103        NewPriorityID           => 'SCALAR',
104        NewOwnerID              => 'SCALAR',
105        NewLockID               => 'SCALAR',
106        NewTypeID               => 'SCALAR',
107        NewResponsibleID        => 'SCALAR',
108        NewServiceID            => 'SCALAR',
109        NewSLAID                => 'SCALAR',
110        ScheduleLastRun         => 'SCALAR',
111        ScheduleLastRunUnixTime => 'SCALAR',
112        Valid                   => 'SCALAR',
113        ScheduleDays            => 'ARRAY',
114        ScheduleMinutes         => 'ARRAY',
115        ScheduleHours           => 'ARRAY',
116        EventValues             => 'ARRAY',
117    );
118
119    # add time attributes
120    for my $Type (
121        qw(Time ChangeTime CloseTime TimePending EscalationTime EscalationResponseTime EscalationUpdateTime EscalationSolutionTime)
122        )
123    {
124        my $Key = $Type . 'SearchType';
125        $Map{$Key} = 'SCALAR';
126    }
127    for my $Type (
128        qw(TicketCreate TicketChange TicketClose TicketLastChange TicketLastClose TicketPending TicketEscalation TicketEscalationResponse TicketEscalationUpdate TicketEscalationSolution)
129        )
130    {
131        for my $Attribute (
132            qw(PointFormat Point PointStart Start StartDay StartMonth StartYear Stop StopDay StopMonth StopYear)
133            )
134        {
135            my $Key = $Type . 'Time' . $Attribute;
136            $Map{$Key} = 'SCALAR';
137        }
138    }
139
140    # Add Dynamic Fields attributes
141    DYNAMICFIELD:
142    for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
143        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
144
145        # get the field type of the dynamic fields for edit and search
146        my $FieldValueType = $DynamicFieldBackendObject->TemplateValueTypeGet(
147            DynamicFieldConfig => $DynamicFieldConfig,
148            FieldType          => 'All',
149        );
150
151        # Add field type to Map
152        if ( IsHashRefWithData($FieldValueType) ) {
153            for my $FieldName ( sort keys %{$FieldValueType} ) {
154                $Map{$FieldName} = $FieldValueType->{$FieldName};
155            }
156        }
157    }
158
159    $Self->{Map} = \%Map;
160
161    return $Self;
162}
163
164=head2 JobRun()
165
166run a generic agent job
167
168    $GenericAgentObject->JobRun(
169        Job          => 'JobName',
170        OnlyTicketID => 123,     # (optional) for event based Job execution
171        SleepTime    => 100_000  # (optional) sleeptime per ticket in microseconds
172        UserID       => 1,
173    );
174
175=cut
176
177sub JobRun {
178    my ( $Self, %Param ) = @_;
179
180    # check needed stuff
181    for (qw(Job UserID)) {
182        if ( !$Param{$_} ) {
183            $Kernel::OM->Get('Kernel::System::Log')->Log(
184                Priority => 'error',
185                Message  => "Need $_!"
186            );
187            return;
188        }
189    }
190    if ( $Self->{NoticeSTDOUT} ) {
191        print "Job: '$Param{Job}'\n";
192    }
193
194    # get job from param
195    my %Job;
196    my %DynamicFieldSearchTemplate;
197    if ( $Param{Config} ) {
198        %Job = %{ $Param{Config} };
199
200        # log event
201        $Kernel::OM->Get('Kernel::System::Log')->Log(
202            Priority => 'notice',
203            Message  => "Run GenericAgent Job '$Param{Job}' from config file.",
204        );
205    }
206
207    # get db job
208    else {
209
210        # log event
211        $Kernel::OM->Get('Kernel::System::Log')->Log(
212            Priority => 'notice',
213            Message  => "Run GenericAgent Job '$Param{Job}' from db.",
214        );
215
216        # get job data
217        my %DBJobRaw = $Self->JobGet( Name => $Param{Job} );
218
219        # updated last run time
220        $Self->_JobUpdateRunTime(
221            Name   => $Param{Job},
222            UserID => $Param{UserID}
223        );
224
225        # rework
226        for my $Key ( sort keys %DBJobRaw ) {
227            if ( $Key =~ /^New/ ) {
228                my $NewKey = $Key;
229                $NewKey =~ s/^New//;
230                $Job{New}->{$NewKey} = $DBJobRaw{$Key};
231            }
232            else {
233
234                # skip dynamic fields
235                if ( $Key !~ m{ DynamicField_ }xms ) {
236                    $Job{$Key} = $DBJobRaw{$Key};
237                }
238            }
239
240            # convert dynamic fields
241            if ( $Key =~ m{ \A DynamicField_ }xms ) {
242                $Job{New}->{$Key} = $DBJobRaw{$Key};
243            }
244            elsif ( $Key =~ m{ \A Search_DynamicField_ }xms ) {
245                $DynamicFieldSearchTemplate{$Key} = $DBJobRaw{$Key};
246            }
247        }
248
249        # Pass module parameters directly to the module in %Param,
250        #   but don't overwrite existing keys
251        for my $Counter ( 1 .. 6 ) {
252            if ( $Job{New}->{"ParamKey$Counter"} ) {
253                $Job{New}->{ $Job{New}->{"ParamKey$Counter"} } //= $Job{New}->{"ParamValue$Counter"};
254            }
255        }
256
257        if ( exists $Job{SearchInArchive} && $Job{SearchInArchive} eq 'ArchivedTickets' ) {
258            $Job{ArchiveFlags} = ['y'];
259        }
260        if ( exists $Job{SearchInArchive} && $Job{SearchInArchive} eq 'AllTickets' ) {
261            $Job{ArchiveFlags} = [ 'y', 'n' ];
262        }
263    }
264
265    # get dynamic field backend objects
266    my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
267
268    # set dynamic fields search parameters
269    my %DynamicFieldSearchParameters;
270    DYNAMICFIELD:
271    for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
272
273        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
274
275        # get search field preferences
276        my $SearchFieldPreferences = $DynamicFieldBackendObject->SearchFieldPreferences(
277            DynamicFieldConfig => $DynamicFieldConfig,
278        );
279
280        next DYNAMICFIELD if !IsArrayRefWithData($SearchFieldPreferences);
281
282        PREFERENCE:
283        for my $Preference ( @{$SearchFieldPreferences} ) {
284
285            my $DynamicFieldTemp = $DynamicFieldSearchTemplate{
286                'Search_DynamicField_'
287                    . $DynamicFieldConfig->{Name}
288                    . $Preference->{Type}
289            };
290
291            next PREFERENCE if !defined $DynamicFieldTemp;
292
293            # extract the dynamic field value from the profile
294            my $SearchParameter = $DynamicFieldBackendObject->SearchFieldParameterBuild(
295                DynamicFieldConfig => $DynamicFieldConfig,
296                Profile            => \%DynamicFieldSearchTemplate,
297                Type               => $Preference->{Type},
298            );
299
300            # set search parameter
301            if ( defined $SearchParameter ) {
302                $DynamicFieldSearchParameters{ 'DynamicField_' . $DynamicFieldConfig->{Name} }
303                    = $SearchParameter->{Parameter};
304            }
305        }
306    }
307
308    if ( $Param{OnlyTicketID} ) {
309        $Job{TicketID} = $Param{OnlyTicketID};
310    }
311
312    # get needed objects
313    my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');
314    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
315
316    # escalation tickets
317    my %Tickets;
318
319    # get ticket limit on job run
320    my $RunLimit = $ConfigObject->Get('Ticket::GenericAgentRunLimit');
321    if ( $Job{Escalation} ) {
322
323        # Find all tickets which will escalate within the next five days.
324        #   The notification module will determine if a notification must be sent out or not.
325        my @Tickets = $TicketObject->TicketSearch(
326            %Job,
327            Result                           => 'ARRAY',
328            Limit                            => $Job{Limit} || $Param{Limit} || 100,
329            TicketEscalationTimeOlderMinutes => $Job{TicketEscalationTimeOlderMinutes}
330                || -( 5 * 24 * 60 ),
331            Permission => 'rw',
332            UserID     => $Param{UserID} || 1,
333        );
334
335        for (@Tickets) {
336            if ( !$Job{Queue} ) {
337                $Tickets{$_} = $TicketObject->TicketNumberLookup( TicketID => $_ );
338            }
339            else {
340                my %Ticket = $TicketObject->TicketGet(
341                    TicketID      => $_,
342                    DynamicFields => 0,
343                );
344                if ( $Ticket{Queue} eq $Job{Queue} ) {
345                    $Tickets{$_} = $Ticket{TicketNumber};
346                }
347            }
348        }
349    }
350
351    # pending tickets
352    elsif ( $Job{PendingReminder} || $Job{PendingAuto} ) {
353        my $Type = '';
354        if ( $Job{PendingReminder} ) {
355            $Type = 'PendingReminder';
356        }
357        else {
358            $Type = 'PendingAuto';
359        }
360        if ( !$Job{Queue} ) {
361            %Tickets = (
362                $TicketObject->TicketSearch(
363                    %Job,
364                    %DynamicFieldSearchParameters,
365                    ConditionInline => 1,
366                    StateType       => $Type,
367                    Limit           => $Param{Limit} || $RunLimit,
368                    UserID          => $Param{UserID},
369                ),
370                %Tickets
371            );
372        }
373        elsif ( ref $Job{Queue} eq 'ARRAY' ) {
374            for ( @{ $Job{Queue} } ) {
375                if ( $Self->{NoticeSTDOUT} ) {
376                    print " For Queue: $_\n";
377                }
378                %Tickets = (
379                    $TicketObject->TicketSearch(
380                        %Job,
381                        %DynamicFieldSearchParameters,
382                        ConditionInline => 1,
383                        Queues          => [$_],
384                        StateType       => $Type,
385                        Limit           => $Param{Limit} || $RunLimit,
386                        UserID          => $Param{UserID},
387                    ),
388                    %Tickets
389                );
390            }
391        }
392        else {
393            %Tickets = (
394                $TicketObject->TicketSearch(
395                    %Job,
396                    %DynamicFieldSearchParameters,
397                    ConditionInline => 1,
398                    StateType       => $Type,
399                    Queues          => [ $Job{Queue} ],
400                    Limit           => $Param{Limit} || $RunLimit,
401                    UserID          => $Param{UserID},
402                ),
403                %Tickets
404            );
405        }
406        for ( sort keys %Tickets ) {
407            my %Ticket = $TicketObject->TicketGet(
408                TicketID      => $_,
409                DynamicFields => 0,
410            );
411            if ( $Ticket{UntilTime} > 1 ) {
412                delete $Tickets{$_};
413            }
414        }
415    }
416
417    # get regular tickets
418    else {
419        if ( !$Job{Queue} ) {
420
421            # check min. one search arg
422            my $Count = 0;
423            for ( sort keys %Job ) {
424                if ( $_ !~ /^(New|Name|Valid|Schedule|Event)/ && $Job{$_} ) {
425                    $Count++;
426                }
427            }
428
429            # also search in Dynamic fields search attributes
430            for my $DynamicFieldName ( sort keys %DynamicFieldSearchParameters ) {
431                $Count++;
432            }
433
434            # log no search attribute
435            if ( !$Count ) {
436                $Kernel::OM->Get('Kernel::System::Log')->Log(
437                    Priority => 'error',
438                    Message  => "Attention: Can't run GenericAgent Job '$Param{Job}' because no "
439                        . "search attributes are used!.",
440                );
441                return;
442            }
443
444            # search tickets
445            if ( $Self->{NoticeSTDOUT} ) {
446                print " For all Queues: \n";
447            }
448            my $GenericAgentTicketSearch = $ConfigObject->Get("Ticket::GenericAgentTicketSearch") || {};
449            %Tickets = $TicketObject->TicketSearch(
450                %Job,
451                %DynamicFieldSearchParameters,
452                ConditionInline => $GenericAgentTicketSearch->{ExtendedSearchCondition},
453                Limit           => $Param{Limit} || $RunLimit,
454                UserID          => $Param{UserID},
455            );
456        }
457        elsif ( ref $Job{Queue} eq 'ARRAY' ) {
458            for ( @{ $Job{Queue} } ) {
459                if ( $Self->{NoticeSTDOUT} ) {
460                    print " For Queue: $_\n";
461                }
462                %Tickets = (
463                    $TicketObject->TicketSearch(
464                        %Job,
465                        %DynamicFieldSearchParameters,
466                        ConditionInline => 1,
467                        Queues          => [$_],
468                        Limit           => $Param{Limit} || $RunLimit,
469                        UserID          => $Param{UserID},
470                    ),
471                    %Tickets
472                );
473            }
474        }
475        else {
476            %Tickets = $TicketObject->TicketSearch(
477                %Job,
478                %DynamicFieldSearchParameters,
479                ConditionInline => 1,
480                Queues          => [ $Job{Queue} ],
481                Limit           => $Param{Limit} || $RunLimit,
482                UserID          => $Param{UserID},
483            );
484        }
485    }
486
487    # process each ticket
488    TICKETID:
489    for my $TicketID ( sort keys %Tickets ) {
490
491        $Self->_JobRunTicket(
492            Config       => \%Job,
493            Job          => $Param{Job},
494            TicketID     => $TicketID,
495            TicketNumber => $Tickets{$TicketID},
496            UserID       => $Param{UserID},
497        );
498
499        next TICKETID if !$Param{SleepTime};
500
501        Time::HiRes::usleep( $Param{SleepTime} );
502    }
503
504    return 1;
505}
506
507=head2 JobList()
508
509returns a hash of jobs
510
511    my %List = $GenericAgentObject->JobList();
512
513=cut
514
515sub JobList {
516    my ( $Self, %Param ) = @_;
517
518    # get cache object
519    my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
520
521    # check cache
522    my $CacheKey = "JobList";
523    my $Cache    = $CacheObject->Get(
524        Type => 'GenericAgent',
525        Key  => $CacheKey,
526    );
527    return %{$Cache} if ref $Cache;
528
529    # get database object
530    my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
531
532    return if !$DBObject->Prepare(
533        SQL => 'SELECT DISTINCT(job_name) FROM generic_agent_jobs',
534    );
535
536    my %Data;
537    while ( my @Row = $DBObject->FetchrowArray() ) {
538        $Data{ $Row[0] } = $Row[0];
539    }
540
541    $CacheObject->Set(
542        Type  => 'GenericAgent',
543        Key   => $CacheKey,
544        Value => \%Data,
545        TTL   => 24 * 60 * 60,
546    );
547
548    return %Data;
549}
550
551=head2 JobGet()
552
553returns a hash of the job data
554
555    my %Job = $GenericAgentObject->JobGet(Name => 'JobName');
556
557=cut
558
559sub JobGet {
560    my ( $Self, %Param ) = @_;
561
562    # check needed stuff
563    for (qw(Name)) {
564        if ( !$Param{$_} ) {
565            $Kernel::OM->Get('Kernel::System::Log')->Log(
566                Priority => 'error',
567                Message  => "Need $_!"
568            );
569            return;
570        }
571    }
572
573    # get cache object
574    my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
575
576    # check cache
577    my $CacheKey = 'JobGet::' . $Param{Name};
578    my $Cache    = $CacheObject->Get(
579        Type => 'GenericAgent',
580        Key  => $CacheKey,
581    );
582    return %{$Cache} if ref $Cache;
583
584    # get database object
585    my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
586
587    return if !$DBObject->Prepare(
588        SQL => '
589            SELECT job_key, job_value
590            FROM generic_agent_jobs
591            WHERE job_name = ?',
592        Bind => [ \$Param{Name} ],
593    );
594
595    my %Data;
596    while ( my @Row = $DBObject->FetchrowArray() ) {
597        if ( $Self->{Map}->{ $Row[0] } && $Self->{Map}->{ $Row[0] } eq 'ARRAY' ) {
598            push @{ $Data{ $Row[0] } }, $Row[1];
599        }
600        else {
601            $Data{ $Row[0] } = $Row[1];
602        }
603    }
604
605    # get time settings
606    my %Map = (
607        TicketCreate             => 'Time',
608        TicketChange             => 'ChangeTime',
609        TicketClose              => 'CloseTime',
610        TicketLastChange         => 'LastChangeTime',
611        TicketLastClose          => 'LastCloseTime',
612        TicketPending            => 'TimePending',
613        TicketEscalation         => 'EscalationTime',
614        TicketEscalationResponse => 'EscalationResponseTime',
615        TicketEscalationUpdate   => 'EscalationUpdateTime',
616        TicketEscalationSolution => 'EscalationSolutionTime',
617    );
618
619    for my $Type (
620        qw(TicketCreate TicketChange TicketClose TicketLastChange TicketLastClose TicketPending TicketEscalation TicketEscalationResponse TicketEscalationUpdate TicketEscalationSolution)
621        )
622    {
623        my $SearchType = $Map{$Type} . 'SearchType';
624
625        if ( !$Data{$SearchType} || $Data{$SearchType} eq 'None' ) {
626
627            # do nothing on time stuff
628            for (
629                qw(TimeStartMonth TimeStopMonth TimeStopDay
630                TimeStartDay TimeStopYear TimePoint
631                TimeStartYear TimePointFormat TimePointStart)
632                )
633            {
634                delete $Data{ $Type . $_ };
635            }
636        }
637        elsif ( $Data{$SearchType} && $Data{$SearchType} eq 'TimeSlot' ) {
638            for (qw(TimePoint TimePointFormat TimePointStart)) {
639                delete $Data{ $Type . $_ };
640            }
641            for (qw(Month Day)) {
642                $Data{ $Type . "TimeStart$_" } = sprintf( '%02d', $Data{ $Type . "TimeStart$_" } );
643                $Data{ $Type . "TimeStop$_" }  = sprintf( '%02d', $Data{ $Type . "TimeStop$_" } );
644            }
645            if (
646                $Data{ $Type . 'TimeStartDay' }
647                && $Data{ $Type . 'TimeStartMonth' }
648                && $Data{ $Type . 'TimeStartYear' }
649                )
650            {
651                $Data{ $Type . 'TimeNewerDate' } = $Data{ $Type . 'TimeStartYear' } . '-'
652                    . $Data{ $Type . 'TimeStartMonth' } . '-'
653                    . $Data{ $Type . 'TimeStartDay' }
654                    . ' 00:00:01';
655            }
656            if (
657                $Data{ $Type . 'TimeStopDay' }
658                && $Data{ $Type . 'TimeStopMonth' }
659                && $Data{ $Type . 'TimeStopYear' }
660                )
661            {
662                $Data{ $Type . 'TimeOlderDate' } = $Data{ $Type . 'TimeStopYear' } . '-'
663                    . $Data{ $Type . 'TimeStopMonth' } . '-'
664                    . $Data{ $Type . 'TimeStopDay' }
665                    . ' 23:59:59';
666            }
667        }
668        elsif ( $Data{$SearchType} && $Data{$SearchType} eq 'TimePoint' ) {
669            for (
670                qw(TimeStartMonth TimeStopMonth TimeStopDay
671                TimeStartDay TimeStopYear TimeStartYear)
672                )
673            {
674                delete $Data{ $Type . $_ };
675            }
676            if (
677                $Data{ $Type . 'TimePoint' }
678                && $Data{ $Type . 'TimePointStart' }
679                && $Data{ $Type . 'TimePointFormat' }
680                )
681            {
682                my $Time = 0;
683                if ( $Data{ $Type . 'TimePointFormat' } eq 'minute' ) {
684                    $Time = $Data{ $Type . 'TimePoint' };
685                }
686                elsif ( $Data{ $Type . 'TimePointFormat' } eq 'hour' ) {
687                    $Time = $Data{ $Type . 'TimePoint' } * 60;
688                }
689                elsif ( $Data{ $Type . 'TimePointFormat' } eq 'day' ) {
690                    $Time = $Data{ $Type . 'TimePoint' } * 60 * 24;
691                }
692                elsif ( $Data{ $Type . 'TimePointFormat' } eq 'week' ) {
693                    $Time = $Data{ $Type . 'TimePoint' } * 60 * 24 * 7;
694                }
695                elsif ( $Data{ $Type . 'TimePointFormat' } eq 'month' ) {
696                    $Time = $Data{ $Type . 'TimePoint' } * 60 * 24 * 30;
697                }
698                elsif ( $Data{ $Type . 'TimePointFormat' } eq 'year' ) {
699                    $Time = $Data{ $Type . 'TimePoint' } * 60 * 24 * 365;
700                }
701                if ( $Data{ $Type . 'TimePointStart' } eq 'Before' ) {
702
703                    # more than ... ago
704                    $Data{ $Type . 'TimeOlderMinutes' } = $Time;
705                }
706                elsif ( $Data{ $Type . 'TimePointStart' } eq 'Next' ) {
707
708                    # within the next ...
709                    $Data{ $Type . 'TimeNewerMinutes' } = 0;
710                    $Data{ $Type . 'TimeOlderMinutes' } = -$Time;
711                }
712                else {
713
714                    # within the last ...
715                    $Data{ $Type . 'TimeOlderMinutes' } = 0;
716                    $Data{ $Type . 'TimeNewerMinutes' } = $Time;
717                }
718            }
719        }
720    }
721
722    # check valid
723    if ( %Data && !defined $Data{Valid} ) {
724        $Data{Valid} = 1;
725    }
726    if (%Data) {
727        $Data{Name} = $Param{Name};
728    }
729
730    $CacheObject->Set(
731        Type  => 'GenericAgent',
732        Key   => $CacheKey,
733        Value => \%Data,
734        TTL   => 24 * 60 * 60,
735    );
736
737    return %Data;
738}
739
740=head2 JobAdd()
741
742adds a new job to the database
743
744    $GenericAgentObject->JobAdd(
745        Name => 'JobName',
746        Data => {
747            Queue => 'SomeQueue',
748            ...
749            Valid => 1,
750        },
751        UserID => 123,
752    );
753
754=cut
755
756sub JobAdd {
757    my ( $Self, %Param ) = @_;
758
759    # check needed stuff
760    for (qw(Name Data UserID)) {
761        if ( !$Param{$_} ) {
762            $Kernel::OM->Get('Kernel::System::Log')->Log(
763                Priority => 'error',
764                Message  => "Need $_!"
765            );
766            return;
767        }
768    }
769
770    # check if job name already exists
771    my %Check = $Self->JobGet( Name => $Param{Name} );
772    if (%Check) {
773        $Kernel::OM->Get('Kernel::System::Log')->Log(
774            Priority => 'error',
775            Message  => "A job with the name '$Param{Name}' already exists.",
776        );
777        return;
778    }
779
780    # get database object
781    my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
782
783    # insert data into db
784    for my $Key ( sort keys %{ $Param{Data} } ) {
785        if ( ref $Param{Data}->{$Key} eq 'ARRAY' ) {
786            for my $Item ( @{ $Param{Data}->{$Key} } ) {
787                if ( defined $Item ) {
788                    $DBObject->Do(
789                        SQL => 'INSERT INTO generic_agent_jobs '
790                            . '(job_name, job_key, job_value) VALUES (?, ?, ?)',
791                        Bind => [ \$Param{Name}, \$Key, \$Item ],
792                    );
793                }
794            }
795        }
796        else {
797            if ( defined $Param{Data}->{$Key} ) {
798                $DBObject->Do(
799                    SQL => 'INSERT INTO generic_agent_jobs '
800                        . '(job_name, job_key, job_value) VALUES (?, ?, ?)',
801                    Bind => [ \$Param{Name}, \$Key, \$Param{Data}->{$Key} ],
802                );
803            }
804        }
805    }
806
807    $Kernel::OM->Get('Kernel::System::Log')->Log(
808        Priority => 'notice',
809        Message  => "New GenericAgent job '$Param{Name}' added (UserID=$Param{UserID}).",
810    );
811
812    $Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
813        Type => 'GenericAgent',
814    );
815
816    return 1;
817}
818
819=head2 JobDelete()
820
821deletes a job from the database
822
823    my $Success = $GenericAgentObject->JobDelete(
824        Name   => 'JobName',
825        UserID => 123,
826    );
827
828returns:
829
830    $Success = 1;       # or false in case of a failure
831
832=cut
833
834sub JobDelete {
835    my ( $Self, %Param ) = @_;
836
837    # check needed stuff
838    for (qw(Name UserID)) {
839        if ( !$Param{$_} ) {
840            $Kernel::OM->Get('Kernel::System::Log')->Log(
841                Priority => 'error',
842                Message  => "Need $_!"
843            );
844            return;
845        }
846    }
847
848    # delete job
849    $Kernel::OM->Get('Kernel::System::DB')->Do(
850        SQL  => 'DELETE FROM generic_agent_jobs WHERE job_name = ?',
851        Bind => [ \$Param{Name} ],
852    );
853
854    $Kernel::OM->Get('Kernel::System::Log')->Log(
855        Priority => 'notice',
856        Message  => "GenericAgent job '$Param{Name}' deleted (UserID=$Param{UserID}).",
857    );
858
859    $Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
860        Type => 'GenericAgent',
861    );
862
863    return 1;
864}
865
866=head2 JobEventList()
867
868returns a hash of events for each job
869
870    my %List = $GenericAgentObject->JobEventList();
871
872=cut
873
874sub JobEventList {
875    my ( $Self, %Param ) = @_;
876
877    # get cache object
878    my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
879
880    # check cache
881    my $CacheKey = "JobEventList";
882    my $Cache    = $CacheObject->Get(
883        Type => 'GenericAgent',
884        Key  => $CacheKey,
885    );
886    return %{$Cache} if ref $Cache;
887
888    my %JobList = $Self->JobList();
889    my %Data;
890    JOB_NAME:
891    for my $JobName ( sort keys %JobList ) {
892        my %Job = $Self->JobGet( Name => $JobName );
893        next JOB_NAME if !$Job{Valid};
894        $Data{$JobName} = $Job{EventValues};
895    }
896
897    $CacheObject->Set(
898        Type  => 'GenericAgent',
899        Key   => $CacheKey,
900        Value => \%Data,
901        TTL   => 24 * 60 * 60,
902    );
903
904    return %Data;
905}
906
907=begin Internal:
908
909=cut
910
911=head2 _JobRunTicket()
912
913run a generic agent job on a ticket
914
915    $GenericAgentObject->_JobRunTicket(
916        TicketID => 123,
917        TicketNumber => '2004081400001',
918        Config => {
919            %Job,
920        },
921        UserID => 1,
922    );
923
924=cut
925
926sub _JobRunTicket {
927    my ( $Self, %Param ) = @_;
928
929    # check needed stuff
930    for (qw(TicketID TicketNumber Config UserID)) {
931        if ( !$Param{$_} ) {
932            $Kernel::OM->Get('Kernel::System::Log')->Log(
933                Priority => 'error',
934                Message  => "Need $_!"
935            );
936            return;
937        }
938    }
939
940    # get ticket object
941    my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');
942
943    my $Ticket = "($Param{TicketNumber}/$Param{TicketID})";
944
945    # disable sending emails
946    $TicketObject->{SendNoNotification} = $Param{Config}->{New}->{SendNoNotification} ? 1 : 0;
947
948    # move ticket
949    if ( $Param{Config}->{New}->{Queue} ) {
950        if ( $Self->{NoticeSTDOUT} ) {
951            print "  - Move Ticket $Ticket to Queue '$Param{Config}->{New}->{Queue}'\n";
952        }
953        $TicketObject->TicketQueueSet(
954            QueueID => $Kernel::OM->Get('Kernel::System::Queue')->QueueLookup(
955                Queue => $Param{Config}->{New}->{Queue},
956                Cache => 1,
957            ),
958            UserID   => $Param{UserID},
959            TicketID => $Param{TicketID},
960        );
961    }
962    if ( $Param{Config}->{New}->{QueueID} ) {
963        if ( $Self->{NoticeSTDOUT} ) {
964            print "  - Move Ticket $Ticket to QueueID '$Param{Config}->{New}->{QueueID}'\n";
965        }
966        $TicketObject->TicketQueueSet(
967            QueueID  => $Param{Config}->{New}->{QueueID},
968            UserID   => $Param{UserID},
969            TicketID => $Param{TicketID},
970        );
971    }
972
973    my $ContentType = 'text/plain';
974
975    # add note if wanted
976    if ( $Param{Config}->{New}->{Note}->{Body} || $Param{Config}->{New}->{NoteBody} ) {
977        if ( $Self->{NoticeSTDOUT} ) {
978            print "  - Add note to Ticket $Ticket\n";
979        }
980
981        my %Ticket = $TicketObject->TicketGet(
982            TicketID      => $Param{TicketID},
983            DynamicFields => 0,
984        );
985
986        if ( IsHashRefWithData( \%Ticket ) ) {
987
988            my %CustomerUserData = {};
989            if ( IsStringWithData( $Ticket{CustomerUserID} ) ) {
990                %CustomerUserData = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerUserDataGet(
991                    User => $Ticket{CustomerUserID},
992                );
993            }
994
995            my %Notification = (
996                Subject     => $Param{Config}->{New}->{NoteSubject},
997                Body        => $Param{Config}->{New}->{NoteBody},
998                ContentType => 'text/plain',
999            );
1000
1001            my %GenericAgentArticle = $Kernel::OM->Get('Kernel::System::TemplateGenerator')->GenericAgentArticle(
1002                TicketID     => $Param{TicketID},
1003                Recipient    => \%CustomerUserData,
1004                Notification => \%Notification,
1005                UserID       => $Param{UserID},
1006            );
1007
1008            if (
1009                IsStringWithData( $GenericAgentArticle{Body} )
1010                || IsHashRefWithData( $GenericAgentArticle{Subject} )
1011                )
1012            {
1013                $Param{Config}->{New}->{Note}->{Subject} = $GenericAgentArticle{Subject} || '';
1014                $Param{Config}->{New}->{Note}->{Body}    = $GenericAgentArticle{Body}    || '';
1015                $ContentType                             = $GenericAgentArticle{ContentType};
1016            }
1017        }
1018
1019        my $ArticleBackendObject = $Kernel::OM->Get('Kernel::System::Ticket::Article')->BackendForChannel(
1020            ChannelName => 'Internal',
1021        );
1022
1023        my $ArticleID = $ArticleBackendObject->ArticleCreate(
1024            TicketID             => $Param{TicketID},
1025            SenderType           => 'agent',
1026            IsVisibleForCustomer => $Param{Config}->{New}->{Note}->{IsVisibleForCustomer}
1027                // $Param{Config}->{New}->{NoteIsVisibleForCustomer}
1028                // 0,
1029            From => $Param{Config}->{New}->{Note}->{From}
1030                || $Param{Config}->{New}->{NoteFrom}
1031                || 'GenericAgent',
1032            Subject => $Param{Config}->{New}->{Note}->{Subject}
1033                || $Param{Config}->{New}->{NoteSubject}
1034                || 'Note',
1035            Body           => $Param{Config}->{New}->{Note}->{Body} || $Param{Config}->{New}->{NoteBody},
1036            MimeType       => $ContentType,
1037            Charset        => 'utf-8',
1038            UserID         => $Param{UserID},
1039            HistoryType    => 'AddNote',
1040            HistoryComment => 'Generic Agent note added.',
1041            NoAgentNotify  => $Param{Config}->{New}->{SendNoNotification} || 0,
1042        );
1043        my $TimeUnits = $Param{Config}->{New}->{Note}->{TimeUnits}
1044            || $Param{Config}->{New}->{NoteTimeUnits};
1045        if ( $ArticleID && $TimeUnits ) {
1046            $TicketObject->TicketAccountTime(
1047                TicketID  => $Param{TicketID},
1048                ArticleID => $ArticleID,
1049                TimeUnit  => $TimeUnits,
1050                UserID    => $Param{UserID},
1051            );
1052        }
1053    }
1054
1055    my %PendingStates = $Kernel::OM->Get('Kernel::System::State')->StateGetStatesByType(
1056        StateType => [ 'pending auto', 'pending reminder' ],
1057        Result    => 'HASH',
1058    );
1059
1060    $Self->{PendingStateList} = \%PendingStates || {};
1061
1062    # set new state
1063    my $IsPendingState;
1064    if ( $Param{Config}->{New}->{State} ) {
1065        if ( $Self->{NoticeSTDOUT} ) {
1066            print "  - changed state of Ticket $Ticket to '$Param{Config}->{New}->{State}'\n";
1067        }
1068        $TicketObject->TicketStateSet(
1069            TicketID => $Param{TicketID},
1070            UserID   => $Param{UserID},
1071            State    => $Param{Config}->{New}->{State},
1072        );
1073
1074        $IsPendingState = grep { $_ eq $Param{Config}->{New}->{State} } values %{ $Self->{PendingStateList} };
1075    }
1076    if ( $Param{Config}->{New}->{StateID} ) {
1077        if ( $Self->{NoticeSTDOUT} ) {
1078            print "  - changed state id of ticket $Ticket to '$Param{Config}->{New}->{StateID}'\n";
1079        }
1080        $TicketObject->TicketStateSet(
1081            TicketID => $Param{TicketID},
1082            UserID   => $Param{UserID},
1083            StateID  => $Param{Config}->{New}->{StateID},
1084        );
1085
1086        $IsPendingState = grep { $_ == $Param{Config}->{New}->{StateID} } keys %{ $Self->{PendingStateList} };
1087    }
1088
1089    if (
1090        $Param{Config}->{New}->{PendingTime}
1091        && !$Param{Config}->{New}->{State}
1092        && !$Param{Config}->{New}->{StateID}
1093        )
1094    {
1095        # if pending time is provided, but there is no new ticket state provided,
1096        # check if ticket is already in pending state
1097        my %Ticket = $TicketObject->TicketGet(
1098            TicketID      => $Param{TicketID},
1099            DynamicFields => 0,
1100        );
1101
1102        $IsPendingState = grep { $_ eq $Ticket{State} } values %{ $Self->{PendingStateList} };
1103    }
1104
1105    # set pending time, if new state is pending state
1106    if ( $IsPendingState && $Param{Config}->{New}->{PendingTime} ) {
1107
1108        # pending time
1109        my $PendingTime = $Param{Config}->{New}->{PendingTime};
1110
1111        # calculate pending time based on hours, minutes, years...
1112        if ( $Param{Config}->{New}->{PendingTimeType} ) {
1113            $PendingTime *= $Param{Config}->{New}->{PendingTimeType};
1114        }
1115
1116        # add systemtime
1117        my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
1118        $DateTimeObject->Add( Seconds => $PendingTime );
1119
1120        # set pending time
1121        $TicketObject->TicketPendingTimeSet(
1122            Year     => $DateTimeObject->Format( Format => '%Y' ),
1123            Month    => $DateTimeObject->Format( Format => '%m' ),
1124            Day      => $DateTimeObject->Format( Format => '%d' ),
1125            Hour     => $DateTimeObject->Format( Format => '%H' ),
1126            Minute   => $DateTimeObject->Format( Format => '%M' ),
1127            TicketID => $Param{TicketID},
1128            UserID   => $Param{UserID},
1129        );
1130    }
1131
1132    # set customer id and customer user
1133    if ( $Param{Config}->{New}->{CustomerID} || $Param{Config}->{New}->{CustomerUserLogin} ) {
1134
1135        # If CustomerID or CustomerUserID is updated but not both in same call,
1136        # keep original values for non updated ones. See bug#14864 (https://bugs.otrs.org/show_bug.cgi?id=14864).
1137        my %Ticket = $TicketObject->TicketGet(
1138            TicketID      => $Param{TicketID},
1139            DynamicFields => 0,
1140        );
1141
1142        if ( $Param{Config}->{New}->{CustomerID} ) {
1143            if ( $Self->{NoticeSTDOUT} ) {
1144                print
1145                    "  - set customer id of Ticket $Ticket to '$Param{Config}->{New}->{CustomerID}'\n";
1146            }
1147        }
1148        if ( $Param{Config}->{New}->{CustomerUserLogin} ) {
1149            if ( $Self->{NoticeSTDOUT} ) {
1150                print
1151                    "  - set customer user id of Ticket $Ticket to '$Param{Config}->{New}->{CustomerUserLogin}'\n";
1152            }
1153        }
1154        $TicketObject->TicketCustomerSet(
1155            TicketID => $Param{TicketID},
1156            No       => $Param{Config}->{New}->{CustomerID} || $Ticket{CustomerID} || '',
1157            User     => $Param{Config}->{New}->{CustomerUserLogin} || $Ticket{CustomerUserID} || '',
1158            UserID   => $Param{UserID},
1159        );
1160    }
1161
1162    # set new title
1163    if ( $Param{Config}->{New}->{Title} ) {
1164        if ( $Self->{NoticeSTDOUT} ) {
1165            print "  - set title of Ticket $Ticket to '$Param{Config}->{New}->{Title}'\n";
1166        }
1167        $TicketObject->TicketTitleUpdate(
1168            Title    => $Param{Config}->{New}->{Title},
1169            TicketID => $Param{TicketID},
1170            UserID   => $Param{UserID},
1171        );
1172    }
1173
1174    # set new type
1175    if ( $Param{Config}->{New}->{Type} ) {
1176        if ( $Self->{NoticeSTDOUT} ) {
1177            print "  - set type of Ticket $Ticket to '$Param{Config}->{New}->{Type}'\n";
1178        }
1179        $TicketObject->TicketTypeSet(
1180            TicketID => $Param{TicketID},
1181            UserID   => $Param{UserID},
1182            Type     => $Param{Config}->{New}->{Type},
1183        );
1184    }
1185    if ( $Param{Config}->{New}->{TypeID} ) {
1186        if ( $Self->{NoticeSTDOUT} ) {
1187            print "  - set type id of Ticket $Ticket to '$Param{Config}->{New}->{TypeID}'\n";
1188        }
1189        $TicketObject->TicketTypeSet(
1190            TicketID => $Param{TicketID},
1191            UserID   => $Param{UserID},
1192            TypeID   => $Param{Config}->{New}->{TypeID},
1193        );
1194    }
1195
1196    # set new service
1197    if ( $Param{Config}->{New}->{Service} ) {
1198        if ( $Self->{NoticeSTDOUT} ) {
1199            print "  - set service of Ticket $Ticket to '$Param{Config}->{New}->{Service}'\n";
1200        }
1201        $TicketObject->TicketServiceSet(
1202            TicketID => $Param{TicketID},
1203            UserID   => $Param{UserID},
1204            Service  => $Param{Config}->{New}->{Service},
1205        );
1206    }
1207    if ( $Param{Config}->{New}->{ServiceID} ) {
1208        if ( $Self->{NoticeSTDOUT} ) {
1209            print "  - set service id of Ticket $Ticket to '$Param{Config}->{New}->{ServiceID}'\n";
1210        }
1211        $TicketObject->TicketServiceSet(
1212            TicketID  => $Param{TicketID},
1213            UserID    => $Param{UserID},
1214            ServiceID => $Param{Config}->{New}->{ServiceID},
1215        );
1216    }
1217
1218    # set new sla
1219    if ( $Param{Config}->{New}->{SLA} ) {
1220        if ( $Self->{NoticeSTDOUT} ) {
1221            print "  - set sla of Ticket $Ticket to '$Param{Config}->{New}->{SLA}'\n";
1222        }
1223        $TicketObject->TicketSLASet(
1224            TicketID => $Param{TicketID},
1225            UserID   => $Param{UserID},
1226            SLA      => $Param{Config}->{New}->{SLA},
1227        );
1228    }
1229    if ( $Param{Config}->{New}->{SLAID} ) {
1230        if ( $Self->{NoticeSTDOUT} ) {
1231            print "  - set sla id of Ticket $Ticket to '$Param{Config}->{New}->{SLAID}'\n";
1232        }
1233        $TicketObject->TicketSLASet(
1234            TicketID => $Param{TicketID},
1235            UserID   => $Param{UserID},
1236            SLAID    => $Param{Config}->{New}->{SLAID},
1237        );
1238    }
1239
1240    # set new priority
1241    if ( $Param{Config}->{New}->{Priority} ) {
1242        if ( $Self->{NoticeSTDOUT} ) {
1243            print "  - set priority of Ticket $Ticket to '$Param{Config}->{New}->{Priority}'\n";
1244        }
1245        $TicketObject->TicketPrioritySet(
1246            TicketID => $Param{TicketID},
1247            UserID   => $Param{UserID},
1248            Priority => $Param{Config}->{New}->{Priority},
1249        );
1250    }
1251    if ( $Param{Config}->{New}->{PriorityID} ) {
1252        if ( $Self->{NoticeSTDOUT} ) {
1253            print
1254                "  - set priority id of Ticket $Ticket to '$Param{Config}->{New}->{PriorityID}'\n";
1255        }
1256        $TicketObject->TicketPrioritySet(
1257            TicketID   => $Param{TicketID},
1258            UserID     => $Param{UserID},
1259            PriorityID => $Param{Config}->{New}->{PriorityID},
1260        );
1261    }
1262
1263    # set new owner
1264    if ( $Param{Config}->{New}->{Owner} ) {
1265        if ( $Self->{NoticeSTDOUT} ) {
1266            print "  - set owner of Ticket $Ticket to '$Param{Config}->{New}->{Owner}'\n";
1267        }
1268        $TicketObject->TicketOwnerSet(
1269            TicketID => $Param{TicketID},
1270            UserID   => $Param{UserID},
1271            NewUser  => $Param{Config}->{New}->{Owner},
1272        );
1273    }
1274    if ( $Param{Config}->{New}->{OwnerID} ) {
1275        if ( $Self->{NoticeSTDOUT} ) {
1276            print "  - set owner id of Ticket $Ticket to '$Param{Config}->{New}->{OwnerID}'\n";
1277        }
1278        $TicketObject->TicketOwnerSet(
1279            TicketID  => $Param{TicketID},
1280            UserID    => $Param{UserID},
1281            NewUserID => $Param{Config}->{New}->{OwnerID},
1282        );
1283    }
1284
1285    # set new responsible
1286    if ( $Param{Config}->{New}->{Responsible} ) {
1287        if ( $Self->{NoticeSTDOUT} ) {
1288            print
1289                "  - set responsible of Ticket $Ticket to '$Param{Config}->{New}->{Responsible}'\n";
1290        }
1291        $TicketObject->TicketResponsibleSet(
1292            TicketID => $Param{TicketID},
1293            UserID   => $Param{UserID},
1294            NewUser  => $Param{Config}->{New}->{Responsible},
1295        );
1296    }
1297    if ( $Param{Config}->{New}->{ResponsibleID} ) {
1298        if ( $Self->{NoticeSTDOUT} ) {
1299            print
1300                "  - set responsible id of Ticket $Ticket to '$Param{Config}->{New}->{ResponsibleID}'\n";
1301        }
1302        $TicketObject->TicketResponsibleSet(
1303            TicketID  => $Param{TicketID},
1304            UserID    => $Param{UserID},
1305            NewUserID => $Param{Config}->{New}->{ResponsibleID},
1306        );
1307    }
1308
1309    # set new lock
1310    if ( $Param{Config}->{New}->{Lock} ) {
1311        if ( $Self->{NoticeSTDOUT} ) {
1312            print "  - set lock of Ticket $Ticket to '$Param{Config}->{New}->{Lock}'\n";
1313        }
1314        $TicketObject->TicketLockSet(
1315            TicketID => $Param{TicketID},
1316            UserID   => $Param{UserID},
1317            Lock     => $Param{Config}->{New}->{Lock},
1318        );
1319    }
1320    if ( $Param{Config}->{New}->{LockID} ) {
1321        if ( $Self->{NoticeSTDOUT} ) {
1322            print "  - set lock id of Ticket $Ticket to '$Param{Config}->{New}->{LockID}'\n";
1323        }
1324        $TicketObject->TicketLockSet(
1325            TicketID => $Param{TicketID},
1326            UserID   => $Param{UserID},
1327            LockID   => $Param{Config}->{New}->{LockID},
1328        );
1329    }
1330
1331    # get dynamic field backend objects
1332    my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
1333
1334    # set new dynamic fields options
1335    # cycle trough the activated Dynamic Fields for this screen
1336    DYNAMICFIELD:
1337    for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
1338
1339        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
1340
1341        # extract the dynamic field value from the web request
1342        my $Value = $DynamicFieldBackendObject->EditFieldValueGet(
1343            DynamicFieldConfig => $DynamicFieldConfig,
1344            Template           => $Param{Config}->{New},
1345            TransformDates     => 0,
1346        );
1347
1348        # check if we got a value or an empty value if
1349        # an empty value is configured as valid (PossibleNone)
1350        # for the current dynamic field
1351        if (
1352            defined $Value
1353            && (
1354                $DynamicFieldConfig->{Config}->{PossibleNone}
1355                || $Value ne ''
1356            )
1357            )
1358        {
1359            my $Success = $DynamicFieldBackendObject->ValueSet(
1360                DynamicFieldConfig => $DynamicFieldConfig,
1361                ObjectID           => $Param{TicketID},
1362                Value              => $Value,
1363                UserID             => 1,
1364            );
1365
1366            if ($Success) {
1367                if ( $Self->{NoticeSTDOUT} ) {
1368                    my $ValueStrg = $DynamicFieldBackendObject->ReadableValueRender(
1369                        DynamicFieldConfig => $DynamicFieldConfig,
1370                        Value              => $Value,
1371                    );
1372                    print "  - set ticket dynamic field $DynamicFieldConfig->{Name} "
1373                        . "of Ticket $Ticket to $ValueStrg->{Title} '\n";
1374                }
1375            }
1376            else {
1377                $Kernel::OM->Get('Kernel::System::Log')->Log(
1378                    Priority => 'error',
1379                    Message  => "Could not set dynamic field $DynamicFieldConfig->{Name} "
1380                        . "for Ticket $Ticket.",
1381                );
1382            }
1383        }
1384    }
1385
1386    # run module
1387    my $AllowCustomModuleExecution
1388        = $Kernel::OM->Get('Kernel::Config')->Get('Ticket::GenericAgentAllowCustomModuleExecution') || 0;
1389
1390    if ( $Param{Config}->{New}->{Module} && $AllowCustomModuleExecution ) {
1391        if ( $Self->{NoticeSTDOUT} ) {
1392            print "  - Use module ($Param{Config}->{New}->{Module}) for Ticket $Ticket.\n";
1393        }
1394        $Kernel::OM->Get('Kernel::System::Log')->Log(
1395            Priority => 'notice',
1396            Message  => "Use module ($Param{Config}->{New}->{Module}) for Ticket $Ticket.",
1397        );
1398        if ( $Self->{Debug} ) {
1399            $Kernel::OM->Get('Kernel::System::Log')->Log(
1400                Priority => 'debug',
1401                Message  => "Try to load module: $Param{Config}->{New}->{Module}!",
1402            );
1403        }
1404
1405        if ( $Kernel::OM->Get('Kernel::System::Main')->Require( $Param{Config}->{New}->{Module} ) )
1406        {
1407
1408            # protect parent process
1409            eval {
1410                my $Object = $Param{Config}->{New}->{Module}->new(
1411                    Debug => $Self->{Debug},
1412                );
1413                if ($Object) {
1414                    $Object->Run(
1415                        %{ $Param{Config} },
1416                        TicketID => $Param{TicketID},
1417                    );
1418                }
1419            };
1420
1421            if ($@) {
1422                $Kernel::OM->Get('Kernel::System::Log')->Log(
1423                    Priority => 'error',
1424                    Message  => $@
1425                );
1426            }
1427        }
1428    }
1429    elsif ( $Param{Config}->{New}->{Module} && !$AllowCustomModuleExecution ) {
1430        if ( $Self->{NoticeSTDOUT} ) {
1431            print "  - Use module ($Param{Config}->{New}->{Module}) is not allowed by the system configuration.\n";
1432        }
1433        $Kernel::OM->Get('Kernel::System::Log')->Log(
1434            Priority => 'error',
1435            Message  => "Use module ($Param{Config}->{New}->{Module}) is not allowed by the system configuration.",
1436        );
1437    }
1438
1439    # set new archive flag
1440    if (
1441        $Param{Config}->{New}->{ArchiveFlag}
1442        && $Kernel::OM->Get('Kernel::Config')->Get('Ticket::ArchiveSystem')
1443        )
1444    {
1445        if ( $Self->{NoticeSTDOUT} ) {
1446            print
1447                "  - set archive flag of Ticket $Ticket to '$Param{Config}->{New}->{ArchiveFlag}'\n";
1448        }
1449        $TicketObject->TicketArchiveFlagSet(
1450            TicketID    => $Param{TicketID},
1451            UserID      => $Param{UserID},
1452            ArchiveFlag => $Param{Config}->{New}->{ArchiveFlag},
1453        );
1454    }
1455
1456    # cmd
1457    my $AllowCustomScriptExecution
1458        = $Kernel::OM->Get('Kernel::Config')->Get('Ticket::GenericAgentAllowCustomScriptExecution') || 0;
1459
1460    if ( $Param{Config}->{New}->{CMD} && $AllowCustomScriptExecution ) {
1461        if ( $Self->{NoticeSTDOUT} ) {
1462            print "  - Execute '$Param{Config}->{New}->{CMD}' for Ticket $Ticket.\n";
1463        }
1464        $Kernel::OM->Get('Kernel::System::Log')->Log(
1465            Priority => 'notice',
1466            Message  => "Execute '$Param{Config}->{New}->{CMD}' for Ticket $Ticket.",
1467        );
1468        system("$Param{Config}->{New}->{CMD} $Param{TicketNumber} $Param{TicketID} ");
1469
1470        if ( $? ne 0 ) {
1471            $Kernel::OM->Get('Kernel::System::Log')->Log(
1472                Priority => 'notice',
1473                Message  => "Command returned a nonzero return code: rc=$?, err=$!",
1474            );
1475        }
1476    }
1477    elsif ( $Param{Config}->{New}->{CMD} && !$AllowCustomScriptExecution ) {
1478        if ( $Self->{NoticeSTDOUT} ) {
1479            print "  - Execute '$Param{Config}->{New}->{CMD}' is not allowed by the system configuration..\n";
1480        }
1481        $Kernel::OM->Get('Kernel::System::Log')->Log(
1482            Priority => 'error',
1483            Message  => "Execute '$Param{Config}->{New}->{CMD}' is not allowed by the system configuration..",
1484        );
1485    }
1486
1487    # delete ticket
1488    if ( $Param{Config}->{New}->{Delete} ) {
1489        if ( $Self->{NoticeSTDOUT} ) {
1490            print "  - Delete Ticket $Ticket.\n";
1491        }
1492        $Kernel::OM->Get('Kernel::System::Log')->Log(
1493            Priority => 'notice',
1494            Message  => "Delete Ticket $Ticket.",
1495        );
1496        $TicketObject->TicketDelete(
1497            UserID   => $Param{UserID},
1498            TicketID => $Param{TicketID},
1499        );
1500    }
1501    return 1;
1502}
1503
1504sub _JobUpdateRunTime {
1505    my ( $Self, %Param ) = @_;
1506
1507    # check needed stuff
1508    for (qw(Name UserID)) {
1509        if ( !$Param{$_} ) {
1510            $Kernel::OM->Get('Kernel::System::Log')->Log(
1511                Priority => 'error',
1512                Message  => "Need $_!"
1513            );
1514            return;
1515        }
1516    }
1517
1518    # get database object
1519    my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
1520
1521    # delete old run times
1522    return if !$DBObject->Do(
1523        SQL  => 'DELETE FROM generic_agent_jobs WHERE job_name = ? AND job_key IN (?, ?)',
1524        Bind => [ \$Param{Name}, \'ScheduleLastRun', \'ScheduleLastRunUnixTime' ],
1525    );
1526
1527    # get time object
1528    my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
1529
1530    # update new run time
1531    my %Insert = (
1532        ScheduleLastRun         => $DateTimeObject->ToString(),
1533        ScheduleLastRunUnixTime => $DateTimeObject->ToEpoch(),
1534    );
1535
1536    for my $Key ( sort keys %Insert ) {
1537        $DBObject->Do(
1538            SQL  => 'INSERT INTO generic_agent_jobs (job_name,job_key, job_value) VALUES (?, ?, ?)',
1539            Bind => [ \$Param{Name}, \$Key, \$Insert{$Key} ],
1540        );
1541    }
1542
1543    $Kernel::OM->Get('Kernel::System::Cache')->Delete(
1544        Key  => 'JobGet::' . $Param{Name},
1545        Type => 'GenericAgent',
1546    );
1547
1548    return 1;
1549}
1550
15511;
1552
1553=end Internal:
1554
1555=head1 TERMS AND CONDITIONS
1556
1557This software is part of the OTRS project (L<https://otrs.org/>).
1558
1559This software comes with ABSOLUTELY NO WARRANTY. For details, see
1560the enclosed file COPYING for license information (GPL). If you
1561did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
1562
1563=cut
1564