Issues (4069)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

modules/Leads/views/view.convertlead.php (8 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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-2013 SugarCRM Inc.
6
7
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
8
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
9
 *
10
 * This program is free software; you can redistribute it and/or modify it under
11
 * the terms of the GNU Affero General Public License version 3 as published by the
12
 * Free Software Foundation with the addition of the following permission added
13
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
14
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
15
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
16
 *
17
 * This program is distributed in the hope that it will be useful, but WITHOUT
18
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
20
 * details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License along with
23
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
24
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25
 * 02110-1301 USA.
26
 *
27
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
28
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
29
 *
30
 * The interactive user interfaces in modified source and object code versions
31
 * of this program must display Appropriate Legal Notices, as required under
32
 * Section 5 of the GNU Affero General Public License version 3.
33
 *
34
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
35
 * these Appropriate Legal Notices must retain the display of the "Powered by
36
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
37
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
38
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
39
 ********************************************************************************/
40
41
require_once("include/EditView/EditView2.php");
42
require_once("include/upload_file.php");
43
44
class ViewConvertLead extends SugarView
45
{
46
    protected $fileName = "modules/Leads/metadata/convertdefs.php";
47
    protected $new_contact = false;
48
49
    public function __construct(
50
        $bean = null,
51
        $view_object_map = array()
52
        )
53
    {
54
        parent::__construct($bean, $view_object_map);
55
    	$this->medataDataFile = $this->fileName;
56
        if (file_exists("custom/$this->fileName"))
57
        {
58
            $this->medataDataFile = "custom/$this->fileName";
59
        }
60
    }
61
62
    public function preDisplay()
63
    {
64
        if (!$this->bean->ACLAccess('edit')) {
65
            ACLController::displayNoAccess();
66
            sugar_die('');
67
        }
68
    }
69
70
    /**
71
	 * @see SugarView::display()
72
	 */
73
	public function display()
74
    {
75
        if (!empty($_REQUEST['handle']) && $_REQUEST['handle'] == 'save')
76
        {
77
        	return $this->handleSave();
78
        }
79
80
    	global $beanList;
81
82
    	// get the EditView defs to check if opportunity_name exists, for a check below for populating data
83
    	$opportunityNameInLayout = false;
84
    	$editviewFile = 'modules/Leads/metadata/editviewdefs.php';
85
        $this->medataDataFile = $editviewFile;
86
        if (file_exists("custom/{$editviewFile}"))
87
        {
88
            $this->medataDataFile = "custom/{$editviewFile}";
89
        }
90
    	include($this->medataDataFile);
91
    	foreach($viewdefs['Leads']['EditView']['panels'] as $panel_index => $section){
92
    	    foreach($section as $row_array){
93
    	        foreach($row_array as $cell){
94
        	        if(isset($cell['name']) && $cell['name'] == 'opportunity_name'){
95
        	            $opportunityNameInLayout = true;
96
        	        }
97
    	        }
98
    	    }
99
    	}
100
101
        $this->medataDataFile = $this->fileName;
102
        if (file_exists("custom/$this->fileName"))
103
        {
104
            $this->medataDataFile = "custom/$this->fileName";
105
        }
106
    	$this->loadDefs();
107
        $this->getRecord();
108
        $this->checkForDuplicates($this->focus);
109
        $smarty = new Sugar_Smarty();
110
        $ev = new EditView();
0 ignored issues
show
Deprecated Code introduced by
The class EditView has been deprecated.

This class, trait or interface has been deprecated.

Loading history...
The call to EditView::__construct() misses some required arguments starting with $module.
Loading history...
111
        $ev->ss = $smarty;
112
        $ev->view = "ConvertLead";
113
        echo $this->getModuleTitle();
114
115
        require_once("include/QuickSearchDefaults.php");
116
        $qsd = QuickSearchDefaults::getQuickSearchDefaults();
117
        $qsd->setFormName("ConvertLead");
118
119
        $this->contact = new Contact();
120
        
121
        /*
122
         * Setup filter for Account/Contact popup picker
123
         */ 
124
        $filter = '';
125
        // Check if Lead has an account set
126
        if (!empty($this->focus->account_name))
127
        {
128
            $filter .= '&name_advanced=' . urlencode($this->focus->account_name);
129
        }
130
        // Check if Lead First name is available
131
        if (!empty($this->focus->first_name))
132
        {
133
            $filter .= '&first_name_advanced=' . urlencode($this->focus->first_name);
134
        }
135
        // Lead Last Name is always available
136
        $filter .= '&last_name_advanced=' . urlencode($this->focus->last_name);
137
        
138
        $smarty->assign('initialFilter', $filter);
139
        $smarty->assign('displayParams', array('initial_filter' => '{$initialFilter}'));
140
        
141
        $relatedFields = $this->contact->get_related_fields();
142
        $selectFields = array();
143
        foreach ($this->defs as $moduleName => $mDefs)
144
        {   
145
            if (!empty($mDefs[$ev->view]['select']) && !empty($relatedFields[$mDefs[$ev->view]['select']]))
146
            {
147
                $selectFields[$moduleName] = $mDefs[$ev->view]['select'];
148
                continue;
149
            }
150
            foreach ($relatedFields as $fDef)
151
            {
152
                if (!empty($fDef['link']) && !empty($fDef['module']) && $fDef['module'] == $moduleName)
153
                {
154
                    $selectFields[$moduleName] = $fDef['name'];
155
                    break;
156
                }
157
            }
158
        }
159
        
160
        $smarty->assign('selectFields', $selectFields);
161
162
        $smarty->assign("contact_def", $this->contact->field_defs);
163
        $smarty->assign("form_name", "ConvertLead");
164
        $smarty->assign("form_id", "ConvertLead");
165
        $smarty->assign("module", "Leads");
166
        $smarty->assign("view", "convertlead");
167
        $smarty->assign("bean", $this->focus);
168
		$smarty->assign("record_id", $this->focus->id);
169
        global $mod_strings;
170
        $smarty->assign('MOD', $mod_strings);
171
        $smarty->display("modules/Leads/tpls/ConvertLeadHeader.tpl");
172
173
        echo "<div class='edit view' style='width:auto;'>";
174
175
        global $sugar_config, $app_list_strings, $app_strings;
176
        $smarty->assign('lead_conv_activity_opt', $sugar_config['lead_conv_activity_opt']);
177
        
178
        //Switch up list depending on copy or move
179
        if($sugar_config['lead_conv_activity_opt'] == 'move')
180
        {
181
        	$smarty->assign('convertModuleListOptions', get_select_options_with_id(array('None'=>$app_strings['LBL_NONE'], 'Contacts' => $app_list_strings["moduleListSingular"]['Contacts']), ''));	
182
        }
183
        else if($sugar_config['lead_conv_activity_opt'] == 'copy')
184
        {
185
        	$smarty->assign('convertModuleListOptions', get_select_options_with_id(array('Contacts' => $app_list_strings["moduleListSingular"]['Contacts']), ''));
186
        }
187
        
188
        
189
190
        foreach($this->defs as $module => $vdef)
191
        {
192
            if(!isset($beanList[$module]))
193
            {
194
                continue;
195
            }
196
197
198
            $bean = $beanList[$module];
199
            $focus = new $bean();
200
201
            // skip if we aren't allowed to save this bean
202
            if (!$focus->ACLAccess('save'))
203
            {
204
                continue;
205
            }
206
207
            $focus->fill_in_additional_detail_fields();
208
            foreach($focus->field_defs as $field => $def)
209
            {
210
            	if(isset($vdef[$ev->view]['copyData']) && $vdef[$ev->view]['copyData'])
211
                {
212
	                if ($module == "Accounts" && $field == 'name')
213
	                {
214
	                    $focus->name = $this->focus->account_name;
215
	                }
216
	                else if ($module == "Opportunities" && $field == 'amount')
217
	                {
218
	                    $focus->amount = unformat_number($this->focus->opportunity_amount);
219
	                } 
220
                 	else if ($module == "Opportunities" && $field == 'name') {
221
                 		if ($opportunityNameInLayout && !empty($this->focus->opportunity_name)){
222
                           $focus->name = $this->focus->opportunity_name;
223
                 		}
224
                   	}
225
	                else if ($field == "id")
226
                    {
227
						//If it is not a contact, don't copy the ID from the lead
228
                    	if ($module == "Contacts") {
229
                    	   $focus->$field = $this->focus->$field;
230
                        }
231
                    } else if (is_a($focus, "Company") && $field == 'phone_office')
232
	                {
233
	                	//Special case where company and person have the same field with a different name
234
	                	$focus->phone_office = $this->focus->phone_work;
235
	                }
236
					else if (strpos($field, "billing_address") !== false && $focus->field_defs[$field]["type"] == "varchar") /* Bug 42219 fix */         
237
					{
238
						$tmp_field = str_replace("billing_", "primary_", $field);
239
						$focus->field_defs[$field]["type"] = "text";
240
                        if (isset($this->focus->$tmp_field)) {
241
						    $focus->$field = $this->focus->$tmp_field;
242
                        }
243
					 }
244
245
					else if (strpos($field, "shipping_address") !== false && $focus->field_defs[$field]["type"] == "varchar") /* Bug 42219 fix */
246
					{
247
						$tmp_field = str_replace("shipping_", "primary_", $field);
248
						if (isset($this->focus->$tmp_field)) {
249
                            $focus->$field = $this->focus->$tmp_field;
250
                        }
251
						$focus->field_defs[$field]["type"] = "text";
252
					}    					
253
                    else if (isset($this->focus->$field))
254
                    {
255
                        $focus->$field = $this->focus->$field;
256
                    }
257
                }
258
            }
259
260
            //Copy over email data
261
            $ev->setup($module, $focus, $this->medataDataFile, "modules/Leads/tpls/ConvertLead.tpl", false);
262
            $ev->process();
263
            echo($ev->display(false));
0 ignored issues
show
The call to EditView::display() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
264
            echo($this->getValidationJS($module, $focus, $vdef[$ev->view]));
265
        }
266
        echo "</div>";
267
        echo ($qsd->getQSScriptsJSONAlreadyDefined());
268
        // need to re-assign bean as it gets overridden by $ev->display
269
        $smarty->assign("bean", $this->focus);
270
        $smarty->display("modules/Leads/tpls/ConvertLeadFooter.tpl");
271
    }
272
273
    protected function getRecord()
274
    {
275
    	$this->focus = new Lead();
276
    	if (isset($_REQUEST['record']))
277
    	{
278
    		$this->focus->retrieve($_REQUEST['record']);
279
    	}
280
    }
281
282
    protected function loadDefs()
283
    {
284
    	$viewdefs = array();
285
    	include($this->medataDataFile);
286
    	$this->defs = $viewdefs;
287
    }
288
289
    /**
290
     * Returns the javascript to enable/disable validation of each module's sub-form
291
     * //TODO: This should probably be on the smarty template
292
     * @param $module String the target module name.
293
     * @param $focus SugarBean instance of the target module.
294
     * @param $focus EditView def for the module.
295
     * @return String, javascript to echo to page.
0 ignored issues
show
The doc-type String, could not be parsed: Expected "|" or "end of type", but got "," at position 6. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
296
     */
297
    protected function getValidationJS(
298
        $module,
299
        $focus,
300
        $viewdef
301
        )
302
    {
303
        $validateSelect = isset($viewdef['required']) && $viewdef['required'] && !empty($viewdef['select']);
304
        $jsOut  = "
305
        <script type='text/javascript'>
306
            if (!SUGAR.convert)  SUGAR.convert = {requiredFields: {}};
307
            SUGAR.convert.toggle$module = function(){
308
                clear_all_errors();
309
                inputsWithErrors = [];
310
                if(!SUGAR.convert.{$module}Enabled)
311
                {
312
                    for(var i in SUGAR.convert.requiredFields.$module)
313
                    {
314
                        addToValidate('ConvertLead', '$module' + i, 'varchar', true, SUGAR.convert.requiredFields.{$module}[i]);
315
                    }
316
                    ";
317
        if ($validateSelect) {
318
        	$jsOut  .= "
319
                    removeFromValidate('ConvertLead', '{$viewdef['select']}');";
320
        }
321
322
        $jsOut .= "
323
                    SUGAR.convert.{$module}Enabled = true;
324
                } else {
325
                    for(var i in SUGAR.convert.requiredFields.$module)
326
                    {
327
                        removeFromValidate('ConvertLead', '$module' + i);
328
                    }";
329
        if ($validateSelect) {
330
            $jsOut  .= "
331
                addToValidate('ConvertLead', '{$viewdef['select']}', 'varchar', true, '"
332
            . translate($this->contact->field_defs[$viewdef['select']]['vname']) . "');";
333
        }
334
        $jsOut .= "
335
                    SUGAR.convert.{$module}Enabled = false;
336
                }
337
                YAHOO.util.Dom.get('convert_create_{$module}').value = SUGAR.convert.{$module}Enabled;
338
            };\n";
339
340
        if (isset($viewdef['required']) && $viewdef['required'])
341
        {
342
            if (!empty($viewdef['select']) && (empty($viewdef['default_action']) || $viewdef['default_action'] != 'create'))
343
            {
344
                $jsOut .= "
345
            SUGAR.convert.{$module}Enabled = true;";
346
            }
347
            $jsOut .= "
348
            YAHOO.util.Event.onDOMReady(SUGAR.convert.toggle$module);";
349
        } else if (isset($viewdef['default_action'])  && $viewdef['default_action'] == "create")
350
        {
351
             $jsOut .= "\n            SUGAR.convert.{$module}Enabled = true;";
352
        }
353
        $jsOut .= "
354
            YAHOO.util.Event.addListener('new$module', 'click', SUGAR.convert.toggle$module);
355
            SUGAR.convert.requiredFields.$module = {};";
356
        foreach($focus->field_defs as $field => $def)
357
        {
358
            if (isset($def['required']) && $def['required'])
359
            {
360
                $jsOut .= "
361
            SUGAR.convert.requiredFields.$module.$field = '". translate($def['vname'], $module) . "';\n";
362
            }
363
        }
364
365
        $jsOut .= "
366
        </script>";
367
368
        return $jsOut;
369
    }
370
371
    /**
372
     * Saves a new Contact as well as any related items passed in.
373
     *
374
     * @return null
375
     */
376
    protected function handleSave()
377
    {
378
        require_once('modules/Campaigns/utils.php');
379
        require_once("include/formbase.php");
380
        $lead = false;
381
        if (!empty($_REQUEST['record']))
382
        {
383
            $lead = new Lead();
384
            $lead->retrieve($_REQUEST['record']);
385
        }
386
387
        global $beanList;
388
        $this->loadDefs();
389
        $beans = array();
390
        $selectedBeans = array();
391
        $selects = array();
392
        
393
        // Make sure the contact object is availible for relationships.
394
        $beans['Contacts'] = new Contact();
395
        
396
        // Contacts
397
        if (!empty($_REQUEST['selectedContact']))
398
        {
399
            $beans['Contacts']->retrieve($_REQUEST['selectedContact']);
400
            if (!empty($beans['Contacts']->id))
401
            {
402
                $beans['Contacts']->new_with_id = false;
403
                unset($_REQUEST["convert_create_Contacts"]);
404
                unset($_POST["convert_create_Contacts"]);
405
            }
406
        }
407
        elseif (!empty($_REQUEST["convert_create_Contacts"]) && $_REQUEST["convert_create_Contacts"] != "false" && !isset($_POST['ContinueContact'])) 
408
        {
409
            require_once('modules/Contacts/ContactFormBase.php');
410
            $contactForm = new ContactFormBase();
411
            $duplicateContacts = $contactForm->checkForDuplicates('Contacts');
412
413
            if (isset($duplicateContacts))
414
            {
415
                echo $contactForm->buildTableForm($duplicateContacts,  'Contacts');
0 ignored issues
show
The call to ContactFormBase::buildTableForm() has too many arguments starting with 'Contacts'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
416
                return;
417
            }
418
            $this->new_contact = true;
419
        } elseif (isset($_POST['ContinueContact'])) {
420
            $this->new_contact = true;
421
        }
422
        // Accounts
423
        if (!empty($_REQUEST['selectedAccount']))
424
        {
425
            $_REQUEST['account_id'] = $_REQUEST['selectedAccount'];
426
            unset($_REQUEST["convert_create_Accounts"]);
427
            unset($_POST["convert_create_Accounts"]);
428
        }
429
        elseif (!empty($_REQUEST["convert_create_Accounts"]) && $_REQUEST["convert_create_Accounts"] != "false" && empty($_POST['ContinueAccount']))
430
        {
431
            require_once('modules/Accounts/AccountFormBase.php');
432
            $accountForm = new AccountFormBase();
433
            $duplicateAccounts = $accountForm->checkForDuplicates('Accounts');
434
            if (isset($duplicateAccounts))
435
            {
436
                echo $accountForm->buildTableForm($duplicateAccounts);
437
                return;
438
            }
439
        }
440
441
        foreach ($this->defs as $module => $vdef)
442
        {
443
            //Create a new record if "create" was selected
444
        	if (!empty($_REQUEST["convert_create_$module"]) && $_REQUEST["convert_create_$module"] != "false")
445
            {
446
                //Save the new record
447
                $bean = $beanList[$module];
448
	            if (empty($beans[$module]))
449
	            	$beans[$module] = new $bean();
450
451
            	$this->populateNewBean($module, $beans[$module], $beans['Contacts'], $lead);
452
                // when creating a new contact, create the id for linking with other modules
453
                // and do not populate it with lead's old account_id
454
                if ($module == 'Contacts')
455
                {
456
                    $beans[$module]->id = create_guid();
457
                    $beans[$module]->new_with_id = true;
458
                    $beans[$module]->account_id = '';
459
                }
460
            }
461
            //If an existing bean was selected, relate it to the contact
462
            else if (!empty($vdef['ConvertLead']['select'])) 
463
            {
464
                //Save the new record
465
                $select = $vdef['ConvertLead']['select'];
466
                $fieldDef = $beans['Contacts']->field_defs[$select];
467
                if (!empty($fieldDef['id_name']) && !empty($_REQUEST[$fieldDef['id_name']]))
468
                {
469
                    $idName = $fieldDef['id_name'];
470
                    $beans['Contacts']->$idName = $_REQUEST[$idName];
471
                    $selects[$module] = $_REQUEST[$idName];
472
                    if (!empty($_REQUEST[$select]))
473
                    {
474
                        $beans['Contacts']->$select = $_REQUEST[$select];
475
                    }
476
                    // Bug 39268 - Add the existing beans to a list of beans we'll potentially add the lead's activities to
477
                    $bean = loadBean($module);
0 ignored issues
show
Deprecated Code introduced by
The function loadBean() has been deprecated with message: use SugarModule::loadBean() instead

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
478
                    $bean->retrieve($_REQUEST[$idName]);
479
                    $selectedBeans[$module] = $bean;
480
                    // If we selected the Contact, just overwrite the $beans['Contacts']
481
                    if ($module == 'Contacts')
482
                    {
483
                        $beans[$module] = $bean;
484
                    }
485
                }
486
            }
487
        }
488
489
        $this->handleActivities($lead, $beans);
490
        // Bug 39268 - Add the lead's activities to the selected beans
491
        $this->handleActivities($lead, $selectedBeans);
492
493
        //link selected account to lead if it exists
494
        if (!empty($selectedBeans['Accounts']))
495
        {
496
            $lead->account_id = $selectedBeans['Accounts']->id;
497
        }
498
        
499
        // link account to contact, if we picked an existing contact and created a new account
500
        if (!empty($beans['Accounts']->id) && !empty($beans['Contacts']->account_id) 
501
                && $beans['Accounts']->id != $beans['Contacts']->account_id)
502
        {
503
            $beans['Contacts']->account_id = $beans['Accounts']->id;
504
        }
505
        
506
        // Saving beans with priorities.
507
        // Contacts and Accounts should be saved before lead activities to create correct relations
508
        $saveBeanPriority = array('Contacts', 'Accounts');
509
        $tempBeans = array();
510
511
        foreach ($saveBeanPriority as $name)
512
        {
513
            if (isset($beans[$name]))
514
            {
515
                $tempBeans[$name] = $beans[$name];
516
            }
517
        }
518
519
        $beans = array_merge($tempBeans, $beans);
520
        unset($tempBeans);
521
522
        //Handle non-contacts relationships
523
        foreach ($beans as $bean)
524
        {
525
            if (!empty($lead))
526
            {
527
                if (empty($bean->assigned_user_id))
528
                {
529
                    $bean->assigned_user_id = $lead->assigned_user_id;
530
                }
531
                $leadsRel = $this->findRelationship($bean, $lead);
532
                if (!empty($leadsRel))
533
                {
534
                    $bean->load_relationship($leadsRel);
535
                    $relObject = $bean->$leadsRel->getRelationshipObject();
536
                    if ($relObject->relationship_type == "one-to-many" && $bean->$leadsRel->_get_bean_position())
537
                    {
538
                        $id_field = $relObject->rhs_key;
539
                        $lead->$id_field = $bean->id;
540
                    }
541
                    else 
542
                    {
543
                        $bean->$leadsRel->add($lead->id);
544
                    }
545
                }
546
            }
547
            //Special case code for opportunities->Accounts
548
            if ($bean->object_name == "Opportunity" && empty($bean->account_id))
549
            {
550
                if (isset($beans['Accounts']))
551
                {
552
                    $bean->account_id = $beans['Accounts']->id;
553
                    $bean->account_name = $beans['Accounts']->name;
554
                }
555
                else if (!empty($selects['Accounts']))
556
                {
557
                    $bean->account_id = $selects['Accounts'];
558
                }
559
            }
560
561
            //create meetings-users relationship
562
            if ($bean->object_name == "Meeting")
563
            {
564
                $bean = $this->setMeetingsUsersRelationship($bean);
565
            }
566
            $this->copyAddressFields($bean, $beans['Contacts']);
567
568
            $bean->save();
569
            //if campaign id exists then there should be an entry in campaign_log table for the newly created contact: bug 44522	
570
            if (isset($lead->campaign_id) && $lead->campaign_id != null && $bean->object_name == "Contact")
571
            {
572
                campaign_log_lead_or_contact_entry($lead->campaign_id, $lead, $beans['Contacts'], 'contact');
573
            }
574
        }
575
        if (!empty($lead))
576
        {	//Mark the original Lead converted
577
            $lead->status = "Converted";
578
            $lead->converted = '1';
579
            $lead->in_workflow = true;
580
            $lead->save();
581
        }
582
583
        $this->displaySaveResults($beans);
584
    }
585
586
    public function setMeetingsUsersRelationship($bean)
587
    {
588
        global $current_user;
589
        $meetingsRel = $this->findRelationshipByName($bean, $this->defs['Meetings']['ConvertLead']['relationship']);
590
        if (!empty($meetingsRel))
591
        {
592
            $bean->load_relationship($meetingsRel);
593
            $bean->$meetingsRel->add($current_user->id);
594
            return $bean;
595
        }
596
        else
597
        {
598
            return false;
599
        }
600
    }
601
    protected function displaySaveResults(
602
        $beans
603
        )
604
    {
605
    	global $beanList;
606
    	echo "<div><ul>";
607
        foreach($beans as $bean)
608
        {
609
            $beanName = $bean->object_name;
610
            if ( $beanName == 'Contact' && !$this->new_contact ) {
611
                echo "<li>" . translate("LBL_EXISTING_CONTACT") . " -
612
                    <a href='index.php?module={$bean->module_dir}&action=DetailView&record={$bean->id}'>
613
                       {$bean->get_summary_text()}
614
                    </a></li>";
615
            }
616
            else {
617
                global $app_list_strings;
618
                if(!empty($app_list_strings['moduleListSingular'][$bean->module_dir])) {
619
                    $module_name = $app_list_strings['moduleListSingular'][$bean->module_dir];
620
                } else {
621
                    $module_name = translate('LBL_MODULE_NAME', $bean->module_dir);
622
                }
623
                if(empty($module_name)) {
624
                    $module_name = translate($beanName);
625
                }
626
                echo "<li>" . translate("LBL_CREATED_NEW") . ' ' . $module_name . " -
627
                    <a href='index.php?module={$bean->module_dir}&action=DetailView&record={$bean->id}'>
628
                       {$bean->get_summary_text()}
629
                    </a></li>";
630
            }
631
        }
632
633
    	echo "</ul></div>";
634
    }
635
636
    protected function handleActivities(
637
        $lead,
638
        $beans
639
        )
640
    {
641
    	global $app_list_strings;
642
        global $sugar_config;
643
        global $app_strings;
644
    	$parent_types = $app_list_strings['record_type_display'];
645
646
    	$activities = $this->getActivitiesFromLead($lead);
647
648
        //if account is being created, we will specify the account as the parent bean
649
        $accountParentInfo = array();
650
651
        //determine the account id info ahead of time if it is being created as part of this conversion
652
        if(!empty($beans['Accounts'])){
653
            $account_id = create_guid();
654
            if(!empty($beans['Accounts']->id)){
655
                $account_id = $beans['Accounts']->id;
656
            }else{
657
                $beans['Accounts']->id = $account_id;
658
            }
659
            $accountParentInfo = array('id'=>$account_id,'type'=>'Accounts');
660
        }
661
662
    	foreach($beans as $module => $bean)
663
    	{
664
	    	if (isset($parent_types[$module]))
665
	    	{
666
                if (empty($bean->id))
667
                {
668
                    $bean->id = create_guid();
669
		            $bean->new_with_id = true;
670
                }
671
                if( isset($_POST['lead_conv_ac_op_sel']) && $_POST['lead_conv_ac_op_sel'] != 'None')
672
                {
673
	                foreach($activities as $activity)
0 ignored issues
show
The expression $activities of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
674
			    	{
675
	                            if (!isset($sugar_config['lead_conv_activity_opt']) || $sugar_config['lead_conv_activity_opt'] == 'copy') {
676
	                                if (isset($_POST['lead_conv_ac_op_sel'])) {
677
	                                    //if the copy to module(s) are defined, copy only to those module(s)
678
	                                    if (is_array($_POST['lead_conv_ac_op_sel'])) {
679
	                                        foreach ($_POST['lead_conv_ac_op_sel'] as $mod) {
680
	                                            if ($mod == $module) {
681
	                                                $this->copyActivityAndRelateToBean($activity, $bean, $accountParentInfo);
682
	                                                break;
683
	                                            }
684
	                                        }
685
	                                    }
686
	                                }
687
	                            }
688
	                            else if ($sugar_config['lead_conv_activity_opt'] == 'move') {
689
	                                // if to move activities, should be only one module selected
690
	                                if ($_POST['lead_conv_ac_op_sel'] == $module) {
691
	                                    $this->moveActivity($activity, $bean);
692
	                                }
693
	                            }
694
			    	}
695
                }
696
	    	}
697
    	}
698
    }
699
700
    /**
701
     * Change the parent id and parent type of an activity
702
     * @param $activity Activity to be modified
703
     * @param $bean New parent bean of the activity
704
     */
705
    protected function moveActivity($activity, $bean) {
706
        global $beanList;
707
708
        $lead = null;
709
        if (!empty($_REQUEST['record']))
710
        {
711
            $lead = new Lead();
712
            $lead->retrieve($_REQUEST['record']);
713
        }
714
715
        // delete the old relationship to the old parent (lead)
716
        if ($rel = $this->findRelationship($activity, $lead)) {
717
            $activity->load_relationship ($rel) ;
718
719
            if ($activity->parent_id && $activity->id) {
720
                $activity->$rel->delete($activity->id, $activity->parent_id);
721
            }
722
        }
723
724
        // add the new relationship to the new parent (contact, account, etc)
725
        if ($rel = $this->findRelationship($activity, $bean)) {
726
            $activity->load_relationship ($rel) ;
727
728
            $relObj = $activity->$rel->getRelationshipObject();
729
            if ( $relObj->relationship_type=='one-to-one' || $relObj->relationship_type == 'one-to-many' )
730
            {
731
                $key = $relObj->rhs_key;
732
                $activity->$key = $bean->id;
733
            }
734
            $activity->$rel->add($bean);
735
        }
736
737
        // set the new parent id and type
738
        $activity->parent_id = $bean->id;
739
        $activity->parent_type = $bean->module_dir;
740
741
        $activity->save();
742
    }
743
744
    /**
745
     * Gets the list of activities related to the lead
746
     * @param Lead $lead Lead to get activities from
747
     * @return Array of Activity SugarBeans .
748
     */
749
	protected function getActivitiesFromLead(
750
	    $lead
751
	    )
752
	{
753
		if (!$lead) return;
754
755
		global $beanList, $db;
756
757
		$activitesList = array("Calls", "Tasks", "Meetings", "Emails", "Notes");
758
		$activities = array();
759
760
		foreach($activitesList as $module)
761
		{
762
			$beanName = $beanList[$module];
763
			$activity = new $beanName();
764
			$query = "SELECT id FROM {$activity->table_name} WHERE parent_id = '{$lead->id}' AND parent_type = 'Leads' AND deleted = 0";
765
			$result = $db->query($query,true);
766
            while($row = $db->fetchByAssoc($result))
767
            {
768
            	$activity = new $beanName();
769
				$activity->retrieve($row['id']);
770
				$activity->fixUpFormatting();
771
				$activities[] = $activity;
772
            }
773
		}
774
775
		return $activities;
776
	}
777
778
	protected function copyActivityAndRelateToBean(
779
	    $activity,
780
	    $bean,
781
        $parentArr = array()
782
	    )
783
	{
784
		global $beanList;
785
786
		$newActivity = clone $activity;
787
		$newActivity->id = create_guid();
788
		$newActivity->new_with_id = true;
789
790
        //set the parent id and type if it was passed in, otherwise use blank to wipe it out
791
        $parentID = '';
792
        $parentType = '';
793
        if(!empty($parentArr)){
794
            if(!empty($parentArr['id'])){
795
                $parentID = $parentArr['id'];
796
            }
797
798
            if(!empty($parentArr['type'])){
799
                $parentType = $parentArr['type'];
800
            }
801
802
        }
803
804
		//Special case to prevent duplicated tasks from appearing under Contacts multiple times
805
    	if ($newActivity->module_dir == "Tasks" && $bean->module_dir != "Contacts")
806
    	{
807
            $newActivity->contact_id = $newActivity->contact_name = "";
808
    	}
809
810
		if ($rel = $this->findRelationship($newActivity, $bean))
811
        {
812
            if (isset($newActivity->$rel))
813
            {
814
                // this comes form $activity, get rid of it and load our own
815
                $newActivity->$rel = '';
816
            }
817
818
            $newActivity->load_relationship ($rel) ;
819
            $relObj = $newActivity->$rel->getRelationshipObject();
820
            if ( $relObj->relationship_type=='one-to-one' || $relObj->relationship_type == 'one-to-many' )
821
            {
822
                $key = $relObj->rhs_key;
823
                $newActivity->$key = $bean->id;
824
            }
825
826
            //parent (related to field) should be blank unless it is explicitly sent in
827
            //it is not sent in unless the account is being created as well during lead conversion
828
            $newActivity->parent_id =  $parentID;
829
            $newActivity->parent_type = $parentType;
830
831
	        $newActivity->update_date_modified = false; //bug 41747
832
	        $newActivity->save();
833
            $newActivity->$rel->add($bean);
834
            if ($newActivity->module_dir == "Notes" && $newActivity->filename) {
835
	        	UploadFile::duplicate_file($activity->id, $newActivity->id,  $newActivity->filename);
836
	        }
837
         }
838
	}
839
840
    /**
841
     * Populates the passed in Bean fron the contact and the $_REQUEST
842
     * @param String $module Module of new bean
843
     * @param SugarBean $bean SugarBean to be populated.
844
     * @param Contact $contact Contact to relate the bean to.
845
     */
846
	protected function populateNewBean(
847
	    $module,
848
	    $bean,
849
	    $contact,
850
	    $lead
851
	    )
852
	{
853
		//Copy data from the contact to new bean
854
		foreach($bean->field_defs as $field => $def)
855
		{
856
			if(!isset($_REQUEST[$module . $field]) && isset($lead->$field) && $field != 'id')
857
			{
858
				$bean->$field = $lead->$field;
859
				if($field == 'date_entered') $bean->$field = gmdate($GLOBALS['timedate']->get_db_date_time_format()); //bug 41030
860
			}
861
		}
862
        populateFromPost($module, $bean, true);
863
		//Try to link to the new contact
864
		$contactRel = "";
865
		if (!empty($vdef['ConvertLead']['select']))
0 ignored issues
show
The variable $vdef seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
866
		{
867
			$select = $vdef['ConvertLead']['select'];
868
			$fieldDef = $contact->field_defs[$select];
869
			if (!empty($fieldDef['id_name']))
870
			{
871
				$bean->id = create_guid();
872
				$bean->new_with_id = true;
873
                $idName = $fieldDef['id_name'];
874
				$contact->$idName = $bean->id ;
875
				if ($idName != $select) {
876
					$rname = isset($fieldDef['rname']) ? $fieldDef['rname'] : "";
877
					if (!empty($rname) && isset($bean->$rname))
878
						$contact->$select = $bean->$rname;
879
					else
880
						$contact->$select = $bean->name;
881
				}
882
			}
883
		} else if ($module != "Contacts"){
884
			$contactRel = $this->findRelationship($contact, $bean);
885
			if (!empty($contactRel))
886
			{
887
				$bean->id = create_guid();
888
				$bean->new_with_id = true;
889
				$contact->load_relationship ($contactRel) ;
890
				$relObject = $contact->$contactRel->getRelationshipObject();
891
				if ($relObject->relationship_type == "one-to-many" && $contact->$contactRel->_get_bean_position())
892
				{
893
					$id_field = $relObject->rhs_key;
894
					$bean->$id_field = $contact->id;
895
				} else {
896
					$contact->$contactRel->add($bean);
897
				}
898
				//Set the parent of activites to the new Contact
899
				if (isset($bean->field_defs['parent_id']) && isset($bean->field_defs['parent_type']))
900
				{
901
					$bean->parent_id = $contact->id;
902
					$bean->parent_type = "Contacts";
903
				}
904
			}
905
		}
906
	}
907
908
	protected function copyAddressFields($bean, $contact)
909
	{
910
	//Copy over address info from the contact to any beans with address not set
911
	        foreach($bean->field_defs as $field => $def)
912
			{
913
				if(!isset($_REQUEST[$bean->module_dir . $field]) && strpos($field, "_address_") !== false)
914
				{
915
					$set = "primary";
916
					if (strpos($field, "alt_") !== false || strpos($field, "shipping_") !== false)
917
						$set = "alt";
918
					$type = "";
919
920
					if(strpos($field, "_address_street_2") !== false)
921
						$type = "_address_street_2";
922
					else if(strpos($field, "_address_street_3") !== false)
923
						$type = "_address_street_3";
924
					else if(strpos($field, "_address_street_4") !== false)
925
						$type = "";
926
					else if(strpos($field, "_address_street") !== false)
927
						$type = "_address_street";
928
					else if(strpos($field, "_address_city") !== false)
929
						$type = "_address_city";
930
					else if(strpos($field, "_address_state") !== false)
931
						$type = "_address_state";
932
					else if(strpos($field, "_address_postalcode") !== false)
933
						$type = "_address_postalcode";
934
					else if(strpos($field, "_address_country") !== false)
935
						$type = "_address_country";
936
937
						$var = $set.$type;
938
					if (isset($contact->$var))
939
						$bean->$field = $contact->$var;
940
				}
941
			}
942
	}
943
944
945
    protected function findRelationship(
946
        $from,
947
        $to
948
        )
949
    {
950
    	global $dictionary;
951
    	require_once("modules/TableDictionary.php");
952
    	foreach ($from->field_defs as $field=>$def)
953
        {
954
            if (isset($def['type']) && $def['type'] == "link" && isset($def['relationship'])) 
955
			{
956
                $rel_name = $def['relationship'];
957
                $rel_def = "";
958
                if (isset($dictionary[$from->object_name]['relationships']) && isset($dictionary[$from->object_name]['relationships'][$rel_name]))
959
                {
960
                    $rel_def = $dictionary[$from->object_name]['relationships'][$rel_name];
961
                }
962
                else if (isset($dictionary[$to->object_name]['relationships']) && isset($dictionary[$to->object_name]['relationships'][$rel_name]))
963
                {
964
                    $rel_def = $dictionary[$to->object_name]['relationships'][$rel_name];
965
                }
966
                else if (isset($dictionary[$rel_name]) && isset($dictionary[$rel_name]['relationships'])
967
                        && isset($dictionary[$rel_name]['relationships'][$rel_name]))
968
                {
969
                	$rel_def = $dictionary[$rel_name]['relationships'][$rel_name];
970
                }
971
                if (!empty($rel_def)) {
972
                    if ($rel_def['lhs_module'] == $from->module_dir && $rel_def['rhs_module'] == $to->module_dir )
973
                    {
974
                    	return $field;
975
                    }
976
                    else if ($rel_def['rhs_module'] == $from->module_dir && $rel_def['lhs_module'] == $to->module_dir )
977
                    {
978
                    	return $field;
979
                    }
980
                }
981
            }
982
        }
983
        return false;
984
    }
985
986
    protected function findRelationshipByName($from, $rel_name)
987
    {
988
        global $dictionary;
989
        require_once("modules/TableDictionary.php");
990
        foreach ($from->field_defs as $field => $def)
991
        {
992
            if (isset($def['relationship']) && $def['relationship'] == $rel_name) 
993
            {
994
                return $field;
995
            }
996
        }
997
        return false;
998
    }
999
	/**
1000
	 * @see SugarView::_getModuleTitleParams()
1001
	 */
1002
	protected function _getModuleTitleParams($browserTitle = false)
1003
	{
1004
	    global $mod_strings;
1005
	    $params = parent::_getModuleTitleParams($browserTitle);
1006
	    $params[] = "<a href='index.php?module=Leads&action=DetailView&record={$this->bean->id}'>{$this->bean->name}</a>";
1007
	    $params[] = $mod_strings['LBL_CONVERTLEAD'];
1008
    	return $params;
1009
    }
1010
1011
1012
    protected function checkForDuplicates(
1013
        $lead
1014
        )
1015
    {
1016
    	if ($lead->status == "Converted")
1017
    	{
1018
    		echo ("<span class='error'>" . translate('LBL_CONVERTLEAD_WARNING'));
1019
    		$dupes = array();
1020
    		$q = "SELECT id, first_name, last_name FROM contacts WHERE first_name LIKE '{$lead->first_name}' AND last_name LIKE '{$lead->last_name}' AND deleted = 0";
1021
    		$result = $lead->db->query($q);
1022
    		while($row = $lead->db->fetchByAssoc($result)) {
1023
    			$contact = new Contact();
1024
    			$contact->retrieve($row['id']);
1025
    			$dupes[$row['id']] = $contact->name;
1026
    		}
1027
    		if (!empty($dupes))
1028
    		{
1029
    			foreach($dupes as $id => $name)
1030
    			{
1031
    				echo (translate('LBL_CONVERTLEAD_WARNING_INTO_RECORD') . "<a href='index.php?module=Contacts&action=DetailView&record=$id'>$name</a>");
1032
    				break;
1033
    			}
1034
    		}
1035
    		echo "</span>";
1036
    	}
1037
    	return false;
1038
    }
1039
}
1040