added invoice archive & configurable invoice numbers (#1541)
This commit is contained in:
@@ -4,10 +4,18 @@
|
||||
|
||||
{% set actions = {'visibility': '#modal_invoice'} %}
|
||||
|
||||
{% if is_granted('history_invoice') %}
|
||||
{% set actions = actions|merge({'list': path('admin_invoice_list')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('manage_invoice_template') %}
|
||||
{% set actions = actions|merge({'invoice-template': path('admin_invoice_template')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('system_configuration') %}
|
||||
{% set actions = actions|merge({'settings': {'url': path('system_configuration_section', {'section': 'invoice'}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'invoices.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.invoices', {'actions': actions, 'view': view}) %}
|
||||
@@ -37,6 +45,46 @@
|
||||
{{ widgets.page_actions(actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro invoice(invoice) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if is_granted('history_invoice') %}
|
||||
{% if invoice.new %}
|
||||
{% set actions = actions|merge({'invoice.pending': path('admin_invoice_status', {'id': invoice.id, 'status': 'pending'})}) %}
|
||||
{% elseif invoice.pending %}
|
||||
{% 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'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.invoice', {'actions': actions, 'invoice': invoice}) %}
|
||||
{{ widgets.table_actions(actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro invoice_listing(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if is_granted('view_invoice') %}
|
||||
{% set actions = actions|merge({'back': path('invoice')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'visibility': '#modal_invoices'}) %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'invoices.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.invoice_details', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro invoice_upload(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
|
||||
@@ -5,20 +5,19 @@
|
||||
{% import "invoice/actions.html.twig" as actions %}
|
||||
|
||||
{% set columns = {
|
||||
'date': 'alwaysVisible',
|
||||
'user': 'hidden-xs hidden-sm',
|
||||
'project': 'hidden-xs hidden-sm',
|
||||
'description': 'hidden-xs hidden-sm',
|
||||
'unit_price': 'hidden-xs text-center',
|
||||
'amount': 'text-center',
|
||||
'duration': 'hidden-xs text-center',
|
||||
'total_rate': 'text-right alwaysVisible',
|
||||
'date': {'class': 'alwaysVisible', 'orderBy': false},
|
||||
'user': {'class': 'hidden-xs hidden-sm', 'orderBy': false},
|
||||
'project': {'class': 'hidden-xs hidden-sm', 'orderBy': false},
|
||||
'description': {'class': 'hidden-xs hidden-sm', 'orderBy': false},
|
||||
'unit_price': {'class': 'hidden-xs text-center', 'orderBy': false},
|
||||
'amount': {'class': 'text-center', 'orderBy': false},
|
||||
'duration': {'class': 'hidden-xs text-center', 'orderBy': false},
|
||||
'total_rate': {'class': 'text-right alwaysVisible', 'orderBy': false},
|
||||
} %}
|
||||
|
||||
{% set tableName = 'invoice' %}
|
||||
|
||||
{% block page_title %}{{ 'invoice.title'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'invoice.subtitle'|trans }}{% endblock %}
|
||||
{% block page_actions %}{{ actions.invoices('index') }}{% endblock %}
|
||||
|
||||
{% block main_before %}
|
||||
@@ -34,21 +33,34 @@
|
||||
{% block box_before %}{{ form_start(form) }}{% endblock %}
|
||||
{% block box_body %}
|
||||
{{ form_errors(form) }}
|
||||
{{ form_row(form.searchTerm) }}
|
||||
{% if form.searchTerm is defined %}
|
||||
{{ form_row(form.searchTerm) }}
|
||||
{% endif %}
|
||||
{{ form_row(form.daterange) }}
|
||||
{{ form_row(form.customer) }}
|
||||
{{ form_row(form.project) }}
|
||||
{{ form_row(form.activity) }}
|
||||
{% if form.activity is defined %}
|
||||
{{ form_row(form.activity) }}
|
||||
{% endif %}
|
||||
{% if form.users is defined %}
|
||||
{{ form_row(form.users) }}
|
||||
{% endif %}
|
||||
{{ form_row(form.tags) }}
|
||||
{{ form_row(form.exported) }}
|
||||
{% if form.tags is defined %}
|
||||
{{ form_row(form.tags) }}
|
||||
{% endif %}
|
||||
{% if form.exported is defined %}
|
||||
{{ form_row(form.exported) }}
|
||||
{% endif %}
|
||||
{{ form_row(form.template) }}
|
||||
{{ form_row(form.markAsExported) }}
|
||||
{% endblock %}
|
||||
{% block box_footer%}
|
||||
{{ form_widget(form.create, {'attr': {'class': 'btn btn-success'}}) }}
|
||||
{% set createAttr = {'class': 'btn btn-success'} %}
|
||||
{% if not is_granted('history_invoice') %}
|
||||
{% set createAttr = createAttr|merge({'formtarget': '_blank'}) %}
|
||||
{% endif %}
|
||||
{{ form_widget(form.create, {'attr': createAttr}) }}
|
||||
{{ form_widget(form.print) }}
|
||||
{{ form_widget(form.preview) }}
|
||||
{% endblock %}
|
||||
{% block box_after %}{{ form_end(form) }}{% endblock %}
|
||||
@@ -96,8 +108,26 @@
|
||||
<td class="text-right text-nowrap">{{ entry.rate|money(model.calculator.currency) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="{{ tables.data_table_column_class(tableName, columns, 'user') }}"></th>
|
||||
<th class="{{ tables.data_table_column_class(tableName, columns, 'project') }}"></th>
|
||||
<th class="{{ tables.data_table_column_class(tableName, columns, 'description') }}"></th>
|
||||
<th class="{{ tables.data_table_column_class(tableName, columns, 'unit_price') }}"></th>
|
||||
<th class="{{ tables.data_table_column_class(tableName, columns, 'amount') }}"></th>
|
||||
<th class="{{ tables.data_table_column_class(tableName, columns, 'duration') }} text-center text-nowrap">{{ model.calculator.timeWorked|duration(isDecimal) }}</th>
|
||||
<th class="text-right text-nowrap">{{ model.calculator.total|money(model.calculator.currency) }}</th>
|
||||
</tr>
|
||||
{{ tables.data_table_footer(entries) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{{ parent() }}
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('kimai.initialized', function() {
|
||||
KimaiReloadPageWidget.create('kimai.systemConfigUpdate', true);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
62
templates/invoice/listing.html.twig
Normal file
62
templates/invoice/listing.html.twig
Normal file
@@ -0,0 +1,62 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% import "macros/toolbar.html.twig" as toolbar %}
|
||||
{% import "macros/datatables.html.twig" as tables %}
|
||||
{% import "invoice/actions.html.twig" as actions %}
|
||||
{% import "invoice/macros.html.twig" as macros %}
|
||||
|
||||
{% set columns = {
|
||||
'date': {'class': 'alwaysVisible text-nowrap', 'orderBy': false},
|
||||
'user': {'class': 'hidden-xs hidden-sm text-nowrap hidden', 'orderBy': false},
|
||||
'customer': {'class': 'hidden-xs hidden-sm text-nowrap', 'orderBy': false},
|
||||
'invoice_number': {'class': 'hidden-xs hidden-sm text-nowrap', 'title': 'invoice.number'|trans, 'orderBy': false},
|
||||
'due_date': {'class': 'hidden-xs text-nowrap', 'title': 'invoice.due_days'|trans, 'orderBy': false},
|
||||
'status': {'class': 'text-center alwaysVisible text-nowrap', 'orderBy': false},
|
||||
'tax': {'class': 'hidden-xs text-center text-nowrap hidden', 'title': 'invoice.tax'|trans, 'orderBy': false},
|
||||
'total_rate': {'class': 'hidden-xs text-center text-nowrap', 'orderBy': false},
|
||||
'actions': {'class': 'actions alwaysVisible', 'orderBy': false},
|
||||
} %}
|
||||
|
||||
{% set tableName = 'invoices' %}
|
||||
|
||||
{% block page_title %}{{ 'invoice.title'|trans }}{% endblock %}
|
||||
{% block page_actions %}{{ actions.invoice_listing('index') }}{% endblock %}
|
||||
|
||||
{% block main_before %}
|
||||
{{ tables.data_table_column_modal(tableName, columns) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
{% if entries is empty %}
|
||||
{{ widgets.callout('warning', 'error.no_entries_found') }}
|
||||
{% else %}
|
||||
{{ tables.datatable_header(tableName, columns, query, {}) }}
|
||||
{% for entry in entries %}
|
||||
<tr>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'date') }}">{{ entry.createdAt|date_short }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'user') }}">{{ widgets.user_avatar(entry.user) }} {{ widgets.username(entry.user) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'customer') }}">{{ widgets.label_customer(entry.customer) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'invoice_number') }}">{{ widgets.label(entry.invoiceNumber, 'default') }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'due_date') }}">{{ macros.invoice_due_date(entry) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'status') }}">{{ macros.invoice_status(entry) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'tax') }}">{{ entry.tax|money(entry.currency) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'total_rate') }}">{{ entry.total|money(entry.currency) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'actions') }}">{{ actions.invoice(entry) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{{ tables.data_table_footer(entries, 'admin_invoice_list') }}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{{ parent() }}
|
||||
{% if download is not null %}
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('kimai.initialized', function() {
|
||||
location.href = '{{ path('admin_invoice_download', {'id': download.id}) }}';
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
25
templates/invoice/macros.html.twig
Normal file
25
templates/invoice/macros.html.twig
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
{% macro invoice_status(invoice) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set overdue = invoice.overdue %}
|
||||
{% if invoice.new and overdue %}
|
||||
{{ widgets.label('status.new'|trans, 'danger') }}
|
||||
{% elseif invoice.new %}
|
||||
{{ widgets.label('status.new'|trans, 'primary') }}
|
||||
{% elseif invoice.pending and overdue %}
|
||||
{{ widgets.label('status.pending'|trans, 'danger') }}
|
||||
{% elseif invoice.pending %}
|
||||
{{ widgets.label('status.pending'|trans, 'warning') }}
|
||||
{% elseif invoice.paid %}
|
||||
{{ widgets.label('status.paid'|trans, 'success') }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro invoice_due_date(invoice) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% if invoice.overdue and not invoice.paid %}
|
||||
{{ widgets.label(invoice.dueDate|date_short, 'danger') }}
|
||||
{% else %}
|
||||
{{ widgets.label(invoice.dueDate|date_short, 'primary') }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
@@ -62,6 +62,11 @@
|
||||
{{ form_row(form.numberGenerator) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ form_row(form.decimalDuration) }}
|
||||
</div>
|
||||
</div>
|
||||
{{ form_widget(form) }}
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
|
||||
Reference in New Issue
Block a user