Initial revision

This commit is contained in:
Ralf Becker 2005-12-19 04:23:14 +00:00
parent 809768937d
commit 9f638e4f08
16 changed files with 1420 additions and 0 deletions

View File

@ -0,0 +1,447 @@
<?php
/**************************************************************************\
* eGroupWare - TimeSheet: business object *
* http://www.eGroupWare.org *
* Written and (c) 2005 by Ralf Becker <RalfBecker@outdoor-training.de> *
* ------------------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
require_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php');
if (!defined('TIMESHEET_APP'))
{
define('TIMESHEET_APP','timesheet');
}
/**
* Business object of the TimeSheet
*
* Uses eTemplate's so_sql as storage object (Table: egw_timesheet).
*
* @package timesheet
* @author RalfBecker-AT-outdoor-training.de
* @copyright (c) 2005 by RalfBecker-AT-outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
class botimesheet extends so_sql
{
/**
* @var array $config timesheets config data
*/
var $config = array();
/**
* @var array $timestamps timestaps that need to be adjusted to user-time on reading or saving
*/
var $timestamps = array(
'ts_start','ts_modified'
);
/**
* @var int $tz_offset_s offset in secconds between user and server-time,
* it need to be add to a server-time to get the user-time or substracted from a user-time to get the server-time
*/
var $tz_offset_s;
/**
* @var int $now actual user-time as timestamp
*/
var $now;
/**
* @var int $today start of today in user-time
*/
var $today;
/**
* @var array $date_filters filter for search limiting the date-range
*/
var $date_filters = array( // Start: year,month,day,week, End: year,month,day,week
'Today' => array(0,0,0,0, 0,0,1,0),
'Yesterday' => array(0,0,-1,0, 0,0,0,0),
'This week' => array(0,0,0,0, 0,0,0,1),
'Last week' => array(0,0,0,-1, 0,0,0,0),
'This month' => array(0,0,0,0, 0,1,0,0),
'Last month' => array(0,-1,0,0, 0,0,0,0),
'2 month ago' => array(0,-2,0,0, 0,-1,0,0),
'This year' => array(0,0,0,0, 1,0,0,0),
'Last year' => array(-1,0,0,0, 0,0,0,0),
'2 years ago' => array(-2,0,0,0, -1,0,0,0),
'3 years ago' => array(-3,0,0,0, -2,0,0,0),
);
function botimesheet()
{
$this->so_sql(TIMESHEET_APP,'egw_timesheet');
$config =& CreateObject('phpgwapi.config',TIMESHEET_APP);
$config->read_repository();
$this->config =& $config->config_data;
unset($config);
if (!is_object($GLOBALS['egw']->datetime))
{
$GLOBALS['egw']->datetime =& CreateObject('phpgwapi.datetime');
}
$this->tz_offset_s = $GLOBALS['egw']->datetime->tz_offset;
$this->now = time() + $this->tz_offset_s; // time() is server-time and we need a user-time
$this->today = mktime(0,0,0,date('m',$this->now),date('d',$this->now),date('Y',$this->now));
// save us in $GLOBALS['botimesheet'] for ExecMethod used in hooks
if (!is_object($GLOBALS['botimesheet']))
{
$GLOBALS['botimesheet'] =& $this;
}
// instanciation of link-class has to be after making us globaly availible, as it calls us to get the search_link
if (!is_object($GLOBALS['egw']->link))
{
$GLOBALS['egw']->link =& CreateObject('phpgwapi.bolink');
}
$this->link =& $GLOBALS['egw']->link;
$this->grants = $GLOBALS['egw']->acl->get_grants(TIMESHEET_APP);
}
/**
* get list of specified grants as uid => Username pairs
*
* @param int $required=EGW_ACL_READ
* @return array with uid => Username pairs
*/
function grant_list($required=EGW_ACL_READ)
{
$result = array();
foreach($this->grants as $uid => $grant)
{
if ($grant & $required)
{
$result[$uid] = $GLOBALS['egw']->common->grab_owner_name($uid);
}
}
natcasesort($result);
return $result;
}
/**
* checks if the user has enough rights for a certain operation
*
* Rights are given via owner grants or role based acl
*
* @param int $required EGW_ACL_READ, EGW_ACL_WRITE, EGW_ACL_ADD, EGW_ACL_DELETE, EGW_ACL_BUDGET, EGW_ACL_EDIT_BUDGET
* @param array/int $data=null project or project-id to use, default the project in $this->data
* @return boolean true if the rights are ok, false if not
*/
function check_acl($required,$data=null)
{
if (!$data)
{
$data =& $this->data;
}
if (!is_array($data))
{
$save_data = $this->data;
$data = $this->read($data,true);
$this->data = $save_data;
}
$rights = $this->grants[$data['ts_owner']];
return $data && !!($rights & $required);
}
function date_filter($name)
{
if (!isset($this->date_filters[$name]))
{
return false;
}
$year = (int) date('Y',$this->today);
$month = (int) date('m',$this->today);
$day = (int) date('d',$this->today);
list($syear,$smonth,$sday,$sweek,$eyear,$emonth,$eday,$eweek) = $this->date_filters[$name];
if ($syear || $eyear)
{
$start = mktime(0,0,0,1,1,$syear+$year);
$end = mktime(0,0,0,1,1,$eyear+$year);
}
elseif ($smonth || $emonth)
{
$start = mktime(0,0,0,$smonth+$month,1,$year);
$end = mktime(0,0,0,$emonth+$month,1,$year);
}
elseif ($sday || $eday)
{
$start = mktime(0,0,0,$month,$sday+$day,$year);
$end = mktime(0,0,0,$month,$eday+$day,$year);
}
elseif ($sweek || $eweek)
{
$wday = (int) date('w',$this->today); // 0=sun, ..., 6=sat
switch($GLOBALS['egw_info']['user']['preferences']['calendar']['weekdaystarts'])
{
case 'Sunday':
$weekstart = $this->today - $wday * 24*60*60;
break;
case 'Saturday':
$weekstart = $this->today - (6-$wday) * 24*60*60;
break;
case 'Moday':
default:
$weekstart = $this->today - ($wday ? $wday-1 : 6) * 24*60*60;
break;
}
$start = $weekstart + $sweek*7*24*60*60;
$end = $weekstart + $eweek*7*24*60*60;
// todo
}
//echo "<p align='right'>date_filter($name) today=".date('l, Y-m-d H:i',$this->today)." ==> ".date('l, Y-m-d H:i:s',$start)." <= date < ".date('l, Y-m-d H:i:s',$end)."</p>\n";
// convert start + end from user to servertime
$start -= $this->tz_offset_s;
$end -= $this->tz_offset_s;
return "($start <= ts_start AND ts_start < $end)";
}
/**
* search the timesheet
*
* reimplemented to limit result to users we have grants from
*
* @param array/string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!)
* @param boolean/string $only_keys=true True returns only keys, False returns all cols. comma seperated list of keys to return
* @param string $order_by='' fieldnames + {ASC|DESC} separated by colons ',', can also contain a GROUP BY (if it contains ORDER BY)
* @param string/array $extra_cols='' string or array of strings to be added to the SELECT, eg. "count(*) as num"
* @param string $wildcard='' appended befor and after each criteria
* @param boolean $empty=false False=empty criteria are ignored in query, True=empty have to be empty in row
* @param string $op='AND' defaults to 'AND', can be set to 'OR' too, then criteria's are OR'ed together
* @param mixed $start=false if != false, return only maxmatch rows begining with start, or array($start,$num)
* @param array $filter=null if set (!=null) col-data pairs, to be and-ed (!) into the query without wildcards
* @param string $join='' sql to do a join, added as is after the table-name, eg. ", table2 WHERE x=y" or
* "LEFT JOIN table2 ON (x=y)", Note: there's no quoting done on $join!
* @param boolean $need_full_no_count=false If true an unlimited query is run to determine the total number of rows, default false
* @return array of matching rows (the row is an array of the cols) or False
*/
function &search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='',$need_full_no_count=false)
{
if (!$extra_cols) $extra_cols = 'ts_quantity*ts_unitprice AS ts_total';
if (!isset($filter['ts_owner']) || !count($filter['ts_owner']))
{
$filter['ts_owner'] = array_keys($this->grants);
}
else
{
if (!is_array($filter['ts_owner'])) $filter['ts_owner'] = array($filter['ts_owner']);
foreach($filter['ts_owner'] as $key => $owner)
{
if (!isset($this->grants[$owner]))
{
unset($filter['ts_owner'][$key]);
}
}
}
if (!count($filter['ts_owner']))
{
$this->total = 0;
return array();
}
$this->summary = parent::search($criteria,'SUM(ts_duration) AS duration,SUM(ts_quantity*ts_unitprice) AS price',
'','',$wildcard,$empty,$op,false,$filter,$join);
$this->summary = $this->summary[0];
return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
}
/**
* read a timesheet entry
*
* @param int $ts_id
* @param boolean $ignore_acl=false should the acl be checked
* @return array/boolean array with timesheet entry or false if no rights
*/
function read($ts_id,$ignore_acl=false)
{
if (!(int)$ts_id || !$ignore_acl && !$this->check_acl(EGW_ACL_READ,$ts_id) ||
$this->data['ts_id'] != (int)$ts_id && !parent::read((int)$ts_id))
{
return false; // no read rights, or entry not found
}
return $this->data;
}
/**
* saves a timesheet entry
*
* reimplemented to notify the link-class
*
* @param array $keys if given $keys are copied to data before saveing => allows a save as
* @param boolean $touch_modified=true should modification date+user be set, default yes
* @param boolean $ignore_acl=false should the acl be checked, returns true if no edit-rigts
* @return int 0 on success and errno != 0 else
*/
function save($keys=null,$touch_modified=true,$ignore_acl=false)
{
if ($keys) $this->data_merge($keys);
if (!$ignore_acl && $this->data['ts_id'] && !$this->check_acl(EGW_ACL_EDIT))
{
return true;
}
if ($touch_modified)
{
$this->data['ts_modifier'] = $GLOBALS['egw_info']['user']['account_id'];
$this->data['ts_modified'] = $this->now;
}
if (!($err = parent::save(null)))
{
// notify the link-class about the update, as other apps may be subscribt to it
$this->link->notify_update(TIMESHEET_APP,$this->data['ts_id'],$this->data);
}
return $err;
}
/**
* deletes a timesheet entry identified by $keys or the loaded one, reimplemented to notify the link class (unlink)
*
* @param array $keys if given array with col => value pairs to characterise the rows to delete
* @param boolean $ignore_acl=false should the acl be checked, returns false if no delete-rigts
* @return int affected rows, should be 1 if ok, 0 if an error
*/
function delete($keys=null,$ignore_acl=false)
{
$ts_id = is_null($keys) ? $this->data['ts_id'] : (is_array($keys) ? $keys['ts_id'] : $keys);
if (!$this->check_acl(EGW_ACL_DELETE,$ts_id))
{
return false;
}
if (($ret = parent::delete($keys)) && $ts_id)
{
// delete all links to timesheet entry $ts_id
$this->link->unlink(0,TIMESHEET_APP,$ts_id);
}
return $ret;
}
/**
* changes the data from the db-format to your work-format
*
* reimplemented to adjust the timezone of the timestamps (adding $this->tz_offset_s to get user-time)
* Please note, we do NOT call the method of the parent so_sql !!!
*
* @param array $data if given works on that array and returns result, else works on internal data-array
* @return array with changed data
*/
function db2data($data=null)
{
if (!is_array($data))
{
$data = &$this->data;
}
foreach($this->timestamps as $name)
{
if (isset($data[$name]) && $data[$name]) $data[$name] += $this->tz_offset_s;
}
return $data;
}
/**
* changes the data from your work-format to the db-format
*
* reimplemented to adjust the timezone of the timestamps (subtraction $this->tz_offset_s to get server-time)
* Please note, we do NOT call the method of the parent so_sql !!!
*
* @param array $data if given works on that array and returns result, else works on internal data-array
* @return array with changed data
*/
function data2db($data=null)
{
if ($intern = !is_array($data))
{
$data = &$this->data;
}
foreach($this->timestamps as $name)
{
if (isset($data[$name]) && $data[$name]) $data[$name] -= $this->tz_offset_s;
}
return $data;
}
/**
* get title for an timesheet entry identified by $entry
*
* Is called as hook to participate in the linking
*
* @param int/array $entry int ts_id or array with timesheet entry
* @param string the title
*/
function link_title( $entry )
{
if (!is_array($entry))
{
$entry = $this->read( $entry );
}
if (!$entry)
{
return False;
}
$format = $GLOBALS['egw_info']['user']['preferences']['common']['dateformat'];
if (date('H:i',$entry['ts_start']) != '00:00') // dont show 00:00 time, as it means date only
{
$format .= ' '.($GLOBALS['egw_info']['user']['preferences']['common']['timeformat'] == 12 ? 'h:i a' : 'H:i');
}
return date($format,$entry['ts_start']).': '.$entry['ts_title'];
}
/**
* query timesheet for entries matching $pattern
*
* Is called as hook to participate in the linking
*
* @param string $pattern pattern to search
* @return array with ts_id - title pairs of the matching entries
*/
function link_query( $pattern )
{
$criteria = array();
foreach(array('ts_project','ts_title','ts_description') as $col)
{
$criteria[$col] = $pattern;
}
$result = array();
foreach((array) $this->search($criteria,false,'','','%',false,'OR') as $ts )
{
$result[$ts['ts_id']] = $this->link_title($ts);
}
return $result;
}
/**
* Hook called by link-class to include timesheet in the appregistry of the linkage
*
* @param array/string $location location and other parameters (not used)
* @return array with method-names
*/
function search_link($location)
{
return array(
'query' => TIMESHEET_APP.'.botimesheet.link_query',
'title' => TIMESHEET_APP.'.botimesheet.link_title',
'view' => array(
'menuaction' => TIMESHEET_APP.'.uitimesheet.view',
),
'view_id' => 'ts_id',
'view_popup' => '600x400',
'add' => array(
'menuaction' => TIMESHEET_APP.'.uitimesheet.edit',
),
'add_app' => 'link_app',
'add_id' => 'link_id',
'add_popup' => '600x400',
);
}
}

