project grouped invoice calculator (#892)
This commit is contained in:
@@ -76,6 +76,9 @@
|
||||
"symfony/thanks": "^1.0"
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.2"
|
||||
},
|
||||
"preferred-install": {
|
||||
"*": "dist"
|
||||
},
|
||||
|
||||
120
composer.lock
generated
120
composer.lock
generated
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ abstract class AbstractCalculator
|
||||
public function getTax(): float
|
||||
{
|
||||
$vat = $this->getVat();
|
||||
if (0 == $vat) {
|
||||
if (0 === $vat) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
46
src/Invoice/Calculator/AbstractSumInvoiceCalculator.php
Normal file
46
src/Invoice/Calculator/AbstractSumInvoiceCalculator.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?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\Invoice\Calculator;
|
||||
|
||||
use App\Entity\Timesheet;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
|
||||
/**
|
||||
* A calculator that sums up the timesheet records by activity.
|
||||
*/
|
||||
abstract class AbstractSumInvoiceCalculator extends AbstractMergedCalculator implements CalculatorInterface
|
||||
{
|
||||
abstract protected function calculateSumIdentifier(Timesheet $timesheet): string;
|
||||
|
||||
/**
|
||||
* @return Timesheet[]
|
||||
*/
|
||||
public function getEntries()
|
||||
{
|
||||
$entries = $this->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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
36
src/Invoice/Calculator/ProjectInvoiceCalculator.php
Normal file
36
src/Invoice/Calculator/ProjectInvoiceCalculator.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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\Invoice\Calculator;
|
||||
|
||||
use App\Entity\Timesheet;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
|
||||
/**
|
||||
* A calculator that sums up the timesheet records by project.
|
||||
*/
|
||||
class ProjectInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface
|
||||
{
|
||||
protected function calculateSumIdentifier(Timesheet $timesheet): string
|
||||
{
|
||||
if (null === $timesheet->getProject()->getId()) {
|
||||
throw new \Exception('Cannot handle un-persisted projects');
|
||||
}
|
||||
|
||||
return (string) $timesheet->getProject()->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId(): string
|
||||
{
|
||||
return 'project';
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
145
tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php
Normal file
145
tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?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\Invoice\Calculator;
|
||||
|
||||
use App\Entity\Activity;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\InvoiceTemplate;
|
||||
use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Invoice\Calculator\ProjectInvoiceCalculator;
|
||||
use App\Model\InvoiceModel;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
|
||||
/**
|
||||
* @covers \App\Invoice\Calculator\ProjectInvoiceCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractSumInvoiceCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractMergedCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractCalculator
|
||||
*/
|
||||
class ProjectInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
public function testEmptyModel()
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
@@ -8,19 +8,23 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="default">
|
||||
<source>default</source>
|
||||
<target>Eintragsbasiert - ein Eintrag pro Zeitmessung (Standard)</target>
|
||||
<target>Standard: ein Eintrag pro Zeitmessung</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="short">
|
||||
<source>short</source>
|
||||
<target>Stunden aufsummiert - nur ein Eintrag</target>
|
||||
<target>Stunden: Einträge aufsummiert, nur ein Eintrag</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="user">
|
||||
<source>user</source>
|
||||
<target>Benutzer gruppiert - ein Eintrag pro Benutzer</target>
|
||||
<target>Benutzer: ein Eintrag pro Benutzer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="activity">
|
||||
<source>activity</source>
|
||||
<target>Aktivitäten gruppiert - ein Eintrag pro Aktivität</target>
|
||||
<target>Aktivität: ein Eintrag pro Aktivität</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="project">
|
||||
<source>project</source>
|
||||
<target>Projekt: ein Eintrag pro Projekt</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
||||
@@ -8,19 +8,23 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="default">
|
||||
<source>default</source>
|
||||
<target>Entry-based - one entry per time measurement (default)</target>
|
||||
<target>Default: one entry per time record</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="short">
|
||||
<source>short</source>
|
||||
<target>Hours added up - only one entry</target>
|
||||
<target>Hours: records summed up, one entry total</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="user">
|
||||
<source>user</source>
|
||||
<target>User grouped - one entry per user</target>
|
||||
<target>User: one entry per user</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="activity">
|
||||
<source>activity</source>
|
||||
<target>Activity grouped - one entry per activity</target>
|
||||
<target>Activity: one entry per activity</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="project">
|
||||
<source>project</source>
|
||||
<target>Project: one entry per project</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
||||
Reference in New Issue
Block a user