/** * Initiates a new subscription cycle and registers a midcom.services.at call for the next cycle. * * The subscription cycles rely on midcom.services.at. I'm not sure if it is wise to rely on it for such * a totally mission critical part of OpenPSA. Some safeguards might be wise to add. */ function run_cycle($cycle_number, $send_invoice = true) { if (time() < $this->_deliverable->start) { debug_add('Subscription hasn\'t started yet, register the start-up event to $start'); return $this->_create_at_entry($cycle_number, $this->_deliverable->start); } debug_add('Running cycle ' . $cycle_number . ' for deliverable "' . $this->_deliverable->title . '"'); $this_cycle_start = $this->get_cycle_start($cycle_number, time()); $next_cycle_start = $this->calculate_cycle_next($this_cycle_start); $product = org_openpsa_products_product_dba::get_cached($this->_deliverable->product); if ($this->_deliverable->state < org_openpsa_sales_salesproject_deliverable_dba::STATUS_STARTED) { $this->_deliverable->state = org_openpsa_sales_salesproject_deliverable_dba::STATUS_STARTED; $this->_deliverable->update(); } if ($send_invoice) { $calculator = new org_openpsa_invoices_calculator(); $this_cycle_amount = $calculator->process_deliverable($this->_deliverable, $cycle_number); } $tasks_completed = array(); $tasks_not_completed = array(); if ($product->orgOpenpsaObtype == org_openpsa_products_product_dba::TYPE_SERVICE) { // Close previous task(s) $last_task = null; $new_task = null; $task_qb = org_openpsa_projects_task_dba::new_query_builder(); $task_qb->add_constraint('agreement', '=', $this->_deliverable->id); $task_qb->add_constraint('status', '<', org_openpsa_projects_task_status_dba::CLOSED); $tasks = $task_qb->execute(); foreach ($tasks as $task) { $stat = org_openpsa_projects_workflow::complete($task, sprintf(midcom::get('i18n')->get_string('completed by subscription %s', 'org.openpsa.sales'), $cycle_number)); if ($stat) { $tasks_completed[] = $task; } else { $tasks_not_completed[] = $task; } $last_task = $task; } // Create task for the duration of this cycle $task_title = sprintf('%s %s', $this->_deliverable->title, $this->get_cycle_identifier($this_cycle_start)); $new_task = $this->create_task($this_cycle_start, $next_cycle_start - 1, $task_title, $last_task); } // TODO: Warehouse management: create new order if ($this->_deliverable->end < $next_cycle_start && $this->_deliverable->end != 0) { debug_add('Do not register next cycle, the contract ends before'); return true; } if ($this->_create_at_entry($cycle_number + 1, $next_cycle_start)) { if ($send_invoice) { $this->_notify_owner($calculator, $cycle_number, $next_cycle_start, $this_cycle_amount, $tasks_completed, $tasks_not_completed); } return true; } else { return false; } }
public function _on_created() { $this->_locale_restore(); //Try to mark the parent task as started try { $parent = new org_openpsa_projects_task_dba($this->task); $parent->update_cache(); org_openpsa_projects_workflow::start($parent, $this->person); //Add person to resources if necessary $parent->get_members(); if (!array_key_exists($this->person, $parent->resources)) { $parent->add_members('resources', array($this->person)); } } catch (midcom_error $e) { } }
/** * @param mixed $handler_id The ID of the handler. * @param Array $args The argument list. * @param Array &$data The local request data. */ public function _handler_action($handler_id, array $args, array &$data) { midcom::get('auth')->require_valid_user(); // Check if we get the task $task = new org_openpsa_projects_task_dba($args[0]); $task->require_do('midgard:update'); // Check if the action is a valid one switch ($args[1]) { case 'reopen': org_openpsa_projects_workflow::reopen($task); return new midcom_response_relocate("task/{$task->guid}/"); case 'complete': org_openpsa_projects_workflow::complete($task); return new midcom_response_relocate("task/{$task->guid}/"); default: throw new midcom_error('Unknown action ' . $args[1]); } }
private function _generate_invoice() { $invoice = new org_openpsa_invoices_invoice_dba(); $invoice->customer = (int) $_POST['org_openpsa_invoices_invoice_customer']; $invoice->number = $invoice->generate_invoice_number(); $invoice->owner = midcom_connection::get_user(); $invoice->vat = $invoice->get_default('vat'); $invoice->description = $invoice->get_default('remarks'); if (!$invoice->create()) { midcom::get('uimessages')->add($this->_l10n->get('org.openpsa.invoices'), $this->_l10n->get('failed to create invoice, reason ') . midcom_connection::get_error_string(), 'error'); return false; } // create invoice_items foreach ($_POST['org_openpsa_invoices_invoice_tasks'] as $task_id => $invoiceable) { if (!$invoiceable) { continue; } $task = $this->_tasks[$task_id]; //instance the invoice_items $item = new org_openpsa_invoices_invoice_item_dba(); $item->task = $task_id; try { $deliverable = org_openpsa_sales_salesproject_deliverable_dba::get_cached($task->agreement); $item->deliverable = $deliverable->id; } catch (midcom_error $e) { $e->log(); } $item->invoice = $invoice->id; $item->description = $task->title; $item->pricePerUnit = (double) $_POST['org_openpsa_invoices_invoice_tasks_price'][$task_id]; $item->units = (double) $_POST['org_openpsa_invoices_invoice_tasks_units'][$task_id]; $item->create(); // Connect invoice to the tasks involved org_openpsa_projects_workflow::mark_invoiced($task, $invoice); } // Generate "Send invoice" task $invoice_sender_guid = $this->_config->get('invoice_sender'); if (!empty($invoice_sender_guid)) { $invoice->generate_invoicing_task($invoice_sender_guid); } midcom::get('uimessages')->add($this->_l10n->get('org.openpsa.invoices'), sprintf($this->_l10n->get('invoice %s created'), $invoice->get_label()), 'ok'); midcom::get()->relocate("invoice/edit/{$invoice->guid}/"); // This will exit }
/** * helper function - contains code to mark invoice as sent, * maybe move it to invoice-class ? * * @param org_openpsa_invoices_invoice_dba $invoice contains invoice */ private function _mark_as_sent(org_openpsa_invoices_invoice_dba $invoice) { if (!$invoice->sent) { $invoice->sent = time(); if ($invoice->update()) { $this->_request_data['message']['message'] = sprintf($this->_l10n->get('marked invoice %s sent'), $invoice->get_label()); } else { $this->_request_data['message']['message'] = sprintf($this->_l10n->get('could not mark invoice %s paid'), $invoice->get_label()); return false; } $mc = new org_openpsa_relatedto_collector($invoice->guid, 'org_openpsa_projects_task_dba'); $tasks = $mc->get_related_objects(); // Close "Send invoice" task foreach ($tasks as $task) { if (org_openpsa_projects_workflow::complete($task) && !isset($args["no_redirect"])) { midcom::get('uimessages')->add($this->_l10n->get('org.openpsa.invoices'), sprintf($this->_l10n->get('marked task "%s" finished'), $task->title), 'ok'); } } } return true; }
public function test_mark_invoiced() { $group = $this->create_object('org_openpsa_products_product_group_dba'); $product_attributes = array('productGroup' => $group->id, 'code' => 'TEST-' . __CLASS__ . time(), 'delivery' => org_openpsa_products_product_dba::DELIVERY_SUBSCRIPTION); $product = $this->create_object('org_openpsa_products_product_dba', $product_attributes); $salesproject = $this->create_object('org_openpsa_sales_salesproject_dba'); $deliverable_attributes = array('salesproject' => $salesproject->id, 'product' => $product->id, 'description' => 'TEST DESCRIPTION', 'plannedUnits' => 15); $deliverable = $this->create_object('org_openpsa_sales_salesproject_deliverable_dba', $deliverable_attributes); self::$_task->agreement = $deliverable->id; self::$_task->update(); $report_attributes = array('task' => self::$_task->id, 'invoiceable' => true, 'hours' => 15); $report = $this->create_object('org_openpsa_projects_hour_report_dba', $report_attributes); $invoice = $this->create_object('org_openpsa_invoices_invoice_dba'); $result = org_openpsa_projects_workflow::mark_invoiced(self::$_task, $invoice); $this->assertEquals(15, $result); $report->refresh(); $this->assertEquals($invoice->id, $report->invoice); }
/** * Helper functions that gets the number of tasks for the different status types * * @return array The task status overview */ function get_task_count() { $numbers = array('not_started' => 0, 'ongoing' => 0, 'on_hold' => 0, 'closed' => 0, 'rejected' => 0); $task_mc = org_openpsa_projects_task_dba::new_collector('project', $this->id); $task_mc->add_constraint('orgOpenpsaObtype', '=', ORG_OPENPSA_OBTYPE_TASK); $statuses = $task_mc->get_values('status'); foreach ($statuses as $status) { $type = org_openpsa_projects_workflow::get_status_type($status); $numbers[$type]++; } return $numbers; }
function get_icon() { return org_openpsa_projects_workflow::get_status_type_icon($this->status_type); }
public function _on_created() { // Add resources to the parent task/project $task = new org_openpsa_projects_task_dba($this->task); $this->add_resource_to_parent($task); if ($this->person) { if ($this->orgOpenpsaObtype == ORG_OPENPSA_OBTYPE_PROJECTRESOURCE) { org_openpsa_projects_workflow::propose($task, $this->person); } $this->_personobject = self::pid_to_obj($this->person); if (!$this->_personobject || !is_object($this->_personobject)) { debug_add('Person ' . $this->person . ' could not be resolved to user, skipping privilege assignment'); } else { $this->set_privilege('midgard:read', $this->_personobject->id, MIDCOM_PRIVILEGE_ALLOW); $this->set_privilege('midgard:delete', $this->_personobject->id, MIDCOM_PRIVILEGE_ALLOW); $this->set_privilege('midgard:update', $this->_personobject->id, MIDCOM_PRIVILEGE_ALLOW); $this->set_privilege('midgard:read', $this->_personobject->id, MIDCOM_PRIVILEGE_ALLOW); if ($task->orgOpenpsaObtype == ORG_OPENPSA_OBTYPE_TASK) { $task->set_privilege('midgard:read', $this->_personobject->id, MIDCOM_PRIVILEGE_ALLOW); // Resources must be permitted to create hour/expense reports into tasks $task->set_privilege('midgard:create', $this->_personobject->id, MIDCOM_PRIVILEGE_ALLOW); //For declines etc they also need update... $task->set_privilege('midgard:update', $this->_personobject->id, MIDCOM_PRIVILEGE_ALLOW); } } } }
/** * Returns the invoice items that should be written * * @return array */ public function get_invoice_items(org_openpsa_invoices_invoice_dba $invoice) { $this->_invoice = $invoice; $items = array(); // Mark the tasks (and hour reports) related to this agreement as invoiced $tasks = $this->_find_tasks(); foreach ($tasks as $task) { $hours_marked = org_openpsa_projects_workflow::mark_invoiced($task, $invoice); $items[] = $this->_generate_invoice_item($task->title, $hours_marked, $task); } if (sizeof($tasks) == 0) { $items[] = $this->_generate_invoice_item($this->_deliverable->title, $this->_deliverable->units); } return $items; }
public function get_row(midcom_core_dbaobject $task) { $prefix = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX); $task_url = $prefix . "task/{$task->guid}/"; $celldata = $this->get_table_row_data($task, $this->_request_data); $manager_card = org_openpsa_widgets_contact::get($task->manager); $entry = array(); $entry['id'] = $task->id; $entry['index_task'] = $task->title; $entry['task'] = '<a href="' . $task_url . '"><img class="status-icon" src="' . MIDCOM_STATIC_URL . '/stock-icons/16x16/' . $task->get_icon() . '" /> ' . $task->title . '</a>'; if ($this->_request_data['view_identifier'] == 'my_tasks' || $this->_request_data['view_identifier'] == 'project_tasks') { $entry['status_control'] = org_openpsa_projects_workflow::render_status_control($task); $status_type = $this->_get_status_type($task); $entry['index_status'] = $this->_status_order[$status_type]; $entry['status'] = $this->_l10n->get($status_type . ' tasks'); $controls = $this->_render_workflow_controls($task); if ($controls != '') { $entry['task'] = '<div class="title">' . $entry['task'] . '</div><div class="details">' . $controls . '</div>'; } } $entry['index_project'] = $celldata['index_parent']; $entry['project'] = $celldata['parent']; $entry['index_priority'] = $task->priority; $entry['priority'] = $task->priority; if (isset($this->_request_data['priority_array']) && array_key_exists($task->priority, $this->_request_data['priority_array'])) { $entry['priority'] = '<span title="' . $this->_l10n->get($this->_request_data['priority_array'][$task->priority]) . '">' . $task->priority . '</span>'; } if ($this->_request_data['view_identifier'] != 'agreement') { $entry['index_customer'] = $celldata['index_customer']; $entry['customer'] = $celldata['customer']; } $entry['manager'] = $manager_card->show_inline(); $entry['index_manager'] = preg_replace('/<span.*?class="uid".*?>.*?<\\/span>/', '', $entry['manager']); $entry['index_manager'] = strip_tags($entry['index_manager']); $entry['start'] = strftime('%Y-%m-%d', $task->start); $entry['end'] = strftime('%Y-%m-%d', $task->end); if ($this->_request_data['view_identifier'] != 'project_tasks') { $entry['index_reported'] = $task->reportedHours; $entry['reported'] = round($task->reportedHours, 2); if ($task->plannedHours > 0) { $entry['reported'] .= ' / ' . round($task->plannedHours, 2); } } else { $entry['planned_hours'] = $task->plannedHours; $entry['invoiced_hours'] = $task->invoicedHours; $entry['approved_hours'] = $task->approvedHours; $entry['reported_hours'] = $task->reportedHours; } return $entry; }
function deliver($update_deliveries = true) { if ($this->state > org_openpsa_sales_salesproject_deliverable_dba::STATUS_DELIVERED) { return false; } $product = org_openpsa_products_product_dba::get_cached($this->product); if ($product->delivery == org_openpsa_products_product_dba::DELIVERY_SUBSCRIPTION) { // Subscriptions are ongoing, not one delivery return false; } // Check if we need to create task or ship goods if ($update_deliveries) { switch ($product->orgOpenpsaObtype) { case org_openpsa_products_product_dba::TYPE_SERVICE: // Change status of tasks connected to the deliverable $task_qb = org_openpsa_projects_task_dba::new_query_builder(); $task_qb->add_constraint('agreement', '=', $this->id); $task_qb->add_constraint('status', '<', org_openpsa_projects_task_status_dba::CLOSED); $tasks = $task_qb->execute(); foreach ($tasks as $task) { org_openpsa_projects_workflow::close($task, sprintf(midcom::get('i18n')->get_string('completed from deliverable %s', 'org.openpsa.sales'), $this->title)); } break; case org_openpsa_products_product_dba::TYPE_GOODS: // TODO: Warehouse management: mark product as shipped // TODO: Warehouse management: mark product as shipped default: break; } } $this->state = org_openpsa_sales_salesproject_deliverable_dba::STATUS_DELIVERED; $this->end = time(); if ($this->update()) { // Update sales project and mark as delivered (if no other deliverables are active) $salesproject = new org_openpsa_sales_salesproject_dba($this->salesproject); $salesproject->mark_delivered(); midcom::get('uimessages')->add(midcom::get('i18n')->get_string('org.openpsa.sales', 'org.openpsa.sales'), sprintf(midcom::get('i18n')->get_string('marked deliverable "%s" delivered', 'org.openpsa.sales'), $this->title), 'ok'); return true; } return false; }
private function _update_task() { $task = org_openpsa_projects_task_dba::get_cached($this->task); if ($this->type == org_openpsa_projects_task_status_dba::PROPOSED) { try { $recipient = midcom_db_person::get_cached($this->targetPerson); //Creator will naturally accept his own proposal... if ($recipient->guid == $this->metadata->creator) { return org_openpsa_projects_workflow::accept($task, 0, $this->comment); } } catch (midcom_error $e) { $e->log(); } } //See if the parent status needs updating if ($task->status == $this->type) { debug_add("Task status is up to date, returning"); return; } $needs_update = false; if ($task->status < $this->type) { // This doesn't really do anything yet, it's moved here from workflow.php if ($this->type == org_openpsa_projects_task_status_dba::ACCEPTED) { switch ($task->acceptanceType) { case ORG_OPENPSA_TASKACCEPTANCE_ALLACCEPT: case ORG_OPENPSA_TASKACCEPTANCE_ONEACCEPTDROP: debug_add('Acceptance mode not implemented', MIDCOM_LOG_ERROR); return false; break; default: case ORG_OPENPSA_TASKACCEPTANCE_ONEACCEPT: //PONDER: Should this be superseded by generic method for querying the status objects to set the latest status ?? debug_add("Required accept received, setting task status to accepted"); // $needs_update = true; break; } } else { $needs_update = true; } } else { $needs_update = true; } if ($needs_update) { debug_add("Setting task status to {$this->type}"); $task->status = $this->type; $task->_skip_acl_refresh = true; $task->update(); } }