mirror of
https://github.com/kevinpapst/kimai2.git
synced 2025-05-11 12:15:43 +00:00
[FEATURE] Add new widgets
This commit is contained in:
parent
cce49cc409
commit
0006b4dd46
54 changed files with 1207 additions and 83 deletions
phpstan.neon
src
Event
Timesheet
Widget/Type
AbstractCounterYear.phpAbstractWidget.phpActiveTimesheets.phpActiveUsersMonth.phpActiveUsersToday.phpActiveUsersTotal.phpActiveUsersWeek.phpActiveUsersYear.phpAmountMonth.phpAmountPreviousMonth.phpAmountPreviousWeek.phpAmountPreviousYear.phpAmountToday.phpAmountWeek.phpAmountYear.phpAmountYesterday.phpDurationMonth.phpDurationPreviousMonth.phpDurationPreviousWeek.phpDurationPreviousYear.phpDurationToday.phpDurationTotal.phpDurationWeek.phpDurationYear.phpDurationYesterday.phpTotalsActivity.phpTotalsCustomer.phpTotalsProject.phpTotalsUser.phpUserAmountMonth.phpUserAmountPreviousMonth.phpUserAmountPreviousWeek.phpUserAmountPreviousYear.phpUserAmountToday.phpUserAmountTotal.phpUserAmountWeek.phpUserAmountYear.phpUserAmountYesterday.phpUserDurationMonth.phpUserDurationPreviousMonth.phpUserDurationPreviousWeek.phpUserDurationPreviousYear.phpUserDurationToday.phpUserDurationTotal.phpUserDurationWeek.phpUserDurationYear.phpUserDurationYesterday.phpUserTeamProjects.phpUserTeams.php
translations
17
phpstan.neon
17
phpstan.neon
|
@ -42,6 +42,13 @@ parameters:
|
|||
containerXmlPath: %rootDir%/../../../var/cache/dev/App_KernelDevDebugContainer.xml
|
||||
ignoreErrors:
|
||||
- '#^Method .*\(\) has parameter \$builder with generic interface Symfony\\Component\\Form\\FormBuilderInterface but does not specify its types\: TData$#'
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method DateTimeInterface\:\:modify\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: src/Timesheet/DateTimeFactory.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$user of class App\\\\Event\\\\PageActionsEvent constructor expects App\\\\Entity\\\\User, App\\\\Entity\\\\User\\|null given\\.$#"
|
||||
count: 4
|
||||
|
@ -1482,11 +1489,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/Event/PermissionsEvent.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Event\\\\RevenueStatisticEvent\\:\\:getRevenue\\(\\) return type has no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Event/RevenueStatisticEvent.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Event\\\\ThemeJavascriptTranslationsEvent\\:\\:getTranslations\\(\\) return type has no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
|
@ -1497,11 +1499,6 @@ parameters:
|
|||
count: 2
|
||||
path: src/Event/UserPreferenceEvent.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Event\\\\UserRevenueStatisticEvent\\:\\:getRevenue\\(\\) return type has no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Event/UserRevenueStatisticEvent.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\EventSubscriber\\\\Actions\\\\AbstractActionsSubscriber\\:\\:isGranted\\(\\) has parameter \\$attributes with no type specified\\.$#"
|
||||
count: 1
|
||||
|
|
|
@ -35,6 +35,9 @@ final class RevenueStatisticEvent extends Event
|
|||
return $this->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getRevenue(): array
|
||||
{
|
||||
return $this->revenue;
|
||||
|
|
|
@ -34,6 +34,9 @@ final class UserRevenueStatisticEvent extends Event
|
|||
return $this->event->getEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getRevenue(): array
|
||||
{
|
||||
return $this->event->getRevenue();
|
||||
|
|
|
@ -171,24 +171,33 @@ final class DateTimeFactory
|
|||
return $defaultDate;
|
||||
}
|
||||
|
||||
$financialYear = $this->createDateTime($financialYear);
|
||||
$financialYear = $financialYear->setDate((int) $defaultDate->format('Y'), (int) $financialYear->format('m'), (int) $financialYear->format('d'));
|
||||
$financialYear = $financialYear->setTime(0, 0, 0);
|
||||
$year = $this->createDateTime($financialYear);
|
||||
$year = $year->setDate((int) $defaultDate->format('Y'), (int) $year->format('m'), (int) $year->format('d'));
|
||||
$year = $year->setTime(0, 0, 0);
|
||||
|
||||
$today = $this->createDateTime('00:00:00');
|
||||
|
||||
if ($financialYear > $today) {
|
||||
$financialYear = $financialYear->modify('-1 year');
|
||||
if ($year > $today) {
|
||||
$year = $year->modify('-1 year');
|
||||
}
|
||||
|
||||
return $financialYear;
|
||||
return $year;
|
||||
}
|
||||
|
||||
public function createStartOfPreviousFinancialYear(?string $financialYear = null): DateTimeInterface
|
||||
{
|
||||
return $this->createStartOfFinancialYear($financialYear)->modify('-2 years');
|
||||
}
|
||||
|
||||
public function createEndOfFinancialYear(DateTimeInterface $financialYear): DateTimeInterface
|
||||
{
|
||||
$yearEnd = DateTime::createFromInterface($financialYear);
|
||||
$yearEnd = $yearEnd->modify('+1 year')->modify('-1 day')->setTime(23, 59, 59);
|
||||
|
||||
return $yearEnd;
|
||||
return $yearEnd->modify('+1 year')->modify('-1 day')->setTime(23, 59, 59);
|
||||
}
|
||||
|
||||
public function createEndOfPreviousFinancialYear(DateTimeInterface $financialYear): DateTimeInterface
|
||||
{
|
||||
return $this->createEndOfFinancialYear($financialYear);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ use App\Timesheet\DateTimeFactory;
|
|||
|
||||
abstract class AbstractCounterYear extends AbstractWidgetType
|
||||
{
|
||||
private bool $isFinancialYear = false;
|
||||
protected bool $isFinancialYear = false;
|
||||
|
||||
public function __construct(private SystemConfiguration $systemConfiguration)
|
||||
public function __construct(protected SystemConfiguration $systemConfiguration)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ abstract class AbstractCounterYear extends AbstractWidgetType
|
|||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$begin = $this->createDate('01 january this year 00:00:00');
|
||||
$end = $this->createDate('31 december this year 23:59:59');
|
||||
$begin = $this->createYearStartDate();
|
||||
$end = $this->createYearEndDate();
|
||||
|
||||
if (null !== ($financialYear = $this->systemConfiguration->getFinancialYearStart())) {
|
||||
$factory = new DateTimeFactory($this->getTimezone());
|
||||
|
|
|
@ -86,6 +86,26 @@ abstract class AbstractWidget implements WidgetInterface
|
|||
return new \DateTime($date, $this->getTimezone());
|
||||
}
|
||||
|
||||
protected function createYearStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('01 january this year 00:00:00');
|
||||
}
|
||||
|
||||
protected function createYearEndDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('31 december this year 23:59:59');
|
||||
}
|
||||
|
||||
protected function createPreviousYearStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('01 january previous year 00:00:00');
|
||||
}
|
||||
|
||||
protected function createPreviousYearEndDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('31 december previous year 23:59:59');
|
||||
}
|
||||
|
||||
protected function createMonthStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('first day of this month 00:00:00');
|
||||
|
@ -96,16 +116,36 @@ abstract class AbstractWidget implements WidgetInterface
|
|||
return $this->createDate('last day of this month 23:59:59');
|
||||
}
|
||||
|
||||
protected function createPreviousMonthStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('first day of previous month 00:00:00');
|
||||
}
|
||||
|
||||
protected function createPreviousMonthEndDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('last day of previous month 23:59:59');
|
||||
}
|
||||
|
||||
protected function createWeekStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('monday this week 00:00:00');
|
||||
}
|
||||
|
||||
protected function createPreviousWeekStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('monday previous week 00:00:00');
|
||||
}
|
||||
|
||||
protected function createWeekEndDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('sunday this week 23:59:59');
|
||||
}
|
||||
|
||||
protected function createPreviousWeekEndDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('sunday previous week 23:59:59');
|
||||
}
|
||||
|
||||
protected function createTodayStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('00:00:00');
|
||||
|
@ -116,6 +156,16 @@ abstract class AbstractWidget implements WidgetInterface
|
|||
return $this->createDate('23:59:59');
|
||||
}
|
||||
|
||||
protected function createYesterdayStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('yesterday 00:00:00');
|
||||
}
|
||||
|
||||
protected function createYesterdayEndDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('yesterday 23:59:59');
|
||||
}
|
||||
|
||||
public function getTimezone(): \DateTimeZone
|
||||
{
|
||||
$timezone = date_default_timezone_get();
|
||||
|
|
|
@ -16,7 +16,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class ActiveTimesheets extends AbstractWidgetType
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ final class ActiveTimesheets extends AbstractWidgetType
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->countActiveEntries();
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class ActiveUsersMonth extends AbstractActiveUsers
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ final class ActiveUsersMonth extends AbstractActiveUsers
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->countActiveUsers($this->createMonthStartDate(), $this->createMonthEndDate(), null);
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class ActiveUsersToday extends AbstractActiveUsers
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ final class ActiveUsersToday extends AbstractActiveUsers
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->countActiveUsers($this->createTodayStartDate(), $this->createTodayEndDate(), null);
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class ActiveUsersTotal extends AbstractActiveUsers
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ final class ActiveUsersTotal extends AbstractActiveUsers
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->countActiveUsers(null, null, null);
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class ActiveUsersWeek extends AbstractActiveUsers
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ final class ActiveUsersWeek extends AbstractActiveUsers
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->countActiveUsers($this->createWeekStartDate(), $this->createWeekEndDate(), null);
|
||||
|
|
|
@ -16,8 +16,10 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class ActiveUsersYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository, SystemConfiguration $systemConfiguration)
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TimesheetRepository $repository,
|
||||
SystemConfiguration $systemConfiguration
|
||||
) {
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
|
@ -36,7 +38,7 @@ final class ActiveUsersYear extends AbstractCounterYear
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->countActiveUsers($begin, $end, null);
|
||||
|
|
|
@ -29,8 +29,9 @@ final class AmountMonth extends AbstractAmountPeriod
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createMonthStartDate(), $this->createMonthEndDate(), $options);
|
||||
}
|
||||
|
|
43
src/Widget/Type/AmountPreviousMonth.php
Normal file
43
src/Widget/Type/AmountPreviousMonth.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class AmountPreviousMonth extends AbstractAmountPeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_MONTH], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'AmountPreviousMonth';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createPreviousMonthStartDate(), $this->createPreviousMonthEndDate(), $options);
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_all_data'];
|
||||
}
|
||||
}
|
43
src/Widget/Type/AmountPreviousWeek.php
Normal file
43
src/Widget/Type/AmountPreviousWeek.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class AmountPreviousWeek extends AbstractAmountPeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_WEEK], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'AmountPreviousWeek';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createPreviousWeekStartDate(), $this->createPreviousWeekEndDate(), $options);
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_all_data'];
|
||||
}
|
||||
}
|
105
src/Widget/Type/AmountPreviousYear.php
Normal file
105
src/Widget/Type/AmountPreviousYear.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Event\RevenueStatisticEvent;
|
||||
use App\Model\Revenue;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Timesheet\DateTimeFactory;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
final class AmountPreviousYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TimesheetRepository $repository,
|
||||
SystemConfiguration $systemConfiguration,
|
||||
private readonly EventDispatcherInterface $dispatcher
|
||||
) {
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
'icon' => 'money',
|
||||
'color' => WidgetInterface::COLOR_YEAR,
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
$begin = $this->createPreviousYearStartDate();
|
||||
$end = $this->createPreviousYearEndDate();
|
||||
|
||||
if (null !== ($financialYear = $this->systemConfiguration->getFinancialYearStart())) {
|
||||
$factory = new DateTimeFactory($this->getTimezone());
|
||||
$begin = $factory->createStartOfPreviousFinancialYear($financialYear);
|
||||
$end = $factory->createEndOfPreviousFinancialYear($begin);
|
||||
$this->isFinancialYear = true;
|
||||
}
|
||||
|
||||
return $this->getYearData($begin, $end, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): array
|
||||
{
|
||||
try {
|
||||
/** @var array<Revenue> $data */
|
||||
$data = $this->repository->getRevenue($begin, $end, null);
|
||||
|
||||
$event = new RevenueStatisticEvent($begin, $end);
|
||||
foreach ($data as $row) {
|
||||
$event->addRevenue($row->getCurrency(), $row->getAmount());
|
||||
}
|
||||
$this->dispatcher->dispatch($event);
|
||||
|
||||
return $event->getRevenue();
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'AmountPreviousYear';
|
||||
}
|
||||
|
||||
protected function getFinancialYearTitle(): string
|
||||
{
|
||||
return 'stats.amountPreviousFinancialYear';
|
||||
}
|
||||
|
||||
public function getTemplateName(): string
|
||||
{
|
||||
return 'widget/widget-counter-money.html.twig';
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_all_data'];
|
||||
}
|
||||
}
|
|
@ -29,8 +29,9 @@ final class AmountToday extends AbstractAmountPeriod
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createTodayStartDate(), $this->createTodayEndDate(), $options);
|
||||
}
|
||||
|
|
|
@ -29,8 +29,9 @@ final class AmountWeek extends AbstractAmountPeriod
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createWeekStartDate(), $this->createWeekEndDate(), $options);
|
||||
}
|
||||
|
|
|
@ -19,8 +19,11 @@ use Psr\EventDispatcher\EventDispatcherInterface;
|
|||
|
||||
final class AmountYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository, SystemConfiguration $systemConfiguration, private EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TimesheetRepository $repository,
|
||||
SystemConfiguration $systemConfiguration,
|
||||
private readonly EventDispatcherInterface $dispatcher
|
||||
) {
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
|
@ -38,8 +41,9 @@ final class AmountYear extends AbstractCounterYear
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): array
|
||||
{
|
||||
try {
|
||||
/** @var array<Revenue> $data */
|
||||
|
|
43
src/Widget/Type/AmountYesterday.php
Normal file
43
src/Widget/Type/AmountYesterday.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class AmountYesterday extends AbstractAmountPeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TODAY], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'AmountYesterday';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createYesterdayStartDate(), $this->createYesterdayEndDate(), $options);
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_all_data'];
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class DurationMonth extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ final class DurationMonth extends AbstractCounterDuration
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createMonthStartDate(), $this->createMonthEndDate(), null);
|
||||
|
|
59
src/Widget/Type/DurationPreviousMonth.php
Normal file
59
src/Widget/Type/DurationPreviousMonth.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class DurationPreviousMonth extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_MONTH], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_other_timesheet'];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'DurationPreviousMonth';
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'stats.durationPreviousMonth';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createPreviousMonthStartDate(), $this->createPreviousMonthEndDate(), null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
59
src/Widget/Type/DurationPreviousWeek.php
Normal file
59
src/Widget/Type/DurationPreviousWeek.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class DurationPreviousWeek extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_WEEK], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_other_timesheet'];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'DurationPreviousWeek';
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'stats.durationPreviousWeek';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createPreviousWeekStartDate(), $this->createPreviousWeekEndDate(), null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
90
src/Widget/Type/DurationPreviousYear.php
Normal file
90
src/Widget/Type/DurationPreviousYear.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Timesheet\DateTimeFactory;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class DurationPreviousYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TimesheetRepository $repository,
|
||||
SystemConfiguration $systemConfiguration
|
||||
) {
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
'icon' => 'duration',
|
||||
'color' => WidgetInterface::COLOR_YEAR,
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
$begin = $this->createPreviousYearStartDate();
|
||||
$end = $this->createPreviousYearEndDate();
|
||||
|
||||
if (null !== ($financialYear = $this->systemConfiguration->getFinancialYearStart())) {
|
||||
$factory = new DateTimeFactory($this->getTimezone());
|
||||
$begin = $factory->createStartOfPreviousFinancialYear($financialYear);
|
||||
$end = $factory->createEndOfPreviousFinancialYear($begin);
|
||||
$this->isFinancialYear = true;
|
||||
}
|
||||
|
||||
return $this->getYearData($begin, $end, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($begin, $end, null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'DurationPreviousYear';
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_other_timesheet'];
|
||||
}
|
||||
|
||||
protected function getFinancialYearTitle(): string
|
||||
{
|
||||
return 'stats.durationPreviousFinancialYear';
|
||||
}
|
||||
|
||||
public function getTemplateName(): string
|
||||
{
|
||||
return 'widget/widget-counter-duration.html.twig';
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class DurationToday extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class DurationTotal extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ final class DurationTotal extends AbstractCounterDuration
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange(null, null, null);
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class DurationWeek extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ final class DurationWeek extends AbstractCounterDuration
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createWeekStartDate(), $this->createWeekEndDate(), null);
|
||||
|
|
|
@ -16,8 +16,10 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class DurationYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository, SystemConfiguration $systemConfiguration)
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TimesheetRepository $repository,
|
||||
SystemConfiguration $systemConfiguration
|
||||
) {
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
|
@ -36,7 +38,7 @@ final class DurationYear extends AbstractCounterYear
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($begin, $end, null);
|
||||
|
|
59
src/Widget/Type/DurationYesterday.php
Normal file
59
src/Widget/Type/DurationYesterday.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class DurationYesterday extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TODAY], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_other_timesheet'];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'DurationYesterday';
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'stats.durationYesterday';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createYesterdayStartDate(), $this->createYesterdayEndDate(), null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class TotalsActivity extends AbstractWidget
|
||||
{
|
||||
public function __construct(private ActivityRepository $activity)
|
||||
public function __construct(private readonly ActivityRepository $activity)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ final class TotalsActivity extends AbstractWidget
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$query = new ActivityQuery();
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class TotalsCustomer extends AbstractWidget
|
||||
{
|
||||
public function __construct(private CustomerRepository $customer)
|
||||
public function __construct(private readonly CustomerRepository $customer)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ final class TotalsCustomer extends AbstractWidget
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$query = new CustomerQuery();
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class TotalsProject extends AbstractWidget
|
||||
{
|
||||
public function __construct(private ProjectRepository $project)
|
||||
public function __construct(private readonly ProjectRepository $project)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ final class TotalsProject extends AbstractWidget
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$query = new ProjectQuery();
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class TotalsUser extends AbstractWidget
|
||||
{
|
||||
public function __construct(private UserRepository $repository)
|
||||
public function __construct(private readonly UserRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ final class TotalsUser extends AbstractWidget
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$query = new UserQuery();
|
||||
|
|
|
@ -29,8 +29,9 @@ final class UserAmountMonth extends AbstractUserRevenuePeriod
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createMonthStartDate(), $this->createMonthEndDate(), $options);
|
||||
}
|
||||
|
|
38
src/Widget/Type/UserAmountPreviousMonth.php
Normal file
38
src/Widget/Type/UserAmountPreviousMonth.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserAmountPreviousMonth extends AbstractUserRevenuePeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_MONTH], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'UserAmountPreviousMonth';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createPreviousMonthStartDate(), $this->createPreviousMonthEndDate(), $options);
|
||||
}
|
||||
}
|
37
src/Widget/Type/UserAmountPreviousWeek.php
Normal file
37
src/Widget/Type/UserAmountPreviousWeek.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserAmountPreviousWeek extends AbstractUserRevenuePeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_WEEK], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'UserAmountPreviousWeek';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return $this->getRevenue($this->createPreviousWeekStartDate(), $this->createPreviousWeekEndDate(), $options);
|
||||
}
|
||||
}
|
105
src/Widget/Type/UserAmountPreviousYear.php
Normal file
105
src/Widget/Type/UserAmountPreviousYear.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Event\UserRevenueStatisticEvent;
|
||||
use App\Model\Revenue;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Timesheet\DateTimeFactory;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
final class UserAmountPreviousYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TimesheetRepository $repository,
|
||||
SystemConfiguration $systemConfiguration,
|
||||
private readonly EventDispatcherInterface $dispatcher
|
||||
) {
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
public function getTemplateName(): string
|
||||
{
|
||||
return 'widget/widget-counter-money.html.twig';
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_rate_own_timesheet'];
|
||||
}
|
||||
|
||||
protected function getFinancialYearTitle(): string
|
||||
{
|
||||
return 'stats.amountPreviousFinancialYear';
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'UserAmountPreviousYear';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
'icon' => 'money',
|
||||
'color' => WidgetInterface::COLOR_YEAR,
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
$begin = $this->createPreviousYearStartDate();
|
||||
$end = $this->createPreviousYearEndDate();
|
||||
|
||||
if (null !== ($financialYear = $this->systemConfiguration->getFinancialYearStart())) {
|
||||
$factory = new DateTimeFactory($this->getTimezone());
|
||||
$begin = $factory->createStartOfPreviousFinancialYear($financialYear);
|
||||
$end = $factory->createEndOfPreviousFinancialYear($begin);
|
||||
$this->isFinancialYear = true;
|
||||
}
|
||||
|
||||
return $this->getYearData($begin, $end, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): array
|
||||
{
|
||||
try {
|
||||
/** @var array<Revenue> $data */
|
||||
$data = $this->repository->getRevenue($begin, $end, $this->getUser());
|
||||
|
||||
$event = new UserRevenueStatisticEvent($this->getUser(), $begin, $end);
|
||||
foreach ($data as $row) {
|
||||
$event->addRevenue($row->getCurrency(), $row->getAmount());
|
||||
}
|
||||
$this->dispatcher->dispatch($event);
|
||||
|
||||
return $event->getRevenue();
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,8 +29,9 @@ final class UserAmountToday extends AbstractUserRevenuePeriod
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createTodayStartDate(), $this->createTodayEndDate(), $options);
|
||||
}
|
||||
|
|
|
@ -29,8 +29,9 @@ final class UserAmountTotal extends AbstractUserRevenuePeriod
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue(null, null, $options);
|
||||
}
|
||||
|
|
|
@ -29,8 +29,9 @@ final class UserAmountWeek extends AbstractUserRevenuePeriod
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createWeekStartDate(), $this->createWeekEndDate(), $options);
|
||||
}
|
||||
|
|
|
@ -19,8 +19,11 @@ use Psr\EventDispatcher\EventDispatcherInterface;
|
|||
|
||||
final class UserAmountYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository, SystemConfiguration $systemConfiguration, private EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TimesheetRepository $repository,
|
||||
SystemConfiguration $systemConfiguration,
|
||||
private readonly EventDispatcherInterface $dispatcher
|
||||
) {
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
|
@ -58,8 +61,9 @@ final class UserAmountYear extends AbstractCounterYear
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): array
|
||||
{
|
||||
try {
|
||||
/** @var array<Revenue> $data */
|
||||
|
|
38
src/Widget/Type/UserAmountYesterday.php
Normal file
38
src/Widget/Type/UserAmountYesterday.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserAmountYesterday extends AbstractUserRevenuePeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TODAY], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'UserAmountYesterday';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getRevenue($this->createYesterdayStartDate(), $this->createYesterdayEndDate(), $options);
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class UserDurationMonth extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ final class UserDurationMonth extends AbstractCounterDuration
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createMonthStartDate(), $this->createMonthEndDate(), $this->getUser());
|
||||
|
|
54
src/Widget/Type/UserDurationPreviousMonth.php
Normal file
54
src/Widget/Type/UserDurationPreviousMonth.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserDurationPreviousMonth extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_MONTH], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_own_timesheet'];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'UserDurationPreviousMonth';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createPreviousMonthStartDate(), $this->createPreviousMonthEndDate(), $this->getUser());
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
54
src/Widget/Type/UserDurationPreviousWeek.php
Normal file
54
src/Widget/Type/UserDurationPreviousWeek.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserDurationPreviousWeek extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_WEEK], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_own_timesheet'];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'UserDurationPreviousWeek';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createPreviousWeekStartDate(), $this->createPreviousWeekEndDate(), $this->getUser());
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
85
src/Widget/Type/UserDurationPreviousYear.php
Normal file
85
src/Widget/Type/UserDurationPreviousYear.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Timesheet\DateTimeFactory;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserDurationPreviousYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TimesheetRepository $repository,
|
||||
SystemConfiguration $systemConfiguration
|
||||
) {
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'UserDurationPreviousYear';
|
||||
}
|
||||
|
||||
protected function getFinancialYearTitle(): string
|
||||
{
|
||||
return 'stats.durationPreviousFinancialYear';
|
||||
}
|
||||
|
||||
public function getTemplateName(): string
|
||||
{
|
||||
return 'widget/widget-counter-duration.html.twig';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
'icon' => 'duration',
|
||||
'color' => WidgetInterface::COLOR_YEAR,
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
$begin = $this->createPreviousYearStartDate();
|
||||
$end = $this->createPreviousYearEndDate();
|
||||
|
||||
if (null !== ($financialYear = $this->systemConfiguration->getFinancialYearStart())) {
|
||||
$factory = new DateTimeFactory($this->getTimezone());
|
||||
$begin = $factory->createStartOfPreviousFinancialYear($financialYear);
|
||||
$end = $factory->createEndOfPreviousFinancialYear($begin);
|
||||
$this->isFinancialYear = true;
|
||||
}
|
||||
|
||||
return $this->getYearData($begin, $end, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($begin, $end, $this->getUser());
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class UserDurationToday extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ final class UserDurationToday extends AbstractCounterDuration
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createTodayStartDate(), $this->createTodayEndDate(), $this->getUser());
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class UserDurationTotal extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ final class UserDurationTotal extends AbstractCounterDuration
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange(null, null, $this->getUser());
|
||||
|
|
|
@ -15,7 +15,7 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class UserDurationWeek extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ final class UserDurationWeek extends AbstractCounterDuration
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createWeekStartDate(), $this->createWeekEndDate(), $this->getUser());
|
||||
|
|
|
@ -16,8 +16,10 @@ use App\Widget\WidgetInterface;
|
|||
|
||||
final class UserDurationYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository, SystemConfiguration $systemConfiguration)
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TimesheetRepository $repository,
|
||||
SystemConfiguration $systemConfiguration
|
||||
) {
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
|
@ -46,7 +48,7 @@ final class UserDurationYear extends AbstractCounterYear
|
|||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($begin, $end, $this->getUser());
|
||||
|
|
54
src/Widget/Type/UserDurationYesterday.php
Normal file
54
src/Widget/Type/UserDurationYesterday.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?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\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserDurationYesterday extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private readonly TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
@return array<string, string|bool|int|null|array<string, mixed>>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TODAY], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return ['view_own_timesheet'];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'UserDurationYesterday';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
*/
|
||||
public function getData(array $options = []): int
|
||||
{
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createYesterdayStartDate(), $this->createYesterdayEndDate(), $this->getUser());
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Model\ProjectBudgetStatisticModel;
|
||||
use App\Project\ProjectStatisticService;
|
||||
use App\Repository\Loader\TeamLoader;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
@ -19,8 +20,7 @@ final class UserTeamProjects extends AbstractWidget
|
|||
public function __construct(
|
||||
private readonly ProjectStatisticService $statisticService,
|
||||
private readonly EntityManagerInterface $entityManager
|
||||
)
|
||||
{
|
||||
) {
|
||||
}
|
||||
|
||||
public function getWidth(): int
|
||||
|
@ -61,8 +61,9 @@ final class UserTeamProjects extends AbstractWidget
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return ProjectBudgetStatisticModel[]
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$teams = $user->getTeams();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Entity\Team;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserTeams extends AbstractWidget
|
||||
|
@ -48,8 +49,9 @@ final class UserTeams extends AbstractWidget
|
|||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null|array<string, mixed>> $options
|
||||
* @return Team[]
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
public function getData(array $options = []): array
|
||||
{
|
||||
return $this->getUser()->getTeams();
|
||||
}
|
||||
|
|
|
@ -894,9 +894,9 @@
|
|||
<source>stats.workingTimeFinancialYear</source>
|
||||
<target>Financial year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="BXBFJP8" resname="stats.workingTime" xml:space="preserve" approved="yes">
|
||||
<trans-unit id="BXBFJP8" resname="stats.workingTime">
|
||||
<source>Working hours</source>
|
||||
<target state="final">Working hours</target>
|
||||
<target>Working hours</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Nx9_QiO" resname="revenue">
|
||||
<source>revenue</source>
|
||||
|
@ -906,22 +906,42 @@
|
|||
<source>stats.durationToday</source>
|
||||
<target>Working hours today</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="7R2dowt" resname="stats.durationYesterday">
|
||||
<source>stats.durationYesterday</source>
|
||||
<target>Working hours yesterday</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="XhKalZH" resname="stats.durationWeek">
|
||||
<source>stats.durationWeek</source>
|
||||
<target>Working hours this week</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="t5QlmRi" resname="stats.durationPreviousWeek">
|
||||
<source>stats.durationPreviousWeek</source>
|
||||
<target>Working hours previous week</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="uaOwf_P" resname="stats.durationMonth">
|
||||
<source>stats.durationMonth</source>
|
||||
<target>Working hours this month</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="c7yE5.3" resname="stats.durationPreviousMonth">
|
||||
<source>stats.durationPreviousMonth</source>
|
||||
<target>Working hours previous month</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="WqF84KR" resname="stats.durationYear">
|
||||
<source>stats.durationYear</source>
|
||||
<target>Working hours this year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Uh1JUB5" resname="stats.durationPreviousYear">
|
||||
<source>stats.durationPreviousYear</source>
|
||||
<target>Working hours previous year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="xkugSAA" resname="stats.durationFinancialYear">
|
||||
<source>stats.durationFinancialYear</source>
|
||||
<target>Working hours this financial year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="MxLC46J" resname="stats.durationPreviousFinancialYear">
|
||||
<source>stats.durationPreviousFinancialYear</source>
|
||||
<target>Working hours previous financial year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="YtvPnl1" resname="stats.durationTotal">
|
||||
<source>stats.durationTotal</source>
|
||||
<target>Working hours total</target>
|
||||
|
@ -930,18 +950,34 @@
|
|||
<source>stats.userDurationToday</source>
|
||||
<target>My working hours today</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="k5ZZw6d" resname="stats.userDurationYesterday">
|
||||
<source>stats.userDurationYesterday</source>
|
||||
<target>My working hours yesterday</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="DXcvOMM" resname="stats.userDurationWeek">
|
||||
<source>stats.userDurationWeek</source>
|
||||
<target>My working hours this week</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="uxUdtKD" resname="stats.userDurationPreviousWeek">
|
||||
<source>stats.userDurationPreviousWeek</source>
|
||||
<target>My working hours previous week</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="0WpgaGa" resname="stats.userDurationMonth">
|
||||
<source>stats.userDurationMonth</source>
|
||||
<target>My working hours this month</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Y_jQvXv" resname="stats.userDurationPreviousMonth">
|
||||
<source>stats.userDurationPreviousMonth</source>
|
||||
<target>My working hours previous month</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="BjyLITj" resname="stats.userDurationYear">
|
||||
<source>stats.userDurationYear</source>
|
||||
<target>My working hours this year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="NVwZpsz" resname="stats.userDurationPreviousYear">
|
||||
<source>stats.userDurationPreviousYear</source>
|
||||
<target>My working hours previous year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="EedlgkM" resname="stats.userDurationTotal">
|
||||
<source>stats.userDurationTotal</source>
|
||||
<target>My working hours total</target>
|
||||
|
@ -954,22 +990,42 @@
|
|||
<source>stats.amountToday</source>
|
||||
<target>Revenue today</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sP2cnvE" resname="stats.amountYesterday">
|
||||
<source>stats.amountYesterday</source>
|
||||
<target>Revenue yesterday</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="xnJvYAE" resname="stats.amountWeek">
|
||||
<source>stats.amountWeek</source>
|
||||
<target>Revenue this week</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="7hEUrao" resname="stats.amountPreviousWeek">
|
||||
<source>stats.amountPreviousWeek</source>
|
||||
<target>Revenue previous week</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ulr3reE" resname="stats.amountMonth">
|
||||
<source>stats.amountMonth</source>
|
||||
<target>Revenue this month</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="28vpRIL" resname="stats.amountPreviousMonth">
|
||||
<source>stats.amountPreviousMonth</source>
|
||||
<target>Revenue previous month</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="bQZyZaO" resname="stats.amountYear">
|
||||
<source>stats.amountYear</source>
|
||||
<target>Revenue this year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="1jHLd_9" resname="stats.amountPreviousYear">
|
||||
<source>stats.amountPreviousYear</source>
|
||||
<target>Revenue previous year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="wuUWovn" resname="stats.amountFinancialYear">
|
||||
<source>stats.amountFinancialYear</source>
|
||||
<target>Revenue this financial year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="AAnLEzy" resname="stats.amountPreviousFinancialYear">
|
||||
<source>stats.amountPreviousFinancialYear</source>
|
||||
<target>Revenue previous financial year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Z0fz23v" resname="stats.amountTotal">
|
||||
<source>stats.amountTotal</source>
|
||||
<target>Total revenue</target>
|
||||
|
@ -978,18 +1034,34 @@
|
|||
<source>stats.userAmountToday</source>
|
||||
<target>My revenue today</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="rI6FnFK" resname="stats.userAmountYesterday">
|
||||
<source>stats.userAmountYesterday</source>
|
||||
<target>My revenue yesterday</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="LDS9o5X" resname="stats.userAmountWeek">
|
||||
<source>stats.userAmountWeek</source>
|
||||
<target>My revenue this week</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="c_eMtvp" resname="stats.userAmountPreviousWeek">
|
||||
<source>stats.userAmountPreviousWeek</source>
|
||||
<target>My revenue previous week</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="E3Kj9lt" resname="stats.userAmountMonth">
|
||||
<source>stats.userAmountMonth</source>
|
||||
<target>My revenue this month</target>
|
||||
</trans-unit>
|
||||
<trans-unit id=".RqeEEx" resname="stats.userAmountPreviousMonth">
|
||||
<source>stats.userAmountPreviousMonth</source>
|
||||
<target>My revenue previous month</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="xvdsZsS" resname="stats.userAmountYear">
|
||||
<source>stats.userAmountYear</source>
|
||||
<target>My revenue this year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="uZKsdVm" resname="stats.userAmountPreviousYear">
|
||||
<source>stats.userAmountPreviousYear</source>
|
||||
<target>My revenue previous year</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="9jlbhkf" resname="stats.userAmountTotal">
|
||||
<source>stats.userAmountTotal</source>
|
||||
<target>My total revenue</target>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue