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