diff --git a/config/packages/kimai.yaml b/config/packages/kimai.yaml index b4d8f6ee..b454dc2c 100644 --- a/config/packages/kimai.yaml +++ b/config/packages/kimai.yaml @@ -19,13 +19,14 @@ kimai: # Rounding rules are used to round the begin & end dates and the duration for timesheet records. # The "default" rule will round "begin" down and "end" up to the full minute, the "duration" will not be rounded. - # Please read var/docs/configurations.md to find out more about rounding rules + # Find out more about rounding rules at https://www.kimai.org/documentation/timesheet.html rounding: default: days: ['monday','tuesday','wednesday','thursday','friday','saturday','sunday'] begin: 1 end: 1 duration: 0 + mode: default # If you want to apply different hourly rates for specific weekdays, you can uncomment the "rates" configuration. # The "weekend" rule will add 50% to each timesheet entry that will be recorded on "saturdays" or "sundays". @@ -69,7 +70,7 @@ kimai: # currency: EUR # -------------------------------------------------------------------------------- - # Free configurable permission system, see var/docs/permissions.md + # Find out more about the configurable permission system at https://www.kimai.org/documentation/permissions.html permissions: sets: # mapping complex rulesets of single permissions to named "sets" ("set name" = [array of "permissions"]) @@ -186,7 +187,7 @@ kimai: end: '20:00' # You can configure unlimited google calendars to display events for your company (e.g. holidays) - # Please read var/docs/configurations.md to find out more about calendar integration + # Find out more about calendar integration at https://www.kimai.org/documentation/calendar.html # google: # api_key: 'your-restricted-google-api-key' # sources: @@ -235,7 +236,7 @@ kimai: widgets: [amountToday, amountWeek, amountMonth, amountYear] # -------------------------------------------------------------------------------- - # All available widgets, please see documentation at var/docs/dashboard.md + # Find out more about dashboard widgets at https://www.kimai.org/documentation/dashboard.html widgets: userDurationToday: { title: stats.durationToday, query: duration, user: true, begin: '00:00:00', end: '23:59:59', icon: duration, color: green } userDurationWeek: { title: stats.durationWeek, query: duration, user: true, begin: 'monday this week 00:00:00', end: 'sunday this week 23:59:59', icon: duration, color: blue } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 822ad27a..5f358eac 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -11,6 +11,7 @@ namespace App\DependencyInjection; use App\Model\DashboardSection; use App\Model\Widget; +use App\Timesheet\Rounding\RoundingInterface; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; @@ -81,6 +82,21 @@ class Configuration implements ConfigurationInterface ->integerNode('duration') ->defaultValue(0) ->end() + ->scalarNode('mode') + ->defaultValue('default') + ->validate() + ->thenInvalid('Chosen rounding mode is invalid') + ->ifTrue(function ($value) { + $class = 'App\\Timesheet\\Rounding\\' . ucfirst($value) . 'Rounding'; + if (class_exists($class)) { + $rounding = new $class(); + return !($rounding instanceof RoundingInterface); + } + return false; + }) + ->thenInvalid('Chosen rounding mode is invalid') + ->end() + ->end() ->end() ->end() ->defaultValue([]) diff --git a/src/Timesheet/Calculator/DurationCalculator.php b/src/Timesheet/Calculator/DurationCalculator.php index 76358912..94dff3b0 100644 --- a/src/Timesheet/Calculator/DurationCalculator.php +++ b/src/Timesheet/Calculator/DurationCalculator.php @@ -11,6 +11,7 @@ namespace App\Timesheet\Calculator; use App\Entity\Timesheet; use App\Timesheet\CalculatorInterface; +use App\Timesheet\Rounding\RoundingInterface; /** * Implementation to calculate the durations for a timesheet record. @@ -66,74 +67,14 @@ class DurationCalculator implements CalculatorInterface $days = array_map('strtolower', $rounding['days']); if (in_array(strtolower($weekday), $days)) { - $this->roundBegin($record, $rounding['begin']); - $this->roundEnd($record, $rounding['end']); + $class = 'App\\Timesheet\\Rounding\\' . ucfirst($rounding['mode']) . 'Rounding'; + /* @var $rounder RoundingInterface */ + $rounder = new $class(); + $rounder->roundBegin($record, $rounding['begin']); + $rounder->roundEnd($record, $rounding['end']); $this->applyDuration($record); - $this->roundDuration($record, $rounding['duration']); + $rounder->roundDuration($record, $rounding['duration']); } } } - - /** - * @param Timesheet $record - * @param int $minutes - */ - protected function roundBegin(Timesheet $record, $minutes) - { - if ($minutes <= 0) { - return; - } - - $timestamp = $record->getBegin()->getTimestamp(); - $seconds = $minutes * 60; - $diff = $timestamp % $seconds; - - if (0 === $diff) { - return; - } - - $record->getBegin()->setTimestamp($timestamp - $diff); - } - - /** - * @param Timesheet $record - * @param int $minutes - */ - protected function roundEnd(Timesheet $record, $minutes) - { - if ($minutes <= 0) { - return; - } - - $timestamp = $record->getEnd()->getTimestamp(); - $seconds = $minutes * 60; - $diff = $timestamp % $seconds; - - if (0 === $diff) { - return; - } - - $record->getEnd()->setTimestamp($timestamp - $diff + $seconds); - } - - /** - * @param Timesheet $record - * @param int $minutes - */ - protected function roundDuration(Timesheet $record, $minutes) - { - if ($minutes <= 0) { - return; - } - - $timestamp = $record->getDuration(); - $seconds = $minutes * 60; - $diff = $timestamp % $seconds; - - if (0 === $diff) { - return; - } - - $record->setDuration($timestamp - $diff + $seconds); - } } diff --git a/src/Timesheet/Rounding/ClosestRounding.php b/src/Timesheet/Rounding/ClosestRounding.php new file mode 100644 index 00000000..8e2fb768 --- /dev/null +++ b/src/Timesheet/Rounding/ClosestRounding.php @@ -0,0 +1,90 @@ +getBegin()->getTimestamp(); + $seconds = $minutes * 60; + $diff = $timestamp % $seconds; + + if (0 === $diff) { + return; + } + + if ($diff > ($seconds / 2)) { + $record->getBegin()->setTimestamp($timestamp - $diff + $seconds); + } else { + $record->getBegin()->setTimestamp($timestamp - $diff); + } + } + + /** + * @param Timesheet $record + * @param int $minutes + */ + public function roundEnd(Timesheet $record, $minutes) + { + if ($minutes <= 0) { + return; + } + + $timestamp = $record->getEnd()->getTimestamp(); + $seconds = $minutes * 60; + $diff = $timestamp % $seconds; + + if (0 === $diff) { + return; + } + + if ($diff > ($seconds / 2)) { + $record->getEnd()->setTimestamp($timestamp - $diff + $seconds); + } else { + $record->getEnd()->setTimestamp($timestamp - $diff); + } + } + + /** + * @param Timesheet $record + * @param int $minutes + */ + public function roundDuration(Timesheet $record, $minutes) + { + if ($minutes <= 0) { + return; + } + + $timestamp = $record->getDuration(); + $seconds = $minutes * 60; + $diff = $timestamp % $seconds; + + if (0 === $diff) { + return; + } + + if ($diff > ($seconds / 2)) { + $record->setDuration($timestamp - $diff + $seconds); + } else { + $record->setDuration($timestamp - $diff); + } + } +} diff --git a/src/Timesheet/Rounding/DefaultRounding.php b/src/Timesheet/Rounding/DefaultRounding.php new file mode 100644 index 00000000..2dbdb5e3 --- /dev/null +++ b/src/Timesheet/Rounding/DefaultRounding.php @@ -0,0 +1,78 @@ +getBegin()->getTimestamp(); + $seconds = $minutes * 60; + $diff = $timestamp % $seconds; + + if (0 === $diff) { + return; + } + + $record->getBegin()->setTimestamp($timestamp - $diff); + } + + /** + * @param Timesheet $record + * @param int $minutes + */ + public function roundEnd(Timesheet $record, $minutes) + { + if ($minutes <= 0) { + return; + } + + $timestamp = $record->getEnd()->getTimestamp(); + $seconds = $minutes * 60; + $diff = $timestamp % $seconds; + + if (0 === $diff) { + return; + } + + $record->getEnd()->setTimestamp($timestamp - $diff + $seconds); + } + + /** + * @param Timesheet $record + * @param int $minutes + */ + public function roundDuration(Timesheet $record, $minutes) + { + if ($minutes <= 0) { + return; + } + + $timestamp = $record->getDuration(); + $seconds = $minutes * 60; + $diff = $timestamp % $seconds; + + if (0 === $diff) { + return; + } + + $record->setDuration($timestamp - $diff + $seconds); + } +} diff --git a/src/Timesheet/Rounding/RoundingInterface.php b/src/Timesheet/Rounding/RoundingInterface.php new file mode 100644 index 00000000..982ef41f --- /dev/null +++ b/src/Timesheet/Rounding/RoundingInterface.php @@ -0,0 +1,37 @@ +{{ entry.username }} {{ entry.email }} {{ entry.title }} - {{ widgets.label_visible(entry.enabled) }} {% for role in entry.roles %} {{ widgets.label_role(role) }} {% endfor %} + {{ widgets.label_visible(entry.enabled) }} {% set actionButtons = {} %} {% if is_granted('edit', entry) %} diff --git a/templates/sidebar/settings.html.twig b/templates/sidebar/settings.html.twig index eb003e2b..5b13af81 100644 --- a/templates/sidebar/settings.html.twig +++ b/templates/sidebar/settings.html.twig @@ -10,7 +10,7 @@
  • - {{ macro.avatar(user.avatar, user.username, 'img-circle') }} + {{ macro.avatar(user.avatar, user.username, 'img-circle') }}