Release 2.41 (#5653)
This commit is contained in:
@@ -422,12 +422,12 @@ class TimesheetControllerTest extends APIControllerBaseTestCase
|
||||
'begin' => '2020-03-27T14:35:00+1300',
|
||||
'end' => '2020-03-28T03:30:00+1300',
|
||||
'description' => "**foo**\nbar",
|
||||
'duration' => 46500,
|
||||
'duration' => 46500, // 12,916 => rounded 12,92 * 137,21 = 46512
|
||||
'exported' => true,
|
||||
'metaFields' => [],
|
||||
'hourlyRate' => 137.21,
|
||||
'rate' => 1772.2958,
|
||||
'internalRate' => 1772.2958,
|
||||
'rate' => 1772.75, // 12,92 * 137,21
|
||||
'internalRate' => 1772.75,
|
||||
];
|
||||
|
||||
foreach ($expected as $key => $value) {
|
||||
|
||||
72
tests/API/ViewHandlerTest.php
Normal file
72
tests/API/ViewHandlerTest.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Tests\API;
|
||||
|
||||
use App\API\ViewHandler;
|
||||
use App\Utils\Pagination;
|
||||
use FOS\RestBundle\View\ConfigurableViewHandlerInterface;
|
||||
use FOS\RestBundle\View\View;
|
||||
use Pagerfanta\Adapter\ArrayAdapter;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
#[CoversClass(ViewHandler::class)]
|
||||
class ViewHandlerTest extends TestCase
|
||||
{
|
||||
public function testValues(): void
|
||||
{
|
||||
$base = $this->createMock(ConfigurableViewHandlerInterface::class);
|
||||
$base->expects($this->once())->method('supports')->willReturn(true);
|
||||
$base->expects($this->exactly(2))->method('setExclusionStrategyGroups');
|
||||
$base->expects($this->once())->method('setExclusionStrategyVersion');
|
||||
$base->expects($this->once())->method('setSerializeNullStrategy');
|
||||
$base->expects($this->once())->method('registerHandler');
|
||||
$base->expects($this->once())->method('createRedirectResponse')->willReturn(new Response());
|
||||
$base->expects($this->once())->method('createResponse')->willReturn(new Response());
|
||||
$base->expects($this->once())->method('handle')->willReturn(new Response());
|
||||
|
||||
$sut = new ViewHandler($base);
|
||||
self::assertTrue($sut->supports('asdf'));
|
||||
$sut->setExclusionStrategyGroups(['bar', 'test']);
|
||||
$sut->setExclusionStrategyGroups('foo');
|
||||
$sut->setExclusionStrategyVersion('1.0');
|
||||
$sut->setSerializeNullStrategy(true);
|
||||
|
||||
$sut->registerHandler('bla', function () {});
|
||||
$response = $sut->createRedirectResponse(new View('bar123'), 'https://www.example.com', 'json');
|
||||
self::assertInstanceOf(Response::class, $response);
|
||||
$response = $sut->createResponse(new View('bar123'), new Request(), 'json');
|
||||
self::assertInstanceOf(Response::class, $response);
|
||||
|
||||
$results = ['foo' => 'bar', 'hello' => 'world'];
|
||||
|
||||
$pagination = new Pagination(new ArrayAdapter($results));
|
||||
$view = new View($pagination);
|
||||
$headers = $view->getHeaders();
|
||||
|
||||
self::assertSame($pagination, $view->getData());
|
||||
self::assertArrayNotHasKey('x-page', $headers);
|
||||
self::assertArrayNotHasKey('x-total-count', $headers);
|
||||
self::assertArrayNotHasKey('x-total-pages', $headers);
|
||||
self::assertArrayNotHasKey('x-per-page', $headers);
|
||||
|
||||
$response = $sut->handle($view, new Request());
|
||||
self::assertInstanceOf(Response::class, $response);
|
||||
|
||||
$headers = $view->getHeaders();
|
||||
self::assertSame($results, $view->getData());
|
||||
self::assertArrayHasKey('x-page', $headers);
|
||||
self::assertArrayHasKey('x-total-count', $headers);
|
||||
self::assertArrayHasKey('x-total-pages', $headers);
|
||||
self::assertArrayHasKey('x-per-page', $headers);
|
||||
}
|
||||
}
|
||||
@@ -209,6 +209,7 @@ class ColumnConverterTest extends TestCase
|
||||
|
||||
$template = new Template('bar', 'foo');
|
||||
$template->setColumns([
|
||||
'id',
|
||||
'date',
|
||||
'begin',
|
||||
'end',
|
||||
@@ -252,6 +253,7 @@ class ColumnConverterTest extends TestCase
|
||||
$columns = $sut->getColumns($template, $query);
|
||||
|
||||
$expected = [
|
||||
'id',
|
||||
'date',
|
||||
'begin',
|
||||
'end',
|
||||
|
||||
@@ -68,13 +68,16 @@ class PriceInvoiceCalculatorTest extends AbstractCalculatorTestCase
|
||||
$timesheet2 = new Timesheet();
|
||||
$timesheet2->setBegin(new DateTime('2018-11-29'));
|
||||
$timesheet2->setEnd(new DateTime());
|
||||
$timesheet2->setDuration(400);
|
||||
$timesheet2->setDuration(400); // 396
|
||||
$timesheet2->setHourlyRate(293.27);
|
||||
$timesheet2->setRate(84.75);
|
||||
$timesheet2->setRate(84.75); // 32,26
|
||||
$timesheet2->setUser($user);
|
||||
$timesheet2->setActivity((new Activity())->setName('bar'));
|
||||
$timesheet2->setProject($project2);
|
||||
|
||||
// 325,53
|
||||
// duration 4000 = 3996
|
||||
|
||||
$timesheet3 = new Timesheet();
|
||||
$timesheet3->setBegin(new DateTime('2018-11-28'));
|
||||
$timesheet3->setEnd(new DateTime());
|
||||
@@ -85,25 +88,34 @@ class PriceInvoiceCalculatorTest extends AbstractCalculatorTestCase
|
||||
$timesheet3->setActivity((new Activity())->setName('foo'));
|
||||
$timesheet3->setProject($project1);
|
||||
|
||||
// 325,53+111,11
|
||||
// duration 1800
|
||||
|
||||
$timesheet4 = new Timesheet();
|
||||
$timesheet4->setBegin(new DateTime('2018-11-28'));
|
||||
$timesheet4->setEnd(new DateTime());
|
||||
$timesheet4->setDuration(400);
|
||||
$timesheet4->setDuration(400); // 396
|
||||
$timesheet4->setHourlyRate(0);
|
||||
$timesheet4->setRate(1947.99);
|
||||
$timesheet4->setUser($user);
|
||||
$timesheet4->setActivity((new Activity())->setName('blub'));
|
||||
$timesheet4->setProject($project2);
|
||||
|
||||
// 325,53+111,11+1947,99
|
||||
// duration 400
|
||||
|
||||
$timesheet5 = new Timesheet();
|
||||
$timesheet5->setBegin(new DateTime('2018-11-28'));
|
||||
$timesheet5->setEnd(new DateTime());
|
||||
$timesheet5->setDuration(400);
|
||||
$timesheet5->setDuration(400); // 396
|
||||
$timesheet5->setRate(84);
|
||||
$timesheet5->setUser(new User());
|
||||
$timesheet5->setActivity(new Activity());
|
||||
$timesheet5->setProject($project3);
|
||||
|
||||
// 325,53+111,11+1947,99+84
|
||||
// duration 400
|
||||
|
||||
$entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5];
|
||||
|
||||
$query = new InvoiceQuery();
|
||||
@@ -115,12 +127,14 @@ class PriceInvoiceCalculatorTest extends AbstractCalculatorTestCase
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
// (325,53+111,11+1947,99+84)*1,19
|
||||
|
||||
self::assertEquals('price', $sut->getId());
|
||||
self::assertEquals(3000.13, $sut->getTotal());
|
||||
self::assertEquals(2937.67, $sut->getTotal());
|
||||
$this->assertTax($sut, 19);
|
||||
self::assertEquals('EUR', $model->getCurrency());
|
||||
self::assertEquals(2521.12, $sut->getSubtotal());
|
||||
self::assertEquals(6600, $sut->getTimeWorked());
|
||||
self::assertEquals(2468.63, $sut->getSubtotal());
|
||||
self::assertEquals(6596, $sut->getTimeWorked());
|
||||
|
||||
$entries = $sut->getEntries();
|
||||
self::assertCount(4, $entries);
|
||||
@@ -130,7 +144,7 @@ class PriceInvoiceCalculatorTest extends AbstractCalculatorTestCase
|
||||
self::assertEquals('2018-11-28', $entries[2]->getBegin()?->format('Y-m-d'));
|
||||
self::assertEquals('2018-11-29', $entries[3]->getBegin()?->format('Y-m-d'));
|
||||
|
||||
self::assertEquals(378.02, $entries[3]->getRate());
|
||||
self::assertEquals(325.53, $entries[3]->getRate());
|
||||
self::assertEquals(111.11, $entries[0]->getRate());
|
||||
self::assertEquals(1947.99, $entries[1]->getRate());
|
||||
self::assertEquals(84, $entries[2]->getRate());
|
||||
|
||||
@@ -94,11 +94,11 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTestCase
|
||||
$sut->setModel($model);
|
||||
|
||||
self::assertEquals('short', $sut->getId());
|
||||
self::assertEquals(562.28, $sut->getTotal());
|
||||
self::assertEquals(561.87, $sut->getTotal());
|
||||
$this->assertTax($sut, 19);
|
||||
self::assertEquals('EUR', $model->getCurrency());
|
||||
self::assertEquals(472.5, $sut->getSubtotal());
|
||||
self::assertEquals(5800, $sut->getTimeWorked());
|
||||
self::assertEquals(472.16, $sut->getSubtotal());
|
||||
self::assertEquals(5796, $sut->getTimeWorked());
|
||||
self::assertEquals(1, \count($sut->getEntries()));
|
||||
|
||||
$entries = $sut->getEntries();
|
||||
@@ -109,8 +109,8 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTestCase
|
||||
self::assertEquals('', $result->getDescription());
|
||||
self::assertEquals(293.27, $result->getHourlyRate());
|
||||
self::assertNull($result->getFixedRate());
|
||||
self::assertEquals(472.5, $result->getRate());
|
||||
self::assertEquals(5800, $result->getDuration());
|
||||
self::assertEquals(472.16, $result->getRate());
|
||||
self::assertEquals(5796, $result->getDuration());
|
||||
self::assertEquals(3, $result->getAmount());
|
||||
self::assertEquals(['foo', 'bar', 'bar1'], $result->getTags());
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ class InvoiceItemTest extends TestCase
|
||||
self::assertNull($sut->getFixedRate());
|
||||
self::assertNull($sut->getEnd());
|
||||
self::assertEquals(0.00, $sut->getRate());
|
||||
self::assertEquals(0.00, $sut->getInternalRate());
|
||||
self::assertEquals(0.00, $sut->getInternalRate()); // @phpstan-ignore method.deprecated
|
||||
self::assertEquals(0.00, $sut->getAppliedRate());
|
||||
self::assertNull($sut->getProject());
|
||||
self::assertIsArray($sut->getAdditionalFields());
|
||||
self::assertEmpty($sut->getAdditionalFields());
|
||||
@@ -53,4 +54,23 @@ class InvoiceItemTest extends TestCase
|
||||
$sut->addTag('foo1');
|
||||
self::assertEquals(['foo', 'foo1', 'BaR'], $sut->getTags());
|
||||
}
|
||||
|
||||
public function testRates(): void
|
||||
{
|
||||
$sut = new InvoiceItem();
|
||||
|
||||
self::assertEquals(0.00, $sut->getHourlyRate());
|
||||
self::assertNull($sut->getFixedRate());
|
||||
self::assertEquals(0.00, $sut->getAppliedRate());
|
||||
|
||||
$sut->setHourlyRate(13.50);
|
||||
self::assertEquals(13.50, $sut->getHourlyRate());
|
||||
self::assertNull($sut->getFixedRate());
|
||||
self::assertEquals(13.50, $sut->getAppliedRate());
|
||||
|
||||
$sut->setFixedRate(30.24);
|
||||
self::assertEquals(13.50, $sut->getHourlyRate());
|
||||
self::assertEquals(30.24, $sut->getFixedRate());
|
||||
self::assertEquals(30.24, $sut->getAppliedRate());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use App\Repository\Query\ActivityQuery;
|
||||
use App\Repository\Query\BaseQuery;
|
||||
use App\Repository\Query\DateRangeInterface;
|
||||
use App\Repository\Query\TimesheetQuery;
|
||||
use App\Repository\Query\VisibilityInterface;
|
||||
use App\Utils\SearchTerm;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@@ -342,6 +343,20 @@ class BaseQueryTest extends TestCase
|
||||
self::assertEquals([13, 27], $sut->getProjectIds());
|
||||
}
|
||||
|
||||
protected function assertVisibility(VisibilityInterface $sut): void
|
||||
{
|
||||
self::assertEquals(VisibilityInterface::SHOW_VISIBLE, $sut->getVisibility());
|
||||
|
||||
$sut->setVisibility(VisibilityInterface::SHOW_BOTH);
|
||||
self::assertEquals(VisibilityInterface::SHOW_BOTH, $sut->getVisibility());
|
||||
|
||||
$sut->setVisibility(VisibilityInterface::SHOW_HIDDEN);
|
||||
self::assertEquals(VisibilityInterface::SHOW_HIDDEN, $sut->getVisibility());
|
||||
|
||||
$sut->setVisibility(VisibilityInterface::SHOW_VISIBLE);
|
||||
self::assertEquals(VisibilityInterface::SHOW_VISIBLE, $sut->getVisibility());
|
||||
}
|
||||
|
||||
protected function assertDateRangeTrait(DateRangeInterface $sut): void
|
||||
{
|
||||
self::assertNull($sut->getBegin());
|
||||
|
||||
@@ -20,6 +20,7 @@ class CustomerQueryTest extends BaseQueryTest
|
||||
$sut = new CustomerQuery();
|
||||
|
||||
$this->assertBaseQuery($sut, 'name');
|
||||
$this->assertVisibility($sut);
|
||||
$this->assertResetByFormError(new CustomerQuery(), 'name');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ class ProjectQueryTest extends BaseQueryTest
|
||||
$sut = new ProjectQuery();
|
||||
|
||||
$this->assertBaseQuery($sut, 'name');
|
||||
$this->assertVisibility($sut);
|
||||
$this->assertCustomer($sut);
|
||||
$this->assertResetByFormError(new ProjectQuery(), 'name');
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ class TagQueryTest extends BaseQueryTest
|
||||
$sut = new TagQuery();
|
||||
|
||||
$this->assertBaseQuery($sut, 'name');
|
||||
$this->assertVisibility($sut);
|
||||
$this->assertResetByFormError(new TagQuery(), 'name');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ class UserQueryTest extends BaseQueryTest
|
||||
{
|
||||
$sut = new UserQuery();
|
||||
$this->assertBaseQuery($sut, 'username');
|
||||
$this->assertVisibility($sut);
|
||||
$this->assertRole($sut);
|
||||
$this->assertSearchTeam($sut);
|
||||
$this->assertResetByFormError(new UserQuery(), 'username');
|
||||
|
||||
@@ -28,7 +28,7 @@ use PHPUnit\Framework\TestCase;
|
||||
#[CoversClass(RateCalculator::class)]
|
||||
class RateCalculatorTest extends TestCase
|
||||
{
|
||||
protected function getRateRepositoryMock(array $rates = [])
|
||||
protected function getRateRepositoryMock(array $rates = []): TimesheetRepository
|
||||
{
|
||||
$mock = $this->getMockBuilder(TimesheetRepository::class)->disableOriginalConstructor()->getMock();
|
||||
if (!empty($rates)) {
|
||||
@@ -38,18 +38,26 @@ class RateCalculatorTest extends TestCase
|
||||
return $mock;
|
||||
}
|
||||
|
||||
public function testCalculateWithTimesheetHourlyRate(): void
|
||||
private function assertRateByTimesheetHourlyRate(int $duration, float $hourlyRate, float $rate): void
|
||||
{
|
||||
$record = new Timesheet();
|
||||
$record->setEnd(new \DateTime());
|
||||
$record->setDuration(1800);
|
||||
$record->setHourlyRate(100);
|
||||
$record->setDuration($duration);
|
||||
$record->setHourlyRate($hourlyRate);
|
||||
$record->setActivity(new Activity());
|
||||
$record->setUser($this->getTestUser());
|
||||
|
||||
$sut = new RateCalculator(new RateService([], $this->getRateRepositoryMock()));
|
||||
$sut->calculate($record, []);
|
||||
self::assertEquals(50, $record->getRate());
|
||||
self::assertEquals($rate, $record->getRate());
|
||||
}
|
||||
|
||||
public function testCalculateWithTimesheetHourlyRate(): void
|
||||
{
|
||||
$this->assertRateByTimesheetHourlyRate(1800, 100, 50);
|
||||
$this->assertRateByTimesheetHourlyRate(400, 100, 11);
|
||||
$this->assertRateByTimesheetHourlyRate(1234, 100, 34);
|
||||
$this->assertRateByTimesheetHourlyRate(2739, 100, 76);
|
||||
}
|
||||
|
||||
public function testCalculateWithTimesheetFixedRate(): void
|
||||
@@ -176,7 +184,7 @@ class RateCalculatorTest extends TestCase
|
||||
self::assertEquals($expectedInternalRate, $timesheet->getInternalRate());
|
||||
}
|
||||
|
||||
protected function getTestUser($rate = 75, $internalRate = 75)
|
||||
protected function getTestUser(?float $rate = 75.0, ?float $internalRate = 75.0): User
|
||||
{
|
||||
$user = new User();
|
||||
|
||||
@@ -230,19 +238,19 @@ class RateCalculatorTest extends TestCase
|
||||
self::assertEquals($expectedRate, $record->getRate());
|
||||
}
|
||||
|
||||
public static function getRuleDefinitions()
|
||||
public static function getRuleDefinitions(): array
|
||||
{
|
||||
$start = new \DateTime('12:00:00', new \DateTimeZone('UTC'));
|
||||
$day = $start->format('l');
|
||||
|
||||
return [
|
||||
[
|
||||
31837,
|
||||
31837, // 31824 = 8,84
|
||||
[],
|
||||
663.2708
|
||||
663
|
||||
],
|
||||
[
|
||||
31837,
|
||||
31837, // 31824 = 8,84
|
||||
[
|
||||
'default' => [
|
||||
'days' => [$day],
|
||||
@@ -253,10 +261,10 @@ class RateCalculatorTest extends TestCase
|
||||
'factor' => 1.5
|
||||
],
|
||||
],
|
||||
1326.5417
|
||||
1326 // 8,84 * 75 (see user) * 2
|
||||
],
|
||||
[
|
||||
31837,
|
||||
31837, // 31824 = 8,84
|
||||
[
|
||||
'default' => [
|
||||
'days' => [$day],
|
||||
@@ -267,7 +275,7 @@ class RateCalculatorTest extends TestCase
|
||||
'factor' => 1.5
|
||||
],
|
||||
],
|
||||
2321.4479
|
||||
2320.5 // 75 * 8,84 * 3,5
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ use PHPUnit\Framework\TestCase;
|
||||
#[CoversClass(RateService::class)]
|
||||
class RateServiceTest extends TestCase
|
||||
{
|
||||
protected function getRateRepositoryMock(array $rates = [])
|
||||
protected function getRateRepositoryMock(array $rates = []): TimesheetRepository
|
||||
{
|
||||
$mock = $this->getMockBuilder(TimesheetRepository::class)->disableOriginalConstructor()->getMock();
|
||||
if (!empty($rates)) {
|
||||
@@ -37,7 +37,7 @@ class RateServiceTest extends TestCase
|
||||
return $mock;
|
||||
}
|
||||
|
||||
private static function createDateTime(string $datetime = null): \DateTime
|
||||
private static function createDateTime(?string $datetime = null): \DateTime
|
||||
{
|
||||
return new \DateTime($datetime ?? 'now', new \DateTimeZone('UTC'));
|
||||
}
|
||||
@@ -124,7 +124,7 @@ class RateServiceTest extends TestCase
|
||||
$customerRate,
|
||||
$customerInternal,
|
||||
$customerIsFixed
|
||||
) {
|
||||
): void {
|
||||
$customer = new Customer('foo');
|
||||
|
||||
$project = new Project();
|
||||
@@ -180,7 +180,7 @@ class RateServiceTest extends TestCase
|
||||
self::assertEquals($expectedInternalRate, $rate->getInternalRate());
|
||||
}
|
||||
|
||||
protected function getTestUser($rate = 75, $internalRate = 75)
|
||||
protected function getTestUser(?float $rate = 75.0, ?float $internalRate = 75.0): User
|
||||
{
|
||||
$user = new User();
|
||||
|
||||
@@ -234,7 +234,7 @@ class RateServiceTest extends TestCase
|
||||
self::assertEquals($expectedRate, $rate->getRate());
|
||||
}
|
||||
|
||||
public static function getRuleDefinitions()
|
||||
public static function getRuleDefinitions(): array
|
||||
{
|
||||
$start = self::createDateTime('12:00:00');
|
||||
$day = $start->format('l');
|
||||
@@ -243,7 +243,7 @@ class RateServiceTest extends TestCase
|
||||
[
|
||||
31837,
|
||||
[],
|
||||
663.2708
|
||||
663
|
||||
],
|
||||
[
|
||||
31837,
|
||||
@@ -257,7 +257,7 @@ class RateServiceTest extends TestCase
|
||||
'factor' => 1.5
|
||||
],
|
||||
],
|
||||
1326.5417
|
||||
1326 // 8,84 * 75 (see user) * 2
|
||||
],
|
||||
[
|
||||
31837,
|
||||
@@ -271,7 +271,7 @@ class RateServiceTest extends TestCase
|
||||
'factor' => 1.5
|
||||
],
|
||||
],
|
||||
2321.4479
|
||||
2320.5 // 75 * 8,84 * 3,5
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -18,23 +18,28 @@ use PHPUnit\Framework\TestCase;
|
||||
class UtilTest extends TestCase
|
||||
{
|
||||
#[DataProvider('getRateCalculationData')]
|
||||
public function testCalculateRate(int|float $hourlyRate, int $duration, int|float $expectedRate): void
|
||||
public function testCalculateRate(float $hourlyRate, int $duration, float $expectedRate): void
|
||||
{
|
||||
self::assertEquals($expectedRate, Util::calculateRate($hourlyRate, $duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<float, int, >>|\Generator
|
||||
*/
|
||||
public static function getRateCalculationData()
|
||||
{
|
||||
yield [0, 0, 0];
|
||||
yield [1, 100, 0.0278];
|
||||
yield [1, 900, 0.25];
|
||||
yield [1, 1800, 0.5];
|
||||
yield [10000, 1, 2.7778];
|
||||
yield [736, 123, 25.1467];
|
||||
yield [7360, 1234, 2522.8444];
|
||||
yield [7360.34, 1234, 2522.961];
|
||||
yield [7360.01, 1234, 2522.8479];
|
||||
yield [7360.99, 1234, 2523.1838];
|
||||
yield [0.00, 0, 0.00];
|
||||
yield [10.00, 7260, 20.2];
|
||||
yield [1.00, 3600, 1.00];
|
||||
yield [1.00, 100, 0.03];
|
||||
yield [1.00, 900, 0.25];
|
||||
yield [1.00, 1800, 0.5];
|
||||
yield [10000.00, 60, 200.00];
|
||||
yield [736.00, 123, 22.08];
|
||||
yield [7360.00, 1234, 2502.4];
|
||||
yield [7360.34, 1234, 2502.52];
|
||||
yield [7360.01, 1234, 2502.4];
|
||||
yield [7360.99, 1234, 2502.74];
|
||||
}
|
||||
|
||||
public function testCalculateRateWithRounding(): void
|
||||
@@ -43,29 +48,37 @@ class UtilTest extends TestCase
|
||||
$seconds = 0;
|
||||
$repeat = 130;
|
||||
|
||||
for ($a = 0; $a < $repeat; $a++) {
|
||||
$inputs = [
|
||||
900,
|
||||
1600,
|
||||
4200,
|
||||
8763,
|
||||
3300,
|
||||
600,
|
||||
1300,
|
||||
1837,
|
||||
4217,
|
||||
5400,
|
||||
3283,
|
||||
600,
|
||||
];
|
||||
$inputs = [
|
||||
[900, 28.69, 0],
|
||||
[1600, 50.49, 0],
|
||||
[4200, 134.26, 0],
|
||||
[8763, 278.84, 0],
|
||||
[3300, 105.57, 0],
|
||||
[600, 19.51, 0],
|
||||
[1300, 41.31, 0],
|
||||
[1837, 58.52, 0],
|
||||
[4217, 134.26, 0],
|
||||
[5400, 172.13, 0],
|
||||
[3283, 104.42, 0],
|
||||
[600, 19.51, 0],
|
||||
];
|
||||
|
||||
foreach ($inputs as $i) {
|
||||
$seconds += $i;
|
||||
$total += Util::calculateRate(114.75, $i);
|
||||
$totalExpected = 0.00;
|
||||
|
||||
for ($a = 0; $a < $repeat; $a++) {
|
||||
foreach ($inputs as $row) {
|
||||
[$duration, $rate] = $row;
|
||||
$seconds += $duration;
|
||||
$totalExpected += $rate;
|
||||
$tmp = Util::calculateRate(114.75, $duration);
|
||||
self::assertEquals($rate, $tmp);
|
||||
$total += $tmp;
|
||||
}
|
||||
}
|
||||
|
||||
self::assertEquals(36000 * $repeat, $seconds);
|
||||
self::assertEquals(1147.50 * $repeat, $total);
|
||||
self::assertEquals($totalExpected, $total);
|
||||
self::assertEqualsWithDelta(1147.51 * $repeat, $total, 0.00001);
|
||||
self::assertEqualsWithDelta(149176.3, $total, 0.00001);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,10 @@ class ProfileManagerTest extends TestCase
|
||||
self::assertEquals(ProfileManager::PROFILE_DESKTOP, $sut->getProfileFromSession($session));
|
||||
}
|
||||
|
||||
public static function getInvalidProfiles()
|
||||
/**
|
||||
* @return array<int, array<string>>
|
||||
*/
|
||||
public static function getInvalidProfiles(): array
|
||||
{
|
||||
return [
|
||||
['MOBILE'],
|
||||
@@ -52,7 +55,10 @@ class ProfileManagerTest extends TestCase
|
||||
self::assertFalse($sut->isValidProfile($profile));
|
||||
}
|
||||
|
||||
public static function getDatatableNames()
|
||||
/**
|
||||
* @return array<int, array<string|null>>
|
||||
*/
|
||||
public static function getDatatableNames(): array
|
||||
{
|
||||
return [
|
||||
['admin-timesheet_mobile', 'admin-timesheet', 'mobile'],
|
||||
@@ -73,7 +79,10 @@ class ProfileManagerTest extends TestCase
|
||||
self::assertEquals($expected, $sut->getDatatableName($datatable, $prefix));
|
||||
}
|
||||
|
||||
public static function getProfileNames()
|
||||
/**
|
||||
* @return array<int, array<string>>
|
||||
*/
|
||||
public static function getProfileNames(): array
|
||||
{
|
||||
return [
|
||||
['mobile', ProfileManager::PROFILE_MOBILE],
|
||||
@@ -119,7 +128,10 @@ class ProfileManagerTest extends TestCase
|
||||
self::assertNull($session->get(ProfileManager::SESSION_PROFILE));
|
||||
}
|
||||
|
||||
public static function getCookieProfiles()
|
||||
/**
|
||||
* @return array<int, array<string>>
|
||||
*/
|
||||
public static function getCookieProfiles(): array
|
||||
{
|
||||
return [
|
||||
['mobile', ProfileManager::PROFILE_MOBILE],
|
||||
@@ -146,7 +158,10 @@ class ProfileManagerTest extends TestCase
|
||||
self::assertEquals($expected, $profile);
|
||||
}
|
||||
|
||||
public static function getSessionProfiles()
|
||||
/**
|
||||
* @return array<int, array<string>>
|
||||
*/
|
||||
public static function getSessionProfiles(): array
|
||||
{
|
||||
return [
|
||||
['mobile', ProfileManager::PROFILE_MOBILE],
|
||||
|
||||
@@ -44,6 +44,7 @@ class WorkingTimeModeFactoryTest extends TestCase
|
||||
$sut = new WorkingTimeModeFactory($modes, $logger);
|
||||
|
||||
$user = new User();
|
||||
$user->setUsername('foo-bar');
|
||||
$user->setWorkContractMode('foo');
|
||||
self::assertInstanceOf(WorkingTimeModeNone::class, $sut->getModeForUser($user));
|
||||
}
|
||||
|
||||
@@ -1965,11 +1965,6 @@ parameters:
|
||||
count: 1
|
||||
path: Timesheet/Calculator/DurationCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\Calculator\\\\RateCalculatorTest\\:\\:getRateRepositoryMock\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/Calculator/RateCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\Calculator\\\\RateCalculatorTest\\:\\:getRateRepositoryMock\\(\\) has parameter \\$rates with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -1980,26 +1975,6 @@ parameters:
|
||||
count: 1
|
||||
path: Timesheet/Calculator/RateCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\Calculator\\\\RateCalculatorTest\\:\\:getRuleDefinitions\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/Calculator/RateCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\Calculator\\\\RateCalculatorTest\\:\\:getTestUser\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/Calculator/RateCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\Calculator\\\\RateCalculatorTest\\:\\:getTestUser\\(\\) has parameter \\$internalRate with no type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/Calculator/RateCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\Calculator\\\\RateCalculatorTest\\:\\:getTestUser\\(\\) has parameter \\$rate with no type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/Calculator/RateCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\Calculator\\\\RateCalculatorTest\\:\\:testCalculateWithRulesByUsersHourlyRate\\(\\) has parameter \\$duration with no type specified\\.$#"
|
||||
count: 1
|
||||
@@ -2120,11 +2095,6 @@ parameters:
|
||||
count: 1
|
||||
path: Timesheet/LockdownServiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\RateServiceTest\\:\\:getRateRepositoryMock\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/RateServiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\RateServiceTest\\:\\:getRateRepositoryMock\\(\\) has parameter \\$rates with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -2135,26 +2105,6 @@ parameters:
|
||||
count: 1
|
||||
path: Timesheet/RateServiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\RateServiceTest\\:\\:getRuleDefinitions\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/RateServiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\RateServiceTest\\:\\:getTestUser\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/RateServiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\RateServiceTest\\:\\:getTestUser\\(\\) has parameter \\$internalRate with no type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/RateServiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\RateServiceTest\\:\\:getTestUser\\(\\) has parameter \\$rate with no type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/RateServiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\RateServiceTest\\:\\:testCalculateWithRulesByUsersHourlyRate\\(\\) has parameter \\$duration with no type specified\\.$#"
|
||||
count: 1
|
||||
@@ -2170,11 +2120,6 @@ parameters:
|
||||
count: 1
|
||||
path: Timesheet/RateServiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\RateServiceTest\\:\\:testRates\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/RateServiceTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\RateServiceTest\\:\\:testRates\\(\\) has parameter \\$activityInternal with no type specified\\.$#"
|
||||
count: 1
|
||||
@@ -2435,11 +2380,6 @@ parameters:
|
||||
count: 1
|
||||
path: Timesheet/TrackingMode/DurationFixedBeginModeTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Timesheet\\\\UtilTest\\:\\:getRateCalculationData\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Timesheet/UtilTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access property \\$file on SimpleXMLElement\\|false\\.$#"
|
||||
count: 4
|
||||
@@ -2675,31 +2615,6 @@ parameters:
|
||||
count: 1
|
||||
path: Utils/FormFormatConverterTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Utils\\\\ProfileManagerTest\\:\\:getCookieProfiles\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Utils/ProfileManagerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Utils\\\\ProfileManagerTest\\:\\:getDatatableNames\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Utils/ProfileManagerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Utils\\\\ProfileManagerTest\\:\\:getInvalidProfiles\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Utils/ProfileManagerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Utils\\\\ProfileManagerTest\\:\\:getProfileNames\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Utils/ProfileManagerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Utils\\\\ProfileManagerTest\\:\\:getSessionProfiles\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Utils/ProfileManagerTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Utils\\\\StringHelperTest\\:\\:getDdeAttackStrings\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
|
||||
Reference in New Issue
Block a user