From 1852d7197434bd5862274a310538e08473712a19 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Mon, 14 Feb 2022 17:55:10 +0100 Subject: [PATCH] export user-list reports in excel (#3154) --- .../Reporting/ReportByUserController.php | 9 + .../Reporting/ReportUsersListController.php | 241 ------------------ .../Reporting/ReportUsersMonthController.php | 127 +++++++++ .../Reporting/ReportUsersWeekController.php | 124 +++++++++ .../Reporting/ReportUsersYearController.php | 130 ++++++++++ src/Reporting/AbstractUserList.php | 11 + .../reporting/report_user_list.html.twig | 60 +---- .../reporting/report_user_list_data.html.twig | 69 +++++ .../report_user_list_export.html.twig | 20 ++ .../report_user_list_monthly.html.twig | 65 +---- .../report_user_list_monthly_data.html.twig | 74 ++++++ .../report_user_list_monthly_export.html.twig | 20 ++ 12 files changed, 594 insertions(+), 356 deletions(-) delete mode 100644 src/Controller/Reporting/ReportUsersListController.php create mode 100644 src/Controller/Reporting/ReportUsersMonthController.php create mode 100644 src/Controller/Reporting/ReportUsersWeekController.php create mode 100644 src/Controller/Reporting/ReportUsersYearController.php create mode 100644 templates/reporting/report_user_list_data.html.twig create mode 100644 templates/reporting/report_user_list_export.html.twig create mode 100644 templates/reporting/report_user_list_monthly_data.html.twig create mode 100644 templates/reporting/report_user_list_monthly_export.html.twig diff --git a/src/Controller/Reporting/ReportByUserController.php b/src/Controller/Reporting/ReportByUserController.php index 01c08824..4275528e 100644 --- a/src/Controller/Reporting/ReportByUserController.php +++ b/src/Controller/Reporting/ReportByUserController.php @@ -199,15 +199,24 @@ final class ReportByUserController extends AbstractController if (!isset($data[$projectId]['duration'])) { $data[$projectId]['duration'] = 0; } + if (!isset($data[$projectId]['rate'])) { + $data[$projectId]['rate'] = 0.0; + } if (!isset($data[$projectId]['activities'][$activityId]['duration'])) { $data[$projectId]['activities'][$activityId]['duration'] = 0; } + if (!isset($data[$projectId]['activities'][$activityId]['rate'])) { + $data[$projectId]['activities'][$activityId]['rate'] = 0.0; + } /** @var StatisticDate $day */ foreach ($activityValues['days']->getDays() as $day) { $statDay = $dailyProjectStatistic->getDayByDateTime($day->getDate()); $statDay->setTotalDuration($statDay->getTotalDuration() + $day->getDuration()); + $statDay->setTotalRate($statDay->getTotalRate() + $day->getRate()); $data[$projectId]['duration'] = $data[$projectId]['duration'] + $day->getDuration(); + $data[$projectId]['rate'] = $data[$projectId]['rate'] + $day->getRate(); $data[$projectId]['activities'][$activityId]['duration'] = $data[$projectId]['activities'][$activityId]['duration'] + $day->getDuration(); + $data[$projectId]['activities'][$activityId]['rate'] = $data[$projectId]['activities'][$activityId]['rate'] + $day->getRate(); } } $data[$projectId]['days'] = $dailyProjectStatistic; diff --git a/src/Controller/Reporting/ReportUsersListController.php b/src/Controller/Reporting/ReportUsersListController.php deleted file mode 100644 index 8c561860..00000000 --- a/src/Controller/Reporting/ReportUsersListController.php +++ /dev/null @@ -1,241 +0,0 @@ -userRepository = $userRepository; - } - - /** - * @Route(path="/yearly_users_list", name="report_yearly_users", methods={"GET","POST"}) - * - * @param Request $request - * @return Response - * @throws Exception - */ - public function yearlyUsersList(Request $request, SystemConfiguration $systemConfiguration, TimesheetStatisticService $statisticService): Response - { - $currentUser = $this->getUser(); - $dateTimeFactory = $this->getDateTimeFactory(); - - $query = new UserQuery(); - $query->setCurrentUser($currentUser); - $allUsers = $this->userRepository->getUsersForQuery($query); - $defaultDate = $dateTimeFactory->createDateTime('01 january this year 00:00:00'); - - if (null !== ($financialYear = $systemConfiguration->getFinancialYearStart())) { - $defaultDate = $this->getDateTimeFactory()->createStartOfFinancialYear($financialYear); - } - - $values = new YearlyUserList(); - $values->setDate(clone $defaultDate); - - $form = $this->createForm(YearlyUserListForm::class, $values, [ - 'timezone' => $dateTimeFactory->getTimezone()->getName(), - 'start_date' => $values->getDate(), - ]); - - $form->submit($request->query->all(), false); - - if ($form->isSubmitted() && !$form->isValid()) { - $values->setDate(clone $defaultDate); - } - - if ($values->getDate() === null) { - $values->setDate(clone $defaultDate); - } - - $start = $values->getDate(); - // there is a potential edge case bug for financial years: - // the last month will be skipped, if the financial year started on a different day than the first - $end = $dateTimeFactory->createEndOfFinancialYear($start); - - $monthStats = []; - $hasData = true; - - if (!empty($allUsers)) { - $monthStats = $statisticService->getMonthlyStats($start, $end, $allUsers); - } - - if (empty($monthStats)) { - $monthStats = [new MonthlyStatistic($start, $end, $currentUser)]; - $hasData = false; - } - - return $this->render('reporting/report_user_list_monthly.html.twig', [ - 'report_title' => 'report_yearly_users', - 'box_id' => 'yearly-user-list-reporting-box', - 'form' => $form->createView(), - 'stats' => $monthStats, - 'hasData' => $hasData, - ]); - } - - /** - * @Route(path="/monthly_users_list", name="report_monthly_users", methods={"GET","POST"}) - */ - public function monthlyUsersList(Request $request, TimesheetStatisticService $statisticService): Response - { - $currentUser = $this->getUser(); - $dateTimeFactory = $this->getDateTimeFactory(); - - $query = new UserQuery(); - $query->setCurrentUser($currentUser); - $allUsers = $this->userRepository->getUsersForQuery($query); - - $values = new MonthlyUserList(); - $values->setDate($dateTimeFactory->getStartOfMonth()); - - $form = $this->createForm(MonthlyUserListForm::class, $values, [ - 'timezone' => $dateTimeFactory->getTimezone()->getName(), - 'start_date' => $values->getDate(), - ]); - - $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'); - - $previous = clone $start; - $previous->modify('-1 month'); - - $next = clone $start; - $next->modify('+1 month'); - - $dayStats = []; - $hasData = true; - - if (!empty($allUsers)) { - $dayStats = $statisticService->getDailyStatistics($start, $end, $allUsers); - } - - if (empty($dayStats)) { - $dayStats = [new DailyStatistic($start, $end, $currentUser)]; - $hasData = false; - } - - return $this->render('reporting/report_user_list.html.twig', [ - 'report_title' => 'report_monthly_users', - 'box_id' => 'monthly-user-list-reporting-box', - 'form' => $form->createView(), - 'current' => $start, - 'next' => $next, - 'previous' => $previous, - 'subReportDate' => $values->getDate(), - 'subReportRoute' => 'report_user_month', - 'stats' => $dayStats, - 'hasData' => $hasData, - ]); - } - - /** - * @Route(path="/weekly_users_list", name="report_weekly_users", methods={"GET","POST"}) - */ - public function weeklyUsersList(Request $request, TimesheetStatisticService $statisticService): Response - { - $currentUser = $this->getUser(); - $dateTimeFactory = $this->getDateTimeFactory(); - - $query = new UserQuery(); - $query->setCurrentUser($currentUser); - $allUsers = $this->userRepository->getUsersForQuery($query); - - $values = new WeeklyUserList(); - $values->setDate($dateTimeFactory->getStartOfWeek()); - - $form = $this->createForm(WeeklyUserListForm::class, $values, [ - 'timezone' => $dateTimeFactory->getTimezone()->getName(), - 'start_date' => $values->getDate(), - ]); - - $form->submit($request->query->all(), false); - - if ($form->isSubmitted() && !$form->isValid()) { - $values->setDate($dateTimeFactory->getStartOfWeek()); - } - - if ($values->getDate() === null) { - $values->setDate($dateTimeFactory->getStartOfWeek()); - } - - $start = $dateTimeFactory->getStartOfWeek($values->getDate()); - $end = $dateTimeFactory->getEndOfWeek($values->getDate()); - - $previous = clone $start; - $previous->modify('-1 week'); - - $next = clone $start; - $next->modify('+1 week'); - - $dayStats = []; - $hasData = true; - - if (!empty($allUsers)) { - $dayStats = $statisticService->getDailyStatistics($start, $end, $allUsers); - } - - if (empty($dayStats)) { - $dayStats = [new DailyStatistic($start, $end, $currentUser)]; - $hasData = false; - } - - return $this->render('reporting/report_user_list.html.twig', [ - 'report_title' => 'report_weekly_users', - 'box_id' => 'weekly-user-list-reporting-box', - 'form' => $form->createView(), - 'current' => $start, - 'next' => $next, - 'previous' => $previous, - 'subReportDate' => $values->getDate(), - 'subReportRoute' => 'report_user_week', - 'stats' => $dayStats, - 'hasData' => $hasData, - ]); - } -} diff --git a/src/Controller/Reporting/ReportUsersMonthController.php b/src/Controller/Reporting/ReportUsersMonthController.php new file mode 100644 index 00000000..a90cf0ca --- /dev/null +++ b/src/Controller/Reporting/ReportUsersMonthController.php @@ -0,0 +1,127 @@ +render( + 'reporting/report_user_list.html.twig', + $this->getData($request, $statisticService, $userRepository) + ); + } + + /** + * @Route(path="/export/monthly_users_list", name="report_monthly_users_export", methods={"GET","POST"}) + */ + public function export(Request $request, TimesheetStatisticService $statisticService, UserRepository $userRepository): Response + { + $data = $this->getData($request, $statisticService, $userRepository); + + $content = $this->container->get('twig')->render('reporting/report_user_list_export.html.twig', $data); + + $reader = new Html(); + $spreadsheet = $reader->loadFromString($content); + + $writer = new BinaryFileResponseWriter(new XlsxWriter(), 'kimai-export-users-weekly'); + + return $writer->getFileResponse($spreadsheet); + } + + private function getData(Request $request, TimesheetStatisticService $statisticService, UserRepository $userRepository): array + { + $currentUser = $this->getUser(); + $dateTimeFactory = $this->getDateTimeFactory(); + + $query = new UserQuery(); + $query->setCurrentUser($currentUser); + $allUsers = $userRepository->getUsersForQuery($query); + + $values = new MonthlyUserList(); + $values->setDate($dateTimeFactory->getStartOfMonth()); + + $form = $this->createForm(MonthlyUserListForm::class, $values, [ + 'timezone' => $dateTimeFactory->getTimezone()->getName(), + 'start_date' => $values->getDate(), + ]); + + $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'); + + $previous = clone $start; + $previous->modify('-1 month'); + + $next = clone $start; + $next->modify('+1 month'); + + $dayStats = []; + $hasData = true; + + if (!empty($allUsers)) { + $dayStats = $statisticService->getDailyStatistics($start, $end, $allUsers); + } + + if (empty($dayStats)) { + $dayStats = [new DailyStatistic($start, $end, $currentUser)]; + $hasData = false; + } + + return [ + 'report_title' => 'report_monthly_users', + 'box_id' => 'monthly-user-list-reporting-box', + 'export_route' => 'report_monthly_users_export', + 'form' => $form->createView(), + 'current' => $start, + 'next' => $next, + 'previous' => $previous, + 'decimal' => $values->isDecimal(), + 'subReportDate' => $values->getDate(), + 'subReportRoute' => 'report_user_month', + 'stats' => $dayStats, + 'hasData' => $hasData, + ]; + } +} diff --git a/src/Controller/Reporting/ReportUsersWeekController.php b/src/Controller/Reporting/ReportUsersWeekController.php new file mode 100644 index 00000000..54f4bc5a --- /dev/null +++ b/src/Controller/Reporting/ReportUsersWeekController.php @@ -0,0 +1,124 @@ +render( + 'reporting/report_user_list.html.twig', + $this->getData($request, $statisticService, $userRepository) + ); + } + + /** + * @Route(path="/export/weekly_users_list", name="report_weekly_users_export", methods={"GET","POST"}) + */ + public function export(Request $request, TimesheetStatisticService $statisticService, UserRepository $userRepository): Response + { + $data = $this->getData($request, $statisticService, $userRepository); + + $content = $this->container->get('twig')->render('reporting/report_user_list_export.html.twig', $data); + + $reader = new Html(); + $spreadsheet = $reader->loadFromString($content); + + $writer = new BinaryFileResponseWriter(new XlsxWriter(), 'kimai-export-users-weekly'); + + return $writer->getFileResponse($spreadsheet); + } + + private function getData(Request $request, TimesheetStatisticService $statisticService, UserRepository $userRepository): array + { + $currentUser = $this->getUser(); + $dateTimeFactory = $this->getDateTimeFactory(); + + $query = new UserQuery(); + $query->setCurrentUser($currentUser); + $allUsers = $userRepository->getUsersForQuery($query); + + $values = new WeeklyUserList(); + $values->setDate($dateTimeFactory->getStartOfWeek()); + + $form = $this->createForm(WeeklyUserListForm::class, $values, [ + 'timezone' => $dateTimeFactory->getTimezone()->getName(), + 'start_date' => $values->getDate(), + ]); + + $form->submit($request->query->all(), false); + + if ($form->isSubmitted() && !$form->isValid()) { + $values->setDate($dateTimeFactory->getStartOfWeek()); + } + + if ($values->getDate() === null) { + $values->setDate($dateTimeFactory->getStartOfWeek()); + } + + $start = $dateTimeFactory->getStartOfWeek($values->getDate()); + $end = $dateTimeFactory->getEndOfWeek($values->getDate()); + + $previous = clone $start; + $previous->modify('-1 week'); + + $next = clone $start; + $next->modify('+1 week'); + + $dayStats = []; + $hasData = true; + + if (!empty($allUsers)) { + $dayStats = $statisticService->getDailyStatistics($start, $end, $allUsers); + } + + if (empty($dayStats)) { + $dayStats = [new DailyStatistic($start, $end, $currentUser)]; + $hasData = false; + } + + return [ + 'report_title' => 'report_weekly_users', + 'box_id' => 'weekly-user-list-reporting-box', + 'export_route' => 'report_weekly_users_export', + 'form' => $form->createView(), + 'current' => $start, + 'next' => $next, + 'previous' => $previous, + 'decimal' => $values->isDecimal(), + 'subReportDate' => $values->getDate(), + 'subReportRoute' => 'report_user_week', + 'stats' => $dayStats, + 'hasData' => $hasData, + ]; + } +} diff --git a/src/Controller/Reporting/ReportUsersYearController.php b/src/Controller/Reporting/ReportUsersYearController.php new file mode 100644 index 00000000..72afb7cb --- /dev/null +++ b/src/Controller/Reporting/ReportUsersYearController.php @@ -0,0 +1,130 @@ +render( + 'reporting/report_user_list_monthly.html.twig', + $this->getData($request, $systemConfiguration, $statisticService, $userRepository) + ); + } + + /** + * @Route(path="/export/yearly_users_list", name="report_yearly_users_export", methods={"GET","POST"}) + * + * @param Request $request + * @return Response + * @throws Exception + */ + public function export(Request $request, SystemConfiguration $systemConfiguration, TimesheetStatisticService $statisticService, UserRepository $userRepository): Response + { + $data = $this->getData($request, $systemConfiguration, $statisticService, $userRepository); + + $content = $this->container->get('twig')->render('reporting/report_user_list_monthly_export.html.twig', $data); + + $reader = new Html(); + $spreadsheet = $reader->loadFromString($content); + + $writer = new BinaryFileResponseWriter(new XlsxWriter(), 'kimai-export-users-yearly'); + + return $writer->getFileResponse($spreadsheet); + } + + private function getData(Request $request, SystemConfiguration $systemConfiguration, TimesheetStatisticService $statisticService, UserRepository $userRepository): array + { + $currentUser = $this->getUser(); + $dateTimeFactory = $this->getDateTimeFactory(); + + $query = new UserQuery(); + $query->setCurrentUser($currentUser); + $allUsers = $userRepository->getUsersForQuery($query); + $defaultDate = $dateTimeFactory->createDateTime('01 january this year 00:00:00'); + + if (null !== ($financialYear = $systemConfiguration->getFinancialYearStart())) { + $defaultDate = $this->getDateTimeFactory()->createStartOfFinancialYear($financialYear); + } + + $values = new YearlyUserList(); + $values->setDate(clone $defaultDate); + + $form = $this->createForm(YearlyUserListForm::class, $values, [ + 'timezone' => $dateTimeFactory->getTimezone()->getName(), + 'start_date' => $values->getDate(), + ]); + + $form->submit($request->query->all(), false); + + if ($form->isSubmitted() && !$form->isValid()) { + $values->setDate(clone $defaultDate); + } + + if ($values->getDate() === null) { + $values->setDate(clone $defaultDate); + } + + $start = $values->getDate(); + // there is a potential edge case bug for financial years: + // the last month will be skipped, if the financial year started on a different day than the first + $end = $dateTimeFactory->createEndOfFinancialYear($start); + + $monthStats = []; + $hasData = true; + + if (!empty($allUsers)) { + $monthStats = $statisticService->getMonthlyStats($start, $end, $allUsers); + } + + if (empty($monthStats)) { + $monthStats = [new MonthlyStatistic($start, $end, $currentUser)]; + $hasData = false; + } + + return [ + 'report_title' => 'report_yearly_users', + 'box_id' => 'yearly-user-list-reporting-box', + 'export_route' => 'report_yearly_users_export', + 'decimal' => $values->isDecimal(), + 'form' => $form->createView(), + 'stats' => $monthStats, + 'hasData' => $hasData, + ]; + } +} diff --git a/src/Reporting/AbstractUserList.php b/src/Reporting/AbstractUserList.php index 45294889..afd86551 100644 --- a/src/Reporting/AbstractUserList.php +++ b/src/Reporting/AbstractUserList.php @@ -15,6 +15,7 @@ abstract class AbstractUserList * @var \DateTime */ private $date; + private $decimal = false; public function getDate(): ?\DateTime { @@ -25,4 +26,14 @@ abstract class AbstractUserList { $this->date = $date; } + + public function isDecimal(): bool + { + return $this->decimal; + } + + public function setDecimal(bool $decimal): void + { + $this->decimal = $decimal; + } } diff --git a/templates/reporting/report_user_list.html.twig b/templates/reporting/report_user_list.html.twig index baffb75a..bfc208a3 100644 --- a/templates/reporting/report_user_list.html.twig +++ b/templates/reporting/report_user_list.html.twig @@ -15,67 +15,15 @@ {% block box_title %} {{ form_widget(form.date) }} {% endblock %} + {% block box_tools %} + + {% endblock %} {% block box_body_class %}{{ box_id }} table-responsive {% if hasData %}no-padding{% endif %}{% endblock %} {% block box_body %} {% if not hasData %} {{ widgets.nothing_found() }} {% else %} - {% set absoluteTotals = 0 %} - {% set totals = {} %} - - - - - - {% for day in stats.0.getDateTimes() %} - - {% set totals = totals|merge({(day|report_date): 0}) %} - {% endfor %} - - - - {% for userDay in stats %} - {% set usersTotalDuration = 0 %} - - - {% for day in userDay.days %} - {% if day.totalDuration > 0 %} - {% set usersTotalDuration = usersTotalDuration + day.totalDuration %} - {% set absoluteTotals = absoluteTotals + day.totalDuration %} - {% endif %} - {% set totals = totals|merge({(day.date|report_date): (totals[day.date|report_date] + day.totalDuration)}) %} - {% endfor %} - - {% for day in userDay.days %} - - {% endfor %} - - {% endfor %} - - - - - - {% for id, duration in totals %} - - {% endfor %} - - -
   - {{ day|date_weekday }} -
- {{ widgets.label_dot(userDay.user.displayName, userDay.user.color) }} - - {{ usersTotalDuration|duration }} - - {% if day.totalDuration > 0 %} - {{ day.totalDuration|duration }} - {% endif %} -
{{ 'stats.durationTotal'|trans }} - {{ absoluteTotals|duration }} - - {{ duration|duration }} -
+ {% embed 'reporting/report_user_list_data.html.twig' %}{% endembed %} {% endif %} {% endblock %} {% endembed %} diff --git a/templates/reporting/report_user_list_data.html.twig b/templates/reporting/report_user_list_data.html.twig new file mode 100644 index 00000000..becf8f34 --- /dev/null +++ b/templates/reporting/report_user_list_data.html.twig @@ -0,0 +1,69 @@ +{% set absoluteTotals = 0 %} +{% set totals = {} %} + + + + + + {% for day in stats.0.getDateTimes() %} + + {% set totals = totals|merge({(day|report_date): 0}) %} + {% endfor %} + + + + {% for userPeriod in stats %} + {% set usersTotalDuration = 0 %} + + + {% for period in userPeriod.days %} + {% if period.totalDuration > 0 %} + {% set usersTotalDuration = usersTotalDuration + period.totalDuration %} + {% set absoluteTotals = absoluteTotals + period.totalDuration %} + {% endif %} + {% set totals = totals|merge({(period.date|report_date): (totals[period.date|report_date] + period.totalDuration)}) %} + {% endfor %} + + {% for period in userPeriod.days %} + + {% endfor %} + + {% endfor %} + + + + + + {% for id, total in totals %} + + {% endfor %} + + +
 {{ 'stats.durationTotal'|trans }} + {% block period_name %} + {{ day|date_weekday }} + {% endblock %} +
+ {% block user_column %} + {% from "macros/widgets.html.twig" import label_dot %} + {{ label_dot(userPeriod.user.displayName, userPeriod.user.color) }} + {% endblock %} + + {% block total_duration_user %} + {{ usersTotalDuration|duration(decimal) }} + {% endblock %} + + {% if period.totalDuration > 0 %} + {% block duration %} + {{ period.totalDuration|duration(decimal) }} + {% endblock %} + {% endif %} +
{{ 'stats.durationTotal'|trans }} + {% block total_duration %} + {{ absoluteTotals|duration(decimal) }} + {% endblock %} + + {% block total_duration_period %} + {{ total|duration(decimal) }} + {% endblock %} +
diff --git a/templates/reporting/report_user_list_export.html.twig b/templates/reporting/report_user_list_export.html.twig new file mode 100644 index 00000000..b1c51caf --- /dev/null +++ b/templates/reporting/report_user_list_export.html.twig @@ -0,0 +1,20 @@ +{% embed 'reporting/report_user_list_data.html.twig' %} + {% block user_column %} + {{ userPeriod.user.displayName }} + {% endblock %} + {% block duration -%} + =VALUE("{{ period.totalDuration|duration(true) }}") + {%- endblock %} + {% block total_duration_user -%} + =VALUE("{{ usersTotalDuration|duration(true) }}") + {%- endblock %} + {% block total_duration -%} + =VALUE("{{ absoluteTotals|duration(true) }}") + {%- endblock %} + {% block total_duration_period -%} + =VALUE("{{ total|duration(true) }}") + {%- endblock %} + {% block period_name %} + {{ day|date_short }} + {% endblock %} +{% endembed %} diff --git a/templates/reporting/report_user_list_monthly.html.twig b/templates/reporting/report_user_list_monthly.html.twig index f319dfe7..2b1076e2 100644 --- a/templates/reporting/report_user_list_monthly.html.twig +++ b/templates/reporting/report_user_list_monthly.html.twig @@ -5,78 +5,25 @@ {% block report %} {% embed '@AdminLTE/Widgets/box-widget.html.twig' %} - {% import "macros/widgets.html.twig" as widgets %} + {% from "macros/widgets.html.twig" import nothing_found, action_button %} {% block box_before %} {{ form_start(form, {'attr': {'class': 'form-inline form-reporting'}}) }} {% endblock %} {% block box_after %} {{ form_end(form) }} {% endblock %} + {% block box_tools %} + + {% endblock %} {% block box_title %} {{ form_widget(form.date) }} {% endblock %} {% block box_body_class %}{{ box_id }} table-responsive {% if hasData %}no-padding{% endif %}{% endblock %} {% block box_body %} {% if not hasData %} - {{ widgets.nothing_found() }} + {{ nothing_found() }} {% else %} - {% set totals = {} %} - - - - - - {% for month in stats.0.getDateTimes() %} - - {% set totals = totals|merge({(month|report_date): 0}) %} - {% endfor %} - - - - {% for userYear in stats|filter(row => row.user is not null) %} - {% set usersTotalDuration = 0 %} - - - {% for mid, month in userYear.months %} - {% if month.totalDuration > 0 %} - {% set usersTotalDuration = usersTotalDuration + month.totalDuration %} - {% endif %} - {% endfor %} - - {% for mid, month in userYear.getMonths() %} - - {% endfor %} - - {% endfor %} - - - - - - {% for id, total in totals %} - - {% endfor %} - - -
   - - {{ month|month_name }}
- {{ month|date_format('Y') }} -
-
- {{ widgets.label_dot(userYear.user.displayName, userYear.user.color) }} - - {{ usersTotalDuration|duration }} - - {% if month.totalDuration > 0 %} - - {{ month.totalDuration|duration }} - - {% set totals = totals|merge({(month.date|report_date): (totals[month.date|report_date] + month.totalDuration)}) %} - {% endif %} -
{{ 'stats.durationTotal'|trans }}  - {{ total|duration }} -
+ {% embed 'reporting/report_user_list_monthly_data.html.twig' %}{% endembed %} {% endif %} {% endblock %} {% endembed %} diff --git a/templates/reporting/report_user_list_monthly_data.html.twig b/templates/reporting/report_user_list_monthly_data.html.twig new file mode 100644 index 00000000..839a2565 --- /dev/null +++ b/templates/reporting/report_user_list_monthly_data.html.twig @@ -0,0 +1,74 @@ +{% set absoluteTotals = 0 %} +{% set totals = {} %} + + + + + + {% for month in stats.0.getDateTimes() %} + + {% set totals = totals|merge({(month|report_date): 0}) %} + {% endfor %} + + + + {% for userPeriod in stats|filter(row => row.user is not null) %} + {% set usersTotalDuration = 0 %} + + + {% for mid, period in userPeriod.months %} + {% if period.totalDuration > 0 %} + {% set usersTotalDuration = usersTotalDuration + period.totalDuration %} + {% set absoluteTotals = absoluteTotals + period.totalDuration %} + {% endif %} + {% endfor %} + + {% for mid, period in userPeriod.months %} + + {% endfor %} + + {% endfor %} + + + + + + {% for id, total in totals %} + + {% endfor %} + + +
 {{ 'stats.durationTotal'|trans }} + {% block period_name %} + + {{ month|month_name }}
+ {{ month|date_format('Y') }} +
+ {% endblock %} +
+ {% block user_column %} + {% from "macros/widgets.html.twig" import label_dot %} + {{ label_dot(userPeriod.user.displayName, userPeriod.user.color) }} + {% endblock %} + + {% block total_duration_user %} + {{ usersTotalDuration|duration(decimal) }} + {% endblock %} + + {% if period.totalDuration > 0 %} + {% block duration %} + + {{ period.totalDuration|duration(decimal) }} + + {% endblock %} + {% set totals = totals|merge({(period.date|report_date): (totals[period.date|report_date] + period.totalDuration)}) %} + {% endif %} +
{{ 'stats.durationTotal'|trans }} + {% block total_duration %} + {{ absoluteTotals|duration(decimal) }} + {% endblock %} + + {% block total_duration_period %} + {{ total|duration(decimal) }} + {% endblock %} +
diff --git a/templates/reporting/report_user_list_monthly_export.html.twig b/templates/reporting/report_user_list_monthly_export.html.twig new file mode 100644 index 00000000..ddf226fa --- /dev/null +++ b/templates/reporting/report_user_list_monthly_export.html.twig @@ -0,0 +1,20 @@ +{% embed 'reporting/report_user_list_monthly_data.html.twig' %} + {% block user_column %} + {{ userPeriod.user.displayName }} + {% endblock %} + {% block duration -%} + =VALUE("{{ period.totalDuration|duration(true) }}") + {%- endblock %} + {% block total_duration_user -%} + =VALUE("{{ usersTotalDuration|duration(true) }}") + {%- endblock %} + {% block total_duration -%} + =VALUE("{{ absoluteTotals|duration(true) }}") + {%- endblock %} + {% block total_duration_period -%} + =VALUE("{{ total|duration(true) }}") + {%- endblock %} + {% block period_name %} + {{ month|month_name }} {{ month|date_format('Y') }} + {% endblock %} +{% endembed %}