View File

@ -0,0 +1,82 @@
<?php
/**************************************************************************\
* eGroupWare - ProjectManager - DataSource for TimeSheet *
* http://www.egroupware.org *
* Written and (c) 2005 by Ralf Becker <RalfBecker@outdoor-training.de> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
include_once(EGW_INCLUDE_ROOT.'/projectmanager/inc/class.datasource.inc.php');
include_once('class.botimesheet.inc.php');
/**
* DataSource for the TimeSheet
*
* @package timesheet
* @author RalfBecker-AT-outdoor-training.de
* @copyright (c) 2005 by RalfBecker-AT-outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
class datasource_timesheet extends datasource
{
/**
* Constructor
*/
function datasource_timesheet()
{
$this->datasource(TIMESHEET_APP);
$this->valid = PM_REAL_START|PM_REAL_END|PM_USED_TIME|PM_USED_BUDGET|PM_RESOURCES|PM_DETAILS|PM_COMPLETION;
}
/**
* get an entry from the underlaying app (if not given) and convert it into a datasource array
*
* @param mixed $data_id id as used in the link-class for that app, or complete entry as array
* @return array/boolean array with the data supported by that source or false on error (eg. not found, not availible)
*/
function get($data_id)
{
// we use $GLOBALS['bocal'] as an already running instance is availible there
if (!is_object($GLOBALS['botimesheet']))
{
$GLOBALS['bocal'] =& new botimesheet();
}
if (!is_array($data_id))
{
if (!(int) $data_id || !($data = $GLOBALS['botimesheet']->read((int) $data_id)))
{
return false;
}
}
else
{
$data =& $data_id;
}
$ds = array(
'pe_title' => $GLOBALS['botimesheet']->link_title($data),
'pe_real_start' => $data['ts_start'],
'pe_resources' => array($data['ts_owner']),
'pe_details' => $data['ts_description'] ? nl2br($data['ts_description']) : '',
'pe_used_budget' => $data['ts_quantity'] * $data['ts_unitprice'],
'pe_completion' => 100,
);
if ($data['ts_duration'])
{
$ds['pe_real_end'] = $data['ts_start'] + 60*$data['ts_duration'];
$ds['pe_used_time'] = $data['ts_duration'];
}
if ($this->debug)
{
echo "datasource_timesheet($data_id) data="; _debug_array($data);
echo "datasource="; _debug_array($ds);
}
return $ds;
}
}

