grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026'; $sqlOperatorList['Less_Than'] = '<'; $sqlOperatorList['Greater_Than_or_Equal_To'] = '>='; $sqlOperatorList['Less_Than_or_Equal_To'] = '<='; $sqlOperatorList['Contains'] = 'LIKE'; $sqlOperatorList['Starts_With'] = 'LIKE'; $sqlOperatorList['Ends_With'] = 'LIKE'; $sqlOperatorList['is_null'] = 'IS NULL'; if (!isset($sqlOperatorList[$key])) { return false; } return $sqlOperatorList[$key]; } /** * check an SQL operator is exists * @param $key name of SQL operator * @return bool true if operator exists otherwise false */ private function isSQLOperator($key) { return $this->getSQLOperator($key) ? true : false; } /** * AOW_WorkFlow constructor. * @param bool $init */ public function __construct($init = true) { parent::__construct(); if ($init) { $this->load_flow_beans(); require_once('modules/AOW_WorkFlow/aow_utils.php'); } } /** * @param $interface * @return bool */ public function bean_implements($interface) { switch ($interface) { case 'ACL': return true; } return false; } public function save($check_notify = false) { if (empty($this->id) || (isset($_POST['duplicateSave']) && $_POST['duplicateSave'] == 'true')) { unset($_POST['aow_conditions_id']); unset($_POST['aow_actions_id']); } $return_id = parent::save($check_notify); require_once('modules/AOW_Conditions/AOW_Condition.php'); $condition = new AOW_Condition(); $condition->save_lines($_POST, $this, 'aow_conditions_'); require_once('modules/AOW_Actions/AOW_Action.php'); $action = new AOW_Action(); $action->save_lines($_POST, $this, 'aow_actions_'); return $return_id; } public function load_flow_beans() { global $beanList, $app_list_strings; if (!empty($app_list_strings['moduleList'])) { $app_list_strings['aow_moduleList'] = $app_list_strings['moduleList']; foreach ($app_list_strings['aow_moduleList'] as $mkey => $mvalue) { if (!isset($beanList[$mkey]) || str_begin($mkey, 'AOW_')) { unset($app_list_strings['aow_moduleList'][$mkey]); } } } $app_list_strings['aow_moduleList'] = array_merge((array)array(''=>''), (array)$app_list_strings['aow_moduleList']); asort($app_list_strings['aow_moduleList']); } /** * Select and run all active flows * @return bool */ public function run_flows() { $flows = AOW_WorkFlow::get_full_list('', " aow_workflow.status = 'Active' AND (aow_workflow.run_when = 'Always' OR aow_workflow.run_when = 'In_Scheduler' OR aow_workflow.run_when = 'Create') "); if (empty($flows)) { LoggerManager::getLogger()->warn('There is no any workflow to run'); } foreach ((array)$flows as $flow) { $flow->run_flow(); } return true; } /** * Retrieve the beans to actioned and run the actions */ public function run_flow() { $beans = $this->get_flow_beans(); if (!empty($beans)) { foreach ($beans as $bean) { $bean->retrieve($bean->id); $this->run_actions($bean); } } } /** * Select and run all active flows for the specified bean */ public function run_bean_flows(SugarBean $bean) { if (!defined('SUGARCRM_IS_INSTALLING') && (!isset($_REQUEST['module']) || $_REQUEST['module'] != 'Import')) { $query = "SELECT id FROM aow_workflow WHERE aow_workflow.flow_module = '" . $bean->module_dir . "' AND aow_workflow.status = 'Active' AND (aow_workflow.run_when = 'Always' OR aow_workflow.run_when = 'On_Save' OR aow_workflow.run_when = 'Create') AND aow_workflow.deleted = 0 "; $result = $this->db->query($query, false); $flow = new AOW_WorkFlow(); while (($row = $bean->db->fetchByAssoc($result)) != null) { $flow->retrieve($row['id']); if ($flow->check_valid_bean($bean)) { $flow->run_actions($bean, true); } } } return true; } /** * Use the condition statements and processed table to build query to retrieve beans to be actioned */ public function get_flow_beans() { global $beanList; $flowModule = null; if (isset($beanList[$this->flow_module])) { $flowModule = $beanList[$this->flow_module]; } else { LoggerManager::getLogger()->warn('Undefined flow module in bean list: ' . $this->flow_module); } if ($flowModule) { $module = new $beanList[$this->flow_module](); $query = ''; $query_array = array(); $query_array['select'][] = $module->table_name.".id AS id"; $query_array = $this->build_flow_query_where($query_array); if (!empty($query_array)) { foreach ($query_array['select'] as $select) { $query .= ($query == '' ? 'SELECT ' : ', ').$select; } $query .= ' FROM '.$module->table_name.' '; if (isset($query_array['join'])) { foreach ($query_array['join'] as $join) { $query .= $join; } } if (isset($query_array['where'])) { $query_where = ''; foreach ($query_array['where'] as $where) { $query_where .= ($query_where == '' ? 'WHERE ' : ' AND ').$where; } $query .= ' '.$query_where; } return $module->process_full_list_query($query); } } return null; } public function build_flow_custom_query_join( $name, $custom_name, SugarBean $module, $query = array() ) { if (!isset($query['join'][$custom_name])) { $query['join'][$custom_name] = 'LEFT JOIN '.$module->get_custom_table_name() .' '.$custom_name.' ON '.$name.'.id = '. $custom_name.'.id_c '; } return $query; } public function build_flow_relationship_query_join( $name, SugarBean $module, $query = array() ) { if (!isset($query['join'][$name])) { if ($module->load_relationship($name)) { $params['join_type'] = 'LEFT JOIN'; $params['join_table_alias'] = $name; $join = $module->$name->getJoin($params, true); $query['join'][$name] = $join['join']; $query['select'][] = $join['select']." AS '".$name."_id'"; } } return $query; } public function build_flow_query_where($query = array()) { global $beanList; $flowModule = null; if (isset($beanList[$this->flow_module])) { $flowModule = $beanList[$this->flow_module]; } else { LoggerManager::getLogger()->warn('Undefined flow module in bean list: ' . $this->flow_module); } if ($flowModule) { $module = new $beanList[$this->flow_module](); $sql = "SELECT id FROM aow_conditions WHERE aow_workflow_id = '".$this->id."' AND deleted = 0 ORDER BY condition_order ASC"; $result = $this->db->query($sql); while ($row = $this->db->fetchByAssoc($result)) { $condition = new AOW_Condition(); $condition->retrieve($row['id']); $query = $this->build_query_where($condition, $module, $query); if (empty($query)) { return $query; } } if ($this->flow_run_on) { switch ($this->flow_run_on) { case'New_Records': if ($module->table_name === 'campaign_log') { $query['where'][] = $module->table_name . '.' . 'activity_date' . ' > ' . "'" . $this->activity_date . "'"; } else { $query['where'][] = $module->table_name . '.' . 'date_entered' . ' > ' . "'" . $this->date_entered . "'"; } break; case'Modified_Records': if ($module->table_name === 'campaign_log') { $query['where'][] = $module->table_name . '.' . 'date_modified' . ' > ' . "'" . $this->activity_date . "'" . ' AND ' . $module->table_name . '.' . 'activity_date' . ' <> ' . $module->table_name . '.' . 'date_modified'; } else { $query['where'][] = $module->table_name . '.' . 'date_modified' . ' > ' . "'" . $this->date_entered . "'" . ' AND ' . $module->table_name . '.' . 'date_entered' . ' <> ' . $module->table_name . '.' . 'date_modified'; } break; } } if (!$this->multiple_runs) { if (!isset($query['where'])) { LoggerManager::getLogger()->warn('Undefined index: where'); $query['where'] = []; } $query['where'][] .= "NOT EXISTS (SELECT * FROM aow_processed WHERE aow_processed.aow_workflow_id='".$this->id."' AND aow_processed.parent_id=".$module->table_name.".id AND aow_processed.status = 'Complete' AND aow_processed.deleted = 0)"; } $query['where'][] = $module->table_name.".deleted = 0 "; } return $query; } public function build_query_where(AOW_Condition $condition, $module, $query = array()) { global $beanList, $app_list_strings, $sugar_config, $timedate; $path = unserialize(base64_decode($condition->module_path)); $condition_module = $module; $table_alias = $condition_module->table_name; if (isset($path[0]) && $path[0] != $module->module_dir) { foreach ($path as $rel) { $query = $this->build_flow_relationship_query_join( $rel, $condition_module, $query ); $condition_module = new $beanList[getRelatedModule($condition_module->module_dir, $rel)]; $table_alias = $rel; } } if ($this->isSQLOperator($condition->operator)) { $where_set = false; $data = $condition_module->field_defs[$condition->field]; if ($data['type'] == 'relate' && isset($data['id_name'])) { $condition->field = $data['id_name']; } if ((isset($data['source']) && $data['source'] == 'custom_fields')) { $field = $table_alias.'_cstm.'.$condition->field; $query = $this->build_flow_custom_query_join( $table_alias, $table_alias.'_cstm', $condition_module, $query ); } else { $field = $table_alias.'.'.$condition->field; } if ($condition->operator == 'is_null') { $query['where'][] = '('.$field.' '.$this->getSQLOperator($condition->operator).' OR '.$field.' '.$this->getSQLOperator('Equal_To')." '')"; return $query; } switch ($condition->value_type) { case 'Field': $data = null; if (isset($module->field_defs[$condition->value])) { $data = $module->field_defs[$condition->value]; } else { LoggerManager::getLogger()->warn('Undefined field def for condition value in module: ' . get_class($module) . '::field_defs[' . $condition->value . ']'); } if ($data['type'] == 'relate' && isset($data['id_name'])) { $condition->value = $data['id_name']; } if ((isset($data['source']) && $data['source'] == 'custom_fields')) { $value = $module->table_name.'_cstm.'.$condition->value; $query = $this->build_flow_custom_query_join( $module->table_name, $module->table_name.'_cstm', $module, $query ); } else { $value = $module->table_name.'.'.$condition->value; } break; case 'Any_Change': //can't detect in scheduler so return return array(); case 'Date': $params = @unserialize(base64_decode($condition->value)); if ($params === false) { LoggerManager::getLogger()->error('Unserializable data given'); $params = [null]; } if ($params[0] == 'now') { if ($sugar_config['dbconfig']['db_type'] == 'mssql') { $value = 'GetUTCDate()'; } else { $value = 'UTC_TIMESTAMP()'; } } elseif (isset($params[0]) && $params[0] == 'today') { if ($sugar_config['dbconfig']['db_type'] == 'mssql') { //$field = $value = 'CAST(GETDATE() AS DATE)'; } else { $field = 'DATE('.$field.')'; $value = 'Curdate()'; } } else { if (isset($params[0]) && $params[0] == 'today') { if ($sugar_config['dbconfig']['db_type'] == 'mssql') { //$field = $value = 'CAST(GETDATE() AS DATE)'; } else { $field = 'DATE('.$field.')'; $value = 'Curdate()'; } } else { $data = null; if (isset($module->field_defs[$params[0]])) { $data = $module->field_defs[$params[0]]; } else { LoggerManager::getLogger()->warn('Filed def data is missing: ' . get_class($module) . '::$field_defs[' . $params[0] . ']'); } if ((isset($data['source']) && $data['source'] == 'custom_fields')) { $value = $module->table_name.'_cstm.'.$params[0]; $query = $this->build_flow_custom_query_join( $module->table_name, $module->table_name.'_cstm', $module, $query ); } else { $value = $module->table_name.'.'.$params[0]; } } } if ($params[1] != 'now') { switch ($params[3]) { case 'business_hours': if (file_exists('modules/AOBH_BusinessHours/AOBH_BusinessHours.php') && $params[0] == 'now') { require_once('modules/AOBH_BusinessHours/AOBH_BusinessHours.php'); $businessHours = new AOBH_BusinessHours(); $amount = $params[2]; if ($params[1] != "plus") { $amount = 0-$amount; } $value = $businessHours->addBusinessHours($amount); $value = "'".$timedate->asDb($value)."'"; break; } //No business hours module found - fall through. $params[3] = 'hour'; // no break default: if ($sugar_config['dbconfig']['db_type'] == 'mssql') { $value = "DATEADD(".$params[3].", ".$app_list_strings['aow_date_operator'][$params[1]]." $params[2], $value)"; } else { if (!isset($params)) { LoggerManager::getLogger()->warn('Undefined variable: param'); $params = [null, null, null, null]; } $params1 = $params[1]; $params2 = $params[2]; $params3 = $params[3]; $dateOp = null; if (isset($app_list_strings['aow_date_operator'][$params1])) { $dateOp = $app_list_strings['aow_date_operator'][$params1]; } else { LoggerManager::getLogger()->warn('Date operator is not set in app_list_string[' . $params1 . ']'); } $value = "DATE_ADD($value, INTERVAL ".$dateOp." $params2 ".$params3.")"; } break; } } break; case 'Multi': $sep = ' AND '; if ($condition->operator == 'Equal_To') { $sep = ' OR '; } $multi_values = unencodeMultienum($condition->value); if (!empty($multi_values)) { $value = '('; if ($data['type'] == 'multienum') { $multi_operator = $condition->operator == 'Equal_To' ? 'LIKE' : 'NOT LIKE'; foreach ($multi_values as $multi_value) { if ($value != '(') { $value .= $sep; } $value .= $field." $multi_operator '%^".$multi_value."^%'"; } } else { foreach ($multi_values as $multi_value) { if ($value != '(') { $value .= $sep; } $value .= $field.' '.$this->getSQLOperator($condition->operator)." '".$multi_value."'"; } } $value .= ')'; $query['where'][] = $value; } $where_set = true; break; case 'SecurityGroup': $sgModule = $condition_module->module_dir; if (isset($data['module']) && $data['module'] !== '') { $sgModule = $data['module']; } $sql = 'EXISTS (SELECT 1 FROM securitygroups_records WHERE record_id = ' . $field . " AND module = '" . $sgModule . "' AND securitygroup_id = '" . $condition->value . "' AND deleted=0)"; if ($sgModule === 'Users') { $sql = 'EXISTS (SELECT 1 FROM securitygroups_users WHERE user_id = ' . $field . " AND securitygroup_id = '" . $condition->value . "' AND deleted=0)"; } $query['where'][] = $sql; $where_set = true; break; case 'Value': default: $value = "'".$condition->value."'"; break; } //handle like conditions switch ($condition->operator) { case 'Contains': $value = "CONCAT('%', ".$value." ,'%')"; break; case 'Starts_With': $value = "CONCAT(".$value." ,'%')"; break; case 'Ends_With': $value = "CONCAT('%', ".$value.")"; break; } if (!$where_set) { $query['where'][] = $field.' '.$this->getSQLOperator($condition->operator).' '.$value; } } return $query; } /** * @param SugarBean $bean * @return bool */ public function check_valid_bean(SugarBean $bean) { global $app_list_strings, $timedate; if (!$this->multiple_runs) { $processed = BeanFactory::getBean('AOW_Processed'); $processed->retrieve_by_string_fields(array('aow_workflow_id' => $this->id, 'parent_id' => $bean->id)); if ($processed->status === 'Complete') { //has already run so return false return false; } } if (!isset($bean->date_entered)) { $bean->date_entered = $bean->fetched_row['date_entered']; } if ($this->flow_run_on) { $dateEntered = $timedate->fromUserType($this->date_entered, 'datetime') ?: $timedate->fromDbType($this->date_entered, 'datetime'); $beanDateEntered = $timedate->fromUserType($bean->date_entered, 'datetime') ?: $timedate->fromDbType($bean->date_entered, 'datetime'); $beanDateModified = $timedate->fromUserType($bean->date_modified, 'datetime') ?: $timedate->fromDbType($bean->date_modified, 'datetime'); switch ($this->flow_run_on) { case'New_Records': if (!empty($bean->fetched_row) || $beanDateEntered < $dateEntered) { return false; } break; case'Modified_Records': if (empty($bean->fetched_row) || ($beanDateModified < $dateEntered && $beanDateModified !== $beanDateEntered)) { return false; } break; } } $sql = "SELECT id FROM aow_conditions WHERE aow_workflow_id = '".$this->id."' AND deleted = 0 ORDER BY condition_order ASC"; $result = $this->db->query($sql); $query_array = array(); while ($row = $this->db->fetchByAssoc($result)) { $condition = new AOW_Condition(); $condition->retrieve($row['id']); $path = unserialize(base64_decode($condition->module_path)); $condition_bean = $bean; if (isset($path[0]) && $path[0] != $bean->module_dir) { $query_array = $this->build_query_where($condition, $condition_bean, $query_array); continue; } $field = $condition->field; $value = $condition->value; $dateFields = array('date','datetime', 'datetimecombo'); if ($this->isSQLOperator($condition->operator)) { $data = $condition_bean->field_defs[$field]; if ($data['type'] === 'relate' && isset($data['id_name'])) { $field = $data['id_name']; $condition->field = $data['id_name']; } $field = $condition_bean->$field; if (in_array($data['type'], $dateFields)) { $field = strtotime($field); } switch ($condition->value_type) { case 'Field': $data = $condition_bean->field_defs[$value]; if ($data['type'] === 'relate' && isset($data['id_name'])) { $value = $data['id_name']; } $value = $condition_bean->$value; if (in_array($data['type'], $dateFields)) { $value = strtotime($value); } break; case 'Any_Change': if ($data['type'] === 'relate' && isset($data['name']) && isset($condition_bean->rel_fields_before_value[$condition->field])) { $value = $condition_bean->rel_fields_before_value[$condition->field]; } else { $value = from_html($condition_bean->fetched_row[$condition->field]); // Bug - on delete bean action CRM load bean in a different way and bean can contain html characters $field = from_html($field); } if (in_array($data['type'], $dateFields)) { $value = strtotime($value); } switch ($condition->operator) { case 'Not_Equal_To': $condition->operator = 'Equal_To'; break; case 'Equal_To': default: $condition->operator = 'Not_Equal_To'; break; } break; case 'Date': $params = unserialize(base64_decode($value)); $dateType = 'datetime'; if ($params[0] == 'now') { $value = date('Y-m-d H:i:s'); } elseif ($params[0] == 'today') { $dateType = 'date'; $value = date('Y-m-d'); $field = strtotime(date('Y-m-d', $field)); } else { if ($params[0] == 'today') { $dateType = 'date'; $value = date('Y-m-d'); $field = strtotime(date('Y-m-d', $field)); } else { $fieldName = $params[0]; $value = $condition_bean->$fieldName; } } if ($params[1] != 'now') { switch ($params[3]) { case 'business_hours': if (file_exists('modules/AOBH_BusinessHours/AOBH_BusinessHours.php')) { require_once('modules/AOBH_BusinessHours/AOBH_BusinessHours.php'); $businessHours = new AOBH_BusinessHours(); $amount = $params[2]; if ($params[1] != "plus") { $amount = 0-$amount; } $value = $businessHours->addBusinessHours($amount, $timedate->fromDb($value)); $value = strtotime($timedate->asDbType($value, $dateType)); break; } //No business hours module found - fall through. $params[3] = 'hours'; // no break default: $value = strtotime($value.' '.$app_list_strings['aow_date_operator'][$params[1]]." $params[2] ".$params[3]); if ($dateType == 'date') { $value = strtotime(date('Y-m-d', $value)); } break; } } else { $value = strtotime($value); } break; case 'Multi': $value = unencodeMultienum($value); if ($data['type'] == 'multienum') { $field = unencodeMultienum($field); } switch ($condition->operator) { case 'Not_Equal_To': $condition->operator = 'Not_One_of'; break; case 'Equal_To': default: $condition->operator = 'One_of'; break; } break; case 'SecurityGroup': if (file_exists('modules/SecurityGroups/SecurityGroup.php')) { $sg_module = $condition_bean->module_dir; if (isset($data['module']) && $data['module'] != '') { $sg_module = $data['module']; } $value = $this->check_in_group($field, $sg_module, $value); $field = true; break; } // no break case 'Value': default: if (in_array($data['type'], $dateFields) && trim($value) != '') { $value = strtotime($value); } elseif ($data['type'] == 'bool' && (!boolval($value) || strtolower($value) == 'false')) { $value = 0; } break; } if (!($this->compare_condition($field, $value, $condition->operator))) { return false; } } } if (isset($query_array['where'])) { $query = 'SELECT '.$bean->table_name.'.id AS id FROM '.$bean->table_name.' '; if (isset($query_array['join'])) { foreach ($query_array['join'] as $join) { $query .= $join; } } $query_where = ''; $query_array['where'][] = $bean->table_name.'.id = '."'".$bean->id."'"; foreach ($query_array['where'] as $where) { $query_where .= ($query_where == '' ? 'WHERE ' : ' AND ').$where; } $query .= ' '.$query_where; $rel_check = $bean->db->getOne($query); if ($rel_check == '') { return false; } } return true; } public function compare_condition($var1, $var2, $operator = 'Equal_To') { switch ($operator) { case "Not_Equal_To": return $var1 != $var2; case "Greater_Than": return $var1 > $var2; case "Less_Than": return $var1 < $var2; case "Greater_Than_or_Equal_To": return $var1 >= $var2; case "Less_Than_or_Equal_To": return $var1 <= $var2; case "Contains": return strpos($var1, $var2); case "Starts_With": return strrpos($var1, $var2, -strlen($var1)); case "Ends_With": return strpos($var1, $var2, strlen($var1) - strlen($var2)); case "is_null": return $var1 == ''; case "One_of": if (is_array($var1)) { foreach ($var1 as $var) { if (in_array($var, $var2)) { return true; } } return false; } return in_array($var1, $var2); case "Not_One_of": if (is_array($var1)) { foreach ($var1 as $var) { if (in_array($var, $var2)) { return false; } } return true; } return !in_array($var1, $var2); case "Equal_To": default: return $var1 == $var2; } } public function check_in_group($bean_id, $module, $group) { $sql = "SELECT id FROM securitygroups_records WHERE record_id = '".$bean_id."' AND module = '".$module."' AND securitygroup_id = '".$group."' AND deleted=0"; if ($module == 'Users') { $sql = "SELECT id FROM securitygroups_users WHERE user_id = '".$bean_id."' AND securitygroup_id = '".$group."' AND deleted=0"; } $id = $this->db->getOne($sql); if ($id != '') { return true; } return false; } /** * Run the actions against the passed $bean */ public function run_actions(SugarBean &$bean, $in_save = false) { require_once('modules/AOW_Processed/AOW_Processed.php'); $processed = new AOW_Processed(); if (!$this->multiple_runs) { $processed->retrieve_by_string_fields(array('aow_workflow_id' => $this->id,'parent_id' => $bean->id)); if ($processed->status == 'Complete') { //should not have gotten this far, so return return true; } } $processed->aow_workflow_id = $this->id; $processed->parent_id = $bean->id; $processed->parent_type = $bean->module_dir; $processed->status = 'Running'; $processed->save(false); $processed->load_relationship('aow_actions'); $pass = true; $sql = "SELECT id FROM aow_actions WHERE aow_workflow_id = '".$this->id."' AND deleted = 0 ORDER BY action_order ASC"; $result = $this->db->query($sql); while ($row = $this->db->fetchByAssoc($result)) { $action = new AOW_Action(); $action->retrieve($row['id']); if ($this->multiple_runs || !$processed->db->getOne("select id from aow_processed_aow_actions where aow_processed_id = '".$processed->id."' AND aow_action_id = '".$action->id."' AND status = 'Complete'")) { $action_name = 'action'.$action->action; if (file_exists('custom/modules/AOW_Actions/actions/'.$action_name.'.php')) { require_once('custom/modules/AOW_Actions/actions/'.$action_name.'.php'); } elseif (file_exists('modules/AOW_Actions/actions/'.$action_name.'.php')) { require_once('modules/AOW_Actions/actions/'.$action_name.'.php'); } else { if (file_exists('modules/AOW_Actions/actions/'.$action_name.'.php')) { require_once('modules/AOW_Actions/actions/'.$action_name.'.php'); } else { return false; } } $custom_action_name = "custom" . $action_name; if (class_exists($custom_action_name)) { $action_name = $custom_action_name; } $flow_action = new $action_name($action->id); if (!$flow_action->run_action($bean, unserialize(base64_decode($action->parameters)), $in_save)) { $pass = false; $processed->aow_actions->add($action->id, array('status' => 'Failed')); } else { $processed->aow_actions->add($action->id, array('status' => 'Complete')); } } } if ($pass) { $processed->status = 'Complete'; } else { $processed->status = 'Failed'; } $processed->save(false); return $pass; } }