delete invoices (#1652)
* include all meta fields as template variables * support invoice preview via command * support deletion of generated invoices
This commit is contained in:
@@ -17,6 +17,7 @@ Perform EACH version specific task between your version and the new one, otherwi
|
||||
- HTML invoice templates are now treated like other files and offered as download. If you are using relative URLs for including
|
||||
assets (CSS, images) you need to either inline them (see the default templates) or use absolute URLs.
|
||||
- Invoice templates that use the templates variables `${activity.X}` or `${project.X}` should be checked and possibly adapted, as multi-select is now possible for filtering
|
||||
- Invoice templates have access to all meta-fields as variables, not only the ones marked as visible
|
||||
|
||||
Permission changes:
|
||||
- `history_invoice` - NEW: grants all features for the new invoice archive (by default for all admins)
|
||||
|
||||
@@ -27,6 +27,9 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class InvoiceCreateCommand extends Command
|
||||
@@ -55,6 +58,10 @@ class InvoiceCreateCommand extends Command
|
||||
* @var EventDispatcherInterface
|
||||
*/
|
||||
private $eventDispatcher;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $previewDirectory;
|
||||
|
||||
public function __construct(
|
||||
ServiceInvoice $serviceInvoice,
|
||||
@@ -94,6 +101,7 @@ class InvoiceCreateCommand extends Command
|
||||
->addOption('template-meta', null, InputOption::VALUE_OPTIONAL, 'Fetch invoice template from a meta-field', null)
|
||||
->addOption('search', null, InputOption::VALUE_OPTIONAL, 'Search term to filter invoice entries', null)
|
||||
->addOption('exported', null, InputOption::VALUE_OPTIONAL, 'Exported filter for invoice entries (possible values: exported, all), by default only "not exported" items are fetched', null)
|
||||
->addOption('preview', null, InputOption::VALUE_OPTIONAL, 'Absolute path for a rendered preview of the invoice, which will neither be saved nor the items be marked as exported.', null)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -208,7 +216,14 @@ class InvoiceCreateCommand extends Command
|
||||
}
|
||||
|
||||
$markAsExported = false;
|
||||
if ($input->getOption('set-exported')) {
|
||||
if ($input->getOption('preview') !== null) {
|
||||
$this->previewDirectory = rtrim($input->getOption('preview'), '/') . '/';
|
||||
if (!is_dir($this->previewDirectory) || !is_writable($this->previewDirectory)) {
|
||||
$io->error('Invalid preview directory given');
|
||||
|
||||
return 1;
|
||||
}
|
||||
} elseif ($input->getOption('set-exported')) {
|
||||
$markAsExported = true;
|
||||
}
|
||||
|
||||
@@ -283,7 +298,11 @@ class InvoiceCreateCommand extends Command
|
||||
$query->setTemplate($tpl);
|
||||
|
||||
try {
|
||||
$invoices[] = $this->serviceInvoice->createInvoice($query, $this->eventDispatcher);
|
||||
if (null !== $this->previewDirectory) {
|
||||
$invoices[] = $this->saveInvoicePreview($this->serviceInvoice->renderInvoice($query, $this->eventDispatcher));
|
||||
} else {
|
||||
$invoices[] = $this->serviceInvoice->createInvoice($query, $this->eventDispatcher);
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
$io->error(sprintf('Failed to create invoice for project "%s" with: %s', $project->getName(), $ex->getMessage()));
|
||||
}
|
||||
@@ -292,6 +311,34 @@ class InvoiceCreateCommand extends Command
|
||||
return $invoices;
|
||||
}
|
||||
|
||||
private function saveInvoicePreview(Response $response)
|
||||
{
|
||||
$filename = uniqid('invoice_');
|
||||
|
||||
if ($response->headers->has('Content-Disposition')) {
|
||||
$disposition = $response->headers->get('Content-Disposition');
|
||||
$parts = explode(';', $disposition);
|
||||
foreach ($parts as $part) {
|
||||
if (stripos($part, 'filename=') === false) {
|
||||
continue;
|
||||
}
|
||||
$filename = explode('filename=', $part);
|
||||
if (\count($filename) > 1) {
|
||||
$filename = $filename[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($response instanceof BinaryFileResponse) {
|
||||
$file = $response->getFile();
|
||||
$file->move($this->previewDirectory, $filename);
|
||||
} else {
|
||||
(new Filesystem())->dumpFile($this->previewDirectory . $filename, $response->getContent());
|
||||
}
|
||||
|
||||
return $this->previewDirectory . $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Customer[] $customers
|
||||
* @param InvoiceQuery $defaultQuery
|
||||
@@ -318,7 +365,11 @@ class InvoiceCreateCommand extends Command
|
||||
$query->setTemplate($tpl);
|
||||
|
||||
try {
|
||||
$invoices[] = $this->serviceInvoice->createInvoice($query, $this->eventDispatcher);
|
||||
if (null !== $this->previewDirectory) {
|
||||
$invoices[] = $this->saveInvoicePreview($this->serviceInvoice->renderInvoice($query, $this->eventDispatcher));
|
||||
} else {
|
||||
$invoices[] = $this->serviceInvoice->createInvoice($query, $this->eventDispatcher);
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
$io->error(sprintf('Failed to create invoice for customer "%s" with: %s', $customer->getName(), $ex->getMessage()));
|
||||
}
|
||||
@@ -343,6 +394,22 @@ class InvoiceCreateCommand extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (null !== $this->previewDirectory) {
|
||||
$columns = ['Filename'];
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaderTitle(sprintf('Created %s invoice(s)', \count($invoices)));
|
||||
$table->setHeaders($columns);
|
||||
|
||||
foreach ($invoices as $invoiceFile) {
|
||||
$table->addRow([$invoiceFile]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$columns = ['ID', 'Customer', 'Total', 'Filename'];
|
||||
|
||||
$table = new Table($output);
|
||||
|
||||
@@ -189,11 +189,26 @@ final class InvoiceController extends AbstractController
|
||||
{
|
||||
try {
|
||||
$this->service->changeInvoiceStatus($invoice, $status);
|
||||
} catch (\InvalidArgumentException $ex) {
|
||||
throw $this->createNotFoundException($ex->getMessage());
|
||||
$this->flashSuccess('action.update.success');
|
||||
} catch (\Exception $ex) {
|
||||
$this->flashError('action.update.error');
|
||||
}
|
||||
|
||||
$this->flashSuccess('action.update.success');
|
||||
return $this->redirectToRoute('admin_invoice_list');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(path="/delete/{id}", name="admin_invoice_delete", methods={"GET"})
|
||||
* @Security("is_granted('history_invoice')")
|
||||
*/
|
||||
public function deleteInvoiceAction(Invoice $invoice): Response
|
||||
{
|
||||
try {
|
||||
$this->service->deleteInvoice($invoice);
|
||||
$this->flashSuccess('action.delete.success');
|
||||
} catch (\Exception $ex) {
|
||||
$this->flashError('action.delete.error');
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('admin_invoice_list');
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ class InvoiceTemplate
|
||||
private $decimalDuration = false;
|
||||
|
||||
/**
|
||||
* Used when rendering HTML templates.
|
||||
* Used for translations and locale dependent number and date formats.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
|
||||
@@ -95,7 +95,7 @@ class InvoiceItemDefaultHydrator implements InvoiceItemHydrator
|
||||
'entry.activity_id' => $activity->getId(),
|
||||
]);
|
||||
|
||||
foreach ($activity->getVisibleMetaFields() as $metaField) {
|
||||
foreach ($activity->getMetaFields() as $metaField) {
|
||||
$values = array_merge($values, [
|
||||
'entry.activity.meta.' . $metaField->getName() => $metaField->getValue(),
|
||||
]);
|
||||
@@ -108,7 +108,7 @@ class InvoiceItemDefaultHydrator implements InvoiceItemHydrator
|
||||
'entry.project_id' => $project->getId(),
|
||||
]);
|
||||
|
||||
foreach ($project->getVisibleMetaFields() as $metaField) {
|
||||
foreach ($project->getMetaFields() as $metaField) {
|
||||
$values = array_merge($values, [
|
||||
'entry.project.meta.' . $metaField->getName() => $metaField->getValue(),
|
||||
]);
|
||||
@@ -121,7 +121,7 @@ class InvoiceItemDefaultHydrator implements InvoiceItemHydrator
|
||||
'entry.customer_id' => $customer->getId(),
|
||||
]);
|
||||
|
||||
foreach ($customer->getVisibleMetaFields() as $metaField) {
|
||||
foreach ($customer->getMetaFields() as $metaField) {
|
||||
$values = array_merge($values, [
|
||||
'entry.customer.meta.' . $metaField->getName() => $metaField->getValue(),
|
||||
]);
|
||||
|
||||
@@ -46,7 +46,7 @@ class InvoiceModelCustomerHydrator implements InvoiceModelHydrator
|
||||
// remaining time-budget?
|
||||
];
|
||||
|
||||
foreach ($customer->getVisibleMetaFields() as $metaField) {
|
||||
foreach ($customer->getMetaFields() as $metaField) {
|
||||
$values = array_merge($values, [
|
||||
'customer.meta.' . $metaField->getName() => $metaField->getValue(),
|
||||
]);
|
||||
|
||||
@@ -27,6 +27,7 @@ class InvoiceModelDefaultHydrator implements InvoiceModelHydrator
|
||||
'invoice.date' => $formatter->getFormattedDateTime($model->getInvoiceDate()),
|
||||
'invoice.number' => $model->getInvoiceNumber(),
|
||||
'invoice.currency' => $currency,
|
||||
'invoice.language' => $model->getTemplate()->getLanguage(), // since 1.9
|
||||
'invoice.currency_symbol' => $formatter->getCurrencySymbol($currency),
|
||||
'invoice.vat' => $model->getCalculator()->getVat(),
|
||||
'invoice.tax' => $formatter->getFormattedMoney($tax, $currency),
|
||||
@@ -52,11 +53,19 @@ class InvoiceModelDefaultHydrator implements InvoiceModelHydrator
|
||||
'template.payment_details' => $model->getTemplate()->getPaymentDetails(),
|
||||
|
||||
'query.begin' => $formatter->getFormattedDateTime($model->getQuery()->getBegin()),
|
||||
'query.day' => $model->getQuery()->getBegin()->format('d'),
|
||||
'query.end' => $formatter->getFormattedDateTime($model->getQuery()->getEnd()),
|
||||
'query.month' => $formatter->getFormattedMonthName($model->getQuery()->getBegin()),
|
||||
'query.month_number' => $model->getQuery()->getBegin()->format('m'),
|
||||
'query.year' => $model->getQuery()->getBegin()->format('Y'),
|
||||
'query.day' => $model->getQuery()->getBegin()->format('d'), // @deprecated
|
||||
'query.month' => $formatter->getFormattedMonthName($model->getQuery()->getBegin()), // @deprecated
|
||||
'query.month_number' => $model->getQuery()->getBegin()->format('m'), // @deprecated
|
||||
'query.year' => $model->getQuery()->getBegin()->format('Y'), // @deprecated
|
||||
'query.begin_day' => $model->getQuery()->getBegin()->format('d'),
|
||||
'query.begin_month' => $formatter->getFormattedMonthName($model->getQuery()->getBegin()),
|
||||
'query.begin_month_number' => $model->getQuery()->getBegin()->format('m'),
|
||||
'query.begin_year' => $model->getQuery()->getBegin()->format('Y'),
|
||||
'query.end' => $formatter->getFormattedDateTime($model->getQuery()->getEnd()), // since 1.9
|
||||
'query.end_day' => $model->getQuery()->getEnd()->format('d'), // since 1.9
|
||||
'query.end_month' => $formatter->getFormattedMonthName($model->getQuery()->getEnd()), // since 1.9
|
||||
'query.end_month_number' => $model->getQuery()->getEnd()->format('m'), // since 1.9
|
||||
'query.end_year' => $model->getQuery()->getEnd()->format('Y'), // since 1.9
|
||||
];
|
||||
|
||||
return $values;
|
||||
|
||||
@@ -396,6 +396,15 @@ final class ServiceInvoice
|
||||
);
|
||||
}
|
||||
|
||||
public function deleteInvoice(Invoice $invoice)
|
||||
{
|
||||
$invoiceDirectory = $this->getInvoicesDirectory();
|
||||
if (is_file($invoiceDirectory . $invoice->getInvoiceFilename())) {
|
||||
$this->fileHelper->removeFile($invoiceDirectory . $invoice->getInvoiceFilename());
|
||||
}
|
||||
$this->invoiceRepository->deleteInvoice($invoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InvoiceQuery $query
|
||||
* @return InvoiceModel
|
||||
|
||||
@@ -28,6 +28,13 @@ class InvoiceRepository extends EntityRepository
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
public function deleteInvoice(Invoice $invoice)
|
||||
{
|
||||
$entityManager = $this->getEntityManager();
|
||||
$entityManager->remove($invoice);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
private function getCounterFor(\DateTime $start, \DateTime $end): int
|
||||
{
|
||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||
|
||||
@@ -58,4 +58,9 @@ final class FileHelper
|
||||
{
|
||||
$this->filesystem->dumpFile($filename, $data);
|
||||
}
|
||||
|
||||
public function removeFile(string $filename)
|
||||
{
|
||||
$this->filesystem->remove($filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,11 +57,8 @@
|
||||
{% set actions = actions|merge({'invoice.paid': path('admin_invoice_status', {'id': invoice.id, 'status': 'paid'})}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if actions|length > 0 %}
|
||||
{% set actions = actions|merge({'divider': null}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'download': {'url': path('admin_invoice_download', {'id': invoice.id}), 'target': '_blank'}}) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('admin_invoice_delete', {'id' : invoice.id}), 'class': 'confirmation-link', 'attr': {'data-question': 'confirm.delete'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.invoice', {'actions': actions, 'invoice': invoice}) %}
|
||||
@@ -107,7 +104,7 @@
|
||||
{% if is_granted('manage_invoice_template') %}
|
||||
{% set actions = actions|merge({'edit': {'url': path('admin_invoice_template_edit', {'id' : template.id}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% set actions = actions|merge({'copy': path('admin_invoice_template_copy', {'id' : template.id})}) %}
|
||||
{% set actions = actions|merge({'trash': path('admin_invoice_template_delete', {'id' : template.id})}) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('admin_invoice_template_delete', {'id' : template.id}), 'class': 'confirmation-link', 'attr': {'data-question': 'confirm.delete'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.invoice_template', {'actions': actions, 'view': view, 'template': template}) %}
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
{% for key, value in model.toArray %}
|
||||
{{ key }}:
|
||||
{{ key }}
|
||||
{% if value is not empty %}
|
||||
{{ value|multiline_indent(' ') }}
|
||||
{{ value|multiline_indent(' ') }}
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% for entry in model.calculator.entries %}
|
||||
---
|
||||
|
||||
{% set items = model.itemToArray(entry) %}
|
||||
{% for key, value in items %}
|
||||
{{ key }}:
|
||||
{{ key }}
|
||||
{% if value is not empty %}
|
||||
{{ value|multiline_indent(' ') }}
|
||||
{{ value|multiline_indent(' ') }}
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -157,6 +157,11 @@ class InvoiceCreateCommandTest extends KernelTestCase
|
||||
$this->assertCommandErrors(['--user' => UserFixtures::USERNAME_SUPER_ADMIN, '--customer' => 1, '--template' => 'x', '--start' => '2020-01-01', '--end' => 'öäüß'], 'Invalid end date given');
|
||||
}
|
||||
|
||||
public function testCreateWithInvalidPreviewDirectory()
|
||||
{
|
||||
$this->assertCommandErrors(['--user' => UserFixtures::USERNAME_SUPER_ADMIN, '--customer' => 1, '--template' => 'x', '--start' => '2020-01-01', '--end' => '2020-01-02', '--preview' => '/kjhg/'], 'Invalid preview directory given');
|
||||
}
|
||||
|
||||
public function testCreateWithInvalidCustomer()
|
||||
{
|
||||
$this->assertCommandErrors(['--user' => UserFixtures::USERNAME_SUPER_ADMIN, '--customer' => 3, '--template' => 'x'], 'Unknown customer ID: 3');
|
||||
@@ -245,4 +250,17 @@ class InvoiceCreateCommandTest extends KernelTestCase
|
||||
$output = $commandTester->getDisplay();
|
||||
$this->assertStringContainsString('Created 1 invoice(s) ', $output);
|
||||
}
|
||||
|
||||
public function testCreateInvoiceByProjectWithPreview()
|
||||
{
|
||||
$start = new \DateTime('-2 months');
|
||||
$end = new \DateTime();
|
||||
|
||||
$this->prepareFixtures($start);
|
||||
|
||||
$commandTester = $this->createInvoice(['--user' => UserFixtures::USERNAME_SUPER_ADMIN, '--exported' => 'all', '--preview' => sys_get_temp_dir(), '--by-project' => null, '--template-meta' => 'template', '--start' => $start->format('Y-m-d'), '--end' => $end->format('Y-m-d')]);
|
||||
|
||||
$output = $commandTester->getDisplay();
|
||||
$this->assertStringContainsString('Created 1 invoice(s) ', $output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ class InvoiceControllerTest extends ControllerBaseTest
|
||||
$this->assertEquals('invoice_print', $node->getIterator()[0]->getAttribute('class'));
|
||||
}
|
||||
|
||||
public function testCreateActionAsAdminWithDownloadAndStatusChange()
|
||||
public function testCreateActionAsAdminWithDownloadAndStatusChangeAndDelete()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
/** @var EntityManager $em */
|
||||
@@ -350,6 +350,11 @@ class InvoiceControllerTest extends ControllerBaseTest
|
||||
$this->assertIsRedirect($client, '/invoice/show');
|
||||
$client->followRedirect();
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$this->request($client, '/invoice/delete/1');
|
||||
$this->assertIsRedirect($client, '/invoice/show');
|
||||
$client->followRedirect();
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
}
|
||||
|
||||
public function testEditTemplateAction()
|
||||
|
||||
@@ -76,6 +76,15 @@ class InvoiceTemplateTest extends TestCase
|
||||
self::assertInstanceOf(InvoiceTemplate::class, $sut->setLanguage('de'));
|
||||
self::assertEquals('de', $sut->getLanguage());
|
||||
|
||||
self::assertInstanceOf(InvoiceTemplate::class, $sut->setNumberGenerator('foo'));
|
||||
self::assertEquals('foo', $sut->getNumberGenerator());
|
||||
|
||||
self::assertInstanceOf(InvoiceTemplate::class, $sut->setRenderer('bar'));
|
||||
self::assertEquals('bar', $sut->getRenderer());
|
||||
|
||||
self::assertInstanceOf(InvoiceTemplate::class, $sut->setCalculator('fooBar'));
|
||||
self::assertEquals('fooBar', $sut->getCalculator());
|
||||
|
||||
self::assertEquals($sut, clone $sut);
|
||||
}
|
||||
|
||||
|
||||
@@ -184,13 +184,15 @@ class UserTest extends TestCase
|
||||
{
|
||||
$sut = new User();
|
||||
$sut->setAlias('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
|
||||
self::assertEquals(60, \strlen($sut->getAlias()));
|
||||
self::assertEquals(60, mb_strlen($sut->getAlias()));
|
||||
$sut->setAlias('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxAAAAA');
|
||||
self::assertEquals(60, \strlen($sut->getAlias()));
|
||||
self::assertEquals(60, mb_strlen($sut->getAlias()));
|
||||
$sut->setAlias('万政提質打録施熟活者韓症写気当。規談表有部確暑将回優隊見竜能南事。竹阪板府入違護究兵厚能提。済伸知題熱正写場京誉事週在複今徳際供。審利世連手阿量携泉指済像更映刊政病世。熱楽時予資方賀月改洋者職原桜提増脚職。気公誌荒原輝文治察専及唱戦白廃模書。着授健出山力集出止員捉害実載措明国無今。棋出陶供供知機使協物確講最新両。');
|
||||
self::assertEquals(60, mb_strlen($sut->getAlias()));
|
||||
$sut->setTitle('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
|
||||
self::assertEquals(50, \strlen($sut->getTitle()));
|
||||
self::assertEquals(50, mb_strlen($sut->getTitle()));
|
||||
$sut->setTitle('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxAAAAAA');
|
||||
self::assertEquals(50, \strlen($sut->getTitle()));
|
||||
self::assertEquals(50, mb_strlen($sut->getTitle()));
|
||||
}
|
||||
|
||||
public function testPreferencesCollectionIsCreatedOnBrokenUser()
|
||||
|
||||
@@ -39,6 +39,7 @@ class InvoiceModelDefaultHydratorTest extends TestCase
|
||||
'invoice.currency',
|
||||
'invoice.currency_symbol',
|
||||
'invoice.vat',
|
||||
'invoice.language',
|
||||
'invoice.tax',
|
||||
'invoice.tax_nc',
|
||||
'invoice.tax_plain',
|
||||
@@ -60,11 +61,19 @@ class InvoiceModelDefaultHydratorTest extends TestCase
|
||||
'template.contact',
|
||||
'template.payment_details',
|
||||
'query.begin',
|
||||
'query.day',
|
||||
'query.end',
|
||||
'query.day',
|
||||
'query.month',
|
||||
'query.month_number',
|
||||
'query.year',
|
||||
'query.begin_day',
|
||||
'query.begin_month',
|
||||
'query.begin_month_number',
|
||||
'query.begin_year',
|
||||
'query.end_day',
|
||||
'query.end_month',
|
||||
'query.end_month_number',
|
||||
'query.end_year',
|
||||
];
|
||||
|
||||
$givenKeys = array_keys($model);
|
||||
|
||||
@@ -84,6 +84,7 @@ class DebugRendererTest extends TestCase
|
||||
'invoice.currency_symbol',
|
||||
'invoice.vat',
|
||||
'invoice.tax',
|
||||
'invoice.language',
|
||||
'invoice.tax_nc',
|
||||
'invoice.tax_plain',
|
||||
'invoice.total_time',
|
||||
@@ -109,6 +110,14 @@ class DebugRendererTest extends TestCase
|
||||
'query.month',
|
||||
'query.month_number',
|
||||
'query.year',
|
||||
'query.begin_day',
|
||||
'query.begin_month',
|
||||
'query.begin_month_number',
|
||||
'query.begin_year',
|
||||
'query.end_day',
|
||||
'query.end_month',
|
||||
'query.end_month_number',
|
||||
'query.end_year',
|
||||
'customer.id',
|
||||
'customer.address',
|
||||
'customer.name',
|
||||
|
||||
@@ -115,6 +115,7 @@ trait RendererTestTrait
|
||||
$template = new InvoiceTemplate();
|
||||
$template->setTitle('a very *long* test invoice / template title with [special] character');
|
||||
$template->setVat(19);
|
||||
$template->setLanguage('en');
|
||||
|
||||
$project = new Project();
|
||||
$project->setName('project name');
|
||||
|
||||
@@ -69,9 +69,19 @@ class TextRendererTest extends KernelTestCase
|
||||
|
||||
foreach ($model->toArray() as $key => $value) {
|
||||
if (null === $value || '' === $value) {
|
||||
self::assertStringContainsString(sprintf("%s:\n\n", $key), $content);
|
||||
self::assertStringContainsString(sprintf("%s\n", $key), $content);
|
||||
} else {
|
||||
self::assertStringContainsString(sprintf("%s:\n %s", $key, explode("\n", $value)[0]), $content);
|
||||
self::assertStringContainsString(sprintf("%s\n %s", $key, explode("\n", $value)[0]), $content);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($model->getCalculator()->getEntries() as $entry) {
|
||||
foreach ($model->itemToArray($entry) as $key => $value) {
|
||||
if (null === $value || '' === $value) {
|
||||
self::assertStringContainsString(sprintf("%s\n", $key), $content);
|
||||
} else {
|
||||
self::assertStringContainsString(sprintf("%s\n %s", $key, explode("\n", $value)[0]), $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
self::assertEquals(\count($model->getCalculator()->getEntries()), substr_count($content, PHP_EOL . '---' . PHP_EOL));
|
||||
|
||||
Reference in New Issue
Block a user