905 lines
27 KiB
Perl
905 lines
27 KiB
Perl
# --
|
|
# 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;
|