| 1 |
<?php
|
| 2 |
|
| 3 |
define('CT_WORK_HOUR', 60 * 60);
|
| 4 |
define('CT_WORK_DAY', 60 * 60 * 24);
|
| 5 |
define('CT_WORK_WEEK', 60 * 60 * 24 * 7);
|
| 6 |
|
| 7 |
define('CT_WORK_STARTFIN', 0);
|
| 8 |
define('CT_WORK_DURATION', 1);
|
| 9 |
define('CT_WORK_STARTFIN_AND', 2);
|
| 10 |
define('CT_WORK_DURATION_AND', 3);
|
| 11 |
|
| 12 |
|
| 13 |
/**
|
| 14 |
* Implementation of hook_help
|
| 15 |
*/
|
| 16 |
function casetracker_work_help($section) {
|
| 17 |
switch ($section) {
|
| 18 |
case 'admin/build/modules#description':
|
| 19 |
return t('Keep track of time spent working.');
|
| 20 |
}
|
| 21 |
}
|
| 22 |
|
| 23 |
/**
|
| 24 |
* Implementation of hook_user().
|
| 25 |
*/
|
| 26 |
function casetracker_work_user($type, $edit, &$user, $category = NULL) {
|
| 27 |
$rates = casetracker_work_get_rates(true);
|
| 28 |
if ($type == 'form' && $category == 'account' && user_access('manage work and rates')) {
|
| 29 |
// Present a form for selecting a default rate per user.
|
| 30 |
$form['casetracker_work'] = array(
|
| 31 |
'#type'=>'fieldset',
|
| 32 |
'#title' => t('Case Tracker settings'),
|
| 33 |
'#weight' => 6,
|
| 34 |
'#collapsible' => true,
|
| 35 |
);
|
| 36 |
$form['casetracker_work']['casetracker_rate'] = array(
|
| 37 |
'#type' => 'select',
|
| 38 |
'#title' => t('Default rate type'),
|
| 39 |
'#default_value' => strlen($edit['casetracker_rate']) ? $edit['casetracker_rate'] : '',
|
| 40 |
'#options' => $rates,
|
| 41 |
'#description' => t('Select the default rate for this user.'),
|
| 42 |
);
|
| 43 |
}
|
| 44 |
return $form;
|
| 45 |
}
|
| 46 |
|
| 47 |
/**
|
| 48 |
* Implementation of hook_perm().
|
| 49 |
*/
|
| 50 |
function casetracker_work_perm() {
|
| 51 |
return array('manage work and rates', 'log work',);
|
| 52 |
}
|
| 53 |
|
| 54 |
/**
|
| 55 |
* Implementation of hook_menu().
|
| 56 |
*/
|
| 57 |
function casetracker_work_menu($may_cache) {
|
| 58 |
$items = array();
|
| 59 |
if ($may_cache) {
|
| 60 |
$items[] = array(
|
| 61 |
'path' => 'casetracker/work/add', 'title' => t('Log time'),
|
| 62 |
'access' => user_access('log work'),
|
| 63 |
'callback' => 'casetracker_work_entry',
|
| 64 |
'callback arguments' => array('add'),
|
| 65 |
'type' => MENU_CALLBACK,
|
| 66 |
);
|
| 67 |
$items[] = array(
|
| 68 |
'path' => 'casetracker/work/edit', 'title' => t('Edit time'),
|
| 69 |
'access' => user_access('manage work and rates'),
|
| 70 |
'callback' => 'casetracker_work_entry',
|
| 71 |
'callback arguments' => array('edit'),
|
| 72 |
'type' => MENU_CALLBACK,
|
| 73 |
);
|
| 74 |
$items[] = array(
|
| 75 |
'access' => user_access('administer case tracker'),
|
| 76 |
'callback' => 'drupal_get_form',
|
| 77 |
'callback arguments' => array('casetracker_work_admin_settings'),
|
| 78 |
'description' => t('Settings for casetracker work, timesheets.'),
|
| 79 |
'path' => 'admin/settings/casetracker_work',
|
| 80 |
'title' => t('Case Tracker work'),
|
| 81 |
);
|
| 82 |
}
|
| 83 |
return $items;
|
| 84 |
}
|
| 85 |
|
| 86 |
function casetracker_work_admin_settings() {
|
| 87 |
$form = array();
|
| 88 |
$form['casetracker_work'] = array(
|
| 89 |
'#type' => 'fieldset',
|
| 90 |
'#title' => t('General settings'),
|
| 91 |
'#collapsible' => TRUE,
|
| 92 |
'#collapsed' => FALSE,
|
| 93 |
);
|
| 94 |
$form['casetracker_work_locked'] = array(
|
| 95 |
'#type' => 'fieldset',
|
| 96 |
'#title' => t('Settings edited in settings.php'),
|
| 97 |
'#description' => t('You need to edit the $conf array in settings.php. (This will not be necessary in future versions.)'),
|
| 98 |
'#collapsible' => TRUE,
|
| 99 |
'#collapsed' => FALSE,
|
| 100 |
);
|
| 101 |
|
| 102 |
$vocabs = array(0 => '-- N/A --');
|
| 103 |
foreach (taxonomy_get_vocabularies() AS $v) {
|
| 104 |
$vocabs[$v->vid] = $v->name;
|
| 105 |
}
|
| 106 |
|
| 107 |
foreach (node_get_types() AS $type) {
|
| 108 |
$node_types[$type->type] = $type->name;
|
| 109 |
}
|
| 110 |
|
| 111 |
// $conf['casetracker_work_base_cost'] = 70;
|
| 112 |
// Currency
|
| 113 |
//$conf['casetracker_work_base_currency'] = 'AUD';
|
| 114 |
// Default rate if none for user
|
| 115 |
// $conf['casetracker_work_rate_default'] = 'L1';
|
| 116 |
|
| 117 |
$rates = casetracker_work_get_rates(true);
|
| 118 |
|
| 119 |
$form['casetracker_work']['casetracker_work_attach_types'] = array(
|
| 120 |
'#type' => 'select',
|
| 121 |
'#multiple' => TRUE,
|
| 122 |
'#title' => t('Relate work to'),
|
| 123 |
'#default_value' => variable_get('casetracker_work_attach_types', 'casetracker_basic_case'),
|
| 124 |
'#options' => $node_types,
|
| 125 |
'#description' => t('Work can be associated with these node types.'),
|
| 126 |
);
|
| 127 |
$form['casetracker_work']['casetracker_work_category'] = array(
|
| 128 |
'#type' => 'select',
|
| 129 |
'#title' => t('Categorize by taxonomy'),
|
| 130 |
'#autocomplete_path' => 'casetracker/autocomplete',
|
| 131 |
'#default_value' => variable_get('casetracker_work_category', 0),
|
| 132 |
'#options' => $vocabs,
|
| 133 |
'#description' => t('Allow categorization of work by this vocabulary. Note that casetracker_work will look for a default by looking at the parent node.'),
|
| 134 |
);
|
| 135 |
$options_time_types = array(
|
| 136 |
CT_WORK_STARTFIN => 'Start-Finish Only',
|
| 137 |
CT_WORK_DURATION => 'Duration Only',
|
| 138 |
CT_WORK_STARTFIN_AND => 'Start-Finish (Duration Optional)',
|
| 139 |
CT_WORK_DURATION_AND => 'Duration (Start-Finish Optional)',
|
| 140 |
);
|
| 141 |
$form['casetracker_work']['casetracker_work_time_type'] = array(
|
| 142 |
'#type' => 'select',
|
| 143 |
'#title' => t('Data entry type'),
|
| 144 |
'#default_value' => variable_get('casetracker_work_time_type', 0),
|
| 145 |
'#options' => $options_time_types,
|
| 146 |
'#description' => t('Options for layout of time data entry.'),
|
| 147 |
);
|
| 148 |
|
| 149 |
// These values are locked while they are set in settings.php. They will be
|
| 150 |
// unlocked once the rates logic is bedded down and the settings move to the database.
|
| 151 |
$form['casetracker_work_locked']['casetracker_work_rate_default'] = array(
|
| 152 |
'#type' => 'select',
|
| 153 |
'#title' => t('Default rate'),
|
| 154 |
'#disabled' => true,
|
| 155 |
'#options' => $rates,
|
| 156 |
'#default_value' => $rates[variable_get('casetracker_work_rate_default', '')],
|
| 157 |
'#description' => t('Rate to use by default (if rate not found for current user).'),
|
| 158 |
);
|
| 159 |
$form['casetracker_work_locked']['casetracker_work_base_cost'] = array(
|
| 160 |
'#type' => 'textfield',
|
| 161 |
'#size' => 10,
|
| 162 |
'#title' => 'Base cost/hr',
|
| 163 |
'#disabled' => true,
|
| 164 |
'#default_value' => variable_get('casetracker_work_base_cost', 0),
|
| 165 |
);
|
| 166 |
$form['casetracker_work_locked']['casetracker_work_base_currency'] = array(
|
| 167 |
'#type' => 'textfield',
|
| 168 |
'#size' => 10,
|
| 169 |
'#title' => 'Base currency',
|
| 170 |
'#disabled' => true,
|
| 171 |
'#default_value' => variable_get('casetracker_work_base_currency', ''),
|
| 172 |
);
|
| 173 |
return system_settings_form($form);
|
| 174 |
}
|
| 175 |
|
| 176 |
/*
|
| 177 |
* Get rates list.
|
| 178 |
* @param $options bool
|
| 179 |
* If for an form select list.
|
| 180 |
*
|
| 181 |
*/
|
| 182 |
function casetracker_work_get_rates($options = false) {
|
| 183 |
$saved_rates = variable_get('casetracker_work_rates', array());
|
| 184 |
foreach ($saved_rates as $rate) {
|
| 185 |
$rates[$rate['code']] = ($options) ? $rate['title'] : $rate;
|
| 186 |
}
|
| 187 |
return $rates;
|
| 188 |
}
|
| 189 |
|
| 190 |
/*
|
| 191 |
* Catch the casetracker/work/edit path and direct to the main work entry routine.
|
| 192 |
*
|
| 193 |
*/
|
| 194 |
function casetracker_work_edit() {
|
| 195 |
return casetracker_work_load(arg(3));
|
| 196 |
}
|
| 197 |
|
| 198 |
function casetracker_work_load($ctwid) {
|
| 199 |
return db_fetch_object(db_query('SELECT * FROM casetracker_work WHERE ctwid = %d', $ctwid));
|
| 200 |
}
|
| 201 |
|
| 202 |
function casetracker_work_entry($op, $arg1 = null) {
|
| 203 |
return drupal_get_form('casetracker_work_entry_form', $op, ($arg1) ? $arg1 : arg(3));
|
| 204 |
}
|
| 205 |
|
| 206 |
|
| 207 |
/*
|
| 208 |
* This is the main work entry add/edit (also called by casetracker_work_edit).
|
| 209 |
* @param $op string
|
| 210 |
* 'add' = a new entry, $values must be a nid
|
| 211 |
* 'edit' = edit an entry, $values must be a ctwid, or $values a work object by casetracker_work_load($ctwid)
|
| 212 |
* @param $arg1 mixed
|
| 213 |
* a work object or a nid or a ctwid depending on op.
|
| 214 |
*
|
| 215 |
* Form values: Database values:
|
| 216 |
* ------------ ----------------
|
| 217 |
* [ctwid] => 99 `ctwid` = 99
|
| 218 |
* [nid] => 9 `nid` = 9
|
| 219 |
* [activity] => Blah blah `activity` = Blah blah
|
| 220 |
* [date_start] => 2006-11-16 --
|
| 221 |
* [start] => 21:00 `start` = 1163088960
|
| 222 |
* [finish] => 22:00 `finish` = 1163092620 (`finish` = 0 if the entry is duration only)
|
| 223 |
* [date_finish] => 2006-11-16 --
|
| 224 |
* [duration] => 1:00 `duration` = 3600
|
| 225 |
* [uid] => Bon Jovi `uid` = 7
|
| 226 |
* [rate] => L1 `rate` = L1
|
| 227 |
*
|
| 228 |
*/
|
| 229 |
|
| 230 |
function casetracker_work_entry_form($op, $arg1 = null) {
|
| 231 |
|
| 232 |
global $user;
|
| 233 |
|
| 234 |
// Prepare an array of the default values.
|
| 235 |
$defaults = array();
|
| 236 |
|
| 237 |
// Build some basic values
|
| 238 |
if ($op == 'edit') {
|
| 239 |
// Don't allow non admin to edit times
|
| 240 |
if (!user_access('manage work and rates')) {
|
| 241 |
// TODO: better control of editing old times. Need a lock field in the table.
|
| 242 |
return array();
|
| 243 |
}
|
| 244 |
$edit = true;
|
| 245 |
if (is_numeric($arg1)) {
|
| 246 |
$values = casetracker_work_load($arg1);
|
| 247 |
}
|
| 248 |
$defaults = (array)$values;
|
| 249 |
}
|
| 250 |
else {
|
| 251 |
if (!user_access('log work')) {
|
| 252 |
return array();
|
| 253 |
}
|
| 254 |
$edit = false;
|
| 255 |
$defaults['nid'] = $arg1;
|
| 256 |
$defaults['rate'] = (isset($user->casetracker_rate)) ? $user->casetracker_rate : variable_get('casetracker_work_rate_default', '');
|
| 257 |
$defaults['activity'] = '';
|
| 258 |
}
|
| 259 |
|
| 260 |
// Get the type and name of the default node
|
| 261 |
if (is_numeric($defaults['nid'])) {
|
| 262 |
$node = node_load($defaults['nid']);
|
| 263 |
}
|
| 264 |
if (!isset($node->type)) {
|
| 265 |
drupal_set_message('Error, unable to determine a parent node for this work entry.', 'error');
|
| 266 |
return array();
|
| 267 |
}
|
| 268 |
|
| 269 |
$defaults['title'] = $node->title;
|
| 270 |
$defaults['type'] = $node->type;
|
| 271 |
$defaults['type_name'] = node_get_types('name', $defaults['type']);
|
| 272 |
|
| 273 |
// Determine the project info if applicable
|
| 274 |
$defaults['project'] = 0;
|
| 275 |
if (casetracker_work_project_types($defaults['type'])) {
|
| 276 |
// Find the parent project for the taxonomy default and list of cases.
|
| 277 |
$defaults['project'] = db_result(db_query('SELECT pid FROM {casetracker_case} WHERE nid = %d', $defaults['nid']));
|
| 278 |
}
|
| 279 |
|
| 280 |
// Find a vocab to use if applicable
|
| 281 |
$vid = variable_get('casetracker_work_category', 0);
|
| 282 |
|
| 283 |
if ($vid) {
|
| 284 |
// We have a vocabulary associated with a work entry. Build the select list.
|
| 285 |
$term_options = array();
|
| 286 |
$result = db_query('SELECT td.tid, td.name FROM term_data AS td WHERE td.vid = %d ORDER BY weight, name', $vid);
|
| 287 |
while ($row = db_fetch_object($result)) {
|
| 288 |
$term_options[$row->tid] = $row->name;
|
| 289 |
}
|
| 290 |
|
| 291 |
if ($edit) {
|
| 292 |
$defaults['tid'] = $values->tid;
|
| 293 |
}
|
| 294 |
else {
|
| 295 |
// Look for a default term to apply to this work, by looking for an
|
| 296 |
// existing vocab/term on the node (usually the 'case' node).
|
| 297 |
// Define the query.
|
| 298 |
$get_term_qry =
|
| 299 |
'SELECT td.tid
|
| 300 |
FROM {node} AS n
|
| 301 |
INNER JOIN {term_node} AS tn ON n.nid = tn.nid
|
| 302 |
INNER JOIN {term_data} AS td ON tn.tid = td.tid
|
| 303 |
INNER JOIN {vocabulary} AS v ON td.vid = v.vid
|
| 304 |
WHERE n.nid = %d AND v.vid = %d';
|
| 305 |
|
| 306 |
// Look at the node to which we are attaching this work entry.
|
| 307 |
$defaults['tid'] = db_result( db_query($get_term_qry, $defaults['nid'], $vid));
|
| 308 |
|
| 309 |
// If the node type we are attaching to is a 'case' and we haven't found an
|
| 310 |
// appropriate term yet, look at the case's project node.
|
| 311 |
if (!$defaults['tid'] && $defaults['project']) {
|
| 312 |
$defaults['tid'] = db_result( db_query($get_term_qry, $defaults['project'], $vid));
|
| 313 |
}
|
| 314 |
}
|
| 315 |
}
|
| 316 |
/*
|
| 317 |
* Finish finding default term.
|
| 318 |
*/
|
| 319 |
|
| 320 |
// Determine if this is a duration time entry.
|
| 321 |
if ($op == 'edit') {
|
| 322 |
$duration = ($values->finish == 0) ? TRUE : FALSE;
|
| 323 |
// Some extra logic to raise a watchdog warning if the entry being edited
|
| 324 |
// contravenes current settings. (Eg. settings allow only Duration,
|
| 325 |
// but we are editing a Start-finish entry from the database.
|
| 326 |
// After raising the warning, we make the data entry page look nice,
|
| 327 |
// however this will fail in the validation unless the user changes the
|
| 328 |
// values appropriately.
|
| 329 |
$time_type = variable_get('casetracker_work_time_type', CT_WORK_DURATION_AND);
|
| 330 |
if ($duration && ($time_type == CT_WORK_STARTFIN)) {
|
| 331 |
watchdog('casetracker', 'A work entry has been viewed/edited that is a Duration entry, however current casetracker_case settings stipulate that only Start-Finish entries are allowed', WATCHDOG_WARNING, l('view', 'casetracker/work/edit/'. $defaults['ctwid']));
|
| 332 |
$time_type = CT_WORK_STARTFIN_AND;
|
| 333 |
$duration = !$duration;
|
| 334 |
}
|
| 335 |
elseif (!$duration && ($time_type == CT_WORK_DURATION)) {
|
| 336 |
watchdog('casetracker', 'A work entry has been viewed/edited that is a Start-Finish entry, however current casetracker_case settings stipulate that only Start-Finish entries are allowed', WATCHDOG_WARNING, l('view', 'casetracker/work/edit/'. $defaults['ctwid']));
|
| 337 |
$time_type = CT_WORK_DURATION_AND;
|
| 338 |
$duration = !$duration;
|
| 339 |
}
|
| 340 |
}
|
| 341 |
else {
|
| 342 |
$time_type = variable_get('casetracker_work_time_type', CT_WORK_DURATION_AND);
|
| 343 |
$duration = ($time_type == CT_WORK_DURATION_AND || $time_type == CT_WORK_DURATION) ? TRUE : FALSE;
|
| 344 |
}
|
| 345 |
|
| 346 |
// Calculate date/time in timestamps/seconds.
|
| 347 |
// Use the $clock array to store the raw time data (database format).
|
| 348 |
// Then use the $input array to store the default visible data-entry values.
|
| 349 |
|
| 350 |
$clock = array();
|
| 351 |
if ($edit && $duration) {
|
| 352 |
// Editing a database duration entry.
|
| 353 |
$clock['start'] = $values->start;
|
| 354 |
$clock['duration'] = $values->duration;
|
| 355 |
}
|
| 356 |
elseif ($edit && !$duration) {
|
| 357 |
// Editing a database start-finish entry.
|
| 358 |
$clock['start'] = $values->start ;
|
| 359 |
$clock['finish'] = $values->finish;
|
| 360 |
}
|
| 361 |
elseif (!$edit && !$duration) {
|
| 362 |
// Editing a new start-finish entry.
|
| 363 |
$clock['start'] = _casetracker_work_time_round(time(), 'down', 'hour');
|
| 364 |
$clock['finish'] = $clock['start'] + (CT_WORK_HOUR);
|
| 365 |
}
|
| 366 |
else {
|
| 367 |
// Editing a new duration entry.
|
| 368 |
$clock['start'] = _casetracker_work_time_round(time(), 'down', 'hour');
|
| 369 |
$clock['duration'] = CT_WORK_HOUR;
|
| 370 |
}
|
| 371 |
|
| 372 |
// Calculate form values in human-readable format.
|
| 373 |
$input = array();
|
| 374 |
$input['date_start'] = format_date($clock['start'], 'custom', 'Y-m-d');
|
| 375 |
$input['start'] = ($duration) ? '' : format_date($clock['start'],'custom','H:i');
|
| 376 |
$input['finish'] = ($duration) ? '' : format_date($clock['finish'],'custom','H:i');
|
| 377 |
$input['date_finish'] = ($duration) ? '' : format_date($clock['finish'], 'custom', 'Y-m-d');
|
| 378 |
$input['duration'] = ($duration) ? _casetracker_work_seconds_display($clock['duration'], 'hh:mm') : '';
|
| 379 |
|
| 380 |
$form['work']['ctwid'] = array(
|
| 381 |
'#type' => 'hidden',
|
| 382 |
'#default_value' => $defaults['ctwid'],
|
| 383 |
);
|
| 384 |
|
| 385 |
$form['work']['nid'] = array(
|
| 386 |
'#type' => 'hidden',
|
| 387 |
'#default_value' => $defaults['nid'],
|
| 388 |
);
|
| 389 |
drupal_set_title(t('Add time to ') . t($defaults['type_name']));
|
| 390 |
$form['work']['activity'] = array(
|
| 391 |
'#type' => 'textfield',
|
| 392 |
'#title' => t('Activity summary'),
|
| 393 |
'#required' => TRUE,
|
| 394 |
'#default_value' => $values->activity,
|
| 395 |
'#rows' => 1,
|
| 396 |
'#maxlength' => 2048,
|
| 397 |
);
|
| 398 |
|
| 399 |
if ($vid) {
|
| 400 |
$form['work']['tid'] = array(
|
| 401 |
'#type' => 'select',
|
| 402 |
'#title' => t('Category'),
|
| 403 |
'#required' => TRUE,
|
| 404 |
'#options' => $term_options,
|
| 405 |
'#default_value' => $defaults['tid'],
|
| 406 |
);
|
| 407 |
}
|
| 408 |
else {
|
| 409 |
$form['work']['tid'] = array(
|
| 410 |
'#type' => 'hidden',
|
| 411 |
'#default_value' => 0,
|
| 412 |
);
|
| 413 |
}
|
| 414 |
$form['work']['rate'] = array(
|
| 415 |
'#type' => 'select',
|
| 416 |
'#title' => t('Rate'),
|
| 417 |
'#weight' => 11,
|
| 418 |
'#options' => casetracker_work_get_rates(true),
|
| 419 |
'#default_value' => ($edit) ? $defaults['rate'] : $user->casetracker_rate,
|
| 420 |
'#description' => t('Hourly rate based on agreed terms.'),
|
| 421 |
);
|
| 422 |
$form['work']['date_start'] = array(
|
| 423 |
'#type' => 'textfield',
|
| 424 |
'#title' => ($duration) ? t('Date') : t('Start date'),
|
| 425 |
'#required' => TRUE,
|
| 426 |
'#maxlength' => 12,
|
| 427 |
'#size' => 20,
|
| 428 |
'#default_value' => $input['date_start'],
|
| 429 |
'#description' => t('Enter yyyy-mm-dd'),
|
| 430 |
);
|
| 431 |
$form['work']['start'] = array(
|
| 432 |
'#type' => 'textfield',
|
| 433 |
'#title' => t('Start'),
|
| 434 |
'#maxlength' => 8,
|
| 435 |
'#size' => 20,
|
| 436 |
'#default_value' => $input['start'],
|
| 437 |
'#description' => t('Enter hh:mm'),
|
| 438 |
);
|
| 439 |
$form['work']['finish'] = array(
|
| 440 |
'#type' => 'textfield',
|
| 441 |
'#title' => t('Finish'),
|
| 442 |
'#maxlength' => 8,
|
| 443 |
'#size' => 20,
|
| 444 |
'#default_value' => $input['finish'],
|
| 445 |
'#description' => t('Enter hh:mm'),
|
| 446 |
);
|
| 447 |
$form['work']['date_finish'] = array(
|
| 448 |
'#type' => 'textfield',
|
| 449 |
'#title' => t('Finish date'),
|
| 450 |
'#maxlength' => 12,
|
| 451 |
'#size' => 20,
|
| 452 |
'#default_value' => $input['date_finish'],
|
| 453 |
'#description' => t('Enter yyyy-mm-dd'),
|
| 454 |
);
|
| 455 |
$form['work']['duration'] = array(
|
| 456 |
'#type' => 'textfield',
|
| 457 |
'#size' => 20,
|
| 458 |
'#title' => 'Duration',
|
| 459 |
'#default_value' => $input['duration'],
|
| 460 |
'#description' => t('Enter duration as <em>h:mm</em>, <em>mm</em>, <em>h,mm</em> etc.'),
|
| 461 |
);
|
| 462 |
|
| 463 |
$form['work']['extra'] = array(
|
| 464 |
'#type' => 'fieldset',
|
| 465 |
'#title' => t('Optional information'),
|
| 466 |
'#collapsible' => TRUE,
|
| 467 |
'#collapsed' => TRUE,
|
| 468 |
);
|
| 469 |
|
| 470 |
// Worker/rate are can be set
|
| 471 |
$form['work']['extra']['uid'] = array(
|
| 472 |
'#type' => 'textfield',
|
| 473 |
'#title' => t('Person'),
|
| 474 |
'#size' => 20,
|
| 475 |
'#weight' => 10,
|
| 476 |
'#disabled' => !user_access('manage work and rates'),
|
| 477 |
'#autocomplete_path' => 'casetracker/autocomplete',
|
| 478 |
'#default_value' => ($edit) ? casetracker_get_name($defaults->uid) : $user->name,
|
| 479 |
);
|
| 480 |
|
| 481 |
// Information for theming.
|
| 482 |
$form['theme']['#duration'] = $duration;
|
| 483 |
$form['theme']['#vid'] = $vid;
|
| 484 |
$form['theme']['#clock'] = $clock;
|
| 485 |
$form['theme']['#defaults'] = $defaults;
|
| 486 |
|
| 487 |
$form['work']['submit'] = array(
|
| 488 |
'#type' => 'submit',
|
| 489 |
'#value' => t('Save time'),
|
| 490 |
);
|
| 491 |
|
| 492 |
// Modify the form array based on the data-entry type specified
|
| 493 |
// in the casetracker_work settings.
|
| 494 |
|
| 495 |
// Modify form based on duration-entry only.
|
| 496 |
if ($time_type == CT_WORK_DURATION) {
|
| 497 |
$form['work']['duration']['#required'] = TRUE;
|
| 498 |
$form['work']['start']['#type'] = 'hidden';
|
| 499 |
$form['work']['finish']['#type'] = 'hidden';
|
| 500 |
$form['work']['date_finish']['#type'] = 'hidden';
|
| 501 |
}
|
| 502 |
// Modify form based on start-finish-entry only.
|
| 503 |
if ($time_type == CT_WORK_STARTFIN) {
|
| 504 |
$form['work']['start']['#required'] = TRUE;
|
| 505 |
$form['work']['finish']['#required'] = TRUE;
|
| 506 |
$form['work']['date_finish']['#required'] = TRUE;
|
| 507 |
$form['work']['duration']['#type'] = HIDDEN;
|
| 508 |
}
|
| 509 |
// Modify form based on duration-entry preferred.
|
| 510 |
if ($time_type == CT_WORK_DURATION_AND) {
|
| 511 |
// This won't be necessary when javascript is added to automatically
|
| 512 |
// remove the other values if duration is entered as an over-ride:
|
| 513 |
$form['work']['start']['#description'] = $form['work']['start']['#description'] .'<br /><strong>Note:</strong> To enter start-finish times instead of duration, you need to delete the value from the duration field';
|
| 514 |
$form['work']['extra']['start'] = $form['work']['start'];
|
| 515 |
$form['work']['extra']['finish'] = $form['work']['finish'];
|
| 516 |
$form['work']['extra']['date_finish'] = $form['work']['date_finish'];
|
| 517 |
unset($form['work']['start']);
|
| 518 |
unset($form['work']['finish']);
|
| 519 |
unset($form['work']['date_finish']);
|
| 520 |
}
|
| 521 |
// Modify form based on start-finish-entry preferred.
|
| 522 |
if ($time_type == CT_WORK_STARTFIN_AND) {
|
| 523 |
// This won't be necessary when javascript is added to automatically
|
| 524 |
// remove the other values if duration is entered as an over-ride:
|
| 525 |
$form['work']['duration']['#description'] = $form['work']['duration']['#description'] .'<br /><strong>Note:</strong> To enter a duration you need to delete the times from the Start & Finish Fields';
|
| 526 |
$form['work']['extra']['duration'] = $form['work']['duration'];
|
| 527 |
unset($form['work']['duration']);
|
| 528 |
}
|
| 529 |
|
| 530 |
return $form;
|
| 531 |
}
|
| 532 |
|
| 533 |
/*
|
| 534 |
*/
|
| 535 |
function theme_casetracker_work_entry_form(&$form) {
|
| 536 |
/*
|
| 537 |
* Style here for development purposes
|
| 538 |
* move to appropriate style sheet later.(?)
|
| 539 |
*/
|
| 540 |
|
| 541 |
// Themers: useful display data can found on the $form['theme'] element.
|
| 542 |
|
| 543 |
drupal_set_title('Record work on '. $form['theme']['#defaults']['type_name']);
|
| 544 |
|
| 545 |
$output .= '<div class="casetracker-work">';
|
| 546 |
|
| 547 |
$output .= '<h3>'. $form['theme']['#defaults']['title'] .'</h3>';
|
| 548 |
|
| 549 |
$rows = array();
|
| 550 |
if ($form['theme']['#duration']) {
|
| 551 |
$rows[1] = array();
|
| 552 |
if ($form['theme']['#vid']) {
|
| 553 |
$rows[2][] = drupal_render($form['work']['tid']);
|
| 554 |
}
|
| 555 |
$rows[2][] = drupal_render($form['work']['date_start']);
|
| 556 |
$rows[2][] = drupal_render($form['work']['duration']);
|
| 557 |
$rows[2][] = drupal_render($form['work']['rate']);
|
| 558 |
$rows[1][] = array('data' => drupal_render($form['work']['activity']), 'colspan' => count($rows[2]),);
|
| 559 |
}
|
| 560 |
else {
|
| 561 |
// First row.
|
| 562 |
$r = array();
|
| 563 |
if ($form['theme']['#vid']) {
|
| 564 |
$r[] = drupal_render($form['work']['tid']);
|
| 565 |
$r[] = array('data' => drupal_render($form['work']['activity']), 'colspan' => 3, );
|
| 566 |
}
|
| 567 |
else {
|
| 568 |
$r[] = array('data' => drupal_render($form['work']['activity']), 'colspan' => 4, );
|
| 569 |
}
|
| 570 |
$rows[] = $r;
|
| 571 |
// Second row.
|
| 572 |
$r = array();
|
| 573 |
$r[] = drupal_render($form['work']['date_start']);
|
| 574 |
$r[] = drupal_render($form['work']['start']);
|
| 575 |
$r[] = drupal_render($form['work']['finish']);
|
| 576 |
$r[] = drupal_render($form['work']['date_finish']);
|
| 577 |
$rows[] = $r;
|
| 578 |
}
|
| 579 |
|
| 580 |
$output .= theme('table', array(), $rows);
|
| 581 |
|
| 582 |
$output .= drupal_render($form);
|
| 583 |
$output .= '</div>';
|
| 584 |
return $output;
|
| 585 |
}
|
| 586 |
|
| 587 |
|
| 588 |
function casetracker_work_entry_form_validate($form_id, &$values) {
|
| 589 |
|
| 590 |
// TODO: make sure that worker and rate are default if user cannot administer resources
|
| 591 |
|
| 592 |
// Perform the conversions used by _submit which will trigger various errors.
|
| 593 |
_casetracker_work_string_to_timestamp($values['date_start'],'date');
|
| 594 |
|
| 595 |
// Check for either start-finish or duration scenario.
|
| 596 |
// Eg. don't test for an end-time if it's a duration entry only.
|
| 597 |
$enough_startfin = ($values['date_start'] && $values['start'] && $values['finish']) ? TRUE : FALSE;
|
| 598 |
$enough_duration = ($values['date_start'] && $values['duration']) ? TRUE : FALSE;
|
| 599 |
|
| 600 |
$date_start = _casetracker_work_string_to_timestamp($values['date_start'],'date');
|
| 601 |
|
| 602 |
switch (variable_get('casetracker_work_time_type', CT_WORK_DURATION_AND)) {
|
| 603 |
case CT_WORK_DURATION:
|
| 604 |
if (!$enough_duration) {
|
| 605 |
form_set_error('work', t('Date and duration required.'));
|
| 606 |
}
|
| 607 |
_casetracker_work_string_to_timestamp($values['duration'], 'duration');
|
| 608 |
break;
|
| 609 |
|
| 610 |
case CT_WORK_STARTFIN:
|
| 611 |
if (!$enough_startfin) {
|
| 612 |
form_set_error('work', t('Date and start/finish times are required.'));
|
| 613 |
}
|
| 614 |
$date_finish = _casetracker_work_string_to_timestamp($values['date_finish'],'date');
|
| 615 |
_casetracker_work_string_to_timestamp($values['start'], 'time', $date_start);
|
| 616 |
_casetracker_work_string_to_timestamp($values['finish'], 'time', $date_finish);
|
| 617 |
break;
|
| 618 |
|
| 619 |
case CT_WORK_DURATION_AND:
|
| 620 |
case CT_WORK_STARTFIN_AND:
|
| 621 |
if ($enough_duration) {
|
| 622 |
_casetracker_work_string_to_timestamp($values['duration'], 'duration');
|
| 623 |
}
|
| 624 |
elseif ($enough_startfin) {
|
| 625 |
$date_finish = _casetracker_work_string_to_timestamp($values['date_finish'],'date');
|
| 626 |
_casetracker_work_string_to_timestamp($values['start'], 'time', $date_start);
|
| 627 |
_casetracker_work_string_to_timestamp($values['finish'], 'time', $date_finish);
|
| 628 |
}
|
| 629 |
else {
|
| 630 |
form_set_error('work', (CT_WORK_DURATION_AND) ? t('CDate and duration required.') : t('DDate and start/finish times are required.'));
|
| 631 |
}
|
| 632 |
}
|
| 633 |
if (!casetracker_get_uid($values['uid'])) {
|
| 634 |
form_set_error('work', 'Invalid user name.');
|
| 635 |
}
|
| 636 |
|
| 637 |
}
|
| 638 |
|
| 639 |
function casetracker_work_entry_form_submit($form_id, &$values) {
|
| 640 |
// Determine which type of time entry we have.
|
| 641 |
// Assume values are already checked in _validate.
|
| 642 |
|
| 643 |
// Determine the type of entry we are making, "start-finish" or "duration".
|
| 644 |
$time_type = variable_get('casetracker_work_time_type', CT_WORK_DURATION_AND);
|
| 645 |
|
| 646 |
// Make a firm decision about the type of entry if we happen to be unsure.
|
| 647 |
switch ($time_type) {
|
| 648 |
case CT_WORK_DURATION_AND:
|
| 649 |
$enough_duration = ($values['date_start'] && $values['duration']) ? TRUE : FALSE;
|
| 650 |
$time_type = ($enough_duration) ? CT_WORK_DURATION : CT_WORK_STARTFIN;
|
| 651 |
break;
|
| 652 |
case CT_WORK_STARTFIN_AND:
|
| 653 |
$enough_startfin = ($values['date_start'] && $values['start'] && $values['finish']) ? TRUE : FALSE;
|
| 654 |
$time_type = ($enough_startfin) ? CT_WORK_STARTFIN : CT_WORK_DURATION;
|
| 655 |
break;
|
| 656 |
}
|
| 657 |
|
| 658 |
// We always need the start date.
|
| 659 |
$date_start = _casetracker_work_string_to_timestamp($values['date_start'],'date');
|
| 660 |
|
| 661 |
// Convert other strings to timestamps or seconds.
|
| 662 |
if ($time_type == CT_WORK_DURATION) {
|
| 663 |
$db['seconds'] = _casetracker_work_string_to_timestamp($values['duration'], 'duration');
|
| 664 |
$db['start'] = $date_start;
|
| 665 |
}
|
| 666 |
else {
|
| 667 |
$date_finish = _casetracker_work_string_to_timestamp($values['date_finish'],'date');
|
| 668 |
$db['start'] = _casetracker_work_string_to_timestamp($values['start'], 'time', $date_start);
|
| 669 |
$db['finish'] = _casetracker_work_string_to_timestamp($values['finish'], 'time', $date_finish);
|
| 670 |
$db['seconds'] = $db['finish'] - $db['start'];
|
| 671 |
}
|
| 672 |
|
| 673 |
|
| 674 |
$db['uid'] = casetracker_get_uid($values['uid']);
|
| 675 |
|
| 676 |
if ($values['ctwid'] == 0) {
|
| 677 |
|
| 678 |
db_query("INSERT INTO {casetracker_work}
|
| 679 |
(activity, nid, uid, tid, start, finish, duration, rate)
|
| 680 |
VALUES ('%s', %d, %d, %d, %d, %d, %d, '%s')",
|
| 681 |
$values['activity'], $values['nid'], $db['uid'], $values['tid'],
|
| 682 |
$db['start'], $db['finish'], $db['seconds'], $values['rate']);
|
| 683 |
}
|
| 684 |
else {
|
| 685 |
db_query("UPDATE {casetracker_work}
|
| 686 |
SET activity = '%s', nid = %d, uid = %d, tid = %d,
|
| 687 |
start = %d, finish = %d,
|
| 688 |
duration = %d, rate = '%s'
|
| 689 |
WHERE ctwid = %d",
|
| 690 |
$values['activity'], $values['nid'], $db['uid'], $values['tid'],
|
| 691 |
$db['start'], $db['finish'], $db['seconds'],
|
| 692 |
$values['rate'], $values['ctwid']);
|
| 693 |
}
|
| 694 |
|
| 695 |
drupal_goto('node/'. $values['nid']);
|
| 696 |
}
|
| 697 |
|
| 698 |
function casetracker_work_link($type, $node = NULL, $teaser = FALSE) {
|
| 699 |
|
| 700 |
if ($type != 'node' || !user_access('log work')) {
|
| 701 |
return;
|
| 702 |
}
|
| 703 |
$valid_types = variable_get('casetracker_work_attach_types', array('casetracker_basic_case' => 'casetracker_basic_case'));
|
| 704 |
if (isset($valid_types[$node->type])) {
|
| 705 |
$links = array();
|
| 706 |
$links['casetrack_work_add_work'] = array(
|
| 707 |
'href' => "casetracker/work/add/$node->nid",
|
| 708 |
'title' => t('Log time'),
|
| 709 |
);
|
| 710 |
}
|
| 711 |
return $links;
|
| 712 |
}
|
| 713 |
|
| 714 |
/**
|
| 715 |
* Implementation of hook_delete().
|
| 716 |
*/
|
| 717 |
function casetracker_work_delete($node) {
|
| 718 |
db_query('DELETE FROM {casetracker_work} WHERE nid=%d', $node->casetracker_work->nid);
|
| 719 |
}
|
| 720 |
|
| 721 |
/*
|
| 722 |
* Time rounding for various uses, especially default form inputs
|
| 723 |
* for user convenience.
|
| 724 |
*
|
| 725 |
*/
|
| 726 |
|
| 727 |
function _casetracker_work_time_round($timestamp, $op, $interval) {
|
| 728 |
|
| 729 |
$time_values = array('z','w','j','H','i','s');
|
| 730 |
$time_string = format_date($timestamp, 'custom', implode(',', $time_values));
|
| 731 |
$t = array_combine( $time_values, explode(',', $time_string) );
|
| 732 |
|
| 733 |
switch ($op) {
|
| 734 |
case 'down':
|
| 735 |
switch ($interval) {
|
| 736 |
case 'hour':
|
| 737 |
return $timestamp - ($t['i']*60) - $t['s'];
|
| 738 |
break;
|
| 739 |
default:
|
| 740 |
return 0;
|
| 741 |
}
|
| 742 |
default:
|
| 743 |
return 0;
|
| 744 |
}
|
| 745 |
}
|
| 746 |
|
| 747 |
/*
|
| 748 |
* Get hour minute second in an array for fine handling.
|
| 749 |
* If there is a $format argument then return the elements
|
| 750 |
* in the desired format.
|
| 751 |
*
|
| 752 |
* If there is a better function for this I'm interested.
|
| 753 |
* Core format_interval() seems too wordy.
|
| 754 |
* Avoid date() and format_date() to avoid timezone shifts.
|
| 755 |
*
|
| 756 |
*/
|
| 757 |
function _casetracker_work_seconds_display($seconds, $format = 'array') {
|
| 758 |
|
| 759 |
$time['day'] = (int)($seconds / CT_WORK_DAY);
|
| 760 |
$seconds = ($seconds % CT_WORK_DAY);
|
| 761 |
$time['hour'] = (int)($seconds / CT_WORK_HOUR);
|
| 762 |
$seconds = ($seconds % CT_WORK_HOUR);
|
| 763 |
$time['minute'] = (int)($seconds / 60);
|
| 764 |
$time['second'] = ($seconds % 60);
|
| 765 |
|
| 766 |
switch ($format) {
|
| 767 |
case 'array':
|
| 768 |
return $time;
|
| 769 |
break;
|
| 770 |
case 'hh:mm':
|
| 771 |
// Nice and clear: format seconds in hh:mm without timezone effects.
|
| 772 |
return ($time['day'] * 24) + $time['hour'] .':'. str_pad($time['minute'], 2, "0", STR_PAD_LEFT);
|
| 773 |
break;
|
| 774 |
}
|
| 775 |
}
|
| 776 |
|
| 777 |
/*
|
| 778 |
* We want to give the user flexibility entering data,
|
| 779 |
* so we expect a narrow range of formats and a wide range of
|
| 780 |
* delimiters.
|
| 781 |
*/
|
| 782 |
function _casetracker_work_string_to_timestamp($time_string, $op, $date_timestamp = NULL) {
|
| 783 |
|
| 784 |
if ($op == 'time' && (!isset($date_timestamp) || !is_numeric($date_timestamp))) {
|
| 785 |
// dpr(ddebug_backtrace()); die();
|
| 786 |
form_set_error ('work', t('API error. Missing the date parameter used for creating a timestamp from hh:mm.'));
|
| 787 |
return 0;
|
| 788 |
}
|
| 789 |
|
| 790 |
$chars = array(':', ',', '.', '-', '/', ' ');
|
| 791 |
$time_string = str_replace($chars, ',', $time_string);
|
| 792 |
$time_string = str_replace(',,', ',', $time_string);
|
| 793 |
|
| 794 |
if ($op == 'duration' && strpos($time_string, ',') === false) {
|
| 795 |
$time_string = ','. $time_string;
|
| 796 |
}
|
| 797 |
|
| 798 |
$t = explode(',', $time_string);
|
| 799 |
|
| 800 |
switch ($op) {
|
| 801 |
case 'date':
|
| 802 |
// Accept only yyyymmdd for now
|
| 803 |
// TODO: user setting for preferred format.
|
| 804 |
if (count($t) != 3 || $t[0] < 2000 || $t[1] > 12 || $t[2] > 31) {
|
| 805 |
form_set_error ('work', t('Please use yyyy/mm/dd format for dates.'));
|
| 806 |
return 0;
|
| 807 |
}
|
| 808 |
else {
|
| 809 |
// TODO: Make this local time, not GMT
|
| 810 |
global $user;
|
| 811 |
return gmmktime (0, 0, 0, $t[1], $t[2], $t[0]) - $user->timezone;
|
| 812 |
}
|
| 813 |
|
| 814 |
case 'duration':
|
| 815 |
// One value is minutes, two values is hour, minutes
|
| 816 |
if ($t[1] > 59 || count($t) > 2) {
|
| 817 |
form_set_error ('work', t('Please enter duration only in hh:mm format, even for multiple days.'));
|
| 818 |
return 0;
|
| 819 |
}
|
| 820 |
else {
|
| 821 |
return ($t[0] * CT_WORK_HOUR) + ($t[1] * 60);
|
| 822 |
}
|
| 823 |
case 'time':
|
| 824 |
// Only accept two values being hour, minutes.
|
| 825 |
if ($t[0] > 23 || $t[1] > 59 || count($t) != 2) {
|
| 826 |
form_set_error ('work', 'Time should be hh:mm in 24hr format only.');
|
| 827 |
return 0;
|
| 828 |
}
|
| 829 |
else {
|
| 830 |
return $date_timestamp + ($t[0] * CT_WORK_HOUR) + ($t[1] * 60);
|
| 831 |
}
|
| 832 |
}
|
| 833 |
|
| 834 |
return $time;
|
| 835 |
}
|
| 836 |
|
| 837 |
// Simple utility for checking a project type. Should be supplied by ct
|
| 838 |
function casetracker_work_project_types($check_type = null) {
|
| 839 |
$types = variable_get('casetracker_project_node_types', 'casetracker_basic_project');
|
| 840 |
foreach ($types as $t => $type) {
|
| 841 |
if (!$type) {
|
| 842 |
unset($types[$t]);
|
| 843 |
}
|
| 844 |
}
|
| 845 |
if ($check_type) {
|
| 846 |
return isset($types[$check_type]);
|
| 847 |
}
|
| 848 |
return $types;
|
| 849 |
}
|
| 850 |
|
| 851 |
function casetracker_work_allow_edit($ctwid = 0) {
|
| 852 |
// if a manager, then allow
|
| 853 |
return user_access('manage work and rates');
|
| 854 |
// if a owner then allow if not locked
|
| 855 |
}
|
| 856 |
|
| 857 |
// ----------------------------------------------------------------------------
|
| 858 |
// Views hooks
|
| 859 |
|
| 860 |
/**
|
| 861 |
* Implementation of hook_views_tables()
|
| 862 |
*/
|
| 863 |
function casetracker_work_views_tables() {
|
| 864 |
$tables['casetracker_work'] = array(
|
| 865 |
'name' => 'casetracker_work',
|
| 866 |
'join' => array(
|
| 867 |
'left' => array(
|
| 868 |
'table' => 'node',
|
| 869 |
'field' => 'nid'
|
| 870 |
),
|
| 871 |
'right' => array(
|
| 872 |
'field' => 'nid'
|
| 873 |
)
|
| 874 |
),
|
| 875 |
'fields' => array(
|
| 876 |
'ctwid' => array(
|
| 877 |
'name' => t('Work: Work ID'),
|
| 878 |
),
|
| 879 |
'uid' => array(
|
| 880 |
'name' => t('Work: User'),
|
| 881 |
'handler' => 'casetracker_work_handler_user_name',
|
| 882 |
'sortable' => true,
|
| 883 |
'help' => t('Display the user of this work entry.'),
|
| 884 |
),
|
| 885 |
'start' => array(
|
| 886 |
'name' => t('Work: Start'),
|
| 887 |
'sortable' => true,
|
| 888 |
'handler' => views_handler_field_dates(),
|
| 889 |
'option' => 'string',
|
| 890 |
'help' => t('Display the work start time.'),
|
| 891 |
),
|
| 892 |
'duration' => array(
|
| 893 |
'name' => t('Work: Duration'),
|
| 894 |
'handler' => 'casetracker_work_handler_duration',
|
| 895 |
'help' => t('Display the work duration.'),
|
| 896 |
),
|
| 897 |
'rate' => array(
|
| 898 |
'name' => t('Work: Rate'),
|
| 899 |
'sortable' => true,
|
| 900 |
),
|
| 901 |
'activity' => array(
|
| 902 |
'name' => t('Work: Activity'),
|
| 903 |
),
|
| 904 |
'edit' => array(
|
| 905 |
'name' => t('Work: Edit link'),
|
| 906 |
'handler' => 'casetracker_work_handler_edit_link',
|
| 907 |
'notafield' => TRUE,
|
| 908 |
'addlfields' => array('ctwid'),
|
| 909 |
'help' => t('Display a link to edit work entry.'),
|
| 910 |
),
|
| 911 |
),
|
| 912 |
'sorts' => array(
|
| 913 |
'sku' => array(
|
| 914 |
'name' => t('Product: SKU'),
|
| 915 |
),
|
| 916 |
'price' => array(
|
| 917 |
'name' => t('Product: Price'),
|
| 918 |
)
|
| 919 |
),
|
| 920 |
'filters' => array(
|
| 921 |
'has_work' => array(
|
| 922 |
'name' => 'Work: Has work',
|
| 923 |
'operator' => array('=' => 'Equals'),
|
| 924 |
'list' => 'views_handler_operator_yesno',
|
| 925 |
'list-type' => 'select',
|
| 926 |
'handler' => 'casetracker_work_handler_filter_has_work',
|
| 927 |
),
|
| 928 |
'uid' => array(
|
| 929 |
'help' => t('Filter by user.'),
|
| 930 |
'list' => 'casetracker_work_handler_user_options',
|
| 931 |
'name' => t('Work: User'),
|
| 932 |
'operator' => views_handler_operator_andor(),
|
| 933 |
'value-type' => 'array',
|
| 934 |
),
|
| 935 |
'assign_to_currentuid' => array(
|
| 936 |
'list' => 'views_handler_filter_usercurrent',
|
| 937 |
'list-type' => 'select',
|
| 938 |
'name' => t('Work: Current user'),
|
| 939 |
'field' => 'uid',
|
| 940 |
'operator' => 'views_handler_operator_eqneq',
|
| 941 |
'help' => t('Filter work by the current user.'),
|
| 942 |
),
|
| 943 |
),
|
| 944 |
);
|
| 945 |
return $tables;
|
| 946 |
}
|
| 947 |
|
| 948 |
/**
|
| 949 |
* display a link to edit a work entry with a destination return
|
| 950 |
*/
|
| 951 |
function casetracker_work_handler_edit_link($fieldinfo, $fielddata, $value, $data) {
|
| 952 |
// try to build a fake node object
|
| 953 |
if (casetracker_work_allow_edit()) {
|
| 954 |
$link_text = t('Edit');
|
| 955 |
return l($link_text, "casetracker/work/edit/{$data->casetracker_work_ctwid}", NULL, drupal_get_destination());
|
| 956 |
}
|
| 957 |
}
|
| 958 |
|
| 959 |
/**
|
| 960 |
* Show the work entry user
|
| 961 |
*/
|
| 962 |
function casetracker_work_handler_user_name($fieldinfo, $fielddata, $value, $data) {
|
| 963 |
return l(casetracker_get_name($data->casetracker_work_uid), "user/{$data->casetracker_work_uid}");
|
| 964 |
}
|
| 965 |
|
| 966 |
/**
|
| 967 |
* Format duration.
|
| 968 |
*/
|
| 969 |
function casetracker_work_handler_duration($fieldinfo, $fielddata, $value, $data) {
|
| 970 |
return _casetracker_work_seconds_display($data->casetracker_work_duration, 'hh:mm');
|
| 971 |
}
|
| 972 |
|
| 973 |
function casetracker_work_handler_user_options() {
|
| 974 |
$results = db_query('SELECT u.uid, u.name FROM {users} AS u INNER JOIN {casetracker_work} AS ctw ON u.uid = ctw.uid WHERE u.uid > 0 ORDER BY u.name');
|
| 975 |
while ($result = db_fetch_object($results)) {
|
| 976 |
$options[$result->uid] = check_plain($result->name);
|
| 977 |
}
|
| 978 |
return $options;
|
| 979 |
}
|
| 980 |
|
| 981 |
|
| 982 |
/**
|
| 983 |
* Filter Nodes based on being a product.
|
| 984 |
*/
|
| 985 |
function casetracker_work_handler_filter_has_work($op, $filter, $filterinfo, &$query) {
|
| 986 |
switch ($op) {
|
| 987 |
case 'handler':
|
| 988 |
$query->ensure_table('casetracker_work');
|
| 989 |
switch ($filter['value'][0]) {
|
| 990 |
case '0':
|
| 991 |
$query->add_where('casetracker_work.ctwid IS NULL');
|
| 992 |
break;
|
| 993 |
|
| 994 |
case '1':
|
| 995 |
$query->add_where('casetracker_work.ctwid IS NOT NULL');
|
| 996 |
break;
|
| 997 |
}
|
| 998 |
break;
|
| 999 |
}
|
| 1000 |
}
|
| 1001 |
|
| 1002 |
|
| 1003 |
/*
|
| 1004 |
* Timesheet display, just a simple search results. This will suffice for a
|
| 1005 |
* short time.
|
| 1006 |
*
|
| 1007 |
* Maybe will be a good idea to separate function to return a range of data,
|
| 1008 |
* so that this can be called from anywhere (eg. case summary).
|
| 1009 |
*
|
| 1010 |
* I don't know whether views can be used to display this info.
|
| 1011 |
*
|
| 1012 |
* Not showing project data here, because casetracker_work lets you assign
|
| 1013 |
* work to multiple node types, so project data might not be appropriate.
|
| 1014 |
*
|
| 1015 |
function casetracker_work_report_temp() {
|
| 1016 |
|
| 1017 |
global $user;
|
| 1018 |
|
| 1019 |
if (!user_access('manage work and rates')) {
|
| 1020 |
$uid = $user->uid;
|
| 1021 |
} elseif (!($uid = arg(2))) {
|
| 1022 |
$uid = $user->uid;
|
| 1023 |
}
|
| 1024 |
|
| 1025 |
$header = array(t('ID'), t('Date'), t('Start'), t('Finish'), t('Time'), t('Rate'), t('Activity'), t('Node'));
|
| 1026 |
|
| 1027 |
$result = db_query(
|
| 1028 |
'SELECT cw.*, n.type, u.name
|
| 1029 |
FROM casetracker_work AS cw
|
| 1030 |
INNER JOIN node AS n
|
| 1031 |
ON cw.nid = n.nid
|
| 1032 |
INNER JOIN users AS u
|
| 1033 |
ON cw.uid = u.uid
|
| 1034 |
WHERE cw.uid = %d
|
| 1035 |
ORDER BY cw.start',
|
| 1036 |
$uid);
|
| 1037 |
|
| 1038 |
while ($work = db_fetch_object($result)) {
|
| 1039 |
|
| 1040 |
$time = _casetracker_work_seconds_display($work->duration, 'hh:mm');
|
| 1041 |
$type_name = node_get_name($work->type);
|
| 1042 |
$start = ($work->finish == 0) ? '' : format_date($work->start, 'custom', 'H:i');
|
| 1043 |
$finish = ($work->finish == 0) ? '' : format_date($work->finish, 'custom', 'H:i');
|
| 1044 |
$name = $work->name;
|
| 1045 |
|
| 1046 |
$rows[] =
|
| 1047 |
array(
|
| 1048 |
l($work->ctwid, 'casetracker/work/edit/'. $work->ctwid),
|
| 1049 |
format_date($work->start, 'custom', 'Y M d'),
|
| 1050 |
$start,
|
| 1051 |
$finish,
|
| 1052 |
$time,
|
| 1053 |
$work->rate,
|
| 1054 |
$work->activity,
|
| 1055 |
l($work->nid, 'node/'. $work->nid),
|
| 1056 |
);
|
| 1057 |
|
| 1058 |
$total_time += $work->duration;
|
| 1059 |
}
|
| 1060 |
|
| 1061 |
drupal_set_title('Timesheet for '. $name);
|
| 1062 |
|
| 1063 |
$output .= theme('table', $header, $rows, array('class' => 'casetracker_timesheet'));
|
| 1064 |
$time = _casetracker_work_seconds_display($total_time, 'hh:mm');
|
| 1065 |
|
| 1066 |
$output .= '<p><b>Total time</b>: '. $time .'</p>';
|
| 1067 |
// $output .= '<p>'. l('More work', 'node/add/casetracker_work') .'</p>';
|
| 1068 |
|
| 1069 |
return $output;
|
| 1070 |
|
| 1071 |
}
|
| 1072 |
*/
|