diff --git a/timesheet/inc/class.timesheet_bo.inc.php b/timesheet/inc/class.timesheet_bo.inc.php index 59f1f67fc2..deea0a4644 100644 --- a/timesheet/inc/class.timesheet_bo.inc.php +++ b/timesheet/inc/class.timesheet_bo.inc.php @@ -137,6 +137,7 @@ class timesheet_bo extends Api\Storage 'ts_description' => 'Description', 'ts_start' => 'Start', 'ts_duration' => 'Duration', + 'ts_paused' => 'Paused', 'ts_quantity' => 'Quantity', 'ts_unitprice' => 'Unitprice', 'ts_owner' => 'Owner', @@ -506,7 +507,7 @@ class timesheet_bo extends Api\Storage //_debug_array($ids); if(empty($ids)) { - $this->summary = array('duration' => 0, 'price' => null, 'quantity' => 0); + $this->summary = array('duration' => 0, 'paused' => 0, 'price' => null, 'quantity' => 0); return array(); } unset($criteria); @@ -520,6 +521,7 @@ class timesheet_bo extends Api\Storage // is not joined, as the join causes a multiplication of the sum per customfield found // joining of the cutomfield table is triggered by criteria being set with either a string or an array $cols = ['SUM(ts_duration) AS duration', + 'SUM(COALESCE(ts_paused,0)) AS paused', "SUM($total_sql) AS price", 'MAX(ts_modified) AS max_modified']; if($this->quantity_sum) @@ -569,7 +571,7 @@ class timesheet_bo extends Api\Storage parent::search($criteria,array( (string)$sum_ts_id[$type],"''","''","''",'MIN(ts_start)','SUM(ts_duration) AS ts_duration', ($this->quantity_sum ? "SUM(ts_quantity) AS ts_quantity" : '0'), - '0','NULL','0','0','0','0','0','0',"SUM($total_sql) AS ts_total" + '0','NULL','0','0','0','0','0','0',"SUM(COALESCE(ts_paused,0)) AS ts_paused","SUM($total_sql) AS ts_total" ),'GROUP BY '.$sum_sql[$type],$sum_extra_cols,$wildcard,$empty,$op,'UNION',$filter,$join,$need_full_no_count); $sum_extra_cols[$type][0] = '0'; } @@ -792,7 +794,7 @@ class timesheet_bo extends Api\Storage { if(!$ids) { - return array('duration' => 0, 'quantity' => 0, 'price' => 0, 'max_modified' => null); + return array('duration' => 0, 'paused' => 0, 'quantity' => 0, 'price' => 0, 'max_modified' => null); } $filter = []; if($ignore_acl) diff --git a/timesheet/inc/class.timesheet_merge.inc.php b/timesheet/inc/class.timesheet_merge.inc.php index 6f4c8c9f1d..69c8a5b6e3 100644 --- a/timesheet/inc/class.timesheet_merge.inc.php +++ b/timesheet/inc/class.timesheet_merge.inc.php @@ -37,6 +37,7 @@ class timesheet_merge extends Api\Storage\Merge */ protected $numeric_fields = array( '$$ts_duration$$', + '$$ts_paused$$', '$$ts_quantity$$', '$$ts_unitprice$$' ); @@ -132,7 +133,7 @@ class timesheet_merge extends Api\Storage\Merge $array = $record->get_record_array(); $array['ts_total'] = $array['ts_quantity'] * $array['ts_unitprice']; - foreach(array('ts_duration','ts_quantity','ts_unitprice','ts_total') as $key) + foreach(array('ts_duration','ts_paused','ts_quantity','ts_unitprice','ts_total') as $key) { $array[$key] = self::number_format($array[$key],2,$this->mimetype); } @@ -204,4 +205,4 @@ class timesheet_merge extends Api\Storage\Merge } return $placeholders; } -} +} \ No newline at end of file diff --git a/timesheet/inc/class.timesheet_ui.inc.php b/timesheet/inc/class.timesheet_ui.inc.php index 2ece32adf6..ee7a06114a 100644 --- a/timesheet/inc/class.timesheet_ui.inc.php +++ b/timesheet/inc/class.timesheet_ui.inc.php @@ -99,7 +99,7 @@ class timesheet_ui extends timesheet_bo // are we supposed to add pending events, to a new or an existing timesheet if (isset($_REQUEST['events'])) { - $pending = Events::getPending($_REQUEST['events'] === 'overall', $time); + $pending = Events::getPending($_REQUEST['events'] === 'overall', $time, $paused); $this->data['events'] = array_merge($this->data['events'], array_values($pending)); $start = $this->data['events'][0]['tse_time']; $this->data['ts_start'] = $start; @@ -107,6 +107,7 @@ class timesheet_ui extends timesheet_bo $this->data['end_time'] = ''; $this->data['ts_duration'] = (int)$this->data['ts_duration'] + round($time / 60); // minutes $this->data['ts_quantity'] = (float)$this->data['ts_quantity'] + $this->data['ts_duration'] / 60.0; // hours + $this->data['ts_paused'] = $paused ? round($paused / 60.0) : null; // check if any of the events contains an app::id to link the timesheet to foreach($pending as $event) { diff --git a/timesheet/lang/egw_de.lang b/timesheet/lang/egw_de.lang index 24ed546aac..4bae7ce516 100644 --- a/timesheet/lang/egw_de.lang +++ b/timesheet/lang/egw_de.lang @@ -108,6 +108,8 @@ overwrite time common de Zeit überschreiben overwriting start or stop time timesheet de Überschreiben der Start- oder Stop-Zeit parent admin de Übergeordnet pause common de Pause +pause time timesheet de Pausenzeit +paused timesheet de Pausen permission denied!!! timesheet de Zugriff verweigert! permissions error - %1 could not %2 timesheet de Fehler in den Zugriffsberechtigungen - %1 nicht möglich %2 prevent deleting admin de Verhindert Löschung diff --git a/timesheet/lang/egw_en.lang b/timesheet/lang/egw_en.lang index 9183a8de92..b1624f054d 100644 --- a/timesheet/lang/egw_en.lang +++ b/timesheet/lang/egw_en.lang @@ -108,6 +108,8 @@ overwrite time common en Overwrite time overwriting start or stop time timesheet en Overwriting start or stop time parent admin en Parent pause common en Pause +pause time timesheet en Pause time +paused timesheet en Paused permission denied!!! timesheet en Permission denied! permissions error - %1 could not %2 timesheet en Permissions error - %1 could not %2 prevent deleting admin en Prevent deleting diff --git a/timesheet/setup/setup.inc.php b/timesheet/setup/setup.inc.php index 2dde50bca4..fe84a80c84 100644 --- a/timesheet/setup/setup.inc.php +++ b/timesheet/setup/setup.inc.php @@ -16,7 +16,7 @@ if (!defined('TIMESHEET_APP')) } $setup_info[TIMESHEET_APP]['name'] = TIMESHEET_APP; -$setup_info[TIMESHEET_APP]['version'] = '23.1'; +$setup_info[TIMESHEET_APP]['version'] = '23.1.001'; $setup_info[TIMESHEET_APP]['app_order'] = 5; $setup_info[TIMESHEET_APP]['tables'] = array('egw_timesheet','egw_timesheet_extra','egw_timesheet_events'); $setup_info[TIMESHEET_APP]['enable'] = 1; @@ -52,4 +52,4 @@ $setup_info[TIMESHEET_APP]['hooks']['config_validate'] = 'EGroupware\\Timesheet\ $setup_info[TIMESHEET_APP]['depends'][] = array( 'appname' => 'api', 'versions' => Array('23.1') -); \ No newline at end of file +); diff --git a/timesheet/setup/tables_current.inc.php b/timesheet/setup/tables_current.inc.php index 1e588df2e9..5b33203b6f 100644 --- a/timesheet/setup/tables_current.inc.php +++ b/timesheet/setup/tables_current.inc.php @@ -19,7 +19,7 @@ $phpgw_baseline = array( 'ts_title' => array('type' => 'varchar','precision' => '255','nullable' => False,'comment' => 'title of the timesheet entry'), 'ts_description' => array('type' => 'varchar','precision' => '16384','comment' => 'description of the timesheet entry'), 'ts_start' => array('type' => 'int','meta' => 'timestamp','precision' => '8','nullable' => False,'comment' => 'timestamp of the startdate'), - 'ts_duration' => array('type' => 'int','precision' => '8','nullable' => False,'default' => '0','comment' => 'duration of the timesheet-entry'), + 'ts_duration' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0','comment' => 'duration of the timesheet-entry'), 'ts_quantity' => array('type' => 'float','precision' => '8','nullable' => False,'comment' => 'quantity'), 'ts_unitprice' => array('type' => 'float','precision' => '4','comment' => 'unitprice'), 'cat_id' => array('type' => 'int','meta' => 'category','precision' => '4','default' => '0','comment' => 'category'), @@ -28,7 +28,8 @@ $phpgw_baseline = array( 'ts_modifier' => array('type' => 'int','meta' => 'user','precision' => '4','nullable' => False,'comment' => 'account id of the last modifier'), 'pl_id' => array('type' => 'int','precision' => '4','default' => '0','comment' => 'id of the linked project'), 'ts_status' => array('type' => 'int','precision' => '4','comment' => 'status of the timesheet-entry'), - 'ts_created' => array('type' => 'int','meta' => 'timestamp','precision' => '8','nullable' => False,'comment' => 'Creation date of the timesheet') + 'ts_created' => array('type' => 'int','meta' => 'timestamp','precision' => '8','nullable' => False,'comment' => 'Creation date of the timesheet'), + 'ts_paused' => array('type' => 'int','precision' => '4','default' => '0','comment' => 'pause time(s) of the timesheet-entry') ), 'pk' => array('ts_id'), 'fk' => array(), @@ -64,4 +65,4 @@ $phpgw_baseline = array( 'ix' => array('ts_id'), 'uc' => array('tse_id') ) -); +); \ No newline at end of file diff --git a/timesheet/setup/tables_update.inc.php b/timesheet/setup/tables_update.inc.php index f353b11b90..5dfc263c9f 100644 --- a/timesheet/setup/tables_update.inc.php +++ b/timesheet/setup/tables_update.inc.php @@ -233,4 +233,15 @@ function timesheet_upgrade21_1() function timesheet_upgrade22_1() { return $GLOBALS['setup_info']['timesheet']['currentver'] = '23.1'; +} +function timesheet_upgrade23_1() +{ + $GLOBALS['egw_setup']->oProc->AddColumn('egw_timesheet','ts_paused',array( + 'type' => 'int', + 'precision' => '4', + 'default' => '0', + 'comment' => 'pause time(s) of the timesheet-entry' + )); + + return $GLOBALS['setup_info']['timesheet']['currentver'] = '23.1.001'; } \ No newline at end of file diff --git a/timesheet/src/Events.php b/timesheet/src/Events.php index a5ff8bee19..184121e4cd 100644 --- a/timesheet/src/Events.php +++ b/timesheet/src/Events.php @@ -218,17 +218,18 @@ class Events extends Api\Storage\Base */ public function storeWorkingTime() { - if (!($events = self::getPending(true, $time)) || !$time) + if (!($events = self::getPending(true, $time, $paused)) || !$time) { throw new Api\Exception\AssertionFailed("No pending overall events!"); } $ids = array_keys($events); $bo = new \timesheet_bo(); - // check if we already have a timesheet for the current periode + // check if we already have a timesheet for the current period if (($period_ts = $bo->periodeWorkingTimesheet(reset($events)['tse_time']))) { - $events = array_merge(self::get(['ts_id' => $period_ts['ts_id']], $period_total), $events); + $events = array_merge(self::get(['ts_id' => $period_ts['ts_id']], $period_total, $period_paused), $events); $time += $period_total; + $paused += $period_paused; } $title = self::workingTimeTitle($events, $start); $bo->init($period_ts); @@ -240,6 +241,7 @@ class Events extends Api\Storage\Base 'end_time' => '', 'ts_duration' => $minutes = round($time / 60), 'ts_quantity' => $minutes / 60.0, + 'ts_paused' => round($paused / 60), 'ts_owner' => $this->user, ]); self::addToTimesheet($bo->data['ts_id'], $ids); @@ -351,6 +353,15 @@ class Events extends Api\Storage\Base */ protected static function evaluate(array &$timer, array $row) { + // paused timer is started or stopped + if ($timer['paused'] && !($row['tse_type'] & self::PAUSE)) + { + $timer['was_paused'] = 60000 * round(($row['tse_time']->getTimestamp() - $timer['pause_started']->getTimestamp())/60); + } + else + { + unset($timer['was_paused']); + } if ($row['tse_type'] & self::START) { $timer['start'] = $timer['started'] = $row['tse_time']; @@ -367,6 +378,10 @@ class Events extends Api\Storage\Base { $timer['paused'] = ($row['tse_type'] & self::PAUSE) === self::PAUSE; } + if ($timer['paused']) + { + $timer['pause_started'] = $row['tse_time']; + } $timer['last'] = $row['tse_time']; $timer['id'] = $row['tse_id']; return $time ?? null; @@ -378,10 +393,11 @@ class Events extends Api\Storage\Base * Not stopped events-sequences are NOT returned (stopped sequences end with a stop event). * * @param int|array $filter - * @param int &$total=null on return time in seconds + * @param ?int &$total=null on return time in seconds + * @param ?int &$paused on return paused time in seconds * @return array[] tse_id => array pairs plus extra key sum (time-sum in seconds) */ - public static function get($filter, int &$total=null) + public static function get($filter, ?int &$total=null, ?int &$paused=null) { if (!is_array($filter)) { @@ -392,7 +408,7 @@ class Events extends Api\Storage\Base 'offset' => 0, 'paused' => false, ]; - $total = $open = 0; + $total = $open = $paused = 0; $events = []; foreach(self::getInstance()->search('', false, 'tse_id', '', '', false, 'AND', false, $filter) as $row) @@ -411,6 +427,7 @@ class Events extends Api\Storage\Base $row['total'] = $total + $timer['offset'] / 1000; } $row['time'] = $time / 1000; + $row['paused'] = !empty($timer['was_paused']) ? $paused += $timer['was_paused']/1000 : null; $events[$row['tse_id']] = $row; } // remove open / unstopped timer events @@ -427,16 +444,17 @@ class Events extends Api\Storage\Base * Not stopped events-sequences are NOT returned (stopped sequences end with a stop event). * * @param bool $overall - * @param int &$time=null on return total time in seconds + * @param ?int &$time=null on return total time in seconds + * @param ?int &$paused=null on return total paused time in seconds * @return array[] tse_id => array pairs */ - public static function getPending($overall=false, int &$time=null) + public static function getPending($overall=false, ?int &$time=null, ?int &$paused=null) { return self::get([ 'ts_id' => null, 'account_id' => self::getInstance()->user, ($overall ? '' : 'NOT ').'(tse_type & '.self::OVERALL.')', - ], $time); + ], $time, $paused); } /** diff --git a/timesheet/src/JsTimesheet.php b/timesheet/src/JsTimesheet.php index 9454b2a669..0a78f611ef 100644 --- a/timesheet/src/JsTimesheet.php +++ b/timesheet/src/JsTimesheet.php @@ -52,6 +52,7 @@ class JsTimesheet extends Api\CalDAV\JsBase 'description' => $timesheet['description'], 'start' => self::UTCDateTime($timesheet['start'], true), 'duration' => (int)$timesheet['duration'], + 'paused' => (int)$timesheet['paused'], 'project' => $timesheet['project_blur'] ?? null, 'pm_id' => !empty($timesheet['pm_id']) ? (int)$timesheet['pm_id'] : null, 'quantity' => (double)$timesheet['quantity'], @@ -132,6 +133,10 @@ class JsTimesheet extends Api\CalDAV\JsBase } break; + case 'paused': + $timesheet['ts_paused'] = self::parseInt($value); + break; + case 'pricelist': $timesheet['pl_id'] = self::parseInt($value); break; diff --git a/timesheet/templates/default/edit.xet b/timesheet/templates/default/edit.xet index 0f872dde79..03a8cfb2e0 100644 --- a/timesheet/templates/default/edit.xet +++ b/timesheet/templates/default/edit.xet @@ -38,15 +38,13 @@ - - - - + - - + + + @@ -86,6 +84,7 @@ + @@ -93,6 +92,7 @@ + @@ -100,6 +100,7 @@ + diff --git a/timesheet/templates/default/index.xet b/timesheet/templates/default/index.xet index f4d6e31fc8..6f93fe71fa 100644 --- a/timesheet/templates/default/index.xet +++ b/timesheet/templates/default/index.xet @@ -19,6 +19,7 @@ + @@ -54,16 +55,20 @@ - + + + + + - + - + @@ -80,8 +85,8 @@ - + +