convert timesheets to UTC with support for user timezone (#372)

This commit is contained in:
Kevin Papst
2019-02-08 18:24:33 +01:00
committed by GitHub
parent 8dcc18dde3
commit d00596d297
58 changed files with 1637 additions and 207 deletions

View File

@@ -11,7 +11,6 @@ namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Timesheet entity.
@@ -25,7 +24,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
* )
* @ORM\Entity(repositoryClass="App\Repository\TimesheetRepository")
* @ORM\HasLifecycleCallbacks()
* @Assert\Callback("validate")
* @App\Validator\Constraints\Timesheet
*/
class Timesheet
{
@@ -53,6 +52,18 @@ class Timesheet
*/
private $end;
/**
* @var string
*
* @ORM\Column(name="timezone", type="string", length=64, nullable=false)
*/
private $timezone;
/**
* @var bool
*/
private $localized = false;
/**
* @var int
*
@@ -137,11 +148,34 @@ class Timesheet
return $this->id;
}
/**
* Make sure begin and end date have the correct timezone.
* This will be called once for each item after being loaded from the database.
*/
protected function localizeDates()
{
if ($this->localized) {
return;
}
if (null !== $this->begin) {
$this->begin->setTimeZone(new \DateTimeZone($this->timezone));
}
if (null !== $this->end) {
$this->end->setTimeZone(new \DateTimeZone($this->timezone));
}
$this->localized = true;
}
/**
* @return \DateTime
*/
public function getBegin()
{
$this->localizeDates();
return $this->begin;
}
@@ -149,9 +183,10 @@ class Timesheet
* @param \DateTime $begin
* @return Timesheet
*/
public function setBegin($begin)
public function setBegin(\DateTime $begin)
{
$this->begin = $begin;
$this->timezone = $begin->getTimezone()->getName();
return $this;
}
@@ -161,6 +196,8 @@ class Timesheet
*/
public function getEnd()
{
$this->localizeDates();
return $this->end;
}
@@ -168,21 +205,21 @@ class Timesheet
* @param \DateTime $end
* @return Timesheet
*/
public function setEnd($end)
public function setEnd(?\DateTime $end)
{
$this->end = $end;
if (null === $end) {
$this->duration = 0;
$this->rate = 0;
} else {
$this->timezone = $end->getTimezone()->getName();
}
return $this;
}
/**
* Set duration
*
* @param int $duration
* @return Timesheet
*/
@@ -194,8 +231,7 @@ class Timesheet
}
/**
* Get duration
* Do not rely on the results of this method for active records.
* Do not rely on the results of this method for running records.
*
* @return int
*/
@@ -205,8 +241,6 @@ class Timesheet
}
/**
* Set user
*
* @param User $user
* @return Timesheet
*/
@@ -218,8 +252,6 @@ class Timesheet
}
/**
* Get user
*
* @return User
*/
public function getUser()
@@ -228,8 +260,6 @@ class Timesheet
}
/**
* Set activity
*
* @param Activity $activity
* @return Timesheet
*/
@@ -241,8 +271,6 @@ class Timesheet
}
/**
* Get Activity
*
* @return Activity
*/
public function getActivity()
@@ -373,74 +401,24 @@ class Timesheet
}
/**
* @param ExecutionContextInterface $context
* @param $payload
* @return string
*/
public function validate(ExecutionContextInterface $context, $payload)
public function getTimezone(): string
{
if (null === ($activity = $this->getActivity())) {
$context->buildViolation('A timesheet must have an activity.')
->atPath('activity')
->setTranslationDomain('validators')
->addViolation();
}
return $this->timezone;
}
if (null === ($project = $this->getProject())) {
$context->buildViolation('A timesheet must have a project.')
->atPath('project')
->setTranslationDomain('validators')
->addViolation();
}
/**
* BE WARNED: this method should NOT be used programmatically, there is very likely no reason for it!
*
* @deprecated since it was introduced, only meant for the initial migration. Will be removed with 1.0.
* @param string $timezone
* @return Timesheet
*/
public function setTimezone(string $timezone)
{
$this->timezone = $timezone;
if (null !== $activity && null !== $project) {
if (null !== $activity->getProject() && $activity->getProject() !== $project) {
$context->buildViolation('Project mismatch, project specific activity and timesheet project are different.')
->atPath('project')
->setTranslationDomain('validators')
->addViolation();
}
if (null === $this->getEnd() && $activity->getVisible() === false) {
$context->buildViolation('Cannot start a disabled activity.')
->atPath('activity')
->setTranslationDomain('validators')
->addViolation();
}
if (null === $this->getEnd() && $project->getVisible() === false) {
$context->buildViolation('Cannot start a disabled project.')
->atPath('project')
->setTranslationDomain('validators')
->addViolation();
}
if (null === $this->getEnd() && $project->getCustomer()->getVisible() === false) {
$context->buildViolation('Cannot start a disabled customer.')
->atPath('customer')
->setTranslationDomain('validators')
->addViolation();
}
}
if (null === $this->getBegin()) {
$context->buildViolation('You must submit a begin date.')
->atPath('begin')
->setTranslationDomain('validators')
->addViolation();
} else {
if (null !== $this->getBegin() && null !== $this->getEnd() && $this->getEnd()->getTimestamp() < $this->getBegin()->getTimestamp()) {
$context->buildViolation('End date must not be earlier then start date.')
->atPath('end')
->setTranslationDomain('validators')
->addViolation();
}
if (time() < $this->getBegin()->getTimestamp()) {
$context->buildViolation('The begin date cannot be in the future.')
->atPath('begin')
->setTranslationDomain('validators')
->addViolation();
}
}
return $this;
}
}