/** * Show a object properties * * Parameters: * * - object - Object of which properties are shown * - show_completed_status - To display object completed status * - show_milestone - To display object milestone * - show_tags - To display object tags * - show_body - To display object description * - show_category - To display object category * - show_file_details - To display file details, if object is file * - show_name - To display object name * - show_priority - To display object priority * - show_milestone_day_info - To display milestone due on info * - show_assignees - To show assignees * - only_show_body - To display only body * * @param array $params * @param Smarty $smarty * @return string */ function smarty_function_mobile_access_object_properties($params, &$smarty) { $object = array_var($params, 'object'); if (!instance_of($object, 'ProjectObject')) { return new InvalidParamError('object', $object, '$object is expected to be an instance of ProjectObject class', true); } // if $smarty->assign(array('_mobile_access_object_properties_object' => $object, '_mobile_access_object_properties_show_completed_status' => (bool) array_var($params, 'show_completed_status', false), '_mobile_access_object_properties_show_milestone' => (bool) array_var($params, 'show_milestone', false), '_mobile_access_object_properties_show_tags' => (bool) array_var($params, 'show_tags', false), '_mobile_access_object_properties_show_body' => (bool) array_var($params, 'show_body', false), '_mobile_access_object_properties_show_category' => (bool) array_var($params, 'show_category', false), '_mobile_access_object_properties_show_file_details' => (bool) array_var($params, 'show_file_details', false), '_mobile_access_object_properties_show_name' => (bool) array_var($params, 'show_name', false), '_mobile_access_object_properties_show_assignees' => (bool) array_var($params, 'show_assignees', false), '_mobile_access_object_properties_show_priority' => (bool) array_var($params, 'show_priority', false), '_mobile_access_object_properties_show_milestone_day_info' => (bool) array_var($params, 'show_milestone_day_info', false), '_mobile_access_object_properties_show_total_time' => (bool) array_var($params, 'show_total_time', false), '_mobile_access_object_properties_only_show_body' => (bool) array_var($params, 'only_show_body', false))); if (module_loaded(TIMETRACKING_MODULE)) { $smarty->assign(array('_mobile_access_object_properties_total_time' => float_format(TimeRecords::sumObjectTime($object), 2))); } return $smarty->fetch(get_template_path('_object_properties', null, MOBILE_ACCESS_MODULE)); }
/** * Render object time widget * * @param array $params * @param Smarty $smarty * @return string */ function smarty_function_object_time($params, &$smarty) { if (!module_loaded('timetracking')) { return ''; } // if $object = array_var($params, 'object'); if (!instance_of($object, 'ProjectObject')) { return new InvalidParamError('$object', $object, '$object is expected to be a valid instance of ProjectObject class'); } // if $show_time = ''; $additional_class = ''; if (array_var($params, 'show_time', true)) { $object_time = TimeRecords::sumObjectTime($object); if ($object->can_have_tasks) { $tasks_time = TimeRecords::sumTasksTime($object); } else { $tasks_time = 0; } // if $additional_class = 'with_text'; $total_time = $object_time + $tasks_time; if ($object_time == 0 && $tasks_time == 0) { $show_time = '<span class="time_widget_text">' . lang('No time tracked') . '</span> '; } elseif ($tasks_time == 0) { $show_time = '<span class="time_widget_text">' . lang(':total hours logged', array('total' => float_format($total_time, 2))) . '</span> '; } else { $show_time = '<span class="time_widget_text">' . lang(':total hours logged - :object_time for the ticket and :tasks_time for tasks', array('type' => $object->getVerboseType(true), 'total' => float_format($total_time, 2), 'object_time' => float_format($object_time, 2), 'tasks_time' => float_format($tasks_time, 2))) . '</span> '; } // if } // if $wrapper_id = 'object_time_widget_' . $object->getId(); $image_url = $object->getHasTime() ? get_image_url('clock-small.gif') : get_image_url('gray-clock-small.gif'); return '<span id="' . $wrapper_id . '" class="time_popup_widget ' . $additional_class . '">' . $show_time . '<a href="' . $object->getTimeUrl() . '" title="' . lang('Time') . '"><img src="' . $image_url . '" alt="" /></a></span><script type="text/javascript">App.TimePopup.init("' . $wrapper_id . '")</script>'; }
/** * Return related time records * * @param void * @param integer $visibility * @return array */ function getTimeRecords($visibility = VISIBILITY_NORMAL) { $ids = $this->getTimeRecordIds(); return is_foreachable($ids) ? TimeRecords::findByIds($ids, STATE_VISIBLE, $visibility) : null; }
/** * Execute report * * @param User $user * @param TimeReport $report * @param Project $project * @return array */ function executeReport($user, $report, $project = null) { $conditions = $report->prepareConditions($user, $project); if (empty($conditions)) { return null; } // if if ($report->getSumByUser()) { $rows = db_execute_all('SELECT SUM(float_field_1) AS total_time, integer_field_1 AS user_id FROM ' . TABLE_PREFIX . 'project_objects WHERE ' . $conditions . ' GROUP BY integer_field_1'); if (is_foreachable($rows)) { $result = array(); foreach ($rows as $row) { $user = Users::findById($row['user_id']); if (instance_of($user, 'User')) { $result[] = array('user' => $user, 'total_time' => float_format($row['total_time'], 2)); } // if } // foreach return $result; } else { return null; } // if } else { return TimeRecords::findBySQL('SELECT * FROM ' . TABLE_PREFIX . 'project_objects WHERE ' . $conditions . ' ORDER BY date_field_1'); } // if }
/** * Create a new invoice * * @param void * @return null */ function add() { $this->wireframe->print_button = false; if (!Invoice::canAdd($this->logged_user)) { $this->httpError(HTTP_ERR_FORBIDDEN); } // if $default_currency = Currencies::findDefault(); if (!instance_of($default_currency, 'Currency')) { $this->httpError(HTTP_ERR_NOT_FOUND, 'Default currency not set'); } // if $time_report = null; $project = null; $timerecord_ids = null; $invoice_data = $this->request->post('invoice'); if (!is_array($invoice_data)) { $duplicate_invoice_id = $this->request->getId('duplicate_invoice_id'); $time_report_id = $this->request->getId('time_report_id'); $ticket_id = $this->request->getId('ticket_id'); // --------------------------------------------------- // Duplicate existing invoice // --------------------------------------------------- if ($duplicate_invoice_id) { $duplicate_invoice = Invoices::findById($duplicate_invoice_id); if (instance_of($duplicate_invoice, 'Invoice')) { $invoice_data = array('company_id' => $duplicate_invoice->getCompanyId(), 'company_address' => $duplicate_invoice->getCompanyAddress(), 'comment' => $duplicate_invoice->getComment(), 'status' => INVOICE_STATUS_DRAFT, 'project_id' => $duplicate_invoice->getProjectId(), 'note' => $duplicate_invoice->getNote(), 'currency_id' => $duplicate_invoice->getCurrencyId()); if (is_foreachable($duplicate_invoice->getItems())) { $invoice_data['items'] = array(); foreach ($duplicate_invoice->getItems() as $item) { $invoice_data['items'][] = array('description' => $item->getDescription(), 'unit_cost' => $item->getUnitCost(), 'quantity' => $item->getQuantity(), 'tax_rate_id' => $item->getTaxRateId(), 'total' => $item->getTotal(), 'subtotal' => $item->getSubtotal()); } // foreach } // if } // if // --------------------------------------------------- // Create invoice from time report // --------------------------------------------------- } else { if ($time_report_id) { $time_report = TimeReports::findById($time_report_id); if (instance_of($time_report, 'TimeReport')) { $project_id = $this->request->getId('project_id'); $client_company_id = null; if ($project_id) { $project = Projects::findById($project_id); } // if $time_report->setBillableFilter(BILLABLE_FILTER_BILLABLE); $conditions = $time_report->prepareConditions($this->logged_user, $project); if ($conditions === false) { $this->httpError(HTTP_ERR_OPERATION_FAILED, 'Failed to prepare time report conditions'); } // if $timerecord_ids = array(); $total_time = 0; $project_objects_table = TABLE_PREFIX . 'project_objects'; $invoice_time_records_table = TABLE_PREFIX . 'invoice_time_records'; $rows = db_execute_all("SELECT DISTINCT id,float_field_1 FROM {$project_objects_table} WHERE {$conditions}"); if (is_foreachable($rows)) { // find time records ids that needs to be attached to this invoice due to time record foreach ($rows as $row) { $timerecord_ids[] = (int) $row['id']; } // foreach $timerecords_filtered = Invoices::filterAvailableTimerecords($timerecord_ids); // calculate total time, but only if time record is not yet attached to the existing invoice if (is_foreachable($rows) && is_foreachable($timerecord_ids)) { foreach ($rows as $row) { if (!in_array($row['id'], $timerecord_ids)) { $total_time += (double) $row['float_field_1']; } // if } // foreach } // if } // if if ($total_time == 0) { $this->wireframe->addPageMessage(lang('You don\'t have any billable time records in this time report, or all bilable time records are already attached to existing invoice'), PAGE_MESSAGE_INFO); } else { if ($timerecords_filtered) { $this->wireframe->addPageMessage(lang('One or more billable timerecords in this time report are already attached to the existing invoice. They won\'t be counted in this one'), PAGE_MESSAGE_INFO); } } // if if (count($timerecord_ids) && $total_time) { if (instance_of($project, 'Project')) { $description = lang('Total of :total hours in :project project', array('total' => $total_time, 'project' => $project->getName())); } else { $description = lang('Total of :total hours', array('total' => $total_time)); } // if $invoice_data = array('due_on' => new DateValue(), 'currency_id' => $default_currency->getId(), 'project_id' => instance_of($project, 'Project') ? $project->getId() : null, 'company_id' => instance_of($project, 'Project') ? $project->getCompanyId() : null, 'items' => array(array('description' => $description, 'unit_cost' => $default_currency->getDefaultRate(), 'quantity' => $total_time, 'subtotal' => $default_currency->getDefaultRate() * $total_time, 'total' => $default_currency->getDefaultRate() * $total_time, 'tax_rate_id' => null, 'time_record_ids' => $timerecord_ids))); } // if } // if // --------------------------------------------------- // Create invoice from ticket // --------------------------------------------------- } else { if ($ticket_id) { $ticket = Tickets::findById($ticket_id); if (instance_of($ticket, 'Ticket')) { $timerecords_filtered = false; $items = array(); if ($ticket->getHasTime()) { $timerecords = TimeRecords::findByParent($ticket, array(BILLABLE_STATUS_BILLABLE), STATE_VISIBLE, $this->logged_user->getVisibility()); $timerecord_ids = array(); $ticket_total_time = 0; if (is_foreachable($timerecords)) { foreach ($timerecords as $timerecord) { if ($timerecord->getValue() > 0) { $timerecord_ids[] = $timerecord->getId(); } // if } // foreach $timerecords_filtered = Invoices::filterAvailableTimerecords($timerecord_ids); foreach ($timerecords as $timerecord) { if (in_array($timerecord->getId(), $timerecord_ids)) { $ticket_total_time += $timerecord->getValue(); } // if } // foreach $items[] = array('description' => lang('Ticket: :ticket_name', array('ticket_name' => $ticket->getName())), 'unit_cost' => $default_currency->getDefaultRate(), 'quantity' => $ticket_total_time, 'subtotal' => $default_currency->getDefaultRate() * $ticket_total_time, 'total' => $default_currency->getDefaultRate() * $ticket_total_time, 'tax_rate_id' => null, 'time_record_ids' => $timerecord_ids); } // if } // if $tasks = $ticket->getTasks(); if (is_foreachable($tasks)) { foreach ($tasks as $task) { if ($task->getHasTime()) { $timerecords = TimeRecords::findByParent($task, array(BILLABLE_STATUS_BILLABLE), STATE_VISIBLE, $this->logged_user->getVisibility()); $task_total_time = 0; $timerecord_ids = array(); if (is_foreachable($timerecords)) { foreach ($timerecords as $timerecord) { if ($timerecord->getValue() > 0) { $timerecord_ids[] = $timerecord->getId(); } // if } // foreach $timerecords_filtered = $timerecords_filtered || Invoices::filterAvailableTimerecords($timerecord_ids); foreach ($timerecords as $timerecord) { if (in_array($timerecord->getId(), $timerecord_ids)) { $task_total_time += $timerecord->getValue(); } // if } // foreach if (is_foreachable($timerecord_ids) && $task_total_time > 0) { $items[] = array('description' => lang('Task: :task_name', array('task_name' => $task->getName())), 'unit_cost' => $default_currency->getDefaultRate(), 'quantity' => $task_total_time, 'subtotal' => $default_currency->getDefaultRate() * $task_total_time, 'total' => $default_currency->getDefaultRate() * $task_total_time, 'tax_rate_id' => null, 'time_record_ids' => $timerecord_ids); } // if } // if } // if } // foreach } // if $project = $ticket->getProject(); $invoice_data = array('due_on' => new DateValue(), 'currency_id' => $default_currency->getId(), 'project_id' => $ticket->getProjectId(), 'company_id' => instance_of($project, 'Project') ? $project->getCompanyId() : null, 'time_record_ids' => $timerecord_ids, 'items' => $items); if ($timerecords_filtered) { $this->wireframe->addPageMessage(lang('One or more billable timerecords in this time report are already attached to the existing invoice. They won\'t be counted in this one'), PAGE_MESSAGE_INFO); } // if } // if } } } // if // --------------------------------------------------- // Start blank // --------------------------------------------------- if (!is_array($invoice_data)) { $invoice_data = array('due_on' => new DateValue(), 'currency_id' => $default_currency->getId(), 'project_id' => instance_of($project, 'Project') ? $project->getId() : null, 'time_record_ids' => null); } // if } // if $invoice_notes = InvoiceNoteTemplates::findAll(); $invoice_item_templates = InvoiceItemTemplates::findAll(); $this->smarty->assign(array('invoice_data' => $invoice_data, 'tax_rates' => TaxRates::findAll(), 'invoice_notes' => $invoice_notes, 'invoice_item_templates' => $invoice_item_templates, 'original_note' => $this->active_invoice->getNote())); $cleaned_notes = array(); if (is_foreachable($invoice_notes)) { foreach ($invoice_notes as $invoice_note) { $cleaned_notes[$invoice_note->getId()] = $invoice_note->getContent(); } // foreach } // if js_assign('invoice_notes', $cleaned_notes); js_assign('original_note', $this->active_invoice->getNote()); $cleaned_item_templates = array(); if (is_foreachable($invoice_item_templates)) { foreach ($invoice_item_templates as $invoice_item_template) { $cleaned_item_templates[$invoice_item_template->getId()] = array('description' => $invoice_item_template->getDescription(), 'unit_cost' => $invoice_item_template->getUnitCost(), 'quantity' => $invoice_item_template->getQuantity(), 'tax_rate_id' => $invoice_item_template->getTaxRateId()); } // foreach } // if js_assign('invoice_item_templates', $cleaned_item_templates); js_assign('company_details_url', assemble_url('invoice_company_details')); js_assign('move_icon_url', get_image_url('move.gif')); if ($this->request->isSubmitted()) { db_begin_work(); $this->active_invoice->setAttributes($invoice_data); $this->active_invoice->setCreatedBy($this->logged_user); $invoice_company = Companies::findById(array_var($invoice_data, 'company_id', null)); $this->active_invoice->setCompanyName($invoice_company->getName()); $save = $this->active_invoice->save(); if ($save && !is_error($save)) { $counter = 0; if (is_foreachable($invoice_data['items'])) { foreach ($invoice_data['items'] as $invoice_item_data) { $invoice_item = new InvoiceItem(); $invoice_item->setAttributes($invoice_item_data); $invoice_item->setInvoiceId($this->active_invoice->getId()); $invoice_item->setPosition($counter + 1); $item_save = $invoice_item->save(); if ($item_save && !is_error($item_save)) { $invoice_item->setTimeRecordIds(array_var($invoice_item_data, 'time_record_ids')); $counter++; } else { // error in invoice_item_data } // if } // foreach } // if if ($counter > 0) { db_commit(); flash_success('Invoice ":number" has been created', array('number' => $this->active_invoice->getName())); $this->redirectToUrl($this->active_invoice->getViewUrl()); } else { db_rollback(); $this->smarty->assign('errors', new ValidationErrors(array('items' => lang('Invoice items data is not valid. All descriptions are required and there need to be at least one unit with cost set per item!')))); } // if } else { db_rollback(); $this->smarty->assign('errors', $save); } // if } // if }
/** * Exports time records * * @param void * @return null */ function export() { $object_visibility = array_var($_GET, 'visibility', VISIBILITY_NORMAL); $exportable_modules = explode(',', array_var($_GET, 'modules', null)); if (!is_foreachable($exportable_modules)) { $exportable_modules = null; } // if require_once PROJECT_EXPORTER_MODULE_PATH . '/models/ProjectExporterOutputBuilder.class.php'; $output_builder = new ProjectExporterOutputBuilder($this->active_project, $this->smarty, $this->active_module, $exportable_modules); if (!$output_builder->createOutputFolder()) { $this->serveData($output_builder->execution_log, 'execution_log', null, FORMAT_JSON); } // if $output_builder->createAttachmentsFolder(); $timerecords = TimeRecords::findByProject($this->active_project, STATE_VISIBLE, $object_visibility); $distinct_months = array(); foreach ($timerecords as $timerecord) { $date = $timerecord->getRecordDate(); $exists = false; for ($x = 0; $x < count($distinct_months); $x++) { if ($distinct_months[$x]['month'] == $date->getMonth() && $distinct_months[$x]['year'] == $date->getYear()) { $exists = true; } // if } // for if (!$exists) { $distinct_months[] = array("year" => $date->getYear(), "month" => $date->getMonth(), "month_string" => $date->date_data['month'], "beginning_of_month" => DateTimeValue::beginningOfMonth($date->getMonth(), $date->getYear()), "end_of_month" => DateTimeValue::endOfMonth($date->getMonth(), $date->getYear())); } // if } // foreach $people = ProjectUsers::findUsersByProject($this->active_project); $companies = Companies::findByProject($this->active_project); $total_times = array(); foreach ($people as $person) { $person->temp_total_time = TimeRecords::getTotalUserTimeOnProject($this->active_project, $person); } // foreach $output_builder->setFileTemplate($this->active_module, $this->controller_name, 'index'); $output_builder->smarty->assign(array("distinct_months" => $distinct_months, "people" => $people, "companies" => $companies, "total_times" => $total_times, "timerecords" => $timerecords)); $output_builder->outputToFile('index'); // export monthly report if (is_foreachable($distinct_months)) { $output_builder->setFileTemplate($this->active_module, $this->controller_name, 'monthly'); foreach ($distinct_months as $distinct_month) { $output_builder->smarty->assign(array('current_month' => $distinct_month, 'start_date' => DateTimeValue::beginningOfMonth($distinct_month[month], $distinct_month['year']), 'end_date' => DateTimeValue::endOfMonth($distinct_month['month'], $distinct_month['year']))); $output_builder->outputToFile('monthly_' . $distinct_month['month'] . '_' . $distinct_month['year']); } // foreach } // if // export report for persons if (is_foreachable($people)) { $output_builder->setFileTemplate($this->active_module, $this->controller_name, 'person'); foreach ($people as $person) { $output_builder->smarty->assign(array('current_person' => $person)); $output_builder->outputToFile('user_' . $person->getId()); } // foreach } // if $this->serveData($output_builder->execution_log, 'execution_log', null, FORMAT_JSON); }
/** * Utility method that will update parents has_time flag * * @param void * @return boolean */ function refreshParentHasTime() { $parent = $this->getParent(); if (instance_of($parent, 'ProjectObject')) { $parent->setHasTime((bool) TimeRecords::sumObjectTime($parent)); return $parent->save(); } // if return true; }
/** * Export tickets * * @param void * @return null */ function export() { $object_visibility = array_var($_GET, 'visibility', VISIBILITY_NORMAL); $exportable_modules = explode(',', array_var($_GET, 'modules', null)); if (!is_foreachable($exportable_modules)) { $exportable_modules = null; } // if require_once PROJECT_EXPORTER_MODULE_PATH . '/models/ProjectExporterOutputBuilder.class.php'; $output_builder = new ProjectExporterOutputBuilder($this->active_project, $this->smarty, $this->active_module, $exportable_modules); if (!$output_builder->createOutputFolder()) { $this->serveData($output_builder->execution_log, 'execution_log', null, FORMAT_JSON); } // if $output_builder->createAttachmentsFolder(); $module_categories = Categories::findByModuleSection($this->active_project, $this->active_module, $this->active_module); $module_objects = Tickets::findByProject($this->active_project, null, STATE_VISIBLE, $object_visibility); $output_builder->setFileTemplate($this->active_module, $this->controller_name, 'index'); $output_builder->smarty->assign('categories', $module_categories); $output_builder->smarty->assign('objects', $module_objects); $output_builder->outputToFile('index'); // export tickets by categories if (is_foreachable($module_categories)) { foreach ($module_categories as $module_category) { if (instance_of($module_category, 'Category')) { $output_builder->smarty->assign(array('current_category' => $module_category, 'objects' => Tickets::findByProject($this->active_project, $module_category, STATE_VISIBLE, $object_visibility))); $output_builder->outputToFile('category_' . $module_category->getId()); } // if } // foreach } // if // export tickets if (is_foreachable($module_objects)) { $output_builder->setFileTemplate($this->active_module, $this->controller_name, 'object'); foreach ($module_objects as $module_object) { if (instance_of($module_object, 'Ticket')) { $output_builder->outputAttachments($module_object->getAttachments()); $comments = $module_object->getComments($object_visibility); $output_builder->outputObjectsAttachments($comments); if (module_loaded('timetracking')) { $timerecords = TimeRecords::findByParent($module_object, null, STATE_VISIBLE, $object_visibility); $total_time = TimeRecords::calculateTime($timerecords); } else { $timerecords = null; $total_time = 0; } // if $output_builder->smarty->assign(array('timerecords' => $timerecords, 'total_time' => $total_time, 'object' => $module_object, 'comments' => $comments)); $output_builder->outputToFile('ticket_' . $module_object->getId()); } // if } // foreach } // if $this->serveData($output_builder->execution_log, 'execution_log', null, FORMAT_JSON); }