Initial commit: Kimai TMS

Kimai time management system (PHP 5.6 / MySQL) with custom extensions:
- Budget tracking (ki_budget)
- Change request form (ki_changerequest)
- Invoice generation (ki_invoice)
- Expense tracking (ki_expenses)
- Flexi time (ki_flexitime)
- Export, admin panel, timesheets, tasks, summary

Database: ~900K time entries, 2,000+ users, 439 projects.
Config: includes/autoconf.php — localhost/kimai/kimai
This commit is contained in:
TMS
2026-06-18 21:20:26 +00:00
commit eb299c9131
1099 changed files with 359817 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
<?php /* Smarty version 2.6.20, created on 2015-01-20 09:05:44
compiled from index.tpl */ ?>
<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
smarty_core_load_plugins(array('plugins' => array(array('modifier', 'escape', 'index.tpl', 24, false),)), $this); ?>
<?php echo '
<script type="text/javascript">
$(document).ready(function() {
bgt_ext_onload();
plotdata = new Array();
'; ?>
<?php $_from = $this->_tpl_vars['arr_plotdata']; if (!is_array($_from) && !is_object($_from)) { settype($_from, 'array'); }if (count($_from)):
foreach ($_from as $this->_tpl_vars['id'] => $this->_tpl_vars['value']):
?>
plotdata[<?php echo $this->_tpl_vars['id']; ?>
] = <?php echo $this->_tpl_vars['value']; ?>
;
<?php endforeach; endif; unset($_from); ?><?php echo '
chartColors = '; ?>
<?php echo $this->_tpl_vars['chartColors']; ?>
<?php echo ';
bgt_ext_plot(plotdata);
});
</script>
'; ?>
<div id="bgt">
<div class="keys">
<?php unset($this->_sections['row']);
$this->_sections['row']['name'] = 'row';
$this->_sections['row']['loop'] = is_array($_loop=$this->_tpl_vars['arr_keys']) ? count($_loop) : max(0, (int)$_loop); unset($_loop);
$this->_sections['row']['show'] = true;
$this->_sections['row']['max'] = $this->_sections['row']['loop'];
$this->_sections['row']['step'] = 1;
$this->_sections['row']['start'] = $this->_sections['row']['step'] > 0 ? 0 : $this->_sections['row']['loop']-1;
if ($this->_sections['row']['show']) {
$this->_sections['row']['total'] = $this->_sections['row']['loop'];
if ($this->_sections['row']['total'] == 0)
$this->_sections['row']['show'] = false;
} else
$this->_sections['row']['total'] = 0;
if ($this->_sections['row']['show']):
for ($this->_sections['row']['index'] = $this->_sections['row']['start'], $this->_sections['row']['iteration'] = 1;
$this->_sections['row']['iteration'] <= $this->_sections['row']['total'];
$this->_sections['row']['index'] += $this->_sections['row']['step'], $this->_sections['row']['iteration']++):
$this->_sections['row']['rownum'] = $this->_sections['row']['iteration'];
$this->_sections['row']['index_prev'] = $this->_sections['row']['index'] - $this->_sections['row']['step'];
$this->_sections['row']['index_next'] = $this->_sections['row']['index'] + $this->_sections['row']['step'];
$this->_sections['row']['first'] = ($this->_sections['row']['iteration'] == 1);
$this->_sections['row']['last'] = ($this->_sections['row']['iteration'] == $this->_sections['row']['total']);
?>
<div class="key"><div class="key_color" style="background-color:<?php echo $this->_tpl_vars['arr_keys'][$this->_sections['row']['index']]['color']; ?>
"></div><?php echo ((is_array($_tmp=$this->_tpl_vars['arr_keys'][$this->_sections['row']['index']]['name'])) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>
</div>
<?php endfor; endif; ?>
<div class="key_end"/>
</div>
<?php unset($this->_sections['row']);
$this->_sections['row']['name'] = 'row';
$this->_sections['row']['loop'] = is_array($_loop=$this->_tpl_vars['arr_pct']) ? count($_loop) : max(0, (int)$_loop); unset($_loop);
$this->_sections['row']['show'] = true;
$this->_sections['row']['max'] = $this->_sections['row']['loop'];
$this->_sections['row']['step'] = 1;
$this->_sections['row']['start'] = $this->_sections['row']['step'] > 0 ? 0 : $this->_sections['row']['loop']-1;
if ($this->_sections['row']['show']) {
$this->_sections['row']['total'] = $this->_sections['row']['loop'];
if ($this->_sections['row']['total'] == 0)
$this->_sections['row']['show'] = false;
} else
$this->_sections['row']['total'] = 0;
if ($this->_sections['row']['show']):
for ($this->_sections['row']['index'] = $this->_sections['row']['start'], $this->_sections['row']['iteration'] = 1;
$this->_sections['row']['iteration'] <= $this->_sections['row']['total'];
$this->_sections['row']['index'] += $this->_sections['row']['step'], $this->_sections['row']['iteration']++):
$this->_sections['row']['rownum'] = $this->_sections['row']['iteration'];
$this->_sections['row']['index_prev'] = $this->_sections['row']['index'] - $this->_sections['row']['step'];
$this->_sections['row']['index_next'] = $this->_sections['row']['index'] + $this->_sections['row']['step'];
$this->_sections['row']['first'] = ($this->_sections['row']['iteration'] == 1);
$this->_sections['row']['last'] = ($this->_sections['row']['iteration'] == $this->_sections['row']['total']);
?>
<div class="bgt_project">
<div class="project_head">
<?php echo ((is_array($_tmp=$this->_tpl_vars['arr_pct'][$this->_sections['row']['index']]['pct_name'])) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>
</div>
<div id="bgt_chartdiv_<?php echo $this->_tpl_vars['arr_pct'][$this->_sections['row']['index']]['pct_ID']; ?>
" style="height:140px;width:150px; "></div>
</div>
<?php endfor; endif; ?>
<div class="bgt_project_end"/>
</div>

View File

@@ -0,0 +1,13 @@
EXTENSION_NAME = "Budget"
EXTENSION_KEY = "ki_budget"
EXTENSION_INIT_FILE = "ki_budget/init.php"
EXTENSION_DIR = "ki_budget"
ADMIN_ALLOWED = "1"
GROUP_LEADER_ALLOWED = "1"
USER_ALLOWED = "1"
CUSTOMER_ALLOWED = "1"
JS_INCLUDE_FILES[] = "../extensions/ki_budget/js/bgt_func.js"
JS_INCLUDE_FILES[] = "../extensions/ki_budget/js/bgt_init.js"
CSS_INCLUDE_FILES = "../extensions/ki_budget/css/styles.css"

View File

@@ -0,0 +1,64 @@
<?php
header('Content-type: text/css');
$table_header = "../../../skins/standard/grfx/g3_table_header.png";
?>
#bgt {
border:1px solid black;
margin:10px;
background-color:#eee;
overflow:auto;
}
#bgt {
top:150px;
z-index:2;
}
.project_head {
background-image: url('<?php echo $table_header; ?>');
color:#FFF;
font-size:11px;
font-weight:bold;
padding:3px 4px 4px 6px;
text-align:center;
}
.bgt_project {
float:left;
/*min-width:150px;
height:150px;*/
background-color:#fafafa;
border:1px solid black;
margin:5px;
padding:2px;
}
.bgt_project_end {
clear:both;
}
.keys {
background-color:#fafafa;
border:1px solid black;
margin:5px;
}
.key {
float:left;
white-space:nowrap;
padding:5px;
font-size: smaller;
}
.key_color {
float:left;
width:1em;
height:1em;
margin-right: 5px;
border: 1px solid black;
}
.key_end {
clear:both;
}