View File

@ -0,0 +1,131 @@
<?php
/**************************************************************************\
* eGroupWare - TimeSheet: Admin-, Preferences- and SideboxMenu-Hooks *
* http://www.eGroupWare.org *
* Written and (c) 2005 by Ralf Becker <RalfBecker@outdoor-training.de> *
* ------------------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
if (!defined('TIMESHEET_APP'))
{
define('TIMESHEET_APP','timesheet');
}
class ts_admin_prefs_sidebox_hooks
{
var $public_functions = array(
// 'check_set_default_prefs' => true,
);
var $config = array();
function pm_admin_prefs_sidebox_hooks()
{
$config =& CreateObject('phpgwapi.config',TIMESHEET_APP);
$config->read_repository();
$this->config =& $config->config_data;
unset($config);
}
/**
* hooks to build projectmanager's sidebox-menu plus the admin and preferences sections
*
* @param string/array $args hook args
*/
function all_hooks($args)
{
$appname = TIMESHEET_APP;
$location = is_array($args) ? $args['location'] : $args;
//echo "<p>ts_admin_prefs_sidebox_hooks::all_hooks(".print_r($args,True).") appname='$appname', location='$location'</p>\n";
if ($location == 'sidebox_menu')
{
$file = array(
);
display_sidebox($appname,$GLOBALS['egw_info']['apps'][$appname]['title'].' '.lang('Menu'),$file);
}
if ($GLOBALS['egw_info']['user']['apps']['preferences'] && $location != 'admin')
{
$file = array(
// 'Preferences' => $GLOBALS['egw']->link('/index.php','menuaction=preferences.uisettings.index&appname='.$appname),
'Grant Access' => $GLOBALS['egw']->link('/index.php','menuaction=preferences.uiaclprefs.index&acl_app='.$appname),
'Edit Categories' => $GLOBALS['egw']->link('/index.php','menuaction=preferences.uicategories.index&cats_app=' . $appname . '&cats_level=True&global_cats=True')
);
if ($location == 'preferences')
{
display_section($appname,$file);
}
else
{
display_sidebox($appname,lang('Preferences'),$file);
}
}
if ($GLOBALS['egw_info']['user']['apps']['admin'] && $location != 'preferences')
{
$file = Array(
// 'Site configuration' => $GLOBALS['egw']->link('/index.php','menuaction=projectmanager.admin.config'),
// 'Custom fields' => $GLOBALS['egw']->link('/index.php','menuaction=admin.customfields.edit&appname='.$appname),
'Global Categories' => $GLOBALS['egw']->link('/index.php',array(
'menuaction' => 'admin.uicategories.index',
'appname' => $appname,
'global_cats'=> True)),
);
if ($location == 'admin')
{
display_section($appname,$file);
}
else
{
display_sidebox($appname,lang('Admin'),$file);
}
}
}
/**
* populates $GLOBALS['settings'] for the preferences
*/
function settings()
{
$this->check_set_default_prefs();
return true; // otherwise prefs say it cant find the file ;-)
}
/**
* Check if reasonable default preferences are set and set them if not
*
* It sets a flag in the app-session-data to be called only once per session
*/
function check_set_default_prefs()
{
if ($GLOBALS['egw']->session->appsession('default_prefs_set',TIMESHEET_APP))
{
return;
}
$GLOBALS['egw']->session->appsession('default_prefs_set',TIMESHEET_APP,'set');
$default_prefs =& $GLOBALS['egw']->preferences->default[TIMESHEET_APP];
$defaults = array(
);
foreach($defaults as $var => $default)
{
if (!isset($default_prefs[$var]) || $default_prefs[$var] === '')
{
$GLOBALS['egw']->preferences->add(TIMESHEET_APP,$var,$default,'default');
$need_save = True;
}
}
if ($need_save)
{
$GLOBALS['egw']->preferences->save_repository(False,'default');
}
}
}

View File

