Improve UX for invoice template management (#4121)
change translations and to explain that calculator actually group items by fields
This commit is contained in:
25
phpstan.neon
25
phpstan.neon
@@ -4091,31 +4091,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Invoice/Calculator/AbstractMergedCalculator.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getId\\(\\) on App\\\\Entity\\\\Project\\|null\\.$#"
|
||||
count: 2
|
||||
path: src/Invoice/Calculator/ProjectInvoiceCalculator.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getInvoiceText\\(\\) on App\\\\Entity\\\\Project\\|null\\.$#"
|
||||
count: 2
|
||||
path: src/Invoice/Calculator/ProjectInvoiceCalculator.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getName\\(\\) on App\\\\Entity\\\\Project\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Invoice/Calculator/ProjectInvoiceCalculator.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getId\\(\\) on App\\\\Entity\\\\User\\|null\\.$#"
|
||||
count: 2
|
||||
path: src/Invoice/Calculator/UserInvoiceCalculator.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method format\\(\\) on DateTime\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Invoice/Calculator/WeeklyInvoiceCalculator.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method format\\(\\) on DateTime\\|null\\.$#"
|
||||
count: 2
|
||||
|
||||
@@ -36,6 +36,7 @@ final class InvoiceCalculatorType extends AbstractType
|
||||
'choice_label' => function ($renderer) {
|
||||
return $renderer;
|
||||
},
|
||||
'help' => 'invoice_calculator.help',
|
||||
'translation_domain' => 'invoice-calculator',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,29 @@ use App\Invoice\InvoiceItem;
|
||||
*/
|
||||
abstract class AbstractSumInvoiceCalculator extends AbstractMergedCalculator implements CalculatorInterface
|
||||
{
|
||||
abstract protected function calculateSumIdentifier(ExportableItem $invoiceItem): string;
|
||||
protected function calculateSumIdentifier(ExportableItem $invoiceItem): string
|
||||
{
|
||||
$ids = $this->getIdentifiers($invoiceItem);
|
||||
|
||||
$identifier = '';
|
||||
foreach ($ids as $id) {
|
||||
if ($id === null) {
|
||||
$id = '__NULL__';
|
||||
}
|
||||
$identifier .= $id;
|
||||
}
|
||||
|
||||
return $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ExportableItem $invoiceItem
|
||||
* @return array<int|string|null>
|
||||
*/
|
||||
public function getIdentifiers(ExportableItem $invoiceItem): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function calculateIdentifier(ExportableItem $entry): string
|
||||
{
|
||||
|
||||
@@ -18,13 +18,11 @@ use App\Invoice\InvoiceItem;
|
||||
*/
|
||||
final class ActivityInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface
|
||||
{
|
||||
protected function calculateSumIdentifier(ExportableItem $invoiceItem): string
|
||||
public function getIdentifiers(ExportableItem $invoiceItem): array
|
||||
{
|
||||
if (null === $invoiceItem->getActivity()) {
|
||||
return '__NULL__';
|
||||
}
|
||||
|
||||
return (string) $invoiceItem->getActivity()->getId();
|
||||
return [
|
||||
$invoiceItem->getActivity()?->getId()
|
||||
];
|
||||
}
|
||||
|
||||
protected function mergeSumInvoiceItem(InvoiceItem $invoiceItem, ExportableItem $entry): void
|
||||
|
||||
50
src/Invoice/Calculator/ActivityUserInvoiceCalculator.php
Normal file
50
src/Invoice/Calculator/ActivityUserInvoiceCalculator.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?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\ExportableItem;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Invoice\InvoiceItem;
|
||||
|
||||
/**
|
||||
* A calculator that sums up the invoice item records by activity and user.
|
||||
*/
|
||||
final class ActivityUserInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface
|
||||
{
|
||||
public function getIdentifiers(ExportableItem $invoiceItem): array
|
||||
{
|
||||
if ($invoiceItem->getUser()?->getId() === null) {
|
||||
throw new \Exception('Cannot handle un-persisted users');
|
||||
}
|
||||
|
||||
return [
|
||||
$invoiceItem->getActivity()?->getId(),
|
||||
$invoiceItem->getUser()->getId()
|
||||
];
|
||||
}
|
||||
|
||||
protected function mergeSumInvoiceItem(InvoiceItem $invoiceItem, ExportableItem $entry): void
|
||||
{
|
||||
if (null === $entry->getActivity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entry->getActivity()->getInvoiceText() !== null) {
|
||||
$invoiceItem->setDescription($entry->getActivity()->getInvoiceText());
|
||||
} else {
|
||||
$invoiceItem->setDescription($entry->getActivity()->getName());
|
||||
}
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'activity_user';
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,15 @@ use App\Invoice\CalculatorInterface;
|
||||
*/
|
||||
final class DateInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface
|
||||
{
|
||||
protected function calculateSumIdentifier(ExportableItem $invoiceItem): string
|
||||
public function getIdentifiers(ExportableItem $invoiceItem): array
|
||||
{
|
||||
if (null === $invoiceItem->getBegin()) {
|
||||
throw new \Exception('Cannot handle invoice items without start date');
|
||||
}
|
||||
|
||||
return $invoiceItem->getBegin()->format('Y-m-d');
|
||||
return [
|
||||
$invoiceItem->getBegin()->format('Y-m-d')
|
||||
];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
|
||||
40
src/Invoice/Calculator/DateUserInvoiceCalculator.php
Normal file
40
src/Invoice/Calculator/DateUserInvoiceCalculator.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?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\ExportableItem;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
|
||||
/**
|
||||
* A calculator that sums up the invoice item records for each day and user.
|
||||
*/
|
||||
final class DateUserInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface
|
||||
{
|
||||
public function getIdentifiers(ExportableItem $invoiceItem): array
|
||||
{
|
||||
if (null === $invoiceItem->getBegin()) {
|
||||
throw new \Exception('Cannot handle invoice items without start date');
|
||||
}
|
||||
|
||||
if ($invoiceItem->getUser()?->getId() === null) {
|
||||
throw new \Exception('Cannot handle un-persisted users');
|
||||
}
|
||||
|
||||
return [
|
||||
$invoiceItem->getBegin()->format('Y-m-d'),
|
||||
$invoiceItem->getUser()->getId()
|
||||
];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'date_user';
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,13 @@ use App\Invoice\CalculatorInterface;
|
||||
*/
|
||||
final class PriceInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface
|
||||
{
|
||||
protected function calculateSumIdentifier(ExportableItem $invoiceItem): string
|
||||
public function getIdentifiers(ExportableItem $invoiceItem): array
|
||||
{
|
||||
if (null !== $invoiceItem->getFixedRate()) {
|
||||
return 'fixed_' . $invoiceItem->getFixedRate();
|
||||
return ['fixed_' . $invoiceItem->getFixedRate()];
|
||||
}
|
||||
|
||||
return 'hourly_' . $invoiceItem->getHourlyRate();
|
||||
return ['hourly_' . $invoiceItem->getHourlyRate()];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
|
||||
@@ -18,17 +18,27 @@ use App\Invoice\InvoiceItem;
|
||||
*/
|
||||
final class ProjectInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface
|
||||
{
|
||||
protected function calculateSumIdentifier(ExportableItem $invoiceItem): string
|
||||
public function getIdentifiers(ExportableItem $invoiceItem): array
|
||||
{
|
||||
if (null === $invoiceItem->getProject()->getId()) {
|
||||
if ($invoiceItem->getProject() === null) {
|
||||
throw new \Exception('Cannot handle invoice items without project');
|
||||
}
|
||||
|
||||
if ($invoiceItem->getProject()->getId() === null) {
|
||||
throw new \Exception('Cannot handle un-persisted projects');
|
||||
}
|
||||
|
||||
return (string) $invoiceItem->getProject()->getId();
|
||||
return [
|
||||
$invoiceItem->getProject()->getId()
|
||||
];
|
||||
}
|
||||
|
||||
protected function mergeSumInvoiceItem(InvoiceItem $invoiceItem, ExportableItem $entry): void
|
||||
{
|
||||
if ($entry->getProject() === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entry->getProject()->getInvoiceText() !== null) {
|
||||
$invoiceItem->setDescription($entry->getProject()->getInvoiceText());
|
||||
} else {
|
||||
|
||||
62
src/Invoice/Calculator/ProjectUserInvoiceCalculator.php
Normal file
62
src/Invoice/Calculator/ProjectUserInvoiceCalculator.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?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\ExportableItem;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Invoice\InvoiceItem;
|
||||
|
||||
/**
|
||||
* A calculator that sums up the invoice item records by project and user.
|
||||
*/
|
||||
final class ProjectUserInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface
|
||||
{
|
||||
public function getIdentifiers(ExportableItem $invoiceItem): array
|
||||
{
|
||||
if ($invoiceItem->getProject() === null) {
|
||||
throw new \Exception('Cannot handle invoice items without project');
|
||||
}
|
||||
|
||||
if ($invoiceItem->getProject()->getId() === null) {
|
||||
throw new \Exception('Cannot handle un-persisted projects');
|
||||
}
|
||||
|
||||
if ($invoiceItem->getUser() === null) {
|
||||
throw new \Exception('Cannot handle invoice items without user');
|
||||
}
|
||||
|
||||
if ($invoiceItem->getUser()->getId() === null) {
|
||||
throw new \Exception('Cannot handle un-persisted users');
|
||||
}
|
||||
|
||||
return [
|
||||
$invoiceItem->getProject()->getId(),
|
||||
$invoiceItem->getUser()->getId()
|
||||
];
|
||||
}
|
||||
|
||||
protected function mergeSumInvoiceItem(InvoiceItem $invoiceItem, ExportableItem $entry): void
|
||||
{
|
||||
if ($entry->getProject() === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entry->getProject()->getInvoiceText() !== null) {
|
||||
$invoiceItem->setDescription($entry->getProject()->getInvoiceText());
|
||||
} else {
|
||||
$invoiceItem->setDescription($entry->getProject()->getName());
|
||||
}
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'project_user';
|
||||
}
|
||||
}
|
||||
@@ -32,9 +32,9 @@ final class ShortInvoiceCalculator extends AbstractMergedCalculator implements C
|
||||
$keys = [];
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
$key = 'hourly_' . (string) $entry->getHourlyRate();
|
||||
$key = 'hourly_' . $entry->getHourlyRate();
|
||||
if (null !== $entry->getFixedRate()) {
|
||||
$key = 'fixed_' . (string) $entry->getFixedRate();
|
||||
$key = 'fixed_' . $entry->getFixedRate();
|
||||
}
|
||||
if (!\in_array($key, $keys)) {
|
||||
$keys[] = $key;
|
||||
|
||||
@@ -17,13 +17,15 @@ use App\Invoice\CalculatorInterface;
|
||||
*/
|
||||
final class UserInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface
|
||||
{
|
||||
protected function calculateSumIdentifier(ExportableItem $invoiceItem): string
|
||||
public function getIdentifiers(ExportableItem $invoiceItem): array
|
||||
{
|
||||
if (null === $invoiceItem->getUser()->getId()) {
|
||||
if (null === $invoiceItem->getUser()?->getId()) {
|
||||
throw new \Exception('Cannot handle un-persisted user');
|
||||
}
|
||||
|
||||
return (string) $invoiceItem->getUser()->getId();
|
||||
return [
|
||||
$invoiceItem->getUser()->getId()
|
||||
];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
|
||||
@@ -17,9 +17,15 @@ use App\Invoice\CalculatorInterface;
|
||||
*/
|
||||
final class WeeklyInvoiceCalculator extends AbstractSumInvoiceCalculator implements CalculatorInterface
|
||||
{
|
||||
protected function calculateSumIdentifier(ExportableItem $invoiceItem): string
|
||||
public function getIdentifiers(ExportableItem $invoiceItem): array
|
||||
{
|
||||
return $invoiceItem->getBegin()->format('W');
|
||||
if (null === $invoiceItem->getBegin()) {
|
||||
throw new \Exception('Cannot handle invoice items without start date');
|
||||
}
|
||||
|
||||
return [
|
||||
$invoiceItem->getBegin()->format('W')
|
||||
];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
|
||||
@@ -11,55 +11,65 @@
|
||||
{% embed formEditTemplate with formOptions %}
|
||||
{% block form_body %}
|
||||
{{ form_row(form.name) }}
|
||||
{{ form_row(form.title) }}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.company) }}
|
||||
<fieldset class="form-fieldset pb-0">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
{{ form_row(form.title) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.vatId) }}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.company) }}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.vatId) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.address) }}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.address) }}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.contact) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.contact) }}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.paymentTerms) }}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.paymentDetails) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.paymentTerms) }}
|
||||
</fieldset>
|
||||
<fieldset class="form-fieldset pb-0">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.dueDays) }}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.vat) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.paymentDetails) }}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.language) }}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.numberGenerator) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.dueDays) }}
|
||||
</fieldset>
|
||||
<fieldset class="form-fieldset pb-0">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.renderer, {'help_html': true, 'help': '<a href="https://github.com/kimai/invoice-templates" target="_blank">' ~ ('download_invoice_renderer'|trans({}, 'invoice-renderer')) ~ '</a>'}) }}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.calculator) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.vat) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.renderer, {'help_html': true, 'help': '<a href="https://github.com/kimai/invoice-templates" target="_blank">' ~ ('download_invoice_renderer'|trans({}, 'invoice-renderer')) ~ '</a>'}) }}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.language) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.calculator) }}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form_row(form.numberGenerator) }}
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
{{ form_rest(form) }}
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Invoice\InvoiceModel;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
@@ -23,7 +24,18 @@ use PHPUnit\Framework\TestCase;
|
||||
|
||||
abstract class AbstractCalculatorTest extends TestCase
|
||||
{
|
||||
protected function assertEmptyModel(CalculatorInterface $sut)
|
||||
abstract protected function getCalculator(): CalculatorInterface;
|
||||
|
||||
public function testCalculatorInterface(): void
|
||||
{
|
||||
$sut = $this->getCalculator();
|
||||
|
||||
self::assertLessThanOrEqual(20, \strlen($sut->getId()));
|
||||
|
||||
$this->assertEmptyModel($sut);
|
||||
}
|
||||
|
||||
private function assertEmptyModel(CalculatorInterface $sut): void
|
||||
{
|
||||
$model = $this->getEmptyModel();
|
||||
$this->assertEquals('EUR', $model->getCurrency());
|
||||
@@ -38,7 +50,7 @@ abstract class AbstractCalculatorTest extends TestCase
|
||||
$this->assertEquals(0, $sut->getTax());
|
||||
}
|
||||
|
||||
protected function getEmptyModel()
|
||||
private function getEmptyModel(): InvoiceModel
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
@@ -52,7 +64,7 @@ abstract class AbstractCalculatorTest extends TestCase
|
||||
return $model;
|
||||
}
|
||||
|
||||
protected function assertDescription(CalculatorInterface $sut, $addProject = false, $addActivity = false)
|
||||
protected function assertDescription(CalculatorInterface $sut, $addProject = false, $addActivity = false): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Invoice\Calculator\ActivityInvoiceCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
@@ -28,12 +29,12 @@ use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
*/
|
||||
class ActivityInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
public function testEmptyModel()
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
$this->assertEmptyModel(new ActivityInvoiceCalculator());
|
||||
return new ActivityInvoiceCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries()
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
@@ -140,7 +141,7 @@ class ActivityInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = new ActivityInvoiceCalculator();
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('activity', $sut->getId());
|
||||
@@ -149,16 +150,16 @@ class ActivityInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$this->assertEquals('EUR', $model->getCurrency());
|
||||
$this->assertEquals(2521.12, $sut->getSubtotal());
|
||||
$this->assertEquals(6600, $sut->getTimeWorked());
|
||||
$this->assertEquals(5, \count($sut->getEntries()));
|
||||
|
||||
$entries = $sut->getEntries();
|
||||
self::assertCount(4, $entries);
|
||||
$this->assertEquals(404.38, $entries[0]->getRate());
|
||||
$this->assertEquals(2032.74, $entries[1]->getRate());
|
||||
$this->assertEquals(84, $entries[2]->getRate());
|
||||
}
|
||||
|
||||
public function testDescriptionByActivity()
|
||||
public function testDescriptionByActivity(): void
|
||||
{
|
||||
$this->assertDescription(new ActivityInvoiceCalculator(), false, true);
|
||||
$this->assertDescription($this->getCalculator(), false, true);
|
||||
}
|
||||
}
|
||||
|
||||
181
tests/Invoice/Calculator/ActivityUserInvoiceCalculatorTest.php
Normal file
181
tests/Invoice/Calculator/ActivityUserInvoiceCalculatorTest.php
Normal file
@@ -0,0 +1,181 @@
|
||||
<?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\ActivityUserInvoiceCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
|
||||
/**
|
||||
* @covers \App\Invoice\Calculator\ActivityUserInvoiceCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractSumInvoiceCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractMergedCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractCalculator
|
||||
*/
|
||||
class ActivityUserInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
return new ActivityUserInvoiceCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
$template->setVat(19);
|
||||
|
||||
$user1 = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$user1->method('getId')->willReturn(1);
|
||||
|
||||
$user2 = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$user2->method('getId')->willReturn(2);
|
||||
|
||||
$activity1 = $this->getMockBuilder(Activity::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$activity1->method('getId')->willReturn(1);
|
||||
|
||||
$activity2 = $this->getMockBuilder(Activity::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$activity2->method('getId')->willReturn(2);
|
||||
|
||||
$activity3 = $this->getMockBuilder(Activity::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$activity3->method('getId')->willReturn(3);
|
||||
|
||||
$timesheet = new Timesheet();
|
||||
$timesheet
|
||||
->setBegin(new \DateTime())
|
||||
->setEnd(new \DateTime())
|
||||
->setDuration(3600)
|
||||
->setRate(293.27)
|
||||
->setUser($user1)
|
||||
->setActivity($activity1)
|
||||
->setProject((new Project())->setName('bar'));
|
||||
|
||||
$timesheet2 = new Timesheet();
|
||||
$timesheet2
|
||||
->setBegin(new \DateTime())
|
||||
->setEnd(new \DateTime())
|
||||
->setDuration(400)
|
||||
->setRate(84.75)
|
||||
->setUser($user1)
|
||||
->setActivity($activity2)
|
||||
->setProject((new Project())->setName('bar'));
|
||||
|
||||
$timesheet3 = new Timesheet();
|
||||
$timesheet3
|
||||
->setBegin(new \DateTime())
|
||||
->setEnd(new \DateTime())
|
||||
->setDuration(1800)
|
||||
->setRate(111.11)
|
||||
->setUser($user1)
|
||||
->setActivity($activity1)
|
||||
->setProject((new Project())->setName('bar'));
|
||||
|
||||
$timesheet4 = new Timesheet();
|
||||
$timesheet4
|
||||
->setBegin(new \DateTime())
|
||||
->setEnd(new \DateTime())
|
||||
->setDuration(400)
|
||||
->setRate(1947.99)
|
||||
->setUser($user1)
|
||||
->setActivity($activity2)
|
||||
->setProject((new Project())->setName('bar'));
|
||||
|
||||
$timesheet5 = new Timesheet();
|
||||
$timesheet5
|
||||
->setBegin(new \DateTime())
|
||||
->setEnd(new \DateTime())
|
||||
->setDuration(400)
|
||||
->setRate(84)
|
||||
->setUser($user2)
|
||||
->setActivity($activity3)
|
||||
->setProject((new Project())->setName('bar'));
|
||||
|
||||
$timesheet5a = new Timesheet();
|
||||
$timesheet5a
|
||||
->setBegin(new \DateTime())
|
||||
->setEnd(new \DateTime())
|
||||
->setDuration(400)
|
||||
->setRate(84)
|
||||
->setUser($user1)
|
||||
->setActivity($activity3)
|
||||
->setProject((new Project())->setName('bar'));
|
||||
|
||||
$timesheet6 = new Timesheet();
|
||||
$timesheet6
|
||||
->setBegin(new \DateTime())
|
||||
->setEnd(new \DateTime())
|
||||
->setDuration(0)
|
||||
->setRate(0)
|
||||
->setUser($user1)
|
||||
->setProject((new Project())->setName('bar'));
|
||||
|
||||
$timesheet7 = new Timesheet();
|
||||
$timesheet7
|
||||
->setBegin(new \DateTime())
|
||||
->setEnd(new \DateTime())
|
||||
->setDuration(0)
|
||||
->setRate(0)
|
||||
->setUser($user2)
|
||||
->setActivity(new Activity())
|
||||
->setProject((new Project())->setName('bar'));
|
||||
|
||||
$timesheet8 = new Timesheet();
|
||||
$timesheet8
|
||||
->setBegin(new \DateTime())
|
||||
->setEnd(new \DateTime())
|
||||
->setDuration(0)
|
||||
->setRate(0)
|
||||
->setUser($user2)
|
||||
->setProject((new Project())->setName('bar'));
|
||||
|
||||
$entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5, $timesheet5a, $timesheet6, $timesheet7, $timesheet8];
|
||||
|
||||
$query = new InvoiceQuery();
|
||||
$query->addActivity($activity1);
|
||||
|
||||
$model = (new InvoiceModelFactoryFactory($this))->create()->createModel(new DebugFormatter());
|
||||
$model->setCustomer($customer);
|
||||
$model->setTemplate($template);
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('activity_user', $sut->getId());
|
||||
$this->assertEquals(3100.09, $sut->getTotal());
|
||||
$this->assertEquals(19, $sut->getVat());
|
||||
$this->assertEquals('EUR', $model->getCurrency());
|
||||
$this->assertEquals(2605.12, $sut->getSubtotal());
|
||||
$this->assertEquals(7000, $sut->getTimeWorked());
|
||||
|
||||
$entries = $sut->getEntries();
|
||||
self::assertCount(6, $entries);
|
||||
$this->assertEquals(404.38, $entries[0]->getRate());
|
||||
$this->assertEquals(2032.74, $entries[1]->getRate());
|
||||
$this->assertEquals(84.0, $entries[2]->getRate());
|
||||
$this->assertEquals(84.0, $entries[3]->getRate());
|
||||
$this->assertEquals(0, $entries[4]->getRate());
|
||||
$this->assertEquals(0, $entries[5]->getRate());
|
||||
}
|
||||
|
||||
public function testDescriptionByActivity(): void
|
||||
{
|
||||
$this->assertDescription($this->getCalculator(), false, true);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Invoice\Calculator\DateInvoiceCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
@@ -29,12 +30,12 @@ use DateTime;
|
||||
*/
|
||||
class DateInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
public function testEmptyModel()
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
$this->assertEmptyModel(new DateInvoiceCalculator());
|
||||
return new DateInvoiceCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries()
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
@@ -113,7 +114,7 @@ class DateInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = new DateInvoiceCalculator();
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('date', $sut->getId());
|
||||
@@ -122,7 +123,6 @@ class DateInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$this->assertEquals('EUR', $model->getCurrency());
|
||||
$this->assertEquals(2521.12, $sut->getSubtotal());
|
||||
$this->assertEquals(6600, $sut->getTimeWorked());
|
||||
$this->assertEquals(3, \count($sut->getEntries()));
|
||||
|
||||
$entries = $sut->getEntries();
|
||||
self::assertCount(3, $entries);
|
||||
@@ -132,8 +132,8 @@ class DateInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
self::assertEquals(2521.12, $entries[0]->getRate() + $entries[1]->getRate() + $entries[2]->getRate());
|
||||
}
|
||||
|
||||
public function testDescriptionByTimesheet()
|
||||
public function testDescriptionByTimesheet(): void
|
||||
{
|
||||
$this->assertDescription(new DateInvoiceCalculator(), false, false);
|
||||
$this->assertDescription($this->getCalculator(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
143
tests/Invoice/Calculator/DateUserInvoiceCalculatorTest.php
Normal file
143
tests/Invoice/Calculator/DateUserInvoiceCalculatorTest.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?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\DateUserInvoiceCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* @covers \App\Invoice\Calculator\DateUserInvoiceCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractSumInvoiceCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractMergedCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractCalculator
|
||||
*/
|
||||
class DateUserInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
return new DateUserInvoiceCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
$template->setVat(19);
|
||||
|
||||
$user1 = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$user1->method('getId')->willReturn(1);
|
||||
|
||||
$user2 = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$user2->method('getId')->willReturn(2);
|
||||
|
||||
$project1 = $this->getMockBuilder(Project::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$project1->method('getId')->willReturn(1);
|
||||
|
||||
$project2 = $this->getMockBuilder(Project::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$project2->method('getId')->willReturn(2);
|
||||
|
||||
$project3 = $this->getMockBuilder(Project::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$project3->method('getId')->willReturn(3);
|
||||
|
||||
$timesheet = new Timesheet();
|
||||
$timesheet
|
||||
->setBegin(new DateTime('2018-11-29'))
|
||||
->setEnd(new DateTime())
|
||||
->setDuration(3600)
|
||||
->setRate(293.27)
|
||||
->setUser($user1)
|
||||
->setActivity((new Activity())->setName('sdsd'))
|
||||
->setProject($project1);
|
||||
|
||||
$timesheet2 = new Timesheet();
|
||||
$timesheet2
|
||||
->setBegin(new DateTime('2018-11-29'))
|
||||
->setEnd(new DateTime())
|
||||
->setDuration(400)
|
||||
->setRate(84.75)
|
||||
->setUser($user1)
|
||||
->setActivity((new Activity())->setName('bar'))
|
||||
->setProject($project2);
|
||||
|
||||
$timesheet3 = new Timesheet();
|
||||
$timesheet3
|
||||
->setBegin(new DateTime('2018-11-28'))
|
||||
->setEnd(new DateTime())
|
||||
->setDuration(1800)
|
||||
->setRate(111.11)
|
||||
->setUser($user1)
|
||||
->setActivity((new Activity())->setName('foo'))
|
||||
->setProject($project1);
|
||||
|
||||
$timesheet4 = new Timesheet();
|
||||
$timesheet4
|
||||
->setBegin(new DateTime())
|
||||
->setEnd(new DateTime())
|
||||
->setDuration(400)
|
||||
->setRate(1947.99)
|
||||
->setUser($user1)
|
||||
->setActivity((new Activity())->setName('blub'))
|
||||
->setProject($project2);
|
||||
|
||||
$timesheet5 = new Timesheet();
|
||||
$timesheet5
|
||||
->setBegin(new DateTime('2018-11-28'))
|
||||
->setEnd(new DateTime())
|
||||
->setDuration(400)
|
||||
->setRate(84)
|
||||
->setUser($user2)
|
||||
->setActivity(new Activity())
|
||||
->setProject($project3);
|
||||
|
||||
$entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5];
|
||||
|
||||
$query = new InvoiceQuery();
|
||||
$query->setProjects([$project1]);
|
||||
|
||||
$model = (new InvoiceModelFactoryFactory($this))->create()->createModel(new DebugFormatter());
|
||||
$model->setCustomer($customer);
|
||||
$model->setTemplate($template);
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('date_user', $sut->getId());
|
||||
$this->assertEquals(3000.13, $sut->getTotal());
|
||||
$this->assertEquals(19, $sut->getVat());
|
||||
$this->assertEquals('EUR', $model->getCurrency());
|
||||
$this->assertEquals(2521.12, $sut->getSubtotal());
|
||||
$this->assertEquals(6600, $sut->getTimeWorked());
|
||||
|
||||
$entries = $sut->getEntries();
|
||||
self::assertCount(4, $entries);
|
||||
$this->assertEquals(378.02, $entries[0]->getRate());
|
||||
$this->assertEquals(111.11, $entries[1]->getRate());
|
||||
$this->assertEquals(1947.99, $entries[2]->getRate());
|
||||
$this->assertEquals(84, $entries[3]->getRate());
|
||||
self::assertEquals(2521.12, $entries[0]->getRate() + $entries[1]->getRate() + $entries[2]->getRate() + $entries[3]->getRate());
|
||||
}
|
||||
|
||||
public function testDescriptionByTimesheet(): void
|
||||
{
|
||||
$this->assertDescription($this->getCalculator(), false, false);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ use App\Entity\InvoiceTemplate;
|
||||
use App\Entity\Tag;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Invoice\Calculator\DefaultCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
@@ -25,12 +26,12 @@ use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
*/
|
||||
class DefaultCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
public function testEmptyModel()
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
$this->assertEmptyModel(new DefaultCalculator());
|
||||
return new DefaultCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries()
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$date = new \DateTime();
|
||||
$customer = new Customer('foo');
|
||||
@@ -69,7 +70,7 @@ class DefaultCalculatorTest extends AbstractCalculatorTest
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery(new InvoiceQuery());
|
||||
|
||||
$sut = new DefaultCalculator();
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('default', $sut->getId());
|
||||
|
||||
@@ -15,8 +15,8 @@ use App\Entity\InvoiceTemplate;
|
||||
use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Invoice\Calculator\DateInvoiceCalculator;
|
||||
use App\Invoice\Calculator\PriceInvoiceCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
@@ -30,12 +30,12 @@ use DateTime;
|
||||
*/
|
||||
class PriceInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
public function testEmptyModel()
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
$this->assertEmptyModel(new DateInvoiceCalculator());
|
||||
return new PriceInvoiceCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries()
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
@@ -118,7 +118,7 @@ class PriceInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = new PriceInvoiceCalculator();
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('price', $sut->getId());
|
||||
@@ -136,8 +136,8 @@ class PriceInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$this->assertEquals(84, $entries[3]->getRate());
|
||||
}
|
||||
|
||||
public function testDescriptionByTimesheet()
|
||||
public function testDescriptionByTimesheet(): void
|
||||
{
|
||||
$this->assertDescription(new PriceInvoiceCalculator(), false, false);
|
||||
$this->assertDescription($this->getCalculator(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Invoice\Calculator\ProjectInvoiceCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
@@ -29,12 +30,12 @@ use DateTime;
|
||||
*/
|
||||
class ProjectInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
public function testEmptyModel()
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
$this->assertEmptyModel(new ProjectInvoiceCalculator());
|
||||
return new ProjectInvoiceCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries()
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
@@ -113,7 +114,7 @@ class ProjectInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = new ProjectInvoiceCalculator();
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('project', $sut->getId());
|
||||
@@ -122,7 +123,6 @@ class ProjectInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$this->assertEquals('EUR', $model->getCurrency());
|
||||
$this->assertEquals(2521.12, $sut->getSubtotal());
|
||||
$this->assertEquals(6600, $sut->getTimeWorked());
|
||||
$this->assertEquals(3, \count($sut->getEntries()));
|
||||
|
||||
$entries = $sut->getEntries();
|
||||
self::assertCount(3, $entries);
|
||||
@@ -132,8 +132,8 @@ class ProjectInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
self::assertEquals(2521.12, $entries[0]->getRate() + $entries[1]->getRate() + $entries[2]->getRate());
|
||||
}
|
||||
|
||||
public function testDescriptionByProject()
|
||||
public function testDescriptionByProject(): void
|
||||
{
|
||||
$this->assertDescription(new ProjectInvoiceCalculator(), true, false);
|
||||
$this->assertDescription($this->getCalculator(), true, false);
|
||||
}
|
||||
}
|
||||
|
||||
142
tests/Invoice/Calculator/ProjectUserInvoiceCalculatorTest.php
Normal file
142
tests/Invoice/Calculator/ProjectUserInvoiceCalculatorTest.php
Normal file
@@ -0,0 +1,142 @@
|
||||
<?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\ProjectUserInvoiceCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* @covers \App\Invoice\Calculator\ProjectUserInvoiceCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractSumInvoiceCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractMergedCalculator
|
||||
* @covers \App\Invoice\Calculator\AbstractCalculator
|
||||
*/
|
||||
class ProjectUserInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
return new ProjectUserInvoiceCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
$template->setVat(19);
|
||||
|
||||
$user1 = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$user1->method('getId')->willReturn(1);
|
||||
|
||||
$user2 = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$user2->method('getId')->willReturn(2);
|
||||
|
||||
$project1 = $this->getMockBuilder(Project::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$project1->method('getId')->willReturn(1);
|
||||
|
||||
$project2 = $this->getMockBuilder(Project::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$project2->method('getId')->willReturn(2);
|
||||
|
||||
$project3 = $this->getMockBuilder(Project::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock();
|
||||
$project3->method('getId')->willReturn(3);
|
||||
|
||||
$timesheet = new Timesheet();
|
||||
$timesheet
|
||||
->setBegin(new DateTime())
|
||||
->setEnd(new DateTime())
|
||||
->setDuration(3600)
|
||||
->setRate(293.27)
|
||||
->setUser($user1)
|
||||
->setActivity((new Activity())->setName('sdsd'))
|
||||
->setProject($project1);
|
||||
|
||||
$timesheet2 = new Timesheet();
|
||||
$timesheet2
|
||||
->setBegin(new DateTime())
|
||||
->setEnd(new DateTime())
|
||||
->setDuration(400)
|
||||
->setRate(84.75)
|
||||
->setUser($user1)
|
||||
->setActivity((new Activity())->setName('bar'))
|
||||
->setProject($project2);
|
||||
|
||||
$timesheet3 = new Timesheet();
|
||||
$timesheet3
|
||||
->setBegin(new DateTime())
|
||||
->setEnd(new DateTime())
|
||||
->setDuration(1800)
|
||||
->setRate(111.11)
|
||||
->setUser($user1)
|
||||
->setActivity((new Activity())->setName('foo'))
|
||||
->setProject($project1);
|
||||
|
||||
$timesheet4 = new Timesheet();
|
||||
$timesheet4
|
||||
->setBegin(new DateTime())
|
||||
->setEnd(new DateTime())
|
||||
->setDuration(400)
|
||||
->setRate(1947.99)
|
||||
->setUser($user1)
|
||||
->setActivity((new Activity())->setName('blub'))
|
||||
->setProject($project2);
|
||||
|
||||
$timesheet5 = new Timesheet();
|
||||
$timesheet5
|
||||
->setBegin(new DateTime())
|
||||
->setEnd(new DateTime())
|
||||
->setDuration(400)
|
||||
->setRate(84)
|
||||
->setUser($user2)
|
||||
->setActivity(new Activity())
|
||||
->setProject($project3);
|
||||
|
||||
$entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5];
|
||||
|
||||
$query = new InvoiceQuery();
|
||||
$query->setProjects([$project1]);
|
||||
|
||||
$model = (new InvoiceModelFactoryFactory($this))->create()->createModel(new DebugFormatter());
|
||||
$model->setCustomer($customer);
|
||||
$model->setTemplate($template);
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('project_user', $sut->getId());
|
||||
$this->assertEquals(3000.13, $sut->getTotal());
|
||||
$this->assertEquals(19, $sut->getVat());
|
||||
$this->assertEquals('EUR', $model->getCurrency());
|
||||
$this->assertEquals(2521.12, $sut->getSubtotal());
|
||||
$this->assertEquals(6600, $sut->getTimeWorked());
|
||||
|
||||
$entries = $sut->getEntries();
|
||||
self::assertCount(3, $entries);
|
||||
$this->assertEquals(404.38, $entries[0]->getRate());
|
||||
$this->assertEquals(2032.74, $entries[1]->getRate());
|
||||
$this->assertEquals(84, $entries[2]->getRate());
|
||||
self::assertEquals(2521.12, $entries[0]->getRate() + $entries[1]->getRate() + $entries[2]->getRate());
|
||||
}
|
||||
|
||||
public function testDescriptionByProject(): void
|
||||
{
|
||||
$this->assertDescription($this->getCalculator(), true, false);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ use App\Entity\Tag;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Invoice\Calculator\ShortInvoiceCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Invoice\InvoiceItem;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
@@ -29,12 +30,12 @@ use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
*/
|
||||
class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
public function testEmptyModel()
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
$this->assertEmptyModel(new ShortInvoiceCalculator());
|
||||
return new ShortInvoiceCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries()
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
@@ -97,7 +98,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = new ShortInvoiceCalculator();
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('short', $sut->getId());
|
||||
@@ -119,7 +120,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$this->assertEquals(['foo', 'bar', 'bar1'], $result->getTags());
|
||||
}
|
||||
|
||||
public function testWithMultipleEntriesDifferentRates()
|
||||
public function testWithMultipleEntriesDifferentRates(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
@@ -179,7 +180,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = new ShortInvoiceCalculator();
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('short', $sut->getId());
|
||||
@@ -200,7 +201,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$this->assertEquals(1, $result->getAmount());
|
||||
}
|
||||
|
||||
public function testWithMixedRateTypes()
|
||||
public function testWithMixedRateTypes(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
@@ -258,7 +259,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = new ShortInvoiceCalculator();
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('short', $sut->getId());
|
||||
@@ -279,8 +280,8 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$this->assertEquals(1, $result->getAmount());
|
||||
}
|
||||
|
||||
public function testDescriptionByTimesheet()
|
||||
public function testDescriptionByTimesheet(): void
|
||||
{
|
||||
$this->assertDescription(new ShortInvoiceCalculator(), false, false);
|
||||
$this->assertDescription($this->getCalculator(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Invoice\Calculator\UserInvoiceCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
@@ -27,12 +28,12 @@ use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
*/
|
||||
class UserInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
public function testEmptyModel()
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
$this->assertEmptyModel(new UserInvoiceCalculator());
|
||||
return new UserInvoiceCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries()
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
@@ -111,7 +112,7 @@ class UserInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = new UserInvoiceCalculator();
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('user', $sut->getId());
|
||||
@@ -120,16 +121,16 @@ class UserInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$this->assertEquals('EUR', $model->getCurrency());
|
||||
$this->assertEquals(2521.12, $sut->getSubtotal());
|
||||
$this->assertEquals(6600, $sut->getTimeWorked());
|
||||
$this->assertEquals(3, \count($sut->getEntries()));
|
||||
|
||||
$entries = $sut->getEntries();
|
||||
self::assertCount(3, $entries);
|
||||
$this->assertEquals(404.38, $entries[0]->getRate());
|
||||
$this->assertEquals(2032.74, $entries[1]->getRate());
|
||||
$this->assertEquals(84, $entries[2]->getRate());
|
||||
}
|
||||
|
||||
public function testDescriptionByTimesheet()
|
||||
public function testDescriptionByTimesheet(): void
|
||||
{
|
||||
$this->assertDescription(new UserInvoiceCalculator(), false, false);
|
||||
$this->assertDescription($this->getCalculator(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Invoice\Calculator\WeeklyInvoiceCalculator;
|
||||
use App\Invoice\CalculatorInterface;
|
||||
use App\Repository\Query\InvoiceQuery;
|
||||
use App\Tests\Invoice\DebugFormatter;
|
||||
use App\Tests\Mocks\InvoiceModelFactoryFactory;
|
||||
@@ -29,12 +30,12 @@ use DateTime;
|
||||
*/
|
||||
class WeeklyInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
{
|
||||
public function testEmptyModel()
|
||||
protected function getCalculator(): CalculatorInterface
|
||||
{
|
||||
$this->assertEmptyModel(new WeeklyInvoiceCalculator());
|
||||
return new WeeklyInvoiceCalculator();
|
||||
}
|
||||
|
||||
public function testWithMultipleEntries()
|
||||
public function testWithMultipleEntries(): void
|
||||
{
|
||||
$customer = new Customer('foo');
|
||||
$template = new InvoiceTemplate();
|
||||
@@ -116,7 +117,7 @@ class WeeklyInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
$model->addEntries($entries);
|
||||
$model->setQuery($query);
|
||||
|
||||
$sut = new WeeklyInvoiceCalculator();
|
||||
$sut = $this->getCalculator();
|
||||
$sut->setModel($model);
|
||||
|
||||
$this->assertEquals('weekly', $sut->getId());
|
||||
@@ -133,8 +134,8 @@ class WeeklyInvoiceCalculatorTest extends AbstractCalculatorTest
|
||||
self::assertEquals(2521.12, $entries[0]->getRate() + $entries[1]->getRate());
|
||||
}
|
||||
|
||||
public function testDescriptionByTimesheet()
|
||||
public function testDescriptionByTimesheet(): void
|
||||
{
|
||||
$this->assertDescription(new WeeklyInvoiceCalculator(), false, false);
|
||||
$this->assertDescription($this->getCalculator(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6547,11 +6547,6 @@ parameters:
|
||||
count: 1
|
||||
path: Form/Type/TypeTestModel.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\AbstractCalculatorTest\\:\\:assertDescription\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/AbstractCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\AbstractCalculatorTest\\:\\:assertDescription\\(\\) has parameter \\$addActivity with no type specified\\.$#"
|
||||
count: 1
|
||||
@@ -6562,141 +6557,6 @@ parameters:
|
||||
count: 1
|
||||
path: Invoice/Calculator/AbstractCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\AbstractCalculatorTest\\:\\:assertEmptyModel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/AbstractCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\AbstractCalculatorTest\\:\\:getEmptyModel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/AbstractCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ActivityInvoiceCalculatorTest\\:\\:testDescriptionByActivity\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ActivityInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ActivityInvoiceCalculatorTest\\:\\:testEmptyModel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ActivityInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ActivityInvoiceCalculatorTest\\:\\:testWithMultipleEntries\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ActivityInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\DateInvoiceCalculatorTest\\:\\:testDescriptionByTimesheet\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/DateInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\DateInvoiceCalculatorTest\\:\\:testEmptyModel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/DateInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\DateInvoiceCalculatorTest\\:\\:testWithMultipleEntries\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/DateInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\DefaultCalculatorTest\\:\\:testEmptyModel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/DefaultCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\DefaultCalculatorTest\\:\\:testWithMultipleEntries\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/DefaultCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\PriceInvoiceCalculatorTest\\:\\:testDescriptionByTimesheet\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/PriceInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\PriceInvoiceCalculatorTest\\:\\:testEmptyModel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/PriceInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\PriceInvoiceCalculatorTest\\:\\:testWithMultipleEntries\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/PriceInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ProjectInvoiceCalculatorTest\\:\\:testDescriptionByProject\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ProjectInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ProjectInvoiceCalculatorTest\\:\\:testEmptyModel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ProjectInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ProjectInvoiceCalculatorTest\\:\\:testWithMultipleEntries\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ProjectInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ShortInvoiceCalculatorTest\\:\\:testDescriptionByTimesheet\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ShortInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ShortInvoiceCalculatorTest\\:\\:testEmptyModel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ShortInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ShortInvoiceCalculatorTest\\:\\:testWithMixedRateTypes\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ShortInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ShortInvoiceCalculatorTest\\:\\:testWithMultipleEntries\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ShortInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\ShortInvoiceCalculatorTest\\:\\:testWithMultipleEntriesDifferentRates\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/ShortInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\UserInvoiceCalculatorTest\\:\\:testDescriptionByTimesheet\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/UserInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\UserInvoiceCalculatorTest\\:\\:testEmptyModel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/UserInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\UserInvoiceCalculatorTest\\:\\:testWithMultipleEntries\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/UserInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\WeeklyInvoiceCalculatorTest\\:\\:testDescriptionByTimesheet\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/WeeklyInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\WeeklyInvoiceCalculatorTest\\:\\:testEmptyModel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/WeeklyInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\WeeklyInvoiceCalculatorTest\\:\\:testWithMultipleEntries\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Invoice/Calculator/WeeklyInvoiceCalculatorTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getEntries\\(\\) on App\\\\Invoice\\\\CalculatorInterface\\|null\\.$#"
|
||||
count: 2
|
||||
|
||||
@@ -4,39 +4,55 @@
|
||||
<body>
|
||||
<trans-unit id="MviRJeB" resname="invoice_calculator">
|
||||
<source>invoice_calculator</source>
|
||||
<target>Summen Berechnung</target>
|
||||
<target>Gruppierung der Rechnungszeilen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="KWX.j1b" resname="invoice_calculator.help">
|
||||
<source>invoice_calculator.help</source>
|
||||
<target>Anhand welcher Felder sollen Rechnungsposten gruppiert werden?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="N6juwc4" resname="default">
|
||||
<source>default</source>
|
||||
<target>Standard: ein Eintrag pro Zeitmessung</target>
|
||||
<target>Standard (eine Zeile pro Eintrag)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="_bAHi13" resname="short">
|
||||
<source>short</source>
|
||||
<target>Stunden: Einträge aufsummiert, nur ein Eintrag</target>
|
||||
<target>Alle (ein Eintrag insgesamt)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="BPiZbad" resname="user">
|
||||
<source>user</source>
|
||||
<target>Benutzer: ein Eintrag pro Benutzer</target>
|
||||
<target>Benutzer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="BlGGO.X" resname="activity">
|
||||
<source>activity</source>
|
||||
<target>Aktivität: ein Eintrag pro Aktivität</target>
|
||||
<target>Aktivität</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="oRa0mkz" resname="activity_user">
|
||||
<source>activity_user</source>
|
||||
<target>Aktivität und Benutzer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="JEIQ5IQ" resname="project">
|
||||
<source>project</source>
|
||||
<target>Projekt: ein Eintrag pro Projekt</target>
|
||||
<target>Projekt</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="AJm1952" resname="project_user">
|
||||
<source>project_user</source>
|
||||
<target>Projekt und Benutzer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="DodjLNR" resname="date">
|
||||
<source>date</source>
|
||||
<target>Datum: ein Eintrag pro Tag (verwendet Startdatum)</target>
|
||||
<target>Datum</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="0l1P9cz" resname="date_user">
|
||||
<source>date_user</source>
|
||||
<target>Datum und Benutzer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="iFDs7Zh" resname="weekly">
|
||||
<source>weekly</source>
|
||||
<target>Wöchentlich: ein Eintrag pro Woche (verwendet Startdatum)</target>
|
||||
<target>Kalenderwoche</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="aDtTH0H" resname="price">
|
||||
<source>price</source>
|
||||
<target>Preis: ein Eintrag je Preis</target>
|
||||
<target>Preis</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
||||
@@ -1,42 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file source-language="en" target-language="de-CH" datatype="plaintext" original="invoice-calculator.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="MviRJeB" resname="invoice_calculator">
|
||||
<source>invoice_calculator</source>
|
||||
<target state="translated">Summenberechnung</target>
|
||||
<target>Gruppierung der Rechnungszeilen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="aDtTH0H" resname="price">
|
||||
<source>price</source>
|
||||
<target state="translated">Preis: ein Eintrag pro Preis</target>
|
||||
<trans-unit id="KWX.j1b" resname="invoice_calculator.help">
|
||||
<source>invoice_calculator.help</source>
|
||||
<target>Anhand welcher Felder sollen Rechnungsposten gruppiert werden?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="N6juwc4" resname="default">
|
||||
<source>default</source>
|
||||
<target state="translated">Standard: ein Eintrag pro Zeiterfassung</target>
|
||||
<target>Standard (eine Zeile pro Eintrag)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="_bAHi13" resname="short">
|
||||
<source>short</source>
|
||||
<target state="translated">Stunden: Aufzeichnungen summiert, ein Eintrag insgesamt</target>
|
||||
<target>Alle (ein Eintrag insgesamt)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="BPiZbad" resname="user">
|
||||
<source>user</source>
|
||||
<target state="translated">Benutzer: ein Eintrag pro Benutzer</target>
|
||||
<target>Benutzer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="BlGGO.X" resname="activity">
|
||||
<source>activity</source>
|
||||
<target state="translated">Aktivität: ein Eintrag pro Aktivität</target>
|
||||
<target>Aktivität</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="oRa0mkz" resname="activity_user">
|
||||
<source>activity_user</source>
|
||||
<target>Aktivität und Benutzer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="JEIQ5IQ" resname="project">
|
||||
<source>project</source>
|
||||
<target state="translated">Projekt: ein Eintrag pro Projekt</target>
|
||||
<target>Projekt</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="AJm1952" resname="project_user">
|
||||
<source>project_user</source>
|
||||
<target>Projekt und Benutzer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="DodjLNR" resname="date">
|
||||
<source>date</source>
|
||||
<target state="translated">Datum: ein Eintrag pro Tag (verwendet Startdatum)</target>
|
||||
<target>Datum</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="0l1P9cz" resname="date_user">
|
||||
<source>date_user</source>
|
||||
<target>Datum und Benutzer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="iFDs7Zh" resname="weekly">
|
||||
<source>weekly</source>
|
||||
<target state="translated">Wöchentlich: ein Eintrag pro Woche (verwendet Startdatum)</target>
|
||||
<target>Kalenderwoche</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="aDtTH0H" resname="price">
|
||||
<source>price</source>
|
||||
<target>Preis</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
||||
@@ -4,39 +4,55 @@
|
||||
<body>
|
||||
<trans-unit id="MviRJeB" resname="invoice_calculator">
|
||||
<source>invoice_calculator</source>
|
||||
<target>Sum calculation</target>
|
||||
<target>Grouping of invoice lines</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="KWX.j1b" resname="invoice_calculator.help">
|
||||
<source>invoice_calculator.help</source>
|
||||
<target>Select by which fields the invoice items should be grouped</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="N6juwc4" resname="default">
|
||||
<source>default</source>
|
||||
<target>Default: one entry per time record</target>
|
||||
<target>Default (one row per entry)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="_bAHi13" resname="short">
|
||||
<source>short</source>
|
||||
<target>Hours: records summed up, one entry total</target>
|
||||
<target>All (one entry total)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="BPiZbad" resname="user">
|
||||
<source>user</source>
|
||||
<target>User: one entry per user</target>
|
||||
<target>User</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="BlGGO.X" resname="activity">
|
||||
<source>activity</source>
|
||||
<target>Activity: one entry per activity</target>
|
||||
<target>Activity</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="oRa0mkz" resname="activity_user">
|
||||
<source>activity_user</source>
|
||||
<target>Activity and user</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="JEIQ5IQ" resname="project">
|
||||
<source>project</source>
|
||||
<target>Project: one entry per project</target>
|
||||
<target>Project</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="AJm1952" resname="project_user">
|
||||
<source>project_user</source>
|
||||
<target>Project and user</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="DodjLNR" resname="date">
|
||||
<source>date</source>
|
||||
<target>Date: one entry per day (uses start date)</target>
|
||||
<target>Date</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="0l1P9cz" resname="date_user">
|
||||
<source>date_user</source>
|
||||
<target>Date and user</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="iFDs7Zh" resname="weekly">
|
||||
<source>weekly</source>
|
||||
<target>Weekly: one entry per week (uses start date)</target>
|
||||
<target>Calendar week</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="aDtTH0H" resname="price">
|
||||
<source>price</source>
|
||||
<target>Price: one entry per price</target>
|
||||
<target>Price</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<body>
|
||||
<trans-unit id="hOcTt2G" resname="invoice_renderer">
|
||||
<source>invoice_renderer</source>
|
||||
<target>Rechnungsdokument</target>
|
||||
<target>Rechnungsvorlage</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="7mEUv6C" resname="help.upload">
|
||||
<source>help.upload</source>
|
||||
@@ -14,12 +14,10 @@
|
||||
<source>download_invoice_renderer</source>
|
||||
<target state="translated">Sie können weitere Vorlagen hier herunterladen</target>
|
||||
</trans-unit>
|
||||
<!-- Optgroups -->
|
||||
<trans-unit id="E5BwZHT" resname="programmatic">
|
||||
<source>programmatic</source>
|
||||
<target>Zur Weiterverarbeitung</target>
|
||||
</trans-unit>
|
||||
<!-- Renderer -->
|
||||
<trans-unit id="Utbj3k_" resname="invoice">
|
||||
<source>invoice</source>
|
||||
<target>Rechnung</target>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<body>
|
||||
<trans-unit id="hOcTt2G" resname="invoice_renderer">
|
||||
<source>invoice_renderer</source>
|
||||
<target state="translated">Rechnungsdokument</target>
|
||||
<target state="translated">Rechnungsvorlage</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Utbj3k_" resname="invoice">
|
||||
<source>invoice</source>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<body>
|
||||
<trans-unit id="hOcTt2G" resname="invoice_renderer">
|
||||
<source>invoice_renderer</source>
|
||||
<target>Invoice document</target>
|
||||
<target>Invoice template</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="7mEUv6C" resname="help.upload">
|
||||
<source>help.upload</source>
|
||||
@@ -14,12 +14,10 @@
|
||||
<source>download_invoice_renderer</source>
|
||||
<target state="translated">You can download further templates here</target>
|
||||
</trans-unit>
|
||||
<!-- Optgroups -->
|
||||
<trans-unit id="E5BwZHT" resname="programmatic">
|
||||
<source>programmatic</source>
|
||||
<target>For further processing</target>
|
||||
</trans-unit>
|
||||
<!-- Renderer -->
|
||||
<trans-unit id="Utbj3k_" resname="invoice">
|
||||
<source>invoice</source>
|
||||
<target>Invoice</target>
|
||||
|
||||
Reference in New Issue
Block a user