teamRepository->findAll(); $selectedTeamId = $request->query->getInt('team', 0); $from = $request->query->get('from', (new DateTime('first day of this month'))->format('Y-m-d')); $to = $request->query->get('to', (new DateTime('last day of this month'))->format('Y-m-d')); $team = null; $rows = []; $projectRows = []; $userColumns = []; $nonbillRows = []; $userColumnsNB = []; if ($selectedTeamId > 0) { $team = $this->teamRepository->find($selectedTeamId); if ($team) { $rows = $this->getUserTimeAnalysis($selectedTeamId, $from, $to); [$projectRows, $userColumns] = $this->getProjectPivot($selectedTeamId, $from, $to, '= 1'); [$nonbillRows, $userColumnsNB] = $this->getProjectPivot($selectedTeamId, $from, $to, '= 0'); [$unprodRows, $userColumnsUP] = $this->getProjectPivot($selectedTeamId, $from, $to, '= 2'); } } return $this->render('reporting/team_summary.html.twig', [ 'report_title' => 'report_team_summary', 'teams' => $teams, 'team' => $team, 'rows' => $rows, 'projectRows' => $projectRows, 'userColumns' => $userColumns, 'nonbillRows' => $nonbillRows, 'userColumnsNB' => $userColumnsNB, 'unprodRows' => $unprodRows, 'userColumnsUP' => $userColumnsUP, 'from' => $from, 'to' => $to, 'selectedTeamId' => $selectedTeamId, ]); } private function getUserTimeAnalysis(int $teamId, string $from, string $to): array { $sql = "SELECT u.username, u.alias, COALESCE(SUM(CASE WHEN p.billable = 1 THEN ts.duration END), 0) / 3600 AS billable_hours, COALESCE(SUM(CASE WHEN p.billable = 0 THEN ts.duration END), 0) / 3600 AS nonbillable_hours, COALESCE(SUM(CASE WHEN p.billable IS NULL OR p.billable NOT IN (0,1) THEN ts.duration END), 0) / 3600 AS unproductive_hours, COALESCE(SUM(ts.duration), 0) / 3600 AS total_hours FROM kimai2_users u JOIN kimai2_users_teams ut ON u.id = ut.user_id LEFT JOIN kimai2_timesheet ts ON u.id = ts.user AND DATE(ts.start_time) >= :from AND DATE(ts.start_time) <= :to LEFT JOIN kimai2_projects p ON ts.project_id = p.id WHERE ut.team_id = :teamId AND u.enabled = 1 GROUP BY u.id, u.username, u.alias HAVING total_hours > 0 ORDER BY u.alias"; return $this->connection->executeQuery($sql, [ 'teamId' => $teamId, 'from' => $from, 'to' => $to ])->fetchAllAssociative(); } private function getProjectPivot(int $teamId, string $from, string $to, string $billableComparison): array { $userSql = "SELECT u.id, u.alias FROM kimai2_users u JOIN kimai2_users_teams ut ON u.id = ut.user_id WHERE ut.team_id = :teamId AND u.enabled = 1 ORDER BY u.alias"; $users = $this->connection->executeQuery($userSql, ['teamId' => $teamId])->fetchAllAssociative(); $userColumns = array_column($users, 'alias'); $sql = "SELECT c.name AS company, p.name AS project, COALESCE(SUM(ts.duration), 0) / 3600 AS project_total, u.alias AS user_alias FROM kimai2_timesheet ts JOIN kimai2_users u ON ts.user = u.id JOIN kimai2_projects p ON ts.project_id = p.id JOIN kimai2_customers c ON p.customer_id = c.id JOIN kimai2_users_teams ut ON u.id = ut.user_id WHERE ut.team_id = :teamId AND DATE(ts.start_time) >= :from AND DATE(ts.start_time) <= :to AND p.billable " . $billableComparison . " GROUP BY c.id, p.id, u.id ORDER BY c.name, p.name"; $raw = $this->connection->executeQuery($sql, [ 'teamId' => $teamId, 'from' => $from, 'to' => $to ])->fetchAllAssociative(); $projectRows = []; foreach ($raw as $row) { $key = $row['company'] . '|||' . $row['project']; if (!isset($projectRows[$key])) { $projectRows[$key] = [ 'company' => $row['company'], 'project' => $row['project'], 'users' => [], 'total' => 0, ]; } $projectRows[$key]['users'][$row['user_alias']] = round($row['project_total'], 2); $projectRows[$key]['total'] += round($row['project_total'], 2); } return [array_values($projectRows), $userColumns]; } }