/** * This is left here for legacy, just calling the new methods * @deprecated * @param int $perJob The Number of records to put in a job * @return array|string An array of jobs ids that were created, unless * there is one, the it's just that single job id */ function updateOpportunitiesForForecasting($perJob = 100) { SugarAutoLoader::load('include/SugarQueue/jobs/SugarJobUpdateOpportunities.php'); return SugarJobUpdateOpportunities::updateOpportunitiesForForecasting($perJob); }
/** * Fix the Opportunity Data to have the correct data once we go back from having RLI's to only have Opps * * - Takes the lowest sales_stage from all the RLIs * - Takes the lowest date_closed from all the RLIs * - Sets commit_stage to empty * - Sets sales_status to empty * * This is all done via a Query since we delete all the RLI's and we didn't want to keep any of them around. * * @throws SugarQueryException */ protected function setOpportunityDataFromRevenueLineItems() { // need to figure out the best way to roll this up before truncating the table. $app_list_strings = return_app_list_strings_language($GLOBALS['current_language']); // get the sales_stage from the RLI module /* @var $rli RevenueLineItem */ $rli = BeanFactory::getBean('RevenueLineItems'); $def = $rli->getFieldDefinition('sales_stage'); $db = DBManagerFactory::getInstance(); $list_value = array(); // get the `options` param so we make sure if they customized it to use their custom version $sqlCase = ''; $list = $def['options']; if (!empty($list) && isset($app_list_strings[$list])) { $i = 0; $order_by_arr = array(); foreach ($app_list_strings[$list] as $key => $value) { $list_value[$i] = $key; if ($key == '') { $order_by_arr[] = "WHEN (sales_stage='' OR sales_stage IS NULL) THEN " . $i++; } else { $order_by_arr[] = "WHEN sales_stage=" . $db->quoted($key) . " THEN " . $i++; } } $sqlCase = "min(CASE " . implode("\n", $order_by_arr) . " ELSE {$i} END)"; } $fcsettings = Forecast::getSettings(); $stage_cases = array(); $closed_stages = array_merge($fcsettings['sales_stage_won'], $fcsettings['sales_stage_lost']); foreach ($closed_stages as $stage) { $stage_cases[] = $db->quoted($stage); } $stage_cases = implode(',', $stage_cases); $sq = new SugarQuery(); $sq->select(array('opportunity_id'))->fieldRaw($sqlCase, 'sales_stage')->fieldRaw($this->dateClosedMigration . '(CASE when sales_stage IN (' . $stage_cases . ') THEN date_closed END)', 'dc_closed')->fieldRaw($this->dateClosedMigration . '(CASE when sales_stage NOT IN (' . $stage_cases . ') THEN date_closed END)', 'dc_open')->fieldRaw($this->dateClosedMigration . '(CASE when sales_stage IN (' . $stage_cases . ') THEN date_closed_timestamp END)', 'dct_closed')->fieldRaw($this->dateClosedMigration . '(CASE when sales_stage NOT IN (' . $stage_cases . ') THEN date_closed_timestamp END)', 'dct_open'); $sq->from($rli); $sq->groupBy('opportunity_id'); $results = $sq->execute(); foreach ($results as $result) { $sql = 'UPDATE opportunities SET date_closed = ' . $db->quoted(!empty($result['dc_open']) ? $result['dc_open'] : $result['dc_closed']) . ', date_closed_timestamp = ' . $db->quoted(!empty($result['dct_open']) ? $result['dct_open'] : $result['dct_closed']) . ', sales_stage = ' . $db->quoted($list_value[$result['sales_stage']]) . ', probability = ' . $db->quoted($app_list_strings['sales_probability_dom'][$list_value[$result['sales_stage']]]) . ', sales_status = ' . $db->quoted('') . ', commit_stage = ' . $db->quoted('') . ' WHERE id = ' . $db->quoted($result['opportunity_id']); $db->query($sql); } if ($this->isForecastSetup()) { SugarAutoLoader::load('include/SugarQueue/jobs/SugarJobUpdateOpportunities.php'); SugarJobUpdateOpportunities::updateOpportunitiesForForecasting(); } }
/** * Forecast Override since we have custom logic that needs to be ran * * {@inheritdoc} */ public function forecastsConfigSave(ServiceBase $api, array $args) { //acl check, only allow if they are module admin if (!$api->user->isAdmin() && !$api->user->isDeveloperForModule('Forecasts')) { // No create access so we construct an error message and throw the exception $failed_module_strings = return_module_language($GLOBALS['current_language'], 'forecasts'); $moduleName = $failed_module_strings['LBL_MODULE_NAME']; $args = null; if (!empty($moduleName)) { $args = array('moduleName' => $moduleName); } throw new SugarApiExceptionNotAuthorized($GLOBALS['app_strings']['EXCEPTION_CHANGE_MODULE_CONFIG_NOT_AUTHORIZED'], $args); } $admin = BeanFactory::getBean('Administration'); //track what settings have changed to determine if timeperiods need rebuilt $prior_forecasts_settings = $admin->getConfigForModule('Forecasts', $api->platform); //If this is a first time setup, default prior settings for timeperiods to 0 so we may correctly recalculate //how many timeperiods to build forward and backward. If we don't do this we would need the defaults to be 0 if (empty($prior_forecasts_settings['is_setup'])) { $prior_forecasts_settings['timeperiod_shown_forward'] = 0; $prior_forecasts_settings['timeperiod_shown_backward'] = 0; } $upgraded = 0; if (!empty($prior_forecasts_settings['is_upgrade'])) { $db = DBManagerFactory::getInstance(); // check if we need to upgrade opportunities when coming from version below 6.7.x. $upgraded = $db->getOne("SELECT count(id) AS total FROM upgrade_history\n WHERE type = 'patch' AND status = 'installed' AND version LIKE '6.7.%'"); if ($upgraded == 1) { //TODO-sfa remove this once the ability to map buckets when they get changed is implemented (SFA-215). $args['has_commits'] = true; } } if (isset($args['show_custom_buckets_options'])) { $json = getJSONobj(); $_args = array('dropdown_lang' => isset($_SESSION['authenticated_user_language']) ? $_SESSION['authenticated_user_language'] : $GLOBALS['current_language'], 'dropdown_name' => 'commit_stage_custom_dom', 'view_package' => 'studio', 'list_value' => $json->encode($args['show_custom_buckets_options']), 'skip_sync' => true); $_REQUEST['view_package'] = 'studio'; require_once 'modules/ModuleBuilder/parsers/parser.dropdown.php'; $parser = new ParserDropDown(); $parser->saveDropDown($_args); unset($args['show_custom_buckets_options']); } // we do the double check here since the front ent will send one one value if the input is empty if (empty($args['worksheet_columns']) || empty($args['worksheet_columns'][0])) { // set the defaults $args['worksheet_columns'] = array('commit_stage', 'parent_name', 'likely_case'); if ($args['show_worksheet_best'] == 1) { $args['worksheet_columns'][] = 'best_case'; } if ($args['show_worksheet_worst'] == 1) { $args['worksheet_columns'][] = 'worst_case'; } } //reload the settings to get the current settings $current_forecasts_settings = parent::configSave($api, $args); // setting are saved, reload the setting in the ForecastBean just in case. Forecast::getSettings(true); // now that we have saved the setting, we need to sync all the data if // this is being upgraded or the forecast was not setup before. if ($upgraded || empty($prior_forecasts_settings['is_setup'])) { if ($args['forecast_by'] === 'Opportunities') { SugarAutoLoader::load('include/SugarQueue/jobs/SugarJobUpdateOpportunities.php'); SugarJobUpdateOpportunities::updateOpportunitiesForForecasting(); } else { SugarAutoLoader::load('include/SugarQueue/jobs/SugarJobUpdateRevenueLineItems.php'); SugarJobUpdateRevenueLineItems::scheduleRevenueLineItemUpdateJobs(); } } // did this change? if ($prior_forecasts_settings['worksheet_columns'] !== $args['worksheet_columns']) { $this->setWorksheetColumns($api, $args['worksheet_columns'], $current_forecasts_settings['forecast_by']); } //if primary settings for timeperiods have changed, then rebuild them if ($this->timePeriodSettingsChanged($prior_forecasts_settings, $current_forecasts_settings)) { $timePeriod = TimePeriod::getByType($current_forecasts_settings['timeperiod_interval']); $timePeriod->rebuildForecastingTimePeriods($prior_forecasts_settings, $current_forecasts_settings); } return $current_forecasts_settings; }