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