Edit file File name : AOW_WorkFlow.php Content :<?php /** * Advanced OpenWorkflow, Automating SugarCRM. * @package Advanced OpenWorkflow for SugarCRM * @copyright SalesAgility Ltd http://www.salesagility.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with this program; if not, see http://www.gnu.org/licenses * or write to the Free Software Foundation,Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301 USA * * @author SalesAgility <info@salesagility.com> */ class AOW_WorkFlow extends Basic { var $new_schema = true; var $module_dir = 'AOW_WorkFlow'; var $object_name = 'AOW_WorkFlow'; var $table_name = 'aow_workflow'; var $importable = false; var $disable_row_level_security = true ; var $id; var $name; var $date_entered; var $date_modified; var $modified_user_id; var $modified_by_name; var $created_by; var $created_by_name; var $description; var $deleted; var $created_by_link; var $modified_user_link; var $assigned_user_id; var $assigned_user_name; var $assigned_user_link; var $flow_module; var $status; var $run_when; public function __construct($init=true){ parent::__construct(); if($init){ $this->load_flow_beans(); require_once('modules/AOW_WorkFlow/aow_utils.php'); } } /** * @deprecated deprecated since version 7.6, PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code, use __construct instead */ public function AOW_WorkFlow($init=true){ $deprecatedMessage = 'PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code'; if(isset($GLOBALS['log'])) { $GLOBALS['log']->deprecated($deprecatedMessage); } else { trigger_error($deprecatedMessage, E_USER_DEPRECATED); } self::__construct($init); } function bean_implements($interface){ switch($interface){ case 'ACL': return true; } return false; } function save($check_notify = FALSE){ if (empty($this->id)){ unset($_POST['aow_conditions_id']); unset($_POST['aow_actions_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_'); } function load_flow_beans(){ global $beanList, $app_list_strings; $app_list_strings['aow_moduleList'] = $app_list_strings['moduleList']; if(!empty($app_list_strings['aow_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 */ 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') "); foreach($flows as $flow){ $flow->run_flow(); } return true; } /** * Retrieve the beans to actioned and run the actions */ 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 */ function run_bean_flows(SugarBean &$bean){ if(!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 */ function get_flow_beans(){ global $beanList; if($beanList[$this->flow_module]){ $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; } function build_flow_query_join($name, SugarBean $module, $type, $query = array()){ if(!isset($query['join'][$name])){ switch ($type){ case 'custom': $query['join'][$name] = 'LEFT JOIN '.$module->get_custom_table_name().' '.$name.' ON '.$module->table_name.'.id = '. $name.'.id_c '; break; case 'relationship': 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'"; } break; default: break; } } return $query; } function build_flow_query_where($query = array()){ global $beanList; if($beanList[$this->flow_module]){ $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': $query['where'][] = $module->table_name . '.' . 'date_entered' . ' > ' . "'" .$this->date_entered."'"; Break; case'Modified_Records': $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){ $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; } 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_query_join($rel, $condition_module, 'relationship', $query); $condition_module = new $beanList[getRelatedModule($condition_module->module_dir,$rel)]; $table_alias = $rel; } } if(isset($app_list_strings['aow_sql_operator_list'][$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_query_join($table_alias.'_cstm', $condition_module, 'custom', $query); } else { $field = $table_alias.'.'.$condition->field; } if($condition->operator == 'is_null'){ $query['where'][] = '('.$field.' '.$app_list_strings['aow_sql_operator_list'][$condition->operator].' OR '.$field.' '.$app_list_strings['aow_sql_operator_list']['Equal_To']." '')"; return $query; } switch($condition->value_type) { case 'Field': $data = $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_query_join($module->table_name.'_cstm', $module, 'custom', $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[0] == 'now'){ if($sugar_config['dbconfig']['db_type'] == 'mssql'){ $value = 'GetUTCDate()'; } else { $value = 'UTC_TIMESTAMP()'; } } else if($params[0] == 'today'){ if($sugar_config['dbconfig']['db_type'] == 'mssql'){ //$field = $value = 'CAST(GETDATE() AS DATE)'; } else { $field = 'DATE('.$field.')'; $value = 'Curdate()'; } } else { $data = $module->field_defs[$params[0]]; if( (isset($data['source']) && $data['source'] == 'custom_fields')) { $value = $module->table_name.'_cstm.'.$params[0]; $query = $this->build_flow_query_join($module->table_name.'_cstm', $module, 'custom', $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'; default: if($sugar_config['dbconfig']['db_type'] == 'mssql'){ $value = "DATEADD(".$params[3].", ".$app_list_strings['aow_date_operator'][$params[1]]." $params[2], $value)"; } else { $value = "DATE_ADD($value, INTERVAL ".$app_list_strings['aow_date_operator'][$params[1]]." $params[2] ".$params[3].")"; } 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.' '.$app_list_strings['aow_sql_operator_list'][$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.' '.$app_list_strings['aow_sql_operator_list'][$condition->operator].' '.$value; } return $query; } function check_valid_bean(SugarBean &$bean){ global $app_list_strings, $timedate; 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'){ //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){ // database time correction with the user's time-zoneqq $beanDateEnteredTimestamp = strtotime($timedate->asUser(new DateTime($timedate->fromDb($bean->date_entered)))); $beanDateModifiedTimestamp = strtotime($timedate->asUser(new DateTime($timedate->fromDb($bean->date_modified)))); $thisDateEnteredTimestamp = strtotime($this->date_entered); switch($this->flow_run_on){ case'New_Records': // it is an invalid bean if the user modify it now because the affection need on new records only! if(!empty($bean->fetched_row) || $beanDateEnteredTimestamp < $thisDateEnteredTimestamp) { return false; } Break; case'Modified_Records': // it isn't a valid bean if the user create it now because the affection need on already exists records only! if(empty($bean->fetched_row) || ($beanDateModifiedTimestamp < $thisDateEnteredTimestamp && $beanDateModifiedTimestamp != $beanDateEnteredTimestamp)) { 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(isset($app_list_strings['aow_sql_operator_list'][$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': $value = $condition_bean->fetched_row[$condition->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'); } 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'; 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; } case 'Value': default: if(in_array($data['type'],$dateFields) && trim($value) != '') { $value = strtotime($value); } 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; } 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; } else 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; } else return !in_array($var1,$var2); case "Equal_To": default: return $var1 == $var2; } } 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 */ 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'); } 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; } } ?> Save