dolibarr  19.0.0-dev
import.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2005-2016 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
4  * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
5  * Copyright (C) 2022 Charlene Benke <charlene@patas-monkey.com>
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  */
20 
27 require_once '../main.inc.php';
28 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
29 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
30 require_once DOL_DOCUMENT_ROOT.'/imports/class/import.class.php';
31 require_once DOL_DOCUMENT_ROOT.'/core/modules/import/modules_import.php';
32 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
33 require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
34 require_once DOL_DOCUMENT_ROOT.'/core/lib/import.lib.php';
35 
36 // Load translation files required by the page
37 $langs->loadLangs(array('exports', 'compta', 'errors'));
38 
39 // Security check
40 $result = restrictedArea($user, 'import');
41 
42 // Map icons, array duplicated in export.php, was not synchronized, TODO put it somewhere only once
43 $entitytoicon = array(
44  'invoice' => 'bill',
45  'invoice_line' => 'bill',
46  'order' => 'order',
47  'order_line' => 'order',
48  'propal' => 'propal',
49  'propal_line' => 'propal',
50  'intervention' => 'intervention',
51  'inter_line' => 'intervention',
52  'member' => 'user',
53  'member_type' => 'group',
54  'subscription' => 'payment',
55  'payment' => 'payment',
56  'tax' => 'bill',
57  'tax_type' => 'generic',
58  'other' => 'generic',
59  'account' => 'account',
60  'product' => 'product',
61  'virtualproduct'=>'product',
62  'subproduct' => 'product',
63  'product_supplier_ref' => 'product',
64  'stock' => 'stock',
65  'warehouse' => 'stock',
66  'batch' => 'stock',
67  'stockbatch' => 'stock',
68  'category' => 'category',
69  'shipment' => 'sending',
70  'shipment_line'=> 'sending',
71  'reception'=> 'sending',
72  'reception_line'=> 'sending',
73  'expensereport'=> 'trip',
74  'expensereport_line'=> 'trip',
75  'holiday' => 'holiday',
76  'contract_line' => 'contract',
77  'translation' => 'generic',
78  'bomm' => 'bom',
79  'bomline' => 'bom'
80 );
81 
82 // Translation code, array duplicated in export.php, was not synchronized, TODO put it somewhere only once
83 $entitytolang = array(
84  'user' => 'User',
85  'company' => 'Company',
86  'contact' => 'Contact',
87  'invoice' => 'Bill',
88  'invoice_line' => 'InvoiceLine',
89  'order' => 'Order',
90  'order_line' => 'OrderLine',
91  'propal' => 'Proposal',
92  'propal_line' => 'ProposalLine',
93  'intervention' => 'Intervention',
94  'inter_line' => 'InterLine',
95  'member' => 'Member',
96  'member_type' => 'MemberType',
97  'subscription' => 'Subscription',
98  'tax' => 'SocialContribution',
99  'tax_type' => 'DictionarySocialContributions',
100  'account' => 'BankTransactions',
101  'payment' => 'Payment',
102  'product' => 'Product',
103  'virtualproduct' => 'AssociatedProducts',
104  'subproduct' => 'SubProduct',
105  'product_supplier_ref' => 'SupplierPrices',
106  'service' => 'Service',
107  'stock' => 'Stock',
108  'movement' => 'StockMovement',
109  'batch' => 'Batch',
110  'stockbatch' => 'StockDetailPerBatch',
111  'warehouse' => 'Warehouse',
112  'category' => 'Category',
113  'other' => 'Other',
114  'trip' => 'TripsAndExpenses',
115  'shipment' => 'Shipments',
116  'shipment_line'=> 'ShipmentLine',
117  'project' => 'Projects',
118  'projecttask' => 'Tasks',
119  'task_time' => 'TaskTimeSpent',
120  'action' => 'Event',
121  'expensereport'=> 'ExpenseReport',
122  'expensereport_line'=> 'ExpenseReportLine',
123  'holiday' => 'TitreRequestCP',
124  'contract' => 'Contract',
125  'contract_line'=> 'ContractLine',
126  'translation' => 'Translation',
127  'bom' => 'BOM',
128  'bomline' => 'BOMLine'
129 );
130 
131 $datatoimport = GETPOST('datatoimport');
132 $format = GETPOST('format');
133 $filetoimport = GETPOST('filetoimport');
134 $action = GETPOST('action', 'alpha');
135 $confirm = GETPOST('confirm', 'alpha');
136 $step = (GETPOST('step') ? GETPOST('step') : 1);
137 $import_name = GETPOST('import_name');
138 $hexa = GETPOST('hexa');
139 $importmodelid = GETPOST('importmodelid', 'int');
140 $excludefirstline = (GETPOST('excludefirstline') ? GETPOST('excludefirstline') : 2);
141 $endatlinenb = (GETPOST('endatlinenb') ? GETPOST('endatlinenb') : '');
142 $updatekeys = (GETPOST('updatekeys', 'array') ? GETPOST('updatekeys', 'array') : array());
143 $separator = (GETPOST('separator', 'alphanohtml') ? GETPOST('separator', 'alphanohtml', 3) : '');
144 $enclosure = (GETPOST('enclosure', 'nohtml') ? GETPOST('enclosure', 'nohtml') : '"'); // We must use 'nohtml' and not 'alphanohtml' because we must accept "
145 $charset = GETPOST('charset', 'aZ09');
146 $separator_used = str_replace('\t', "\t", $separator);
147 
148 $objimport = new Import($db);
149 $objimport->load_arrays($user, ($step == 1 ? '' : $datatoimport));
150 
151 $objmodelimport = new ModeleImports();
152 
153 $form = new Form($db);
154 $htmlother = new FormOther($db);
155 $formfile = new FormFile($db);
156 
157 // Init $array_match_file_to_database from _SESSION
158 if (empty($array_match_file_to_database)) {
159  $serialized_array_match_file_to_database = isset($_SESSION["dol_array_match_file_to_database_select"]) ? $_SESSION["dol_array_match_file_to_database_select"] : '';
160  $array_match_file_to_database = array();
161  $fieldsarray = explode(',', $serialized_array_match_file_to_database);
162  foreach ($fieldsarray as $elem) {
163  $tabelem = explode('=', $elem, 2);
164  $key = $tabelem[0];
165  $val = (isset($tabelem[1]) ? $tabelem[1] : '');
166  if ($key && $val) {
167  $array_match_file_to_database[$key] = $val;
168  }
169  }
170 }
171 
172 
173 /*
174  * Actions
175  */
176 
177 /*
178 if ($action=='downfield' || $action=='upfield')
179 {
180  $pos=$array_match_file_to_database[$_GET["field"]];
181  if ($action=='downfield') $newpos=$pos+1;
182  if ($action=='upfield') $newpos=$pos-1;
183  // Recherche code avec qui switcher
184  $newcode="";
185  foreach($array_match_file_to_database as $code=>$value)
186  {
187  if ($value == $newpos)
188  {
189  $newcode=$code;
190  break;
191  }
192  }
193  //print("Switch pos=$pos (code=".$_GET["field"].") and newpos=$newpos (code=$newcode)");
194  if ($newcode) // Si newcode trouve (protection contre resoumission de page)
195  {
196  $array_match_file_to_database[$_GET["field"]]=$newpos;
197  $array_match_file_to_database[$newcode]=$pos;
198  $_SESSION["dol_array_match_file_to_database"]=$serialized_array_match_file_to_database;
199  }
200 }
201 */
202 // if ($action == 'builddoc') {
203 // // Build import file
204 // $result = $objimport->build_file($user, GETPOST('model', 'alpha'), $datatoimport, $array_match_file_to_database);
205 // if ($result < 0) {
206 // setEventMessages($objimport->error, $objimport->errors, 'errors');
207 // } else {
208 // setEventMessages($langs->trans("FileSuccessfullyBuilt"), null, 'mesgs');
209 // }
210 // }
211 
212 if ($action == 'deleteprof') {
213  if (GETPOST("id", 'int')) {
214  $objimport->fetch(GETPOST("id", 'int'));
215  $result = $objimport->delete($user);
216  }
217 }
218 
219 // Save import config to database
220 if ($action == 'add_import_model') {
221  if ($import_name) {
222  // Set save string
223  $hexa = '';
224  foreach ($array_match_file_to_database as $key => $val) {
225  if ($hexa) {
226  $hexa .= ',';
227  }
228  $hexa .= $key.'='.$val;
229  }
230 
231  $objimport->model_name = $import_name;
232  $objimport->datatoimport = $datatoimport;
233  $objimport->hexa = $hexa;
234  $objimport->fk_user = (GETPOST('visibility', 'aZ09') == 'all' ? 0 : $user->id);
235 
236  $result = $objimport->create($user);
237  if ($result >= 0) {
238  setEventMessages($langs->trans("ImportModelSaved", $objimport->model_name), null, 'mesgs');
239  $import_name = '';
240  } else {
241  $langs->load("errors");
242  if ($objimport->errno == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
243  setEventMessages($langs->trans("ErrorImportDuplicateProfil"), null, 'errors');
244  } else {
245  setEventMessages($objimport->error, null, 'errors');
246  }
247  }
248  } else {
249  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("ImportModelName")), null, 'errors');
250  }
251 }
252 
253 if ($step == 3 && $datatoimport) {
254  if (GETPOST('sendit') && !empty($conf->global->MAIN_UPLOAD_DOC)) {
255  dol_mkdir($conf->import->dir_temp);
256  $nowyearmonth = dol_print_date(dol_now(), '%Y%m%d%H%M%S');
257 
258  $fullpath = $conf->import->dir_temp."/".$nowyearmonth.'-'.$_FILES['userfile']['name'];
259  if (dol_move_uploaded_file($_FILES['userfile']['tmp_name'], $fullpath, 1) > 0) {
260  dol_syslog("File ".$fullpath." was added for import");
261  } else {
262  $langs->load("errors");
263  setEventMessages($langs->trans("ErrorFailedToSaveFile"), null, 'errors');
264  }
265  }
266 
267  // Delete file
268  if ($action == 'confirm_deletefile' && $confirm == 'yes') {
269  $langs->load("other");
270 
271  $param = '&datatoimport='.urlencode($datatoimport).'&format='.urlencode($format);
272  if ($excludefirstline) {
273  $param .= '&excludefirstline='.urlencode($excludefirstline);
274  }
275  if ($endatlinenb) {
276  $param .= '&endatlinenb='.urlencode($endatlinenb);
277  }
278 
279  $file = $conf->import->dir_temp.'/'.GETPOST('urlfile'); // Do not use urldecode here ($_GET and $_REQUEST are already decoded by PHP).
280  $ret = dol_delete_file($file);
281  if ($ret) {
282  setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
283  } else {
284  setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
285  }
286  Header('Location: '.$_SERVER["PHP_SELF"].'?step='.$step.$param);
287  exit;
288  }
289 }
290 
291 if ($step == 4 && $action == 'select_model') {
292  // Reinit match arrays
293  $_SESSION["dol_array_match_file_to_database"] = '';
294  $serialized_array_match_file_to_database = '';
295  $array_match_file_to_database = array();
296 
297  // Load model from $importmodelid and set $array_match_file_to_database
298  // and $_SESSION["dol_array_match_file_to_database"]
299  $result = $objimport->fetch($importmodelid);
300  if ($result > 0) {
301  $serialized_array_match_file_to_database = $objimport->hexa;
302  $fieldsarray = explode(',', $serialized_array_match_file_to_database);
303  foreach ($fieldsarray as $elem) {
304  $tabelem = explode('=', $elem);
305  $key = $tabelem[0];
306  $val = $tabelem[1];
307  if ($key && $val) {
308  $array_match_file_to_database[$key] = $val;
309  }
310  }
311  $_SESSION["dol_array_match_file_to_database"] = $serialized_array_match_file_to_database;
312  $_SESSION['dol_array_match_file_to_database_select'] = $_SESSION["dol_array_match_file_to_database"];
313  }
314 }
315 if ($action == 'saveselectorder') {
316  // Enregistrement de la position des champs
317  $serialized_array_match_file_to_database = '';
318  dol_syslog("selectorder=".GETPOST('selectorder'), LOG_DEBUG);
319  $selectorder = explode(",", GETPOST('selectorder'));
320  $fieldtarget = $fieldstarget = $objimport->array_import_fields[0];
321  foreach ($selectorder as $key => $code) {
322  $serialized_array_match_file_to_database .= $key.'='.$code;
323  $serialized_array_match_file_to_database .= ',';
324  }
325  $serialized_array_match_file_to_database = substr($serialized_array_match_file_to_database, 0, -1);
326  dol_syslog('dol_array_match_file_to_database_select='.$serialized_array_match_file_to_database);
327  $_SESSION["dol_array_match_file_to_database_select"] = $serialized_array_match_file_to_database;
328  echo "{}";
329  exit(0);
330 }
331 
332 
333 
334 /*
335  * View
336  */
337 
338 
339 $help_url = 'EN:Module_Imports_En|FR:Module_Imports|ES:M&oacute;dulo_Importaciones';
340 
341 
342 // STEP 1: Page to select dataset to import
343 if ($step == 1 || !$datatoimport) {
344  // Clean saved file-database matching
345  $serialized_array_match_file_to_database = '';
346  $array_match_file_to_database = array();
347  $_SESSION["dol_array_match_file_to_database"] = '';
348  $_SESSION["dol_array_match_file_to_database_select"] = '';
349 
350  $param = '';
351  if ($excludefirstline) {
352  $param .= '&excludefirstline='.urlencode($excludefirstline);
353  }
354  if ($endatlinenb) {
355  $param .= '&endatlinenb='.urlencode($endatlinenb);
356  }
357  if ($separator) {
358  $param .= '&separator='.urlencode($separator);
359  }
360  if ($enclosure) {
361  $param .= '&enclosure='.urlencode($enclosure);
362  }
363 
364  llxHeader('', $langs->trans("NewImport"), $help_url);
365 
366  $head = import_prepare_head($param, 1);
367 
368  print dol_get_fiche_head($head, 'step1', '', -1);
369 
370  print '<div class="opacitymedium">'.$langs->trans("SelectImportDataSet").'</div><br>';
371 
372  // Affiche les modules d'imports
373  print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
374  print '<table class="noborder centpercent">';
375  print '<tr class="liste_titre">';
376  print '<td>'.$langs->trans("Module").'</td>';
377  print '<td>'.$langs->trans("ImportableDatas").'</td>';
378  print '<td>&nbsp;</td>';
379  print '</tr>';
380 
381  if (count($objimport->array_import_module)) {
382  $sortedarrayofmodules = dol_sort_array($objimport->array_import_module, 'position_of_profile', 'asc', 0, 0, 1);
383  foreach ($sortedarrayofmodules as $key => $value) {
384  //var_dump($key.' '.$value['position_of_profile'].' '.$value['import_code'].' '.$objimport->array_import_module[$key]['module']->getName().' '.$objimport->array_import_code[$key]);
385  print '<tr class="oddeven"><td>';
386  $titleofmodule = $objimport->array_import_module[$key]['module']->getName();
387  // Special cas for import common to module/services
388  if (in_array($objimport->array_import_code[$key], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
389  $titleofmodule = $langs->trans("ProductOrService");
390  }
391  print $titleofmodule;
392  print '</td><td>';
393  $entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[$key]);
394  $entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
395  print img_object($objimport->array_import_module[$key]['module']->getName(), $entityicon).' ';
396  print $objimport->array_import_label[$key];
397  print '</td><td style="text-align: right">';
398  if ($objimport->array_import_perms[$key]) {
399  print '<a href="'.DOL_URL_ROOT.'/imports/import.php?step=2&datatoimport='.$objimport->array_import_code[$key].$param.'">'.img_picto($langs->trans("NewImport"), 'next', 'class="fa-15"').'</a>';
400  } else {
401  print $langs->trans("NotEnoughPermissions");
402  }
403  print '</td></tr>';
404  }
405  } else {
406  print '<tr><td class="oddeven" colspan="3">'.$langs->trans("NoImportableData").'</td></tr>';
407  }
408  print '</table>';
409  print '</div>';
410 
411  print dol_get_fiche_end();
412 }
413 
414 
415 // STEP 2: Page to select input format file
416 if ($step == 2 && $datatoimport) {
417  $param = '&datatoimport='.urlencode($datatoimport);
418  if ($excludefirstline) {
419  $param .= '&excludefirstline='.urlencode($excludefirstline);
420  }
421  if ($endatlinenb) {
422  $param .= '&endatlinenb='.urlencode($endatlinenb);
423  }
424  if ($separator) {
425  $param .= '&separator='.urlencode($separator);
426  }
427  if ($enclosure) {
428  $param .= '&enclosure='.urlencode($enclosure);
429  }
430 
431  llxHeader('', $langs->trans("NewImport"), $help_url);
432 
433  $head = import_prepare_head($param, 2);
434 
435  print dol_get_fiche_head($head, 'step2', '', -2);
436 
437  print '<div class="underbanner clearboth"></div>';
438  print '<div class="fichecenter">';
439 
440  print '<table class="border tableforfield centpercent">';
441 
442  // Module
443  print '<tr><td class="titlefieldcreate">'.$langs->trans("Module").'</td>';
444  print '<td>';
445  $titleofmodule = $objimport->array_import_module[0]['module']->getName();
446  // Special cas for import common to module/services
447  if (in_array($objimport->array_import_code[0], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
448  $titleofmodule = $langs->trans("ProductOrService");
449  }
450  print $titleofmodule;
451  print '</td></tr>';
452 
453  // Dataset to import
454  print '<tr><td>'.$langs->trans("DatasetToImport").'</td>';
455  print '<td>';
456  $entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[0]);
457  $entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
458  print img_object($objimport->array_import_module[0]['module']->getName(), $entityicon).' ';
459  print $objimport->array_import_label[0];
460  print '</td></tr>';
461 
462  print '</table>';
463  print '</div>';
464 
465  print dol_get_fiche_end();
466 
467  print '<form name="userfile" action="'.$_SERVER["PHP_SELF"].'" enctype="multipart/form-data" METHOD="POST">';
468  print '<input type="hidden" name="token" value="'.newToken().'">';
469 
470  print '<br>';
471 
472  print '<span class="opacitymedium">';
473  $s = $langs->trans("ChooseFormatOfFileToImport", '{s1}');
474  $s = str_replace('{s1}', img_picto('', 'next'), $s);
475  print $s;
476  print '</span><br><br>';
477 
478  print '<br>';
479 
480  print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
481  print '<table class="noborder centpercent" cellpadding="4">';
482 
483  $filetoimport = '';
484 
485  // Add format informations and link to download example
486  print '<tr class="liste_titre"><td colspan="5">';
487  print $langs->trans("FileMustHaveOneOfFollowingFormat");
488  print '</td></tr>';
489  $list = $objmodelimport->listOfAvailableImportFormat($db);
490  foreach ($list as $key) {
491  print '<tr class="oddeven">';
492  print '<td width="16">'.img_picto_common($key, $objmodelimport->getPictoForKey($key)).'</td>';
493  $text = $objmodelimport->getDriverDescForKey($key);
494  print '<td>'.$form->textwithpicto($objmodelimport->getDriverLabelForKey($key), $text).'</td>';
495  print '<td style="text-align:center">';
496  $filename = $langs->trans("ExampleOfImportFile").'_'.$datatoimport.'.'.$key;
497  print '<a href="'.DOL_URL_ROOT.'/imports/emptyexample.php?format='.$key.$param.'&output=file&file='.urlencode($filename).'" target="_blank" rel="noopener noreferrer">';
498  print img_picto('', 'download', 'class="paddingright opacitymedium"');
499  print $langs->trans("DownloadEmptyExampleShort");
500  print '</a>';
501  print $form->textwithpicto('', $langs->trans("DownloadEmptyExample").'.<br>'.$langs->trans("StarAreMandatory"));
502  print '</td>';
503  // Action button
504  print '<td style="text-align:right">';
505  print '<a href="'.DOL_URL_ROOT.'/imports/import.php?step=3&format='.$key.$param.'">'.img_picto($langs->trans("SelectFormat"), 'next', 'class="fa-15"').'</a>';
506  print '</td>';
507  print '</tr>';
508  }
509 
510  print '</table>';
511  print '</div>';
512 
513  print '</form>';
514 }
515 
516 
517 // STEP 3: Page to select file
518 if ($step == 3 && $datatoimport) {
519  $param = '&datatoimport='.urlencode($datatoimport).'&format='.urlencode($format);
520  if ($excludefirstline) {
521  $param .= '&excludefirstline='.urlencode($excludefirstline);
522  }
523  if ($endatlinenb) {
524  $param .= '&endatlinenb='.urlencode($endatlinenb);
525  }
526  if ($separator) {
527  $param .= '&separator='.urlencode($separator);
528  }
529  if ($enclosure) {
530  $param .= '&enclosure='.urlencode($enclosure);
531  }
532 
533  $list = $objmodelimport->listOfAvailableImportFormat($db);
534 
535  llxHeader('', $langs->trans("NewImport"), $help_url);
536 
537  $head = import_prepare_head($param, 3);
538 
539  print dol_get_fiche_head($head, 'step3', '', -2);
540 
541  /*
542  * Confirm delete file
543  */
544  if ($action == 'delete') {
545  print $form->formconfirm($_SERVER["PHP_SELF"].'?urlfile='.urlencode(GETPOST('urlfile')).'&step=3'.$param, $langs->trans('DeleteFile'), $langs->trans('ConfirmDeleteFile'), 'confirm_deletefile', '', 0, 1);
546  }
547 
548  print '<div class="underbanner clearboth"></div>';
549  print '<div class="fichecenter">';
550 
551  print '<table class="border tableforfield centpercent">';
552 
553  // Module
554  print '<tr><td class="titlefieldcreate">'.$langs->trans("Module").'</td>';
555  print '<td>';
556  $titleofmodule = $objimport->array_import_module[0]['module']->getName();
557  // Special cas for import common to module/services
558  if (in_array($objimport->array_import_code[0], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
559  $titleofmodule = $langs->trans("ProductOrService");
560  }
561  print $titleofmodule;
562  print '</td></tr>';
563 
564  // Lot de donnees a importer
565  print '<tr><td>'.$langs->trans("DatasetToImport").'</td>';
566  print '<td>';
567  $entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[0]);
568  $entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
569  print img_object($objimport->array_import_module[0]['module']->getName(), $entityicon).' ';
570  print $objimport->array_import_label[0];
571  print '</td></tr>';
572 
573  print '</table>';
574  print '</div>';
575 
576  print load_fiche_titre($langs->trans("InformationOnSourceFile"), '', 'file-export');
577 
578  print '<div class="underbanner clearboth"></div>';
579  print '<div class="fichecenter">';
580  print '<table width="100%" class="border tableforfield">';
581 
582  // Source file format
583  print '<tr><td class="titlefieldcreate">'.$langs->trans("SourceFileFormat").'</td>';
584  print '<td class="nowraponall">';
585  $text = $objmodelimport->getDriverDescForKey($format);
586  print $form->textwithpicto($objmodelimport->getDriverLabelForKey($format), $text);
587  print '</td><td style="text-align:right" class="nowrap">';
588  $filename = $langs->trans("ExampleOfImportFile").'_'.$datatoimport.'.'.$format;
589  print '<a href="'.DOL_URL_ROOT.'/imports/emptyexample.php?format='.$format.$param.'&output=file&file='.urlencode($filename).'" target="_blank" rel="noopener noreferrer">';
590  print img_picto('', 'download', 'class="paddingright opacitymedium"');
591  print $langs->trans("DownloadEmptyExampleShort");
592  print '</a>';
593  print $form->textwithpicto('', $langs->trans("DownloadEmptyExample").'.<br>'.$langs->trans("StarAreMandatory"));
594  print '</td></tr>';
595 
596  print '</table>';
597  print '</div>';
598 
599  print dol_get_fiche_end();
600 
601 
602  if ($format == 'xlsx' && !class_exists('XMLWriter')) {
603  $langs->load("install");
604  print info_admin($langs->trans("ErrorPHPDoesNotSupport", 'php-xml'), 0, 0, 1, 'error');
605  }
606 
607 
608  print '<br><br>';
609 
610  print '<form name="userfile" action="'.$_SERVER["PHP_SELF"].'" enctype="multipart/form-data" method="POST">';
611  print '<input type="hidden" name="token" value="'.newToken().'">';
612  print '<input type="hidden" value="'.$step.'" name="step">';
613  print '<input type="hidden" value="'.dol_escape_htmltag($format).'" name="format">';
614  print '<input type="hidden" value="'.$excludefirstline.'" name="excludefirstline">';
615  print '<input type="hidden" value="'.$endatlinenb.'" name="endatlinenb">';
616  print '<input type="hidden" value="'.dol_escape_htmltag($separator).'" name="separator">';
617  print '<input type="hidden" value="'.dol_escape_htmltag($enclosure).'" name="enclosure">';
618  print '<input type="hidden" value="'.dol_escape_htmltag($datatoimport).'" name="datatoimport">';
619 
620  print '<span class="opacitymedium">';
621  $s = $langs->trans("ChooseFileToImport", '{s1}');
622  $s = str_replace('{s1}', img_picto('', 'next'), $s);
623  print $s;
624  print '</span><br><br>';
625 
626  $filetoimport = '';
627 
628  // Input file name box
629  print '<div class="marginbottomonly">';
630  $maxfilesizearray = getMaxFileSizeArray();
631  $maxmin = $maxfilesizearray['maxmin'];
632  if ($maxmin > 0) {
633  print '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
634  }
635  print '<input type="file" name="userfile" size="20" maxlength="80"> &nbsp; &nbsp; ';
636  $out = (empty($conf->global->MAIN_UPLOAD_DOC) ? ' disabled' : '');
637  print '<input type="submit" class="button small" value="'.$langs->trans("AddFile").'"'.$out.' name="sendit">';
638  $out = '';
639  if (!empty($conf->global->MAIN_UPLOAD_DOC)) {
640  $max = $conf->global->MAIN_UPLOAD_DOC; // In Kb
641  $maxphp = @ini_get('upload_max_filesize'); // In unknown
642  if (preg_match('/k$/i', $maxphp)) {
643  $maxphp = (int) substr($maxphp, 0, -1);
644  }
645  if (preg_match('/m$/i', $maxphp)) {
646  $maxphp = (int) substr($maxphp, 0, -1) * 1024;
647  }
648  if (preg_match('/g$/i', $maxphp)) {
649  $maxphp = (int) substr($maxphp, 0, -1) * 1024 * 1024;
650  }
651  if (preg_match('/t$/i', $maxphp)) {
652  $maxphp = (int) substr($maxphp, 0, -1) * 1024 * 1024 * 1024;
653  }
654  $maxphp2 = @ini_get('post_max_size'); // In unknown
655  if (preg_match('/k$/i', $maxphp2)) {
656  $maxphp2 = (int) substr($maxphp2, 0, -1);
657  }
658  if (preg_match('/m$/i', $maxphp2)) {
659  $maxphp2 = (int) substr($maxphp2, 0, -1) * 1024;
660  }
661  if (preg_match('/g$/i', $maxphp2)) {
662  $maxphp2 = (int) substr($maxphp2, 0, -1) * 1024 * 1024;
663  }
664  if (preg_match('/t$/i', $maxphp2)) {
665  $maxphp2 = (int) substr($maxphp2, 0, -1) * 1024 * 1024 * 1024;
666  }
667  // Now $max and $maxphp and $maxphp2 are in Kb
668  $maxmin = $max;
669  $maxphptoshow = $maxphptoshowparam = '';
670  if ($maxphp > 0) {
671  $maxmin = min($max, $maxphp);
672  $maxphptoshow = $maxphp;
673  $maxphptoshowparam = 'upload_max_filesize';
674  }
675  if ($maxphp2 > 0) {
676  $maxmin = min($max, $maxphp2);
677  if ($maxphp2 < $maxphp) {
678  $maxphptoshow = $maxphp2;
679  $maxphptoshowparam = 'post_max_size';
680  }
681  }
682 
683  $langs->load('other');
684  $out .= ' ';
685  $out .= info_admin($langs->trans("ThisLimitIsDefinedInSetup", $max, $maxphptoshow), 1);
686  } else {
687  $out .= ' ('.$langs->trans("UploadDisabled").')';
688  }
689  print $out;
690  print '</div>';
691 
692  // Search available imports
693  $filearray = dol_dir_list($conf->import->dir_temp, 'files', 0, '', '', 'name', SORT_DESC);
694  if (count($filearray) > 0) {
695  print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
696  print '<table class="noborder centpercent" width="100%" cellpadding="4">';
697 
698  $dir = $conf->import->dir_temp;
699 
700  // Search available files to import
701  $i = 0;
702  foreach ($filearray as $key => $val) {
703  $file = $val['name'];
704 
705  // readdir return value in ISO and we want UTF8 in memory
706  if (!utf8_check($file)) {
707  $file = utf8_encode($file);
708  }
709 
710  if (preg_match('/^\./', $file)) {
711  continue;
712  }
713 
714  $modulepart = 'import';
715  $urlsource = $_SERVER["PHP_SELF"].'?step='.$step.$param.'&filetoimport='.urlencode($filetoimport);
716  $relativepath = $file;
717 
718  print '<tr class="oddeven">';
719  print '<td>';
720  print img_mime($file, '', 'pictofixedwidth');
721  print '<a data-ajax="false" href="'.DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&file='.urlencode($relativepath).'&step=3'.$param.'" target="_blank" rel="noopener noreferrer">';
722  print $file;
723  print '</a>';
724  print '</td>';
725  // Affiche taille fichier
726  print '<td style="text-align:right">'.dol_print_size(dol_filesize($dir.'/'.$file)).'</td>';
727  // Affiche date fichier
728  print '<td style="text-align:right">'.dol_print_date(dol_filemtime($dir.'/'.$file), 'dayhour').'</td>';
729  // Del button
730  print '<td style="text-align:right"><a href="'.$_SERVER['PHP_SELF'].'?action=delete&token='.newToken().'&step=3'.$param.'&urlfile='.urlencode($relativepath);
731  print '">'.img_delete().'</a></td>';
732  // Action button
733  print '<td style="text-align:right">';
734  print '<a href="'.$_SERVER['PHP_SELF'].'?step=4'.$param.'&filetoimport='.urlencode($relativepath).'">'.img_picto($langs->trans("NewImport"), 'next', 'class="fa-15"').'</a>';
735  print '</td>';
736  print '</tr>';
737  }
738 
739  print '</table>';
740  print '</div>';
741  }
742 
743  print '</form>';
744 }
745 
746 
747 // STEP 4: Page to make matching between source file and database fields
748 if ($step == 4 && $datatoimport) {
749  //var_dump($_SESSION["dol_array_match_file_to_database_select"]);
750  $serialized_array_match_file_to_database = isset($_SESSION["dol_array_match_file_to_database_select"]) ? $_SESSION["dol_array_match_file_to_database_select"] : '';
751  $fieldsarray = explode(',', $serialized_array_match_file_to_database);
752  $array_match_file_to_database = array(); // Same than $fieldsarray but with mapped value only (col1 => 's.fielda', col2 => 's.fieldb'...)
753  foreach ($fieldsarray as $elem) {
754  $tabelem = explode('=', $elem, 2);
755  $key = $tabelem[0];
756  $val = (isset($tabelem[1]) ? $tabelem[1] : '');
757  if ($key && $val) {
758  $array_match_file_to_database[$key] = $val;
759  }
760  }
761 
762  //var_dump($serialized_array_match_file_to_database);
763  //var_dump($fieldsarray);
764  //var_dump($array_match_file_to_database);
765 
766  $model = $format;
767  $list = $objmodelimport->listOfAvailableImportFormat($db);
768 
769  if (empty($separator)) {
770  $separator = (empty($conf->global->IMPORT_CSV_SEPARATOR_TO_USE) ? ',' : $conf->global->IMPORT_CSV_SEPARATOR_TO_USE);
771  }
772 
773  // The separator has been defined, if it is a unique char, we check it is valid by reading the source file
774  if ($model == 'csv' && strlen($separator) == 1 && !GETPOSTISSET('separator')) {
775  // Count the char in first line of file.
776  $fh = fopen($conf->import->dir_temp.'/'.$filetoimport, 'r');
777  if ($fh) {
778  $sline = fgets($fh, 1000000);
779  fclose($fh);
780  $nboccurence = substr_count($sline, $separator);
781  $nboccurencea = substr_count($sline, ',');
782  $nboccurenceb = substr_count($sline, ';');
783  //var_dump($nboccurence." ".$nboccurencea." ".$nboccurenceb);exit;
784  if ($nboccurence == 0) {
785  if ($nboccurencea > 2) {
786  $separator = ',';
787  } elseif ($nboccurenceb > 2) {
788  $separator = ';';
789  }
790  }
791  }
792  }
793 
794  // The value to use
795  $separator_used = str_replace('\t', "\t", $separator);
796 
797  // Create classe to use for import
798  $dir = DOL_DOCUMENT_ROOT."/core/modules/import/";
799  $file = "import_".$model.".modules.php";
800  $classname = "Import".ucfirst($model);
801  require_once $dir.$file;
802  $obj = new $classname($db, $datatoimport);
803  if ($model == 'csv') {
804  $obj->separator = $separator_used;
805  $obj->enclosure = $enclosure;
806  $obj->charset = '';
807  }
808  if ($model == 'xlsx') {
809  if (!preg_match('/\.xlsx$/i', $filetoimport)) {
810  $langs->load("errors");
811  $param = '&datatoimport='.$datatoimport.'&format='.$format;
812  setEventMessages($langs->trans("ErrorFileMustHaveFormat", $model), null, 'errors');
813  header("Location: ".$_SERVER["PHP_SELF"].'?step=3'.$param.'&filetoimport='.urlencode($relativepath));
814  exit;
815  }
816  }
817 
818  if (GETPOST('update')) {
819  $array_match_file_to_database = array();
820  }
821 
822  // Load the source fields from input file into variable $arrayrecord
823  $fieldssource = array();
824  $result = $obj->import_open_file($conf->import->dir_temp.'/'.$filetoimport, $langs);
825  if ($result >= 0) {
826  // Read first line
827  $arrayrecord = $obj->import_read_record();
828 
829  // Create array $fieldssource starting with 1 with values found of first line.
830  $i = 1;
831  foreach ($arrayrecord as $key => $val) {
832  if ($val["type"] != -1) {
833  $fieldssource[$i]['example1'] = dol_trunc($val['val'], 128);
834  $i++;
835  } else {
836  $fieldssource[$i]['example1'] = $langs->trans('Empty');
837  $i++;
838  }
839  }
840  $obj->import_close_file();
841  }
842 
843  // Load targets fields in database
844  $fieldstarget = $objimport->array_import_fields[0];
845  $minpos = min(count($fieldssource), count($fieldstarget));
846  //var_dump($array_match_file_to_database);
847 
848 
849  $initialloadofstep4 = false;
850  if (empty($_SESSION['dol_array_match_file_to_database_select'])) {
851  $initialloadofstep4 = true;
852  }
853 
854  // Is it a first time in page (if yes, we must initialize array_match_file_to_database)
855  if (count($array_match_file_to_database) == 0) {
856  // This is first input in screen, we need to define
857  // $array_match_file_to_database
858  // $serialized_array_match_file_to_database
859  // $_SESSION["dol_array_match_file_to_database"]
860  $pos = 1;
861  $num = count($fieldssource);
862  while ($pos <= $num) {
863  if ($num >= 1 && $pos <= $num) {
864  $posbis = 1;
865  foreach ($fieldstarget as $key => $val) {
866  if ($posbis < $pos) {
867  $posbis++;
868  continue;
869  }
870  // We found the key of targets that is at position pos
871  $array_match_file_to_database[$pos] = $key;
872  break;
873  }
874  }
875  $pos++;
876  }
877  }
878  $array_match_database_to_file = array_flip($array_match_file_to_database);
879  //var_dump($array_match_database_to_file);
880  //var_dump($_SESSION["dol_array_match_file_to_database_select"]);
881 
882  $fieldstarget_tmp = array();
883  $arraykeysfieldtarget = array_keys($fieldstarget);
884  $position = 0;
885  foreach ($fieldstarget as $key => $label) {
886  $isrequired = preg_match('/\*$/', $label);
887  if (!empty($isrequired)) {
888  $newlabel = substr($label, 0, -1);
889  $fieldstarget_tmp[$key] = array("label"=>$newlabel, "required"=>true);
890  } else {
891  $fieldstarget_tmp[$key] = array("label"=>$label, "required"=>false);
892  }
893  if (!empty($array_match_database_to_file[$key])) {
894  $fieldstarget_tmp[$key]["imported"] = true;
895  $fieldstarget_tmp[$key]["position"] = $array_match_database_to_file[$key]-1;
896  $keytoswap = $key;
897  while (!empty($array_match_database_to_file[$keytoswap])) {
898  if ($position+1 > $array_match_database_to_file[$keytoswap]) {
899  $keytoswapwith = $array_match_database_to_file[$keytoswap]-1;
900  $tmp = [$keytoswap=>$fieldstarget_tmp[$keytoswap]];
901  unset($fieldstarget_tmp[$keytoswap]);
902  $fieldstarget_tmp = arrayInsert($fieldstarget_tmp, $keytoswapwith, $tmp);
903  $keytoswapwith = $arraykeysfieldtarget[$array_match_database_to_file[$keytoswap]-1];
904  $tmp = $fieldstarget_tmp[$keytoswapwith];
905  unset($fieldstarget_tmp[$keytoswapwith]);
906  $fieldstarget_tmp[$keytoswapwith] = $tmp;
907  $keytoswap = $keytoswapwith;
908  } else {
909  break;
910  }
911  }
912  } else {
913  $fieldstarget_tmp[$key]["imported"] = false;
914  }
915  $position++;
916  }
917  $fieldstarget = $fieldstarget_tmp;
918 
919  //print $serialized_array_match_file_to_database;
920  //print $_SESSION["dol_array_match_file_to_database"];
921  //print $_SESSION["dol_array_match_file_to_database_select"];
922  //var_dump($array_match_file_to_database);exit;
923 
924  // Now $array_match_file_to_database contains fieldnb(1,2,3...)=>fielddatabase(key in $array_match_file_to_database)
925 
926  $param = '&format='.$format.'&datatoimport='.urlencode($datatoimport).'&filetoimport='.urlencode($filetoimport);
927  if ($excludefirstline) {
928  $param .= '&excludefirstline='.urlencode($excludefirstline);
929  }
930  if ($endatlinenb) {
931  $param .= '&endatlinenb='.urlencode($endatlinenb);
932  }
933  if ($separator) {
934  $param .= '&separator='.urlencode($separator);
935  }
936  if ($enclosure) {
937  $param .= '&enclosure='.urlencode($enclosure);
938  }
939 
940  llxHeader('', $langs->trans("NewImport"), $help_url);
941 
942  $head = import_prepare_head($param, 4);
943 
944  print dol_get_fiche_head($head, 'step4', '', -2);
945 
946  print '<div class="underbanner clearboth"></div>';
947  print '<div class="fichecenter">';
948 
949  print '<table class="centpercent border tableforfield">';
950 
951  // Module
952  print '<tr><td class="titlefieldcreate">'.$langs->trans("Module").'</td>';
953  print '<td>';
954  $titleofmodule = $objimport->array_import_module[0]['module']->getName();
955  // Special cas for import common to module/services
956  if (in_array($objimport->array_import_code[0], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
957  $titleofmodule = $langs->trans("ProductOrService");
958  }
959  print $titleofmodule;
960  print '</td></tr>';
961 
962  // Lot de donnees a importer
963  print '<tr><td>'.$langs->trans("DatasetToImport").'</td>';
964  print '<td>';
965  $entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[0]);
966  $entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
967  print img_object($objimport->array_import_module[0]['module']->getName(), $entityicon).' ';
968  print $objimport->array_import_label[0];
969  print '</td></tr>';
970 
971  print '</table>';
972  print '</div>';
973 
974  print load_fiche_titre($langs->trans("InformationOnSourceFile"), '', 'file-export');
975 
976  print '<div class="underbanner clearboth"></div>';
977  print '<div class="fichecenter">';
978  print '<table width="100%" class="border tableforfield">';
979 
980  // Source file format
981  print '<tr><td class="titlefieldcreate">'.$langs->trans("SourceFileFormat").'</td>';
982  print '<td>';
983  $text = $objmodelimport->getDriverDescForKey($format);
984  print $form->textwithpicto($objmodelimport->getDriverLabelForKey($format), $text);
985  print '</td></tr>';
986 
987  // Separator and enclosure
988  if ($model == 'csv') {
989  print '<tr><td>'.$langs->trans("CsvOptions").'</td>';
990  print '<td>';
991  print '<form method="POST">';
992  print '<input type="hidden" name="token" value="'.newToken().'">';
993  print '<input type="hidden" value="'.$step.'" name="step">';
994  print '<input type="hidden" value="'.$format.'" name="format">';
995  print '<input type="hidden" value="'.$excludefirstline.'" name="excludefirstline">';
996  print '<input type="hidden" value="'.$endatlinenb.'" name="endatlinenb">';
997  print '<input type="hidden" value="'.$datatoimport.'" name="datatoimport">';
998  print '<input type="hidden" value="'.$filetoimport.'" name="filetoimport">';
999  print $langs->trans("Separator").' : ';
1000  print '<input type="text" class="width25 center" name="separator" value="'.dol_escape_htmltag($separator).'"/>';
1001  print '&nbsp;&nbsp;&nbsp;&nbsp;'.$langs->trans("Enclosure").' : ';
1002  print '<input type="text" class="width25 center" name="enclosure" value="'.dol_escape_htmltag($enclosure).'"/> ';
1003  print '<input name="update" type="submit" value="'.$langs->trans('Update').'" class="button smallpaddingimp" />';
1004  print '</form>';
1005  print '</td></tr>';
1006  }
1007 
1008  // File to import
1009  print '<tr><td>'.$langs->trans("FileToImport").'</td>';
1010  print '<td>';
1011  $modulepart = 'import';
1012  $relativepath = GETPOST('filetoimport');
1013  print '<a data-ajax="false" href="'.DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&file='.urlencode($relativepath).'&step=4'.$param.'" target="_blank" rel="noopener noreferrer">';
1014  print img_mime($file, '', 'pictofixedwidth');
1015  print $filetoimport;
1016  print img_picto($langs->trans("Download"), 'download', 'class="paddingleft opacitymedium"');
1017  print '</a>';
1018  print '</td></tr>';
1019 
1020  print '</table>';
1021  print '</div>';
1022 
1023  print dol_get_fiche_end();
1024 
1025  print '<br>'."\n";
1026 
1027 
1028  // List of source fields
1029  print '<!-- List of source fields -->'."\n";
1030  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
1031  print '<input type="hidden" name="token" value="'.newToken().'">';
1032  print '<input type="hidden" name="action" value="select_model">';
1033  print '<input type="hidden" name="step" value="4">';
1034  print '<input type="hidden" name="format" value="'.$format.'">';
1035  print '<input type="hidden" name="datatoimport" value="'.$datatoimport.'">';
1036  print '<input type="hidden" name="filetoimport" value="'.$filetoimport.'">';
1037  print '<input type="hidden" name="excludefirstline" value="'.$excludefirstline.'">';
1038  print '<input type="hidden" name="endatlinenb" value="'.$endatlinenb.'">';
1039  print '<input type="hidden" name="separator" value="'.dol_escape_htmltag($separator).'">';
1040  print '<input type="hidden" name="enclosure" value="'.dol_escape_htmltag($enclosure).'">';
1041 
1042  // Import profile to use/load
1043  print '<div class="marginbottomonly">';
1044  print '<span class="opacitymedium">';
1045  $s = $langs->trans("SelectImportFieldsSource", '{s1}');
1046  $s = str_replace('{s1}', img_picto('', 'grip_title', '', false, 0, 0, '', '', 0), $s);
1047  print $s;
1048  print '</span> ';
1049  $htmlother->select_import_model($importmodelid, 'importmodelid', $datatoimport, 1, $user->id);
1050  print '<input type="submit" class="button small reposition" value="'.$langs->trans("Select").'">';
1051  print '</div>';
1052  print '</form>';
1053 
1054  // Title of array with fields
1055  print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
1056  print '<table class="noborder centpercent">';
1057  print '<tr class="liste_titre">';
1058  print '<td>'.$langs->trans("FieldsInSourceFile").'</td>';
1059  print '<td>'.$langs->trans("FieldsInTargetDatabase").'</td>';
1060  print '</tr>';
1061 
1062  //var_dump($array_match_file_to_database);
1063 
1064  print '<tr valign="top"><td width="50%" class="nopaddingleftimp">';
1065 
1066  $fieldsplaced = array();
1067  $valforsourcefieldnb = array();
1068  $listofkeys = array();
1069  foreach ($array_match_file_to_database as $key => $val) {
1070  $listofkeys[$key] = 1;
1071  }
1072 
1073  print "\n<!-- Box left container -->\n";
1074  print '<div id="left" class="connectedSortable">'."\n";
1075 
1076  // List of source fields
1077 
1078  $var = false;
1079  $lefti = 1;
1080  foreach ($fieldssource as $key => $val) {
1081  show_elem($fieldssource, $key, $val, $var); // key is field number in source file
1082  $listofkeys[$key] = 1;
1083  $fieldsplaced[$key] = 1;
1084  $valforsourcefieldnb[$lefti] = $key;
1085  $lefti++;
1086 
1087  /*if ($lefti > count($fieldstarget)) {
1088  break; // Other fields are in the not imported area
1089  }*/
1090  }
1091  //var_dump($valforsourcefieldnb);
1092 
1093  print "</div>\n";
1094  print "<!-- End box left container -->\n";
1095 
1096 
1097  print '</td><td width="50%" class="nopaddingrightimp">';
1098 
1099  // Set the list of all possible target fields in Dolibarr.
1100 
1101  $optionsall = array();
1102  foreach ($fieldstarget as $code => $line) {
1103  //var_dump($line);
1104 
1105  $tmparray = explode('|', $line["label"]); // If label of field is several translation keys separated with |
1106  $labeltoshow = '';
1107  foreach ($tmparray as $tmpkey => $tmpval) {
1108  $labeltoshow .= ($labeltoshow ? ' '.$langs->trans('or').' ' : '').$langs->transnoentities($tmpval);
1109  }
1110  $optionsall[$code] = array('labelkey'=>$line['label'], 'labelkeyarray'=>$tmparray, 'label'=>$labeltoshow, 'required'=>(empty($line["required"]) ? 0 : 1), 'position'=>!empty($line['position']) ? $line['position'] : 0);
1111  // TODO Get type from a new array into module descriptor.
1112  //$picto = 'email';
1113  $picto = '';
1114  if ($picto) {
1115  $optionsall[$code]['picto'] = $picto;
1116  }
1117  }
1118  // $optionsall is an array of all possible target fields. key=>array('label'=>..., 'xxx')
1119 
1120  $height = '32px'; //needs px for css height attribute below
1121  $i = 0;
1122  $mandatoryfieldshavesource = true;
1123 
1124  //var_dump($fieldstarget);
1125  //var_dump($optionsall);
1126  //exit;
1127 
1128  //var_dump($_SESSION['dol_array_match_file_to_database']);
1129  //var_dump($_SESSION['dol_array_match_file_to_database_select']);
1130  //exit;
1131  //var_dump($optionsall);
1132  //var_dump($fieldssource);
1133  //var_dump($fieldstarget);
1134 
1135  $modetoautofillmapping = 'session'; // Use setup in session
1136  if ($initialloadofstep4) {
1137  $modetoautofillmapping = 'guess';
1138  }
1139  //var_dump($modetoautofillmapping);
1140 
1141  print '<table class="nobordernopadding centpercent tableimport">';
1142  foreach ($fieldssource as $code => $line) { // $fieldssource is an array code=column num, line=content on first line for column in source file.
1143  /*if ($i == $minpos) {
1144  break;
1145  }*/
1146  print '<tr style="height:'.$height.'" class="trimport oddevenimport">';
1147  $entity = (!empty($objimport->array_import_entities[0][$code]) ? $objimport->array_import_entities[0][$code] : $objimport->array_import_icon[0]);
1148 
1149  $entityicon = !empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity; // $entityicon must string name of picto of the field like 'project', 'company', 'contact', 'modulename', ...
1150  $entitylang = $entitytolang[$entity] ? $entitytolang[$entity] : $objimport->array_import_label[0]; // $entitylang must be a translation key to describe object the field is related to, like 'Company', 'Contact', 'MyModyle', ...
1151 
1152  print '<td class="nowraponall hideonsmartphone" style="font-weight: normal">=> </td>';
1153  print '<td class="nowraponall" style="font-weight: normal">';
1154 
1155  //var_dump($_SESSION['dol_array_match_file_to_database_select']);
1156  //var_dump($_SESSION['dol_array_match_file_to_database']);
1157 
1158  $selectforline = '';
1159  $selectforline .= '<select id="selectorderimport_'.($i+1).'" class="targetselectchange minwidth300" name="select_'.($i+1).'">';
1160  if (!empty($line["imported"])) {
1161  $selectforline .= '<option value="-1">&nbsp;</option>';
1162  } else {
1163  $selectforline .= '<option selected="" value="-1">&nbsp;</option>';
1164  }
1165 
1166  $j = 0;
1167  $codeselectedarray = array();
1168  foreach ($optionsall as $tmpcode => $tmpval) { // Loop on each entry to add into each combo list.
1169  $label = '';
1170  if (!empty($tmpval['picto'])) {
1171  $label .= img_picto('', $tmpval['picto'], 'class="pictofixedwidth"');
1172  }
1173  $label .= $tmpval['required'] ? '<strong>' : '';
1174  $label .= $tmpval['label'];
1175  $label .= $tmpval['required'] ? '*</strong>' : '';
1176 
1177  $tablealias = preg_replace('/(\..*)$/i', '', $tmpcode);
1178  $tablename = !empty($objimport->array_import_tables[0][$tablealias]) ? $objimport->array_import_tables[0][$tablealias] : "";
1179 
1180  $htmltext = '';
1181 
1182  $filecolumn = ($i + 1);
1183  // Source field info
1184  if (empty($objimport->array_import_convertvalue[0][$tmpcode])) { // If source file does not need convertion
1185  $filecolumntoshow = num2Alpha($i);
1186  } else {
1187  if ($objimport->array_import_convertvalue[0][$tmpcode]['rule'] == 'fetchidfromref') {
1188  $htmltext .= $langs->trans("DataComeFromIdFoundFromRef", $langs->transnoentitiesnoconv($entitylang)).'<br>';
1189  }
1190  if ($objimport->array_import_convertvalue[0][$tmpcode]['rule'] == 'fetchidfromcodeid') {
1191  $htmltext .= $langs->trans("DataComeFromIdFoundFromCodeId", $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$tmpcode]['dict'])).'<br>';
1192  }
1193  }
1194  // Source required
1195  $example = !empty($objimport->array_import_examplevalues[0][$tmpcode])?$objimport->array_import_examplevalues[0][$tmpcode]:"";
1196  // Example
1197  if (empty($objimport->array_import_convertvalue[0][$tmpcode])) { // If source file does not need convertion
1198  if ($example) {
1199  $htmltext .= $langs->trans("SourceExample").': <b>'.str_replace('"', '', $example).'</b><br>';
1200  }
1201  } else {
1202  if ($objimport->array_import_convertvalue[0][$tmpcode]['rule'] == 'fetchidfromref') {
1203  $htmltext .= $langs->trans("SourceExample").': <b>'.$langs->transnoentitiesnoconv("ExampleAnyRefFoundIntoElement", $entitylang).($example ? ' ('.$langs->transnoentitiesnoconv("Example").': '.str_replace('"', '', $example).')' : '').'</b><br>';
1204  } elseif ($objimport->array_import_convertvalue[0][$tmpcode]['rule'] == 'fetchidfromcodeid') {
1205  $htmltext .= $langs->trans("SourceExample").': <b>'.$langs->trans("ExampleAnyCodeOrIdFoundIntoDictionary", $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$tmpcode]['dict'])).($example ? ' ('.$langs->transnoentitiesnoconv("Example").': '.str_replace('"', '', $example).')' : '').'</b><br>';
1206  } elseif ($example) {
1207  $htmltext .= $langs->trans("SourceExample").': <b>'.str_replace('"', '', $example).'</b><br>';
1208  }
1209  }
1210  // Format control rule
1211  if (!empty($objimport->array_import_regex[0][$tmpcode])) {
1212  $htmltext .= $langs->trans("FormatControlRule").': <b>'.str_replace('"', '', $objimport->array_import_regex[0][$tmpcode]).'</b><br>';
1213  }
1214 
1215  //var_dump($htmltext);
1216  $htmltext .= $langs->trans("InformationOnTargetTables").': &nbsp; <b>'.$tablename."->".preg_replace('/^.*\./', '', $tmpcode)."</b>";
1217 
1218  $labelhtml = $label.' '.$form->textwithpicto('', $htmltext, 1, 'help', '', 1);
1219 
1220  $selectforline .= '<option value="'.$tmpcode.'"';
1221  if ($modetoautofillmapping == 'orderoftargets') {
1222  // The mode where we fill the preselected value of combo one by one in order of available targets fields in the declaration in descriptor file.
1223  if ($j == $i) {
1224  $selectforline .= ' selected';
1225  }
1226  } elseif ($modetoautofillmapping == 'guess') {
1227  // The mode where we try to guess which value to preselect from the name in first column of source file.
1228  // $line['example1'] is the label of the column found on first line
1229  $regs = array();
1230  if (preg_match('/^(.+)\‍((.+\..+)\‍)$/', $line['example1'], $regs)) { // If text is "Label (x.abc)"
1231  $tmpstring1 = $regs[1];
1232  $tmpstring2 = $regs[2];
1233  } else {
1234  $tmpstring1 = $line['example1'];
1235  $tmpstring2 = '';
1236  }
1237  $tmpstring1 = strtolower(str_replace('*', '', trim($tmpstring1)));
1238  $tmpstring2 = strtolower(str_replace('*', '', trim($tmpstring2)));
1239 
1240  // $tmpstring1 and $tmpstring2 are string from input file.
1241  foreach ($tmpval['labelkeyarray'] as $tmpval2) {
1242  $labeltarget = $langs->transnoentities($tmpval2);
1243  //var_dump($tmpstring1.' - '.$tmpstring2.' - '.$tmpval['labelkey'].' - '.$tmpval['label'].' - '.$tmpval2.' - '.$labeltarget);
1244  if ($tmpstring1 && ($tmpstring1 == $tmpcode || $tmpstring1 == strtolower($labeltarget)
1245  || $tmpstring1 == strtolower(dol_string_unaccent($labeltarget)) || $tmpstring1 == strtolower($tmpval2))) {
1246  if (empty($codeselectedarray[$code])) {
1247  $selectforline .= ' selected';
1248  $codeselectedarray[$code] = 1;
1249  break;
1250  }
1251  } elseif ($tmpstring2 && ($tmpstring2 == $tmpcode || $tmpstring2 == strtolower($labeltarget)
1252  || $tmpstring2 == strtolower(dol_string_unaccent($labeltarget)) || $tmpstring2 == strtolower($tmpval2))) {
1253  if (empty($codeselectedarray[$code])) {
1254  $selectforline .= ' selected';
1255  $codeselectedarray[$code] = 1;
1256  break;
1257  }
1258  }
1259  }
1260  } elseif ($modetoautofillmapping == 'session' && !empty($_SESSION['dol_array_match_file_to_database_select'])) {
1261  $tmpselectioninsession = dolExplodeIntoArray($_SESSION['dol_array_match_file_to_database_select'], ',', '=');
1262  //var_dump($code);
1263  if (!empty($tmpselectioninsession[($i+1)]) && $tmpselectioninsession[($i+1)] == $tmpcode) {
1264  $selectforline .= ' selected';
1265  }
1266  $selectforline .= ' data-debug="'.$tmpcode.'-'.$code.'-'.$j.'-'.(!empty($tmpselectioninsession[($i+1)]) ? $tmpselectioninsession[($i+1)] : "").'"';
1267  }
1268  $selectforline .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
1269  $selectforline .= '>';
1270  $selectforline .= $label;
1271  $selectforline .= '</options>';
1272  $j++;
1273  }
1274  $selectforline .= '</select>';
1275  $selectforline .= ajax_combobox('selectorderimport_'.($i+1));
1276 
1277  print $selectforline;
1278 
1279  print '</td>';
1280 
1281  // Tooltip at end of line
1282  print '<td class="nowraponall" style="font-weight:normal; text-align:right">';
1283 
1284  // Source field info
1285  $htmltext = '<b><u>'.$langs->trans("FieldSource").'</u></b><br>';
1286  $filecolumntoshow = num2Alpha($i);
1287  $htmltext .= $langs->trans("DataComeFromFileFieldNb", $filecolumntoshow).'<br>';
1288 
1289  print $form->textwithpicto('', $htmltext);
1290 
1291  print '</td>';
1292  print '</tr>';
1293  $i++;
1294  }
1295  print '</table>';
1296 
1297  print '</td></tr>';
1298 
1299  // Lines for remark
1300  print '<tr class="liste_titre"><td colspan="2">'.$langs->trans("Note").'</td></tr>';
1301  print '<tr><td colspan="2"><div id="div-mandatory-target-fields-not-mapped"></div></td></tr>';
1302 
1303  print '</table>';
1304  print '</div>';
1305 
1306 
1307  if (!empty($conf->use_javascript_ajax)) {
1308  print '<script type="text/javascript">'."\n";
1309  print 'var previousselectedvalueimport = "0";'."\n";
1310  print 'var previousselectedlabelimport = "0";'."\n";
1311  print 'var arrayofselectedvalues = [];'."\n";
1312  print 'var arrayoftargetfields = [];'."\n";
1313  print 'var arrayoftargetmandatoryfields = [];'."\n";
1314 
1315  // Loop on $fieldstarget (seems sorted by 'position') to store php array into javascript array
1316  $tmpi = 0;
1317  foreach ($fieldstarget as $key => $val) {
1318  print "arrayoftargetfields[".$tmpi."] = '".dol_escape_js($langs->trans($val['label']))."'; ";
1319  if ($val['required']) {
1320  print "arrayoftargetmandatoryfields[".$tmpi."] = '".dol_escape_js($key)."'; ";
1321  }
1322  $tmpi++;
1323  }
1324  print "\n";
1325 
1326  print '$(document).ready(function () {'."\n";
1327 
1328  print 'setOptionsToDisabled();'."\n";
1329  print 'saveSelection();'."\n";
1330 
1331  print '$(".targetselectchange").focus(function(){'."\n";
1332  print ' previousselectedvalueimport = $(this).val();'."\n";
1333  print ' previousselectedlabelimport = $(this).children("option:selected").text();'."\n";
1334  print ' console.log("previousselectedvalueimport="+previousselectedvalueimport)'."\n";
1335  print '})'."\n";
1336 
1337  // Function to set the disabled flag
1338  // - We set all option to "enabled"
1339  // - Then we scan all combo to get the value currently selected and save them into the array arrayofselectedvalues
1340  // - Then we set to disabled all fields that are selected
1341  print 'function setOptionsToDisabled() {'."\n";
1342  print ' console.log("Remove the disabled flag everywhere");'."\n";
1343  print ' $("select.targetselectchange").not($( this )).find(\'option\').prop("disabled", false);'."\n"; // Enable all options
1344  print ' arrayofselectedvalues = [];'."\n";
1345 
1346  print ' $("select.targetselectchange").each(function(){'."\n";
1347  print ' id = $(this).attr(\'id\')'."\n";
1348  print ' value = $(this).val()'."\n";
1349  print ' console.log("a selected value has been found for component "+id+" = "+value);'."\n";
1350  print ' arrayofselectedvalues.push(value);'."\n";
1351  print ' });'."\n";
1352 
1353  print ' console.log("List of all selected values arrayofselectedvalues");'."\n";
1354  print ' console.log(arrayofselectedvalues);'."\n";
1355  print ' console.log("Set the option to disabled for every entry that is currently selected somewhere else (so into arrayofselectedvalues)");'."\n";
1356 
1357  print ' $.each(arrayofselectedvalues, function(key, value) {'."\n"; // Loop on each selected value
1358  print ' if (value != -1) {'."\n";
1359  print ' console.log("Process key="+key+" value="+value+" to disable.");'."\n";
1360  print ' $("select.targetselectchange").find(\'option[value="\'+value+\'"]:not(:selected)\').prop("disabled", true);'."\n"; // Set to disabled except if currently selected
1361  print ' }'."\n";
1362  print ' });'."\n";
1363  print '}'."\n";
1364 
1365  // Function to save the selection in database
1366  print 'function saveSelection() {'."\n";
1367  //print ' console.log(arrayofselectedvalues);'."\n";
1368  print ' arrayselectedfields = [];'."\n";
1369  print ' arrayselectedfields.push(0);'."\n";
1370 
1371  print ' $.each( arrayofselectedvalues, function( key, value ) {'."\n";
1372  print ' if (value != -1) {'."\n";
1373  print ' arrayselectedfields.push(value);'."\n";
1374  print ' } else {'."\n";
1375  print ' arrayselectedfields.push(0);'."\n";
1376  print ' }'."\n";
1377  print ' });'."\n";
1378 
1379  print " $.ajax({\n";
1380  print " type: 'POST',\n";
1381  print " dataType: 'json',\n";
1382  print " url: '".dol_escape_js($_SERVER["PHP_SELF"])."?action=saveselectorder&token=".newToken()."',\n";
1383  print " data: 'selectorder='+arrayselectedfields.toString(),\n";
1384  print " success: function(){\n";
1385  print " console.log('The selected fields have been saved into '+arrayselectedfields.toString());\n";
1386  print " },\n";
1387  print ' });'."\n";
1388 
1389  // Now we loop on all target fields that are mandatory to show if they are not mapped yet.
1390  print ' console.log("arrayselectedfields");';
1391  print ' console.log(arrayselectedfields);';
1392  print ' console.log("arrayoftargetmandatoryfields");';
1393  print ' console.log(arrayoftargetmandatoryfields);';
1394  print " listtoshow = '';";
1395  print " nbelement = arrayoftargetmandatoryfields.length
1396  for (let i = 0; i < nbelement; i++) {
1397  if (arrayoftargetmandatoryfields[i] && ! arrayselectedfields.includes(arrayoftargetmandatoryfields[i])) {
1398  console.log(arrayoftargetmandatoryfields[i]+' not mapped');
1399  listtoshow = listtoshow + (listtoshow ? ', ' : '') + '<b>' + arrayoftargetfields[i] + '*</b>';
1400  }
1401  }
1402  console.log(listtoshow);
1403  if (listtoshow) {
1404  listtoshow = '".dol_escape_js(img_warning($langs->trans("MandatoryTargetFieldsNotMapped")).' '.$langs->trans("MandatoryTargetFieldsNotMapped")).": ' + listtoshow;
1405  $('#div-mandatory-target-fields-not-mapped').html(listtoshow);
1406  } else {
1407  $('#div-mandatory-target-fields-not-mapped').html('<span class=\"opacitymedium\">".dol_escape_js($langs->trans("AllTargetMandatoryFieldsAreMapped"))."</span>');
1408  }
1409  ";
1410 
1411  print '}'."\n";
1412 
1413  // If we make a change on a selectbox
1414  print '$(".targetselectchange").change(function(){'."\n";
1415  print ' setOptionsToDisabled();'."\n";
1416 
1417  print ' if(previousselectedlabelimport != "" && previousselectedvalueimport != -1) {'."\n";
1418  print ' let valuetochange = $(this).val(); '."\n";
1419  print ' $(".boxtdunused").each(function(){'."\n";
1420  print ' if ($(this).text().includes(valuetochange)){'."\n";
1421  print ' arraychild = $(this)[0].childNodes'."\n";
1422  print ' arraytexttomodify = arraychild[0].textContent.split(" ")'."\n";
1423  print ' arraytexttomodify[1] = previousselectedvalueimport '."\n";
1424  print ' textmodified = arraytexttomodify.join(" ") '."\n";
1425  print ' arraychild[0].textContent = textmodified'."\n";
1426  print ' arraychild[1].innerHTML = previousselectedlabelimport'."\n";
1427  print ' }'."\n";
1428  print ' })'."\n";
1429  print ' }'."\n";
1430  print ' $(this).blur()'."\n";
1431 
1432  print ' saveSelection()'."\n";
1433  print '});'."\n";
1434 
1435  print '})'."\n";
1436  print '</script>'."\n";
1437  }
1438 
1439  /*
1440  * Action bar
1441  */
1442  print '<div class="tabsAction">';
1443 
1444  if (count($array_match_file_to_database)) {
1445  if ($mandatoryfieldshavesource) {
1446  print '<a class="butAction saveorderselect" href="import.php?step=5'.$param.'&filetoimport='.urlencode($filetoimport).'">'.$langs->trans("NextStep").'</a>';
1447  } else {
1448  print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv("SomeMandatoryFieldHaveNoSource")).'">'.$langs->trans("NextStep").'</a>';
1449  }
1450  }
1451 
1452  print '</div>';
1453 
1454 
1455  // Area for profils import
1456  if (count($array_match_file_to_database)) {
1457  print '<br>'."\n";
1458  print '<!-- Area to add new import profile -->'."\n";
1459  print '<div class="marginbottomonly"><span class="opacitymedium">'.$langs->trans("SaveImportModel").'</span></div>';
1460 
1461  print '<form class="nocellnopadd" action="'.$_SERVER["PHP_SELF"].'" method="post">';
1462  print '<input type="hidden" name="token" value="'.newToken().'">';
1463  print '<input type="hidden" name="action" value="add_import_model">';
1464  print '<input type="hidden" name="step" value="'.$step.'">';
1465  print '<input type="hidden" name="format" value="'.$format.'">';
1466  print '<input type="hidden" name="datatoimport" value="'.$datatoimport.'">';
1467  print '<input type="hidden" name="filetoimport" value="'.$filetoimport.'">';
1468  print '<input type="hidden" name="hexa" value="'.$hexa.'">';
1469  print '<input type="hidden" name="excludefirstline" value="'.$excludefirstline.'">';
1470  print '<input type="hidden" name="endatlinenb" value="'.$endatlinenb.'">';
1471  print '<input type="hidden" name="page_y" value="">';
1472  print '<input type="hidden" value="'.dol_escape_htmltag($separator).'" name="separator">';
1473  print '<input type="hidden" value="'.dol_escape_htmltag($enclosure).'" name="enclosure">';
1474 
1475  print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
1476  print '<table summary="selectofimportprofil" class="noborder centpercent">';
1477  print '<tr class="liste_titre">';
1478  print '<td>'.$langs->trans("ImportModelName").'</td>';
1479  print '<td>'.$langs->trans("Visibility").'</td>';
1480  print '<td></td>';
1481  print '</tr>';
1482 
1483  $nameofimportprofile = str_replace(' ', '-', $langs->trans("ImportProfile").' '.$titleofmodule.' '.dol_print_date(dol_now('gmt'), 'dayxcard'));
1484  if (GETPOST('import_name')) { // If we have submited a form, we take value used fot the update try
1485  $nameofimportprofile = $import_name;
1486  }
1487 
1488  print '<tr class="oddeven">';
1489  print '<td><input name="import_name" class="minwidth300" value="'.$nameofimportprofile.'"></td>';
1490  print '<td>';
1491  $arrayvisibility = array('private'=>$langs->trans("Private"), 'all'=>$langs->trans("Everybody"));
1492  print $form->selectarray('visibility', $arrayvisibility, 'private');
1493  print '</td>';
1494  print '<td class="right">';
1495  print '<input type="submit" class="button smallpaddingimp reposition" value="'.$langs->trans("SaveImportProfile").'">';
1496  print '</td></tr>';
1497 
1498  // List of existing import profils
1499  $sql = "SELECT rowid, label, fk_user, entity";
1500  $sql .= " FROM ".MAIN_DB_PREFIX."import_model";
1501  $sql .= " WHERE type = '".$db->escape($datatoimport)."'";
1502  if (empty($conf->global->EXPORTS_SHARE_MODELS)) { // EXPORTS_SHARE_MODELS means all templates are visible, whatever is owner.
1503  $sql .= " AND fk_user IN (0, ".((int) $user->id).")";
1504  }
1505  $sql .= " ORDER BY rowid";
1506 
1507  $resql = $db->query($sql);
1508  if ($resql) {
1509  $num = $db->num_rows($resql);
1510 
1511  $tmpuser = new User($db);
1512 
1513  $i = 0;
1514  while ($i < $num) {
1515  $obj = $db->fetch_object($resql);
1516 
1517  print '<tr class="oddeven"><td>';
1518  print $obj->label;
1519  print '</td>';
1520  print '<td class="tdoverflowmax150">';
1521  if (empty($obj->fk_user)) {
1522  print $langs->trans("Everybody");
1523  } else {
1524  $tmpuser->fetch($obj->fk_user);
1525  print $tmpuser->getNomUrl(-1);
1526  }
1527  print '</td>';
1528  print '<td class="right">';
1529  print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?step='.$step.$param.'&action=deleteprof&token='.newToken().'&id='.$obj->rowid.'&filetoimport='.urlencode($filetoimport).'">';
1530  print img_delete();
1531  print '</a>';
1532  print '</tr>';
1533  $i++;
1534  }
1535  } else {
1536  dol_print_error($db);
1537  }
1538 
1539  print '</table>';
1540  print '</div>';
1541 
1542  print '</form>';
1543  }
1544 }
1545 
1546 // STEP 5: Summary of choices and launch simulation
1547 if ($step == 5 && $datatoimport) {
1548  $max_execution_time_for_importexport = (empty($conf->global->IMPORT_MAX_EXECUTION_TIME) ? 300 : $conf->global->IMPORT_MAX_EXECUTION_TIME); // 5mn if not defined
1549  $max_time = @ini_get("max_execution_time");
1550  if ($max_time && $max_time < $max_execution_time_for_importexport) {
1551  dol_syslog("max_execution_time=".$max_time." is lower than max_execution_time_for_importexport=".$max_execution_time_for_importexport.". We try to increase it dynamically.");
1552  @ini_set("max_execution_time", $max_execution_time_for_importexport); // This work only if safe mode is off. also web servers has timeout of 300
1553  }
1554 
1555  $model = $format;
1556  $list = $objmodelimport->listOfAvailableImportFormat($db);
1557 
1558  // Create classe to use for import
1559  $dir = DOL_DOCUMENT_ROOT."/core/modules/import/";
1560  $file = "import_".$model.".modules.php";
1561  $classname = "Import".ucfirst($model);
1562  require_once $dir.$file;
1563  $obj = new $classname($db, $datatoimport);
1564  if ($model == 'csv') {
1565  $obj->separator = $separator_used;
1566  $obj->enclosure = $enclosure;
1567  }
1568 
1569  // Load source fields in input file
1570  $fieldssource = array();
1571  $result = $obj->import_open_file($conf->import->dir_temp.'/'.$filetoimport, $langs);
1572 
1573  if ($result >= 0) {
1574  // Read first line
1575  $arrayrecord = $obj->import_read_record();
1576  // Put into array fieldssource starting with 1.
1577  $i = 1;
1578  foreach ($arrayrecord as $key => $val) {
1579  $fieldssource[$i]['example1'] = dol_trunc($val['val'], 24);
1580  $i++;
1581  }
1582  $obj->import_close_file();
1583  }
1584 
1585  $nboflines = $obj->import_get_nb_of_lines($conf->import->dir_temp.'/'.$filetoimport);
1586 
1587  $param = '&leftmenu=import&format='.urlencode($format).'&datatoimport='.urlencode($datatoimport).'&filetoimport='.urlencode($filetoimport).'&nboflines='.urlencode($nboflines).'&separator='.urlencode($separator).'&enclosure='.urlencode($enclosure);
1588  $param2 = $param; // $param2 = $param without excludefirstline and endatlinenb
1589  if ($excludefirstline) {
1590  $param .= '&excludefirstline='.urlencode($excludefirstline);
1591  }
1592  if ($endatlinenb) {
1593  $param .= '&endatlinenb='.urlencode($endatlinenb);
1594  }
1595  if (!empty($updatekeys)) {
1596  $param .= '&updatekeys[]='.implode('&updatekeys[]=', $updatekeys);
1597  }
1598 
1599  llxHeader('', $langs->trans("NewImport"), $help_url);
1600 
1601  $head = import_prepare_head($param, 5);
1602 
1603 
1604  print '<form action="'.$_SERVER["PHP_SELF"].'?'.$param2.'" method="POST">';
1605  print '<input type="hidden" name="token" value="'.newToken().'">';
1606  print '<input type="hidden" name="step" value="5">'; // step 5
1607  print '<input type="hidden" name="action" value="launchsimu">'; // step 5
1608 
1609  print dol_get_fiche_head($head, 'step5', '', -2);
1610 
1611  print '<div class="underbanner clearboth"></div>';
1612  print '<div class="fichecenter">';
1613 
1614  print '<table width="100%" class="border tableforfield">';
1615 
1616  // Module
1617  print '<tr><td class="titlefieldcreate">'.$langs->trans("Module").'</td>';
1618  print '<td>';
1619  $titleofmodule = $objimport->array_import_module[0]['module']->getName();
1620  // Special cas for import common to module/services
1621  if (in_array($objimport->array_import_code[0], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
1622  $titleofmodule = $langs->trans("ProductOrService");
1623  }
1624  print $titleofmodule;
1625  print '</td></tr>';
1626 
1627  // Lot de donnees a importer
1628  print '<tr><td>'.$langs->trans("DatasetToImport").'</td>';
1629  print '<td>';
1630  $entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[0]);
1631  $entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
1632  print img_object($objimport->array_import_module[0]['module']->getName(), $entityicon).' ';
1633  print $objimport->array_import_label[0];
1634  print '</td></tr>';
1635 
1636  print '</table>';
1637  print '</div>';
1638 
1639  print load_fiche_titre($langs->trans("InformationOnSourceFile"), '', 'file-export');
1640 
1641  print '<div class="underbanner clearboth"></div>';
1642  print '<div class="fichecenter">';
1643  print '<table width="100%" class="border tableforfield">';
1644 
1645  // Source file format
1646  print '<tr><td class="titlefieldcreate">'.$langs->trans("SourceFileFormat").'</td>';
1647  print '<td>';
1648  $text = $objmodelimport->getDriverDescForKey($format);
1649  print $form->textwithpicto($objmodelimport->getDriverLabelForKey($format), $text);
1650  print '</td></tr>';
1651 
1652  // Separator and enclosure
1653  if ($model == 'csv') {
1654  print '<tr><td>'.$langs->trans("CsvOptions").'</td>';
1655  print '<td>';
1656  print $langs->trans("Separator").' : '.dol_escape_htmltag($separator);
1657  print '&nbsp;&nbsp;&nbsp;&nbsp;'.$langs->trans("Enclosure").' : '.dol_escape_htmltag($enclosure);
1658  print '</td></tr>';
1659  }
1660 
1661  // File to import
1662  print '<tr><td>'.$langs->trans("FileToImport").'</td>';
1663  print '<td>';
1664  $modulepart = 'import';
1665  $relativepath = GETPOST('filetoimport');
1666  print '<a data-ajax="false" href="'.DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&file='.urlencode($relativepath).'&step=4'.$param.'" target="_blank" rel="noopener noreferrer">';
1667  print img_mime($file, '', 'pictofixedwidth');
1668  print $filetoimport;
1669  print img_picto($langs->trans("Download"), 'download', 'class="paddingleft opacitymedium"');
1670  print '</a>';
1671  print '</td></tr>';
1672 
1673  // Total lines in source file
1674  print '<tr><td>';
1675  print $langs->trans("NbOfSourceLines");
1676  print '</td><td>';
1677  print $nboflines;
1678  print '</td></tr>';
1679 
1680  // Range of lines to import
1681  print '<tr><td>';
1682  print $langs->trans("ImportFromToLine");
1683  print '</td><td>';
1684  if ($action == 'launchsimu') {
1685  print '<input type="number" class="maxwidth50 right" name="excludefirstlinebis" disabled="disabled" value="'.$excludefirstline.'">';
1686  print '<input type="hidden" name="excludefirstline" value="'.$excludefirstline.'">';
1687  } else {
1688  print '<input type="number" class="maxwidth50 right" name="excludefirstline" value="'.$excludefirstline.'">';
1689  print $form->textwithpicto("", $langs->trans("SetThisValueTo2ToExcludeFirstLine"));
1690  }
1691  print ' - ';
1692  if ($action == 'launchsimu') {
1693  print '<input type="text" class="maxwidth50" name="endatlinenbbis" disabled="disabled" value="'.$endatlinenb.'">';
1694  print '<input type="hidden" name="endatlinenb" value="'.$endatlinenb.'">';
1695  } else {
1696  print '<input type="text" class="maxwidth50" name="endatlinenb" value="'.$endatlinenb.'">';
1697  print $form->textwithpicto("", $langs->trans("KeepEmptyToGoToEndOfFile"));
1698  }
1699  if ($action == 'launchsimu') {
1700  print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'?step=5'.$param.'">'.$langs->trans("Modify").'</a>';
1701  }
1702  if ($excludefirstline == 2) {
1703  print $form->textwithpicto("", $langs->trans("WarningFirstImportedLine", $excludefirstline), 1, 'warning', "warningexcludefirstline");
1704  print '<script>
1705  $( document ).ready(function() {
1706  $("input[name=\'excludefirstline\']").on("change",function(){
1707  if($(this).val() <= 1){
1708  $(".warningexcludefirstline").hide();
1709  }else{
1710  $(".warningexcludefirstline").show();
1711  }
1712  })
1713  });
1714  </script>';
1715  }
1716  print '</td></tr>';
1717 
1718  // Keys for data UPDATE (not INSERT of new data)
1719  print '<tr><td>';
1720  print $form->textwithpicto($langs->trans("KeysToUseForUpdates"), $langs->trans("SelectPrimaryColumnsForUpdateAttempt"));
1721  print '</td><td>';
1722  if ($action == 'launchsimu') {
1723  if (count($updatekeys)) {
1724  print $form->multiselectarray('updatekeysbis', $objimport->array_import_updatekeys[0], $updatekeys, 0, 0, '', 1, '80%', 'disabled');
1725  } else {
1726  print '<span class="opacitymedium">'.$langs->trans("NoUpdateAttempt").'</span> &nbsp; -';
1727  }
1728  foreach ($updatekeys as $val) {
1729  print '<input type="hidden" name="updatekeys[]" value="'.$val.'">';
1730  }
1731  print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'?step=5'.$param.'">'.$langs->trans("Modify").'</a>';
1732  } else {
1733  if (is_array($objimport->array_import_updatekeys[0]) && count($objimport->array_import_updatekeys[0])) { //TODO dropdown UL is created inside nested SPANS
1734  print $form->multiselectarray('updatekeys', $objimport->array_import_updatekeys[0], $updatekeys, 0, 0, '', 1, '80%');
1735  //print $form->textwithpicto("", $langs->trans("SelectPrimaryColumnsForUpdateAttempt"));
1736  } else {
1737  print '<span class="opacitymedium">'.$langs->trans("UpdateNotYetSupportedForThisImport").'</span>';
1738  }
1739  }
1740  /*echo '<pre>';
1741  print_r($objimport->array_import_updatekeys);
1742  echo '</pre>';*/
1743  print '</td></tr>';
1744 
1745  print '</table>';
1746  print '</div>';
1747 
1748 
1749  print load_fiche_titre($langs->trans("InformationOnTargetTables"), '', 'file-import');
1750 
1751  print '<div class="underbanner clearboth"></div>';
1752  print '<div class="fichecenter">';
1753 
1754  print '<table width="100%" class="border tableforfield">';
1755 
1756  // Tables imported
1757  print '<tr><td class="titlefieldcreate">';
1758  print $langs->trans("TablesTarget");
1759  print '</td><td>';
1760  $listtables = array();
1761  $sort_array_match_file_to_database = $array_match_file_to_database;
1762  foreach ($array_match_file_to_database as $code => $label) {
1763  //var_dump($fieldssource);
1764  if ($code > count($fieldssource)) {
1765  continue;
1766  }
1767  //print $code.'-'.$label;
1768  $alias = preg_replace('/(\..*)$/i', '', $label);
1769  $listtables[$alias] = $objimport->array_import_tables[0][$alias];
1770  }
1771  if (count($listtables)) {
1772  $newval = '';
1773  //ksort($listtables);
1774  foreach ($listtables as $val) {
1775  if ($newval) {
1776  print ', ';
1777  }
1778  $newval = $val;
1779  // Link to Dolibarr wiki pages
1780  /*$helppagename='EN:Table_'.$newval;
1781  if ($helppagename && empty($conf->global->MAIN_HELP_DISABLELINK))
1782  {
1783  // Get helpbaseurl, helppage and mode from helppagename and langs
1784  $arrayres=getHelpParamFor($helppagename,$langs);
1785  $helpbaseurl=$arrayres['helpbaseurl'];
1786  $helppage=$arrayres['helppage'];
1787  $mode=$arrayres['mode'];
1788  $newval.=' <a href="'.sprintf($helpbaseurl,$helppage).'">'.img_picto($langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage': 'GoToHelpPage'),DOL_URL_ROOT.'/theme/common/helpdoc.png','',1).'</a>';
1789  }*/
1790  print $newval;
1791  }
1792  } else {
1793  print $langs->trans("Error");
1794  }
1795  print '</td></tr>';
1796 
1797  // Fields imported
1798  print '<tr><td>';
1799  print $langs->trans("FieldsTarget").'</td><td>';
1800  $listfields = array();
1801  $i = 0;
1802  //print 'fieldsource='.$fieldssource;
1803  $sort_array_match_file_to_database = $array_match_file_to_database;
1804  ksort($sort_array_match_file_to_database);
1805  //var_dump($sort_array_match_file_to_database);
1806  foreach ($sort_array_match_file_to_database as $code => $label) {
1807  $i++;
1808  //var_dump($fieldssource);
1809  if ($code > count($fieldssource)) {
1810  continue;
1811  }
1812  //print $code.'-'.$label;
1813  $alias = preg_replace('/(\..*)$/i', '', $label);
1814  $listfields[$i] = '<span class="nowrap">'.$langs->trans("Column").' '.num2Alpha($code - 1).' -> '.$label.'</span>';
1815  }
1816  print count($listfields) ? (join(', ', $listfields)) : $langs->trans("Error");
1817  print '</td></tr>';
1818 
1819  print '</table>';
1820  print '</div>';
1821 
1822  print dol_get_fiche_end();
1823 
1824 
1825  if ($action != 'launchsimu') {
1826  // Show import id
1827  print '<br><span class="opacitymedium">';
1828  print $langs->trans("NowClickToTestTheImport", $langs->transnoentitiesnoconv("RunSimulateImportFile")).'</span><br>';
1829  print '<br>';
1830 
1831  // Actions
1832  print '<div class="center">';
1833  if ($user->hasRight('import', 'run')) {
1834  print '<input type="submit" class="butAction" value="'.$langs->trans("RunSimulateImportFile").'">';
1835  } else {
1836  print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions")).'">'.$langs->trans("RunSimulateImportFile").'</a>';
1837  }
1838  print '</div>';
1839  } else {
1840  // Launch import
1841  $arrayoferrors = array();
1842  $arrayofwarnings = array();
1843  $maxnboferrors = empty($conf->global->IMPORT_MAX_NB_OF_ERRORS) ? 50 : $conf->global->IMPORT_MAX_NB_OF_ERRORS;
1844  $maxnbofwarnings = empty($conf->global->IMPORT_MAX_NB_OF_WARNINGS) ? 50 : $conf->global->IMPORT_MAX_NB_OF_WARNINGS;
1845  $nboferrors = 0;
1846  $nbofwarnings = 0;
1847 
1848  $importid = dol_print_date(dol_now(), '%Y%m%d%H%M%S');
1849 
1850  //var_dump($array_match_file_to_database);
1851 
1852  $db->begin();
1853 
1854  // Open input file
1855  $nbok = 0;
1856  $pathfile = $conf->import->dir_temp.'/'.$filetoimport;
1857  $result = $obj->import_open_file($pathfile, $langs);
1858  if ($result > 0) {
1859  global $tablewithentity_cache;
1860  $tablewithentity_cache = array();
1861  $sourcelinenb = 0; $endoffile = 0;
1862 
1863  // Loop on each input file record
1864  while (($sourcelinenb < $nboflines) && !$endoffile) {
1865  $sourcelinenb++;
1866  // Read line and store it into $arrayrecord
1867  //dol_syslog("line ".$sourcelinenb.' - '.$nboflines.' - '.$excludefirstline.' - '.$endatlinenb);
1868  $arrayrecord = $obj->import_read_record();
1869  if ($arrayrecord === false) {
1870  $arrayofwarnings[$sourcelinenb][0] = array('lib'=>'File has '.$nboflines.' lines. However we reach the end of file or an empty line at record '.$sourcelinenb.'. This may occurs when some records are split onto several lines and not correctly delimited by the "Char delimiter", or if there is line with no data on all fields.', 'type'=>'EOF_RECORD_ON_SEVERAL_LINES');
1871  $endoffile++;
1872  continue;
1873  }
1874  if ($excludefirstline && ($sourcelinenb < $excludefirstline)) {
1875  continue;
1876  }
1877  if ($endatlinenb && ($sourcelinenb > $endatlinenb)) {
1878  break;
1879  }
1880 
1881  // Run import
1882  $result = $obj->import_insert($arrayrecord, $array_match_file_to_database, $objimport, count($fieldssource), $importid, $updatekeys);
1883 
1884  if (count($obj->errors)) {
1885  $arrayoferrors[$sourcelinenb] = $obj->errors;
1886  }
1887  if (count($obj->warnings)) {
1888  $arrayofwarnings[$sourcelinenb] = $obj->warnings;
1889  }
1890  if (!count($obj->errors) && !count($obj->warnings)) {
1891  $nbok++;
1892  }
1893  }
1894  // Close file
1895  $obj->import_close_file();
1896  } else {
1897  print $langs->trans("ErrorFailedToOpenFile", $pathfile);
1898  }
1899 
1900  $error = 0;
1901 
1902  // Run the sql after import if defined
1903  //var_dump($objimport->array_import_run_sql_after[0]);
1904  if (!empty($objimport->array_import_run_sql_after[0]) && is_array($objimport->array_import_run_sql_after[0])) {
1905  $i = 0;
1906  foreach ($objimport->array_import_run_sql_after[0] as $sqlafterimport) {
1907  $i++;
1908  $resqlafterimport = $db->query($sqlafterimport);
1909  if (!$resqlafterimport) {
1910  $arrayoferrors['none'][] = array('lib'=>$langs->trans("Error running final request: ".$sqlafterimport));
1911  $error++;
1912  }
1913  }
1914  }
1915 
1916  $db->rollback(); // We force rollback because this was just a simulation.
1917 
1918  // Show OK
1919  if (!count($arrayoferrors) && !count($arrayofwarnings)) {
1920  print '<br>';
1921  print '<div class="info">';
1922  print '<div class=""><b>'.$langs->trans("ResultOfSimulationNoError").'</b></div>';
1923  print $langs->trans("NbInsertSim", empty($obj->nbinsert) ? 0 : $obj->nbinsert).'<br>';
1924  print $langs->trans("NbUpdateSim", empty($obj->nbupdate) ? 0 : $obj->nbupdate).'<br>';
1925  print '</div>';
1926  print '<br>';
1927  } else {
1928  print '<br>';
1929  print '<div class="warning">';
1930  print $langs->trans("NbOfLinesOK", $nbok).'...<br>';
1931  print '</div>';
1932  print '<br>';
1933  }
1934 
1935  // Show Errors
1936  //var_dump($arrayoferrors);
1937  if (count($arrayoferrors)) {
1938  print img_error().' <b>'.$langs->trans("ErrorsOnXLines", count($arrayoferrors)).'</b><br>';
1939  print '<table width="100%" class="border"><tr><td>';
1940  foreach ($arrayoferrors as $key => $val) {
1941  $nboferrors++;
1942  if ($nboferrors > $maxnboferrors) {
1943  print $langs->trans("TooMuchErrors", (count($arrayoferrors) - $nboferrors))."<br>";
1944  break;
1945  }
1946  print '* '.$langs->trans("Line").' '.dol_escape_htmltag($key).'<br>';
1947  foreach ($val as $i => $err) {
1948  print ' &nbsp; &nbsp; > '.dol_escape_htmltag($err['lib']).'<br>';
1949  }
1950  }
1951  print '</td></tr></table>';
1952  print '<br>';
1953  }
1954 
1955  // Show Warnings
1956  //var_dump($arrayoferrors);
1957  if (count($arrayofwarnings)) {
1958  print img_warning().' <b>'.$langs->trans("WarningsOnXLines", count($arrayofwarnings)).'</b><br>';
1959  print '<table width="100%" class="border"><tr><td>';
1960  foreach ($arrayofwarnings as $key => $val) {
1961  $nbofwarnings++;
1962  if ($nbofwarnings > $maxnbofwarnings) {
1963  print $langs->trans("TooMuchWarnings", (count($arrayofwarnings) - $nbofwarnings))."<br>";
1964  break;
1965  }
1966  print ' * '.$langs->trans("Line").' '.dol_escape_htmltag($key).'<br>';
1967  foreach ($val as $i => $err) {
1968  print ' &nbsp; &nbsp; > '.dol_escape_htmltag($err['lib']).'<br>';
1969  }
1970  }
1971  print '</td></tr></table>';
1972  print '<br>';
1973  }
1974 
1975  // Show import id
1976  $importid = dol_print_date(dol_now(), '%Y%m%d%H%M%S');
1977 
1978  print '<div class="center">';
1979  print '<span class="opacitymedium">'.$langs->trans("NowClickToRunTheImport", $langs->transnoentitiesnoconv("RunImportFile")).'</span><br>';
1980  /*if (empty($nboferrors)) {
1981  print $langs->trans("DataLoadedWithId", $importid).'<br>';
1982  }*/
1983  print '</div>';
1984 
1985  print '<br>';
1986 
1987  // Actions
1988  print '<div class="center">';
1989  if ($user->hasRight('import', 'run')) {
1990  if (empty($nboferrors)) {
1991  print '<a class="butAction" href="'.DOL_URL_ROOT.'/imports/import.php?leftmenu=import&step=6&importid='.$importid.$param.'">'.$langs->trans("RunImportFile").'</a>';
1992  } else {
1993  //print '<input type="submit" class="butAction" value="'.dol_escape_htmltag($langs->trans("RunSimulateImportFile")).'">';
1994 
1995  print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv("CorrectErrorBeforeRunningImport")).'">'.$langs->trans("RunImportFile").'</a>';
1996  }
1997  } else {
1998  print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions")).'">'.$langs->trans("RunSimulateImportFile").'</a>';
1999 
2000  print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions")).'">'.$langs->trans("RunImportFile").'</a>';
2001  }
2002  print '</div>';
2003  }
2004 
2005  print '</form>';
2006 }
2007 
2008 
2009 // STEP 6: Real import
2010 if ($step == 6 && $datatoimport) {
2011  $max_execution_time_for_importexport = (empty($conf->global->IMPORT_MAX_EXECUTION_TIME) ? 300 : $conf->global->IMPORT_MAX_EXECUTION_TIME); // 5mn if not defined
2012  $max_time = @ini_get("max_execution_time");
2013  if ($max_time && $max_time < $max_execution_time_for_importexport) {
2014  dol_syslog("max_execution_time=".$max_time." is lower than max_execution_time_for_importexport=".$max_execution_time_for_importexport.". We try to increase it dynamically.");
2015  @ini_set("max_execution_time", $max_execution_time_for_importexport); // This work only if safe mode is off. also web servers has timeout of 300
2016  }
2017 
2018  $model = $format;
2019  $list = $objmodelimport->listOfAvailableImportFormat($db);
2020  $importid = GETPOST("importid", 'alphanohtml');
2021 
2022 
2023  // Create classe to use for import
2024  $dir = DOL_DOCUMENT_ROOT."/core/modules/import/";
2025  $file = "import_".$model.".modules.php";
2026  $classname = "Import".ucfirst($model);
2027  require_once $dir.$file;
2028  $obj = new $classname($db, $datatoimport);
2029  if ($model == 'csv') {
2030  $obj->separator = $separator_used;
2031  $obj->enclosure = $enclosure;
2032  }
2033 
2034  // Load source fields in input file
2035  $fieldssource = array();
2036  $result = $obj->import_open_file($conf->import->dir_temp.'/'.$filetoimport, $langs);
2037  if ($result >= 0) {
2038  // Read first line
2039  $arrayrecord = $obj->import_read_record();
2040  // Put into array fieldssource starting with 1.
2041  $i = 1;
2042  foreach ($arrayrecord as $key => $val) {
2043  $fieldssource[$i]['example1'] = dol_trunc($val['val'], 24);
2044  $i++;
2045  }
2046  $obj->import_close_file();
2047  }
2048 
2049  $nboflines = (!empty($_GET["nboflines"]) ? $_GET["nboflines"] : dol_count_nb_of_line($conf->import->dir_temp.'/'.$filetoimport));
2050 
2051  $param = '&format='.$format.'&datatoimport='.urlencode($datatoimport).'&filetoimport='.urlencode($filetoimport).'&nboflines='.urlencode($nboflines);
2052  if ($excludefirstline) {
2053  $param .= '&excludefirstline='.urlencode($excludefirstline);
2054  }
2055  if ($endatlinenb) {
2056  $param .= '&endatlinenb='.urlencode($endatlinenb);
2057  }
2058  if ($separator) {
2059  $param .= '&separator='.urlencode($separator);
2060  }
2061  if ($enclosure) {
2062  $param .= '&enclosure='.urlencode($enclosure);
2063  }
2064 
2065  llxHeader('', $langs->trans("NewImport"), $help_url);
2066 
2067  $head = import_prepare_head($param, 6);
2068 
2069  print dol_get_fiche_head($head, 'step6', '', -1);
2070 
2071  print '<div class="underbanner clearboth"></div>';
2072  print '<div class="fichecenter">';
2073 
2074  print '<table width="100%" class="border">';
2075 
2076  // Module
2077  print '<tr><td class="titlefieldcreate">'.$langs->trans("Module").'</td>';
2078  print '<td>';
2079  $titleofmodule = $objimport->array_import_module[0]['module']->getName();
2080  // Special cas for import common to module/services
2081  if (in_array($objimport->array_import_code[0], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
2082  $titleofmodule = $langs->trans("ProductOrService");
2083  }
2084  print $titleofmodule;
2085  print '</td></tr>';
2086 
2087  // Lot de donnees a importer
2088  print '<tr><td>'.$langs->trans("DatasetToImport").'</td>';
2089  print '<td>';
2090  $entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[0]);
2091  $entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
2092  print img_object($objimport->array_import_module[0]['module']->getName(), $entityicon).' ';
2093  print $objimport->array_import_label[0];
2094  print '</td></tr>';
2095 
2096  print '</table>';
2097  print '</div>';
2098 
2099  print load_fiche_titre($langs->trans("InformationOnSourceFile"), '', 'file-export');
2100 
2101  print '<div class="underbanner clearboth"></div>';
2102  print '<div class="fichecenter">';
2103  print '<table width="100%" class="border">';
2104 
2105  // Source file format
2106  print '<tr><td class="titlefieldcreate">'.$langs->trans("SourceFileFormat").'</td>';
2107  print '<td>';
2108  $text = $objmodelimport->getDriverDescForKey($format);
2109  print $form->textwithpicto($objmodelimport->getDriverLabelForKey($format), $text);
2110  print '</td></tr>';
2111 
2112  // Separator and enclosure
2113  if ($model == 'csv') {
2114  print '<tr><td>'.$langs->trans("CsvOptions").'</td>';
2115  print '<td>';
2116  print $langs->trans("Separator").' : ';
2117  print htmlentities($separator);
2118  print '&nbsp;&nbsp;&nbsp;&nbsp;'.$langs->trans("Enclosure").' : ';
2119  print htmlentities($enclosure);
2120  print '</td></tr>';
2121  }
2122 
2123  // File to import
2124  print '<tr><td>'.$langs->trans("FileToImport").'</td>';
2125  print '<td>';
2126  $modulepart = 'import';
2127  $relativepath = GETPOST('filetoimport');
2128  print '<a data-ajax="false" href="'.DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&file='.urlencode($relativepath).'&step=4'.$param.'" target="_blank" rel="noopener noreferrer">';
2129  print img_mime($file, '', 'pictofixedwidth');
2130  print $filetoimport;
2131  print '</a>';
2132  print '</td></tr>';
2133 
2134  // Nb of fields
2135  print '<tr><td>';
2136  print $langs->trans("NbOfSourceLines");
2137  print '</td><td>';
2138  print $nboflines;
2139  print '</td></tr>';
2140 
2141  // Do not import first lines
2142  print '<tr><td>';
2143  print $langs->trans("ImportFromLine");
2144  print '</td><td>';
2145  print '<input type="text" size="4" name="excludefirstline" disabled="disabled" value="'.$excludefirstline.'">';
2146  print '</td></tr>';
2147 
2148  // Do not import end lines
2149  print '<tr><td>';
2150  print $langs->trans("EndAtLineNb");
2151  print '</td><td>';
2152  print '<input type="text" size="4" name="endatlinenb" disabled="disabled" value="'.$endatlinenb.'">';
2153  print '</td></tr>';
2154 
2155  print '</table>';
2156  print '</div>';
2157 
2158  print '<br>';
2159 
2160  print '<b>'.$langs->trans("InformationOnTargetTables").'</b>';
2161  print '<div class="underbanner clearboth"></div>';
2162  print '<div class="fichecenter">';
2163  print '<table class="border centpercent">';
2164 
2165  // Tables imported
2166  print '<tr><td width="25%">';
2167  print $langs->trans("TablesTarget");
2168  print '</td><td>';
2169  $listtables = array();
2170  foreach ($array_match_file_to_database as $code => $label) {
2171  //var_dump($fieldssource);
2172  if ($code > count($fieldssource)) {
2173  continue;
2174  }
2175  //print $code.'-'.$label;
2176  $alias = preg_replace('/(\..*)$/i', '', $label);
2177  $listtables[$alias] = $objimport->array_import_tables[0][$alias];
2178  }
2179  if (count($listtables)) {
2180  $newval = '';
2181  foreach ($listtables as $val) {
2182  if ($newval) {
2183  print ', ';
2184  }
2185  $newval = $val;
2186  // Link to Dolibarr wiki pages
2187  /*$helppagename='EN:Table_'.$newval;
2188  if ($helppagename && empty($conf->global->MAIN_HELP_DISABLELINK))
2189  {
2190  // Get helpbaseurl, helppage and mode from helppagename and langs
2191  $arrayres=getHelpParamFor($helppagename,$langs);
2192  $helpbaseurl=$arrayres['helpbaseurl'];
2193  $helppage=$arrayres['helppage'];
2194  $mode=$arrayres['mode'];
2195  $newval.=' <a href="'.sprintf($helpbaseurl,$helppage).'">'.img_picto($langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage': 'GoToHelpPage'),DOL_URL_ROOT.'/theme/common/helpdoc.png','',1).'</a>';
2196  }*/
2197  print $newval;
2198  }
2199  } else {
2200  print $langs->trans("Error");
2201  }
2202  print '</td></tr>';
2203 
2204  // Fields imported
2205  print '<tr><td>';
2206  print $langs->trans("FieldsTarget").'</td><td>';
2207  $listfields = array();
2208  $i = 0;
2209  $sort_array_match_file_to_database = $array_match_file_to_database;
2210  ksort($sort_array_match_file_to_database);
2211  //var_dump($sort_array_match_file_to_database);
2212  foreach ($sort_array_match_file_to_database as $code => $label) {
2213  $i++;
2214  //var_dump($fieldssource);
2215  if ($code > count($fieldssource)) {
2216  continue;
2217  }
2218  //print $code.'-'.$label;
2219  $alias = preg_replace('/(\..*)$/i', '', $label);
2220  $listfields[$i] = $langs->trans("Field").' '.$code.'->'.$label;
2221  }
2222  print count($listfields) ? (join(', ', $listfields)) : $langs->trans("Error");
2223  print '</td></tr>';
2224 
2225  print '</table>';
2226  print '</div>';
2227 
2228  // Launch import
2229  $arrayoferrors = array();
2230  $arrayofwarnings = array();
2231  $maxnboferrors = empty($conf->global->IMPORT_MAX_NB_OF_ERRORS) ? 50 : $conf->global->IMPORT_MAX_NB_OF_ERRORS;
2232  $maxnbofwarnings = empty($conf->global->IMPORT_MAX_NB_OF_WARNINGS) ? 50 : $conf->global->IMPORT_MAX_NB_OF_WARNINGS;
2233  $nboferrors = 0;
2234  $nbofwarnings = 0;
2235 
2236  $importid = dol_print_date(dol_now(), '%Y%m%d%H%M%S');
2237 
2238  //var_dump($array_match_file_to_database);
2239 
2240  $db->begin();
2241 
2242  // Open input file
2243  $nbok = 0;
2244  $pathfile = $conf->import->dir_temp.'/'.$filetoimport;
2245  $result = $obj->import_open_file($pathfile, $langs);
2246  if ($result > 0) {
2247  global $tablewithentity_cache;
2248  $tablewithentity_cache = array();
2249  $sourcelinenb = 0; $endoffile = 0;
2250 
2251  while ($sourcelinenb < $nboflines && !$endoffile) {
2252  $sourcelinenb++;
2253  $arrayrecord = $obj->import_read_record();
2254  if ($arrayrecord === false) {
2255  $arrayofwarnings[$sourcelinenb][0] = array('lib'=>'File has '.$nboflines.' lines. However we reach the end of file or an empty line at record '.$sourcelinenb.'. This may occurs when some records are split onto several lines and not correctly delimited by the "Char delimiter", or if there is line with no data on all fields.', 'type'=>'EOF_RECORD_ON_SEVERAL_LINES');
2256  $endoffile++;
2257  continue;
2258  }
2259  if ($excludefirstline && ($sourcelinenb < $excludefirstline)) {
2260  continue;
2261  }
2262  if ($endatlinenb && ($sourcelinenb > $endatlinenb)) {
2263  break;
2264  }
2265 
2266  // Run import
2267  $result = $obj->import_insert($arrayrecord, $array_match_file_to_database, $objimport, count($fieldssource), $importid, $updatekeys);
2268 
2269  if (count($obj->errors)) {
2270  $arrayoferrors[$sourcelinenb] = $obj->errors;
2271  }
2272  if (count($obj->warnings)) {
2273  $arrayofwarnings[$sourcelinenb] = $obj->warnings;
2274  }
2275  if (!count($obj->errors) && !count($obj->warnings)) {
2276  $nbok++;
2277  }
2278  }
2279  // Close file
2280  $obj->import_close_file();
2281  } else {
2282  print $langs->trans("ErrorFailedToOpenFile", $pathfile);
2283  }
2284 
2285  if (count($arrayoferrors) > 0) {
2286  $db->rollback(); // We force rollback because this was errors.
2287  } else {
2288  $error = 0;
2289 
2290  // Run the sql after import if defined
2291  //var_dump($objimport->array_import_run_sql_after[0]);
2292  if (!empty($objimport->array_import_run_sql_after[0]) && is_array($objimport->array_import_run_sql_after[0])) {
2293  $i = 0;
2294  foreach ($objimport->array_import_run_sql_after[0] as $sqlafterimport) {
2295  $i++;
2296  $resqlafterimport = $db->query($sqlafterimport);
2297  if (!$resqlafterimport) {
2298  $arrayoferrors['none'][] = array('lib'=>$langs->trans("Error running final request: ".$sqlafterimport));
2299  $error++;
2300  }
2301  }
2302  }
2303 
2304  if (!$error) {
2305  $db->commit(); // We can commit if no errors.
2306  } else {
2307  $db->rollback();
2308  }
2309  }
2310 
2311  print dol_get_fiche_end();
2312 
2313 
2314  // Show result
2315  print '<br>';
2316  print '<div class="info">';
2317  print $langs->trans("NbOfLinesImported", $nbok).'</b><br>';
2318  print $langs->trans("NbInsert", empty($obj->nbinsert) ? 0 : $obj->nbinsert).'<br>';
2319  print $langs->trans("NbUpdate", empty($obj->nbupdate) ? 0 : $obj->nbupdate).'<br>';
2320  print '</div>';
2321  print '<div class="center">';
2322  print $langs->trans("FileWasImported", $importid).'<br>';
2323  print '<span class="opacitymedium">'.$langs->trans("YouCanUseImportIdToFindRecord", $importid).'</span><br>';
2324  print '</div>';
2325 }
2326 
2327 
2328 
2329 print '<br>';
2330 
2331 // End of page
2332 llxFooter();
2333 $db->close();
2334 
2335 
2346 function show_elem($fieldssource, $pos, $key, $var, $nostyle = '')
2347 {
2348  global $conf, $langs;
2349 
2350  $height = '32px';
2351 
2352  if ($key == 'none') {
2353  //stop multiple duplicate ids with no number
2354  print "\n\n<!-- Box_no-key start-->\n";
2355  print '<div class="box boximport" style="padding:0;">'."\n";
2356  print '<table summary="boxtable_no-key" class="centpercent nobordernopadding">'."\n";
2357  } else {
2358  print "\n\n<!-- Box ".$pos." start -->\n";
2359  print '<div class="box boximport" style="padding: 0;" id="boxto_'.$pos.'">'."\n";
2360 
2361  print '<table summary="boxtable'.$pos.'" class="nobordernopadding centpercent tableimport">'."\n";
2362  }
2363 
2364  if (($pos && $pos > count($fieldssource)) && (!isset($fieldssource[$pos]["imported"]))) { // No fields
2365  /*
2366  print '<tr style="height:'.$height.'" class="trimport oddevenimport">';
2367  print '<td class="nocellnopadding" width="16" style="font-weight: normal">';
2368  print '</td>';
2369  print '<td style="font-weight: normal">';
2370  print $langs->trans("NoFields");
2371  print '</td>';
2372  print '</tr>';
2373  */
2374  } elseif ($key == 'none') { // Empty line
2375  print '<tr style="height:'.$height.'" class="trimport oddevenimport">';
2376  print '<td class="nocellnopadding" width="16" style="font-weight: normal">';
2377  print '&nbsp;';
2378  print '</td>';
2379  print '<td style="font-weight: normal">';
2380  print '&nbsp;';
2381  print '</td>';
2382  print '</tr>';
2383  } else {
2384  // Print field of source file
2385  print '<tr style="height:'.$height.'" class="trimport oddevenimport">';
2386  print '<td class="nocellnopadding" width="16" style="font-weight: normal">';
2387  // The image must have the class 'boxhandle' beause it's value used in DOM draggable objects to define the area used to catch the full object
2388  //print img_picto($langs->trans("MoveField", $pos), 'grip_title', 'class="boxhandle" style="cursor:move;"');
2389  print img_picto($langs->trans("Column").' '.num2Alpha($pos - 1), 'file', 'class="pictofixedwith"');
2390  print '</td>';
2391  if (isset($fieldssource[$pos]['imported']) && $fieldssource[$pos]['imported'] == false) {
2392  print '<td class="nowraponall boxtdunused" style="font-weight: normal">';
2393  } else {
2394  print '<td class="nowraponall tdoverflowmax500" style="font-weight: normal">';
2395  }
2396  print $langs->trans("Column").' '.num2Alpha($pos - 1).' (#'.$pos.')';
2397  if (empty($fieldssource[$pos]['example1'])) {
2398  $example = $fieldssource[$pos]['label'];
2399  } else {
2400  $example = $fieldssource[$pos]['example1'];
2401  }
2402  if ($example) {
2403  if (!utf8_check($example)) {
2404  $example = utf8_encode($example);
2405  }
2406  if (!empty($conf->dol_optimize_smallscreen)) {
2407  //print '<br>';
2408  print ' - ';
2409  } else {
2410  print ' - ';
2411  }
2412  print '<i class="opacitymedium">'.dol_escape_htmltag($example).'</i>';
2413  }
2414  print '</td>';
2415  print '</tr>';
2416  }
2417 
2418  print "</table>\n";
2419 
2420  print "</div>\n";
2421  print "<!-- Box end -->\n\n";
2422 }
2423 
2424 
2432 function getnewkey(&$fieldssource, &$listofkey)
2433 {
2434  $i = count($fieldssource) + 1;
2435  // Max number of key
2436  $maxkey = 0;
2437  foreach ($listofkey as $key => $val) {
2438  $maxkey = max($maxkey, $key);
2439  }
2440  // Found next empty key
2441  while ($i <= $maxkey) {
2442  if (empty($listofkey[$i])) {
2443  break;
2444  } else {
2445  $i++;
2446  }
2447  }
2448 
2449  $listofkey[$i] = 1;
2450  return $i;
2451 }
2460 function arrayInsert($array, $position, $insertArray)
2461 {
2462  $ret = [];
2463 
2464  if ($position == count($array)) {
2465  $ret = $array + $insertArray;
2466  } else {
2467  $i = 0;
2468  foreach ($array as $key => $value) {
2469  if ($position == $i++) {
2470  $ret += $insertArray;
2471  }
2472 
2473  $ret[$key] = $value;
2474  }
2475  }
2476 
2477  return $ret;
2478 }
if(GETPOST('button_removefilter_x', 'alpha')||GETPOST('button_removefilter.x', 'alpha')||GETPOST('button_removefilter', 'alpha')) if(GETPOST('button_search_x', 'alpha')||GETPOST('button_search.x', 'alpha')||GETPOST('button_search', 'alpha')) if($action=="save" &&empty($cancel)) $help_url
View.
Definition: agenda.php:118
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:449
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
llxFooter()
Empty footer.
Definition: wrapper.php:70
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Classe permettant la generation de composants html autre Only common components are here.
Class to manage imports.
Parent class for import file readers.
Class to manage Dolibarr users.
Definition: user.class.php:48
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->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') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_filemtime($pathoffile)
Return time of a file.
Definition: files.lib.php:599
dol_filesize($pathoffile)
Return size of a file.
Definition: files.lib.php:587
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
Definition: files.lib.php:1334
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile', $upload_dir='')
Make control on an uploaded file from an GUI page and move it to final destination.
Definition: files.lib.php:1196
dol_count_nb_of_line($file)
Count number of lines in a file.
Definition: files.lib.php:556
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:62
dolExplodeIntoArray($string, $delimiter=';', $kv='=')
Split a string with 2 keys into key array.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
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.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
img_error($titlealt='default')
Show error logo.
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.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
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.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
import_prepare_head($param, $maxstep=0)
Function to return list of tabs for import pages.
Definition: import.lib.php:36
getnewkey(&$fieldssource, &$listofkey)
Return not used field number.
Definition: import.php:2432
arrayInsert($array, $position, $insertArray)
Return array with element inserted in it at position $position.
Definition: import.php:2460
show_elem($fieldssource, $pos, $key, $var, $nostyle='')
Function to put the movable box of a source field.
Definition: import.php:2346
getMaxFileSizeArray()
Return the max allowed for file upload.
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.