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