init III
This commit is contained in:
431
Perl OTRS/Kernel/System/Stats/Dynamic/ITSMChangeManagement.pm
Normal file
431
Perl OTRS/Kernel/System/Stats/Dynamic/ITSMChangeManagement.pm
Normal file
@@ -0,0 +1,431 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Dynamic::ITSMChangeManagement;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Kernel::System::VariableCheck qw(:all);
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::DynamicField',
|
||||
'Kernel::System::DynamicField::Backend',
|
||||
'Kernel::System::ITSMChange',
|
||||
'Kernel::System::Log',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
# get the dynamic fields for change object
|
||||
$Self->{DynamicField} = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
|
||||
Valid => 1,
|
||||
ObjectType => ['ITSMCHange'],
|
||||
);
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectName {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return 'ITSMChangeManagement';
|
||||
}
|
||||
|
||||
sub GetObjectBehaviours {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my %Behaviours = (
|
||||
ProvidesDashboardWidget => 1,
|
||||
);
|
||||
|
||||
return %Behaviours;
|
||||
}
|
||||
|
||||
sub GetObjectAttributes {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get change state list
|
||||
my $ChangeStates = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangePossibleStatesGet(
|
||||
UserID => 1,
|
||||
);
|
||||
my %ChangeStateList = map { $_->{Key} => $_->{Value} } @{$ChangeStates};
|
||||
|
||||
# get cip lists
|
||||
my $Categories = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangePossibleCIPGet(
|
||||
Type => 'Category',
|
||||
UserID => 1,
|
||||
);
|
||||
my %CategoryList = map { $_->{Key} => $_->{Value} } @{$Categories};
|
||||
|
||||
my $Impacts = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangePossibleCIPGet(
|
||||
Type => 'Impact',
|
||||
UserID => 1,
|
||||
);
|
||||
my %ImpactList = map { $_->{Key} => $_->{Value} } @{$Impacts};
|
||||
|
||||
my $Priorities = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangePossibleCIPGet(
|
||||
Type => 'Priority',
|
||||
UserID => 1,
|
||||
);
|
||||
my %PriorityList = map { $_->{Key} => $_->{Value} } @{$Priorities};
|
||||
|
||||
# get current time to fix bug#4870
|
||||
my $Today = $Kernel::OM->Create('Kernel::System::DateTime')->Format( Format => '%Y-%m-%d 23:59:59' );
|
||||
|
||||
my @ObjectAttributes = (
|
||||
{
|
||||
Name => 'Change State',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'ChangeStateIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%ChangeStateList,
|
||||
},
|
||||
{
|
||||
Name => 'Category',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CategoryIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%CategoryList,
|
||||
},
|
||||
{
|
||||
Name => 'Priority',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'PriorityIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%PriorityList,
|
||||
},
|
||||
{
|
||||
Name => 'Impact',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'ImpactIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%ImpactList,
|
||||
},
|
||||
{
|
||||
Name => 'Timeperiod',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'TimePeriod',
|
||||
TimePeriodFormat => 'DateInputFormat', # 'DateInputFormatLong',
|
||||
Block => 'Time',
|
||||
TimeStop => $Today,
|
||||
Values => {
|
||||
TimeStart => 'CreateTimeNewerDate',
|
||||
TimeStop => 'CreateTimeOlderDate',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
# get dynamic field backend object
|
||||
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
|
||||
|
||||
# cycle trough the activated Dynamic Fields for this screen
|
||||
DYNAMICFIELD:
|
||||
for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
|
||||
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
|
||||
|
||||
# skip all fields not designed to be supported by statistics
|
||||
my $IsStatsCondition = $DynamicFieldBackendObject->HasBehavior(
|
||||
DynamicFieldConfig => $DynamicFieldConfig,
|
||||
Behavior => 'IsStatsCondition',
|
||||
);
|
||||
|
||||
next DYNAMICFIELD if !$IsStatsCondition;
|
||||
|
||||
my $PossibleValuesFilter;
|
||||
|
||||
# get field html
|
||||
my $DynamicFieldStatsParameter = $DynamicFieldBackendObject->StatsFieldParameterBuild(
|
||||
DynamicFieldConfig => $DynamicFieldConfig,
|
||||
PossibleValuesFilter => $PossibleValuesFilter,
|
||||
);
|
||||
|
||||
if ( IsHashRefWithData($DynamicFieldStatsParameter) ) {
|
||||
|
||||
# backward compatibility
|
||||
if ( !$DynamicFieldStatsParameter->{Block} ) {
|
||||
$DynamicFieldStatsParameter->{Block} = 'InputField';
|
||||
if ( IsHashRefWithData( $DynamicFieldStatsParameter->{Values} ) ) {
|
||||
$DynamicFieldStatsParameter->{Block} = 'MultiSelectField';
|
||||
}
|
||||
}
|
||||
|
||||
if ( $DynamicFieldStatsParameter->{Block} eq 'Time' ) {
|
||||
|
||||
# create object attributes (date/time fields)
|
||||
my $TimePeriodFormat = $DynamicFieldStatsParameter->{TimePeriodFormat} || 'DateInputFormatLong';
|
||||
|
||||
my %ObjectAttribute = (
|
||||
Name => $DynamicFieldStatsParameter->{Name},
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => $DynamicFieldStatsParameter->{Element},
|
||||
TimePeriodFormat => $TimePeriodFormat,
|
||||
Block => $DynamicFieldStatsParameter->{Block},
|
||||
TimePeriodFormat => $TimePeriodFormat,
|
||||
Values => {
|
||||
TimeStart =>
|
||||
$DynamicFieldStatsParameter->{Element}
|
||||
. '_GreaterThanEquals',
|
||||
TimeStop =>
|
||||
$DynamicFieldStatsParameter->{Element}
|
||||
. '_SmallerThanEquals',
|
||||
},
|
||||
);
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
elsif ( $DynamicFieldStatsParameter->{Block} eq 'MultiSelectField' ) {
|
||||
|
||||
# create object attributes (multiple values)
|
||||
my %ObjectAttribute = (
|
||||
Name => $DynamicFieldStatsParameter->{Name},
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => $DynamicFieldStatsParameter->{Element},
|
||||
Block => $DynamicFieldStatsParameter->{Block},
|
||||
Values => $DynamicFieldStatsParameter->{Values},
|
||||
Translation => 0,
|
||||
IsDynamicField => 1,
|
||||
ShowAsTree => $DynamicFieldConfig->{Config}->{TreeView} || 0,
|
||||
);
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
else {
|
||||
|
||||
# create object attributes (text fields)
|
||||
my %ObjectAttribute = (
|
||||
Name => $DynamicFieldStatsParameter->{Name},
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => $DynamicFieldStatsParameter->{Element},
|
||||
Block => $DynamicFieldStatsParameter->{Block},
|
||||
);
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return @ObjectAttributes;
|
||||
}
|
||||
|
||||
sub GetStatElementPreview {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return int rand 50;
|
||||
}
|
||||
|
||||
sub GetStatElement {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get dynamic field backend object
|
||||
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
|
||||
|
||||
for my $ParameterName ( sort keys %Param ) {
|
||||
if (
|
||||
$ParameterName =~ m{ \A DynamicField_ ( [a-zA-Z\d]+ ) (?: _ ( [a-zA-Z\d]+ ) )? \z }xms
|
||||
)
|
||||
{
|
||||
my $FieldName = $1;
|
||||
my $Operator = $2;
|
||||
|
||||
# loop over the dynamic fields configured
|
||||
DYNAMICFIELD:
|
||||
for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
|
||||
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
|
||||
next DYNAMICFIELD if !$DynamicFieldConfig->{Name};
|
||||
|
||||
# skip all fields that do not match with current field name
|
||||
# without the 'DynamicField_' prefix
|
||||
next DYNAMICFIELD if $DynamicFieldConfig->{Name} ne $FieldName;
|
||||
|
||||
# skip all fields not designed to be supported by statistics
|
||||
my $IsStatsCondition = $DynamicFieldBackendObject->HasBehavior(
|
||||
DynamicFieldConfig => $DynamicFieldConfig,
|
||||
Behavior => 'IsStatsCondition',
|
||||
);
|
||||
|
||||
next DYNAMICFIELD if !$IsStatsCondition;
|
||||
|
||||
# get new search parameter
|
||||
my $DynamicFieldStatsSearchParameter = $DynamicFieldBackendObject->StatsSearchFieldParameterBuild(
|
||||
DynamicFieldConfig => $DynamicFieldConfig,
|
||||
Value => $Param{$ParameterName},
|
||||
Operator => $Operator,
|
||||
);
|
||||
|
||||
# add new search parameter
|
||||
if ( !IsHashRefWithData( $Param{"DynamicField_$FieldName"} ) ) {
|
||||
$Param{"DynamicField_$FieldName"} =
|
||||
$DynamicFieldStatsSearchParameter;
|
||||
}
|
||||
|
||||
# extend search parameter
|
||||
elsif ( IsHashRefWithData($DynamicFieldStatsSearchParameter) ) {
|
||||
$Param{"DynamicField_$FieldName"} = {
|
||||
%{ $Param{"DynamicField_$FieldName"} },
|
||||
%{$DynamicFieldStatsSearchParameter},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# search changes
|
||||
my $Count = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangeSearch(
|
||||
UserID => 1,
|
||||
Result => 'COUNT',
|
||||
Permission => 'ro',
|
||||
Limit => 100_000_000,
|
||||
%Param,
|
||||
);
|
||||
|
||||
return $Count;
|
||||
}
|
||||
|
||||
sub ExportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# wrap ids to used spelling
|
||||
for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) {
|
||||
ELEMENT:
|
||||
for my $Element ( @{ $Param{$Use} } ) {
|
||||
|
||||
next ELEMENT if !$Element;
|
||||
next ELEMENT if !$Element->{SelectedValues};
|
||||
|
||||
my $ElementName = $Element->{Element};
|
||||
my $Values = $Element->{SelectedValues};
|
||||
|
||||
if ( $ElementName eq 'ChangeStateIDs' ) {
|
||||
my $StateList = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangePossibleStatesGet( UserID => 1 );
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
STATE:
|
||||
for my $State ( @{$StateList} ) {
|
||||
next STATE if $ID->{Content} ne $State->{Key};
|
||||
$ID->{Content} = $State->{Value};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elsif (
|
||||
$ElementName eq 'CategoryIDs' || $ElementName eq 'ImpactIDs'
|
||||
|| $ElementName eq 'PriorityIDs'
|
||||
)
|
||||
{
|
||||
my ($Type) = $ElementName =~ m{ \A (.*?) IDs \z }xms;
|
||||
|
||||
my $CIPList = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangePossibleCIPGet(
|
||||
Type => $Type,
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
ELEMENT:
|
||||
for my $Element ( @{$CIPList} ) {
|
||||
next ELEMENT if $ID->{Content} ne $Element->{Key};
|
||||
$ID->{Content} = $Element->{Value};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
sub ImportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# wrap used spelling to ids
|
||||
for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) {
|
||||
ELEMENT:
|
||||
for my $Element ( @{ $Param{$Use} } ) {
|
||||
|
||||
next ELEMENT if !$Element;
|
||||
next ELEMENT if !$Element->{SelectedValues};
|
||||
|
||||
my $ElementName = $Element->{Element};
|
||||
my $Values = $Element->{SelectedValues};
|
||||
|
||||
if ( $ElementName eq 'ChangeStateIDs' ) {
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
my $ChangeStateID = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangeStateLookup(
|
||||
ChangeState => $ID->{Content},
|
||||
Cache => 1,
|
||||
);
|
||||
if ($ChangeStateID) {
|
||||
$ID->{Content} = $ChangeStateID;
|
||||
}
|
||||
else {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Import: Can't find state $ID->{Content}!"
|
||||
);
|
||||
$ID = undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# import wrapper for CIP
|
||||
for my $Type (qw(Category Impact Priority)) {
|
||||
if ( $ElementName eq $Type . 'IDs' ) {
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
my $CIPID = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangeCIPLookup(
|
||||
CIP => $ID->{Content},
|
||||
Type => $Type,
|
||||
);
|
||||
if ($CIPID) {
|
||||
$ID->{Content} = $CIPID;
|
||||
}
|
||||
else {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Import: Can't find $Type $ID->{Content}!"
|
||||
);
|
||||
$ID = undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,197 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Dynamic::ITSMChangeManagementChangesIncidents;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::ITSMChange',
|
||||
'Kernel::System::Ticket',
|
||||
'Kernel::System::Type',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectName {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return 'ITSMChangeManagementChangesIncidents';
|
||||
}
|
||||
|
||||
sub GetObjectBehaviours {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my %Behaviours = (
|
||||
ProvidesDashboardWidget => 1,
|
||||
);
|
||||
|
||||
return %Behaviours;
|
||||
}
|
||||
|
||||
sub GetObjectAttributes {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get list of ticket types
|
||||
my %Objects = $Kernel::OM->Get('Kernel::System::Type')->TypeList(
|
||||
Valid => 1,
|
||||
);
|
||||
$Objects{'-1'} = 'Changes';
|
||||
|
||||
# get current time to fix bug#4870
|
||||
my $Today = $Kernel::OM->Create('Kernel::System::DateTime')->Format( Format => '%Y-%m-%d 23:59:59' );
|
||||
|
||||
my @ObjectAttributes = (
|
||||
{
|
||||
Name => 'Objects',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Object',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%Objects,
|
||||
SelectedValues => [ keys %Objects ],
|
||||
},
|
||||
{
|
||||
Name => 'Timeperiod',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'TimePeriod',
|
||||
TimePeriodFormat => 'DateInputFormat', # 'DateInputFormatLong',
|
||||
Block => 'Time',
|
||||
TimeStop => $Today,
|
||||
Values => {
|
||||
TimeStart => 'CreateTimeNewerDate',
|
||||
TimeStop => 'CreateTimeOlderDate',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return @ObjectAttributes;
|
||||
}
|
||||
|
||||
sub GetStatElementPreview {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return int rand 50;
|
||||
}
|
||||
|
||||
sub GetStatElement {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# delete CreateTimeNewerData as we want to get *ALL* existing objects
|
||||
delete $Param{CreateTimeNewerDate};
|
||||
|
||||
# for tickets the search option is "TicketCreateTimeOlderDate"
|
||||
$Param{TicketCreateTimeOlderDate} = $Param{CreateTimeOlderDate};
|
||||
|
||||
# if this cell should be filled with number of changes
|
||||
if ( $Param{Object}->[0] == -1 ) {
|
||||
return $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangeSearch(
|
||||
UserID => 1,
|
||||
Result => 'COUNT',
|
||||
Permission => 'ro',
|
||||
Limit => 100_000_000,
|
||||
%Param,
|
||||
);
|
||||
}
|
||||
|
||||
# if this cell should be filled with number of tickets
|
||||
else {
|
||||
return $Kernel::OM->Get('Kernel::System::Ticket')->TicketSearch(
|
||||
UserID => 1,
|
||||
Result => 'COUNT',
|
||||
Permission => 'ro',
|
||||
Limit => 100_000_000,
|
||||
TypeIDs => [ $Param{Object}->[0] ],
|
||||
%Param,
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub ExportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get list of ticket types
|
||||
my %Objects = $Kernel::OM->Get('Kernel::System::Type')->TypeList( Valid => 1 );
|
||||
$Objects{'-1'} = 'Changes';
|
||||
|
||||
# wrap ids to used spelling
|
||||
for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) {
|
||||
ELEMENT:
|
||||
for my $Element ( @{ $Param{$Use} } ) {
|
||||
|
||||
next ELEMENT if !$Element;
|
||||
next ELEMENT if !$Element->{SelectedValues};
|
||||
|
||||
my $ElementName = $Element->{Element};
|
||||
my $Values = $Element->{SelectedValues};
|
||||
|
||||
if ( $ElementName eq 'Object' ) {
|
||||
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
$ID->{Content} = $Objects{ $ID->{Content} };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
sub ImportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get list of ticket types
|
||||
my %Objects = $Kernel::OM->Get('Kernel::System::Type')->TypeList( Valid => 1 );
|
||||
$Objects{'-1'} = 'Changes';
|
||||
|
||||
# wrap used spelling to ids
|
||||
for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) {
|
||||
ELEMENT:
|
||||
for my $Element ( @{ $Param{$Use} } ) {
|
||||
|
||||
next ELEMENT if !$Element;
|
||||
next ELEMENT if !$Element->{SelectedValues};
|
||||
|
||||
my $ElementName = $Element->{Element};
|
||||
my $Values = $Element->{SelectedValues};
|
||||
|
||||
if ( $ElementName eq 'Object' ) {
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
for my $Key ( sort keys %Objects ) {
|
||||
$ID->{Content} = $Key if $Objects{$Key} eq $ID->{Content};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,368 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Dynamic::ITSMChangeManagementChangesPerCIClasses;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::DB',
|
||||
'Kernel::System::GeneralCatalog',
|
||||
'Kernel::System::ITSMChange',
|
||||
'Kernel::System::LinkObject',
|
||||
'Kernel::System::Log',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectName {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return 'ITSMChangeManagementChangesPerCIClasses';
|
||||
}
|
||||
|
||||
sub GetObjectBehaviours {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my %Behaviours = (
|
||||
ProvidesDashboardWidget => 1,
|
||||
);
|
||||
|
||||
return %Behaviours;
|
||||
}
|
||||
|
||||
sub GetObjectAttributes {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get cip lists
|
||||
my $Categories = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangePossibleCIPGet(
|
||||
Type => 'Category',
|
||||
UserID => 1,
|
||||
);
|
||||
my %CategoryList = map { $_->{Key} => $_->{Value} } @{$Categories};
|
||||
|
||||
# get class list
|
||||
my $ClassList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
||||
Class => 'ITSM::ConfigItem::Class',
|
||||
);
|
||||
|
||||
# get deployment state list
|
||||
my $DeplStateList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
||||
Class => 'ITSM::ConfigItem::DeploymentState',
|
||||
);
|
||||
|
||||
# get incident state list
|
||||
my $InciStateList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
||||
Class => 'ITSM::Core::IncidentState',
|
||||
);
|
||||
|
||||
# get current time to fix bug#4870
|
||||
my $Today = $Kernel::OM->Create('Kernel::System::DateTime')->Format( Format => '%Y-%m-%d 23:59:59' );
|
||||
|
||||
my @ObjectAttributes = (
|
||||
{
|
||||
Name => 'ConfigItem Classes',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 0,
|
||||
Element => 'CIClassIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => $ClassList,
|
||||
},
|
||||
{
|
||||
Name => 'Category',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 0,
|
||||
Element => 'CategoryIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%CategoryList,
|
||||
},
|
||||
{
|
||||
Name => 'ConfigItem Status',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CIStateIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => $InciStateList,
|
||||
},
|
||||
{
|
||||
Name => 'Timeperiod',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'TimePeriod',
|
||||
TimePeriodFormat => 'DateInputFormat', # 'DateInputFormatLong',
|
||||
Block => 'Time',
|
||||
TimeStop => $Today,
|
||||
Values => {
|
||||
TimeStart => 'CreateTimeNewerDate',
|
||||
TimeStop => 'CreateTimeOlderDate',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return @ObjectAttributes;
|
||||
}
|
||||
|
||||
sub GetStatElementPreview {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return int rand 50;
|
||||
}
|
||||
|
||||
sub GetStatElement {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get object ids for change and config item
|
||||
my $ConfigItemObjectID = $Kernel::OM->Get('Kernel::System::LinkObject')->ObjectLookup(
|
||||
Name => 'ITSMConfigItem',
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
return if !$ConfigItemObjectID;
|
||||
|
||||
my $ChangeObjectID = $Kernel::OM->Get('Kernel::System::LinkObject')->ObjectLookup(
|
||||
Name => 'ITSMWorkOrder',
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
return if !$ChangeObjectID;
|
||||
|
||||
# get change id and config item id
|
||||
return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
||||
SQL => 'SELECT chi.id AS change_id, ci.id AS ci_id '
|
||||
. 'FROM change_item chi, change_workorder chw, link_relation lr, configitem ci '
|
||||
. 'WHERE chi.id = chw.change_id '
|
||||
. 'AND chi.category_id = ? '
|
||||
. 'AND ( '
|
||||
. '( '
|
||||
. 'chw.id = lr.target_key '
|
||||
. 'AND lr.target_object_id = ? '
|
||||
. 'AND lr.source_object_id = ? '
|
||||
. 'AND lr.source_key = ci.id '
|
||||
. 'AND ci.class_id = ? '
|
||||
. ') '
|
||||
. 'OR '
|
||||
. '( '
|
||||
. 'chw.id = lr.source_key '
|
||||
. 'AND lr.source_object_id = ? '
|
||||
. 'AND lr.target_object_id = ? '
|
||||
. 'AND lr.target_key = ci.id '
|
||||
. 'AND ci.class_id = ? '
|
||||
. ') '
|
||||
. ')',
|
||||
Bind => [
|
||||
\( $Param{CategoryIDs}->[0] ),
|
||||
\$ChangeObjectID,
|
||||
\$ConfigItemObjectID,
|
||||
\( $Param{CIClassIDs}->[0] ),
|
||||
\$ChangeObjectID,
|
||||
\$ConfigItemObjectID,
|
||||
\( $Param{CIClassIDs}->[0] ),
|
||||
],
|
||||
);
|
||||
|
||||
# fetch change and config item ids
|
||||
my @Matches;
|
||||
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
||||
push @Matches, \@Row;
|
||||
}
|
||||
|
||||
# check for each change if the config item is in appropriate status
|
||||
# if so, count the change
|
||||
my %ChangesAlreadyCounted;
|
||||
MATCH:
|
||||
for my $Match (@Matches) {
|
||||
next MATCH if $ChangesAlreadyCounted{ $Match->[0] };
|
||||
|
||||
# get current state of the config item
|
||||
next MATCH if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
||||
SQL => 'SELECT inci_state_id FROM configitem_version '
|
||||
. 'WHERE configitem_id = ? '
|
||||
. 'AND create_time >= ? AND create_time <= ?',
|
||||
Bind => [
|
||||
\( $Match->[1] ),
|
||||
\( $Param{CreateTimeNewerDate} ),
|
||||
\( $Param{CreateTimeOlderDate} ),
|
||||
],
|
||||
Limit => 1,
|
||||
);
|
||||
|
||||
# fetch current incident state
|
||||
my $IncidentStateID;
|
||||
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
||||
$IncidentStateID = $Row[0];
|
||||
}
|
||||
|
||||
next MATCH if !$IncidentStateID;
|
||||
|
||||
# check if user has selected this state
|
||||
my ($Found) = grep { $_ == $IncidentStateID } @{ $Param{CIStateIDs} };
|
||||
|
||||
next MATCH if !$Found;
|
||||
|
||||
$ChangesAlreadyCounted{ $Match->[0] }++;
|
||||
}
|
||||
|
||||
# return the number of changes
|
||||
my $Count = keys %ChangesAlreadyCounted;
|
||||
return $Count;
|
||||
}
|
||||
|
||||
sub ExportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get class list
|
||||
my $ClassList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
||||
Class => 'ITSM::ConfigItem::Class',
|
||||
);
|
||||
|
||||
# get incident state list
|
||||
my $InciStateList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
||||
Class => 'ITSM::Core::IncidentState',
|
||||
);
|
||||
|
||||
# wrap ids to used spelling
|
||||
for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) {
|
||||
ELEMENT:
|
||||
for my $Element ( @{ $Param{$Use} } ) {
|
||||
next ELEMENT if !$Element || !$Element->{SelectedValues};
|
||||
my $ElementName = $Element->{Element};
|
||||
my $Values = $Element->{SelectedValues};
|
||||
|
||||
if ( $ElementName eq 'CIStateIDs' ) {
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
$ID->{Content} = $InciStateList->{ $ID->{Content} };
|
||||
}
|
||||
}
|
||||
elsif ( $ElementName eq 'CIClassIDs' ) {
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
$ID->{Content} = $ClassList->{ $ID->{Content} };
|
||||
}
|
||||
}
|
||||
elsif ( $ElementName eq 'CategoryIDs' ) {
|
||||
|
||||
my $CIPList = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangePossibleCIPGet(
|
||||
Type => 'Category',
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
ELEMENT:
|
||||
for my $Element ( @{$CIPList} ) {
|
||||
next ELEMENT if $ID->{Content} ne $Element->{Key};
|
||||
$ID->{Content} = $Element->{Value};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
sub ImportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get class list
|
||||
my $ClassList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
||||
Class => 'ITSM::ConfigItem::Class',
|
||||
);
|
||||
|
||||
# get incident state list
|
||||
my $InciStateList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
||||
Class => 'ITSM::Core::IncidentState',
|
||||
);
|
||||
|
||||
# wrap used spelling to ids
|
||||
for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) {
|
||||
ELEMENT:
|
||||
for my $Element ( @{ $Param{$Use} } ) {
|
||||
next ELEMENT if !$Element || !$Element->{SelectedValues};
|
||||
my $ElementName = $Element->{Element};
|
||||
my $Values = $Element->{SelectedValues};
|
||||
|
||||
if ( $ElementName eq 'CIStateIDs' ) {
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
KEY:
|
||||
for my $Key ( sort keys %{$InciStateList} ) {
|
||||
if ( $ID->{Content} eq $InciStateList->{$Key} ) {
|
||||
$ID->{Content} = $Key;
|
||||
last KEY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ( $ElementName eq 'CIClassIDs' ) {
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
for my $Key ( sort keys %{$ClassList} ) {
|
||||
if ( $ID->{Content} eq $ClassList->{$Key} ) {
|
||||
$ID->{Content} = $Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# import wrapper for CIP
|
||||
for my $Type (qw(Category)) {
|
||||
if ( $ElementName eq $Type . 'IDs' ) {
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
my $CIPID = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangeCIPLookup(
|
||||
CIP => $ID->{Content},
|
||||
Type => $Type,
|
||||
);
|
||||
if ($CIPID) {
|
||||
$ID->{Content} = $CIPID;
|
||||
}
|
||||
else {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Import: Can' find $Type $ID->{Content}!"
|
||||
);
|
||||
$ID = undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,191 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Dynamic::ITSMChangeManagementHistory;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::ITSMChange',
|
||||
'Kernel::System::ITSMChange::History',
|
||||
'Kernel::System::Log',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectName {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return 'ITSMChangeManagementHistory';
|
||||
}
|
||||
|
||||
sub GetObjectBehaviours {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my %Behaviours = (
|
||||
ProvidesDashboardWidget => 1,
|
||||
);
|
||||
|
||||
return %Behaviours;
|
||||
}
|
||||
|
||||
sub GetObjectAttributes {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get change state list
|
||||
my $ChangeStates = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangePossibleStatesGet(
|
||||
UserID => 1,
|
||||
);
|
||||
my %ChangeStateList = map { $_->{Key} => $_->{Value} } @{$ChangeStates};
|
||||
|
||||
# get current time to fix bug#4870
|
||||
my $Today = $Kernel::OM->Create('Kernel::System::DateTime')->Format( Format => '%Y-%m-%d 23:59:59' );
|
||||
|
||||
my @ObjectAttributes = (
|
||||
{
|
||||
Name => 'Change State',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'NewValues',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%ChangeStateList,
|
||||
},
|
||||
{
|
||||
Name => 'Timeperiod',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'TimePeriod',
|
||||
TimePeriodFormat => 'DateInputFormat', # 'DateInputFormatLong',
|
||||
Block => 'Time',
|
||||
TimeStop => $Today,
|
||||
Values => {
|
||||
TimeStart => 'ChangeTimeNewerDate',
|
||||
TimeStop => 'ChangeTimeOlderDate',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return @ObjectAttributes;
|
||||
}
|
||||
|
||||
sub GetStatElementPreview {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return int rand 50;
|
||||
}
|
||||
|
||||
sub GetStatElement {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# search history
|
||||
my $IDs = $Kernel::OM->Get('Kernel::System::ITSMChange::History')->HistorySearch(
|
||||
UserID => 1,
|
||||
Type => 'Change',
|
||||
Attribute => 'ChangeStateID',
|
||||
Limit => 100_000_000,
|
||||
%Param,
|
||||
);
|
||||
|
||||
my @ChangeNumbers;
|
||||
if ( $IDs && ref $IDs eq 'ARRAY' ) {
|
||||
|
||||
ID:
|
||||
for my $ID ( @{$IDs} ) {
|
||||
my $Change = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangeGet(
|
||||
ChangeID => $ID,
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
next ID if !$Change;
|
||||
|
||||
push @ChangeNumbers, $Change->{ChangeNumber};
|
||||
}
|
||||
}
|
||||
|
||||
return join "\n", @ChangeNumbers;
|
||||
}
|
||||
|
||||
sub ExportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# wrap ids to used spelling
|
||||
for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) {
|
||||
ELEMENT:
|
||||
for my $Element ( @{ $Param{$Use} } ) {
|
||||
next ELEMENT if !$Element || !$Element->{SelectedValues};
|
||||
my $ElementName = $Element->{Element};
|
||||
my $Values = $Element->{SelectedValues};
|
||||
|
||||
if ( $ElementName eq 'NewValues' ) {
|
||||
my $StateList = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangePossibleStatesGet( UserID => 1 );
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
STATE:
|
||||
for my $State ( @{$StateList} ) {
|
||||
next STATE if $ID->{Content} ne $State->{Key};
|
||||
$ID->{Content} = $State->{Value};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
sub ImportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# wrap used spelling to ids
|
||||
for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) {
|
||||
ELEMENT:
|
||||
for my $Element ( @{ $Param{$Use} } ) {
|
||||
next ELEMENT if !$Element || !$Element->{SelectedValues};
|
||||
my $ElementName = $Element->{Element};
|
||||
my $Values = $Element->{SelectedValues};
|
||||
|
||||
if ( $ElementName eq 'NewValues' ) {
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
my $ChangeStateID = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangeStateLookup(
|
||||
ChangeState => $ID->{Content},
|
||||
Cache => 1,
|
||||
);
|
||||
if ($ChangeStateID) {
|
||||
$ID->{Content} = $ChangeStateID;
|
||||
}
|
||||
else {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Import: Can' find state $ID->{Content}!"
|
||||
);
|
||||
$ID = undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,199 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Dynamic::ITSMChangeManagementRfcRequester;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Config',
|
||||
'Kernel::System::CustomerUser',
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::Ticket',
|
||||
'Kernel::System::User',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectName {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return 'ITSMChangeManagementRfcRequester';
|
||||
}
|
||||
|
||||
sub GetObjectBehaviours {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my %Behaviours = (
|
||||
ProvidesDashboardWidget => 1,
|
||||
);
|
||||
|
||||
return %Behaviours;
|
||||
}
|
||||
|
||||
sub GetObjectAttributes {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $RfCTypes = $Kernel::OM->Get('Kernel::Config')->Get('ITSMChange::AddChangeLinkTicketTypes');
|
||||
|
||||
# get all rfcs
|
||||
my @TicketIDs = $Kernel::OM->Get('Kernel::System::Ticket')->TicketSearch(
|
||||
UserID => 1,
|
||||
Permission => 'ro',
|
||||
Limit => 100_000_000,
|
||||
Types => $RfCTypes,
|
||||
Result => 'ARRAY',
|
||||
);
|
||||
|
||||
# get all requester
|
||||
my %Requester;
|
||||
|
||||
TICKETID:
|
||||
for my $TicketID (@TicketIDs) {
|
||||
my %Ticket = $Kernel::OM->Get('Kernel::System::Ticket')->TicketGet(
|
||||
TicketID => $TicketID,
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
next TICKETID if !%Ticket;
|
||||
|
||||
if ( $Ticket{CustomerUserID} ) {
|
||||
my $CustomerUserID = $Ticket{CustomerUserID};
|
||||
|
||||
next TICKETID if $Requester{"customer_$CustomerUserID"};
|
||||
|
||||
my %CustomerUser = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerUserDataGet(
|
||||
User => $CustomerUserID,
|
||||
);
|
||||
|
||||
$Requester{"customer_$CustomerUserID"} = $CustomerUser{UserFullname};
|
||||
}
|
||||
else {
|
||||
my $OwnerID = $Ticket{OwnerID};
|
||||
|
||||
next TICKETID if $Requester{"agent_$OwnerID"};
|
||||
|
||||
my %User = $Kernel::OM->Get('Kernel::System::User')->GetUserData(
|
||||
UserID => $OwnerID,
|
||||
);
|
||||
|
||||
$Requester{"agent_$OwnerID"} = $User{UserFullname};
|
||||
}
|
||||
}
|
||||
|
||||
# get current time to fix bug#4870
|
||||
my $Today = $Kernel::OM->Create('Kernel::System::DateTime')->Format( Format => '%Y-%m-%d 23:59:59' );
|
||||
|
||||
my @ObjectAttributes = (
|
||||
{
|
||||
Name => 'Requester',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 0,
|
||||
SelectedValues => [ keys %Requester ],
|
||||
Element => 'Requester',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%Requester,
|
||||
},
|
||||
{
|
||||
Name => 'Timeperiod',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 0,
|
||||
Element => 'TimePeriod',
|
||||
TimePeriodFormat => 'DateInputFormat', # 'DateInputFormatLong',
|
||||
Block => 'Time',
|
||||
TimeStop => $Today,
|
||||
Values => {
|
||||
TimeStart => 'TicketCreateTimeNewerDate',
|
||||
TimeStop => 'TicketCreateTimeOlderDate',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return @ObjectAttributes;
|
||||
}
|
||||
|
||||
sub GetStatElementPreview {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return int rand 50;
|
||||
}
|
||||
|
||||
sub GetStatElement {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check what type of requester we have
|
||||
# ticket search criteria differ for agents and customers
|
||||
my $Type = '';
|
||||
my $ID;
|
||||
if ( $Param{Requester} && $Param{Requester}->[0] ) {
|
||||
( $Type, $ID ) = split /_/, $Param{Requester}->[0];
|
||||
my $Key = $Type eq 'agent' ? 'OwnerIDs' : 'CustomerUserLogin';
|
||||
$Param{$Key} = [$ID];
|
||||
}
|
||||
|
||||
# get ticket types that are handled as RfCs
|
||||
my $RfCTypes = $Kernel::OM->Get('Kernel::Config')->Get('ITSMChange::AddChangeLinkTicketTypes');
|
||||
|
||||
# search tickets
|
||||
my @TicketIDs = $Kernel::OM->Get('Kernel::System::Ticket')->TicketSearch(
|
||||
UserID => 1,
|
||||
Result => 'ARRAY',
|
||||
Permission => 'ro',
|
||||
Limit => 100_000_000,
|
||||
Types => $RfCTypes,
|
||||
%Param,
|
||||
);
|
||||
|
||||
# if this wants the number of RfCs for an agent we have to check
|
||||
# whether a customer id is in the ticket. The owner is *NOT* the
|
||||
# requester then.
|
||||
if ( $Type eq 'agent' ) {
|
||||
my $Count = 0;
|
||||
|
||||
TICKETID:
|
||||
for my $TicketID (@TicketIDs) {
|
||||
my %Ticket = $Kernel::OM->Get('Kernel::System::Ticket')->TicketGet(
|
||||
TicketID => $TicketID,
|
||||
);
|
||||
|
||||
next TICKETID if !%Ticket;
|
||||
next TICKETID if $Ticket{CustomerUserID};
|
||||
|
||||
$Count++;
|
||||
}
|
||||
|
||||
return $Count;
|
||||
}
|
||||
|
||||
return scalar @TicketIDs;
|
||||
}
|
||||
|
||||
sub ExportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
sub ImportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
1;
|
||||
320
Perl OTRS/Kernel/System/Stats/Dynamic/ITSMConfigItem.pm
Normal file
320
Perl OTRS/Kernel/System/Stats/Dynamic/ITSMConfigItem.pm
Normal file
@@ -0,0 +1,320 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Dynamic::ITSMConfigItem;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::System::GeneralCatalog',
|
||||
'Kernel::System::ITSMConfigItem',
|
||||
'Kernel::System::DateTime',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectName {
|
||||
my $Self = shift;
|
||||
|
||||
return 'ITSMConfigItem';
|
||||
}
|
||||
|
||||
sub GetObjectBehaviours {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my %Behaviours = (
|
||||
ProvidesDashboardWidget => 1,
|
||||
);
|
||||
|
||||
return %Behaviours;
|
||||
}
|
||||
|
||||
sub GetObjectAttributes {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get class list
|
||||
my $ClassList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
||||
Class => 'ITSM::ConfigItem::Class',
|
||||
);
|
||||
|
||||
# get deployment state list
|
||||
my $DeplStateList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
||||
Class => 'ITSM::ConfigItem::DeploymentState',
|
||||
);
|
||||
|
||||
# get incident state list
|
||||
my $InciStateList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
||||
Class => 'ITSM::Core::IncidentState',
|
||||
);
|
||||
|
||||
# get current time to fix bug#3830
|
||||
my $TimeStamp = $Kernel::OM->Create('Kernel::System::DateTime')->ToString();
|
||||
|
||||
# create object attribute array
|
||||
my @ObjectAttributes = (
|
||||
{
|
||||
Name => 'Class',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'ClassIDs',
|
||||
Block => 'MultiSelectField',
|
||||
LanguageTranslation => 0,
|
||||
Values => $ClassList,
|
||||
},
|
||||
{
|
||||
Name => 'Deployment State',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'DeplStateIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => $DeplStateList,
|
||||
},
|
||||
{
|
||||
Name => 'Incident State',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'InciStateIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => $InciStateList,
|
||||
},
|
||||
{
|
||||
Name => 'Number',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Number',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'Name',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Name',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'Create Time',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreateTime',
|
||||
TimePeriodFormat => 'DateInputFormat',
|
||||
Block => 'Time',
|
||||
Values => {
|
||||
TimeStart => 'ConfigItemCreateTimeNewerDate',
|
||||
TimeStop => 'ConfigItemCreateTimeOlderDate',
|
||||
},
|
||||
},
|
||||
{
|
||||
Name => 'Change Time',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'ChangeTime',
|
||||
TimePeriodFormat => 'DateInputFormat',
|
||||
Block => 'Time',
|
||||
TimeStop => $TimeStamp,
|
||||
Values => {
|
||||
TimeStart => 'ConfigItemChangeTimeNewerDate',
|
||||
TimeStop => 'ConfigItemChangeTimeOlderDate',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
# add the xml data
|
||||
CLASSID:
|
||||
for my $ClassID ( sort keys %{$ClassList} ) {
|
||||
|
||||
# get xml definition hash
|
||||
my $XMLDefinition = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->DefinitionGet(
|
||||
ClassID => $ClassID,
|
||||
);
|
||||
|
||||
next CLASSID if !$XMLDefinition->{DefinitionID};
|
||||
|
||||
$Self->_XMLAttributeAdd(
|
||||
ObjectAttributes => \@ObjectAttributes,
|
||||
XMLDefinition => $XMLDefinition->{DefinitionRef},
|
||||
Prefix => 'XML::' . $ClassID,
|
||||
PrefixName => $ClassList->{$ClassID},
|
||||
);
|
||||
}
|
||||
|
||||
return @ObjectAttributes;
|
||||
}
|
||||
|
||||
sub _XMLAttributeAdd {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return if !$Param{ObjectAttributes};
|
||||
return if !$Param{XMLDefinition};
|
||||
return if ref $Param{XMLDefinition} ne 'ARRAY';
|
||||
|
||||
if ( $Param{Prefix} ) {
|
||||
$Param{Prefix} .= '::';
|
||||
}
|
||||
if ( $Param{PrefixName} ) {
|
||||
$Param{PrefixName} .= '::';
|
||||
}
|
||||
|
||||
$Param{Level} ||= 0;
|
||||
$Param{Prefix} ||= '';
|
||||
$Param{PrefixName} ||= '';
|
||||
|
||||
ITEM:
|
||||
for my $Item ( @{ $Param{XMLDefinition} } ) {
|
||||
|
||||
next ITEM if !$Item->{Searchable} && !$Item->{Sub};
|
||||
|
||||
# create key and name
|
||||
my $Key = $Param{Prefix} . $Item->{Key};
|
||||
my $Name = $Param{PrefixName} . $Item->{Name};
|
||||
|
||||
# add attribute
|
||||
my $Attribute = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->XMLStatsAttributeCreate(
|
||||
Key => $Key,
|
||||
Item => $Item,
|
||||
Name => $Name,
|
||||
);
|
||||
|
||||
next ITEM if !$Attribute;
|
||||
next ITEM if ref $Attribute ne 'ARRAY';
|
||||
next ITEM if !scalar @{$Attribute};
|
||||
|
||||
# add attributes to object array
|
||||
push @{ $Param{ObjectAttributes} }, @{$Attribute};
|
||||
|
||||
next ITEM if !$Item->{Sub};
|
||||
|
||||
# start recursion, if "Sub" was found
|
||||
$Self->_XMLAttributeAdd(
|
||||
ObjectAttributes => $Param{ObjectAttributes},
|
||||
XMLDefinition => $Item->{Sub},
|
||||
Level => $Param{Level} + 1,
|
||||
Prefix => $Key,
|
||||
PrefixName => $Name,
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub GetStatElementPreview {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return ( int rand 500 ) + 1;
|
||||
}
|
||||
|
||||
sub GetStatElement {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# set limit
|
||||
$Param{Limit} = 1_000_000;
|
||||
|
||||
# extract all xml param keys from the param hash
|
||||
my @XMLParams = grep { $_ =~ m{\A XML::}xms } sort keys %Param;
|
||||
|
||||
if (@XMLParams) {
|
||||
return 'You must define a class in one axis.' if !$Param{ClassIDs};
|
||||
return 'You must define a class in one axis.' if ref $Param{ClassIDs} ne 'ARRAY';
|
||||
}
|
||||
|
||||
# to collect date fields separately
|
||||
my %XMLParamsDateFields;
|
||||
|
||||
my %XMLClassIDs;
|
||||
PARAMKEY:
|
||||
for my $ParamKey (@XMLParams) {
|
||||
|
||||
# extract search values
|
||||
my $SearchValues = $Param{$ParamKey};
|
||||
|
||||
# prepare param value
|
||||
if ( !ref $SearchValues ) {
|
||||
$SearchValues = [$SearchValues];
|
||||
}
|
||||
|
||||
next PARAMKEY if !@{$SearchValues};
|
||||
|
||||
# split param key
|
||||
my ( $ClassID, $SearchKey ) = $ParamKey =~ m{ \A XML:: ( \d+ ) :: (.+) \z }xms;
|
||||
|
||||
# prepare search key
|
||||
$SearchKey =~ s[ :: ]['}[%]{']xmsg;
|
||||
|
||||
# Add class id to xml class id hash
|
||||
$XMLClassIDs{$ClassID} = 1;
|
||||
|
||||
# collect date fields separately (e.g WarrantyExpirationDateNewerDate)
|
||||
if ( $SearchKey =~ m{ (.+) ( NewerDate | OlderDate ) \z }xms ) {
|
||||
$XMLParamsDateFields{$1}->{$2} = $SearchValues->[0];
|
||||
|
||||
next PARAMKEY;
|
||||
}
|
||||
|
||||
# create search hash
|
||||
my $SearchHash = {
|
||||
'[1]{\'Version\'}[1]{\'' . $SearchKey . '\'}[%]{\'Content\'}' => $SearchValues,
|
||||
};
|
||||
|
||||
push @{ $Param{What} }, $SearchHash;
|
||||
}
|
||||
|
||||
# build search hash for date fields
|
||||
for my $DateFieldName ( sort keys %XMLParamsDateFields ) {
|
||||
|
||||
my $SearchHash = {
|
||||
'[1]{\'Version\'}[1]{\'' . $DateFieldName . '\'}[%]{\'Content\'}' => {
|
||||
'-between' => [
|
||||
$XMLParamsDateFields{$DateFieldName}->{NewerDate},
|
||||
$XMLParamsDateFields{$DateFieldName}->{OlderDate},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
push @{ $Param{What} }, $SearchHash;
|
||||
}
|
||||
|
||||
if (%XMLClassIDs) {
|
||||
my @Exists = grep { $XMLClassIDs{$_} } @{ $Param{ClassIDs} };
|
||||
|
||||
return 0 if !@Exists;
|
||||
}
|
||||
|
||||
# start config item extended search
|
||||
my $ConfigItemIDs = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->ConfigItemSearchExtended(%Param);
|
||||
|
||||
return scalar @{$ConfigItemIDs};
|
||||
}
|
||||
|
||||
sub ExportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
sub ImportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,503 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Dynamic::ITSMTicketFirstLevelSolutionRate;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Kernel::System::VariableCheck qw(:all);
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Config',
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::DB',
|
||||
'Kernel::System::DynamicField',
|
||||
'Kernel::System::DynamicField::Backend',
|
||||
'Kernel::System::Priority',
|
||||
'Kernel::System::Queue',
|
||||
'Kernel::System::SLA',
|
||||
'Kernel::System::Service',
|
||||
'Kernel::System::State',
|
||||
'Kernel::System::Ticket',
|
||||
'Kernel::System::Ticket::Article',
|
||||
'Kernel::System::Type',
|
||||
'Kernel::System::User',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
$Self->{DBSlaveObject} = $Param{DBSlaveObject} || $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# get the dynamic fields for ticket object
|
||||
$Self->{DynamicField} = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
|
||||
Valid => 1,
|
||||
ObjectType => ['Ticket'],
|
||||
);
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectName {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return 'ITSMTicketFirstLevelSolutionRate';
|
||||
}
|
||||
|
||||
sub GetObjectBehaviours {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my %Behaviours = (
|
||||
ProvidesDashboardWidget => 1,
|
||||
);
|
||||
|
||||
return %Behaviours;
|
||||
}
|
||||
|
||||
sub GetObjectAttributes {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get user list
|
||||
my %UserList = $Kernel::OM->Get('Kernel::System::User')->UserList(
|
||||
Type => 'Long',
|
||||
Valid => 0,
|
||||
);
|
||||
|
||||
# get state list
|
||||
my %StateList = $Kernel::OM->Get('Kernel::System::State')->StateGetStatesByType(
|
||||
StateType => ['closed'],
|
||||
Result => 'HASH',
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
# get queue list
|
||||
my %QueueList = $Kernel::OM->Get('Kernel::System::Queue')->GetAllQueues();
|
||||
|
||||
# get priority list
|
||||
my %PriorityList = $Kernel::OM->Get('Kernel::System::Priority')->PriorityList(
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
# get current time to fix bug#3830
|
||||
my $Today = $Kernel::OM->Create('Kernel::System::DateTime')->Format( Format => '%Y-%m-%d 23:59:59' );
|
||||
|
||||
my @ObjectAttributes = (
|
||||
{
|
||||
Name => 'Queue',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'QueueIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%QueueList,
|
||||
},
|
||||
{
|
||||
Name => 'State',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'StateIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%StateList,
|
||||
},
|
||||
{
|
||||
Name => 'Priority',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'PriorityIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%PriorityList,
|
||||
},
|
||||
{
|
||||
Name => 'Created in Queue',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreatedQueueIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%QueueList,
|
||||
},
|
||||
{
|
||||
Name => 'Created Priority',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreatedPriorityIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%PriorityList,
|
||||
},
|
||||
{
|
||||
Name => 'Created State',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreatedStateIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%StateList,
|
||||
},
|
||||
{
|
||||
Name => 'Title',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Title',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'CustomerUserLogin',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CustomerUserLogin',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'From',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'From',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'To',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'To',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'Cc',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Cc',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'Subject',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Subject',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'Text',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Body',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'Create Time',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreateTime',
|
||||
TimePeriodFormat => 'DateInputFormat', # 'DateInputFormatLong',
|
||||
Block => 'Time',
|
||||
TimeStop => $Today,
|
||||
Values => {
|
||||
TimeStart => 'TicketCreateTimeNewerDate',
|
||||
TimeStop => 'TicketCreateTimeOlderDate',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if ( $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Service') ) {
|
||||
|
||||
# get service list
|
||||
my %Service = $Kernel::OM->Get('Kernel::System::Service')->ServiceList(
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
# get sla list
|
||||
my %SLA = $Kernel::OM->Get('Kernel::System::SLA')->SLAList(
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
my @ObjectAttributeAdd = (
|
||||
{
|
||||
Name => 'Service',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'ServiceIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%Service,
|
||||
},
|
||||
{
|
||||
Name => 'SLA',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'SLAIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%SLA,
|
||||
},
|
||||
);
|
||||
|
||||
unshift @ObjectAttributes, @ObjectAttributeAdd;
|
||||
}
|
||||
|
||||
if ( $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Type') ) {
|
||||
|
||||
# get ticket type list
|
||||
my %Type = $Kernel::OM->Get('Kernel::System::Type')->TypeList(
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
my %ObjectAttribute1 = (
|
||||
Name => 'Type',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'TypeIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%Type,
|
||||
);
|
||||
|
||||
unshift @ObjectAttributes, \%ObjectAttribute1;
|
||||
}
|
||||
|
||||
if ( $Kernel::OM->Get('Kernel::Config')->Get('Stats::UseAgentElementInStats') ) {
|
||||
|
||||
my @ObjectAttributeAdd = (
|
||||
{
|
||||
Name => 'Agent/Owner',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'OwnerIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%UserList,
|
||||
},
|
||||
{
|
||||
Name => 'Created by Agent/Owner',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreatedUserIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%UserList,
|
||||
},
|
||||
{
|
||||
Name => 'Responsible',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'ResponsibleIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%UserList,
|
||||
},
|
||||
);
|
||||
|
||||
push @ObjectAttributes, @ObjectAttributeAdd;
|
||||
}
|
||||
|
||||
if ( $Kernel::OM->Get('Kernel::Config')->Get('Stats::CustomerIDAsMultiSelect') ) {
|
||||
|
||||
# Get CustomerID
|
||||
# (This way also can be the solution for the CustomerUserID)
|
||||
$Self->{DBSlaveObject}->Prepare(
|
||||
SQL => 'SELECT DISTINCT customer_id FROM ticket',
|
||||
);
|
||||
|
||||
# fetch the result
|
||||
my %CustomerID;
|
||||
while ( my @Row = $Self->{DBSlaveObject}->FetchrowArray() ) {
|
||||
if ( $Row[0] ) {
|
||||
$CustomerID{ $Row[0] } = $Row[0];
|
||||
}
|
||||
}
|
||||
|
||||
my %ObjectAttribute = (
|
||||
Name => 'CustomerID',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CustomerID',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%CustomerID,
|
||||
);
|
||||
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
else {
|
||||
|
||||
my %ObjectAttribute = (
|
||||
Name => 'CustomerID',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CustomerID',
|
||||
Block => 'InputField',
|
||||
);
|
||||
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
|
||||
# cycle trough the activated Dynamic Fields for this screen
|
||||
DYNAMICFIELD:
|
||||
for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
|
||||
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
|
||||
|
||||
my $PossibleValuesFilter;
|
||||
|
||||
# set possible values filter from ACLs
|
||||
my $ACL = $Kernel::OM->Get('Kernel::System::Ticket')->TicketAcl(
|
||||
Action => 'AgentStats',
|
||||
Type => 'DynamicField_' . $DynamicFieldConfig->{Name},
|
||||
ReturnType => 'Ticket',
|
||||
ReturnSubType => 'DynamicField_' . $DynamicFieldConfig->{Name},
|
||||
Data => $DynamicFieldConfig->{Config}->{PossibleValues} || {},
|
||||
UserID => 1,
|
||||
);
|
||||
if ($ACL) {
|
||||
my %Filter = $Kernel::OM->Get('Kernel::System::Ticket')->TicketAclData();
|
||||
$PossibleValuesFilter = \%Filter;
|
||||
}
|
||||
|
||||
# get field html
|
||||
my $DynamicFieldStatsParameter
|
||||
= $Kernel::OM->Get('Kernel::System::DynamicField::Backend')->StatsFieldParameterBuild(
|
||||
DynamicFieldConfig => $DynamicFieldConfig,
|
||||
PossibleValuesFilter => $PossibleValuesFilter,
|
||||
);
|
||||
|
||||
if ( IsHashRefWithData($DynamicFieldStatsParameter) ) {
|
||||
if ( IsHashRefWithData( $DynamicFieldStatsParameter->{Values} ) ) {
|
||||
|
||||
my %ObjectAttribute = (
|
||||
Name => $DynamicFieldStatsParameter->{Name},
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => $DynamicFieldStatsParameter->{Element},
|
||||
Block => 'MultiSelectField',
|
||||
Values => $DynamicFieldStatsParameter->{Values},
|
||||
Translation => 0,
|
||||
);
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
else {
|
||||
my %ObjectAttribute = (
|
||||
Name => $DynamicFieldStatsParameter->{Name},
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => $DynamicFieldStatsParameter->{Element},
|
||||
Block => 'InputField',
|
||||
);
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return @ObjectAttributes;
|
||||
}
|
||||
|
||||
sub GetStatElementPreview {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return int rand 50;
|
||||
}
|
||||
|
||||
sub GetStatElement {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# use all closed stats if no states are given
|
||||
if ( !$Param{StateIDs} ) {
|
||||
$Param{StateType} = ['closed'];
|
||||
}
|
||||
|
||||
# start ticket search
|
||||
my @TicketSearchIDs = $Kernel::OM->Get('Kernel::System::Ticket')->TicketSearch(
|
||||
%Param,
|
||||
Result => 'ARRAY',
|
||||
Limit => 100_000_000,
|
||||
UserID => 1,
|
||||
Permission => 'ro',
|
||||
);
|
||||
|
||||
return 0 if !@TicketSearchIDs;
|
||||
|
||||
my $ArticleObject = $Kernel::OM->Get('Kernel::System::Ticket::Article');
|
||||
|
||||
my $FirstLevelSolutionTickets = 0;
|
||||
TICKETID:
|
||||
for my $TicketID (@TicketSearchIDs) {
|
||||
|
||||
my @Articles = $ArticleObject->ArticleList(
|
||||
TicketID => $TicketID,
|
||||
IsVisibleForCustomer => 1,
|
||||
);
|
||||
|
||||
next TICKETID if !@Articles;
|
||||
next TICKETID if scalar @Articles > 2;
|
||||
|
||||
# get sender type of first article
|
||||
my $SenderTypeFirstArticle = $ArticleObject->ArticleSenderTypeLookup(
|
||||
SenderTypeID => $Articles[0]->{SenderTypeID},
|
||||
);
|
||||
|
||||
next TICKETID if $SenderTypeFirstArticle eq 'system';
|
||||
|
||||
# if the ticket could be solved within the first contact
|
||||
if ( !$Articles[1] ) {
|
||||
$FirstLevelSolutionTickets++;
|
||||
next TICKETID;
|
||||
}
|
||||
|
||||
# noe we handle the case where the first article is from the customer
|
||||
next TICKETID if $SenderTypeFirstArticle ne 'customer';
|
||||
|
||||
# get sender type of second article
|
||||
my $SenderTypeSecondArticle = $ArticleObject->ArticleSenderTypeLookup(
|
||||
SenderTypeID => $Articles[1]->{SenderTypeID},
|
||||
);
|
||||
|
||||
# the scond article is from the agent
|
||||
next TICKETID if $SenderTypeSecondArticle ne 'agent';
|
||||
|
||||
$FirstLevelSolutionTickets++;
|
||||
}
|
||||
|
||||
return $FirstLevelSolutionTickets;
|
||||
}
|
||||
|
||||
sub ExportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
sub ImportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,684 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Dynamic::ITSMTicketSolutionTimeAverage;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Kernel::System::VariableCheck qw(:all);
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Config',
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::DB',
|
||||
'Kernel::System::DynamicField',
|
||||
'Kernel::System::DynamicField::Backend',
|
||||
'Kernel::System::Priority',
|
||||
'Kernel::System::Queue',
|
||||
'Kernel::System::SLA',
|
||||
'Kernel::System::Service',
|
||||
'Kernel::System::State',
|
||||
'Kernel::System::Ticket',
|
||||
'Kernel::System::Type',
|
||||
'Kernel::System::User',
|
||||
'Kernel::System::Stats',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
$Self->{DBSlaveObject} = $Param{DBSlaveObject} || $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# get the dynamic fields for ticket object
|
||||
$Self->{DynamicField} = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
|
||||
Valid => 1,
|
||||
ObjectType => ['Ticket'],
|
||||
);
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectName {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return 'ITSMTicketSolutionTimeAverage';
|
||||
}
|
||||
|
||||
sub GetObjectBehaviours {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my %Behaviours = (
|
||||
ProvidesDashboardWidget => 1,
|
||||
);
|
||||
|
||||
return %Behaviours;
|
||||
}
|
||||
|
||||
sub GetObjectAttributes {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get user list
|
||||
my %UserList = $Kernel::OM->Get('Kernel::System::User')->UserList(
|
||||
Type => 'Long',
|
||||
Valid => 0,
|
||||
);
|
||||
|
||||
# get state list
|
||||
my %StateList = $Kernel::OM->Get('Kernel::System::State')->StateGetStatesByType(
|
||||
StateType => ['closed'],
|
||||
Result => 'HASH',
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
# get queue list
|
||||
my %QueueList = $Kernel::OM->Get('Kernel::System::Queue')->GetAllQueues();
|
||||
|
||||
# get priority list
|
||||
my %PriorityList = $Kernel::OM->Get('Kernel::System::Priority')->PriorityList(
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
# get current time to fix bug#3830
|
||||
my $Today = $Kernel::OM->Create('Kernel::System::DateTime')->Format( Format => '%Y-%m-%d 23:59:59' );
|
||||
|
||||
my @ObjectAttributes = (
|
||||
{
|
||||
Name => 'Queue',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'QueueIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%QueueList,
|
||||
},
|
||||
{
|
||||
Name => 'State',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'StateIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%StateList,
|
||||
},
|
||||
{
|
||||
Name => 'Priority',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'PriorityIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%PriorityList,
|
||||
},
|
||||
{
|
||||
Name => 'Created in Queue',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreatedQueueIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%QueueList,
|
||||
},
|
||||
{
|
||||
Name => 'Created Priority',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreatedPriorityIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%PriorityList,
|
||||
},
|
||||
{
|
||||
Name => 'Created State',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreatedStateIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%StateList,
|
||||
},
|
||||
{
|
||||
Name => 'Title',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Title',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'CustomerUserLogin',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CustomerUserLogin',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'From',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'From',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'To',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'To',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'Cc',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Cc',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'Subject',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Subject',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'Text',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Body',
|
||||
Block => 'InputField',
|
||||
},
|
||||
{
|
||||
Name => 'Create Time',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreateTime',
|
||||
TimePeriodFormat => 'DateInputFormat', # 'DateInputFormatLong',
|
||||
Block => 'Time',
|
||||
TimeStop => $Today,
|
||||
Values => {
|
||||
TimeStart => 'TicketCreateTimeNewerDate',
|
||||
TimeStop => 'TicketCreateTimeOlderDate',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if ( $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Service') ) {
|
||||
|
||||
# get service list
|
||||
my %Service = $Kernel::OM->Get('Kernel::System::Service')->ServiceList(
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
# get sla list
|
||||
my %SLA = $Kernel::OM->Get('Kernel::System::SLA')->SLAList(
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
my @ObjectAttributeAdd = (
|
||||
{
|
||||
Name => 'Service',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'ServiceIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%Service,
|
||||
},
|
||||
{
|
||||
Name => 'SLA',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'SLAIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%SLA,
|
||||
},
|
||||
);
|
||||
|
||||
unshift @ObjectAttributes, @ObjectAttributeAdd;
|
||||
}
|
||||
|
||||
if ( $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Type') ) {
|
||||
|
||||
# get ticket type list
|
||||
my %Type = $Kernel::OM->Get('Kernel::System::Type')->TypeList(
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
my %ObjectAttribute1 = (
|
||||
Name => 'Type',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'TypeIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%Type,
|
||||
);
|
||||
|
||||
unshift @ObjectAttributes, \%ObjectAttribute1;
|
||||
}
|
||||
|
||||
if ( $Kernel::OM->Get('Kernel::Config')->Get('Stats::UseAgentElementInStats') ) {
|
||||
|
||||
my @ObjectAttributeAdd = (
|
||||
{
|
||||
Name => 'Agent/Owner',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'OwnerIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%UserList,
|
||||
},
|
||||
{
|
||||
Name => 'Created by Agent/Owner',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CreatedUserIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%UserList,
|
||||
},
|
||||
{
|
||||
Name => 'Responsible',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'ResponsibleIDs',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%UserList,
|
||||
},
|
||||
);
|
||||
|
||||
push @ObjectAttributes, @ObjectAttributeAdd;
|
||||
}
|
||||
|
||||
if ( $Kernel::OM->Get('Kernel::Config')->Get('Stats::CustomerIDAsMultiSelect') ) {
|
||||
|
||||
# Get CustomerID
|
||||
# (This way also can be the solution for the CustomerUserID)
|
||||
$Self->{DBSlaveObject}->Prepare(
|
||||
SQL => 'SELECT DISTINCT customer_id FROM ticket',
|
||||
);
|
||||
|
||||
# fetch the result
|
||||
my %CustomerID;
|
||||
while ( my @Row = $Self->{DBSlaveObject}->FetchrowArray() ) {
|
||||
if ( $Row[0] ) {
|
||||
$CustomerID{ $Row[0] } = $Row[0];
|
||||
}
|
||||
}
|
||||
|
||||
my %ObjectAttribute = (
|
||||
Name => 'CustomerID',
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CustomerID',
|
||||
Block => 'MultiSelectField',
|
||||
Values => \%CustomerID,
|
||||
);
|
||||
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
else {
|
||||
|
||||
my %ObjectAttribute = (
|
||||
Name => 'CustomerID',
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'CustomerID',
|
||||
Block => 'InputField',
|
||||
);
|
||||
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
|
||||
# cycle trough the activated Dynamic Fields for this screen
|
||||
DYNAMICFIELD:
|
||||
for my $DynamicFieldConfig ( @{ $Self->{DynamicField} } ) {
|
||||
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
|
||||
|
||||
my $PossibleValuesFilter;
|
||||
|
||||
# set possible values filter from ACLs
|
||||
my $ACL = $Kernel::OM->Get('Kernel::System::Ticket')->TicketAcl(
|
||||
Action => 'AgentStats',
|
||||
Type => 'DynamicField_' . $DynamicFieldConfig->{Name},
|
||||
ReturnType => 'Ticket',
|
||||
ReturnSubType => 'DynamicField_' . $DynamicFieldConfig->{Name},
|
||||
Data => $DynamicFieldConfig->{Config}->{PossibleValues} || {},
|
||||
UserID => 1,
|
||||
);
|
||||
if ($ACL) {
|
||||
my %Filter = $Kernel::OM->Get('Kernel::System::Ticket')->TicketAclData();
|
||||
$PossibleValuesFilter = \%Filter;
|
||||
}
|
||||
|
||||
# get field html
|
||||
my $DynamicFieldStatsParameter
|
||||
= $Kernel::OM->Get('Kernel::System::DynamicField::Backend')->StatsFieldParameterBuild(
|
||||
DynamicFieldConfig => $DynamicFieldConfig,
|
||||
PossibleValuesFilter => $PossibleValuesFilter,
|
||||
);
|
||||
|
||||
if ( IsHashRefWithData($DynamicFieldStatsParameter) ) {
|
||||
if ( IsHashRefWithData( $DynamicFieldStatsParameter->{Values} ) ) {
|
||||
|
||||
my %ObjectAttribute = (
|
||||
Name => $DynamicFieldStatsParameter->{Name},
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 1,
|
||||
Element => $DynamicFieldStatsParameter->{Element},
|
||||
Block => 'MultiSelectField',
|
||||
Values => $DynamicFieldStatsParameter->{Values},
|
||||
Translation => 0,
|
||||
);
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
else {
|
||||
my %ObjectAttribute = (
|
||||
Name => $DynamicFieldStatsParameter->{Name},
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => $DynamicFieldStatsParameter->{Element},
|
||||
Block => 'InputField',
|
||||
);
|
||||
push @ObjectAttributes, \%ObjectAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
return @ObjectAttributes;
|
||||
}
|
||||
|
||||
sub GetStatElementPreview {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return int rand 50;
|
||||
}
|
||||
|
||||
sub GetStatElement {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# use all closed stats if no states are given
|
||||
if ( !$Param{StateIDs} ) {
|
||||
$Param{StateType} = ['closed'];
|
||||
}
|
||||
|
||||
# start ticket search
|
||||
my @TicketSearchIDs = $Kernel::OM->Get('Kernel::System::Ticket')->TicketSearch(
|
||||
%Param,
|
||||
Result => 'ARRAY',
|
||||
Limit => 100_000_000,
|
||||
UserID => 1,
|
||||
Permission => 'ro',
|
||||
);
|
||||
|
||||
return '-' if !@TicketSearchIDs;
|
||||
|
||||
my $Time = 0;
|
||||
|
||||
TICKETID:
|
||||
for my $TicketID (@TicketSearchIDs) {
|
||||
|
||||
# get ticket data
|
||||
my $TicketData = $Self->_TicketDataGet(
|
||||
TicketID => $TicketID,
|
||||
);
|
||||
|
||||
return 'ERROR' if !%{$TicketData};
|
||||
|
||||
# get relevant ticket history
|
||||
my $HistoryData = $Self->_TicketHistoryDataGet(
|
||||
TicketID => $TicketID,
|
||||
);
|
||||
|
||||
return 'ERROR' if !$HistoryData;
|
||||
|
||||
# if ticket is closed in the ticket create mask
|
||||
if ( @{$HistoryData} == 1 ) {
|
||||
$Time += ( 3 * 60 );
|
||||
next TICKETID;
|
||||
}
|
||||
|
||||
my %Timespans;
|
||||
my $Counter = 0;
|
||||
|
||||
ENTRY:
|
||||
for my $Entry ( @{$HistoryData} ) {
|
||||
|
||||
if ( $Timespans{$Counter} ) {
|
||||
|
||||
next ENTRY if $Entry->{Viewable};
|
||||
|
||||
# set stop time
|
||||
$Timespans{$Counter}->{StopTime} = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
String => $Entry->{CreateTime},
|
||||
},
|
||||
)->ToEpoch();
|
||||
|
||||
$Counter++;
|
||||
}
|
||||
else {
|
||||
|
||||
next ENTRY if !$Entry->{Viewable};
|
||||
|
||||
# set start time
|
||||
$Timespans{$Counter}->{StartTime} = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
String => $Entry->{CreateTime},
|
||||
},
|
||||
)->ToEpoch();
|
||||
}
|
||||
}
|
||||
|
||||
# get calendar
|
||||
my $Calendar = $Self->_CalendarGet(
|
||||
TicketData => $TicketData,
|
||||
);
|
||||
|
||||
for my $Count ( sort keys %Timespans ) {
|
||||
|
||||
# extract timestamp
|
||||
my $Timespan = $Timespans{$Count};
|
||||
|
||||
$Timespan->{StopTime} ||= $Timespan->{StartTime} + ( 3 * 60 );
|
||||
|
||||
my $WorkingTimeStartDateTimeObject = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
Epoch => $Timespan->{StartTime},
|
||||
},
|
||||
);
|
||||
|
||||
my $WorkingTimeStopDateTimeObject = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
Epoch => $Timespan->{StopTime},
|
||||
},
|
||||
);
|
||||
|
||||
my $Delta = $WorkingTimeStartDateTimeObject->Delta(
|
||||
DateTimeObject => $WorkingTimeStopDateTimeObject,
|
||||
ForWorkingTime => 1,
|
||||
Calendar => $Calendar,
|
||||
);
|
||||
|
||||
$Time += $Delta->{AbsoluteSeconds};
|
||||
}
|
||||
}
|
||||
|
||||
my $TicketCount = @TicketSearchIDs;
|
||||
my $AverageTime = $Time / $TicketCount;
|
||||
|
||||
# translate seconds in a readable format
|
||||
my $Value = $Kernel::OM->Get('Kernel::System::Stats')->_HumanReadableAgeGet(
|
||||
Age => int $AverageTime,
|
||||
);
|
||||
|
||||
return $Value;
|
||||
}
|
||||
|
||||
sub _TicketDataGet {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return {} if !$Param{TicketID};
|
||||
|
||||
# ask database
|
||||
$Self->{DBSlaveObject}->Prepare(
|
||||
SQL => 'SELECT queue_id, sla_id, create_time
|
||||
FROM ticket
|
||||
WHERE id = ?',
|
||||
Bind => [ \$Param{TicketID} ],
|
||||
Limit => 1,
|
||||
);
|
||||
|
||||
# fetch the result
|
||||
my %TicketData;
|
||||
while ( my @Row = $Self->{DBSlaveObject}->FetchrowArray() ) {
|
||||
$TicketData{QueueID} = $Row[0];
|
||||
$TicketData{SLAID} = $Row[1];
|
||||
$TicketData{CreateTime} = $Row[2];
|
||||
}
|
||||
|
||||
return \%TicketData;
|
||||
}
|
||||
|
||||
sub _CalendarGet {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get config option
|
||||
$Self->{TicketServiceFeature} ||= $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Service');
|
||||
|
||||
my %EscalationData;
|
||||
if ( $Self->{TicketServiceFeature} && $Param{TicketData}->{SLAID} ) {
|
||||
%EscalationData = $Kernel::OM->Get('Kernel::System::SLA')->SLAGet(
|
||||
SLAID => $Param{TicketData}->{SLAID},
|
||||
UserID => 1,
|
||||
Cache => 1,
|
||||
);
|
||||
}
|
||||
else {
|
||||
%EscalationData = $Kernel::OM->Get('Kernel::System::Queue')->QueueGet(
|
||||
ID => $Param{TicketData}->{QueueID},
|
||||
UserID => 1,
|
||||
Cache => 1,
|
||||
);
|
||||
}
|
||||
|
||||
return $EscalationData{Calendar} || undef;
|
||||
}
|
||||
|
||||
sub _TicketHistoryDataGet {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return if !$Param{TicketID};
|
||||
|
||||
# get id of histoy type StateUpdate
|
||||
if ( !$Self->{StateUpdateID} ) {
|
||||
$Self->{StateUpdateID} = $Kernel::OM->Get('Kernel::System::Ticket')->HistoryTypeLookup(
|
||||
Type => 'StateUpdate',
|
||||
);
|
||||
}
|
||||
|
||||
# get id of histoy type NewTicket
|
||||
if ( !$Self->{NewTicketID} ) {
|
||||
$Self->{NewTicketID} = $Kernel::OM->Get('Kernel::System::Ticket')->HistoryTypeLookup(
|
||||
Type => 'NewTicket',
|
||||
);
|
||||
}
|
||||
|
||||
# get viewable state ids
|
||||
if ( !$Self->{ViewableStateIDs} ) {
|
||||
my @ViewableStateIDs = $Kernel::OM->Get('Kernel::System::State')->StateGetStatesByType(
|
||||
Type => 'Viewable',
|
||||
Result => 'ID',
|
||||
);
|
||||
|
||||
my %ViewableStateIDList;
|
||||
for my $StateID (@ViewableStateIDs) {
|
||||
$ViewableStateIDList{$StateID} = 1;
|
||||
}
|
||||
|
||||
$Self->{ViewableStateIDs} = \%ViewableStateIDList;
|
||||
}
|
||||
|
||||
# ask database
|
||||
$Self->{DBSlaveObject}->Prepare(
|
||||
SQL => 'SELECT state_id, create_time
|
||||
FROM ticket_history
|
||||
WHERE ticket_id = ?
|
||||
AND history_type_id IN ( ?, ? )
|
||||
ORDER BY create_time',
|
||||
Bind => [
|
||||
\$Param{TicketID},
|
||||
\$Self->{StateUpdateID},
|
||||
\$Self->{NewTicketID},
|
||||
],
|
||||
);
|
||||
|
||||
# fetch the result
|
||||
my @TicketHistoryList;
|
||||
while ( my @Row = $Self->{DBSlaveObject}->FetchrowArray() ) {
|
||||
|
||||
my %HistoryData;
|
||||
$HistoryData{StateID} = $Row[0];
|
||||
$HistoryData{CreateTime} = $Row[1];
|
||||
|
||||
push @TicketHistoryList, \%HistoryData;
|
||||
}
|
||||
|
||||
ENTRY:
|
||||
for my $Entry (@TicketHistoryList) {
|
||||
|
||||
$Entry->{Viewable} = 0;
|
||||
next ENTRY if !$Self->{ViewableStateIDs}->{ $Entry->{StateID} };
|
||||
$Entry->{Viewable} = 1;
|
||||
}
|
||||
|
||||
return \@TicketHistoryList;
|
||||
}
|
||||
|
||||
sub ExportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
sub ImportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
1;
|
||||
1024
Perl OTRS/Kernel/System/Stats/Dynamic/Ticket.pm
Normal file
1024
Perl OTRS/Kernel/System/Stats/Dynamic/Ticket.pm
Normal file
File diff suppressed because it is too large
Load Diff
1280
Perl OTRS/Kernel/System/Stats/Dynamic/TicketAccountedTime.pm
Normal file
1280
Perl OTRS/Kernel/System/Stats/Dynamic/TicketAccountedTime.pm
Normal file
File diff suppressed because it is too large
Load Diff
1993
Perl OTRS/Kernel/System/Stats/Dynamic/TicketList.pm
Normal file
1993
Perl OTRS/Kernel/System/Stats/Dynamic/TicketList.pm
Normal file
File diff suppressed because it is too large
Load Diff
1355
Perl OTRS/Kernel/System/Stats/Dynamic/TicketSolutionResponseTime.pm
Normal file
1355
Perl OTRS/Kernel/System/Stats/Dynamic/TicketSolutionResponseTime.pm
Normal file
File diff suppressed because it is too large
Load Diff
904
Perl OTRS/Kernel/System/Stats/Dynamic/TimeAccounting.pm
Normal file
904
Perl OTRS/Kernel/System/Stats/Dynamic/TimeAccounting.pm
Normal file
@@ -0,0 +1,904 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Dynamic::TimeAccounting;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Kernel::Language qw(Translatable);
|
||||
use Kernel::System::VariableCheck qw(IsArrayRefWithData);
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::System::Log',
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::TimeAccounting',
|
||||
'Kernel::System::User',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectName {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return 'TimeAccounting';
|
||||
}
|
||||
|
||||
sub GetObjectAttributes {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $DateTimeObjectCurrent = $Kernel::OM->Create('Kernel::System::DateTime');
|
||||
|
||||
# set predefined start time
|
||||
my $TimeStamp = $DateTimeObjectCurrent->ToEpoch();
|
||||
my ($Date) = split /\s+/, $TimeStamp;
|
||||
my $Today = sprintf "%s 23:59:59", $Date;
|
||||
|
||||
# get time accounting object
|
||||
my $TimeAccountingObject = $Kernel::OM->Get('Kernel::System::TimeAccounting');
|
||||
|
||||
# get project list
|
||||
my %ProjectList = $TimeAccountingObject->ProjectSettingsGet(
|
||||
Status => 'valid',
|
||||
);
|
||||
|
||||
# get action list
|
||||
my %ActionListSource = $TimeAccountingObject->ActionSettingsGet();
|
||||
my %ActionList;
|
||||
|
||||
for my $Action ( sort keys %ActionListSource ) {
|
||||
$ActionList{$Action} = $ActionListSource{$Action}->{Action};
|
||||
}
|
||||
|
||||
# get user list
|
||||
my %UserList = $Kernel::OM->Get('Kernel::System::User')->UserList(
|
||||
Type => 'Long',
|
||||
Valid => 0,
|
||||
);
|
||||
|
||||
my @Attributes = (
|
||||
{
|
||||
Name => Translatable('Project'),
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Project',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => $ProjectList{Project},
|
||||
},
|
||||
{
|
||||
Name => Translatable('User'),
|
||||
UseAsXvalue => 1,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'User',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%UserList,
|
||||
},
|
||||
{
|
||||
Name => Translatable('Sort sequence'),
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 1,
|
||||
UseAsRestriction => 0,
|
||||
Element => 'SortSequence',
|
||||
Block => 'SelectField',
|
||||
Translation => 1,
|
||||
Values => {
|
||||
Up => 'ascending',
|
||||
Down => 'descending',
|
||||
},
|
||||
},
|
||||
{
|
||||
Name => Translatable('Task'),
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'ProjectAction',
|
||||
Block => 'MultiSelectField',
|
||||
Translation => 0,
|
||||
Values => \%ActionList,
|
||||
},
|
||||
{
|
||||
Name => Translatable('Period'),
|
||||
UseAsXvalue => 0,
|
||||
UseAsValueSeries => 0,
|
||||
UseAsRestriction => 1,
|
||||
Element => 'Period',
|
||||
TimePeriodFormat => 'DateInputFormat', # 'DateInputFormatLong',
|
||||
Block => 'Time',
|
||||
Values => {
|
||||
TimeStart => 'TimeAccountingPeriodStart',
|
||||
TimeStop => 'TimeAccountingPeriodStop',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return @Attributes;
|
||||
}
|
||||
|
||||
sub GetHeaderLine {
|
||||
my ( $Self, %Param ) = @_;
|
||||
my @HeaderLine = ("");
|
||||
|
||||
# Users as X-value
|
||||
if ( $Param{XValue}->{Element} && $Param{XValue}->{Element} eq 'User' ) {
|
||||
|
||||
# user have been selected as x-value
|
||||
my @UserIDs = @{ $Param{XValue}->{SelectedValues} };
|
||||
|
||||
# get user object
|
||||
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
|
||||
|
||||
# iterate over selected users
|
||||
USERID:
|
||||
for my $UserID (@UserIDs) {
|
||||
my $UserName = $UserObject->UserName(
|
||||
UserID => $UserID,
|
||||
);
|
||||
|
||||
push @HeaderLine, $UserName;
|
||||
}
|
||||
}
|
||||
|
||||
# Projects as X-value
|
||||
else {
|
||||
# projects have been selected as x-value
|
||||
my @ProjectIDs = @{ $Param{XValue}->{SelectedValues} };
|
||||
|
||||
# get time accounting object
|
||||
my $TimeAccountingObject = $Kernel::OM->Get('Kernel::System::TimeAccounting');
|
||||
|
||||
# iterate over selected projects
|
||||
PROJECTID:
|
||||
for my $ProjectID (@ProjectIDs) {
|
||||
my %ProjectData = $TimeAccountingObject->ProjectGet(
|
||||
ID => $ProjectID,
|
||||
);
|
||||
|
||||
push @HeaderLine, $ProjectData{Project};
|
||||
}
|
||||
}
|
||||
|
||||
return \@HeaderLine;
|
||||
}
|
||||
|
||||
sub GetStatTable {
|
||||
my ( $Self, %Param ) = @_;
|
||||
my @StatArray;
|
||||
my @UserIDs;
|
||||
|
||||
# Users as X-value
|
||||
if ( $Param{XValue}->{Element} && $Param{XValue}->{Element} eq 'User' ) {
|
||||
|
||||
# user have been selected as x-value
|
||||
@UserIDs = @{ $Param{XValue}->{SelectedValues} };
|
||||
|
||||
# get stat data
|
||||
my $StatData = $Self->_GetStatData(
|
||||
Param => \%Param,
|
||||
UserIDs => \@UserIDs,
|
||||
);
|
||||
|
||||
# check stat data
|
||||
return if !$StatData;
|
||||
return if ref $StatData ne 'ARRAY';
|
||||
|
||||
my @RawStatArray = @{$StatData};
|
||||
return if !@RawStatArray;
|
||||
|
||||
# get time accounting object
|
||||
my $TimeAccountingObject = $Kernel::OM->Get('Kernel::System::TimeAccounting');
|
||||
|
||||
# get list of needed data
|
||||
my %ProjectData = $TimeAccountingObject->ProjectSettingsGet();
|
||||
my %ProjectList = %{ $ProjectData{Project} || {} };
|
||||
|
||||
my %ActionData = $TimeAccountingObject->ActionSettingsGet();
|
||||
my %ActionList = map { ( $_ => $ActionData{$_}->{Action} ) } keys %ActionData;
|
||||
|
||||
my @SortedProjectIDs = sort { $ProjectList{$a} cmp $ProjectList{$b} } keys %ProjectList;
|
||||
my @SortedActionIDs = sort { $ActionList{$a} cmp $ActionList{$b} } keys %ActionList;
|
||||
|
||||
# re-sort projects depending on selected sequence
|
||||
if (
|
||||
IsArrayRefWithData( $Param{ValueSeries} )
|
||||
&& $Param{ValueSeries}->[0]->{SelectedValues}->[0] eq 'Down'
|
||||
)
|
||||
{
|
||||
@SortedProjectIDs = reverse @SortedProjectIDs;
|
||||
}
|
||||
|
||||
# iterate over sorted project list
|
||||
SORTEDPROJECTID:
|
||||
for my $SortedProjectID (@SortedProjectIDs) {
|
||||
|
||||
# check for unselected projects
|
||||
if (
|
||||
$Param{Restrictions}->{Project}
|
||||
&& !grep { $_ == $SortedProjectID } @{ $Param{Restrictions}->{Project} || [] }
|
||||
)
|
||||
{
|
||||
next SORTEDPROJECTID;
|
||||
}
|
||||
|
||||
# get the current project data of current project
|
||||
my @ProjectStatData = grep { $_->{ProjectID} == $SortedProjectID } @RawStatArray;
|
||||
|
||||
# iterate over sorted action list
|
||||
SORTEDACTIONID:
|
||||
for my $SortedActionID (@SortedActionIDs) {
|
||||
|
||||
# check for unselected actions
|
||||
if (
|
||||
$Param{Restrictions}->{ProjectAction}
|
||||
&& !grep { $_ == $SortedActionID } @{ $Param{Restrictions}->{ProjectAction} || [] }
|
||||
)
|
||||
{
|
||||
next SORTEDACTIONID;
|
||||
}
|
||||
|
||||
# get the current action out of the current project
|
||||
my @ActionStatData = grep { $_->{ActionID} == $SortedActionID } @ProjectStatData;
|
||||
|
||||
my @RowData;
|
||||
|
||||
# add descriptive first column
|
||||
my $RowLabel = "$ProjectList{$SortedProjectID}::$ActionList{$SortedActionID}";
|
||||
push @RowData, $RowLabel;
|
||||
|
||||
# iterate over selected users
|
||||
USERID:
|
||||
for my $UserID (@UserIDs) {
|
||||
|
||||
# at least get '0' for user data
|
||||
my $UserPeriodSum = 0;
|
||||
|
||||
# iterate over period data of user
|
||||
for my $PeriodData ( grep { $_->{UserID} == $UserID } @ActionStatData ) {
|
||||
$UserPeriodSum += $PeriodData->{Period};
|
||||
}
|
||||
|
||||
# safe user data to row data
|
||||
push @RowData, $UserPeriodSum;
|
||||
}
|
||||
|
||||
# store current row to global stat array
|
||||
push @StatArray, \@RowData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Projects as X-value
|
||||
else {
|
||||
|
||||
# projects have been selected as x-value
|
||||
my @ProjectIDs = @{ $Param{XValue}->{SelectedValues} };
|
||||
|
||||
# get user object
|
||||
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
|
||||
|
||||
# we need to get all users
|
||||
my %UserIDs = $UserObject->UserList(
|
||||
Type => 'Short',
|
||||
Valid => 1,
|
||||
);
|
||||
|
||||
@UserIDs = keys %UserIDs;
|
||||
|
||||
# get calculated stats data
|
||||
my $StatData = $Self->_GetStatData(
|
||||
Param => \%Param,
|
||||
UserIDs => \@UserIDs,
|
||||
);
|
||||
|
||||
# check stat data
|
||||
return if !$StatData;
|
||||
return if ref $StatData ne 'ARRAY';
|
||||
|
||||
my @RawStatArray = @{$StatData};
|
||||
return if !@RawStatArray;
|
||||
|
||||
# get list of needed data
|
||||
my %UserList = $UserObject->UserList(
|
||||
Type => 'Long',
|
||||
Valid => 1,
|
||||
);
|
||||
|
||||
my @SortedUserIDs = sort { $UserList{$a} cmp $UserList{$b} } keys %UserList;
|
||||
|
||||
# re-sort users depending on selected sequence
|
||||
if (
|
||||
IsArrayRefWithData( $Param{ValueSeries} )
|
||||
&& $Param{ValueSeries}->[0]->{SelectedValues}->[0] eq 'Down'
|
||||
)
|
||||
{
|
||||
@SortedUserIDs = reverse @SortedUserIDs;
|
||||
}
|
||||
|
||||
# iterate over sorted user list
|
||||
SORTEDUSERID:
|
||||
for my $SortedUserID (@SortedUserIDs) {
|
||||
|
||||
# check for unselected users
|
||||
if (
|
||||
$Param{Restrictions}->{User}
|
||||
&& !grep { $_ == $SortedUserID } @{ $Param{Restrictions}->{User} || [] }
|
||||
)
|
||||
{
|
||||
next SORTEDUSERID;
|
||||
}
|
||||
|
||||
# get the current user data of current user
|
||||
my @UserStatData = grep { $_->{UserID} == $SortedUserID } @RawStatArray;
|
||||
|
||||
my @RowData;
|
||||
|
||||
# add descriptive first column
|
||||
my $RowLabel = $UserList{$SortedUserID};
|
||||
push @RowData, $RowLabel;
|
||||
|
||||
# iterate over selected projects
|
||||
PROJECTID:
|
||||
for my $ProjectID (@ProjectIDs) {
|
||||
|
||||
# at least get '0' for user data
|
||||
my $ProjectPeriodSum = 0;
|
||||
|
||||
# iterate over period data of user
|
||||
for my $PeriodData ( grep { $_->{ProjectID} == $ProjectID } @UserStatData ) {
|
||||
$ProjectPeriodSum += $PeriodData->{Period};
|
||||
}
|
||||
|
||||
# safe user data to row data
|
||||
push @RowData, $ProjectPeriodSum;
|
||||
}
|
||||
|
||||
# store current row to global stat array
|
||||
push @StatArray, \@RowData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return @StatArray;
|
||||
}
|
||||
|
||||
sub GetStatTablePreview {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my @StatArray;
|
||||
my @UserIDs;
|
||||
|
||||
# Users as X-value
|
||||
if ( $Param{XValue}->{Element} && $Param{XValue}->{Element} eq 'User' ) {
|
||||
|
||||
# user have been selected as x-value
|
||||
@UserIDs = @{ $Param{XValue}->{SelectedValues} };
|
||||
|
||||
# get time accounting object
|
||||
my $TimeAccountingObject = $Kernel::OM->Get('Kernel::System::TimeAccounting');
|
||||
|
||||
# get list of needed data
|
||||
my %ProjectData = $TimeAccountingObject->ProjectSettingsGet();
|
||||
my %ProjectList = %{ $ProjectData{Project} || {} };
|
||||
|
||||
my %ActionData = $TimeAccountingObject->ActionSettingsGet();
|
||||
my %ActionList = map { ( $_ => $ActionData{$_}->{Action} ) } keys %ActionData;
|
||||
|
||||
my @SortedProjectIDs = sort { $ProjectList{$a} cmp $ProjectList{$b} } keys %ProjectList;
|
||||
my @SortedActionIDs = sort { $ActionList{$a} cmp $ActionList{$b} } keys %ActionList;
|
||||
|
||||
# re-sort projects depending on selected sequence
|
||||
if (
|
||||
IsArrayRefWithData( $Param{ValueSeries} )
|
||||
&& $Param{ValueSeries}->[0]->{SelectedValues}->[0] eq 'Down'
|
||||
)
|
||||
{
|
||||
@SortedProjectIDs = reverse @SortedProjectIDs;
|
||||
}
|
||||
|
||||
# iterate over sorted project list
|
||||
SORTEDPROJECTID:
|
||||
for my $SortedProjectID (@SortedProjectIDs) {
|
||||
|
||||
# check for unselected projects
|
||||
if (
|
||||
$Param{Restrictions}->{Project}
|
||||
&& !grep { $_ == $SortedProjectID } @{ $Param{Restrictions}->{Project} || [] }
|
||||
)
|
||||
{
|
||||
next SORTEDPROJECTID;
|
||||
}
|
||||
|
||||
# iterate over sorted action list
|
||||
SORTEDACTIONID:
|
||||
for my $SortedActionID (@SortedActionIDs) {
|
||||
|
||||
# check for unselected actions
|
||||
if (
|
||||
$Param{Restrictions}->{ProjectAction}
|
||||
&& !grep { $_ == $SortedActionID } @{ $Param{Restrictions}->{ProjectAction} || [] }
|
||||
)
|
||||
{
|
||||
next SORTEDACTIONID;
|
||||
}
|
||||
|
||||
my @RowData;
|
||||
|
||||
# add descriptive first column
|
||||
my $RowLabel = "$ProjectList{$SortedProjectID}::$ActionList{$SortedActionID}";
|
||||
push @RowData, $RowLabel;
|
||||
|
||||
# iterate over selected users
|
||||
USERID:
|
||||
for my $UserID (@UserIDs) {
|
||||
|
||||
# safe user data to row data
|
||||
push @RowData, int rand 50;
|
||||
}
|
||||
|
||||
# store current row to global stat array
|
||||
push @StatArray, \@RowData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Projects as X-value
|
||||
else {
|
||||
|
||||
# projects have been selected as x-value
|
||||
my @ProjectIDs = @{ $Param{XValue}{SelectedValues} };
|
||||
|
||||
# get user object
|
||||
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
|
||||
|
||||
# we need to get all users
|
||||
my %UserIDs = $UserObject->UserList(
|
||||
Type => 'Short',
|
||||
Valid => 1,
|
||||
);
|
||||
|
||||
@UserIDs = keys %UserIDs;
|
||||
|
||||
# get list of needed data
|
||||
my %UserList = $UserObject->UserList(
|
||||
Type => 'Long',
|
||||
Valid => 1,
|
||||
);
|
||||
|
||||
my @SortedUserIDs = sort { $UserList{$a} cmp $UserList{$b} } keys %UserList;
|
||||
|
||||
# re-sort users depending on selected sequence
|
||||
if (
|
||||
IsArrayRefWithData( $Param{ValueSeries} )
|
||||
&& $Param{ValueSeries}->[0]->{SelectedValues}->[0] eq 'Down'
|
||||
)
|
||||
{
|
||||
@SortedUserIDs = reverse @SortedUserIDs;
|
||||
}
|
||||
|
||||
# iterate over sorted user list
|
||||
SORTEDUSERID:
|
||||
for my $SortedUserID (@SortedUserIDs) {
|
||||
|
||||
# check for unselected users
|
||||
if (
|
||||
$Param{Restrictions}->{User}
|
||||
&& !grep { $_ == $SortedUserID } @{ $Param{Restrictions}->{User} || [] }
|
||||
)
|
||||
{
|
||||
next SORTEDUSERID;
|
||||
}
|
||||
|
||||
my @RowData;
|
||||
|
||||
# add descriptive first column
|
||||
my $RowLabel = $UserList{$SortedUserID};
|
||||
push @RowData, $RowLabel;
|
||||
|
||||
# iterate over selected projects
|
||||
PROJECTID:
|
||||
for my $ProjectID (@ProjectIDs) {
|
||||
|
||||
# safe user data to row data
|
||||
push @RowData, int rand 50;
|
||||
}
|
||||
|
||||
# store current row to global stat array
|
||||
push @StatArray, \@RowData;
|
||||
}
|
||||
}
|
||||
|
||||
return @StatArray;
|
||||
}
|
||||
|
||||
sub ExportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get needed objects
|
||||
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
|
||||
my $TimeAccountingObject = $Kernel::OM->Get('Kernel::System::TimeAccounting');
|
||||
|
||||
# wrap ids to used spelling
|
||||
for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) {
|
||||
|
||||
ELEMENT:
|
||||
for my $Element ( @{ $Param{$Use} } ) {
|
||||
next ELEMENT if !$Element;
|
||||
next ELEMENT if !$Element->{SelectedValues};
|
||||
|
||||
my $ElementName = $Element->{Element};
|
||||
my $Values = $Element->{SelectedValues};
|
||||
|
||||
if ( $ElementName eq 'User' ) {
|
||||
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
$ID->{Content} = $UserObject->UserLookup(
|
||||
UserID => $ID->{Content}
|
||||
);
|
||||
}
|
||||
}
|
||||
elsif ( $ElementName eq 'Project' ) {
|
||||
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
my %TmpProjectData = $TimeAccountingObject->ProjectGet(
|
||||
ID => $ID->{Content}
|
||||
);
|
||||
$ID->{Content} = $TmpProjectData{Project};
|
||||
}
|
||||
}
|
||||
elsif ( $ElementName eq 'ProjectAction' ) {
|
||||
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
my %TmpActionData = $TimeAccountingObject->ActionGet(
|
||||
ID => $ID->{Content}
|
||||
);
|
||||
$ID->{Content} = $TmpActionData{Action};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
sub ImportWrapper {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get needed objects
|
||||
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
|
||||
my $LogObject = $Kernel::OM->Get('Kernel::System::Log');
|
||||
my $TimeAccountingObject = $Kernel::OM->Get('Kernel::System::TimeAccounting');
|
||||
|
||||
# wrap used spelling to ids
|
||||
for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) {
|
||||
ELEMENT:
|
||||
for my $Element ( @{ $Param{$Use} } ) {
|
||||
next ELEMENT if !$Element;
|
||||
next ELEMENT if !$Element->{SelectedValues};
|
||||
|
||||
my $ElementName = $Element->{Element};
|
||||
my $Values = $Element->{SelectedValues};
|
||||
|
||||
if ( $ElementName eq 'User' ) {
|
||||
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
my $UserID = $UserObject->UserLookup(
|
||||
UserLogin => $ID->{Content},
|
||||
);
|
||||
|
||||
if ($UserID) {
|
||||
$ID->{Content} = $UserID;
|
||||
}
|
||||
else {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => "Import: Can' find the user $ID->{Content}!"
|
||||
);
|
||||
$ID = undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ( $ElementName eq 'Project' ) {
|
||||
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
my %Project = $TimeAccountingObject->ProjectGet(
|
||||
Project => $ID->{Content},
|
||||
);
|
||||
if ( $Project{ID} ) {
|
||||
$ID->{Content} = $Project{ID};
|
||||
}
|
||||
else {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => "Import: Can' find project $ID->{Content}!"
|
||||
);
|
||||
$ID = undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ( $ElementName eq 'ProjectAction' ) {
|
||||
ID:
|
||||
for my $ID ( @{$Values} ) {
|
||||
next ID if !$ID;
|
||||
|
||||
my %Action = $TimeAccountingObject->ActionGet(
|
||||
Action => $ID->{Content},
|
||||
);
|
||||
if ( $Action{ID} ) {
|
||||
$ID->{Content} = $Action{ID};
|
||||
}
|
||||
else {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => "Import: Can' find action $ID->{Content}!"
|
||||
);
|
||||
$ID = undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return \%Param;
|
||||
}
|
||||
|
||||
sub GetExtendedTitle {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return if $Param{Restrictions}->{TimeAccountingPeriodStart} || $Param{Restrictions}->{TimeAccountingPeriodStop};
|
||||
|
||||
my %DateIndexToName = (
|
||||
'Second' => 0,
|
||||
'Minute' => 1,
|
||||
'Hour' => 2,
|
||||
'Day' => 3,
|
||||
'Month' => 4,
|
||||
'Year' => 5,
|
||||
);
|
||||
|
||||
my %PreviousMonthDates = $Self->_GetPreviousMonthDates(
|
||||
DateIndexToName => \%DateIndexToName,
|
||||
);
|
||||
|
||||
my $StartDate = sprintf "%04d-%02d-%02d 00:00:00", $PreviousMonthDates{NewStartDate}->[0],
|
||||
$PreviousMonthDates{NewStartDate}->[1], $PreviousMonthDates{NewStartDate}->[2];
|
||||
my $StopDate = sprintf "%04d-%02d-%02d 00:00:00", $PreviousMonthDates{NewStopDate}->[0],
|
||||
$PreviousMonthDates{NewStopDate}->[1], $PreviousMonthDates{NewStopDate}->[2];
|
||||
|
||||
return "$StartDate-$StopDate";
|
||||
}
|
||||
|
||||
sub _GetStatData {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my @Return;
|
||||
my @UserIDs = @{ $Param{UserIDs} || [] };
|
||||
|
||||
my %DateIndexToName = (
|
||||
'Second' => 0,
|
||||
'Minute' => 1,
|
||||
'Hour' => 2,
|
||||
'Day' => 3,
|
||||
'Month' => 4,
|
||||
'Year' => 5,
|
||||
);
|
||||
|
||||
# get time accounting object
|
||||
my $TimeAccountingObject = $Kernel::OM->Get('Kernel::System::TimeAccounting');
|
||||
|
||||
# looping over all or selected users
|
||||
for my $UserID (@UserIDs) {
|
||||
|
||||
my $StartDate;
|
||||
my $StopDate;
|
||||
|
||||
# check if time period has been selected
|
||||
if ( $Param{Param}->{Restrictions}->{TimeAccountingPeriodStart} ) {
|
||||
|
||||
# get UNIX time-stamp of start and end values
|
||||
$StartDate = $TimeAccountingObject->TimeStamp2SystemTime(
|
||||
String => $Param{Param}->{Restrictions}->{TimeAccountingPeriodStart},
|
||||
);
|
||||
$StopDate = $TimeAccountingObject->TimeStamp2SystemTime(
|
||||
String => $Param{Param}->{Restrictions}->{TimeAccountingPeriodStop},
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
||||
# IMPORTANT:
|
||||
# If no time period had been selected previous month will be used as period!
|
||||
my %PreviousMonthDates = $Self->_GetPreviousMonthDates(
|
||||
DateIndexToName => \%DateIndexToName,
|
||||
);
|
||||
|
||||
# Calculate UNIX timestamps for start and stop date.
|
||||
$StartDate = $TimeAccountingObject->Date2SystemTime(
|
||||
Year => $PreviousMonthDates{NewStartDate}->[0],
|
||||
Month => $PreviousMonthDates{NewStartDate}->[1],
|
||||
Day => $PreviousMonthDates{NewStartDate}->[2],
|
||||
Hour => 0,
|
||||
Minute => 0,
|
||||
Second => 0,
|
||||
);
|
||||
$StopDate = $TimeAccountingObject->Date2SystemTime(
|
||||
Year => $PreviousMonthDates{NewStopDate}->[0],
|
||||
Month => $PreviousMonthDates{NewStopDate}->[1],
|
||||
Day => $PreviousMonthDates{NewStopDate}->[2],
|
||||
Hour => 23,
|
||||
Minute => 59,
|
||||
Second => 59,
|
||||
);
|
||||
}
|
||||
|
||||
# calculate number of days within the given range
|
||||
my $Days = int( ( $StopDate - $StartDate ) / 86400 ) + 1;
|
||||
|
||||
DAY:
|
||||
for my $Day ( 0 .. $Days ) {
|
||||
|
||||
# get day relative to start date
|
||||
my $DateOfPeriod = $StartDate + $Day * 86400;
|
||||
|
||||
# get needed date values out of time-stamp
|
||||
my @DateValues = $TimeAccountingObject->SystemTime2Date(
|
||||
SystemTime => $DateOfPeriod,
|
||||
);
|
||||
|
||||
# get working unit for user and day
|
||||
my %WorkingUnit = $TimeAccountingObject->WorkingUnitsGet(
|
||||
Year => $DateValues[ $DateIndexToName{'Year'} ],
|
||||
Month => $DateValues[ $DateIndexToName{'Month'} ],
|
||||
Day => $DateValues[ $DateIndexToName{'Day'} ],
|
||||
UserID => $UserID,
|
||||
);
|
||||
|
||||
# extract detailed information
|
||||
my @DayWorkingUnits = @{ $WorkingUnit{WorkingUnits} || [] };
|
||||
|
||||
# check for project restrictions
|
||||
if (
|
||||
$Param{Param}->{Restrictions}->{Project}
|
||||
&& ref $Param{Param}->{Restrictions}->{Project} eq 'ARRAY'
|
||||
)
|
||||
{
|
||||
|
||||
# build matching hash for selected projects
|
||||
my %SelectedProjectIDs = map { ( $_ => 1 ) } @{ $Param{Param}->{Restrictions}->{Project} };
|
||||
|
||||
# filter only selected projects
|
||||
my @FilteredProjectWUs = grep {
|
||||
$SelectedProjectIDs{ $_->{ProjectID} }
|
||||
} @DayWorkingUnits;
|
||||
|
||||
@DayWorkingUnits = @FilteredProjectWUs;
|
||||
}
|
||||
|
||||
# check for task restrictions
|
||||
if (
|
||||
$Param{Param}->{Restrictions}->{ProjectAction}
|
||||
&& ref $Param{Param}->{Restrictions}->{ProjectAction} eq 'ARRAY'
|
||||
)
|
||||
{
|
||||
|
||||
# build matching hash for selected actions
|
||||
my %SelectedActionIDs = map { ( $_ => 1 ) } @{ $Param{Param}->{Restrictions}->{ProjectAction} };
|
||||
|
||||
# filter only selected actions
|
||||
my @FilteredActionWUs = grep { $SelectedActionIDs{ $_->{ActionID} } } @DayWorkingUnits;
|
||||
|
||||
@DayWorkingUnits = @FilteredActionWUs;
|
||||
}
|
||||
|
||||
# check for user restrictions
|
||||
if (
|
||||
$Param{Param}->{Restrictions}->{User}
|
||||
&& ref $Param{Param}->{Restrictions}->{User} eq 'ARRAY'
|
||||
)
|
||||
{
|
||||
|
||||
# build matching hash for selected actions
|
||||
my %SelectedUserIDs = map { ( $_ => 1 ) } @{ $Param{Param}->{Restrictions}->{User} };
|
||||
|
||||
# filter only selected actions
|
||||
my @FilteredUserWUs = grep { $SelectedUserIDs{ $_->{UserID} } } @DayWorkingUnits;
|
||||
|
||||
@DayWorkingUnits = @FilteredUserWUs;
|
||||
}
|
||||
|
||||
# do not store data if no data is available
|
||||
next DAY if !@DayWorkingUnits;
|
||||
|
||||
# add data to global result set
|
||||
push @Return, @DayWorkingUnits;
|
||||
}
|
||||
}
|
||||
|
||||
return \@Return;
|
||||
}
|
||||
|
||||
sub _GetPreviousMonthDates {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
if ( !$Param{DateIndexToName} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need DateIndexToName!",
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# get time accounting object
|
||||
my $TimeAccountingObject = $Kernel::OM->Get('Kernel::System::TimeAccounting');
|
||||
my $DateTimeObjectCurrent = $Kernel::OM->Create('Kernel::System::DateTime');
|
||||
|
||||
# Get current date values.
|
||||
my @CurrentDate = $TimeAccountingObject->SystemTime2Date(
|
||||
SystemTime => $DateTimeObjectCurrent->ToEpoch(),
|
||||
);
|
||||
|
||||
# Get first day of previous month.
|
||||
my @NewStartDate = $TimeAccountingObject->AddDeltaYMD(
|
||||
$CurrentDate[ $Param{DateIndexToName}->{'Year'} ],
|
||||
$CurrentDate[ $Param{DateIndexToName}->{'Month'} ],
|
||||
1,
|
||||
0,
|
||||
-1,
|
||||
0,
|
||||
);
|
||||
|
||||
# Get first day of next month relative to previous month.
|
||||
my @NewStopDate = $TimeAccountingObject->AddDeltaYMD(
|
||||
$NewStartDate[0],
|
||||
$NewStartDate[1],
|
||||
$NewStartDate[2],
|
||||
0,
|
||||
+1,
|
||||
0,
|
||||
);
|
||||
|
||||
# Get last of day previous month.
|
||||
@NewStopDate = $TimeAccountingObject->AddDeltaYMD(
|
||||
$NewStopDate[0],
|
||||
$NewStopDate[1],
|
||||
$NewStopDate[2],
|
||||
0,
|
||||
0,
|
||||
-1,
|
||||
);
|
||||
|
||||
return (
|
||||
NewStartDate => \@NewStartDate,
|
||||
NewStopDate => \@NewStopDate,
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
252
Perl OTRS/Kernel/System/Stats/Static/FAQAccess.pm
Normal file
252
Perl OTRS/Kernel/System/Stats/Static/FAQAccess.pm
Normal file
@@ -0,0 +1,252 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Static::FAQAccess;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Config',
|
||||
'Kernel::System::FAQ',
|
||||
'Kernel::System::Log',
|
||||
'Kernel::System::DateTime',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# Allocate new hash for object.
|
||||
my $Self = {%Param};
|
||||
bless( $Self, $Type );
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectBehaviours {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my %Behaviours = (
|
||||
ProvidesDashboardWidget => 0,
|
||||
);
|
||||
|
||||
return %Behaviours;
|
||||
}
|
||||
|
||||
sub Param {
|
||||
|
||||
my $Self = shift;
|
||||
|
||||
my @Params = ();
|
||||
|
||||
# Get current time.
|
||||
my $DateTimeObject = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
);
|
||||
my $DateTimeSettings = $DateTimeObject->Get();
|
||||
|
||||
my $D = sprintf( "%02d", $DateTimeSettings->{Day} );
|
||||
my $M = sprintf( "%02d", $DateTimeSettings->{Month} );
|
||||
my $Y = sprintf( "%02d", $DateTimeSettings->{Year} );
|
||||
|
||||
# Create possible time selections.
|
||||
my %Year = map { $_ => $_ } ( $Y - 10 .. $Y + 1 );
|
||||
my %Month = map { sprintf( "%02d", $_ ) => sprintf( "%02d", $_ ) } ( 1 .. 12 );
|
||||
my %Day = map { sprintf( "%02d", $_ ) => sprintf( "%02d", $_ ) } ( 1 .. 31 );
|
||||
|
||||
push @Params, {
|
||||
Frontend => 'Start day',
|
||||
Name => 'StartDay',
|
||||
Multiple => 0,
|
||||
Size => 0,
|
||||
SelectedID => '01',
|
||||
Data => {
|
||||
%Day,
|
||||
},
|
||||
};
|
||||
push @Params, {
|
||||
Frontend => 'Start month',
|
||||
Name => 'StartMonth',
|
||||
Multiple => 0,
|
||||
Size => 0,
|
||||
SelectedID => $M,
|
||||
Data => {
|
||||
%Month,
|
||||
},
|
||||
};
|
||||
push @Params, {
|
||||
Frontend => 'Start year',
|
||||
Name => 'StartYear',
|
||||
Multiple => 0,
|
||||
Size => 0,
|
||||
SelectedID => $Y,
|
||||
Data => {
|
||||
%Year,
|
||||
},
|
||||
};
|
||||
push @Params, {
|
||||
Frontend => 'End day',
|
||||
Name => 'EndDay',
|
||||
Multiple => 0,
|
||||
Size => 0,
|
||||
SelectedID => $D,
|
||||
Data => {
|
||||
%Day,
|
||||
},
|
||||
};
|
||||
push @Params, {
|
||||
Frontend => 'End month',
|
||||
Name => 'EndMonth',
|
||||
Multiple => 0,
|
||||
Size => 0,
|
||||
SelectedID => $M,
|
||||
Data => {
|
||||
%Month,
|
||||
},
|
||||
};
|
||||
push @Params, {
|
||||
Frontend => 'End year',
|
||||
Name => 'EndYear',
|
||||
Multiple => 0,
|
||||
Size => 0,
|
||||
SelectedID => $Y,
|
||||
Data => {
|
||||
%Year,
|
||||
},
|
||||
};
|
||||
|
||||
return @Params;
|
||||
}
|
||||
|
||||
sub Run {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# Check needed stuff.
|
||||
for my $ParamName (qw(StartYear StartMonth StartDay EndYear EndMonth EndDay)) {
|
||||
if ( !$Param{$ParamName} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $ParamName!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
my $DateTimeObjectStart = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
Year => $Param{StartYear},
|
||||
Month => $Param{StartMonth},
|
||||
Day => 1,
|
||||
TimeZone => 'floating',
|
||||
},
|
||||
);
|
||||
|
||||
my $LastDayOfMonthStart;
|
||||
if ( defined $DateTimeObjectStart ) {
|
||||
$LastDayOfMonthStart = $DateTimeObjectStart->LastDayOfMonthGet();
|
||||
}
|
||||
|
||||
# Correct start day of month if entered wrong by user.
|
||||
my $StartDay = sprintf( "%02d", $LastDayOfMonthStart );
|
||||
if ( $Param{StartDay} < $StartDay ) {
|
||||
$StartDay = $Param{StartDay};
|
||||
}
|
||||
|
||||
my $DateTimeObjectEnd = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
Year => $Param{EndYear},
|
||||
Month => $Param{EndMonth},
|
||||
Day => 1,
|
||||
TimeZone => 'floating',
|
||||
},
|
||||
);
|
||||
|
||||
my $LastDayOfMonthEnd;
|
||||
if ( defined $DateTimeObjectEnd ) {
|
||||
$LastDayOfMonthEnd = $DateTimeObjectEnd->LastDayOfMonthGet();
|
||||
}
|
||||
|
||||
# Correct end day of month if entered wrong by user.
|
||||
my $EndDay = sprintf( "%02d", $LastDayOfMonthEnd );
|
||||
if ( $Param{EndDay} < $EndDay ) {
|
||||
$EndDay = $Param{EndDay};
|
||||
}
|
||||
|
||||
# Set start and end date.
|
||||
my $StartDate = "$Param{StartYear}-$Param{StartMonth}-$StartDay 00:00:00";
|
||||
my $EndDate = "$Param{EndYear}-$Param{EndMonth}-$EndDay 23:59:59";
|
||||
|
||||
my $FAQObject = $Kernel::OM->Get('Kernel::System::FAQ');
|
||||
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
my $FAQTop10LimitConfig = $ConfigObject->Get('FAQ::Explorer::Top10::Limit');
|
||||
|
||||
# Get a count of all FAQ articles.
|
||||
my $Top10ItemIDsRef = $FAQObject->FAQTop10Get(
|
||||
Interface => 'internal',
|
||||
StartDate => $StartDate,
|
||||
EndDate => $EndDate,
|
||||
UserID => 1,
|
||||
Limit => $FAQTop10LimitConfig,
|
||||
) || [];
|
||||
|
||||
# Build result table.
|
||||
my @Data;
|
||||
for my $ItemIDRef ( @{$Top10ItemIDsRef} ) {
|
||||
|
||||
my %FAQData = $FAQObject->FAQGet(
|
||||
ItemID => $ItemIDRef->{ItemID},
|
||||
ItemFields => 0,
|
||||
UserID => 1,
|
||||
);
|
||||
|
||||
my $VoteData = $FAQObject->ItemVoteDataGet(
|
||||
ItemID => $ItemIDRef->{ItemID},
|
||||
UserID => 1,
|
||||
);
|
||||
my $VoteResult = sprintf(
|
||||
"%0."
|
||||
. $ConfigObject->Get(
|
||||
"FAQ::Explorer::ItemList::VotingResultDecimalPlaces"
|
||||
)
|
||||
. "f",
|
||||
$VoteData->{Result}
|
||||
|| 0
|
||||
);
|
||||
my $Votes = $VoteData->{Votes} || 0;
|
||||
|
||||
# Build table row.
|
||||
push @Data, [
|
||||
$FAQData{Number},
|
||||
$FAQData{Title},
|
||||
$ItemIDRef->{Count},
|
||||
$VoteResult,
|
||||
$Votes,
|
||||
];
|
||||
}
|
||||
|
||||
# Set report title.
|
||||
my $Title = "$Param{StartYear}-$Param{StartMonth}-$StartDay - $Param{EndYear}-$Param{EndMonth}-$EndDay";
|
||||
|
||||
# Table headlines.
|
||||
my @HeadData = (
|
||||
'FAQ #',
|
||||
'Title',
|
||||
'Count',
|
||||
'Vote Result',
|
||||
'Votes',
|
||||
);
|
||||
|
||||
my @Result = ( [$Title], [@HeadData], @Data );
|
||||
|
||||
return @Result;
|
||||
}
|
||||
|
||||
1;
|
||||
186
Perl OTRS/Kernel/System/Stats/Static/StateAction.pm
Normal file
186
Perl OTRS/Kernel/System/Stats/Static/StateAction.pm
Normal file
@@ -0,0 +1,186 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Stats::Static::StateAction;
|
||||
## nofilter(TidyAll::Plugin::OTRS::Perl::Time)
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Language',
|
||||
'Kernel::System::DB',
|
||||
'Kernel::System::DateTime',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub GetObjectBehaviours {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my %Behaviours = (
|
||||
ProvidesDashboardWidget => 1,
|
||||
);
|
||||
|
||||
return %Behaviours;
|
||||
}
|
||||
|
||||
sub Param {
|
||||
my $Self = shift;
|
||||
|
||||
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
|
||||
|
||||
# get one month before
|
||||
$DateTimeObject->Subtract( Months => 1 );
|
||||
my $DateTimeSettings = $DateTimeObject->Get();
|
||||
|
||||
# create possible time selections
|
||||
my %Year = map { $_ => $_; } ( $DateTimeSettings->{Year} - 10 .. $DateTimeSettings->{Year} );
|
||||
my %Month = map { $_ => sprintf( "%02d", $_ ); } ( 1 .. 12 );
|
||||
|
||||
my @Params = (
|
||||
{
|
||||
Frontend => 'Year',
|
||||
Name => 'Year',
|
||||
Multiple => 0,
|
||||
Size => 0,
|
||||
SelectedID => $DateTimeSettings->{Year},
|
||||
Data => \%Year,
|
||||
},
|
||||
{
|
||||
Frontend => 'Month',
|
||||
Name => 'Month',
|
||||
Multiple => 0,
|
||||
Size => 0,
|
||||
SelectedID => $DateTimeSettings->{Month},
|
||||
Data => \%Month,
|
||||
},
|
||||
);
|
||||
return @Params;
|
||||
}
|
||||
|
||||
sub Run {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return if !$Param{Year} || !$Param{Month};
|
||||
|
||||
# get language object
|
||||
my $LanguageObject = $Kernel::OM->Get('Kernel::Language');
|
||||
|
||||
my $Year = $Param{Year};
|
||||
my $Month = $Param{Month};
|
||||
|
||||
my %States = $Self->_GetHistoryTypes();
|
||||
my @PossibleStates;
|
||||
for my $StateID ( sort { $States{$a} cmp $States{$b} } keys %States ) {
|
||||
$States{$StateID} = $LanguageObject->Translate( $States{$StateID} );
|
||||
push @PossibleStates, $States{$StateID};
|
||||
}
|
||||
|
||||
# build x axis
|
||||
|
||||
# first take epoch for 12:00 on the 1st of given month
|
||||
my $DateTimeObject = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
Year => $Param{Year},
|
||||
Month => $Param{Month},
|
||||
Day => 1,
|
||||
Hour => 12,
|
||||
Minute => 0,
|
||||
Second => 0,
|
||||
},
|
||||
);
|
||||
my $DateTimeValues = $DateTimeObject->Get();
|
||||
|
||||
my @Data;
|
||||
my @Days = ();
|
||||
my %StateDate = ();
|
||||
|
||||
# execute for all days of this month
|
||||
while ( $DateTimeValues->{Month} == int $Param{Month} ) {
|
||||
|
||||
# x-label is of format 'Mon 1, Tue 2,' etc
|
||||
my $Text = $LanguageObject->Translate( $DateTimeValues->{DayAbbr} ) . ' ' . $DateTimeValues->{Day};
|
||||
|
||||
push @Days, $Text;
|
||||
my @Row = ();
|
||||
for my $StateID ( sort { $States{$a} cmp $States{$b} } keys %States ) {
|
||||
my $Count = $Self->_GetDBDataPerDay(
|
||||
Year => $Year,
|
||||
Month => $Month,
|
||||
Day => $DateTimeValues->{Day},
|
||||
StateID => $StateID,
|
||||
);
|
||||
push @Row, $Count;
|
||||
|
||||
$StateDate{$Text}->{$StateID} = ( $StateDate{$Text}->{$StateID} || 0 ) + $Count;
|
||||
}
|
||||
|
||||
# move to next day
|
||||
$DateTimeObject->Add( Days => 1 );
|
||||
$DateTimeValues = $DateTimeObject->Get();
|
||||
}
|
||||
for my $StateID ( sort { $States{$a} cmp $States{$b} } keys %States ) {
|
||||
my @Row = ( $States{$StateID} );
|
||||
for my $Day (@Days) {
|
||||
my %Hash = %{ $StateDate{$Day} };
|
||||
push @Row, $Hash{$StateID};
|
||||
}
|
||||
push @Data, \@Row;
|
||||
}
|
||||
|
||||
my $Title = "$Year-$Month";
|
||||
return ( [$Title], [ $LanguageObject->Translate('Days'), @Days ], @Data );
|
||||
}
|
||||
|
||||
sub _GetHistoryTypes {
|
||||
my $Self = shift;
|
||||
|
||||
my $SQL = 'SELECT id, name FROM ticket_history_type WHERE valid_id = 1';
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
$DBObject->Prepare( SQL => $SQL );
|
||||
|
||||
my %Stats;
|
||||
while ( my @Row = $DBObject->FetchrowArray() ) {
|
||||
$Stats{ $Row[0] } = $Row[1];
|
||||
}
|
||||
|
||||
return %Stats;
|
||||
}
|
||||
|
||||
sub _GetDBDataPerDay {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $Start = "$Param{Year}-$Param{Month}-$Param{Day} 00:00:01";
|
||||
my $End = "$Param{Year}-$Param{Month}-$Param{Day} 23:59:59";
|
||||
my $SQL = 'SELECT count(*) FROM ticket_history '
|
||||
. 'WHERE history_type_id = ? AND create_time >= ? AND create_time <= ?';
|
||||
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
$DBObject->Prepare(
|
||||
SQL => $SQL,
|
||||
Bind => [ \$Param{StateID}, \$Start, \$End ]
|
||||
);
|
||||
|
||||
my $DayData = 0;
|
||||
while ( my @Row = $DBObject->FetchrowArray() ) {
|
||||
$DayData = $Row[0];
|
||||
}
|
||||
return $DayData;
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user