2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
38 /*********************************************************************************
40 * Description: TODO: To be written.
41 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
42 * All Rights Reserved.
43 * Contributor(s): ______________________________________..
44 ********************************************************************************/
46 require_once('include/SugarObjects/templates/person/Person.php');
55 require_once('include/SugarObjects/templates/person/Person.php');
57 // Lead is used to store profile information for people who may become customers.
58 class Lead extends Person {
64 var $modified_user_id;
65 var $assigned_user_id;
68 var $modified_by_name;
85 var $primary_address_street;
86 var $primary_address_city;
87 var $primary_address_state;
88 var $primary_address_postalcode;
89 var $primary_address_country;
90 var $alt_address_street;
91 var $alt_address_city;
92 var $alt_address_state;
93 var $alt_address_postalcode;
94 var $alt_address_country;
103 var $opportunity_name;
104 var $opportunity_amount;
105 //used for vcard export only
108 var $status_description;
111 var $lead_source_description;
112 // These are for related fields
114 var $acc_name_from_accounts;
116 var $account_description;
125 var $assigned_user_name;
128 var $alt_address_street_2;
129 var $alt_address_street_3;
130 var $primary_address_street_2;
131 var $primary_address_street_3;
134 var $table_name = "leads";
135 var $object_name = "Lead";
136 var $object_names = "Leads";
137 var $module_dir = "Leads";
138 var $new_schema = true;
141 var $importable = true;
143 // This is used to retrieve related fields from form posts.
144 var $additional_column_fields = Array('assigned_user_name', 'task_id', 'note_id', 'meeting_id', 'call_id', 'email_id');
145 var $relationship_fields = Array('email_id'=>'emails','call_id'=>'calls','meeting_id'=>'meetings','task_id'=>'tasks',);
151 function get_account()
153 if(isset($this->account_id) && !empty($this->account_id)){
154 $query = "SELECT name , assigned_user_id account_name_owner FROM accounts WHERE id='{$this->account_id}'";
156 //requireSingleResult has beeen deprecated.
157 //$result = $this->db->requireSingleResult($query);
158 $result = $this->db->limitQuery($query,0,1,true, "Want only a single row");
161 $row = $this->db->fetchByAssoc($result);
162 $this->account_name = $row['name'];
163 $this->account_name_owner = $row['account_name_owner'];
164 $this->account_name_mod = 'Accounts';
168 function get_opportunity()
170 if(isset($this->opportunity_id) && !empty($this->opportunity_id)){
171 $query = "SELECT name, assigned_user_id opportunity_name_owner FROM opportunities WHERE id='{$this->opportunity_id}'";
173 //requireSingleResult has beeen deprecated.
174 //$result = $this->db->requireSingleResult($query);
175 $result = $this->db->limitQuery($query,0,1,true, "Want only a single row");
178 $row = $this->db->fetchByAssoc($result);
179 $this->opportunity_name = $row['name'];
180 $this->opportunity_name_owner = $row['opportunity_name_owner'];
181 $this->opportunity_name_mod = 'Opportunities';
185 function get_contact()
188 if(isset($this->contact_id) && !empty($this->contact_id)){
189 $query = "SELECT first_name, last_name, assigned_user_id contact_name_owner FROM contacts WHERE id='{$this->contact_id}'";
191 //requireSingleResult has beeen deprecated.
192 //$result = $this->db->requireSingleResult($query);
193 $result = $this->db->limitQuery($query,0,1,true, "Want only a single row");
195 $row= $this->db->fetchByAssoc($result);
196 $this->contact_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name']);
197 $this->contact_name_owner = $row['contact_name_owner'];
198 $this->contact_name_mod = 'Contacts';
203 function create_list_query($order_by, $where, $show_deleted=0)
205 $custom_join = $this->getCustomJoin();
209 $query .= "$this->table_name.*, users.user_name assigned_user_name";
210 $query .= $custom_join['select'];
211 $query .= " FROM leads ";
213 $query .= " LEFT JOIN users
214 ON leads.assigned_user_id=users.id ";
215 $query .= "LEFT JOIN email_addr_bean_rel eabl ON eabl.bean_id = leads.id AND eabl.bean_module = 'Leads' and eabl.primary_address = 1 and eabl.deleted=0 ";
216 $query .= "LEFT JOIN email_addresses ea ON (ea.id = eabl.email_address_id) ";
217 $query .= $custom_join['join'];
219 if($show_deleted == 0){
220 $where_auto = " leads.deleted=0 ";
221 }else if($show_deleted == 1){
222 $where_auto = " leads.deleted=1 ";
226 $query .= "where ($where) AND ".$where_auto;
228 $query .= "where ".$where_auto; //."and (leads.converted='0')";
230 if(!empty($order_by))
231 $query .= " ORDER BY $order_by";
236 function create_new_list_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false, $parentbean = null, $singleSelect = false){
238 $ret_array = parent::create_new_list_query($order_by, $where, $filter, $params, $show_deleted, $join_type, true, $parentbean, $singleSelect);
239 if(strpos($ret_array['select'],"leads.account_name") == false && strpos($ret_array['select'],"leads.*") == false)
240 $ret_array['select'] .= " ,leads.account_name";
241 if ( !$return_array )
242 return $ret_array['select'] . $ret_array['from'] . $ret_array['where']. $ret_array['order_by'];
246 function converted_lead($leadid, $contactid, $accountid, $opportunityid){
247 $query = "UPDATE leads set converted='1', contact_id=$contactid, account_id=$accountid, opportunity_id=$opportunityid where id=$leadid and deleted=0";
248 $this->db->query($query,true,"Error converting lead: ");
250 //we must move the status out here in order to be able to capture workflow conditions
251 $leadid = str_replace("'","", $leadid);
253 $lead->retrieve($leadid);
254 $lead->status='Converted';
258 function fill_in_additional_list_fields()
260 parent::fill_in_additional_list_fields();
261 $this->_create_proper_name_field();
262 $this->get_account();
266 function fill_in_additional_detail_fields()
268 //Fill in the assigned_user_name
269 //if(!empty($this->status))
270 //$this->status = translate('lead_status_dom', '', $this->status);
271 parent::fill_in_additional_detail_fields();
272 $this->_create_proper_name_field();
273 $this->get_contact();
274 $this->get_opportunity();
275 $this->get_account();
277 if(!empty($this->campaign_id)){
279 $camp = new Campaign();
280 $where = "campaigns.id='$this->campaign_id'";
281 $campaign_list = $camp->get_full_list("campaigns.name", $where, true);
282 if(!empty($campaign_list))
283 $this->campaign_name = $campaign_list[0]->name;
287 function get_list_view_data(){
289 $temp_array = parent::get_list_view_data();
291 $temp_array['ACC_NAME_FROM_ACCOUNTS'] = empty($temp_array['ACC_NAME_FROM_ACCOUNTS']) ? ($temp_array['ACCOUNT_NAME']) : ($temp_array['ACC_NAME_FROM_ACCOUNTS']);
297 * Returns an array of fields that are of type link.
299 * @return array List of fields.
301 * Internal function, do not override.
303 //fix for bug 27339 Shine
304 function get_linked_fields()
306 $linked_fields=array();
307 $fieldDefs = $this->getFieldDefinitions();
309 //find all definitions of type link.
310 if (!empty($fieldDefs))
312 foreach ($fieldDefs as $name=>$properties)
314 if ($name == 'oldmeetings' || $name == 'oldcalls') { continue; }
315 elseif (array_search('link',$properties) === 'type')
317 $linked_fields[$name]=$properties;
321 return $linked_fields;
325 builds a generic search based on the query string using or
326 do not include any $this-> because this is called on without having the class instantiated
328 function build_generic_where_clause ($the_query_string) {
329 $where_clauses = Array();
330 $the_query_string = $GLOBALS['db']->quote($the_query_string);
332 array_push($where_clauses, "leads.last_name like '$the_query_string%'");
333 array_push($where_clauses, "leads.account_name like '$the_query_string%'");
334 array_push($where_clauses, "leads.first_name like '$the_query_string%'");
335 array_push($where_clauses, "ea.email_address like '$the_query_string%'");
337 if (is_numeric($the_query_string)) {
338 array_push($where_clauses, "leads.phone_home like '%$the_query_string%'");
339 array_push($where_clauses, "leads.phone_mobile like '%$the_query_string%'");
340 array_push($where_clauses, "leads.phone_work like '%$the_query_string%'");
341 array_push($where_clauses, "leads.phone_other like '%$the_query_string%'");
342 array_push($where_clauses, "leads.phone_fax like '%$the_query_string%'");
347 foreach($where_clauses as $clause)
349 if($the_where != "") $the_where .= " or ";
350 $the_where .= $clause;
357 function set_notification_body($xtpl, $lead)
359 global $app_list_strings;
362 $xtpl->assign("LEAD_NAME", $locale->getLocaleFormattedName($lead->first_name, $lead->last_name, $lead->salutation));
363 $xtpl->assign("LEAD_SOURCE", (isset($lead->lead_source) ? $app_list_strings['lead_source_dom'][$lead->lead_source] : ""));
364 $xtpl->assign("LEAD_STATUS", (isset($lead->status)? $app_list_strings['lead_status_dom'][$lead->status]:""));
365 $xtpl->assign("LEAD_DESCRIPTION", $lead->description);
370 function bean_implements($interface){
372 case 'ACL':return true;
376 function listviewACLHelper(){
377 $array_assign = parent::listviewACLHelper();
379 if(!empty($this->account_name)){
381 if(!empty($this->account_name_owner)){
382 global $current_user;
383 $is_owner = $current_user->id == $this->account_name_owner;
386 if( ACLController::checkAccess('Accounts', 'view', $is_owner)){
387 $array_assign['ACCOUNT'] = 'a';
389 $array_assign['ACCOUNT'] = 'span';
392 if(!empty($this->opportunity_name)){
394 if(!empty($this->opportunity_name_owner)){
395 global $current_user;
396 $is_owner = $current_user->id == $this->opportunity_name_owner;
399 if( ACLController::checkAccess('Opportunities', 'view', $is_owner)){
400 $array_assign['OPPORTUNITY'] = 'a';
402 $array_assign['OPPORTUNITY'] = 'span';
407 if(!empty($this->contact_name)){
409 if(!empty($this->contact_name_owner)){
410 global $current_user;
411 $is_owner = $current_user->id == $this->contact_name_owner;
414 if( ACLController::checkAccess('Contacts', 'view', $is_owner)){
415 $array_assign['CONTACT'] = 'a';
417 $array_assign['CONTACT'] = 'span';
420 return $array_assign;
423 //carrys forward custom lead fields to contacts, accounts, opportunities during Lead Conversion
424 function convertCustomFieldsForm(&$form, &$tempBean, &$prefix) {
426 global $mod_strings, $app_list_strings, $app_strings, $lbl_required_symbol;
428 foreach($this->field_defs as $field => $value) {
430 if(!empty($value['source']) && $value['source'] == 'custom_fields') {
431 if( !empty($tempBean->field_defs[$field]) AND isset($tempBean->field_defs[$field]) ) {
432 $form .= "<tr><td nowrap colspan='4' class='dataLabel'>".$mod_strings[$tempBean->field_defs[$field]['vname']].":";
434 if( !empty($tempBean->custom_fields->avail_fields[$field]['required']) AND ( ($tempBean->custom_fields->avail_fields[$field]['required']== 1) OR ($tempBean->custom_fields->avail_fields[$field]['required']== '1') OR ($tempBean->custom_fields->avail_fields[$field]['required']== 'true') OR ($tempBean->custom_fields->avail_fields[$field]['required']== true) ) ) {
435 $form .= " <span class='required'>".$lbl_required_symbol."</span>";
437 $form .= "</td></tr>";
438 $form .= "<tr><td nowrap colspan='4' class='dataField' nowrap>";
440 if(isset($value['isMultiSelect']) && $value['isMultiSelect'] == 1){
441 $this->$field = unencodeMultienum($this->$field);
442 $multiple = "multiple";
449 if(!empty($value['options']) AND isset($value['options']) ) {
450 $form .= "<select " . $multiple . " name='".$prefix.$field.$array."'>";
451 $form .= get_select_options_with_id($app_list_strings[$value['options']], $this->$field);
453 } elseif($value['type'] == 'bool' ) {
454 if( ($this->$field == 1) OR ($this->$field == '1') ) { $checked = 'checked'; } else { $checked = ''; }
455 $form .= "<input type='checkbox' name='".$prefix.$field."' id='".$prefix.$field."' value='1' ".$checked."/>";
456 } elseif($value['type'] == 'text' ) {
457 $form .= "<textarea name='".$prefix.$field."' rows='6' cols='50'>".$this->$field."</textarea>";
458 } elseif($value['type'] == 'date' ) {
459 $form .= "<input name='".$prefix.$field."' id='jscal_field".$field."' type='text' size='11' maxlength='10' value='".$this->$field."'> ".SugarThemeRegistry::current()->getImage("jscalendar", "id='jscal_trigger".$field."' align='absmiddle'", null, null, ".gif", $mod_strings['LBL_ENTERDATE'])."' <span class='dateFormat'>yyyy-mm-dd</span><script type='text/javascript'>Calendar.setup ({inputField : 'jscal_field".$field."', ifFormat : '%Y-%m-%d', showsTime : false, button : 'jscal_trigger".$field."', singleClick : true, step : 1, weekNumbers:false}); addToValidate('ConvertLead', '".$field."', 'date', false,'".$mod_strings[$tempBean->field_defs[$field]['vname']]."' );</script>";
461 $form .= "<input name='".$prefix.$field."' type='text' value='".$this->$field."'>";
463 if($this->custom_fields->avail_fields[$field]['type'] == 'int') {
464 $form .= "<script>addToValidate('ConvertLead', '".$prefix.$field."', 'int', false,'".$prefix.":".$mod_strings[$tempBean->field_defs[$field]['vname']]."' );</script>";
466 elseif($this->custom_fields->avail_fields[$field]['type'] == 'float') {
467 $form .= "<script>addToValidate('ConvertLead', '".$prefix.$field."', 'float', false,'".$prefix.":".$mod_strings[$tempBean->field_defs[$field]['vname']]."' );</script>";
472 if( !empty($tempBean->custom_fields->avail_fields[$field]['required']) AND ( ($tempBean->custom_fields->avail_fields[$field]['required']== 1) OR ($tempBean->custom_fields->avail_fields[$field]['required']== '1') OR ($tempBean->custom_fields->avail_fields[$field]['required']== 'true') OR ($tempBean->custom_fields->avail_fields[$field]['required']== true) ) ) {
473 $form .= "<script>addToValidate('ConvertLead', '".$prefix.$field."', 'relate', true,'".$prefix.":".$mod_strings[$tempBean->field_defs[$field]['vname']]."' );</script>";
476 $form .= "</td></tr>";
487 function save($check_notify = false) {
488 if(empty($this->status))
489 $this->status = 'New';
490 // call save first so that $this->id will be set
491 $value = parent::save($check_notify);
494 function get_unlinked_email_query($type=array()) {
496 return get_unlinked_email_query($type, $this);
500 * Returns query to find the related calls created pre-5.1
502 * @return string SQL statement
504 public function get_old_related_calls()
506 $return_array['select']='SELECT calls.id ';
507 $return_array['from']='FROM calls ';
508 $return_array['where']=" WHERE calls.parent_id = '$this->id'
509 AND calls.parent_type = 'Leads' AND calls.id NOT IN ( SELECT call_id FROM calls_leads ) ";
510 $return_array['join'] = "";
511 $return_array['join_tables'][0] = '';
513 return $return_array;
517 * Returns array of lead conversion activity options
519 * @return string SQL statement
521 public static function getActivitiesOptions() {
523 if (isset($GLOBALS['app_list_strings']['lead_conv_activity_opt'])) {
524 return $GLOBALS['app_list_strings']['lead_conv_activity_opt'];
532 * Returns query to find the related meetings created pre-5.1
534 * @return string SQL statement
536 public function get_old_related_meetings()
538 $return_array['select']='SELECT meetings.id ';
539 $return_array['from']='FROM meetings ';
540 $return_array['where']=" WHERE meetings.parent_id = '$this->id'
541 AND meetings.parent_type = 'Leads' AND meetings.id NOT IN ( SELECT meeting_id FROM meetings_leads ) ";
542 $return_array['join'] = "";
543 $return_array['join_tables'][0] = '';
545 return $return_array;