support tags in invoices (#2526)
This commit is contained in:
@@ -114,5 +114,11 @@ abstract class AbstractMergedCalculator extends AbstractCalculator
|
|||||||
if (empty($invoiceItem->getDescription()) && null !== $entry->getActivity()) {
|
if (empty($invoiceItem->getDescription()) && null !== $entry->getActivity()) {
|
||||||
$invoiceItem->setDescription($entry->getActivity()->getName());
|
$invoiceItem->setDescription($entry->getActivity()->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($entry instanceof Timesheet) {
|
||||||
|
foreach ($entry->getTagsAsArray() as $tag) {
|
||||||
|
$invoiceItem->addTag($tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class InvoiceItemDefaultHydrator implements InvoiceItemHydrator
|
|||||||
'entry.description' => $description,
|
'entry.description' => $description,
|
||||||
'entry.amount' => $amount,
|
'entry.amount' => $amount,
|
||||||
'entry.type' => $item->getType(),
|
'entry.type' => $item->getType(),
|
||||||
|
'entry.tags' => implode(', ', $item->getTags()),
|
||||||
'entry.category' => $item->getCategory(),
|
'entry.category' => $item->getCategory(),
|
||||||
'entry.rate' => $formatter->getFormattedMoney($appliedRate, $currency),
|
'entry.rate' => $formatter->getFormattedMoney($appliedRate, $currency),
|
||||||
'entry.rate_nc' => $formatter->getFormattedMoney($appliedRate, $currency, false),
|
'entry.rate_nc' => $formatter->getFormattedMoney($appliedRate, $currency, false),
|
||||||
|
|||||||
@@ -75,6 +75,10 @@ final class InvoiceItem
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $category;
|
private $category;
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $tags = [];
|
||||||
|
|
||||||
public function addAdditionalField(string $name, ?string $value): InvoiceItem
|
public function addAdditionalField(string $name, ?string $value): InvoiceItem
|
||||||
{
|
{
|
||||||
@@ -269,4 +273,23 @@ final class InvoiceItem
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addTag(string $tag): void
|
||||||
|
{
|
||||||
|
foreach ($this->tags as $t) {
|
||||||
|
if (strcasecmp($tag, $t) === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->tags[] = $tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getTags(): array
|
||||||
|
{
|
||||||
|
return $this->tags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -288,6 +288,8 @@
|
|||||||
if (jQuery(field).data('daterangepicker') !== undefined) {
|
if (jQuery(field).data('daterangepicker') !== undefined) {
|
||||||
jQuery(field).data('daterangepicker').setStartDate(momentObj);
|
jQuery(field).data('daterangepicker').setStartDate(momentObj);
|
||||||
jQuery(field).data('daterangepicker').setEndDate(momentObj);
|
jQuery(field).data('daterangepicker').setEndDate(momentObj);
|
||||||
|
{# make sure that the project list is reloaded and the dates can be compared against the project end date #}
|
||||||
|
jQuery('#{{ blockPrefix }}_customer').trigger('change');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace App\Tests\Invoice\Calculator;
|
|||||||
use App\Entity\Activity;
|
use App\Entity\Activity;
|
||||||
use App\Entity\Customer;
|
use App\Entity\Customer;
|
||||||
use App\Entity\InvoiceTemplate;
|
use App\Entity\InvoiceTemplate;
|
||||||
|
use App\Entity\Tag;
|
||||||
use App\Entity\Timesheet;
|
use App\Entity\Timesheet;
|
||||||
use App\Invoice\Calculator\DefaultCalculator;
|
use App\Invoice\Calculator\DefaultCalculator;
|
||||||
use App\Invoice\InvoiceModel;
|
use App\Invoice\InvoiceModel;
|
||||||
@@ -31,27 +32,31 @@ class DefaultCalculatorTest extends AbstractCalculatorTest
|
|||||||
|
|
||||||
public function testWithMultipleEntries()
|
public function testWithMultipleEntries()
|
||||||
{
|
{
|
||||||
|
$date = new \DateTime();
|
||||||
$customer = new Customer();
|
$customer = new Customer();
|
||||||
$template = new InvoiceTemplate();
|
$template = new InvoiceTemplate();
|
||||||
$template->setVat(19);
|
$template->setVat(19);
|
||||||
|
|
||||||
$timesheet = new Timesheet();
|
$timesheet = new Timesheet();
|
||||||
$timesheet->setDescription('foo 1');
|
$timesheet->setDescription('foo 1');
|
||||||
$timesheet->setBegin(new \DateTime());
|
$timesheet->setBegin(clone $date);
|
||||||
$timesheet->setDuration(3600);
|
$timesheet->setDuration(3600);
|
||||||
$timesheet->setRate(293.27);
|
$timesheet->setRate(293.27);
|
||||||
$timesheet->setActivity(new Activity());
|
$timesheet->setActivity(new Activity());
|
||||||
|
$timesheet->addTag((new Tag())->setName('foo'));
|
||||||
|
$timesheet->addTag((new Tag())->setName('bar'));
|
||||||
|
|
||||||
$timesheet2 = new Timesheet();
|
$timesheet2 = new Timesheet();
|
||||||
$timesheet2->setDescription('foo 2');
|
$timesheet2->setDescription('foo 2');
|
||||||
$timesheet2->setBegin(new \DateTime());
|
$timesheet2->setBegin(clone $date);
|
||||||
$timesheet2->setDuration(400);
|
$timesheet2->setDuration(400);
|
||||||
$timesheet2->setRate(84);
|
$timesheet2->setRate(84);
|
||||||
$timesheet2->setActivity(new Activity());
|
$timesheet2->setActivity(new Activity());
|
||||||
|
$timesheet2->addTag((new Tag())->setName('bar1'));
|
||||||
|
|
||||||
$timesheet3 = new Timesheet();
|
$timesheet3 = new Timesheet();
|
||||||
$timesheet3->setDescription('foo 3');
|
$timesheet3->setDescription('foo 3');
|
||||||
$timesheet3->setBegin(new \DateTime());
|
$timesheet3->setBegin(clone $date);
|
||||||
$timesheet3->setDuration(1800);
|
$timesheet3->setDuration(1800);
|
||||||
$timesheet3->setRate(111.11);
|
$timesheet3->setRate(111.11);
|
||||||
$timesheet3->setActivity(new Activity());
|
$timesheet3->setActivity(new Activity());
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use App\Entity\Activity;
|
|||||||
use App\Entity\Customer;
|
use App\Entity\Customer;
|
||||||
use App\Entity\InvoiceTemplate;
|
use App\Entity\InvoiceTemplate;
|
||||||
use App\Entity\Project;
|
use App\Entity\Project;
|
||||||
|
use App\Entity\Tag;
|
||||||
use App\Entity\Timesheet;
|
use App\Entity\Timesheet;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Invoice\Calculator\ShortInvoiceCalculator;
|
use App\Invoice\Calculator\ShortInvoiceCalculator;
|
||||||
@@ -56,6 +57,8 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
|||||||
->setProject($project)
|
->setProject($project)
|
||||||
->setBegin(new \DateTime())
|
->setBegin(new \DateTime())
|
||||||
->setEnd(new \DateTime())
|
->setEnd(new \DateTime())
|
||||||
|
->addTag((new Tag())->setName('foo'))
|
||||||
|
->addTag((new Tag())->setName('bar'))
|
||||||
;
|
;
|
||||||
|
|
||||||
$timesheet2 = new Timesheet();
|
$timesheet2 = new Timesheet();
|
||||||
@@ -68,6 +71,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
|||||||
->setProject($project)
|
->setProject($project)
|
||||||
->setBegin(new \DateTime())
|
->setBegin(new \DateTime())
|
||||||
->setEnd(new \DateTime())
|
->setEnd(new \DateTime())
|
||||||
|
->addTag((new Tag())->setName('bar1'))
|
||||||
;
|
;
|
||||||
|
|
||||||
$timesheet3 = new Timesheet();
|
$timesheet3 = new Timesheet();
|
||||||
@@ -112,6 +116,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
|||||||
$this->assertEquals(472.5, $result->getRate());
|
$this->assertEquals(472.5, $result->getRate());
|
||||||
$this->assertEquals(5800, $result->getDuration());
|
$this->assertEquals(5800, $result->getDuration());
|
||||||
$this->assertEquals(3, $result->getAmount());
|
$this->assertEquals(3, $result->getAmount());
|
||||||
|
$this->assertEquals(['foo', 'bar', 'bar1'], $result->getTags());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWithMultipleEntriesDifferentRates()
|
public function testWithMultipleEntriesDifferentRates()
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ class InvoiceItemDefaultHydratorTest extends TestCase
|
|||||||
'entry.customer.meta.foo-customer',
|
'entry.customer.meta.foo-customer',
|
||||||
'entry.category',
|
'entry.category',
|
||||||
'entry.type',
|
'entry.type',
|
||||||
|
'entry.tags',
|
||||||
];
|
];
|
||||||
|
|
||||||
$keys = array_merge($keys, $metaFields);
|
$keys = array_merge($keys, $metaFields);
|
||||||
|
|||||||
@@ -42,5 +42,15 @@ class InvoiceItemTest extends TestCase
|
|||||||
self::assertEquals(0, $sut->getDuration());
|
self::assertEquals(0, $sut->getDuration());
|
||||||
self::assertNull($sut->getCategory());
|
self::assertNull($sut->getCategory());
|
||||||
self::assertNull($sut->getType());
|
self::assertNull($sut->getType());
|
||||||
|
self::assertEquals([], $sut->getTags());
|
||||||
|
$sut->addTag('foo');
|
||||||
|
$sut->addTag('foo');
|
||||||
|
$sut->addTag('foo1');
|
||||||
|
$sut->addTag('BaR');
|
||||||
|
$sut->addTag('bar');
|
||||||
|
$sut->addTag('FOO');
|
||||||
|
$sut->addTag('bar');
|
||||||
|
$sut->addTag('foo1');
|
||||||
|
self::assertEquals(['foo', 'foo1', 'BaR'], $sut->getTags());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ class DebugRendererTest extends TestCase
|
|||||||
'user.title',
|
'user.title',
|
||||||
'user.meta.hello',
|
'user.meta.hello',
|
||||||
'user.meta.kitty',
|
'user.meta.kitty',
|
||||||
'testFromModelHydrator'
|
'testFromModelHydrator',
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($activityCounter > 1) {
|
if ($activityCounter > 1) {
|
||||||
@@ -242,7 +242,8 @@ class DebugRendererTest extends TestCase
|
|||||||
'entry.customer.meta.foo-customer',
|
'entry.customer.meta.foo-customer',
|
||||||
'entry.category',
|
'entry.category',
|
||||||
'entry.type',
|
'entry.type',
|
||||||
'testFromItemHydrator'
|
'testFromItemHydrator',
|
||||||
|
'entry.tags',
|
||||||
];
|
];
|
||||||
|
|
||||||
$keys = array_merge($keys, $metaFields);
|
$keys = array_merge($keys, $metaFields);
|
||||||
|
|||||||
Reference in New Issue
Block a user