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() %}
-
- {{ day|date_weekday }}
- |
- {% set totals = totals|merge({(day|report_date): 0}) %}
- {% endfor %}
-
-
-
- {% for userDay in stats %}
- {% set usersTotalDuration = 0 %}
-
- |
- {{ widgets.label_dot(userDay.user.displayName, userDay.user.color) }}
- |
- {% 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 %}
-
- {{ usersTotalDuration|duration }}
- |
- {% for day in userDay.days %}
-
- {% if day.totalDuration > 0 %}
- {{ day.totalDuration|duration }}
- {% endif %}
- |
- {% endfor %}
-
- {% endfor %}
-
-
-
- | {{ 'stats.durationTotal'|trans }} |
-
- {{ absoluteTotals|duration }}
- |
- {% for id, duration in totals %}
-
- {{ duration|duration }}
- |
- {% endfor %}
-
-
-
+ {% 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 = {} %}
+
+
+
+ | |
+ {{ 'stats.durationTotal'|trans }} |
+ {% for day in stats.0.getDateTimes() %}
+
+ {% block period_name %}
+ {{ day|date_weekday }}
+ {% endblock %}
+ |
+ {% set totals = totals|merge({(day|report_date): 0}) %}
+ {% endfor %}
+
+
+
+ {% for userPeriod in stats %}
+ {% set usersTotalDuration = 0 %}
+
+ |
+ {% block user_column %}
+ {% from "macros/widgets.html.twig" import label_dot %}
+ {{ label_dot(userPeriod.user.displayName, userPeriod.user.color) }}
+ {% endblock %}
+ |
+ {% 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 %}
+
+ {% block total_duration_user %}
+ {{ usersTotalDuration|duration(decimal) }}
+ {% endblock %}
+ |
+ {% for period in userPeriod.days %}
+
+ {% if period.totalDuration > 0 %}
+ {% block duration %}
+ {{ period.totalDuration|duration(decimal) }}
+ {% endblock %}
+ {% endif %}
+ |
+ {% endfor %}
+
+ {% endfor %}
+
+
+
+ | {{ 'stats.durationTotal'|trans }} |
+
+ {% block total_duration %}
+ {{ absoluteTotals|duration(decimal) }}
+ {% endblock %}
+ |
+ {% for id, total in totals %}
+
+ {% block total_duration_period %}
+ {{ total|duration(decimal) }}
+ {% endblock %}
+ |
+ {% endfor %}
+
+
+
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() %}
-
-
- {{ month|month_name }}
- {{ month|date_format('Y') }}
-
- |
- {% set totals = totals|merge({(month|report_date): 0}) %}
- {% endfor %}
-
-
-
- {% for userYear in stats|filter(row => row.user is not null) %}
- {% set usersTotalDuration = 0 %}
-
- |
- {{ widgets.label_dot(userYear.user.displayName, userYear.user.color) }}
- |
- {% for mid, month in userYear.months %}
- {% if month.totalDuration > 0 %}
- {% set usersTotalDuration = usersTotalDuration + month.totalDuration %}
- {% endif %}
- {% endfor %}
-
- {{ usersTotalDuration|duration }}
- |
- {% for mid, month in userYear.getMonths() %}
-
- {% if month.totalDuration > 0 %}
-
- {{ month.totalDuration|duration }}
-
- {% set totals = totals|merge({(month.date|report_date): (totals[month.date|report_date] + month.totalDuration)}) %}
- {% endif %}
- |
- {% endfor %}
-
- {% endfor %}
-
-
-
- | {{ 'stats.durationTotal'|trans }} |
- |
- {% for id, total in totals %}
-
- {{ total|duration }}
- |
- {% endfor %}
-
-
-
+ {% 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 = {} %}
+
+
+
+ | |
+ {{ 'stats.durationTotal'|trans }} |
+ {% for month in stats.0.getDateTimes() %}
+
+ {% block period_name %}
+
+ {{ month|month_name }}
+ {{ month|date_format('Y') }}
+
+ {% endblock %}
+ |
+ {% set totals = totals|merge({(month|report_date): 0}) %}
+ {% endfor %}
+
+
+
+ {% for userPeriod in stats|filter(row => row.user is not null) %}
+ {% set usersTotalDuration = 0 %}
+
+ |
+ {% block user_column %}
+ {% from "macros/widgets.html.twig" import label_dot %}
+ {{ label_dot(userPeriod.user.displayName, userPeriod.user.color) }}
+ {% endblock %}
+ |
+ {% for mid, period in userPeriod.months %}
+ {% if period.totalDuration > 0 %}
+ {% set usersTotalDuration = usersTotalDuration + period.totalDuration %}
+ {% set absoluteTotals = absoluteTotals + period.totalDuration %}
+ {% endif %}
+ {% endfor %}
+
+ {% block total_duration_user %}
+ {{ usersTotalDuration|duration(decimal) }}
+ {% endblock %}
+ |
+ {% for mid, period in userPeriod.months %}
+
+ {% 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 %}
+ |
+ {% endfor %}
+
+ {% endfor %}
+
+
+
+ | {{ 'stats.durationTotal'|trans }} |
+
+ {% block total_duration %}
+ {{ absoluteTotals|duration(decimal) }}
+ {% endblock %}
+ |
+ {% for id, total in totals %}
+
+ {% block total_duration_period %}
+ {{ total|duration(decimal) }}
+ {% endblock %}
+ |
+ {% endfor %}
+
+
+
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 %}