View File

@@ -0,0 +1 @@
@import "setup.css.php";

View File

@@ -0,0 +1,68 @@
<?php
/**
* This file is part of
* Kimai - Open Source Time Tracking // http://www.kimai.org
* (c) 2006-2009 Kimai-Development-Team
*
* Kimai 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; Version 3, 29 June 2007
*
* Kimai is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kimai; If not, see <http://www.gnu.org/licenses/>.
*/
// Include Basics
include('../../includes/basics.php');
require("private_func.php");
$usr = checkUser();
// set smarty config
require_once(WEBROOT.'libraries/smarty/Smarty.class.php');
$tpl = new Smarty();
$tpl->template_dir = 'templates/';
$tpl->compile_dir = 'compile/';
// Get all project for the logged in customer or the current user.
if (isset($kga['customer']))
$arr_pct = get_arr_pct_by_knd("all",$kga['customer']['knd_ID']);
else
$arr_pct = get_arr_pct($kga['usr']['usr_grp']);
$usedEvents = array();
$xpensesOccured = false;
// If there are any projects create the plot data.
if (count($arr_pct)>0) {
$arr_plotdata = budget_plot_data($arr_pct,$usedEvents,$expensesOccured);
$tpl->assign('arr_plotdata', $arr_plotdata);
$tpl->assign('arr_pct', $arr_pct);
} else {
$tpl->assign('arr_pct', 0);
}
$chartColors = array("#efefef", "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc");
$tpl->assign('chartColors',json_encode($chartColors));
// Create the keys which explain to the user which color means what.
$keys = array();
$keys[] = array('color'=>$chartColors[0], 'name' => $kga['lang']['ext_budget']['unusedBudget']);
if ($expensesOccured)
$keys[] = array('color'=>$chartColors[1], 'name' => $kga['lang']['xp_ext']['expenses']);
for ($i = 0;$i<count($usedEvents);$i++) {
$keys[] = array('color'=>$chartColors[($i+2)%(count($chartColors)-1)], 'name' => $usedEvents[$i]['evt_name']);
}
$tpl->assign('arr_keys',$keys);
$tpl->display('index.tpl');
?>

