public function testCRUD() { midcom::get('auth')->request_sudo('org.openpsa.invoices'); $item = new org_openpsa_invoices_invoice_item_dba(); $item->invoice = self::$_invoice->id; $item->deliverable = self::$_deliverable->id; $item->pricePerUnit = 100; $item->units = 2.5; $stat = $item->create(); $this->assertTrue($stat); $this->register_object($item); $parent = $item->get_parent(); $this->assertEquals($parent->guid, self::$_invoice->guid); self::$_invoice->refresh(); self::$_deliverable->refresh(); $this->assertEquals(self::$_invoice->sum, 250); $this->assertEquals(self::$_deliverable->invoiced, 250); $this->assertEquals(self::$_deliverable->state, org_openpsa_sales_salesproject_deliverable_dba::STATUS_INVOICED); $item->units = 3.5; $stat = $item->update(); $this->assertTrue($stat); self::$_invoice->refresh(); self::$_deliverable->refresh(); $this->assertEquals(self::$_invoice->sum, 350); $this->assertEquals(self::$_deliverable->invoiced, 350); $stat = $item->delete(); $this->assertTrue($stat); self::$_invoice->refresh(); self::$_deliverable->refresh(); $this->assertEquals(self::$_invoice->sum, 0); $this->assertEquals(self::$_deliverable->invoiced, 0); midcom::get('auth')->drop_sudo(); }
public function test_generate_invoice() { midcom::get('auth')->request_sudo('org.openpsa.invoices'); $customer = $this->create_object('org_openpsa_contacts_group_dba'); $salesproject = $this->create_object('org_openpsa_sales_salesproject_dba'); $deliverable_attributes = array('salesproject' => $salesproject->id, 'price' => 100, 'state' => org_openpsa_sales_salesproject_deliverable_dba::STATUS_DELIVERED, 'invoiceByActualUnits' => false); $deliverable = $this->create_object('org_openpsa_sales_salesproject_deliverable_dba', $deliverable_attributes); $task_attributes = array('project' => $salesproject->id, 'agreement' => $deliverable->id, 'status' => org_openpsa_projects_task_status_dba::COMPLETED, 'invoiceableHours' => true); $task = $this->create_object('org_openpsa_projects_task_dba', $task_attributes); $_POST = array('org_openpsa_invoices_invoice' => true, 'org_openpsa_invoices_invoice_tasks' => array($task->id => true), 'org_openpsa_invoices_invoice_tasks_price' => array($task->id => 10), 'org_openpsa_invoices_invoice_tasks_units' => array($task->id => 10), 'org_openpsa_invoices_invoice_customer' => $customer->id); $url = $this->run_relocate_handler('org.openpsa.invoices', array('projects')); $qb = org_openpsa_invoices_invoice_item_dba::new_query_builder(); $qb->add_constraint('task', '=', $task->id); $results = $qb->execute(); $this->assertEquals(1, sizeof($results)); $item = $results[0]; $invoice = new org_openpsa_invoices_invoice_dba($item->invoice); $task->refresh(); $this->assertEquals('invoice/edit/' . $invoice->guid . '/', $url); $this->assertEquals(100, $invoice->sum); $this->assertEquals($deliverable->id, $item->deliverable); $deliverable->refresh(); $this->assertEquals(org_openpsa_sales_salesproject_deliverable_dba::STATUS_INVOICED, $deliverable->state); midcom::get('auth')->drop_sudo(); }
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 }
private function _get_deliverable_invoices($id) { $mc = org_openpsa_invoices_invoice_item_dba::new_collector('deliverable', $id); $ids = $mc->get_values('invoice'); if (sizeof($ids) < 1) { return array(); } $qb = org_openpsa_invoices_invoice_dba::new_query_builder(); $qb->add_constraint('id', 'IN', $ids); $qb->add_constraint('sent', '>=', $this->_request_data['start']); $qb->add_constraint('sent', '<=', $this->_request_data['end']); return $qb->execute(); }
/** * @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_itemposition($handler_id, array $args, array &$data) { midcom::get()->skip_page_style = true; $item = new org_openpsa_invoices_invoice_item_dba((int) $_POST['id']); $item->position = $_POST['position']; if (!$item->update()) { throw new midcom_error('Failed to update item: ' . midcom_connection::get_error_string()); } return new midcom_response_json(array()); }
if ($cycle_number) { $description .= ' ' . $cycle_number; } foreach ($items as $item) { if ($item->description == $description && $item->deliverable == 0) { echo "Found invoice item for deliverable " . $deliverable->title . " by description\n"; flush(); $found = true; break; } } } if (!$found) { echo "Could not identify invoice item for deliverable " . $deliverable->title . " on invoice " . $invoice->get_label() . ", creating empty item\n"; flush(); $item = new org_openpsa_invoices_invoice_item_dba(); $item->invoice = $invoice->id; $item->deliverable = $deliverable->id; $item->pricePerUnit = 0; $item->units = 1; $item->description = $deliverable->title . ' (auto-generated)'; $item->create(); } } $relatedto->delete(); } } $qb_items = org_openpsa_invoices_invoice_item_dba::new_query_builder(); $qb_items->add_constraint('task', '>', 0); $qb_items->add_constraint('deliverable', '=', 0); $items = $qb_items->execute();
/** * Helper function that tries to locate unsent invoices for deliverables in the same salesproject * * Example use case: A support contract with multiple hourly rates (defined * as deliverables) for different types of work. Instead of sending the customer * one invoice per hourly rate per month, one composite invoice for all fees is generated */ private function _probe_invoice($cycle_number) { $deliverable_mc = org_openpsa_sales_salesproject_deliverable_dba::new_collector('salesproject', $this->_deliverable->salesproject); $deliverable_mc->add_constraint('state', '>', org_openpsa_sales_salesproject_deliverable_dba::STATUS_DECLINED); $deliverable_mc->add_constraint('product.delivery', '=', org_openpsa_products_product_dba::DELIVERY_SUBSCRIPTION); $deliverables = $deliverable_mc->get_values('id'); $item_mc = org_openpsa_invoices_invoice_item_dba::new_collector('metadata.deleted', false); $item_mc->add_constraint('deliverable.salesproject', '=', $this->_deliverable->salesproject); $item_mc->add_constraint('invoice.sent', '=', 0); $suspects = $item_mc->get_values('invoice'); if (sizeof($suspects) > 0) { return new org_openpsa_invoices_invoice_dba(array_pop($suspects)); } //Nothing found, create a new invoice return $this->_create_invoice($cycle_number); }
private function _find_tasks() { $qb = org_openpsa_projects_task_dba::new_query_builder(); $qb->add_constraint('agreement', '=', $this->_deliverable->id); if ($this->_deliverable->invoiceByActualUnits) { $qb->add_constraint('invoiceableHours', '>', 0); } else { $item_mc = org_openpsa_invoices_invoice_item_dba::new_collector('deliverable', $this->_deliverable->id); $skip_ids = $item_mc->get_values('task'); if (sizeof($skip_ids) > 0) { $qb->add_constraint('id', 'NOT IN', $skip_ids); } } return $qb->execute(); }
midcom::get('auth')->require_admin_user(); // Ensure this is not buffered midcom::get('cache')->content->enable_live_mode(); while (@ob_end_flush()) { midcom::get()->disable_limits(); } echo "<h1>Invalidating deliverable caches:</h1>\n"; $qb = org_openpsa_sales_salesproject_deliverable_dba::new_query_builder(); $qb->add_constraint('state', '>=', org_openpsa_sales_salesproject_deliverable_dba::STATUS_ORDERED); $deliverables = $qb->execute(); echo "<pre>\n"; flush(); foreach ($deliverables as $deliverable) { $start = microtime(true); echo "Update caches for deliverable #{$deliverable->id} " . $deliverable->title . "\n"; echo "units: {$deliverable->units} uninvoiceable: {$deliverable->uninvoiceableUnits} price: {$deliverable->price} cost: {$deliverable->cost} invoiced: {$deliverable->invoiced}\n"; flush(); $deliverable->calculate_price(false); org_openpsa_invoices_invoice_item_dba::update_deliverable($deliverable); $deliverable->update_units(); $deliverable->update(); $time_consumed = round(microtime(true) - $start, 2); echo "OK ({$time_consumed} secs), new units:\n"; echo "units: {$deliverable->units} uninvoiceable: {$deliverable->uninvoiceableUnits} price: {$deliverable->price} cost: {$deliverable->cost} invoiced: {$deliverable->invoiced}\n"; flush(); } ?> </pre> <p>All done</p>
/** * Helper function to get invoice_item for the passed task id, if there is no item * it will return a new created one */ private function _probe_invoice_item_for_task($task_id) { //check if there is already an invoice_item for this task $qb_invoice_item = org_openpsa_invoices_invoice_item_dba::new_query_builder(); $qb_invoice_item->add_constraint('invoice', '=', $this->id); $qb_invoice_item->add_constraint('task', '=', $task_id); $invoice_items = $qb_invoice_item->execute(); if (count($invoice_items) == 1) { $invoice_item = $invoice_items[0]; } else { if (count($invoice_items) > 1) { debug_add('More than one item found for task #' . $task_id . ', only returning the first', MIDCOM_LOG_INFO); $invoice_item = $invoice_items[0]; } else { $invoice_item = new org_openpsa_invoices_invoice_item_dba(); $invoice_item->task = $task_id; $invoice_item->invoice = $this->id; $invoice_item->create(); } } return $invoice_item; }
private function _count_invoice_items($invoice_id) { $qb = org_openpsa_invoices_invoice_item_dba::new_query_builder(); $qb->add_constraint('invoice', '=', $invoice_id); $items = $qb->execute(); $this->register_objects($items); return count($items); }
/** * @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(); }
/** * Helper that adds a customer/deliverable constraints to list QBs * * @param midcom_core_querybuilder &$qb th QB we're working with */ private function _add_filters(&$qb) { if ($this->_customer) { if (is_a($this->_customer, 'org_openpsa_contacts_group_dba')) { $qb->add_constraint('customer', '=', $this->_customer->id); } else { $qb->add_constraint('customerContact', '=', $this->_customer->id); } } if ($this->_deliverable) { $mc = org_openpsa_invoices_invoice_item_dba::new_collector('deliverable', $this->_deliverable->id); $invoice_ids = $mc->get_values('invoice'); if (!empty($invoice_ids)) { $qb->add_constraint('id', 'IN', $invoice_ids); } else { $qb->add_constraint('id', '=', 0); } } }