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-2012 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((!empty($sugar_config['authenticationClass'])? $sugar_config['authenticationClass'] : 'SugarAuthenticate'));
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((!empty($sugar_config['authenticationClass'])? $sugar_config['authenticationClass'] : 'SugarAuthenticate'));
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)){
268 $_SESSION['seamless_login'] = true;
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;
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();
370 foreach($list as $value)
372 if(isset($value->emailAddress)){
373 $value->emailAddress->handleLegacyRetrieve($value);
376 $value->retrieveEmailText();
378 $value->fill_in_additional_detail_fields();
379 $output_list[] = get_return_value($value, $module_name);
380 if(empty($field_list)){
381 $field_list = get_field_list($value);
385 // Filter the search results to only include the requested fields.
386 $output_list = filter_return_list($output_list, $select_fields, $module_name);
388 // Filter the list of fields to only include information on the requested fields.
389 $field_list = filter_return_list($field_list,$select_fields, $module_name);
391 // Calculate the offset for the start of the next page
392 $next_offset = $offset + sizeof($output_list);
394 return array('result_count'=>sizeof($output_list), 'next_offset'=>$next_offset,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
399 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'id'=>'xsd:string', 'select_fields'=>'tns:select_fields'),
400 array('return'=>'tns:get_entry_result'),
404 * Retrieve a single SugarBean based on ID.
406 * @param String $session -- Session ID returned by a previous call to login.
407 * @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)..
408 * @param String $id -- The SugarBean's ID value.
409 * @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.
412 function get_entry($session, $module_name, $id,$select_fields ){
413 return get_entries($session, $module_name, array($id), $select_fields);
418 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'ids'=>'tns:select_fields', 'select_fields'=>'tns:select_fields'),
419 array('return'=>'tns:get_entry_result'),
423 * Retrieve a list of SugarBean's based on provided IDs.
425 * @param String $session -- Session ID returned by a previous call to login.
426 * @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)..
427 * @param Array $ids -- An array of SugarBean IDs.
428 * @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.
429 * @return Array 'field_list' -- Var def information about the returned fields
430 * 'entry_list' -- The records that were retrieved
431 * 'error' -- The SOAP error, if any
433 function get_entries($session, $module_name, $ids,$select_fields ){
434 global $beanList, $beanFiles;
435 $error = new SoapError();
436 $field_list = array();
437 $output_list = array();
438 if(!validate_authenticated($session)){
439 $error->set_error('invalid_login');
440 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
443 if($module_name == 'CampaignProspects'){
444 $module_name = 'Prospects';
447 if(empty($beanList[$module_name])){
448 $error->set_error('no_module');
449 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
451 global $current_user;
452 if(!check_modules_access($current_user, $module_name, 'read')){
453 $error->set_error('no_access');
454 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
457 $class_name = $beanList[$module_name];
458 require_once($beanFiles[$class_name]);
460 //todo can modify in there to call bean->get_list($order_by, $where, 0, -1, -1, $deleted);
461 //that way we do not have to call retrieve for each bean
462 //perhaps also add a select_fields to this, so we only get the fields we need
463 //and not do a select *
464 foreach($ids as $id){
465 $seed = new $class_name();
468 $seed = $seed->retrieveTarget($id);
470 if ($seed->retrieve($id) == null)
474 if ($seed->deleted == 1) {
476 $list[] = array('name'=>'warning', 'value'=>'Access to this object is denied since it has been deleted or does not exist');
477 $list[] = array('name'=>'deleted', 'value'=>'1');
478 $output_list[] = Array('id'=>$id,
479 'module_name'=> $module_name,
480 'name_value_list'=>$list,
484 if(! $seed->ACLAccess('DetailView')){
485 $error->set_error('no_access');
486 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
488 $output_list[] = get_return_value($seed, $module_name);
490 if(empty($field_list)){
491 $field_list = get_field_list($seed);
496 $output_list = filter_return_list($output_list, $select_fields, $module_name);
497 $field_list = filter_field_list($field_list,$select_fields, $module_name);
499 return array( 'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
504 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'name_value_list'=>'tns:name_value_list'),
505 array('return'=>'tns:set_entry_result'),
509 * Update or create a single SugarBean.
511 * @param String $session -- Session ID returned by a previous call to login.
512 * @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)..
513 * @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.
514 * @return Array 'id' -- the ID of the bean that was written to (-1 on error)
515 * 'error' -- The SOAP error if any.
517 function set_entry($session,$module_name, $name_value_list){
518 global $beanList, $beanFiles;
520 $error = new SoapError();
521 if(!validate_authenticated($session)){
522 $error->set_error('invalid_login');
523 return array('id'=>-1, 'error'=>$error->get_soap_array());
525 if(empty($beanList[$module_name])){
526 $error->set_error('no_module');
527 return array('id'=>-1, 'error'=>$error->get_soap_array());
529 global $current_user;
530 if(!check_modules_access($current_user, $module_name, 'write')){
531 $error->set_error('no_access');
532 return array('id'=>-1, 'error'=>$error->get_soap_array());
535 $class_name = $beanList[$module_name];
536 require_once($beanFiles[$class_name]);
537 $seed = new $class_name();
539 foreach($name_value_list as $value){
540 if($value['name'] == 'id' && isset($value['value']) && strlen($value['value']) > 0){
541 $result = $seed->retrieve($value['value']);
542 //bug: 44680 - check to ensure the user has access before proceeding.
545 $error->set_error('no_access');
546 return array('id'=>-1, 'error'=>$error->get_soap_array());
555 foreach($name_value_list as $value){
556 $GLOBALS['log']->debug($value['name']." : ".$value['value']);
557 $seed->$value['name'] = $value['value'];
559 if(! $seed->ACLAccess('Save') || ($seed->deleted == 1 && !$seed->ACLAccess('Delete')))
561 $error->set_error('no_access');
562 return array('id'=>-1, 'error'=>$error->get_soap_array());
565 if($seed->deleted == 1){
566 $seed->mark_deleted($seed->id);
568 return array('id'=>$seed->id, 'error'=>$error->get_soap_array());
574 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'name_value_lists'=>'tns:name_value_lists'),
575 array('return'=>'tns:set_entries_result'),
579 * Update or create a list of SugarBeans
581 * @param String $session -- Session ID returned by a previous call to login.
582 * @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)..
583 * @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.
584 * @return Array 'ids' -- Array of the IDs of the beans that was written to (-1 on error)
585 * 'error' -- The SOAP error if any.
587 function set_entries($session,$module_name, $name_value_lists){
588 $error = new SoapError();
590 if(!validate_authenticated($session)){
591 $error->set_error('invalid_login');
595 'error' => $error->get_soap_array()
599 return handle_set_entries($module_name, $name_value_lists, FALSE);
606 'set_note_attachment',
607 array('session'=>'xsd:string','note'=>'tns:note_attachment'),
608 array('return'=>'tns:set_entry_result'),
612 * Add or replace the attachment on a Note.
614 * @param String $session -- Session ID returned by a previous call to login.
615 * @param Binary $note -- The flie contents of the attachment.
616 * @return Array 'id' -- The ID of the new note or -1 on error
617 * 'error' -- The SOAP error if any.
619 function set_note_attachment($session,$note)
622 $error = new SoapError();
623 if(!validate_authenticated($session)){
624 $error->set_error('invalid_login');
625 return array('id'=>-1, 'error'=>$error->get_soap_array());
628 require_once('modules/Notes/NoteSoap.php');
629 $ns = new NoteSoap();
630 return array('id'=>$ns->saveFile($note), 'error'=>$error->get_soap_array());
635 'get_note_attachment',
636 array('session'=>'xsd:string', 'id'=>'xsd:string'),
637 array('return'=>'tns:return_note_attachment'),
641 * Retrieve an attachment from a note
642 * @param String $session -- Session ID returned by a previous call to login.
643 * @param Binary $note -- The flie contents of the attachment.
644 * @return Array 'id' -- The ID of the new note or -1 on error
645 * 'error' -- The SOAP error if any.
647 * @param String $session -- Session ID returned by a previous call to login.
648 * @param String $id -- The ID of the appropriate Note.
649 * @return Array 'note_attachment' -- Array String 'id' -- The ID of the Note containing the attachment
650 * String 'filename' -- The file name of the attachment
651 * Binary 'file' -- The binary contents of the file.
652 * 'error' -- The SOAP error if any.
654 function get_note_attachment($session,$id)
656 $error = new SoapError();
657 if(!validate_authenticated($session)){
658 $error->set_error('invalid_login');
659 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
664 $note->retrieve($id);
665 if(!$note->ACLAccess('DetailView')){
666 $error->set_error('no_access');
667 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
669 require_once('modules/Notes/NoteSoap.php');
670 $ns = new NoteSoap();
671 if(!isset($note->filename)){
672 $note->filename = '';
674 $file= $ns->retrieveFile($id,$note->filename);
676 $error->set_error('no_file');
680 return array('note_attachment'=>array('id'=>$id, 'filename'=>$note->filename, 'file'=>$file), 'error'=>$error->get_soap_array());
684 'relate_note_to_module',
685 array('session'=>'xsd:string', 'note_id'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string'),
686 array('return'=>'tns:error_value'),
690 * Attach a note to another bean. Once you have created a note to store an
691 * attachment, the note needs to be related to the bean.
693 * @param String $session -- Session ID returned by a previous call to login.
694 * @param String $note_id -- The ID of the note that you want to associate with a bean
695 * @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)..
696 * @param String $module_id -- The ID of the bean that you want to associate the note with
697 * @return no error for success, error for failure
699 function relate_note_to_module($session,$note_id, $module_name, $module_id){
700 global $beanList, $beanFiles;
701 $error = new SoapError();
702 if(!validate_authenticated($session)){
703 $error->set_error('invalid_login');
704 return $error->get_soap_array();
706 if(empty($beanList[$module_name])){
707 $error->set_error('no_module');
708 return $error->get_soap_array();
710 global $current_user;
711 if(!check_modules_access($current_user, $module_name, 'read')){
712 $error->set_error('no_access');
713 return $error->get_soap_array();
715 $class_name = $beanList['Notes'];
716 require_once($beanFiles[$class_name]);
717 $seed = new $class_name();
718 $seed->retrieve($note_id);
719 if(!$seed->ACLAccess('ListView')){
720 $error->set_error('no_access');
721 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
724 if($module_name != 'Contacts'){
725 $seed->parent_type=$module_name;
726 $seed->parent_id = $module_id;
730 $seed->contact_id=$module_id;
736 return $error->get_soap_array();
741 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string', 'select_fields'=>'tns:select_fields'),
742 array('return'=>'tns:get_entry_result'),
746 * Retrieve the collection of notes that are related to a bean.
748 * @param String $session -- Session ID returned by a previous call to login.
749 * @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)..
750 * @param String $module_id -- The ID of the bean that you want to associate the note with
751 * @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.
752 * @return Array 'result_count' -- The number of records returned (-1 on error)
753 * '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.
754 * 'field_list' -- The vardef information on the selected fields.
755 * 'entry_list' -- The records that were retrieved
756 * 'error' -- The SOAP error, if any
758 function get_related_notes($session,$module_name, $module_id, $select_fields){
759 global $beanList, $beanFiles;
760 $error = new SoapError();
761 if(!validate_authenticated($session)){
762 $error->set_error('invalid_login');
763 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
765 if(empty($beanList[$module_name])){
766 $error->set_error('no_module');
767 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
769 global $current_user;
770 if(!check_modules_access($current_user, $module_name, 'read')){
771 $error->set_error('no_access');
772 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
775 $class_name = $beanList[$module_name];
776 require_once($beanFiles[$class_name]);
777 $seed = new $class_name();
778 $seed->retrieve($module_id);
779 if(!$seed->ACLAccess('DetailView')){
780 $error->set_error('no_access');
781 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
783 $list = $seed->get_linked_beans('notes','Note', array(), 0, -1, 0);
785 $output_list = Array();
786 $field_list = Array();
787 foreach($list as $value)
789 $output_list[] = get_return_value($value, 'Notes');
790 if(empty($field_list))
792 $field_list = get_field_list($value);
795 $output_list = filter_return_list($output_list, $select_fields, $module_name);
796 $field_list = filter_field_list($field_list,$select_fields, $module_name);
798 return array('result_count'=>sizeof($output_list), 'next_offset'=>0,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
803 array('session'=>'xsd:string'),
804 array('return'=>'tns:error_value'),
808 * Log out of the session. This will destroy the session and prevent other's from using it.
810 * @param String $session -- Session ID returned by a previous call to login.
811 * @return Empty error on success, Error on failure
813 function logout($session){
814 global $current_user;
816 $error = new SoapError();
817 LogicHook::initialize();
818 if(validate_authenticated($session)){
819 $current_user->call_custom_logic('before_logout');
821 $GLOBALS['logic_hook']->call_custom_logic('Users', 'after_logout');
822 return $error->get_soap_array();
824 $error->set_error('no_session');
825 $GLOBALS['logic_hook']->call_custom_logic('Users', 'after_logout');
826 return $error->get_soap_array();
831 array('session'=>'xsd:string', 'module_name'=>'xsd:string'),
832 array('return'=>'tns:module_fields'),
836 * Retrieve vardef information on the fields of the specified bean.
838 * @param String $session -- Session ID returned by a previous call to login.
839 * @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)..
840 * @return Array 'module_fields' -- The vardef information on the selected fields.
841 * 'error' -- The SOAP error, if any
843 function get_module_fields($session, $module_name){
844 global $beanList, $beanFiles;
845 $error = new SoapError();
846 $module_fields = array();
847 if(! validate_authenticated($session)){
848 $error->set_error('invalid_session');
849 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
851 if(empty($beanList[$module_name])){
852 $error->set_error('no_module');
853 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
855 global $current_user;
856 if(!check_modules_access($current_user, $module_name, 'read')){
857 $error->set_error('no_access');
858 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
860 $class_name = $beanList[$module_name];
862 if(empty($beanFiles[$class_name]))
864 $error->set_error('no_file');
865 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
868 require_once($beanFiles[$class_name]);
869 $seed = new $class_name();
870 if($seed->ACLAccess('ListView', true) || $seed->ACLAccess('DetailView', true) || $seed->ACLAccess('EditView', true) )
872 return get_return_module_fields($seed, $module_name, $error);
876 $error->set_error('no_access');
877 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
882 'get_available_modules',
883 array('session'=>'xsd:string'),
884 array('return'=>'tns:module_list'),
888 * Retrieve the list of available modules on the system available to the currently logged in user.
890 * @param String $session -- Session ID returned by a previous call to login.
891 * @return Array 'modules' -- An array of module names
892 * 'error' -- The SOAP error, if any
894 function get_available_modules($session){
895 $error = new SoapError();
897 if(! validate_authenticated($session)){
898 $error->set_error('invalid_session');
899 return array('modules'=> $modules, 'error'=>$error->get_soap_array());
901 $modules = array_keys($_SESSION['avail_modules']);
903 return array('modules'=> $modules, 'error'=>$error->get_soap_array());
908 'update_portal_user',
909 array('session'=>'xsd:string', 'portal_name'=>'xsd:string', 'name_value_list'=>'tns:name_value_list'),
910 array('return'=>'tns:error_value'),
914 * Update the properties of a contact that is portal user. Add the portal user name to the user's properties.
916 * @param String $session -- Session ID returned by a previous call to login.
917 * @param String $portal_name -- The portal user_name of the contact
918 * @param Array $name_value_list -- collection of 'name'=>'value' pairs for finding the contact
919 * @return Empty error on success, Error on failure
921 function update_portal_user($session,$portal_name, $name_value_list){
922 global $beanList, $beanFiles;
923 $error = new SoapError();
924 if(! validate_authenticated($session)){
925 $error->set_error('invalid_session');
926 return $error->get_soap_array();
928 $contact = new Contact();
930 $searchBy = array('deleted'=>0);
931 foreach($name_value_list as $name_value){
932 $searchBy[$name_value['name']] = $name_value['value'];
934 if($contact->retrieve_by_string_fields($searchBy) != null){
935 if(!$contact->duplicates_found){
936 $contact->portal_name = $portal_name;
937 $contact->portal_active = 1;
938 if($contact->ACLAccess('Save')){
941 $error->set_error('no_access');
943 return $error->get_soap_array();
945 $error->set_error('duplicates');
946 return $error->get_soap_array();
948 $error->set_error('no_records');
949 return $error->get_soap_array();
954 array('session'=>'xsd:string'),
955 array('return'=>'xsd:string'),
959 * Return the user_id of the user that is logged into the current session.
961 * @param String $session -- Session ID returned by a previous call to login.
962 * @return String -- the User ID of the current session
965 function get_user_id($session){
966 if(validate_authenticated($session)){
967 global $current_user;
968 return $current_user->id;
977 array('session'=>'xsd:string'),
978 array('return'=>'xsd:string'),
982 * Return the ID of the default team for the user that is logged into the current session.
984 * @param String $session -- Session ID returned by a previous call to login.
985 * @return String -- the Team ID of the current user's default team
986 * 1 for Community Edition
989 function get_user_team_id($session){
990 if(validate_authenticated($session))
1001 array('return'=>'xsd:string'),
1005 * 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.
1007 * @return String -- The current date/time 'Y-m-d H:i:s'
1009 function get_server_time(){
1010 return date('Y-m-d H:i:s');
1016 array('return'=>'xsd:string'),
1020 * Return the current time on the server in the format 'Y-m-d H:i:s'. This time is in GMT.
1022 * @return String -- The current date/time 'Y-m-d H:i:s'
1024 function get_gmt_time(){
1025 return TimeDate::getInstance()->nowDb();
1031 array('return'=>'xsd:string'),
1035 * Retrieve the specific flavor of sugar.
1037 * @return String 'CE' -- For Community Edition
1038 * 'PRO' -- For Professional
1039 * 'ENT' -- For Enterprise
1041 function get_sugar_flavor(){
1042 global $sugar_flavor;
1044 return $sugar_flavor;
1049 'get_server_version',
1051 array('return'=>'xsd:string'),
1055 * Retrieve the version number of Sugar that the server is running.
1057 * @return String -- The current sugar version number.
1060 function get_server_version(){
1062 $admin = new Administration();
1063 $admin->retrieveSettings('info');
1064 if(isset($admin->settings['info_sugar_version'])){
1065 return $admin->settings['info_sugar_version'];
1073 'get_relationships',
1074 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string', 'related_module'=>'xsd:string', 'related_module_query'=>'xsd:string', 'deleted'=>'xsd:int'),
1075 array('return'=>'tns:get_relationships_result'),
1079 * Retrieve a collection of beans tha are related to the specified bean.
1080 * As of 4.5.1c, all combinations of related modules are supported
1082 * @param String $session -- Session ID returned by a previous call to login.
1083 * @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)..
1084 * @param String $module_id -- The ID of the bean in the specified module
1085 * @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)..
1086 * @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.
1087 * @param Number $deleted -- false if deleted records should not be include, true if deleted records should be included.
1090 function get_relationships($session, $module_name, $module_id, $related_module, $related_module_query, $deleted){
1091 $error = new SoapError();
1093 if(!validate_authenticated($session)){
1094 $error->set_error('invalid_login');
1095 return array('ids'=>$ids,'error'=> $error->get_soap_array());
1097 global $beanList, $beanFiles;
1098 $error = new SoapError();
1100 if(empty($beanList[$module_name]) || empty($beanList[$related_module])){
1101 $error->set_error('no_module');
1102 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1104 $class_name = $beanList[$module_name];
1105 require_once($beanFiles[$class_name]);
1106 $mod = new $class_name();
1107 $mod->retrieve($module_id);
1108 if(!$mod->ACLAccess('DetailView')){
1109 $error->set_error('no_access');
1110 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1113 require_once 'include/SugarSQLValidate.php';
1114 $valid = new SugarSQLValidate();
1115 if(!$valid->validateQueryClauses($related_module_query)) {
1116 $GLOBALS['log']->error("Bad query: $related_module_query");
1117 $error->set_error('no_access');
1119 'result_count' => -1,
1120 'error' => $error->get_soap_array()
1124 $id_list = get_linked_records($related_module, $module_name, $module_id);
1126 if ($id_list === FALSE) {
1127 $error->set_error('no_relationship_support');
1128 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1130 elseif (count($id_list) == 0) {
1131 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1136 $in = "'".implode("', '", $id_list)."'";
1138 $related_class_name = $beanList[$related_module];
1139 require_once($beanFiles[$related_class_name]);
1140 $related_mod = new $related_class_name();
1142 $sql = "SELECT {$related_mod->table_name}.id FROM {$related_mod->table_name} ";
1145 $sql .= " WHERE {$related_mod->table_name}.id IN ({$in}) ";
1147 if (!empty($related_module_query)) {
1148 $sql .= " AND ( {$related_module_query} )";
1151 $result = $related_mod->db->query($sql);
1152 while ($row = $related_mod->db->fetchByAssoc($result)) {
1153 $list[] = $row['id'];
1156 $return_list = array();
1158 foreach($list as $id) {
1159 $related_class_name = $beanList[$related_module];
1160 $related_mod = new $related_class_name();
1161 $related_mod->retrieve($id);
1163 $return_list[] = array(
1165 'date_modified' => $related_mod->date_modified,
1166 'deleted' => $related_mod->deleted
1170 return array('ids' => $return_list, 'error' => $error->get_soap_array());
1176 array('session'=>'xsd:string','set_relationship_value'=>'tns:set_relationship_value'),
1177 array('return'=>'tns:error_value'),
1181 * Set a single relationship between two beans. The items are related by module name and id.
1183 * @param String $session -- Session ID returned by a previous call to login.
1184 * @param Array $set_relationship_value --
1185 * '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)..
1186 * 'module1_id' -- The ID of the bean in the specified module
1187 * '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)..
1188 * 'module2_id' -- The ID of the bean in the specified module
1189 * @return Empty error on success, Error on failure
1191 function set_relationship($session, $set_relationship_value){
1192 $error = new SoapError();
1193 if(!validate_authenticated($session)){
1194 $error->set_error('invalid_login');
1195 return $error->get_soap_array();
1197 return handle_set_relationship($set_relationship_value, $session);
1201 'set_relationships',
1202 array('session'=>'xsd:string','set_relationship_list'=>'tns:set_relationship_list'),
1203 array('return'=>'tns:set_relationship_list_result'),
1207 * Setup several relationships between pairs of beans. The items are related by module name and id.
1209 * @param String $session -- Session ID returned by a previous call to login.
1210 * @param Array $set_relationship_list -- One for each relationship to setup. Each entry is itself an array.
1211 * '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)..
1212 * 'module1_id' -- The ID of the bean in the specified module
1213 * '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)..
1214 * 'module2_id' -- The ID of the bean in the specified module
1215 * @return Empty error on success, Error on failure
1217 function set_relationships($session, $set_relationship_list){
1218 $error = new SoapError();
1219 if(!validate_authenticated($session)){
1220 $error->set_error('invalid_login');
1225 foreach($set_relationship_list as $set_relationship_value){
1226 $reter = handle_set_relationship($set_relationship_value, $session);
1227 if($reter['number'] == 0){
1233 return array('created'=>$count , 'failed'=>$failed, 'error'=>$error);
1238 //INTERNAL FUNCTION NOT EXPOSED THROUGH SOAP
1240 * (Internal) Create a relationship between two beans.
1242 * @param Array $set_relationship_value --
1243 * '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)..
1244 * 'module1_id' -- The ID of the bean in the specified module
1245 * '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)..
1246 * 'module2_id' -- The ID of the bean in the specified module
1247 * @return Empty error on success, Error on failure
1249 function handle_set_relationship($set_relationship_value, $session='')
1251 global $beanList, $beanFiles;
1252 $error = new SoapError();
1254 $module1 = $set_relationship_value['module1'];
1255 $module1_id = $set_relationship_value['module1_id'];
1256 $module2 = $set_relationship_value['module2'];
1257 $module2_id = $set_relationship_value['module2_id'];
1259 if(empty($beanList[$module1]) || empty($beanList[$module2]) )
1261 $error->set_error('no_module');
1262 return $error->get_soap_array();
1264 $class_name = $beanList[$module1];
1265 require_once($beanFiles[$class_name]);
1266 $mod = new $class_name();
1267 $mod->retrieve($module1_id);
1268 if(!$mod->ACLAccess('DetailView')){
1269 $error->set_error('no_access');
1270 return $error->get_soap_array();
1272 if($module1 == "Contacts" && $module2 == "Users"){
1273 $key = 'contacts_users_id';
1276 $key = array_search(strtolower($module2),$mod->relationship_fields);
1278 $key = Relationship::retrieve_by_modules($module1, $module2, $GLOBALS['db']);
1280 // BEGIN SnapLogic fix for bug 32064
1281 if ($module1 == "Quotes" && $module2 == "ProductBundles") {
1282 // Alternative solution is perhaps to
1283 // do whatever Sugar does when the same
1284 // request is received from the web:
1285 $pb_cls = $beanList[$module2];
1286 $pb = new $pb_cls();
1287 $pb->retrieve($module2_id);
1289 // Check if this relationship already exists
1290 $query = "SELECT count(*) AS count FROM product_bundle_quote WHERE quote_id = '{$module1_id}' AND bundle_id = '{$module2_id}' AND deleted = '0'";
1291 $result = $GLOBALS['db']->query($query, true, "Error checking for previously existing relationship between quote and product_bundle");
1292 $row = $GLOBALS['db']->fetchByAssoc($result);
1293 if(isset($row['count']) && $row['count'] > 0){
1294 return $error->get_soap_array();
1297 $query = "SELECT MAX(bundle_index)+1 AS idx FROM product_bundle_quote WHERE quote_id = '{$module1_id}' AND deleted='0'";
1298 $result = $GLOBALS['db']->query($query, true, "Error getting bundle_index");
1299 $GLOBALS['log']->debug("*********** Getting max bundle_index");
1300 $GLOBALS['log']->debug($query);
1301 $row = $GLOBALS['db']->fetchByAssoc($result);
1308 $pb->set_productbundle_quote_relationship($module1_id,$module2_id,$idx);
1310 return $error->get_soap_array();
1312 } else if ($module1 == "ProductBundles" && $module2 == "Products") {
1313 // And, well, similar things apply in this case
1314 $pb_cls = $beanList[$module1];
1315 $pb = new $pb_cls();
1316 $pb->retrieve($module1_id);
1318 // Check if this relationship already exists
1319 $query = "SELECT count(*) AS count FROM product_bundle_product WHERE bundle_id = '{$module1_id}' AND product_id = '{$module2_id}' AND deleted = '0'";
1320 $result = $GLOBALS['db']->query($query, true, "Error checking for previously existing relationship between quote and product_bundle");
1321 $row = $GLOBALS['db']->fetchByAssoc($result);
1322 if(isset($row['count']) && $row['count'] > 0){
1323 return $error->get_soap_array();
1326 $query = "SELECT MAX(product_index)+1 AS idx FROM product_bundle_product WHERE bundle_id='{$module1_id}'";
1327 $result = $GLOBALS['db']->query($query, true, "Error getting bundle_index");
1328 $GLOBALS['log']->debug("*********** Getting max bundle_index");
1329 $GLOBALS['log']->debug($query);
1330 $row = $GLOBALS['db']->fetchByAssoc($result);
1336 $pb->set_productbundle_product_relationship($module2_id,$idx,$module1_id);
1339 $prod_cls = $beanList[$module2];
1340 $prod = new $prod_cls();
1341 $prod->retrieve($module2_id);
1342 $prod->quote_id = $pb->quote_id;
1344 return $error->get_soap_array();
1346 // END SnapLogic fix for bug 32064
1349 $mod->load_relationship($key);
1350 $mod->$key->add($module2_id);
1351 return $error->get_soap_array();
1358 $error->set_error('no_module');
1359 return $error->get_soap_array();
1362 if(($module1 == 'Meetings' || $module1 == 'Calls') && ($module2 == 'Contacts' || $module2 == 'Users')){
1363 $key = strtolower($module2);
1364 $mod->load_relationship($key);
1365 $mod->$key->add($module2_id);
1367 else if ($module1 == 'Contacts' && ($module2 == 'Notes' || $module2 == 'Calls' || $module2 == 'Meetings' || $module2 == 'Tasks') && !empty($session)){
1368 $mod->$key = $module2_id;
1369 $mod->save_relationship_changes(false);
1370 if (!empty($mod->account_id)) {
1371 // when setting a relationship from a Contact to these activities, if the Contacts is related to an Account,
1372 // we want to associate that Account to the activity as well
1373 $ret = set_relationship($session, array('module1'=>'Accounts', 'module1_id'=>$mod->account_id, 'module2'=>$module2, 'module2_id'=>$module2_id));
1377 $mod->$key = $module2_id;
1378 $mod->save_relationship_changes(false);
1381 return $error->get_soap_array();
1386 'set_document_revision',
1387 array('session'=>'xsd:string','note'=>'tns:document_revision'),
1388 array('return'=>'tns:set_entry_result'),
1392 * Enter description here...
1394 * @param String $session -- Session ID returned by a previous call to login.
1395 * @param unknown_type $document_revision
1398 function set_document_revision($session,$document_revision)
1401 $error = new SoapError();
1402 if(!validate_authenticated($session)){
1403 $error->set_error('invalid_login');
1404 return array('id'=>-1, 'error'=>$error->get_soap_array());
1407 require_once('modules/Documents/DocumentSoap.php');
1408 $dr = new DocumentSoap();
1409 return array('id'=>$dr->saveFile($document_revision), 'error'=>$error->get_soap_array());
1415 array('user_name'=>'xsd:string','password'=>'xsd:string','search_string'=>'xsd:string', 'modules'=>'tns:select_fields', 'offset'=>'xsd:int', 'max_results'=>'xsd:int'),
1416 array('return'=>'tns:get_entry_list_result'),
1420 * Given a list of modules to search and a search string, return the id, module_name, along with the fields
1421 * as specified in the $query_array
1423 * @param string $user_name - username of the Sugar User
1424 * @param string $password - password of the Sugar User
1425 * @param string $search_string - string to search
1426 * @param string[] $modules - array of modules to query
1427 * @param int $offset - a specified offset in the query
1428 * @param int $max_results - max number of records to return
1429 * @return get_entry_list_result - id, module_name, and list of fields from each record
1431 function search_by_module($user_name, $password, $search_string, $modules, $offset, $max_results){
1432 global $beanList, $beanFiles;
1434 $error = new SoapError();
1435 $hasLoginError = false;
1437 if(empty($user_name) && !empty($password))
1439 if(!validate_authenticated($password))
1441 $hasLoginError = true;
1443 } else if(!validate_user($user_name, $password)) {
1444 $hasLoginError = true;
1447 //If there is a login error, then return the error here
1450 $error->set_error('invalid_login');
1451 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
1454 global $current_user;
1455 if($max_results > 0){
1456 global $sugar_config;
1457 $sugar_config['list_max_entries_per_page'] = $max_results;
1459 // MRF - BUG:19552 - added a join for accounts' emails below
1460 $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"),
1461 'Bugs'=>array('where'=>array('Bugs' => array(0 => "bugs.name like '{0}%'", 1 => "bugs.bug_number = {0}")),'fields'=>"bugs.id, bugs.name, bugs.bug_number"),
1462 'Cases'=>array('where'=>array('Cases' => array(0 => "cases.name like '{0}%'", 1 => "cases.case_number = {0}")),'fields'=>"cases.id, cases.name, cases.case_number"),
1463 '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"),
1464 'Project'=>array('where'=>array('Project' => array(0 => "project.name like '{0}%'")), 'fields'=>"project.id, project.name"),
1465 'ProjectTask'=>array('where'=>array('ProjectTask' => array(0 => "project.id = '{0}'")), 'fields'=>"project_task.id, project_task.name"),
1466 '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"),
1467 'Opportunities'=>array('where'=>array('Opportunities' => array(0 => "opportunities.name like '{0}%'")), 'fields'=>"opportunities.id, opportunities.name"),
1468 'Users'=>array('where'=>array('EmailAddresses' => array(0 => "ea.email_address like '{0}%'")),'fields'=>"users.id, users.user_name, users.first_name, ea.email_address"),
1471 if(!empty($search_string) && isset($search_string)){
1472 foreach($modules as $module_name){
1473 $class_name = $beanList[$module_name];
1474 require_once($beanFiles[$class_name]);
1475 $seed = new $class_name();
1476 if(empty($beanList[$module_name])){
1479 if(!check_modules_access($current_user, $module_name, 'read')){
1482 if(! $seed->ACLAccess('ListView'))
1487 if(isset($query_array[$module_name])){
1490 //split here to do while loop
1491 foreach($query_array[$module_name]['where'] as $key => $value){
1492 foreach($value as $where_clause){
1495 $tmpQuery = ' UNION ';
1496 $tmpQuery .= "SELECT ".$query_array[$module_name]['fields']." FROM $seed->table_name ";
1497 // We need to confirm that the user is a member of the team of the item.
1500 if($module_name == 'ProjectTask'){
1501 $tmpQuery .= "INNER JOIN project ON $seed->table_name.project_id = project.id ";
1504 if(isset($seed->emailAddress) && $key == 'EmailAddresses'){
1505 $tmpQuery .= " INNER JOIN email_addr_bean_rel eabl ON eabl.bean_id = $seed->table_name.id and eabl.deleted=0";
1506 $tmpQuery .= " INNER JOIN email_addresses ea ON (ea.id = eabl.email_address_id) ";
1509 $search_terms = explode(", ", $search_string);
1510 $termCount = count($search_terms);
1512 if($key != 'EmailAddresses'){
1513 foreach($search_terms as $term){
1514 if(!strpos($where_clause, 'number')){
1515 $where .= string_format($where_clause,array($GLOBALS['db']->quote($term)));
1516 }elseif(is_numeric($term)){
1517 $where .= string_format($where_clause,array($GLOBALS['db']->quote($term)));
1521 if($count < $termCount){
1528 foreach ($search_terms as $term)
1530 $where .= "ea.email_address LIKE '".$GLOBALS['db']->quote($term)."'";
1531 if ($count < $termCount)
1539 $tmpQuery .= $where;
1540 $tmpQuery .= ") AND $seed->table_name.deleted = 0";
1542 $query .= $tmpQuery;
1545 //grab the items from the db
1546 $result = $seed->db->query($query, $offset, $max_results);
1548 while(($row = $seed->db->fetchByAssoc($result)) != null){
1550 $fields = explode(", ", $query_array[$module_name]['fields']);
1551 foreach($fields as $field){
1552 $field_names = explode(".", $field);
1553 $list[$field] = array('name'=>$field_names[1], 'value'=>$row[$field_names[1]]);
1556 $output_list[] = array('id'=>$row['id'],
1557 'module_name'=>$module_name,
1558 'name_value_list'=>$list);
1559 if(empty($field_list)){
1560 $field_list = get_field_list($row);
1567 $next_offset = $offset + sizeof($output_list);
1569 return array('result_count'=>sizeof($output_list), 'next_offset'=>$next_offset,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
1575 'get_mailmerge_document',
1576 array('session'=>'xsd:string','file_name'=>'xsd:string', 'fields' => 'tns:select_fields'),
1577 array('return'=>'tns:get_sync_result_encoded'),
1581 * Get MailMerge document
1583 * @param String $session -- Session ID returned by a previous call to login.
1584 * @param unknown_type $file_name
1585 * @param unknown_type $fields
1588 function get_mailmerge_document($session, $file_name, $fields)
1590 global $beanList, $beanFiles, $app_list_strings;
1591 $error = new SoapError();
1592 if(!validate_authenticated($session))
1594 $error->set_error('invalid_login');
1595 return array('result'=>'', 'error'=>$error->get_soap_array());
1597 if(!preg_match('/^sugardata[\.\d\s]+\.php$/', $file_name)) {
1598 $error->set_error('no_records');
1599 return array('result'=>'', 'error'=>$error->get_soap_array());
1603 $file_name = sugar_cached('MergedDocuments/').pathinfo($file_name, PATHINFO_BASENAME);
1605 $master_fields = array();
1606 $related_fields = array();
1608 if(file_exists($file_name))
1610 include($file_name);
1612 $class1 = $merge_array['master_module'];
1613 $beanL = $beanList[$class1];
1614 $bean1 = $beanFiles[$beanL];
1615 require_once($bean1);
1616 $seed1 = new $beanL();
1618 if(!empty($merge_array['related_module']))
1620 $class2 = $merge_array['related_module'];
1621 $beanR = $beanList[$class2];
1622 $bean2 = $beanFiles[$beanR];
1623 require_once($bean2);
1624 $seed2 = new $beanR();
1628 //$token1 = strtolower($class1);
1629 if($class1 == 'Prospects'){
1630 $class1 = 'CampaignProspects';
1632 foreach($fields as $field)
1634 $pos = strpos(strtolower($field), strtolower($class1));
1635 $pos2 = strpos(strtolower($field), strtolower($class2));
1637 $fieldName = str_replace(strtolower($class1).'_', '', strtolower($field));
1638 array_push($master_fields, $fieldName);
1639 }else if($pos2 !== false){
1640 $fieldName = str_replace(strtolower($class2).'_', '', strtolower($field));
1641 array_push($related_fields, $fieldName);
1645 $html = '<html ' . get_language_header() .'><body><table border = 1><tr>';
1647 foreach($master_fields as $master_field){
1648 $html .= '<td>'.$class1.'_'.$master_field.'</td>';
1650 foreach($related_fields as $related_field){
1651 $html .= '<td>'.$class2.'_'.$related_field.'</td>';
1655 $ids = $merge_array['ids'];
1656 $is_prospect_merge = ($seed1->object_name == 'Prospect');
1657 foreach($ids as $key=>$value){
1658 if($is_prospect_merge){
1659 $seed1 = $seed1->retrieveTarget($key);
1661 $seed1->retrieve($key);
1664 foreach($master_fields as $master_field){
1665 if(isset($seed1->$master_field)){
1666 if($seed1->field_name_map[$master_field]['type'] == 'enum'){
1667 //pull in the translated dom
1668 $html .='<td>'.$app_list_strings[$seed1->field_name_map[$master_field]['options']][$seed1->$master_field].'</td>';
1670 $html .='<td>'.$seed1->$master_field.'</td>';
1674 $html .= '<td></td>';
1677 if(isset($value) && !empty($value)){
1678 $seed2->retrieve($value);
1679 foreach($related_fields as $related_field){
1680 if(isset($seed2->$related_field)){
1681 if($seed2->field_name_map[$related_field]['type'] == 'enum'){
1682 //pull in the translated dom
1683 $html .='<td>'.$app_list_strings[$seed2->field_name_map[$related_field]['options']][$seed2->$related_field].'</td>';
1685 $html .= '<td>'.$seed2->$related_field.'</td>';
1689 $html .= '<td></td>';
1695 $html .= "</table></body></html>";
1698 $result = base64_encode($html);
1699 return array('result' => $result, 'error' => $error);
1703 'get_mailmerge_document2',
1704 array('session'=>'xsd:string','file_name'=>'xsd:string', 'fields' => 'tns:select_fields'),
1705 array('return'=>'tns:get_mailmerge_document_result'),
1709 * Enter description here...
1711 * @param String $session -- Session ID returned by a previous call to login.
1712 * @param unknown_type $file_name
1713 * @param unknown_type $fields
1716 function get_mailmerge_document2($session, $file_name, $fields)
1718 global $beanList, $beanFiles, $app_list_strings, $app_strings;
1720 $error = new SoapError();
1721 if(!validate_authenticated($session))
1723 $GLOBALS['log']->error('invalid_login');
1724 $error->set_error('invalid_login');
1725 return array('result'=>'', 'error'=>$error->get_soap_array());
1727 if(!preg_match('/^sugardata[\.\d\s]+\.php$/', $file_name)) {
1728 $GLOBALS['log']->error($app_strings['ERR_NO_SUCH_FILE'] . " ({$file_name})");
1729 $error->set_error('no_records');
1730 return array('result'=>'', 'error'=>$error->get_soap_array());
1734 $file_name = sugar_cached('MergedDocuments/').pathinfo($file_name, PATHINFO_BASENAME);
1736 $master_fields = array();
1737 $related_fields = array();
1739 if(file_exists($file_name))
1741 include($file_name);
1743 $class1 = $merge_array['master_module'];
1744 $beanL = $beanList[$class1];
1745 $bean1 = $beanFiles[$beanL];
1746 require_once($bean1);
1747 $seed1 = new $beanL();
1749 if(!empty($merge_array['related_module']))
1751 $class2 = $merge_array['related_module'];
1752 $beanR = $beanList[$class2];
1753 $bean2 = $beanFiles[$beanR];
1754 require_once($bean2);
1755 $seed2 = new $beanR();
1759 //$token1 = strtolower($class1);
1760 if($class1 == 'Prospects'){
1761 $class1 = 'CampaignProspects';
1763 foreach($fields as $field)
1765 $pos = strpos(strtolower($field), strtolower($class1));
1766 $pos2 = strpos(strtolower($field), strtolower($class2));
1768 $fieldName = str_replace(strtolower($class1).'_', '', strtolower($field));
1769 array_push($master_fields, $fieldName);
1770 }else if($pos2 !== false){
1771 $fieldName = str_replace(strtolower($class2).'_', '', strtolower($field));
1772 array_push($related_fields, $fieldName);
1776 $html = '<html ' . get_language_header() . '><body><table border = 1><tr>';
1778 foreach($master_fields as $master_field){
1779 $html .= '<td>'.$class1.'_'.$master_field.'</td>';
1781 foreach($related_fields as $related_field){
1782 $html .= '<td>'.$class2.'_'.$related_field.'</td>';
1786 $ids = $merge_array['ids'];
1787 $resultIds = array();
1788 $is_prospect_merge = ($seed1->object_name == 'Prospect');
1789 if($is_prospect_merge){
1792 foreach($ids as $key=>$value){
1794 if($is_prospect_merge){
1795 $seed1 = $pSeed->retrieveTarget($key);
1797 $seed1->retrieve($key);
1799 $resultIds[] = array('name' => $seed1->module_name, 'value' => $key);
1801 foreach($master_fields as $master_field){
1802 if(isset($seed1->$master_field)){
1803 if($seed1->field_name_map[$master_field]['type'] == 'enum'){
1804 //pull in the translated dom
1805 $html .='<td>'.$app_list_strings[$seed1->field_name_map[$master_field]['options']][$seed1->$master_field].'</td>';
1806 } else if ($seed1->field_name_map[$master_field]['type'] == 'multienum') {
1808 if(isset($app_list_strings[$seed1->field_name_map[$master_field]['options']]) )
1810 $items = unencodeMultienum($seed1->$master_field);
1812 foreach($items as $item) {
1813 if ( !empty($app_list_strings[$seed1->field_name_map[$master_field]['options']][$item]) )
1815 array_push($output, $app_list_strings[$seed1->field_name_map[$master_field]['options']][$item]);
1821 $encoded_output = encodeMultienumValue($output);
1822 $html .= "<td>$encoded_output</td>";
1826 $html .='<td>'.$seed1->$master_field.'</td>';
1830 $html .= '<td></td>';
1833 if(isset($value) && !empty($value)){
1834 $resultIds[] = array('name' => $seed2->module_name, 'value' => $value);
1835 $seed2->retrieve($value);
1836 foreach($related_fields as $related_field){
1837 if(isset($seed2->$related_field)){
1838 if($seed2->field_name_map[$related_field]['type'] == 'enum'){
1839 //pull in the translated dom
1840 $html .='<td>'.$app_list_strings[$seed2->field_name_map[$related_field]['options']][$seed2->$related_field].'</td>';
1842 $html .= '<td>'.$seed2->$related_field.'</td>';
1846 $html .= '<td></td>';
1852 $html .= "</table></body></html>";
1854 $result = base64_encode($html);
1856 return array('html' => $result, 'name_value_list' => $resultIds, 'error' => $error);
1860 'get_document_revision',
1861 array('session'=>'xsd:string','i'=>'xsd:string'),
1862 array('return'=>'tns:return_document_revision'),
1866 * This method is used as a result of the .htaccess lock down on the cache directory. It will allow a
1867 * properly authenticated user to download a document that they have proper rights to download.
1869 * @param String $session -- Session ID returned by a previous call to login.
1870 * @param String $id -- ID of the document revision to obtain
1871 * @return return_document_revision - this is a complex type as defined in SoapTypes.php
1873 function get_document_revision($session,$id)
1875 global $sugar_config;
1877 $error = new SoapError();
1878 if(!validate_authenticated($session)){
1879 $error->set_error('invalid_login');
1880 return array('id'=>-1, 'error'=>$error->get_soap_array());
1884 $dr = new DocumentRevision();
1886 if(!empty($dr->filename)){
1887 $filename = "upload://{$dr->id}";
1888 $contents = base64_encode(sugar_file_get_contents($filename));
1889 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());
1891 $error->set_error('no_records');
1892 return array('id'=>-1, 'error'=>$error->get_soap_array());
1897 'set_campaign_merge',
1898 array('session'=>'xsd:string', 'targets'=>'tns:select_fields', 'campaign_id'=>'xsd:string'),
1899 array('return'=>'tns:error_value'),
1902 * Once we have successfuly done a mail merge on a campaign, we need to notify Sugar of the targets
1903 * and the campaign_id for tracking purposes
1905 * @param session the session id of the authenticated user
1906 * @param targets a string array of ids identifying the targets used in the merge
1907 * @param campaign_id the campaign_id used for the merge
1909 * @return error_value
1911 function set_campaign_merge($session,$targets, $campaign_id){
1912 $error = new SoapError();
1913 if(!validate_authenticated($session)){
1914 $error->set_error('invalid_login');
1915 return $error->get_soap_array();
1917 if (empty($campaign_id) or !is_array($targets) or count($targets) == 0) {
1918 $GLOBALS['log']->debug('set_campaign_merge: Merge action status will not be updated, because, campaign_id is null or no targets were selected.');
1920 require_once('modules/Campaigns/utils.php');
1921 campaign_log_mail_merge($campaign_id,$targets);
1924 return $error->get_soap_array();
1927 'get_entries_count',
1928 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'query'=>'xsd:string', 'deleted' => 'xsd:int'),
1929 array('return'=>'tns:get_entries_count_result'),
1933 * Retrieve number of records in a given module
1935 * @param session the session id of the authenticated user
1936 * @param module_name module to retrieve number of records from
1937 * @param query allows webservice user to provide a WHERE clause
1938 * @param deleted specify whether or not to include deleted records
1940 @return get_entries_count_result - this is a complex type as defined in SoapTypes.php
1942 function get_entries_count($session, $module_name, $query, $deleted) {
1943 global $beanList, $beanFiles, $current_user;
1945 $error = new SoapError();
1947 if (!validate_authenticated($session)) {
1948 $error->set_error('invalid_login');
1950 'result_count' => -1,
1951 'error' => $error->get_soap_array()
1955 if (empty($beanList[$module_name])) {
1956 $error->set_error('no_module');
1958 'result_count' => -1,
1959 'error' => $error->get_soap_array()
1963 if(!check_modules_access($current_user, $module_name, 'list')){
1964 $error->set_error('no_access');
1966 'result_count' => -1,
1967 'error' => $error->get_soap_array()
1971 $class_name = $beanList[$module_name];
1972 require_once($beanFiles[$class_name]);
1973 $seed = new $class_name();
1975 if (!$seed->ACLAccess('ListView')) {
1976 $error->set_error('no_access');
1978 'result_count' => -1,
1979 'error' => $error->get_soap_array()
1983 $sql = 'SELECT COUNT(*) result_count FROM ' . $seed->table_name . ' ';
1986 if (isset($seed->custom_fields)) {
1987 $customJoin = $seed->custom_fields->getJOIN();
1988 $sql .= $customJoin ? $customJoin['join'] : '';
1991 // build WHERE clauses, if any
1992 $where_clauses = array();
1993 if (!empty($query)) {
1994 require_once 'include/SugarSQLValidate.php';
1995 $valid = new SugarSQLValidate();
1996 if(!$valid->validateQueryClauses($query)) {
1997 $GLOBALS['log']->error("Bad query: $query");
1998 $error->set_error('no_access');
2000 'result_count' => -1,
2001 'error' => $error->get_soap_array()
2004 $where_clauses[] = $query;
2006 if ($deleted == 0) {
2007 $where_clauses[] = $seed->table_name . '.deleted = 0';
2010 // if WHERE clauses exist, add them to query
2011 if (!empty($where_clauses)) {
2012 $sql .= ' WHERE ' . implode(' AND ', $where_clauses);
2015 $res = $GLOBALS['db']->query($sql);
2016 $row = $GLOBALS['db']->fetchByAssoc($res);
2019 'result_count' => $row['result_count'],
2020 'error' => $error->get_soap_array()
2025 'set_entries_details',
2026 array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'name_value_lists'=>'tns:name_value_lists', 'select_fields' => 'tns:select_fields'),
2027 array('return'=>'tns:set_entries_detail_result'),
2031 * Update or create a list of SugarBeans, returning details about the records created/updated
2033 * @param String $session -- Session ID returned by a previous call to login.
2034 * @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)..
2035 * @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.
2036 * @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.
2037 * @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.
2038 * 'error' -- The SOAP error if any.
2040 function set_entries_details($session, $module_name, $name_value_lists, $select_fields) {
2041 $error = new SoapError();
2043 if(!validate_authenticated($session)){
2044 $error->set_error('invalid_login');
2048 'error' => $error->get_soap_array()
2052 return handle_set_entries($module_name, $name_value_lists, $select_fields);
2055 // INTERNAL FUNCTION NOT EXPOSED THROUGH API
2056 function handle_set_entries($module_name, $name_value_lists, $select_fields = FALSE) {
2057 global $beanList, $beanFiles, $app_list_strings, $current_user;
2059 $error = new SoapError();
2060 $ret_values = array();
2062 if(empty($beanList[$module_name])){
2063 $error->set_error('no_module');
2064 return array('ids'=>array(), 'error'=>$error->get_soap_array());
2067 if(!check_modules_access($current_user, $module_name, 'write')){
2068 $error->set_error('no_access');
2069 return array('ids'=>-1, 'error'=>$error->get_soap_array());
2072 $class_name = $beanList[$module_name];
2073 require_once($beanFiles[$class_name]);
2076 $total = sizeof($name_value_lists);
2078 foreach($name_value_lists as $name_value_list){
2079 $seed = new $class_name();
2081 $seed->update_vcal = false;
2083 //See if we can retrieve the seed by a given id value
2084 foreach($name_value_list as $value)
2086 if($value['name'] == 'id')
2088 $seed->retrieve($value['value']);
2094 $dataValues = array();
2096 foreach($name_value_list as $value)
2098 $val = $value['value'];
2100 if($seed->field_name_map[$value['name']]['type'] == 'enum' || $seed->field_name_map[$value['name']]['type'] == 'radioenum')
2102 $vardef = $seed->field_name_map[$value['name']];
2103 if(isset($app_list_strings[$vardef['options']]) && !isset($app_list_strings[$vardef['options']][$val]) )
2105 if ( in_array($val,$app_list_strings[$vardef['options']]) )
2107 $val = array_search($val,$app_list_strings[$vardef['options']]);
2111 } else if($seed->field_name_map[$value['name']]['type'] == 'multienum') {
2113 $vardef = $seed->field_name_map[$value['name']];
2115 if(isset($app_list_strings[$vardef['options']]) && !isset($app_list_strings[$vardef['options']][$value]) )
2117 $items = explode(",", $val);
2118 $parsedItems = array();
2119 foreach ($items as $item)
2121 if ( in_array($item, $app_list_strings[$vardef['options']]) )
2123 $keyVal = array_search($item,$app_list_strings[$vardef['options']]);
2124 array_push($parsedItems, $keyVal);
2128 if (!empty($parsedItems))
2130 $val = encodeMultienumValue($parsedItems);
2135 //Apply the non-empty values now since this will be used for duplicate checks
2136 //allow string or int of 0 to be updated if set.
2137 if(!empty($val) || ($val==='0' || $val===0))
2139 $seed->$value['name'] = $val;
2141 //Store all the values in dataValues Array to apply later
2142 $dataValues[$value['name']] = $val;
2145 if($count == $total)
2147 $seed->update_vcal = false;
2151 //Add the account to a contact
2152 if($module_name == 'Contacts'){
2153 $GLOBALS['log']->debug('Creating Contact Account');
2154 add_create_account($seed);
2155 $duplicate_id = check_for_duplicate_contacts($seed);
2156 if($duplicate_id == null)
2158 if($seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete')))
2160 //Now apply the values, since this is not a duplicate we can just pass false for the $firstSync argument
2161 apply_values($seed, $dataValues, false);
2163 if($seed->deleted == 1){
2164 $seed->mark_deleted($seed->id);
2169 //since we found a duplicate we should set the sync flag
2170 if( $seed->ACLAccess('Save'))
2172 //Determine if this is a first time sync. We find out based on whether or not a contacts_users relationship exists
2173 $seed->id = $duplicate_id;
2174 $seed->load_relationship("user_sync");
2175 $beans = $seed->user_sync->getBeans();
2176 $first_sync = empty($beans);
2178 //Now apply the values and indicate whether or not this is a first time sync
2179 apply_values($seed, $dataValues, $first_sync);
2180 $seed->contacts_users_id = $current_user->id;
2182 $ids[] = $duplicate_id;//we have a conflict
2186 } else if($module_name == 'Meetings' || $module_name == 'Calls'){
2187 //we are going to check if we have a meeting in the system
2188 //with the same outlook_id. If we do find one then we will grab that
2190 if( $seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
2191 if(empty($seed->id) && !isset($seed->id)){
2192 if(!empty($seed->outlook_id) && isset($seed->outlook_id)){
2193 //at this point we have an object that does not have
2194 //the id set, but does have the outlook_id set
2195 //so we need to query the db to find if we already
2196 //have an object with this outlook_id, if we do
2197 //then we can set the id, otherwise this is a new object
2199 $query = $seed->table_name.".outlook_id = '".$seed->outlook_id."'";
2200 $response = $seed->get_list($order_by, $query, 0,-1,-1,0);
2201 $list = $response['list'];
2202 if(count($list) > 0){
2203 foreach($list as $value)
2205 $seed->id = $value->id;
2211 if (empty($seed->reminder_time)) {
2212 $seed->reminder_time = -1;
2214 if($seed->reminder_time == -1){
2215 $defaultRemindrTime = $current_user->getPreference('reminder_time');
2216 if ($defaultRemindrTime != -1){
2217 $seed->reminder_checked = '1';
2218 $seed->reminder_time = $defaultRemindrTime;
2222 if ($seed->deleted == 1) {
2223 $seed->mark_deleted($seed->id);
2230 if( $seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
2236 // if somebody is calling set_entries_detail() and wants fields returned...
2237 if ($select_fields !== FALSE) {
2238 $ret_values[$count] = array();
2240 foreach ($select_fields as $select_field) {
2241 if (isset($seed->$select_field)) {
2242 $ret_values[$count][] = get_name_value($select_field, $seed->$select_field);
2248 // handle returns for set_entries_detail() and set_entries()
2249 if ($select_fields !== FALSE) {
2251 'name_value_lists' => $ret_values,
2252 'error' => $error->get_soap_array()
2258 'error' => $error->get_soap_array()