Ejemplo n.º 1
0
 /**
  * Calculates the prices of deliverables
  *
  * and adds them up to the salesproject value
  */
 function calculate_price()
 {
     $value = 0;
     $cost = 0;
     $deliverable_qb = org_openpsa_sales_salesproject_deliverable_dba::new_query_builder();
     $deliverable_qb->add_constraint('salesproject', '=', $this->id);
     $deliverable_qb->add_constraint('up', '=', 0);
     $deliverable_qb->add_constraint('state', '<>', org_openpsa_sales_salesproject_deliverable_dba::STATUS_DECLINED);
     $deliverables = $deliverable_qb->execute();
     foreach ($deliverables as $deliverable) {
         if ($deliverable->orgOpenpsaObtype == org_openpsa_products_product_dba::DELIVERY_SUBSCRIPTION) {
             $scheduler = new org_openpsa_invoices_scheduler($deliverable);
             if ($deliverable->end == 0) {
                 // FIXME: Get this from config key 'subscription_profit_months'
                 $cycles = $scheduler->calculate_cycles(12);
             } else {
                 $cycles = $scheduler->calculate_cycles();
             }
             $value = $value + $deliverable->price * $cycles;
             $cost = $cost + $deliverable->cost * $cycles;
         } else {
             $value = $value + $deliverable->price;
             $cost = $cost + $deliverable->cost;
         }
     }
     $profit = $value - $cost;
     if ($this->value != $value || $this->profit != $profit) {
         $this->value = $value;
         $this->profit = $value - $cost;
         $this->update();
     }
 }
Ejemplo n.º 2
0
 /**
  * Manually trigger a subscription cycle run.
  */
 private function _run_cycle()
 {
     if (empty($_POST['at_entry'])) {
         throw new midcom_error('No AT entry specified');
     }
     $entry = new midcom_services_at_entry_dba($_POST['at_entry']);
     $deliverable = new org_openpsa_sales_salesproject_deliverable_dba($entry->arguments['deliverable']);
     $scheduler = new org_openpsa_invoices_scheduler($deliverable);
     if (!$scheduler->run_cycle($entry->arguments['cycle'])) {
         throw new midcom_error('Failed to run cycle, see debug log for details');
     }
     if (!$entry->delete()) {
         throw new midcom_error('Could not delete AT entry: ' . midcom_connection::get_error_string());
     }
 }
Ejemplo n.º 3
0
 private function _get_invoices_for_subscription($deliverable, $at_entry)
 {
     if ($deliverable->invoiceByActualUnits && $at_entry->arguments['cycle'] > 1) {
         $invoice_sum = $deliverable->invoiced / ($at_entry->arguments['cycle'] - 1);
         if ($invoice_sum == 0) {
             return array();
         }
         $calculation_base = sprintf($this->_l10n->get('average of %s runs'), $at_entry->arguments['cycle'] - 1);
     } else {
         $invoice_sum = $deliverable->price;
         $calculation_base = $this->_l10n->get('fixed price');
     }
     $salesproject = org_openpsa_sales_salesproject_dba::get_cached($deliverable->salesproject);
     $scheduler = new org_openpsa_invoices_scheduler($deliverable);
     $invoices = array();
     $time = $at_entry->start;
     while ($time < $this->_request_data['end'] && ($time < $deliverable->end || $deliverable->continuous)) {
         $invoice = new org_openpsa_invoices_invoice_dba();
         $invoice->customer = $salesproject->customer;
         $invoice->customerContact = $salesproject->customerContact;
         $invoice->owner = $salesproject->owner;
         $invoice->sum = $invoice_sum;
         $invoice->sent = $time;
         $invoice->due = $invoice->get_default('due') * 3600 * 24 + $time;
         $invoice->vat = $invoice->get_default('vat');
         $invoice->description = $deliverable->title . ' (' . $calculation_base . ')';
         if ($this->_sales_url) {
             $invoice->description = '<a href="' . $this->_sales_url . 'deliverable/' . $deliverable->guid . '/">' . $invoice->description . '</a>';
         }
         $invoice->paid = $invoice->due;
         $invoices[] = $invoice;
         if (!($time = $scheduler->calculate_cycle_next($time))) {
             debug_add('Failed to calculate timestamp for next cycle, exiting', MIDCOM_LOG_WARN);
             break;
         }
     }
     return $invoices;
 }