@ -0,0 +1,316 @@
<?php
/**************************************************************************\
* eGroupWare - TimeSheet: user interface *
* http://www.eGroupWare.org *
* Written and (c) 2005 by Ralf Becker <RalfBecker@outdoor-training.de> *
* ------------------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
require_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.uietemplate.inc.php');
require_once('class.botimesheet.inc.php');
/**
* User interface object of the TimeSheet
*
* @package timesheet
* @author RalfBecker-AT-outdoor-training.de
* @copyright (c) 2005 by RalfBecker-AT-outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
class uitimesheet extends botimesheet
{
var $public_functions = array(
'view' => true,
'edit' => true,
'index' => true,
);
function uitimesheet()
{
$this->botimesheet();
}
function view()
{
$this->edit(null,true);
}
function edit($content = null,$view = false)
{
$tabs = 'general|notes|links';
if (!is_array($content))
{
if ($view || (int)$_GET['ts_id'])
{
if (!$this->read((int)$_GET['ts_id']))
{
$GLOBALS['egw']->common->egw_header();
echo "<script>alert('".lang('Permission denied!!!')."'); window.close();</script>\n";
$GLOBALS['egw']->common->egw_exit();
}
if (!$view && !$this->check_acl(EGW_ACL_EDIT))
{
$view = true;
}
}
else // new entry
{
$this->data = array(
'ts_start' => $this->today,
'ts_owner' => $GLOBALS['egw_info']['user']['account_id'],
'cat_id' => (int) $_REQUEST['cat_id'],
);
}
$referer = preg_match('/menuaction=([^&]+)/',$_SERVER['HTTP_REFERER'],$matches) ? $matches[1] : TIMESHEET_APP.'.uitimesheet.index';
}
else
{
list($button) = each($content['button']);
$view = $content['view'];
$referer = $content['referer'];
$this->data = $content;
foreach(array('button','view','referer',$tabs) as $key)
{
unset($this->data[$key]);
}
switch($button)
{
case 'edit':
if ($this->check_acl(EGW_ACL_EDIT)) $view = false;
break;
case 'save':
case 'save_new':
case 'apply':
if (!$this->data['ts_quantity']) // set the quantity (in h) from the duration (in min)
{
$this->data['ts_quantity'] = $this->data['ts_duration'] / 60.0;
}
if (!$this->data['ts_project']) $this->data['ts_project'] = $this->data['ts_project_blur'];
if ($this->save() != 0)
{
$msg = lang('Error saving the entry!!!');
$button = '';
}
else
{
$msg = lang('Entry saved');
if (is_array($content['link_to']['to_id']) && count($content['link_to']['to_id']))
{
$this->link->link(TIMESHEET_APP,$this->data['ts_id'],$content['link_to']['to_id']);
}
}
$js = "opener.location.href='".$GLOBALS['egw']->link('/index.php',array(
'menuaction' => $referer,
'msg' => $msg,
))."';";
if ($button == 'apply') break;
if ($button == 'save_new')
{
// create a new entry
$this->data['ts_start'] += 60 * $this->data['ts_duration'];
foreach(array('ts_id','ts_title','ts_description','ts_duration','ts_quantity','ts_modified','ts_modifier') as $name)
{
unset($this->data[$name]);
}
break;
}
// fall-through for save
case 'delete':
if ($button == 'delete')
{
$this->delete();
$msg = lang('Entry deleted');
$js = "opener.location.href=opener.location.href+'&msg=$msg'";
}
case 'cancel':
$js .= 'window.close();';
echo "<html>\n<body>\n<script>\n$js\n</script>\n</body>\n</html>\n";
$GLOBALS['egw']->common->egw_exit();
break;
}
}
$preserv = $this->data + array(
'view' => $view,
'referer' => $referer,
);
$content = $this->data + array(
'msg' => $msg,
'view' => $view,
$tabs => $content[$tabs],
'link_to' => array(
'to_id' => $content['link_to']['to_id'] ? $content['link_to']['to_id'] : $this->data['ts_id'],
'to_app' => TIMESHEET_APP,
),
'js' => "<script>\n$js\n</script>\n",
'ts_quantity_blur' => $this->data['ts_duration'] ? $this->data['ts_duration'] / 60.0 : '',
);
if (!$this->data['ts_id'] && isset($_GET['link_app']) && isset($_GET['link_id']) &&
preg_match('/^[a-z_0-9-]+:[:a-z_0-9-]+$/i',$_GET['link_app'].':'.$_GET['link_id']) && // gard against XSS
!is_array($content['link_to']['to_id']))
{
$this->link->link(TIMESHEET_APP,$content['link_to']['to_id'],$_GET['link_app'],$_GET['link_id']);
// $content['ts_project'] = $this->link->title($_GET['link_app'],$_GET['link_id']);
if ($_GET['link_app'] == 'projectmanager')
{
$links = array($_GET['link_id']);
}
}
elseif ($this->data['ts_id'])
{
$links = $this->link->get_links(TIMESHEET_APP,$this->data['ts_id'],'projectmanager');
}
if ($links)
{
$preserv['ts_project_blur'] = $content['ts_project_blur'] = $this->link->title('projectmanager',array_shift($links));
}
$readonlys = array(
'button[delete]' => !$this->data['ts_id'] || !$this->check_acl(EGW_ACL_DELETE),
'button[edit]' => !$view || !$this->check_acl(EGW_ACL_EDIT),
'button[save]' => $view,
'button[save_new]' => $view,
'button[apply]' => $view,
);
if ($view)
{
foreach($this->data as $key => $val)
{
$readonlys[$key] = true;
}
}
$edit_grants = $this->grant_list(EGW_ACL_EDIT);
if (count($edit_grants) == 1)
{
$readonlys['ts_owner'] = true;
}
$GLOBALS['egw_info']['flags']['app_header'] = lang('timesheet').' - '.
($view ? lang('View') : ($this->data['ts_id'] ? lang('Edit') : lang('Add')));
$etpl =& new etemplate('timesheet.edit');
return $etpl->exec(TIMESHEET_APP.'.uitimesheet.edit',$content,array(
'ts_owner' => $edit_grants,
),$readonlys,$preserv,2);
}
/**
* query projects for nextmatch in the projects-list
*
* reimplemented from so_sql to disable action-buttons based on the acl and make some modification on the data
*
* @param array $query
* @param array &$rows returned rows/cups
* @param array &$readonlys eg. to disable buttons based on acl
*/
function get_rows($query,&$rows,&$readonlys)
{
$GLOBALS['egw']->session->appsession('index',TIMESHEET_APP,$query);
unset($query['col_filter']['cat_id']);
if ($query['cat_id'])
{
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories');
}
$cats = $GLOBALS['egw']->categories->return_all_children((int)$query['cat_id']);
$query['col_filter']['cat_id'] = count($cats) > 1 ? $cats : $query['cat_id'];
}
if ($query['filter'])
{
$query['col_filter'][0] = $this->date_filter($query['filter']);
}
if (!$query['col_filter']['ts_owner']) unset($query['col_filter']['ts_owner']);
$total = parent::get_rows($query,$rows,$readonlys);
unset($query['col_filter'][0]);
$readonlys = array();
foreach($rows as $n => $val)
{
$row =& $rows[$n];
if (!$this->check_acl(EGW_ACL_EDIT,$row))
{
$readonlys["edit[$row[ts_id]]"] = true;
}
if (!$this->check_acl(EGW_ACL_DELETE,$row))
{
$readonlys["delete[$row[ts_id]]"] = true;
}
if ($query['col_filter']['ts_project'] || !$query['filter2'])
{
unset($row['ts_project']); // dont need or want to show it
}
else
{
if (($links = $this->link->get_links(TIMESHEET_APP,$row['ts_id'],'projectmanager')))
{
$row['ts_link'] = array(
'app' => 'projectmanager',
'id' => array_shift($links),
);
}
$row['ts_link']['title'] = $row['ts_project'];
}
if (!$query['filter2'])
{
unset($row['ts_description']);
}
}
$rows['no_owner_col'] = $query['no_owner_col'];
if ($query['filter'])
{
$rows['duration'] = $this->summary['duration'];
$rows['price'] = $this->summary['price'];
}
return $total;
}
/**
* List timesheet entries
*
* @param array $content=null
*/
function index($content = null,$msg='')
{
$etpl =& new etemplate('timesheet.index');
if ($_GET['msg']) $msg = $_GET['msg'];
$content = array(
'nm' => $GLOBALS['egw']->session->appsession('index',TIMESHEET_APP),
'msg' => $msg,
);
if (!is_array($content['nm']))
{
$date_filters = array('All');
foreach($this->date_filters as $name => $date)
{
$date_filters[$name] = $name;
}
$content['nm'] = array(
'get_rows' => TIMESHEET_APP.'.uitimesheet.get_rows',
'options-filter' => $date_filters,
'options-filter2' => array('No details','Details'),
'order' => 'ts_start',// IO name of the column to sort after (optional for the sortheaders)
'sort' => 'DESC',// IO direction of the sort: 'ASC' or 'DESC'
);
}
$read_grants = $this->grant_list(EGW_ACL_READ);
$content['nm']['no_owner_col'] = count($read_grants) == 1;
return $etpl->exec(TIMESHEET_APP.'.uitimesheet.index',$content,array(
'ts_project' => $this->query_list('ts_project'),
'ts_owner' => $read_grants,
),$readonlys,$preserv);
}
}

39
timesheet/index.php Normal file
View File

