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