diff --git a/src/Repository/TimesheetRepository.php b/src/Repository/TimesheetRepository.php index 495c4cbc..fce4d95e 100644 --- a/src/Repository/TimesheetRepository.php +++ b/src/Repository/TimesheetRepository.php @@ -275,37 +275,86 @@ class TimesheetRepository extends EntityRepository * @param User|null $user * @return mixed */ - public function getDailyData(DateTime $begin, DateTime $end, ?User $user = null) + protected function getDailyData(DateTime $begin, DateTime $end, ?User $user = null) { - $qb = $this->getEntityManager()->createQueryBuilder(); + $query = new TimesheetQuery(); + $query + ->setBegin($begin) + ->setEnd($end) + ->setUser($user) + ->setState(TimesheetQuery::STATE_STOPPED) + ; + $timesheets = $this->getTimesheetsForQuery($query); - $qb - ->addSelect('SUM(t.rate) as rate') - ->addSelect('SUM(t.duration) as duration') - ->addSelect('MONTH(t.begin) as month') - ->addSelect('YEAR(t.begin) as year') - ->addSelect('DAY(t.begin) as day') - ->from(Timesheet::class, 't') - ->andWhere($qb->expr()->gte('t.begin', ':from')) - ->setParameter('from', $begin, Type::DATETIME) - ->andWhere($qb->expr()->lte('t.end', ':to')) - ->setParameter('to', $end, Type::DATETIME); + $results = []; + /** @var Timesheet $result */ + foreach ($timesheets as $result) { + $timezone = new \DateTimeZone($result->getTimezone()); + /** @var \DateTime $beginTmp */ + $beginTmp = $result->getBegin(); + $beginTmp->setTimezone($timezone); + /** @var DateTime $endTmp */ + $endTmp = $result->getEnd(); + $endTmp->setTimezone($timezone); + $dateKeyEnd = $endTmp->format('Ymd'); - if (null !== $user) { - $qb->andWhere('t.user = :user') - ->setParameter('user', $user); + do { + $dateKey = $beginTmp->format('Ymd'); + + if (!isset($results[$dateKey])) { + $results[$dateKey] = [ + 'rate' => 0, + 'duration' => 0, + 'month' => $beginTmp->format('n'), + 'year' => $beginTmp->format('Y'), + 'day' => $beginTmp->format('j'), + 'details' => [] + ]; + } + + if ($dateKey !== $dateKeyEnd) { + $newDateBegin = clone $beginTmp; + $newDateBegin->add(new \DateInterval('P1D')); + $newDateBegin->setTime(0, 0, 0); + } else { + $newDateBegin = clone $endTmp; + } + + $duration = $newDateBegin->getTimestamp() - $beginTmp->getTimestamp(); + $durationPercent = $duration / $result->getDuration(); + $rate = $result->getRate() * $durationPercent; + + $results[$dateKey]['rate'] += $rate; + $results[$dateKey]['duration'] += $duration; + $detailsId = $result->getProject()->getCustomer()->getId() . '_' . $result->getProject()->getId(); + if (!isset($results[$dateKey]['details'][$detailsId])) { + $results[$dateKey]['details'][$detailsId] = [ + 'project' => $result->getProject(), + 'activity' => $result->getActivity(), + 'duration' => 0, + 'rate' => 0, + ]; + + $results[$dateKey]['details'][$detailsId]['duration'] += $duration; + $results[$dateKey]['details'][$detailsId]['rate'] += $rate; + } + + $beginTmp = $newDateBegin; + + if ((int) $end->format('Ymd') < (int) $newDateBegin->format('Ymd')) { + break 1; + } + } while ($dateKey !== $dateKeyEnd); } - $qb - ->addGroupBy('year') - ->addGroupBy('month') - ->addGroupBy('day') - ->addOrderBy('year', 'DESC') - ->addOrderBy('month', 'ASC') - ->addOrderBy('day', 'ASC') - ; + ksort($results); - return $qb->getQuery()->execute(); + foreach ($results as $key => $value) { + $results[$key]['details'] = array_values($results[$key]['details']); + } + $results = array_values($results); + + return $results; } /** @@ -334,7 +383,9 @@ class TimesheetRepository extends EntityRepository foreach ($results as $statRow) { $dateTime = new DateTime(); $dateTime->setDate($statRow['year'], $statRow['month'], $statRow['day']); - $days[$dateTime->format('Ymd')] = new Day($dateTime, (int) $statRow['duration'], (float) $statRow['rate']); + $dateTime->setTime(0, 0, 0); + $day = new Day($dateTime, (int) $statRow['duration'], (float) $statRow['rate']); + $days[$dateTime->format('Ymd')] = $day; } ksort($days); diff --git a/src/Widget/Type/DailyWorkingTimeChart.php b/src/Widget/Type/DailyWorkingTimeChart.php index ff79295f..169902e0 100644 --- a/src/Widget/Type/DailyWorkingTimeChart.php +++ b/src/Widget/Type/DailyWorkingTimeChart.php @@ -11,6 +11,7 @@ namespace App\Widget\Type; use App\Repository\TimesheetRepository; use App\Security\CurrentUser; +use App\Timesheet\UserDateTimeFactory; use DateTime; class DailyWorkingTimeChart extends SimpleWidget @@ -21,10 +22,15 @@ class DailyWorkingTimeChart extends SimpleWidget * @var TimesheetRepository */ protected $repository; + /** + * @var UserDateTimeFactory + */ + private $dateTimeFactory; - public function __construct(TimesheetRepository $repository, CurrentUser $user) + public function __construct(TimesheetRepository $repository, CurrentUser $user, UserDateTimeFactory $dateTime) { $this->repository = $repository; + $this->dateTimeFactory = $dateTime; $this->setId('DailyWorkingTimeChart'); $this->setTitle('stats.yourWorkingHours'); $this->setOptions([ @@ -57,8 +63,8 @@ class DailyWorkingTimeChart extends SimpleWidget $options = $this->getOptions($options); $user = $options['user']; - $begin = new DateTime($options['begin']); - $end = new DateTime($options['end']); + $begin = new DateTime($options['begin'], $this->dateTimeFactory->getTimezone()); + $end = new DateTime($options['end'], $this->dateTimeFactory->getTimezone()); return $this->repository->getDailyStats($user, $begin, $end); } diff --git a/templates/widget/widget-dailyworkingtimechart.html.twig b/templates/widget/widget-dailyworkingtimechart.html.twig index bc306aed..df6326a0 100644 --- a/templates/widget/widget-dailyworkingtimechart.html.twig +++ b/templates/widget/widget-dailyworkingtimechart.html.twig @@ -35,7 +35,7 @@ document.addEventListener('kimai.initialized', function() { data: { labels: [ {% for day in data -%} - moment('{{ day.day|date_format(constant('\DateTime::ISO8601')) }}').format('ll') + moment('{{ day.day|date_format('Y-m-d') }}').format('ll') {% if not loop.last %},{% endif -%} {%- endfor %} ], diff --git a/tests/Widget/Type/DailyWorkingTimeChartTest.php b/tests/Widget/Type/DailyWorkingTimeChartTest.php index 67e8619f..b39d97e0 100644 --- a/tests/Widget/Type/DailyWorkingTimeChartTest.php +++ b/tests/Widget/Type/DailyWorkingTimeChartTest.php @@ -13,6 +13,7 @@ use App\Entity\User; use App\Model\Statistic\Day; use App\Repository\TimesheetRepository; use App\Security\CurrentUser; +use App\Tests\Mocks\Security\UserDateTimeFactoryFactory; use App\Widget\Type\AbstractWidgetType; use App\Widget\Type\DailyWorkingTimeChart; use App\Widget\Type\SimpleWidget; @@ -31,8 +32,9 @@ class DailyWorkingTimeChartTest extends TestCase $repository = $this->getMockBuilder(TimesheetRepository::class)->disableOriginalConstructor()->getMock(); $user = $this->getMockBuilder(CurrentUser::class)->disableOriginalConstructor()->setMethods(['getUser'])->getMock(); $user->expects($this->once())->method('getUser')->willReturn(new User()); + $mockFactory = new UserDateTimeFactoryFactory($this); - return new DailyWorkingTimeChart($repository, $user); + return new DailyWorkingTimeChart($repository, $user, $mockFactory->create('Europe/Berlin')); } public function testExtendsSimpleWidget() @@ -106,8 +108,9 @@ class DailyWorkingTimeChartTest extends TestCase }); $user = $this->getMockBuilder(CurrentUser::class)->disableOriginalConstructor()->setMethods(['getUser'])->getMock(); $user->expects($this->once())->method('getUser')->willReturn((new User())->setUsername('tralalala')); + $mockFactory = new UserDateTimeFactoryFactory($this); - $sut = new DailyWorkingTimeChart($repository, $user); + $sut = new DailyWorkingTimeChart($repository, $user, $mockFactory->create('Europe/Berlin')); $data = $sut->getData([]); self::assertCount(7, $data); foreach ($data as $statObj) {