added decimal format variable for invoice duration (#1037)
This commit is contained in:
@@ -89,4 +89,13 @@ abstract class AbstractRenderer
|
||||
{
|
||||
return $this->extension->duration($seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $seconds
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getFormattedDecimalDuration($seconds)
|
||||
{
|
||||
return $this->extension->durationDecimal($seconds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,12 @@ trait RendererTrait
|
||||
*/
|
||||
abstract protected function getFormattedDuration($seconds);
|
||||
|
||||
/**
|
||||
* @param int $seconds
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function getFormattedDecimalDuration($seconds);
|
||||
|
||||
/**
|
||||
* @param InvoiceModel $model
|
||||
* @return array
|
||||
@@ -93,6 +99,7 @@ trait RendererTrait
|
||||
'invoice.vat' => $model->getCalculator()->getVat(),
|
||||
'invoice.tax' => $this->getFormattedMoney($model->getCalculator()->getTax(), $currency),
|
||||
'invoice.total_time' => $this->getFormattedDuration($model->getCalculator()->getTimeWorked()),
|
||||
'invoice.duration_decimal' => $this->getFormattedDecimalDuration($model->getCalculator()->getTimeWorked()),
|
||||
'invoice.total' => $this->getFormattedMoney($model->getCalculator()->getTotal(), $currency),
|
||||
'invoice.subtotal' => $this->getFormattedMoney($model->getCalculator()->getSubtotal(), $currency),
|
||||
|
||||
@@ -177,7 +184,7 @@ trait RendererTrait
|
||||
if (null !== $timesheet->getFixedRate()) {
|
||||
$rate = $timesheet->getFixedRate();
|
||||
$hourlyRate = $timesheet->getFixedRate();
|
||||
$amount = 1;
|
||||
$amount = 1; // FIXME fixed rates
|
||||
}
|
||||
|
||||
if (empty($description)) {
|
||||
@@ -206,6 +213,7 @@ trait RendererTrait
|
||||
'entry.total' => $this->getFormattedMoney($rate, $currency),
|
||||
'entry.currency' => $currency,
|
||||
'entry.duration' => $timesheet->getDuration(),
|
||||
'entry.duration_decimal' => $this->getFormattedDecimalDuration($timesheet->getDuration()),
|
||||
'entry.duration_minutes' => number_format($timesheet->getDuration() / 60),
|
||||
'entry.begin' => $this->getFormattedDateTime($begin),
|
||||
'entry.begin_time' => $this->getFormattedTime($begin),
|
||||
|
||||
@@ -63,6 +63,7 @@ class Extensions extends AbstractExtension
|
||||
{
|
||||
return [
|
||||
new TwigFilter('duration', [$this, 'duration']),
|
||||
new TwigFilter('duration_decimal', [$this, 'durationDecimal']),
|
||||
new TwigFilter('money', [$this, 'money']),
|
||||
new TwigFilter('currency', [$this, 'currency']),
|
||||
new TwigFilter('country', [$this, 'country']),
|
||||
@@ -102,6 +103,30 @@ class Extensions extends AbstractExtension
|
||||
* @return string
|
||||
*/
|
||||
public function duration($duration, $format = null)
|
||||
{
|
||||
$duration = $this->getSecondsForDuration($duration);
|
||||
|
||||
if (null === $format) {
|
||||
$format = $this->localeSettings->getDurationFormat();
|
||||
}
|
||||
|
||||
return $this->formatDuration($duration, $format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms seconds into a decimal formatted duration string.
|
||||
*
|
||||
* @param int|Timesheet $duration
|
||||
* @return string
|
||||
*/
|
||||
public function durationDecimal($duration)
|
||||
{
|
||||
$duration = $this->getSecondsForDuration($duration);
|
||||
|
||||
return $this->getNumberFormatter()->format(number_format($duration / 3600, 2));
|
||||
}
|
||||
|
||||
private function getSecondsForDuration($duration): int
|
||||
{
|
||||
if (null === $duration) {
|
||||
$duration = 0;
|
||||
@@ -116,19 +141,15 @@ class Extensions extends AbstractExtension
|
||||
$duration = $seconds;
|
||||
}
|
||||
|
||||
return $this->formatDuration((int) $duration, $format);
|
||||
return (int) $duration;
|
||||
}
|
||||
|
||||
protected function formatDuration(int $seconds, $format = null): string
|
||||
protected function formatDuration(int $seconds, string $format): string
|
||||
{
|
||||
if ($seconds < 0) {
|
||||
return '?';
|
||||
}
|
||||
|
||||
if (null === $format) {
|
||||
$format = $this->localeSettings->getDurationFormat();
|
||||
}
|
||||
|
||||
return $this->durationFormatter->format($seconds, $format);
|
||||
}
|
||||
|
||||
@@ -159,6 +180,33 @@ class Extensions extends AbstractExtension
|
||||
return Constants::HOMEPAGE . '/documentation/' . $url;
|
||||
}
|
||||
|
||||
private function initLocale()
|
||||
{
|
||||
$locale = $this->localeSettings->getLocale();
|
||||
|
||||
if ($this->locale === $locale) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->locale = $locale;
|
||||
$this->numberFormatter = new NumberFormatter($locale, NumberFormatter::DECIMAL);
|
||||
$this->moneyFormatter = new NumberFormatter($locale, NumberFormatter::CURRENCY);
|
||||
}
|
||||
|
||||
private function getNumberFormatter(): NumberFormatter
|
||||
{
|
||||
$this->initLocale();
|
||||
|
||||
return $this->numberFormatter;
|
||||
}
|
||||
|
||||
private function getMoneyFormatter(): NumberFormatter
|
||||
{
|
||||
$this->initLocale();
|
||||
|
||||
return $this->moneyFormatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $amount
|
||||
* @param string $currency
|
||||
@@ -166,19 +214,11 @@ class Extensions extends AbstractExtension
|
||||
*/
|
||||
public function money($amount, $currency = null)
|
||||
{
|
||||
$locale = $this->localeSettings->getLocale();
|
||||
|
||||
if ($this->locale !== $locale) {
|
||||
$this->locale = $locale;
|
||||
$this->numberFormatter = new NumberFormatter($locale, NumberFormatter::DECIMAL);
|
||||
$this->moneyFormatter = new NumberFormatter($locale, NumberFormatter::CURRENCY);
|
||||
}
|
||||
|
||||
if (null !== $currency) {
|
||||
return $this->moneyFormatter->formatCurrency($amount, $currency);
|
||||
return $this->getMoneyFormatter()->formatCurrency($amount, $currency);
|
||||
}
|
||||
|
||||
return $this->numberFormatter->format($amount);
|
||||
return $this->getNumberFormatter()->format($amount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
{% set duration = entry.duration|duration %}
|
||||
{% if entry.fixedRate is not null %}
|
||||
{% set rate = entry.fixedRate %}
|
||||
{% set duration = 1 %}
|
||||
{% set duration = 1 %}{# FIXME fixed rates #}
|
||||
{% elseif entry.hourlyRate is not null %}
|
||||
{% set rate = entry.hourlyRate %}
|
||||
{% else %}
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
{% set duration = entry.duration|duration %}
|
||||
{% if entry.fixedRate is not null %}
|
||||
{% set rate = entry.fixedRate %}
|
||||
{% set duration = 1 %}
|
||||
{% set duration = 1 %}{# FIXME fixed rates #}
|
||||
{% elseif entry.hourlyRate is not null %}
|
||||
{% set rate = entry.hourlyRate %}
|
||||
{% else %}
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
{% set duration = entry.duration|duration %}
|
||||
{% if entry.fixedRate is not null %}
|
||||
{% set rate = entry.fixedRate %}
|
||||
{% set duration = 1 %}
|
||||
{% set duration = 1 %}{# FIXME fixed rates #}
|
||||
{% elseif entry.hourlyRate is not null %}
|
||||
{% set rate = entry.hourlyRate %}
|
||||
{% else %}
|
||||
|
||||
@@ -86,6 +86,9 @@
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th></th>
|
||||
{% if model.query.user is empty %}
|
||||
<th></th>
|
||||
{% endif %}
|
||||
<th>{{ 'invoice.total_working_time'|trans }}</th>
|
||||
<th>{{ model.calculator.timeWorked|duration }}</th>
|
||||
</tr>
|
||||
|
||||
@@ -80,6 +80,15 @@ class DebugRenderer implements RendererInterface
|
||||
return $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $seconds
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getFormattedDecimalDuration($seconds)
|
||||
{
|
||||
return $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the given InvoiceDocument with the data from the InvoiceModel into a stupid array for testing only.
|
||||
*
|
||||
|
||||
@@ -61,6 +61,7 @@ class DebugRendererTest extends TestCase
|
||||
'invoice.vat',
|
||||
'invoice.tax',
|
||||
'invoice.total_time',
|
||||
'invoice.duration_decimal',
|
||||
'invoice.total',
|
||||
'invoice.subtotal',
|
||||
'template.name',
|
||||
@@ -126,6 +127,7 @@ class DebugRendererTest extends TestCase
|
||||
'entry.total',
|
||||
'entry.currency',
|
||||
'entry.duration',
|
||||
'entry.duration_decimal',
|
||||
'entry.duration_minutes',
|
||||
'entry.begin',
|
||||
'entry.begin_time',
|
||||
|
||||
@@ -50,7 +50,7 @@ class ExtensionsTest extends TestCase
|
||||
|
||||
public function testGetFilters()
|
||||
{
|
||||
$filters = ['duration', 'money', 'currency', 'country', 'docu_link'];
|
||||
$filters = ['duration', 'duration_decimal', 'money', 'currency', 'country', 'docu_link'];
|
||||
$sut = $this->getSut($this->localeDe);
|
||||
$twigFilters = $sut->getFilters();
|
||||
$this->assertCount(count($filters), $twigFilters);
|
||||
@@ -200,6 +200,33 @@ class ExtensionsTest extends TestCase
|
||||
$this->assertEquals('00:00 h', $sut->duration(null));
|
||||
}
|
||||
|
||||
public function testDurationDecimal()
|
||||
{
|
||||
$record = $this->getTimesheet(9437);
|
||||
|
||||
$sut = $this->getSut($this->localeEn);
|
||||
$this->assertEquals('2.62', $sut->durationDecimal($record->getDuration()));
|
||||
|
||||
// test Timesheet object
|
||||
$this->assertEquals('2.62', $sut->durationDecimal($record));
|
||||
|
||||
// test extended format
|
||||
$sut = $this->getSut($this->localeDe, 'de');
|
||||
$this->assertEquals('2,62', $sut->durationDecimal($record->getDuration()));
|
||||
|
||||
// test negative duration
|
||||
$sut = $this->getSut($this->localeEn, 'en');
|
||||
$this->assertEquals('0', $sut->durationDecimal('-1'));
|
||||
|
||||
// test zero duration
|
||||
$sut = $this->getSut($this->localeEn, 'en');
|
||||
$this->assertEquals('0', $sut->durationDecimal('0'));
|
||||
|
||||
$sut = $this->getSut($this->localeEn, 'en');
|
||||
|
||||
$this->assertEquals('0', $sut->durationDecimal(null));
|
||||
}
|
||||
|
||||
protected function getTimesheet($seconds)
|
||||
{
|
||||
$begin = new \DateTime();
|
||||
|
||||
Reference in New Issue
Block a user