@ -0,0 +1,39 @@
<?php
/**************************************************************************\
* eGroupWare - TimeSheet - time tracking for ProjectManager *
* http://www.egroupware.org *
* Written and (c) 2005 by Ralf Becker <RalfBecker@outdoor-training.de> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
include_once('setup/setup.inc.php');
$ts_version = $setup_info[TIMESHEET_APP]['version'];
unset($setup_info);
$GLOBALS['egw_info'] = array(
'flags' => array(
'currentapp' => TIMESHEET_APP,
'noheader' => True,
'nonavbar' => True
));
include('../header.inc.php');
if ($ts_version != $GLOBALS['egw_info']['apps'][TIMESHEET_APP]['version'])
{
$GLOBALS['egw']->common->egw_header();
parse_navbar();
echo '<p style="text-align: center; color:red; font-weight: bold;">'.lang('Your database is NOT up to date (%1 vs. %2), please run %3setup%4 to update your database.',
$ts_version,$GLOBALS['egw_info']['apps'][TIMESHEET_APP]['version'],
'<a href="../setup/">','</a>')."</p>\n";
$GLOBALS['egw']->common->egw_exit();
}
//ExecMethod(TIMESHEET_APP.'.pm_admin_prefs_sidebox_hooks.check_set_default_prefs');
$GLOBALS['egw']->redirect_link('/index.php',array('menuaction'=>TIMESHEET_APP.'.uitimesheet.index'));

View File

@ -0,0 +1,19 @@
<?php
// eTemplates for Application 'timesheet', generated by soetemplate::dump4setup() 2005-12-19 01:52
/* $Id$ */
$templ_version=1;
$templ_data[] = array('name' => 'timesheet.edit','template' => '','lang' => '','group' => '0','version' => '0.1.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:8:{i:0;a:8:{s:2:"c2";s:2:"th";s:2:"c3";s:3:"row";s:1:"A";s:3:"100";s:2:"c6";s:3:"row";s:2:"h6";s:14:",!@ts_modified";s:2:"c4";s:3:"row";s:2:"h2";s:2:"28";s:2:"h1";s:6:",!@msg";}i:1;a:2:{s:1:"A";a:5:{s:4:"type";s:5:"label";s:4:"span";s:13:"all,redItalic";s:4:"name";s:3:"msg";s:7:"no_lang";s:1:"1";s:5:"align";s:6:"center";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:11:",,,ts_owner";s:5:"label";s:4:"User";}s:1:"B";a:4:{s:4:"type";s:6:"select";s:4:"name";s:8:"ts_owner";s:4:"span";s:3:"all";s:7:"no_lang";s:1:"1";}}i:3;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:13:",,,ts_project";s:5:"label";s:7:"Project";}s:1:"B";a:5:{s:4:"type";s:4:"text";s:4:"size";s:5:"65,80";s:4:"name";s:10:"ts_project";s:4:"span";s:3:"all";s:4:"blur";s:16:"@ts_project_blur";}}i:4;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:14:",,ts_unitprice";s:5:"label";s:9:"Unitprice";}s:1:"B";a:3:{s:4:"type";s:5:"float";s:4:"name";s:12:"ts_unitprice";s:4:"span";s:3:"all";}}i:5;a:2:{s:1:"A";a:4:{s:4:"type";s:3:"tab";s:5:"label";s:19:"General|Notes|Links";s:4:"name";s:19:"general|notes|links";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:6;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:13:"Last modified";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:11:"ts_modified";s:8:"readonly";s:1:"1";}i:2;a:4:{s:4:"type";s:14:"select-account";s:4:"name";s:11:"ts_modifier";s:5:"label";s:2:"by";s:8:"readonly";s:1:"1";}}}i:7;a:2:{s:1:"A";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:5:"2,0,0";s:4:"span";s:1:"2";i:1;a:8:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"6";i:1;a:4:{s:4:"type";s:6:"button";s:5:"label";s:4:"Edit";s:4:"name";s:12:"button[edit]";s:4:"help";s:15:"Edit this entry";}i:2;a:4:{s:4:"type";s:6:"button";s:4:"name";s:16:"button[save_new]";s:5:"label";s:10:"Save & New";s:4:"help";s:34:"Saves this entry and add a new one";}i:3;a:4:{s:4:"type";s:6:"button";s:4:"name";s:12:"button[save]";s:5:"label";s:4:"Save";s:4:"help";s:22:"Saves the changes made";}i:4;a:4:{s:4:"type";s:6:"button";s:4:"name";s:13:"button[apply]";s:5:"label";s:5:"Apply";s:4:"help";s:24:"Applies the changes made";}i:5;a:5:{s:4:"type";s:6:"button";s:4:"name";s:14:"button[cancel]";s:5:"label";s:6:"Cancel";s:4:"help";s:44:"closes the window without saving the changes";s:7:"onclick";s:15:"window.close();";}i:6;a:2:{s:4:"type";s:4:"html";s:4:"name";s:2:"js";}}i:2;a:6:{s:4:"type";s:6:"button";s:5:"label";s:6:"Delete";s:5:"align";s:5:"right";s:4:"name";s:14:"button[delete]";s:4:"help";s:17:"Delete this entry";s:7:"onclick";s:36:"return confirm(\'Delete this entry\');";}}s:1:"B";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:7;s:4:"cols";i:2;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1134772260',);
$templ_data[] = array('name' => 'timesheet.edit.general','template' => '','lang' => '','group' => '0','version' => '0.1.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:6:{i:0;a:5:{s:2:"c1";s:3:"row";s:1:"A";s:2:"95";s:2:"c3";s:3:"row";s:2:"c4";s:3:"row";s:2:"c2";s:3:"row";}i:1;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:11:",,,ts_title";s:5:"label";s:5:"Title";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:4:"size";s:5:"65,80";s:4:"name";s:8:"ts_title";s:6:"needed";s:1:"1";}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:9:",,,cat_id";s:5:"label";s:8:"Category";}s:1:"B";a:3:{s:4:"type";s:10:"select-cat";s:4:"name";s:6:"cat_id";s:4:"size";s:4:"None";}}i:3;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:11:",,,ts_start";s:5:"label";s:4:"Date";}s:1:"B";a:4:{s:4:"type";s:9:"date-time";s:4:"name";s:8:"ts_start";s:6:"needed";s:1:"1";s:4:"size";s:2:",8";}}i:4;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:14:",,,ts_duration";s:5:"label";s:8:"Duration";}s:1:"B";a:3:{s:4:"type";s:13:"date-duration";s:4:"name";s:11:"ts_duration";s:4:"size";s:2:",h";}}i:5;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"size";s:14:",,,ts_quantity";s:5:"label";s:8:"Quantity";}s:1:"B";a:4:{s:4:"type";s:5:"float";s:4:"name";s:11:"ts_quantity";s:4:"help";s:30:"empty if identical to duration";s:4:"blur";s:17:"@ts_quantity_blur";}}}s:4:"rows";i:5;s:4:"cols";i:2;s:4:"size";s:8:"100%,150";s:7:"options";a:2:{i:0;s:4:"100%";i:1;s:3:"150";}}}','size' => '100%,150','style' => '','modified' => '1134773043',);
$templ_data[] = array('name' => 'timesheet.edit.links','template' => '','lang' => '','group' => '0','version' => '0.1.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:5:{i:0;a:7:{s:1:"A";s:3:"100";s:2:"h1";s:13:",@status_only";s:2:"h2";s:13:",@status_only";s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";s:2:"c3";s:2:"th";s:2:"c4";s:11:"row_off,top";}i:1;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:16:"Create new links";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:7:"link-to";s:4:"span";s:3:"all";s:4:"name";s:7:"link_to";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:3;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:14:"Existing links";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:4;a:2:{s:1:"A";a:3:{s:4:"type";s:9:"link-list";s:4:"span";s:3:"all";s:4:"name";s:7:"link_to";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:4;s:4:"cols";i:2;s:4:"size";s:17:"100%,150,,,,,auto";s:7:"options";a:3:{i:0;s:4:"100%";i:1;s:3:"150";i:6;s:4:"auto";}}}','size' => '100%,150,,,,,auto','style' => '','modified' => '1134775301',);
$templ_data[] = array('name' => 'timesheet.edit.notes','template' => '','lang' => '','group' => '0','version' => '0.1.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:1:{s:2:"c1";s:7:"row,top";}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:8:"textarea";s:4:"size";s:4:"8,70";s:4:"name";s:14:"ts_description";}}}s:4:"rows";i:1;s:4:"cols";i:1;s:4:"size";s:8:"100%,150";s:7:"options";a:2:{i:0;s:4:"100%";i:1;s:3:"150";}}}','size' => '100%,150','style' => '','modified' => '1134773787',);
$templ_data[] = array('name' => 'timesheet.index','template' => '','lang' => '','group' => '0','version' => '0.1.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:1:{s:2:"h1";s:6:",!@msg";}i:1;a:1:{s:1:"A";a:5:{s:4:"type";s:5:"label";s:4:"span";s:13:"all,redItalic";s:7:"no_lang";s:1:"1";s:4:"name";s:3:"msg";s:5:"align";s:6:"center";}}i:2;a:1:{s:1:"A";a:3:{s:4:"type";s:9:"nextmatch";s:4:"name";s:2:"nm";s:4:"size";s:20:"timesheet.index.rows";}}i:3;a:1:{s:1:"A";a:4:{s:4:"type";s:6:"button";s:5:"label";s:3:"Add";s:4:"name";s:3:"add";s:7:"onclick";s:163:"window.open(egw::link(\'/index.php\',\'menuaction=timesheet.uitimesheet.edit\'),\'_blank\',\'dependent=yes,width=600,height=400,scrollbars=yes,status=yes\'); return false;";}}}s:4:"rows";i:3;s:4:"cols";i:1;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1134799202',);
$templ_data[] = array('name' => 'timesheet.index.rows','template' => '','lang' => '','group' => '0','version' => '0.1.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:5:{s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";s:1:"A";s:3:"15%";s:1:"G";s:14:",@no_owner_col";s:1:"B";s:3:"50%";}i:1;a:8:{s:1:"A";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:4:"Date";s:4:"name";s:8:"ts_start";}s:1:"B";a:5:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";s:7:"no_lang";s:1:"1";i:1;a:4:{s:4:"type";s:22:"nextmatch-filterheader";s:4:"size";s:7:"Project";s:4:"name";s:10:"ts_project";s:7:"no_lang";s:1:"1";}i:2;a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:5:"Title";s:4:"name";s:8:"ts_title";}}s:1:"C";a:4:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:8:"Duration";s:4:"name";s:11:"ts_duration";}i:2;a:4:{s:4:"type";s:13:"date-duration";s:4:"name";s:8:"duration";s:4:"size";s:6:",h,,,1";s:8:"readonly";s:1:"1";}}s:1:"D";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:8:"Quantity";s:4:"name";s:11:"ts_quantity";}s:1:"E";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:5:"Price";s:4:"name";s:12:"ts_unitprice";}s:1:"F";a:4:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:5:"Total";s:4:"name";s:8:"ts_total";}i:2;a:3:{s:4:"type";s:5:"float";s:4:"name";s:5:"price";s:8:"readonly";s:1:"1";}}s:1:"G";a:4:{s:4:"type";s:22:"nextmatch-filterheader";s:4:"name";s:8:"ts_owner";s:4:"size";s:4:"User";s:7:"no_lang";s:1:"1";}s:1:"H";a:2:{s:4:"type";s:5:"label";s:5:"label";s:7:"Actions";}}i:2;a:8:{s:1:"A";a:4:{s:4:"type";s:9:"date-time";s:4:"name";s:16:"${row}[ts_start]";s:8:"readonly";s:1:"1";s:4:"size";s:2:",8";}s:1:"B";a:5:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"3";i:1;a:3:{s:4:"type";s:4:"link";s:4:"name";s:15:"${row}[ts_link]";s:7:"no_lang";s:1:"1";}i:2;a:4:{s:4:"type";s:5:"label";s:4:"name";s:16:"${row}[ts_title]";s:7:"no_lang";s:1:"1";s:4:"size";s:1:"b";}i:3;a:3:{s:4:"type";s:5:"label";s:4:"name";s:22:"${row}[ts_description]";s:7:"no_lang";s:1:"1";}}s:1:"C";a:4:{s:4:"type";s:13:"date-duration";s:4:"name";s:19:"${row}[ts_duration]";s:8:"readonly";s:1:"1";s:4:"size";s:5:",,,,1";}s:1:"D";a:3:{s:4:"type";s:5:"label";s:4:"name";s:19:"${row}[ts_quantity]";s:7:"no_lang";s:1:"1";}s:1:"E";a:3:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";s:4:"name";s:20:"${row}[ts_unitprice]";}s:1:"F";a:3:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";s:4:"name";s:16:"${row}[ts_total]";}s:1:"G";a:3:{s:4:"type";s:14:"select-account";s:4:"name";s:16:"${row}[ts_owner]";s:8:"readonly";s:1:"1";}s:1:"H";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"3";i:1;a:6:{s:4:"type";s:6:"button";s:4:"size";s:4:"view";s:5:"label";s:4:"View";s:4:"name";s:22:"view[$row_cont[ts_id]]";s:7:"onclick";s:186:"window.open(egw::link(\'/index.php\',\'menuaction=timesheet.uitimesheet.view&ts_id=$row_cont[ts_id]\'),\'_blank\',\'dependent=yes,width=600,height=400,scrollbars=yes,status=yes\'); return false;";s:4:"help";s:15:"View this entry";}i:2;a:6:{s:4:"type";s:6:"button";s:4:"size";s:4:"edit";s:5:"label";s:4:"Edit";s:4:"name";s:22:"edit[$row_cont[ts_id]]";s:4:"help";s:15:"Edit this entry";s:7:"onclick";s:186:"window.open(egw::link(\'/index.php\',\'menuaction=timesheet.uitimesheet.edit&ts_id=$row_cont[ts_id]\'),\'_blank\',\'dependent=yes,width=600,height=400,scrollbars=yes,status=yes\'); return false;";}i:3;a:6:{s:4:"type";s:6:"button";s:4:"size";s:6:"delete";s:5:"label";s:6:"Delete";s:4:"name";s:24:"delete[$row_cont[ts_id]]";s:4:"help";s:17:"Delete this entry";s:7:"onclick";s:36:"return confirm(\'Delete this entry\');";}}}}s:4:"rows";i:2;s:4:"cols";i:8;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1134799629',);

