diff --git a/phpstan.neon b/phpstan.neon
index c06a4aef..929e7167 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -4830,16 +4830,6 @@ parameters:
count: 1
path: src/Form/Type/EntityMetaDefinitionType.php
- -
- message: "#^Parameter \\#1 \\$string of function strtolower expects string, string\\|null given\\.$#"
- count: 1
- path: src/Form/Type/InvoiceRendererType.php
-
- -
- message: "#^Parameter \\#1 \\$string of function ucfirst expects string, string\\|null given\\.$#"
- count: 1
- path: src/Form/Type/InvoiceRendererType.php
-
-
message: "#^PHPDoc tag @var for variable \\$collection contains generic class Doctrine\\\\Common\\\\Collections\\\\ArrayCollection but does not specify its types\\: TKey, T$#"
count: 1
diff --git a/src/Constants.php b/src/Constants.php
index cd03da8d..4b56ffa4 100644
--- a/src/Constants.php
+++ b/src/Constants.php
@@ -17,11 +17,11 @@ class Constants
/**
* The current release version
*/
- public const VERSION = '2.0.5';
+ public const VERSION = '2.0.6';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
- public const VERSION_ID = 20005;
+ public const VERSION_ID = 20006;
/**
* The software name
*/
diff --git a/src/Controller/InvoiceController.php b/src/Controller/InvoiceController.php
index 82767014..1eb1b20f 100644
--- a/src/Controller/InvoiceController.php
+++ b/src/Controller/InvoiceController.php
@@ -109,7 +109,7 @@ final class InvoiceController extends AbstractController
$total += \count($model->getCalculator()->getEntries());
$values = [
- 'invoiceDate' => $query->getInvoiceDate(),
+ 'invoiceDate' => null,
'template' => $customerTpl
];
@@ -364,10 +364,10 @@ final class InvoiceController extends AbstractController
$table->addColumn('mf_' . $metaColumn->getName(), ['title' => $metaColumn->getLabel(), 'class' => 'd-none', 'orderBy' => false]);
}
- $table->addColumn('invoice_number', ['class' => 'd-none d-md-table-cell w-min', 'title' => 'invoice.number', 'orderBy' => false]);
+ $table->addColumn('invoice_number', ['class' => 'd-none d-md-table-cell w-min', 'title' => 'invoice.number', 'orderBy' => 'invoice.number']);
$table->addColumn('due_date', ['class' => 'd-none w-min', 'title' => 'invoice.due_days', 'orderBy' => false]);
$table->addColumn('payment_date', ['class' => 'd-none w-min', 'title' => 'invoice.payment_date', 'orderBy' => false]);
- $table->addColumn('status', ['class' => 'd-none d-sm-table-cell w-min', 'orderBy' => false]);
+ $table->addColumn('status', ['class' => 'd-none d-sm-table-cell w-min', 'orderBy' => 'status']);
$table->addColumn('subtotal', ['class' => 'd-none text-end w-min', 'title' => 'invoice.subtotal', 'orderBy' => false]);
$table->addColumn('tax', ['class' => 'd-none text-end w-min', 'title' => 'invoice.tax']);
$table->addColumn('total_rate', ['class' => 'd-none d-md-table-cell text-end w-min']);
diff --git a/src/Form/Type/InvoiceRendererType.php b/src/Form/Type/InvoiceRendererType.php
index 762c24cb..c3bbed18 100644
--- a/src/Form/Type/InvoiceRendererType.php
+++ b/src/Form/Type/InvoiceRendererType.php
@@ -61,13 +61,16 @@ final class InvoiceRendererType extends AbstractType
$type = array_pop($parts);
+ if (!\is_string($type)) {
+ return 'programmatic';
+ }
+
return match (strtolower($type)) {
'json', 'txt', 'xml' => 'programmatic',
- 'pdf' => 'PDF',
'docx', 'doc' => 'Word',
'xls', 'xlsx' => 'Excel',
'ods' => 'LibreOffice',
- default => ucfirst($type),
+ default => strtoupper($type),
};
}
diff --git a/src/Invoice/Renderer/AbstractSpreadsheetRenderer.php b/src/Invoice/Renderer/AbstractSpreadsheetRenderer.php
index ffe1c147..10143b18 100644
--- a/src/Invoice/Renderer/AbstractSpreadsheetRenderer.php
+++ b/src/Invoice/Renderer/AbstractSpreadsheetRenderer.php
@@ -101,7 +101,7 @@ abstract class AbstractSpreadsheetRenderer extends AbstractRenderer
if (\is_string($content) && str_starts_with($content, '=')) {
$contentLooksLikeFormula = true;
}
- $value = str_replace($searchKey, $content, $value);
+ $value = str_replace($searchKey, $content ?? '', $value);
}
if ($contentLooksLikeFormula && $firstReplacerPos === 0) {
diff --git a/src/Repository/InvoiceRepository.php b/src/Repository/InvoiceRepository.php
index b6565432..a193e218 100644
--- a/src/Repository/InvoiceRepository.php
+++ b/src/Repository/InvoiceRepository.php
@@ -204,7 +204,7 @@ class InvoiceRepository extends EntityRepository
case 'date':
$orderBy = 'i.createdAt';
break;
- case 'number':
+ case 'invoice.number':
$orderBy = 'i.invoiceNumber';
break;
case 'payed':
@@ -213,9 +213,11 @@ class InvoiceRepository extends EntityRepository
case 'total_rate':
$orderBy = 'i.total';
break;
- case 'tax':
case 'status':
- $orderBy = 'i.' . $orderBy;
+ $orderBy = 'i.status';
+ break;
+ case 'tax':
+ $orderBy = 'i.tax';
break;
}
diff --git a/src/Repository/Query/InvoiceArchiveQuery.php b/src/Repository/Query/InvoiceArchiveQuery.php
index ea0ad191..79caf0be 100644
--- a/src/Repository/Query/InvoiceArchiveQuery.php
+++ b/src/Repository/Query/InvoiceArchiveQuery.php
@@ -21,9 +21,9 @@ class InvoiceArchiveQuery extends BaseQuery
use DateRangeTrait;
public const INVOICE_ARCHIVE_ORDER_ALLOWED = [
- 'date', 'total_rate',
+ 'date', 'invoice.number', 'status', 'total_rate'
// TODO other fields have a problem with translation
- // 'number', 'tax', 'payed', 'status'
+ // , 'tax', 'payed'
];
/**
diff --git a/templates/invoice/renderer/timesheet.html.twig b/templates/invoice/renderer/timesheet.html.twig
index 14b2ff0a..66d0d716 100644
--- a/templates/invoice/renderer/timesheet.html.twig
+++ b/templates/invoice/renderer/timesheet.html.twig
@@ -1,130 +1,142 @@
-{% import "macros/widgets.html.twig" as widgets %}
-{% extends 'invoice/layout.html.twig' %}
-
-{% block invoice %}
- {% set isDecimal = true %}
- {% set project = model.query.project %}
- {% set activity = model.query.activity %}
-
-
-
-
-
-
- {{ 'invoice.from'|trans }}
-
- {% if model.query.user is not empty %}
- {{ widgets.username(model.query.user) }}
- {% else %}
- {{ model.template.company }}
- {% endif %}
-
-
-
- {{ 'date'|trans }}
-
- {% if model.query.begin|date('m') != model.query.end|date('m') or model.query.begin|date('Y') != model.query.end|date('Y') %}
- {{ model.query.begin|date_short }} - {{ model.query.end|date_short }}
- {% else %}
- {{ model.query.end|month_name }} {{ model.query.end|date('Y') }}
- {% endif %}
-
-
-
- {{ 'customer'|trans }}
-
- {% if model.customer.number is not empty %}[{{ model.customer.number }}]{% endif %}
- {{ model.customer.name }}{% if model.customer.contact is not empty %} / {{ model.customer.contact }}{% endif %}
-
-
- {% if project is not null %}
-
- {{ 'project'|trans }}
-
- {{ project.name }}
- {% if project.orderNumber is not empty %}
- ({{ 'orderNumber'|trans }}: {{ project.orderNumber }})
- {% endif %}
-
-
- {% endif %}
- {% if activity is not null %}
-
- {{ 'activity'|trans }}
-
- {{ activity.name }}
-
-
- {% endif %}
-
-
-
-
-
-
-
-
-
- {{ 'date'|trans }}
- {% if model.query.user is empty %}
- {{ 'user'|trans }}
- {% endif %}
- {{ 'activity'|trans }}
- {{ 'hours'|trans }}
-
-
-
- {% for entry in model.calculator.entries %}
-
- {{ entry.begin|date_short }}
- {% if model.query.user is empty %}
- {{ widgets.username(entry.user) }}
- {% endif %}
-
- {% if entry.description is not empty %}
- {{ entry.description|nl2br }}
- {% else %}
- {% if entry.activity is not null %}{{ entry.activity.name }} / {% endif %}{{ entry.project.name }}
- {% endif %}
-
- {{ entry.duration|duration(isDecimal) }}
-
- {% endfor %}
-
-
-
-
- {% if model.query.user is empty %}
-
- {% endif %}
- {{ 'invoice.total_working_time'|trans }}
- {{ model.calculator.timeWorked|duration(isDecimal) }}
-
-
-
-
-
-
-
-
- {% if model.template.paymentTerms is not empty %}
-
{{ 'payment_terms'|trans }}
-
-
- {{ model.template.paymentTerms|trim|nl2br }}
-
- {% endif %}
-
-
-
{{ 'invoice.signature_user'|trans }}
-
{{ 'invoice.signature_customer'|trans }}
+
+{% set fallback = app.request is not null ? app.request.locale : 'en' %}
+{% set language = model.template.language|default(fallback) %}
+{% set isDecimal = true %}
+{% set project = model.query.project %}
+{% set activity = model.query.activity %}
+
+
+
+
+
+
{{ model.invoiceNumber }}-{{ model.customer.company|default(model.customer.name)|u.snake }}
+
+
+
+
+
+
+
+
+ {{ 'invoice.from'|trans }}
+
+ {% if model.query.user is not empty %}
+ {{ model.query.user.displayName }}
+ {% else %}
+ {{ model.template.company }}
+ {% endif %}
+
+
+
+ {{ 'date'|trans }}
+
+ {% if model.query.begin|date('m') != model.query.end|date('m') or model.query.begin|date('Y') != model.query.end|date('Y') %}
+ {{ model.query.begin|date_short }} - {{ model.query.end|date_short }}
+ {% else %}
+ {{ model.query.end|month_name }} {{ model.query.end|date('Y') }}
+ {% endif %}
+
+
+
+ {{ 'customer'|trans }}
+
+ {% if model.customer.number is not empty %}[{{ model.customer.number }}]{% endif %}
+ {{ model.customer.name }}{% if model.customer.contact is not empty %} / {{ model.customer.contact }}{% endif %}
+
+
+ {% if project is not null %}
+
+ {{ 'project'|trans }}
+
+ {{ project.name }}
+ {% if project.orderNumber is not empty %}
+ ({{ 'orderNumber'|trans }}: {{ project.orderNumber }})
+ {% endif %}
+
+
+ {% endif %}
+ {% if activity is not null %}
+
+ {{ 'activity'|trans }}
+
+ {{ activity.name }}
+
+
+ {% endif %}
+
+
+
+
+
+
+
+
+ {{ 'date'|trans }}
+ {% if model.query.user is empty %}
+ {{ 'user'|trans }}
+ {% endif %}
+ {{ 'activity'|trans }}
+ {{ 'hours'|trans }}
+
+
+
+ {% for entry in model.calculator.entries %}
+
+ {{ entry.begin|date_short }}
+ {% if model.query.user is empty %}
+ {{ entry.user.displayName }}
+ {% endif %}
+
+ {% if entry.description is not empty %}
+ {{ entry.description|nl2br }}
+ {% else %}
+ {% if entry.activity is not null %}{{ entry.activity.name }} / {% endif %}{{ entry.project.name }}
+ {% endif %}
+
+ {{ entry.duration|duration(isDecimal) }}
+
+ {% endfor %}
+
+
+
+
+ {% if model.query.user is empty %}
+
+ {% endif %}
+ {{ 'invoice.total_working_time'|trans }}
+ {{ model.calculator.timeWorked|duration(isDecimal) }}
+
+
+
+
+
+
+
+ {% if model.template.paymentTerms is not empty %}
+
{{ 'payment_terms'|trans }}
+
+
+ {{ model.template.paymentTerms|trim|nl2br }}
+
+ {% endif %}
+
+
+
{{ 'invoice.signature_user'|trans }}
+
{{ 'invoice.signature_customer'|trans }}
+
+
+
+
-{% endblock %}
\ No newline at end of file
+
+
diff --git a/templates/macros/widgets.html.twig b/templates/macros/widgets.html.twig
index 35095d67..0fbabbc2 100644
--- a/templates/macros/widgets.html.twig
+++ b/templates/macros/widgets.html.twig
@@ -284,33 +284,33 @@
{% endmacro %}
{% macro form_type_value(type, value, entity) %}
- {% if '\\ColorPickerType' in type or '\\ColorChoiceType' in type %}
+ {% if 'ColorPickerType' in type or 'ColorChoiceType' in type %}
{% if value is not empty %}
{% endif %}
- {% elseif '\\DurationType' in type %}
+ {% elseif 'DurationType' in type %}
{{ value|duration }}
- {% elseif '\\YesNoType' in type or '\\CheckBoxType' in type %}
+ {% elseif 'YesNoType' in type or 'CheckBoxType' in type %}
{{ _self.label_boolean(value) }}
- {% elseif '\\DatePickerType' in type %}
+ {% elseif 'DatePickerType' in type %}
{{ value|date_short }}
- {% elseif '\\DateTimePickerType' in type %}
+ {% elseif 'DateTimePickerType' in type %}
{{ value|date_time }}
- {% elseif '\\CountryType' in type %}
+ {% elseif 'CountryType' in type %}
{{ value|country_name }}
- {% elseif '\\CurrencyType' in type %}
+ {% elseif 'CurrencyType' in type %}
{{ value|currency_name }}
- {% elseif '\\LanguageType' in type %}
+ {% elseif 'LanguageType' in type %}
{{ value|locale_name }}
- {% elseif '\\TagsType' in type %}
+ {% elseif 'TagsType' in type %}
{% for tag in value|split(',') %}
{% if tag is not empty %}
{{ _self.badge(tag, null|colorize(tag)) }}
{% endif %}
{% endfor %}
- {% elseif '\\MoneyType' in type %}
+ {% elseif 'MoneyType' in type %}
{% set classname = class_name(entity) %}
{% if entity is null %}
{{ value }}
@@ -325,11 +325,11 @@
{% else %}
{{ value }}
{% endif %}
- {% elseif '\\TextareaType' in type %}
+ {% elseif 'TextareaType' in type %}
{{ value|nl2br }}
- {% elseif '\\EmailType' in type %}
+ {% elseif 'EmailType' in type %}
{{ value }}
- {% elseif '\\UrlType' in type %}
+ {% elseif 'UrlType' in type %}
{{ value }}
{% else %}
{{ value }}
diff --git a/templates/timesheet/export.html.twig b/templates/timesheet/export.html.twig
index fce53104..4cc3853b 100644
--- a/templates/timesheet/export.html.twig
+++ b/templates/timesheet/export.html.twig
@@ -1,99 +1,110 @@
-{% extends 'invoice/layout.html.twig' %}
-{% import "macros/widgets.html.twig" as widgets %}
+
{% import "macros/datatables.html.twig" as tables %}
+{% set language = app.request is not null ? app.request.locale : 'en' %}
+{% set decimal = false %}
+{% set showUserColumn = true %}
+{% if query.user %}
+ {% set showUserColumn = false %}
+{% endif %}
+
+
+
+
+
+
{{ 'export'|trans }}
+
+
+
+
+
-{% block title %}{{ 'export'|trans }}{% endblock %}
-{% block invoice %}
- {% set decimal = decimal|default(false) %}
- {% set showUserColumn = true %}
- {% if query.user %}
- {% set showUserColumn = false %}
- {% endif %}
-
-
-
-
-
-
-
-
- {{ 'date'|trans }}
- {% if showUserColumn %}
- {{ 'username'|trans }}
+
-
-
- {% set timeWorked = 0 %}
- {% for entry in entries %}
- {% set timeWorked = timeWorked + entry.duration %}
+ {% if query.begin is not empty %}
+ {{ query.begin|date_short }}
+ {% else %}
+ {% set last = entries|last %}
+ {{ last.begin|date_short }}
+ {% endif %}
+ –
+ {% if query.end is not empty %}
+ {{ query.end|date_short }}
+ {% else %}
+ {% set first = entries|first %}
+ {{ first.end|date_short }}
+ {% endif %}
+
+
+
+
+
+
+
+
- {{ entry.begin|date_short }}
+ {{ 'date'|trans }}
{% if showUserColumn %}
- {{ widgets.username(entry.user) }}
+ {{ 'username'|trans }}
{% endif %}
-
- {% if entry.description is not empty %}
-
- {{ entry.description|desc2html }}
-
+ {{ 'description'|trans }}
+ {% for field in timesheetMetaFields %}
+ {{ field.label|trans }}
+ {% endfor %}
+ {{ 'hours'|trans }}
+
+
+
+ {% set timeWorked = 0 %}
+ {% for entry in entries %}
+ {% set timeWorked = timeWorked + entry.duration %}
+
+ {{ entry.begin|date_short }}
+ {% if showUserColumn %}
+ {{ entry.user.displayName }}
{% endif %}
-
+
+ {% if entry.description is not empty %}
+
+ {{ entry.description|desc2html }}
+
+ {% endif %}
+
{% if entry.activity is not null %}{{ 'activity'|trans }}: {{ entry.activity.name }} |{% endif %}
- {{ 'project'|trans }}: {{ entry.project.name }} |
+ {{ 'project'|trans }}: {{ entry.project.name }} |
{{ 'customer'|trans }}: {{ entry.project.customer.name }}
-
- {% for field in timesheetMetaFields %}
- {{ tables.datatable_meta_column(entry, field) }}
- {% endfor %}
- {{ entry.duration|duration(decimal) }}
-
- {% endfor %}
-
-
-
-
- {% if showUserColumn %}
-
- {% endif %}
- {% for field in timesheetMetaFields %}
-
+
+ {% for field in timesheetMetaFields %}
+ {{ tables.datatable_meta_column(entry, field) }}
+ {% endfor %}
+ {{ entry.duration|duration(decimal) }}
+
{% endfor %}
- {{ 'invoice.total_working_time'|trans }}
- {{ timeWorked|duration(decimal) }}
-
-
-
+
+
+
+
+ {% if showUserColumn %}
+
+ {% endif %}
+ {% for field in timesheetMetaFields %}
+
+ {% endfor %}
+ {{ 'invoice.total_working_time'|trans }}
+ {{ timeWorked|duration(decimal) }}
+
+
+
+
-
-{% endblock %}
-
-{% block print_button %}{% endblock %}
\ No newline at end of file
+
+
+
+
diff --git a/tests/Invoice/templates/default.pdf.twig b/tests/Invoice/templates/default.pdf.twig
index 93b8b4c3..99fffdfe 100644
--- a/tests/Invoice/templates/default.pdf.twig
+++ b/tests/Invoice/templates/default.pdf.twig
@@ -1,147 +1,157 @@
-{% extends 'invoice/layout.html.twig' %}
-{% set language = model.template.language|default(app.request.locale) %}
-{% set isDecimal = model.template.decimalDuration|default(false) %}
+
+{% set fallback = app.request is not null ? app.request.locale : 'en' %}
+{% set language = model.template.language|default(fallback) %}
{% set currency = model.currency %}
-
-{% block invoice %}
-
-
-
-
- {{ 'invoice.from'|trans({}, 'messages', language) }}
-
- {{ model.template.company }}
- {{ model.template.address|trim|nl2br }}
- {% if model.template.vatId is not empty %}
-
- {{ 'vat_id'|trans({}, 'messages', language) }}:
- {{ model.template.vatId }}
- {% endif %}
-
-
-
-
- {{ 'invoice.to'|trans({}, 'messages', language) }}
-
- {{ model.customer.company|default(model.customer.name) }}
- {{ model.customer.address|nl2br }}
- {% if model.customer.vatId is not empty %}
-
- {{ 'vat_id'|trans({}, 'messages', language) }}: {{ model.customer.vatId }}
- {% endif %}
- {% if model.customer.number is not empty %}
-
- {{ 'number'|trans({}, 'messages', language) }}: {{ model.customer.number }}
- {% endif %}
- {% if model.query.project is not empty and model.query.project.orderNumber is not empty %}
-
- {{ 'orderNumber'|trans({}, 'messages', language) }}: {{ model.query.project.orderNumber }}
- {% endif %}
-
-
-
-
-
-
-
- {{ 'invoice.number'|trans({}, 'messages', language) }}:
- {{ model.invoiceNumber }}
-
-
- {{ 'invoice.due_days'|trans({}, 'messages', language) }}:
- {{ model.dueDate|date_short }}
-
-
-
-
-
-
-
-
-
-
- {{ 'date'|trans({}, 'messages', language) }}
- {{ 'description'|trans({}, 'messages', language) }}
- {{ 'unit_price'|trans({}, 'messages', language) }}
- {{ 'amount'|trans({}, 'messages', language) }}
- {{ 'total_rate'|trans({}, 'messages', language) }}
-
-
-
- {% for entry in model.calculator.entries %}
- {% set duration = entry.duration|duration(isDecimal) %}
- {% if entry.fixedRate %}
- {% set rate = entry.fixedRate %}
- {% set duration = entry.amount|amount %}
- {% else %}
- {% set rate = entry.hourlyRate %}
- {% endif %}
-
- {{ entry.begin|date_short }}
-
- {% if entry.description is not empty %}
- {{ entry.description|nl2br }}
- {% else %}
- {% if entry.activity is not null %}{{ entry.activity.name }} / {% endif %}{{ entry.project.name }}
- {% endif %}
-
- {{ rate|money(currency) }}
- {{ duration }}
- {{ entry.rate|money(currency) }}
-
- {% endfor %}
-
-
-
-
- {{ 'invoice.subtotal'|trans({}, 'messages', language) }}
-
- {{ model.calculator.subtotal|money(currency) }}
-
-
-
- {{ 'invoice.tax'|trans({}, 'messages', language) }} ({{ model.calculator.vat }}%)
-
- {{ model.calculator.tax|money(currency) }}
-
-
-
- {{ 'invoice.total'|trans({}, 'messages', language) }}
-
-
- {{ model.calculator.total|money(currency) }}
-
-
-
-
-
-
-
-
-
- {% if model.template.paymentTerms is not empty %}
-
- {{ model.template.paymentTerms|nl2br|md2html }}
+
+
+
+
+
+
+
+
+
+
+ {{ 'invoice.from'|trans({}, 'messages', language) }}
+
+ {{ model.template.company }}
+ {{ model.template.address|trim|nl2br }}
+ {% if model.template.vatId is not empty %}
+
+ {{ 'vat_id'|trans({}, 'messages', language) }}:
+ {{ model.template.vatId }}
+ {% endif %}
+
+
+
+
+ {{ 'invoice.to'|trans({}, 'messages', language) }}
+
+ {{ model.customer.company|default(model.customer.name) }}
+ {{ model.customer.address|nl2br }}
+ {% if model.customer.vatId is not empty %}
+
+ {{ 'vat_id'|trans({}, 'messages', language) }}: {{ model.customer.vatId }}
+ {% endif %}
+ {% if model.customer.number is not empty %}
+
+ {{ 'number'|trans({}, 'messages', language) }}: {{ model.customer.number }}
+ {% endif %}
+ {% if model.query.project is not empty and model.query.project.orderNumber is not empty %}
+
+ {{ 'orderNumber'|trans({}, 'messages', language) }}: {{ model.query.project.orderNumber }}
+ {% endif %}
+
+
+
+
+
+
+
+ {{ 'invoice.number'|trans({}, 'messages', language) }}:
+ {{ model.invoiceNumber }}
+
+
+ {{ 'invoice.due_days'|trans({}, 'messages', language) }}:
+ {{ model.dueDate|date_short }}
+
+
+
+
+
+
+
+
+
+
+ {{ 'date'|trans({}, 'messages', language) }}
+ {{ 'description'|trans({}, 'messages', language) }}
+ {{ 'unit_price'|trans({}, 'messages', language) }}
+ {{ 'amount'|trans({}, 'messages', language) }}
+ {{ 'total_rate'|trans({}, 'messages', language) }}
+
+
+
+ {% for entry in model.calculator.entries %}
+ {% set duration = entry.duration|duration(true) %}
+ {% if entry.fixedRate %}
+ {% set rate = entry.fixedRate %}
+ {% set duration = entry.amount|amount %}
+ {% else %}
+ {% set rate = entry.hourlyRate %}
+ {% endif %}
+
+ {{ entry.begin|date_short }}
+
+ {% if entry.description is not empty %}
+ {{ entry.description|nl2br }}
+ {% else %}
+ {% if entry.activity is not null %}{{ entry.activity.name }} / {% endif %}{{ entry.project.name }}
+ {% endif %}
+
+ {{ rate|money(currency) }}
+ {{ duration }}
+ {{ entry.rate|money(currency) }}
+
+ {% endfor %}
+
+
+
+
+ {{ 'invoice.subtotal'|trans({}, 'messages', language) }}
+
+ {{ model.calculator.subtotal|money(currency) }}
+
+
+
+ {{ 'invoice.tax'|trans({}, 'messages', language) }} ({{ model.calculator.vat }}%)
+
+ {{ model.calculator.tax|money(currency) }}
+
+
+
+ {{ 'invoice.total'|trans({}, 'messages', language) }}
+
+
+ {{ model.calculator.total|money(currency) }}
+
+
+
+
+
+
+
+
+
+ {% if model.template.paymentTerms is not empty %}
+
+ {{ model.template.paymentTerms|nl2br|md2html }}
+
+ {% endif %}
+
+
+
+
+
-
-
-
-{% endblock %}
\ No newline at end of file
+
+
diff --git a/translations/invoice-renderer.ar.xlf b/translations/invoice-renderer.ar.xlf
index dec65c88..e45fd025 100644
--- a/translations/invoice-renderer.ar.xlf
+++ b/translations/invoice-renderer.ar.xlf
@@ -18,10 +18,6 @@
service-date
مستقل
-
- Html
- HTML (للطباعة عبر المتصفح)
-
default
فاتورة
diff --git a/translations/invoice-renderer.cs.xlf b/translations/invoice-renderer.cs.xlf
index d651e09b..d1b0577d 100644
--- a/translations/invoice-renderer.cs.xlf
+++ b/translations/invoice-renderer.cs.xlf
@@ -26,10 +26,6 @@
programmatic
K dalšímu zpracování
-
- Html
- HTMP (pro tisk pomocí prohlížeče)
-
default
Faktura
diff --git a/translations/invoice-renderer.de.xlf b/translations/invoice-renderer.de.xlf
index 4c442dd9..cc9f0871 100644
--- a/translations/invoice-renderer.de.xlf
+++ b/translations/invoice-renderer.de.xlf
@@ -19,10 +19,6 @@
programmatic
Zur Weiterverarbeitung
-
- Html
- HTML (zum Drucken via Browser)
-
invoice
diff --git a/translations/invoice-renderer.el.xlf b/translations/invoice-renderer.el.xlf
index 611057a1..e05e2419 100644
--- a/translations/invoice-renderer.el.xlf
+++ b/translations/invoice-renderer.el.xlf
@@ -15,10 +15,6 @@
programmatic
Για περαιτέρω επεξεργασία
-
- Html
- HTML (για εκτύπωση μέσω προγράμματος περιήγησης)
-
invoice
diff --git a/translations/invoice-renderer.en.xlf b/translations/invoice-renderer.en.xlf
index d6365806..255c4dba 100644
--- a/translations/invoice-renderer.en.xlf
+++ b/translations/invoice-renderer.en.xlf
@@ -19,10 +19,6 @@
programmatic
For further processing
-
- Html
- HTML (for printing via Browser)
-
invoice
diff --git a/translations/invoice-renderer.es.xlf b/translations/invoice-renderer.es.xlf
index c8ee51eb..d036f647 100644
--- a/translations/invoice-renderer.es.xlf
+++ b/translations/invoice-renderer.es.xlf
@@ -26,10 +26,6 @@
programmatic
Para su procesamiento posterior
-
- Html
- HTML (impresión por Navegador)
-
default
Factura
diff --git a/translations/invoice-renderer.fa.xlf b/translations/invoice-renderer.fa.xlf
index fc4df4fd..d899fb26 100644
--- a/translations/invoice-renderer.fa.xlf
+++ b/translations/invoice-renderer.fa.xlf
@@ -15,10 +15,6 @@
programmatic
برای پردازش بیشتر
-
- Html
- HTML (برای چاپ از طریق مرورگر)
-
invoice
diff --git a/translations/invoice-renderer.fi.xlf b/translations/invoice-renderer.fi.xlf
index cca6896f..d1212fd2 100644
--- a/translations/invoice-renderer.fi.xlf
+++ b/translations/invoice-renderer.fi.xlf
@@ -15,10 +15,6 @@
programmatic
Jatko käsittelyä varten
-
- Html
- HTML (tulostukseen selaimen kautta)
-
invoice
diff --git a/translations/invoice-renderer.fr.xlf b/translations/invoice-renderer.fr.xlf
index 8a7a06db..e992add3 100644
--- a/translations/invoice-renderer.fr.xlf
+++ b/translations/invoice-renderer.fr.xlf
@@ -18,10 +18,6 @@
service-date
Freelancer
-
- Html
- HTML (pour l'impression via le navigateur)
-
help.upload
Attention : les fichiers existants seront écrasés. Les types de fichiers autorisés sont : %extensions%.
diff --git a/translations/invoice-renderer.he.xlf b/translations/invoice-renderer.he.xlf
index 921ddf66..b337bb71 100644
--- a/translations/invoice-renderer.he.xlf
+++ b/translations/invoice-renderer.he.xlf
@@ -26,10 +26,6 @@
programmatic
לעיבוד נוסף
-
- Html
- HTML (להדפסה דרך הדפדפן)
-
default
חשבונית
diff --git a/translations/invoice-renderer.hr.xlf b/translations/invoice-renderer.hr.xlf
index 7ec5f10d..b0096cba 100644
--- a/translations/invoice-renderer.hr.xlf
+++ b/translations/invoice-renderer.hr.xlf
@@ -15,10 +15,6 @@
programmatic
Za daljnju obradu
-
- Html
- HTML (za ispis putem preglednika)
-
invoice
diff --git a/translations/invoice-renderer.hu.xlf b/translations/invoice-renderer.hu.xlf
index 62a3179e..ff1ae751 100644
--- a/translations/invoice-renderer.hu.xlf
+++ b/translations/invoice-renderer.hu.xlf
@@ -26,10 +26,6 @@
programmatic
További feldolgozáshoz
-
- Html
- HTML (böngészőn keresztüli nyomtatáshoz)
-
default
Számla
diff --git a/translations/invoice-renderer.ko.xlf b/translations/invoice-renderer.ko.xlf
index 88ab9831..1dfe7c08 100644
--- a/translations/invoice-renderer.ko.xlf
+++ b/translations/invoice-renderer.ko.xlf
@@ -22,10 +22,6 @@
help.upload
주의: 기존 파일을 덮어씁니다. 허용되는 파일 형식은 %extensions%입니다.
-
- Html
- HTML (브라우저를 통한 인쇄용)
-
text
텍스트
diff --git a/translations/invoice-renderer.nb_NO.xlf b/translations/invoice-renderer.nb_NO.xlf
index b6b95801..486de350 100644
--- a/translations/invoice-renderer.nb_NO.xlf
+++ b/translations/invoice-renderer.nb_NO.xlf
@@ -15,10 +15,6 @@
programmatic
For videre behandling
-
- Html
- HTML (for utskrift via nettleser)
-
invoice
diff --git a/translations/invoice-renderer.nl.xlf b/translations/invoice-renderer.nl.xlf
index cbd7ef64..b2ada47c 100644
--- a/translations/invoice-renderer.nl.xlf
+++ b/translations/invoice-renderer.nl.xlf
@@ -15,10 +15,6 @@
programmatic
Voor verdere verwerking
-
- Html
- HTML (voor afdrukken via de Browser)
-
invoice
diff --git a/translations/invoice-renderer.pl.xlf b/translations/invoice-renderer.pl.xlf
index 850ad6b6..3d0bb99c 100644
--- a/translations/invoice-renderer.pl.xlf
+++ b/translations/invoice-renderer.pl.xlf
@@ -26,10 +26,6 @@
programmatic
Do dalszego przetwarzania
-
- Html
- HTML (do wydruku przez przeglądarkę)
-
default
Faktura
diff --git a/translations/invoice-renderer.pt.xlf b/translations/invoice-renderer.pt.xlf
index 44e78bd2..dd06c4f7 100644
--- a/translations/invoice-renderer.pt.xlf
+++ b/translations/invoice-renderer.pt.xlf
@@ -15,10 +15,6 @@
programmatic
Para processamento posterior
-
- Html
- HTML (para impressão via navegador web)
-
invoice
diff --git a/translations/invoice-renderer.pt_BR.xlf b/translations/invoice-renderer.pt_BR.xlf
index ff02e3b0..e26bcb28 100644
--- a/translations/invoice-renderer.pt_BR.xlf
+++ b/translations/invoice-renderer.pt_BR.xlf
@@ -22,10 +22,6 @@
help.upload
Atenção: os arquivos já existentes serão substituídos. Os tipos dos arquivos permitidos são: %extensions%.
-
- Html
- HTML (para impressão via navegador)
-
programmatic
Para processamento posterior
diff --git a/translations/invoice-renderer.ro.xlf b/translations/invoice-renderer.ro.xlf
index f0c0393b..e5be994d 100644
--- a/translations/invoice-renderer.ro.xlf
+++ b/translations/invoice-renderer.ro.xlf
@@ -26,10 +26,6 @@
programmatic
Pentru prelucrare ulterioară
-
- Html
- HTML (pentru imprimare prin browser)
-
default
Factură
diff --git a/translations/invoice-renderer.sv.xlf b/translations/invoice-renderer.sv.xlf
index 7744f233..8e895dc7 100644
--- a/translations/invoice-renderer.sv.xlf
+++ b/translations/invoice-renderer.sv.xlf
@@ -26,10 +26,6 @@
programmatic
För ytterligare bearbetning
-
- Html
- HTML (för utskrift från webbläsare)
-
default
Faktura
diff --git a/translations/invoice-renderer.tr.xlf b/translations/invoice-renderer.tr.xlf
index 6964110a..d11c3420 100644
--- a/translations/invoice-renderer.tr.xlf
+++ b/translations/invoice-renderer.tr.xlf
@@ -30,10 +30,6 @@
help.upload
Dikkat: mevcut dosyaların üzerine yazılacaktır. İzin verilen dosya türleri: %extensions%.
-
- Html
- HTML (Tarayıcı ile yazdırmak için)
-
text
Metin
diff --git a/translations/invoice-renderer.uk.xlf b/translations/invoice-renderer.uk.xlf
index d0efb766..1b0ca981 100644
--- a/translations/invoice-renderer.uk.xlf
+++ b/translations/invoice-renderer.uk.xlf
@@ -15,10 +15,6 @@
programmatic
Для подальшої обробки
-
- Html
- HTML (для друку через браузер)
-
invoice
diff --git a/translations/invoice-renderer.vi.xlf b/translations/invoice-renderer.vi.xlf
index cdd56f96..1d09bb3d 100644
--- a/translations/invoice-renderer.vi.xlf
+++ b/translations/invoice-renderer.vi.xlf
@@ -26,10 +26,6 @@
programmatic
Để xử lý thêm
-
- Html
- HTML (Để in qua Trình duyệt)
-
default
Hóa đơn
diff --git a/translations/invoice-renderer.zh_CN.xlf b/translations/invoice-renderer.zh_CN.xlf
index 9cd5260a..a7da5f81 100644
--- a/translations/invoice-renderer.zh_CN.xlf
+++ b/translations/invoice-renderer.zh_CN.xlf
@@ -18,10 +18,6 @@
service-date
兼职人员
-
- Html
- HTML(用于通过浏览器打印)
-
default
发票
diff --git a/translations/tasks.ar.xlf b/translations/tasks.ar.xlf
index 3685db50..556e8027 100644
--- a/translations/tasks.ar.xlf
+++ b/translations/tasks.ar.xlf
@@ -58,10 +58,6 @@
tasks.my
مهامي
-
- task.delete
- هل تريد حذف المهمة؟ لن يتم حذف سجلات الوقت!
-
task.help.end
يجب إنجاز المهمة إلى غاية هذا التاريخ
diff --git a/translations/tasks.cs.xlf b/translations/tasks.cs.xlf
index e9916164..a03c81eb 100644
--- a/translations/tasks.cs.xlf
+++ b/translations/tasks.cs.xlf
@@ -94,10 +94,6 @@
tasks.pending
Nevyřízené úkoly
-
- task.delete
- Smazat úkol? Časové záznamy nebudou smazány!
-
task.help.user
Přiřaďte tuto úlohu uživateli
diff --git a/translations/tasks.de.xlf b/translations/tasks.de.xlf
index d86b2047..370f518a 100644
--- a/translations/tasks.de.xlf
+++ b/translations/tasks.de.xlf
@@ -53,10 +53,6 @@
tasks.my
Meine Aufgaben
-
- task.delete
- Aufgabe löschen? Aufgezeichnete Zeiten werden nicht gelöscht!
-
task.help.title
Eine kurze Beschreibung der Aufgabe
diff --git a/translations/tasks.en.xlf b/translations/tasks.en.xlf
index a62e3562..cbc67a91 100644
--- a/translations/tasks.en.xlf
+++ b/translations/tasks.en.xlf
@@ -53,10 +53,6 @@
tasks.my
My tasks
-
- task.delete
- Delete task? Time records will not be deleted!
-
task.help.title
A short description of the task
diff --git a/translations/tasks.es.xlf b/translations/tasks.es.xlf
index da59b2c7..22243ebd 100644
--- a/translations/tasks.es.xlf
+++ b/translations/tasks.es.xlf
@@ -78,10 +78,6 @@
task.help.title
Una breve descripción de la tarea
-
- task.delete
- ¿Eliminar tarea? ¡Los registros de tiempo no se borrarán!
-
task.help.user
Asignar esta tarea a un usuario
diff --git a/translations/tasks.fi.xlf b/translations/tasks.fi.xlf
index 3ed72a16..247b92e1 100644
--- a/translations/tasks.fi.xlf
+++ b/translations/tasks.fi.xlf
@@ -53,10 +53,6 @@
tasks.my
Tehtäväni
-
- task.delete
- Poista tehtävä? Työaikoja ei poisteta!
-
task.help.title
Lyhyt kuvaus tehtävälle
diff --git a/translations/tasks.fr.xlf b/translations/tasks.fr.xlf
index a13cc00b..f8bb0218 100644
--- a/translations/tasks.fr.xlf
+++ b/translations/tasks.fr.xlf
@@ -53,10 +53,6 @@
tasks.my
Mes tâches
-
- task.delete
- Effacer la tâche? Les temps assignés ne seront pas supprimés!
-
task.help.title
Une description courte de la tâche
diff --git a/translations/tasks.he.xlf b/translations/tasks.he.xlf
index 1bd65c0a..3f6892d0 100644
--- a/translations/tasks.he.xlf
+++ b/translations/tasks.he.xlf
@@ -53,10 +53,6 @@
tasks.my
המשימות שלי
-
- task.delete
- למחוק משימה? רשומות השעות לא תימחקנה!
-
task.help.title
תיאור קצר של המשימה
diff --git a/translations/tasks.nb_NO.xlf b/translations/tasks.nb_NO.xlf
index 04f577af..edd1b3f7 100644
--- a/translations/tasks.nb_NO.xlf
+++ b/translations/tasks.nb_NO.xlf
@@ -50,10 +50,6 @@
task.assign
Tildel til meg
-
- task.delete
- Slett gjøremål? Tidssedelene vil ikke bli slettet.
-
task.help.end
Gjøremålet må utføres før denne datoen
diff --git a/translations/tasks.pt_BR.xlf b/translations/tasks.pt_BR.xlf
index ae51129d..de9f62ea 100644
--- a/translations/tasks.pt_BR.xlf
+++ b/translations/tasks.pt_BR.xlf
@@ -73,10 +73,6 @@
task.widget_rows
Quantidade de tarefas por página na ferramenta do painel
-
- task.delete
- Excluir a tarefa? Os registros de tempo não serão apagados!
-
task.help.estimation
Tempo necessário estimado para completar a tarefa em hh:mm
diff --git a/translations/tasks.tr.xlf b/translations/tasks.tr.xlf
index 7235cd13..1322901c 100644
--- a/translations/tasks.tr.xlf
+++ b/translations/tasks.tr.xlf
@@ -18,10 +18,6 @@
task.stop
İşlemeyi duraklat
-
- task.delete
- Görev silinsin mi? Zaman kayıtları silinmeyecektir!
-
Tasks
Görevler