private static function save_job_tasks($job_id, $data) { $result = array('status' => false); $check_completed = false; $job_data = false; $job_task_creation_permissions = self::get_job_task_creation_permissions(); // check for new tasks or changed tasks. $tasks = self::get_tasks($job_id); if (isset($data['job_task']) && is_array($data['job_task'])) { foreach ($data['job_task'] as $task_id => $task_data) { if (isset($task_data['manual_percent']) && strlen($task_data['manual_percent']) == 0) { unset($task_data['manual_percent']); } $original_task_id = $task_id; $task_id = (int) $task_id; if (!is_array($task_data)) { continue; } if ($task_id > 0 && !isset($tasks[$task_id])) { $task_id = 0; // creating a new task on this job. } if (!isset($task_data['description']) || $task_data['description'] == '' || $task_data['description'] == _TASK_DELETE_KEY) { if ($task_id > 0 && $task_data['description'] == _TASK_DELETE_KEY) { // remove task. // but onyl remove it if it hasn't been invoiced. if (isset($tasks[$task_id]) && $tasks[$task_id]['invoiced']) { // it has been invoiced! dont remove it. set_error('Unable to remove an invoiced task'); $result['status'] = 'error'; break; // break out of loop saving tasks. } else { $sql = "DELETE FROM `" . _DB_PREFIX . "task` WHERE task_id = '{$task_id}' AND job_id = {$job_id} LIMIT 1"; query($sql); $sql = "DELETE FROM `" . _DB_PREFIX . "task_log` WHERE task_id = '{$task_id}'"; query($sql); $result['status'] = 'deleted'; $result['task_id'] = $task_id; } } continue; } // add / save this task. $task_data['job_id'] = $job_id; if (module_job::job_task_only_show_split_hours($job_id, $job_data, $task_id, $task_data)) { if (isset($task_data['hours']) && !isset($task_data['staff_hours'])) { $task_data['staff_hours'] = $task_data['hours']; $task_data['staff_amount'] = $task_data['amount']; } if (isset($task_data['hours'])) { unset($task_data['hours']); unset($task_data['amount']); } } if (isset($task_data['hours'])) { $task_data['hours'] = function_exists('decimal_time_in') ? decimal_time_in($task_data['hours']) : $task_data['hours']; } if (isset($task_data['staff_hours'])) { $task_data['staff_hours'] = function_exists('decimal_time_in') ? decimal_time_in($task_data['staff_hours']) : $task_data['staff_hours']; } if (isset($task_data['log_hours'])) { $task_data['log_hours'] = function_exists('decimal_time_in') ? decimal_time_in($task_data['log_hours']) : $task_data['log_hours']; } // remove the amount of it equals the hourly rate. if (isset($task_data['amount']) && $task_data['amount'] != 0 && isset($task_data['hours']) && $task_data['hours'] > 0) { if (isset($data['hourly_rate']) && $task_data['amount'] - $task_data['hours'] * $data['hourly_rate'] == 0) { unset($task_data['amount']); } } if (isset($task_data['staff_amount']) && $task_data['staff_amount'] != 0 && isset($task_data['staff_hours']) && $task_data['staff_hours'] > 0) { if (isset($data['staff_hourly_rate']) && $task_data['staff_amount'] - $task_data['staff_hours'] * $data['staff_hourly_rate'] == 0) { unset($task_data['staff_amount']); } } // check if we haven't unticked a non-hourly task if (isset($task_data['fully_completed_t']) && $task_data['fully_completed_t']) { if (!isset($task_data['fully_completed']) || !$task_data['fully_completed']) { // we have unchecked that tickbox $task_data['fully_completed'] = 0; } else { if (isset($tasks[$task_id]) && !$tasks[$task_id]['fully_completed']) { // we completed a preveiously incomplete task. // chekc if this task has a custom percentage filled in, we remove this custom percentage. if (isset($task_data['manual_percent']) && $task_data['manual_percent'] >= 0) { $task_data['manual_percent'] = -1; } // hack: if we haven't logged any hours for this, we log the number of hours. // if we have logged some hours already then we don't log anything extra. // this is so they can log 0.5hours for a 1 hour completed task etc.. if (isset($task_data['hours']) && $task_data['hours'] > 0 && (!isset($task_data['log_hours']) || !$task_data['log_hours'])) { $logged_hours = 0; foreach (get_multiple('task_log', array('job_id' => $job_id, 'task_id' => $task_id)) as $task_log) { $logged_hours += $task_log['hours']; } if ($logged_hours == 0) { $task_data['log_hours'] = $task_data['hours']; } } } } $check_completed = true; } // check if we haven't unticked a billable task if (isset($task_data['billable_t']) && $task_data['billable_t'] && !isset($task_data['billable'])) { $task_data['billable'] = 0; } // set default taxable status if (!$task_id && !isset($task_data['taxable_t'])) { // we're creating a new task. $task_data['taxable'] = module_config::c('task_taxable_default', 1); } if (isset($task_data['taxable_t']) && $task_data['taxable_t'] && !isset($task_data['taxable'])) { $task_data['taxable'] = 0; } if (isset($task_data['completed']) && $task_data['completed'] > 0) { // check the completed date of all our tasks. $check_completed = true; } if (!$task_id && isset($task_data['new_fully_completed']) && $task_data['new_fully_completed']) { $task_data['fully_completed'] = 1; // is this bad for set amount tasks? if (!isset($task_data['date_done']) || !$task_data['date_done']) { $task_data['date_done'] = print_date(time()); } if (isset($task_data['hours'])) { $task_data['log_hours'] = $task_data['hours']; } $check_completed = true; } // todo: move the task creation code into a public method so that the public user can add tasks to their jobs. if (!$task_id && module_security::is_logged_in() && !module_job::can_i('create', 'Job Tasks')) { continue; // dont allow new tasks. } // check if the user is allowed to create new tasks. // check the approval status of jobs switch ($job_task_creation_permissions) { case _JOB_TASK_CREATION_NOT_ALLOWED: if (!$task_id) { continue; // dont allow new tasks. } break; case _JOB_TASK_CREATION_REQUIRES_APPROVAL: $task_data['approval_required'] = 1; break; case _JOB_TASK_CREATION_WITHOUT_APPROVAL: // no action required . break; } if (isset($tasks[$task_id]) && $tasks[$task_id]['approval_required'] == 2) { // task has been rejected, saving it again for approval. $task_data['approval_required'] = 1; } $task_id = update_insert('task_id', $task_id, 'task', $task_data); // todo - fix cross task job boundary issue. meh. $result['task_id'] = $task_id; if ($task_id != $original_task_id) { $result['status'] = 'created'; } else { $result['status'] = 'edited'; } if ($task_id && isset($task_data['log_hours']) && (double) $task_data['log_hours'] > 0) { // we are increasing the task complete hours by the amount specified in log hours. // log a new task record, and incrase the "completed" column. //$original_task_data = $tasks[$task_id]; //$task_data['completed'] = $task_data['completed'] + $task_data['log_hours']; // only log hours if it's an hourly task. if (!isset($task_data['manual_task_type']) || $task_data['manual_task_type'] < 0) { if (!$job_data) { $job_data = self::get_job($job_id); } $task_data['manual_task_type'] = $job_data['default_task_type']; } if ($task_data['manual_task_type'] == _TASK_TYPE_HOURS_AMOUNT) { update_insert('task_log_id', 'new', 'task_log', array('task_id' => $task_id, 'job_id' => $job_id, 'hours' => (double) $task_data['log_hours'], 'log_time' => time())); $result['log_hours'] = $task_data['log_hours']; } } } } if ($check_completed) { self::update_job_completion_status($job_id); } module_cache::clear('job'); return $result; }