Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Introduce rounding method and remove allow rounding down
Browse files Browse the repository at this point in the history
  • Loading branch information
simonschaufi committed Nov 6, 2019
1 parent 0c189d0 commit 697a379
Show file tree
Hide file tree
Showing 24 changed files with 613 additions and 40 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
],
"require": {
"php": ">=5.6.0",
"ext-json": "*",
"phpoffice/phpexcel": "1.8.*",
"tecnickcom/tcpdf": "^6.2.12",
"tinybutstrong/tinybutstrong": "^3.10",
Expand Down
2 changes: 1 addition & 1 deletion extensions/ki_adminpanel/processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@
$config_data['status'] = implode(',', $_REQUEST['status']);
}
$config_data['roundPrecision'] = $_REQUEST['roundPrecision'];
$config_data['allowRoundDown'] = getRequestBool('allowRoundDown');
$config_data['roundingMethod'] = $_REQUEST['roundingMethod'];
$config_data['roundMinutes'] = $_REQUEST['roundMinutes'];
$config_data['roundSeconds'] = $_REQUEST['roundSeconds'];
$config_data['roundTimesheetEntries'] = $_REQUEST['roundTimesheetEntries'];
Expand Down
21 changes: 13 additions & 8 deletions extensions/ki_adminpanel/templates/scripts/advanced.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,19 @@
</div>
<div>
<?php echo $this->translate('round_time')?> <select name="roundPrecision" class="formfield">
<option value="0" <?php if ($this->kga->getRoundPrecisionRecorderTimes() == 0): ?> selected="selected" <?php endif; ?>>-</option>
<option value="1" <?php if ($this->kga->getRoundPrecisionRecorderTimes() == 1): ?> selected="selected" <?php endif; ?>>1</option>
<option value="5" <?php if ($this->kga->getRoundPrecisionRecorderTimes() == 5): ?> selected="selected" <?php endif; ?>>5</option>
<option value="10" <?php if ($this->kga->getRoundPrecisionRecorderTimes() == 10): ?> selected="selected" <?php endif; ?>>10</option>
<option value="15" <?php if ($this->kga->getRoundPrecisionRecorderTimes() == 15): ?> selected="selected" <?php endif; ?>>15</option>
<option value="15" <?php if ($this->kga->getRoundPrecisionRecorderTimes() == 20): ?> selected="selected" <?php endif; ?>>20</option>
<option value="30" <?php if ($this->kga->getRoundPrecisionRecorderTimes() == 30): ?> selected="selected" <?php endif; ?>>30</option>
</select> <?php echo $this->translate('round_time_minute')?> <input type="checkbox" name="allowRoundDown" <?php if($this->kga->isRoundDownRecorderTimes()): ?> checked="checked" <?php endif; ?> value="1" class="formfield"> <?php echo $this->translate('allowRoundDown');?>
<option value="0" <?php if ($this->kga->getRoundPrecisionRecorderTimes() === 0): ?> selected="selected" <?php endif; ?>>-</option>
<option value="1" <?php if ($this->kga->getRoundPrecisionRecorderTimes() === 1): ?> selected="selected" <?php endif; ?>>1</option>
<option value="5" <?php if ($this->kga->getRoundPrecisionRecorderTimes() === 5): ?> selected="selected" <?php endif; ?>>5</option>
<option value="10" <?php if ($this->kga->getRoundPrecisionRecorderTimes() === 10): ?> selected="selected" <?php endif; ?>>10</option>
<option value="15" <?php if ($this->kga->getRoundPrecisionRecorderTimes() === 15): ?> selected="selected" <?php endif; ?>>15</option>
<option value="30" <?php if ($this->kga->getRoundPrecisionRecorderTimes() === 30): ?> selected="selected" <?php endif; ?>>30</option>
<option value="60" <?php if ($this->kga->getRoundPrecisionRecorderTimes() === 60): ?> selected="selected" <?php endif; ?>>60</option>
</select> <?php echo $this->translate('round_time_minute')?>
<?php echo $this->translate('roundingMethod') ?> <select name="roundingMethod" class="formfield">
<option value="default" <?php if ($this->kga->getRoundingMethod() === 'default'): ?> selected="selected" <?php endif; ?>><?php echo $this->translate('roundingMethod_default') ?></option>
<option value="closest" <?php if ($this->kga->getRoundingMethod() === 'closest'): ?> selected="selected" <?php endif; ?>><?php echo $this->translate('roundingMethod_closest') ?></option>
<option value="ceil" <?php if ($this->kga->getRoundingMethod() === 'ceil'): ?> selected="selected" <?php endif; ?>><?php echo $this->translate('roundingMethod_ceil') ?></option>
</select>
</div>
<div>
<?php echo $this->translate('decimal_separator')?>: <input type="text" name="decimalSeparator" size="1" value="<?php echo $this->escape($this->kga['conf']['decimalSeparator']) ?>" class="formfield">
Expand Down
2 changes: 1 addition & 1 deletion extensions/ki_timesheets/processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ function($activity) {
(int)$inDate->getTimestamp(),
(int)$outDate->getTimestamp(),
$kga->getRoundPrecisionRecorderTimes(),
$kga->isRoundDownRecorderTimes()
$kga->getRoundingMethod()
);
$data['start'] = $rounded['start'];
$data['end'] = $rounded['end'];
Expand Down
2 changes: 1 addition & 1 deletion includes/version.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?php
$kga['version'] = '1.3.5';
$kga['revision'] = 1394; // database revision number (incremented whenever the database changes)
$kga['revision'] = 1400; // database revision number (incremented whenever the database changes)
$kga['status'] = ''; // leave blank if stable
2 changes: 1 addition & 1 deletion installer/install.php
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ function quoteForSql($input)
('table_time_format', '%H:%M'),
('language', '" . $kga['language'] . "'),
('roundPrecision', '1'),
('allowRoundDown', '1'),
('roundingMethod', 'default'),
('decimalSeparator', ','),
('durationWithSeconds', '0'),
('exactSums', '0'),
Expand Down
1 change: 0 additions & 1 deletion language/bg.php
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@
'table_time_format' => 'Формат на времето в табелите (<a href="http://php.net/manual/de/function.strftime.php" target="_blank">Нотация на strftime()</a>)',
'round_time' => 'Закръгли времето на ',
'round_time_minute' => ' Минути.',
'allowRoundDown' => 'Позволи закръгляне на времето.',
'logged_in_as' => 'Потебител: ',
'decimal_separator' => 'Десетична запетая',
'view_filter' => 'Филтър',
Expand Down
5 changes: 4 additions & 1 deletion language/de.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,10 @@
'table_time_format' => 'Format der Zeiten in den Tabellen (<a href="http://php.net/manual/de/function.strftime.php" target="_blank">Notation für strftime()</a>)',
'round_time' => 'Zeit runden auf ',
'round_time_minute' => ' Minute(n).',
'allowRoundDown' => 'Erlaube das Abrunden von Zeiten.',
'roundingMethod' => 'Rundungsmethode',
'roundingMethod_default' => 'Standard (Start ab, Stop auf)',
'roundingMethod_closest' => 'Mathematisch runden (Start auf/ab, Stop auf/ab)',
'roundingMethod_ceil' => 'Immer Aufrunden',
'logged_in_as' => 'Angemeldet als:',
'decimal_separator' => 'Dezimal-Trennzeichen',
'view_filter' => 'Ansichtsfilter',
Expand Down
5 changes: 4 additions & 1 deletion language/en.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,10 @@
'table_time_format' => 'Time format for tables (<a href="http://php.net/manual/en/function.strftime.php" target="_blank">notation for strftime()</a>)',
'round_time' => 'Round time to ',
'round_time_minute' => ' minute(s).',
'allowRoundDown' => 'Allow rounding entries down.',
'roundingMethod' => 'Rounding method',
'roundingMethod_default' => 'Default (Start down, Stop up)',
'roundingMethod_closest' => 'Mathematical round (Start up/down, Stop up/down)',
'roundingMethod_ceil' => 'Always round up',
'logged_in_as' => 'logged in as:',
'decimal_separator' => 'Decimal separator',
'view_filter' => 'view filter',
Expand Down
1 change: 0 additions & 1 deletion language/et.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,6 @@
'table_date_format' => 'Tabelite kuupäevavorming (<a href="http://php.net/manual/en/function.strftime.php" target="_blank">tähiste juhend</a>)',
'round_time' => 'Aeg ümardatakse täpsusele',
'round_time_minute' => ' minut(it).',
'allowRoundDown' => 'Väiksemaks ümardamine on lubatud.',
'logged_in_as' => 'Sees kasutajana',

