$canViewReports = $user->can('view_reports') || $user->can('view_all_reports');
$isClient = $user->isClient();
- $no_grouping = ($options['group_by1'] == null || $options['group_by1'] == 'no_grouping') &&
- ($options['group_by2'] == null || $options['group_by2'] == 'no_grouping') &&
- ($options['group_by3'] == null || $options['group_by3'] == 'no_grouping');
+ $grouping = ttReportHelper::grouping($options);
$grouping_by_date = ($options['group_by1'] == 'date'|| $options['group_by2'] == 'date' || $options['group_by3'] == 'date');
$grouping_by_client = ($options['group_by1'] == 'client'|| $options['group_by2'] == 'client' || $options['group_by3'] == 'client');
$grouping_by_project = ($options['group_by1'] == 'project'|| $options['group_by2'] == 'project' || $options['group_by3'] == 'project');
// Determine sort part.
$sort_part = ' order by ';
- if ($no_grouping)
- $sort_part .= 'date';
- else {
+ if ($grouping) {
$sort_part2 .= ($options['group_by1'] != null && $options['group_by1'] != 'no_grouping') ? ', '.$options['group_by1'] : '';
$sort_part2 .= ($options['group_by2'] != null && $options['group_by2'] != 'no_grouping') ? ', '.$options['group_by2'] : '';
$sort_part2 .= ($options['group_by3'] != null && $options['group_by3'] != 'no_grouping') ? ', '.$options['group_by3'] : '';
if (!$grouping_by_date) $sort_part2 .= ', date';
$sort_part .= ltrim($sort_part2, ', '); // Remove leading comma and space.
+ } else {
+ $sort_part .= 'date';
}
if (($canViewReports || $isClient) && $options['users'] && !$grouping_by_user)
$sort_part .= ', user, type';
$val['expense'] = str_replace('.', $user->decimal_mark, $val['expense']);
}
- if (!$no_grouping) $val['grouped_by'] = ttReportHelper::makeGroupByKey($options, $val);
+ if ($grouping) $val['grouped_by'] = ttReportHelper::makeGroupByKey($options, $val);
$val['date'] = ttDateToUserFormat($val['date']);
$report_items[] = $val;
static function getSubtotals($options) {
global $user;
- $group_fields = ttReportHelper::makeGroupByFieldsPart($options);
- if (!$group_fields) return null;
-
$mdb2 = getConnection();
$concat_part = ttReportHelper::makeConcatPart($options);
$concat_part = ttReportHelper::makeConcatExpensesPart($options);
$join_part = ttReportHelper::makeJoinExpensesPart($options);
$where = ttReportHelper::getExpenseWhere($options);
- $group_by_part = ttReportHelper::makeGroupByExpensesPart($options);
+ $group_by_expenses_part = ttReportHelper::makeGroupByExpensesPart($options);
$sql_for_expenses = "select $concat_part, null as time";
if ($options['show_work_units']) $sql_for_expenses .= ", null as units";
- $sql_for_expenses .= ", sum(ei.cost) as cost, sum(ei.cost) as expenses from tt_expense_items ei $join_part $where $group_by_part";
+ $sql_for_expenses .= ", sum(ei.cost) as cost, sum(ei.cost) as expenses from tt_expense_items ei $join_part $where $group_by_expenses_part";
// Create a combined query.
- $combined = "select group_field, sum(time) as time";
+ $fields = ttReportHelper::makeCombinedSelectPart($options);
+ $combined = "select $fields, sum(time) as time";
if ($options['show_work_units']) $combined .= ", sum(units) as units";
- $combined .= ", sum(cost) as cost, sum(expenses) as expenses from (($sql) union all ($sql_for_expenses)) t group by group_field";
+ $combined .= ", sum(cost) as cost, sum(expenses) as expenses from (($sql) union all ($sql_for_expenses)) t group by $fields";
$sql = $combined;
}
$res = $mdb2->query($sql);
if (is_a($res, 'PEAR_Error')) die($res->getMessage());
while ($val = $res->fetchRow()) {
-// TODO: consider writing a function that properly formats a date part in a multi-part key.
-//
-// if ('date' == $group_by_option) {
-// $val['group_field'] = ttDateToUserFormat($val['group_field']);
-// }
$time = $val['time'] ? sec_to_time_fmt_hm($val['time']) : null;
+ $rowLabel = ttReportHelper::makeGroupByLabel($val['group_field'], $options);
if ($options['show_cost']) {
if ('.' != $user->decimal_mark) {
$val['cost'] = str_replace('.', $user->decimal_mark, $val['cost']);
$val['expenses'] = str_replace('.', $user->decimal_mark, $val['expenses']);
}
- $subtotals[$val['group_field']] = array('name'=>$val['group_field'],'time'=>$time, 'units'=> $val['units'], 'cost'=>$val['cost'],'expenses'=>$val['expenses']);
+ $subtotals[$val['group_field']] = array('name'=>$rowLabel,'user'=>$val['user'],'project'=>$val['project'],'task'=>$val['task'],'client'=>$val['client'],'cf_1'=>$val['cf_1'],'time'=>$time,'units'=> $val['units'],'cost'=>$val['cost'],'expenses'=>$val['expenses']);
} else
- $subtotals[$val['group_field']] = array('name'=>$val['group_field'],'time'=>$time, 'units'=> $val['units']);
+ $subtotals[$val['group_field']] = array('name'=>$rowLabel,'user'=>$val['user'],'project'=>$val['project'],'task'=>$val['task'],'client'=>$val['client'],'cf_1'=>$val['cf_1'],'time'=>$time, 'units'=> $val['units']);
}
return $subtotals;
// makeGroupByPart builds a combined group by part for sql query for time items using group_by1,
// group_by2, and group_by3 values passed in $options.
static function makeGroupByPart($options) {
- $no_grouping = ($options['group_by1'] == null || $options['group_by1'] == 'no_grouping') &&
- ($options['group_by2'] == null || $options['group_by2'] == 'no_grouping') &&
- ($options['group_by3'] == null || $options['group_by3'] == 'no_grouping');
- if ($no_grouping) return null;
+ if (!ttReportHelper::grouping($options)) return null;
$group_by1 = $options['group_by1'];
$group_by2 = $options['group_by2'];
}
// Remove garbage from the beginning.
$group_by_parts = ltrim($group_by_parts, ', ');
- $group_by_part = "group by $group_by_parts";
+ if ($group_by_parts)
+ $group_by_part = "group by $group_by_parts";
return $group_by_part;
}
break;
case 'user':
$what_to_concat .= ", ' - ', u.name";
+ $fields_part .= ', u.name as user';
break;
case 'client':
$what_to_concat .= ", ' - ', coalesce(c.name, 'Null')";
+ $fields_part .= ', c.name as client';
break;
case 'project':
$what_to_concat .= ", ' - ', coalesce(p.name, 'Null')";
+ $fields_part .= ', p.name as project';
break;
case 'task':
$what_to_concat .= ", ' - ', coalesce(t.name, 'Null')";
+ $fields_part .= ', t.name as task';
break;
case 'cf_1':
$what_to_concat .= ", ' - ', coalesce(cfo.value, 'Null')";
+ $fields_part .= ', cfo.value as cf_1';
break;
}
switch ($group_by2) {
break;
case 'user':
$what_to_concat .= ", ' - ', u.name";
+ $fields_part .= ', u.name as user';
break;
case 'client':
$what_to_concat .= ", ' - ', coalesce(c.name, 'Null')";
+ $fields_part .= ', c.name as client';
break;
case 'project':
$what_to_concat .= ", ' - ', coalesce(p.name, 'Null')";
+ $fields_part .= ', p.name as project';
break;
case 'task':
$what_to_concat .= ", ' - ', coalesce(t.name, 'Null')";
+ $fields_part .= ', t.name as task';
break;
case 'cf_1':
$what_to_concat .= ", ' - ', coalesce(cfo.value, 'Null')";
+ $fields_part .= ', cfo.value as cf_1';
break;
}
switch ($group_by3) {
break;
case 'user':
$what_to_concat .= ", ' - ', u.name";
+ $fields_part .= ', u.name as user';
break;
case 'client':
$what_to_concat .= ", ' - ', coalesce(c.name, 'Null')";
+ $fields_part .= ', c.name as client';
break;
case 'project':
$what_to_concat .= ", ' - ', coalesce(p.name, 'Null')";
+ $fields_part .= ', p.name as project';
break;
case 'task':
$what_to_concat .= ", ' - ', coalesce(t.name, 'Null')";
+ $fields_part .= ', t.name as task';
break;
case 'cf_1':
$what_to_concat .= ", ' - ', coalesce(cfo.value, 'Null')";
+ $fields_part .= ', cfo.value as cf_1';
break;
}
// Remove garbage from both ends.
$what_to_concat = trim($what_to_concat, "', -");
$concat_part = "concat($what_to_concat) as group_field";
$concat_part = trim($concat_part, ' -');
- return $concat_part;
+ return "$concat_part $fields_part";
}
// makeConcatPart builds a concatenation part for getSubtotals query (for expense items).
break;
case 'user':
$what_to_concat .= ", ' - ', u.name";
+ $fields_part .= ', u.name as user';
break;
case 'client':
$what_to_concat .= ", ' - ', coalesce(c.name, 'Null')";
+ $fields_part .= ', c.name as client';
break;
case 'project':
$what_to_concat .= ", ' - ', coalesce(p.name, 'Null')";
+ $fields_part .= ', p.name as project';
+ break;
+
+ case 'task':
+ $what_to_concat .= ", ' - ', 'Null'";
+ $fields_part .= ', null as task';
+ break;
+
+ case 'cf_1':
+ $what_to_concat .= ", ' - ', 'Null'";
+ $fields_part .= ', null as cf_1';
break;
}
switch ($group_by2) {
break;
case 'user':
$what_to_concat .= ", ' - ', u.name";
+ $fields_part .= ', u.name as user';
break;
case 'client':
$what_to_concat .= ", ' - ', coalesce(c.name, 'Null')";
+ $fields_part .= ', c.name as client';
break;
case 'project':
$what_to_concat .= ", ' - ', coalesce(p.name, 'Null')";
+ $fields_part .= ', p.name as project';
+ break;
+
+ case 'task':
+ $what_to_concat .= ", ' - ', 'Null'";
+ $fields_part .= ', null as task';
+ break;
+
+ case 'cf_1':
+ $what_to_concat .= ", ' - ', 'Null'";
+ $fields_part .= ', null as cf_1';
break;
}
switch ($group_by3) {
break;
case 'user':
$what_to_concat .= ", ' - ', u.name";
+ $fields_part .= ', u.name as user';
break;
case 'client':
$what_to_concat .= ", ' - ', coalesce(c.name, 'Null')";
+ $fields_part .= ', c.name as client';
break;
case 'project':
$what_to_concat .= ", ' - ', coalesce(p.name, 'Null')";
+ $fields_part .= ', p.name as project';
+ break;
+
+ case 'task':
+ $what_to_concat .= ", ' - ', 'Null'";
+ $fields_part .= ', null as task';
+ break;
+
+ case 'cf_1':
+ $what_to_concat .= ", ' - ', 'Null'";
+ $fields_part .= ', null as cf_1';
break;
}
- // Remove garbage from both ends.
- $what_to_concat = trim($what_to_concat, "', -");
+ // Remove garbage from the beginning.
+ if ($what_to_concat)
+ $what_to_concat = substr($what_to_concat, 8);
$concat_part = "concat($what_to_concat) as group_field";
- $concat_part = trim($concat_part, ' -');
- return $concat_part;
+ return "$concat_part $fields_part";
+ }
+
+ // makeCombinedSelectPart builds a list of fields for a combined select on a union for getSubtotals.
+ // This is used when we include expenses.
+ static function makeCombinedSelectPart($options) {
+ $group_by1 = $options['group_by1'];
+ $group_by2 = $options['group_by2'];
+ $group_by3 = $options['group_by3'];
+
+ $fields = "group_field";
+
+ switch ($group_by1) {
+ case 'user':
+ $fields .= ', user';
+ break;
+ case 'client':
+ $fields_part .= ', client';
+ break;
+ case 'project':
+ $fields .= ', project';
+ break;
+
+ case 'task':
+ $fields .= ', task';
+ break;
+
+ case 'cf_1':
+ $fields .= ', cf_1';
+ break;
+ }
+ switch ($group_by2) {
+ case 'user':
+ $fields .= ', user';
+ break;
+ case 'client':
+ $fields_part .= ', client';
+ break;
+ case 'project':
+ $fields .= ', project';
+ break;
+
+ case 'task':
+ $fields .= ', task';
+ break;
+
+ case 'cf_1':
+ $fields .= ', cf_1';
+ break;
+ }
+ switch ($group_by3) {
+ case 'user':
+ $fields .= ', user';
+ break;
+ case 'client':
+ $fields_part .= ', client';
+ break;
+ case 'project':
+ $fields .= ', project';
+ break;
+
+ case 'task':
+ $fields .= ', task';
+ break;
+
+ case 'cf_1':
+ $fields .= ', cf_1';
+ break;
+ }
+ return $fields;
}
// makeJoinPart builds a left join part for getSubtotals query (for time items).
return $group_by_fields;
}
- // grouping determines if we are grooping the project by either group_by1,
+ // grouping determines if we are grouping the report by either group_by1,
// group_by2, or group_by3 values passed in $options.
static function grouping($options) {
$grouping = ($options['group_by1'] != null && $options['group_by1'] != 'no_grouping') ||
return false;
}
+
+ // groupingBy determines if we are grouping a report by a value of $what
+ // ('user', 'project', etc.) by checking group_by1, group_by2, and group_by3
+ // values passed in $options.
+ static function groupingBy($what, $options) {
+ $grouping = ($options['group_by1'] != null && $options['group_by1'] != $what) ||
+ ($options['group_by2'] != null && $options['group_by2'] != $what) ||
+ ($options['group_by3'] != null && $options['group_by3'] != $what);
+ return $grouping;
+ }
// makeGroupByHeader builds a column header for a totals-only report using group_by1,
// group_by2, and group_by3 values passed in $options.
$group_by_header = ltrim($group_by_header, ' -');
return $group_by_header;
}
+
+ // makeGroupByXmlTag creates an xml tag for a totals only report using group_by1,
+ // group_by2, and group_by3 values passed in $options.
+ static function makeGroupByXmlTag($options) {
+ if ($options['group_by1'] != null && $options['group_by1'] != 'no_grouping') {
+ // We have group_by1.
+ $tag .= '_'.$options['group_by1'];
+ }
+ if ($options['group_by2'] != null && $options['group_by2'] != 'no_grouping') {
+ // We have group_by2.
+ $tag .= '_'.$options['group_by2'];
+ }
+ if ($options['group_by3'] != null && $options['group_by3'] != 'no_grouping') {
+ // We have group_by3.
+ $tag .= '_'.$options['group_by3'];
+ }
+ $tag = ltrim($tag, '_');
+ return $tag;
+ }
+
+ // makeGroupByLabel builds a label for one row in a "Totals only" report of grouped by items.
+ // It does one thing: if we are grouping by date, the date format is converted for user.
+ static function makeGroupByLabel($key, $options) {
+ if (!ttReportHelper::groupingBy('date', $options))
+ return $key; // No need to format.
+
+ global $user;
+ if ($user->date_format == DB_DATEFORMAT)
+ return $key; // No need to format.
+
+ $label = $key;
+ if (preg_match('/\d\d\d\d-\d\d-\d\d/', $key, $matches)) {
+ // Replace the first found match of a date in DB_DATEFORMAT.
+ // This is not entirely clean but better than nothing for a label in a row.
+ $userDate = ttDateToUserFormat($matches[0]);
+ $label = str_replace($matches[0], $userDate, $key);
+ }
+ return $label;
+ }
}