From 50e7e20aff1309ffbe5b1cdfe5e69f5ba77b79fa Mon Sep 17 00:00:00 2001 From: farukvukovic <104840615+farukvukovic@users.noreply.github.com> Date: Wed, 28 Jan 2026 16:49:22 +0100 Subject: [PATCH] #5624 Fix recent timesheets display on monthly view --- .../Controllers/ShowMyMonthlyTimesheet.php | 2 +- .../Timesheets/Repositories/Timesheets.php | 64 +++++++++++++++ app/Domain/Timesheets/Services/Timesheets.php | 78 +++++++++++++++++++ .../Templates/showMyMonthlyTimesheet.tpl.php | 2 +- 4 files changed, 144 insertions(+), 2 deletions(-) diff --git a/app/Domain/Timesheets/Controllers/ShowMyMonthlyTimesheet.php b/app/Domain/Timesheets/Controllers/ShowMyMonthlyTimesheet.php index de894d1d4f..8d95b5cbf5 100644 --- a/app/Domain/Timesheets/Controllers/ShowMyMonthlyTimesheet.php +++ b/app/Domain/Timesheets/Controllers/ShowMyMonthlyTimesheet.php @@ -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); diff --git a/app/Domain/Timesheets/Repositories/Timesheets.php b/app/Domain/Timesheets/Repositories/Timesheets.php index fd78bee542..77719bc168 100644 --- a/app/Domain/Timesheets/Repositories/Timesheets.php +++ b/app/Domain/Timesheets/Repositories/Timesheets.php @@ -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 * diff --git a/app/Domain/Timesheets/Services/Timesheets.php b/app/Domain/Timesheets/Services/Timesheets.php index a2b246f31b..36fd9196ce 100644 --- a/app/Domain/Timesheets/Services/Timesheets.php +++ b/app/Domain/Timesheets/Services/Timesheets.php @@ -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 */ diff --git a/app/Domain/Timesheets/Templates/showMyMonthlyTimesheet.tpl.php b/app/Domain/Timesheets/Templates/showMyMonthlyTimesheet.tpl.php index 22dab22321..0947068b59 100644 --- a/app/Domain/Timesheets/Templates/showMyMonthlyTimesheet.tpl.php +++ b/app/Domain/Timesheets/Templates/showMyMonthlyTimesheet.tpl.php @@ -433,4 +433,4 @@ class="hourCell"
- \ No newline at end of file +