]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/Contacts/Contact.php
Release 6.5.15
[Github/sugarcrm.git] / modules / Contacts / Contact.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-2013 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 /*********************************************************************************
39
40  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
41  * All Rights Reserved.
42  * Contributor(s): ______________________________________..
43  ********************************************************************************/
44
45 require_once('include/SugarObjects/templates/person/Person.php');
46 // Contact is used to store customer information.
47 class Contact extends Person {
48     var $field_name_map;
49         // Stored fields
50         var $id;
51         var $name = '';
52         var $lead_source;
53         var $date_entered;
54         var $date_modified;
55         var $modified_user_id;
56         var $assigned_user_id;
57         var $created_by;
58         var $created_by_name;
59         var $modified_by_name;
60
61         var $description;
62         var $salutation;
63         var $first_name;
64         var $last_name;
65         var $title;
66         var $department;
67         var $birthdate;
68         var $reports_to_id;
69         var $do_not_call;
70         var $phone_home;
71         var $phone_mobile;
72         var $phone_work;
73         var $phone_other;
74         var $phone_fax;
75         var $email1;
76         var $email_and_name1;
77         var $email_and_name2;
78         var $email2;
79         var $assistant;
80         var $assistant_phone;
81         var $email_opt_out;
82         var $primary_address_street;
83         var $primary_address_city;
84         var $primary_address_state;
85         var $primary_address_postalcode;
86         var $primary_address_country;
87         var $alt_address_street;
88         var $alt_address_city;
89         var $alt_address_state;
90         var $alt_address_postalcode;
91         var $alt_address_country;
92         var $portal_name;
93         var $portal_app;
94         var $portal_active;
95         var $contacts_users_id;
96         // These are for related fields
97         var $bug_id;
98         var $account_name;
99         var $account_id;
100         var $report_to_name;
101         var $opportunity_role;
102         var $opportunity_rel_id;
103         var $opportunity_id;
104         var $case_role;
105         var $case_rel_id;
106         var $case_id;
107         var $task_id;
108         var $note_id;
109         var $meeting_id;
110         var $call_id;
111         var $email_id;
112         var $assigned_user_name;
113         var $accept_status;
114     var $accept_status_id;
115     var $accept_status_name;
116     var $alt_address_street_2;
117     var $alt_address_street_3;
118     var $opportunity_role_id;
119     var $portal_password;
120     var $primary_address_street_2;
121     var $primary_address_street_3;
122     var $campaign_id;
123     var $sync_contact;
124         var $full_name; // l10n localized name
125         var $invalid_email;
126         var $table_name = "contacts";
127         var $rel_account_table = "accounts_contacts";
128         //This is needed for upgrade.  This table definition moved to Opportunity module.
129         var $rel_opportunity_table = "opportunities_contacts";
130
131         var $object_name = "Contact";
132         var $module_dir = 'Contacts';
133         var $emailAddress;
134         var $new_schema = true;
135         var $importable = true;
136
137         // This is used to retrieve related fields from form posts.
138         var $additional_column_fields = Array('bug_id', 'assigned_user_name', 'account_name', 'account_id', 'opportunity_id', 'case_id', 'task_id', 'note_id', 'meeting_id', 'call_id', 'email_id'
139         );
140
141         var $relationship_fields = Array('account_id'=> 'accounts','bug_id' => 'bugs', 'call_id'=>'calls','case_id'=>'cases','email_id'=>'emails',
142                                                                 'meeting_id'=>'meetings','note_id'=>'notes','task_id'=>'tasks', 'opportunity_id'=>'opportunities', 'contacts_users_id' => 'user_sync'
143                                                                 );
144
145         function Contact() {
146                 parent::Person();
147         }
148
149         function add_list_count_joins(&$query, $where)
150         {
151                 // accounts.name
152                 if(stristr($where, "accounts.name"))
153                 {
154                         // add a join to the accounts table.
155                         $query .= "
156                     LEFT JOIN accounts_contacts
157                     ON contacts.id=accounts_contacts.contact_id
158                     LEFT JOIN accounts
159                     ON accounts_contacts.account_id=accounts.id
160                         ";
161                 }
162         $custom_join = $this->getCustomJoin();
163         $query .= $custom_join['join'];
164
165
166         }
167
168         function listviewACLHelper(){
169                 $array_assign = parent::listviewACLHelper();
170                 $is_owner = false;
171                 //MFH BUG 18281; JChi #15255
172                 $is_owner = !empty($this->assigned_user_id) && $this->assigned_user_id == $GLOBALS['current_user']->id;
173                         if(!ACLController::moduleSupportsACL('Accounts') || ACLController::checkAccess('Accounts', 'view', $is_owner)){
174                                 $array_assign['ACCOUNT'] = 'a';
175                         }else{
176                                 $array_assign['ACCOUNT'] = 'span';
177
178                         }
179                 return $array_assign;
180         }
181
182         function create_new_list_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false)
183         {
184                 //if this is from "contact address popup" action, then process popup list query
185                 if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'ContactAddressPopup'){
186                         return $this->address_popup_create_new_list_query($order_by, $where, $filter, $params, $show_deleted, $join_type, $return_array, $parentbean, $singleSelect);
187
188                 }else{
189                         //any other action goes to parent function in sugarbean
190                         if(strpos($order_by,'sync_contact') !== false){
191                                 //we have found that the user is ordering by the sync_contact field, it would be troublesome to sort by this field
192                                 //and perhaps a performance issue, so just remove it
193                                 $order_by = '';
194                         }
195                         return parent::create_new_list_query($order_by, $where, $filter, $params, $show_deleted, $join_type, $return_array, $parentbean, $singleSelect);
196                 }
197
198
199         }
200
201
202
203         function address_popup_create_new_list_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false)
204         {
205                 //if this is any action that is not the contact address popup, then go to parent function in sugarbean
206                 if(isset($_REQUEST['action']) && $_REQUEST['action'] !== 'ContactAddressPopup'){
207                         return parent::create_new_list_query($order_by, $where, $filter, $params, $show_deleted, $join_type, $return_array, $parentbean, $singleSelect);
208                 }
209
210         $custom_join = $this->getCustomJoin();
211                 // MFH - BUG #14208 creates alias name for select
212                 $select_query = "SELECT ";
213                 $select_query .= db_concat($this->table_name,array('first_name','last_name')) . " name, ";
214                 $select_query .= "
215                                 $this->table_name.*,
216                 accounts.name as account_name,
217                 accounts.id as account_id,
218                 accounts.assigned_user_id account_id_owner,
219                 users.user_name as assigned_user_name ";
220         $select_query .= $custom_join['select'];
221                 $ret_array['select'] = $select_query;
222
223                 $from_query = "
224                 FROM contacts ";
225
226                 $from_query .=          "LEFT JOIN users
227                             ON contacts.assigned_user_id=users.id
228                             LEFT JOIN accounts_contacts
229                             ON contacts.id=accounts_contacts.contact_id  and accounts_contacts.deleted = 0
230                             LEFT JOIN accounts
231                             ON accounts_contacts.account_id=accounts.id AND accounts.deleted=0 ";
232                 $from_query .= "LEFT JOIN email_addr_bean_rel eabl  ON eabl.bean_id = contacts.id AND eabl.bean_module = 'Contacts' and eabl.primary_address = 1 and eabl.deleted=0 ";
233         $from_query .= "LEFT JOIN email_addresses ea ON (ea.id = eabl.email_address_id) ";
234         $from_query .= $custom_join['join'];
235                 $ret_array['from'] = $from_query;
236                 $ret_array['from_min'] = 'from contacts';
237
238                 $where_auto = '1=1';
239                 if($show_deleted == 0){
240                 $where_auto = " $this->table_name.deleted=0 ";
241                 //$where_auto .= " AND accounts.deleted=0  ";
242                 }else if($show_deleted == 1){
243                                 $where_auto = " $this->table_name.deleted=1 ";
244                 }
245
246
247                 if($where != ""){
248                         $where_query = "where ($where) AND ".$where_auto;
249                 }else{
250                         $where_query = "where ".$where_auto;
251                 }
252
253
254                 $ret_array['where'] = $where_query;
255         $ret_array['order_by'] = '';
256
257         //process order by and add if it's not empty
258         $order_by = $this->process_order_by($order_by);
259         if (!empty($order_by)) {
260             $ret_array['order_by'] = ' ORDER BY ' . $order_by;
261         }
262
263                 if($return_array)
264         {
265                 return $ret_array;
266         }
267
268             return $ret_array['select'] . $ret_array['from'] . $ret_array['where']. $ret_array['order_by'];
269
270         }
271
272
273
274
275         function create_export_query(&$order_by, &$where, $relate_link_join='')
276         {
277             $custom_join = $this->getCustomJoin(true, true, $where);
278             $custom_join['join'] .= $relate_link_join;
279                          $query = "SELECT
280                                 contacts.*,
281                                 email_addresses.email_address email_address,
282                                 '' email_addresses_non_primary, " . // email_addresses_non_primary needed for get_field_order_mapping()
283                                 "accounts.name as account_name,
284                                 users.user_name as assigned_user_name ";
285             $query .= $custom_join['select'];
286                                                  $query .= " FROM contacts ";
287                          $query .= "LEFT JOIN users
288                                         ON contacts.assigned_user_id=users.id ";
289                              $query .= "LEFT JOIN accounts_contacts
290                                         ON ( contacts.id=accounts_contacts.contact_id and (accounts_contacts.deleted is null or accounts_contacts.deleted = 0))
291                                         LEFT JOIN accounts
292                                         ON accounts_contacts.account_id=accounts.id ";
293
294                                                 //join email address table too.
295                                                 $query .=  ' LEFT JOIN  email_addr_bean_rel on contacts.id = email_addr_bean_rel.bean_id and email_addr_bean_rel.bean_module=\'Contacts\' and email_addr_bean_rel.deleted=0 and email_addr_bean_rel.primary_address=1 ';
296                                                 $query .=  ' LEFT JOIN email_addresses on email_addresses.id = email_addr_bean_rel.email_address_id ' ;
297
298             $query .= $custom_join['join'];
299
300                 $where_auto = "( accounts.deleted IS NULL OR accounts.deleted=0 )
301                       AND contacts.deleted=0 ";
302
303                 if($where != "")
304                         $query .= "where ($where) AND ".$where_auto;
305                 else
306                         $query .= "where ".$where_auto;
307
308         $order_by = $this->process_order_by($order_by);
309         if (!empty($order_by)) {
310             $query .= ' ORDER BY ' . $order_by;
311         }
312
313                 return $query;
314         }
315
316         function fill_in_additional_list_fields() {
317                 parent::fill_in_additional_list_fields();
318                 $this->_create_proper_name_field();
319                 // cn: bug 8586 - l10n names for Contacts in Email TO: field
320                 $this->email_and_name1 = "{$this->full_name} &lt;".$this->email1."&gt;";
321                 $this->email_and_name2 = "{$this->full_name} &lt;".$this->email2."&gt;";
322
323                 if($this->force_load_details == true) {
324                         $this->fill_in_additional_detail_fields();
325                 }
326         }
327
328         function fill_in_additional_detail_fields() {
329                 parent::fill_in_additional_detail_fields();
330         if(empty($this->id)) return;
331
332         global $locale, $app_list_strings, $current_user;
333
334                 // retrieve the account information and the information about the person the contact reports to.
335                 $query = "SELECT acc.id, acc.name, con_reports_to.first_name, con_reports_to.last_name
336                 from contacts
337                 left join accounts_contacts a_c on a_c.contact_id = '".$this->id."' and a_c.deleted=0
338                 left join accounts acc on a_c.account_id = acc.id and acc.deleted=0
339                 left join contacts con_reports_to on con_reports_to.id = contacts.reports_to_id
340                 where contacts.id = '".$this->id."'";
341                 // Bug 43196 - If a contact is related to multiple accounts, make sure we pull the one we are looking for
342                 // Bug 44730  was introduced due to this, fix is to simply clear any whitespaces around the account_id first
343
344         $clean_account_id = trim($this->account_id);
345
346         if ( !empty($clean_account_id) ) {
347                     $query .= " and acc.id = '{$this->account_id}'";
348                 }
349
350         $query .= " ORDER BY a_c.date_modified DESC";
351
352                 $result = $this->db->query($query,true," Error filling in additional detail fields: ");
353
354                 // Get the id and the name.
355                 $row = $this->db->fetchByAssoc($result);
356
357                 if($row != null)
358                 {
359                         $this->account_name = $row['name'];
360                         $this->account_id = $row['id'];
361                         $this->report_to_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name'],'','','',null,true);
362                 }
363                 else
364                 {
365                         $this->account_name = '';
366                         $this->account_id = '';
367                         $this->report_to_name = '';
368                 }
369                 $this->load_contacts_users_relationship();
370                 /** concating this here because newly created Contacts do not have a
371                  * 'name' attribute constructed to pass onto related items, such as Tasks
372                  * Notes, etc.
373                  */
374                 $this->name = $locale->getLocaleFormattedName($this->first_name, $this->last_name);
375         if(!empty($this->contacts_users_id)) {
376                    $this->sync_contact = true;
377                 }
378
379                 if(!empty($this->portal_active) && $this->portal_active == 1) {
380                    $this->portal_active = true;
381                 }
382         // Set campaign name if there is a campaign id
383                 if( !empty($this->campaign_id)){
384
385                         $camp = new Campaign();
386                     $where = "campaigns.id='{$this->campaign_id}'";
387                     $campaign_list = $camp->get_full_list("campaigns.name", $where, true);
388                     $this->campaign_name = $campaign_list[0]->name;
389                 }
390         }
391
392                 /**
393                 loads the contacts_users relationship to populate a checkbox
394                 where a user can select if they would like to sync a particular
395                 contact to Outlook
396         */
397         function load_contacts_users_relationship(){
398                 global $current_user;
399
400                 $this->load_relationship("user_sync");
401
402         $beanIDs = $this->user_sync->get();
403
404         if( in_array($current_user->id, $beanIDs) )
405         {
406             $this->contacts_users_id = $current_user->id;
407         }
408         }
409
410         function get_list_view_data($filter_fields = array()) {
411
412         $temp_array = parent::get_list_view_data();
413
414                 if($filter_fields && !empty($filter_fields['sync_contact'])){
415                         $this->load_contacts_users_relationship();
416                         $temp_array['SYNC_CONTACT'] = !empty($this->contacts_users_id) ? 1 : 0;
417                 }
418
419         $temp_array['EMAIL_AND_NAME1'] = "{$this->full_name} &lt;".$temp_array['EMAIL1']."&gt;";
420
421                 return $temp_array;
422         }
423
424         /**
425                 builds a generic search based on the query string using or
426                 do not include any $this-> because this is called on without having the class instantiated
427         */
428         function build_generic_where_clause ($the_query_string)
429         {
430                 $where_clauses = Array();
431                 $the_query_string = $this->db->quote($the_query_string);
432
433                 array_push($where_clauses, "contacts.last_name like '$the_query_string%'");
434                 array_push($where_clauses, "contacts.first_name like '$the_query_string%'");
435                 array_push($where_clauses, "accounts.name like '$the_query_string%'");
436                 array_push($where_clauses, "contacts.assistant like '$the_query_string%'");
437                 array_push($where_clauses, "ea.email_address like '$the_query_string%'");
438
439                 if (is_numeric($the_query_string))
440                 {
441                         array_push($where_clauses, "contacts.phone_home like '%$the_query_string%'");
442                         array_push($where_clauses, "contacts.phone_mobile like '%$the_query_string%'");
443                         array_push($where_clauses, "contacts.phone_work like '%$the_query_string%'");
444                         array_push($where_clauses, "contacts.phone_other like '%$the_query_string%'");
445                         array_push($where_clauses, "contacts.phone_fax like '%$the_query_string%'");
446                         array_push($where_clauses, "contacts.assistant_phone like '%$the_query_string%'");
447                 }
448
449                 $the_where = "";
450                 foreach($where_clauses as $clause)
451                 {
452                         if($the_where != "") $the_where .= " or ";
453                         $the_where .= $clause;
454                 }
455
456
457                 return $the_where;
458         }
459
460         function set_notification_body($xtpl, $contact)
461         {
462             global $locale;
463
464                 $xtpl->assign("CONTACT_NAME", trim($locale->getLocaleFormattedName($contact->first_name, $contact->last_name)));
465                 $xtpl->assign("CONTACT_DESCRIPTION", $contact->description);
466
467                 return $xtpl;
468         }
469
470         function get_contact_id_by_email($email)
471         {
472                 $email = trim($email);
473                 if(empty($email)){
474                         //email is empty, no need to query, return null
475                         return null;
476                 }
477
478                 $where_clause = "(email1='$email' OR email2='$email') AND deleted=0";
479
480         $query = "SELECT id FROM $this->table_name WHERE $where_clause";
481         $GLOBALS['log']->debug("Retrieve $this->object_name: ".$query);
482                 $result = $this->db->getOne($query, true, "Retrieving record $where_clause:");
483
484                 return empty($result)?null:$result;
485         }
486
487         function save_relationship_changes($is_update) {
488
489                 //if account_id was replaced unlink the previous account_id.
490                 //this rel_fields_before_value is populated by sugarbean during the retrieve call.
491                 if (!empty($this->account_id) and !empty($this->rel_fields_before_value['account_id']) and
492                                 (trim($this->account_id) != trim($this->rel_fields_before_value['account_id']))) {
493                                 //unlink the old record.
494                                 $this->load_relationship('accounts');
495                                 $this->accounts->delete($this->id,$this->rel_fields_before_value['account_id']);
496                 }
497                 parent::save_relationship_changes($is_update);
498         }
499
500         function bean_implements($interface)
501         {
502                 switch($interface){
503                         case 'ACL':return true;
504                 }
505                 return false;
506         }
507
508         function get_unlinked_email_query($type=array())
509         {
510                 return get_unlinked_email_query($type, $this);
511         }
512
513     /**
514      * used by import to add a list of users
515      *
516      * Parameter can be one of the following:
517      * - string 'all': add this contact for all users
518      * - comma deliminated lists of teams and/or users
519      *
520      * @param string $list_of_user
521      */
522     function process_sync_to_outlook($list_of_users)
523     {
524         static $focus_user;
525
526         // cache this object since we'll be reusing it a bunch
527         if ( !($focus_user instanceof User) ) {
528
529             $focus_user = new User();
530         }
531
532
533                 if ( empty($list_of_users) ) {
534             return;
535                 }
536         if ( !isset($this->users) ) {
537             $this->load_relationship('user_sync');
538         }
539
540                 if ( strtolower($list_of_users) == 'all' ) {
541             // add all non-deleted users
542                         $sql = "SELECT id FROM users WHERE deleted=0 AND is_group=0 AND portal_only=0";
543                         $result=$this->db->query($sql);
544                         while ( $hash = $this->db->fetchByAssoc($result) ) {
545                 $this->user_sync->add($hash['id']);
546                         }
547                 }
548         else {
549             $theList = explode(",",$list_of_users);
550             foreach ($theList as $eachItem) {
551                 if ( ($user_id = $focus_user->retrieve_user_id($eachItem))
552                         || $focus_user->retrieve($eachItem)) {
553                     // it is a user, add user
554                     $this->user_sync->add($user_id ? $user_id : $focus_user->id);
555                     return;
556                 }
557                         }
558                 }
559         }
560 }