static function getMonthReport($userId, $year, $month, $workdayHours = self::DEFAULT_WORKDAY_HOURS, $idleMinutes = null)
{
$userId = intval($userId);
if ($userId <= 0)
return false;
$year = intval($year);
$year = $year > 3000 || $year < 1900? date('Y'): $year;
$month = intval($month);
$month = $month > 12 || $month < 1? date('n'): $month;
$idleMinutes = !is_null($idleMinutes)? intval($idleMinutes): self::getMinimumIdleForReport();
$idleMinutes = $idleMinutes > 0? $idleMinutes: 0;
$workdayHours = intval($workdayHours);
$workdayHours = $workdayHours > 0? $workdayHours: 1;
$workdayHoursInSeconds = $workdayHours*60*60;
$dateStart = new BitrixMainTypeDateTime($year.'-'.str_pad($month, 2, '0', STR_PAD_LEFT).'-01 00:00:00', 'Y-m-d H:i:s');
$dateFinish = new BitrixMainTypeDateTime(($year+($month==12? 1: 0)).'-'.str_pad(($month==12? 1: $month+1), 2, '0', STR_PAD_LEFT).'-01 00:00:00', 'Y-m-d H:i:s');
$dateFinish->add('-1 SECONDS');
$workDays = Array();
$orm = BitrixTimemanModelAbsenceTable::getList(Array(
'select' => Array(
'ID', 'USER_ID', 'TYPE', 'DATE_START', 'DATE_FINISH', 'DURATION', 'ACTIVE', 'ENTRY_ID', 'REPORT_TYPE', 'REPORT_TEXT', 'SYSTEM_TEXT', 'SOURCE_START', 'SOURCE_FINISH', 'IP_START', 'IP_FINISH',
'ENTRIES_DATE_START' => 'ENTRIES.DATE_START',
'ENTRIES_DATE_FINISH' => 'ENTRIES.DATE_FINISH',
'ENTRIES_TIME_LEAKS' => 'ENTRIES.TIME_LEAKS',
'ENTRIES_DURATION' => 'ENTRIES.DURATION',
),
'filter' => Array(
'=USER_ID' => $userId,
'>=DATE_START' => $dateStart,
'<=DATE_START' => $dateFinish
),
'runtime' => Array(
new BitrixMainEntityReferenceField(
'ENTRIES',
'BitrixTimemanModelEntriesTable',
array(
"=ref.ID" => "this.ENTRY_ID",
),
array("join_type"=>"left")
)
)
));
while ($entry = $orm->fetch())
{
$entry['ACTIVE'] = $entry['ACTIVE'] !== 'N';
$entry['DURATION'] = (int)$entry['DURATION'];
if (
$entry['ENTRIES_DURATION'] == 0
&& $entry['ENTRIES_DATE_START'] instanceof BitrixMainTypeDateTime
&& $entry['ENTRIES_DATE_FINISH'] instanceof BitrixMainTypeDateTime
)
{
$entry['ENTRIES_DURATION'] = $entry['ENTRIES_DATE_FINISH']->getTimestamp() - $entry['ENTRIES_DATE_START']->getTimestamp() - (int)$entry['ENTRIES_TIME_LEAKS'];
}
$index = $entry['DATE_START'] instanceof BitrixMainTypeDateTime? $entry['DATE_START']->format('Ymd'): time();
$duration = $entry['DURATION'];
if ($entry['ENTRIES_DATE_FINISH'] instanceof BitrixMainTypeDateTime)
{
$entry['ENTRIES_DAY_COMPLETE'] = true;
}
else
{
$entry['ENTRIES_DAY_COMPLETE'] = false;
$entry['ENTRIES_DATE_FINISH'] = new BitrixMainTypeDateTime();
$entry['ENTRIES_DURATION'] = $entry['ENTRIES_DATE_FINISH']->getTimestamp() - $entry['ENTRIES_DATE_START']->getTimestamp();
}
if (!$entry['DATE_FINISH'] && $entry['ENTRIES_DATE_FINISH'] instanceof BitrixMainTypeDateTime)
{
$entry['DATE_FINISH'] = $entry['ENTRIES_DATE_FINISH'];
$duration = $entry['DURATION'] = $entry['DATE_FINISH']->getTimestamp() - $entry['DATE_START']->getTimestamp();
}
if ($entry['ENTRIES_DATE_FINISH'] instanceof BitrixMainTypeDateTime)
{
if (
$entry['DATE_START'] instanceof BitrixMainTypeDateTime
&& $entry['DATE_START']->getTimestamp() > $entry['ENTRIES_DATE_FINISH']->getTimeStamp()
)
{
continue;
}
else if (
$entry['DATE_FINISH'] instanceof BitrixMainTypeDateTime
&& $entry['DATE_FINISH']->getTimestamp() > $entry['ENTRIES_DATE_FINISH']->getTimeStamp()
)
{
$entry['DATE_FINISH'] = $entry['ENTRIES_DATE_FINISH'];
$duration = $entry['DURATION'] = $entry['DATE_FINISH']->getTimestamp() - $entry['DATE_START']->getTimestamp();
}
}
$workDays[$index]['INDEX'] = $index;
$workDays[$index]['DAY_TITLE'] = $entry['DATE_START'] instanceof BitrixMainTypeDateTime? $entry['DATE_START']->format(BitrixMainTypeDate::getFormat()): '';
$workDays[$index]['WORKDAY_DATE_START'] = $entry['ENTRIES_DATE_START'] instanceof BitrixMainTypeDateTime? $entry['ENTRIES_DATE_START']: null;
$workDays[$index]['WORKDAY_DATE_FINISH'] = $entry['ENTRIES_DATE_FINISH'] instanceof BitrixMainTypeDateTime? $entry['ENTRIES_DATE_FINISH']: null;
$workDays[$index]['WORKDAY_COMPLETE'] = $entry['ENTRIES_DAY_COMPLETE'];
$workDays[$index]['WORKDAY_TIME_LEAKS_USER'] = (int)$entry['ENTRIES_TIME_LEAKS'];
$workDays[$index]['WORKDAY_TIME_LEAKS_FINAL'] = 0;
$workDays[$index]['WORKDAY_DURATION'] = (int)$entry['ENTRIES_DURATION'];
$workDays[$index]['WORKDAY_DURATION_FINAL'] = 0;
$workDays[$index]['WORKDAY_DURATION_CONFIG'] = $workdayHoursInSeconds;
if (!isset($workDays[$index]['REPORTS']))
{
$workDays[$index]['REPORTS'] = [];
$workDays[$index]['WORKDAY_TIME_LEAKS_REAL'] = 0;
}
$duration = (int)$duration;
$entry['DATE_START'] = $entry['DATE_START'] instanceof BitrixMainTypeDateTime? $entry['DATE_START']: null;
$entry['DATE_FINISH'] = $entry['DATE_FINISH'] instanceof BitrixMainTypeDateTime? $entry['DATE_FINISH']: null;
if (
$entry['SOURCE_START'] == self::SOURCE_TM_EVENT
|| $entry['SOURCE_START'] == self::SOURCE_DESKTOP_OFFLINE_AGENT
|| $entry['SOURCE_START'] == self::SOURCE_DESKTOP_ONLINE_EVENT
|| $entry['SOURCE_START'] == self::SOURCE_DESKTOP_START_EVENT && !BitrixTimemanCommon::isNetworkRange($entry['IP_START'])
)
{
// ok
}
else if (
$entry['DATE_FINISH'] && !$duration
|| $duration && $duration <= $idleMinutes*60
)
{
continue;
}
$entry['IP_START_NETWORK'] = false;
if ($entry['IP_START'])
{
if ($result = BitrixTimemanCommon::isNetworkRange($entry['IP_START']))
{
$entry['IP_START_NETWORK'] = $result;
}
}
$entry['IP_FINISH_NETWORK'] = false;
if ($entry['IP_FINISH'])
{
if ($result = BitrixTimemanCommon::isNetworkRange($entry['IP_FINISH']))
{
$entry['IP_FINISH_NETWORK'] = $result;
}
}
if ($entry['REPORT_TYPE'] != self::REPORT_TYPE_WORK)
{
$workDays[$index]['WORKDAY_TIME_LEAKS_REAL'] += $duration;
}
else
{
$workDays[$index]['WORKDAY_TIME_LEAKS_REAL'] += 0;
}
if ($workDays[$index]['WORKDAY_DATE_START'])
{
// $workdayHours
if (!$workDays[$index]['WORKDAY_COMPLETE'] && $entry['ENTRIES_DURATION'] > 0)
{
$workDays[$index]['WORKDAY_DURATION'] = $workDays[$index]['WORKDAY_DURATION'] - $workDays[$index]['WORKDAY_TIME_LEAKS_USER'];
}
if ($workDays[$index]['WORKDAY_DATE_FINISH'] && $entry['ENTRIES_DURATION'] > 0)
{
if ($workDays[$index]['WORKDAY_DURATION'] > $workdayHoursInSeconds)
{
$workDays[$index]['WORKDAY_TIME_LEAKS_FINAL'] = $workDays[$index]['WORKDAY_DURATION'] - $workdayHoursInSeconds - $workDays[$index]['WORKDAY_TIME_LEAKS_REAL'];
$workDays[$index]['WORKDAY_TIME_LEAKS_FINAL'] = $workDays[$index]['WORKDAY_TIME_LEAKS_FINAL'] * -1;
}
else
{
$workDays[$index]['WORKDAY_TIME_LEAKS_FINAL'] = $workdayHoursInSeconds - $workDays[$index]['WORKDAY_DURATION'] + $workDays[$index]['WORKDAY_TIME_LEAKS_REAL'];
}
if ($workDays[$index]['WORKDAY_TIME_LEAKS_FINAL'] > $workdayHoursInSeconds)
{
$workDays[$index]['WORKDAY_TIME_LEAKS_FINAL'] = $workdayHoursInSeconds;
}
}
}
if ($entry['ENTRIES_DURATION'] > 0)
{
$workDays[$index]['WORKDAY_DURATION_FINAL'] = $workdayHoursInSeconds-$workDays[$index]['WORKDAY_TIME_LEAKS_FINAL'];
}
unset($entry['ENTRIES_DATE_FINISH']);
unset($entry['ENTRIES_DATE_START']);
unset($entry['ENTRIES_DAY_COMPLETE']);
unset($entry['ENTRIES_DURATION']);
unset($entry['ENTRIES_TIME_LEAKS']);
$workDays[$index]['REPORTS'][] = $entry;
}
if (!empty($workDays))
{
foreach ($workDays as $key => $row)
{
BitrixMainTypeCollection::sortByColumn(
$workDays[$key]['REPORTS'],
array('ID' => SORT_ASC)
);
}
BitrixMainTypeCollection::sortByColumn(
$workDays,
array('INDEX' => SORT_ASC)
);
}
return Array(
'REPORT' => Array(
'MONTH_TITLE' => Loc::getMessage('MONTH_'.$month),
'DATE_START' => $dateStart,
'DATE_FINISH' => $dateFinish,
'DAYS' => $workDays,
),
'USER' => self::getUserData($userId)
);
}