dolibarr  20.0.0-alpha
import_xlsx.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  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  * or see https://www.gnu.org/
21  */
22 
29 use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
30 use PhpOffice\PhpSpreadsheet\Spreadsheet;
31 use PhpOffice\PhpSpreadsheet\Style\Alignment;
32 
33 require_once DOL_DOCUMENT_ROOT . '/core/modules/import/modules_import.php';
34 
35 
40 {
44  public $db;
45 
49  public $id;
50 
54  public $label;
55 
56  public $extension; // Extension of files imported by driver
57 
62  public $version = 'dolibarr';
63 
64  public $label_lib; // Label of external lib used by driver
65 
66  public $version_lib; // Version of external lib used by driver
67 
68  public $separator;
69 
70  public $file; // Path of file
71 
72  public $handle; // Handle fichier
73 
74  public $cacheconvert = array(); // Array to cache list of value found after a conversion
75 
76  public $cachefieldtable = array(); // Array to cache list of value found into fields@tables
77 
78  public $nbinsert = 0; // # of insert done during the import
79 
80  public $nbupdate = 0; // # of update done during the import
81 
82  public $workbook; // temporary import file
83 
84  public $record; // current record
85 
86  public $headers;
87 
88 
95  public function __construct($db, $datatoimport)
96  {
97  global $conf, $langs;
98 
99  parent::__construct();
100  $this->db = $db;
101 
102  // this is used as an extension from the example file code, so we have to put xlsx here !!!
103  $this->id = 'xlsx'; // Same value as xxx in file name export_xxx.modules.php
104  $this->label = 'Excel 2007'; // Label of driver
105  $this->desc = $langs->trans("Excel2007FormatDesc");
106  $this->extension = 'xlsx'; // Extension for generated file by this driver
107  $this->picto = 'mime/xls'; // Picto (This is not used by the example file code as Mime type, too bad ...)
108  $this->version = '1.0'; // Driver version
109 
110  // If driver use an external library, put its name here
111  require_once DOL_DOCUMENT_ROOT.'/includes/phpoffice/phpspreadsheet/src/autoloader.php';
112  require_once DOL_DOCUMENT_ROOT.'/includes/Psr/autoloader.php';
113  require_once PHPEXCELNEW_PATH.'Spreadsheet.php';
114  $this->workbook = new Spreadsheet();
115 
116  // If driver use an external library, put its name here
117  if (!class_exists('ZipArchive')) { // For Excel2007
118  $langs->load("errors");
119  $this->error = $langs->trans('ErrorPHPNeedModule', 'zip');
120  return;
121  }
122  $this->label_lib = 'PhpSpreadSheet';
123  $this->version_lib = '1.8.0';
124 
125  $this->datatoimport = $datatoimport;
126  if (preg_match('/^societe_/', $datatoimport)) {
127  $this->thirdpartyobject = new Societe($this->db);
128  }
129  }
130 
131 
132  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
139  public function write_header_example($outputlangs)
140  {
141  // phpcs:enable
142  global $user, $conf, $langs, $file;
143  // create a temporary object, the final output will be generated in footer
144  $this->workbook->getProperties()->setCreator($user->getFullName($outputlangs) . ' - Dolibarr ' . DOL_VERSION);
145  $this->workbook->getProperties()->setTitle($outputlangs->trans("Import") . ' - ' . $file);
146  $this->workbook->getProperties()->setSubject($outputlangs->trans("Import") . ' - ' . $file);
147  $this->workbook->getProperties()->setDescription($outputlangs->trans("Import") . ' - ' . $file);
148 
149  $this->workbook->setActiveSheetIndex(0);
150  $this->workbook->getActiveSheet()->setTitle($outputlangs->trans("Sheet"));
151  $this->workbook->getActiveSheet()->getDefaultRowDimension()->setRowHeight(16);
152 
153  return '';
154  }
155 
156  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
164  public function write_title_example($outputlangs, $headerlinefields)
165  {
166  // phpcs:enable
167  global $conf;
168  $this->workbook->getActiveSheet()->getStyle('1')->getFont()->setBold(true);
169  $this->workbook->getActiveSheet()->getStyle('1')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT);
170 
171  $col = 1;
172  foreach ($headerlinefields as $field) {
173  $this->workbook->getActiveSheet()->SetCellValueByColumnAndRow($col, 1, $outputlangs->transnoentities($field));
174  // set autowidth
175  //$this->workbook->getActiveSheet()->getColumnDimension($this->column2Letter($col + 1))->setAutoSize(true);
176  $col++;
177  }
178 
179  return ''; // final output will be generated in footer
180  }
181 
182  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
190  public function write_record_example($outputlangs, $contentlinevalues)
191  {
192  // phpcs:enable
193  $col = 1;
194  $row = 2;
195  foreach ($contentlinevalues as $cell) {
196  $this->workbook->getActiveSheet()->SetCellValueByColumnAndRow($col, $row, $cell);
197  $col++;
198  }
199 
200  return ''; // final output will be generated in footer
201  }
202 
203  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
210  public function write_footer_example($outputlangs)
211  {
212  // phpcs:enable
213  // return the file content as a string
214  $tempfile = tempnam(sys_get_temp_dir(), 'dol');
215  $objWriter = new PhpOffice\PhpSpreadsheet\Writer\Xlsx($this->workbook);
216  $objWriter->save($tempfile);
217  $this->workbook->disconnectWorksheets();
218  unset($this->workbook);
219 
220  $content = file_get_contents($tempfile);
221  unlink($tempfile);
222  return $content;
223  }
224 
225 
226 
227  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
234  public function import_open_file($file)
235  {
236  // phpcs:enable
237  global $langs;
238  $ret = 1;
239 
240  dol_syslog(get_class($this) . "::open_file file=" . $file);
241 
242  $reader = new Xlsx();
243  $this->workbook = $reader->load($file);
244  $this->record = 1;
245  $this->file = $file;
246 
247  return $ret;
248  }
249 
250 
251  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
258  public function import_get_nb_of_lines($file)
259  {
260  // phpcs:enable
261  $reader = new Xlsx();
262  $this->workbook = $reader->load($file);
263 
264  $rowcount = $this->workbook->getActiveSheet()->getHighestDataRow();
265 
266  $this->workbook->disconnectWorksheets();
267  unset($this->workbook);
268 
269  return $rowcount;
270  }
271 
272 
273  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
279  public function import_read_header()
280  {
281  // phpcs:enable
282  // This is not called by the import code !!!
283  $this->headers = array();
284  $xlsx = new Xlsx();
285  $info = $xlsx->listWorksheetinfo($this->file);
286  $countcolumns = $info[0]['totalColumns'];
287  for ($col = 1; $col <= $countcolumns; $col++) {
288  $this->headers[$col] = $this->workbook->getActiveSheet()->getCellByColumnAndRow($col, 1)->getValue();
289  }
290  return 0;
291  }
292 
293 
294  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
300  public function import_read_record()
301  {
302  // phpcs:enable
303  global $conf;
304 
305  $rowcount = $this->workbook->getActiveSheet()->getHighestDataRow();
306  if ($this->record > $rowcount) {
307  return false;
308  }
309  $array = array();
310  $xlsx = new Xlsx();
311  $info = $xlsx->listWorksheetinfo($this->file);
312  $countcolumns = $info[0]['totalColumns'];
313  for ($col = 1; $col <= $countcolumns; $col++) {
314  $val = $this->workbook->getActiveSheet()->getCellByColumnAndRow($col, $this->record)->getValue();
315  $array[$col]['val'] = $val;
316  $array[$col]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we consider it null
317  }
318  $this->record++;
319  return $array;
320  }
321 
322  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
328  public function import_close_file()
329  {
330  // phpcs:enable
331  $this->workbook->disconnectWorksheets();
332  unset($this->workbook);
333  return 0;
334  }
335 
336 
337  // What is this doing here ? it is common to all imports, is should be in the parent class
338  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
350  public function import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
351  {
352  // phpcs:enable
353  global $langs, $conf, $user;
354  global $thirdparty_static; // Specific to thirdparty import
355  global $tablewithentity_cache; // Cache to avoid to call desc at each rows on tables
356 
357  $error = 0;
358  $warning = 0;
359  $this->errors = array();
360  $this->warnings = array();
361 
362  //dol_syslog("import_csv.modules maxfields=".$maxfields." importid=".$importid);
363 
364  //var_dump($array_match_file_to_database);
365  //var_dump($arrayrecord); exit;
366 
367  $array_match_database_to_file = array_flip($array_match_file_to_database);
368  $sort_array_match_file_to_database = $array_match_file_to_database;
369  ksort($sort_array_match_file_to_database);
370 
371  //var_dump($sort_array_match_file_to_database);
372 
373  if (count($arrayrecord) == 0 || (count($arrayrecord) == 1 && empty($arrayrecord[1]['val']))) {
374  //print 'W';
375  $this->warnings[$warning]['lib'] = $langs->trans('EmptyLine');
376  $this->warnings[$warning]['type'] = 'EMPTY';
377  $warning++;
378  } else {
379  $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)
380  $updatedone = false;
381  $insertdone = false;
382  // For each table to insert, me make a separate insert
383  foreach ($objimport->array_import_tables[0] as $alias => $tablename) {
384  // Build sql request
385  $sql = '';
386  $listfields = array();
387  $listvalues = array();
388  $i = 0;
389  $errorforthistable = 0;
390 
391  // Define $tablewithentity_cache[$tablename] if not already defined
392  if (!isset($tablewithentity_cache[$tablename])) { // keep this test with "isset"
393  dol_syslog("Check if table " . $tablename . " has an entity field");
394  $resql = $this->db->DDLDescTable($tablename, 'entity');
395  if ($resql) {
396  $obj = $this->db->fetch_object($resql);
397  if ($obj) {
398  $tablewithentity_cache[$tablename] = 1; // table contains entity field
399  } else {
400  $tablewithentity_cache[$tablename] = 0; // table does not contain entity field
401  }
402  } else {
403  dol_print_error($this->db);
404  }
405  } else {
406  //dol_syslog("Table ".$tablename." check for entity into cache is ".$tablewithentity_cache[$tablename]);
407  }
408 
409  // Define array to convert fields ('c.ref', ...) into column index (1, ...)
410  $arrayfield = array();
411  foreach ($sort_array_match_file_to_database as $key => $val) {
412  $arrayfield[$val] = ($key);
413  }
414 
415  // $arrayrecord start at key 1
416  // $sort_array_match_file_to_database start at key 1
417 
418  // Loop on each fields in the match array: $key = 1..n, $val=alias of field (s.nom)
419  foreach ($sort_array_match_file_to_database as $key => $val) {
420  $fieldalias = preg_replace('/\..*$/i', '', $val);
421  $fieldname = preg_replace('/^.*\./i', '', $val);
422 
423  if ($alias != $fieldalias) {
424  continue; // Not a field of current table
425  }
426 
427  if ($key <= $maxfields) {
428  // Set $newval with value to insert and set $listvalues with sql request part for insert
429  $newval = '';
430  if ($arrayrecord[($key)]['type'] > 0) {
431  $newval = $arrayrecord[($key)]['val']; // If type of field into input file is not empty string (so defined into input file), we get value
432  }
433 
434  //var_dump($newval);var_dump($val);
435  //var_dump($objimport->array_import_convertvalue[0][$val]);
436 
437  // Make some tests on $newval
438 
439  // Is it a required field ?
440  if (preg_match('/\*/', $objimport->array_import_fields[0][$val]) && ((string) $newval == '')) {
441  $this->errors[$error]['lib'] = $langs->trans('ErrorMissingMandatoryValue', num2Alpha($key - 1));
442  $this->errors[$error]['type'] = 'NOTNULL';
443  $errorforthistable++;
444  $error++;
445  } else {
446  // Test format only if field is not a missing mandatory field (field may be a value or empty but not mandatory)
447  // We convert field if required
448  if (!empty($objimport->array_import_convertvalue[0][$val])) {
449  //print 'Must convert '.$newval.' with rule '.join(',',$objimport->array_import_convertvalue[0][$val]).'. ';
450  if ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeid'
451  || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromref'
452  || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel'
453  ) {
454  // 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.
455  $isidorref = 'id';
456  if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
457  $isidorref = 'ref';
458  }
459  $newval = preg_replace('/^(id|ref):/i', '', $newval); // Remove id: or ref: that was used to force if field is id or ref
460  //print 'Newval is now "'.$newval.'" and is type '.$isidorref."<br>\n";
461 
462  if ($isidorref == 'ref') { // If value into input import file is a ref, we apply the function defined into descriptor
463  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
464  $class = $objimport->array_import_convertvalue[0][$val]['class'];
465  $method = $objimport->array_import_convertvalue[0][$val]['method'];
466  if ($this->cacheconvert[$file . '_' . $class . '_' . $method . '_'][$newval] != '') {
467  $newval = $this->cacheconvert[$file . '_' . $class . '_' . $method . '_'][$newval];
468  } else {
469  $resultload = dol_include_once($file);
470  if (empty($resultload)) {
471  dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
472  break;
473  }
474  $classinstance = new $class($this->db);
475  if ($class == 'CGenericDic') {
476  $classinstance->element = $objimport->array_import_convertvalue[0][$val]['element'];
477  $classinstance->table_element = $objimport->array_import_convertvalue[0][$val]['table_element'];
478  }
479 
480  // Try the fetch from code or ref
481  $param_array = array('', $newval);
482  if ($class == 'AccountingAccount') {
483  //var_dump($arrayrecord[0]['val']);
484  /*include_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancysystem.class.php';
485  $tmpchartofaccount = new AccountancySystem($this->db);
486  $tmpchartofaccount->fetch(getDolGlobalInt('CHARTOFACCOUNTS'));
487  //var_dump($tmpchartofaccount->ref.' - '.$arrayrecord[0]['val']);
488  if ((! (getDolGlobalInt('CHARTOFACCOUNTS') > 0)) || $tmpchartofaccount->ref != $arrayrecord[0]['val'])
489  {
490  $this->errors[$error]['lib']=$langs->trans('ErrorImportOfChartLimitedToCurrentChart', $tmpchartofaccount->ref);
491  $this->errors[$error]['type']='RESTRICTONCURRENCTCHART';
492  $errorforthistable++;
493  $error++;
494  }*/
495  $param_array = array('', $newval, 0, $arrayrecord[0]['val']); // Param to fetch parent from account, in chart.
496  }
497 
498  $result = call_user_func_array(array($classinstance, $method), $param_array);
499 
500  // If duplicate record found
501  if (!($classinstance->id != '') && $result == -2) {
502  $this->errors[$error]['lib'] = $langs->trans('ErrorMultipleRecordFoundFromRef', $newval);
503  $this->errors[$error]['type'] = 'FOREIGNKEY';
504  $errorforthistable++;
505  $error++;
506  }
507 
508  // If not found, try the fetch from label
509  if (!($classinstance->id != '') && $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel') {
510  $param_array = array('', '', $newval);
511  call_user_func_array(array($classinstance, $method), $param_array);
512  }
513  $this->cacheconvert[$file . '_' . $class . '_' . $method . '_'][$newval] = $classinstance->id;
514 
515  //print 'We have made a '.$class.'->'.$method.' to get id from code '.$newval.'. ';
516  if ($classinstance->id != '') { // id may be 0, it is a found value
517  $newval = $classinstance->id;
518  } elseif (! $error) {
519  if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
520  // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
521  $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, $newval, 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
522  } elseif (!empty($objimport->array_import_convertvalue[0][$val]['element'])) {
523  // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
524  $this->errors[$error]['lib'] = $langs->trans('ErrorFieldRefNotIn', $key, $newval, $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['element']));
525  } else {
526  $this->errors[$error]['lib'] = 'ErrorBadDefinitionOfImportProfile';
527  }
528  $this->errors[$error]['type'] = 'FOREIGNKEY';
529  $errorforthistable++;
530  $error++;
531  }
532  }
533  }
534  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeandlabel') {
535  $isidorref = 'id';
536  if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
537  $isidorref = 'ref';
538  }
539  $newval = preg_replace('/^(id|ref):/i', '', $newval);
540 
541  if ($isidorref == 'ref') {
542  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
543  $class = $objimport->array_import_convertvalue[0][$val]['class'];
544  $method = $objimport->array_import_convertvalue[0][$val]['method'];
545  $codefromfield = $objimport->array_import_convertvalue[0][$val]['codefromfield'];
546  $code = $arrayrecord[$arrayfield[$codefromfield]]['val'];
547  if ($this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $code][$newval] != '') {
548  $newval = $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $code][$newval];
549  } else {
550  $resultload = dol_include_once($file);
551  if (empty($resultload)) {
552  dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method . ', code=' . $code);
553  break;
554  }
555  $classinstance = new $class($this->db);
556  // Try the fetch from code and ref
557  $param_array = array('', $newval, $code);
558  call_user_func_array(array($classinstance, $method), $param_array);
559  $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $code][$newval] = $classinstance->id;
560  if ($classinstance->id > 0) { // we found record
561  $newval = $classinstance->id;
562  } else {
563  if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
564  // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
565  $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
566  } else {
567  $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
568  }
569  $this->errors[$error]['type'] = 'FOREIGNKEY';
570  $errorforthistable++;
571  $error++;
572  }
573  }
574  }
575  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'zeroifnull') {
576  if (empty($newval)) {
577  $newval = '0';
578  }
579  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits' || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchscalefromcodeunits') {
580  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
581  $class = $objimport->array_import_convertvalue[0][$val]['class'];
582  $method = $objimport->array_import_convertvalue[0][$val]['method'];
583  $units = $objimport->array_import_convertvalue[0][$val]['units'];
584  if ($this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $units][$newval] != '') {
585  $newval = $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $units][$newval];
586  } else {
587  $resultload = dol_include_once($file);
588  if (empty($resultload)) {
589  dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method . ', units=' . $units);
590  break;
591  }
592  $classinstance = new $class($this->db);
593  // Try the fetch from code or ref
594  call_user_func_array(array($classinstance, $method), array('', '', $newval, $units));
595  $scaleorid = (($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits') ? $classinstance->id : $classinstance->scale);
596  $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $units][$newval] = $scaleorid;
597  //print 'We have made a '.$class.'->'.$method." to get a value from key '".$newval."' and we got '".$scaleorid."'.";exit;
598  if ($classinstance->id > 0) { // we found record
599  $newval = $scaleorid ? $scaleorid : 0;
600  } else {
601  if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
602  // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
603  $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
604  } else {
605  $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
606  }
607  $this->errors[$error]['type'] = 'FOREIGNKEY';
608  $errorforthistable++;
609  $error++;
610  }
611  }
612  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomercodeifauto') {
613  if (strtolower($newval) == 'auto') {
614  $this->thirdpartyobject->get_codeclient(0, 0);
615  $newval = $this->thirdpartyobject->code_client;
616  //print 'code_client='.$newval;
617  }
618  if (empty($newval)) {
619  $arrayrecord[($key)]['type'] = -1; // If we get empty value, we will use "null"
620  }
621  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsuppliercodeifauto') {
622  if (strtolower($newval) == 'auto') {
623  $this->thirdpartyobject->get_codefournisseur(0, 1);
624  $newval = $this->thirdpartyobject->code_fournisseur;
625  //print 'code_fournisseur='.$newval;
626  }
627  if (empty($newval)) {
628  $arrayrecord[($key)]['type'] = -1; // If we get empty value, we will use "null"
629  }
630  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomeraccountancycodeifauto') {
631  if (strtolower($newval) == 'auto') {
632  $this->thirdpartyobject->get_codecompta('customer');
633  $newval = $this->thirdpartyobject->code_compta;
634  //print 'code_compta='.$newval;
635  }
636  if (empty($newval)) {
637  $arrayrecord[($key)]['type'] = -1; // If we get empty value, we will use "null"
638  }
639  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsupplieraccountancycodeifauto') {
640  if (strtolower($newval) == 'auto') {
641  $this->thirdpartyobject->get_codecompta('supplier');
642  $newval = $this->thirdpartyobject->code_compta_fournisseur;
643  if (empty($newval)) {
644  $arrayrecord[($key)]['type'] = -1; // If we get empty value, we will use "null"
645  }
646  //print 'code_compta_fournisseur='.$newval;
647  }
648  if (empty($newval)) {
649  $arrayrecord[($key)]['type'] = -1; // If we get empty value, we will use "null"
650  }
651  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getrefifauto') {
652  if (strtolower($newval) == 'auto') {
653  $defaultref = '';
654 
655  $classModForNumber = $objimport->array_import_convertvalue[0][$val]['class'];
656  $pathModForNumber = $objimport->array_import_convertvalue[0][$val]['path'];
657 
658  if (!empty($classModForNumber) && !empty($pathModForNumber) && is_readable(DOL_DOCUMENT_ROOT.$pathModForNumber)) {
659  require_once DOL_DOCUMENT_ROOT.$pathModForNumber;
660  $modForNumber = new $classModForNumber();
661 
662  $tmpobject = null;
663  // Set the object with the date property when we can
664  if (!empty($objimport->array_import_convertvalue[0][$val]['classobject'])) {
665  $pathForObject = $objimport->array_import_convertvalue[0][$val]['pathobject'];
666  require_once DOL_DOCUMENT_ROOT.$pathForObject;
667  $tmpclassobject = $objimport->array_import_convertvalue[0][$val]['classobject'];
668  $tmpobject = new $tmpclassobject($this->db);
669  foreach ($arrayfield as $tmpkey => $tmpval) { // $arrayfield is array('c.ref'=>1, ...)
670  if (in_array($tmpkey, array('t.date', 'c.date_commande'))) {
671  $tmpobject->date = dol_stringtotime($arrayrecord[$arrayfield[$tmpkey]]['val'], 1);
672  }
673  }
674  }
675 
676  $defaultref = $modForNumber->getNextValue(null, $tmpobject);
677  }
678  if (is_numeric($defaultref) && $defaultref <= 0) { // If error
679  $defaultref = '';
680  }
681  $newval = $defaultref;
682  }
683  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'compute') {
684  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
685  $class = $objimport->array_import_convertvalue[0][$val]['class'];
686  $method = $objimport->array_import_convertvalue[0][$val]['method'];
687  $resultload = dol_include_once($file);
688  if (empty($resultload)) {
689  dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
690  break;
691  }
692  $classinstance = new $class($this->db);
693  $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, $key));
694  if (empty($classinstance->error) && empty($classinstance->errors)) {
695  $newval = $res; // We get new value computed.
696  } else {
697  $this->errors[$error]['type'] = 'CLASSERROR';
698  $this->errors[$error]['lib'] = implode(
699  "\n",
700  array_merge([$classinstance->error], $classinstance->errors)
701  );
702  $errorforthistable++;
703  $error++;
704  }
705  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'numeric') {
706  $newval = price2num($newval);
707  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'accountingaccount') {
708  if (!getDolGlobalString('ACCOUNTING_MANAGE_ZERO')) {
709  $newval = rtrim(trim($newval), "0");
710  } else {
711  $newval = trim($newval);
712  }
713  }
714 
715  //print 'Val to use as insert is '.$newval.'<br>';
716  }
717 
718  // Test regexp
719  if (!empty($objimport->array_import_regex[0][$val]) && ($newval != '')) {
720  // If test is "Must exist in a field@table or field@table:..."
721  $reg = array();
722  if (preg_match('/^(.+)@([^:]+)(:.+)?$/', $objimport->array_import_regex[0][$val], $reg)) {
723  $field = $reg[1];
724  $table = $reg[2];
725  $filter = !empty($reg[3]) ? substr($reg[3], 1) : '';
726 
727  $cachekey = $field . '@' . $table;
728  if (!empty($filter)) {
729  $cachekey .= ':' . $filter;
730  }
731 
732  // Load content of field@table into cache array
733  if (!is_array($this->cachefieldtable[$cachekey])) { // If content of field@table not already loaded into cache
734  $sql = "SELECT " . $field . " as aliasfield FROM " . $table;
735  if (!empty($filter)) {
736  $sql .= ' WHERE ' . $filter;
737  }
738 
739  $resql = $this->db->query($sql);
740  if ($resql) {
741  $num = $this->db->num_rows($resql);
742  $i = 0;
743  while ($i < $num) {
744  $obj = $this->db->fetch_object($resql);
745  if ($obj) {
746  $this->cachefieldtable[$cachekey][] = $obj->aliasfield;
747  }
748  $i++;
749  }
750  } else {
751  dol_print_error($this->db);
752  }
753  }
754 
755  // Now we check cache is not empty (should not) and key is into cache
756  if (!is_array($this->cachefieldtable[$cachekey]) || !in_array($newval, $this->cachefieldtable[$cachekey])) {
757  $tableforerror = $table;
758  if (!empty($filter)) {
759  $tableforerror .= ':' . $filter;
760  }
761  // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
762  $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorFieldValueNotIn', $key, $newval, $field, $tableforerror);
763  $this->errors[$error]['type'] = 'FOREIGNKEY';
764  $errorforthistable++;
765  $error++;
766  }
767  } elseif (!preg_match('/' . $objimport->array_import_regex[0][$val] . '/i', $newval)) {
768  // If test is just a static regex
769  //if ($key == 19) print "xxx".$newval."zzz".$objimport->array_import_regex[0][$val]."<br>";
770  // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
771  $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorWrongValueForField', $key, $newval, $objimport->array_import_regex[0][$val]);
772  $this->errors[$error]['type'] = 'REGEX';
773  $errorforthistable++;
774  $error++;
775  }
776  }
777 
778  // Check HTML injection
779  $inj = testSqlAndScriptInject($newval, 0);
780  if ($inj) {
781  // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
782  $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorHtmlInjectionForField', $key, dol_trunc($newval, 100));
783  $this->errors[$error]['type'] = 'HTMLINJECTION';
784  $errorforthistable++;
785  $error++;
786  }
787 
788  // Other tests
789  // ...
790  }
791 
792  // Define $listfields and $listvalues to build the SQL request
793  if (isModEnabled("socialnetworks") && strpos($fieldname, "socialnetworks") !== false) {
794  if (!in_array("socialnetworks", $listfields)) {
795  $listfields[] = "socialnetworks";
796  $socialkey = array_search("socialnetworks", $listfields); // Return position of 'socialnetworks' key in array. Example socialkey=19
797  $listvalues[$socialkey] = '';
798  }
799  if (!empty($newval) && $arrayrecord[($key)]['type'] > 0) {
800  $socialkey = array_search("socialnetworks", $listfields); // Return position of 'socialnetworks' key in array. Example socialkey=19
801  $socialnetwork = explode("_", $fieldname)[1];
802  if (empty($listvalues[$socialkey]) || $listvalues[$socialkey] == "null") {
803  $json = new stdClass();
804  $json->$socialnetwork = $newval;
805  $listvalues[$socialkey] = json_encode($json);
806  } else {
807  $jsondata = $listvalues[$socialkey];
808  $json = json_decode($jsondata);
809  $json->$socialnetwork = $newval;
810  $listvalues[$socialkey] = json_encode($json);
811  }
812  }
813  } else {
814  $listfields[] = $fieldname;
815 
816  // Note: arrayrecord (and 'type') is filled with ->import_read_record called by import.php page before calling import_insert
817  if (empty($newval) && $arrayrecord[($key)]['type'] < 0) {
818  $listvalues[] = ($newval == '0' ? (int) $newval : "null");
819  } elseif (empty($newval) && $arrayrecord[($key)]['type'] == 0) {
820  $listvalues[] = "''";
821  } else {
822  $listvalues[] = "'".$this->db->escape($newval)."'";
823  }
824  }
825  }
826  $i++;
827  }
828 
829  // We add hidden fields (but only if there is at least one field to add into table)
830  // We process here all the fields that were declared into the array $this->import_fieldshidden_array of the descriptor file.
831  // Previously we processed the ->import_fields_array.
832  if (!empty($listfields) && is_array($objimport->array_import_fieldshidden[0])) {
833  // Loop on each hidden fields to add them into listfields/listvalues
834  foreach ($objimport->array_import_fieldshidden[0] as $key => $val) {
835  if (!preg_match('/^'.preg_quote($alias, '/').'\./', $key)) {
836  continue; // Not a field of current table
837  }
838  if ($val == 'user->id') {
839  $listfields[] = preg_replace('/^' . preg_quote($alias, '/') . '\./', '', $key);
840  $listvalues[] = ((int) $user->id);
841  } elseif (preg_match('/^lastrowid-/', $val)) {
842  $tmp = explode('-', $val);
843  $lastinsertid = (isset($last_insert_id_array[$tmp[1]])) ? $last_insert_id_array[$tmp[1]] : 0;
844  $keyfield = preg_replace('/^' . preg_quote($alias, '/') . '\./', '', $key);
845  $listfields[] = $keyfield;
846  $listvalues[] = (int) $lastinsertid;
847  //print $key."-".$val."-".$listfields."-".$listvalues."<br>";exit;
848  } elseif (preg_match('/^const-/', $val)) {
849  $tmp = explode('-', $val, 2);
850  $listfields[] = preg_replace('/^' . preg_quote($alias, '/') . '\./', '', $key);
851  $listvalues[] = "'".$this->db->escape($tmp[1])."'";
852  } elseif (preg_match('/^rule-/', $val)) {
853  $fieldname = $key;
854  if (!empty($objimport->array_import_convertvalue[0][$fieldname])) {
855  if ($objimport->array_import_convertvalue[0][$fieldname]['rule'] == 'compute') {
856  $file = (empty($objimport->array_import_convertvalue[0][$fieldname]['classfile']) ? $objimport->array_import_convertvalue[0][$fieldname]['file'] : $objimport->array_import_convertvalue[0][$fieldname]['classfile']);
857  $class = $objimport->array_import_convertvalue[0][$fieldname]['class'];
858  $method = $objimport->array_import_convertvalue[0][$fieldname]['method'];
859  $type = $objimport->array_import_convertvalue[0][$fieldname]['type'];
860  $resultload = dol_include_once($file);
861  if (empty($resultload)) {
862  dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
863  break;
864  }
865  $classinstance = new $class($this->db);
866  $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, $key));
867  $fieldArr = explode('.', $fieldname);
868  if (count($fieldArr) > 0) {
869  $fieldname = $fieldArr[1];
870  }
871 
872  // Set $listfields and $listvalues
873  $listfields[] = $fieldname;
874  if ($type == 'int') {
875  $listvalues[] = (int) $res;
876  } elseif ($type == 'double') {
877  $listvalues[] = (float) $res;
878  } else {
879  $listvalues[] = "'".$this->db->escape($res)."'";
880  }
881  } else {
882  $this->errors[$error]['type'] = 'CLASSERROR';
883  $this->errors[$error]['lib'] = implode(
884  "\n",
885  array_merge([$classinstance->error], $classinstance->errors)
886  );
887  $errorforthistable++;
888  $error++;
889  }
890  }
891  } else {
892  $this->errors[$error]['lib'] = 'Bad value of profile setup ' . $val . ' for array_import_fieldshidden';
893  $this->errors[$error]['type'] = 'Import profile setup';
894  $error++;
895  }
896  }
897  }
898  //print 'listfields='.$listfields.'<br>listvalues='.$listvalues.'<br>';
899 
900  // If no error for this $alias/$tablename, we have a complete $listfields and $listvalues that are defined
901  // so we can try to make the insert or update now.
902  if (!$errorforthistable) {
903  //print "$alias/$tablename/$listfields/$listvalues<br>";
904  if (!empty($listfields)) {
905  $updatedone = false;
906  $insertdone = false;
907 
908  $is_table_category_link = false;
909  $fname = 'rowid';
910  if (strpos($tablename, '_categorie_') !== false) {
911  $is_table_category_link = true;
912  $fname = '*';
913  }
914 
915  if (!empty($updatekeys)) {
916  // We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
917 
918  if (empty($lastinsertid)) { // No insert done yet for a parent table
919  $sqlSelect = "SELECT ".$fname." FROM " . $tablename;
920 
921  $data = array_combine($listfields, $listvalues);
922 
923  $where = array(); // filters to forge SQL request
924  '@phan-var string[] $where';
925  $filters = array(); // filters to forge output error message
926  foreach ($updatekeys as $key) {
927  $col = $objimport->array_import_updatekeys[0][$key];
928  $key = preg_replace('/^.*\./i', '', $key);
929  if (isModEnabled("socialnetworks") && strpos($key, "socialnetworks") !== false) {
930  $tmp = explode("_", $key);
931  $key = $tmp[0];
932  $socialnetwork = $tmp[1];
933  $jsondata = $data[$key];
934  $json = json_decode($jsondata);
935  $stringtosearch = json_encode($socialnetwork).':'.json_encode($json->$socialnetwork);
936  //var_dump($stringtosearch);
937  //var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like)
938  $where[] = $key." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
939  $filters[] = $col." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
940  //var_dump($where[1]); // This provide a value for sql string inside a like
941  } else {
942  $where[] = $key.' = '.$data[$key];
943  $filters[] = $col.' = '.$data[$key];
944  }
945  }
946  if (!empty($tablewithentity_cache[$tablename])) {
947  $where[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
948  $filters[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
949  }
950  $sqlSelect .= " WHERE " . implode(' AND ', $where);
951 
952  $resql = $this->db->query($sqlSelect);
953  if ($resql) {
954  $num_rows = $this->db->num_rows($resql);
955  if ($num_rows == 1) {
956  $res = $this->db->fetch_object($resql);
957  $lastinsertid = $res->rowid;
958  if ($is_table_category_link) {
959  $lastinsertid = 'linktable';
960  } // used to apply update on tables like llx_categorie_product and avoid being blocked for all file content if at least one entry already exists
961  $last_insert_id_array[$tablename] = $lastinsertid;
962  } elseif ($num_rows > 1) {
963  $this->errors[$error]['lib'] = $langs->trans('MultipleRecordFoundWithTheseFilters', implode(', ', $filters));
964  $this->errors[$error]['type'] = 'SQL';
965  $error++;
966  } else {
967  // No record found with filters, insert will be tried below
968  }
969  } else {
970  //print 'E';
971  $this->errors[$error]['lib'] = $this->db->lasterror();
972  $this->errors[$error]['type'] = 'SQL';
973  $error++;
974  }
975  } else {
976  // We have a last INSERT ID (got by previous pass), so we check if we have a row referencing this foreign key.
977  // This is required when updating table with some extrafields. When inserting a record in parent table, we can make
978  // a direct insert into subtable extrafields, but when me wake an update, the insertid is defined and the child record
979  // may already exists. So we rescan the extrafield table to know if record exists or not for the rowid.
980  // Note: For extrafield tablename, we have in importfieldshidden_array an entry 'extra.fk_object'=>'lastrowid-tableparent' so $keyfield is 'fk_object'
981  $sqlSelect = "SELECT rowid FROM " . $tablename;
982 
983 
984  if (empty($keyfield)) {
985  $keyfield = 'rowid';
986  }
987  $sqlSelect .= " WHERE ".$keyfield." = ".((int) $lastinsertid);
988 
989  if (!empty($tablewithentity_cache[$tablename])) {
990  $sqlSelect .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
991  }
992 
993  $resql = $this->db->query($sqlSelect);
994  if ($resql) {
995  $res = $this->db->fetch_object($resql);
996  if ($this->db->num_rows($resql) == 1) {
997  // We have a row referencing this last foreign key, continue with UPDATE.
998  } else {
999  // No record found referencing this last foreign key,
1000  // force $lastinsertid to 0 so we INSERT below.
1001  $lastinsertid = 0;
1002  }
1003  } else {
1004  //print 'E';
1005  $this->errors[$error]['lib'] = $this->db->lasterror();
1006  $this->errors[$error]['type'] = 'SQL';
1007  $error++;
1008  }
1009  }
1010 
1011  if (!empty($lastinsertid)) {
1012  // We db escape social network field because he isn't in field creation
1013  if (in_array("socialnetworks", $listfields)) {
1014  $socialkey = array_search("socialnetworks", $listfields);
1015  $tmpsql = $listvalues[$socialkey];
1016  $listvalues[$socialkey] = "'".$this->db->escape($tmpsql)."'";
1017  }
1018 
1019  // Build SQL UPDATE request
1020  $sqlstart = "UPDATE " . $tablename;
1021 
1022  $data = array_combine($listfields, $listvalues);
1023  $set = array();
1024  foreach ($data as $key => $val) {
1025  $set[] = $key." = ".$val; // $val was escaped/sanitized previously
1026  }
1027  $sqlstart .= " SET " . implode(', ', $set) . ", import_key = '" . $this->db->escape($importid) . "'";
1028 
1029  if (empty($keyfield)) {
1030  $keyfield = 'rowid';
1031  }
1032  $sqlend = " WHERE " . $keyfield . " = ".((int) $lastinsertid);
1033 
1034  if ($is_table_category_link) {
1035  '@phan-var-force string[] $where';
1036  $sqlend = " WHERE " . implode(' AND ', $where);
1037  }
1038 
1039  if (!empty($tablewithentity_cache[$tablename])) {
1040  $sqlend .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
1041  }
1042 
1043  $sql = $sqlstart . $sqlend;
1044 
1045  // Run update request
1046  $resql = $this->db->query($sql);
1047  if ($resql) {
1048  // No error, update has been done. $this->db->db->affected_rows can be 0 if data hasn't changed
1049  $updatedone = true;
1050  } else {
1051  //print 'E';
1052  $this->errors[$error]['lib'] = $this->db->lasterror();
1053  $this->errors[$error]['type'] = 'SQL';
1054  $error++;
1055  }
1056  }
1057  }
1058 
1059  // Update not done, we do insert
1060  if (!$error && !$updatedone) {
1061  // We db escape social network field because he isn't in field creation
1062  if (in_array("socialnetworks", $listfields)) {
1063  $socialkey = array_search("socialnetworks", $listfields);
1064  $tmpsql = $listvalues[$socialkey];
1065  $listvalues[$socialkey] = "'".$this->db->escape($tmpsql)."'";
1066  }
1067 
1068  // Build SQL INSERT request
1069  $sqlstart = "INSERT INTO " . $tablename . "(" . implode(", ", $listfields) . ", import_key";
1070  $sqlend = ") VALUES(" . implode(', ', $listvalues) . ", '" . $this->db->escape($importid) . "'";
1071  if (!empty($tablewithentity_cache[$tablename])) {
1072  $sqlstart .= ", entity";
1073  $sqlend .= ", " . $conf->entity;
1074  }
1075  if (!empty($objimport->array_import_tables_creator[0][$alias])) {
1076  $sqlstart .= ", " . $objimport->array_import_tables_creator[0][$alias];
1077  $sqlend .= ", " . $user->id;
1078  }
1079  $sql = $sqlstart . $sqlend . ")";
1080  //dol_syslog("import_xlsx.modules", LOG_DEBUG);
1081 
1082  // Run insert request
1083  if ($sql) {
1084  $resql = $this->db->query($sql);
1085  if ($resql) {
1086  if (!$is_table_category_link) {
1087  $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).
1088  }
1089  $insertdone = true;
1090  } else {
1091  //print 'E';
1092  $this->errors[$error]['lib'] = $this->db->lasterror();
1093  $this->errors[$error]['type'] = 'SQL';
1094  $error++;
1095  }
1096  }
1097  }
1098  }
1099  /*else
1100  {
1101  dol_print_error(null,'ErrorFieldListEmptyFor '.$alias."/".$tablename);
1102  }*/
1103  }
1104 
1105  if ($error) {
1106  break;
1107  }
1108  }
1109 
1110  if ($updatedone) {
1111  $this->nbupdate++;
1112  }
1113  if ($insertdone) {
1114  $this->nbinsert++;
1115  }
1116  }
1117 
1118  return 1;
1119  }
1120 }
Class to import Excel files.
__construct($db, $datatoimport)
Constructor.
write_record_example($outputlangs, $contentlinevalues)
Output record of an example file for this format.
import_open_file($file)
Open input file.
import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
Insert a record into database.
write_footer_example($outputlangs)
Output footer of an example file for this format.
import_read_header()
Input header line from file.
write_header_example($outputlangs)
Output header of an example file for this format.
import_read_record()
Return array of next record in input file.
write_title_example($outputlangs, $headerlinefields)
Output title line of an example file for this format.
import_get_nb_of_lines($file)
Return nb of records.
import_close_file()
Close file handle.
Parent class for import file readers.
getElementFromTableWithPrefix($tableNameWithPrefix)
Get element from table name with prefix.
Class to manage third parties objects (customers, suppliers, prospects...)
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:744
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition: date.lib.php:426
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
num2Alpha($n)
Return a numeric value into an Excel like column number.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition: main.inc.php:90
div float
Buy price without taxes.
Definition: style.css.php:959