dolibarr  13.0.2
import_csv.modules.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2006-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2009-2012 Regis Houssin <regis.houssin@inodbox.com>
4  * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
5  * Copyright (C) 2012-2016 Juanjo Menent <jmenent@2byte.es>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  * or see https://www.gnu.org/
20  */
21 
28 require_once DOL_DOCUMENT_ROOT.'/core/modules/import/modules_import.php';
29 
30 
34 class ImportCsv extends ModeleImports
35 {
39  public $db;
40 
41  public $datatoimport;
42 
46  public $error = '';
47 
51  public $errors = array();
52 
56  public $id;
57 
61  public $label;
62 
63  public $extension; // Extension of files imported by driver
64 
69  public $version = 'dolibarr';
70 
71  public $label_lib; // Label of external lib used by driver
72 
73  public $version_lib; // Version of external lib used by driver
74 
75  public $separator;
76 
77  public $file; // Path of file
78 
79  public $handle; // Handle fichier
80 
81  public $cacheconvert = array(); // Array to cache list of value found after a convertion
82 
83  public $cachefieldtable = array(); // Array to cache list of value found into fields@tables
84 
85  public $nbinsert = 0; // # of insert done during the import
86 
87  public $nbupdate = 0; // # of update done during the import
88 
89 
96  public function __construct($db, $datatoimport)
97  {
98  global $conf, $langs;
99  $this->db = $db;
100 
101  $this->separator = (GETPOST('separator') ?GETPOST('separator') : (empty($conf->global->IMPORT_CSV_SEPARATOR_TO_USE) ? ',' : $conf->global->IMPORT_CSV_SEPARATOR_TO_USE));
102  $this->enclosure = '"';
103  $this->escape = '"';
104 
105  $this->id = 'csv'; // Same value then xxx in file name export_xxx.modules.php
106  $this->label = 'Csv'; // Label of driver
107  $this->desc = $langs->trans("CSVFormatDesc", $this->separator, $this->enclosure, $this->escape);
108  $this->extension = 'csv'; // Extension for generated file by this driver
109  $this->picto = 'mime/other'; // Picto
110  $this->version = '1.34'; // Driver version
111 
112  // If driver use an external library, put its name here
113  $this->label_lib = 'Dolibarr';
114  $this->version_lib = DOL_VERSION;
115 
116  $this->datatoimport = $datatoimport;
117  if (preg_match('/^societe_/', $datatoimport)) $this->thirpartyobject = new Societe($this->db);
118  }
119 
120 
121  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
128  public function write_header_example($outputlangs)
129  {
130  // phpcs:enable
131  return '';
132  }
133 
134  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
142  public function write_title_example($outputlangs, $headerlinefields)
143  {
144  // phpcs:enable
145  $s = join($this->separator, array_map('cleansep', $headerlinefields));
146  return $s."\n";
147  }
148 
149  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
157  public function write_record_example($outputlangs, $contentlinevalues)
158  {
159  // phpcs:enable
160  $s = join($this->separator, array_map('cleansep', $contentlinevalues));
161  return $s."\n";
162  }
163 
164  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
171  public function write_footer_example($outputlangs)
172  {
173  // phpcs:enable
174  return '';
175  }
176 
177 
178  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
185  public function import_open_file($file)
186  {
187  // phpcs:enable
188  global $langs;
189  $ret = 1;
190 
191  dol_syslog(get_class($this)."::open_file file=".$file);
192 
193  ini_set('auto_detect_line_endings', 1); // For MAC compatibility
194 
195  $this->handle = fopen(dol_osencode($file), "r");
196  if (!$this->handle)
197  {
198  $langs->load("errors");
199  $this->error = $langs->trans("ErrorFailToOpenFile", $file);
200  $ret = -1;
201  } else {
202  $this->file = $file;
203  }
204 
205  return $ret;
206  }
207 
208 
209  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
216  public function import_get_nb_of_lines($file)
217  {
218  // phpcs:enable
219  return dol_count_nb_of_line($file);
220  }
221 
222 
223  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
229  public function import_read_header()
230  {
231  // phpcs:enable
232  return 0;
233  }
234 
235 
236  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
242  public function import_read_record()
243  {
244  // phpcs:enable
245  global $conf;
246 
247  $arrayres = fgetcsv($this->handle, 100000, $this->separator, $this->enclosure, $this->escape);
248 
249  // End of file
250  if ($arrayres === false) return false;
251 
252  //var_dump($this->handle);
253  //var_dump($arrayres);exit;
254  $newarrayres = array();
255  if ($arrayres && is_array($arrayres))
256  {
257  foreach ($arrayres as $key => $val)
258  {
259  if (!empty($conf->global->IMPORT_CSV_FORCE_CHARSET)) // Forced charset
260  {
261  if (strtolower($conf->global->IMPORT_CSV_FORCE_CHARSET) == 'utf8')
262  {
263  $newarrayres[$key]['val'] = $val;
264  $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
265  } else {
266  $newarrayres[$key]['val'] = utf8_encode($val);
267  $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
268  }
269  } else // Autodetect format (UTF8 or ISO)
270  {
271  if (utf8_check($val))
272  {
273  $newarrayres[$key]['val'] = $val;
274  $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
275  } else {
276  $newarrayres[$key]['val'] = utf8_encode($val);
277  $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
278  }
279  }
280  }
281 
282  $this->col = count($newarrayres);
283  }
284 
285  return $newarrayres;
286  }
287 
288  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
294  public function import_close_file()
295  {
296  // phpcs:enable
297  fclose($this->handle);
298  return 0;
299  }
300 
301 
302  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
314  public function import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
315  {
316  // phpcs:enable
317  global $langs, $conf, $user;
318  global $thirdparty_static; // Specific to thirdparty import
319  global $tablewithentity_cache; // Cache to avoid to call desc at each rows on tables
320 
321  $error = 0;
322  $warning = 0;
323  $this->errors = array();
324  $this->warnings = array();
325 
326  //dol_syslog("import_csv.modules maxfields=".$maxfields." importid=".$importid);
327 
328  //var_dump($array_match_file_to_database);
329  //var_dump($arrayrecord);
330  $array_match_database_to_file = array_flip($array_match_file_to_database);
331  $sort_array_match_file_to_database = $array_match_file_to_database;
332  ksort($sort_array_match_file_to_database);
333 
334  //var_dump($sort_array_match_file_to_database);
335 
336  if (count($arrayrecord) == 0 || (count($arrayrecord) == 1 && empty($arrayrecord[0]['val'])))
337  {
338  //print 'W';
339  $this->warnings[$warning]['lib'] = $langs->trans('EmptyLine');
340  $this->warnings[$warning]['type'] = 'EMPTY';
341  $warning++;
342  } else {
343  $last_insert_id_array = array(); // store the last inserted auto_increment id for each table, so that dependent tables can be inserted with the appropriate id (eg: extrafields fk_object will be set with the last inserted object's id)
344  $updatedone = false;
345  $insertdone = false;
346  // For each table to insert, me make a separate insert
347  foreach ($objimport->array_import_tables[0] as $alias => $tablename)
348  {
349  // Build sql request
350  $sql = '';
351  $listfields = array();
352  $listvalues = array();
353  $i = 0;
354  $errorforthistable = 0;
355 
356  // Define $tablewithentity_cache[$tablename] if not already defined
357  if (!isset($tablewithentity_cache[$tablename])) // keep this test with "isset"
358  {
359  dol_syslog("Check if table ".$tablename." has an entity field");
360  $resql = $this->db->DDLDescTable($tablename, 'entity');
361  if ($resql)
362  {
363  $obj = $this->db->fetch_object($resql);
364  if ($obj) $tablewithentity_cache[$tablename] = 1; // table contains entity field
365  else $tablewithentity_cache[$tablename] = 0; // table does not contains entity field
366  } else dol_print_error($this->db);
367  } else {
368  //dol_syslog("Table ".$tablename." check for entity into cache is ".$tablewithentity_cache[$tablename]);
369  }
370 
371  // array of fields to column index
372  $arrayfield = array();
373  foreach ($sort_array_match_file_to_database as $key => $val) {
374  $arrayfield[$val] = ($key - 1);
375  }
376 
377  // Loop on each fields in the match array: $key = 1..n, $val=alias of field (s.nom)
378  foreach ($sort_array_match_file_to_database as $key => $val)
379  {
380  $fieldalias = preg_replace('/\..*$/i', '', $val);
381  $fieldname = preg_replace('/^.*\./i', '', $val);
382 
383  if ($alias != $fieldalias) continue; // Not a field of current table
384 
385  if ($key <= $maxfields)
386  {
387  // Set $newval with value to insert and set $listvalues with sql request part for insert
388  $newval = '';
389  if ($arrayrecord[($key - 1)]['type'] > 0) $newval = $arrayrecord[($key - 1)]['val']; // If type of field into input file is not empty string (so defined into input file), we get value
390 
391  // Make some tests on $newval
392 
393  // Is it a required field ?
394  if (preg_match('/\*/', $objimport->array_import_fields[0][$val]) && ((string) $newval == ''))
395  {
396  $this->errors[$error]['lib'] = $langs->trans('ErrorMissingMandatoryValue', $key);
397  $this->errors[$error]['type'] = 'NOTNULL';
398  $errorforthistable++;
399  $error++;
400  }
401  // Test format only if field is not a missing mandatory field (field may be a value or empty but not mandatory)
402  else {
403  // We convert field if required
404  if (!empty($objimport->array_import_convertvalue[0][$val]))
405  {
406  //print 'Must convert '.$newval.' with rule '.join(',',$objimport->array_import_convertvalue[0][$val]).'. ';
407  if ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeid'
408  || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromref'
409  || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel'
410  )
411  {
412  // New val can be an id or ref. If it start with id: it is forced to id, if it start with ref: it is forced to ref. It not, we try to guess.
413  $isidorref = 'id';
414  if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) $isidorref = 'ref';
415 
416  $newval = preg_replace('/^(id|ref):/i', '', $newval); // Remove id: or ref: that was used to force if field is id or ref
417  //print 'Val is now '.$newval.' and is type '.$isidorref."<br>\n";
418 
419  if ($isidorref == 'ref') { // If value into input import file is a ref, we apply the function defined into descriptor
420  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
421  $class = $objimport->array_import_convertvalue[0][$val]['class'];
422  $method = $objimport->array_import_convertvalue[0][$val]['method'];
423  if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval] != '')
424  {
425  $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval];
426  } else {
427  $resultload = dol_include_once($file);
428  if (empty($resultload))
429  {
430  dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method);
431  break;
432  }
433  $classinstance = new $class($this->db);
434  // Try the fetch from code or ref
435  $param_array = array('', $newval);
436  if ($class == 'AccountingAccount') {
437  //var_dump($arrayrecord[0]['val']);
438  /*include_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancysystem.class.php';
439  $tmpchartofaccount = new AccountancySystem($this->db);
440  $tmpchartofaccount->fetch($conf->global->CHARTOFACCOUNTS);
441  var_dump($tmpchartofaccount->ref.' - '.$arrayrecord[0]['val']);
442  if ((! ($conf->global->CHARTOFACCOUNTS > 0)) || $tmpchartofaccount->ref != $arrayrecord[0]['val'])
443  {
444  $this->errors[$error]['lib']=$langs->trans('ErrorImportOfChartLimitedToCurrentChart', $tmpchartofaccount->ref);
445  $this->errors[$error]['type']='RESTRICTONCURRENCTCHART';
446  $errorforthistable++;
447  $error++;
448  }*/
449  $param_array = array('', $newval, 0, $arrayrecord[0]['val']); // Param to fetch parent from account, in chart.
450  }
451 
452  call_user_func_array(array($classinstance, $method), $param_array);
453  // If not found, try the fetch from label
454  if (!($classinstance->id != '') && $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel')
455  {
456  $param_array = array('', '', $newval);
457  call_user_func_array(array($classinstance, $method), $param_array);
458  }
459  $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval] = $classinstance->id;
460  //print 'We have made a '.$class.'->'.$method.' to get id from code '.$newval.'. ';
461  if ($classinstance->id != '') // id may be 0, it is a found value
462  {
463  $newval = $classinstance->id;
464  } else {
465  if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, $newval, 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
466  elseif (!empty($objimport->array_import_convertvalue[0][$val]['element'])) $this->errors[$error]['lib'] = $langs->trans('ErrorFieldRefNotIn', $key, $newval, $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['element']));
467  else $this->errors[$error]['lib'] = 'ErrorBadDefinitionOfImportProfile';
468  $this->errors[$error]['type'] = 'FOREIGNKEY';
469  $errorforthistable++;
470  $error++;
471  }
472  }
473  }
474  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeandlabel') {
475  $isidorref = 'id';
476  if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) $isidorref = 'ref';
477  $newval = preg_replace('/^(id|ref):/i', '', $newval);
478 
479  if ($isidorref == 'ref') {
480  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
481  $class = $objimport->array_import_convertvalue[0][$val]['class'];
482  $method = $objimport->array_import_convertvalue[0][$val]['method'];
483  $codefromfield = $objimport->array_import_convertvalue[0][$val]['codefromfield'];
484  $code = $arrayrecord[$arrayfield[$codefromfield]]['val'];
485  if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval] != '') {
486  $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval];
487  } else {
488  $resultload = dol_include_once($file);
489  if (empty($resultload)) {
490  dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method.', code='.$code);
491  break;
492  }
493  $classinstance = new $class($this->db);
494  // Try the fetch from code and ref
495  $param_array = array('', $newval, $code);
496  call_user_func_array(array($classinstance, $method), $param_array);
497  $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval] = $classinstance->id;
498  if ($classinstance->id > 0) // we found record
499  {
500  $newval = $classinstance->id;
501  } else {
502  if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
503  else $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
504  $this->errors[$error]['type'] = 'FOREIGNKEY';
505  $errorforthistable++;
506  $error++;
507  }
508  }
509  }
510  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'zeroifnull') {
511  if (empty($newval)) $newval = '0';
512  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits' || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchscalefromcodeunits') {
513  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
514  $class = $objimport->array_import_convertvalue[0][$val]['class'];
515  $method = $objimport->array_import_convertvalue[0][$val]['method'];
516  $units = $objimport->array_import_convertvalue[0][$val]['units'];
517  if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval] != '')
518  {
519  $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval];
520  } else {
521  $resultload = dol_include_once($file);
522  if (empty($resultload))
523  {
524  dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method.', units='.$units);
525  break;
526  }
527  $classinstance = new $class($this->db);
528  // Try the fetch from code or ref
529  call_user_func_array(array($classinstance, $method), array('', '', $newval, $units));
530  $scaleorid = (($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits') ? $classinstance->id : $classinstance->scale);
531  $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval] = $scaleorid;
532  //print 'We have made a '.$class.'->'.$method." to get a value from key '".$newval."' and we got '".$scaleorid."'.";exit;
533  if ($classinstance->id > 0) // we found record
534  {
535  $newval = $scaleorid ? $scaleorid : 0;
536  } else {
537  if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
538  else $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
539  $this->errors[$error]['type'] = 'FOREIGNKEY';
540  $errorforthistable++;
541  $error++;
542  }
543  }
544  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomercodeifauto') {
545  if (strtolower($newval) == 'auto')
546  {
547  $this->thirpartyobject->get_codeclient(0, 0);
548  $newval = $this->thirpartyobject->code_client;
549  //print 'code_client='.$newval;
550  }
551  if (empty($newval)) $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
552  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsuppliercodeifauto') {
553  if (strtolower($newval) == 'auto')
554  {
555  $newval = $this->thirpartyobject->get_codefournisseur(0, 1);
556  $newval = $this->thirpartyobject->code_fournisseur;
557  //print 'code_fournisseur='.$newval;
558  }
559  if (empty($newval)) $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
560  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomeraccountancycodeifauto') {
561  if (strtolower($newval) == 'auto')
562  {
563  $this->thirpartyobject->get_codecompta('customer');
564  $newval = $this->thirpartyobject->code_compta;
565  //print 'code_compta='.$newval;
566  }
567  if (empty($newval)) $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
568  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsupplieraccountancycodeifauto') {
569  if (strtolower($newval) == 'auto')
570  {
571  $this->thirpartyobject->get_codecompta('supplier');
572  $newval = $this->thirpartyobject->code_compta_fournisseur;
573  if (empty($newval)) $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
574  //print 'code_compta_fournisseur='.$newval;
575  }
576  if (empty($newval)) $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
577  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getrefifauto') {
578  $defaultref = '';
579  // TODO provide the $modTask (module of generation of ref) as parameter of import_insert function
580  $obj = empty($conf->global->PROJECT_TASK_ADDON) ? 'mod_task_simple' : $conf->global->PROJECT_TASK_ADDON;
581  if (!empty($conf->global->PROJECT_TASK_ADDON) && is_readable(DOL_DOCUMENT_ROOT."/core/modules/project/task/".$conf->global->PROJECT_TASK_ADDON.".php"))
582  {
583  require_once DOL_DOCUMENT_ROOT."/core/modules/project/task/".$conf->global->PROJECT_TASK_ADDON.'.php';
584  $modTask = new $obj;
585  $defaultref = $modTask->getNextValue(null, null);
586  }
587  if (is_numeric($defaultref) && $defaultref <= 0) $defaultref = '';
588  $newval = $defaultref;
589  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'compute') {
590  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
591  $class = $objimport->array_import_convertvalue[0][$val]['class'];
592  $method = $objimport->array_import_convertvalue[0][$val]['method'];
593  $resultload = dol_include_once($file);
594  if (empty($resultload))
595  {
596  dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method);
597  break;
598  }
599  $classinstance = new $class($this->db);
600  $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord));
601  if ($res < 0) {
602  if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, $newval, 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
603  else $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
604  $this->errors[$error]['type'] = 'FOREIGNKEY';
605  $errorforthistable++;
606  $error++;
607  } else {
608  $newval = $arrayrecord[($key - 1)]['val']; //We get new value computed.
609  }
610  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'numeric') {
611  $newval = price2num($newval);
612  }
613 
614  //print 'Val to use as insert is '.$newval.'<br>';
615  }
616 
617  // Test regexp
618  if (!empty($objimport->array_import_regex[0][$val]) && ($newval != ''))
619  {
620  // If test is "Must exist in a field@table or field@table:..."
621  $reg = array();
622  if (preg_match('/^(.+)@([^:]+)(:.+)?$/', $objimport->array_import_regex[0][$val], $reg))
623  {
624  $field = $reg[1];
625  $table = $reg[2];
626  $filter = !empty($reg[3]) ?substr($reg[3], 1) : '';
627 
628  $cachekey = $field.'@'.$table;
629  if (!empty($filter)) $cachekey .= ':'.$filter;
630 
631  // Load content of field@table into cache array
632  if (!is_array($this->cachefieldtable[$cachekey])) // If content of field@table not already loaded into cache
633  {
634  $sql = "SELECT ".$field." as aliasfield FROM ".$table;
635  if (!empty($filter))
636  {
637  $sql .= ' WHERE '.$filter;
638  }
639 
640  $resql = $this->db->query($sql);
641  if ($resql)
642  {
643  $num = $this->db->num_rows($resql);
644  $i = 0;
645  while ($i < $num)
646  {
647  $obj = $this->db->fetch_object($resql);
648  if ($obj) $this->cachefieldtable[$cachekey][] = $obj->aliasfield;
649  $i++;
650  }
651  } else {
652  dol_print_error($this->db);
653  }
654  }
655 
656  // Now we check cache is not empty (should not) and key is into cache
657  if (!is_array($this->cachefieldtable[$cachekey]) || !in_array($newval, $this->cachefieldtable[$cachekey]))
658  {
659  $tableforerror = $table;
660  if (!empty($filter)) $tableforerror .= ':'.$filter;
661  $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorFieldValueNotIn', $key, $newval, $field, $tableforerror);
662  $this->errors[$error]['type'] = 'FOREIGNKEY';
663  $errorforthistable++;
664  $error++;
665  }
666  }
667  // If test is just a static regex
668  elseif (!preg_match('/'.$objimport->array_import_regex[0][$val].'/i', $newval)) {
669  //if ($key == 19) print "xxx".$newval."zzz".$objimport->array_import_regex[0][$val]."<br>";
670  $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorWrongValueForField', $key, $newval, $objimport->array_import_regex[0][$val]);
671  $this->errors[$error]['type'] = 'REGEX';
672  $errorforthistable++;
673  $error++;
674  }
675  }
676 
677  // Other tests
678  // ...
679  }
680 
681  // Define $listfields and $listvalues to build SQL request
682  $listfields[] = $fieldname;
683 
684  // Note: arrayrecord (and 'type') is filled with ->import_read_record called by import.php page before calling import_insert
685  if (empty($newval) && $arrayrecord[($key - 1)]['type'] < 0) {
686  $listvalues[] = ($newval == '0' ? $newval : "null");
687  } elseif (empty($newval) && $arrayrecord[($key - 1)]['type'] == 0) {
688  $listvalues[] = "''";
689  } else {
690  $listvalues[] = "'".$this->db->escape($newval)."'";
691  }
692  }
693  $i++;
694  }
695 
696  // We add hidden fields (but only if there is at least one field to add into table)
697  if (!empty($listfields) && is_array($objimport->array_import_fieldshidden[0]))
698  {
699  // Loop on each hidden fields to add them into listfields/listvalues
700  foreach ($objimport->array_import_fieldshidden[0] as $key => $val)
701  {
702  if (!preg_match('/^'.preg_quote($alias, '/').'\./', $key)) continue; // Not a field of current table
703  if ($val == 'user->id')
704  {
705  $listfields[] = preg_replace('/^'.preg_quote($alias, '/').'\./', '', $key);
706  $listvalues[] = $user->id;
707  } elseif (preg_match('/^lastrowid-/', $val))
708  {
709  $tmp = explode('-', $val);
710  $lastinsertid = (isset($last_insert_id_array[$tmp[1]])) ? $last_insert_id_array[$tmp[1]] : 0;
711  $keyfield = preg_replace('/^'.preg_quote($alias, '/').'\./', '', $key);
712  $listfields[] = $keyfield;
713  $listvalues[] = $lastinsertid;
714  //print $key."-".$val."-".$listfields."-".$listvalues."<br>";exit;
715  } elseif (preg_match('/^const-/', $val))
716  {
717  $tmp = explode('-', $val, 2);
718  $listfields[] = preg_replace('/^'.preg_quote($alias, '/').'\./', '', $key);
719  $listvalues[] = "'".$tmp[1]."'";
720  } else {
721  $this->errors[$error]['lib'] = 'Bad value of profile setup '.$val.' for array_import_fieldshidden';
722  $this->errors[$error]['type'] = 'Import profile setup';
723  $error++;
724  }
725  }
726  }
727  //print 'listfields='.$listfields.'<br>listvalues='.$listvalues.'<br>';
728 
729  // If no error for this $alias/$tablename, we have a complete $listfields and $listvalues that are defined
730  // so we can try to make the insert or update now.
731  if (!$errorforthistable)
732  {
733  //print "$alias/$tablename/$listfields/$listvalues<br>";
734  if (!empty($listfields))
735  {
736  $updatedone = false;
737  $insertdone = false;
738 
739  if (!empty($updatekeys)) {
740  // We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
741 
742  if (empty($lastinsertid)) { // No insert done yet for a parent table
743  $sqlSelect = 'SELECT rowid FROM '.$tablename;
744 
745  $data = array_combine($listfields, $listvalues);
746  $where = array();
747  $filters = array();
748  foreach ($updatekeys as $key) {
749  $col = $objimport->array_import_updatekeys[0][$key];
750  $key = preg_replace('/^.*\./i', '', $key);
751  $where[] = $key.' = '.$data[$key];
752  $filters[] = $col.' = '.$data[$key];
753  }
754  $sqlSelect .= ' WHERE '.implode(' AND ', $where);
755 
756  $resql = $this->db->query($sqlSelect);
757  if ($resql) {
758  $res = $this->db->fetch_object($resql);
759  if ($resql->num_rows == 1) {
760  $lastinsertid = $res->rowid;
761  $last_insert_id_array[$tablename] = $lastinsertid;
762  } elseif ($resql->num_rows > 1) {
763  $this->errors[$error]['lib'] = $langs->trans('MultipleRecordFoundWithTheseFilters', implode(', ', $filters));
764  $this->errors[$error]['type'] = 'SQL';
765  $error++;
766  } else {
767  // No record found with filters, insert will be tried below
768  }
769  } else {
770  //print 'E';
771  $this->errors[$error]['lib'] = $this->db->lasterror();
772  $this->errors[$error]['type'] = 'SQL';
773  $error++;
774  }
775  } else {
776  // We have a last INSERT ID (got by previous pass), so we check if we have a row referencing this foreign key.
777  // This is required when updating table with some extrafields. When inserting a record in parent table, we can make
778  // a direct insert into subtable extrafields, but when me wake an update, the insertid is defined and the child record
779  // may already exists. So we rescan the extrafield table to know if record exists or not for the rowid.
780  // Note: For extrafield tablename, we have in importfieldshidden_array an enty 'extra.fk_object'=>'lastrowid-tableparent' so $keyfield is 'fk_object'
781  $sqlSelect = 'SELECT rowid FROM '.$tablename;
782 
783  if (empty($keyfield)) $keyfield = 'rowid';
784  $sqlSelect .= ' WHERE '.$keyfield.' = '.$lastinsertid;
785 
786  $resql = $this->db->query($sqlSelect);
787  if ($resql) {
788  $res = $this->db->fetch_object($resql);
789  if ($resql->num_rows == 1) {
790  // We have a row referencing this last foreign key, continue with UPDATE.
791  } else {
792  // No record found referencing this last foreign key,
793  // force $lastinsertid to 0 so we INSERT below.
794  $lastinsertid = 0;
795  }
796  } else {
797  //print 'E';
798  $this->errors[$error]['lib'] = $this->db->lasterror();
799  $this->errors[$error]['type'] = 'SQL';
800  $error++;
801  }
802  }
803 
804  if (!empty($lastinsertid)) {
805  // Build SQL UPDATE request
806  $sqlstart = 'UPDATE '.$tablename;
807 
808  $data = array_combine($listfields, $listvalues);
809  $set = array();
810  foreach ($data as $key => $val) {
811  $set[] = $key.' = '.$val;
812  }
813  $sqlstart .= ' SET '.implode(', ', $set);
814 
815  if (empty($keyfield)) $keyfield = 'rowid';
816  $sqlend = ' WHERE '.$keyfield.' = '.$lastinsertid;
817 
818  $sql = $sqlstart.$sqlend;
819 
820  // Run update request
821  $resql = $this->db->query($sql);
822  if ($resql) {
823  // No error, update has been done. $this->db->db->affected_rows can be 0 if data hasn't changed
824  $updatedone = true;
825  } else {
826  //print 'E';
827  $this->errors[$error]['lib'] = $this->db->lasterror();
828  $this->errors[$error]['type'] = 'SQL';
829  $error++;
830  }
831  }
832  }
833 
834  // Update not done, we do insert
835  if (!$error && !$updatedone) {
836  // Build SQL INSERT request
837  $sqlstart = 'INSERT INTO '.$tablename.'('.implode(', ', $listfields).', import_key';
838  $sqlend = ') VALUES('.implode(', ', $listvalues).", '".$this->db->escape($importid)."'";
839  if (!empty($tablewithentity_cache[$tablename])) {
840  $sqlstart .= ', entity';
841  $sqlend .= ', '.$conf->entity;
842  }
843  if (!empty($objimport->array_import_tables_creator[0][$alias])) {
844  $sqlstart .= ', '.$objimport->array_import_tables_creator[0][$alias];
845  $sqlend .= ', '.$user->id;
846  }
847  $sql = $sqlstart.$sqlend.')';
848  //dol_syslog("import_csv.modules", LOG_DEBUG);
849 
850  // Run insert request
851  if ($sql)
852  {
853  $resql = $this->db->query($sql);
854  if ($resql)
855  {
856  $last_insert_id_array[$tablename] = $this->db->last_insert_id($tablename); // store the last inserted auto_increment id for each table, so that child tables can be inserted with the appropriate id. This must be done just after the INSERT request, else we risk losing the id (because another sql query will be issued somewhere in Dolibarr).
857  $insertdone = true;
858  } else {
859  //print 'E';
860  $this->errors[$error]['lib'] = $this->db->lasterror();
861  $this->errors[$error]['type'] = 'SQL';
862  $error++;
863  }
864  }
865  }
866  }
867  /*else
868  {
869  dol_print_error('','ErrorFieldListEmptyFor '.$alias."/".$tablename);
870  }*/
871  }
872 
873  if ($error) break;
874  }
875 
876  if ($updatedone) $this->nbupdate++;
877  if ($insertdone) $this->nbinsert++;
878  }
879 
880  return 1;
881  }
882 }
883 
890 function cleansep($value)
891 {
892  return str_replace(array(',', ';'), '/', $value);
893 };
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname= '')
Make an include_once using default root and alternate root if it fails.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
write_footer_example($outputlangs)
Output footer of an example file for this format.
import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
Insert a record into database.
cleansep($value)
Clean a string from separator.
import_close_file()
Close file handle.
__construct($db, $datatoimport)
Constructor.
$conf db
API class for accounts.
Definition: inc.php:54
import_get_nb_of_lines($file)
Return nb of records.
import_read_record()
Return array of next record in input file.
Class to manage third parties objects (customers, suppliers, prospects...)
dol_strlen($string, $stringencoding= 'UTF-8')
Make a strlen call.
price2num($amount, $rounding= '', $option=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
utf8_check($str)
Check if a string is in UTF8.
dol_count_nb_of_line($file)
Count number of lines in a file.
Definition: files.lib.php:524
Class to import CSV files.
write_header_example($outputlangs)
Output header of an example file for this format.
Parent class for import file readers.
write_title_example($outputlangs, $headerlinefields)
Output title line of an example file for this format.
write_record_example($outputlangs, $contentlinevalues)
Output record of an example file for this format.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
import_open_file($file)
Open input file.
import_read_header()
Input header line from file.