This commit is contained in:
@@ -4,8 +4,10 @@ kimai:
|
||||
invoice:
|
||||
renderer:
|
||||
default: 'App\Controller\InvoiceController::invoiceAction'
|
||||
timesheet: 'App\Controller\InvoiceController::timesheetAction'
|
||||
calculator:
|
||||
default: 'App\Invoice\DefaultCalculator'
|
||||
short: 'App\Invoice\ShortInvoiceCalculator'
|
||||
number_generator:
|
||||
default: 'App\Invoice\DateNumberGenerator'
|
||||
#random: 'App\Invoice\RandomNumberGenerator'
|
||||
|
||||
@@ -231,6 +231,17 @@ class InvoiceController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InvoiceModel $model
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function timesheetAction(InvoiceModel $model)
|
||||
{
|
||||
return $this->render('invoice/timesheet.html.twig', [
|
||||
'model' => $model,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InvoiceQuery $query
|
||||
* @return \Symfony\Component\Form\FormInterface
|
||||
|
||||
@@ -44,6 +44,7 @@ class CustomerEditForm extends AbstractType
|
||||
])
|
||||
->add('number', TextType::class, [
|
||||
'label' => 'label.customer_number',
|
||||
'required' => false,
|
||||
])
|
||||
->add('comment', TextareaType::class, [
|
||||
'label' => 'label.comment',
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace App\Invoice;
|
||||
|
||||
use App\Entity\Timesheet;
|
||||
use App\Model\InvoiceModel;
|
||||
|
||||
/**
|
||||
@@ -22,26 +23,43 @@ interface CalculatorInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Return the timesheet records that will be displayed on the invoice.
|
||||
*
|
||||
* @return Timesheet[]
|
||||
*/
|
||||
public function getEntries();
|
||||
|
||||
/**
|
||||
* Set the invoice model and can be used to fetch the customer.
|
||||
*
|
||||
* @param InvoiceModel $model
|
||||
*/
|
||||
public function setModel(InvoiceModel $model);
|
||||
|
||||
/**
|
||||
* Returns the subtotal before taxes.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getSubtotal(): float;
|
||||
|
||||
/**
|
||||
* Returns the tax amount for this invoice.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getTax(): float;
|
||||
|
||||
/**
|
||||
* Returns the total amount for this invoice including taxes.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getTotal(): float;
|
||||
|
||||
/**
|
||||
* Returns the currency for the invoices amounts.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrency(): string;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace App\Invoice;
|
||||
|
||||
use App\Entity\Timesheet;
|
||||
use App\Model\InvoiceModel;
|
||||
|
||||
/**
|
||||
@@ -34,6 +35,14 @@ class DefaultCalculator implements CalculatorInterface
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* @return Timesheet[]
|
||||
*/
|
||||
public function getEntries()
|
||||
{
|
||||
return $this->model->getEntries();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InvoiceModel $model
|
||||
*/
|
||||
|
||||
43
src/Invoice/ShortInvoiceCalculator.php
Normal file
43
src/Invoice/ShortInvoiceCalculator.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai package.
|
||||
*
|
||||
* (c) Kevin Papst <kevin@kevinpapst.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Invoice;
|
||||
|
||||
use App\Entity\Timesheet;
|
||||
|
||||
/**
|
||||
* A calculator that sums up all timesheet records from the model and returns only one
|
||||
* entry for a compact invoice version.
|
||||
*
|
||||
* @author Kevin Papst <kevin@kevinpapst.de>
|
||||
*/
|
||||
class ShortInvoiceCalculator extends DefaultCalculator
|
||||
{
|
||||
|
||||
/**
|
||||
* @return Timesheet[]
|
||||
*/
|
||||
public function getEntries()
|
||||
{
|
||||
$timesheet = new Timesheet();
|
||||
|
||||
foreach ($this->model->getEntries() as $entry) {
|
||||
$timesheet->setDuration($timesheet->getDuration() + $entry->getDuration());
|
||||
if ($timesheet->getActivity() === null) {
|
||||
$timesheet->setActivity($entry->getActivity());
|
||||
$timesheet->setEnd($entry->getEnd());
|
||||
}
|
||||
$timesheet->setBegin($entry->getBegin());
|
||||
}
|
||||
|
||||
return [$timesheet];
|
||||
}
|
||||
}
|
||||
@@ -33,11 +33,11 @@
|
||||
</div>
|
||||
<div class="col-sm-4 invoice-col">
|
||||
<p contenteditable="true">
|
||||
<b>{{ 'invoice.number'|trans }} {{ model.numberGenerator.invoiceNumber }}</b>
|
||||
<b>{{ 'invoice.number'|trans }}: {{ model.numberGenerator.invoiceNumber }}</b>
|
||||
</p>
|
||||
<p contenteditable="true">
|
||||
<b>{{ 'invoice.due_days'|trans }}:</b> {{ model.dueDate|date(kimai_context.date_1) }}<br>
|
||||
<b>{{ 'label.customer_number'|trans }}:</b> {{ model.customer.number }}<br>
|
||||
{% if model.customer.number is not empty %}<b>{{ 'label.customer_number'|trans }}:</b> {{ model.customer.number }}<br>{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,7 +54,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in model.entries %}
|
||||
{% for entry in model.calculator.entries %}
|
||||
<tr>
|
||||
<td>{{ entry.begin|date(kimai_context.date_1) }}</td>
|
||||
<td>{{ entry.activity.name }} / {{ entry.activity.project.name }}</td>
|
||||
|
||||
94
templates/invoice/timesheet.html.twig
Normal file
94
templates/invoice/timesheet.html.twig
Normal file
@@ -0,0 +1,94 @@
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h2 class="page-header">
|
||||
<span contenteditable="true">{{ model.template.title|default('invoice_renderer.timesheet'|trans) }}</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row invoice-info" style="padding: 10px 0 20px 0">
|
||||
<div class="col-sm-12 invoice-col">
|
||||
<table>
|
||||
<tr>
|
||||
<th>{{ 'invoice.from'|trans }}</th>
|
||||
<td contenteditable="true">
|
||||
{% if model.query.user is not empty %}
|
||||
{{ widgets.username(model.query.user) }}
|
||||
{% else %}
|
||||
{{ model.template.company }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="width:50%">{{ 'label.date'|trans }}</th>
|
||||
<td contenteditable="true">{{ model.invoiceDate|date('F Y') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ 'label.customer'|trans }}</th>
|
||||
<td contenteditable="true">
|
||||
{% if model.customer.number is not empty %}[{{ model.customer.number }}]{% endif %}
|
||||
{{ model.customer.name }} / {{ model.customer.contact }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12 table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'label.date'|trans }}</th>
|
||||
<th>{{ 'label.activity'|trans }}</th>
|
||||
<th>{{ 'label.hours'|trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in model.calculator.entries %}
|
||||
<tr>
|
||||
<td>{{ entry.begin|date(kimai_context.date_1) }}</td>
|
||||
<td>{{ entry.activity.name }} / {{ entry.activity.project.name }}</td>
|
||||
<td>{{ entry.duration|duration }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" style="padding: 60px 0">
|
||||
<div class="col-xs-12">
|
||||
{% if model.template.paymentTerms is not empty %}
|
||||
<p class="lead">{{ 'label.payment_terms'|trans }}</p>
|
||||
|
||||
<p class="text-muted well well-sm no-shadow" contenteditable="true">
|
||||
{{ model.template.paymentTerms|trim|nl2br }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th style="width:50%;padding-bottom: 60px">{{ 'invoice.signature_user'|trans }}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ 'invoice.signature_customer'|trans }}</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</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;" style="margin-right: 5px;">
|
||||
<i class="fa fa-print"></i> {{ 'button.print'|trans }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -673,7 +673,11 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="invoice_renderer.default">
|
||||
<source>invoice_renderer.default</source>
|
||||
<target>HTML Rechnung (Standard)</target>
|
||||
<target>Rechnung (Standard)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="invoice_renderer.timesheet">
|
||||
<source>invoice_renderer.timesheet</source>
|
||||
<target>Stundenzettel</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="label.invoice_number_generator">
|
||||
<source>label.invoice_number_generator</source>
|
||||
@@ -695,6 +699,18 @@
|
||||
<source>invoice_calculator.default</source>
|
||||
<target>Stundenbasiert (Standard)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="invoice_calculator.short">
|
||||
<source>invoice_calculator.short</source>
|
||||
<target>Stundenbasiert - Kurzversion (nur ein Eintrag)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="invoice.signature_user">
|
||||
<source>invoice.signature_user</source>
|
||||
<target>Leistungsbestätigung: Datum / Name Berater / Unterschrift</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="invoice.signature_customer">
|
||||
<source>invoice.signature_customer</source>
|
||||
<target>Leistungsbestätigung: Datum / Name Kunde / Unterschrift</target>
|
||||
</trans-unit>
|
||||
|
||||
<!--
|
||||
Month names
|
||||
|
||||
@@ -673,7 +673,11 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="invoice_renderer.default">
|
||||
<source>invoice_renderer.default</source>
|
||||
<target>HTML Invoice (default)</target>
|
||||
<target>Invoice (default)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="invoice_renderer.timesheet">
|
||||
<source>invoice_renderer.timesheet</source>
|
||||
<target>Timesheet</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="label.invoice_number_generator">
|
||||
<source>label.invoice_number_generator</source>
|
||||
@@ -695,6 +699,18 @@
|
||||
<source>invoice_calculator.default</source>
|
||||
<target>Hourly rates (default)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="invoice_calculator.short">
|
||||
<source>invoice_calculator.short</source>
|
||||
<target>Hourly rates - short version (only one record)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="invoice.signature_user">
|
||||
<source>invoice.signature_user</source>
|
||||
<target>Confirmation: Date / Name Consultant / Signature</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="invoice.signature_customer">
|
||||
<source>invoice.signature_customer</source>
|
||||
<target>Confirmation: Date / Name Customer / Signature</target>
|
||||
</trans-unit>
|
||||
|
||||
<!--
|
||||
Month names
|
||||
|
||||
Reference in New Issue
Block a user