improved invoices with new renderer (#306)
* added docx renderer and demo template * added csv renderer and demo template * added xlsx renderer and demo template * added ods renderer and demo template * added user calculator * added invoice documentation
This commit is contained in:
@@ -18,10 +18,33 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
{% if model.entries is empty or action is empty %}
|
||||
{% if model.entries is empty %}
|
||||
{{ widgets.callout('warning', 'invoice.select_filter') }}
|
||||
{% else %}
|
||||
{{ render(controller(action, {'model': model, 'appRequest': app.request})) }}
|
||||
|
||||
{{ include('invoice/preview.html.twig') }}
|
||||
|
||||
<div class="row no-print">
|
||||
<div class="col-xs-12">
|
||||
<button type="button" id="print-invoice-button" class="btn btn-success pull-right">
|
||||
<i class="{{ 'print'|icon }}"></i> {{ 'button.print'|trans }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$( "#print-invoice-button" ).click(function() {
|
||||
var prevAction = $( "#invoice-print-form" ).attr('action');
|
||||
$( "#invoice-print-form" ).attr('target', '_blank').attr('action', '{{ path('invoice_print') }}');
|
||||
$( "#invoice-print-form" ).submit();
|
||||
$( "#invoice-print-form" ).removeAttr('target').attr('action', prevAction);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
26
templates/invoice/layout.html.twig
Normal file
26
templates/invoice/layout.html.twig
Normal file
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ app.request.locale }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<link rel="stylesheet" href="{{ asset('build/app.css') }}">
|
||||
<script src="{{ asset('build/app.js') }}"></script>
|
||||
</head>
|
||||
<body class="invoice_print">
|
||||
<div class="wrapper">
|
||||
<section class="invoice">
|
||||
{% block invoice %}{% endblock %}
|
||||
</section>
|
||||
{% block print_button %}
|
||||
<div class="row no-print">
|
||||
<div class="col-xs-12">
|
||||
<button type="button" class="btn btn-success pull-right" onclick="window.print();return false;">
|
||||
<i class="{{ 'print'|icon }}"></i> {{ 'button.print'|trans }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
52
templates/invoice/preview.html.twig
Normal file
52
templates/invoice/preview.html.twig
Normal file
@@ -0,0 +1,52 @@
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{{ widgets.callout('success', 'invoice.preview') }}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'label.date'|trans }}</th>
|
||||
<th class="hidden-xs hidden-sm">{{ 'label.user'|trans }}</th>
|
||||
<th class="hidden-xs hidden-sm">{{ 'label.activity'|trans }}</th>
|
||||
<th class="text-center">{{ 'invoice.unit_price'|trans }}</th>
|
||||
<th class="text-center">{{ 'invoice.amount'|trans }}</th>
|
||||
<th class="text-right">{{ 'invoice.total_rate'|trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in model.calculator.entries %}
|
||||
{% set duration = entry.duration|duration() %}
|
||||
{% if entry.fixedRate is not null %}
|
||||
{% set rate = entry.fixedRate %}
|
||||
{% set duration = 1 %}
|
||||
{% elseif entry.hourlyRate is not null %}
|
||||
{% set rate = entry.hourlyRate %}
|
||||
{% else %}
|
||||
{% set rate = app.user.getPreferenceValue('hourly_rate') %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>{{ entry.begin|date_short }}</td>
|
||||
<td class="hidden-xs hidden-sm">{{ widgets.username(entry.user) }}</td>
|
||||
<td class="hidden-xs hidden-sm timesheet-description">
|
||||
{% if entry.description is not empty %}
|
||||
{{ entry.description|desc2html }}
|
||||
{% else %}
|
||||
{{ entry.activity.name }} / {{ entry.activity.project.name }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center" contenteditable="true">
|
||||
{{ rate|money(model.calculator.currency) }}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{{ duration }}
|
||||
</td>
|
||||
<td class="text-right">{{ entry.rate|money(model.calculator.currency) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
BIN
templates/invoice/renderer/company.docx
Normal file
BIN
templates/invoice/renderer/company.docx
Normal file
Binary file not shown.
@@ -1,3 +1,6 @@
|
||||
{% extends 'invoice/layout.html.twig' %}
|
||||
|
||||
{% block invoice %}
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h2 class="page-header">
|
||||
@@ -108,11 +111,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row no-print">
|
||||
<div class="col-xs-12">
|
||||
<button type="button" class="btn btn-success pull-right" onclick="window.print();return false;">
|
||||
<i class="{{ 'print'|icon }}"></i> {{ 'button.print'|trans }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
2
templates/invoice/renderer/export.csv
Normal file
2
templates/invoice/renderer/export.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
start_date,start_timestamp,end_date,end_timestamp,duration,username,description,rate,amount,total
|
||||
${entry.begin},${entry.begin_timestamp},${entry.end},${entry.end_timestamp},${entry.duration},${entry.user_name},${entry.description},${entry.rate},${entry.amount},${entry.total}
|
||||
|
@@ -1,5 +1,10 @@
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{# You can overrwite these settings in your config/packages.local.yaml under the key "twig.globals.company" #}
|
||||
|
||||
{% extends 'invoice/layout.html.twig' %}
|
||||
|
||||
{% block invoice %}
|
||||
|
||||
{# You can overwrite these settings in your config/packages.local.yaml under the key "twig.globals.company" #}
|
||||
{% set company = company|default({
|
||||
name: 'Kimai Inc.',
|
||||
homepage: 'www.kimai.org',
|
||||
@@ -137,11 +142,4 @@
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row no-print">
|
||||
<div class="col-xs-12">
|
||||
<button type="button" class="btn btn-success pull-right" onclick="window.print();return false;">
|
||||
<i class="{{ 'print'|icon }}"></i> {{ 'button.print'|trans }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
BIN
templates/invoice/renderer/open-spreadsheet.ods
Normal file
BIN
templates/invoice/renderer/open-spreadsheet.ods
Normal file
Binary file not shown.
BIN
templates/invoice/renderer/spreadsheet.xlsx
Normal file
BIN
templates/invoice/renderer/spreadsheet.xlsx
Normal file
Binary file not shown.
@@ -1,5 +1,7 @@
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% extends 'invoice/layout.html.twig' %}
|
||||
|
||||
{% block invoice %}
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h2 class="page-header">
|
||||
@@ -23,7 +25,13 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="width:50%">{{ 'label.date'|trans }}</th>
|
||||
<td contenteditable="true">{{ model.query.end|month_name|trans }} {{ model.query.end|date('Y') }}</td>
|
||||
<td contenteditable="true">
|
||||
{% 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|trans }} {{ model.query.end|date('Y') }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ 'label.customer'|trans }}</th>
|
||||
@@ -50,6 +58,9 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'label.date'|trans }}</th>
|
||||
{% if model.query.user is empty %}
|
||||
<th>{{ 'label.user'|trans }}</th>
|
||||
{% endif %}
|
||||
<th>{{ 'label.activity'|trans }}</th>
|
||||
<th>{{ 'label.hours'|trans }}</th>
|
||||
</tr>
|
||||
@@ -58,6 +69,9 @@
|
||||
{% for entry in model.calculator.entries %}
|
||||
<tr>
|
||||
<td>{{ entry.begin|date_short }}</td>
|
||||
{% if model.query.user is empty %}
|
||||
<td>{{ widgets.username(entry.user) }}</td>
|
||||
{% endif %}
|
||||
<td>{{ entry.activity.name }} / {{ entry.activity.project.name }}</td>
|
||||
<td>{{ entry.duration|duration }}</td>
|
||||
</tr>
|
||||
@@ -99,11 +113,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row no-print">
|
||||
<div class="col-xs-12">
|
||||
<button type="button" class="btn btn-success pull-right" onclick="window.print();return false;">
|
||||
<i class="{{ 'print'|icon }}"></i> {{ 'button.print'|trans }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -16,7 +16,6 @@
|
||||
'title': '',
|
||||
'due_days': 'hidden-xs',
|
||||
'vat': 'hidden-xs',
|
||||
'invoice_renderer': 'hidden-xs',
|
||||
'actions': 'alwaysVisible',
|
||||
}) }}
|
||||
|
||||
@@ -26,7 +25,6 @@
|
||||
<td>{{ entry.title }}</td>
|
||||
<td class="hidden-xs hidden-sm">{{ entry.dueDays }}</td>
|
||||
<td class="hidden-xs hidden-sm">{{ entry.vat }}</td>
|
||||
<td class="hidden-xs hidden-sm">{{ "invoice_renderer.#{entry.renderer}"|trans }}</td>
|
||||
<td>
|
||||
{% set actionButtons = {'edit': path('admin_invoice_template_edit', {'id' : entry.id, 'page': page})} %}
|
||||
{% set actionButtons = actionButtons|merge({'trash': path('admin_invoice_template_delete', {'id' : entry.id, 'page': page})}) %}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
{% endif %}
|
||||
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'activity') }}">{{ widgets.label_activity(entry.activity) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'description') }} timesheet-description">{{ entry.description|default('')|desc2html }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'description') }} timesheet-description">{{ entry.description|desc2html }}</td>
|
||||
<td>
|
||||
{% set actionButtons = {'edit': path('timesheet_edit', {'id' : entry.id, 'page': page})} %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user