timesheetRepository = $timesheetRepository; $this->userRepository = $userRepository; } /** * @Route(path="/", name="reporting", methods={"GET"}) * * @return Response */ public function defaultReport(ReportingService $reportingService): Response { $user = $this->getUser(); $route = null; $defaultReport = $user->getPreferenceValue('reporting.initial_view', ReportingService::DEFAULT_VIEW); $allReports = $reportingService->getAvailableReports($user); foreach ($allReports as $report) { if ($report->getId() === $defaultReport) { $route = $report->getRoute(); break; } } // fallback, if the configured report could not be found // eg. when it was deleted or replaced by an enhanced version with a new id if ($route === null && \count($allReports) > 0) { $report = $allReports[array_keys($allReports)[0]]; $route = $report->getRoute(); } if ($route === null) { throw $this->createNotFoundException('Unknown default report'); } return $this->redirectToRoute($route); } private function canSelectUser(): bool { // also found in App\EventSubscriber\Actions\UserSubscriber if (!$this->isGranted('view_other_timesheet')) { return false; } return true; } /** * @Route(path="/month_by_user", name="report_user_month", methods={"GET","POST"}) * * @param Request $request * @return Response * @throws Exception */ public function monthByUser(Request $request): Response { $currentUser = $this->getUser(); $dateTimeFactory = $this->getDateTimeFactory($currentUser); $localeFormats = $this->getLocaleFormats($request->getLocale()); $canChangeUser = $this->canSelectUser(); $values = new MonthByUser(); $values->setUser($currentUser); $values->setDate($dateTimeFactory->getStartOfMonth()); $form = $this->createForm(MonthByUserForm::class, $values, [ 'include_user' => $canChangeUser, 'timezone' => $dateTimeFactory->getTimezone()->getName(), 'start_date' => $values->getDate(), 'format' => $localeFormats->getDateTypeFormat(), ]); $form->submit($request->query->all(), false); if ($values->getUser() === null) { $values->setUser($currentUser); } if ($currentUser !== $values->getUser() && !$canChangeUser) { throw new AccessDeniedException('User is not allowed to see other users timesheet'); } if ($values->getDate() === null) { $values->setDate($dateTimeFactory->getStartOfMonth()); } $start = $values->getDate(); $start->modify('first day of 00:00:00'); $end = clone $start; $end->modify('last day of 23:59:59'); $selectedUser = $values->getUser(); $previousMonth = clone $start; $previousMonth->modify('-1 month'); $nextMonth = clone $start; $nextMonth->modify('+1 month'); $data = $this->timesheetRepository->getDailyStats($selectedUser, $start, $end); $rows = $this->prepareMonthlyData($data); return $this->render('reporting/month_by_user.html.twig', [ 'form' => $form->createView(), 'days' => $data, 'rows' => $rows, 'user' => $selectedUser, 'current' => $start, 'next' => $nextMonth, 'previous' => $previousMonth, ]); } /** * @Route(path="/week_by_user", name="report_user_week", methods={"GET","POST"}) * * @param Request $request * @return Response * @throws Exception */ public function weekByUser(Request $request): Response { $currentUser = $this->getUser(); $dateTimeFactory = $this->getDateTimeFactory($currentUser); $localeFormats = $this->getLocaleFormats($request->getLocale()); $canChangeUser = $this->canSelectUser(); $values = new WeekByUser(); $values->setUser($currentUser); $values->setDate($dateTimeFactory->getStartOfWeek()); $form = $this->createForm(WeekByUserForm::class, $values, [ 'include_user' => $canChangeUser, 'timezone' => $dateTimeFactory->getTimezone()->getName(), 'start_date' => $values->getDate(), 'format' => $localeFormats->getDateTypeFormat(), ]); $form->submit($request->query->all(), false); if ($values->getUser() === null) { $values->setUser($currentUser); } if ($currentUser !== $values->getUser() && !$canChangeUser) { throw new AccessDeniedException('User is not allowed to see other users timesheet'); } if ($values->getDate() === null) { $values->setDate($dateTimeFactory->getStartOfWeek()); } $start = $dateTimeFactory->getStartOfWeek($values->getDate()); $end = $dateTimeFactory->getEndOfWeek($values->getDate()); $selectedUser = $values->getUser(); $previous = clone $start; $previous->modify('-1 week'); $next = clone $start; $next->modify('+1 week'); $data = $this->timesheetRepository->getDailyStats($selectedUser, $start, $end); $rows = $this->prepareMonthlyData($data); return $this->render('reporting/week_by_user.html.twig', [ 'form' => $form->createView(), 'days' => $data, 'rows' => $rows, 'user' => $selectedUser, 'current' => $start, 'next' => $next, 'previous' => $previous, ]); } /** * @Route(path="/monthly_users_list", name="report_monthly_users", methods={"GET","POST"}) * @Security("is_granted('view_other_timesheet')") * * @param Request $request * @return Response * @throws Exception */ public function monthlyUsersList(Request $request): Response { $currentUser = $this->getUser(); $dateTimeFactory = $this->getDateTimeFactory(); $localeFormats = $this->getLocaleFormats($request->getLocale()); $query = new UserQuery(); $query->setCurrentUser($currentUser); $allUsers = $this->userRepository->getUsersForQuery($query); $rows = []; $values = new MonthlyUserList(); $values->setDate($dateTimeFactory->getStartOfMonth()); $form = $this->createForm(MonthlyUserListForm::class, $values, [ 'timezone' => $dateTimeFactory->getTimezone()->getName(), 'start_date' => $values->getDate(), 'format' => $localeFormats->getDateTypeFormat(), ]); $form->submit($request->query->all(), false); if ($form->isSubmitted() && !$form->isValid()) { $values->setDate($dateTimeFactory->getStartOfMonth()); } if ($values->getDate() === null) { $values->setDate($dateTimeFactory->getStartOfMonth()); } $start = $values->getDate(); $start->modify('first day of 00:00:00'); $end = clone $start; $end->modify('last day of 23:59:59'); $previousMonth = clone $start; $previousMonth->modify('-1 month'); $nextMonth = clone $start; $nextMonth->modify('+1 month'); foreach ($allUsers as $user) { $rows[] = [ 'days' => $this->timesheetRepository->getDailyStats($user, $start, $end), 'user' => $user ]; } $days = []; if (isset($rows[0])) { /** @var Day $day */ foreach ($rows[0]['days'] as $day) { $days[$day->getDay()->format('Ymd')] = $day->getDay(); } } return $this->render('reporting/monthly_user_list.html.twig', [ 'form' => $form->createView(), 'rows' => $rows, 'days' => $days, 'current' => $start, 'next' => $nextMonth, 'previous' => $previousMonth, ]); } private function prepareMonthlyData(array $data): array { $days = []; foreach ($data as $day) { $days[$day->getDay()->format('Ymd')] = ['date' => $day->getDay(), 'duration' => 0]; } $rows = []; /** @var Day $day */ foreach ($data as $day) { $dayId = $day->getDay()->format('Ymd'); foreach ($day->getDetails() as $id => $detail) { $projectId = $detail['project']->getId(); if (!\array_key_exists($projectId, $rows)) { $rows[$projectId] = [ 'project' => $detail['project'], 'duration' => 0, 'days' => $days, 'activities' => [], ]; } $rows[$projectId]['duration'] += $detail['duration']; $rows[$projectId]['days'][$dayId]['duration'] += $detail['duration']; $activityId = $detail['activity']->getId(); if (!\array_key_exists($activityId, $rows[$projectId]['activities'])) { $rows[$projectId]['activities'][$activityId] = [ 'activity' => $detail['activity'], 'duration' => 0, 'days' => $days, ]; } $rows[$projectId]['activities'][$activityId]['duration'] += $detail['duration']; $rows[$projectId]['activities'][$activityId]['days'][$dayId]['duration'] += $detail['duration']; } } return $rows; } }