'decimal_separator' => 'Kümnendkohti eraldab',
Expand Down
1 change: 0 additions & 1 deletion language/fr.php
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,6 @@
'table_date_format' => 'Format de la date pour les tables (<a href="http://php.net/manual/en/function.strftime.php" target="_blank">pour la fonction strftime()</a>)',
'round_time' => 'Arrondir le temps à ',
'round_time_minute' => ' minute(s).',
"allowRoundDown" => "Permettre d'arrondir l'entrée à la baisse.",
'logged_in_as' => 'Connecté comme:',

'decimal_separator' => 'Séparateur décimal',
Expand Down
473 changes: 472 additions & 1 deletion language/hu.php

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion language/jp.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,6 @@
'table_date_format' => 'テーブルの日付フォーマット (<a href="http://php.net/manual/ja/function.strftime.php" target="_blank">strftime()の表記法</a>)',
'round_time' => '時間を丸める',
'round_time_minute' => ' 分に丸める',
'allowRoundDown' => 'エントリーに切り下げを可能する',
'logged_in_as' => '現在ユーザー:',
'decimal_separator' => '小数点の記号',
'view_filter' => 'ビューフィルター',
Expand Down
1 change: 0 additions & 1 deletion language/nl.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,6 @@
'table_date_format' => 'Datum opmaak voor tabellen (<a href="http://php.net/manual/en/function.strftime.php" target="_blank">notation for strftime()</a>)',
'round_time' => 'Tijd afronden op ',
'round_time_minute' => ' minuten.',
'allowRoundDown' => 'Sta toe invoer naar beneden af te ronden.',
'logged_in_as' => 'Ingelogd als:',
'decimal_separator' => 'Decimaal scheidingsteken',
'view_filter' => 'toon filter',
Expand Down
1 change: 0 additions & 1 deletion language/pt_BR.php
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,6 @@
'table_date_format' => 'Formato de data para tabelas (<a href="http://php.net/manual/pt_BR/function.strftime.php" target="_blank">notação de strftime()</a>)',
'round_time' => 'Arredondar tempo para ',
'round_time_minute' => ' minuto(s).',
'allowRoundDown' => 'Permitir arredondar registros para baixo.',
'logged_in_as' => 'Usuário registrado:',
'decimal_separator' => 'Separador decimal',
'view_filter' => 'Filtro de visualização',
Expand Down
1 change: 0 additions & 1 deletion language/ro.php
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@
'table_date_format' => 'Formatarea datei pentru tabele (<a href="http://php.net/manual/en/function.strftime.php" target="_blank">notare pentru strftime()</a>)',
'round_time' => 'Rotunjire timp cu ',
'round_time_minute' => ' minut(e).',
'allowRoundDown' => 'Aplica la toate inregisrarile.',
'logged_in_as' => 'conectat ca:',
'decimal_separator' => 'Separator zecimal',
'view_filter' => 'Filtrare',
Expand Down
1 change: 0 additions & 1 deletion language/ru.php
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,6 @@
'table_date_format' => 'Date format for tables (<a href="http://php.net/manual/en/function.strftime.php" target="_blank">notation for strftime()</a>)',
'round_time' => 'Округлять время до ',
'round_time_minute' => ' минут.',
'allowRoundDown' => 'Разрешить округлять в меньшую сторону.',
'logged_in_as' => 'Вошел как',
'decimal_separator' => 'Decimal separator',
'view_filter' => 'view filter',
Expand Down
1 change: 0 additions & 1 deletion language/sk.php
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@
'table_date_format' => 'Formát dátumu pre tabuľky (<a href="http://php.net/manual/en/function.strftime.php" target="_blank">notácia pre PHP funkciu strftime()</a>)',
'round_time' => 'Zaokrúhľovať čas na ',
'round_time_minute' => ' minúta(y).',
'allowRoundDown' => 'Povoliť zaokrúhľovanie smerom nadol.',
'logged_in_as' => 'prihlásený ako:',
'decimal_separator' => 'Oddeľovač desatín',
'view_filter' => 'filtruj',
Expand Down
1 change: 0 additions & 1 deletion language/tr.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,6 @@
'table_time_format' => 'Tablolar için saat formatı (<a href="http://php.net/manual/en/function.strftime.php" target="_blank">notation for strftime()</a>)',
'round_time' => 'Saati şuna yuvarla ',
'round_time_minute' => ' dakika.',
'allowRoundDown' => 'Aşağı yuvarlamaya müsaade et.',
'logged_in_as' => 'olarak giriş yapıldı:',
'decimal_separator' => 'ondalık ayırıcısı',
'view_filter' => 'filtreyi göster',
Expand Down
9 changes: 9 additions & 0 deletions libraries/Kimai/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,14 @@ public function getRoundPrecisionRecorderTimes()
return (int)$this->get('roundPrecision', 0);
}

