]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - soap/SoapSugarUsers.php
Release 6.2.1
[Github/sugarcrm.git] / soap / SoapSugarUsers.php
1 <?php
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-2011 SugarCRM Inc.
6  * 
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.
13  * 
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
17  * details.
18  * 
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
22  * 02110-1301 USA.
23  * 
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.
26  * 
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.
30  * 
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  ********************************************************************************/
37
38 require_once('soap/SoapHelperFunctions.php');
39 require_once('soap/SoapTypes.php');
40
41 /*************************************************************************************
42
43 THIS IS FOR SUGARCRM USERS
44
45
46 *************************************************************************************/
47 $disable_date_format = true;
48
49 $server->register(
50     'is_user_admin',
51     array('session'=>'xsd:string'),
52     array('return'=>'xsd:int'),
53     $NAMESPACE);
54
55 /**
56  * Return if the user is an admin or not
57  *
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
60  */
61 function is_user_admin($session){
62         if(validate_authenticated($session)){
63                 global $current_user;
64                 return is_admin($current_user);
65
66         }else{
67                 return 0;
68         }
69 }
70
71
72 $server->register(
73         'login',
74         array('user_auth'=>'tns:user_auth', 'application_name'=>'xsd:string'),
75         array('return'=>'tns:set_entry_result'),
76         $NAMESPACE);
77
78 /**
79  * Log the user into the application
80  *
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.
87  */
88 function login($user_auth, $application){
89         global $sugar_config, $system_config;
90
91         $error = new SoapError();
92         $user = new User();
93         $success = false;
94         //rrs
95                 $system_config = new Administration();
96         $system_config->retrieveSettings('system');
97         $authController = new AuthenticationController((!empty($sugar_config['authenticationClass'])? $sugar_config['authenticationClass'] : 'SugarAuthenticate'));
98         //rrs
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']);
101         if($usr_id) {
102                 $user->retrieve($usr_id);
103         }
104
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);
112                 } // if
113                 if(!empty($user) && !empty($user->id) && !$user->is_group) {
114                         $success = true;
115                         global $current_user;
116                         $current_user = $user;
117                 } // if
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'])){
128                         $success = true;
129                 } // if
130         } // else if
131
132         if($success){
133                 session_start();
134                 global $current_user;
135                 //$current_user = $user;
136                 login_success();
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'];
145
146                 $current_user->call_custom_logic('after_login');
147                 return array('id'=>session_id(), 'error'=>$error);
148         }
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);
154
155 }
156
157 //checks if the soap server and client are running on the same machine
158 $server->register(
159         'is_loopback',
160         array(),
161         array('return'=>'xsd:int'),
162         $NAMESPACE);
163
164 /**
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.
167  *
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.
170  */
171 function is_loopback(){
172         if(query_client_ip() == $_SERVER['SERVER_ADDR'])
173                 return 1;
174         return 0;
175 }
176
177 /**
178  * Validate the provided session information is correct and current.  Load the session.
179  *
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.
183  */
184 function validate_authenticated($session_id){
185         if(!empty($session_id)){
186                 session_id($session_id);
187                 session_start();
188
189                 if(!empty($_SESSION['is_valid_session']) && is_valid_ip_address('ip_address') && $_SESSION['type'] == 'user'){
190
191                         global $current_user;
192
193                         $current_user = new User();
194                         $current_user->retrieve($_SESSION['user_id']);
195                         login_success();
196                         return true;
197                 }
198
199                 session_destroy();
200         }
201         LogicHook::initialize();
202         $GLOBALS['log']->fatal('SECURITY: The session ID is invalid');
203         $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed');
204         return false;
205 }
206
207 /**
208  * Use the same logic as in SugarAuthenticate to validate the ip address
209  *
210  * @param string $session_var
211  * @return bool - true if the ip address is valid, false otherwise.
212  */
213 function is_valid_ip_address($session_var){
214         global $sugar_config;
215         // grab client ip address
216         $clientIP = query_client_ip();
217         $classCheck = 0;
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) {
226                 $classCheck = 0;
227             }else {
228                         // match class C IP addresses
229                         for ($i = 0; $i < 3; $i ++) {
230                                 if ($session_parts[$i] == $client_parts[$i]) {
231                                         $classCheck = 1;
232                                                 continue;
233                                 } else {
234                                         $classCheck = 0;
235                                         break;
236                                         }
237                                 }
238                 }
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}");
242                                         return false;
243                                 }
244                         } else {
245                                 return false;
246                         }
247         }
248         return true;
249 }
250
251 $server->register(
252     'seamless_login',
253     array('session'=>'xsd:string'),
254     array('return'=>'xsd:int'),
255     $NAMESPACE);
256
257 /**
258  * Perform a seamless login.  This is used internally during the sync process.
259  *
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
263  */
264 function seamless_login($session){
265                 if(!validate_authenticated($session)){
266                         return 0;
267                 }
268                 $_SESSION['seamless_login'] = true;
269                 return 1;
270 }
271
272 $server->register(
273     'get_entry_list',
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'),
276     $NAMESPACE);
277
278 /**
279  * Retrieve a list of beans.  This is the primary method for getting list of SugarBeans from Sugar using the SOAP API.
280  *
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
299  */
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());
306         }
307     $using_cp = false;
308     if($module_name == 'CampaignProspects'){
309         $module_name = 'Prospects';
310         $using_cp = true;
311     }
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());
315         }
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());
320         }
321
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;
326         }
327
328
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')))
333         {
334                 $error->set_error('no_access');
335                 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
336         }
337         if($query == ''){
338                 $where = '';
339         }
340         if($offset == '' || $offset == -1){
341                 $offset = 0;
342         }
343     if($using_cp){
344         $response = $seed->retrieveTargetList($query, $select_fields, $offset,-1,-1,$deleted);
345     }else{
346            $response = $seed->get_list($order_by, $query, $offset,-1,-1,$deleted,true);
347     }
348         $list = $response['list'];
349
350
351         $output_list = array();
352
353     $isEmailModule = false;
354     if($module_name == 'Emails'){
355         $isEmailModule = true;
356     }
357         // retrieve the vardef information on the bean's fields.
358         $field_list = array();
359         foreach($list as $value)
360         {
361                 if(isset($value->emailAddress)){
362                         $value->emailAddress->handleLegacyRetrieve($value);
363                 }
364         if($isEmailModule){
365             $value->retrieveEmailText();
366         }
367                 $value->fill_in_additional_detail_fields();
368                 $output_list[] = get_return_value($value, $module_name);
369                 if(empty($field_list)){
370                         $field_list = get_field_list($value);
371                 }
372         }
373
374         // Filter the search results to only include the requested fields.
375         $output_list = filter_return_list($output_list, $select_fields, $module_name);
376
377         // Filter the list of fields to only include information on the requested fields.
378         $field_list = filter_return_list($field_list,$select_fields, $module_name);
379
380         // Calculate the offset for the start of the next page
381         $next_offset = $offset + sizeof($output_list);
382
383         return array('result_count'=>sizeof($output_list), 'next_offset'=>$next_offset,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
384 }
385
386 $server->register(
387     'get_entry',
388     array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'id'=>'xsd:string', 'select_fields'=>'tns:select_fields'),
389     array('return'=>'tns:get_entry_result'),
390     $NAMESPACE);
391
392 /**
393  * Retrieve a single SugarBean based on ID.
394  *
395  * @param String $session -- Session ID returned by a previous call to login.
396  * @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)..
397  * @param String $id -- The SugarBean's ID value.
398  * @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.
399  * @return unknown
400  */
401 function get_entry($session, $module_name, $id,$select_fields ){
402         return get_entries($session, $module_name, array($id), $select_fields);
403 }
404
405 $server->register(
406     'get_entries',
407     array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'ids'=>'tns:select_fields', 'select_fields'=>'tns:select_fields'),
408     array('return'=>'tns:get_entry_result'),
409     $NAMESPACE);
410
411 /**
412  * Retrieve a list of SugarBean's based on provided IDs.
413  *
414  * @param String $session -- Session ID returned by a previous call to login.
415  * @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)..
416  * @param Array $ids -- An array of SugarBean IDs.
417  * @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.
418  * @return Array 'field_list' -- Var def information about the returned fields
419  *               'entry_list' -- The records that were retrieved
420  *               'error' -- The SOAP error, if any
421  */
422 function get_entries($session, $module_name, $ids,$select_fields ){
423         global  $beanList, $beanFiles;
424         $error = new SoapError();
425         $field_list = array();
426         $output_list = array();
427         if(!validate_authenticated($session)){
428                 $error->set_error('invalid_login');
429                 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
430         }
431     $using_cp = false;
432     if($module_name == 'CampaignProspects'){
433         $module_name = 'Prospects';
434         $using_cp = true;
435     }
436         if(empty($beanList[$module_name])){
437                 $error->set_error('no_module');
438                 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
439         }
440         global $current_user;
441         if(!check_modules_access($current_user, $module_name, 'read')){
442                 $error->set_error('no_access');
443                 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
444         }
445
446         $class_name = $beanList[$module_name];
447         require_once($beanFiles[$class_name]);
448
449         //todo can modify in there to call bean->get_list($order_by, $where, 0, -1, -1, $deleted);
450         //that way we do not have to call retrieve for each bean
451         //perhaps also add a select_fields to this, so we only get the fields we need
452         //and not do a select *
453         foreach($ids as $id){
454                 $seed = new $class_name();
455
456     if($using_cp){
457         $seed = $seed->retrieveTarget($id);
458     }else{
459                 if ($seed->retrieve($id) == null)
460                         $seed->deleted = 1;
461     }
462
463     if ($seed->deleted == 1) {
464         $list = array();
465         $list[] = array('name'=>'warning', 'value'=>'Access to this object is denied since it has been deleted or does not exist');
466                 $list[] = array('name'=>'deleted', 'value'=>'1');
467         $output_list[] = Array('id'=>$id,
468                                                                 'module_name'=> $module_name,
469                                                         'name_value_list'=>$list,
470                                                         );
471                 continue;
472     }
473         if(! $seed->ACLAccess('DetailView')){
474                 $error->set_error('no_access');
475                 return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
476         }
477                 $output_list[] = get_return_value($seed, $module_name);
478
479                 if(empty($field_list)){
480                                 $field_list = get_field_list($seed);
481
482                 }
483         }
484
485                 $output_list = filter_return_list($output_list, $select_fields, $module_name);
486                 $field_list = filter_field_list($field_list,$select_fields, $module_name);
487
488         return array( 'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
489 }
490
491 $server->register(
492     'set_entry',
493     array('session'=>'xsd:string', 'module_name'=>'xsd:string',  'name_value_list'=>'tns:name_value_list'),
494     array('return'=>'tns:set_entry_result'),
495     $NAMESPACE);
496
497 /**
498  * Update or create a single SugarBean.
499  *
500  * @param String $session -- Session ID returned by a previous call to login.
501  * @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)..
502  * @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.
503  * @return Array    'id' -- the ID of the bean that was written to (-1 on error)
504  *                  'error' -- The SOAP error if any.
505  */
506 function set_entry($session,$module_name, $name_value_list){
507         global  $beanList, $beanFiles;
508
509         $error = new SoapError();
510         if(!validate_authenticated($session)){
511                 $error->set_error('invalid_login');
512                 return array('id'=>-1, 'error'=>$error->get_soap_array());
513         }
514         if(empty($beanList[$module_name])){
515                 $error->set_error('no_module');
516                 return array('id'=>-1, 'error'=>$error->get_soap_array());
517         }
518         global $current_user;
519         if(!check_modules_access($current_user, $module_name, 'write')){
520                 $error->set_error('no_access');
521                 return array('id'=>-1, 'error'=>$error->get_soap_array());
522         }
523
524         $class_name = $beanList[$module_name];
525         require_once($beanFiles[$class_name]);
526         $seed = new $class_name();
527
528         foreach($name_value_list as $value){
529         if($value['name'] == 'id' && isset($value['value']) && strlen($value['value']) > 0){
530                         $result = $seed->retrieve($value['value']);
531             //bug: 44680 - check to ensure the user has access before proceeding.
532             if(is_null($result))
533             {
534                 $error->set_error('no_access');
535                         return array('id'=>-1, 'error'=>$error->get_soap_array());
536             }
537             else
538             {
539                 break;
540             }
541
542                 }
543         }
544         foreach($name_value_list as $value){
545         $GLOBALS['log']->debug($value['name']." : ".$value['value']);
546                 $seed->$value['name'] = $value['value'];
547         }
548         if(! $seed->ACLAccess('Save') || ($seed->deleted == 1  &&  !$seed->ACLAccess('Delete')))
549         {
550                 $error->set_error('no_access');
551                 return array('id'=>-1, 'error'=>$error->get_soap_array());
552         }
553         $seed->save();
554         if($seed->deleted == 1){
555                         $seed->mark_deleted($seed->id);
556         }
557         return array('id'=>$seed->id, 'error'=>$error->get_soap_array());
558
559 }
560
561 $server->register(
562     'set_entries',
563     array('session'=>'xsd:string', 'module_name'=>'xsd:string',  'name_value_lists'=>'tns:name_value_lists'),
564     array('return'=>'tns:set_entries_result'),
565     $NAMESPACE);
566
567 /**
568  * Update or create a list of SugarBeans
569  *
570  * @param String $session -- Session ID returned by a previous call to login.
571  * @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)..
572  * @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.
573  * @return Array    'ids' -- Array of the IDs of the beans that was written to (-1 on error)
574  *                  'error' -- The SOAP error if any.
575  */
576 function set_entries($session,$module_name, $name_value_lists){
577         $error = new SoapError();
578
579         if(!validate_authenticated($session)){
580                 $error->set_error('invalid_login');
581
582                 return array(
583                         'ids' => array(),
584                         'error' => $error->get_soap_array()
585                 );
586         }
587
588         return handle_set_entries($module_name, $name_value_lists, FALSE);
589 }
590
591 /*
592 NOTE SPECIFIC CODE
593 */
594 $server->register(
595         'set_note_attachment',
596         array('session'=>'xsd:string','note'=>'tns:note_attachment'),
597         array('return'=>'tns:set_entry_result'),
598         $NAMESPACE);
599
600 /**
601  * Add or replace the attachment on a Note.
602  *
603  * @param String $session -- Session ID returned by a previous call to login.
604  * @param Binary $note -- The flie contents of the attachment.
605  * @return Array 'id' -- The ID of the new note or -1 on error
606  *               'error' -- The SOAP error if any.
607  */
608 function set_note_attachment($session,$note)
609 {
610
611         $error = new SoapError();
612         if(!validate_authenticated($session)){
613                 $error->set_error('invalid_login');
614                 return array('id'=>-1, 'error'=>$error->get_soap_array());
615         }
616
617         require_once('modules/Notes/NoteSoap.php');
618         $ns = new NoteSoap();
619         return array('id'=>$ns->saveFile($note), 'error'=>$error->get_soap_array());
620
621 }
622
623 $server->register(
624     'get_note_attachment',
625     array('session'=>'xsd:string', 'id'=>'xsd:string'),
626     array('return'=>'tns:return_note_attachment'),
627     $NAMESPACE);
628
629 /**
630  * Retrieve an attachment from a note
631  * @param String $session -- Session ID returned by a previous call to login.
632  * @param Binary $note -- The flie contents of the attachment.
633  * @return Array 'id' -- The ID of the new note or -1 on error
634  *               'error' -- The SOAP error if any.
635  *
636  * @param String $session -- Session ID returned by a previous call to login.
637  * @param String $id -- The ID of the appropriate Note.
638  * @return Array 'note_attachment' -- Array String 'id' -- The ID of the Note containing the attachment
639  *                                          String 'filename' -- The file name of the attachment
640  *                                          Binary 'file' -- The binary contents of the file.
641  *               'error' -- The SOAP error if any.
642  */
643 function get_note_attachment($session,$id)
644 {
645         $error = new SoapError();
646         if(!validate_authenticated($session)){
647                 $error->set_error('invalid_login');
648                 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
649         }
650
651         $note = new Note();
652
653         $note->retrieve($id);
654         if(!$note->ACLAccess('DetailView')){
655                 $error->set_error('no_access');
656                 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
657         }
658         require_once('modules/Notes/NoteSoap.php');
659         $ns = new NoteSoap();
660         if(!isset($note->filename)){
661                 $note->filename = '';
662         }
663         $file= $ns->retrieveFile($id,$note->filename);
664         if($file == -1){
665                 $error->set_error('no_file');
666                 $file = '';
667         }
668
669         return array('note_attachment'=>array('id'=>$id, 'filename'=>$note->filename, 'file'=>$file), 'error'=>$error->get_soap_array());
670
671 }
672 $server->register(
673     'relate_note_to_module',
674     array('session'=>'xsd:string', 'note_id'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string'),
675     array('return'=>'tns:error_value'),
676     $NAMESPACE);
677
678 /**
679  * Attach a note to another bean.  Once you have created a note to store an
680  * attachment, the note needs to be related to the bean.
681  *
682  * @param String $session -- Session ID returned by a previous call to login.
683  * @param String $note_id -- The ID of the note that you want to associate with a bean
684  * @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)..
685  * @param String $module_id -- The ID of the bean that you want to associate the note with
686  * @return no error for success, error for failure
687  */
688 function relate_note_to_module($session,$note_id, $module_name, $module_id){
689         global  $beanList, $beanFiles;
690         $error = new SoapError();
691         if(!validate_authenticated($session)){
692                 $error->set_error('invalid_login');
693                 return $error->get_soap_array();
694         }
695         if(empty($beanList[$module_name])){
696                 $error->set_error('no_module');
697                 return $error->get_soap_array();
698         }
699         global $current_user;
700         if(!check_modules_access($current_user, $module_name, 'read')){
701                 $error->set_error('no_access');
702                 return $error->get_soap_array();
703         }
704         $class_name = $beanList['Notes'];
705         require_once($beanFiles[$class_name]);
706         $seed = new $class_name();
707         $seed->retrieve($note_id);
708         if(!$seed->ACLAccess('ListView')){
709                 $error->set_error('no_access');
710                 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
711         }
712
713         if($module_name != 'Contacts'){
714                 $seed->parent_type=$module_name;
715                 $seed->parent_id = $module_id;
716
717         }else{
718
719                 $seed->contact_id=$module_id;
720
721         }
722
723         $seed->save();
724
725         return $error->get_soap_array();
726
727 }
728 $server->register(
729     'get_related_notes',
730     array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string', 'select_fields'=>'tns:select_fields'),
731     array('return'=>'tns:get_entry_result'),
732     $NAMESPACE);
733
734 /**
735  * Retrieve the collection of notes that are related to a bean.
736  *
737  * @param String $session -- Session ID returned by a previous call to login.
738  * @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)..
739  * @param String $module_id -- The ID of the bean that you want to associate the note with
740  * @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.
741  * @return Array    'result_count' -- The number of records returned (-1 on error)
742  *                  '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.
743  *                  'field_list' -- The vardef information on the selected fields.
744  *                  'entry_list' -- The records that were retrieved
745  *                  'error' -- The SOAP error, if any
746  */
747 function get_related_notes($session,$module_name, $module_id, $select_fields){
748         global  $beanList, $beanFiles;
749         $error = new SoapError();
750         if(!validate_authenticated($session)){
751                 $error->set_error('invalid_login');
752                 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
753         }
754         if(empty($beanList[$module_name])){
755                 $error->set_error('no_module');
756                 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
757         }
758         global $current_user;
759         if(!check_modules_access($current_user, $module_name, 'read')){
760                 $error->set_error('no_access');
761                 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
762         }
763
764         $class_name = $beanList[$module_name];
765         require_once($beanFiles[$class_name]);
766         $seed = new $class_name();
767         $seed->retrieve($module_id);
768         if(!$seed->ACLAccess('DetailView')){
769                 $error->set_error('no_access');
770                 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
771         }
772         $list = $seed->get_linked_beans('notes','Note', array(), 0, -1, 0);
773
774         $output_list = Array();
775         $field_list = Array();
776         foreach($list as $value)
777         {
778                 $output_list[] = get_return_value($value, 'Notes');
779         if(empty($field_list))
780         {
781                         $field_list = get_field_list($value);
782                 }
783         }
784         $output_list = filter_return_list($output_list, $select_fields, $module_name);
785         $field_list = filter_field_list($field_list,$select_fields, $module_name);
786
787         return array('result_count'=>sizeof($output_list), 'next_offset'=>0,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
788 }
789
790 $server->register(
791         'logout',
792         array('session'=>'xsd:string'),
793         array('return'=>'tns:error_value'),
794         $NAMESPACE);
795
796 /**
797  * Log out of the session.  This will destroy the session and prevent other's from using it.
798  *
799  * @param String $session -- Session ID returned by a previous call to login.
800  * @return Empty error on success, Error on failure
801  */
802 function logout($session){
803         global $current_user;
804
805         $error = new SoapError();
806         LogicHook::initialize();
807         if(validate_authenticated($session)){
808                 $current_user->call_custom_logic('before_logout');
809                 session_destroy();
810                 $GLOBALS['logic_hook']->call_custom_logic('Users', 'after_logout');
811                 return $error->get_soap_array();
812         }
813         $error->set_error('no_session');
814         $GLOBALS['logic_hook']->call_custom_logic('Users', 'after_logout');
815         return $error->get_soap_array();
816 }
817
818 $server->register(
819     'get_module_fields',
820     array('session'=>'xsd:string', 'module_name'=>'xsd:string'),
821     array('return'=>'tns:module_fields'),
822     $NAMESPACE);
823
824 /**
825  * Retrieve vardef information on the fields of the specified bean.
826  *
827  * @param String $session -- Session ID returned by a previous call to login.
828  * @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)..
829  * @return Array    'module_fields' -- The vardef information on the selected fields.
830  *                  'error' -- The SOAP error, if any
831  */
832 function get_module_fields($session, $module_name){
833         global  $beanList, $beanFiles;
834         $error = new SoapError();
835         $module_fields = array();
836         if(! validate_authenticated($session)){
837                 $error->set_error('invalid_session');
838                 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
839         }
840         if(empty($beanList[$module_name])){
841                 $error->set_error('no_module');
842                 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
843         }
844         global $current_user;
845         if(!check_modules_access($current_user, $module_name, 'read')){
846                 $error->set_error('no_access');
847                 return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
848         }
849         $class_name = $beanList[$module_name];
850
851         if(empty($beanFiles[$class_name]))
852         {
853        $error->set_error('no_file');
854        return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
855         }
856
857         require_once($beanFiles[$class_name]);
858         $seed = new $class_name();
859         if($seed->ACLAccess('ListView', true) || $seed->ACLAccess('DetailView', true) ||        $seed->ACLAccess('EditView', true) )
860     {
861         return get_return_module_fields($seed, $module_name, $error);
862     }
863     else
864     {
865         $error->set_error('no_access');
866         return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
867     }
868 }
869
870 $server->register(
871     'get_available_modules',
872     array('session'=>'xsd:string'),
873     array('return'=>'tns:module_list'),
874     $NAMESPACE);
875
876 /**
877  * Retrieve the list of available modules on the system available to the currently logged in user.
878  *
879  * @param String $session -- Session ID returned by a previous call to login.
880  * @return Array    'modules' -- An array of module names
881  *                  'error' -- The SOAP error, if any
882  */
883 function get_available_modules($session){
884         $error = new SoapError();
885         $modules = array();
886         if(! validate_authenticated($session)){
887                 $error->set_error('invalid_session');
888                 return array('modules'=> $modules, 'error'=>$error->get_soap_array());
889         }
890         $modules = array_keys($_SESSION['avail_modules']);
891
892         return array('modules'=> $modules, 'error'=>$error->get_soap_array());
893 }
894
895
896 $server->register(
897     'update_portal_user',
898     array('session'=>'xsd:string', 'portal_name'=>'xsd:string', 'name_value_list'=>'tns:name_value_list'),
899     array('return'=>'tns:error_value'),
900     $NAMESPACE);
901
902 /**
903  * Update the properties of a contact that is portal user.  Add the portal user name to the user's properties.
904  *
905  * @param String $session -- Session ID returned by a previous call to login.
906  * @param String $portal_name -- The portal user_name of the contact
907  * @param Array $name_value_list -- collection of 'name'=>'value' pairs for finding the contact
908  * @return Empty error on success, Error on failure
909  */
910 function update_portal_user($session,$portal_name, $name_value_list){
911         global  $beanList, $beanFiles;
912         $error = new SoapError();
913         if(! validate_authenticated($session)){
914                 $error->set_error('invalid_session');
915                 return $error->get_soap_array();
916         }
917         $contact = new Contact();
918
919         $searchBy = array('deleted'=>0);
920         foreach($name_value_list as $name_value){
921                         $searchBy[$name_value['name']] = $name_value['value'];
922         }
923         if($contact->retrieve_by_string_fields($searchBy) != null){
924                 if(!$contact->duplicates_found){
925                         $contact->portal_name = $portal_name;
926                         $contact->portal_active = 1;
927                         if($contact->ACLAccess('Save')){
928                                 $contact->save();
929                         }else{
930                                 $error->set_error('no_access');
931                         }
932                         return $error->get_soap_array();
933                 }
934                 $error->set_error('duplicates');
935                 return $error->get_soap_array();
936         }
937         $error->set_error('no_records');
938         return $error->get_soap_array();
939 }
940
941 $server->register(
942     'get_user_id',
943     array('session'=>'xsd:string'),
944     array('return'=>'xsd:string'),
945     $NAMESPACE);
946
947 /**
948  * Return the user_id of the user that is logged into the current session.
949  *
950  * @param String $session -- Session ID returned by a previous call to login.
951  * @return String -- the User ID of the current session
952  *                  -1 on error.
953  */
954 function get_user_id($session){
955         if(validate_authenticated($session)){
956                 global $current_user;
957                 return $current_user->id;
958
959         }else{
960                 return '-1';
961         }
962 }
963
964 $server->register(
965     'get_user_team_id',
966     array('session'=>'xsd:string'),
967     array('return'=>'xsd:string'),
968     $NAMESPACE);
969
970 /**
971  * Return the ID of the default team for the user that is logged into the current session.
972  *
973  * @param String $session -- Session ID returned by a previous call to login.
974  * @return String -- the Team ID of the current user's default team
975  *                  1 for Community Edition
976  *                  -1 on error.
977  */
978 function get_user_team_id($session){
979         if(validate_authenticated($session))
980         {
981                  return 1;
982         }else{
983                 return '-1';
984         }
985 }
986
987 $server->register(
988     'get_server_time',
989     array(),
990     array('return'=>'xsd:string'),
991     $NAMESPACE);
992
993 /**
994  * 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.
995  *
996  * @return String -- The current date/time 'Y-m-d H:i:s'
997  */
998 function get_server_time(){
999         return date('Y-m-d H:i:s');
1000 }
1001
1002 $server->register(
1003     'get_gmt_time',
1004     array(),
1005     array('return'=>'xsd:string'),
1006     $NAMESPACE);
1007
1008 /**
1009  * Return the current time on the server in the format 'Y-m-d H:i:s'.  This time is in GMT.
1010  *
1011  * @return String -- The current date/time 'Y-m-d H:i:s'
1012  */
1013 function get_gmt_time(){
1014         return TimeDate::getInstance()->nowDb();
1015 }
1016
1017 $server->register(
1018     'get_sugar_flavor',
1019     array(),
1020     array('return'=>'xsd:string'),
1021     $NAMESPACE);
1022
1023 /**
1024  * Retrieve the specific flavor of sugar.
1025  *
1026  * @return String   'CE' -- For Community Edition
1027  *                  'PRO' -- For Professional
1028  *                  'ENT' -- For Enterprise
1029  */
1030 function get_sugar_flavor(){
1031  global $sugar_flavor;
1032
1033  return $sugar_flavor;
1034 }
1035
1036
1037 $server->register(
1038     'get_server_version',
1039     array(),
1040     array('return'=>'xsd:string'),
1041     $NAMESPACE);
1042
1043 /**
1044  * Retrieve the version number of Sugar that the server is running.
1045  *
1046  * @return String -- The current sugar version number.
1047  *                   '1.0' on error.
1048  */
1049 function get_server_version(){
1050
1051         $admin  = new Administration();
1052         $admin->retrieveSettings('info');
1053         if(isset($admin->settings['info_sugar_version'])){
1054                 return $admin->settings['info_sugar_version'];
1055         }else{
1056                 return '1.0';
1057         }
1058
1059 }
1060
1061 $server->register(
1062     'get_relationships',
1063     array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string', 'related_module'=>'xsd:string', 'related_module_query'=>'xsd:string', 'deleted'=>'xsd:int'),
1064     array('return'=>'tns:get_relationships_result'),
1065     $NAMESPACE);
1066
1067 /**
1068  * Retrieve a collection of beans tha are related to the specified bean.
1069  * As of 4.5.1c, all combinations of related modules are supported
1070  *
1071  * @param String $session -- Session ID returned by a previous call to login.
1072  * @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)..
1073  * @param String $module_id -- The ID of the bean in the specified module
1074  * @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)..
1075  * @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.
1076  * @param Number $deleted -- false if deleted records should not be include, true if deleted records should be included.
1077  * @return unknown
1078  */
1079 function get_relationships($session, $module_name, $module_id, $related_module, $related_module_query, $deleted){
1080                 $error = new SoapError();
1081         $ids = array();
1082         if(!validate_authenticated($session)){
1083                 $error->set_error('invalid_login');
1084                 return array('ids'=>$ids,'error'=> $error->get_soap_array());
1085         }
1086         global  $beanList, $beanFiles;
1087         $error = new SoapError();
1088
1089         if(empty($beanList[$module_name]) || empty($beanList[$related_module])){
1090                 $error->set_error('no_module');
1091                 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1092         }
1093         $class_name = $beanList[$module_name];
1094         require_once($beanFiles[$class_name]);
1095         $mod = new $class_name();
1096         $mod->retrieve($module_id);
1097         if(!$mod->ACLAccess('DetailView')){
1098                 $error->set_error('no_access');
1099                 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1100         }
1101
1102         $id_list = get_linked_records($related_module, $module_name, $module_id);
1103
1104         if ($id_list === FALSE) {
1105                 $error->set_error('no_relationship_support');
1106                 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1107         }
1108         elseif (count($id_list) == 0) {
1109                 return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1110         }
1111
1112         $list = array();
1113
1114         $id_list_quoted = array_map(create_function('$str','return "\'" . $str . "\'";'), $id_list);
1115         $in = implode(", ", $id_list_quoted);
1116
1117         $related_class_name = $beanList[$related_module];
1118         require_once($beanFiles[$related_class_name]);
1119         $related_mod = new $related_class_name();
1120
1121         $sql = "SELECT {$related_mod->table_name}.id FROM {$related_mod->table_name} ";
1122
1123
1124         $sql .= " WHERE {$related_mod->table_name}.id IN ({$in}) ";
1125
1126         if (!empty($related_module_query)) {
1127                 $sql .= " AND ( {$related_module_query} )";
1128         }
1129
1130         $result = $related_mod->db->query($sql);
1131         while ($row = $related_mod->db->fetchByAssoc($result)) {
1132                 $list[] = $row['id'];
1133         }
1134
1135         $return_list = array();
1136
1137         foreach($list as $id) {
1138                 $related_class_name = $beanList[$related_module];
1139                 $related_mod = new $related_class_name();
1140                 $related_mod->retrieve($id);
1141
1142                 $return_list[] = array(
1143                         'id' => $id,
1144                         'date_modified' => $related_mod->date_modified,
1145                         'deleted' => $related_mod->deleted
1146                 );
1147         }
1148
1149         return array('ids' => $return_list, 'error' => $error->get_soap_array());
1150 }
1151
1152
1153 $server->register(
1154     'set_relationship',
1155     array('session'=>'xsd:string','set_relationship_value'=>'tns:set_relationship_value'),
1156     array('return'=>'tns:error_value'),
1157     $NAMESPACE);
1158
1159 /**
1160  * Set a single relationship between two beans.  The items are related by module name and id.
1161  *
1162  * @param String $session -- Session ID returned by a previous call to login.
1163  * @param Array $set_relationship_value --
1164  *      '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)..
1165  *      'module1_id' -- The ID of the bean in the specified module
1166  *      '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)..
1167  *      'module2_id' -- The ID of the bean in the specified module
1168  * @return Empty error on success, Error on failure
1169  */
1170 function set_relationship($session, $set_relationship_value){
1171         $error = new SoapError();
1172         if(!validate_authenticated($session)){
1173                 $error->set_error('invalid_login');
1174                 return $error->get_soap_array();
1175         }
1176         return handle_set_relationship($set_relationship_value);
1177 }
1178
1179 $server->register(
1180     'set_relationships',
1181     array('session'=>'xsd:string','set_relationship_list'=>'tns:set_relationship_list'),
1182     array('return'=>'tns:set_relationship_list_result'),
1183     $NAMESPACE);
1184
1185 /**
1186  * Setup several relationships between pairs of beans.  The items are related by module name and id.
1187  *
1188  * @param String $session -- Session ID returned by a previous call to login.
1189  * @param Array $set_relationship_list -- One for each relationship to setup.  Each entry is itself an array.
1190  *      '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)..
1191  *      'module1_id' -- The ID of the bean in the specified module
1192  *      '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)..
1193  *      'module2_id' -- The ID of the bean in the specified module
1194  * @return Empty error on success, Error on failure
1195  */
1196 function set_relationships($session, $set_relationship_list){
1197         $error = new SoapError();
1198         if(!validate_authenticated($session)){
1199                 $error->set_error('invalid_login');
1200                 return -1;
1201         }
1202         $count = 0;
1203         $failed = 0;
1204         foreach($set_relationship_list as $set_relationship_value){
1205                 $reter = handle_set_relationship($set_relationship_value);
1206                 if($reter['number'] == 0){
1207                         $count++;
1208                 }else{
1209                         $failed++;
1210                 }
1211         }
1212         return array('created'=>$count , 'failed'=>$failed, 'error'=>$error);
1213 }
1214
1215
1216
1217 //INTERNAL FUNCTION NOT EXPOSED THROUGH SOAP
1218 /**
1219  * (Internal) Create a relationship between two beans.
1220  *
1221  * @param Array $set_relationship_value --
1222  *      '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)..
1223  *      'module1_id' -- The ID of the bean in the specified module
1224  *      '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)..
1225  *      'module2_id' -- The ID of the bean in the specified module
1226  * @return Empty error on success, Error on failure
1227  */
1228 function handle_set_relationship($set_relationship_value)
1229 {
1230     global  $beanList, $beanFiles;
1231     $error = new SoapError();
1232
1233     $module1 = $set_relationship_value['module1'];
1234     $module1_id = $set_relationship_value['module1_id'];
1235     $module2 = $set_relationship_value['module2'];
1236     $module2_id = $set_relationship_value['module2_id'];
1237
1238     if(empty($beanList[$module1]) || empty($beanList[$module2]) )
1239     {
1240         $error->set_error('no_module');
1241         return $error->get_soap_array();
1242     }
1243     $class_name = $beanList[$module1];
1244     require_once($beanFiles[$class_name]);
1245     $mod = new $class_name();
1246     $mod->retrieve($module1_id);
1247         if(!$mod->ACLAccess('DetailView')){
1248                 $error->set_error('no_access');
1249                 return $error->get_soap_array();
1250         }
1251         if($module1 == "Contacts" && $module2 == "Users"){
1252                 $key = 'contacts_users_id';
1253         }
1254         else{
1255         $key = array_search(strtolower($module2),$mod->relationship_fields);
1256         if(!$key) {
1257             $key = Relationship::retrieve_by_modules($module1, $module2, $GLOBALS['db']);
1258             
1259             // BEGIN SnapLogic fix for bug 32064
1260             if ($module1 == "Quotes" && $module2 == "ProductBundles") {
1261                 // Alternative solution is perhaps to 
1262                 // do whatever Sugar does when the same
1263                 // request is received from the web:
1264                 $pb_cls = $beanList[$module2]; 
1265                 $pb = new $pb_cls();
1266                 $pb->retrieve($module2_id);
1267                 
1268                 // Check if this relationship already exists
1269                 $query = "SELECT count(*) AS count FROM product_bundle_quote WHERE quote_id = '{$module1_id}' AND bundle_id = '{$module2_id}' AND deleted = '0'";
1270                 $result = $GLOBALS['db']->query($query, true, "Error checking for previously existing relationship between quote and product_bundle");
1271                 $row = $GLOBALS['db']->fetchByAssoc($result);
1272                 if(isset($row['count']) && $row['count'] > 0){
1273                     return $error->get_soap_array();
1274                 }
1275                 
1276                 $query = "SELECT MAX(bundle_index)+1 AS idx FROM product_bundle_quote WHERE quote_id = '{$module1_id}' AND deleted='0'";
1277                 $result = $GLOBALS['db']->query($query, true, "Error getting bundle_index");
1278                 $GLOBALS['log']->debug("*********** Getting max bundle_index");
1279                 $GLOBALS['log']->debug($query);
1280                 $row = $GLOBALS['db']->fetchByAssoc($result);
1281                 
1282                 $idx = 0;
1283                 if ($row) {
1284                     $idx = $row['idx'];
1285                 }
1286                 
1287                 $pb->set_productbundle_quote_relationship($module1_id,$module2_id,$idx);
1288                 $pb->save();
1289                 return $error->get_soap_array();
1290
1291             } else if ($module1 == "ProductBundles" && $module2 == "Products") {
1292                 // And, well, similar things apply in this case
1293                 $pb_cls = $beanList[$module1];
1294                 $pb = new $pb_cls();
1295                 $pb->retrieve($module1_id);
1296
1297                 // Check if this relationship already exists
1298                 $query = "SELECT count(*) AS count FROM product_bundle_product WHERE bundle_id = '{$module1_id}' AND product_id = '{$module2_id}' AND deleted = '0'";
1299                 $result = $GLOBALS['db']->query($query, true, "Error checking for previously existing relationship between quote and product_bundle");
1300                 $row = $GLOBALS['db']->fetchByAssoc($result);
1301                 if(isset($row['count']) && $row['count'] > 0){
1302                     return $error->get_soap_array();
1303                 }
1304                 
1305                 $query = "SELECT MAX(product_index)+1 AS idx FROM product_bundle_product WHERE bundle_id='{$module1_id}'";
1306                 $result = $GLOBALS['db']->query($query, true, "Error getting bundle_index");
1307                 $GLOBALS['log']->debug("*********** Getting max bundle_index");
1308                 $GLOBALS['log']->debug($query);
1309                 $row = $GLOBALS['db']->fetchByAssoc($result);
1310
1311                 $idx = 0;
1312                 if ($row) {
1313                     $idx = $row['idx'];
1314                 }
1315                 $pb->set_productbundle_product_relationship($module2_id,$idx,$module1_id);
1316                 $pb->save();
1317
1318                 $prod_cls = $beanList[$module2];
1319                 $prod = new $prod_cls();
1320                 $prod->retrieve($module2_id);
1321                 $prod->quote_id = $pb->quote_id;
1322                 $prod->save();
1323                 return $error->get_soap_array();
1324             }
1325             // END SnapLogic fix for bug 32064
1326             
1327                 if (!empty($key)) {
1328                         $mod->load_relationship($key);
1329                         $mod->$key->add($module2_id);
1330                         return $error->get_soap_array();
1331                 } // if
1332         }
1333     }
1334
1335     if(!$key)
1336     {
1337         $error->set_error('no_module');
1338         return $error->get_soap_array();
1339     }
1340
1341     if(($module1 == 'Meetings' || $module1 == 'Calls') && ($module2 == 'Contacts' || $module2 == 'Users')){
1342         $key = strtolower($module2);
1343         $mod->load_relationship($key);
1344         $mod->$key->add($module2_id);
1345     }else{
1346         $mod->$key = $module2_id;
1347         $mod->save_relationship_changes(false);
1348     }
1349
1350     return $error->get_soap_array();
1351 }
1352
1353
1354 $server->register(
1355         'set_document_revision',
1356         array('session'=>'xsd:string','note'=>'tns:document_revision'),
1357         array('return'=>'tns:set_entry_result'),
1358         $NAMESPACE);
1359
1360 /**
1361  * Enter description here...
1362  *
1363  * @param String $session -- Session ID returned by a previous call to login.
1364  * @param unknown_type $document_revision
1365  * @return unknown
1366  */
1367 function set_document_revision($session,$document_revision)
1368 {
1369
1370         $error = new SoapError();
1371         if(!validate_authenticated($session)){
1372                 $error->set_error('invalid_login');
1373                 return array('id'=>-1, 'error'=>$error->get_soap_array());
1374         }
1375
1376         require_once('modules/Documents/DocumentSoap.php');
1377         $dr = new DocumentSoap();
1378         return array('id'=>$dr->saveFile($document_revision), 'error'=>$error->get_soap_array());
1379
1380 }
1381
1382 $server->register(
1383         'search_by_module',
1384         array('user_name'=>'xsd:string','password'=>'xsd:string','search_string'=>'xsd:string', 'modules'=>'tns:select_fields', 'offset'=>'xsd:int', 'max_results'=>'xsd:int'),
1385         array('return'=>'tns:get_entry_list_result'),
1386         $NAMESPACE);
1387
1388 /**
1389  * Given a list of modules to search and a search string, return the id, module_name, along with the fields
1390  * as specified in the $query_array
1391  *
1392  * @param string $user_name             - username of the Sugar User
1393  * @param string $password                      - password of the Sugar User
1394  * @param string $search_string         - string to search
1395  * @param string[] $modules                     - array of modules to query
1396  * @param int $offset                           - a specified offset in the query
1397  * @param int $max_results                      - max number of records to return
1398  * @return get_entry_list_result        - id, module_name, and list of fields from each record
1399  */
1400 function search_by_module($user_name, $password, $search_string, $modules, $offset, $max_results){
1401         global  $beanList, $beanFiles;
1402
1403         $error = new SoapError();
1404         if(!validate_user($user_name, $password)){
1405                 $error->set_error('invalid_login');
1406                 return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
1407         }
1408         global $current_user;
1409         if($max_results > 0){
1410                 global $sugar_config;
1411                 $sugar_config['list_max_entries_per_page'] = $max_results;
1412         }
1413         //  MRF - BUG:19552 - added a join for accounts' emails below
1414         $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"),
1415                                 'Bugs'=>array('where'=>array('Bugs' => array(0 => "bugs.name like '{0}%'", 1 => "bugs.bug_number = {0}")),'fields'=>"bugs.id, bugs.name, bugs.bug_number"),
1416                                                         'Cases'=>array('where'=>array('Cases' => array(0 => "cases.name like '{0}%'", 1 => "cases.case_number = {0}")),'fields'=>"cases.id, cases.name, cases.case_number"),
1417                                                         '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"),
1418                                                         'Project'=>array('where'=>array('Project' => array(0 => "project.name like '{0}%'")), 'fields'=>"project.id, project.name"),
1419                             'ProjectTask'=>array('where'=>array('ProjectTask' => array(0 => "project.id = '{0}'")), 'fields'=>"project_task.id, project_task.name"),
1420                                                         '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"),
1421                                                         'Opportunities'=>array('where'=>array('Opportunities' => array(0 => "opportunities.name like '{0}%'")), 'fields'=>"opportunities.id, opportunities.name"),
1422                                                         'Users'=>array('where'=>array('EmailAddresses' => array(0 => "ea.email_address like '{0}%'")),'fields'=>"users.id, users.user_name, users.first_name, ea.email_address"),
1423                                                 );
1424
1425         if(!empty($search_string) && isset($search_string)){
1426                 foreach($modules as $module_name){
1427                         $class_name = $beanList[$module_name];
1428                         require_once($beanFiles[$class_name]);
1429                         $seed = new $class_name();
1430                         if(empty($beanList[$module_name])){
1431                                 continue;
1432                         }
1433                         if(!check_modules_access($current_user, $module_name, 'read')){
1434                                 continue;
1435                         }
1436                         if(! $seed->ACLAccess('ListView'))
1437                         {
1438                                 continue;
1439                         }
1440
1441                         if(isset($query_array[$module_name])){
1442                                 $query = '';
1443                                 $tmpQuery = '';
1444                                 //split here to do while loop
1445                                 foreach($query_array[$module_name]['where'] as $key => $value){
1446                                         foreach($value as $where_clause){
1447                                                 $addQuery = true;
1448                                                 if(!empty($query))
1449                                                         $tmpQuery = ' UNION ';
1450                                                 $tmpQuery .= "SELECT ".$query_array[$module_name]['fields']." FROM $seed->table_name ";
1451                                                 // We need to confirm that the user is a member of the team of the item.
1452
1453
1454                                 if($module_name == 'ProjectTask'){
1455                                     $tmpQuery .= "INNER JOIN project ON $seed->table_name.project_id = project.id ";
1456                                 }
1457
1458                                 if(isset($seed->emailAddress) && $key == 'EmailAddresses'){
1459                                         $tmpQuery .= " INNER JOIN email_addr_bean_rel eabl  ON eabl.bean_id = $seed->table_name.id and eabl.deleted=0";
1460                                         $tmpQuery .= " INNER JOIN email_addresses ea ON (ea.id = eabl.email_address_id) ";
1461                                 }
1462                                                 $where = "WHERE (";
1463                                                 $search_terms = explode(", ", $search_string);
1464                                                 $termCount = count($search_terms);
1465                                                 $count = 1;
1466                                                 if($key != 'EmailAddresses'){
1467                                                         foreach($search_terms as $term){
1468                                                                 if(!strpos($where_clause, 'number')){
1469                                                                         $where .= string_format($where_clause,array($term));
1470                                                                 }elseif(is_numeric($term)){
1471                                                                         $where .= string_format($where_clause,array($term));
1472                                                                 }else{
1473                                                                         $addQuery = false;
1474                                                                 }
1475                                                                 if($count < $termCount){
1476                                                                         $where .= " OR ";
1477                                                                 }
1478                                                                 $count++;
1479                                                         }
1480                                                 }else{
1481                                                         $where .= 'ea.email_address IN (';
1482                                                         foreach($search_terms as $term){
1483                                                                 $where .= "'".$GLOBALS['db']->quote($term)."'";
1484                                                                 if($count < $termCount){
1485                                                                         $where .= ",";
1486                                                                 }
1487                                                                 $count++;
1488                                                         }
1489                                                         $where .= ')';
1490                                                 }
1491                                                 $tmpQuery .= $where;
1492                                                 $tmpQuery .= ") AND $seed->table_name.deleted = 0";
1493                                                 if($addQuery)
1494                                                         $query .= $tmpQuery;
1495                                         }
1496                                 }
1497                                 //grab the items from the db
1498                                 $result = $seed->db->query($query, $offset, $max_results);
1499
1500                                 $list = Array();
1501                                 if(empty($rows_found)){
1502                                                 $rows_found =  $seed->db->getRowCount($result);
1503                                 }//fi
1504
1505                                 $row_offset = 0;
1506
1507                                 while(($row = $seed->db->fetchByAssoc($result)) != null){
1508                                         $list = array();
1509                                         $fields = explode(", ", $query_array[$module_name]['fields']);
1510                                         foreach($fields as $field){
1511                                                 $field_names = explode(".", $field);
1512                                                 $list[$field] = array('name'=>$field_names[1], 'value'=>$row[$field_names[1]]);
1513                                         }
1514
1515                                         $output_list[] = array('id'=>$row['id'],
1516                                                                            'module_name'=>$module_name,
1517                                                                            'name_value_list'=>$list);
1518                                         if(empty($field_list)){
1519                                                 $field_list = get_field_list($row);
1520                                         }
1521                                 }//end while
1522                         }
1523                 }//end foreach
1524         }
1525
1526         $next_offset = $offset + sizeof($output_list);
1527
1528         return array('result_count'=>sizeof($output_list), 'next_offset'=>$next_offset,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
1529
1530 }//end function
1531
1532
1533 $server->register(
1534 'get_mailmerge_document',
1535 array('session'=>'xsd:string','file_name'=>'xsd:string', 'fields' => 'tns:select_fields'),
1536 array('return'=>'tns:get_sync_result_encoded'),
1537 $NAMESPACE);
1538
1539 /**
1540  * Enter description here...
1541  *
1542  * @param String $session -- Session ID returned by a previous call to login.
1543  * @param unknown_type $file_name
1544  * @param unknown_type $fields
1545  * @return unknown
1546  */
1547 function get_mailmerge_document($session, $file_name, $fields)
1548 {
1549     global  $beanList, $beanFiles, $app_list_strings;
1550     $error = new SoapError();
1551     if(!validate_authenticated($session))
1552     {
1553         $error->set_error('invalid_login');
1554         return array('result'=>'', 'error'=>$error->get_soap_array());
1555     }
1556     $html = '';
1557     $file_name = $GLOBALS['sugar_config']['cache_dir'].'MergedDocuments/'.$file_name;
1558
1559     $master_fields = array();
1560     $related_fields = array();
1561
1562     if(file_exists($file_name))
1563     {
1564         require_once($file_name);
1565
1566         $class1 = $merge_array['master_module'];
1567         $beanL = $beanList[$class1];
1568         $bean1 = $beanFiles[$beanL];
1569         require_once($bean1);
1570         $seed1 = new $beanL();
1571
1572         if(!empty($merge_array['related_module']))
1573         {
1574             $class2 = $merge_array['related_module'];
1575             $beanR = $beanList[$class2];
1576             $bean2 = $beanFiles[$beanR];
1577             require_once($bean2);
1578             $seed2 = new $beanR();
1579         }
1580
1581         //parse fields
1582         //$token1 = strtolower($class1);
1583         if($class1 == 'Prospects'){
1584             $class1 = 'CampaignProspects';
1585         }
1586         foreach($fields as $field)
1587         {
1588             $pos = strpos(strtolower($field), strtolower($class1));
1589             $pos2 = strpos(strtolower($field), strtolower($class2));
1590             if($pos !== false){
1591                 $fieldName = str_replace(strtolower($class1).'_', '', strtolower($field));
1592                 array_push($master_fields, $fieldName);
1593             }else if($pos2 !== false){
1594                 $fieldName = str_replace(strtolower($class2).'_', '', strtolower($field));
1595                 array_push($related_fields, $fieldName);
1596             }
1597         }
1598
1599         $html = '<html><body><table border = 1><tr>';
1600
1601         foreach($master_fields as $master_field){
1602             $html .= '<td>'.$class1.'_'.$master_field.'</td>';
1603         }
1604         foreach($related_fields as $related_field){
1605             $html .= '<td>'.$class2.'_'.$related_field.'</td>';
1606         }
1607         $html .= '</tr>';
1608
1609         $ids = $merge_array['ids'];
1610         $is_prospect_merge = ($seed1->object_name == 'Prospect');
1611         foreach($ids as $key=>$value){
1612             if($is_prospect_merge){
1613                 $seed1 = $seed1->retrieveTarget($key);
1614             }else{
1615                 $seed1->retrieve($key);
1616             }
1617             $html .= '<tr>';
1618             foreach($master_fields as $master_field){
1619                 if(isset($seed1->$master_field)){
1620                     if($seed1->field_name_map[$master_field]['type'] == 'enum'){
1621                         //pull in the translated dom
1622                          $html .='<td>'.$app_list_strings[$seed1->field_name_map[$master_field]['options']][$seed1->$master_field].'</td>';
1623                     }else{
1624                         $html .='<td>'.$seed1->$master_field.'</td>';
1625                     }
1626                 }
1627                 else{
1628                     $html .= '<td></td>';
1629                     }
1630             }
1631             if(isset($value) && !empty($value)){
1632                 $seed2->retrieve($value);
1633                 foreach($related_fields as $related_field){
1634                     if(isset($seed2->$related_field)){
1635                         if($seed2->field_name_map[$related_field]['type'] == 'enum'){
1636                             //pull in the translated dom
1637                             $html .='<td>'.$app_list_strings[$seed2->field_name_map[$related_field]['options']][$seed2->$related_field].'</td>';
1638                         }else{
1639                             $html .= '<td>'.$seed2->$related_field.'</td>';
1640                         }
1641                     }
1642                     else{
1643                         $html .= '<td></td>';
1644                     }
1645                 }
1646             }
1647             $html .= '</tr>';
1648         }
1649         $html .= "</table></body></html>";
1650      }
1651
1652     $result = base64_encode($html);
1653     return array('result' => $result, 'error' => $error);
1654 }
1655
1656 $server->register(
1657 'get_mailmerge_document2',
1658 array('session'=>'xsd:string','file_name'=>'xsd:string', 'fields' => 'tns:select_fields'),
1659 array('return'=>'tns:get_mailmerge_document_result'),
1660 $NAMESPACE);
1661
1662 /**
1663  * Enter description here...
1664  *
1665  * @param String $session -- Session ID returned by a previous call to login.
1666  * @param unknown_type $file_name
1667  * @param unknown_type $fields
1668  * @return unknown
1669  */
1670 function get_mailmerge_document2($session, $file_name, $fields)
1671 {
1672     global  $beanList, $beanFiles, $app_list_strings;
1673     $error = new SoapError();
1674     if(!validate_authenticated($session))
1675     {
1676         $error->set_error('invalid_login');
1677         return array('result'=>'', 'error'=>$error->get_soap_array());
1678     }
1679     $html = '';
1680     $file_name = $GLOBALS['sugar_config']['cache_dir'].'MergedDocuments/'.$file_name;
1681
1682     $master_fields = array();
1683     $related_fields = array();
1684
1685     if(file_exists($file_name))
1686     {
1687         require_once($file_name);
1688
1689         $class1 = $merge_array['master_module'];
1690         $beanL = $beanList[$class1];
1691         $bean1 = $beanFiles[$beanL];
1692         require_once($bean1);
1693         $seed1 = new $beanL();
1694
1695         if(!empty($merge_array['related_module']))
1696         {
1697             $class2 = $merge_array['related_module'];
1698             $beanR = $beanList[$class2];
1699             $bean2 = $beanFiles[$beanR];
1700             require_once($bean2);
1701             $seed2 = new $beanR();
1702         }
1703
1704         //parse fields
1705         //$token1 = strtolower($class1);
1706         if($class1 == 'Prospects'){
1707             $class1 = 'CampaignProspects';
1708         }
1709         foreach($fields as $field)
1710         {
1711                 $pos = strpos(strtolower($field), strtolower($class1));
1712             $pos2 = strpos(strtolower($field), strtolower($class2));
1713             if($pos !== false){
1714                 $fieldName = str_replace(strtolower($class1).'_', '', strtolower($field));
1715                 array_push($master_fields, $fieldName);
1716             }else if($pos2 !== false){
1717                 $fieldName = str_replace(strtolower($class2).'_', '', strtolower($field));
1718                 array_push($related_fields, $fieldName);
1719             }
1720         }
1721
1722         $html = '<html><body><table border = 1><tr>';
1723
1724         foreach($master_fields as $master_field){
1725             $html .= '<td>'.$class1.'_'.$master_field.'</td>';
1726         }
1727         foreach($related_fields as $related_field){
1728             $html .= '<td>'.$class2.'_'.$related_field.'</td>';
1729         }
1730         $html .= '</tr>';
1731
1732         $ids = $merge_array['ids'];
1733         $resultIds = array();
1734         $is_prospect_merge = ($seed1->object_name == 'Prospect');
1735         if($is_prospect_merge){
1736                 $pSeed = $seed1;
1737         }
1738         foreach($ids as $key=>$value){
1739
1740             if($is_prospect_merge){
1741                 $seed1 = $pSeed->retrieveTarget($key);
1742             }else{
1743                 $seed1->retrieve($key);
1744             }
1745              $resultIds[] = array('name' => $seed1->module_name, 'value' => $key);
1746             $html .= '<tr>';
1747             foreach($master_fields as $master_field){
1748                 if(isset($seed1->$master_field)){
1749                     if($seed1->field_name_map[$master_field]['type'] == 'enum'){
1750                         //pull in the translated dom
1751                          $html .='<td>'.$app_list_strings[$seed1->field_name_map[$master_field]['options']][$seed1->$master_field].'</td>';
1752                     }else{
1753                         $html .='<td>'.$seed1->$master_field.'</td>';
1754                     }
1755                 }
1756                 else{
1757                     $html .= '<td></td>';
1758                     }
1759             }
1760             if(isset($value) && !empty($value)){
1761                 $resultIds[] = array('name' => $seed2->module_name, 'value' => $value);
1762                                 $seed2->retrieve($value);
1763                 foreach($related_fields as $related_field){
1764                     if(isset($seed2->$related_field)){
1765                         if($seed2->field_name_map[$related_field]['type'] == 'enum'){
1766                             //pull in the translated dom
1767                             $html .='<td>'.$app_list_strings[$seed2->field_name_map[$related_field]['options']][$seed2->$related_field].'</td>';
1768                         }else{
1769                             $html .= '<td>'.$seed2->$related_field.'</td>';
1770                         }
1771                     }
1772                     else{
1773                         $html .= '<td></td>';
1774                     }
1775                 }
1776             }
1777             $html .= '</tr>';
1778         }
1779         $html .= "</table></body></html>";
1780      }
1781
1782     $result = base64_encode($html);
1783     return array('html' => $result, 'name_value_list' => $resultIds, 'error' => $error);
1784 }
1785
1786 $server->register(
1787         'get_document_revision',
1788         array('session'=>'xsd:string','i'=>'xsd:string'),
1789         array('return'=>'tns:return_document_revision'),
1790         $NAMESPACE);
1791
1792 /**
1793  * This method is used as a result of the .htaccess lock down on the cache directory. It will allow a
1794  * properly authenticated user to download a document that they have proper rights to download.
1795  *
1796  * @param String $session -- Session ID returned by a previous call to login.
1797  * @param String $id      -- ID of the document revision to obtain
1798  * @return return_document_revision - this is a complex type as defined in SoapTypes.php
1799  */
1800 function get_document_revision($session,$id)
1801 {
1802     global $sugar_config;
1803
1804     $error = new SoapError();
1805     if(!validate_authenticated($session)){
1806         $error->set_error('invalid_login');
1807         return array('id'=>-1, 'error'=>$error->get_soap_array());
1808     }
1809
1810
1811     $dr = new DocumentRevision();
1812     $dr->retrieve($id);
1813     if(!empty($dr->filename)){
1814         $filename = $sugar_config['upload_dir']."/".$dr->id;
1815         $contents = base64_encode(sugar_file_get_contents($filename));
1816 //        $fh = sugar_fopen($sugar_config['upload_dir']."/rogerrsmith.doc", 'w');
1817 //        fwrite($fh, base64_decode($contents));
1818         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());
1819     }else{
1820         $error->set_error('no_records');
1821         return array('id'=>-1, 'error'=>$error->get_soap_array());
1822     }
1823
1824 }
1825 $server->register(
1826     'set_campaign_merge',
1827     array('session'=>'xsd:string', 'targets'=>'tns:select_fields', 'campaign_id'=>'xsd:string'),
1828     array('return'=>'tns:error_value'),
1829     $NAMESPACE);
1830 /**
1831 *   Once we have successfuly done a mail merge on a campaign, we need to notify Sugar of the targets
1832 *   and the campaign_id for tracking purposes
1833 *
1834 * @param session        the session id of the authenticated user
1835 * @param targets        a string array of ids identifying the targets used in the merge
1836 * @param campaign_id    the campaign_id used for the merge
1837 *
1838 * @return error_value
1839 */
1840 function set_campaign_merge($session,$targets, $campaign_id){
1841     $error = new SoapError();
1842     if(!validate_authenticated($session)){
1843         $error->set_error('invalid_login');
1844         return $error->get_soap_array();
1845     }
1846     if (empty($campaign_id) or !is_array($targets) or count($targets) == 0) {
1847         $GLOBALS['log']->debug('set_campaign_merge: Merge action status will not be updated, because, campaign_id is null or no targets were selected.');
1848     } else {
1849         require_once('modules/Campaigns/utils.php');
1850         campaign_log_mail_merge($campaign_id,$targets);
1851     }
1852
1853     return $error->get_soap_array();
1854 }
1855 $server->register(
1856     'get_entries_count',
1857     array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'query'=>'xsd:string', 'deleted' => 'xsd:int'),
1858     array('return'=>'tns:get_entries_count_result'),
1859     $NAMESPACE);
1860
1861 /**
1862 *   Retrieve number of records in a given module
1863 *
1864 * @param session        the session id of the authenticated user
1865 * @param module_name    module to retrieve number of records from
1866 * @param query          allows webservice user to provide a WHERE clause
1867 * @param deleted        specify whether or not to include deleted records
1868 *
1869 @return get_entries_count_result - this is a complex type as defined in SoapTypes.php
1870 */
1871 function get_entries_count($session, $module_name, $query, $deleted) {
1872         global $beanList, $beanFiles, $current_user;
1873
1874         $error = new SoapError();
1875
1876         if (!validate_authenticated($session)) {
1877                 $error->set_error('invalid_login');
1878                 return array(
1879                         'result_count' => -1,
1880                         'error' => $error->get_soap_array()
1881                 );
1882         }
1883
1884         if (empty($beanList[$module_name])) {
1885                 $error->set_error('no_module');
1886                 return array(
1887                         'result_count' => -1,
1888                         'error' => $error->get_soap_array()
1889                 );
1890         }
1891
1892         if(!check_modules_access($current_user, $module_name, 'list')){
1893                 $error->set_error('no_access');
1894                 return array(
1895                         'result_count' => -1,
1896                         'error' => $error->get_soap_array()
1897                 );
1898         }
1899
1900         $class_name = $beanList[$module_name];
1901         require_once($beanFiles[$class_name]);
1902         $seed = new $class_name();
1903
1904         if (!$seed->ACLAccess('ListView')) {
1905                 $error->set_error('no_access');
1906                 return array(
1907                         'result_count' => -1,
1908                         'error' => $error->get_soap_array()
1909                 );
1910         }
1911
1912         $sql = 'SELECT COUNT(*) result_count FROM ' . $seed->table_name . ' ';
1913
1914
1915         // build WHERE clauses, if any
1916         $where_clauses = array();
1917         if (!empty($query)) {
1918                 $where_clauses[] = $query;
1919         }
1920         if ($deleted == 0) {
1921                 $where_clauses[] = $seed->table_name . '.deleted = 0';
1922         }
1923
1924         // if WHERE clauses exist, add them to query
1925         if (!empty($where_clauses)) {
1926                 $sql .= ' WHERE ' . implode(' AND ', $where_clauses);
1927         }
1928
1929         $res = $GLOBALS['db']->query($sql);
1930         $row = $GLOBALS['db']->fetchByAssoc($res);
1931
1932         return array(
1933                 'result_count' => $row['result_count'],
1934                 'error' => $error->get_soap_array()
1935         );
1936 }
1937
1938 $server->register(
1939     'set_entries_details',
1940     array('session'=>'xsd:string', 'module_name'=>'xsd:string',  'name_value_lists'=>'tns:name_value_lists', 'select_fields' => 'tns:select_fields'),
1941     array('return'=>'tns:set_entries_detail_result'),
1942     $NAMESPACE);
1943
1944 /**
1945  * Update or create a list of SugarBeans, returning details about the records created/updated
1946  *
1947  * @param String $session -- Session ID returned by a previous call to login.
1948  * @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)..
1949  * @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.
1950  * @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.
1951  * @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.
1952  *                  'error' -- The SOAP error if any.
1953  */
1954 function set_entries_details($session, $module_name, $name_value_lists, $select_fields) {
1955         $error = new SoapError();
1956
1957         if(!validate_authenticated($session)){
1958                 $error->set_error('invalid_login');
1959
1960                 return array(
1961                         'ids' => array(),
1962                         'error' => $error->get_soap_array()
1963                 );
1964         }
1965
1966         return handle_set_entries($module_name, $name_value_lists, $select_fields);
1967 }
1968
1969 // INTERNAL FUNCTION NOT EXPOSED THROUGH API
1970 function handle_set_entries($module_name, $name_value_lists, $select_fields = FALSE) {
1971         global $beanList, $beanFiles, $app_list_strings;
1972
1973         $error = new SoapError();
1974         $ret_values = array();
1975
1976         if(empty($beanList[$module_name])){
1977                 $error->set_error('no_module');
1978                 return array('ids'=>array(), 'error'=>$error->get_soap_array());
1979         }
1980         global $current_user;
1981         if(!check_modules_access($current_user, $module_name, 'write')){
1982                 $error->set_error('no_access');
1983                 return array('ids'=>-1, 'error'=>$error->get_soap_array());
1984         }
1985
1986         $class_name = $beanList[$module_name];
1987         require_once($beanFiles[$class_name]);
1988         $ids = array();
1989         $count = 1;
1990         $total = sizeof($name_value_lists);
1991         foreach($name_value_lists as $name_value_list){
1992                 $seed = new $class_name();
1993
1994                 $seed->update_vcal = false;
1995                 foreach($name_value_list as $value){
1996                         if($value['name'] == 'id'){
1997                                 $seed->retrieve($value['value']);
1998                                 break;
1999                         }
2000                 }
2001
2002                 foreach($name_value_list as $value) {
2003                         $val = $value['value'];
2004                         if($seed->field_name_map[$value['name']]['type'] == 'enum' ||$seed->field_name_map[$value['name']]['type'] == 'radioenum'){
2005                                 $vardef = $seed->field_name_map[$value['name']];
2006                                 if(isset($app_list_strings[$vardef['options']]) && !isset($app_list_strings[$vardef['options']][$value]) ) {
2007                             if ( in_array($val,$app_list_strings[$vardef['options']]) ){
2008                                 $val = array_search($val,$app_list_strings[$vardef['options']]);
2009                             }
2010                         }
2011                         } else if($seed->field_name_map[$value['name']]['type'] == 'multienum') {
2012                                 $vardef = $seed->field_name_map[$value['name']];
2013                                 if(isset($app_list_strings[$vardef['options']]) && !isset($app_list_strings[$vardef['options']][$value]) ) {
2014                                         $items = explode(",", $val);
2015                                         $parsedItems = array();
2016                                         foreach ($items as $item) {
2017                                                 if ( in_array($item, $app_list_strings[$vardef['options']]) ){
2018                                                         $keyVal = array_search($item,$app_list_strings[$vardef['options']]);
2019                                                         array_push($parsedItems, $keyVal);
2020                                                 }
2021                                         }
2022                                 if (!empty($parsedItems)) {
2023                                                 $val = encodeMultienumValue($parsedItems);
2024                                 }
2025                         }
2026                         }
2027                         $seed->$value['name'] = $val;
2028                 }
2029
2030                 if($count == $total){
2031                         $seed->update_vcal = false;
2032                 }
2033                 $count++;
2034
2035                 //Add the account to a contact
2036                 if($module_name == 'Contacts'){
2037                         $GLOBALS['log']->debug('Creating Contact Account');
2038                         add_create_account($seed);
2039                         $duplicate_id = check_for_duplicate_contacts($seed);
2040                         if($duplicate_id == null){
2041                                 if($seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
2042                                         $seed->save();
2043                                         if($seed->deleted == 1){
2044                                                 $seed->mark_deleted($seed->id);
2045                                         }
2046                                         $ids[] = $seed->id;
2047                                 }
2048                         }
2049                         else{
2050                                 //since we found a duplicate we should set the sync flag
2051                                 if( $seed->ACLAccess('Save')){
2052                                         $seed->id = $duplicate_id;
2053                                         $seed->contacts_users_id = $current_user->id;
2054                                         $seed->save();
2055                                         $ids[] = $duplicate_id;//we have a conflict
2056                                 }
2057                         }
2058                 }
2059                 else if($module_name == 'Meetings' || $module_name == 'Calls'){
2060                         //we are going to check if we have a meeting in the system
2061                         //with the same outlook_id. If we do find one then we will grab that
2062                         //id and save it
2063                         if( $seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
2064                                 if(empty($seed->id) && !isset($seed->id)){
2065                                         if(!empty($seed->outlook_id) && isset($seed->outlook_id)){
2066                                                 //at this point we have an object that does not have
2067                                                 //the id set, but does have the outlook_id set
2068                                                 //so we need to query the db to find if we already
2069                                                 //have an object with this outlook_id, if we do
2070                                                 //then we can set the id, otherwise this is a new object
2071                                                 $order_by = "";
2072                                                 $query = $seed->table_name.".outlook_id = '".$seed->outlook_id."'";
2073                                                 $response = $seed->get_list($order_by, $query, 0,-1,-1,0);
2074                                                 $list = $response['list'];
2075                                                 if(count($list) > 0){
2076                                                         foreach($list as $value)
2077                                                         {
2078                                                                 $seed->id = $value->id;
2079                                                                 break;
2080                                                         }
2081                                                 }//fi
2082                                         }//fi
2083                                 }//fi
2084                                 if (empty($seed->reminder_time)) {
2085                     $seed->reminder_time = -1;
2086                 }
2087                                 if($seed->reminder_time == -1){
2088                                         $defaultRemindrTime = $current_user->getPreference('reminder_time');
2089                                         if ($defaultRemindrTime != -1){
2090                         $seed->reminder_checked = '1';
2091                         $seed->reminder_time = $defaultRemindrTime;
2092                                         }
2093                                 }
2094                                 $seed->save();
2095                                 $ids[] = $seed->id;
2096                         }//fi
2097                 }
2098                 else
2099                 {
2100                         if( $seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
2101                                 $seed->save();
2102                                 $ids[] = $seed->id;
2103                         }
2104                 }
2105
2106                 // if somebody is calling set_entries_detail() and wants fields returned...
2107                 if ($select_fields !== FALSE) {
2108                         $ret_values[$count] = array();
2109
2110                         foreach ($select_fields as $select_field) {
2111                                 if (isset($seed->$select_field)) {
2112                                         $ret_values[$count][] = get_name_value($select_field, $seed->$select_field);
2113                                 }
2114                         }
2115                 }
2116         }
2117
2118         // handle returns for set_entries_detail() and set_entries()
2119         if ($select_fields !== FALSE) {
2120                 return array(
2121                         'name_value_lists' => $ret_values,
2122                         'error' => $error->get_soap_array()
2123                 );
2124         }
2125         else {
2126                 return array(
2127                         'ids' => $ids,
2128                         'error' => $error->get_soap_array()
2129                 );
2130         }
2131 }
2132
2133 ?>