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::Output::HTML::TicketOverview::Small;
10
11use strict;
12use warnings;
13
14use Kernel::System::VariableCheck qw(:all);
15use Kernel::Language qw(Translatable);
16
17our @ObjectDependencies = (
18    'Kernel::Config',
19    'Kernel::Language',
20    'Kernel::System::Log',
21    'Kernel::Output::HTML::Layout',
22    'Kernel::System::CustomerUser',
23    'Kernel::System::Group',
24    'Kernel::System::User',
25    'Kernel::System::JSON',
26    'Kernel::System::DynamicField',
27    'Kernel::System::Ticket::ColumnFilter',
28    'Kernel::System::DynamicField::Backend',
29    'Kernel::System::Ticket',
30    'Kernel::System::Ticket::Article',
31    'Kernel::System::Main',
32);
33
34sub new {
35    my ( $Type, %Param ) = @_;
36
37    # allocate new hash for object
38    my $Self = \%Param;
39    bless( $Self, $Type );
40
41    # get UserID param
42    $Self->{UserID} = $Param{UserID} || die "Got no UserID!";
43
44    # get config object
45    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
46
47    # set pref for columns key
48    $Self->{PrefKeyColumns} = 'UserFilterColumnsEnabled' . '-' . $Self->{Action};
49
50    # load backend config
51    my $BackendConfigKey = 'Ticket::Frontend::' . $Self->{Action};
52    $Self->{Config} = $ConfigObject->Get($BackendConfigKey);
53
54    my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences(
55        UserID => $Self->{UserID},
56    );
57
58    # get JSON object
59    my $JSONObject = $Kernel::OM->Get('Kernel::System::JSON');
60
61    # set stored filters if present
62    my $StoredFiltersKey = 'UserStoredFilterColumns-' . $Self->{Action};
63    if ( $Preferences{$StoredFiltersKey} ) {
64        my $StoredFilters = $JSONObject->Decode(
65            Data => $Preferences{$StoredFiltersKey},
66        );
67        $Self->{StoredFilters} = $StoredFilters;
68    }
69
70    # get the configured dyanmic fields from the Small Overview setting as a basis
71    my %DefaultDynamicFields = %{ $ConfigObject->Get("Ticket::Frontend::OverviewSmall")->{DynamicField} || {} };
72
73    my %DefaultColumns = map { 'DynamicField_' . $_ => $DefaultDynamicFields{$_} } sort keys %DefaultDynamicFields;
74
75    # take general settings (Frontend::Agent) if not defined for the screen
76    $Self->{Config}->{DefaultColumns} //= $ConfigObject->Get('DefaultOverviewColumns');
77
78    # check for default settings specific for this screen, should overide the dynamic fields
79    %DefaultColumns = ( %DefaultColumns, %{ $Self->{Config}->{DefaultColumns} || {} } );
80
81    # configure columns
82    my @ColumnsAvailable = grep { $DefaultColumns{$_} ne '0' } sort keys %DefaultColumns;
83    my @ColumnsEnabled   = grep { $DefaultColumns{$_} eq '2' } sort _DefaultColumnSort keys %DefaultColumns;
84
85    # if preference settings are available, take them
86    if ( $Preferences{ $Self->{PrefKeyColumns} } ) {
87
88        my $ColumnsEnabled = $JSONObject->Decode(
89            Data => $Preferences{ $Self->{PrefKeyColumns} },
90        );
91
92        # remove duplicate columns
93        my %UniqueColumns;
94        my @ColumnsEnabledAux;
95
96        for my $Column ( @{$ColumnsEnabled} ) {
97            if ( !$UniqueColumns{$Column} ) {
98                push @ColumnsEnabledAux, $Column;
99            }
100            $UniqueColumns{$Column} = 1;
101        }
102
103        # set filtered column list
104        @ColumnsEnabled = @ColumnsEnabledAux;
105
106    }
107
108    # always set TicketNumber
109    if ( !grep { $_ eq 'TicketNumber' } @ColumnsEnabled ) {
110        unshift @ColumnsEnabled, 'TicketNumber';
111    }
112
113    $Self->{ColumnsEnabled}   = \@ColumnsEnabled;
114    $Self->{ColumnsAvailable} = \@ColumnsAvailable;
115
116    {
117
118        # loop through all the dynamic fields to get the ones that should be shown
119        DYNAMICFIELDNAME:
120        for my $DynamicFieldName (@ColumnsEnabled) {
121
122            next DYNAMICFIELDNAME if $DynamicFieldName !~ m{ DynamicField_ }xms;
123
124            # remove dynamic field prefix
125            my $FieldName = $DynamicFieldName;
126            $FieldName =~ s/DynamicField_//gi;
127            $Self->{DynamicFieldFilter}->{$FieldName} = 1;
128        }
129    }
130
131    # get the dynamic fields for this screen
132    $Self->{DynamicField} = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
133        Valid       => 1,
134        ObjectType  => ['Ticket'],
135        FieldFilter => $Self->{DynamicFieldFilter} || {},
136    );
137
138    # hash with all valid sortable columns (taken from TicketSearch)
139    # SortBy  => 'Age',   # Created|Owner|Responsible|CustomerID|State|TicketNumber|Queue
140    # |Priority|Type|Lock|Title|Service|Changed|SLA|PendingTime|EscalationTime
141    # | EscalationUpdateTime|EscalationResponseTime|EscalationSolutionTime
142    $Self->{ValidSortableColumns} = {
143        'Age'                    => 1,
144        'Created'                => 1,
145        'Owner'                  => 1,
146        'Responsible'            => 1,
147        'CustomerID'             => 1,
148        'State'                  => 1,
149        'TicketNumber'           => 1,
150        'Queue'                  => 1,
151        'Priority'               => 1,
152        'Type'                   => 1,
153        'Lock'                   => 1,
154        'Title'                  => 1,
155        'Service'                => 1,
156        'Changed'                => 1,
157        'SLA'                    => 1,
158        'PendingTime'            => 1,
159        'EscalationTime'         => 1,
160        'EscalationUpdateTime'   => 1,
161        'EscalationResponseTime' => 1,
162        'EscalationSolutionTime' => 1,
163    };
164
165    $Self->{AvailableFilterableColumns} = {
166        'Owner'          => 1,
167        'Responsible'    => 1,
168        'CustomerID'     => 1,
169        'CustomerUserID' => 1,
170        'State'          => 1,
171        'Queue'          => 1,
172        'Priority'       => 1,
173        'Type'           => 1,
174        'Lock'           => 1,
175        'Service'        => 1,
176        'SLA'            => 1,
177    };
178
179    # remove queue from filters on AgentTicketQueue
180    if ( $Self->{Action} eq 'AgentTicketQueue' ) {
181        delete $Self->{AvailableFilterableColumns}->{Queue};
182    }
183
184    # remove service from filters on AgentTicketService
185    if ( $Self->{Action} eq 'AgentTicketService' ) {
186        delete $Self->{AvailableFilterableColumns}->{Service};
187    }
188
189    # get dynamic field backend object
190    my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
191
192    # get filterable dynamic fields
193    # cycle trough the activated dynamic fields for this screen
194    DYNAMICFIELD:
195    for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
196        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
197
198        my $IsFiltrable = $DynamicFieldBackendObject->HasBehavior(
199            DynamicFieldConfig => $DynamicFieldConfig,
200            Behavior           => 'IsFiltrable',
201        );
202
203        # if the dynamic field is filterable add it to the AvailableFilterableColumns hash
204        if ($IsFiltrable) {
205            $Self->{AvailableFilterableColumns}->{ 'DynamicField_' . $DynamicFieldConfig->{Name} } = 1;
206        }
207    }
208
209    # get sortable dynamic fields
210    # cycle trough the activated dynamic fields for this screen
211    DYNAMICFIELD:
212    for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
213        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
214
215        my $IsSortable = $DynamicFieldBackendObject->HasBehavior(
216            DynamicFieldConfig => $DynamicFieldConfig,
217            Behavior           => 'IsSortable',
218        );
219
220        # if the dynamic field is sortable add it to the ValidSortableColumns hash
221        if ($IsSortable) {
222            $Self->{ValidSortableColumns}->{ 'DynamicField_' . $DynamicFieldConfig->{Name} } = 1;
223        }
224    }
225
226    return $Self;
227}
228
229sub ActionRow {
230    my ( $Self, %Param ) = @_;
231
232    # get needed objects
233    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
234    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
235
236    # check if bulk feature is enabled
237    my $BulkFeature = 0;
238    if ( $Param{Bulk} && $ConfigObject->Get('Ticket::Frontend::BulkFeature') ) {
239        my @Groups;
240        if ( $ConfigObject->Get('Ticket::Frontend::BulkFeatureGroup') ) {
241            @Groups = @{ $ConfigObject->Get('Ticket::Frontend::BulkFeatureGroup') };
242        }
243        if ( !@Groups ) {
244            $BulkFeature = 1;
245        }
246        else {
247            my $GroupObject = $Kernel::OM->Get('Kernel::System::Group');
248            GROUP:
249            for my $Group (@Groups) {
250                my $HasPermission = $GroupObject->PermissionCheck(
251                    UserID    => $Self->{UserID},
252                    GroupName => $Group,
253                    Type      => 'rw',
254                );
255                if ($HasPermission) {
256                    $BulkFeature = 1;
257                    last GROUP;
258                }
259            }
260        }
261    }
262
263    $LayoutObject->Block(
264        Name => 'DocumentActionRow',
265        Data => \%Param,
266    );
267
268    if ($BulkFeature) {
269        $LayoutObject->Block(
270            Name => 'DocumentActionRowBulk',
271            Data => {
272                %Param,
273                Name => Translatable('Bulk'),
274            },
275        );
276    }
277
278    # check if there was a column filter and no results, and print a link to back
279    if ( scalar @{ $Param{TicketIDs} } == 0 && $Param{LastColumnFilter} ) {
280        $LayoutObject->Block(
281            Name => 'DocumentActionRowLastColumnFilter',
282            Data => {
283                %Param,
284            },
285        );
286    }
287
288    my %ColumnTranslations;
289    my $LanguageObject = $Kernel::OM->Get('Kernel::Language');
290
291    # add translations for the allocation lists for regular columns
292    my $Columns = $Self->{Config}->{DefaultColumns} || $ConfigObject->Get('DefaultOverviewColumns') || {};
293    if ( $Columns && IsHashRefWithData($Columns) ) {
294
295        COLUMN:
296        for my $Column ( sort keys %{$Columns} ) {
297
298            # dynamic fields will be translated in the next block
299            next COLUMN if $Column =~ m{ \A DynamicField_ }xms;
300
301            my $TranslatedWord = $Column;
302            if ( $Column eq 'EscalationTime' ) {
303                $TranslatedWord = Translatable('Service Time');
304            }
305            elsif ( $Column eq 'EscalationResponseTime' ) {
306                $TranslatedWord = Translatable('First Response Time');
307            }
308            elsif ( $Column eq 'EscalationSolutionTime' ) {
309                $TranslatedWord = Translatable('Solution Time');
310            }
311            elsif ( $Column eq 'EscalationUpdateTime' ) {
312                $TranslatedWord = Translatable('Update Time');
313            }
314            elsif ( $Column eq 'PendingTime' ) {
315                $TranslatedWord = Translatable('Pending till');
316            }
317            elsif ( $Column eq 'CustomerCompanyName' ) {
318                $TranslatedWord = Translatable('Customer Name');
319            }
320            elsif ( $Column eq 'CustomerID' ) {
321                $TranslatedWord = Translatable('Customer ID');
322            }
323            elsif ( $Column eq 'CustomerName' ) {
324                $TranslatedWord = Translatable('Customer User Name');
325            }
326            elsif ( $Column eq 'CustomerUserID' ) {
327                $TranslatedWord = Translatable('Customer User ID');
328            }
329
330            # send data to JS
331            $LayoutObject->AddJSData(
332                Key   => 'Column' . $Column,
333                Value => $LanguageObject->Translate($TranslatedWord),
334            );
335        }
336    }
337
338    # add translations for the allocation lists for dynamic field columns
339    my $ColumnsDynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
340        Valid      => 0,
341        ObjectType => ['Ticket'],
342    );
343
344    if ( $ColumnsDynamicField && IsArrayRefWithData($ColumnsDynamicField) ) {
345
346        my $Counter = 0;
347
348        DYNAMICFIELD:
349        for my $DynamicField ( sort @{$ColumnsDynamicField} ) {
350
351            next DYNAMICFIELD if !$DynamicField;
352
353            $Counter++;
354
355            # send data to JS
356            $LayoutObject->AddJSData(
357                Key   => 'ColumnDynamicField_' . $DynamicField->{Name},
358                Value => $LanguageObject->Translate( $DynamicField->{Label} ),
359            );
360        }
361    }
362
363    my $Output = $LayoutObject->Output(
364        TemplateFile => 'AgentTicketOverviewSmall',
365        Data         => \%Param,
366    );
367
368    return $Output;
369}
370
371sub SortOrderBar {
372    my ( $Self, %Param ) = @_;
373
374    return '';
375}
376
377sub Run {
378    my ( $Self, %Param ) = @_;
379
380    # If $Param{EnableColumnFilters} is not sent, we want to disable all filters
381    #   for the current screen. We localize the setting for this sub and change it
382    #   after that, if needed. The original value will be restored after this function.
383    local $Self->{AvailableFilterableColumns} = $Self->{AvailableFilterableColumns};
384    if ( !$Param{EnableColumnFilters} ) {
385        $Self->{AvailableFilterableColumns} = {};    # disable all column filters
386    }
387
388    for my $Item (qw(TicketIDs PageShown StartHit)) {
389        if ( !$Param{$Item} ) {
390            $Kernel::OM->Get('Kernel::System::Log')->Log(
391                Priority => 'error',
392                Message  => "Need $Item!",
393            );
394            return;
395        }
396    }
397
398    # get needed objects
399    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
400    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
401
402    # check if bulk feature is enabled
403    my $BulkFeature = 0;
404    if ( $Param{Bulk} && $ConfigObject->Get('Ticket::Frontend::BulkFeature') ) {
405        my @Groups;
406        if ( $ConfigObject->Get('Ticket::Frontend::BulkFeatureGroup') ) {
407            @Groups = @{ $ConfigObject->Get('Ticket::Frontend::BulkFeatureGroup') };
408        }
409        if ( !@Groups ) {
410            $BulkFeature = 1;
411        }
412        else {
413            my $GroupObject = $Kernel::OM->Get('Kernel::System::Group');
414            GROUP:
415            for my $Group (@Groups) {
416                my $HasPermission = $GroupObject->PermissionCheck(
417                    UserID    => $Self->{UserID},
418                    GroupName => $Group,
419                    Type      => 'rw',
420                );
421                if ($HasPermission) {
422                    $BulkFeature = 1;
423                    last GROUP;
424                }
425            }
426        }
427    }
428
429    my $Counter = 0;
430    my @ArticleBox;
431
432    my $TicketObject  = $Kernel::OM->Get('Kernel::System::Ticket');
433    my $ArticleObject = $Kernel::OM->Get('Kernel::System::Ticket::Article');
434
435    # Get extended ticket data if columns are used, save performance. See bug#14748.
436    my %ExtendedColumnsHash = (
437        FirstResponse          => 1,
438        FirstResponseInMin     => 1,
439        FirstResponseDiffInMin => 1,
440        SolutionInMin          => 1,
441        SolutionDiffInMin      => 1,
442        FirstLock              => 1,
443    );
444
445    my $Extended = 0;
446    if ( grep { $ExtendedColumnsHash{$_} } @{ $Self->{ColumnsEnabled} } ) {
447        $Extended = 1;
448    }
449
450    for my $TicketID ( @{ $Param{TicketIDs} } ) {
451        $Counter++;
452        if ( $Counter >= $Param{StartHit} && $Counter < ( $Param{PageShown} + $Param{StartHit} ) ) {
453
454            # Get last customer article.
455            my @Articles = $ArticleObject->ArticleList(
456                TicketID   => $TicketID,
457                SenderType => 'customer',
458                OnlyLast   => 1,
459            );
460
461            # If the ticket has no customer article, get the last agent article.
462            if ( !@Articles ) {
463                @Articles = $ArticleObject->ArticleList(
464                    TicketID   => $TicketID,
465                    SenderType => 'agent',
466                    OnlyLast   => 1,
467                );
468            }
469
470            # Finally, if everything failed, get latest article.
471            if ( !@Articles ) {
472                @Articles = $ArticleObject->ArticleList(
473                    TicketID => $TicketID,
474                    OnlyLast => 1,
475                );
476            }
477
478            my %Article;
479            for my $Article (@Articles) {
480                %Article = $ArticleObject->BackendForArticle( %{$Article} )->ArticleGet(
481                    %{$Article},
482                    DynamicFields => 0,
483                );
484            }
485
486            # Get ticket data.
487            my %Ticket = $TicketObject->TicketGet(
488                TicketID      => $TicketID,
489                Extended      => $Extended,
490                DynamicFields => 0,
491            );
492
493            %Article = ( %Article, %Ticket );
494
495            # Get channel specific fields.
496            if ( $Article{ArticleID} ) {
497                my %ArticleFields = $LayoutObject->ArticleFields(
498                    TicketID  => $TicketID,
499                    ArticleID => $Article{ArticleID},
500                );
501                FIELD:
502                for my $FieldKey (qw(Sender Subject)) {
503                    next FIELD if !defined $ArticleFields{$FieldKey}->{Value};
504                    $Article{$FieldKey} = $ArticleFields{$FieldKey}->{Realname} // $ArticleFields{$FieldKey}->{Value};
505                }
506            }
507
508            # Fallback for tickets without articles: get at least basic ticket data.
509            if ( !%Article ) {
510                %Article = %Ticket;
511                if ( !$Article{Title} ) {
512                    $Article{Title} = $LayoutObject->{LanguageObject}->Translate(
513                        'This ticket has no title or subject'
514                    );
515                }
516                $Article{Subject} = $Article{Title};
517            }
518
519            # show ticket create time in small view
520            $Article{Created} = $Ticket{Created};
521
522            # create human age
523            $Article{Age} = $LayoutObject->CustomerAge(
524                Age   => $Article{Age},
525                Space => ' ',
526            );
527
528            # get ACL restrictions
529            my %PossibleActions;
530            my $Counter = 0;
531
532            # get all registered Actions
533            if ( ref $ConfigObject->Get('Frontend::Module') eq 'HASH' ) {
534
535                my %Actions = %{ $ConfigObject->Get('Frontend::Module') };
536
537                # only use those Actions that stats with AgentTicket
538                %PossibleActions = map { ++$Counter => $_ }
539                    grep { substr( $_, 0, length 'AgentTicket' ) eq 'AgentTicket' }
540                    sort keys %Actions;
541            }
542
543            my $ACL = $TicketObject->TicketAcl(
544                Data          => \%PossibleActions,
545                Action        => $Self->{Action},
546                TicketID      => $Article{TicketID},
547                ReturnType    => 'Action',
548                ReturnSubType => '-',
549                UserID        => $Self->{UserID},
550            );
551            my %AclAction = %PossibleActions;
552            if ($ACL) {
553                %AclAction = $TicketObject->TicketAclActionData();
554            }
555
556            # run ticket pre menu modules
557            my @ActionItems;
558            if ( ref $ConfigObject->Get('Ticket::Frontend::PreMenuModule') eq 'HASH' ) {
559                my %Menus = %{ $ConfigObject->Get('Ticket::Frontend::PreMenuModule') };
560                my @Items;
561                MENU:
562                for my $Menu ( sort keys %Menus ) {
563
564                    # load module
565                    if ( !$Kernel::OM->Get('Kernel::System::Main')->Require( $Menus{$Menu}->{Module} ) ) {
566                        return $LayoutObject->FatalError();
567                    }
568                    my $Object = $Menus{$Menu}->{Module}->new(
569                        %{$Self},
570                        TicketID => $Article{TicketID},
571                    );
572
573                    # run module
574                    my $Item = $Object->Run(
575                        %Param,
576                        Ticket => \%Article,
577                        ACL    => \%AclAction,
578                        Config => $Menus{$Menu},
579                    );
580                    next MENU if !$Item;
581                    next MENU if ref $Item ne 'HASH';
582
583                    # add session id if needed
584                    if ( !$LayoutObject->{SessionIDCookie} && $Item->{Link} ) {
585                        $Item->{Link}
586                            .= ';'
587                            . $LayoutObject->{SessionName} . '='
588                            . $LayoutObject->{SessionID};
589                    }
590
591                    # create id
592                    $Item->{ID} = $Item->{Name};
593                    $Item->{ID} =~ s/(\s|&|;)//ig;
594
595                    my $Output;
596                    if ( $Item->{Block} ) {
597                        $LayoutObject->Block(
598                            Name => $Item->{Block},
599                            Data => $Item,
600                        );
601                        $Output = $LayoutObject->Output(
602                            TemplateFile => 'AgentTicketOverviewSmall',
603                            Data         => $Item,
604                        );
605                    }
606                    else {
607                        $Output = '<li id="'
608                            . $Item->{ID}
609                            . '"><a href="#" title="'
610                            . $LayoutObject->{LanguageObject}->Translate( $Item->{Description} )
611                            . '">'
612                            . $LayoutObject->{LanguageObject}->Translate( $Item->{Name} )
613                            . '</a></li>';
614                    }
615
616                    $Output =~ s/\n+//g;
617                    $Output =~ s/\s+/ /g;
618                    $Output =~ s/<\!--.+?-->//g;
619
620                    push @ActionItems, {
621                        HTML        => $Output,
622                        ID          => $Item->{ID},
623                        Link        => $LayoutObject->{Baselink} . $Item->{Link},
624                        Target      => $Item->{Target},
625                        PopupType   => $Item->{PopupType},
626                        Description => $Item->{Description},
627                    };
628                    $Article{ActionItems} = \@ActionItems;
629                }
630            }
631            push @ArticleBox, \%Article;
632        }
633    }
634
635    # check if sysconfig is a hash reference
636    if ( IsArrayRefWithData( $Self->{ColumnsEnabled} ) ) {
637
638        # check if column is really filterable
639        COLUMNNAME:
640        for my $ColumnName ( @{ $Self->{ColumnsEnabled} } ) {
641            next COLUMNNAME if !grep { $_ eq $ColumnName } @{ $Self->{ColumnsEnabled} };
642            next COLUMNNAME if !$Self->{AvailableFilterableColumns}->{$ColumnName};
643            $Self->{ValidFilterableColumns}->{$ColumnName} = 1;
644        }
645    }
646
647    my $ColumnValues = $Self->_GetColumnValues(
648        OriginalTicketIDs => $Param{OriginalTicketIDs},
649    );
650
651    # send data to JS
652    $LayoutObject->AddJSData(
653        Key   => 'LinkPage',
654        Value => $Param{LinkPage},
655    );
656
657    $LayoutObject->Block(
658        Name => 'DocumentContent',
659        Data => \%Param,
660    );
661
662    # array to save the column names to do the query
663    my @Col = @{ $Self->{ColumnsEnabled} };
664
665    # define special ticket columns
666    my %SpecialColumns = (
667        TicketNumber => 1,
668        Owner        => 1,
669        Responsible  => 1,
670        CustomerID   => 1,
671    );
672
673    # get dynamic field backend object
674    my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
675
676    $Param{OrderBy} = $Param{OrderBy} || 'Up';
677
678    my $TicketData = scalar @ArticleBox;
679    if ($TicketData) {
680
681        $LayoutObject->Block( Name => 'OverviewTable' );
682        $LayoutObject->Block( Name => 'TableHeader' );
683
684        if ($BulkFeature) {
685            $LayoutObject->Block(
686                Name => 'GeneralOverviewHeader',
687            );
688            $LayoutObject->Block(
689                Name => 'BulkNavBar',
690                Data => \%Param,
691            );
692        }
693
694        # meta items
695        my @TicketMetaItems = $LayoutObject->TicketMetaItemsCount();
696        for my $Item (@TicketMetaItems) {
697
698            $LayoutObject->Block(
699                Name => 'GeneralOverviewHeader',
700            );
701
702            my $CSS     = '';
703            my $OrderBy = $Param{OrderBy};
704            my $Link;
705            my $Title = $LayoutObject->{LanguageObject}->Translate($Item);
706
707            if ( $Param{SortBy} && ( $Param{SortBy} eq $Item ) ) {
708                my $TitleDesc;
709
710                # Change order for sorting column.
711                $OrderBy = $OrderBy eq 'Up' ? 'Down' : 'Up';
712
713                if ( $OrderBy eq 'Down' ) {
714                    $CSS .= ' SortAscendingLarge';
715                    $TitleDesc = Translatable('sorted ascending');
716                }
717                else {
718                    $CSS .= ' SortDescendingLarge';
719                    $TitleDesc = Translatable('sorted descending');
720                }
721
722                $TitleDesc = $LayoutObject->{LanguageObject}->Translate($TitleDesc);
723                $Title .= ', ' . $TitleDesc;
724            }
725
726            $LayoutObject->Block(
727                Name => 'OverviewNavBarPageFlag',
728                Data => {
729                    CSS   => $CSS,
730                    Title => $Title,
731                },
732            );
733
734            if ( $Item eq 'New Article' ) {
735                $LayoutObject->Block(
736                    Name => 'OverviewNavBarPageFlagEmpty',
737                    Data => {
738                        Name => $Item,
739                    }
740                );
741            }
742            else {
743                $LayoutObject->Block(
744                    Name => 'OverviewNavBarPageFlagLink',
745                    Data => {
746                        %Param,
747                        Name    => $Item,
748                        CSS     => $CSS,
749                        OrderBy => $OrderBy,
750                        Title   => $Title,
751                    },
752                );
753            }
754
755        }
756
757        my $CSS = '';
758
759        # show special ticket columns, if needed
760        COLUMN:
761        for my $Column (@Col) {
762
763            $LayoutObject->Block(
764                Name => 'GeneralOverviewHeader',
765            );
766
767            $CSS = $Column;
768            my $Title   = $LayoutObject->{LanguageObject}->Translate($Column);
769            my $OrderBy = $Param{OrderBy};
770
771            # output overall block so TicketNumber as well as other columns can be ordered
772            $LayoutObject->Block(
773                Name => 'OverviewNavBarPageTicketHeader',
774                Data => {},
775            );
776
777            if ( $SpecialColumns{$Column} ) {
778
779                if ( $Param{SortBy} && ( $Param{SortBy} eq $Column ) ) {
780                    my $TitleDesc;
781
782                    # Change order for sorting column.
783                    $OrderBy = $OrderBy eq 'Up' ? 'Down' : 'Up';
784
785                    if ( $OrderBy eq 'Down' ) {
786                        $CSS .= ' SortAscendingLarge';
787                        $TitleDesc = Translatable('sorted ascending');
788                    }
789                    else {
790                        $CSS .= ' SortDescendingLarge';
791                        $TitleDesc = Translatable('sorted descending');
792                    }
793
794                    $TitleDesc = $LayoutObject->{LanguageObject}->Translate($TitleDesc);
795                    $Title .= ', ' . $TitleDesc;
796                }
797
798                # translate the column name to write it in the current language
799                my $TranslatedWord;
800                if ( $Column eq 'CustomerID' ) {
801                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Customer ID');
802                }
803                else {
804                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate($Column);
805                }
806
807                my $FilterTitle     = $TranslatedWord;
808                my $FilterTitleDesc = Translatable('filter not active');
809                if (
810                    $Self->{StoredFilters} &&
811                    (
812                        $Self->{StoredFilters}->{$Column} ||
813                        $Self->{StoredFilters}->{ $Column . 'IDs' }
814                    )
815                    )
816                {
817                    $CSS .= ' FilterActive';
818                    $FilterTitleDesc = Translatable('filter active');
819                }
820                $FilterTitleDesc = $LayoutObject->{LanguageObject}->Translate($FilterTitleDesc);
821                $FilterTitle .= ', ' . $FilterTitleDesc;
822
823                $LayoutObject->Block(
824                    Name =>
825                        $Column eq 'TicketNumber'
826                    ? 'OverviewNavBarPageTicketNumber'
827                    : 'OverviewNavBarPageColumn',
828                    Data => {
829                        %Param,
830                        OrderBy              => $OrderBy,
831                        ColumnName           => $Column || '',
832                        CSS                  => $CSS || '',
833                        ColumnNameTranslated => $TranslatedWord || $Column,
834                        Title                => $Title,
835                    },
836                );
837
838                # verify if column is filterable and sortable
839                if (
840                    $Self->{ValidFilterableColumns}->{$Column}
841                    && $Self->{ValidSortableColumns}->{$Column}
842                    )
843                {
844                    my $Css;
845                    if ( $Column eq 'CustomerID' || $Column eq 'Owner' || $Column eq 'Responsible' ) {
846                        $Css .= ' Hidden';
847                    }
848
849                    # variable to save the filter's html code
850                    my $ColumnFilterHTML = $Self->_InitialColumnFilter(
851                        ColumnName    => $Column,
852                        Label         => $Column,
853                        ColumnValues  => $ColumnValues->{$Column},
854                        SelectedValue => $Param{GetColumnFilter}->{$Column} || '',
855                        Css           => $Css,
856                    );
857
858                    $LayoutObject->Block(
859                        Name => 'OverviewNavBarPageColumnFilterLink',
860                        Data => {
861                            %Param,
862                            ColumnName           => $Column,
863                            CSS                  => $CSS,
864                            ColumnNameTranslated => $TranslatedWord || $Column,
865                            ColumnFilterStrg     => $ColumnFilterHTML,
866                            OrderBy              => $OrderBy,
867                            Title                => $Title,
868                            FilterTitle          => $FilterTitle,
869                        },
870                    );
871
872                    if ( $Column eq 'CustomerID' ) {
873
874                        $LayoutObject->Block(
875                            Name =>
876                                'ContentLargeTicketGenericHeaderColumnFilterLinkCustomerIDSearch',
877                            Data => {},
878                        );
879
880                        # send data to JS
881                        $LayoutObject->AddJSData(
882                            Key   => 'CustomerIDAutocomplete',
883                            Value => {
884                                'QueryDelay'          => 100,
885                                'MaxResultsDisplayed' => 20,
886                                'MinQueryLength'      => 2,
887                            },
888                        );
889                    }
890                    elsif ( $Column eq 'Owner' || $Column eq 'Responsible' ) {
891
892                        $LayoutObject->Block(
893                            Name => 'ContentLargeTicketGenericHeaderColumnFilterLinkUserSearch',
894                            Data => {},
895                        );
896
897                        # send data to JS
898                        $LayoutObject->AddJSData(
899                            Key   => 'UserAutocomplete',
900                            Value => {
901                                'QueryDelay'          => 100,
902                                'MaxResultsDisplayed' => 20,
903                                'MinQueryLength'      => 2,
904                            },
905                        );
906                    }
907
908                }
909
910                # verify if column is filterable
911                elsif ( $Self->{ValidFilterableColumns}->{$Column} ) {
912
913                    # variable to save the filter's HTML code
914                    my $ColumnFilterHTML = $Self->_InitialColumnFilter(
915                        ColumnName    => $Column,
916                        Label         => $Column,
917                        ColumnValues  => $ColumnValues->{$Column},
918                        SelectedValue => $Param{GetColumnFilter}->{$Column} || '',
919                    );
920
921                    $LayoutObject->Block(
922                        Name => 'OverviewNavBarPageColumnFilter',
923                        Data => {
924                            %Param,
925                            ColumnName           => $Column,
926                            CSS                  => $CSS,
927                            ColumnNameTranslated => $TranslatedWord || $Column,
928                            ColumnFilterStrg     => $ColumnFilterHTML,
929                            OrderBy              => $OrderBy,
930                            Title                => $Title,
931                            FilterTitle          => $FilterTitle,
932                        },
933                    );
934                }
935
936                # verify if column is sortable
937                elsif ( $Self->{ValidSortableColumns}->{$Column} ) {
938                    $LayoutObject->Block(
939                        Name => 'OverviewNavBarPageColumnLink',
940                        Data => {
941                            %Param,
942                            ColumnName           => $Column,
943                            CSS                  => $CSS,
944                            ColumnNameTranslated => $TranslatedWord || $Column,
945                            OrderBy              => $OrderBy,
946                            Title                => $Title,
947                        },
948                    );
949                }
950                else {
951                    $LayoutObject->Block(
952                        Name => 'OverviewNavBarPageColumnEmpty',
953                        Data => {
954                            %Param,
955                            ColumnName           => $Column,
956                            CSS                  => $CSS,
957                            ColumnNameTranslated => $TranslatedWord || $Column,
958                            Title                => $Title,
959                        },
960                    );
961                }
962                next COLUMN;
963            }
964            elsif ( $Column !~ m{\A DynamicField_}xms ) {
965
966                if ( $Param{SortBy} && ( $Param{SortBy} eq $Column ) ) {
967                    my $TitleDesc;
968
969                    # Change order for sorting column.
970                    $OrderBy = $OrderBy eq 'Up' ? 'Down' : 'Up';
971
972                    if ( $OrderBy eq 'Down' ) {
973                        $CSS .= ' SortAscendingLarge';
974                        $TitleDesc = Translatable('sorted ascending');
975                    }
976                    else {
977                        $CSS .= ' SortDescendingLarge';
978                        $TitleDesc = Translatable('sorted descending');
979                    }
980
981                    $TitleDesc = $LayoutObject->{LanguageObject}->Translate($TitleDesc);
982                    $Title .= ', ' . $TitleDesc;
983                }
984
985                # translate the column name to write it in the current language
986                my $TranslatedWord;
987                if ( $Column eq 'EscalationTime' ) {
988                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Service Time');
989                }
990                elsif ( $Column eq 'EscalationResponseTime' ) {
991                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('First Response Time');
992                }
993                elsif ( $Column eq 'EscalationSolutionTime' ) {
994                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Solution Time');
995                }
996                elsif ( $Column eq 'EscalationUpdateTime' ) {
997                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Update Time');
998                }
999                elsif ( $Column eq 'PendingTime' ) {
1000                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Pending till');
1001                }
1002                elsif ( $Column eq 'CustomerCompanyName' ) {
1003                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Customer Name');
1004                }
1005                elsif ( $Column eq 'CustomerName' ) {
1006                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Customer User Name');
1007                }
1008                elsif ( $Column eq 'CustomerUserID' ) {
1009                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate('Customer User ID');
1010                }
1011                else {
1012                    $TranslatedWord = $LayoutObject->{LanguageObject}->Translate($Column);
1013                }
1014
1015                my $FilterTitle     = $TranslatedWord;
1016                my $FilterTitleDesc = Translatable('filter not active');
1017                if ( $Self->{StoredFilters} && $Self->{StoredFilters}->{ $Column . 'IDs' } ) {
1018                    $CSS .= ' FilterActive';
1019                    $FilterTitleDesc = Translatable('filter active');
1020                }
1021                $FilterTitleDesc = $LayoutObject->{LanguageObject}->Translate($FilterTitleDesc);
1022                $FilterTitle .= ', ' . $FilterTitleDesc;
1023
1024                $LayoutObject->Block(
1025                    Name => 'OverviewNavBarPageColumn',
1026                    Data => {
1027                        %Param,
1028                        ColumnName           => $Column,
1029                        CSS                  => $CSS,
1030                        ColumnNameTranslated => $TranslatedWord || $Column,
1031                    },
1032                );
1033
1034                # verify if column is filterable and sortable
1035                if (
1036                    $Self->{ValidFilterableColumns}->{$Column}
1037                    && $Self->{ValidSortableColumns}->{$Column}
1038                    )
1039                {
1040
1041                    # variable to save the filter's HTML code
1042                    my $ColumnFilterHTML = $Self->_InitialColumnFilter(
1043                        ColumnName    => $Column,
1044                        Label         => $Column,
1045                        ColumnValues  => $ColumnValues->{$Column},
1046                        SelectedValue => $Param{GetColumnFilter}->{$Column} || '',
1047                    );
1048
1049                    $LayoutObject->Block(
1050                        Name => 'OverviewNavBarPageColumnFilterLink',
1051                        Data => {
1052                            %Param,
1053                            ColumnName           => $Column,
1054                            CSS                  => $CSS,
1055                            ColumnNameTranslated => $TranslatedWord || $Column,
1056                            ColumnFilterStrg     => $ColumnFilterHTML,
1057                            OrderBy              => $OrderBy,
1058                            Title                => $Title,
1059                            FilterTitle          => $FilterTitle,
1060                        },
1061                    );
1062                }
1063
1064                # verify if column is just filterable
1065                elsif ( $Self->{ValidFilterableColumns}->{$Column} ) {
1066
1067                    my $Css;
1068                    if ( $Column eq 'CustomerUserID' ) {
1069                        $Css = 'Hidden';
1070                    }
1071
1072                    # variable to save the filter's HTML code
1073                    my $ColumnFilterHTML = $Self->_InitialColumnFilter(
1074                        ColumnName    => $Column,
1075                        Label         => $Column,
1076                        ColumnValues  => $ColumnValues->{$Column},
1077                        SelectedValue => $Param{GetColumnFilter}->{$Column} || '',
1078                        Css           => $Css,
1079                    );
1080                    $LayoutObject->Block(
1081                        Name => 'OverviewNavBarPageColumnFilter',
1082                        Data => {
1083                            %Param,
1084                            ColumnName           => $Column,
1085                            CSS                  => $CSS,
1086                            ColumnNameTranslated => $TranslatedWord || $Column,
1087                            ColumnFilterStrg     => $ColumnFilterHTML,
1088                            OrderBy              => $OrderBy,
1089                            Title                => $Title,
1090                            FilterTitle          => $FilterTitle,
1091                        },
1092                    );
1093                    if ( $Column eq 'CustomerUserID' ) {
1094
1095                        $LayoutObject->Block(
1096                            Name =>
1097                                'ContentLargeTicketGenericHeaderColumnFilterLinkCustomerUserSearch',
1098                            Data => {},
1099                        );
1100
1101                        # send data to JS
1102                        $LayoutObject->AddJSData(
1103                            Key   => 'CustomerUserAutocomplete',
1104                            Value => {
1105                                'QueryDelay'          => 100,
1106                                'MaxResultsDisplayed' => 20,
1107                                'MinQueryLength'      => 2,
1108                            },
1109                        );
1110                    }
1111                }
1112
1113                # verify if column is sortable
1114                elsif ( $Self->{ValidSortableColumns}->{$Column} ) {
1115                    $LayoutObject->Block(
1116                        Name => 'OverviewNavBarPageColumnLink',
1117                        Data => {
1118                            %Param,
1119                            ColumnName           => $Column,
1120                            CSS                  => $CSS,
1121                            ColumnNameTranslated => $TranslatedWord || $Column,
1122                            OrderBy              => $OrderBy,
1123                            Title                => $Title,
1124                        },
1125                    );
1126                }
1127                else {
1128                    $LayoutObject->Block(
1129                        Name => 'OverviewNavBarPageColumnEmpty',
1130                        Data => {
1131                            %Param,
1132                            ColumnName           => $Column,
1133                            CSS                  => $CSS,
1134                            ColumnNameTranslated => $TranslatedWord || $Column,
1135                            Title                => $Title,
1136                        },
1137                    );
1138                }
1139            }
1140
1141            # show the DFs
1142            else {
1143
1144                my $DynamicFieldConfig;
1145                my $DFColumn = $Column;
1146                $DFColumn =~ s/DynamicField_//g;
1147                DYNAMICFIELD:
1148                for my $DFConfig ( @{ $Self->{DynamicField} } ) {
1149                    next DYNAMICFIELD if !IsHashRefWithData($DFConfig);
1150                    next DYNAMICFIELD if $DFConfig->{Name} ne $DFColumn;
1151
1152                    $DynamicFieldConfig = $DFConfig;
1153                    last DYNAMICFIELD;
1154                }
1155                next COLUMN if !IsHashRefWithData($DynamicFieldConfig);
1156
1157                my $Label = $DynamicFieldConfig->{Label};
1158                $Title = $Label;
1159                my $FilterTitle = $Label;
1160
1161                # get field sortable condition
1162                my $IsSortable = $DynamicFieldBackendObject->HasBehavior(
1163                    DynamicFieldConfig => $DynamicFieldConfig,
1164                    Behavior           => 'IsSortable',
1165                );
1166
1167                if ($IsSortable) {
1168                    my $CSS = 'DynamicField_' . $DynamicFieldConfig->{Name};
1169                    if (
1170                        $Param{SortBy}
1171                        && ( $Param{SortBy} eq ( 'DynamicField_' . $DynamicFieldConfig->{Name} ) )
1172                        )
1173                    {
1174                        my $TitleDesc;
1175
1176                        # Change order for sorting column.
1177                        $OrderBy = $OrderBy eq 'Up' ? 'Down' : 'Up';
1178
1179                        if ( $OrderBy eq 'Down' ) {
1180                            $CSS .= ' SortAscendingLarge';
1181                            $TitleDesc = Translatable('sorted ascending');
1182                        }
1183                        else {
1184                            $CSS .= ' SortDescendingLarge';
1185                            $TitleDesc = Translatable('sorted descending');
1186                        }
1187
1188                        $TitleDesc = $LayoutObject->{LanguageObject}->Translate($TitleDesc);
1189                        $Title .= ', ' . $TitleDesc;
1190                    }
1191
1192                    my $FilterTitleDesc = Translatable('filter not active');
1193                    if ( $Self->{StoredFilters} && $Self->{StoredFilters}->{$Column} ) {
1194                        $CSS .= ' FilterActive';
1195                        $FilterTitleDesc = Translatable('filter active');
1196                    }
1197                    $FilterTitleDesc = $LayoutObject->{LanguageObject}->Translate($FilterTitleDesc);
1198                    $FilterTitle .= ', ' . $FilterTitleDesc;
1199
1200                    $LayoutObject->Block(
1201                        Name => 'OverviewNavBarPageDynamicField',
1202                        Data => {
1203                            %Param,
1204                            CSS => $CSS,
1205                        },
1206                    );
1207
1208                    my $DynamicFieldName = 'DynamicField_' . $DynamicFieldConfig->{Name};
1209
1210                    if ( $Self->{ValidFilterableColumns}->{$DynamicFieldName} ) {
1211
1212                        # variable to save the filter's HTML code
1213                        my $ColumnFilterHTML = $Self->_InitialColumnFilter(
1214                            ColumnName    => $DynamicFieldName,
1215                            Label         => $Label,
1216                            ColumnValues  => $ColumnValues->{$DynamicFieldName},
1217                            SelectedValue => $Param{GetColumnFilter}->{$DynamicFieldName} || '',
1218                        );
1219
1220                        $LayoutObject->Block(
1221                            Name => 'OverviewNavBarPageDynamicFieldFiltrableSortable',
1222                            Data => {
1223                                %Param,
1224                                OrderBy          => $OrderBy,
1225                                Label            => $Label,
1226                                DynamicFieldName => $DynamicFieldConfig->{Name},
1227                                ColumnFilterStrg => $ColumnFilterHTML,
1228                                Title            => $Title,
1229                                FilterTitle      => $FilterTitle,
1230                            },
1231                        );
1232                    }
1233
1234                    else {
1235                        $LayoutObject->Block(
1236                            Name => 'OverviewNavBarPageDynamicFieldSortable',
1237                            Data => {
1238                                %Param,
1239                                OrderBy          => $OrderBy,
1240                                Label            => $Label,
1241                                DynamicFieldName => $DynamicFieldConfig->{Name},
1242                                Title            => $Title,
1243                            },
1244                        );
1245                    }
1246
1247                    # example of dynamic fields order customization
1248                    $LayoutObject->Block(
1249                        Name => 'OverviewNavBarPageDynamicField_' . $DynamicFieldConfig->{Name},
1250                        Data => {
1251                            %Param,
1252                            CSS => $CSS,
1253                        },
1254                    );
1255
1256                    if ( $Self->{ValidFilterableColumns}->{$DynamicFieldName} ) {
1257
1258                        # variable to save the filter's HTML code
1259                        my $ColumnFilterHTML = $Self->_InitialColumnFilter(
1260                            ColumnName    => $DynamicFieldName,
1261                            Label         => $Label,
1262                            ColumnValues  => $ColumnValues->{$DynamicFieldName},
1263                            SelectedValue => $Param{GetColumnFilter}->{$DynamicFieldName} || '',
1264                        );
1265
1266                        $LayoutObject->Block(
1267                            Name => 'OverviewNavBarPageDynamicField'
1268                                . $DynamicFieldConfig->{Name}
1269                                . '_FiltrableSortable',
1270                            Data => {
1271                                %Param,
1272                                OrderBy          => $OrderBy,
1273                                Label            => $Label,
1274                                DynamicFieldName => $DynamicFieldConfig->{Name},
1275                                ColumnFilterStrg => $ColumnFilterHTML,
1276                                Title            => $Title,
1277                            },
1278                        );
1279                    }
1280                    else {
1281                        $LayoutObject->Block(
1282                            Name => 'OverviewNavBarPageDynamicField_'
1283                                . $DynamicFieldConfig->{Name}
1284                                . '_Sortable',
1285                            Data => {
1286                                %Param,
1287                                OrderBy          => $OrderBy,
1288                                Label            => $Label,
1289                                DynamicFieldName => $DynamicFieldConfig->{Name},
1290                                Title            => $Title,
1291                            },
1292                        );
1293                    }
1294                }
1295                else {
1296
1297                    my $DynamicFieldName = 'DynamicField_' . $DynamicFieldConfig->{Name};
1298                    my $CSS              = $DynamicFieldName;
1299
1300                    $LayoutObject->Block(
1301                        Name => 'OverviewNavBarPageDynamicField',
1302                        Data => {
1303                            %Param,
1304                            CSS => $CSS,
1305                        },
1306                    );
1307
1308                    if ( $Self->{ValidFilterableColumns}->{$DynamicFieldName} ) {
1309
1310                        # variable to save the filter's HTML code
1311                        my $ColumnFilterHTML = $Self->_InitialColumnFilter(
1312                            ColumnName    => $DynamicFieldName,
1313                            Label         => $Label,
1314                            ColumnValues  => $ColumnValues->{$DynamicFieldName},
1315                            SelectedValue => $Param{GetColumnFilter}->{$DynamicFieldName} || '',
1316                        );
1317
1318                        $LayoutObject->Block(
1319                            Name => 'OverviewNavBarPageDynamicFieldFiltrableNotSortable',
1320                            Data => {
1321                                %Param,
1322                                Label            => $Label,
1323                                DynamicFieldName => $DynamicFieldConfig->{Name},
1324                                ColumnFilterStrg => $ColumnFilterHTML,
1325                                Title            => $Title,
1326                                FilterTitle      => $FilterTitle,
1327                            },
1328                        );
1329                    }
1330                    else {
1331                        $LayoutObject->Block(
1332                            Name => 'OverviewNavBarPageDynamicFieldNotSortable',
1333                            Data => {
1334                                %Param,
1335                                Label => $Label,
1336                                Title => $Title,
1337                            },
1338                        );
1339                    }
1340
1341                    # example of dynamic fields order customization
1342                    $LayoutObject->Block(
1343                        Name => 'OverviewNavBarPageDynamicField_' . $DynamicFieldConfig->{Name},
1344                        Data => {
1345                            %Param,
1346                        },
1347                    );
1348
1349                    if ( $Self->{ValidFilterableColumns}->{$DynamicFieldName} ) {
1350
1351                        # variable to save the filter's HTML code
1352                        my $ColumnFilterHTML = $Self->_InitialColumnFilter(
1353                            ColumnName    => $DynamicFieldName,
1354                            Label         => $Label,
1355                            ColumnValues  => $ColumnValues->{$DynamicFieldName},
1356                            SelectedValue => $Param{GetColumnFilter}->{$DynamicFieldName} || '',
1357                        );
1358
1359                        $LayoutObject->Block(
1360                            Name => 'OverviewNavBarPageDynamicField_'
1361                                . $DynamicFieldConfig->{Name}
1362                                . '_FiltrableNotSortable',
1363                            Data => {
1364                                %Param,
1365                                Label            => $Label,
1366                                DynamicFieldName => $DynamicFieldConfig->{Name},
1367                                ColumnFilterStrg => $ColumnFilterHTML,
1368                                Title            => $Title,
1369                            },
1370                        );
1371                    }
1372                    else {
1373                        $LayoutObject->Block(
1374                            Name => 'OverviewNavBarPageDynamicField_'
1375                                . $DynamicFieldConfig->{Name}
1376                                . '_NotSortable',
1377                            Data => {
1378                                %Param,
1379                                Label => $Label,
1380                                Title => $Title,
1381                            },
1382                        );
1383                    }
1384                }
1385
1386            }
1387
1388        }
1389
1390        $LayoutObject->Block( Name => 'TableBody' );
1391
1392    }
1393    else {
1394        $LayoutObject->Block( Name => 'NoTicketFound' );
1395    }
1396
1397    my %ActionRowTickets;
1398
1399    for my $ArticleRef (@ArticleBox) {
1400
1401        # get last customer article
1402        my %Article = %{$ArticleRef};
1403
1404        # escalation human times
1405        if ( $Article{EscalationTime} ) {
1406            $Article{EscalationTimeHuman} = $LayoutObject->CustomerAge(
1407                Age                => $Article{EscalationTime},
1408                TimeShowAlwaysLong => 1,
1409                Space              => ' ',
1410            );
1411            $Article{EscalationTimeWorkingTime} = $LayoutObject->CustomerAge(
1412                Age                => $Article{EscalationTimeWorkingTime},
1413                TimeShowAlwaysLong => 1,
1414                Space              => ' ',
1415            );
1416        }
1417
1418        # customer info
1419        my %CustomerInfo;
1420        if ( $Param{Config}->{CustomerInfo} ) {
1421            if ( $Article{CustomerUserID} ) {
1422
1423                # get customer user object
1424                my $CustomerUserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
1425
1426                $Article{CustomerName} = $CustomerUserObject->CustomerName(
1427                    UserLogin => $Article{CustomerUserID},
1428                );
1429
1430                %CustomerInfo = $CustomerUserObject->CustomerUserDataGet(
1431                    User => $Article{CustomerUserID},
1432                );
1433
1434                INFOKEY:
1435                for my $InfoKey ( sort keys %CustomerInfo ) {
1436                    next INFOKEY if $InfoKey =~ m{\ACustomer}xms;
1437
1438                    $CustomerInfo{ 'Customer' . $InfoKey } = $CustomerInfo{$InfoKey};
1439                }
1440            }
1441        }
1442
1443        # get user object
1444        my $UserObject = $Kernel::OM->Get('Kernel::System::User');
1445
1446        # user info
1447        my %UserInfo = $UserObject->GetUserData(
1448            UserID => $Article{OwnerID},
1449        );
1450
1451        # Responsible info.
1452        my %ResponsibleInfo = $UserObject->GetUserData(
1453            UserID => $Article{ResponsibleID},
1454        );
1455        $UserInfo{ResponsibleInfo} = \%ResponsibleInfo;
1456
1457        $LayoutObject->Block(
1458            Name => 'Record',
1459            Data => { %Article, %UserInfo },
1460        );
1461
1462        # check if bulk feature is enabled
1463        if ($BulkFeature) {
1464            $LayoutObject->Block(
1465                Name => 'GeneralOverviewRow',
1466            );
1467            $LayoutObject->Block(
1468                Name => Translatable('Bulk'),
1469                Data => { %Article, %UserInfo },
1470            );
1471        }
1472
1473        # show ticket flags
1474        my @TicketMetaItems = $LayoutObject->TicketMetaItems(
1475            Ticket => \%Article,
1476        );
1477        for my $Item (@TicketMetaItems) {
1478            $LayoutObject->Block(
1479                Name => 'GeneralOverviewRow',
1480            );
1481            $LayoutObject->Block(
1482                Name => 'ContentLargeTicketGenericRowMeta',
1483                Data => $Item,
1484            );
1485            if ($Item) {
1486                $LayoutObject->Block(
1487                    Name => 'ContentLargeTicketGenericRowMetaImage',
1488                    Data => $Item,
1489                );
1490            }
1491        }
1492
1493        # save column content
1494        my $DataValue;
1495
1496        # show all needed columns
1497        TICKETCOLUMN:
1498        for my $TicketColumn (@Col) {
1499            $LayoutObject->Block(
1500                Name => 'GeneralOverviewRow',
1501            );
1502            if ( $TicketColumn !~ m{\A DynamicField_}xms ) {
1503                $LayoutObject->Block(
1504                    Name => 'RecordTicketData',
1505                    Data => {},
1506                );
1507
1508                if ( $SpecialColumns{$TicketColumn} ) {
1509                    $LayoutObject->Block(
1510                        Name => 'Record' . $TicketColumn,
1511                        Data => { %Article, %UserInfo },
1512                    );
1513
1514                    next TICKETCOLUMN;
1515                }
1516
1517                if ( $TicketColumn eq 'CreatedBy' ) {
1518
1519                    my %TicketCreatedByInfo = $UserObject->GetUserData(
1520                        UserID => $Article{CreateBy},
1521                    );
1522
1523                    $LayoutObject->Block(
1524                        Name => 'RecordTicketCreatedBy',
1525                        Data => \%TicketCreatedByInfo,
1526                    );
1527                    next TICKETCOLUMN;
1528                }
1529
1530                # escalation column
1531                my %EscalationData;
1532                if ( $TicketColumn eq 'EscalationTime' ) {
1533                    $EscalationData{EscalationTime}            = $Article{EscalationTime};
1534                    $EscalationData{EscalationDestinationDate} = $Article{EscalationDestinationDate};
1535
1536                    $EscalationData{EscalationTimeHuman} = $LayoutObject->CustomerAge(
1537                        Age                => $EscalationData{EscalationTime},
1538                        TimeShowAlwaysLong => 1,
1539                        Space              => ' ',
1540                    ) || '-';
1541                    $EscalationData{EscalationTimeWorkingTime} = $LayoutObject->CustomerAge(
1542                        Age                => $EscalationData{EscalationTimeWorkingTime},
1543                        TimeShowAlwaysLong => 1,
1544                        Space              => ' ',
1545                    );
1546                    if (
1547                        defined $Article{EscalationTime}
1548                        && $Article{EscalationTime} < 60 * 60 * 1
1549                        )
1550                    {
1551                        $EscalationData{EscalationClass} = 'Warning';
1552                    }
1553                    $LayoutObject->Block(
1554                        Name => 'RecordEscalationTime',
1555                        Data => {%EscalationData},
1556                    );
1557                    next TICKETCOLUMN;
1558                }
1559
1560                my $BlockType = '';
1561                my $CSSClass  = '';
1562                if ( $TicketColumn eq 'EscalationSolutionTime' ) {
1563                    $BlockType = 'Escalation';
1564                    $DataValue = $LayoutObject->CustomerAge(
1565                        Age                => $Article{SolutionTime} || 0,
1566                        TimeShowAlwaysLong => 1,
1567                        Space              => ' ',
1568                    );
1569                    if ( defined $Article{SolutionTime} && $Article{SolutionTime} < 60 * 60 * 1 ) {
1570                        $CSSClass = 'Warning';
1571                    }
1572                }
1573                elsif ( $TicketColumn eq 'EscalationResponseTime' ) {
1574                    $BlockType = 'Escalation';
1575                    $DataValue = $LayoutObject->CustomerAge(
1576                        Age                => $Article{FirstResponseTime} || 0,
1577                        TimeShowAlwaysLong => 1,
1578                        Space              => ' ',
1579                    );
1580                    if (
1581                        defined $Article{FirstResponseTime}
1582                        && $Article{FirstResponseTime} < 60 * 60 * 1
1583                        )
1584                    {
1585                        $CSSClass = 'Warning';
1586                    }
1587                }
1588                elsif ( $TicketColumn eq 'EscalationUpdateTime' ) {
1589                    $BlockType = 'Escalation';
1590                    $DataValue = $LayoutObject->CustomerAge(
1591                        Age                => $Article{UpdateTime} || 0,
1592                        TimeShowAlwaysLong => 1,
1593                        Space              => ' ',
1594                    );
1595                    if ( defined $Article{UpdateTime} && $Article{UpdateTime} < 60 * 60 * 1 ) {
1596                        $CSSClass = 'Warning';
1597                    }
1598                }
1599                elsif ( $TicketColumn eq 'PendingTime' ) {
1600                    $BlockType = 'Escalation';
1601                    $DataValue = $LayoutObject->CustomerAge(
1602                        Age   => $Article{'UntilTime'},
1603                        Space => ' '
1604                    );
1605                    if ( defined $Article{UntilTime} && $Article{UntilTime} < -1 ) {
1606                        $CSSClass = 'Warning';
1607                    }
1608                }
1609                elsif (
1610                    $TicketColumn eq 'State'
1611                    || $TicketColumn eq 'Lock'
1612                    || $TicketColumn eq 'Priority'
1613                    )
1614                {
1615                    $BlockType = 'Translatable';
1616                    $DataValue = $Article{$TicketColumn} || $UserInfo{$TicketColumn};
1617                }
1618                elsif ( $TicketColumn eq 'Created' || $TicketColumn eq 'Changed' ) {
1619                    $BlockType = 'Time';
1620                    $DataValue = $Article{$TicketColumn} || $UserInfo{$TicketColumn};
1621                }
1622                elsif ( $TicketColumn eq 'Responsible' ) {
1623
1624                    my %ResponsibleInfo = $UserObject->GetUserData(
1625                        UserID => $Article{ResponsibleID},
1626                    );
1627
1628                    $DataValue = $ResponsibleInfo{'UserFullname'};
1629                }
1630                else {
1631                    $DataValue = $Article{$TicketColumn}
1632                        || $UserInfo{$TicketColumn}
1633                        || $CustomerInfo{$TicketColumn};
1634
1635                    # If value is in date format, change block type to 'Time' so it can be localized. See bug#14542.
1636                    if (
1637                        defined $DataValue
1638                        && $DataValue =~ /^\d\d\d\d-(\d|\d\d)-(\d|\d\d)\s(\d|\d\d):(\d|\d\d):(\d|\d\d)/
1639                        )
1640                    {
1641                        $BlockType = 'Time';
1642                    }
1643                }
1644
1645                $LayoutObject->Block(
1646                    Name => "RecordTicketColumn$BlockType",
1647                    Data => {
1648                        GenericValue => $DataValue || '-',
1649                        Class        => $CSSClass  || '',
1650                    },
1651                );
1652            }
1653
1654            # dynamic fields
1655            else {
1656
1657                # cycle trough the activated dynamic fields for this screen
1658
1659                my $DynamicFieldConfig;
1660                my $DFColumn = $TicketColumn;
1661                $DFColumn =~ s/DynamicField_//g;
1662                DYNAMICFIELD:
1663                for my $DFConfig ( @{ $Self->{DynamicField} } ) {
1664                    next DYNAMICFIELD if !IsHashRefWithData($DFConfig);
1665                    next DYNAMICFIELD if $DFConfig->{Name} ne $DFColumn;
1666
1667                    $DynamicFieldConfig = $DFConfig;
1668                    last DYNAMICFIELD;
1669                }
1670                next TICKETCOLUMN if !IsHashRefWithData($DynamicFieldConfig);
1671
1672                # get field value
1673                my $Value = $DynamicFieldBackendObject->ValueGet(
1674                    DynamicFieldConfig => $DynamicFieldConfig,
1675                    ObjectID           => $Article{TicketID},
1676                );
1677
1678                my $ValueStrg = $DynamicFieldBackendObject->DisplayValueRender(
1679                    DynamicFieldConfig => $DynamicFieldConfig,
1680                    Value              => $Value,
1681                    ValueMaxChars      => 20,
1682                    LayoutObject       => $LayoutObject,
1683                );
1684
1685                $LayoutObject->Block(
1686                    Name => 'RecordDynamicField',
1687                    Data => {
1688                        Value => $ValueStrg->{Value},
1689                        Title => $ValueStrg->{Title},
1690                    },
1691                );
1692
1693                if ( $ValueStrg->{Link} ) {
1694                    $LayoutObject->Block(
1695                        Name => 'RecordDynamicFieldLink',
1696                        Data => {
1697                            Value                       => $ValueStrg->{Value},
1698                            Title                       => $ValueStrg->{Title},
1699                            Link                        => $ValueStrg->{Link},
1700                            $DynamicFieldConfig->{Name} => $ValueStrg->{Title},
1701                        },
1702                    );
1703                }
1704                else {
1705                    $LayoutObject->Block(
1706                        Name => 'RecordDynamicFieldPlain',
1707                        Data => {
1708                            Value => $ValueStrg->{Value},
1709                            Title => $ValueStrg->{Title},
1710                        },
1711                    );
1712                }
1713
1714                # example of dynamic fields order customization
1715                $LayoutObject->Block(
1716                    Name => 'RecordDynamicField_' . $DynamicFieldConfig->{Name},
1717                    Data => {
1718                        Value => $ValueStrg->{Value},
1719                        Title => $ValueStrg->{Title},
1720                    },
1721                );
1722
1723                if ( $ValueStrg->{Link} ) {
1724                    $LayoutObject->Block(
1725                        Name => 'RecordDynamicField_' . $DynamicFieldConfig->{Name} . '_Link',
1726                        Data => {
1727                            Value                       => $ValueStrg->{Value},
1728                            Title                       => $ValueStrg->{Title},
1729                            Link                        => $ValueStrg->{Link},
1730                            $DynamicFieldConfig->{Name} => $ValueStrg->{Title},
1731                        },
1732                    );
1733                }
1734                else {
1735                    $LayoutObject->Block(
1736                        Name => 'RecordDynamicField_' . $DynamicFieldConfig->{Name} . '_Plain',
1737                        Data => {
1738                            Value => $ValueStrg->{Value},
1739                            Title => $ValueStrg->{Title},
1740                        },
1741                    );
1742                }
1743            }
1744        }
1745
1746        # add action items as js
1747        if ( $Article{ActionItems} ) {
1748
1749            # replace TT directives from string with values
1750            for my $ActionItem ( @{ $Article{ActionItems} } ) {
1751                $ActionItem->{Link} = $LayoutObject->Output(
1752                    Template => $ActionItem->{Link},
1753                    Data     => {
1754                        TicketID => $Article{TicketID},
1755                    },
1756                );
1757            }
1758
1759            $ActionRowTickets{ $Article{TicketID} } = $LayoutObject->JSONEncode( Data => $Article{ActionItems} );
1760        }
1761    }
1762
1763    # send data to JS
1764    $LayoutObject->AddJSData(
1765        Key   => 'ActionRowTickets',
1766        Value => \%ActionRowTickets,
1767    );
1768
1769    # set column filter form, to correctly fill the column filters is necessary to pass each
1770    #    overview some information in the AJAX call, for example the fixed Filters or NavBarFilters
1771    #    and also other values like the Queue in AgentTicketQueue, otherwise the filters will be
1772    #    filled with default restrictions, resulting in more options than the ones that the
1773    #    available tickets should provide, see Bug#9902
1774    if ( IsHashRefWithData( $Param{ColumnFilterForm} ) ) {
1775        $LayoutObject->Block(
1776            Name => 'DocumentColumnFilterForm',
1777            Data => {},
1778        );
1779
1780        # Add UseSubQueues param if available.
1781        if ( $Param{UseSubQueues} ) {
1782            $Param{ColumnFilterForm}->{UseSubQueues} = $Param{UseSubQueues};
1783        }
1784
1785        for my $Element ( sort keys %{ $Param{ColumnFilterForm} } ) {
1786            $LayoutObject->Block(
1787                Name => 'DocumentColumnFilterFormElement',
1788                Data => {
1789                    ElementName  => $Element,
1790                    ElementValue => $Param{ColumnFilterForm}->{$Element},
1791                },
1792            );
1793        }
1794    }
1795
1796    # use template
1797    my $Output = $LayoutObject->Output(
1798        TemplateFile => 'AgentTicketOverviewSmall',
1799        Data         => {
1800            %Param,
1801            Type => $Self->{ViewType},
1802        },
1803    );
1804
1805    return $Output;
1806}
1807
1808sub _GetColumnValues {
1809    my ( $Self, %Param ) = @_;
1810
1811    return if !IsStringWithData( $Param{HeaderColumn} );
1812
1813    my $HeaderColumn = $Param{HeaderColumn};
1814    my %ColumnFilterValues;
1815    my $TicketIDs;
1816
1817    if ( IsArrayRefWithData( $Param{OriginalTicketIDs} ) ) {
1818        $TicketIDs = $Param{OriginalTicketIDs};
1819    }
1820
1821    if ( $HeaderColumn !~ m/^DynamicField_/ ) {
1822        my $FunctionName = $HeaderColumn . 'FilterValuesGet';
1823        if ( $HeaderColumn eq 'CustomerID' ) {
1824            $FunctionName = 'CustomerFilterValuesGet';
1825        }
1826        $ColumnFilterValues{$HeaderColumn} = $Kernel::OM->Get('Kernel::System::Ticket::ColumnFilter')->$FunctionName(
1827            TicketIDs    => $TicketIDs,
1828            HeaderColumn => $HeaderColumn,
1829            UserID       => $Self->{UserID},
1830        );
1831    }
1832    else {
1833        DYNAMICFIELD:
1834        for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
1835            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
1836            my $FieldName = 'DynamicField_' . $DynamicFieldConfig->{Name};
1837            next DYNAMICFIELD if $FieldName ne $HeaderColumn;
1838
1839            # get dynamic field backend object
1840            my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
1841            my $IsFiltrable               = $DynamicFieldBackendObject->HasBehavior(
1842                DynamicFieldConfig => $DynamicFieldConfig,
1843                Behavior           => 'IsFiltrable',
1844            );
1845            next DYNAMICFIELD if !$IsFiltrable;
1846            $Self->{ValidFilterableColumns}->{$HeaderColumn} = $IsFiltrable;
1847            if ( IsArrayRefWithData($TicketIDs) ) {
1848
1849                # get the historical values for the field
1850                $ColumnFilterValues{$HeaderColumn} = $DynamicFieldBackendObject->ColumnFilterValuesGet(
1851                    DynamicFieldConfig => $DynamicFieldConfig,
1852                    LayoutObject       => $Kernel::OM->Get('Kernel::Output::HTML::Layout'),
1853                    TicketIDs          => $TicketIDs,
1854                );
1855            }
1856            else {
1857
1858                # get PossibleValues
1859                $ColumnFilterValues{$HeaderColumn} = $DynamicFieldBackendObject->PossibleValuesGet(
1860                    DynamicFieldConfig => $DynamicFieldConfig,
1861                );
1862            }
1863            last DYNAMICFIELD;
1864        }
1865    }
1866
1867    return \%ColumnFilterValues;
1868}
1869
1870sub _InitialColumnFilter {
1871    my ( $Self, %Param ) = @_;
1872
1873    return if !$Param{ColumnName};
1874    return if !$Self->{ValidFilterableColumns}->{ $Param{ColumnName} };
1875
1876    # get layout object
1877    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
1878
1879    my $Label = $Param{Label} || $Param{ColumnName};
1880    $Label = $LayoutObject->{LanguageObject}->Translate($Label);
1881
1882    # set fixed values
1883    my $Data = [
1884        {
1885            Key   => '',
1886            Value => uc $Label,
1887        },
1888    ];
1889
1890    # define if column filter values should be translatable
1891    my $TranslationOption = 0;
1892
1893    if (
1894        $Param{ColumnName} eq 'State'
1895        || $Param{ColumnName} eq 'Lock'
1896        || $Param{ColumnName} eq 'Priority'
1897        )
1898    {
1899        $TranslationOption = 1;
1900    }
1901
1902    my $Class = 'ColumnFilter';
1903    if ( $Param{Css} ) {
1904        $Class .= ' ' . $Param{Css};
1905    }
1906
1907    # build select HTML
1908    my $ColumnFilterHTML = $LayoutObject->BuildSelection(
1909        Name        => 'ColumnFilter' . $Param{ColumnName},
1910        Data        => $Data,
1911        Class       => $Class,
1912        Translation => $TranslationOption,
1913        SelectedID  => '',
1914    );
1915    return $ColumnFilterHTML;
1916}
1917
1918sub FilterContent {
1919    my ( $Self, %Param ) = @_;
1920
1921    return if !$Param{HeaderColumn};
1922
1923    my $HeaderColumn = $Param{HeaderColumn};
1924
1925    # get column values for to build the filters later
1926    my $ColumnValues = $Self->_GetColumnValues(
1927        OriginalTicketIDs => $Param{OriginalTicketIDs},
1928        HeaderColumn      => $HeaderColumn,
1929    );
1930
1931    my $SelectedValue  = '';
1932    my $SelectedColumn = $HeaderColumn;
1933    if ( $HeaderColumn eq 'CustomerUserID' ) {
1934        $SelectedColumn = 'CustomerUserLogin';
1935    }
1936    elsif ( $HeaderColumn eq 'CustomerID' ) {
1937        $SelectedColumn = 'CustomerID';
1938    }
1939    elsif ( $HeaderColumn !~ m{ \A DynamicField_ }xms ) {
1940        $SelectedColumn .= 'IDs';
1941    }
1942
1943    my $LabelColumn = $HeaderColumn;
1944    if ( $LabelColumn =~ m{ \A DynamicField_ }xms ) {
1945
1946        my $DynamicFieldConfig;
1947        $LabelColumn =~ s{\A DynamicField_ }{}xms;
1948
1949        DYNAMICFIELD:
1950        for my $DFConfig ( @{ $Self->{DynamicField} } ) {
1951            next DYNAMICFIELD if !IsHashRefWithData($DFConfig);
1952            next DYNAMICFIELD if $DFConfig->{Name} ne $LabelColumn;
1953
1954            $DynamicFieldConfig = $DFConfig;
1955            last DYNAMICFIELD;
1956        }
1957        if ( IsHashRefWithData($DynamicFieldConfig) ) {
1958            $LabelColumn = $DynamicFieldConfig->{Label};
1959        }
1960    }
1961
1962    if ( $SelectedColumn && $Self->{StoredFilters}->{$SelectedColumn} ) {
1963
1964        if ( IsArrayRefWithData( $Self->{StoredFilters}->{$SelectedColumn} ) ) {
1965            $SelectedValue = $Self->{StoredFilters}->{$SelectedColumn}->[0];
1966        }
1967        elsif ( IsHashRefWithData( $Self->{StoredFilters}->{$SelectedColumn} ) ) {
1968            $SelectedValue = $Self->{StoredFilters}->{$SelectedColumn}->{Equals};
1969        }
1970    }
1971
1972    # variable to save the filter's HTML code
1973    my $ColumnFilterJSON = $Self->_ColumnFilterJSON(
1974        ColumnName    => $HeaderColumn,
1975        Label         => $LabelColumn,
1976        ColumnValues  => $ColumnValues->{$HeaderColumn},
1977        SelectedValue => $SelectedValue,
1978    );
1979
1980    return $ColumnFilterJSON;
1981}
1982
1983# =head2 _ColumnFilterJSON()
1984
1985#     creates a JSON select filter for column header
1986
1987#     my $ColumnFilterJSON = $TicketOverviewSmallObject->_ColumnFilterJSON(
1988#         ColumnName => 'Queue',
1989#         Label      => 'Queue',
1990#         ColumnValues => {
1991#             1 => 'PostMaster',
1992#             2 => 'Junk',
1993#         },
1994#         SelectedValue '1',
1995#     );
1996
1997# =cut
1998
1999sub _ColumnFilterJSON {
2000    my ( $Self, %Param ) = @_;
2001
2002    if (
2003        !$Self->{AvailableFilterableColumns}->{ $Param{ColumnName} } &&
2004        !$Self->{AvailableFilterableColumns}->{ $Param{ColumnName} . 'IDs' }
2005        )
2006    {
2007        return;
2008    }
2009
2010    # get layout object
2011    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
2012
2013    my $Label = $Param{Label};
2014    $Label =~ s{ \A DynamicField_ }{}gxms;
2015    $Label = $LayoutObject->{LanguageObject}->Translate($Label);
2016
2017    # set fixed values
2018    my $Data = [
2019        {
2020            Key   => 'DeleteFilter',
2021            Value => uc $Label,
2022        },
2023        {
2024            Key      => '-',
2025            Value    => '-',
2026            Disabled => 1,
2027        },
2028    ];
2029
2030    if ( $Param{ColumnValues} && ref $Param{ColumnValues} eq 'HASH' ) {
2031
2032        my %Values = %{ $Param{ColumnValues} };
2033
2034        # Keys must be link encoded for dynamic fields because they are added to URL during filtering
2035        # and can contain characters like '&', ';', etc.
2036        # See bug#14497 - https://bugs.otrs.org/show_bug.cgi?id=14497.
2037        my $Encoding = ( $Param{ColumnName} =~ m/^DynamicField_/ ) ? 1 : 0;
2038
2039        # Set possible values.
2040        for my $ValueKey ( sort { lc $Values{$a} cmp lc $Values{$b} } keys %Values ) {
2041            push @{$Data}, {
2042                Key   => $Encoding ? $LayoutObject->LinkEncode($ValueKey) : $ValueKey,
2043                Value => $Values{$ValueKey},
2044            };
2045        }
2046    }
2047
2048    # define if column filter values should be translatable
2049    my $TranslationOption = 0;
2050
2051    if (
2052        $Param{ColumnName} eq 'State'
2053        || $Param{ColumnName} eq 'Lock'
2054        || $Param{ColumnName} eq 'Priority'
2055        )
2056    {
2057        $TranslationOption = 1;
2058    }
2059
2060    # build select HTML
2061    my $JSON = $LayoutObject->BuildSelectionJSON(
2062        [
2063            {
2064                Name         => 'ColumnFilter' . $Param{ColumnName},
2065                Data         => $Data,
2066                Class        => 'ColumnFilter',
2067                Sort         => 'AlphanumericKey',
2068                TreeView     => 1,
2069                SelectedID   => $Param{SelectedValue},
2070                Translation  => $TranslationOption,
2071                AutoComplete => 'off',
2072            },
2073        ],
2074    );
2075
2076    return $JSON;
2077}
2078
2079sub _DefaultColumnSort {
2080
2081    my %DefaultColumns = (
2082        TicketNumber           => 100,
2083        Age                    => 110,
2084        Changed                => 111,
2085        PendingTime            => 112,
2086        EscalationTime         => 113,
2087        EscalationSolutionTime => 114,
2088        EscalationResponseTime => 115,
2089        EscalationUpdateTime   => 116,
2090        Sender                 => 120,
2091        Title                  => 122,
2092        Subject                => 124,
2093        State                  => 130,
2094        Lock                   => 140,
2095        Queue                  => 150,
2096        Owner                  => 160,
2097        Responsible            => 161,
2098        CustomerID             => 170,
2099        CustomerName           => 171,
2100        CustomerUserID         => 172,
2101        Type                   => 180,
2102        Service                => 191,
2103        SLA                    => 192,
2104        Priority               => 193,
2105    );
2106
2107    # dynamic fields can not be on the DefaultColumns sorting hash
2108    # when comparing 2 dynamic fields sorting must be alphabetical
2109    if ( !$DefaultColumns{$a} && !$DefaultColumns{$b} ) {
2110        return $a cmp $b;
2111    }
2112
2113    # when a dynamic field is compared to a ticket attribute it must be higher
2114    elsif ( !$DefaultColumns{$a} ) {
2115        return 1;
2116    }
2117
2118    # when a ticket attribute is compared to a dynamic field it must be lower
2119    elsif ( !$DefaultColumns{$b} ) {
2120        return -1;
2121    }
2122
2123    # otherwise do a numerical comparison with the ticket attributes
2124    return $DefaultColumns{$a} <=> $DefaultColumns{$b};
2125}
2126
21271;
2128