View File

@@ -0,0 +1,53 @@
/**
* This file is part of
* Kimai - Open Source Time Tracking // http://www.kimai.org
* (c) 2006-2009 Kimai-Development-Team
*
* Kimai 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; Version 3, 29 June 2007
*
* Kimai is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kimai; If not, see <http://www.gnu.org/licenses/>.
*/
// =============
// BGT EXT funcs
// =============
function bgt_ext_onload() {
bgt_ext_resize();
$("#loader").hide();
lists_visible(false);
}
function bgt_ext_get_dimensions() {
bgt_h = pageHeight()-224;//-headerHeight()-28;
}
function bgt_ext_resize() {
bgt_ext_get_dimensions();
$("#bgt").css("height",bgt_h);
}
function bgt_ext_plot(plotdata) {
for (var i in plotdata) {
if ($('#bgt_chartdiv_'+i).length == 0) continue;
try {
$.jqplot('bgt_chartdiv_'+i, [plotdata[i]], {
seriesDefaults:{renderer:$.jqplot.PieRenderer,
rendererOptions: {padding:10}
},
seriesColors:chartColors,
grid:{background:$('#bgt_chartdiv_'+i).css("background-color"), borderWidth:0, shadow:false}
});
}
catch (err) {
}
}
}

View File

@@ -0,0 +1,42 @@
/**
* This file is part of
* Kimai - Open Source Time Tracking // http://www.kimai.org
* (c) 2006-2009 Kimai-Development-Team
*
* Kimai 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; Version 3, 29 June 2007
*
* Kimai is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kimai; If not, see <http://www.gnu.org/licenses/>.
*/
// ============
// BGT EXT init
// ============
// set path of extension
var bgt_ext_path = "../extensions/ki_budget/";
var bgt_w;
var bgt_h;
var chartColors;
$(document).ready(function(){
var bgt_resizeTimer = null;
$(window).bind('resize', function() {
if (bgt_resizeTimer) clearTimeout(bgt_resizeTimer);
bgt_resizeTimer = setTimeout(bgt_ext_resize, 500);
});
$.jqplot.config.enablePlugins = true;
});

View File