/**
* @return string
*/
public function getRoundingMethod()
{
return $this->get('roundingMethod', 'default');
}

/**
* @return int
*/
Expand Down Expand Up @@ -382,6 +390,7 @@ public function getTableTimeFormat()

/**
* @return bool
* @deprecated Use getRoundingMethod instead
*/
public function isRoundDownRecorderTimes()
{
Expand Down
4 changes: 2 additions & 2 deletions libraries/Kimai/Database/Mysql.php
Original file line number Diff line number Diff line change
Expand Up @@ -2976,10 +2976,10 @@ public function initializeConfig(Kimai_Config $config)
case 'date_format_3':
case 'table_time_format':
case 'roundPrecision':
case 'roundingMethod':
case 'exactSums':
case 'defaultVat':
case 'editLimit':
case 'allowRoundDown':
case 'defaultStatusID':
$config->set($key, $value);
break;
Expand Down Expand Up @@ -3742,7 +3742,7 @@ public function stopRecorder($id)
$activity['start'],
time(),
$this->kga->getRoundPrecisionRecorderTimes(),
$this->kga->isRoundDownRecorderTimes()
$this->kga->getRoundingMethod()
);

$values['start'] = $rounded['start'];
Expand Down
100 changes: 93 additions & 7 deletions libraries/Kimai/Rounding.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,30 @@ class Kimai_Rounding
* @param int $start the beginning of the timespan
* @param int $end the end of the timespan
* @param int $minutes the steps in minutes (has to divide an hour, e.g. 5 is valid while 7 is not)
* @param bool $allowRoundDown
*
* @param string $method
* @return array
*/
public static function roundTimespan($start, $end, $minutes, $allowRoundDown)
public static function roundTimespan($start, $end, $minutes, $method = 'default')
{
if ($allowRoundDown) {
return self::defaultRounding($start, $end, $minutes);
switch ($method) {
case 'closest':
return self::closestRounding($start, $end, $minutes);
case 'ceil':
return self::ceilRounding($start, $end, $minutes);
case 'default':
default:
return self::defaultRounding($start, $end, $minutes);
}

return self::ceilRounding($start, $end, $minutes);
}

// --- default

/**
* @param int $start
* @param int $end
* @param int $minutes
* @return array
*/
private static function defaultRounding($start, $end, $minutes)
{
$roundedStart = self::getDefaultRoundingStart($start, $minutes);
Expand Down Expand Up @@ -85,6 +96,81 @@ private static function getDefaultRoundingEnd($end, $minutes)
return $timestamp - $diff + $seconds;
}

// --- closest

/**
* @param int $start
* @param int $end
* @param int $minutes
* @return array
*/
private static function closestRounding($start, $end, $minutes)
{
$roundedStart = self::getClosestRoundingStart($start, $minutes);
$roundedEnd = self::getClosestRoundingEnd($end, $minutes);

return [
'start' => $roundedStart !== null ? $roundedStart : $start,
'end' => $roundedEnd !== null ? $roundedEnd : $end,
];
}

/**
* @param int $start
* @param int $minutes
*
* @return float|int|null
*/
private static function getClosestRoundingStart($start, $minutes)
{
if ($minutes <= 0) {
return null;
}

$timestamp = $start;
$seconds = $minutes * 60;
$diff = $timestamp % $seconds;

if (0 === $diff) {
return $start;
}

if ($diff > ($seconds / 2)) {
return $timestamp - $diff + $seconds;
}

return $timestamp - $diff;
}

/**
* @param int $end
* @param int $minutes
*
* @return float|int|null
*/
private static function getClosestRoundingEnd($end, $minutes)
{
if ($minutes <= 0) {
return null;
}

$timestamp = $end;
$seconds = $minutes * 60;
$diff = $timestamp % $seconds;

if (0 === $diff) {
return $end;
}

if ($diff > ($seconds / 2)) {
return $timestamp - $diff + $seconds;
}

return $timestamp - $diff;
}

// --- ceil

/**
* @param int $start
* @param int $end
Expand Down
12 changes: 6 additions & 6 deletions tests/library/Kimai/RoundingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function testRoundTimespanWithStepsZero()
{
$start = time() - 3600;
$end = time() + 3600;
$actual = Kimai_Rounding::roundTimespan($start, $end, 0, true);
$actual = Kimai_Rounding::roundTimespan($start, $end, 0, 'default');

$this->assertInternalType('array', $actual);
$this->assertArrayHasKey('start', $actual);
Expand All @@ -50,7 +50,7 @@ public function testRoundTimespanWithSteps15MinAndNoRoundDownOnExactStep()
{
$start = strtotime('2019-10-26T17:00:00+00:00');
$end = strtotime('2019-10-26T17:15:00+00:00');
$actual = Kimai_Rounding::roundTimespan($start, $end, 15, false);
$actual = Kimai_Rounding::roundTimespan($start, $end, 15, 'ceil');

$this->assertInternalType('array', $actual);
$this->assertArrayHasKey('start', $actual);
Expand All @@ -67,7 +67,7 @@ public function testRoundTimespanWithSteps15MinAndNoRoundDownOnAnyMinute()
{
$start = strtotime('2019-10-26T17:05:00+00:00'); // round up to 17:15
$end = strtotime('2019-10-26T17:20:00+00:00'); // round up to 17:30
$actual = Kimai_Rounding::roundTimespan($start, $end, 15, false);
$actual = Kimai_Rounding::roundTimespan($start, $end, 15, 'ceil');

$this->assertInternalType('array', $actual);
$this->assertArrayHasKey('start', $actual);
Expand All @@ -84,7 +84,7 @@ public function testRoundTimespanWithSteps15MinAndRoundDownOnExactStep(){

$start = strtotime('2019-10-26T17:00:00+00:00');
$end = strtotime('2019-10-26T17:15:00+00:00');
$actual = Kimai_Rounding::roundTimespan($start, $end, 15, true);
$actual = Kimai_Rounding::roundTimespan($start, $end, 15, 'default');

$this->assertInternalType('array', $actual);
$this->assertArrayHasKey('start', $actual);
Expand All @@ -101,7 +101,7 @@ public function testRoundTimespanWithSteps15MinAndRoundDown(){

$start = strtotime('2019-10-26T17:05:00+00:00'); // round down to 17:00
$end = strtotime('2019-10-26T17:16:00+00:00'); // round up to 17:30
$actual = Kimai_Rounding::roundTimespan($start, $end, 15, true);
$actual = Kimai_Rounding::roundTimespan($start, $end, 15, 'default');

$this->assertInternalType('array', $actual);
$this->assertArrayHasKey('start', $actual);
Expand All @@ -118,7 +118,7 @@ public function testRoundTimespan()
{
$start = strtotime('2016-03-19T16:59:33+00:00'); // round down to 16:45
$end = strtotime('2016-03-19T18:46:17+00:00'); // round up to 19:00
$actual = Kimai_Rounding::roundTimespan($start, $end, 15, true);
$actual = Kimai_Rounding::roundTimespan($start, $end, 15, 'default');

$this->assertInternalType('array', $actual);
$this->assertArrayHasKey('start', $actual);
Expand Down
Loading

0 comments on commit 697a379

Please sign in to comment.