2543 lines
67 KiB
Perl
2543 lines
67 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::TimeAccounting;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Kernel::System::DateTime;
|
|
use Kernel::System::VariableCheck qw( :all );
|
|
|
|
our @ObjectDependencies = (
|
|
'Kernel::Config',
|
|
'Kernel::System::DB',
|
|
'Kernel::System::Log',
|
|
'Kernel::System::DateTime',
|
|
'Kernel::System::User',
|
|
);
|
|
|
|
=head1 NAME
|
|
|
|
Kernel::System::TimeAccounting - time accounting lib
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
All time accounting functions
|
|
|
|
=head1 PUBLIC INTERFACE
|
|
|
|
=head2 new()
|
|
|
|
create an object
|
|
|
|
use Kernel::System::ObjectManager;
|
|
local $Kernel::OM = Kernel::System::ObjectManager->new();
|
|
my $TimeAccountingObject = $Kernel::OM->Get('Kernel::System::TimeAccounting');
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my ( $Type, %Param ) = @_;
|
|
|
|
# allocate new hash for object
|
|
my $Self = {};
|
|
bless( $Self, $Type );
|
|
|
|
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
|
|
|
|
$Self->{TimeZone} = $Param{TimeZone}
|
|
|| $Param{UserTimeZone}
|
|
|| $DateTimeObject->OTRSTimeZoneGet();
|
|
|
|
return $Self;
|
|
}
|
|
|
|
=head2 UserCurrentPeriodGet()
|
|
|
|
returns a hash with the current period data of the specified user
|
|
|
|
my %UserData = $TimeAccountingObject->UserCurrentPeriodGet(
|
|
Year => '2005',
|
|
Month => '12',
|
|
Day => '24',
|
|
);
|
|
|
|
The returned hash contains the following elements:
|
|
|
|
%UserData = (
|
|
1 => {
|
|
UserID => 1,
|
|
Period => 123,
|
|
DateStart => '2005-12-24',
|
|
DateEnd => '2005-12-24',
|
|
WeeklyHours => 40.4,
|
|
LeaveDays => 12,
|
|
OverTime => 34,
|
|
},
|
|
);
|
|
|
|
=cut
|
|
|
|
sub UserCurrentPeriodGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed params
|
|
for my $NeededParam (qw(Year Month Day)) {
|
|
if ( !$Param{$NeededParam} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "UserCurrentPeriodGet: Need $NeededParam!",
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
# build date string for given params
|
|
my $Date = sprintf "%04d-%02d-%02d 00:00:00", $Param{Year}, $Param{Month}, $Param{Day};
|
|
|
|
# check cache
|
|
if ( $Self->{'Cache::UserCurrentPeriodGet'}{$Date} ) {
|
|
|
|
return %{ $Self->{'Cache::UserCurrentPeriodGet'}{$Date} };
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db select
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT user_id, preference_period, date_start, date_end, weekly_hours, leave_days,
|
|
overtime
|
|
FROM time_accounting_user_period
|
|
WHERE date_start <= ?
|
|
AND date_end >= ?
|
|
AND status = ?',
|
|
Bind => [ \$Date, \$Date, \1, ],
|
|
);
|
|
|
|
# fetch the data
|
|
my %Data;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
my $UserRef = {
|
|
UserID => $Row[0],
|
|
Period => $Row[1],
|
|
DateStart => substr( $Row[2], 0, 10 ),
|
|
DateEnd => substr( $Row[3], 0, 10 ),
|
|
WeeklyHours => $Row[4],
|
|
LeaveDays => $Row[5],
|
|
Overtime => $Row[6],
|
|
};
|
|
$Data{ $Row[0] } = $UserRef;
|
|
}
|
|
|
|
# check for valid user data
|
|
return if !%Data;
|
|
|
|
# store user data in cache
|
|
$Self->{'Cache::UserCurrentPeriodGet'}{$Date} = \%Data;
|
|
|
|
return %Data;
|
|
}
|
|
|
|
=head2 UserReporting()
|
|
|
|
returns a hash with information about leave days, overtimes,
|
|
working hours etc. of all users
|
|
|
|
my %Data = $TimeAccountingObject->UserReporting(
|
|
Year => '2005',
|
|
Month => '12',
|
|
Day => '12', # Optional
|
|
);
|
|
|
|
=cut
|
|
|
|
sub UserReporting {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# get log object
|
|
my $LogObject = $Kernel::OM->Get('Kernel::System::Log');
|
|
|
|
# check needed params
|
|
for my $NeededParam (qw(Year Month Day)) {
|
|
if ( !$Param{$NeededParam} && $NeededParam ne 'Day' ) {
|
|
$LogObject->Log(
|
|
Priority => 'error',
|
|
Message => "UserReporting: Need $NeededParam!"
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
# check valid date values
|
|
my $DateTimeObject = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
Year => $Param{Year},
|
|
Month => $Param{Month},
|
|
Day => $Param{Day} || 1,
|
|
},
|
|
);
|
|
|
|
return if !$DateTimeObject;
|
|
|
|
# get days of month if not provided
|
|
my $LastDayOfMonth = $DateTimeObject->LastDayOfMonthGet();
|
|
$Param{Day} ||= $LastDayOfMonth->{Day};
|
|
|
|
my %UserCurrentPeriod = $Self->UserCurrentPeriodGet(%Param);
|
|
my $YearStart = 1970;
|
|
my $MonthStart = 1;
|
|
my $DayStart = 1;
|
|
my $YearEnd = $Param{Year};
|
|
my $MonthEnd = $Param{Month};
|
|
my $DayEnd = $Param{Day};
|
|
|
|
my %Data;
|
|
|
|
USERID:
|
|
for my $UserID ( sort keys %UserCurrentPeriod ) {
|
|
|
|
if ( $UserCurrentPeriod{$UserID}->{DateStart} =~ m{ \A (\d{4})-(\d{2})-(\d{2}) }xms ) {
|
|
$YearStart = $1;
|
|
$MonthStart = $2;
|
|
$DayStart = $3;
|
|
}
|
|
|
|
my $DateTimeObject = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
Year => $YearStart,
|
|
Month => $MonthStart,
|
|
Day => $DayStart,
|
|
},
|
|
);
|
|
|
|
if ( !$DateTimeObject ) {
|
|
|
|
$LogObject->Log(
|
|
Priority => 'notice',
|
|
Message => 'UserReporting: Invalid start date for user '
|
|
. "$UserID: $UserCurrentPeriod{$UserID}{DateStart}",
|
|
);
|
|
|
|
next USERID;
|
|
}
|
|
|
|
my %CurrentUserData = (
|
|
LeaveDate => 0,
|
|
Sick => 0,
|
|
Overtime => 0,
|
|
TargetState => 0,
|
|
LeaveDayTotal => 0,
|
|
SickTotal => 0,
|
|
SickTotal => 0,
|
|
TargetStateTotal => 0,
|
|
);
|
|
|
|
my $Calendar = { $Self->UserGet( UserID => $UserID ) }->{Calendar};
|
|
|
|
YEAR:
|
|
for my $Year ( $YearStart .. $YearEnd ) {
|
|
|
|
my $MonthStartPoint = $Year == $YearStart ? $MonthStart : 1;
|
|
my $MonthEndPoint = $Year == $YearEnd ? $MonthEnd : 12;
|
|
|
|
MONTH:
|
|
for my $Month ( $MonthStartPoint .. $MonthEndPoint ) {
|
|
|
|
my $DayStartPoint =
|
|
$Year == $YearStart && $Month == $MonthStart
|
|
? $DayStart
|
|
: 1;
|
|
|
|
my $DayEndPoint;
|
|
|
|
if ( $Year == $YearEnd && $Month == $MonthEnd ) {
|
|
$DayEndPoint = $DayEnd;
|
|
}
|
|
else {
|
|
$DayEndPoint = $Self->DaysInMonth( $Year, $Month );
|
|
}
|
|
|
|
DAY:
|
|
for my $Day ( $DayStartPoint .. $DayEndPoint ) {
|
|
|
|
my %WorkingUnit = $Self->WorkingUnitsGet(
|
|
Year => $Year,
|
|
Month => $Month,
|
|
Day => $Day,
|
|
UserID => $UserID,
|
|
);
|
|
|
|
my $LeaveDay = 0;
|
|
my $Sick = 0;
|
|
my $Overtime = 0;
|
|
my $TargetState = 0;
|
|
|
|
if ( $WorkingUnit{LeaveDay} ) {
|
|
$CurrentUserData{LeaveDayTotal}++;
|
|
$LeaveDay = 1;
|
|
}
|
|
elsif ( $WorkingUnit{Sick} ) {
|
|
$CurrentUserData{SickTotal}++;
|
|
$Sick = 1;
|
|
}
|
|
elsif ( $WorkingUnit{Overtime} ) {
|
|
$CurrentUserData{OvertimeTotal}++;
|
|
$Overtime = 1;
|
|
}
|
|
|
|
$CurrentUserData{WorkingHoursTotal} += $WorkingUnit{Total};
|
|
my $VacationCheck = $Self->VacationCheck(
|
|
Year => $Year,
|
|
Month => $Month,
|
|
Day => $Day,
|
|
Calendar => $Calendar || '',
|
|
);
|
|
my $Weekday = $Self->DayOfWeek( $Year, $Month, $Day );
|
|
if (
|
|
$Weekday != 6
|
|
&& $Weekday != 7
|
|
&& !$VacationCheck
|
|
&& !$Sick
|
|
&& !$LeaveDay
|
|
)
|
|
{
|
|
$CurrentUserData{TargetStateTotal}
|
|
+= $UserCurrentPeriod{$UserID}{WeeklyHours} / 5;
|
|
$TargetState = $UserCurrentPeriod{$UserID}{WeeklyHours} / 5;
|
|
}
|
|
|
|
if ( $Month == $MonthEnd && $Year == $YearEnd ) {
|
|
$CurrentUserData{TargetState} += $TargetState;
|
|
$CurrentUserData{WorkingHours} += $WorkingUnit{Total};
|
|
$CurrentUserData{LeaveDay} += $LeaveDay;
|
|
$CurrentUserData{Sick} += $Sick;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$CurrentUserData{Overtime} = $CurrentUserData{WorkingHours} - $CurrentUserData{TargetState};
|
|
$CurrentUserData{OvertimeTotal} = $UserCurrentPeriod{$UserID}{Overtime}
|
|
+ $CurrentUserData{WorkingHoursTotal}
|
|
- $CurrentUserData{TargetStateTotal};
|
|
$CurrentUserData{OvertimeUntil} = $CurrentUserData{OvertimeTotal} - $CurrentUserData{Overtime};
|
|
$CurrentUserData{LeaveDayRemaining} = $UserCurrentPeriod{$UserID}{LeaveDays} - $CurrentUserData{LeaveDayTotal};
|
|
|
|
$Data{$UserID} = \%CurrentUserData;
|
|
}
|
|
|
|
return %Data;
|
|
}
|
|
|
|
=head2 ProjectSettingsGet()
|
|
|
|
returns a hash with all the projects' data
|
|
|
|
my %ProjectData = $TimeAccountingObject->ProjectSettingsGet(
|
|
Status => 'valid' || 'invalid', optional default valid && invalid
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ProjectSettingsGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $Where = '';
|
|
if ( $Param{Status} ) {
|
|
$Where = ' WHERE status = ';
|
|
$Where .= $Param{Status} eq 'invalid' ? "'0'" : "'1'";
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db select
|
|
$DBObject->Prepare(
|
|
SQL => "
|
|
SELECT id, project, description, status
|
|
FROM time_accounting_project
|
|
$Where",
|
|
);
|
|
|
|
# fetch the data
|
|
my %Data;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
my $ID = $Row[0];
|
|
$Data{Project}{$ID} = $Row[1];
|
|
$Data{ProjectDescription}{$ID} = $Row[2];
|
|
$Data{ProjectStatus}{$ID} = $Row[3];
|
|
}
|
|
|
|
return %Data;
|
|
}
|
|
|
|
=head2 ProjectGet()
|
|
|
|
returns a hash with the requested project data
|
|
|
|
my %ProjectData = $TimeAccountingObject->ProjectGet( ID => 2 );
|
|
|
|
This returns something like:
|
|
|
|
$TimeAccountingObject = (
|
|
Project => 'internal',
|
|
ProjectDescription => 'description',
|
|
ProjectStatus => 1,
|
|
);
|
|
|
|
or
|
|
|
|
my %ProjectData = $TimeAccountingObject->ProjectGet( Project => 'internal' );
|
|
|
|
This returns something like:
|
|
|
|
$TimeAccountingObject = (
|
|
ID => 2,
|
|
ProjectDescription => 'description',
|
|
ProjectStatus => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ProjectGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ID} && !$Param{Project} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ID or project name!'
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
my %Project;
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# look for the task data with the ID
|
|
if ( $Param{ID} ) {
|
|
|
|
# SQL
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT project, description, status
|
|
FROM time_accounting_project
|
|
WHERE id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
);
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
%Project = (
|
|
ID => $Param{ID},
|
|
Project => $Data[0],
|
|
ProjectDescription => $Data[1],
|
|
ProjectStatus => $Data[2],
|
|
);
|
|
}
|
|
}
|
|
|
|
# look for the task data with the task name
|
|
else {
|
|
|
|
# SQL
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT id, description, status
|
|
FROM time_accounting_project
|
|
WHERE project = ?',
|
|
Bind => [ \$Param{Project} ],
|
|
);
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
%Project = (
|
|
Project => $Param{Project},
|
|
ID => $Data[0],
|
|
ProjectDescription => $Data[1],
|
|
ProjectStatus => $Data[2],
|
|
);
|
|
}
|
|
}
|
|
|
|
return %Project;
|
|
}
|
|
|
|
=head2 ProjectSettingsInsert()
|
|
|
|
inserts a new project in the db
|
|
|
|
$TimeAccountingObject->ProjectSettingsInsert(
|
|
Project => 'internal', # optional
|
|
ProjectDescription => 'description', # optional
|
|
ProjectStatus => 1 || 0, # optional
|
|
);
|
|
|
|
returns ID of created project
|
|
|
|
=cut
|
|
|
|
sub ProjectSettingsInsert {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# get config object
|
|
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
|
|
|
$Param{Project} ||= $ConfigObject->Get('TimeAccounting::DefaultProjectName');
|
|
$Param{ProjectDescription} ||= '';
|
|
|
|
if ( $Param{ProjectStatus} ne '0' && $Param{ProjectStatus} ne '1' ) {
|
|
$Param{ProjectStatus} = $ConfigObject->Get('TimeAccounting::DefaultProjectStatus');
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# insert project record
|
|
return if !$DBObject->Do(
|
|
SQL => '
|
|
INSERT INTO time_accounting_project (project, description, status)
|
|
VALUES (?, ?, ?)',
|
|
Bind => [ \$Param{Project}, \$Param{ProjectDescription}, \$Param{ProjectStatus} ],
|
|
);
|
|
|
|
# get id of newly created project record
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT id
|
|
FROM time_accounting_project
|
|
WHERE project = ?',
|
|
Bind => [ \$Param{Project} ],
|
|
Limit => 1,
|
|
);
|
|
|
|
# fetch the data
|
|
my $ProjectID;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
$ProjectID = $Row[0];
|
|
}
|
|
|
|
return $ProjectID;
|
|
}
|
|
|
|
=head2 ProjectSettingsUpdate()
|
|
|
|
updates a project
|
|
|
|
my $Success = $TimeAccountingObject->ProjectSettingsUpdate(
|
|
ID => 123,
|
|
Project => 'internal',
|
|
ProjectDescription => 'description',
|
|
ProjectStatus => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ProjectSettingsUpdate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw(ID Project)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!"
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
# SQL
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => '
|
|
UPDATE time_accounting_project
|
|
SET project = ?, description = ?, status = ?
|
|
WHERE id = ?',
|
|
Bind => [
|
|
\$Param{Project}, \$Param{ProjectDescription}, \$Param{ProjectStatus}, \$Param{ID},
|
|
],
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 ActionSettingsGet()
|
|
|
|
returns a hash with all the actions settings
|
|
|
|
my %ActionData = $TimeAccountingObject->ActionSettingsGet();
|
|
|
|
=cut
|
|
|
|
sub ActionSettingsGet {
|
|
my $Self = shift;
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db select
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT id, action, status
|
|
FROM time_accounting_action',
|
|
);
|
|
|
|
# fetch the data
|
|
my %Data;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
$Data{ $Row[0] }{Action} = $Row[1];
|
|
$Data{ $Row[0] }{ActionStatus} = $Row[2];
|
|
}
|
|
|
|
return %Data;
|
|
}
|
|
|
|
=head2 ActionGet()
|
|
|
|
returns a hash with the requested action (task) data
|
|
|
|
my %ActionData = $TimeAccountingObject->ActionGet( ID => 2 );
|
|
|
|
This returns something like:
|
|
|
|
$TimeAccountingObject = (
|
|
Action => 'My task',
|
|
ActionStatus => 1,
|
|
);
|
|
|
|
or
|
|
|
|
my %ActionData = $TimeAccountingObject->ActionGet( Action => 'My task' );
|
|
|
|
This returns something like:
|
|
|
|
$TimeAccountingObject = (
|
|
ID => 2,
|
|
ActionStatus => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ActionGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ID} && !$Param{Action} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ID or Action!'
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
my %Task;
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# look for the task data with the ID
|
|
if ( $Param{ID} ) {
|
|
|
|
# SQL
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT action, status
|
|
FROM time_accounting_action
|
|
WHERE id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
);
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
%Task = (
|
|
ID => $Param{ID},
|
|
Action => $Data[0],
|
|
ActionStatus => $Data[1],
|
|
);
|
|
}
|
|
}
|
|
|
|
# look for the task data with the task name
|
|
else {
|
|
|
|
# SQL
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT id, status
|
|
FROM time_accounting_action
|
|
WHERE action = ?',
|
|
Bind => [ \$Param{Action} ],
|
|
);
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
%Task = (
|
|
Action => $Param{Action},
|
|
ID => $Data[0],
|
|
ActionStatus => $Data[1],
|
|
);
|
|
}
|
|
}
|
|
|
|
return %Task;
|
|
}
|
|
|
|
=head2 ActionSettingsInsert()
|
|
|
|
inserts a new action in the db
|
|
|
|
$TimeAccountingObject->ActionSettingsInsert(
|
|
Action => 'meeting', # optional
|
|
ActionStatus => 1 || 0, # optional
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ActionSettingsInsert {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# get config object
|
|
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
|
|
|
$Param{Action} ||= $ConfigObject->Get('TimeAccounting::DefaultActionName') || '';
|
|
if ( $Param{ActionStatus} ne '0' && $Param{ActionStatus} ne '1' ) {
|
|
$Param{ActionStatus} = $ConfigObject->Get('TimeAccounting::DefaultActionStatus');
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db insert
|
|
return if !$DBObject->Do(
|
|
SQL => '
|
|
INSERT INTO time_accounting_action (action, status)
|
|
VALUES (?, ?)',
|
|
Bind => [ \$Param{Action}, \$Param{ActionStatus}, ],
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 ActionSettingsUpdate()
|
|
|
|
updates an action (task)
|
|
|
|
my $Success = $TimeAccountingObject->ActionSettingsUpdate(
|
|
ActionID => 123,
|
|
Action => 'internal',
|
|
ActionStatus => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ActionSettingsUpdate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw(ActionID Action)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!"
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
# SQL
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => '
|
|
UPDATE time_accounting_action
|
|
SET action = ?, status = ?
|
|
WHERE id = ?',
|
|
Bind => [
|
|
\$Param{Action}, \$Param{ActionStatus}, \$Param{ActionID}
|
|
],
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 UserList()
|
|
|
|
returns a hash with the user data of all users
|
|
|
|
my %UserData = $TimeAccountingObject->UserList();
|
|
|
|
=cut
|
|
|
|
sub UserList {
|
|
my $Self = shift;
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db select
|
|
$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT user_id, description, show_overtime, create_project, allow_skip, calendar
|
|
FROM time_accounting_user',
|
|
);
|
|
|
|
# fetch the data
|
|
my %Data;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
$Data{ $Row[0] }{UserID} = $Row[0];
|
|
$Data{ $Row[0] }{Description} = $Row[1];
|
|
$Data{ $Row[0] }{ShowOvertime} = $Row[2];
|
|
$Data{ $Row[0] }{CreateProject} = $Row[3];
|
|
$Data{ $Row[0] }{AllowSkip} = $Row[4];
|
|
$Data{ $Row[0] }{Calendar} = $Row[5];
|
|
}
|
|
|
|
return %Data;
|
|
}
|
|
|
|
=head2 UserGet()
|
|
|
|
returns a hash with the user data of one user
|
|
|
|
my %UserData = $TimeAccountingObject->UserGet(
|
|
UserID => 15,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub UserGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed data
|
|
if ( !$Param{UserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'UserGet: Need UserID!',
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db select
|
|
$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT description, show_overtime, create_project, allow_skip, calendar
|
|
FROM time_accounting_user
|
|
WHERE user_id = ?',
|
|
Bind => [ \$Param{UserID} ],
|
|
);
|
|
|
|
# fetch the data
|
|
my %Data;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
$Data{UserID} = $Param{UserID};
|
|
$Data{Description} = $Row[0];
|
|
$Data{ShowOvertime} = $Row[1];
|
|
$Data{CreateProject} = $Row[2];
|
|
$Data{AllowSkip} = $Row[3];
|
|
$Data{Calendar} = $Row[4];
|
|
}
|
|
|
|
return %Data;
|
|
}
|
|
|
|
=head2 UserSettingsGet()
|
|
|
|
returns a hash with the complete user period data for all users
|
|
|
|
my %UserData = $TimeAccountingObject->UserSettingsGet();
|
|
|
|
returns:
|
|
%UserData = (
|
|
3 => {
|
|
1 => {
|
|
DateEnd => "2015-12-31",
|
|
DateStart => "2015-01-01",
|
|
LeaveDays => "23.00",
|
|
Overtime => "0.00",
|
|
Period => 1,
|
|
UserID => 3,
|
|
UserStatus => 1,
|
|
WeeklyHours => "40.00",
|
|
},
|
|
2 => {
|
|
DateEnd => "2015-12-31",
|
|
DateStart => "2015-01-01",
|
|
LeaveDays => "23.00",
|
|
Overtime => "0.00",
|
|
Period => 2,
|
|
UserID => 3,
|
|
UserStatus => 1,
|
|
WeeklyHours => "32.00",
|
|
},
|
|
},
|
|
4 => {
|
|
1 => {
|
|
DateEnd => "2015-12-31",
|
|
DateStart => "2015-01-01",
|
|
LeaveDays => "23.00",
|
|
Overtime => "0.00",
|
|
Period => 1,
|
|
UserID => 4,
|
|
UserStatus => 1,
|
|
WeeklyHours => "40.00",
|
|
},
|
|
},
|
|
};
|
|
|
|
=cut
|
|
|
|
sub UserSettingsGet {
|
|
my $Self = shift;
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db select
|
|
$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT user_id, preference_period, date_start, date_end, weekly_hours, leave_days,
|
|
overtime, status
|
|
FROM time_accounting_user_period'
|
|
);
|
|
|
|
# fetch the data
|
|
my %Data;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
$Data{ $Row[0] }{ $Row[1] }{UserID} = $Row[0];
|
|
$Data{ $Row[0] }{ $Row[1] }{Period} = $Row[1];
|
|
$Data{ $Row[0] }{ $Row[1] }{DateStart} = substr( $Row[2], 0, 10 );
|
|
$Data{ $Row[0] }{ $Row[1] }{DateEnd} = substr( $Row[3], 0, 10 );
|
|
$Data{ $Row[0] }{ $Row[1] }{WeeklyHours} = $Row[4];
|
|
$Data{ $Row[0] }{ $Row[1] }{LeaveDays} = $Row[5];
|
|
$Data{ $Row[0] }{ $Row[1] }{Overtime} = $Row[6];
|
|
$Data{ $Row[0] }{ $Row[1] }{UserStatus} = $Row[7];
|
|
}
|
|
|
|
return %Data;
|
|
}
|
|
|
|
=head2 SingleUserSettingsGet()
|
|
|
|
returns a hash with the requested user's period data
|
|
|
|
my %UserData = $TimeAccountingObject->SingleUserSettingsGet( UserID => 1 );
|
|
|
|
=cut
|
|
|
|
sub SingleUserSettingsGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{UserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need UserID!'
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db select
|
|
$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT user_id, preference_period, date_start, date_end, weekly_hours, leave_days,
|
|
overtime, status
|
|
FROM time_accounting_user_period WHERE user_id = ?',
|
|
Bind => [ \$Param{UserID} ],
|
|
);
|
|
|
|
# fetch the data
|
|
my %UserData;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
$UserData{ $Row[1] }{UserID} = $Row[0];
|
|
$UserData{ $Row[1] }{Period} = $Row[1];
|
|
$UserData{ $Row[1] }{DateStart} = substr( $Row[2], 0, 10 );
|
|
$UserData{ $Row[1] }{DateEnd} = substr( $Row[3], 0, 10 );
|
|
$UserData{ $Row[1] }{WeeklyHours} = $Row[4];
|
|
$UserData{ $Row[1] }{LeaveDays} = $Row[5];
|
|
$UserData{ $Row[1] }{Overtime} = $Row[6];
|
|
$UserData{ $Row[1] }{UserStatus} = $Row[7];
|
|
}
|
|
|
|
return %UserData;
|
|
}
|
|
|
|
=head2 UserLastPeriodNumberGet()
|
|
|
|
returns the number of the last registered period for the specified user
|
|
|
|
my $LastPeriodNumber = $TimeAccountingObject->UserLastPeriodNumberGet( UserID => 1 );
|
|
|
|
=cut
|
|
|
|
sub UserLastPeriodNumberGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{UserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need UserID!'
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db select
|
|
$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT max(preference_period)
|
|
FROM time_accounting_user_period
|
|
WHERE user_id = ?',
|
|
Bind => [ \$Param{UserID} ],
|
|
);
|
|
|
|
# fetch the data
|
|
my @Row = $DBObject->FetchrowArray();
|
|
my $LastPeriodNumber = $Row[0] || 0;
|
|
|
|
return $LastPeriodNumber;
|
|
}
|
|
|
|
=head2 UserSettingsInsert()
|
|
|
|
insert new user data in the db
|
|
|
|
$TimeAccountingObject->UserSettingsInsert(
|
|
UserID => '2',
|
|
Period => '2',
|
|
);
|
|
|
|
=cut
|
|
|
|
sub UserSettingsInsert {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw (UserID Period)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed"
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
# check if user exists
|
|
if ( !$Kernel::OM->Get('Kernel::System::User')->UserLookup( UserID => $Param{UserID} ) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "UserID $Param{UserID} does not exist!"
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
# get config object
|
|
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
|
|
|
$Param{WeeklyHours} = $ConfigObject->Get('TimeAccounting::DefaultUserWeeklyHours')
|
|
|| '40';
|
|
$Param{LeaveDays} = $ConfigObject->Get('TimeAccounting::DefaultUserLeaveDays') || '25';
|
|
$Param{UserStatus} = $ConfigObject->Get('TimeAccounting::DefaultUserStatus') || '1';
|
|
$Param{Overtime} = $ConfigObject->Get('TimeAccounting::DefaultUserOvertime') || '0';
|
|
$Param{DateEnd} = $ConfigObject->Get('TimeAccounting::DefaultUserDateEnd')
|
|
|| '2019-12-31';
|
|
$Param{DateStart} = $ConfigObject->Get('TimeAccounting::DefaultUserDateStart')
|
|
|| '2019-01-01';
|
|
$Param{Description} = $ConfigObject->Get('TimeAccounting::DefaultUserDescription')
|
|
|| 'Put your description here.';
|
|
|
|
$Param{DateStart} .= ' 00:00:00';
|
|
$Param{DateEnd} .= ' 00:00:00';
|
|
|
|
# delete cache
|
|
delete $Self->{'Cache::UserCurrentPeriodGet'};
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db insert
|
|
return if !$DBObject->Do(
|
|
SQL => '
|
|
INSERT INTO time_accounting_user_period (user_id, preference_period, date_start,
|
|
date_end, weekly_hours, leave_days, overtime, status)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
|
Bind => [
|
|
\$Param{UserID}, \$Param{Period}, \$Param{DateStart}, \$Param{DateEnd},
|
|
\$Param{WeeklyHours}, \$Param{LeaveDays}, \$Param{Overtime}, \$Param{UserStatus},
|
|
],
|
|
);
|
|
|
|
# select UserID
|
|
$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT user_id
|
|
FROM time_accounting_user
|
|
WHERE user_id = ?',
|
|
Bind => [ \$Param{UserID}, ],
|
|
Limit => 1,
|
|
);
|
|
|
|
# fetch the data
|
|
my $UserID;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
$UserID = $Row[0];
|
|
}
|
|
|
|
if ( !defined $UserID ) {
|
|
|
|
# db insert
|
|
return if !$DBObject->Do(
|
|
SQL => '
|
|
INSERT INTO time_accounting_user (user_id, description)
|
|
VALUES (?, ?)',
|
|
Bind => [ \$Param{UserID}, \$Param{Description}, ],
|
|
);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 UserSettingsUpdate()
|
|
|
|
updates user data in the db
|
|
|
|
$TimeAccountingObject->UserSettingsUpdate(
|
|
UserID => 1,
|
|
Description => 'Some Text',
|
|
CreateProject => 1 || 0,
|
|
ShowOvertime => 1 || 0,
|
|
AllowSkip => 1 || 0,
|
|
Period => {
|
|
1 => {
|
|
DateStart => '2015-12-12',
|
|
DateEnd => '2015-12-31',
|
|
WeeklyHours => '38',
|
|
LeaveDays => '25',
|
|
Overtime => '38',
|
|
UserStatus => 1 || 0,
|
|
},
|
|
2 => {
|
|
DateStart => '2015-12-12',
|
|
DateEnd => '2015-12-31',
|
|
WeeklyHours => '38',
|
|
LeaveDays => '25',
|
|
Overtime => '38',
|
|
UserStatus => 1 || 0,
|
|
},
|
|
3 => ......
|
|
}
|
|
);
|
|
|
|
=cut
|
|
|
|
sub UserSettingsUpdate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# delete cache
|
|
delete $Self->{'Cache::UserCurrentPeriodGet'};
|
|
|
|
my $UserID = $Param{UserID};
|
|
|
|
if ( !defined $Param{Period}->{1}{DateStart} && !defined $Param{Period}->{1}{DateEnd} ) {
|
|
|
|
return $Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "UserSettingUpdate: No data for user id $UserID!"
|
|
);
|
|
}
|
|
|
|
# set default values
|
|
$Param{ShowOvertime} ||= 0;
|
|
$Param{CreateProject} ||= 0;
|
|
$Param{AllowSkip} ||= 0;
|
|
$Param{Calendar} ||= 0;
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db insert
|
|
return if !$DBObject->Do(
|
|
SQL => '
|
|
UPDATE time_accounting_user
|
|
SET description = ?, show_overtime = ?, create_project = ?, allow_skip = ?, calendar = ?
|
|
WHERE user_id = ?',
|
|
Bind => [
|
|
\$Param{Description}, \$Param{ShowOvertime},
|
|
\$Param{CreateProject}, \$Param{AllowSkip}, \$Param{Calendar}, \$Param{UserID}
|
|
],
|
|
);
|
|
|
|
# update all periods
|
|
for my $Period ( sort keys %{ $Param{Period} } ) {
|
|
|
|
# db insert
|
|
return if !$DBObject->Do(
|
|
SQL => '
|
|
UPDATE time_accounting_user_period
|
|
SET leave_days = ?, date_start = ?, date_end = ?, overtime = ?, weekly_hours = ?,
|
|
status = ?
|
|
WHERE user_id = ?
|
|
AND preference_period = ?',
|
|
Bind => [
|
|
\$Param{Period}->{$Period}{LeaveDays}, \$Param{Period}->{$Period}{DateStart},
|
|
\$Param{Period}->{$Period}{DateEnd}, \$Param{Period}->{$Period}{Overtime},
|
|
\$Param{Period}->{$Period}{WeeklyHours}, \$Param{Period}->{$Period}{UserStatus},
|
|
\$UserID, \$Period,
|
|
]
|
|
);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 WorkingUnitsCompletnessCheck()
|
|
|
|
returns a hash with the incomplete working days and
|
|
the information if the incomplete working days are in the allowed
|
|
range.
|
|
|
|
my %WorkingUnitsCheck = $TimeAccountingObject->WorkingUnitsCompletnessCheck(
|
|
UserID => 123,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub WorkingUnitsCompletnessCheck {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
if ( !$Param{UserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need UserID"
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
my $UserID = $Param{UserID};
|
|
|
|
my %UserData = $Self->UserGet( UserID => $UserID );
|
|
if ( !%UserData ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Could not get user data',
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
# Skip check for users that are not required to log times.
|
|
return () if $UserData{AllowSkip};
|
|
|
|
my %Data = ();
|
|
my $WorkingUnitID = 0;
|
|
my %CompleteWorkingDays = ();
|
|
|
|
# get time object
|
|
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
|
|
my $DateTimeSettings = $DateTimeObject->Get();
|
|
|
|
my ( $Sec, $Min, $Hour, $Day, $Month, $Year ) = (
|
|
$DateTimeSettings->{Second},
|
|
$DateTimeSettings->{Minute},
|
|
$DateTimeSettings->{Hour},
|
|
$DateTimeSettings->{Day},
|
|
$DateTimeSettings->{Month},
|
|
$DateTimeSettings->{Year},
|
|
);
|
|
|
|
# TODO: Search only in the CurrentUserPeriod
|
|
# TODO: Search only working units where action_id and project_id is true
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT DISTINCT time_start
|
|
FROM time_accounting_table
|
|
WHERE user_id = ?',
|
|
Bind => [ \$UserID ],
|
|
);
|
|
|
|
# fetch the data
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
if ( $Row[0] =~ /^(\d+)-(\d+)-(\d+)/ ) {
|
|
$CompleteWorkingDays{$1}{$2}{$3} = 1;
|
|
}
|
|
}
|
|
|
|
my %UserCurrentPeriod = $Self->UserCurrentPeriodGet(
|
|
Year => $Year,
|
|
Month => $Month,
|
|
Day => $Day,
|
|
);
|
|
|
|
my $WorkingDays = 0;
|
|
my $YearStart = 1970;
|
|
my $MonthStart = 1;
|
|
my $DayStart = 1;
|
|
my $YearEnd = $Year;
|
|
my $MonthEnd = $Month;
|
|
my $DayEnd = $Day;
|
|
|
|
if (
|
|
$UserCurrentPeriod{$UserID}->{DateStart}
|
|
&& $UserCurrentPeriod{$UserID}->{DateStart} =~ /^(\d+)-(\d+)-(\d+)/
|
|
)
|
|
{
|
|
$YearStart = $1;
|
|
$MonthStart = $2;
|
|
$DayStart = $3;
|
|
}
|
|
|
|
# get config object
|
|
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
|
|
|
my $Calendar = $UserData{Calendar};
|
|
|
|
for my $Year ( $YearStart .. $YearEnd ) {
|
|
|
|
my $MonthStartPoint = $Year == $YearStart ? $MonthStart : 1;
|
|
my $MonthEndPoint = $Year == $YearEnd ? $MonthEnd : 12;
|
|
|
|
for my $Month ( $MonthStartPoint .. $MonthEndPoint ) {
|
|
|
|
my $DayStartPoint = $Year == $YearStart && $Month == $MonthStart ? $DayStart : 1;
|
|
|
|
my $DayEndPoint;
|
|
if ( $Year == $YearEnd && $Month == $MonthEnd ) {
|
|
$DayEndPoint = $DayEnd;
|
|
}
|
|
else {
|
|
$DayEndPoint = $Self->DaysInMonth( $Year, $Month );
|
|
}
|
|
|
|
my $MonthString = sprintf "%02d", $Month;
|
|
|
|
for my $Day ( $DayStartPoint .. $DayEndPoint ) {
|
|
|
|
my $VacationCheck = $Self->VacationCheck(
|
|
Year => $Year,
|
|
Month => $Month,
|
|
Day => $Day,
|
|
Calendar => $Calendar || '',
|
|
);
|
|
|
|
# Get calendar timezone or use the one of time-accounting object.
|
|
my $TimeZone = $ConfigObject->Get( "TimeZone::Calendar" . ( $Calendar || '' ) )
|
|
|| $Self->{TimeZone};
|
|
|
|
my $DayStartTime = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
Year => $Year,
|
|
Month => $Month,
|
|
Day => $Day,
|
|
Hour => 0,
|
|
Minute => 0,
|
|
Second => 0,
|
|
TimeZone => $TimeZone,
|
|
},
|
|
);
|
|
|
|
my $DayStopTime = $DayStartTime->Clone();
|
|
$DayStopTime->Set(
|
|
Hour => 23,
|
|
Minute => 59,
|
|
Second => 59,
|
|
);
|
|
|
|
# Convert to the timezone of time-accounting object.
|
|
$DayStartTime->ToTimeZone(
|
|
TimeZone => $Self->{TimeZone},
|
|
);
|
|
$DayStopTime->ToTimeZone(
|
|
TimeZone => $Self->{TimeZone},
|
|
);
|
|
|
|
# Convert to epochs.
|
|
$DayStartTime = $DayStartTime->ToEpoch();
|
|
$DayStopTime = $DayStopTime->ToEpoch();
|
|
|
|
# OLD CODE
|
|
|
|
#my $DateTimeObject = $Kernel::OM->Create(
|
|
# 'Kernel::System::DateTime',
|
|
# ObjectParams => {
|
|
# Year => $Year,
|
|
# Month => $Month,
|
|
# Day => $Day,
|
|
# },
|
|
#);
|
|
|
|
#my $Date = sprintf "%04d-%02d-%02d", $Year, $Month, $Day;
|
|
|
|
#my $DateTimeObjectStart = $Kernel::OM->Create(
|
|
# 'Kernel::System::DateTime',
|
|
# ObjectParams => {
|
|
# String => $Date . ' 00:00:00',
|
|
# },
|
|
#);
|
|
#my $DayStartTime = $DateTimeObjectStart->ToEpoch();
|
|
|
|
#my $DateTimeObjectStop = $Kernel::OM->Create(
|
|
# 'Kernel::System::DateTime',
|
|
# ObjectParams => {
|
|
# String => $Date . ' 23:59:59',
|
|
# },
|
|
#);
|
|
#my $DayStopTime = $DateTimeObjectStop->ToEpoch();
|
|
|
|
# add time zone to calculation
|
|
#my $Zone = $ConfigObject->Get( "TimeZone::Calendar" . ( $Calendar || '' ) );
|
|
#if ($Zone) {
|
|
# my $ZoneSeconds = $Zone * 60 * 60;
|
|
# $DayStartTime = $DayStartTime - $ZoneSeconds;
|
|
# $DayStopTime = $DayStopTime - $ZoneSeconds;
|
|
#}
|
|
|
|
# END
|
|
|
|
my $ThisDayWorkingTime = $Self->WorkingTime(
|
|
StartTime => $DayStartTime,
|
|
StopTime => $DayStopTime,
|
|
Calendar => $Calendar || '',
|
|
) || '0';
|
|
|
|
my $DayString = sprintf "%02d", $Day;
|
|
|
|
if ( $ThisDayWorkingTime && !$VacationCheck ) {
|
|
$WorkingDays += 1;
|
|
}
|
|
if (
|
|
$ThisDayWorkingTime
|
|
&& !$VacationCheck
|
|
&& !$CompleteWorkingDays{$Year}{$MonthString}{$DayString}
|
|
)
|
|
{
|
|
$Data{Incomplete}{$Year}{$MonthString}{$DayString} = $WorkingDays;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
my $MaxIntervallOfIncompleteDays = $ConfigObject->Get('TimeAccounting::MaxIntervalOfIncompleteDays') || '5';
|
|
my $MaxIntervallOfIncompleteDaysBeforeWarning
|
|
= $ConfigObject->Get('TimeAccounting::MaxIntervalOfIncompleteDaysBeforeWarning')
|
|
|| '3';
|
|
for my $Year ( sort keys %{ $Data{Incomplete} } ) {
|
|
|
|
for my $Month ( sort keys %{ $Data{Incomplete}{$Year} } ) {
|
|
|
|
for my $Day ( sort keys %{ $Data{Incomplete}{$Year}{$Month} } ) {
|
|
|
|
if (
|
|
$Data{Incomplete}{$Year}{$Month}{$Day}
|
|
< $WorkingDays - $MaxIntervallOfIncompleteDays
|
|
)
|
|
{
|
|
$Data{EnforceInsert} = 1;
|
|
}
|
|
elsif (
|
|
$Data{Incomplete}{$Year}{$Month}{$Day}
|
|
< $WorkingDays - $MaxIntervallOfIncompleteDaysBeforeWarning
|
|
)
|
|
{
|
|
$Data{Warning} = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return %Data;
|
|
}
|
|
|
|
=head2 WorkingUnitsGet()
|
|
|
|
returns a hash with the working units data
|
|
|
|
my %WorkingUnitsData = $TimeAccountingObject->WorkingUnitsGet(
|
|
Year => '2005',
|
|
Month => '7',
|
|
Day => '13',
|
|
UserID => '123',
|
|
);
|
|
|
|
=cut
|
|
|
|
sub WorkingUnitsGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
if ( !$Param{UserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need UserID"
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
my $Date = sprintf "%04d-%02d-%02d", $Param{Year}, $Param{Month}, $Param{Day};
|
|
my $DateStart = $Date . " 00:00:00";
|
|
my $DateStop = $Date . " 23:59:59";
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# ask the database
|
|
$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT user_id, project_id, action_id, remark, time_start, time_end, period
|
|
FROM time_accounting_table
|
|
WHERE time_start >= ?
|
|
AND time_start <= ?
|
|
AND user_id = ?
|
|
ORDER by id',
|
|
Bind => [ \$DateStart, \$DateStop, \$Param{UserID} ],
|
|
);
|
|
|
|
my %Data = (
|
|
Total => 0,
|
|
Date => $Date,
|
|
);
|
|
|
|
# fetch the result
|
|
ROW:
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
|
|
next ROW if $Row[4] !~ m{^ (.+?) \s (\d+:\d+) : (\d+) }xms;
|
|
|
|
# check if it is a special working unit
|
|
if ( $Row[1] == -1 ) {
|
|
my $ActionID = $Row[2];
|
|
|
|
$Data{Sick} = $ActionID == -1 ? 1 : 0;
|
|
$Data{LeaveDay} = $ActionID == -2 ? 1 : 0;
|
|
$Data{Overtime} = $ActionID == -3 ? 1 : 0;
|
|
|
|
next ROW;
|
|
}
|
|
|
|
my $StartTime = $2;
|
|
my $EndTime = '';
|
|
if ( $Row[5] =~ m{^(.+?)\s(\d+:\d+):(\d+)}xms ) {
|
|
$EndTime = $2;
|
|
|
|
# replace 23:59:59 with 24:00
|
|
if ( $EndTime eq '23:59' && $3 eq '59' ) {
|
|
$EndTime = '24:00';
|
|
}
|
|
}
|
|
|
|
my %WorkingUnit = (
|
|
UserID => $Row[0],
|
|
ProjectID => $Row[1],
|
|
ActionID => $Row[2],
|
|
Remark => $Row[3],
|
|
StartTime => $StartTime,
|
|
EndTime => $EndTime,
|
|
Period => defined( $Row[6] ) ? sprintf( "%.2f", $Row[6] ) : 0,
|
|
);
|
|
|
|
# only count complete working units
|
|
if ( $Row[1] && $Row[2] ) {
|
|
$Data{Total} += $WorkingUnit{Period};
|
|
}
|
|
|
|
push @{ $Data{WorkingUnits} }, \%WorkingUnit;
|
|
}
|
|
|
|
return %Data;
|
|
}
|
|
|
|
=head2 WorkingUnitsInsert()
|
|
|
|
insert working units in the db
|
|
|
|
$TimeAccountingObject->WorkingUnitsInsert(
|
|
Year => '2005',
|
|
Month => '07',
|
|
Day => '02',
|
|
LeaveDay => 1, || 0
|
|
Sick => 1, || 0
|
|
Overtime => 1, || 0
|
|
WorkingUnits => [
|
|
{
|
|
ProjectID => 1,
|
|
ActionID => 23,
|
|
Remark => 'SomeText',
|
|
StartTime => '7:30',
|
|
EndTime => '11:00',
|
|
Period => '8.5',
|
|
},
|
|
{ ...... },
|
|
],
|
|
UserID => 123,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub WorkingUnitsInsert {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
for my $Needed (qw(Year Month Day UserID)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "WorkingUnitsInsert: Need $Needed!"
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
my $Date = sprintf "%04d-%02d-%02d", $Param{Year}, $Param{Month}, $Param{Day};
|
|
|
|
# add special time working units
|
|
my %SpecialAction = (
|
|
'Sick' => '-1',
|
|
'LeaveDay' => '-2',
|
|
'Overtime' => '-3',
|
|
);
|
|
|
|
ELEMENT:
|
|
for my $Element (qw(LeaveDay Sick Overtime)) {
|
|
|
|
next ELEMENT if !$Param{$Element};
|
|
|
|
my %Unit = (
|
|
ProjectID => -1,
|
|
ActionID => $SpecialAction{$Element},
|
|
Remark => '',
|
|
StartTime => '',
|
|
EndTime => '',
|
|
Period => 0,
|
|
);
|
|
|
|
push @{ $Param{WorkingUnits} }, \%Unit;
|
|
}
|
|
|
|
# insert new working units
|
|
UNITREF:
|
|
for my $UnitRef ( @{ $Param{WorkingUnits} } ) {
|
|
|
|
my $StartTime = $Date . ' ' . ( $UnitRef->{StartTime} || '00:00' ) . ':00';
|
|
my $EndTime = $Date . ' ' . ( $UnitRef->{EndTime} || '00:00' ) . ':00';
|
|
|
|
# '' does not work in integer field of PostgreSQL
|
|
$UnitRef->{ProjectID} ||= 0;
|
|
$UnitRef->{ActionID} ||= 0;
|
|
$UnitRef->{Period} ||= 0;
|
|
|
|
# build DQL
|
|
my $SQL = '
|
|
INSERT INTO time_accounting_table (user_id, project_id, action_id, remark, time_start,
|
|
time_end, period, created )
|
|
VALUES ( ?, ?, ?, ?, ?, ?, ?, current_timestamp)';
|
|
my $Bind = [
|
|
\$Param{UserID}, \$UnitRef->{ProjectID}, \$UnitRef->{ActionID},
|
|
\$UnitRef->{Remark}, \$StartTime, \$EndTime, \$UnitRef->{Period},
|
|
];
|
|
|
|
# db insert
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => $SQL,
|
|
Bind => $Bind
|
|
);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 WorkingUnitsDelete()
|
|
|
|
deletes working units in the db
|
|
|
|
$TimeAccountingObject->WorkingUnitsDelete(
|
|
Year => '2015',
|
|
Month => '7',
|
|
Day => '13',
|
|
UserID => 123,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub WorkingUnitsDelete {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
for my $Needed (qw(Year Month Day UserID)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "WorkingUnitsInsert: Need $Needed!"
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
my $Date = sprintf "%04d-%02d-%02d", $Param{Year}, $Param{Month}, $Param{Day};
|
|
my $StartTime = $Date . ' 00:00:00';
|
|
my $EndTime = $Date . ' 23:59:59';
|
|
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => '
|
|
DELETE FROM time_accounting_table
|
|
WHERE time_start >= ?
|
|
AND time_start <= ?
|
|
AND user_id = ?',
|
|
Bind => [ \$StartTime, \$EndTime, \$Param{UserID}, ],
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 ProjectActionReporting()
|
|
|
|
returns a hash with the hours dependent project and action data
|
|
|
|
my %ProjectData = $TimeAccountingObject->ProjectActionReporting(
|
|
Year => 2005,
|
|
Month => 7,
|
|
UserID => 123, # optional; no UserID means 'of all users'
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ProjectActionReporting {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
for my $Parameter (qw(Year Month)) {
|
|
$Param{$Parameter} = $DBObject->Quote( $Param{$Parameter} ) || '';
|
|
if ( !$Param{$Parameter} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "ProjectActionReporting: Need $Parameter!"
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
# hours per month
|
|
my $DaysInMonth = $Self->DaysInMonth( $Param{Year}, $Param{Month} );
|
|
my $DateString = $Param{Year} . "-" . sprintf( "%02d", $Param{Month} );
|
|
my $SQLDate = "$DateString-$DaysInMonth 23:59:59";
|
|
|
|
my $SQL = '
|
|
SELECT project_id, action_id, period
|
|
FROM time_accounting_table
|
|
WHERE project_id != -1
|
|
AND time_start <= ?';
|
|
my @Bind = ( \$SQLDate );
|
|
|
|
if ( $Param{UserID} ) {
|
|
$SQL .= ' AND user_id = ?';
|
|
push @Bind, \$Param{UserID};
|
|
}
|
|
|
|
# total hours
|
|
$DBObject->Prepare(
|
|
SQL => $SQL,
|
|
Bind => \@Bind,
|
|
);
|
|
|
|
# fetch the data
|
|
my %Data;
|
|
ROW:
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
|
|
next ROW if !$Row[2];
|
|
|
|
$Data{ $Row[0] }->{Actions}->{ $Row[1] }->{Total} += $Row[2];
|
|
}
|
|
|
|
my $SQLDateStart = "$DateString-01 00:00:00";
|
|
|
|
$SQL = '
|
|
SELECT project_id, action_id, period
|
|
FROM time_accounting_table
|
|
WHERE project_id != -1
|
|
AND time_start >= ?
|
|
AND time_start <= ?';
|
|
@Bind = ( \$SQLDateStart, \$SQLDate );
|
|
|
|
if ( $Param{UserID} ) {
|
|
$SQL .= ' AND user_id = ?';
|
|
push @Bind, \$Param{UserID};
|
|
}
|
|
|
|
$DBObject->Prepare(
|
|
SQL => $SQL,
|
|
Bind => \@Bind,
|
|
);
|
|
|
|
# fetch the data
|
|
ROW:
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
|
|
next ROW if !$Row[2];
|
|
|
|
$Data{ $Row[0] }->{Actions}->{ $Row[1] }->{PerMonth} += $Row[2];
|
|
}
|
|
|
|
# add readable components
|
|
my %Project = $Self->ProjectSettingsGet();
|
|
my %Action = $Self->ActionSettingsGet();
|
|
|
|
for my $ProjectID ( sort keys %Data ) {
|
|
|
|
$Data{$ProjectID}->{Name} = $Project{Project}->{$ProjectID} || '';
|
|
$Data{$ProjectID}->{Status} = $Project{ProjectStatus}->{$ProjectID};
|
|
$Data{$ProjectID}->{Description} = $Project{ProjectDescription}->{$ProjectID};
|
|
|
|
my $ActionsRef = $Data{$ProjectID}->{Actions};
|
|
|
|
for my $ActionID ( sort keys %{$ActionsRef} ) {
|
|
$Data{$ProjectID}->{Actions}->{$ActionID}->{Name} = $Action{$ActionID}->{Action} || '';
|
|
}
|
|
}
|
|
|
|
return %Data;
|
|
}
|
|
|
|
=head2 ProjectTotalHours()
|
|
|
|
returns the sum of all hours related to a project
|
|
|
|
my $ProjectTotalHours = $TimeAccountingObject->ProjectTotalHours(
|
|
ProjectID => 15,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ProjectTotalHours {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed param
|
|
if ( !$Param{ProjectID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'ProjectActionReporting: Need ProjectID!'
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# ask the database
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT SUM(period)
|
|
FROM time_accounting_table
|
|
WHERE project_id = ?',
|
|
Bind => [ \$Param{ProjectID} ],
|
|
Limit => 1,
|
|
);
|
|
|
|
# fetch the result
|
|
my $Total = 0;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
$Total = $Row[0];
|
|
}
|
|
|
|
return $Total;
|
|
}
|
|
|
|
=head2 ProjectHistory()
|
|
|
|
returns an array with all WorkingUnits related to a project
|
|
|
|
my @ProjectHistoryArray = $TimeAccountingObject->ProjectHistory(
|
|
ProjectID => 15,
|
|
);
|
|
|
|
This would return
|
|
|
|
@ProjectHistoryArray = (
|
|
{
|
|
ID => 999,
|
|
UserID => 15,
|
|
User => 'Tom',
|
|
ActionID => 6,
|
|
Action => 'misc',
|
|
Remark => 'remark',
|
|
TimeStart => '7:00',
|
|
TimeEnd => '18:00',
|
|
Date => '2008-10-31', # the date of the working unit
|
|
Period => 11,
|
|
Created => '2008-11-01', # the insert time of the working unit
|
|
},
|
|
{
|
|
ID => 999,
|
|
UserID => 16,
|
|
User => 'Mane',
|
|
ActionID => 7,
|
|
Action => 'development',
|
|
Remark => 'remark',
|
|
TimeStart => '7:00',
|
|
TimeEnd => '18:00',
|
|
Period => 11,
|
|
Date => '2008-11-03',
|
|
Created => '2008-11-03',
|
|
}
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ProjectHistory {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed param
|
|
if ( !$Param{ProjectID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'ProjectActionReporting: Need ProjectID!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# call action data to get the readable name of the action
|
|
my %ActionData = $Self->ActionSettingsGet();
|
|
|
|
# get user list
|
|
my %ShownUsers = $Kernel::OM->Get('Kernel::System::User')->UserList(
|
|
Type => 'Long',
|
|
Valid => 0,
|
|
);
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# ask the database
|
|
$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT id, user_id, action_id, remark, time_start, time_end, period, created
|
|
FROM time_accounting_table
|
|
WHERE project_id = ?
|
|
ORDER BY time_start',
|
|
Bind => [ \$Param{ProjectID} ],
|
|
);
|
|
|
|
# fetch the result
|
|
my @Data;
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
|
|
my $UserRef = {
|
|
ID => $Row[0],
|
|
UserID => $Row[1],
|
|
User => $ShownUsers{ $Row[1] },
|
|
ActionID => $Row[2],
|
|
Action => $ActionData{ $Row[2] }{Action},
|
|
Remark => $Row[3] || '',
|
|
TimeStart => $Row[4],
|
|
TimeEnd => $Row[5],
|
|
Date => $Row[4],
|
|
Period => $Row[6],
|
|
Created => $Row[7],
|
|
};
|
|
$UserRef->{Date} =~ s{(\d\d\d\d-\d\d-\d\d) \s .+ }{$1}xms;
|
|
|
|
push @Data, $UserRef;
|
|
}
|
|
|
|
return @Data;
|
|
}
|
|
|
|
=head2 LastProjectsOfUser()
|
|
|
|
returns an array with the last projects of the current user
|
|
|
|
my @LastProjects = $TimeAccountingObject->LastProjectsOfUser(
|
|
UserID => 123,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub LastProjectsOfUser {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
if ( !$Param{UserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need UserID"
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# db select
|
|
# I don't use distinct because of ORDER BY problems of PostgreSQL
|
|
return if !$DBObject->Prepare(
|
|
SQL => '
|
|
SELECT project_id FROM time_accounting_table
|
|
WHERE user_id = ?
|
|
AND project_id <> -1
|
|
ORDER BY time_start DESC',
|
|
Bind => [ \$Param{UserID} ],
|
|
Limit => 40,
|
|
);
|
|
|
|
# fetch the result
|
|
my %Projects;
|
|
my $Counter = 0;
|
|
ROW:
|
|
while ( my @Row = $DBObject->FetchrowArray() ) {
|
|
|
|
next ROW if $Counter > 7;
|
|
next ROW if $Projects{ $Row[0] };
|
|
|
|
$Projects{ $Row[0] } = 1;
|
|
$Counter++;
|
|
}
|
|
|
|
return keys %Projects;
|
|
}
|
|
|
|
=head2 DayOfWeek()
|
|
|
|
Substitute for Date::Pcalc::Day_of_Week() which uses Kernel::System::DateTime.
|
|
|
|
=cut
|
|
|
|
sub DayOfWeek {
|
|
my ( $Self, $Year, $Month, $Day ) = @_;
|
|
|
|
my $DateTimeObject = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
Year => $Year,
|
|
Month => $Month,
|
|
Day => $Day,
|
|
TimeZone => 'floating',
|
|
},
|
|
);
|
|
|
|
if ( !$DateTimeObject ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => "error",
|
|
Message => "Error creating DateTime object.",
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
my $DateTimeValues = $DateTimeObject->Get();
|
|
|
|
return $DateTimeValues->{DayOfWeek};
|
|
}
|
|
|
|
=head2 AddDeltaYMD()
|
|
|
|
Substitute for Date::Pcalc::Add_Delta_YMD() which uses Kernel::System::DateTime.
|
|
|
|
=cut
|
|
|
|
sub AddDeltaYMD {
|
|
my ( $Self, $Year, $Month, $Day, $YearsToAdd, $MonthsToAdd, $DaysToAdd ) = @_;
|
|
|
|
my $DateTimeObject = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
Year => $Year,
|
|
Month => $Month,
|
|
Day => $Day,
|
|
TimeZone => 'floating',
|
|
},
|
|
);
|
|
|
|
if ( !$DateTimeObject ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => "error",
|
|
Message => "Error creating DateTime object.",
|
|
);
|
|
|
|
return ( $Year, $Month, $Day, );
|
|
}
|
|
|
|
$DateTimeObject->Add(
|
|
Years => $YearsToAdd || 0,
|
|
Months => $MonthsToAdd || 0,
|
|
Days => $DaysToAdd || 0,
|
|
);
|
|
my $DateTimeValues = $DateTimeObject->Get();
|
|
|
|
return (
|
|
$DateTimeValues->{Year},
|
|
$DateTimeValues->{Month},
|
|
$DateTimeValues->{Day},
|
|
);
|
|
}
|
|
|
|
=head2 DaysInMonth()
|
|
|
|
Substitute for Date::Pcalc::Days_in_Month() which uses Kernel::System::DateTime.
|
|
|
|
=cut
|
|
|
|
sub DaysInMonth {
|
|
my ( $Self, $Year, $Month ) = @_;
|
|
|
|
my $DateTimeObject = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
Year => $Year,
|
|
Month => $Month,
|
|
Day => 1,
|
|
TimeZone => 'floating',
|
|
},
|
|
);
|
|
|
|
if ( !$DateTimeObject ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => "error",
|
|
Message => "Error creating DateTime object.",
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
my $LastDayOfMonth = $DateTimeObject->LastDayOfMonthGet();
|
|
|
|
return $LastDayOfMonth->{Day};
|
|
}
|
|
|
|
=head2 VacationCheck()
|
|
|
|
check if the selected day is a vacation (it does not matter if you
|
|
insert 01 or 1 for month or day in the function or in the SysConfig)
|
|
|
|
returns (true) vacation day if exists, returns false if date is no
|
|
vacation day
|
|
|
|
$TimeAccountingObject->VacationCheck(
|
|
Year => 2005,
|
|
Month => 7 || '07',
|
|
Day => 13,
|
|
);
|
|
|
|
$TimeAccountingObject->VacationCheck(
|
|
Year => 2005,
|
|
Month => 7 || '07',
|
|
Day => 13,
|
|
Calendar => 3, # '' is default; 0 is handled like ''
|
|
);
|
|
|
|
=cut
|
|
|
|
sub VacationCheck {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check required params
|
|
for (qw(Year Month Day)) {
|
|
if ( !$Param{$_} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "VacationCheck: Need $_!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
my $DateTimeObject = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
%Param,
|
|
TimeZone => $Self->{TimeZone},
|
|
},
|
|
);
|
|
if ( !$DateTimeObject ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Error creating DateTime object.",
|
|
);
|
|
return;
|
|
}
|
|
|
|
return $DateTimeObject->IsVacationDay(
|
|
Calendar => $Param{Calendar},
|
|
);
|
|
}
|
|
|
|
=head2 WorkingTime()
|
|
|
|
get the working time in seconds between these local system times.
|
|
|
|
my $WorkingTime = $TimeAccountingObject->WorkingTime(
|
|
StartTime => $Created,
|
|
StopTime => $TimeObject->SystemTime(),
|
|
);
|
|
|
|
my $WorkingTime = $TimeAccountingObject->WorkingTime(
|
|
StartTime => $Created,
|
|
StopTime => $TimeObject->SystemTime(),
|
|
Calendar => 3, # '' is default
|
|
);
|
|
|
|
=cut
|
|
|
|
sub WorkingTime {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for (qw(StartTime StopTime)) {
|
|
if ( !defined $Param{$_} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $_!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
return 0 if $Param{StartTime} >= $Param{StopTime};
|
|
|
|
my $StartDateTimeObject = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
Epoch => $Param{StartTime},
|
|
TimeZone => $Self->{TimeZone},
|
|
},
|
|
);
|
|
|
|
my $StopDateTimeObject = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
Epoch => $Param{StopTime},
|
|
TimeZone => $Self->{TimeZone},
|
|
},
|
|
);
|
|
|
|
my $Delta = $StartDateTimeObject->Delta(
|
|
DateTimeObject => $StopDateTimeObject,
|
|
ForWorkingTime => 1,
|
|
Calendar => $Param{Calendar},
|
|
);
|
|
|
|
if ( !IsHashRefWithData($Delta) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Error calculating working time.',
|
|
);
|
|
return;
|
|
}
|
|
|
|
return $Delta->{AbsoluteSeconds};
|
|
}
|
|
|
|
=head2 SystemTime2Date()
|
|
|
|
converts a system time to a structured date array.
|
|
|
|
my ($Sec, $Min, $Hour, $Day, $Month, $Year, $WeekDay) = $TimeAccountingObject->SystemTime2Date(
|
|
SystemTime => $TimeObject->SystemTime(),
|
|
);
|
|
|
|
$WeekDay is the day of the week, with 0 indicating Sunday and 3 indicating Wednesday.
|
|
|
|
=cut
|
|
|
|
sub SystemTime2Date {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !defined $Param{SystemTime} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need SystemTime!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
my $DateTimeObject = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
Epoch => $Param{SystemTime},
|
|
},
|
|
);
|
|
|
|
$DateTimeObject->ToTimeZone( TimeZone => $Self->{TimeZone} );
|
|
|
|
my $DateTimeValues = $DateTimeObject->Get();
|
|
|
|
my $Year = $DateTimeValues->{Year};
|
|
my $Month = sprintf "%02d", $DateTimeValues->{Month};
|
|
my $Day = sprintf "%02d", $DateTimeValues->{Day};
|
|
my $Hour = sprintf "%02d", $DateTimeValues->{Hour};
|
|
my $Min = sprintf "%02d", $DateTimeValues->{Minute};
|
|
my $Sec = sprintf "%02d", $DateTimeValues->{Second};
|
|
|
|
my $WDay = $DateTimeValues->{DayOfWeek} == 7 ? 0 : $DateTimeValues->{DayOfWeek};
|
|
|
|
return ( $Sec, $Min, $Hour, $Day, $Month, $Year, $WDay );
|
|
}
|
|
|
|
=head2 DayOfWeekToName()
|
|
|
|
Convert a day number into the day name
|
|
|
|
my $DayName = $TimeAccountingObject->DayOfWeekToName(
|
|
Number => 1 # will return 'Monday'
|
|
);
|
|
|
|
=cut
|
|
|
|
sub DayOfWeekToName {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !defined $Param{Number} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need Number!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
if ( !IsPositiveInteger( $Param{Number} ) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Number must be a positive integer!",
|
|
);
|
|
return;
|
|
}
|
|
if ( $Param{Number} > 7 ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Number must not be grater than 7!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
my @DayNames = (
|
|
'Monday',
|
|
'Tuesday',
|
|
'Wednesday',
|
|
'Thursday',
|
|
'Friday',
|
|
'Saturday',
|
|
'Sunday'
|
|
);
|
|
|
|
return $DayNames[ $Param{Number} - 1 ];
|
|
}
|
|
|
|
=head2 Date2SystemTime()
|
|
|
|
converts a structured date array to system time of OTRS.
|
|
|
|
my $SystemTime = $TimeAccountingObject->Date2SystemTime(
|
|
Year => 2004,
|
|
Month => 8,
|
|
Day => 14,
|
|
Hour => 22,
|
|
Minute => 45,
|
|
Second => 0,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub Date2SystemTime {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for (qw(Year Month Day Hour Minute Second)) {
|
|
if ( !defined $Param{$_} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $_!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
my $DateTimeObject = $Kernel::OM->Create(
|
|
'Kernel::System::DateTime',
|
|
ObjectParams => {
|
|
%Param,
|
|
TimeZone => $Self->{TimeZone},
|
|
},
|
|
);
|
|
|
|
if ( !$DateTimeObject ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message =>
|
|
"Invalid Date '$Param{Year}-$Param{Month}-$Param{Day} $Param{Hour}:$Param{Minute}:$Param{Second}'!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
my $SystemTime = $DateTimeObject->ToEpoch();
|
|
|
|
return $SystemTime;
|
|
}
|
|
|
|
=head2 TimeStamp2SystemTime()
|
|
|
|
converts a given time stamp to local system time.
|
|
|
|
my $SystemTime = $TimeAccountingObject->TimeStamp2SystemTime(
|
|
String => '2004-08-14 22:45:00',
|
|
);
|
|
|
|
=cut
|
|
|
|
sub TimeStamp2SystemTime {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{String} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need String!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
my $SystemTime = 0;
|
|
|
|
# match iso date format
|
|
if ( $Param{String} =~ /(\d{4})-(\d{1,2})-(\d{1,2})\s(\d{1,2}):(\d{1,2}):(\d{1,2})/ ) {
|
|
$SystemTime = $Self->Date2SystemTime(
|
|
Year => $1,
|
|
Month => $2,
|
|
Day => $3,
|
|
Hour => $4,
|
|
Minute => $5,
|
|
Second => $6,
|
|
);
|
|
}
|
|
|
|
# match iso date format (wrong format)
|
|
elsif ( $Param{String} =~ /(\d{1,2})-(\d{1,2})-(\d{4})\s(\d{1,2}):(\d{1,2}):(\d{1,2})/ ) {
|
|
$SystemTime = $Self->Date2SystemTime(
|
|
Year => $3,
|
|
Month => $2,
|
|
Day => $1,
|
|
Hour => $4,
|
|
Minute => $5,
|
|
Second => $6,
|
|
);
|
|
}
|
|
|
|
# match euro time format
|
|
elsif ( $Param{String} =~ /(\d{1,2})\.(\d{1,2})\.(\d{4})\s(\d{1,2}):(\d{1,2}):(\d{1,2})/ ) {
|
|
$SystemTime = $Self->Date2SystemTime(
|
|
Year => $3,
|
|
Month => $2,
|
|
Day => $1,
|
|
Hour => $4,
|
|
Minute => $5,
|
|
Second => $6,
|
|
);
|
|
}
|
|
|
|
# match yyyy-mm-ddThh:mm:ss+tt:zz time format
|
|
elsif (
|
|
$Param{String}
|
|
=~ /(\d{4})-(\d{1,2})-(\d{1,2})T(\d{1,2}):(\d{1,2}):(\d{1,2})(\+|\-)((\d{1,2}):(\d{1,2}))/i
|
|
)
|
|
{
|
|
$SystemTime = $Self->Date2SystemTime(
|
|
Year => $1,
|
|
Month => $2,
|
|
Day => $3,
|
|
Hour => $4,
|
|
Minute => $5,
|
|
Second => $6,
|
|
);
|
|
}
|
|
|
|
# match mail time format
|
|
elsif (
|
|
$Param{String}
|
|
=~ /((...),\s+|)(\d{1,2})\s(...)\s(\d{4})\s(\d{1,2}):(\d{1,2}):(\d{1,2})\s((\+|\-)(\d{2})(\d{2})|...)/
|
|
)
|
|
{
|
|
my @MonthMap = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/;
|
|
my $Month = 1;
|
|
my $MonthString = $4;
|
|
for my $MonthCount ( 0 .. $#MonthMap ) {
|
|
if ( $MonthString =~ /$MonthMap[$MonthCount]/i ) {
|
|
$Month = $MonthCount + 1;
|
|
}
|
|
}
|
|
$SystemTime = $Self->Date2SystemTime(
|
|
Year => $5,
|
|
Month => $Month,
|
|
Day => $3,
|
|
Hour => $6,
|
|
Minute => $7,
|
|
Second => $8,
|
|
); # + $Self->{TimeSecDiff};
|
|
}
|
|
elsif ( # match yyyy-mm-ddThh:mm:ssZ
|
|
$Param{String} =~ /(\d{4})-(\d{1,2})-(\d{1,2})T(\d{1,2}):(\d{1,2}):(\d{1,2})Z$/
|
|
)
|
|
{
|
|
$SystemTime = $Self->Date2SystemTime(
|
|
Year => $1,
|
|
Month => $2,
|
|
Day => $3,
|
|
Hour => $4,
|
|
Minute => $5,
|
|
Second => $6,
|
|
);
|
|
}
|
|
|
|
# return error
|
|
if ( !defined $SystemTime ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Invalid Date '$Param{String}'!",
|
|
);
|
|
}
|
|
|
|
# return system time
|
|
return $SystemTime;
|
|
|
|
}
|
|
|
|
1;
|
|
|
|
=head1 TERMS AND CONDITIONS
|
|
|
|
This software is part of the OTRS project (L<https://otrs.org/>).
|
|
|
|
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 L<https://www.gnu.org/licenses/gpl-3.0.txt>.
|
|
|
|
=cut
|