View File

@ -0,0 +1,34 @@
2 month ago timesheet de Vor 2 Monaten
2 years ago timesheet de Vor 2 Jahren
3 years ago timesheet de Vor 3 Jahren
actions timesheet de Aktionen
by timesheet de von
create new links timesheet de Neue Verknüpfung erstellen
delete this entry timesheet de Diesen Eintrag löschen
edit this entry timesheet de diesen Eintrag bearbeiten
empty if identical to duration timesheet de leer lassen wenn gleich Dauer
entry deleted timesheet de Eintrag gelöscht
entry saved timesheet de Eintrag gespeichert
error saving the entry!!! timesheet de Fehler beim Speichern des Eintrags!!!
existing links timesheet de Bestehende Verknüpfungen
general timesheet de Allgemein
last modified timesheet de Zuletzt geändert
last month timesheet de Letzten Monat
last week timesheet de Letzte Woche
last year timesheet de Letztes Jahr
links timesheet de Verknüpfungen
no details timesheet de Keine Details
permission denied!!! timesheet de Zugriff verweigert!!!
price timesheet de Preis
quantity timesheet de Menge
save & new timesheet de Speichern & Neu
saves the changes made timesheet de Speichert die Änderungen
saves this entry and add a new one timesheet de Speichert diesen Eintrag und fügt einen neune hinzu
this month timesheet de Diesen Monat
this week timesheet de Diese Woche
this year timesheet de Diese Jahr
timesheet common de Stundenzettel
unitprice timesheet de Preis pro Einheit
view this entry timesheet de Diesen Eintrag anzeigen
yesterday timesheet de Gestern
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. timesheet de Ihre Datenbank ist NICHT aktuell (%1 statt %2), bitte rufen sie %3setup%4 auf um die Datenbank zu aktualisieren.

