/** * 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 }
/** * 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); }