diff --git a/composer.json b/composer.json index 827e8691..e72a250c 100644 --- a/composer.json +++ b/composer.json @@ -76,6 +76,9 @@ "symfony/thanks": "^1.0" }, "config": { + "platform": { + "php": "7.2" + }, "preferred-install": { "*": "dist" }, diff --git a/composer.lock b/composer.lock index 2be03bbe..7db77e9f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "67746acda4894c88c47e3afffab130e4", + "content-hash": "689eb3aa452e83c4ad8a67a1bae462d0", "packages": [ { "name": "beberlei/doctrineextensions", @@ -400,16 +400,16 @@ }, { "name": "doctrine/data-fixtures", - "version": "v1.3.1", + "version": "v1.3.2", "source": { "type": "git", "url": "https://github.com/doctrine/data-fixtures.git", - "reference": "3a1e2c3c600e615a2dffe56d4ca0875cc5233e0a" + "reference": "09b16943b27f3d80d63988d100ff256148c2f78b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/3a1e2c3c600e615a2dffe56d4ca0875cc5233e0a", - "reference": "3a1e2c3c600e615a2dffe56d4ca0875cc5233e0a", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/09b16943b27f3d80d63988d100ff256148c2f78b", + "reference": "09b16943b27f3d80d63988d100ff256148c2f78b", "shasum": "" }, "require": { @@ -456,7 +456,7 @@ "keywords": [ "database" ], - "time": "2018-03-20T09:06:36+00:00" + "time": "2019-07-10T18:30:35+00:00" }, { "name": "doctrine/dbal", @@ -1479,16 +1479,16 @@ }, { "name": "egulias/email-validator", - "version": "2.1.9", + "version": "2.1.10", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "128cc721d771ec2c46ce59698f4ca42b73f71b25" + "reference": "a6c8d7101b19a451c1707b1b79bbbc56e4bdb7ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/128cc721d771ec2c46ce59698f4ca42b73f71b25", - "reference": "128cc721d771ec2c46ce59698f4ca42b73f71b25", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/a6c8d7101b19a451c1707b1b79bbbc56e4bdb7ec", + "reference": "a6c8d7101b19a451c1707b1b79bbbc56e4bdb7ec", "shasum": "" }, "require": { @@ -1498,7 +1498,8 @@ "require-dev": { "dominicsayers/isemail": "dev-master", "phpunit/phpunit": "^4.8.35||^5.7||^6.0", - "satooshi/php-coveralls": "^1.0.1" + "satooshi/php-coveralls": "^1.0.1", + "symfony/phpunit-bridge": "^4.4@dev" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" @@ -1532,7 +1533,7 @@ "validation", "validator" ], - "time": "2019-06-23T10:14:27+00:00" + "time": "2019-07-19T20:52:08+00:00" }, { "name": "erusev/parsedown", @@ -3765,16 +3766,16 @@ }, { "name": "pagerfanta/pagerfanta", - "version": "v2.1.2", + "version": "v2.1.3", "source": { "type": "git", "url": "https://github.com/whiteoctober/Pagerfanta.git", - "reference": "45a85ad426316ae37f2d007022e5b4c95bc3aef4" + "reference": "a53ff01d521648d9dbca19b93ac6bc75a59b0972" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/whiteoctober/Pagerfanta/zipball/45a85ad426316ae37f2d007022e5b4c95bc3aef4", - "reference": "45a85ad426316ae37f2d007022e5b4c95bc3aef4", + "url": "https://api.github.com/repos/whiteoctober/Pagerfanta/zipball/a53ff01d521648d9dbca19b93ac6bc75a59b0972", + "reference": "a53ff01d521648d9dbca19b93ac6bc75a59b0972", "shasum": "" }, "require": { @@ -3830,7 +3831,7 @@ "paginator", "paging" ], - "time": "2019-04-02T08:50:39+00:00" + "time": "2019-07-17T20:56:16+00:00" }, { "name": "paragonie/random_compat", @@ -4127,16 +4128,16 @@ }, { "name": "phpoffice/phpspreadsheet", - "version": "1.8.1", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", - "reference": "352c7002fefe4e4037d02654d853a1b09520946f" + "reference": "0c1346a1956347590b7db09533966307d20cb7cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/352c7002fefe4e4037d02654d853a1b09520946f", - "reference": "352c7002fefe4e4037d02654d853a1b09520946f", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/0c1346a1956347590b7db09533966307d20cb7cc", + "reference": "0c1346a1956347590b7db09533966307d20cb7cc", "shasum": "" }, "require": { @@ -4217,7 +4218,7 @@ "xls", "xlsx" ], - "time": "2019-07-01T20:46:51+00:00" + "time": "2019-07-08T21:21:25+00:00" }, { "name": "phpoffice/phpword", @@ -5634,16 +5635,16 @@ }, { "name": "symfony/flex", - "version": "v1.4.1", + "version": "v1.4.5", "source": { "type": "git", "url": "https://github.com/symfony/flex.git", - "reference": "a388cacccf6e3c5e5a395e020c5aa05849ea4ccc" + "reference": "4467ab35c82edebac58fe58c22cea166a805eb1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/flex/zipball/a388cacccf6e3c5e5a395e020c5aa05849ea4ccc", - "reference": "a388cacccf6e3c5e5a395e020c5aa05849ea4ccc", + "url": "https://api.github.com/repos/symfony/flex/zipball/4467ab35c82edebac58fe58c22cea166a805eb1f", + "reference": "4467ab35c82edebac58fe58c22cea166a805eb1f", "shasum": "" }, "require": { @@ -5679,7 +5680,7 @@ } ], "description": "Composer plugin for Symfony", - "time": "2019-06-28T18:01:09+00:00" + "time": "2019-07-19T08:59:18+00:00" }, { "name": "symfony/form", @@ -6160,16 +6161,16 @@ }, { "name": "symfony/maker-bundle", - "version": "v1.11.6", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "d262c2cace4d9bca99137a84f6fc6ba909a17e02" + "reference": "201d0e050dca336c44f93657ce1f34f3b3868432" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/d262c2cace4d9bca99137a84f6fc6ba909a17e02", - "reference": "d262c2cace4d9bca99137a84f6fc6ba909a17e02", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/201d0e050dca336c44f93657ce1f34f3b3868432", + "reference": "201d0e050dca336c44f93657ce1f34f3b3868432", "shasum": "" }, "require": { @@ -6185,12 +6186,14 @@ "symfony/http-kernel": "^3.4|^4.0" }, "require-dev": { - "allocine/twigcs": "^3.0", "doctrine/doctrine-bundle": "^1.8", "doctrine/orm": "^2.3", "friendsofphp/php-cs-fixer": "^2.8", - "symfony/phpunit-bridge": "^3.4|^4.0", + "friendsoftwig/twigcs": "^3.1.2", + "symfony/http-client": "^4.3", + "symfony/phpunit-bridge": "^3.4.19|^4.0", "symfony/process": "^3.4|^4.0", + "symfony/security-core": "^3.4|^4.0", "symfony/yaml": "^3.4|^4.0" }, "type": "symfony-bundle", @@ -6222,7 +6225,7 @@ "scaffold", "scaffolding" ], - "time": "2019-04-19T17:26:45+00:00" + "time": "2019-07-09T22:19:18+00:00" }, { "name": "symfony/monolog-bridge", @@ -9266,16 +9269,16 @@ }, { "name": "nette/php-generator", - "version": "v3.2.2", + "version": "v3.2.3", "source": { "type": "git", "url": "https://github.com/nette/php-generator.git", - "reference": "acff8b136fad84b860a626d133e791f95781f9f5" + "reference": "aea6e81437bb238e5f0e5b5ce06337433908e63b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/php-generator/zipball/acff8b136fad84b860a626d133e791f95781f9f5", - "reference": "acff8b136fad84b860a626d133e791f95781f9f5", + "url": "https://api.github.com/repos/nette/php-generator/zipball/aea6e81437bb238e5f0e5b5ce06337433908e63b", + "reference": "aea6e81437bb238e5f0e5b5ce06337433908e63b", "shasum": "" }, "require": { @@ -9321,7 +9324,7 @@ "php", "scaffolding" ], - "time": "2019-03-15T03:41:13+00:00" + "time": "2019-07-05T13:01:56+00:00" }, { "name": "nette/robot-loader", @@ -9783,16 +9786,16 @@ }, { "name": "phpstan/phpstan", - "version": "0.11.9", + "version": "0.11.12", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "6771e622ad93f0aff16a100547811e1e50781acb" + "reference": "56b3eb2a371b60537fd20794e24af9e7e8ed4e30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6771e622ad93f0aff16a100547811e1e50781acb", - "reference": "6771e622ad93f0aff16a100547811e1e50781acb", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/56b3eb2a371b60537fd20794e24af9e7e8ed4e30", + "reference": "56b3eb2a371b60537fd20794e24af9e7e8ed4e30", "shasum": "" }, "require": { @@ -9854,7 +9857,7 @@ "MIT" ], "description": "PHPStan - PHP Static Analysis Tool", - "time": "2019-07-03T21:25:16+00:00" + "time": "2019-07-08T06:55:18+00:00" }, { "name": "phpstan/phpstan-doctrine", @@ -10251,16 +10254,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "3.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18" + "reference": "c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c", + "reference": "c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c", "shasum": "" }, "require": { @@ -10296,20 +10299,20 @@ "keywords": [ "tokenizer" ], - "time": "2018-10-30T05:52:18+00:00" + "time": "2019-07-08T05:24:54+00:00" }, { "name": "phpunit/phpunit", - "version": "7.5.13", + "version": "7.5.14", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b9278591caa8630127f96c63b598712b699e671c" + "reference": "2834789aeb9ac182ad69bfdf9ae91856a59945ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b9278591caa8630127f96c63b598712b699e671c", - "reference": "b9278591caa8630127f96c63b598712b699e671c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2834789aeb9ac182ad69bfdf9ae91856a59945ff", + "reference": "2834789aeb9ac182ad69bfdf9ae91856a59945ff", "shasum": "" }, "require": { @@ -10369,8 +10372,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "role": "lead", + "email": "sebastian@phpunit.de" } ], "description": "The PHP Unit Testing framework.", @@ -10380,7 +10383,7 @@ "testing", "xunit" ], - "time": "2019-06-19T12:01:51+00:00" + "time": "2019-07-15T06:24:08+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -11278,5 +11281,8 @@ "ext-pdo": "*", "ext-zip": "*" }, - "platform-dev": [] + "platform-dev": [], + "platform-overrides": { + "php": "7.2" + } } diff --git a/src/Invoice/Calculator/AbstractCalculator.php b/src/Invoice/Calculator/AbstractCalculator.php index e2c2c64a..30705912 100644 --- a/src/Invoice/Calculator/AbstractCalculator.php +++ b/src/Invoice/Calculator/AbstractCalculator.php @@ -69,7 +69,7 @@ abstract class AbstractCalculator public function getTax(): float { $vat = $this->getVat(); - if (0 == $vat) { + if (0 === $vat) { return 0; } diff --git a/src/Invoice/Calculator/AbstractMergedCalculator.php b/src/Invoice/Calculator/AbstractMergedCalculator.php index 5dc86932..0418b5a2 100644 --- a/src/Invoice/Calculator/AbstractMergedCalculator.php +++ b/src/Invoice/Calculator/AbstractMergedCalculator.php @@ -20,9 +20,15 @@ abstract class AbstractMergedCalculator extends AbstractCalculator protected function mergeTimesheets(Timesheet $timesheet, Timesheet $entry) { $timesheet->setUser($entry->getUser()); - $timesheet->setFixedRate($entry->getFixedRate()); // FIXME invoice - $timesheet->setHourlyRate($entry->getHourlyRate()); // FIXME invoice $timesheet->setRate($timesheet->getRate() + $entry->getRate()); + + if (null !== $timesheet->getFixedRate() || null !== $entry->getFixedRate()) { + $timesheet->setFixedRate($timesheet->getRate()); + } + if (null === $timesheet->getHourlyRate() && null !== $entry->getHourlyRate() && $timesheet->getHourlyRate() !== $entry->getHourlyRate()) { + $timesheet->setHourlyRate($entry->getHourlyRate()); + } + $timesheet->setDuration($timesheet->getDuration() + $entry->getDuration()); if (null === $timesheet->getBegin() || $timesheet->getBegin()->getTimestamp() > $entry->getBegin()->getTimestamp()) { diff --git a/src/Invoice/Calculator/AbstractSumInvoiceCalculator.php b/src/Invoice/Calculator/AbstractSumInvoiceCalculator.php new file mode 100644 index 00000000..5dc8f74d --- /dev/null +++ b/src/Invoice/Calculator/AbstractSumInvoiceCalculator.php @@ -0,0 +1,46 @@ +model->getEntries(); + if (empty($entries)) { + return []; + } + + /** @var Timesheet[] $timesheets */ + $timesheets = []; + + foreach ($entries as $entry) { + $id = $this->calculateSumIdentifier($entry); + if (!isset($timesheets[$id])) { + $timesheets[$id] = new Timesheet(); + } + $timesheet = $timesheets[$id]; + $this->mergeTimesheets($timesheet, $entry); + } + + return array_values($timesheets); + } +} diff --git a/src/Invoice/Calculator/ActivityInvoiceCalculator.php b/src/Invoice/Calculator/ActivityInvoiceCalculator.php index 22a23229..e6a9beea 100644 --- a/src/Invoice/Calculator/ActivityInvoiceCalculator.php +++ b/src/Invoice/Calculator/ActivityInvoiceCalculator.php @@ -15,30 +15,15 @@ use App\Invoice\CalculatorInterface; /** * A calculator that sums up the timesheet records by activity. */ -class ActivityInvoiceCalculator extends AbstractMergedCalculator implements CalculatorInterface +class ActivityInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface { - /** - * @return Timesheet[] - */ - public function getEntries() + protected function calculateSumIdentifier(Timesheet $timesheet): string { - $entries = $this->model->getEntries(); - if (empty($entries)) { - return []; + if (null === $timesheet->getActivity()->getId()) { + throw new \Exception('Cannot handle un-persisted activities'); } - /** @var Timesheet[] $timesheets */ - $timesheets = []; - - foreach ($entries as $entry) { - if (!isset($timesheets[$entry->getActivity()->getId()])) { - $timesheets[$entry->getActivity()->getId()] = new Timesheet(); - } - $timesheet = $timesheets[$entry->getActivity()->getId()]; - $this->mergeTimesheets($timesheet, $entry); - } - - return array_values($timesheets); + return (string) $timesheet->getActivity()->getId(); } /** diff --git a/src/Invoice/Calculator/ProjectInvoiceCalculator.php b/src/Invoice/Calculator/ProjectInvoiceCalculator.php new file mode 100644 index 00000000..87fd875a --- /dev/null +++ b/src/Invoice/Calculator/ProjectInvoiceCalculator.php @@ -0,0 +1,36 @@ +getProject()->getId()) { + throw new \Exception('Cannot handle un-persisted projects'); + } + + return (string) $timesheet->getProject()->getId(); + } + + /** + * @return string + */ + public function getId(): string + { + return 'project'; + } +} diff --git a/tests/Invoice/Calculator/AbstractCalculatorTest.php b/tests/Invoice/Calculator/AbstractCalculatorTest.php index 167ed7b1..523244cc 100644 --- a/tests/Invoice/Calculator/AbstractCalculatorTest.php +++ b/tests/Invoice/Calculator/AbstractCalculatorTest.php @@ -50,13 +50,23 @@ abstract class AbstractCalculatorTest extends TestCase $template = new InvoiceTemplate(); $template->setVat(19); - $project = new Project(); - $project->setName('project description'); - $project->setCustomer($customer); + $project = $this->getMockBuilder(Project::class)->setMethods(['getId', 'getCustomer', 'getName'])->disableOriginalConstructor()->getMock(); + $project->method('getId')->willReturn(1); + $project->method('getCustomer')->willReturn($customer); + $project->method('getName')->willReturn('project description'); - $activity = new Activity(); - $activity->setName('activity description'); - $activity->setProject($project); + $project1 = $this->getMockBuilder(Project::class)->setMethods(['getId', 'getName'])->disableOriginalConstructor()->getMock(); + $project1->method('getId')->willReturn(1); + $project1->method('getName')->willReturn('bar'); + + $activity = $this->getMockBuilder(Activity::class)->setMethods(['getId', 'getProject', 'getName'])->disableOriginalConstructor()->getMock(); + $activity->method('getId')->willReturn(1); + $activity->method('getProject')->willReturn($project); + $activity->method('getName')->willReturn('activity description'); + + $activity1 = $this->getMockBuilder(Activity::class)->setMethods(['getId', 'getName'])->disableOriginalConstructor()->getMock(); + $activity1->method('getId')->willReturn(1); + $activity1->method('getName')->willReturn('foo'); $query = new InvoiceQuery(); if ($addProject === true) { @@ -72,8 +82,8 @@ abstract class AbstractCalculatorTest extends TestCase ->setDuration(3600) ->setRate(293.27) ->setUser(new User()) - ->setActivity((new Activity())->setName('foo')) - ->setProject((new Project())->setName('bar')); + ->setActivity($activity1) + ->setProject($project1); $model = new InvoiceModel(); $model->setCustomer($customer); diff --git a/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php index 466a1246..f2c65d3b 100644 --- a/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php @@ -21,6 +21,7 @@ use App\Repository\Query\InvoiceQuery; /** * @covers \App\Invoice\Calculator\ActivityInvoiceCalculator + * @covers \App\Invoice\Calculator\AbstractSumInvoiceCalculator * @covers \App\Invoice\Calculator\AbstractMergedCalculator * @covers \App\Invoice\Calculator\AbstractCalculator */ @@ -46,6 +47,9 @@ class ActivityInvoiceCalculatorTest extends AbstractCalculatorTest $activity2 = $this->getMockBuilder(Activity::class)->setMethods(['getId'])->disableOriginalConstructor()->getMock(); $activity2->method('getId')->willReturn(2); + $activity3 = $this->getMockBuilder(Activity::class)->setMethods(['getId'])->disableOriginalConstructor()->getMock(); + $activity3->method('getId')->willReturn(3); + $timesheet = new Timesheet(); $timesheet ->setBegin(new \DateTime()) @@ -93,7 +97,7 @@ class ActivityInvoiceCalculatorTest extends AbstractCalculatorTest ->setDuration(400) ->setRate(84) ->setUser(new User()) - ->setActivity(new Activity()) + ->setActivity($activity3) ->setProject((new Project())->setName('bar')); $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; diff --git a/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php new file mode 100644 index 00000000..47c1d130 --- /dev/null +++ b/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php @@ -0,0 +1,145 @@ +assertEmptyModel(new ProjectInvoiceCalculator()); + } + + public function testWithMultipleEntries() + { + $customer = new Customer(); + $template = new InvoiceTemplate(); + $template->setVat(19); + + $user = $this->getMockBuilder(User::class)->setMethods(['getId'])->disableOriginalConstructor()->getMock(); + $user->method('getId')->willReturn(1); + + $project1 = $this->getMockBuilder(Project::class)->setMethods(['getId'])->disableOriginalConstructor()->getMock(); + $project1->method('getId')->willReturn(1); + + $project2 = $this->getMockBuilder(Project::class)->setMethods(['getId'])->disableOriginalConstructor()->getMock(); + $project2->method('getId')->willReturn(2); + + $project3 = $this->getMockBuilder(Project::class)->setMethods(['getId'])->disableOriginalConstructor()->getMock(); + $project3->method('getId')->willReturn(3); + + $timesheet = new Timesheet(); + $timesheet + ->setBegin(new \DateTime()) + ->setEnd(new \DateTime()) + ->setDuration(3600) + ->setRate(293.27) + ->setUser($user) + ->setActivity((new Activity())->setName('sdsd')) + ->setProject($project1); + + $timesheet2 = new Timesheet(); + $timesheet2 + ->setBegin(new \DateTime()) + ->setEnd(new \DateTime()) + ->setDuration(400) + ->setRate(84.75) + ->setUser($user) + ->setActivity((new Activity())->setName('bar')) + ->setProject($project2); + + $timesheet3 = new Timesheet(); + $timesheet3 + ->setBegin(new \DateTime()) + ->setEnd(new \DateTime()) + ->setDuration(1800) + ->setRate(111.11) + ->setUser($user) + ->setActivity((new Activity())->setName('foo')) + ->setProject($project1); + + $timesheet4 = new Timesheet(); + $timesheet4 + ->setBegin(new \DateTime()) + ->setEnd(new \DateTime()) + ->setDuration(400) + ->setRate(1947.99) + ->setUser($user) + ->setActivity((new Activity())->setName('blub')) + ->setProject($project2); + + $timesheet5 = new Timesheet(); + $timesheet5 + ->setBegin(new \DateTime()) + ->setEnd(new \DateTime()) + ->setDuration(400) + ->setRate(84) + ->setUser(new User()) + ->setActivity(new Activity()) + ->setProject($project3); + + $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5]; + + $query = new InvoiceQuery(); + $query->setProject($project1); + + $model = new InvoiceModel(); + $model->setCustomer($customer); + $model->setTemplate($template); + $model->setEntries($entries); + $model->setQuery($query); + + $sut = new ProjectInvoiceCalculator(); + $sut->setModel($model); + + $this->assertEquals('project', $sut->getId()); + $this->assertEquals(3000.13, $sut->getTotal()); + $this->assertEquals(19, $sut->getVat()); + $this->assertEquals('EUR', $sut->getCurrency()); + $this->assertEquals(2521.12, $sut->getSubtotal()); + $this->assertEquals(6600, $sut->getTimeWorked()); + $this->assertEquals(3, count($sut->getEntries())); + + $entries = $sut->getEntries(); + $this->assertEquals(404.38, $entries[0]->getRate()); + $this->assertEquals(2032.74, $entries[1]->getRate()); + $this->assertEquals(84, $entries[2]->getRate()); + } + + public function testDescriptionByTimesheet() + { + $this->assertDescription(new ProjectInvoiceCalculator(), false, false); + } + + public function testDescriptionByActivity() + { + $this->assertDescription(new ProjectInvoiceCalculator(), false, true); + } + + public function testDescriptionByProject() + { + $this->assertDescription(new ProjectInvoiceCalculator(), true, false); + } +} diff --git a/translations/invoice-calculator.de.xliff b/translations/invoice-calculator.de.xliff index dba779a0..ae834fc6 100644 --- a/translations/invoice-calculator.de.xliff +++ b/translations/invoice-calculator.de.xliff @@ -8,19 +8,23 @@ default - Eintragsbasiert - ein Eintrag pro Zeitmessung (Standard) + Standard: ein Eintrag pro Zeitmessung short - Stunden aufsummiert - nur ein Eintrag + Stunden: Einträge aufsummiert, nur ein Eintrag user - Benutzer gruppiert - ein Eintrag pro Benutzer + Benutzer: ein Eintrag pro Benutzer activity - Aktivitäten gruppiert - ein Eintrag pro Aktivität + Aktivität: ein Eintrag pro Aktivität + + + project + Projekt: ein Eintrag pro Projekt diff --git a/translations/invoice-calculator.en.xliff b/translations/invoice-calculator.en.xliff index 474bb791..138dbb71 100644 --- a/translations/invoice-calculator.en.xliff +++ b/translations/invoice-calculator.en.xliff @@ -8,19 +8,23 @@ default - Entry-based - one entry per time measurement (default) + Default: one entry per time record short - Hours added up - only one entry + Hours: records summed up, one entry total user - User grouped - one entry per user + User: one entry per user activity - Activity grouped - one entry per activity + Activity: one entry per activity + + + project + Project: one entry per project