default value for billable flag and support in batch update (#2851)
This commit is contained in:
@@ -232,6 +232,11 @@ class SystemConfiguration implements SystemBundleConfiguration
|
||||
return (string) $this->find('timesheet.default_begin');
|
||||
}
|
||||
|
||||
public function getTimesheetDefaultBillable(): bool
|
||||
{
|
||||
return (bool) $this->find('defaults.timesheet.billable');
|
||||
}
|
||||
|
||||
public function isTimesheetAllowFutureTimes(): bool
|
||||
{
|
||||
return (bool) $this->find('timesheet.rules.allow_future_times');
|
||||
|
||||
@@ -382,6 +382,10 @@ final class SystemConfigurationController extends AbstractController
|
||||
->setConstraints([
|
||||
new GreaterThanOrEqual(['value' => 0])
|
||||
]),
|
||||
(new Configuration())
|
||||
->setName('defaults.timesheet.billable')
|
||||
->setType(YesNoType::class)
|
||||
->setOptions(['help' => 'default_value_new', 'label' => 'label.billable']),
|
||||
]),
|
||||
(new SystemConfigurationModel())
|
||||
->setSection(SystemConfigurationModel::SECTION_LOCKDOWN)
|
||||
|
||||
@@ -364,6 +364,10 @@ abstract class TimesheetAbstractController extends AbstractController
|
||||
$timesheet->setExported($dto->isExported());
|
||||
$execute = true;
|
||||
}
|
||||
if (null !== $dto->isBillable()) {
|
||||
$timesheet->setBillable($dto->isBillable());
|
||||
$execute = true;
|
||||
}
|
||||
|
||||
if ($dto->isRecalculateRates()) {
|
||||
$timesheet->setFixedRate(null);
|
||||
|
||||
@@ -635,6 +635,12 @@ class Configuration implements ConfigurationInterface
|
||||
->scalarNode('currency')->defaultValue(Customer::DEFAULT_CURRENCY)->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('timesheet')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->booleanNode('billable')->defaultTrue()->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('user')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
|
||||
@@ -207,6 +207,17 @@ class TimesheetMultiUpdate extends AbstractType
|
||||
]);
|
||||
}
|
||||
|
||||
if ($options['include_billable']) {
|
||||
$builder->add('billable', ChoiceType::class, [
|
||||
'label' => 'label.billable',
|
||||
'choices' => [
|
||||
'' => null,
|
||||
'yes' => true,
|
||||
'no' => false,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
if ($options['include_rate']) {
|
||||
$builder
|
||||
->add('recalculateRates', YesNoType::class, [
|
||||
@@ -279,6 +290,7 @@ class TimesheetMultiUpdate extends AbstractType
|
||||
'include_user' => false,
|
||||
'include_rate' => false,
|
||||
'include_exported' => false,
|
||||
'include_billable' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ use Doctrine\Common\Collections\Collection;
|
||||
|
||||
/**
|
||||
* @App\Validator\Constraints\TimesheetMultiUpdate
|
||||
* @internal
|
||||
*/
|
||||
class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithMetaFields
|
||||
{
|
||||
@@ -57,6 +58,10 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
* @var bool|null
|
||||
*/
|
||||
private $exported = null;
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private $billable = null;
|
||||
/**
|
||||
* @var float|null
|
||||
*/
|
||||
@@ -84,11 +89,9 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
return $this->customer;
|
||||
}
|
||||
|
||||
public function setCustomer(Customer $customer): TimesheetMultiUpdateDTO
|
||||
public function setCustomer(Customer $customer): void
|
||||
{
|
||||
$this->customer = $customer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProject(): ?Project
|
||||
@@ -96,11 +99,9 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
return $this->project;
|
||||
}
|
||||
|
||||
public function setProject(Project $project): TimesheetMultiUpdateDTO
|
||||
public function setProject(Project $project): void
|
||||
{
|
||||
$this->project = $project;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActivity(): ?Activity
|
||||
@@ -108,11 +109,9 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
return $this->activity;
|
||||
}
|
||||
|
||||
public function setActivity(Activity $activity): TimesheetMultiUpdateDTO
|
||||
public function setActivity(Activity $activity): void
|
||||
{
|
||||
$this->activity = $activity;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,11 +122,9 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
public function setTags(iterable $tags): TimesheetMultiUpdateDTO
|
||||
public function setTags(iterable $tags): void
|
||||
{
|
||||
$this->tags = $tags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUser(): ?User
|
||||
@@ -135,11 +132,9 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function setUser(User $user): TimesheetMultiUpdateDTO
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isExported(): ?bool
|
||||
@@ -147,11 +142,19 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
return $this->exported;
|
||||
}
|
||||
|
||||
public function setExported(bool $exported): TimesheetMultiUpdateDTO
|
||||
public function setExported(?bool $exported): void
|
||||
{
|
||||
$this->exported = $exported;
|
||||
}
|
||||
|
||||
return $this;
|
||||
public function isBillable(): ?bool
|
||||
{
|
||||
return $this->billable;
|
||||
}
|
||||
|
||||
public function setBillable(?bool $billable): void
|
||||
{
|
||||
$this->billable = $billable;
|
||||
}
|
||||
|
||||
public function isRecalculateRates(): bool
|
||||
@@ -159,11 +162,9 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
return $this->recalculateRates;
|
||||
}
|
||||
|
||||
public function setRecalculateRates(bool $recalculateRates): TimesheetMultiUpdateDTO
|
||||
public function setRecalculateRates(bool $recalculateRates): void
|
||||
{
|
||||
$this->recalculateRates = $recalculateRates;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isReplaceTags(): bool
|
||||
@@ -171,11 +172,9 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
return $this->replaceTags;
|
||||
}
|
||||
|
||||
public function setReplaceTags(bool $replaceTags): TimesheetMultiUpdateDTO
|
||||
public function setReplaceTags(bool $replaceTags): void
|
||||
{
|
||||
$this->replaceTags = $replaceTags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFixedRate(): ?float
|
||||
@@ -183,11 +182,9 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
return $this->fixedRate;
|
||||
}
|
||||
|
||||
public function setFixedRate(?float $fixedRate): TimesheetMultiUpdateDTO
|
||||
public function setFixedRate(?float $fixedRate): void
|
||||
{
|
||||
$this->fixedRate = $fixedRate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHourlyRate(): ?float
|
||||
@@ -195,11 +192,9 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO implements EntityWithM
|
||||
return $this->hourlyRate;
|
||||
}
|
||||
|
||||
public function setHourlyRate(?float $hourlyRate): TimesheetMultiUpdateDTO
|
||||
public function setHourlyRate(?float $hourlyRate): void
|
||||
{
|
||||
$this->hourlyRate = $hourlyRate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -110,6 +110,8 @@ final class TimesheetService
|
||||
$mode = $this->trackingModeService->getActiveMode();
|
||||
$mode->create($timesheet, $request);
|
||||
|
||||
$timesheet->setBillable($this->configuration->getTimesheetDefaultBillable());
|
||||
|
||||
return $timesheet;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
{{ form_row(form.exported) }}
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
{% if form.billable is defined %}
|
||||
<fieldset>
|
||||
{{ form_row(form.billable) }}
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
{% if form.recalculateRates is defined %}
|
||||
<fieldset>
|
||||
{{ form_row(form.recalculateRates) }}
|
||||
|
||||
@@ -140,6 +140,9 @@ class AppExtensionTest extends TestCase
|
||||
'templates/invoice/renderer/',
|
||||
],
|
||||
'kimai.defaults' => [
|
||||
'timesheet' => [
|
||||
'billable' => true,
|
||||
],
|
||||
'customer' => [
|
||||
'timezone' => null,
|
||||
'country' => 'DE',
|
||||
|
||||
@@ -395,6 +395,9 @@ class ConfigurationTest extends TestCase
|
||||
'dashboard' => [],
|
||||
'widgets' => [],
|
||||
'defaults' => [
|
||||
'timesheet' => [
|
||||
'billable' => true,
|
||||
],
|
||||
'customer' => [
|
||||
'timezone' => null,
|
||||
'country' => 'DE',
|
||||
|
||||
@@ -32,6 +32,7 @@ class TimesheetMultiUpdateDTOTest extends TestCase
|
||||
self::assertNull($sut->getAction());
|
||||
|
||||
self::assertNull($sut->isExported());
|
||||
self::assertNull($sut->isBillable());
|
||||
self::assertNull($sut->getProject());
|
||||
self::assertNull($sut->getAction());
|
||||
self::assertNull($sut->getCustomer());
|
||||
@@ -70,37 +71,44 @@ class TimesheetMultiUpdateDTOTest extends TestCase
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setEntities($entities));
|
||||
self::assertEquals($entities, $sut->getEntities());
|
||||
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setExported(true));
|
||||
self::assertNull($sut->isExported());
|
||||
$sut->setExported(true);
|
||||
self::assertTrue($sut->isExported());
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setExported(false));
|
||||
$sut->setExported(false);
|
||||
self::assertFalse($sut->isExported());
|
||||
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setTags(['foo', '0815']));
|
||||
self::assertNull($sut->isBillable());
|
||||
$sut->setBillable(true);
|
||||
self::assertTrue($sut->isBillable());
|
||||
$sut->setExported(false);
|
||||
self::assertFalse($sut->isExported());
|
||||
|
||||
$sut->setTags(['foo', '0815']);
|
||||
self::assertEquals(['foo', '0815'], $sut->getTags());
|
||||
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setReplaceTags(true));
|
||||
$sut->setReplaceTags(true);
|
||||
self::assertTrue($sut->isReplaceTags());
|
||||
|
||||
$user = (new User())->setUsername('sdfsdfsd');
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setUser($user));
|
||||
$sut->setUser($user);
|
||||
self::assertSame($user, $sut->getUser());
|
||||
|
||||
$activity = (new Activity())->setName('sdfsdfsd');
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setActivity($activity));
|
||||
$sut->setActivity($activity);
|
||||
self::assertSame($activity, $sut->getActivity());
|
||||
|
||||
$project = (new Project())->setName('sdfsdfsd');
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setProject($project));
|
||||
$sut->setProject($project);
|
||||
self::assertSame($project, $sut->getProject());
|
||||
|
||||
$customer = (new Customer())->setName('sdfsdfsd');
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setCustomer($customer));
|
||||
$sut->setCustomer($customer);
|
||||
self::assertSame($customer, $sut->getCustomer());
|
||||
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setFixedRate(12.78));
|
||||
$sut->setFixedRate(12.78);
|
||||
self::assertEquals(12.78, $sut->getFixedRate());
|
||||
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setHourlyRate(123.45));
|
||||
$sut->setHourlyRate(123.45);
|
||||
self::assertEquals(123.45, $sut->getHourlyRate());
|
||||
|
||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setUpdateMeta(['foo', 'bar']));
|
||||
|
||||
@@ -44,10 +44,8 @@ class TimesheetMultiUpdateValidatorTest extends ConstraintValidatorTestCase
|
||||
$activity->setProject($project1);
|
||||
|
||||
$timesheet = new TimesheetMultiUpdateDTO();
|
||||
$timesheet
|
||||
->setActivity($activity)
|
||||
->setProject($project2)
|
||||
;
|
||||
$timesheet->setActivity($activity);
|
||||
$timesheet->setProject($project2);
|
||||
|
||||
$this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage']));
|
||||
|
||||
@@ -90,10 +88,8 @@ class TimesheetMultiUpdateValidatorTest extends ConstraintValidatorTestCase
|
||||
public function testHourlyRateAndFixedRateInParallelAreNotAllowed()
|
||||
{
|
||||
$timesheet = new TimesheetMultiUpdateDTO();
|
||||
$timesheet
|
||||
->setHourlyRate(10.12)
|
||||
->setFixedRate(123.45)
|
||||
;
|
||||
$timesheet->setHourlyRate(10.12);
|
||||
$timesheet->setFixedRate(123.45);
|
||||
|
||||
$this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage']));
|
||||
|
||||
@@ -118,10 +114,8 @@ class TimesheetMultiUpdateValidatorTest extends ConstraintValidatorTestCase
|
||||
$activity->setProject($project);
|
||||
|
||||
$timesheet = new TimesheetMultiUpdateDTO();
|
||||
$timesheet
|
||||
->setActivity($activity)
|
||||
->setProject($project)
|
||||
;
|
||||
$timesheet->setActivity($activity);
|
||||
$timesheet->setProject($project);
|
||||
|
||||
$this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage']));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user