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