diff --git a/src/Configuration/SystemConfiguration.php b/src/Configuration/SystemConfiguration.php
index 07e58e94..49ad1e02 100644
--- a/src/Configuration/SystemConfiguration.php
+++ b/src/Configuration/SystemConfiguration.php
@@ -208,6 +208,11 @@ class SystemConfiguration implements SystemBundleConfiguration
return (string) $this->find('timesheet.rules.lockdown_grace_period');
}
+ public function getTimesheetLockdownTimeZone(): ?string
+ {
+ return $this->find('timesheet.rules.lockdown_period_timezone');
+ }
+
public function isTimesheetLockdownActive(): bool
{
return !empty($this->find('timesheet.rules.lockdown_period_start')) && !empty($this->find('timesheet.rules.lockdown_period_end'));
diff --git a/src/Controller/SystemConfigurationController.php b/src/Controller/SystemConfigurationController.php
index 226ed81e..731fc387 100644
--- a/src/Controller/SystemConfigurationController.php
+++ b/src/Controller/SystemConfigurationController.php
@@ -22,6 +22,7 @@ use App\Form\Type\LanguageType;
use App\Form\Type\MinuteIncrementType;
use App\Form\Type\RoundingModeType;
use App\Form\Type\SkinType;
+use App\Form\Type\TimezoneType;
use App\Form\Type\TrackingModeType;
use App\Form\Type\WeekDaysType;
use App\Form\Type\YesNoType;
@@ -37,7 +38,6 @@ use Symfony\Component\Form\Extension\Core\Type\CountryType;
use Symfony\Component\Form\Extension\Core\Type\CurrencyType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
-use Symfony\Component\Form\Extension\Core\Type\TimezoneType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@@ -232,18 +232,32 @@ final class SystemConfigurationController extends AbstractController
$dateFormat = 'D, d M Y H:i:s';
if ($this->configurations->isTimesheetLockdownActive()) {
+ $userTimezone = $this->getDateTimeFactory()->getTimezone();
+ $timezone = $this->configurations->getTimesheetLockdownTimeZone();
+
+ if ($timezone !== null) {
+ $timezone = new \DateTimeZone($timezone);
+ }
+
+ if ($timezone === null) {
+ $timezone = $userTimezone;
+ }
+
try {
if (!empty($this->configurations->getTimesheetLockdownPeriodStart())) {
- $lockdownStartHelp = $this->getDateTimeFactory()->createDateTime($this->configurations->getTimesheetLockdownPeriodStart());
+ $lockdownStartHelp = new \DateTime($this->configurations->getTimesheetLockdownPeriodStart(), $timezone);
+ $lockdownStartHelp->setTimezone($userTimezone);
$lockdownStartHelp = $lockdownStartHelp->format($dateFormat);
}
if (!empty($this->configurations->getTimesheetLockdownPeriodEnd())) {
- $lockdownEndHelp = $this->getDateTimeFactory()->createDateTime($this->configurations->getTimesheetLockdownPeriodEnd());
+ $lockdownEndHelp = new \DateTime($this->configurations->getTimesheetLockdownPeriodEnd(), $timezone);
if (!empty($this->configurations->getTimesheetLockdownGracePeriod())) {
$lockdownGraceHelp = clone $lockdownEndHelp;
$lockdownGraceHelp->modify($this->configurations->getTimesheetLockdownGracePeriod());
+ $lockdownGraceHelp->setTimezone($userTimezone);
$lockdownGraceHelp = $lockdownGraceHelp->format($dateFormat);
}
+ $lockdownEndHelp->setTimezone($userTimezone);
$lockdownEndHelp = $lockdownEndHelp->format($dateFormat);
}
} catch (\Exception $ex) {
@@ -276,27 +290,6 @@ final class SystemConfigurationController extends AbstractController
->setName('timesheet.rules.allow_overbooking_budget')
->setType(CheckboxType::class)
->setTranslationDomain('system-configuration'),
- (new Configuration())
- ->setName('timesheet.rules.lockdown_period_start')
- ->setOptions(['help' => $lockdownStartHelp])
- ->setType(TextType::class)
- ->setRequired(false)
- ->setConstraints([new DateTimeFormat()])
- ->setTranslationDomain('system-configuration'),
- (new Configuration())
- ->setName('timesheet.rules.lockdown_period_end')
- ->setOptions(['help' => $lockdownEndHelp])
- ->setType(TextType::class)
- ->setRequired(false)
- ->setConstraints([new DateTimeFormat()])
- ->setTranslationDomain('system-configuration'),
- (new Configuration())
- ->setName('timesheet.rules.lockdown_grace_period')
- ->setOptions(['help' => $lockdownGraceHelp])
- ->setType(TextType::class)
- ->setRequired(false)
- ->setConstraints([new DateTimeFormat()])
- ->setTranslationDomain('system-configuration'),
(new Configuration())
->setName('timesheet.active_entries.hard_limit')
->setType(IntegerType::class)
@@ -327,6 +320,36 @@ final class SystemConfigurationController extends AbstractController
new GreaterThanOrEqual(['value' => 0])
]),
]),
+ (new SystemConfigurationModel())
+ ->setSection(SystemConfigurationModel::SECTION_LOCKDOWN)
+ ->setConfiguration([
+ (new Configuration())
+ ->setName('timesheet.rules.lockdown_period_start')
+ ->setOptions(['help' => $lockdownStartHelp])
+ ->setType(TextType::class)
+ ->setRequired(false)
+ ->setConstraints([new DateTimeFormat()])
+ ->setTranslationDomain('system-configuration'),
+ (new Configuration())
+ ->setName('timesheet.rules.lockdown_period_end')
+ ->setOptions(['help' => $lockdownEndHelp])
+ ->setType(TextType::class)
+ ->setRequired(false)
+ ->setConstraints([new DateTimeFormat()])
+ ->setTranslationDomain('system-configuration'),
+ (new Configuration())
+ ->setName('timesheet.rules.lockdown_period_timezone')
+ ->setType(TimezoneType::class)
+ ->setRequired(false)
+ ->setTranslationDomain('system-configuration'),
+ (new Configuration())
+ ->setName('timesheet.rules.lockdown_grace_period')
+ ->setOptions(['help' => $lockdownGraceHelp])
+ ->setType(TextType::class)
+ ->setRequired(false)
+ ->setConstraints([new DateTimeFormat()])
+ ->setTranslationDomain('system-configuration'),
+ ]),
(new SystemConfigurationModel())
->setSection(SystemConfigurationModel::SECTION_ROUNDING)
->setConfiguration([
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index 67ece1b0..31a7af76 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -235,6 +235,9 @@ class Configuration implements ConfigurationInterface
->scalarNode('lockdown_period_end')
->defaultNull()
->end()
+ ->scalarNode('lockdown_period_timezone')
+ ->defaultNull()
+ ->end()
->scalarNode('lockdown_grace_period')
->defaultNull()
->end()
diff --git a/src/EventSubscriber/UserPreferenceSubscriber.php b/src/EventSubscriber/UserPreferenceSubscriber.php
index 1c9fca18..bafcad7c 100644
--- a/src/EventSubscriber/UserPreferenceSubscriber.php
+++ b/src/EventSubscriber/UserPreferenceSubscriber.php
@@ -21,12 +21,12 @@ use App\Form\Type\LanguageType;
use App\Form\Type\ReportType;
use App\Form\Type\SkinType;
use App\Form\Type\ThemeLayoutType;
+use App\Form\Type\TimezoneType;
use App\Reporting\ReportingService;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
-use Symfony\Component\Form\Extension\Core\Type\TimezoneType;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Validator\Constraints\Range;
diff --git a/src/Form/CustomerEditForm.php b/src/Form/CustomerEditForm.php
index 21059272..3cb57bdb 100644
--- a/src/Form/CustomerEditForm.php
+++ b/src/Form/CustomerEditForm.php
@@ -11,13 +11,13 @@ namespace App\Form;
use App\Entity\Customer;
use App\Form\Type\MailType;
+use App\Form\Type\TimezoneType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CountryType;
use Symfony\Component\Form\Extension\Core\Type\CurrencyType;
use Symfony\Component\Form\Extension\Core\Type\TelType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
-use Symfony\Component\Form\Extension\Core\Type\TimezoneType;
use Symfony\Component\Form\Extension\Core\Type\UrlType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
diff --git a/src/Form/Model/SystemConfiguration.php b/src/Form/Model/SystemConfiguration.php
index 00fd19a4..de14ada9 100644
--- a/src/Form/Model/SystemConfiguration.php
+++ b/src/Form/Model/SystemConfiguration.php
@@ -12,6 +12,7 @@ namespace App\Form\Model;
class SystemConfiguration
{
public const SECTION_ROUNDING = 'rounding';
+ public const SECTION_LOCKDOWN = 'lockdown_period';
public const SECTION_TIMESHEET = 'timesheet';
public const SECTION_FORM_INVOICE = 'invoice';
public const SECTION_FORM_CUSTOMER = 'form_customer';
diff --git a/src/Form/Type/TimezoneType.php b/src/Form/Type/TimezoneType.php
new file mode 100644
index 00000000..e42c0b98
--- /dev/null
+++ b/src/Form/Type/TimezoneType.php
@@ -0,0 +1,37 @@
+setDefaults([
+ 'intl' => false,
+ ]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getParent()
+ {
+ return BaseTimezoneType::class;
+ }
+}
diff --git a/src/Form/UserEditType.php b/src/Form/UserEditType.php
index 24959e3f..da8f4c26 100644
--- a/src/Form/UserEditType.php
+++ b/src/Form/UserEditType.php
@@ -12,11 +12,11 @@ namespace App\Form;
use App\Entity\User;
use App\Form\Type\AvatarType;
use App\Form\Type\LanguageType;
+use App\Form\Type\TimezoneType;
use App\Form\Type\YesNoType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
-use Symfony\Component\Form\Extension\Core\Type\TimezoneType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
diff --git a/src/Timesheet/LockdownService.php b/src/Timesheet/LockdownService.php
index 9c5a1c1d..f55d9b08 100644
--- a/src/Timesheet/LockdownService.php
+++ b/src/Timesheet/LockdownService.php
@@ -55,10 +55,17 @@ final class LockdownService
$lockedStart = $this->configuration->getTimesheetLockdownPeriodStart();
$lockedEnd = $this->configuration->getTimesheetLockdownPeriodEnd();
$gracePeriod = $this->configuration->getTimesheetLockdownGracePeriod();
+ $timezone = $this->configuration->getTimesheetLockdownTimeZone();
+
+ if ($timezone === null) {
+ $timezone = $timesheetStart->getTimezone();
+ } else {
+ $timezone = new \DateTimeZone($timezone);
+ }
try {
- $lockdownStart = new \DateTime($lockedStart, $timesheetStart->getTimezone());
- $lockdownEnd = new \DateTime($lockedEnd, $timesheetStart->getTimezone());
+ $lockdownStart = new \DateTime($lockedStart, $timezone);
+ $lockdownEnd = new \DateTime($lockedEnd, $timezone);
$lockdownGrace = clone $lockdownEnd;
if (!empty($gracePeriod)) {
$lockdownGrace->modify($gracePeriod);
diff --git a/tests/Controller/SystemConfigurationControllerTest.php b/tests/Controller/SystemConfigurationControllerTest.php
index be1915ee..82b6beb3 100644
--- a/tests/Controller/SystemConfigurationControllerTest.php
+++ b/tests/Controller/SystemConfigurationControllerTest.php
@@ -72,6 +72,7 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
{
return [
['form[name=system_configuration_form_timesheet]', $this->createUrl('/admin/system-config/update/timesheet')],
+ ['form[name=system_configuration_form_lockdown_period]', $this->createUrl('/admin/system-config/update/lockdown_period')],
['form[name=system_configuration_form_invoice]', $this->createUrl('/admin/system-config/update/invoice')],
['form[name=system_configuration_form_rounding]', $this->createUrl('/admin/system-config/update/rounding')],
['form[name=system_configuration_form_form_customer]', $this->createUrl('/admin/system-config/update/form_customer')],
@@ -102,9 +103,6 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
['name' => 'timesheet.rules.allow_future_times', 'value' => false],
['name' => 'timesheet.rules.allow_overlapping_records', 'value' => false],
['name' => 'timesheet.rules.allow_overbooking_budget', 'value' => false],
- ['name' => 'timesheet.rules.lockdown_period_start', 'value' => null],
- ['name' => 'timesheet.rules.lockdown_period_end', 'value' => null],
- ['name' => 'timesheet.rules.lockdown_grace_period', 'value' => null],
['name' => 'timesheet.active_entries.hard_limit', 'value' => 99],
['name' => 'timesheet.active_entries.soft_limit', 'value' => 77],
]
@@ -124,6 +122,41 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
$this->assertEquals(77, $configService->find('timesheet.active_entries.soft_limit'));
}
+ public function testUpdateLockdownPeriodConfig()
+ {
+ $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
+ $this->assertAccessIsGranted($client, '/admin/system-config/');
+
+ $configService = static::$kernel->getContainer()->get(SystemConfiguration::class);
+ $this->assertNull($configService->find('timesheet.rules.lockdown_period_start'));
+ $this->assertNull($configService->find('timesheet.rules.lockdown_period_end'));
+ $this->assertNull($configService->find('timesheet.rules.lockdown_period_timezone'));
+ $this->assertNull($configService->find('timesheet.rules.lockdown_grace_period'));
+
+ $form = $client->getCrawler()->filter('form[name=system_configuration_form_lockdown_period]')->form();
+ $client->submit($form, [
+ 'system_configuration_form_lockdown_period' => [
+ 'configuration' => [
+ ['name' => 'timesheet.rules.lockdown_period_start', 'value' => 'first day of last month 01:23:45'],
+ ['name' => 'timesheet.rules.lockdown_period_end', 'value' => 'last day of last month 23:01:45'],
+ ['name' => 'timesheet.rules.lockdown_period_timezone', 'value' => 'Africa/Bangui'],
+ ['name' => 'timesheet.rules.lockdown_grace_period', 'value' => '+ 12 hours'],
+ ]
+ ]
+ ]);
+
+ $this->assertIsRedirect($client, $this->createUrl('/admin/system-config/'));
+ $client->followRedirect();
+ $this->assertTrue($client->getResponse()->isSuccessful());
+ $this->assertHasFlashSaveSuccess($client);
+
+ $configService = static::$kernel->getContainer()->get(SystemConfiguration::class);
+ $this->assertEquals('first day of last month 01:23:45', $configService->find('timesheet.rules.lockdown_period_start'));
+ $this->assertEquals('last day of last month 23:01:45', $configService->find('timesheet.rules.lockdown_period_end'));
+ $this->assertEquals('Africa/Bangui', $configService->find('timesheet.rules.lockdown_period_timezone'));
+ $this->assertEquals('+ 12 hours', $configService->find('timesheet.rules.lockdown_grace_period'));
+ }
+
public function testUpdateTimesheetConfigValidation()
{
$this->assertFormHasValidationError(
@@ -138,9 +171,6 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
['name' => 'timesheet.rules.allow_future_times', 'value' => 1],
['name' => 'timesheet.rules.allow_overlapping_records', 'value' => 1],
['name' => 'timesheet.rules.allow_overbooking_budget', 'value' => 1],
- ['name' => 'timesheet.rules.lockdown_period_start', 'value' => 'first day of last month'],
- ['name' => 'timesheet.rules.lockdown_period_end', 'value' => 'first day of last month'],
- ['name' => 'timesheet.rules.lockdown_grace_period', 'value' => '+10 days'],
['name' => 'timesheet.active_entries.hard_limit', 'value' => -1],
['name' => 'timesheet.active_entries.soft_limit', 'value' => -1],
]
@@ -148,8 +178,8 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
],
[
'#system_configuration_form_timesheet_configuration_0_value', // mode
- '#system_configuration_form_timesheet_configuration_8_value', // hard_limit
- '#system_configuration_form_timesheet_configuration_9_value', // soft_limit
+ '#system_configuration_form_timesheet_configuration_5_value', // hard_limit
+ '#system_configuration_form_timesheet_configuration_6_value', // soft_limit
],
true
);
diff --git a/tests/Controller/TimesheetControllerTest.php b/tests/Controller/TimesheetControllerTest.php
index 29f10b69..79764a5e 100644
--- a/tests/Controller/TimesheetControllerTest.php
+++ b/tests/Controller/TimesheetControllerTest.php
@@ -375,9 +375,6 @@ class TimesheetControllerTest extends ControllerBaseTest
['name' => 'timesheet.rules.allow_future_times', 'value' => true],
['name' => 'timesheet.rules.allow_overlapping_records', 'value' => false],
['name' => 'timesheet.rules.allow_overbooking_budget', 'value' => true],
- ['name' => 'timesheet.rules.lockdown_period_start', 'value' => null],
- ['name' => 'timesheet.rules.lockdown_period_end', 'value' => null],
- ['name' => 'timesheet.rules.lockdown_grace_period', 'value' => null],
['name' => 'timesheet.active_entries.hard_limit', 'value' => 1],
['name' => 'timesheet.active_entries.soft_limit', 'value' => 1],
]
diff --git a/tests/DependencyInjection/AppExtensionTest.php b/tests/DependencyInjection/AppExtensionTest.php
index c91bef61..599d652a 100644
--- a/tests/DependencyInjection/AppExtensionTest.php
+++ b/tests/DependencyInjection/AppExtensionTest.php
@@ -207,6 +207,7 @@ class AppExtensionTest extends TestCase
'lockdown_period_end' => null,
'lockdown_grace_period' => null,
'allow_overbooking_budget' => true,
+ 'lockdown_period_timezone' => null,
],
'default_begin' => 'now',
'duration_increment' => null,
diff --git a/tests/DependencyInjection/ConfigurationTest.php b/tests/DependencyInjection/ConfigurationTest.php
index f55f96de..6f7b351f 100644
--- a/tests/DependencyInjection/ConfigurationTest.php
+++ b/tests/DependencyInjection/ConfigurationTest.php
@@ -286,6 +286,7 @@ class ConfigurationTest extends TestCase
'lockdown_period_end' => null,
'lockdown_grace_period' => null,
'allow_overbooking_budget' => true,
+ 'lockdown_period_timezone' => null,
],
'duration_increment' => null,
'time_increment' => null,
diff --git a/tests/Timesheet/LockdownServiceTest.php b/tests/Timesheet/LockdownServiceTest.php
index bb37e295..fbaf6f9c 100644
--- a/tests/Timesheet/LockdownServiceTest.php
+++ b/tests/Timesheet/LockdownServiceTest.php
@@ -20,7 +20,7 @@ use PHPUnit\Framework\TestCase;
*/
class LockdownServiceTest extends TestCase
{
- protected function createService(?string $start, ?string $end, ?string $grace)
+ protected function createService(?string $start, ?string $end, ?string $grace, ?string $timezone = null)
{
$loader = $this->createMock(ConfigLoaderInterface::class);
$config = new SystemConfiguration($loader, [
@@ -28,6 +28,7 @@ class LockdownServiceTest extends TestCase
'rules' => [
'lockdown_period_start' => $start,
'lockdown_period_end' => $end,
+ 'lockdown_period_timezone' => $timezone,
'lockdown_grace_period' => $grace,
],
]
diff --git a/translations/system-configuration.de.xlf b/translations/system-configuration.de.xlf
index be07e9e4..dc31f486 100644
--- a/translations/system-configuration.de.xlf
+++ b/translations/system-configuration.de.xlf
@@ -74,6 +74,14 @@
label.timesheet.rules.allow_overlapping_records
Erlaube überlappende Zeiteinträge
+
+ lockdown_period
+ Gesperrter Zeitraum
+
+
+ label.timesheet.rules.lockdown_period_timezone
+ Zeitzone (falls leer, wird Zeitzone des jeweiligen Benutzers verwendet)
+
label.timesheet.rules.lockdown_period_start
Start des gesperrten Zeitraums (relatives PHP Datumsformat)
diff --git a/translations/system-configuration.en.xlf b/translations/system-configuration.en.xlf
index 513b10f3..6ee7fe3e 100644
--- a/translations/system-configuration.en.xlf
+++ b/translations/system-configuration.en.xlf
@@ -74,6 +74,14 @@
label.timesheet.rules.allow_overlapping_records
Allow overlapping time entries
+
+ lockdown_period
+ Lockdown period
+
+
+ label.timesheet.rules.lockdown_period_timezone
+ Time zone (if empty, time zone of the respective user is used)
+
label.timesheet.rules.lockdown_period_start
Lockdown period start (PHP relative date to now)