diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index a35cd1e63c02..39662af39b53 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -503,7 +503,13 @@ class CompanySettings extends BaseSettings public $enable_rappen_rounding = false; + public bool $task_round_up = true; + + public int $task_round_to_nearest = 1; + public static $casts = [ + 'task_round_up' => 'bool', + 'task_round_to_nearest' => 'int', 'e_quote_type' => 'string', 'enable_rappen_rounding' => 'bool', 'use_unapplied_payment' => 'string', diff --git a/app/Repositories/TaskRepository.php b/app/Repositories/TaskRepository.php index 31e680fa9d98..1778c83ea86e 100644 --- a/app/Repositories/TaskRepository.php +++ b/app/Repositories/TaskRepository.php @@ -27,6 +27,10 @@ class TaskRepository extends BaseRepository private $completed = true; + private bool $task_round_up = true; + + private int $task_round_to_nearest = 1; + /** * Saves the task and its contacts. * @@ -44,6 +48,8 @@ class TaskRepository extends BaseRepository $task->fill($data); $task->saveQuietly(); + $this->init($task); + if ($this->new_task && ! $task->status_id) { $task->status_id = $this->setDefaultStatus($task); } @@ -105,6 +111,11 @@ class TaskRepository extends BaseRepository $key_values = array_column($time_log, 0); array_multisort($key_values, SORT_ASC, $time_log); + foreach($time_log as $key => $value) + { + $time_log[$key][1] = $this->roundTimeLog($time_log[$key][1]); + } + if (isset($data['action'])) { if ($data['action'] == 'start') { $task->is_running = true; @@ -126,8 +137,6 @@ class TaskRepository extends BaseRepository $task->time_log = json_encode($time_log); - - $task->saveQuietly(); if (array_key_exists('documents', $data)) { @@ -243,14 +252,27 @@ class TaskRepository extends BaseRepository return $task; } + public function roundTimeLog(int $end_time): int + { + if($this->task_round_to_nearest == 1) + return $end_time; + + if($this->task_round_up) + return (int)ceil($end_time/$this->task_round_to_nearest)*$this->task_round_to_nearest; + + return (int)floor($end_time/$this->task_round_to_nearest) * $this->task_round_to_nearest; + } + public function stop(Task $task) { + $this->init($task); + $log = json_decode($task->time_log, true); $last = end($log); if (is_array($last) && $last[1] === 0) { - $last[1] = time(); + $last[1] = $this->roundTimeLog(time()); array_pop($log); $log = array_merge($log, [$last]);//check at this point, it may be prepending here. @@ -275,6 +297,15 @@ class TaskRepository extends BaseRepository return $task; } + private function init(Task $task): self + { + + $this->task_round_up = $task->client ? $task->client->getSetting('task_round_up') : $task->company->getSetting('task_round_up'); + $this->task_round_to_nearest = $task->client ? $task->client->getSetting('task_round_to_nearest') : $task->company->getSetting('task_round_to_nearest'); + + return $this; + + } private function trySaving(Task $task) { diff --git a/tests/Feature/TaskApiTest.php b/tests/Feature/TaskApiTest.php index c84201a1b7d3..ebd881225e51 100644 --- a/tests/Feature/TaskApiTest.php +++ b/tests/Feature/TaskApiTest.php @@ -104,6 +104,64 @@ class TaskApiTest extends TestCase } } + public function testRoundingViaApi() + { + + $data = [ + 'client_id' => $this->client->hashed_id, + 'description' => 'Test Task', + 'time_log' => '[[1681165417,1681165432,"sumtin",true],[1681165446,0]]', + 'assigned_user' => [], + 'project' => [], + 'user' => [], + // 'status' => [], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson("/api/v1/tasks", $data); + + $response->assertStatus(200); + + } + + public function testRoundingToNearestXXX() + { + + $time = 1680036807; + + $round_up_to_next_minute = ceil($time / 60) * 60; + $round_down_to_next_minute = floor($time / 60) * 60; + $this->assertEquals(1680036840, $round_up_to_next_minute); + $this->assertEquals(1680036780, $round_down_to_next_minute); + + $round_up_to_next_minute = ceil($round_up_to_next_minute / 3600) * 3600; + $round_down_to_next_minute = floor($round_down_to_next_minute / 3600) * 3600; + $this->assertEquals(1680037200, $round_up_to_next_minute); + $this->assertEquals(1680033600, $round_down_to_next_minute); + + } + + public function testKsortPerformance() + { + $logs = [ + [1680035007,1680036807,"",true], + [1681156840,1681158000,"",true], + [1680302433,1680387960,"",true], + [1680715620,1680722820,"",true], + [1,1680737460,"",true] + ]; + + $key_values = array_column($logs, 0); + array_multisort($key_values, SORT_ASC, $logs); + + $start = $logs[0]; + + $this->assertEquals(1, $start[0]); + + } + public function testRequestRuleParsing() { @@ -393,26 +451,6 @@ class TaskApiTest extends TestCase } - - public function testKsortPerformance() - { - $logs = [ - [1680035007,1680036807,"",true], - [1681156840,1681158000,"",true], - [1680302433,1680387960,"",true], - [1680715620,1680722820,"",true], - [1,1680737460,"",true] - ]; - - $key_values = array_column($logs, 0); - array_multisort($key_values, SORT_ASC, $logs); - - $start = $logs[0]; - - $this->assertEquals(1, $start[0]); - - } - public function testStartStopSanity() {