added project filter in user-list reports (#4615)
This commit is contained in:
@@ -21,6 +21,7 @@ use App\Form\UserPreferencesForm;
|
||||
use App\Form\UserRolesType;
|
||||
use App\Form\UserTeamsType;
|
||||
use App\Form\UserTwoFactorType;
|
||||
use App\Repository\Query\TimesheetStatisticQuery;
|
||||
use App\Repository\TeamRepository;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Repository\UserRepository;
|
||||
@@ -84,13 +85,15 @@ final class ProfileController extends AbstractController
|
||||
// but we need a full year, because the chart needs always 12 month
|
||||
$begin = $dateFactory->createStartOfYear($begin);
|
||||
|
||||
$query = new TimesheetStatisticQuery($begin, $end, [$profile]);
|
||||
|
||||
$viewVars = [
|
||||
'tab' => 'charts',
|
||||
'page_setup' => $this->getPageSetup($profile, 'charts'),
|
||||
'user' => $profile,
|
||||
'stats' => $userStats,
|
||||
'workingSince' => $workStartingDay,
|
||||
'workMonths' => $statisticService->getMonthlyStats($begin, $end, [$profile])[0]
|
||||
'workMonths' => $statisticService->getMonthlyStats($query)[0]
|
||||
];
|
||||
|
||||
return $this->render('user/stats.html.twig', $viewVars);
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Export\Spreadsheet\Writer\XlsxWriter;
|
||||
use App\Model\DailyStatistic;
|
||||
use App\Reporting\MonthlyUserList\MonthlyUserList;
|
||||
use App\Reporting\MonthlyUserList\MonthlyUserListForm;
|
||||
use App\Repository\Query\TimesheetStatisticQuery;
|
||||
use App\Repository\Query\UserQuery;
|
||||
use App\Repository\Query\VisibilityInterface;
|
||||
use App\Repository\UserRepository;
|
||||
@@ -106,7 +107,9 @@ final class ReportUsersMonthController extends AbstractController
|
||||
$hasData = true;
|
||||
|
||||
if (!empty($allUsers)) {
|
||||
$dayStats = $statisticService->getDailyStatistics($start, $end, $allUsers);
|
||||
$statsQuery = new TimesheetStatisticQuery($start, $end, $allUsers);
|
||||
$statsQuery->setProject($values->getProject());
|
||||
$dayStats = $statisticService->getDailyStatistics($statsQuery);
|
||||
}
|
||||
|
||||
if (empty($dayStats)) {
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Export\Spreadsheet\Writer\XlsxWriter;
|
||||
use App\Model\DailyStatistic;
|
||||
use App\Reporting\WeeklyUserList\WeeklyUserList;
|
||||
use App\Reporting\WeeklyUserList\WeeklyUserListForm;
|
||||
use App\Repository\Query\TimesheetStatisticQuery;
|
||||
use App\Repository\Query\UserQuery;
|
||||
use App\Repository\Query\VisibilityInterface;
|
||||
use App\Repository\UserRepository;
|
||||
@@ -102,7 +103,9 @@ final class ReportUsersWeekController extends AbstractController
|
||||
$hasData = true;
|
||||
|
||||
if (!empty($allUsers)) {
|
||||
$dayStats = $statisticService->getDailyStatistics($start, $end, $allUsers);
|
||||
$statsQuery = new TimesheetStatisticQuery($start, $end, $allUsers);
|
||||
$statsQuery->setProject($values->getProject());
|
||||
$dayStats = $statisticService->getDailyStatistics($statsQuery);
|
||||
}
|
||||
|
||||
if (empty($dayStats)) {
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Export\Spreadsheet\Writer\XlsxWriter;
|
||||
use App\Model\MonthlyStatistic;
|
||||
use App\Reporting\YearlyUserList\YearlyUserList;
|
||||
use App\Reporting\YearlyUserList\YearlyUserListForm;
|
||||
use App\Repository\Query\TimesheetStatisticQuery;
|
||||
use App\Repository\Query\UserQuery;
|
||||
use App\Repository\Query\VisibilityInterface;
|
||||
use App\Repository\UserRepository;
|
||||
@@ -107,7 +108,9 @@ final class ReportUsersYearController extends AbstractController
|
||||
$hasData = true;
|
||||
|
||||
if (!empty($allUsers)) {
|
||||
$monthStats = $statisticService->getMonthlyStats($start, $end, $allUsers);
|
||||
$statsQuery = new TimesheetStatisticQuery($start, $end, $allUsers);
|
||||
$statsQuery->setProject($values->getProject());
|
||||
$monthStats = $statisticService->getMonthlyStats($statsQuery);
|
||||
}
|
||||
|
||||
if (empty($monthStats)) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Reporting;
|
||||
|
||||
use App\Entity\Project;
|
||||
use App\Entity\Team;
|
||||
|
||||
abstract class AbstractUserList
|
||||
@@ -17,6 +18,7 @@ abstract class AbstractUserList
|
||||
private bool $decimal = false;
|
||||
private string $sumType = 'duration';
|
||||
private ?Team $team = null;
|
||||
private ?Project $project = null;
|
||||
|
||||
public function getDate(): ?\DateTimeInterface
|
||||
{
|
||||
@@ -61,4 +63,14 @@ abstract class AbstractUserList
|
||||
{
|
||||
$this->team = $team;
|
||||
}
|
||||
|
||||
public function getProject(): ?Project
|
||||
{
|
||||
return $this->project;
|
||||
}
|
||||
|
||||
public function setProject(?Project $project): void
|
||||
{
|
||||
$this->project = $project;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
namespace App\Reporting\MonthlyUserList;
|
||||
|
||||
use App\Form\Type\MonthPickerType;
|
||||
use App\Form\Type\ProjectType;
|
||||
use App\Form\Type\ReportSumType;
|
||||
use App\Form\Type\TeamType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
@@ -33,6 +34,11 @@ final class MonthlyUserListForm extends AbstractType
|
||||
'required' => false,
|
||||
'width' => false,
|
||||
]);
|
||||
$builder->add('project', ProjectType::class, [
|
||||
'multiple' => false,
|
||||
'required' => false,
|
||||
'width' => false,
|
||||
]);
|
||||
$builder->add('sumType', ReportSumType::class);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Reporting\WeeklyUserList;
|
||||
|
||||
use App\Form\Type\ProjectType;
|
||||
use App\Form\Type\ReportSumType;
|
||||
use App\Form\Type\TeamType;
|
||||
use App\Form\Type\WeekPickerType;
|
||||
@@ -33,6 +34,11 @@ final class WeeklyUserListForm extends AbstractType
|
||||
'required' => false,
|
||||
'width' => false,
|
||||
]);
|
||||
$builder->add('project', ProjectType::class, [
|
||||
'multiple' => false,
|
||||
'required' => false,
|
||||
'width' => false,
|
||||
]);
|
||||
$builder->add('sumType', ReportSumType::class);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Reporting\YearlyUserList;
|
||||
|
||||
use App\Form\Type\ProjectType;
|
||||
use App\Form\Type\ReportSumType;
|
||||
use App\Form\Type\TeamType;
|
||||
use App\Form\Type\YearPickerType;
|
||||
@@ -34,6 +35,11 @@ final class YearlyUserListForm extends AbstractType
|
||||
'required' => false,
|
||||
'width' => false,
|
||||
]);
|
||||
$builder->add('project', ProjectType::class, [
|
||||
'multiple' => false,
|
||||
'required' => false,
|
||||
'width' => false,
|
||||
]);
|
||||
$builder->add('sumType', ReportSumType::class);
|
||||
}
|
||||
|
||||
|
||||
57
src/Repository/Query/TimesheetStatisticQuery.php
Normal file
57
src/Repository/Query/TimesheetStatisticQuery.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Repository\Query;
|
||||
|
||||
use App\Entity\Project;
|
||||
use App\Entity\User;
|
||||
|
||||
final class TimesheetStatisticQuery
|
||||
{
|
||||
private ?Project $project = null;
|
||||
|
||||
/**
|
||||
* @param array<User> $users
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly \DateTimeInterface $begin,
|
||||
private readonly \DateTimeInterface $end,
|
||||
private array $users
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public function getBegin(): \DateTimeInterface
|
||||
{
|
||||
return $this->begin;
|
||||
}
|
||||
|
||||
public function getEnd(): \DateTimeInterface
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User[]
|
||||
*/
|
||||
public function getUsers(): array
|
||||
{
|
||||
return $this->users;
|
||||
}
|
||||
|
||||
public function getProject(): ?Project
|
||||
{
|
||||
return $this->project;
|
||||
}
|
||||
|
||||
public function setProject(?Project $project): void
|
||||
{
|
||||
$this->project = $project;
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ class UserRepository extends EntityRepository implements UserLoaderInterface, Us
|
||||
* @throws ORMException
|
||||
* @throws \Doctrine\ORM\OptimisticLockException
|
||||
*/
|
||||
public function saveUser(User $user)
|
||||
public function saveUser(User $user): void
|
||||
{
|
||||
$entityManager = $this->getEntityManager();
|
||||
$entityManager->persist($user);
|
||||
@@ -397,7 +397,7 @@ class UserRepository extends EntityRepository implements UserLoaderInterface, Us
|
||||
* @param UserQuery $query
|
||||
* @return User[]
|
||||
*/
|
||||
public function getUsersForQuery(UserQuery $query): iterable
|
||||
public function getUsersForQuery(UserQuery $query): array
|
||||
{
|
||||
$qb = $this->getQueryBuilderForQuery($query);
|
||||
|
||||
@@ -408,8 +408,9 @@ class UserRepository extends EntityRepository implements UserLoaderInterface, Us
|
||||
* @param QueryBuilder $qb
|
||||
* @return User[]
|
||||
*/
|
||||
protected function getHydratedResultsByQuery(QueryBuilder $qb): iterable
|
||||
protected function getHydratedResultsByQuery(QueryBuilder $qb): array
|
||||
{
|
||||
/** @var array<User> $results */
|
||||
$results = $qb->getQuery()->getResult();
|
||||
|
||||
$loader = new UserLoader($qb->getEntityManager());
|
||||
|
||||
@@ -12,8 +12,8 @@ namespace App\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Model\DailyStatistic;
|
||||
use App\Model\MonthlyStatistic;
|
||||
use App\Repository\Query\TimesheetStatisticQuery;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use DateTime;
|
||||
use DateTimeInterface;
|
||||
|
||||
final class TimesheetStatisticService
|
||||
@@ -23,13 +23,15 @@ final class TimesheetStatisticService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface $begin
|
||||
* @param DateTimeInterface $end
|
||||
* @param User[] $users
|
||||
* @return DailyStatistic[]
|
||||
*/
|
||||
public function getDailyStatistics(DateTimeInterface $begin, DateTimeInterface $end, array $users): array
|
||||
public function getDailyStatistics(TimesheetStatisticQuery $query): array
|
||||
{
|
||||
$begin = $query->getBegin();
|
||||
$end = $query->getEnd();
|
||||
$users = $query->getUsers();
|
||||
$project = $query->getProject();
|
||||
|
||||
/** @var DailyStatistic[] $stats */
|
||||
$stats = [];
|
||||
|
||||
@@ -63,6 +65,13 @@ final class TimesheetStatisticService
|
||||
->addGroupBy('billable')
|
||||
;
|
||||
|
||||
if ($project !== null) {
|
||||
$qb
|
||||
->andWhere($qb->expr()->eq('t.project', ':project'))
|
||||
->setParameter('project', $project)
|
||||
;
|
||||
}
|
||||
|
||||
$results = $qb->getQuery()->getResult();
|
||||
|
||||
foreach ($results as $row) {
|
||||
@@ -241,7 +250,7 @@ final class TimesheetStatisticService
|
||||
return $stats;
|
||||
}
|
||||
|
||||
public function findFirstRecordDate(User $user): ?DateTime
|
||||
public function findFirstRecordDate(User $user): ?\DateTimeImmutable
|
||||
{
|
||||
$result = $this->repository->createQueryBuilder('t')
|
||||
->select('MIN(t.begin)')
|
||||
@@ -254,19 +263,19 @@ final class TimesheetStatisticService
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DateTime((string) $result, new \DateTimeZone($user->getTimezone()));
|
||||
return new \DateTimeImmutable((string) $result, new \DateTimeZone($user->getTimezone()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of Year statistics.
|
||||
*
|
||||
* @param DateTime $begin
|
||||
* @param DateTime $end
|
||||
* @param User[] $users
|
||||
* @return MonthlyStatistic[]
|
||||
*/
|
||||
public function getMonthlyStats(DateTime $begin, DateTime $end, array $users): array
|
||||
public function getMonthlyStats(TimesheetStatisticQuery $query): array
|
||||
{
|
||||
$begin = $query->getBegin();
|
||||
$end = $query->getEnd();
|
||||
$users = $query->getUsers();
|
||||
$project = $query->getProject();
|
||||
|
||||
/** @var MonthlyStatistic[] $stats */
|
||||
$stats = [];
|
||||
|
||||
@@ -297,6 +306,13 @@ final class TimesheetStatisticService
|
||||
->addGroupBy('billable')
|
||||
;
|
||||
|
||||
if ($project !== null) {
|
||||
$qb
|
||||
->andWhere($qb->expr()->eq('t.project', ':project'))
|
||||
->setParameter('project', $project)
|
||||
;
|
||||
}
|
||||
|
||||
$results = $qb->getQuery()->getResult();
|
||||
|
||||
foreach ($results as $row) {
|
||||
|
||||
Reference in New Issue
Block a user