View File

@ -0,0 +1,34 @@
2 month ago timesheet en 2 month ago
2 years ago timesheet en 2 years ago
3 years ago timesheet en 3 years ago
actions timesheet en Actions
by timesheet en by
create new links timesheet en Create new links
delete this entry timesheet en Delete this entry
edit this entry timesheet en Edit this entry
empty if identical to duration timesheet en empty if identical to duration
entry deleted timesheet en Entry deleted
entry saved timesheet en Entry saved
error saving the entry!!! timesheet en Error saving the entry!!!
existing links timesheet en Existing links
general timesheet en General
last modified timesheet en Last modified
last month timesheet en Last month
last week timesheet en Last week
last year timesheet en Last year
links timesheet en Links
no details timesheet en no details
permission denied!!! timesheet en Permission denied!!!
price timesheet en Price
quantity timesheet en Quantity
save & new timesheet en Save & New
saves the changes made timesheet en Saves the changes made
saves this entry and add a new one timesheet en Saves this entry and add a new one
this month timesheet en This month
this week timesheet en This week
this year timesheet en This year
timesheet common en TimeSheet
unitprice timesheet en Unitprice
view this entry timesheet en View this entry
yesterday timesheet en Yesterday
your database is not up to date (%1 vs. %2), please run %3setup%4 to update your database. timesheet en Your database is NOT up to date (%1 vs. %2), please run %3setup%4 to update your database.

View File

@ -0,0 +1,55 @@
<?php
/**************************************************************************\
* eGroupWare - TimeSheet - time tracking for ProjectManager *
* http://www.egroupware.org *
* Written and (c) 2005 by Ralf Becker <RalfBecker@outdoor-training.de> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
if (!defined('TIMESHEET_APP'))
{
define('TIMESHEET_APP','timesheet');
}
$setup_info[TIMESHEET_APP]['name'] = TIMESHEET_APP;
$setup_info[TIMESHEET_APP]['version'] = '0.1.001';
$setup_info[TIMESHEET_APP]['app_order'] = 5;
$setup_info[TIMESHEET_APP]['tables'] = array('egw_timesheet');
$setup_info[TIMESHEET_APP]['enable'] = 1;
$setup_info[TIMESHEET_APP]['author'] =
$setup_info[TIMESHEET_APP]['maintainer'] = array(
'name' => 'Ralf Becker',
'email' => 'RalfBecker@outdoor-training.de'
);
$setup_info[TIMESHEET_APP]['license'] = 'GPL';
$setup_info[TIMESHEET_APP]['description'] =
'Tracking times and other activities for the Projectmanager.';
$setup_info[TIMESHEET_APP]['note'] =
'The TimeSheet application is sponsored by:<ul>
<li> <a href="http://www.stylite.de" target="_blank">Stylite GmbH</a></li>
<li> <a href="http://www.outdoor-training.de" target="_blank">Outdoor Unlimited Training GmbH</a></li>
</ul>';
/* The hooks this app includes, needed for hooks registration */
$setup_info[TIMESHEET_APP]['hooks']['preferences'] = TIMESHEET_APP.'.ts_admin_prefs_sidebox_hooks.all_hooks';
$setup_info[TIMESHEET_APP]['hooks']['settings'] = TIMESHEET_APP.'.ts_admin_prefs_sidebox_hooks.settings';
$setup_info[TIMESHEET_APP]['hooks']['admin'] = TIMESHEET_APP.'.ts_admin_prefs_sidebox_hooks.all_hooks';
$setup_info[TIMESHEET_APP]['hooks']['sidebox_menu'] = TIMESHEET_APP.'.ts_admin_prefs_sidebox_hooks.all_hooks';
$setup_info[TIMESHEET_APP]['hooks']['search_link'] = TIMESHEET_APP.'.botimesheet.search_link';
/* Dependencies for this app to work */
$setup_info[TIMESHEET_APP]['depends'][] = array(
'appname' => 'phpgwapi',
'versions' => Array('1.2','1.3')
);
$setup_info[TIMESHEET_APP]['depends'][] = array(
'appname' => 'etemplate',
'versions' => Array('1.2','1.3')
);

View File

@ -0,0 +1,37 @@
<?php
/**************************************************************************\
* eGroupWare - Setup *
* http://www.eGroupWare.org *
* Created by eTemplates DB-Tools written by ralfbecker@outdoor-training.de *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
$phpgw_baseline = array(
'egw_timesheet' => array(
'fd' => array(
'ts_id' => array('type' => 'auto','nullable' => False),
'ts_project' => array('type' => 'varchar','precision' => '80'),
'ts_title' => array('type' => 'varchar','precision' => '80','nullable' => False),
'ts_description' => array('type' => 'text'),
'ts_start' => array('type' => 'int','precision' => '8','nullable' => False),
'ts_duration' => array('type' => 'int','precision' => '8','nullable' => False,'default' => '0'),
'ts_quantity' => array('type' => 'float','precision' => '8','nullable' => False),
'ts_unitprice' => array('type' => 'float','precision' => '4'),
'cat_id' => array('type' => 'int','precision' => '4','default' => '0'),
'ts_owner' => array('type' => 'int','precision' => '4','nullable' => False),
'ts_modified' => array('type' => 'int','precision' => '8','nullable' => False),
'ts_modifier' => array('type' => 'int','precision' => '4','nullable' => False)
),
'pk' => array('ts_id'),
'fk' => array(),
'ix' => array('ts_project','ts_owner'),
'uc' => array()
)
);

View File

@ -0,0 +1,2 @@
/* $Id$ */
.redItalic { color: red; font-style: italics; }

View File

