added invoice archive & configurable invoice numbers (#1541)

This commit is contained in:
Kevin Papst
2020-03-14 01:16:58 +01:00
committed by GitHub
parent dd64eb98f9
commit e6e6a1eeea
106 changed files with 2587 additions and 339 deletions

View File

@@ -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 %}

View File

@@ -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 %}

View 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 %}

View 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 %}

View File

@@ -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 %}