Skip to content
This repository was archived by the owner on Oct 22, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function run(): Response
}

$fromDateDb = $fromDate->copy()->setToDbTimezone();
$myTimesheets = $this->timesheetService->getWeeklyTimesheets(-1, $fromDateDb, session('userdata.id'));
$myTimesheets = $this->timesheetService->getMonthlyTimesheets(-1, $fromDateDb, session('userdata.id'));
$existingTicketIds = array_map(fn($item) => $item['ticketId'], $myTimesheets);

$this->tpl->assign('existingTicketIds', $existingTicketIds);
Expand Down
64 changes: 64 additions & 0 deletions app/Domain/Timesheets/Repositories/Timesheets.php
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,70 @@ public function getWeeklyTimesheets(int $projectId, CarbonInterface $fromDate, i
return $call->fetchAll();
}

/* getMonthlyTimesheets - get timesheet entries for a full month (for monthly view) */
public function getMonthlyTimesheets(int $projectId, CarbonInterface $fromDate, int $userId = 0, int $daysInMonth = 31): array
{
$query = 'SELECT
zp_timesheets.id,
zp_timesheets.userId,
zp_timesheets.ticketId,
zp_timesheets.workDate as workDate,
zp_timesheets.hours,
zp_timesheets.description,
zp_timesheets.kind,
zp_timesheets.invoicedEmpl,
zp_timesheets.invoicedComp,
zp_timesheets.invoicedEmplDate,
zp_timesheets.invoicedCompDate,
zp_timesheets.paid,
zp_timesheets.paidDate,
zp_timesheets.kind,
zp_timesheets.modified,
zp_tickets.headline,
zp_tickets.planHours,
zp_projects.name,
zp_projects.id AS projectId,
zp_projects.projectKey AS projectKey,
zp_projects.clientId AS clientId,
zp_clients.name AS clientName
FROM
zp_timesheets
LEFT JOIN zp_tickets ON zp_tickets.id = zp_timesheets.ticketId
LEFT JOIN zp_projects ON zp_tickets.projectId = zp_projects.id
LEFT JOIN zp_clients ON zp_clients.id = zp_projects.clientId
WHERE
(zp_timesheets.workDate >= :dateStart1 AND zp_timesheets.workDate < :dateEnd)
AND (zp_timesheets.userId = :userId)
AND hours > 0
';

if ($projectId > 0) {
$query .= ' AND zp_tickets.projectId = :projectId';
}

$query .= ' ORDER BY zp_timesheets.ticketId, zp_timesheets.kind, zp_timesheets.workDate DESC';

$call = $this->dbcall(func_get_args());

$call->prepare($query);

if (! $fromDate->isUtc()) {
$fromDate->setTimezone('UTC');
}

$call->bindValue(':dateStart1', $fromDate);

$endDate = $fromDate->copy()->addDays($daysInMonth);
$call->bindValue(':dateEnd', $endDate);
$call->bindValue(':userId', $userId, PDO::PARAM_INT);

if ($projectId > 0) {
$call->bindValue(':projectId', $projectId, PDO::PARAM_INT);
}

return $call->fetchAll();
}

/**
* getUsersTicketHours - get the total hours
*
Expand Down
78 changes: 78 additions & 0 deletions app/Domain/Timesheets/Services/Timesheets.php
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,84 @@ public function getWeeklyTimesheets(int $projectId, CarbonInterface $fromDate, i
return $timesheetGroups;
}

/* getMonthlyTimesheets - get timesheets grouped by day for the full month (for monthly view) */
public function getMonthlyTimesheets(int $projectId, CarbonInterface $fromDate, int $userId = 0): array
{
$daysInMonth = $fromDate->daysInMonth();

$allTimesheets = $this->timesheetsRepo->getMonthlyTimesheets(
projectId: $projectId,
fromDate: $fromDate,
userId: $userId,
daysInMonth: $daysInMonth
);

$timesheetGroups = [];
foreach ($allTimesheets as $timesheet) {
try {
$currentWorkDate = dtHelper()->parseDbDateTime($timesheet['workDate']);
} catch (\Exception $e) {
Log::warning($e);

continue;
}

$workdateOffsetStart = (int) ($currentWorkDate->setToUserTimezone()->secondsSinceMidnight() / 60 / 60);
$timezonedTime = $currentWorkDate->format('H:i:s');
$groupKey = $timesheet['ticketId'].'-'.$timesheet['kind'].'-'.$timezonedTime;

if (! isset($timesheetGroups[$groupKey])) {
$group = [
'kind' => $timesheet['kind'],
'clientName' => $timesheet['clientName'],
'name' => $timesheet['name'],
'headline' => $timesheet['headline'],
'ticketId' => $timesheet['ticketId'],
'projectId' => $timesheet['projectId'],
'projectKey' => $timesheet['projectKey'],
'hasTimesheetOffset' => $workdateOffsetStart !== 0,
'rowSum' => 0,
];

for ($d = 0; $d < $daysInMonth; $d++) {
$dayNum = $d + 1;
$dayStart = $fromDate->copy()->addDays($d);
$dayEnd = $fromDate->copy()->addDays($d)->addHours(23)->addMinutes(59);
$group['day'.$dayNum] = [
'start' => $dayStart,
'end' => $dayEnd,
'actualWorkDate' => $workdateOffsetStart === 0
? $fromDate->copy()->addDays($d)->setTime($currentWorkDate->hour, $currentWorkDate->minute, $currentWorkDate->second)
: '',
'hours' => 0,
'description' => '',
'id' => null,
];
}

$timesheetGroups[$groupKey] = $group;
}

for ($d = 1; $d <= $daysInMonth; $d++) {
$dayKey = 'day'.$d;
$start = $timesheetGroups[$groupKey][$dayKey]['start'];
$end = $timesheetGroups[$groupKey][$dayKey]['end'];

if ($currentWorkDate->gte($start) && $currentWorkDate->lt($end)) {
$timesheetGroups[$groupKey][$dayKey]['hours'] += $timesheet['hours'];
$timesheetGroups[$groupKey][$dayKey]['actualWorkDate'] = $currentWorkDate;
$timesheetGroups[$groupKey][$dayKey]['description'] = $timesheet['description'];
$timesheetGroups[$groupKey][$dayKey]['id'] = $timesheet['id'];
break;
}
}

$timesheetGroups[$groupKey]['rowSum'] += $timesheet['hours'];
}

return $timesheetGroups;
}

/**
* @api
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,4 +433,4 @@ class="hourCell"
<div class="clearall"></div>
</form>
</div>
</div>
</div>