@ -0,0 +1,134 @@
<?xml version="1.0"?>
<!-- $Id$ -->
<overlay>
<template id="timesheet.edit.general" template="" lang="" group="0" version="0.1.001">
<grid width="100%" height="150">
<columns>
<column width="95"/>
<column/>
</columns>
<rows>
<row class="row">
<description options=",,,ts_title" value="Title"/>
<textbox size="65" maxlength="80" id="ts_title" needed="1"/>
</row>
<row class="row">
<description options=",,,cat_id" value="Category"/>
<menulist>
<menupopup type="select-cat" id="cat_id" options="None"/>
</menulist>
</row>
<row class="row">
<description options=",,,ts_start" value="Date"/>
<date-time id="ts_start" needed="1" options=",8"/>
</row>
<row class="row">
<description options=",,,ts_duration" value="Duration"/>
<date-duration id="ts_duration" options=",h"/>
</row>
<row>
<description options=",,,ts_quantity" value="Quantity"/>
<textbox type="float" id="ts_quantity" statustext="empty if identical to duration" blur="@ts_quantity_blur"/>
</row>
</rows>
</grid>
</template>
<template id="timesheet.edit.notes" template="" lang="" group="0" version="0.1.001">
<grid width="100%" height="150">
<columns>
<column/>
</columns>
<rows>
<row class="row" valign="top">
<textbox multiline="true" rows="8" cols="70" id="ts_description"/>
</row>
</rows>
</grid>
</template>
<template id="timesheet.edit.links" template="" lang="" group="0" version="0.1.001">
<grid width="100%" height="150" overflow="auto">
<columns>
<column width="100"/>
<column/>
</columns>
<rows>
<row class="th" disabled="@status_only">
<description span="all" value="Create new links"/>
</row>
<row class="row" disabled="@status_only">
<link-to span="all" id="link_to"/>
</row>
<row class="th">
<description span="all" value="Existing links"/>
</row>
<row class="row_off" valign="top">
<link-list span="all" id="link_to"/>
</row>
</rows>
</grid>
</template>
<template id="timesheet.edit" template="" lang="" group="0" version="0.1.001">
<grid width="100%">
<columns>
<column width="100"/>
<column/>
</columns>
<rows>
<row disabled="!@msg">
<description span="all" class="redItalic" id="msg" no_lang="1" align="center"/>
<description/>
</row>
<row class="th" height="28">
<description options=",,,ts_owner" value="User"/>
<menulist span="all">
<menupopup id="ts_owner" no_lang="1"/>
</menulist>
</row>
<row class="row">
<description options=",,,ts_project" value="Project"/>
<textbox size="65" maxlength="80" id="ts_project" span="all" blur="@ts_project_blur"/>
</row>
<row class="row">
<description options=",,ts_unitprice" value="Unitprice"/>
<textbox type="float" id="ts_unitprice" span="all"/>
</row>
<row>
<tabbox span="all">
<tabs>
<tab label="General" statustext=""/>
<tab label="Notes" statustext=""/>
<tab label="Links" statustext=""/>
</tabs>
<tabpanels>
<template id="timesheet.edit.general"/>
<template id="timesheet.edit.notes"/>
<template id="timesheet.edit.links"/>
</tabpanels>
</tabbox>
</row>
<row class="row" disabled="!@ts_modified">
<description value="Last modified"/>
<hbox>
<date-time id="ts_modified" readonly="true"/>
<menulist>
<menupopup type="select-account" id="ts_modifier" label="by" readonly="true"/>
</menulist>
</hbox>
</row>
<row>
<hbox span="2" orient="0,0">
<hbox>
<button label="Edit" id="button[edit]" statustext="Edit this entry"/>
<button id="button[save_new]" label="Save &amp; New" statustext="Saves this entry and add a new one"/>
<button id="button[save]" label="Save" statustext="Saves the changes made"/>
<button id="button[apply]" label="Apply" statustext="Applies the changes made"/>
<button id="button[cancel]" label="Cancel" statustext="closes the window without saving the changes" onclick="window.close();"/>
<html id="js"/>
</hbox>
<button label="Delete" align="right" id="button[delete]" statustext="Delete this entry" onclick="return confirm('Delete this entry');"/>
</hbox>
</row>
</rows>
</grid>
</template>
</overlay>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,77 @@
<?xml version="1.0"?>
<!-- $Id$ -->
<overlay>
<template id="timesheet.index.rows" template="" lang="" group="0" version="0.1.001">
<grid width="100%">
<columns>
<column width="15%"/>
<column width="50%"/>
<column/>
<column/>
<column/>
<column/>
<column disabled="@no_owner_col"/>
<column/>
</columns>
<rows>
<row class="th">
<nextmatch-sortheader label="Date" id="ts_start"/>
<vbox no_lang="1">
<nextmatch-filterheader options="Project" id="ts_project" no_lang="1"/>
<nextmatch-sortheader label="Title" id="ts_title"/>
</vbox>
<vbox>
<nextmatch-sortheader label="Duration" id="ts_duration"/>
<date-duration id="duration" options=",h,,,1" readonly="true"/>
</vbox>
<nextmatch-sortheader label="Quantity" id="ts_quantity"/>
<nextmatch-sortheader label="Price" id="ts_unitprice"/>
<vbox>
<nextmatch-sortheader label="Total" id="ts_total"/>
<textbox type="float" id="price" readonly="true"/>
</vbox>
<nextmatch-filterheader id="ts_owner" options="User" no_lang="1"/>
<description value="Actions"/>
</row>
<row class="row">
<date-time id="${row}[ts_start]" readonly="true" options=",8"/>
<vbox>
<link id="${row}[ts_link]" no_lang="1"/>
<description id="${row}[ts_title]" no_lang="1" options="b"/>
<description id="${row}[ts_description]" no_lang="1"/>
</vbox>
<date-duration id="${row}[ts_duration]" readonly="true" options=",,,,1"/>
<description id="${row}[ts_quantity]" no_lang="1"/>
<description no_lang="1" id="${row}[ts_unitprice]"/>
<description no_lang="1" id="${row}[ts_total]"/>
<menulist>
<menupopup type="select-account" id="${row}[ts_owner]" readonly="true"/>
</menulist>
<hbox>
<button image="view" label="View" id="view[$row_cont[ts_id]]" onclick="window.open(egw::link('/index.php','menuaction=timesheet.uitimesheet.view&amp;ts_id=$row_cont[ts_id]'),'_blank','dependent=yes,width=600,height=400,scrollbars=yes,status=yes'); return false;" statustext="View this entry"/>
<button image="edit" label="Edit" id="edit[$row_cont[ts_id]]" statustext="Edit this entry" onclick="window.open(egw::link('/index.php','menuaction=timesheet.uitimesheet.edit&amp;ts_id=$row_cont[ts_id]'),'_blank','dependent=yes,width=600,height=400,scrollbars=yes,status=yes'); return false;"/>
<button image="delete" label="Delete" id="delete[$row_cont[ts_id]]" statustext="Delete this entry" onclick="return confirm('Delete this entry');"/>
</hbox>
</row>
</rows>
</grid>
</template>
<template id="timesheet.index" template="" lang="" group="0" version="0.1.001">
<grid width="100%">
<columns>
<column/>
</columns>
<rows>
<row disabled="!@msg">
<description span="all" class="redItalic" no_lang="1" id="msg" align="center"/>
</row>
<row>
<nextmatch id="nm" options="timesheet.index.rows"/>
</row>
<row>
<button label="Add" id="add" onclick="window.open(egw::link('/index.php','menuaction=timesheet.uitimesheet.edit'),'_blank','dependent=yes,width=600,height=400,scrollbars=yes,status=yes'); return false;"/>
</row>
</rows>
</grid>
</template>
</overlay>

View File

@ -0,0 +1,7 @@
<!-- $Id$ -->
<tr class="{row_class}">
<td>{user}</td>
<td align="center"><input type="checkbox" name="{read}" value="Y"{read_selected}></td>
<td align="center"><input type="checkbox" name="{edit}" value="Y"{edit_selected}></td>
<td align="center"><input type="checkbox" name="{delete}" value="Y"{delete_selected}></td>
</tr>

View File

@ -0,0 +1,6 @@
<tr class="th">
<td>{string}</td>
<td align="center" width="8%">{lang_read}</td>
<td align="center" width="8%">{lang_edit}</td>
<td align="center" width="8%">{lang_delete}</td>
</tr>