/** * Looks up a deliverable to display. * * @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_add($handler_id, array $args, array &$data) { if ($_SERVER['REQUEST_METHOD'] != 'POST') { throw new midcom_error_forbidden('Only POST requests are allowed here.'); } $this->_salesproject = new org_openpsa_sales_salesproject_dba($args[0]); $this->_salesproject->require_do('midgard:create'); if (!array_key_exists('product', $_POST)) { throw new midcom_error('No product specified, aborting.'); } $this->_product = new org_openpsa_products_product_dba((int) $_POST['product']); $this->_prepare_datamanager(); $data['controller'] = $this->_controller; // Process form switch ($data['controller']->process_form()) { case 'save': $formdata = $data['controller']->datamanager->types; $this->_master->process_notify_date($formdata, $this->_deliverable); case 'cancel': return new midcom_response_relocate("salesproject/{$this->_salesproject->guid}/"); } org_openpsa_helpers::dm2_savecancel($this); $this->add_breadcrumb("salesproject/{$this->_salesproject->guid}/", $this->_salesproject->title); $this->add_breadcrumb('', $this->_l10n->get('add offer')); }
public function get_row(midcom_core_dbaobject $at_entry) { $invoice = array('time' => strftime('%Y-%m-%d %H:%M:%S', $at_entry->start)); try { $deliverable = org_openpsa_sales_salesproject_deliverable_dba::get_cached($at_entry->arguments['deliverable']); $salesproject = org_openpsa_sales_salesproject_dba::get_cached($deliverable->salesproject); } catch (midcom_error $e) { $e->log(); return $invoice; } if ($deliverable->invoiceByActualUnits) { $type = midcom::get('i18n')->get_l10n('org.openpsa.expenses')->get('invoiceable reports'); $invoice_sum = $deliverable->units * $deliverable->pricePerUnit; } else { $invoice_sum = $deliverable->price; $type = midcom::get('i18n')->get_l10n('org.openpsa.reports')->get('fixed price'); } $invoice['sum'] = $invoice_sum; $invoice['deliverable'] = $deliverable->title; $invoice['index_deliverable'] = $deliverable->title; $invoice['type'] = $type; $invoice = $this->_render_contact_field($salesproject->customer, 'customer', $invoice, 'org_openpsa_contacts_group_dba'); $invoice = $this->_render_contact_field($salesproject->customerContact, 'customerContact', $invoice); $invoice = $this->_render_contact_field($salesproject->owner, 'owner', $invoice); if (!empty($this->_sales_url)) { $invoice['deliverable'] = '<a href="' . $this->_sales_url . 'deliverable/' . $deliverable->guid . '/">' . $invoice['deliverable'] . '</a>'; } return $invoice; }
/** * @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_list($handler_id, array $args, array &$data) { midcom::get('auth')->require_valid_user(); // Locate Contacts node for linking $siteconfig = org_openpsa_core_siteconfig::get_instance(); $data['contacts_url'] = $siteconfig->get_node_full_url('org.openpsa.contacts'); $data['reports_url'] = $siteconfig->get_node_full_url('org.openpsa.reports'); $qb = org_openpsa_sales_salesproject_dba::new_query_builder(); if ($handler_id == 'list_status') { $qb = $this->_add_status_constraint($args[0], $qb); $data['mode'] = $args[0]; $data['list_title'] = $this->_l10n->get('salesprojects ' . $args[0]); } else { $qb = $this->_add_customer_constraint($args[0], $qb); $data['mode'] = 'customer'; $data['list_title'] = sprintf($this->_l10n->get('salesprojects with %s'), $data['customer']->get_label()); if ($data['contacts_url']) { $this->_view_toolbar->add_item(array(MIDCOM_TOOLBAR_URL => $data['contacts_url'] . (is_a($data['customer'], 'org_openpsa_contacts_group_dba') ? 'group' : 'person') . "/{$data['customer']->guid}/", MIDCOM_TOOLBAR_LABEL => $this->_l10n->get('go to customer'), MIDCOM_TOOLBAR_ICON => 'stock-icons/16x16/jump-to.png')); } } $this->_salesprojects = $qb->execute(); foreach ($this->_salesprojects as $key => $salesproject) { // Populate previous/next actions in the project $salesproject->get_actions(); } // TODO: Filtering $data['grid'] = new org_openpsa_widgets_grid($data['mode'] . '_salesprojects_grid', 'local'); midcom::get('head')->add_jsfile(MIDCOM_STATIC_URL . '/org.openpsa.core/table2csv.js'); $this->add_breadcrumb("", $data['list_title']); }
/** * Looks up a salesproject to display. * * @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_view($handler_id, array $args, array &$data) { $this->_salesproject = new org_openpsa_sales_salesproject_dba($args[0]); $this->_load_controller(); $this->_list_deliverables(); $this->_prepare_request_data(); $this->_populate_toolbar(); $customer = $this->_salesproject->get_customer(); if ($customer) { $this->add_breadcrumb("list/customer/{$customer->guid}/", $customer->get_label()); } $this->add_breadcrumb("salesproject/{$this->_salesproject->guid}/", $this->_salesproject->title); midcom::get('metadata')->set_request_metadata($this->_salesproject->metadata->revised, $this->_salesproject->guid); midcom::get('head')->set_pagetitle($this->_salesproject->title); $this->add_stylesheet(MIDCOM_STATIC_URL . "/org.openpsa.core/list.css"); org_openpsa_invoices_viewer::add_head_elements_for_invoice_grid(); }
public function testCRUD() { midcom::get('auth')->request_sudo('org.openpsa.sales'); $salesproject = new org_openpsa_sales_salesproject_dba(); $stat = $salesproject->create(); $this->assertTrue($stat); $this->register_object($salesproject); $this->assertEquals(org_openpsa_sales_salesproject_dba::STATUS_ACTIVE, $salesproject->status); $salesproject->refresh(); $this->assertEquals('salesproject #' . $salesproject->id, $salesproject->title); $salesproject->title = 'Test Project'; $stat = $salesproject->update(); $this->assertTrue($stat); $this->assertEquals('Test Project', $salesproject->title); $stat = $salesproject->delete(); $this->assertTrue($stat); midcom::get('auth')->drop_sudo(); }
public static function generate_salesproject_number() { // TODO: Make configurable $year = date('Y', time()); $qb = org_openpsa_sales_salesproject_dba::new_query_builder(); $qb->add_order('metadata.created', 'DESC'); $qb->add_constraint('start', '>=', mktime(0, 0, 1, 1, 1, $year)); $previous = $qb->count_unchecked(); return sprintf('%d-%04d', $year, $previous + 1); }
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; }
/** * * @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'); }
private function _prepare_save() { //Make sure we have start if (!$this->start) { $this->start = time(); } //Make sure we have end if (!$this->end || $this->end == -1) { $this->end = time(); } //Reset start and end to start/end of day $this->start = mktime(0, 0, 0, date('n', $this->start), date('j', $this->start), date('Y', $this->start)); $this->end = mktime(23, 59, 59, date('n', $this->end), date('j', $this->end), date('Y', $this->end)); if ($this->start > $this->end) { debug_add("start ({$this->start}) is greater than end ({$this->end}), aborting", MIDCOM_LOG_ERROR); return false; } if ($this->orgOpenpsaWgtype == ORG_OPENPSA_OBTYPE_TASK) { $this->orgOpenpsaWgtype = ORG_OPENPSA_WGTYPE_NONE; } if ($this->agreement) { // Get customer company into cache from agreement's sales project try { $agreement = org_openpsa_sales_salesproject_deliverable_dba::get_cached($this->agreement); $this->hoursInvoiceableDefault = true; if (!$this->customer) { $salesproject = org_openpsa_sales_salesproject_dba::get_cached($agreement->salesproject); $this->customer = $salesproject->customer; } } catch (midcom_error $e) { } } else { // No agreement, we can't be invoiceable $this->hoursInvoiceableDefault = false; } // Update hour caches $this->update_cache(false); return true; }
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; }
/** * @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_new($handler_id, array $args, array &$data) { midcom::get('auth')->require_valid_user(); midcom::get('auth')->require_user_do('midgard:create', null, 'org_openpsa_sales_salesproject_dba'); $this->_defaults['code'] = org_openpsa_sales_salesproject_dba::generate_salesproject_number(); $this->_defaults['owner'] = midcom_connection::get_user(); if (!isset($this->_datamanager)) { $this->_initialize_datamanager($this->_config->get('schemadb_salesproject')); } $this->_load_create_controller(); switch ($this->_controller->process_form()) { case 'save': // Relocate to main view $prefix = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX); return new midcom_response_relocate($prefix . "salesproject/edit/" . $this->_salesproject->guid . "/"); case 'cancel': return new midcom_response_relocate(''); } $this->_request_data['controller'] =& $this->_controller; midcom::get('head')->set_pagetitle(sprintf($this->_l10n_midcom->get('create %s'), $this->_l10n->get('salesproject'))); // Add toolbar items org_openpsa_helpers::dm2_savecancel($this); }
/** * Used by org_openpsa_relatedto_find_suspects to in case the given object is a person */ private function _org_openpsa_relatedto_find_suspects_person(&$object, &$defaults, &$links_array) { $seen_sp = array(); $mc = org_openpsa_contacts_role_dba::new_collector('role', ORG_OPENPSA_OBTYPE_SALESPROJECT_MEMBER); $mc->add_constraint('person', '=', array_keys($object->id)); $guids = $mc->get_values('objectGuid'); if (!empty($guids)) { $qb = org_openpsa_sales_salesproject_dba::new_query_builder(); $qb->add_constraint('status', '=', org_openpsa_sales_salesproject_dba::STATUS_ACTIVE); $qb->add_constraint('guid', 'IN', $guids); $qbret = @$qb->execute(); if (is_array($qbret)) { foreach ($qbret as $salesproject) { if (isset($seen_sp[$salesproject->id])) { //Only process one salesproject once (someone might be both resource and contact for example) continue; } $seen_sp[$salesproject->id] = true; $to_array = array('other_obj' => false, 'link' => false); $link = new org_openpsa_relatedto_dba(); org_openpsa_relatedto_suspect::defaults_helper($link, $defaults, $this->_component, $salesproject); $to_array['other_obj'] = $salesproject; $to_array['link'] = $link; $links_array[] = $to_array; } } } $qb2 = org_openpsa_sales_salesproject_dba::new_query_builder(); $qb2->add_constraint('owner', '=', $object->id); $qb2->add_constraint('status', '=', org_openpsa_sales_salesproject_dba::STATUS_ACTIVE); $qb2ret = @$qb2->execute(); if (is_array($qb2ret)) { foreach ($qb2ret as $sp) { if (isset($seen_sp[$sp->id])) { //Only process one task once (someone might be both resource and contact for example) continue; } $seen_sp[$sp->id] = true; $to_array = array('other_obj' => false, 'link' => false); $link = new org_openpsa_relatedto_dba(); org_openpsa_relatedto_suspect::defaults_helper($link, $defaults, $this->_component, $sp); $to_array['other_obj'] = $sp; $to_array['link'] = $link; $links_array[] = $to_array; } } }
/** * @todo Check if we already have an open task for this delivery? */ function create_task($start, $end, $title, $source_task = null) { $salesproject = org_openpsa_sales_salesproject_dba::get_cached($this->_deliverable->salesproject); $product = org_openpsa_products_product_dba::get_cached($this->_deliverable->product); // Check if we already have a project for the sales project $project = $salesproject->get_project(); // Create the task $task = new org_openpsa_projects_task_dba(); $task->agreement = $this->_deliverable->id; $task->customer = $salesproject->customer; $task->title = $title; $task->description = $this->_deliverable->description; $task->start = $start; $task->end = $end; $task->plannedHours = $this->_deliverable->plannedUnits; $task->manager = $salesproject->owner; if ($project) { $task->project = $project->id; $task->orgOpenpsaAccesstype = $project->orgOpenpsaAccesstype; $task->orgOpenpsaOwnerWg = $project->orgOpenpsaOwnerWg; } if (!empty($source_task)) { $task->priority = $source_task->priority; $task->manager = $source_task->manager; } // TODO: Figure out if we really want to keep this $task->hoursInvoiceableDefault = true; if ($task->create()) { $task->add_members('contacts', array_keys($salesproject->contacts)); if (!empty($source_task)) { $source_task->get_members(); $task->add_members('resources', array_keys($source_task->resources)); } org_openpsa_relatedto_plugin::create($task, 'org.openpsa.projects', $product, 'org.openpsa.products'); // Copy tags from deliverable so we can seek resources $tagger = new net_nemein_tag_handler(); $tagger->copy_tags($this->_deliverable, $task); midcom::get('uimessages')->add(midcom::get('i18n')->get_string('org.openpsa.sales', 'org.openpsa.sales'), sprintf(midcom::get('i18n')->get_string('created task "%s"', 'org.openpsa.sales'), $task->title), 'ok'); return $task; } else { throw new midcom_error("The task for this cycle could not be created. Last Midgard error was: " . midcom_connection::get_error_string()); } }
</div> <div class="main"> <?php $data['datamanager']->display_view(true); //add tabs $tabs = array(); $siteconfig = org_openpsa_core_siteconfig::get_instance(); $invoices_url = $siteconfig->get_node_relative_url('org.openpsa.invoices'); $sales_url = $siteconfig->get_node_relative_url('org.openpsa.sales'); //TODO: Check for privileges somehow $invoices_url = $siteconfig->get_node_relative_url('org.openpsa.invoices'); if ($invoices_url) { $qb = org_openpsa_invoices_invoice_dba::new_query_builder(); $qb->add_constraint('customerContact', '=', $data['person']->id); $qb->set_limit(1); if ($qb->count() > 0) { $tabs[] = array('url' => $invoices_url . "list/customer/all/{$data['person']->guid}/", 'title' => midcom::get('i18n')->get_string('invoices', 'org.openpsa.invoices')); } } if ($sales_url) { $qb = org_openpsa_sales_salesproject_dba::new_query_builder(); $qb->add_constraint('customerContact', '=', $data['person']->id); $qb->set_limit(1); if ($qb->count() > 0) { $tabs[] = array('url' => $sales_url . "list/customer/{$data['person']->guid}/", 'title' => midcom::get('i18n')->get_string('salesprojects', 'org.openpsa.sales')); } } org_openpsa_widgets_ui::render_tabs($data['person']->guid, $tabs); ?> </div>
$task =& $data['object']; $task->get_members(); $prefix = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX); $siteconfig = org_openpsa_core_siteconfig::get_instance(); $sales_url = $siteconfig->get_node_full_url('org.openpsa.sales'); $expenses_url = $siteconfig->get_node_relative_url('org.openpsa.expenses'); ?> <div class="org_openpsa_projects_task"> <div class="sidebar"> <?php if ($task->agreement) { try { $agreement = org_openpsa_sales_salesproject_deliverable_dba::get_cached($task->agreement); $output = $agreement->deliverable_html; if ($sales_url) { $salesproject = org_openpsa_sales_salesproject_dba::get_cached($agreement->salesproject); $output = "<a href=\"{$sales_url}salesproject/{$salesproject->guid}/#{$agreement->guid}/\">{$output}</a>\n"; } echo "<h2>" . $data['l10n']->get('agreement') . "</h2>\n"; echo $output; } catch (midcom_error $e) { } } if ($task->manager) { echo "<h2>" . $data['l10n']->get('manager') . "</h2>\n"; $contact = org_openpsa_widgets_contact::get($task->manager); echo $contact->show_inline(); } $remote_search = $task->parameter('org.openpsa.projects.projectbroker', 'remote_search'); if ($remote_search) { echo "<div class=\"resources search\">\n";