]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/Import/Importer.php
Release 6.5.1
[Github/sugarcrm.git] / modules / Import / Importer.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3
4 /*********************************************************************************
5  * SugarCRM Community Edition is a customer relationship management program developed by
6  * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7  * 
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.
14  * 
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
18  * details.
19  * 
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
23  * 02110-1301 USA.
24  * 
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.
27  * 
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.
31  * 
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  ********************************************************************************/
38
39
40 require_once('modules/Import/ImportCacheFiles.php');
41 require_once('modules/Import/ImportFieldSanitize.php');
42 require_once('modules/Import/ImportDuplicateCheck.php');
43
44
45 class Importer
46 {
47     /**
48      * @var ImportFieldSanitizer
49      */
50     protected $ifs;
51
52     /**
53      * @var Currency
54      */
55     protected $defaultUserCurrency;
56
57     /**
58      * @var importColumns
59      */
60     protected $importColumns;
61
62     /**
63      * @var importSource
64      */
65     protected $importSource;
66
67     /**
68      * @var $isUpdateOnly
69      */
70     protected $isUpdateOnly;
71
72     /**
73      * @var  $bean
74      */
75     protected $bean;
76
77     /**
78      * @var sugarToExternalSourceFieldMap
79      */
80     protected $sugarToExternalSourceFieldMap = array();
81
82
83     public function __construct($importSource, $bean)
84     {
85         global $mod_strings, $sugar_config;
86
87         $this->importSource = $importSource;
88
89         //Vanilla copy of the bean object.
90         $this->bean = $bean;
91
92         // use our own error handler
93         set_error_handler(array('Importer','handleImportErrors'),E_ALL);
94
95          // Increase the max_execution_time since this step can take awhile
96         ini_set("max_execution_time", max($sugar_config['import_max_execution_time'],3600));
97
98         // stop the tracker
99         TrackerManager::getInstance()->pause();
100
101         // set the default locale settings
102         $this->ifs = $this->getFieldSanitizer();
103
104         //Get the default user currency
105         $this->defaultUserCurrency = new Currency();
106         $this->defaultUserCurrency->retrieve('-99');
107
108         //Get our import column definitions
109         $this->importColumns = $this->getImportColumns();
110         $this->isUpdateOnly = ( isset($_REQUEST['import_type']) && $_REQUEST['import_type'] == 'update' );
111     }
112
113     public function import()
114     {
115         foreach($this->importSource as $row)
116         {
117             $this->importRow($row);
118         }
119
120         // save mapping if requested
121         if ( isset($_REQUEST['save_map_as']) && $_REQUEST['save_map_as'] != '' )
122         {
123             $this->saveMappingFile();
124         }
125
126         $this->importSource->writeStatus();
127
128         //All done, remove file.
129     }
130
131
132     protected function importRow($row)
133     {
134         global $sugar_config, $mod_strings, $current_user;
135
136         $focus = clone $this->bean;
137         $focus->unPopulateDefaultValues();
138         $focus->save_from_post = false;
139         $focus->team_id = null;
140         $this->ifs->createdBeans = array();
141         $this->importSource->resetRowErrorCounter();
142         $do_save = true;
143
144         for ( $fieldNum = 0; $fieldNum < $_REQUEST['columncount']; $fieldNum++ )
145         {
146             // loop if this column isn't set
147             if ( !isset($this->importColumns[$fieldNum]) )
148                 continue;
149
150             // get this field's properties
151             $field           = $this->importColumns[$fieldNum];
152             $fieldDef        = $focus->getFieldDefinition($field);
153             $fieldTranslated = translate((isset($fieldDef['vname'])?$fieldDef['vname']:$fieldDef['name']), $focus->module_dir)." (".$fieldDef['name'].")";
154             $defaultRowValue = '';
155             // Bug 37241 - Don't re-import over a field we already set during the importing of another field
156             if ( !empty($focus->$field) )
157                 continue;
158
159             // translate strings
160             global $locale;
161             if(empty($locale))
162             {
163                 $locale = new Localization();
164             }
165             if ( isset($row[$fieldNum]) )
166             {
167                 $rowValue = $locale->translateCharset(strip_tags(trim($row[$fieldNum])),$this->importSource->importlocale_charset,$sugar_config['default_charset']);
168             }
169             else if( isset($this->sugarToExternalSourceFieldMap[$field]) && isset($row[$this->sugarToExternalSourceFieldMap[$field]]) )
170             {
171                 $rowValue = $locale->translateCharset(strip_tags(trim($row[$this->sugarToExternalSourceFieldMap[$field]])),$this->importSource->importlocale_charset,$sugar_config['default_charset']);
172             }
173             else
174             {
175                 $rowValue = '';
176             }
177
178             // If there is an default value then use it instead
179             if ( !empty($_REQUEST[$field]) )
180             {
181                 $defaultRowValue = $this->populateDefaultMapValue($field, $_REQUEST[$field], $fieldDef);
182
183
184                 if( empty($rowValue))
185                 {
186                     $rowValue = $defaultRowValue;
187                     //reset the default value to empty
188                     $defaultRowValue='';
189                 }
190             }
191
192             // Bug 22705 - Don't update the First Name or Last Name value if Full Name is set
193             if ( in_array($field, array('first_name','last_name')) && !empty($focus->full_name) )
194                 continue;
195
196             // loop if this value has not been set
197             if ( !isset($rowValue) )
198                 continue;
199
200             // If the field is required and blank then error out
201             if ( array_key_exists($field,$focus->get_import_required_fields()) && empty($rowValue) && $rowValue!='0')
202             {
203                 $this->importSource->writeError( $mod_strings['LBL_REQUIRED_VALUE'],$fieldTranslated,'NULL');
204                 $do_save = false;
205             }
206
207             // Handle the special case "Sync to Outlook"
208             if ( $focus->object_name == "Contact" && $field == 'sync_contact' )
209             {
210                 /**
211                  * Bug #41194 : if true used as value of sync_contact - add curent user to list to sync
212                  */
213                 if ( true == $rowValue || 'true' == strtolower($rowValue)) {
214                     $focus->sync_contact = $focus->id;
215                 } elseif (false == $rowValue || 'false' == strtolower($rowValue)) {
216                     $focus->sync_contact = '';
217                 } else {
218                     $bad_names = array();
219                     $returnValue = $this->ifs->synctooutlook($rowValue,$fieldDef,$bad_names);
220                     // try the default value on fail
221                     if ( !$returnValue && !empty($defaultRowValue) )
222                         $returnValue = $this->ifs->synctooutlook($defaultRowValue, $fieldDef, $bad_names);
223                     if ( !$returnValue )
224                     {
225                         $this->importSource->writeError($mod_strings['LBL_ERROR_SYNC_USERS'], $fieldTranslated, $bad_names);
226                         $do_save = 0;
227                     } else {
228                         $focus->sync_contact = $returnValue;
229                     }
230                 }
231             }
232
233             // Handle email1 and email2 fields ( these don't have the type of email )
234             if ( $field == 'email1' || $field == 'email2' )
235             {
236                 $returnValue = $this->ifs->email($rowValue, $fieldDef, $focus);
237                 // try the default value on fail
238                 if ( !$returnValue && !empty($defaultRowValue) )
239                     $returnValue = $this->ifs->email( $defaultRowValue, $fieldDef);
240                 if ( $returnValue === FALSE )
241                 {
242                     $do_save=0;
243                     $this->importSource->writeError( $mod_strings['LBL_ERROR_INVALID_EMAIL'], $fieldTranslated, $rowValue);
244                 }
245                 else
246                 {
247                     $rowValue = $returnValue;
248                     // check for current opt_out and invalid email settings for this email address
249                     // if we find any, set them now
250                     $emailres = $focus->db->query( "SELECT opt_out, invalid_email FROM email_addresses WHERE email_address = '".$focus->db->quote($rowValue)."'");
251                     if ( $emailrow = $focus->db->fetchByAssoc($emailres) )
252                     {
253                         $focus->email_opt_out = $emailrow['opt_out'];
254                         $focus->invalid_email = $emailrow['invalid_email'];
255                     }
256                 }
257             }
258
259             // Handle splitting Full Name into First and Last Name parts
260             if ( $field == 'full_name' && !empty($rowValue) )
261             {
262                 $this->ifs->fullname($rowValue,$fieldDef,$focus);
263             }
264
265             // to maintain 451 compatiblity
266             if(!isset($fieldDef['module']) && $fieldDef['type']=='relate')
267                 $fieldDef['module'] = ucfirst($fieldDef['table']);
268
269             if(isset($fieldDef['custom_type']) && !empty($fieldDef['custom_type']))
270                 $fieldDef['type'] = $fieldDef['custom_type'];
271
272             // If the field is empty then there is no need to check the data
273             if( !empty($rowValue) )
274             {
275                 //Start
276                 $rowValue = $this->sanitizeFieldValueByType($rowValue, $fieldDef, $defaultRowValue, $focus, $fieldTranslated);
277                 if ($rowValue === FALSE) {
278                                         /* BUG 51213 - jeff @ neposystems.com */
279                     $do_save = false;
280                     continue;
281                                 }
282             }
283
284             // if the parent type is in singular form, get the real module name for parent_type
285             if (isset($fieldDef['type']) && $fieldDef['type']=='parent_type') {
286                 $rowValue = get_module_from_singular($rowValue);
287             }
288
289             $focus->$field = $rowValue;
290             unset($defaultRowValue);
291         }
292
293         // Now try to validate flex relate fields
294         if ( isset($focus->field_defs['parent_name']) && isset($focus->parent_name) && ($focus->field_defs['parent_name']['type'] == 'parent') )
295         {
296             // populate values from the picker widget if the import file doesn't have them
297             $parent_idField = $focus->field_defs['parent_name']['id_name'];
298             if ( empty($focus->$parent_idField) && !empty($_REQUEST[$parent_idField]) )
299                 $focus->$parent_idField = $_REQUEST[$parent_idField];
300
301             $parent_typeField = $focus->field_defs['parent_name']['type_name'];
302
303             if ( empty($focus->$parent_typeField) && !empty($_REQUEST[$parent_typeField]) )
304                 $focus->$parent_typeField = $_REQUEST[$parent_typeField];
305             // now validate it
306             $returnValue = $this->ifs->parent($focus->parent_name,$focus->field_defs['parent_name'],$focus, empty($_REQUEST['parent_name']));
307             if ( !$returnValue && !empty($_REQUEST['parent_name']) )
308                 $returnValue = $this->ifs->parent( $_REQUEST['parent_name'],$focus->field_defs['parent_name'], $focus);
309         }
310
311         // check to see that the indexes being entered are unique.
312         if (isset($_REQUEST['enabled_dupes']) && $_REQUEST['enabled_dupes'] != "")
313         {
314             $toDecode = html_entity_decode  ($_REQUEST['enabled_dupes'], ENT_QUOTES);
315             $enabled_dupes = json_decode($toDecode);
316             $idc = new ImportDuplicateCheck($focus);
317
318             if ( $idc->isADuplicateRecord($enabled_dupes) )
319             {
320                 $this->importSource->markRowAsDuplicate($idc->_dupedFields);
321                 $this->_undoCreatedBeans($this->ifs->createdBeans);
322                 return;
323             }
324         }
325         //Allow fields to be passed in for dup check as well (used by external adapters)
326         else if( !empty($_REQUEST['enabled_dup_fields']) )
327         {
328             $toDecode = html_entity_decode  ($_REQUEST['enabled_dup_fields'], ENT_QUOTES);
329             $enabled_dup_fields = json_decode($toDecode);
330             $idc = new ImportDuplicateCheck($focus);
331             if ( $idc->isADuplicateRecordByFields($enabled_dup_fields) )
332             {
333                 $this->importSource->markRowAsDuplicate($idc->_dupedFields);
334                 $this->_undoCreatedBeans($this->ifs->createdBeans);
335                 return;
336             }
337         }
338
339         // if the id was specified
340         $newRecord = true;
341         if ( !empty($focus->id) )
342         {
343             $focus->id = $this->_convertId($focus->id);
344
345             // check if it already exists
346             $query = "SELECT * FROM {$focus->table_name} WHERE id='".$focus->db->quote($focus->id)."'";
347             $result = $focus->db->query($query)
348             or sugar_die("Error selecting sugarbean: ");
349
350             $dbrow = $focus->db->fetchByAssoc($result);
351
352             if (isset ($dbrow['id']) && $dbrow['id'] != -1)
353             {
354                 // if it exists but was deleted, just remove it
355                 if (isset ($dbrow['deleted']) && $dbrow['deleted'] == 1 && $this->isUpdateOnly ==false)
356                 {
357                     $this->removeDeletedBean($focus);
358                     $focus->new_with_id = true;
359                 }
360                 else
361                 {
362                     if( ! $this->isUpdateOnly )
363                     {
364                         $this->importSource->writeError($mod_strings['LBL_ID_EXISTS_ALREADY'],'ID',$focus->id);
365                         $this->_undoCreatedBeans($this->ifs->createdBeans);
366                         return;
367                     }
368
369                     $clonedBean = $this->cloneExistingBean($focus);
370                     if($clonedBean === FALSE)
371                     {
372                         $this->importSource->writeError($mod_strings['LBL_RECORD_CANNOT_BE_UPDATED'],'ID',$focus->id);
373                         $this->_undoCreatedBeans($this->ifs->createdBeans);
374                         return;
375                     }
376                     else
377                     {
378                         $focus = $clonedBean;
379                         $newRecord = FALSE;
380                     }
381                 }
382             }
383             else
384             {
385                 $focus->new_with_id = true;
386             }
387         }
388
389         if ($do_save)
390         {
391             $this->saveImportBean($focus, $newRecord);
392             // Update the created/updated counter
393             $this->importSource->markRowAsImported($newRecord);
394         }
395         else
396             $this->_undoCreatedBeans($this->ifs->createdBeans);
397
398         unset($defaultRowValue);
399
400     }
401
402
403     protected function sanitizeFieldValueByType($rowValue, $fieldDef, $defaultRowValue, $focus, $fieldTranslated)
404     {
405         global $mod_strings, $app_list_strings;
406         switch ($fieldDef['type'])
407         {
408             case 'enum':
409             case 'multienum':
410                 if ( isset($fieldDef['type']) && $fieldDef['type'] == "multienum" )
411                     $returnValue = $this->ifs->multienum($rowValue,$fieldDef);
412                 else
413                     $returnValue = $this->ifs->enum($rowValue,$fieldDef);
414                 // try the default value on fail
415                 if ( !$returnValue && !empty($defaultRowValue) )
416                 {
417                     if ( isset($fieldDef['type']) && $fieldDef['type'] == "multienum" )
418                         $returnValue = $this->ifs->multienum($defaultRowValue,$fieldDef);
419                     else
420                         $returnValue = $this->ifs->enum($defaultRowValue,$fieldDef);
421                 }
422                 if ( $returnValue === FALSE )
423                 {
424                     $this->importSource->writeError($mod_strings['LBL_ERROR_NOT_IN_ENUM'] . implode(",",$app_list_strings[$fieldDef['options']]), $fieldTranslated,$rowValue);
425                     return FALSE;
426                 }
427                 else
428                     return $returnValue;
429
430                 break;
431             case 'relate':
432             case 'parent':
433                 $returnValue = $this->ifs->relate($rowValue, $fieldDef, $focus, empty($defaultRowValue));
434                 if (!$returnValue && !empty($defaultRowValue))
435                     $returnValue = $this->ifs->relate($defaultRowValue,$fieldDef, $focus);
436                 // Bug 33623 - Set the id value found from the above method call as an importColumn
437                 if ($returnValue !== false)
438                     $this->importColumns[] = $fieldDef['id_name'];
439                 return $rowValue;
440                 break;
441             case 'teamset':
442                 $this->ifs->teamset($rowValue,$fieldDef,$focus);
443                 $this->importColumns[] = 'team_set_id';
444                 $this->importColumns[] = 'team_id';
445                 return $rowValue;
446                 break;
447             case 'fullname':
448                 return $rowValue;
449                 break;
450             default:
451                 $fieldtype = $fieldDef['type'];
452                 $returnValue = $this->ifs->$fieldtype($rowValue, $fieldDef, $focus);
453                 // try the default value on fail
454                 if ( !$returnValue && !empty($defaultRowValue) )
455                     $returnValue = $this->ifs->$fieldtype($defaultRowValue,$fieldDef, $focus);
456                 if ( !$returnValue )
457                 {
458                     $this->importSource->writeError($mod_strings['LBL_ERROR_INVALID_'.strtoupper($fieldDef['type'])],$fieldTranslated,$rowValue,$focus);
459                     return FALSE;
460                 }
461                 return $returnValue;
462         }
463     }
464
465     protected function cloneExistingBean($focus)
466     {
467         $existing_focus = clone $this->bean;
468         if ( !( $existing_focus->retrieve($focus->id) instanceOf SugarBean ) )
469         {
470             return FALSE;
471         }
472         else
473         {
474             $newData = $focus->toArray();
475             foreach ( $newData as $focus_key => $focus_value )
476                 if ( in_array($focus_key,$this->importColumns) )
477                     $existing_focus->$focus_key = $focus_value;
478
479             return $existing_focus;
480         }
481     }
482
483     protected function removeDeletedBean($focus)
484     {
485         global $mod_strings;
486
487         $query2 = "DELETE FROM {$focus->table_name} WHERE id='".$focus->db->quote($focus->id)."'";
488         $result2 = $focus->db->query($query2) or sugar_die($mod_strings['LBL_ERROR_DELETING_RECORD']." ".$focus->id);
489         if ($focus->hasCustomFields())
490         {
491             $query3 = "DELETE FROM {$focus->table_name}_cstm WHERE id_c='".$focus->db->quote($focus->id)."'";
492             $result2 = $focus->db->query($query3);
493         }
494     }
495
496     protected function saveImportBean($focus, $newRecord)
497     {
498         global $timedate, $current_user;
499
500         // Populate in any default values to the bean
501         $focus->populateDefaultValues();
502
503         if ( !isset($focus->assigned_user_id) || $focus->assigned_user_id == '' && $newRecord )
504         {
505             $focus->assigned_user_id = $current_user->id;
506         }
507         /*
508         * Bug 34854: Added all conditions besides the empty check on date modified.
509         */
510         if ( ( !empty($focus->new_with_id) && !empty($focus->date_modified) ) ||
511              ( empty($focus->new_with_id) && $timedate->to_db($focus->date_modified) != $timedate->to_db($timedate->to_display_date_time($focus->fetched_row['date_modified'])) )
512         ) 
513             $focus->update_date_modified = false;
514
515         // Bug 53636 - Allow update of "Date Created"
516         if (!empty($focus->date_entered)) {
517                 $focus->update_date_entered = true;
518         }
519             
520         $focus->optimistic_lock = false;
521         if ( $focus->object_name == "Contact" && isset($focus->sync_contact) )
522         {
523             //copy the potential sync list to another varible
524             $list_of_users=$focus->sync_contact;
525             //and set it to false for the save
526             $focus->sync_contact=false;
527         }
528         else if($focus->object_name == "User" && !empty($current_user) && $focus->is_admin && !is_admin($current_user) && is_admin_for_module($current_user, 'Users')) {
529             sugar_die($GLOBALS['mod_strings']['ERR_IMPORT_SYSTEM_ADMININSTRATOR']);
530         }
531         //bug# 46411 importing Calls will not populate Leads or Contacts Subpanel
532         if (!empty($focus->parent_type) && !empty($focus->parent_id))
533         {
534             foreach ($focus->relationship_fields as $key => $val)
535             {
536                 if ($val == strtolower($focus->parent_type))
537                 {
538                     $focus->$key = $focus->parent_id;
539                 }
540             }
541         }                                       
542         //bug# 40260 setting it true as the module in focus is involved in an import
543         $focus->in_import=true;
544         // call any logic needed for the module preSave
545         $focus->beforeImportSave();
546
547         // Bug51192: check if there are any changes in the imported data
548         $hasDataChanges = false;
549         $dataChanges=$focus->db->getDataChanges($focus);
550         
551         if(!empty($dataChanges)) {
552             foreach($dataChanges as $field=>$fieldData) {
553                 if($fieldData['data_type'] != 'date' || strtotime($fieldData['before']) != strtotime($fieldData['after'])) {
554                     $hasDataChanges = true;
555                     break;
556                 }
557             }
558         }
559         
560         // if modified_user_id is set, set the flag to false so SugarBEan will not reset it
561         if (isset($focus->modified_user_id) && $focus->modified_user_id && !$hasDataChanges) {
562             $focus->update_modified_by = false;
563         }
564         // if created_by is set, set the flag to false so SugarBEan will not reset it
565         if (isset($focus->created_by) && $focus->created_by) {
566             $focus->set_created_by = false;
567         }
568
569         if ( $focus->object_name == "Contact" && isset($list_of_users) )
570             $focus->process_sync_to_outlook($list_of_users);
571
572         $focus->save(false);
573
574         //now that save is done, let's make sure that parent and related id's were saved as relationships
575         //this takes place before the afterImportSave()
576         $this->checkRelatedIDsAfterSave($focus);
577
578         // call any logic needed for the module postSave
579         $focus->afterImportSave();
580
581         // Add ID to User's Last Import records
582         if ( $newRecord )
583             $this->importSource->writeRowToLastImport( $_REQUEST['import_module'],($focus->object_name == 'Case' ? 'aCase' : $focus->object_name),$focus->id);
584
585     }
586
587     protected function saveMappingFile()
588     {
589         global $current_user;
590
591         $firstrow    = unserialize(base64_decode($_REQUEST['firstrow']));
592         $mappingValsArr = $this->importColumns;
593         $mapping_file = new ImportMap();
594         if ( isset($_REQUEST['has_header']) && $_REQUEST['has_header'] == 'on')
595         {
596             $header_to_field = array ();
597             foreach ($this->importColumns as $pos => $field_name)
598             {
599                 if (isset($firstrow[$pos]) && isset($field_name))
600                 {
601                     $header_to_field[$firstrow[$pos]] = $field_name;
602                 }
603             }
604
605             $mappingValsArr = $header_to_field;
606         }
607         //get array of values to save for duplicate and locale settings
608         $advMapping = $this->retrieveAdvancedMapping();
609
610         //merge with mappingVals array
611         if(!empty($advMapping) && is_array($advMapping))
612         {
613             $mappingValsArr = array_merge($mappingValsArr,$advMapping);
614         }
615
616         //set mapping
617         $mapping_file->setMapping($mappingValsArr);
618
619         // save default fields
620         $defaultValues = array();
621         for ( $i = 0; $i < $_REQUEST['columncount']; $i++ )
622         {
623             if (isset($this->importColumns[$i]) && !empty($_REQUEST[$this->importColumns[$i]]))
624             {
625                 $field = $this->importColumns[$i];
626                 $fieldDef = $this->bean->getFieldDefinition($field);
627                 if(!empty($fieldDef['custom_type']) && $fieldDef['custom_type'] == 'teamset')
628                 {
629                     require_once('include/SugarFields/Fields/Teamset/SugarFieldTeamset.php');
630                     $sugar_field = new SugarFieldTeamset('Teamset');
631                     $teams = $sugar_field->getTeamsFromRequest($field);
632                     if(isset($_REQUEST['primary_team_name_collection']))
633                     {
634                         $primary_index = $_REQUEST['primary_team_name_collection'];
635                     }
636
637                     //If primary_index was selected, ensure that the first Array entry is the primary team
638                     if(isset($primary_index))
639                     {
640                         $count = 0;
641                         $new_teams = array();
642                         foreach($teams as $id=>$name)
643                         {
644                             if($primary_index == $count++)
645                             {
646                                 $new_teams[$id] = $name;
647                                 unset($teams[$id]);
648                                 break;
649                             }
650                         }
651
652                         foreach($teams as $id=>$name)
653                         {
654                             $new_teams[$id] = $name;
655                         }
656                         $teams = $new_teams;
657                     } //if
658
659                     $json = getJSONobj();
660                     $defaultValues[$field] = $json->encode($teams);
661                 }
662                 else
663                 {
664                     $defaultValues[$field] = $_REQUEST[$this->importColumns[$i]];
665                 }
666             }
667         }
668         $mapping_file->setDefaultValues($defaultValues);
669         $result = $mapping_file->save( $current_user->id,  $_REQUEST['save_map_as'], $_REQUEST['import_module'], $_REQUEST['source'],
670             ( isset($_REQUEST['has_header']) && $_REQUEST['has_header'] == 'on'), $_REQUEST['custom_delimiter'], html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES)
671         );
672     }
673
674
675     protected function populateDefaultMapValue($field, $fieldValue, $fieldDef)
676     {
677         global $timedate, $current_user;
678
679         if ( is_array($fieldValue) )
680             $defaultRowValue = encodeMultienumValue($fieldValue);
681         else
682             $defaultRowValue = $_REQUEST[$field];
683         // translate default values to the date/time format for the import file
684         if( $fieldDef['type'] == 'date' && $this->ifs->dateformat != $timedate->get_date_format() )
685             $defaultRowValue = $timedate->swap_formats($defaultRowValue, $this->ifs->dateformat, $timedate->get_date_format());
686
687         if( $fieldDef['type'] == 'time' && $this->ifs->timeformat != $timedate->get_time_format() )
688             $defaultRowValue = $timedate->swap_formats($defaultRowValue, $this->ifs->timeformat, $timedate->get_time_format());
689
690         if( ($fieldDef['type'] == 'datetime' || $fieldDef['type'] == 'datetimecombo') && $this->ifs->dateformat.' '.$this->ifs->timeformat != $timedate->get_date_time_format() )
691             $defaultRowValue = $timedate->swap_formats($defaultRowValue, $this->ifs->dateformat.' '.$this->ifs->timeformat,$timedate->get_date_time_format());
692
693         if ( in_array($fieldDef['type'],array('currency','float','int','num')) && $this->ifs->num_grp_sep != $current_user->getPreference('num_grp_sep') )
694             $defaultRowValue = str_replace($current_user->getPreference('num_grp_sep'), $this->ifs->num_grp_sep,$defaultRowValue);
695
696         if ( in_array($fieldDef['type'],array('currency','float')) && $this->ifs->dec_sep != $current_user->getPreference('dec_sep') )
697             $defaultRowValue = str_replace($current_user->getPreference('dec_sep'), $this->ifs->dec_sep,$defaultRowValue);
698
699         $user_currency_symbol = $this->defaultUserCurrency->symbol;
700         if ( $fieldDef['type'] == 'currency' && $this->ifs->currency_symbol != $user_currency_symbol )
701             $defaultRowValue = str_replace($user_currency_symbol, $this->ifs->currency_symbol,$defaultRowValue);
702
703         return $defaultRowValue;
704     }
705
706     protected function getImportColumns()
707     {
708         $importable_fields = $this->bean->get_importable_fields();
709         $importColumns = array();
710         foreach ($_REQUEST as $name => $value)
711         {
712             // only look for var names that start with "fieldNum"
713             if (strncasecmp($name, "colnum_", 7) != 0)
714                 continue;
715
716             // pull out the column position for this field name
717             $pos = substr($name, 7);
718
719             if ( isset($importable_fields[$value]) )
720             {
721                 // now mark that we've seen this field
722                 $importColumns[$pos] = $value;
723             }
724         }
725
726         return $importColumns;
727     }
728
729     protected function getFieldSanitizer()
730     {
731         $ifs = new ImportFieldSanitize();
732         $copyFields = array('dateformat','timeformat','timezone','default_currency_significant_digits','num_grp_sep','dec_sep','default_locale_name_format');
733         foreach($copyFields as $field)
734         {
735             $fieldKey = "importlocale_$field";
736             $ifs->$field = $this->importSource->$fieldKey;
737         }
738
739         $currency = new Currency();
740         $currency->retrieve($this->importSource->importlocale_currency);
741         $ifs->currency_symbol = $currency->symbol;
742
743         return $ifs;
744     }
745
746     /**
747      * Sets a translation map from sugar field key to external source key used while importing a row.  This allows external sources
748      * to return a data set that is an associative array rather than numerically indexed.
749      *
750      * @param  $translator
751      * @return void
752      */
753     public function setFieldKeyTranslator($translator)
754     {
755         $this->sugarToExternalSourceFieldMap = $translator;
756     }
757
758     /**
759      * If a bean save is not done for some reason, this method will undo any of the beans that were created
760      *
761      * @param array $ids ids of user_last_import records created
762      */
763     protected function _undoCreatedBeans( array $ids )
764     {
765         $focus = new UsersLastImport();
766         foreach ($ids as $id)
767             $focus->undoById($id);
768     }
769
770     /**
771      * clean id's when being imported
772      *
773      * @param  string $string
774      * @return string
775      */
776     protected function _convertId($string)
777     {
778         return preg_replace_callback(
779             '|[^A-Za-z0-9\-\_]|',
780             create_function(
781             // single quotes are essential here,
782             // or alternative escape all $ as \$
783             '$matches',
784             'return ord($matches[0]);'
785                  ) ,
786             $string);
787     }
788
789     public function retrieveAdvancedMapping()
790     {
791         $advancedMappingSettings = array();
792
793         //harvest the dupe index settings
794         if( isset($_REQUEST['enabled_dupes']) )
795         {
796             $toDecode = html_entity_decode  ($_REQUEST['enabled_dupes'], ENT_QUOTES);
797             $dupe_ind = json_decode($toDecode);
798
799             foreach($dupe_ind as $dupe)
800             {
801                 $advancedMappingSettings['dupe_'.$dupe] = $dupe;
802             }
803         }
804
805         foreach($_REQUEST as $rk=>$rv)
806         {
807             //harvest the import locale settings
808             if(strpos($rk,'portlocale_')>0)
809             {
810                 $advancedMappingSettings[$rk] = $rv;
811             }
812
813         }
814         return $advancedMappingSettings;
815     }
816
817     public static function getImportableModules()
818     {
819         global $beanList;
820         $importableModules = array();
821         foreach ($beanList as $moduleName => $beanName)
822         {
823             if( class_exists($beanName) )
824             {
825                 $tmp = new $beanName();
826                 if( isset($tmp->importable) && $tmp->importable )
827                 {
828                     $label = isset($GLOBALS['app_list_strings']['moduleList'][$moduleName]) ? $GLOBALS['app_list_strings']['moduleList'][$moduleName] : $moduleName;
829                     $importableModules[$moduleName] = $label;
830                 }
831             }
832         }
833
834         asort($importableModules);
835         return $importableModules;
836     }
837
838
839     /**
840      * Replaces PHP error handler in Step4
841      *
842      * @param int    $errno
843      * @param string $errstr
844      * @param string $errfile
845      * @param string $errline
846      */
847     public static function handleImportErrors($errno, $errstr, $errfile, $errline)
848     {
849         $GLOBALS['log']->fatal("Caught error: $errstr");
850
851         if ( !defined('E_DEPRECATED') )
852             define('E_DEPRECATED','8192');
853         if ( !defined('E_USER_DEPRECATED') )
854             define('E_USER_DEPRECATED','16384');
855
856         $isFatal = false;
857         switch ($errno)
858         {
859             case E_USER_ERROR:
860                 $message = "ERROR: [$errno] $errstr on line $errline in file $errfile<br />\n";
861                 $isFatal = true;
862                 break;
863             case E_USER_WARNING:
864             case E_WARNING:
865                 $message = "WARNING: [$errno] $errstr on line $errline in file $errfile<br />\n";
866                 break;
867             case E_USER_NOTICE:
868             case E_NOTICE:
869                 $message = "NOTICE: [$errno] $errstr on line $errline in file $errfile<br />\n";
870                 break;
871             case E_STRICT:
872             case E_DEPRECATED:
873             case E_USER_DEPRECATED:
874                 // don't worry about these
875                 // $message = "STRICT ERROR: [$errno] $errstr on line $errline in file $errfile<br />\n";
876                 $message = "";
877                 break;
878             default:
879                 $message = "Unknown error type: [$errno] $errstr on line $errline in file $errfile<br />\n";
880                 break;
881         }
882
883         // check to see if current reporting level should be included based upon error_reporting() setting, if not
884         // then just return
885         if (error_reporting() & $errno)
886         {
887             echo $message;
888         }
889
890         if ($isFatal)
891         {
892             exit(1);
893         }
894     }
895
896
897     /**
898          * upon bean save, the relationships are saved by SugarBean->save_relationship_changes() method, but those values depend on
899      * the request object and is not reliable during import.  This function makes sure any defined related or parent id's are processed
900          * and their relationship saved.
901          */
902     public function checkRelatedIDsAfterSave($focus)
903     {
904         if(empty($focus)){
905             return false;
906         }
907
908         //check relationship fields first
909         if(!empty($focus->parent_id) && !empty($focus->parent_type)){
910             $relParentName = strtolower($focus->parent_type);
911             $relParentID = strtolower($focus->parent_id);
912         }
913         if(!empty($focus->related_id) && !empty($focus->related_type)){
914             $relName = strtolower($focus->related_type);
915             $relID = strtolower($focus->related_id);
916         }
917
918         //now refresh the bean and process for parent relationship
919         $focus->retrieve($focus->id);
920         if(!empty($relParentName) && !empty($relParentID)){
921
922             //grab the relationship and any available ids
923             if(!empty($focus->$relParentName)){
924                 $rel_ids=array();
925                 $focus->load_relationship($relParentName);
926                 $rel_ids = $focus->$relParentName->get();
927
928                 //if the current parent_id is not part of the stored rels, then add it
929                 if(!in_array($relParentID, $rel_ids)){
930                     $focus->$relParentName->add($relParentID);
931                 }
932             }
933         }
934
935         //now lets process any related fields
936         if(!empty($relName) && !empty($relID)){
937             if(!empty($focus->$relName)){
938                 $rel_ids=array();
939                 $focus->load_relationship($relName);
940                 $rel_ids = $focus->$relName->get();
941
942                 //if the related_id is not part of the stored rels, then add it
943                 if(!in_array($relID, $rel_ids)){
944                     $focus->$relName->add($relID);
945                 }
946             }
947         }
948     }
949
950
951 }