/** * @param $data * @return bool */ public function run($data) { $this->job->runnable_ran = true; $this->job->runnable_data = $data; $data = json_decode($data, true); Activity::disable(); $ftsInstance = SugarSearchEngineFactory::getInstance(); $ftsInstance->setForceAsyncIndex(true); foreach ($data as $row) { /* @var $opp Opportunity */ $opp = BeanFactory::getBean('Opportunities', $row['id']); $opp->save(false); } $ftsInstance->setForceAsyncIndex(SugarConfig::getInstance()->get('search_engine.force_async_index', false)); Activity::enable(); $this->job->succeedJob(); $this->notifyAssignedUser(); return true; }
public function convertQuote(ServiceBase $api, $args) { $this->requireArgs($args, array('record')); /* @var $quote Quote */ $quote = $this->loadBean($api, $args); if (!$quote->ACLAccess('view')) { throw new SugarApiExceptionNotAuthorized('EXCEPTION_NOT_AUTHORIZED'); } // first lets load up the bean to make sure we have access to the opportunity save /* @var $opportunity Opportunity */ $opportunity = $this->loadBean($api, array('module' => 'Opportunities', 'record' => '')); if (!$opportunity->ACLAccess('save')) { // No create access so we construct an error message and throw the exception $failed_module_strings = return_module_language($GLOBALS['current_language'], $opportunity->module_dir); $moduleName = $failed_module_strings['LBL_MODULE_NAME']; $args = null; if (!empty($moduleName)) { $args = array('moduleName' => $moduleName); } throw new SugarApiExceptionNotAuthorized('EXCEPTION_CREATE_MODULE_NOT_AUTHORIZED', $args); } // we made it though all the ACL checks. lets see if this quote already has an an opportunity $quote->load_relationship('opportunities'); if (count($quote->opportunities->getBeans())) { // throw an exception here as we already have one. throw new SugarApiExceptionEditConflict('EXCEPTION_QUOTE_ALREADY_CONVERTED', array(), 'Quotes', 0, 'already_converted'); } // since we are creating a bunch of noise with this, we need to disable Activity Streams Activity::disable(); $this->mapQuoteToOpportunity($quote, $opportunity); $this->convertQuoteLineItemsToRevenueLineItems($quote, $opportunity); $this->linkQuoteContactsToOpportunity($quote, $opportunity); $this->linkQuoteContractsToOpportunity($quote, $opportunity); $opportunity->save(); // re-enable activity streams Activity::enable(); return array('record' => $this->formatBean($api, $args, $opportunity), 'related_record' => $this->formatBean($api, $args, $quote)); }
/** * Save repeat activities * @param SugarBean $bean * @param array $timeArray array of datetimes * @return array */ static function saveRecurring(SugarBean $bean, $timeArray) { // Here we will create single big inserting query for each invitee relationship // rather than using relationships framework due to performance issues. // Relationship framework runs very slowly $db = $GLOBALS['db']; $id = $bean->id; $date_modified = $GLOBALS['timedate']->nowDb(); $lower_name = strtolower($bean->object_name); $qu = "SELECT * FROM {$bean->rel_users_table} WHERE deleted = 0 AND {$lower_name}_id = '{$id}'"; $re = $db->query($qu); $users_rel_arr = array(); // If the bean has a users_arr then related records for those ids will have // already been created. This prevents duplicates of those records for // users, contacts and leads (handled below) $exclude_users = empty($bean->users_arr) ? array() : array_flip($bean->users_arr); while ($ro = $db->fetchByAssoc($re)) { if (!isset($exclude_users[$ro['user_id']])) { $users_rel_arr[] = $ro['user_id']; } } $qu = "SELECT * FROM {$bean->rel_contacts_table} WHERE deleted = 0 AND {$lower_name}_id = '{$id}'"; $re = $db->query($qu); $contacts_rel_arr = array(); while ($ro = $db->fetchByAssoc($re)) { $contacts_rel_arr[] = $ro['contact_id']; } $qu = "SELECT * FROM {$bean->rel_leads_table} WHERE deleted = 0 AND {$lower_name}_id = '{$id}'"; $re = $db->query($qu); $leads_rel_arr = array(); while ($ro = $db->fetchByAssoc($re)) { $leads_rel_arr[] = $ro['lead_id']; } $qu_contacts = array(); $qu_users = array(); $qu_leads = array(); $arr = array(); $i = 0; Activity::disable(); $clone = clone $bean; //this is a new bean being created - so throw away cloned fetched_row //attribute that incorrectly makes it look like an existing bean $clone->fetched_row = false; foreach ($timeArray as $date_start) { $clone->id = ""; $clone->date_start = $date_start; // TODO CHECK DATETIME VARIABLE $date = SugarDateTime::createFromFormat($GLOBALS['timedate']->get_date_time_format(), $date_start); $date = $date->get("+{$bean->duration_hours} Hours")->get("+{$bean->duration_minutes} Minutes"); $date_end = $date->format($GLOBALS['timedate']->get_date_time_format()); $clone->date_end = $date_end; $clone->recurring_source = "Sugar"; $clone->repeat_parent_id = $id; $clone->update_vcal = false; $clone->save(false); if ($clone->id) { foreach ($users_rel_arr as $user_id) { $qu_users[] = array('id' => create_guid(), 'user_id' => $user_id, $lower_name . '_id' => $clone->id, 'date_modified' => $date_modified); } foreach ($contacts_rel_arr as $contact_id) { $qu_contacts[] = array('id' => create_guid(), 'contact_id' => $contact_id, $lower_name . '_id' => $clone->id, 'date_modified' => $date_modified); } foreach ($leads_rel_arr as $lead_id) { $qu_leads[] = array('id' => create_guid(), 'lead_id' => $lead_id, $lower_name . '_id' => $clone->id, 'date_modified' => $date_modified); } if ($i < 44) { $clone->date_start = $date_start; $clone->date_end = $date_end; $arr[] = array_merge(array('id' => $clone->id), CalendarUtils::get_time_data($clone)); } $i++; } } Activity::enable(); if (!empty($qu_users)) { $fields = array('id' => array('name' => 'id', 'type' => 'id'), 'user_id' => array('name' => 'user_id', 'type' => 'id'), $lower_name . '_id' => array('name' => $lower_name . '_id', 'type' => 'id'), 'date_modified' => array('name' => 'date_modified', 'type' => 'datetime')); foreach ($qu_users as $qu_user) { $db->insertParams($bean->rel_users_table, $fields, $qu_user); } } if (!empty($qu_contacts)) { $fields = array('id' => array('name' => 'id', 'type' => 'id'), 'contact_id' => array('name' => 'contact_id', 'type' => 'id'), $lower_name . '_id' => array('name' => $lower_name . '_id', 'type' => 'id'), 'date_modified' => array('name' => 'date_modified', 'type' => 'datetime')); foreach ($qu_contacts as $qu_contact) { $db->insertParams($bean->rel_contacts_table, $fields, $qu_contact); } } if (!empty($qu_leads)) { $fields = array('id' => array('name' => 'id', 'type' => 'id'), 'lead_id' => array('name' => 'lead_id', 'type' => 'id'), $lower_name . '_id' => array('name' => $lower_name . '_id', 'type' => 'id'), 'date_modified' => array('name' => 'date_modified', 'type' => 'datetime')); foreach ($qu_leads as $qu_lead) { $db->insertParams($bean->rel_leads_table, $fields, $qu_lead); } } vCal::cache_sugar_vcal($GLOBALS['current_user']); return $arr; }
foreach ($failarr as $failure) { echo $failure . "\n<BR>\n"; } if (empty($failarr)) { echo "{$mod_strings_users['LBL_REASS_NONE']}\n<BR>\n"; } } else { echo "{$mod_strings_users['LBL_REASS_UPDATE_COMPLETE']}\n<BR>\n"; echo " " . count($successarr) . " {$mod_strings_users['LBL_REASS_SUCCESSFUL']}\n<BR>\n"; echo " " . count($failarr) . " {$mod_strings_users['LBL_REASS_FAILED']}\n"; } echo "<BR>\n"; } echo "</td></tr></table>\n"; } Activity::enable(); echo "<BR><input type=button class=\"button\" value=\"{$mod_strings_users['LBL_REASS_BUTTON_RETURN']}\" onclick='document.location=\"index.php?module=Users&action=reassignUserRecords\"'>\n"; /////////////////// END STEP 3 - Execute reassignment /////////////////////// } } } if (!empty($quicksearch_js)) { //rrs - bug: 31056 - move to end to allow for form field to render echo $quicksearch_js; } ?> <script type="text/javascript"> function clearCurrentRecords() { var callback = {
/** * This function should be overridden in each module. It marks an item as deleted. * * If it is not overridden, then marking this type of item is not allowed */ public function mark_deleted($id) { global $current_user; $date_modified = $GLOBALS['timedate']->nowDb(); if (isset($_SESSION['show_deleted'])) { $this->mark_undeleted($id); } else { // Ensure that Activity Messages do not occur in the context of a Delete action (e.g. unlink) // and do so for all nested calls within the Top Level Delete Context $opflag = static::enterOperation('delete'); $aflag = Activity::isEnabled(); Activity::disable(); // call the custom business logic $custom_logic_arguments['id'] = $id; $this->call_custom_logic("before_delete", $custom_logic_arguments); $this->deleted = 1; $this->mark_relationships_deleted($id); if (isset($this->field_defs['modified_user_id'])) { if (!empty($current_user)) { $this->modified_user_id = $current_user->id; } else { $this->modified_user_id = 1; } $query = "UPDATE {$this->table_name} set deleted=1, date_modified = '{$date_modified}',\n modified_user_id = '{$this->modified_user_id}' where id='{$id}'"; if ($this->isFavoritesEnabled()) { SugarFavorites::markRecordDeletedInFavorites($id, $date_modified, $this->modified_user_id); } } else { $query = "UPDATE {$this->table_name} set deleted=1 , date_modified = '{$date_modified}' where id='{$id}'"; if ($this->isFavoritesEnabled()) { SugarFavorites::markRecordDeletedInFavorites($id, $date_modified); } } $this->db->query($query, true, "Error marking record deleted: "); // Take the item off the recently viewed lists $tracker = BeanFactory::getBean('Trackers'); $tracker->makeInvisibleForAll($id); require_once 'include/SugarSearchEngine/SugarSearchEngineFactory.php'; $searchEngine = SugarSearchEngineFactory::getInstance(); $searchEngine->delete($this); SugarRelationship::resaveRelatedBeans(); // call the custom business logic $this->call_custom_logic("after_delete", $custom_logic_arguments); if (static::leaveOperation('delete', $opflag) && $aflag) { Activity::enable(); } } }
/** * Relates existing records to related bean. * * @param ServiceBase $api The API class of the request. * @param array $args The arguments array passed in from the API. * @return array Array of formatted fields. * @throws SugarApiExceptionNotFound If bean can't be retrieved. */ public function createRelatedLinksFromRecordList($api, $args) { Activity::disable(); $result = array('related_records' => array('success' => array(), 'error' => array())); $this->requireArgs($args, array('module', 'record', 'remote_id', 'link_name')); $primaryBean = $this->loadBean($api, $args); list($linkName) = $this->checkRelatedSecurity($api, $args, $primaryBean, 'view', 'view'); $recordList = RecordListFactory::getRecordList($args['remote_id']); $relatedBeans = $primaryBean->{$linkName}->add($recordList['records']); if ($relatedBeans === true) { $result['related_records']['success'] = $recordList['records']; } elseif (is_array($relatedBeans)) { $result['related_records']['success'] = array_diff($recordList['records'], $relatedBeans); $result['related_records']['error'] = $relatedBeans; } SugarRelationship::resaveRelatedBeans(); Activity::enable(); $result['record'] = $this->formatBean($api, $args, $primaryBean); return $result; }
public function import() { $aflag = Activity::isEnabled(); Activity::disable(); // do we have a currency_id field $this->currencyFieldPosition = array_search('currency_id', $this->importColumns); //catch output including notices and warnings so import process can run to completion $output = ''; ob_start(); foreach ($this->importSource as $row) { $this->importRow($row); } //if any output was produced, then display it as an error. //first, replace more than one consecutive spaces with a single space. This is to condense //multiple line/row errors and prevent miscount of rows in list navigation UI $output = ob_get_clean(); if (!empty($output)) { $output = preg_replace('/\\s+/', ' ', trim($output)); $this->importSource->writeError('Execution', 'Execution Error', $output); } // save mapping if requested if (isset($_REQUEST['save_map_as']) && $_REQUEST['save_map_as'] != '') { $this->saveMappingFile(); } $this->importSource->writeStatus(); if ($aflag) { Activity::enable(); } //All done, remove file. }
/** * @param string $data The job data set for this particular Scheduled Job instance * @return boolean true if the run succeeded; false otherwise */ public function run($data) { $settings = Opportunity::getSettings(); if (isset($settings['opps_view_by']) && $settings['opps_view_by'] !== 'Opportunities') { $GLOBALS['log']->fatal("Opportunity are being used with Revenue Line Items. " . __CLASS__ . " should not be running"); return false; } $args = json_decode(html_entity_decode($data), true); $this->job->runnable_ran = true; $labels = $args['labels']; $data = $args['chunk']; $currencies = array(); Activity::disable(); // disable the fts index as well /* @var $ftsSearch SugarSearchEngineElastic */ $ftsSearch = SugarSearchEngineFactory::getInstance(); $ftsSearch->setForceAsyncIndex(true); foreach ($data as $opp_id => $rli_data) { /* @var $opp Opportunity */ $opp = BeanFactory::getBean('Opportunities', $opp_id); /* @var $note Note */ $note = BeanFactory::getBean('Notes'); $note->parent_id = $opp_id; $note->parent_type = 'Opportunities'; $note->assigned_user_id = $opp->assigned_user_id; $note->created_by = $opp->created_by; $note->name = 'Previous Associated Revenue Line Items'; $desc = ''; foreach ($rli_data as $rli) { $desc .= $rli['name'] . "\n"; foreach ($rli as $field => $value) { if (isset($labels[$field])) { if ($field === 'currency_id') { if (!isset($currencies[$value])) { $currencies[$value] = SugarCurrency::getCurrencyByID($value); } $desc .= " - " . $labels[$field] . ": " . $currencies[$value]->name . "\n"; } elseif ($field !== 'name' && $field !== 'opportunity_id') { $desc .= " - " . $labels[$field] . ": " . $value . "\n"; } } } $desc .= "\n\n"; } $note->description = trim($desc); $note->save(); } // set it back to the default value from the config. $ftsSearch->setForceAsyncIndex(SugarConfig::getInstance()->get('search_engine.force_async_index', false)); Activity::enable(); $this->job->succeedJob(); $this->notifyAssignedUser(); return true; }
/** * Process the chunks of opportunities to create related Revenue Line Items * * - This always sets commit_stage to empty since forecasts is not setup any more. * * @param array $data */ public static function processOpportunityIds(array $data) { Activity::disable(); // disable the fts index as well /* @var $ftsSearch SugarSearchEngineElastic */ $ftsSearch = SugarSearchEngineFactory::getInstance(); $ftsSearch->setForceAsyncIndex(true); foreach ($data as $db_opp) { /* @var $opp Opportunity */ $opp = BeanFactory::getBean('Opportunities', $db_opp['id']); if ($opp->id === $db_opp['id']) { /* @var $rli RevenueLineItem */ $rli = BeanFactory::getBean('RevenueLineItems'); $rli->update_modified_by = false; $rli->set_created_by = false; $rli->name = $opp->name; $rli->best_case = $opp->best_case; $rli->likely_case = $opp->amount; $rli->worst_case = $opp->worst_case; $rli->cost_price = $opp->amount; $rli->quantity = 1; $rli->currency_id = $opp->currency_id; $rli->base_rate = $opp->base_rate; $rli->probability = $opp->probability; $rli->date_closed = $opp->date_closed; $rli->date_closed_timestamp = $opp->date_closed_timestamp; $rli->assigned_user_id = $opp->assigned_user_id; $rli->modified_user_id = $opp->modified_user_id; $rli->modified_by_name = $opp->modified_by_name; $rli->created_by = $opp->created_by; $rli->created_by_name = $opp->created_by_name; $rli->account_id = $opp->account_id; $rli->commit_stage = ''; $rli->sales_stage = $opp->sales_stage; $rli->deleted = $opp->deleted; $rli->save(); // set the relationship up correctly $rli->load_relationship('opportunities'); $rli->opportunities->add($opp->id); } } // set it back to the default value from the config. $ftsSearch->setForceAsyncIndex(SugarConfig::getInstance()->get('search_engine.force_async_index', false)); Activity::enable(); }
/** * Actually do the work of assigning a quota from the worksheets * * @param string $quota The amount of the quota * @param string $type What type is the quota * @param string $user_id Who is the quota for * @param string $timeperiod_id What timeperiod is the quota for * @param bool $disableActivityStream Should we disable activity streams and create our own entry */ protected function _assignQuota($quota, $type, $user_id, $timeperiod_id, $disableActivityStream = false) { if ($disableActivityStream) { Activity::disable(); $current_quota = $this->getQuota($user_id, $timeperiod_id, $type); } // get the updated quota back, this is needed because current_quota might be empty // as it could very well not exist yet. $quota = $this->commitQuota($quota, $user_id, $timeperiod_id, $type); $new_quota = $this->recalcQuotas($user_id, $timeperiod_id, true); if ($disableActivityStream) { Activity::enable(); if ($new_quota !== $current_quota->amount) { $args = array('isUpdate' => !empty($current_quota->amount), 'dataChanges' => array('amount' => array('field_name' => 'amount', 'field_type' => 'currency', 'before' => $current_quota->amount, 'after' => $new_quota))); // Manually Create the Activity Stream Entry! SugarAutoLoader::load('modules/ActivityStream/Activities/ActivityQueueManager.php'); $aqm = new ActivityQueueManager(); $aqm->eventDispatcher($quota, 'after_save', $args); } } }