Ejemplo n.º 4
0
 /**
  *
  * @param mixed $handler_id The ID of the handler.
  * @param array &$data The local request data.
  */
 public function _show_generator($handler_id, array &$data)
 {
     midcom_show_style('sales_report-deliverable-start');
     // Quick workaround to Bergies lazy determination of whether this is user's or everyone's report...
     if ($this->_request_data['query_data']['resource'] == 'user:'******'auth')->user->guid) {
         // My report
         $data['handler_id'] = 'deliverable_report';
     } else {
         // Generic report
         $data['handler_id'] = 'sales_report';
     }
     /*** Copied from sales/handler/deliverable/report.php ***/
     midcom_show_style('sales_report-deliverable-header');
     $invoices_node = midcom_helper_misc::find_node_by_component('org.openpsa.invoices');
     $sums_per_person = array();
     $sums_all = array('price' => 0, 'cost' => 0, 'profit' => 0);
     $odd = true;
     foreach ($data['invoices'] as $deliverable_guid => $invoices) {
         if (count($invoices) == 0) {
             // No invoices sent in this project, skip
             continue;
         }
         try {
             $deliverable = org_openpsa_sales_salesproject_deliverable_dba::get_cached($deliverable_guid);
             $product = org_openpsa_products_product_dba::get_cached($deliverable->product);
             $salesproject = org_openpsa_sales_salesproject_dba::get_cached($deliverable->salesproject);
             $customer = midcom_db_group::get_cached($salesproject->customer);
         } catch (midcom_error $e) {
             continue;
         }
         if (!array_key_exists($salesproject->owner, $sums_per_person)) {
             $sums_per_person[$salesproject->owner] = array('price' => 0, 'cost' => 0, 'profit' => 0);
         }
         // Calculate the price and cost from invoices
         $invoice_price = 0;
         $data['invoice_string'] = '';
         $invoice_cycle_numbers = array();
         foreach ($invoices as $invoice) {
             $invoice_price += $invoice->sum;
             $invoice_class = $invoice->get_status();
             if ($invoices_node) {
                 $invoice_label = "<a class=\"{$invoice_class}\" href=\"{$invoices_node[MIDCOM_NAV_FULLURL]}invoice/{$invoice->guid}/\">" . $invoice->get_label() . "</a>";
             } else {
                 $invoice_label = $invoice->get_label();
             }
             if ($product->delivery == org_openpsa_products_product_dba::DELIVERY_SUBSCRIPTION) {
                 $invoice_cycle_numbers[] = (int) $invoice->parameter('org.openpsa.sales', 'cycle_number');
             }
             $data['invoice_string'] .= "<li class=\"{$invoice_class}\">{$invoice_label}</li>\n";
         }
         if ($product->delivery == org_openpsa_products_product_dba::DELIVERY_SUBSCRIPTION) {
             // This is a subscription, it should be shown only if it is the first invoice
             if (!in_array(1, $invoice_cycle_numbers)) {
                 continue;
                 // This will skip to next deliverable
             }
             $scheduler = new org_openpsa_invoices_scheduler($deliverable);
             if ($deliverable->end == 0) {
                 // Subscription doesn't have an end date, use specified amount of months for calculation
                 $cycles = $scheduler->calculate_cycles($this->_config->get('subscription_profit_months'));
                 $data['calculation_basis'] = sprintf($data['l10n']->get('%s cycles in %s months'), $cycles, $this->_config->get('subscription_profit_months'));
             } else {
                 $cycles = $scheduler->calculate_cycles();
                 $data['calculation_basis'] = sprintf($data['l10n']->get('%s cycles, %s - %s'), $cycles, strftime('%x', $deliverable->start), strftime('%x', $deliverable->end));
             }
             $price = $deliverable->price * $cycles;
             $cost = $deliverable->cost * $cycles;
         } else {
             // This is a single delivery, calculate cost as percentage as it may be invoiced in pieces
             if ($deliverable->price) {
                 $cost_percentage = 100 / $deliverable->price * $invoice_price;
                 $cost = $deliverable->cost / 100 * $cost_percentage;
             } else {
                 $cost_percentage = 100;
                 $cost = $deliverable->cost;
             }
             $price = $invoice_price;
             $data['calculation_basis'] = sprintf($data['l10n']->get('%s%% of %s'), round($cost_percentage), $deliverable->price);
         }
         // And now just count the profit
         $profit = $price - $cost;
         $data['customer'] = $customer;
         $data['salesproject'] = $salesproject;
         $data['deliverable'] = $deliverable;
         $data['price'] = $price;
         $sums_per_person[$salesproject->owner]['price'] += $price;
         $sums_all['price'] += $price;
         $data['cost'] = $cost;
         $sums_per_person[$salesproject->owner]['cost'] += $cost;
         $sums_all['cost'] += $cost;
         $data['profit'] = $profit;
         $sums_per_person[$salesproject->owner]['profit'] += $profit;
         $sums_all['profit'] += $profit;
         if ($odd) {
             $data['row_class'] = '';
             $odd = false;
         } else {
             $data['row_class'] = ' class="even"';
             $odd = true;
         }
         midcom_show_style('sales_report-deliverable-item');
     }
     $data['sums_per_person'] = $sums_per_person;
     $data['sums_all'] = $sums_all;
     midcom_show_style('sales_report-deliverable-footer');
     /*** /Copied from sales/handler/deliverable/report.php ***/
     midcom_show_style('sales_report-deliverable-end');
 }
