Example #1
0
 /**
  * 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;
     }
 }
Example #2
0
 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) {
     }
 }
Example #3
0
 /**
  * @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]);
     }
 }
Example #4
0
 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
 }
Example #5
0
 /**
  * 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;
 }
Example #6
0
 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);
 }
Example #7
0
 /**
  * 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;
 }
Example #8
0
 function get_icon()
 {
     return org_openpsa_projects_workflow::get_status_type_icon($this->status_type);
 }
Example #9
0
 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);
             }
         }
     }
 }
Example #10
0
 /**
  * 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;
 }
Example #11
0
 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;
 }
Example #12
0
 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;
 }
Example #13
0
 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();
     }
 }