@@ -0,0 +1,144 @@
<?php
/**
* This file is part of
* Kimai - Open Source Time Tracking // http://www.kimai.org
* (c) 2006-2009 Kimai-Development-Team
*
* Kimai 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; Version 3, 29 June 2007
*
* Kimai is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kimai; If not, see <http://www.gnu.org/licenses/>.
*/
include('../ki_expenses/private_db_layer_'.$kga['server_conn'].'.php');
/**
* Sum up expenses for the project.
*/
function calculate_expenses_sum($projectId) {
$expSum = 0;
$exp_arr = get_arr_exp(0,time(),null,null,array($projectId));
foreach ($exp_arr as $exp) {
$expSum += $exp['exp_value'];
}
return $expSum;
}
/**
* Create an array of arrays which hold the size of the pie chart elements
* for every projects.
* The first element in the inner arrays represents the unused budget costs,
* the second element in the inner arrays represents the expense costs,
* the third and all other elements in the inner arrays represents the
* costs for individual events.
*
* An visual example for two projects with the ID 2 and 5:
* $array = {
* 2 => array (budget left , expenses cost, task1, task2 ),
* 5 => array (budget left , expenses cost, task1, task2 ),
* };
*
* @param array $projects IDs of all projects to include in the plot data
* @param array $usedEvents array of all used events (each as an array of its data)
* @return array containing arrays for every project which hold the size of the pie chart elements
*
*/
function budget_plot_data($projects,&$usedEvents,&$expensesOccured) {
$wages = array();
$eventUsage = array(); // track what events are used
$usedEvents = array();
$expensesOccured = false;
$events = get_arr_evt("all");
/*
* sum up expenses
*/
foreach ($projects as $project) {
$pctId = $project['pct_ID'];
$wages[$pctId]['budget'] = $project['pct_budget'];
$wages[$pctId]['expenses'] =
calculate_expenses_sum($project['pct_ID']);
if ($wages[$pctId]['expenses'] != 0)
$expensesOccured = true;
if ($wages[$pctId]['budget'] < 0) {
//Costs over budget, set remaining budget to 0.
$wages[$pctId]['budget'] = 0;
}
// initialize entries for every event using its ID
foreach($events as $event) {
$wages[$pctId][$event['evt_ID']] = 0;
}
}
/*
* sum up wages for every project and every event
*/
foreach ($projects as $project) {
$projectId = $project['pct_ID'];
$zef_arr = get_arr_zef(0,time(),null,null,array($projectId));
foreach ($zef_arr as $zef) {
$pctId = $zef['zef_pctID'];
if ($zef['wage_decimal'] == 0.00)
continue;
if (key_exists($zef['zef_evtID'],$wages[$pctId])) {
$eventUsage[$zef['zef_evtID']] = true;
$wages[$pctId][$zef['zef_evtID']] += $zef['wage_decimal'];
$wages[$pctId]['budget'] -= $zef['wage_decimal'];
}
if ($wages[$pctId]['budget'] < 0) {
//Costs over budget, set remaining budget to 0.
$wages[$pctId]['budget'] = 0;
}
}
}
/*
* Delete unused events.
*/
foreach ($events as $event) {
if (isset($eventUsage[$event['evt_ID']])) {
$usedEvents[] = $event;
continue;
}
foreach ($wages as $projectData) {
unset($projectData[$event['evt_ID']]);
}
}
/*
* Convert array of wages to javascript array for every project.
*/
$plot_data = array();
foreach ($wages as $project_id => $wage_array) {
$plot_data[$project_id] = '['.implode(',',$wage_array).']';
}
return $plot_data;
}
?>

View File

@@ -0,0 +1,38 @@
{literal}
<script type="text/javascript">
$(document).ready(function() {
bgt_ext_onload();
plotdata = new Array();
{/literal}
{foreach key=id item=value from=$arr_plotdata}
plotdata[{$id}] = {$value};
{/foreach}{literal}
chartColors = {/literal}{$chartColors}{literal};
bgt_ext_plot(plotdata);
});
</script>
{/literal}
<div id="bgt">
<div class="keys">
{section name=row loop=$arr_keys}
<div class="key"><div class="key_color" style="background-color:{$arr_keys[row].color}"></div>{$arr_keys[row].name|escape:'html'}</div>
{/section}
<div class="key_end"/>
</div>
{section name=row loop=$arr_pct}
<div class="bgt_project">
<div class="project_head">
{$arr_pct[row].pct_name|escape:'html'}
</div>
<div id="bgt_chartdiv_{$arr_pct[row].pct_ID}" style="height:140px;width:150px; "></div>
</div>
{/section}
<div class="bgt_project_end"/>
</div>