2 if (!defined('sugarEntry') || !sugarEntry)
3 die('Not A Valid Entry Point');
4 /*********************************************************************************
5 * SugarCRM Community Edition is a customer relationship management program developed by
6 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Affero General Public License version 3 as published by the
10 * Free Software Foundation with the addition of the following permission added
11 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
12 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
13 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
20 * You should have received a copy of the GNU Affero General Public License along with
21 * this program; if not, see http://www.gnu.org/licenses or write to the Free
22 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
26 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
28 * The interactive user interfaces in modified source and object code versions
29 * of this program must display Appropriate Legal Notices, as required under
30 * Section 5 of the GNU Affero General Public License version 3.
32 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
33 * these Appropriate Legal Notices must retain the display of the "Powered by
34 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
35 * technical reasons, the Appropriate Legal Notices must display the words
36 * "Powered by SugarCRM".
37 ********************************************************************************/
39 /*********************************************************************************
41 * Description: TODO: To be written.
42 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
43 * All Rights Reserved.
44 * Contributor(s): ______________________________________..
45 ********************************************************************************/
49 require_once ('include/JSON.php');
50 $timedate = TimeDate::getInstance();
53 global $app_list_strings;
54 global $current_language;
56 global $currentModule;
58 global $filter_for_valid_editable_attributes;
59 //filter condition for fields in vardefs that can participate in merge.
60 $filter_for_valid_editable_attributes =
62 array('type'=>'datetimecombo','source'=>'db'),
63 array('type'=>'datetime','source'=>'db'),
64 array('type'=>'varchar','source'=>'db'),
65 array('type'=>'enum','source'=>'db'),
66 array('type'=>'multienum','source'=>'db'),
67 array('type'=>'text','source'=>'db'),
68 array('type'=>'date','source'=>'db'),
69 array('type'=>'time','source'=>'db'),
70 array('type'=>'int','source'=>'db'),
71 array('type'=>'long','source'=>'db'),
72 array('type'=>'double','source'=>'db'),
73 array('type'=>'float','source'=>'db'),
74 array('type'=>'short','source'=>'db'),
75 array('dbType'=>'varchar','source'=>'db'),
76 array('dbType'=>'double','source'=>'db'),
77 array('type'=>'relate'),
80 $filter_for_valid_related_attributes = array( array('type'=>'link'),);
81 $filter_for_invalid_related_attributes = array(array('type'=>'link','link_type'=>'one'));
83 //following attributes will be ignored from the merge process.
84 $invalid_attribute_by_name= array('date_entered'=>'date_entered','date_modified'=>'date_modified','modified_user_id'=>'modified_user_id', 'created_by'=>'created_by','deleted'=>'deleted');
86 $merge_ids_array = array ();
87 if (isset($_REQUEST['change_parent']) && $_REQUEST['change_parent']=='1') {
88 $base_id=$_REQUEST['change_parent_id'];
89 foreach ($_REQUEST['merged_ids'] as $id) {
90 if ($id != $base_id) {
91 $merge_ids_array[] = $id;
94 //add the existing parent to merged_id array.
95 $merge_ids_array[] = $_REQUEST['record'];
96 } elseif (isset($_REQUEST['remove']) && $_REQUEST['remove']=='1') {
97 $base_id=$_REQUEST['record'];
98 $removed_id= $_REQUEST['remove_id'];
99 foreach ($_REQUEST['merged_ids'] as $id) {
100 if ($id != $removed_id) {
101 $merge_ids_array[] = $id;
105 $base_id=$_REQUEST['record'];
106 foreach ($_REQUEST['mass'] as $id) {
107 $merge_ids_array[] = $id;
110 $focus = new MergeRecord();
111 $focus->load_merge_bean($_REQUEST['merge_module'], true, $base_id);
113 $params[] = "<a href='index.php?module={$focus->merge_bean->module_dir}&action=index'>{$GLOBALS['app_list_strings']['moduleList'][$focus->merge_bean->module_dir]}</a>";
114 $params[] = $mod_strings['LBL_MODULE_NAME'];
115 $params[] = $focus->merge_bean->name;
116 echo getClassicModuleTitle($focus->merge_bean->module_dir, $params, true);
118 $mergeBeanArray = array ();
120 //render a column for each record to merge
122 $merge_records_names=array();
123 foreach ($merge_ids_array as $id) {
124 require_once ($focus->merge_bean_file_path);
125 $mergeBeanArray[$id] = new $focus->merge_bean_class();
126 $mergeBeanArray[$id]->retrieve($id);
127 $merge_records_names[]=$mergeBeanArray[$id]->get_summary_text();
129 $merged_ids.="<input type='hidden' name='merged_ids[]' value='$id'>";
132 $col_width=floor(80/$records).'%';
133 global $max_data_length;
134 $max_data_length=floor(65/$records);
136 $xtpl = new XTemplate("modules/MergeRecords/Step3.html");
137 $xtpl->assign("MOD", $mod_strings);
138 $xtpl->assign("APP", $app_strings);
140 $xtpl->assign("ID", $focus->merge_bean->id);
141 $xtpl->assign("MERGE_MODULE", $focus->merge_module);
143 $xtpl->assign("MERGED_IDS", $merged_ids);
145 //set return parameters.
146 if (!empty ($_REQUEST['return_module'])) {
147 $xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']);
149 if (!empty ($_REQUEST['return_action'])) {
150 $xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']);
152 if (!empty ($_REQUEST['return_id'])) {
153 $xtpl->assign("RETURN_ID", $_REQUEST['return_id']);
156 $temp_field_array = $focus->merge_bean->field_defs;
158 $json = new JSON(JSON_LOOSE_TYPE);
160 foreach ($temp_field_array as $field_array) {
163 if (show_field($field_array)
166 $select_row_curr_field_value = null;
167 $b_values_different = false;
168 $section_name='merge_row_similar';
170 //Prcoess locaton of the field. if values are different show field in first section. else 2nd.
171 $select_row_curr_field_value = $focus->merge_bean->$field_array['name'];
172 foreach ($merge_ids_array as $id) {
173 if (($mergeBeanArray[$id]-> $field_array['name']=='' and $select_row_curr_field_value =='') or $mergeBeanArray[$id]-> $field_array['name'] == $select_row_curr_field_value ) {
174 $section_name='merge_row_similar';
176 $section_name='merge_row_diff';
181 //check for vname in mod strings first, then app, else just display name
182 $col_name = $field_array['name'];
183 if (isset ($focus->merge_bean_strings[$field_array['vname']]) && $focus->merge_bean_strings[$field_array['vname']] != '')
184 $xtpl->assign("FIELD_LABEL", $focus->merge_bean_strings[$field_array['vname']]);
185 elseif (isset ($app_strings[$field_array['vname']]) && $app_strings[$field_array['vname']] != '') $xtpl->assign("FIELD_LABEL", $app_strings[$field_array['vname']]);
187 $xtpl->assign("FIELD_LABEL", $field_array['name']);
188 //if required add signage.
189 if (!empty($focus->merge_bean->required_fields[$col_name]) or $col_name=='team_name') {
190 $xtpl->assign("REQUIRED_SYMBOL","<span class='required'>".$app_strings['LBL_REQUIRED_SYMBOL']."</span>");
192 $xtpl->assign("REQUIRED_SYMBOL","");
195 $xtpl->assign("CELL_WIDTH", "20%");
196 $xtpl->parse("main.".$section_name.".merge_cell_label");
198 if (isset ($field_array['custom_type']) && $field_array['custom_type'] != '')
199 $field_check = $field_array['custom_type'];
201 $field_check = $field_array['type'];
204 if(preg_match('/.*?_address_street$/', $field_array['name'])) {
205 $field_check = 'text';
208 $xtpl->assign("EDIT_FIELD_NAME", $field_array['name']);
209 $xtpl->assign("TAB_INDEX", $field_count);
211 switch ($field_check) {
217 case ('custom_fields') :
224 $xtpl->assign("EDIT_FIELD_VALUE", $select_row_curr_field_value);
225 $xtpl->assign("CELL_WIDTH", $col_width);
226 $xtpl->parse("main.".$section_name.".merge_cell_edit_text");
229 $xtpl->assign("EDIT_FIELD_VALUE", $select_row_curr_field_value);
230 $xtpl->assign("CELL_WIDTH", $col_width);
231 $xtpl->parse("main.".$section_name.".merge_cell_edit_textarea");
234 $xtpl->assign("SELECT_OPTIONS", get_select_options_with_id($app_list_strings[$field_array['options']], $select_row_curr_field_value));
235 $xtpl->assign("CELL_WIDTH",$col_width);
236 $xtpl->parse("main.".$section_name.".merge_cell_edit_dropdown");
239 $select_row_curr_field_value = unencodeMultienum($select_row_curr_field_value);
240 $xtpl->assign("SELECT_OPTIONS", get_select_options_with_id($app_list_strings[$field_array['options']], $select_row_curr_field_value));
241 $xtpl->assign("CELL_WIDTH",$col_width);
242 $xtpl->parse("main.".$section_name.".merge_cell_edit_multidropdown");
244 //popup fields need to be fixed.., cant automate with vardefs
246 if(!empty($field_array['link'])) {
247 $exclude[$field_array['link']] = $field_array['link'];
251 if (empty($select_row_curr_field_value)) {
252 $related_name=get_related_name($field_array,$focus->merge_bean->$field_array['id_name']);
253 if ($related_name !== false ) {
254 $select_row_curr_field_value=$related_name;
257 if($field_check == 'link') {//relate type should not enter this.
258 $exclude[$field_array['name']] = $field_array['name'];
260 $xtpl->assign("POPUP_ID_FIELD", $field_array['id_name']);
261 $xtpl->assign("POPUP_NAME_FIELD", $field_array['name']);
262 $xtpl->assign("POPUP_NAME_VALUE", $select_row_curr_field_value);
263 $xtpl->assign("POPUP_ID_VALUE", $focus->merge_bean-> $field_array['id_name']);
264 $xtpl->assign("POPUP_MODULE", $field_array['module']);
265 $xtpl->assign("CELL_WIDTH", $col_width);
266 $xtpl->assign("MERGED_LINKS", implode(',', $exclude));
268 $popup_data = array ('call_back_function' => 'set_return', 'form_name' => 'EditView', 'field_to_name_array' => array ('id' => $field_array['id_name'], 'name' => $field_array['name'],),);
269 $xtpl->assign('ENCODED_POPUP_DATA', $json->encode($popup_data));
271 $xtpl->parse("main.".$section_name.".merge_cell_edit_popup");
274 if (($select_row_curr_field_value == '1' || $select_row_curr_field_value == 'yes' || $select_row_curr_field_value == 'on') && !empty($select_row_curr_field_value))
275 $xtpl->assign("EDIT_FIELD_VALUE", " checked");
277 $xtpl->assign("EDIT_FIELD_VALUE", "");
279 $xtpl->assign("CELL_WIDTH", $col_width);
280 $xtpl->parse("main.".$section_name.".merge_cell_edit_checkbox");
284 $xtpl->assign("CALENDAR_LANG", "en");
285 $xtpl->assign("USER_DATEFORMAT", '('.$timedate->get_user_date_format().')');
286 $xtpl->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format());
287 $xtpl->assign("EDIT_FIELD_VALUE", $select_row_curr_field_value);
288 $xtpl->assign("CELL_WIDTH", $col_width);
289 $xtpl->assign("THEME", $theme);
290 $xtpl->parse("main.".$section_name.".merge_cell_edit_date");
292 case ('datetimecombo') :
293 $xtpl->assign("CALENDAR_LANG", "en");
294 $xtpl->assign("USER_DATEFORMAT", $timedate->get_user_time_format());
295 $xtpl->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format());
296 $xtpl->assign("EDIT_FIELD_VALUE", $select_row_curr_field_value);
297 $xtpl->assign("CELL_WIDTH", $col_width);
298 $xtpl->assign("THEME", $theme);
299 $xtpl->parse("main.".$section_name.".merge_cell_edit_datetime");
305 //render a column for each selected record to merge
306 foreach ($merge_ids_array as $id) {
307 $xtpl->assign("CELL_WIDTH", $col_width);
309 switch ($field_check) {
311 if (($mergeBeanArray[$id]->$field_array['name'] == '1' || $mergeBeanArray[$id]->$field_array['name'] == 'yes' || $mergeBeanArray[$id]->$field_array['name'] == 'on') && !empty($mergeBeanArray[$id]->$field_array['name'])) {
312 $xtpl->assign("FIELD_VALUE", " checked");
314 $xtpl->assign("FIELD_VALUE", "");
316 $field_name="main.".$section_name.".merge_cell_field_value_checkbox";
319 if ($mergeBeanArray[$id]-> $field_array['name'] != '' and isset($field_array['options']) and isset($app_list_strings[$field_array['options']][$mergeBeanArray[$id]-> $field_array['name']])) {
320 display_field_value( $app_list_strings[$field_array['options']][$mergeBeanArray[$id]-> $field_array['name']]);
322 display_field_value($mergeBeanArray[$id]-> $field_array['name']);
324 $field_name="main.".$section_name.".merge_cell_field_value";
327 if ($mergeBeanArray[$id]-> $field_array['name'] != '' and isset($field_array['options']) and isset($app_list_strings[$field_array['options']][$mergeBeanArray[$id]-> $field_array['name']])) {
328 display_field_value(str_replace("^","",$app_list_strings[$field_array['options']][$mergeBeanArray[$id]-> $field_array['name']]));
330 display_field_value(str_replace("^","",$mergeBeanArray[$id]-> $field_array['name']));
332 $field_name="main.".$section_name.".merge_cell_field_value";
337 if (empty($mergeBeanArray[$id]-> $field_array['name']) && !empty($mergeBeanArray[$id]-> $field_array['id_name'])) {
338 $related_name=get_related_name($field_array,$mergeBeanArray[$id]-> $field_array['id_name']);
339 if ($related_name !== false) {
340 $mergeBeanArray[$id]-> $field_array['name']=$related_name;
343 display_field_value($mergeBeanArray[$id]-> $field_array['name']);
344 $field_name="main.".$section_name.".merge_cell_field_value";
347 display_field_value($mergeBeanArray[$id]-> $field_array['name']);
348 $field_name="main.".$section_name.".merge_cell_field_value";
352 $json_data = array ('field_name' => $field_array['name'], 'field_type' => $field_check,);
353 //add an array of fields/values to the json array
354 //for setting all the values for merge
355 if ($field_check == 'relate' or $field_check == 'link') {
356 $temp_array = Array ();
357 $json_data['popup_fields'] = Array ($field_array['name'] => $mergeBeanArray[$id]-> $field_array['name'], $field_array['id_name'] => $mergeBeanArray[$id]-> $field_array['id_name'],);
358 } else if($field_check == 'teamset') {
359 $json_data['field_value'] = TeamSetManager::getCommaDelimitedTeams($mergeBeanArray[$id]->team_set_id, $mergeBeanArray[$id]->team_id, true);
360 $json_data['field_value2'] = TeamSetManager::getTeamsFromSet($mergeBeanArray[$id]->team_set_id);
361 $json_data['field_value3'] = $mergeBeanArray[$id]->team_set_id;
362 } else if($field_check == 'multienum') {
363 $json_data['field_value'] = unencodeMultienum($mergeBeanArray[$id]-> $field_array['name']);
365 $json_data['field_value'] = $mergeBeanArray[$id]-> $field_array['name'];
367 $encoded_json_data = $json->encode($json_data);
368 $xtpl->assign('ENCODED_JSON_DATA', $encoded_json_data);
369 $xtpl->parse($field_name);
372 $xtpl->parse("main.".$section_name);
377 $header_cols= array();
378 foreach ($merge_ids_array as $id) {
379 $td="<td width='$col_width' valign='top' class='dataLabel' align='left'><input type='button' class='button' id='$id' onclick=\"change_primary(this,'{$id}');\" value='<<'> {$mod_strings['LBL_CHANGE_PARENT']}";
380 if (count($merge_ids_array) > 1) {
381 $td.=" |<a id='remove_$id' onclick=\"remove_me(this,'{$id}');\" href='#' >{$mod_strings['LBL_REMOVE_FROM_MERGE']}</a>";
387 if ($diff_field_count>0) {
388 $xtpl->assign("DIFF_HEADER","<tr height='20'><td colspan=2><strong>{$mod_strings['LBL_DIFF_COL_VALUES']}</strong></td>".implode(' ',$header_cols)."</tr>");
389 $xtpl->assign("SIMILAR_HEADER","<tr height='20'><td colspan=20><strong>{$mod_strings['LBL_SAME_COL_VALUES']}</strong></td></tr>");
390 $xtpl->assign("GROUP_PARTITION","<tr height=3><td colspan=20' class='listViewHRS1'></td></tr>");
392 $xtpl->assign("SIMILAR_HEADER","<tr height='20'><td colspan=2><strong>{$mod_strings['LBL_SAME_COL_VALUES']}</strong></td>".implode(' ',$header_cols)."</tr>");
394 $merge_verify=$mod_strings['LBL_DELETE_MESSAGE'].'\\n';
395 foreach ($merge_records_names as $name) {
396 $merge_verify.= $name."\\n";
398 $merge_verify.='\\n'.$mod_strings['LBL_PROCEED'];
399 $xtpl->assign("MERGE_VERIFY",$merge_verify);
403 //Jenny - Bug 8386 - The object_name couldn't be found because it was searching for
404 // 'Case' instead of 'aCase'.
405 if ($focus->merge_bean->object_name == 'Case') {
406 $focus->merge_bean->object_name = 'aCase';
409 $mod=array_search($focus->merge_bean->object_name,$beanList);
410 $mod_strings = return_module_language($current_language, $mod);
412 //add javascript for required fields enforcement.
414 $javascript = new javascript();
415 $javascript->setFormName('EditView');
416 $javascript->setSugarBean($focus->merge_bean);
417 $javascript->addAllFields('');
418 if (isset($focus->merge_bean->field_defs['team_name'])) {
419 $javascript->addFieldGeneric('team_name', 'varchar', $app_strings['LBL_TEAM'] ,'true');
421 $xtpl->assign("VALIDATION_JS", $javascript->getScript());
423 $xtpl->parse("main");
427 * function truncates values to max_data_legth and adds the complete value as hover text.
429 function display_field_value($value) {
430 global $xtpl, $max_data_length, $mod_strings;
431 if (strlen($value)-$max_data_length > 3) {
432 $xtpl->assign("FIELD_VALUE", substr($value,0,$max_data_length).'...');
434 $xtpl->assign("FIELD_VALUE", $value);
436 $xtpl->assign("HOVER_TEXT", $mod_strings['LBL_MERGE_VALUE_OVER'] .': ' . $value);
439 * implements the rules that decide which fields will participate in a merge.
441 function show_field($field_def) {
442 global $filter_for_valid_editable_attributes,$invalid_attribute_by_name;
443 //field in invalid attributes list?
444 if (isset($invalid_attribute_by_name[$field_def['name']])) {
447 //field has 'duplicate_merge property set to disabled?'
448 if (isset($field_def['duplicate_merge']) ) {
449 if ($field_def['duplicate_merge']=='disabled' or $field_def['duplicate_merge']==false) {
452 if ($field_def['duplicate_merge']=='enabled' or $field_def['duplicate_merge']==true) {
457 //field has auto_increment set to true do not participate in merge.
458 //we have a unique index on that field.
459 if (isset($field_def['auto_increment']) and $field_def['auto_increment']==true) {
463 //set required attribute values in $field_def
464 if (!isset($field_def['source']) or empty($field_def['source'])) {
465 $field_def['source']='db';
468 if (!isset($field_def['dbType']) or empty($field_def['dbType']) and isset($field_def['type'])) {
469 $field_def['dbType']=$field_def['type'];
472 foreach ($filter_for_valid_editable_attributes as $attribute_set) {
474 foreach ($attribute_set as $attr=>$value) {
475 if (isset($field_def[$attr]) and $field_def[$attr]==$value) {
488 /* if the attribute of type relate and name is empty fetch using the vardef entries.
491 function get_related_name($field_def,$id_value) {
492 if (!empty($field_def['rname']) && !empty($field_def['id_name']) && !empty($field_def['table'])) {
493 if (!empty($id_value)) {
495 //default the column name to rname in vardefs
496 $col_name = $field_def['rname'];
497 //if this module is non db and has a module set, then check to see if this field should be concatenated
498 if (!empty($field_def['module']) && $field_def['source'] == 'non-db'){
499 global $beanList, $beanFiles;
500 //get the bean field defs based on the module param
501 $bean = $beanList[$field_def['module']];
502 require_once ($beanFiles[$bean]);
503 $focus = new $bean();
504 if(!empty( $focus->field_defs[$field_def['rname']])){
505 $related_def = $focus->field_defs[$field_def['rname']];
506 //if field defs has concat field array set, then concatenate values
507 if(isset($related_def['db_concat_fields']) && !empty($related_def['db_concat_fields'])){
508 $col_name = $focus->db->concat($field_def['table'], $related_def['db_concat_fields']);
513 $query = "select ".$col_name." from " .$field_def['table'] ." where id='$id_value'";
515 $result=$GLOBALS['db']->query($query);
516 $row=$GLOBALS['db']->fetchByAssoc($result);
517 if (!empty($row[$field_def['rname']])) {
518 return $row[$field_def['rname']];