/** * Constructor * * @param Request $request * @return PeopleController */ function __construct($request) { parent::__construct($request); if (!$this->logged_user->isAdministrator() && !$this->logged_user->getSystemPermission('use_time_reports')) { $this->httpError(HTTP_ERR_FORBIDDEN); } // if $this->wireframe->addBreadCrumb(lang('Time'), assemble_url('global_time')); if (TimeReport::canAdd($this->logged_user)) { $this->wireframe->addPageAction(lang('New Report'), assemble_url('global_time_report_add')); } // if $report_id = $this->request->getId('report_id'); if ($report_id) { $this->active_report = TimeReports::findById($report_id); } // if if (instance_of($this->active_report, 'TimeReport')) { $this->wireframe->addBreadCrumb($this->active_report->getName(), $this->active_report->getUrl()); } else { $this->active_report = new TimeReport(); } // if $this->wireframe->current_menu_item = 'time'; $this->smarty->assign('active_report', $this->active_report); }
/** * 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 }