Ejemplo n.º 5
0
 public function testCreate_task()
 {
     $organization = $this->create_object('org_openpsa_contacts_group_dba');
     $manager = $this->create_object('midcom_db_person');
     $member = $this->create_object('midcom_db_person');
     $group = $this->create_object('org_openpsa_products_product_group_dba');
     $product_attributes = array('productGroup' => $group->id, 'code' => 'TEST-' . __CLASS__ . time());
     $product = $this->create_object('org_openpsa_products_product_dba', $product_attributes);
     $salesproject_attributes = array('owner' => $manager->id, 'customer' => $organization->id);
     $salesproject = $this->create_object('org_openpsa_sales_salesproject_dba', $salesproject_attributes);
     $member_attributes = array('person' => $member->id, 'objectGuid' => $salesproject->guid, 'role' => ORG_OPENPSA_OBTYPE_SALESPROJECT_MEMBER);
     $this->create_object('org_openpsa_contacts_role_dba', $member_attributes);
     $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);
     $start = time();
     $end = $start + 30 * 24 * 60 * 60;
     $title = 'TEST TITLE';
     $start_cmp = mktime(0, 0, 0, date('n', $start), date('j', $start), date('Y', $start));
     $end_cmp = mktime(23, 59, 59, date('n', $end), date('j', $end), date('Y', $end));
     $scheduler = new org_openpsa_invoices_scheduler($deliverable);
     midcom::get('auth')->request_sudo('org.openpsa.invoices');
     $task = $scheduler->create_task($start, $end, $title);
     $this->assertTrue(is_a($task, 'org_openpsa_projects_task_dba'));
     $this->register_object($task);
     $this->assertEquals($deliverable->id, $task->agreement);
     $this->assertEquals($salesproject->customer, $task->customer);
     $this->assertEquals($title, $task->title);
     $this->assertEquals($deliverable->description, $task->description);
     $this->assertEquals($start_cmp, $task->start);
     $this->assertEquals($end_cmp, $task->end);
     $this->assertEquals($deliverable->plannedUnits, $task->plannedHours);
     $this->assertEquals($salesproject->owner, $task->manager);
     $this->assertTrue($task->hoursInvoiceableDefault);
     $mc = org_openpsa_relatedto_dba::new_collector('fromGuid', $task->guid);
     $mc->add_value_property('toGuid');
     $mc->execute();
     $keys = $mc->list_keys();
     $this->assertEquals(1, sizeof($keys));
     $product_guid = $mc->get_subkey(key($keys), 'toGuid');
     $this->assertEquals($product->guid, $product_guid);
     $salesproject->get_members();
     $task->get_members();
     $this->assertEquals($salesproject->contacts, $task->contacts);
     $project = new org_openpsa_projects_project($task->project);
     $this->assertTrue(!empty($project->guid));
     $this->register_object($project);
     $project->get_members();
     $this->assertEquals($salesproject->contacts, $project->contacts);
     $this->assertEquals($salesproject->owner, $project->manager);
     $task->priority = 4;
     $task->manager = $member->id;
     $task->update();
     $task->add_members('resources', array($member->id));
     $task->refresh();
     $task2 = $scheduler->create_task($start, $end, $title, $task);
     $this->register_object($task2);
     $task2->get_members();
     $task->get_members();
     $this->assertEquals(4, $task2->priority);
     $this->assertEquals($member->id, $task2->manager);
     $this->assertEquals($task->resources, $task2->resources);
     midcom::get('auth')->drop_sudo();
 }
Ejemplo n.º 6
0
 function order()
 {
     if ($this->state >= org_openpsa_sales_salesproject_deliverable_dba::STATUS_ORDERED) {
         return false;
     }
     // Cache the original cost values intended and reset the fields
     $this->plannedUnits = $this->units;
     $this->plannedCost = $this->cost;
     if ($this->invoiceByActualUnits) {
         $this->cost = 0;
         $this->units = 0;
     }
     // Check what kind of order this is
     $product = org_openpsa_products_product_dba::get_cached($this->product);
     $scheduler = new org_openpsa_invoices_scheduler($this);
     if ($product->delivery == org_openpsa_products_product_dba::DELIVERY_SUBSCRIPTION) {
         // This is a new subscription, initiate the cycle but don't send invoice
         if (!$scheduler->run_cycle(1, false)) {
             return false;
         }
     } else {
         // Check if we need to create task or ship goods
         switch ($product->orgOpenpsaObtype) {
             case org_openpsa_products_product_dba::TYPE_SERVICE:
                 $scheduler->create_task($this->start, $this->end, $this->title);
                 break;
             case org_openpsa_products_product_dba::TYPE_GOODS:
                 // TODO: Warehouse management: create new order
             // TODO: Warehouse management: create new order
             default:
                 break;
         }
     }
     $this->state = org_openpsa_sales_salesproject_deliverable_dba::STATUS_ORDERED;
     if ($this->update()) {
         // Update sales project and mark as won
         $salesproject = new org_openpsa_sales_salesproject_dba($this->salesproject);
         if ($salesproject->status != org_openpsa_sales_salesproject_dba::STATUS_WON) {
             $salesproject->status = org_openpsa_sales_salesproject_dba::STATUS_WON;
             $salesproject->update();
         }
         return true;
     }
     return false;
 }
