Preparations for coming features (#1818)
* removed unused convert_tz code * added timestampable listener to support automatic updates of change columns * added modified_at, billable and category timesheet fields * new timesheet API query parameter modified_after
This commit is contained in:
@@ -3,7 +3,6 @@ doctrine:
|
|||||||
dql:
|
dql:
|
||||||
datetime_functions:
|
datetime_functions:
|
||||||
addtime: DoctrineExtensions\Query\Mysql\AddTime
|
addtime: DoctrineExtensions\Query\Mysql\AddTime
|
||||||
convert_tz: DoctrineExtensions\Query\Mysql\ConvertTz
|
|
||||||
date: DoctrineExtensions\Query\Mysql\Date
|
date: DoctrineExtensions\Query\Mysql\Date
|
||||||
date_format: DoctrineExtensions\Query\Mysql\DateFormat
|
date_format: DoctrineExtensions\Query\Mysql\DateFormat
|
||||||
dateadd: DoctrineExtensions\Query\Mysql\DateAdd
|
dateadd: DoctrineExtensions\Query\Mysql\DateAdd
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ doctrine:
|
|||||||
orm:
|
orm:
|
||||||
dql:
|
dql:
|
||||||
datetime_functions:
|
datetime_functions:
|
||||||
convert_tz: App\Doctrine\Query\Sqlite\ConvertTz
|
|
||||||
date: DoctrineExtensions\Query\Sqlite\Date
|
date: DoctrineExtensions\Query\Sqlite\Date
|
||||||
date_format: DoctrineExtensions\Query\Sqlite\DateFormat
|
date_format: DoctrineExtensions\Query\Sqlite\DateFormat
|
||||||
#dateadd: DoctrineExtensions\Query\Sqlite\DateAdd
|
#dateadd: DoctrineExtensions\Query\Sqlite\DateAdd
|
||||||
|
|||||||
@@ -101,6 +101,14 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: doctrine.event_subscriber, priority: 50 }
|
- { name: doctrine.event_subscriber, priority: 50 }
|
||||||
|
|
||||||
|
# updates timestampable columns (higher priority, so the TimesheetSubscriber will be executed later)
|
||||||
|
Gedmo\Timestampable\TimestampableListener:
|
||||||
|
class: Gedmo\Timestampable\TimestampableListener
|
||||||
|
tags:
|
||||||
|
- { name: doctrine.event_subscriber, priority: 60 }
|
||||||
|
calls:
|
||||||
|
- [ setAnnotationReader, [ "@annotation_reader" ] ]
|
||||||
|
|
||||||
# make sure, that sqlite supports foreign keys and cascade deletes
|
# make sure, that sqlite supports foreign keys and cascade deletes
|
||||||
App\Doctrine\SqliteSessionInitSubscriber:
|
App\Doctrine\SqliteSessionInitSubscriber:
|
||||||
class: App\Doctrine\SqliteSessionInitSubscriber
|
class: App\Doctrine\SqliteSessionInitSubscriber
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ class TimesheetController extends BaseApiController
|
|||||||
* @Rest\QueryParam(name="active", requirements="0|1", strict=true, nullable=true, description="Filter for running/active records. Allowed values: 0=stopped, 1=active (default: all)")
|
* @Rest\QueryParam(name="active", requirements="0|1", strict=true, nullable=true, description="Filter for running/active records. Allowed values: 0=stopped, 1=active (default: all)")
|
||||||
* @Rest\QueryParam(name="full", requirements="true", strict=true, nullable=true, description="Allows to fetch fully serialized objects including subresources. Allowed values: true (default: false)")
|
* @Rest\QueryParam(name="full", requirements="true", strict=true, nullable=true, description="Allows to fetch fully serialized objects including subresources. Allowed values: true (default: false)")
|
||||||
* @Rest\QueryParam(name="term", description="Free search term")
|
* @Rest\QueryParam(name="term", description="Free search term")
|
||||||
|
* @Rest\QueryParam(name="modified_after", requirements=@Constraints\DateTime(format="Y-m-d\TH:i:s"), strict=true, nullable=true, description="Only records changed after this date will be included (format: HTML5). Available since Kimai 1.10 and works only for records that were created/updated since then.")
|
||||||
*
|
*
|
||||||
* @Security("is_granted('view_own_timesheet') or is_granted('view_other_timesheet')")
|
* @Security("is_granted('view_own_timesheet') or is_granted('view_other_timesheet')")
|
||||||
*
|
*
|
||||||
@@ -255,6 +256,10 @@ class TimesheetController extends BaseApiController
|
|||||||
$query->setSearchTerm(new SearchTerm($term));
|
$query->setSearchTerm(new SearchTerm($term));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($modifiedAfter = $paramFetcher->get('modified_after'))) {
|
||||||
|
$query->setModifiedAfter($this->dateTime->createDateTime($modifiedAfter));
|
||||||
|
}
|
||||||
|
|
||||||
/** @var Pagerfanta $data */
|
/** @var Pagerfanta $data */
|
||||||
$data = $this->repository->getPagerfantaForQuery($query);
|
$data = $this->repository->getPagerfantaForQuery($query);
|
||||||
$data = (array) $data->getCurrentPageResults();
|
$data = (array) $data->getCurrentPageResults();
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
<?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\Doctrine\Query\Sqlite;
|
|
||||||
|
|
||||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
|
||||||
use Doctrine\ORM\Query\Lexer;
|
|
||||||
use Doctrine\ORM\Query\Parser;
|
|
||||||
use Doctrine\ORM\Query\SqlWalker;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is just a fake, as SQLITE does not support this by now.
|
|
||||||
*/
|
|
||||||
class ConvertTz extends FunctionNode
|
|
||||||
{
|
|
||||||
protected $dateExpression;
|
|
||||||
|
|
||||||
protected $fromTz;
|
|
||||||
|
|
||||||
protected $toTz;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function getSql(SqlWalker $sqlWalker)
|
|
||||||
{
|
|
||||||
$fieldName = $sqlWalker->walkArithmeticExpression($this->dateExpression);
|
|
||||||
$fromTz = $sqlWalker->walkStringPrimary($this->fromTz);
|
|
||||||
$toTz = $sqlWalker->walkStringPrimary($this->toTz);
|
|
||||||
|
|
||||||
return sprintf('%s', $fieldName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function parse(Parser $parser)
|
|
||||||
{
|
|
||||||
$parser->match(Lexer::T_IDENTIFIER);
|
|
||||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
|
||||||
|
|
||||||
$this->dateExpression = $parser->ArithmeticExpression();
|
|
||||||
$parser->match(Lexer::T_COMMA);
|
|
||||||
|
|
||||||
$this->fromTz = $parser->StringPrimary();
|
|
||||||
$parser->match(Lexer::T_COMMA);
|
|
||||||
|
|
||||||
$this->toTz = $parser->StringPrimary();
|
|
||||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -102,6 +102,7 @@ class Invoice
|
|||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
* @ORM\Column(name="currency", type="string", length=3, nullable=false)
|
* @ORM\Column(name="currency", type="string", length=3, nullable=false)
|
||||||
|
* @Assert\NotNull()
|
||||||
* @Assert\Length(max=3)
|
* @Assert\Length(max=3)
|
||||||
*/
|
*/
|
||||||
private $currency;
|
private $currency;
|
||||||
@@ -110,6 +111,7 @@ class Invoice
|
|||||||
* @var int
|
* @var int
|
||||||
*
|
*
|
||||||
* @ORM\Column(name="due_days", type="integer", length=3, nullable=false)
|
* @ORM\Column(name="due_days", type="integer", length=3, nullable=false)
|
||||||
|
* @Assert\NotNull()
|
||||||
* @Assert\Range(min = 0, max = 999)
|
* @Assert\Range(min = 0, max = 999)
|
||||||
*/
|
*/
|
||||||
private $dueDays = 30;
|
private $dueDays = 30;
|
||||||
@@ -118,6 +120,7 @@ class Invoice
|
|||||||
* @var float
|
* @var float
|
||||||
*
|
*
|
||||||
* @ORM\Column(name="vat", type="float", nullable=false)
|
* @ORM\Column(name="vat", type="float", nullable=false)
|
||||||
|
* @Assert\NotNull()
|
||||||
* @Assert\Range(min = 0.0, max = 99.99)
|
* @Assert\Range(min = 0.0, max = 99.99)
|
||||||
*/
|
*/
|
||||||
private $vat = 0.00;
|
private $vat = 0.00;
|
||||||
@@ -126,13 +129,16 @@ class Invoice
|
|||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
* @ORM\Column(name="status", type="string", length=20, nullable=false)
|
* @ORM\Column(name="status", type="string", length=20, nullable=false)
|
||||||
|
* @Assert\NotNull()
|
||||||
*/
|
*/
|
||||||
private $status = self::STATUS_NEW;
|
private $status = self::STATUS_NEW;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
* @ORM\Column(name="invoice_filename", type="string", length=100, nullable=false)
|
* @ORM\Column(name="invoice_filename", type="string", length=150, nullable=false)
|
||||||
|
* @Assert\NotNull()
|
||||||
|
* @Assert\Length(min=1, max=150)
|
||||||
*/
|
*/
|
||||||
private $invoiceFilename;
|
private $invoiceFilename;
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use DateTimeZone;
|
|||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Gedmo\Mapping\Annotation as Gedmo;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,18 +32,29 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||||||
* @ORM\Entity(repositoryClass="App\Repository\TimesheetRepository")
|
* @ORM\Entity(repositoryClass="App\Repository\TimesheetRepository")
|
||||||
* @ORM\HasLifecycleCallbacks()
|
* @ORM\HasLifecycleCallbacks()
|
||||||
* @App\Validator\Constraints\Timesheet
|
* @App\Validator\Constraints\Timesheet
|
||||||
*
|
|
||||||
* columns={"user"} => IDX_4F60C6B18D93D649 => count results for user timesheets
|
|
||||||
* columns={"activity_id"} => IDX_4F60C6B181C06096 => ???
|
|
||||||
* columns={"user","start_time"} => IDX_4F60C6B18D93D649502DF587 => recent activities, user timesheet with date filzer
|
|
||||||
* columns={"start_time"} => IDX_4F60C6B1502DF587 => team timesheets with timerange filter only
|
|
||||||
* columns={"start_time","end_time"} => IDX_4F60C6B1502DF58741561401 => ???
|
|
||||||
* columns={"start_time","end_time","user"} => IDX_4F60C6B1502DF587415614018D93D649 => ???
|
|
||||||
*/
|
*/
|
||||||
class Timesheet implements EntityWithMetaFields, ExportItemInterface
|
class Timesheet implements EntityWithMetaFields, ExportItemInterface
|
||||||
{
|
{
|
||||||
public const TYPE_TIMESHEET = 'timesheet';
|
/**
|
||||||
public const CATEGORY_WORK = 'work';
|
* Category: Normal work-time (default category)
|
||||||
|
*/
|
||||||
|
public const WORK = 'work';
|
||||||
|
/**
|
||||||
|
* Category: Holiday
|
||||||
|
*/
|
||||||
|
public const HOLIDAY = 'holiday';
|
||||||
|
/**
|
||||||
|
* Category: Sickness
|
||||||
|
*/
|
||||||
|
public const SICKNESS = 'sickness';
|
||||||
|
/**
|
||||||
|
* Category: Parental leave
|
||||||
|
*/
|
||||||
|
public const PARENTAL = 'parental';
|
||||||
|
/**
|
||||||
|
* Category: Overtime reduction
|
||||||
|
*/
|
||||||
|
public const OVERTIME = 'overtime';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int|null
|
* @var int|null
|
||||||
@@ -161,6 +173,30 @@ class Timesheet implements EntityWithMetaFields, ExportItemInterface
|
|||||||
*/
|
*/
|
||||||
private $exported = false;
|
private $exported = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*
|
||||||
|
* @ORM\Column(name="billable", type="boolean", nullable=false, options={"default": true})
|
||||||
|
* @Assert\NotNull()
|
||||||
|
*/
|
||||||
|
private $billable = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
* @ORM\Column(name="category", type="string", length=10, nullable=false, options={"default": "work"})
|
||||||
|
* @Assert\NotNull()
|
||||||
|
*/
|
||||||
|
private $category = self::WORK;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var DateTime|null
|
||||||
|
*
|
||||||
|
* @Gedmo\Timestampable
|
||||||
|
* @ORM\Column(name="modified_at", type="datetime", nullable=true)
|
||||||
|
*/
|
||||||
|
private $modifiedAt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Tag[]|ArrayCollection
|
* @var Tag[]|ArrayCollection
|
||||||
*
|
*
|
||||||
@@ -185,9 +221,6 @@ class Timesheet implements EntityWithMetaFields, ExportItemInterface
|
|||||||
*/
|
*/
|
||||||
private $meta;
|
private $meta;
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor, initializes collections
|
|
||||||
*/
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->tags = new ArrayCollection();
|
$this->tags = new ArrayCollection();
|
||||||
@@ -472,16 +505,44 @@ class Timesheet implements EntityWithMetaFields, ExportItemInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns ALWAYS: "timesheet"
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function getType(): string
|
public function getType(): string
|
||||||
{
|
{
|
||||||
// this will be improved in a future version
|
return 'timesheet';
|
||||||
return self::TYPE_TIMESHEET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCategory(): string
|
public function getCategory(): string
|
||||||
{
|
{
|
||||||
// this will be improved in a future version
|
return $this->category;
|
||||||
return self::CATEGORY_WORK;
|
}
|
||||||
|
|
||||||
|
public function setCategory(string $category): Timesheet
|
||||||
|
{
|
||||||
|
$allowed = [self::WORK, self::HOLIDAY, self::SICKNESS, self::PARENTAL, self::OVERTIME];
|
||||||
|
|
||||||
|
if (!\in_array($category, $allowed)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Invalid timesheet category "%s" given, expected one of: %s', $category, implode(', ', $allowed)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->category = $category;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isBillable(): bool
|
||||||
|
{
|
||||||
|
return $this->billable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBillable(bool $billable): Timesheet
|
||||||
|
{
|
||||||
|
$this->billable = $billable;
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFixedRate(): ?float
|
public function getFixedRate(): ?float
|
||||||
@@ -508,6 +569,11 @@ class Timesheet implements EntityWithMetaFields, ExportItemInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getModifiedAt(): ?DateTime
|
||||||
|
{
|
||||||
|
return $this->modifiedAt;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection|MetaTableTypeInterface[]
|
* @return Collection|MetaTableTypeInterface[]
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -52,9 +52,11 @@ class UserEnvironmentSubscriber implements EventSubscriberInterface
|
|||||||
|
|
||||||
$user = $this->storage->getToken()->getUser();
|
$user = $this->storage->getToken()->getUser();
|
||||||
|
|
||||||
|
// the locale depends on the request, not on the user configuration
|
||||||
|
\Locale::setDefault($event->getRequest()->getLocale());
|
||||||
|
|
||||||
if ($user instanceof User) {
|
if ($user instanceof User) {
|
||||||
date_default_timezone_set($user->getTimezone());
|
date_default_timezone_set($user->getTimezone());
|
||||||
\Locale::setDefault($user->getLocale());
|
|
||||||
$user->initCanSeeAllData($this->auth->isGranted('view_all_data'));
|
$user->initCanSeeAllData($this->auth->isGranted('view_all_data'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
63
src/Migrations/Version20200705152310.php
Normal file
63
src/Migrations/Version20200705152310.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 DoctrineMigrations;
|
||||||
|
|
||||||
|
use App\Doctrine\AbstractMigration;
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @version 1.10
|
||||||
|
*/
|
||||||
|
final class Version20200705152310 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Updated invoice and added timesheet columns';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$invoices = $schema->getTable('kimai2_invoices');
|
||||||
|
$invoices->getColumn('invoice_filename')->setLength(150);
|
||||||
|
|
||||||
|
$timesheet = $schema->getTable('kimai2_timesheet');
|
||||||
|
$timesheet->addColumn('billable', 'boolean', ['notnull' => false, 'default' => true]);
|
||||||
|
$timesheet->addColumn('category', 'string', ['length' => 10, 'notnull' => true, 'default' => 'work']);
|
||||||
|
$timesheet->addColumn('modified_at', 'datetime', ['notnull' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$invoices = $schema->getTable('kimai2_invoices');
|
||||||
|
$invoices->getColumn('invoice_filename')->setLength(100);
|
||||||
|
|
||||||
|
$timesheet = $schema->getTable('kimai2_timesheet');
|
||||||
|
$timesheet->dropColumn('billable');
|
||||||
|
$timesheet->dropColumn('category');
|
||||||
|
$timesheet->dropColumn('modified_at');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isSupportingForeignKeys(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isTransactional(): bool
|
||||||
|
{
|
||||||
|
if ($this->isPlatformSqlite()) {
|
||||||
|
// does fail if we use transactions, as tables are re-created and foreign keys would fail
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,12 @@ class InvoiceQuery extends TimesheetQuery
|
|||||||
*/
|
*/
|
||||||
private $markAsExported = false;
|
private $markAsExported = false;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->setBillable(InvoiceQuery::STATE_BILLABLE);
|
||||||
|
}
|
||||||
|
|
||||||
public function getTemplate(): ?InvoiceTemplate
|
public function getTemplate(): ?InvoiceTemplate
|
||||||
{
|
{
|
||||||
return $this->template;
|
return $this->template;
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ class TimesheetQuery extends ActivityQuery
|
|||||||
public const STATE_STOPPED = 3;
|
public const STATE_STOPPED = 3;
|
||||||
public const STATE_EXPORTED = 4;
|
public const STATE_EXPORTED = 4;
|
||||||
public const STATE_NOT_EXPORTED = 5;
|
public const STATE_NOT_EXPORTED = 5;
|
||||||
|
public const STATE_BILLABLE = 6;
|
||||||
|
public const STATE_NOT_BILLABLE = 7;
|
||||||
|
|
||||||
public const TIMESHEET_ORDER_ALLOWED = ['begin', 'end', 'duration', 'rate', 'customer', 'project', 'activity', 'description'];
|
public const TIMESHEET_ORDER_ALLOWED = ['begin', 'end', 'duration', 'rate', 'customer', 'project', 'activity', 'description'];
|
||||||
|
|
||||||
@@ -43,6 +45,14 @@ class TimesheetQuery extends ActivityQuery
|
|||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
protected $exported = self::STATE_ALL;
|
protected $exported = self::STATE_ALL;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $billable = self::STATE_ALL;
|
||||||
|
/**
|
||||||
|
* @var \DateTime|null
|
||||||
|
*/
|
||||||
|
private $modifiedAfter;
|
||||||
/**
|
/**
|
||||||
* @var DateRange
|
* @var DateRange
|
||||||
*/
|
*/
|
||||||
@@ -115,7 +125,7 @@ class TimesheetQuery extends ActivityQuery
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Activity|int|null
|
* @return Activity|int|null
|
||||||
* @deprecated since 1.9 - use getProjects() instead - will be removed with 2.0
|
* @deprecated since 1.9 - use getActivities() instead - will be removed with 2.0
|
||||||
*/
|
*/
|
||||||
public function getActivity()
|
public function getActivity()
|
||||||
{
|
{
|
||||||
@@ -151,7 +161,7 @@ class TimesheetQuery extends ActivityQuery
|
|||||||
* @param Activity|int $activity
|
* @param Activity|int $activity
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function addActivity($activity)
|
public function addActivity($activity): TimesheetQuery
|
||||||
{
|
{
|
||||||
$this->activities[] = $activity;
|
$this->activities[] = $activity;
|
||||||
|
|
||||||
@@ -162,7 +172,7 @@ class TimesheetQuery extends ActivityQuery
|
|||||||
* @param Activity[]|int[] $activities
|
* @param Activity[]|int[] $activities
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setActivities(array $activities)
|
public function setActivities(array $activities): TimesheetQuery
|
||||||
{
|
{
|
||||||
$this->activities = $activities;
|
$this->activities = $activities;
|
||||||
|
|
||||||
@@ -174,19 +184,22 @@ class TimesheetQuery extends ActivityQuery
|
|||||||
return !empty($this->activities);
|
return !empty($this->activities);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getState(): int
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getState()
|
|
||||||
{
|
{
|
||||||
return $this->state;
|
return $this->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function isRunning(): bool
|
||||||
* @param int $state
|
{
|
||||||
* @return TimesheetQuery
|
return $this->state === self::STATE_RUNNING;
|
||||||
*/
|
}
|
||||||
public function setState($state)
|
|
||||||
|
public function isStopped(): bool
|
||||||
|
{
|
||||||
|
return $this->state === self::STATE_STOPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setState(int $state): TimesheetQuery
|
||||||
{
|
{
|
||||||
$state = (int) $state;
|
$state = (int) $state;
|
||||||
if (\in_array($state, [self::STATE_ALL, self::STATE_RUNNING, self::STATE_STOPPED], true)) {
|
if (\in_array($state, [self::STATE_ALL, self::STATE_RUNNING, self::STATE_STOPPED], true)) {
|
||||||
@@ -196,19 +209,22 @@ class TimesheetQuery extends ActivityQuery
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getExported(): int
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getExported()
|
|
||||||
{
|
{
|
||||||
return $this->exported;
|
return $this->exported;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function isExported(): bool
|
||||||
* @param int $exported
|
{
|
||||||
* @return TimesheetQuery
|
return $this->exported === self::STATE_EXPORTED;
|
||||||
*/
|
}
|
||||||
public function setExported($exported)
|
|
||||||
|
public function isNotExported(): bool
|
||||||
|
{
|
||||||
|
return $this->exported === self::STATE_NOT_EXPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setExported(int $exported): TimesheetQuery
|
||||||
{
|
{
|
||||||
$exported = (int) $exported;
|
$exported = (int) $exported;
|
||||||
if (\in_array($exported, [self::STATE_ALL, self::STATE_EXPORTED, self::STATE_NOT_EXPORTED], true)) {
|
if (\in_array($exported, [self::STATE_ALL, self::STATE_EXPORTED, self::STATE_NOT_EXPORTED], true)) {
|
||||||
@@ -223,11 +239,7 @@ class TimesheetQuery extends ActivityQuery
|
|||||||
return $this->dateRange->getBegin();
|
return $this->dateRange->getBegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function setBegin(\DateTime $begin): TimesheetQuery
|
||||||
* @param \DateTime $begin
|
|
||||||
* @return TimesheetQuery
|
|
||||||
*/
|
|
||||||
public function setBegin($begin)
|
|
||||||
{
|
{
|
||||||
$this->dateRange->setBegin($begin);
|
$this->dateRange->setBegin($begin);
|
||||||
|
|
||||||
@@ -239,40 +251,26 @@ class TimesheetQuery extends ActivityQuery
|
|||||||
return $this->dateRange->getEnd();
|
return $this->dateRange->getEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function setEnd(\DateTime $end): TimesheetQuery
|
||||||
* @param \DateTime $end
|
|
||||||
* @return TimesheetQuery
|
|
||||||
*/
|
|
||||||
public function setEnd($end)
|
|
||||||
{
|
{
|
||||||
$this->dateRange->setEnd($end);
|
$this->dateRange->setEnd($end);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return DateRange
|
|
||||||
*/
|
|
||||||
public function getDateRange(): DateRange
|
public function getDateRange(): DateRange
|
||||||
{
|
{
|
||||||
return $this->dateRange;
|
return $this->dateRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function setDateRange(DateRange $dateRange): TimesheetQuery
|
||||||
* @param DateRange $dateRange
|
|
||||||
* @return TimesheetQuery
|
|
||||||
*/
|
|
||||||
public function setDateRange(DateRange $dateRange)
|
|
||||||
{
|
{
|
||||||
$this->dateRange = $dateRange;
|
$this->dateRange = $dateRange;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getTags(bool $allowUnknown = false): iterable
|
||||||
* @return iterable
|
|
||||||
*/
|
|
||||||
public function getTags($allowUnknown = false)
|
|
||||||
{
|
{
|
||||||
if (empty($this->tags)) {
|
if (empty($this->tags)) {
|
||||||
return [];
|
return [];
|
||||||
@@ -290,14 +288,46 @@ class TimesheetQuery extends ActivityQuery
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function setTags(iterable $tags): TimesheetQuery
|
||||||
* @param iterable $tags
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setTags(iterable $tags)
|
|
||||||
{
|
{
|
||||||
$this->tags = $tags;
|
$this->tags = $tags;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBillable(): int
|
||||||
|
{
|
||||||
|
return $this->billable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isBillable(): bool
|
||||||
|
{
|
||||||
|
return $this->billable === self::STATE_BILLABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isNotBillable(): bool
|
||||||
|
{
|
||||||
|
return $this->billable === self::STATE_NOT_BILLABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBillable(int $billable): TimesheetQuery
|
||||||
|
{
|
||||||
|
if (\in_array($billable, [self::STATE_ALL, self::STATE_BILLABLE, self::STATE_NOT_BILLABLE], true)) {
|
||||||
|
$this->billable = $billable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getModifiedAfter(): ?\DateTime
|
||||||
|
{
|
||||||
|
return $this->modifiedAfter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setModifiedAfter(\DateTime $modifiedAfter): TimesheetQuery
|
||||||
|
{
|
||||||
|
$this->modifiedAfter = $modifiedAfter;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -753,9 +753,9 @@ class TimesheetRepository extends EntityRepository
|
|||||||
->setParameter('begin', $query->getBegin());
|
->setParameter('begin', $query->getBegin());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TimesheetQuery::STATE_RUNNING == $query->getState()) {
|
if ($query->isRunning()) {
|
||||||
$qb->andWhere($qb->expr()->isNull('t.end'));
|
$qb->andWhere($qb->expr()->isNull('t.end'));
|
||||||
} elseif (TimesheetQuery::STATE_STOPPED == $query->getState()) {
|
} elseif ($query->isStopped()) {
|
||||||
$qb->andWhere($qb->expr()->isNotNull('t.end'));
|
$qb->andWhere($qb->expr()->isNotNull('t.end'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,12 +764,23 @@ class TimesheetRepository extends EntityRepository
|
|||||||
->setParameter('end', $query->getEnd());
|
->setParameter('end', $query->getEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($query->getExported() === TimesheetQuery::STATE_EXPORTED) {
|
if ($query->isExported()) {
|
||||||
$qb->andWhere('t.exported = :exported')->setParameter('exported', true, \PDO::PARAM_BOOL);
|
$qb->andWhere('t.exported = :exported')->setParameter('exported', true, \PDO::PARAM_BOOL);
|
||||||
} elseif ($query->getExported() === TimesheetQuery::STATE_NOT_EXPORTED) {
|
} elseif ($query->isNotExported()) {
|
||||||
$qb->andWhere('t.exported = :exported')->setParameter('exported', false, \PDO::PARAM_BOOL);
|
$qb->andWhere('t.exported = :exported')->setParameter('exported', false, \PDO::PARAM_BOOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($query->isBillable()) {
|
||||||
|
$qb->andWhere('t.billable = :billable')->setParameter('billable', true, \PDO::PARAM_BOOL);
|
||||||
|
} elseif ($query->isNotBillable()) {
|
||||||
|
$qb->andWhere('t.billable = :billable')->setParameter('billable', false, \PDO::PARAM_BOOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $query->getModifiedAfter()) {
|
||||||
|
$qb->andWhere($qb->expr()->gte($this->getDatetimeFieldSql('t.modifiedAt'), ':modified_at'))
|
||||||
|
->setParameter('modified_at', $query->getModifiedAfter());
|
||||||
|
}
|
||||||
|
|
||||||
if ($query->hasActivities()) {
|
if ($query->hasActivities()) {
|
||||||
$qb->andWhere($qb->expr()->in('t.activity', ':activity'))
|
$qb->andWhere($qb->expr()->in('t.activity', ':activity'))
|
||||||
->setParameter('activity', $query->getActivities());
|
->setParameter('activity', $query->getActivities());
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ use App\Utils\Duration;
|
|||||||
use App\Utils\LocaleFormats;
|
use App\Utils\LocaleFormats;
|
||||||
use App\Utils\LocaleHelper;
|
use App\Utils\LocaleHelper;
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
use Symfony\Component\Intl\Languages;
|
|
||||||
use Symfony\Component\Intl\Locales;
|
use Symfony\Component\Intl\Locales;
|
||||||
use Twig\Extension\AbstractExtension;
|
use Twig\Extension\AbstractExtension;
|
||||||
use Twig\TwigFilter;
|
use Twig\TwigFilter;
|
||||||
@@ -163,6 +162,8 @@ final class LocaleExtensions extends AbstractExtension
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns the currency symbol.
|
||||||
|
*
|
||||||
* @param string $currency
|
* @param string $currency
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
|||||||
|
|
||||||
public function testGetCollectionWithQuery()
|
public function testGetCollectionWithQuery()
|
||||||
{
|
{
|
||||||
|
$modifiedAfter = new \DateTime('-1 hour');
|
||||||
$begin = new \DateTime('first day of this month');
|
$begin = new \DateTime('first day of this month');
|
||||||
$begin->setTime(0, 0, 0);
|
$begin->setTime(0, 0, 0);
|
||||||
$end = new \DateTime('last day of this month');
|
$end = new \DateTime('last day of this month');
|
||||||
@@ -155,6 +156,7 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
|||||||
'order' => 'DESC',
|
'order' => 'DESC',
|
||||||
'orderBy' => 'rate',
|
'orderBy' => 'rate',
|
||||||
'active' => 0,
|
'active' => 0,
|
||||||
|
'modified_after' => $modifiedAfter->format(self::DATE_FORMAT_HTML5),
|
||||||
'begin' => $begin->format(self::DATE_FORMAT_HTML5),
|
'begin' => $begin->format(self::DATE_FORMAT_HTML5),
|
||||||
'end' => $end->format(self::DATE_FORMAT_HTML5),
|
'end' => $end->format(self::DATE_FORMAT_HTML5),
|
||||||
'exported' => 0,
|
'exported' => 0,
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ class TimesheetTest extends TestCase
|
|||||||
self::assertNull($sut->getId());
|
self::assertNull($sut->getId());
|
||||||
self::assertNull($sut->getBegin());
|
self::assertNull($sut->getBegin());
|
||||||
self::assertNull($sut->getEnd());
|
self::assertNull($sut->getEnd());
|
||||||
|
self::assertTrue($sut->isBillable());
|
||||||
|
self::assertNull($sut->getModifiedAt());
|
||||||
self::assertSame(0, $sut->getDuration());
|
self::assertSame(0, $sut->getDuration());
|
||||||
self::assertNull($sut->getUser());
|
self::assertNull($sut->getUser());
|
||||||
self::assertNull($sut->getActivity());
|
self::assertNull($sut->getActivity());
|
||||||
@@ -140,4 +142,34 @@ class TimesheetTest extends TestCase
|
|||||||
self::assertEquals(3, $sut->getMetaFields()->count());
|
self::assertEquals(3, $sut->getMetaFields()->count());
|
||||||
self::assertCount(2, $sut->getVisibleMetaFields());
|
self::assertCount(2, $sut->getVisibleMetaFields());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testBillable()
|
||||||
|
{
|
||||||
|
$sut = new Timesheet();
|
||||||
|
self::assertTrue($sut->isBillable());
|
||||||
|
self::assertInstanceOf(Timesheet::class, $sut->setBillable(false));
|
||||||
|
self::assertFalse($sut->isBillable());
|
||||||
|
self::assertInstanceOf(Timesheet::class, $sut->setBillable(true));
|
||||||
|
self::assertTrue($sut->isBillable());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCategory()
|
||||||
|
{
|
||||||
|
$sut = new Timesheet();
|
||||||
|
self::assertInstanceOf(Timesheet::class, $sut->setCategory(Timesheet::HOLIDAY));
|
||||||
|
self::assertEquals('holiday', $sut->getCategory());
|
||||||
|
self::assertInstanceOf(Timesheet::class, $sut->setCategory(Timesheet::WORK));
|
||||||
|
self::assertEquals('work', $sut->getCategory());
|
||||||
|
self::assertInstanceOf(Timesheet::class, $sut->setCategory(Timesheet::SICKNESS));
|
||||||
|
self::assertEquals('sickness', $sut->getCategory());
|
||||||
|
self::assertInstanceOf(Timesheet::class, $sut->setCategory(Timesheet::PARENTAL));
|
||||||
|
self::assertEquals('parental', $sut->getCategory());
|
||||||
|
self::assertInstanceOf(Timesheet::class, $sut->setCategory(Timesheet::OVERTIME));
|
||||||
|
self::assertEquals('overtime', $sut->getCategory());
|
||||||
|
|
||||||
|
self::expectException(\InvalidArgumentException::class);
|
||||||
|
self::expectExceptionMessage('Invalid timesheet category "foo" given, expected one of: work, holiday, sickness, parental, overtime');
|
||||||
|
|
||||||
|
$sut->setCategory('foo');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
namespace App\Tests\Repository\Query;
|
namespace App\Tests\Repository\Query;
|
||||||
|
|
||||||
use App\Repository\Query\InvoiceQuery;
|
use App\Repository\Query\InvoiceQuery;
|
||||||
|
use App\Repository\Query\TimesheetQuery;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers \App\Repository\Query\InvoiceQuery
|
* @covers \App\Repository\Query\InvoiceQuery
|
||||||
@@ -33,13 +34,19 @@ class InvoiceQueryTest extends TimesheetQueryTest
|
|||||||
$this->assertState($sut);
|
$this->assertState($sut);
|
||||||
$this->assertExported($sut);
|
$this->assertExported($sut);
|
||||||
$this->assertMarkAsExported($sut);
|
$this->assertMarkAsExported($sut);
|
||||||
|
$this->assertModifiedAfter($sut);
|
||||||
|
|
||||||
|
self::assertEquals(TimesheetQuery::STATE_BILLABLE, $sut->getBillable());
|
||||||
|
self::assertTrue($sut->isBillable());
|
||||||
|
self::assertFalse($sut->isNotBillable());
|
||||||
|
$this->assertBillable($sut);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function assertMarkAsExported(InvoiceQuery $sut)
|
protected function assertMarkAsExported(InvoiceQuery $sut)
|
||||||
{
|
{
|
||||||
$this->assertFalse($sut->isMarkAsExported());
|
self::assertFalse($sut->isMarkAsExported());
|
||||||
|
|
||||||
$sut->setMarkAsExported(true);
|
$sut->setMarkAsExported(true);
|
||||||
$this->assertTrue($sut->isMarkAsExported());
|
self::assertTrue($sut->isMarkAsExported());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,23 +35,29 @@ class TimesheetQueryTest extends BaseQueryTest
|
|||||||
$this->assertState($sut);
|
$this->assertState($sut);
|
||||||
$this->assertExported($sut);
|
$this->assertExported($sut);
|
||||||
$this->assertSearchTerm($sut);
|
$this->assertSearchTerm($sut);
|
||||||
|
$this->assertModifiedAfter($sut);
|
||||||
|
|
||||||
|
self::assertEquals(TimesheetQuery::STATE_ALL, $sut->getBillable());
|
||||||
|
self::assertFalse($sut->isBillable());
|
||||||
|
self::assertFalse($sut->isNotBillable());
|
||||||
|
$this->assertBillable($sut);
|
||||||
|
|
||||||
$this->assertResetByFormError(new TimesheetQuery(), 'begin', 'DESC');
|
$this->assertResetByFormError(new TimesheetQuery(), 'begin', 'DESC');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function assertUser(TimesheetQuery $sut)
|
protected function assertUser(TimesheetQuery $sut)
|
||||||
{
|
{
|
||||||
$this->assertNull($sut->getUser());
|
self::assertNull($sut->getUser());
|
||||||
|
|
||||||
$expected = new User();
|
$expected = new User();
|
||||||
$expected->setUsername('foo-bar');
|
$expected->setUsername('foo-bar');
|
||||||
$sut->setUser($expected);
|
self::assertInstanceOf(TimesheetQuery::class, $sut->setUser($expected));
|
||||||
$this->assertEquals($expected, $sut->getUser());
|
self::assertEquals($expected, $sut->getUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function assertUsers(TimesheetQuery $sut)
|
protected function assertUsers(TimesheetQuery $sut)
|
||||||
{
|
{
|
||||||
$this->assertEmpty($sut->getUsers());
|
self::assertEmpty($sut->getUsers());
|
||||||
|
|
||||||
$user = $this->getMockBuilder(User::class)->disableOriginalConstructor()->getMock();
|
$user = $this->getMockBuilder(User::class)->disableOriginalConstructor()->getMock();
|
||||||
$user->method('getId')->willReturn(1);
|
$user->method('getId')->willReturn(1);
|
||||||
@@ -70,43 +76,86 @@ class TimesheetQueryTest extends BaseQueryTest
|
|||||||
$sut->addUser($user);
|
$sut->addUser($user);
|
||||||
$sut->removeUser($user);
|
$sut->removeUser($user);
|
||||||
|
|
||||||
$this->assertCount(2, $sut->getUsers());
|
self::assertCount(2, $sut->getUsers());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function assertState(TimesheetQuery $sut)
|
protected function assertState(TimesheetQuery $sut)
|
||||||
{
|
{
|
||||||
$this->assertEquals(TimesheetQuery::STATE_ALL, $sut->getState());
|
self::assertEquals(TimesheetQuery::STATE_ALL, $sut->getState());
|
||||||
|
self::assertFalse($sut->isRunning());
|
||||||
|
self::assertFalse($sut->isStopped());
|
||||||
|
|
||||||
$sut->setState(PHP_INT_MAX);
|
self::assertInstanceOf(TimesheetQuery::class, $sut->setState(PHP_INT_MAX));
|
||||||
$this->assertEquals(TimesheetQuery::STATE_ALL, $sut->getState());
|
self::assertEquals(TimesheetQuery::STATE_ALL, $sut->getState());
|
||||||
|
|
||||||
$sut->setState(TimesheetQuery::STATE_STOPPED);
|
$sut->setState(TimesheetQuery::STATE_STOPPED);
|
||||||
$this->assertEquals(TimesheetQuery::STATE_STOPPED, $sut->getState());
|
self::assertEquals(TimesheetQuery::STATE_STOPPED, $sut->getState());
|
||||||
|
self::assertFalse($sut->isRunning());
|
||||||
|
self::assertTrue($sut->isStopped());
|
||||||
|
|
||||||
$sut->setState(TimesheetQuery::STATE_RUNNING);
|
$sut->setState(TimesheetQuery::STATE_RUNNING);
|
||||||
$this->assertEquals(TimesheetQuery::STATE_RUNNING, $sut->getState());
|
self::assertEquals(TimesheetQuery::STATE_RUNNING, $sut->getState());
|
||||||
|
self::assertTrue($sut->isRunning());
|
||||||
|
self::assertFalse($sut->isStopped());
|
||||||
|
|
||||||
$sut->setState(TimesheetQuery::STATE_ALL);
|
$sut->setState(TimesheetQuery::STATE_ALL);
|
||||||
$this->assertEquals(TimesheetQuery::STATE_ALL, $sut->getState());
|
self::assertEquals(TimesheetQuery::STATE_ALL, $sut->getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function assertExported(TimesheetQuery $sut)
|
protected function assertExported(TimesheetQuery $sut)
|
||||||
{
|
{
|
||||||
$this->assertEquals(TimesheetQuery::STATE_ALL, $sut->getExported());
|
self::assertEquals(TimesheetQuery::STATE_ALL, $sut->getExported());
|
||||||
|
self::assertFalse($sut->isExported());
|
||||||
|
self::assertFalse($sut->isNotExported());
|
||||||
|
|
||||||
$sut->setExported(PHP_INT_MAX);
|
self::assertInstanceOf(TimesheetQuery::class, $sut->setExported(PHP_INT_MAX));
|
||||||
$this->assertEquals(TimesheetQuery::STATE_ALL, $sut->getExported());
|
self::assertEquals(TimesheetQuery::STATE_ALL, $sut->getExported());
|
||||||
|
|
||||||
$sut->setExported(TimesheetQuery::STATE_EXPORTED);
|
$sut->setExported(TimesheetQuery::STATE_EXPORTED);
|
||||||
$this->assertEquals(TimesheetQuery::STATE_EXPORTED, $sut->getExported());
|
self::assertEquals(TimesheetQuery::STATE_EXPORTED, $sut->getExported());
|
||||||
|
self::assertTrue($sut->isExported());
|
||||||
|
self::assertFalse($sut->isNotExported());
|
||||||
|
|
||||||
$sut->setExported(TimesheetQuery::STATE_NOT_EXPORTED);
|
$sut->setExported(TimesheetQuery::STATE_NOT_EXPORTED);
|
||||||
$this->assertEquals(TimesheetQuery::STATE_NOT_EXPORTED, $sut->getExported());
|
self::assertEquals(TimesheetQuery::STATE_NOT_EXPORTED, $sut->getExported());
|
||||||
|
self::assertFalse($sut->isExported());
|
||||||
|
self::assertTrue($sut->isNotExported());
|
||||||
|
|
||||||
$sut->setExported(TimesheetQuery::STATE_ALL);
|
$sut->setExported(TimesheetQuery::STATE_ALL);
|
||||||
$this->assertEquals(TimesheetQuery::STATE_ALL, $sut->getExported());
|
self::assertEquals(TimesheetQuery::STATE_ALL, $sut->getExported());
|
||||||
|
|
||||||
$sut->setExported('02');
|
$sut->setExported('02');
|
||||||
$this->assertEquals(TimesheetQuery::STATE_ALL, $sut->getExported());
|
self::assertEquals(TimesheetQuery::STATE_ALL, $sut->getExported());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function assertModifiedAfter(TimesheetQuery $sut)
|
||||||
|
{
|
||||||
|
self::assertNull($sut->getModifiedAfter());
|
||||||
|
$date = new \DateTime('-3 hours');
|
||||||
|
|
||||||
|
self::assertInstanceOf(TimesheetQuery::class, $sut->setModifiedAfter($date));
|
||||||
|
self::assertNotNull($sut->getModifiedAfter()); // just here to fix a PHPStan issue
|
||||||
|
self::assertSame($date, $sut->getModifiedAfter());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function assertBillable(TimesheetQuery $sut)
|
||||||
|
{
|
||||||
|
self::assertInstanceOf(TimesheetQuery::class, $sut->setBillable(TimesheetQuery::STATE_ALL));
|
||||||
|
self::assertEquals(TimesheetQuery::STATE_ALL, $sut->getBillable());
|
||||||
|
self::assertFalse($sut->isBillable());
|
||||||
|
self::assertFalse($sut->isNotBillable());
|
||||||
|
|
||||||
|
$sut->setBillable(PHP_INT_MAX);
|
||||||
|
self::assertEquals(TimesheetQuery::STATE_ALL, $sut->getBillable());
|
||||||
|
|
||||||
|
$sut->setBillable(TimesheetQuery::STATE_BILLABLE);
|
||||||
|
self::assertEquals(TimesheetQuery::STATE_BILLABLE, $sut->getBillable());
|
||||||
|
self::assertTrue($sut->isBillable());
|
||||||
|
self::assertFalse($sut->isNotBillable());
|
||||||
|
|
||||||
|
$sut->setBillable(TimesheetQuery::STATE_NOT_BILLABLE);
|
||||||
|
self::assertEquals(TimesheetQuery::STATE_NOT_BILLABLE, $sut->getBillable());
|
||||||
|
self::assertFalse($sut->isBillable());
|
||||||
|
self::assertTrue($sut->isNotBillable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user