set rates via batch update (#1326)
This commit is contained in:
@@ -343,6 +343,15 @@ abstract class TimesheetAbstractController extends AbstractController
|
|||||||
$timesheet->setExported($dto->isExported());
|
$timesheet->setExported($dto->isExported());
|
||||||
$execute = true;
|
$execute = true;
|
||||||
}
|
}
|
||||||
|
if (null !== $dto->getHourlyRate()) {
|
||||||
|
$timesheet->setFixedRate(null);
|
||||||
|
$timesheet->setHourlyRate($dto->getHourlyRate());
|
||||||
|
$execute = true;
|
||||||
|
} elseif (null !== $dto->getFixedRate()) {
|
||||||
|
$timesheet->setFixedRate($dto->getFixedRate());
|
||||||
|
$timesheet->setHourlyRate(null);
|
||||||
|
$execute = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($execute) {
|
if ($execute) {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace App\Form\MultiUpdate;
|
|||||||
|
|
||||||
use App\Form\Type\ActivityType;
|
use App\Form\Type\ActivityType;
|
||||||
use App\Form\Type\CustomerType;
|
use App\Form\Type\CustomerType;
|
||||||
|
use App\Form\Type\FixedRateType;
|
||||||
|
use App\Form\Type\HourlyRateType;
|
||||||
use App\Form\Type\ProjectType;
|
use App\Form\Type\ProjectType;
|
||||||
use App\Form\Type\TagsInputType;
|
use App\Form\Type\TagsInputType;
|
||||||
use App\Form\Type\UserType;
|
use App\Form\Type\UserType;
|
||||||
@@ -57,6 +59,7 @@ class TimesheetMultiUpdate extends AbstractType
|
|||||||
$activity = null;
|
$activity = null;
|
||||||
$project = null;
|
$project = null;
|
||||||
$customer = null;
|
$customer = null;
|
||||||
|
$currency = null;
|
||||||
$customerCount = $this->customers->countCustomer(true);
|
$customerCount = $this->customers->countCustomer(true);
|
||||||
|
|
||||||
if (isset($options['data'])) {
|
if (isset($options['data'])) {
|
||||||
@@ -70,6 +73,10 @@ class TimesheetMultiUpdate extends AbstractType
|
|||||||
if (null === $project && null !== $activity) {
|
if (null === $project && null !== $activity) {
|
||||||
$project = $activity->getProject();
|
$project = $activity->getProject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== $customer) {
|
||||||
|
$currency = $customer->getCurrency();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
@@ -189,6 +196,14 @@ class TimesheetMultiUpdate extends AbstractType
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$builder
|
||||||
|
->add('fixedRate', FixedRateType::class, [
|
||||||
|
'currency' => $currency,
|
||||||
|
])
|
||||||
|
->add('hourlyRate', HourlyRateType::class, [
|
||||||
|
'currency' => $currency,
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('entities', HiddenType::class, [
|
$builder->add('entities', HiddenType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -49,6 +49,14 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO
|
|||||||
* @var bool|null
|
* @var bool|null
|
||||||
*/
|
*/
|
||||||
private $exported = null;
|
private $exported = null;
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $fixedRate;
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $hourlyRate;
|
||||||
|
|
||||||
public function getCustomer(): ?Customer
|
public function getCustomer(): ?Customer
|
||||||
{
|
{
|
||||||
@@ -136,4 +144,28 @@ class TimesheetMultiUpdateDTO extends MultiUpdateTableDTO
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFixedRate(): ?float
|
||||||
|
{
|
||||||
|
return $this->fixedRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFixedRate(?float $fixedRate): TimesheetMultiUpdateDTO
|
||||||
|
{
|
||||||
|
$this->fixedRate = $fixedRate;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHourlyRate(): ?float
|
||||||
|
{
|
||||||
|
return $this->hourlyRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHourlyRate(?float $hourlyRate): TimesheetMultiUpdateDTO
|
||||||
|
{
|
||||||
|
$this->hourlyRate = $hourlyRate;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,22 @@ use Symfony\Component\Validator\Constraint;
|
|||||||
*/
|
*/
|
||||||
class TimesheetMultiUpdate extends Constraint
|
class TimesheetMultiUpdate extends Constraint
|
||||||
{
|
{
|
||||||
public const MISSING_ACTIVITY_ERROR = 'yd5hffg-dsfef3-426a-83d7-1f2d33hs5d84';
|
public const MISSING_ACTIVITY_ERROR = 'ts-multi-update-84';
|
||||||
public const MISSING_PROJECT_ERROR = 'yd5hffg-dsfef3-426a-83d7-1f2d33hs5d85';
|
public const MISSING_PROJECT_ERROR = 'ts-multi-update-85';
|
||||||
public const ACTIVITY_PROJECT_MISMATCH_ERROR = 'xy5hffg-dsfef3-426a-83d7-1f2d33hs5d86';
|
public const ACTIVITY_PROJECT_MISMATCH_ERROR = 'ts-multi-update-86';
|
||||||
public const DISABLED_ACTIVITY_ERROR = 'yd5hffg-dsfef3-426a-83d7-1f2d33hs5d87';
|
public const DISABLED_ACTIVITY_ERROR = 'ts-multi-update-87';
|
||||||
public const DISABLED_PROJECT_ERROR = 'yd5hffg-dsfef3-426a-83d7-1f2d33hs5d88';
|
public const DISABLED_PROJECT_ERROR = 'ts-multi-update-88';
|
||||||
public const DISABLED_CUSTOMER_ERROR = 'yd5hffg-dsfef3-426a-83d7-1f2d33hs5d89';
|
public const DISABLED_CUSTOMER_ERROR = 'ts-multi-update-89';
|
||||||
|
public const HOURLY_RATE_FIXED_RATE = 'ts-multi-update-90';
|
||||||
|
|
||||||
protected static $errorNames = [
|
protected static $errorNames = [
|
||||||
self::MISSING_ACTIVITY_ERROR => 'A timesheet must have an activity.',
|
self::MISSING_ACTIVITY_ERROR => 'You need to choose an activity, if the project should be changed.',
|
||||||
self::MISSING_PROJECT_ERROR => 'A timesheet must have a project.',
|
self::MISSING_PROJECT_ERROR => 'A timesheet must have a project.',
|
||||||
self::ACTIVITY_PROJECT_MISMATCH_ERROR => 'Project mismatch: chosen project does not match the activity project.',
|
self::ACTIVITY_PROJECT_MISMATCH_ERROR => 'Project mismatch: chosen project does not match the activity project.',
|
||||||
self::DISABLED_ACTIVITY_ERROR => 'Cannot start a disabled activity.',
|
self::DISABLED_ACTIVITY_ERROR => 'Cannot start a disabled activity.',
|
||||||
self::DISABLED_PROJECT_ERROR => 'Cannot start a disabled project.',
|
self::DISABLED_PROJECT_ERROR => 'Cannot start a disabled project.',
|
||||||
self::DISABLED_CUSTOMER_ERROR => 'Cannot start a disabled customer.',
|
self::DISABLED_CUSTOMER_ERROR => 'Cannot start a disabled customer.',
|
||||||
|
self::HOURLY_RATE_FIXED_RATE => 'Cannot set hourly rate and fixed rate at the same time.',
|
||||||
];
|
];
|
||||||
|
|
||||||
public $message = 'This form has invalid settings.';
|
public $message = 'This form has invalid settings.';
|
||||||
|
|||||||
@@ -9,43 +9,22 @@
|
|||||||
|
|
||||||
namespace App\Validator\Constraints;
|
namespace App\Validator\Constraints;
|
||||||
|
|
||||||
use App\Configuration\TimesheetConfiguration;
|
|
||||||
use App\Form\MultiUpdate\TimesheetMultiUpdateDTO;
|
use App\Form\MultiUpdate\TimesheetMultiUpdateDTO;
|
||||||
use App\Validator\Constraints\TimesheetMultiUpdate as TimesheetConstraint;
|
use App\Validator\Constraints\TimesheetMultiUpdate as TimesheetMultiUpdateConstraint;
|
||||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
use Symfony\Component\Validator\ConstraintValidator;
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||||
|
|
||||||
class TimesheetMultiUpdateValidator extends ConstraintValidator
|
final class TimesheetMultiUpdateValidator extends ConstraintValidator
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var AuthorizationCheckerInterface
|
|
||||||
*/
|
|
||||||
protected $auth;
|
|
||||||
/**
|
|
||||||
* @var TimesheetConfiguration
|
|
||||||
*/
|
|
||||||
protected $configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param AuthorizationCheckerInterface $auth
|
|
||||||
* @param TimesheetConfiguration $configuration
|
|
||||||
*/
|
|
||||||
public function __construct(AuthorizationCheckerInterface $auth, TimesheetConfiguration $configuration)
|
|
||||||
{
|
|
||||||
$this->auth = $auth;
|
|
||||||
$this->configuration = $configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param TimesheetMultiUpdateDTO|mixed $value
|
* @param TimesheetMultiUpdateDTO|mixed $value
|
||||||
* @param Constraint $constraint
|
* @param Constraint $constraint
|
||||||
*/
|
*/
|
||||||
public function validate($value, Constraint $constraint)
|
public function validate($value, Constraint $constraint)
|
||||||
{
|
{
|
||||||
if (!($constraint instanceof TimesheetConstraint)) {
|
if (!($constraint instanceof TimesheetMultiUpdateConstraint)) {
|
||||||
throw new UnexpectedTypeException($constraint, __NAMESPACE__ . '\TimesheetMultiUpdate');
|
throw new UnexpectedTypeException($constraint, __NAMESPACE__ . '\TimesheetMultiUpdate');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +33,20 @@ class TimesheetMultiUpdateValidator extends ConstraintValidator
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->validateActivityAndProject($value, $this->context);
|
$this->validateActivityAndProject($value, $this->context);
|
||||||
|
|
||||||
|
if (null !== $value->getFixedRate() && null !== $value->getHourlyRate()) {
|
||||||
|
$this->context->buildViolation('Cannot set hourly rate and fixed rate at the same time.')
|
||||||
|
->atPath('fixedRate')
|
||||||
|
->setTranslationDomain('validators')
|
||||||
|
->setCode(TimesheetMultiUpdateConstraint::HOURLY_RATE_FIXED_RATE)
|
||||||
|
->addViolation();
|
||||||
|
|
||||||
|
$this->context->buildViolation('Cannot set hourly rate and fixed rate at the same time.')
|
||||||
|
->atPath('hourlyRate')
|
||||||
|
->setTranslationDomain('validators')
|
||||||
|
->setCode(TimesheetMultiUpdateConstraint::HOURLY_RATE_FIXED_RATE)
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,20 +60,24 @@ class TimesheetMultiUpdateValidator extends ConstraintValidator
|
|||||||
|
|
||||||
// non global activity without project
|
// non global activity without project
|
||||||
if (null !== $activity && null !== $activity->getProject() && null === $project) {
|
if (null !== $activity && null !== $activity->getProject() && null === $project) {
|
||||||
$context->buildViolation('Missing project')
|
$context->buildViolation('Missing project.')
|
||||||
->atPath('project')
|
->atPath('project')
|
||||||
->setTranslationDomain('validators')
|
->setTranslationDomain('validators')
|
||||||
->setCode(TimesheetConstraint::MISSING_PROJECT_ERROR)
|
->setCode(TimesheetMultiUpdateConstraint::MISSING_PROJECT_ERROR)
|
||||||
->addViolation();
|
->addViolation();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only project was chosen
|
// only project was chosen
|
||||||
if (null === $activity && null !== $project) {
|
if (null === $activity && null !== $project) {
|
||||||
$context->buildViolation('Missing activity')
|
$context->buildViolation('You need to choose an activity, if the project should be changed.')
|
||||||
->atPath('project')
|
->atPath('activity')
|
||||||
->setTranslationDomain('validators')
|
->setTranslationDomain('validators')
|
||||||
->setCode(TimesheetConstraint::MISSING_ACTIVITY_ERROR)
|
->setCode(TimesheetMultiUpdateConstraint::MISSING_ACTIVITY_ERROR)
|
||||||
->addViolation();
|
->addViolation();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $activity) {
|
if (null !== $activity) {
|
||||||
@@ -88,15 +85,17 @@ class TimesheetMultiUpdateValidator extends ConstraintValidator
|
|||||||
$context->buildViolation('Project mismatch, project specific activity and timesheet project are different.')
|
$context->buildViolation('Project mismatch, project specific activity and timesheet project are different.')
|
||||||
->atPath('project')
|
->atPath('project')
|
||||||
->setTranslationDomain('validators')
|
->setTranslationDomain('validators')
|
||||||
->setCode(TimesheetConstraint::ACTIVITY_PROJECT_MISMATCH_ERROR)
|
->setCode(TimesheetMultiUpdateConstraint::ACTIVITY_PROJECT_MISMATCH_ERROR)
|
||||||
->addViolation();
|
->addViolation();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$activity->isVisible()) {
|
if (!$activity->isVisible()) {
|
||||||
$context->buildViolation('Cannot assign a disabled activity.')
|
$context->buildViolation('Cannot assign a disabled activity.')
|
||||||
->atPath('activity')
|
->atPath('activity')
|
||||||
->setTranslationDomain('validators')
|
->setTranslationDomain('validators')
|
||||||
->setCode(TimesheetConstraint::DISABLED_ACTIVITY_ERROR)
|
->setCode(TimesheetMultiUpdateConstraint::DISABLED_ACTIVITY_ERROR)
|
||||||
->addViolation();
|
->addViolation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,7 +105,7 @@ class TimesheetMultiUpdateValidator extends ConstraintValidator
|
|||||||
$context->buildViolation('Cannot assign a disabled project.')
|
$context->buildViolation('Cannot assign a disabled project.')
|
||||||
->atPath('project')
|
->atPath('project')
|
||||||
->setTranslationDomain('validators')
|
->setTranslationDomain('validators')
|
||||||
->setCode(TimesheetConstraint::DISABLED_PROJECT_ERROR)
|
->setCode(TimesheetMultiUpdateConstraint::DISABLED_PROJECT_ERROR)
|
||||||
->addViolation();
|
->addViolation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +113,7 @@ class TimesheetMultiUpdateValidator extends ConstraintValidator
|
|||||||
$context->buildViolation('Cannot assign a disabled customer.')
|
$context->buildViolation('Cannot assign a disabled customer.')
|
||||||
->atPath('customer')
|
->atPath('customer')
|
||||||
->setTranslationDomain('validators')
|
->setTranslationDomain('validators')
|
||||||
->setCode(TimesheetConstraint::DISABLED_CUSTOMER_ERROR)
|
->setCode(TimesheetMultiUpdateConstraint::DISABLED_CUSTOMER_ERROR)
|
||||||
->addViolation();
|
->addViolation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ class PermissionControllerTest extends ControllerBaseTest
|
|||||||
self::assertEquals(1, $permission->getRole()->getId());
|
self::assertEquals(1, $permission->getRole()->getId());
|
||||||
|
|
||||||
// flush the cache to prevent wrong results
|
// flush the cache to prevent wrong results
|
||||||
$em->clear(RolePermission::class);
|
$em->clear();
|
||||||
|
|
||||||
// update the permission
|
// update the permission
|
||||||
$this->request($client, '/admin/permissions/roles/1/view_user/0');
|
$this->request($client, '/admin/permissions/roles/1/view_user/0');
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class TagControllerTest extends ControllerBaseTest
|
|||||||
$this->assertIsRedirect($client, $this->createUrl('/admin/tags/'));
|
$this->assertIsRedirect($client, $this->createUrl('/admin/tags/'));
|
||||||
$client->followRedirect();
|
$client->followRedirect();
|
||||||
|
|
||||||
$em->clear(Tag::class);
|
$em->clear();
|
||||||
self::assertEquals(0, $em->getRepository(Tag::class)->count([]));
|
self::assertEquals(0, $em->getRepository(Tag::class)->count([]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ class TimesheetControllerTest extends ControllerBaseTest
|
|||||||
$this->assertIsRedirect($client, $this->createUrl('/timesheet/'));
|
$this->assertIsRedirect($client, $this->createUrl('/timesheet/'));
|
||||||
$client->followRedirect();
|
$client->followRedirect();
|
||||||
|
|
||||||
$em->clear(Timesheet::class);
|
$em->clear();
|
||||||
self::assertEquals(0, $em->getRepository(Timesheet::class)->count([]));
|
self::assertEquals(0, $em->getRepository(Timesheet::class)->count([]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,11 +404,12 @@ class TimesheetControllerTest extends ControllerBaseTest
|
|||||||
$client->submit($form, [
|
$client->submit($form, [
|
||||||
'timesheet_multi_update' => [
|
'timesheet_multi_update' => [
|
||||||
'exported' => true,
|
'exported' => true,
|
||||||
'tags' => 'test, foo-bar'
|
'tags' => 'test, foo-bar',
|
||||||
|
'fixedRate' => 13,
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$em->clear(Timesheet::class);
|
$em->clear();
|
||||||
|
|
||||||
/** @var Timesheet[] $timesheets */
|
/** @var Timesheet[] $timesheets */
|
||||||
$timesheets = $em->getRepository(Timesheet::class)->findAll();
|
$timesheets = $em->getRepository(Timesheet::class)->findAll();
|
||||||
@@ -416,6 +417,7 @@ class TimesheetControllerTest extends ControllerBaseTest
|
|||||||
foreach ($timesheets as $timesheet) {
|
foreach ($timesheets as $timesheet) {
|
||||||
self::assertCount(2, $timesheet->getTags());
|
self::assertCount(2, $timesheet->getTags());
|
||||||
self::assertTrue($timesheet->isExported());
|
self::assertTrue($timesheet->isExported());
|
||||||
|
self::assertEquals(13, $timesheet->getFixedRate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use App\Entity\TimesheetMeta;
|
|||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Form\Type\DateRangeType;
|
use App\Form\Type\DateRangeType;
|
||||||
use App\Tests\DataFixtures\TimesheetFixtures;
|
use App\Tests\DataFixtures\TimesheetFixtures;
|
||||||
|
use App\Timesheet\Util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group integration
|
* @group integration
|
||||||
@@ -276,7 +277,7 @@ class TimesheetTeamControllerTest extends ControllerBaseTest
|
|||||||
$this->assertIsRedirect($client, $this->createUrl('/team/timesheet/'));
|
$this->assertIsRedirect($client, $this->createUrl('/team/timesheet/'));
|
||||||
$client->followRedirect();
|
$client->followRedirect();
|
||||||
|
|
||||||
$em->clear(Timesheet::class);
|
$em->clear();
|
||||||
self::assertEquals(0, $em->getRepository(Timesheet::class)->count([]));
|
self::assertEquals(0, $em->getRepository(Timesheet::class)->count([]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,11 +324,12 @@ class TimesheetTeamControllerTest extends ControllerBaseTest
|
|||||||
'user' => $newUser->getId(),
|
'user' => $newUser->getId(),
|
||||||
'exported' => true,
|
'exported' => true,
|
||||||
'replaceTags' => true,
|
'replaceTags' => true,
|
||||||
'tags' => 'test, foo-bar, tralalala'
|
'tags' => 'test, foo-bar, tralalala',
|
||||||
|
'hourlyRate' => 13.78,
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$em->clear(Timesheet::class);
|
$em->clear();
|
||||||
|
|
||||||
/** @var Timesheet[] $timesheets */
|
/** @var Timesheet[] $timesheets */
|
||||||
$timesheets = $em->getRepository(Timesheet::class)->findAll();
|
$timesheets = $em->getRepository(Timesheet::class)->findAll();
|
||||||
@@ -336,6 +338,7 @@ class TimesheetTeamControllerTest extends ControllerBaseTest
|
|||||||
self::assertCount(3, $timesheet->getTags());
|
self::assertCount(3, $timesheet->getTags());
|
||||||
self::assertEquals($newUser->getId(), $timesheet->getUser()->getId());
|
self::assertEquals($newUser->getId(), $timesheet->getUser()->getId());
|
||||||
self::assertTrue($timesheet->isExported());
|
self::assertTrue($timesheet->isExported());
|
||||||
|
self::assertEquals(Util::calculateRate(13.78, $timesheet->getDuration()), $timesheet->getRate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ class UserControllerTest extends ControllerBaseTest
|
|||||||
$this->assertHasFlashDeleteSuccess($client);
|
$this->assertHasFlashDeleteSuccess($client);
|
||||||
|
|
||||||
// SQLIte does not necessarly support onCascade delete, so these timesheet will stay after deletion
|
// SQLIte does not necessarly support onCascade delete, so these timesheet will stay after deletion
|
||||||
// $em->clear(Timesheet::class);
|
// $em->clear();
|
||||||
// $timesheets = $em->getRepository(Timesheet::class)->count([]);
|
// $timesheets = $em->getRepository(Timesheet::class)->count([]);
|
||||||
// $this->assertEquals(0, $timesheets);
|
// $this->assertEquals(0, $timesheets);
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ class TimesheetMultiUpdateDTOTest extends TestCase
|
|||||||
self::assertEquals([], $sut->getTags());
|
self::assertEquals([], $sut->getTags());
|
||||||
self::assertNull($sut->getUser());
|
self::assertNull($sut->getUser());
|
||||||
self::assertFalse($sut->isReplaceTags());
|
self::assertFalse($sut->isReplaceTags());
|
||||||
|
self::assertNull($sut->getFixedRate());
|
||||||
|
self::assertNull($sut->getHourlyRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetterAndGetter()
|
public function testSetterAndGetter()
|
||||||
@@ -86,5 +88,11 @@ class TimesheetMultiUpdateDTOTest extends TestCase
|
|||||||
$customer = (new Customer())->setName('sdfsdfsd');
|
$customer = (new Customer())->setName('sdfsdfsd');
|
||||||
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setCustomer($customer));
|
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setCustomer($customer));
|
||||||
self::assertSame($customer, $sut->getCustomer());
|
self::assertSame($customer, $sut->getCustomer());
|
||||||
|
|
||||||
|
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setFixedRate(12.78));
|
||||||
|
self::assertEquals(12.78, $sut->getFixedRate());
|
||||||
|
|
||||||
|
self::assertInstanceOf(TimesheetMultiUpdateDTO::class, $sut->setHourlyRate(123.45));
|
||||||
|
self::assertEquals(123.45, $sut->getHourlyRate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
<?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\Tests\Validator\Constraints;
|
||||||
|
|
||||||
|
use App\Entity\Activity;
|
||||||
|
use App\Entity\Customer;
|
||||||
|
use App\Entity\Project;
|
||||||
|
use App\Form\MultiUpdate\TimesheetMultiUpdateDTO;
|
||||||
|
use App\Validator\Constraints\TimesheetMultiUpdate as TimesheetMultiUpdateConstraint;
|
||||||
|
use App\Validator\Constraints\TimesheetMultiUpdateValidator;
|
||||||
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
|
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \App\Validator\Constraints\TimesheetMultiUpdateValidator
|
||||||
|
*/
|
||||||
|
class TimesheetMultiUpdateValidatorTest extends ConstraintValidatorTestCase
|
||||||
|
{
|
||||||
|
protected function createValidator($isGranted = true)
|
||||||
|
{
|
||||||
|
return new TimesheetMultiUpdateValidator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConstraintIsInvalid()
|
||||||
|
{
|
||||||
|
$this->expectException(UnexpectedTypeException::class);
|
||||||
|
|
||||||
|
$this->validator->validate('foo', new NotBlank());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProjectMismatch()
|
||||||
|
{
|
||||||
|
$activity = new Activity();
|
||||||
|
$project1 = new Project();
|
||||||
|
$project2 = new Project();
|
||||||
|
$activity->setProject($project1);
|
||||||
|
|
||||||
|
$timesheet = new TimesheetMultiUpdateDTO();
|
||||||
|
$timesheet
|
||||||
|
->setActivity($activity)
|
||||||
|
->setProject($project2)
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage']));
|
||||||
|
|
||||||
|
$this->buildViolation('Project mismatch, project specific activity and timesheet project are different.')
|
||||||
|
->atPath('property.path.project')
|
||||||
|
->setCode(TimesheetMultiUpdateConstraint::ACTIVITY_PROJECT_MISMATCH_ERROR)
|
||||||
|
->assertRaised();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProjectWithoutActivity()
|
||||||
|
{
|
||||||
|
$timesheet = new TimesheetMultiUpdateDTO();
|
||||||
|
$timesheet
|
||||||
|
->setProject(new Project())
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage']));
|
||||||
|
|
||||||
|
$this->buildViolation('You need to choose an activity, if the project should be changed.')
|
||||||
|
->atPath('property.path.activity')
|
||||||
|
->setCode(TimesheetMultiUpdateConstraint::MISSING_ACTIVITY_ERROR)
|
||||||
|
->assertRaised();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testActivityWithoutProject()
|
||||||
|
{
|
||||||
|
$timesheet = new TimesheetMultiUpdateDTO();
|
||||||
|
$timesheet
|
||||||
|
->setActivity((new Activity())->setProject(new Project()))
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage']));
|
||||||
|
|
||||||
|
$this->buildViolation('Missing project.')
|
||||||
|
->atPath('property.path.project')
|
||||||
|
->setCode(TimesheetMultiUpdateConstraint::MISSING_PROJECT_ERROR)
|
||||||
|
->assertRaised();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHourlyRateAndFixedRateInParallelAreNotAllowed()
|
||||||
|
{
|
||||||
|
$timesheet = new TimesheetMultiUpdateDTO();
|
||||||
|
$timesheet
|
||||||
|
->setHourlyRate(10.12)
|
||||||
|
->setFixedRate(123.45)
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage']));
|
||||||
|
|
||||||
|
$this->buildViolation('Cannot set hourly rate and fixed rate at the same time.')
|
||||||
|
->atPath('property.path.fixedRate')
|
||||||
|
->setCode(TimesheetMultiUpdateConstraint::HOURLY_RATE_FIXED_RATE)
|
||||||
|
->buildNextViolation('Cannot set hourly rate and fixed rate at the same time.')
|
||||||
|
->atPath('property.path.hourlyRate')
|
||||||
|
->setCode(TimesheetMultiUpdateConstraint::HOURLY_RATE_FIXED_RATE)
|
||||||
|
->assertRaised();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDisabledValues()
|
||||||
|
{
|
||||||
|
$customer = new Customer();
|
||||||
|
$customer->setVisible(false);
|
||||||
|
$activity = new Activity();
|
||||||
|
$activity->setVisible(false);
|
||||||
|
$project = new Project();
|
||||||
|
$project->setVisible(false);
|
||||||
|
$project->setCustomer($customer);
|
||||||
|
$activity->setProject($project);
|
||||||
|
|
||||||
|
$timesheet = new TimesheetMultiUpdateDTO();
|
||||||
|
$timesheet
|
||||||
|
->setActivity($activity)
|
||||||
|
->setProject($project)
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage']));
|
||||||
|
|
||||||
|
$this->buildViolation('Cannot assign a disabled activity.')
|
||||||
|
->atPath('property.path.activity')
|
||||||
|
->setCode(TimesheetMultiUpdateConstraint::DISABLED_ACTIVITY_ERROR)
|
||||||
|
->buildNextViolation('Cannot assign a disabled project.')
|
||||||
|
->atPath('property.path.project')
|
||||||
|
->setCode(TimesheetMultiUpdateConstraint::DISABLED_PROJECT_ERROR)
|
||||||
|
->buildNextViolation('Cannot assign a disabled customer.')
|
||||||
|
->atPath('property.path.customer')
|
||||||
|
->setCode(TimesheetMultiUpdateConstraint::DISABLED_CUSTOMER_ERROR)
|
||||||
|
->assertRaised();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user