dolibarr  20.0.0-beta
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 
44  public $id;
45 
49  public $label;
50 
51  public $extension; // Extension of files imported by driver
52 
57  public $version = 'dolibarr';
58 
59  public $label_lib; // Label of external lib used by driver
60 
61  public $version_lib; // Version of external lib used by driver
62 
63  public $separator;
64 
65  public $file; // Path of file
66 
67  public $handle; // Handle fichier
68 
69  public $cacheconvert = array(); // Array to cache list of value found after a conversion
70 
71  public $cachefieldtable = array(); // Array to cache list of value found into fields@tables
72 
73  public $nbinsert = 0; // # of insert done during the import
74 
75  public $nbupdate = 0; // # of update done during the import
76 
77  public $charset = '';
78 
79  public $col;
80 
81 
88  public function __construct($db, $datatoimport)
89  {
90  global $conf, $langs;
91 
92  parent::__construct();
93  $this->db = $db;
94 
95  $this->separator = (GETPOST('separator') ? GETPOST('separator') : (!getDolGlobalString('IMPORT_CSV_SEPARATOR_TO_USE') ? ',' : $conf->global->IMPORT_CSV_SEPARATOR_TO_USE));
96  $this->enclosure = '"';
97  $this->escape = '"';
98 
99  $this->id = 'csv'; // Same value then xxx in file name export_xxx.modules.php
100  $this->label = 'Csv'; // Label of driver
101  $this->desc = $langs->trans("CSVFormatDesc", $this->separator, $this->enclosure, $this->escape);
102  $this->extension = 'csv'; // Extension for generated file by this driver
103  $this->picto = 'mime/other'; // Picto
104  $this->version = '1.34'; // Driver version
105 
106  // If driver use an external library, put its name here
107  $this->label_lib = 'Dolibarr';
108  $this->version_lib = DOL_VERSION;
109 
110  $this->datatoimport = $datatoimport;
111  if (preg_match('/^societe_/', $datatoimport)) {
112  $this->thirdpartyobject = new Societe($this->db);
113  }
114  }
115 
116 
117  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
124  public function write_header_example($outputlangs)
125  {
126  // phpcs:enable
127  return '';
128  }
129 
130  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
138  public function write_title_example($outputlangs, $headerlinefields)
139  {
140  // phpcs:enable
141  $s = implode($this->separator, array_map('cleansep', $headerlinefields));
142  return $s."\n";
143  }
144 
145  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
153  public function write_record_example($outputlangs, $contentlinevalues)
154  {
155  // phpcs:enable
156  $s = implode($this->separator, array_map('cleansep', $contentlinevalues));
157  return $s."\n";
158  }
159 
160  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
167  public function write_footer_example($outputlangs)
168  {
169  // phpcs:enable
170  return '';
171  }
172 
173 
174  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
181  public function import_open_file($file)
182  {
183  // phpcs:enable
184  global $langs;
185  $ret = 1;
186 
187  dol_syslog(get_class($this)."::open_file file=".$file);
188 
189  ini_set('auto_detect_line_endings', 1); // For MAC compatibility
190 
191  $this->handle = fopen(dol_osencode($file), "r");
192  if (!$this->handle) {
193  $langs->load("errors");
194  $this->error = $langs->trans("ErrorFailToOpenFile", $file);
195  $ret = -1;
196  } else {
197  $this->file = $file;
198  }
199 
200  return $ret;
201  }
202 
203 
204  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
211  public function import_get_nb_of_lines($file)
212  {
213  // phpcs:enable
214  return dol_count_nb_of_line($file);
215  }
216 
217 
218  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
224  public function import_read_header()
225  {
226  // phpcs:enable
227  return 0;
228  }
229 
230 
231  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
237  public function import_read_record()
238  {
239  // phpcs:enable
240  global $conf;
241 
242  $arrayres = fgetcsv($this->handle, 100000, $this->separator, $this->enclosure, $this->escape);
243 
244  // End of file
245  if ($arrayres === false) {
246  return false;
247  }
248 
249  //var_dump($this->handle);
250  //var_dump($arrayres);exit;
251  $newarrayres = array();
252  if ($arrayres && is_array($arrayres)) {
253  foreach ($arrayres as $key => $val) {
254  if (getDolGlobalString('IMPORT_CSV_FORCE_CHARSET')) { // Forced charset
255  if (strtolower($conf->global->IMPORT_CSV_FORCE_CHARSET) == 'utf8') {
256  $newarrayres[$key]['val'] = $val;
257  $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we consider it's null
258  } else {
259  $newarrayres[$key]['val'] = mb_convert_encoding($val, 'UTF-8', 'ISO-8859-1');
260  $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we consider it's null
261  }
262  } else { // Autodetect format (UTF8 or ISO)
263  if (utf8_check($val)) {
264  $newarrayres[$key]['val'] = $val;
265  $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we consider it's null
266  } else {
267  $newarrayres[$key]['val'] = mb_convert_encoding($val, 'UTF-8', 'ISO-8859-1');
268  $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we consider it's null
269  }
270  }
271  }
272 
273  $this->col = count($newarrayres);
274  }
275 
276  return $newarrayres;
277  }
278 
279  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
285  public function import_close_file()
286  {
287  // phpcs:enable
288  fclose($this->handle);
289  return 0;
290  }
291 
292 
293  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
305  public function import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
306  {
307  // phpcs:enable
308  global $langs, $conf, $user;
309  global $thirdparty_static; // Specific to thirdparty import
310  global $tablewithentity_cache; // Cache to avoid to call desc at each rows on tables
311 
312  $error = 0;
313  $warning = 0;
314  $this->errors = array();
315  $this->warnings = array();
316 
317  //dol_syslog("import_csv.modules maxfields=".$maxfields." importid=".$importid);
318 
319  //var_dump($array_match_file_to_database);
320  //var_dump($arrayrecord); exit;
321 
322  $array_match_database_to_file = array_flip($array_match_file_to_database);
323  $sort_array_match_file_to_database = $array_match_file_to_database;
324  ksort($sort_array_match_file_to_database);
325 
326  //var_dump($sort_array_match_file_to_database);
327 
328  if (count($arrayrecord) == 0 || (count($arrayrecord) == 1 && empty($arrayrecord[0]['val']))) {
329  //print 'W';
330  $this->warnings[$warning]['lib'] = $langs->trans('EmptyLine');
331  $this->warnings[$warning]['type'] = 'EMPTY';
332  $warning++;
333  } else {
334  $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)
335  $updatedone = false;
336  $insertdone = false;
337  // For each table to insert, me make a separate insert
338  foreach ($objimport->array_import_tables[0] as $alias => $tablename) {
339  // Build sql request
340  $sql = '';
341  $listfields = array();
342  $listvalues = array();
343  $i = 0;
344  $errorforthistable = 0;
345 
346  // Define $tablewithentity_cache[$tablename] if not already defined
347  if (!isset($tablewithentity_cache[$tablename])) { // keep this test with "isset"
348  dol_syslog("Check if table ".$tablename." has an entity field");
349  $resql = $this->db->DDLDescTable($tablename, 'entity');
350  if ($resql) {
351  $obj = $this->db->fetch_object($resql);
352  if ($obj) {
353  $tablewithentity_cache[$tablename] = 1; // table contains entity field
354  } else {
355  $tablewithentity_cache[$tablename] = 0; // table does not contain entity field
356  }
357  } else {
358  dol_print_error($this->db);
359  }
360  } else {
361  //dol_syslog("Table ".$tablename." check for entity into cache is ".$tablewithentity_cache[$tablename]);
362  }
363 
364  // Define array to convert fields ('c.ref', ...) into column index (1, ...)
365  $arrayfield = array();
366  foreach ($sort_array_match_file_to_database as $key => $val) {
367  $arrayfield[$val] = ($key - 1);
368  }
369 
370  // $arrayrecord start at key 0
371  // $sort_array_match_file_to_database start at key 1
372 
373  // Loop on each fields in the match array: $key = 1..n, $val=alias of field (s.nom)
374  foreach ($sort_array_match_file_to_database as $key => $val) {
375  $fieldalias = preg_replace('/\..*$/i', '', $val);
376  $fieldname = preg_replace('/^.*\./i', '', $val);
377 
378  if ($alias != $fieldalias) {
379  continue; // Not a field of current table
380  }
381 
382  if ($key <= $maxfields) {
383  // Set $newval with value to insert and set $listvalues with sql request part for insert
384  $newval = '';
385  if ($arrayrecord[($key - 1)]['type'] > 0) {
386  $newval = $arrayrecord[($key - 1)]['val']; // If type of field into input file is not empty string (so defined into input file), we get value
387  }
388 
389  //var_dump($newval);var_dump($val);
390  //var_dump($objimport->array_import_convertvalue[0][$val]);
391 
392  // Make some tests on $newval
393 
394  // Is it a required field ?
395  if (preg_match('/\*/', $objimport->array_import_fields[0][$val]) && ((string) $newval == '')) {
396  // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
397  $this->errors[$error]['lib'] = $langs->trans('ErrorMissingMandatoryValue', $key);
398  $this->errors[$error]['type'] = 'NOTNULL';
399  $errorforthistable++;
400  $error++;
401  } else {
402  // Test format only if field is not a missing mandatory field (field may be a value or empty but not mandatory)
403  // We convert field if required
404  if (!empty($objimport->array_import_convertvalue[0][$val])) {
405  //print 'Must convert '.$newval.' with rule '.join(',',$objimport->array_import_convertvalue[0][$val]).'. ';
406  if ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeid'
407  || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromref'
408  || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel'
409  ) {
410  // 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.
411  $isidorref = 'id';
412  if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
413  $isidorref = 'ref';
414  }
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 'Newval 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  $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval];
425  } else {
426  $resultload = dol_include_once($file);
427  if (empty($resultload)) {
428  dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method);
429  break;
430  }
431  $classinstance = new $class($this->db);
432  if ($class == 'CGenericDic') {
433  $classinstance->element = $objimport->array_import_convertvalue[0][$val]['element'];
434  $classinstance->table_element = $objimport->array_import_convertvalue[0][$val]['table_element'];
435  }
436 
437  // Try the fetch from code or ref
438  $param_array = array('', $newval);
439  if ($class == 'AccountingAccount') {
440  //var_dump($arrayrecord[0]['val']);
441  /*include_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancysystem.class.php';
442  $tmpchartofaccount = new AccountancySystem($this->db);
443  $tmpchartofaccount->fetch(getDolGlobalInt('CHARTOFACCOUNTS'));
444  //var_dump($tmpchartofaccount->ref.' - '.$arrayrecord[0]['val']);
445  if ((! (getDolGlobalInt('CHARTOFACCOUNTS') > 0)) || $tmpchartofaccount->ref != $arrayrecord[0]['val'])
446  {
447  $this->errors[$error]['lib']=$langs->trans('ErrorImportOfChartLimitedToCurrentChart', $tmpchartofaccount->ref);
448  $this->errors[$error]['type']='RESTRICTONCURRENCTCHART';
449  $errorforthistable++;
450  $error++;
451  }*/
452  $param_array = array('', $newval, 0, $arrayrecord[0]['val']); // Param to fetch parent from account, in chart.
453  }
454  if ($class == 'CActionComm') {
455  $param_array = array($newval); // CActionComm fetch method have same parameter for id and code
456  }
457  $result = call_user_func_array(array($classinstance, $method), $param_array);
458 
459  // If duplicate record found
460  if (!($classinstance->id != '') && $result == -2) {
461  $this->errors[$error]['lib'] = $langs->trans('ErrorMultipleRecordFoundFromRef', $newval);
462  $this->errors[$error]['type'] = 'FOREIGNKEY';
463  $errorforthistable++;
464  $error++;
465  }
466 
467  // If not found, try the fetch from label
468  if (!($classinstance->id != '') && $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel') {
469  $param_array = array('', '', $newval);
470  call_user_func_array(array($classinstance, $method), $param_array);
471  }
472  $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval] = $classinstance->id;
473 
474  //print 'We have made a '.$class.'->'.$method.' to get id from code '.$newval.'. ';
475  if ($classinstance->id != '') { // id may be 0, it is a found value
476  $newval = $classinstance->id;
477  } elseif (! $error) {
478  if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
479  $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
480  } elseif (!empty($objimport->array_import_convertvalue[0][$val]['element'])) {
481  $this->errors[$error]['lib'] = $langs->trans('ErrorFieldRefNotIn', num2Alpha($key - 1), $newval, $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['element']));
482  } else {
483  $this->errors[$error]['lib'] = 'ErrorBadDefinitionOfImportProfile';
484  }
485  $this->errors[$error]['type'] = 'FOREIGNKEY';
486  $errorforthistable++;
487  $error++;
488  }
489  }
490  }
491  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeandlabel') {
492  $isidorref = 'id';
493  if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
494  $isidorref = 'ref';
495  }
496  $newval = preg_replace('/^(id|ref):/i', '', $newval);
497 
498  if ($isidorref == 'ref') {
499  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
500  $class = $objimport->array_import_convertvalue[0][$val]['class'];
501  $method = $objimport->array_import_convertvalue[0][$val]['method'];
502  $codefromfield = $objimport->array_import_convertvalue[0][$val]['codefromfield'];
503  $code = $arrayrecord[$arrayfield[$codefromfield]]['val'];
504  if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval] != '') {
505  $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval];
506  } else {
507  $resultload = dol_include_once($file);
508  if (empty($resultload)) {
509  dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method.', code='.$code);
510  break;
511  }
512  $classinstance = new $class($this->db);
513  // Try the fetch from code and ref
514  $param_array = array('', $newval, $code);
515  call_user_func_array(array($classinstance, $method), $param_array);
516  $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval] = $classinstance->id;
517  if ($classinstance->id > 0) { // we found record
518  $newval = $classinstance->id;
519  } else {
520  if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
521  $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
522  } else {
523  $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
524  }
525  $this->errors[$error]['type'] = 'FOREIGNKEY';
526  $errorforthistable++;
527  $error++;
528  }
529  }
530  }
531  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'zeroifnull') {
532  if (empty($newval)) {
533  $newval = '0';
534  }
535  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits' || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchscalefromcodeunits') {
536  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
537  $class = $objimport->array_import_convertvalue[0][$val]['class'];
538  $method = $objimport->array_import_convertvalue[0][$val]['method'];
539  $units = $objimport->array_import_convertvalue[0][$val]['units'];
540  if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval] != '') {
541  $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval];
542  } else {
543  $resultload = dol_include_once($file);
544  if (empty($resultload)) {
545  dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method.', units='.$units);
546  break;
547  }
548  $classinstance = new $class($this->db);
549  // Try the fetch from code or ref
550  call_user_func_array(array($classinstance, $method), array('', '', $newval, $units));
551  $scaleorid = (($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits') ? $classinstance->id : $classinstance->scale);
552  $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval] = $scaleorid;
553  //print 'We have made a '.$class.'->'.$method." to get a value from key '".$newval."' and we got '".$scaleorid."'.";exit;
554  if ($classinstance->id > 0) { // we found record
555  $newval = $scaleorid ? $scaleorid : 0;
556  } else {
557  if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
558  $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
559  } else {
560  $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
561  }
562  $this->errors[$error]['type'] = 'FOREIGNKEY';
563  $errorforthistable++;
564  $error++;
565  }
566  }
567  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomercodeifauto') {
568  if (strtolower($newval) == 'auto') {
569  $this->thirdpartyobject->get_codeclient(0, 0);
570  $newval = $this->thirdpartyobject->code_client;
571  //print 'code_client='.$newval;
572  }
573  if (empty($newval)) {
574  $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
575  }
576  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsuppliercodeifauto') {
577  if (strtolower($newval) == 'auto') {
578  $this->thirdpartyobject->get_codefournisseur(0, 1);
579  $newval = $this->thirdpartyobject->code_fournisseur;
580  //print 'code_fournisseur='.$newval;
581  }
582  if (empty($newval)) {
583  $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
584  }
585  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomeraccountancycodeifauto') {
586  if (strtolower($newval) == 'auto') {
587  $this->thirdpartyobject->get_codecompta('customer');
588  $newval = $this->thirdpartyobject->code_compta;
589  //print 'code_compta='.$newval;
590  }
591  if (empty($newval)) {
592  $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
593  }
594  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsupplieraccountancycodeifauto') {
595  if (strtolower($newval) == 'auto') {
596  $this->thirdpartyobject->get_codecompta('supplier');
597  $newval = $this->thirdpartyobject->code_compta_fournisseur;
598  if (empty($newval)) {
599  $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
600  }
601  //print 'code_compta_fournisseur='.$newval;
602  }
603  if (empty($newval)) {
604  $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
605  }
606  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getrefifauto') {
607  if (strtolower($newval) == 'auto') {
608  $defaultref = '';
609 
610  $classModForNumber = $objimport->array_import_convertvalue[0][$val]['class'];
611  $pathModForNumber = $objimport->array_import_convertvalue[0][$val]['path'];
612 
613  if (!empty($classModForNumber) && !empty($pathModForNumber) && is_readable(DOL_DOCUMENT_ROOT.$pathModForNumber)) {
614  require_once DOL_DOCUMENT_ROOT.$pathModForNumber;
615  $modForNumber = new $classModForNumber();
616 
617  $tmpobject = null;
618  // Set the object with the date property when we can
619  if (!empty($objimport->array_import_convertvalue[0][$val]['classobject'])) {
620  $pathForObject = $objimport->array_import_convertvalue[0][$val]['pathobject'];
621  require_once DOL_DOCUMENT_ROOT.$pathForObject;
622  $tmpclassobject = $objimport->array_import_convertvalue[0][$val]['classobject'];
623  $tmpobject = new $tmpclassobject($this->db);
624  foreach ($arrayfield as $tmpkey => $tmpval) { // $arrayfield is array('c.ref'=>0, ...)
625  if (in_array($tmpkey, array('t.date', 'c.date_commande'))) {
626  $tmpobject->date = dol_stringtotime($arrayrecord[$arrayfield[$tmpkey]]['val'], 1);
627  }
628  }
629  }
630 
631  $defaultref = $modForNumber->getNextValue(null, $tmpobject);
632  }
633  if (is_numeric($defaultref) && $defaultref <= 0) { // If error
634  $defaultref = '';
635  }
636  $newval = $defaultref;
637  }
638  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'compute') {
639  $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
640  $class = $objimport->array_import_convertvalue[0][$val]['class'];
641  $method = $objimport->array_import_convertvalue[0][$val]['method'];
642  $resultload = dol_include_once($file);
643  if (empty($resultload)) {
644  dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method);
645  break;
646  }
647  $classinstance = new $class($this->db);
648  $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, ($key - 1)));
649  if (empty($classinstance->error) && empty($classinstance->errors)) {
650  $newval = $res; // We get new value computed.
651  } else {
652  $this->errors[$error]['type'] = 'CLASSERROR';
653  $this->errors[$error]['lib'] = implode(
654  "\n",
655  array_merge([$classinstance->error], $classinstance->errors)
656  );
657  $errorforthistable++;
658  $error++;
659  }
660  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'numeric') {
661  $newval = price2num($newval);
662  } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'accountingaccount') {
663  if (!getDolGlobalString('ACCOUNTING_MANAGE_ZERO')) {
664  $newval = rtrim(trim($newval), "0");
665  } else {
666  $newval = trim($newval);
667  }
668  }
669 
670  //print 'Val to use as insert is '.$newval.'<br>';
671  }
672 
673  // Test regexp
674  if (!empty($objimport->array_import_regex[0][$val]) && ($newval != '')) {
675  // If test regex string is "field@table" or "field@table:..." (means must exists into table ...)
676  $reg = array();
677  if (preg_match('/^(.+)@([^:]+)(:.+)?$/', $objimport->array_import_regex[0][$val], $reg)) {
678  $field = $reg[1];
679  $table = $reg[2];
680  $filter = !empty($reg[3]) ? substr($reg[3], 1) : '';
681 
682  $cachekey = $field.'@'.$table;
683  if (!empty($filter)) {
684  $cachekey .= ':'.$filter;
685  }
686 
687  // Load content of field@table into cache array
688  if (!is_array($this->cachefieldtable[$cachekey])) { // If content of field@table not already loaded into cache
689  $sql = "SELECT ".$field." as aliasfield FROM ".$table;
690  if (!empty($filter)) {
691  $sql .= ' WHERE '.$filter;
692  }
693 
694  $resql = $this->db->query($sql);
695  if ($resql) {
696  $num = $this->db->num_rows($resql);
697  $i = 0;
698  while ($i < $num) {
699  $obj = $this->db->fetch_object($resql);
700  if ($obj) {
701  $this->cachefieldtable[$cachekey][] = $obj->aliasfield;
702  }
703  $i++;
704  }
705  } else {
706  dol_print_error($this->db);
707  }
708  }
709 
710  // Now we check cache is not empty (should not) and key is into cache
711  if (!is_array($this->cachefieldtable[$cachekey]) || !in_array($newval, $this->cachefieldtable[$cachekey])) {
712  $tableforerror = $table;
713  if (!empty($filter)) {
714  $tableforerror .= ':'.$filter;
715  }
716  $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, $field, $tableforerror);
717  $this->errors[$error]['type'] = 'FOREIGNKEY';
718  $errorforthistable++;
719  $error++;
720  }
721  } elseif (!preg_match('/'.$objimport->array_import_regex[0][$val].'/i', $newval)) {
722  // If test is just a static regex
723  //if ($key == 19) print "xxx".$newval."zzz".$objimport->array_import_regex[0][$val]."<br>";
724  $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorWrongValueForField', num2Alpha($key - 1), $newval, $objimport->array_import_regex[0][$val]);
725  $this->errors[$error]['type'] = 'REGEX';
726  $errorforthistable++;
727  $error++;
728  }
729  }
730 
731  // Check HTML injection
732  $inj = testSqlAndScriptInject($newval, 0);
733  if ($inj) {
734  $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorHtmlInjectionForField', num2Alpha($key - 1), dol_trunc($newval, 100));
735  $this->errors[$error]['type'] = 'HTMLINJECTION';
736  $errorforthistable++;
737  $error++;
738  }
739 
740  // Other tests
741  // ...
742  }
743 
744  // Define $listfields and $listvalues to build the SQL request
745  if (isModEnabled("socialnetworks") && strpos($fieldname, "socialnetworks") !== false) {
746  if (!in_array("socialnetworks", $listfields)) {
747  $listfields[] = "socialnetworks";
748  $socialkey = array_search("socialnetworks", $listfields); // Return position of 'socialnetworks' key in array
749  $listvalues[$socialkey] = '';
750  }
751  //var_dump($newval); var_dump($arrayrecord[($key - 1)]['type']);
752  if (!empty($newval) && $arrayrecord[($key - 1)]['type'] > 0) {
753  $socialkey = array_search("socialnetworks", $listfields); // Return position of 'socialnetworks' key in array
754  //var_dump('sk='.$socialkey); // socialkey=19
755  $socialnetwork = explode("_", $fieldname)[1];
756  if (empty($listvalues[$socialkey]) || $listvalues[$socialkey] == "null") {
757  $json = new stdClass();
758  $json->$socialnetwork = $newval;
759  $listvalues[$socialkey] = json_encode($json);
760  } else {
761  $jsondata = $listvalues[$socialkey];
762  $json = json_decode($jsondata);
763  $json->$socialnetwork = $newval;
764  $listvalues[$socialkey] = json_encode($json);
765  }
766  }
767  } else {
768  $listfields[] = $fieldname;
769  // Note: arrayrecord (and 'type') is filled with ->import_read_record called by import.php page before calling import_insert
770  if (empty($newval) && $arrayrecord[($key - 1)]['type'] < 0) {
771  $listvalues[] = ($newval == '0' ? (int) $newval : "null");
772  } elseif (empty($newval) && $arrayrecord[($key - 1)]['type'] == 0) {
773  $listvalues[] = "''";
774  } else {
775  $listvalues[] = "'".$this->db->escape($newval)."'";
776  }
777  }
778  }
779  $i++;
780  }
781 
782  // We add hidden fields (but only if there is at least one field to add into table)
783  // We process here all the fields that were declared into the array $this->import_fieldshidden_array of the descriptor file.
784  // Previously we processed the ->import_fields_array.
785  if (!empty($listfields) && is_array($objimport->array_import_fieldshidden[0])) {
786  // Loop on each hidden fields to add them into listfields/listvalues
787  foreach ($objimport->array_import_fieldshidden[0] as $tmpkey => $tmpval) {
788  if (!preg_match('/^' . preg_quote($alias, '/') . '\./', $tmpkey)) {
789  continue; // Not a field of current table
790  }
791  $keyfield = preg_replace('/^' . preg_quote($alias, '/') . '\./', '', $tmpkey);
792 
793  if (in_array($keyfield, $listfields)) { // avoid duplicates in insert
794  continue;
795  } elseif ($tmpval == 'user->id') {
796  $listfields[] = $keyfield;
797  $listvalues[] = ((int) $user->id);
798  } elseif (preg_match('/^lastrowid-/', $tmpval)) {
799  $tmp = explode('-', $tmpval);
800  $lastinsertid = (isset($last_insert_id_array[$tmp[1]])) ? $last_insert_id_array[$tmp[1]] : 0;
801  $listfields[] = $keyfield;
802  $listvalues[] = (int) $lastinsertid;
803  //print $tmpkey."-".$tmpval."-".$listfields."-".$listvalues."<br>";exit;
804  } elseif (preg_match('/^const-/', $tmpval)) {
805  $tmp = explode('-', $tmpval, 2);
806  $listfields[] = $keyfield;
807  $listvalues[] = "'".$this->db->escape($tmp[1])."'";
808  } elseif (preg_match('/^rule-/', $tmpval)) {
809  $fieldname = $tmpkey;
810  if (!empty($objimport->array_import_convertvalue[0][$fieldname])) {
811  if ($objimport->array_import_convertvalue[0][$fieldname]['rule'] == 'compute') {
812  $file = (empty($objimport->array_import_convertvalue[0][$fieldname]['classfile']) ? $objimport->array_import_convertvalue[0][$fieldname]['file'] : $objimport->array_import_convertvalue[0][$fieldname]['classfile']);
813  $class = $objimport->array_import_convertvalue[0][$fieldname]['class'];
814  $method = $objimport->array_import_convertvalue[0][$fieldname]['method'];
815  $type = $objimport->array_import_convertvalue[0][$fieldname]['type'];
816  $resultload = dol_include_once($file);
817  if (empty($resultload)) {
818  dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
819  break;
820  }
821  $classinstance = new $class($this->db);
822  $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, ($key - 1)));
823  if (empty($classinstance->error) && empty($classinstance->errors)) {
824  $fieldArr = explode('.', $fieldname);
825  if (count($fieldArr) > 0) {
826  $fieldname = $fieldArr[1];
827  }
828 
829  // Set $listfields and $listvalues
830  $listfields[] = $fieldname;
831  if ($type == 'int') {
832  $listvalues[] = (int) $res;
833  } elseif ($type == 'double') {
834  $listvalues[] = (float) $res;
835  } else {
836  $listvalues[] = "'".$this->db->escape($res)."'";
837  }
838  } else {
839  $this->errors[$error]['type'] = 'CLASSERROR';
840  $this->errors[$error]['lib'] = implode(
841  "\n",
842  array_merge([$classinstance->error], $classinstance->errors)
843  );
844  $errorforthistable++;
845  $error++;
846  }
847  }
848  }
849  } else {
850  $this->errors[$error]['lib'] = 'Bad value of profile setup '.$tmpval.' for array_import_fieldshidden';
851  $this->errors[$error]['type'] = 'Import profile setup';
852  $error++;
853  }
854  }
855  }
856  //print 'listfields='.$listfields.'<br>listvalues='.$listvalues.'<br>';
857 
858  // If no error for this $alias/$tablename, we have a complete $listfields and $listvalues that are defined
859  // so we can try to make the insert or update now.
860  if (!$errorforthistable) {
861  //print "$alias/$tablename/$listfields/$listvalues<br>";
862  if (!empty($listfields)) {
863  $updatedone = false;
864  $insertdone = false;
865 
866  $is_table_category_link = false;
867  $fname = 'rowid';
868  if (strpos($tablename, '_categorie_') !== false) {
869  $is_table_category_link = true;
870  $fname = '*';
871  }
872 
873  if (!empty($updatekeys)) {
874  // We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
875 
876  if (empty($lastinsertid)) { // No insert done yet for a parent table
877  $sqlSelect = "SELECT ".$fname." FROM ".$tablename;
878  $data = array_combine($listfields, $listvalues);
879  $where = array(); // filters to forge SQL request
880  $filters = array(); // filters to forge output error message
881  foreach ($updatekeys as $key) {
882  $col = $objimport->array_import_updatekeys[0][$key];
883  $key = preg_replace('/^.*\./i', '', $key);
884  if (isModEnabled("socialnetworks") && strpos($key, "socialnetworks") !== false) {
885  $tmp = explode("_", $key);
886  $key = $tmp[0];
887  $socialnetwork = $tmp[1];
888  $jsondata = $data[$key];
889  $json = json_decode($jsondata);
890  $stringtosearch = json_encode($socialnetwork).':'.json_encode($json->$socialnetwork);
891  //var_dump($stringtosearch);
892  //var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like)
893  $where[] = $key." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
894  $filters[] = $col." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
895  //var_dump($where[1]); // This provide a value for sql string inside a like
896  } else {
897  $where[] = $key.' = '.$data[$key];
898  $filters[] = $col.' = '.$data[$key];
899  }
900  }
901  if (!empty($tablewithentity_cache[$tablename])) {
902  $where[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
903  $filters[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
904  }
905  $sqlSelect .= " WHERE ".implode(' AND ', $where);
906 
907  $resql = $this->db->query($sqlSelect);
908  if ($resql) {
909  $num_rows = $this->db->num_rows($resql);
910  if ($num_rows == 1) {
911  $res = $this->db->fetch_object($resql);
912  $lastinsertid = $res->rowid;
913  if ($is_table_category_link) {
914  $lastinsertid = 'linktable';
915  } // 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
916  $last_insert_id_array[$tablename] = $lastinsertid;
917  } elseif ($num_rows > 1) {
918  $this->errors[$error]['lib'] = $langs->trans('MultipleRecordFoundWithTheseFilters', implode(', ', $filters));
919  $this->errors[$error]['type'] = 'SQL';
920  $error++;
921  } else {
922  // No record found with filters, insert will be tried below
923  }
924  } else {
925  //print 'E';
926  $this->errors[$error]['lib'] = $this->db->lasterror();
927  $this->errors[$error]['type'] = 'SQL';
928  $error++;
929  }
930  } else {
931  // We have a last INSERT ID (got by previous pass), so we check if we have a row referencing this foreign key.
932  // This is required when updating table with some extrafields. When inserting a record in parent table, we can make
933  // a direct insert into subtable extrafields, but when me wake an update, the insertid is defined and the child record
934  // may already exists. So we rescan the extrafield table to know if record exists or not for the rowid.
935  // Note: For extrafield tablename, we have in importfieldshidden_array an entry 'extra.fk_object'=>'lastrowid-tableparent' so $keyfield is 'fk_object'
936  $sqlSelect = "SELECT rowid FROM ".$tablename;
937 
938  if (empty($keyfield)) {
939  $keyfield = 'rowid';
940  }
941  $sqlSelect .= " WHERE ".$keyfield." = ".((int) $lastinsertid);
942 
943  if (!empty($tablewithentity_cache[$tablename])) {
944  $sqlSelect .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
945  }
946 
947  $resql = $this->db->query($sqlSelect);
948  if ($resql) {
949  $res = $this->db->fetch_object($resql);
950  if ($this->db->num_rows($resql) == 1) {
951  // We have a row referencing this last foreign key, continue with UPDATE.
952  } else {
953  // No record found referencing this last foreign key,
954  // force $lastinsertid to 0 so we INSERT below.
955  $lastinsertid = 0;
956  }
957  } else {
958  //print 'E';
959  $this->errors[$error]['lib'] = $this->db->lasterror();
960  $this->errors[$error]['type'] = 'SQL';
961  $error++;
962  }
963  }
964 
965  if (!empty($lastinsertid)) {
966  // We db escape social network field because he isn't in field creation
967  if (in_array("socialnetworks", $listfields)) {
968  $socialkey = array_search("socialnetworks", $listfields);
969  $tmpsql = $listvalues[$socialkey];
970  $listvalues[$socialkey] = "'".$this->db->escape($tmpsql)."'";
971  }
972 
973  // Build SQL UPDATE request
974  $sqlstart = "UPDATE ".$tablename;
975 
976  $data = array_combine($listfields, $listvalues);
977  $set = array();
978  foreach ($data as $key => $val) {
979  $set[] = $key." = ".$val; // $val was escaped/sanitized previously
980  }
981  $sqlstart .= " SET ".implode(', ', $set).", import_key = '".$this->db->escape($importid)."'";
982 
983  if (empty($keyfield)) {
984  $keyfield = 'rowid';
985  }
986  $sqlend = " WHERE ".$keyfield." = ".((int) $lastinsertid);
987 
988  if ($is_table_category_link) {
989  '@phan-var-force string[] $where';
990  $sqlend = " WHERE " . implode(' AND ', $where);
991  }
992 
993  if (!empty($tablewithentity_cache[$tablename])) {
994  $sqlend .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
995  }
996 
997  $sql = $sqlstart.$sqlend;
998 
999  // Run update request
1000  $resql = $this->db->query($sql);
1001  if ($resql) {
1002  // No error, update has been done. $this->db->db->affected_rows can be 0 if data hasn't changed
1003  $updatedone = true;
1004  } else {
1005  //print 'E';
1006  $this->errors[$error]['lib'] = $this->db->lasterror();
1007  $this->errors[$error]['type'] = 'SQL';
1008  $error++;
1009  }
1010  }
1011  }
1012 
1013  // Update not done, we do insert
1014  if (!$error && !$updatedone) {
1015  // We db escape social network field because he isn't in field creation
1016  if (in_array("socialnetworks", $listfields)) {
1017  $socialkey = array_search("socialnetworks", $listfields);
1018  $tmpsql = $listvalues[$socialkey];
1019  $listvalues[$socialkey] = "'".$this->db->escape($tmpsql)."'";
1020  }
1021 
1022  // Build SQL INSERT request
1023  $sqlstart = "INSERT INTO ".$tablename."(".implode(", ", $listfields).", import_key";
1024  $sqlend = ") VALUES(".implode(', ', $listvalues).", '".$this->db->escape($importid)."'";
1025  if (!empty($tablewithentity_cache[$tablename])) {
1026  $sqlstart .= ", entity";
1027  $sqlend .= ", ".$conf->entity;
1028  }
1029  if (!empty($objimport->array_import_tables_creator[0][$alias])) {
1030  $sqlstart .= ", ".$objimport->array_import_tables_creator[0][$alias];
1031  $sqlend .= ", ".$user->id;
1032  }
1033  $sql = $sqlstart.$sqlend.")";
1034  //dol_syslog("import_csv.modules", LOG_DEBUG);
1035 
1036  // Run insert request
1037  if ($sql) {
1038  $resql = $this->db->query($sql);
1039  if ($resql) {
1040  if (!$is_table_category_link) {
1041  $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).
1042  }
1043  $insertdone = true;
1044  } else {
1045  //print 'E';
1046  $this->errors[$error]['lib'] = $this->db->lasterror();
1047  $this->errors[$error]['type'] = 'SQL';
1048  $error++;
1049  }
1050  }
1051  }
1052  }
1053  /*else
1054  {
1055  dol_print_error(null,'ErrorFieldListEmptyFor '.$alias."/".$tablename);
1056  }*/
1057  }
1058 
1059  if ($error) {
1060  break;
1061  }
1062  }
1063 
1064  if ($updatedone) {
1065  $this->nbupdate++;
1066  }
1067  if ($insertdone) {
1068  $this->nbinsert++;
1069  }
1070  }
1071 
1072  return 1;
1073  }
1074 }
1075 
1082 function cleansep($value)
1083 {
1084  return str_replace(array(',', ';'), '/', $value);
1085 }
Class to import CSV files.
write_header_example($outputlangs)
Output header of an example file for this format.
import_get_nb_of_lines($file)
Return nb of records.
import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
Insert a record into database.
__construct($db, $datatoimport)
Constructor.
import_read_record()
Return array of next record in input file.
write_record_example($outputlangs, $contentlinevalues)
Output record of an example file for this format.
write_footer_example($outputlangs)
Output footer of an example file for this format.
import_close_file()
Close file handle.
import_read_header()
Input header line from file.
write_title_example($outputlangs, $headerlinefields)
Output title line of an example file for this format.
import_open_file($file)
Open input file.
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:745
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:427
dol_count_nb_of_line($file)
Count number of lines in a file.
Definition: files.lib.php:602
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
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.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
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.
utf8_check($str)
Check if a string is in UTF8.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
cleansep($value)
Clean a string from separator.
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition: main.inc.php:123
div float
Buy price without taxes.
Definition: style.css.php:960