2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
38 require_once('soap/SoapHelperFunctions.php');
39 require_once('soap/SoapTypes.php');
41 /*************************************************************************************
43 THIS IS FOR SUGARCRM USERS
46 *************************************************************************************/
47 $disable_date_format = true;
51 array('session'=>'xsd:string'),
52 array('return'=>'xsd:int'),
56 * Return if the user is an admin or not
58 * @param String $session -- Session ID returned by a previous call to login.
59 * @return int 1 or 0 depending on if the user is an admin
61 function is_user_admin($session){
62 if(validate_authenticated($session)){
64 return is_admin($current_user);
74 array('user_auth'=>'tns:user_auth', 'application_name'=>'xsd:string'),
75 array('return'=>'tns:set_entry_result'),
79 * Log the user into the application
81 * @param UserAuth array $user_auth -- Set user_name and password (password needs to be
82 * in the right encoding for the type of authentication the user is setup for. For Base
83 * sugar validation, password is the MD5 sum of the plain text password.
84 * @param String $application -- The name of the application you are logging in from. (Currently unused).
85 * @return Array(session_id, error) -- session_id is the id of the session that was
86 * created. Error is set if there was any error during creation.
88 function login($user_auth, $application){
89 global $sugar_config, $system_config;
91 $error = new SoapError();
95 $system_config = new Administration();
96 $system_config->retrieveSettings('system');
97 $authController = new AuthenticationController();
99 $isLoginSuccess = $authController->login($user_auth['user_name'], $user_auth['password'], array('passwordEncrypted' => true));
100 $usr_id=$user->retrieve_user_id($user_auth['user_name']);
102 $user->retrieve($usr_id);
105 if ($isLoginSuccess) {
106 if ($_SESSION['hasExpiredPassword'] =='1') {
107 $error->set_error('password_expired');
108 $GLOBALS['log']->fatal('password expired for user ' . $user_auth['user_name']);
109 LogicHook::initialize();
110 $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed');
111 return array('id'=>-1, 'error'=>$error);
113 if(!empty($user) && !empty($user->id) && !$user->is_group) {
115 global $current_user;
116 $current_user = $user;
118 } else if($usr_id && isset($user->user_name) && ($user->getPreference('lockout') == '1')) {
119 $error->set_error('lockout_reached');
120 $GLOBALS['log']->fatal('Lockout reached for user ' . $user_auth['user_name']);
121 LogicHook::initialize();
122 $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed');
123 return array('id'=>-1, 'error'=>$error);
124 } else if(function_exists('mcrypt_cbc')){
125 $password = decrypt_string($user_auth['password']);
126 $authController = new AuthenticationController();
127 if($authController->login($user_auth['user_name'], $password) && isset($_SESSION['authenticated_user_id'])){
134 global $current_user;
135 //$current_user = $user;
137 $current_user->loadPreferences();
138 $_SESSION['is_valid_session']= true;
139 $_SESSION['ip_address'] = query_client_ip();
140 $_SESSION['user_id'] = $current_user->id;
141 $_SESSION['type'] = 'user';
142 $_SESSION['avail_modules']= get_user_module_list($current_user);
143 $_SESSION['authenticated_user_id'] = $current_user->id;
144 $_SESSION['unique_key'] = $sugar_config['unique_key'];
146 $current_user->call_custom_logic('after_login');
147 return array('id'=>session_id(), 'error'=>$error);
149 $error->set_error('invalid_login');
150 $GLOBALS['log']->fatal('SECURITY: User authentication for '. $user_auth['user_name']. ' failed');
151 LogicHook::initialize();
152 $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed');
153 return array('id'=>-1, 'error'=>$error);
157 //checks if the soap server and client are running on the same machine
161 array('return'=>'xsd:int'),
165 * Check to see if the soap server and client are on the same machine.
166 * We don't allow a server to sync to itself.
168 * @return true -- if the SOAP server and client are on the same machine
169 * @return false -- if the SOAP server and client are not on the same machine.
171 function is_loopback(){
172 if(query_client_ip() == $_SERVER['SERVER_ADDR'])
178 * Validate the provided session information is correct and current. Load the session.
180 * @param String $session_id -- The session ID that was returned by a call to login.
181 * @return true -- If the session is valid and loaded.
182 * @return false -- if the session is not valid.
184 function validate_authenticated($session_id){
185 if(!empty($session_id)){
186 session_id($session_id);
189 if(!empty($_SESSION['is_valid_session']) && is_valid_ip_address('ip_address') && $_SESSION['type'] == 'user'){
191 global $current_user;
193 $current_user = new User();
194 $current_user->retrieve($_SESSION['user_id']);
201 LogicHook::initialize();
202 $GLOBALS['log']->fatal('SECURITY: The session ID is invalid');
203 $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed');
208 * Use the same logic as in SugarAuthenticate to validate the ip address
210 * @param string $session_var
211 * @return bool - true if the ip address is valid, false otherwise.
213 function is_valid_ip_address($session_var){
214 global $sugar_config;
215 // grab client ip address
216 $clientIP = query_client_ip();
218 // check to see if config entry is present, if not, verify client ip
219 if (!isset ($sugar_config['verify_client_ip']) || $sugar_config['verify_client_ip'] == true) {
220 // check to see if we've got a current ip address in $_SESSION
221 // and check to see if the session has been hijacked by a foreign ip
222 if (isset ($_SESSION[$session_var])) {
223 $session_parts = explode(".", $_SESSION[$session_var]);
224 $client_parts = explode(".", $clientIP);
225 if(count($session_parts) < 4) {
228 // match class C IP addresses
229 for ($i = 0; $i < 3; $i ++) {
230 if ($session_parts[$i] == $client_parts[$i]) {
239 // we have a different IP address
240 if ($_SESSION[$session_var] != $clientIP && empty ($classCheck)) {
241 $GLOBALS['log']->fatal("IP Address mismatch: SESSION IP: {$_SESSION[$session_var]} CLIENT IP: {$clientIP}");
253 array('session'=>'xsd:string'),
254 array('return'=>'xsd:int'),
258 * Perform a seamless login. This is used internally during the sync process.
260 * @param String $session -- Session ID returned by a previous call to login.
261 * @return true -- if the session was authenticated
262 * @return false -- if the session could not be authenticated
264 function seamless_login($session){
265 if(!validate_authenticated($session)){
274 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'query'=>'xsd:string', 'order_by'=>'xsd:string','offset'=>'xsd:int', 'select_fields'=>'tns:select_fields', 'max_results'=>'xsd:int', 'deleted'=>'xsd:int'),
275 array('return'=>'tns:get_entry_list_result'),
279 * Retrieve a list of beans. This is the primary method for getting list of SugarBeans from Sugar using the SOAP API.
281 * @param String $session -- Session ID returned by a previous call to login.
282 * @param String $module_name -- The name of the module to return records from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
283 * @param String $query -- SQL where clause without the word 'where'
284 * @param String $order_by -- SQL order by clause without the phrase 'order by'
285 * @param String $offset -- The record offset to start from.
286 * @param Array $select_fields -- A list of the fields to be included in the results. This optional parameter allows for only needed fields to be retrieved.
287 * @param String $max_results -- The maximum number of records to return. The default is the sugar configuration value for 'list_max_entries_per_page'
288 * @param Number $deleted -- false if deleted records should not be include, true if deleted records should be included.
289 * @return Array 'result_count' -- The number of records returned
290 * 'next_offset' -- The start of the next page (This will always be the previous offset plus the number of rows returned. It does not indicate if there is additional data unless you calculate that the next_offset happens to be closer than it should be.
291 * 'field_list' -- The vardef information on the selected fields.
292 * Array -- 'field'=> 'name' -- the name of the field
293 * 'type' -- the data type of the field
294 * 'label' -- the translation key for the label of the field
295 * 'required' -- Is the field required?
296 * 'options' -- Possible values for a drop down field
297 * 'entry_list' -- The records that were retrieved
298 * 'error' -- The SOAP error, if any
300 function get_entry_list($session, $module_name, $query, $order_by,$offset, $select_fields, $max_results, $deleted ){
301 global $beanList, $beanFiles, $current_user;
302 $error = new SoapError();
303 if(!validate_authenticated($session)){
304 $error->set_error('invalid_login');
305 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
308 if($module_name == 'CampaignProspects'){
309 $module_name = 'Prospects';
312 if(empty($beanList[$module_name])){
313 $error->set_error('no_module');
314 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
316 global $current_user;
317 if(!check_modules_access($current_user, $module_name, 'read')){
318 $error->set_error('no_access');
319 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
322 // If the maximum number of entries per page was specified, override the configuration value.
323 if($max_results > 0){
324 global $sugar_config;
325 $sugar_config['list_max_entries_per_page'] = $max_results;
329 $class_name = $beanList[$module_name];
330 require_once($beanFiles[$class_name]);
331 $seed = new $class_name();
332 if(! ($seed->ACLAccess('Export') && $seed->ACLAccess('list')))
334 $error->set_error('no_access');
335 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
338 require_once 'include/SugarSQLValidate.php';
339 $valid = new SugarSQLValidate();
340 if(!$valid->validateQueryClauses($query, $order_by)) {
341 $GLOBALS['log']->error("Bad query: $query $order_by");
342 $error->set_error('no_access');
344 'result_count' => -1,
345 'error' => $error->get_soap_array()
351 if($offset == '' || $offset == -1){
355 $response = $seed->retrieveTargetList($query, $select_fields, $offset,-1,-1,$deleted);
357 $response = $seed->get_list($order_by, $query, $offset,-1,-1,$deleted,true);
359 $list = $response['list'];
362 $output_list = array();
364 $isEmailModule = false;
365 if($module_name == 'Emails'){
366 $isEmailModule = true;
368 // retrieve the vardef information on the bean's fields.
369 $field_list = array();
371 require_once 'modules/Currencies/Currency.php';
373 $userCurrencyId = $current_user->getPreference('currency');
374 $userCurrency = new Currency;
375 $userCurrency->retrieve($userCurrencyId);
377 foreach($list as $value)
379 if(isset($value->emailAddress)){
380 $value->emailAddress->handleLegacyRetrieve($value);
383 $value->retrieveEmailText();
385 $value->fill_in_additional_detail_fields();
387 // bug 55129 - populate currency from user settings
388 if (property_exists($value, 'currency_id') && $userCurrency->deleted != 1)
390 // walk through all currency-related fields
391 foreach ($value->field_defs as $temp_field)
393 if (isset($temp_field['type']) && 'relate' == $temp_field['type']
394 && isset($temp_field['module']) && 'Currencies' == $temp_field['module']
395 && isset($temp_field['id_name']) && 'currency_id' == $temp_field['id_name'])
397 // populate related properties manually
398 $temp_property = $temp_field['name'];
399 $currency_property = $temp_field['rname'];
400 $value->$temp_property = $userCurrency->$currency_property;
402 else if ($value->currency_id != $userCurrency->id
403 && isset($temp_field['type'])
404 && 'currency' == $temp_field['type']
405 && substr($temp_field['name'], -9) != '_usdollar')
407 $temp_property = $temp_field['name'];
408 $value->$temp_property *= $userCurrency->conversion_rate;
412 $value->currency_id = $userCurrencyId;
416 $output_list[] = get_return_value($value, $module_name);
417 if(empty($field_list)){
418 $field_list = get_field_list($value);
422 // Filter the search results to only include the requested fields.
423 $output_list = filter_return_list($output_list, $select_fields, $module_name);
425 // Filter the list of fields to only include information on the requested fields.
426 $field_list = filter_return_list($field_list,$select_fields, $module_name);
428 // Calculate the offset for the start of the next page
429 $next_offset = $offset + sizeof($output_list);
431 return array('result_count'=>sizeof($output_list), 'next_offset'=>$next_offset,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
436 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'id'=>'xsd:string', 'select_fields'=>'tns:select_fields'),
437 array('return'=>'tns:get_entry_result'),
441 * Retrieve a single SugarBean based on ID.
443 * @param String $session -- Session ID returned by a previous call to login.
444 * @param String $module_name -- The name of the module to return records from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
445 * @param String $id -- The SugarBean's ID value.
446 * @param Array $select_fields -- A list of the fields to be included in the results. This optional parameter allows for only needed fields to be retrieved.
449 function get_entry($session, $module_name, $id,$select_fields ){
450 return get_entries($session, $module_name, array($id), $select_fields);
455 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'ids'=>'tns:select_fields', 'select_fields'=>'tns:select_fields'),
456 array('return'=>'tns:get_entry_result'),
460 * Retrieve a list of SugarBean's based on provided IDs.
462 * @param String $session -- Session ID returned by a previous call to login.
463 * @param String $module_name -- The name of the module to return records from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
464 * @param Array $ids -- An array of SugarBean IDs.
465 * @param Array $select_fields -- A list of the fields to be included in the results. This optional parameter allows for only needed fields to be retrieved.
466 * @return Array 'field_list' -- Var def information about the returned fields
467 * 'entry_list' -- The records that were retrieved
468 * 'error' -- The SOAP error, if any
470 function get_entries($session, $module_name, $ids,$select_fields ){
471 global $beanList, $beanFiles;
472 $error = new SoapError();
473 $field_list = array();
474 $output_list = array();
475 if(!validate_authenticated($session)){
476 $error->set_error('invalid_login');
477 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
480 if($module_name == 'CampaignProspects'){
481 $module_name = 'Prospects';
484 if(empty($beanList[$module_name])){
485 $error->set_error('no_module');
486 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
488 global $current_user;
489 if(!check_modules_access($current_user, $module_name, 'read')){
490 $error->set_error('no_access');
491 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
494 $class_name = $beanList[$module_name];
495 require_once($beanFiles[$class_name]);
497 //todo can modify in there to call bean->get_list($order_by, $where, 0, -1, -1, $deleted);
498 //that way we do not have to call retrieve for each bean
499 //perhaps also add a select_fields to this, so we only get the fields we need
500 //and not do a select *
501 foreach($ids as $id){
502 $seed = new $class_name();
505 $seed = $seed->retrieveTarget($id);
507 if ($seed->retrieve($id) == null)
511 if ($seed->deleted == 1) {
513 $list[] = array('name'=>'warning', 'value'=>'Access to this object is denied since it has been deleted or does not exist');
514 $list[] = array('name'=>'deleted', 'value'=>'1');
515 $output_list[] = Array('id'=>$id,
516 'module_name'=> $module_name,
517 'name_value_list'=>$list,
521 if(! $seed->ACLAccess('DetailView')){
522 $error->set_error('no_access');
523 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
525 $output_list[] = get_return_value($seed, $module_name);
527 if(empty($field_list)){
528 $field_list = get_field_list($seed);
533 $output_list = filter_return_list($output_list, $select_fields, $module_name);
534 $field_list = filter_field_list($field_list,$select_fields, $module_name);
536 return array( 'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
541 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'name_value_list'=>'tns:name_value_list'),
542 array('return'=>'tns:set_entry_result'),
546 * Update or create a single SugarBean.
548 * @param String $session -- Session ID returned by a previous call to login.
549 * @param String $module_name -- The name of the module to return records from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
550 * @param Array $name_value_list -- The keys of the array are the SugarBean attributes, the values of the array are the values the attributes should have.
551 * @return Array 'id' -- the ID of the bean that was written to (-1 on error)
552 * 'error' -- The SOAP error if any.
554 function set_entry($session,$module_name, $name_value_list){
555 global $beanList, $beanFiles;
557 $error = new SoapError();
558 if(!validate_authenticated($session)){
559 $error->set_error('invalid_login');
560 return array('id'=>-1, 'error'=>$error->get_soap_array());
562 if(empty($beanList[$module_name])){
563 $error->set_error('no_module');
564 return array('id'=>-1, 'error'=>$error->get_soap_array());
566 global $current_user;
567 if(!check_modules_access($current_user, $module_name, 'write')){
568 $error->set_error('no_access');
569 return array('id'=>-1, 'error'=>$error->get_soap_array());
572 $class_name = $beanList[$module_name];
573 require_once($beanFiles[$class_name]);
574 $seed = new $class_name();
576 foreach($name_value_list as $value){
577 if($value['name'] == 'id' && isset($value['value']) && strlen($value['value']) > 0){
578 $result = $seed->retrieve($value['value']);
579 //bug: 44680 - check to ensure the user has access before proceeding.
582 $error->set_error('no_access');
583 return array('id'=>-1, 'error'=>$error->get_soap_array());
592 foreach($name_value_list as $value){
593 $GLOBALS['log']->debug($value['name']." : ".$value['value']);
594 $seed->$value['name'] = $value['value'];
596 if(! $seed->ACLAccess('Save') || ($seed->deleted == 1 && !$seed->ACLAccess('Delete')))
598 $error->set_error('no_access');
599 return array('id'=>-1, 'error'=>$error->get_soap_array());
602 if($seed->deleted == 1){
603 $seed->mark_deleted($seed->id);
605 return array('id'=>$seed->id, 'error'=>$error->get_soap_array());
611 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'name_value_lists'=>'tns:name_value_lists'),
612 array('return'=>'tns:set_entries_result'),
616 * Update or create a list of SugarBeans
618 * @param String $session -- Session ID returned by a previous call to login.
619 * @param String $module_name -- The name of the module to return records from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
620 * @param Array $name_value_lists -- Array of Bean specific Arrays where the keys of the array are the SugarBean attributes, the values of the array are the values the attributes should have.
621 * @return Array 'ids' -- Array of the IDs of the beans that was written to (-1 on error)
622 * 'error' -- The SOAP error if any.
624 function set_entries($session,$module_name, $name_value_lists){
625 $error = new SoapError();
627 if(!validate_authenticated($session)){
628 $error->set_error('invalid_login');
632 'error' => $error->get_soap_array()
636 return handle_set_entries($module_name, $name_value_lists, FALSE);
643 'set_note_attachment',
644 array('session'=>'xsd:string','note'=>'tns:note_attachment'),
645 array('return'=>'tns:set_entry_result'),
649 * Add or replace the attachment on a Note.
651 * @param String $session -- Session ID returned by a previous call to login.
652 * @param Binary $note -- The flie contents of the attachment.
653 * @return Array 'id' -- The ID of the new note or -1 on error
654 * 'error' -- The SOAP error if any.
656 function set_note_attachment($session,$note)
659 $error = new SoapError();
660 if(!validate_authenticated($session)){
661 $error->set_error('invalid_login');
662 return array('id'=>-1, 'error'=>$error->get_soap_array());
665 require_once('modules/Notes/NoteSoap.php');
666 $ns = new NoteSoap();
667 return array('id'=>$ns->saveFile($note), 'error'=>$error->get_soap_array());
672 'get_note_attachment',
673 array('session'=>'xsd:string', 'id'=>'xsd:string'),
674 array('return'=>'tns:return_note_attachment'),
678 * Retrieve an attachment from a note
679 * @param String $session -- Session ID returned by a previous call to login.
680 * @param Binary $note -- The flie contents of the attachment.
681 * @return Array 'id' -- The ID of the new note or -1 on error
682 * 'error' -- The SOAP error if any.
684 * @param String $session -- Session ID returned by a previous call to login.
685 * @param String $id -- The ID of the appropriate Note.
686 * @return Array 'note_attachment' -- Array String 'id' -- The ID of the Note containing the attachment
687 * String 'filename' -- The file name of the attachment
688 * Binary 'file' -- The binary contents of the file.
689 * 'error' -- The SOAP error if any.
691 function get_note_attachment($session,$id)
693 $error = new SoapError();
694 if(!validate_authenticated($session)){
695 $error->set_error('invalid_login');
696 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
701 $note->retrieve($id);
702 if(!$note->ACLAccess('DetailView')){
703 $error->set_error('no_access');
704 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
706 require_once('modules/Notes/NoteSoap.php');
707 $ns = new NoteSoap();
708 if(!isset($note->filename)){
709 $note->filename = '';
711 $file= $ns->retrieveFile($id,$note->filename);
713 $error->set_error('no_file');
717 return array('note_attachment'=>array('id'=>$id, 'filename'=>$note->filename, 'file'=>$file), 'error'=>$error->get_soap_array());
721 'relate_note_to_module',
722 array('session'=>'xsd:string', 'note_id'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string'),
723 array('return'=>'tns:error_value'),
727 * Attach a note to another bean. Once you have created a note to store an
728 * attachment, the note needs to be related to the bean.
730 * @param String $session -- Session ID returned by a previous call to login.
731 * @param String $note_id -- The ID of the note that you want to associate with a bean
732 * @param String $module_name -- The name of the module to return records from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
733 * @param String $module_id -- The ID of the bean that you want to associate the note with
734 * @return no error for success, error for failure
736 function relate_note_to_module($session,$note_id, $module_name, $module_id){
737 global $beanList, $beanFiles;
738 $error = new SoapError();
739 if(!validate_authenticated($session)){
740 $error->set_error('invalid_login');
741 return $error->get_soap_array();
743 if(empty($beanList[$module_name])){
744 $error->set_error('no_module');
745 return $error->get_soap_array();
747 global $current_user;
748 if(!check_modules_access($current_user, $module_name, 'read')){
749 $error->set_error('no_access');
750 return $error->get_soap_array();
752 $class_name = $beanList['Notes'];
753 require_once($beanFiles[$class_name]);
754 $seed = new $class_name();
755 $seed->retrieve($note_id);
756 if(!$seed->ACLAccess('ListView')){
757 $error->set_error('no_access');
758 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
761 if($module_name != 'Contacts'){
762 $seed->parent_type=$module_name;
763 $seed->parent_id = $module_id;
767 $seed->contact_id=$module_id;
773 return $error->get_soap_array();
778 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string', 'select_fields'=>'tns:select_fields'),
779 array('return'=>'tns:get_entry_result'),
783 * Retrieve the collection of notes that are related to a bean.
785 * @param String $session -- Session ID returned by a previous call to login.
786 * @param String $module_name -- The name of the module to return records from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
787 * @param String $module_id -- The ID of the bean that you want to associate the note with
788 * @param Array $select_fields -- A list of the fields to be included in the results. This optional parameter allows for only needed fields to be retrieved.
789 * @return Array 'result_count' -- The number of records returned (-1 on error)
790 * 'next_offset' -- The start of the next page (This will always be the previous offset plus the number of rows returned. It does not indicate if there is additional data unless you calculate that the next_offset happens to be closer than it should be.
791 * 'field_list' -- The vardef information on the selected fields.
792 * 'entry_list' -- The records that were retrieved
793 * 'error' -- The SOAP error, if any
795 function get_related_notes($session,$module_name, $module_id, $select_fields){
796 global $beanList, $beanFiles;
797 $error = new SoapError();
798 if(!validate_authenticated($session)){
799 $error->set_error('invalid_login');
800 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
802 if(empty($beanList[$module_name])){
803 $error->set_error('no_module');
804 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
806 global $current_user;
807 if(!check_modules_access($current_user, $module_name, 'read')){
808 $error->set_error('no_access');
809 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
812 $class_name = $beanList[$module_name];
813 require_once($beanFiles[$class_name]);
814 $seed = new $class_name();
815 $seed->retrieve($module_id);
816 if(!$seed->ACLAccess('DetailView')){
817 $error->set_error('no_access');
818 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
820 $list = $seed->get_linked_beans('notes','Note', array(), 0, -1, 0);
822 $output_list = Array();
823 $field_list = Array();
824 foreach($list as $value)
826 $output_list[] = get_return_value($value, 'Notes');
827 if(empty($field_list))
829 $field_list = get_field_list($value);
832 $output_list = filter_return_list($output_list, $select_fields, $module_name);
833 $field_list = filter_field_list($field_list,$select_fields, $module_name);
835 return array('result_count'=>sizeof($output_list), 'next_offset'=>0,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
840 array('session'=>'xsd:string'),
841 array('return'=>'tns:error_value'),
845 * Log out of the session. This will destroy the session and prevent other's from using it.
847 * @param String $session -- Session ID returned by a previous call to login.
848 * @return Empty error on success, Error on failure
850 function logout($session){
851 global $current_user;
853 $error = new SoapError();
854 LogicHook::initialize();
855 if(validate_authenticated($session)){
856 $current_user->call_custom_logic('before_logout');
858 $GLOBALS['logic_hook']->call_custom_logic('Users', 'after_logout');
859 return $error->get_soap_array();
861 $error->set_error('no_session');
862 $GLOBALS['logic_hook']->call_custom_logic('Users', 'after_logout');
863 return $error->get_soap_array();
868 array('session'=>'xsd:string', 'module_name'=>'xsd:string'),
869 array('return'=>'tns:module_fields'),
873 * Retrieve vardef information on the fields of the specified bean.
875 * @param String $session -- Session ID returned by a previous call to login.
876 * @param String $module_name -- The name of the module to return records from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
877 * @return Array 'module_fields' -- The vardef information on the selected fields.
878 * 'error' -- The SOAP error, if any
880 function get_module_fields($session, $module_name){
881 global $beanList, $beanFiles;
882 $error = new SoapError();
883 $module_fields = array();
884 if(! validate_authenticated($session)){
885 $error->set_error('invalid_session');
886 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
888 if(empty($beanList[$module_name])){
889 $error->set_error('no_module');
890 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
892 global $current_user;
893 if(!check_modules_access($current_user, $module_name, 'read')){
894 $error->set_error('no_access');
895 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
897 $class_name = $beanList[$module_name];
899 if(empty($beanFiles[$class_name]))
901 $error->set_error('no_file');
902 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
905 require_once($beanFiles[$class_name]);
906 $seed = new $class_name();
907 if($seed->ACLAccess('ListView', true) || $seed->ACLAccess('DetailView', true) || $seed->ACLAccess('EditView', true) )
909 return get_return_module_fields($seed, $module_name, $error);
913 $error->set_error('no_access');
914 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
919 'get_available_modules',
920 array('session'=>'xsd:string'),
921 array('return'=>'tns:module_list'),
925 * Retrieve the list of available modules on the system available to the currently logged in user.
927 * @param String $session -- Session ID returned by a previous call to login.
928 * @return Array 'modules' -- An array of module names
929 * 'error' -- The SOAP error, if any
931 function get_available_modules($session){
932 $error = new SoapError();
934 if(! validate_authenticated($session)){
935 $error->set_error('invalid_session');
936 return array('modules'=> $modules, 'error'=>$error->get_soap_array());
938 $modules = array_keys($_SESSION['avail_modules']);
940 return array('modules'=> $modules, 'error'=>$error->get_soap_array());
945 'update_portal_user',
946 array('session'=>'xsd:string', 'portal_name'=>'xsd:string', 'name_value_list'=>'tns:name_value_list'),
947 array('return'=>'tns:error_value'),
951 * Update the properties of a contact that is portal user. Add the portal user name to the user's properties.
953 * @param String $session -- Session ID returned by a previous call to login.
954 * @param String $portal_name -- The portal user_name of the contact
955 * @param Array $name_value_list -- collection of 'name'=>'value' pairs for finding the contact
956 * @return Empty error on success, Error on failure
958 function update_portal_user($session,$portal_name, $name_value_list){
959 global $beanList, $beanFiles;
960 $error = new SoapError();
961 if(! validate_authenticated($session)){
962 $error->set_error('invalid_session');
963 return $error->get_soap_array();
965 $contact = new Contact();
967 $searchBy = array('deleted'=>0);
968 foreach($name_value_list as $name_value){
969 $searchBy[$name_value['name']] = $name_value['value'];
971 if($contact->retrieve_by_string_fields($searchBy) != null){
972 if(!$contact->duplicates_found){
973 $contact->portal_name = $portal_name;
974 $contact->portal_active = 1;
975 if($contact->ACLAccess('Save')){
978 $error->set_error('no_access');
980 return $error->get_soap_array();
982 $error->set_error('duplicates');
983 return $error->get_soap_array();
985 $error->set_error('no_records');
986 return $error->get_soap_array();
991 array('session'=>'xsd:string'),
992 array('return'=>'xsd:string'),
996 * Return the user_id of the user that is logged into the current session.
998 * @param String $session -- Session ID returned by a previous call to login.
999 * @return String -- the User ID of the current session
1002 function get_user_id($session){
1003 if(validate_authenticated($session)){
1004 global $current_user;
1005 return $current_user->id;
1014 array('session'=>'xsd:string'),
1015 array('return'=>'xsd:string'),
1019 * Return the ID of the default team for the user that is logged into the current session.
1021 * @param String $session -- Session ID returned by a previous call to login.
1022 * @return String -- the Team ID of the current user's default team
1023 * 1 for Community Edition
1026 function get_user_team_id($session){
1027 if(validate_authenticated($session))
1036 'get_user_team_set_id',
1037 array('session'=>'xsd:string'),
1038 array('return'=>'xsd:string'),
1042 * Return the Team Set ID for the user that is logged into the current session.
1044 * @param String $session -- Session ID returned by a previous call to login.
1045 * @return String -- the Team Set ID of the current user
1046 * 1 for Community Edition
1049 function get_user_team_set_id($session){
1050 if(validate_authenticated($session))
1061 array('return'=>'xsd:string'),
1065 * Return the current time on the server in the format 'Y-m-d H:i:s'. This time is in the server's default timezone.
1067 * @return String -- The current date/time 'Y-m-d H:i:s'
1069 function get_server_time(){
1070 return date('Y-m-d H:i:s');
1076 array('return'=>'xsd:string'),
1080 * Return the current time on the server in the format 'Y-m-d H:i:s'. This time is in GMT.
1082 * @return String -- The current date/time 'Y-m-d H:i:s'
1084 function get_gmt_time(){
1085 return TimeDate::getInstance()->nowDb();
1091 array('return'=>'xsd:string'),
1095 * Retrieve the specific flavor of sugar.
1097 * @return String 'CE' -- For Community Edition
1098 * 'PRO' -- For Professional
1099 * 'ENT' -- For Enterprise
1101 function get_sugar_flavor(){
1102 global $sugar_flavor;
1104 return $sugar_flavor;
1109 'get_server_version',
1111 array('return'=>'xsd:string'),
1115 * Retrieve the version number of Sugar that the server is running.
1117 * @return String -- The current sugar version number.
1120 function get_server_version(){
1122 $admin = new Administration();
1123 $admin->retrieveSettings('info');
1124 if(isset($admin->settings['info_sugar_version'])){
1125 return $admin->settings['info_sugar_version'];
1133 'get_relationships',
1134 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string', 'related_module'=>'xsd:string', 'related_module_query'=>'xsd:string', 'deleted'=>'xsd:int'),
1135 array('return'=>'tns:get_relationships_result'),
1139 * Retrieve a collection of beans tha are related to the specified bean.
1140 * As of 4.5.1c, all combinations of related modules are supported
1142 * @param String $session -- Session ID returned by a previous call to login.
1143 * @param String $module_name -- The name of the module that the primary record is from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1144 * @param String $module_id -- The ID of the bean in the specified module
1145 * @param String $related_module -- The name of the related module to return records from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1146 * @param String $related_module_query -- A portion of the where clause of the SQL statement to find the related items. The SQL query will already be filtered to only include the beans that are related to the specified bean.
1147 * @param Number $deleted -- false if deleted records should not be include, true if deleted records should be included.
1150 function get_relationships($session, $module_name, $module_id, $related_module, $related_module_query, $deleted){
1151 $error = new SoapError();
1153 if(!validate_authenticated($session)){
1154 $error->set_error('invalid_login');
1155 return array('ids'=>$ids,'error'=> $error->get_soap_array());
1157 global $beanList, $beanFiles;
1158 $error = new SoapError();
1160 if(empty($beanList[$module_name]) || empty($beanList[$related_module])){
1161 $error->set_error('no_module');
1162 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1164 $class_name = $beanList[$module_name];
1165 require_once($beanFiles[$class_name]);
1166 $mod = new $class_name();
1167 $mod->retrieve($module_id);
1168 if(!$mod->ACLAccess('DetailView')){
1169 $error->set_error('no_access');
1170 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1173 require_once 'include/SugarSQLValidate.php';
1174 $valid = new SugarSQLValidate();
1175 if(!$valid->validateQueryClauses($related_module_query)) {
1176 $GLOBALS['log']->error("Bad query: $related_module_query");
1177 $error->set_error('no_access');
1179 'result_count' => -1,
1180 'error' => $error->get_soap_array()
1184 $id_list = get_linked_records($related_module, $module_name, $module_id);
1186 if ($id_list === FALSE) {
1187 $error->set_error('no_relationship_support');
1188 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1190 elseif (count($id_list) == 0) {
1191 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1196 $in = "'".implode("', '", $id_list)."'";
1198 $related_class_name = $beanList[$related_module];
1199 require_once($beanFiles[$related_class_name]);
1200 $related_mod = new $related_class_name();
1202 $sql = "SELECT {$related_mod->table_name}.id FROM {$related_mod->table_name} ";
1205 if (isset($related_mod->custom_fields)) {
1206 $customJoin = $related_mod->custom_fields->getJOIN();
1207 $sql .= $customJoin ? $customJoin['join'] : '';
1210 $sql .= " WHERE {$related_mod->table_name}.id IN ({$in}) ";
1212 if (!empty($related_module_query)) {
1213 $sql .= " AND ( {$related_module_query} )";
1216 $result = $related_mod->db->query($sql);
1217 while ($row = $related_mod->db->fetchByAssoc($result)) {
1218 $list[] = $row['id'];
1221 $return_list = array();
1223 foreach($list as $id) {
1224 $related_class_name = $beanList[$related_module];
1225 $related_mod = new $related_class_name();
1226 $related_mod->retrieve($id);
1228 $return_list[] = array(
1230 'date_modified' => $related_mod->date_modified,
1231 'deleted' => $related_mod->deleted
1235 return array('ids' => $return_list, 'error' => $error->get_soap_array());
1241 array('session'=>'xsd:string','set_relationship_value'=>'tns:set_relationship_value'),
1242 array('return'=>'tns:error_value'),
1246 * Set a single relationship between two beans. The items are related by module name and id.
1248 * @param String $session -- Session ID returned by a previous call to login.
1249 * @param Array $set_relationship_value --
1250 * 'module1' -- The name of the module that the primary record is from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1251 * 'module1_id' -- The ID of the bean in the specified module
1252 * 'module2' -- The name of the module that the related record is from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1253 * 'module2_id' -- The ID of the bean in the specified module
1254 * @return Empty error on success, Error on failure
1256 function set_relationship($session, $set_relationship_value){
1257 $error = new SoapError();
1258 if(!validate_authenticated($session)){
1259 $error->set_error('invalid_login');
1260 return $error->get_soap_array();
1262 return handle_set_relationship($set_relationship_value, $session);
1266 'set_relationships',
1267 array('session'=>'xsd:string','set_relationship_list'=>'tns:set_relationship_list'),
1268 array('return'=>'tns:set_relationship_list_result'),
1272 * Setup several relationships between pairs of beans. The items are related by module name and id.
1274 * @param String $session -- Session ID returned by a previous call to login.
1275 * @param Array $set_relationship_list -- One for each relationship to setup. Each entry is itself an array.
1276 * 'module1' -- The name of the module that the primary record is from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1277 * 'module1_id' -- The ID of the bean in the specified module
1278 * 'module2' -- The name of the module that the related record is from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1279 * 'module2_id' -- The ID of the bean in the specified module
1280 * @return Empty error on success, Error on failure
1282 function set_relationships($session, $set_relationship_list){
1283 $error = new SoapError();
1284 if(!validate_authenticated($session)){
1285 $error->set_error('invalid_login');
1290 foreach($set_relationship_list as $set_relationship_value){
1291 $reter = handle_set_relationship($set_relationship_value, $session);
1292 if($reter['number'] == 0){
1298 return array('created'=>$count , 'failed'=>$failed, 'error'=>$error);
1303 //INTERNAL FUNCTION NOT EXPOSED THROUGH SOAP
1305 * (Internal) Create a relationship between two beans.
1307 * @param Array $set_relationship_value --
1308 * 'module1' -- The name of the module that the primary record is from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1309 * 'module1_id' -- The ID of the bean in the specified module
1310 * 'module2' -- The name of the module that the related record is from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1311 * 'module2_id' -- The ID of the bean in the specified module
1312 * @return Empty error on success, Error on failure
1314 function handle_set_relationship($set_relationship_value, $session='')
1316 global $beanList, $beanFiles;
1317 $error = new SoapError();
1319 $module1 = $set_relationship_value['module1'];
1320 $module1_id = $set_relationship_value['module1_id'];
1321 $module2 = $set_relationship_value['module2'];
1322 $module2_id = $set_relationship_value['module2_id'];
1324 if(empty($beanList[$module1]) || empty($beanList[$module2]) )
1326 $error->set_error('no_module');
1327 return $error->get_soap_array();
1329 $class_name = $beanList[$module1];
1330 require_once($beanFiles[$class_name]);
1331 $mod = new $class_name();
1332 $mod->retrieve($module1_id);
1333 if(!$mod->ACLAccess('DetailView')){
1334 $error->set_error('no_access');
1335 return $error->get_soap_array();
1337 if($module1 == "Contacts" && $module2 == "Users"){
1338 $key = 'contacts_users_id';
1341 $key = array_search(strtolower($module2),$mod->relationship_fields);
1343 $key = Relationship::retrieve_by_modules($module1, $module2, $GLOBALS['db']);
1345 // BEGIN SnapLogic fix for bug 32064
1346 if ($module1 == "Quotes" && $module2 == "ProductBundles") {
1347 // Alternative solution is perhaps to
1348 // do whatever Sugar does when the same
1349 // request is received from the web:
1350 $pb_cls = $beanList[$module2];
1351 $pb = new $pb_cls();
1352 $pb->retrieve($module2_id);
1354 // Check if this relationship already exists
1355 $query = "SELECT count(*) AS count FROM product_bundle_quote WHERE quote_id = '{$module1_id}' AND bundle_id = '{$module2_id}' AND deleted = '0'";
1356 $result = $GLOBALS['db']->query($query, true, "Error checking for previously existing relationship between quote and product_bundle");
1357 $row = $GLOBALS['db']->fetchByAssoc($result);
1358 if(isset($row['count']) && $row['count'] > 0){
1359 return $error->get_soap_array();
1362 $query = "SELECT MAX(bundle_index)+1 AS idx FROM product_bundle_quote WHERE quote_id = '{$module1_id}' AND deleted='0'";
1363 $result = $GLOBALS['db']->query($query, true, "Error getting bundle_index");
1364 $GLOBALS['log']->debug("*********** Getting max bundle_index");
1365 $GLOBALS['log']->debug($query);
1366 $row = $GLOBALS['db']->fetchByAssoc($result);
1373 $pb->set_productbundle_quote_relationship($module1_id,$module2_id,$idx);
1375 return $error->get_soap_array();
1377 } else if ($module1 == "ProductBundles" && $module2 == "Products") {
1378 // And, well, similar things apply in this case
1379 $pb_cls = $beanList[$module1];
1380 $pb = new $pb_cls();
1381 $pb->retrieve($module1_id);
1383 // Check if this relationship already exists
1384 $query = "SELECT count(*) AS count FROM product_bundle_product WHERE bundle_id = '{$module1_id}' AND product_id = '{$module2_id}' AND deleted = '0'";
1385 $result = $GLOBALS['db']->query($query, true, "Error checking for previously existing relationship between quote and product_bundle");
1386 $row = $GLOBALS['db']->fetchByAssoc($result);
1387 if(isset($row['count']) && $row['count'] > 0){
1388 return $error->get_soap_array();
1391 $query = "SELECT MAX(product_index)+1 AS idx FROM product_bundle_product WHERE bundle_id='{$module1_id}'";
1392 $result = $GLOBALS['db']->query($query, true, "Error getting bundle_index");
1393 $GLOBALS['log']->debug("*********** Getting max bundle_index");
1394 $GLOBALS['log']->debug($query);
1395 $row = $GLOBALS['db']->fetchByAssoc($result);
1401 $pb->set_productbundle_product_relationship($module2_id,$idx,$module1_id);
1404 $prod_cls = $beanList[$module2];
1405 $prod = new $prod_cls();
1406 $prod->retrieve($module2_id);
1407 $prod->quote_id = $pb->quote_id;
1409 return $error->get_soap_array();
1411 // END SnapLogic fix for bug 32064
1414 $mod->load_relationship($key);
1415 $mod->$key->add($module2_id);
1416 return $error->get_soap_array();
1423 $error->set_error('no_module');
1424 return $error->get_soap_array();
1427 if(($module1 == 'Meetings' || $module1 == 'Calls') && ($module2 == 'Contacts' || $module2 == 'Users')){
1428 $key = strtolower($module2);
1429 $mod->load_relationship($key);
1430 $mod->$key->add($module2_id);
1432 else if ($module1 == 'Contacts' && ($module2 == 'Notes' || $module2 == 'Calls' || $module2 == 'Meetings' || $module2 == 'Tasks') && !empty($session)){
1433 $mod->$key = $module2_id;
1434 $mod->save_relationship_changes(false);
1435 if (!empty($mod->account_id)) {
1436 // when setting a relationship from a Contact to these activities, if the Contacts is related to an Account,
1437 // we want to associate that Account to the activity as well
1438 $ret = set_relationship($session, array('module1'=>'Accounts', 'module1_id'=>$mod->account_id, 'module2'=>$module2, 'module2_id'=>$module2_id));
1442 $mod->$key = $module2_id;
1443 $mod->save_relationship_changes(false);
1446 return $error->get_soap_array();
1451 'set_document_revision',
1452 array('session'=>'xsd:string','note'=>'tns:document_revision'),
1453 array('return'=>'tns:set_entry_result'),
1457 * Enter description here...
1459 * @param String $session -- Session ID returned by a previous call to login.
1460 * @param unknown_type $document_revision
1463 function set_document_revision($session,$document_revision)
1466 $error = new SoapError();
1467 if(!validate_authenticated($session)){
1468 $error->set_error('invalid_login');
1469 return array('id'=>-1, 'error'=>$error->get_soap_array());
1472 require_once('modules/Documents/DocumentSoap.php');
1473 $dr = new DocumentSoap();
1474 return array('id'=>$dr->saveFile($document_revision), 'error'=>$error->get_soap_array());
1480 array('user_name'=>'xsd:string','password'=>'xsd:string','search_string'=>'xsd:string', 'modules'=>'tns:select_fields', 'offset'=>'xsd:int', 'max_results'=>'xsd:int'),
1481 array('return'=>'tns:get_entry_list_result'),
1485 * Given a list of modules to search and a search string, return the id, module_name, along with the fields
1486 * as specified in the $query_array
1488 * @param string $user_name - username of the Sugar User
1489 * @param string $password - password of the Sugar User
1490 * @param string $search_string - string to search
1491 * @param string[] $modules - array of modules to query
1492 * @param int $offset - a specified offset in the query
1493 * @param int $max_results - max number of records to return
1494 * @return get_entry_list_result - id, module_name, and list of fields from each record
1496 function search_by_module($user_name, $password, $search_string, $modules, $offset, $max_results){
1497 global $beanList, $beanFiles;
1499 $error = new SoapError();
1500 $hasLoginError = false;
1502 if(empty($user_name) && !empty($password))
1504 if(!validate_authenticated($password))
1506 $hasLoginError = true;
1508 } else if(!validate_user($user_name, $password)) {
1509 $hasLoginError = true;
1512 //If there is a login error, then return the error here
1515 $error->set_error('invalid_login');
1516 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
1519 global $current_user;
1520 if($max_results > 0){
1521 global $sugar_config;
1522 $sugar_config['list_max_entries_per_page'] = $max_results;
1524 // MRF - BUG:19552 - added a join for accounts' emails below
1525 $query_array = array('Accounts'=>array('where'=>array('Accounts' => array(0 => "accounts.name like '{0}%'"), 'EmailAddresses' => array(0 => "ea.email_address like '{0}%'")),'fields'=>"accounts.id, accounts.name"),
1526 'Bugs'=>array('where'=>array('Bugs' => array(0 => "bugs.name like '{0}%'", 1 => "bugs.bug_number = {0}")),'fields'=>"bugs.id, bugs.name, bugs.bug_number"),
1527 'Cases'=>array('where'=>array('Cases' => array(0 => "cases.name like '{0}%'", 1 => "cases.case_number = {0}")),'fields'=>"cases.id, cases.name, cases.case_number"),
1528 'Leads'=>array('where'=>array('Leads' => array(0 => "leads.first_name like '{0}%'",1 => "leads.last_name like '{0}%'"), 'EmailAddresses' => array(0 => "ea.email_address like '{0}%'")), 'fields'=>"leads.id, leads.first_name, leads.last_name, leads.status"),
1529 'Project'=>array('where'=>array('Project' => array(0 => "project.name like '{0}%'")), 'fields'=>"project.id, project.name"),
1530 'ProjectTask'=>array('where'=>array('ProjectTask' => array(0 => "project.id = '{0}'")), 'fields'=>"project_task.id, project_task.name"),
1531 'Contacts'=>array('where'=>array('Contacts' => array(0 => "contacts.first_name like '{0}%'", 1 => "contacts.last_name like '{0}%'"), 'EmailAddresses' => array(0 => "ea.email_address like '{0}%'")),'fields'=>"contacts.id, contacts.first_name, contacts.last_name"),
1532 'Opportunities'=>array('where'=>array('Opportunities' => array(0 => "opportunities.name like '{0}%'")), 'fields'=>"opportunities.id, opportunities.name"),
1533 'Users'=>array('where'=>array('EmailAddresses' => array(0 => "ea.email_address like '{0}%'")),'fields'=>"users.id, users.user_name, users.first_name, ea.email_address"),
1536 $more_query_array = array();
1537 foreach($modules as $module) {
1538 if (!array_key_exists($module, $query_array)) {
1539 $seed = new $beanList[$module]();
1540 $table_name = $seed->table_name;
1541 if (!empty($seed->field_defs['name']['db_concat_fields'])) {
1542 $namefield = $seed->db->concat($table_name, $seed->field_defs['name']['db_concat_fields']);
1544 $namefield = "$table_name.name";
1546 $more_query_array[$module] = array(
1549 0 => "$namefield like '%{0}%'",
1552 'fields' => "$table_name.id, $namefield AS name"
1557 if (!empty($more_query_array)) {
1558 $query_array = array_merge($query_array, $more_query_array);
1561 if(!empty($search_string) && isset($search_string)){
1562 foreach($modules as $module_name){
1563 $class_name = $beanList[$module_name];
1564 require_once($beanFiles[$class_name]);
1565 $seed = new $class_name();
1566 if(empty($beanList[$module_name])){
1569 if(!check_modules_access($current_user, $module_name, 'read')){
1572 if(! $seed->ACLAccess('ListView'))
1577 if(isset($query_array[$module_name])){
1580 //split here to do while loop
1581 foreach($query_array[$module_name]['where'] as $key => $value){
1582 foreach($value as $where_clause){
1585 $tmpQuery = ' UNION ';
1586 $tmpQuery .= "SELECT ".$query_array[$module_name]['fields']." FROM $seed->table_name ";
1587 // We need to confirm that the user is a member of the team of the item.
1590 if($module_name == 'ProjectTask'){
1591 $tmpQuery .= "INNER JOIN project ON $seed->table_name.project_id = project.id ";
1594 if(isset($seed->emailAddress) && $key == 'EmailAddresses'){
1595 $tmpQuery .= " INNER JOIN email_addr_bean_rel eabl ON eabl.bean_id = $seed->table_name.id and eabl.deleted=0";
1596 $tmpQuery .= " INNER JOIN email_addresses ea ON (ea.id = eabl.email_address_id) ";
1599 $search_terms = explode(", ", $search_string);
1600 $termCount = count($search_terms);
1602 if($key != 'EmailAddresses'){
1603 foreach($search_terms as $term){
1604 if(!strpos($where_clause, 'number')){
1605 $where .= string_format($where_clause,array($GLOBALS['db']->quote($term)));
1606 }elseif(is_numeric($term)){
1607 $where .= string_format($where_clause,array($GLOBALS['db']->quote($term)));
1611 if($count < $termCount){
1618 foreach ($search_terms as $term)
1620 $where .= "ea.email_address LIKE '".$GLOBALS['db']->quote($term)."'";
1621 if ($count < $termCount)
1629 $tmpQuery .= $where;
1630 $tmpQuery .= ") AND $seed->table_name.deleted = 0";
1632 $query .= $tmpQuery;
1635 //grab the items from the db
1636 $result = $seed->db->query($query, $offset, $max_results);
1638 while(($row = $seed->db->fetchByAssoc($result)) != null){
1640 foreach ($row as $field_key => $field_value) {
1641 $list[$field_key] = array('name'=>$field_key, 'value'=>$field_value);
1644 $output_list[] = array('id'=>$row['id'],
1645 'module_name'=>$module_name,
1646 'name_value_list'=>$list);
1647 if(empty($field_list)){
1648 $field_list = get_field_list($row);
1655 $next_offset = $offset + sizeof($output_list);
1657 return array('result_count'=>sizeof($output_list), 'next_offset'=>$next_offset,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
1663 'get_mailmerge_document',
1664 array('session'=>'xsd:string','file_name'=>'xsd:string', 'fields' => 'tns:select_fields'),
1665 array('return'=>'tns:get_sync_result_encoded'),
1669 * Get MailMerge document
1671 * @param String $session -- Session ID returned by a previous call to login.
1672 * @param unknown_type $file_name
1673 * @param unknown_type $fields
1676 function get_mailmerge_document($session, $file_name, $fields)
1678 global $beanList, $beanFiles, $app_list_strings;
1679 $error = new SoapError();
1680 if(!validate_authenticated($session))
1682 $error->set_error('invalid_login');
1683 return array('result'=>'', 'error'=>$error->get_soap_array());
1685 if(!preg_match('/^sugardata[\.\d\s]+\.php$/', $file_name)) {
1686 $error->set_error('no_records');
1687 return array('result'=>'', 'error'=>$error->get_soap_array());
1691 $file_name = sugar_cached('MergedDocuments/').pathinfo($file_name, PATHINFO_BASENAME);
1693 $master_fields = array();
1694 $related_fields = array();
1696 if(file_exists($file_name))
1698 include($file_name);
1700 $class1 = $merge_array['master_module'];
1701 $beanL = $beanList[$class1];
1702 $bean1 = $beanFiles[$beanL];
1703 require_once($bean1);
1704 $seed1 = new $beanL();
1706 if(!empty($merge_array['related_module']))
1708 $class2 = $merge_array['related_module'];
1709 $beanR = $beanList[$class2];
1710 $bean2 = $beanFiles[$beanR];
1711 require_once($bean2);
1712 $seed2 = new $beanR();
1716 //$token1 = strtolower($class1);
1717 if($class1 == 'Prospects'){
1718 $class1 = 'CampaignProspects';
1720 foreach($fields as $field)
1722 $pos = strpos(strtolower($field), strtolower($class1));
1723 $pos2 = strpos(strtolower($field), strtolower($class2));
1725 $fieldName = str_replace(strtolower($class1).'_', '', strtolower($field));
1726 array_push($master_fields, $fieldName);
1727 }else if($pos2 !== false){
1728 $fieldName = str_replace(strtolower($class2).'_', '', strtolower($field));
1729 array_push($related_fields, $fieldName);
1733 $html = '<html ' . get_language_header() .'><body><table border = 1><tr>';
1735 foreach($master_fields as $master_field){
1736 $html .= '<td>'.$class1.'_'.$master_field.'</td>';
1738 foreach($related_fields as $related_field){
1739 $html .= '<td>'.$class2.'_'.$related_field.'</td>';
1743 $ids = $merge_array['ids'];
1744 $is_prospect_merge = ($seed1->object_name == 'Prospect');
1745 foreach($ids as $key=>$value){
1746 if($is_prospect_merge){
1747 $seed1 = $seed1->retrieveTarget($key);
1749 $seed1->retrieve($key);
1752 foreach($master_fields as $master_field){
1753 if(isset($seed1->$master_field)){
1754 if($seed1->field_name_map[$master_field]['type'] == 'enum'){
1755 //pull in the translated dom
1756 $html .='<td>'.$app_list_strings[$seed1->field_name_map[$master_field]['options']][$seed1->$master_field].'</td>';
1758 $html .='<td>'.$seed1->$master_field.'</td>';
1762 $html .= '<td></td>';
1765 if(isset($value) && !empty($value)){
1766 $seed2->retrieve($value);
1767 foreach($related_fields as $related_field){
1768 if(isset($seed2->$related_field)){
1769 if($seed2->field_name_map[$related_field]['type'] == 'enum'){
1770 //pull in the translated dom
1771 $html .='<td>'.$app_list_strings[$seed2->field_name_map[$related_field]['options']][$seed2->$related_field].'</td>';
1773 $html .= '<td>'.$seed2->$related_field.'</td>';
1777 $html .= '<td></td>';
1783 $html .= "</table></body></html>";
1786 $result = base64_encode($html);
1787 return array('result' => $result, 'error' => $error);
1791 'get_mailmerge_document2',
1792 array('session'=>'xsd:string','file_name'=>'xsd:string', 'fields' => 'tns:select_fields'),
1793 array('return'=>'tns:get_mailmerge_document_result'),
1797 * Enter description here...
1799 * @param String $session -- Session ID returned by a previous call to login.
1800 * @param unknown_type $file_name
1801 * @param unknown_type $fields
1804 function get_mailmerge_document2($session, $file_name, $fields)
1806 global $beanList, $beanFiles, $app_list_strings, $app_strings;
1808 $error = new SoapError();
1809 if(!validate_authenticated($session))
1811 $GLOBALS['log']->error('invalid_login');
1812 $error->set_error('invalid_login');
1813 return array('result'=>'', 'error'=>$error->get_soap_array());
1815 if(!preg_match('/^sugardata[\.\d\s]+\.php$/', $file_name)) {
1816 $GLOBALS['log']->error($app_strings['ERR_NO_SUCH_FILE'] . " ({$file_name})");
1817 $error->set_error('no_records');
1818 return array('result'=>'', 'error'=>$error->get_soap_array());
1822 $file_name = sugar_cached('MergedDocuments/').pathinfo($file_name, PATHINFO_BASENAME);
1824 $master_fields = array();
1825 $related_fields = array();
1827 if(file_exists($file_name))
1829 include($file_name);
1831 $class1 = $merge_array['master_module'];
1832 $beanL = $beanList[$class1];
1833 $bean1 = $beanFiles[$beanL];
1834 require_once($bean1);
1835 $seed1 = new $beanL();
1837 if(!empty($merge_array['related_module']))
1839 $class2 = $merge_array['related_module'];
1840 $beanR = $beanList[$class2];
1841 $bean2 = $beanFiles[$beanR];
1842 require_once($bean2);
1843 $seed2 = new $beanR();
1847 //$token1 = strtolower($class1);
1848 if($class1 == 'Prospects'){
1849 $class1 = 'CampaignProspects';
1851 foreach($fields as $field)
1853 $pos = strpos(strtolower($field), strtolower($class1));
1854 $pos2 = strpos(strtolower($field), strtolower($class2));
1856 $fieldName = str_replace(strtolower($class1).'_', '', strtolower($field));
1857 array_push($master_fields, $fieldName);
1858 }else if($pos2 !== false){
1859 $fieldName = str_replace(strtolower($class2).'_', '', strtolower($field));
1860 array_push($related_fields, $fieldName);
1864 $html = '<html ' . get_language_header() . '><body><table border = 1><tr>';
1866 foreach($master_fields as $master_field){
1867 $html .= '<td>'.$class1.'_'.$master_field.'</td>';
1869 foreach($related_fields as $related_field){
1870 $html .= '<td>'.$class2.'_'.$related_field.'</td>';
1874 $ids = $merge_array['ids'];
1875 $resultIds = array();
1876 $is_prospect_merge = ($seed1->object_name == 'Prospect');
1877 if($is_prospect_merge){
1880 foreach($ids as $key=>$value){
1882 if($is_prospect_merge){
1883 $seed1 = $pSeed->retrieveTarget($key);
1885 $seed1->retrieve($key);
1887 $resultIds[] = array('name' => $seed1->module_name, 'value' => $key);
1889 foreach($master_fields as $master_field){
1890 if(isset($seed1->$master_field)){
1891 if($seed1->field_name_map[$master_field]['type'] == 'enum'){
1892 //pull in the translated dom
1893 $html .='<td>'.$app_list_strings[$seed1->field_name_map[$master_field]['options']][$seed1->$master_field].'</td>';
1894 } else if ($seed1->field_name_map[$master_field]['type'] == 'multienum') {
1896 if(isset($app_list_strings[$seed1->field_name_map[$master_field]['options']]) )
1898 $items = unencodeMultienum($seed1->$master_field);
1900 foreach($items as $item) {
1901 if ( !empty($app_list_strings[$seed1->field_name_map[$master_field]['options']][$item]) )
1903 array_push($output, $app_list_strings[$seed1->field_name_map[$master_field]['options']][$item]);
1909 $encoded_output = encodeMultienumValue($output);
1910 $html .= "<td>$encoded_output</td>";
1913 } else if ($seed1->field_name_map[$master_field]['type'] == 'currency') {
1914 $amount_field = $seed1->$master_field;
1915 $params = array( 'currency_symbol' => false );
1916 $amount_field = currency_format_number($amount_field, $params);
1917 $html .='<td>'.$amount_field.'</td>';
1919 $html .='<td>'.$seed1->$master_field.'</td>';
1923 $html .= '<td></td>';
1926 if(isset($value) && !empty($value)){
1927 $resultIds[] = array('name' => $seed2->module_name, 'value' => $value);
1928 $seed2->retrieve($value);
1929 foreach($related_fields as $related_field){
1930 if(isset($seed2->$related_field)){
1931 if($seed2->field_name_map[$related_field]['type'] == 'enum'){
1932 //pull in the translated dom
1933 $html .='<td>'.$app_list_strings[$seed2->field_name_map[$related_field]['options']][$seed2->$related_field].'</td>';
1934 } else if ($seed2->field_name_map[$related_field]['type'] == 'currency') {
1935 $amount_field = $seed2->$related_field;
1936 $params = array( 'currency_symbol' => false );
1937 $amount_field = currency_format_number($amount_field, $params);
1938 $html .='<td>'.$amount_field.'</td>';
1940 $html .= '<td>'.$seed2->$related_field.'</td>';
1944 $html .= '<td></td>';
1950 $html .= "</table></body></html>";
1952 $result = base64_encode($html);
1954 return array('html' => $result, 'name_value_list' => $resultIds, 'error' => $error);
1958 'get_document_revision',
1959 array('session'=>'xsd:string','i'=>'xsd:string'),
1960 array('return'=>'tns:return_document_revision'),
1964 * This method is used as a result of the .htaccess lock down on the cache directory. It will allow a
1965 * properly authenticated user to download a document that they have proper rights to download.
1967 * @param String $session -- Session ID returned by a previous call to login.
1968 * @param String $id -- ID of the document revision to obtain
1969 * @return return_document_revision - this is a complex type as defined in SoapTypes.php
1971 function get_document_revision($session,$id)
1973 global $sugar_config;
1975 $error = new SoapError();
1976 if(!validate_authenticated($session)){
1977 $error->set_error('invalid_login');
1978 return array('id'=>-1, 'error'=>$error->get_soap_array());
1982 $dr = new DocumentRevision();
1984 if(!empty($dr->filename)){
1985 $filename = "upload://{$dr->id}";
1986 $contents = base64_encode(sugar_file_get_contents($filename));
1987 return array('document_revision'=>array('id' => $dr->id, 'document_name' => $dr->document_name, 'revision' => $dr->revision, 'filename' => $dr->filename, 'file' => $contents), 'error'=>$error->get_soap_array());
1989 $error->set_error('no_records');
1990 return array('id'=>-1, 'error'=>$error->get_soap_array());
1995 'set_campaign_merge',
1996 array('session'=>'xsd:string', 'targets'=>'tns:select_fields', 'campaign_id'=>'xsd:string'),
1997 array('return'=>'tns:error_value'),
2000 * Once we have successfuly done a mail merge on a campaign, we need to notify Sugar of the targets
2001 * and the campaign_id for tracking purposes
2003 * @param session the session id of the authenticated user
2004 * @param targets a string array of ids identifying the targets used in the merge
2005 * @param campaign_id the campaign_id used for the merge
2007 * @return error_value
2009 function set_campaign_merge($session,$targets, $campaign_id){
2010 $error = new SoapError();
2011 if(!validate_authenticated($session)){
2012 $error->set_error('invalid_login');
2013 return $error->get_soap_array();
2015 if (empty($campaign_id) or !is_array($targets) or count($targets) == 0) {
2016 $GLOBALS['log']->debug('set_campaign_merge: Merge action status will not be updated, because, campaign_id is null or no targets were selected.');
2018 require_once('modules/Campaigns/utils.php');
2019 campaign_log_mail_merge($campaign_id,$targets);
2022 return $error->get_soap_array();
2025 'get_entries_count',
2026 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'query'=>'xsd:string', 'deleted' => 'xsd:int'),
2027 array('return'=>'tns:get_entries_count_result'),
2031 * Retrieve number of records in a given module
2033 * @param session the session id of the authenticated user
2034 * @param module_name module to retrieve number of records from
2035 * @param query allows webservice user to provide a WHERE clause
2036 * @param deleted specify whether or not to include deleted records
2038 @return get_entries_count_result - this is a complex type as defined in SoapTypes.php
2040 function get_entries_count($session, $module_name, $query, $deleted) {
2041 global $beanList, $beanFiles, $current_user;
2043 $error = new SoapError();
2045 if (!validate_authenticated($session)) {
2046 $error->set_error('invalid_login');
2048 'result_count' => -1,
2049 'error' => $error->get_soap_array()
2053 if (empty($beanList[$module_name])) {
2054 $error->set_error('no_module');
2056 'result_count' => -1,
2057 'error' => $error->get_soap_array()
2061 if(!check_modules_access($current_user, $module_name, 'list')){
2062 $error->set_error('no_access');
2064 'result_count' => -1,
2065 'error' => $error->get_soap_array()
2069 $class_name = $beanList[$module_name];
2070 require_once($beanFiles[$class_name]);
2071 $seed = new $class_name();
2073 if (!$seed->ACLAccess('ListView')) {
2074 $error->set_error('no_access');
2076 'result_count' => -1,
2077 'error' => $error->get_soap_array()
2081 $sql = 'SELECT COUNT(*) result_count FROM ' . $seed->table_name . ' ';
2084 $customJoin = $seed->getCustomJoin();
2085 $sql .= $customJoin['join'];
2087 // build WHERE clauses, if any
2088 $where_clauses = array();
2089 if (!empty($query)) {
2090 require_once 'include/SugarSQLValidate.php';
2091 $valid = new SugarSQLValidate();
2092 if(!$valid->validateQueryClauses($query)) {
2093 $GLOBALS['log']->error("Bad query: $query");
2094 $error->set_error('no_access');
2096 'result_count' => -1,
2097 'error' => $error->get_soap_array()
2100 $where_clauses[] = $query;
2102 if ($deleted == 0) {
2103 $where_clauses[] = $seed->table_name . '.deleted = 0';
2106 // if WHERE clauses exist, add them to query
2107 if (!empty($where_clauses)) {
2108 $sql .= ' WHERE ' . implode(' AND ', $where_clauses);
2111 $res = $GLOBALS['db']->query($sql);
2112 $row = $GLOBALS['db']->fetchByAssoc($res);
2115 'result_count' => $row['result_count'],
2116 'error' => $error->get_soap_array()
2121 'set_entries_details',
2122 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'name_value_lists'=>'tns:name_value_lists', 'select_fields' => 'tns:select_fields'),
2123 array('return'=>'tns:set_entries_detail_result'),
2127 * Update or create a list of SugarBeans, returning details about the records created/updated
2129 * @param String $session -- Session ID returned by a previous call to login.
2130 * @param String $module_name -- The name of the module to return records from. This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
2131 * @param Array $name_value_lists -- Array of Bean specific Arrays where the keys of the array are the SugarBean attributes, the values of the array are the values the attributes should have.
2132 * @param Array $select_fields -- A list of the fields to be included in the results. This optional parameter allows for only needed fields to be retrieved.
2133 * @return Array 'name_value_lists' -- Array of Bean specific Arrays where the keys of the array are the SugarBean attributes, the values of the array are the values the attributes should have.
2134 * 'error' -- The SOAP error if any.
2136 function set_entries_details($session, $module_name, $name_value_lists, $select_fields) {
2137 $error = new SoapError();
2139 if(!validate_authenticated($session)){
2140 $error->set_error('invalid_login');
2144 'error' => $error->get_soap_array()
2148 return handle_set_entries($module_name, $name_value_lists, $select_fields);
2151 // INTERNAL FUNCTION NOT EXPOSED THROUGH API
2152 function handle_set_entries($module_name, $name_value_lists, $select_fields = FALSE) {
2153 global $beanList, $beanFiles, $app_list_strings, $current_user;
2155 $error = new SoapError();
2156 $ret_values = array();
2158 if(empty($beanList[$module_name])){
2159 $error->set_error('no_module');
2160 return array('ids'=>array(), 'error'=>$error->get_soap_array());
2163 if(!check_modules_access($current_user, $module_name, 'write')){
2164 $error->set_error('no_access');
2165 return array('ids'=>-1, 'error'=>$error->get_soap_array());
2168 $class_name = $beanList[$module_name];
2169 require_once($beanFiles[$class_name]);
2172 $total = sizeof($name_value_lists);
2174 foreach($name_value_lists as $name_value_list){
2175 $seed = new $class_name();
2177 $seed->update_vcal = false;
2179 //See if we can retrieve the seed by a given id value
2180 foreach($name_value_list as $value)
2182 if($value['name'] == 'id')
2184 $seed->retrieve($value['value']);
2190 $dataValues = array();
2192 foreach($name_value_list as $value)
2194 $val = $value['value'];
2196 if($seed->field_name_map[$value['name']]['type'] == 'enum' || $seed->field_name_map[$value['name']]['type'] == 'radioenum')
2198 $vardef = $seed->field_name_map[$value['name']];
2199 if(isset($app_list_strings[$vardef['options']]) && !isset($app_list_strings[$vardef['options']][$val]) )
2201 if ( in_array($val,$app_list_strings[$vardef['options']]) )
2203 $val = array_search($val,$app_list_strings[$vardef['options']]);
2207 } else if($seed->field_name_map[$value['name']]['type'] == 'multienum') {
2209 $vardef = $seed->field_name_map[$value['name']];
2211 if(isset($app_list_strings[$vardef['options']]) && !isset($app_list_strings[$vardef['options']][$value]) )
2213 $items = explode(",", $val);
2214 $parsedItems = array();
2215 foreach ($items as $item)
2217 if ( in_array($item, $app_list_strings[$vardef['options']]) )
2219 $keyVal = array_search($item,$app_list_strings[$vardef['options']]);
2220 array_push($parsedItems, $keyVal);
2224 if (!empty($parsedItems))
2226 $val = encodeMultienumValue($parsedItems);
2231 //Apply the non-empty values now since this will be used for duplicate checks
2232 //allow string or int of 0 to be updated if set.
2233 if(!empty($val) || ($val==='0' || $val===0))
2235 $seed->$value['name'] = $val;
2237 //Store all the values in dataValues Array to apply later
2238 $dataValues[$value['name']] = $val;
2241 if($count == $total)
2243 $seed->update_vcal = false;
2247 //Add the account to a contact
2248 if($module_name == 'Contacts'){
2249 $GLOBALS['log']->debug('Creating Contact Account');
2250 add_create_account($seed);
2251 $duplicate_id = check_for_duplicate_contacts($seed);
2252 if($duplicate_id == null)
2254 if($seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete')))
2256 //Now apply the values, since this is not a duplicate we can just pass false for the $firstSync argument
2257 apply_values($seed, $dataValues, false);
2259 if($seed->deleted == 1){
2260 $seed->mark_deleted($seed->id);
2265 //since we found a duplicate we should set the sync flag
2266 if( $seed->ACLAccess('Save'))
2268 //Determine if this is a first time sync. We find out based on whether or not a contacts_users relationship exists
2269 $seed->id = $duplicate_id;
2270 $seed->load_relationship("user_sync");
2271 $beans = $seed->user_sync->getBeans();
2272 $first_sync = empty($beans);
2274 //Now apply the values and indicate whether or not this is a first time sync
2275 apply_values($seed, $dataValues, $first_sync);
2276 $seed->contacts_users_id = $current_user->id;
2278 $ids[] = $duplicate_id;//we have a conflict
2282 } else if($module_name == 'Meetings' || $module_name == 'Calls'){
2283 //we are going to check if we have a meeting in the system
2284 //with the same outlook_id. If we do find one then we will grab that
2286 if ($seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))) {
2287 // Check if we're updating an old record, or creating a new
2288 if (empty($seed->id)) {
2289 // If it's a new one, and we have outlook_id set
2290 // which means we're syncing from OPI check if it already exists
2291 if (!empty($seed->outlook_id)) {
2292 $GLOBALS['log']->debug(
2293 'Looking for ' . $module_name . ' with outlook_id ' . $seed->outlook_id
2297 'outlook_id' => $seed->outlook_id
2299 // Try to fetch a bean with this outlook_id
2300 $temp = BeanFactory::getBean($module_name);
2301 $temp = $temp->retrieve_by_string_fields($fields);
2303 // If we fetched one, just copy the ID to the one we're syncing
2304 if (!empty($temp)) {
2305 $seed->id = $temp->id;
2307 $GLOBALS['log']->debug(
2308 'Looking for ' . $module_name .
2309 ' with name/date_start/duration_hours/duration_minutes ' .
2310 $seed->name . '/' . $seed->date_start . '/' .
2311 $seed->duration_hours . '/' . $seed->duration_minutes
2314 // If we didn't, try to find the meeting by comparing the passed
2315 // Subject, start date and duration
2317 'name' => $seed->name,
2318 'date_start' => $seed->date_start,
2319 'duration_hours' => $seed->duration_hours,
2320 'duration_minutes' => $seed->duration_minutes
2322 $temp = BeanFactory::getBean($module_name);
2323 $temp = $temp->retrieve_by_string_fields($fields);
2325 if (!empty($temp)) {
2326 $seed->id = $temp->id;
2329 $GLOBALS['log']->debug(
2330 $module_name . ' found: ' . !empty($seed->id)
2334 if (empty($seed->reminder_time)) {
2335 $seed->reminder_time = -1;
2337 if($seed->reminder_time == -1){
2338 $defaultRemindrTime = $current_user->getPreference('reminder_time');
2339 if ($defaultRemindrTime != -1){
2340 $seed->reminder_checked = '1';
2341 $seed->reminder_time = $defaultRemindrTime;
2345 if ($seed->deleted == 1) {
2346 $seed->mark_deleted($seed->id);
2353 if( $seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
2359 // if somebody is calling set_entries_detail() and wants fields returned...
2360 if ($select_fields !== FALSE) {
2361 $ret_values[$count] = array();
2363 foreach ($select_fields as $select_field) {
2364 if (isset($seed->$select_field)) {
2365 $ret_values[$count][] = get_name_value($select_field, $seed->$select_field);
2371 // handle returns for set_entries_detail() and set_entries()
2372 if ($select_fields !== FALSE) {
2374 'name_value_lists' => $ret_values,
2375 'error' => $error->get_soap_array()
2381 'error' => $error->get_soap_array()