Files
scripts/Perl OTRS/Kernel/Modules/AgentTimeAccountingReporting.pm
2024-10-14 00:08:40 +02:00

538 lines
18 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::Modules::AgentTimeAccountingReporting;
use strict;
use warnings;
use Kernel::Language qw(Translatable);
use Kernel::System::VariableCheck qw(:all);
our $ObjectManagerDisabled = 1;
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {%Param};
bless( $Self, $Type );
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
$Self->{TimeZone} = $Param{TimeZone}
|| $Param{UserTimeZone}
|| $DateTimeObject->OTRSTimeZoneGet();
return $Self;
}
sub Run {
my ( $Self, %Param ) = @_;
my @MonthArray = (
'', 'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October', 'November',
'December',
);
my @WeekdayArray = ( 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', );
# get needed objects
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
my $TimeAccountingObject = $Kernel::OM->Get('Kernel::System::TimeAccounting');
my $DateTimeObjectCurrent = $Kernel::OM->Create('Kernel::System::DateTime');
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
# ---------------------------------------------------------- #
# time accounting project reporting
# ---------------------------------------------------------- #
if ( $Self->{Subaction} eq 'ReportingProject' ) {
my $Config = $Kernel::OM->Get('Kernel::Config')->Get("TimeAccounting::Frontend::$Self->{Subaction}");
my %Frontend = ();
# permission check
if ( !$Self->{AccessRo} ) {
return $LayoutObject->NoPermission(
WithHeader => 'yes',
);
}
# get params
$Param{ProjectID} = $ParamObject->GetParam( Param => 'ProjectID' );
# check needed params
if ( !$Param{ProjectID} ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('ReportingProject: Need ProjectID')
);
}
my %Action = $TimeAccountingObject->ActionSettingsGet();
my %Project = $TimeAccountingObject->ProjectSettingsGet();
$Param{Project} = $Project{Project}->{ $Param{ProjectID} };
# get system users
my %ShownUsers = $UserObject->UserList(
Type => 'Long',
Valid => 0
);
$Param{ShowOnlyActiveUsers} = $Config->{ShowOnlyActiveUsers};
if ( $Param{ShowOnlyActiveUsers} ) {
# get registered users
my %RegisteredUsers = $TimeAccountingObject->UserList();
# reduce shown users to only the ones that are registered in time accounting
%ShownUsers = map { $_ => $ShownUsers{$_} } keys %RegisteredUsers;
}
# necessary because the ProjectActionReporting is not reworked
my ( $Sec, $Min, $Hour, $CurrentDay, $Month, $Year ) = $TimeAccountingObject->SystemTime2Date(
SystemTime => $DateTimeObjectCurrent->ToEpoch(),
);
my %ProjectData = ();
my %ProjectTime = ();
my @UserWhiteList;
# Only one function should be enough
for my $UserID ( sort keys %ShownUsers ) {
# Overview per project and action
# REMARK: This is the wrong function to get this information
%ProjectData = $TimeAccountingObject->ProjectActionReporting(
Year => $Year,
Month => $Month,
UserID => $UserID,
);
if ( $ProjectData{ $Param{ProjectID} } ) {
my $UserTotalHoursInProject;
my $ActionsRef = $ProjectData{ $Param{ProjectID} }->{Actions};
for my $ActionID ( sort keys %{$ActionsRef} ) {
$ProjectTime{$ActionID}->{$UserID}->{Hours} = $ActionsRef->{$ActionID}->{Total};
# remember the sum of all hours of all tasks
$UserTotalHoursInProject += $ActionsRef->{$ActionID}->{Total} || 0;
}
# remember only the users that has been added hours to this project
if ( defined $UserTotalHoursInProject && $UserTotalHoursInProject > 0 ) {
push @UserWhiteList, $UserID;
}
}
}
if ( $Param{ShowOnlyActiveUsers} ) {
# reduce shown users to only the ones that are active in the project (by adding hours)
%ShownUsers = map { $_ => $ShownUsers{$_} } @UserWhiteList;
}
if ( !IsHashRefWithData( \%ShownUsers ) ) {
$LayoutObject->Block(
Name => 'NoUserDataFoundMsg',
Data => {},
);
}
else {
$LayoutObject->Block(
Name => 'UserTable',
Data => {},
);
# show the header line
for my $UserID ( sort { $ShownUsers{$a} cmp $ShownUsers{$b} } keys %ShownUsers ) {
$LayoutObject->Block(
Name => 'UserName',
Data => { User => $ShownUsers{$UserID} },
);
}
# better solution for sort actions necessary
my %NewAction = ();
for my $ActionID ( sort keys %ProjectTime ) {
$NewAction{$ActionID} = $Action{$ActionID}->{Action};
}
%Action = %NewAction;
# show the results
my %Total = ();
for my $ActionID ( sort { $Action{$a} cmp $Action{$b} } keys %Action ) {
my $TotalHours = 0;
$LayoutObject->Block(
Name => 'Action',
Data => {
Action => $Action{$ActionID},
},
);
for my $UserID ( sort { $ShownUsers{$a} cmp $ShownUsers{$b} } keys %ShownUsers ) {
$TotalHours += $ProjectTime{$ActionID}{$UserID}{Hours} || 0;
$Total{$UserID} += $ProjectTime{$ActionID}{$UserID}{Hours} || 0;
$LayoutObject->Block(
Name => 'User',
Data => {
Hours =>
sprintf( "%.2f", $ProjectTime{$ActionID}{$UserID}{Hours} || 0 ),
},
);
}
# Total
$LayoutObject->Block(
Name => 'User',
Data => {
Hours => sprintf( "%.2f", $TotalHours ),
},
);
}
$Param{TotalAll} = 0;
for my $UserID ( sort { $ShownUsers{$a} cmp $ShownUsers{$b} } keys %ShownUsers ) {
$Param{TotalAll} += $Total{$UserID};
$LayoutObject->Block(
Name => 'UserTotal',
Data => {
Total => sprintf( "%.2f", $Total{$UserID} ),
},
);
}
$LayoutObject->Block(
Name => 'UserTotalAll',
Data => {
TotalAll => sprintf( "%.2f", $Param{TotalAll} ),
},
);
}
my @ProjectHistoryArray = $TimeAccountingObject->ProjectHistory(
ProjectID => $Param{ProjectID},
);
if ( !IsArrayRefWithData( \@ProjectHistoryArray ) ) {
$LayoutObject->Block(
Name => 'NoProjectDataFoundMsg',
Data => {},
);
}
else {
$LayoutObject->Block(
Name => 'ProjectTable',
Data => {
%Param,
%Frontend
},
);
for my $Row (@ProjectHistoryArray) {
$LayoutObject->Block(
Name => 'Row',
Data => {
User => $Row->{User},
Action => $Row->{Action},
Remark => $Row->{Remark} || '--',
Period => sprintf( "%.2f", $Row->{Period} ),
Date => $Row->{Date},
},
);
}
# show the total sum of hours at the end of the history list
# I also can use $Param{TotalAll}
my $ProjectTotalHours = sprintf(
"%.2f",
$TimeAccountingObject->ProjectTotalHours(
ProjectID => $Param{ProjectID},
)
);
$LayoutObject->Block(
Name => 'HistoryTotal',
Data => {
HistoryTotal => $ProjectTotalHours || 0,
},
);
}
# build output
my $Output = $LayoutObject->Header(
Title => Translatable('Reporting Project'),
);
$Output .= $LayoutObject->NavigationBar();
$Output .= $LayoutObject->Output(
Data => {
%Param,
%Frontend,
},
TemplateFile => 'AgentTimeAccountingReportingProject',
);
$Output .= $LayoutObject->Footer();
return $Output;
}
# ---------------------------------------------------------- #
# time accounting reporting
# ---------------------------------------------------------- #
my %Frontend = ();
my %ShownUsers = $UserObject->UserList(
Type => 'Long',
Valid => 0
);
my ( $Sec, $Min, $Hour, $CurrentDay, $Month, $Year ) = $TimeAccountingObject->SystemTime2Date(
SystemTime => $DateTimeObjectCurrent->ToEpoch(),
);
# permission check
if ( !$Self->{AccessRw} ) {
return $LayoutObject->NoPermission(
WithHeader => 'yes',
);
}
for my $Parameter (qw(Status Month Year ProjectStatusShow)) {
$Param{$Parameter} = $ParamObject->GetParam( Param => $Parameter );
}
# Check Date
if ( !$Param{Year} || !$Param{Month} ) {
$Param{Year} = $Year;
$Param{Month} = $Month;
}
else {
$Param{Month} = sprintf( "%02d", $Param{Month} );
}
# store last screen
$Kernel::OM->Get('Kernel::System::AuthSession')->UpdateSessionID(
SessionID => $Self->{SessionID},
Key => 'LastScreen',
Value =>
"Action=$Self->{Action};Year=$Param{Year};Month=$Param{Month}",
);
$Param{Month_to_Text} = $MonthArray[ $Param{Month} ];
my %Month = ();
for my $ID ( 1 .. 12 ) {
$Month{ sprintf( "%02d", $ID ) } = $MonthArray[$ID];
}
$Frontend{MonthOption} = $LayoutObject->BuildSelection(
Data => \%Month,
SelectedID => $Param{Month} || '',
Name => 'Month',
Sort => 'NumericKey',
Translation => 1,
Title => $LayoutObject->{LanguageObject}->Translate("Month"),
);
my @Year = ( $Year - 4 .. $Year + 1 );
$Frontend{YearOption} = $LayoutObject->BuildSelection(
Data => \@Year,
SelectedID => $Param{Year} || '',
Name => 'Year',
Translation => 0,
Title => $LayoutObject->{LanguageObject}->Translate("Year"),
);
( $Param{YearBack}, $Param{MonthBack}, $Param{DayBack} )
= $TimeAccountingObject->AddDeltaYMD( $Param{Year}, $Param{Month}, 1, 0, -1, 0 );
( $Param{YearNext}, $Param{MonthNext}, $Param{DayNext} )
= $TimeAccountingObject->AddDeltaYMD( $Param{Year}, $Param{Month}, 1, 0, 1, 0 );
my %UserReport = $TimeAccountingObject->UserReporting(
Year => $Param{Year},
Month => $Param{Month},
UserID => $Param{UserID},
);
my %UserBasics = $TimeAccountingObject->UserList();
if ( !IsHashRefWithData( \%ShownUsers ) || !IsHashRefWithData( \%UserReport ) ) {
$LayoutObject->Block(
Name => 'NoUserDataFoundMsg',
Data => {},
);
}
else {
$LayoutObject->Block(
Name => 'UserTable',
Data => { %Param, %Frontend },
);
USERID:
for my $UserID ( sort { $ShownUsers{$a} cmp $ShownUsers{$b} } keys %ShownUsers ) {
next USERID if !$UserReport{$UserID};
for my $Parameter (
qw(LeaveDay Overtime WorkingHours Sick LeaveDayRemaining OvertimeTotal)
)
{
$Param{$Parameter} = sprintf( "%.2f", ( $UserReport{$UserID}{$Parameter} || 0 ) );
$Param{ 'Total' . $Parameter } += $Param{$Parameter};
}
# Show Overtime if allowed
if ( !$UserBasics{$UserID}{ShowOvertime} ) {
$Param{Overtime} = '';
$Param{OvertimeTotal} = '';
}
$Param{User} = $ShownUsers{$UserID};
$Param{UserID} = $UserID;
$LayoutObject->Block(
Name => 'User',
Data => { %Param, %Frontend },
);
}
for my $Parameter (
qw(TotalLeaveDay TotalOvertime TotalWorkingHours
TotalSick TotalLeaveDayRemaining TotalOvertimeTotal)
)
{
$Param{$Parameter} = sprintf( "%.2f", ( $Param{$Parameter} ) || 0 );
}
$LayoutObject->Block(
Name => 'UserGrandTotal',
Data => {%Param},
);
}
# show the report sort by projects
if ( !$Param{ProjectStatusShow} || $Param{ProjectStatusShow} eq 'valid' ) {
$Param{ProjectStatusShow} = 'all';
}
elsif ( $Param{ProjectStatusShow} eq 'all' ) {
$Param{ProjectStatusShow} = 'valid';
}
$Param{ShowProjects} = 'Show ' . $Param{ProjectStatusShow} . ' projects';
my %ProjectData = $TimeAccountingObject->ProjectActionReporting(
Year => $Param{Year},
Month => $Param{Month},
);
if ( !IsHashRefWithData( \%ProjectData ) ) {
$LayoutObject->Block(
Name => 'NoProjectDataFoundMsg',
Data => {},
);
$Param{ProjectStatusLinkClass} = 'Hidden';
}
else {
$LayoutObject->Block(
Name => 'ProjectTable',
Data => { %Param, %Frontend },
);
# REMARK: merge this project reporting list with the list in overview
PROJECTID:
for my $ProjectID (
sort { $ProjectData{$a}->{Name} cmp $ProjectData{$b}->{Name} }
keys %ProjectData
)
{
my $ProjectRef = $ProjectData{$ProjectID};
my $ActionsRef = $ProjectRef->{Actions};
$Param{Project} = '';
$Param{Status} = $ProjectRef->{Status} ? '' : 'passiv';
my $Total = 0;
my $TotalTotal = 0;
next PROJECTID if $Param{ProjectStatusShow} eq 'all' && $Param{Status};
for my $ActionID (
sort { $ActionsRef->{$a}->{Name} cmp $ActionsRef->{$b}->{Name} }
keys %{$ActionsRef}
)
{
my $ActionRef = $ActionsRef->{$ActionID};
$Param{ProjectID} = $ProjectID;
$Param{Action} = $ActionRef->{Name};
$Param{Hours} = sprintf( "%.2f", $ActionRef->{PerMonth} || 0 );
$Param{HoursTotal} = sprintf( "%.2f", $ActionRef->{Total} || 0 );
$Total += $Param{Hours};
$TotalTotal += $Param{HoursTotal};
$LayoutObject->Block(
Name => 'Action',
Data => {%Param},
);
if ( !$Param{Project} ) {
$Param{Project} = $ProjectRef->{Name};
my $ProjectDescription = $LayoutObject->Ascii2Html(
Text => $ProjectRef->{Description},
HTMLResultMode => 1,
NewLine => 50,
);
$LayoutObject->Block(
Name => 'Project',
Data => {
RowSpan => ( 1 + scalar keys %{$ActionsRef} ),
Status => $Param{Status},
ProjectDescription => $ProjectDescription,
Project => $ProjectRef->{Name},
ProjectID => $ProjectID,
},
);
}
}
$Param{Hours} = sprintf( "%.2f", $Total );
$Param{HoursTotal} = sprintf( "%.2f", $TotalTotal );
$Param{TotalHours} += $Total;
$Param{TotalHoursTotal} += $TotalTotal;
$LayoutObject->Block(
Name => 'ActionTotal',
Data => { %Param, %Frontend },
);
}
$Param{TotalHours} ||= 0;
$Param{TotalHoursTotal} ||= 0;
$Param{TotalHours} = sprintf( "%.2f", $Param{TotalHours} );
$Param{TotalHoursTotal} = sprintf( "%.2f", $Param{TotalHoursTotal} );
$LayoutObject->Block(
Name => 'ProjectGrandTotal',
Data => { %Param, %Frontend },
);
}
# build output
my $Output = $LayoutObject->Header(
Title => Translatable('Reporting'),
);
$Output .= $LayoutObject->NavigationBar();
$Output .= $LayoutObject->Output(
Data => { %Param, %Frontend },
TemplateFile => 'AgentTimeAccountingReporting'
);
$Output .= $LayoutObject->Footer();
return $Output;
}
1;