Ejemplo n.º 7
0
 /**
  * @depends testRun_cycle
  */
 public function testRun_cycle_multiple()
 {
     midcom::get('auth')->request_sudo('org.openpsa.invoices');
     $deliverable_attributes = array('salesproject' => $this->_salesproject->id, 'product' => $this->_product->id, 'description' => 'TEST DESCRIPTION 2', 'pricePerUnit' => 10, 'plannedUnits' => 15, 'units' => 10, 'invoiceByActualUnits' => true, 'state' => org_openpsa_sales_salesproject_deliverable_dba::STATUS_STARTED, 'start' => strtotime('2010-02-02 00:00:00'));
     $deliverable2 = $this->create_object('org_openpsa_sales_salesproject_deliverable_dba', $deliverable_attributes);
     $task_attributes = array('project' => $this->_project->id, 'agreement' => $deliverable2->id, 'title' => 'TEST TITLE 2', 'reportedHours' => 10);
     $task2 = $this->create_object('org_openpsa_projects_task_dba', $task_attributes);
     $this->_product->delivery = org_openpsa_products_product_dba::DELIVERY_SUBSCRIPTION;
     $this->_product->update();
     $this->_deliverable->start = strtotime('2010-02-02 00:00:00');
     $this->_deliverable->continuous = true;
     $this->_deliverable->invoiceByActualUnits = false;
     $this->_deliverable->pricePerUnit = 10;
     $this->_deliverable->plannedUnits = 10;
     $this->_deliverable->state = org_openpsa_sales_salesproject_deliverable_dba::STATUS_STARTED;
     $this->_deliverable->update();
     $scheduler = new org_openpsa_invoices_scheduler($this->_deliverable);
     $stat = $scheduler->run_cycle(1, true);
     $this->assertTrue($stat);
     $scheduler = new org_openpsa_invoices_scheduler($deliverable2);
     $stat = $scheduler->run_cycle(1, true);
     $this->assertTrue($stat);
     $qb = org_openpsa_invoices_invoice_item_dba::new_query_builder();
     $qb->add_constraint('deliverable', '=', $this->_deliverable->id);
     $results = $qb->execute();
     $this->assertEquals(1, sizeof($results));
     $item1 = $results[0];
     $this->register_object($item1);
     $qb = org_openpsa_invoices_invoice_item_dba::new_query_builder();
     $qb->add_constraint('deliverable', '=', $deliverable2->id);
     $results = $qb->execute();
     $this->assertEquals(1, sizeof($results));
     $item2 = $results[0];
     $this->register_object($item2);
     $this->assertEquals($item1->invoice, $item2->invoice);
     $this->assertEquals($this->_deliverable->id, $item1->deliverable);
     $this->assertEquals($deliverable2->id, $item2->deliverable);
     $invoice = new org_openpsa_invoices_invoice_dba($item2->invoice);
     $this->register_object($invoice);
     $this->assertEquals(200, $invoice->sum);
     $this->assertEquals(100, $deliverable2->invoiced);
     midcom::get('auth')->drop_sudo();
 }
Ejemplo n.º 8
0
 /**
  * AT handler for handling subscription cycles.
  *
  * @param array $args handler arguments
  * @param object &$handler reference to the cron_handler object calling this method.
  * @return boolean indicating success/failure
  */
 function new_subscription_cycle($args, &$handler)
 {
     if (!isset($args['deliverable']) || !isset($args['cycle'])) {
         $msg = 'deliverable GUID or cycle number not set, aborting';
         $handler->print_error($msg);
         debug_add($msg, MIDCOM_LOG_ERROR);
         return false;
     }
     try {
         $deliverable = new org_openpsa_sales_salesproject_deliverable_dba($args['deliverable']);
     } catch (midcom_error $e) {
         $msg = "Deliverable {$args['deliverable']} not found, error " . midcom_connection::get_error_string();
         $handler->print_error($msg);
         debug_add($msg, MIDCOM_LOG_ERROR);
         return false;
     }
     $scheduler = new org_openpsa_invoices_scheduler($deliverable);
     return $scheduler->run_cycle($args['cycle']);
 }